Bladeren bron

对接接口,修改创建框架

dusenyao 1 jaar geleden
bovenliggende
commit
dd4fef6c85

+ 8 - 8
package-lock.json

@@ -29,7 +29,7 @@
         "@electron-forge/maker-squirrel": "^7.3.1",
         "@electron-forge/maker-zip": "^7.3.1",
         "@electron-forge/plugin-auto-unpack-natives": "^7.3.1",
-        "@rushstack/eslint-patch": "^1.8.0",
+        "@rushstack/eslint-patch": "^1.10.1",
         "@types/md5": "^2.3.5",
         "@vue/cli-plugin-babel": "~5.0.8",
         "@vue/cli-plugin-eslint": "~5.0.8",
@@ -37,7 +37,7 @@
         "@vue/eslint-config-prettier": "^9.0.0",
         "@vue/preload-webpack-plugin": "^2.0.0",
         "compression-webpack-plugin": "^6.1.2",
-        "electron": "^29.1.5",
+        "electron": "^29.1.6",
         "eslint": "^8.57.0",
         "eslint-plugin-prettier": "^5.1.3",
         "eslint-plugin-vue": "^9.24.0",
@@ -4012,9 +4012,9 @@
       "dev": true
     },
     "node_modules/@rushstack/eslint-patch": {
-      "version": "1.8.0",
-      "resolved": "https://registry.npmmirror.com/@rushstack/eslint-patch/-/eslint-patch-1.8.0.tgz",
-      "integrity": "sha512-0HejFckBN2W+ucM6cUOlwsByTKt9/+0tWhqUffNIcHqCXkthY/mZ7AuYPK/2IIaGWhdl0h+tICDO0ssLMd6XMQ==",
+      "version": "1.10.1",
+      "resolved": "https://registry.npmmirror.com/@rushstack/eslint-patch/-/eslint-patch-1.10.1.tgz",
+      "integrity": "sha512-S3Kq8e7LqxkA9s7HKLqXGTGck1uwis5vAXan3FnU5yw1Ec5hsSGnq4s/UCaSqABPOnOTg7zASLyst7+ohgWexg==",
       "dev": true
     },
     "node_modules/@sideway/address": {
@@ -8220,9 +8220,9 @@
       "dev": true
     },
     "node_modules/electron": {
-      "version": "29.1.5",
-      "resolved": "https://registry.npmmirror.com/electron/-/electron-29.1.5.tgz",
-      "integrity": "sha512-1uWGRw/ffA62lcrklxGUgVxVtOHojsg/nwsYr+/F9cVjipZJn8iPv/ABGIIexhmUqWcho8BqfTJ4osCBa29gBg==",
+      "version": "29.1.6",
+      "resolved": "https://registry.npmmirror.com/electron/-/electron-29.1.6.tgz",
+      "integrity": "sha512-UIYfpHR9gRBFKHyejHuXUVQ7nNzZRnoPVOHlijkvqR+DSLwgJ2ZcVVt0LNduNeO8PhPkY1+6kHonL52OTC1cOw==",
       "dev": true,
       "hasInstallScript": true,
       "dependencies": {

+ 2 - 2
package.json

@@ -31,7 +31,7 @@
     "@babel/core": "^7.24.3",
     "@babel/eslint-parser": "^7.24.1",
     "@types/md5": "^2.3.5",
-    "@rushstack/eslint-patch": "^1.8.0",
+    "@rushstack/eslint-patch": "^1.10.1",
     "@vue/eslint-config-prettier": "^9.0.0",
     "@vue/preload-webpack-plugin": "^2.0.0",
     "@electron-forge/cli": "^7.3.1",
@@ -44,7 +44,7 @@
     "@vue/cli-plugin-eslint": "~5.0.8",
     "@vue/cli-service": "~5.0.8",
     "compression-webpack-plugin": "^6.1.2",
-    "electron": "^29.1.5",
+    "electron": "^29.1.6",
     "eslint": "^8.57.0",
     "eslint-plugin-prettier": "^5.1.3",
     "eslint-plugin-vue": "^9.24.0",

+ 7 - 0
src/api/book.js

@@ -92,6 +92,13 @@ export function DeleteChapter(data) {
 }
 
 /**
+ * 得到教材章节
+ */
+export function AddCoursewareToBook(data) {
+  return http.post(`${process.env.VUE_APP_BookWebSI}?MethodName=book-courseware_manager-AddCoursewareToBook`, data);
+}
+
+/**
  * 得到章节下的互动课件列表
  * @param {object} data
  * @param {string} data.chapter_id 章节ID

+ 2 - 75
src/utils/common.js

@@ -1,7 +1,7 @@
 /**
  * 换算数据大小
- * @param {Number} size
- * @returns String
+ * @param {number} size
+ * @returns {string} 换算后的数据大小,两位小数带单位
  */
 export function conversionSize(size) {
   let _size = size;
@@ -13,76 +13,3 @@ export function conversionSize(size) {
   }
   return `${_size.toFixed(2)}${units[factor]}`;
 }
-
-// 分割线
-const type = {
-  type: 'divider',
-  property: {
-    height: 40,
-    type: 'solid',
-  },
-};
-
-const data = {
-  id: '1',
-  background_image_url: 'https://file/1/1.jpg',
-  background_position: {
-    x: 0,
-    y: 0,
-    width: 100,
-    height: 100,
-  },
-  // 组件列表
-  component_list: [
-    // 第一行
-    [
-      // 第一行第一列
-      {
-        id: '1-1',
-        type: 'image',
-        width: '100%',
-        component_list: [],
-      },
-    ],
-    // 第二行
-    [
-      // 第二行第一列
-      {
-        id: '2-1',
-        type: 'video',
-        width: '30%',
-        component_list: [],
-      },
-      // 第二行第二列
-      {
-        id: '2-2',
-        type: 'audio',
-        width: '30%',
-        component_list: [],
-      },
-      // 第二行第三列
-      {
-        id: '',
-        type: '',
-        width: '40%',
-        // 组件列表
-        component_list: [
-          // 第二行第三列第一行
-          [
-            {
-              id: '3-1',
-              type: 'image',
-            },
-          ],
-          // 第二行第三列第二行
-          [
-            {
-              id: '3-2',
-              type: 'video',
-            },
-          ],
-        ],
-      },
-    ],
-  ],
-};

+ 316 - 0
src/views/book/courseware/create/components/SelectBackground.vue

@@ -0,0 +1,316 @@
+<template>
+  <el-dialog
+    custom-class="background"
+    width="608px"
+    :close-on-click-modal="false"
+    :visible="visible"
+    :before-close="handleClose"
+  >
+    <div class="select-background">
+      <div class="select-background-top">
+        <span class="tab">背景图</span>
+        <SelectUpload type="image" @uploadSuccess="uploadSuccess" />
+      </div>
+      <div class="background-img">
+        <div v-if="file_url" class="img-set" :style="{ top: `${imgData.top - 9}px`, left: `${imgData.left}px` }">
+          <div class="dot top-left" @mousedown="dragStart($event, 'nwse-resize', 'top-left')"></div>
+          <div class="horizontal-line" @mousedown="dragStart($event, 'ns-resize', 'top')"></div>
+          <div class="dot top-right" @mousedown="dragStart($event, 'nesw-resize', 'top-right')"></div>
+          <div class="vertical-line" @mousedown="dragStart($event, 'ew-resize', 'left')"></div>
+          <img
+            :src="file_url"
+            draggable="false"
+            alt="背景图"
+            :style="{ width: `${imgData.width}px`, height: `${imgData.height}px` }"
+            @mousedown="dragStart($event, 'move', 'move')"
+          />
+          <div class="vertical-line" @mousedown="dragStart($event, 'ew-resize', 'right')"></div>
+          <div class="dot bottom-left" @mousedown="dragStart($event, 'nesw-resize', 'bottom-left')"></div>
+          <div class="horizontal-line" @mousedown="dragStart($event, 'ns-resize', 'bottom')"></div>
+          <div class="dot bottom-right" @mousedown="dragStart($event, 'nwse-resize', 'bottom-right')"></div>
+        </div>
+      </div>
+    </div>
+
+    <div slot="footer">
+      <el-button @click="handleClose">取消</el-button>
+      <el-button type="primary" @click="confirm">确定</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import SelectUpload from './common/SelectUpload.vue';
+
+export default {
+  name: 'SelectBackground',
+  components: {
+    SelectUpload,
+  },
+  props: {
+    visible: {
+      type: Boolean,
+      required: true,
+    },
+  },
+  data() {
+    return {
+      maxWidth: 576,
+      maxHeight: 310,
+      file_url: '',
+      drag: {
+        dragging: false,
+        startX: 0,
+        startY: 0,
+        type: '',
+      },
+      imgData: {
+        width: 0,
+        height: 0,
+        top: 0,
+        left: 0,
+      },
+    };
+  },
+  mounted() {
+    document.querySelector('.el-dialog__wrapper').addEventListener('mousemove', this.mouseMove);
+    document.body.addEventListener('mouseup', this.mouseUp);
+  },
+  beforeDestroy() {
+    document.querySelector('.el-dialog__wrapper')?.removeEventListener('mousemove', this.mouseMove);
+    document.body.removeEventListener('mouseup', this.mouseUp);
+  },
+  methods: {
+    handleClose() {
+      this.$emit('update:visible', false);
+    },
+    confirm() {
+      this.$emit('update:visible', false);
+      const { width, height, top, left } = this.imgData;
+      this.$emit('setBackgroundImage', this.file_url, {
+        width: (width / this.maxWidth) * 100,
+        height: (height / this.maxHeight) * 100,
+        top: (top / this.maxHeight) * 100,
+        left: (left / this.maxWidth) * 100,
+      });
+    },
+    /**
+     * 拖拽开始
+     * @param {MouseEvent} event
+     * @param {string} cursor
+     * @param {string} type
+     */
+    dragStart(event, cursor, type) {
+      const { clientX, clientY } = event;
+      this.drag = {
+        dragging: true,
+        startX: clientX,
+        startY: clientY,
+        type,
+      };
+
+      document.querySelector('.el-dialog__wrapper').style.cursor = cursor;
+    },
+    /**
+     * 鼠标移动
+     * @param {MouseEvent} event
+     */
+    mouseMove(event) {
+      if (!this.drag.dragging) return;
+      const { clientX, clientY } = event;
+      const { startX, startY, type } = this.drag;
+
+      const widthDiff = clientX - startX;
+      const heightDiff = clientY - startY;
+
+      if (type === 'top-left') {
+        this.imgData.width = Math.min(this.maxWidth, Math.max(0, this.imgData.width - widthDiff));
+        this.imgData.height = Math.min(this.maxHeight, Math.max(0, this.imgData.height - heightDiff));
+        this.imgData.top = Math.min(this.maxHeight - this.imgData.height, Math.max(0, this.imgData.top + heightDiff));
+        this.imgData.left = Math.min(this.maxWidth - this.imgData.width, Math.max(0, this.imgData.left + widthDiff));
+      } else if (type === 'top-right') {
+        this.imgData.width = Math.min(this.maxWidth, Math.max(this.imgData.width + widthDiff));
+        this.imgData.height = Math.min(this.maxHeight, Math.max(0, this.imgData.height - heightDiff));
+        this.imgData.top = Math.min(this.maxHeight - this.imgData.height, Math.max(0, this.imgData.top + heightDiff));
+        this.imgData.left = Math.min(this.maxWidth - this.imgData.width, Math.max(0, this.imgData.left));
+      } else if (type === 'bottom-left') {
+        this.imgData.width = Math.min(this.maxWidth, Math.max(0, this.imgData.width - widthDiff));
+        this.imgData.height = Math.min(this.maxHeight, Math.max(this.imgData.height + heightDiff));
+        this.imgData.top = Math.min(this.maxHeight - this.imgData.height, Math.max(0, this.imgData.top));
+        this.imgData.left = Math.min(this.maxWidth - this.imgData.width, Math.max(0, this.imgData.left + widthDiff));
+      } else if (type === 'bottom-right') {
+        this.imgData.width = Math.min(this.maxWidth, Math.max(this.imgData.width + widthDiff));
+        this.imgData.height = Math.min(this.maxHeight, Math.max(this.imgData.height + heightDiff));
+        this.imgData.top = Math.min(this.maxHeight - this.imgData.height, Math.max(0, this.imgData.top));
+        this.imgData.left = Math.min(this.maxWidth - this.imgData.width, Math.max(0, this.imgData.left));
+      }
+
+      if (type === 'top') {
+        this.imgData.height = Math.min(this.maxHeight, Math.max(0, this.imgData.height - heightDiff));
+        this.imgData.top = Math.min(this.maxHeight - this.imgData.height, Math.max(0, this.imgData.top + heightDiff));
+      } else if (type === 'bottom') {
+        this.imgData.height = Math.min(this.maxHeight, Math.max(this.imgData.height + heightDiff));
+        this.imgData.top = Math.min(this.maxHeight - this.imgData.height, Math.max(0, this.imgData.top));
+      } else if (type === 'left') {
+        this.imgData.width = Math.min(this.maxWidth, Math.max(this.imgData.width - widthDiff));
+        this.imgData.left = Math.min(this.maxWidth - this.imgData.width, Math.max(0, this.imgData.left + widthDiff));
+      } else if (type === 'right') {
+        this.imgData.width = Math.min(this.maxWidth, Math.max(this.imgData.width + widthDiff));
+        this.imgData.left = Math.min(this.maxWidth - this.imgData.width, Math.max(0, this.imgData.left));
+      }
+
+      if (type === 'move') {
+        this.imgData.top = Math.min(this.maxHeight - this.imgData.height, Math.max(0, this.imgData.top + heightDiff));
+        this.imgData.left = Math.min(this.maxWidth - this.imgData.width, Math.max(0, this.imgData.left + widthDiff));
+      }
+      this.drag.startX = clientX;
+      this.drag.startY = clientY;
+    },
+    /**
+     * 鼠标抬起
+     */
+    mouseUp() {
+      this.drag.dragging = false;
+      document.querySelector('.el-dialog__wrapper').style.cursor = 'auto';
+    },
+    /**
+     * 上传成功
+     * @param {array} fileList
+     */
+    uploadSuccess(fileList) {
+      if (fileList.length > 0) {
+        let file_url = fileList[0].file_url;
+        const img = new Image();
+        img.src = file_url;
+        img.onload = () => {
+          const { width, height } = img;
+
+          if (width > this.maxWidth || height > this.maxHeight) {
+            const wScale = width / this.maxWidth;
+            const hScale = height / this.maxHeight;
+            const scale = wScale > hScale ? this.maxWidth / 2 / width : this.maxHeight / 2 / height;
+
+            this.imgData = {
+              width: width * scale,
+              height: height * scale,
+              top: 0,
+              left: 0,
+            };
+          } else {
+            this.imgData = {
+              width,
+              height,
+              top: 0,
+              left: 0,
+            };
+          }
+          this.file_url = fileList[0].file_url_open;
+        };
+      }
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.select-background {
+  &-top {
+    display: flex;
+    align-items: center;
+    margin-bottom: 16px;
+
+    .tab {
+      width: 80px;
+      font-size: 14px;
+      color: $font-light-color;
+    }
+  }
+
+  .background-img {
+    height: 310px;
+    border: 1px dashed rgba(0, 0, 0, 8%);
+
+    .img-set {
+      position: relative;
+      display: inline-grid;
+      grid-template:
+        ' . . . ' 2px
+        ' . img . ' auto
+        ' . . . ' 2px
+        / 2px auto 2px;
+
+      img {
+        object-fit: cover;
+      }
+
+      .horizontal-line,
+      .vertical-line {
+        background-color: $main-color;
+      }
+
+      .horizontal-line {
+        width: 100%;
+        height: 2px;
+        cursor: ns-resize;
+      }
+
+      .vertical-line {
+        width: 2px;
+        height: 100%;
+        cursor: ew-resize;
+      }
+
+      .dot {
+        z-index: 1;
+        width: 6px;
+        height: 6px;
+        background-color: $main-color;
+
+        &.top-left {
+          top: -2px;
+          left: -2px;
+        }
+
+        &.top-right {
+          top: -2px;
+          right: 2px;
+        }
+
+        &.bottom-left {
+          bottom: 2px;
+          left: -2px;
+        }
+
+        &.bottom-right {
+          right: 2px;
+          bottom: 2px;
+        }
+
+        &.top-left,
+        &.bottom-right {
+          position: relative;
+          cursor: nwse-resize;
+        }
+
+        &.top-right,
+        &.bottom-left {
+          position: relative;
+          cursor: nesw-resize;
+        }
+      }
+    }
+  }
+}
+</style>
+
+<style lang="scss">
+.el-dialog.background {
+  .el-dialog__header {
+    display: none;
+  }
+
+  .el-dialog__body {
+    padding: 8px 16px;
+  }
+}
+</style>

+ 5 - 5
src/views/book/courseware/create/components/base/audio/Audio.vue

@@ -3,11 +3,11 @@
     <template #content>
       <UploadFile
         id="AudioUploadPage"
-        :moduleData="data"
-        :labelText="labelText"
-        :acceptFileType="acceptFileType"
-        :uploadTip="uploadTip"
-        :iconClass="iconClass"
+        :module-data="data"
+        :label-text="labelText"
+        :accept-file-type="acceptFileType"
+        :upload-tip="uploadTip"
+        :icon-class="iconClass"
       />
     </template>
   </ModuleBase>

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

@@ -25,13 +25,10 @@
         <div class="file-name">
           <span>
             <SvgIcon :icon-class="iconClass" size="12" />
-            <span>{{ file.name }}</span>
+            <span>{{ file.file_name ?? file.name }}</span>
             <!-- <span>({{ file.size }})</span> -->
           </span>
-          <span v-show="file.progress > 0">
-            <!-- <SvgIcon icon-class="progress" size="12" /> -->
-            {{ file.progress }}%
-          </span>
+          <span v-show="file.progress > 0"> {{ file.progress }}% </span>
         </div>
         <SvgIcon icon-class="delete-black" size="12" @click="removeFile(file, i)" />
         <SvgIcon v-show="moduleData.type == 'picture'" icon-class="mark" size="12" @click="viewDialog" />
@@ -43,7 +40,6 @@
 </template>
 
 <script>
-import ModuleMixin from '../../common/ModuleMixin';
 import { fileUpload } from '@/api/app';
 import { conversionSize } from '@/utils/common';
 import FillDescribe from '../../common/FillDescribe';
@@ -53,7 +49,6 @@ export default {
   components: {
     FillDescribe,
   },
-  mixins: [ModuleMixin],
   props: {
     // 组件标签
     labelText: {
@@ -197,7 +192,7 @@ export default {
 
     .label-text {
       font-size: 14px;
-      color: #4e5969;
+      color: $font-light-color;
     }
 
     div {
@@ -225,7 +220,7 @@ export default {
       :deep .el-upload {
         &--text {
           width: 100%;
-          background-color: #f2f3f5;
+          background-color: $fill-color;
           border-radius: 2px 0 0 2px;
 
           .el-button {

+ 6 - 6
src/views/book/courseware/create/components/base/picture/Picture.vue

@@ -3,11 +3,11 @@
     <template #content>
       <UploadFile
         id="PictureUploadPage"
-        :moduleData="data"
-        :labelText="labelText"
-        :acceptFileType="acceptFileType"
-        :uploadTip="uploadTip"
-        :iconClass="iconClass"
+        :module-data="data"
+        :label-text="labelText"
+        :accept-file-type="acceptFileType"
+        :upload-tip="uploadTip"
+        :icon-class="iconClass"
       />
     </template>
   </ModuleBase>
@@ -20,8 +20,8 @@ import UploadFile from '../common/UploadFile.vue';
 
 export default {
   name: 'PicturePage',
-  mixins: [ModuleMixin],
   components: { UploadFile },
+  mixins: [ModuleMixin],
   data() {
     return {
       data: getPictureData(),

+ 7 - 1
src/views/book/courseware/create/components/common/ModuleBase.vue

@@ -7,7 +7,7 @@
         <span :class="[{ active: getCurSettingId() === id }]" @click="showSetting">
           <SvgIcon icon-class="setup" size="10" />
         </span>
-        <span><SvgIcon icon-class="delete" size="10" /></span>
+        <span @click="deleteComponent"><SvgIcon icon-class="delete" size="10" /></span>
       </div>
     </div>
     <div class="module-content">
@@ -33,12 +33,18 @@ export default {
       componentNameList,
     };
   },
+  methods: {
+    deleteComponent() {
+      this.$emit('deleteComponent');
+    },
+  },
 };
 </script>
 
 <style lang="scss" scoped>
 .module {
   padding: 8px;
+  background-color: #fff;
   border: 1px solid #ebebeb;
 
   &-top {

+ 129 - 0
src/views/book/courseware/create/components/common/SelectUpload.vue

@@ -0,0 +1,129 @@
+<template>
+  <div class="select-upload">
+    <span v-if="label" class="label-text">{{ label }}</span>
+    <el-upload
+      ref="upload"
+      class="file-uploader"
+      action="no"
+      :accept="curTypeObj.accept"
+      :multiple="multiple"
+      :show-file-list="false"
+      :auto-upload="false"
+      :on-change="onFileChange"
+    >
+      <el-button>{{ showText }}</el-button>
+    </el-upload>
+    <el-button size="small" class="upload-button" type="primary" @click="uploadFiles">上传</el-button>
+  </div>
+</template>
+
+<script>
+import { fileUpload } from '@/api/app';
+
+export default {
+  name: 'SelectUpload',
+  props: {
+    type: {
+      type: String,
+      required: true,
+    },
+    multiple: {
+      type: Boolean,
+      default: false,
+    },
+    label: {
+      type: String,
+      default: '',
+    },
+  },
+  data() {
+    return {
+      typeObj: {
+        image: {
+          label: '图片',
+          accept: '.jpg,.png,.jpeg',
+        },
+        video: {
+          label: '视频',
+          accept: '.mp4',
+        },
+        audio: {
+          label: '音频',
+          accept: '.mp3,.acc,.wma',
+        },
+      },
+      fileList: [],
+    };
+  },
+  computed: {
+    curTypeObj() {
+      return this.typeObj[this.type];
+    },
+    showText() {
+      if (this.fileList.length > 0) {
+        return this.fileList.map((file) => file.name).join('、');
+      }
+      return `选取${this.curTypeObj.label}文件`;
+    },
+  },
+  methods: {
+    onFileChange(file, fileList) {
+      this.fileList = fileList;
+    },
+    uploadFiles() {
+      const list = this.$refs.upload.uploadFiles;
+      if (list.length === 0) {
+        this.$message.error('请选择文件');
+        return;
+      }
+      list.forEach((file) => {
+        let form = new FormData();
+        form.append(file.name, file.raw, file.name);
+        fileUpload('Mid', form, { isGlobalprogress: true })
+          .then(({ file_info_list }) => {
+            this.fileList = [];
+            this.$refs.upload.clearFiles();
+            if (file_info_list.length > 0) {
+              this.$emit('uploadSuccess', file_info_list);
+            }
+          })
+          .catch(() => {
+            this.$message.error('上传失败');
+          });
+      });
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.select-upload {
+  display: flex;
+  flex: 1;
+  align-items: center;
+
+  .label-text {
+    padding-right: 16px;
+  }
+
+  .file-uploader {
+    flex: 1;
+
+    :deep .el-upload--text {
+      width: 100%;
+      border-radius: 2px 0 0 2px;
+    }
+
+    .el-button {
+      width: 100%;
+      color: #86909c;
+      text-align: left;
+      background-color: $fill-color;
+    }
+  }
+
+  .upload-button {
+    border-radius: 0 2px 2px 0;
+  }
+}
+</style>

+ 420 - 0
src/views/book/courseware/create/components/createCanvas.vue

@@ -0,0 +1,420 @@
+<template>
+  <main
+    ref="canvas"
+    class="canvas"
+    :style="[
+      {
+        backgroundImage: data.background_image_url ? `url(${data.background_image_url})` : '',
+        backgroundSize: data.background_image_url
+          ? `${data.background_position.width}% ${data.background_position.height}%`
+          : '',
+        backgroundPosition: data.background_image_url
+          ? `${data.background_position.left}% ${data.background_position.top}%`
+          : '',
+      },
+    ]"
+  >
+    <span class="drag-line" data-row="-1"></span>
+    <div v-for="(row, i) in data.row_list" :key="i" class="row">
+      <div
+        v-for="(col, j) in row.col_list"
+        :key="j"
+        class="col"
+        :style="{
+          width: col.width,
+          gridTemplateAreas: col.grid_template_areas,
+          gridTemplateColumns: col.grid_template_columns,
+          gridTemplateRows: col.grid_template_rows,
+        }"
+      >
+        <template v-for="(grid, k) in col.grid_list">
+          <span
+            v-if="k === 0"
+            :key="`start-${k}`"
+            class="drag-vertical-line"
+            :data-row="i"
+            :data-col="j"
+            :data-grid="k"
+          ></span>
+          <component
+            :is="componentList[grid.type]"
+            :id="grid.id"
+            ref="component"
+            :key="k"
+            :style="{ gridArea: grid.grid_area }"
+            @showSetting="showSetting"
+            @deleteComponent="deleteComponent"
+          />
+          <span :key="`end-${k}`" class="drag-vertical-line" :data-row="i" :data-col="j" :data-grid="k + 1"></span>
+        </template>
+      </div>
+      <span class="drag-line" :data-row="i"></span>
+    </div>
+  </main>
+</template>
+
+<script>
+import { getRandomNumber } from '@/utils/index';
+import { componentList } from '../../data/bookType';
+import { SaveCoursewareContent, GetCoursewareContent } from '@/api/book';
+
+export default {
+  name: 'CreateCanvas',
+  data() {
+    const { book_id, chapter_id } = this.$route.query;
+
+    return {
+      courseware_id: this.$route.params.courseware_id,
+      book_id,
+      chapter_id,
+      data: {
+        background_image_url: '',
+        background_position: {
+          width: 100,
+          height: 100,
+          top: 0,
+          left: 0,
+        },
+        // 组件列表
+        row_list: [],
+      },
+      curType: 'divider',
+      componentList,
+      curRow: -2,
+      curCol: -1,
+      curGrid: -1,
+      enterCanvas: false, // 是否进入画布
+      // 拖拽状态
+      drag: {
+        clientX: 0,
+        clientY: 0,
+        dragging: false,
+      },
+    };
+  },
+  watch: {
+    drag: {
+      handler(val) {
+        if (val.dragging) {
+          const dragging = document.querySelector('.dragging');
+          dragging.style.left = `${val.clientX}px`;
+          dragging.style.top = `${val.clientY}px`;
+        }
+      },
+      deep: true,
+    },
+    enterCanvas: {
+      handler(val) {
+        if (val) return;
+        const dragLineList = document.querySelectorAll('.drag-line');
+        dragLineList.forEach((item) => {
+          item.style.opacity = 0;
+        });
+        this.curRow = -2;
+        const dragVerticalLineList = document.querySelectorAll('.drag-vertical-line');
+        dragVerticalLineList.forEach((item) => {
+          item.style.opacity = 0;
+        });
+        this.curCol = -1;
+        this.curGrid = -1;
+      },
+    },
+  },
+  created() {
+    GetCoursewareContent({ id: this.courseware_id }).then(({ content }) => {
+      if (content) this.data = JSON.parse(content);
+    });
+  },
+  mounted() {
+    document.addEventListener('mousemove', this.dragMove);
+    document.addEventListener('mouseup', this.dragEnd);
+  },
+  beforeDestroy() {
+    document.removeEventListener('mousemove', this.dragMove);
+    document.removeEventListener('mouseup', this.dragEnd);
+  },
+  methods: {
+    saveCoursewareContent() {
+      let component_id_list = this.data.row_list.flatMap((row) =>
+        row.col_list.flatMap((col) => col.grid_list.map((grid) => grid.id)),
+      );
+
+      this.$refs.component.forEach((item) => {
+        item.saveCoursewareComponentContent();
+      });
+
+      SaveCoursewareContent({
+        id: this.courseware_id,
+        category: 'NEW',
+        content: JSON.stringify(this.data),
+        component_id_list,
+      }).then(() => {
+        this.$message.success('保存成功');
+      });
+    },
+    setBackgroundImage(url, position) {
+      this.data.background_image_url = url;
+      this.data.background_position = position;
+
+      this.$message.success('设置背景图成功');
+    },
+    /**
+     * 显示设置
+     * @param {object} setting
+     * @param {string} type
+     */
+    showSetting(setting, type, id) {
+      this.$emit('showSetting', setting, type, id);
+    },
+    deleteComponent() {
+      console.log(1);
+      this.$message.success('删除成功');
+    },
+    /**
+     * 拖拽开始
+     * 用点击模拟拖拽
+     * @param {MouseEvent} event
+     * @param {string} type
+     */
+    dragStart(event, type) {
+      // 获取鼠标位置
+      const { clientX, clientY } = event;
+      document.body.style.userSelect = 'none'; // 禁止选中文本
+      this.drag.dragging = true;
+      this.curType = type;
+      // 在鼠标位置创建一个拖拽元素
+      const dragging = document.createElement('div');
+      dragging.className = 'dragging';
+      this.drag.clientX = clientX;
+      this.drag.clientY = clientY;
+      document.body.appendChild(dragging);
+    },
+    /**
+     * 鼠标移动
+     */
+    dragMove(event) {
+      if (!this.drag.dragging) return;
+
+      const { clientX, clientY } = event;
+      this.drag.clientX = clientX;
+      this.drag.clientY = clientY;
+
+      let { isInsideCanvas } = this.getMarginDifferences();
+
+      this.enterCanvas = isInsideCanvas;
+      if (!isInsideCanvas) return;
+
+      this.showRecentLine(clientX, clientY);
+    },
+    /**
+     * 显示最近的线
+     * @param {number} clientX
+     * @param {number} clientY
+     */
+    showRecentLine(clientX, clientY) {
+      const dragLineList = document.querySelectorAll('.drag-line'); // 获取所有的横线
+      const dragVerticalLineList = document.querySelectorAll('.drag-vertical-line'); // 获取所有的竖线
+      let minDistance = Infinity;
+      let minIndex = -1;
+      const list = [...dragLineList, ...dragVerticalLineList];
+
+      list.forEach((item, index) => {
+        const rect = item.getBoundingClientRect();
+        const distance = Math.sqrt(
+          Math.pow(clientX - rect.left - rect.width / 2, 2) + Math.pow(clientY - rect.top - rect.height / 2, 2),
+        );
+        if (distance < minDistance) {
+          minDistance = distance;
+          minIndex = index;
+        }
+      });
+      list.forEach((item, index) => {
+        if (index === minIndex) {
+          this.curRow = Number(item.getAttribute('data-row'));
+          this.curCol = Number(item.getAttribute('data-col') || -1);
+          this.curGrid = Number(item.getAttribute('data-grid') || -1);
+
+          item.style.opacity = 1;
+        } else {
+          item.style.opacity = 0;
+        }
+      });
+    },
+
+    /**
+     * 鼠标松开
+     */
+    dragEnd() {
+      document.body.style.userSelect = 'auto';
+      const dragging = document.querySelector('.dragging');
+      if (dragging) {
+        document.body.removeChild(dragging);
+        this.drag.dragging = false;
+      }
+
+      if (this.enterCanvas) {
+        if (this.curRow >= -1 && this.curCol <= -1) {
+          this.data.row_list.splice(this.curRow + 1, 0, this.calculateRowInsertedObject());
+        }
+        if (this.curRow >= -1 && this.curCol > -1 && this.curGrid > -1) {
+          this.calculateColObject();
+        }
+      }
+      this.enterCanvas = false;
+    },
+    /**
+     * 计算列插入的对象
+     */
+    calculateColObject() {
+      let num = 0; // 计算当前行之前的所有 grid_list 的数量
+      for (let i = 0; i <= this.curRow; i++) {
+        this.data.row_list[i]?.col_list.forEach((item) => {
+          num += item.grid_list.length;
+        });
+      }
+      const id = getRandomNumber(12);
+      const letter = String.fromCharCode(65 + num);
+      let col = this.data.row_list[this.curRow].col_list[this.curCol];
+
+      col.grid_list.splice(this.curGrid, 0, {
+        id,
+        grid_area: letter,
+        type: this.curType,
+      });
+
+      let grid_template_columns = '0';
+      col.grid_list.forEach((item, i) => {
+        if (i === col.grid_list.length - 1) grid_template_columns += ' auto 0';
+        else grid_template_columns += ' auto 16px';
+      });
+      col.grid_template_columns = grid_template_columns;
+
+      let grid_template_areas = '.';
+      col.grid_list.forEach(({ grid_area }) => {
+        grid_template_areas += ` ${grid_area} .`;
+      });
+      col.grid_template_areas = `"${grid_template_areas}"`;
+    },
+    /**
+     * 计算行插入的对象
+     */
+    calculateRowInsertedObject() {
+      let num = 0; // 计算当前行之前的所有 grid_list 的数量
+      for (let i = 0; i <= this.curRow; i++) {
+        this.data.row_list[i]?.col_list.forEach((item) => {
+          num += item.grid_list.length;
+        });
+      }
+      const id = getRandomNumber(12);
+      const letter = String.fromCharCode(65 + num);
+
+      return {
+        col_list: [
+          {
+            width: '100%',
+            grid_template_areas: `'. ${letter} .'`,
+            grid_template_columns: '0 auto 0',
+            grid_template_rows: 'auto',
+            grid_list: [
+              {
+                id,
+                grid_area: letter,
+                type: this.curType,
+              },
+            ],
+          },
+        ],
+      };
+    },
+    /**
+     * 获取拖拽元素和画布的边距差值
+     * @returns {object} { leftMarginDifference, topMarginDifference, isInsideCanvas }
+     * leftMarginDifference: 拖拽元素和画布左边距差值
+     * topMarginDifference: 拖拽元素和画布上边距差值
+     * isInsideCanvas: 是否在画布内
+     */
+    getMarginDifferences() {
+      const rect1 = document.querySelector('.dragging').getBoundingClientRect();
+      const rect2 = this.$refs.canvas.getBoundingClientRect();
+
+      const leftMarginDifference = rect1.left - rect2.left + 128;
+      const topMarginDifference = rect1.top - rect2.top + 72;
+
+      let isInsideCanvas =
+        leftMarginDifference > 0 &&
+        leftMarginDifference < rect2.width &&
+        topMarginDifference > 0 &&
+        topMarginDifference < rect2.height;
+
+      return { leftMarginDifference, topMarginDifference, isInsideCanvas };
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.canvas {
+  display: flex;
+  flex-direction: column;
+  row-gap: 6px;
+  width: 100%;
+  min-height: calc(100% - 56px);
+  padding: 24px;
+  background-color: #fff;
+  background-repeat: no-repeat;
+  border-radius: 4px;
+
+  .row {
+    display: flex;
+    flex-direction: column;
+    row-gap: 6px;
+
+    .col {
+      display: grid;
+
+      .drag-vertical-line:first-child {
+        left: -8px;
+      }
+
+      .drag-vertical-line:not(:first-child, :last-child) {
+        left: 6px;
+      }
+
+      .drag-vertical-line:last-child {
+        right: -4px;
+      }
+    }
+  }
+
+  .drag-line {
+    width: calc(100% - 16px);
+    height: 4px;
+    margin: 0 8px;
+    background-color: #379fff;
+    border-radius: 4px;
+    opacity: 0;
+  }
+
+  .drag-vertical-line {
+    position: relative;
+    width: 4px;
+    height: 100%;
+    background-color: #379fff;
+    border-radius: 4px;
+    opacity: 0;
+  }
+}
+</style>
+
+<style lang="scss">
+.dragging {
+  position: fixed;
+  z-index: 999;
+  width: 320px;
+  height: 180px;
+  background-color: #eaf5ff;
+  border: 1px solid #b5dbff;
+  border-radius: 4px;
+  transform: translate(-40%, -40%);
+}
+</style>

+ 23 - 361
src/views/book/courseware/create/index.vue

@@ -22,7 +22,7 @@
 
     <div class="create-middle">
       <div class="create-operation">
-        <el-button><SvgIcon icon-class="background-img" />背景图</el-button>
+        <el-button @click="showSetBackground"><SvgIcon icon-class="background-img" />背景图</el-button>
         <el-button><SvgIcon icon-class="template" />模板</el-button>
         <el-button class="exit-edit">
           <span><i class="el-icon-close"></i> 退出编辑</span>
@@ -36,59 +36,30 @@
         </el-button>
       </div>
 
-      <main ref="canvas" class="canvas">
-        <span class="drag-line" data-row="-1"></span>
-        <div v-for="(row, i) in data.row_list" :key="i" class="row">
-          <div
-            v-for="(col, j) in row.col_list"
-            :key="j"
-            class="col"
-            :style="{
-              width: col.width,
-              gridTemplateAreas: col.grid_template_areas,
-              gridTemplateColumns: col.grid_template_columns,
-              gridTemplateRows: col.grid_template_rows,
-            }"
-          >
-            <template v-for="(grid, k) in col.grid_list">
-              <span
-                v-if="k === 0"
-                :key="`start-${k}`"
-                class="drag-vertical-line"
-                :data-row="i"
-                :data-col="j"
-                :data-grid="k"
-              ></span>
-              <component
-                :is="componentList[grid.type]"
-                :id="grid.id"
-                ref="component"
-                :key="k"
-                :style="{ gridArea: grid.grid_area }"
-                @showSetting="showSetting"
-              />
-              <span :key="`end-${k}`" class="drag-vertical-line" :data-row="i" :data-col="j" :data-grid="k + 1"></span>
-            </template>
-          </div>
-          <span class="drag-line" :data-row="i"></span>
-        </div>
-      </main>
+      <CreateCanvas ref="createCanvas" @showSetting="showSetting" />
     </div>
 
     <div class="create-right">
       <div class="setting-tittle">设置</div>
       <component :is="componentSettingList[curSettingType]" ref="setting" />
     </div>
+
+    <SelectBackground :visible.sync="visible" @setBackgroundImage="setBackgroundImage" />
   </div>
 </template>
 
 <script>
-import { bookTypeOption, componentList, componentSettingList } from '../data/bookType';
-import { getRandomNumber } from '@/utils/index';
-import { SaveCoursewareContent, GetCoursewareContent } from '@/api/book';
+import { bookTypeOption, componentSettingList } from '../data/bookType';
+
+import CreateCanvas from './components/createCanvas.vue';
+import SelectBackground from './components/SelectBackground.vue';
 
 export default {
   name: 'CreatePage',
+  components: {
+    CreateCanvas,
+    SelectBackground,
+  },
   provide() {
     return {
       getCurSettingId: () => this.curSettingId,
@@ -102,97 +73,26 @@ export default {
       courseware_id: this.$route.params.courseware_id,
       book_id,
       chapter_id,
-      data: {
-        background_image_url: '',
-        background_position: {
-          x: 0,
-          y: 0,
-          width: 100,
-          height: 100,
-        },
-        // 组件列表
-        row_list: [],
-      },
       curSettingType: '',
       curSettingId: '',
-      curType: 'divider',
-      componentList,
       componentSettingList,
       bookTypeOption,
-      curRow: -2,
-      curCol: -1,
-      curGrid: -1,
-      enterCanvas: false, // 是否进入画布
-      // 拖拽状态
-      drag: {
-        clientX: 0,
-        clientY: 0,
-        dragging: false,
-      },
+      visible: false,
     };
   },
-  watch: {
-    drag: {
-      handler(val) {
-        if (val.dragging) {
-          const dragging = document.querySelector('.dragging');
-          dragging.style.left = `${val.clientX}px`;
-          dragging.style.top = `${val.clientY}px`;
-        }
-      },
-      deep: true,
-    },
-    enterCanvas: {
-      handler(val) {
-        if (val) return;
-        const dragLineList = document.querySelectorAll('.drag-line');
-        dragLineList.forEach((item) => {
-          item.style.opacity = 0;
-        });
-        this.curRow = -2;
-        const dragVerticalLineList = document.querySelectorAll('.drag-vertical-line');
-        dragVerticalLineList.forEach((item) => {
-          item.style.opacity = 0;
-        });
-        this.curCol = -1;
-        this.curGrid = -1;
-      },
-    },
-  },
-  created() {
-    GetCoursewareContent({ id: this.courseware_id }).then(({ content }) => {
-      if (content) this.data = JSON.parse(content);
-    });
-  },
-  mounted() {
-    document.addEventListener('mousemove', this.dragMove);
-    document.addEventListener('mouseup', this.dragEnd);
-  },
-  beforeDestroy() {
-    document.removeEventListener('mousemove', this.dragMove);
-    document.removeEventListener('mouseup', this.dragEnd);
-  },
+
   methods: {
     back() {
       this.$router.push({ path: '/chapter', query: { chapter_id: this.chapter_id, book_id: this.book_id } });
     },
+    dragStart(event, type) {
+      this.$refs.createCanvas.dragStart(event, type);
+    },
     saveCoursewareContent() {
-      let component_id_list = this.data.row_list.flatMap((row) =>
-        row.col_list.flatMap((col) => col.grid_list.map((grid) => grid.id)),
-      );
-
-      this.$refs.component.forEach((item) => {
-        item.saveCoursewareComponentContent();
-      });
-
-      SaveCoursewareContent({
-        id: this.courseware_id,
-        category: 'NEW',
-        content: JSON.stringify(this.data),
-        component_id_list,
-      }).then(() => {
-        this.$message.success('保存成功');
-      });
+      this.$refs.createCanvas.saveCoursewareContent();
+    },
+    showSetBackground() {
+      this.visible = true;
     },
     /**
      * 显示设置
@@ -206,184 +106,8 @@ export default {
         this.$refs.setting.setSetting(setting);
       });
     },
-    /**
-     * 拖拽开始
-     * 用点击模拟拖拽
-     * @param {MouseEvent} event
-     * @param {string} type
-     */
-    dragStart(event, type) {
-      // 获取鼠标位置
-      const { clientX, clientY } = event;
-      document.body.style.userSelect = 'none'; // 禁止选中文本
-      this.drag.dragging = true;
-      this.curType = type;
-      // 在鼠标位置创建一个拖拽元素
-      const dragging = document.createElement('div');
-      dragging.className = 'dragging';
-      this.drag.clientX = clientX;
-      this.drag.clientY = clientY;
-      document.body.appendChild(dragging);
-    },
-    /**
-     * 鼠标移动
-     */
-    dragMove(event) {
-      if (!this.drag.dragging) return;
-
-      const { clientX, clientY } = event;
-      this.drag.clientX = clientX;
-      this.drag.clientY = clientY;
-
-      let { isInsideCanvas } = this.getMarginDifferences();
-
-      this.enterCanvas = isInsideCanvas;
-      if (!isInsideCanvas) return;
-
-      this.showRecentLine(clientX, clientY);
-    },
-    /**
-     * 显示最近的线
-     * @param {number} clientX
-     * @param {number} clientY
-     */
-    showRecentLine(clientX, clientY) {
-      const dragLineList = document.querySelectorAll('.drag-line'); // 获取所有的横线
-      const dragVerticalLineList = document.querySelectorAll('.drag-vertical-line'); // 获取所有的竖线
-      let minDistance = Infinity;
-      let minIndex = -1;
-      const list = [...dragLineList, ...dragVerticalLineList];
-
-      list.forEach((item, index) => {
-        const rect = item.getBoundingClientRect();
-        const distance = Math.sqrt(
-          Math.pow(clientX - rect.left - rect.width / 2, 2) + Math.pow(clientY - rect.top - rect.height / 2, 2),
-        );
-        if (distance < minDistance) {
-          minDistance = distance;
-          minIndex = index;
-        }
-      });
-
-      list.forEach((item, index) => {
-        if (index === minIndex) {
-          this.curRow = Number(item.getAttribute('data-row'));
-          this.curCol = Number(item.getAttribute('data-col') || -1);
-          this.curGrid = Number(item.getAttribute('data-grid') || -1);
-
-          item.style.opacity = 1;
-        } else {
-          item.style.opacity = 0;
-        }
-      });
-    },
-
-    /**
-     * 鼠标松开
-     */
-    dragEnd() {
-      document.body.style.userSelect = 'auto';
-      const dragging = document.querySelector('.dragging');
-      if (dragging) {
-        document.body.removeChild(dragging);
-        this.drag.dragging = false;
-      }
-
-      if (this.enterCanvas) {
-        if (this.curRow >= -1 && this.curCol <= -1) {
-          this.data.row_list.splice(this.curRow + 1, 0, this.calculateRowInsertedObject());
-        }
-        if (this.curRow >= -1 && this.curCol > -1 && this.curGrid > -1) {
-          this.calculateColObject();
-        }
-      }
-      this.enterCanvas = false;
-    },
-    /**
-     * 计算列插入的对象
-     */
-    calculateColObject() {
-      let num = 0; // 计算当前行之前的所有 grid_list 的数量
-      for (let i = 0; i <= this.curRow; i++) {
-        this.data.row_list[i]?.col_list.forEach((item) => {
-          num += item.grid_list.length;
-        });
-      }
-      const id = getRandomNumber(12);
-      const letter = String.fromCharCode(65 + num);
-      let col = this.data.row_list[this.curRow].col_list[this.curCol];
-
-      col.grid_list.splice(this.curGrid, 0, {
-        id,
-        grid_area: letter,
-        type: this.curType,
-      });
-
-      let grid_template_columns = '0';
-      col.grid_list.forEach((item, i) => {
-        if (i === col.grid_list.length - 1) grid_template_columns += ' auto 0';
-        else grid_template_columns += ' auto 16px';
-      });
-      col.grid_template_columns = grid_template_columns;
-
-      let grid_template_areas = '.';
-      col.grid_list.forEach(({ grid_area }) => {
-        grid_template_areas += ` ${grid_area} .`;
-      });
-      col.grid_template_areas = `"${grid_template_areas}"`;
-    },
-    /**
-     * 计算行插入的对象
-     */
-    calculateRowInsertedObject() {
-      let num = 0; // 计算当前行之前的所有 grid_list 的数量
-      for (let i = 0; i <= this.curRow; i++) {
-        this.data.row_list[i]?.col_list.forEach((item) => {
-          num += item.grid_list.length;
-        });
-      }
-      const id = getRandomNumber(12);
-      const letter = String.fromCharCode(65 + num);
-
-      return {
-        col_list: [
-          {
-            width: '100%',
-            grid_template_areas: `'. ${letter} .'`,
-            grid_template_columns: '0 auto 0',
-            grid_template_rows: 'auto',
-            grid_list: [
-              {
-                id,
-                grid_area: letter,
-                type: this.curType,
-              },
-            ],
-          },
-        ],
-      };
-    },
-    /**
-     * 获取拖拽元素和画布的边距差值
-     * @returns {object} { leftMarginDifference, topMarginDifference, isInsideCanvas }
-     * leftMarginDifference: 拖拽元素和画布左边距差值
-     * topMarginDifference: 拖拽元素和画布上边距差值
-     * isInsideCanvas: 是否在画布内
-     */
-    getMarginDifferences() {
-      const rect1 = document.querySelector('.dragging').getBoundingClientRect();
-      const rect2 = this.$refs.canvas.getBoundingClientRect();
-
-      const leftMarginDifference = rect1.left - rect2.left + 128;
-      const topMarginDifference = rect1.top - rect2.top + 72;
-
-      let isInsideCanvas =
-        leftMarginDifference > 0 &&
-        leftMarginDifference < rect2.width &&
-        topMarginDifference > 0 &&
-        topMarginDifference < rect2.height;
-
-      return { leftMarginDifference, topMarginDifference, isInsideCanvas };
+    setBackgroundImage(...data) {
+      this.$refs.createCanvas.setBackgroundImage(...data);
     },
   },
 };
@@ -491,57 +215,6 @@ export default {
         }
       }
     }
-
-    .canvas {
-      display: flex;
-      flex-direction: column;
-      row-gap: 6px;
-      width: 100%;
-      min-height: calc(100% - 56px);
-      padding: 24px;
-      background-color: #fff;
-      border-radius: 4px;
-
-      .row {
-        display: flex;
-        flex-direction: column;
-        row-gap: 6px;
-
-        .col {
-          display: grid;
-
-          .drag-vertical-line:first-child {
-            left: -8px;
-          }
-
-          .drag-vertical-line:not(:first-child, :last-child) {
-            left: 6px;
-          }
-
-          .drag-vertical-line:last-child {
-            right: -4px;
-          }
-        }
-      }
-
-      .drag-line {
-        width: calc(100% - 16px);
-        height: 4px;
-        margin: 0 8px;
-        background-color: #379fff;
-        border-radius: 4px;
-        opacity: 0;
-      }
-
-      .drag-vertical-line {
-        position: relative;
-        width: 4px;
-        height: 100%;
-        background-color: #379fff;
-        border-radius: 4px;
-        opacity: 0;
-      }
-    }
   }
 
   &-right {
@@ -559,17 +232,6 @@ export default {
 </style>
 
 <style lang="scss">
-.dragging {
-  position: fixed;
-  z-index: 999;
-  width: 320px;
-  height: 180px;
-  background-color: #eaf5ff;
-  border: 1px solid #b5dbff;
-  border-radius: 4px;
-  transform: translate(-40%, -40%);
-}
-
 .save-popover {
   width: 100px;
   min-width: 100px;

+ 1 - 1
src/views/home/index.vue

@@ -269,7 +269,7 @@ export default {
       &.active {
         font-weight: bold;
         color: $main-color;
-        background-color: #f2f3f5;
+        background-color: $fill-color;
       }
     }
   }