Forráskód Böngészése

Merge branch 'master' of http://116.204.116.5:3000/zzw/cbjsxt-front-master

shiyanyu 1 hónapja
szülő
commit
9868fc63bf

+ 2 - 1
src/api/costVerifyManage.js

@@ -59,9 +59,10 @@ export function listByVerifyTemplateId(params) {
 
 export function exportExcel(params) {
   return request({
-    url: `${url}/fdTemplateExport/v1/exportExcel`,
+    url: `${url}/api/fdTemplateExport/v1/exportExcel`,
     method: 'get',
     params,
+    responseType: 'arraybuffer',
   })
 }
 

+ 53 - 1
src/components/task/components/costAudit.vue

@@ -136,6 +136,7 @@
   import { catalogMixin } from '@/mixins/useDict'
   export default {
     name: 'CostAudit',
+    mixins: [catalogMixin],
     props: {
       id: {
         type: [String, Number],
@@ -162,6 +163,20 @@
     },
     data() {
       return {
+        props: {
+          filterable: true,
+          placeholder: '请选择监审类别',
+          style: 'width: 100%',
+          showAllLevels: false,
+          props: {
+            multiple: false,
+            children: 'children',
+            checkStrictly: false,
+            label: 'catalogName',
+            value: 'id',
+            emitPath: false,
+          },
+        },
         // 成本核定表模板列表
         auditFormList: [],
         // 成本调查表模板列表
@@ -315,7 +330,7 @@
             this.project = res.value
             this.auditForm.catalogId = res.value.catalogId
             // this.auditForm.surveyTemplateId = '9368f1cf-77e7-49fe-8502-4a7a2da99668'
-            this.loadTemplateDataForEdit()
+            this.loadTemplateData()
           }
         })
       },
@@ -413,6 +428,43 @@
           : ''
         this.loadTemplateDataForEdit(this.auditForm.surveyTemplateId)
       },
