瀏覽代碼

基础组件界面

zq 1 年之前
父節點
當前提交
8705c7ea73

+ 3 - 0
src/icons/svg/components/delete-black.svg

@@ -0,0 +1,3 @@
+<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M7.49899 1.25V0.25L2.49899 0.250001V1.25L0.248993 1.25V2.25H1.12399L1.12399 9C1.12399 9.41421 1.45978 9.75 1.87399 9.75L8.12399 9.75C8.53821 9.75 8.87399 9.41421 8.87399 9V2.25L9.74899 2.25V1.25L7.49899 1.25ZM2.12399 8.75L2.12399 2.25L7.87399 2.25V8.75L2.12399 8.75ZM3.49899 3.5V7.25H4.49899V3.5H3.49899ZM5.49899 3.5V7.25H6.49899V3.5H5.49899Z" fill="#4E5969"/>
+</svg>

+ 3 - 0
src/icons/svg/components/note.svg

@@ -0,0 +1,3 @@
+<svg width="10" height="12" viewBox="0 0 10 12" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M4 7.0234V0H9.33333V1.33333H5.33333V9.33333C5.33333 10.8061 4.1394 12 2.66667 12C1.19391 12 0 10.8061 0 9.33333C0 7.8606 1.19391 6.66667 2.66667 6.66667C3.1524 6.66667 3.6078 6.79653 4 7.0234ZM2.66667 10.6667C3.40307 10.6667 4 10.0697 4 9.33333C4 8.59693 3.40307 8 2.66667 8C1.93029 8 1.33333 8.59693 1.33333 9.33333C1.33333 10.0697 1.93029 10.6667 2.66667 10.6667Z" fill="black"/>
+</svg>

+ 4 - 0
src/icons/svg/components/progress.svg

@@ -0,0 +1,4 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<circle cx="8" cy="8" r="6" stroke="#94BFFF" stroke-width="4"/>
+<path d="M8 2C8.94686 2 9.88028 2.22409 10.7239 2.65396C11.5676 3.08383 12.2975 3.70726 12.8541 4.47329C13.4107 5.23932 13.778 6.12619 13.9261 7.06139C14.0743 7.9966 13.9989 8.95358 13.7063 9.8541" stroke="#165DFF" stroke-width="4"/>
+</svg>

+ 18 - 0
src/styles/element.scss

