Browse Source

Merge branch 'master' of http://60.205.254.193:3000/GCLS/GCLS_Page_Textbook

dusenyao 5 days ago
parent
commit
27bbb70409

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

@@ -33,8 +33,8 @@ export default {
     return {
       data: getAudioData(),
       labelText: '音频',
-      acceptFileType: '.mp3,.acc,.wma',
-      uploadTip: '支持上传mp3、acc、wma,等格式音频文件,单个文件最大100MB,总文件体积不超1G。',
+      acceptFileType: '.mp3,.acc,.wma,.wav',
+      uploadTip: '支持上传mp3、acc、wma、.wav,等格式音频文件,单个文件最大100MB,总文件体积不超1G。',
       iconClass: 'note',
     };
   },

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

@@ -31,7 +31,15 @@
             <span>{{ file.file_name ?? file.name }}</span>
             <!-- <span>({{ file.size }})</span> -->
           </span>
-          <span v-if="file.progress > 0 && file.progress < 100"> {{ file.progress }}% </span>
+          <el-progress
+            v-if="file.progress > 0 && file.progress < 100"
+            type="circle"
+            :percentage="file.progress"
+            width="20"
+            color="#2A5AF6"
+            stroke-linecap="butt"
+            :show-text="false"
+          />
           <span v-else-if="file.file_id"> 完成 </span>
         </div>
         <SvgIcon icon-class="delete-black" size="12" @click="removeFile(file, i)" />
@@ -210,8 +218,8 @@ export default {
       let typeTip = '';
 
       if (this.type === 'audio') {
-        fileType = ['mp3', 'acc', 'wma'];
-        typeTip = '音频文件只能是 mp3、acc、wma 格式!';
+        fileType = ['mp3', 'acc', 'wma', 'wav'];
+        typeTip = '音频文件只能是 mp3、acc、wma、wav格式!';
       } else if (this.type === 'picture') {
         fileType = ['jpg', 'png', 'jpeg'];
         typeTip = '图片文件只能是 jpg、png、jpeg 格式!';

+ 30 - 3
src/views/book/courseware/create/components/base/divider/Divider.vue

@@ -1,14 +1,14 @@
 <template>
   <ModuleBase :type="data.type">
     <template #content>
-      <hr :style="settingStyle" />
+      <div v-if="'wavy' === data.property.line_type" class="wavy" :style="settingWavyStyle"></div>
+      <hr v-else :style="settingStyle" />
     </template>
   </ModuleBase>
 </template>
 
 <script>
 import { getDividerData } from '@/views/book/courseware/data/divider';
-
 import ModuleMixin from '../../common/ModuleMixin';
 
 export default {
@@ -24,10 +24,37 @@ export default {
       return {
         margin: `${this.data.property.height / 2}px 0`,
         border: 'none',
-        borderTop: `1px ${this.data.property.line_type} #ebebeb`,
+        borderTop: `1px ${this.data.property.line_type} ${this.data.property.color}`,
+        width: `${this.data.property.width}px`,
+      };
+    },
+    settingWavyStyle() {
+      return {
+        margin: `${this.data.property.height / 2}px 0`,
+        width: `${this.data.property.width}px`,
+        height: '10px',
+        color: `${this.data.property.color}`,
+        letterSpacing: `${this.data.property.width}px`,
       };
     },
   },
   methods: {},
 };
 </script>
+<style lang="scss" scoped>
+.wavy {
+  display: block;
+  padding-top: 0.5em;
+  overflow: hidden;
+  white-space: nowrap;
+}
+
+.wavy::before {
+  /* IE浏览器实线代替 */
+  text-decoration: overline;
+
+  /* 现代浏览器 */
+  text-decoration: overline wavy;
+  content: '\2000';
+}
+</style>

+ 11 - 1
src/views/book/courseware/create/components/base/divider/DividerSetting.vue

@@ -6,15 +6,22 @@
       </el-form-item>
       <el-form-item label="类型">
         <el-select v-model="property.line_type">
-          <el-option label="实线" value="solid" />
+          <el-option v-for="(line, i) in lineTypeList" :key="i" :label="line.string" :value="line.value" />
         </el-select>
       </el-form-item>
+      <el-form-item label="颜色">
+        <el-color-picker v-model="property.color" />
+      </el-form-item>
+      <el-form-item label="线宽">
+        <el-input v-model="property.width" />
+      </el-form-item>
     </el-form>
   </div>
 </template>
 
 <script>
 import SettingMixin from '@/views/book/courseware/create/components/common/SettingMixin';
+import { lineTypeList } from '@/views/book/courseware/data/divider';
 
 export default {
   name: 'DividerSetting',
@@ -25,7 +32,10 @@ export default {
       property: {
         height: 100,
         type: 'solid',
+        width: 920,
+        color: '#FF0000',
       },
+      lineTypeList,
     };
   },
   methods: {},

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

@@ -34,7 +34,7 @@ export default {
       data: getPictureData(),
       labelText: '图片',
       acceptFileType: '.jpg,.png,.jpeg',
-      uploadTip: '支持上传jpg、png、jpeg,等格式图片文件,单个文件最大1MB,总文件体积不超100MB。',
+      uploadTip: '支持上传jpg、png、jpeg,等格式图片文件,单个文件最大2MB,总文件体积不超40MB。',
       iconClass: 'picture',
     };
   },

