# 用户列表 - 布局与组件结构描述 ## 1️⃣ 页面概述 用户列表页面用于管理系统用户账号,包括本地用户和域用户的查看、创建、编辑、删除等操作。支持用户状态管理(启用/禁用)、密码重置等功能。 ## 2️⃣ 布局结构(使用约定术语) ### Page Layout - **Layout Type**: Vertical Stack Layout(垂直堆叠布局) - **Direction**: Vertical(垂直方向) - **Spacing**: 无间距(紧密堆叠) - **Padding**: 0(全屏布局) ### Component Hierarchy(层级结构) ``` Page (页面) └── Main Container (主容器) ├── Header Region (头部区域) │ └── Tabs Component (选项卡组件) │ ├── Tab Item: 用户列表 │ ├── Tab Item: 角色列表 │ ├── Tab Item: 域用户组 │ └── Tab Item: LDAP │ ├── Content Region (内容区域) │ └── Table Section (表格分区) │ ├── Table Component (表格组件) │ │ ├── Column: 用户名称 │ │ ├── Column: 角色 │ │ ├── Column: 用户类型 │ │ ├── Column: 账号状态 (Switch) │ │ └── Column: 锁定状态 │ │ │ └── Pagination Component (分页组件) │ ├── Total Count Display │ ├── Page Size Selector │ ├── Page Navigation │ └── Page Jump Input │ └── Footer Region (底部区域) └── Action Toolbar (操作工具栏) ├── Button: 重置密码 ├── Button: 刷新 ├── Button: 删除 ├── Button: 编辑 └── Button: 新建 (Primary) ``` ### Layout Properties(布局属性) #### Main Container - **Type**: Flexbox Layout - **Direction**: Column - **Height**: 100vh - **Overflow**: Hidden - **Background**: Token.colorBgContainer #### Header Region (Tabs) - **Height**: 48px - **Background**: Token.colorBgContainer - **Border-bottom**: 1px solid Token.colorBorderSecondary - **Padding**: 0 24px #### Content Region - **Type**: Flex Layout - **Flex**: 1 (占据剩余空间) - **Overflow**: Auto - **Padding**: 24px 24px 0 24px #### Table Section - **Type**: Flexbox Layout - **Direction**: Column - **Gap**: 16px - **Height**: 100% #### Footer Region - **Height**: 72px - **Background**: Token.colorBgContainer - **Border-top**: 1px solid Token.colorBorderSecondary - **Padding**: 16px 24px - **Alignment**: Center - **Justify**: Center #### Action Toolbar - **Type**: Horizontal Flex Layout - **Gap**: 12px - **Justify**: Center ## 3️⃣ Ant Design 组件选择 ### 使用的组件及理由 | 组件 | 用途 | 选择理由 | |------|------|---------| | **Tabs** | 顶部导航选项卡 | - 提供标准的选项卡导航
- 自动处理选中状态
- 支持路由集成
- 清晰的视觉分隔
- 适合管理多个相关页面 | | **Table** | 用户数据展示 | - 强大的数据表格组件
- 内置排序、筛选功能
- 支持行选择
- 自动处理分页数据
- 列宽自适应
- 固定列支持 | | **Switch** | 账号状态开关 | - 直观的开关交互
- 即时生效反馈
- 支持加载状态
- 适合布尔值切换
- 占用空间小 | | **Pagination** | 分页控制 | - 完整的分页功能
- 支持页码跳转
- 每页条数选择
- 总数显示
- 国际化支持 | | **Button** | 操作按钮 | - 提供多种按钮样式
- 支持加载状态
- 图标支持
- 自动防重复点击
- 主题一致性 | | **Space** | 按钮组间距 | - 统一管理按钮间距
- 响应式布局
- 自动对齐 | | **Modal** | 弹窗对话框 | - 用于编辑/新建用户
- 模态交互
- 表单提交
- 确认删除操作 | | **Popconfirm** | 操作确认 | - 删除确认提示
- 轻量级确认
- 避免误操作 | ### Tabs 组件选择理由 选择 **Tabs** 作为顶部导航的原因: - ✅ 将相关的用户管理功能组织在一起(用户列表、角色列表、域用户组、LDAP) - ✅ 清晰的视觉层级,用户可以快速切换不同的管理视图 - ✅ 节省页面空间,避免多个独立页面 - ✅ 符合用户管理系统的常见设计模式 - ✅ 支持路由集成,可以通过 URL 直接访问特定标签页 ### Table 组件选择理由 选择 **Ant Design Table** 的原因: - ✅ 企业级表格组件,功能强大且稳定 - ✅ 内置虚拟滚动,支持大数据量 - ✅ 列配置灵活,支持自定义渲染 - ✅ 内置排序、筛选、分页等功能 - ✅ 支持行选择,便于批量操作 - ✅ 响应式设计,适配不同屏幕 ### Switch 组件选择理由 使用 **Switch** 而不是按钮来控制账号状态的原因: - ✅ 直观展示当前状态(开/关) - ✅ 单击即可切换,操作效率高 - ✅ 占用空间小,适合表格列 - ✅ 即时反馈,用户体验好 - ✅ 符合开关控制的通用设计模式 ## 4️⃣ 功能清单 ### 数据展示功能 - [x] **用户列表展示** - [ ] 显示用户名称 - [ ] 显示用户角色 - [ ] 显示用户类型(本地用户/域用户) - [ ] 显示账号状态(启用/禁用) - [ ] 显示锁定状态 - [ ] 支持列排序 - [ ] 支持列筛选 - [x] **分页功能** - [ ] 显示总条数 - [ ] 每页条数选择(10/20/50/100) - [ ] 页码导航 - [ ] 快速跳转到指定页 - [x] **数据加载** - [ ] 初始加载用户列表 - [ ] 加载状态指示 - [ ] 加载失败处理 - [ ] 自动刷新(可选) ### 用户操作功能 - [x] **新建用户** - [ ] 打开新建用户表单 - [ ] 输入用户基本信息 - [ ] 选择用户角色 - [ ] 设置初始密码 - [ ] 表单验证 - [ ] 提交创建请求 - [x] **编辑用户** - [ ] 选中用户 - [ ] 打开编辑表单 - [ ] 修改用户信息 - [ ] 保存修改 - [x] **删除用户** - [ ] 单选删除 - [ ] 批量删除(可选) - [ ] 删除确认提示 - [ ] 删除操作 - [ ] 删除结果反馈 - [x] **重置密码** - [ ] 选中用户 - [ ] 打开重置密码对话框 - [ ] 生成新密码或手动输入 - [ ] 密码强度验证 - [ ] 提交重置请求 - [ ] 显示新密码(一次性) - [x] **账号状态管理** - [ ] 启用账号 - [ ] 禁用账号 - [ ] 状态切换确认 - [ ] 即时生效反馈 - [x] **刷新列表** - [ ] 重新加载用户列表 - [ ] 保持当前页码和筛选条件 - [ ] 刷新状态提示 ### 选择与批量操作 - [x] **行选择** - [ ] 单选用户 - [ ] 多选用户(复选框) - [ ] 全选/取消全选 - [ ] 显示已选数量 - [x] **批量操作** - [ ] 批量删除 - [ ] 批量启用/禁用(可选) - [ ] 批量导出(可选) ### 搜索与筛选 - [x] **搜索功能** - [ ] 按用户名搜索 - [ ] 按角色筛选 - [ ] 按用户类型筛选 - [ ] 按账号状态筛选 - [ ] 实时搜索/延迟搜索 ### 标签页切换 - [x] **Tab 导航** - [ ] 切换到角色列表 - [ ] 切换到域用户组 - [ ] 切换到 LDAP 配置 - [ ] 保持当前页面状态 ## 5️⃣ 功能需求与思考 ### 功能1:用户列表展示与加载 **需求描述**: - 页面加载时自动获取用户列表数据 - 支持分页加载,每页显示 20 条(可配置) - 显示用户的关键信息:用户名、角色、类型、状态 **交互流程**: 1. 页面挂载时触发数据加载 2. 显示 Table 加载状态(Skeleton 或 Spin) 3. 数据加载成功后渲染表格 4. 加载失败显示错误提示,提供重试按钮 **数据结构**: ```typescript interface User { id: string; username: string; // 用户名称 role: string; // 角色 userType: 'local' | 'domain'; // 用户类型 isEnabled: boolean; // 账号状态 isLocked: boolean; // 锁定状态 lastLoginTime?: string; // 最后登录时间 createdAt: string; // 创建时间 updatedAt: string; // 更新时间 } interface UserListResponse { data: User[]; total: number; page: number; pageSize: number; } ``` **边界情况**: - 无数据(空状态展示) - 数据量大(虚拟滚动) - 网络慢(加载超时处理) - 并发请求(取消过期请求) ### 功能2:账号状态切换 **需求描述**: - 通过 Switch 组件即时切换用户账号的启用/禁用状态 - 提供即时反馈,显示操作结果 **交互流程**: 1. 用户点击 Switch 开关 2. Switch 进入 loading 状态 3. 发送状态更新请求到后端 4. 请求成功:Switch 切换状态,显示成功提示 5. 请求失败:Switch 恢复原状态,显示错误提示 **验证规则**: - 不能禁用当前登录用户自己的账号 - 不能禁用系统管理员账号(除非有多个管理员) - 需要相应权限才能操作 **安全考虑**: - 禁用账号时,立即终止该用户的所有会话 - 记录状态变更操作日志 - 关键操作需要二次确认 **边界情况**: - 网络中断时的状态同步 - 并发修改冲突 - 权限不足的提示 - 当前登录用户的特殊处理 ### 功能3:新建用户 **需求描述**: - 通过 Modal 表单创建新用户 - 输入用户基本信息并设置初始密码 **交互流程**: 1. 点击"新建"按钮 2. 打开新建用户 Modal 3. 填写用户信息表单: - 用户名(必填,唯一性校验) - 显示名称(可选) - 角色选择(必填) - 用户类型(本地/域) - 初始密码(必填,强度校验) - 确认密码(必填,一致性校验) - 邮箱(可选,格式校验) - 电话(可选) 4. 点击"确定"提交 5. 显示创建进度 6. 成功:关闭 Modal,刷新列表,显示成功消息 7. 失败:显示错误信息,保持 Modal 打开 **表单字段**: ```typescript interface CreateUserForm { username: string; // 3-20字符,字母数字下划线 displayName?: string; // 显示名称 role: string; // 角色ID userType: 'local' | 'domain'; password: string; // 8-20字符,包含大小写+数字 confirmPassword: string; // 与password一致 email?: string; // 邮箱格式 phone?: string; // 电话格式 } ``` **验证规则**: - 用户名:3-20字符,只能包含字母、数字、下划线,不能以数字开头 - 密码:8-20字符,必须包含大写字母、小写字母、数字 - 邮箱:标准邮箱格式 - 电话:11位手机号或固定电话格式 **边界情况**: - 用户名已存在 - 表单验证失败 - 网络超时 - 服务器错误 ### 功能4:编辑用户 **需求描述**: - 修改现有用户的信息(除用户名外) - 可以修改角色、显示名称、联系方式等 **交互流程**: 1. 选中用户(单选) 2. 点击"编辑"按钮 3. 打开编辑用户 Modal 4. 表单预填充当前用户信息 5. 修改可编辑字段 6. 提交修改 7. 成功:关闭 Modal,刷新列表 8. 失败:显示错误信息 **可编辑字段**: - 显示名称 - 角色 - 邮箱 - 电话 - 备注 **不可编辑字段**: - 用户名(主键,不可修改) - 用户类型(创建后不可修改) - 创建时间 **权限限制**: - 普通用户只能编辑自己的部分信息 - 管理员可以编辑所有用户 - 不能修改超级管理员的角色 **边界情况**: - 未选中用户点击编辑 - 选中多个用户(禁用编辑按钮) - 编辑过程中用户被删除 - 并发编辑冲突 ### 功能5:删除用户 **需求描述**: - 删除选中的用户账号 - 提供删除确认,防止误操作 **交互流程**: 1. 选中要删除的用户(单选或多选) 2. 点击"删除"按钮 3. 弹出 Popconfirm 确认对话框 4. 用户确认删除 5. 发送删除请求 6. 成功:从列表移除,显示成功消息 7. 失败:显示错误信息 **确认对话框内容**: - 单个删除:`确定要删除用户 "${username}" 吗?` - 批量删除:`确定要删除选中的 ${count} 个用户吗?` - 警告提示:`删除后将无法恢复,且该用户的所有会话将被终止。` **删除限制**: - 不能删除当前登录用户 - 不能删除系统内置用户(如 Administrator) - 需要相应权限 - 用户有关联数据时需要特殊处理(如操作日志) **安全措施**: - 二次确认 - 软删除(标记为已删除,保留数据)或硬删除 - 记录删除操作日志 - 立即终止被删除用户的所有会话 **边界情况**: - 未选中用户点击删除(禁用按钮) - 删除过程中网络中断 - 删除后分页处理(如删除最后一页的唯一记录) - 批量删除部分成功部分失败 ### 功能6:重置密码 **需求描述**: - 管理员为用户重置密码 - 支持自动生成或手动输入新密码 **交互流程**: 1. 选中用户 2. 点击"重置密码"按钮 3. 打开重置密码 Modal 4. 选择重置方式: - 自动生成随机密码 - 手动输入新密码 5. 如手动输入,需验证密码强度和确认密码 6. 提交重置请求 7. 成功:显示新密码(一次性),提示用户记录 8. 失败:显示错误信息 **密码生成规则**: - 长度:12-16位 - 包含:大写字母、小写字母、数字、特殊字符 - 易读性:避免易混淆字符(如 0/O, 1/l/I) **安全考虑**: - 新密码只显示一次 - 重置后强制用户首次登录时修改密码 - 记录密码重置操作日志 - 立即终止该用户的所有会话 **权限要求**: - 只有管理员可以重置他人密码 - 用户可以自己修改密码(不是重置) **边界情况**: - 未选中用户 - 选中多个用户(可以批量重置吗?) - 生成的密码不符合系统策略 - 重置当前登录用户的密码 ### 功能7:刷新列表 **需求描述**: - 重新加载用户列表数据 - 保持当前的筛选和分页状态 **交互流程**: 1. 点击"刷新"按钮 2. 显示刷新状态(按钮 loading) 3. 重新请求当前页数据 4. 更新表格显示 5. 显示刷新成功提示(可选) **保持状态**: - 当前页码 - 每页条数 - 搜索关键词 - 筛选条件 - 排序规则 **使用场景**: - 怀疑数据有更新时 - 操作完成后验证结果 - 网络错误后重试 - 定时自动刷新(可选) ### 功能8:行选择与批量操作 **需求描述**: - 支持单选和多选用户 - 根据选中状态启用/禁用操作按钮 **交互流程**: 1. 点击行首复选框选择用户 2. 显示已选中数量 3. 根据选中状态更新按钮可用性: - 未选中:禁用"编辑"、"删除"、"重置密码" - 选中1个:启用所有操作 - 选中多个:禁用"编辑",启用"删除"、"重置密码" **选择状态管理**: ```typescript interface SelectionState { selectedRowKeys: string[]; // 选中的用户ID数组 selectedRows: User[]; // 选中的用户对象数组 } ``` **批量操作**: - 批量删除:删除所有选中用户 - 批量重置密码:为所有选中用户生成新密码 - 批量导出:导出选中用户信息(可选) **边界情况**: - 切换页面后清空选择 - 删除选中用户后更新选择状态 - 全选时排除不可操作的用户 ### 功能9:Tab 切换 **需求描述**: - 在用户列表、角色列表、域用户组、LDAP 之间切换 - 保持各自的状态 **交互流程**: 1. 点击 Tab 标签 2. 切换到对应的内容 3. 加载对应的数据(如未加载) 4. 保持当前 Tab 的状态 **路由集成**: - URL 反映当前 Tab:`/system/users?tab=user-list` - 支持直接通过 URL 访问特定 Tab - 浏览器前进/后退支持 **状态管理**: - 每个 Tab 独立管理自己的状态 - 不同 Tab 之间不共享筛选条件 - Tab 切换时保留未提交的表单数据(可选) ## 6️⃣ 后续实现建议 ### 状态管理 #### Redux Slice 设计 ```typescript // states/userManagementSlice.ts interface UserManagementState { // 用户列表数据 users: { data: User[]; total: number; loading: boolean; error: string | null; }; // 分页状态 pagination: { current: number; pageSize: number; }; // 搜索和筛选 filters: { keyword: string; role: string | null; userType: 'all' | 'local' | 'domain'; status: 'all' | 'enabled' | 'disabled'; }; // 排序 sorter: { field: string | null; order: 'ascend' | 'descend' | null; }; // 选择状态 selection: { selectedRowKeys: string[]; selectedRows: User[]; }; // 当前 Tab activeTab: 'user-list' | 'role-list' | 'domain-group' | 'ldap'; // 模态框状态 modals: { createUser: boolean; editUser: boolean; resetPassword: boolean; }; // 当前编辑的用户 currentUser: User | null; } // 异步 Thunks export const fetchUsers = createAsyncThunk( 'userManagement/fetchUsers', async (params: FetchUsersParams) => { const response = await getUserList(params); return response; } ); export const createUser = createAsyncThunk( 'userManagement/createUser', async (userData: CreateUserForm) => { const response = await createUserAPI(userData); return response; } ); export const updateUser = createAsyncThunk( 'userManagement/updateUser', async ({ id, data }: { id: string; data: UpdateUserForm }) => { const response = await updateUserAPI(id, data); return response; } ); export const deleteUsers = createAsyncThunk( 'userManagement/deleteUsers', async (userIds: string[]) => { await deleteUsersAPI(userIds); return userIds; } ); export const toggleUserStatus = createAsyncThunk( 'userManagement/toggleUserStatus', async ({ id, isEnabled }: { id: string; isEnabled: boolean }) => { await updateUserStatusAPI(id, isEnabled); return { id, isEnabled }; } ); export const resetPassword = createAsyncThunk( 'userManagement/resetPassword', async ({ id, password }: { id: string; password?: string }) => { const response = await resetPasswordAPI(id, password); return response; } ); ``` ### API 接口设计 ```typescript // API/user.ts // 获取用户列表 export interface FetchUsersParams { page: number; pageSize: number; keyword?: string; role?: string; userType?: 'local' | 'domain'; status?: 'enabled' | 'disabled'; sortField?: string; sortOrder?: 'asc' | 'desc'; } export const getUserList = (params: FetchUsersParams): Promise => { return request.get('/api/system/users', { params }); }; // 创建用户 export interface CreateUserForm { username: string; displayName?: string; role: string; userType: 'local' | 'domain'; password: string; email?: string; phone?: string; } export const createUserAPI = (data: CreateUserForm): Promise => { return request.post('/api/system/users', data); }; // 更新用户 export interface UpdateUserForm { displayName?: string; role?: string; email?: string; phone?: string; remark?: string; } export const updateUserAPI = (id: string, data: UpdateUserForm): Promise => { return request.put(`/api/system/users/${id}`, data); }; // 删除用户 export const deleteUsersAPI = (userIds: string[]): Promise => { return request.delete('/api/system/users', { data: { userIds } }); }; // 更新用户状态 export const updateUserStatusAPI = (id: string, isEnabled: boolean): Promise => { return request.patch(`/api/system/users/${id}/status`, { isEnabled }); }; // 重置密码 export interface ResetPasswordResponse { newPassword: string; // 新密码(仅一次性返回) } export const resetPasswordAPI = ( id: string, password?: string ): Promise => { return request.post(`/api/system/users/${id}/reset-password`, { password }); }; // 检查用户名是否存在 export const checkUsernameExists = (username: string): Promise => {