2 Commity 407a241b8d ... d8eac19822

Autor SHA1 Wiadomość Data
  dsy d8eac19822 ctrl+c复制组件 5 dni temu
  dsy 337aa80c4e 问题修改 5 dni temu

+ 1 - 1
.env

@@ -11,4 +11,4 @@ VUE_APP_BookWebSI = '/GCLSBookWebSI/ServiceInterface'
 VUE_APP_EepServer = '/EEPServer/SI'
 
 #version
-VUE_APP_VERSION = '2026.04.06'
+VUE_APP_VERSION = '2026.04.09'

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "eep_page",
-  "version": "2026.04.06",
+  "version": "2026.04.09",
   "private": true,
   "main": "main.js",
   "description": "智慧梧桐数字教材编辑器",

+ 4 - 1
src/components/CommonPreview.vue

@@ -88,7 +88,10 @@
       <div
         ref="previewMain"
         class="main-container"
-        :style="{ paddingLeft: navigationShow ? '15px' : '315px', paddingRight: sidebarShow ? '15px' : '315px' }"
+        :style="{
+          paddingLeft: !isFullScreen && navigationShow ? '15px' : '315px',
+          paddingRight: !isFullScreen && sidebarShow ? '15px' : '315px',
+        }"
       >
         <!-- 左侧菜单栏 - 收缩 -->
         <div v-if="!navigationShow && !isFullScreen" class="catalogue-bar" @click="toggleNavigationShow">

+ 11 - 0
src/views/book/courseware/create/components/CreateCanvas.vue

