iZaiZaiA 2 years ago
parent
commit
f0141c1a24

+ 41 - 0
src/api/modules/data-fill/query.js

@@ -49,4 +49,45 @@ export default {
             params: form
         })
     },
+    //批量下载
+    async batchDownloadFileToZip(form) {
+        return request({
+            url: '/api/blade-business/informationWriteQuery/batchDownloadFileToZip',
+            method: 'post',
+            params: form,
+            responseType: 'blob'
+        })
+    },
+    //批量打印
+    async batchPrint(form) {
+        return request({
+            url: '/api/blade-business/informationWriteQuery/batchPrint',
+            method: 'post',
+            params: form
+        })
+    },
+    //本地验签
+    async localVerify(form) {
+        return request({
+            url: '/api/blade-business/informationWriteQuery/localVerify',
+            method: 'post',
+            params: form
+        })
+    },
+    //在线验签
+    async onlineVerify(form) {
+        return request({
+            url: '/api/blade-business/informationWriteQuery/onlineVerify',
+            method: 'post',
+            params: form
+        })
+    },
+    //输入框查询合同段树
+    async searchContractTree(form) {
+        return request({
+            url: '/api/blade-business/informationWriteQuery/searchContractTree',
+            method: 'get',
+            params: form
+        })
+    },
 }

+ 88 - 0
src/api/modules/data-fill/wbs.js

@@ -97,5 +97,93 @@ export default {
             data: form
         });
     },
+    //获取表单数据
+    async getBussDataInfo(form) {
+        return request({
+            url: '/api/blade-manager/exceltab/get-buss-dataInfo',
+            method: 'get',
+            params: form
+        });
+    },
+    //查询节点状态
+    async queryNodeStatus(form) {
+        return request({
+            url: '/api/blade-business/informationWriteQuery/queryNodeStatus',
+            method: 'post',
+            params: form
+        });
+    },
+    //单个废除
+    async abolishOne(form) {
+        return request({
+            url: '/api/blade-business/informationWriteQuery/abolishOne',
+            method: 'post',
+            params: form
+        });
+    },
+    //隐藏表单
+    async showBussTab(form) {
+        return request({
+            url: '/api/blade-manager/exceltab/show-buss-tab',
+            method: 'get',
+            params: form
+        });
+    },
+    //单表pdf预览
+    async getBussPdfInfo(form) {
+        return request({
+            url: '/api/blade-manager/exceltab/get-buss-pdfInfo',
+            method: 'get',
+            params: form
+        });
+    },
+    //表单复制
+    async copeBussTab(form) {
+        return request({
+            url: '/api/blade-manager/exceltab/cope-buss-tab',
+            method: 'get',
+            params: form
+        });
+    },
+    //多表预览
+    async getBussPdfs(form) {
+        return request({
+            url: '/api/blade-manager/exceltab/get-buss-pdfs',
+            method: 'get',
+            params: form
+        });
+    },
+    //获取附件列表
+    async getBussFileList(form) {
+        return request({
+            url: '/api/blade-manager/tablefile/get-buss-fileList',
+            method: 'get',
+            params: form
+        });
+    },
+    //逻辑删除
+    async removeBussFile(form) {
+        return request({
+            url: '/api/blade-manager/tablefile/remove',
+            method: 'post',
+            params: form
+        });
+    },
+    //用户端删除复制信息表
+    async removeBussTabInfo(form) {
+        return request({
+            url: '/api/blade-manager/exceltab/remove-buss-tabInfo',
+            method: 'post',
+            params: form
+        });
+    },
+    //复制节点填报数据
+    async copyContractNodeSubmitBusinessData(form) {
+        return request({
+            url: '/api/blade-business/informationWriteQuery/copyContractNodeSubmitBusinessData',
+            method: 'post',
+            data: form
+        });
+    },
 }
 

+ 8 - 0
src/api/modules/ledger/query.js

@@ -33,4 +33,12 @@ export default {
             params: form
         })
     },
+    //获取合同段当前日志节点下的填报日期记录
+    async getSubmitLogDateList(form) {
+        return request({
+            url: '/api/blade-business/contractLog/getSubmitLogDateList',
+            method: 'post',
+            params: form
+        })
+    },
 }

+ 8 - 0
src/api/modules/other/first-item.js

@@ -17,4 +17,12 @@ export default {
             params: form
         })
     },
+    //分页数据
+    async getQueryPageData(form) {
+        return request({
+            url: '/api/blade-business/informationWriteQuery/page',
+            method: 'post',
+            data: form
+        })
+    },
 }

+ 44 - 0
src/api/modules/schedule/data.js

@@ -0,0 +1,44 @@
+import request from "../../request/index";
+
+export default {
+    //查询内业资料进度
+    async queryMaterialProgress(form) {
+        return request({
+            url: '/api/blade-business/materialProgress/queryMaterialProgress',
+            method: 'post',
+            params: form
+        });
+    },
+    //报表资料审批统计
+    async queryMaterialProgressStatus(form) {
+        return request({
+            url: '/api/blade-business/materialProgress/queryMaterialProgressStatus',
+            method: 'post',
+            params: form
+        });
+    },
+    //声像媒体资料统计
+    async queryImageClassification(form) {
+        return request({
+            url: '/api/blade-business/materialProgress/queryImageClassification',
+            method: 'post',
+            params: form
+        });
+    },
+    //资料进度
+    async queryContractTreeMaterialProgress(form) {
+        return request({
+            url: '/api/blade-business/materialProgress/queryContractTreeMaterialProgress',
+            method: 'post',
+            params: form
+        });
+    },
+    // 内外业进度
+    async queryNeiWaiYeProgress(form) {
+        return request({
+            url: '/api/blade-business/neiWaiYeProgressController/neiWaiYeProgress',
+            method: 'get',
+            params: form
+        });
+    },
+}

+ 1 - 1
src/global/components/hc-new-switch/index.vue

@@ -52,7 +52,7 @@ const switchClick = (item) => {
         color: #838791;
         padding: 2px 12px;
         border-radius: 80px;
-        height: 24px;
+        min-height: 24px;
         &.dots {
             color: #ffffff;
             background: var(--el-color-primary);

+ 31 - 5
src/styles/app/element.scss

@@ -1,12 +1,32 @@
 //饿了么UI组件的样式重绘
-
 .el-button[block] {
     width: 100%;
 }
+//主色
+.el-button--primary.is-link,
+.el-button--primary.is-plain,
+.el-button--primary.is-text {
+    --el-button-border-color: transparent;
+    --el-button-hover-text-color: var(--el-color-primary);
+    --el-button-hover-bg-color: var(--el-color-primary-light-8);
+    --el-button-hover-border-color: transparent;
+}
+//红色
+.el-button--danger.is-link,
+.el-button--danger.is-plain,
+.el-button--danger.is-text {
+    --el-button-border-color: transparent;
+    --el-button-hover-text-color: var(--el-color-danger);
+    --el-button-hover-bg-color: var(--el-color-danger-light-8);
+    --el-button-hover-border-color: transparent;
+}
+.el-button + .el-button {
+    margin-left: 20px;
+}
 
 //单选框、多选框
 .el-checkbox.size-xl .el-checkbox__inner,
-.el-radio.size-xl .el-radio__inner{
+.el-radio.size-xl .el-radio__inner {
     width: 18px;
     height: 18px;
 }
@@ -70,9 +90,6 @@
         margin-right: 4px;
     }
 }
-.el-button + .el-button {
-    margin-left: 20px;
-}
 
 //表单
 .el-form {
@@ -288,3 +305,12 @@
         font-size: 16px;
     }
 }
+
+//弹窗提示
+.el-dialog .el-dialog__body {
+    position: relative;
+    .el-alert {
+        margin-top: -10px;
+        margin-bottom: 20px;
+    }
+}

+ 56 - 8
src/styles/data-fill/wbs.scss

@@ -172,19 +172,53 @@
     display: none;
 }
 
