Bladeren bron

新增隐藏资料页面

duy 1 jaar geleden
bovenliggende
commit
42b4829102

+ 6 - 0
src/router/modules/base.js

@@ -203,6 +203,12 @@ export default [
                         meta: { title: '首件工程' },
                         component: () => import('~src/views/other/first-item.vue'),
                     },
+                    {
+                        path: '/hide/data',
+                        name: 'hide-data',
+                        meta: { title: '隐藏资料' },
+                        component: () => import('~src/views/other/hide-data.vue'),
+                    },
                 ],
             },
         ],

+ 157 - 0
src/views/other/collapse-form/index.scss

@@ -0,0 +1,157 @@
+table {
+    width: 100%;
+}
+.data-fill-list-box {
+    position: relative;
+    .hc-collapse-item-header {
+        flex: 1;
+        position: relative;
+        margin-left: 10px;
+        display: flex;
+        align-items: center;
+        .real-fill-rate {
+            position: relative;
+            height: 100%;
+            line-height: initial;
+            margin-right: 18px;
+            padding-right: 18px;
+            &::after {
+                content: "";
+                background: #bfc8cf;
+                position: absolute;
+                right: 0;
+                height: 100%;
+                width: 1px;
+                top: 0;
+            }
+            .tag {
+                position: relative;
+                background: white;
+                font-size: 12px;
+                color: #BD3124;
+                padding: 1px 6px;
+                border-radius: 3px;
+                border: 1px solid #BD3124;
+                margin-bottom: 2px;
+                margin-top: 2px;
+            }
+            .tag.yes {
+                color: #88CF65;
+                border-color: #88CF65;
+            }
+        }
+        .item-title {
+            flex: 1;
+            position: relative;
+            user-select: none;
+            color: #591BB7;
+            font-size: 16px;
+            font-weight: bold;
+            cursor: pointer;
+        }
+        .hc-extra-text-box {
+            position: relative;
+            padding-right: 24px;
+            line-height: initial;
+        }
+    }
+    .data-fill-list-item-content {
+        position: relative;
+        height: calc(100vh - 222px);
+        .data-fill-table-form-box {
+            position: relative;
+            height: calc(100% - 36px);
+            overflow: hidden;
+            border: 4px solid #c4c4c4;
+            &.is-window {
+                border: 0;
+                .hc-window-tip {
+                    position: relative;
+                    height: 100%;
+                    display: flex;
+                    justify-content: center;
+                    align-items: center;
+                    .table-form-no {
+                        position: relative;
+                        img {
+                            width: 380px;
+                        }
+                        .desc {
+                            text-align: center;
+                            font-size: 20px;
+                            color: #aaa;
+                        }
+                    }
+                }
+            }
+            .form-window-icon {
+                position: absolute;
+                top: 10px;
+                right: 10px;
+                background: #3794FF;
+                color: white;
+                font-size: 20px;
+                width: 32px;
+                height: 32px;
+                display: flex;
+                justify-content: center;
+                align-items: center;
+                border-radius: 30px;
+                cursor: pointer;
+                &:hover {
+                    background: #204DA0;
+                }
+            }
+        }
+        .data-fill-table-action {
+            position: relative;
+            display: flex;
+            align-items: center;
+            padding: 4px 10px;
+            .tip-action {
+                cursor: pointer;
+                margin-right: 24px;
+            }
+            .link-action {
+                position: relative;
+                flex: 1;
+            }
+            .btn-action {
+                position: relative;
+            }
+        }
+    }
+}
+.radio-group-box {
+    text-align: center;
+}
+
+.data-fill-table-tip-box {
+    position: relative;
+    .tip-title {
+        font-size: 16px;
+        margin-bottom: 10px;
+        display: flex;
+        align-items: center;
+    }
+    .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;
+                display: flex;
+                align-items: center;
+            }
+        }
+    }
+}

+ 776 - 0
src/views/other/collapse-form/index.vue

