<template>
  <div class="app-container">
    <div class="audit-controls">
      <el-form
        ref="auditForm"
        :model="auditForm"
        :rules="rules"
        :disabled="hasTableData"
      >
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="" prop="templateType">
              <div
                style="display: flex; justify-self: start; align-items: center"
              >
                <el-radio
                  v-model="auditForm.templateType"
                  label="1"
                  @change="handleTemplateTypeChange"
                >
                  选择调查表修改核定表
                </el-radio>
                <el-select
                  v-model="auditForm.dataTable"
                  placeholder="请选择"
                  :disabled="auditForm.templateType !== '1'"
                  style="width: 100%"
                >
                  <el-option
                    v-for="item in surveyFormList"
                    :key="item.id"
                    :label="item.surveyTemplateName"
                    :value="item.surveyTemplateId"
                  ></el-option>
                </el-select>
              </div>
            </el-form-item>
          </el-col>
          <el-col :span="8">
            <el-form-item label="" prop="">
              <div
                style="display: flex; justify-self: start; align-items: center"
              >
                <el-radio
                  v-model="auditForm.templateType"
                  label="2"
                  @change="handleTemplateTypeChange"
                >
                  选择核定表历史版本
                </el-radio>
                <el-select
                  v-model="auditForm.historyTemplate"
                  placeholder="请选择"
                  :disabled="auditForm.templateType !== '2'"
                  style="width: 100%"
                >
                  <el-option
                    v-for="item in auditFormList"
                    :key="item.id"
                    :label="item.surveyTemplateName"
                    :value="item.surveyTemplateId"
                  ></el-option>
                </el-select>
              </div>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <el-button
        v-if="!hasTableData"
        type="primary"
        size="small"
        :loading="loading"
        @click="handleGenerateTemplate"
      >
        生成核定表
      </el-button>
      <el-button
        v-if="!hasUploadData"
        type="primary"
        size="small"
        @click="handleSaveTemplate"
      >
        保存核定模版
      </el-button>
      <el-button
        v-if="showButtons"
        type="primary"
        size="small"
        @click="handleExportTemplate"
      >
        导出模版
      </el-button>
      <el-button
        v-if="showButtons"
        type="primary"
        size="small"
        @click="handleImportData"
      >
        导入数据
      </el-button>
      <el-button
        v-if="showButtons"
        type="primary"
        size="small"
        @click="handleSaveData"
      >
        保存核定数据
      </el-button>
    </div>

    <el-table :data="costAuditData" style="width: 100%" border>
      <el-table-column
        v-for="item in visibleCostAuditColumns"
        :key="item.prop"
        :prop="item.prop"
        :label="item.label"
        :width="item.width"
        :min-width="item.minWidth"
        :align="item.align"
        :fixed="item.fixed"
        :show-overflow-tooltip="item.showOverflowTooltip"
      >
        <template slot-scope="scope">
          <span v-if="item.isDisplayOnly">{{ scope.row[item.prop] }}</span>
          <!-- 字符串类型输入框 -->
          <el-input
            v-else-if="item.fieldType === 'string' && !item.dictCode"
            v-model="scope.row[item.prop]"
            :placeholder="item.label"
            :disabled="item.disabled"
            :maxlength="item.fieldTypelen ? parseInt(item.fieldTypelen) : null"
            show-word-limit
            style="width: 100%"
            @input="handleCellInput(scope.row, item)"
            @change="handleCellInput(scope.row, item)"
          ></el-input>
          <!-- 整数类型输入框（校验：仅整数，长度限制） -->
          <el-input
            v-else-if="item.fieldType === 'integer'"
            v-model="scope.row[item.prop]"
            :placeholder="item.label"
            :disabled="item.disabled"
            :maxlength="
              computeNumberMaxlength({
                totalLength: item.fieldTypelen,
                decimalLength: 0,
              })
            "
            style="width: 100%"
            @input="
              sanitizeNumberInput(scope.row, {
                prop: item.prop,
                totalLength: item.fieldTypelen,
                decimalLength: 0,
              })
            "
            @keypress.native="
              onNumberKeypressNumeric($event, scope.row, {
                prop: item.prop,
                decimalLength: 0,
              })
            "
            @keydown.native="
              onNumberKeydownNumeric($event, scope.row, {
                prop: item.prop,
                decimalLength: 0,
              })
            "
            @paste.native.prevent="
              onNumberPasteNumeric($event, scope.row, {
                prop: item.prop,
                decimalLength: 0,
              })
            "
            @compositionend.native="
              onNumberCompositionEndNumeric(scope.row, {
                prop: item.prop,
                totalLength: item.fieldTypelen,
                decimalLength: 0,
              })
            "
            @change="handleCellInput(scope.row, item)"
          ></el-input>
          <!-- 小数类型输入框（校验：小数位长度和值长度） -->
          <el-input
            v-else-if="item.fieldType === 'double'"
            v-model="scope.row[item.prop]"
            :placeholder="item.label"
            :disabled="item.disabled"
            :maxlength="
              computeNumberMaxlength({
                totalLength: item.fieldTypelen,
                decimalLength: item.fieldTypenointlen,
              })
            "
            style="width: 100%"
            @input="
              sanitizeNumberInput(scope.row, {
                prop: item.prop,
                totalLength: item.fieldTypelen,
                decimalLength: item.fieldTypenointlen,
              })
            "
            @keypress.native="
              onNumberKeypressNumeric($event, scope.row, {
                prop: item.prop,
                decimalLength: item.fieldTypenointlen,
              })
            "
            @keydown.native="
              onNumberKeydownNumeric($event, scope.row, {
                prop: item.prop,
                decimalLength: item.fieldTypenointlen,
              })
            "
            @paste.native.prevent="
              onNumberPasteNumeric($event, scope.row, {
                prop: item.prop,
                decimalLength: item.fieldTypenointlen,
              })
            "
            @compositionend.native="
              onNumberCompositionEndNumeric(scope.row, {
                prop: item.prop,
                totalLength: item.fieldTypelen,
                decimalLength: item.fieldTypenointlen,
              })
            "
            @change="handleCellInput(scope.row, item)"
          ></el-input>
          <!-- 日期/日期时间（根据 format 自动选择） -->
          <el-date-picker
            v-else-if="item.fieldType === 'datetime'"
            v-model="scope.row[item.prop]"
            :placeholder="item.label"
            :disabled="item.disabled"
            style="width: 100%"
            :type="computeDateType(item)"
            :format="computeDateFormat(item)"
            :value-format="computeDateFormat(item)"
            @input="handleCellInput(scope.row, item)"
            @change="handleCellInput(scope.row, item)"
          ></el-date-picker>
          <!-- 字典类型下拉框 -->
          <el-select
            v-else-if="item.dictCode"
            v-model="scope.row[item.prop]"
            :placeholder="item.label"
            :disabled="item.disabled"
            style="width: 100%"
            @input="handleCellInput(scope.row, item)"
            @change="handleCellInput(scope.row, item)"
          >
            <el-option
              v-for="dict in getDictOptions(item.dictCode)"
              :key="dict.key || dict.value"
              :label="dict.name || dict.label"
              :value="dict.key || dict.value"
            ></el-option>
          </el-select>
          <!-- 默认输入框 -->
          <el-input
            v-else
            v-model="scope.row[item.prop]"
            :placeholder="item.label"
            :disabled="item.disabled"
            :maxlength="item.fieldTypelen ? parseInt(item.fieldTypelen) : null"
            show-word-limit
            style="width: 100%"
            @input="handleCellInput(scope.row, item)"
            @change="handleCellInput(scope.row, item)"
          ></el-input>
        </template>
      </el-table-column>
      <el-table-column
        v-if="!hasUploadData"
        prop="action"
        label="操作"
        width="100"
        align="center"
        fixed="right"
      >
        <template slot-scope="scope">
          <el-button
            v-if="scope.row.parentid == '-1'"
            type="text"
            title="添加行"
            @click="handleAddItem(scope.row)"
          >
            <i class="el-icon iconfont-5039297 icon-zengjia1"></i>
          </el-button>
          <el-button
            v-if="scope.row.parentid != '-1'"
            type="text"
            title="删除行"
            @click="handleDeleteItem(scope.row)"
          >
            <i class="el-icon el-icon-remove"></i>
          </el-button>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