@@ -360,12 +360,23 @@ export default {
   mounted() {
     document.addEventListener('mousemove', this.dragMove);
     document.addEventListener('mouseup', this.dragEnd);
+    window.addEventListener('keydown', this.handleCopy);
   },
   beforeDestroy() {
     document.removeEventListener('mousemove', this.dragMove);
     document.removeEventListener('mouseup', this.dragEnd);
+    window.removeEventListener('keydown', this.handleCopy);
   },
   methods: {
+    /**
+     * 监听复制事件,触发复制组件方法
+     * @param {KeyboardEvent} event 键盘事件
+     */
+    handleCopy(event) {
+      if (event.ctrlKey && event.key === 'c' && this.curComponentId.length > 0) {
+        this.findChildComponentByKey(`grid-${this.curComponentId}`)?.copyComponent();
+      }
+    },
     handleHeightChange(id, newHeight) {
       this.data.row_list.forEach((row) => {
         row.col_list.forEach((col) => {

+ 3 - 1
src/views/book/courseware/create/components/SetBackground.vue

@@ -66,6 +66,7 @@
                 v-for="mode in imageModeList"
                 :key="mode.value"
                 :class="{ active: mode.value === background.imageMode }"
+                :style="{ fontSize: mode.value === imageModeList[3].value ? '12px' : '' }"
                 @click="background.imageMode = mode.value"
               >
                 {{ mode.label }}
@@ -213,7 +214,7 @@ export default {
         { label: '平铺', value: 'fill' },
         { label: '拉伸', value: 'stretch' },
         { label: '适应', value: 'adapt' },
-        { label: '自定', value: 'auto' },
+        { label: '自定', value: 'auto' },
       ],
     };
   },
@@ -859,6 +860,7 @@ export default {
           span {
             flex: 1;
             padding: 2px 6px;
+            line-height: 21px;
             text-align: center;
             cursor: pointer;
 

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

@@ -4,9 +4,19 @@
       <span class="label-text">{{ labelText }}</span>
       <div class="upload-box">
         <!-- style="pointer-events: none;" -->
-        <el-upload ref="upload" class="file-uploader" action="no" :accept="acceptFileType"
-          :multiple="limit === null || limit > 1" :show-file-list="false" :auto-upload="false" :file-list="fileList"
-          :on-change="onFileChange" :on-exceed="handleExceed" :limit="limit">
+        <el-upload
+          ref="upload"
+          class="file-uploader"
+          action="no"
+          :accept="acceptFileType"
+          :multiple="limit === null || limit > 1"
+          :show-file-list="false"
+          :auto-upload="false"
+          :file-list="fileList"
+          :on-change="onFileChange"
+          :on-exceed="handleExceed"
+          :limit="limit"
+        >
           <el-button>{{ type === 'h5_games' ? '选择Zip压缩包或单个html文件' : '选取' + labelText + '文件' }}</el-button>
         </el-upload>
         <el-button size="small" type="primary" @click="selectAndUpload">本地上传</el-button>
@@ -35,41 +45,75 @@
             }}</span>
             <!-- <span>({{ file.size }})</span> -->
           </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" />
+          <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)" />
-        <SvgIcon v-show="type === 'picture' && file.file_id" icon-class="mark" size="12"
-          @click="viewDialog(file.file_id)" />
+        <SvgIcon
+          v-show="type === 'picture' && file.file_id"
+          icon-class="mark"
+          size="12"
+          @click="viewDialog(file.file_id)"
+        />
         <!-- 编辑名称和序号 -->
         <template v-if="canEditName && file.file_id">
-          <SvgIcon v-if="content.file_info[file.file_id].isEdit" icon-class="icon-save" size="12"
-            @click="changeIsEdit(content.file_info[file.file_id])" />
+          <SvgIcon
+            v-if="content.file_info[file.file_id].isEdit"
+            icon-class="icon-save"
+            size="12"
+            @click="changeIsEdit(content.file_info[file.file_id])"
+          />
           <SvgIcon v-else icon-class="icon-edit" size="12" @click="changeIsEdit(content.file_info[file.file_id])" />
         </template>
 
         <el-tooltip effect="dark" placement="top" content="提交到资源库">
-          <SvgIcon v-if="isEnable(projectResourcePopedom.is_can_upload) && file.file_id" icon-class="upload"
-            @click="handleSubmitToResource(file)" />
+          <SvgIcon
+            v-if="isEnable(projectResourcePopedom.is_can_upload) && file.file_id"
+            icon-class="upload"
+            @click="handleSubmitToResource(file)"
+          />
         </el-tooltip>
 
-        <SvgIcon v-if="isEnable(projectResourcePopedom.is_can_download) && file.file_id" icon-class="download"
-          @click="downLoad(file)" />
+        <SvgIcon
+          v-if="isEnable(projectResourcePopedom.is_can_download) && file.file_id"
+          icon-class="download"
+          @click="downLoad(file)"
+        />
       </li>
     </ul>
 
     <FillDescribe :file-data="curFile" :visible.sync="visible" @fillDescribeToFile="fillDescribeToFile" />
 
-    <SelectResource :visible.sync="visibleResource" :project-id="project_id" :accept="accept"
-      :courseware-id="courseware_id" @selectResource="selectResource" />
-
-    <el-dialog :visible.sync="visibleSubmitResource" width="500px" append-to-body :show-close="true" title="提交到资源库"
-      :close-on-click-modal="false">
+    <SelectResource
+      :visible.sync="visibleResource"
+      :project-id="project_id"
+      :accept="accept"
+      :courseware-id="courseware_id"
+      @selectResource="selectResource"
+    />
+
+    <el-dialog
+      :visible.sync="visibleSubmitResource"
+      width="500px"
+      append-to-body
+      :show-close="true"
+      title="提交到资源库"
+      :close-on-click-modal="false"
+    >
       <el-form ref="resourceForm" :model="resourceForm" :rules="resourceRules" label-width="60px">
         <el-form-item prop="position" label="位置">
           <el-radio-group v-model="resourceForm.position" size="medium">
-            <el-radio border v-for="node in node_list" :label="node.node_id">{{ node.node_name }}</el-radio>
+            <el-radio v-for="node in node_list" :key="node.node_id" border :label="node.node_id">
+              {{ node.node_name }}
+            </el-radio>
           </el-radio-group>
         </el-form-item>
         <el-form-item prop="name" label="名称">
@@ -88,7 +132,6 @@
         <el-button :loading="loading" type="primary" @click="SubmitToResource">确 定</el-button>
       </template>
     </el-dialog>
-
   </div>
 </template>
 
@@ -191,8 +234,7 @@ export default {
       default: true,
     },
   },
-  data() 
-  {
+  data() {
     return {
       curFile: null,
       conversionSize,
@@ -215,12 +257,8 @@ export default {
         intro: '',
       },
       resourceRules: {
-        position: [
-          { required: true, message: '请选择位置', trigger: 'blur' },
-        ],
-        name: [
-          { required: true, message: '请输入名称', trigger: 'blur' },
-        ],
+        position: [{ required: true, message: '请选择位置', trigger: 'blur' }],
+        name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
       },
     };
   },
@@ -288,7 +326,8 @@ export default {
       });
       if (this.limit !== null && this.content.file_list.length + files.length > this.limit) {
         this.$message.warning(
-          `当前限制选择 ${this.limit} 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + this.content.file_list.length
+          `当前限制选择 ${this.limit} 个文件,本次选择了 ${files.length} 个文件,共选择了 ${
+            files.length + this.content.file_list.length
           } 个文件`,
         );
         return;
@@ -300,7 +339,8 @@ export default {
 
     handleExceed(files, fileList) {
       this.$message.warning(
-        `当前限制选择 ${this.limit} 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length
+        `当前限制选择 ${this.limit} 个文件,本次选择了 ${files.length} 个文件,共选择了 ${
+          files.length + fileList.length
         } 个文件`,
       );
     },
@@ -317,7 +357,7 @@ export default {
           this.content.file_list.splice(i, 1);
           this.content.file_id_list.splice(i, 1);
         })
-        .catch(() => { });
+        .catch(() => {});
     },
 
     // 文件校验
@@ -494,7 +534,7 @@ export default {
 
     // 提交到资源库
     handleSubmitToResource(file) {
-      debugger
+      debugger;
       this.visibleSubmitResource = true;
       this.curFile = file;
       this.resourceForm = {
@@ -504,10 +544,9 @@ export default {
         intro: file.intro || '',
       };
 
-      GetBookCoursewarePath({ id: this.courseware_id }).then(res => {
-        this.node_list = res.path_list
+      GetBookCoursewarePath({ id: this.courseware_id }).then((res) => {
+        this.node_list = res.path_list;
       });
-
     },
     SubmitToResource() {
       this.$refs.resourceForm.validate((valid) => {
@@ -587,7 +626,7 @@ export default {
     display: flex;
     justify-content: space-between;
 
-    .el-button+.el-button {
+    .el-button + .el-button {
       margin-left: 2px;
     }
 

+ 1 - 0
src/views/book/courseware/create/components/question/matching/Matching.vue

@@ -7,6 +7,7 @@
             <span class="serial-number">{{ computeOptionMethods[data.property.serial_number_type_list[j]](i) }}</span>
             <span class="option-content">
               <RichText
+                v-if="property.isGetContent"
                 ref="richText"
                 v-model="item.content"
                 placeholder="请输入"

+ 5 - 0
src/views/book/courseware/preview/common/PreviewOperation.vue

@@ -24,6 +24,11 @@ export default {
       type: Boolean,
       default: true,
     },
+    // 是否显示重做按钮
+    isShowRetry: {
+      type: Boolean,
+      default: true,
+    },
   },
   data() {
     return {};

+ 9 - 2
src/views/book/courseware/preview/components/fill/FillPreview.vue

@@ -103,7 +103,7 @@
     </div>
 
     <WriteDialog :visible.sync="writeVisible" @confirm="handleWriteConfirm" />
-    <PreviewOperation @showAnswerAnalysis="showAnswerAnalysis" @retry="retry" />
+    <PreviewOperation :is-show-answer="isShowAnswer" @showAnswerAnalysis="showAnswerAnalysis" @retry="retry" />
     <AnswerCorrect :visible.sync="visibleAnswerCorrect" @closeAnswerCorrect="closeAnswerCorrect" />
     <AnswerAnalysis
       :visible.sync="visibleAnswerAnalysis"
@@ -174,7 +174,14 @@ export default {
   },
   computed: {
     fontFamily() {
-      return fillFontList.find(({ value }) => this.data.property.fill_font === value).font;
+      const fontItem = fillFontList.find(({ value }) => this.data.property.fill_font === value);
+      return fontItem ? fontItem.font : '';
+    },
+    isShowAnswer() {
+      return (
+        (Array.isArray(this.data.answer_list) && this.data.answer_list.length > 0) ||
+        (Array.isArray(this.data.analysis_list) && this.data.analysis_list.length > 0)
+      );
     },
   },
   watch: {

+ 1 - 0
src/views/book/courseware/preview/components/judge/JudgePreview.vue

@@ -192,6 +192,7 @@ export default {
       if (!this.isJudgingRightWrong) return '';
       let selectOption = this.answer.answer_list.find((item) => item.mark === mark); // 查找是否已选中的选项
       if (!selectOption) return 'wrong';
+      if (selectOption.option_type.length === 0) return '';
       return this.data.answer.answer_list.find((item) => item.mark === mark)?.option_type === selectOption.option_type
         ? 'right'
         : 'wrong';

+ 6 - 1
src/views/book/courseware/preview/components/record_input/RecordInputPreview.vue

@@ -27,7 +27,12 @@
           @handleWav="handleWav"
         />
       </div>
-      <PreviewOperation @showAnswerAnalysis="showAnswerAnalysis" @retry="retry" :isShowAnswer="isShowAnswers" />
+      <PreviewOperation
+        :is-show-answer="isShowAnswers"
+        :is-show-retry="isEnable(data.is_enable_input)"
+        @showAnswerAnalysis="showAnswerAnalysis"
+        @retry="retry"
+      />
       <AnswerCorrect
         :answer-correct="data?.answer_correct"
         :visible.sync="visibleAnswerCorrect"