This commit is contained in:
2026-08-04 21:01:34 +08:00
parent 161bf580c7
commit 2313fd238c
12 changed files with 716 additions and 24 deletions
@@ -78,14 +78,13 @@ const qualificationCertificateNo = ref('')
const unifiedSocialCreditCodePattern = /^[0-9A-Z]{18}$/
const companyCreditCodeValid = computed(() => unifiedSocialCreditCodePattern.test(store.company.creditCode))
const normalizedQualificationCertificateNo = computed(() => qualificationCertificateNo.value.trim().toUpperCase())
const businessLicenseFileSelected = computed(() => Boolean(
qualificationDrafts.find((item) => item.value === 'BUSINESS_LICENSE')?.file,
))
const qualificationCreditCodeReady = computed(() => !businessLicenseFileSelected.value
|| companyCreditCodeValid.value
|| unifiedSocialCreditCodePattern.test(normalizedQualificationCertificateNo.value))
const draftCreditCodeValid = computed(() => unifiedSocialCreditCodePattern.test(normalizedQualificationCertificateNo.value))
const businessLicenseFileSelected = computed(() => Boolean(qualificationDraftItem('BUSINESS_LICENSE')?.file))
const qualificationCreditCodeReady = computed(() => companyCreditCodeValid.value
|| (businessLicenseFileSelected.value && draftCreditCodeValid.value))
const qualificationCreditCodeError = computed(() => {
if (qualificationCreditCodeReady.value) return ''
if (draftCreditCodeValid.value && !businessLicenseFileSelected.value) return '统一社会信用代码必须随营业执照文件共同保存'
return '请输入18位字母或数字组成的统一社会信用代码'
})
const canUploadQualification = computed(() => ['PROFILE_REQUIRED', 'REJECTED'].includes(store.company.auditStatus))
@@ -93,6 +92,17 @@ const uploadedQualificationTypes = computed(() => new Set(store.qualifications
.filter((item) => item.status === 'PENDING')
.map((item) => qualificationTypes.find((type) => type.label === item.type)?.value)
.filter((type): type is MerchantQualificationType => Boolean(type))))
const requiredPackageFilesReady = computed(() => requiredQualificationTypes.every((type) => (
uploadedQualificationTypes.value.has(type.value) || Boolean(qualificationDraftItem(type.value)?.file)
)))
const requiredPackageComplete = computed(() => qualificationCreditCodeReady.value && requiredPackageFilesReady.value)
const missingRequiredPackageItems = computed(() => {
const missing = requiredQualificationTypes
.filter((type) => !uploadedQualificationTypes.value.has(type.value) && !qualificationDraftItem(type.value)?.file)
.map((type) => type.label)
if (!qualificationCreditCodeReady.value) missing.splice(1, 0, '18位统一社会信用代码')
return missing
})
const qualificationUploadDisabledReason = computed(() => {
if (store.company.auditStatus === 'PENDING') return '企业资料正在审核,暂不能再次提交资质文件。'
if (store.company.auditStatus === 'ACTIVE') return '当前企业已审核通过,资质替换请联系平台管理员处理。'
@@ -102,11 +112,11 @@ const qualificationUploadDisabledReason = computed(() => {
const selectedQualificationCount = computed(() => qualificationDrafts.filter((item) => Boolean(item.file)).length)
const canSaveQualificationBatch = computed(() => canUploadQualification.value
&& selectedQualificationCount.value > 0
&& qualificationCreditCodeReady.value)
&& requiredPackageComplete.value)
const qualificationSaveDisabledReason = computed(() => {
if (!canUploadQualification.value) return qualificationUploadDisabledReason.value
if (!qualificationCreditCodeReady.value) return qualificationCreditCodeError.value
if (!selectedQualificationCount.value) return '请选择需要新增或替换的资质文件'
if (!requiredPackageComplete.value) return `请完整保存必填业务项:${missingRequiredPackageItems.value.join('、')}`
if (!selectedQualificationCount.value) return '当前没有需要保存的变更'
return ''
})
const qualificationDialogHint = computed(() => qualificationSaveDisabledReason.value === qualificationCreditCodeError.value
@@ -314,17 +324,13 @@ async function submitQualification() {
ElMessage.warning(qualificationUploadDisabledReason.value)
return
}
if (!qualificationCreditCodeReady.value) {
if (!requiredPackageComplete.value) {
const businessLicense = qualificationDraftItem('BUSINESS_LICENSE')
if (businessLicense) businessLicense.error = qualificationCreditCodeError.value
ElMessage.warning(qualificationCreditCodeError.value)
if (businessLicense && !qualificationCreditCodeReady.value) businessLicense.error = qualificationCreditCodeError.value
ElMessage.warning(`请完整保存必填业务项:${missingRequiredPackageItems.value.join('、')}`)
return
}
const pendingItems = qualificationDrafts.filter((item) => item.file)
if (!pendingItems.length) {
ElMessage.warning('请选择需要新增或替换的资质文件')
return
}
qualificationSubmitting.value = true
let uploadedCount = 0
const failures: string[] = []
@@ -364,7 +370,7 @@ async function submitQualification() {
return
}
qualificationOpen.value = false
if (refreshed) ElMessage.success(`已保存 ${uploadedCount} 项资质文件,尚未提交审核`)
if (refreshed) ElMessage.success('营业执照、统一社会信用代码和法人身份证已完整保存,尚未提交审核')
else ElMessage.warning('资质文件已保存,但最新状态刷新失败,请点击“重新加载”确认状态')
} finally {
qualificationSubmitting.value = false
@@ -526,8 +532,8 @@ function closeQualificationPreview() {
@closed="resetQualificationDraft"
>
<div class="qualification-dialog-intro">
<strong>必填资质与选填资料</strong>
<span>营业执照、法人身份证必填;其余两项可按需上传。文件保存不会自动提交企业审核。</span>
<strong>企业认证必填业务项</strong>
<span>营业执照、18位统一社会信用代码、法人身份证需共同完整保存;其余两项可按需上传。</span>
</div>
<div class="qualification-upload-grid">
<article v-for="item in qualificationDrafts" :key="item.value" class="qualification-upload-item">
@@ -563,8 +569,9 @@ function closeQualificationPreview() {
<p v-if="item.error" class="qualification-upload-error" role="alert">{{ item.error }}</p>
</article>
</div>
<el-form-item label="统一社会信用代码" class="qualification-credit-code" :required="businessLicenseFileSelected && !companyCreditCodeValid" :error="qualificationCreditCodeReady ? '' : qualificationCreditCodeError">
<el-input v-model="qualificationCertificateNo" maxlength="18" placeholder="请输入18位统一社会信用代码" @input="qualificationCertificateNo = String($event).toUpperCase()" />
<el-form-item label="统一社会信用代码" class="qualification-credit-code" required :error="qualificationCreditCodeReady ? '' : qualificationCreditCodeError">
<el-input v-model="qualificationCertificateNo" maxlength="18" :disabled="companyCreditCodeValid" placeholder="请输入18位统一社会信用代码" @input="qualificationCertificateNo = String($event).toUpperCase()" />
<small class="qualification-credit-code-hint">{{ companyCreditCodeValid ? '已登记的统一社会信用代码不可直接修改。' : '与营业执照一致,保存后不可直接修改。' }}</small>
</el-form-item>
<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>
@@ -649,6 +656,7 @@ function closeQualificationPreview() {
.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; }
.qualification-credit-code { max-width: 420px; margin: 18px 0 0; }
.qualification-credit-code-hint { display:block; margin-top:6px; color:var(--muted); font-size:11px; line-height:1.5; }
.qualification-dialog-hint { margin: 10px 0 0; color: var(--muted); font-size: 11px; line-height: 1.5; }
.document-preview { display: grid; min-height: 260px; place-items: center; align-content: center; gap: 12px; border: 1px dashed #b8c8c5; background: #f6faf9; color: var(--primary); }
.document-preview > strong { max-width: min(420px, calc(100% - 32px)); overflow-wrap: anywhere; color: var(--navy); text-align: center; }
@@ -47,7 +47,9 @@ test('implements company details, contact information and qualification workflow
assert.match(profileSource, /:close-on-click-modal="!qualificationSubmitting"/)
assert.match(profileSource, /:close-on-press-escape="!qualificationSubmitting"/)
assert.match(profileSource, /:show-close="!qualificationSubmitting"/)
assert.match(profileSource, /const qualificationCreditCodeReady = computed\(\(\) => !businessLicenseFileSelected\.value/)
assert.match(profileSource, /const requiredPackageComplete = computed/)
assert.match(profileSource, /营业执照、18位统一社会信用代码、法人身份证需共同完整保存/)
assert.match(profileSource, /已登记的统一社会信用代码不可直接修改/)
assert.match(profileSource, /companyCreditCodeValid\.value/)
assert.doesNotMatch(profileSource, /<el-select v-model="qualificationDraft\.type"/)
assert.match(profileSource, /class="mobile-qualification-list"/)
@@ -69,7 +71,7 @@ test('implements company details, contact information and qualification workflow
assert.match(profileSource, /qualificationUploadErrorMessage\(error\)/)
assert.match(profileSource, /submitTenantQualificationReview/)
assert.match(profileSource, /提交企业审核/)
assert.match(profileSource, /已保存.*项资质文件,尚未提交审核/)
assert.match(profileSource, /营业执照、统一社会信用代码和法人身份证已完整保存,尚未提交审核/)
assert.match(profileSource, /资质文件已保存,但最新状态刷新失败/)
assert.match(profileSource, /企业资料已提交审核,但最新状态刷新失败/)
assert.match(profileSource, /qualificationStatusMeta/)