# 用户列表 - 布局与组件结构描述
## 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 => {