@@ -0,0 +1,776 @@
+<template>
+    <div class="data-fill-list-box">
+        <el-collapse v-model="ActiveKey" accordion @change="CollapseChange">
+            <el-collapse-item v-for="(item, index) in listDatas" :id="`item-${index}-${item?.pkeyId}`" :key="item?.pkeyId" :disabled="item.isBussShow === 2" :name="`item-${index}-${item?.pkeyId}`">
+                <template #title>
+                    <div class="hc-collapse-item-header">
+                        <div class="real-fill-rate">
+                            <div class="tag" :class="item.realFillRate >= 80 ? 'yes' : ''">已填{{ item.realFillRate ?? 0 }}%</div>
+                            <HcTooltip v-if="isStatus !== 3" keys="wbs_preview_table">
+                                <el-link v-if="item.isBussShow === 2 || item.isTabPdf === 1 || item.pdfUrl === '' || item.pdfUrl === null" type="primary" disabled>本 表 预 览</el-link>
+                                <el-link v-else type="primary" :disabled="tableFormPreviewLoading" @click.stop="previewClick(item)">本 表 预 览</el-link>
+                            </HcTooltip>
+                        </div>
+                        <div class="text-lg truncate item-title">{{ item.nodeName }}</div>
+                    </div>
+                </template>
+                <div :style="`height: calc(100vh - ${draw_type ? '555px' : '222px'});`" class="data-fill-list-item-content">
+                    <div v-if="item?.isWindow" class="data-fill-table-form-box is-window">
+                        <div class="hc-window-tip">
+                            <div class="table-form-no">
+                                <img :src="NoDataSvg" alt="">
+                                <div class="desc">当前表单处于窗口模式,关闭相关窗口后恢复</div>
+                            </div>
+                        </div>
+                    </div>
+                    <div v-else class="data-fill-table-form-box">
+                        <TableFormItem
+                            v-if="item.isTableRender"
+                            :ref="(el) => setItemRefs(el, item)"
+                            :classify="classifys"
+                            :datas="changeFormDatas(item?.pkeyId, 'collapse')"
+                            :kid="item?.pkeyId"
+                            :node-name="item.nodeName"
+                            :pid="`table-form-${item?.pkeyId}`"
+                            :tid="treeId"
+                            @excel-body-tap="excelTableFormClick($event)"
+                            @render="tableFormRender($event, item, index)"
+                            @right-tap="tableFormRightTap($event, index)"
+                        />
+                        <el-tooltip :content="item.isWindow ? '关闭窗口并恢复' : '当前表单窗口化'" :hide-after="0" placement="top">
+                            <div class="form-window-icon" @click.stop="windowClick(item, index)">
+                                <template v-if="item.isWindow">
+                                    <HcIcon name="fullscreen-exit" />
+                                </template>
+                                <template v-else>
+                                    <HcIcon name="fullscreen" />
+                                </template>
+                            </div>
+                        </el-tooltip>
+                    </div>
+                </div>
+            </el-collapse-item>
+        </el-collapse>
+    </div>
+    <!-- 查看表单 -->
+    <template v-for="(item, index) in DragModalTableForm" :key="index">
+        <HcDragModal
+            :close-icon-arr="closeIconArr" :eid="item.pkeyId" :height="DragModalHeight" :is-show="item.isShow"
+            :loading="item.loading" :loading-text="item.loadingText" :title="item.title" is-sort-top
+            @close="TableFormClose(item, index)" @close-icon-tap="closeIconTap($event, item, index)"
+        >
+            <HcDragNode :more-menu="dragNodeMoreMenu" @menu-tap="dragNodeMoreMenuTap($event, item)">
+                <TableFormItem
+                    :ref="(el) => setItemRefs(el, item)"
+                    :classify="item.classify"
+                    :datas="changeFormDatas(item?.pkeyId, 'window')"
+                    :height="item.height"
+                    :kid="item.pkeyId"
+                    :node-name="item.title"
+                    :pid="`table-form-${item?.pkeyId}`"
+                    :scroll="false"
+                    :tid="item.treeId"
+                    :width="item.width"
+                    @excel-body-tap="excelTableFormClick($event)"
+                    @render="tableFormRender($event, item.item, item.index)"
+                    @right-tap="tableFormRightTap($event, item.index)"
+                />
+            </HcDragNode>
+        </HcDragModal>
+    </template>
+</template>
+
+<script setup>
+import { nextTick, onActivated, onDeactivated, onMounted, onUnmounted, ref, watch } from 'vue'
+import { getStoreValue } from '~src/utils/storage'
+import HTableForm from '~src/plugins/HTableForm'
+import { useAppStore } from '~src/store'
+import wbsApi from '~api/data-fill/wbs'
+
+import TableFormItem from './table-form-item.vue'
+
+
+
+
+
+import NoDataSvg from '~src/assets/view/no-data.svg'
+
+import {
+    arrIndex, deepClone,
+    downloadBlob, getArrValue, getObjVal, getObjValue, isNullES, setPosRange,
+} from 'js-fast-way'
+
+import { toPdfPage } from '~uti/btn-auth'
+//参数
+const props = defineProps({
+    datas: {
+        type: Array,
+        default: () => ([]),
+    },
+    classify: {
+        type: [String, Number],
+        default: '',
+    },
+    status: {
+        type: [String, Number],
+        default: '',
+    },
+    primaryKeyId: {
+        type: [String, Number],
+        default: '',
+    },
+    contractId: {
+        type: [String, Number],
+        default: '',
+    },
+    drawType: {
+        type: Boolean,
+        default: false,
+    },
+    wbsTempId: {
+        type: [String, Number],
+        default: '',
+    },
+    tenantId: {
+        type: [String, Number],
+        default: '',
+    },
+    wbsType: {
+        type: [String, Number],
+        default: '',
+    },
+    treeAutoExpandKeys: {
+        type: [Array],
+        default: () => ([]),
+    },
+    treenodeDataInfo: {
+        type: [Object],
+        default: () => ({}),
+    },
+    newlistdata:{
+        type: [Array],
+        default: () => ([]),
+    },
+
+})
+
+//事件
+const emit = defineEmits(['renew', 'offsetTop', 'getList'])
+
+//初始变量
+const useAppState = useAppStore()
+
+//全局变量
+const projectId = ref(useAppState.projectId)
+const contract_id = ref(props.contractId)
+const treeId = ref(props.primaryKeyId)
+const classifys = ref(props.classify)
+const wbsTemp_id = ref(props.wbsTempId)
+const tenant_id = ref(props.tenantId)
+const wbs_type = ref(props.wbsType)
+const isStatus = ref(parseInt(props.status))
+const listDatas = ref([])
+const draw_type = ref(props.drawType)
+const tree_AutoExpandKeys = ref(props.treeAutoExpandKeys)
+const treenodeDataInfo = ref(props.treenodeDataInfo)
+const newlistdata = ref(props.newlistdata)
+
+
+//表单变量
+const formDataList = ref([])
+const formKeyIds = ref('')
+const formparentId = ref('')
+
+//处理ref
+const itemRefs = ref([])
+const setItemRefs = (el, { pkeyId }) => {
+    if (el) {
+        let index = arrIndex(itemRefs.value, 'pkeyId', pkeyId)
+        if (index !== -1) {
+            itemRefs.value[index].ref = el
+        } else {
+            itemRefs.value.push({
+                pkeyId: pkeyId,
+                ref: el,
+            })
+        }
+    }
+}
+
+//处理表单的ref
+const setSpliceItemRefs = async ({ pkeyId }) => {
+    const refs = itemRefs.value
+    let index = arrIndex(refs, 'pkeyId', pkeyId)
+    if (index !== -1) {
+        refs.splice(index, 1)
+        itemRefs.value = refs
+    }
+}
+
+const closeIconArr = [
+    { key: 'reduction', icon: 'picture-in-picture-2', name: '还原到面板内,并自动展开面板' },
+]
+
+//组件参数变量
+const apis = ref({
+    dataInfo: wbsApi.getBussDataInfo,
+    bussCols: wbsApi.getHtmlBussCols,
+    excelHtml: wbsApi.getExcelHtml,
+})
+
+//深度监听数据
+watch(() => [
+    props.datas,
+], ([datas]) => {
+    setFormDataNum(datas)
+}, { deep: true })
+
+//监听变量值
+watch(() => [
+    useAppState.projectId,
+    props.contractId,
+    props.wbsTempId,
+    props.tenantId,
+    props.wbsType,
+    props.status,
+    props.classify,
+    props.primaryKeyId,
+    props.newlistdata,
+    props.treenodeDataInfo,
+], ([pid, cid, temp_id, tid, type, status, class_id, tree_id, Newlistdata, TreenodeDataInfo]) => {
+    projectId.value = pid
+    contract_id.value = cid
+    wbsTemp_id.value = temp_id
+    tenant_id.value = tid
+    wbs_type.value = type
+    isStatus.value = parseInt(status)
+    classifys.value = class_id
+    treeId.value = tree_id
+    newlistdata.value = Newlistdata
+    treenodeDataInfo.value = TreenodeDataInfo
+})
+
+//渲染完成
+onMounted(() => {
+    setFormDataNum(props.datas)
+    // setTableFormMenu(useAppState.projectInfo)
+    const { offsetHeight } = document.body
+    DragModalHeight.value = offsetHeight - 200
+    setMountOnEventKey()
+})
+
+//处理变动的数据
+const changeFormData = ref({
+    window: [],
+    collapse: [],
+})
+const changeFormDatas = (pkeyId, type) => {
+    const changeData = changeFormData.value[type]
+    const index = arrIndex(changeData, 'pkeyId', pkeyId)
+    if (index !== -1) {
+        return changeData[index]
+    } else {
+        return {}
+    }
+}
+
+//设置变动的数据
+const setChangeFormDatas = async (pkeyId, type) => {
+    const refs = await getFormRef(pkeyId)
+    const formData = refs?.getFormData()
+    const changeData = changeFormData.value[type]
+    const index = arrIndex(changeData, 'pkeyId', pkeyId)
+    if (index !== -1) {
+        changeData[index] = formData
+    } else {
+        changeData.push(formData)
+    }
+    changeFormData.value[type] = changeData
+}
+
+//展开事件
+const ActiveKey = ref('')
+const CollapseChange = (name) => {
+    ActiveKey.value = name
+    let index = getCollapseItemIndex(name)
+    if (index > -1) {
+        getOffsetTop(name)
+        const item = listDatas.value[index]
+        formKeyIds.value = setToString(item.pkeyId)
+        formparentId.value = setToString(item.parentId)
+        nextTick(() => {
+            if (!item.isTableRender) {
+                item.isTableRender = true
+            }
+        })
+    } else {
+        getOffsetTop()
+        formKeyIds.value = ''
+        formparentId.value = ''
+    }
+}
+
+const setCollapseKey = (key) => {
+    CollapseChange(key)
+}
+
+//初始设置
+const setFormDataNum = (datas) => {
+    itemRefs.value = []
+    ActiveKey.value = ''
+    let newArr = []
+    for (let i = 0; i < datas.length; i++) {
+        newArr.push({ isCollapseLoad: false })
+    }
+    formDataList.value = newArr
+    listDatas.value = deepClone(datas)
+}
+
+//渲染完成
+const tableFormRender = (form, item, index) => {
+    formDataList.value[index] = form
+    formDataList.value[index].isCollapseLoad = form.isRenderForm
+    item.isTableForm = form.isRenderForm
+}
+
+
+//菜单数据
+const contextMenuRef = ref(null)
+
+const tableFormItemNode = ref({}) //临时信息
+
+
+
+//鼠标右键事件
+const tableFormRightTap = ({ event, KeyName, startPos, endPos, pkeyId }, index) => {
+    //存储临时信息
+    tableFormItemNode.value = { KeyName, index, startPos, endPos, pkeyId }
+    contextMenuRef.value?.showMenu(event, false) //展开菜单
+}
+
+//插入设计值
+const designModal = ref(false)
+
+const formDesignModel = ref()
+
+//初始设计值/频率表单
+const setInitDesignForm = () => {
+    formDesignModel.value = {
+        type: 1, design: '', size: '',
+        dev: '', key: '', capacity: '',
+        pass: '', pkId: '', direction:1,
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//窗口化
+const DragModalTableForm = ref([])
+const DragModalHeight = ref(600)
+const windowClick = async (item, indexs) => {
+    const list = deepClone(DragModalTableForm.value)
+    let index = arrIndex(list, 'pkeyId', item.pkeyId)
+    if (!item.isWindow) {
+        const formSize = getTableFormSize(item?.pkeyId)
+        const newTableForm = {
+            ...setInitDragModalTableForm(item, indexs),
+            ...formSize,
+        }
+        await setChangeFormDatas(item?.pkeyId, 'window')
+        item.isWindow = true
+        //处理表单的ref
+        await setSpliceItemRefs(item)
+        //弹窗表单的排序
+        if (index === -1) {
+            list.push(newTableForm)
+        } else if (index !== list.length - 1) {
+            //检查是否在最上层,不在则置顶,可以解决多次点击时,频繁更改全局状态的问题
+            list.splice(index, 1)
+            list.push(newTableForm)
+        }
+        DragModalTableForm.value = list
+        ActiveKey.value = ''
+    } else {
+        await setChangeFormDatas(item?.pkeyId, 'collapse')
+        //处理表单的ref
+        await setSpliceItemRefs(item)
+        if (index !== -1) {
+            list.splice(index, 1)
+            DragModalTableForm.value = list
+        }
+        item.isWindow = false
+    }
+}
+
+//初始拖动表单的内容
+const setInitDragModalTableForm = (item, index) => {
+    return {
+        projectId: projectId.value,
+        contractId: contract_id.value,
+        wbsTempId: wbsTemp_id.value,
+        tenantId: tenant_id.value,
+        wbsType: wbs_type.value,
+        classify: classifys.value,
+        treeId: treeId.value,
+        pkeyId: item.pkeyId,
+        height: '100%',
+        width: '100%',
+        title: item.nodeName,
+        isShow: true,
+        index: index,
+        item: item,
+    }
+}
+
+//关闭窗口
+const TableFormClose = async ({ pkeyId, index }, indexs) => {
+    const list = deepClone(DragModalTableForm.value)
+    //取表单的数据
+    await setChangeFormDatas(pkeyId, 'collapse')
+    //关闭窗口
+    list.splice(indexs, 1)
+    DragModalTableForm.value = list
+    listDatas.value[index].isWindow = false
+}
+
+const dragNodeMoreMenu = [
+    { key: 'save', icon: 'save-2', name: '保存' },
+    { key: 'preview', icon: 'eye', name: '预览' },
+]
+
+//还原窗口
+const closeIconTap = async (event, item, indexs) => {
+    const { index, pkeyId } = item
+    let KeyId = `item-${index}-${pkeyId}`
+    await TableFormClose(item, indexs)
+    ActiveKey.value = KeyId
+}
+
+//菜单被点击
+const dragNodeMoreMenuTap = ({ key }, items) => {
+    const { item } = items
+    if (key === 'save') {
+        if (item?.isTableForm) {
+            tableFormSaveClick(item, items)
+        } else {
+            window.$message.warning('此表单暂无数据和文件')
+        }
+    } else if (key === 'preview') {
+        if (item['isBussShow'] === 2 || item['isTabPdf'] === 1 || item['pdfUrl'] === '' || item['pdfUrl'] === null) {
+            window.$message.warning('此表单暂无可预览文件')
+        } else {
+            previewClick(item, items)
+        }
+    }
+}
+
+
+//跨节点复制弹窗
+// const copyClick =  (items) => {
+//     showcopyModal.value=true
+//     copyItems.value=items
+
+// }
+
+
+
+//获取表单列表
+const getNewList = ()=>{
+    emit('getList')
+   setTimeout(() => {
+    let newObj = newlistdata.value
+    let oldObj = listDatas.value
+    const addedObject = newObj.find(obj => !oldObj.some(oldObj => oldObj.pkeyId === obj.pkeyId))
+    let index = arrIndex(listDatas.value, 'id', addedObject.id) // 1
+    listDatas.value.splice(index + 1, 0, addedObject)
+   }, 1000)
+}
+
+
+//预览本表
+const tableFormPreviewLoading = ref(false)
+const previewClick = async (item, dragItem = null) => {
+    tableFormPreviewLoading.value = true
+    await getBussPdfInfo(item, dragItem)
+    tableFormPreviewLoading.value = false
+}
+
+
+
+
+
+
+
+
+
+//预览PDF
+const getBussPdfInfo = async ({ pkeyId }, dragItem = null, showTip = true) => {
+    setDragModalLoading(dragItem, '获取pdf中...', true)
+    const { error, code, data } = await wbsApi.getBussPdfInfo({
+        pkeyId: pkeyId,
+    }, false)
+    setDragModalLoading(dragItem)
+    if (!error && code === 200) {
+        if (data) {
+            toPdfPage(data)
+            //window.open(data, '_blank')
+        } else if (showTip) {
+            window?.$message?.warning('PDF错误')
+        }
+    } else {
+        if (showTip) {
+            window?.$message?.warning(data.msg || '获取PDF失败')
+        }
+    }
+}
+
+
+//通知数据更新
+const renewData = () => {
+    emit('renew', ActiveKey.value)
+    ActiveKey.value = ''
+}
+
+//设置表单的加载状态
+const setDragModalLoading = (dragItem, text = '保存中...', show = false) => {
+    if (dragItem && show) {
+        dragItem.loading = true
+        dragItem.loadingText = text
+    }
+    if (dragItem && !show) {
+        dragItem.loading = false
+    }
+}
+
+//获取表单的ref
+const getFormRef = async (pkeyId) => {
+    const itemRef = getArrValue(itemRefs.value)
+    if (itemRef.length <= 0) return ''
+    const index = arrIndex(itemRef, 'pkeyId', pkeyId)
+    if (index === -1) return ''
+    const obj = getObjValue(itemRef[index])
+    return obj?.ref
+}
+
+//删除打开的窗口
+const delWindowRefs = (pkeyId) => {
+    //判断是否存在窗口,如果存在,就删除窗口
+    const list = DragModalTableForm.value
+    const index = arrIndex(list, 'pkeyId', pkeyId)
+    if (index !== -1) {
+        list.splice(index, 1)
+        DragModalTableForm.value = list
+    }
+}
+
+//计算展开高度和滚动位置
+const getOffsetTop = (key = '') => {
+    if (key) {
+        const dom = document.getElementById(key)
+        if (!draw_type.value) {
+            if (dom?.offsetTop >= 583 && key) {
+                emit('offsetTop', dom?.offsetTop - 583)
+            } else {
+                emit('offsetTop', dom?.offsetTop)
+            }
+        } else {
+            if (dom.offsetTop >= 424 && key) {
+                emit('offsetTop', dom?.offsetTop - 424)
+            } else {
+                emit('offsetTop', dom?.offsetTop)
+            }
+        }
+    } else {
+        emit('offsetTop', 0)
+    }
+    ActiveKey.value = key
+}
+
+//获取折叠面板的索引
+const getCollapseItemIndex = (name) => {
+    const keys = name.split('-')
+    if (keys.length > 0) {
+        return keys[1]
+    } else {
+        return -1
+    }
+}
+
+//获取表单的大小
+const getTableFormSize = (pkeyId) => {
+    let formId = `table-form-${pkeyId}`
+    try {
+        const { clientWidth, clientHeight } = document.getElementById(formId).children[0]
+        return {
+            width: (clientWidth + 40) + 'px',
+            height: (clientHeight + 80) + 'px',
+        }
+    } catch {
+        return {
+            width: '100%',
+            height: '100%',
+        }
+    }
+}
+
+//转字符串
+const setToString = (val) => {
+    return val ? val + '' : ''
+}
+
+//表单被点击
+const presentId = ref('')
+const excelTableFormClick = (key) => {
+    presentId.value = key
+}
+
+//缓存被激活时
+onActivated(() => {
+    setMountOnEventKey()
+})
+
+//缓存时被移除
+onDeactivated(() => {
+    HTableForm.unmountEventKey()
+})
+
+//页面被卸载
+onUnmounted(() => {
+    HTableForm.unmountEventKey()
+})
+
+const setMountOnEventKey = () => {
+    HTableForm.setOnEventKey({
+        //按下ctrl键 或 control 键
+        onCtrlDown: async () => {
+            //window.$HcLog('全局按键', '按下ctrl键 或 control 键')
+            const refs = await setOnFuncFormRef()
+            refs?.setIsCtrlKey(true)
+        },
+        //按下复制快捷键
+        onCtrlDownC: async (event) => {
+            //window.$HcLog('全局按键', '按下复制快捷键')
+            const refs = await setOnFuncFormRef()
+            refs?.setCopyKeyList(event)
+        },
+        //按下粘贴快捷键
+        onCtrlDownV: async (event) => {
+            //window.$HcLog('全局按键', '按下粘贴快捷键')
+            const refs = await setOnFuncFormRef()
+            await refs?.setPasteKeyList(event)
+        },
+        //放开ctrl键 或 control 键
+        onCtrlUp: async () => {
+            //window.$HcLog('全局按键', '放开ctrl键 或 control 键')
+            const refs = await setOnFuncFormRef()
+            refs?.setIsCtrlKey(false)
+        },
+    })
+}
+
+//获取表单的ref
+const setOnFuncFormRef = async () => {
+    const pkeyId = presentId.value
+    if (!isNullES(pkeyId)) {
+        return await getFormRef(pkeyId)
+    } else {
+        return
+    }
+}
+
+
+//获取已渲染的表单
+const getFilterFormData = async () => {
+    const formArr = formDataList.value
+    return formArr.filter((item) => {
+        return (item.pkeyId ?? '') !== '' && item.isCollapseLoad
+    })
+}
+
+//获取表单数据
+const getFormData = async () => {
+    const formArr = await getFilterFormData()
+    //获取表单数据
+    let newArr = []
+    for (let i = 0; i < formArr.length; i++) {
+        const pkeyId = formArr[i].pkeyId
+        const refs = await getFormRef(pkeyId)
+        const form = refs?.getFormData()
+        newArr.push({ ...form })
+    }
+    console.log('表单数据', newArr)
+    return newArr
+}
+
+//获取表单效验数据
+const getFormRegExpJson = async () => {
+    const formArr = await getFilterFormData()
+    const list = listDatas.value
+    //获取表单数据
+    let formRegExpJson = {}
+    for (let i = 0; i < formArr.length; i++) {
+        const pkeyId = formArr[i].pkeyId
+        const refs = await getFormRef(pkeyId)
+        const regExp = refs?.getRegExpJson()
+        const nodeName = refs?.getNodeName()
+        if (getObjVal(regExp)) {
+            const index = arrIndex(list, 'pkeyId', pkeyId)
+            formRegExpJson[pkeyId] = {
+                ...regExp,
+                itemId: `item-${index}-${pkeyId}`,
+                nodeName: nodeName,
+            }
+        }
+    }
+    return formRegExpJson
+}
+
+//获取当前展开项
+const getActiveKey = () => {
+    return ActiveKey.value
+}
+
+//设置当前展开项
+const setActiveKey = (key) => {
+    return ActiveKey.value = key
+}
+
+
+
+// 暴露出去
+defineExpose({
+    getFormData,
+    getFormRegExpJson,
+    getActiveKey,
+    setActiveKey,
+    setCollapseKey,
+})
+</script>
+
+<style lang="scss" scoped>
+@import "./index.scss";
+</style>
+
+<style lang="scss">
+@import "./style.scss";
+</style>

+ 113 - 0
src/views/other/collapse-form/style.scss

@@ -0,0 +1,113 @@
+//插入特殊字符弹窗的输入框
+.data-fill-list-box .data-fill-table-form-box td,
+.data-fill-list-box .data-fill-table-form-box td .el-input .el-input__wrapper .el-input__inner,
+.el-form-item.special-form-item .el-form-item__content .el-input .el-input__wrapper .el-input__inner {
+    font-family: "hc-eudc", hc-sans, 宋体, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
+}
+
+.data-fill-list-box {
+    .el-collapse {
+        --el-collapse-header-height: 50px;
+        border: 0;
+        .el-collapse-item {
+            margin: 0 0 6px;
+            background-color: #E6EEF4;
+            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 {
+               display: none;
+            }
+        }
+        .el-collapse-item.is-active .el-collapse-item__header.is-active {
+            background-color: #E7EEF4;
+        }
+        .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;
+            }
+        }
+    }
+    .hc-collapse-item-header .real-fill-rate .el-link {
+        font-size: 12px;
+    }
+    .el-link {
+        text-decoration: underline;
+        &:hover {
+            text-decoration: auto;
+        }
+    }
+    .el-link + .el-link {
+        margin-left: 20px;
+    }
+}
+.data-fill-list-box .data-fill-table-form-box .hc-table-form-data-item {
+    padding: 0;
+    background-color: initial;
+}
+
+//复制本表弹窗
+.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;
+    }
+}
+
+.copy-node-many-table {
+    position: relative;
+    flex: 1;
+    height: 100%;
+    padding: 20px 0 20px 20px;
+}
+.dialog-table-box {
+    position: relative;
+    flex: 1;
+    height: 100%;
+    padding: 18px;
+    .dialog-search {
+        position: relative;
+        display: flex;
+    }
+    .dialog-table {
+        position: relative;
+        height: calc(100% - 68px);
+        padding: 18px 0;
+    }
+    .dialog-pages {
+        position: relative;
+    }
+}
+.text-blue {
+    color: blue;
+}
+.text-green {
+    color: green
+}

+ 291 - 0
src/views/other/collapse-form/table-form-item.vue

