Преглед на файлове

1、填空题只显示正确答案 2、使用模板增加全路径 3、保存模板增加弹窗输入名称、标签、描述

dsy преди 1 седмица
родител
ревизия
0f0d107e24

+ 1 - 1
.env

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

+ 1 - 1
package.json

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

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

@@ -125,65 +125,6 @@
               <span v-else :key="j" v-html="convertText(sanitizeHTML(li.content))"></span>
             </template>
             <template v-if="li.type === 'input'">
-              <template v-if="data.property.fill_type === fillTypeList[0].value">
-                <el-input
-                  :key="j"
-                  v-model="li.content"
-                  :disabled="disabled"
-                  :class="[data.property.fill_font, ...computedAnswerClass(li.mark)]"
-                  :style="[{ width: Math.max(80, li.content.length * 21.3) + 'px' }]"
-                />
-              </template>
-
-              <template v-else-if="data.property.fill_type === fillTypeList[1].value">
-                <el-popover :key="j" placement="top" trigger="click">
-                  <div class="word-list">
-                    <span
-                      v-for="{ content, mark } in data.word_list"
-                      :key="mark"
-                      class="word-item"
-                      @click="handleSelectWord(content, mark, li)"
-                    >
-                      {{ content }}
-                    </span>
-                  </div>
-
-                  <el-input
-                    slot="reference"
-                    v-model="li.content"
-                    :readonly="true"
-                    :class="[data.property.fill_font, ...computedAnswerClass(li.mark)]"
-                    class="pinyin"
-                    :style="[{ width: Math.max(80, li.content.length * 21.3) + 'px' }]"
-                  />
-                </el-popover>
-              </template>
-
-              <template v-else-if="data.property.fill_type === fillTypeList[2].value">
-                <span :key="j" class="write-click" @click="handleWriteClick(li.mark)">
-                  <img
-                    v-show="li.write_base64"
-                    style="background-color: #f4f4f4"
-                    :src="li.write_base64"
-                    alt="write-show"
-                  />
-                </span>
-              </template>
-
-              <template v-else-if="data.property.fill_type === fillTypeList[3].value">
-                <SoundRecordBox
-                  ref="record"
-                  :key="j"
-                  type="mini"
-                  :many-times="false"
-                  class="record-box"
-                  :attrib="data.unified_attrib"
-                  :answer-record-list="data.audio_answer_list"
-                  :task-model="isJudgingRightWrong ? 'ANSWER' : ''"
-                  @handleWav="handleMiniWav($event, li.mark)"
-                />
-              </template>
-
               <span v-show="computedAnswerText(li.mark).length > 0" :key="`answer-${j}`" class="right-answer">
                 {{ computedAnswerText(li.mark) }}
               </span>
@@ -431,7 +372,7 @@ export default {
       let answerValue = answerOption.value;
       let isRight = selectValue === answerValue;
       if (isRight) return '';
-      return `${answerValue}`;
+      return `${answerValue}`;
     },
     // 重做
     retry() {
@@ -526,16 +467,6 @@ export default {
         }
       }
 
-      & + .right-answer {
-        position: relative;
-        left: -4px;
-        display: inline-block;
-        height: 32px;
-        line-height: 28px;
-        vertical-align: bottom;
-        border-bottom: 1px solid $font-color;
-      }
-
       :deep input.el-input__inner {
         padding: 0;
         font-size: 16pt;
@@ -548,16 +479,14 @@ export default {
       }
     }
 
-    .popper-list {
-      & + .right-answer {
-        position: relative;
-        left: -4px;
-        display: inline-block;
-        height: 32px;
-        line-height: 28px;
-        vertical-align: bottom;
-        border-bottom: 1px solid $font-color;
-      }
+    .right-answer {
+      position: relative;
+      display: inline-block;
+      height: 32px;
+      margin: 0 4px;
+      line-height: 32px;
+      vertical-align: bottom;
+      border-bottom: 1px solid $font-color;
     }
   }
 

+ 22 - 2
src/views/personal_workbench/edit_task/edit/UseTemplate.vue

@@ -60,8 +60,9 @@
           </div>
           <el-button slot="reference" class="courseware-name">{{ coursewareName }}</el-button>
         </el-popover>
+        <span class="fullpath">{{ fullPath }}</span>
         <CoursewarePreview
-          v-if="coursewareData.row_list.length > 0"
+          v-if="coursewareData.row_list?.length > 0"
           ref="courserware"
           :is-show-group="false"
           :group-show-all="true"
@@ -168,6 +169,20 @@ export default {
       const node = this.node_list.find((x) => x.id === this.curSelectId);
       return node ? node.name : '选择章节';
     },
