This commit is contained in:
2026-09-02 10:15:51 +08:00
parent 6dcea387d3
commit 7d97be6450
3 changed files with 21 additions and 7 deletions
@@ -83,6 +83,7 @@ const normalizedQualificationCertificateNo = computed(() => qualificationCertifi
const draftCreditCodeValid = computed(() => unifiedSocialCreditCodePattern.test(normalizedQualificationCertificateNo.value)) const draftCreditCodeValid = computed(() => unifiedSocialCreditCodePattern.test(normalizedQualificationCertificateNo.value))
const businessLicenseFileSelected = computed(() => Boolean(qualificationDraftItem('BUSINESS_LICENSE')?.file)) const businessLicenseFileSelected = computed(() => Boolean(qualificationDraftItem('BUSINESS_LICENSE')?.file))
const legalPersonIdFileSelected = computed(() => Boolean(qualificationDraftItem('LEGAL_PERSON_ID')?.file)) const legalPersonIdFileSelected = computed(() => Boolean(qualificationDraftItem('LEGAL_PERSON_ID')?.file))
const standaloneLegalPersonIdUnsupported = computed(() => legalPersonIdFileSelected.value && !businessLicenseFileSelected.value)
const requiredPackageChangeSelected = computed(() => businessLicenseFileSelected.value) const requiredPackageChangeSelected = computed(() => businessLicenseFileSelected.value)
const requiredPackageFilesSelected = computed(() => businessLicenseFileSelected.value) const requiredPackageFilesSelected = computed(() => businessLicenseFileSelected.value)
const qualificationCreditCodeReady = computed(() => requiredPackageChangeSelected.value const qualificationCreditCodeReady = computed(() => requiredPackageChangeSelected.value
@@ -90,7 +91,6 @@ const qualificationCreditCodeReady = computed(() => requiredPackageChangeSelecte
: companyCreditCodeValid.value) : companyCreditCodeValid.value)
const qualificationCreditCodeError = computed(() => { const qualificationCreditCodeError = computed(() => {
if (qualificationCreditCodeReady.value) return '' if (qualificationCreditCodeReady.value) return ''
if (legalPersonIdFileSelected.value && !businessLicenseFileSelected.value) return '法人身份证需与本次营业执照一起保存'
if (draftCreditCodeValid.value && !requiredPackageFilesSelected.value) return '统一社会信用代码必须随营业执照共同保存' if (draftCreditCodeValid.value && !requiredPackageFilesSelected.value) return '统一社会信用代码必须随营业执照共同保存'
return '请输入18位字母或数字组成的统一社会信用代码' return '请输入18位字母或数字组成的统一社会信用代码'
}) })
@@ -122,11 +122,11 @@ const qualificationUploadDisabledReason = computed(() => {
const selectedQualificationCount = computed(() => qualificationDrafts.filter((item) => Boolean(item.file)).length) const selectedQualificationCount = computed(() => qualificationDrafts.filter((item) => Boolean(item.file)).length)
const canSaveQualificationBatch = computed(() => canUploadQualification.value const canSaveQualificationBatch = computed(() => canUploadQualification.value
&& selectedQualificationCount.value > 0 && selectedQualificationCount.value > 0
&& (!legalPersonIdFileSelected.value || businessLicenseFileSelected.value) && !standaloneLegalPersonIdUnsupported.value
&& requiredPackageComplete.value) && requiredPackageComplete.value)
const qualificationSaveDisabledReason = computed(() => { const qualificationSaveDisabledReason = computed(() => {
if (!canUploadQualification.value) return qualificationUploadDisabledReason.value if (!canUploadQualification.value) return qualificationUploadDisabledReason.value
if (legalPersonIdFileSelected.value && !businessLicenseFileSelected.value) return '法人身份证需与本次营业执照一起保存' if (standaloneLegalPersonIdUnsupported.value) return '法人身份证为选填项;当前文件服务尚未开放单独保存,请取消本次选择后保存其他资质。'
if (!requiredPackageComplete.value) return `请完整保存必填业务项:${missingRequiredPackageItems.value.join('、')}` if (!requiredPackageComplete.value) return `请完整保存必填业务项:${missingRequiredPackageItems.value.join('、')}`
if (!selectedQualificationCount.value) return '当前没有需要保存的变更' if (!selectedQualificationCount.value) return '当前没有需要保存的变更'
return '' return ''
@@ -150,7 +150,10 @@ const profileFormRules: FormRules<TenantCompanyProfile> = {
companyName: [{ required: true, whitespace: true, message: '请输入公司名称', trigger: 'blur' }], companyName: [{ required: true, whitespace: true, message: '请输入公司名称', trigger: 'blur' }],
legalRepresentative: [{ required: true, whitespace: true, message: '请输入法人姓名', trigger: 'blur' }], legalRepresentative: [{ required: true, whitespace: true, message: '请输入法人姓名', trigger: 'blur' }],
contactName: [{ required: true, whitespace: true, message: '请输入联系人姓名', trigger: 'blur' }], contactName: [{ required: true, whitespace: true, message: '请输入联系人姓名', trigger: 'blur' }],
contactPhone: [{ required: true, whitespace: true, message: '请输入公司联系电话', trigger: 'blur' }], contactPhone: [
{ required: true, whitespace: true, message: '请输入公司联系电话', trigger: 'blur' },
{ pattern: /^[0-9-]{4,32}$/, message: '公司联系电话仅支持 4–32 位数字或连字符', trigger: 'blur' },
],
contactEmail: [{ type: 'email', message: '请输入正确的联系邮箱', trigger: 'blur' }], contactEmail: [{ type: 'email', message: '请输入正确的联系邮箱', trigger: 'blur' }],
} }
const qualificationColumns: DataTableColumn[] = [ const qualificationColumns: DataTableColumn[] = [
@@ -337,6 +340,13 @@ async function submitQualification() {
ElMessage.warning(qualificationUploadDisabledReason.value) ElMessage.warning(qualificationUploadDisabledReason.value)
return return
} }
if (standaloneLegalPersonIdUnsupported.value) {
const legalPersonId = qualificationDraftItem('LEGAL_PERSON_ID')
const message = '当前文件服务尚未开放法人身份证单独上传或替换,该选填文件未提交。'
if (legalPersonId) { legalPersonId.error = message; legalPersonId.uploadState = 'error' }
ElMessage.warning(message)
return
}
if (!requiredPackageComplete.value) { if (!requiredPackageComplete.value) {
const businessLicense = qualificationDraftItem('BUSINESS_LICENSE') const businessLicense = qualificationDraftItem('BUSINESS_LICENSE')
if (businessLicense && !qualificationCreditCodeReady.value) businessLicense.error = qualificationCreditCodeError.value if (businessLicense && !qualificationCreditCodeReady.value) businessLicense.error = qualificationCreditCodeError.value
@@ -571,7 +581,7 @@ function closeQualificationPreview() {
<h3>联系信息</h3> <h3>联系信息</h3>
<div class="form-grid-two"> <div class="form-grid-two">
<el-form-item label="联系人" prop="contactName" required><el-input v-model="draft.contactName" placeholder="请输入联系人姓名" /></el-form-item> <el-form-item label="联系人" prop="contactName" required><el-input v-model="draft.contactName" placeholder="请输入联系人姓名" /></el-form-item>
<el-form-item label="公司联系电话" prop="contactPhone" required><el-input v-model="draft.contactPhone" placeholder="请输入公司联系电话" /><small class="profile-field-hint">仅用于公司业务联系,不会修改任何成员的登录手机号。</small></el-form-item> <el-form-item label="公司联系电话" prop="contactPhone" required><el-input v-model="draft.contactPhone" maxlength="32" inputmode="tel" placeholder="请输入公司联系电话" /><small class="profile-field-hint">仅用于公司业务联系,不会修改任何成员的登录手机号。</small></el-form-item>
<el-form-item label="联系邮箱" prop="contactEmail"><el-input v-model="draft.contactEmail" placeholder="请输入联系邮箱(选填)" /></el-form-item> <el-form-item label="联系邮箱" prop="contactEmail"><el-input v-model="draft.contactEmail" placeholder="请输入联系邮箱(选填)" /></el-form-item>
</div> </div>
</el-form> </el-form>
@@ -199,7 +199,7 @@ async function resetPassword(member: TenantMember) {
<el-form-item label="成员姓名" prop="name" required><el-input v-model="form.name" maxlength="64" placeholder="例如 张三" /></el-form-item> <el-form-item label="成员姓名" prop="name" required><el-input v-model="form.name" maxlength="64" placeholder="例如 张三" /></el-form-item>
<el-form-item label="登录账号" prop="account" required><el-input v-model="form.account" :disabled="Boolean(editingId)" maxlength="64" placeholder="4–64 位字母、数字或 _ . @ -" /></el-form-item> <el-form-item label="登录账号" prop="account" required><el-input v-model="form.account" :disabled="Boolean(editingId)" maxlength="64" placeholder="4–64 位字母、数字或 _ . @ -" /></el-form-item>
<el-form-item v-if="!editingId" label="初始密码" prop="password" required><el-input v-model="form.password" type="password" show-password autocomplete="new-password" maxlength="64" placeholder="8–64 位,同时包含字母和数字" /></el-form-item> <el-form-item v-if="!editingId" label="初始密码" prop="password" required><el-input v-model="form.password" type="password" show-password autocomplete="new-password" maxlength="64" placeholder="8–64 位,同时包含字母和数字" /></el-form-item>
<div class="member-form-grid"><el-form-item label="登录手机号" prop="phone"><el-input v-model="form.phone" maxlength="11" inputmode="tel" autocomplete="tel" placeholder="例如 13800138000(选填)" /><span class="member-field-help">用于该成员手机号登录;修改后会同步认证账号。</span></el-form-item><el-form-item label="邮箱" prop="email"><el-input v-model="form.email" maxlength="128" placeholder="例如 name@example.com(选填)" /></el-form-item></div> <div class="member-form-grid"><el-form-item label="登录手机号" prop="phone"><el-input v-model="form.phone" maxlength="11" inputmode="tel" autocomplete="tel" placeholder="例如 13800138000(选填)" /><span class="member-field-help">用于该成员手机号登录;修改后会同步认证账号并退出该成员现有会话。</span></el-form-item><el-form-item label="邮箱" prop="email"><el-input v-model="form.email" maxlength="128" placeholder="例如 name@example.com(选填)" /></el-form-item></div>
<el-form-item label="成员角色" prop="roleIds" required><el-select v-model="form.roleIds" multiple :disabled="Boolean(editingId) && !canGrantMemberRole" placeholder="请选择角色"><el-option v-for="role in store.roles.filter((item) => item.status === 'ACTIVE' && (!item.builtin || form.roleIds.includes(item.id)))" :key="role.id" :label="role.name" :value="role.id" :disabled="role.builtin" /></el-select></el-form-item> <el-form-item label="成员角色" prop="roleIds" required><el-select v-model="form.roleIds" multiple :disabled="Boolean(editingId) && !canGrantMemberRole" placeholder="请选择角色"><el-option v-for="role in store.roles.filter((item) => item.status === 'ACTIVE' && (!item.builtin || form.roleIds.includes(item.id)))" :key="role.id" :label="role.name" :value="role.id" :disabled="role.builtin" /></el-select></el-form-item>
<div v-if="!editingId" class="member-form-tip"><KeyRound :size="17" /><span>请通过安全渠道将初始密码交给成员;前端不会保存或再次展示该密码。</span></div> <div v-if="!editingId" class="member-form-tip"><KeyRound :size="17" /><span>请通过安全渠道将初始密码交给成员;前端不会保存或再次展示该密码。</span></div>
</el-form> </el-form>
@@ -72,6 +72,9 @@ test('implements company details, contact information and qualification workflow
assert.match(profileSource, /银行开户许可证'.*required: false/) assert.match(profileSource, /银行开户许可证'.*required: false/)
assert.match(profileSource, /requiredQualificationTypes\.every/) assert.match(profileSource, /requiredQualificationTypes\.every/)
assert.doesNotMatch(profileSource, /四类必填资质/) assert.doesNotMatch(profileSource, /四类必填资质/)
assert.doesNotMatch(profileSource, /法人身份证需与本次营业执照一起保存/)
assert.match(profileSource, /const standaloneLegalPersonIdUnsupported = computed/)
assert.match(profileSource, /当前文件服务尚未开放法人身份证单独上传或替换,该选填文件未提交/)
assert.match(profileSource, /qualificationUploadErrorMessage\(error\)/) assert.match(profileSource, /qualificationUploadErrorMessage\(error\)/)
assert.match(profileSource, /submitTenantQualificationReview/) assert.match(profileSource, /submitTenantQualificationReview/)
assert.match(profileSource, /提交企业审核/) assert.match(profileSource, /提交企业审核/)
@@ -97,6 +100,7 @@ test('implements company details, contact information and qualification workflow
assert.match(profileSource, /<dt>公司联系电话<\/dt><dd>\{\{ store\.company\.contactPhone/) assert.match(profileSource, /<dt>公司联系电话<\/dt><dd>\{\{ store\.company\.contactPhone/)
assert.match(profileSource, /label="公司联系电话" prop="contactPhone" required/) assert.match(profileSource, /label="公司联系电话" prop="contactPhone" required/)
assert.match(profileSource, /不会修改任何成员的登录手机号/) assert.match(profileSource, /不会修改任何成员的登录手机号/)
assert.match(profileSource, /pattern: \/\^\[0-9-\]\{4,32\}\$\//)
assert.doesNotMatch(profileSource, /<dt>联系电话<\/dt><dd>\{\{ store\.company\.contactPhone/) assert.doesNotMatch(profileSource, /<dt>联系电话<\/dt><dd>\{\{ store\.company\.contactPhone/)
assert.match(storeSource, /expiresAt: item\.validTo \|\| '长期有效'/) assert.match(storeSource, /expiresAt: item\.validTo \|\| '长期有效'/)
}) })
@@ -141,7 +145,7 @@ test('implements member list, role assignment, password reset and status control
assert.doesNotMatch(membersSource, /member-metrics/) assert.doesNotMatch(membersSource, /member-metrics/)
assert.match(membersSource, /label="登录手机号" prop="phone"/) assert.match(membersSource, /label="登录手机号" prop="phone"/)
assert.match(membersSource, /登录手机号 \/ 邮箱/) assert.match(membersSource, /登录手机号 \/ 邮箱/)
assert.match(membersSource, /用于该成员手机号登录;修改后会同步认证账号/) assert.match(membersSource, /用于该成员手机号登录;修改后会同步认证账号并退出该成员现有会话/)
assert.match(membersSource, /phone: \[\{ pattern: \/\^1\[3-9\]\\d\{9\}\$\//) assert.match(membersSource, /phone: \[\{ pattern: \/\^1\[3-9\]\\d\{9\}\$\//)
assert.doesNotMatch(membersSource, /label="联系电话" prop="phone"/) assert.doesNotMatch(membersSource, /label="联系电话" prop="phone"/)
}) })