Преглед изворни кода

Merge remote-tracking branch 'origin/master'

zzw пре 1 месец
родитељ
комит
e2aa8c87c5
27 измењених фајлова са 1249 додато и 441 уклоњено
  1. 1 1
      src/api/audit/survey.js
  2. 1 3
      src/api/costFormManage.js
  3. 26 0
      src/api/costVerifyManage.js
  4. 30 1
      src/components/task/cbjsInfo.vue
  5. 203 44
      src/components/task/components/costAudit.vue
  6. 209 10
      src/components/task/components/costSurvey.vue
  7. 26 3
      src/components/task/components/submitData.vue
  8. 25 11
      src/components/task/taskComponents/surveyTab.vue
  9. 118 3
      src/components/task/taskInfo.vue
  10. 2 2
      src/views/EntDeclaration/auditTaskManagement/components/CostSurveyTab.vue
  11. 31 1
      src/views/EntDeclaration/auditTaskManagement/components/DataRequirementsTab.vue
  12. 15 3
      src/views/EntDeclaration/auditTaskManagement/components/DynamicTableDialog.vue
  13. 1 1
      src/views/EntDeclaration/auditTaskManagement/components/SurveyFormDialog.vue
  14. 69 24
      src/views/EntDeclaration/auditTaskManagement/taskFillIn.vue
  15. 286 290
      src/views/costAudit/auditInfo/auditManage/costAudit.vue
  16. 1 1
      src/views/costAudit/auditInfo/auditManage/details.vue
  17. 1 1
      src/views/costAudit/auditInfo/auditManage/index.vue
  18. 3 1
      src/views/costAudit/baseInfo/auditDocNoManage/index.vue
  19. 1 1
      src/views/costAudit/baseInfo/costFormManage/infoMaintain.vue
  20. 29 11
      src/views/costAudit/baseInfo/costVerifyManage/index.vue
  21. 47 0
      src/views/costAudit/baseInfo/financeSheetManage/infoMaintain.vue
  22. 7 3
      src/views/costAudit/projectInfo/auditTaskManage/taskCustomizedRelease/auditNoticeTab.vue
  23. 30 14
      src/views/costAudit/projectInfo/auditTaskManage/taskCustomizedRelease/index.js
  24. 18 6
      src/views/costAudit/projectInfo/auditTaskManage/taskProgressManage/conclusionTab.vue
  25. 66 6
      src/views/costAudit/projectInfo/auditTaskManage/taskProgressManage/detailTabs.vue
  26. 1 0
      src/views/costAudit/projectInfo/auditTaskManage/taskProgressManage/index.vue
  27. 2 0
      src/views/costAudit/projectInfo/auditTaskManage/taskQueryStatistics/index.vue

+ 1 - 1
src/api/audit/survey.js

@@ -5,7 +5,7 @@ const url = window.context.form
 // 成本调查列表
 export function getSurveyList(data) {
   return request({
-    url: url + '/api/enterprise/castTaskInfo/listUploadByCatalogId',
+    url: url + '/api/enterprise/castTaskInfo/listByTaskId',
     method: 'get',
     params: data,
   })

+ 1 - 3
src/api/costFormManage.js

@@ -77,9 +77,7 @@ export function getCostFormVersionsByTemplateId(params) {
   return request({
     url: `${url}/costVerifyTemplateItems/v1/listByTemplateId`,
     method: 'get',
-    params: {
-      surveyTemplateId: params.surveyTemplateId,
-    },
+    params,
   })
 }
 

+ 26 - 0
src/api/costVerifyManage.js

@@ -56,3 +56,29 @@ export function listByVerifyTemplateId(params) {
     params,
   })
 }
+
+export function exportExcel(params) {
+  return request({
+    url: `${url}/api/fdTemplateExport/v1/exportExcel`,
+    method: 'get',
+    params,
+    responseType: 'arraybuffer',
+  })
+}
+
+export function importExcel(data, params) {
+  return request({
+    url: `${url}/api/fdTemplateExport/v1/importExcel`,
+    method: 'post',
+    data,
+    params,
+  })
+}
+// /costVerifyTemplate/v1/getDetail
+export function getVerifyTemplateDetail(params) {
+  return request({
+    url: `${url}/costVerifyTemplate/v1/getDetail`,
+    method: 'get',
+    params,
+  })
+}

+ 30 - 1
src/components/task/cbjsInfo.vue

@@ -8,16 +8,23 @@
       @close="handleClose"
     >
       <!-- 标签页面 - 移除了操作按钮区域 -->
-      <el-tabs v-model="activeTab" type="card" class="audit-tabs">
+      <el-tabs
+        v-model="activeTab"
+        type="card"
+        class="audit-tabs"
+        @tab-click="handleTabClick"
+      >
         <el-tab-pane label="报送资料" name="submitData">
           <submit-data :id="id" :disabled="true" />
         </el-tab-pane>
         <el-tab-pane label="成本调查表" name="costSurvey">
           <cost-survey
             :id="id"
+            ref="costSurveyRef"
             :disabled="true"
             :audited-unit-id="auditedUnitId"
             :catalog-id="catalogId"
+            :task-id="taskId"
           />
         </el-tab-pane>
         <el-tab-pane
@@ -149,6 +156,13 @@
           ''
         )
       },
+      taskId() {
+        return (
+          (this.selectedProject &&
+            (this.selectedProject.taskId || this.selectedProject.taskid)) ||
+          ''
+        )
+      },
     },
     watch: {
       visible(newVal) {
@@ -212,6 +226,21 @@
           this.activeTab = 'submitData'
         }
       },
+      // 标签切换时回调
+      handleTabClick(tab) {
+        if (tab && tab.name === 'costSurvey') {
+          // 切到成本调查表时,调用子组件刷新
+          this.$nextTick(() => {
+            if (
+              this.$refs &&
+              this.$refs.costSurveyRef &&
+              this.$refs.costSurveyRef.loadList
+            ) {
+              this.$refs.costSurveyRef.loadList()
+            }
+          })
+        }
+      },
       handleClose() {
         // 关闭弹窗时触发事件
         this.$emit('update:visible', false)

+ 203 - 44
src/components/task/components/costAudit.vue

@@ -7,19 +7,39 @@
         :rules="rules"
         :disabled="disabled"
       >
-        <el-form-item label="核定模板名称:" prop="surveyTemplateName">
-          <el-input
-            v-model="auditForm.surveyTemplateName"
-            style="width: 350px"
-            clearable
-            placeholder="请输入核定模板名称"
-          ></el-input>
-        </el-form-item>
+        <el-row>
+          <el-col :span="6">
+            <el-form-item label="" prop="catalogId">
+              <div
+                style="display: flex; justify-self: start; align-items: center"
+              >
+                <div style="width: 120px">监审类别:</div>
+                <el-cascader
+                  v-model="auditForm.catalogId"
+                  :options="catalogListOptions"
+                  v-bind="props"
+                  style="width: 200px"
+                  clearable
+                ></el-cascader>
+              </div>
+            </el-form-item>
+          </el-col>
+          <el-col :span="6">
+            <el-form-item label="核定模板名称:" prop="surveyTemplateName">
+              <el-input
+                v-model="auditForm.surveyTemplateName"
+                style="width: 200px"
+                clearable
+                placeholder="请输入核定模板名称"
+              ></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
         <el-row :gutter="20">
-          <el-col :span="12">
+          <el-col :span="6">
             <el-form-item label="" prop="templateType">
               <div
-                style="display: flex; align-items: center; margin-bottom: 10px"
+                style="display: flex; justify-self: start; align-items: center"
               >
                 <el-radio
                   v-model="auditForm.templateType"
@@ -31,7 +51,6 @@
                 <el-select
                   v-model="auditForm.dataTable"
                   placeholder="请选择"
-                  style="width: 300px"
                   :disabled="auditForm.templateType !== '1'"
                 >
                   <el-option
@@ -44,12 +63,10 @@
               </div>
             </el-form-item>
           </el-col>
-        </el-row>
-        <el-row :gutter="20">
-          <el-col :span="12">
+          <el-col :span="6">
             <el-form-item label="" prop="">
               <div
-                style="display: flex; align-items: center; margin-bottom: 10px"
+                style="display: flex; justify-self: start; align-items: center"
               >
                 <el-radio
                   v-model="auditForm.templateType"
@@ -61,7 +78,6 @@
                 <el-select
                   v-model="auditForm.historyTemplate"
                   placeholder="请选择"
-                  style="width: 300px"
                   :disabled="auditForm.templateType !== '2'"
                 >
                   <el-option
@@ -112,16 +128,15 @@
   } from '@/api/costFormManage'
   import {
     getlistBySurveyTemplateId,
-    batchDeleteCostVerifyForm,
-    getlistBySurveyTemplateIdcurrentversion,
-    batchSave,
-    enable,
-    getListFixedEnabled,
-    listByVerifyTemplateId,
+    getVerifyTemplateDetail,
+    importExcel,
+    exportExcel,
   } from '@/api/costVerifyManage'
   import { getDetail } from '@/api/auditInitiation'
