Ver código fonte

工作底稿核增核减、提取材料登记新增编辑删除列表接口对接完成

shiyanyu 1 mês atrás
pai
commit
4f4e34555d

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

@@ -0,0 +1,26 @@
+import request from '@/utils/request'
+
+const url = window.context.form
+// 工作底稿核增核减列表
+export function getTaskDraftList(data) {
+  return request({
+    url: url + '/api/enterprise/taskDraft/record/listByTaskId',
+    params: data,
+    method: 'get',
+  })
+}
+// 新增编辑工作底稿核增核减
+export function addTaskDraft(data) {
+  return request({
+    url: url + '/api/enterprise/taskDraft/record/opera',
+    method: 'post',
+    data: data,
+  })
+}
+// 删除工作底稿核增核减
+export function deleteTaskDraft(data) {
+  return request({
+    url: url + '/api/enterprise/taskDraft/record/delete?id=' + data.id,
+    method: 'post',
+  })
+}

+ 35 - 0
src/api/audit/taskEvidence.js

@@ -0,0 +1,35 @@
+import request from '@/utils/request'
+
+const url = window.context.form
+// 提取材料登记列表
+export function getExtractMaterialList(data) {
+  return request({
+    url: url + '/api/enterprise/taskEvidence/listByTaskId',
+    method: 'get',
+    params: data,
+  })
+}
+// 新增资料登记
+export function addTaskEvidence(data) {
+  return request({
+    url: url + '/api/enterprise/taskEvidence/add',
+    method: 'post',
+    data: data,
+  })
+}
+// 更新资料登记
+export function updateTaskEvidence(data) {
+  return request({
+    url: url + '/api/enterprise/taskEvidence/update',
+    method: 'post',
+    data: data,
+  })
+}
+// 删除资料登记
+export function deleteTaskEvidence(data) {
+  return request({
+    url: url + '/api/enterprise/taskEvidence/delete',
+    method: 'post',
+    data: data,
+  })
+}

+ 115 - 18
src/views/costAudit/auditInfo/auditManage/details.vue

@@ -103,37 +103,99 @@
     },
     watch: {
       visible(newVal) {
-        // 监听visible变化,可以在这里添加初始化逻辑
+        // 监听visible变化,弹窗打开时设置标签页并获取按钮数据
         if (newVal && this.id) {
-          // 当弹窗显示且有id时的初始化操作
+          // 使用 $nextTick 确保 props 已更新
+          this.$nextTick(() => {
+            // 设置标签页
+            this.setActiveTab()
+            // 获取资料初审按钮数据
+            this.getPreliminaryReviewButton()
+          })
+        }
+      },
+      // 监听currentNode变化,如果弹窗已打开,更新标签页并重新获取按钮数据
+      currentNode(newVal, oldVal) {
+        if (this.visible && this.id && newVal && newVal !== oldVal) {
+          this.$nextTick(() => {
+            // 设置标签页
+            this.setActiveTab()
+            // 重新获取按钮数据
+            this.getPreliminaryReviewButton()
+          })
+        }
+      },
+      // 监听currentStatus变化,如果弹窗已打开,更新标签页并重新获取按钮数据
+      currentStatus(newVal, oldVal) {
+        if (this.visible && this.id && newVal && newVal !== oldVal) {
+          this.$nextTick(() => {
+            // 设置标签页
+            this.setActiveTab()
+            // 重新获取按钮数据
+            this.getPreliminaryReviewButton()
+          })
+        }
+      },
+      // 监听id变化,如果弹窗已打开,重新获取按钮数据
+      id(newVal) {
+        if (this.visible && newVal) {
+          this.$nextTick(() => {
+            // 设置标签页
+            this.setActiveTab()
+            // 获取按钮数据
+            this.getPreliminaryReviewButton()
+          })
         }
       },
     },
     mounted() {
-      // 如果是审核中的审核节点,默认选中成本审核标签页
-      if (this.currentNode === 'sdshenhe' && this.currentStatus === '审核中') {
-        this.activeTab = 'costAudit'
-      } else if (this.currentNode === 'clcs') {
-        // 如果是成本调查节点,默认选中成本调查表标签页
-        this.activeTab = 'costSurvey'
-      }
-      if (this.id) {
-        this.getPreliminaryReviewButton()
+      // 设置标签页
+      this.setActiveTab()
+      // 如果组件挂载时弹窗已打开且有id,也调用一次
+      if (this.visible && this.id) {
+        this.$nextTick(() => {
+          this.getPreliminaryReviewButton()
+        })
       }
     },
     methods: {
+      // 根据 currentNode 和 currentStatus 设置活动标签页
+      setActiveTab() {
+        // 如果 currentNode 是 'sdshenhe' 并且 currentStatus 是 '审核中',显示成本审核标签页
+        if (
+          this.currentNode === 'sdshenhe' &&
+          this.currentStatus === '审核中'
+        ) {
+          this.activeTab = 'costAudit'
+        } else if (this.currentNode === 'clcs') {
+          // 如果 currentNode 是 'clcs',显示成本调查表标签页
+          this.activeTab = 'costSurvey'
+        } else {
+          // 其他情况默认显示报送资料标签页
+          this.activeTab = 'submitData'
+        }
+      },
       // 获取资料初审按钮
       async getPreliminaryReviewButton() {
+        // 直接从 props 获取 currentNode,确保是最新的值
+        const currentNode = this.currentNode
+
+        // 构建参数对象
         const params = {
           taskId: this.id,
-          // taskId: '1977383902654959616',
-          // processNodeKey: this.currentNode,
-          processNodeKey:
-            this.currentNode === 'ccls' ? 'clcs' : this.currentNode,
         }
-        const response = await getDataPreliminaryReviewButton(params)
-        console.log('接口返回数据:', response)
-        this.buttonData = response.value
+
+        // 只有当 currentNode 有值时才添加 processNodeKey
+        if (currentNode && currentNode.trim() !== '') {
+          params.processNodeKey = currentNode === 'ccls' ? 'clcs' : currentNode
+        }
+
+        try {
+          const response = await getDataPreliminaryReviewButton(params)
+          this.buttonData = response.value || []
+        } catch (error) {
+          this.buttonData = []
+        }
       },
       handleClose() {
         // 关闭弹窗时触发事件
@@ -144,6 +206,40 @@
         // 打开弹窗方法,供父组件通过ref调用
         this.$emit('update:visible', true)
       },
+      // 处理审核操作按钮点击
+      async handleAuditPass(item) {
+        if (!this.id) {
+          this.$message.error('缺少任务ID')
+          return
+        }
+
+        try {
+          const params = {
+            taskId: this.id,
+            ...(this.currentNode &&
+              this.currentNode.trim() !== '' && {
+                processNodeKey:
+                  this.currentNode === 'ccls' ? 'clcs' : this.currentNode,
+              }),
+            // 根据按钮项传递其他必要参数
+            ...item,
+          }
+
+          const response = await doProcessBtn(params)
+
+          if (response && response.code === 200) {
+            this.$message.success(item.value + '操作成功')
+            // 关闭弹窗
+            this.handleClose()
+            // 触发父组件刷新列表
+            this.$emit('refresh')
+          } else {
+            this.$message.error(response?.message || item.value + '操作失败')
+          }
+        } catch (error) {
+          this.$message.error(item.value + '操作失败')
+        }
+      },
     },
   }
 </script>
