Просмотр исходного кода

feat(文档模板): 新增文档模板管理功能及相关组件

liujt 6 месяцев назад
Родитель
Сommit
de2fc73d16

+ 36 - 0
src/api/home/index.js

@@ -81,3 +81,39 @@ export async function getList(params) {
   }
   return Promise.reject(new Error(res.data.message));
 }
+
+/**
+ * 我的项目统计
+ * @params params
+ */
+export async function getMyProjectTotal(params) {
+  const res = await request.get(`/pro/projects/v1/getMyProjectTotal`, { params });
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+/**
+ * 我的工单统计
+ * @params params
+ */
+export async function getMyWorkOrderTotal(params) {
+  const res = await request.get(`/eam/workorder/v1/getMyWorkOrderTotal`, { params });
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+/**
+ * 我的任务统计
+ * @params params
+ */
+export async function getMyTaskTotal(params) {
+  const res = await request.get(`/pro/projectstask/v1/getMyTaskTotal`, { params });
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}

+ 101 - 0
src/views/bpm/documents/documentTemplate/components/file-add.vue

@@ -0,0 +1,101 @@
+<template>
+    <div class="ele-body">
+        <el-card shadow="never">
+            <el-tabs v-model="tabValue" type="card" @tab-click="handleTabClick">
+                <el-tab-pane label="范文信息" name="1">
+                    <el-form
+                        :model="formData"
+                        ref="form"
+                        label-width="110px"
+                        :rules="rules"
+                        style="margin-top: 20px;"
+                    >
+                        <el-row :gutter="24">
+                            <el-col :span="6">
+                                <el-form-item label="范文编号" prop="documentNo">
+                                    <el-input
+                                        placeholder="请输入范文编号"
+                                        v-model="formData.documentNo"
+                                    >
+                                    </el-input>
+                                </el-form-item>
+                            </el-col>
+                            <el-col :span="6">
+                                <el-form-item label="范文名称" prop="documentName">
+                                    <el-input
+                                        placeholder="请输入范文名称"
+                                        v-model="formData.documentName"
+                                    >
+                                    </el-input>
+                                </el-form-item>
+                            </el-col>
+                            <el-col :span="6">
+                                <el-form-item label="状态" prop="status">
+                                    <el-switch
+                                        v-model="formData.status"
+                                        active-text="启用"
+                                        inactive-text="停用">
+                                    </el-switch>
+                                </el-form-item>
+                            </el-col>
+                        </el-row>
+                    </el-form>
+                </el-tab-pane>
+                <el-tab-pane label="稿纸信息" name="2">
+                    <MainBodyTemplate></MainBodyTemplate>
+                </el-tab-pane>
+                <el-tab-pane label="正文" name="3"></el-tab-pane>
+            </el-tabs>
+            <div slot="footer" class="footer">
+                <el-button type="primary" @click="save" v-click-once>保存</el-button>
+                <el-button @click="cancel">取消</el-button>
+                </div>
+        </el-card>
+    </div>
+</template>
+<script>
+import MainBodyTemplate from './mainBodyTemplate.vue'
+export default {
+  components: {
+    MainBodyTemplate
+  },
+
+  data() {
+    return {
+      tabValue: '1',
+      formData: {
+        documentNo: '',
+        documentName: '',
+        status: true,
+      },
+      rules: {
+        documentNo: [{ required: true, message: '请输入范文编号', trigger: 'blur' }],
+        documentName: [{ required: true, message: '请输入范文名称', trigger: 'blur' }],
+        status: [{ required: true, message: '请选择状态', trigger: 'blur' }],
+      }
+    }
+  },
+  methods: {
+    handleTabClick(tab) {
+      this.tabValue = tab.name;
+    },
+    save() {
+    //   this.$refs.form.validate((valid) => {
+    //     if (valid) {
+    //       this.$emit('save', this.form);
+    //     } else {
+    //       console.log('校验失败');
+    //     }
+    //   });
+    },
+    cancel() {
+      this.$router.go(-1);
+    },
+  }
+}
+</script>
+<style scoped>
+.footer {
+  text-align: right;
+}
+</style>

+ 149 - 0
src/views/bpm/documents/documentTemplate/components/file-search.vue

@@ -0,0 +1,149 @@
+<!-- 搜索表单 -->
+<template>
+  <div style="display: flex; align-items: center">
+    <el-form
+      size="small"
+      class="ele-form-search"
+      @keyup.enter.native="search"
+      @submit.native.prevent
+      style="width: 260px; display: inline-block"
+    >
+      <el-form-item label="文档名称" label-width="80px">
+        <el-input
+          clearable
+          size="small"
+          v-model.trim="where.name"
+          placeholder="请输入文档名称"
+        />
+      </el-form-item>
+    </el-form>
+    <el-button
+      size="small"
+      type="primary"
+      icon="el-icon-search"
+      class="ele-btn-icon"
+      @click="search"
+    >
+      查询
+    </el-button>
+    <el-popover
+      placement="bottom"
+      title="查询"
+      width="600"
+      trigger="manual"
+      v-model="visible"
+    >
+      <el-form
+        size="small"
+        class="ele-form-search"
+        @keyup.enter.native="search"
+        @submit.native.prevent
+        style="width: 500px; display: inline-block"
+      >
+        <el-row :gutter="24">
+          <el-col :span="24">
+            <el-form-item label="创建人" label-width="80px">
+              <el-input
+                clearable
+                size="small"
+                v-model="where.createUserName"
+                placeholder="请选择"
+                @click.native="$refs.addRef.open()"
+                readonly
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="文档编码" label-width="80px">
+              <el-input
+                clearable
+                size="small"
+                v-model.trim="where.code"
+                placeholder="请输入文档编码"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <div style="justify-content: flex-end; display: flex">
+              <el-button size="small" @click="visible = false">
+                关闭
+              </el-button>
+              <el-button
+                size="small"
+                type="primary"
+                icon="el-icon-search"
+                class="ele-btn-icon"
+                @click="search"
+                style="margin-left: 5px"
+              >
+                查询
+              </el-button>
+              <el-button size="small" @click="reset" style="margin-left: 5px">
+                重置
+              </el-button>
+            </div>
+          </el-col>
+        </el-row>
+      </el-form>
+      <el-button
+        size="small"
+        type="primary"
+        icon="el-icon-search"
+        class="ele-btn-icon"
+        slot="reference"
+        style="margin-left: 5px"
+        @click="visible = !visible"
+      >
+        更多查询
+      </el-button>
+    </el-popover>
+    <!-- <Add ref="addRef" @success="success" :isSearch="true" /> -->
+  </div>
+</template>
+
+<script>
+  // import Add from '@/views/doc/components/power/add.vue';
+
+  export default {
+    components: {
+      // Add
+    },
+    data() {
+      // 默认表单数据
+      const defaultWhere = {
+        name: '',
+        code: '',
+        createUserName: '',
+        createUserIds: []
+      };
+      return {
+        // 表单数据
+        where: { ...defaultWhere },
+        visible: false
+      };
+    },
+    computed: {
+      // 是否开启响应式布局
+      styleResponsive() {
+        return this.$store.state.theme.styleResponsive;
+      }
+    },
+    methods: {
+      success(data) {
+        console.log(data, 'data');
+        this.where.createUserIds = data.map((item) => item.id);
+        this.where.createUserName = data.map((item) => item.name).toString();
+      },
+      /* 搜索 */
+      search() {
+        this.$emit('search', this.where);
+        this.visible = false;
+      },
+      /*  重置 */
+      reset() {
+        this.where = { ...this.defaultWhere };
+        this.search();
+      }
+    }
+  };
+</script>

+ 709 - 0
src/views/bpm/documents/documentTemplate/components/file-table-list.vue

@@ -0,0 +1,709 @@
+<template>
+  <div>
+    <seek-page :seekList="seekList" @search="reload"></seek-page>
+    <!-- 数据表格 -->
+    <ele-pro-table
+      ref="table"
+      :columns="columns"
+      :datasource="datasource"
+      height="calc(45vh)"
+      tool-class="ele-toolbar-form"
+      :initLoad="false"
+      row-key="id"
+      :current.sync="current"
+      :selection.sync="selection"
+      highlight-current-row
+      @row-click="rowClick"
+      @selection-change="selectionClick"
+      @done="done"
+      :toolbar="!isPop"
+    >
+      <!-- 表头工具栏 -->
+      <template v-slot:toolbar>
+        <el-dropdown trigger="click" v-if="lcyStatus == 1">
+          <el-button type="primary">
+            新建<i class="el-icon-arrow-down el-icon--right"></i>
+          </el-button>
+          <el-dropdown-menu slot="dropdown">
+            <el-dropdown-item
+              @click.native="
+                parenOpen('add', {
+                  power: 'add',
+                  dataKey: 'parentData',
+                  isArr: false
+                })
+              "
+              >新建文件夹</el-dropdown-item
+            >
+            <el-dropdown-item
+              @click.native="
+                openEdit('add', '', {
+                  power: 'add',
+                  dataKey: 'parentData',
+                  isArr: false
+                })
+              "
+              >新建文档</el-dropdown-item
+            >
+          </el-dropdown-menu>
+        </el-dropdown>
+  
+        <el-button
+          :disabled="selection.length > 1"
+          type="danger"
+          @click.native="move"
+        >
+          删除
+        </el-button>
+      </template>
+
+      <!-- 操作列 -->
+      <template v-slot:action="{ row }">
+        <el-link type="primary" :underline="false" icon="el-icon-edit">
+          复制
+        </el-link>
+        <el-dropdown
+          trigger="click"
+          v-if="
+            lcyStatus == 1 &&
+            (row.reviewStatus == 0 || row.reviewStatus == 3) &&
+            row.status == 0
+          "
+        >
+          <el-link type="primary" :underline="false" icon="el-icon-edit">
+            编辑
+          </el-link>
+          <el-dropdown-menu slot="dropdown">
+            <el-dropdown-item
+              @click.native="
+                openEdit('edit', row, {
+                  power: 'revise',
+                  dataKey: 'current',
+                  isArr: false
+                })
+              "
+              >修改</el-dropdown-item
+            >
+            <el-dropdown-item>
+              <el-popconfirm
+                class="ele-action"
+                title="确定要删除此文档吗?"
+                @confirm="
+                  remove(row, {
+                    power: 'del',
+                    dataKey: 'current',
+                    isArr: false
+                  })
+                "
+              >
+                <template v-slot:reference>
+                  <el-link type="danger" :underline="false"> 删除 </el-link>
+                </template>
+              </el-popconfirm>
+            </el-dropdown-item>
+          </el-dropdown-menu>
+        </el-dropdown>
+
+        <el-link type="primary" :underline="false" icon="el-icon-edit">
+          停用
+        </el-link>
+        <el-link type="danger" :underline="false" icon="el-icon-edit">
+          删除
+        </el-link>
+      </template>
+    </ele-pro-table>
+
+    <!-- <sendEdit ref="sendEditRef" @done="reload" :isAdd="false"></sendEdit> -->
+    <process-submit-dialog
+      :processSubmitDialogFlag.sync="processSubmitDialogFlag"
+      v-if="processSubmitDialogFlag"
+      ref="processSubmitDialogRef"
+      @reload="reload"
+    ></process-submit-dialog>
+    <ele-modal
+      width="70vw"
+      :visible.sync="powerOpenShow"
+      :close-on-click-modal="false"
+      custom-class="ele-dialog-form"
+      :maxable="true"
+      append-to-body
+    >
+      <!-- <Power style="" @powerSave="powerSave" ref="PowerRefAll" /> -->
+    </ele-modal>
+  </div>
+</template>
+
+<script>
+  import fileSearch from './file-search.vue';
+  // import fileAdd from './file-add.vue';
+  // import fileEditAll from './file-editAll.vue';
+  // import move from './move.vue';
+
+  // import Info from './info.vue';
+  // import folderInfo from './folderInfo.vue';
+  // import processSubmitDialog from '@/components/processSubmitDialog/processSubmitDialog.vue';
+  // import Version from './version.vue';
+  // import Power from './power/index.vue';
+  // import Issue from './issue.vue';
+  // import Action from './action.vue';
+  // import Change from './change.vue';
+  // import Receive from './receive.vue';
+  // import print from './print.vue';
+  // import bpm from './bpm.vue';
+  // import browse from './browse.vue';
+  // import sendEdit from '@/views/doc/issue_doc/components/edit.vue';
+
+  import { isPower, isCheckOut, fileStatus, isCreateUserId } from '../util.js';
+  import { getFile } from '@/api/system/file/index.js';
+  // import {
+  //   fileDeleteAPI,
+  //   filePageAPI,
+  //   checkEnter,
+  //   checkOut,
+  //   fileUpdateAPI,
+  //   updateLcyStatus,
+  //   noUpdateLcyStatus,
+  //   fileUpdateAllAPI
+  // } from '@/api/doc-manage';
+  export default {
+    components: {
+      fileSearch,
+      // fileEdit,
+      // Info,
+      // Version,
+      // Power,
+      // Issue,
+      // Action,
+      // Change,
+      // folderInfo,
+      // processSubmitDialog,
+      // Receive,
+      // print,
+      // fileEditAll,
+      // bpm,
+      // sendEdit,
+      // browse,
+      // move
+    },
+    props: {
+      // 上级
+      parentData: {
+        type: Object,
+        default: () => {}
+      },
+      // 文件夹数据
+      folderList: {
+        type: Array,
+        default: () => []
+      },
+      lcyStatus: {
+        default: 1
+      },
+      fileType: '', //0:公共文档 1:个人文档 2:文档模板
+
+      isPop: '',
+      disabledTableList: {
+        //已选择列表
+        default: () => []
+      }
+    },
+    //add:新建 fileEdit:修改  filePigeonhole:归档 fileUnPigeonhole:取消归档  fileIssue:发布 fileChange:变更 fileDel:删除
+
+    data() {
+      return {
+        isPower,
+        isCheckOut,
+        isCreateUserId,
+        powerOpenShow: false,
+        selection: [],
+        processSubmitDialogFlag: false,
+        current: {},
+        fileUrl: '',
+        activeName: '常规',
+        // 表格列配置
+        columns: [
+          {
+            width: 45,
+            type: 'selection',
+            columnKey: 'selection',
+            align: 'center',
+            selectable: (row, index) => {
+              return (
+                !this.disabledTableList
+                  .map((item) => item.id)
+                  .includes(row.id) &&
+                row.reviewStatus != 1 &&
+                row.status != 1
+              );
+            }
+          },
+          {
+            label: '文档位置',
+            prop: 'typeName',
+            width: 180,
+            align: 'center',
+            fixed: 'left',
+            showOverflowTooltip: true,
+            formatter: () => {
+              // 优先使用fullPath,如果没有则回退到name
+              return this.parentData?.fullPath || this.parentData?.name || '';
+            }
+          },
+          {
+            label: '编码',
+            prop: 'code',
+            width: 180,
+            align: 'center',
+            fixed: 'left',
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'name',
+            label: '范文名称',
+            align: 'center',
+            slot: 'name',
+            showOverflowTooltip: true,
+            minWidth: 200
+          },
+          {
+            prop: 'createUserName',
+            label: '创建人',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 100
+          },
+          {
+            prop: 'createTime',
+            label: '创建时间',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 160
+          },
+          {
+            prop: 'status',
+            label: '状态',
+            align: 'center',
+            showOverflowTooltip: true,
+            minWidth: 100,
+            formatter: (_row, _column, cellValue) => {
+              return fileStatus(cellValue);
+            }
+          },
+          {
+            columnKey: 'action',
+            label: '操作',
+            width: 200,
+            align: 'center',
+            resizable: false,
+            slot: 'action',
+            showOverflowTooltip: true,
+            fixed: 'right'
+          }
+        ],
+        // 是否显示编辑弹窗
+        showEditFlag: false
+      };
+    },
+    computed: {
+      seekList() {
+        return [
+          {
+            prop: 'code:',
+            label: '范文名称',
+            type: 'input'
+          },
+          {
+            prop: 'name',
+            label: '创建人:',
+            type: 'input'
+          }
+        ];
+      }
+    },
+    created() {},
+
+    methods: {
+      /* 表格数据源 */
+      datasource({ page, limit, where, order }) {
+        if (this.lcyStatus) {
+          this.current = {};
+          return filePageAPI({
+            ...where,
+            ...order,
+            pageNum: page,
+            size: limit,
+            directoryId: this.parentData?.id,
+            lcyStatus: this.lcyStatus,
+            fileType: this.fileType,
+            isQueryAll: this.$hasPermission('fm:doc:viewAll') ? 1 : ''
+          });
+        }
+      },
+      /* 刷新表格 */
+      reload(where) {
+        this.$refs.table &&
+          this.$refs.table.reload({ pageNum: 1, where: where });
+      },
+
+      processSubmit(powerData) {
+        if (this.selection.length == 0 || this.selection.length > 1) {
+          this.$message.warning('请选择一条数据');
+          return;
+        }
+        if (this.selection[0].checkOutUserName) {
+          this.$message.warning(
+            this.selection[0].name +
+              '已被' +
+              this.selection[0].checkOutUserName +
+              '检出 无法废止'
+          );
+          return;
+        }
+        if (this.powerFn(powerData)) {
+          return;
+        }
+        if (isCheckOut(this.selection[0])) {
+          this.$message.warning(
+            this.selection[0].name +
+              '已被' +
+              this.selection[0].checkOutUserName +
+              '检出 无法发起流程'
+          );
+          return;
+        }
+        this.processSubmitDialogFlag = true;
+        this.$nextTick(() => {
+          this.selection[0]['businessKey'] = 'fm_file_repeal_approve';
+          this.$refs.processSubmitDialogRef.init(this.selection[0]);
+        });
+      },
+      //发布模板
+      processSubmit_template() {
+        if (this.selection.length == 0 || this.selection.length > 1) {
+          this.$message.warning('请选择一条数据');
+          return;
+        }
+        if (this.selection[0].checkOutUserName) {
+          this.$message.warning(
+            this.selection[0].name +
+              '已被' +
+              this.selection[0].checkOutUserName +
+              '检出 无法发布'
+          );
+          return;
+        }
+        if (this.selection[0].status == 2) {
+          this.$message.warning('模板已发布');
+          return;
+        }
+        this.processSubmitDialogFlag = true;
+        this.$nextTick(() => {
+          this.selection[0]['businessKey'] = 'fm_file_template_approve';
+          this.$refs.processSubmitDialogRef.init(this.selection[0]);
+        });
+      },
+      selectionClick(data) {
+        this.current = data.reverse()[0] || {};
+        this.rowClick(this.current);
+        this.$refs.table.setCurrentRow(this.current);
+      },
+      rowClick(row) {
+        this.$nextTick(() => {
+          this.$refs.browseRef && this.$refs.browseRef.setFileUrl(row);
+          this.$refs.PowerRef &&
+            this.$refs.PowerRef.setTableList(row.userAuthority);
+        });
+      },
+      /* 显示编辑 */
+      openEdit(type, row = '', powerData) {
+        // if (type != 'add') {
+        //   if (!row.checkOutUserName) {
+        //     this.$message.warning('请先检出在修改');
+        //     return;
+        //   }
+        //   if (isCheckOut(this.current)) {
+        //     this.$message.warning(
+        //       this.current.name +
+        //         '已被' +
+        //         this.current.checkOutUserName +
+        //         '检出 无法修改'
+        //     );
+        //     return;
+        //   }
+        // }
+        // if (this.powerFn(powerData, row)) {
+        //   return;
+        // }
+
+        // this.$refs.fileAddRef.open(type, row, this.folderList);
+        const query = {};
+        if (row?.id) {
+          query.id = row.id;
+        }
+        this.$router.push({
+          path: '/documents/documentTemplate/file-add',
+          // query
+        });
+      },
+      /* 显示编辑 */
+      openEditAll(powerData) {
+        if (this.powerFn(powerData)) {
+          return;
+        }
+        this.$refs.fileEditAllRef.open(this.folderList);
+      },
+      tabClick(data) {
+        if (this.$refs[data.name] && this.$refs[data.name].init) {
+          this.$refs[data.name].init();
+        }
+      },
+      parenOpen(type, powerData) {
+        // if (this.powerFn(powerData)) {
+        //   return;
+        // }
+        this.$emit('parenOpen', type);
+      },
+      // async success(current) {
+      //   await this.reload();
+      //   this.current = current;
+      //   this.$nextTick(() => {
+      //     this.$refs.PowerRef &&
+      //       this.$refs.PowerRef.setTableList(this.current.userAuthority);
+      //   });
+      // },
+      //权限判断
+      powerFn({ power, dataKey, isArr }, row) {
+        let arr = isArr ? this.selection : [];
+        if (!isPower(row || this[dataKey], power, arr)) {
+          this.$message.warning('抱歉,您没有操作权限!');
+          return true;
+        }
+      },
+      powerOpen() {
+        if (!this.selection?.length) {
+          this.$message.warning('请选择一条数据!');
+          return;
+        }
+
+        let createUserS=[],checkOutS=[]
+        this.selection.forEach(item=>{
+          if(!isCreateUserId(item)){
+            createUserS.push(item.name)
+          }
+          if(isCreateUserId(item)){
+            checkOutS.push(item.name)
+          }
+        })
+        if(createUserS.toString()){
+          this.$message.warning(createUserS+'您不是创建人,无权限修改!');
+          return;
+        }
+        if(!checkOutS.toString()){
+          this.$message.warning(checkOutS+'已被检出 无法修改!');
+          return;
+        }
+        this.powerOpenShow = true;
+        this.$nextTick(()=>{
+          this.$refs.PowerRefAll.setTableList([])
+        })
+                
+      },
+      //权限保存
+      powerSave(tableList) {
+        if (this.powerOpenShow) {
+          let data = this.selection.map((item) => {
+            return {
+              id: item.id,
+              userAuthority: tableList,
+              authority: 1
+            };
+          });
+          fileUpdateAllAPI(data).then((msg) => {
+            this.reload();
+          });
+          this.powerOpenShow = false;
+        } else {
+          fileUpdateAPI({
+            id: this.current.id,
+            userAuthority: tableList,
+            authority: 1
+          }).then((msg) => {
+            this.reload();
+          });
+        }
+      },
+      //检出
+      checkOut(powerData) {
+        if (this.selection.length == 0) {
+          this.$message.warning('请选择一条数据');
+          return;
+        }
+        if (this.powerFn(powerData)) {
+          return;
+        }
+        checkOut({
+          id: this.selection[0].id,
+          checkOutStatus: 1
+        }).then((msg) => {
+          this.reload();
+        });
+      },
+      //检入
+      checkEnter(powerData) {
+        if (this.selection.length == 0) {
+          this.$message.warning('请选择一条数据');
+          return;
+        }
+        if (this.powerFn(powerData)) {
+          return;
+        }
+        checkEnter({
+          id: this.selection[0].id,
+          checkOutStatus: 0
+        }).then((msg) => {
+          this.reload();
+        });
+      },
+      done() {
+        this.$refs.table.reRenderTable();
+        this.selection = [];
+      },
+      //下载
+      getFile(powerData) {
+        if (this.selection.length == 0) {
+          this.$message.warning('请选择一条数据');
+          return;
+        }
+        if (this.powerFn(powerData)) {
+          return;
+        }
+
+        this.selection.forEach((item) => {
+          getFile(
+            { objectName: item.storagePath[0].storePath },
+            item.storagePath[0].name
+          );
+        });
+      },
+      updateLcyStatus(powerData) {
+        if (this.selection.length == 0 || this.selection.length.length > 1) {
+          this.$message.warning('请选择一条数据');
+          return;
+        }
+        if (this.selection[0].checkOutUserName) {
+          this.$message.warning(
+            this.selection[0].name +
+              '已被' +
+              this.selection[0].checkOutUserName +
+              '检出 无法归档'
+          );
+          return;
+        }
+        if (this.powerFn(powerData)) {
+          return;
+        }
+        updateLcyStatus({ id: this.selection[0].id }).then((res) => {
+          this.reload();
+        });
+      },
+      noUpdateLcyStatus(powerData) {
+        if (this.selection.length == 0 || this.selection.length.length > 1) {
+          this.$message.warning('请选择一条数据');
+          return;
+        }
+        if (this.powerFn(powerData)) {
+          return;
+        }
+        noUpdateLcyStatus({ id: this.selection[0].id }).then((res) => {
+          this.reload();
+        });
+      },
+      // selectionChange( selection){
+      //   console.log( selection,' selection')
+      //   let data=selection[selection.length-1]
+      //   this.current=data||this.current
+      //   this.rowClick(this.current)
+      // },
+      /* 删除 */
+      remove(row, powerData) {
+        if (this.powerFn(powerData, row)) {
+          return;
+        }
+        if (!row.checkOutUserName) {
+          this.$message.warning('请先检出在删除');
+          return;
+        }
+
+        if (isCheckOut(this.current)) {
+          this.$message.warning(
+            this.current.name +
+              '已被' +
+              this.current.checkOutUserName +
+              '检出 无法删除'
+          );
+          return;
+        }
+        const loading = this.$loading({ lock: true });
+        fileDeleteAPI([row.id])
+          .then((msg) => {
+            loading.close();
+            this.$message.success('操作成功');
+            this.reload();
+          })
+          .catch((e) => {
+            loading.close();
+            // this.$message.error(e.message);
+          });
+      },
+      //发布
+      openSendEdit(powerData) {
+        if (this.selection.length == 0) {
+          this.$message.warning('请选择一条数据');
+          return;
+        }
+        if (this.selection[0].checkOutUserName) {
+          this.$message.warning(
+            this.selection[0].name +
+              '已被' +
+              this.selection[0].checkOutUserName +
+              '检出 无法发布'
+          );
+          return;
+        }
+        if (this.powerFn(powerData)) {
+          return;
+        }
+        this.$refs.sendEditRef.open('add', '', this.selection, this.fileType);
+      },
+      //移动
+      move() {
+        if (this.selection.length == 0) {
+          this.$message.warning('请选择一条数据');
+          return;
+        }
+        if (this.selection[0].checkOutUserName) {
+          this.$message.warning(
+            this.selection[0].name +
+              '已被' +
+              this.selection[0].checkOutUserName +
+              '检出 无法移动'
+          );
+          return;
+        }
+        this.$refs.moveRef.open(this.selection[0]);
+      },
+      getTableList() {
+        return JSON.parse(JSON.stringify(this.selection));
+      }
+    }
+  };
+</script>
+<style scoped lang="scss">
+  :deep(.el-tabs__content) {
+    height: calc(100% - 39px);
+    overflow: auto;
+  }
+  :deep(.ele-table-tool-title-content) {
+    display: contents;
+  }
+</style>

+ 178 - 0
src/views/bpm/documents/documentTemplate/components/folder-edit.vue

@@ -0,0 +1,178 @@
+<!-- 机构编辑弹窗 -->
+<template>
+  <ele-modal
+    width="420px"
+    :visible="showFolderEditFlag"
+    :close-on-click-modal="false"
+    custom-class="ele-dialog-form"
+    :title="type == 'edit' ? '修改' : '添加'"
+    append-to-body
+    @close="cancel"
+  >
+    <el-form ref="form" :model="form" :rules="rules" label-width="110px">
+      <el-row :gutter="15">
+        <el-col :span="24">
+          <el-form-item label="文件夹名称:" prop="name">
+            <el-input
+              clearable
+              :maxlength="20"
+              v-model="form.name"
+              placeholder="文件夹名称"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="24">
+          <el-form-item label="详细描述:" prop="remark">
+            <el-input
+              type="textarea"
+              clearable
+              :maxlength="20"
+              v-model="form.remark"
+              placeholder="详细描述"
+            />
+          </el-form-item>
+        </el-col>
+        <el-col :span="24">
+          <el-form-item label="位置:" prop="parentId">
+            <el-cascader
+              style="width: 100%"
+              v-model="form.parentId"
+              :options="folderList"
+              :disabled="this.type == 'edit'"
+              :props="{
+                value: 'id',
+                label: 'name',
+                children: 'sonDirectoryList',
+                emitPath: false,
+                checkStrictly: true,
+                disabled: 'disabled'
+              }"
+            ></el-cascader>
+          </el-form-item>
+        </el-col>
+        <!-- <el-col :span="24">
+          <el-form-item label="密级:" prop="secretLevel">
+            <el-select v-model="form.secretLevel" style="width: 100%">
+              <el-option
+                v-for="item in secretLevelList"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              ></el-option>
+            </el-select>
+          </el-form-item>
+        </el-col> -->
+      </el-row>
+    </el-form>
+    <template v-slot:footer>
+      <el-button type="primary" :loading="loading" @click="save">
+        确认
+      </el-button>
+      <el-button @click="cancel()">取消</el-button>
+    </template>
+  </ele-modal>
+</template>
+
+<script>
+// import { directorySaveAPI, directoryUpdateAPi } from '@/api/doc-manage';
+import { setFolderList } from '../util.js';
+import { secretLevelList } from '@/enum/dict';
+
+export default {
+  components: {},
+
+  data() {
+    const defaultForm = {
+      name: '',
+      type: '',
+      parentId: '',
+      remark: '',
+      secretLevel: 1
+    };
+    return {
+      defaultForm,
+      responsibleName: '',
+      showFolderEditFlag: false,
+      type: '',
+      // 表单数据
+      form: { ...defaultForm },
+      // 表单验证规则
+      rules: {
+        name: [{ required: true, message: '请输入', trigger: 'blur' }],
+        parentId: [{ required: true, message: '请选择', trigger: 'blur' }]
+      },
+      folderList: [],
+      // 提交状态
+      loading: false,
+      secretLevelList
+    };
+  },
+  computed: {
+    // 是否开启响应式布局
+    styleResponsive() {
+      return this.$store.state.theme.styleResponsive;
+    }
+  },
+  props: {
+    fileType: ''
+  },
+  methods: {
+    open(type, value, folderList) {
+      this.type = type;
+      this.showFolderEditFlag = true;
+      if (type == 'edit') {
+        this.form = value;
+      } else {
+        this.form.parentId = value.id;
+      }
+      this.folderList = JSON.parse(JSON.stringify(folderList));
+      setFolderList(this.folderList); //权限过滤
+    },
+
+    cancel() {
+      this.form = { ...this.defaultForm };
+      this.$refs.form.clearValidate();
+      this.showFolderEditFlag = false;
+    },
+    /* 保存编辑 */
+    async save() {
+      if (!(await this.formValidate())) return false;
+
+      let form = {
+        ...this.form
+      };
+      this.loading = true;
+      const data = {
+        ...form,
+        parentId: this.form.parentId || 0
+      };
+      if (this.type != 'edit') {
+        delete data.id;
+        data.type = this.fileType;
+      }
+      const saveOrUpdate =
+        this.type == 'edit' ? directoryUpdateAPi : directorySaveAPI;
+      // console.log(this.type)
+      // return
+      saveOrUpdate(data)
+        .then((msg) => {
+          this.loading = false;
+          // this.$message.success('新建成功');
+          this.cancel();
+          this.$emit('done', data);
+        })
+        .catch((e) => {
+          this.loading = false;
+          // this.$message.error(e.message);
+        });
+    },
+    formValidate() {
+      return new Promise((resolve, reject) => {
+        this.$refs.form.validate((valid) => {
+          resolve(valid);
+        });
+      });
+    }
+  }
+};
+</script>

+ 360 - 0
src/views/bpm/documents/documentTemplate/components/mainBodyTemplate.vue

@@ -0,0 +1,360 @@
+<template>
+  <div class="main-body-template">
+    <h2 class="title">发文通知稿纸</h2>
+    
+    <el-form :model="form" :rules="rules" ref="form">
+      <table class="table-container" border="1" cellpadding="10" cellspacing="0">
+        <!-- 第一行 -->
+        <tr>
+          <td>发文名称</td>
+          <td colspan="1">
+            <el-form-item prop="documentName" style="margin: 0;">
+              <el-input v-model="form.documentName" placeholder="请输入"></el-input>
+            </el-form-item>
+          </td>
+          <td>发文字号</td>
+          <td colspan="1">
+            <el-form-item prop="documentNumber" style="margin: 0;">
+              <el-input v-model="form.documentNumber" placeholder="请输入"></el-input>
+            </el-form-item>
+          </td>
+        </tr>
+        <tr>
+          <td>申请编码</td>
+          <td colspan="3">
+            <el-input v-model="form.applicationCode" disabled style="width: 100%;"></el-input>
+          </td>
+        </tr>
+        
+        <!-- 第二行 -->
+        <tr>
+          <td>发文机关</td>
+          <td colspan="3">
+            <el-form-item prop="issuingAuthority" style="margin: 0;">
+              <el-select v-model="form.issuingAuthority" placeholder="请选择" style="width: 200px;">
+                <el-option label="办公室" value="办公室"></el-option>
+                <!-- 其他选项 -->
+              </el-select>
+              <el-checkbox v-model="form.jointIssuance" style="margin-left: 10px;">联合发文</el-checkbox>
+            </el-form-item>
+          </td>
+        </tr>
+        <tr>
+          <td>拟稿人</td>
+          <td colspan="3">
+            <el-form-item prop="draftPerson" style="margin: 0;">
+              <el-input v-model="form.draftPerson" placeholder="请输入" style="width: 100%;">
+                <template slot="append">
+                  <el-button type="text" icon="el-icon-user"></el-button>
+                </template>
+              </el-input>
+            </el-form-item>
+          </td>
+        </tr>
+        
+        <!-- 第三行 -->
+        <tr>
+          <td>主送</td>
+          <td colspan="3">
+            <el-form-item prop="mainRecipient" style="margin: 0;">
+              <el-select v-model="form.mainRecipient" placeholder="请选择" multiple style="width: 100%;">
+                <!-- 选项 -->
+              </el-select>
+            </el-form-item>
+          </td>
+        </tr>
+        <tr>
+          <td>抄送</td>
+          <td colspan="3">
+            <el-form-item prop="ccRecipient" style="margin: 0;">
+              <el-select v-model="form.ccRecipient" placeholder="请选择" multiple style="width: 100%;">
+                <!-- 选项 -->
+              </el-select>
+            </el-form-item>
+          </td>
+        </tr>
+        
+        <!-- 第四行 -->
+        <tr>
+          <td>发文单位意见</td>
+          <td colspan="3">
+            <el-form-item prop="unitOpinion" style="margin: 0;">
+              <el-input v-model="form.unitOpinion" placeholder="请输入" style="width: 100%;"></el-input>
+            </el-form-item>
+          </td>
+        </tr>
+        <tr>
+          <td>核稿</td>
+          <td colspan="3">
+            <el-form-item prop="reviewer" style="margin: 0;">
+              <el-input v-model="form.reviewer" placeholder="请输入" style="width: 100%;"></el-input>
+            </el-form-item>
+          </td>
+        </tr>
+        
+        <!-- 第五行 -->
+        <tr>
+          <td>会办单位意见</td>
+          <td colspan="3">
+            <el-form-item prop="coUnitOpinion" style="margin: 0;">
+              <el-input v-model="form.coUnitOpinion" placeholder="请输入" style="width: 100%;"></el-input>
+            </el-form-item>
+          </td>
+        </tr>
+        
+        <!-- 第六行 -->
+        <tr>
+          <td>主题词</td>
+          <td colspan="3">
+            <el-form-item prop="keywords" style="margin: 0;">
+              <el-input v-model="form.keywords" placeholder="请输入,按回车键多个主题词,用分号隔开" style="width: 100%;"></el-input>
+            </el-form-item>
+          </td>
+        </tr>
+        
+        <!-- 第七行 -->
+        <tr>
+          <td>领导批示</td>
+          <td colspan="3">
+            <el-form-item prop="leaderInstruction" style="margin: 0;">
+              <el-input v-model="form.leaderInstruction" placeholder="请输入" style="width: 100%;"></el-input>
+            </el-form-item>
+          </td>
+        </tr>
+        
+        <!-- 第八行 -->
+        <tr>
+          <td>秘密等级</td>
+          <td>
+            <el-form-item prop="secretLevel" style="margin: 0;">
+              <el-select v-model="form.secretLevel" placeholder="请选择" style="width: 100%;">
+                <el-option label="公开" value="公开"></el-option>
+                <el-option label="内部" value="内部"></el-option>
+                <el-option label="秘密" value="秘密"></el-option>
+                <el-option label="机密" value="机密"></el-option>
+                <el-option label="绝密" value="绝密"></el-option>
+              </el-select>
+            </el-form-item>
+          </td>
+          <td>紧急程度</td>
+          <td>
+            <el-form-item prop="urgencyLevel" style="margin: 0;">
+              <el-select v-model="form.urgencyLevel" placeholder="请选择" style="width: 100%;">
+                <el-option label="普通" value="普通"></el-option>
+                <el-option label="加急" value="加急"></el-option>
+                <el-option label="特急" value="特急"></el-option>
+              </el-select>
+            </el-form-item>
+          </td>
+        </tr>
+        
+        <!-- 第九行 -->
+        <tr>
+          <td>保密期限</td>
+          <td>
+            <el-form-item prop="secretPeriod" style="margin: 0;">
+              <el-input v-model="form.secretPeriod" placeholder="请输入" style="width: 120px;"></el-input>
+              <el-select v-model="form.secretPeriodUnit" style="width: 80px;">
+                <el-option label="年" value="年"></el-option>
+                <el-option label="月" value="月"></el-option>
+                <el-option label="日" value="日"></el-option>
+              </el-select>
+            </el-form-item>
+          </td>
+          <td>打印份数</td>
+          <td>
+            <el-form-item prop="printCopies" style="margin: 0;">
+              <el-input v-model="form.printCopies" placeholder="请输入" type="number" style="width: 100%;"></el-input>
+            </el-form-item>
+          </td>
+        </tr>
+        
+        <!-- 第十行 -->
+        <tr>
+          <td>印发机关</td>
+          <td>
+            <el-form-item prop="printingAuthority" style="margin: 0;">
+              <el-select v-model="form.printingAuthority" placeholder="请选择" style="width: 100%;">
+                <el-option label="办公室" value="办公室"></el-option>
+                <!-- 其他选项 -->
+              </el-select>
+            </el-form-item>
+          </td>
+          <td>印发日期</td>
+          <td>
+            <el-form-item prop="printDate" style="margin: 0;">
+              <el-date-picker v-model="form.printDate" type="date" placeholder="选择日期" style="width: 100%;"></el-date-picker>
+            </el-form-item>
+          </td>
+        </tr>
+        
+        <!-- 第十一行 -->
+        <tr>
+          <td>说明</td>
+          <td>
+            <el-form-item prop="description" style="margin: 0;">
+              <el-input v-model="form.description" placeholder="请输入" style="width: 100%;"></el-input>
+            </el-form-item>
+          </td>
+          <td>是否纳入督办</td>
+          <td>
+            <el-form-item prop="includeSupervision" style="margin: 0;">
+              <el-select v-model="form.includeSupervision" placeholder="请选择" style="width: 100%;">
+                <el-option label="是" value="是"></el-option>
+                <el-option label="否" value="否"></el-option>
+              </el-select>
+            </el-form-item>
+          </td>
+        </tr>
+        
+        <!-- 第十二行 -->
+        <tr>
+          <td>附件</td>
+          <td colspan="3">
+            <el-form-item prop="attachments" style="margin: 0;">
+              <el-upload
+                class="upload-demo"
+                action="#"
+                :on-preview="handlePreview"
+                :on-remove="handleRemove"
+                :file-list="fileList"
+                :auto-upload="false"
+              >
+                <el-button size="small" type="primary">上传文件,请点击上传</el-button>
+                <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
+              </el-upload>
+            </el-form-item>
+          </td>
+        </tr>
+      </table>
+      
+      <div class="text-center" style="margin-top: 30px;">
+        <el-button type="primary" @click="submitForm">提交</el-button>
+        <el-button @click="resetForm">重置</el-button>
+      </div>
+    </el-form>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'MainBodyTemplate',
+  data() {
+    return {
+      tableData: [{}], // 用于el-table的数据
+      form: {
+        documentName: '',
+        documentNumber: '',
+        applicationCode: 'PZ-00002-文本-202639',
+        issuingAuthority: '',
+        jointIssuance: false,
+        draftPerson: '潘小帅(部门总监)',
+        mainRecipient: [],
+        ccRecipient: [],
+        unitOpinion: '',
+        reviewer: '',
+        coUnitOpinion: '',
+        keywords: '',
+        leaderInstruction: '',
+        secretLevel: '',
+        urgencyLevel: '',
+        secretPeriod: '',
+        secretPeriodUnit: '年',
+        printCopies: '',
+        printingAuthority: '',
+        printDate: '',
+        description: '',
+        includeSupervision: '是',
+        attachments: []
+      },
+      fileList: [],
+      rules: {
+        documentName: [
+          { required: true, message: '请输入发文名称', trigger: 'blur' }
+        ],
+        documentNumber: [
+          { required: true, message: '请输入发文字号', trigger: 'blur' }
+        ],
+        issuingAuthority: [
+          { required: true, message: '请选择发文机关', trigger: 'change' }
+        ],
+        secretLevel: [
+          { required: true, message: '请选择秘密等级', trigger: 'change' }
+        ],
+        urgencyLevel: [
+          { required: true, message: '请选择紧急程度', trigger: 'change' }
+        ],
+        printingAuthority: [
+          { required: true, message: '请选择印发机关', trigger: 'change' }
+        ]
+      }
+    };
+  },
+  methods: {
+    handleRemove(file, fileList) {
+      console.log(file, fileList);
+    },
+    handlePreview(file) {
+      console.log(file);
+    },
+    submitForm() {
+      this.$refs.form.validate((valid) => {
+        if (valid) {
+          alert('提交成功');
+        } else {
+          console.log('验证失败');
+          return false;
+        }
+      });
+    },
+    resetForm() {
+      this.$refs.form.resetFields();
+    }
+  }
+};
+</script>
+
+<style scoped>
+.main-body-template {
+  padding: 20px;
+  background-color: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+}
+
+.title {
+  text-align: center;
+  color: #ff0000;
+  margin-bottom: 30px;
+  font-size: 20px;
+  font-weight: bold;
+}
+
+.el-form {
+  border: 1px solid #ff0000;
+  padding: 20px;
+  border-radius: 4px;
+}
+
+.table-container {
+  width: 100%;
+  margin-bottom: 20px;
+  border: 1px solid #ff0000;
+  
+  td {
+    border: 1px solid #ff0000;
+    padding: 10px;
+    vertical-align: top;
+  }
+  
+  td:first-child {
+    font-weight: bold;
+    width: 150px;
+  }
+}
+
+.text-center {
+  text-align: center;
+  margin-top: 30px;
+}
+</style>

