Forráskód Böngészése

feat(costAudit): 完善监审文书管理功能

- 新增文书类型切换和高亮显示功能
-优化生成文书按钮权限控制逻辑
- 改进生成时间展示格式,分为日期和时间两行显示
- 统一附件上传和查看按钮的权限判断方式
- 移除签章功能相关代码
- 调整弹窗宽度和层级,提升用户体验- 完善表单验证规则和字段绑定
- 新增数据值可编辑功能,支持直接修改文书数据- 增强单位选择功能,支持单选和多选模式
- 补充文件上传和下载功能实现
- 优化文书模板参数设置界面布局
- 增加文书查看弹窗,支持预览和参数展示
- 完善企业单位数据过滤逻辑,支持多种ID格式- 修复分页查询和数据回显相关问题- 增加时间自动填充和附件上传功能
- 优化文件下载逻辑,支持多种文件格式处理
luzhixia 1 hónapja
szülő
commit
5bc482dabc

+ 33 - 31
package-lock.json

@@ -2161,25 +2161,6 @@
           "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
           "dev": true
         },
-        "json5": {
-          "version": "2.2.3",
-          "resolved": "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz",
-          "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
-          "dev": true,
-          "optional": true
-        },
-        "loader-utils": {
-          "version": "2.0.4",
-          "resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-2.0.4.tgz",
-          "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "big.js": "^5.2.2",
-            "emojis-list": "^3.0.0",
-            "json5": "^2.1.2"
-          }
-        },
         "ssri": {
           "version": "8.0.1",
           "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz",
@@ -2188,18 +2169,6 @@
           "requires": {
             "minipass": "^3.1.1"
           }
-        },
-        "vue-loader-v16": {
-          "version": "npm:vue-loader@16.8.3",
-          "resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-16.8.3.tgz",
-          "integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "chalk": "^4.1.0",
-            "hash-sum": "^2.0.0",
-            "loader-utils": "^2.0.0"
-          }
         }
       }
     },
@@ -19510,6 +19479,39 @@
         }
       }
     },
+    "vue-loader-v16": {
+      "version": "npm:vue-loader@16.8.3",
+      "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
+      "integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "chalk": "^4.1.0",
+        "hash-sum": "^2.0.0",
+        "loader-utils": "^2.0.0"
+      },
+      "dependencies": {
+        "json5": {
+          "version": "2.2.3",
+          "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+          "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+          "dev": true,
+          "optional": true
+        },
+        "loader-utils": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
+          "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "big.js": "^5.2.2",
+            "emojis-list": "^3.0.0",
+            "json5": "^2.1.2"
+          }
+        }
+      }
+    },
     "vue-pdf": {
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/vue-pdf/-/vue-pdf-4.2.0.tgz",

+ 7 - 8
public/config.js

@@ -2,11 +2,11 @@
 // 当前后端不在同一个服务器时,需要指定host地址
 // var host = 'http://10.7.13.26' // 以前
 // var host = 'http://116.204.117.33' //基本用这个
-//var host = 'http://116.204.117.33' // 测试
+var host = 'http://1.71.9.215' // 测试
 // var host = 'http://b463f4b7.natappfree.cc' // 后端服务海鹏
 // var host = 'http://5jrgep.ipx.wanziwk.cn' // 后端服务译文
-// var host = 'http://192.168.1.144' // 后端服务译文
-var host = 'http://5jrgep.ipx.wanziwk.cn'
+// var host = 'http://192.168.1.2' // 后端服务译文
+// var host = 'http://localhost'
 // combine为true时五合一部署, 为false时分五个服务部署
 var combine = true
 // var gateway = '8280/stage-api'
@@ -22,15 +22,14 @@ var defaultModulePortMap = {
 }
 window.getModuleRootUrl = function (module) {
   // 默认是全部服务合一的端口
-  //var modulePort = '8089' // 以前
-  //var modulePort = '9506' // 基本用这个
+  // var modulePort = '8089' // 以前
+  var modulePort = '9506' // 基本用这个
   // var modulePort = '8088' //测试
-  var modulePort = ''
+  // var modulePort = ''
   if (!combine) {
     modulePort = defaultModulePortMap[module]
   }
-  return "http://5jrgep.ipx.wanziwk.cn";
-  //return host + ':' + modulePort
+  return host + ':' + modulePort
   // return host + modulePort
 }
 window.context = {

+ 8 - 0
src/api/taskCustomizedRelease.js

@@ -237,6 +237,14 @@ export function updateScan(data) {
     data,
   })
 }
