iZaiZaiA 2 年 前
コミット
a8e11499f8

+ 34 - 2
src/api/modules/other/first-item.js

@@ -2,9 +2,9 @@ import {httpApi} from "../../request/httpApi";
 
 export default {
     //获取合同段划分树中被标记为首件的节点
-    async queryWbsTreeData(form, msg = true) {
+    async queryContractWbsTreeByFirstInfo(form, msg = true) {
         return httpApi({
-            url: '/api/blade-business/treeContractFirst/queryContractWbsTreeFirstByContractIdAndType',
+            url: '/api/blade-business/informationWriteQuery/queryContractWbsTreeByFirstInfo',
             method: 'get',
             params: form
         }, msg);
@@ -25,4 +25,36 @@ export default {
             data: form
         }, msg)
     },
+    //首件表单获取html页面
+    async getFirstExcelHtml(form, msg = true) {
+        return httpApi({
+            url: '/api/blade-manager/first/get-first-excel-html',
+            method: 'get',
+            params: form
+        }, msg)
+    },
+    //首件-pdf预览
+    async getFirstBussPdfInfo(form, msg = true) {
+        return httpApi({
+            url: '/api/blade-manager/first/get-first-buss-pdfInfo',
+            method: 'get',
+            params: form
+        }, msg)
+    },
+    //获取首件用户保存数据
+    async getFirstBussDataInfo(form, msg = true) {
+        return httpApi({
+            url: '/api/blade-manager/first/get-first-buss-dataInfo',
+            method: 'get',
+            params: form
+        }, msg)
+    },
+    //填报页面数据保存
+    async saveBussData(form, msg = true) {
+        return httpApi({
+            url: '/api/blade-manager/exceltab/save_buss_data',
+            method: 'post',
+            data: form
+        }, msg);
+    },
 }

+ 55 - 0
src/styles/other/first-item.scss

@@ -0,0 +1,55 @@
+.hc-layout-box {
+    display: flex;
+    position: relative;
+    height: 100%;
+    .hc-layout-left-box {
+        width: 382px;
+        position: relative;
+        background: #f1f5f8;
+        border-radius: 10px;
+        box-shadow: -2px 0 10px 0 rgba(32,37,50,0.03), 0 10px 21px 20px rgba(32,37,50,0.03);
+        .horizontal-drag-line {
+            position: absolute;
+            right: 0;
+            top: 0;
+            width: 2px;
+            height: 100%;
+            user-select: none;
+            cursor: col-resize;
+            background-color: #00000000;
+        }
+        .hc-project-box {
+            position: relative;
+            padding: 15px 24px;
+            display: flex;
+            align-items: flex-start;
+            border-bottom: 1px solid #E9E9E9;
+            .hc-project-icon-box {
+                font-size: 30px;
+                color: var(--el-color-primary);
+            }
+            .project-name-box {
+                flex: auto;
+                position: relative;
+                overflow: hidden;
+                .project-alias {
+                    color: var(--el-color-primary);
+                }
+                .project-name {
+                    margin-top: 6px;
+                    color: #838791;
+                }
+            }
+        }
+        .hc-tree-box {
+            position: relative;
+            padding: 15px 20px;
+            height: calc(100% - 80px);
+        }
+    }
+    .hc-layout-content-box {
+        flex: 1;
+        position: relative;
+        margin-left: 24px;
+    }
+}

+ 7 - 1
src/views/data-fill/components/ListItem.vue

@@ -65,7 +65,10 @@
                                 </div>
                                 <div class="tip-right-btn">
                                     <HcTooltip keys="wbs_save_table">
-                                        <el-button type="primary" hc-btn size="large" @click="tableFormSaveClick(item,index)">保存</el-button>
+                                        <el-button type="primary" hc-btn :disabled="item?.isTableForm === false" :loading="tableFormSaveLoading" @click="tableFormSaveClick(item,index)">
+                                            <HcIcon name="save"/>
+                                            <span>保存</span>
+                                        </el-button>
                                     </HcTooltip>
                                 </div>
                             </div>
