优化
This commit is contained in:
@@ -37,6 +37,8 @@ export interface MerchantQualification {
|
||||
qualificationType: MerchantQualificationType
|
||||
certificateNo: string | null
|
||||
documentUrl?: string | null
|
||||
originalFileName?: string | null
|
||||
updatedAt?: string | null
|
||||
validTo: string | null
|
||||
status: QualificationStatus
|
||||
reviewComment: string | null
|
||||
@@ -119,6 +121,11 @@ export interface MerchantPersonalProfile {
|
||||
email: string | null
|
||||
}
|
||||
|
||||
export interface QualificationDeletionResult {
|
||||
qualificationId: number | string
|
||||
deletedDocumentUrl: string | null
|
||||
}
|
||||
|
||||
export interface ChangeMerchantLoginIdentifiersRequest {
|
||||
username: string
|
||||
phone: string
|
||||
@@ -157,6 +164,13 @@ export function getTenantQualifications() {
|
||||
return apiRequest<MerchantQualification[]>({ method: 'GET', url: '/merchant/v1/iam/tenant/qualifications' })
|
||||
}
|
||||
|
||||
export function deleteTenantQualification(qualificationId: number | string) {
|
||||
return apiRequest<QualificationDeletionResult>({
|
||||
method: 'DELETE',
|
||||
url: `/merchant/v1/iam/tenant/qualifications/${qualificationId}`,
|
||||
})
|
||||
}
|
||||
|
||||
export function getMerchantPermissionResources() {
|
||||
return apiRequest<MerchantPermissionResource[]>({ method: 'GET', url: '/merchant/v1/iam/permissions' })
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
changeMerchantRoleStatus,
|
||||
createMerchantMember,
|
||||
createMerchantRole,
|
||||
deleteTenantQualification,
|
||||
deleteMerchantRole,
|
||||
getMerchantMembers,
|
||||
getMerchantPermissionResources,
|
||||
@@ -91,6 +92,13 @@ function formatLastLoginAt(value: string | null) {
|
||||
return date.toLocaleString('zh-CN', { hour12: false })
|
||||
}
|
||||
|
||||
function formatQualificationUpdatedAt(value: string | null | undefined) {
|
||||
if (!value) return '—'
|
||||
const date = new Date(value)
|
||||
if (Number.isNaN(date.getTime())) return value
|
||||
return date.toLocaleString('zh-CN', { hour12: false })
|
||||
}
|
||||
|
||||
const emptyCompany: TenantCompanyProfile = {
|
||||
companyName: '',
|
||||
creditCode: '',
|
||||
@@ -145,10 +153,10 @@ export const useTenantAdministrationStore = defineStore('tenant-administration',
|
||||
FREIGHT_FORWARDER_CERTIFICATE: '货代资质证书',
|
||||
BANK_ACCOUNT_LICENSE: '银行开户许可证',
|
||||
} as const)[item.qualificationType] || '企业资质',
|
||||
fileName: documentUrl.split('/').pop() || '资质文件',
|
||||
fileName: item.originalFileName?.trim() || '—',
|
||||
status: normalizeQualificationStatus(item.status),
|
||||
expiresAt: item.validTo || '长期有效',
|
||||
updatedAt: '-',
|
||||
updatedAt: formatQualificationUpdatedAt(item.updatedAt),
|
||||
documentUrl,
|
||||
}
|
||||
})
|
||||
@@ -198,6 +206,11 @@ export const useTenantAdministrationStore = defineStore('tenant-administration',
|
||||
roles.value = roleRecords.map(mapMerchantRole)
|
||||
}
|
||||
|
||||
async function deleteQualification(id: string) {
|
||||
await deleteTenantQualification(id)
|
||||
qualifications.value = qualifications.value.filter((item) => item.id !== id)
|
||||
}
|
||||
|
||||
async function loadMembers() {
|
||||
members.value = []
|
||||
members.value = (await getMerchantMembers()).map(mapMerchantMember)
|
||||
@@ -335,6 +348,7 @@ export const useTenantAdministrationStore = defineStore('tenant-administration',
|
||||
roles,
|
||||
activeMemberCount,
|
||||
loadCompanyContext,
|
||||
deleteQualification,
|
||||
loadRoles,
|
||||
loadMembers,
|
||||
updateCompany,
|
||||
|
||||
@@ -2,10 +2,12 @@ import assert from 'node:assert/strict'
|
||||
import test from 'node:test'
|
||||
import { formatQualificationFileSize, qualificationUploadErrorMessage, QUALIFICATION_MAX_FILE_SIZE, validateQualificationFile } from './qualificationFile.ts'
|
||||
|
||||
test('accepts the backend-confirmed PDF, JPG and PNG formats up to 5MB', () => {
|
||||
test('accepts PDF, JPG, PNG and BMP formats up to 5MB', () => {
|
||||
assert.equal(validateQualificationFile({ name: '营业执照.jpeg', size: QUALIFICATION_MAX_FILE_SIZE, type: 'image/jpeg' }), '')
|
||||
assert.equal(validateQualificationFile({ name: '营业执照.PNG', size: 2048, type: 'image/png' }), '')
|
||||
assert.equal(validateQualificationFile({ name: '货代资质.pdf', size: 2048, type: 'application/pdf' }), '')
|
||||
assert.equal(validateQualificationFile({ name: '法人身份证.bmp', size: 2048, type: 'image/bmp' }), '')
|
||||
assert.equal(validateQualificationFile({ name: '营业执照.bmp', size: 2048, type: 'image/x-ms-bmp' }), '')
|
||||
})
|
||||
|
||||
test('rejects unsupported, empty, mismatched, and oversized files', () => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export const QUALIFICATION_MAX_FILE_SIZE = 5 * 1024 * 1024
|
||||
|
||||
const allowedExtensions = new Set(['jpg', 'jpeg', 'png', 'pdf'])
|
||||
const allowedMimeTypes = new Set(['image/jpeg', 'image/png', 'application/pdf'])
|
||||
const allowedExtensions = new Set(['jpg', 'jpeg', 'png', 'bmp', 'pdf'])
|
||||
const allowedMimeTypes = new Set(['image/jpeg', 'image/png', 'image/bmp', 'image/x-ms-bmp', 'application/pdf'])
|
||||
|
||||
export interface QualificationFileLike {
|
||||
name: string
|
||||
@@ -11,7 +11,7 @@ export interface QualificationFileLike {
|
||||
|
||||
export function validateQualificationFile(file: QualificationFileLike) {
|
||||
const extension = file.name.includes('.') ? file.name.split('.').pop()?.toLowerCase() ?? '' : ''
|
||||
if (!allowedExtensions.has(extension)) return '文件格式不支持,请选择 PDF、JPG 或 PNG 文件'
|
||||
if (!allowedExtensions.has(extension)) return '文件格式不支持,请选择 PDF、JPG、PNG 或 BMP 文件'
|
||||
if (file.type && !allowedMimeTypes.has(file.type)) return '文件内容类型与支持的资质格式不一致'
|
||||
if (file.size <= 0) return '文件内容为空,请重新选择'
|
||||
if (file.size > QUALIFICATION_MAX_FILE_SIZE) return '文件超过 5MB,请压缩后重新选择'
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeUnmount, onMounted, reactive, ref } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import type { FormInstance, FormRules, UploadFile } from 'element-plus'
|
||||
import { Building2, CheckCircle2, Clock3, FileCheck2, FileText, Pencil, Trash2, Upload, UserRound } from '@lucide/vue'
|
||||
import DataTable, { type DataTableColumn } from '@/components/common/DataTable.vue'
|
||||
@@ -18,6 +19,7 @@ import {
|
||||
|
||||
const store = useTenantAdministrationStore()
|
||||
const auth = useAuthStore()
|
||||
const route = useRoute()
|
||||
const companyApproved = computed(() => store.company.auditStatus === 'ACTIVE')
|
||||
const auditStatusCopy = computed(() => ({
|
||||
PROFILE_REQUIRED: { title: '请完善企业资质', detail: '上传营业执照并提交审核后,才能提交头程订单;法人身份证可按需补充。' },
|
||||
@@ -41,6 +43,7 @@ const qualificationPage = ref(1)
|
||||
const qualificationPageSize = ref(10)
|
||||
const qualificationSubmitting = ref(false)
|
||||
const reviewSubmitting = ref(false)
|
||||
const deletingQualificationId = ref('')
|
||||
const profileSubmitting = ref(false)
|
||||
const loading = ref(false)
|
||||
const loadError = ref('')
|
||||
@@ -60,7 +63,7 @@ type QualificationDraftItem = QualificationTypeDefinition & {
|
||||
|
||||
const qualificationTypes: QualificationTypeDefinition[] = [
|
||||
{ value: 'BUSINESS_LICENSE', label: '营业执照', description: '上传清晰完整的营业执照文件。', required: true },
|
||||
{ value: 'LEGAL_PERSON_ID', label: '法人身份证', description: '选填;如上传,正反面请合并为一个 PDF、JPG 或 PNG 文件。', required: false },
|
||||
{ value: 'LEGAL_PERSON_ID', label: '法人身份证', description: '选填;如上传,正反面请合并为一个 PDF、JPG、PNG 或 BMP 文件。', required: false },
|
||||
{ value: 'FREIGHT_FORWARDER_CERTIFICATE', label: '货代资质证书', description: '如有,可上传当前有效的货代资质证明。', required: false },
|
||||
{ value: 'BANK_ACCOUNT_LICENSE', label: '银行开户许可证', description: '如有,可上传企业对公账户开户证明。', required: false },
|
||||
]
|
||||
@@ -154,7 +157,7 @@ const profileFormRules: FormRules<TenantCompanyProfile> = {
|
||||
contactEmail: [{ type: 'email', message: '请输入正确的联系邮箱', trigger: 'blur' }],
|
||||
}
|
||||
const qualificationColumns: DataTableColumn[] = [
|
||||
{ key: 'actions', label: '操作', width: 90, fixed: 'left', slotName: 'actions' },
|
||||
{ key: 'actions', label: '操作', width: 132, fixed: 'left', slotName: 'actions' },
|
||||
{ key: 'type', prop: 'type', label: '文件类型', minWidth: 150 },
|
||||
{ key: 'fileName', prop: 'fileName', label: '文件名称', minWidth: 220, showOverflowTooltip: true },
|
||||
{ key: 'status', label: '状态', width: 110, slotName: 'status' },
|
||||
@@ -184,7 +187,13 @@ async function loadCompanyContext() {
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
onMounted(() => void loadCompanyContext())
|
||||
onMounted(async () => {
|
||||
await loadCompanyContext()
|
||||
if (route.query.qualification === 'upload' && canUploadQualification.value) {
|
||||
activeTab.value = 'qualification'
|
||||
openQualificationDialog()
|
||||
}
|
||||
})
|
||||
onBeforeUnmount(() => qualificationDrafts.forEach(releaseQualificationPreview))
|
||||
|
||||
function startEdit() {
|
||||
@@ -299,7 +308,7 @@ 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)
|
||||
if (raw.type.startsWith('image/') || /\.(jpe?g|png|bmp)$/i.test(raw.name)) item.previewUrl = URL.createObjectURL(raw)
|
||||
}
|
||||
|
||||
function removeSelectedFile(type: MerchantQualificationType) {
|
||||
@@ -329,19 +338,19 @@ function resetQualificationDraft() {
|
||||
qualificationCertificateNo.value = store.company.creditCode
|
||||
}
|
||||
|
||||
async function submitQualification() {
|
||||
if (qualificationSubmitting.value) return
|
||||
async function submitQualification(closeDialog = true) {
|
||||
if (qualificationSubmitting.value) return false
|
||||
if (!canUploadQualification.value) {
|
||||
qualificationOpen.value = false
|
||||
await loadCompanyContext()
|
||||
ElMessage.warning(qualificationUploadDisabledReason.value)
|
||||
return
|
||||
return false
|
||||
}
|
||||
if (!requiredPackageComplete.value) {
|
||||
const businessLicense = qualificationDraftItem('BUSINESS_LICENSE')
|
||||
if (businessLicense && !qualificationCreditCodeReady.value) businessLicense.error = qualificationCreditCodeError.value
|
||||
ElMessage.warning(`请完整保存必填业务项:${missingRequiredPackageItems.value.join('、')}`)
|
||||
return
|
||||
return false
|
||||
}
|
||||
const optionalItems = qualificationDrafts.filter((item) => !item.required
|
||||
&& item.file
|
||||
@@ -418,20 +427,32 @@ async function submitQualification() {
|
||||
if (!canUploadQualification.value) qualificationOpen.value = false
|
||||
const uploadedCopy = uploadedCount ? `已保存 ${uploadedCount} 项;` : ''
|
||||
ElMessage.error(`${uploadedCopy}${failures[0]}`)
|
||||
return
|
||||
return false
|
||||
}
|
||||
qualificationOpen.value = false
|
||||
if (closeDialog) qualificationOpen.value = false
|
||||
if (refreshed) ElMessage.success(includedLegalPersonId
|
||||
? (requiredPackageChangeSelected.value
|
||||
? '营业执照、统一社会信用代码和法人身份证已保存,尚未提交审核'
|
||||
: '法人身份证已保存,尚未提交审核')
|
||||
: '资质文件已保存,尚未提交审核')
|
||||
else ElMessage.warning('资质文件已保存,但最新状态刷新失败,请点击“重新加载”确认状态')
|
||||
return refreshed
|
||||
} finally {
|
||||
qualificationSubmitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function submitQualificationAndReview() {
|
||||
if (qualificationSubmitting.value || reviewSubmitting.value) return
|
||||
if (selectedQualificationCount.value > 0 && !await submitQualification(false)) return
|
||||
if (!canSubmitQualificationReview.value) {
|
||||
ElMessage.warning(qualificationReviewDisabledReason.value)
|
||||
return
|
||||
}
|
||||
await submitQualificationReview()
|
||||
if (store.company.auditStatus === 'PENDING') qualificationOpen.value = false
|
||||
}
|
||||
|
||||
async function submitQualificationReview() {
|
||||
if (!canSubmitQualificationReview.value || reviewSubmitting.value) return
|
||||
reviewSubmitting.value = true
|
||||
@@ -450,6 +471,34 @@ async function submitQualificationReview() {
|
||||
}
|
||||
}
|
||||
|
||||
function qualificationDeleteDisabled(record: TenantQualification) {
|
||||
return deletingQualificationId.value === record.id
|
||||
|| !auth.hasPermission('company:qualification:upload')
|
||||
|| !canUploadQualification.value
|
||||
}
|
||||
|
||||
async function deleteQualification(record: TenantQualification) {
|
||||
if (qualificationDeleteDisabled(record)) return
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`确认删除资质文件“${record.fileName}”?删除后如需送审必须重新上传。`,
|
||||
'删除资质文件',
|
||||
{ type: 'warning', confirmButtonText: '确认删除', cancelButtonText: '取消' },
|
||||
)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
deletingQualificationId.value = record.id
|
||||
try {
|
||||
await store.deleteQualification(record.id)
|
||||
ElMessage.success('资质文件已删除')
|
||||
} catch (error) {
|
||||
ElMessage.error(error instanceof Error ? error.message : '资质文件删除失败')
|
||||
} finally {
|
||||
deletingQualificationId.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
async function previewQualification(record: TenantQualification) {
|
||||
if (previewUrl.value) URL.revokeObjectURL(previewUrl.value)
|
||||
previewRecord.value = record
|
||||
@@ -548,7 +597,10 @@ function closeQualificationPreview() {
|
||||
:total="store.qualifications.length"
|
||||
row-key="id"
|
||||
>
|
||||
<template #actions="{ row }"><el-button link type="primary" @click="previewQualification(row as TenantQualification)">查看</el-button></template>
|
||||
<template #actions="{ row }">
|
||||
<el-button link type="primary" @click="previewQualification(row as TenantQualification)">查看</el-button>
|
||||
<el-button link type="danger" :loading="deletingQualificationId === (row as TenantQualification).id" :disabled="qualificationDeleteDisabled(row as TenantQualification)" @click="deleteQualification(row as TenantQualification)">删除</el-button>
|
||||
</template>
|
||||
<template #status="{ row }"><el-tag :type="qualificationStatusMeta(row.status).type" effect="light">{{ qualificationStatusMeta(row.status).label }}</el-tag></template>
|
||||
</DataTable>
|
||||
<div class="mobile-qualification-list">
|
||||
@@ -556,7 +608,10 @@ function closeQualificationPreview() {
|
||||
<header><strong>{{ record.type }}</strong><el-tag :type="qualificationStatusMeta(record.status).type" effect="light">{{ qualificationStatusMeta(record.status).label }}</el-tag></header>
|
||||
<div class="qualification-file-name"><FileText :size="16" /><span>{{ record.fileName }}</span></div>
|
||||
<dl><div><dt>有效期</dt><dd>{{ record.expiresAt }}</dd></div><div><dt>更新时间</dt><dd>{{ record.updatedAt }}</dd></div></dl>
|
||||
<el-button link type="primary" @click="previewQualification(record)">查看文件信息</el-button>
|
||||
<div class="mobile-qualification-actions">
|
||||
<el-button link type="primary" @click="previewQualification(record)">查看文件信息</el-button>
|
||||
<el-button link type="danger" :loading="deletingQualificationId === record.id" :disabled="qualificationDeleteDisabled(record)" @click="deleteQualification(record)">删除</el-button>
|
||||
</div>
|
||||
</article>
|
||||
<div v-if="store.qualifications.length === 0" class="client-empty">暂无企业资质记录。</div>
|
||||
</div>
|
||||
@@ -612,11 +667,11 @@ function closeQualificationPreview() {
|
||||
:key="`${item.value}-${item.inputVersion}`"
|
||||
:auto-upload="false"
|
||||
:show-file-list="false"
|
||||
accept=".pdf,.jpg,.jpeg,.png,application/pdf,image/jpeg,image/png"
|
||||
accept=".pdf,.jpg,.jpeg,.png,.bmp,application/pdf,image/jpeg,image/png,image/bmp,image/x-ms-bmp"
|
||||
@change="handleQualificationFileChange(item.value, $event)"
|
||||
>
|
||||
<el-button :disabled="qualificationSubmitting"><Upload :size="16" />{{ qualificationRecord(item.value) ? '替换文件' : '选择文件' }}</el-button>
|
||||
<template #tip><div class="upload-tip">支持 PDF、JPG、PNG,单个文件不超过 5MB。</div></template>
|
||||
<template #tip><div class="upload-tip">支持 PDF、JPG、PNG、BMP,单个文件不超过 5MB。</div></template>
|
||||
</el-upload>
|
||||
<div v-if="item.fileName" class="selected-qualification-file" aria-live="polite">
|
||||
<a v-if="item.previewUrl" class="selected-file-preview" :href="item.previewUrl" target="_blank" rel="noopener" :aria-label="`查看${item.label}图片预览`">
|
||||
@@ -634,7 +689,7 @@ function closeQualificationPreview() {
|
||||
<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>
|
||||
<template #footer><el-button :disabled="qualificationSubmitting || reviewSubmitting" @click="qualificationOpen = false">取消</el-button><el-button :loading="qualificationSubmitting" :disabled="!canSaveQualificationBatch || reviewSubmitting" @click="submitQualification()">保存草稿</el-button><el-button type="primary" :loading="qualificationSubmitting || reviewSubmitting" :disabled="selectedQualificationCount > 0 ? !canSaveQualificationBatch : !canSubmitQualificationReview" @click="submitQualificationAndReview">提交审核</el-button></template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="previewOpen" :title="`${previewRecord?.type || '资质文件'}详情`" width="min(560px, 92vw)" @closed="closeQualificationPreview">
|
||||
@@ -692,6 +747,7 @@ function closeQualificationPreview() {
|
||||
.form-grid-two { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 16px; }
|
||||
.form-grid-two .full-row { grid-column: 1 / -1; }
|
||||
.drawer-actions { display: flex; justify-content: flex-end; gap: 8px; }
|
||||
.mobile-qualification-actions { display: flex; align-items: center; gap: 8px; }
|
||||
.qualification-dialog-intro { display: flex; align-items: flex-start; justify-content: space-between; gap: 18px; margin-bottom: 16px; padding: 13px 15px; background: #f4f7f7; }
|
||||
.qualification-dialog-intro strong { color: var(--navy); font-size: 13px; }
|
||||
.qualification-dialog-intro span { max-width: 420px; color: var(--muted); font-size: 11px; line-height: 1.6; text-align: right; }
|
||||
|
||||
@@ -8,6 +8,7 @@ const membersSource = fs.readFileSync(new URL('./MembersView.vue', import.meta.u
|
||||
const rolesSource = fs.readFileSync(new URL('./RolesView.vue', import.meta.url), 'utf8')
|
||||
const permissionsSource = fs.readFileSync(new URL('./PermissionsView.vue', import.meta.url), 'utf8')
|
||||
const storeSource = fs.readFileSync(new URL('../store/tenantAdministration.ts', import.meta.url), 'utf8')
|
||||
const apiSource = fs.readFileSync(new URL('../api/merchantIam.ts', import.meta.url), 'utf8')
|
||||
|
||||
test('routes tenant administration modules to implemented views instead of the placeholder', () => {
|
||||
assert.match(routerSource, /path: 'company\/profile'[\s\S]*?CompanyProfileView\.vue/)
|
||||
@@ -23,7 +24,7 @@ test('implements company details, contact information and qualification workflow
|
||||
assert.match(profileSource, /联系信息/)
|
||||
assert.match(profileSource, /资质文件/)
|
||||
assert.match(profileSource, /async function saveProfile\(\)/)
|
||||
assert.match(profileSource, /function submitQualification\(\)/)
|
||||
assert.match(profileSource, /function submitQualification\(closeDialog = true\)/)
|
||||
assert.match(profileSource, /validateQualificationFile/)
|
||||
assert.match(profileSource, /function removeSelectedFile\(type: MerchantQualificationType\)/)
|
||||
assert.match(profileSource, /qualificationSubmitting/)
|
||||
@@ -32,7 +33,9 @@ test('implements company details, contact information and qualification workflow
|
||||
assert.match(profileSource, /:key="`\$\{item\.value\}-\$\{item\.inputVersion\}`"/)
|
||||
assert.match(profileSource, /class="qualification-upload-grid"/)
|
||||
assert.match(profileSource, /v-for="item in qualificationDrafts"/)
|
||||
assert.match(profileSource, /保存全部资质/)
|
||||
assert.match(profileSource, /保存草稿/)
|
||||
assert.match(profileSource, /提交审核/)
|
||||
assert.match(profileSource, /async function submitQualificationAndReview\(\)/)
|
||||
assert.match(profileSource, /uploadMerchantRequiredQualificationPackage/)
|
||||
assert.match(profileSource, /const requiredPackageFilesSelected = computed/)
|
||||
assert.match(profileSource, /item\.uploadState = 'uploading'/)
|
||||
@@ -69,6 +72,8 @@ test('implements company details, contact information and qualification workflow
|
||||
assert.match(profileSource, /const requiredQualificationTypes = qualificationTypes\.filter\(\(type\) => type\.required\)/)
|
||||
assert.match(profileSource, /货代资质证书'.*required: false/)
|
||||
assert.match(profileSource, /法人身份证'.*required: false/)
|
||||
assert.match(profileSource, /accept="\.pdf,\.jpg,\.jpeg,\.png,\.bmp,application\/pdf,image\/jpeg,image\/png,image\/bmp,image\/x-ms-bmp"/)
|
||||
assert.match(profileSource, /支持 PDF、JPG、PNG、BMP/)
|
||||
assert.match(profileSource, /银行开户许可证'.*required: false/)
|
||||
assert.match(profileSource, /requiredQualificationTypes\.every/)
|
||||
assert.doesNotMatch(profileSource, /四类必填资质/)
|
||||
@@ -79,6 +84,17 @@ test('implements company details, contact information and qualification workflow
|
||||
assert.match(profileSource, /法人身份证已保存,尚未提交审核/)
|
||||
assert.match(profileSource, /qualificationUploadErrorMessage\(error\)/)
|
||||
assert.match(profileSource, /submitTenantQualificationReview/)
|
||||
assert.match(apiSource, /function deleteTenantQualification\(qualificationId: number \| string\)/)
|
||||
assert.match(apiSource, /method: 'DELETE'/)
|
||||
assert.match(apiSource, /`\/merchant\/v1\/iam\/tenant\/qualifications\/\$\{qualificationId\}`/)
|
||||
assert.match(profileSource, /function qualificationDeleteDisabled\(record: TenantQualification\)/)
|
||||
assert.match(profileSource, /!canUploadQualification\.value/)
|
||||
assert.match(profileSource, /store\.deleteQualification\(record\.id\)/)
|
||||
assert.match(profileSource, /资质文件已删除/)
|
||||
assert.match(profileSource, /:disabled="qualificationDeleteDisabled\(row as TenantQualification\)"/)
|
||||
assert.match(profileSource, /:disabled="qualificationDeleteDisabled\(record\)"/)
|
||||
assert.match(storeSource, /originalFileName\?\.trim\(\) \|\| '—'/)
|
||||
assert.match(storeSource, /formatQualificationUpdatedAt\(item\.updatedAt\)/)
|
||||
assert.match(profileSource, /提交企业审核/)
|
||||
assert.match(profileSource, /资质文件已保存,尚未提交审核/)
|
||||
assert.match(profileSource, /资质文件已保存,但最新状态刷新失败/)
|
||||
@@ -105,6 +121,8 @@ test('implements company details, contact information and qualification workflow
|
||||
assert.match(profileSource, /pattern: \/\^\[0-9-\]\{4,32\}\$\//)
|
||||
assert.doesNotMatch(profileSource, /<dt>联系电话<\/dt><dd>\{\{ store\.company\.contactPhone/)
|
||||
assert.match(storeSource, /expiresAt: item\.validTo \|\| '长期有效'/)
|
||||
assert.match(storeSource, /fileName: item\.originalFileName\?\.trim\(\) \|\| '—'/)
|
||||
assert.match(storeSource, /updatedAt: formatQualificationUpdatedAt\(item\.updatedAt\)/)
|
||||
})
|
||||
|
||||
test('implements member list, role assignment, password reset and status control', () => {
|
||||
|
||||
Reference in New Issue
Block a user