2026-05-08-REQ-USR-003.md
4.31 KB
req_id: REQ-USR-003 date: 2026-05-08
module: usr
Spec: REQ-USR-003 — 查询用户
目标
超级管理员可按 8 种查询字段 + 3 种匹配方式组合筛选,分页浏览本品牌下的用户列表;列表同时展示关联职员的员工名与部门。
输入 / 触发
HTTP 请求:GET /api/usr/users(需 Bearer Token 鉴权)
Query 参数:
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| queryField | String | 否 | username |
查询字段枚举,见下表 |
| matchType | String | 否 | contains |
匹配方式枚举:contains / notContains / equals
|
| queryValue | String | 否 | — | 查询值;空字符串或不传 = 全部 |
| page | int | 否 | 1 | 页码,从 1 开始 |
| pageSize | int | 否 | 20 | 每页条数,最大 100 |
queryField 枚举(前端显示名 → 参数值 → 后端列):
| 前端显示 | 参数值 | 后端列 |
|---|---|---|
| 用户名 | username |
u.sUsername |
| 员工名 | staffName |
s.sStaffName |
| 用户号 | userCode |
u.sUserCode |
| 部门 | department |
s.sDepartment |
| 用户类型 | userType |
u.sUserType |
| 作废 | disabled |
u.bIsDisabled |
| 登录日期 | lastLoginDate |
u.tLastLoginDate |
| 制单人 | creator |
u.sCreatorUsername |
输出 / 结果
HTTP 200,Result<PageVO<UserListItemVO>>
PageVO<T> 结构(通用分页包装):
{
"total": 25,
"page": 1,
"pageSize": 20,
"list": [ ...UserListItemVO... ]
}
UserListItemVO 字段(禁止返回 sPasswordHash / iLoginFailCount / tLockUntil):
| JSON 字段 | 来源列 | 可 null |
|---|---|---|
| sId | usr_user.sId | 否 |
| sUsername | usr_user.sUsername | 否 |
| sUserCode | usr_user.sUserCode | 否 |
| sUserType | usr_user.sUserType | 否 |
| sLanguage | usr_user.sLanguage | 否 |
| bIsDisabled | usr_user.bIsDisabled | 否 |
| tLastLoginDate | usr_user.tLastLoginDate | 是 |
| sCreatorUsername | usr_user.sCreatorUsername | 是 |
| tCreateDate | usr_user.tCreateDate | 否 |
| sStaffName | tStaff.sStaffName | 是(LEFT JOIN) |
| sDepartment | tStaff.sDepartment | 是(LEFT JOIN) |
业务规则
-
多租户隔离:所有查询必须附加
u.sBrandsId = principal.brandId() - queryValue 为空:忽略查询条件,返回该品牌全部用户
-
匹配方式映射(文本字段:username / staffName / userCode / department / userType / creator):
-
contains→LIKE '%value%' -
notContains→NOT LIKE '%value%' -
equals→= 'value'
-
-
布尔字段(disabled):仅有意义的匹配是 equals;queryValue="是" →
bIsDisabled = 1;"否" →bIsDisabled = 0;其他值(包括 contains/notContains 的非 "是"/"否")忽略条件 -
日期字段(lastLoginDate):queryValue 格式
YYYY-MM-DD;无论 matchType 为何,均使用DATE(tLastLoginDate) = 'YYYY-MM-DD' - pageSize 截断:pageSize > 100 时强制截断为 100
-
分页越界:page 超出总页数时返回最后一页(MyBatis-Plus
Page默认行为) -
职员 JOIN:
LEFT JOIN tStaff s ON u.sEmployeeId = s.sId AND s.sBrandsId = u.sBrandsId AND s.bDeleted = 0;未关联职员时 sStaffName / sDepartment 为 null
边界与约束
- 接口为只读,无写副作用
- 鉴权失败返回 401(SecurityConfig.authenticationEntryPoint 已配置)
- 单次最多返回 100 条
依赖的 schema 表 / 字段
-
usr_user (别名 u):sId, sUsername, sUserCode, sUserType, sLanguage, bIsDisabled, sEmployeeId, sCreatorUsername, tLastLoginDate, tCreateDate, sBrandsId -
tStaff (别名 s):sId, sStaffName, sDepartment, sBrandsId, bDeleted
依赖的接口
-
POST /api/auth/login(REQ-USR-004,获取 Bearer Token 供本接口鉴权使用)
验收标准
-
GET /api/usr/users(无参)HTTP 200,返回本品牌所有用户,不含密码字段 -
queryField=username&matchType=contains&queryValue=admin仅返回 sUsername 含 "admin" 的用户 -
queryField=disabled&matchType=equals&queryValue=是仅返回 bIsDisabled=1 的记录 - 无匹配条件时返回
{ total: 0, list: [] }而非 4xx/5xx - page=999(超出总页)返回最后一页而不报错
- Token 品牌 A 无法查到品牌 B 的用户(多租户隔离)
- 响应 JSON 中不含 sPasswordHash / iLoginFailCount / tLockUntil
- 无 Token 请求返回 401