Ver Fonte

预览加用户反馈

zq há 1 dia atrás
pai
commit
a39b45e2c1

+ 23 - 0
src/api/book.js

@@ -434,3 +434,26 @@ export function SaveAnswerMarking(data) {
 export function GetAnswerMarking(data) {
   return http.post(`${process.env.VUE_APP_EepServer}?MethodName=book_preview_manager-GetAnswerMarking`, data);
 }
+
+
+/**
+ *@description 添加课件反馈
+ * @param {object} data
+ */
+export function AddCoursewareFeedback(data) {
+  return http.post(`${process.env.VUE_APP_EepServer}?MethodName=book_preview_manager-AddCoursewareFeedback`, data);
+}
+/**
+ * @description 得到课件反馈列表
+ * @param {object} data
+ */
+export function GetCoursewareFeedbackList(data) {
+  return http.post(`${process.env.VUE_APP_EepServer}?MethodName=book_preview_manager-GetCoursewareFeedbackList`, data);
+}
+/**
+ * @description 删除课件反馈
+ * @param {object} data
+ */
+export function DeleteCoursewareFeedback(data) {
+  return http.post(`${process.env.VUE_APP_EepServer}?MethodName=book_preview_manager-DeleteCoursewareFeedback`, data);
+}

+ 1 - 0
src/assets/icon/sidebar-feedback.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1776823029085" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3716" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M512 616m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#1E2129" p-id="3717"></path><path d="M890 128H744a40 40 0 0 0-40 40 40 40 0 0 0 40 40h96a40 40 0 0 1 40 40v416a40 40 0 0 1-40 40H648.88a70 70 0 0 0-49.5 20.5l-59.5 59.5L512 811.88 484.12 784l-40-40-19.5-19.5a70 70 0 0 0-49.5-20.5H184a40 40 0 0 1-40-40V248a40 40 0 0 1 40-40h96a40 40 0 0 0 40-40 40 40 0 0 0-40-40H134a70 70 0 0 0-70 70v516a70 70 0 0 0 70 70h237l112.72 112.74a40 40 0 0 0 56.56 0L653 784h237a70 70 0 0 0 70-70V198a70 70 0 0 0-70-70z" fill="#1E2129" p-id="3718"></path><path d="M512 512a40 40 0 0 0 40-40V168a40 40 0 0 0-80 0v304a40 40 0 0 0 40 40z" fill="#1E2129" p-id="3719"></path></svg>

+ 7 - 3
src/components/ExplanatoryNoteDialog.vue

@@ -1,8 +1,8 @@
 <template>
-  <el-dialog title="编辑注释" :visible.sync="visible" width="680px" @close="dialogClose()">
+  <el-dialog :title="'编辑' + titleText" :visible.sync="visible" width="680px" @close="dialogClose()">
     <RichText
-      v-model="richData.note"
-      toolbar="fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright"
+      v-model="richData.dataStr"
+      toolbar="fontselect fontsizeselect forecolor backcolor | underline | bold italic strikethrough alignleft aligncenter alignright image"
       :wordlimit-num="false"
       :height="240"
       placeholder="输入内容"
@@ -33,6 +33,10 @@ export default {
       type: Object,
       default: () => ({}),
     },
+    titleText: {
+      type: String,
+      default: '注释',
+    },
   },
   data() {
     return {

+ 1 - 0
src/icons/svg/sibebar/sidebar-feedback.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1776823029085" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3716" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M512 616m-40 0a40 40 0 1 0 80 0 40 40 0 1 0-80 0Z" fill="#1E2129" p-id="3717"></path><path d="M890 128H744a40 40 0 0 0-40 40 40 40 0 0 0 40 40h96a40 40 0 0 1 40 40v416a40 40 0 0 1-40 40H648.88a70 70 0 0 0-49.5 20.5l-59.5 59.5L512 811.88 484.12 784l-40-40-19.5-19.5a70 70 0 0 0-49.5-20.5H184a40 40 0 0 1-40-40V248a40 40 0 0 1 40-40h96a40 40 0 0 0 40-40 40 40 0 0 0-40-40H134a70 70 0 0 0-70 70v516a70 70 0 0 0 70 70h237l112.72 112.74a40 40 0 0 0 56.56 0L653 784h237a70 70 0 0 0 70-70V198a70 70 0 0 0-70-70z" fill="#1E2129" p-id="3718"></path><path d="M512 512a40 40 0 0 0 40-40V168a40 40 0 0 0-80 0v304a40 40 0 0 0 40 40z" fill="#1E2129" p-id="3719"></path></svg>

+ 6 - 0
src/icons/svg/sibebar/sidebar-translate.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24" width="24" height="24" style="" filter="none">
+    
+    <g>
+    <path d="M20 5h-9.12L10 2H4c-1.1 0-2 .9-2 2v13c0 1.1.9 2 2 2h7l1 3h8c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zM7.17 14.59c-2.25 0-4.09-1.83-4.09-4.09s1.83-4.09 4.09-4.09c1.04 0 1.99.37 2.74 1.07l.07.06-1.23 1.18-.06-.05c-.29-.27-.78-.59-1.52-.59-1.31 0-2.38 1.09-2.38 2.42s1.07 2.42 2.38 2.42c1.37 0 1.96-.87 2.12-1.46H7.08V9.91h3.95l.01.07c.04.21.05.4.05.61 0 2.35-1.61 4-3.92 4zm6.03-1.71c.33.6.74 1.18 1.19 1.7l-.54.53-.65-2.23zm.77-.76h-.99l-.31-1.04h3.99s-.34 1.31-1.56 2.74a9.18 9.18 0 0 1-1.13-1.7zM21 20c0 .55-.45 1-1 1h-7l2-2-.81-2.77.92-.92L17.79 18l.73-.73-2.71-2.68c.9-1.03 1.6-2.25 1.92-3.51H19v-1.04h-3.64V9h-1.04v1.04h-1.96L11.18 6H20c.55 0 1 .45 1 1v13z" fill="rgba(51,51,51,1)"></path>
+    </g>
+  </svg>

+ 13 - 3
src/views/book/courseware/preview/CoursewarePreview.vue

@@ -75,9 +75,9 @@
       <span class="line"></span>
       <span class="button" @click="setCollect"><SvgIcon icon-class="sidebar-collect" size="14" /> 收藏 </span>
       <span class="line"></span>
-      <span class="button" @click="setTranslate">
-        <img :src="require('@/assets/icon/sidebar-translate.png')" style="width: 14px; height: 14px" /> 翻译
-      </span>
+      <span class="button" @click="setTranslate"> <SvgIcon icon-class="sidebar-translate" size="14" />翻译</span>
+      <span class="line"></span>
+      <span class="button" @click="setFeedback"> <SvgIcon icon-class="sidebar-feedback" size="14" />意见反馈</span>
     </div>
   </div>
 </template>
@@ -627,6 +627,16 @@ export default {
       this.$emit('getTranslate', info);
       this.selectedInfo = null;
     },
+    // 反馈
+    setFeedback() {
+      this.showToolbar = false;
+      this.oldRichData = {};
+      let info = this.selectHandleInfo;
+      if (!info) return;
+      info.coursewareId = this.courseware_id;
+      this.$emit('editFeedback', info);
+      this.selectedInfo = null;
+    },
     // 定位
     handleLocation(item) {
       this.scrollToDataId(item.blockId);

+ 150 - 7
src/web_preview/index.vue

@@ -110,6 +110,7 @@
             @editNote="handEditNote"
             @saveCollect="saveCollect"
             @getTranslate="getTranslate"
+            @editFeedback="handEditFeedback"
           />
           <div class="preview-right"></div>
         </main>
@@ -322,6 +323,27 @@
               </el-select>
             </div>
           </div>
+
+          <div v-if="curToolbarIcon === 'feedback'" class="resource_box">
+            <h5>{{ drawerTitle }}</h5>
+            <div style="height: 40px"></div>
+            <ul v-if="allFeedbackList.length > 0" class="card-box">
+              <li v-for="item in allFeedbackList" :key="item.id">
+                <span class="el-icon-notebook-2"> 原文</span>
+                <span>{{ item.text }}</span>
+                <el-divider class="mt10" />
+                <span v-html="item.feedBack"></span>
+                <div>
+                  <el-button type="text" class="el-icon-edit" @click="handEditFeedback(item)"> 编辑</el-button>
+                  <el-divider direction="vertical" />
+                  <el-button type="text" class="el-icon-delete" @click="handDelFeedback(item.id)"> 删除</el-button>
+                  <el-divider direction="vertical" />
+                  <el-button type="text" class="el-icon-place" @click="handleLocation(item, 13)"> 定位</el-button>
+                </div>
+              </li>
+            </ul>
+          </div>
+
           <template v-if="curToolbarIcon === 'audit'">
             <AuditRemark :remark-list="remark_list" :is-audit="isShowAudit" @deleteRemarks="deleteRemarks" />
           </template>
@@ -372,9 +394,9 @@
       ref="explanatoryNote"
       :open.sync="editDialogOpen"
       :init-data="oldRichData"
-      title-text="笔记"
-      @confirm="saveNote"
-      @cancel="delNote"
+      :title-text="dialogTitleText"
+      @confirm="dialogSave"
+      @cancel="dialogCancel"
     />
 
     <TranslateDialog :open.sync="showTranslate" :init-text="translateText" :book-id="projectId" title-text="翻译" />
@@ -410,6 +432,9 @@ import {
   GetMyCollectList,
   DeleteMyCollect,
   SearchBookContentText,
+  AddCoursewareFeedback,
+  GetCoursewareFeedbackList,
+  DeleteCoursewareFeedback,
 } from '@/api/book';
 import { getLocalStore } from '@/utils/auth';
 import { toggleFullScreen } from '@/utils/common';
@@ -459,6 +484,7 @@ export default {
       { icon: 'note', title: '笔记', handle: 'getNote', param: { type: '12' } },
       { icon: 'translate', title: '多语言', handle: 'openTranslate', param: { type: '21' } },
       { icon: 'setting', title: '设置', handle: 'openSetting', param: { type: 6 } },
+      { icon: 'feedback', title: '意见反馈', handle: 'getFeedback', param: { type: 22 } },
     ];
 
     const book_id = getLocalStore('book_id') || '';
@@ -510,9 +536,10 @@ export default {
         5: '文本资源',
         6: '设置',
         11: '收藏列表',
-        12: '笔记列表',
+        12: '笔记列表1',
         13: '搜索结果',
         21: '多语言',
+        22: '意见反馈',
       },
       sidebarIconList,
       twoSidebarList: [],
@@ -557,8 +584,10 @@ export default {
       showTranslate: false,
       translateText: '',
       oldRichData: {},
+      dialogType: 1,
       newSelectedInfo: null,
       allCottectList: [],
+      allFeedbackList: [],
       bookChapterList: [],
       book_id: '',
       activeBookChapterId: '',
@@ -592,6 +621,10 @@ export default {
         return this.activeBookChapterId === chapter.id && item && item.file_id;
       };
     },
+    dialogTitleText() {
+      if (this.dialogType === 2) return '反馈';
+      return '笔记';
+    },
   },
   watch: {
     isJudgeCorrect() {
@@ -602,6 +635,8 @@ export default {
         this.getNote();
       } else if (this.curToolbarIcon === 'collect') {
         this.getCollect();
+      } else if (this.curToolbarIcon === 'feedback') {
+        this.getFeedback();
       }
     },
   },
@@ -1156,7 +1191,7 @@ export default {
     /**
      * 定位到对应位置
      * @param {Object} item - 位置对象
-     * @param {number} type - 定位类型(11: 笔记定位, 12: 收藏定位, 0: 资源定位)
+     * @param {number} type - 定位类型(11: 笔记定位, 12: 收藏定位, 13:反馈定位 0: 资源定位)
      */
     handleLocation(item, type) {
       if (type === 0) {
@@ -1176,6 +1211,16 @@ export default {
         window.open(file.file_url);
       }
     },
+
+    dialogSave(obj) {
+      if (this.dialogType === 1) return this.saveNote(obj);
+      if (this.dialogType === 2) return this.saveFeedback(obj);
+    },
+    dialogCancel(id) {
+      if (this.dialogType === 1) return this.delNote(id);
+      if (this.dialogType === 2) return this.delFeedback(id);
+    },
+
     /**
      * 获取笔记列表
      * @param {Object} params - 参数对象
@@ -1217,16 +1262,18 @@ export default {
       );
       if (old) {
         this.oldRichData = old;
+        this.oldRichData.dataStr = old.note;
       }
       this.newSelectedInfo = note;
       this.editDialogOpen = true;
+      this.dialogType = 1;
     },
     saveNote(note) {
       let noteInfo = {
         blockId: this.newSelectedInfo.blockId,
         startIndex: this.newSelectedInfo.startIndex,
         endIndex: this.newSelectedInfo.endIndex,
-        note: note.note,
+        note: note.dataStr,
         text: this.newSelectedInfo.text,
       };
 
@@ -1357,6 +1404,100 @@ export default {
       this.showTranslate = true;
       this.translateText = info.text;
     },
+
+    async getFeedback(params) {
+      if (params && params.type) this.drawerType = Number(params.type);
+      this.allFeedbackList = [];
+      await GetCoursewareFeedbackList({ courseware_id: this.curSelectId }).then((res) => {
+        if (res.status === 1 && res.feedback_list) {
+          res.feedback_list.forEach((x) => {
+            if (x.content) {
+              let n = JSON.parse(x.content);
+              let obj = {
+                coursewareId: x.courseware_id,
+                id: x.id,
+                blockId: n.blockId,
+                startIndex: n.startIndex,
+                endIndex: n.endIndex,
+                text: n.text,
+                feedBack: n.feedBack,
+              };
+              this.allFeedbackList.push(obj);
+            }
+          });
+        }
+      });
+    },
+    async handEditFeedback(feedBack) {
+      this.oldRichData = {};
+      if (this.allFeedbackList.length === 0) {
+        await this.getFeedback();
+      }
+      let old = this.allFeedbackList.find(
+        (x) =>
+          x.coursewareId === feedBack.coursewareId &&
+          x.blockId === feedBack.blockId &&
+          x.startIndex === feedBack.startIndex &&
+          x.endIndex === feedBack.endIndex,
+      );
+      if (old) {
+        this.oldRichData = old;
+        this.oldRichData.dataStr = old.feedBack;
+      }
+      this.newSelectedInfo = feedBack;
+      this.editDialogOpen = true;
+      this.dialogType = 2;
+    },
+    saveFeedback(feedBack) {
+      if (feedBack.id) {
+        this.delFeedback(feedBack.id);
+      }
+
+      if (feedBack.dataStr) {
+        let feedBackInfo = {
+          blockId: this.newSelectedInfo.blockId,
+          startIndex: this.newSelectedInfo.startIndex,
+          endIndex: this.newSelectedInfo.endIndex,
+          feedBack: feedBack.dataStr,
+          text: this.newSelectedInfo.text,
+        };
+
+        let reqData = {
+          courseware_id: this.newSelectedInfo.coursewareId, // 课件 ID
+          component_id: 'WHOLE',
+          content: JSON.stringify(feedBackInfo),
+          content_select: this.newSelectedInfo.text,
+        };
+
+        AddCoursewareFeedback(reqData).then(() => {
+          this.getFeedback();
+        });
+      }
+      this.editDialogOpen = false;
+      this.newSelectedInfo = null;
+      this.selectedInfo = null;
+    },
+    handDelFeedback(id) {
+      this.$confirm('确定要删除此条反馈吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning',
+      })
+        .then(() => {
+          this.delFeedback(id);
+        })
+        .catch(() => {});
+    },
+    delFeedback(id) {
+      const feedBackId = id || (this.oldRichData && this.oldRichData.id);
+      if (!feedBackId) return;
+      DeleteCoursewareFeedback({ id: feedBackId })
+        .then((res) => {
+          this.allFeedbackList = this.allFeedbackList.filter((x) => x.id !== feedBackId);
+        })
+        .catch((err) => {});
+    },
+
     getSearch(params) {
       if (params && params.type) this.drawerType = Number(params.type);
     },
@@ -1632,7 +1773,9 @@ $total-width: $courseware-width + $courseware-left-margin + $courseware-right-ma
               text-overflow: ellipsis;
               word-break: break-word;
               white-space: normal;
-              -webkit-line-clamp: 2; /* 多行省略行数,按需调整 */
+              -webkit-line-clamp: 2;
+
+              /* 多行省略行数,按需调整 */
               -webkit-box-orient: vertical;
             }
           }