+ 473 - 0
src/views/bpm/documents/documentTemplate/index.vue

@@ -0,0 +1,473 @@
+<template>
+  <div class="ele-body">
+    <el-card shadow="never" v-loading="loading">
+      <ele-split-layout
+        width="210px"
+        allow-collapse
+        :right-style="{ overflow: 'hidden' }"
+      >
+        <div>
+          <!-- 操作按钮 -->
+          <ele-toolbar class="ele-toolbar-actions">
+            <div style="margin: 5px 0">
+              <!-- <el-button
+                size="small"
+                type="primary"
+                icon="el-icon-plus"
+                class="ele-btn-icon"
+                @click="openEdit()"
+              >
+                添加
+              </el-button>
+              <el-button
+                size="small"
+                type="warning"
+                icon="el-icon-edit"
+                class="ele-btn-icon"
+                :disabled="!current"
+                @click="openEdit(current)"
+              >
+                修改
+              </el-button>
+              <el-button
+                size="small"
+                type="danger"
+                icon="el-icon-delete"
+                class="ele-btn-icon"
+                :disabled="!current"
+                @click="remove"
+              >
+                删除
+              </el-button> -->
+            </div>
+          </ele-toolbar>
+
+          <div class="ele-border-lighter sys-organization-list">
+            <el-tree
+              ref="tree"
+              :data="data"
+              highlight-current
+              :draggable="true"
+              node-key="id"
+              :props="{ label: 'name', children: 'sonDirectoryList' }"
+              :expand-on-click-node="false"
+              :default-expand-all="true"
+              @node-click="onNodeClick"
+              @node-drop="nodeDrop"
+              :allow-drop="allowDrop"
+            >
+              <span
+                class="custom-tree-node"
+                slot-scope="{ node, data }"
+                @contextmenu.prevent="onRightClick(data,$event)"
+                @click.prevent="clicka"
+                ref="trueNodeRef" 
+              >
+                <el-popover
+                  style="position: fixed; z-index: 2000"
+                  width="130"
+                  ref="popoverRef"
+                  v-model="visible"
+                  @click.native="visible = false"
+                  
+                  v-if="data.id == rightData.id && fileType === 0 && !isPop"
+                >
+                  <div>
+                    <el-link
+                      v-if="lcyStatus == 1 && isPower(current)"
+                      :underline="false"
+                      @click.native="setPower(data)"
+                      >更改权限
+                    </el-link></div
+                  >
+                  <div>
+                    <el-link
+                      v-if="lcyStatus != 1"
+                      :underline="false"
+                      @click.native="goTo('文档工作区', data)"
+                      >转到文档工作区
+                    </el-link></div
+                  >
+                  <div>
+                    <el-link
+                      v-if="lcyStatus != '2'"
+                      :underline="false"
+                      @click.native="goTo('文档归档区', data)"
+                      >转到文档归档区
+                    </el-link></div
+                  >
+                  <div>
+                    <el-link
+                      v-if="lcyStatus != '3'"
+                      :underline="false"
+                      @click.native="goTo('文档发布区', data)"
+                      >转到文档发布区
+                    </el-link></div
+                  >
+                </el-popover>
+
+                <ElementTreeLine
+                  :node="node"
+                  :showLabelLine="true"
+                  :indent="20"
+                >
+                  <img src="~@/assets/wjj.png" />
+
+                  <span>{{ node.label }}</span>
+                </ElementTreeLine>
+              </span>
+            </el-tree>
+          </div>
+        </div>
+        <template v-slot:content>
+          <FileTableList
+            ref="tableRef"
+            :parentData="current"
+            :folderList="data"
+            @parenOpen="openEdit"
+            :fileType="fileType"
+            :lcyStatus="lcyStatus"
+            :isPop="isPop"
+            :disabledTableList="disabledTableList"
+          />
+        </template>
+      </ele-split-layout>
+    </el-card>
+    <!-- 编辑弹窗 -->
+    <folder-edit @done="query" ref="editRef" :fileType="fileType" />
+    <!-- 文件夹权限 -->
+
+    <ele-modal
+      width="50vw"
+      :visible="powerVisible"
+      @close="powerVisible = false"
+      :close-on-click-modal="false"
+      append-to-body
+    >
+      <!-- <Power @powerSave="powerSave" ref="PowerRef" :powerArr="powerArr" /> -->
+    </ele-modal>
+    <!-- {{current?.id}} -->
+  </div>
+</template>
+
+<script>
+//
+import FileTableList from './components/file-table-list.vue';
+import folderEdit from './components/folder-edit.vue';
+// import {
+//   directoryDeleteAPI,
+//   getDocTreeListAPI,
+//   directoryUpdateAPi,
+//   validationPersonal,
+//   moveDirectory
+// } from '@/api/doc-manage';
+import { mapGetters } from 'vuex';
+// import Power from './power/index.vue';
+import { isPower } from './util.js';
+
+import ElementTreeLine from 'element-tree-line';
+// css
+import 'element-tree-line/dist/style.scss';
+export default {
+  components: { 
+    FileTableList, 
+    folderEdit, 
+    ElementTreeLine 
+  },
+  props: {
+    fileType: '', //0:公共文档 1:个人文档 2:文档模板
+    lcyStatus: '', //1:文档工作区 2:文档归档区 3:文档发布区 4:文档废止区
+    isPop: {
+      //是否弹出
+      default: false
+    },
+    disabledTableList: {
+      //已选择列表
+      default: () => []
+    }
+  },
+  data() {
+    return {
+    //   isPower,
+      powerArr: [
+        { name: 'add', label: '新建' },
+        { name: 'revise', label: '修改' },
+        { name: 'del', label: '删除' }
+      ],
+      visible: false,
+      powerVisible: false,
+      rightData: {},
+      // 加载状态
+      loading: false,
+      // 列表数据
+      data: [],
+      institutionList: [],
+      // 选中数据
+      current: {},
+      // 是否显示表单弹窗
+      showFolderEditFlag: false,
+      // 编辑回显数据
+      editData: null,
+      // 上级id
+      parentId: null
+    };
+  },
+  computed: {
+    ...mapGetters(['user'])
+  },
+  created() {
+    // this.query();
+  },
+  mounted() {
+    document.addEventListener('click', this.clicka);
+  },
+  destroyed() {
+    document.removeEventListener('click', this.clicka);
+  },
+
+  methods: {
+    /* 查询 */
+    async query(row) {
+      this.loading = true;
+      let query = {
+        type: this.fileType,
+        currentUserId: this.user.info.userId
+      };
+      this.data = await getDocTreeListAPI(query);
+      if (this.fileType == 1 && this.data.length == 0) {
+        await validationPersonal();
+        await this.query();
+      }
+   
+      this.$nextTick(() => {
+        if (this.$route.params.row) {
+          this.$refs.tree.setCurrentKey(this.$route.params.row.id);
+          this.onNodeClick(this.$route.params.row);
+        }else if (row&&row.id) {
+          this.$refs.tree.setCurrentKey(row.id);
+          this.onNodeClick(row);
+        }else {
+          this.$refs.tree.setCurrentKey(this.data[0].id);
+
+          this.onNodeClick(this.data[0]);
+        }
+      });
+      this.loading = false;
+    },
+    /* 选择数据 */
+    onNodeClick(row, node, list) {
+      console.log('row',row, node, list)
+      if (row) {
+        // 构建完整路径
+        const fullPath = this.buildFullPath(row, this.data);
+        // 将完整路径添加到current对象中
+        this.current = {
+          ...row,
+          fullPath: fullPath
+        };
+        this.$nextTick(() => {
+          this.$refs.tableRef.reload();
+        });
+      } else {
+        this.current = null;
+      }
+    },
+    
+    /* 构建完整路径 */
+    buildFullPath(currentNode, folderList) {
+      // 如果节点没有parentId,直接返回节点名称
+      if (!currentNode.parentId || currentNode.parentId === 0) {
+        return currentNode.name;
+      }
+      
+      // 递归查找上级节点
+      function findParent(node, list) {
+        let path = [node.name];
+        let parentId = node.parentId;
+        
+        // 递归查找所有父节点
+        function searchParent(id) {
+          for (const item of list) {
+            if (item.id === id) {
+              path.unshift(item.name); // 将父节点名称添加到路径开头
+              if (item.parentId && item.parentId !== 0) {
+                searchParent(item.parentId); // 继续查找上一级
+              }
+              return;
+            }
+            // 如果当前节点有子节点,继续在子节点中查找
+            if (item.sonDirectoryList && item.sonDirectoryList.length > 0) {
+              searchParentInChildren(item.sonDirectoryList, id);
+            }
+          }
+        }
+        
+        // 在子节点列表中查找父节点
+        function searchParentInChildren(children, id) {
+          for (const child of children) {
+            if (child.id === id) {
+              path.unshift(child.name);
+              if (child.parentId && child.parentId !== 0) {
+                searchParent(child.parentId);
+              }
+              return;
+            }
+            if (child.sonDirectoryList && child.sonDirectoryList.length > 0) {
+              searchParentInChildren(child.sonDirectoryList, id);
+            }
+          }
+        }
+        
+        if (parentId) {
+          searchParent(parentId);
+        }
+        
+        return path.join(' / ');
+      }
+      
+      return findParent(currentNode, folderList);
+    },
+    allowDrop(draggingNode, dropNode, type) {
+      //拖拽限制
+      return dropNode.parent.id == draggingNode.parent.id && type != 'inner';
+    },
+    clicka() {
+      this.visible = false;
+    },
+
+    onRightClick(data,PointerEvent) {
+      this.rightData = data;
+      this.visible = true;
+      this.$nextTick(() => {
+        let y = PointerEvent.pageY;
+        let x = PointerEvent.pageX+10;
+        if (PointerEvent.screenY >= PointerEvent.view.innerHeight) {
+          y -= 80;
+        }
+        this.$refs.popoverRef.$el.style.top = y+'px'
+        this.$refs.popoverRef.$el.style.left = x+'px'
+      });
+    },
+    setPower(data) {
+      this.powerVisible = true;
+      this.$nextTick(() => {
+        this.$refs.PowerRef &&
+          this.$refs.PowerRef.setTableList(data.userAuthority || []);
+      });
+    },
+    //权限保存
+    powerSave(tableList) {
+      directoryUpdateAPi({
+        id: this.current.id,
+        userAuthority: tableList,
+        authority: 1
+      }).then((msg) => {
+        this.powerVisible = false;
+        this.query();
+      });
+    },
+    goTo(name, row) {
+      this.$router.push({
+        name,
+        params: {
+          row
+        }
+      });
+    },
+    /* 显示编辑 */
+    openEdit(type) {
+      if (type == 'del') {
+        this.remove();
+        return;
+      }
+      this.$refs.editRef.open(
+        type,
+        JSON.parse(JSON.stringify(this.current)),
+        this.data
+      );
+    },
+    /* 删除 */
+    remove() {
+      this.$confirm('确定要删除选中文件夹吗?', '提示', {
+        type: 'warning'
+      })
+        .then(() => {
+          const loading = this.$loading({ lock: true });
+          directoryDeleteAPI([this.current.id])
+            .then((msg) => {
+              loading.close();
+              this.$message.success('操作成功');
+              this.query();
+            })
+            .catch((e) => {
+              loading.close();
+            });
+        })
+        .catch(() => {});
+    },
+    nodeDrop(to, form) {
+      moveDirectory({
+        targetId: form.data.id,
+        replaceId: to.data.id
+      });
+    },
+    getTableList() {
+      return this.$refs.tableRef.getTableList();
+    }
+  }
+};
+</script>
+
+<style lang="scss" scoped>
+.sys-organization-list {
+  height: calc(100vh - 180px);
+  box-sizing: border-box;
+  border-width: 1px;
+  border-style: solid;
+  overflow: auto;
+}
+
+.sys-organization-list :deep(.el-tree-node__content) {
+  height: 25px;
+
+  & > .el-tree-node__expand-icon {
+    margin-left: 10px;
+  }
+}
+.custom-tree-node {
+  display: flex;
+  align-items: center;
+}
+:deep(.el-popover) {
+  min-width: 50px;
+  position: fixed;
+  background: #409EFF;
+  
+}
+:deep(.el-link--inner) {
+  padding: 3px 0;
+}
+:deep(.el-link.el-link--default) {
+  color:#fff
+}
+// :deep(.element-tree-node-line-hor) {
+//   border-bottom: 1px solid #dcdfe6;
+// }
+// :deep(.element-tree-node-line-ver) {
+//   border-left: 1px solid #dcdfe6;
+// }
+</style>
+<style lang="scss">
+.el-tree
+  > .el-tree-node
+  > .el-tree-node__content:nth-of-type(1)
+  .element-tree-node-line-hor {
+  border: none;
+}
+.el-tree
+  > .el-tree-node
+  > .el-tree-node__content:nth-of-type(1)
+  .element-tree-node-line-ver {
+  border: none;
+}
+</style>

