3 Commitit 028fba29bf ... 4c0631853c

Tekijä SHA1 Viesti Päivämäärä
  zzw 4c0631853c Merge remote-tracking branch 'new/master' 1 viikko sitten
  zzw d5da036cca fix:卷宗转html预览(测试) 1 viikko sitten
  zzw b2975df55f fix:核定表生成 1 viikko sitten

+ 9 - 0
src/api/costFormManage.js

@@ -203,3 +203,12 @@ export function clearCostVerifyData(data) {
     params: data,
   })
 }
+
+// 预览核定模板数据(不保存到数据库)
+export function previewCostVerifyTemplate(data) {
+  return request({
+    url: `${url}/costVerifyTemplate/v1/previewTemplateData`,
+    method: 'get',
+    params: data,
+  })
+}

+ 24 - 15
src/views/costAudit/auditInfo/archivesManage/ArchivePreview.vue

@@ -95,9 +95,19 @@
     >
       <!-- 已生成且有URL时显示预览 -->
       <div v-if="archiveStatus === '2' && archiveUrl">
+        <!-- HTML预览(优先) -->
         <iframe
+          v-if="archiveHtmlUrl"
           :key="previewKey"
-          :src="previewUrl"
+          :src="htmlPreviewUrl"
+          style="width: 100%; height: 600px; border: none"
+          @load="handlePreviewLoaded"
+        ></iframe>
+        <!-- kkFileView预览(兜底) -->
+        <iframe
+          v-else
+          :key="previewKey"
+          :src="kkfileviewPreviewUrl"
           style="width: 100%; height: 600px; border: none"
           @load="handlePreviewLoaded"
         ></iframe>
@@ -135,23 +145,31 @@
         generating: false,
         archiveStatus: null, // 0-未生成 1-生成中 2-已生成 3-生成失败
         archiveUrl: '',
+        archiveHtmlUrl: '',  // 新增:HTML预览URL
         archiveTime: '',
         pollingTimer: null, // 轮询定时器
         pollingInterval: 5000, // 轮询间隔(毫秒)
 
