瀏覽代碼

feat: 成本调查表动态表完成

shiyanyu 1 月之前
父節點
當前提交
01aeb879e2

+ 26 - 0
src/api/audit/survey.js

@@ -37,3 +37,29 @@ export function getSurveyDetail(data) {
     data: data,
   })
 }
+
+// 动态表表格数据
+export function getDynamicTableData(data) {
+  return request({
+    url: url + '/api/enterprise/castTaskInfo/listPeriodRecord',
+    method: 'post',
+    data: data,
+  })
+}
+
+// 动态表新增数据
+export function addDynamicTableData(data) {
+  return request({
+    url: url + '/api/enterprise/castTaskInfo/addPeriodRecord',
+    method: 'post',
+    data: data,
+  })
+}
+
+//动态表删除数据
+export function deleteDynamicTableData(data) {
+  return request({
+    url: url + '/api/enterprise/castTaskInfo/deletePeriodRecord?id=' + data.id,
+    method: 'post',
+  })
+}

+ 17 - 142
src/components/task/cbjsInfo.vue

@@ -8,11 +8,7 @@
       @close="handleClose"
     >
       <!-- 标签页面 - 移除了操作按钮区域 -->
-      <el-tabs
-        v-model="activeTab"
-        type="card"
-        class="audit-tabs disabled-container"
-      >
+      <el-tabs v-model="activeTab" type="card" class="audit-tabs">
         <el-tab-pane label="报送资料" name="submitData">
           <submit-data :id="id" :disabled="true" />
         </el-tab-pane>
@@ -228,7 +224,7 @@
   .audit-tabs .el-tabs__content {
     height: calc(100% - 60px); /* 减去标签头的高度 */
     overflow-y: auto; /* 这是最重要的设置,确保内容超出时显示滚动条 */
-    /* padding: 15px; */
+    padding: 15px;
     box-sizing: border-box;
   }
 
@@ -261,147 +257,26 @@
     width: 100%;
   }
 
