ZaiZai пре 6 месеци
родитељ
комит
0ad02599dc

+ 1 - 1
package.json

@@ -18,7 +18,7 @@
         "dayjs": "^1.11.12",
         "echarts": "^5.5.1",
         "element-plus": "2.8.0",
-        "hc-vue3-ui": "^4.1.6",
+        "hc-vue3-ui": "^4.1.7",
         "js-base64": "^3.7.7",
         "js-fast-way": "^0.5.6",
         "js-md5": "^0.8.3",

+ 16 - 0
src/api/modules/exctab/exceltab.js

@@ -238,4 +238,20 @@ export default {
             params: form,
         })
     },
+    //分页获取清表
+    async getList(form) {
+        return HcApi({
+            url: '/api/blade-manager/exceltab/list',
+            method: 'get',
+            params: form,
+        })
+    },
+    //关联清表保存
+    async saveLinkTab(form) {
+        return HcApi({
+            url: '/api/blade-manager/exceltab/save-linkTab',
+            method: 'get',
+            params: form,
+        })
+    },
 }

+ 19 - 1
src/components/table-form/modules/components.vue

@@ -7,7 +7,8 @@
         :data-objs="objsData" :data-multiple="multiple" :data-range="rangeSeparator" :data-def="deftext" :data-max="maxlength"
         :data-tip="tip"
     >
-        {{ name || placeholder }}
+        <span class="name-placeholder">{{ name || placeholder }}</span>
+        <i class="i-iconoir-warning-triangle-solid warning-icon" />
         <div v-if="isSlots" class="slot-content">
             <slot />
         </div>
@@ -109,9 +110,26 @@ const isSlots = !!slots.default
     transition: border 0.2s;
     font-size: 14px;
     height: 100%;
+    .name-placeholder {
+        display: block;
+    }
+    .warning-icon {
+        display: none;
+        color: #101010;
+        font-size: 18px;
+    }
     .slot-content {
         display: none;
     }
+    &.warnstyle {
+        background: #fe641e;
+        .name-placeholder {
+            display: none;
+        }
+        .warning-icon {
+            display: block;
+        }
+    }
     &:hover {
         background: #eddac4;
     }

+ 3 - 9
src/components/table-form/table-form.vue

@@ -23,7 +23,7 @@ const props = defineProps({
 })
 
 //事件
-const emit = defineEmits(['tap', 'render'])
+const emit = defineEmits(['tap', 'render', 'right'])
 
 const uuid = getRandom(8)
 
@@ -84,15 +84,9 @@ const getExcelHtml = () => {
         onFormDataChange: (form) => {
             excelForm.value = form
         },
-        /*onRight: () => {
-            console.log('onRight')
+        onRight: (event, a, b, c, d, e, f, Key) => {
+            emit('right', event, a, b, c, d, e, f, Key)
         },
-        onBlur: () => {
-            console.log('onBlur')
-        },
-        onLeftClick: () => {
-            console.log('onLeftClick')
-        },*/
     })
     tableFormApp.value = app
     tableFormVM.value = vm

+ 2 - 2
src/plugins/HTableForm.js