@@ -151,6 +247,7 @@
 <style scoped>
   .btn-group {
     margin-bottom: 20px;
+    margin-left: 20px;
   }
 
   .btn-group .el-button {

+ 370 - 85
src/views/costAudit/auditInfo/auditManage/extractMaterial.vue

@@ -2,13 +2,13 @@
   <div class="extract-material-container">
     <div class="extract-controls">
       <el-button type="primary" @click="handleAddExtract">添加资料</el-button>
-      <el-button
+      <!-- <el-button
         type="danger"
         :disabled="selectedRows.length === 0"
         @click="handleBatchDelete"
       >
         批量删除
-      </el-button>
+      </el-button> -->
     </div>
 
     <el-table
@@ -18,13 +18,12 @@
       stripe
       border
       size="small"
-      @selection-change="handleSelectionChange"
     >
-      <el-table-column
+      <!-- <el-table-column
         type="selection"
         width="55"
         align="center"
-      ></el-table-column>
+      ></el-table-column> -->
       <el-table-column prop="id" label="编号" width="80"></el-table-column>
       <el-table-column
         prop="materialName"
@@ -45,7 +44,7 @@
         show-overflow-tooltip
       ></el-table-column>
       <el-table-column
-        prop="extractTime"
+        prop="createTime"
         label="提取时间"
         width="200"
         :formatter="formatDate"
@@ -71,12 +70,13 @@
         </template>
       </el-table-column>
     </el-table>
-
     <el-dialog
       :visible.sync="dialogVisible"
       :title="dialogTitle"
       width="500px"
       :close-on-click-modal="false"
+      :modal="false"
+      append-to-body
     >
       <el-form
         ref="extractForm"
@@ -90,14 +90,50 @@
             placeholder="请输入材料名称"
           ></el-input>
         </el-form-item>
-        <el-form-item label="页数" prop="pages">
+        <el-form-item label="页数" prop="pageCount">
           <el-input-number
-            v-model.number="extractForm.pages"
+            v-model.number="extractForm.pageCount"
             placeholder="请输入页数"
             :min="1"
             :step="1"
           ></el-input-number>
         </el-form-item>
+        <el-form-item label="序号" prop="orderNum">
+          <el-input-number
+            v-model.number="extractForm.orderNum"
+            placeholder="请输入序号"
+            :min="1"
+            :step="1"
+          ></el-input-number>
+        </el-form-item>
+        <el-form-item label="上传附件" prop="fileList">
+          <el-upload
+            class="upload-demo"
+            :action="''"
+            :http-request="handleFileUpload"
+            :on-remove="handleFileRemove"
+            :before-upload="beforeFileUpload"
+            :on-success="handleFileUploadSuccess"
+            :on-error="handleFileUploadError"
+            :on-progress="handleFileUploadProgress"
+            :file-list="extractForm.fileList"
+            :limit="1"
+            :on-exceed="handleFileExceed"
+          >
+            <el-button
+              v-show="
+                !extractForm.fileList || extractForm.fileList.length === 0
+              "
+              size="small"
+              type="primary"
+            >
+              选择文件
+            </el-button>
+            <div slot="tip" class="el-upload__tip">
+              支持 pdf, doc, docx, xls, xlsx, csv 格式,单个文件不超过50MB
+            </div>
+          </el-upload>
+        </el-form-item>
         <el-form-item label="备注" prop="remark">
           <el-input
             v-model="extractForm.remark"
@@ -117,7 +153,13 @@
 
 <script>
   // 暂时使用mock数据,后续根据实际API调整
-  // import { getExtractMaterials, addExtractMaterial, updateExtractMaterial, deleteExtractMaterial } from '@/api/auditManage'
+  import {
+    getExtractMaterialList,
+    addTaskEvidence,
+    updateTaskEvidence,
+    deleteTaskEvidence,
+  } from '@/api/audit/taskEvidence'
+  import { uploadFile } from '@/api/file'
 
   export default {
     name: 'ExtractMaterial',
@@ -138,8 +180,11 @@
         extractForm: {
           id: '',
           materialName: '',
-          pages: null,
+          pageCount: null,
+          orderNum: null,
           remark: '',
+          fileList: [],
+          attachmentUrl: '',
         },
         rules: {
           materialName: [
@@ -151,10 +196,65 @@
               trigger: 'blur',
             },
           ],
-          pages: [
-            { required: true, message: '请输入页数', trigger: 'blur' },
-            { type: 'number', message: '页数必须为数字', trigger: 'blur' },
-            { min: 1, message: '页数必须大于0', trigger: 'blur' },
+          pageCount: [
+            {
+              required: true,
+              message: '请输入页数',
+              trigger: ['blur', 'change'],
+            },
+            {
+              type: 'number',
+              message: '页数必须为数字',
+              trigger: ['blur', 'change'],
+            },
+            {
+              validator: (rule, value, callback) => {
+                if (value === null || value === undefined || value === '') {
+                  callback()
+                  return
+                }
+                if (typeof value !== 'number' || isNaN(value)) {
+                  callback(new Error('页数必须为数字'))
+                  return
+                }
+                if (value < 1) {
+                  callback(new Error('页数必须大于0'))
+                  return
+                }
+                callback()
+              },
+              trigger: ['blur', 'change'],
+            },
+          ],
+          orderNum: [
+            {
+              required: true,
+              message: '请输入序号',
+              trigger: ['blur', 'change'],
+            },
+            {
+              type: 'number',
+              message: '序号必须为数字',
+              trigger: ['blur', 'change'],
+            },
+            {
+              validator: (rule, value, callback) => {
+                if (value === null || value === undefined || value === '') {
+                  callback()
+                  return
+                }
+                if (typeof value !== 'number' || isNaN(value)) {
+                  callback(new Error('序号必须为数字'))
+                  return
+                }
+                if (value < 1) {
+                  callback(new Error('序号必须大于0'))
+                  return
+                }
+                callback()
+              },
+              trigger: ['blur', 'change'],
+            },
           ],
         },
       }
@@ -174,40 +274,29 @@
 
       // 获取提取材料列表
       async getExtractMaterials() {
+        if (!this.id) {
+          return
+        }
+
         try {
           this.loading = true
-          // 模拟API请求延迟
-          await new Promise((resolve) => setTimeout(resolve, 500))
-
-          // Mock数据
-          this.extractMaterials = [
-            {
-              id: '1',
-              materialName: '营业执照复印件',
-              pages: 2,
-              remark: '加盖公章',
-              extractTime: new Date().toISOString(),
-            },
-            {
-              id: '2',
-              materialName: '财务报表',
-              pages: 5,
-              remark: '包含资产负债表、利润表',
-              extractTime: new Date().toISOString(),
-            },
-            {
-              id: '3',
-              materialName: '成本核算清单',
-              pages: 10,
-              remark: '',
-              extractTime: new Date().toISOString(),
-            },
-          ]
+          const res = await getExtractMaterialList({
+            taskId: this.id,
+          })
 
-          this.$message.success('获取提取材料列表成功')
+          if (res && res.value) {
+            // 统一字段名:如果后端返回的是 pageCount,映射为 pages
+            this.extractMaterials = (res.value || []).map((item) => ({
+              ...item,
+              pages: item.pages !== undefined ? item.pages : item.pageCount,
+            }))
+          } else {
+            this.extractMaterials = []
+          }
         } catch (error) {
           this.$message.error('获取提取材料列表失败')
           console.error('获取提取材料列表失败:', error)
+          this.extractMaterials = []
         } finally {
           this.loading = false
         }
@@ -220,8 +309,15 @@
         this.extractForm = {
           id: '',
           materialName: '',
-          pages: null,
+          pageCount: null,
+          orderNum: null,
           remark: '',
+          fileList: [],
+          attachmentUrl: '',
+        }
+        // 重置表单验证状态
+        if (this.$refs.extractForm) {
+          this.$refs.extractForm.resetFields()
         }
         this.dialogVisible = true
       },
@@ -230,7 +326,25 @@
       handleEditExtract(row) {
         this.isEdit = true
         this.dialogTitle = '编辑提取材料'
-        this.extractForm = { ...row }
+        // 确保字段名统一,如果后端返回的是 pages,映射为 pageCount
+        // 处理文件列表
+        let fileList = []
+        if (row.attachmentUrl) {
+          fileList = [
+            {
+              name: row.fileName || '附件',
+              url: row.attachmentUrl,
+              response: { savePath: row.attachmentUrl },
+            },
+          ]
+        }
+        this.extractForm = {
+          ...row,
+          pageCount: row.pageCount !== undefined ? row.pageCount : row.pages,
+          orderNum: row.orderNum !== undefined ? row.orderNum : row.orderNumber,
+          fileList: fileList,
+          attachmentUrl: row.attachmentUrl || '',
+        }
         this.dialogVisible = true
       },
 
@@ -243,18 +357,15 @@
             type: 'warning',
           })
 