-  /* 禁用容器样式 - 所有交互元素不可操作但不改变视觉样式 */
-
-  /* 确保 tab 头部完全可交互 */
-  .disabled-container :deep(.el-tabs__header),
-  .disabled-container :deep(.el-tabs__nav-wrap),
-  .disabled-container :deep(.el-tabs__nav),
-  .disabled-container :deep(.el-tabs__item) {
-    pointer-events: auto !important;
-    cursor: pointer !important;
-  }
-
-  /* 所有输入框禁用交互并置灰 */
-  .disabled-container :deep(.el-input__inner),
-  .disabled-container :deep(.el-input__wrapper),
-  .disabled-container :deep(.el-textarea__inner),
-  .disabled-container :deep(.el-select .el-input__inner),
-  .disabled-container :deep(.el-input-number__input) {
-    background-color: #f5f7fa !important;
-    color: #909399 !important;
-    border-color: #e4e7ed !important;
-    cursor: not-allowed !important;
-    pointer-events: none !important;
-  }
-
-  /* 所有输入框禁用状态 */
-  .disabled-container :deep(.el-input.is-disabled .el-input__inner),
-  .disabled-container :deep(.el-input.is-disabled .el-input__wrapper),
-  .disabled-container :deep(.el-textarea.is-disabled .el-textarea__inner) {
-    background-color: #f5f7fa !important;
-    color: #909399 !important;
-    cursor: not-allowed !important;
-    pointer-events: none !important;
-  }
-
-  /* 所有按钮禁用交互并置灰 */
-  .disabled-container :deep(.el-button) {
-    background-color: #f5f7fa !important;
-    border-color: #e4e7ed !important;
-    color: #909399 !important;
-    cursor: not-allowed !important;
-    pointer-events: none !important;
-  }
-
-  .disabled-container :deep(.el-button--primary) {
-    background-color: #c0c4cc !important;
-    border-color: #c0c4cc !important;
-    color: #fff !important;
-  }
-
-  .disabled-container :deep(.el-button--text) {
-    color: #909399 !important;
-  }
-
-  /* 所有选择器禁用交互并置灰 */
-  .disabled-container :deep(.el-select) {
-    cursor: not-allowed !important;
-    pointer-events: none !important;
-  }
-
-  .disabled-container :deep(.el-select .el-input) {
-    pointer-events: none !important;
-  }
-
-  .disabled-container :deep(.el-select .el-input__inner) {
-    background-color: #f5f7fa !important;
-    color: #909399 !important;
-    border-color: #e4e7ed !important;
-  }
-
-  /* 所有单选框和复选框禁用交互 */
-  .disabled-container :deep(.el-radio),
-  .disabled-container :deep(.el-checkbox) {
-    cursor: not-allowed !important;
-    pointer-events: none !important;
-  }
-
-  .disabled-container :deep(.el-radio__input),
-  .disabled-container :deep(.el-checkbox__input) {
-    pointer-events: none !important;
-  }
-
-  /* 表格内的输入框和按钮置灰 */
-  .disabled-container :deep(.el-table .el-input__inner) {
-    background-color: #f5f7fa !important;
-    color: #909399 !important;
-    border-color: #e4e7ed !important;
-    cursor: not-allowed !important;
-    pointer-events: none !important;
-  }
-
-  .disabled-container :deep(.el-table .el-button) {
-    background-color: #f5f7fa !important;
-    border-color: #e4e7ed !important;
-    color: #909399 !important;
-    cursor: not-allowed !important;
-    pointer-events: none !important;
-  }
-
-  /* 日期选择器置灰 */
-  .disabled-container :deep(.el-date-editor) {
-    cursor: not-allowed !important;
-    pointer-events: none !important;
+  /* 只读样式 */
+  :deep(.el-form-item__content) {
+    color: #909399;
   }
 
-  .disabled-container :deep(.el-date-editor .el-input__inner) {
-    background-color: #f5f7fa !important;
-    color: #909399 !important;
-    border-color: #e4e7ed !important;
+  :deep(.el-input__inner),
+  :deep(.el-select__inner),
+  :deep(.el-textarea__inner) {
+    background-color: #f5f7fa;
+    color: #909399;
+    cursor: not-allowed;
   }
 
-  /* 数字输入框置灰 */
-  .disabled-container :deep(.el-input-number) {
-    cursor: not-allowed !important;
-    pointer-events: none !important;
+  :deep(.el-checkbox),
+  :deep(.el-radio) {
+    cursor: not-allowed;
   }
 
-  .disabled-container :deep(.el-input-number .el-input__inner) {
-    background-color: #f5f7fa !important;
-    color: #909399 !important;
-    border-color: #e4e7ed !important;
-  }
-
-  /* 上传组件 */
-  .disabled-container :deep(.el-upload) {
-    cursor: not-allowed !important;
-    pointer-events: none !important;
-  }
-
-  /* 链接 */
-  .disabled-container :deep(a) {
-    cursor: not-allowed !important;
-    pointer-events: none !important;
-  }
-
-  /* 标签页内容区域恢复交互以便滚动 */
-  .disabled-container .el-tabs__content {
-    pointer-events: auto;
-  }
-
-  /* 但标签页内容内的所有交互元素仍需禁用 */
-  /* .disabled-container .el-tabs__content > * {
+  :deep(.el-button) {
     pointer-events: none;
-  } */
+    opacity: 0.6;
+  }
 </style>

+ 87 - 17
src/views/EntDeclaration/auditTaskManagement/components/CostSurveyTab.vue

@@ -43,12 +43,26 @@
 
     <!-- 动态表填报弹窗 -->
     <dynamic-table-dialog
+      :key="dynamicDialogKey"
       :visible.sync="dynamicTableDialogVisible"
       :survey-data="currentSurveyRow"
       :table-data="dynamicTableData"
       :table-items="tableItems"
       :is-view-mode="isViewMode"
+      :audited-unit-id="auditedUnitId"
+      :upload-id="
+        currentSurveyRow && (currentSurveyRow.uploadId || currentSurveyRow.id)
+          ? currentSurveyRow.uploadId || currentSurveyRow.id
+          : uploadId
+      "
+      :catalog-id="catalogId"
+      :survey-template-id="
+        currentSurveyRow && currentSurveyRow.surveyTemplateId
+          ? currentSurveyRow.surveyTemplateId
+          : surveyTemplateId
+      "
       @save="handleDynamicTableSave"
+      @refresh="handleRefresh"
     />
 
     <el-table
@@ -216,6 +230,7 @@
   import {
     getSingleRecordSurveyList,
     getSurveyDetail,
+    getDynamicTableData,
   } from '@/api/audit/survey'
 
   export default {
@@ -280,6 +295,8 @@
         auditPeriods: [],
         // 动态表数据
         dynamicTableData: [],
+        dynamicDialogKey: 0,
+        dynamicTableLoading: false,
       }
     },
     mounted() {
@@ -335,8 +352,8 @@
           // 接口调用完成后会自动打开弹窗(在 initFixedTableData 中处理)
         } else if (row.tableType === '动态表') {
           // 如果表格类型是"动态表",弹出动态表填报弹窗
-          this.initDynamicTableData()
-          this.dynamicTableDialogVisible = true
+          this.resetDynamicDialogState()
+          await this.initDynamicTableData()
         } else {
           // 其他类型,触发原有事件
           this.$emit('handle-online-fill', row)
@@ -368,28 +385,75 @@
       },
       // 处理动态表保存
       handleDynamicTableSave(tableData) {
-        // 可以将保存的数据传递给父组件
+        // 将保存的数据传递给父组件
         this.$emit('handle-dynamic-table-save', {
           row: this.currentSurveyRow,
           tableData: tableData,
         })
+        // 触发刷新事件
+        this.handleRefresh()
       },
       // 初始化动态表数据
-      initDynamicTableData() {
-        // 如果当前行有动态表数据,则使用
-        if (this.currentSurveyRow && this.currentSurveyRow.dynamicTableData) {
-          this.dynamicTableData = this.currentSurveyRow.dynamicTableData
-        } else {
-          // 使用空数组,组件内部会使用假数据
-          this.dynamicTableData = []
-        }
+      async initDynamicTableData() {
+        try {
+          this.dynamicTableLoading = true
+          const uploadId =
+            (this.currentSurveyRow &&
+              (this.currentSurveyRow.uploadId || this.currentSurveyRow.id)) ||
+            this.uploadId ||
+            ''
+          const auditedUnitId =
+            this.auditedUnitId ||
+            (this.currentSurveyRow && this.currentSurveyRow.auditedUnitId) ||
+            ''
+          const catalogId =
+            (this.currentSurveyRow && this.currentSurveyRow.catalogId) ||
+            this.catalogId ||
+            ''
+          const surveyTemplateId =
+            (this.currentSurveyRow && this.currentSurveyRow.surveyTemplateId) ||
+            this.surveyTemplateId ||
+            ''
 
-        // 初始化表格项配置(用于详情/编辑时显示表单)
-        if (this.currentSurveyRow && this.currentSurveyRow.tableItems) {
-          this.tableItems = this.currentSurveyRow.tableItems
-        } else {
-          // 使用固定表的假数据配置
-          this.tableItems = this.getMockTableItems()
+          const params = {
+            uploadId,
+            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 : []
+          } else {
+            // 接口调用失败,使用当前行的动态表数据或空数组
+            this.dynamicTableData =
+              this.currentSurveyRow?.dynamicTableData || []
+          }
+
+          // 初始化表格项配置(用于详情/编辑时显示表单)
+          if (
+            this.currentSurveyRow &&
+            this.currentSurveyRow.tableItems &&
+            this.currentSurveyRow.tableItems.length > 0
+          ) {
+            this.tableItems = this.currentSurveyRow.tableItems
+          } else {
+            this.tableItems = this.getMockTableItems()
+          }
+
+          this.dynamicTableDialogVisible = true
+        } catch (error) {
+          console.error('获取动态表数据失败', error)
+          // 出错时使用当前行的动态表数据或空数组
+          this.dynamicTableData = this.currentSurveyRow?.dynamicTableData || []
+          this.tableItems =
+            this.currentSurveyRow?.tableItems || this.getMockTableItems()
+          // 出错时也打开弹窗
+          this.dynamicTableDialogVisible = true
+        } finally {
+          this.dynamicTableLoading = false
         }
       },
       // 初始化表单字段配置
@@ -849,6 +913,12 @@
           },
         ]
       },
+      resetDynamicDialogState() {
+        this.dynamicTableDialogVisible = false
+        this.dynamicTableData = []
+        this.tableItems = []
+        this.dynamicDialogKey = Date.now()
+      },
     },
   }
 </script>

