Files
Environment-Monitoring-System/Design/frontend_Design/PersonnelManagementPage_Design.md
ChuXun 4ce487588a 1
2025-10-19 20:31:01 +08:00

296 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 人员管理页面设计文档
## 1. 页面概述
人员管理页面是提供给系统管理员ADMIN用于管理所有用户账户的界面。其核心功能包括展示用户列表、添加新用户、编辑现有用户信息、更改用户角色与状态以及搜索和筛选用户。
## 2. 页面布局
![人员管理页面布局示意图](https://placeholder-for-personnel-page-mockup.png)
### 2.1 布局结构
页面采用经典的后台管理布局,与任务管理、反馈管理页面保持一致:
- **顶部**: 操作区域,包含"添加用户"按钮。
- **中部**: 筛选和搜索区域,支持按用户名、角色或状态进行搜索。
- **下部**: 用户数据表格,展示所有用户及其关键信息,并提供行内操作。
- **底部**: 分页组件。
## 3. 组件结构
```vue
<template>
<div class="personnel-management-page">
<el-page-header title="人员管理" content="系统用户列表" />
<el-card class="page-container">
<!-- 搜索与操作区域 -->
<div class="table-toolbar">
<el-form :model="filters" inline class="filter-form">
<el-form-item>
<el-input v-model="filters.name" placeholder="按姓名或用户名搜索" clearable />
</el-form-item>
<el-form-item>
<el-select v-model="filters.role" placeholder="按角色筛选" clearable>
<el-option label="管理员" value="ADMIN" />
<el-option label="主管" value="SUPERVISOR" />
<el-option label="网格员" value="GRID_WORKER" />
<el-option label="决策者" value="DECISION_MAKER" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleSearch">搜索</el-button>
</el-form-item>
</el-form>
<div class="action-buttons">
<el-button type="primary" icon="Plus" @click="handleCreateUser">添加用户</el-button>
</div>
</div>
<!-- 用户表格 -->
<el-table :data="users" v-loading="loading" stripe>
<el-table-column prop="username" label="用户名" />
<el-table-column prop="name" label="姓名" />
<el-table-column prop="role" label="角色">
<template #default="{ row }">
<span>{{ formatRole(row.role) }}</span>
</template>
</el-table-column>
<el-table-column prop="email" label="邮箱" />
<el-table-column prop="status" label="状态">
<template #default="{ row }">
<el-switch
v-model="row.isActive"
@change="handleStatusChange(row)"
:loading="row.statusChanging"
active-text="启用"
inactive-text="禁用"
/>
</template>
</el-table-column>
<el-table-column label="操作" width="200" fixed="right">
<template #default="{ row }">
<el-button link type="primary" @click="handleEdit(row)">编辑</el-button>
<el-popconfirm title="确定要删除该用户吗?" @confirm="handleDelete(row)">
<template #reference>
<el-button link type="danger">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
v-if="total > 0"
class="pagination-container"
:current-page="pagination.page"
:page-size="pagination.pageSize"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</el-card>
<!-- 用户表单对话框 -->
<UserFormDialog
v-model="dialogVisible"
:user-id="selectedUserId"
@success="onFormSuccess"
/>
</div>
</template>
```
## 4. 数据结构
```typescript
// 用户筛选条件
interface UserFilters {
name?: string;
role?: 'ADMIN' | 'SUPERVISOR' | 'GRID_WORKER' | 'DECISION_MAKER';
}
// 用户列表项
interface UserListItem {
id: number;
username: string;
name: string;
email: string;
role: string;
isActive: boolean;
statusChanging?: boolean; // 用于控制 Switch 的 loading 状态
}
// 用户表单数据 (用于对话框)
interface UserFormData {
id?: number;
username: string;
name: string;
email: string;
role: string;
password?: string; // 创建时需要,编辑时可选
}
```
## 5. 状态管理
```typescript
// 组件内状态
const filters = ref<UserFilters>({});
const pagination = ref({ page: 1, pageSize: 10 });
const dialogVisible = ref(false);
const selectedUserId = ref<number | null>(null);
// 全局状态 (Pinia Store)
const personnelStore = usePersonnelStore();
const { users, total, loading } = storeToRefs(personnelStore);
```
## 6. 交互逻辑
### 6.1 CRUD 操作
```typescript
const fetchUsers = () => {
personnelStore.fetchUsers({ ...filters.value, ...pagination.value });
};
onMounted(fetchUsers);
const handleSearch = () => {
pagination.value.page = 1;
fetchUsers();
};
const handleCreateUser = () => {
selectedUserId.value = null;
dialogVisible.value = true;
};
const handleEdit = (user: UserListItem) => {
selectedUserId.value = user.id;
dialogVisible.value = true;
};
const handleDelete = async (user: UserListItem) => {
await personnelStore.deleteUser(user.id);
ElMessage.success('用户删除成功');
fetchUsers(); // 刷新列表
};
const handleStatusChange = async (user: UserListItem) => {
user.statusChanging = true;
try {
await personnelStore.updateUserStatus(user.id, user.isActive);
ElMessage.success('状态更新成功');
} catch {
// 失败时将开关拨回原位
user.isActive = !user.isActive;
} finally {
user.statusChanging = false;
}
};
const onFormSuccess = () => {
dialogVisible.value = false;
fetchUsers();
};
```
### 6.2 辅助函数
```typescript
const formatRole = (role: string) => {
const roleMap = {
ADMIN: '管理员',
SUPERVISOR: '主管',
GRID_WORKER: '网格员',
DECISION_MAKER: '决策者'
};
return roleMap[role] || '未知角色';
};
```
## 7. API 调用
```typescript
// api/personnel.ts
export const personnelApi = {
getUsers: (params) => apiClient.get('/personnel', { params }),
getUserById: (id: number) => apiClient.get(`/personnel/${id}`),
createUser: (data: UserFormData) => apiClient.post('/personnel', data),
updateUser: (id: number, data: UserFormData) => apiClient.put(`/personnel/${id}`, data),
deleteUser: (id: number) => apiClient.delete(`/personnel/${id}`),
};
// stores/personnel.ts
export const usePersonnelStore = defineStore('personnel', {
state: () => ({
users: [] as UserListItem[],
total: 0,
loading: false,
}),
actions: {
async fetchUsers(params) {
this.loading = true;
try {
const { data } = await personnelApi.getUsers(params);
this.users = data.items.map(u => ({ ...u, statusChanging: false }));
this.total = data.total;
} finally {
this.loading = false;
}
},
// ...其他 createUser, updateUser, deleteUser 等 actions
}
});
```
## 8. 样式设计
```scss
.personnel-management-page {
padding: 24px;
.page-container {
margin-top: 24px;
}
.table-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.pagination-container {
margin-top: 24px;
display: flex;
justify-content: flex-end;
}
}
```
## 9. 关联组件
### `UserFormDialog.vue`
用于创建和编辑用户的对话框组件。
- **Props**: `modelValue`, `userId`
- **功能**:
- 如果 `userId` 存在,则为编辑模式,对话框打开时会根据 ID 加载用户信息。
- 如果 `userId` 为空,则为创建模式。
- 包含用户名、姓名、邮箱、角色和密码的表单字段。
- 密码字段在编辑模式下为可选,并提示"留空则不修改密码"。
- 表单提交时进行验证,并调用 store 中对应的 `createUser``updateUser` action。
- 操作成功后,发出 `success` 事件。
## 10. 测试用例
- **集成测试**:
- 测试能否成功添加一个新用户。
- 测试能否成功编辑一个现有用户的信息(包括修改密码和不修改密码两种情况)。
- 测试能否成功删除一个用户。
- 测试启用/禁用开关是否能正确更新用户状态。
- 测试搜索和筛选功能是否能正确过滤用户列表。