2026-05-15-FE-02.md
11.6 KB
前端功能规格 — FE-02 用户管理(列表 + 新增 / 编辑)
关联 REQ:REQ-USR-002, REQ-USR-003, REQ-USR-004 关联原型:prototype/erp.html#screen-userlist, prototype/erp.html#screen-userdetail 日期:2026-05-15
一、功能概述
超级管理员管理用户账号的三大场景:
-
列表 / 筛选(REQ-USR-004):分页 + 多字段筛选 + 排序,路由
/users -
新增用户(REQ-USR-002):独立表单页
/users/new,提交后跳回/users -
编辑用户(REQ-USR-003):独立表单页
/users/:userId,预填详情后允许部分字段更新
UI 模式:与 prototype 两个独立 section 对齐——userlist 是表格 + filter;userdetail 是表单页(toolbar + form-grid + Tabs + 权限分类)。新增 / 编辑共用同一 UserFormPage 组件(用 :userId === undefined 切模式)。
本 FE 不含:作废 / 取消作废、删除、重置密码、导出 Excel、客户查看 / 供应商查看 / 人员查看 / 工序查看 / 司机查看等多 Tab 权限(仅实现"权限组"主 Tab)。这些后续 FE 补。
二、组件树
基于 prototype/erp.html 中 #screen-userlist + #screen-userdetail 推导:
UsersListPage (pages/users/UsersListPage.tsx, route="/users", protected by RequireAuth)
├── PageToolbar
│ ├── RefreshButton (调 list query)
│ ├── AddNewButton (navigate to /users/new)
│ └── (导出 Excel 按钮:visually 保留但 disabled)
├── FilterBar (filter form)
│ ├── QueryFieldSelect (username / employeeName / userCode / departmentName / userType / isDeleted / lastLoginDate / createdBy)
│ ├── MatchModeSelect (contains / notContains / equals)
│ ├── QueryValueInput
│ ├── SearchButton
│ └── ResetButton
├── UsersTable (AntD Table)
│ ├── columns: 序号 / 用户名 / 员工名 / 用户号 / 部门 / 用户类型 / 语言 / 作废 / 登录日期 / 制单人 / 制单日期 / 操作(编辑链接)
│ ├── rowKey="userId"
│ ├── onRowClick → navigate to /users/{userId}
│ └── pagination footer
└── UsersPagination (AntD Pagination integrated with Table)
UserFormPage (pages/users/UserFormPage.tsx, route="/users/new" + "/users/:userId", protected by RequireAuth)
├── PageToolbar
│ ├── SaveButton
│ ├── CancelButton (navigate back to /users)
│ └── (新增按钮:仅编辑模式可见,跳 /users/new)
├── UserFormFieldsPanel (form-grid)
│ ├── CreatedTime (只读,仅编辑模式显示)
│ ├── CreatedBy (只读,仅编辑模式显示)
│ ├── EmployeeSelect (label "员工名"; 当前硬编码可选员工 fixture,等 HR REQ 后改 GET /api/v1/employees)
│ ├── UsernameInput (label "用户名",编辑模式 readonly)
│ ├── UserCodeInput (label "用户号")
│ ├── UserTypeSelect (label "类型",options: NORMAL / SUPER_ADMIN)
│ ├── LanguageSelect (label "语言",options: zh-CN / en-US / zh-TW)
│ └── CanEditDocumentCheckbox (label "单据修改权限")
├── PermissionTabs (单一 Tab "权限组",其他 Tab visually 保留但 disabled)
└── PermissionCategoryList (AntD List + Checkbox 行选)
└── PermissionCategoryRow × N (当前硬编码 fixture {PUR, SAL}, 等运营 REQ 后改 GET /api/v1/permission-categories)
三、页面状态机
UsersListPage 状态
| # | 状态 | 触发条件 | 视觉表现 | 用户可执行操作 |
|---|---|---|---|---|
| 1 | loading | 首次进入 / refresh / filter 提交 | Table loading=true 显 spinner | 等待 |
| 2 | empty | API 返 total=0 | Table 空态 + "暂无用户" | 点新增 / 清空筛选 |
| 3 | normal | 正常返回 records | Table 渲染数据;分页器显示 total / page / size | 点行编辑 / 翻页 / 排序 / 筛选 |
| 4 | error_network | 网络错(-1) | Table 顶部 Alert "网络异常,请重试" + 重试按钮 | 点重试 |
| 5 | error_forbidden | 403 / 40301 | 全屏 Result "权限不足" | 点退回 |
UserFormPage 状态
| # | 状态 | 触发条件 | 视觉表现 | 用户可执行操作 |
|---|---|---|---|---|
| 1 | loading_initial | 编辑模式首次进入(new 模式跳过) | 表单 disabled + spinner | 等待 |
| 2 | error_load | GET /api/v1/users/{userId} 失败(404 / 40401) | 全屏 Result "用户不存在" + 返回按钮 | 点返回 |
| 3 | idle | 表单已加载完成 | 表单可编辑(编辑模式 username 只读) | 修改字段 |
| 4 | validating | 用户点 save → 前端字段校验 | submit 按钮 disabled | 等待 |
| 5 | submitting | 校验通过,调 POST/PUT | submit 显 loading 旋转 | 等待 |
| 6 | error_field | 后端返 40001/40901/40902/40004 | 对应字段下方红字 + Alert | 改字段重试 |
| 7 | error_global | 40101 / 40301 / 40302 / 网络 | 顶部 Alert 显文案 | 操作返回 |
| 8 | success | 后端返 200/201 | message.success "保存成功";navigate(-1) 或 navigate('/users') | 自动跳转 |
四、消费的后端端点
| # | 方法 | 路径 | 触发时机 | 关联 REQ |
|---|---|---|---|---|
| 1 | GET | /api/v1/users |
UsersListPage 加载 / refresh / filter 提交 / 翻页 / 排序 | REQ-USR-004 |
| 2 | GET | /api/v1/users/{userId} |
UserFormPage 编辑模式挂载 | REQ-USR-003 |
| 3 | POST | /api/v1/users |
UserFormPage 新增模式 submit | REQ-USR-002 |
| 4 | PUT | /api/v1/users/{userId} |
UserFormPage 编辑模式 submit | REQ-USR-003 |
请求体 / 响应结构与 docs/05 一致;客户端 usersApi.{list, get, create, update} 包装函数。
五、业务规则前端复刻清单
| # | 规则描述 | 触发时机 | 报错文案 | 来源 REQ |
|---|---|---|---|---|
| 1 | 列表 size 上限 100 | 翻页器选项;默认 20 | (AntD pagination 内置) | REQ-USR-004 |
| 2 | 列表 page<1 / sortField 非白名单 / matchMode 非白名单 → 后端返 40001/40003,前端做 banner 提示 | filter submit | "请检查筛选参数" | REQ-USR-004 |
| 3 | 用户名(新增)必填 + 3-20 位字母数字下划线(正则 ^[A-Za-z0-9_]{3,20}$) |
submit 前 | "用户名必须为 3-20 位字母数字下划线" | REQ-USR-002 |
| 4 | 用户号必填 + 最大 50 字符 | submit 前 | "请输入用户号 / 不超过 50 字符" | REQ-USR-002 / 003 |
| 5 | 类型 / 语言必填且为枚举 | submit 前 | "请选择类型 / 语言" | REQ-USR-002 / 003 |
| 6 | 单据修改权限:boolean,默认 false | 字段渲染 | — | REQ-USR-002 / 003 |
| 7 | 员工 ID 可选;选 "无 / 解除关联" 时新增传 null,编辑传 0(spec § PATCH 三态) | submit | — | REQ-USR-003 |
| 8 | 编辑模式 username + 密码字段不允许修改(username readonly;表单不展示 password 字段) | 字段渲染 | — | REQ-USR-003 |
| 9 | 新增成功 → message + navigate('/users') | 响应处理 | "新增用户成功" | REQ-USR-002 |
| 10 | 编辑成功 → message + navigate('/users') | 响应处理 | "保存成功" | REQ-USR-003 |
| 11 | 40901 用户名冲突 → field-level "用户名已存在" | 响应处理 | "用户名已存在" | REQ-USR-002 |
| 12 | 40902 用户号冲突 → field-level "用户号已存在" | 响应处理 | "用户号已被占用" | REQ-USR-002 / 003 |
| 13 | 40004 员工 / 权限分类不存在 → field-level 错误 | 响应处理 | "员工或权限分类不存在或已删除" | REQ-USR-002 / 003 |
| 14 | 40301 非超级管理员 → 全屏 Result | 响应处理 | "权限不足,仅超级管理员可调用" | REQ-USR-002 / 003 / 004 |
| 15 | 40302 试图停用自己 → banner(FE-02 不含作废按钮,此分支只在意外触发时显示) | 响应处理 | "不允许停用当前登录用户自己" | REQ-USR-003 |
| 16 | 40401 用户不存在(编辑模式 GET / PUT 都可能命中) | 响应处理 | "用户不存在" → 跳回列表 | REQ-USR-003 |
| 17 | 网络错 → banner 重试 | 响应处理 | "网络异常,请检查连接后重试" | docs/04 § 2.4 |
要求:每条规则必须在前端 form-level 校验中复刻(前端能预防的不依赖后端报错)。文案与后端语义一致。
六、Design Tokens 引用清单
--color-primary (主按钮 / 链接 / Tab 激活下划线)
--color-primary-hover (hover)
--color-primary-active (按下)
--color-text (表格行文字 / 标签)
--color-text-secondary (表格表头辅助文字 / 占位)
--color-text-disabled (只读字段文字)
--color-error (错误字段 / 错误 Alert)
--color-success (保存成功 message)
--color-warning (列表网络错黄色 Alert)
--color-border (表格 / 输入框边框)
--color-split (列表行分割线)
--color-bg-page (页面底色)
--color-bg-container (Table / 表单 card bg)
--color-bg-disabled (只读字段 bg)
均来自 docs/06 § 二。本 FE 不引入新 token。
七、交互流程关键路径
列表查询 + 翻页
[用户访问 /users]
1. UsersListPage 挂载 → useEffect 调 usersApi.list({page:1, size:20, sortField:'tCreateDate', sortOrder:'desc'})
2. Table loading=true → API 返回 → set records + total
3. 用户改 filter 输入 → 点搜索 → 重新调 list
4. 用户点列头排序 → set sortField/sortOrder → 重新调 list
5. 用户翻页 → set page → 重新调 list
[用户点行]
→ navigate('/users/' + row.userId)
新增用户
[用户在 /users 点新增]
→ navigate('/users/new')
→ UserFormPage mode=create,空表单
→ 用户填字段 → 点保存
→ validateFields → submitting 态
→ usersApi.create(form) → 成功 → message.success → navigate('/users')
→ 失败:按错误码 setFieldErrors 或 banner
编辑用户
[用户在 /users 点行 或 访问 /users/:id]
→ UserFormPage mode=edit,挂载时调 usersApi.get(userId)
→ loading_initial → 收到 detail → 填入表单(username readonly)
→ 用户改字段 → 点保存
→ validateFields → submitting → usersApi.update(userId, patch) → 成功 → message.success → navigate('/users')
→ 40401 不存在 → error_load 全屏 Result
filter 状态保留(推迟到 FE-03+)
本 FE:刷新页面 filter 清空;下一 FE 可引入 URL query string 同步。
八、备注与开放问题
- GET /api/v1/employees + /api/v1/permission-categories 暂未实现:员工 + 权限分类下拉用 fixture 数据(见 prototype,可硬编码 2-3 项;用户选择后传 ID)。spec § 一标记延后
- 导出 Excel / 删除 / 重置密码 / 作废切换 / 多 Tab 权限:本 FE 不实现,prototype 按钮 visually 保留但 disabled / 不绑定点击事件。docs/08 § 三 中明确"FE-02 = 列表 + 新增 / 编辑",其他能力推后
- 大表格性能:当前默认 size=20,size 上限 100,无需虚拟滚动;docs/04 § 3.2 一致
- i18n:硬编码中文。后续 i18n 接入时统一替换
- a11y:表单字段必须有 label(与 FE-01 同样规则);Table 行点击同时支持键盘 Enter 跳详情
- 后端 40001 data.field-level 信息:当前接口未明示返回 detail;FE 接到 40001 暂统一 banner,待后端扩展
-
userType=NORMAL 用户调用列表 / 详情会被后端 40301:FE 在用户进入路由前根据 LoginContext 已知 userType,可主动 RequireSuperAdmin 守卫减少不必要请求。本 FE 实现
<RequireSuperAdmin>守卫包裹/users/**路由 - PATCH 编辑模式 employeeId 三态:null=不变;0=解除关联;正整数=更新。前端 form 把 "无" 选项 value=0 处理