@@ -0,0 +1,291 @@
+<template>
+    <HcTableForm
+        ref="tableFormRef"
+        :cols="colsKeys"
+        :form="tableFormInfo"
+        :height="heights"
+        :html="excelHtml"
+        :loading="loading"
+        :pid="activeKey"
+        :pkey="keyId"
+        :scroll="scroll"
+        :width="widths"
+        @excel-body-tap="excelTableFormClick"
+        @render="tableFormRender"
+        @right-tap="tableFormRightTap"
+    />
+</template>
+
+<script setup>
+import { onMounted, ref, watch } from 'vue'
+import { useAppStore } from '~src/store'
+import wbsApi from '~api/data-fill/wbs'
+import { deepClone, getArrValue, getObjVal, isString } from 'js-fast-way'
+
+//初始
+const props = defineProps({
+    tid: { // 树节点
+        type: [String, Number],
+        default: '',
+    },
+    kid: { // pkeyId
+        type: [String, Number],
+        default: '',
+    },
+    classify: { // 类型
+        type: [String, Number],
+        default: '',
+    },
+    scroll: {
+        type: Boolean,
+        default: true,
+    },
+    height: {
+        type: String,
+        default: '100%',
+    },
+    width: {
+        type: String,
+        default: 'auto',
+    },
+    datas: {
+        type: Object,
+        default: () => ({}),
+    },
+    nodeName: { // 表单名称
+        type: String,
+        default: '',
+    },
+    pid: { // 折叠ID
+        type: String,
+        default: '',
+    },
+})
+
+//事件
+const emit = defineEmits(['rightTap', 'render', 'excelBodyTap'])
+//初始变量
+const useAppState = useAppStore()
+const projectId = ref(useAppState.getProjectId)
+const contractId = ref(useAppState.getContractId)
+const keyId = ref(props.kid ? props.kid + '' : '')
+const treeId = ref(props.tid)
+const classify = ref(props.classify)
+const loading = ref(false)
+const changeData = ref(props.datas)
+const nodeNames = ref(props.nodeName)
+
+const heights = ref(props.height)
+const widths = ref(props.width)
+const activeKey = ref(props.pid)
+
+const tableFormRef = ref(null)
+
+//监听
+watch(() => [
+    useAppState.getProjectId,
+    useAppState.getContractId,
+    props.tid,
+    props.kid,
+    props.classify,
+    props.nodeName,
+    props.height,
+    props.width,
+    props.pid,
+], (
+    [project_id, contract_id, tree_id, key_id, cid, nodeName, height, width, pid],
+) => {
+    projectId.value = project_id
+    contractId.value = contract_id
+    treeId.value = tree_id
+    keyId.value = key_id ? key_id + '' : ''
+    classify.value = cid
+    nodeNames.value = nodeName
+    heights.value = height
+    widths.value = width
+    activeKey.value = pid
+})
+
+//深度监听变动的对象数据
+watch(() => [
+    props.datas,
+], ([data]) => {
+    changeData.value = data
+    setFormChangeData(data)
+}, { deep: true })
+
+
+//渲染完成
+onMounted(async () => {
+    loading.value = true
+    //获取已填写的数据
+    await getTableFormInfo(keyId.value)
+    //按键key列表
+    await getHtmlBussColsApi(keyId.value)
+    //渲染表单
+    await getExcelHtml(keyId.value)
+    loading.value = false
+})
+
+//表单被点击
+const excelTableFormClick = (item) => {
+    emit('excelBodyTap', item)
+}
+
+//获取表单初始数据
+const getFormDataInit = () => {
+    return {
+        projectId: projectId.value,
+        contractId: contractId.value,
+        classify: classify.value,
+        pkeyId: keyId.value,
+        nodeId: treeId.value,
+        isRenderForm: false,
+    }
+}
+
+//获取已填写的数据
+const tableFormInfo = ref({})
+const getTableFormInfo = async (pkeyId) => {
+    if (pkeyId) {
+        const { error, code, data } = await wbsApi.getBussDataInfo({
+            pkeyId: pkeyId,
+        }, false)
+        const resData = getObjVal(data)
+        if (!error && code === 200 && resData) {
+            tableFormInfo.value = {
+                ...resData,
+                ...getFormDataInit(),
+                ...changeData.value,
+            }
+        } else {
+            tableFormInfo.value = {
+                ...getFormDataInit(),
+                ...changeData.value,
+            }
+        }
+    } else {
+        tableFormInfo.value = {}
+        window?.$message?.warning('pkeyId为空')
+    }
+}
+
+//获取按键切换输入框的key列表
+const colsKeys = ref([])
+const getHtmlBussColsApi = async (pkeyId) => {
+    if (pkeyId) {
+        const { error, code, data } = await wbsApi.getHtmlBussCols({
+            pkeyId: pkeyId,
+        }, false)
+        if (!error && code === 200) {
+            let keys = getArrValue(data)
+            for (let i = 0; i < keys.length; i++) {
+                if (keys[i].length <= 0) {
+                    keys.splice(i, 1)
+                }
+            }
+            colsKeys.value = keys
+        } else {
+            colsKeys.value = []
+        }
+    } else {
+        colsKeys.value = []
+    }
+}
+
+//获取模板标签数据
+const excelHtml = ref('')
+const getExcelHtml = async (pkeyId) => {
+    if (pkeyId) {
+        const { error, code, data } = await wbsApi.getExcelHtml({
+            pkeyId: pkeyId,
+        }, false)
+        const resData = isString(data) ? data || '' : ''
+        if (!error && code === 200 && resData) {
+            excelHtml.value = resData
+        } else {
+            excelHtml.value = ''
+            tableFormInfo.value.isRenderForm = false
+            window?.$message?.warning('暂无表单')
+        }
+    } else {
+        excelHtml.value = ''
+        tableFormInfo.value.isRenderForm = false
+        window?.$message?.warning('pkeyId为空')
+    }
+}
+
+//渲染完成
+const tableFormRender = (form) => {
+    tableFormInfo.value = form
+    emit('render', form)
+}
+
+//右键点击
+const tableFormRightTap = (item) => {
+    emit('rightTap', item)
+}
+
+//设置数据
+const setFormChangeData = (data) => {
+    const form = deepClone(tableFormInfo.value)
+    tableFormInfo.value = { ...form, ...data }
+    //console.log('设置数据', {...form, ...data})
+}
+
+const getFormData = () => {
+    return tableFormInfo.value
+    //return tableFormRef.value?.getFormData()
+}
+const getCols = ()=>{
+    return colsKeys.value
+}
+const setFormData = (data) => {
+    setFormChangeData(data)
+    tableFormRef.value?.setFormData(tableFormInfo.value)
+}
+
+const getRegExpJson = () => {
+    return tableFormRef.value?.getRegExpJson()
+}
+
+const isFormRegExp = async () => {
+    return await tableFormRef.value?.isFormRegExp()
+}
+
+//获取表单名称
+const getNodeName = () => {
+    return nodeNames.value
+}
+
+//按下ctrl键
+const setIsCtrlKey = (data) => {
+    tableFormRef.value?.setIsCtrlKey(data)
+}
+
+//按下复制快捷键
+const setCopyKeyList = (event) => {
+    tableFormRef.value?.setCopyKeyList(event)
+}
+
+//按下粘贴快捷键
+const setPasteKeyList = async (event) => {
+    await tableFormRef.value?.setPasteKeyList(event)
+}
+
+// 暴露出去
+defineExpose({
+    getFormData,
+    setFormData,
+    getRegExpJson,
+    isFormRegExp,
+    getNodeName,
+    setIsCtrlKey,
+    setCopyKeyList,
+    setPasteKeyList,
+    getExcelHtml,
+    getTableFormInfo,
+    getHtmlBussColsApi,
+    getCols,
+})
+</script>

+ 191 - 0
src/views/other/components/HcTreeNode.vue

@@ -0,0 +1,191 @@
+<template>
+    <div v-loading="isElTreeLoadNode">
+        <HcDataTree
+            ref="ElTreeRef"
+            :h-props="ElTreeProps"
+            :datas="ElTreeData"
+            :check-strictly="isStrictly"
+            show-checkbox
+            @check="ElTreeCheckChange"
+        >
+            <template #default="{ node, data }">
+                <div class="custom-tree-node">
+                    <div class="label" @dblclick="ElTreeDblClick(data)">
+                        <el-input v-if="data.isInputName" v-model="data.nodeName" size="small" @blur="ElTreeBtnClick(data)" @keyup="keyUpEvent($event, data)">
+                            <template #append>
+                                <el-button plain size="small" type="primary" @click="ElTreeBtnClick(data)">
+                                    <HcIcon name="check" />
+                                </el-button>
+                            </template>
+                        </el-input>
+                        <span v-else>{{ data.nodeName }}</span>
+                    </div>
+                </div>
+            </template>
+        </HcDataTree>
+    </div>
+</template>
+
+<script setup>
+import { nextTick, onMounted, ref, watch } from 'vue'
+import { getArrValue } from 'js-fast-way'
+import wbsApi from '~api/data-fill/wbs'
+
+//参数
+const props = defineProps({
+    projectId: {
+        type: [String, Number],
+        default: '',
+    },
+    contractId:{
+        type: [String, Number],
+        default: '',
+    },
+    nodeKey: {
+        type: String,
+        default: 'primaryKeyId',
+    },
+    nodeId: {
+        type: [String, Number],
+        default: '',
+    },
+    oldId: {
+        type: [String, Number],
+        default: '',
+    },
+    strictly: {
+        type: Boolean,
+        default: false,
+    },
+    wbsId:{
+        type: [String, Number],
+        default: '',
+    },
+    isCustom:{
+        type: [String, Number],
+        default: '',
+    },
+})
+
+//事件
+const emit = defineEmits(['check-change'])
+//变量
+const ElTreeRef = ref(null)
+const projectId = ref(props.projectId)
+const contractId = ref(props.contractId)
+const isStrictly = ref(props.strictly)
+const wbsId = ref(props.wbsId)
+const isCustom = ref(props.isCustom)
+const ElTreeProps = ref({
+    label: 'nodeName',
+    children: 'children',
+    isLeaf: 'notExsitChild',
+})
+const isElTreeLoadNode = ref(false)
+
+//监听
+watch(() => [
+    props.projectId,
+    props.strictly,
+    props.contractId,
+    props.wbsId,
+    props.isCustom,
+], ([pid, strictly, cid, wid, cus]) => {
+    projectId.value = pid
+    contractId.value = cid
+    isStrictly.value = strictly
+    wbsId.value = wid
+    isCustom.value = cus
+
+})
+
+//渲染完成
+onMounted(() => {
+    ElTreeLoadNode()
+})
+
+//树形结构异步加载数据
+const ElTreeData = ref([])
+const ElTreeLoadNode = async () => {
+    if (isCustom.value === 1) {
+        isElTreeLoadNode.value = true
+        let nodeId = props.nodeId || ''
+        const { error, code, data } = await wbsApi.queryPriateTree({
+            pKeyId: nodeId,
+            contractId: contractId.value,
+            projectId: projectId.value,
+        })
+        if (!error && code === 200) {
+            isElTreeLoadNode.value = false
+            ElTreeData.value = getArrValue(data)
+            ElTreeData.value.forEach((ele, index)=>{
+                if (index == 0) {
+                    ele.isPeer = 1
+                }
+            })
+        
+            await nextTick(() => {
+                ElTreeCheckedKeys()
+            })
+        }
+        isElTreeLoadNode.value = false
+    } else {
+        isElTreeLoadNode.value = true
+        let nodeId = props.nodeId || ''
+        const { error, code, data } = await wbsApi.queryWbsTreeContractByContractIdAndId({
+            pKeyId: nodeId,
+            contractId: contractId.value,
+            projectId: projectId.value,
+        })
+        if (!error && code === 200) {
+            isElTreeLoadNode.value = false
+            ElTreeData.value = getArrValue(data)
+            ElTreeData.value.forEach((ele, index)=>{
+                if (index == 0) {
+                    ele.isPeer = 1
+                }
+            })
+        
+            await nextTick(() => {
+                ElTreeCheckedKeys()
+            })
+        }
+        isElTreeLoadNode.value = false
+    }
+}
+
+//被选择的
+const ElTreeCheckChange = (_, nodes) => {
+    emit('check-change', nodes)
+}
+
+//处理节点
+const ElTreeCheckedKeys = () => {
+    const Nodes = ElTreeRef.value?.treeRef?.getCheckedNodes() || []
+    const HalfNodes = ElTreeRef.value?.treeRef?.getHalfCheckedNodes() || []
+    emit('check-change', {
+        checkedNodes: Nodes,
+        halfCheckedNodes: HalfNodes,
+    })
+}
+
+//更改节点名称
+const ElTreeDblClick = (item) => {
+    item.isInputName = true
+}
+//回车
+const keyUpEvent = (e, item) => {
+    if (e.key === 'Enter') {
+        ElTreeBtnClick(item)
+    }
+}
+//更改节点名称完成
+const ElTreeBtnClick = (item) => {
+    if (!item?.nodeName) {
+        window?.$message?.warning('节点名称不能为空')
+    } else {
+        item.isInputName = false
+        ElTreeCheckedKeys()
+    }
+}
+</script>

+ 190 - 0
src/views/other/components/nodeTree/children.vue

@@ -0,0 +1,190 @@
+<template>
+    <div class="cu-tree-node-children">
+        <div v-for="item in nodes" :key="item['primaryKeyId']" class="cu-tree-node-view is-leaf">
+            <div class="cu-tree-node-label">
+                <div class="cu-tree-node-label-text">
+                    <div :id="`node-tree-${item.key}`" class="cu-tree-node-label-name" @click="nodeLabelClick(item)"
+                         @dblclick="nodeLabelDblClick(item)"
+                         @contextmenu.prevent.stop="nodeLabelContextMenu($event,item,item?.data)">
+                        <el-button v-if="item?.colorStatus === 2" :loading="item.loading" color="#0081ff" hc-btn>
+                            {{ item.label }}
+                        </el-button>
+                        <el-button v-else-if="item?.colorStatus === 3" :loading="item.loading" color="#f37b1d" hc-btn>
+                            {{ item.label }}
+                        </el-button>
+                        <el-button v-else-if="item?.colorStatus === 4" :loading="item.loading" color="#1ECC95" hc-btn
+                                   text-white>{{ item.label }}
+                        </el-button>
+                        <el-button v-else :loading="item.loading" hc-btn type="info">{{ item.label }}</el-button>
+                    </div>
+                    <span v-if="isExpanded(item)" :class="[ifExpanded(item)?'expanded':'']"
+                          class="cu-tree-node-label-btn" @click="expandedClick(item)"/>
+                </div>
+            </div>
+            <TreeNodeChildren v-if="ifExpanded(item)" :data="item.childNodes" :parentNodes="item"
+                              @expandClick="ChildrenExpandedClick" @menuClick="ChildrenCpoverMenuClick"
+                              @nodeClick="ChildrenNodeLabelClick" @nodeDblClick="ChildrenNodeLabelDblClick"/>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import {ref, watch, onMounted} from "vue";
+import TreeNodeChildren from "./children.vue"
+import {isObject, isBoolean} from "js-fast-way"
+
+const props = defineProps({
+    data: {
+        type: Array,
+        default: () => ([])
+    },
+    parentNodes: {
+        type: Object,
+        default: () => ({})
+    },
+    accordion: {
+        type: Boolean,
+        default: false
+    },
+})
+
+//初始数据
+const datas = ref(props.data)
+const parent = ref(props.parentNodes)
+const nodes = ref([])
+
+//监听
+watch(() => [
+    props.data,
+    props.parentNodes
+], ([val, Nodes]) => {
+    datas.value = val
+    if (isDataType(Nodes)) {
+        parent.value = Nodes
+        setDatasToNodes()
+    } else {
+        parent.value = {}
+    }
+})
+
+//渲染完成
+onMounted(() => {
+    if (isDataType(props.parentNodes)) {
+        parent.value = props.parentNodes
+        setDatasToNodes()
+    } else {
+        parent.value = {}
+    }
+})
+
+//检查数据类型
+const isDataType = (data) => {
+    if (isObject(data)) {
+        return Object.keys(data).length !== 0;
+    } else {
+        return false
+    }
+}
+
+//处理为node节点类型的数据
+const setDatasToNodes = () => {
+    let nodesArr = [];
+    const deepData = datas.value
+    for (let i = 0; i < deepData.length; i++) {
+        let childNodes = deepData[i]['children'] //子级数据
+        let ifChildren = !!(childNodes && childNodes.length > 0);
+        nodesArr.push({
+            childNodes: childNodes, //子节点原始数据
+            childrenNodes: [],      //子节点node封装数据
+            data: deepData[i],      //节点主要数据
+            parentNodes: parent.value,  //父节点数据
+            expanded: ifChildren || deepData[i]['expanded'] || false,  //是否展开
+            isExpand: ifChildren || deepData[i]['isExpand'] || false,   //是否能展开
+            isLeaf: deepData[i]['isLeaf'] || false,     //是否为最后一节
+            loading: deepData[i]['loading'] || false,   //加载状态
+            colorStatus: deepData[i]['colorStatus'] || 1,   //颜色状态
+            key: deepData[i]['primaryKeyId'],      //节点的key
+            label: deepData[i]['title']   //节点显示的名称
+        })
+    }
+    nodes.value = nodesArr //渲染使用
+    parent.value['childrenNodes'] = nodes.value //把当前节点数据,存入父节点的数据里。
+}
+
+const emit = defineEmits(['expandClick', 'nodeMouseover', 'nodeMouseout', 'nodeClick', 'nodeDblClick', 'menuClick'])
+
+//下级数据是否存在
+const isChildren = (item) => {
+    return !!(item.childNodes && item.childNodes.length > 0);
+}
+//是否显示展开和隐藏按钮
+const isExpanded = (item) => {
+    let ifChildren = isChildren(item);
+    if (isBoolean(item['expanded'])) {
+        let res = !!(item['expanded'] && ifChildren);
+        item['expanded'] = res;
+        return res;
+    } else {
+        item['expanded'] = false;
+        return false;
+    }
+}
+//处理展开和隐藏的样式
+const ifExpanded = (item) => {
+    let ifChildren = isChildren(item);
+    if (isBoolean(item['isExpand'])) {
+        let res = !!(item['isExpand'] && ifChildren);
+        item['isExpand'] = res;
+        return res;
+    } else {
+        item['isExpand'] = ifChildren;
+        return ifChildren;
+    }
+}
+//展开和隐藏按钮被点击
+const expandedClick = (item) => {
+    emit('expandClick', {
+        node: item,
+        data: item.data
+    })
+}
+const ChildrenExpandedClick = ({node, data}) => {
+    emit('expandClick', {node, data})
+}
+
+//鼠标左键单击事件
+const nodeLabelClick = (item) => {
+    emit('nodeClick', {
+        node: item,
+        data: item.data
+    })
+}
+const ChildrenNodeLabelClick = ({node, data}) => {
+    emit('nodeClick', {node, data})
+}
+
+//双击事件
+const nodeLabelDblClick = (item) => {
+    emit('nodeDblClick', {
+        node: item,
+        data: item.data
+    })
+}
+const ChildrenNodeLabelDblClick = ({node, data}) => {
+    emit('nodeDblClick', {node, data})
+}
+
+//鼠标右键事件
+const nodeLabelContextMenu = (event, node, data) => {
+    emit('menuClick', event, node, data)
+}
+
+//菜单被点击
+const ChildrenCpoverMenuClick = (event, node, data) => {
+    emit('menuClick', event, node, data)
+}
+</script>
+
+<style lang="scss" scoped>
+@import "style";
+</style>

