Quellcode durchsuchen

编辑页面选择列表

dusenyao vor 1 Monat
Ursprung
Commit
5a7424a230

+ 4 - 0
src/api/book.js

@@ -18,6 +18,10 @@ export function ChapterGetBookChapterStruct(data) {
 /**
  * @description 得到教材章节结构展开列表
  * @param {object} data
+ * @param {string} data.book_id - 教材ID
+ * @param {number} data.node_deep_mode - 节点深度模式
+ * @param {'true'|'false'} data.is_contain_producer - 是否包含制作人信息
+ * @param {'true'|'false'} data.is_contain_auditor - 是否包含审核人信息
  */
 export function ChapterGetBookChapterStructExpandList(data) {
   return http.post(

+ 27 - 0
src/api/project.js

@@ -38,6 +38,9 @@ export function GetMyBookCoursewareTaskList(data) {
 /**
  * @description 得到教材课件信息
  * @param {object} data
+ * @param {string} data.id 课件ID
+ * @param {'true' | 'false'} data.is_contain_producer 是否包含制作人信息
+ * @param {'true' | 'false'} data.is_contain_audit 是否包含审校人信息
  */
 export function GetBookCoursewareInfo(data) {
   return http.post(`${process.env.VUE_APP_EepServer}?MethodName=project_task_manager-GetBookCoursewareInfo`, data);
@@ -74,3 +77,27 @@ export function AddAuditNode(data) {
 export function DeleteAuditNode(data) {
   return http.post(`${process.env.VUE_APP_EepServer}?MethodName=book_audit_manager-DeleteAuditNode`, data);
 }
+
+/**
+ * @description 设置审校人
+ * @param {object} data
+ */
+export function SetAuditor(data) {
+  return http.post(`${process.env.VUE_APP_EepServer}?MethodName=book_audit_manager-SetAuditor`, data);
+}
+
+/**
+ * @description 设置主审人
+ * @param {object} data
+ */
+export function SetMainAuditor(data) {
+  return http.post(`${process.env.VUE_APP_EepServer}?MethodName=book_audit_manager-SetMainAuditor`, data);
+}
+
+/**
+ * @description 得到章节节点审校人列表
+ * @param {object} data
+ */
+export function GetChapterNodeAuditorList(data) {
+  return http.post(`${process.env.VUE_APP_EepServer}?MethodName=book_audit_manager-GetChapterNodeAuditorList`, data);
+}

+ 12 - 0
src/icons/svg/menu-item.svg

@@ -0,0 +1,12 @@
+<?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="1748119730242" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4550"
+  data-spm-anchor-id="a313x.search_index.0.i2.104a3a81fAh7GP" xmlns:xlink="http://www.w3.org/1999/xlink" width="16"
+  height="16">
+  <g transform="rotate(-90) translate(-1024, 0)">
+    <path
+      d="M560.938667 162.261333l298.666666 209.066667A85.333333 85.333333 0 0 1 896 441.173333V810.666667a85.333333 85.333333 0 0 1-85.333333 85.333333H213.333333a85.333333 85.333333 0 0 1-85.333333-85.333333v-369.450667a85.333333 85.333333 0 0 1 36.394667-69.888l298.666666-209.066667a85.333333 85.333333 0 0 1 97.877334 0zM810.666667 441.173333l-298.666667-209.066666-298.666667 209.066666V810.666667h597.333334v-369.450667z"
+      p-id="4551" data-spm-anchor-id="a313x.search_index.0.i4.104a3a81fAh7GP"></path>
+    <path d="M469.333333 640h85.333334v128h-85.333334z" p-id="4552"></path>
+  </g>
+</svg>

+ 9 - 0
src/utils/common.js

@@ -85,3 +85,12 @@ export function handleToneValue(valItem) {
 
   return numList.length === 0 ? [{ con: valItem }] : numList;
 }
+
+/**
+ * @description 是否为 true
+ * @param {'true'|'false'} value
+ * @returns {boolean}
+ */
+export function isTrue(value) {
+  return value === 'true';
+}

+ 3 - 1
src/views/book/courseware/preview/components/picture/PicturePreview.vue

@@ -164,7 +164,9 @@ export default {
     // Object.values(this.pictureObserversMap).forEach((observer) => {
     //   observer.disconnect();
     // });
-    this.resizeObserver.disconnect();
+    if (this.resizeObserver) {
+      this.resizeObserver.disconnect();
+    }
   },
   methods: {
     // 是否显示左右箭头

+ 3 - 1
src/views/book/courseware/preview/components/video/VideoPreview.vue

@@ -167,7 +167,9 @@ export default {
     });
   },
   beforeDestroy() {
-    this.resizeObserver.disconnect();
+    if (this.resizeObserver) {
+      this.resizeObserver.disconnect();
+    }
   },
   methods: {
     handleAudioClick(index) {

+ 122 - 20
src/views/personal_workbench/edit_task/preview/index.vue

@@ -4,14 +4,36 @@
 
     <div class="task-preview__header">
       <div class="menu">
-        <span></span>
+        <el-popover placement="bottom" trigger="click" popper-class="menu-popover">
+          <div class="menu-list">
+            <div
+              v-for="{ id: nodeId, name, deep, is_leaf_chapter, is_my_edit_task } in node_list"
+              :key="nodeId"
+              :class="['menu-item', { active: curSelectId === nodeId }]"
+              :style="computedNameStyle(deep, isTrue(is_leaf_chapter))"
+              @click="selectNode(nodeId, isTrue(is_leaf_chapter))"
+            >
+              <SvgIcon
+                v-if="isTrue(is_leaf_chapter)"
+                size="12"
+                icon-class="menu-item"
+                :class-name="isTrue(is_my_edit_task) ? 'my-edit-task' : ''"
+              />
+              <span class="name">
+                {{ name }}
+              </span>
+            </div>
+          </div>
+          <el-button slot="reference">{{ courseware_info.name_path }}</el-button>
+        </el-popover>
+
         <span class="link" @click="goBackBookList">返回教材列表</span>
       </div>
       <div class="courseware">
         <span class="name-path">{{ courseware_info.name_path }}</span>
         <div class="operator">
-          <span class="link" @click="editTask">开始编辑</span>
-          <span class="link">提交审核</span>
+          <span v-if="isTrue(courseware_info.is_my_edit_task)" class="link" @click="editTask">开始编辑</span>
+          <span v-if="isTrue(courseware_info.is_my_audit_task)" class="link">提交审核</span>
         </div>
       </div>
     </div>
@@ -28,8 +50,9 @@
 </template>
 
 <script>
-import { GetBookCoursewareInfo, GetMyBookCoursewareTaskList } from '@/api/project';
-import { ContentGetCoursewareContent_View } from '@/api/book';
+import { GetBookCoursewareInfo } from '@/api/project';
+import { ContentGetCoursewareContent_View, ChapterGetBookChapterStructExpandList } from '@/api/book';
+import { isTrue } from '@/utils/common';
 
 import MenuPage from '@/views/personal_workbench/menu.vue';
 import CoursewarePreview from '@/views/book/courseware/preview/CoursewarePreview.vue';
@@ -44,7 +67,11 @@ export default {
     return {
       id: this.$route.params.id,
       project_id: this.$route.query.project_id,
-      courseware_info: {},
+      curSelectId: this.$route.params.id,
+      courseware_info: {
+        is_my_edit_task: 'false',
+        is_my_audit_task: 'false',
+      },
       background: {
         background_image_url: '',
         background_position: {
@@ -58,13 +85,14 @@ export default {
         row_list: [],
       },
       component_list: [],
-      courseware_list: [],
+      node_list: [],
+      isTrue,
     };
   },
   created() {
-    this.getBookCoursewareInfo();
-    this.getCoursewareComponentContent_View();
-    this.getMyBookCoursewareTaskList();
+    this.getBookCoursewareInfo(this.id);
+    this.getCoursewareComponentContent_View(this.id);
+    this.getBookChapterStructExpandList();
   },
   methods: {
     goBackBookList() {
@@ -76,28 +104,64 @@ export default {
         query: { project_id: this.project_id },
       });
     },
-    getCoursewareComponentContent_View() {
-      ContentGetCoursewareContent_View({ id: this.id }).then(({ content, component_list }) => {
+    /**
+     * 得到课件内容(展示内容)
+     * @param {string} id - 课件ID
+     */
+    getCoursewareComponentContent_View(id) {
+      ContentGetCoursewareContent_View({ id }).then(({ content, component_list }) => {
         if (content) this.data = JSON.parse(content);
         if (component_list) this.component_list = component_list;
       });
     },
     /**
      * 得到教材课件信息
+     * @param {string} id - 课件ID
      */
-    getBookCoursewareInfo() {
-      GetBookCoursewareInfo({ id: this.id }).then(({ courseware_info }) => {
-        this.courseware_info = courseware_info;
-      });
+    getBookCoursewareInfo(id) {
+      GetBookCoursewareInfo({ id, is_contain_producer: 'true', is_contain_auditor: 'true' }).then(
+        ({ courseware_info }) => {
+          this.courseware_info = courseware_info;
+        },
+      );
     },
     /**
-     * 得到我的教材课件任务列表
+     * 得到教材章节结构展开列表
      */
-    getMyBookCoursewareTaskList() {
-      GetMyBookCoursewareTaskList({ project_id: this.project_id }).then(({ courseware_list }) => {
-        this.courseware_list = courseware_list;
+    getBookChapterStructExpandList() {
+      ChapterGetBookChapterStructExpandList({
+        book_id: this.project_id,
+        node_deep_mode: 0,
+        is_contain_producer: 'true',
+        is_contain_auditor: 'true',
+      }).then(({ node_list }) => {
+        this.node_list = node_list;
       });
     },
+    /**
+     * 选择节点
+     * @param {string} nodeId 节点ID
+     * @param {boolean} isLeaf 是否是叶子节点
+     */
+    selectNode(nodeId, isLeaf) {
+      if (!isLeaf) return;
+      if (this.curSelectId === nodeId) return;
+      this.curSelectId = nodeId;
+      this.getCoursewareComponentContent_View(nodeId);
+      this.getBookCoursewareInfo(nodeId);
+    },
+    /**
+     * 计算章节名称样式
+     * @param {number} deep - 节点深度
+     * @param {boolean} isLeaf - 是否是叶子节点
+     * @returns {Object} - 样式对象
+     */
+    computedNameStyle(deep, isLeaf) {
+      return {
+        'padding-left': `${(deep - 1) * 16}px`,
+        cursor: isLeaf ? 'pointer' : 'auto',
+      };
+    },
   },
 };
 </script>
@@ -115,6 +179,10 @@ export default {
       width: 360px;
       padding: 4px 8px;
       border-right: $border;
+
+      .el-popover__reference {
+        border: none;
+      }
     }
 
     .courseware {
@@ -154,3 +222,37 @@ export default {
   }
 }
 </style>
+
+<style lang="scss" scoped>
+.menu-popover {
+  .menu-list {
+    display: flex;
+    flex-direction: column;
+
+    .menu-item {
+      display: flex;
+      align-items: center;
+
+      .svg-icon {
+        margin-left: 4px;
+
+        &.my-edit-task {
+          color: $right-color;
+        }
+      }
+
+      .name {
+        flex: 1;
+        padding: 4px 8px 4px 2px;
+        border-radius: 4px;
+      }
+
+      &.active {
+        .name {
+          background-color: $main-active-color;
+        }
+      }
+    }
+  }
+}
+</style>

+ 25 - 8
src/views/personal_workbench/project/ProductionEditorialManage.vue

@@ -29,7 +29,7 @@
           <span class="title-cell">操作</span>
         </div>
         <div
-          v-for="{ id, name, deep, producer_list, is_leaf_chapter } in node_list"
+          v-for="{ id, name, deep, producer_list, is_leaf_chapter, auditor_desc } in node_list"
           :key="id"
           :class="['catalogue', { active: curSelectId === id }]"
           @click="selectActiveChapter(id, is_leaf_chapter === 'true')"
@@ -44,12 +44,12 @@
           <div class="producer">
             <span>{{ producer_list.map((producer) => producer.name).join(';') }}</span>
           </div>
-          <div class="audit"></div>
+          <div class="audit">{{ auditor_desc }}</div>
           <div class="status"></div>
           <div class="operator">
             <span class="link">修改</span>
             <span class="link" @click="openSetProducer(id)">设置制作人</span>
-            <span v-if="is_leaf_chapter === 'true'" class="link">设置审校人</span>
+            <span v-if="is_leaf_chapter === 'true'" class="link" @click="openSetAuditor(id)">设置审校人</span>
             <span class="link danger" @click="deleteChapter(id)">删除</span>
           </div>
         </div>
@@ -67,23 +67,31 @@
       @addCourseware="chapterAddCoursewareToBook"
     />
 
-    <SetProducer
+    <SetUser
       :id="producer.id"
-      :visible="producer.visible"
+      :visible.sync="producer.visible"
       :member-list="member_list"
       @close="producer.visible = false"
       @chapterSetProducer="chapterSetProducer"
     />
 
     <SetAuditSteps :book-id="book_id" :visible.sync="visibleAuditSteps" @updateProject="getProjectBaseInfo" />
+
+    <SetAuditor
+      :id="auditor.id"
+      :visible.sync="auditor.visible"
+      :member-list="member_list"
+      @close="getBookChapterStructExpandList"
+    />
   </div>
 </template>
 
 <script>
 import AddChapter from './components/AddChapter.vue';
-import SetProducer from './components/SetProducer.vue';
+import SetUser from './components/SetUser.vue';
 import SetAuditSteps from './components/SetAuditSteps.vue';
 import MenuPage from '@/views/personal_workbench/menu.vue';
+import SetAuditor from './components/SetAuditor.vue';
 
 import { GetProjectBaseInfo } from '@/api/project';
 import {
@@ -98,9 +106,10 @@ export default {
   name: 'ProductionEditorialManage',
   components: {
     AddChapter,
-    SetProducer,
+    SetUser,
     MenuPage,
     SetAuditSteps,
+    SetAuditor,
   },
   data() {
     return {
@@ -118,6 +127,10 @@ export default {
         id: '', // 章节ID
       },
       visibleAuditSteps: false, // 设置审校步骤弹窗
+      auditor: {
+        visible: false, // 设置审校人弹窗
+        id: '', // 章节ID
+      },
     };
   },
   created() {
@@ -152,6 +165,7 @@ export default {
         book_id: this.book_id,
         node_deep_mode: 0,
         is_contain_producer: 'true',
+        is_contain_auditor: 'true',
       }).then(({ node_list }) => {
         this.node_list = node_list;
       });
@@ -227,6 +241,10 @@ export default {
       this.producer.visible = true;
       this.producer.id = id;
     },
+    openSetAuditor(id) {
+      this.auditor.visible = true;
+      this.auditor.id = id;
+    },
     /**
      * 设置制作人
      * @param {Object} data - 章节制作人数据
@@ -237,7 +255,6 @@ export default {
       ChapterSetProducer({ book_id: this.book_id, ...data })
         .then(() => {
           this.getBookChapterStructExpandList();
-          this.producer.visible = false;
           this.$message.success('制作人设置成功');
         })
         .catch(({ error }) => {

+ 146 - 0
src/views/personal_workbench/project/components/SetAuditor.vue

@@ -0,0 +1,146 @@
+<template>
+  <el-dialog :title="title" :visible="visible" width="750px" @close="dialogClose">
+    <el-table :data="flow_node_list" border>
+      <el-table-column label="序号" width="60" align="center" header-align="center">
+        <template slot-scope="scope">
+          {{ scope.$index + 1 }}
+        </template>
+      </el-table-column>
+      <el-table-column label="审校步骤" prop="name" width="120" header-align="center" align="center" />
+      <el-table-column label="审校人" width="180" header-align="center" align="center">
+        <template slot-scope="{ row }">
+          <span>{{ row.auditor_list.map((auditor) => auditor.name).join(', ') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="主审校人" width="120" header-align="center" align="center">
+        <template slot-scope="{ row }">
+          <span>{{ row?.main_auditor?.name }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" fixed="right" header-align="center" align="center">
+        <template slot-scope="{ row }">
+          <span class="link" @click="openSetUserDialog(row.id, 'auditor')">设置审校人</span>
+          <span class="link" @click="openSetUserDialog(row.id, 'mainAuditor')">设置主审校人</span>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <div slot="footer">
+      <el-button @click="dialogClose">关闭</el-button>
+    </div>
+
+    <SetUser
+      :id="user.flow_node_id"
+      :member-list="memberList"
+      :type="user.type"
+      :visible.sync="user.visible"
+      @SetAuditor="setAuditor"
+      @SetMainAuditor="setMainAuditor"
+    />
+  </el-dialog>
+</template>
+
+<script>
+import SetUser from './SetUser.vue';
+
+import { SetAuditor, SetMainAuditor, GetChapterNodeAuditorList } from '@/api/project';
+
+export default {
+  name: 'SetAuditor',
+  components: {
+    SetUser,
+  },
+  props: {
+    visible: {
+      type: Boolean,
+      default: false,
+    },
+    id: {
+      type: String,
+      default: '',
+    },
+    memberList: {
+      type: Array,
+      default: () => [],
+    },
+  },
+  data() {
+    return {
+      flow_node_list: [],
+      chapter_node_name_path: '',
+      auditor_desc: '',
+      user: {
+        type: 'auditor',
+        visible: false,
+        flow_node_id: '',
+      },
+    };
+  },
+  computed: {
+    title() {
+      return `设置审校人(${this.chapter_node_name_path})`;
+    },
+  },
+  watch: {
+    visible(newVal) {
+      if (newVal) {
+        this.getChapterNodeAuditorList();
+      }
+    },
+  },
+  methods: {
+    dialogClose() {
+      this.$emit('update:visible', false);
+      this.$emit('close');
+      this.flow_node_list = [];
+      this.chapter_node_name_path = '';
+      this.auditor_desc = '';
+      this.user = {
+        type: 'auditor',
+        visible: false,
+        flow_node_id: '',
+      };
+    },
+    openSetUserDialog(flow_node_id, type) {
+      this.user.flow_node_id = flow_node_id;
+      this.user.type = type;
+      this.user.visible = true;
+    },
+    /**
+     * @description 设置审校人
+     * @param {object} param0 - 参数对象
+     * @param {string} param0.flow_node_id - 审核节点ID
+     * @param {Array<string>} param0.user_id_list - 用户ID列表
+     */
+    setAuditor({ flow_node_id, user_id_list }) {
+      SetAuditor({ book_chapter_node_id: this.id, flow_node_id, user_id_list }).then(() => {
+        this.$message.success('设置审校人成功');
+        this.getChapterNodeAuditorList();
+      });
+    },
+    /**
+     * @description 设置主审校人
+     * @param {object} param0 - 参数对象
+     * @param {string} param0.flow_node_id - 审核节点ID
+     * @param {string} param0.user_id - 用户ID
+     */
+    setMainAuditor({ flow_node_id, user_id }) {
+      SetMainAuditor({ book_chapter_node_id: this.id, flow_node_id, user_id }).then(() => {
+        this.$message.success('设置主审校人成功');
+        this.getChapterNodeAuditorList();
+      });
+    },
+    getChapterNodeAuditorList() {
+      GetChapterNodeAuditorList({ book_chapter_node_id: this.id }).then(
+        ({ flow_node_list, chapter_node_name_path, auditor_desc }) => {
+          this.flow_node_list = flow_node_list;
+          this.chapter_node_name_path = chapter_node_name_path;
+          this.auditor_desc = auditor_desc;
+        },
+      );
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped></style>

+ 0 - 53
src/views/personal_workbench/project/components/SetProducer.vue

@@ -1,53 +0,0 @@
-<template>
-  <el-dialog title="设置制作人" :visible="visible" width="320px" :show-close="false" @close="dialogClose">
-    <el-select v-model="producer" placeholder="请选择制作人" multiple>
-      <el-option v-for="item in memberList" :key="item.id" :label="item.name" :value="item.id" />
-    </el-select>
-
-    <div slot="footer">
-      <el-button @click="dialogClose">取消</el-button>
-      <el-button type="primary" @click="addChapterNode">确定</el-button>
-    </div>
-  </el-dialog>
-</template>
-
-<script>
-export default {
-  name: 'SetProducer',
-  props: {
-    visible: {
-      type: Boolean,
-      required: true,
-    },
-    id: {
-      type: String,
-      default: '',
-    },
-    memberList: {
-      type: Array,
-      required: true,
-    },
-  },
-  data() {
-    return {
-      producer: [],
-    };
-  },
-  methods: {
-    dialogClose() {
-      this.$emit('close');
-      this.producer = [];
-    },
-    addChapterNode() {
-      this.$emit('chapterSetProducer', { node_id: this.id, producer_id_list: this.producer });
-      this.producer = [];
-    },
-  },
-};
-</script>
-
-<style lang="scss" scoped>
-.el-select {
-  width: 100%;
-}
-</style>

+ 90 - 0
src/views/personal_workbench/project/components/SetUser.vue

@@ -0,0 +1,90 @@
+<template>
+  <el-dialog :title="title" :visible="visible" width="320px" :append-to-body="true" @close="dialogClose">
+    <el-select v-model="user[bindKey]" :placeholder="placeholder" :multiple="isMultiple">
+      <el-option v-for="item in memberList" :key="item.id" :label="item.name" :value="item.id" />
+    </el-select>
+
+    <div slot="footer">
+      <el-button @click="dialogClose">取消</el-button>
+      <el-button type="primary" @click="addChapterNode">确定</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+export default {
+  name: 'SetUser',
+  props: {
+    visible: {
+      type: Boolean,
+      required: true,
+    },
+    id: {
+      type: String,
+      default: '',
+    },
+    memberList: {
+      type: Array,
+      required: true,
+    },
+    type: {
+      type: String,
+      default: 'producer',
+    },
+  },
+  data() {
+    return {
+      user: {
+        id_list: [],
+        id: '',
+      },
+      typeList: [
+        { type: 'producer', label: '设置制作人', placeholder: '请选择制作人', bindKey: 'id_list', isMultiple: true },
+        { type: 'auditor', label: '设置审校人', placeholder: '请选择审校人', bindKey: 'id_list', isMultiple: true },
+        { type: 'mainAuditor', label: '设置主审校人', placeholder: '请选择主审校人', bindKey: 'id', isMultiple: false },
+      ],
+    };
+  },
+  computed: {
+    title() {
+      return this.typeList.find((item) => item.type === this.type).label;
+    },
+    placeholder() {
+      return this.typeList.find((item) => item.type === this.type).placeholder;
+    },
+    isMultiple() {
+      return this.typeList.find((item) => item.type === this.type).isMultiple;
+    },
+    bindKey() {
+      return this.typeList.find((item) => item.type === this.type).bindKey;
+    },
+  },
+  methods: {
+    dialogClose() {
+      this.$emit('update:visible', false);
+      this.user = {
+        id_list: [],
+        id: '',
+      };
+    },
+    addChapterNode() {
+      if (this.type === this.typeList[0].type) {
+        this.$emit('chapterSetProducer', { node_id: this.id, producer_id_list: this.user.id_list });
+      }
+      if (this.type === this.typeList[1].type) {
+        this.$emit('SetAuditor', { flow_node_id: this.id, user_id_list: this.user.id_list });
+      }
+      if (this.type === this.typeList[2].type) {
+        this.$emit('SetMainAuditor', { flow_node_id: this.id, user_id: this.user.id });
+      }
+      this.dialogClose();
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.el-select {
+  width: 100%;
+}
+</style>