+ 13 - 1
src/views/book/courseware/create/components/base/picture/PictureSetting.vue

@@ -8,13 +8,24 @@
           {{ label }}
         </el-radio>
       </el-form-item>
+      <el-form-item label="备注">
+        <el-radio
+          v-for="{ value, label } in switchOption"
+          :key="value"
+          v-model="property.view_memo"
+          :label="value"
+          :disabled="'list' !== property.view_method"
+        >
+          {{ label }}
+        </el-radio>
+      </el-form-item>
     </el-form>
   </div>
 </template>
 
 <script>
 import SettingMixin from '@/views/book/courseware/create/components/common/SettingMixin';
-import { viewMethodList } from '@/views/book/courseware/data/common';
+import { viewMethodList, switchOption } from '@/views/book/courseware/data/common';
 import { getPictureProperty } from '@/views/book/courseware/data/picture';
 
 export default {
@@ -25,6 +36,7 @@ export default {
       viewMethodList,
       labelPosition: 'left',
       property: getPictureProperty(),
+      switchOption,
     };
   },
   methods: {},

+ 2 - 2
src/views/book/courseware/create/components/common/FillDescribe.vue

@@ -1,7 +1,7 @@
 <template>
   <el-dialog :visible="visible" width="260px" top="38vh" :show-close="false" @close="dialogClose">
-    <el-input v-model="file.title" autocomplete="off" placeholder="标题" />
-    <el-input v-model="file.intro" type="textarea" placeholder="介绍" />
+    <el-input v-model="file.title" autocomplete="off" placeholder="标题" maxlength="20" :show-word-limit="true" />
+    <el-input v-model="file.intro" type="textarea" placeholder="介绍" maxlength="200" :show-word-limit="true" />
     <template slot="footer">
       <el-button size="medium" @click="dialogClose">取消</el-button>
       <el-button type="primary" size="medium" @click="confirm">确定</el-button>

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

@@ -6,6 +6,17 @@ export function getDividerData() {
     property: {
       height: 40,
       line_type: 'solid', // dotted 虚线
+      color: '#FF0000',
+      width: 920,
     },
   };
 }
+
+// 线条样式
+export const lineTypeList = [
+  { string: '实线', value: 'solid' },
+  { string: '虚线', value: 'dashed' },
+  { string: '点状', value: 'dotted' },
+  { string: '波浪线', value: 'wavy' },
+  { string: '不显示', value: 'none' },
+];

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

@@ -3,6 +3,7 @@ import {
   viewMethodList,
   serialNumberTypeList,
   serialNumberPositionList,
+  switchOption,
 } from '@/views/book/courseware/data/common';
 
 export function getPictureProperty() {
@@ -12,6 +13,7 @@ export function getPictureProperty() {
     sn_position: serialNumberPositionList[0].value, // 序号位置:top-start top top-end,left-start left left-end等
     sn_display_mode: displayList[0].value, // 序号显示方式:true显示 false隐藏
     view_method: viewMethodList[0].value, // 查看方式:independent独立 list列表
+    view_memo: switchOption[0].value,
   };
 }
 