+.lr-dialog-footer {
+    position: relative;
+    display: flex;
+    align-items: flex-end;
+    justify-content: space-between;
+    .left {
+        .el-button + .el-button {
+            margin-left: 10px;
+        }
+    }
+}
+
+.copy-node-many-box {
+    position: relative;
+    height: 53vh;
+    display: flex;
+    margin-top: 24px;
+    margin-bottom: -30px;
+    border-top: 1px solid #efeff5;
+    .copy-node-many-tree {
+        position: relative;
+        flex: 1;
+        height: 100%;
+        padding: 20px 20px 20px 0;
+        border-right: 1px solid #efeff5;
+    }
+    .copy-node-many-table {
+        position: relative;
+        flex: 1;
+        height: 100%;
+        padding: 20px 0 20px 20px;
+    }
+}
+
 .sort-node-body-box.list-group {
     position: relative;
     min-height: 20px;
+    border: 1px solid #EEEEEE;
     .list-group-item {
         position: relative;
         display: flex;
         align-items: center;
-        padding: 6px 0;
+        padding: 6px 15px;
         cursor: move;
         transition: background 0.2s;
         .index-box {
             position: relative;
-            text-align: center;
             width: 50px;
         }
         .title-box {
@@ -195,12 +229,12 @@
         .icon-box {
             position: relative;
             font-size: 18px;
-            i {
+            display: flex;
+            align-items: center;
+            .icon {
                 cursor: pointer;
-                color: var(--hc-primary);
-            }
-            i + i {
-                margin-left: 6px;
+                display: flex;
+                align-items: center;
             }
         }
         &:first-child .icon-box i:last-child,
@@ -209,7 +243,21 @@
             color: #aaaaaa;
         }
         &:hover {
-            background: var(--hc-primary-light-7);
+            background: var(--el-color-primary-light-9);
+        }
+    }
+    .list-group-item + .list-group-item {
+        border-top: 1px solid #EEEEEE;
+    }
+    &.header {
+        border-bottom: 0;
+        .list-group-item {
+            cursor: default;
+            padding: 8px 15px;
+            background-color: #F8F8F8;
+            .index-box, .title-box, .icon-box {
+                font-size: 14px;
+            }
         }
     }
 }

+ 27 - 31
src/views/data-fill/components/HcTreeNode.vue

@@ -1,17 +1,15 @@
 <template>
-    <ElTree class="hc-tree-node-box" ref="ElTreeRef" :props="ElTreeProps" :load="ElTreeLoadNode" :node-key="nodeKey"
-            lazy highlight-current accordion show-checkbox :expand-on-click-node="false" @check="ElTreeCheckChange">
+    <ElTree class="hc-tree-node-box" ref="ElTreeRef" :props="ElTreeProps" :data="ElTreeData" :node-key="nodeKey" highlight-current accordion show-checkbox :expand-on-click-node="false" @check="ElTreeCheckChange">
         <template #default="{ node, data }">
             <div class="custom-tree-node">
                 <div class="label" @dblclick="ElTreeDblClick(data)">
-                    <n-input-group v-if="data.isInputName">
-                        <n-input v-model:value="data.title" size="small" @keyup="keyUpEvent($event,data)"/>
-                        <n-button type="primary" strong secondary size="small" @click="ElTreeBtnClick(data)">
-                            <template #icon>
-                                <i class="_icon-check"/>
-                            </template>
-                        </n-button>
-                    </n-input-group>
+                    <el-input v-model="data.title" size="small" @keyup="keyUpEvent($event,data)" v-if="data.isInputName" @blur="ElTreeBtnClick(data)">
+                        <template #append>
+                            <el-button type="primary" plain size="small" @click="ElTreeBtnClick(data)">
+                                <HcIcon name="done"/>
+                            </el-button>
+                        </template>
+                    </el-input>
                     <span v-else>{{data.title}}</span>
                 </div>
             </div>
@@ -20,8 +18,9 @@
 </template>
 
 <script setup>
-import {nextTick, ref, watch} from "vue";
+import {nextTick, onMounted, ref, watch} from "vue";
 import wbsApi from '~api/data-fill/wbs';
+import { getArrValue } from "vue-utils-plus"
 //参数
 const props = defineProps({
     projectId: {
@@ -45,7 +44,7 @@ const props = defineProps({
 //变量
 const ElTreeRef = ref(null)
 const projectId = ref(props.projectId)
-const ElTreeProps = ref({label: 'title', children: 'children', isLeaf: 'exsitChild'})
+const ElTreeProps = ref({label: 'title', children: 'children', isLeaf: 'notExsitChild'})
 
 //监听
 watch(() => [
@@ -54,25 +53,25 @@ watch(() => [
     projectId.value = pid
 })
 
+//渲染完成
+onMounted(() => {
+    ElTreeLoadNode()
+})
+
 //事件
 const emit = defineEmits(['check-change'])
 
 //树形结构异步加载数据
-const ElTreeLoadNode = (node, resolve) => {
-    let nodeId = node.level === 0 ? props.oldId || props.nodeId : node.data?.id
-    wbsApi.queryWbsTreePrivateByProjectIdAndId({
+const ElTreeData = ref([])
+const ElTreeLoadNode = async () => {
+    let nodeId = props.oldId || props.nodeId || ''
+    const {data} = await wbsApi.queryWbsTreePrivateByProjectIdAndId({
         id: nodeId,
         projectId: projectId.value
-    }).then(res => {
-        resolve(res?.data?.data || [])
-        nextTick(() => {
-            ElTreeCheckedKeys()
-        })
-    }).catch(() => {
-        resolve([])
-        nextTick(() => {
-            ElTreeCheckedKeys()
-        })
+    })
+    ElTreeData.value = getArrValue(data?.data)
+    await nextTick(() => {
+        ElTreeCheckedKeys()
     })
 }
 
@@ -98,19 +97,16 @@ const ElTreeDblClick = (item) => {
 //回车
 const keyUpEvent = (e,item) => {
     if (e.key === "Enter") {
-        if (!item?.title) {
-            window?.$message?.warning('节点名称不能为空')
-        } else {
-            item.isInputName = false;
-        }
+        ElTreeBtnClick(item)
     }
 }
 //更改节点名称完成
 const ElTreeBtnClick = (item) => {
     if (!item?.title) {
-        window?.$message?.warning('节点名称不能为空')
+        window?.$ElMessage?.warning('节点名称不能为空')
     } else {
         item.isInputName = false;
+        ElTreeCheckedKeys()
     }
 }
 </script>

+ 150 - 171
src/views/data-fill/components/ListItem.vue

@@ -1,54 +1,39 @@
 <template>
     <div class="data-fill-list-box">
-        <n-collapse accordion @update:expanded-names="updateExpandedNames">
+        <el-collapse v-model="activeName" accordion>
             <template v-for="(item,index) in listDatas" :key="item?.pkeyId">
-                <n-collapse-item display-directive="show" :id="`item-${index}-${item?.pkeyId}`" :name="`item-${index}-${item?.pkeyId}`">
-                    <template #header>
-                        <div class="text-lg truncate item-title">{{item.name}}</div>
-                    </template>
-                    <template #header-extra>
-                        <div class="flex items-center hc-extra-text-box">
-                            <n-popover trigger="hover" :disabled="!bubbleVal || !btn_copy_table?.textInfo" v-if="btn_copy_table">
-                                <template #trigger>
-                                    <div class="text-main extra-text-item" @click.stop="copyClick(item,index)">
-                                        <i class="hcicon-a-Frame3"/>
-                                        <span class="ml-1">复制本表</span>
-                                    </div>
-                                </template>
-                                <span>{{btn_copy_table?.textInfo}}</span>
-                            </n-popover>
-                            <n-popover trigger="hover" :disabled="!bubbleVal || !btn_hide_table?.textInfo" v-if="btn_hide_table">
-                                <template #trigger>
-                                    <div class="text-gray-400 ml-8 extra-text-item" @click.stop="hideClick(item,index)">
-                                        <i class="hcicon-a-Frame4"/>
-                                        <span class="ml-1">隐藏本表</span>
-                                    </div>
-                                </template>
-                                <span>{{btn_hide_table?.textInfo}}</span>
-                            </n-popover>
-                            <n-popover trigger="hover" :disabled="!bubbleVal || !btn_pre_table?.textInfo" v-if="btn_pre_table">
-                                <template #trigger>
-                                    <div class="text-gray-400 ml-8 extra-text-item" @click.stop="previewClick(item,index)">
-                                        <i class="hcicon-Frame"/>
-                                        <span class="ml-1">预览</span>
-                                    </div>
-                                </template>
-                                <span>{{btn_pre_table?.textInfo}}</span>
-                            </n-popover>
-                            <n-popover trigger="hover" :disabled="!bubbleVal || !btn_up_table?.textInfo" v-if="btn_up_table">
-                                <template #trigger>
-                                    <div class="text-main ml-8 extra-text-item" @click.stop="uploadClick(item,index)">
-                                        <i class="hcicon-shangchuan"/>
-                                        <span class="ml-1">上传</span>
-                                    </div>
-                                </template>
-                                <span>{{btn_up_table?.textInfo}}</span>
-                            </n-popover>
+                <el-collapse-item :name="`item-${index}-${item?.pkeyId}`" :disabled="item?.isBussShow == 2" :id="`item-${index}-${item?.pkeyId}`">
+                    <template #title>
+                        <div class="hc-collapse-item-header">
+                            <div class="text-lg truncate item-title">{{item.deptName}}</div>
+                            <div class="hc-extra-text-box">
+                                <el-tooltip :content="btn_del_table?.textInfo" placement="top" :disabled="!bubbleVal || !btn_del_table?.textInfo" v-if="btn_del_table && item?.isCopeTab === 2">
+                                    <el-button type="danger" plain :disabled="item?.isBussShow == 2" @click.stop="delClick(item,index)">删除本表</el-button>
+                                </el-tooltip>
+                                <el-tooltip :content="btn_copy_table?.textInfo" placement="top" :disabled="!bubbleVal || !btn_copy_table?.textInfo" v-if="btn_copy_table">
+                                    <el-button type="primary" plain :disabled="item?.isBussShow == 2" @click.stop="copyClick(item,index)">复制本表</el-button>
+                                </el-tooltip>
+                                <el-tooltip :content="btn_hide_table?.textInfo" placement="top" :disabled="!bubbleVal || !btn_hide_table?.textInfo" v-if="btn_hide_table">
+                                    <el-button type="primary" plain @click.stop="hideClick(item,index)">
+                                        <template v-if="item?.isBussShow == 1">隐藏本表</template>
+                                        <template v-else>显示本表</template>
+                                    </el-button>
+                                </el-tooltip>
+                                <el-tooltip :content="btn_pre_table?.textInfo" placement="top" :disabled="!bubbleVal || !btn_pre_table?.textInfo" v-if="btn_pre_table">
+                                    <el-button type="primary" plain :disabled="item?.isBussShow == 2 || item?.isTabPdf === 1" @click.stop="previewClick(item,index)">预览</el-button>
+                                </el-tooltip>
+                                <el-tooltip :content="btn_up_table?.textInfo" placement="top" :disabled="!bubbleVal || !btn_up_table?.textInfo" v-if="btn_up_table">
+                                    <el-button :type="item?.tabFileType === 2?'success':'primary'" plain :disabled="item?.isBussShow == 2" @click.stop="uploadClick(item,index)">
+                                        <template v-if="item?.tabFileType === 2">已上传</template>
+                                        <template v-else>上传</template>
+                                    </el-button>
+                                </el-tooltip>
+                            </div>
                         </div>
                     </template>
                     <div class="data-fill-list-item-content">
                         <div class="data-fill-table-form-box">
-                            <div :id="`table-form-${item?.pkeyId}`"></div>
+                            <div :id="`table-form-${item?.pkeyId}`"/>
                             <div class="hc-no-table-form" v-if="item?.isTableForm === false">
                                 <div class="table-form-no">
                                     <img :src="notableform" alt=""/>
@@ -58,104 +43,48 @@
                         </div>
                         <div class="data-fill-table-tip-box">
                             <div class="text-orange tip-title">
-                                <i class="_icon-info-o"/>
+                                <HcIcon name="error" fill ui="text-2xl"/>
                                 <span class="ml-1">提示</span>
                             </div>
                             <div class="text-gray-400 tip-item">1、灰色框代表可通过系统识别计算,公式自动引用,可通过公式计算少量数据,(表头数据及简单),也可只填写白色框数据</div>
                             <div class="text-gray-400 tip-item">2、系统支持键盘中,shift + tab键向上一个填报框切换,tab向下一个填报框切换。暂不支持上下按键切换输入框</div>
                             <div class="table-tip-foot">
                                 <div class="tip-left-btn">
-                                    <n-popover trigger="hover" :disabled="!bubbleVal || !btn_impo_table?.textInfo" v-if="btn_impo_table">
-                                        <template #trigger>
-                                            <div class="text-gray-400 dow-text">
-                                                <i class="hcicon-Frame1"/>
-                                                <span class="ml-1">导入列表数据</span>
-                                            </div>
-                                        </template>
-                                        <span>{{btn_impo_table?.textInfo}}</span>
-                                    </n-popover>
-                                    <n-popover trigger="hover" :disabled="!bubbleVal || !btn_down_table?.textInfo" v-if="btn_down_table">
-                                        <template #trigger>
-                                            <div class="text-main dow-text">
-                                                <i class="hcicon-a-Frame11"/>
-                                                <span class="ml-1">下载导入模板</span>
-                                            </div>
-                                        </template>
-                                        <span>{{btn_down_table?.textInfo}}</span>
-                                    </n-popover>
+                                    <el-tooltip :content="btn_impo_table?.textInfo" placement="top" :disabled="!bubbleVal || !btn_impo_table?.textInfo" v-if="btn_impo_table">
+                                        <div class="text-gray-400 dow-text">
+                                            <HcIcon name="publish" ui="text-lg"/>
+                                            <span class="ml-1">导入列表数据</span>
+                                        </div>
+                                    </el-tooltip>
+                                    <el-tooltip :content="btn_down_table?.textInfo" placement="top" :disabled="!bubbleVal || !btn_down_table?.textInfo" v-if="btn_down_table">
+                                        <div class="text-main dow-text">
+                                            <HcIcon name="file_download" ui="text-lg"/>
+                                            <span class="ml-1">下载导入模板</span>
+                                        </div>
+                                    </el-tooltip>
                                 </div>
                                 <div class="tip-right-btn">
-                                    <n-popover trigger="hover" :disabled="!bubbleVal || !btn_save_table?.textInfo" v-if="btn_save_table">
-                                        <template #trigger>
-                                            <n-button type="primary" strong secondary size="large" @click="tableFormSaveClick(item,index)">保存</n-button>
-                                        </template>
-                                        <span>{{btn_save_table?.textInfo}}</span>
-                                    </n-popover>
+                                    <el-tooltip :content="btn_save_table?.textInfo" placement="top" :disabled="!bubbleVal || !btn_save_table?.textInfo" v-if="btn_save_table">
+                                        <el-button type="primary" hc-btn size="large" @click="tableFormSaveClick(item,index)">保存</el-button>
+                                    </el-tooltip>
                                 </div>
                             </div>
                         </div>
                     </div>
-                </n-collapse-item>
+                </el-collapse-item>
             </template>
-        </n-collapse>
+        </el-collapse>
     </div>
-    <!--鼠标右键菜单-->
-    <n-dropdown placement="bottom" inverted trigger="manual" :x="tableFormMenuX" :y="tableFormMenuY" size="huge" :options="tableFormMenu" :show="tableFormMenuShow" @clickoutside="onClickoutside" @select="handleMenuSelect"/>
-    <!--插入设计值/频率-->
-    <n-modal v-model:show="IDVFModal" class="hc-custom-card" title="插入设计值/频率" preset="card" style="width: 600px;" :segmented="{content: 'soft', footer: 'soft'}">
-        <div class="text-base mb-6 ml-16 pl-1">填写完设计值和频率,系统自动计算实测值</div>
-        <n-form ref="formIDVFRef" :model="formIDVFModel" :rules="formIDVFRules" label-placement="left" label-width="auto" size="large">
-            <n-form-item label="设计值" path="designValue">
-                <n-input v-model:value="formIDVFModel.designValue" placeholder="请输入设计值"/>
-            </n-form-item>
-            <n-form-item label="频率" path="frequency">
-                <n-input v-model:value="formIDVFModel.frequency" placeholder="请输入频率"/>
-            </n-form-item>
-        </n-form>
-        <template #footer>
-            <div class="text-center">
-                <n-button @click="IDVFModal = false">取消</n-button>
-                <n-button type="primary" class="ml-6">确认插入</n-button>
-            </div>
-        </template>
-    </n-modal>
-    <!--插入特殊字符-->
-    <n-modal v-model:show="specialModal" class="hc-custom-card" title="插入特殊字符" preset="card" style="width: 600px;" :segmented="{content: 'soft', footer: 'soft'}">
-        <n-input ref="specialRef" id="specialId" class="font-EUDC mb-6" v-model:value="specialValue" size="large" placeholder="请选择特殊字符代码" clearable autofocus/>
-        <n-grid :x-gap="10" :y-gap="10" :cols="8">
-            <n-grid-item v-for="item in specialCharacters" :key="item">
-                <div class="special-box" @click="specialClick">
-                    <span class="font-EUDC" :title="`字符代码(C):${item !== 'K̅'?item.slice(2,7):'K̅'}`" v-html="item"/>
-                </div>
-            </n-grid-item>
-        </n-grid>
-        <template #footer>
-            <div class="text-center">
-                <n-button @click="specialModal = false">取消</n-button>
-                <n-button type="primary" class="ml-6" @click="specialNodeClick">确认插入</n-button>
-            </div>
-        </template>
-    </n-modal>
-    <!--关联试验数据-->
-    <n-modal v-model:show="CTDModal" class="hc-custom-card" title="关联试验数据" preset="card" style="width: 850px;" :segmented="{content: 'soft', footer: 'soft'}">
-        123456
-        <template #footer>
-            <div class="text-center">
-                <n-button @click="CTDModal = false">取消</n-button>
-                <n-button type="primary" class="ml-6">确认插入</n-button>
-            </div>
-        </template>
-    </n-modal>
 </template>
 
 <script setup>
 import {ref,watch,nextTick} from "vue";
+import {createApp} from "vue/dist/vue.esm-bundler.js";
 import {useAppStore} from "~src/store/index";
+import notableform from '~src/assets/view/notableform.svg';
 import wbsApi from "~api/data-fill/wbs"
+import {isString} from "vue-utils-plus"
 import {ElInput,ElDatePicker} from 'element-plus'
-import {createApp} from "vue/dist/vue.esm-bundler.js";
-import {isString} from "~src/utils/lib/isApp";
-import notableform from '~src/assets/view/notableform.svg';
 
 //初始
 const useAppState = useAppStore()
@@ -198,7 +127,7 @@ watch(() => [
     projectId.value = pid
     contractId.value = cid
     classify.value = classifyVal
-    setFormDataNum(datas)
+    //setFormDataNum(datas)
 })
 
 //获取气泡数据
@@ -210,6 +139,7 @@ const btn_copy_table = ref(getButtonsVal('wbs_copy_table')) //复制本表
 const btn_hide_table = ref(getButtonsVal('wbs_hide_table')) //隐藏本表
 const btn_pre_table = ref(getButtonsVal('wbs_preview_table')) //预览本表
 const btn_up_table = ref(getButtonsVal('wbs_upload_table')) //上传
+const btn_del_table = ref(getButtonsVal('wbs_del_table')) //删除
 
 const btn_down_table = ref(getButtonsVal('wbs_download_table')) //下载导入模板
 const btn_impo_table = ref(getButtonsVal('wbs_import_table')) //导入列表数据
@@ -219,9 +149,12 @@ const btn_save_table = ref(getButtonsVal('wbs_save_table'))//保存本表
 const emit = defineEmits(['uploadTap','itemTap','copyTap','hideTap','previewTap','offsetTop'])
 
 nextTick(() => {
-    setFormDataNum(props.datas)
+    //setFormDataNum(props.datas)
 })
 
+const activeName = ref('')
+
+
 //展开事件
 const updateExpandedNames = (name) => {
     const keys = name.length > 0 ? name[0]:'';
@@ -362,6 +295,22 @@ const tableFormSaveClick = (item,index) => {
     })
 }
 
+//删除本表
+const delClick = (item,index) => {
+    wbsApi.removeBussTabInfo({
+        pkeyid: item.pkeyId,
+        classify: classify.value,
+    }).then(({data}) => {
+        if(data.code === 200) {
+            window?.$message?.success('操作成功')
+            emit('uploadData')
+            emit('delTap', {item,index})
+        } else {
+            window?.$message?.warning(data.msg || '操作失败')
+        }
+    })
+}
+
 //复制本表
 const copyClick = (item,index) => {
     emit('copyTap', {item,index})
@@ -480,22 +429,34 @@ const CTDModal = ref(false)
 <style lang="scss" scoped>
 .data-fill-list-box {
     position: relative;
-    .item-title {
+    .hc-collapse-item-header {
+        flex: 1;
         position: relative;
-        padding-left: 10px;
-        user-select: none;
-    }
-    .hc-extra-text-box .extra-text-item {
-        font-size: 16px;
-        user-select: none;
+        margin-left: 46px;
+        display: flex;
+        align-items: center;
+        .item-title {
+            flex: 1;
+            position: relative;
+            user-select: none;
+            color: #50545E;
+            font-size: 16px;
+            font-weight: 400;
+            cursor: pointer;
+        }
+        .hc-extra-text-box {
+            position: relative;
+            padding-right: 24px;
+        }
     }
     .data-fill-list-item-content {
         position: relative;
         display: flex;
+        height: calc(100vh - 386px);
         .data-fill-table-form-box {
             position: relative;
             padding: 24px 20px;
-            height: calc(100vh - 380px);
+            height: 100%;
             overflow: auto;
             flex: 1;
             .hc-no-table-form {
@@ -520,11 +481,13 @@ const CTDModal = ref(false)
         .data-fill-table-tip-box {
             width: 240px;
             position: relative;
-            border-left: 1px solid #e4e4e4;
+            border-left: 1px solid #E9E9E9;
             padding: 20px 15px 80px;
             .tip-title {
                 font-size: 16px;
                 margin-bottom: 10px;
+                display: flex;
+                align-items: center;
             }
             .tip-item {
                 margin-bottom: 20px;
@@ -541,6 +504,8 @@ const CTDModal = ref(false)
                     flex: 1;
                     .dow-text {
                         cursor: pointer;
+                        display: flex;
+                        align-items: center;
                     }
                 }
             }
@@ -559,8 +524,8 @@ const CTDModal = ref(false)
     user-select: none;
     transition: color .3s, background-color .3s;
     &:hover {
-        color: var(--hc-primary);
-        background-color: var(--hc-primary-light-1);
+        color: var(--el-color-primary);
+        background-color: var(--el-color-primary-light-3);
     }
     .font-EUDC {
         font-size: 30px;
@@ -571,48 +536,62 @@ const CTDModal = ref(false)
 
 <style lang="scss">
 .data-fill-list-box {
-    .n-collapse .n-collapse-item {
-        border: 1px solid #ddd;
-        border-radius: 3px;
-        margin: 0 0 15px;
-        background-color: white;
-        .n-collapse-item__header {
-            padding: 0;
-            transition: color .3s var(--n-bezier), background-color .3s;
-            border-radius: 3px 3px 0 0;
-            .n-collapse-item__header-main {
-                padding: 15px 20px;
-            }
-            .n-collapse-item__header-extra {
-                padding-right: 20px;
-            }
-            &.n-collapse-item__header--active {
-                background-color: #F9F9F9;
-                border-bottom: 1px solid #ddd;
+    .el-collapse {
+        --el-collapse-header-height: 60px;
+        border: 0;
+        .el-collapse-item {
+            margin: 0 0 16px;
+            background-color: #f1f5f8;
+            border: 1px solid #E9E9E9;
+            border-radius: 4px;
+        }
+        .el-collapse-item__header {
+            background-color: transparent;
+            font-weight: 400;
+            border-bottom: 0;
+            cursor: default;
+            font-size: 14px;
+            .el-collapse-item__arrow {
+                position: absolute;
+                color: #50545E;
+                cursor: pointer;
+                left: 20px;
+                margin: 0;
             }
         }
-        .n-collapse-item__content-wrapper .n-collapse-item__content-inner {
-            padding-top: 0;
+        .el-collapse-item.is-active .el-collapse-item__header.is-active {
+            background-color: #E7EEF4;
         }
-    }
-}
-//设置表单样式
-.data-fill-table-form-box {
-    td {
-        padding: 6px;
-        font-family: "EUDC", 宋体, v-sans, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !important;
-        .el-input {
-            background-color: #ffffff !important;
-            border-radius: 3px;
-            .el-input__wrapper {
-                background-color: inherit;
+        .el-collapse-item__wrap {
+            background-color: transparent;
+            border-bottom: 0;
+            .el-collapse-item__content {
+                position: relative;
+                padding-bottom: 0;
+                font-size: 14px;
+                color: #50545E;
+                line-height: initial;
             }
-            .el-input__wrapper.is-focus, .el-input__wrapper:hover {
-                box-shadow: 0 0 0 1.5px var(--el-input-focus-border-color) inset;
-                background-color: #eddac4;
+        }
+    }
+    //设置表单样式
+    .data-fill-table-form-box {
+        td {
+            padding: 6px;
+            font-family: "EUDC", 宋体, v-sans, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !important;
+            .el-input {
+                background-color: #ffffff !important;
+                border-radius: 3px;
+                .el-input__wrapper {
+                    background-color: inherit;
+                }
+                .el-input__wrapper.is-focus, .el-input__wrapper:hover {
+                    box-shadow: 0 0 0 1.5px var(--el-input-focus-border-color) inset;
+                    background-color: #eddac4;
+                }
+                //公式 #dcdcdc
+                //焦点 #eddac4
             }
-            //公式 #dcdcdc
-            //焦点 #eddac4
         }
     }
 }

+ 839 - 0
src/views/data-fill/components/ListItem_bak.vue

@@ -0,0 +1,839 @@
+<template>
+    <div class="data-fill-list-box">
+        <n-collapse accordion :expanded-names="expandedNames" @update:expanded-names="updateExpandedNames">
+            <template v-for="(item,index) in listDatas" :key="item?.pkeyId">
+                <n-collapse-item display-directive="show" :id="`item-${index}-${item?.pkeyId}`" :name="`item-${index}-${item?.pkeyId}`">
+                    <template #header>
+                        <div class="text-lg truncate item-title">{{item.name}}</div>
+                    </template>
+                    <template #header-extra>
+                        <div class="flex items-center hc-extra-text-box">
+                            <n-popover trigger="hover" :disabled="!bubbleVal || !btn_del_table?.textInfo" v-if="btn_del_table && item?.isCopeTab === 2">
+                                <template #trigger>
+                                    <div class="mr-8 text-main extra-text-item" @click.stop="delClick(item,index)">
+                                        <i class="hcicon-a-Frame3"/>
+                                        <span class="ml-1">删除本表</span>
+                                    </div>
+                                </template>
+                                <span>{{btn_del_table?.textInfo}}</span>
+                            </n-popover>
+                            <n-popover trigger="hover" :disabled="!bubbleVal || !btn_copy_table?.textInfo" v-if="btn_copy_table">
+                                <template #trigger>
+                                    <div class="text-gray-400 extra-text-item" v-if="item?.isBussShow == 2" @click.stop>
+                                        <i class="hcicon-a-Frame3"/>
+                                        <span class="ml-1">复制本表</span>
+                                    </div>
+                                    <div class="text-main extra-text-item" v-else @click.stop="copyClick(item,index)">
+                                        <i class="hcicon-a-Frame3"/>
+                                        <span class="ml-1">复制本表</span>
+                                    </div>
+                                </template>
+                                <span>{{btn_copy_table?.textInfo}}</span>
+                            </n-popover>
+                            <n-popover trigger="hover" :disabled="!bubbleVal || !btn_hide_table?.textInfo" v-if="btn_hide_table">
+                                <template #trigger>
+                                    <div class="ml-8 text-main extra-text-item" @click.stop="hideClick(item,index)">
+                                        <template v-if="item?.isBussShow == 1">
+                                            <i class="hcicon-a-Frame4"/>
+                                            <span class="ml-1">隐藏本表</span>
+                                        </template>
+                                        <template v-else>
+                                            <i class="hcicon-zhengkaiyanjing4"/>
+                                            <span class="ml-1">显示本表</span>
+                                        </template>
+                                    </div>
+                                </template>
+                                <span>{{btn_hide_table?.textInfo}}</span>
+                            </n-popover>
+                            <n-popover trigger="hover" :disabled="!bubbleVal || !btn_pre_table?.textInfo" v-if="btn_pre_table">
+                                <template #trigger>
+                                    <div class="ml-8 text-gray-400 extra-text-item" v-if="item?.isBussShow == 2 || item?.isTabPdf === 1" @click.stop>
+                                        <i class="hcicon-Frame"/>
+                                        <span class="ml-1">预览</span>
+                                    </div>
+                                    <div class="ml-8 text-main extra-text-item" v-else @click.stop="previewClick(item,index)">
+                                        <i class="hcicon-Frame"/>
+                                        <span class="ml-1">预览</span>
+                                    </div>
+                                </template>
+                                <span>{{btn_pre_table?.textInfo}}</span>
+                            </n-popover>
+                            <n-popover trigger="hover" :disabled="!bubbleVal || !btn_up_table?.textInfo" v-if="btn_up_table">
+                                <template #trigger>
+                                    <div class="ml-8 text-gray-400 extra-text-item" v-if="item?.isBussShow == 2" @click.stop>
+                                        <i class="hcicon-shangchuan"/>
+                                        <span class="ml-1">上传</span>
+                                    </div>
+                                    <div class="ml-8 extra-text-item" :class="item?.tabFileType === 2?'text-green':'text-main'" v-else @click.stop="uploadClick(item,index)">
+                                        <i class="hcicon-shangchuan"/>
+                                        <span class="ml-1">{{item?.tabFileType === 2?'已上传':'上传' }}</span>
+                                    </div>
+                                </template>
+                                <span>{{btn_up_table?.textInfo}}</span>
+                            </n-popover>
+                        </div>
+                    </template>
+                    <div class="data-fill-list-item-content">
+                        <div class="data-fill-table-form-box">
+                            <div :id="`table-form-${item?.pkeyId}`"></div>
+                            <div class="hc-no-table-form" v-if="item?.isTableForm === false">
+                                <div class="table-form-no">
+                                    <img :src="notableform" alt=""/>
+                                    <div class="desc">暂无表单数据</div>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="data-fill-table-tip-box">
+                            <div class="text-orange tip-title">
+                                <i class="_icon-info-o"/>
+                                <span class="ml-1">提示</span>
+                            </div>
+                            <div class="text-gray-400 tip-item">1、灰色框代表可通过系统识别计算,公式自动引用,可通过公式计算少量数据,(表头数据及简单),也可只填写白色框数据</div>
+                            <div class="text-gray-400 tip-item">2、系统支持键盘中,shift + tab键向上一个填报框切换,tab向下一个填报框切换。暂不支持上下按键切换输入框</div>
+                            <div class="table-tip-foot">
+                                <div class="tip-left-btn">
+                                    <n-popover trigger="hover" :disabled="!bubbleVal || !btn_impo_table?.textInfo" v-if="btn_impo_table">
+                                        <template #trigger>
+                                            <div class="text-gray-400 dow-text">
+                                                <i class="hcicon-Frame1"/>
+                                                <span class="ml-1">导入列表数据</span>
+                                            </div>
+                                        </template>
+                                        <span>{{btn_impo_table?.textInfo}}</span>
+                                    </n-popover>
+                                    <n-popover trigger="hover" :disabled="!bubbleVal || !btn_down_table?.textInfo" v-if="btn_down_table">
+                                        <template #trigger>
+                                            <div class="text-main dow-text">
+                                                <i class="hcicon-a-Frame11"/>
+                                                <span class="ml-1">下载导入模板</span>
+                                            </div>
+                                        </template>
+                                        <span>{{btn_down_table?.textInfo}}</span>
+                                    </n-popover>
+                                </div>
+                                <div class="tip-right-btn">
+                                    <n-popover trigger="hover" :disabled="!bubbleVal || !btn_save_table?.textInfo" v-if="btn_save_table">
+                                        <template #trigger>
+                                            <n-button type="primary" strong secondary size="large" @click="tableFormSaveClick(item,index)">保存</n-button>
+                                        </template>
+                                        <span>{{btn_save_table?.textInfo}}</span>
+                                    </n-popover>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </n-collapse-item>
+            </template>
+        </n-collapse>
+    </div>
+    <!--鼠标右键菜单-->
+    <n-dropdown placement="bottom" inverted trigger="manual" :x="tableFormMenuX" :y="tableFormMenuY" size="huge" :options="tableFormMenu" :show="tableFormMenuShow" @clickoutside="onClickoutside" @select="handleMenuSelect"/>
+    <!--插入设计值/频率-->
+    <n-modal v-model:show="IDVFModal" class="hc-custom-card" title="插入设计值/频率" preset="card" style="width: 600px;" :segmented="{content: 'soft', footer: 'soft'}">
+        <div class="text-base mb-6 ml-16 pl-1">填写完设计值和频率,系统自动计算实测值</div>
+        <n-form ref="formIDVFRef" :model="formIDVFModel" :rules="formIDVFRules" label-placement="left" label-width="auto" size="large">
+            <n-form-item label="设计值" path="designValue">
+                <n-input v-model:value="formIDVFModel.designValue" placeholder="请输入设计值"/>
+            </n-form-item>
+            <n-form-item label="频率" path="frequency">
+                <n-input v-model:value="formIDVFModel.frequency" placeholder="请输入频率"/>
+            </n-form-item>
+        </n-form>
+        <template #footer>
+            <div class="text-center">
+                <n-button @click="IDVFModal = false">取消</n-button>
+                <n-button type="primary" class="ml-6">确认插入</n-button>
+            </div>
+        </template>
+    </n-modal>
+    <!--插入特殊字符-->
+    <n-modal v-model:show="specialModal" class="hc-custom-card" title="插入特殊字符" preset="card" style="width: 600px;" :segmented="{content: 'soft', footer: 'soft'}">
+        <n-input ref="specialRef" id="specialId" class="font-EUDC mb-6" v-model:value="specialValue" size="large" placeholder="请选择特殊字符代码" clearable autofocus/>
+        <n-grid :x-gap="10" :y-gap="10" :cols="8">
+            <n-grid-item v-for="item in specialCharacters" :key="item">
+                <div class="special-box" @click="specialClick">
+                    <span class="font-EUDC" :title="`字符代码(C):${item !== 'K̅'?item.slice(2,7):'K̅'}`" v-html="item"/>
+                </div>
+            </n-grid-item>
+        </n-grid>
+        <template #footer>
+            <div class="text-center">
+                <n-button @click="specialModal = false">取消</n-button>
+                <n-button type="primary" class="ml-6" @click="specialNodeClick">确认插入</n-button>
+            </div>
+        </template>
+    </n-modal>
+    <!--关联试验数据-->
+    <n-modal v-model:show="CTDModal" class="hc-custom-card" title="关联试验数据" preset="card" style="width: 850px;" :segmented="{content: 'soft', footer: 'soft'}">
+        123456
+        <template #footer>
+            <div class="text-center">
+                <n-button @click="CTDModal = false">取消</n-button>
+                <n-button type="primary" class="ml-6">确认插入</n-button>
+            </div>
+        </template>
+    </n-modal>
+    <!--上传文件-->
+    <n-modal v-model:show="uploadModal" class="hc-custom-card w-606" title="上传文件" preset="card" :segmented="{content: 'soft', footer: 'soft'}">
+        <n-upload v-model:file-list="fileListData" :action="action" :headers="getTokenHeader()" :data="addData" :accept="accept" multiple @before-upload="beforeUpload" @finish="uploadFinish" @change="UploadChange" @remove="delUploadData"  @update:file-list="fileListUpdate">
+            <n-button type="primary">选择文件并上传</n-button>
+        </n-upload>
+    </n-modal>
+</template>
+
+<script setup>
+import {ref,watch,nextTick} from "vue";
+import {useAppStore} from "~src/store/index";
+import wbsApi from "~api/data-fill/wbs"
+import {ElInput,ElDatePicker} from 'element-plus'
+import {createApp} from "vue/dist/vue.esm-bundler.js";
+import {isString,isObject} from "~src/utils/lib/isApp";
+import notableform from '~src/assets/view/notableform.svg';
+import {isObjNull} from "../../utils/lib/isApp";
+import {getTokenHeader} from '~src/api/request/header';
+
+//初始
+const useAppState = useAppStore()
+const props = defineProps({
+    datas: {
+        type: Array,
+        default: () => ([])
+    },
+    projectId: {
+        type: [String,Number],
+        default: ''
+    },
+    contractId: {
+        type: [String,Number],
+        default: ''
+    },
+    classify: {
+        type: [String,Number],
+        default: ''
+    },
+})
+
+//按钮气泡开关
+const bubbleVal = ref(useAppState.getBubble);
+const projectId = ref(props.projectId)
+const contractId = ref(props.contractId)
+const listDatas = ref(props.datas)
+const classify = ref(props.classify)
+const expandedNames = ref(null)
+
+//监听
+watch(() => [
+    props.datas,
+    props.projectId,
+    props.contractId,
+    useAppState.getBubble,
+    props.classify,
+], ([datas, pid, cid, Bubble,classifyVal]) => {
+    listDatas.value = datas
+    bubbleVal.value = Bubble
+    projectId.value = pid
+    contractId.value = cid
+    classify.value = classifyVal
+    expandedNames.value = null
+    setFormDataNum(datas)
+})
+
+//获取气泡数据
+const getButtonsVal = (value) => {
+    return useAppState.getButtonsVal(value)
+}
+
+const btn_copy_table = ref(getButtonsVal('wbs_copy_table')) //复制本表
+const btn_hide_table = ref(getButtonsVal('wbs_hide_table')) //隐藏本表
+const btn_pre_table = ref(getButtonsVal('wbs_preview_table')) //预览本表
+const btn_up_table = ref(getButtonsVal('wbs_upload_table')) //上传
+const btn_del_table = ref(getButtonsVal('wbs_del_table')) //删除
+
+const btn_down_table = ref(getButtonsVal('wbs_download_table')) //下载导入模板
+const btn_impo_table = ref(getButtonsVal('wbs_import_table')) //导入列表数据
+const btn_save_table = ref(getButtonsVal('wbs_save_table'))//保存本表
+
+//事件
+const emit = defineEmits(['uploadData','uploadTap','saveTap','itemTap','copyTap','hideTap','previewTap','offsetTop', 'delTap'])
+
+nextTick(() => {
+    setFormDataNum(props.datas)
+})
+
+//渲染模板标签
+const formData = ref([])
+
+//展开事件
+const updateExpandedNames = async (name) => {
+    expandedNames.value = name
+    const keys = name.length > 0 ? name[0]:'';
+    const names = name.length > 0 ? name[0].split('-'): []
+    if (names.length > 0) {
+        getOffsetTop(keys)
+        const index = names[1]
+        const item = listDatas.value[index]
+        if (!item.isTableFormRender) {
+            getExcelHtml(item,index)
+        }
+        //获取已填写的数据
+        const {data: valData} = await wbsApi.getBussDataInfo({pkeyId: item.pkeyId + ''})
+        const valRes = isObject(valData.data) ? valData.data : {}
+        if (!isObjNull(valRes)) {
+            //有数据,关联数据
+            formData.value[index] = {
+                projectId: projectId.value,
+                contractId: contractId.value,
+                pkeyId: item.pkeyId + '',
+                classify: classify.value,
+                ...valRes
+            }
+        } else {
+            formData.value[index] = {
+                projectId: projectId.value,
+                contractId: contractId.value,
+                pkeyId: item.pkeyId + '',
+                classify: classify.value
+            }
+        }
+    } else {
+        emit('offsetTop', {offsetTop: 0, dom: null})
+    }
+}
+
+//获取模板标签数据
+const getExcelHtml = (item,index) => {
+    if (item.pkeyId !== 0) {
+        wbsApi.getExcelHtml({
+            pkeyId: item.pkeyId + ''
+        }).then(({data}) => {
+            const res = isString(data.data)?data.data:''
+            if (res) {
+                item.isTableForm = true
+                HTableForm(res, item, index)
+            } else {
+                item.isTableForm = false
+                window?.$message?.warning(res.msg || '暂无表单')
+            }
+        }).catch(() => {
+            item.isTableForm = false
+        })
+    } else {
+        item.isTableForm = false
+        window?.$message?.warning('pkeyId为空')
+    }
+}
+
+//设置表单对象的数量
+const setFormDataNum = (datas) => {
+    let newArr = [];
+    for (let i = 0; i < datas.length; i++) {
+        newArr.push({
+            projectId: projectId.value,
+            contractId: contractId.value,
+            pkeyId: datas[i].pkeyId + '',
+            classify: classify.value
+        })
+    }
+    formData.value = newArr
+}
+
+//渲染表格表单
+const HTableForm = (templateData,item,index) => {
+    const app = createApp({
+        data() {
+            return {
+                formData: formData.value[index],
+            }
+        },
+        template: templateData,
+        components: {ElInput,ElDatePicker},
+        methods: {
+            RightClick(a,b,c,d,e,f,event) {
+                event.preventDefault();
+                const key = event?.target?.getAttribute('keyname') || ''
+                onRightClick(event,key,index)
+            },
+            getInformation(a,b,c) {
+
+            },
+        }
+    })
+    app.mount(`#table-form-${item.pkeyId}`)
+    item.isTableFormRender = true
+}
+
+//树的菜单相关变量
+const tableFormMenuShow = ref(false)
+const tableFormItemNode = ref({})
+const tableFormMenuX = ref(0);
+const tableFormMenuY = ref(0);
+
+//树的菜单数据
+const tableFormMenu = ref([
+    {label: '插入设计值/频率', key: "IDVF"},
+    {label: '插入特殊字符', key: "special"},
+    {label: '关联试验数据', key: "CTD"},
+])
+
+//鼠标右键事件
+const onRightClick = (event,key,index) => {
+    //取光标位置
+    let specialDom = document.getElementById(key + "");
+    let startPos = specialDom?.selectionStart, endPos = specialDom?.selectionEnd;
+    //存储临时信息
+    tableFormItemNode.value = {key, index, startPos, endPos}
+    //取坐标
+    nextTick().then(() => {
+        tableFormMenuShow.value = true;
+        tableFormMenuX.value = event.clientX;
+        tableFormMenuY.value = event.clientY;
+    });
+}
+
+//鼠标右键菜单被点击
+const handleMenuSelect = (key) => {
+    //const item = tableFormItemNode.value;
+    tableFormMenuShow.value = false;
+    if (key === 'IDVF') {
+        IDVFModal.value = true
+    } else if (key === 'special') {
+        specialModalShow()
+    } else if (key === 'CTD') {
+        CTDModal.value = true
+    }
+}
+
+const onClickoutside = () => {
+    tableFormItemNode.value = {};
+    tableFormMenuShow.value = false;
+}
+
+const saveExcelBussData = async (item,index) => {
+    const {data} = await wbsApi.saveExcelBussData({
+        pkeyId: item.pkeyId,
+        classify: classify.value,
+        ...formData.value[index]
+    })
+    if(data && data.code === 200) {
+        window?.$message?.success('保存成功')
+        return true
+    } else {
+        window?.$message?.warning(data.msg || '保存失败')
+        return false
+    }
+}
+
+//单个保存
+const tableFormSaveClick = async (item,index) => {
+    const res = await saveExcelBussData(item,index)
+    if (res) {
+        getBussPdfInfo(item,index)
+        emit('uploadData')
+        emit('saveTap', {item,index})
+    }
+}
+
+//删除本表
+const delClick = (item,index) => {
+    wbsApi.removeBussTabInfo({
+        pkeyid: item.pkeyId,
+        classify: classify.value,
+    }).then(({data}) => {
+        if(data.code === 200) {
+            window?.$message?.success('操作成功')
+            emit('uploadData')
+            emit('delTap', {item,index})
+        } else {
+            window?.$message?.warning(data.msg || '操作失败')
+        }
+    })
+}
+
+//复制本表
+const copyClick = async (item,index) => {
+    const res = await saveExcelBussData(item,index)
+    if (res) {
+        const {data} = await wbsApi.copeBussTab({pkeyId: item.pkeyId})
+        if(data && data.code === 200) {
+            window?.$message?.success('操作成功')
+            emit('uploadData')
+            emit('copyTap', {item,index})
+        } else {
+            window?.$message?.warning(data.msg || '操作失败')
+        }
+    } else {
+        window?.$message?.warning('复制本表操作失败')
+    }
+}
+
+//隐藏本表
+const hideClick = (item,index) => {
+    //状态(1显示 2隐藏)
+    const isBussShow = item?.isBussShow == 2 ? 1 : 2
+    //发起请求
+    wbsApi.showBussTab({
+        pkeyId: item.pkeyId,
+        status: isBussShow
+    }).then(({data}) => {
+        if(data.code === 200) {
+            window?.$message?.success('操作成功')
+            emit('uploadData')
+            emit('hideTap', {item,index})
+        } else {
+            window?.$message?.warning(data.msg || '操作失败')
+        }
+    })
+}
+
+const getBussPdfInfo = (item,index) => {
+    wbsApi.getBussPdfInfo({
+        pkeyId: item.pkeyId
+    }).then(({data}) => {
+        if(data.code === 200 && data?.data) {
+            window.open(data?.data,'_blank')
+            emit('previewTap', {item,index})
+        } else {
+            window.$message?.warning('暂无PDF')
+        }
+    })
+}
+
+//预览
+const previewClick = async (item,index) => {
+    const res = await saveExcelBussData(item,index)
+    if (res) {
+        getBussPdfInfo(item,index)
+    } else {
+        window?.$message?.warning('操作失败')
+    }
+}
+
+//上传被点击
+const uploadModal = ref(false)
+const addData = ref({})
+const uploadClick = (item) => {
+    addData.value = {
+        projectId: projectId.value,
+        contractId: contractId.value,
+        classify: classify.value,
+        pkeyId: item.pkeyId
+    }
+    uploadModal.value = true
+    //获取文件列表
+    wbsApi.getBussFileList({
+        pkeyid: item.pkeyId
+    }).then(({data}) => {
+        if(data.code === 200) {
+            fileListData.value = isObjNull(data?.data) ? [] : data?.data
+        } else {
+            fileListData.value = []
+        }
+    }).catch(() => {
+        fileListData.value = []
+    })
+}
+//上传组件参数
+const action = '/api/blade-manager/exceltab/add-buss-file';
+const accept = 'image/png,image/jpg,image/jpeg,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.ms-excel,application/pdf,.doc,.docx,application/msword';
+const fileListData = ref([]);
+//上传前
+const uploadLoading = ref(false)
+const beforeUpload = async ({file}) => {
+    let maxTrillion = 60;
+    let fileSizeData = file?.file?.size
+    let maxSize = maxTrillion * 1024 * 1024
+    if (fileSizeData > maxSize) {
+        window.$message?.warning(`文件大小,不能过${maxTrillion}M!`);
+        return false;
+    } else {
+        uploadLoading.value = true
+        return true;
+    }
+}
+//上传完成
+const uploadFinish = ({file,event}) => {
+    uploadLoading.value = false
+    let res = JSON.parse(event?.target?.response);
+    if (res.code === 200) {
+        window.$message?.success('上传成功');
+        uploadModal.value = false
+        emit('uploadData')
+        emit('uploadTap')
+    } else {
+        window.$message?.error('上传失败');
+    }
+}
+
+//列表改变
+const UploadChange = (data) => {
+    fileListData.value = data.fileList;
+}
+const fileListUpdate = (data) => {
+    fileListData.value = data
+}
+//删除
+const delUploadData = async ({file}) => {
+    const {data} = await wbsApi.removeBussFile({ids: file?.id})
+    if(data && data.code === 200) {
+        window.$message?.success('删除成功');
+        emit('uploadData')
+        return true
+    } else {
+        return false
+    }
+}
+
+//被点击
+const getOffsetTop = (key) => {
+    const dom = document.getElementById(key)
+    emit('offsetTop', dom.offsetTop)
+}
+
+//插入设计值/频率
+const IDVFModal = ref(false)
+const formIDVFRef = ref(null)
+const formIDVFModel = ref({
+    designValue: '', frequency: ''
+})
+const formIDVFRules = {
+    designValue: {
+        required: true,
+        trigger: ["blur", "input"],
+        message: "请输入设计值"
+    },
+    frequency: {
+        required: true,
+        trigger: ["blur", "input"],
+        message: "请输入频率"
+    }
+}
+
+//插入特殊字符
+const specialModal = ref(false)
+const specialCharacters = ref([
+    '&#57344;', "&#57345;", "&#57346;", "&#57347;", '&#8804;', '&#8805;', '&#8451;',
+    '&#9312;', '&#9313;', '&#9314;', '&#9315;', '&#9316;', '&#9317;', '&#9318;', '&#9319;', '&#9320;', '&#9321;', '&#9322;', '&#9323;',
+    '&#9324;', '&#9325;', '&#9326;', '&#9327;', '&#9328;', '&#9329;', '&#9330;', '&#9331;',
+    "&#8544;", "&#8545;", "&#8546;", "&#8547;", "&#8548;", "&#8549;", "&#8550;", "&#8551;", "&#8552;", "&#8553;", "&#8554;", "&#8555;","K̅"
+])
+const specialRef = ref(null)
+const specialValue = ref('')
+const specialModalShow = () => {
+    specialValue.value = ''
+    specialModal.value = true
+    nextTick(() => {
+        specialRef.value?.focus();
+    })
+}
+const specialClick = (event) => {
+    inputInsertValue("specialId", event.target.innerText)
+}
+//输入框插入内容
+const inputInsertValue = (Id,val) => {
+    let specialDom = document.getElementById(Id + "").getElementsByTagName('input')[0];
+    let startPos = specialDom?.selectionStart, endPos = specialDom?.selectionEnd;
+    if (startPos || startPos === 0) {
+        let specialVal = specialValue.value;
+        specialValue.value = specialVal.substring(0, startPos) + val + specialVal.substring(endPos, specialVal.length)
+        specialDom?.focus();
+        //设置光标位置
+        let posVal = startPos + val.length;
+        nextTick(() => {
+            specialDom?.setSelectionRange(posVal,posVal)
+        })
+    } else {
+        specialValue.value += val;
+        specialDom?.focus();
+    }
+}
+
+//插入内容
+const inputPosInsert = (dom, startPos = 0, endPos = 0, special, value) => {
+    let val = value || '', specialVal = special || ''
+    console.log(startPos,endPos)
+    if(startPos === 0 && endPos === 0) {
+        val = specialVal;
+        dom?.focus();
+    } else if (startPos !== 0 && endPos !== 0) {
+        val = val.substring(0, startPos) + specialVal + val.substring(endPos, val.length)
+        dom?.focus();
+        //设置光标位置
+        let posVal = startPos + specialVal.length;
+        nextTick(() => {
+            dom?.setSelectionRange(posVal,posVal)
+        })
+    } else {
+        val += specialVal;
+        dom?.focus();
+    }
+    return val
+}
+
+//确认插入
+const specialNodeClick = () => {
+    const item = tableFormItemNode.value;
+    const form = formData.value[item.index]
+    let keyDom = document.getElementById(item.key);
+    const res = inputPosInsert(keyDom,item.startPos,item.endPos,specialValue.value,form[item.key])
+    console.log(res)
+    formData.value[item.index][item.key] = res
+    specialModal.value = false
+}
+
+//关联试验数据
+const CTDModal = ref(false)
+
+//获取表单数据
+const getFormData = () => {
+    console.log(formData.value)
+    return formData.value
+}
+
+// 暴露出去
+defineExpose({
+    getFormData
+})
+</script>
+
+<style lang="scss" scoped>
+@import "../../styles/EUDC/index";
+
+.data-fill-list-box {
+    position: relative;
+    .item-title {
+        position: relative;
+        padding-left: 10px;
+        user-select: none;
+    }
+    .hc-extra-text-box .extra-text-item {
+        font-size: 16px;
+        user-select: none;
+    }
+    .data-fill-list-item-content {
+        position: relative;
+        display: flex;
+        .data-fill-table-form-box {
+            position: relative;
+            padding: 24px 20px;
+            height: calc(100vh - 380px);
+            overflow: auto;
+            flex: 1;
+            .hc-no-table-form {
+                position: relative;
+                height: 100%;
+                display: flex;
+                justify-content: center;
+                align-items: center;
+                .table-form-no {
+                    position: relative;
+                    img {
+                        width: 350px;
+                    }
+                    .desc {
+                        text-align: center;
+                        font-size: 20px;
+                        color: #aaa;
+                    }
+                }
+            }
+        }
+        .data-fill-table-tip-box {
+            width: 240px;
+            position: relative;
+            border-left: 1px solid #e4e4e4;
+            padding: 20px 15px 80px;
+            .tip-title {
+                font-size: 16px;
+                margin-bottom: 10px;
+            }
+            .tip-item {
+                margin-bottom: 20px;
+            }
+            .table-tip-foot {
+                position: absolute;
+                bottom: 15px;
+                right: 0;
+                left: 0;
+                display: flex;
+                align-items: center;
+                padding: 0 15px;
+                .tip-left-btn {
+                    flex: 1;
+                    .dow-text {
+                        cursor: pointer;
+                    }
+                }
+            }
+        }
+    }
+}
+.special-box {
+    position: relative;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    border: 1px solid #eee;
+    border-radius: 3px;
+    height: 60px;
+    cursor: default;
+    user-select: none;
+    transition: color .3s, background-color .3s;
+    &:hover {
+        color: var(--hc-primary);
+        background-color: var(--hc-primary-light-1);
+    }
+    .font-EUDC {
+        font-size: 30px;
+        cursor: default;
+    }
+}
+</style>
+
+<style lang="scss">
+.data-fill-list-box {
+    .n-collapse .n-collapse-item {
+        border: 1px solid #ddd;
+        border-radius: 3px;
+        margin: 0 0 15px;
+        background-color: white;
+        .n-collapse-item__header {
+            padding: 0;
+            transition: color .3s var(--n-bezier), background-color .3s;
+            border-radius: 3px 3px 0 0;
+            .n-collapse-item__header-main {
+                padding: 15px 20px;
+            }
+            .n-collapse-item__header-extra {
+                padding-right: 20px;
+            }
+            &.n-collapse-item__header--active {
+                background-color: #F9F9F9;
+                border-bottom: 1px solid #ddd;
+            }
+        }
+        .n-collapse-item__content-wrapper .n-collapse-item__content-inner {
+            padding-top: 0;
+        }
+    }
+}
+//设置表单样式
+.data-fill-table-form-box {
+    td {
+        padding: 6px;
+        font-family: "EUDC", 宋体, v-sans, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !important;
+        .el-input {
+            background-color: #ffffff !important;
+            border-radius: 3px;
+            .el-input__wrapper {
+                background-color: inherit;
+            }
+            .el-input__wrapper.is-focus, .el-input__wrapper:hover {
+                box-shadow: 0 0 0 1.5px var(--el-input-focus-border-color) inset;
+                background-color: #eddac4;
+            }
+            //公式 #dcdcdc
+            //焦点 #eddac4
+        }
+    }
+}
+</style>

+ 21 - 5
src/views/data-fill/components/WbsTree.vue

@@ -2,10 +2,11 @@
     <ElTree class="hc-tree-node" ref="ElTreeRef" :props="ElTreeProps" :load="ElTreeLoadNode" lazy highlight-current accordion node-key="primaryKeyId"
             :default-expanded-keys="defaultExpandedCids" @node-click="ElTreeClick" @node-contextmenu="ElTreeLabelContextMenu">
         <template #default="{ node, data }">
-            <div class="data-custom-tree-node" :id="`wbs-tree-${data['primaryKeyId']}`">
+            <div class="data-custom-tree-node" :id="`${idPrefix}${data['primaryKeyId']}`">
                 <!--树组件,节点名称-->
                 <div class="label" :class="node.level === 1?'level-name':''">
-                    <span :class="data?.colorStatus === 2?'text-blue':data?.colorStatus === 3?'text-orange':data?.colorStatus === 4?'text-green':''">{{ node.label }}</span>
+                    <span :class="data?.colorStatus === 2?'text-blue':data?.colorStatus === 3?'text-orange':data?.colorStatus === 4?'text-green':''" v-if="isColor">{{ node.label }}</span>
+                    <span v-else>{{ node.label }}</span>
                 </div>
                 <!--树组件,操作菜单-->
                 <div class="menu-icon" :class="node.showTreeMenu?'show':''" v-if="node.level !== 1 && menusData.length > 0" @click.stop>
@@ -51,10 +52,22 @@ const props = defineProps({
         type: Boolean,
         default: false
     },
+    idPrefix: {
+        type: String,
+        default: '`wbs-tree-'
+    },
     isAutoKeys: {
         type: Boolean,
         default: true
     },
+    isAutoClick: {
+        type: Boolean,
+        default: true
+    },
+    isColor: {
+        type: Boolean,
+        default: false
+    },
 })
 
 //变量
@@ -76,6 +89,7 @@ const isAutoKeys = ref(props.isAutoKeys)
 const TreeExpandKey = ref(props.autoExpandKeys)
 const projectId = ref(props.projectId);
 const contractId = ref(props.contractId);
+const idPrefix = ref(props.idPrefix);
 
 //监听
 watch(() => [
@@ -85,13 +99,15 @@ watch(() => [
     props.autoExpandKeys,
     props.projectId,
     props.contractId,
-], ([menus, isMark, AutoKeys, expandKeys, UserProjectId, UserContractId]) => {
+    props.idPrefix,
+], ([menus, isMark, AutoKeys, expandKeys, UserProjectId, UserContractId,UserIdPrefix]) => {
     menusData.value = menus
     menuMark.value = isMark
     isAutoKeys.value = AutoKeys
     TreeExpandKey.value = expandKeys
     projectId.value = UserProjectId
     contractId.value = UserContractId
+    idPrefix.value = UserIdPrefix
 })
 
 //树形结构异步加载数据
@@ -132,9 +148,9 @@ const ElTreeLoadNode = async (node, resolve) => {
     defaultExpandedCids.value = defaultExpandedArr
     resolve(resData)
     //最后一个,执行点击
-    if (clickKey) {
+    if (props.isAutoClick && clickKey) {
         await nextTick(() => {
-            document.getElementById(`wbs-tree-${clickKey}`)?.click()
+            document.getElementById(`${idPrefix.value}${clickKey}`)?.click()
         })
     }
 }

File diff suppressed because it is too large
+ 473 - 262
src/views/data-fill/wbs.vue


+ 1439 - 0
src/views/data-fill/wbs_new.vue

@@ -0,0 +1,1439 @@
+<template>
+    <n-divider dashed title-placement="left">{{wbsTypeTabKey === 'tree'?'树形结构填报':'导图结构填报'}}</n-divider>
+    <div class="hc-layout-box">
+        <div class="hc-layout-left-box" :style="'width:' + leftWidth + 'px;'" v-if="wbsTypeTabKey === 'tree'">
+            <div class="hc-project-box">
+                <div class="text-xl text-cut project-alias-box">
+                    <i class="hcicon-xiangmu"/>
+                    <span class="ml-2">{{projectInfo['projectAlias']}}</span>
+                </div>
+                <div class="text-xs text-cut project-name">{{projectInfo['name']}}</div>
+            </div>
+            <div class="hc-el-tree-box">
+                <HcTree ref="HcTreeRef" type="data-fill-wbs" :params="treeParams" :props="wbsElTreeProps" :menus="ElTreeMenu" :menuMark="TreeMark" lazy :autoExpandKeys="TreeAutoExpandKeys" isColor @node-click="wbsElTreeClick" @menuTap="ElTreeMenuClick"/>
+            </div>
+            <div class="hc-tree-foot-tip-box">
+                <div class="dot-view green">已审批</div>
+                <div class="dot-view black">未填报</div>
+                <div class="dot-view orange">已填报-待审批</div>
+                <div class="dot-view blue">已填报-未上报</div>
+            </div>
+            <!--左右拖动-->
+            <div class="horizontal-drag-line" @mousedown="onmousedown"/>
+        </div>
+        <div class="hc-layout-content-box">
+            <n-card class="hc-card-overflow-box" :segmented="{content: true}">
+                <template #header>
+                    <div class="hc-card-header flex items-center" v-show="wbsTypeTabKey === 'tree' || isDrawer">
+                        <n-popover trigger="hover" :disabled="!bubbleVal || !btn_drawings?.textInfo" v-if="btn_drawings">
+                            <template #trigger>
+                                <n-button type="primary" strong secondary class="px-3" @click="viewsDrawings" v-if="nodeDataInfo.fileUrl">
+                                    <i class="hcicon-Frame"/>
+                                    <span class="ml-2">查看图纸</span>
+                                </n-button>
+                                <n-button color="#EEEEEE" text-color="#999999" class="px-3" @click="viewsDrawingsTip" v-else>
+                                    <i class="hcicon-Frame"/>
+                                    <span class="ml-2">查看图纸</span>
+                                </n-button>
+                            </template>
+                            <span>{{btn_drawings?.textInfo}}</span>
+                        </n-popover>
+                        <BtnTab class="ml-8" :datas="authBtnTabData" :cur="authBtnTabKey" :disabled="!nodeDataInfo?.primaryKeyId" @tabClick="authBtnTabClick"/>
+                    </div>
+                </template>
+                <template #header-extra>
+                    <HcTabs :datas="wbsTypeTab" :keys="wbsTypeTabKey" @change="wbsTypeTabChange"/>
+                </template>
+                <div class="data-fill-wbs-content" id="data-fill-wbs-content-target">
+                    <div class="hc-card-max-h-box" id="hc-card-list-item" v-if="wbsTypeTabKey === 'tree'">
+                        <ListItem ref="ListItemRef" :datas="ListItemDatas" :projectId="projectId" :contractId="contractId" :classify="authBtnTabKey" @offsetTop="ListItemOffsetTop" @uploadData="getTableDataAll"/>
+                    </div>
+                    <div class="hc-card-max-h-box node-tree" v-if="wbsTypeTabKey === 'map'">
+                        <NodeTree ref="NodeTreeRef" :data="NodeTreeData" :format="NodeTreeFormat" :autoExpandKeys="TreeAutoExpandKeys" :menus="ElTreeMenu" :isMark="TreeMark" isColor
+                                  :accordion='NodeTreeAccordion' @nodeClick="NodeTreeClick" @expand="expandClick" @nodeDblClick="NodeTreeDblClick" @menuClick="NodeTreeMenuClick"/>
+                        <div class="hc-tree-foot-tip-box bg-svg-xml">
+                            <div class="dot-view green">已审批</div>
+                            <div class="dot-view black">未填报</div>
+                            <div class="dot-view orange">已填报-待审批</div>
+                            <div class="dot-view blue">已填报-未上报</div>
+                        </div>
+                    </div>
+                </div>
+                <!--填报弹窗-->
+                <n-drawer v-model:show="isDrawer" :width="200" :height="200" placement="top" :trap-focus="false" :block-scroll="false" to="#data-fill-wbs-content-target">
+                    <div class="drawer-data-fill-content-box">
+                        <n-card :segmented="{content: true}">
+                            <div class="data-fill-content" id="hc-drawer-list-item">
+                                <ListItem ref="ListItemsRef" :datas="ListItemDatas" :projectId="projectId" :contractId="contractId" :classify="authBtnTabKey" @offsetTop="ListItemOffsetTop" @uploadData="getTableDataAll"/>
+                            </div>
+                            <template #action>
+                                <div class="data-fill-foot">
+                                    <template v-if="ListItemDatas.length > 0">
+                                        <n-popover trigger="hover" :disabled="!bubbleVal || !btn_save?.textInfo" v-if="btn_save && NodeStatus !== '3'">
+                                            <template #trigger>
+                                                <n-button type="primary" size="large" class="px-8" :disabled="NodeStatus === '3'" :loading="tableFormSaveLoading" @click="tableFormSaveClick">保存</n-button>
+                                            </template>
+                                            <span>{{btn_save?.textInfo}}</span>
+                                        </n-popover>
+                                        <n-popover trigger="hover" :disabled="!bubbleVal || !btn_preview?.textInfo" v-if="btn_preview">
+                                            <template #trigger>
+                                                <n-button type="primary" strong secondary class="px-8 ml-6" size="large" :disabled="NodeStatus === '1'" :loading="bussPdfsLoading" @click="bussPdfsClick">预览</n-button>
+                                            </template>
+                                            <span>{{btn_preview?.textInfo}}</span>
+                                        </n-popover>
+                                        <n-popover trigger="hover" :disabled="!bubbleVal || !btn_report?.textInfo" v-if="btn_report && NodeStatus !== '3'">
+                                            <template #trigger>
+                                                <n-button type="primary" strong secondary class="px-8 ml-6" size="large" :disabled="NodeStatus === '3' || NodeStatus === '1'" @click="reportModalClick">上报</n-button>
+                                            </template>
+                                            <span>{{btn_report?.textInfo}}</span>
+                                        </n-popover>
+                                        <n-popover trigger="hover" :disabled="!bubbleVal || !btn_abolish?.textInfo" v-if="btn_abolish && NodeStatus === '3'">
+                                            <template #trigger>
+                                                <n-button type="primary" strong secondary class="px-8 ml-6" size="large" @click="abolishOneClick">撤回上报流程</n-button>
+                                            </template>
+                                            <span>{{btn_abolish?.textInfo}}</span>
+                                        </n-popover>
+                                    </template>
+                                    <n-button type="primary" strong secondary class="px-8 ml-6" size="large" @click="isDrawer = false">关闭填报页面</n-button>
+                                </div>
+                            </template>
+                        </n-card>
+                    </div>
+                </n-drawer>
+            </n-card>
+            <div class="bg-white data-fill-foot-box" v-if="wbsTypeTabKey === 'tree' && ListItemDatas.length > 0">
+                <n-popover trigger="hover" :disabled="!bubbleVal || !btn_save?.textInfo" v-if="btn_save && NodeStatus !== '3'">
+                    <template #trigger>
+                        <n-button type="primary" size="large" class="px-8" :disabled="NodeStatus === '3'" :loading="tableFormSaveLoading" @click="tableFormSaveClick">保存</n-button>
+                    </template>
+                    <span>{{btn_save?.textInfo}}</span>
+                </n-popover>
+                <n-popover trigger="hover" :disabled="!bubbleVal || !btn_preview?.textInfo" v-if="btn_preview">
+                    <template #trigger>
+                        <n-button type="primary" strong secondary class="px-8 ml-6" size="large" :disabled="NodeStatus === '1'" :loading="bussPdfsLoading" @click="bussPdfsClick">预览</n-button>
+                    </template>
+                    <span>{{btn_preview?.textInfo}}</span>
+                </n-popover>
+                <n-popover trigger="hover" :disabled="!bubbleVal || !btn_report?.textInfo" v-if="btn_report && NodeStatus !== '3'">
+                    <template #trigger>
+                        <n-button type="primary" strong secondary class="px-8 ml-6" size="large" :disabled="NodeStatus === '3' || NodeStatus === '1'" @click="reportModalClick">上报</n-button>
+                    </template>
+                    <span>{{btn_report?.textInfo}}</span>
+                </n-popover>
+                <n-popover trigger="hover" :disabled="!bubbleVal || !btn_abolish?.textInfo" v-if="btn_abolish && NodeStatus === '3'">
+                    <template #trigger>
+                        <n-button type="primary" strong secondary class="px-8 ml-6" size="large" @click="abolishOneClick">撤回上报流程</n-button>
+                    </template>
+                    <span>{{btn_abolish?.textInfo}}</span>
+                </n-popover>
+            </div>
+        </div>
+    </div>
+    <DragModal title="查看图纸" :isShow="drawingsShow" closeIcon tops="125" widths="380px" bg="bg-dark-3" @close="drawingsClose">
+        <div class="img-preview-box">
+            <ImgPreview :src="nodeDataInfo.fileUrl" isDom toolsSm/>
+        </div>
+    </DragModal>
+
+    <!--标记首件-->
+    <n-modal v-model:show="firstItemModal" class="hc-custom-card" title="标记首件制" preset="card" style="width: 600px;" size="huge" :bordered="false" :segmented="{content: 'soft', footer: 'soft'}">
+        <div class="text-center text-base font-bold">
+            <span>请确认将</span>
+            <span class="text-main">【{{nodeDataInfo.title}}】</span>
+            <span>{{nodeDataInfo.isFirst?'取消':''}}标记为首件</span>
+        </div>
+        <template #footer>
+            <div class="text-center">
+                <n-button class="px-4" @click="firstItemModal = false">取消</n-button>
+                <n-button type="primary" class="px-4 ml-6" :loading="firstItemLoading" @click="firstItemClick">确认</n-button>
+            </div>
+        </template>
+    </n-modal>
+
+    <!--编辑节点-->
+    <n-modal v-model:show="editNodeModal" class="hc-custom-card" title="编辑节点" preset="card" style="width: 600px;" :segmented="{content: 'soft', footer: 'soft'}">
+        <n-form ref="formEditNodeRef" :model="formEditNodeModel" :rules="formEditNodeRules" label-placement="left" label-width="auto" size="large">
+            <n-form-item label="节点名称" path="title">
+                <n-input v-model:value="formEditNodeModel.title" placeholder="请输入节点名称"/>
+            </n-form-item>
+            <n-form-item label="上级节点">
+                <n-input v-model:value="formEditNodeModel.parent.title" disabled/>
+            </n-form-item>
+            <n-form-item label="节点类型">
+                <n-select v-model:value="formEditNodeModel.type" :options="nodeTypeData" disabled/>
+            </n-form-item>
+            <n-form-item label="划分编号" path="partitionCode">
+                <n-input v-model:value="formEditNodeModel.partitionCode" placeholder="请输入划分编号"/>
+            </n-form-item>
+        </n-form>
+        <template #footer>
+            <div class="text-center">
+                <n-button class="px-4" @click="editNodeModal = false">取消</n-button>
+                <n-button type="primary" class="px-4 ml-6" :loading="editNodeLoading" @click="editNodeClick">确认</n-button>
+            </div>
+        </template>
+    </n-modal>
+
+    <!--复制节点-->
+    <n-modal v-model:show="copyNodeModal" title="复制节点" preset="card" class="hc-custom-card copy" :class="copyNodeTabKey==='1'?'one':'many'" :segmented="{content: 'soft', footer: 'soft'}">
+        <template #header-extra>
+            <HcTabs :datas="copyNodeTab" :keys="copyNodeTabKey" @change="copyNodeTabChange"/>
+        </template>
+        <n-form ref="formCopyNodeModelRef" :model="formCopyNodeModel" :rules="formCopyNodeModelRules" label-placement="left" label-width="auto" size="large" v-if="copyNodeTabKey !== '3'">
+            <n-form-item label="节点名称" path="title">
+                <n-input v-model:value="formCopyNodeModel.title" placeholder="请输入节点名称"/>
+            </n-form-item>
+        </n-form>
+        <template #footer v-if="copyNodeTabKey === '1'">
+            <div class="text-center">
+                <n-button class="px-4" @click="copyNodeModal = false">取消</n-button>
+                <n-button type="primary" class="px-4 ml-6" :loading="copyNodeLoading" @click="copyNodeClick">确认</n-button>
+            </div>
+        </template>
+        <div class="copy-node-many-box" v-if="copyNodeTabKey === '2'">
+            <div class="copy-node-many-tree">
+                <HcTree type="data-fill-query" :params="treeParams" :props="wbsElTreeProps" lazy idPrefix="tree-node-copy-" :isAutoRes="false" :autoExpandKeys="treeExpandKeys" @node-click="copyNodeElTreeClick"/>
+            </div>
+            <div class="copy-node-many-table">
+                <div class="copy-node-many-table-data">
+                    <el-table :data="copyNodeTable" border stripe>
+                        <el-table-column prop="title" label="复制到的位置"/>
+                        <el-table-column prop="nodeName" label="节点名称">
+                            <template #default="{row}">
+                                <n-form ref="copyNodeTableRef" :model="row" :rules="copyNodeTableRules">
+                                    <n-form-item path="nodeName">
+                                        <n-input v-model:value="row.nodeName"/>
+                                    </n-form-item>
+                                </n-form>
+                            </template>
+                        </el-table-column>
+                        <el-table-column prop="action" label="操作" width="120" align="center">
+                            <template #default="{_,$index}">
+                                <n-button type="primary" color="#e54d42" size="small" secondary @click="copyNodeTableDel($index)">删除</n-button>
+                            </template>
+                        </el-table-column>
+                    </el-table>
+                </div>
+                <div class="copy-node-many-foot-center">
+                    <n-button class="px-4" @click="copyNodeModal = false">取消</n-button>
+                    <n-button type="primary" class="px-4 ml-6" :loading="copyNodeLoading" @click="copyNodeClick">确认</n-button>
+                </div>
+            </div>
+        </div>
+        <div class="copy-node-many-box" v-if="copyNodeTabKey === '3'">
+            <div class="copy-node-many-tree">
+                <HcTree type="data-fill-query" :params="treeParams" :props="wbsElTreeProps" lazy idPrefix="tree-node-copy-data-" :isAutoRes="false" :autoExpandKeys="treeExpandKeys" @node-click="copyNodeDataElTreeClick"/>
+            </div>
+            <div class="copy-node-many-table">
+                <div class="copy-node-many-table-data">
+                    <el-table :data="copyNodeDataTable" border stripe>
+                        <el-table-column prop="nodeName" label="复制到的位置"/>
+                        <el-table-column prop="action" label="操作" width="120" align="center">
+                            <template #default="{_,$index}">
+                                <n-button type="primary" color="#e54d42" size="small" secondary @click="copyNodeDataTableDel($index)">删除</n-button>
+                            </template>
+                        </el-table-column>
+                    </el-table>
+                </div>
+                <div class="copy-node-many-foot-center">
+                    <n-button class="px-4" @click="copyNodeModal = false">取消</n-button>
+                    <n-button type="primary" class="px-4 ml-6" :loading="copyNodeDataLoading" @click="copyNodeDataClick">确认</n-button>
+                </div>
+            </div>
+        </div>
+    </n-modal>
+
+    <!--新增子节点-->
+    <n-modal v-model:show="addNodeModal" class="hc-custom-card" title="新增子节点" preset="card" style="width: 720px;" :segmented="{content: 'soft', footer: 'soft'}">
+        <HcTreeNode :projectId="projectId" :nodeId="addTreeNodeId" :oldId="addTreeNodeOldId" @check-change="addTreeNodeCheckChange"/>
+        <template #footer>
+            <div class="hc-add-node-modal-foot-box">
+                <div class="left-box">
+                    <div class="font-bold mr-4">选中方式:</div>
+                    <el-radio-group v-model="addTreeNodeType">
+                        <el-radio label="1" border>当前及子节点</el-radio>
+                        <el-radio label="2" border>仅当前节点</el-radio>
+                    </el-radio-group>
+                </div>
+                <div class="right-box">
+                    <n-button class="px-4" @click="addNodeModal = false">取消</n-button>
+                    <n-button type="primary" class="px-4 ml-6" :loading="addNodeLoading" @click="addNodeClick">确认</n-button>
+                </div>
+            </div>
+        </template>
+    </n-modal>
+
+    <!--批量上报审批-->
+    <HcReportModal  title="批量上报审批" url="informationWriteQuery/taskOne" :show="showReportModal" :projectId="projectId" :contractId="contractId"
+                    :taskName="reportTaskName" :ids="reportIds" :addition="reportAddition" @hide="showReportModal= false" @finish="showReportFinish"/>
+
+    <!--上传图纸-->
+    <div class="upload-drawing" id="upload-drawing">
+        <n-upload :action="action" :headers="getTokenHeader()" :accept="accept" with-credentials @before-upload="beforeUpload" @finish="uploadFinish"/>
+    </div>
+
+    <!--调整排序-->
+    <n-modal v-model:show="sortNodeModal" class="hc-custom-card" title="调整排序" preset="card" style="width: 720px;" :segmented="{content: 'soft', footer: 'soft'}">
+        <Draggable class="sort-node-body-box list-group" ghost-class="ghost" :list="sortNodeData" item-key="id" @start="sortNodeDrag = true" @end="sortNodeDrag = false">
+            <template #item="{element, index}">
+                <div class="list-group-item">
+                    <div class="index-box">{{index + 1}}</div>
+                    <div class="title-box">{{element.title}}</div>
+                    <div class="icon-box">
+                        <i class="hcicon-wind-descending" @click="downSortClick(index)"/>
+                        <i class="hcicon-wind-ascending" @click="upSortClick(index)"/>
+                    </div>
+                </div>
+            </template>
+        </Draggable>
+        <template #footer>
+            <div class="text-center">
+                <n-button class="px-4" @click="sortNodeModal = false">取消</n-button>
+                <n-button type="primary" class="px-4 ml-6" :loading="sortNodeLoading" @click="sortNodeClick">确认</n-button>
+            </div>
+        </template>
+    </n-modal>
+
+</template>
+
+<script setup>
+import {ref,watch,nextTick,onMounted} from "vue";
+import {useRoute} from 'vue-router'
+import router from '~src/router/index';
+import {useAppStore} from "~src/store/index";
+import {HcIcon} from "~src/plugins/renderele";
+import HcTabs from "~com/plugins/naive/HcTabs.vue"
+import HcTree from "~com/plugins/element/HcTree.vue"
+import BtnTab from "~com/btnTab/index.vue"
+import ListItem from "~com/data-fill/ListItem.vue"
+import NodeTree from "~com/data-fill/nodeTree/index.vue"
+import DragModal from "~com/dragModal/index.vue"
+import ImgPreview from "~com/imgPreview/index.vue"
+import HcReportModal from "~com/reportModal/index.vue"
+import HcTreeNode from "./components/HcTreeNode.vue"
+import wbsApi from "~api/data-fill/wbs"
+import {deepClone} from "~src/utils/lib/util";
+import {getTokenHeader} from '~src/api/request/header';
+import {isArray,isObjNull} from "~src/utils/lib/isApp";
+import {setStore,getStore} from "~src/utils/lib/storage";
+import Draggable from "vuedraggable";
+
+//变量
+const useRoutes = useRoute()
+const useAppState = useAppStore()
+const projectId = ref(useAppState.getProjectId);
+const contractId = ref(useAppState.getContractId);
+const projectInfo = ref(useAppState.getProjectInfo);
+const contractInfo = ref(useAppState.getContractInfo);
+
+//路由参数
+const routerQuery = useRoutes?.query;
+const MenuBarKey = routerQuery?.MenuBarKey || '';
+const typeName = routerQuery?.type || 'map'
+
+const TreeAutoExpandKeys = ref(getStore({name: 'wbsTreeExpandKeys'}) || [])
+
+//按钮气泡开关
+const bubbleVal = ref(useAppState.getBubble);
+
+//监听
+watch(() => [
+    useAppState.getProjectId,
+    useAppState.getContractId,
+    useAppState.getProjectInfo,
+    useAppState.getContractInfo,
+    useAppState.getBubble,
+], ([UserProjectId, UserContractId, UserProjectInfo,UserContractInfo,Bubble]) => {
+    //项目合同数据
+    projectId.value = UserProjectId
+    contractId.value = UserContractId
+    projectInfo.value = UserProjectInfo
+    contractInfo.value = UserContractInfo
+    //按钮气泡开关
+    bubbleVal.value = Bubble
+    setContractType(UserContractInfo?.contractType)
+})
+//获取气泡数据
+const getButtonsVal = (value) => {
+    return useAppState.getButtonsVal(value)
+}
+//气泡数据
+const btn_drawings = ref(getButtonsVal('wbs_views_drawings'))   //查看图纸
+const btn_save = ref(getButtonsVal('wbs_save'))                 //保存
+const btn_preview = ref(getButtonsVal('wbs_preview'))           //预览
+const btn_report = ref(getButtonsVal('wbs_report'))             //上报
+const btn_abolish = ref(getButtonsVal('wbs_abolish'))           //撤回上报流程
+
+//树菜单
+const tree_menu_edit = ref(getButtonsVal('wbs_tree_edit'))  //编辑节点
+const tree_menu_mark = ref(getButtonsVal('wbs_tree_mark'))  //标记为首件
+const tree_menu_copy = ref(getButtonsVal('wbs_tree_copy'))  //复制节点
+const tree_menu_add = ref(getButtonsVal('wbs_tree_add'))    //新增节点
+const tree_menu_up = ref(getButtonsVal('wbs_tree_upload'))  //上传图纸
+const tree_menu_del = ref(getButtonsVal('wbs_tree_del'))    //删除节点
+const tree_menu_sort = ref(getButtonsVal('wbs_tree_sort'))  //调整排序
+
+
+//上传文件的
+const action = ref("/api/blade-resource/oss/endpoint/put-file")
+const accept = ref("image/png,image/jpg,image/jpeg")
+
+//身份按钮切换数据
+const authBtnTabKey = ref('1')
+const authBtnTabData = [
+    {key: "1", label: "施工质检", icon: 'hcicon-a-Frame1'},
+    {key: "2", label: "监理抽检", icon: 'hcicon-a-Frame2'}
+]
+const authBtnTabClick = (val) => {
+    authBtnTabKey.value = val
+    searchNodeAllTable()
+    queryNodeStatus()
+}
+
+const getTableDataAll = () => {
+    searchNodeAllTable()
+    queryNodeStatus()
+}
+
+//结构类型tab数据和相关处理
+const wbsTypeTabKey = ref(typeName)
+const wbsTypeTab = ref([
+    {key:'map',  name: '导图结构填报'},
+    {key:'tree', name: '树形结构填报'}
+]);
+
+//渲染完成
+onMounted(()=> {
+    const contractType = contractInfo.value?.contractType
+    setContractType(contractType)
+    setElTreeMenu()
+    if (wbsTypeTabKey.value === 'map') {
+        queryMappingStructureTree()
+    }
+})
+
+const setContractType = (contractType) => {
+    //contractType,  1施工,2监理
+    if (contractType <= 0) {
+        authBtnTabKey.value = '1'
+    } else {
+        authBtnTabKey.value = contractType + ''
+    }
+}
+
+const wbsTypeTabChange = async (value) => {
+    wbsTypeTabKey.value = value;
+    isDrawer.value = false;
+    const keys = await NodeExpandKeys(true)
+    router.push({
+        path: useRoutes.path,
+        query: {
+            MenuBarKey: MenuBarKey,
+            type: value
+        }
+    })
+    nextTick(() => {
+        TreeAutoExpandKeys.value = keys
+        if (value === 'map') {
+            queryMappingStructureTree()
+        }
+    })
+}
+
+const NodeTreeAccordion = ref(true)
+
+//设置树菜单数据
+const ElTreeMenu = ref([])
+const TreeMark = ref(false)
+const setElTreeMenu = () => {
+    let newArr = [];
+    if (tree_menu_edit.value) {
+        newArr.push({icon: HcIcon('hcicon-bianji'), label: '编辑节点', key: "edit"})
+    }
+    if (tree_menu_mark.value) {
+        newArr.push({icon: HcIcon('cicon-star-o'), label: '标记为首件', key: "mark"})
+        TreeMark.value = true
+    }
+    if (tree_menu_copy.value) {
+        newArr.push({icon: HcIcon('cicon-file-copy-o'), label: '复制节点', key: "copy"})
+    }
+    if (tree_menu_add.value) {
+        newArr.push({icon: HcIcon('cicon-add-round-o'), label: '新增节点', key: "add"})
+    }
+    if (tree_menu_up.value) {
+        newArr.push({icon: HcIcon('hcicon-shangchuan'), label: '上传图纸', key: "upload"})
+    }
+    if (tree_menu_del.value) {
+        newArr.push({icon: HcIcon('cicon-delete-line-o'), label: '删除节点', key: "del"})
+    }
+    if (tree_menu_sort.value) {
+        newArr.push({icon: HcIcon('cicon-sort-order'), label: '调整排序', key: "sort"})
+    }
+    ElTreeMenu.value = newArr
+}
+
+//树的配置
+const HcTreeRef = ref(null)
+const wbsElTreeProps = {label: 'title', children: 'children', isLeaf: 'notExsitChild'}
+const treeParams = ref({contractId: contractId.value})
+
+//树被点击
+const wbsElTreeClick = ({node,data}) => {
+    nodeItemInfo.value = node
+    nodeDataInfo.value = data
+    searchNodeAllTable()
+    queryNodeStatus()
+}
+
+//导图结构数据
+const NodeTreeRef = ref(null)
+const NodeTreeFormat = ref({key: "primaryKeyId", label: "title", children: "children"})
+const NodeTreeData = ref({})
+
+//导图结构树节点查询
+const queryMappingStructureTree = () => {
+    wbsApi.queryMappingStructureTree({
+        contractId: contractId.value,
+        contractIdRelation: '',
+        parentId: '0',
+        wbsType: 1
+    }).then(({data}) => {
+        NodeTreeData.value = data?.data[0] || {}
+    })
+}
+
+//导图结构展开和收缩被点击
+const expandClick = ({node,data}) => {
+    if (!node.children) {
+        node.expanded = false;
+    }
+    node.isExpand = !node.isExpand;
+}
+
+//鼠标左键单击事件
+const NodeTreeClick = ({node,data}) => {
+    let ifChildren = !!(node.childNodes && node.childNodes.length > 0);
+    if (!ifChildren) {
+        node.loading = true
+        const cid = data?.contractIdRelation
+        const key = data?.primaryKeyId
+        const id = data?.id
+        wbsApi.queryMappingStructureTree({
+            contractId: contractId.value,
+            contractIdRelation: cid,
+            parentId: cid?key:id,
+            wbsType: 1
+        }).then((res) => {
+            const resData = res?.data?.data || []
+            node.childNodes = resData
+            nextTick(() => {
+                if (resData.length > 0) {
+                    node.expanded = true;
+                    node.isExpand = true;
+                } else {
+                    node.expanded = false;
+                    node.expanded = false;
+                }
+                node.loading = false
+            })
+        })
+    } else {
+        node.expanded = true;
+        node.isExpand = true;
+        node.loading = false
+    }
+}
+
+//双击事件
+const isDrawer = ref(false)
+const NodeTreeDblClick = ({node,data}) => {
+    nodeItemInfo.value = node
+    nodeDataInfo.value = data
+    isDrawer.value = true;
+    searchNodeAllTable()
+    queryNodeStatus()
+}
+
+//菜单被点击
+const firstItemModal = ref(false)
+const editNodeModal = ref(false)
+const nodeItemInfo = ref({})
+const nodeDataInfo = ref({})
+const treeExpandKeys = ref([])
+const ElTreeMenuClick = async ({key,node,data}) => {
+    nodeItemInfo.value = node
+    nodeDataInfo.value = data
+    if (key === 'mark' || key === 'cancel_mark') {
+        firstItemModal.value = true
+    } else if (key === 'edit') {
+        const parent = deepClone(node?.parent?.data || {})
+        formEditNodeModel.value = {...deepClone(data), parent: parent}
+        editNodeModal.value = true
+    } else if (key === 'copy') {
+        const parent = deepClone(node?.parent?.data || {})
+        formCopyNodeModel.value = {...deepClone(data), parent: parent}
+        copyNodeTable.value = []
+        copyNodeLoading.value = false
+        treeExpandKeys.value = await NodeExpandKeys()
+        copyNodeModal.value = true
+    } else if (key === 'add') {
+        addTreeNodeId.value = data?.id
+        addTreeNodeOldId.value = data?.oldId
+        addNodeLoading.value = false
+        addNodeModal.value = true
+    } else if (key === 'upload') {
+        const uploadDom = document.getElementById('upload-drawing');
+        let inputDom = uploadDom?.getElementsByTagName('input')[0];
+        inputDom.click()
+    } else if (key === 'del') {
+        delModalClick()
+    } else if (key === 'sort') {
+        let nodes = []
+        const childNodes = node?.parent?.childNodes || []
+        for (let i = 0; i < childNodes.length; i++) {
+            const res = childNodes[i]?.data
+            nodes.push({
+                id: res?.primaryKeyId,
+                title: res?.title
+            })
+        }
+        sortNodeData.value = nodes
+        sortNodeModal.value = true
+    }
+}
+
+const NodeExpandKeys = async (wbsTab = false) => {
+    let newKeysArr = [], node = nodeItemInfo.value || {}
+    await getNodeExpandKeys(node,newKeysArr,wbsTab)
+    const treeKeys = newKeysArr.reverse()
+    await setStore({name: 'wbsTreeExpandKeys', content: treeKeys})
+    return treeKeys
+}
+
+//处理自动展开的节点KEY
+const getNodeExpandKeys = async (node, newKeys, wbsTab = false) => {
+    const tabType = wbsTypeTabKey.value || ''
+    const primaryKeyId = node?.data?.primaryKeyId || ''
+    if (primaryKeyId) {
+        const nodes = node?.parentNodes || []
+        const parent = node?.parent || []
+        newKeys.push(primaryKeyId)
+        if (tabType === 'map' && !wbsTab) {
+            await getNodeExpandKeys(nodes, newKeys,wbsTab)
+        } else if (tabType === 'tree' && !wbsTab) {
+            await getNodeExpandKeys(parent, newKeys,wbsTab)
+        } else if (tabType === 'map' && wbsTab) {
+            await getNodeExpandKeys(parent, newKeys,wbsTab)
+        } else if (tabType === 'tree' && wbsTab) {
+            await getNodeExpandKeys(nodes, newKeys,wbsTab)
+        }
+    }
+}
+
+const NodeTreeMenuClick = async ({key,node,data}) => {
+    nodeItemInfo.value = node
+    nodeDataInfo.value = data
+    if (key === 'mark' || key === 'cancel_mark') {
+        firstItemModal.value = true
+    } else if (key === 'edit') {
+        const parent = deepClone(node?.parentNodes?.data || {})
+        formEditNodeModel.value = {...deepClone(data), parent: parent}
+        editNodeModal.value = true
+    } else if (key === 'copy') {
+        const parent = deepClone(node?.parentNodes?.data || {})
+        formCopyNodeModel.value = {...deepClone(data), parent: parent}
+        copyNodeTable.value = []
+        copyNodeLoading.value = false
+        treeExpandKeys.value = await NodeExpandKeys()
+        copyNodeModal.value = true
+    } else if (key === 'add') {
+        addTreeNodeId.value = data?.id
+        addTreeNodeOldId.value = data?.oldId
+        addNodeLoading.value = false
+        addNodeModal.value = true
+    } else if (key === 'upload') {
+        const uploadDom = document.getElementById('upload-drawing');
+        let inputDom = uploadDom?.getElementsByTagName('input')[0];
+        inputDom.click()
+    } else if (key === 'del') {
+        delModalClick()
+    } else if (key === 'sort') {
+        let nodes = []
+        const childNodes = node?.parentNodes?.childrenNodes || []
+        for (let i = 0; i < childNodes.length; i++) {
+            const res = childNodes[i]?.data
+            nodes.push({
+                id: res?.primaryKeyId,
+                title: res?.title
+            })
+        }
+        sortNodeData.value = nodes
+        sortNodeModal.value = true
+    }
+}
+
+//上传前
+const loadingReactive = ref(null)
+const beforeUpload = () => {
+    loadingReactive.value = window?.$message?.loading('上传中...', {
+        duration: 0
+    })
+    return true
+}
+
+//上传完成
+const uploadFinish = ({event}) => {
+    const res = JSON.parse(event?.target?.response);
+    const info = nodeDataInfo.value;
+    let link = res?.data?.link;
+    wbsApi.saveContractTreeDrawings({
+        fileUrl: link,
+        id: info['drawingsId'],
+        primaryKeyId: info['primaryKeyId']
+    }).then(({data}) => {
+        loadingReactive.value.destroy()
+        loadingReactive.value = null
+        if (data.code === 200) {
+            nodeDataInfo.value['drawingsId'] = data.data
+            nodeDataInfo.value['fileUrl'] = link
+            window?.$message?.success('上传成功')
+        } else {
+            window?.$message?.error(data.msg || '上传失败')
+        }
+    }).catch(erro => {
+        loadingReactive.value.destroy()
+        loadingReactive.value = null
+        window?.$message?.error('请求异常')
+    })
+}
+
+//确认标记为首件
+const firstItemLoading = ref(false)
+const firstItemClick = () => {
+    const info = nodeDataInfo.value;
+    const TabKey = wbsTypeTabKey.value;
+    wbsApi.wbsTreeFirstSave({
+        primaryKeyId: info['primaryKeyId'],
+        saveOrDeleted: !!info['isFirst']?1:0,
+    }).then(({data}) => {
+        if (data.code === 200) {
+            const isFirst = !info['isFirst'];
+            firstItemModal.value = false
+            nodeDataInfo.value['isFirst'] = isFirst
+            //处理菜单状态
+            if (TabKey === 'tree') {
+                HcTreeRef.value.setElTreeMenuMark(data?.data || [], isFirst)
+            } else {
+                setNodeTreeMenuMark(info['primaryKeyId'],data?.data || [], isFirst)
+            }
+            window?.$message?.success('操作成功')
+        } else {
+            window?.$message?.error(data.msg || '操作失败')
+        }
+    })
+}
+
+//设置树菜单的标记数据
+const setNodeTreeMenuMark = (KeyId,keys,isFirst) => {
+    const info = nodeItemInfo.value;
+    setNodeTreeParentNodes(info['parentNodes'],keys,isFirst)
+    setNodeTreeChildNodes(info['childrenNodes'],keys,isFirst)
+}
+
+//设置父级
+const setNodeTreeParentNodes = (parent,keys,isFirst) => {
+    if (keys.indexOf(parent['key']) !== -1) {
+        parent['data']['isFirst'] = isFirst
+    }
+    if (!isObjNull(parent['parentNodes'])) {
+        setNodeTreeParentNodes(parent['parentNodes'],keys,isFirst)
+    }
+}
+
+//设置子级
+const setNodeTreeChildNodes = (child,keys,isFirst) => {
+    if (child.length > 0) {
+        child.forEach(item => {
+            if (keys.indexOf(item['key']) !== -1) {
+                item['data']['isFirst'] = isFirst
+            }
+            if (item['childrenNodes'].length > 0) {
+                setNodeTreeChildNodes(item['childrenNodes'],keys,isFirst)
+            }
+        })
+    }
+}
+
+//编辑节点
+const nodeTypeData = ref([{label: "分项工程", value: 1}, {label: "分部工程", value: 2}])
+const editNodeLoading = ref(false)
+const formEditNodeRef = ref(null)
+const formEditNodeModel = ref({})
+const formEditNodeRules = {
+    title: {
+        required: true,
+        trigger: ["blur", "input"],
+        message: "请输入节点名称"
+    },
+}
+const editNodeClick = () => {
+    editNodeLoading.value = true
+    const {primaryKeyId,title,partitionCode} = formEditNodeModel.value
+    wbsApi.wbsTreeUpdateNode({
+        deptName: title,
+        pKeyId: primaryKeyId,
+        partitionCode: partitionCode||''
+    }).then(({data}) => {
+        editNodeLoading.value = false
+        if (data.code === 200) {
+            window?.$message?.success('修改成功')
+            nodeDataInfo.value['title'] = title || ''
+            nodeDataInfo.value['partitionCode'] = partitionCode || ''
+            editNodeModal.value = false
+        } else {
+            window?.$message?.error(data.msg || '修改失败')
+        }
+    }).catch(erro => {
+        editNodeLoading.value = false
+        window?.$message?.error('请求异常')
+    })
+}
+
+//复制节点
+const copyNodeModal = ref(false)
+
+//复制节点类型tab数据和相关处理
+const copyNodeTabKey = ref('2')
+const copyNodeTab = ref([
+    {key:'1',  name: '单份复制'},
+    {key:'2', name: '多份复制'},
+    {key:'3', name: '复制数据'},
+]);
+const copyNodeTabChange = (value) => {
+    copyNodeTabKey.value = value;
+    copyNodeLoading.value = false
+}
+const copyNodeLoading = ref(false)
+const formCopyNodeModel = ref({})
+const copyNodeTable = ref([])
+
+//树被点击
+const copyNodeElTreeClick = ({data}) => {
+    const {title} = formCopyNodeModel.value;
+    if (!data?.notExsitChild) {
+        copyNodeTable.value.push({
+            title: data?.title || '',
+            nodeName: title || '',
+            primaryKeyId: data?.primaryKeyId || ''
+        })
+    }
+}
+//树被点击
+const copyNodeDataTable = ref([])
+const copyNodeDataElTreeClick = ({data}) => {
+    if (data?.notExsitChild) {
+        copyNodeDataTable.value.push({
+            nodeName: data?.title || '',
+            primaryKeyId: data?.primaryKeyId || ''
+        })
+    }
+}
+
+const formCopyNodeModelRef = ref(null)
+const formCopyNodeModelRules = {
+    title: {
+        required: true,
+        trigger: ["blur", "input"],
+        message: "请输入节点名称"
+    }
+}
+
+//删除选中的节点
+const copyNodeTableDel = (index) => {
+    copyNodeTable.value.splice(index,1)
+}
+const copyNodeDataTableDel = (index) => {
+    copyNodeDataTable.value.splice(index,1)
+}
+
+const copyNodeTableRef = ref(null)
+const copyNodeTableRules = {
+    nodeName: {
+        required: true,
+        trigger: ["blur", "input"],
+        message: "请输入节点名称"
+    }
+}
+
+const copyNodeClick = async () => {
+    const type = copyNodeTabKey.value
+    const form = formCopyNodeModel.value
+    const table = copyNodeTable.value
+    //效验数据
+    let validate = false
+    if (type === '1') {
+        const errors = await formCopyNodeModelRef.value?.validate()
+        validate = !errors
+    } else if (type === '2') {
+        if (table.length > 0) {
+            const errors = await copyNodeTableRef.value?.validate()
+            validate = !errors
+        } else {
+            validate = false
+            window?.$message?.warning('请先在左侧选择要复制到的节点')
+        }
+    }
+    //发起请求
+    if (validate) {
+        copyNodeLoading.value = true
+        const {data} = await wbsApi.copyContractTreeNode({
+            copyType: type,
+            needCopyNodeName: form?.title || '',
+            needCopyPrimaryKeyId: form?.primaryKeyId || '',
+            parentPrimaryKeyId: form?.parent?.primaryKeyId || '',
+            copyBatchToPaths: table
+        })
+        //判断状态
+        if (data.code === 200) {
+            window?.$message?.success('复制成功')
+            copyNodeLoading.value = false
+            copyNodeModal.value = false
+            await NodeExpandKeys()
+            window?.location?.reload()  //刷新页面
+        } else {
+            copyNodeLoading.value = false
+            window?.$message?.error(data.msg || '复制失败')
+        }
+    } else {
+        window?.$message?.warning('请先检查相关表单是否正确填写或节点是否选择')
+    }
+}
+
+//复制数据
+const copyNodeDataLoading = ref(false)
+const copyNodeDataClick = async () => {
+    const form = formCopyNodeModel.value
+    const table = copyNodeDataTable.value
+    if (table.length > 0) {
+        copyNodeDataLoading.value = true
+        const {data} = await wbsApi.copyContractNodeSubmitBusinessData({
+            needCopyPrimaryKeyId: form?.primaryKeyId || '',
+            copyBatchToPaths: table
+        })
+        //判断状态
+        if (data && data.code === 200) {
+            window?.$message?.success('复制成功')
+            copyNodeDataLoading.value = false
+            copyNodeModal.value = false
+            await NodeExpandKeys()
+            window?.location?.reload()  //刷新页面
+        } else {
+            copyNodeDataLoading.value = false
+            window?.$message?.error(data.msg || '复制失败')
+        }
+    } else {
+        window?.$message?.warning('请先选择节点')
+    }
+}
+
+
+//新增节点
+const addNodeModal = ref(false)
+const addTreeNodeId = ref('')
+const addTreeNodeOldId = ref('')
+const addTreeNodeType = ref('1')
+
+//选中的节点
+const allSelectedList = ref([])
+const halfSelectedList = ref([])
+const addTreeNodeCheckChange = (nodes) => {
+    let NodesArr = [], halfArr = []
+    //全选数据
+    const keys = nodes.checkedNodes || []
+    for (let i = 0; i < keys.length; i++) {
+        NodesArr.push({
+            nodeName: keys[i].title,
+            primaryKeyId: keys[i].primaryKeyId
+        })
+    }
+    allSelectedList.value = NodesArr
+    //半选数据
+    const halfNodes = nodes.halfCheckedNodes || []
+    for (let i = 0; i < halfNodes.length; i++) {
+        halfArr.push({
+            nodeName: halfNodes[i].title,
+            primaryKeyId: halfNodes[i].primaryKeyId
+        })
+    }
+    halfSelectedList.value = halfArr
+}
+
+//新增节点
+const addNodeLoading = ref(false)
+const addNodeClick = async () => {
+    const keys = allSelectedList.value || []
+    if (keys.length <= 0) {
+        window?.$message?.warning('请先选择节点')
+    } else {
+        //发起请求
+        addNodeLoading.value = true
+        const {data} = await wbsApi.saveContractTreeNode({
+            projectId: projectId.value,
+            contractId: contractId.value,
+            saveType: addTreeNodeType.value,
+            allSelectedList: allSelectedList.value,
+            halfSelectedList: halfSelectedList.value,
+            currentNodePrimaryKeyId: nodeDataInfo.value?.primaryKeyId
+        })
+        //判断状态
+        if (data.code === 200) {
+            window?.$message?.success('新增成功')
+            await NodeExpandKeys()
+            addNodeLoading.value = false
+            addNodeModal.value = false
+            window?.location?.reload()  //刷新页面
+        } else {
+            addNodeLoading.value = false
+            window?.$message?.error(data.msg || '新增失败')
+        }
+    }
+}
+
+//删除确认弹窗
+const delModalClick  = () => {
+    window?.$dialog?.error({
+        title: "确认此操作?",
+        content: "请谨慎考虑后,确认是否需要删除",
+        positiveText: "确认删除",
+        negativeText: "取消",
+        onPositiveClick: () => {
+            const info = nodeDataInfo.value;
+            const TabKey = wbsTypeTabKey.value;
+            wbsApi.removeContractTreeNode({
+                ids: info['primaryKeyId']
+            }).then(({data}) => {
+                if (data.code === 200) {
+                    window?.$message?.success('删除成功')
+                    //处理菜单状态
+                    if (TabKey === 'tree') {
+                        HcTreeRef.value.removeElTreeNode(info['primaryKeyId'])
+                    } else {
+                        removeNodeTreeNode()
+                    }
+                } else {
+                    window?.$message?.error(data.msg || '删除失败')
+                }
+            }).catch(erro => {
+                window?.$message?.error('请求异常')
+            })
+        }
+    });
+}
+const removeNodeTreeNode = () => {
+    const info = nodeItemInfo.value;
+    const parent = info['parentNodes']
+    const childNodes = parent['childNodes'] || []
+    const childrenNodes = parent['childrenNodes'] || []
+    //删除
+    for (let i = 0; i < childNodes.length; i++) {
+        if (info['key'] === childNodes[i]['primaryKeyId']) {
+            childNodes.splice(i, 1);
+        }
+    }
+    //删除
+    for (let i = 0; i < childrenNodes.length; i++) {
+        if (info['key'] === childrenNodes[i]['key']) {
+            childrenNodes.splice(i, 1);
+        }
+    }
+}
+
+//调整排序
+const sortNodeModal = ref(false)
+const sortNodeLoading = ref(false)
+const sortNodeData = ref([])
+const sortNodeDrag = ref(false)
+//向下
+const downSortClick = (index) => {
+    const indexs = index + 1
+    const data = sortNodeData.value || []
+    if(indexs !== data.length) {
+        const tmp = data.splice(indexs,1);
+        sortNodeData.value.splice(index,0,tmp[0]);
+    } else {
+        window?.$message?.warning('已经处于置底,无法下移')
+    }
+}
+//向上
+const upSortClick = (index) => {
+    const data = sortNodeData.value || []
+    if(index !== 0) {
+        const tmp = data.splice(index - 1,1);
+        sortNodeData.value.splice(index,0,tmp[0]);
+    } else {
+        window?.$message?.warning('已经处于置顶,无法上移')
+    }
+}
+//确认排序
+const sortNodeClick = async () => {
+    const sortList = [];
+    const nodes = sortNodeData.value || []
+    nodes.forEach(item => {
+        sortList.push(item?.id)
+    })
+    //发起请求
+    sortNodeLoading.value = true
+    const { data } = await wbsApi.diySortTreeNode({sortList})
+    //判断状态
+    if (data.code === 200) {
+        window?.$message?.success('保存成功')
+        await NodeExpandKeys()
+        sortNodeLoading.value = false
+        sortNodeModal.value = false
+        window?.location?.reload()  //刷新页面
+    } else {
+        sortNodeLoading.value = false
+        window?.$message?.error(data.msg || '保存失败')
+    }
+}
+
+
+//查看图纸
+const drawingsShow = ref(false);
+const viewsDrawings = () => {
+    drawingsShow.value = true
+}
+const drawingsClose = (res) => {
+    drawingsShow.value = res
+}
+const viewsDrawingsTip = () => {
+    const {primaryKeyId,fileUrl} = nodeDataInfo.value
+    if (!primaryKeyId) {
+        window?.$message?.warning('请先选择树节点')
+    } else if (!fileUrl) {
+        window?.$message?.warning('该节点暂未上传图纸')
+    }
+}
+
+//数据列表
+const ListItemDatas = ref([]);
+
+//获取数据列表
+const searchNodeAllTable = () => {
+    const info = nodeDataInfo.value;
+    const cid = info?.contractIdRelation || ''
+    const key = info?.primaryKeyId || ''
+    const id = info?.id || ''
+    wbsApi.searchNodeAllTable({
+        primaryKeyId: cid?id:key,
+        type: authBtnTabKey.value,
+        projectId: projectId.value,
+        contractId: contractId.value
+    }).then(({data}) => {
+        if (data.code === 200) {
+            let tableData = isArray(data?.data)?data['data']:[]
+            if (tableData.length > 0) {
+                tableData.forEach(item => {
+                    item.name = item.deptName
+                })
+            }
+            ListItemDatas.value = tableData
+        } else {
+            ListItemDatas.value = []
+        }
+    }).catch(() => {
+        ListItemDatas.value = []
+    })
+}
+
+//批量上报
+const reportIds = ref('')
+const reportTaskName = ref('')
+const reportAddition = ref({})
+const showReportModal = ref(false)
+const reportModalClick = () => {
+    const info = nodeDataInfo.value;
+    const rows = ListItemDatas.value;
+    reportIds.value = info?.primaryKeyId || ''
+    if (rows.length > 0) {
+        reportTaskName.value = rows.length > 1?`${rows[0].name}等${rows.length}个文件`:rows[0].name
+        reportAddition.value = {
+            classify: authBtnTabKey.value
+        }
+        showReportModal.value = true
+    } else {
+        window.$message?.warning('暂无相关数据')
+    }
+}
+
+//上报完成
+const showReportFinish = () => {
+    showReportModal.value = false
+    searchNodeAllTable()
+    queryNodeStatus()
+}
+
+//被展开
+const ListItemOffsetTop = (offsetTop) => {
+    if (offsetTop > 0) {
+        const type = wbsTypeTabKey.value || 'map'
+        setTimeout(() => {
+            if (type === 'map') {
+                document.getElementById('hc-drawer-list-item').scrollTop = offsetTop
+            } else if (type === 'tree') {
+                document.getElementById('hc-card-list-item').scrollTop = offsetTop
+            }
+        }, 200)
+    }
+}
+
+//查询状态
+const NodeStatus = ref('1')
+const queryNodeStatus = () => {
+    const info = nodeDataInfo.value;
+    wbsApi.queryNodeStatus({
+        primaryKeyId:  info?.primaryKeyId || '',
+        classify: authBtnTabKey.value
+    }).then(({data}) => {
+        //1 未填报,2待上报,3已上报
+        if (data.code === 200) {
+            NodeStatus.value = data?.data || '1'
+        }
+    })
+}
+
+//撤回上报流程
+const abolishOneClick = () => {
+    window?.$dialog?.warning({
+        title: "确认操作",
+        content: "请谨慎操作",
+        positiveText: "确定撤回",
+        negativeText: "取消",
+        onPositiveClick: () => {
+            abolishOneSave()
+        }
+    });
+}
+
+//撤回请求
+const abolishOneSave = () => {
+    const info = nodeDataInfo.value;
+    wbsApi.abolishOne({
+        primaryKeyId:  info?.primaryKeyId || '',
+        classify: authBtnTabKey.value
+    }).then(({data}) => {
+        if (data.code === 200) {
+            window.$message?.success('撤回成功')
+            searchNodeAllTable()
+            queryNodeStatus()
+        } else {
+            window.$message?.error(data.msg || '撤回失败')
+            searchNodeAllTable()
+            queryNodeStatus()
+        }
+    })
+}
+
+//表单变量
+const ListItemRef = ref(null)
+const ListItemsRef = ref(null)
+
+//保存
+const tableFormSaveLoading = ref(false)
+const tableFormSaveClick = () => {
+    let FormData = [];
+    if (isDrawer.value) {
+        FormData = ListItemsRef.value.getFormData()
+    } else {
+        FormData = ListItemRef.value.getFormData()
+    }
+    console.log(FormData)
+    tableFormSaveLoading.value = true
+    wbsApi.saveExcelBussData({
+        dataInfo: {orderList: FormData}
+    }).then(({data}) => {
+        if(data.code === 200) {
+            window?.$message?.success('保存成功')
+            bussPdfsClick()
+            searchNodeAllTable()
+            queryNodeStatus()
+        } else {
+            window?.$message?.warning(data.msg || '保存失败')
+        }
+    }).catch(() => {
+        tableFormSaveLoading.value = false
+    })
+}
+
+//多表预览
+const bussPdfsLoading = ref(false)
+const bussPdfsClick = () => {
+    const info = nodeDataInfo.value;
+    bussPdfsLoading.value = true
+    wbsApi.getBussPdfs({
+        nodeId:  info?.primaryKeyId || '',
+        classify: authBtnTabKey.value,
+        projectId: projectId.value,
+        contractId: contractId.value
+    }).then(({data}) => {
+        tableFormSaveLoading.value = false
+        bussPdfsLoading.value = false
+        if(data.code === 200 && data?.data) {
+            window.open(data?.data,'_blank')
+        } else {
+            window.$message?.warning('暂无PDF')
+        }
+    }).catch(() => {
+        tableFormSaveLoading.value = false
+        bussPdfsLoading.value = false
+    })
+}
+
+
+//左右拖动,改变树形结构宽度
+const leftWidth = ref(382);
+const onmousedown = () => {
+    document.onmousemove = (ve) => {
+        let diffVal = ve.clientX + 2;
+        if(diffVal >= 310 && diffVal <= 900) {
+            leftWidth.value = diffVal;
+        }
+    }
+    document.onmouseup = () => {
+        document.onmousemove = null;
+        document.onmouseup = null;
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+@import "../../styles/data-fill/wbs.scss";
+.hc-add-node-modal-foot-box {
+    position: relative;
+    display: flex;
+    align-items: center;
+    .left-box {
+        position: relative;
+        flex: 1;
+        display: flex;
+        align-items: center;
+    }
+    .right-box {
+        position: relative;
+    }
+}
+
+html.theme-dark {
+    .bg-svg-xml {
+        background-color: initial;
+        background-image: initial;
+    }
+    .hc-layout-box .hc-layout-content-box .hc-card-max-h-box.node-tree .hc-tree-foot-tip-box {
+        border-top: 1px solid #303030;
+    }
+}
+</style>
+
+<style lang="scss">
+.data-fill-wbs-content {
+    position: relative;
+    height: 100%;
+    .n-drawer-container {
+        margin: -20px -24px;
+    }
+    .n-drawer.n-drawer--top-placement {
+        height: auto !important;
+        background-color: initial;
+        pointer-events: none;
+        bottom: 0;
+    }
+    .drawer-data-fill-content-box {
+        position: relative;
+        height: 100%;
+        padding: 24px;
+        .n-card {
+            pointer-events: auto;
+            height: 100%;
+            overflow: auto;
+        }
+        .data-fill-content {
+            position: relative;
+            height: 100%;
+            overflow-y: auto;
+            scroll-behavior: smooth;
+            .data-fill-list-box .data-fill-list-item-content {
+                height: calc(100vh - 470px);
+                .data-fill-table-form-box {
+                    height: 100%;
+                }
+            }
+        }
+        .data-fill-foot {
+            position: relative;
+            text-align: center;
+        }
+    }
+}
+.n-card.hc-card-overflow-box .n-card__content {
+    padding: 24px;
+}
+.n-card.hc-custom-card > .n-card-header {
+    padding: 15px 24px;
+}
+.n-card.hc-custom-card.copy {
+    width: 1200px;
+    max-height: 90vh;
+    overflow: auto;
+    .n-card-header .n-card-header__close {
+        display: none;
+    }
+    &.one {
+        width: 600px;
+    }
+    &.many {
+        width: 1200px;
+        .copy-node-many-box {
+            position: relative;
+            height: 60vh;
+            display: flex;
+            .copy-node-many-tree {
+                position: relative;
+                flex: 1;
+                height: 100%;
+                overflow: auto;
+                padding-right: 20px;
+                border-right: 1px solid #efeff5;
+            }
+            .copy-node-many-table {
+                position: relative;
+                flex: 1;
+                height: 100%;
+                margin-left: 20px;
+                .copy-node-many-table-data {
+                    position: relative;
+                    height: calc(100% - 74px);
+                    margin-bottom: 20px;
+                    overflow: auto;
+                }
+                .copy-node-many-foot-center {
+                    position: relative;
+                    text-align: center;
+                    padding-top: 20px;
+                    border-top: 1px solid #efeff5;
+                }
+            }
+        }
+    }
+}
+.img-preview-box {
+    position: relative;
+    height: 100%;
+    width: 100%;
+    .cu-img-preview.cu-img-preview-dom .cu-img-preview-box {
+        height: calc(100% - 60px);
+    }
+    .cu-img-preview.cu-img-preview-dom .cu-img-preview-tools-box{
+        position: absolute;
+    }
+}
+</style>

Some files were not shown because too many files changed in this diff