feat: 实现证书和报告文件的实际上传功能,并在审核详情页中集成上传后的数据更新逻辑

This commit is contained in:
Wei_佳 2025-11-24 17:19:52 +08:00
parent 6432325387
commit 3db6b38e2e
2 changed files with 132 additions and 67 deletions

View File

@ -14,6 +14,8 @@ import {
import { formatDate } from '@/utils' import { formatDate } from '@/utils'
import TheIcon from '@/components/icon/TheIcon.vue' import TheIcon from '@/components/icon/TheIcon.vue'
import CertificateModal from './CertificateModal.vue' import CertificateModal from './CertificateModal.vue'
import api from '@/api'
import { useMessage } from 'naive-ui'
import { getStatusConfig } from '../constants' import { getStatusConfig } from '../constants'
import { import {
@ -34,6 +36,7 @@ const props = defineProps({
}) })
const emit = defineEmits(['back', 'approve', 'reject']) const emit = defineEmits(['back', 'approve', 'reject'])
const $message = useMessage()
const activeDetailTab = ref('audit') const activeDetailTab = ref('audit')
@ -313,11 +316,39 @@ const handleViewCertificate = () => {
certificateModalVisible.value = true certificateModalVisible.value = true
} }
const handleCertificateConfirm = (data) => { const handleCertificateConfirm = async (data) => {
console.log('证书数据:', data) console.log('证书数据:', data)
// API
$message?.success('证书上传成功') 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 certificateModalVisible.value = false
emit('back') // emit('refresh')
} catch (error) {
console.error('更新失败:', error)
$message.error('操作失败')
}
} }
</script> </script>

View File

@ -7,11 +7,14 @@ import {
NUpload, NUpload,
NText, NText,
NImage, NImage,
NImageGroup NImageGroup,
useMessage
} from 'naive-ui' } from 'naive-ui'
// //
// import { DownloadIcon } from '@vicons/tabler' // import { DownloadIcon } from '@vicons/tabler'
import { getToken } from '@/utils/auth/token'
const props = defineProps({ const props = defineProps({
visible: { visible: {
type: Boolean, type: Boolean,
@ -28,6 +31,7 @@ const props = defineProps({
}) })
const emit = defineEmits(['update:visible', 'confirm']) const emit = defineEmits(['update:visible', 'confirm'])
const message = useMessage()
const formData = ref({ const formData = ref({
reportFiles: [], reportFiles: [],
@ -37,6 +41,11 @@ const formData = ref({
const reportFileList = ref([]) const reportFileList = ref([])
const certificateFileList = ref([]) const certificateFileList = ref([])
const uploadUrl = `${import.meta.env.VITE_BASE_API}/upload/file`
const uploadHeaders = computed(() => ({
Authorization: `Bearer ${getToken()}`,
}))
// //
watch( watch(
() => props.visible, () => props.visible,
@ -82,56 +91,104 @@ const beforeUpload = (data) => {
const isVideo = file.type.startsWith('video/') const isVideo = file.type.startsWith('video/')
if (!isImage && !isPdf && !isWord && !isVideo) { if (!isImage && !isPdf && !isWord && !isVideo) {
$message.error('只能上传图片、PDF、Word文档或视频文件') message.error('只能上传图片、PDF、Word文档或视频文件')
return false return false
} }
const isLt50M = file.size / 1024 / 1024 < 50 const isLt50M = file.size / 1024 / 1024 < 50
if (!isLt50M) { if (!isLt50M) {
$message.error('文件大小不能超过50MB') message.error('文件大小不能超过50MB')
return false return false
} }
return true return true
} }
// //
const handleReportUploadChange = ({ fileList: newFileList }) => { const handleReportUploadFinish = ({ file, event }) => {
reportFileList.value = newFileList try {
formData.value.reportFiles = newFileList.map(file => ({ const res = JSON.parse(event.target.response)
id: file.id, if (res.code === 200 && res.data?.url) {
name: file.name, const targetFile = reportFileList.value.find(f => f.id === file.id) || file
url: file.url, targetFile.url = res.data.url
type: file.type 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 }) => { const handleCertificateUploadFinish = ({ file, event }) => {
certificateFileList.value = newFileList try {
formData.value.certificateFiles = newFileList.map(file => ({ const res = JSON.parse(event.target.response)
id: file.id, if (res.code === 200 && res.data?.url) {
name: file.name, const targetFile = certificateFileList.value.find(f => f.id === file.id) || file
url: file.url, targetFile.url = res.data.url
type: file.type 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 = () => { 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 return true
} }
// const modalTitle = computed(() => {
const removeCertificateFile = (index) => { return props.mode === 'upload' ? '上传' : '查看'
certificateFileList.value.splice(index, 1) })
formData.value.certificateFiles = certificateFileList.value.map(file => ({
id: file.id, const isUploadMode = computed(() => props.mode === 'upload')
name: file.name,
url: file.url || '',
type: file.type || ''
}))
}
// //
@ -145,37 +202,12 @@ const handleDownloadReport = () => {
const handlePreview = (file) => { const handlePreview = (file) => {
// //
if (!file.type?.startsWith('image/')) { if (!file.type?.startsWith('image/')) {
$message.info('此文件类型不支持预览,请下载查看') message.info('此文件类型不支持预览,请下载查看')
return false return false
} }
// true NUpload 使 // true NUpload 使
return true 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')
</script> </script>
<template> <template>
@ -201,12 +233,13 @@ const isUploadMode = computed(() => props.mode === 'upload')
<div class="upload-content"> <div class="upload-content">
<NUpload <NUpload
v-model:file-list="reportFileList" v-model:file-list="reportFileList"
:max="5" multiple
list-type="image-card" list-type="image-card"
:action="uploadUrl"
:headers="uploadHeaders"
:before-upload="beforeUpload" :before-upload="beforeUpload"
@change="handleReportUploadChange" @finish="handleReportUploadFinish"
@remove="handleRemove" @remove="handleRemove"
:custom-request="customRequest"
:disabled="!isUploadMode" :disabled="!isUploadMode"
show-preview-button show-preview-button
show-download-button show-download-button
@ -222,12 +255,13 @@ const isUploadMode = computed(() => props.mode === 'upload')
<div class="upload-content"> <div class="upload-content">
<NUpload <NUpload
v-model:file-list="certificateFileList" v-model:file-list="certificateFileList"
:max="5" multiple
list-type="image-card" list-type="image-card"
:action="uploadUrl"
:headers="uploadHeaders"
:before-upload="beforeUpload" :before-upload="beforeUpload"
@change="handleCertificateUploadChange" @finish="handleCertificateUploadFinish"
@remove="handleRemove" @remove="handleRemove"
:custom-request="customRequest"
:disabled="!isUploadMode" :disabled="!isUploadMode"
show-preview-button show-preview-button
show-download-button show-download-button