+  import { catalogMixin } from '@/mixins/useDict'
   export default {
     name: 'CostAudit',
+    mixins: [catalogMixin],
     props: {
       id: {
         type: [String, Number],
@@ -148,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: [],
         // 成本调查表模板列表
@@ -161,6 +190,9 @@
           catalogId: '',
         },
         rules: {
+          catalogId: [
+            { required: true, message: '请输选择监审类别', trigger: 'change' },
+          ],
           surveyTemplateName: [
             { required: true, message: '请输入模版名称', trigger: 'blur' },
           ],
@@ -277,22 +309,31 @@
         if (newVal) {
           this.$nextTick(() => {
             // 获取项目的成本审核表数据
-            // 获取项目的详情数据
-            getDetail({ id: newVal.projectId }).then((res) => {
-              if (res.code === 200) {
-                this.project = res.value
-                this.auditForm.catalogId = res.value.catalogId
-              }
-            })
+            this.getDetail()
           })
         }
       },
     },
     created() {
+      if (this.selectedProject && this.selectedProject.projectId) {
+        // 获取项目的详情数据
+        this.getDetail()
+      }
       this.getActiveCostVerifyFormListByType()
       this.getActiveCostVerifyFormList()
     },
     methods: {
+      getDetail() {
+        // 获取项目的详情数据
+        getDetail({ id: this.selectedProject.projectId }).then((res) => {
+          if (res.code === 200) {
+            this.project = res.value
+            this.auditForm.catalogId = res.value.catalogId
+            // this.auditForm.surveyTemplateId = '9368f1cf-77e7-49fe-8502-4a7a2da99668'
+            this.loadTemplateData()
+          }
+        })
+      },
       // 获取所有模板类型为固定表的所有启用成本调查表数据
       getActiveCostVerifyFormListByType() {
         getActiveCostVerifyFormListByType().then((res) => {
@@ -387,14 +428,53 @@
           : ''
         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([
           getlistBySurveyTemplateId({
-            surveyTemplateId,
+            surveyTemplateId: this.auditForm.surveyTemplateId,
+            taskId: this.selectedProject.taskId,
           }),
           getCostFormVersionsByTemplateId({
-            surveyTemplateId,
+            surveyTemplateId: this.auditForm.surveyTemplateId,
+            taskId: this.selectedProject.taskId,
           }),
         ])
         // 处理表头数据
@@ -409,11 +489,22 @@
       parseAndDisplayTableHeaders(res) {
         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 = [] // 清空现有列配置
           this.tableHeadersRes.forEach((item) => {
             let column = {
+              ...item,
               prop: item.fieldEname,
               label: item.fieldName,
               width: '150px',
@@ -425,16 +516,18 @@
             prop: 'unit',
             label: '单位',
             width: '80px',
-            align: 'center',
           })
-          if (this.selectedProject.auditPeriod) {
+          // 检查tableHeadersRes数组是否包含年账面值
+          const hasBookValueColumn = this.checkHasBookValueColumn()
+
+          if (!hasBookValueColumn && this.selectedProject.auditPeriod) {
             // 获取审计期间并按年份排序
             let auditPeriod = this.selectedProject.auditPeriod
               .split(',')
               .map((year) => parseInt(year))
               .sort((a, b) => a - b)
               .map((year) => year.toString())
-
+            let num = this.tableHeadersRes.length
             // 按年份顺序生成三个字段
             auditPeriod.forEach((item) => {
               // 账面价值字段
@@ -443,32 +536,98 @@
                 label: item + '年账面值',
                 width: '120px',
                 align: 'right',
+                fieldName: item + '年账面值',
+                fieldType: 'integer',
+                format: '',
+                fieldTypelen: '255',
+                fieldTypenointlen: '',
+                isAuditPeriod: 'true',
+                isRequired: 'true',
+                showVisible: '1',
+                isDict: 'false',
+                dictid: '',
+                dictValue: '',
+                tabtype: this.tableHeadersRes[0].tabtype,
+                surveyTemplateId: this.tableHeadersRes[0].surveyTemplateId,
+                versionId: this.tableHeadersRes[0].versionId,
+                orderNum: this.getMaxOrderNum() + 1,
               }
-
+              this.costAuditcolumn.push(bookValueColumn)
+              this.tableHeadersRes.push(bookValueColumn)
               // 审核字段
               let auditColumn = {
                 prop: 'year' + item + 'Audit',
                 label: item + '年审核调整值',
                 width: '150px',
                 align: 'center',
+                fieldName: item + '年审核调整值',
+                fieldType: 'integer',
+                format: '',
+                fieldTypelen: '255',
+                fieldTypenointlen: '',
+                isRequired: 'true',
+                isAuditPeriod: 'true',
+                showVisible: '1',
+                isDict: 'false',
+                dictid: '',
+                dictValue: '',
+                tabtype: this.tableHeadersRes[0].tabtype,
+                surveyTemplateId: this.tableHeadersRes[0].surveyTemplateId,
+                versionId: this.tableHeadersRes[0].versionId,
+                orderNum: this.getMaxOrderNum() + num + 1,
               }
-
+              this.costAuditcolumn.push(auditColumn)
+              this.tableHeadersRes.push(auditColumn)
               // 核定值字段
               let approvedValueColumn = {
                 prop: 'year' + item + 'ApprovedValue',
                 label: item + '年核定值',
                 width: '120px',
                 align: 'right',
+                fieldName: item + '年核定值',
+                fieldType: 'integer',
+                format: '',
+                fieldTypelen: '255',
+                fieldTypenointlen: '',
+                isRequired: 'true',
+                isAuditPeriod: 'true',
+                showVisible: '1',
+                isDict: 'false',
+                dictid: '',
+                dictValue: '',
+                tabtype: this.tableHeadersRes[0].tabtype,
+                surveyTemplateId: this.tableHeadersRes[0].surveyTemplateId,
+                versionId: this.tableHeadersRes[0].versionId,
+                orderNum: this.getMaxOrderNum() + num + 1,
               }
-
-              // 依次添加三个字段到列配置
-              this.costAuditcolumn.push(bookValueColumn)
-              this.costAuditcolumn.push(auditColumn)
               this.costAuditcolumn.push(approvedValueColumn)
+              this.tableHeadersRes.push(approvedValueColumn)
             })
           }
         }
       },
+      getMaxOrderNum() {
+        if (!this.tableHeadersRes || this.tableHeadersRes.length === 0) {
+          return 0
+        }
+        const maxOrderNum = Math.max(
+          ...this.tableHeadersRes.map((item) => item.orderNum || 0)
+        )
+        return maxOrderNum
+      },
+      // 检查tableHeadersRes数组是否包含年账面值列
+      checkHasBookValueColumn() {
+        if (!this.tableHeadersRes || this.tableHeadersRes.length === 0) {
+          return false
+        }
+        // 检查是否有列的label或fieldName包含'年账面值'字样
+        return this.tableHeadersRes.some((item) => {
+          return (
+            (item.label && item.label.includes('年账面值')) ||
+            (item.fieldName && item.fieldName.includes('年账面值'))
+          )
+        })
+      },
       parseAndDisplayTableData(res) {
         // 清空现有数据
         this.costAuditData = []
@@ -508,8 +667,8 @@
               }
             })
 
-            // 为审计期间的三个字段添加初始值
             if (this.selectedProject && this.selectedProject.auditPeriod) {
+              // 为审计期间的三个字段添加初始值
               // 获取审计期间并按年份排序
               let auditPeriod = this.selectedProject.auditPeriod
                 .split(',')
@@ -519,9 +678,9 @@
 
               // 为每个年份添加三个字段的初始值
               auditPeriod.forEach((year) => {
-                rowData[`year${year}BookValue`] = '' // 账面
-                rowData[`year${year}Audit`] = '' // 审核调整值
-                rowData[`year${year}ApprovedValue`] = '' // 核定值
+                rowData[`${year}BookValue账面值`] = '' // 账面值
+                rowData[`${year}Audit审核调整值`] = '' // 审核调整值
+                rowData[`${year}ApprovedValue核定值`] = '' // 核定值
               })
             }
 

+ 209 - 10
src/components/task/components/costSurvey.vue

@@ -24,6 +24,13 @@
         align="center"
         header-align="center"
       />
+      <!-- 表格类型 -->
+      <el-table-column
+        prop="tableType"
+        label="表格类型"
+        width="120"
+        align="center"
+      />
       <el-table-column
         prop="isRequired"
         label="是否必填"
@@ -31,6 +38,18 @@
         align="center"
         header-align="center"
       />
+      <!-- 是否上传(只读显示) -->
+      <el-table-column label="是否上传" width="100" align="center">
+        <template slot-scope="scope">
+          <span
+            :style="{
+              color: scope.row.isUploaded === true ? '#67c23a' : '#f56c6c',
+            }"
+          >
+            {{ scope.row.isUploaded === true ? '已上传' : '未上传' }}
+          </span>
+        </template>
+      </el-table-column>
       <el-table-column
         label="操作"
         width="120"
@@ -48,7 +67,7 @@
     <!-- 单记录弹窗(查看) -->
     <survey-form-dialog
       :visible.sync="singleDialogVisible"
-      :survey-data="{}"
+      :survey-data="{ ...currentSurveyRow, ...surveyDetailData }"
       :is-view-mode="true"
       :audited-unit-id="
         (currentTemplateRow && currentTemplateRow.auditedUnitId) || ''
@@ -66,6 +85,7 @@
     <!-- 固定表弹窗(查看) -->
     <fixed-table-dialog
       :visible.sync="fixedDialogVisible"
+      :survey-data="surveyDetailData"
       :is-view-mode="true"
       :audited-unit-id="
         (currentTemplateRow && currentTemplateRow.auditedUnitId) || ''
@@ -78,11 +98,14 @@
         ''
       "
       :catalog-id="(currentTemplateRow && currentTemplateRow.catalogId) || ''"
+      :table-items="tableItems"
+      :audit-periods="auditPeriods"
     />
 
     <!-- 动态表弹窗(查看) -->
     <dynamic-table-dialog
       :visible.sync="dynamicDialogVisible"
+      :table-data="dynamicTableData"
       :is-view-mode="true"
       :audited-unit-id="
         (currentTemplateRow && currentTemplateRow.auditedUnitId) || ''
@@ -100,7 +123,12 @@
 </template>
 <script>
   import taskMixins from './taskMixins.js'
-  import { getSurveyList } from '@/api/audit/survey'
+  import {
+    getSurveyList,
+    getSurveyDetail,
+    getSingleRecordSurveyList,
+    getDynamicTableData,
+  } from '@/api/audit/survey'
   import SurveyFormDialog from '@/views/EntDeclaration/auditTaskManagement/components/SurveyFormDialog.vue'
   import FixedTableDialog from '@/views/EntDeclaration/auditTaskManagement/components/FixedTableDialog.vue'
   import DynamicTableDialog from '@/views/EntDeclaration/auditTaskManagement/components/DynamicTableDialog.vue'
@@ -110,25 +138,95 @@
     props: {
       auditedUnitId: { type: String, default: '' },
       catalogId: { type: String, default: '' },
+      taskId: { type: String, default: '' },
     },
     data() {
       return {
         loading: false,
         rows: [],
         currentTemplateRow: null,
+        currentSurveyRow: null,
+        surveyDetailData: {},
+        tableItems: [],
+        auditPeriods: [],
+        dynamicTableData: [],
         singleDialogVisible: false,
         fixedDialogVisible: false,
         dynamicDialogVisible: false,
       }
     },
+    watch: {
+      taskId(newVal, oldVal) {
+        if (newVal && newVal !== oldVal) {
+          this.loadList()
+        }
+      },
+      auditedUnitId(newVal, oldVal) {
+        if (this.taskId && newVal !== oldVal) {
+          this.loadList()
+        }
+      },
+    },
     created() {
-      this.loadList()
+      console.log('auditedUnitId', this.auditedUnitId)
+      console.log('taskId', this.taskId)
+      if (this.taskId) {
+        this.loadList()
+      }
     },
     methods: {
+      // 预取单记录详情作为回显
+      async loadSingleRecordDetail() {
+        this.surveyDetailData = {}
+        const row = this.currentTemplateRow || {}
+        const uploadId = row.uploadId || row.id || ''
+        const auditedUnitId = row.auditedUnitId || this.auditedUnitId || ''
+        if (!uploadId || !auditedUnitId) return
+        try {
+          const params = { uploadId, auditedUnitId }
+          const res = await getSurveyDetail(params)
+          if (res && res.code === 200 && res.value) {
+            const detail = {}
+            const val = res.value
+            if (Array.isArray(val)) {
+              val.forEach((item) => {
+                if (!item || typeof item !== 'object') return
+                const key =
+                  item.rowid !== undefined
+                    ? item.rowid
+                    : item.rowId !== undefined
+                    ? item.rowId
+                    : item.id !== undefined
+                    ? item.id
+                    : undefined
+                const value =
+                  item.rvalue !== undefined
+                    ? item.rvalue
+                    : item.rValue !== undefined
+                    ? item.rValue
+                    : item.value !== undefined
+                    ? item.value
+                    : item.val !== undefined
+                    ? item.val
+                    : ''
+                if (key !== undefined) {
+                  detail[key] = value
+                }
+              })
+            } else if (val && typeof val === 'object') {
+              // 兼容对象结构,直接合并
+              Object.assign(detail, val)
+            }
+            this.surveyDetailData = detail
+          }
+        } catch (e) {
+          this.surveyDetailData = {}
+        }
+      },
       async loadList() {
         try {
           const params = {
-            catalogId: this.catalogId,
+            taskId: this.taskId,
             pageNum: 1,
             pageSize: 100,
           }
@@ -165,7 +263,7 @@
               dataType: it.dataType || '预置模板',
               tableType,
               isRequired: String(it.isRequired) === '1' ? '是' : '否',
-              isUpload: String(it.isUpload) === '1' || it.isUpload === true,
+              isUploaded: String(it.isUpload) === '1' || it.isUpload === true,
               uploadId: it.uploadId || it.id || '',
               surveyTemplateId: it.templateId || it.surveyTemplateId || '',
               catalogId: it.catalogId || this.catalogId || '',
@@ -177,18 +275,119 @@
           this.rows = []
         }
       },
-      handleViewTemplate(row) {
+      async handleViewTemplate(row) {
         this.currentTemplateRow = row || null
+        this.currentSurveyRow = row || null
         const t = String(
           (row && (row.templateType || row.templatetype)) || ''
         ).trim()
-        if (t === '1') this.singleDialogVisible = true
-        else if (t === '2') this.fixedDialogVisible = true
-        else if (t === '3') this.dynamicDialogVisible = true
-        else
+        if (t === '1') {
+          // 单记录:清理并预取详情
+          this.surveyDetailData = {}
+          await this.loadSingleRecordDetail()
+          this.singleDialogVisible = true
+        } else if (t === '2') {
+          // 预加载固定表配置(tableItems)并推断监审期间
+          this.tableItems = []
+          this.auditPeriods = []
+          await this.initFixedTableData()
+          this.fixedDialogVisible = true
+        } else if (t === '3') {
+          // 预加载动态表列表数据
+          this.dynamicTableData = []
+          await this.initDynamicTableData()
+          this.dynamicDialogVisible = true
+        } else {
           this.$message &&
             this.$message.warning &&
             this.$message.warning('未知的模板类型,无法打开预置模板')
+        }
+      },
+      async initFixedTableData() {
+        this.tableItems = []
+        this.auditPeriods = []
+        const row = this.currentTemplateRow || {}
+        const surveyTemplateId = row.templateId || row.surveyTemplateId || ''
+        if (!surveyTemplateId) return
+        try {
+          const params = { surveyTemplateId }
+          const res = await getSingleRecordSurveyList(params)
+          if (res && res.code === 200 && res.value) {
+            const { itemlist } = res.value || {}
+            if (Array.isArray(itemlist) && itemlist.length > 0) {
+              this.tableItems = itemlist.map((item) => ({
+                id: item.id || item.itemId || '',
+                rowid: item.rowid || item.id || item.itemId || '',
+                seq: item.序号,
+                itemName: item.项目 || item.itemName || '',
+                unit: item.unit || '',
+                isCategory: item.isCategory || false,
+                categorySeq: item.categorySeq || '',
+                categoryId: item.categoryId || '',
+                parentid:
+                  item.parentid !== undefined
+                    ? item.parentid
+                    : item.parentId !== undefined
+                    ? item.parentId
+                    : '-1',
+                validateRules: item.validateRules || {},
+                linkageRules: item.linkageRules || {},
+                children: item.children || [],
+                ...item,
+              }))
+            }
+            // 尝试从当前行或配置中解析监审期间
+            const periodStr =
+              row.auditPeriod || (res.value && res.value.auditPeriod) || ''
+            this.auditPeriods = this.parseAuditPeriod(periodStr)
+          }
+        } catch (e) {
+          this.tableItems = []
+          this.auditPeriods = []
+        }
+      },
+      parseAuditPeriod(periodStr) {
+        if (!periodStr) return []
+        const str = String(periodStr)
+        if (str.includes(',')) {
+          return str.split(',').map((p) => String(p).trim())
+        }
+        if (str.includes('-')) {
+          const parts = str.split('-')
+          if (parts.length === 2) {
+            const start = parseInt(parts[0].trim())
+            const end = parseInt(parts[1].trim())
+            const years = []
+            for (let y = start; y <= end; y++) years.push(String(y))
+            return years
+          }
+        }
+        return [String(str)]
+      },
+      async initDynamicTableData() {
+        this.dynamicTableData = []
+        const row = this.currentTemplateRow || {}
+        const uploadId = row.uploadId || row.id || ''
+        const auditedUnitId = row.auditedUnitId || this.auditedUnitId || ''
+        const catalogId = row.catalogId || this.catalogId || ''
+        const surveyTemplateId = row.templateId || row.surveyTemplateId || ''
+        // 动态表列表以 uploadId 为主键查询,auditedUnitId 可选
+        if (!uploadId) return
+        try {
+          const params = {
+            uploadId,
+            ...(auditedUnitId ? { auditedUnitId } : {}),
+            catalogId,
+            surveyTemplateId,
+          }
+          const res = await getDynamicTableData(params)
+          if (res && res.code === 200) {
+            const records = res.value?.records || res.value || []
+            this.dynamicTableData = Array.isArray(records) ? records : []
+          }
+        } catch (e) {
+          this.dynamicTableData = []
+        }
       },
     },
   }

+ 26 - 3
src/components/task/components/submitData.vue

@@ -318,10 +318,33 @@
             this.$message({ type: 'info', message: '已取消操作' })
           })
       },