+ 366 - 0
src/views/other/components/nodeTree/index.vue

@@ -0,0 +1,366 @@
+<template>
+    <div v-loading="treeNodeLoading" class="cu-tree-node-container" @mousewheel.prevent="treeNodeMousewheel">
+        <div
+            v-if="!!nodes.label" :id="`tree-node-${uuid}`" :style="{ zoom: `${zoomRef}%` }"
+            class="cu-tree-node-box horizontal collapsable" @mousedown="treeNodeMouseDown"
+        >
+            <div class="cu-tree-node-view">
+                <div class="cu-tree-node-label">
+                    <div class="cu-tree-node-label-text">
+                        <div :id="`node-tree-${nodes.key}`" class="cu-tree-node-label-name">
+                            <el-button :loading="nodes.loading" hc-btn type="primary">
+                                {{ nodes.label }}
+                            </el-button>
+                        </div>
+                    </div>
+                </div>
+                <TreeNodeChildren
+                    :data="nodes.childNodes" :parent-nodes="nodes" @expand-click="expandClick"
+                    @menu-click="poverMenuClick" @node-click="nodeLabelClick"
+                    @node-dbl-click="nodeLabelDblClick"
+                />
+            </div>
+        </div>
+        <!-- 右键菜单 -->
+        <HcContextMenu
+            v-if="menusData.length > 0" ref="contextMenuRef" :datas="menusData"
+            @item-click="handleMenuSelect"
+        >
+            <template #mark="{ item }">
+                <HcIcon :fill="treeRefData?.isFirst" :name="item.icon" class="menu-item-icon" />
+                <span class="menu-item-name">{{ treeRefData?.isFirst ? '取消标记为首件' : '标记为首件' }}</span>
+            </template>
+            <template #sort="{ item }">
+                <HcIcon :line="false" :name="item.icon" class="menu-item-icon" />
+                <span class="menu-item-name">{{ item.label }}</span>
+            </template>
+        </HcContextMenu>
+    </div>
+</template>
+
+<script setup>
+import { nextTick, onActivated, onMounted, ref, watch } from 'vue'
+import TreeNodeChildren from './children.vue'
+import wbsApi from '~api/data-fill/wbs'
+import { getArrValue, getObjValue, getRandom, isArrItem } from 'js-fast-way'
+import { useRoute } from 'vue-router'
+import { getStoreValue, setStoreValue } from '~src/utils/storage'
+
+//参数
+const props = defineProps({
+    autoExpandKeys: {
+        type: Array,
+        default: () => ([]),
+    },
+    menus: {
+        type: Array,
+        default: () => ([]),
+    },
+    isMark: {
+        type: Boolean,
+        default: false,
+    },
+    accordion: {
+        type: Boolean,
+        default: false,
+    },
+    projectId: {
+        type: [String, Number],
+        default: '',
+    },
+    contractId: {
+        type: [String, Number],
+        default: '',
+    },
+})
+
+const emit = defineEmits(['expand', 'nodeClick', 'nodeDblClick', 'menuClick'])
+
+//初始数据
+const uuid = getRandom()
+const datas = ref({})
+const nodes = ref({})
+const menusData = ref(props.menus)
+const menuMark = ref(props.isMark)
+const projectId = ref(props.projectId)
+const contractId = ref(props.contractId)
+const TreeExpandKey = ref(props.autoExpandKeys)
+const treeRefNode = ref(null)
+const treeRefData = ref(null)
+const tableOwner = ref('')
+const classifyType = ref('')
+
+//监听
+watch(() => [
+    props.autoExpandKeys,
+    props.menus,
+    props.isMark,
+    props.projectId,
+    props.contractId,
+], ([expandKeys, menus, isMark, UserProjectId, UserContractId]) => {
+    TreeExpandKey.value = expandKeys
+    menusData.value = menus
+    menuMark.value = isMark
+    projectId.value = UserProjectId
+    contractId.value = UserContractId
+})
+
+//渲染完成
+onMounted(() => {
+    const useRoutes = useRoute()
+    tableOwner.value = getStoreValue('tableOwner')
+    classifyType.value = getStoreValue('classifyType')
+    getTreeOneLevel()
+})
+
+
+
+//导图结构树节点查询
+const treeNodeLoading = ref(false)
+const getTreeOneLevel = async () => {
+    treeNodeLoading.value = true
+    const data = await queryMappingStructureTree({
+        contractId: contractId.value,
+        contractIdRelation: '',
+        primaryKeyId: '',
+        parentId: '',
+        classifyType:classifyType.value,
+        tableOwner:tableOwner.value,
+    })
+    //处理数据
+    const res = getObjValue(data[0])
+    //自动展开第二级
+    const keys = TreeExpandKey.value || []
+    if (keys.length > 0 && res?.id) {
+        const children = await queryMappingStructureTree({
+            contractId: contractId.value,
+            contractIdRelation: res?.contractIdRelation || '',
+            // primaryKeyId: res?.primaryKeyId,
+            primaryKeyId: res?.id,
+            parentId: res?.id,
+            classifyType:classifyType.value,
+            tableOwner:tableOwner.value,
+        })
+        if (children.length > 0) {
+            await setTreeExpandKey(children, res)
+        }
+    }
+    datas.value = res
+    setDatasToNodes()
+    treeNodeLoading.value = false
+}
+
+//设置自动展开
+const setTreeExpandKey = async (arr, res) => {
+    const keys = TreeExpandKey.value || []
+    res.children = []
+    for (const item of arr) {
+        if (isArrItem(keys, item?.primaryKeyId)) {
+            const children = await queryMappingStructureTree({
+                contractId: contractId.value,
+                contractIdRelation: item?.contractIdRelation || '',
+                // primaryKeyId: item?.primaryKeyId,
+                primaryKeyId: item?.id,
+                parentId: item?.id,
+                classifyType:classifyType.value,
+                tableOwner:tableOwner.value,
+            })
+            if (children.length > 0) {
+                await setTreeExpandKey(children, item)
+            }
+        }
+        res.children.push(item)
+    }
+}
+
+//获取数据
+const queryMappingStructureTree = async (form) => {
+    const { error, code, data } = await wbsApi.queryMappingStructureTree({
+        ...form,
+        // wbsType: 1,
+        classifyType:classifyType.value,
+        tableOwner:tableOwner.value,
+    })
+    //处理数据
+    if (!error && code === 200) {
+        return getArrValue(data)
+    } else {
+        return []
+    }
+}
+
+//处理为node节点类型的数据
+const setDatasToNodes = () => {
+    const deepData = datas.value
+    let childNodes = getArrValue(deepData['children'])
+    nodes.value = {
+        childNodes: childNodes,
+        childrenNodes: [],
+        data: deepData,
+        parentNodes: {},
+        expanded: deepData['expanded'] || false,
+        isExpand: deepData['isExpand'] || false,
+        isLeaf: deepData['isLeaf'] || false,
+        loading: deepData['loading'] || false,
+        key: deepData['primaryKeyId'] || '',
+        label: deepData['title'] || '',
+    }
+}
+
+//放大缩小
+const zoomRef = ref(100)
+const treeNodeMousewheel = (event) => {
+    /* 获取当前页面的缩放比 若未设置zoom缩放比,则为默认100%,即1,原图大小 */
+    let zoom = parseInt(zoomRef.value + '') || 100
+    /* event.wheelDelta 获取滚轮滚动值并将滚动值叠加给缩放比zoom wheelDelta统一为±120,其中正数表示为向上滚动,负数表示向下滚动 */
+    zoom += event.wheelDelta / 12
+    /* 最小范围 和 最大范围 的图片缩放尺度 */
+    if (zoom >= 10 && zoom < 200) {
+        zoomRef.value = zoom
+    }
+    return false
+}
+
+const isDown = ref(false)
+const treeNodeMouseDown = (event) => {
+    // 阻止默认事件和冒泡
+    event.preventDefault()
+    event.stopPropagation()
+    //获取相关dom元素
+    let dom = document.getElementById('tree-node-' + uuid)
+    //获取x坐标和y坐标
+    let clientX = event.clientX, clientY = event.clientY
+
+    //获取左部和顶部的偏移量
+    let offsetLeft = dom.offsetLeft, offsetTop = dom.offsetTop
+    //开关打开
+    isDown.value = true
+
+    //设置样式
+    dom.style.cursor = 'move'
+
+    document.onmousemove = (e) => {
+        if (isDown.value === false) {
+            return
+        }
+        //获取x和y
+        let nx = e.clientX
+        let ny = e.clientY
+        //计算移动后的左偏移量和顶部的偏移量
+        let nl = nx - (clientX - offsetLeft)
+        let nt = ny - (clientY - offsetTop)
+
+        dom.style.left = nl + 'px'
+        dom.style.top = nt + 'px'
+    }
+    document.onmouseup = () => {
+        //开关关闭
+        isDown.value = false
+        dom.style.cursor = 'default'
+        document.onmousemove = null
+        document.onmouseup = null
+    }
+}
+
+//处理自动展开的节点KEY
+const getNodeExpandKeys = async (node, newKeys) => {
+    const parent = node?.parentNodes ?? []
+    const primaryKeyId = node?.data?.primaryKeyId ?? ''
+    if (primaryKeyId) {
+        newKeys.push(primaryKeyId)
+        await getNodeExpandKeys(parent, newKeys)
+    }
+}
+
+//导图结构展开和收缩被点击
+const expandClick = ({ node, data }) => {
+    if (!node.children) {
+        node.expanded = false
+    }
+    node.isExpand = !node.isExpand
+    emit('expand', { node, data })
+}
+
+//鼠标左键单击事件
+const nodeLabelClick = async ({ node, data }) => {
+    if (data?.notExsitChild) {
+        await awaitNodeClick(node, data)
+    } else {
+        let ifChildren = !!(node.childNodes && node.childNodes.length > 0)
+        if (ifChildren) {
+            node.expanded = true
+            node.isExpand = true
+            node.loading = false
+            await awaitNodeClick(node, data)
+        } else {
+            node.loading = true
+            const children = await queryMappingStructureTree({
+                contractId: contractId.value,
+                contractIdRelation: data?.contractIdRelation || '',
+                // primaryKeyId: data?.primaryKeyId,
+                primaryKeyId: data?.id,
+                parentId: data?.id,
+                classifyType:classifyType.value,
+                tableOwner:tableOwner.value,
+            })
+            node.childNodes = children
+            await nextTick(async () => {
+                if (children.length > 0) {
+                    node.expanded = true
+                    node.isExpand = true
+                } else {
+                    node.expanded = false
+                    node.expanded = false
+                }
+                node.loading = false
+                await awaitNodeClick(node, data)
+            })
+        }
+    }
+}
+
+//处理数据
+const awaitNodeClick = async (node, data) => {
+    let autoKeysArr = []
+    await getNodeExpandKeys(node, autoKeysArr)
+    const autoKeys = autoKeysArr.reverse()
+    emit('nodeClick', { node, data, keys: autoKeys })
+}
+
+//双击事件
+const nodeLabelDblClick = (item) => {
+    emit('nodeDblClick', item)
+}
+
+//菜单被点击
+const contextMenuRef = ref(null)
+const poverMenuClick = (event, node, data) => {
+    const rows = menusData.value || []
+    if (rows.length > 0) {
+        event.preventDefault()
+        treeRefNode.value = node
+        treeRefData.value = data
+        contextMenuRef.value?.showMenu(event)
+    }
+}
+
+//鼠标右键菜单被点击
+const handleMenuSelect = ({ key }) => {
+    const node = treeRefNode.value
+    const data = treeRefData.value
+    //如果为标记菜单
+    if (key === 'mark' && menuMark.value) {
+        if (data.isFirst === true) {
+            emit('menuClick', { key: 'cancel_mark', node, data })
+        } else {
+            emit('menuClick', { key: 'mark', node, data })
+        }
+    } else {
+        emit('menuClick', { key, node, data })
+    }
+}
+</script>
+
+<style lang="scss">
+@import "style";
+</style>

+ 210 - 0
src/views/other/components/nodeTree/style.scss

