fix(e2e,pc): 不再产生跨租户同名的登录账号
账号唯一性是 (tenant_id, username),跨租户重名本身是合法行为(登录靠租户码区分);但默认值与 e2e 残留会让它变成默认状态:不带租户码登录会撞上 40012(该账号存在于多个单位),平台侧看账号也分不清哪个 admin 属于哪所学校。三处一起收口 —— 1) scripts/e2e-m0.py 跑完不再留租户:以前每跑一次就留下一个 e2e###### 租户 + 里面叫 admin 的管理员 + demo 下 3 个测试组织,库里那两个孤儿租户就是这么来的。现在按本次跑出的 id 自清(崩溃路径也兜住),不越界成 LIKE 'e2e%' 全清。 2) scripts/e2e-m1-tenant-domain.py 自己造、自己清「另一个租户里也有 admin」的夹具:它原本靠第 1 条的残留凑出 40012 这个前提,残留一被清掉就会静默反转成 8 条 FAIL。顺带修掉同族的第二处隐式依赖 —— 它假定 t14.localhost 是个真实租户,而那个租户早就不存在了。 3) PC 端「开通租户」的登录账号默认值不再写死 admin,改为跟随租户编码生成 admin_<编码>;运营一旦手改就不再被编码覆盖。 验证:全量 python scripts/verify-all.py --with-e2e 通过(37 脚本 / 1597 断言 / 0 失败),跑完库里仍只有 1 个租户、0 处跨租户重名;PC 端 pnpm typecheck 0 错、pnpm lint 干净、check-wiring 未接线 0 条,浏览器实演默认值跟随与手改不回退。
This commit is contained in:
@@ -18,7 +18,7 @@ import {
|
||||
NTag,
|
||||
useMessage
|
||||
} from 'naive-ui'
|
||||
import { computed, h, onMounted, reactive, ref } from 'vue'
|
||||
import { computed, h, onMounted, reactive, ref, watch } from 'vue'
|
||||
import * as tenantApi from '@/apis/xt/tenant'
|
||||
import { TENANT_STATUS, TENANT_TYPE_NAMES } from '@/apis/xt/tenant'
|
||||
import { listPagination } from '@/composables/pagination'
|
||||
@@ -55,6 +55,26 @@ const created = ref<TenantCreateResult | null>(null)
|
||||
const createdName = ref('')
|
||||
const formRef = ref<FormInst | null>(null)
|
||||
|
||||
/**
|
||||
* 「首个管理员的登录账号」默认值**按租户编码生成**(`admin_jxjd`),不是写死的 `admin`。
|
||||
*
|
||||
* ⚠️ 为什么不能用固定默认值:账号唯一性是 `(tenant_id, username)`,即"跨租户重名"
|
||||
* 本身是被允许的(登录时靠租户码区分)。但**默认值**固定成 `admin` 的后果是
|
||||
* "运营不动手,每开一所学校就多一个 `admin`" —— 于是不带租户码登录会撞上
|
||||
* `40012 该账号存在于多个单位`,平台侧看账号也分不清是哪所学校的。
|
||||
* 默认值跟着编码走,开一所学校天然不重名;运营仍可以改成自己想要的账号名。
|
||||
*/
|
||||
const ADMIN_USERNAME_PREFIX = 'admin_'
|
||||
/** 人有没有手动改过登录账号:改过就不再被编码覆盖(否则会把人填的值冲掉) */
|
||||
const adminUsernameTouched = ref(false)
|
||||
/** 上一次**自动填出来**的值。用它区分"人改的"与"我们填的"(两者改的是同一个字段) */
|
||||
let autoUsername = ''
|
||||
|
||||
function deriveAdminUsername(code: string): string {
|
||||
const c = code.trim().toLowerCase()
|
||||
return c ? `${ADMIN_USERNAME_PREFIX}${c}` : ''
|
||||
}
|
||||
|
||||
function emptyForm() {
|
||||
return {
|
||||
tenantName: '',
|
||||
@@ -65,7 +85,7 @@ function emptyForm() {
|
||||
// 用 null 而不是 '':n-date-picker 清空时会回传 null,
|
||||
// 声明成 string 会在 v-model 上产生类型打架(运行期没事,但 vue-tsc 会红)
|
||||
expireTime: null as string | null,
|
||||
adminUsername: 'admin',
|
||||
adminUsername: '',
|
||||
adminRealName: '',
|
||||
adminPhone: ''
|
||||
}
|
||||
@@ -199,6 +219,9 @@ function setStatus(v: number | undefined): void {
|
||||
|
||||
function onAdd(): void {
|
||||
Object.assign(form, emptyForm())
|
||||
// 每次打开弹窗都重新开始"跟着编码走"的状态,否则第二次打开时人会发现自己改不动账号名
|
||||
adminUsernameTouched.value = false
|
||||
autoUsername = ''
|
||||
created.value = null
|
||||
visible.value = true
|
||||
}
|
||||
@@ -251,6 +274,23 @@ function closeCreated(): void {
|
||||
visible.value = false
|
||||
}
|
||||
|
||||
// ── 登录账号跟着租户编码走(默认值,人一改就交还给填写者) ──
|
||||
watch(() => form.tenantCode, (code) => {
|
||||
if (adminUsernameTouched.value) {
|
||||
return
|
||||
}
|
||||
autoUsername = deriveAdminUsername(code)
|
||||
form.adminUsername = autoUsername
|
||||
})
|
||||
|
||||
watch(() => form.adminUsername, (v) => {
|
||||
// 只有"值不是我们刚填进去的那个"才算人改的 —— 少了这一层,
|
||||
// 自动填充本身就会把字段标成"已手改",编码再变一次就再也不跟了
|
||||
if (v !== autoUsername) {
|
||||
adminUsernameTouched.value = true
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(load)
|
||||
</script>
|
||||
|
||||
@@ -399,7 +439,11 @@ onMounted(load)
|
||||
</div>
|
||||
<div class="tenant__grid tenant__grid--3">
|
||||
<NFormItem label="登录账号" path="adminUsername">
|
||||
<NInput v-model:value="form.adminUsername" clearable />
|
||||
<NInput
|
||||
v-model:value="form.adminUsername"
|
||||
placeholder="按租户编码自动生成,如 admin_jxjd"
|
||||
clearable
|
||||
/>
|
||||
</NFormItem>
|
||||
<NFormItem label="姓名" path="adminRealName">
|
||||
<NInput v-model:value="form.adminRealName" clearable />
|
||||
|
||||
Reference in New Issue
Block a user