f
This commit is contained in:
@@ -125,33 +125,25 @@
|
||||
<div class="text-xs mb-1 text-blue-500">
|
||||
请在非 IE 浏览器下上传大小不超过 1M 的图片,最多 10 张,需体现门楣 LOGO、办公设备与工作人员。
|
||||
</div>
|
||||
<div
|
||||
class="upload-drop-zone"
|
||||
:class="{ 'is-dragover': officePlaceDragover }"
|
||||
@dragover.prevent="officePlaceDragover = true"
|
||||
@dragleave.prevent="officePlaceDragover = false"
|
||||
@drop.prevent="onOfficePlaceDrop"
|
||||
<el-upload
|
||||
ref="officePlaceUploadRef"
|
||||
class="upload-area"
|
||||
action="#"
|
||||
list-type="picture-card"
|
||||
:auto-upload="false"
|
||||
v-model:file-list="officePlaceFileList"
|
||||
accept="image/jpeg,image/jpg,image/png,image/webp"
|
||||
multiple
|
||||
:limit="10"
|
||||
:on-change="handleOfficePlaceChange"
|
||||
:on-remove="handleOfficePlaceRemove"
|
||||
:before-upload="beforeUpload"
|
||||
>
|
||||
<el-upload
|
||||
ref="officePlaceUploadRef"
|
||||
class="upload-area"
|
||||
action="#"
|
||||
list-type="picture-card"
|
||||
:auto-upload="false"
|
||||
v-model:file-list="officePlaceFileList"
|
||||
accept="image/jpeg,image/jpg,image/png,image/webp"
|
||||
multiple
|
||||
:limit="10"
|
||||
:on-change="handleOfficePlaceChange"
|
||||
:on-remove="handleOfficePlaceRemove"
|
||||
:before-upload="beforeUpload"
|
||||
>
|
||||
<div class="upload-trigger-inner">
|
||||
<el-icon class="upload-icon"><ArrowUpTrayIcon /></el-icon>
|
||||
<div class="el-upload__text">上传办公场地环境照片</div>
|
||||
</div>
|
||||
</el-upload>
|
||||
</div>
|
||||
<div class="upload-trigger-inner">
|
||||
<el-icon class="upload-icon"><ArrowUpTrayIcon /></el-icon>
|
||||
<div class="el-upload__text">上传办公场地环境照片</div>
|
||||
</div>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -319,33 +311,25 @@
|
||||
<div class="text-xs mb-1 text-blue-500">
|
||||
请在非 IE 浏览器下上传大小不超过 1M 的图片,最多 10 张后台应用截图。
|
||||
</div>
|
||||
<div
|
||||
class="upload-drop-zone"
|
||||
:class="{ 'is-dragover': scenarioDragover }"
|
||||
@dragover.prevent="scenarioDragover = true"
|
||||
@dragleave.prevent="scenarioDragover = false"
|
||||
@drop.prevent="onScenarioDrop"
|
||||
<el-upload
|
||||
ref="scenarioUploadRef"
|
||||
class="upload-area"
|
||||
action="#"
|
||||
list-type="picture-card"
|
||||
:auto-upload="false"
|
||||
v-model:file-list="scenarioFileList"
|
||||
accept="image/jpeg,image/jpg,image/png,image/webp"
|
||||
multiple
|
||||
:limit="10"
|
||||
:on-change="handleScenarioChange"
|
||||
:on-remove="handleScenarioRemove"
|
||||
:before-upload="beforeUpload"
|
||||
>
|
||||
<el-upload
|
||||
ref="scenarioUploadRef"
|
||||
class="upload-area"
|
||||
action="#"
|
||||
list-type="picture-card"
|
||||
:auto-upload="false"
|
||||
v-model:file-list="scenarioFileList"
|
||||
accept="image/jpeg,image/jpg,image/png,image/webp"
|
||||
multiple
|
||||
:limit="10"
|
||||
:on-change="handleScenarioChange"
|
||||
:on-remove="handleScenarioRemove"
|
||||
:before-upload="beforeUpload"
|
||||
>
|
||||
<div class="upload-trigger-inner">
|
||||
<el-icon class="upload-icon"><ArrowUpTrayIcon /></el-icon>
|
||||
<div class="el-upload__text">上传业务场景相关截图或证明材料</div>
|
||||
</div>
|
||||
</el-upload>
|
||||
</div>
|
||||
<div class="upload-trigger-inner">
|
||||
<el-icon class="upload-icon"><ArrowUpTrayIcon /></el-icon>
|
||||
<div class="el-upload__text">上传业务场景相关截图或证明材料</div>
|
||||
</div>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -378,7 +362,7 @@ import {
|
||||
CheckIcon,
|
||||
DocumentIcon
|
||||
} from '@heroicons/vue/24/outline'
|
||||
import { ElMessage, ElMessageBox, genFileId } from 'element-plus'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { useAliyunCaptcha } from '@/composables/useAliyunCaptcha'
|
||||
|
||||
const props = defineProps({
|
||||
@@ -449,8 +433,6 @@ const ocrResult = ref(false)
|
||||
const uploadRef = ref()
|
||||
const officePlaceUploadRef = ref()
|
||||
const scenarioUploadRef = ref()
|
||||
const officePlaceDragover = ref(false)
|
||||
const scenarioDragover = ref(false)
|
||||
|
||||
// 上传文件列表(前端展示用)
|
||||
const officePlaceFileList = ref([])
|
||||
@@ -681,9 +663,6 @@ const handleFileChange = async (file) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否为前端 blob 预览地址(需上传到服务器后替换为真实 URL)
|
||||
const isBlobUrl = (url) => typeof url === 'string' && url.startsWith('blob:')
|
||||
|
||||
// 上传单张图片到七牛云,返回可访问 URL
|
||||
const uploadFileToServer = async (file) => {
|
||||
const res = await certificationApi.uploadFile(file)
|
||||
@@ -693,17 +672,17 @@ const uploadFileToServer = async (file) => {
|
||||
return res.data.url
|
||||
}
|
||||
|
||||
// 选择后立即上传:对 el-upload 的 file 对象上传并更新 url/status,不更新表单(由调用方更新)
|
||||
// 选择后立即上传:服务器 URL 存到 response.url,保留 file.url 为 blob 以便预览(避免服务器证书等问题导致预览失败)
|
||||
const uploadFileOnceSelected = async (file) => {
|
||||
if (!file?.raw) return null
|
||||
if (file.url && !isBlobUrl(file.url)) return file.url // 已是服务器 URL,不重复上传
|
||||
if (file.response?.url) return file.response.url // 已上传过,不重复上传
|
||||
file.status = 'uploading'
|
||||
try {
|
||||
const url = await uploadFileToServer(file.raw)
|
||||
file.url = url
|
||||
file.status = 'success'
|
||||
if (file.response === undefined) file.response = {}
|
||||
file.response.url = url
|
||||
// 不覆盖 file.url,保留 blob 预览地址,避免服务器证书无效时预览失败
|
||||
return url
|
||||
} catch (err) {
|
||||
file.status = 'fail'
|
||||
@@ -712,64 +691,27 @@ const uploadFileOnceSelected = async (file) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 提交前将 blob 图片全部上传到七牛云,并更新表单中的 URL
|
||||
const uploadAllBlobFilesAndFillForm = async () => {
|
||||
const tasks = []
|
||||
// 提交前仅从 fileList 同步 URL 到表单,并检查是否全部已上传(选择即上传,提交时不再批量上传)
|
||||
const syncFormUrlsAndCheckReady = () => {
|
||||
form.value.businessLicenseImageURL = extractUrls(businessLicenseFileList.value)[0] || ''
|
||||
form.value.officePlaceImageURLs = extractUrls(officePlaceFileList.value)
|
||||
form.value.scenarioAttachmentURLs = extractUrls(scenarioFileList.value)
|
||||
updateAuthorizedRepIDImageURLs()
|
||||
|
||||
// 营业执照:若当前是 blob 则上传
|
||||
if (isBlobUrl(form.value.businessLicenseImageURL) && businessLicenseFileList.value.length > 0 && businessLicenseFileList.value[0].raw) {
|
||||
tasks.push(
|
||||
uploadFileToServer(businessLicenseFileList.value[0].raw).then((url) => {
|
||||
form.value.businessLicenseImageURL = url
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
// 办公场地多图:按顺序上传
|
||||
if (officePlaceFileList.value.length > 0) {
|
||||
const files = officePlaceFileList.value.filter((f) => f.raw).map((f) => f.raw)
|
||||
if (files.length > 0) {
|
||||
tasks.push(
|
||||
Promise.all(files.map((f) => uploadFileToServer(f))).then((urls) => {
|
||||
form.value.officePlaceImageURLs = urls
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 应用场景附件多图:按顺序上传
|
||||
if (scenarioFileList.value.length > 0) {
|
||||
const files = scenarioFileList.value.filter((f) => f.raw).map((f) => f.raw)
|
||||
if (files.length > 0) {
|
||||
tasks.push(
|
||||
Promise.all(files.map((f) => uploadFileToServer(f))).then((urls) => {
|
||||
form.value.scenarioAttachmentURLs = urls
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 授权代表身份证正反面:人像面 + 国徽面
|
||||
const frontRaw = authorizedRepIDFrontFileList.value[0]?.raw
|
||||
const backRaw = authorizedRepIDBackFileList.value[0]?.raw
|
||||
if (frontRaw || backRaw) {
|
||||
tasks.push(
|
||||
(async () => {
|
||||
const urls = []
|
||||
if (frontRaw) urls.push(await uploadFileToServer(frontRaw))
|
||||
if (backRaw) urls.push(await uploadFileToServer(backRaw))
|
||||
form.value.authorizedRepIDImageURLs = urls
|
||||
})()
|
||||
)
|
||||
}
|
||||
|
||||
await Promise.all(tasks)
|
||||
const hasUploading = (list) => list.some((f) => f.status === 'uploading')
|
||||
const hasUnfinished = (list) => list.some((f) => f.raw && !f.response?.url)
|
||||
if (hasUploading(businessLicenseFileList.value) || hasUnfinished(businessLicenseFileList.value)) return false
|
||||
if (hasUploading(officePlaceFileList.value) || hasUnfinished(officePlaceFileList.value)) return false
|
||||
if (hasUploading(scenarioFileList.value) || hasUnfinished(scenarioFileList.value)) return false
|
||||
if (hasUploading(authorizedRepIDFrontFileList.value) || hasUnfinished(authorizedRepIDFrontFileList.value)) return false
|
||||
if (hasUploading(authorizedRepIDBackFileList.value) || hasUnfinished(authorizedRepIDBackFileList.value)) return false
|
||||
return true
|
||||
}
|
||||
|
||||
// 从 el-upload 的 fileList 中提取 URL 数组(后端接好上传接口后可用 response.url)
|
||||
// 从 el-upload 的 fileList 中提取 URL 数组,优先用服务器 URL(response.url),提交用
|
||||
const extractUrls = (fileList) => {
|
||||
return fileList
|
||||
.map(f => f.url || f.response?.url || f.name)
|
||||
.map(f => f.response?.url || f.url || f.name)
|
||||
.filter(Boolean)
|
||||
}
|
||||
|
||||
@@ -781,8 +723,8 @@ const handleBusinessLicenseChange = async (file, fileList) => {
|
||||
|
||||
if (file && file.raw) {
|
||||
await handleFileChange(file)
|
||||
// OCR 若未返回服务器 URL,则选择后立即上传
|
||||
if (isBlobUrl(form.value.businessLicenseImageURL)) {
|
||||
// OCR 若未返回服务器 URL,则选择后立即上传(未上传过才上传)
|
||||
if (!file.response?.url) {
|
||||
const url = await uploadFileOnceSelected(file)
|
||||
if (url) form.value.businessLicenseImageURL = url
|
||||
}
|
||||
@@ -804,7 +746,7 @@ const clearBusinessLicense = () => {
|
||||
// 授权代表身份证人像面图片变更:选择即上传
|
||||
const handleAuthorizedRepIDFrontChange = async (file, fileList) => {
|
||||
authorizedRepIDFrontFileList.value = fileList
|
||||
if (file?.raw && isBlobUrl(file.url)) {
|
||||
if (file?.raw && !file.response?.url) {
|
||||
await uploadFileOnceSelected(file)
|
||||
}
|
||||
updateAuthorizedRepIDImageURLs()
|
||||
@@ -818,7 +760,7 @@ const handleAuthorizedRepIDFrontRemove = (file, fileList) => {
|
||||
// 授权代表身份证国徽面图片变更:选择即上传
|
||||
const handleAuthorizedRepIDBackChange = async (file, fileList) => {
|
||||
authorizedRepIDBackFileList.value = fileList
|
||||
if (file?.raw && isBlobUrl(file.url)) {
|
||||
if (file?.raw && !file.response?.url) {
|
||||
await uploadFileOnceSelected(file)
|
||||
}
|
||||
updateAuthorizedRepIDImageURLs()
|
||||
@@ -851,48 +793,10 @@ const updateAuthorizedRepIDImageURLs = () => {
|
||||
form.value.authorizedRepIDImageURLs = urls
|
||||
}
|
||||
|
||||
// 办公场地:拖放文件时通过 handleStart 加入列表
|
||||
const onOfficePlaceDrop = (e) => {
|
||||
officePlaceDragover.value = false
|
||||
const upload = officePlaceUploadRef.value
|
||||
if (!upload) return
|
||||
const files = Array.from(e.dataTransfer?.files || []).filter(
|
||||
(f) => f.type && /^image\/(jpeg|jpg|png|webp)$/i.test(f.type)
|
||||
)
|
||||
const limit = 10
|
||||
const remain = Math.max(0, limit - officePlaceFileList.value.length)
|
||||
const toAdd = files.slice(0, remain)
|
||||
for (const file of toAdd) {
|
||||
if (!beforeUpload(file)) continue
|
||||
if (typeof file.uid === 'undefined') file.uid = genFileId()
|
||||
upload.handleStart(file)
|
||||
}
|
||||
if (files.length > remain && remain > 0) ElMessage.warning(`最多上传 ${limit} 张,已忽略多余文件`)
|
||||
}
|
||||
|
||||
// 应用场景:拖放文件时通过 handleStart 加入列表
|
||||
const onScenarioDrop = (e) => {
|
||||
scenarioDragover.value = false
|
||||
const upload = scenarioUploadRef.value
|
||||
if (!upload) return
|
||||
const files = Array.from(e.dataTransfer?.files || []).filter(
|
||||
(f) => f.type && /^image\/(jpeg|jpg|png|webp)$/i.test(f.type)
|
||||
)
|
||||
const limit = 10
|
||||
const remain = Math.max(0, limit - scenarioFileList.value.length)
|
||||
const toAdd = files.slice(0, remain)
|
||||
for (const file of toAdd) {
|
||||
if (!beforeUpload(file)) continue
|
||||
if (typeof file.uid === 'undefined') file.uid = genFileId()
|
||||
upload.handleStart(file)
|
||||
}
|
||||
if (files.length > remain && remain > 0) ElMessage.warning(`最多上传 ${limit} 张,已忽略多余文件`)
|
||||
}
|
||||
|
||||
// 办公场地图片变更:选择即上传
|
||||
const handleOfficePlaceChange = async (file, fileList) => {
|
||||
officePlaceFileList.value = fileList
|
||||
if (file?.raw && isBlobUrl(file.url)) {
|
||||
if (file?.raw && !file.response?.url) {
|
||||
await uploadFileOnceSelected(file)
|
||||
}
|
||||
form.value.officePlaceImageURLs = extractUrls(fileList)
|
||||
@@ -906,7 +810,7 @@ const handleOfficePlaceRemove = (file, fileList) => {
|
||||
// 应用场景附件图片变更:选择即上传
|
||||
const handleScenarioChange = async (file, fileList) => {
|
||||
scenarioFileList.value = fileList
|
||||
if (file?.raw && isBlobUrl(file.url)) {
|
||||
if (file?.raw && !file.response?.url) {
|
||||
await uploadFileOnceSelected(file)
|
||||
}
|
||||
form.value.scenarioAttachmentURLs = extractUrls(fileList)
|
||||
@@ -937,11 +841,9 @@ const submitForm = async () => {
|
||||
}
|
||||
)
|
||||
|
||||
// 先将所有 blob 图片上传到七牛云,再提交企业信息
|
||||
try {
|
||||
await uploadAllBlobFilesAndFillForm()
|
||||
} catch (err) {
|
||||
ElMessage.error(err?.message || '图片上传失败,请重试')
|
||||
// 选择即上传:提交时不再上传,仅同步 URL 并校验是否均已上传完成
|
||||
if (!syncFormUrlsAndCheckReady()) {
|
||||
ElMessage.warning('请等待所有图片上传完成后再提交')
|
||||
submitting.value = false
|
||||
return
|
||||
}
|
||||
@@ -1157,18 +1059,6 @@ onUnmounted(() => {
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
/* 拖放区域:包裹 picture-card 上传,支持拖拽图片到整块区域 */
|
||||
.upload-drop-zone {
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
transition: background 0.2s, border-color 0.2s;
|
||||
}
|
||||
.upload-drop-zone.is-dragover {
|
||||
background: var(--el-color-primary-light-9, #ecf5ff);
|
||||
outline: 2px dashed var(--el-color-primary);
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
/* 上传区域基础样式 */
|
||||
.upload-area {
|
||||
width: 100%;
|
||||
|
||||
Reference in New Issue
Block a user