创建租户改为事务化一站式操作:自动复制 gdlib 权限模板 + 补充基础管理权限, 创建 tenant_admin 角色和管理员用户,支持自定义账号密码。 前端表单增加管理员输入区块,成功弹窗展示凭据并支持一键复制。 同步实现 menuIds 菜单分配(消除原 TODO)。 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
5.6 KiB
5.6 KiB
租户创建自动生成管理员账号 — 设计方案
所属端:超管端 状态:已完成 创建日期:2026-04-02 最后更新:2026-04-02
1. 背景与问题
超管端创建新租户(机构)后,需要手动到用户管理页面另行创建该租户的管理员账号、角色、权限,流程割裂且容易遗漏,导致新建的租户无法登录使用。
核心问题:
- 创建租户与创建管理员是分离的两步操作,缺乏原子性
- 新租户没有默认角色和权限,管理员账号无法正常使用
- 菜单分配(menuIds)也未实现(后端标记为 TODO)
2. 现状分析
2.1 创建租户接口
POST /api/tenants→SysTenantServiceImpl.createTenant()- 仅创建
t_sys_tenant记录,不创建用户、角色、权限、菜单关联 - menuIds 参数存在但未处理(TODO 注释)
2.2 初始化脚本的做法
backend/scripts/init-dev-tenants.ts(Node 版,已移除)中,创建租户时会一并完成:
- 创建租户 → 2. 创建权限 → 3. 创建角色 → 4. 角色绑定权限 → 5. 创建 admin 用户 → 6. 用户绑定角色 → 7. 分配菜单
init.sql 中每个租户也都有对应的 admin 用户和角色。
2.3 涉及的数据表
| 表名 | 说明 |
|---|---|
t_sys_tenant |
租户 |
t_sys_user |
用户 |
t_sys_role |
角色 |
t_sys_permission |
权限(按租户隔离) |
t_sys_user_role |
用户-角色关联 |
t_sys_role_permission |
角色-权限关联 |
t_sys_tenant_menu |
租户-菜单关联 |
3. 设计方案
3.1 整体思路
创建租户时在同一事务中自动完成:创建租户 → 复制权限模板 → 创建管理员角色 → 创建管理员用户 → 绑定关联关系 → 分配菜单。接口返回租户信息 + 管理员凭据。
3.2 权限模板策略
- 模板来源:运行时从广东省图租户(code=
gdlib,tenant_id=9)复制权限,该租户拥有 26 项业务权限,覆盖活动、报名、评审、作品、公告等核心模块 - 补充基础管理权限:模板中缺少的 7 项基础权限自动补充:
user:update、user:delete— 用户管理role:create、role:update、role:delete、role:assign— 角色管理permission:read— 权限查看
- 新租户最终获得 33 项权限(26 模板 + 7 补充)
3.3 前端页面设计
创建表单改动:
- 基本信息 Tab 增加「管理员账号」区块(用分割线分隔)
- 新增两个输入框:管理员账号(默认 admin)、管理员密码(默认 admin@{编码})
- 仅新建时显示,编辑时隐藏
成功弹窗改动:
- 原先:提示"创建成功"+ 跳转用户管理页按钮
- 现在:展示管理员账号、初始密码、登录地址
- 新增「复制账号信息」按钮,一键复制全部信息到剪贴板
3.4 后端改动
CreateTenantDto — 新增字段:
adminUsername(String,可选,默认 "admin")adminPassword(String,可选,默认 "admin@{tenantCode}")
ISysTenantService.createTenant() — 返回值改为 Map<String, Object>
SysTenantServiceImpl.createTenant() — 核心改动,事务内完成 7 步:
- 创建租户记录
copyTemplatePermissions()— 复制 gdlib 权限 + 补充基础权限- 创建
tenant_admin角色 - 批量绑定角色-权限
- 创建管理员用户(密码 BCrypt 加密)
- 绑定用户-角色
- 处理 menuIds 菜单分配
新增私有方法 copyTemplatePermissions(Long newTenantId):
- 查询 gdlib 租户的全部权限,逐条复制(替换 tenantId)
- 对比已有权限编码,补充缺失的基础管理权限
SysTenantServiceImpl.updateTenant() — 同步实现 menuIds 更新(先删后增)
SysTenantController.create() — 返回类型从 Result<SysTenant> 改为 Result<Map<String, Object>>
3.5 接口响应格式
{
"code": 200,
"data": {
"tenant": {
"id": 13,
"name": "测试图书馆",
"code": "test-lib",
"tenantType": "library",
...
},
"admin": {
"username": "libadmin",
"password": "Lib@2026",
"userId": 32,
"nickname": "测试图书馆管理员"
}
}
}
3.6 前端改动
src/api/tenants.ts:
CreateTenantForm新增adminUsername、adminPassword- 新增
CreateTenantResult接口 createTenant()返回类型改为CreateTenantResult
src/views/system/tenants/Index.vue:
- 表单 reactive 新增
adminUsername、adminPassword - 模板增加管理员输入区块
- 成功弹窗展示管理员信息卡片 + 复制按钮
- 移除
useRouter、useAuthStore无用依赖
4. 改动范围
后端(Java)
| 操作 | 文件 |
|---|---|
| 修改 | modules/sys/dto/CreateTenantDto.java |
| 修改 | modules/sys/service/ISysTenantService.java |
| 修改 | modules/sys/service/impl/SysTenantServiceImpl.java |
| 修改 | modules/sys/controller/SysTenantController.java |
前端
| 操作 | 文件 |
|---|---|
| 修改 | src/api/tenants.ts |
| 修改 | src/views/system/tenants/Index.vue |
5. 实施记录
2026-04-02 — 初版实现
- 完成后端事务化创建租户 + 管理员 + 角色 + 权限 + 菜单分配
- 权限模板使用 gdlib 租户(26项)+ 7项基础管理权限补充
- 前端表单增加管理员账号/密码输入,成功弹窗展示凭据信息
- 测试验证:创建租户 → 管理员登录成功 → 获得 97 项权限(含 gdlib 完整业务权限 + 补充权限)
- 同步实现了
updateTenant的 menuIds 更新(消除 TODO)