+// 更新反馈文件
+export function updateFeedback(data) {
+  return request({
+    url: `${url}/api/costProjectDocument/v1/feedback/document/url`,
+    method: 'post',
+    data,
+  })
+}
 // 根据id生成文书并且下载
 export function downDocument(params) {
   return request({

+ 2 - 2
src/components/costAudit/CostAuditDialog.vue

@@ -158,7 +158,7 @@
     },
     data() {
       return {
-        currentZIndex: null,
+        currentZIndex: 2000,
       }
     },
     computed: {
@@ -171,7 +171,7 @@
       },
       effectiveZIndex() {
         // 使用动态计算的zIndex优先,否则使用传入的zIndex
-        return this.currentZIndex || this.zIndex
+        return this.zIndex
       },
     },
     methods: {

+ 459 - 14
src/components/task/taskInfo.vue

@@ -277,31 +277,71 @@
                 </template>
               </el-table-column>
               <el-table-column
-                prop="name"
+                prop="documentName"
                 label="文书类型"
                 min-width="150"
                 align="center"
               ></el-table-column>
               <el-table-column
-                prop="province"
+                prop="documentNumber"
                 label="文书文号"
                 min-width="200"
                 align="center"
               ></el-table-column>
               <el-table-column
-                prop="city"
+                prop="generateTime"
                 label="推送时间"
                 min-width="180"
                 align="center"
               ></el-table-column>
               <el-table-column
-                prop="address"
-                label="文书状态"
+                prop="electronicDocumentUrl"
+                label="文书操作"
                 min-width="120"
                 align="center"
               >
                 <template slot-scope="scope">
-                  <span>{{ scope.row.address || '-' }}</span>
+                  <el-button
+                    type="text"
+                    size="mini"
+                    @click="handleDocView(scope.row)"
+                  >
+                    查看
+                  </el-button>
+                  <el-button
+                    type="text"
+                    size="mini"
+                    @click="handleDownloadDocument(scope.row)"
+                  >
+                    下载
+                  </el-button>
+                </template>
+              </el-table-column>
+              <el-table-column
+                prop="feedbackDocumentUrl"
+                label="向监审主体反馈文件"
+                min-width="120"
+                align="center"
+              >
+                <template slot-scope="scope">
+                  <!-- <el-button
+                    :disabled="isViewMode"
+                    type="text"
+                    size="mini"
+                    @click="handleUploadScan(scope.row, 'feedbackDocumentUrl')"
+                  >
+                    上传附件
+                  </el-button> -->
+                  <span>
+                    {{ scope.row.feedbackDocumentUrl ? '已回传' : '未回传' }}
+                  </span>
+                  <el-button
+                    type="text"
+                    size="mini"
+                    @click="handleViewFeedback(scope.row.feedbackDocumentUrl)"
+                  >
+                    查看附件
+                  </el-button>
                 </template>
               </el-table-column>
             </el-table>
@@ -705,6 +745,140 @@
         </el-tab-pane>
       </el-tabs>
     </div>
+    <!-- 查看监审通知书 -->
+    <CostAuditDialog
+      :title="documentDialogTitle"
+      :visible="documentDialogVisible"
+      width="82%"
+      :close-on-click-modal="false"
+      :z-index="8000"
+      @cancel="handleDocCancel"
+    >
+      <div class="document-edit-container">
+        <!-- 左侧:文书参数设置 -->
+        <div class="document-params">
+          <h4>文书参数设置:</h4>
+          <el-form
+            ref="documentForm"
+            :model="document"
+            label-width="170px"
+            size="small"
+            disabled
+          >
+            <el-form-item label="模板:" prop="documentId">
+              {{ document.documentName }}
+            </el-form-item>
+            <el-form-item label="通知书文号:" prop="documentNumber">
+              {{ document.documentNumber }}
+            </el-form-item>
+            <el-form-item label="被监审单位" prop="enterpriseId">
+              <div style="display: flex; align-items: center; gap: 15px">
+                <el-select
+                  v-model="document.enterpriseId"
+                  placeholder="请选择被监审单位"
+                  style="width: 100%"
+                  clearable
+                >
+                  <el-option
+                    v-for="item in unitList"
+                    :key="item.unitId"
+                    :label="item.unitName"
+                    :value="item.unitId"
+                  ></el-option>
+                </el-select>
+              </div>
+            </el-form-item>
+            <el-form-item label="是否推送被监审单位:" prop="isPushed">
+              <!-- 是否推送被监审单位 -->
+              <el-radio-group v-model="document.isPushed">
+                <el-radio label="1">是</el-radio>
+                <el-radio label="0">否</el-radio>
+              </el-radio-group>
+            </el-form-item>
+            <!-- 数据内容区域 -->
+            <div style="margin-top: 20px">
+              <h4 style="margin-bottom: 10px">数据内容:</h4>
+              <el-table
+                :data="costDocumentTemplateFiles"
+                style="
+                  width: 100%;
+                  border: 1px solid #dcdfe6;
+                  border-radius: 4px;
+                "
+              >
+                <el-table-column
+                  prop="originalText"
+                  label="数据项"
+                  width="120"
+                  align="center"
+                  show-overflow-tooltip
+                ></el-table-column>
+                <!-- <el-table-column
+                  prop="labelValue"
+                  label="标签"
+                  width="100"
+                  align="center"
+                  show-overflow-tooltip
+                ></el-table-column> -->
+                <el-table-column
+                  prop="originalText"
+                  label="描述"
+                  min-width="120"
+                  align="center"
+                  show-overflow-tooltip
+                ></el-table-column>
+                <el-table-column
+                  prop="dataValue"
+                  label="数据值"
+                  min-width="150"
+                  align="center"
+                  show-overflow-tooltip
+                >
+                  <template slot-scope="scope">
+                    <el-input
+                      v-if="scope.row.originalText !== '需要提供材料'"
+                      v-model="scope.row.dataValue"
+                      size="small"
+                      placeholder="请输入数据值"
+                      disabled
+                    ></el-input>
+                    <!-- 否则显示上传按钮 -->
+                    <div v-else>
+                      <!-- <el-button
+                      type="primary"
+                      size="small"
+                      @click="handleUploadClick(scope.row)"
+                    >
+                      上传附件
+                    </el-button> -->
+                      <el-button
+                        type="primary"
+                        size="small"
+                        @click="handleViewScan(scope.row.dataValue)"
+                      >
+                        查看附件
+                      </el-button>
+                    </div>
+                  </template>
+                </el-table-column>
+              </el-table>
+            </div>
+          </el-form>
+        </div>
+
+        <!-- 右侧:模板预览和编辑区 -->
+        <div class="document-preview">
+          <!-- 预览/修改标签页 -->
+          <TemplatePreviewEdit :active-tab="activeDocTab" :file-url="fileUrl" />
+        </div>
+      </div>
+    </CostAuditDialog>
+    <!-- 多附件查看弹窗 -->
+    <multi-attachment-dialog
+      :visible="dialogMultiVisible"
+      :attachments="attachments"
+      @close="dialogMultiVisible = false"
+    ></multi-attachment-dialog>
 
     <div slot="footer" class="dialog-footer">
       <el-button type="primary" @click="handleClose">关闭</el-button>
@@ -725,12 +899,24 @@
     sendMessage,
   } from '@/api/auditTaskProcessing'
   import { getSurveyList } from '@/api/audit/survey'
-
+  import {
+    getCostProjectDocumentPageList,
+    updateFeedback,
+    downDocument,
+  } from '@/api/taskCustomizedRelease.js'
+  import { getCostProjectDocumentFile } from '@/api/auditReviewDocManage.js'
+  import CostAuditDialog from '@/components/costAudit/CostAuditDialog.vue'
+  import TemplatePreviewEdit from '@/components/costAudit/TemplatePreviewEdit.vue'
+  import MultiAttachmentDialog from '@/components/costAudit/MultiAttachmentDialog'
+  import { uploadFile } from '@/api/file'
   export default {
     name: 'TaskInfo',
     components: {
       RegionSelector,
       CatalogCascader,
+      CostAuditDialog,
+      TemplatePreviewEdit,
+      MultiAttachmentDialog,
     },
     mixins: [dictMixin],
     props: {
@@ -771,6 +957,11 @@
           pageSize: 10,
           total: 0,
         },
+        auditDocumentPagination: {
+          page: 1,
+          pageSize: 10,
+          total: 0,
+        },
         unitList: [],
         OrgList: [],
         userList: [],
@@ -825,6 +1016,15 @@
         },
         showAuditOpinion: true,
         currentNode: '',
+        documentDialogVisible: false,
+        documentDialogTitle: '查看监审通知书',
+        dialogWidth: '80%',
+        fileUrl: '',
+        costDocumentTemplateFiles: [],
+        document: {},
+        activeDocTab: 'preview', // 当前标签页,preview:预览,edit:修改
+        dialogMultiVisible: false,
+        attachments: [],
       }
     },
     computed: {
@@ -1252,15 +1452,19 @@
       async loadAuditDocument() {
         try {
           this.loading = true
-          // TODO: 调用监审文书接口
-          // const res = await getAuditDocumentList(this.currentTaskInfo.taskId)
-          // if (res && res.code === 200) {
-          //   this.formData.auditDocument = res.value || []
-          // }
-
-          // 暂时使用mock数据
+          //调用监审文书接口
           this.formData.auditDocument = []
           this.tabLoadedStatus.auditDocument = true
+          getCostProjectDocumentPageList({
+            pageNum: this.auditDocumentPagination.page,
+            pageSize: this.auditDocumentPagination.pageSize,
+            projectId: this.currentTaskInfo.projectId,
+            documentName: '',
+            permissionType: 1,
+          }).then((res) => {
+            this.formData.auditDocument = res.value.value.records
+            this.auditDocumentPagination.total = res.value.value.total
+          })
         } catch (error) {
           console.error('加载监审文书失败:', error)
           // this.$message.error('加载监审文书失败')
@@ -1268,6 +1472,238 @@
           this.loading = false
         }
       },
+      handleTemplateChange() {
+        let data = this.documentData.documentTypes.find(
+          (item) => item.id === this.document.documentId
+        )
+        this.fileUrl = data.fileUrl
+      },
+      // 查看监审文书
+      handleDocView(row) {
+        this.document = {
+          ...row,
+        }
+        this.handleTemplateChange()
+        this.documentDialogVisible = true
+        getCostProjectDocumentFile({
+          id: row.id,
+        }).then((res) => {
+          this.costDocumentTemplateFiles = res.value || []
+        })
+      },
+      // 关闭监审文书查看弹窗
+      handleDocCancel() {
+        this.documentDialogVisible = false
+        // 重置相关数据状态,避免再次打开时显示上一次的数据
+        this.document = {}
+        this.fileUrl = ''
+        this.costDocumentTemplateFiles = []
+      },
+      // 查看文件
+      handleViewScan(fileUrl) {
+        if (!fileUrl) {
+          this.$message.error('暂无文件!')
+          return
+        }
+        // 对文件URL进行Base64编码
+        const encodedUrl = encodeURIComponent(
+          Base64.encode(window.context.form + fileUrl)
+        )
+
+        // 构建 kkFileView 预览URL
+        // onlinePreview - 在线预览
+        // onlinePreview?type=pdf - 强制使用PDF模式预览
+        window.open(`${host}:8012/onlinePreview?url=${encodedUrl}`)
+      },
+      // 查看反馈
+      handleViewFeedback(feedbackDocumentUrl) {
+        if (!feedbackDocumentUrl) {
+          this.$message.error('暂无文件!')
+          return
+        }
+        // 确保attachments是数组格式
+        if (feedbackDocumentUrl) {
+          if (typeof feedbackDocumentUrl === 'string') {
+            // 如果是逗号分隔的字符串,转换为数组
+            this.attachments = feedbackDocumentUrl.split(',')
+          } else {
+            // 其他情况,包装为数组
+            this.attachments = [feedbackDocumentUrl]
+          }
+        } else {
+          this.attachments = []
+        }
+        // 显示附件弹窗
+        this.dialogMultiVisible = true
+      },
+      // 上传文件
+      handleUploadScan(row, type) {
+        let loading = null
+        // 第一步:创建文件选择器
+        const input = document.createElement('input')
+        input.type = 'file'
+        input.accept = '.pdf,.doc,.docx,.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 = [
+              '.pdf',
+              '.doc',
+              '.docx',
+              '.xls',
+              '.xlsx',
+              '.csv',
+            ]
+            const fileName = file.name.toLowerCase()
+            const isValidFormat = allowedFormats.some((format) =>
+              fileName.endsWith(format)
+            )
+
+            if (!isValidFormat) {
+              this.$message.error(
+                '只允许上传.pdf,.doc,.docx,.xls,.xlsx,.csv格式的文件!'
+              )
+              return
+            }
+
+            // 显示遮罩层
+            loading = this.$baseLoading(1, '文件上传中...')
+
+            // 第三步:创建FormData并上传文件
+            const formData = new FormData()
+            formData.append('file', file)
+
+            // 先调用上传API
+            const uploadRes = await uploadFile('/api/file/v1/upload', formData)
+
+            // 第四步:检查上传结果
+            if (!uploadRes || !uploadRes.value) {
+              // this.$message.error('文件上传失败!');
+              return
+            }
+
+            // 第五步:文件上传成功后,再更新数据
+            const fileInfo = uploadRes.value
+            let feedbackDocumentUrl = row.feedbackDocumentUrl
+            if (feedbackDocumentUrl) {
+              feedbackDocumentUrl = feedbackDocumentUrl.split(',')
+              feedbackDocumentUrl.push(fileInfo?.savePath)
+              feedbackDocumentUrl = feedbackDocumentUrl.join(',')
+            } else {
+              feedbackDocumentUrl = fileInfo?.savePath
+            }
+            // 创建更新数据对象
+            const updateData = {
+              id: row.id,
+              feedbackDocumentUrl: feedbackDocumentUrl, // 更新扫描件URL
+            }
+
+            // 第六步:调用更新API
+            await updateFeedback(updateData)
+
+            // 第七步:更新成功,显示提示并刷新
+            this.$message.success('文件上传成功并更新数据!')
+            this.loadAuditDocument()
+          } catch (error) {
+            // 错误处理
+            this.$message.error('操作失败:' + (error.message || '未知错误'))
+            console.error('文件上传失败:', error)
+          } finally {
+            // 关闭遮罩层
+            loading.close()
+          }
+        }
+        // 触发文件选择
+        input.click()
+      },
+      // 下载文档
+      handleDownloadDocument(row) {
+        // 显示加载状态
+        this.$loading({
+          lock: true,
+          text: '文件下载中...',
+          spinner: 'el-icon-loading',
+          background: 'rgba(0, 0, 0, 0.7)',
+        })
+
+        // 从API中获取文件URL
+        downDocument({
+          id: row.id,
+        })
+          .then((res) => {
+            // 关闭加载状态
+            this.$loading().close()
+
+            // 检查返回结果是否成功
+            if (!res || !res.state) {
+              this.$message.error(
+                `下载失败:${res?.message || '未获取到文件数据'}`
+              )
+              return
+            }
+
+            // 获取文件URL
+            const fileUrl = res.value
+            if (!fileUrl) {
+              this.$message.error('下载失败:未获取到文件URL')
+              return
+            }
+
+            // 优先从URL中提取文件名
+            let fileName = ''
+
+            // 从URL中提取文件名
+            const urlParts = fileUrl.split('/')
+            let urlFileName = urlParts[urlParts.length - 1]
+
+            // 处理URL可能包含查询参数的情况
+            if (urlFileName.includes('?')) {
+              urlFileName = urlFileName.split('?')[0]
+            }
+
+            // 检查从URL提取的文件名是否有效
+            if (urlFileName && /\.[a-zA-Z0-9]+$/.test(urlFileName)) {
+              fileName = urlFileName
+            } else {
+              // URL中无法提取有效文件名时,使用row.documentName作为备选
+              fileName =
+                row.documentName ||
+                `${row.documentName}_${new Date().getTime()}`
+
+              // 确保备选文件名有扩展名
+              if (!/\.[a-zA-Z0-9]+$/.test(fileName)) {
+                fileName += '.pdf'
+              }
+            }
+            // 创建隐藏的a标签进行下载
+            const link = document.createElement('a')
+            link.style.display = 'none'
+            link.href = fileUrl
+            // link.href = window.context.form + row.electronicDocumentUrl
+            // 设置下载文件名
+            link.download = fileName
+            document.body.appendChild(link)
+            link.click()
+            document.body.removeChild(link)
+          })
+          .catch((error) => {
+            // 关闭加载状态
+            this.$loading().close()
+            console.error('获取文件URL失败:', error)
+          })
+      },
+
       // 加载报送资料
       async loadDataRequirements() {
         if (!this.currentTaskInfo?.taskId) {
@@ -1639,4 +2075,13 @@
     text-align: center;
     padding-top: 10px;
   }
+  .document-edit-container {
+    display: flex;
+    .document-params {
+      width: 55%;
+    }
+    .document-preview {
+      width: 45%;
+    }
+  }
 </style>

+ 439 - 25
src/views/EntDeclaration/auditTaskManagement/components/AuditDocumentTab.vue

@@ -4,87 +4,231 @@
       <strong>说明:</strong>
       被监审单位接收《送达回证》后需签名并反馈监审主体。
     </div>
-    <el-table style="width: 100%; margin-top: 20px" border :data="formData">
-      <el-table-column prop="id" label="序号" width="120" align="center">
+    <el-table style="width: 100%" border :data="formData" size="small">
+      <el-table-column prop="id" label="序号" width="80" align="center">
         <template slot-scope="scope">
           {{ scope.$index + 1 }}
         </template>
       </el-table-column>
       <el-table-column
-        prop="name"
+        prop="documentName"
         label="文书类型"
         min-width="150"
         align="center"
       ></el-table-column>
       <el-table-column
-        prop="province"
+        prop="documentNumber"
         label="文书文号"
-        min-width="230"
+        min-width="200"
         align="center"
       ></el-table-column>
       <el-table-column
-        prop="city"
+        prop="generateTime"
         label="推送时间"
-        min-width="230"
+        min-width="180"
         align="center"
       ></el-table-column>
       <el-table-column
-        prop="address"
+        prop="electronicDocumentUrl"
         label="文书操作"
-        min-width="150"
+        min-width="120"
         align="center"
       >
         <template slot-scope="scope">
-          <el-button
-            type="text"
-            size="small"
-            :disabled="isViewMode"
-            @click="$emit('handle-click', scope.row)"
-          >
+          <el-button type="text" size="mini" @click="handleDocView(scope.row)">
             查看
           </el-button>
           <el-button
             type="text"
-            size="small"
-            :disabled="isViewMode"
-            @click="$emit('handle-download', scope.row)"
+            size="mini"
+            @click="handleDownloadDocument(scope.row)"
           >
             下载
           </el-button>
         </template>
       </el-table-column>
       <el-table-column
-        prop="zip"
+        prop="feedbackDocumentUrl"
         label="向监审主体反馈文件"
-        min-width="200"
+        min-width="120"
         align="center"
       >
         <template slot-scope="scope">
+          <span>
+            {{ scope.row.feedbackDocumentUrl ? '已回传' : '未回传' }}
+          </span>
           <el-button
             type="text"
-            size="small"
+            size="mini"
             :disabled="isViewMode"
-            @click="$emit('handle-upload', scope.row)"
+            @click="handleUploadScan(scope.row, 'feedbackDocumentUrl')"
           >
             上传附件
           </el-button>
           <el-button
             type="text"
-            size="small"
-            :disabled="isViewMode"
-            @click="$emit('handle-click', scope.row)"
+            size="mini"
+            @click="handleViewFeedback(scope.row.feedbackDocumentUrl)"
           >
             查看附件
           </el-button>
         </template>
       </el-table-column>
     </el-table>
+    <!-- 查看监审通知书 -->
+    <CostAuditDialog
+      :title="documentDialogTitle"
+      :visible="documentDialogVisible"
+      width="82%"
+      :close-on-click-modal="false"
+      :z-index="9100"
+      @cancel="handleDocCancel"
+    >
+      <div class="document-edit-container">
+        <!-- 左侧:文书参数设置 -->
+        <div class="document-params">
+          <h4>文书参数设置:</h4>
+          <el-form
+            ref="documentForm"
+            :model="document"
+            label-width="170px"
+            size="small"
+            disabled
+          >
+            <el-form-item label="模板:" prop="documentId">
+              {{ document.documentName }}
+            </el-form-item>
+            <el-form-item label="通知书文号:" prop="documentNumber">
+              {{ document.documentNumber }}
+            </el-form-item>
+            <el-form-item label="被监审单位" prop="enterpriseId">
+              <div style="display: flex; align-items: center; gap: 15px">
+                <el-select
+                  v-model="document.enterpriseId"
+                  placeholder="请选择被监审单位"
+                  style="width: 100%"
+                  clearable
+                >
+                  <el-option
+                    v-for="item in unitList"
+                    :key="item.unitId"
+                    :label="item.unitName"
+                    :value="item.unitId"
+                  ></el-option>
+                </el-select>
+              </div>
+            </el-form-item>
+            <el-form-item label="是否推送被监审单位:" prop="isPushed">
+              <!-- 是否推送被监审单位 -->
+              <el-radio-group v-model="document.isPushed">
+                <el-radio label="1">是</el-radio>
+                <el-radio label="0">否</el-radio>
+              </el-radio-group>
+            </el-form-item>
+            <!-- 数据内容区域 -->
+            <div style="margin-top: 20px">
+              <h4 style="margin-bottom: 10px">数据内容:</h4>
+              <el-table
+                :data="costDocumentTemplateFiles"
+                style="
+                  width: 100%;
+                  border: 1px solid #dcdfe6;
+                  border-radius: 4px;
+                "
+              >
+                <el-table-column
+                  prop="originalText"
+                  label="数据项"
+                  width="120"
+                  align="center"
+                  show-overflow-tooltip
+                ></el-table-column>
+                <!-- <el-table-column
+                  prop="labelValue"
+                  label="标签"
+                  width="100"
+                  align="center"
+                  show-overflow-tooltip
+                ></el-table-column> -->
+                <el-table-column
+                  prop="originalText"
+                  label="描述"
+                  min-width="120"
+                  align="center"
+                  show-overflow-tooltip
+                ></el-table-column>
+                <el-table-column
+                  prop="dataValue"
+                  label="数据值"
+                  min-width="150"
+                  align="center"
+                  show-overflow-tooltip
+                >
+                  <template slot-scope="scope">
+                    <el-input
+                      v-if="scope.row.originalText !== '需要提供材料'"
+                      v-model="scope.row.dataValue"
+                      size="small"
+                      placeholder="请输入数据值"
+                      disabled
+                    ></el-input>
+                    <!-- 否则显示上传按钮 -->
+                    <div v-else>
+                      <!-- <el-button
+                        type="text"
+                        size="small"
+                        @click="handleUploadClick(scope.row)"
+                      >
+                        上传附件
+                      </el-button> -->
+                      <el-button
+                        type="text"
+                        size="small"
+                        :disabled="false"
+                        @click="handleViewScan(scope.row.dataValue)"
+                      >
+                        查看附件
+                      </el-button>
+                    </div>
+                  </template>
+                </el-table-column>
+              </el-table>
+            </div>
+          </el-form>
+        </div>
+
+        <!-- 右侧:模板预览和编辑区 -->
+        <div class="document-preview">
+          <!-- 预览/修改标签页 -->
+          <TemplatePreviewEdit :active-tab="activeDocTab" :file-url="fileUrl" />
+        </div>
+      </div>
+    </CostAuditDialog>
+    <!-- 多附件查看弹窗 -->
+    <multi-attachment-dialog
+      :visible="dialogMultiVisible"
+      :attachments="attachments"
+      @close="dialogMultiVisible = false"
+    ></multi-attachment-dialog>
   </div>
 </template>
 
 <script>
+  import { updateFeedback, downDocument } from '@/api/taskCustomizedRelease.js'
+  import { getCostProjectDocumentFile } from '@/api/auditReviewDocManage.js'
+  import CostAuditDialog from '@/components/costAudit/CostAuditDialog.vue'
+  import TemplatePreviewEdit from '@/components/costAudit/TemplatePreviewEdit.vue'
+  import MultiAttachmentDialog from '@/components/costAudit/MultiAttachmentDialog'
+  import { uploadFile } from '@/api/file'
+  import { getAllUnitList } from '@/api/auditEntityManage'
   export default {
     name: 'AuditDocumentTab',
+    components: {
+      CostAuditDialog,
+      TemplatePreviewEdit,
+      MultiAttachmentDialog,
+    },
+
     props: {
       formData: {
         type: Array,
@@ -95,5 +239,275 @@
         default: false,
       },
     },
+    data() {
+      return {
+        documentDialogVisible: false,
+        documentDialogTitle: '查看监审通知书',
+        dialogWidth: '80%',
+        fileUrl: '',
+        costDocumentTemplateFiles: [],
+        document: {},
+        activeDocTab: 'preview', // 当前标签页,preview:预览,edit:修改
+        dialogMultiVisible: false,
+        attachments: [],
+        unitList: [],
+      }
+    },
+    mounted() {
+      // this.$emit('refresh')
+      this.getAllUnitList()
+    },
+    methods: {
+      // 获取所有单位列表
+      getAllUnitList() {
+        getAllUnitList()
+          .then((res) => {
+            this.unitList = res.value || []
+          })
+          .catch(() => {})
+      },
+      handleTemplateChange() {
+        let data = this.documentData.documentTypes.find(
+          (item) => item.id === this.document.documentId
+        )
+        this.fileUrl = data.fileUrl
+      },
+      // 查看监审文书
+      handleDocView(row) {
+        this.document = {
+          ...row,
+        }
+        this.handleTemplateChange()
+        this.documentDialogVisible = true
+        getCostProjectDocumentFile({
+          id: row.id,
+        }).then((res) => {
+          this.costDocumentTemplateFiles = res.value || []
+        })
+      },
+      // 查看文件
+      handleViewScan(fileUrl) {
+        if (!fileUrl) {
+          this.$message.error('暂无文件!')
+          return
+        }
+        // 对文件URL进行Base64编码
+        const encodedUrl = encodeURIComponent(
+          Base64.encode(window.context.form + fileUrl)
+        )
+
+        // 构建 kkFileView 预览URL
+        // onlinePreview - 在线预览
+        // onlinePreview?type=pdf - 强制使用PDF模式预览
+        window.open(`${host}:8012/onlinePreview?url=${encodedUrl}`)
+      },
+      // 查看反馈
+      handleViewFeedback(feedbackDocumentUrl) {
+        if (!feedbackDocumentUrl) {
+          this.$message.error('暂无文件!')
+          return
+        }
+        // 确保attachments是数组格式
+        if (feedbackDocumentUrl) {
+          if (typeof feedbackDocumentUrl === 'string') {
+            // 如果是逗号分隔的字符串,转换为数组
+            this.attachments = feedbackDocumentUrl.split(',')
+          } else {
+            // 其他情况,包装为数组
+            this.attachments = [feedbackDocumentUrl]
+          }
+        } else {
+          this.attachments = []
+        }
+        // 显示附件弹窗
+        this.dialogMultiVisible = true
+      },
+      // 上传文件
+      handleUploadScan(row, type) {
+        let loading = null
+        // 第一步:创建文件选择器
+        const input = document.createElement('input')
+        input.type = 'file'
+        input.accept = '.pdf,.doc,.docx,.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 = [
+              '.pdf',
+              '.doc',
+              '.docx',
+              '.xls',
+              '.xlsx',
+              '.csv',
+            ]
+            const fileName = file.name.toLowerCase()
+            const isValidFormat = allowedFormats.some((format) =>
+              fileName.endsWith(format)
+            )
+
+            if (!isValidFormat) {
+              this.$message.error(
+                '只允许上传.pdf,.doc,.docx,.xls,.xlsx,.csv格式的文件!'
+              )
+              return
+            }
+
+            // 显示遮罩层
+            loading = this.$baseLoading(1, '文件上传中...')
+
+            // 第三步:创建FormData并上传文件
+            const formData = new FormData()
+            formData.append('file', file)
+
+            // 先调用上传API
+            const uploadRes = await uploadFile('/api/file/v1/upload', formData)
+
+            // 第四步:检查上传结果
+            if (!uploadRes || !uploadRes.value) {
+              // this.$message.error('文件上传失败!');
+              return
+            }
+
+            // 第五步:文件上传成功后,再更新数据
+            const fileInfo = uploadRes.value
+            let feedbackDocumentUrl = row.feedbackDocumentUrl
+            if (feedbackDocumentUrl) {
+              feedbackDocumentUrl = feedbackDocumentUrl.split(',')
+              feedbackDocumentUrl.push(fileInfo?.savePath)
+              feedbackDocumentUrl = feedbackDocumentUrl.join(',')
+            } else {
+              feedbackDocumentUrl = fileInfo?.savePath
+            }
+            // 创建更新数据对象
+            const updateData = {
+              id: row.id,
+              feedbackDocumentUrl: feedbackDocumentUrl, // 更新扫描件URL
+            }
+
+            // 第六步:调用更新API
+            await updateFeedback(updateData)
+
+            // 第七步:更新成功,显示提示并刷新
+            this.$message.success('文件上传成功并更新数据!')
+            this.$emit('refresh')
+          } catch (error) {
+            // 错误处理
+            this.$message.error('操作失败:' + (error.message || '未知错误'))
+            console.error('文件上传失败:', error)
+          } finally {
+            // 关闭遮罩层
+            loading.close()
+          }
+        }
+        // 触发文件选择
+        input.click()
+      },
+      // 下载文档
+      handleDownloadDocument(row) {
+        // 显示加载状态
+        this.$loading({
+          lock: true,
+          text: '文件下载中...',
+          spinner: 'el-icon-loading',
+          background: 'rgba(0, 0, 0, 0.7)',
+        })
+
+        // 从API中获取文件URL
+        downDocument({
+          id: row.id,
+        })
+          .then((res) => {
+            // 关闭加载状态
+            this.$loading().close()
+
+            // 检查返回结果是否成功
+            if (!res || !res.state) {
+              this.$message.error(
+                `下载失败:${res?.message || '未获取到文件数据'}`
+              )
+              return
+            }
+
+            // 获取文件URL
+            const fileUrl = res.value
+            if (!fileUrl) {
+              this.$message.error('下载失败:未获取到文件URL')
+              return
+            }
+
+            // 优先从URL中提取文件名
+            let fileName = ''
+
+            // 从URL中提取文件名
+            const urlParts = fileUrl.split('/')
+            let urlFileName = urlParts[urlParts.length - 1]
+
+            // 处理URL可能包含查询参数的情况
+            if (urlFileName.includes('?')) {
+              urlFileName = urlFileName.split('?')[0]
+            }
+
+            // 检查从URL提取的文件名是否有效
+            if (urlFileName && /\.[a-zA-Z0-9]+$/.test(urlFileName)) {
+              fileName = urlFileName
+            } else {
+              // URL中无法提取有效文件名时,使用row.documentName作为备选
+              fileName =
+                row.documentName ||
+                `${row.documentName}_${new Date().getTime()}`
+
+              // 确保备选文件名有扩展名
+              if (!/\.[a-zA-Z0-9]+$/.test(fileName)) {
+                fileName += '.pdf'
+              }
+            }
+            // 创建隐藏的a标签进行下载
+            const link = document.createElement('a')
+            link.style.display = 'none'
+            link.href = fileUrl
+            // link.href = window.context.form + row.electronicDocumentUrl
+            // 设置下载文件名
+            link.download = fileName
+            document.body.appendChild(link)
+            link.click()
+            document.body.removeChild(link)
+          })
+          .catch((error) => {
+            // 关闭加载状态
+            this.$loading().close()
+            console.error('获取文件URL失败:', error)
+          })
+      },
+      // 关闭监审文书查看弹窗
+      handleDocCancel() {
+        this.documentDialogVisible = false
+        // 重置相关数据状态,避免再次打开时显示上一次的数据
+        this.document = {}
+        this.fileUrl = ''
+        this.costDocumentTemplateFiles = []
+      },
+    },
   }
 </script>