@@ -44,10 +44,10 @@ export default class HTableForm {
                 //鼠标右键事件
                 RightClick(a, b, c, d, e, f, event) {
                     setTimeout(() => {
-                        const KeyName = event?.target?.getAttribute('keyname') || ''
+                        const KeyName = event?.target?.getAttribute('data-key') || ''
                         if (onRight) {
                             event.preventDefault()
-                            onRight(event, KeyName)
+                            onRight(event, a, b, c, d, e, f, KeyName)
                         }
                     }, 100)
                 },

+ 1 - 1
src/views/project/list/adjust-excel.vue

@@ -60,7 +60,7 @@ watch(isShow, (val) => {
 const splitOptions = { sizes: [70, 30], snapOffset: 0, minSize: [300, 300] }
 
 //选项卡
-const tabsKey = ref('tab5')
+const tabsKey = ref('tab1')
 const tabsProps = [
     { label: '输入框', value: 'tab1' },
     { label: '电签位置', value: 'tab2' },

+ 217 - 0
src/views/project/list/association-list.vue

@@ -0,0 +1,217 @@
+<template>
+    <hc-dialog v-model="isShow" widths="40rem" ui="hc-association-list-box" is-table title="关联清表" is-footer-center @close="dialogClose">
+        <el-form ref="formRef" :model="formModel" label-position="top" label-width="auto">
+            <el-form-item label="清表模版:">
+                <el-select v-model="formModel.name" placeholder="请选择清表模版" filterable block @change="nameChange">
+                    <el-option v-for="item in excelData" :key="item.id" :label="item.name" :value="item.id" />
+                </el-select>
+            </el-form-item>
+            <el-form-item label="请输入需要选择的内容:">
+                <el-input v-model="formModel.search" placeholder="请输入需要选择的内容" />
+            </el-form-item>
+        </el-form>
+        <div v-loading="isLoading" class="hc-association-list-tree-box">
+            <el-scrollbar>
+                <el-tree
+                    ref="treeRef"
+                    :filter-node-method="filterNode"
+                    class="filter-tree"
+                    :props="tabTreeProps"
+                    :data="tabTreeData"
+                    node-key="id"
+                    accordion
+                    show-checkbox
+                    @check="checkChange"
+                />
+            </el-scrollbar>
+        </div>
+        <template #footer>
+            <el-button hc-btn @click="dialogClose">取消</el-button>
+            <el-button hc-btn type="primary" :loading="submitLoading" @click="dialogSubmit">提交</el-button>
+        </template>
+    </hc-dialog>
+</template>
+
+<script setup>
+import { ref, watch } from 'vue'
+import { deepClone, getArrValue, isNullES } from 'js-fast-way'
+import excelApi from '~api/exctab/exceltab'
+
+const props = defineProps({
+    info: {
+        type: Object,
+        default: () => ({}),
+    },
+})
+
+//事件
+const emit = defineEmits(['change', 'close'])
+
+//双向绑定
+// eslint-disable-next-line no-undef
+const isShow = defineModel('modelValue', {
+    default: false,
+})
+
+//监听数据
+const rows = ref(props.info)
+watch(() => props.info, (info) => {
+    rows.value = info
+}, { deep: true })
+
+//监听显示
+watch(isShow, (val) => {
+    if (val) {
+        getDataInfo()
+    } else {
+        emit('close')
+    }
+})
+
+//表单
+const formRef = ref(null)
+const formModel = ref({})
+const getDataInfo = () => {
+    const form = deepClone(rows.value)
+    getExcelListData()
+    formModel.value = {
+        id: form.pkeyId,
+        ids: form.id,
+        excelId: form.excelId,
+        name: form.modeId,
+        initTableId: form.initTableId,
+        initTableName: form.initTableName,
+    }
+    setTimeout(() => {
+        treeRef.value?.setCheckedKeys([form.excelId])
+    }, 2000)
+}
+
+//获取清表列表
+const excelData = ref([])
+const getExcelListData = async () => {
+    const { data } = await excelApi.getList({
+        current: 1,
+        size: 100000,
+        parentId: 0,
+    })
+    excelData.value = getArrValue(data?.records)
+}
+
+//清表列表被选择
+const nameChange = () => {
+    if (!isNullES(formModel.value.name)) {
+        formModel.value.search = ''
+        getTabLazytreeAll()
+    }
+}
+
+//清表树参数
+const treeRef = ref(null)
+const tabTreeProps = {
+    label: 'name',
+    children: 'children',
+    disabled: 'hasChildren',
+    isLeaf: function (data) {
+        let tag = false
+        if (!data.hasChildren) {
+            tag = true
+        }
+        if (data.isExistForm == 1) {
+            tag = true
+        }
+        return tag
+    },
+}
+
+//获取清表树
+const isLoading = ref(false)
+const tabTreeData = ref([])
+const getTabLazytreeAll = async () => {
+    const { name, search } = formModel.value
+    isLoading.value = true
+    const { data } = await excelApi.tabLazyTreeAll({
+        modeId: name,
+        name: search,
+    })
+    tabTreeData.value = getArrValue(data)
+    isLoading.value = false
+}
+
+//搜索筛选
+const filterNode = (value, data, node) => {
+    if (isNullES(value)) return true
+    let _array = []//这里使用数组存储 只是为了存储值。
+    getReturnNode2(node, _array, value)
+    let result = false
+    _array.forEach((item) => {
+        result = result || item
+    })
+    return result
+}
+
+const getReturnNode2 = (node, _array, value) => {
+    let isPass = node.data && node.data.name && node.data.name.indexOf(value) !== -1
+    isPass ? _array.push(isPass) : ''
+    if (!isPass && node.level !== 1 && node.parent) {
+        getReturnNode2(node.parent, _array, value)
+    }
+}
+
+const checkChange = (data) => {
+    //节点选中回调
+    if (treeRef.value?.getCheckedNodes().length === 0) {
+        treeRef.value?.setCheckedKeys([])
+    } else if (treeRef.value?.getCheckedNodes().length >= 1) {
+        treeRef.value?.setCheckedKeys([data.id])
+    }
+}
+
+//提交表单
+const submitLoading = ref(false)
+const dialogSubmit = async () => {
+    let checkNodes = treeRef.value?.getCheckedNodes()
+    if (checkNodes.length <= 0) {
+        window?.$message?.warning('请先设置清表')
+        return
+    }
+    let node = checkNodes[checkNodes.length - 1]
+    if (Number(node.fileType) !== 3) {
+        window?.$message?.warning('请先上传Excel表')
+        return
+    }
+    submitLoading.value = true
+    const { isRes } = await excelApi.saveLinkTab({
+        exceTabId: node.id,
+        tabId: formModel.value.id,
+    })
+    submitLoading.value = false
+    if (!isRes) return
+    dialogClose()
+    window?.$message?.success('关联清表成功')
+    emit('change')
+}
+
+//关闭弹窗
+const dialogClose = () => {
+    formModel.value.name = ''
+    formModel.value.search = ''
+    formModel.value.id = ''
+    tabTreeData.value = []
+    treeRef.value?.setCheckedKeys([])
+    isShow.value = false
+    emit('close')
+}
+</script>
+
+<style lang="scss">
+.el-overlay-dialog .el-dialog.hc-new-dialog.hc-association-list-box .hc-new-dialog-body {
+    .hc-association-list-tree-box {
+        position: relative;
+        padding: 5px 0;
+        height: calc(100% - 160px);
+        border: 1px solid #dcdfe6;
+        border-radius: 5px;
+    }
+}
+</style>

+ 240 - 0
src/views/project/list/edit-element.vue

@@ -0,0 +1,240 @@
+<template>
+    <hc-drawer v-model="isShow" ui="hc-project-list-edit-element-drawer" to-id="hc-layout-box" is-close @close="drawerClose">
+        <hc-page-split :fold="false" :options="splitOptions">
+            <template #left>
+                <hc-card :title="`【编辑元素】${dataInfo.tableName}`">
+                    <template #search>
+                        <div class="text-13px color-#f0720a">
+                            <span>提示:鼠标右键功能:更换匹配元素字段、新增元素字段、删除匹配元素字段、公式配置</span>
+                            <span class="ml-14px text-red-6">红色:代表匹配不成功、</span>
+                            <span class="text-blue-6">蓝色代表推荐匹配元素字段、</span>
+                            <span class="text-green-6">绿色代表匹配成功</span>
+                        </div>
+                    </template>
+                    <hc-table-form ref="excelRef" :html="excelHtml" @tap="excelClick" />
+                </hc-card>
+            </template>
+            <hc-card scrollbar>
+                <template #header>
+                    <el-button type="warning">表单调整</el-button>
+                    <el-button type="primary">公式配置</el-button>
+                </template>
+                <template #extra>
+                    <el-button @click="drawerClose">返回上一级</el-button>
+                </template>
+                <el-form ref="formRef" :model="formModel" :rules="formRules" label-position="left" label-width="auto">
+                    <el-form-item label="当前元素坐标:" prop="colName">
+                        <el-input v-model="formModel.colName" placeholder="请点击左侧表单" disabled />
+                    </el-form-item>
+                    <el-form-item label="将元素替换为:" prop="htmlType">
+                        <el-select v-model="formModel.htmlType" filterable block placeholder="输入元素名称搜索">
+                            <el-option label="个人证书" :value="2" />
+                            <el-option label="企业证书" :value="6" />
+                        </el-select>
+                    </el-form-item>
+                </el-form>
+                <div class="action-btn-box mb-40px mt-10px text-center">
+                    <el-button type="primary" @click="savingClick">临时保存</el-button>
+                    <el-button type="danger" style="margin-left: 50px">删除文本</el-button>
+                </div>
+                <div class="hc-edit-element-collapse">
+                    <el-collapse v-model="activeNames">
+                        <el-collapse-item name="key1">
+                            <template #title>
+                                <div class="hc-collapse-item-header hc-flex">
+                                    <div class="title text-green">本次临时保存的元素</div>
+                                    <div class="hc-extra-text-box">
+                                        <el-button type="success" size="small" :loading="submitLoading" @click="dialogSubmit">全部提交保存</el-button>
+                                    </div>
+                                </div>
+                            </template>
+                            1111
+                        </el-collapse-item>
+                        <el-collapse-item name="key2">
+                            <template #title>
+                                <div class="hc-collapse-item-header hc-flex">
+                                    <div class="title text-orange">未进行匹配的元素字段</div>
+                                    <div class="hc-extra-text-box">
+                                        <el-button type="warning" size="small">新增元素</el-button>
+                                    </div>
+                                </div>
+                            </template>
+                            1111
+                        </el-collapse-item>
+                    </el-collapse>
+                </div>
+            </hc-card>
+        </hc-page-split>
+    </hc-drawer>
+</template>
+
+<script setup>
+import { ref, watch } from 'vue'
+import { getArrValue, getObjValue, isNullES } from 'js-fast-way'
+import excelApi from '~api/exctab/exceltab'
+
+const props = defineProps({
+    info: {
+        type: Object,
+        default: () => ({}),
+    },
+    data: {
+        type: Object,
+        default: () => ({}),
+    },
+})
+
+//事件
+const emit = defineEmits(['close'])
+
+//双向绑定
+const isShow = defineModel('modelValue', {
+    default: false,
+})
+
+//监听数据
+const dataInfo = ref(props.info)
+const editData = ref(props.data)
+watch(() => [props.info, props.data], ([info, data]) => {
+    dataInfo.value = getObjValue(info)
+    editData.value = getObjValue(data)
+}, { immediate: true, deep: true })
+
+//监听显示
+watch(isShow, (val) => {
+    if (val) getDataApi()
+})
+
+//页面分割
+const splitOptions = { sizes: [70, 30], snapOffset: 0, minSize: [300, 300] }
+
+//处理相关数据
+const excelRef = ref(null)
+const excelHtml = ref('')
+const getDataApi = async () => {
+    const { pkeyId, excelId } = getObjValue(dataInfo.value)
+    if (isNullES(pkeyId) || isNullES(excelId)) {
+        window?.$message.warning('表单值异常,请联系管理员')
+        return
+    }
+    const { data } = await excelApi.getExcelHtml({ pkeyId })
+    excelHtml.value = data || ''
+}
+
+//基础表单
+const formRef = ref(null)
+const formModel = ref({})
+const formRules = {
+    colName: { required: true, trigger: 'change', message: '请先获取元素坐标' },
+    htmlType: { required: true, trigger: 'change', message: '请先寻找将元素替换为' },
+}
+
+//元素被点击
+const excelClick = async (item) => {
+    const { pkeyId } = getObjValue(dataInfo.value)
+    if (isNullES(pkeyId)) {
+        window?.$message.warning('表单值异常,请联系管理员')
+        return
+    }
+    const data = await getDomAttribute(item)
+    const arr = getArrValue(formDataArr.value)
+    console.log(data)
+    /*formModel.value = {
+        tabId: pkeyId,
+        colName: data.name || data.key,
+        tdIndex: data.td,
+        trIndex: data.tr,
+        htmlType: '',
+    }*/
+}
+
+//获取元素相关信息
+const keys = [
+    'type', 'key', 'tr', 'td', 'index', 'x1', 'y1', 'x2', 'y2', 'name', 'text', 'rows', 'format', 'tip',
+    'weighing', 'label', 'value', 'src', 'val', 'contractid', 'pkeyid', 'objs', 'range', 'def', 'max',
+]
+const getDomAttribute = async (item) => {
+    const dom = item?.target
+    let obj = { zdom: item }
+    for (let i = 0; i < keys.length; i++) {
+        obj[keys[i]] = await getAttribute(dom, keys[i])
+    }
+    return obj
+}
+
+//获取属性
+const getAttribute = async (dom, key) => {
+    try {
+        return dom?.getAttribute(`data-${key}`)
+    } catch (e) {
+        return null
+    }
+}
+
+//临时保存
+const formDataArr = ref([])
+const savingClick = () => {
+
+}
+
+//折叠面板
+const activeNames = ref(['key2'])
+
+//保存数据
+const submitLoading = ref(false)
+const dialogSubmit = async () => {
+    console.log(formModel.value)
+}
+
+//关闭抽屉
+const drawerClose = () => {
+    isShow.value = false
+    emit('close')
+}
+</script>
+
+<style lang="scss">
+.el-overlay .el-drawer.hc-project-list-edit-element-drawer {
+    background-color: #F1F5F8;
+    .hc-table-form-data-item {
+        padding: 0;
+    }
+    .hc-table-form-data-item .hc-excel-table-form {
+        background: #e4e7eb;
+    }
+    .hc-edit-element-collapse {
+        position: relative;
+        border: 1px solid #ebeef5;
+        border-top: 0;
+        border-bottom: 0;
+        .el-collapse {
+            --el-collapse-header-bg-color: #f9f9f9;
+        }
+        .el-collapse .el-collapse-item {
+            .el-collapse-item__header {
+                padding-left: 10px;
+            }
+            .el-collapse-item__wrap {
+                padding: 10px;
+                border-top: 1px solid #ebeef5;
+                .el-collapse-item__content {
+                    padding-bottom: 0;
+                }
+            }
+        }
+        .el-collapse .el-collapse-item .hc-collapse-item-header {
+            position: relative;
+            flex: 1;
+            .title {
+                position: relative;
+                flex: 1;
+                text-align: left;
+            }
+            .hc-extra-text-box {
+                position: relative;
+                margin-right: 24px;
+            }
+        }
+    }
+}
+</style>

+ 43 - 3
src/views/project/list/wbs-tree.vue

@@ -82,8 +82,8 @@
                                 <template #isLinkTable="{ row }">{{ row.isLinkTable === 2 ? '是' : '否' }}</template>
                                 <template #tableOwner="{ row }">{{ getDictionaryName(ownerTypeList, row.tableOwner, true) }}</template>
                                 <template #action="{ row }">
-                                    <el-link type="success">关联清表</el-link>
-                                    <el-link type="primary" :disabled="row.excelId === -1 || isNullES(row.excelId)">编辑元素</el-link>
+                                    <el-link type="success" @click="associationList(row)">关联清表</el-link>
+                                    <el-link v-loading="editElementLoading" type="primary" :disabled="row.excelId === -1 || isNullES(row.excelId)" @click="editElement(row)">编辑元素</el-link>
                                     <el-link v-loading="adjustExcelLoading" type="warning" :disabled="row.excelId === -1 || isNullES(row.excelId)" @click="adjustExcelClick(row)">调整表单</el-link>
                                     <el-link type="primary">编辑元素公式</el-link>
                                     <el-link type="warning">表单同步</el-link>
@@ -118,6 +118,10 @@
                 </template>
             </hc-table>
         </hc-new-dialog>
+        <!-- 关联清表 -->
+        <HcAssociationList v-model="isAssociationShow" :info="associationInfo" @change="getInfoTableData" />
+        <!-- 编辑元素 -->
+        <HcEditElement v-model="isEditElementShow" :info="editElementInfo" :data="editElementData" />
         <!-- 调整表单 -->
         <HcAdjustExcel v-model="isAdjustExcelShow" :info="adjustExcelInfo" />
     </hc-drawer>
@@ -131,6 +135,8 @@ import { deepClone, getArrValue, getObjValue, isNullES } from 'js-fast-way'
 import { getDictionaryData, reloadPage } from '~uti/tools'
 import TreeNodeEditDialog from './tree-node-edit.vue'
 import HcAdjustExcel from './adjust-excel.vue'
+import HcAssociationList from './association-list.vue'
+import HcEditElement from './edit-element.vue'
 import excelApi from '~api/exctab/exceltab'
 import wbsTreeApi from '~api/wbs/tree'
 import mainApi from '~api/wbs/private'
@@ -575,7 +581,7 @@ const infoTableColumn1 = ref([
     { key: 'fillRate', name: '填报率', align: 'center', width: 80 },
     { key: 'isLinkTable', name: '关联清表', align: 'center', width: 80 },
     { key: 'tableOwner', name: '所属方', align: 'center', width: 100 },
-    { key: 'action', name: '操作', width: 490, align: 'center' },
+    { key: 'action', name: '操作', width: 490, align: 'center', fixed: 'right' },
 ])
 const setIsFormSetValue = () => {
     isFormSet.value = !isFormSet.value
@@ -595,6 +601,40 @@ const dataSyncMenuClick = (item) => {
     console.log( item)
 }
 
+// 关联清表
+const isAssociationShow = ref(false)
+const associationInfo = ref({})
+const associationList = async (item) => {
+    associationInfo.value = item
+    await nextTick()
+    isAssociationShow.value = true
+}
+
+//编辑元素
+const isEditElementShow = ref(false)
+const editElementInfo = ref({})
+const editElementData = ref({})
+const editElementLoading = ref(false)
+const editElement = async (row) => {
+    editElementLoading.value = true
+    const { code, data } = await excelApi.getExcelHtml({ pkeyId: row.pkeyId })
+    if (code !== 200 || isNullES(data)) {
+        editElementLoading.value = false
+        window?.$message.warning('表单异常,请联系管理员')
+        return
+    }
+    editElementLoading.value = false
+    editElementInfo.value = row
+    editElementData.value = {
+        pid: projectInfo.value.id,
+        wbsid: wbsId.value,
+        nodeid: treeItem.value.id,
+    }
+    await nextTick()
+    isEditElementShow.value = true
+}
+
+
 //调整表单
 const isAdjustExcelShow = ref(false)
 const adjustExcelLoading = ref(false)

+ 4 - 4
yarn.lock

@@ -2017,10 +2017,10 @@ has-flag@^4.0.0:
   resolved "http://39.108.216.210:9000/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
   integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
 
-hc-vue3-ui@^4.1.6:
-  version "4.1.6"
-  resolved "http://39.108.216.210:9000/hc-vue3-ui/-/hc-vue3-ui-4.1.6.tgz#8997a29c818a009e3436b8ed9cad269fe3776b6c"
-  integrity sha512-g3GTPNcoH9NblPCSqki1aKpHaW7CPqOwMGDBqgxhAtvZU0lD7xaV86zINyTeYiVNTszOow+1Jea2Hl25LTeUHQ==
+hc-vue3-ui@^4.1.7:
+  version "4.1.7"
+  resolved "http://39.108.216.210:9000/hc-vue3-ui/-/hc-vue3-ui-4.1.7.tgz#b9f7e6b2ba272e9d8574466535924ba9cbae5eb8"
+  integrity sha512-rIKsZcsg627trBP5g24lgyy2u1tr+q4n73xZcUF8fVHg/G1rp9DD6NtzWnpeHhfbnc8EZV2ti3numxMBbKXrkA==
   dependencies:
     axios "^1.7.4"
     dayjs "^1.11.12"