+ 168 - 0
src/views/bpm/documents/documentTemplate/util.js

@@ -0,0 +1,168 @@
+import store from '@/store';
+import vue from 'vue';
+const userId = store.state.user.info.userId;
+const userName = store.state.user.info.name;
+
+export function isCreateUserId(row) {
+  if (vue.prototype.$hasPermission('fm:doc:viewAll')) {
+    return true;
+  }
+  return userId == row?.createUserId;
+}
+export function isPower(data = {}, power, selection = []) {
+  if (!data.id && selection.length == 0) {
+    return false;
+  }
+  if (
+    //文件查看浏览权限
+    vue.prototype.$hasPermission('fm:doc:viewAll')
+  ) {
+    return true;
+  }
+
+  if (power == 'add' && data.userAuthority.length == 0) {
+    return true;
+  }
+  if (power == 'checkEnter' && data?.checkOutUserId != userId) {
+    //检入特殊处理
+    return false;
+  }
+  if (selection.length > 0) {
+    //多选情况处理
+    let _isPower = true;
+    let userAuthorityS = [];
+    let createUserIdS = selection
+      .map((item) => item.createUserId)
+      .filter((createUserId) => createUserId == userId);
+    if (createUserIdS.length == selection.length || userName == 'admin') {
+      //创建人/admin所有权限
+      return true;
+    }
+
+    selection.forEach((val) => {
+      const powerObj = val.userAuthority.find((item) => item.id == userId);
+      if (powerObj) {
+        userAuthorityS.push(powerObj);
+      }
+    });
+
+    if (userAuthorityS.length == 0) {
+      _isPower = false;
+    }
+    userAuthorityS.forEach((item) => {
+      if (item[power] != '1') {
+        _isPower = false;
+      }
+    });
+    return _isPower;
+  }
+
+  if (data.createUserId == userId || userName == 'admin') {
+    //创建人/admin所有权限
+    return true;
+  }
+  if (!power) {
+    return false;
+  }
+  const powerObj = data.userAuthority?.find((item) => item.id == userId);
+  if (powerObj) {
+    return powerObj[power] == '1';
+  }
+}
+export function isCheckOut(data = {}) {
+  //检出判断
+  if (data?.checkOutStatus == 1 && userId != data.checkOutUserId) {
+    return true;
+  }
+}
+export function setFolderList(data) {
+  //递归过滤文件夹权限
+  data.forEach((item) => {
+    item['disabled'] = !isPower(item, 'add');
+    if (item.sonDirectoryList && item.sonDirectoryList.length > 0) {
+      setFolderList(item.sonDirectoryList);
+    }
+  });
+}
+export function setFileUrl(row) {
+  let file = row.storagePath[0];
+  let fileNames = file.storePath.split('/');
+  let url =
+    window.location.origin +
+    '/api/main/file/getFile?objectName=' +
+    file.storePath +
+    '&fullfilename=' +
+    fileNames[fileNames.length - 1];
+  return '/kkfile/onlinePreview?url=' + btoa(url);
+}
+
+export function getFileType() {
+  return [
+    'par',
+    'asm',
+    'psm',
+    'dft',
+    'sldprt',
+    'sldasm',
+    'ipt',
+    ' iam',
+    'prt',
+    '3dxml',
+    'CATPart',
+    'CATProduct',
+    'cgr',
+    'model',
+    'exp',
+    'session',
+    'x_t',
+    'xmt_txt',
+    'x_b',
+    'xmp_bin',
+    'xmp_txt',
+    'sat',
+    '.sab',
+    '.igs',
+    'iges',
+    'stp',
+    'step',
+    'jt',
+    'xcgm',
+    '3dm',
+    'stl',
+    'obj',
+    '3mf',
+    'fbx',
+    'vda',
+    'dxf',
+    'dwg',
+    'idf',
+    'idb',
+    'emn',
+    'brd'
+  ];
+}
+export function fileStatus(status) {
+  return status == 1
+    ? '发布中'
+    : status == 2
+    ? '已发布'
+    : status == 3
+    ? '已归档'
+    : status == 4
+    ? '已废止'
+    : '';
+  // if (fileType == 2) {
+  //     return status == 1 ? '已发布' : '未发布';
+  // }
+  // if (fileType === 0) {
+  //     if (lcyStatus == 2) {
+  //         return '已归档'
+  //     }
+  //     if (lcyStatus == 3) {
+  //         return '已发布'
+  //     }
+  //     if (lcyStatus == 4) {
+  //         return '已废止'
+  //     }
+  // }
+}