@@ -0,0 +1,210 @@
+.cu-tree-node-container {
+    position: relative;
+    width: 100%;
+    height: 100%;
+    overflow: auto;
+    .cu-tree-node-box {
+        display: table;
+        text-align: center;
+        &:before, &:after {
+            content: '';
+            display: table;
+        }
+        &:after {
+            clear: both;
+        }
+        &.horizontal {
+            position: absolute;
+            left: 50%;
+            top: 50%;
+            transform: translate(-50%, -50%);
+        }
+        .cu-tree-node-view, .cu-tree-node-children {
+            position: relative;
+            margin: 0;
+            padding: 0;
+            list-style-type: none;
+            &:before, &:after {
+                transition: all .35s;
+            }
+        }
+        .cu-tree-node-view {
+            padding-top: 40px;
+            display: table-cell;
+            vertical-align: top;
+            &.is-leaf, &.collapsed {
+                padding-left: 10px;
+                padding-right: 10px;
+            }
+            &:before, &:after {
+                content: '';
+                position: absolute;
+                top: 0;
+                left: 0;
+                width: 50%;
+                height: 40px;
+            }
+            &:after {
+                left: 50%;
+                border-left: 1.5px solid #999999;
+            }
+            &:not(:first-child):before,
+            &:not(:last-child):after {
+                border-top: 1.5px solid #999999;
+            }
+            .cu-tree-node-label {
+                position: relative;
+                display: inline-block;
+                z-index: 20;
+                .cu-tree-node-label-text {
+                    position: relative;
+                    text-align: center;
+                    .cu-tree-node-label-name {
+                        white-space: nowrap;
+                        &:before {
+                            content: "";
+                            display: block;
+                            background: inherit;
+                            filter: blur(5px);
+                            position: absolute;
+                            width: 100%;
+                            height: 100%;
+                            top: 0;
+                            left: 0;
+                            z-index: -1;
+                            opacity: var(--ui-Shadow-opacity-lg);
+                            transform-origin: 0 0;
+                            border-radius: inherit;
+                            transform: scale(1);
+                        }
+                        .el-button[hc-btn] {
+                            box-shadow: 4px 4px 8px 0 rgb(54 92 167 / 15%);
+                        }
+                    }
+                }
+            }
+        }
+        .cu-tree-node-label-btn {
+            position: absolute;
+            top: 100%;
+            left: 50%;
+            width: 20px;
+            height: 20px;
+            z-index: 10;
+            background-color: #ffffff;
+            border: 1px solid #999999;
+            border-radius: 50%;
+            box-shadow: 0 0 2px rgba(0, 0, 0, .15);
+            cursor: pointer;
+            transition: all .35s ease;
+            &:hover {
+                background-color: #e7e8e9;
+                transform: scale(1.15);
+            }
+            &:before, &:after {
+                content: '';
+                position: absolute;
+            }
+            &:before {
+                top: 50%;
+                left: 4px;
+                right: 4px;
+                height: 0;
+                border-top: 1px solid #999999;
+            }
+            &:after {
+                top: 4px;
+                left: 50%;
+                bottom: 4px;
+                width: 0;
+                border-left: 1px solid #999999;
+            }
+            &.expanded:after {
+                border: none;
+            }
+        }
+        .cu-tree-node-children {
+            padding-top: 40px;
+            display: table;
+            &:before {
+                content: '';
+                position: absolute;
+                top: 0;
+                left: 50%;
+                width: 0;
+                height: 40px;
+                border-left: 1.5px solid #999999;
+            }
+            &:after {
+                content: '';
+                display: table;
+                clear: both;
+            }
+        }
+        &.horizontal {
+            .cu-tree-node-view {
+                display: table-cell;
+                float: none;
+                padding-top: 0;
+                padding-left: 40px;
+                &.is-leaf {
+                    padding-top: 10px;
+                    padding-bottom: 10px;
+                }
+                &:before, &:after {
+                    width: 40px;
+                    height: 50%;
+                }
+                &:after {
+                    top: 50%;
+                    left: 0;
+                    border-left: 0;
+                }
+                &:only-child:before {
+                    top: 1px;
+                    border-bottom: 1.5px solid #999999;
+                }
+                &:not(:first-child):before,
+                &:not(:last-child):after {
+                    border-top: 0;
+                    border-left: 1.5px solid #999999;
+                }
+                &:not(:only-child):after {
+                    border-top: 1.5px solid #999999;
+                }
+            }
+            .cu-tree-node-label {
+                display: table-cell;
+                vertical-align: middle;
+            }
+            & > .cu-tree-node-view:only-child:before {
+                border-bottom: 0;
+            }
+            .cu-tree-node-children {
+                display: table-cell;
+                padding-top: 0;
+                padding-left: 40px;
+                &:before {
+                    top: 50%;
+                    left: 0;
+                    width: 40px;
+                    height: 0;
+                    border-left: 0;
+                    border-top: 1.5px solid #999999;
+                }
+                &:after {
+                    display: none;
+                }
+                & > .cu-tree-node-view {
+                    display: block;
+                }
+            }
+            .cu-tree-node-label-btn {
+                top: 50%;
+                left: 100%;
+                margin-top: -10.1px;
+                margin-left: 10px;
+            }
+        }
+    }
+}

+ 1923 - 0
src/views/other/hide-data.vue