<script>
  import {
    generateCostVerifyForm,
    generateCostVerifyFormData,
    getActiveCostVerifyFormList,
    getActiveCostVerifyFormListByType,
    getCostFormVersionsByTemplateId,
    getCostVerifyTemplateDetailByTaskId,
    batchSaveOrUpdate,
    getCostVerifyTemplate,
  } from '@/api/costFormManage'
  import {
    getlistBySurveyTemplateId,
    getVerifyTemplateDetail,
  } from '@/api/costVerifyManage'
  import { getDetail } from '@/api/auditInitiation'
  import { catalogMixin, dictMixin } from '@/mixins/useDict'
  import { getByTypeKey } from '@/api/dictionaryManage'
  import {
    saveSingleRecordSurvey,
    getSurveyDetail,
    downloadTemplate,
    importData,
  } from '@/api/audit/survey'
  export default {
    name: 'CostAudit',
    mixins: [catalogMixin, dictMixin],
    props: {
      id: {
        type: [String, Number],
        default: null,
      },
      selectedProject: {
        type: Object,
        default: () => {
          return {}
        },
      },
      catalogId: {
        type: [String, Number],
        default: '',
      },
      currentNode: {
        type: String,
        default: '',
      },
      currentStatus: {
        type: String,
        default: '',
      },
      auditedUnitId: { type: String, default: '' },
    },
    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: [],
        // 成本调查表模板列表
        surveyFormList: [],
        auditForm: {
          surveyTemplateName: '',
          surveyTemplateId: '',
          templateType: '',
          dataTable: '',
          historyTemplate: '',
          catalogId: '',
        },
        rules: {
          catalogId: [
            { required: true, message: '请输选择监审类别', trigger: 'change' },
          ],
        },
        tableHeadersRes: [],
        tableDataRes: [],
        // 成本审核表格列配置
        costAuditcolumn: [],
        // 成本审核数据
        costAuditData: [],
        project: {},
        // 是否已有上传数据（用于控制“生成核定表”按钮显示隐藏）
        hasUploadData: false,
        // 防重与去重：避免重复请求 getSurveyDetail
        echoInProgress: false,
        lastEchoSignature: '',
        // 年份到各列prop的映射
        yearPropMap: {},
        // 字典缓存（当未使用 dictMixin 批量加载时备用）
        dictCache: {},
        // 生成核定表时的加载状态
        loading: false,
        // 控制按钮显示的标志
        showButtons: false,
      }
    },
    computed: {
      visibleCostAuditColumns() {
        const cols = Array.isArray(this.costAuditcolumn)
          ? this.costAuditcolumn
          : []
        return cols.filter((c) => c && c.showVisible !== '0')
      },
      hasTableData() {
        return (
          Array.isArray(this.costAuditData) && this.costAuditData.length > 0
        )
      },
    },
    watch: {
      // 直接监听最终的模板ID：一旦有值（或变更），拉取最新版本数据回显
      'auditForm.surveyTemplateId'(val) {
        if (
          val &&
          !this._loadingTemplate &&
          val !== this._lastLoadedTemplateId
        ) {
          this.loadTemplateDataForEdit(val)
        }
      },
      // 选择“根据调查表生成”时，选择了 dataTable 就将其作为当前模板ID并回显
      'auditForm.dataTable'(val) {
        if (this.auditForm && this.auditForm.templateType === '1' && val) {
          this.auditForm.surveyTemplateId = val
        }
      },
      // 选择“根据历史核定模板”时，选择了 historyTemplate 就将其作为当前模板ID并回显
      'auditForm.historyTemplate'(val) {
        if (this.auditForm && this.auditForm.templateType === '2' && val) {
          this.auditForm.surveyTemplateId = val
        }
      },
    },
    mounted() {
      // 进入页签时，不论是否已有ID，都尝试解析并加载一次
      this.getDetail()
      // 检查按钮显示权限
      this.checkButtonVisibility()
    },
    activated() {
      // keep-alive 场景下，激活时同样尝试解析并加载
      this.getDetail()
      // 检查按钮显示权限
      this.checkButtonVisibility()
    },
    methods: {
      // 尝试从多来源解析模板ID
      _resolveTemplateId() {
        // 1) 优先：已确定的 surveyTemplateId
        if (this.auditForm && this.auditForm.surveyTemplateId)
          return this.auditForm.surveyTemplateId
        // 2) 根据当前来源选择项
        if (
          this.auditForm &&
          this.auditForm.templateType === '1' &&
          this.auditForm.dataTable
        )
          return this.auditForm.dataTable
        if (
          this.auditForm &&
          this.auditForm.templateType === '2' &&
          this.auditForm.historyTemplate
        )
          return this.auditForm.historyTemplate
        // 3) 从选中项目中兜底
        const sp = this.selectedProject || {}
        if (sp.surveyTemplateId || sp.surveytemplateid)
          return sp.surveyTemplateId || sp.surveytemplateid
        if (sp.templateId || sp.templateid)
          return sp.templateId || sp.templateid
        // 4) 其他可能传入的字段（尽量不报错）
        if (sp.costSurveyTemplateId) return sp.costSurveyTemplateId
        return ''
      },
      // 供父组件在切到“成本审核”标签时调用，按照当前模板ID拉取版本并回显
      async getDetail() {
        // 1) 优先通过 taskId 获取 createmode/createtemplateid，然后按模板ID加载，满足“先调 getDetailByTaskId 再调版本并回显”
        const loadedByTask = await this.loadFromTaskId()
        if (loadedByTask) return

        // 2) 按需：不带模板ID直接拉一次版本列表，满足“直接调”要求
        await this.loadVersionsWithoutId()

        // 然后再尝试解析模板ID以获取表头+更完整的数据（若可用）
        let id = this._resolveTemplateId()
        if (!id) {
          // 兜底：尝试取一个启用的核定模板作为展示
          try {
            const res = await getActiveCostVerifyFormList()
            const list = Array.isArray(res?.value) ? res.value : []
            const first = list && list[0]
            id =
              (first &&
                (first.surveyTemplateId || first.templateId || first.id)) ||
              ''
            if (id && this.auditForm) this.auditForm.surveyTemplateId = id
          } catch (e) {
            // ignore
          }
        }
        if (id) await this.loadTemplateDataForEdit(id)
      },
      // 先通过任务ID获取模板创建信息，再按模板ID加载版本与表头，实现“先调 getDetailByTaskId 再调 listByTemplateId 并回显”
      async loadFromTaskId() {
        try {
          const taskId =
            (this.selectedProject && this.selectedProject.taskId) ||
            this.id ||
            ''
          console.log('[CostAudit] loadFromTaskId called with taskId:', taskId)
          if (!taskId) return false
          const res = await getCostVerifyTemplateDetailByTaskId({ id: taskId })
          console.log('[CostAudit] getDetailByTaskId response:', res)
          if (!res || res.code !== 200) return false
          const v = res.value || {}
          // 若后端返回 code=200 但 value=null，允许用户自行选择来源与模板（不置灰）
          if (!res.value) {
            if (this.auditForm) {
              this.auditForm.surveyTemplateId = ''
              this.auditForm.dataTable = ''
              this.auditForm.historyTemplate = ''
              // 保持 templateType 由用户自行选择
            }
            this.hasUploadData = false
            return false
          }
          // 兼容不同字段命名：createTemplateId/createMode 或 createtemplateid/createmode
          const createMode = v.createMode != null ? v.createMode : v.createmode
          // 生成模板依赖模型id（用于UI来源选择的回显）
          const createTemplateId =
            v.createTemplateId ||
            v.createtemplateid ||
            v.templateId ||
            v.templateid ||
            ''
          // 用于版本/表头查询的 surveyTemplateId，优先取接口直接返回
          const surveyTplId = v.surveyTemplateId || v.surveytemplateid || ''
          // 若拿到模板ID，则记录并按模板ID完整加载（表头+数据+版本）
          if (createTemplateId || surveyTplId) {
            console.log('[CostAudit] resolved template from task:', {
              createTemplateId,
              surveyTplId,
              createMode,
            })
            if (this.auditForm) {
              // 后续版本/表头请求一律使用 surveyTemplateId（若缺失则回退到 createTemplateId）
              this.auditForm.surveyTemplateId = surveyTplId || createTemplateId
              if (createMode != null) {
                // 回显来源类型：1 固定表（成本调查表），2 历史成本审核表
                const modeStr = String(createMode)
                this.auditForm.templateType = modeStr
                // 先加载对应下拉选项，再设置选中值，保证界面能正确显示中文标签
                if (modeStr === '1') {
                  try {
                    await this.loadSurveyFormOptions()
                  } catch (e) {}
                  this.auditForm.dataTable = createTemplateId
                  this.auditForm.historyTemplate = ''
                } else if (modeStr === '2') {
                  try {
                    await this.loadHistoryTemplateOptions()
                  } catch (e) {}
                  this.auditForm.historyTemplate = createTemplateId
                  this.auditForm.dataTable = ''
                }
              }
            }
            // 使用 watcher 触发加载，避免与 watcher 重复调用
            return true
          }
          return false
        } catch (e) {
          console.error('[CostAudit] loadFromTaskId error:', e)
          return false
        }
      },
      // 不传模板ID直接拉取版本数据（只做数据回显，不加载表头）
      async loadVersionsWithoutId() {
        try {
          const taskId =
            (this.selectedProject && this.selectedProject.taskId) ||
            this.id ||
            ''
          const versionsRes = await getCostFormVersionsByTemplateId({ taskId })
          if (versionsRes && versionsRes.code === 200) {
            const list = Array.isArray(versionsRes.value)
              ? versionsRes.value
              : (versionsRes.value && versionsRes.value.itemlist) || []
            // 若能从版本数据中推断出模板ID，则走完整加载（表头+数据）确保表格正确回显
            const first = list && list[0]
            const inferredId =
              (first &&
                (first.templateId || first.surveyTemplateId || first.id)) ||
              ''
            if (inferredId) {
              // 记录并按模板ID完整加载
              if (this.auditForm) this.auditForm.surveyTemplateId = inferredId
              await this.loadTemplateDataForEdit(inferredId)
            } else {
              // 否则仅以返回的列表进行数据回显（前提：已有列配置）
              const parsedDataRes = { value: { itemlist: list } }
              this.parseAndDisplayTableData(parsedDataRes)
              this.computeApprovedForAllRows && this.computeApprovedForAllRows()
            }
          }
        } catch (e) {
          // ignore
        }
      },
      // 供父组件直接指定模板ID进行加载
      loadByTemplateId(id) {
        if (id) {
          this.auditForm.surveyTemplateId = id
          this.loadTemplateDataForEdit(id)
        }
      },
      handleTemplateTypeChange() {
        if (this.auditForm && this.auditForm.templateType === '1') {
          this.auditForm.historyTemplate = ''
          this.loadSurveyFormOptions()
        } else if (this.auditForm && this.auditForm.templateType === '2') {
          this.auditForm.dataTable = ''
          this.loadHistoryTemplateOptions()
        }
      },
      async loadSurveyFormOptions() {
        try {
          const res = await getActiveCostVerifyFormListByType({
            catalogId: this.catalogId,
          })
          const list = Array.isArray(res?.value) ? res.value : []
          // 规范为 surveyTemplateId / surveyTemplateName 结构供下拉使用
          this.surveyFormList = list.map((it) => ({
            surveyTemplateId:
              it.surveyTemplateId || it.templateId || it.id || '',
            surveyTemplateName:
              it.surveyTemplateName ||
              it.templatename ||
              it.name ||
              it.title ||
              '',
            ...it,
          }))
        } catch (e) {
          console.error('获取成本调查表模板(固定表启用)失败:', e)
          this.surveyFormList = []
        }
      },
      async loadHistoryTemplateOptions() {
        try {
          const res = await getActiveCostVerifyFormList()
          const list = Array.isArray(res?.value) ? res.value : []
          // 规范为 surveyTemplateId / surveyTemplateName 结构供下拉使用
          this.auditFormList = list.map((it) => ({
            surveyTemplateId:
              it.surveyTemplateId || it.templateId || it.id || '',
            surveyTemplateName:
              it.surveyTemplateName ||
              it.templatename ||
              it.name ||
              it.title ||
              '',
            ...it,
          }))
        } catch (e) {
          console.error('获取启用的成本核定表模板失败:', e)
          this.auditFormList = []
        }
      },
      handleGenerateTemplate() {
        this.$confirm(
          '生成后不能修改根据调查表生成还是根据历史核定模板生成，确定生成模板吗？',
          '提示',
          {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning',
          }
        ).then(() => {
          this.$refs['auditForm'].validate((valid) => {
            if (!valid) {
              this.$message.error('请填写表单数据')
              return
            }
            if (this.auditForm.templateType === '1') {
              if (!this.auditForm.dataTable) {
                this.$message.error('请选择成本调查表模板')
                return
              }
              this.generateFromSurveyTemplate()
            } else if (this.auditForm.templateType === '2') {
              if (!this.auditForm.historyTemplate) {
                this.$message.error('请选择历史核定模板')
                return
              }
              this.generateFromHistoryTemplate()
            } else {
              this.$message.error('请选择模板来源方式')
            }
          })
        })
      },
      async generateFromSurveyTemplate() {
        try {
          this.loading = true
          const resp = await generateCostVerifyForm({
            catalogId: this.catalogId,
            templatename: this.auditForm.surveyTemplateName,
            templateId: this.auditForm.dataTable,
            taskId: (this.selectedProject && this.selectedProject.taskId) || '',
          })
          this.auditForm.surveyTemplateId = resp?.value?.surveyTemplateId || ''
          if (typeof this.loadTemplateDataForEdit === 'function') {
            await this.loadTemplateDataForEdit(this.auditForm.surveyTemplateId)
          } else if (typeof this.loadTemplateData === 'function') {
            await this.loadTemplateData()
          }
        } catch (error) {
          console.error('生成模板失败：', error)
        } finally {
          this.loading = false
        }
      },
      async generateFromHistoryTemplate() {
        try {
          this.loading = true
          const resp = await generateCostVerifyFormData({
            catalogId: this.auditForm.catalogId,
            templatename: this.auditForm.surveyTemplateName,
            templateId: this.auditForm.historyTemplate,
            taskId: (this.selectedProject && this.selectedProject.taskId) || '',
          })
          this.auditForm.surveyTemplateId = resp?.value?.surveyTemplateId || ''
          if (typeof this.loadTemplateDataForEdit === 'function') {
            await this.loadTemplateDataForEdit(this.auditForm.surveyTemplateId)
          } else if (typeof this.loadTemplateData === 'function') {
            await this.loadTemplateData()
          }
        } catch (error) {
          console.error('生成模板失败：', error)
        } finally {
          this.loading = false
        }
      },
      // 生成后，按模板ID加载表头与详情，保持与 base 管理页一致
      async loadTemplateDataForEdit(surveyTemplateId) {
        try {
          const id = surveyTemplateId || this.auditForm?.surveyTemplateId || ''
          if (!id) return
          // 防重：避免同一ID并发重复加载
          this._loadingTemplate = true
          const taskId =
            (this.selectedProject && this.selectedProject.taskId) ||
            this.id ||
            ''
          // 并行获取：表头配置 + 版本数据(明细) + 模板详情（兜底）
          const [tableHeadersRes, versionsRes, detailRes] = await Promise.all([
            getlistBySurveyTemplateId({ surveyTemplateId: id }),
            // 兼容后端不同参数命名（有环境期望 surveyTemplateId，有环境期望 templateId）
            getCostFormVersionsByTemplateId({
              templateId: id,
              surveyTemplateId: id,
              taskId,
            }),
            getVerifyTemplateDetail({ id }),
          ])

          if (tableHeadersRes && tableHeadersRes.code === 200) {
            await this.parseAndDisplayTableHeaders(tableHeadersRes)
          } else {
            this.tableHeadersRes = []
            this.costAuditcolumn = []
          }

          // 优先使用版本接口返回的数据；若无则回退到模板详情
          let parsedDataRes = null
          if (versionsRes && versionsRes.code === 200) {
            const list = Array.isArray(versionsRes.value)
              ? versionsRes.value
              : (versionsRes.value && versionsRes.value.itemlist) || []
            parsedDataRes = { value: { itemlist: list } }
          } else if (detailRes && detailRes.code === 200) {
            parsedDataRes = detailRes
          }

          // 确保下拉列表包含当前模板，便于中文名称正确回显
          try {
            const tplName =
              (detailRes &&
                detailRes.value &&
                (detailRes.value.surveyTemplateName ||
                  detailRes.value.templatename ||
                  detailRes.value.name ||
                  detailRes.value.title)) ||
              ''
            const curType = this.auditForm && this.auditForm.templateType
            if (curType === '1') {
              const exists =
                Array.isArray(this.surveyFormList) &&
                this.surveyFormList.some(
                  (it) => (it.surveyTemplateId || it.templateId || it.id) === id
                )
              if (!exists) {
                this.surveyFormList = this.surveyFormList || []
                this.surveyFormList.push({
                  surveyTemplateId: id,
                  surveyTemplateName: tplName || '固定表模板',
                })
              }
            } else if (curType === '2') {
              const exists =
                Array.isArray(this.auditFormList) &&
                this.auditFormList.some(
                  (it) => (it.surveyTemplateId || it.templateId || it.id) === id
                )
              if (!exists) {
                this.auditFormList = this.auditFormList || []
                this.auditFormList.push({
                  surveyTemplateId: id,
                  surveyTemplateName: tplName || '历史核定模板',
                })
              }
            }
          } catch (e) {}

          if (parsedDataRes) {
            this.parseAndDisplayTableData(parsedDataRes)
          } else {
            this.costAuditData = []
          }

          // 追加：调用 getSurveyDetail 回显已上传的数据；若有数据则覆盖版本数据并隐藏“生成核定表”按钮
          await this.tryEchoUploadData({
            surveyTemplateId: id,
            taskId,
            type: 3,
          })

          // 依据当前数据触发一次联动计算
          this.computeApprovedForAllRows()
        } catch (e) {
          console.error('加载核定模板数据失败:', e)
        } finally {
          this._loadingTemplate = false
          const finalId =
            surveyTemplateId || this.auditForm?.surveyTemplateId || ''
          if (finalId) this._lastLoadedTemplateId = finalId
        }
      },
      // 调用上传数据查询接口进行数据回显，若存在数据则覆盖显示并隐藏生成按钮
      async tryEchoUploadData({ surveyTemplateId, taskId, type, force } = {}) {
        try {
          const stid =
            surveyTemplateId || this.auditForm?.surveyTemplateId || ''
          const tid =
            taskId ||
            (this.selectedProject && this.selectedProject.taskId) ||
            this.id ||
            ''
          const t = type || 3
          if (!stid || !tid) {
            this.hasUploadData = false
            return
          }
          const sig = `${stid}|${tid}|${t}`
          if (!force && this.echoInProgress && this.lastEchoSignature === sig) {
            return
          }
          if (!force && this.lastEchoSignature === sig && this.hasUploadData) {
            return
          }
          this.echoInProgress = true
          const res = await getSurveyDetail({
            surveyTemplateId: stid,
            taskId: tid,
            type: t,
          })
          // 兼容不同返回结构：value.itemlist 或 value.itemsList 或 直接 value 数组
          let list = []
          if (res && res.code === 200) {
            const v = res.value || res.data || res
            if (Array.isArray(v)) list = v
            else if (v && Array.isArray(v.itemlist)) list = v.itemlist
            else if (v && Array.isArray(v.itemsList)) list = v.itemsList
          }
          this.hasUploadData = Array.isArray(list) && list.length > 0
          if (this.hasUploadData) {
            // 将“单元格列表(list)”按 rowid 聚合为“行对象数组”
            const headers = Array.isArray(this.tableHeadersRes)
              ? this.tableHeadersRes
              : []
            const nameToHeader = new Map()
            headers.forEach((h) => {
              if (h && (h.fieldName || h.label)) {
                nameToHeader.set(String(h.fieldName || h.label), h)
              }
            })
            const rowsById = new Map()
            list.forEach((cell) => {
              const rowId =
                cell && (cell.rowid != null ? String(cell.rowid) : '')
              if (!rowId) return
              if (!rowsById.has(rowId)) {
                rowsById.set(rowId, {
                  rowid: rowId,
                  parentid:
                    cell.parentId != null ? String(cell.parentId) : '-1',
                  isChild:
                    cell.parentId != null &&
                    cell.parentId !== -1 &&
                    String(cell.parentId) !== '-1',
                })
              }
              const row = rowsById.get(rowId)
              const rkey = cell.rkey != null ? String(cell.rkey) : ''
              const rvalue = cell.rvalue != null ? String(cell.rvalue) : ''
              const header = nameToHeader.get(rkey)
              if (header && header.fieldEname) {
                row[header.fieldEname] = rvalue
                // 兼容 parseAndDisplayTableData 对中文列名读取
                row[header.fieldName] = rvalue
              }
              // 保留基础键值，便于后续保存
              row.rkey = rkey
              row.rvalue = rvalue
            })
            const transformed = Array.from(rowsById.values())
            const parsed = { value: { itemlist: transformed } }
            this.parseAndDisplayTableData(parsed)
            this.computeApprovedForAllRows && this.computeApprovedForAllRows()
            // 记录 uploadId（若返回里包含）
            if (
              res &&
              res.value &&
              (res.value.uploadId || res.value.uploadid)
            ) {
              this.auditForm.uploadId = res.value.uploadId || res.value.uploadid
            }
          }
          this.lastEchoSignature = sig
        } catch (e) {
          this.hasUploadData = false
        } finally {
          this.echoInProgress = false
        }
      },
      // 单元格输入联动：当账面值或审核调整值变化时，自动计算核定值
      handleCellInput(row, item) {
        if (!row) return
        // 若未传入列信息，则对该行全部年份重算
        if (!item || !item.prop) {
          this.computeApprovedForRow(row)
          return
        }
        const m = String(item.prop).match(
          /^year(\d{4})(BookValue|Audit|ApprovedValue)$/
        )
        if (!m) {
          this.computeApprovedForRow(row)
          return
        }
        const year = m[1]
        const bookProp = `year${year}BookValue`
        const auditProp = `year${year}Audit`
        const approvedProp = `year${year}ApprovedValue`
        const a = parseFloat(row[bookProp])
        const b = parseFloat(row[auditProp])
        const aNum = isNaN(a) ? 0 : a
        const bNum = isNaN(b) ? 0 : b
        // 若两者皆为空字符串则清空核定值；否则计算和
        if (
          (row[bookProp] === '' || row[bookProp] === undefined) &&
          (row[auditProp] === '' || row[auditProp] === undefined)
        ) {
          this.$set(row, approvedProp, '')
        } else {
          this.$set(row, approvedProp, String(aNum + bNum))
        }
      },
      // 针对单行，遍历存在的年份字段进行重新计算
      computeApprovedForRow(row) {
        if (!row) return
        const map = this.yearPropMap || {}
        Object.keys(map).forEach((year) => {
          const bookProp = map[year].book
          const auditProp = map[year].audit
          const approvedProp = map[year].approved
          if (!bookProp || !auditProp || !approvedProp) return
          const a = parseFloat(row[bookProp])
          const b = parseFloat(row[auditProp])
          const aNum = isNaN(a) ? 0 : a
          const bNum = isNaN(b) ? 0 : b
          if (
            (row[bookProp] === '' || row[bookProp] === undefined) &&
            (row[auditProp] === '' || row[auditProp] === undefined)
          ) {
            this.$set(row, approvedProp, '')
          } else {
            this.$set(row, approvedProp, String(aNum + bNum))
          }
        })
      },
      // 针对全表，批量重新计算核定值
      computeApprovedForAllRows() {
        if (!Array.isArray(this.costAuditData)) return
        this.costAuditData.forEach((row) => this.computeApprovedForRow(row))
      },
      async parseAndDisplayTableHeaders(res) {
        this.tableHeadersRes = Array.isArray(res.value) ? res.value : []
        if (this.tableHeadersRes.length > 0) {
          // 重置年份映射
          this.yearPropMap = {}
          this.auditForm.surveyTemplateId = res.value[0].surveyTemplateId
          // 表头按照orderNum重新排序
          this.tableHeadersRes.sort((a, b) => a.orderNum - b.orderNum)
          this.costAuditcolumn = [] // 清空现有列配置
          const dictCodes = new Set()
          this.tableHeadersRes.forEach((item) => {
            let column = {
              ...item,
              prop: item.fieldEname,
              label: item.fieldName,
              // 自动宽度：仅"序号"使用固定宽，其余使用最小宽度并开启溢出提示
              width: item.fieldName == '序号' ? '80px' : undefined,
              minWidth: item.fieldName == '序号' ? undefined : '150px',
              align: 'center',
              fieldType: item.fieldType,
              fieldTypelen: item.fieldTypelen,
              isDict: item.isDict,
              dictCode: item.dictCode,
              showOverflowTooltip: item.fieldName == '序号' ? false : true,
            }
            this.costAuditcolumn.push(column)

            // 收集字典编码，统一加载
            if (column && column.dictCode) {
              dictCodes.add(String(column.dictCode))
            }

            // 基于表头中文名构建年份映射
            const name = item.fieldName || item.label || ''
            const prop = item.fieldEname || item.prop || ''
            const m = String(name).match(
              /^(\d{4})年(账面值|审核调整值|核定值)$/
            )
            if (m && prop) {
              const year = m[1]
              const kind = m[2]
              if (!this.yearPropMap[year]) this.yearPropMap[year] = {}
              if (kind === '账面值') this.yearPropMap[year].book = prop
              else if (kind === '审核调整值')
                this.yearPropMap[year].audit = prop
              else if (kind === '核定值') this.yearPropMap[year].approved = prop
            }
          })
          // 统一初始化并加载字典（等待加载完成，避免首次渲染下拉为空）
          if (dictCodes.size > 0) {
            if (!this.dictData) this.dictData = {}
            dictCodes.forEach((code) => {
              if (!this.dictData[code]) this.$set(this.dictData, code, [])
            })
            if (typeof this.getDictType === 'function') {
              await this.getDictType()
            }
          }

          // 若表头未包含“单位”列，则追加；已包含则不重复添加
          // const hasUnitCol = this.costAuditcolumn.some(
          //   (c) => c && (c.label === '单位' || c.fieldName === '单位')
          // )
          // if (!hasUnitCol) {
          //   this.costAuditcolumn.push({
          //     prop: 'unit',
          //     label: '单位',
          //     width: '80px',
          //     align: 'center',
          //   })
          // }
          // 检查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) => {
              // 账面价值字段
              let bookValueColumn = {
                fieldEname: 'year' + item + 'BookValue',
                prop: 'year' + item + 'BookValue',
                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)
              // 映射
              if (!this.yearPropMap[item]) this.yearPropMap[item] = {}
              this.yearPropMap[item].book = bookValueColumn.prop
              // 审核字段
              let auditColumn = {
                fieldEname: 'year' + item + 'Audit',
                prop: 'year' + item + 'Audit',
                label: item + '年审核调整值',
                width: '150px',
                align: 'center',
                fieldName: item + '年审核调整值',
                fieldType: 'integer',
                format: '',
                fieldTypelen: '9',
                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)
              this.yearPropMap[item].audit = auditColumn.prop
              // 核定值字段
              let approvedValueColumn = {
                fieldEname: 'year' + item + 'ApprovedValue',
                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(approvedValueColumn)
              this.tableHeadersRes.push(approvedValueColumn)
              this.yearPropMap[item].approved = approvedValueColumn.prop
            })
          }
        }
      },
      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 = []

        if (
          res &&
          res.value &&
          res.value.itemlist &&
          res.value.itemlist.length > 0
        ) {
          let headers = this.tableHeadersRes
          let itemlist = res.value.itemlist

          // 遍历每个数据项
          itemlist.forEach((item, index) => {
            // 为每个数据项创建一个完整的对象
            // 判断是否为子项（parentid不为-1且不为"-1"）
            const isSubItem =
              item.parentid && item.parentid !== -1 && item.parentid !== '-1'
            let rowData = {
              ...item,
              isChild: isSubItem,
              isSubItem: isSubItem,
            }

            // 遍历表头，将字段值映射到对应的列
            headers.forEach((header) => {
              if (header && header.fieldEname && header.fieldName) {
                let fieldEname = header.fieldEname
                let fieldName = header.fieldName
                // 优先用中文列名取值，不存在则用英文prop取值
                let fieldValue =
                  (item &&
                    (item[fieldName] != null ? item[fieldName] : undefined)) !==
                  undefined
                    ? item[fieldName]
                    : item[fieldEname] || ''

                // 将字段值添加到行数据中
                rowData[fieldEname] = fieldValue
                rowData.rkey = fieldName
                rowData.rvalue = fieldValue
              }
            })

            // 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)
          })

          // 平铺顺序：父项在前、子项紧随其后
          const sortFn = (a, b) =>
            Number(a.orderNum || 0) - Number(b.orderNum || 0)
          const byRowId = new Map()
          const parents = []
          const childGroups = new Map()
          this.costAuditData.forEach((row) => {
            if (row && row.children) delete row.children
            const key = row.rowid != null ? String(row.rowid) : ''
            if (key) byRowId.set(key, row)
            const pid = row.parentid
            const isParent =
              pid === -1 || pid === '-1' || pid === null || pid === undefined
            if (isParent) {
              parents.push(row)
            } else {
              const pKey = pid != null ? String(pid) : ''
              if (!childGroups.has(pKey)) childGroups.set(pKey, [])
              childGroups.get(pKey).push(row)
            }
          })
          parents.sort(sortFn)
          const flat = []
          const seen = new Set()
          parents.forEach((p) => {
            flat.push(p)
            seen.add(p)
            const group = childGroups.get(String(p.rowid)) || []
            group.sort(sortFn).forEach((c) => {
              flat.push(c)
              seen.add(c)
            })
          })
          // 处理找不到父项的子项：放在末尾
          this.costAuditData.forEach((row) => {
            if (!seen.has(row)) flat.push(row)
          })
          this.costAuditData = flat
          // 平铺完成后统一计算核定值
          this.computeApprovedForAllRows()
        }
      },
      handleSaveTemplate(type) {
        // 显示加载状态
        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 = {
          costVerifyTemplateId: this.auditForm.surveyTemplateId,
          headersList: headersList,
          itemsList: splitData,
        }
        batchSaveOrUpdate(data)
          .then(async (data) => {
            // 关闭加载状态
            this.$loading().close()
            if (type != 'delete') {
              this.$message.success('保存成功')
              await this.checkButtonVisibility()
              this.loadTemplateData()
              // 保存成功后重新检查按钮显示权限
            }
          })
          .catch((err) => {
            // 关闭加载状态
            this.$loading().close()
            console.log(err)
          })
      },
      async handleSaveData() {
        const loading = this.$loading({
          lock: true,
          text: '保存数据中...',
          spinner: 'el-icon-loading',
          background: 'rgba(0, 0, 0, 0.7)',
        })
        try {
          // 1) 基于当前表格数据生成保存明细
          const rawItems =
            this.splitFixedTableDataForSave(this.costAuditData) || []
          const auditedUnitId =
            this.auditedUnitId || this.auditForm.auditedUnitId || ''
          const surveyTemplateId =
            this.auditForm.surveyTemplateId || this.auditForm.dataTable || ''
          const catalogId = this.auditForm.catalogId || ''
          const hasData = !!(this.auditForm && this.auditForm.uploadId)
          const taskId =
            (this.selectedProject && this.selectedProject.taskId) || ''
          console.log('rawItems', rawItems)
          const finalSaveData = rawItems.map((it) => {
            const base = {
              rowid: it.rowid,
              rkey: it.rkey,
              rvalue: it.rvalue != null ? String(it.rvalue) : '',
              auditedUnitId,
              surveyTemplateId,
              catalogId,
              taskId,
              // id: it.id,
              parentId: it.parentid || '-1',
              // refId: taskId,
              type: '3',
              // uploadId: '',
            }
            if (hasData) base.uploadId = this.auditForm.uploadId
            return base
          })

          // 2) 调用保存接口
          const res = await saveSingleRecordSurvey(finalSaveData)
          if (res && res.code === 200) {
            this.$message.success('保存成功')
            this.loadTemplateData && this.loadTemplateData()
          } else {
            this.$message.error((res && res.message) || '保存失败')
          }
        } catch (err) {
          console.error(err)
          // this.$message.error('保存失败')
        } finally {
          loading.close()
        }
      },
      //分割字符串
      stringToObjects(str) {
        const items = str.split(',')
        return items.map((item) => ({
          rkey: item,
          rvalue: '',
        }))
      },
      splitFixedTableDataForSave(
        tables = this.costAuditData,
        headers = this.tableHeadersRes
      ) {
        let fixedHeaders = headers
        let fixedTables = tables
        let fixedFields = fixedHeaders
          .map((header) => header.fieldName)
          .join(',')
        let fixedTitles = this.stringToObjects(fixedFields || '')
        // 结果数组
        const result = []
        const processNode = (node, parentRowIndex = 0) => {
          // 确保node和fixedValues存在
          if (!node) {
            console.warn('遇到空节点，跳过处理')
            return
          }

          // 确保fixedValues属性存在，如果不存在则初始化为空对象
          if (!node.fixedValues) {
            node.fixedValues = {}
          }

          // 为每个固定列创建一条记录
          fixedTitles.forEach((title) => {
            // 找到对应的表头信息
            const correspondingHeader = fixedHeaders.find(
              (header) => header.fieldName === title.rkey
            )
            if (!correspondingHeader) {
              return
            }
            const newItem = {
              rkey: title.rkey,
              rvalue:
                node[correspondingHeader.prop] !== undefined &&
                node[correspondingHeader.prop] !== null
                  ? node[correspondingHeader.prop]
                  : node[correspondingHeader.fieldEname] !== undefined &&
                    node[correspondingHeader.fieldEname] !== null
                  ? node[correspondingHeader.fieldEname]
                  : '',
              [correspondingHeader.fieldName]:
                node[correspondingHeader.fieldEname] !== undefined &&
                node[correspondingHeader.fieldEname] !== null
                  ? node[correspondingHeader.fieldEname]
                  : '',
              surveyTemplateId:
                node.surveyTemplateId || correspondingHeader.surveyTemplateId,
              versionId: node.versionId || correspondingHeader.versionId,
              tabtype: correspondingHeader.tabtype || node.tabtype,
              // 添加 headersId 字段（表头的id）
              headersId: correspondingHeader ? correspondingHeader.id : null,
              // 添加记录的id（itemlist中每条记录的id）
              id: node.id || null,
              // 添加父子关系字段
              parentid: node.parentid || -1, // 父项ID，默认为-1表示无父项
              isChild: node.isChild || false, // 是否为子项
              // 添加 rowid 字段
              rowid: node.rowid || null,
              // 添加计算公式相关字段
              calculationFormula: node.calculationFormula || null,
              jsonstr: node.jsonstr || null,
              orderNum:
                typeof node.orderNum === 'number'
                  ? node.orderNum
                  : parseInt(node.orderNum, 10) || 0,
              // 添加用户需要的其他字段
              orderText: node.orderText || '',
              percentage: node.percentage || '',
              unit: node.unit || '',
            }
            // 添加其他固定表特有的字段
            if (!node.isSubItem) {
              newItem.cellCode = node.cellCode || ''
              newItem.unit = node.unit || ''
            }

            // 添加其他可能需要的字段，但排除特定字段
            Object.keys(node).forEach((key) => {
              if (
                !(key in newItem) &&
                key !== 'fixedValues' &&
                key !== 'itemId' &&
                key !== 'id' &&
                key !== 'parentid' &&
                key !== 'isChild' &&
                key !== 'isSubItem' &&
                key !== 'rowid' &&
                key !== 'jsonstr' &&
                key !== 'calculationFormula' &&
                key !== 'children' // 排除children字段
              ) {
                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，作为新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 = item.orderNum
            usedOrderNums.add(nextAvailableOrderNum)
            nextAvailableOrderNum++
          }
        })

        return result
      },

      //
      handleImportData() {
        let loading = null
        // 第一步：创建文件选择器
        const input = document.createElement('input')
        input.type = 'file'
        input.accept = '.xls,.xlsx,.csv' // 允许的文件类型

        input.onchange = async (event) => {
          const file = event.target.files[0]
          if (!file) return

          try {
            // 校验文件大小（50MB）
            const maxSize = 50 * 1024 * 1024 // 50MB
            if (file.size > maxSize) {
              this.$message.error('文件大小不能超过50MB！')
              return
            }

            // 校验文件格式
            const allowedFormats = ['.xls', '.xlsx', 'csv']
            const fileName = file.name.toLowerCase()
            const isValidFormat = allowedFormats.some((format) =>
              fileName.endsWith(format)
            )

            if (!isValidFormat) {
              this.$message.error('只允许上传.xls,.xlsx,.csv格式的文件！')
              return
            }

            // 显示遮罩层
            loading = this.$baseLoading(1, '文件上传中...')

            // 第三步：创建FormData并上传文件
            const formData = new FormData()
            formData.append('file', file)

            // 其他参数作为表单字段传递
            formData.append('surveyTemplateId', this.auditForm.surveyTemplateId)
            formData.append('taskId', this.selectedProject.taskId)
            formData.append('materialId', '')
            formData.append('periodRecordId', '')
            formData.append('type', 3)

            // 调用新的导入接口
            const uploadRes = await importData(formData)

            // 第四步：检查上传结果
            if (!uploadRes.state) {
              this.$message.error('导入失败！')
              return
            }
            this.$message.success('导入成功')
            await this.tryEchoUploadData({
              surveyTemplateId: this.auditForm.surveyTemplateId,
              taskId:
                (this.selectedProject &&
                  (this.selectedProject.taskId ||
                    this.selectedProject.taskID)) ||
                this.id,
              type: 3,
              force: true,
            })
            this.computeApprovedForAllRows && this.computeApprovedForAllRows()
            // this.$emit('refresh', this.project.projectId) // 通知父组件刷新
          } catch (error) {
            // 错误处理
            // this.$message.error('操作失败：' + (error.message || '未知错误'))
          } finally {
            // 关闭遮罩层
            loading.close()
          }
        }
        // 触发文件选择
        input.click()
      },
      handleExportTemplate() {
        if (this.costAuditData.length === 0) {
          return
        }
        // 显示加载状态
        const loading = this.$loading({
          lock: true,
          text: '文件下载中...',
          spinner: 'el-icon-loading',
          background: 'rgba(0, 0, 0, 0.7)',
        })

        // 参数与 CostSurveyTab.vue 对齐：带上 surveyTemplateId、versionId、type，并追加 taskId（如有）
        const surveyTemplateId =
          (this.auditForm && this.auditForm.surveyTemplateId) || ''
        const versionId =
          (Array.isArray(this.tableHeadersRes) &&
            this.tableHeadersRes[0] &&
            (this.tableHeadersRes[0].versionId ||
              this.tableHeadersRes[0].templateVersionId ||
              this.tableHeadersRes[0].version)) ||
          ''
        const params = { surveyTemplateId, versionId, type: 3 }
        const taskId =
          (this.selectedProject &&
            (this.selectedProject.taskId || this.selectedProject.taskID)) ||
          this.id
        if (taskId) params.taskId = taskId

        downloadTemplate(params)
          .then((res) => {
            console.log('downloadTemplate res:', res)
            const headers = (res && res.headers) || {}
            const contentDisposition =
              headers['content-disposition'] || headers['Content-Disposition']
            let fileName = `成本审核模板_${new Date()
              .toLocaleString()
              .replace(/[:\s]/g, '_')}.xlsx`
            if (contentDisposition) {
              const match = contentDisposition.match(
                /filename\*=UTF-8''([^;]+)|filename=([^;]+)/i
              )
              const raw = (match && (match[1] || match[2])) || ''
              if (raw) fileName = decodeURIComponent(raw.replace(/['"]/g, ''))
            }
            if (!/\.[a-zA-Z0-9]+$/.test(fileName)) fileName += '.xlsx'

            const blobData = (res && res.data) || res
            const blob =
              blobData instanceof Blob ? blobData : new Blob([blobData])
            const url = window.URL.createObjectURL(blob)
            const a = document.createElement('a')
            a.style.display = 'none'
            a.href = url
            a.download = fileName
            document.body.appendChild(a)
            a.click()
            loading.close()
            setTimeout(() => {
              document.body.removeChild(a)
              window.URL.revokeObjectURL(url)
            }, 100)
          })
          .catch((error) => {
            loading.close()
            console.error('文件下载失败:', error)
          })
      },

      handleExportData() {
        this.$message({ type: 'info', message: '导出数据' })
      },

      // handleSaveData() {
      //   this.$message({ type: 'success', message: '成本审核数据已保存' })
      // },

      handleRemark(row, field) {
        this.$prompt('请输入说明', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          inputValue: row[field],
        })
          .then(({ value }) => {
            row[field] = value
            this.$message({ type: 'success', message: '说明已保存' })
          })
          .catch(() => {
            this.$message({ type: 'info', message: '已取消' })
          })
      },
      // 按层级关系排序表格数据，子项排在父项后面
      sortItemsByHierarchy() {
        if (!this.costAuditData || this.costAuditData.length === 0) {
          return
        }

        // 构建父子关系映射
        const itemMap = new Map()
        const rootItems = []
        const childrenMap = new Map()
        const processedItems = new Set() // 用于避免循环引用

        // 初始化映射和找出根节点
        this.costAuditData.forEach((item) => {
          const currentId = item.id || item.itemId
          if (currentId !== undefined) {
            itemMap.set(currentId, item)
          }

          // 检查是否有有效父ID
          const parentId = item.parentId || item.parentItemId
          const hasValidParent =
            parentId !== undefined &&
            parentId !== null &&
            parentId !== '' &&
            parentId !== -1

          if (!hasValidParent) {
            // 没有有效父ID的是根节点
            rootItems.push(item)
          } else {
            // 有父ID的添加到子节点映射中
            if (!childrenMap.has(parentId)) {
              childrenMap.set(parentId, [])
            }
            childrenMap.get(parentId).push(item)
          }
        })

        // 深度优先遍历生成排序后的数据
        const sortedData = []

        function traverse(item) {
          const currentId = item.id || item.itemId

          // 避免循环引用
          if (processedItems.has(currentId)) {
            return
          }

          // 标记为已处理
          processedItems.add(currentId)

          // 添加当前项
          sortedData.push(item)

          // 获取当前项的子项并递归遍历
          const children = childrenMap.get(currentId) || []

          // 对子项按照orderNum或id进行排序
          children.sort((a, b) => {
            if (a.orderNum !== undefined && b.orderNum !== undefined) {
              return a.orderNum - b.orderNum
            }
            const aId = a.id || a.itemId || 0
            const bId = b.id || b.itemId || 0
            return aId - bId
          })

          // 递归处理每个子项
          children.forEach((child) => {
            traverse(child)
          })
        }

        // 对根节点按照orderNum或id进行排序
        rootItems.sort((a, b) => {
          if (a.orderNum !== undefined && b.orderNum !== undefined) {
            return a.orderNum - b.orderNum
          }
          const aId = a.id || a.itemId || 0
          const bId = b.id || b.itemId || 0
          return aId - bId
        })

        // 从根节点开始遍历
        rootItems.forEach((root) => {
          traverse(root)
        })

        // 如果有未被包含的项目（可能没有正确的父子关系），直接添加到末尾
        if (sortedData.length < this.costAuditData.length) {
          this.costAuditData.forEach((item) => {
            const currentId = item.id || item.itemId
            if (currentId !== undefined && !processedItems.has(currentId)) {
              sortedData.push(item)
              processedItems.add(currentId)
            }
          })
        }

        // 更新表格数据为排序后的数据
        this.costAuditData = sortedData

        // 更新序号字段而非覆盖原始ID
        // this.costAuditData.forEach((item, index) => {
        //   // 创建或更新序号字段，保留原始ID不变
        //   item.index = index + 1
        // })
      },
      handleAddItem(row) {
        // 判断是否为父项（可添加子项）
        if (row.parentid !== '-1') {
          this.$message.error('只能在父项上添加子项')
          return
        }
        // 获取当前父项的所有子项
        const parentRowId = row.rowid // 使用当前行的rowid作为父ID
        const children = this.costAuditData.filter(
          (item) => item.parentid === parentRowId
        )

        // 找到当前父项的最后一个子项的 orderNum
        let maxOrderNum = 0
        children.forEach((child) => {
          if (child.orderNum > maxOrderNum) {
            maxOrderNum = child.orderNum
          }
        })

        // 新行的 orderNum 为最大子项 orderNum + 1
        const newOrderNum = maxOrderNum + 1

        // 创建新行：作为当前父项的子项
        const newItem = {
          ...row,
          parentId: parentRowId,
          parentid: parentRowId,
          orderNum: newOrderNum,
          rowid: this.generateUUID(),
          id: null,
          rvalue: '',
        }
        console.log('children.length', children.length)

        // 清空字段值
        this.costAuditcolumn.forEach((col) => {
          if (col.label === '序号') {
            newItem[col.prop] = children.length + 1
          } else {
            newItem[col.label] = ''
            newItem[col.prop] = ''
          }
        })

        // 找到父项的最后一个子项在数组中的位置
        let insertIndex = this.costAuditData.length // 默认插入到末尾

        // 遍历数组，找到父项的最后一个子项的位置
        for (let i = 0; i < this.costAuditData.length; i++) {
          // 如果是当前父项的子项，更新插入位置为该子项后一位
          if (this.costAuditData[i].parentid === row.rowid) {
            insertIndex = i + 1
          }
        }

        // 在最后一个子项后面插入新数据
        this.costAuditData.splice(insertIndex, 0, newItem)
        this.$message.success('子项添加成功')
      },
      handleDeleteItem(row) {
        // 显示确认对话框
        this.$confirm('确定要删除此行数据吗？', '确认删除', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning',
        })
          .then(() => {
            // 仅删除当前这一行
            const targetId =
              (row && (row.rowid || row.rowId || row.id || row.itemId)) || null
            const index = this.costAuditData.findIndex((it) => {
              if (it === row) return true
              const itId = it && (it.rowid || it.rowId || it.id || it.itemId)
              return targetId != null && itId === targetId
            })
            if (index !== -1) {
              this.costAuditData.splice(index, 1)
            }

            // 更新剩余行的orderNum
            this.updateOrderNumbersAfterDelete(row)

            // 删除行后调用保存模板方法
            // this.handleSaveTemplate('delete')

            this.$message.success('行删除成功')
          })
          .catch(() => {
            // 用户取消删除
            this.$message.info('已取消删除操作')
          })
      },
      // 删除行后更新orderNum的方法
      updateOrderNumbersAfterDelete(deletedRow) {
        const deletedOrderNum = deletedRow && deletedRow.orderNum
        const deletedParentId =
          (deletedRow && (deletedRow.parentId || deletedRow.parentid)) || '-1'

        // 遍历所有行，更新orderNum（同父级范围内顺延）
        this.costAuditData.forEach((item) => {
          const parentId = item.parentId || item.parentid || '-1'
          if (
            parentId === deletedParentId &&
            typeof item.orderNum !== 'undefined' &&
            typeof deletedOrderNum !== 'undefined' &&
            item.orderNum > deletedOrderNum
          ) {
            item.orderNum -= 1
          }
        })
      },
      // 生成唯一ID
      generateUUID() {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
          /[xy]/g,
          function (c) {
            const r = (Math.random() * 16) | 0,
              v = c === 'x' ? r : (r & 0x3) | 0x8
            return v.toString(16)
          }
        )
      },
      // 获取字典选项（由 dictMixin.getDictType 维护 dictData）
      getDictOptions(dictCode) {
        if (!dictCode || !this.dictData) return []
        const arr = this.dictData[String(dictCode)]
        return Array.isArray(arr) ? arr : []
      },
      // -------------- 数字/日期输入校验（对齐 FixedTableDialog 思路） --------------
      computeNumberMaxlength(cfg) {
        const intLimit = Number(cfg && cfg.totalLength)
        const decLimit = Number(cfg && cfg.decimalLength)
        if (!isNaN(intLimit) && intLimit > 0) {
          const extra = !isNaN(decLimit) && decLimit > 0 ? 1 + decLimit : 0
          // 预留一个符号位
          return intLimit + extra + 1
        }
        return undefined
      },
      sanitizeNumberInput(row, cfg) {
        const prop = cfg && cfg.prop
        const totalLen = Number(cfg && cfg.totalLength)
        const decLen = Number(cfg && cfg.decimalLength)
        if (!row || !prop) return
        let v = row[prop]
        if (v === null || v === undefined) {
          row[prop] = ''
          return
        }
        v = String(v)
        // 仅保留数字、+、-、.
        v = v.replace(/[^0-9+\-.]/g, '')
        // 只允许一个正负号且在最前
        v = v.replace(/(?!^)[+\-]/g, '')
        // 小数位限制
        const sign = v.startsWith('-') || v.startsWith('+') ? v[0] : ''
        let unsigned = sign ? v.slice(1) : v
        // 处理多个小数点
        const parts = unsigned.split('.')
        if (parts.length > 2)
          unsigned = parts[0] + '.' + parts.slice(1).join('')
        let iRaw, dRaw
        if (unsigned.includes('.')) {
          ;[iRaw, dRaw = ''] = unsigned.split('.')
        } else {
          iRaw = unsigned
          dRaw = undefined
        }
        let i = (iRaw || '').replace(/^0+(?=\d)/, '')
        let d = dRaw || ''
        if (!isNaN(totalLen) && totalLen > 0 && i.length > totalLen) {
          i = i.slice(0, totalLen)
        }
        if (!isNaN(decLen) && decLen >= 0 && d.length > decLen) {
          d = d.slice(0, decLen)
        }
        if (!isNaN(decLen) && decLen === 0) {
          v = sign + i
        } else if (dRaw !== undefined) {
          v = sign + (i || '0') + '.' + d
        } else {
          v = sign + i
        }
        if (v === '-' || v === '+') {
          row[prop] = ''
          return
        }
        row[prop] = v
      },
      onNumberKeypressNumeric(e, row, cfg) {
        const decLimit = Number(cfg && cfg.decimalLength)
        const ch = e.key
        if (ch.length !== 1) return
        if (/[0-9]/.test(ch)) return
        if (ch === '.') {
          if (isNaN(decLimit) || decLimit <= 0) {
            e.preventDefault()
            return
          }
          const prop = cfg && cfg.prop
          const val = String((prop && row[prop]) || '')
          if (val.includes('.')) e.preventDefault()
          return
        }
        if (ch === '-' || ch === '+') {
          const prop = cfg && cfg.prop
          const val = String((prop && row[prop]) || '')
          const el = e.target
          // 允许在开头输入正负号：
          // 1) 若当前值为空，允许
          // 2) 若光标在起始位置且当前无前导正负号，允许
          if (
            val.length === 0 ||
            (el && el.selectionStart === 0 && !/^[-+]/.test(val))
          ) {
            return
          }
          e.preventDefault()
          return
        }
        e.preventDefault()
      },
      onNumberKeydownNumeric(e) {
        const code = e.key
        const allowed = [
          'Backspace',
          'Delete',
          'Tab',
          'ArrowLeft',
          'ArrowRight',
          'Home',
          'End',
        ]
        if (allowed.includes(code)) return
      },
      onNumberPasteNumeric(e, row, cfg) {
        const text = (e.clipboardData && e.clipboardData.getData('text')) || ''
        if (!text) return
        const decLimit = Number(cfg && cfg.decimalLength)
        let v = text.replace(/[^0-9+\-.]/g, '')
        v = v.replace(/(?!^)[+\-]/g, '')
        if (!isNaN(decLimit) && decLimit === 0) {
          v = v.replace(/[.]/g, '')
        } else {
          const ps = v.split('.')
          if (ps.length > 2) v = ps[0] + '.' + ps.slice(1).join('')
        }
        const prop = cfg && cfg.prop
        if (!prop) return
        row[prop] = v
        this.sanitizeNumberInput(row, cfg)
      },
      onNumberCompositionEndNumeric(row, cfg) {
        this.sanitizeNumberInput(row, cfg)
      },
      // 父组件在切换到“成本审核”Tab时会调用该方法
      // 保留上方 async getDetail() 作为唯一入口，避免重复定义
      computeDateType(item) {
        const fmt =
          item && item.format ? String(item.format).trim().toLowerCase() : ''
        if (fmt.includes('h')) return 'datetime'
        if (/^y{4}$/.test(fmt)) return 'year'
        if (fmt.includes('yyyy-mm')) return 'date'
        // 没有format时，根据字段类型默认日期
        return 'date'
      },
      computeDateFormat(item) {
        const t = this.computeDateType(item)
        const fmt = item && item.format ? String(item.format).trim() : ''
        if (t === 'datetime') return fmt || 'yyyy-MM-dd HH:mm:ss'
        if (t === 'year') return fmt || 'yyyy'
        return fmt || 'yyyy-MM-dd'
      },
      // 检查按钮显示权限
      async checkButtonVisibility() {
        try {
          const taskId =
            (this.selectedProject && this.selectedProject.taskId) ||
            this.id ||
            ''
          if (!taskId) {
            this.showButtons = false
            return
          }
          const response = await getCostVerifyTemplate({ taskId })
          console.log('response', response)
          // 根据接口返回值设置按钮显示状态
          this.showButtons = !!(response && response.value)
        } catch (error) {
          console.error('检查按钮显示权限失败:', error)
          this.showButtons = false
        }
      },
    },
  }
</script>

<style scoped>
  /* .app-container {
    padding: 20px;
  } */

  .audit-controls {
    margin-bottom: 20px;
  }

  .audit-controls .el-select {
    margin-right: 10px;
    width: 150px;
  }

  .el-icon {
    font-size: 24px;
  }
</style>
