fix(user): /admin/user status \xe7\x99\xbd\xe5\x90\x8d\xe5\x8d\x95 \xe5\x85\x9c\xe5\xba\x95 (#1829 → PR #1834)

这个提交包含在:
API Changelog Bot 2026-05-07 18:10:13 +08:00
父节点 87b07e839e
当前提交 f839745b84

查看文件

@ -0,0 +1,72 @@
# fix(user): /admin/user 列表非字典 status (status=1) 致 total > 0 records=0
**PR**: [#1834](https://git.1814.love:8443/wx/HL/pulls/1834)(主修复)+ #1831 + #1832(回滚于 #1833) **Issue**: [#1829](https://git.1814.love:8443/wx/HL/issues/1829) **合并**: 2026-05-07
通知对象: 无前端配合(后端 controller 防御兜底,前端可继续传任意值后端兜底)
---
## 现象
正式 admin: `https://admin.1814.love/admin/user?page=1&pageSize=100&status=1` 显示「有数量没有数据」。
测试服真 admin token round-trip 完美复现:
| 请求 | total | records | 备注 |
|---|---|---|---|
| `status=1` | **28** | **0** | ❌ BUG |
| 其他无效值(0/2/ABCXYZ/true) | 0 | 0 | ✅ 一致 |
| `status=ACTIVE` | 28 | 28 | ✅ |
`status=1` 这个特定值出 BUG。
## 根因(深度排查 3 轮才定位)
MP `PaginationInnerInterceptor` 用 jsqlparser 把 records SELECT SQL parse 改成 count SQL。`status='1'` 这个字面值 + `.select(projection)` + `.ne(status, X)` + `.eq(status, '1')` 组合触发 jsqlparser 解析失败,**fallback 到 `SELECT COUNT(*) FROM admin_user`**(丢全部 WHERE)→ count=28(全表)records=0。
3 轮修复教训:
- **r1 PR #1831**: wrapper 从 `LambdaQueryWrapper``LambdaQueryWrapperX` + Mapper default 方法。合 CODE_RULES 1.2,顺手修了 `status=""` 空串过滤。**但 status=1 BUG 仍在**。
- **r2 PR #1832**: 试图 `selectCount(w) + setSearchCount(false) + selectPage(page,w)` 绕过 PaginationInnerInterceptor 自动 count。**炸 SQL 全 500 BadSqlGrammarException**(wrapper state mutation 引发)→ PR #1833 revert 紧急回滚。
- **r3 PR #1834 (最终)**: 在 controller 层加 status 字典白名单 (`ACTIVE/LOCKED/DISABLED`),非字典值直接返 `PageResult.empty()` 不进 mapper。**从源头杜绝 MP BUG 路径**。
## 后端修了什么
`AdminUserController.listAdmins`(`hl-user-service/.../controller/AdminUserController.java`)在 role 鉴权之后、调 service 之前加:
```java
private static final Set<String> VALID_ADMIN_STATUS = Set.of(
UserConstants.STATUS_ACTIVE,
UserConstants.ADMIN_STATUS_LOCKED,
UserConstants.STATUS_DISABLED);
if (status != null && !status.isEmpty() && !VALID_ADMIN_STATUS.contains(status)) {
return Result.success(PageResult.of(Collections.emptyList(), 0L, page, pageSize));
}
```
mapper / service 0 改动。守护单测 `listAdmins_invalidStatus_returnsEmptyPage` 验证 status="1" 时 mapper 不被调用 + 响应空。
## 前端无需改动
前端可继续传任意值,后端兜底返空。但**建议前端只传字典值**(ACTIVE/LOCKED/DISABLED)避免无意义请求。
## 部署依赖
无 nacos / SQL / 第三方配置变更。直接部署即生效。
## 受影响范围
- `/admin/user` 列表所有 status 过滤路径(修复)
- 其他 GET 列表接口同样 PaginationInnerInterceptor 行为可能存在类似潜在 BUG,但本 PR 不范围内修复
- 已识别遗留(本次未处理): MP `PaginationInnerInterceptor` jsqlparser fallback BUG 根因仍在,需要升级 MP 版本或换 SQL 方案,留后续 PR
## 测试服 round-trip 验证 (PR #1834 部署后)
```
status=1 → total=0 records.length=0 ✅
status=0/2/ABCXYZ/true → 0/0 ✅
status=ACTIVE → 28/28 ✅
status=DISABLED → 0/0 ✅
不传 status → 28/28 ✅
status=ACTIVE&roleId=1 → 7/7 ✅
```