-      // 查看下载文件
+      // 查看下载文件(与 taskInfo.vue 一致的 kkFileView 预览)
       handleViewDownload(row) {
-        this.$message.info(`查看下载文件:${row.name}`)
-        // 这里可以添加查看下载文件的逻辑
+        console.log(row, '这一行')
+        try {
+          const filePath =
+            row?.filePath ||
+            row?.filepath ||
+            row?.fileUrl ||
+            row?.url ||
+            row?.path ||
+            ''
+          if (!filePath) {
+            this.$message &&
+              this.$message.warning &&
+              this.$message.warning('未找到可预览的文件路径')
+            return
+          }
+          const encodedUrl = encodeURIComponent(
+            Base64.encode((window.context && window.context.form) + filePath)
+          )
+          window.open(`${host}:8012/onlinePreview?url=${encodedUrl}`)
+        } catch (e) {
+          console.error('文件预览失败: ', e)
+          this.$message &&
+            this.$message.error &&
+            this.$message.error('文件预览失败')
+        }
       },
       // 查看报表
       handleViewReport(row) {

+ 25 - 11
src/components/task/taskComponents/surveyTab.vue

@@ -66,13 +66,13 @@
     watch: {
       project: {
         handler(newVal) {
-          const catalogId = this.getCatalogId(newVal)
-          if (catalogId) {
-            // 如果 catalogId 没有变化,不重复加载
-            if (this.projectIdCache === catalogId) {
+          const taskId = this.getTaskId(newVal)
+          if (taskId) {
+            // 如果 taskId 没有变化,不重复加载
+            if (this.projectIdCache === taskId) {
               return
             }
-            this.projectIdCache = catalogId
+            this.projectIdCache = taskId
             // 调用接口加载数据
             this.loadSurveyData()
           }
@@ -83,13 +83,27 @@
     },
     mounted() {
       console.log('project', this.project)
-      // 如果已有 catalogId,立即加载
-      const catalogId = this.getCatalogId(this.project)
-      if (catalogId) {
+      // 如果已有 taskId,立即加载
+      const taskId = this.getTaskId(this.project)
+      if (taskId) {
         this.loadSurveyData()
       }
     },
     methods: {
+      // 从任务信息中获取 taskId
+      getTaskId(project) {
+        if (!project) return null
+        if (project.taskId) return project.taskId
+        if (project.basicInfo && project.basicInfo.taskId)
+          return project.basicInfo.taskId
+        if (
+          project.data &&
+          project.data.basicInfo &&
+          project.data.basicInfo.taskId
+        )
+          return project.data.basicInfo.taskId
+        return null
+      },
       // 从立项信息中获取 catalogId
       getCatalogId(project) {
         if (!project) {
@@ -115,15 +129,15 @@
       },
       // 加载成本调查表数据
       async loadSurveyData() {
-        const catalogId = this.getCatalogId(this.project)
-        if (!catalogId) {
+        const taskId = this.getTaskId(this.project)
+        if (!taskId) {
           return
         }
 
         try {
           this.loading = true
           const params = {
-            catalogId: catalogId,
+            taskId: taskId,
           }
           const res = await getSurveyList(params)
 

+ 118 - 3
src/components/task/taskInfo.vue

@@ -439,7 +439,7 @@
                         "
                         type="text"
                         size="small"
-                        @click="$emit('handleFileView', scope.row)"
+                        @click="handleFileView(scope.row)"
                       >
                         查看
                       </el-button>
@@ -449,7 +449,7 @@
                         "
                         type="text"
                         size="small"
-                        @click="$emit('handleFileDownload', scope.row)"
+                        @click="handleFileDownload(scope.row)"
                       >
                         下载
                       </el-button>
@@ -919,6 +919,113 @@
       this.initData()
     },
     methods: {
+      // 报送资料-查看(同 taskFillIn)
+      handleFileView(row) {
+        console.log(row, '这一行数据')
+        try {
+          const filePath =
+            row?.filePath ||
+            row?.filepath ||
+            row?.fileUrl ||
+            row?.url ||
+            row?.path ||
+            ''
+          if (!filePath) {
+            this.$message &&
+              this.$message.warning &&
+              this.$message.warning('未找到可预览的文件路径')
+            return
+          }
+          const encodedUrl = encodeURIComponent(
+            Base64.encode((window.context && window.context.form) + filePath)
+          )
+          window.open(`${host}:8012/onlinePreview?url=${encodedUrl}`)
+          // 兼容保留:通知父组件
+          this.$emit('handleFileView', row)
+        } catch (e) {
+          console.error('文件预览失败: ', e)
+          this.$message &&
+            this.$message.error &&
+            this.$message.error('文件预览失败')
+        }
+      },
+      // 报送资料-下载(同 taskFillIn)
+      handleFileDownload(row) {
+        if (!row || !row.fileUrl) {
+          this.$message &&
+            this.$message.warning &&
+            this.$message.warning('该资料暂无文件可下载')
+          return
+        }
+        this.downloadByFetch(row.fileUrl, row.informationName || '下载文件')
+      },
+      async downloadByFetch(rawUrl, fallbackName) {
+        const url = this.normalizeUrl(rawUrl)
+        let loading
+        try {
+          loading = this.$baseLoading
+            ? this.$baseLoading(1, '文件下载中...')
+            : this.$loading({
+                lock: true,
+                text: '文件下载中...',
+                spinner: 'el-icon-loading',
+                background: 'rgba(0,0,0,0.7)',
+              })
+          const res = await fetch(url, { method: 'GET' })
+          if (!res.ok) throw new Error('下载失败')
+          const blob = await res.blob()
+          let fileName =
+            this.extractFileName(res.headers.get('content-disposition')) ||
+            fallbackName ||
+            '下载文件'
+          if (!/\.[a-zA-Z0-9]+$/.test(fileName)) {
+            const extFromUrl = (
+              url.split('?')[0].split('#')[0].split('.').pop() || ''
+            ).toLowerCase()
+            fileName = extFromUrl ? `${fileName}.${extFromUrl}` : fileName
+          }
+          const objectUrl = window.URL.createObjectURL(blob)
+          const link = document.createElement('a')
+          link.style.display = 'none'
+          link.href = objectUrl
+          link.download = fileName
+          document.body.appendChild(link)
+          link.click()
+          document.body.removeChild(link)
+          window.URL.revokeObjectURL(objectUrl)
+          this.$message &&
+            this.$message.success &&
+            this.$message.success('开始下载文件')
+        } catch (e) {
+          this.$message &&
+            this.$message.error &&
+            this.$message.error(e.message || '文件下载失败')
+        } finally {
+          if (loading && loading.close) loading.close()
+        }
+      },
+      normalizeUrl(u) {
+        if (!u) return ''
+        if (/^https?:\/\//i.test(u)) return u
+        const base = (window.context && window.context.form) || ''
+        if (!base) return u
+        if (u.startsWith('/')) return base + u
+        return base.replace(/\/$/, '') + '/' + u
+      },
+      extractFileName(contentDisposition) {
+        if (!contentDisposition) return ''
+        const match = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/i.exec(
+          contentDisposition
+        )
+        if (match && match[1]) {
+          try {
+            return decodeURIComponent(match[1].replace(/['"]/g, ''))
+          } catch (e) {
+            return match[1].replace(/['"]/g, '')
+          }
+        }
+        return ''
+      },
       // 初始化数据
       initData() {
         this.getAllUnitList()
@@ -1187,8 +1294,16 @@
         // }
         try {
           this.loading = true
+          // getSurveyList 现在按 taskId 查询
+          if (!this.currentTaskInfo || !this.currentTaskInfo.taskId) {
+            this.formData.costSurveyData = []
+            this.costSurveyPagination.total = 0
+            this.tabLoadedStatus.costSurvey = true
+            this.loading = false
+            return
+          }
           const params = {
-            catalogId: this.catalogId,
+            taskId: this.currentTaskInfo.taskId,
             pageNum: this.costSurveyPagination.currentPage,
             pageSize: this.costSurveyPagination.pageSize,
           }

+ 2 - 2
src/views/EntDeclaration/auditTaskManagement/components/CostSurveyTab.vue

@@ -154,14 +154,14 @@
             >
               在线填报
             </el-button>
-            <el-button
+            <!-- <el-button
               type="text"
               size="small"
               :disabled="isViewMode"
               @click="$emit('handle-modify', scope.row)"
             >
               修改
-            </el-button>
+            </el-button> -->
             <el-button
               type="text"
               size="small"

+ 31 - 1
src/views/EntDeclaration/auditTaskManagement/components/DataRequirementsTab.vue

@@ -114,7 +114,7 @@
                 v-if="scope.row.isUpload === 1 || scope.row.isUpload === '1'"
                 type="text"
                 size="small"
-                @click="$emit('handleFileView', scope.row)"
+                @click="handleFileView(scope.row)"
               >
                 查看
               </el-button>
@@ -226,6 +226,36 @@
     },
 
     methods: {
+      // 预览:与 UploadComponent.vue 的 handlePreview 一致
+      handleFileView(row) {
+        console.log(row, '这一行数据')
+        try {
+          const filePath =
+            row?.filePath ||
+            row?.filepath ||
+            row?.fileUrl ||
+            row?.url ||
+            row?.path ||
+            ''
+          if (!filePath) {
+            this.$message &&
+              this.$message.warning &&
+              this.$message.warning('未找到可预览的文件路径')
+            return
+          }
+          const encodedUrl = encodeURIComponent(
+            Base64.encode((window.context && window.context.form) + filePath)
+          )
+          window.open(`${host}:8012/onlinePreview?url=${encodedUrl}`)
+          // 兼容保留:通知父组件
+          this.$emit('handleFileView', row)
+        } catch (e) {
+          console.error('文件预览失败: ', e)
+          this.$message &&
+            this.$message.error &&
+            this.$message.error('文件预览失败')
+        }
+      },
       // 根据资料类型返回上传accept白名单
       getUploadAccept(row) {
         const fmt = row && row.formatRequired

+ 15 - 3
src/views/EntDeclaration/auditTaskManagement/components/DynamicTableDialog.vue

@@ -84,7 +84,6 @@
           <el-button
             type="text"
             size="small"
-            :disabled="isViewMode"
             @click="handleViewDetail(scope.row)"
           >
             详情
@@ -266,6 +265,15 @@
         type: String,
         default: '',
       },
+      // 任务ID(用于新增动态表数据)
+      taskId: {
+        type: String,
+        default: '',
+      },
+      projectId: {
+        type: String,
+        default: '',
+      },
       // 表格数据
       tableData: {
         type: Array,
@@ -737,6 +745,8 @@
             const catalogId = this.catalogId || sd.catalogId || ''
             const surveyTemplateId =
               this.surveyTemplateId || sd.surveyTemplateId || ''
+            const taskId = this.taskId || sd.taskId || ''
+            const projectId = this.projectId || sd.projectId || ''
             // if (!uploadId || !auditedUnitId) {
             //   Message.error('缺少必要参数:uploadId 或 auditedUnitId')
             //   this.adding = false
@@ -748,6 +758,8 @@
               auditedUnitId,
               catalogId,
               surveyTemplateId,
+              taskId,
+              projectId,
               auditPeriod: this.addForm.auditPeriod,
               reportingTime: this.addForm.reportingTime || now,
             }
@@ -759,11 +771,11 @@
               // 触发刷新事件,通知父组件刷新列表
               this.$emit('refresh')
             } else {
-              Message.error(res?.message || '新增失败')
+              Message.error(res?.message)
             }
           } catch (e) {
             console.error('新增失败:', e)
-            Message.error('新增失败')
+            // Message.error('新增失败')
           } finally {
             this.adding = false
           }

+ 1 - 1
src/views/EntDeclaration/auditTaskManagement/components/SurveyFormDialog.vue

@@ -14,7 +14,7 @@
         <!-- 动态生成表单字段 -->
         <el-col
           v-for="(field, index) in effectiveFormFields"
-          :key="field.prop || field.id || `field-${index}`"
+          :key="`${field.prop || field.id || 'field'}-${index}`"
           :span="field.colSpan || 12"
         >
           <el-form-item :label="field.label" :prop="field.prop">

+ 69 - 24
src/views/EntDeclaration/auditTaskManagement/taskFillIn.vue

@@ -104,6 +104,8 @@
               :is-view-mode="isViewMode"
               :audited-unit-id="auditedUnitId"
               :catalog-id="taskInfo.catalogId"
+              :task-id="taskInfo.taskId"
+              :project-id="taskInfo.projectId"
               :audit-period="getAuditPeriodArray()"
               @handle-modify="handleModify"
               @handle-data-download="handleDataDownload"
@@ -1210,10 +1212,12 @@
       getCostSurveyList() {
         this.tabLoading.costSurvey = true
         const params = {
+          taskId: this.taskId || (this.taskInfo && this.taskInfo.taskId) || '',
           catalogId: this.taskInfo.catalogId,
           pageNum: this.costSurveyPagination.currentPage,
           pageSize: this.costSurveyPagination.pageSize,
         }
+        // if (this.auditedUnitId) params.auditedUnitId = this.auditedUnitId
         getSurveyList(params)
           .then((res) => {
             console.log('成本调查表列表', res)
@@ -1475,18 +1479,7 @@
           this.$message.warning('该文书暂无文件可下载')
           return
         }
-
-        // 创建隐藏的a标签进行下载
-        const link = document.createElement('a')
-        link.style.display = 'none'
-        link.href = row.fileUrl
-        // 设置下载文件名
-        link.download = row.name || '文书文件'
-        document.body.appendChild(link)
-        link.click()
-        document.body.removeChild(link)
-
-        this.$message.success('开始下载文件')
+        this.downloadByFetch(row.fileUrl, row.name || '文书文件')
       },
       // 上传附件
       handleUpload(row) {
@@ -1509,18 +1502,70 @@
           this.$message.warning('该资料暂无文件可下载')
           return
         }
-
-        // 创建隐藏的a标签进行下载
-        const link = document.createElement('a')
-        link.style.display = 'none'
-        link.href = row.fileUrl
-        // 设置下载文件名,优先使用资料名称
-        link.download = row.informationName || '下载文件'
-        document.body.appendChild(link)
-        link.click()
-        document.body.removeChild(link)
-
-        this.$message.success('开始下载文件')
+        this.downloadByFetch(row.fileUrl, row.informationName || '下载文件')
+      },
+      async downloadByFetch(rawUrl, fallbackName) {
+        const url = this.normalizeUrl(rawUrl)
+        let loading
+        try {
+          loading = this.$baseLoading
+            ? this.$baseLoading(1, '文件下载中...')
+            : this.$loading({
+                lock: true,
+                text: '文件下载中...',
+                spinner: 'el-icon-loading',
+                background: 'rgba(0,0,0,0.7)',
+              })
+          const res = await fetch(url, { method: 'GET' })
+          if (!res.ok) throw new Error('下载失败')
+          const blob = await res.blob()
+          let fileName =
+            this.extractFileName(res.headers.get('content-disposition')) ||
+            fallbackName ||
+            '下载文件'
+          if (!/\.[a-zA-Z0-9]+$/.test(fileName)) {
+            const extFromUrl = (
+              url.split('?')[0].split('#')[0].split('.').pop() || ''
+            ).toLowerCase()
+            fileName = extFromUrl ? `${fileName}.${extFromUrl}` : fileName
+          }
+          const objectUrl = window.URL.createObjectURL(blob)
+          const link = document.createElement('a')
+          link.style.display = 'none'
+          link.href = objectUrl
+          link.download = fileName
+          document.body.appendChild(link)
+          link.click()
+          document.body.removeChild(link)
+          window.URL.revokeObjectURL(objectUrl)
+          this.$message.success('开始下载文件')
+        } catch (e) {
+          this.$message.error(e.message || '文件下载失败')
+        } finally {
+          if (loading && loading.close) loading.close()
+        }
+      },
+      normalizeUrl(u) {
+        if (!u) return ''
+        if (/^https?:\/\//i.test(u)) return u
+        const base = (window.context && window.context.form) || ''
+        if (!base) return u
+        if (u.startsWith('/')) return base + u
+        return base.replace(/\/$/, '') + '/' + u
+      },
+      extractFileName(contentDisposition) {
+        if (!contentDisposition) return ''
+        const match = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/i.exec(
+          contentDisposition
+        )
+        if (match && match[1]) {
+          try {
+            return decodeURIComponent(match[1].replace(/['"]/g, ''))
+          } catch (e) {
+            return match[1].replace(/['"]/g, '')
+          }
+        }
+        return ''
       },
       // 报送资料文件上传
       async handleFileUpload(row, acceptFromChild) {

+ 286 - 290
src/views/costAudit/auditInfo/auditManage/costAudit.vue

@@ -1,7 +1,12 @@
 <template>
   <div class="app-container">
     <div class="audit-controls">
-      <el-form ref="auditForm" :model="auditForm" :rules="rules">
+      <el-form
+        ref="auditForm"
+        :model="auditForm"
+        :rules="rules"
+        :disabled="auditForm.surveyTemplateId !== ''"
+      >
         <el-row>
           <el-col :span="6">
             <el-form-item label="" prop="catalogId">
@@ -87,7 +92,12 @@
           </el-col>
         </el-row>
       </el-form>
-      <el-button type="primary" size="small" @click="handleGenerateTemplate">
+      <el-button
+        v-if="!auditForm.surveyTemplateId"
+        type="primary"
+        size="small"
+        @click="handleGenerateTemplate"
+      >
         生成核定表
       </el-button>
       <el-button type="primary" size="small" @click="handleSaveTemplate">
@@ -162,15 +172,13 @@
   } from '@/api/costFormManage'
   import {
     getlistBySurveyTemplateId,
-    batchDeleteCostVerifyForm,
-    getlistBySurveyTemplateIdcurrentversion,
-    batchSave,
-    enable,
-    getListFixedEnabled,
-    listByVerifyTemplateId,
+    getVerifyTemplateDetail,
+    importExcel,
+    exportExcel,
   } from '@/api/costVerifyManage'
   import { getDetail } from '@/api/auditInitiation'
   import { catalogMixin } from '@/mixins/useDict'
+  import { saveAs } from 'file-saver'
   export default {
     name: 'CostAudit',
     mixins: [catalogMixin],
@@ -233,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: {},
       }
     },
@@ -342,12 +260,7 @@
         if (newVal) {
           this.$nextTick(() => {
             // 获取项目的详情数据
-            getDetail({ id: newVal.projectId }).then((res) => {
-              if (res.code === 200) {
-                this.project = res.value
-                this.auditForm.catalogId = res.value.catalogId
-              }
-            })
+            this.getDetail()
           })
         }
       },
@@ -355,19 +268,24 @@
     created() {
       if (this.selectedProject && this.selectedProject.projectId) {
         // 获取项目的详情数据
-        getDetail({ id: this.selectedProject.projectId }).then((res) => {
-          if (res.code === 200) {
-            this.project = res.value
-            this.auditForm.catalogId = res.value.catalogId
-            this.loadTemplateDataForEdit()
-          }
-        })
+        this.getDetail()
       }
       this.getActiveCostVerifyFormListByType()
       this.getActiveCostVerifyFormList()
       // this.handleGenerateTemplate1()
     },
     methods: {
+      getDetail() {
+        // 获取项目的详情数据
+        getDetail({ id: this.selectedProject.projectId }).then((res) => {
+          if (res.code === 200) {
+            this.project = res.value
+            this.auditForm.catalogId = res.value.catalogId
+            // this.auditForm.surveyTemplateId = '9368f1cf-77e7-49fe-8502-4a7a2da99668'
+            this.loadTemplateData()
+          }
+        })
+      },
       // 获取所有模板类型为固定表的所有启用成本调查表数据
       getActiveCostVerifyFormListByType() {
         getActiveCostVerifyFormListByType().then((res) => {
@@ -461,16 +379,54 @@
           : ''
         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([
           getlistBySurveyTemplateId({
-            surveyTemplateId: this.auditForm.surveyTemplateId,
             taskId: this.selectedProject.taskId,
+            surveyTemplateId: this.auditForm.surveyTemplateId,
           }),
           getCostFormVersionsByTemplateId({
-            surveyTemplateId: this.auditForm.surveyTemplateId,
             taskId: this.selectedProject.taskId,
+            surveyTemplateId: '',
           }),
         ])
         // 处理表头数据
@@ -485,6 +441,7 @@
       parseAndDisplayTableHeaders(res) {
         this.tableHeadersRes = Array.isArray(res.value) ? res.value : []
         if (this.tableHeadersRes.length > 0) {
+          this.auditForm.surveyTemplateId = res.value[0].surveyTemplateId
           // 表头按照orderNum重新排序
           this.tableHeadersRes.sort((a, b) => a.orderNum - b.orderNum)
           this.costAuditcolumn = [] // 清空现有列配置
@@ -503,7 +460,10 @@
             label: '单位',
             width: '80px',
           })
-          if (this.selectedProject.auditPeriod) {
+          // 检查tableHeadersRes数组是否包含年账面值
+          const hasBookValueColumn = this.checkHasBookValueColumn()
+
+          if (!hasBookValueColumn && this.selectedProject.auditPeriod) {
             // 获取审计期间并按年份排序
             let auditPeriod = this.selectedProject.auditPeriod
               .split(',')
@@ -520,10 +480,11 @@
                 width: '120px',
                 align: 'right',
                 fieldName: item + '年账面值',
-                fieldType: 'string',
-                format: '255',
-                fieldTypelen: '',
+                fieldType: 'integer',
+                format: '',
+                fieldTypelen: '255',
                 fieldTypenointlen: '',
+                isAuditPeriod: 'true',
                 isRequired: 'true',
                 showVisible: '1',
                 isDict: 'false',
@@ -532,9 +493,10 @@
                 tabtype: this.tableHeadersRes[0].tabtype,
                 surveyTemplateId: this.tableHeadersRes[0].surveyTemplateId,
                 versionId: this.tableHeadersRes[0].versionId,
-                orderNum: num + 1,
+                orderNum: this.getMaxOrderNum() + 1,
               }
-
+              this.costAuditcolumn.push(bookValueColumn)
+              this.tableHeadersRes.push(bookValueColumn)
               // 审核字段
               let auditColumn = {
                 prop: 'year' + item + 'Audit',
@@ -542,11 +504,12 @@
                 width: '150px',
                 align: 'center',
                 fieldName: item + '年审核调整值',
-                fieldType: 'string',
-                format: '255',
-                fieldTypelen: '',
+                fieldType: 'integer',
+                format: '',
+                fieldTypelen: '9',
                 fieldTypenointlen: '',
                 isRequired: 'true',
+                isAuditPeriod: 'true',
                 showVisible: '1',
                 isDict: 'false',
                 dictid: '',
@@ -554,9 +517,10 @@
                 tabtype: this.tableHeadersRes[0].tabtype,
                 surveyTemplateId: this.tableHeadersRes[0].surveyTemplateId,
                 versionId: this.tableHeadersRes[0].versionId,
-                orderNum: num + 2,
+                orderNum: this.getMaxOrderNum() + num + 1,
               }
-
+              this.costAuditcolumn.push(auditColumn)
+              this.tableHeadersRes.push(auditColumn)
               // 核定值字段
               let approvedValueColumn = {
                 prop: 'year' + item + 'ApprovedValue',
@@ -564,11 +528,12 @@
                 width: '120px',
                 align: 'right',
                 fieldName: item + '年核定值',
-                fieldType: 'string',
-                format: '255',
-                fieldTypelen: '',
+                fieldType: 'integer',
+                format: '',
+                fieldTypelen: '255',
                 fieldTypenointlen: '',
                 isRequired: 'true',
+                isAuditPeriod: 'true',
                 showVisible: '1',
                 isDict: 'false',
                 dictid: '',
@@ -576,20 +541,36 @@
                 tabtype: this.tableHeadersRes[0].tabtype,
                 surveyTemplateId: this.tableHeadersRes[0].surveyTemplateId,
                 versionId: this.tableHeadersRes[0].versionId,
-                orderNum: num + 3,
+                orderNum: this.getMaxOrderNum() + num + 1,
               }
-
-              // 依次添加三个字段到列配置
-              this.costAuditcolumn.push(bookValueColumn)
-              this.costAuditcolumn.push(auditColumn)
               this.costAuditcolumn.push(approvedValueColumn)
-              this.tableHeadersRes.push(bookValueColumn)
-              this.tableHeadersRes.push(auditColumn)
               this.tableHeadersRes.push(approvedValueColumn)
             })
           }
         }
       },
+      getMaxOrderNum() {
+        if (!this.tableHeadersRes || this.tableHeadersRes.length === 0) {
+          return 0
+        }
+        const maxOrderNum = Math.max(
+          ...this.tableHeadersRes.map((item) => item.orderNum || 0)
+        )
+        return maxOrderNum
+      },
+      // 检查tableHeadersRes数组是否包含年账面值列
+      checkHasBookValueColumn() {
+        if (!this.tableHeadersRes || this.tableHeadersRes.length === 0) {
+          return false
+        }
+        // 检查是否有列的label或fieldName包含'年账面值'字样
+        return this.tableHeadersRes.some((item) => {
+          return (
+            (item.label && item.label.includes('年账面值')) ||
+            (item.fieldName && item.fieldName.includes('年账面值'))
+          )
+        })
+      },
       parseAndDisplayTableData(res) {
         // 清空现有数据
         this.costAuditData = []
@@ -629,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${year}BookValue`] = '' // 账面
-                rowData[`year${year}Audit`] = '' // 审核调整值
-                rowData[`year${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)
@@ -655,7 +636,18 @@
         }
       },
       handleSaveTemplate(type) {
-        let headersList = this.tableHeadersRes
+        // 显示加载状态
+        this.$loading({
+          lock: true,
+          text: '保存数据中...',
+          spinner: 'el-icon-loading',
+          background: 'rgba(0, 0, 0, 0.7)',
+        })
+        // 加上遮罩层
+        const headersList = this.tableHeadersRes.map((header, index) => ({
+          ...header,
+          orderNum: header.orderNum || index + 1,
+        }))
         let splitData = this.splitFixedTableDataForSave(this.costAuditData)
 
         let data = {
@@ -665,11 +657,16 @@
         }
         batchSaveOrUpdate(data)
           .then((data) => {
+            // 关闭加载状态
+            this.$loading().close()
             if (type != 'delete') {
               this.$message.success('保存成功')
+              this.loadTemplateData()
             }
           })
           .catch((err) => {
+            // 关闭加载状态
+            this.$loading().close()
             console.log(err)
           })
         // this.$message({ type: 'success', message: '保存成功' })
@@ -683,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.fieldName],
+              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' &&
@@ -744,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并标记为已使用
-              item.orderNum = nextAvailableOrderNum
-              usedOrderNums.add(nextAvailableOrderNum)
+        // 找到当前最大的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) => {
+          // 只为子节点重新分配orderNum
+          if (item.isChild && item.parentid !== -1) {
+            // 找到下一个未使用的orderNum
+            while (usedOrderNums.has(nextAvailableOrderNum)) {
               nextAvailableOrderNum++
             }
-          })
+
+            // 分配新的orderNum并标记为已使用
+            item.orderNum = nextAvailableOrderNum
+            usedOrderNums.add(nextAvailableOrderNum)
+            nextAvailableOrderNum++
+          }
         })
 
         return result
@@ -796,7 +812,6 @@
 
       //
       handleImportData() {
-        return
         let loading = null
         // 第一步:创建文件选择器
         const input = document.createElement('input')
@@ -834,28 +849,24 @@
             const formData = new FormData()
             formData.append('file', file)
 
-            // 先调用上传API
-            // const uploadRes = await uploadFile('/api/file/v1/upload', formData)
-
-            // 第四步:检查上传结果
-            // if (!uploadRes || !uploadRes.value) {
-            //   // this.$message.error('文件上传失败!');
-            //   return
-            // }
-
-            // 第五步:文件上传成功后,再更新数据
-            const fileInfo = uploadRes.value
-            // 创建更新数据对象
-            // const updateData = {
-            //   id: row.id,
-            //   scanDocumentUrl: fileInfo?.savePath, // 更新扫描件URL
-            // }
+            // 其他参数作为query参数传递
+            const queryParams = {
+              surveyTemplateId: this.auditForm.surveyTemplateId,
+              taskId: this.selectedProject.taskId,
+              materialId: '', // 根据API文档,此参数为必填,但当前没有值,保留空字符串
+              periodRecordId: '', // 非必填参数
+            }
 
-            // 第六步:调用更新API
-            // await updateScan(updateData)
+            // 先调用上传API,将参数作为query传递
+            const uploadRes = await importExcel(formData, queryParams)
 
-            // 第七步:更新成功,显示提示并刷新
-            // this.$message.success('文件上传成功并更新数据!')
+            // 第四步:检查上传结果
+            if (!uploadRes.state) {
+              this.$message.error('导入失败!')
+              return
+            }
+            this.$message.success('导入成功')
+            this.loadTemplateData()
             // this.$emit('refresh', this.project.projectId) // 通知父组件刷新
           } catch (error) {
             // 错误处理
@@ -869,80 +880,65 @@
         input.click()
       },
       handleExportTemplate() {
-        return
-
-        // this.$message({ type: 'info', message: '导出数据' })
+        if (this.costAuditData.length === 0) {
+          return
+        }
         // 显示加载状态
-        this.$loading({
+        const loading = this.$loading({
           lock: true,
           text: '文件下载中...',
           spinner: 'el-icon-loading',
           background: 'rgba(0, 0, 0, 0.7)',
         })
 
-        // 从API中获取文件URL
-        downDocument({
-          id: row.id,
+        // 调用导出API
+        exportExcel({
+          // 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 = ''
-
-            // 从URL中提取文件名
-            const urlParts = fileUrl.split('/')
-            let urlFileName = urlParts[urlParts.length - 1]
+            // 使用a标签方式下载文件
+            const blobData = new Blob([res.data], {
+              type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+            })
 
-            // 处理URL可能包含查询参数的情况
-            if (urlFileName.includes('?')) {
-              urlFileName = urlFileName.split('?')[0]
-            }
+            // 创建URL对象
+            const url = window.URL.createObjectURL(blobData)
 
-            // 检查从URL提取的文件名是否有效
-            if (urlFileName && /\.[a-zA-Z0-9]+$/.test(urlFileName)) {
-              fileName = urlFileName
-            } else {
-              // URL中无法提取有效文件名时,使用row.documentName作为备选
-              fileName =
-                row.documentName || `成本核定表审核_${new Date().getTime()}`
+            // 创建a标签
+            const a = document.createElement('a')
+            a.style.display = 'none'
+            a.href = url
+            a.download = fileName // 设置下载文件名
 
-              // 确保备选文件名有扩展名
-              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)
           })
       },
 

+ 1 - 1
src/views/costAudit/auditInfo/auditManage/details.vue

@@ -464,7 +464,7 @@
         console.log(this.taskInfo, '这行数据')
         try {
           const params = {
-            catalogId: this.catalogId,
+            taskId: this.taskInfo.taskId,
             pageNum: this.costSurveyPagination.currentPage,
             pageSize: this.costSurveyPagination.pageSize,
           }

+ 1 - 1
src/views/costAudit/auditInfo/auditManage/index.vue

@@ -194,7 +194,7 @@
     <!-- 成本监审信息弹窗 -->
     <cbjs-info
       :id="cbjsInfoData && cbjsInfoData.id"
-      :selected-project="selectedProject"
+      :selected-project="cbjsInfoData"
       :visible.sync="cbjsInfoVisible"
       :current-node="cbjsInfoData && cbjsInfoData.currentNode"
       :current-status="cbjsInfoData && cbjsInfoData.status"

+ 3 - 1
src/views/costAudit/baseInfo/auditDocNoManage/index.vue

@@ -456,7 +456,9 @@
             label: '适用区域',
             showOverflowTooltip: true,
             align: 'center',
-            formatter: (row) => this.regionNameMap[row.areaCode] || '-',
+            formatter: (row) => {
+              return this.regionNameMap[row.areaCode] || '-'
+            },
           },
           {
             prop: 'generateType',

+ 1 - 1
src/views/costAudit/baseInfo/costFormManage/infoMaintain.vue

@@ -3208,7 +3208,7 @@
               row.status = '0'
               putSurveyTemplatePublishVersion(row).then((res) => {
                 if (res.code === 200) {
-                  this.$message.success(`用成功`)
+                  this.$message.success(`用成功`)
                   this.handleSearch()
                 }
               })

+ 29 - 11
src/views/costAudit/baseInfo/costVerifyManage/index.vue

@@ -759,7 +759,7 @@
                     <el-tag v-else type="info" size="small">无</el-tag>
                   </template>
                 </el-table-column>
-                <el-table-column label="序号" width="150" align="center">
+                <el-table-column label="序号" width="80" align="center">
                   <template slot-scope="scope">
                     <div
                       class="row-indent-container"
@@ -787,6 +787,7 @@
                     .fixedTableHeaders"
                   :key="index"
                   :label="item.rkey"
+                  width="120"
                   align="center"
                 >
                   <template slot-scope="scope">
@@ -2495,16 +2496,22 @@
        * @param {Object} responseData - listByCurrentTemplateId接口返回的数据
        */
       parseAndDisplayFixedTableData(responseData) {
-        if (responseData.value.fixedFields) {
-          this.contentEditForm.fixedTable.fixedTablesTitle =
-            this.stringToObjects(responseData.value.fixedFields || '')
-        } else {
-          let fixedFields = this.contentEditForm.fixedTable.tableHeaders
-            .map((item) => item.fieldName)
-            .join(',')
-          this.contentEditForm.fixedTable.fixedTablesTitle =
-            this.stringToObjects(fixedFields || '')
-        }
+        // if (responseData.value.fixedFields) {
+        //   this.contentEditForm.fixedTable.fixedTablesTitle =
+        //     this.stringToObjects(responseData.value.fixedFields || '')
+        // } else {
+        //   let fixedFields = this.contentEditForm.fixedTable.tableHeaders
+        //     .map((item) => item.fieldName)
+        //     .join(',')
+        //   this.contentEditForm.fixedTable.fixedTablesTitle =
+        //     this.stringToObjects(fixedFields || '')
+        // }
+        let fixedFields = this.contentEditForm.fixedTable.tableHeaders
+          .map((item) => item.fieldName)
+          .join(',')
+        this.contentEditForm.fixedTable.fixedTablesTitle = this.stringToObjects(
+          fixedFields || ''
+        )
         const fixedTitles = this.contentEditForm.fixedTable.fixedTablesTitle
         this.contentEditForm.fixedTable.fixedTableHeaders = fixedTitles.filter(
           (title) => title.rkey !== '序号'
@@ -2766,6 +2773,13 @@
         // 校验表单
         this.$refs['contentEditForm'].validate((valid) => {
           if (valid) {
+            // 显示加载状态
+            this.$loading({
+              lock: true,
+              text: '保存数据中...',
+              spinner: 'el-icon-loading',
+              background: 'rgba(0, 0, 0, 0.7)',
+            })
             if (this.dialogTitle == '修改成本核定模板') {
               let data = {
                 ...this.contentEditForm,
@@ -2790,11 +2804,15 @@
             }
             batchSaveOrUpdate(data)
               .then((data) => {
+                // 关闭加载状态
+                this.$loading().close()
                 this.dialogVisible = false
                 this.$message.success('保存成功')
                 this.handleSearch()
               })
               .catch((err) => {
+                // 关闭加载状态
+                this.$loading().close()
                 console.log(err)
               })
           } else {

+ 47 - 0
src/views/costAudit/baseInfo/financeSheetManage/infoMaintain.vue

@@ -1840,6 +1840,53 @@
         this.pagination.currentPage = 1
         this.handleSearch()
       },
+      // 启动/停用状态
+      handleStatus(row) {
+        const action = row.status === 0 ? '停用' : '启用'
+        if (row.status === '0') {
+          this.$confirm(`确认要停用该数据吗?`, '操作确认', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning',
+          })
+            .then(() => {
+              row.status = '-1'
+              putSurveyFdTemplatePublishVersion(row).then((res) => {
+                if (res.code === 200) {
+                  this.$message.success(`停用成功`)
+                  this.handleSearch()
+                }
+              })
+            })
+            .catch(() => {
+              this.$message({
+                type: 'info',
+                message: '已取消操作',
+              })
+            })
+        } else if (row.status === '-1') {
+          this.$confirm(`确认要启用该数据吗?`, '操作确认', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning',
+          })
+            .then(() => {
+              row.status = '0'
+              putSurveyFdTemplatePublishVersion(row).then((res) => {
+                if (res.code === 200) {
+                  this.$message.success(`启用成功`)
+                  this.handleSearch()
+                }
+              })
+            })
+            .catch(() => {
+              this.$message({
+                type: 'info',
+                message: '已取消操作',
+              })
+            })
+        }
+      },
 
       handleRowClick(row, column, event) {
         if (column && column.property !== 'checked') {

+ 7 - 3
src/views/costAudit/projectInfo/auditTaskManage/taskCustomizedRelease/auditNoticeTab.vue

@@ -605,12 +605,16 @@
       },
       getWhListData() {
         getData({
-          pageNum: this.selectDocumentWhPagination.currentPage,
+          page: this.selectDocumentWhPagination.currentPage,
           pageSize: this.selectDocumentWhPagination.pageSize,
           whType: this.document.documentId,
         }).then((res) => {
-          this.selectDocumentWhData = res.value.records || []
-          this.selectDocumentWhPagination.total = res.value.total || 0
+          this.selectDocumentWhData = res.rows || []
+          this.selectDocumentWhPagination.total = res.total || 0
+          // 获取区域名称,填充regionNameMap
+          if (this.selectDocumentWhData.length > 0) {
+            this.fetchRegionNames(this.selectDocumentWhData, 'areaCode')
+          }
         })
       },
       selectDocumentWhPaginationChange({ currentPage, pageSize }) {

+ 30 - 14
src/views/costAudit/projectInfo/auditTaskManage/taskCustomizedRelease/index.js

@@ -478,12 +478,12 @@ export const taskMixin = {
         .catch(() => {})
     },
     getBasicInfo() {
-      if (!this.project.projectId) {
-        return
-      }
-      getCostProjectDetail({
-        id: this.project.projectId,
-      })
+      const pid =
+        (this.project && (this.project.projectId || this.project.id)) ||
+        (this.taskData && (this.taskData.projectId || this.taskData.id)) ||
+        ''
+      if (!pid) return
+      getCostProjectDetail({ id: pid })
         .then((res) => {
           this.formData.basicInfo = {
             ...this.project,
@@ -496,9 +496,12 @@ export const taskMixin = {
     },
     // 获取监审工作方案数据
     getScenarioData() {
-      getCostProjectScenarioDetail({
-        projectId: this.project.projectId,
-      }).then((res) => {
+      const pid =
+        (this.project && (this.project.projectId || this.project.id)) ||
+        (this.taskData && (this.taskData.projectId || this.taskData.id)) ||
+        ''
+      if (!pid) return
+      getCostProjectScenarioDetail({ projectId: pid }).then((res) => {
         if (res.value) {
           this.formData.workPlan = res.value
           this.formData.workPlan.attachmentIds = res.value.attachmentIds
@@ -511,10 +514,15 @@ export const taskMixin = {
     },
     // 报送资料要求数据
     getMaterialData() {
+      const pid =
+        (this.project && (this.project.projectId || this.project.id)) ||
+        (this.taskData && (this.taskData.projectId || this.taskData.id)) ||
+        ''
+      if (!pid) return
       getCostProjectMaterialPageList({
         pageNum: this.materialData.pagination.currentPage,
         pageSize: this.materialData.pagination.pageSize,
-        projectId: this.project.projectId,
+        projectId: pid,
       }).then((res) => {
         if (res.value.code == 200) {
           this.materialData.list = res.value.value.records || []
@@ -538,10 +546,15 @@ export const taskMixin = {
     },
     // 获取监审通知数据
     async getDocumentData(data) {
+      const pid =
+        (this.project && (this.project.projectId || this.project.id)) ||
+        (this.taskData && (this.taskData.projectId || this.taskData.id)) ||
+        ''
+      if (!pid) return
       getCostProjectDocumentPageList({
         pageNum: this.documentData.pagination.currentPage,
         pageSize: this.documentData.pagination.pageSize,
-        projectId: this.project.projectId,
+        projectId: pid,
         documentName: data ? data.documentName : '',
       }).then((res) => {
         this.documentData.list = res.value.value.records
@@ -550,9 +563,12 @@ export const taskMixin = {
     },
     // 获取流程数据
     getWorkflow() {
-      getCostProjectNodeTmpleteGetDetail({
-        projectId: this.project.projectId,
-      }).then((res) => {
+      const pid =
+        (this.project && (this.project.projectId || this.project.id)) ||
+        (this.taskData && (this.taskData.projectId || this.taskData.id)) ||
+        ''
+      if (!pid) return
+      getCostProjectNodeTmpleteGetDetail({ projectId: pid }).then((res) => {
         this.workflowData.list = res.value.nodeList || []
         this.workflowData.detailInfo = res.value
         this.formData.workflow.plannedAuditStartDate =

+ 18 - 6
src/views/costAudit/projectInfo/auditTaskManage/taskProgressManage/conclusionTab.vue

@@ -137,13 +137,25 @@
     mounted() {},
     methods: {
       getConclusionDetails() {
-        getConclusionDetail({
-          projectId: this.project.projectId,
-        }).then((res) => {
-          if (res.code === 200) {
-            this.conclusionForm = res.value
+        if (!this.project || !this.project.projectId) return
+        getConclusionDetail({ projectId: this.project.projectId }).then(
+          (res) => {
+            if (res && res.code === 200) {
+              const v = (res && res.value) || {}
+              this.conclusionForm = {
+                pricingCostStructure: v.pricingCostStructure || '',
+                auditContentMethod: v.auditContentMethod || '',
+                costDeductionReason: v.costDeductionReason || '',
+                costAuditConclusion: v.costAuditConclusion || '',
+                defaultConditions: v.defaultConditions || '',
+                otherExplanations: v.otherExplanations || '',
+                conclusionStatus: v.conclusionStatus || '',
+                projectId:
+                  v.projectId || (this.project && this.project.projectId) || '',
+              }
+            }
           }
-        })
+        )
       },
     },
   }

+ 66 - 6
src/views/costAudit/projectInfo/auditTaskManage/taskProgressManage/detailTabs.vue

@@ -105,10 +105,12 @@
         />
       </el-tab-pane>
       <el-tab-pane label="成本调查表" name="survey">
-        <surveyTab
-          :project="project"
-          :is-view="isView"
-          :survey-data="surveyData"
+        <CostSurvey
+          ref="costSurveyRef"
+          :disabled="true"
+          :task-id="taskId"
+          :audited-unit-id="taskData.auditedUnitId"
+          :catalog-id="catalogId"
         />
       </el-tab-pane>
       <el-tab-pane label="监审文书" name="auditNotice">
@@ -133,7 +135,7 @@
 <script>
   import basicInfoTab from '@/views/costAudit/projectInfo/auditTaskManage/taskCustomizedRelease/basicInfoTab.vue'
   import materialTab from '@/views/costAudit/projectInfo/auditTaskManage/taskCustomizedRelease/materialTab.vue'
-  import surveyTab from '@/views/costAudit/projectInfo/auditTaskManage/taskCustomizedRelease/surveyTab.vue'
+  import CostSurvey from '@/components/task/components/costSurvey.vue'
   import meetingTab from './meetingTab.vue'
   import conclusionTab from './conclusionTab.vue'
   import workflowTab from './workflowTab.vue'
@@ -144,7 +146,7 @@
     components: {
       basicInfoTab,
       materialTab,
-      surveyTab,
+      CostSurvey,
       meetingTab,
       conclusionTab,
       workflowTab,
@@ -236,6 +238,47 @@
         },
       }
     },
+    computed: {
+      auditedUnitId() {
+        const p = this.project || {}
+        console.log(this.project, '项目')
+        return (
+          p.auditedUnitId ||
+          (p.basicInfo &&
+            (p.basicInfo.auditedUnitId || p.basicInfo.auditedunitid)) ||
+          (p.data &&
+            p.data.basicInfo &&
+            (p.data.basicInfo.auditedUnitId ||
+              p.data.basicInfo.auditedunitid)) ||
+          ''
+        )
+      },
+      catalogId() {
+        const p = this.project || {}
+        return (
+          p.catalogId ||
+          (p.basicInfo && (p.basicInfo.catalogId || p.basicInfo.catalogid)) ||
+          (p.data &&
+            p.data.basicInfo &&
+            (p.data.basicInfo.catalogId || p.data.basicInfo.catalogid)) ||
+          ''
+        )
+      },
+      taskId() {
+        const t = this.taskData || {}
+        const p = this.project || {}
+        return (
+          t.taskId ||
+          t.id ||
+          p.taskId ||
+          (p.basicInfo && (p.basicInfo.taskId || p.basicInfo.taskid)) ||
+          (p.data &&
+            p.data.basicInfo &&
+            (p.data.basicInfo.taskId || p.data.basicInfo.taskid)) ||
+          ''
+        )
+      },
+    },
     mounted() {
       this.handleTabClick()
     },
@@ -244,6 +287,23 @@
       handleDetailClose() {
         this.$emit('detailClose')
       },
+      // 标签切换:切到成本调查表时加载列表
+      // handleTabClick(tab) {
+      //   if (
+      //     (tab && tab.name === 'survey') ||
+      //     (!tab && this.activeTab === 'survey')
+      //   ) {
+      //     this.$nextTick(() => {
+      //       if (
+      //         this.$refs &&
+      //         this.$refs.costSurveyRef &&
+      //         this.$refs.costSurveyRef.loadList
+      //       ) {
+      //         this.$refs.costSurveyRef.loadList()
+      //       }
+      //     })
+      //   }
+      // },
     },
   }
 </script>

+ 1 - 0
src/views/costAudit/projectInfo/auditTaskManage/taskProgressManage/index.vue

@@ -604,6 +604,7 @@
 
       // 任务详情相关方法
       handleViewTaskDetail(row) {
+        console.log(row, '这行')
         this.taskData = row
         this.getProject()
         this.activeView = 'detail'

+ 2 - 0
src/views/costAudit/projectInfo/auditTaskManage/taskQueryStatistics/index.vue

@@ -102,6 +102,8 @@
     <div v-if="activeView == 'detail'" class="detail-content">
       <detail-tabs
         :project="project"
+        :task-data="taskData"
+        :is-view="true"
         @detailClose="handleDetailClose"
       ></detail-tabs>
     </div>