Files
2026-10-20 21:53:26 +08:00

91 lines
3.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 6.1 用户管理
:::tip 概述
用户模块(goframe_user,租户级表)是机制最全的模块:唯一校验(按行现租户)、租户用户上限、角色全量重写、城市编解码、Excel 导入导出、数据权限接线、批量名称回填。路由前缀 /api/user。
:::
## 接口清单
| 方法 | 路由 | 权限 | 说明 |
|------|------|------|------|
| GET | /api/user/page | sys:user:page | 分页(关键词/状态/部门/角色/职级/岗位筛选) |
| GET | /api/user/list | sys:user:list | 全量列表(下拉选择用) |
| GET | /api/user/detail/:id | sys:user:detail | 详情(含角色 ID 数组与四级区划编码) |
| POST | /api/user/add | sys:user:add | 新增(返回新记录 ID) |
| PUT | /api/user/update | sys:user:update | 修改(密码留空不改) |
| PUT | /api/user/status | sys:user:status | 状态切换 |
| PUT | /api/user/resetPwd | sys:user:resetPwd | 重置密码(logType=reset) |
| DELETE | /api/user/delete/:id | sys:user:delete | 软删(清理 user_role) |
| DELETE | /api/user/batchDelete | sys:user:batchDelete | 批量删除 |
| POST | /api/user/import | sys:user:import | Excel 导入 |
| GET | /api/user/export | sys:user:export | Excel 导出 |
| GET | /api/user/document/:id | sys:user:detail | 打印信息 |
## 核心机制
### 唯一校验(手写,按行现租户)
```text
usernameExists / mobileExists 按 (username|mobile, tenant_id, 排除自身) 查;
Update 时先读被改行的 tenant_id 再校验——校验范围必须等于
uk_tenant_username / uk_tenant_mobile 索引范围(含 del_flag 由 dao.Ctx 恒过滤保证)。
历史教训:用 GetTenantID(超管=默认租户)会漏报 1062——必须按行现租户。
```
### 角色同步(AssignRoles)
```text
AssignRoles(userId, roleIds):全量重写 user_role(先删后插)
→ clearIdentityCache(userId)
Add/Update 均经此方法;Update 改 dept_id 也在该路径清缓存——部门变更即时生效
(数据权限无需等 300s 缓存过期)
```
### 租户用户上限(checkTenantUserMax)
统计租户现有用户数 vs tenant.max_user_num,超限返回 1007。在 user.Add 生效。
### 用户编码(genUserCode)
```text
前缀=租户 code(平台/超管为 "SYS"),序号=该租户现有用户数+1
格式 "{prefix}-%06d",如 T0001-000001
```
### 数据权限接线
userSpec 声明 `DataScope: ApplyDataScope("dept_id")`——user 是当前唯一接线模块(全库仅 user 表有 dept_id 列)。
### 列表名称回填(userExpandNames)
列表行批量补 dept/level/position/role 名称与城市文本(namesById/dictName 批查防 N+1)。
## 导入导出
```text
Import(POST /api/user/import):
excel.ReadSheet → 表头映射 → 逐行:唯一校验 / 租户上限 / 默认密码 bcrypt
(事务外预计算)/ 角色与城市解析 → 批量插入 → 返回成功/失败统计
城市列经 ResolveCityCodes(名称串) 转编码入库
Export(GET /api/user/export):
与列表同筛选(userFilter + DataScope,applyFilters 同链)
→ ChunkQuery 500/页 → excel.WriteSheet
导出可见集 = 列表可见集(导出=所见)
```
## 城市编解码接入
Add/Update/Import/Detail 均接入包级函数:写侧 `ResolveCityCodes`(名称串 → 四级编码入库),读侧 `ResolveCityNames`(编码 → 名称还原)。机制见 [6.9 行政区划管理](./city)。
## 字段与安全边界
```text
password/salt:bcrypt 双重加盐;接口永不返回
密码留空 = 不修改(Update 语义)
删除守卫:userDeleteGuard / 关联清理(user_role)
SerializeMaps:status → user_status({field}Text 字典填充)
FileFields: avatar + FileSaveDir: "user"(两段式上传自动转正)
```