+      // 回显数据用
+      async loadTemplateData(surveyTemplateId) {
+        // 先获取表格数据
+        const tableDataRes = await getCostFormVersionsByTemplateId({
+          taskId: this.selectedProject.taskId,
+          // surveyTemplateId: '',
+        })
+
+        // 处理表格数据
+        if (tableDataRes.code == 200) {
+          this.auditForm.surveyTemplateId =
+            tableDataRes.value.itemlist[0].surveyTemplateId
+          // 有数据后再获取表头数据
+          const tableHeadersRes = await getlistBySurveyTemplateId({
+            // taskId: this.selectedProject.taskId,
+            surveyTemplateId: this.auditForm.surveyTemplateId,
+          })
+          getVerifyTemplateDetail({
+            id: this.auditForm.surveyTemplateId,
+          }).then((res) => {
+            this.auditForm.surveyTemplateName = res.value.surveyTemplateName
+            this.auditForm.catalogId = res.value.catalogId
+            this.auditForm.templateType = res.value.createmode
+            if (res.value.createmode == '1') {
+              this.auditForm.dataTable = res.value.createtemplateid
+            } else if (res.value.createmode == '2') {
+              this.auditForm.historyTemplate = res.value.createtemplateid
+            }
+          })
+
+          // 处理表头数据
+          if (tableHeadersRes.code == 200) {
+            this.parseAndDisplayTableHeaders(tableHeadersRes)
+            this.parseAndDisplayTableData(tableDataRes)
+          }
+        }
+      },
       async loadTemplateDataForEdit(surveyTemplateId) {
         // 并行获取表头和表格数据
         const [tableHeadersRes, tableDataRes] = await Promise.all([

+ 184 - 254
src/views/costAudit/auditInfo/auditManage/costAudit.vue

@@ -178,6 +178,7 @@
   } from '@/api/costVerifyManage'
   import { getDetail } from '@/api/auditInitiation'
   import { catalogMixin } from '@/mixins/useDict'
+  import { saveAs } from 'file-saver'
   export default {
     name: 'CostAudit',
     mixins: [catalogMixin],
@@ -240,99 +241,9 @@
         tableHeadersRes: [],
         tableDataRes: [],
         // 成本审核表格列配置
-        costAuditcolumn: [
-          // {
-          //   prop: 'id',
-          //   label: '序号',
-          //   width: 80,
-          //   align: 'center',
-          // },
-          // {
-          //   prop: 'itemName',
-          //   label: '项目',
-          //   width: 180,
-          // },
-          // {
-          //   prop: 'unit',
-          //   label: '单位',
-          //   width: 100,
-          //   align: 'center',
-          // },
-          // {
-          //   prop: 'year2022BookValue',
-          //   label: '2022年账面值',
-          //   width: 120,
-          //   align: 'right',
-          // },
-          // {
-          //   prop: 'year2022Audit',
-          //   label: '2022年审核',
-          //   width: 120,
-          //   align: 'center',
-          // },
-          // {
-          //   prop: 'year2022ApprovedValue',
-          //   label: '2022年核定值',
-          //   width: 120,
-          //   align: 'right',
-          // },
-          // {
-          //   prop: 'year2023BookValue',
-          //   label: '2023年账面值',
-          //   width: 120,
-          //   align: 'right',
-          // },
-          // {
-          //   prop: 'year2023Audit',
-          //   label: '2023年审核',
-          //   width: 120,
-          //   align: 'center',
-          // },
-          // {
-          //   prop: 'year2023ApprovedValue',
-          //   label: '2023年核定值',
-          //   width: 120,
-          //   align: 'right',
-          // },
-          // {
-          //   prop: 'year2024BookValue',
-          //   label: '2024年账面值',
-          //   width: 120,
-          //   align: 'right',
-          // },
-          // {
-          //   prop: 'year2024Audit',
-          //   label: '2024年审核',
-          //   width: 120,
-          //   align: 'center',
-          // },
-          // {
-          //   prop: 'year2024ApprovedValue',
-          //   label: '2024年核定值',
-          //   width: 120,
-          //   align: 'right',
-          // },
-          // {
-          //   prop: 'action',
-          //   label: '操作',
-          //   width: 150,
-          //   align: 'center',
-          //   fixed: 'right',
-          // },
-        ],
+        costAuditcolumn: [],
         // 成本审核数据
-        costAuditData: [
-          // {
-          //   id: '一',
-          //   itemName: '人员费用小计',
-          //   unit: '元',
-          // },
-          // {
-          //   id: 1,
-          //   itemName: '基本工资',
-          //   unit: '元',
-          // },
-        ],
+        costAuditData: [],
         project: {},
       }
     },
@@ -371,7 +282,7 @@
             this.project = res.value
             this.auditForm.catalogId = res.value.catalogId
             // this.auditForm.surveyTemplateId = '9368f1cf-77e7-49fe-8502-4a7a2da99668'
-            this.loadTemplateDataForEdit()
+            this.loadTemplateData()
           }
         })
       },
@@ -468,6 +379,44 @@
           : ''
         this.loadTemplateDataForEdit(this.auditForm.surveyTemplateId)
       },