+ 865 - 0
src/views/bpm/documents/noticeIssuance/index.vue

@@ -0,0 +1,865 @@
+<template>
+  <div class="ele-body">
+    <el-card shadow="never" v-loading="loading">
+      <seek-page :seekList="seekList" @search="search"></seek-page>
+
+      <el-tabs v-model="tabValue" type="card" @tab-click="handleTabClick">
+        <el-tab-pane label="全部" name="1"></el-tab-pane>
+        <el-tab-pane label="草稿" name="5"></el-tab-pane>
+        <el-tab-pane label="审核中" name="4"></el-tab-pane>
+        <el-tab-pane label="退回" name="6"></el-tab-pane>
+        <el-tab-pane label="办结" name="7"></el-tab-pane>
+      </el-tabs>
+      <!-- 数据表格 -->
+      <ele-pro-table
+        ref="table"
+        :key="activeName"
+        :initLoad="false"
+        :columns="columns"
+        :datasource="datasource"
+        row-key="code"
+        :selection.sync="selection"
+        @sort-change="onSortChange"
+        autoAmendPage
+        :parse-data="parseData"
+        @columns-change="handleColumnChange"
+        :cache-key="cacheKeyUrl"
+        :pageSize="20"
+        :height="tableHeight"
+        @fullscreen-change="fullscreenChange"
+      >
+        <template v-slot:toolbar>
+          <el-button type="primary" @click="toAdd()">新增</el-button>
+          <el-button type="danger" @click="toDel()">删除</el-button>
+          <el-button type="success" @click="toEnd()">导出</el-button>
+          <el-button type="primary" @click="allPrinting()">打印</el-button>
+        </template>
+
+        <template v-slot:code="{ row }">
+          <el-link type="primary" :underline="false" @click="goDetail(row)">
+            {{ row.code }}
+          </el-link>
+        </template>
+
+        <template v-slot:apsWorkOrderCode="{ row }">
+          <label>{{ row.apsWorkOrderCode || '' }}</label>
+        </template>
+
+        <template v-slot:formingNum="{ row }">
+          <span> {{ row.formingNum }} </span>
+        </template>
+
+        <template v-slot:formingWeight="{ row }">
+          <span> {{ row.formingWeight }} {{ row.weightUnit }} </span>
+        </template>
+
+        <template v-slot:singleReport="{ row }">
+          <span v-if="row.singleReport == 0">批量报工</span>
+          <span v-if="row.singleReport == 1">单个报工</span>
+        </template>
+
+        <template v-slot:sourceType="{ row }">
+          <span v-if="row.sourceType == 1">生产计划</span>
+          <span v-if="row.sourceType == 2">临时生产计划</span>
+          <span v-if="row.sourceType == 3">受托转订单</span>
+        </template>
+
+        <template v-slot:workOrderType="{ row }">
+          <span v-if="row.workOrderType == 1">普通订单</span>
+          <span v-if="row.workOrderType == 2">临时订单</span>
+          <span v-if="row.workOrderType == 3">受托订单</span>
+        </template>
+
+        <template v-slot:entrustStatus="{ row }">
+          <div v-if="row.entrustStatus">
+            <span v-if="row.entrustStatus == 1">未请托</span>
+            <span v-if="row.entrustStatus == 2">请托中</span>
+            <span v-if="row.entrustStatus == 3">请托完成</span>
+          </div>
+          <span v-else>未请托</span>
+        </template>
+
+        <template v-slot:outsourceStatus="{ row }">
+          <div v-if="row.outsourceStatus">
+            <span v-if="row.outsourceStatus == 1">未委外</span>
+            <span v-if="row.outsourceStatus == 2">委外中</span>
+            <span v-if="row.outsourceStatus == 3">完成委外</span>
+          </div>
+        </template>
+
+        <template #taskName="{ row }">
+          <div v-if="taskNameMap[row.id]?.length" class="task-flow">
+            <template v-for="(item, index) in taskNameMap[row.id]">
+              <el-tag
+                size="mini"
+                effect="dark"
+                :type="getTaskTagTypeByStatus(item.flag)"
+              >
+                {{ item.taskTypeName }}
+              </el-tag>
+
+              <!-- 箭头 -->
+              <span
+                v-if="index < taskNameMap[row.id].length - 1"
+                class="task-arrow"
+              >
+                →
+              </span>
+            </template>
+          </div>
+          <span v-else>—</span>
+        </template>
+
+        <template v-slot:status="{ row }">
+          <span :class="{ 'ele-text-danger': row.status == 3 }">
+            {{ statusFormatter(row.status) }}
+          </span>
+        </template>
+        <!-- 操作列 -->
+        <template v-slot:action="{ row }">
+            <el-link
+                type="primary"
+                :underline="false"
+                @click="routing(row)"
+            >
+                编辑
+            </el-link>
+            <el-link
+                type="primary"
+                :underline="false"
+                @click="handleOrderPublish(row)"
+            >
+                删除
+            </el-link>
+            <el-link
+                type="primary"
+                :underline="false"
+                @click="toEnd(row)"
+            >
+                提交
+            </el-link>
+            <el-link
+                type="primary"
+                :underline="false"
+                @click="toReleaseOpen(row)"
+            >
+                发布
+            </el-link>
+
+            <el-link
+                type="primary"
+                @click="toRelease(row)"
+                >撤销</el-link
+            >
+            <el-link
+                type="primary"
+                @click="toRelease(row)"
+                >作废</el-link
+            >
+        </template>
+      </ele-pro-table>
+    </el-card>
+  </div>
+</template>
+
+<script>
+//   import releaseDialog from './components/releaseDialog';
+//   import workReport from './workReport.vue';
+//   import {
+//     getPage,
+//     batchCompletion,
+//     cancelCompletion,
+//     updatePriority,
+//     update,
+//     getTaskIdByInstanceId,
+//     updateStatusPause,
+//     updateStatusTerminate,
+//     getMyPage
+//   } from '@/api/produceOrder/index.js';
+//   import xlhView from './components/xlhView.vue';
+//   import { fieldModel } from '@/api/produceWord/index.js';
+
+  import { debounce } from 'lodash';
+  import tableColumnsMixin from '@/mixins/tableColumnsMixin';
+//   import checkAdd from '@/views/checklistManagement/components/checkAdd.vue';
+//   import checkDetails from '@/views/checklistManagement/components/checkDetails.vue';
+//   import { getTaskInstanceList } from '@/api/produce/job';
+
+  export default {
+    mixins: [tableColumnsMixin],
+    components: {
+   
+    },
+
+    data() {
+      return {
+        activeName: 'first',
+        tabValue: '1',
+        id: '',
+        where: {},
+        // 加载状态
+        loading: false,
+        pageType: 'add',
+        dialogTitle: '',
+        isBindPlan: false,
+        statusOpt: {
+          first: [
+            { label: '所有状态', value: '5,4' },
+            { label: '待生产', value: '4' },
+            { label: '生产中', value: '5' }
+            // { label: '已延期', value: '7' }
+          ],
+          second: [{ label: '已完成', value: '6' }]
+        },
+        planType: [
+          { label: '所有计划类型', value: null },
+          { label: '内销计划', value: '1' },
+          { label: '外销计划', value: '2' },
+          { label: '预制计划', value: '3' }
+        ],
+        selection: [],
+        cacheKeyUrl: '7cc8e5d2-wt-noticeIssuance-index',
+        columnsVersion: 0,
+        dispatchVisible: false,
+        dispatchRow: {},
+        tableHeight: 'calc(100vh - 375px)',
+        workDataList: [],
+        taskNameMap: {}
+      };
+    },
+    computed: {
+      // 表格列配置
+      seekList() {
+        return [
+          {
+            label: '标题:',
+            value: 'keyWord',
+            type: 'input',
+            placeholder: ''
+          },
+          {
+            label: '发文字号:',
+            value: 'code',
+            type: 'input',
+            placeholder: '',
+            labelWidth: 100
+          },
+          {
+            label: '发文机关:',
+            value: 'apsWorkOrderCode',
+            type: 'select',
+            labelWidth: 100
+          },
+          {
+            label: '紧急程度:',
+            value: 'productionPlanCode',
+            type: 'select',
+            width: 240
+          },
+        ];
+      },
+      columns() {
+        const num = this.columnsVersion;
+        return [
+          {
+            width: 45,
+            type: 'selection',
+            columnKey: 'selection',
+            align: 'center',
+            fixed: 'left'
+          },
+          {
+            prop: 'batchNo',
+            label: '序号',
+            align: 'center',
+            minWidth: 130,
+            showOverflowTooltip: true
+          },
+
+          {
+            prop: 'lineNumber',
+            label: '发文编码',
+            align: 'center',
+            minWidth: 130,
+            showOverflowTooltip: true
+          },
+
+          {
+            prop: 'code',
+            slot: 'code',
+            label: '标题',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'QRcode',
+            slot: 'QRcode',
+            label: '发文字号',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'apsWorkOrderCode',
+            label: '发文机关',
+            slot: 'apsWorkOrderCode',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'sourceType',
+            label: '拟稿人',
+            slot: 'sourceType',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'sourceCode',
+            label: '拟稿日期',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'workOrderType',
+            label: '紧急程度',
+            slot: 'workOrderType',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'productionPlanCode',
+            label: '审批状态',
+            align: 'center',
+            minWidth: 110,
+            showOverflowTooltip: true
+          },
+          {
+            prop: 'planType',
+            label: '发布状态',
+            align: 'center',
+            showOverflowTooltip: true,
+            formatter: (row) => {
+              const obj = this.planType.find((i) => i.value == row.planType);
+              return obj && obj.label;
+            }
+          },
+          {
+            prop: 'bomType',
+            label: '当前环节',
+            align: 'center',
+            showOverflowTooltip: true,
+            width: 120,
+            formatter: (row) => {
+              if (row.bomType == 1) {
+                return '产品(PBOM)';
+              }
+              if (row.bomType == 2) {
+                return '加工(MBOM)';
+              }
+              if (row.bomType == 3) {
+                return '装配(ABOM)';
+              }
+              // if (row.bomType == 4) {
+              //   return '装配(EBOM)';
+              // }
+              return '';
+            }
+          },
+          {
+            prop: 'bomCategoryName',
+            label: '当前处理人',
+            align: 'center',
+            width: 130,
+            showOverflowTooltip: true,
+            formatter: (row) => {
+              if (row.bomCategoryName) {
+                return `${row.bomCategoryName} (V${row.bomCategoryVersions}.0)`;
+              }
+              return '';
+            }
+          },
+         
+
+          {
+            prop: 'action',
+            label: '操作',
+            align: 'center',
+            slot: 'action',
+            showOverflowTooltip: true
+          }
+        ];
+      },
+      dispatchBtn() {
+        return (row) => {
+          if (Number(row.taskId) == NaN || Number(row.taskId) <= 0) {
+            return false;
+          }
+          return !!row.taskId;
+        };
+      },
+      clientEnvironmentId() {
+        return this.$store.state.user.info.clientEnvironmentId;
+      }
+    },
+    watch: {
+      activeName: {
+        handler() {
+          if (this.activeName) {
+            this.where.status = this.statusOpt[this.activeName][0].value;
+            this.reload();
+          }
+        },
+        immediate: true
+      }
+    },
+    created() {
+    },
+    mounted() {
+      this.reload();
+    },
+
+    methods: {
+        toAdd() {
+
+        },
+      //派单
+      toReleaseOpen(row) {
+        getTaskIdByInstanceId(row.taskId)
+          .then((res) => {
+            if (res) {
+              this.dispatchRow = { ...row };
+              this.dispatchRow.initialWeight = row.formingWeight
+                ? row.formingWeight + row.weightUnit
+                : '';
+              this.dispatchRow.taskInstanceId = res;
+              this.dispatchVisible = true;
+            }
+          })
+          .catch((err) => {
+            this.$message.error(err.message);
+          });
+      },
+      search(e) {
+        if (Array.isArray(e.createTime) && e.createTime.length) {
+          e.createTimeStart = e.createTime[0];
+          e.createTimeEnd = e.createTime[1];
+        }
+        this.reload(e);
+      },
+
+      // 查看序列号
+      toView(row) {
+        this.$refs.xlhRef.open(row);
+      },
+
+      handlePicking() {
+        this.$router.push({
+          path: '/produceOrder/picking'
+        });
+      },
+      statusFormatter(status) {
+        const obj = this.statusOpt[this.activeName].find(
+          (i) => i.value == status
+        );
+
+        return obj && obj.label;
+      },
+
+      btnPrint() {
+        const url = this.$router.resolve({ path: '/print' }).href; // 获取目标URL路径的完整URL字符串
+        window.open(url, '_blank');
+        // this.$router.push({
+        //   path: '/print'
+        // });
+      },
+
+      routing(row) {
+        this.id = row.id;
+
+        this.$refs.equipmentRef.open();
+      },
+      handleTabClick() {
+        if (this.tabValue == '6') {
+          this.activeName = 'second';
+        } else {
+          this.activeName = 'first';
+        }
+        this.reload();
+      },
+
+      async loadTaskNames(list) {
+        for (const row of list) {
+          try {
+            const res = await getTaskInstanceList(row.id);
+            const findIndex = res.findIndex(
+              (item) => item.taskId == row.taskId
+            );
+
+            const markedList = res.map((item, index) => {
+              let flag = 'after';
+
+              if (findIndex != -1) {
+                if (index < findIndex) {
+                  flag = '4';
+                } else if (index === findIndex) {
+                  flag = '3';
+                } else {
+                  flag = '1';
+                }
+              }
+
+              return {
+                ...item,
+                flag
+              };
+            });
+
+            this.$set(this.taskNameMap, row.id, markedList);
+
+            // this.$set(
+            //   this.taskNameMap,
+            //   row.taskId,
+            //   res.list.map((i) => i.name)
+            // );
+            // console.log(res, '工序数据');
+          } catch (e) {
+            this.$set(this.taskNameMap, row.id, []);
+          }
+        }
+
+        this.$nextTick(() => {
+          this.$refs.table?.doLayout?.();
+        });
+      },
+
+      getTaskTagTypeByStatus(status) {
+        return (
+          {
+            1: 'info',
+            2: 'primary',
+            3: 'warning',
+            4: 'success'
+          }[status] || ''
+        );
+      },
+
+      originCode() {
+        if (!this.selection.length) {
+          return this.$message.warning('请至少选择一条工单!');
+        }
+
+        if (this.selection.length > 1) {
+          return this.$message.warning('只能选择一条工单');
+        }
+
+        this.$refs.originCodeRef.open(this.selection[0].id);
+      },
+
+      /* 表格数据源 */
+      async datasource({ page, limit, where, order }) {
+        console.log(this.tabValue, '888');
+        let statusList = this.tabValue == 1 ? [4, 5, 7] : [this.tabValue];
+
+        let params = {
+          ...where,
+          ...order,
+          queryTermination: this.tabValue == '10' ? 1 : 0,
+          pageNum: page,
+          size: limit,
+          ...this.sort
+        };
+
+        // 只有 tabValue == 1 才可能需要 workCenterIds 字段,可根据业务决定是否添加
+        if (this.tabValue == 1) {
+          params.workCenterIds = this.$store.state.user.info.workCenterIds;
+        }
+
+        const URL = this.tabValue == 1 ? getMyPage : getPage;
+
+        let res = await URL({ ...params, statusList });
+
+        // this.loadTaskNames(res.list);
+        // let res = await URL({ ...params, statusList });
+
+        // await Promise.all(
+        //   res.list.map(async (row) => {
+        //     const tasks = await getTaskInstanceList(row.id);
+        //     row._taskList = tasks;
+        //   })
+        // );
+
+        return res;
+      },
+
+      getWorkData() {
+        if (this.$refs.table.getData().length != 0) {
+          // const data = this.deep()
+        }
+      },
+
+      onSortChange(e) {
+        let sort = {
+          orderBy: e.order,
+          sortName: e.prop
+        };
+        this.sort = sort;
+        this.reload();
+      },
+      flattenArray(arr) {
+        var result = []; // 存放结果的数组
+        for (let i = 0; i < arr.length; i++) {
+          if (Array.isArray(arr[i].subWorkOrder)) {
+            let _arr = [];
+            _arr = _arr.concat(arr[i].subWorkOrder);
+            delete arr[i].subWorkOrder;
+            result.push(arr[i]);
+            result.push(..._arr);
+          } else {
+            result.push(arr[i]);
+          }
+        }
+
+        return result;
+      },
+
+      /* 数据转为树形结构 */
+      parseData(data) {
+        return {
+          ...data,
+          list: this.$util.toTreeData({
+            data: data.list,
+            count: data.total,
+
+            idField: 'code',
+            parentIdField: 'originalCode'
+          })
+        };
+      },
+
+      /* 数据转为树形结构 */
+
+      createSuccess() {
+        this.reload();
+      },
+      handleCreate() {
+        this.$refs.createRef.open(0);
+      },
+      // 发布工单
+      handleOrderPublish(row) {
+        this.$refs.workReport.open(row);
+        // this.$router.push({
+        //   path: '/produce',
+        //   query: {
+        //     workOrderId: row.id
+        //   }
+        // });
+        // this.$router.push({
+        //   path: '/produceOrder/workReport',
+        //   query: {
+        //     workOrderId: row.id
+        //   }
+        // });
+      },
+
+      fullscreenChange(fullscreen) {
+        if (fullscreen) {
+          this.tableHeight = 'calc(100vh - 120px)';
+        } else {
+          this.tableHeight = 'calc(100vh - 375px)';
+        }
+      },
+
+      // 删除
+      toDel(row) {
+        if (row) {
+          this.$confirm(`是否要完结工单【${row.code}】?`, '提醒', {
+            confirmButtonText: '确认',
+            cancelButtonText: '取消',
+            type: 'warning'
+          })
+            .then(() => {
+              batchCompletion([row.id]).then((res) => {
+                this.$message.success('成功');
+                this.reload();
+              });
+            })
+            .catch(() => {});
+        } else {
+          if (!this.selection.length) {
+            return this.$message.warning('请至少选择一条工单!');
+          }
+          const ids = [];
+          this.selection.map((item) => {
+            ids.push(item.id);
+          });
+          const h = this.$createElement;
+          this.$msgbox({
+            title: '提醒',
+            message: h('p', null, [
+              h('span', null, '是否要完结 '),
+              h(
+                'span',
+                { style: 'color: #70B603' },
+                `${this.selection.length}`
+              ),
+              h('span', null, ' 条工单?')
+            ]),
+            showCancelButton: true,
+            confirmButtonText: '确认',
+            cancelButtonText: '取消',
+            type: 'warning'
+          })
+            .then(() => {
+              batchCompletion(ids).then((res) => {
+                this.$message.success('成功');
+                this.reload();
+              });
+            })
+            .catch(() => {});
+        }
+      },
+
+      // 取消完结
+      toCancel(row) {
+        cancelCompletion([row.id]).then((res) => {
+          this.$message.success('成功');
+          this.reload();
+        });
+      },
+
+      // 拆分
+      toUnpack(row) {
+        this.$refs.unpackRef.open(row);
+      },
+      handleTabChange() {
+        this.$refs.searchRef.reset();
+      },
+
+      /* 刷新表格 */
+      reload(where = {}) {
+        this.$nextTick(() => {
+          where.statusList = (
+            where.status || this.statusOpt[this.activeName][0].value
+          ).split(',');
+          this.$refs.table.reload({ page: 1, where });
+        });
+      },
+
+      // 生产工单跳转
+      goDetail(row) {
+        this.$refs.detailsRef.open(row);
+      },
+      handleDelete({ id }) {
+        this.$confirm('确定删除当前数据?', '提示').then(async () => {
+          await del(id);
+          this.$message.success('删除成功!');
+          this.reload();
+        });
+      },
+
+      handleQRcode(row) {
+        console.log('clientEnvironmentId', this.clientEnvironmentId);
+        if (this.clientEnvironmentId == 2) {
+          this.$refs.printSrRef.open([row.id]);
+        } else if (this.clientEnvironmentId == 3) {
+          this.$refs.printTgRef.open([row.id]);
+        } else {
+          this.$refs.printRef.open([row.id]);
+        }
+      },
+
+      allPrinting() {
+        let ids = this.findAllIds(this.selection);
+        if (this.clientEnvironmentId == 2) {
+          this.$refs.printSrRef.open(ids);
+        } else if (this.clientEnvironmentId == 3) {
+          this.$refs.printTgRef.open(ids);
+        } else {
+          this.$refs.printRef.open(ids);
+        }
+      },
+      // 工艺卡打印
+      cardPrinting() {
+        if (this.selection.length < 1) {
+          return this.$message.warning('请选择一条工单!');
+        }
+        let ids = this.findAllIds(this.selection);
+        this.$refs.printCardRef.open(ids);
+      },
+
+      findAllIds(nodes) {
+        let ids = [];
+        nodes.forEach((node) => {
+          ids.push(node.id); // 添加当前节点的id
+          if (node.children && node.children.length > 0) {
+            // 递归调用自身来处理子节点
+            ids = ids.concat(this.findAllIds(node.children));
+          }
+        });
+        return ids;
+      },
+
+      choose(row) {
+        this.updateFn(row);
+      },
+
+      async updateFn(row) {
+        let req = {
+          id: this.id, //工艺路线id		false
+          produceRoutingId: row[0].id, //工艺路线id		false
+          produceRoutingName: row[0].name
+        };
+        const res = await update(req);
+        this.reload();
+      },
+
+      sortTop(row) {
+        row.priority = Number(row.priority) + 1;
+        this.priorityChange(row);
+      },
+      sortBottom(row) {
+        if (row.priority <= 1) {
+          return;
+        }
+        row.priority = Number(row.priority) - 1;
+        this.priorityChange(row);
+      },
+
+      priorityChange(row) {
+        if (row.priority > 10) {
+          row.priority = 10; // 如果大于 10,则设置为 10
+        } else if (row.priority < 0) {
+          row.priority = 0; // 如果小于 0,则设置为 0
+        }
+
+        this.priorityFn(row);
+      },
+      priorityFn: debounce(function (row) {
+        let params = {
+          id: row.id,
+          priority: row.priority
+        };
+        updatePriority(params).then((res) => {});
+      }, 800),
+    }
+  };
+</script>
+
+<style scoped>
+  .task-flow {
+    display: flex;
+    align-items: center;
+    flex-wrap: wrap;
+  }
+
+  .task-arrow {
+    margin: 0 6px;
+    color: #999;
+    font-weight: bold;
+  }
+</style>