+<style scoped lang="scss">
+  .document-edit-container {
+    display: flex;
+    .document-params {
+      width: 55%;
+    }
+    .document-preview {
+      width: 45%;
+    }
+  }
+</style>

+ 34 - 28
src/views/EntDeclaration/auditTaskManagement/taskFillIn.vue

@@ -69,6 +69,7 @@
               @handleClick="handleClick"
               @handleDownload="handleDownload"
               @handleUpload="handleUpload"
+              @refresh="getAuditDocumentList"
             />
           </el-tab-pane>
 
@@ -344,7 +345,7 @@
   import CostAuditDialog from '@/components/costAudit/CostAuditDialog'
   import CostAuditTable from '@/components/costAudit/CostAuditTable.vue'
   import { allcurrentCostSurveyList } from '@/api/financeSheetManage'
-
+  import { getCostProjectDocumentPageList } from '@/api/taskCustomizedRelease.js'
   export default {
     name: 'TaskFillIn',
     components: {
@@ -442,6 +443,11 @@
           pageSize: 10,
           total: 0,
         },
+        auditDocumentPagination: {
+          page: 1,
+          pageSize: 10,
+          total: 0,
+        },
         // 所有表单数据聚合
         formData: {
           basicInfo: {
@@ -468,24 +474,7 @@
             plannedAuditStartDate: '',
             plannedAuditEndDate: '',
           },
-          auditDocument: [
-            {
-              date: '2016-05-02',
-              name: '王小虎',
-              province: '上海',
-              city: '普陀区',
-              address: '上海市普陀区金沙江路 1518 弄',
-              zip: 200333,
-            },
-            {
-              date: '2016-05-04',
-              name: '王小虎',
-              province: '上海',
-              city: '普陀区',
-              address: '上海市普陀区金沙江路 1517 弄',
-              zip: 200333,
-            },
-          ],
+          auditDocument: [],
           dataRequirements: [],
           costSurveyData: [
             {
@@ -1119,6 +1108,9 @@
               }
             })
           })