-          // 模拟API请求
-          await new Promise((resolve) => setTimeout(resolve, 300))
+          const res = await deleteTaskEvidence({ id: row.id })
 
-          // 从列表中删除
-          const index = this.extractMaterials.findIndex(
-            (item) => item.id === row.id
-          )
-          if (index > -1) {
-            this.extractMaterials.splice(index, 1)
+          if (res.code === 200) {
+            this.$message.success('删除成功')
+            // 重新获取列表
+            this.getExtractMaterials()
+          } else {
+            this.$message.error(res.message || '删除失败')
           }
-
-          this.$message.success('删除成功')
         } catch (error) {
           if (error !== 'cancel') {
             this.$message.error('删除失败')
@@ -281,20 +392,32 @@
             }
           )
 
-          // 模拟API请求
-          await new Promise((resolve) => setTimeout(resolve, 300))
-
-          // 从列表中删除选中的项
-          const idsToDelete = this.selectedRows.map((row) => row.id)
-          this.extractMaterials = this.extractMaterials.filter(
-            (item) => !idsToDelete.includes(item.id)
+          // 批量删除,逐条调用删除接口
+          const deletePromises = this.selectedRows.map((row) =>
+            deleteTaskEvidence({ id: row.id })
           )
-          this.selectedRows = [] // 清空选择
+          const results = await Promise.all(deletePromises)
 
-          this.$message.success('批量删除成功')
+          // 检查是否有失败的
+          const failedCount = results.filter((res) => res.code !== 200).length
+          if (failedCount === 0) {
+            this.$message.success('批量删除成功')
+            this.selectedRows = [] // 清空选择
+            // 重新获取列表
+            this.getExtractMaterials()
+          } else {
+            this.$message.warning(
+              `批量删除完成,${
+                results.length - failedCount
+              } 条成功,${failedCount} 条失败`
+            )
+            // 即使有失败的,也刷新列表以获取最新数据
+            this.selectedRows = []
+            this.getExtractMaterials()
+          }
         } catch (error) {
           if (error !== 'cancel') {
-            this.$message.error('删除失败')
+            this.$message.error('批量删除失败')
             console.error('批量删除提取材料失败:', error)
           }
         }
