Browse Source

课件预览

dsy 6 days ago
parent
commit
bc75195766

+ 3 - 3
src/api/book.js

@@ -387,8 +387,8 @@ export function GetBookChapterStructExpandList(data) {
  * @param {string} data.courseware_id 课件 ID
  * @param {string} data.answer 答案信息的 JSON 或富文本信息文本
  */
-export function SaveMyAnswer(data) {
-  return http.post(`${process.env.VUE_APP_EepServer}?MethodName=book_preview_manager-SaveMyAnswer`, data);
+export function SaveAnswer(data) {
+  return http.post(`${process.env.VUE_APP_EepServer}?MethodName=book_preview_manager-SaveAnswer`, data);
 }
 
 /**
@@ -399,7 +399,7 @@ export function SaveMyAnswer(data) {
  * @param {string} data.courseware_id 课件 ID
  * @return {object} 答题结果
  */
-export function GetMyAnswer(data) {
+export function GetAnswer(data) {
   return http.post(`${process.env.VUE_APP_EepServer}?MethodName=book_preview_manager-GetAnswer`, data);
 }
 

+ 0 - 8
src/components/CommonPreview.vue

@@ -12,7 +12,6 @@
           <el-checkbox v-model="isShowGroup">显示分组</el-checkbox>
           <el-checkbox v-model="groupShowAll">分组显示全部</el-checkbox>
           <el-checkbox v-model="isJudgeCorrect">判断对错</el-checkbox>
-          <el-checkbox v-model="isShowAnswer" :disabled="!isJudgeCorrect">显示答案</el-checkbox>
         </div>
         <span class="link">
           <el-select v-model="lang" placeholder="请选择语言" size="mini" class="lang-select">
@@ -286,7 +285,6 @@ export default {
       lang: 'ZH',
       chinese: 'zh-Hans',
       isJudgeCorrect: false,
-      isShowAnswer: false,
     };
   },
   computed: {
@@ -299,14 +297,8 @@ export default {
   },
   watch: {
     isJudgeCorrect(newVal) {
-      if (!newVal) {
-        this.isShowAnswer = false;
-      }
       this.simulateAnswer(newVal);
     },
-    isShowAnswer() {
-      this.simulateAnswer();
-    },
   },
   created() {
     if (this.id) {

+ 17 - 210
src/courseware_preview/index.vue

@@ -21,8 +21,10 @@
         <span class="link">
           <el-checkbox v-model="chinese" true-label="zh-Hant" false-label="zh-Hans">繁体</el-checkbox>
         </span> -->
+        <img class="fullscreen" :src="require('@/assets/icon/sidebar-fullscreen.png')" alt="全屏" @click="fullScreen" />
         <div class="operator">
           <slot name="operator" :courseware="courseware_info"></slot>
+          <el-checkbox v-model="isJudgeCorrect" :disabled="!permissionControl.can_judge_correct">判断对错</el-checkbox>
           <span class="link" @click="confirmAnswer()">提交答案</span>
           <span class="link" @click="getAnswer()">读取答案</span>
           <span class="link" @click="confirmCorrect()">提交批改</span>
@@ -55,206 +57,7 @@
           />
           <div class="preview-right"></div>
         </main>
-
-        <!-- 右侧菜单栏 - 收缩 -->
-        <aside v-if="!sidebarShow && !isFullScreen" class="sidebar-bar">
-          <aside class="toolbar">
-            <div class="toolbar-special">
-              <img :src="require('@/assets/icon/sidebar-fullscreen.png')" alt="全屏" @click="fullScreen" />
-              <img :src="require('@/assets/icon/sidebar-toolkit.png')" alt="工具箱" />
-              <img :src="require(`@/assets/icon/arrow-down.png`)" alt="伸缩" @click="toggleSidebarShow" />
-            </div>
-          </aside>
-        </aside>
-      </div>
-
-      <div v-if="!sidebarShow" class="back-top" @click="backTop">
-        <img :src="require(`@/assets/icon/back-top.png`)" alt="返回顶部" />
       </div>
-
-      <!-- 右侧工具栏 -->
-      <aside v-if="sidebarShow" ref="sidebarMenu" class="sidebar">
-        <aside class="toolbar">
-          <div class="toolbar-special">
-            <img :src="require('@/assets/icon/sidebar-fullscreen.png')" alt="全屏" @click="fullScreen" />
-            <img :src="require('@/assets/icon/sidebar-toolkit.png')" alt="工具箱" />
-          </div>
-          <div v-if="sidebarShow" class="toolbar-list">
-            <div
-              v-for="{ icon, title, handle, param, children } in sidebarIconList"
-              :key="icon"
-              :class="['sidebar-item', { active: curToolbarIcon === icon }]"
-              :title="title"
-              @click="handleSidebarClick(handle, param, icon, children)"
-            >
-              <div
-                class="sidebar-icon icon-mask"
-                :style="{
-                  backgroundColor: curToolbarIcon === icon ? '#fff' : '#1E2129',
-                  maskImage: `url(${require(`@/assets/icon/sidebar-${icon}.svg`)})`,
-                }"
-              ></div>
-            </div>
-          </div>
-          <div class="adjustable" @click="toggleSidebarShow">
-            <img :src="require(`@/assets/icon/arrow-up.png`)" alt="伸缩" />
-          </div>
-        </aside>
-        <div class="content">
-          <div v-if="curToolbarIcon === 'search'" class="resource_box">
-            <h5>{{ drawerTitle }}</h5>
-            <div style="height: 40px"></div>
-            <el-row :gutter="10" style="margin: 5px">
-              <el-col :span="16">
-                <el-input v-model="searchContent" placeholder="请输入文本内容" clearable />
-              </el-col>
-              <el-col :span="4">
-                <el-button type="primary" @click="querySearchList"> 查询 </el-button>
-              </el-col>
-            </el-row>
-            <div>
-              <el-table :data="searchList" :show-header="false">
-                <!-- <el-table-column prop="courseware_name" label="课件" />
-                <el-table-column prop="component_type" label="组件" /> -->
-                <el-table-column>
-                  <template #default="{ row }">
-                    {{ row.courseware_name + ' / ' + row.component_type_name }}
-                  </template>
-                </el-table-column>
-                <el-table-column label="" width="50">
-                  <template #default="{ row }">
-                    <el-link type="primary" @click="handleLocation(row, 3)">定位</el-link>
-                  </template>
-                </el-table-column>
-              </el-table>
-            </div>
-          </div>
-          <!-- <div v-if="curToolbarIcon === 'totalResources'" class="resource_box"></div> -->
-          <div v-if="['image', 'audio', 'video'].includes(twoCurToolbarIcon)" class="resource_box">
-            <div class="source-toolbar-list">
-              <div
-                v-for="{ icon, title, handle, param } in twoSidebarList"
-                :key="icon"
-                :class="['sidebar-item', { active: twoCurToolbarIcon === icon }]"
-                :title="title"
-                @click="handleSidebarClick(handle, param, icon, '', 2)"
-              >
-                <div
-                  class="sidebar-icon icon-mask"
-                  :style="{
-                    backgroundColor: twoCurToolbarIcon === icon ? '#fff' : '#1E2129',
-                    maskImage: `url(${require(`@/assets/icon/sidebar-${icon}.svg`)})`,
-                  }"
-                ></div>
-              </div>
-            </div>
-            <div style="height: 40px"></div>
-
-            <el-collapse v-model="activeBookChapterId" accordion @change="multimediaHandleChange">
-              <el-collapse-item
-                v-for="chapter in bookChapterList"
-                :key="chapter.id"
-                :name="chapter.id"
-                :title="chapter.name"
-              >
-                <!-- 加载状态 -->
-                <div v-if="multimediaLoadingStates" class="loading-text">加载中...</div>
-
-                <!-- 加载完成显示数据 -->
-                <div v-else-if="chapter.data">
-                  <ul class="scroll-container" infinite-scroll-disabled="disabled" :infinite-scroll-immediate="false">
-                    <li
-                      v-for="(item, index) in chapter.data"
-                      :key="`${chapter.id}-${index}`"
-                      class="list-item"
-                      @click="handleFileClick(item?.courseware_id, item?.component_id)"
-                    >
-                      <template v-if="parseInt(drawerType) === 0">
-                        <el-image v-if="shouldShowItem(chapter, item)" :src="item.file_url" fit="contain" />
-                        <div class="mark">
-                          <span class="word">{{ item.file_name }}</span>
-                          <el-link type="primary" class="el-icon-place linkLocation" @click="handleLocation(item, 3)" />
-                        </div>
-                      </template>
-                      <template v-else-if="parseInt(drawerType) === 1">
-                        <AudioPlay
-                          v-if="shouldShowItem(chapter, item)"
-                          view-size="middle"
-                          :file-id="item.file_id"
-                          :file-name="item.file_name.slice(0, item.file_name.lastIndexOf('.'))"
-                          :show-slider="true"
-                          :audio-index="index"
-                        />
-                        <div class="mark">
-                          <span class="word"></span>
-                          <el-link type="primary" class="el-icon-place linkLocation" @click="handleLocation(item, 3)" />
-                        </div>
-                      </template>
-                      <template v-else-if="parseInt(drawerType) === 2">
-                        <VideoPlay
-                          v-if="shouldShowItem(chapter, item)"
-                          view-size="small"
-                          :file-id="item.file_id"
-                          :video-index="index"
-                        />
-                        <div class="mark">
-                          <span class="word">{{ item.file_name }}</span>
-                          <el-link type="primary" class="el-icon-place linkLocation" @click="handleLocation(item, 3)" />
-                        </div>
-                      </template>
-                    </li>
-                  </ul>
-                </div>
-
-                <!-- 加载失败或未加载 -->
-                <div v-else class="error-text">没有资源</div>
-              </el-collapse-item>
-            </el-collapse>
-          </div>
-
-          <div v-if="curToolbarIcon === 'collect'" class="resource_box">
-            <h5>{{ drawerTitle }}</h5>
-            <div style="height: 40px"></div>
-            <ul v-if="allCottectList.length > 0" class="card-box">
-              <li v-for="item in allCottectList" :key="item.id">
-                <span class="el-icon-notebook-2"> 原文</span>
-                <span>{{ item.text }}</span>
-                <div>
-                  <el-button type="text" class="el-icon-delete" @click="handDelCollect(item.id)"> 删除</el-button>
-                  <el-divider direction="vertical" />
-                  <el-button type="text" class="el-icon-place" @click="handleLocation(item, 2)"> 定位</el-button>
-                </div>
-              </li>
-            </ul>
-          </div>
-          <div v-if="curToolbarIcon === 'note'" class="resource_box">
-            <h5>{{ drawerTitle }}</h5>
-            <div style="height: 40px"></div>
-            <ul v-if="allNoteList.length > 0" class="card-box">
-              <li v-for="item in allNoteList" :key="item.id">
-                <span class="el-icon-notebook-2"> 原文</span>
-                <span>{{ item.text }}</span>
-                <el-divider class="mt10" />
-                <span v-html="item.note"></span>
-                <div>
-                  <el-button type="text" class="el-icon-edit" @click="handEditNote(item)"> 编辑</el-button>
-                  <el-divider direction="vertical" />
-                  <el-button type="text" class="el-icon-delete" @click="handDelNote(item.id)"> 删除</el-button>
-                  <el-divider direction="vertical" />
-                  <el-button type="text" class="el-icon-place" @click="handleLocation(item, 1)"> 定位</el-button>
-                </div>
-              </li>
-            </ul>
-          </div>
-          <template v-if="curToolbarIcon === 'audit'">
-            <AuditRemark :remark-list="remark_list" :is-audit="isShowAudit" @deleteRemarks="deleteRemarks" />
-          </template>
-        </div>
-
-        <div class="back-top" @click="backTop">
-          <img :src="require(`@/assets/icon/back-top.png`)" alt="返回顶部" />
-        </div>
-      </aside>
     </div>
 
     <el-dialog title="" :visible="visibleMindMap" width="1100px" class="audit-dialog" @close="dialogClose('MindMap')">
@@ -436,7 +239,6 @@ export default {
       lang: 'ZH',
       chinese: 'zh-Hans',
       isJudgeCorrect: false,
-      isShowAnswer: false,
       unified_attrib: {},
       curSelectId: this.id,
       sidebarShow: true,
@@ -493,13 +295,7 @@ export default {
     },
   },
   watch: {
-    isJudgeCorrect(newVal) {
-      if (!newVal) {
-        this.isShowAnswer = false;
-      }
-      this.simulateAnswer(newVal);
-    },
-    isShowAnswer() {
+    isJudgeCorrect() {
       this.simulateAnswer();
     },
     curSelectId() {
@@ -999,8 +795,12 @@ export default {
       }
     },
 
+    /**
+     * 模拟答题
+     * @param {boolean} [disabled=true] - 是否禁用
+     */
     simulateAnswer(disabled = true) {
-      this.$refs.courserware.simulateAnswer(this.isJudgeCorrect, this.isShowAnswer, disabled);
+      this.$refs.courserware.simulateAnswer(this.isJudgeCorrect, false, disabled);
     },
 
     /**
@@ -1248,10 +1048,11 @@ export default {
       toggleFullScreen(this.$refs.previewMain);
     },
     confirmAnswer() {
-      this.$refs.courserware.saveMyAnswer({ task_id: this.task_id, user_id: this.user_id, courseware_id: this.id });
+      this.$refs.courserware.saveAnswer({ task_id: this.task_id, user_id: this.user_id, courseware_id: this.id });
     },
     getAnswer() {
-      this.$refs.courserware.getMyAnswer({ task_id: this.task_id, user_id: this.user_id, courseware_id: this.id });
+      this.$refs.courserware.getAnswer({ task_id: this.task_id, user_id: this.user_id, courseware_id: this.id });
+      this.isJudgeCorrect = true;
     },
     confirmCorrect() {
       this.$refs.courserware.saveAnswerMarking({
@@ -1325,6 +1126,12 @@ $total-width: $courseware-width + $courseware-left-margin + $courseware-right-ma
         }
       }
 
+      .fullscreen {
+        width: 32px;
+        height: 32px;
+        cursor: pointer;
+      }
+
       .operator {
         display: flex;
         column-gap: 8px;

+ 12 - 9
src/views/book/courseware/preview/CoursewarePreview.vue

@@ -79,7 +79,7 @@
 
 <script>
 import { previewComponentList } from '@/views/book/courseware/data/bookType';
-import { SaveMyAnswer, GetMyAnswer, SaveAnswerMarking, GetAnswerMarking } from '@/api/book';
+import { SaveAnswer, GetAnswer, SaveAnswerMarking, GetAnswerMarking } from '@/api/book';
 
 export default {
   name: 'CoursewarePreview',
@@ -157,6 +157,7 @@ export default {
       },
       selectedInfo: null,
       selectHandleInfo: null,
+      getAnswerLoading: false, // 是否正在加载答案
     };
   },
   watch: {
@@ -415,6 +416,7 @@ export default {
      * @param {boolean} disabled 是否禁用
      */
     simulateAnswer(isJudgingRightWrong, isShowRightAnswer, disabled = true, answer = null) {
+      if (this.getAnswerLoading) return;
       this.$refs.preview.forEach((item) => {
         item.showAnswer(isJudgingRightWrong, isShowRightAnswer, answer, disabled);
       });
@@ -705,9 +707,6 @@ export default {
       if (!_offset) _offset = 0;
       const element = document.querySelector(`div[data-id="${dataId}"]`);
       if (element) {
-        const elementPosition = element.getBoundingClientRect().top + window.pageYOffset;
-        const offsetPosition = elementPosition - _offset;
-
         element.scrollIntoView({
           behavior: 'smooth', // 滚动行为:'auto' | 'smooth'
           block: 'center', // 垂直对齐:'start' | 'center' | 'end' | 'nearest'
@@ -721,12 +720,12 @@ export default {
      * @param {string} user_id 用户ID
      * @param {string} courseware_id 课件ID
      */
-    saveMyAnswer({ task_id, user_id, courseware_id }) {
+    saveAnswer({ task_id, user_id, courseware_id }) {
       let answer = {};
       this.$refs.preview.forEach((item) => {
         answer[item.id] = JSON.stringify(item.getAnswer());
       });
-      SaveMyAnswer({
+      SaveAnswer({
         task_id,
         user_id,
         courseware_id,
@@ -741,8 +740,9 @@ export default {
      * @param {string} user_id 用户ID
      * @param {string} courseware_id 课件ID
      */
-    getMyAnswer({ task_id, user_id, courseware_id }) {
-      GetMyAnswer({
+    getAnswer({ task_id, user_id, courseware_id }) {
+      this.getAnswerLoading = true;
+      GetAnswer({
         task_id,
         user_id,
         courseware_id,
@@ -752,9 +752,10 @@ export default {
           this.$refs.preview.forEach((item) => {
             let answerItem = _answer[item.id];
             if (answerItem) {
-              item.showAnswer(true, true, JSON.parse(answerItem), true);
+              item.showAnswer(true, false, JSON.parse(answerItem), true);
             }
           });
+          this.getAnswerLoading = false;
         }
       });
     },
@@ -774,6 +775,8 @@ export default {
         user_id,
         courseware_id,
         answer_marking: JSON.stringify(answer_marking),
+      }).then(() => {
+        this.$message.success('批改保存成功');
       });
     },
     /**

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

@@ -6,11 +6,7 @@
       class="button correct"
       @click="openAnswerCorrect()"
     ></div>
-    <div
-      v-show="permissionControl.can_judge_correct || permissionControl.can_show_answer"
-      class="button answer"
-      @click="showAnswerAnalysis()"
-    ></div>
+    <div v-show="permissionControl.can_show_answer" class="button answer" @click="showAnswerAnalysis()"></div>
   </div>
 </template>
 

+ 9 - 1
src/views/book/courseware/preview/components/common/PreviewMixin.js

@@ -70,6 +70,12 @@ const mixin = {
       },
       immediate: true,
     },
+    'permissionControl.can_answer': {
+      handler(newVal) {
+        this.disabled = !newVal;
+      },
+      immediate: true,
+    },
   },
   components: {
     SerialNumberPosition,
@@ -134,7 +140,9 @@ const mixin = {
       this.isJudgingRightWrong = isJudgingRightWrong;
       this.isShowRightAnswer = isShowRightAnswer;
       this.disabled = disabled;
-      if (userAnswer) this.answer = userAnswer;
+      if (userAnswer) {
+        this.answer = userAnswer;
+      }
     },
     /**
      * 获取批改信息

+ 10 - 0
src/views/book/courseware/preview/components/input/InputPreview.vue

@@ -10,10 +10,12 @@
         v-model="data.answer.text"
         type="text"
         :style="{
+          cursor: disabled ? 'not-allowed' : 'pointer',
           font: data.property.font,
           fontSize: data.property.font_size + 'px',
           color: data.property.text_color,
         }"
+        :disabled="disabled"
         :class="[
           'input',
           { 'input-horizontal': data.property.input_style === inputStyleList[0].value },
@@ -56,6 +58,14 @@ export default {
       inputStyleList,
     };
   },
+  watch: {
+    'data.answer.text'(newVal) {
+      this.answer.text = newVal;
+    },
+    answer(newVal) {
+      this.data.answer.text = newVal?.text || '';
+    },
+  },
   mounted() {
     this.$nextTick(() => {
       this.$refs.input.$el.querySelector('.el-input__inner').style.backgroundColor =

+ 9 - 13
src/web_preview/index.vue

@@ -12,7 +12,6 @@
           <el-checkbox v-model="isShowGroup">显示分组</el-checkbox>
           <el-checkbox v-model="groupShowAll">分组显示全部</el-checkbox>
           <el-checkbox v-model="isJudgeCorrect">判断对错</el-checkbox>
-          <el-checkbox v-model="isShowAnswer" :disabled="!isJudgeCorrect">显示答案</el-checkbox>
         </div>
         <span class="link">
           <el-select v-model="lang" placeholder="请选择语言" size="mini" class="lang-select">
@@ -476,7 +475,6 @@ export default {
       lang: 'ZH',
       chinese: 'zh-Hans',
       isJudgeCorrect: false,
-      isShowAnswer: false,
       unified_attrib: {},
       curSelectId: this.id,
       navigationShow: true,
@@ -499,9 +497,9 @@ export default {
       title_list: [],
       // 模拟答题权限控制
       permissionControl: {
-        can_answer: false, // 可作答
-        can_judge_correct: false, // 可判断对错(客观题)
-        can_show_answer: false, // 可查看答案
+        can_answer: true, // 可作答
+        can_judge_correct: true, // 可判断对错(客观题)
+        can_show_answer: true, // 可查看答案
         can_correct: false, // 可批改
         can_check_correct: false, // 可查看批改
       },
@@ -534,13 +532,7 @@ export default {
     },
   },
   watch: {
-    isJudgeCorrect(newVal) {
-      if (!newVal) {
-        this.isShowAnswer = false;
-      }
-      this.simulateAnswer(newVal);
-    },
-    isShowAnswer() {
+    isJudgeCorrect() {
       this.simulateAnswer();
     },
     curSelectId() {
@@ -1040,8 +1032,12 @@ export default {
       }
     },
 
+    /**
+     * 模拟答题
+     * @param {boolean} [disabled=true] - 是否禁用
+     */
     simulateAnswer(disabled = true) {
-      this.$refs.courserware.simulateAnswer(this.isJudgeCorrect, this.isShowAnswer, disabled);
+      this.$refs.courserware.simulateAnswer(this.isJudgeCorrect, false, disabled);
     },
 
     /**