Browse Source

画板模板

natasha 2 ngày trước cách đây
mục cha
commit
028d7d0321

BIN
src/assets/drawing-back.png


BIN
src/assets/icon-clean.png


BIN
src/assets/thick-pen-active.png


BIN
src/assets/thick-pen.png


BIN
src/assets/thicks-pen-active.png


BIN
src/assets/thicks-pen.png


BIN
src/assets/thin-pen-active.png


BIN
src/assets/thin-pen.png


+ 1 - 1
src/views/book/courseware/create/components/base/common/UploadFile.vue

@@ -249,7 +249,7 @@ export default {
       if (this.type === 'audio') {
         fileType = ['mp3', 'acc', 'wma', 'wav'];
         typeTip = '音频文件只能是 mp3、acc、wma、wav格式!';
-      } else if (this.type === 'picture' || this.type === 'image_text') {
+      } else if (this.type === 'picture' || this.type === 'image_text' || this.type === 'drawing') {
         fileType = ['jpg', 'png', 'jpeg'];
         typeTip = '图片文件只能是 jpg、png、jpeg 格式!';
       } else if (this.type === 'video') {

+ 143 - 0
src/views/book/courseware/create/components/question/drawing/Drawing.vue

@@ -0,0 +1,143 @@
+<template>
+  <ModuleBase :type="data.type">
+    <template #content>
+      <UploadFile
+        key="upload_image"
+        :courseware-id="courseware_id"
+        :component-id="id"
+        :type="data.type"
+        :total-size="data.total_size"
+        :file-list="data.image_list"
+        :file-id-list="data.image_id_list"
+        :file-info-list="data.image_info_list"
+        :label-text="labelText"
+        :accept-file-type="acceptFileType"
+        :icon-class="iconClass"
+        :limit="1"
+        :single-size="500"
+        @updateFileList="updateFileList"
+      />
+      <div class="image-size">
+        <span>图片大小</span
+        ><el-input-number v-model="data.image_width" :step="100" :min="200" :max="800" /><el-input-number
+          v-model="data.image_height"
+          :step="100"
+          :min="200"
+          :max="800"
+        />
+      </div>
+      <div
+        id="selectableArea"
+        :style="{
+          width: data.image_width + 'px',
+          height: data.image_height + 'px',
+          background: data.image_list[0]
+            ? 'url(' + data.image_list[0].file_url + ') center / contain no-repeat'
+            : '#DCDFE6',
+          position: 'relative',
+          border: '1px dotted #DCDFE6',
+          textAlign: 'center',
+          lineHeight: data.image_height + 'px',
+        }"
+      >
+        {{ data.image_list[0] ? '' : '背景图' }}
+      </div>
+    </template>
+  </ModuleBase>
+</template>
+
+<script>
+import ModuleMixin from '../../common/ModuleMixin';
+import UploadFile from '../../base/common/UploadFile.vue';
+import { getDrawingData } from '@/views/book/courseware/data/drawing';
+import SelectUpload from '@/views/book/courseware/create/components/common/SelectUpload.vue';
+import { GetFileURLMap } from '@/api/app';
+
+export default {
+  name: 'DrawingPage',
+  components: { UploadFile, SelectUpload },
+  mixins: [ModuleMixin],
+  data() {
+    return {
+      data: getDrawingData(),
+      labelText: '背景图',
+      acceptFileType: '.jpg,.png,.jpeg',
+      iconClass: 'picture',
+    };
+  },
+  watch: {
+    'data.image_list': {
+      handler(val) {
+        if (val.length > 0) {
+          this.handleData();
+        }
+      },
+      immediate: true,
+    },
+  },
+  methods: {
+    updateFileList({ file_list, file_id_list, file_info_list }) {
+      this.data.image_list = file_list;
+      this.data.image_id_list = file_id_list;
+      this.data.image_info_list = file_info_list;
+    },
+
+    handleData() {
+      this.data.image_list.forEach((item) => {
+        GetFileURLMap({ file_id_list: [item.file_id] }).then(({ url_map }) => {
+          this.$set(item, 'file_url', url_map[item.file_id]);
+        });
+      });
+      this.handleMindMap();
+    },
+    handleMindMap() {
+      // 思维导图数据
+      let node_list = [];
+      this.data.image_list.forEach((item) => {
+        node_list.push({
+          name: item.file_name,
+          id: Math.random().toString(36).substring(2, 12),
+        });
+      });
+      this.data.mind_map.node_list = node_list;
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+.upload-file {
+  display: flex;
+  column-gap: 12px;
+  align-items: center;
+  margin: 8px 0;
+
+  .file-name {
+    display: flex;
+    column-gap: 14px;
+    align-items: center;
+    justify-content: space-between;
+    max-width: 360px;
+    padding: 8px 12px;
+    font-size: 14px;
+    color: #1d2129;
+    background-color: #f7f8fa;
+
+    span {
+      display: flex;
+      column-gap: 14px;
+      align-items: center;
+    }
+  }
+
+  .svg-icon {
+    cursor: pointer;
+  }
+}
+
+.image-size {
+  display: flex;
+  gap: 10px;
+  align-items: center;
+  padding: 20px 0;
+}
+</style>

+ 34 - 0
src/views/book/courseware/create/components/question/drawing/DrawingSetting.vue

@@ -0,0 +1,34 @@
+<template>
+  <div>
+    <el-form :model="property" label-width="72px" label-position="left">
+      <SerailNumber :property="property" />
+    </el-form>
+  </div>
+</template>
+
+<script>
+import SettingMixin from '@/views/book/courseware/create/components/common/SettingMixin';
+
+import { getDrawingProperty } from '@/views/book/courseware/data/drawing';
+import { isEnable } from '@/views/book/courseware/data/common';
+
+export default {
+  name: 'DrawingSetting',
+  mixins: [SettingMixin],
+  data() {
+    return {
+      isEnable,
+      property: getDrawingProperty(),
+    };
+  },
+  methods: {},
+};
+</script>
+
+<style lang="scss" scoped>
+@use '@/styles/mixin.scss' as *;
+
+.el-form {
+  @include setting-base;
+}
+</style>

+ 11 - 0
src/views/book/courseware/data/bookType.js

@@ -59,6 +59,8 @@ import ImageText from '../create/components/question/image_text/ImageText.vue';
 import ImageTextSetting from '../create/components/question/image_text/ImageTextSetting.vue';
 import H5Games from '../create/components/base/h5_games/H5Games.vue';
 import H5GamesSetting from '../create/components/base/h5_games/H5GamesSetting.vue';
+import Drawing from '../create/components/question/drawing/Drawing.vue';
+import DrawingSetting from '../create/components/question/drawing/DrawingSetting.vue';
 
 // 预览组件页面列表
 import AudioPreview from '@/views/book/courseware/preview/components/audio/AudioPreview.vue';
@@ -92,6 +94,7 @@ import JudgePreview from '../preview/components/judge/JudgePreview.vue';
 import WriteBasePreview from '../preview/components/write_base/WriteBasePreview.vue';
 import ImageTextPreview from '../preview/components/image_text/ImageTextPreview.vue';
 import H5GamesPreview from '../preview/components/h5_games/H5GamesPreview.vue';
+import DrawingPreview from '../preview/components/drawing/DrawingPreview.vue';
 
 export const bookTypeOption = [
   {
@@ -345,6 +348,14 @@ export const bookTypeOption = [
         set: PinyinBaseSetting,
         preview: PinyinBasePreview,
       },
+      {
+        value: 'drawing',
+        label: '画板',
+        icon: '',
+        component: Drawing,
+        set: DrawingSetting,
+        preview: DrawingPreview,
+      },
     ],
   },
 ];

+ 40 - 0
src/views/book/courseware/data/drawing.js

@@ -0,0 +1,40 @@
+import {
+  displayList,
+  serialNumberTypeList,
+  serialNumberPositionList,
+  isEnable,
+} from '@/views/book/courseware/data/common';
+
+export { isEnable };
+
+export function getDrawingProperty() {
+  return {
+    serial_number: 1,
+    sn_type: serialNumberTypeList[0].value,
+    sn_position: serialNumberPositionList[3].value,
+    sn_display_mode: displayList[0].value,
+
+    
+  };
+}
+
+export function getDrawingData() {
+  return {
+    type: 'drawing',
+    title: '画板',
+    property: getDrawingProperty(),
+    total_size: 500, // 单位MB
+    image_list: [], // 图片列表
+    image_info_list: [],
+    image_id_list: [], // 文件 id
+    image_width: 500, // 图片宽度px
+    image_height: 500, // 图片高度px
+    mind_map: {
+      node_list: [
+      ], // 思维导图数据
+    },
+    answer: {
+      answer_list: [],
+    },
+  };
+}

+ 163 - 0
src/views/book/courseware/preview/components/drawing/DrawingPreview.vue

@@ -0,0 +1,163 @@
+<!-- eslint-disable vue/no-v-html -->
+<template>
+  <div class="imageText-preview" :style="getAreaStyle()">
+    <SerialNumberPosition v-if="isEnable(data.property.sn_display_mode)" :property="data.property" />
+
+    <div
+      class="img-box"
+      :style="{
+        background: image_url ? 'url(' + image_url + ') center / contain no-repeat' : '#DCDFE6',
+        width: data.image_width + 'px',
+        height: data.image_height + 'px',
+        border: '1px dotted #DCDFE6',
+      }"
+    >
+      <!-- 如果是查看答案模式 v-if 下面画画的vue-esign不显示 -->
+      <!-- <img :src="answer.answer_list[0].answer" alt="" /> -->
+      <vue-esign
+        ref="esign-drawing"
+        class="esign-canvas"
+        :width="data.image_width"
+        :height="data.image_height"
+        :is-crop="isCrop"
+        :line-width="lineWidth"
+        :line-color="lineColor"
+      />
+    </div>
+    <div class="footer">
+      <div class="pen">
+        <!-- 选择颜色 -->
+        <el-color-picker v-model="lineColor"></el-color-picker>
+        <!-- 清除一笔 -->
+        <!-- <img @click="removeOne" class="clean-btn" src="@/assets/drawing-back.png" /> -->
+        <!-- 清空画板 -->
+        <img @click="handleReset" class="clean-btn" src="@/assets/icon-clean.png" />
+        <img :src="penIndex == 0 ? thinpenActive : thinpen" @click="changePen(0)" class="pen-img" />
+        <img :src="penIndex == 1 ? thickpenActive : thickpen" @click="changePen(1)" class="pen-img" />
+        <img :src="penIndex == 2 ? thicskpenActive : thicskpen" @click="changePen(2)" class="pen-img" />
+        <div class="save" @click="handleGenerate">Save</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import PreviewMixin from '../common/PreviewMixin';
+import { getDrawingData } from '@/views/book/courseware/data/drawing';
+import { GetFileURLMap } from '@/api/app';
+import vueEsign from 'vue-esign';
+export default {
+  name: 'DrawingPreview',
+
+  components: { vueEsign },
+  mixins: [PreviewMixin],
+  data() {
+    return {
+      data: getDrawingData(),
+      penIndex: 0,
+      image_url: '',
+      lineWidth: 2,
+      lineColor: '#000000',
+      bgColor: '#f7f8fa',
+      isCrop: false,
+      weightList: [2, 4, 8],
+      thinpen: require('@/assets/thin-pen.png'), //细笔
+      thinpenActive: require('@/assets/thin-pen-active.png'),
+      thickpen: require('@/assets/thick-pen.png'),
+      thickpenActive: require('@/assets/thick-pen-active.png'),
+      thicskpen: require('@/assets/thicks-pen.png'),
+      thicskpenActive: require('@/assets/thicks-pen-active.png'),
+      resultImg: null,
+    };
+  },
+  created() {
+    this.initData();
+  },
+  mounted() {
+    this.audio_width = document.getElementsByClassName('imageText-preview')[0].clientWidth - 150;
+  },
+  methods: {
+    initData() {
+      if (!this.isJudgingRightWrong) {
+        this.answer.answer_list = [];
+        let obj = {
+          answer: '',
+        };
+        this.answer.answer_list.push(obj);
+      }
+
+      this.data.image_list.forEach((item) => {
+        GetFileURLMap({ file_id_list: [item.file_id] }).then(({ url_map }) => {
+          this.image_url = url_map[item.file_id];
+        });
+      });
+    },
+    // 保存图片
+    handleGenerate() {
+      console.log(this.$refs['esign-drawing']);
+      this.$refs['esign-drawing']
+        .generate()
+        .then((res) => {
+          this.resultImg = res;
+          this.answer.answer_list[0].answer = res;
+          this.$message.success('保存成功');
+        })
+        .catch((err) => {});
+    },
+    changePen(index) {
+      this.penIndex = index;
+      this.lineWidth = this.weightList[this.penIndex];
+    },
+    handleReset() {
+      this.$refs['esign-drawing'].reset(false);
+    },
+    // 删除最后一笔
+    removeOne() {
+      console.log(this.$refs['esign-drawing']);
+      // this.$refs['esign-drawing'].removelastOne();
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+@use '@/styles/mixin.scss' as *;
+
+.img-box {
+  position: relative;
+  margin: 20px auto;
+}
+
+.pen {
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
+
+  .save {
+    box-sizing: border-box;
+    width: 65px;
+    height: 32px;
+    margin-left: 16px;
+    font-size: 16px;
+    font-weight: 400;
+    line-height: 32px;
+    color: #000;
+    text-align: center;
+    cursor: pointer;
+    background: rgba(0, 0, 0, 5%);
+    border: 1px solid rgba(0, 0, 0, 10%);
+    border-radius: 6px;
+  }
+
+  .save:hover {
+    background: rgba(0, 0, 0, 25%);
+  }
+
+  > img {
+    width: 24px;
+    height: 24px;
+    margin: 0 8px;
+    cursor: pointer;
+  }
+}
+</style>