+ 775 - 362
src/views/EntDeclaration/auditTaskManagement/components/DynamicTableDialog.vue

@@ -122,6 +122,51 @@
       @size-change="handleSizeChange"
     />
 
+    <!-- 新增记录弹窗(仅监审期间和填报时间) -->
+    <el-dialog
+      title="新增记录"
+      :visible.sync="addDialogVisible"
+      width="500px"
+      :close-on-click-modal="false"
+      append-to-body
+    >
+      <el-form
+        ref="addFormRef"
+        :model="addForm"
+        :rules="addRules"
+        label-width="120px"
+      >
+        <el-form-item label="监审期间" prop="auditPeriod">
+          <el-date-picker
+            v-model="addForm.auditPeriod"
+            type="year"
+            value-format="yyyy"
+            format="yyyy"
+            placeholder="选择年份"
+            style="width: 100%"
+          />
+        </el-form-item>
+        <el-form-item label="填报时间" prop="reportingTime">
+          <el-date-picker
+            v-model="addForm.reportingTime"
+            type="datetime"
+            value-format="yyyy-MM-dd HH:mm:ss"
+            format="yyyy-MM-dd HH:mm:ss"
+            placeholder="不填默认当前时间"
+            style="width: 100%"
+            :default-time="'00:00:00'"
+            clearable
+          />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="addDialogVisible = false">取消</el-button>
+        <el-button type="primary" :loading="adding" @click="handleAddSave">
+          保存
+        </el-button>
+      </div>
+    </el-dialog>
+
     <!-- 详情/编辑弹窗 -->
     <el-dialog
       :title="detailDialogTitle"
@@ -141,8 +186,25 @@
         <fixed-assets-table
           ref="fixedAssetsTable"
           :table-items="localTableItems"
-          :saved-data="currentRow ? currentRow.data || {} : {}"
+          :saved-data="resolvedFixedAssetsSavedData"
           :is-view-mode="!isEditMode"
+          :fixed-fields="fixedFields"
+          :fixed-fieldids="fixedFieldids"
+          :audited-unit-id="
+            auditedUnitId || (surveyData && surveyData.auditedUnitId) || ''
+          "
+          :survey-template-id="
+            surveyTemplateId ||
+            (surveyData && surveyData.surveyTemplateId) ||
+            ''
+          "
+          :catalog-id="catalogId || (surveyData && surveyData.catalogId) || ''"
+          :upload-id="
+            uploadId ||
+            (surveyData && (surveyData.uploadId || surveyData.id)) ||
+            ''
+          "
+          :period-record-id="currentRow ? currentRow.id : ''"
         />
       </div>
       <div slot="footer" class="dialog-footer">
@@ -162,6 +224,13 @@
 <script>
   import { Message, MessageBox } from 'element-ui'
   import FixedAssetsTable from './FixedAssetsTable.vue'
+  import {
+    getDynamicTableData,
+    deleteDynamicTableData,
+    addDynamicTableData,
+    getSingleRecordSurveyList,
+    getSurveyDetail,
+  } from '@/api/audit/survey'
 
   export default {
     name: 'DynamicTableDialog',
@@ -173,10 +242,30 @@
         type: Boolean,
         default: false,
       },
+      // 成本调查表模板ID
+      surveyTemplateId: {
+        type: String,
+        default: '',
+      },
+      // 目录ID
+      catalogId: {
+        type: String,
+        default: '',
+      },
       surveyData: {
         type: Object,
         default: () => ({}),
       },