+ 84 - 3
src/views/home/common-dialog.vue

@@ -24,9 +24,36 @@
         </el-col>
         <el-col :span="24">
           <el-form-item label="图标:" prop="icon">
-            <ele-icon-picker v-model="form.icon" :size="24" :show-label="false" />
+            <el-button type="default" @click="showIconDialog = true" size="small">
+              <img v-if="form.pic" :src="form.icon" alt="" style="width: 30px; height: 30px; margin-right: 4px;">
+              <span v-else>选择图标</span>
+            </el-button>
           </el-form-item>
         </el-col>
+        
+        <!-- 图标选择弹窗 -->
+        <ele-modal
+          custom-class="icon-select-modal"
+          :centered="true"
+          :visible.sync="showIconDialog"
+          title="选择图标"
+          :close-on-click-modal="false"
+          append-to-body
+          width="60%">
+          <div class="icon-list">
+            <div 
+              v-for="(icon, index) in iconList" 
+              :key="index" 
+              class="icon-item"
+              @click="selectIcon(icon, index)"
+            >
+              <img :src="icon" alt="" style="width: 32px; height: 32px;">
+            </div>
+          </div>
+          <div slot="footer">
+            <el-button size="small" @click="showIconDialog = false">关 闭</el-button>
+          </div>
+        </ele-modal>
       </el-row>
       <!-- <div style="margin: 6px 0 28px 0">
         <el-divider />