@@ -14,3 +14,21 @@ div.el-table {
 .el-pagination {
   text-align: right;
 }
+
+label.el-radio {
+  margin-right: 24px;
+  color: $font-color;
+
+  .el-radio__label {
+    padding-left: 8px;
+  }
+
+  .el-radio__input.is-checked + .el-radio__label {
+    color: $font-color;
+  }
+
+  .el-radio__input.is-checked .el-radio__inner {
+    background-color: $main-color;
+    border-color: $main-color;
+  }
+}

+ 1 - 0
src/styles/variables.scss

@@ -18,6 +18,7 @@ $error-color: #f2555a;
 $right-color: #30a47d;
 $right-bc-color: #e8f7f2;
 $label-color: #076aff;
+$setting-active-color: #4176FF;
 
 // px
 $header-h: 64px;

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

@@ -1,42 +1,198 @@
 <template>
   <ModuleBase :type="data.type">
     <template #content>
-      <span>音频</span>
-      <el-upload>
-        <el-button slot="trigger" size="small" type="primary">选取文件</el-button>
-        <el-button size="small" type="primary">上传</el-button>
-        <el-divider />
-        <div slot="tip" class="el-upload__tip">支持上传mp3、acc、wma,等格式音频文件,单个文件最大100MB,总文件体积不超1G。</div>
-      </el-upload>
+      <div class="audio-area">
+        <span class="label-text">音频</span>
+        <div class="upload-box">
+          <el-upload
+            ref="upload"
+            class="audio-uploader"
+            action="no"
+            accept=".mp3,.acc,.wma"
+            :multiple="true"
+            :show-file-list="false"
+            :file-list="file_info_list"
+            :auto-upload="false"
+            :before-upload="beforeAudioUpload"
+            :on-change="onFileChange"
+          >
+            <el-button>选取音频文件</el-button>
+          </el-upload>
+          <el-button size="small" type="primary" @click="uploadAudio">上传</el-button>
+        </div>
+      </div>
+      <el-divider />
+      <div class="upload-tip">支持上传mp3、acc、wma,等格式音频文件,单个文件最大100MB,总文件体积不超1G。</div>
+      <ul slot="file-list" class="file-list">
+        <li v-for="(file, i) in file_info_list" :key="i">
+          <div class="file-name">
+            <span>
+              <SvgIcon icon-class="note" size="12" />
+              <span>{{ file.name }}</span>
+            </span>
+            <span>
+              <SvgIcon icon-class="progress" size="12" />
+            </span>
+          </div>
+          <SvgIcon icon-class="delete-black" size="12" @click="removeFile(file, i)" />
+        </li>
+      </ul>
     </template>
   </ModuleBase>
 </template>
 
 <script>
 import { AudioData } from '@/views/book/courseware/data/audio';
-
 import ModuleMixin from '../../common/ModuleMixin';
+import { fileUpload, GetFileStoreInfo } from '@/api/app';
 
 export default {
-  name: 'Divider',
+  name: 'AudioPage',
   components: {},
   mixins: [ModuleMixin],
   data() {
     return {
       data: AudioData,
+      file_info_list: [],
     };
   },
-  computed: {
-    settingStyle() {
-      return {
-        margin: `${this.data.setting.height / 2}px 0`,
-        border: 'none',
-        borderTop: `1px ${this.data.setting.type} #ebebeb`,
-      };
+  computed: {},
+  watch: {
+    // fileIdList: {
+    //   handler(list) {
+    //     this.file_info_list = [];
+    //     if (!list || list.length === 0) return;
+    //     list.forEach((p) => {
+    //       GetFileStoreInfo({ file_id: p }).then((res) => {
+    //         this.file_info_list.push(res);
+    //       });
+    //     });
+    //   },
+    //   immediate: true,
+    // },
+  },
+  methods: {
+    onFileChange(file, fileList) {
+      console.log(fileList);
+      this.file_info_list = fileList;
+    },
+    removeFile(file, i) {
+      this.$refs.upload.handleRemove(file);
+      this.file_info_list.splice(i, 1);
+    },
+    beforeAudioUpload(file) {
+      const fileName = file.name;
+      const suffix = fileName.slice(fileName.lastIndexOf('.') + 1, fileName.length).toLowerCase();
+      const isNeedType = ['mp3', 'acc', 'wma'].includes(suffix);
+      if (!isNeedType) {
+        this.$message.error('音频文件只能是 mp3、acc、wma 格式!');
+        return false;
+      }
+
+      const isLt100M = file.size / 1024 / 1024 < 100;
+      if (!isLt100M) {
+        this.$message.error('单个音频文件大小不能超过 100MB!');
+        return false;
+      }
+
+      const isExceed1GB =
+        file.size + (this.$refs.upload.uploadFiles || []).reduce((acc, cur) => acc + cur.size, 0) > 1024 * 1024 * 1024;
+      // 限制总文件大小为 1GB
+      if (isExceed1GB) {
+        this.$message.error('总文件大小不能超过 1GB');
+        return false;
+      }
+    },
+    uploadAudio() {
+      this.$refs.upload.submit();
     },
   },
-  methods: {},
 };
 </script>
 
-<style lang="scss" scoped></style>
+<style lang="scss" scoped>
+.module-content {
+  .audio-area {
+    display: flex;
+    column-gap: 16px;
+    align-items: center;
+
+    .label-text {
+      font-size: 14px;
+      color: #4e5969;
+    }
+
+    div {
+      flex: 1;
+    }
+  }
+
+  .el-divider {
+    margin: 16px 0;
+  }
+
+  .upload-tip {
+    margin-bottom: 16px;
+    font-size: 12px;
+    color: #86909c;
+  }
+
+  .upload-box {
+    display: flex;
+    justify-content: space-between;
+
+    .audio-uploader {
+      flex: 1;
+
+      :deep .el-upload {
+        &--text {
+          width: 100%;
+          background-color: #f2f3f5;
+          border-radius: 2px 0 0 2px;
+
+          .el-button {
+            width: 100%;
+            color: #86909c;
+            text-align: left;
+          }
+        }
+      }
+    }
+
+    .el-button {
+      border-radius: 0 2px 2px 0;
+    }
+  }
+
+  .file-list {
+    display: flex;
+    flex-direction: column;
+    row-gap: 16px;
+
+    li {
+      display: flex;
+      column-gap: 12px;
+      align-items: center;
+
+      .file-name {
+        display: flex;
+        column-gap: 14px;
+        align-items: center;
+        justify-content: space-between;
+        width: 360px;
+        max-width: 360px;
+        padding: 8px 12px;
+        font-size: 14px;
+        color: #1d2129;
+        background-color: #f7f8fa;
+
+        span {
+          display: flex;
+          column-gap: 14px;
+          align-items: center;
+        }
+      }
+    }
+  }
+}
+</style>

+ 168 - 10
src/views/book/courseware/create/components/base/audio/AudioSetting.vue

@@ -2,16 +2,88 @@
   <div>
     <el-form :model="setting" :label-position="labelPosition" label-width="72px">
       <el-form-item label="序号" class="serial-number">
-        <el-input v-model="setting.question_number" />
+        <el-input v-model="setting.serialNumber" />
         <SvgIcon icon-class="switch" size="14" />
       </el-form-item>
       <el-form-item>
-        <el-radio v-for="{ value, label } in questionNumberTypeList" :key="value" :label="value">
+        <el-radio
+          v-for="{ value, label } in serialNumberTypeList"
+          :key="value"
+          v-model="setting.other.serial_number_type"
+          :label="value"
+        >
           {{ label }}
         </el-radio>
       </el-form-item>
       <el-form-item label="序号位置">
-        <el-radio v-for="{ value, label } in questionNumberTypeList" :key="value" :label="value">
+        <div class="grid-container">
+          <div class="top">
+            <el-button
+              :class="['top-start', { active: 'top-start' === setting.numberPosition }]"
+              @click="changeNumberPosition('top-start')"
+            />
+            <el-button
+              :class="['top', { active: 'top' === setting.numberPosition }]"
+              @click="changeNumberPosition('top')"
+            />
+            <el-button
+              :class="['top-end', { active: 'top-end' === setting.numberPosition }]"
+              @click="changeNumberPosition('top-end')"
+            />
+          </div>
+          <div class="left">
+            <el-button
+              :class="['left-start', { active: 'left-start' === setting.numberPosition }]"
+              @click="changeNumberPosition('left-start')"
+            />
+            <el-button
+              :class="['left', { active: 'left' === setting.numberPosition }]"
+              @click="changeNumberPosition('left')"
+            />
+            <el-button
+              :class="['left-end', { active: 'left-end' === setting.numberPosition }]"
+              @click="changeNumberPosition('left-end')"
+            />
+          </div>
+          <div class="main"></div>
+          <div class="right">
+            <el-button
+              :class="['right-start', { active: 'right-start' === setting.numberPosition }]"
+              @click="changeNumberPosition('right-start')"
+            />
+            <el-button
+              :class="['right', { active: 'right' === setting.numberPosition }]"
+              @click="changeNumberPosition('right')"
+            />
+            <el-button
+              :class="['right-end', { active: 'right-end' === setting.numberPosition }]"
+              @click="changeNumberPosition('right-end')"
+            />
+          </div>
+          <div class="bottom">
+            <el-button
+              :class="['bottom-start', { active: 'bottom-start' === setting.numberPosition }]"
+              @click="changeNumberPosition('bottom-start')"
+            />
+            <el-button
+              :class="['bottom', { active: 'bottom' === setting.numberPosition }]"
+              @click="changeNumberPosition('bottom')"
+            />
+            <el-button
+              :class="['bottom-end', { active: 'bottom-end' === setting.numberPosition }]"
+              @click="changeNumberPosition('bottom-end')"
+            />
+          </div>
+        </div>
+      </el-form-item>
+      <el-divider />
+      <el-form-item label="查看方式">
+        <el-radio
+          v-for="{ value, label } in audioViewingMethodsList"
+          :key="value"
+          v-model="setting.audioViewingMethods"
+          :label="value"
+        >
           {{ label }}
         </el-radio>
       </el-form-item>
@@ -20,18 +92,24 @@
 </template>
 
 <script>
-import ModuleMixin from '../../common/ModuleMixin';
+import { serialNumberTypeList, audioViewingMethodsList } from '@/views/book/courseware/data/common';
 
 export default {
-  name: 'DividerSetting',
-  mixins: [ModuleMixin],
+  name: 'AudioSetting',
   data() {
     return {
+      serialNumberTypeList,
+      audioViewingMethodsList,
       labelPosition: 'left',
       isSet: false, // 父组件是否已设置
       setting: {
-        height: 100,
-        type: 'solid',
+        serialNumber: 1, // 序号
+        numberPosition: 'top-start', // 序号位置
+        audioViewingMethods: audioViewingMethodsList[0].value, // 查看方式
+        // 其他属性
+        other: {
+          serial_number_type: serialNumberTypeList[0].value, // 题号类型
+        },
       },
     };
   },
@@ -54,6 +132,14 @@ export default {
       this.isSet = true;
       this.setting = setting;
     },
+
+    /**
+     * @description 改变序号位置
+     * @param {String} numberPosition
+     */
+    changeNumberPosition(numberPosition) {
+      this.setting.numberPosition = numberPosition;
+    },
   },
 };
 </script>
@@ -63,14 +149,86 @@ export default {
   .serial-number {
     :deep .el-form-item__content {
       display: flex;
-      column-gap: 16px;
       align-items: center;
+      justify-content: space-between;
     }
   }
 
   .el-input {
-    width: 100px;
     margin-right: 16px;
   }
+
+  .top {
+    grid-area: top;
+    column-gap: 8px;
+    justify-content: center;
+  }
+
+  .left {
+    flex-direction: column;
+    grid-area: left;
+    row-gap: 4px;
+  }
+
+  .main {
+    grid-area: main;
+  }
+
+  .right {
+    flex-direction: column;
+    grid-area: right;
+    row-gap: 4px;
+  }
+
+  .bottom {
+    grid-area: bottom;
+    column-gap: 8px;
+    justify-content: center;
+  }
+
+  .grid-container {
+    display: grid;
+    grid:
+      'top top top top top top'
+      'left main main main main right'
+      'bottom bottom bottom bottom bottom bottom';
+    width: 134px;
+    height: 80px;
+    padding: 8px 8px 0;
+    line-height: 10px;
+    border: 1px solid #ebebeb;
+
+    div {
+      display: flex;
+      margin: 0 auto;
+      text-align: center;
+      background-color: rgba(255, 255, 255, 8%);
+
+      .el-button {
+        width: 16px;
+        height: 8px;
+        padding: 0;
+        margin: 0;
+        border: 1px solid #e4e4e4;
+        border-radius: 2px;
+
+        &.active {
+          background-color: $setting-active-color;
+        }
+      }
+    }
+
+    .main {
+      width: 64px;
+      height: 32px;
+      background-color: #f8f8f8;
+      border: 1px solid #e4e4e4;
+      border-radius: 2px;
+    }
+  }
+
+  .el-divider {
+    margin: 16px 0;
+  }
 }
 </style>

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

@@ -0,0 +1,141 @@
+<template>
+  <ModuleBase :type="data.type">
+    <template #content>
+      <div class="audio-area">
+        <span class="label-text">音频</span>
+        <div class="upload-box">
+          <el-upload
+            class="picture-uploader"
+            action="no"
+            accept=".mp3,.acc,.wma"
+            :show-file-list="false"
+            :auto-upload="false"
+            :before-upload="beforePictureUpload"
+          >
+            <el-button>选取图片文件</el-button>
+          </el-upload>
+          <el-button size="small" type="primary" @click="uploadPicture">上传</el-button>
+        </div>
+      </div>
+      <el-divider />
+      <div class="upload-tip">支持上传mp3、acc、wma,等格式音频文件,单个文件最大100MB,总文件体积不超1G。</div>
+      <ul class="file-list">
+        <li v-for="({ name, url }, i) in fileList" :key="url">
+          <div class="file-name">
+            <SvgIcon icon-class="picture" size="12" />
+            <span>{{ name }}</span>
+          </div>
+          <SvgIcon icon-class="delete-black" size="12" @click="removeFile(i)" />
+        </li>
+      </ul>
+    </template>
+  </ModuleBase>
+</template>
+
+<script>
+import { PictureData } from '@/views/book/courseware/data/picture';
+import ModuleMixin from '../../common/ModuleMixin';
+
+export default {
+  name: 'PicturePage',
+  components: {},
+  mixins: [ModuleMixin],
+  data() {
+    return {
+      data: PictureData,
+      fileList: [
+        {
+          name: 'food.jpeg',
+          url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'
+        },
+        {
+          name: 'food2.jpeg',
+          url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100'
+        },
+      ],
+    };
+  },
+  computed: {},
+  methods: {},
+};
+</script>
+
+<style lang="scss" scoped>
+.module-content {
+  .audio-area {
+    display: flex;
+    column-gap: 16px;
+    align-items: center;
+
+    .label-text {
+      font-size: 14px;
+      color: #4e5969;
+    }
+
+    div {
+      flex: 1;
+    }
+  }
+
+  .el-divider {
+    margin: 16px 0;
+  }
+
+  .upload-tip {
+    margin-bottom: 16px;
+    font-size: 12px;
+    color: #86909c;
+  }
+
+  .upload-box {
+    display: flex;
+    justify-content: space-between;
+
+    .picture-uploader {
+      flex: 1;
+
+      :deep .el-upload {
+        &--text {
+          width: 100%;
+          background-color: #f2f3f5;
+          border-radius: 2px 0 0 2px;
+
+          .el-button {
+            width: 100%;
+            color: #86909c;
+            text-align: left;
+          }
+        }
+      }
+    }
+
+    .el-button {
+      border-radius: 0 2px 2px 0;
+    }
+  }
+
+  .file-list {
+    display: flex;
+    flex-direction: column;
+    row-gap: 16px;
+
+    li {
+      display: flex;
+      column-gap: 12px;
+      align-items: center;
+
+      .file-name {
+        display: flex;
+        column-gap: 14px;
+        align-items: center;
+        width: 360px;
+        max-width: 360px;
+        padding: 8px 12px;
+        font-size: 14px;
+        color: #1d2129;
+        background-color: #f7f8fa;
+      }
+    }
+  }
+}
+</style>

+ 234 - 0
src/views/book/courseware/create/components/base/picture/PictureSetting.vue

@@ -0,0 +1,234 @@
+<template>
+  <div>
+    <el-form :model="setting" :label-position="labelPosition" label-width="72px">
+      <el-form-item label="序号" class="serial-number">
+        <el-input v-model="setting.serialNumber" />
+        <SvgIcon icon-class="switch" size="14" />
+      </el-form-item>
+      <el-form-item>
+        <el-radio
+          v-for="{ value, label } in serialNumberTypeList"
+          :key="value"
+          v-model="setting.other.serial_number_type"
+          :label="value"
+        >
+          {{ label }}
+        </el-radio>
+      </el-form-item>
+      <el-form-item label="序号位置">
+        <div class="grid-container">
+          <div class="top">
+            <el-button
+              :class="['top-start', { active: 'top-start' === setting.numberPosition }]"
+              @click="changeNumberPosition('top-start')"
+            />
+            <el-button
+              :class="['top', { active: 'top' === setting.numberPosition }]"
+              @click="changeNumberPosition('top')"
+            />
+            <el-button
+              :class="['top-end', { active: 'top-end' === setting.numberPosition }]"
+              @click="changeNumberPosition('top-end')"
+            />
+          </div>
+          <div class="left">
+            <el-button
+              :class="['left-start', { active: 'left-start' === setting.numberPosition }]"
+              @click="changeNumberPosition('left-start')"
+            />
+            <el-button
+              :class="['left', { active: 'left' === setting.numberPosition }]"
+              @click="changeNumberPosition('left')"
+            />
+            <el-button
+              :class="['left-end', { active: 'left-end' === setting.numberPosition }]"
+              @click="changeNumberPosition('left-end')"
+            />
+          </div>
+          <div class="main"></div>
+          <div class="right">
+            <el-button
+              :class="['right-start', { active: 'right-start' === setting.numberPosition }]"
+              @click="changeNumberPosition('right-start')"
+            />
+            <el-button
+              :class="['right', { active: 'right' === setting.numberPosition }]"
+              @click="changeNumberPosition('right')"
+            />
+            <el-button
+              :class="['right-end', { active: 'right-end' === setting.numberPosition }]"
+              @click="changeNumberPosition('right-end')"
+            />
+          </div>
+          <div class="bottom">
+            <el-button
+              :class="['bottom-start', { active: 'bottom-start' === setting.numberPosition }]"
+              @click="changeNumberPosition('bottom-start')"
+            />
+            <el-button
+              :class="['bottom', { active: 'bottom' === setting.numberPosition }]"
+              @click="changeNumberPosition('bottom')"
+            />
+            <el-button
+              :class="['bottom-end', { active: 'bottom-end' === setting.numberPosition }]"
+              @click="changeNumberPosition('bottom-end')"
+            />
+          </div>
+        </div>
+      </el-form-item>
+      <el-divider />
+      <el-form-item label="查看方式">
+        <el-radio
+          v-for="{ value, label } in viewingMethodsList"
+          :key="value"
+          v-model="setting.viewingMethods"
+          :label="value"
+        >
+          {{ label }}
+        </el-radio>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import { serialNumberTypeList, viewingMethodsList } from '@/views/book/courseware/data/common';
+
+export default {
+  name: 'AudioSetting',
+  data() {
+    return {
+      serialNumberTypeList,
+      viewingMethodsList,
+      labelPosition: 'left',
+      isSet: false, // 父组件是否已设置
+      setting: {
+        serialNumber: 1, // 序号
+        numberPosition: 'top-start', // 序号位置
+        viewingMethods: viewingMethodsList[0].value, // 查看方式
+        // 其他属性
+        other: {
+          serial_number_type: serialNumberTypeList[0].value, // 题号类型
+        },
+      },
+    };
+  },
+  watch: {
+    setting: {
+      handler(val) {
+        if (this.isSet) {
+          this.$emit('updateSetting', val);
+        }
+      },
+      deep: true,
+    },
+  },
+  methods: {
+    /**
+     * @description 设置属性
+     * @param {Object} setting 属性
+     */
+    setSetting(setting) {
+      this.isSet = true;
+      this.setting = setting;
+    },
+
+    /**
+     * @description 改变序号位置
+     * @param {String} numberPosition
+     */
+    changeNumberPosition(numberPosition) {
+      this.setting.numberPosition = numberPosition;
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.el-form {
+  .serial-number {
+    :deep .el-form-item__content {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+    }
+  }
+
+  .el-input {
+    margin-right: 16px;
+  }
+
+  .top {
+    grid-area: top;
+    column-gap: 8px;
+    justify-content: center;
+  }
+
+  .left {
+    flex-direction: column;
+    grid-area: left;
+    row-gap: 4px;
+  }
+
+  .main {
+    grid-area: main;
+  }
+
+  .right {
+    flex-direction: column;
+    grid-area: right;
+    row-gap: 4px;
+  }
+
+  .bottom {
+    grid-area: bottom;
+    column-gap: 8px;
+    justify-content: center;
+  }
+
+  .grid-container {
+    display: grid;
+    grid:
+      'top top top top top top'
+      'left main main main main right'
+      'bottom bottom bottom bottom bottom bottom';
+    width: 134px;
+    height: 80px;
+    padding: 8px 8px 0;
+    line-height: 10px;
+    border: 1px solid #ebebeb;
+
+    div {
+      display: flex;
+      margin: 0 auto;
+      text-align: center;
+      background-color: rgba(255, 255, 255, 8%);
+
+      .el-button {
+        width: 16px;
+        height: 8px;
+        padding: 0;
+        margin: 0;
+        border: 1px solid #e4e4e4;
+        border-radius: 2px;
+
+        &.active {
+          background-color: $setting-active-color;
+        }
+      }
+    }
+
+    .main {
+      width: 64px;
+      height: 32px;
+      background-color: #f8f8f8;
+      border: 1px solid #e4e4e4;
+      border-radius: 2px;
+    }
+  }
+
+  .el-divider {
+    margin: 16px 0;
+  }
+}
+</style>

+ 4 - 2
src/views/book/courseware/create/components/common/ModuleMixin.js

@@ -1,11 +1,13 @@
 // 组件混入
 import ModuleBase from './ModuleBase.vue';
-import { questionNumberTypeList } from '@/views/book/courseware/data/common';
+import { serialNumberTypeList, viewingMethodsList, audioViewingMethodsList } from '@/views/book/courseware/data/common';
 
 const mixin = {
   data() {
     return {
-      questionNumberTypeList,
+      serialNumberTypeList,
+      viewingMethodsList,
+      audioViewingMethodsList,
     };
   },
   props: {

+ 9 - 2
src/views/book/courseware/data/audio.js

@@ -1,8 +1,15 @@
+import { serialNumberTypeList, audioViewingMethodsList } from '@/views/book/courseware/data/common';
+
 export let AudioData = {
   type: 'audio',
   title: '音频',
   setting: {
-    serialNumber: 1,
-    height: 40,
+    serialNumber: 1, // 序号
+    numberPosition: 'top-start', // 序号位置
+    audioViewingMethods: audioViewingMethodsList[0].value, // 查看方式
+    // 其他属性
+    other: {
+      serial_number_type: serialNumberTypeList[0].value, // 题号类型
+    },
   },
 };

+ 4 - 2
src/views/book/courseware/data/bookType.js

@@ -4,6 +4,8 @@ import SpacingPage from '../create/components/base/spacing/Spacing.vue';
 import SpacingSetting from '../create/components/base/spacing/SpacingSetting.vue';
 import AudioPage from '../create/components/base/audio/Audio.vue';
 import AudioSetting from '../create/components/base/audio/AudioSetting.vue';
+import PicturePage from '../create/components/base/picture/Picture.vue';
+import PictureSetting from '../create/components/base/picture/PictureSetting.vue';
 
 export const bookTypeOption = [
   {
@@ -50,8 +52,8 @@ export const bookTypeOption = [
         value: 'picture',
         label: '图片',
         icon: 'picture',
-        component: '',
-        set: '',
+        component: PicturePage,
+        set: PictureSetting,
       },
       {
         value: 'divider',

+ 15 - 2
src/views/book/courseware/data/common.js

@@ -1,5 +1,18 @@
-// 号类型
-export const questionNumberTypeList = [
+// 号类型
+export const serialNumberTypeList = [
   { value: 'recalculate', label: '重新计算' },
   { value: 'follow', label: '跟随上题' },
 ];
+
+// 查看方式
+export const viewingMethodsList = [
+  { value: 'independent', label: '独立排放' },
+  { value: 'list', label: '播放列表' },
+];
+
+// 查看方式
+export const audioViewingMethodsList = [
+  { value: 'independent', label: '独立' },
+  { value: 'list', label: '列表' },
+  { value: 'icon', label: '图标' },
+];

+ 15 - 0
src/views/book/courseware/data/picture.js

@@ -0,0 +1,15 @@
+import { serialNumberTypeList, viewingMethodsList } from '@/views/book/courseware/data/common';
+
+export let PictureData = {
+  type: 'picture',
+  title: '图片',
+  setting: {
+    serialNumber: 1, // 序号
+    numberPosition: 'top-start', // 序号位置
+    viewingMethods: viewingMethodsList[0].value, // 查看方式
+    // 其他属性
+    other: {
+      serial_number_type: serialNumberTypeList[0].value, // 题号类型
+    },
+  },
+};