-        // 预览加载状态:iframe 内容真正加载完成后再关闭
+        // 预览加载状态
         previewLoading: false,
         previewKey: 0,
       }
     },
     computed: {
-      // kkFileView 预览URL
-      previewUrl() {
+      // HTML预览URL
+      htmlPreviewUrl() {
+        if (!this.archiveHtmlUrl) return ''
+        return this.getFullFileUrl(this.archiveHtmlUrl)
+      },
+
+      // kkFileView预览URL(兜底)
+      kkfileviewPreviewUrl() {
         if (!this.archiveUrl) return ''
         const fileUrl = this.getFullFileUrl(this.archiveUrl)
         const encodedUrl = encodeURIComponent(Base64.encode(fileUrl))
         return `${host}:8012/onlinePreview?url=${encodedUrl}`
       },
+
       statusText() {
         const textMap = {
           0: '卷宗尚未生成,请点击"生成卷宗"按钮开始生成',
@@ -252,6 +270,7 @@
             const data = response.value
             this.archiveStatus = data.archiveStatus || '0'
             this.archiveUrl = data.archiveUrl || ''
+            this.archiveHtmlUrl = data.archiveHtmlUrl || ''  // 新增
             this.archiveTime = data.archiveTime || ''
           } else {
             this.archiveStatus = '0'
@@ -315,16 +334,6 @@
       handlePreviewLoaded() {
         this.previewLoading = false
       },
-      // 使用 kkFileView 预览
-      handlePreview() {
-        if (!this.archiveUrl) {
-          this.$message.warning('卷宗文件地址为空')
-          return
-        }
-        const fileUrl = this.getFullFileUrl(this.archiveUrl)
-        const encodedUrl = encodeURIComponent(Base64.encode(fileUrl))
-        window.open(`${host}:8012/onlinePreview?url=${encodedUrl}`, '_blank')
-      },
       handleDownload() {
         if (!this.archiveUrl) {
           this.$message.warning('卷宗文件地址为空')
@@ -334,7 +343,7 @@
         // 创建下载链接
         const link = document.createElement('a')
         link.href = fileUrl
-        link.download = '档案卷宗.pdf'
+        link.download = '档案卷宗.docx'
         link.target = '_blank'
         document.body.appendChild(link)
         link.click()

+ 241 - 92
src/views/costAudit/auditInfo/auditManage/costAudit.vue

@@ -5,7 +5,7 @@
         ref="auditForm"
         :model="auditForm"
         :rules="rules"
-        :disabled="hasTableData"
+        :disabled="isSaved"
       >
         <el-row :gutter="20">
           <el-col :span="8">
@@ -65,20 +65,9 @@
             </el-form-item>
           </el-col>
         </el-row>
-        <el-row v-if="!hasTableData" :gutter="20">
-          <el-col :span="16">
-            <el-form-item label="新模板名称" prop="surveyTemplateName">
-              <el-input
-                v-model="auditForm.surveyTemplateName"
-                placeholder="请输入新的核定表模板名称"
-                clearable
-              ></el-input>
-            </el-form-item>
-          </el-col>
-        </el-row>
       </el-form>
       <el-button
-        v-if="!hasTableData"
+        v-if="!isSaved"
         type="primary"
         size="small"
         :loading="loading"
@@ -87,15 +76,15 @@
         生成核定表
       </el-button>
       <el-button
-        v-if="!hasUploadData"
+        v-if="hasTableData && !isSaved"
         type="primary"
         size="small"
         @click="handleSaveTemplate"
       >
-        保存核定模板
+        保存模板
       </el-button>
       <el-button
-        v-if="showButtons"
+        v-if="isSaved"
         type="primary"
         size="small"
         @click="handleExportTemplate"
@@ -103,7 +92,7 @@
         导出模板
       </el-button>
       <el-button
-        v-if="showButtons"
+        v-if="isSaved"
         type="primary"
         size="small"
         @click="handleImportData"
@@ -111,7 +100,7 @@
         导入数据
       </el-button>
       <el-button
-        v-if="showButtons"
+        v-if="isSaved"
         type="primary"
         size="small"
         @click="handleSaveData"
@@ -303,7 +292,7 @@
         </template>
       </el-table-column> -->
       <el-table-column
-        v-if="!hasUploadData"
+        v-if="!isSaved && !hasUploadData"
         prop="action"
         label="操作"
         width="100"
@@ -345,6 +334,7 @@
     batchSaveOrUpdate,
     getCostVerifyTemplate,
     clearCostVerifyData,
+    previewCostVerifyTemplate,
   } from '@/api/costFormManage'
   import {
     getlistBySurveyTemplateId,
@@ -408,7 +398,6 @@
         // 成本调查表模板列表
         surveyFormList: [],
         auditForm: {
-          surveyTemplateName: '',
           surveyTemplateId: '',
           templateType: '',
           dataTable: '',
@@ -419,10 +408,14 @@
           catalogId: [
             { required: true, message: '请输选择监审类别', trigger: 'change' },
           ],
-          surveyTemplateName: [
-            { required: true, message: '请输入新的核定表模板名称', trigger: 'blur' },
-          ],
         },
+        // 当前预览的源模板信息
+        currentPreviewSource: {
+          templateId: '',
+          templateType: ''
+        },
+        // 是否已保存到数据库
+        isSaved: false,
         tableHeadersRes: [],
         tableDataRes: [],
         // 成本审核表格列配置
@@ -430,7 +423,7 @@
         // 成本审核数据
         costAuditData: [],
         project: {},
-        // 是否已有上传数据(用于控制“生成核定表”按钮显示隐藏)
+        // 是否已有上传数据(用于控制"生成核定表"按钮显示隐藏)
         hasUploadData: false,
         // 防重与去重:避免重复请求 getSurveyDetail
         echoInProgress: false,
@@ -578,7 +571,7 @@
           if (!res || res.code !== 200) return false
           const v = res.value || {}
           // 若后端返回 code=200 但 value=null:说明任务下尚未生成/绑定模板
-          // 此时必须保持空表(不再走任何兜底加载),避免出现“value=null 但仍有表头”的问题
+          // 此时必须保持空表(不再走任何兜底加载),避免出现"value=null 但仍有表头"的问题
           if (!res.value) {
             if (this.auditForm) {
               this.auditForm.surveyTemplateId = ''
@@ -587,8 +580,13 @@
               // 保持 templateType 由用户自行选择
             }
             this.resetAuditTableState()
+            this.isSaved = false
             return 'EMPTY'
           }
+
+          // 如果获取到了数据,说明该任务已经有核定表了,标记为已保存状态
+          this.isSaved = true
+
           // 兼容不同字段命名:createTemplateId/createMode 或 createtemplateid/createmode
           const createMode = v.createMode != null ? v.createMode : v.createmode
           // 生成模板依赖模型id(用于UI来源选择的回显)
@@ -688,6 +686,61 @@
           this.loadHistoryTemplateOptions()
         }
       },
+      // 点击"生成核定表"按钮,加载数据显示
+      handleGenerateTemplate() {
+        // 校验是否选择了生成方式
+        if (!this.auditForm || !this.auditForm.templateType) {
+          this.$message.error('请先选择核定表生成方式')
+          return
+        }
+
+        // 校验是否选择了源模板
+        const sourceTemplateId = this.auditForm.templateType === '1'
+          ? this.auditForm.dataTable
+          : this.auditForm.historyTemplate
+
+        if (!sourceTemplateId) {
+          this.$message.error('请选择源模板')
+          return
+        }
+
+        // 加载数据显示
+        this.loadPreviewData(sourceTemplateId, this.auditForm.templateType)
+      },
+      // 加载数据显示(手动触发)
+      async loadPreviewData(templateId, templateType) {
+        try {
+          this.loading = true
+          const taskId = (this.selectedProject && this.selectedProject.taskId) || ''
+
+          // 调用后端预览接口
+          const resp = await previewCostVerifyTemplate({
+            templateId: templateId,
+            catalogId: this.catalogId,
+            taskId: taskId,
+            templateType: templateType
+          })
+
+          if (resp && resp.code === 200 && resp.value) {
+            // 记录当前的源模板
+            this.currentPreviewSource = {
+              templateId: templateId,
+              templateType: templateType
+            }
+
+            // 渲染数据
+            await this.renderPreviewData({
+              headers: resp.value.headers || [],
+              items: resp.value.items || []
+            })
+          }
+        } catch (error) {
+          console.error('加载数据失败:', error)
+          this.$message.error('加载数据失败:' + (error.message || '未知错误'))
+        } finally {
+          this.loading = false
+        }
+      },
       async loadSurveyFormOptions() {
         try {
           const res = await getActiveCostVerifyFormListByType({
@@ -732,48 +785,62 @@
           this.auditFormList = []
         }
       },
-      handleGenerateTemplate() {
-        // 先校验是否选择了"核定表生成方式"
-        if (!this.auditForm || !this.auditForm.templateType) {
-          this.$message.error('请先选择核定表生成方式')
-          return
-        }
-        // 校验是否输入了模板名称
-        if (!this.auditForm.surveyTemplateName || !this.auditForm.surveyTemplateName.trim()) {
-          this.$message.error('请输入新的核定表模板名称')
-          return
-        }
-        this.$confirm(
-          '核定表生成后,不再支持修改生成方式。确定生成模板吗?',
-          '提示',
-          {
-            confirmButtonText: '确定',
-            cancelButtonText: '取消',
-            type: 'warning',
+      async renderPreviewData(data) {
+        // 解析表头
+        const headersRes = { code: 200, value: data.headers }
+        await this.parseAndDisplayTableHeaders(headersRes)
+
+        // 将"单元格列表"转换为"行对象列表"
+        const rowsMap = new Map()
+        const headers = data.headers || []
+
+        // 创建表头名称到字段的映射
+        const nameToHeader = new Map()
+        headers.forEach((h) => {
+          if (h && (h.fieldName || h.label)) {
+            nameToHeader.set(String(h.fieldName || h.label), h)
           }
-        ).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('请选择模板来源方式')
-            }
-          })
         })
+
+        // 按 rowid 分组
+        data.items.forEach((item) => {
+          const rowId = item.rowid != null ? String(item.rowid) : ''
+          if (!rowId) return
+
+          if (!rowsMap.has(rowId)) {
+            rowsMap.set(rowId, {
+              rowid: rowId,
+              parentid: item.parentid != null ? String(item.parentid) : '-1',
+              orderNum: item.orderNum,
+              id: item.id,
+              surveyTemplateId: item.surveyTemplateId,
+              versionId: item.versionId,
+            })
+          }
+
+          const row = rowsMap.get(rowId)
+          const rkey = item.rkey != null ? String(item.rkey) : ''
+          const rvalue = item.rvalue != null ? String(item.rvalue) : ''
+
+          // 根据 rkey 找到对应的表头
+          const header = nameToHeader.get(rkey)
+          if (header && header.fieldEname) {
+            // 使用 fieldEname 作为属性名
+            row[header.fieldEname] = rvalue
+            // 同时保存中文列名,兼容性
+            row[header.fieldName] = rvalue
+          }
+        })
+
+        // 转换为数组
+        const rowsList = Array.from(rowsMap.values())
+
+        // 解析数据
+        const itemsRes = { code: 200, value: { itemlist: rowsList } }
+        this.parseAndDisplayTableData(itemsRes)
+
+        // 计算核定值
+        this.computeApprovedForAllRows()
       },
       async generateFromSurveyTemplate() {
         try {
@@ -1401,40 +1468,122 @@
         }
       },
       handleSaveTemplate(type) {
-        // 显示加载状态
-        this.$loading({
+        // 弹窗输入模板名称
+        this.$prompt('请输入新的核定表模板名称', '保存模板', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          inputPattern: /\S+/,
+          inputErrorMessage: '模板名称不能为空',
+          inputPlaceholder: '请输入模板名称'
+        }).then(({ value: templateName }) => {
+          this.saveTemplateWithName(templateName)
+        }).catch(() => {
+          this.$message.info('已取消保存')
+        })
+      },
+      async saveTemplateWithName(templateName) {
+        const loading = this.$loading({
           lock: true,
-          text: '保存数据中...',
+          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,
+
+        try {
+          const taskId = (this.selectedProject && this.selectedProject.taskId) || ''
+
+          // 调用后端生成模板接口(真正保存到数据库)
+          const resp = await this.generateTemplateToDatabase({
+            catalogId: this.catalogId,
+            templatename: templateName,
+            templateId: this.currentPreviewSource.templateId,
+            taskId: taskId,
+            templateType: this.currentPreviewSource.templateType
+          })
+
+          const newTemplateId = resp?.value?.surveyTemplateId || ''
+
+          if (!newTemplateId) {
+            throw new Error('生成模板失败:未返回模板ID')
+          }
+
+          this.$message.success('模板生成成功')
+
+          // 标记为已保存
+          this.isSaved = true
+
+          // 更新当前模板ID
+          this.auditForm.surveyTemplateId = newTemplateId
+
+          // 重新加载数据
+          await this.loadTemplateDataForEdit(newTemplateId)
+
+          // 检查按钮显示权限
+          await this.checkButtonVisibility()
+
+        } catch (error) {
+          console.error('生成模板失败:', error)
+          this.$message.error('生成模板失败:' + (error.message || '未知错误'))
+        } finally {
+          loading.close()
         }
-        batchSaveOrUpdate(data)
-          .then(async (data) => {
-            // 关闭加载状态
-            this.$loading().close()
-            if (type != 'delete') {
-              this.$message.success('保存成功')
-              await this.checkButtonVisibility()
-              this.loadTemplateData()
-              // 保存成功后重新检查按钮显示权限
-            }
+      },
+      async generateTemplateToDatabase(params) {
+        if (params.templateType === '1') {
+          // 从调查表生成
+          return await generateCostVerifyForm({
+            catalogId: params.catalogId,
+            templatename: params.templatename,
+            templateId: params.templateId,
+            taskId: params.taskId,
           })
-          .catch((err) => {
-            // 关闭加载状态
-            this.$loading().close()
-            console.log(err)
+        } else {
+          // 从历史核定表生成
+          return await generateCostVerifyFormData({
+            catalogId: params.catalogId,
+            templatename: params.templatename,
+            templateId: params.templateId,
+            taskId: params.taskId,
           })
+        }
+      },
+      async saveExistingTemplate(type) {
+        // 显示加载状态
+        const loading = this.$loading({
+          lock: true,
+          text: '保存数据中...',
+          spinner: 'el-icon-loading',
+          background: 'rgba(0, 0, 0, 0.7)',
+        })
+
+        try {
+          // 加上遮罩层
+          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,
+          }
+
+          await batchSaveOrUpdate(data)
+
+          // 关闭加载状态
+          loading.close()
+          if (type != 'delete') {
+            this.$message.success('保存成功')
+            await this.checkButtonVisibility()
+            this.loadTemplateData && this.loadTemplateData()
+            // 保存成功后重新检查按钮显示权限
+          }
+        } catch (err) {
+          // 关闭加载状态
+          loading.close()
+          console.log(err)
+        }
       },
       async handleSaveData() {
         const loading = this.$loading({