优化
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, reactive, ref } from 'vue'
|
||||
import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import type { FormInstance, FormRules, UploadFile } from 'element-plus'
|
||||
import { Building2, CheckCircle2, Clock3, FileCheck2, FileText, Pencil, Trash2, Upload, UserRound } from '@lucide/vue'
|
||||
@@ -50,6 +50,7 @@ type QualificationDraftItem = QualificationTypeDefinition & {
|
||||
fileName: string
|
||||
fileSize: number
|
||||
fileType: string
|
||||
previewUrl: string
|
||||
inputVersion: number
|
||||
error: string
|
||||
uploadState: QualificationUploadState
|
||||
@@ -67,6 +68,7 @@ const qualificationDrafts = reactive<QualificationDraftItem[]>(qualificationType
|
||||
fileName: '',
|
||||
fileSize: 0,
|
||||
fileType: '',
|
||||
previewUrl: '',
|
||||
inputVersion: 0,
|
||||
error: '',
|
||||
uploadState: 'idle',
|
||||
@@ -116,6 +118,9 @@ const qualificationSaveDisabledReason = computed(() => {
|
||||
if (!selectedQualificationCount.value) return '请选择需要新增或替换的资质文件'
|
||||
return ''
|
||||
})
|
||||
const qualificationDialogHint = computed(() => qualificationSaveDisabledReason.value === qualificationCreditCodeError.value
|
||||
? ''
|
||||
: qualificationSaveDisabledReason.value)
|
||||
const canSubmitQualificationReview = computed(() => canUploadQualification.value
|
||||
&& companyCreditCodeValid.value
|
||||
&& qualificationTypes.every((type) => uploadedQualificationTypes.value.has(type.value)))
|
||||
@@ -167,6 +172,7 @@ async function loadCompanyContext() {
|
||||
}
|
||||
|
||||
onMounted(() => void loadCompanyContext())
|
||||
onBeforeUnmount(() => qualificationDrafts.forEach(releaseQualificationPreview))
|
||||
|
||||
function startEdit() {
|
||||
Object.assign(draft, store.company)
|
||||
@@ -223,6 +229,12 @@ function qualificationDraftItem(type: MerchantQualificationType) {
|
||||
return qualificationDrafts.find((item) => item.value === type)
|
||||
}
|
||||
|
||||
function releaseQualificationPreview(item: QualificationDraftItem) {
|
||||
if (!item.previewUrl) return
|
||||
URL.revokeObjectURL(item.previewUrl)
|
||||
item.previewUrl = ''
|
||||
}
|
||||
|
||||
function qualificationSlotLabel(item: QualificationDraftItem) {
|
||||
if (item.uploadState === 'uploading') return '上传中'
|
||||
if (item.uploadState === 'uploaded') return '已保存'
|
||||
@@ -244,6 +256,7 @@ function qualificationSlotTagType(item: QualificationDraftItem) {
|
||||
function handleQualificationFileChange(type: MerchantQualificationType, file: UploadFile) {
|
||||
const item = qualificationDraftItem(type)
|
||||
if (!item) return
|
||||
releaseQualificationPreview(item)
|
||||
const raw = file.raw
|
||||
if (!raw) {
|
||||
item.error = '未能读取所选文件,请重新选择'
|
||||
@@ -272,11 +285,13 @@ function handleQualificationFileChange(type: MerchantQualificationType, file: Up
|
||||
item.fileName = raw.name
|
||||
item.fileSize = raw.size
|
||||
item.fileType = raw.type || raw.name.split('.').pop()?.toUpperCase() || '文件'
|
||||
if (raw.type.startsWith('image/') || /\.(jpe?g|png)$/i.test(raw.name)) item.previewUrl = URL.createObjectURL(raw)
|
||||
}
|
||||
|
||||
function removeSelectedFile(type: MerchantQualificationType) {
|
||||
const item = qualificationDraftItem(type)
|
||||
if (!item) return
|
||||
releaseQualificationPreview(item)
|
||||
item.fileName = ''
|
||||
item.fileSize = 0
|
||||
item.fileType = ''
|
||||
@@ -288,6 +303,7 @@ function removeSelectedFile(type: MerchantQualificationType) {
|
||||
|
||||
function resetQualificationDraft() {
|
||||
qualificationDrafts.forEach((item) => {
|
||||
releaseQualificationPreview(item)
|
||||
item.fileName = ''
|
||||
item.fileSize = 0
|
||||
item.fileType = ''
|
||||
@@ -341,6 +357,7 @@ async function submitQualification() {
|
||||
item.value === 'BUSINESS_LICENSE' ? normalizedQualificationCertificateNo.value : undefined,
|
||||
Boolean(replaceableQualification(item.value)),
|
||||
)
|
||||
releaseQualificationPreview(item)
|
||||
item.file = null
|
||||
item.fileName = ''
|
||||
item.fileSize = 0
|
||||
@@ -552,8 +569,11 @@ function closeQualificationPreview() {
|
||||
<template #tip><div class="upload-tip">支持 PDF、JPG、PNG,单个文件不超过 5MB。</div></template>
|
||||
</el-upload>
|
||||
<div v-if="item.fileName" class="selected-qualification-file" aria-live="polite">
|
||||
<FileText :size="18" />
|
||||
<div><strong>{{ item.fileName }}</strong><span>{{ item.fileType }} · {{ formatQualificationFileSize(item.fileSize) }}</span></div>
|
||||
<a v-if="item.previewUrl" class="selected-file-preview" :href="item.previewUrl" target="_blank" rel="noopener" :aria-label="`查看${item.label}图片预览`">
|
||||
<img :src="item.previewUrl" :alt="`${item.label}待上传图片预览`" />
|
||||
</a>
|
||||
<div v-else class="selected-file-type" aria-hidden="true"><FileText :size="18" /><span>PDF</span></div>
|
||||
<div class="selected-file-meta"><strong>{{ item.fileName }}</strong><span>{{ item.fileType }} · {{ formatQualificationFileSize(item.fileSize) }}</span></div>
|
||||
<el-button link type="danger" :disabled="qualificationSubmitting" :aria-label="`移除${item.label}文件`" @click="removeSelectedFile(item.value)"><Trash2 :size="16" />移除</el-button>
|
||||
</div>
|
||||
<p v-if="item.error" class="qualification-upload-error" role="alert">{{ item.error }}</p>
|
||||
@@ -562,7 +582,7 @@ function closeQualificationPreview() {
|
||||
<el-form-item label="统一社会信用代码" class="qualification-credit-code" :required="!companyCreditCodeValid" :error="qualificationCreditCodeReady ? '' : qualificationCreditCodeError">
|
||||
<el-input v-model="qualificationCertificateNo" maxlength="18" placeholder="请输入18位统一社会信用代码" @input="qualificationCertificateNo = String($event).toUpperCase()" />
|
||||
</el-form-item>
|
||||
<p v-if="qualificationSaveDisabledReason" class="qualification-dialog-hint">{{ qualificationSaveDisabledReason }}</p>
|
||||
<p v-if="qualificationDialogHint" class="qualification-dialog-hint">{{ qualificationDialogHint }}</p>
|
||||
<template #footer><el-button :disabled="qualificationSubmitting" @click="qualificationOpen = false">取消</el-button><el-button type="primary" :loading="qualificationSubmitting" :disabled="!canSaveQualificationBatch" @click="submitQualification">保存全部资质</el-button></template>
|
||||
</el-dialog>
|
||||
|
||||
@@ -635,8 +655,12 @@ function closeQualificationPreview() {
|
||||
.existing-qualification-file span { min-width: 0; overflow: hidden; color: var(--muted); text-overflow: ellipsis; white-space: nowrap; }
|
||||
.upload-tip { margin-top: 8px; color: var(--muted); font-size: 11px; line-height: 1.55; }
|
||||
.selected-qualification-file { display: flex; width: 100%; min-width: 0; align-items: center; gap: 10px; margin-top: 12px; padding: 12px; border: 1px solid #cfe1dd; background: #f3f8f7; color: var(--primary); }
|
||||
.selected-qualification-file > svg { flex: 0 0 20px; }
|
||||
.selected-qualification-file > div { display: flex; min-width: 0; flex: 1; flex-direction: column; gap: 3px; }
|
||||
.selected-file-preview { display: block; width: 54px; height: 54px; flex: 0 0 54px; overflow: hidden; border: 1px solid #bfd4cf; background: #fff; }
|
||||
.selected-file-preview img { display: block; width: 100%; height: 100%; object-fit: cover; }
|
||||
.selected-file-preview:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
|
||||
.selected-file-type { display: grid; width: 54px; height: 54px; flex: 0 0 54px; place-items: center; align-content: center; gap: 2px; border: 1px solid #cfe1dd; background: #fff; }
|
||||
.selected-file-type span { color: var(--muted); font-size: 9px; font-weight: 700; }
|
||||
.selected-file-meta { display: flex; min-width: 0; flex: 1; flex-direction: column; gap: 3px; }
|
||||
.selected-qualification-file strong { overflow: hidden; color: var(--navy); font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.selected-qualification-file span { color: var(--muted); font-size: 10px; }
|
||||
.qualification-upload-error { margin: 9px 0 0; color: #b42318; font-size: 11px; line-height: 1.5; }
|
||||
@@ -673,6 +697,6 @@ function closeQualificationPreview() {
|
||||
.document-preview dl { grid-template-columns: 1fr; }
|
||||
.document-preview dl div + div { border-top: 1px solid var(--border); }
|
||||
.selected-qualification-file { align-items: flex-start; flex-wrap: wrap; }
|
||||
.selected-qualification-file > .el-button { margin-left: 28px; }
|
||||
.selected-qualification-file > .el-button { margin-left: 64px; }
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user