+    fullPath() {
+      if (!this.curSelectId || this.curType === 0) return '';
+      const node = this.node_list.find((x) => x.id === this.curSelectId);
+      if (!node) return '';
+      const path = [];
+      let currentDeep = node.deep;
+      let currentNode = node;
+      while (currentNode && currentDeep > 0) {
+        path.unshift(currentNode.name);
+        currentNode = this.node_list.find((x) => x.deep === currentDeep - 1 && x.is_leaf_chapter === 'false');
+        currentDeep -= 1;
+      }
+      return path.join(' / ');
+    },
   },
   watch: {
     curSelectId(newVal) {
@@ -421,7 +436,7 @@ export default {
     }
 
     .template-list {
-      width: 400px;
+      width: 460px;
     }
 
     .courseware-preview {
@@ -431,6 +446,11 @@ export default {
       .courseware-name {
         margin: 2px 0 0 4px;
       }
+
+      .fullpath {
+        display: inline-block;
+        margin-left: 24px;
+      }
     }
   }
 }

+ 150 - 0
src/views/personal_workbench/edit_task/preview/CreateCoursewareAsTemplate.vue

@@ -0,0 +1,150 @@
+<template>
+  <el-dialog :visible="visible" :title="title" :close-on-click-modal="false" width="420px" @close="dialogClose">
+    <div class="form">
+      <div class="form-item">
+        <label for="name">模板名称</label>
+        <div class="form-item-container">
+          <el-input id="name" v-model="form.name" placeholder="请输入模板名称" />
+        </div>
+      </div>
+      <div class="form-item">
+        <label for="label">标签</label>
+        <div class="form-item-container label-list">
+          <el-tag v-for="tag in form.label_list" :key="tag" size="medium" closable @close="handleTagClose(tag)">
+            {{ tag }}
+          </el-tag>
+
+          <el-input
+            v-if="inputVisible"
+            ref="saveTagInput"
+            v-model="inputValue"
+            class="input-new-tag"
+            size="small"
+            @keyup.enter.native="handleInputConfirm"
+            @blur="handleInputConfirm"
+          />
+          <el-button v-else class="button-new-tag" size="small" @click="showInput">+</el-button>
+        </div>
+      </div>
+      <div class="form-item">
+        <label for="memo">模板描述</label>
+        <div class="form-item-container">
+          <el-input
+            id="memo"
+            v-model="form.memo"
+            placeholder="请输入模板描述"
+            type="textarea"
+            resize="none"
+            :rows="4"
+          />
+        </div>
+      </div>
+    </div>
+
+    <div slot="footer">
+      <el-button @click="dialogClose()">取 消</el-button>
+      <el-button type="primary" @click="confirm()">确 定</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+export default {
+  name: 'CreateCoursewareAsTemplate',
+  props: {
+    visible: {
+      type: Boolean,
+      required: true,
+    },
+    scope: {
+      type: Number,
+      required: true,
+    },
+  },
+  data() {
+    return {
+      titleList: {
+        0: '保存本页为模板',
+        1: '保存本书为模板',
+        3: '保存本课为模板',
+      },
+      form: {
+        name: '',
+        label_list: [],
+        memo: '',
+      },
+      inputVisible: false,
+      inputValue: '',
+    };
+  },
+  computed: {
+    title() {
+      return this.titleList[this.scope];
+    },
+  },
+  methods: {
+    dialogClose() {
+      this.$emit('update:visible', false);
+    },
+    confirm() {
+      if (this.form.name.trim() === '') {
+        this.$message.error('模板名称不能为空');
+        return;
+      }
+      this.$emit('confirm', this.form);
+    },
+    /**
+     * 处理标签关闭
+     * @param {string} tag 标签内容
+     */
+    handleTagClose(tag) {
+      this.form.label_list = this.form.label_list.filter((item) => item !== tag);
+    },
+    showInput() {
+      this.inputVisible = true;
+      this.$nextTick(() => {
+        this.$refs.saveTagInput.$refs.input.focus();
+      });
+    },
+    handleInputConfirm() {
+      let inputValue = this.inputValue;
+      if (inputValue) {
+        this.form.label_list.push(inputValue);
+      }
+      this.inputVisible = false;
+      this.inputValue = '';
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.form {
+  &-item {
+    display: flex;
+    flex-direction: column;
+    row-gap: 8px;
+    margin-bottom: 20px;
+
+    label {
+      font-size: 14px;
+      color: $text-color;
+    }
+
+    .form-item-container {
+      flex: 1;
+    }
+
+    .label-list {
+      display: flex;
+      flex-wrap: wrap;
+      gap: 8px;
+      align-items: center;
+
+      .input-new-tag {
+        width: 80px;
+      }
+    }
+  }
+}
+</style>

+ 28 - 6
src/views/personal_workbench/edit_task/preview/index.vue

@@ -5,9 +5,9 @@
     <CommonPreview :id="id" ref="preview" :project-id="project_id" type="edit_preview">
       <template #operator="{ courseware }">
         <el-popover placement="bottom" width="125" trigger="click">
-          <el-link type="primary" @click="saveCoursewareAsTemplate(0)">保存本页为模板</el-link>
-          <el-link type="primary" @click="saveCoursewareAsTemplate(3)">保存本课为模板</el-link>
-          <el-link type="primary" @click="saveCoursewareAsTemplate(1)">保存本书为模板</el-link>
+          <el-link type="primary" @click="openCreateTemplateDialog(0)">保存本页为模板</el-link>
+          <el-link type="primary" @click="openCreateTemplateDialog(3)">保存本课为模板</el-link>
+          <el-link type="primary" @click="openCreateTemplateDialog(1)">保存本书为模板</el-link>
           <span slot="reference" class="link save-template">保存为个人模板</span>
         </el-popover>
         <span class="link"></span>
@@ -18,12 +18,19 @@
         <span class="link" @click="goBackBookList()">返回教材列表</span>
       </template>
     </CommonPreview>
+
+    <CreateCoursewareAsTemplateVue
+      :visible.sync="visibleTemplate"
+      :scope="templateScope"
+      @confirm="saveCoursewareAsTemplate"
+    />
   </div>
 </template>
 
 <script>
 import MenuPage from '@/views/personal_workbench/common/menu.vue';
 import CommonPreview from '@/components/CommonPreview.vue';
+import CreateCoursewareAsTemplateVue from '@/views/personal_workbench/edit_task/preview/CreateCoursewareAsTemplate.vue';
 
 import { SubmitBookCoursewareToAuditFlow } from '@/api/project';
 import { isTrue } from '@/utils/validate';
@@ -34,12 +41,15 @@ export default {
   components: {
     MenuPage,
     CommonPreview,
+    CreateCoursewareAsTemplateVue,
   },
   data() {
     return {
       id: this.$route.params.id,
       project_id: this.$route.query.project_id,
       isTrue,
+      visibleTemplate: false,
+      templateScope: 0,
     };
   },
   methods: {
@@ -61,18 +71,30 @@ export default {
         this.$refs.preview.getBookCoursewareInfo(this.$refs.preview.select_node);
       });
     },
+    openCreateTemplateDialog(scope) {
+      this.visibleTemplate = true;
+      this.templateScope = scope;
+    },
     /**
      * 保存为个人模板
-     * @param {Number} scope 范围
+     * @param {object} form 模板信息
+     * @param {string} form.name 模板名称
+     * @param {array} form.label_list 模板标签列表
+     * @param {string} form.memo 模板备注
      */
-    saveCoursewareAsTemplate(scope) {
+    saveCoursewareAsTemplate(form) {
       this.$confirm('确定保存为个人模板吗?', '提示', {
         confirmButtonText: '确定',
         cancelButtonText: '取消',
         type: 'warning',
       })
         .then(() => {
-          SaveCoursewareAsTemplatePersonal({ courseware_id: this.$refs.preview.select_node, scope }).then(() => {
+          this.visibleTemplate = false;
+          SaveCoursewareAsTemplatePersonal({
+            courseware_id: this.$refs.preview.select_node,
+            scope: this.templateScope,
+            ...form,
+          }).then(() => {
             this.$message.success('已保存为个人模板');
           });
         })

+ 4 - 4
src/views/project_manage/org/authorization/index.vue

@@ -271,7 +271,7 @@ export default {
           }
           this.dialogSearchBook = false;
           CreateOBOC(data).then((res) => {
-            if (res && res.status == 1) {
+            if (res && res.status === 1) {
               this.dialogFormEdit = false;
               this.queryList();
             }
@@ -282,7 +282,7 @@ export default {
       });
     },
     copyUrl(id) {
-      let url = this.list.find((x) => x.id == id).url;
+      let url = this.list.find((x) => x.id === id).url;
 
       navigator.clipboard.writeText(url).then(() => {
         this.$message.success('链接已复制到剪贴板');
@@ -295,7 +295,7 @@ export default {
         type: 'warning',
       })
         .then(() => {
-          DisableOBOC({ id: id }).then(() => {
+          DisableOBOC({ id }).then(() => {
             this.queryList();
           });
         })
@@ -308,7 +308,7 @@ export default {
         type: 'warning',
       })
         .then(() => {
-          DeleteOBOC({ id: id }).then(() => {
+          DeleteOBOC({ id }).then(() => {
             this.queryList();
           });
         })