+        } else if (tab.name === 'auditDocument') {
+          // 监审文件
+          this.getAuditDocumentList()
         }
         // 其他标签页(如 auditDocument、costSurvey)如果不需要异步加载数据,则不需要设置加载状态
 
@@ -1468,16 +1460,21 @@
         console.log(data)
         this.formData.basicInfo.projectName = data.label
       },
-
-      // 查看文书
-      handleClick(row) {
-        console.log(row)
-        if (row.fileUrl) {
-          window.open(row.fileUrl, '_blank')
-        } else {
-          this.$message.warning('暂无文件可查看')
-        }
+      // 获取监审文书
+      getAuditDocumentList() {
+        getCostProjectDocumentPageList({
+          pageNum: this.auditDocumentPagination.page,
+          pageSize: this.auditDocumentPagination.pageSize,
+          projectId: this.projectId,
+          documentName: '',
+          permissionType: 1,
+        }).then((res) => {
+          this.formData.auditDocument = res.value.value.records
+          this.auditDocumentPagination.total = res.value.value.total
+        })
       },
+      handleClick(row) {},
+
       // 下载文书
       handleDownload(row) {
         console.log(row)
@@ -2373,4 +2370,13 @@
   ::v-deep .el-drawer__body {
     padding: 0;
   }
+  .document-edit-container {
+    display: flex;
+    .document-params {
+      width: 55%;
+    }
+    .document-preview {
+      width: 45%;
+    }
+  }
 </style>

+ 669 - 170
src/views/costAudit/auditInfo/auditManage/auditDocumentsMain.vue

@@ -8,6 +8,8 @@
           v-for="type in documentData.documentTypes"
           :key="type.id"
           class="type-item"
+          :class="{ active: activeDocumentTypeId === type.id }"
+          @click="handleDocumentTypeClick(type)"
         >
           {{ type.documentName }}
         </div>
@@ -17,10 +19,10 @@
       <div class="documents-content">
         <div class="operation-bar">
           <el-button
+            v-if="!isView"
             plain
             type="success"
             icon="el-icon-circle-plus"
-            :disabled="isView"
             @click="handleGenerateDocument"
           >
             生成文书
@@ -41,11 +43,19 @@
           <template #enterpriseId="{ row }">
             {{ getEnterpriseName(row) }}
           </template>
+          <template #generateTime="{ row }">
+            <div>
+              {{ row.generateTime ? row.generateTime.split(' ')[0] : '' }}
+            </div>
+            <div>
+              {{ row.generateTime ? row.generateTime.split(' ')[1] : '' }}
+            </div>
+          </template>
           <template #scanDocumentUrl="scope">
             <el-button
+              v-if="!isView"
               type="text"
               size="mini"
-              :disabled="isView"
               @click="handleUploadScan(scope.row, 'scanDocumentUrl')"
             >
               上传附件
@@ -53,9 +63,7 @@
             <el-button
               type="text"
               size="mini"
-              @click="
-                handleViewScan(scope.row.scanDocumentUrl, 'scanDocumentUrl')
-              "
+              @click="handleViewScan(scope.row.scanDocumentUrl)"
             >
               查看附件
             </el-button>
@@ -72,37 +80,32 @@
             <el-button
               type="text"
               size="mini"
-              @click="
-                handleViewScan(
-                  scope.row.feedbackDocumentUrl,
-                  'feedbackDocumentUrl'
-                )
-              "
+              @click="handleViewScan(scope.row.feedbackDocumentUrl)"
             >
               查看附件
             </el-button>
           </template>
           <template #electronicDocumentUrl="scope">
             <el-button
+              v-if="!isView"
               type="text"
               size="mini"
-              :disabled="isView"
               @click="handleEditDocument(scope.row)"
             >
               修改
             </el-button>
-            <el-button
+            <!-- <el-button
+              v-if="!isView"
               type="text"
               size="mini"
-              :disabled="isView"
               @click="handleSignDocument(scope.row)"
             >
               签章
-            </el-button>
+            </el-button> -->
             <el-button
+              v-if="!isView"
               type="text"
               size="mini"
-              :disabled="isView"
               @click="handleDeleteDocument(scope.row)"
             >
               删除
@@ -126,8 +129,9 @@
     <CostAuditDialog
       :title="documentDialogTitle"
       :visible="documentDialogVisible"
-      :width="dialogWidth"
+      width="82%"
       :close-on-click-modal="false"
+      :z-index="9100"
       @cancel="handleCancel"
       @confirm="handleConfirm"
     >
@@ -136,12 +140,14 @@
         <div class="document-params">
           <h4>文书参数设置:</h4>
           <el-form
+            ref="documentForm"
             v-loading="loading.saveDocument"
             :model="document"
-            label-width="160px"
+            label-width="170px"
             size="small"
+            :rules="documentRules"
           >
-            <el-form-item label="选择模板:">
+            <el-form-item label="选择模板:" prop="documentId">
               <el-select
                 v-model="document.documentId"
                 placeholder="请选择模板"
@@ -156,11 +162,12 @@
                 ></el-option>
               </el-select>
             </el-form-item>
-            <el-form-item label="通知书文号:" prop="documentWhId">
+            <el-form-item label="通知书文号:" prop="documentNumber">
               <el-input
                 v-model="document.documentNumber"
                 placeholder="请选择通知书文号"
                 style="width: 74%"
+                disabled
               ></el-input>
               <!-- disabled -->
               <el-button
@@ -172,25 +179,28 @@
                 选择文号
               </el-button>
             </el-form-item>
-            <el-form-item label="被监审单位:">
-              <el-select
-                v-model="document.enterpriseId"
-                placeholder="请选择被监审单位"
-                style="width: 100%"
-                clearable
-                multiple
-              >
-                <el-option
-                  v-for="item in allUnits"
-                  :key="item.unitId"
-                  :label="item.unitName"
-                  :value="item.unitId"
-                ></el-option>
-              </el-select>
+            <el-form-item label="被监审单位" prop="enterpriseId">
+              <div style="display: flex; align-items: center; gap: 15px">
+                <el-select
+                  v-model="document.enterpriseId"
+                  placeholder="请选择被监审单位"
+                  style="width: 100%"
+                  clearable
+                  :multiple="isMultipleMode"
+                  @change="handleEnterpriseChange"
+                >
+                  <el-option
+                    v-for="item in allUnits"
+                    :key="item.unitId"
+                    :label="item.unitName"
+                    :value="item.unitId"
+                  ></el-option>
+                </el-select>
+              </div>
             </el-form-item>
-            <el-form-item label="是否推送被监审单位:">
+            <el-form-item label="是否推送被监审单位:" prop="isPushed">
               <!-- 是否推送被监审单位 -->
-              <el-radio-group v-model="document.isPush">
+              <el-radio-group v-model="document.isPushed">
                 <el-radio label="1">是</el-radio>
                 <el-radio label="0">否</el-radio>
               </el-radio-group>
@@ -227,28 +237,58 @@
                   label="数据项"
                   width="120"
                   align="center"
+                  show-overflow-tooltip
                 ></el-table-column>
-                <el-table-column
-                  prop="label"
+                <!-- <el-table-column
+                  prop="labelValue"
                   label="标签"
                   width="100"
                   align="center"
-                ></el-table-column>
+                  show-overflow-tooltip
+                ></el-table-column> -->
                 <el-table-column
                   prop="originalText"
                   label="描述"
                   min-width="120"
-                  align="left"
+                  align="center"
+                  show-overflow-tooltip
                 ></el-table-column>
                 <el-table-column
                   prop="dataValue"
                   label="数据值"
                   min-width="150"
-                  align="left"
-                ></el-table-column>
+                  align="center"
+                  show-overflow-tooltip
+                >
+                  <template slot-scope="scope">
+                    <el-input
+                      v-if="scope.row.originalText !== '需要提供材料'"
+                      v-model="scope.row.dataValue"
+                      size="small"
+                      placeholder="请输入数据值"
+                    ></el-input>
+                    <!-- 否则显示上传按钮 -->
+                    <div v-else>
+                      <el-button
+                        type="text"
+                        size="small"
+                        @click="handleUploadClick(scope.row)"
+                      >
+                        上传附件
+                      </el-button>
+                      <el-button
+                        type="text"
+                        size="small"
+                        @click="handleViewScan(scope.row.dataValue)"
+                      >
+                        查看附件
+                      </el-button>
+                    </div>
+                  </template>
+                </el-table-column>
               </el-table>
               <div style="margin-top: 10px; font-size: 12px; color: #909399">
-                说明:数据内容不可修改,已在监审文书管理中配置完成,数据值为本次监审项目的相关数据。
+                说明:数据内容可以在此处直接修改,修改后的数据将用于生成监审文书
               </div>
             </div>
           </el-form>
@@ -266,6 +306,7 @@
       :visible="dialogVisible"
       :width="dialogWidth"
       :close-on-click-modal="false"
+      :z-index="9200"
       @cancel="handleCancel"
       @confirm="handleConfirm"
     >
@@ -288,20 +329,24 @@
   </div>
 </template>
 <script>
-  // import { taskMixin } from './index.js'
   import CostAuditTable from '@/components/costAudit/CostAuditTable.vue'
   import CostAuditDialog from '@/components/costAudit/CostAuditDialog.vue'
   import TemplatePreviewEdit from '@/components/costAudit/TemplatePreviewEdit.vue'
   import { getAllUnitList } from '@/api/auditEntityManage'
   import {
-    getWhCateList,
-    queryByDocumentId,
+    getDocList,
+    getCostProjectDocumentFile,
+    queryByDocumentIdandWhereValue,
   } from '@/api/auditReviewDocManage.js'
   import { getData } from '@/api/auditDocNoManage.js'
   import {
     addCostProjectDocument,
     updateCostProjectDocument,
     deleteCostProjectDocument,
+    getCostProjectDocumentDetail,
+    updateScan,
+    downDocument,
+    getCostProjectDocumentPageList,
   } from '@/api/taskCustomizedRelease.js'
   import { dictMixin, regionMixin } from '@/mixins/useDict'
   import { uploadFile } from '@/api/file'
@@ -314,32 +359,46 @@
         type: Object,
         default: () => {},
       },
+      id: {
+        type: String,
+        default: '',
+      },
       isView: {
         type: Boolean,
         default: false,
       },
-      documentData: {
-        type: Object,
-        default: () => ({
-          documentTypes: [],
-          list: [],
-          pagination: {},
-          dataList: [],
-          documentColumns: [],
-        }),
-      },
     },
     data() {
       return {
+        isMultipleMode: false,
         dictData: {
           whGenerateType: [],
         },
+        activeDocumentTypeId: '',
         document: {
+          createBy: '',
+          createTime: '',
+          documentAlias: '',
           documentId: '',
-          documentWhId: '',
+          documentName: '',
           documentNumber: '',
+          documentType: '',
+          documentWhId: '',
+          electronicDocumentUrl: '',
           enterpriseId: [],
-          dataList: [],
+          feedbackDocumentUrl: '',
+          feedbackTime: '',
+          generateTime: '',
+          id: '',
+          isDeleted: '',
+          isPushed: '',
+          orderNum: 0,
+          pkVal: '',
+          projectId: '',
+          pushTime: '',
+          scanDocumentUrl: '',
+          updateBy: '',
+          updateTime: '',
         },
         loading: {
           saveDocument: false,
@@ -351,8 +410,8 @@
         dialogVisible: false,
         dialogTitle: '选择文号',
         documentDialogVisible: false,
-        documentDialogTitle: '编辑监审通知书',
-        dialogWidth: '70%',
+        documentDialogTitle: '添加监审通知书',
+        dialogWidth: '80%',
         fileUrl: '',
         selectDocumentWhData: [],
         selectDocumentWhPagination: {
@@ -362,6 +421,103 @@
         },
         selectDocumentWhSelection: [],
         costDocumentTemplateFiles: [],
+        documentData: {
+          documentTypes: [],
+          selectedDoc: 'notice',
+          list: [],
+          pagination: {
+            currentPage: 1,
+            pageSize: 10,
+            total: 0,
+          },
+          documentColumns: [
+            {
+              prop: 'documentId',
+              label: '文书类型',
+              align: 'center',
+              slotName: 'documentId',
+            },
+            {
+              prop: 'documentNumber',
+              label: '文书文号',
+              width: 200,
+              align: 'center',
+            },
+            {
+              prop: 'enterpriseId',
+              label: '被监审单位',
+              width: 200,
+              align: 'left',
+              slotName: 'enterpriseId',
+            },
+            {
+              prop: 'generateTime',
+              label: '生成时间',
+              width: 100,
+              align: 'center',
+              slotName: 'generateTime',
+            },
+            {
+              prop: 'electronicDocumentUrl',
+              label: '电子文书',
+              width: 200,
+              align: 'center',
+              slotName: 'electronicDocumentUrl',
+            },
+            {
+              prop: 'scanDocumentUrl',
+              label: '上传扫描件',
+              width: 150,
+              align: 'center',
+              slotName: 'scanDocumentUrl',
+            },
+            {
+              prop: 'isPushed',
+              label: '是否推送被监审单位',
+              width: 100,
+              align: 'center',
+              formatter: (row) => (row.isPushed == 1 ? '是' : '否'),
+            },
+            {
+              prop: 'feedbackDocumentUrl',
+              label: '被监审单位反馈资料',
+              width: 150,
+              align: 'center',
+              slotName: 'feedbackDocumentUrl',
+            },
+          ],
+        },
+        documentRules: {
+          // documentNumber: [
+          //   {
+          //     required: true,
+          //     message: '请选择通知书文号',
+          //     trigger: 'change',
+          //   },
+          // ],
+          enterpriseId: [
+            {
+              required: true,
+              message: '请选择被监审单位',
+              trigger: 'change',
+            },
+          ],
+          documentId: [
+            {
+              required: true,
+              message: '请选择模板',
+              trigger: 'change',
+            },
+          ],
+          isPushed: [
+            {
+              required: true,
+              message: '请选择否推送被监审单位',
+              trigger: 'change',
+            },
+          ],
+        },
+        dataUploadUrl: [],
       }
     },
     computed: {
@@ -405,23 +561,76 @@
         ]
       },
     },