+
+      // 回显数据用
+      async loadTemplateData(surveyTemplateId) {
+        // 先获取表格数据
+        const tableDataRes = await getCostFormVersionsByTemplateId({
+          taskId: this.selectedProject.taskId,
+          // surveyTemplateId: '',
+        })
+
+        // 处理表格数据
+        if (tableDataRes.code == 200) {
+          this.auditForm.surveyTemplateId =
+            tableDataRes.value.itemlist[0].surveyTemplateId
+          // 有数据后再获取表头数据
+          const tableHeadersRes = await getlistBySurveyTemplateId({
+            // taskId: this.selectedProject.taskId,
+            surveyTemplateId: this.auditForm.surveyTemplateId,
+          })
+          getVerifyTemplateDetail({
+            id: this.auditForm.surveyTemplateId,
+          }).then((res) => {
+            this.auditForm.surveyTemplateName = res.value.surveyTemplateName
+            this.auditForm.catalogId = res.value.catalogId
+            this.auditForm.templateType = res.value.createmode
+            if (res.value.createmode == '1') {
+              this.auditForm.dataTable = res.value.createtemplateid
+            } else if (res.value.createmode == '2') {
+              this.auditForm.historyTemplate = res.value.createtemplateid
+            }
+          })
+
+          // 处理表头数据
+          if (tableHeadersRes.code == 200) {
+            this.parseAndDisplayTableHeaders(tableHeadersRes)
+            this.parseAndDisplayTableData(tableDataRes)
+          }
+        }
+      },
       async loadTemplateDataForEdit(surveyTemplateId) {
         // 并行获取表头和表格数据
         const [tableHeadersRes, tableDataRes] = await Promise.all([
@@ -493,15 +442,6 @@
         this.tableHeadersRes = Array.isArray(res.value) ? res.value : []
         if (this.tableHeadersRes.length > 0) {
           this.auditForm.surveyTemplateId = res.value[0].surveyTemplateId
-          if (!this.auditForm.surveyTemplateId) {
-            getVerifyTemplateDetail({
-              id: this.auditForm.surveyTemplateId,
-            }).then((res) => {
-              this.auditForm.surveyTemplateName = res.value.surveyTemplateName
-              this.auditForm.catalogId = res.value.catalogId
-            })
-          }
-
           // 表头按照orderNum重新排序
           this.tableHeadersRes.sort((a, b) => a.orderNum - b.orderNum)
           this.costAuditcolumn = [] // 清空现有列配置
@@ -566,7 +506,7 @@
                 fieldName: item + '年审核调整值',
                 fieldType: 'integer',
                 format: '',
-                fieldTypelen: '255',
+                fieldTypelen: '9',
                 fieldTypenointlen: '',
                 isRequired: 'true',
                 isAuditPeriod: 'true',
@@ -670,22 +610,22 @@
               }
             })
 
-            if (this.selectedProject && this.selectedProject.auditPeriod) {
-              // 为审计期间的三个字段添加初始值
-              // 获取审计期间并按年份排序
-              let auditPeriod = this.selectedProject.auditPeriod
-                .split(',')
-                .map((year) => parseInt(year))
-                .sort((a, b) => a - b)
-                .map((year) => year.toString())
-
-              // 为每个年份添加三个字段的初始值
-              auditPeriod.forEach((year) => {
-                rowData[`${year}BookValue账面值`] = '' // 账面值
-                rowData[`${year}Audit审核调整值`] = '' // 审核调整值
-                rowData[`${year}ApprovedValue核定值`] = '' // 核定值
-              })
-            }
+            // if (this.selectedProject && this.selectedProject.auditPeriod) {
+            //   // 为审计期间的三个字段添加初始值
+            //   // 获取审计期间并按年份排序
+            //   let auditPeriod = this.selectedProject.auditPeriod
+            //     .split(',')
+            //     .map((year) => parseInt(year))
+            //     .sort((a, b) => a - b)
+            //     .map((year) => year.toString())
+
+            //   // 为每个年份添加三个字段的初始值,使用与表头定义一致的属性名
+            //   auditPeriod.forEach((year) => {
+            //     rowData[`year${year}BookValue`] = '' // 账面值
+            //     rowData[`year${year}Audit`] = '' // 审核调整值
+            //     rowData[`year${year}ApprovedValue`] = '' // 核定值
+            //   })
+            // }
 
             // 添加完整的行数据到表格数据中
             this.costAuditData.push(rowData)
@@ -704,7 +644,10 @@
           background: 'rgba(0, 0, 0, 0.7)',
         })
         // 加上遮罩层
