duy 3 өдөр өмнө
parent
commit
30e23bd82b

+ 1 - 1
public/version.json

@@ -1,3 +1,3 @@
 {
-  "value": "20251208165809"
+  "value": "20251210125321"
 }

+ 19 - 1
src/api/exctab/exceltab.js

@@ -96,4 +96,22 @@ export const getTempExcelFileUrl= (form) => {
     method: 'post',
     data:form
   })
-}
+}
+
+//查看清表模板下的表格
+export const getWbsTreeExcelTab = (params) => {
+  return request({
+    url: '/api/blade-manager/exceltab/getWbsTreeExcelTab',
+    method: 'get',
+    params:params
+  })
+}
+
+// 批量保存表单
+export const saveBatchWbsTree= (form) => {
+  return request({
+    url: '/api/blade-manager/wbsTree/saveBatchWbsTree',
+    method: 'post',
+    data:form
+  })
+}

+ 39 - 66
src/components/table-sort/index.vue

@@ -1,65 +1,36 @@
 <template>
-  <el-dialog
-    title="合同段排序"
-    :visible.sync="visible"
-    width="600px"
-    append-to-body
-    @close="handleClose"
-    class="project-dialog"
-  >  
-  <span slot="title">
-            <i class="el-icon-sort" style="color: #2550A2;margin-right: 5px;"></i>{{ title }}
+  <el-dialog title="合同段排序" :visible.sync="visible" width="600px" append-to-body @close="handleClose"
+    class="project-dialog">
+    <span slot="title">
+      <i class="el-icon-sort" style="color: #2550A2;margin-right: 5px;"></i>{{ title }}
     </span>
     <div class="sort-container">
       <!-- 提示信息 -->
       <div class="tip-box">
         <i class="el-icon-info"></i>
-             拖动项目可调整顺序,或者使用箭头按钮、输入序号进行排序
+        拖动项目可调整顺序,或者使用箭头按钮、输入序号进行排序
 
       </div>
 
       <!-- 排序列表 -->
-      <draggable 
-        v-model="sortList" 
-        class="sort-list"
-        handle=".drag-handle"
-        @end="handleDragEnd"
-      >
-        <div v-for="(item, index) in sortList" 
-          :key="item.id" 
-          class="sort-item"
-        >
+      <draggable v-model="sortList" class="sort-list" handle=".drag-handle" @end="handleDragEnd">
+        <div v-for="(item, index) in sortList" :key="item.id" class="sort-item">
           <i class="el-icon-rank drag-handle"></i>
           <div class="item-content">
             <span>{{ item.name }}</span>
 
             <div class="item-actions">
-                <div class="move-btns">
-                    <el-button 
-                    type="text" 
-                    icon="el-icon-arrow-up"
-                    :disabled="index === 0"
-                    @click="moveItem(index, -1)"
-                    ></el-button>
-                    <el-button 
-                    type="text" 
-                    icon="el-icon-arrow-down"
-                    :disabled="index === sortList.length - 1"
-                    @click="moveItem(index, 1)"
-                    ></el-button>
-                </div>
-                <span>移至</span>
-              <el-input-number 
-              :controls="false"
-                v-model="item.sortNum" 
-                :min="1" 
-                :max="sortList.length"
-                size="mini"
-                style="width: 60px;"
-                @change="handleNumberChange($event, index)"
-              ></el-input-number>
+              <div class="move-btns">
+                <el-button type="text" icon="el-icon-arrow-up" :disabled="index === 0"
+                  @click="moveItem(index, -1)"></el-button>
+                <el-button type="text" icon="el-icon-arrow-down" :disabled="index === sortList.length - 1"
+                  @click="moveItem(index, 1)"></el-button>
+              </div>
+              <span>移至</span>
+              <el-input-number :controls="false" v-model="item.sortNum" :min="1" :max="sortList.length" size="mini"
+                style="width: 60px;" @change="handleNumberChange($event, index)"></el-input-number>
               <span>位</span>
-              
+
             </div>
           </div>
         </div>
@@ -68,7 +39,8 @@
 
     <div slot="footer" style="text-align: center">
       <el-button @click="handleClose">取 消</el-button>