@@ -271,6 +274,7 @@ const getBussDataInfo = async (item,pkeyId, index) => {
 }
 
 //单个保存
+const tableFormSaveLoading = ref(false)
 const tableFormSaveClick = async (item,index) => {
     if (isStatus.value !== '3') {
         const res = await saveExcelBussData(item,index)
@@ -285,12 +289,14 @@ const tableFormSaveClick = async (item,index) => {
 
 //保存表单数据
 const saveExcelBussData = async (item, index, showTip = true) => {
+    tableFormSaveLoading.value = true
     const InitObj = getFormDataInit(item, item.pkeyId)
     const {error, code, data} = await wbsApi.saveExcelBussData({
         ...formData.value[index],
         ...InitObj
     }, false)
     //处理数据
+    tableFormSaveLoading.value = false
     if (!error && code === 200) {
         if(showTip) window?.$message?.success('保存成功')
         return true

+ 5 - 0
src/views/ledger/components/table-form.vue

@@ -164,6 +164,7 @@ const getExcelHtml = async (excelId) => {
     if (excelId) {
         //获取数据
         const { error, code, data } = await queryApi.getExcelHtml({
+            contractId: contractId.value || '',
             pkeyId: excelId
         }, false)
         //处理数据
@@ -323,11 +324,14 @@ const ElTreeLoadNode = async (node, resolve) => {
 const processDataList = ref([])
 const processNodeClick = () => {
     const keys = processElTree.value.getCheckedKeys();
+    //formLogDataList.value = formArrData
     let NodesArr = []
     for (let index = 0; index < keys.length; index++) {
         let pathArr = [];
         let node = processElTree.value.getNode(keys[index]);
         getPathName(node, pathArr);
+        //path: item['pathName'],
+        //primaryKeyId: item['primaryKeyId']
         NodesArr.push({
             primaryKeyId: keys[index],
             pathName: pathArr.join('/')
@@ -507,6 +511,7 @@ const copyTimeSaveClick = async () => {
 //设置表单默认数据
 const setFormDefaultData = (formInfo) => {
     return {
+        linkTabIds: [],
         ...formInfo,
         projectId: projectId.value,
         contractId: contractId.value,

+ 156 - 0
src/views/other/components/WbsTree.vue

@@ -0,0 +1,156 @@
+<template>
+    <ElTree class="hc-tree-node" :props="ElTreeProps" :load="ElTreeLoadNode" lazy highlight-current accordion node-key="primaryKeyId"
+            :default-expanded-keys="defaultExpandedCids" @node-click="ElTreeClick">
+        <template #default="{ node, data }">
+            <div class="data-custom-tree-node" :id="`${idPrefix}${data['primaryKeyId']}`">
+                <div class="label" :class="node.level === 1?'level-name':''">{{ node.label }}</div>
+            </div>
+        </template>
+    </ElTree>
+</template>
+
+<script setup>
+import {ref,nextTick,watch} from "vue";
+import firstApi from '~api/other/first-item';
+import {isItem,getArrValue,getObjValue} from "vue-utils-plus"
+//参数
+const props = defineProps({
+    projectId: {
+        type: [String,Number],
+        default: ''
+    },
+    contractId: {
+        type: [String,Number],
+        default: ''
+    },
+    autoExpandKeys: {
+        type: Array,
+        default: () => ([])
+    },
+    idPrefix: {
+        type: String,
+        default: 'first-tree-'
+    },
+    isAutoKeys: {
+        type: Boolean,
+        default: true
+    },
+    isAutoClick: {
+        type: Boolean,
+        default: true
+    },
+})
+
+//变量
+const ElTreeProps = ref({
+    label: 'title',
+    children: 'children',
+    isLeaf: 'notExsitChild'
+})
+
+const isAutoKeys = ref(props.isAutoKeys)
+const TreeExpandKey = ref(props.autoExpandKeys)
+const projectId = ref(props.projectId);
+const contractId = ref(props.contractId);
+
+//监听
+watch(() => [
+    props.isAutoKeys,
+    props.autoExpandKeys,
+    props.projectId,
+    props.contractId,
+], ([AutoKeys, expandKeys, UserProjectId, UserContractId]) => {
+    isAutoKeys.value = AutoKeys
+    TreeExpandKey.value = expandKeys
+    projectId.value = UserProjectId
+    contractId.value = UserContractId
+})
+
+//树形结构异步加载数据
+const defaultExpandedCids = ref([])
+const ElTreeLoadNode = async (node, resolve) => {
+    //获取数据
+    const { contractIdRelation, primaryKeyId, id } = getObjValue(node?.data);
+    const {error, code, data} = await firstApi.queryContractWbsTreeByFirstInfo({
+        contractId: contractId.value || '',
+        contractIdRelation: contractIdRelation || '',
+        primaryKeyId: primaryKeyId || '',
+        parentId: node.level !== 0 ? id : ''
+    })
+    //处理数据
+    if (!error && code === 200) {
+        let clickKey = '', defaultExpandedArr = [];
+        const keys = TreeExpandKey.value || []
+        const resData = getArrValue(data)
+        if (keys.length > 0) {
+            let lastKey = keys[keys.length-1];
+            for (const item of resData) {
+                //自动展开
+                if (isItem(keys,item?.primaryKeyId)) {
+                    defaultExpandedArr.push(item?.primaryKeyId)
+                }
+                //最后一个,选中点击
+                if (item?.primaryKeyId === lastKey) {
+                    clickKey = item?.primaryKeyId
+                }
+            }
+        } else if (node.level === 0) {
+            defaultExpandedArr.push(resData[0]?.primaryKeyId)
+        }
+        //自动展开
+        defaultExpandedCids.value = defaultExpandedArr
+        resolve(resData)
+        //最后一个,执行点击
+        if (props.isAutoClick && clickKey) {
+            await nextTick(() => {
+                document.getElementById(`${props.idPrefix}${clickKey}`)?.click()
+            })
+        }
+    } else {
+        resolve([])
+    }
+}
+
+//事件
+const emit = defineEmits(['nodeTap'])
+
+//节点被点击
+const ElTreeClick = async (data,node) => {
+    if (isAutoKeys.value) {
+        let autoKeysArr = []
+        await getNodeExpandKeys(node, autoKeysArr)
+        const autoKeys = autoKeysArr.reverse()
+        emit('nodeTap', {node, data, keys: autoKeys})
+    } else {
+        emit('nodeTap', {node, data, keys: []})
+    }
+}
+
+//处理自动展开的节点KEY
+const getNodeExpandKeys = async (node, newKeys) => {
+    const parent = getArrValue(node?.parent)
+    const { primaryKeyId } = getObjValue(node?.data)
+    if (primaryKeyId) {
+        newKeys.push(primaryKeyId)
+        await getNodeExpandKeys(parent, newKeys)
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+.data-custom-tree-node {
+    position: relative;
+    display: flex;
+    align-items: center;
+    width: 100%;
+    color: var(--ui-TC);
+    .label {
+        flex: auto;
+        font-size: 16px;
+    }
+    .label.level-name {
+        font-size: 18px;
+        font-weight: bold;
+    }
+}
+</style>

+ 123 - 3
src/views/other/first-item.vue

@@ -1,13 +1,133 @@
 <template>
-    <div>
-        首件工程
+    <div class="hc-layout-box">
+        <div class="hc-layout-left-box" :style="'width:' + leftWidth + 'px;'">
+            <div class="hc-project-box">
+                <div class="hc-project-icon-box">
+                    <HcIcon name="stack"/>
+                </div>
+                <div class="ml-2 project-name-box">
+                    <span class="text-xl text-cut project-alias">{{projectInfo['projectAlias']}}</span>
+                    <div class="text-xs text-cut project-name">{{projectInfo['name']}}</div>
+                </div>
+            </div>
+            <div class="hc-tree-box">
+                <el-scrollbar>
+                    <WbsTree :autoExpandKeys="TreeAutoExpandKeys" :projectId="projectId" :contractId="contractId" @nodeTap="nodeWbsElTreeClick"/>
+                </el-scrollbar>
+            </div>
+            <!--左右拖动-->
+            <div class="horizontal-drag-line" @mousedown="onmousedown"/>
+        </div>
+        <div class="hc-layout-content-box first-item">
+            <HcCard :scrollbar="false" actionSize="lg">
+                <template #header>
+
+                </template>
+                <template #extra>
+                    <HcNewSwitch :datas="tabTypeTab" :keys="tabTypeKey" @change="tabTypeChange"/>
+                </template>
+                <template #search>
+
+                </template>
+
+                <template #action>
+
+                </template>
+            </HcCard>
+        </div>
     </div>
 </template>
 
 <script setup>
+import {onMounted, ref, watch} from 'vue'
+import {useAppStore} from "~src/store";
+import {useRouter, useRoute} from 'vue-router'
+import WbsTree from "./components/WbsTree.vue"
+import {getStoreData, setStoreData} from '~src/utils/storage'
+import {downloadBlob, getArrValue, deepClone} from "vue-utils-plus"
+
+//变量
+const router = useRouter()
+const useRoutes = useRoute()
+const useAppState = useAppStore()
+const projectId = ref(useAppState.getProjectId);
+const contractId = ref(useAppState.getContractId);
+const projectInfo = ref(useAppState.getProjectInfo);
+const isCollapse = ref(useAppState.getCollapse)
+
+//路由参数
+const routerQuery = useRoutes?.query;
+const typeName = routerQuery?.type || 'mark'
+
+//监听
+watch(() => [
+    useAppState.getCollapse
+], ([Collapse]) => {
+    isCollapse.value = Collapse
+})
+
+//自动展开缓存
+const TreeAutoExpandKeys = ref(getStoreData('wbsTreeExpandKeys') || [])
 
+//类型tab数据和相关处理
+const tabTypeKey = ref(typeName)
+const tabTypeTab = ref([
+    {key:'mark',  name: '已标记为首件'},
+    {key:'query', name: '首件查询'}
+]);
+const tabTypeChange = (item) => {
+    tabTypeKey.value = item?.key;
+    //路由跳转
+    router.push({
+        path: useRoutes.path,
+        query: {type: item?.key}
+    })
+}
+
+//项目树被点击
+const treeItem = ref({})
+const nodeWbsElTreeClick = ({data, keys}) => {
+    if (data.leaf === true) {
+        treeItem.value = data
+        //wbsId.value = data['primaryKeyId']
+        //formValue.value.wbsId = data['primaryKeyId']
+        //缓存自动展开
+        TreeAutoExpandKeys.value = keys
+        setStoreData('TreeExpandKeys', keys)
+    } else {
+        //wbsId.value = ''
+        treeItem.value = {}
+        //formValue.value.wbsId = null
+    }
+}
+
+
+
+
+//拼接ID
+const rowsToId = (rows) => {
+    return rows.map((obj) => {
+        return obj.id;
+    }).join(",")
+}
+
+//左右拖动,改变树形结构宽度
+const leftWidth = ref(382)
+const onmousedown = () => {
+    const leftNum = isCollapse.value ? 142 : 272
+    document.onmousemove = (ve) => {
+        const diffVal = ve.clientX - leftNum;
+        if(diffVal >= 310 && diffVal <= 900) {
+            leftWidth.value = diffVal;
+        }
+    }
+    document.onmouseup = () => {
+        document.onmousemove = null;
+        document.onmouseup = null;
+    }
+}
 </script>
 
 <style lang="scss" scoped>
-
+@import "../../styles/other/first-item.scss";
 </style>