-        let headersList = this.tableHeadersRes
+        const headersList = this.tableHeadersRes.map((header, index) => ({
+          ...header,
+          orderNum: header.orderNum || index + 1,
+        }))
         let splitData = this.splitFixedTableDataForSave(this.costAuditData)
 
         let data = {
@@ -718,6 +661,7 @@
             this.$loading().close()
             if (type != 'delete') {
               this.$message.success('保存成功')
+              this.loadTemplateData()
             }
           })
           .catch((err) => {
@@ -736,54 +680,70 @@
         }))
       },
       splitFixedTableDataForSave() {
-        let headersList = this.tableHeadersRes
+        let fixedHeaders = this.tableHeadersRes
         let fixedTables = this.costAuditData
-        let fixedFields = headersList
+        let fixedFields = fixedHeaders
           .map((header) => header.fieldName)
           .join(',')
         let fixedTitles = this.stringToObjects(fixedFields || '')
         // 结果数组
         const result = []
-        // 为每个固定列创建一条记录
-        fixedTables.forEach((row) => {
-          fixedTitles.forEach((item) => {
+        const processNode = (node, parentRowIndex = 0) => {
+          // 确保node和fixedValues存在
+          if (!node) {
+            console.warn('遇到空节点,跳过处理')
+            return
+          }
+
+          // 确保fixedValues属性存在,如果不存在则初始化为空对象
+          if (!node.fixedValues) {
+            node.fixedValues = {}
+          }
+
+          // 为每个固定列创建一条记录
+          fixedTitles.forEach((title) => {
             // 找到对应的表头信息
-            const correspondingHeader = headersList.find(
-              (header) => header.fieldName === item.rkey
+            const correspondingHeader = fixedHeaders.find(
+              (header) => header.fieldName === title.rkey
             )
             const newItem = {
-              id: row.itemId || null,
-              rkey: correspondingHeader.fieldName,
-              rvalue: row[correspondingHeader.fieldEname],
+              rkey: title.rkey,
+              rvalue: node[correspondingHeader.fieldEname] || '',
+              [correspondingHeader.fieldName]:
+                node[correspondingHeader.fieldEname] || '',
               surveyTemplateId:
-                row.surveyTemplateId || correspondingHeader.surveyTemplateId,
-              versionId: row.versionId || correspondingHeader.versionId,
-              tabtype: row.tabtype || correspondingHeader.tabtype,
+                node.surveyTemplateId || correspondingHeader.surveyTemplateId,
+              versionId: node.versionId || correspondingHeader.versionId,
+              tabtype: node.tabtype || correspondingHeader.templateType,
               // 添加 headersId 字段(表头的id)
               headersId: correspondingHeader ? correspondingHeader.id : null,
               // 添加记录的id(itemlist中每条记录的id)
-              id: row.itemId || null,
+              id: node.id || null,
               // 添加父子关系字段
-              parentid: row.parentid || -1, // 父项ID,默认为-1表示无父项
-              isChild: row.isChild || false, // 是否为子项
+              parentid: node.parentid || -1, // 父项ID,默认为-1表示无父项
+              isChild: node.isChild || false, // 是否为子项
               // 添加 rowid 字段
-              rowid: row.rowid || null,
+              rowid: node.rowid || null,
               // 添加计算公式相关字段
-              calculationFormula: row.calculationFormula || null,
-              jsonstr: row.jsonstr || null,
+              calculationFormula: node.calculationFormula || null,
+              jsonstr: node.jsonstr || null,
               orderNum:
-                typeof row.orderNum === 'number'
-                  ? row.orderNum
-                  : parseInt(row.orderNum, 10) || 0,
+                typeof node.orderNum === 'number'
+                  ? node.orderNum
+                  : parseInt(node.orderNum, 10) || 0,
+              // 添加用户需要的其他字段
+              orderText: node.orderText || '',
+              percentage: node.percentage || '',
+              unit: node.unit || '',
             }
             // 添加其他固定表特有的字段
-            if (!row.isSubItem) {
-              newItem.cellCode = row.cellCode || ''
-              newItem.unit = row.unit || ''
+            if (!node.isSubItem) {
+              newItem.cellCode = node.cellCode || ''
+              newItem.unit = node.unit || ''
             }
 
             // 添加其他可能需要的字段,但排除特定字段
-            Object.keys(row).forEach((key) => {
+            Object.keys(node).forEach((key) => {
               if (
                 !(key in newItem) &&
                 key !== 'fixedValues' &&
@@ -797,51 +757,54 @@
                 key !== 'calculationFormula' &&
                 key !== 'children' // 排除children字段
               ) {
-                newItem[key] = row[key]
+                newItem[key] = node[key]
               }
             })
 
             result.push(newItem)
           })
+        }
+        fixedTables.forEach((row) => {
+          processNode(row)
+        })
 
-          // 首先收集所有父节点的orderNum,确保不与子节点冲突
-          const parentOrderNums = new Set()
-
-          // 第一次遍历:识别父节点并收集它们的orderNum
-          result.forEach((item) => {
-            // 假设isChild为false或parentid为-1的是父节点
-            if (!item.isChild || item.parentid === -1) {
-              parentOrderNums.add(item.orderNum)
-            }
-          })
-
-          // 创建映射来跟踪已使用的orderNum
-          const usedOrderNums = new Set([...parentOrderNums])
-          let nextAvailableOrderNum = 1
+        // 首先收集所有父节点的orderNum,确保不与子节点冲突
+        const parentOrderNums = new Set()
 
-          // 找到当前最大的orderNum,作为新orderNum的起点
-          const allOrderNums = result
-            .map((item) => item.orderNum)
-            .filter((num) => typeof num === 'number' && !isNaN(num))
-          if (allOrderNums.length > 0) {
-            nextAvailableOrderNum = Math.max(...allOrderNums) + 1
+        // 第一次遍历:识别父节点并收集它们的orderNum
+        result.forEach((item) => {
+          // 假设isChild为false或parentid为-1的是父节点
+          if (!item.isChild || item.parentid === -1) {
+            parentOrderNums.add(item.orderNum)
           }
+        })
 
-          // 第二次遍历:为子节点分配唯一的orderNum
-          result.forEach((item) => {
-            // 只为子节点重新分配orderNum
-            if (item.isChild && item.parentid !== -1) {
-              // 找到下一个未使用的orderNum
-              while (usedOrderNums.has(nextAvailableOrderNum)) {
-                nextAvailableOrderNum++
-              }
+        // 创建映射来跟踪已使用的orderNum
+        const usedOrderNums = new Set([...parentOrderNums])
+        let nextAvailableOrderNum = 1
+
+        // 找到当前最大的orderNum,作为新orderNum的起点
+        const allOrderNums = result
+          .map((item) => item.orderNum)
+          .filter((num) => typeof num === 'number' && !isNaN(num))
+        if (allOrderNums.length > 0) {
+          nextAvailableOrderNum = Math.max(...allOrderNums) + 1
+        }
 
-              // 分配新的orderNum并标记为已使用
-              item.orderNum = nextAvailableOrderNum
-              usedOrderNums.add(nextAvailableOrderNum)
+        // 第二次遍历:为子节点分配唯一的orderNum
+        result.forEach((item) => {
+          // 只为子节点重新分配orderNum
+          if (item.isChild && item.parentid !== -1) {
+            // 找到下一个未使用的orderNum
+            while (usedOrderNums.has(nextAvailableOrderNum)) {
               nextAvailableOrderNum++
             }
-          })
+
+            // 分配新的orderNum并标记为已使用
+            item.orderNum = nextAvailableOrderNum
+            usedOrderNums.add(nextAvailableOrderNum)
+            nextAvailableOrderNum++
+          }
         })
 
         return result
@@ -888,11 +851,9 @@
 
             // 其他参数作为query参数传递
             const queryParams = {
-              materialId: '', // 根据API文档,此参数为必填,但当前没有值,保留空字符串
-              surveyTemplateId:
-                this.auditForm.surveyTemplateId ||
-                '62d10551-1576-49b0-9130-622b513f431e',
+              surveyTemplateId: this.auditForm.surveyTemplateId,
               taskId: this.selectedProject.taskId,
+              materialId: '', // 根据API文档,此参数为必填,但当前没有值,保留空字符串
               periodRecordId: '', // 非必填参数
             }
 
@@ -900,24 +861,12 @@
             const uploadRes = await importExcel(formData, queryParams)
 
             // 第四步:检查上传结果
-            if (!uploadRes || !uploadRes.value) {
+            if (!uploadRes.state) {
               this.$message.error('导入失败!')
               return
             }
-
-            // 第五步:文件上传成功后,再更新数据
-            // const fileInfo = uploadRes.value
-            // 创建更新数据对象
-            // const updateData = {
-            //   id: row.id,
-            //   scanDocumentUrl: fileInfo?.savePath, // 更新扫描件URL
-            // }
-
-            // 第六步:调用更新API
-            // await updateScan(updateData)
-
-            // 第七步:更新成功,显示提示并刷新
             this.$message.success('导入成功')
+            this.loadTemplateData()
             // this.$emit('refresh', this.project.projectId) // 通知父组件刷新
           } catch (error) {
             // 错误处理
@@ -934,81 +883,62 @@
         if (this.costAuditData.length === 0) {
           return
         }
-        // this.$message({ type: 'info', message: '导出数据' })
         // 显示加载状态
-        this.$loading({
+        const loading = this.$loading({
           lock: true,
           text: '文件下载中...',
           spinner: 'el-icon-loading',
           background: 'rgba(0, 0, 0, 0.7)',
         })
 
-        // 从API中获取文件URL
+        // 调用导出API
         exportExcel({
-          surveyTemplateId:
-            this.costAuditData[0].surveyTemplateId ||
-            '62d10551-1576-49b0-9130-622b513f431e',
-          versionId: this.costAuditData[0].versionId || '',
+          // surveyTemplateId: '1985224388517109760', // 测试用  1989165590455066624
+          surveyTemplateId: this.auditForm.surveyTemplateId,
+          versionId: this.tableHeadersRes[0].versionId || '',
         })
           .then((res) => {
-            // 关闭加载状态
-            this.$loading().close()
-
-            // 检查返回结果是否成功
-            if (!res || !res.state) {
-              this.$message.error(
-                `下载失败:${res?.message || '未获取到文件数据'}`
-              )
-              return
-            }
-
-            // 获取文件URL
-            const fileUrl = res.value
-            if (!fileUrl) {
-              this.$message.error('下载失败:未获取到文件URL')
-              return
+            // 从响应头获取文件名(如果有)
+            let fileName = `成本审核模板_${new Date()
+              .toLocaleString()
+              .replace(/[:\s]/g, '_')}.xlsx`
+            if (res.headers && res.headers['content-disposition']) {
+              const contentDisposition = res.headers['content-disposition']
+              const match = contentDisposition.match(/filename=([^;]+)/i)
+              if (match && match[1]) {
+                fileName = decodeURIComponent(match[1].replace(/['"]/g, ''))
+              }
             }
 
-            // 优先从URL中提取文件名
-            let fileName = ''
+            // 使用a标签方式下载文件
+            const blobData = new Blob([res.data], {
+              type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+            })
 
-            // 从URL中提取文件名
-            const urlParts = fileUrl.split('/')
-            let urlFileName = urlParts[urlParts.length - 1]
+            // 创建URL对象
+            const url = window.URL.createObjectURL(blobData)
 
-            // 处理URL可能包含查询参数的情况
-            if (urlFileName.includes('?')) {
-              urlFileName = urlFileName.split('?')[0]
-            }
+            // 创建a标签
+            const a = document.createElement('a')
+            a.style.display = 'none'
+            a.href = url
+            a.download = fileName // 设置下载文件名
 
-            // 检查从URL提取的文件名是否有效
-            if (urlFileName && /\.[a-zA-Z0-9]+$/.test(urlFileName)) {
-              fileName = urlFileName
-            } else {
-              // URL中无法提取有效文件名时,使用row.documentName作为备选
-              fileName =
-                row.documentName || `成本核定表审核_${new Date().getTime()}`
-
-              // 确保备选文件名有扩展名
-              if (!/\.[a-zA-Z0-9]+$/.test(fileName)) {
-                fileName += '.pdf'
-              }
-            }
-            // 创建隐藏的a标签进行下载
-            const link = document.createElement('a')
-            link.style.display = 'none'
-            link.href = fileUrl
-            // link.href = window.context.form + row.electronicDocumentUrl
-            // 设置下载文件名
-            link.download = fileName
-            document.body.appendChild(link)
-            link.click()
-            document.body.removeChild(link)
+            // 添加到DOM并触发点击
+            document.body.appendChild(a)
+            a.click()
+            // 关闭加载状态
+            loading.close()
+            // 清理
+            setTimeout(() => {
+              document.body.removeChild(a)
+              window.URL.revokeObjectURL(url) // 释放URL对象,避免内存泄漏
+            }, 100)
           })
           .catch((error) => {
             // 关闭加载状态
-            this.$loading().close()
-            console.error('获取文件URL失败:', error)
+            loading.close()
+            console.error('文件下载失败:', error)
           })
       },