-    // 添加watch监听project变化,确保项目数据更新时重新加载数据
     watch: {
-      project: {
+      id: {
         handler(newVal) {
-          if (newVal && newVal.projectId) {
-            // 通知父组件需要加载数据
-            this.$emit('refresh', newVal.projectId)
+          if (newVal) {
+            this.getData()
           }
         },
         deep: true,
         immediate: true,
       },
+      costDocumentTemplateFiles: {
+        handler(newVal, oldVal) {
+          if (newVal.length > 0) {
+            console.log(this.costDocumentTemplateFiles)
+            this.costDocumentTemplateFiles.forEach((item) => {
+              if (
+                item.pinyin.includes('ShiJian') &&
+                (item.dataValue == null || item.dataValue == '')
+              ) {
+                // 获取当前时间,格式为YYYY-MM-DD HH:mm:ss
+                let date = new Date()
+                let year = date.getFullYear()
+                let month = String(date.getMonth() + 1).padStart(2, '0')
+                let day = String(date.getDate()).padStart(2, '0')
+                let hours = String(date.getHours()).padStart(2, '0')
+                let minutes = String(date.getMinutes()).padStart(2, '0')
+                let seconds = String(date.getSeconds()).padStart(2, '0')
+                item.dataValue = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
+              }
+              if (
+                item.originalText.includes('需要提供材料') &&
+                item.dataValue
+              ) {
+                this.dataUploadUrl = item.dataValue
+              }
+            })
+          }
+        },
+        deep: true,
+      },
     },
     mounted() {
+      this.getData()
       this.loadOpts()
     },
     methods: {
+      // 获取监审通知数据
+      async getData() {
+        const res = await getDocList({
+          page: 1,
+          pageSize: 50,
+        })
+        this.documentData.documentTypes = res.value.records || []
+        const pid = this.project.projectId
+        if (!pid) return
+        this.getlist()
+      },
+      getlist() {
+        getCostProjectDocumentPageList({
+          pageNum: this.documentData.pagination.currentPage,
+          pageSize: this.documentData.pagination.pageSize,
+          projectId: this.project.projectId,
+          documentName: '',
+          permissionType: '0',
+        }).then((res) => {
+          this.documentData.list = res.value.value.records
+          this.documentData.pagination.total = res.value.value.total
+          console.log(this.documentData.list)
+        })
+      },
       getEnterpriseName(row) {
         // 处理enterpriseId,无论是数组还是逗号分隔的字符串
         let enterpriseIds = []
@@ -455,7 +664,9 @@
         )?.documentName
       },
       handlePaginationChange({ currentPage, pageSize }) {
-        this.$emit('paginationChange', { currentPage, pageSize })
+        this.documentData.pagination.currentPage = currentPage
+        this.documentData.pagination.pageSize = pageSize
+        this.getlist()
       },
 
       // 加载选项数据
@@ -465,20 +676,87 @@
           this.allUnits = res.value || []
           // 过滤掉状态为停用的数据
           this.allUnits = this.allUnits.filter((item) => item.status == 1)
+          // 筛选this.project.auditedUnitId中的单位,支持多种格式
+          if (this.project.auditedUnitId) {
+            // 确保将project.auditedUnitId转换为数组格式
+            let auditedUnitIds = []
+            if (Array.isArray(this.project.auditedUnitId)) {
+              auditedUnitIds = this.project.auditedUnitId
+            } else if (
+              typeof this.project.auditedUnitId === 'string' &&
+              this.project.auditedUnitId.includes(',')
+            ) {
+              // 如果是逗号分隔的字符串,转换为数组
+              auditedUnitIds = this.project.auditedUnitId
+                .split(',')
+                .map((id) => id.trim())
+            } else {
+              // 单个ID也转换为数组
+              auditedUnitIds = [this.project.auditedUnitId]
+            }
+            // 使用数组进行筛选
+            this.allUnits = this.allUnits.filter((item) =>
+              auditedUnitIds.includes(item.unitId)
+            )
+          }
         })
       },
 
       // 生成文书
       handleGenerateDocument() {
+        this.documentDialogTitle = '添加监审通知书'
         this.documentDialogVisible = true
         this.activeView = 'form'
+        this.costDocumentTemplateFiles = []
         this.document = {
+          createBy: '',
+          createTime: '',
+          documentAlias: '',
           documentId: '',
-          documentWhId: '',
+          documentName: '',
           documentNumber: '',
-          enterpriseId: [],
+          documentType: '',
+          documentWhId: '',
+          electronicDocumentUrl: '',
+          enterpriseId: this.isMultipleMode ? [] : '',
+          feedbackDocumentUrl: '',
+          feedbackTime: '',
+          generateTime: '',
+          id: '',
+          isDeleted: '',
+          isPushed: '1',
+          orderNum: this.documentData.list.length + 1,
+          pkVal: '',
+          projectId: '',
+          pushTime: '',
+          scanDocumentUrl: '',
+          updateBy: '',
+          updateTime: '',
+        }
+        // if(this.isMultipleMode){
+        //   this.document.enterpriseId = this.project.auditedUnitId ? this.project.auditedUnitId.split(',') : []
+        //   console.log('this.document.enterpriseId',this.document.enterpriseId)
+        // }else{
+        //   this.document.enterpriseId = this.project.auditedUnitId
+        // }
+        this.loadOpts()
+        if (this.activeDocumentTypeId) {
+          this.document.documentId = this.activeDocumentTypeId
+          this.handleTemplateChange()
         }
-        this.costProjectDocumentFiles = []
+      },
+      getDetail() {
+        getCostProjectDocumentDetail({
+          projectId: this.project.projectId,
+        }).then((res) => {
+          if (res.value) {
+            this.document = {
+              ...this.document,
+              ...res.value,
+            }
+            this.loadOpts()
+          }
+        })
       },
       selectClick() {
         this.dialogVisible = true
@@ -487,12 +765,16 @@
       },
       getWhListData() {
         getData({
-          pageNum: this.selectDocumentWhPagination.currentPage,
+          page: this.selectDocumentWhPagination.currentPage,
           pageSize: this.selectDocumentWhPagination.pageSize,
           whType: this.document.documentId,
         }).then((res) => {
-          this.selectDocumentWhData = res.value.records || []
-          this.selectDocumentWhPagination.total = res.value.total || 0
+          this.selectDocumentWhData = res.rows || []
+          this.selectDocumentWhPagination.total = res.total || 0
+          // 获取区域名称,填充regionNameMap
+          if (this.selectDocumentWhData.length > 0) {
+            this.fetchRegionNames(this.selectDocumentWhData, 'areaCode')
+          }
         })
       },
       selectDocumentWhPaginationChange({ currentPage, pageSize }) {
@@ -507,19 +789,30 @@
           this.selectDocumentWhSelection = selection
         }
       },