@@ -305,29 +428,34 @@
         try {
           await this.$refs.extractForm.validate()
 
-          // 模拟API请求
-          await new Promise((resolve) => setTimeout(resolve, 300))
-
-          const formData = { ...this.extractForm }
-          if (!this.isEdit) {
-            // 添加新记录
-            formData.id = Date.now().toString() // 生成临时ID
-            formData.taskId = this.id
-            formData.extractTime = new Date().toISOString()
-            this.extractMaterials.unshift(formData)
-            this.$message.success('添加成功')
+          const formData = {
+            id: this.extractForm.id,
+            materialName: this.extractForm.materialName,
+            pageCount: this.extractForm.pageCount,
+            orderNum: this.extractForm.orderNum,
+            remark: this.extractForm.remark,
+            attachmentUrl: this.extractForm.attachmentUrl,
+            taskId: this.id,
+          }
+
+          let res
+          if (this.isEdit) {
+            // 编辑模式,调用更新接口
+            res = await updateTaskEvidence(formData)
           } else {
-            // 更新现有记录
-            const index = this.extractMaterials.findIndex(
-              (item) => item.id === formData.id
-            )
-            if (index > -1) {
-              this.extractMaterials.splice(index, 1, formData)
-            }
-            this.$message.success('更新成功')
+            // 添加模式,调用新增接口
+            res = await addTaskEvidence(formData)
           }
 
-          this.dialogVisible = false
+          if (res.code === 200) {
+            this.$message.success(this.isEdit ? '更新成功' : '添加成功')
+            this.dialogVisible = false
+            this.getExtractMaterials()
+          } else {
+            this.$message.error(
+              res.message || (this.isEdit ? '更新失败' : '添加失败')
+            )
+          }
         } catch (error) {
           if (error !== 'cancel') {
             this.$message.error(this.isEdit ? '更新失败' : '添加失败')
@@ -339,6 +467,163 @@
         }
       },
 
+      // 文件上传前验证
+      beforeFileUpload(file) {
+        const allowedTypes = [
+          'application/pdf',
+          'application/msword',
+          'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+          'application/vnd.ms-excel',
+          'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+          'text/csv',
+        ]
+
+        const allowedExtensions = [
+          '.pdf',
+          '.doc',
+          '.docx',
+          '.xls',
+          '.xlsx',
+          '.csv',
+        ]
+        const fileExtension = '.' + file.name.split('.').pop().toLowerCase()
+
+        // 检查文件格式
+        const isCorrectType = allowedTypes.includes(file.type)
+        const isCorrectExtension = allowedExtensions.includes(fileExtension)
+
+        if (!isCorrectType && !isCorrectExtension) {
+          this.$message.error(
+            '只允许上传 pdf, doc, docx, xls, xlsx, csv 格式的文件!'
+          )
+          return false
+        }
+
+        // 检查文件大小 (50MB)
+        const isLt50M = file.size / 1024 / 1024 < 50
+        if (!isLt50M) {
+          this.$message.error('文件大小不能超过 50MB!')
+          return false
+        }
+
+        return true
+      },
+
+      // 自定义上传方法
+      async handleFileUpload(options) {
+        const { file, onProgress, onSuccess, onError } = options
+
+        // 检查是否已经上传了文件
+        if (
+          this.extractForm.fileList &&
+          this.extractForm.fileList.length >= 1
+        ) {
+          this.$message.warning('只能上传一个文件,请先删除已上传的文件')
+          if (onError) {
+            onError(new Error('只能上传一个文件'))
+          }
+          return
+        }
+
+        const formData = new FormData()
+        formData.append('file', file)
+
+        try {
+          // 显示上传进度
+          if (onProgress) {
+            onProgress({ percent: 0 })
+          }
+
+          // 调用上传API
+          const uploadRes = await uploadFile('/api/file/v1/upload', formData, {
+            onUploadProgress: (progressEvent) => {
+              // 计算上传进度
+              if (progressEvent.total) {
+                const percent = Math.round(
+                  (progressEvent.loaded * 100) / progressEvent.total
+                )
+                if (onProgress) {
+                  onProgress({ percent })
+                }
+              }
+            },
+          })
+
+          // 检查上传结果
+          if (uploadRes && uploadRes.code === 200 && uploadRes.value) {
+            const fileInfo = uploadRes.value
+            // 构造文件信息对象,符合element-ui upload组件的格式
+            const fileObj = {
+              uid: file.uid,
+              name: file.name,
+              status: 'success',
+              size: file.size,
+              response: fileInfo,
+              url: fileInfo.savePath || fileInfo.url,
+            }
+
+            if (onSuccess) {
+              onSuccess(fileInfo, fileObj)
+              this.extractForm.attachmentUrl = fileInfo.savePath || fileInfo.url
+            }
+
+            this.$message.success(`${file.name} 上传成功`)
+          } else {
+            throw new Error(uploadRes?.message || '上传失败,请稍后重试')
+          }
+        } catch (error) {
+          console.error('文件上传失败:', error)
+          this.$message.error(`文件上传失败:${error.message || '未知错误'}`)
+          if (onError) {
+            onError(error)
+          }
+        }
+      },
+
+      // 上传成功回调
+      handleFileUploadSuccess(response, file, fileList) {
+        // 更新文件列表,添加文件URL信息
+        this.extractForm.fileList = fileList.map((item) => {
+          if (item.uid === file.uid && response) {
+            return {
+              ...item,
+              url: response.savePath || response.url || item.url,
+              response: response,
+            }
+          }
+          return item
+        })
+      },
+
+      // 上传进度回调
+      handleFileUploadProgress(event, file, fileList) {
+        // element-ui 会自动处理上传进度显示
+      },
+
+      // 上传失败回调
+      handleFileUploadError(err, file, fileList) {
+        console.error('文件上传错误:', err)
+        this.$message.error(`${file.name} 上传失败`)
+        // 从文件列表中移除失败的文件
+        this.extractForm.fileList = fileList.filter(
+          (item) => item.uid !== file.uid
+        )
+      },
+
+      // 超出文件数量限制
+      handleFileExceed(files, fileList) {
+        this.$message.warning(
+          `当前限制选择 1 个文件,本次选择了 ${files.length} 个文件,共选择了 ${fileList.length} 个文件`
+        )
+      },
+
+      // 移除文件
+      handleFileRemove(file, fileList) {
+        this.extractForm.fileList = fileList
+        this.extractForm.attachmentUrl = ''
+        this.$message.info(`${file.name} 已移除`)
+      },
+
       // 格式化日期
       formatDate(row, column, cellValue) {
         if (!cellValue) return ''

+ 13 - 4
src/views/costAudit/auditInfo/auditManage/index.vue

@@ -91,7 +91,7 @@
                 任务详情
               </el-button>
               <el-button
-                v-if="scope.row.currentNode === 'sdsh'"
+                v-if="scope.row.currentNode === 'sdshenhe'"
                 type="text"
                 @click="handleOpenDetails(scope.row)"
               >
@@ -114,7 +114,8 @@
               </el-button>
               <el-button
                 v-if="
-                  scope.row.currentNode === 'sdshenhe' &&
+                  (scope.row.currentNode === 'sdshenhe' ||
+                    scope.row.currentNode === 'yjfk') &&
                   scope.row.status === '审核中'
                 "
                 type="text"
@@ -143,9 +144,10 @@
       :id="selectedProject && selectedProject.id"
       ref="detailsRef"
       :visible.sync="detailsVisible"
-      :current-node="selectedProject && selectedProject.auditNode"
-      :current-status="selectedProject && selectedProject.auditStatus"
+      :current-node="selectedProject && selectedProject.currentNode"
+      :current-status="selectedProject && selectedProject.status"
       @close="handleDetailsClose"
+      @refresh="handleRefresh"
     />
   </div>
 </template>
@@ -293,6 +295,7 @@
 
       // 打开详情弹窗
       handleOpenDetails(project) {
+        console.log('project', project)
         this.selectedProject = project
         this.detailsVisible = true
       },
@@ -304,6 +307,12 @@
         // 可以在这里添加刷新列表的逻辑
       },
 
+      // 刷新表格数据
+      handleRefresh() {
+        // 刷新列表数据
+        this.loadAuditProjectList()
+      },
+
       // 查记录
       handleCheckRecord(project) {
         // memoManage

+ 454 - 105
src/views/costAudit/auditInfo/auditManage/workDraft.vue

@@ -15,6 +15,7 @@
       </el-button>
     </div>
     <el-table
+      v-loading="loading"
       :data="workingPaperRecords"
       style="width: 100%; margin-top: 20px"
       border
@@ -74,6 +75,8 @@
       :title="workingPaperDialogTitle"
       :visible.sync="workingPaperDialogVisible"
       width="70%"
+      :modal="false"
+      append-to-body
     >
       <el-form
         ref="workingPaperForm"
@@ -81,23 +84,23 @@
         :rules="workingPaperRules"
         label-width="120px"
       >
-        <el-form-item label="被审核科目" prop="auditSubject">
+        <el-form-item label="被审核科目" prop="subject">
           <el-input
-            v-model="workingPaperForm.auditSubject"
+            v-model="workingPaperForm.subject"
             placeholder="请输入被审核科目"
           />
         </el-form-item>
-        <el-form-item label="基本情况" prop="basicInfo">
+        <el-form-item label="基本情况" prop="basicSituation">
           <el-input
-            v-model="workingPaperForm.basicInfo"
+            v-model="workingPaperForm.basicSituation"
             type="textarea"
             :rows="4"
             placeholder="请输入基本情况"
           />
         </el-form-item>
-        <el-form-item label="核增核减说明" prop="auditDesc">
+        <el-form-item label="核增核减说明" prop="description">
           <el-input
-            v-model="workingPaperForm.auditDesc"
+            v-model="workingPaperForm.description"
             type="textarea"
             :rows="4"
             placeholder="请输入核增核减说明"
@@ -128,6 +131,35 @@
             />
           </div>
         </el-form-item>
+        <el-form-item label="上传附件" prop="fileList">
+          <el-upload
+            class="upload-demo"
+            :action="''"
+            :http-request="handleFileUpload"
+            :on-remove="handleFileRemove"
+            :before-upload="beforeFileUpload"
+            :on-success="handleFileUploadSuccess"
+            :on-error="handleFileUploadError"
+            :on-progress="handleFileUploadProgress"
+            :file-list="workingPaperForm.fileList"
+            :limit="1"
+            :on-exceed="handleFileExceed"
+          >
+            <el-button
+              v-show="
+                !workingPaperForm.fileList ||
+                workingPaperForm.fileList.length === 0
+              "
+              size="small"
+              type="primary"
+            >
+              选择文件
+            </el-button>
+            <div slot="tip" class="el-upload__tip">
+              支持 pdf, doc, docx, xls, xlsx, csv 格式,单个文件不超过50MB
+            </div>
+          </el-upload>
+        </el-form-item>
       </el-form>
       <div slot="footer" class="dialog-footer">
         <el-button @click="workingPaperDialogVisible = false">取消</el-button>
@@ -140,10 +172,23 @@
 </template>
 
 <script>
+  import {
+    getTaskDraftList,
+    addTaskDraft,
+    deleteTaskDraft,
+  } from '@/api/audit/taskDraft'
+  import { uploadFile } from '@/api/file'
   export default {
     name: 'WorkDraft',
+    props: {
+      id: {
+        type: [String, Number],
+        default: null,
+      },
+    },
     data() {
       return {
+        loading: false,
         editorConfig: {
           // 可以在这里覆盖全局配置的选项
           height: '300px',
@@ -153,60 +198,86 @@
         // 工作底稿数据
         workingPaperContent: '工作底稿内容将在这里展示。',
         // 工作底稿记录列表
-        workingPaperRecords: [
-          {
-            id: '001',
-            auditSubject: '科目核减',
-            basicInfo: '该科目存在多计费用情况',
-            auditDesc: '根据凭证检查,发现重复列支费用20万元,建议核减',
-            auditTime: '2025-01-20 13:00-17:00',
-            attachments: ['审计凭证.pdf'],
-          },
-          {
-            id: '002',
-            auditSubject: '科目核增',
-            basicInfo: '该科目存在少计收入情况',
-            auditDesc: '通过银行流水核对,发现未入账收入15万元,建议核增',
-            auditTime: '2025-01-27 14:00-17:30',
-            attachments: [],
-          },
-          {
-            id: '003',
-            auditSubject: '费用列支',
-            basicInfo: '检查期间费用列支情况',
-            auditDesc: '发现部分费用列支不规范,需补充说明材料',
-            auditTime: '2025-01-30 09:00-18:00',
-            attachments: ['费用明细.xlsx'],
-          },
-        ],
+        workingPaperRecords: [],
         // 工作底稿弹窗
         workingPaperDialogVisible: false,
         workingPaperDialogTitle: '添加工作底稿',
         isEditWorkingPaper: false,
         workingPaperForm: {
           id: '',
-          auditSubject: '',
-          basicInfo: '',
-          auditDesc: '',
+          subject: '',
+          basicSituation: '',
+          description: '',
           auditDate: '',
           startTime: '',
           endTime: '',
           attachments: [],
+          fileList: [],
+          attachmentUrl: '',
         },
         workingPaperRules: {
-          auditSubject: [
+          subject: [
             { required: true, message: '请输入被审核科目', trigger: 'blur' },
           ],
-          basicInfo: [
+          basicSituation: [
             { required: true, message: '请输入基本情况', trigger: 'blur' },
           ],
-          auditDesc: [
+          description: [
             { required: true, message: '请输入核增核减说明', trigger: 'blur' },
           ],
         },
       }
     },
+    mounted() {
+      this.getWorkingPaperRecords()
+    },
     methods: {
+      // 获取工作底稿列表
+      async getWorkingPaperRecords() {
+        if (!this.id) {
+          return
+        }
+        try {
+          this.loading = true
+          const res = await getTaskDraftList({ taskId: this.id })
+          if (res && res.value) {
+            // 处理数据,格式化时间显示
+            this.workingPaperRecords = (res.value || []).map((item) => {
+              // 格式化时间显示,如果后端返回的是 time 字段,直接使用
+              let auditTime = ''
+              if (item.time) {
+                auditTime = item.time
+              } else if (item.auditTime) {
+                auditTime = item.auditTime
+              } else if (item.auditDate) {
+                const date = new Date(item.auditDate)
+                const formattedDate = `${date.getFullYear()}-${String(
+                  date.getMonth() + 1
+                ).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`
+                const startTime = item.startTime || '00:00'
+                const endTime = item.endTime || '23:59'
+                auditTime = `${formattedDate} ${startTime}-${endTime}`
+              }
+              // 字段名映射
+              return {
+                ...item,
+                auditSubject: item.subject || item.auditSubject,
+                basicInfo: item.basicSituation || item.basicInfo,
+                auditDesc: item.description || item.auditDesc,
+                auditTime: auditTime,
+              }
+            })
+          } else {
+            this.workingPaperRecords = []
+          }
+        } catch (error) {
+          this.$message.error('获取工作底稿列表失败')
+          console.error('获取工作底稿列表失败:', error)
+          this.workingPaperRecords = []
+        } finally {
+          this.loading = false
+        }
+      },
       onEditorReady(editor) {
         // 编辑器初始化完成后的回调
         console.log('编辑器已就绪', editor)
@@ -218,13 +289,19 @@
         this.workingPaperDialogTitle = '添加工作底稿'
         this.workingPaperForm = {
           id: '',
-          auditSubject: '',
-          basicInfo: '',
-          auditDesc: '',
+          subject: '',
+          basicSituation: '',
+          description: '',
           auditDate: new Date(),
           startTime: '',
           endTime: '',
           attachments: [],
+          fileList: [],
+          attachmentUrl: '',
+        }
+        // 重置表单验证状态
+        if (this.$refs.workingPaperForm) {
+          this.$refs.workingPaperForm.resetFields()
         }
         this.workingPaperDialogVisible = true
       },
@@ -232,89 +309,361 @@
       handleEditWorkingPaper(row) {
         this.isEditWorkingPaper = true
         this.workingPaperDialogTitle = '修改工作底稿'
-        const timeParts = row.auditTime.split(' ')
-        const date = timeParts[0]
-        const timeRange = timeParts[1].split('-')
+        // 解析时间字符串
+        let auditDate = new Date()
+        let startTime = null
+        let endTime = null
+
+        // 优先使用 time 字段,如果没有则使用 auditTime,再没有则使用分开的日期时间
+        const timeStr = row.time || row.auditTime || ''
+        if (timeStr) {
+          const timeParts = timeStr.split(' ')
+          if (timeParts.length >= 2) {
+            const date = timeParts[0]
+            const timeRange = timeParts[1].split('-')
+            auditDate = new Date(date)
+            // 将时间字符串转换为 Date 对象
+            if (timeRange[0]) {
+              const [hours, minutes] = timeRange[0].split(':')
+              startTime = new Date()
+              startTime.setHours(
+                parseInt(hours) || 0,
+                parseInt(minutes) || 0,
+                0,
+                0
+              )
+            }
+            if (timeRange[1]) {
+              const [hours, minutes] = timeRange[1].split(':')
+              endTime = new Date()
+              endTime.setHours(
+                parseInt(hours) || 0,
+                parseInt(minutes) || 0,
+                0,
+                0
+              )
+            }
+          }
+        } else if (row.auditDate) {
+          auditDate = new Date(row.auditDate)
+          // 将时间字符串转换为 Date 对象
+          if (row.startTime) {
+            const [hours, minutes] = row.startTime.split(':')
+            startTime = new Date()
+            startTime.setHours(
+              parseInt(hours) || 0,
+              parseInt(minutes) || 0,
+              0,
+              0
+            )
+          }
+          if (row.endTime) {
+            const [hours, minutes] = row.endTime.split(':')
+            endTime = new Date()
+            endTime.setHours(parseInt(hours) || 0, parseInt(minutes) || 0, 0, 0)
+          }
+        }
+
+        // 处理文件列表
+        let fileList = []
+        if (row.attachmentUrl) {
+          fileList = [
+            {
+              name: row.fileName || '附件',
+              url: row.attachmentUrl,
+              response: { savePath: row.attachmentUrl },
+            },
+          ]
+        }
 
+        // 字段名映射
         this.workingPaperForm = {
           ...row,
-          auditDate: new Date(date),
-          startTime: timeRange[0],
-          endTime: timeRange[1],
+          subject: row.subject || row.auditSubject || '',
+          basicSituation: row.basicSituation || row.basicInfo || '',
+          description: row.description || row.auditDesc || '',
+          auditDate: auditDate,
+          startTime: startTime,
+          endTime: endTime,
+          fileList: fileList,
+          attachmentUrl: row.attachmentUrl || '',
         }
         this.workingPaperDialogVisible = true
       },
 
-      handleDeleteWorkingPaper(row) {
-        this.$confirm('确定要删除这条工作底稿吗?', '提示', {
-          confirmButtonText: '确定',
-          cancelButtonText: '取消',
-          type: 'warning',
-        })
-          .then(() => {
-            const index = this.workingPaperRecords.indexOf(row)
-            if (index !== -1) {
-              this.workingPaperRecords.splice(index, 1)
-            }
-            this.$message({ type: 'success', message: '工作底稿已删除' })
-          })
-          .catch(() => {
-            this.$message({ type: 'info', message: '已取消删除' })
+      async handleDeleteWorkingPaper(row) {
+        try {
+          await this.$confirm('确定要删除这条工作底稿吗?', '提示', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning',
           })
+
+          const res = await deleteTaskDraft({ id: row.id })
+          if (res.code === 200) {
+            this.$message.success('工作底稿已删除')
+            // 重新获取列表
+            this.getWorkingPaperRecords()
+          } else {
+            this.$message.error(res.message || '删除失败')
+          }
+        } catch (error) {
+          if (error !== 'cancel') {
+            this.$message.error('删除失败')
+            console.error('删除工作底稿失败:', error)
+          }
+        }
       },
 
-      handleWorkingPaperSubmit() {
-        this.$refs.workingPaperForm.validate((valid) => {
-          if (valid) {
-            const auditDate = new Date(this.workingPaperForm.auditDate)
-            const formattedDate = `${auditDate.getFullYear()}-${String(
-              auditDate.getMonth() + 1
-            ).padStart(2, '0')}-${String(auditDate.getDate()).padStart(2, '0')}`
-            const auditTime = `${formattedDate} ${
-              this.workingPaperForm.startTime || '00:00'
-            }-${this.workingPaperForm.endTime || '23:59'}`
-
-            if (this.isEditWorkingPaper) {
-              // 修改操作
-              const index = this.workingPaperRecords.findIndex(
-                (item) => item.id === this.workingPaperForm.id
-              )
-              if (index !== -1) {
-                this.workingPaperRecords[index] = {
-                  ...this.workingPaperRecords[index],
-                  auditSubject: this.workingPaperForm.auditSubject,
-                  basicInfo: this.workingPaperForm.basicInfo,
-                  auditDesc: this.workingPaperForm.auditDesc,
-                  auditTime: auditTime,
-                }
-                this.$message({ type: 'success', message: '工作底稿修改成功' })
-              }
-            } else {
-              // 添加操作
-              const newId = String(
-                this.workingPaperRecords.length + 1
-              ).padStart(3, '0')
-              this.workingPaperRecords.push({
-                id: newId,
-                auditSubject: this.workingPaperForm.auditSubject,
-                basicInfo: this.workingPaperForm.basicInfo,
-                auditDesc: this.workingPaperForm.auditDesc,
-                auditTime: auditTime,
-                attachments: [],
-              })
-              this.$message({ type: 'success', message: '工作底稿添加成功' })
-            }
+      async handleWorkingPaperSubmit() {
+        try {
+          await this.$refs.workingPaperForm.validate()
+
+          // 格式化日期
+          const auditDate = new Date(this.workingPaperForm.auditDate)
+          const formattedDate = `${auditDate.getFullYear()}-${String(
+            auditDate.getMonth() + 1
+          ).padStart(2, '0')}-${String(auditDate.getDate()).padStart(2, '0')}`
+
+          // 格式化时间(如果没有选择时间,使用默认值)
+          const startTime = this.workingPaperForm.startTime
+            ? this.formatTime(this.workingPaperForm.startTime)
+            : '00:00'
+          const endTime = this.workingPaperForm.endTime
+            ? this.formatTime(this.workingPaperForm.endTime)
+            : '23:59'
+
+          // 合并日期和时间范围为 time 字段
+          const time = `${formattedDate} ${startTime}-${endTime}`
+
+          // 构造提交数据
+          const formData = {
+            taskId: this.id,
+            subject: this.workingPaperForm.subject,
+            basicSituation: this.workingPaperForm.basicSituation,
+            description: this.workingPaperForm.description,
+            time: time,
+            attachmentUrl: this.workingPaperForm.attachmentUrl,
+          }
+
+          // 如果是编辑模式,添加 id
+          if (this.isEditWorkingPaper && this.workingPaperForm.id) {
+            formData.id = this.workingPaperForm.id
+          }
+
+          const res = await addTaskDraft(formData)
+          if (res.code === 200) {
+            this.$message.success(
+              this.isEditWorkingPaper ? '工作底稿修改成功' : '工作底稿添加成功'
+            )
             this.workingPaperDialogVisible = false
+            // 重新获取列表
+            this.getWorkingPaperRecords()
+          } else {
+            this.$message.error(
+              res.message || (this.isEditWorkingPaper ? '修改失败' : '添加失败')
+            )
           }
-        })
+        } catch (error) {
+          if (error !== 'cancel') {
+            this.$message.error(
+              this.isEditWorkingPaper ? '修改失败' : '添加失败'
+            )
+            console.error('提交工作底稿失败:', error)
+          }
+        }
+      },
+
+      // 格式化时间为 HH:mm 格式
+      formatTime(time) {
+        if (!time) return ''
+        if (typeof time === 'string') {
+          // 如果已经是字符串格式 HH:mm,直接返回
+          if (/^\d{2}:\d{2}$/.test(time)) {
+            return time
+          }
+        }
+        // 如果是 Date 对象
+        if (time instanceof Date) {
+          const hours = String(time.getHours()).padStart(2, '0')
+          const minutes = String(time.getMinutes()).padStart(2, '0')
+          return `${hours}:${minutes}`
+        }
+        return ''
       },
 
       handlePreviewWorkingPaperAttachment(row) {
+        const attachments =
+          row.attachments && Array.isArray(row.attachments)
+            ? row.attachments
+            : []
+        if (attachments.length === 0) {
+          this.$message.info('暂无附件')
+          return
+        }
         this.$message({
           type: 'info',
-          message: `预览附件:${row.attachments.join(', ')}`,
+          message: `预览附件:${attachments.join(', ')}`,
         })
       },
+
+      // 文件上传前验证
+      beforeFileUpload(file) {
+        const allowedTypes = [
+          'application/pdf',
+          'application/msword',
+          'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+          'application/vnd.ms-excel',
+          'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+          'text/csv',
+        ]
+
+        const allowedExtensions = [
+          '.pdf',
+          '.doc',
+          '.docx',
+          '.xls',
+          '.xlsx',
+          '.csv',
+        ]
+        const fileExtension = '.' + file.name.split('.').pop().toLowerCase()
+
+        // 检查文件格式
+        const isCorrectType = allowedTypes.includes(file.type)
+        const isCorrectExtension = allowedExtensions.includes(fileExtension)
+
+        if (!isCorrectType && !isCorrectExtension) {
+          this.$message.error(
+            '只允许上传 pdf, doc, docx, xls, xlsx, csv 格式的文件!'
+          )
+          return false
+        }
+
+        // 检查文件大小 (50MB)
+        const isLt50M = file.size / 1024 / 1024 < 50
+        if (!isLt50M) {
+          this.$message.error('文件大小不能超过 50MB!')
+          return false
+        }
+
+        return true
+      },
+
+      // 自定义上传方法
+      async handleFileUpload(options) {
+        const { file, onProgress, onSuccess, onError } = options
+
+        // 检查是否已经上传了文件
+        if (
+          this.workingPaperForm.fileList &&
+          this.workingPaperForm.fileList.length >= 1
+        ) {
+          this.$message.warning('只能上传一个文件,请先删除已上传的文件')
+          if (onError) {
+            onError(new Error('只能上传一个文件'))
+          }
+          return
+        }
+
+        const formData = new FormData()
+        formData.append('file', file)
+
+        try {
+          // 显示上传进度
+          if (onProgress) {
+            onProgress({ percent: 0 })
+          }
+
+          // 调用上传API
+          const uploadRes = await uploadFile('/api/file/v1/upload', formData, {
+            onUploadProgress: (progressEvent) => {
+              // 计算上传进度
+              if (progressEvent.total) {
+                const percent = Math.round(
+                  (progressEvent.loaded * 100) / progressEvent.total
+                )
+                if (onProgress) {
+                  onProgress({ percent })
+                }
+              }
+            },
+          })
+
+          // 检查上传结果
+          if (uploadRes && uploadRes.code === 200 && uploadRes.value) {
+            const fileInfo = uploadRes.value
+            // 构造文件信息对象,符合element-ui upload组件的格式
+            const fileObj = {
+              uid: file.uid,
+              name: file.name,
+              status: 'success',
+              size: file.size,
+              response: fileInfo,
+              url: fileInfo.savePath || fileInfo.url,
+            }
+
+            if (onSuccess) {
+              onSuccess(fileInfo, fileObj)
+              this.workingPaperForm.attachmentUrl =
+                fileInfo.savePath || fileInfo.url
+            }
+
+            this.$message.success(`${file.name} 上传成功`)
+          } else {
+            throw new Error(uploadRes?.message || '上传失败,请稍后重试')
+          }
+        } catch (error) {
+          console.error('文件上传失败:', error)
+          this.$message.error(`文件上传失败:${error.message || '未知错误'}`)
+          if (onError) {
+            onError(error)
+          }
+        }
+      },
+
+      // 上传成功回调
+      handleFileUploadSuccess(response, file, fileList) {
+        // 更新文件列表,添加文件URL信息
+        this.workingPaperForm.fileList = fileList.map((item) => {
+          if (item.uid === file.uid && response) {
+            return {
+              ...item,
+              url: response.savePath || response.url || item.url,
+              response: response,
+            }
+          }
+          return item
+        })
+      },
+
+      // 上传进度回调
+      handleFileUploadProgress(event, file, fileList) {
+        // element-ui 会自动处理上传进度显示
+      },
+
+      // 上传失败回调
+      handleFileUploadError(err, file, fileList) {
+        console.error('文件上传错误:', err)
+        this.$message.error(`${file.name} 上传失败`)
+        // 从文件列表中移除失败的文件
+        this.workingPaperForm.fileList = fileList.filter(
+          (item) => item.uid !== file.uid
+        )
+      },
+
+      // 超出文件数量限制
+      handleFileExceed(files, fileList) {
+        this.$message.warning(
+          `当前限制选择 1 个文件,本次选择了 ${files.length} 个文件,共选择了 ${fileList.length} 个文件`
+        )
+      },
+
+      // 移除文件
+      handleFileRemove(file, fileList) {
+        this.workingPaperForm.fileList = fileList
+        this.workingPaperForm.attachmentUrl = ''
+        this.$message.info(`${file.name} 已移除`)
+      },
     },
   }
 </script>