@@ -0,0 +1,1923 @@
+<template>
+    <div class="h-full">
+        <div v-if="wbsTypeTabKey === 'tree'" class="hc-layout-box" element-loading-text="批量保存数据中...">
+            <div
+                id="wbs-left-tree" :class="[isWbsTreeShow ? 'show' : '', isMouseTree ? 'on-transition' : '']"
+                :style="`width:${isWbsTreeShow ? leftWidth : 0}px; ${isWbsTreeShow ? '' : 'display: none'}`"
+                class="hc-layout-left-box bg-white"
+            >
+                <div class="hc-project-box">
+                    <div class="hc-project-icon-box">
+                        <HcIcon name="stack" />
+                    </div>
+                    <div class="ml-2 project-name-box">
+                        <div class="project-alias">{{ projectInfo.projectName }}</div>
+                    </div>
+                </div>
+                <div class="hc-tree-box">
+                    <div class="hc-tree-back-to">
+                        <el-link type="primary" @click="gobackHistory">回到上一次填报部位</el-link>
+                        <el-link type="warning" class="ml-4" @click="wbsMapTypeTab">导图结构填报</el-link>
+                        <el-button type="primary" class="ml-6" hc-btn keys="hide-data-show">显示</el-button>
+                    </div>
+                    <div class="hc-search-tree-val">
+                        <el-input v-model="searchTreeVal" block clearable placeholder="请输入名称关键词检索" @keyup="searchTreeKeyUp">
+                            <template #suffix>
+                                <HcIcon name="search-2" ui="text-xl iscusor" @click="searchTreeClick" />
+                            </template>
+                        </el-input>
+                    </div>
+                    <div v-if="isShowLeft" id="hc-tree-scrollbar" v-loading="treeLoading" class="hc-tree-scrollbar" element-loading-text="获取数据中...">
+                        <el-scrollbar v-show="isSearchTree" class="scroll-bar-right-16">
+                            <HcDataTree
+                             
+                                :datas="searchTreeData"
+                                :is-mark="TreeMark"
+                               
+                                is-counts
+                                is-type
+                                :auto-expand-keys="TreeAutoExpandKeys"
+                                default-expand-all
+                                @node-tap="wbsElTreeClick"
+                                @menu-tap="ElTreeMenuClick"
+                            />
+                        </el-scrollbar>
+                        <el-scrollbar v-show="!isSearchTree" class="scroll-bar-right-16">
+                            <HcLazyTree
+                                ref="wbstree"
+                            
+                                :auto-expand-keys="TreeAutoExpandKeys"
+                                :is-mark="TreeMark"
+                             
+                                is-counts
+                                is-type
+                                show-checkbox
+                                check-strictly
+                                @load="treeLoadNode"
+                                @menu-tap="ElTreeMenuClick"
+                                @node-loading="ElTreeNodeLoading"
+                                @node-tap="wbsElTreeClick"
+                                @check="ElTreeNodeCheck"
+                            />
+                        </el-scrollbar>
+                    </div>
+                </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 id="wbs-content-box" v-loading="ListItemLoading" class="hc-layout-content-box">
+                <!---展开收缩树 -->
+                <div class="hc-expansion-contraction-tree" @click="setWbsTreeShow">
+                    <HcIcon v-show="isWbsTreeShow" name="arrow-left-s" />
+                    <HcIcon v-show="!isWbsTreeShow" name="arrow-right-s" />
+                </div>
+                <hc-tab-card :tabs="authBtnTabdata" :tab-key="authBtnTabKey" @change="authBtnTabClick">
+                    <el-scrollbar v-if="ListItemDatas.length > 0" ref="ListItemScrollRef">
+                        <CollapseForm
+                            ref="ListItemRef"
+                            :tree-auto-expand-keys="TreeAutoExpandKeys"
+                            :classify="authBtnTabKey"
+                            :contract-id="contractId"
+                            :datas="ListItemDatas"
+                            :draw-type="!isDrawType"
+                            :primary-key-id="primaryKeyId"
+                            :status="NodeStatus"
+                            :tenant-id="userInfo?.tenant_id"
+                            :wbs-temp-id="projectInfo?.referenceWbsTemplateIdTrial"
+                            :wbs-type="2"
+                            :treenode-data-info="nodeDataInfo"
+                            :newlistdata="newlistdata"
+                            @offset-top="ListItemOffsetTop"
+                            @renew="getTableDataAll"
+                            @get-list="searchNodeAllTable1"
+                        />
+                    </el-scrollbar>
+                    <hc-empty v-else title="暂无表单" />
+                </hc-tab-card>
+            </div>
+        </div>
+        <HcNewCard v-if="wbsTypeTabKey === 'map'" id-ref="wbs-node-tree-card-target">
+            <template #header>
+                <HcTooltip keys="wbs_views_division_btn">
+                    <el-button class="mr-10" hc-btn type="primary" @click="divisionClick">
+                        <HcIcon :line="false" name="node-tree" />
+                        <span>划分变更</span>
+                    </el-button>
+                </HcTooltip>
+                <HcNewSwitch v-if="isDrawer" :datas="authBtnTabdata" :keys="authBtnTabKey" :round="false" size="default" @change="authBtnTabClick" />
+            </template>
+            <template #extra>
+                <HcNewSwitch :datas="wbsTypeTab" :keys="wbsTypeTabKey" size="default" @change="wbsTypeTabChange" />
+            </template>
+            <NodeTree
+                ref="NodeTreeRef"
+                :accordion="NodeTreeAccordion"
+                :auto-expand-keys="TreeAutoExpandKeys"
+                :contract-id="contractId"
+                :is-mark="TreeMark"
+                
+                :project-id="projectId"
+                @menu-click="NodeTreeMenuClick"
+                @node-click="NodeTreeClick"
+                @node-dbl-click="NodeTreeDblClick"
+            />
+            <template #action>
+                <div class="hc-tree-mp-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>
+            </template>
+            <HcDrawer v-model="isDrawer" action-ui="text-center" to-id="wbs-node-tree-card-target" @close="drawerClose">
+                <!-- 清表列表 -->
+                <el-scrollbar v-if="ListItemDatas.length > 0" ref="ListItemScrollRef">
+                    <CollapseForm
+                        ref="ListItemsRef"
+                        :classify="authBtnTabKey"
+                        :contract-id="contractId"
+                        :datas="ListItemDatas"
+                        :draw-type="isDrawType"
+                        :primary-key-id="primaryKeyId"
+                        :status="NodeStatus"
+                        :tenant-id="userInfo?.tenant_id"
+                        :wbs-temp-id="projectInfo?.referenceWbsTemplateIdTrial"
+                        :wbs-type="2"
+                        @offset-top="ListItemOffsetTop"
+                        @renew="getTableDataAll"
+                    />
+                </el-scrollbar>
+                <hc-status v-else text="暂无表单" />
+                <!-- 底部按钮区域 -->
+            </HcDrawer>
+        </HcNewCard>
+    </div>
+</template>
+
+<script setup>
+import { nextTick, onMounted, ref, watch } from 'vue'
+import { useRoute, useRouter } from 'vue-router'
+import { useAppStore } from '~src/store'
+import { HcIsButton } from '~src/plugins/IsButtons'
+import CollapseForm from './collapse-form/index.vue'
+import NodeTree from './components/nodeTree/index.vue'
+import HcTreeNode from './components/HcTreeNode.vue'
+import { getHeader } from 'hc-vue3-ui'
+import { getStoreValue, setStoreValue } from '~src/utils/storage'
+import {
+    arrDelKey,
+    deepClone,
+    formValidate,
+    getArrValue,
+    getObjVal,
+    getObjValue,
+    isNullES,
+    isString,
+    setCopyText,
+} from 'js-fast-way'
+import { eVisaTaskCheckApi, getDictionary, getDictionaryBiz } from '~api/other'
+import wbsApi from '~api/data-fill/wbs'
+import queryApi from '~api/data-fill/query'
+import Draggable from 'vuedraggable'
+import { HcDelMsg } from 'hc-vue3-ui'
+import HcUpload from './components/HcUpload.vue'
+import { toPdfPage } from '~uti/btn-auth'
+
+//初始变量
+const router = useRouter()
+const useRoutes = useRoute()
+const useAppState = useAppStore()
+
+//全局变量
+const projectId = ref(useAppState.projectId)
+const contractId = ref(useAppState.contractId)
+const projectInfo = ref(useAppState.projectInfo)
+const contractInfo = ref(useAppState.contractInfo)
+const isCollapse = ref(useAppState.getCollapse)
+const userInfo = ref(useAppState.getUserInfo)
+//路由参数
+const routerQuery = useRoutes?.query
+// const typeName = routerQuery?.type || 'map'
+const typeName = routerQuery?.type || 'tree'
+//是否是抽屉
+const isDrawType = ref(true)
+//自动展开缓存
+const TreeAutoExpandKeys = ref(getStoreValue('wbsTreeExpandKeys') || [])
+
+//树搜索
+const isSearchTree = ref(false)
+const wbstreeKey = ref(Math.random())
+const searchElTreeLoadNode = ref(true)
+const searchTreeHeight = ref()
+const getSearchTreeData = async () => {
+    treeLoading.value = true
+    const { error, code, data } = await queryApi.getTreeNodeByQueryValueAndContractId({
+        contractId: contractId.value,
+        queryValue: searchTreeVal.value,
+        tableOwner:authBtnTabKey.value,
+    })
+    //判断状态
+    if (!error && code === 200) {
+        let treedata = getArrValue(data)
+        searchTreeData.value = treedata
+        treeLoading.value = false
+
+    } else {
+        treeLoading.value = false
+
+        searchTreeData.value = []
+    }
+}
+
+//监听
+const searchTreeVal = ref('')
+watch(() => [
+    useAppState.getCollapse, searchTreeVal.value,
+], ([Collapse, search]) => {
+    isCollapse.value = Collapse
+    if (search.length == 0) {
+        isSearchTree.value = false
+    }
+
+})
+
+//加载树需要的classType
+const classType = ref('')
+watch(() => [
+    classType.value,
+], ([classify]) => {
+ if (classify) {
+      //重新加载左边树
+      isShowLeft.value = false
+        setTimeout(()=>{
+            isShowLeft.value = true
+        }, 500)
+ }
+
+})
+//渲染完成
+onMounted(() => {
+    console.log(projectInfo.value)
+    treeLoading.value = typeName === 'tree'
+    setContractType(contractInfo.value?.contractType)
+    getDictionaryApi()
+})
+
+//身份按钮切换数据
+const authBtnTabKey = ref('1')
+
+//变量
+const wbstree = ref(null)
+const isShowLeft = ref(true)
+const authBtnTabClick = (val) => {
+    if (!primaryKeyId.value) {
+        window?.$message?.warning('请先在左侧项目树选择一个节点')
+    } else if (val['key'] !== authBtnTabKey.value) {
+        authBtnTabKey.value = val['key']
+        //重新加载左边树
+        isShowLeft.value = false
+        setTimeout(()=>{
+            isShowLeft.value = true
+        }, 500)
+        getTableDataAll()
+    }
+}
+//contractType,  1施工,2监理
+const setContractType = (contractType) => {
+    if (contractType <= 0) {
+        authBtnTabKey.value = '1'
+        classType.value = '1'
+    } else if (contractType === 3) {
+        authBtnTabKey.value = '1'
+        classType.value = '1'
+    } else {
+        authBtnTabKey.value = contractType + ''
+        classType.value = contractType + ''
+    }
+    setElTreeMenu(contractType)
+}
+
+const getTableDataAll = async (key) => {
+    await searchNodeAllTable()
+    await queryNodeStatus()
+//     wbstree.value.resetNode().then((res)=>{
+//         if(res){
+//             searchNodeAllTable()
+//             queryNodeStatus()
+//         }
+//  })
+    //保存后自动展开到当前表单
+    if (!isNullES(key)) {
+        console.log(key)
+        await nextTick(() => {
+            ListItemRef.value?.setCollapseKey(key)
+        })
+    }
+}
+
+//结构类型tab数据和相关处理
+const wbsTypeTabKey = ref(typeName)
+const wbsTypeTab = ref([
+    { key: 'map', name: '导图结构填报' },
+    { key: 'tree', name: '树形结构填报' },
+])
+const authBtnTabdata = ref([
+    { key: '1', name: '施工质检' },
+    { key: '2', name: '监理质检' },
+])
+const wbsTypeTabChange = (item) => {
+    wbsTypeTabKey.value = item?.key
+    ListItemDatas.value = []
+    isDrawer.value = false
+    treeLoading.value = typeName === 'tree'
+    setStoreValue('classifyType', classType.value)
+    setStoreValue('tableOwner', authBtnTabKey.value)
+    //路由跳转
+    router.push({
+        path: useRoutes.path,
+        query: {
+            type: item?.key,
+            classifyType:classType.value,
+            tableOwner:authBtnTabKey.value,
+        },
+    })
+    getSearchTreeData()
+}
+//切换导图结构
+const wbsMapTypeTab = () => {
+    wbsTypeTabChange({ key: 'map', name: '导图结构填报' })
+}
+
+
+//上传文件的
+const HcUploadFileRef = ref(null)
+const uploadFileOptions = ref({})
+const uploadFileParams = ref({})
+const uploadFileEchoParams = ref({})
+//上传成功
+const uploadFileSuccess = ({ echoParams, resData }) => {
+    if (echoParams['type'] === 'upload-drawing' && resData?.link) {
+        setUploadDrawingsData(echoParams, resData?.link)
+    } else if (echoParams['type'] === 'add-fileList' && resData?.link) {
+        console.log(echoParams, 'echoParams', ' resData?.link')
+    } else {
+        window?.$message?.error('文件上传失败')
+    }
+}
+//上传完成
+const uploadFileFinish = ()=>{
+    nextTick(()=>{
+        HcUploadFileRef?.value.setModalShow(false)
+    })
+}
+//点击使用文件
+const uploadFileItem = ({ item }) => {
+    const { echoParams, resData } = item
+    if (echoParams['type'] === 'upload-drawing' && resData?.link) {
+        setUploadDrawingsData(echoParams, resData?.link)
+    } else if (echoParams['type'] === 'add-fileList' && resData?.link) {
+        console.log(echoParams, 'echoParams111', ' resData?.link111')
+    } else {
+        window?.$message?.error('文件上传失败')
+    }
+}
+
+//设置图纸数据
+const setUploadDrawingsData = async (echoParams, link) => {
+    const info = nodeDataInfo.value
+    const { error, code, data } = await wbsApi.saveContractTreeDrawings({
+        fileUrl: link,
+        id: echoParams['drawingsId'],
+        primaryKeyId: echoParams['primaryKeyId'],
+    }, false)
+    //处理数据
+    if (!error && code === 200) {
+        if (info['primaryKeyId'] === echoParams['primaryKeyId']) {
+            nodeDataInfo.value['drawingsId'] = data
+            nodeDataInfo.value['fileUrl'] = link
+            window?.$message?.success('图纸上传成功')
+        } else {
+            window?.$message?.success('图纸上传成功,由于您切换了其他节点,需要手动刷新才能查看到图纸')
+        }
+    } else {
+        window?.$message?.error('图纸保存失败')
+    }
+}
+
+const NodeTreeAccordion = ref(true)
+
+//设置树菜单数据
+const ElTreeMenu = ref([])
+const TreeMark = ref(false)
+const setElTreeMenu = (contractType) => {
+    let newArr = []
+    if (contractType === 1) {
+
+        if (HcIsButton('wbs_tree_add')) {
+            newArr.push({ icon: 'add-circle', label: '新增节点', key: 'add' })
+            newArr.push( { icon: 'add-circle', label: '新增自定义节点', key: 'add1' })
+        }
+        
+       
+        if (HcIsButton('wbs_tree_edit')) {
+            newArr.push({ icon: 'draft', label: '编辑节点', key: 'edit' })
+        }
+        if (HcIsButton('wbs_tree_copy')) {
+            newArr.push({ icon: 'file-copy-2', label: '复制节点', key: 'copy' })
+        }
+        if (HcIsButton('wbs_tree_mark')) {
+            newArr.push({ icon: 'star', label: '标记为首件', key: 'mark' })
+            TreeMark.value = true
+        }
+        if (HcIsButton('wbs_tree_upload')) {
+            newArr.push({ icon: 'file-upload', label: '上传图纸', key: 'upload' })
+        }
+        if (HcIsButton('wbs_tree_sort')) {
+            newArr.push({ icon: 'sort-asc', label: '调整排序', key: 'sort' })
+        }
+        if (HcIsButton('wbs_tree_del')) {
+            newArr.push({ icon: 'delete-bin', label: '删除节点', key: 'del' })
+        }
+        if (HcIsButton('wbs_views_division_btn')) {
+            newArr.push({ icon: 'folder-shared', label: '工程划分', key: 'nodetree' })
+        }
+    } else if (contractType === 2) {
+
+        if (HcIsButton('wbs_tree_add')) {
+            newArr.push({ icon: 'add-circle', label: '新增节点', key: 'add' })
+            newArr.push( { icon: 'add-circle', label: '新增自定义节点', key: 'add1' })
+        }
+        if (HcIsButton('wbs_tree_copy')) {
+            newArr.push({ icon: 'file-copy-2', label: '复制节点', key: 'copy' })
+        }
+    }
+    ElTreeMenu.value = newArr
+}
+
+//树相关变量
+const primaryKeyId = ref('')
+const nodeItemInfo = ref({})
+const nodeDataInfo = ref({})
+
+
+
+const searchTreeData = ref([])
+
+//回车
+const searchTreeKeyUp = (e) => {
+    if (e.key === 'Enter') {
+        searchTreeClick()
+    }
+}
+
+
+const treeLoading = ref(true)
+
+const searchTreeClick = async () => {
+    if (searchTreeVal.value) {
+        searchTreeHeight.value = document.getElementById('hc-tree-scrollbar').offsetHeight
+        isSearchTree.value = true
+        //treeLoading.value = true
+        getSearchTreeData()
+    } else {
+        isSearchTree.value = false
+    }
+}
+
+//懒加载的数据
+const treeLoadNode = async ({ node, item, level }, resolve) => {
+    let contractIdRelation = '', parentId = '', primaryKeyId = ''
+    if (level !== 0) {
+        const nodeData = getObjValue(item)
+        contractIdRelation = nodeData?.contractIdRelation || ''
+        parentId = contractIdRelation ? nodeData?.primaryKeyId : nodeData?.id
+        primaryKeyId = nodeData?.id || ''
+
+    }
+    //获取数据
+    const { data } = await queryApi.queryWbsTreeData({
+        contractId: contractId.value || '',
+        contractIdRelation,
+        primaryKeyId,
+        parentId,
+        // classifyType: authBtnTabKey.value,
+        classifyType: classType.value,
+        tableOwner:authBtnTabKey.value,
+    })
+    treeLoading.value = false
+
+    resolve(getArrValue(data))
+}
+
+//树被点击
+const wbsElTreeClick = ({ node, data, keys }) => {
+    nodeItemInfo.value = node
+    nodeDataInfo.value = data
+    primaryKeyId.value = data?.primaryKeyId || ''
+    const { notExsitChild } = data
+    const { hasChildren } = data
+    if (notExsitChild || !hasChildren) {
+        isCanadd.value = false
+        getTableDataAll()
+    } else {
+        isCanadd.value = true
+        ListItemDatas.value = []
+        NodeStatus.value = '1'
+    }
+    setStoreValue('wbsTreeExpandKeys', keys)
+    TreeAutoExpandKeys.value = keys || []
+    saveHistory(keys.join(','))
+    // getTableDataAll()
+}
+//树加载完成
+const ElTreeNodeLoading = () => {
+    treeLoading.value = false
+}
+//保存用户填报历史
+const saveHistory = async (endNode)=>{
+     await wbsApi.saveUserHistory({
+        contractId: contractId.value,
+        projectId: projectId.value,
+        endNode,
+    })
+}
+//回到上次填报历史
+const gobackHistory = async ()=>{
+    isSearchTree.value = false
+    const { error, code, data, msg } = await wbsApi.getUserHistory({
+        contractId: contractId.value,
+        projectId: projectId.value,
+    })
+    if (!error && code === 200) {
+        TreeAutoExpandKeys.value = data['endNode'].split(',') || []
+        //重新加载左边树
+        isShowLeft.value = false
+            setTimeout(()=>{
+                isShowLeft.value = true
+            }, 500)
+    } else {
+        window.$message.warning(msg)
+    }
+}
+//树菜单被点击
+const ElTreeMenuClick = async ({ key, node, data, keys }) => {
+    nodeItemInfo.value = node
+    nodeDataInfo.value = data
+    setStoreValue('wbsTreeExpandKeys', keys)
+    TreeAutoExpandKeys.value = keys || []
+    setTreeMenuDataClick({ key, node, data })
+}
+const treeMenuClick = (data)=>{
+    console.log(data, 'data1')
+}
+//导图结构数据
+const NodeTreeRef = ref(null)
+
+//鼠标左键单击事件
+const NodeTreeClick = ({ keys }) => {
+    setStoreValue('wbsTreeExpandKeys', keys)
+    TreeAutoExpandKeys.value = keys || []
+}
+
+//双击事件
+const isDrawer = ref(false)
+const NodeTreeDblClick = ({ node, data }) => {
+    nodeItemInfo.value = node
+    nodeDataInfo.value = data
+    primaryKeyId.value = data?.primaryKeyId || ''
+    isDrawer.value = true
+    getTableDataAll()
+}
+const drawerClose = () => {
+    isDrawer.value = false
+    ListItemDatas.value = []
+}
+
+//导图树菜单被点击
+const NodeTreeMenuClick = async ({ key, node, data }) => {
+    nodeItemInfo.value = node
+    nodeDataInfo.value = data
+    setTreeMenuDataClick({ key, node, data })
+}
+
+//处理菜单被点击数据
+const setTreeMenuDataClick = ({ key, node, data }) => {
+    const tabKey = wbsTypeTabKey.value
+    if (key === 'mark' || key === 'cancel_mark') {
+        firstItemBox()
+    } else if (key === 'edit') {
+        console.log(data, 'data')
+        let form = {}
+        if (tabKey === 'tree') {
+            const parent = deepClone(node?.parent?.data || {})
+            form = { ...deepClone(data), parent: parent }
+        } else if (tabKey === 'map') {
+            const parent = deepClone(node?.parentNodes?.data || {})
+            form = { ...deepClone(data), parent: parent }
+        }
+        formEditNodeModel.value = form
+        editNodeModal.value = true
+        //处理路径
+        let pathArr = []
+        getPathName(node, pathArr)
+        form.position = pathArr.join('\\')
+        formEditNodeModel.value = form
+    } else if (key === 'copy') {
+        if (tabKey === 'tree') {
+            const parent = deepClone(node?.parent?.data || {})
+            formCopyNodeModel.value = { ...deepClone(data), parent: parent }
+        } else if (tabKey === 'map') {
+            const parent = deepClone(node?.parentNodes?.data || {})
+            formCopyNodeModel.value = { ...deepClone(data), parent: parent }
+        }
+        classifyType.value = authBtnTabKey.value
+        copyNodeTabKey.value = '1'
+        copyNodeTable.value = []
+        copyNodeLoading.value = false
+        copyNodeModal.value = true
+    } else if (key === 'add') {
+        const { childNodes } = node
+        console.log(childNodes, 'childNodes')
+
+        isCustom.value = data?.isCustom
+        addTreeNodeId.value = data?.primaryKeyId
+        addTreeNodeOldId.value = data?.oldId
+        addNodeLoading.value = false
+        addNodeModal.value = true
+    } else if (key === 'add1') {
+
+
+            addTreeNodeId.value = data?.primaryKeyId
+            addTreeNodeOldId.value = data?.oldId
+            addNodeLoading.value = false
+            nodeNameinput.value = ''
+            addNodeModalCus.value = true
+
+
+    } else if (key === 'upload') {
+        const info = nodeDataInfo.value
+        //上传的配置
+        uploadFileOptions.value = {
+            url: '/api/blade-resource/oss/endpoint/put-file',
+            accept: 'image/png,image/jpg,image/jpeg',
+            accept_tip: 'png、jpg、jpeg',
+            headers: getHeader(),
+            multiple: false,
+        }
+        uploadFileEchoParams.value = {
+            type: 'upload-drawing',
+            drawingsId: info['drawingsId'],
+            primaryKeyId: info['primaryKeyId'],
+        }
+        uploadFileParams.value = {}
+        HcUploadFileRef.value?.selectFile()
+    } else if (key === 'del') {
+        console.log(data, 'data')
+        if (data['colorStatus'] === 1 || data['colorStatus'] === 2 || data['colorStatus'] === null || data['colorStatus'] === -1) {
+            delModalClick()
+        } else {
+            window?.$message?.warning('该节点已存在上报数据,不允许删除')
+        }
+    } else if (key === 'sort') {
+        let nodes = [], childNodes = []
+        if (tabKey === 'tree') {
+            childNodes = node?.parent?.childNodes || node?.parent?.children || []
+        } else if (tabKey === 'map') {
+            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
+    } else if (key === 'nodetree') {
+        divisionClick()
+    }
+}
+
+//获取节点的路径名字
+const getPathName = (node, pathArr) => {
+    if (node.parent?.parent) {
+        pathArr.unshift(node.data?.title.replace(/(^\s*)|(\s*$)/g, '')) //去掉头尾空格
+        getPathName(node.parent, pathArr)
+    } else {
+        //根节点结束
+        pathArr.unshift(node.data?.title.replace(/(^\s*)|(\s*$)/g, '')) //去掉头尾空格
+        return pathArr
+    }
+}
+
+//确认标记为首件
+const firstItemBox = () => {
+    const info = nodeDataInfo.value
+    window?.$messageBox?.alert(`<div class="text-base font-bold">
+            <span>请确认将</span>
+            <span class="text-main">【${info['title']}】</span>
+            <span>${info['isFirst'] ? '取消' : ''}标记为首件</span>
+        </div>`, '标记首件制', {
+        showCancelButton: true,
+        dangerouslyUseHTMLString: true,
+        callback: (action) => {
+            if (action === 'confirm') {
+                firstItemHttp(info)
+            }
+        },
+    })
+}
+//首件请求
+const firstItemHttp = async (info) => {
+    const { error, code, msg } = await wbsApi.wbsTreeFirstSave({
+        primaryKeyId: info['primaryKeyId'],
+        saveOrDeleted: info['isFirst'] ? 1 : 0,
+    })
+    //处理数据
+    if (!error && code === 200) {
+        window?.$message?.success('操作成功')
+        window?.location?.reload() //刷新页面
+    } else {
+       window?.$message?.error(msg)
+     }
+}
+
+//编辑节点
+const editNodeModal = ref(false)
+
+//获取节点类型
+const nodeTypeData = ref([])
+const getDictionaryApi = async () => {
+    const { data } = await getDictionary({
+        code: 'wbs_node_type',
+    })
+    //处理数据
+    let newArr = []
+    const newData = getArrValue(data)
+    for (let i = 0; i < newData.length; i++) {
+        newArr.push({
+            label: newData[i]['dictValue'],
+            value: Number(newData[i]['dictKey']),
+        })
+    }
+    nodeTypeData.value = newArr
+}
+
+const formEditNodeRef = ref(null)
+const formEditNodeModel = ref({
+    title: '',
+    parent: {
+        title: '',
+    },
+    nodeType: null,
+    partitionCode: '',
+    position: '',
+})
+const formEditNodeRules = {
+    title: {
+        required: true,
+        trigger: 'blur',
+        message: '请输入节点名称',
+    },
+}
+const editNodeLoading = ref(false)
+//保存编辑节点数据
+const editNodeClick = async () => {
+    const validate = await formValidate(formEditNodeRef.value)
+    if (validate) {
+        //发起请求
+        editNodeLoading.value = true
+        const { primaryKeyId, title, partitionCode } = formEditNodeModel.value
+        const { error, code, msg } = await wbsApi.wbsTreeUpdateNode({
+            nodeName: title || '',
+            pKeyId: primaryKeyId || '',
+            partitionCode: partitionCode || '',
+        })
+        //处理数据
+        editNodeLoading.value = false
+        if (!error && code === 200) {
+            window?.$message?.success('修改成功')
+            nodeDataInfo.value['title'] = title || ''
+            nodeDataInfo.value['partitionCode'] = partitionCode || ''
+            editNodeModal.value = false
+            window?.location?.reload() //刷新页面
+        } else {
+                window?.$message?.error(msg)
+            }
+    }
+}
+
+//复制节点
+const copyNodeModal = ref(false)
+
+//复制节点类型tab数据和相关处理
+const copyNodeTabKey = ref('')
+const copyNodeTab = ref([
+    { key: '1', name: '单份复制' },
+    { key: '2', name: '多份复制' },
+    //{key: '3', name: '复制数据'}
+])
+const copyNodeTabChange = (key) => {
+    if (key !== copyNodeTabKey.value) {
+        copyNodeTabKey.value = key
+        copyNodeTable.value = []
+        copyNodeLoading.value = false
+    }
+}
+
+//复制节点变量
+const copyNodeLoading = ref(false)
+const formCopyNodeModel = ref({})
+const classifyList = ref([])
+const copyNodeTable = ref([])
+const isCopyData = ref(0)
+
+//复制树被点击
+const copyNodeElTreeClick = ({ data, node }) => {
+    const TabKey = copyNodeTabKey.value
+    const { title, type, partitionCode } = formCopyNodeModel.value
+    if (TabKey === '2') {
+        // setCopyNodeTable(data, title, partitionCode)
+        //1 单位工程,2 分部工程,3 子分部工程,4 分项工程, 5 子分项工程,6 工序
+//         //不能复制到本身节点下
+//         //只能往上一级点击,不能跨层级点击
+//         //已上报的工序节点不能点击选择
+//         //如果选择的是父级节点,那不能复制到子级节点
+        const { hasChildren } = data
+        if (hasChildren === 0) {
+            if (data['colorStatus'] === 2 || data['colorStatus'] == 1 || data['colorStatus'] === null || data['colorStatus'] === -1) {//已上报的工序不能点击
+                if (data['id'] !== formCopyNodeModel.value.id) {//不能复制到本身节点下
+                    //只能往上一级点击,不能跨层级点击
+                    //如果选择的是父级节点,那不能复制到子级节点
+                    if (type === 6 && (data['type'] === 4 || data['type'] === 5 || data['type'] == 6)) {
+                        setCopyNodeTable(data, title)
+                    }
+                    if (type === 5 && data['type'] === 4) {
+                        setCopyNodeTable(data, title, partitionCode)
+                    }
+                    if (type === 4 && (data['type'] === 2 || data['type'] === 3)) {
+                        setCopyNodeTable(data, title, partitionCode)
+                    }
+                    if (type === 3 && data['type'] === 2) {
+                        setCopyNodeTable(data, title, partitionCode)
+                    }
+                    if (type === 2 && data['type'] === 1) {
+                        setCopyNodeTable(data, title, partitionCode)
+                    }
+                    if (type === 1 && data['type'] === 1) {
+                        setCopyNodeTable(data, title, partitionCode)
+                    }
+
+
+                }
+            } else {
+                window?.$message?.warning('该节点已存在上报数据,不允许复制')
+            }
+        } else {
+            if (data['id'] !== formCopyNodeModel.value.id) {//不能复制到本身节点下
+                    //只能往上一级点击,不能跨层级点击
+                    //如果选择的是父级节点,那不能复制到子级节点
+                    if (type === 6 && (data['type'] === 4 || data['type'] === 5 || data['type'] == 6)) {
+                        setCopyNodeTable(data, title)
+                    }
+                    if (type === 5 && data['type'] === 4) {
+                        setCopyNodeTable(data, title, partitionCode)
+                    }
+                    if (type === 4 && (data['type'] === 2 || data['type'] === 3)) {
+                        setCopyNodeTable(data, title, partitionCode)
+                    }
+                    if (type === 3 && data['type'] === 2) {
+                        setCopyNodeTable(data, title, partitionCode)
+                    }
+                    if (type === 2 && data['type'] === 1) {
+                        setCopyNodeTable(data, title, partitionCode)
+                    }
+                    if (type === 1 && data['type'] === 1) {
+                        setCopyNodeTable(data, title, partitionCode)
+                    }
+
+
+                }
+        }
+
+
+
+    } else if (TabKey === '3') {
+        console.log(1111111)
+        setCopyNodeTable(data, data?.title)
+
+
+    }
+}
+
+
+const setCopyNodeTable = (data, title) => {
+    copyNodeTable.value.push({
+        title: data?.title || '',
+        nodeName: title || '',
+        primaryKeyId: data?.primaryKeyId || '',
+        parentId: data?.parentId || '',
+        id: data?.id || '',
+
+    })
+}
+
+//节点表单
+const formCopyNodeModelRef = ref(null)
+const formCopyNodeModelRules = {
+    title: {
+        required: true,
+        trigger: 'blur',
+        message: '请输入节点名称',
+    },
+}
+//表格节点表单
+const copyNodeTableRef = ref(null)
+const copyNodeTableRules = {
+    nodeName: {
+        required: true,
+        trigger: 'blur',
+        message: '请输入节点名称',
+    },
+}
+//删除选中的节点
+const copyNodeTableDel = (index) => {
+    copyNodeTable.value.splice(index, 1)
+}
+
+
+const classifyType = ref(authBtnTabKey.value)
+const classifyTypeTabClick = ({ key }) => {
+    classifyType.value = key
+}
+
+//复制节点
+const copyNodeClick = async () => {
+    const type = copyNodeTabKey.value
+    const form = formCopyNodeModel.value
+    const table = copyNodeTable.value
+    let classify = ''
+    let arr = []
+    if (classifyList.value.length > 0) {
+        classifyList.value.forEach((item) => {
+            if (item === '施工') {
+                arr.push(1)
+            } else if (item === '监理') {
+                arr.push(2)
+            }
+        })
+        classify = arr.join(',')
+    }
+    //isSameNode 是否同节点 1=同节点,0=跨节点
+    if (table.length > 0) {
+        table.forEach((ele) => {
+            if (ele.parentId === formCopyNodeModel.value.parentId || ele.id === formCopyNodeModel.value.parentId) {
+                ele.isSameNode = 1
+            } else {
+                ele.isSameNode = 0
+            }
+        })
+    }
+    if (isCopyData.value === 1) {
+        if (classify) {
+            //效验数据
+            if (type === '1') {
+                const validate = await formValidate(formCopyNodeModelRef.value)
+                if (validate) await copyContractTreeNode(type, form, [], classify)
+            } else if (type === '2') {
+                if (table.length > 0) {
+                    const validate = await formValidate(copyNodeTableRef.value)
+                    if (validate) await copyContractTreeNode(type, form, table, classify)
+                } else {
+                    window?.$message?.warning('请先在左侧选择要复制到的节点')
+                }
+            }
+        } else {
+            window?.$message?.warning('请选择所属方')
+        }
+    } else {
+        if (type === '1') {
+            const validate = await formValidate(formCopyNodeModelRef.value)
+            if (validate) await copyContractTreeNode(type, form, [], classify)
+        } else if (type === '2') {
+            if (table.length > 0) {
+                const validate = await formValidate(copyNodeTableRef.value)
+                if (validate) await copyContractTreeNode(type, form, table, classify)
+            } else {
+                window?.$message?.warning('请先在左侧选择要复制到的节点')
+            }
+        }
+    }
+}
+//单个复制、多份复制请求
+const copyContractTreeNode = async (type, form, table, classify) => {
+    copyNodeLoading.value = true
+    if (type === '1') {
+        const { error, code, msg } = await wbsApi.copyContractTreeNode({
+            copyType: type,
+            needCopyNodeName: form?.title || '',
+            partitionCode: form?.partitionCode || '',
+            needCopyPrimaryKeyId: form?.primaryKeyId || '',
+            parentPrimaryKeyId: form?.parent?.primaryKeyId || '',
+            copyBatchToPaths: table,
+            classifyType: classify,
+            isCopyData:isCopyData.value,
+        })
+        //判断状态
+        copyNodeLoading.value = false
+        if (!error && code === 200) {
+            window?.$message?.success('复制成功')
+            copyNodeModal.value = false
+            window?.location?.reload() //刷新页面
+        } else {
+                window?.$message?.error(msg)
+         }
+    } else {
+        const { error, code, msg } = await wbsApi.copyContractTreeNode({
+            copyType: type,
+            needCopyNodeName: form?.title || '',
+            needCopyPrimaryKeyId: form?.primaryKeyId || '',
+            parentPrimaryKeyId: form?.parent?.primaryKeyId || '',
+            copyBatchToPaths: table,
+            classifyType: classify,
+            isCopyData:isCopyData.value,
+        })
+        //判断状态
+        copyNodeLoading.value = false
+        if (!error && code === 200) {
+            window?.$message?.success('复制成功')
+            copyNodeModal.value = false
+            window?.location?.reload() //刷新页面
+        } else {
+                window?.$message?.error(msg)
+         }
+    }
+}
+//复制数据
+const copyContractNodeSubmitBusinessData = async (form, table, classify) => {
+    copyNodeLoading.value = true
+    const { error, code } = await wbsApi.copyContractNodeSubmitBusinessData({
+        needCopyPrimaryKeyId: form?.primaryKeyId || '',
+        copyBatchToPaths: table,
+        classify: classify,
+    })
+    //判断状态
+    copyNodeLoading.value = false
+    if (!error && code === 200) {
+        window?.$message?.success('复制成功')
+        copyNodeModal.value = false
+        window?.location?.reload() //刷新页面
+    }
+}
+
+//新增节点
+const addNodeModal = ref(false)
+const addTreeNodeId = ref('')
+const addTreeNodeOldId = ref('')
+const addTreeNodeType = ref('1')
+const isCustom = ref(null)
+
+
+//新增自定义节点
+const addNodeModalCus = ref(false)
+const addNodeLoadingCus = ref(false)
+const nodeNameinput = ref('')
+//选中的节点
+const allSelectedList = ref([])
+const halfSelectedList = ref([])
+const addTreeNodeCheckChange = (nodes) => {
+    let NodesArr = [], halfArr = []
+    //全选数据
+    const keys = nodes.checkedNodes || []
+    console.log(keys, 'keys')
+    for (let i = 0; i < keys.length; i++) {
+        NodesArr.push({
+            nodeName: keys[i].nodeName,
+            primaryKeyId: keys[i].pKeyId,
+            isPeer:keys[i].isPeer || 2,
+        })
+    }
+    allSelectedList.value = NodesArr
+    console.log( allSelectedList.value, ' allSelectedList.value')
+    //半选数据
+    const halfNodes = nodes.halfCheckedNodes || []
+    for (let i = 0; i < halfNodes.length; i++) {
+        halfArr.push({
+            nodeName: halfNodes[i].nodeName,
+            primaryKeyId: halfNodes[i].pKeyId,
+            isPeer:halfNodes[i].isPeer || 2,
+        })
+    }
+    halfSelectedList.value = halfArr
+    console.log( halfSelectedList.value, ' halfSelectedList.value')
+}
+
+//新增节点
+const addNodeLoading = ref(false)
+const addNodeClick = async () => {
+    const keys = allSelectedList.value || []
+    if (keys.length <= 0) {
+        window?.$message?.warning('请先选择节点')
+    } else {
+         //发起请求
+         addNodeLoading.value = true
+            const primaryKeyId = nodeDataInfo.value?.primaryKeyId || ''
+            const { error, code } = await wbsApi.saveContractTreeNode({
+                projectId: projectId.value,
+                contractId: contractId.value,
+                saveType: addTreeNodeType.value,
+                allSelectedList: allSelectedList.value,
+                halfSelectedList: halfSelectedList.value,
+                currentNodePrimaryKeyId: primaryKeyId,
+            })
+            //判断状态
+            addNodeLoading.value = false
+            if (!error && code === 200) {
+                window?.$message?.success('新增成功')
+                addNodeModal.value = false
+                window?.location?.reload() //刷新页面
+            }
+        }
+    }
+const addNodeClickCur = async ()=>{
+             //发起请求
+             addNodeLoadingCus.value = true
+            const { error, code, msg } = await wbsApi.saveCustomAddContractNode({
+                nodeName: nodeNameinput.value,
+                nodeType: nodeDataInfo.value?.nodeType || '',
+                partitionCode: nodeDataInfo.value?.partitionCode || '',
+                primaryKeyId: nodeDataInfo.value?.primaryKeyId || '',
+            })
+            //判断状态
+            addNodeLoadingCus.value = false
+            if (!error && code === 200) {
+                window?.$message?.success('新增成功')
+                addNodeModalCus.value = false
+                window?.location?.reload() //刷新页面
+            } else {
+                window?.$message?.error(msg)
+            }
+}
+
+//删除节点
+const delModalClick = () => {
+    HcDelMsg(async (resolve) => {
+        await removeContractTreeNode()
+        resolve() //关闭弹窗的回调
+    })
+}
+
+const removeContractTreeNode = async () => {
+    const loadingInstance = window.$loading.service({
+        fullscreen: true,
+        text: '删除节点中,请耐心等待...',
+        background: 'rgba(0, 0, 0, 0.7)',
+    })
+    const { error, code, msg } = await wbsApi.removeContractTreeNode({
+        ids: nodeDataInfo.value?.primaryKeyId || '',
+    })
+    //处理结果
+    loadingInstance.close()
+    if (!error && code === 200) {
+        window?.$message?.success('删除成功')
+        window?.location?.reload() //刷新页面
+    } else {
+        window.$message.error(msg)
+    }
+}
+
+//调整排序
+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 { error, code, msg } = await wbsApi.diySortTreeNode({ sortList })
+    sortNodeLoading.value = false
+    //判断状态
+    if (!error && code === 200) {
+        window?.$message?.success('保存成功')
+        sortNodeModal.value = false
+        window?.location?.reload() //刷新页面
+    } else {
+        window.$message.error(msg)
+    }
+}
+
+//查看图纸
+const drawList = ref('')
+const drawingsShow = ref(false)
+const viewsDrawings = () => {
+    const { primaryKeyId, drawingsId } = nodeDataInfo.value
+    if (!primaryKeyId) {
+        window?.$message?.warning('请先选择树节点')
+    } else if (drawingsId === -1 || drawingsId === null) {
+        window?.$message?.warning('该节点暂未上传图纸')
+    } else {
+        drawingsShow.value = true
+        getDrawList(drawingsId)
+    }
+}
+const drawingsClose = (res) => {
+    drawingsShow.value = res
+}
+const getDrawList = async (primaryKeyId)=>{
+    const { error, code, data } = await wbsApi.getTreeDrawings({ primaryKeyId })
+       //判断状态
+       if (!error && code === 200) {
+            drawList.value = data
+       } else {
+        drawList.value = data
+       }
+}
+
+//设置滚动条位置
+const ListItemScrollRef = ref(null)
+const ListItemOffsetTop = (offsetTop) => {
+    if (offsetTop > 0) {
+        setTimeout(() => {
+            ListItemScrollRef.value?.setScrollTop(offsetTop)
+        }, 350)
+    } else {
+        ListItemScrollRef.value?.setScrollTop(offsetTop)
+    }
+}
+
+//获取数据列表
+const ListItemDatas = ref([])
+const ListItemLoading = ref(false)
+const searchNodeAllTable = async () => {
+    ListItemLoading.value = true
+    ListItemDatas.value = []
+    const info = nodeDataInfo.value
+    const { data } = await wbsApi.searchNodeAllTable({
+        projectId: projectId.value,
+        contractId: contractId.value,
+        primaryKeyId: info['primaryKeyId'],
+        type: authBtnTabKey.value,
+    })
+    ListItemDatas.value = getArrValue(data)
+    ListItemLoading.value = false
+}
+
+const newlistdata = ref([])
+const searchNodeAllTable1 = async () => {
+  console.log('重新获取表单列表')
+    const info = nodeDataInfo.value
+    const { data } = await wbsApi.searchNodeAllTable({
+        projectId: projectId.value,
+        contractId: contractId.value,
+        primaryKeyId: info['primaryKeyId'],
+        type: authBtnTabKey.value,
+    })
+    newlistdata.value = getArrValue(data)
+}
+//查询状态
+const NodeStatus = ref('1')
+const queryNodeStatus = async () => {
+    const info = nodeDataInfo.value
+    if (contractInfo.value?.contractType == 1) {
+        const { error, code, data } = await wbsApi.queryNodeStatus({
+            primaryKeyId: info['primaryKeyId'],
+            //classify:1
+            classify: authBtnTabKey.value,
+        })
+        //1 未填报,2待上报,3已上报
+        if (!error && code === 200) {
+            NodeStatus.value = data ?? '1'
+        } else {
+            NodeStatus.value = '1'
+        }
+    } else {
+        const { error, code, data } = await wbsApi.queryNodeStatusJl({
+            // primaryKeyId: info['contractIdRelation'] ? info['id'] : info['primaryKeyId'],
+            primaryKeyId: info['primaryKeyId'],
+            //classify: 1
+            classify: authBtnTabKey.value,
+        })
+        //1 未填报,2待上报,3已上报
+        if (!error && code === 200) {
+            NodeStatus.value = data ?? '1'
+        } else {
+            NodeStatus.value = '1'
+        }
+    }
+}
+
+//批量上报
+const reportIds = ref('')
+const reportTaskName = ref('')
+const reportAddition = ref({})
+const showReportModal = ref(false)
+const reportLoading = ref(false)
+const reportTypeData = ref([])
+const reportModalClick = async () => {
+    const info = nodeDataInfo.value
+    const rows = ListItemDatas.value
+    if (rows.length > 0) {
+        reportLoading.value = true
+        const taskCheck = await eVisaTaskCheckApi({
+            projectId: projectId.value,
+            contractId: contractInfo.value?.contractType == 2 ? info?.contractIdRelation : contractId.value,
+            // contractId: contractId.value
+        })
+        //处理数据
+        let newArr = []
+        for (let i = 0; i < rows.length; i++) {
+            newArr.push(rows[i]['isTypePrivatePid'])
+        }
+        reportTypeData.value = newArr
+        reportLoading.value = false
+        if (taskCheck) {
+            //初始弹出弹窗,防呆
+            reportIds.value = info['primaryKeyId']
+            reportAddition.value = {
+                classify: authBtnTabKey.value,
+                contractIdRelation: info['contractIdRelation'],
+            }
+            showReportModal.value = true
+            //请求文件题名
+            const { data } = await wbsApi.queryDocumentTitle({
+                primaryKeyId: info['primaryKeyId'],
+                classify: authBtnTabKey.value,
+            })
+            reportTaskName.value = isString(data) ? data : ''
+        }
+    } else {
+        window.$message?.warning('暂无相关数据')
+    }
+}
+
+//上报完成
+const showReportFinish = () => {
+    showReportModal.value = false
+    getTableDataAll()
+    // window?.location?.reload()  //刷新页面
+
+}
+
+//表单变量
+const ListItemRef = ref(null)
+const ListItemsRef = ref(null)
+
+//保存
+const tableFormSaveLoading = ref(false)
+const tableFormSaveClick = async () => {
+    //获取数据
+    let FormData = [], FormRegExpJson = {}
+    if (isDrawer.value) {
+        FormData = await ListItemsRef.value?.getFormData()
+        FormRegExpJson = await ListItemsRef.value?.getFormRegExpJson()
+    } else {
+
+        FormData = await ListItemRef.value?.getFormData()
+        FormRegExpJson = await ListItemRef.value?.getFormRegExpJson()
+    }
+    //效验数据
+    if (getObjVal(FormRegExpJson)) {
+        setFormRegExpJson(FormRegExpJson)
+    } else if (FormData.length > 0) {
+        console.log('保存')
+        tableFormSaveLoading.value = true
+        console.log('FormData', FormData)
+        const { error, code, msg } = await wbsApi.saveExcelBussData({
+            dataInfo: { orderList: FormData },
+        })
+        tableFormSaveLoading.value = false
+        if (!error && code === 200) {
+            window?.$message?.success('保存成功')
+            // await bussPdfsClick()
+             const activeKey = ListItemRef.value?.getActiveKey()
+            getTableDataAll(activeKey)
+        } else {
+            window?.$message?.error(msg || '操作失败')
+        }
+    } else {
+        console.log('预览')
+        // await bussPdfsClick()
+    }
+}
+
+//效验数据
+const setFormRegExpJson = (FormRegExpJson) => {
+    let nodeName = '', itemId = ''
+    Object.keys(FormRegExpJson).forEach(key => {
+        const name = FormRegExpJson[key]?.nodeName ?? ''
+        if (name) {
+            if (nodeName) {
+                nodeName += ',' + name
+            } else {
+                nodeName = name
+                itemId = FormRegExpJson[key]?.itemId
+            }
+        }
+    })
+    //const activeKey = ListItemRef.value?.getActiveKey()
+    //弹出提示
+    const val = '<div style="font-size: 16px;">请先完善  <span style="color:#1ECC95;">' + nodeName + '</span>  的数据内容</div>'
+    window?.$messageBox?.alert(val, '表单完善提醒', {
+        confirmButtonText: '确定',
+        dangerouslyUseHTMLString: true,
+        callback: (action) => {
+            if (action === 'confirm') {
+                ListItemRef.value?.setActiveKey(itemId)
+                ListItemOffsetTop(0)
+                setTimeout(() => {
+                    const offsetTop = document.getElementById(itemId)?.offsetTop
+                    ListItemOffsetTop(offsetTop)
+                }, 350)
+            }
+        },
+    })
+}
+
+
+//多表预览
+const bussPdfsLoading = ref(false)
+const bussPdfsClick = async () => {
+    const info = nodeDataInfo.value
+    bussPdfsLoading.value = true
+    const { error, code, data } = await wbsApi.getBussPdfs({
+        nodeId: info?.primaryKeyId || '',
+        classify: authBtnTabKey.value,
+        projectId: projectId.value,
+        // contractId: contractId.value
+        contractId: contractInfo.value?.contractType == 2 ? info?.contractIdRelation : contractId.value,
+    })
+    tableFormSaveLoading.value = false
+    bussPdfsLoading.value = false
+    if (!error && code === 200) {
+        toPdfPage(data)
+        //window.open(data, '_blank')
+    } else {
+        window.$message?.warning('获取PDF失败')
+    }
+}
+
+//撤回上报流程
+const abolishLoaing = ref(false)
+const abolishOneClick = () => {
+    window?.$messageBox?.alert('请谨慎考虑后,是否确定撤回?', '撤回上报', {
+        showCancelButton: true,
+        confirmButtonText: '确定撤回',
+        cancelButtonText: '取消',
+        callback: (action) => {
+            if (action === 'confirm') {
+                abolishOneSave()
+            }
+        },
+    })
+}
+
+//撤回请求
+const abolishOneSave = async () => {
+    const info = nodeDataInfo.value
+    abolishLoaing.value = true
+    const { error, code } = await wbsApi.abolishOne({
+        primaryKeyId: info?.primaryKeyId || '',
+        classify: authBtnTabKey.value,
+        projectId:projectId.value,
+        contractId:contractId.value,
+    })
+    abolishLoaing.value = false
+    if (!error && code === 200) {
+        window.$message?.success('撤回成功')
+        getTableDataAll()
+        window?.location?.reload() //刷新页面
+
+    }
+}
+
+//附件列表
+const attachmentModal = ref(false)
+const attachmentModalShow = () => {
+    attachmentModal.value = true
+    getAttachmentList()
+}
+const attachmentListLoaing = ref(false)
+const attachmentList = ref([])
+const getAttachmentList = async ()=>{
+    attachmentListLoaing.value = true
+    const info = nodeDataInfo.value
+    const { error, code, data } = await wbsApi.tablesAndFile({
+        primaryKeyId: info?.primaryKeyId || '',
+        type: authBtnTabKey.value,
+        contractId:contractId.value,
+        projectId:projectId.value,
+    })
+    attachmentListLoaing.value = false
+    if (!error && code === 200) {
+        attachmentList.value = getArrValue(data)
+
+
+    } else {
+        attachmentList.value = []
+    }
+ }
+ //预览
+ const previewFile = (item)=>{
+     toPdfPage(item['domainPdfUrl'])
+    //window.open(item['domainPdfUrl'], '_blank')
+ }
+ //删除
+ const delFile = async (item)=>{
+    item.loading = true
+    const { error, code, msg } = await wbsApi.removeBussFile({
+        ids: item.id,
+    })
+    item.loading = false
+    if (!error && code === 200) {
+        window?.$message?.success('删除成功')
+        getAttachmentList()
+        getTableDataAll()
+        return true
+    } else {
+        window.$message.error(msg)
+        return false
+    }
+ }
+//划分变更
+const divisionClick = () => {
+    router.push({
+        path: '/data-fill/division',
+    })
+}
+
+//树展开和收起
+const isWbsTreeShow = ref(true)
+const setWbsTreeShow = () => {
+    isWbsTreeShow.value = !isWbsTreeShow.value
+}
+
+//拷贝内容
+const copyPositionText = (val) => {
+    if (val) {
+        //navigator.clipboard.writeText(val);
+        setCopyText(val).then(() => {
+            window.$message?.success('复制成功')
+        }).catch(() => {
+            window.$message?.error('复制失败,请手动复制')
+        })
+    } else {
+        window.$message?.warning('没有可复制的数据')
+    }
+}
+
+//左右拖动,改变树形结构宽度
+const leftWidth = ref(382)
+const isMouseTree = ref(false)
+const onmousedown = () => {
+    const leftNum = isCollapse.value ? 142 : 272
+    isMouseTree.value = true
+    document.onmousemove = (ve) => {
+        let diffVal = ve.clientX - leftNum
+        if (diffVal >= 310 && diffVal <= 900) {
+            leftWidth.value = diffVal
+        }
+    }
+    document.onmouseup = () => {
+        document.onmousemove = null
+        document.onmouseup = null
+        isMouseTree.value = false
+    }
+}
+//同步质检资料
+const syncdataloading = ref(false)
+const syncdata = async ()=>{
+    ListItemRef.value?.setActiveKey('')
+    const info = nodeDataInfo.value
+    syncdataloading.value = true
+    const { error, code, msg } = await wbsApi.syncTbadata({
+        pKeyId: info?.primaryKeyId || '',
+
+    })
+    syncdataloading.value = false
+    if (!error && code === 200) {
+        window.$message?.success(msg)
+        getTableDataAll()
+
+        // window?.location?.reload()  //刷新页面
+
+    }
+}
+//附件添加
+
+const typeoptions = ref([
+{
+    value: '1',
+    label: '模板1',
+  },
+  {
+    value: '2',
+    label: '模板2',
+  },
+])
+const getFileTypeApi = async () => {
+    const { data } = await getDictionaryBiz({
+        code: 'table_file_type',
+    })
+    //处理数据
+    let newArr = []
+    const newData = getArrValue(data)
+    for (let i = 0; i < newData.length; i++) {
+        newArr.push({
+            label: newData[i]['dictValue'],
+            value: Number(newData[i]['dictKey']),
+        })
+    }
+    typeoptions.value = newArr
+}
+const typevalue = ref('')
+
+const isCanadd = ref(true)
+ const uploadModal = ref(false)
+ const fileListData = ref([])
+const uploadData = ref({})
+const uploadModalClose = ()=>{
+    uploadModal.value = false
+    typevalue.value = ''
+ }
+
+
+//获取附件添加列表
+const getBussFileList = async (pkeyId) => {
+    const { error, code, data } = await wbsApi.selectTableFileListByTen({
+        pkeyid: pkeyId,
+    })
+    if (!error && code === 200) {
+        fileListData.value = getArrValue(data)
+    } else {
+        fileListData.value = []
+    }
+}
+const addFilelist = async ()=>{
+    getBussFileList(primaryKeyId.value)
+     uploadModal.value = true
+    await getFileTypeApi()
+
+       //上传的配置
+       uploadData.value = {
+                classify:authBtnTabKey.value,
+                nodeId: primaryKeyId.value,
+                type:typevalue.value,
+                contractId:contractId.value,
+            }
+
+}
+const changeType = (val)=>{
+    uploadData.value.type = val
+}
+//上传文件
+const uploadChange = async ({ type }) => {
+    if (type === 'success') {
+        getBussFileList(primaryKeyId.value)
+    } else if (type === 'del') {
+        getBussFileList(primaryKeyId.value)
+    }
+}
+
+//树节点被选中
+const treeSelectNode = ref([])
+const ElTreeNodeCheck = (_, { checkedKeys }) => {
+    treeSelectNode.value = getArrValue(checkedKeys)
+}
+const loadMenu = ({ node, item, level }, resolve)=>{
+    setElTreeMenu(contractInfo.value?.contractType)
+    let menusArr = ElTreeMenu.value
+    const { isCustomChild, notExsitChild } = item //isCustomChild===1//代表子级是自定义节点
+    // const { isCustom } = item
+    // if (isCustom === 1 && isCustomChild === 0 && notExsitChild) {//无子级,显示两个按钮
+    //     menusArr.unshift( { icon: 'add-circle', label: '新增自定义节点', key: 'add1' })
+    //     resolve(menusArr)
+    // } else if (isCustom === 1 && isCustomChild === 1) {//自定义节点类型下如果有自定义节点,就不允许新增节点
+    //     menusArr.unshift( { icon: 'add-circle', label: '新增自定义节点', key: 'add1' })
+    //     let menusArr1 = arrDelKey(menusArr, 'label', '新增节点') // [{id:1}]
+    //     resolve(menusArr1)
+    // } else if (isCustom === 1 && isCustomChild === 0 && !notExsitChild) { //自定义节点类型下如果有划分节点,就不允许新增自定义节点
+    //     resolve(menusArr)
+    // } else if (level === 1) {
+    //     menusArr = [ { icon: 'add-circle', label: '新增自定义节点', key: 'add1' }]
+    //     resolve(menusArr)
+    // } else {
+    //     resolve(menusArr)
+    // }
+    if (level === 1) {
+        menusArr = [ { icon: 'add-circle', label: '新增自定义节点', key: 'add1' }]
+        resolve(menusArr)
+    } else {
+        resolve(menusArr)
+    }
+}
+</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;
+    }
+}
+.hc-expansion-contraction-tree {
+    position: absolute;
+    left: -13px;
+    top: 0;
+    width: 10px;
+    height: 100%;
+    user-select: none;
+    cursor: pointer;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    color: #8c9099;
+    font-size: 22px;
+    border-radius: 5px;
+    transition: background 0.2s;
+    background: rgba(255, 255, 255, 0);
+    &:hover {
+        background: #f1f5f8;
+        color: var(--el-color-primary);
+    }
+}
+.hc-table-form-action-tip {
+    position: absolute;
+    bottom: 77px;
+    width: 100%;
+}
+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">
+.hc-tree-box .el-tree-node {
+    .el-checkbox {
+        margin-right: 0;
+        .el-checkbox__inner {
+            display: none;
+        }
+    }
+    .is-leaf + .el-checkbox {
+        margin-right: 8px;
+        .el-checkbox__inner {
+            display: inline-block;
+        }
+    }
+}
+
+.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;
+    }
+}
+.img-preview-box {
+    position: relative;
+    height: 100%;
+    width: 100%;
+}
+.hc-layout-content-box {
+    position: relative;
+}
+
+.iscusor {
+    cursor: pointer;
+}
+.hc-table-form-action-tip .hc-alert {
+    background-color: #f1f5f8;
+    display: inline;
+    vertical-align: middle;
+    box-shadow: -2px 0 10px 0 rgba(32, 37, 50, 0.03), 0 10px 21px 20px rgba(32, 37, 50, 0.03);
+}
+.copy-node-form-box {
+    margin-top: 24px;
+    padding-top: 24px;
+    border-top: 1px solid #efeff5;
+}
+.hc-position-input-icon {
+    position: relative;
+    margin-bottom: 0;
+    .el-form-item__content {
+        position: relative;
+        .el-textarea .el-textarea__inner {
+            padding-right: 30px;
+        }
+        .hc-icon-i {
+            position: absolute;
+            right: 10px;
+            bottom: 0;
+            font-size: 20px;
+            cursor: pointer;
+            color: #0081ff;
+            opacity: 1;
+            transition: opacity 0.2s;
+            &:hover {
+                opacity: .5;
+            }
+        }
+    }
+}
+</style>