@@ -47,13 +74,12 @@
 
 
 import {mapGetters} from "vuex";
-import {EleIconPicker} from 'ele-admin';
 import {getAllResourceByCurrentUserAPI, userResourceSaveAPI} from "@/api/home";
 
 export default {
   name: "common-dialog",
   components: {
-    EleIconPicker
+    
   },
   props: {
     commonDialogFlag: {
@@ -67,6 +93,8 @@ export default {
       form: {
         sort: 1,
         resourceId: '',
+        icon: '',
+        pic: ''
       },
       rules: {
         resourceId:{required:true,message:'',trigger:['blur','change']},
@@ -74,6 +102,26 @@ export default {
       menuList: [],
       menuTreeList: [],
       dialogType: '',
+      showIconDialog: false,
+      iconList: [
+        require('@/assets/home/commonIcon/icon_0.svg'),
+        require('@/assets/home/commonIcon/icon_1.svg'),
+        require('@/assets/home/commonIcon/icon_2.svg'),
+        require('@/assets/home/commonIcon/icon_3.svg'),
+        require('@/assets/home/commonIcon/icon_4.svg'),
+        require('@/assets/home/commonIcon/icon_5.svg'),
+        require('@/assets/home/commonIcon/icon_6.svg'),
+        require('@/assets/home/commonIcon/icon_7.svg'),
+        require('@/assets/home/commonIcon/icon_8.svg'),
+        require('@/assets/home/commonIcon/icon_9.svg'),
+        require('@/assets/home/commonIcon/icon_10.svg'),
+        require('@/assets/home/commonIcon/icon_11.svg'),
+        require('@/assets/home/commonIcon/icon_12.svg'),
+        require('@/assets/home/commonIcon/icon_13.svg'),
+        require('@/assets/home/commonIcon/icon_14.svg'),
+        require('@/assets/home/commonIcon/icon_15.svg'),
+        require('@/assets/home/commonIcon/icon_16.svg')
+      ]
     }
   },
   computed: {
@@ -94,7 +142,14 @@ export default {
     },
 
 
+    selectIcon(icon, index) {
+      this.form.icon = icon;
+      // 存储原始静态路径到 pic 字段
+      this.form.pic = `icon_${index}.svg`;
+      this.showIconDialog = false;
+    },
     async submit(type = '') {
+      console.log('form~~~', this.form);
       await userResourceSaveAPI(this.form)
       this.$message.success('操作成功');
       this.cancel()
@@ -109,5 +164,31 @@ export default {
 
 
 <style scoped lang="scss">
+.icon-list {
+  display: grid;
+  grid-template-columns: repeat(8, 1fr);
+  gap: 16px;
+  padding: 16px;
+}
 
+.icon-item {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  padding: 12px;
+  border: 1px solid #eaeaea;
+  border-radius: 4px;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  
+  &:hover {
+    border-color: #1890ff;
+    background-color: #f0f9ff;
+  }
+  
+  img {
+    width: 32px;
+    height: 32px;
+  }
+}
 </style>

+ 250 - 219
src/views/home/indexNew.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="home-container">
-    <el-row :gutter="20">
-      <el-col :span="24">
+    <el-row :gutter="12" style="height: 158px;">
+      <el-col :span="24" class="box-col">
         <el-card class="box-card">
           <div slot="header" class="clearfix">
             <span>常用功能</span>
@@ -25,11 +25,11 @@
                 "
               >
                 <!-- <div class="common-function-item-content"> -->
-                  <div>
+                  <div class="common-function-item-icon">
                     <!-- <i :class="item.icon || 'el-icon-s-opportunity'"></i> -->
-                    <img :src="item.icon || '~@/assets/home/commonIcon/icon_0.svg'" alt="">
+                    <img :src="getIconPath(item.pic)" alt="">
                   </div>
-                  <div>{{ item.name }}</div>
+                  <div class="common-function-item-name">{{ item.name }}</div>
                 <!-- </div> -->
               </div>
             </vuedraggable>
@@ -38,8 +38,8 @@
       </el-col>
     </el-row>
 
-    <el-row :gutter="20" class="mt-20">
-      <el-col :span="18">
+    <el-row :gutter="12" class="mt-20" style="height: 250px;">
+      <el-col :span="18" class="box-col">
         <el-card class="box-card">
           <div slot="header" class="clearfix">
             <span>数据概览</span>
@@ -52,26 +52,20 @@
                     <div class="overview-top-img"><img src="~@/assets/home/my-project.svg" alt=""></div>
                     <div class="overview-top-content">
                       <div class="overview-top-content-name">我的项目</div>
-                      <div class="overview-top-content-count">123</div>
+                      <div class="overview-top-content-count">{{ myProjectList['总数量'] || 0 }}</div>
                     </div>
                   </div>
                   <el-divider></el-divider>
                   <div class="overview-bottom">
-                    <div class="overview-bottom-item">
-                      <div class="overview-bottom-item-name">实施项目</div>
-                      <div class="overview-bottom-item-count">123</div>
-                    </div>
-                    <div class="overview-bottom-item">
-                      <div class="overview-bottom-item-name">开发项目</div>
-                      <div class="overview-bottom-item-count">123</div>
-                    </div>
-                    <div class="overview-bottom-item">
-                      <div class="overview-bottom-item-name">测试项目</div>
-                      <div class="overview-bottom-item-count">123</div>
-                    </div>
-                    <div class="overview-bottom-item">
-                      <div class="overview-bottom-item-name">研发项目</div>
-                      <div class="overview-bottom-item-count">123</div>
+                    <div 
+                      v-for="(value, key) in myProjectList" 
+                      :key="key"
+                      v-if="key !== '总数量'"
+                      class="overview-bottom-item"
+                      @click="handleTo(key)"
+                    >
+                      <div class="overview-bottom-item-name">{{ key }}</div>
+                      <div class="overview-bottom-item-count">{{ value || 0 }}</div>
                     </div>
                   </div>
                 </div>
@@ -82,26 +76,20 @@
                     <div class="overview-top-img"><img src="~@/assets/home/my-project.svg" alt=""></div>
                     <div class="overview-top-content">
                       <div class="overview-top-content-name">我的工单</div>
-                      <div class="overview-top-content-count">123</div>
+                      <div class="overview-top-content-count">{{ myWorkOrderList['总数量'] || 0 }}</div>
                     </div>
                   </div>
                   <el-divider></el-divider>
                   <div class="overview-bottom">
-                    <div class="overview-bottom-item">
-                      <div class="overview-bottom-item-name">运维工单</div>
-                      <div class="overview-bottom-item-count">123</div>
-                    </div>
-                    <div class="overview-bottom-item">
-                      <div class="overview-bottom-item-name">生产工单</div>
-                      <div class="overview-bottom-item-count">123</div>
-                    </div>
-                    <div class="overview-bottom-item">
-                      <div class="overview-bottom-item-name">质检工单</div>
-                      <div class="overview-bottom-item-count">123</div>
-                    </div>
-                    <div class="overview-bottom-item">
-                      <div class="overview-bottom-item-name">盘点工单</div>
-                      <div class="overview-bottom-item-count">123</div>
+                    <div 
+                      v-for="(value, key) in myWorkOrderList" 
+                      :key="key"
+                      v-if="key !== '总数量'"
+                      class="overview-bottom-item"
+                      @click="handleTo(key)"
+                    >
+                      <div class="overview-bottom-item-name">{{ key }}</div>
+                      <div class="overview-bottom-item-count">{{ value || 0 }}</div>
                     </div>
                   </div>
                 </div>
@@ -112,26 +100,20 @@
                     <div class="overview-top-img"><img src="~@/assets/home/my-project.svg" alt=""></div>
                     <div class="overview-top-content">
                       <div class="overview-top-content-name">我的任务</div>
-                      <div class="overview-top-content-count">123</div>
+                      <div class="overview-top-content-count">{{ myTaskList['总数量'] || 0 }}</div>
                     </div>
                   </div>
                   <el-divider></el-divider>
                   <div class="overview-bottom">
-                    <div class="overview-bottom-item">
-                      <div class="overview-bottom-item-name">项目任务</div>
-                      <div class="overview-bottom-item-count">123</div>
-                    </div>
-                    <div class="overview-bottom-item">
-                      <div class="overview-bottom-item-name">生产任务</div>
-                      <div class="overview-bottom-item-count">123</div>
-                    </div>
-                    <div class="overview-bottom-item">
-                      <div class="overview-bottom-item-name">质检任务</div>
-                      <div class="overview-bottom-item-count">123</div>
-                    </div>
-                    <div class="overview-bottom-item">
-                      <div class="overview-bottom-item-name">盘点任务</div>
-                      <div class="overview-bottom-item-count">123</div>
+                    <div 
+                      v-for="(value, key) in myTaskList" 
+                      :key="key"
+                      v-if="key !== '总数量'"
+                      class="overview-bottom-item"
+                      @click="handleTo(key)"
+                    >
+                      <div class="overview-bottom-item-name">{{ key }}</div>
+                      <div class="overview-bottom-item-count">{{ value || 0 }}</div>
                     </div>
                   </div>
                 </div>
@@ -140,14 +122,14 @@
           </div>
         </el-card>
       </el-col>
-      <el-col :span="6">
+      <el-col :span="6" class="box-col">
         <el-card class="box-card">
           <div slot="header" class="clearfix">
             <span>统一门户</span>
           </div>
-          <div class="card-content">
+          <div class="card-content portal-content">
             <div class="portal">
-              <el-row :gutter="20">
+              <el-row :gutter="12">
                 <el-col :span="12" v-for="item in portals" :key="item.name" class="portal-item">
                   <div class="portal-item-content">
                     <div class="portal-item-img"><img :src="item.img" alt=""></div>
@@ -161,8 +143,8 @@
       </el-col>
     </el-row>
 
-    <el-row :gutter="20" class="mt-20">
-      <el-col :span="18">
+    <el-row :gutter="12" class="mt-20" style="height: 404px;">
+      <el-col :span="18" class="box-col">
         <el-card class="box-card">
           <!-- <div slot="header" class="clearfix">
             <span>通知公告</span>
@@ -178,26 +160,29 @@
               <el-tab-pane label="系统通知" name="system"></el-tab-pane>
             </el-tabs>
             
-            <div class="notification-list">
-              <div v-for="(item, index) in currentNotifications" :key="index" class="notification-item">
+            <div v-if="notifications.length > 0" class="notification-list">
+              <div v-for="(item, index) in notifications" :key="index" class="notification-item">
                 <div class="notification-dot"></div>
                 <div class="notification-content">
                   <div class="notification-header">
                     <div class="notification-title">{{ item.title }}</div>
                     <div class="notification-text">{{ item.content }}</div>
                   </div>
-                  <div class="notification-info">{{ item.info }}</div>
+                  <div class="notification-info">发文机关:{{ item.department }}  {{ item.createUser }}</div>
                 </div>
-                <div class="notification-date">{{ item.date }}</div>
+                <div class="notification-date">{{ item.createTime }}</div>
               </div>
               <div class="notification-more" @click="loadMoreNotifications">
                 更多......
               </div>
             </div>
+            <div v-else class="no-notification">
+              <el-empty description="暂无数据"></el-empty>
+            </div>
           </div>
         </el-card>
       </el-col>
-      <el-col :span="6">
+      <el-col :span="6" class="box-col">
         <el-card class="box-card">
           <div slot="header" class="clearfix">
             <span>工作日历</span>
@@ -262,13 +247,17 @@
 </template>
 
 <script>
+import { notifyMessagePageAPI } from '@/api/bpm/task';
 import {
-    projectsPageAPI,
-    projectsTaskPageAPI,
     userResourceDeleteAPI,
     userResourceListAPI,
-    getList
+    getList,
+    getMyProjectTotal,
+    getMyWorkOrderTotal,
+    getMyTaskTotal
   } from '@/api/home';
+import { deepClone } from 'ele-admin/lib/utils/core';
+import { mapGetters } from 'vuex';
 import vuedraggable from 'vuedraggable';
 import commonDialog from '@/views/home/common-dialog.vue';
 export default {
@@ -279,154 +268,110 @@ export default {
   },
   data() {
     return {
-      activeMenu: 'workbench',
       currentDate: new Date(),
       calendarRange: [],
-      commonFunctions: [
-        { name: '出差申请', icon: 'el-icon-plane' },
-        { name: '报销申请', icon: 'el-icon-document' },
-        { name: '请假申请', icon: 'el-icon-time' },
-        { name: '加班申请', icon: 'el-icon-clock' },
-        { name: '日报', icon: 'el-icon-date' },
-        { name: '周报', icon: 'el-icon-date' },
-        { name: '月报', icon: 'el-icon-date' },
-        { name: '出差申请1', icon: 'el-icon-plane' },
-        { name: '报销申请2', icon: 'el-icon-document' },
-        { name: '请假申请3', icon: 'el-icon-time' },
-        { name: '加班申请4', icon: 'el-icon-clock' },
-        { name: '日报5', icon: 'el-icon-date' },
-        { name: '周报6', icon: 'el-icon-date' },
-        { name: '月报7', icon: 'el-icon-date' }
-      ],
-      projectData: [
-        { name: '实施项目', value: 30 },
-        { name: '开发项目', value: 30 },
-        { name: '测试项目', value: 30 },
-        { name: '研发项目', value: 30 },
-        { name: '运维工单', value: 30 },
-        { name: '生产工单', value: 30 },
-        { name: '质检工单', value: 30 },
-        { name: '盘点工单', value: 30 }
-      ],
-      orderData: [
-        { name: '运维工单', value: 30 },
-        { name: '生产工单', value: 30 },
-        { name: '质检工单', value: 30 },
-        { name: '盘点工单', value: 30 }
-      ],
-      taskData: [
-        { name: '项目任务', value: 30 },
-        { name: '生产任务', value: 30 },
-        { name: '质检任务', value: 30 },
-        { name: '盘点任务', value: 30 }
-      ],
-      notifications: [
-        {
-          title: '关于门户界面升级的通知公告',
-          info: '发文机关:总经办 联系人:张三',
-          date: '2023-09-09'
-        },
-        {
-          title: '关于门户界面升级的通知公告',
-          info: '发文机关:总经办 联系人:张三',
-          date: '2023-09-09'
-        },
-        {
-          title: '关于门户界面升级的通知公告',
-          info: '发文机关:总经办 联系人:张三',
-          date: '2023-09-09'
-        },
-        {
-          title: '关于门户界面升级的通知公告',
-          info: '发文机关:总经办 联系人:张三',
-          date: '2023-09-09'
-        }
-      ],
-      activeTab: 'notice',
-      notifications: {
-        notice: [
-          {
-            title: '关于门户界面升级的通知公告',
-            info: '发文机关:总经办 拟稿人:张三',
-            content: '连日来,外交部和中国民航局全力协调,紧急派出航班协助滞留中东地区中国旅客回国。外交部领事保护中心建议……',
-            date: '2023-03-09'
-          },
-          {
-            title: '关于门户界面升级的通知公告',
-            info: '发文机关:总经办 拟稿人:张三',
-            content: '连日来,外交部和中国民航局全力协调,紧急派出航班协助滞留中东地区中国旅客回国。外交部领事保护中心建议……',
-            date: '2023-03-09'
-          },
-          {
-            title: '关于门户界面升级的通知公告',
-            info: '发文机关:总经办 拟稿人:张三',
-            content: '连日来,外交部和中国民航局全力协调,紧急派出航班协助滞留中东地区中国旅客回国。外交部领事保护中心建议……',
-            date: '2023-03-09'
-          },
-          {
-            title: '关于门户界面升级的通知公告',
-            info: '发文机关:总经办 拟稿人:张三',
-            content: '连日来,外交部和中国民航局全力协调,紧急派出航班协助滞留中东地区中国旅客回国。外交部领事保护中心建议……',
-            date: '2023-03-09'
-          }
-        ],
-        industry: [
-          {
-            title: '行业发展趋势分析',
-            info: '来源:行业协会 发布人:李四',
-            content: '近年来,人工智能技术在各行业的应用日益广泛,为企业数字化转型提供了强大动力……',
-            date: '2023-03-08'
-          },
-          {
-            title: '市场调研报告',
-            info: '来源:市场研究机构 发布人:王五',
-            content: '根据最新市场调研数据显示,2023年上半年市场需求呈现稳步增长趋势……',
-            date: '2023-03-07'
-          }
-        ],
-        system: [
-          {
-            title: '系统升级通知',
-            info: '发布人:系统管理员',
-            content: '系统将于今晚23:00-次日凌晨2:00进行升级维护,期间系统可能暂时无法访问,请提前做好准备。',
-            date: '2023-03-06'
-          },
-          {
-            title: '数据备份通知',
-            info: '发布人:系统管理员',
-            content: '系统已完成本月数据备份,备份文件已存储至安全位置。',
-            date: '2023-03-01'
-          }
-        ]
-      },
+      commonFunctions: [],
+      activeTab: 'system',
+      notifications: [],
       currentPage: 1,
       pageSize: 4,
       portals: [],
-      schedules: [
-        { time: '10:00-12:00', content: '研发项目"产品启动会"' },
-        { time: '10:00-12:00', content: '**工单' },
-        { time: '10:00-12:00', content: '**工单' }
-      ],
       calendarShowMore: false,
       isDelFlag: false,
-      commonDialogFlag: false
+      commonDialogFlag: false,
+      myProjectList: {},
+      myWorkOrderList: {},
+      myTaskList: {}
     };
   },
   computed: {
+    ...mapGetters(['user']),
     currentNotifications() {
       const notifications = this.notifications[this.activeTab] || [];
-      const start = (this.currentPage - 1) * this.pageSize;
-      const end = start + this.pageSize;
-      return notifications.slice(0, end);
+      return notifications;
     }
   },
   created() {
     this.calendarRange = this.getWeekRange();
     this.getPortalsList();
     this.getCommonFunctionsList();
+    this.getMyProjectTotal();
+    this.getMyWorkOrderTotal();
+    this.getMyTaskTotal();
+    this.getMessageList();
   },
   methods: {
+    handleTo(key) {
+      switch(key) {
+        case '测试项目':
+        case '研发项目':
+        case '实施项目':
+        case '开发项目':
+          this.handelRouterTo('/page-pro/project-initiation')
+          break;
+        case '运维工单':
+          this.handelRouterTo('/page-eam/maintenance/patrol')
+          break;
+        case '质检工单':
+          this.handelRouterTo('/page-qms/inspectionWork')
+          break;
+        case '生产工单':
+          this.handelRouterTo('/page-mes/produceOrder')
+          break;
+        case '盘点工单':
+          this.handelRouterTo('/page-wms/warehouseManagement/stocktaking/work')
+          break;
+        case '盘点任务':
+          this.handelRouterTo('')
+          break;
+        case '生产任务':
+          this.handelRouterTo('/page-mes/rw')
+          break;
+        case '质检任务':
+          this.handelRouterTo('/page-qms/inspectionProjectTask')
+          break;
+        case '项目任务':
+          this.handelRouterTo('/page-pro/task/myTaskList')
+          break;
+      }
+    },
+    async getMessageList() {
+      let list = [];
+      if(this.activeTab === 'notice') {
+        list = []
+      } else if(this.activeTab === 'industry') {
+        list = []
+      } else if(this.activeTab === 'system') {
+        const res = await notifyMessagePageAPI({
+          pageNum: 1,
+          size: 5,
+          userId: this.user.info.userId
+        });
+        list = (res.list || []).map((item) => {
+          return {
+            title: item.templateName,
+            content: item.templateContent,
+            createUser: '创建人:' + item.userName,
+            department: item.department,
+            createTime: item.createTime
+          }
+        });
+      }
+      
+      this.notifications = list;
+      console.log('notifications~~~', this.notifications);
+    },
+    async getMyProjectTotal() {
+      this.myProjectList = await getMyProjectTotal({});
+    },
+    async getMyWorkOrderTotal() {
+      this.myWorkOrderList = await getMyWorkOrderTotal({});
+    },
+    async getMyTaskTotal() {
+      this.myTaskList = await getMyTaskTotal({});
+    },
     handleAdd() {
+      if(this.commonFunctions.length > 10) return this.$message.warning('最多只能添加10个常用功能');
       this.commonDialogFlag = true;
       this.$nextTick(() => {
         this.$refs.commonDialogRef.init();
@@ -439,6 +384,7 @@ export default {
       if (this.isDelFlag) return this.handleCommonListDel(item, index);
 
       let urlPath = item.topUrl + item.url;
+      console.log('urlPath~~~', urlPath);
       this.handelRouterTo(urlPath);
     },
     async handleCommonListDel(item, index) {
@@ -448,6 +394,14 @@ export default {
     handelRouterTo(path) {
       window.history.pushState(null, '', path);
     },
+    getIconPath(pic) {
+      if (pic) {
+        // 如果后端返回的是静态路径字符串,需要通过 require() 处理
+        return require(`@/assets/home/commonIcon/${pic}`);
+      }
+      // 如果没有 pic 字段,使用默认图标
+      return require('@/assets/home/commonIcon/icon_0.svg');
+    },
     async getCommonFunctionsList() {
       this.commonFunctions = await userResourceListAPI();
       console.log('commonFunctions~~~', this.commonFunctions);
@@ -476,11 +430,23 @@ export default {
     },
     handleTabClick() {
       // 切换标签页时重置页码
-      this.currentPage = 1;
+      // this.currentPage = 1;
+      this.getMessageList();
     },
     loadMoreNotifications() {
       // 加载更多通知(增加页码)
-      this.currentPage++;
+      // this.currentPage++;
+      switch(this.activeTab) {
+        case 'notice':
+          this.handelRouterTo('/notice');
+          break;
+        case 'industry':
+          this.handelRouterTo('/industry');
+          break;
+        case 'system':
+          this.handelRouterTo('/page-wt/message');
+          break;
+      }
     },
     // 获取当天所在周的范围,周一开头
     getWeekRange() {
@@ -540,8 +506,41 @@ export default {
   box-sizing: border-box;
   display: flex;
   flex-direction: column;
-  height: calc(100vh - 96px);
+  // height: calc(100vh - 96px);
   .card-content {
+    &.portal-content {
+      max-height: 180px;
+      overflow-y: auto;
+      overflow-x: hidden;
+      padding-right: 8px;
+      flex-shrink: 0;
+      min-height: 0;
+      
+      .portal {
+        max-height: 100%;
+        overflow-y: auto;
+        overflow-x: hidden;
+      }
+      
+      &::-webkit-scrollbar {
+        width: 6px;
+      }
+      
+      &::-webkit-scrollbar-track {
+        background: #f1f1f1;
+        border-radius: 3px;
+      }
+      
+      &::-webkit-scrollbar-thumb {
+        background: #c1c1c1;
+        border-radius: 3px;
+      }
+      
+      &::-webkit-scrollbar-thumb:hover {
+        background: #a8a8a8;
+      }
+    }
+    
     .common-function {
       display: flex;
       flex-wrap: wrap;
@@ -552,19 +551,33 @@ export default {
         flex-direction: column;
         justify-content: center;
         align-items: center;
-        width: 50px;
-        height: 50px;
-        margin: 5px;
+        margin: 0 20px;
         border-radius: 5px;
-        background-color: #f0f2f5;
         cursor: pointer;
         transition: all 0.3s ease-in-out;
-        &:hover {
-          background-color: #e4e7ed;
+        .common-function-item-icon {
+          width: 56px;
+          height: 56px;
+          box-shadow: 0px 1px 2px 1px #eae7e7;
+          background: #f8fafc;
+          border-radius: 17px;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          img {
+            width: 32px;
+            height: 32px;
+          }
+        }
+        .common-function-item-name {
+          font-size: 16px;
+          font-weight: 400;
+          color: #7a7a7a;
+          margin-top: 10px;
         }
       }
       .div-del {
-          background: #cccccc !important;
+          // background: #cccccc !important;
           position: relative;
         }
 
@@ -580,7 +593,7 @@ export default {
 
     .overview-container {
       .overview {
-        padding: 20px;
+        padding: 16px;
         box-sizing: border-box;
         border-radius: 17px;
         box-shadow: -1px 1px 0px 1px #ececec, 1px -1px 0px 1px #ececec;
@@ -590,8 +603,8 @@ export default {
           justify-content: flex-start;
           align-items: center;
           .overview-top-img {
-            width: 70px;
-            height: 70px;
+            width: 66px;
+            height: 66px;
             border-radius: 50%;
             margin-right: 10px;
             img {
@@ -605,20 +618,21 @@ export default {
             justify-content: center;
             align-items: flex-start;
             .overview-top-content-name {
-              font-size: 20px;
+              font-size: 18px;
               font-weight: 500;
               color: #525252;;
             }
             .overview-top-content-count {
-              font-size: 35px;
+              font-size: 28px;
               font-weight: 500;
               color: #2D80EE;
               line-height: 42px;
+              margin-top: 8px;
             }
           }
         }
         .el-divider {
-          margin: 20px 0;
+          margin: 12px 0;
         }
         .overview-bottom {
           display: grid;
@@ -628,14 +642,15 @@ export default {
             display: flex;
             justify-content: flex-start;
             align-items: center;
+            cursor: pointer;
             .overview-bottom-item-name {
-              font-size: 20px;
+              font-size: 16px;
               font-weight: 400;
               color: #7a7a7a;
               margin-right: 30px;
             }
             .overview-bottom-item-count {
-              font-size: 20px;
+              font-size: 16px;
               font-weight: 400;
               color: #303133;
             }
@@ -646,7 +661,7 @@ export default {
 
     .portal {
       .portal-item {
-        margin-bottom: 20px;
+        margin-bottom: 12px;
         .portal-item-content {
           display: flex;
           justify-content: flex-start;
@@ -749,7 +764,18 @@ export default {
   }
 }
 .mt-20 {
-  margin-top: 20px;
+  margin-top: 16px;
+}
+
+.box-col {
+  height: 100%;
+}
+
+.box-card {
+  height: 100%;
+  ::v-deep .el-card__body {
+    padding: 12px;
+  }
 }
 
 /* 通知公告样式 */
@@ -757,6 +783,10 @@ export default {
   margin-top: 16px;
 }
 
+.no-notification {
+
+}
+
 .notification-item {
   display: flex;
   align-items: center;
@@ -768,9 +798,9 @@ export default {
 }
 
 .notification-dot {
-  width: 8px;
-  height: 8px;
-  background-color: #1890ff;
+  width: 15px;
+  height: 15px;
+  background-color: #a6ccff;;
   border-radius: 50%;
   margin-right: 12px;
   margin-top: 5px;
@@ -796,7 +826,8 @@ export default {
   white-space: nowrap;
   overflow: hidden;
   text-overflow: ellipsis;
-  flex-shrink: 0;
+  flex-shrink: 1;
+  max-width: 200px;
 }
 
 .notification-info {