-      // 选择文档类型
-      selectDocumentType(doc) {
-        // this.documentData.selectedDoc = doc.value
-      },
       handleTemplateChange() {
-        this.fileUrl = this.documentData.documentTypes.find(
+        let data = this.documentData.documentTypes.find(
           (item) => item.id === this.document.documentId
-        ).fileUrl
-        this.getDocumentData(this.document.documentId)
+        )
+        this.fileUrl = data.fileUrl
+        this.document.documentName = data.documentName
+        this.document.documentNumber = ''
+        this.document.documentWhId = ''
+        this.getDocumentData()
       },
-      getDocumentData(documentId) {
-        if (documentId) {
-          queryByDocumentId({ documentId }).then((res) => {
+      getDocumentData() {
+        if (this.document.id === null || this.document.id === '') {
+          queryByDocumentIdandWhereValue({
+            documentId: this.document.documentId,
+            whereValue: this.project.projectId,
+          }).then((res) => {
+            this.costDocumentTemplateFiles = res.value || []
+          })
+        } else {
+          getCostProjectDocumentFile({
+            // documentId: this.document.documentId,
+            // whereValue: this.project.projectId,
+            id: this.document.id,
+          }).then((res) => {
             this.costDocumentTemplateFiles = res.value || []
           })
         }
@@ -541,84 +834,100 @@
           this.$message.error('请选择一个文号!')
           return
         }
+        // 获取选中的文号信息
+        const selectedDocument = this.selectDocumentWhSelection[0]
 
-        this.document.documentNumber = this.selectDocumentWhSelection[0].whNo
-        this.document.documentWhId = this.selectDocumentWhSelection[0].id // 假设这是正确的字段名
+        this.document.documentNumber = selectedDocument.whNo
+        this.document.documentWhId = selectedDocument.id
+        // 数据表格回显文号
+        this.costDocumentTemplateFiles.forEach((item) => {
+          if (
+            item.pinyin.includes('WenHao') ||
+            item.pinyin.includes('WenJianHao')
+          ) {
+            item.dataValue = selectedDocument.whNo
+          }
+          if (item.pinyin.includes('SongDaWenShuMingCheng')) {
+            item.dataValue = selectedDocument.whName
+          }
+        })
         this.dialogVisible = false
         this.activeView = 'form'
       },
+      handleEnterpriseChange(val) {
+        if (this.document.enterpriseId) {
+          // BeiJianShenDanWei
+          let unit = this.allUnits.find(
+            (item) => item.unitId === this.document.enterpriseId
+          )
+          this.costDocumentTemplateFiles.forEach((item) => {
+            if (item.pinyin.includes('BeiJianShenDanWei')) {
+              item.dataValue = unit.unitName
+            }
+            if (item.pinyin.includes('ShouSongDaRen')) {
+              item.dataValue = unit.contactName
+            }
+            if (item.pinyin.includes('BeiJianShenDanWeiBanGongDiDian')) {
+              item.dataValue = unit.address
+            }
+            if (item.pinyin.includes('BeiJianShenDanWeiLianXiRenDianHua')) {
+              item.dataValue = unit.contactMobile
+            }
+          })
+        }
+      },
       // 保存文档
       handleSaveDocument() {
-        // 验证是否选择了企业
-        if (
-          !this.document.enterpriseId ||
-          this.document.enterpriseId.length === 0
-        ) {
-          this.$message.error('请至少选择一个被监审单位!')
-          return
-        }
-
-        this.loading.saveDocument = true
-        if (this.document.id) {
-          updateCostProjectDocument({
-            id: this.document.id,
-            // documentAlias: this.document.documentAlias,
-            documentId: this.document.documentId,
-            documentNumber: this.document.documentNumber,
-            documentWhId: this.document.documentWhId,
-            costProjectDocumentFiles: this.costProjectDocumentFiles || [],
-            // isPushed: this.document.isPushed,
-            projectId: this.project.projectId,
-            // electronicDocumentUrl: '',
-            enterpriseId: this.document.enterpriseId.join(','), // 保存时转换为逗号分隔的字符串
-            // feedbackDocumentUrl: '',
-            // feedbackTime: '',
-            // generateTime: '',
-          })
-            .then((res) => {
-              this.loading.saveDocument = false
-              this.$message.success('保存成功!')
-              this.documentDialogVisible = false
-              this.activeView = ''
-              this.$emit('refresh', this.project.projectId)
-            })
-            .catch((err) => {
-              this.loading.saveDocument = false
-            })
-        } else {
-          // 处理多选逻辑,如果选择了多个单位,为每个单位创建一个文档记录
-          const promises = this.document.enterpriseId.map((enterpriseId) => {
-            return addCostProjectDocument({
-              // documentAlias: this.document.documentAlias,
+        // 校验表单
+        this.$refs.documentForm.validate((valid) => {
+          if (!valid) {
+            this.$message.error('请填写必填项!')
+            return false
+          }
+          this.loading.saveDocument = true
+          if (this.document.id) {
+            updateCostProjectDocument({
+              ...this.document,
+              costProjectDocumentFiles: this.costDocumentTemplateFiles,
               projectId: this.project.projectId,
-              documentId: this.document.documentId,
-              documentNumber: this.document.documentNumber,
-              documentWhId: this.document.documentWhId,
-              costProjectDocumentFiles: this.costProjectDocumentFiles || [],
-              enterpriseId: enterpriseId,
-              // electronicDocumentUrl: '',
-              // feedbackDocumentUrl: '',
-              // feedbackTime: '',
-              // generateTime: '',
-              isPushed: this.document.isPushed,
-              // orderNum: 0,
-              // pushTime: '',
-              // scanDocumentUrl: '',
-            })
-          })
-
-          Promise.all(promises)
-            .then(() => {
-              this.loading.saveDocument = false
-              this.$message.success('保存成功!')
-              this.dialogVisible = false
-              this.activeView = ''
-              this.$emit('refresh', this.project.projectId)
+              electronicDocumentUrl:
+                this.document.electronicDocumentUrl || this.fileUrl,
+              enterpriseId: this.isMultipleMode
+                ? this.document.enterpriseId.join(',')
+                : this.document.enterpriseId, // 保存时转换为逗号分隔的字符串
             })
-            .catch((err) => {
-              this.loading.saveDocument = false
+              .then((res) => {
+                this.loading.saveDocument = false
+                this.$message.success('保存成功!')
+                this.documentDialogVisible = false
+                this.activeView = ''
+                this.getlist()
+              })
+              .catch((err) => {
+                this.loading.saveDocument = false
+              })
+          } else {
+            addCostProjectDocument({
+              ...this.document,
+              projectId: this.project.projectId,
+              costProjectDocumentFiles: this.costDocumentTemplateFiles || [],
+              enterpriseId: this.isMultipleMode
+                ? this.document.enterpriseId.join(',')
+                : this.document.enterpriseId,
+              electronicDocumentUrl: this.fileUrl,
             })
-        }
+              .then(() => {
+                this.loading.saveDocument = false
+                this.$message.success('保存成功!')
+                this.documentDialogVisible = false
+                this.activeView = ''
+                this.getlist()
+              })
+              .catch((err) => {
+                this.loading.saveDocument = false
+              })
+          }
+        })
       },
       // 处理取消
       handleCancel() {
@@ -691,18 +1000,17 @@
             const fileInfo = uploadRes.value
             // 创建更新数据对象
             const updateData = {
-              ...row,
+              id: row.id,
               scanDocumentUrl: fileInfo?.savePath, // 更新扫描件URL
             }
 
             // 第六步:调用更新API
-            await updateCostProjectDocument(updateData)
+            await updateScan(updateData)
 
             // 第七步:更新成功,显示提示并刷新
             this.$message.success('文件上传成功并更新数据!')
-            this.$emit('refresh', this.project.projectId) // 通知父组件刷新
+            this.getlist()
           } catch (error) {
-            console.error('操作失败:' + (error.message || '未知错误'))
             // 错误处理
             // this.$message.error('操作失败:' + (error.message || '未知错误'))
           } finally {
@@ -714,7 +1022,7 @@
         input.click()
       },
       // 查看扫描件
-      handleViewScan(fileUrl, type) {
+      handleViewScan(fileUrl) {
         if (!fileUrl) {
           this.$message.error('暂无文件!')
           return
@@ -731,28 +1039,29 @@
       },
       // 编辑文档
       handleEditDocument(row) {
+        this.documentDialogTitle = '修改监审通知书'
         this.documentDialogVisible = true
         this.activeView = 'form'
         this.loadOpts()
         // 确保enterpriseId是数组格式,处理可能的逗号分隔字符串
-        const enterpriseId = row.enterpriseId
-          ? Array.isArray(row.enterpriseId)
-            ? row.enterpriseId
-            : typeof row.enterpriseId === 'string'
-            ? row.enterpriseId
-                .split(',')
-                .map((id) => id.trim())
-                .filter((id) => id) // 将逗号分隔字符串转换为数组
-            : [row.enterpriseId]
-          : []
+        const enterpriseId = this.isMultipleMode
+          ? row.enterpriseId.split(',')
+          : row.enterpriseId
         this.document = {
           ...row,
+          documentId: Number(row.documentId),
           enterpriseId,
+          // 确保isPushed有值,如果row中没有,设置默认值'1'
+          isPushed: row.isPushed !== undefined ? row.isPushed : '1',
         }
+        this.fileUrl = this.document.electronicDocumentUrl
+        this.getDocumentData()
       },
 
       // 签章
-      handleSignDocument(row) {},
+      handleSignDocument(row) {
+        this.$message.warning('签章功能待实现!')
+      },
 
       // 删除文档
       handleDeleteDocument(row) {
@@ -763,13 +1072,203 @@
         }).then(() => {
           deleteCostProjectDocument(row.id).then((res) => {
             this.$message.success('删除成功!')
-            this.$emit('refresh', this.project.projectId)
+            this.getlist()
           })
         })
       },
 
+      handleDownloadDocument1(row) {
+        // 显示加载状态
+        this.$loading({
+          lock: true,
+          text: '文件下载中...',
+          spinner: 'el-icon-loading',
+          background: 'rgba(0, 0, 0, 0.7)',
+        })
+        let fileUrl = window.context.form + row.electronicDocumentUrl
+        let fileName = ''
+        // 从URL中提取文件名
+        const urlParts = fileUrl.split('/')
+        let urlFileName = urlParts[urlParts.length - 1]
+
+        // 处理URL可能包含查询参数的情况
+        if (urlFileName.includes('?')) {
+          urlFileName = urlFileName.split('?')[0]
+        }
+
+        // 检查从URL提取的文件名是否有效
+        if (urlFileName && /\.[a-zA-Z0-9]+$/.test(urlFileName)) {
+          fileName = urlFileName
+        } else {
+          // URL中无法提取有效文件名时,使用row.documentName作为备选
+          fileName = row.documentName || `监审通知书_${new Date().getTime()}`
+
+          // 确保备选文件名有扩展名
+          if (!/\.[a-zA-Z0-9]+$/.test(fileName)) {
+            fileName += '.pdf'
+          }
+        }
+        // 创建隐藏的a标签进行下载
+        const link = document.createElement('a')
+        link.style.display = 'none'
+        link.href = fileUrl
+        // 设置下载文件名
+        link.download = fileName
+        document.body.appendChild(link)
+        link.click()
+        document.body.removeChild(link)
+        // 关闭加载状态
+        this.$loading().close()
+      },
       // 下载文档
-      handleDownloadDocument(row) {},
+      handleDownloadDocument(row) {
+        // 显示加载状态
+        this.$loading({
+          lock: true,
+          text: '文件下载中...',
+          spinner: 'el-icon-loading',
+          background: 'rgba(0, 0, 0, 0.7)',
+        })
+
+        // 从API中获取文件URL
+        downDocument({
+          id: row.id,
+        })
+          .then((res) => {
+            // 关闭加载状态
+            this.$loading().close()
+
+            // 检查返回结果是否成功
+            if (!res || !res.state) {
+              this.$message.error(
+                `下载失败:${res?.message || '未获取到文件数据'}`
+              )
+              return
+            }
+
+            // 获取文件URL
+            const fileUrl = res.value
+            if (!fileUrl) {
+              this.$message.error('下载失败:未获取到文件URL')
+              return
+            }
+
+            // 优先从URL中提取文件名
+            let fileName = ''
+
+            // 从URL中提取文件名
+            const urlParts = fileUrl.split('/')
+            let urlFileName = urlParts[urlParts.length - 1]
+
+            // 处理URL可能包含查询参数的情况
+            if (urlFileName.includes('?')) {
+              urlFileName = urlFileName.split('?')[0]
+            }
+
+            // 检查从URL提取的文件名是否有效
+            if (urlFileName && /\.[a-zA-Z0-9]+$/.test(urlFileName)) {
+              fileName = urlFileName
+            } else {
+              // URL中无法提取有效文件名时,使用row.documentName作为备选
+              fileName =
+                row.documentName || `监审通知书_${new Date().getTime()}`
+
+              // 确保备选文件名有扩展名
+              if (!/\.[a-zA-Z0-9]+$/.test(fileName)) {
+                fileName += '.pdf'
+              }
+            }
+            // 创建隐藏的a标签进行下载
+            const link = document.createElement('a')
+            link.style.display = 'none'
+            link.href = fileUrl
+            // link.href = window.context.form + row.electronicDocumentUrl
+            // 设置下载文件名
+            link.download = fileName
+            document.body.appendChild(link)
+            link.click()
+            document.body.removeChild(link)
+          })
+          .catch((error) => {
+            // 关闭加载状态
+            this.$loading().close()
+            console.error('获取文件URL失败:', error)
+          })
+      },
+      handleUploadClick(row) {
+        console.log('handleUploadClick', row)
+        let loading = null
+        // 第一步:创建文件选择器
+        const input = document.createElement('input')
+        input.type = 'file'
+        input.accept = '.pdf,.doc,.docx,.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 = [
+              '.pdf',
+              '.doc',
+              '.docx',
+              '.xls',
+              '.xlsx',
+              'csv',
+            ]
+            const fileName = file.name.toLowerCase()
+            const isValidFormat = allowedFormats.some((format) =>
+              fileName.endsWith(format)
+            )
+
+            if (!isValidFormat) {
+              this.$message.error(
+                '只允许上传.pdf,.doc,.docx,.xls,.xlsx,.csv格式的文件!'
+              )
+              return
+            }
+
+            // 显示遮罩层
+            loading = this.$baseLoading(1, '文件上传中...')
+
+            // 第三步:创建FormData并上传文件
+            const formData = new FormData()
+            formData.append('file', file)
+
+            // 先调用上传API
+            const uploadRes = await uploadFile('/api/file/v1/upload', formData)
+
+            // 第四步:检查上传结果
+            if (!uploadRes || !uploadRes.value) {
+              // this.$message.error('文件上传失败!');
+              return
+            }
+
+            // 第五步:文件上传成功后,再更新数据
+            const fileInfo = uploadRes.value
+            this.costDocumentTemplateFiles.find(
+              (item) => item.originalText === row.originalText
+            ).dataValue = fileInfo.savePath
+            this.$message.success('文件上传成功!')
+          } catch (error) {
+            console.error('文件上传失败:', error)
+          } finally {
+            // 关闭遮罩层
+            loading.close()
+          }
+        }
+
+        // 触发文件选择对话框显示
+        input.click()
+      },
     },
   }
 </script>

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

@@ -184,6 +184,7 @@
     <mainDetailsDialog
       :id="selectedProject && selectedProject.id"
       ref="mainDetailsRef"
+      :project="selectedProject"
       :visible.sync="mainDetailsVisible"
       :current-node="selectedProject && selectedProject.currentNode"
       :current-status="selectedProject && selectedProject.status"

+ 17 - 7
src/views/costAudit/auditInfo/auditManage/mainDetails.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="details-container">
     <el-drawer
-      :visible.sync="visible"
+      :visible.sync="drawerVisible"
       :title="dialogTitle"
       size="90%"
       @close="handleClose"
@@ -24,6 +24,7 @@
         <el-tab-pane label="监审文书" name="submitData">
           <auditDocumentsMain
             :id="id"
+            :project="project"
             :current-node="currentNode"
             :current-status="currentStatus"
           />
@@ -122,6 +123,10 @@
         type: Boolean,
         default: true,
       },
+      project: {
+        type: Object,
+        default: () => {},
+      },
       id: {
         type: [String, Number],
         default: null,
@@ -147,6 +152,7 @@
       return {
         buttonData: [], //资料初审按钮数据
         activeTab: 'submitData', // 默认选中报送资料标签页
+        drawerVisible: this.visible, // 本地变量控制drawer显示状态
         // 弹窗显示状态
         showSupplementDialog: false,
         showAbortDialog: false,
@@ -211,7 +217,9 @@
     },
     watch: {
       visible(newVal) {
-        // 监听visible变化,弹窗打开时设置标签页并获取按钮数据
+        // 监听visible prop变化,更新本地drawerVisible变量
+        this.drawerVisible = newVal
+        // 弹窗打开时设置标签页并获取按钮数据
         if (newVal && this.id) {
           // 使用 $nextTick 确保 props 已更新
           this.$nextTick(() => {
@@ -224,7 +232,7 @@
       },
       // 监听currentNode变化,如果弹窗已打开,更新标签页并重新获取按钮数据
       currentNode(newVal, oldVal) {
-        if (this.visible && this.id && newVal && newVal !== oldVal) {
+        if (this.drawerVisible && this.id && newVal && newVal !== oldVal) {
           this.$nextTick(() => {
             // 设置标签页
             this.setActiveTab()
@@ -235,7 +243,7 @@
       },
       // 监听currentStatus变化,如果弹窗已打开,更新标签页并重新获取按钮数据
       currentStatus(newVal, oldVal) {
-        if (this.visible && this.id && newVal && newVal !== oldVal) {
+        if (this.drawerVisible && this.id && newVal && newVal !== oldVal) {
           this.$nextTick(() => {
             // 设置标签页
             this.setActiveTab()
@@ -246,7 +254,7 @@
       },
       // 监听id变化,如果弹窗已打开,重新获取按钮数据
       id(newVal) {
-        if (this.visible && newVal) {
+        if (this.drawerVisible && newVal) {
           this.$nextTick(() => {
             // 设置标签页
             this.setActiveTab()
@@ -260,7 +268,7 @@
       // 设置标签页
       this.setActiveTab()
       // 如果组件挂载时弹窗已打开且有id,也要获取按钮数据
-      if (this.visible && this.id) {
+      if (this.drawerVisible && this.id) {
         this.$nextTick(() => {
           // 弹窗打开时,无论什么情况都要获取资料初审按钮数据
           this.getPreliminaryReviewButton()
@@ -293,7 +301,8 @@
         }
       },
       handleClose() {
-        // 关闭弹窗时触发事件
+        // 关闭弹窗时更新本地状态并触发事件
+        this.drawerVisible = false
         this.$emit('update:visible', false)
         this.$emit('close')
       },
@@ -304,6 +313,7 @@
       },
       open() {
         // 打开弹窗方法,供父组件通过ref调用
+        this.drawerVisible = true
         this.$emit('update:visible', true)
       },
       // 处理结论保存成功

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

@@ -269,14 +269,14 @@
                     <!-- 否则显示上传按钮 -->
                     <div v-else>
                       <el-button
-                        type="primary"
+                        type="text"
                         size="small"
                         @click="handleUploadClick(scope.row)"
                       >
                         上传附件
                       </el-button>
                       <el-button
-                        type="primary"
+                        type="text"
                         size="small"
                         @click="handleViewScan(scope.row.dataValue)"
                       >
@@ -337,12 +337,13 @@
     queryByDocumentIdandWhereValue,
   } from '@/api/auditReviewDocManage.js'
   import { getData } from '@/api/auditDocNoManage.js'
-  import { updateScan, downDocument } from '@/api/taskCustomizedRelease.js'
   import {
     addCostProjectDocument,
     updateCostProjectDocument,
     deleteCostProjectDocument,
     getCostProjectDocumentDetail,
+    updateScan,
+    downDocument,
   } from '@/api/taskCustomizedRelease.js'
   import { dictMixin, regionMixin } from '@/mixins/useDict'
   import { uploadFile } from '@/api/file'

+ 7 - 3
src/views/costAudit/projectInfo/auditTaskManage/taskCustomizedRelease/index.js

@@ -9,7 +9,7 @@ import {
 } from '@/api/taskCustomizedRelease.js'
 import { getAllUserList } from '@/api/uc'
 import { getCostSurveyTemplates } from '@/api/catalogManage.js'
-import { getWhCateList } from '@/api/auditReviewDocManage.js'
+import { getWhCateList, getDocList } from '@/api/auditReviewDocManage.js'
 // 引入地区选择混入
 import {
   dictMixin,
@@ -458,8 +458,7 @@ export const taskMixin = {
           // this.getSurveyData()
           break
         case 'auditNotice':
-          const res = await getWhCateList()
-          this.documentData.documentTypes = res.value || []
+          // const res = await getWhCateList()
           this.getDocumentData()
           break
         case 'workflow':
@@ -546,6 +545,11 @@ export const taskMixin = {
     },
     // 获取监审通知数据
     async getDocumentData(data) {
+      const res = await getDocList({
+        page: 1,
+        pageSize: 50,
+      })
+      this.documentData.documentTypes = res.value.records || []
       const pid =
         (this.project && (this.project.projectId || this.project.id)) ||
         (this.taskData && (this.taskData.projectId || this.taskData.id)) ||

+ 1 - 1
src/views/costAudit/projectInfo/auditTaskManage/taskCustomizedRelease/tabs.vue

@@ -144,7 +144,7 @@
           <auditNoticeTab
             ref="auditNoticeTab"
             :project="project"
-            :is-view="isView"
+            :is-view="false"
             :document-data="documentData"
             @refresh="getDocumentData"
             @paginationChange="handlePaginationChange"