-      <el-button type="primary" @click="handleConfirm" style="  background-color: #2550A2;border-color: #2550A2 ;color: white;">确 定</el-button>
+      <el-button type="primary" @click="handleConfirm"
+        style="  background-color: #2550A2;border-color: #2550A2 ;color: white;">确 定</el-button>
     </div>
   </el-dialog>
 </template>
@@ -91,7 +63,7 @@ export default {
       type: Boolean,
       default: false,
     },
-   
+
   },
   data() {
     return {
@@ -101,20 +73,20 @@ export default {
   },
 
   methods: {
-        // 添加显示方法
-     // 修改显示方法
-  show(contractList) {
-    if(!contractList || !Array.isArray(contractList)) {
-      console.warn('contractList must be an array');
-      return;
-    }
-    // 初始化排序列表
-    this.sortList = contractList.map((item, index) => ({
-      ...item,
-      sortNum: index + 1
-    }));
-    this.visible = true;
-  },    // 添加隐藏方法
+    // 添加显示方法
+    // 修改显示方法
+    show(contractList) {
+      if (!contractList || !Array.isArray(contractList)) {
+        console.warn('contractList must be an array');
+        return;
+      }
+      // 初始化排序列表
+      this.sortList = contractList.map((item, index) => ({
+        ...item,
+        sortNum: index + 1
+      }));
+      this.visible = true;
+    },    // 添加隐藏方法
     hide() {
       this.visible = false;
     },
@@ -139,7 +111,7 @@ export default {
     handleNumberChange(value, index) {
       const targetIndex = value - 1;
       if (targetIndex === index) return;
-      
+
       const item = this.sortList.splice(index, 1)[0];
       this.sortList.splice(targetIndex, 0, item);
       this.handleDragEnd();
@@ -166,7 +138,7 @@ export default {
     border-radius: 4px;
     color: #3271FF;
     font-size: 13px;
-    
+
     .el-icon-info {
       margin-right: 5px;
       color: #3271FF;
@@ -176,6 +148,7 @@ export default {
   .sort-list {
     max-height: 500px;
     overflow-y: auto;
+
     .sort-item {
       display: flex;
       align-items: center;
@@ -183,7 +156,7 @@ export default {
       border: 1px solid #EBEEF5;
       margin-bottom: 10px;
       border-radius: 4px;
-      
+
       &:hover {
         background: #f5f7fa;
       }
@@ -209,7 +182,7 @@ export default {
 
         .move-btns {
           display: flex;
-        
+
         }
       }
     }

+ 397 - 0
src/views/manager/wbsinfo/components/ChooseExcelTable.vue

@@ -0,0 +1,397 @@
+<template>
+  <div>
+    <!-- 选择清表表单 -->
+    <el-dialog title="选择表单" class="excel-dialog" :visible.sync="tableDialogVisible" modal-append-to-body append-to-body
+      :close-on-click-modal="false" width="75vw" top="10vh" @closed="cancel">
+      <div class="excel-container">
+        <div class="tree-box">
+          <el-select style="width: 100%" v-model="selectedExcelTemplate.id" placeholder="请选择清表模板"
+            @change="changeTemplate($event)">
+            <el-option v-for="(item, key) in excelTemplateOption" :key="key" :label="item.name" :value="item.id">
+            </el-option>
+          </el-select>
+          <div class="flex" v-if="isShowSearch">
+            <el-input size="small" placeholder="输入关键字搜索" clearable @clear="clearInput" v-model="filterText">
+            </el-input>
+            <el-button size="small" class="mg-l-10" @click="treeFilter">搜索</el-button>
+          </div>
+          <div class="scrollbar">
+            <el-tree v-if="isShowLazyTree" @node-click="handleNodeClickExcel" ref="tree" class="excel-table-tree"
+              :props="treeProps" :data="lazyTreeData" :load="loadNode" lazy node-key="id" accordion
+              :default-expanded-keys="expandedKeys">
+              <template #default="{ node, data }">
+                <span :class="{
+                  'checked-bg': tableMap.has(data.id),
+                  'not-create': tableMap.has(data.id) && tableMap.get(data.id).isCreate > 0
+                }">
+                  {{ node.label }}
+                </span>
+              </template>
+            </el-tree>
+            <el-tree v-show="isShowAllTree" ref="treeAll" class="excel-table-tree" v-loading="treeLoading"
+              :props="treeProps" :data="allTreeData" @node-click="handleNodeClickExcel" node-key="id"
+              :expand-on-click-node="false" :filter-node-method="filterNode">
+              <template #default="{ node, data }">
+                <span :class="{
+                  'checked-bg': tableMap.has(data.id),
+                  'not-create': tableMap.has(data.id) && tableMap.get(data.id).isCreate > 0
+                }">
+                  {{ node.label }}
+                </span>
+              </template>
+            </el-tree>
+          </div>
+        </div>
+        <div class="table-box">
+          <el-table :data="tableList" height="100%" border style="width: 100%;">
+            <el-table-column prop="excelTabName" label="清表名称" align="center">
+              <template #header>
+                <div style="display: flex;align-items: center;justify-content: center;">
+                  <span style="padding-right: 4px;">清表名称</span>
+                  <el-button type="text" icon="el-icon-sort" class="text-icon"
+                    @click="$refs.tableSortRef.show(tableList)"></el-button>
+                </div>
+              </template>
+            </el-table-column>
+            <el-table-column prop="elementTableName" label="元素表名称" align="center" />
+            <el-table-column prop="tableType" label="表单类型" align="center">
+              <template slot-scope="scope">
+                <el-select v-model="scope.row.tableType" placeholder="请选择">
+                  <el-option v-for="item in tableTypeOption" :key="item.dictKey" :label="item.dictValue"
+                    :value="item.dictKey">
+                  </el-option>
+                </el-select>
+              </template>
+            </el-table-column>
+            <el-table-column prop="tableOwner" label="所属方" align="center">
+              <template slot-scope="scope">
+                <el-select v-model="scope.row.tableOwner" placeholder="请选择">
+                  <el-option v-for="item in ownerTypeOption" :key="item.dictKey" :label="item.dictValue"
+                    :value="item.dictKey">
+                  </el-option>
+                </el-select>
+              </template>
+            </el-table-column>
+            <el-table-column prop="isCreate" label="是否允许创建" align="center">
+              <template slot-scope="scope">
+                <el-tooltip :disabled="!scope.row.isCreate" :content="isCreateTypeOption[scope.row.isCreate]"
+                  placement="top">
+                  <div :class="['tag', scope.row.isCreate ? 'no' : 'yes']">
+                    {{ scope.row.isCreate ? '否' : '是' }}
+                    <i v-if="scope.row.isCreate" class="el-icon-warning"></i>
+                  </div>
+                </el-tooltip>
+              </template>
+            </el-table-column>
+            <el-table-column label="操作" align="center" width="200">
+              <template slot-scope="scope">
+                <el-link type="danger" size="mini" style="margin: 0px" @click="delTable(scope.$index)">删除</el-link>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+      </div>
+      <span slot="footer" class="dialog-footer" style="display: flex; justify-content: center; align-items: center">
+        <el-button @click="cancel()">取 消</el-button>
+        <el-button style="margin-left: 30px" type="primary" @click="save()" :loading="saveBtnLoading">确 定</el-button>
+      </span>
+    </el-dialog>
+    <TableSort ref="tableSortRef" @confirm="sortConfirm"></TableSort>
+  </div>
+</template>
+
+<script>
+import { tabLazytree, tabLazytreeAll } from "@/api/exctab/excelmodel";
+import { getList, getWbsTreeExcelTab, saveBatchWbsTree } from "@/api/exctab/exceltab";
+import { getDictionary } from "@/api/system/dict";
+import TableSort from "@/components/table-sort/index.vue";
+export default {
+  name: 'ChooseExcelTable',
+  props: {
+    nodeId: String,
+    wbsId: String
+  },
+  components: { TableSort },
+  data() {
+    return {
+      tableDialogVisible: false,
+      excelTemplateOption: [], // 清表模版下拉列表数据
+      treeProps: {
+        label: "name",
+        children: "children",
+        isLeaf: "isLeaf",
+      },
+      selectedExcelTemplate: {}, //选中的清表模版
+      isShowSearch: false, // 是否显示搜索框      
+      filterText: "",
+      isShowAllTree: false,
+      isShowLazyTree: false,
+      lazyTreeData: [],
+      allTreeData: [],
+      treeLoading: false,
+      expandedKeys: [],
+      tableList: [], // 清表表格数据
+      ownerTypeOption: [], // 所有者类型下拉列表数据
+      tableTypeOption: [], // 表单类型下拉列表数据
+      isCreateTypeOption: {
+        0: "可以创建",
+        1: "已存在元素表",
+        2: "未创建元素表",
+        3: "未上传清表"
+      }, // 是否允许创建Map
+      saveBtnLoading: false,
+    };
+  },
+  computed: {
+    tableMap() {
+      return new Map(this.tableList.map(t => [t.excelTabId, t]));
+    },
+    checkedSet() {
+      return new Set(this.tableList.map(t => t.excelTabId)) || new Set();
+    }
+  },
+  methods: {
+    async show() {
+      // this.filterText = "";
+      // this.selectedExcelTemplate = {};
+      // this.isShowSearch = false;
+      // this.isShowAllTree = false;
+      // this.isShowLazyTree = false;
+      // this.lazyTreeData = [];
+      // this.allTreeData = [];
+      await this.getExcelTemplateOption();
+      this.tableDialogVisible = true;
+      this.ownerTypeOption = await this.getDictionaryData("owner_type");
+      this.tableTypeOption = await this.getDictionaryData("table_type");
+    },
+    async getExcelTemplateOption() {
+      const { data } = await getList(1, 1000, { parentId: 0 })
+      if (data.code === 200) {
+        this.excelTemplateOption = data.data.records
+      }
+    },
+    async getDictionaryData(key) {
+
+      const res = await getDictionary({ code: key })
+      return res.data.data.map((element) => ({ ...element, dictKey: Number(element.dictKey) }))
+    },
+    changeTemplate(templateId) {
+      // console.log(item, "item");
+      const item = this.excelTemplateOption.find((item) => item.id === templateId);
+      this.expandedKeys = [templateId]
+
+      this.selectedExcelTemplate = { ...item };
+      this.isShowLazyTree = false;
+      this.isShowAllTree = false;
+      this.filterText = "";
+      if (this.selectedExcelTemplate.name != "") {
+        this.lazyTreeData = [];
+        this.addTableData = [];
+        this.isShowSearch = false;
+        this.$nextTick(() => {
+          this.isShowLazyTree = true;
+        });
+      }
+    },
+    async loadNode(node, resolve) {
+      //懒加载
+      console.log("loadNode", node);
+      if (node.level === 0) {
+        return resolve(await this.getLazyTree(0));
+      } else {
+        return resolve(await this.getLazyTree(node.data.id));
+      }
+    },
+    async getLazyTree(parentId) {
+      //清表树信息
+      const { data: res } = await tabLazytree({
+        parentId: parentId,
+        modeId: this.selectedExcelTemplate.id
+      });
+      console.log(res);
+      if (res.code === 200 && res.msg === "操作成功") {
+        if (res.data.length > 0) {
+          this.isShowSearch = true;
+          res.data.forEach((val) => {
+            val.isLeaf = !val.hasChildren;
+          });
+        }
+        return res.data;
+      } else {
+        return [];
+      }
+    },
+    treeFilter() {
+      if (this.filterText) {
+        this.isShowAllTree = true;
+        this.isShowLazyTree = false;
+        if (!this.allTreeData.length) {
+          this.treeLoading = true;
+          tabLazytreeAll({
+            modeId: this.selectedExcelTemplate.id,
+            name: "",
+          }).then((res) => {
+            this.treeLoading = false;
+            this.allTreeData = res.data.data;
+            this.$nextTick(() => {
+              this.$refs.treeAll.filter(this.filterText);
+            });
+          });
+        } else {
+          this.$refs.treeAll.filter(this.filterText);
+        }
+      } else {
+        this.isShowAllTree = false;
+      }
+    },
+    filterNode(value, data) {
+      if (!value) return true;
+      return data.name.indexOf(value) !== -1;
+    },
+    clearInput() {
+      this.isShowAllTree = false;
+      this.isShowLazyTree = true;
+    },
+    handleNodeClickExcel(data, node) {
+      console.log(data, node);
+      if (data.hasChildren) return
+      if (this.tableList.some(item => item.excelTabId === data.id)) return
+      getWbsTreeExcelTab({ nodeId: this.nodeId, id: data.id }).then((res) => {
+        console.log(res);
+        if (res.data.code === 200) {
+          this.tableList.push({ ...res.data.data, name: res.data.data.elementTableName });
+        }
+      });
+    },
+
+    delTable(index) {
+      this.tableList.splice(index, 1)
+    },
+
+    sortConfirm(list) {
+      this.tableList = list
+    },
+
+    cancel() {
+      this.tableDialogVisible = false;
+      this.tableList = []
+      this.filterText = "";
+      this.selectedExcelTemplate = {};
+      this.isShowSearch = false;
+      this.isShowAllTree = false;
+      this.isShowLazyTree = false;
+      this.lazyTreeData = [];
+      this.allTreeData = [];
+    },
+    async save() {
+      if (this.tableList.length === 0) {
+        this.$message.warning("请选择表格后再提交")
+        return
+      } else if (this.tableList.some(el => el.isCreate)) {
+        this.$message.warning("存在不可创建表单,请检查后重试")
+        return
+      } else if (this.tableList.some(el => !el.tableOwner)) {
+        this.$message.warning("表单所属方数据不能为空,请选择后再提交")
+        return
+      }
+      this.saveBtnLoading = true;
+      const { data } = await saveBatchWbsTree({
+        wbsId: this.wbsId,
+        nodeId: this.nodeId,
+        list: this.tableList
+      })
+      this.saveBtnLoading = false;
+      if (data.code === 200) {
+        this.$message.success("保存成功")
+        this.cancel()
+        this.$emit('confirm')
+      }
+    },
+  },
+};
+</script>
+
+<style scoped lang="scss">
+::v-deep .excel-container {
+  height: 60vh !important;
+  width: 100%;
+  box-sizing: border-box;
+  display: grid;
+  gap: 20px;
+  grid-template-columns: calc(30% - 10px) calc(70% - 10px);
+
+  .tree-box {
+    min-height: 0;
+    height: 100%;
+    width: 100%;
+    display: flex;
+    flex-direction: column;
+    gap: 10px;
+
+    .scrollbar {
+      // flex: 1;
+      overflow: scroll;
+      // height: auto !important;
+    }
+
+    .el-tree-node>.el-tree-node__children{
+      overflow: visible !important;
+    }
+  }
+
+  .table-box {
+    box-sizing: border-box;
+    height: 100%;
+    width: 100%;
+  }
+}
+
+/* 全局样式文件 */
+::v-deep .excel-table-tree .el-tree-node {
+  .checked-bg {
+    background-color: #DCFCE7;
+    padding: 4px;
+  }
+
+  .not-create {
+    background-color: #FEE2E3;
+    padding: 4px;
+  }
+
+  // /* 隐藏所有复选框 */
+  // .el-checkbox {
+  //   display: none;
+  // }
+
+  // /* 只有叶子节点才显示 */
+  // .is-leaf+.el-checkbox {
+  //   display: inline-block;
+  // }
+}
+
+.tag {
+  display: block;
+  padding: 6px;
+  border-radius: 18px;
+  width: 60px;
+  margin: 0 auto;
+  position: relative;
+
+  &.yes {
+    background-color: #DCFCE7;
+    color: #16A34A
+  }
+
+  &.no {
+    background-color: #FEE2E3;
+    color: #E14247
+  }
+
+  .el-icon-warning {
+    position: absolute;
+    top: 4px;
+    right: 10px;
+    font-size: 12px;
+  }
+}
+</style>

+ 0 - 0
src/views/manager/wbsinfo/PublicWbs.vue → src/views/manager/wbsinfo/components/PublicWbs.vue


+ 0 - 0
src/views/manager/wbsinfo/TreeCopyModal.vue → src/views/manager/wbsinfo/components/TreeCopyModal.vue


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 149 - 593
src/views/manager/wbsinfo/edit.vue


+ 1 - 1
src/views/manager/wbsinfo/element.vue

@@ -319,7 +319,7 @@ import { getTableElments } from "@/api/manager/wbstree";
 import { tabTypeLazyTreeAll, delTabInfoAll } from "@/api/manager/wbsprivate";
 import { saveElement, remove as removeElement, updateBatchElements, getTemplate, importWbsElement } from "@/api/manager/wbsformelement";
 import FormulaEdit from "@/views/formula/edit1.vue";
-import PublicWbs from './PublicWbs.vue'
+import PublicWbs from './components/PublicWbs.vue'
 import { searchNodeTables, } from "@/api/exctab/excelmodel";
 import { wbsInfotabSort } from "@/api/manager/wbsinfo";
 import { getDictionary } from "@/api/system/dict";

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно