From 3db6b38e2e30325ea2035a0ef08822b05a547036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wei=5F=E4=BD=B3?= Date: Mon, 24 Nov 2025 17:19:52 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E8=AF=81=E4=B9=A6?= =?UTF-8?q?=E5=92=8C=E6=8A=A5=E5=91=8A=E6=96=87=E4=BB=B6=E7=9A=84=E5=AE=9E?= =?UTF-8?q?=E9=99=85=E4=B8=8A=E4=BC=A0=E5=8A=9F=E8=83=BD=EF=BC=8C=E5=B9=B6?= =?UTF-8?q?=E5=9C=A8=E5=AE=A1=E6=A0=B8=E8=AF=A6=E6=83=85=E9=A1=B5=E4=B8=AD?= =?UTF-8?q?=E9=9B=86=E6=88=90=E4=B8=8A=E4=BC=A0=E5=90=8E=E7=9A=84=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=9B=B4=E6=96=B0=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../audit/components/AuditDetail.vue | 39 ++++- .../audit/components/CertificateModal.vue | 160 +++++++++++------- 2 files changed, 132 insertions(+), 67 deletions(-) diff --git a/web/src/views/valuation/audit/components/AuditDetail.vue b/web/src/views/valuation/audit/components/AuditDetail.vue index 6abe9ae..31f334d 100644 --- a/web/src/views/valuation/audit/components/AuditDetail.vue +++ b/web/src/views/valuation/audit/components/AuditDetail.vue @@ -14,6 +14,8 @@ import { import { formatDate } from '@/utils' import TheIcon from '@/components/icon/TheIcon.vue' import CertificateModal from './CertificateModal.vue' +import api from '@/api' +import { useMessage } from 'naive-ui' import { getStatusConfig } from '../constants' import { @@ -34,6 +36,7 @@ const props = defineProps({ }) const emit = defineEmits(['back', 'approve', 'reject']) +const $message = useMessage() const activeDetailTab = ref('audit') @@ -313,11 +316,39 @@ const handleViewCertificate = () => { certificateModalVisible.value = true } -const handleCertificateConfirm = (data) => { +const handleCertificateConfirm = async (data) => { console.log('证书数据:', data) - // 这里可以调用 API 保存证书数据 - $message?.success('证书上传成功') - certificateModalVisible.value = false + + try { + const certificateUrl = data.certificateFiles?.map(f => f.url).filter(Boolean) || [] + const reportUrl = data.reportFiles?.map(f => f.url).filter(Boolean) || [] + + if (!certificateUrl.length) { + $message.warning('请上传证书') + return + } + + if (!reportUrl.length) { + $message.warning('请上传报告') + return + } + + const payload = { + ...props.detailData, + certificate_url: certificateUrl, + report_url: reportUrl, + status: 'success' + } + + await api.updateValuation(payload) + + $message.success('上传并通知成功') + certificateModalVisible.value = false + emit('back') // 或者 emit('refresh') 取决于需求,这里假设返回列表或刷新 + } catch (error) { + console.error('更新失败:', error) + $message.error('操作失败') + } } diff --git a/web/src/views/valuation/audit/components/CertificateModal.vue b/web/src/views/valuation/audit/components/CertificateModal.vue index 668b6c9..348a26c 100644 --- a/web/src/views/valuation/audit/components/CertificateModal.vue +++ b/web/src/views/valuation/audit/components/CertificateModal.vue @@ -7,11 +7,14 @@ import { NUpload, NText, NImage, - NImageGroup + NImageGroup, + useMessage } from 'naive-ui' // 临时移除图标导入以解决模块解析问题 // import { DownloadIcon } from '@vicons/tabler' +import { getToken } from '@/utils/auth/token' + const props = defineProps({ visible: { type: Boolean, @@ -28,6 +31,7 @@ const props = defineProps({ }) const emit = defineEmits(['update:visible', 'confirm']) +const message = useMessage() const formData = ref({ reportFiles: [], @@ -37,6 +41,11 @@ const formData = ref({ const reportFileList = ref([]) const certificateFileList = ref([]) +const uploadUrl = `${import.meta.env.VITE_BASE_API}/upload/file` +const uploadHeaders = computed(() => ({ + Authorization: `Bearer ${getToken()}`, +})) + // 监听弹窗打开,初始化数据 watch( () => props.visible, @@ -82,56 +91,104 @@ const beforeUpload = (data) => { const isVideo = file.type.startsWith('video/') if (!isImage && !isPdf && !isWord && !isVideo) { - $message.error('只能上传图片、PDF、Word文档或视频文件') + message.error('只能上传图片、PDF、Word文档或视频文件') return false } const isLt50M = file.size / 1024 / 1024 < 50 if (!isLt50M) { - $message.error('文件大小不能超过50MB') + message.error('文件大小不能超过50MB') return false } return true } -// 报告文件上传变化 -const handleReportUploadChange = ({ fileList: newFileList }) => { - reportFileList.value = newFileList - formData.value.reportFiles = newFileList.map(file => ({ - id: file.id, - name: file.name, - url: file.url, - type: file.type - })) +// 报告上传完成 +const handleReportUploadFinish = ({ file, event }) => { + try { + const res = JSON.parse(event.target.response) + if (res.code === 200 && res.data?.url) { + const targetFile = reportFileList.value.find(f => f.id === file.id) || file + targetFile.url = res.data.url + targetFile.name = res.data.filename || targetFile.name + targetFile.status = 'finished' + + formData.value.reportFiles = reportFileList.value.map(f => ({ + id: f.id, + name: f.name, + url: f.url, + type: f.type + })) + message.success('报告上传成功') + } else { + message.error(res.message || '上传失败') + const index = reportFileList.value.findIndex((item) => item.id === file.id) + if (index > -1) reportFileList.value.splice(index, 1) + } + } catch (error) { + console.error('上传响应解析失败:', error) + message.error('上传失败:服务器响应异常') + const index = reportFileList.value.findIndex((item) => item.id === file.id) + if (index > -1) reportFileList.value.splice(index, 1) + } + return file } -// 证书文件上传变化 -const handleCertificateUploadChange = ({ fileList: newFileList }) => { - certificateFileList.value = newFileList - formData.value.certificateFiles = newFileList.map(file => ({ - id: file.id, - name: file.name, - url: file.url, - type: file.type - })) +// 证书上传完成 +const handleCertificateUploadFinish = ({ file, event }) => { + try { + const res = JSON.parse(event.target.response) + if (res.code === 200 && res.data?.url) { + const targetFile = certificateFileList.value.find(f => f.id === file.id) || file + targetFile.url = res.data.url + targetFile.name = res.data.filename || targetFile.name + targetFile.status = 'finished' + + formData.value.certificateFiles = certificateFileList.value.map(f => ({ + id: f.id, + name: f.name, + url: f.url, + type: f.type + })) + message.success('证书上传成功') + } else { + message.error(res.message || '上传失败') + const index = certificateFileList.value.findIndex((item) => item.id === file.id) + if (index > -1) certificateFileList.value.splice(index, 1) + } + } catch (error) { + console.error('上传响应解析失败:', error) + message.error('上传失败:服务器响应异常') + const index = certificateFileList.value.findIndex((item) => item.id === file.id) + if (index > -1) certificateFileList.value.splice(index, 1) + } + return file } // 移除文件 const handleRemove = () => { + // 更新 formData + formData.value.reportFiles = reportFileList.value.map(f => ({ + id: f.id, + name: f.name, + url: f.url, + type: f.type + })) + formData.value.certificateFiles = certificateFileList.value.map(f => ({ + id: f.id, + name: f.name, + url: f.url, + type: f.type + })) return true } -// 移除证书文件 -const removeCertificateFile = (index) => { - certificateFileList.value.splice(index, 1) - formData.value.certificateFiles = certificateFileList.value.map(file => ({ - id: file.id, - name: file.name, - url: file.url || '', - type: file.type || '' - })) -} +const modalTitle = computed(() => { + return props.mode === 'upload' ? '上传' : '查看' +}) + +const isUploadMode = computed(() => props.mode === 'upload') // 下载报告 @@ -145,37 +202,12 @@ const handleDownloadReport = () => { const handlePreview = (file) => { // 对于非图片文件,显示提示 if (!file.type?.startsWith('image/')) { - $message.info('此文件类型不支持预览,请下载查看') + message.info('此文件类型不支持预览,请下载查看') return false } // 图片文件返回 true,让 NUpload 使用内置预览 return true } - -// 文件下载 -const handleDownload = (file) => { - const link = document.createElement('a') - link.href = file.url || '' - link.download = file.name || 'download' - document.body.appendChild(link) - link.click() - document.body.removeChild(link) -} - -// 自定义上传预览 -const customRequest = ({ file, onFinish, onError }) => { - // 这里可以实现自定义上传逻辑 - // 暂时模拟上传成功 - setTimeout(() => { - onFinish() - }, 1000) -} - -const modalTitle = computed(() => { - return props.mode === 'upload' ? '上传' : '查看' -}) - -const isUploadMode = computed(() => props.mode === 'upload')