+      // 上传记录ID(用于查询动态表列表)
+      uploadId: {
+        type: String,
+        default: '',
+      },
+      // 被监审单位ID(用于查询动态表列表)
+      auditedUnitId: {
+        type: String,
+        default: '',
+      },
       // 表格数据
       tableData: {
         type: Array,
@@ -196,6 +285,19 @@
     data() {
       return {
         dialogVisible: false,
+        loading: false,
+        // 新增弹窗状态与表单
+        addDialogVisible: false,
+        adding: false,
+        addForm: {
+          auditPeriod: '',
+          reportingTime: '',
+        },
+        addRules: {
+          auditPeriod: [
+            { required: true, message: '请选择监审期间', trigger: 'change' },
+          ],
+        },
         // 表格数据
         localTableData: [],
         // 选中的行
@@ -213,6 +315,12 @@
         isEditMode: false,
         // 表格项配置(本地)
         localTableItems: [],
+        // 单记录回显数据
+        detailSavedData: null,
+        singleRecordLoading: false,
+        // 固定字段配置
+        fixedFields: '',
+        fixedFieldids: '',
       }
     },
     computed: {
@@ -223,24 +331,32 @@
         const end = start + this.pagination.pageSize
         return this.localTableData.slice(start, end)
       },
+      resolvedFixedAssetsSavedData() {
+        if (this.detailSavedData) {
+          return this.detailSavedData
+        }
+        if (this.currentRow && this.currentRow.data) {
+          return this.currentRow.data
+        }
+        return {}
+      },
     },
     watch: {
-      visible: {
-        handler(newVal) {
-          this.dialogVisible = newVal
-          if (newVal) {
-            this.initTableData()
-            this.initTableItems()
-          }
-        },
-        immediate: true,
-      },
       tableItems: {
         handler(newVal) {
           this.initTableItems()
         },
         deep: true,
       },
+      visible(newVal) {
+        // 监听props的visible变化,同步到dialogVisible
+        this.dialogVisible = newVal
+        console.log(this.dialogVisible, '111')
+        // 如果弹窗打开且有表格数据,初始化表格
+        if (newVal) {
+          this.initTableData()
+        }
+      },
       dialogVisible(newVal) {
         if (!newVal) {
           this.$emit('update:visible', false)
@@ -248,279 +364,349 @@
       },
       tableData: {
         handler(newVal) {
-          this.initTableData()
+          this.loadDynamicTableData()
         },
         deep: true,
       },
     },
     methods: {
+      // 加载动态表数据(对接接口)
+      async loadDynamicTableData() {
+        // 优先使用接口数据(需要 uploadId、auditedUnitId)
+        const sd = this.surveyData || {}
+        const uploadId = this.uploadId || sd.uploadId || sd.id || ''
+        const auditedUnitId = this.auditedUnitId || sd.auditedUnitId || ''
+
+        if (uploadId && auditedUnitId) {
+          try {
+            this.loading = true
+            const params = {
+              uploadId,
+              auditedUnitId,
+            }
+            const res = await getDynamicTableData(params)
+            if (res && res.code === 200) {
+              console.log('res', res)
+              const records = res.value?.records || res.value || []
+              const mapped = (Array.isArray(records) ? records : []).map(
+                (item, idx) => {
+                  return {
+                    id: item.id || item.recordId || `row-${idx + 1}`,
+                    seq: idx + 1,
+                    auditPeriod:
+                      item.auditPeriod ||
+                      item.period ||
+                      item.year ||
+                      item.audit_year ||
+                      '',
+                    fillTime:
+                      item.fillTime ||
+                      item.createTime ||
+                      item.createdTime ||
+                      item.created_at ||
+                      '',
+                    lastModifyTime:
+                      item.lastModifyTime ||
+                      item.updateTime ||
+                      item.modifiedTime ||
+                      item.updated_at ||
+                      '',
+                    data: item.data || item.detail || {},
+                    // 透传原始字段,避免信息丢失
+                    ...item,
+                  }
+                }
+              )
+              this.localTableData = mapped
+            } else {
+              this.localTableData = []
+            }
+          } catch (e) {
+            console.error('加载动态表数据失败:', e)
+            Message.error('加载动态表数据失败')
+            this.localTableData = []
+          } finally {
+            this.loading = false
+            this.pagination.total = this.localTableData.length
+            this.pagination.currentPage = 1
+          }
+          return
+        }
+
+        // 无查询条件时:回退到传入/本地数据或 mock
+        this.initTableData()
+      },
       // 初始化表格项配置
       initTableItems() {
-        // if (this.tableItems && this.tableItems.length > 0) {
-        //   this.localTableItems = [...this.tableItems]
-        // } else {
-        //   // 使用假数据
-        //   this.localTableItems = this.getMockTableItems()
-        // }
-        this.localTableItems = this.getMockTableItems()
+        if (this.tableItems && this.tableItems.length > 0) {
+          this.localTableItems = this.cloneDeep(this.tableItems)
+        } else if (!this.localTableItems || this.localTableItems.length === 0) {
+          this.localTableItems = this.getMockTableItems()
+        }
+      },
+      cloneDeep(obj) {
+        if (obj === null || obj === undefined) return obj
+        try {
+          return JSON.parse(JSON.stringify(obj))
+        } catch (err) {
+          console.warn('cloneDeep 失败,返回原对象', err)
+          return obj
+        }
       },
       // 获取假数据表格项配置(用于测试)
       getMockTableItems() {
-        return [
-          {
-            id: 'I',
-            itemName: '房屋建筑物',
-            isCategory: true,
-            categorySeq: 'I',
-            children: [
-              {
-                id: 'I-1',
-                itemName: '办公用房',
-                unit: '',
-                originalValue: '',
-                entryDate: '',
-                depreciationPeriod: '',
-                depreciationExpense: '',
-                fundSource: '',
-                remark: '',
-              },
-              {
-                id: 'I-2',
-                itemName: '教保用房',
-                unit: '',
-                originalValue: '',
-                entryDate: '',
-                depreciationPeriod: '',
-                depreciationExpense: '',
-                fundSource: '',
-                remark: '',
-              },
-              {
-                id: 'I-3',
-                itemName: '幼儿宿舍用房',
-                unit: '',
-                originalValue: '',
-                entryDate: '',
-                depreciationPeriod: '',
-                depreciationExpense: '',
-                fundSource: '',
-                remark: '',
-              },
-              {
-                id: 'I-4',
-                itemName: '其它',
-                unit: '',
-                originalValue: '',
-                entryDate: '',
-                depreciationPeriod: '',
-                depreciationExpense: '',
-                fundSource: '',
-                remark: '',
-              },
-            ],
-          },
-          {
-            id: 'II',
-            itemName: '交通运输工具',
-            isCategory: true,
-            categorySeq: 'II',
-            children: [
-              {
-                id: 'II-1',
-                itemName: '车辆',
-                unit: '',
-                originalValue: '',
-                entryDate: '',
-                depreciationPeriod: '',
-                depreciationExpense: '',
-                fundSource: '',
-                remark: '',
-              },
-            ],
-          },
-          {
-            id: 'III',
-            itemName: '教保专用设备',
-            isCategory: true,
-            categorySeq: 'III',
-            children: [
-              {
-                id: 'III-1',
-                itemName: '电教',
-                unit: '',
-                originalValue: '',
-                entryDate: '',
-                depreciationPeriod: '',
-                depreciationExpense: '',
-                fundSource: '',
-                remark: '',
-              },
-              {
-                id: 'III-2',
-                itemName: '文体',
-                unit: '',
-                originalValue: '',
-                entryDate: '',
-                depreciationPeriod: '',
-                depreciationExpense: '',
-                fundSource: '',
-                remark: '',
-              },
-            ],
-          },
-          {
-            id: 'IV',
-            itemName: '办公设备',
-            isCategory: true,
-            categorySeq: 'IV',
-            children: [
-              {
-                id: 'IV-1',
-                itemName: '电脑',
-                unit: '',
-                originalValue: '',
-                entryDate: '',
-                depreciationPeriod: '',
-                depreciationExpense: '',
-                fundSource: '',
-                remark: '',
-              },
-            ],
-          },
-          {
-            id: 'V',
-            itemName: '其它固定资产',
-            isCategory: true,
-            categorySeq: 'V',
-            children: [
-              {
-                id: 'V-1',
-                itemName: '空调',
-                unit: '',
-                originalValue: '',
-                entryDate: '',
-                depreciationPeriod: '',
-                depreciationExpense: '',
-                fundSource: '',
-                remark: '',
-              },
-              {
-                id: 'V-2',
-                itemName: '家电',
-                unit: '',
-                originalValue: '',
-                entryDate: '',
-                depreciationPeriod: '',
-                depreciationExpense: '',
-                fundSource: '',
-                remark: '',
-              },
-              {
-                id: 'V-3',
-                itemName: '供水系统',
-                unit: '',
-                originalValue: '',
-                entryDate: '',
-                depreciationPeriod: '',
-                depreciationExpense: '',
-                fundSource: '',
-                remark: '',
-              },
-              {
-                id: 'V-4',
-                itemName: '洗涤用具',
-                unit: '',
-                originalValue: '',
-                entryDate: '',
-                depreciationPeriod: '',
-                depreciationExpense: '',
-                fundSource: '',
-                remark: '',
-              },
-              {
-                id: 'V-5',
-                itemName: '家具',
-                unit: '',
-                originalValue: '',
-                entryDate: '',
-                depreciationPeriod: '',
-                depreciationExpense: '',
-                fundSource: '',
-                remark: '',
-              },
-              {
-                id: 'V-6',
-                itemName: '炊事用具',
-                unit: '',
-                originalValue: '',
-                entryDate: '',
-                depreciationPeriod: '',
-                depreciationExpense: '',
-                fundSource: '',
-                remark: '',
-              },
-              {
-                id: 'V-7',
-                itemName: '其它',
-                unit: '',
-                originalValue: '',
-                entryDate: '',
-                depreciationPeriod: '',
-                depreciationExpense: '',
-                fundSource: '',
-                remark: '',
-              },
-            ],
-          },
-        ]
+        // return [
+        //   {
+        //     id: 'I',
+        //     itemName: '房屋建筑物',
+        //     isCategory: true,
+        //     categorySeq: 'I',
+        //     children: [
+        //       {
+        //         id: 'I-1',
+        //         itemName: '办公用房',
+        //         unit: '',
+        //         originalValue: '',
+        //         entryDate: '',
+        //         depreciationPeriod: '',
+        //         depreciationExpense: '',
+        //         fundSource: '',
+        //         remark: '',
+        //       },
+        //       {
+        //         id: 'I-2',
+        //         itemName: '教保用房',
+        //         unit: '',
+        //         originalValue: '',
+        //         entryDate: '',
+        //         depreciationPeriod: '',
+        //         depreciationExpense: '',
+        //         fundSource: '',
+        //         remark: '',
+        //       },
+        //       {
+        //         id: 'I-3',
+        //         itemName: '幼儿宿舍用房',
+        //         unit: '',
+        //         originalValue: '',
+        //         entryDate: '',
+        //         depreciationPeriod: '',
+        //         depreciationExpense: '',
+        //         fundSource: '',
+        //         remark: '',
+        //       },
+        //       {
+        //         id: 'I-4',
+        //         itemName: '其它',
+        //         unit: '',
+        //         originalValue: '',
+        //         entryDate: '',
+        //         depreciationPeriod: '',
+        //         depreciationExpense: '',
+        //         fundSource: '',
+        //         remark: '',
+        //       },
+        //     ],
+        //   },
+        //   {
+        //     id: 'II',
+        //     itemName: '交通运输工具',
+        //     isCategory: true,
+        //     categorySeq: 'II',
+        //     children: [
+        //       {
+        //         id: 'II-1',
+        //         itemName: '车辆',
+        //         unit: '',
+        //         originalValue: '',
+        //         entryDate: '',
+        //         depreciationPeriod: '',
+        //         depreciationExpense: '',
+        //         fundSource: '',
+        //         remark: '',
+        //       },
+        //     ],
+        //   },
+        //   {
+        //     id: 'III',
+        //     itemName: '教保专用设备',
+        //     isCategory: true,
+        //     categorySeq: 'III',
+        //     children: [
+        //       {
+        //         id: 'III-1',
+        //         itemName: '电教',
+        //         unit: '',
+        //         originalValue: '',
+        //         entryDate: '',
+        //         depreciationPeriod: '',
+        //         depreciationExpense: '',
+        //         fundSource: '',
+        //         remark: '',
+        //       },
+        //       {
+        //         id: 'III-2',
+        //         itemName: '文体',
+        //         unit: '',
+        //         originalValue: '',
+        //         entryDate: '',
+        //         depreciationPeriod: '',
+        //         depreciationExpense: '',
+        //         fundSource: '',
+        //         remark: '',
+        //       },
+        //     ],
+        //   },
+        //   {
+        //     id: 'IV',
+        //     itemName: '办公设备',
+        //     isCategory: true,
+        //     categorySeq: 'IV',
+        //     children: [
+        //       {
+        //         id: 'IV-1',
+        //         itemName: '电脑',
+        //         unit: '',
+        //         originalValue: '',
+        //         entryDate: '',
+        //         depreciationPeriod: '',
+        //         depreciationExpense: '',
+        //         fundSource: '',
+        //         remark: '',
+        //       },
+        //     ],
+        //   },
+        //   {
+        //     id: 'V',
+        //     itemName: '其它固定资产',
+        //     isCategory: true,
+        //     categorySeq: 'V',
+        //     children: [
+        //       {
+        //         id: 'V-1',
+        //         itemName: '空调',
+        //         unit: '',
+        //         originalValue: '',
+        //         entryDate: '',
+        //         depreciationPeriod: '',
+        //         depreciationExpense: '',
+        //         fundSource: '',
+        //         remark: '',
+        //       },
+        //       {
+        //         id: 'V-2',
+        //         itemName: '家电',
+        //         unit: '',
+        //         originalValue: '',
+        //         entryDate: '',
+        //         depreciationPeriod: '',
+        //         depreciationExpense: '',
+        //         fundSource: '',
+        //         remark: '',
+        //       },
+        //       {
+        //         id: 'V-3',
+        //         itemName: '供水系统',
+        //         unit: '',
+        //         originalValue: '',
+        //         entryDate: '',
+        //         depreciationPeriod: '',
+        //         depreciationExpense: '',
+        //         fundSource: '',
+        //         remark: '',
+        //       },
+        //       {
+        //         id: 'V-4',
+        //         itemName: '洗涤用具',
+        //         unit: '',
+        //         originalValue: '',
+        //         entryDate: '',
+        //         depreciationPeriod: '',
+        //         depreciationExpense: '',
+        //         fundSource: '',
+        //         remark: '',
+        //       },
+        //       {
+        //         id: 'V-5',
+        //         itemName: '家具',
+        //         unit: '',
+        //         originalValue: '',
+        //         entryDate: '',
+        //         depreciationPeriod: '',
+        //         depreciationExpense: '',
+        //         fundSource: '',
+        //         remark: '',
+        //       },
+        //       {
+        //         id: 'V-6',
+        //         itemName: '炊事用具',
+        //         unit: '',
+        //         originalValue: '',
+        //         entryDate: '',
+        //         depreciationPeriod: '',
+        //         depreciationExpense: '',
+        //         fundSource: '',
+        //         remark: '',
+        //       },
+        //       {
+        //         id: 'V-7',
+        //         itemName: '其它',
+        //         unit: '',
+        //         originalValue: '',
+        //         entryDate: '',
+        //         depreciationPeriod: '',
+        //         depreciationExpense: '',
+        //         fundSource: '',
+        //         remark: '',
+        //       },
+        //     ],
+        //   },
+        // ]
       },
       // 初始化表格数据
       initTableData() {
         if (this.tableData && this.tableData.length > 0) {
           this.localTableData = [...this.tableData]
-        } else {
-          // 使用假数据
-          this.localTableData = this.getMockTableData()
         }
         this.pagination.total = this.localTableData.length
         this.pagination.currentPage = 1
       },
       // 获取假数据(用于测试)
-      getMockTableData() {
-        const currentDate = new Date()
-        const formatDateTime = (date) => {
-          const year = date.getFullYear()
-          const month = String(date.getMonth() + 1).padStart(2, '0')
-          const day = String(date.getDate()).padStart(2, '0')
-          const hours = String(date.getHours()).padStart(2, '0')
-          const minutes = String(date.getMinutes()).padStart(2, '0')
-          const seconds = String(date.getSeconds()).padStart(2, '0')
-          return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
-        }
+      // getMockTableData() {
+      //   const currentDate = new Date()
+      //   const formatDateTime = (date) => {
+      //     const year = date.getFullYear()
+      //     const month = String(date.getMonth() + 1).padStart(2, '0')
+      //     const day = String(date.getDate()).padStart(2, '0')
+      //     const hours = String(date.getHours()).padStart(2, '0')
+      //     const minutes = String(date.getMinutes()).padStart(2, '0')
+      //     const seconds = String(date.getSeconds()).padStart(2, '0')
+      //     return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
+      //   }
 
-        const data = []
-        const currentYear = currentDate.getFullYear()
-
-        // 生成25条假数据
-        for (let i = 0; i < 25; i++) {
-          const year = currentYear - i
-          const fillDate = new Date(currentDate)
-          fillDate.setDate(fillDate.getDate() - i)
-          const modifyDate = new Date(fillDate)
-          modifyDate.setHours(modifyDate.getHours() + 1)
-
-          data.push({
-            id: `row-${i + 1}`,
-            seq: i + 1,
-            auditPeriod: `${year}`,
-            fillTime: formatDateTime(fillDate),
-            lastModifyTime: formatDateTime(modifyDate),
-            data: {}, // 存储具体的填报数据
-          })
-        }
+      //   const data = []
+      //   const currentYear = currentDate.getFullYear()
 
-        return data
-      },
+      //   // 生成25条假数据
+      //   for (let i = 0; i < 25; i++) {
+      //     const year = currentYear - i
+      //     const fillDate = new Date(currentDate)
+      //     fillDate.setDate(fillDate.getDate() - i)
+      //     const modifyDate = new Date(fillDate)
+      //     modifyDate.setHours(modifyDate.getHours() + 1)
+
+      //     data.push({
+      //       id: `row-${i + 1}`,
+      //       seq: i + 1,
+      //       auditPeriod: `${year}`,
+      //       fillTime: formatDateTime(fillDate),
+      //       lastModifyTime: formatDateTime(modifyDate),
+      //       data: {}, // 存储具体的填报数据
+      //     })
+      //   }
+
+      //   return data
+      // },
       // 获取行索引(考虑分页)
       getRowIndex(index) {
         return (
@@ -535,38 +721,53 @@
       },
       // 新增
       handleAdd() {
-        const currentYear = new Date().getFullYear()
-        const currentDate = new Date()
-        const formatDateTime = (date) => {
-          const year = date.getFullYear()
-          const month = String(date.getMonth() + 1).padStart(2, '0')
-          const day = String(date.getDate()).padStart(2, '0')
-          const hours = String(date.getHours()).padStart(2, '0')
-          const minutes = String(date.getMinutes()).padStart(2, '0')
-          const seconds = String(date.getSeconds()).padStart(2, '0')
-          return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
-        }
-
-        const newRow = {
-          id: `row-${Date.now()}`,
-          seq: this.localTableData.length + 1,
-          auditPeriod: String(currentYear),
-          fillTime: formatDateTime(currentDate),
-          lastModifyTime: formatDateTime(currentDate),
-          data: {},
-        }
-
-        this.localTableData.unshift(newRow)
-        this.pagination.total = this.localTableData.length
-        this.pagination.currentPage = 1
-
-        // 打开编辑弹窗
-        this.currentRow = newRow
-        this.isEditMode = true
-        this.detailDialogTitle = '编辑'
-        this.detailDialogVisible = true
-
-        Message.success('新增成功,请填写数据')
+        // 打开新增弹窗,仅填写两个字段
+        this.addForm = { auditPeriod: '', reportingTime: '' }
+        this.addDialogVisible = true
+      },
+      // 新增保存
+      handleAddSave() {
+        this.$refs.addFormRef.validate(async (valid) => {
+          if (!valid) return
+          try {
+            this.adding = true
+            const sd = this.surveyData || {}
+            const uploadId = this.uploadId || sd.uploadId || sd.id || ''
+            const auditedUnitId = this.auditedUnitId || sd.auditedUnitId || ''
+            const catalogId = this.catalogId || sd.catalogId || ''
+            const surveyTemplateId =
+              this.surveyTemplateId || sd.surveyTemplateId || ''
+            // if (!uploadId || !auditedUnitId) {
+            //   Message.error('缺少必要参数:uploadId 或 auditedUnitId')
+            //   this.adding = false
+            //   return
+            // }
+            const now = this.formatDateTime(new Date())
+            const payload = {
+              uploadId,
+              auditedUnitId,
+              catalogId,
+              surveyTemplateId,
+              auditPeriod: this.addForm.auditPeriod,
+              reportingTime: this.addForm.reportingTime || now,
+            }
+            const res = await addDynamicTableData(payload)
+            if (res && res.code === 200) {
+              Message.success('新增成功')
+              this.addDialogVisible = false
+              await this.loadDynamicTableData()
+              // 触发刷新事件,通知父组件刷新列表
+              this.$emit('refresh')
+            } else {
+              Message.error(res?.message || '新增失败')
+            }
+          } catch (e) {
+            console.error('新增失败:', e)
+            Message.error('新增失败')
+          } finally {
+            this.adding = false
+          }
+        })
       },
       // 批量删除
       handleBatchDelete() {
@@ -585,22 +786,25 @@
           }
         )
           .then(() => {
-            const selectedIds = this.selectedRows.map((row) => row.id)
-            this.localTableData = this.localTableData.filter(
-              (row) => !selectedIds.includes(row.id)
-            )
-            this.pagination.total = this.localTableData.length
+            const selectedIds = this.selectedRows
+              .map((row) => row.id)
+              .filter(Boolean)
 
-            // 如果当前页没有数据了,跳转到上一页
-            if (
-              this.paginatedTableData.length === 0 &&
-              this.pagination.currentPage > 1
-            ) {
-              this.pagination.currentPage--
+            if (selectedIds.length === 0) {
+              Message.warning('所选记录缺少可删除的ID')
+              return
             }
 
-            this.selectedRows = []
-            Message.success('删除成功')
+            const tasks = selectedIds.map((id) =>
+              deleteDynamicTableData({ id }).catch((e) => e)
+            )
+
+            Promise.allSettled(tasks).then(() => {
+              Message.success('删除成功')
+              this.selectedRows = []
+              // 重新加载数据
+              this.loadDynamicTableData()
+            })
           })
           .catch(() => {})
       },
@@ -610,6 +814,9 @@
         this.isEditMode = false
         this.detailDialogTitle = '详情'
         this.detailDialogVisible = true
+        // 清空后由接口回显,否则使用行内 data 兜底
+        this.detailSavedData = null
+        this.loadSingleRecordSurveyList()
       },
       // 编辑
       handleEdit(row) {
@@ -617,84 +824,290 @@
         this.isEditMode = true
         this.detailDialogTitle = '编辑'
         this.detailDialogVisible = true
+        this.detailSavedData = null
+        this.loadSingleRecordSurveyList()
       },
-      // 保存详情
-      handleSaveDetail() {
-        // 验证表格数据
-        if (this.$refs.fixedAssetsTable) {
-          const isValid = this.$refs.fixedAssetsTable.validate()
-          if (!isValid) {
-            const errors = this.$refs.fixedAssetsTable.validationErrors
-            Message.error('数据验证失败:\n' + errors.join('\n'))
-            return
-          }
+      async loadSingleRecordSurveyList() {
+        if (!this.currentRow) return
+
+        const sd = this.surveyData || {}
+        const uploadId =
+          this.currentRow.uploadId ||
+          this.uploadId ||
+          sd.uploadId ||
+          sd.id ||
+          ''
+        const auditedUnitId =
+          this.auditedUnitId ||
+          this.currentRow.auditedUnitId ||
+          sd.auditedUnitId ||
+          ''
+        const catalogId =
+          this.catalogId || this.currentRow.catalogId || sd.catalogId || ''
+        const surveyTemplateId =
+          this.surveyTemplateId ||
+          this.currentRow.surveyTemplateId ||
+          sd.surveyTemplateId ||
+          ''
+        const periodRecordId =
+          this.currentRow.id || this.currentRow.periodRecordId || ''
+
+        const configParams = {
+          uploadId,
+          auditedUnitId,
+          catalogId,
+          surveyTemplateId,
+        }
+
+        const detailParams = {
+          uploadId,
+          auditedUnitId,
+          periodRecordId,
+        }
+
+        try {
+          this.singleRecordLoading = true
+
+          // 1. 获取表头配置
+          const configRes = await getSingleRecordSurveyList(configParams)
+          if (configRes && configRes.code === 200) {
+            const configPayload =
+              configRes.value || configRes.data || configRes.result || configRes
+
+            if (configPayload.fixedFields) {
+              this.fixedFields = configPayload.fixedFields
+            }
+            if (configPayload.fixedFieldids) {
+              this.fixedFieldids = configPayload.fixedFieldids
+            }
 
-          // 获取表格数据
-          const tableData = this.$refs.fixedAssetsTable.getTableData()
-          if (this.currentRow) {
-            // 更新当前行的数据
-            this.currentRow.data = tableData
-            this.currentRow.lastModifyTime = this.formatDateTime(new Date())
+            const { tableItems } =
+              this.normalizeSingleRecordResponse(configPayload)
 
-            // 更新本地表格数据
-            const index = this.localTableData.findIndex(
-              (item) => item.id === this.currentRow.id
+            if (tableItems && tableItems.length > 0) {
+              this.localTableItems = tableItems
+            }
+          } else {
+            Message.warning(
+              configRes?.message || '获取表头配置失败,将尝试加载详情数据'
             )
-            if (index > -1) {
-              this.$set(this.localTableData, index, { ...this.currentRow })
+          }
+
+          // 2. 获取填报数据
+          const detailRes =
+            periodRecordId || uploadId
+              ? await getSurveyDetail(detailParams)
+              : null
+
+          if (detailRes && detailRes.code === 200) {
+            const detailPayload =
+              detailRes.value || detailRes.data || detailRes.result || detailRes
+            const { tableItems, savedData } =
+              this.normalizeSingleRecordResponse(detailPayload)
+
+            if (detailPayload.fixedFields) {
+              this.fixedFields = detailPayload.fixedFields
+            }
+            if (detailPayload.fixedFieldids) {
+              this.fixedFieldids = detailPayload.fixedFieldids
+            }
+            if (tableItems && tableItems.length > 0) {
+              this.localTableItems = tableItems
+            }
+
+            if (savedData) {
+              this.detailSavedData = savedData
+            } else if (tableItems && tableItems.length > 0) {
+              this.detailSavedData = this.cloneDeep(tableItems)
+            } else {
+              this.detailSavedData =
+                (this.currentRow && this.currentRow.data) || null
+            }
+          } else {
+            if (detailRes) {
+              Message.warning(detailRes?.message || '获取单记录数据失败')
+            }
+            this.detailSavedData =
+              (this.currentRow && this.currentRow.data) || null
+          }
+        } catch (error) {
+          console.error('获取单记录数据失败:', error)
+          Message.error('获取单记录数据失败')
+          this.detailSavedData =
+            (this.currentRow && this.currentRow.data) || null
+        } finally {
+          this.singleRecordLoading = false
+        }
+      },
+      normalizeSingleRecordResponse(payload) {
+        if (!payload) {
+          return { tableItems: [], savedData: null }
+        }
+
+        const itemsFromPayload = this.extractArrayFromPayload(payload)
+        const uploadDataSource =
+          payload.uploadData ||
+          payload.uploaddata ||
+          payload.detail ||
+          payload.dataSource ||
+          payload.fillData ||
+          null
+        const itemsFromUpload = this.extractArrayFromPayload(uploadDataSource)
+
+        let tableItemsSource = []
+        if (itemsFromPayload.length > 0) {
+          tableItemsSource = itemsFromPayload
+        } else if (itemsFromUpload.length > 0) {
+          tableItemsSource = itemsFromUpload
+        }
+
+        const tableItems = this.buildHierarchicalItems(tableItemsSource)
+
+        let savedData = null
+        if (itemsFromUpload.length > 0) {
+          savedData = this.buildHierarchicalItems(itemsFromUpload)
+        } else if (
+          uploadDataSource &&
+          typeof uploadDataSource === 'object' &&
+          !Array.isArray(uploadDataSource)
+        ) {
+          savedData = uploadDataSource
+        } else if (tableItemsSource.length > 0) {
+          savedData = this.cloneDeep(tableItemsSource)
+        }
+
+        return {
+          tableItems,
+          savedData,
+        }
+      },
+      extractArrayFromPayload(source) {
+        if (!source) return []
+        if (Array.isArray(source)) {
+          return this.cloneDeep(source)
+        }
+        if (typeof source !== 'object') {
+          return []
+        }
+        const candidateKeys = [
+          'itemlist',
+          'items',
+          'data',
+          'value',
+          'records',
+          'rows',
+          'children',
+          'list',
+        ]
+        for (const key of candidateKeys) {
+          const current = source[key]
+          if (Array.isArray(current) && current.length >= 0) {
+            return this.cloneDeep(current)
+          }
+        }
+        return []
+      },
+      buildHierarchicalItems(items) {
+        if (!Array.isArray(items) || items.length === 0) return []
+
+        const cloned = this.cloneDeep(items)
+        const hasNestedChildren = cloned.some(
+          (item) =>
+            item && Array.isArray(item.children) && item.children.length > 0
+        )
+
+        if (hasNestedChildren) {
+          return cloned
+        }
+
+        const map = new Map()
+        cloned.forEach((item, index) => {
+          if (!item || typeof item !== 'object') return
+          const generatedId = `item-${index}-${Math.random()
+            .toString(16)
+            .slice(2, 10)}`
+          const id =
+            item.id ||
+            item.itemId ||
+            item.rowid ||
+            item.rowId ||
+            item.code ||
+            item.key ||
+            generatedId
+          item.id = id
+          if (!Array.isArray(item.children)) {
+            item.children = []
+          }
+          map.set(id, item)
+        })
+
+        const roots = []
+        cloned.forEach((item) => {
+          if (!item || typeof item !== 'object') return
+          const parentId =
+            item.parentId ??
+            item.parentid ??
+            item.parentID ??
+            item.parentCode ??
+            item.parent_code ??
+            item.parentRowId ??
+            item.parentrowid
+          if (parentId && map.has(parentId)) {
+            const parent = map.get(parentId)
+            if (!Array.isArray(parent.children)) {
+              parent.children = []
             }
+            parent.children.push(item)
+            parent.isCategory = true
+          } else {
+            roots.push(item)
+          }
+        })
 
-            Message.success('保存成功')
+        return roots.length > 0 ? roots : cloned
+      },
+      // 保存详情
+      async handleSaveDetail() {
+        if (this.$refs.fixedAssetsTable) {
+          // 调用 FixedAssetsTable 的 saveData 方法
+          const success = await this.$refs.fixedAssetsTable.saveData()
+          if (success) {
             this.detailDialogVisible = false
+            // 触发刷新事件,通知父组件刷新列表
+            this.$emit('refresh')
           }
         }
       },
       // 删除单条记录
       handleDelete(row) {
+        console.log('row', row)
         MessageBox.confirm('确定要删除这条记录吗?', '提示', {
           confirmButtonText: '确定',
           cancelButtonText: '取消',
           type: 'warning',
         })
           .then(() => {
-            const index = this.localTableData.findIndex(
-              (item) => item.id === row.id
-            )
-            if (index > -1) {
-              this.localTableData.splice(index, 1)
-              this.pagination.total = this.localTableData.length
-
-              // 如果当前页没有数据了,跳转到上一页
-              if (
-                this.paginatedTableData.length === 0 &&
-                this.pagination.currentPage > 1
-              ) {
-                this.pagination.currentPage--
-              }
-
-              Message.success('删除成功')
+            if (!row || !row.id) {
+              Message.warning('该记录缺少可删除的ID')
+              return
             }
+            deleteDynamicTableData({ id: row.id })
+              .then(() => {
+                Message.success('删除成功')
+                // 重新加载数据
+                this.loadDynamicTableData()
+              })
+              .catch((e) => {
+                console.error('删除失败:', e)
+                Message.error('删除失败')
+              })
           })
           .catch(() => {})
       },
       // 详情/编辑保存
-      handleDetailSave(saveData) {
-        if (this.currentRow) {
-          // 更新当前行的数据
-          this.currentRow.data = saveData
-          this.currentRow.lastModifyTime = this.formatDateTime(new Date())
-
-          // 更新本地表格数据
-          const index = this.localTableData.findIndex(
-            (item) => item.id === this.currentRow.id
-          )
-          if (index > -1) {
-            this.$set(this.localTableData, index, { ...this.currentRow })
-          }
-
-          Message.success('保存成功')
-          this.detailDialogVisible = false
-        }
+      handleDetailSave() {
+        // This method is no longer needed as handleSaveDetail handles the save logic
+        // Keeping it for now, but it will be removed if not used elsewhere.
       },
       // 格式化日期时间
       formatDateTime(date) {

文件差異過大導致無法顯示
+ 617 - 406
src/views/EntDeclaration/auditTaskManagement/components/FixedAssetsTable.vue


部分文件因文件數量過多而無法顯示