@@ -19,8 +21,8 @@ export function getPictureData() {
   return {
     type: 'picture',
     title: '图片',
-    single_size: 1, // 单位MB
-    total_size: 100, // 单位MB
+    single_size: 2, // 单位MB
+    total_size: 40, // 单位MB
     min_width: '144', // 大于等于最小缩略图宽度
     min_height: '306', // 大于等于2倍缩略图宽度加间隙高度
     property: getPictureProperty(),

+ 31 - 3
src/views/book/courseware/preview/components/divider/DividerPreview.vue

@@ -1,5 +1,6 @@
 <template>
-  <hr :style="settingStyle" />
+  <div v-if="'wavy' === data.property.line_type" class="wavy" :style="settingWavyStyle"></div>
+  <hr v-else :style="settingStyle" />
 </template>
 
 <script>
@@ -17,8 +18,18 @@ export default {
   computed: {
     settingStyle() {
       return {
-        margin: `${this.data.property.height / 2}px 0`,
-        borderTopStyle: this.data.property.line_type,
+        margin: `${this.data.property.height / 2}px auto ${this.data.property.height / 2}px`,
+        border: 'none',
+        borderTop: `1px ${this.data.property.line_type} ${this.data.property.color}`,
+        width: `${this.data.property.width}px`,
+      };
+    },
+    settingWavyStyle() {
+      return {
+        margin: `${this.data.property.height / 2}px auto ${this.data.property.height / 2}px`,
+        width: `${this.data.property.width}px`,
+        color: `${this.data.property.color}`,
+        letterSpacing: `${this.data.property.width}px`,
       };
     },
   },
@@ -31,4 +42,21 @@ hr {
   border-top-color: #ebebeb;
   border-top-width: 1px;
 }
+
+.wavy {
+  display: block;
+  height: 11px !important;
+  padding-top: 0.5em;
+  overflow: hidden;
+  white-space: nowrap;
+}
+
+.wavy::before {
+  /* IE浏览器实线代替 */
+  text-decoration: overline;
+
+  /* 现代浏览器 */
+  text-decoration: overline wavy;
+  content: '\2000';
+}
 </style>

+ 71 - 35
src/views/book/courseware/preview/components/picture/PicturePreview.vue

@@ -1,40 +1,53 @@
 <template>
   <div ref="pictureArea" class="picture-area" :style="getAreaStyle()">
     <SerialNumberPosition v-if="isEnable(data.property.sn_display_mode)" :property="data.property" />
-
     <div ref="pictureAreaBox" class="main">
       <div class="view-area">
-        <template v-if="'list' === data.property.view_method">
-          <el-carousel
-            ref="pictureCarousel"
-            class="view-list"
-            indicator-position="none"
-            :autoplay="false"
-            :style="{ height: elementHeight - 144 - 17 + 'px' }"
-          >
-            <el-carousel-item v-for="(file, i) in data.file_list" :key="i">
+        <div class="picture-area">
+          <template v-if="'list' === data.property.view_method">
+            <el-carousel
+              ref="pictureCarousel"
+              class="view-list"
+              indicator-position="none"
+              :autoplay="false"
+              :style="{ height: elementHeight - 144 - 17 + 'px' }"
+              @change="handleChange"
+            >
+              <el-carousel-item v-for="(file, i) in data.file_list" :key="i">
+                <el-image
+                  :id="file.file_id"
+                  :src="file.file_url"
+                  fit="contain"
+                  :preview-src-list="data.file_list.map((x) => x.file_url)"
+                />
+              </el-carousel-item>
+            </el-carousel>
+            <div class="container-box">
+              <button v-if="viewLeftRightBtn" class="arrow left" @click="scroll(-1)">
+                <i class="el-icon-arrow-left"></i>
+              </button>
+              <ul ref="container" class="view-list-bottom" :style="{ width: elementWidth + 'px' }">
+                <li v-for="(file, i) in data.file_list" :key="i" @click="handleIndicatorClick(i)">
+                  <el-image :id="file.file_id" :src="file.file_url" fit="contain" />
+                </li>
+              </ul>
+              <button v-if="viewLeftRightBtn" class="arrow right" @click="scroll(1)">
+                <i class="el-icon-arrow-right"></i>
+              </button>
+            </div>
+          </template>
+          <ul v-else class="view-independent">
+            <li v-for="(file, i) in data.file_list" :key="i" @click="handleIndicatorClick(i)">
               <el-image :id="file.file_id" :src="file.file_url" fit="contain" />
-            </el-carousel-item>
-          </el-carousel>
-          <div class="container-box">
-            <button v-if="viewLeftRightBtn" class="arrow left" @click="scroll(-1)">
-              <i class="el-icon-arrow-left"></i>
-            </button>
-            <ul ref="container" class="view-list-bottom" :style="{ width: elementWidth + 'px' }">
-              <li v-for="(file, i) in data.file_list" :key="i" @click="handleIndicatorClick(i)">
-                <el-image :id="file.file_id" :src="file.file_url" fit="contain" />
-              </li>
-            </ul>
-            <button v-if="viewLeftRightBtn" class="arrow right" @click="scroll(1)">
-              <i class="el-icon-arrow-right"></i>
-            </button>
+            </li>
+          </ul>
+        </div>
+        <div v-if="'list' === data.property.view_method && isEnable(data.property.view_memo)" class="memo-area">
+          <div v-for="(file, i) in data.file_info_list" :key="i">
+            <div class="title-div" v-if="curPictureMemoIndex === i">{{ file.title ?? file.title }}</div>
+            <div class="memo-div" v-if="curPictureMemoIndex === i">{{ file.intro ?? file.intro }}</div>
           </div>
-        </template>
-        <ul v-else class="view-independent">
-          <li v-for="(file, i) in data.file_list" :key="i" @click="handleIndicatorClick(i)">
-            <el-image :id="file.file_id" :src="file.file_url" fit="contain" />
-          </li>
-        </ul>
+        </div>
       </div>
     </div>
   </div>
@@ -58,6 +71,7 @@ export default {
       fileLen: 0,
       elementID: '',
       pictureObserversMap: {},
+      curPictureMemoIndex: 0,
     };
   },
   watch: {
@@ -70,12 +84,13 @@ export default {
           // this.elementHeight = ele.clientHeight;
 
           const sn_position = this.data.property.sn_position;
+          const viewMemo = this.isEnable(this.data.property.view_memo);
           // 序号在左和右补齐序号高度,去掉padding(8*2)
           if (sn_position.includes('left') || sn_position.includes('right')) {
-            this.elementWidth = ele.clientWidth - 16;
+            this.elementWidth = viewMemo ? (ele.clientWidth - 16) * 0.8 : ele.clientWidth - 16;
             this.elementHeight = ele.clientHeight + 30;
           } else {
-            this.elementWidth = ele.clientWidth;
+            this.elementWidth = viewMemo ? ele.clientWidth * 0.8 : ele.clientWidth;
             this.elementHeight = ele.clientHeight;
           }
 
@@ -110,12 +125,13 @@ export default {
         for (let entry of entries) {
           window.requestAnimationFrame(() => {
             const sn_position = this.data.property.sn_position;
+            const viewMemo = this.isEnable(this.data.property.view_memo);
             // 序号在上方和下方减去序号高度,在左右去掉padding(8*2)
             if (sn_position.includes('top') || sn_position.includes('bottom')) {
-              this.elementWidth = entry.contentRect.width;
+              this.elementWidth = viewMemo ? entry.contentRect.width * 0.8 : entry.contentRect.width;
               this.elementHeight = entry.contentRect.height - 30;
             } else {
-              this.elementWidth = entry.contentRect.width - 16;
+              this.elementWidth = viewMemo ? (entry.contentRect.width - 16) * 0.8 : entry.contentRect.width - 16;
               this.elementHeight = entry.contentRect.height;
             }
           });
@@ -151,6 +167,10 @@ export default {
       const carousel = this.$refs.pictureCarousel;
       // 切换到对应索引的图片
       carousel.setActiveItem(index);
+      this.curPictureMemoIndex = index;
+    },
+    handleChange(index) {
+      this.curPictureMemoIndex = index;
     },
     // 滚动图片列表
     scroll(direction) {
@@ -167,6 +187,7 @@ export default {
 .picture-area {
   display: grid;
   gap: 6px;
+  float: left;
   padding: 8px;
 
   > .main {
@@ -183,7 +204,22 @@ export default {
     width: 100%;
 
     .view-area {
-      width: 100%;
+      .memo-area {
+        float: left;
+        width: 15%;
+        padding-left: 5px;
+        border-left: 1px solid #eee;
+
+        .title-div {
+          font-size: 16px;
+          font-weight: 600;
+        }
+
+        .memo-div {
+          color: #706f78;
+          overflow-wrap: break-word;
+        }
+      }
 
       :deep .el-carousel {
         margin-bottom: 17px;