-
+
-
+
重置保存并重新登录
diff --git a/src/modules/auth/views/AuthViews.test.mjs b/src/modules/auth/views/AuthViews.test.mjs
index 00167c9..a41ff01 100644
--- a/src/modules/auth/views/AuthViews.test.mjs
+++ b/src/modules/auth/views/AuthViews.test.mjs
@@ -53,6 +53,8 @@ test('implements every backend registration field and real submission', () => {
for (const field of ['username', 'companyName', 'displayName', 'legalPerson', 'legalPhone', 'contactEmail', 'countryCode', 'address', 'password', 'agreement']) {
assert.match(registerSource, new RegExp(`prop="${field}"`))
}
+ assert.match(registerSource, /label="登录手机号" prop="legalPhone"/)
+ assert.match(registerSource, /注册时同时初始化公司联系电话;注册后两者可分别修改,互不联动/)
assert.match(registerSource, /registerMerchant\(/)
assert.match(registerSource, /4–64 位/)
assert.match(registerSource, /8–72 位/)
diff --git a/src/modules/auth/views/RegisterView.vue b/src/modules/auth/views/RegisterView.vue
index 3b07e2b..3e683e0 100644
--- a/src/modules/auth/views/RegisterView.vue
+++ b/src/modules/auth/views/RegisterView.vue
@@ -131,7 +131,7 @@ async function submit() {
-
+ 注册时同时初始化公司联系电话;注册后两者可分别修改,互不联动。
diff --git a/src/modules/tenant-management/api/merchantIam.test.mjs b/src/modules/tenant-management/api/merchantIam.test.mjs
index db73402..bb0cb5f 100644
--- a/src/modules/tenant-management/api/merchantIam.test.mjs
+++ b/src/modules/tenant-management/api/merchantIam.test.mjs
@@ -78,6 +78,8 @@ test('starts empty and only loads server role and member records', () => {
assert.match(storeSource, /await resetMerchantMemberPassword/)
assert.match(source, /username: string/)
assert.match(source, /lastLoginAt: string \| null/)
+ assert.match(source, /phone: string \| null/)
+ assert.match(storeSource, /phone: payload\.phone\.trim\(\) \|\| null/)
assert.match(source, /memberCount: number/)
assert.match(storeSource, /account: member\.username/)
assert.match(storeSource, /lastLoginAt: formatLastLoginAt\(member\.lastLoginAt\)/)
diff --git a/src/modules/tenant-management/api/merchantIam.ts b/src/modules/tenant-management/api/merchantIam.ts
index 2a06f58..6a1b2cc 100644
--- a/src/modules/tenant-management/api/merchantIam.ts
+++ b/src/modules/tenant-management/api/merchantIam.ts
@@ -129,8 +129,8 @@ export interface CreateMerchantMemberRequest {
username: string
password: string
displayName: string
- phone: string
- email: string
+ phone: string | null
+ email: string | null
memberType: 'EMPLOYEE'
memberNo: string
roleIds: Array
@@ -138,8 +138,8 @@ export interface CreateMerchantMemberRequest {
export interface UpdateMerchantMemberRequest {
displayName: string
- phone: string
- email: string
+ phone: string | null
+ email: string | null
memberType: string
memberNo: string
roleIds: Array
diff --git a/src/modules/tenant-management/store/tenantAdministration.ts b/src/modules/tenant-management/store/tenantAdministration.ts
index c1e17e1..5331a45 100644
--- a/src/modules/tenant-management/store/tenantAdministration.ts
+++ b/src/modules/tenant-management/store/tenantAdministration.ts
@@ -234,8 +234,8 @@ export const useTenantAdministrationStore = defineStore('tenant-administration',
username: payload.account.trim(),
password: payload.password,
displayName: payload.name.trim(),
- phone: payload.phone.trim(),
- email: payload.email.trim(),
+ phone: payload.phone.trim() || null,
+ email: payload.email.trim() || null,
memberType: 'EMPLOYEE',
memberNo: payload.memberNo.trim(),
roleIds: payload.roleIds,
@@ -248,8 +248,8 @@ export const useTenantAdministrationStore = defineStore('tenant-administration',
if (!member) throw new Error('成员不存在')
const updated = await updateMerchantMember(id, {
displayName: payload.name.trim(),
- phone: payload.phone.trim(),
- email: payload.email.trim(),
+ phone: payload.phone.trim() || null,
+ email: payload.email.trim() || null,
memberType: member.isAdministrator ? 'OWNER' : 'EMPLOYEE',
memberNo: payload.memberNo.trim(),
roleIds: payload.roleIds,
diff --git a/src/modules/tenant-management/views/CompanyProfileView.vue b/src/modules/tenant-management/views/CompanyProfileView.vue
index f49f27c..a1a1227 100644
--- a/src/modules/tenant-management/views/CompanyProfileView.vue
+++ b/src/modules/tenant-management/views/CompanyProfileView.vue
@@ -150,7 +150,7 @@ const profileFormRules: FormRules = {
companyName: [{ required: true, whitespace: true, message: '请输入公司名称', trigger: 'blur' }],
legalRepresentative: [{ 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' }],
contactEmail: [{ type: 'email', message: '请输入正确的联系邮箱', trigger: 'blur' }],
}
const qualificationColumns: DataTableColumn[] = [
@@ -516,7 +516,7 @@ function closeQualificationPreview() {
- 联系人
- {{ store.company.contactName || '-' }}
- - 联系电话
- {{ store.company.contactPhone || '-' }}
+ - 公司联系电话
- {{ store.company.contactPhone || '-' }}
- 联系邮箱
- {{ store.company.contactEmail || '-' }}
- 联系微信
- {{ store.company.contactWechat || '-' }}
@@ -571,7 +571,7 @@ function closeQualificationPreview() {
联系信息
-
+ 仅用于公司业务联系,不会修改任何成员的登录手机号。
@@ -684,6 +684,7 @@ function closeQualificationPreview() {
.mobile-qualification-list { display: none; }
.profile-form h3 { margin: 4px 0 18px; padding-bottom: 10px; border-bottom: 1px solid var(--border); font-size: 15px; }
.profile-form h3:not(:first-child) { margin-top: 22px; }
+.profile-field-hint { display: block; margin-top: 5px; color: var(--muted); font-size: 10px; line-height: 1.5; }
.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; }
diff --git a/src/modules/tenant-management/views/MembersView.vue b/src/modules/tenant-management/views/MembersView.vue
index 4dc0154..4d09626 100644
--- a/src/modules/tenant-management/views/MembersView.vue
+++ b/src/modules/tenant-management/views/MembersView.vue
@@ -30,19 +30,19 @@ const memberRules: FormRules = {
{ required: true, message: '请输入初始密码', trigger: 'blur' },
{ pattern: /^(?=.*[A-Za-z])(?=.*\d).{8,64}$/, message: '密码需为 8–64 位,并同时包含字母和数字', trigger: 'blur' },
],
- phone: [{ max: 32, message: '联系电话不能超过 32 个字符', trigger: 'blur' }],
+ phone: [{ pattern: /^1[3-9]\d{9}$/, message: '请输入有效的中国大陆登录手机号', trigger: 'blur' }],
email: [{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }],
roleIds: [{ type: 'array', required: true, min: 1, message: '请至少选择一个成员角色', trigger: 'change' }],
}
const memberQueryFields: QueryField[] = [
- { key: 'keyword', type: 'input', placeholder: '姓名、账号、手机或邮箱' },
+ { key: 'keyword', type: 'input', placeholder: '姓名、账号、登录手机号或邮箱' },
{ key: 'status', type: 'select', placeholder: '全部状态', options: [{ label: '正常', value: 'ACTIVE' }, { label: '已停用', value: 'INACTIVE' }] },
]
const memberTableColumns: DataTableColumn[] = [
{ key: 'actions', label: '操作', fixed: 'left', width: 230, slotName: 'actions' },
{ key: 'member', label: '成员', minWidth: 170, slotName: 'member' },
- { key: 'contact', label: '联系方式', minWidth: 200, slotName: 'contact' },
+ { key: 'contact', label: '登录手机号 / 邮箱', minWidth: 200, slotName: 'contact' },
{ key: 'roles', label: '角色', minWidth: 130, slotName: 'roles' },
{ key: 'lastLoginAt', prop: 'lastLoginAt', label: '登录记录', minWidth: 130 },
{ key: 'status', label: '状态', width: 90, slotName: 'status' },
@@ -176,7 +176,7 @@ async function resetPassword(member: TenantMember) {
编辑重置密码{{ (row as TenantMember).status === 'ACTIVE' ? '停用' : '启用' }}仅查看
{{ (row as TenantMember).name.slice(0, 1) }}{{ (row as TenantMember).name }}{{ (row as TenantMember).account }}
- {{ (row as TenantMember).phone }}{{ (row as TenantMember).email || '-' }}
+ {{ (row as TenantMember).phone || '-' }}{{ (row as TenantMember).email || '-' }}
{{ name }}未分配
{{ (row as TenantMember).status === 'ACTIVE' ? '正常' : '已停用' }}
没有匹配的企业成员,请调整筛选条件。
@@ -186,7 +186,7 @@ async function resetPassword(member: TenantMember) {
- - 手机
- {{ member.phone }}
- 最近登录
- {{ member.lastLoginAt }}
- 角色
- {{ store.roleNames(member.roleIds).join('、') }}
+ - 登录手机号
- {{ member.phone || '-' }}
- 最近登录
- {{ member.lastLoginAt }}
- 角色
- {{ store.roleNames(member.roleIds).join('、') }}
@@ -199,7 +199,7 @@ async function resetPassword(member: TenantMember) {
-
+ 用于该成员手机号登录;修改后会同步认证账号。
请通过安全渠道将初始密码交给成员;前端不会保存或再次展示该密码。
@@ -225,6 +225,7 @@ async function resetPassword(member: TenantMember) {
.mobile-member-list, .mobile-member-empty { display: none; }
.member-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.member-form-tip { display: flex; gap: 10px; padding: 13px; border: 1px solid #cfe1dc; background: #f2f7f6; color: var(--muted); font-size: 11px; line-height: 1.6; }
+.member-field-help { margin-top: 5px; color: var(--muted); font-size: 10px; line-height: 1.5; }
.member-form-tip svg { flex: 0 0 17px; color: var(--primary); }
.drawer-actions { display: flex; justify-content: flex-end; gap: 8px; }
.members-page :deep(.el-form-item__error) { line-height: 1.45; overflow-wrap: anywhere; }
diff --git a/src/modules/tenant-management/views/TenantAdministrationViews.test.mjs b/src/modules/tenant-management/views/TenantAdministrationViews.test.mjs
index c7815e4..a0d53f1 100644
--- a/src/modules/tenant-management/views/TenantAdministrationViews.test.mjs
+++ b/src/modules/tenant-management/views/TenantAdministrationViews.test.mjs
@@ -94,6 +94,10 @@ test('implements company details, contact information and qualification workflow
assert.match(profileSource, /成立日期<\/dt>\{\{ store\.company\.establishedDate/)
assert.match(profileSource, /注册资本<\/dt>\{\{ store\.company\.registeredCapital/)
assert.match(profileSource, /联系微信<\/dt>\{\{ store\.company\.contactWechat/)
+ assert.match(profileSource, /公司联系电话<\/dt>\{\{ store\.company\.contactPhone/)
+ assert.match(profileSource, /label="公司联系电话" prop="contactPhone" required/)
+ assert.match(profileSource, /不会修改任何成员的登录手机号/)
+ assert.doesNotMatch(profileSource, /联系电话<\/dt>\{\{ store\.company\.contactPhone/)
assert.match(storeSource, /expiresAt: item\.validTo \|\| '长期有效'/)
})
@@ -135,6 +139,11 @@ test('implements member list, role assignment, password reset and status control
assert.match(membersSource, /canChangeMemberStatus.*company:member:status/)
assert.doesNotMatch(membersSource, /company:member:write/)
assert.doesNotMatch(membersSource, /member-metrics/)
+ assert.match(membersSource, /label="登录手机号" prop="phone"/)
+ assert.match(membersSource, /登录手机号 \/ 邮箱/)
+ assert.match(membersSource, /用于该成员手机号登录;修改后会同步认证账号/)
+ assert.match(membersSource, /phone: \[\{ pattern: \/\^1\[3-9\]\\d\{9\}\$\//)
+ assert.doesNotMatch(membersSource, /label="联系电话" prop="phone"/)
})
test('protects built-in roles and exposes role permission assignment', () => {