清理
This commit is contained in:
@@ -1,696 +0,0 @@
|
||||
# EMS 后端 API 文档 (v3.0)
|
||||
|
||||
本文档为EMS(环境监控系统)后端API提供了全面的接口说明。所有接口均基于RESTful设计原则,使用JSON格式进行数据交换,并通过JWT进行认证授权。
|
||||
|
||||
**基础URL**: `http://localhost:8080`
|
||||
|
||||
---
|
||||
|
||||
## 1. 认证模块 (`/api/auth`)
|
||||
|
||||
负责处理用户身份验证、注册、登出和密码管理等所有认证相关操作。
|
||||
|
||||
### 1.1 用户登录
|
||||
|
||||
- **功能**: 用户通过邮箱和密码登录,成功后返回JWT令牌及用户信息。
|
||||
- **URL**: `/api/auth/login`
|
||||
- **方法**: `POST`
|
||||
- **请求体** (`LoginRequest`):
|
||||
```json
|
||||
{
|
||||
"email": "admin@example.com",
|
||||
"password": "password123"
|
||||
}
|
||||
```
|
||||
- **成功响应** (`200 OK`, `JwtAuthenticationResponse`):
|
||||
```json
|
||||
{
|
||||
"token": "eyJhbGciOiJIUzI1NiJ9...",
|
||||
"user": {
|
||||
"id": 1,
|
||||
"name": "Admin User",
|
||||
"email": "admin@example.com",
|
||||
"role": "ADMIN"
|
||||
}
|
||||
}
|
||||
```
|
||||
- **失败响应**: `401 Unauthorized` (凭证无效)
|
||||
|
||||
### 1.2 用户注册
|
||||
|
||||
- **功能**: 使用提供的用户信息和验证码创建新用户账户。
|
||||
- **URL**: `/api/auth/signup`
|
||||
- **方法**: `POST`
|
||||
- **请求体** (`SignUpRequest`):
|
||||
```json
|
||||
{
|
||||
"name": "New User",
|
||||
"email": "newuser@example.com",
|
||||
"password": "password123",
|
||||
"code": "123456"
|
||||
}
|
||||
```
|
||||
- **成功响应**: `201 Created`
|
||||
- **失败响应**: `400 Bad Request` (验证码错误、邮箱已存在等)
|
||||
|
||||
### 1.3 用户登出
|
||||
|
||||
- **功能**: 服务端记录用户登出操作。
|
||||
- **URL**: `/api/auth/logout`
|
||||
- **方法**: `POST`
|
||||
- **认证**: 需要有效的JWT令牌
|
||||
- **成功响应**: `200 OK`
|
||||
|
||||
### 1.4 发送注册验证码
|
||||
|
||||
- **功能**: 向指定邮箱发送用于账号注册的验证码。
|
||||
- **URL**: `/api/auth/send-verification-code`
|
||||
- **方法**: `POST`
|
||||
- **请求参数**:
|
||||
- `email` (string, `query`): 接收验证码的邮箱地址。
|
||||
- **成功响应**: `200 OK`
|
||||
- **失败响应**: `400 Bad Request` (邮箱格式不正确)
|
||||
|
||||
### 1.5 发送密码重置验证码
|
||||
|
||||
- **功能**: 向指定邮箱发送用于重置密码的验证码。
|
||||
- **URL**: `/api/auth/send-password-reset-code`
|
||||
- **方法**: `POST`
|
||||
- **请求参数**:
|
||||
- `email` (string, `query`): 注册时使用的邮箱地址。
|
||||
- **成功响应**: `200 OK`
|
||||
|
||||
### 1.6 使用验证码重置密码
|
||||
|
||||
- **功能**: 校验验证码并重置为新密码。
|
||||
- **URL**: `/api/auth/reset-password-with-code`
|
||||
- **方法**: `POST`
|
||||
- **请求体** (`PasswordResetWithCodeDto`):
|
||||
```json
|
||||
{
|
||||
"email": "user@example.com",
|
||||
"code": "654321",
|
||||
"newPassword": "newSecurePassword456"
|
||||
}
|
||||
```
|
||||
- **成功响应**: `200 OK`
|
||||
- **失败响应**: `400 Bad Request` (验证码无效或密码不符合要求)
|
||||
|
||||
---
|
||||
|
||||
## 2. 仪表盘模块 (`/api/dashboard`)
|
||||
|
||||
提供决策支持的各类统计和可视化数据。所有端点都需要 `DECISION_MAKER` 或 `ADMIN` 角色权限,特殊权限会单独注明。
|
||||
|
||||
### 2.1 核心统计数据
|
||||
|
||||
- **功能**: 获取仪表盘的核心统计数据,如总任务数、待处理反馈数等。
|
||||
- **URL**: `/api/dashboard/stats`
|
||||
- **方法**: `GET`
|
||||
- **成功响应** (`200 OK`): `DashboardStatsDTO`
|
||||
|
||||
### 2.2 报告与分析
|
||||
|
||||
#### AQI等级分布
|
||||
- **功能**: 获取AQI(空气质量指数)在不同等级下的分布情况。
|
||||
- **URL**: `/api/dashboard/reports/aqi-distribution`
|
||||
- **方法**: `GET`
|
||||
- **成功响应** (`200 OK`): `List<AqiDistributionDTO>`
|
||||
|
||||
#### 月度超标趋势
|
||||
- **功能**: 获取过去几个月内环境指标超标事件的趋势。
|
||||
- **URL**: `/api/dashboard/reports/monthly-exceedance-trend`
|
||||
- **方法**: `GET`
|
||||
- **成功响应** (`200 OK`): `List<TrendDataPointDTO>`
|
||||
|
||||
#### 网格覆盖情况
|
||||
- **功能**: 按城市统计网格的覆盖率和状态。
|
||||
- **URL**: `/api/dashboard/reports/grid-coverage`
|
||||
- **方法**: `GET`
|
||||
- **成功响应** (`200 OK`): `List<GridCoverageDTO>`
|
||||
|
||||
#### 污染物统计
|
||||
- **功能**: 获取主要污染物的统计数据报告。
|
||||
- **URL**: `/api/dashboard/reports/pollution-stats`
|
||||
- **方法**: `GET`
|
||||
- **成功响应** (`200 OK`): `List<PollutionStatsDTO>`
|
||||
|
||||
#### 任务完成情况
|
||||
- **功能**: 统计任务的整体完成率和状态分布。
|
||||
- **URL**: `/api/dashboard/reports/task-completion-stats`
|
||||
- **方法**: `GET`
|
||||
- **成功响应** (`200 OK`): `TaskStatsDTO`
|
||||
|
||||
#### 污染物月度趋势
|
||||
- **功能**: 获取不同污染物类型的月度变化趋势。
|
||||
- **URL**: `/api/dashboard/reports/pollutant-monthly-trends`
|
||||
- **方法**: `GET`
|
||||
- **成功响应** (`200 OK`): `Map<String, List<TrendDataPointDTO>>`
|
||||
|
||||
### 2.3 地图数据
|
||||
|
||||
#### 反馈热力图
|
||||
- **功能**: 获取用于在地图上展示反馈问题地理分布的热力图数据。
|
||||
- **URL**: `/api/dashboard/map/heatmap`
|
||||
- **方法**: `GET`
|
||||
- **成功响应** (`200 OK`): `List<HeatmapPointDTO>`
|
||||
|
||||
#### AQI热力图
|
||||
- **功能**: 获取用于在地图上展示AQI指数地理分布的热力图数据。
|
||||
- **URL**: `/api/dashboard/map/aqi-heatmap`
|
||||
- **方法**: `GET`
|
||||
- **成功响应** (`200 OK`): `List<AqiHeatmapPointDTO>`
|
||||
|
||||
### 2.4 污染物阈值管理
|
||||
|
||||
#### 获取所有阈值
|
||||
- **功能**: 获取所有污染物的阈值设置。
|
||||
- **URL**: `/api/dashboard/thresholds`
|
||||
- **方法**: `GET`
|
||||
- **成功响应** (`200 OK`): `List<PollutantThresholdDTO>`
|
||||
|
||||
#### 获取指定污染物阈值
|
||||
- **功能**: 根据污染物名称获取其特定的阈值设置。
|
||||
- **URL**: `/api/dashboard/thresholds/{pollutantName}`
|
||||
- **方法**: `GET`
|
||||
- **URL参数**: `pollutantName` (string)
|
||||
- **成功响应** (`200 OK`): `PollutantThresholdDTO`
|
||||
|
||||
#### 保存阈值
|
||||
- **功能**: 创建或更新一个污染物的阈值设置。
|
||||
- **权限**: **`ADMIN`**
|
||||
- **URL**: `/api/dashboard/thresholds`
|
||||
- **方法**: `POST`
|
||||
- **请求体** (`PollutantThresholdDTO`):
|
||||
```json
|
||||
{
|
||||
"pollutantName": "PM2.5",
|
||||
"goodThreshold": 35,
|
||||
"moderateThreshold": 75,
|
||||
"unhealthyThreshold": 115
|
||||
}
|
||||
```
|
||||
- **成功响应** (`200 OK`): `PollutantThresholdDTO` (已保存的数据)
|
||||
|
||||
---
|
||||
|
||||
## 3. 反馈模块 (`/api/feedback`)
|
||||
|
||||
处理公众和用户的环境问题反馈,包括提交、查询、统计和处理。
|
||||
|
||||
### 3.1 提交反馈
|
||||
|
||||
- **功能**: 已认证用户提交环境问题反馈,可附带文件。
|
||||
- **权限**: **`isAuthenticated()`** (任何已认证用户)
|
||||
- **URL**: `/api/feedback/submit`
|
||||
- **方法**: `POST`
|
||||
- **内容类型**: `multipart/form-data`
|
||||
- **请求部分**:
|
||||
- `feedback` (JSON, `FeedbackSubmissionRequest`):
|
||||
```json
|
||||
{
|
||||
"title": "River Pollution",
|
||||
"description": "The river near downtown is heavily polluted.",
|
||||
"latitude": 34.0522,
|
||||
"longitude": -118.2437,
|
||||
"pollutionType": "WATER",
|
||||
"severityLevel": "HIGH"
|
||||
}
|
||||
```
|
||||
- `files` (File[], optional): (可选) 上传的图片或视频文件。
|
||||
- **成功响应** (`201 Created`): `Feedback` (包含ID的已创建反馈对象)
|
||||
|
||||
### 3.2 获取反馈列表 (分页+过滤)
|
||||
|
||||
- **功能**: 根据多种条件组合查询反馈列表,支持分页。
|
||||
- **权限**: **`isAuthenticated()`**
|
||||
- **URL**: `/api/feedback`
|
||||
- **方法**: `GET`
|
||||
- **请求参数**:
|
||||
- `page` (int, optional): 页码 (从0开始)
|
||||
- `size` (int, optional): 每页数量
|
||||
- `sort` (string, optional): 排序字段,如 `createdAt,desc`
|
||||
- `status` (string, optional): 状态 (e.g., `PENDING_REVIEW`, `PROCESSED`)
|
||||
- `pollutionType` (string, optional): 污染类型 (e.g., `AIR`, `WATER`)
|
||||
- `severityLevel` (string, optional): 严重程度 (e.g., `LOW`, `MEDIUM`)
|
||||
- `cityName` (string, optional): 城市名称
|
||||
- `districtName` (string, optional): 区县名称
|
||||
- `startDate` (string, optional): 开始日期 (格式: `YYYY-MM-DD`)
|
||||
- `endDate` (string, optional): 结束日期 (格式: `YYYY-MM-DD`)
|
||||
- `keyword` (string, optional): 标题或描述中的关键词
|
||||
- **成功响应** (`200 OK`): `Page<FeedbackResponseDTO>` (分页的反馈数据)
|
||||
|
||||
### 3.3 获取反馈详情
|
||||
|
||||
- **功能**: 根据ID获取单个反馈的详细信息。
|
||||
- **权限**: **`ADMIN`**, **`SUPERVISOR`**, **`DECISION_MAKER`**
|
||||
- **URL**: `/api/feedback/{id}`
|
||||
- **方法**: `GET`
|
||||
- **URL参数**: `id` (long)
|
||||
- **成功响应** (`200 OK`): `FeedbackResponseDTO`
|
||||
|
||||
### 3.4 获取反馈统计
|
||||
|
||||
- **功能**: 获取当前用户的反馈统计数据 (例如,不同状态下的反馈数量)。
|
||||
- **权限**: **`isAuthenticated()`**
|
||||
- **URL**: `/api/feedback/stats`
|
||||
- **方法**: `GET`
|
||||
- **成功响应** (`200 OK`): `FeedbackStatsResponse`
|
||||
|
||||
### 3.5 处理反馈 (审批)
|
||||
|
||||
- **功能**: 主管或管理员对反馈进行处理,例如审批通过、驳回等。
|
||||
- **权限**: **`ADMIN`**, **`SUPERVISOR`**
|
||||
- **URL**: `/api/feedback/{id}/process`
|
||||
- **方法**: `POST`
|
||||
- **URL参数**: `id` (long)
|
||||
- **请求体** (`ProcessFeedbackRequest`):
|
||||
```json
|
||||
{
|
||||
"newStatus": "PROCESSED",
|
||||
"remarks": "Feedback has been verified and assigned."
|
||||
}
|
||||
```
|
||||
- **成功响应** (`200 OK`): `FeedbackResponseDTO` (更新后的反馈对象)
|
||||
|
||||
---
|
||||
|
||||
## 4. 公共接口模块 (`/api/public`)
|
||||
|
||||
无需认证即可访问的接口,主要用于公众参与。
|
||||
|
||||
### 4.1 提交公共反馈
|
||||
|
||||
- **功能**: 公众用户提交环境问题反馈,可附带文件。
|
||||
- **URL**: `/api/public/feedback`
|
||||
- **方法**: `POST`
|
||||
- **内容类型**: `multipart/form-data`
|
||||
- **请求部分**:
|
||||
- `feedback` (JSON, `PublicFeedbackRequest`):
|
||||
```json
|
||||
{
|
||||
"title": "Noise Complaint",
|
||||
"description": "Loud construction noise at night.",
|
||||
"latitude": 34.0522,
|
||||
"longitude": -118.2437,
|
||||
"contactInfo": "anonymous@example.com"
|
||||
}
|
||||
```
|
||||
- `files` (File[], optional): 上传的图片或视频等附件。
|
||||
- **成功响应** (`201 Created`): `Feedback` (包含ID的已创建反馈对象)
|
||||
|
||||
---
|
||||
|
||||
## 5. 文件模块 (`/api`)
|
||||
|
||||
处理系统中文件的访问、下载和预览。
|
||||
|
||||
### 5.1 文件下载/预览
|
||||
|
||||
- **功能**: 根据文件名获取文件资源,既可用于下载,也可用于浏览器内联预览。
|
||||
- **URL**:
|
||||
- `/api/files/{filename}`
|
||||
- `/api/view/{filename}`
|
||||
- **方法**: `GET`
|
||||
- **URL参数**:
|
||||
- `filename` (string): 完整的文件名,包含扩展名 (例如, `image.png`, `report.pdf`)。
|
||||
- **成功响应** (`200 OK`):
|
||||
- **Content-Type**: 根据文件类型动态设置 (e.g., `image/jpeg`, `application/pdf`)。
|
||||
- **Content-Disposition**: `inline`,建议浏览器内联显示。
|
||||
- **Body**: 文件内容的二进制流。
|
||||
- **失败响应**: `404 Not Found` (文件不存在)
|
||||
|
||||
---
|
||||
|
||||
## 6. 网格管理模块 (`/api/grids`)
|
||||
|
||||
负责环境监督网格的查询、更新以及网格员的分配管理。
|
||||
|
||||
### 6.1 获取所有网格
|
||||
|
||||
- **功能**: 获取系统中所有的网格数据列表。
|
||||
- **权限**: `ADMIN`, `DECISION_MAKER`, `GRID_WORKER`
|
||||
- **URL**: `/api/grids`
|
||||
- **方法**: `GET`
|
||||
- **成功响应** (`200 OK`): `List<Grid>`
|
||||
|
||||
### 6.2 更新网格信息
|
||||
|
||||
- **功能**: 更新指定ID的网格信息,例如修改其负责人或状态。
|
||||
- **权限**: `ADMIN`
|
||||
- **URL**: `/api/grids/{id}`
|
||||
- **方法**: `PATCH`
|
||||
- **URL参数**: `id` (long)
|
||||
- **请求体** (`GridUpdateRequest`):
|
||||
```json
|
||||
{
|
||||
"status": "ACTIVE",
|
||||
"notes": "This grid is now actively monitored."
|
||||
}
|
||||
```
|
||||
- **成功响应** (`200 OK`): `Grid` (更新后的网格对象)
|
||||
|
||||
### 6.3 获取网格覆盖率统计
|
||||
|
||||
- **功能**: 按城市统计网格的覆盖情况。
|
||||
- **权限**: `ADMIN`
|
||||
- **URL**: `/api/grids/coverage`
|
||||
- **方法**: `GET`
|
||||
- **成功响应** (`200 OK`): `List<GridCoverageDTO>`
|
||||
|
||||
### 6.4 分配/解分配网格员 (通过网格ID)
|
||||
|
||||
#### 分配网格员
|
||||
- **功能**: 将一个网格员分配到指定的网格。
|
||||
- **权限**: `ADMIN`
|
||||
- **URL**: `/api/grids/{gridId}/assign`
|
||||
- **方法**: `POST`
|
||||
- **URL参数**: `gridId` (long)
|
||||
- **请求体**:
|
||||
```json
|
||||
{
|
||||
"userId": 123
|
||||
}
|
||||
```
|
||||
- **成功响应** (`200 OK`)
|
||||
|
||||
#### 解分配网格员
|
||||
- **功能**: 将一个网格员从指定的网格中移除。
|
||||
- **权限**: `ADMIN`
|
||||
- **URL**: `/api/grids/{gridId}/unassign`
|
||||
- **方法**: `POST`
|
||||
- **URL参数**: `gridId` (long)
|
||||
- **成功响应** (`200 OK`)
|
||||
|
||||
### 6.5 分配/解分配网格员 (通过坐标)
|
||||
|
||||
#### 分配网格员
|
||||
- **功能**: 将一个网格员分配到指定坐标的网格。
|
||||
- **权限**: `ADMIN`, `GRID_WORKER`
|
||||
- **URL**: `/api/grids/coordinates/{gridX}/{gridY}/assign`
|
||||
- **方法**: `POST`
|
||||
- **URL参数**:
|
||||
- `gridX` (int)
|
||||
- `gridY` (int)
|
||||
- **请求体**:
|
||||
```json
|
||||
{
|
||||
"userId": 123
|
||||
}
|
||||
```
|
||||
- **成功响应** (`200 OK`)
|
||||
|
||||
#### 解分配网格员
|
||||
- **功能**: 将一个网格员从指定坐标的网格中移除。
|
||||
- **权限**: `ADMIN`, `GRID_WORKER`
|
||||
- **URL**: `/api/grids/coordinates/{gridX}/{gridY}/unassign`
|
||||
- **方法**: `POST`
|
||||
- **URL参数**:
|
||||
- `gridX` (int)
|
||||
- `gridY` (int)
|
||||
- **成功响应** (`200 OK`)
|
||||
|
||||
---
|
||||
|
||||
## 7. 人员管理模块 (`/api/personnel`)
|
||||
|
||||
负责系统中所有用户账户的创建、查询、更新和删除 (CRUD)。
|
||||
|
||||
### 7.1 获取用户列表 (分页)
|
||||
|
||||
- **功能**: 获取系统中的用户列表,支持按角色和姓名进行筛选,并提供分页。
|
||||
- **权限**: `ADMIN`, `GRID_WORKER`
|
||||
- **URL**: `/api/personnel/users`
|
||||
- **方法**: `GET`
|
||||
- **请求参数**:
|
||||
- `role` (string, optional): 角色名称 (e.g., `ADMIN`, `GRID_WORKER`)
|
||||
- `name` (string, optional): 用户姓名 (模糊匹配)
|
||||
- `page` (int, optional): 页码
|
||||
- `size` (int, optional): 每页数量
|
||||
- **成功响应** (`200 OK`): `PageDTO<UserAccount>`
|
||||
|
||||
### 7.2 创建新用户
|
||||
|
||||
- **功能**: 创建一个新的用户账户。
|
||||
- **权限**: `ADMIN`
|
||||
- **URL**: `/api/personnel/users`
|
||||
- **方法**: `POST`
|
||||
- **请求体** (`UserCreationRequest`):
|
||||
```json
|
||||
{
|
||||
"name": "John Doe",
|
||||
"email": "john.doe@example.com",
|
||||
"password": "strongPassword123",
|
||||
"role": "GRID_WORKER"
|
||||
}
|
||||
```
|
||||
- **成功响应** (`201 Created`): `UserAccount`
|
||||
|
||||
### 7.3 获取用户详情
|
||||
|
||||
- **功能**: 根据ID获取单个用户的详细信息。
|
||||
- **权限**: `ADMIN`
|
||||
- **URL**: `/api/personnel/users/{userId}`
|
||||
- **方法**: `GET`
|
||||
- **URL参数**: `userId` (long)
|
||||
- **成功响应** (`200 OK`): `UserAccount` (密码字段为空)
|
||||
|
||||
### 7.4 更新用户信息
|
||||
|
||||
- **功能**: 更新指定用户的信息(例如姓名、邮箱,但不包括角色)。
|
||||
- **权限**: `ADMIN`
|
||||
- **URL**: `/api/personnel/users/{userId}`
|
||||
- **方法**: `PATCH`
|
||||
- **URL参数**: `userId` (long)
|
||||
- **请求体** (`UserUpdateRequest`):
|
||||
```json
|
||||
{
|
||||
"name": "Johnathan Doe",
|
||||
"email": "johnathan.doe@example.com"
|
||||
}
|
||||
```
|
||||
- **成功响应** (`200 OK`): `UserAccount`
|
||||
|
||||
### 7.5 更新用户角色
|
||||
|
||||
- **功能**: 单独更新用户的角色。
|
||||
- **权限**: `ADMIN`
|
||||
- **URL**: `/api/personnel/users/{userId}/role`
|
||||
- **方法**: `PUT`
|
||||
- **URL参数**: `userId` (long)
|
||||
- **请求体** (`UserRoleUpdateRequest`):
|
||||
```json
|
||||
{
|
||||
"role": "SUPERVISOR"
|
||||
}
|
||||
```
|
||||
- **成功响应** (`200 OK`): `UserAccount` (密码字段为空)
|
||||
|
||||
### 7.6 删除用户
|
||||
|
||||
- **功能**: 从系统中永久删除一个用户。
|
||||
- **权限**: `ADMIN`
|
||||
- **URL**: `/api/personnel/users/{userId}`
|
||||
- **方法**: `DELETE`
|
||||
- **URL参数**: `userId` (long)
|
||||
- **成功响应** (`204 No Content`)
|
||||
|
||||
---
|
||||
|
||||
## 8. 网格员任务模块 (`/api/worker`)
|
||||
|
||||
专为网格员 (`GRID_WORKER`) 提供的任务管理接口。
|
||||
|
||||
### 8.1 获取我的任务列表
|
||||
|
||||
- **功能**: 获取分配给当前登录网格员的任务列表,支持按状态筛选和分页。
|
||||
- **权限**: `GRID_WORKER`
|
||||
- **URL**: `/api/worker`
|
||||
- **方法**: `GET`
|
||||
- **请求参数**:
|
||||
- `status` (string, optional): 任务状态 (e.g., `ASSIGNED`, `IN_PROGRESS`, `COMPLETED`)
|
||||
- `page` (int, optional): 页码
|
||||
- `size` (int, optional): 每页数量
|
||||
- **成功响应** (`200 OK`): `Page<TaskSummaryDTO>`
|
||||
|
||||
### 8.2 获取任务详情
|
||||
|
||||
- **功能**: 获取单个任务的详细信息。
|
||||
- **权限**: `GRID_WORKER`
|
||||
- **URL**: `/api/worker/{taskId}`
|
||||
- **方法**: `GET`
|
||||
- **URL参数**: `taskId` (long)
|
||||
- **成功响应** (`200 OK`): `TaskDetailDTO`
|
||||
|
||||
### 8.3 接受任务
|
||||
|
||||
- **功能**: 网格员接受一个已分配给自己的任务。
|
||||
- **权限**: `GRID_WORKER`
|
||||
- **URL**: `/api/worker/{taskId}/accept`
|
||||
- **方法**: `POST`
|
||||
- **URL参数**: `taskId` (long)
|
||||
- **成功响应** (`200 OK`): `TaskSummaryDTO` (更新后的任务摘要)
|
||||
|
||||
### 8.4 提交任务完成情况
|
||||
|
||||
- **功能**: 网格员提交任务的完成情况,可附带文字说明和文件。
|
||||
- **权限**: `GRID_WORKER`
|
||||
- **URL**: `/api/worker/{taskId}/submit`
|
||||
- **方法**: `POST`
|
||||
- **内容类型**: `multipart/form-data`
|
||||
- **URL参数**: `taskId` (long)
|
||||
- **请求部分**:
|
||||
- `comments` (string): 任务完成情况的文字说明。
|
||||
- `files` (File[], optional): (可选) 相关的证明文件或图片。
|
||||
- **成功响应** (`200 OK`): `TaskSummaryDTO` (更新后的任务摘要)
|
||||
|
||||
---
|
||||
|
||||
## 9. 地图与寻路模块 (`/api/map`, `/api/pathfinding`)
|
||||
|
||||
提供地图数据管理和基于A*算法的路径规划功能。
|
||||
|
||||
### 9.1 地图管理 (`/api/map`)
|
||||
|
||||
#### 获取完整地图网格
|
||||
- **功能**: 获取用于渲染前端地图的完整网格数据。
|
||||
- **URL**: `/api/map/grid`
|
||||
- **方法**: `GET`
|
||||
- **成功响应** (`200 OK`): `List<MapGrid>`
|
||||
|
||||
#### 创建或更新网格单元
|
||||
- **功能**: 创建或更新单个网格单元的信息,如设置障碍物。
|
||||
- **URL**: `/api/map/grid`
|
||||
- **方法**: `POST`
|
||||
- **请求体** (`MapGrid`):
|
||||
```json
|
||||
{
|
||||
"x": 10,
|
||||
"y": 15,
|
||||
"obstacle": true,
|
||||
"terrainType": "water"
|
||||
}
|
||||
```
|
||||
- **成功响应** (`200 OK`): `MapGrid` (已保存的网格单元)
|
||||
|
||||
#### 初始化地图
|
||||
- **功能**: 清空并重新生成指定大小的地图网格(主要用于开发和测试)。
|
||||
- **URL**: `/api/map/initialize`
|
||||
- **方法**: `POST`
|
||||
- **请求参数**:
|
||||
- `width` (int, optional, default=20)
|
||||
- `height` (int, optional, default=20)
|
||||
- **成功响应** (`200 OK`): `String` (例如, "Initialized a 20x20 map.")
|
||||
|
||||
### 9.2 路径规划 (`/api/pathfinding`)
|
||||
|
||||
#### 查找路径
|
||||
- **功能**: 使用A*算法计算两点之间的最短路径,会避开障碍物。
|
||||
- **URL**: `/api/pathfinding/find`
|
||||
- **方法**: `POST`
|
||||
- **请求体** (`PathfindingRequest`):
|
||||
```json
|
||||
{
|
||||
"startX": 0,
|
||||
"startY": 0,
|
||||
"endX": 18,
|
||||
"endY": 18
|
||||
}
|
||||
```
|
||||
- **成功响应** (`200 OK`): `List<Point>` (路径点坐标列表,若无路径则为空列表)
|
||||
|
||||
---
|
||||
|
||||
## 10. 个人资料模块 (`/api/me`)
|
||||
|
||||
处理与当前登录用户个人账户相关的操作。
|
||||
|
||||
### 10.1 获取我的反馈历史
|
||||
|
||||
- **功能**: 获取当前登录用户提交过的所有反馈记录,支持分页。
|
||||
- **权限**: `isAuthenticated()` (任何已认证用户)
|
||||
- **URL**: `/api/me/feedback`
|
||||
- **方法**: `GET`
|
||||
- **请求参数**:
|
||||
- `page` (int, optional): 页码
|
||||
- `size` (int, optional): 每页数量
|
||||
- **成功响应** (`200 OK`): `Page<UserFeedbackSummaryDTO>`
|
||||
|
||||
---
|
||||
|
||||
## 11. 主管审核模块 (`/api/supervisor`)
|
||||
|
||||
专为主管 (`SUPERVISOR`) 和管理员 (`ADMIN`) 提供的反馈审核接口。
|
||||
|
||||
### 11.1 获取待审核列表
|
||||
|
||||
- **功能**: 获取所有状态为"待审核"的反馈列表。
|
||||
- **权限**: `SUPERVISOR`, `ADMIN`
|
||||
- **URL**: `/api/supervisor/reviews`
|
||||
- **方法**: `GET`
|
||||
- **成功响应** (`200 OK`): `List<Feedback>`
|
||||
|
||||
### 11.2 批准反馈
|
||||
|
||||
- **功能**: 将指定ID的反馈状态变更为"已批准"(通常意味着后续可被分配任务)。
|
||||
- **权限**: `SUPERVISOR`, `ADMIN`
|
||||
- **URL**: `/api/supervisor/reviews/{feedbackId}/approve`
|
||||
- **方法**: `POST`
|
||||
- **URL参数**: `feedbackId` (long)
|
||||
- **成功响应** (`200 OK`)
|
||||
|
||||
### 11.3 拒绝反馈
|
||||
|
||||
- **功能**: 拒绝一个反馈,并记录拒绝理由。
|
||||
- **权限**: `SUPERVISOR`, `ADMIN`
|
||||
- **URL**: `/api/supervisor/reviews/{feedbackId}/reject`
|
||||
- **方法**: `POST`
|
||||
- **URL参数**: `feedbackId` (long)
|
||||
- **请求体** (`RejectFeedbackRequest`):
|
||||
```json
|
||||
{
|
||||
"reason": "Insufficient evidence provided."
|
||||
}
|
||||
```
|
||||
- **成功响应** (`200 OK`)
|
||||
|
||||
---
|
||||
|
||||
## 12. 任务分配模块 (`/api/tasks`)
|
||||
|
||||
专为主管 (`SUPERVISOR`) 和管理员 (`ADMIN`) 提供的、将已审核通过的反馈分配为具体任务的接口。
|
||||
|
||||
### 12.1 获取未分配的任务
|
||||
|
||||
- **功能**: 获取所有已批准但尚未分配给任何网格员的反馈列表。
|
||||
- **权限**: `SUPERVISOR`, `ADMIN`
|
||||
- **URL**: `/api/tasks/unassigned`
|
||||
- **方法**: `GET`
|
||||
- **成功响应** (`200 OK`): `List<Feedback>`
|
||||
|
||||
### 12.2 获取可用的网格员
|
||||
|
||||
- **功能**: 获取系统中所有角色为 `GRID_WORKER` 的用户列表,用于任务分配。
|
||||
- **权限**: `SUPERVISOR`, `ADMIN`
|
||||
- **URL**: `/api/tasks/grid-workers`
|
||||
- **方法**: `GET`
|
||||
- **成功响应** (`200 OK`): `List<UserAccount>`
|
||||
|
||||
### 12.3 分配任务
|
||||
|
||||
- **功能**: 将一个反馈分配给一个网格员,从而创建一个新任务。
|
||||
- **权限**: `SUPERVISOR`, `ADMIN`
|
||||
- **URL**: `/api/tasks/assign`
|
||||
- **方法**: `POST`
|
||||
- **请求体** (`AssignmentRequest`):
|
||||
```json
|
||||
{
|
||||
"feedbackId": 10,
|
||||
"assigneeId": 123
|
||||
}
|
||||
```
|
||||
- **成功响应** (`200 OK`): `Assignment` (创建的任务分配记录)
|
||||
|
||||
---
|
||||
|
||||
## 13. 任务管理模块 (`/api/management/tasks`)
|
||||
@@ -1,559 +0,0 @@
|
||||
# Spring Boot 项目深度解析
|
||||
|
||||
本文档旨在深入解析当前 Spring Boot 项目的构建原理、核心技术以及业务逻辑,帮助您更好地理解和准备答疑。
|
||||
|
||||
## 一、Spring Boot 核心原理
|
||||
|
||||
Spring Boot 是一个用于简化新 Spring 应用的初始搭建以及开发过程的框架。其核心原理主要体现在以下几个方面:
|
||||
|
||||
### 1. 自动配置 (Auto-Configuration) - 智能的“管家”
|
||||
|
||||
您可以将 Spring Boot 的自动配置想象成一个非常智能的“管家”。在传统的 Spring 开发中,您需要手动配置很多东西,比如数据库连接、We你b 服务器等,就像您需要亲自告诉管家每一个细节:如何烧水、如何扫地。
|
||||
|
||||
而 Spring Boot 的“管家”则会观察您家里添置了什么新东西(即您在项目中加入了什么依赖),然后自动地把这些东西配置好,让它们能正常工作。
|
||||
|
||||
**它是如何工作的?**
|
||||
|
||||
1. **观察您的“购物清单” (`pom.xml`)**:当您在项目的 `pom.xml` 文件中加入一个 `spring-boot-starter-*` 依赖,比如 `spring-boot-starter-web`,就等于告诉“管家”:“我需要开发一个网站。”
|
||||
|
||||
2. **自动准备所需工具**:看到这个“购物清单”后,“管家”会立刻为您准备好一套完整的网站开发工具:
|
||||
* 一个嵌入式的 **Tomcat 服务器**,这样您就不用自己安装和配置服务器了。
|
||||
* 配置好 **Spring MVC** 框架,这是处理网页请求的核心工具。
|
||||
* 设置好处理 JSON 数据的工具 (Jackson),方便前后端通信。
|
||||
|
||||
3. **背后的魔法 (`@EnableAutoConfiguration`)**:这一切的起点是您项目主启动类上的 `@SpringBootApplication` 注解,它内部包含了 `@EnableAutoConfiguration`。这个注解就是给“管家”下达“开始自动工作”命令的开关。它会去检查一个固定的清单(位于 `META-INF/spring.factories`),上面写着所有它认识的工具(自动配置类)以及何时应该启用它们。
|
||||
|
||||
**项目实例:**
|
||||
|
||||
在本项目中,因为 `pom.xml` 包含了 `spring-boot-starter-web`,所以 Spring Boot 自动为您配置了处理 Web 请求的所有环境。这就是为什么您可以在 `com.dne.ems.controller` 包下的任何一个 Controller(例如 `AuthController`)中直接使用 `@RestController` 和 `@PostMapping` 这样的注解来定义 API 接口,而无需编写任何一行 XML 配置来启动 Web 服务或配置 Spring MVC。
|
||||
|
||||
简单来说,**自动配置就是 Spring Boot 替您完成了大部分繁琐、重复的配置工作,让您可以专注于编写业务代码。**
|
||||
|
||||
### 2. 起步依赖 (Starter Dependencies) - “主题工具箱”
|
||||
|
||||
如果说自动配置是“智能管家”,那么起步依赖就是“管家”使用的“主题工具箱”。您不需要告诉管家需要买钉子、锤子、螺丝刀……您只需要说:“我需要一个木工工具箱。”
|
||||
|
||||
起步依赖 (`spring-boot-starter-*`) 就是这样的“主题工具箱”。每一个 starter 都包含了一整套用于某个特定任务的、经过测试、版本兼容的依赖。
|
||||
|
||||
**项目实例:**
|
||||
|
||||
- **`spring-boot-starter-web`**: 这是“Web 开发工具箱”。它不仅包含了 Spring MVC,还包含了内嵌的 Tomcat 服务器和处理验证的库。您只需要引入这一个依赖,所有 Web 开发的基础环境就都准备好了。
|
||||
|
||||
- **`spring-boot-starter-data-jpa`**: 这是“数据库操作工具箱”。它打包了与数据库交互所需的一切,包括 Spring Data JPA、Hibernate (JPA 的一种实现) 和数据库连接池 (HikariCP)。您引入它之后,就可以直接在 `com.dne.ems.repository` 包下编写 `JpaRepository` 接口来进行数据库操作,而无需关心如何配置 Hibernate 或事务管理器。
|
||||
|
||||
- **`spring-boot-starter-security`**: 这是“安全管理工具箱”。引入它之后,Spring Security 框架就被集成进来,提供了认证和授权的基础功能。您可以在 `com.dne.ems.security.SecurityConfig` 中看到对这个“工具箱”的具体配置,比如定义哪些 API 需要登录才能访问。
|
||||
|
||||
**优势总结:**
|
||||
|
||||
- **简化依赖**:您不必再手动添加一长串的单个依赖项。
|
||||
- **避免冲突**:Spring Boot 已经为您管理好了这些依赖之间的版本,您不必再担心因为版本不兼容而导致的各种奇怪错误。
|
||||
|
||||
通过使用这些“工具箱”,您可以非常快速地搭建起一个功能完备的应用程序框架。
|
||||
|
||||
### 3. 嵌入式 Web 服务器
|
||||
|
||||
Spring Boot 内嵌了常见的 Web 服务器,如 Tomcat、Jetty 或 Undertow。这意味着您不需要将应用程序打包成 WAR 文件部署到外部服务器,而是可以直接将应用程序打包成一个可执行的 JAR 文件,通过 `java -jar` 命令来运行。
|
||||
|
||||
- **优势**:简化了部署流程,便于持续集成和持续部署 (CI/CD)。
|
||||
|
||||
## 二、前后端分离与交互原理
|
||||
|
||||
本项目采用前后端分离的架构,前端(如 Vue.js)和后端(Spring Boot)是两个独立的项目,它们之间通过 API 进行通信。
|
||||
|
||||
### 1. RESTful API
|
||||
|
||||
后端通过暴露一组 RESTful API 来提供服务。REST (Representational State Transfer) 是一种软件架构风格,它定义了一组用于创建 Web 服务的约束。核心思想是,将应用中的所有事物都看作资源,每个资源都有一个唯一的标识符 (URI)。
|
||||
|
||||
- **HTTP 方法**:
|
||||
- `GET`:获取资源。
|
||||
- `POST`:创建新资源。
|
||||
- `PUT` / `PATCH`:更新资源。
|
||||
- `DELETE`:删除资源。
|
||||
|
||||
### 2. JSON (JavaScript Object Notation)
|
||||
|
||||
前后端之间的数据交换格式通常是 JSON。当浏览器向后端发送请求时,它可能会在请求体中包含 JSON 数据。当后端响应时,它会将 Java 对象序列化为 JSON 字符串返回给前端。
|
||||
|
||||
- **Spring Boot 中的实现**:Spring Boot 默认使用 Jackson 库来处理 JSON 的序列化和反序列化。当 Controller 的方法参数有 `@RequestBody` 注解时,Spring 会自动将请求体中的 JSON 转换为 Java 对象。当方法有 `@ResponseBody` 或类有 `@RestController` 注解时,Spring 会自动将返回的 Java 对象转换为 JSON。
|
||||
|
||||
### 3. 认证与授权 (JWT)
|
||||
|
||||
在前后端分离架构中,常用的认证机制是 JSON Web Token (JWT)。
|
||||
|
||||
- **流程**:
|
||||
1. 用户使用用户名和密码登录。
|
||||
2. 后端验证凭据,如果成功,则生成一个 JWT 并返回给前端。
|
||||
3. 前端将收到的 JWT 存储起来(例如,在 `localStorage` 或 `sessionStorage` 中)。
|
||||
4. 在后续的每个请求中,前端都会在 HTTP 请求的 `Authorization` 头中携带这个 JWT。
|
||||
5. 后端的安全过滤器会拦截每个请求,验证 JWT 的有效性。如果验证通过,则允许访问受保护的资源。
|
||||
|
||||
## 三、项目业务逻辑与分层结构分析
|
||||
|
||||
本项目是一个环境管理系统 (EMS),其代码结构遵循经典的分层架构模式。
|
||||
|
||||
### 1. 分层结构概述
|
||||
|
||||
```
|
||||
+----------------------------------------------------+
|
||||
| Controller (表现层) |
|
||||
| (处理 HTTP 请求, 调用 Service, 返回 JSON 响应) |
|
||||
+----------------------+-----------------------------+
|
||||
| (调用)
|
||||
+----------------------v-----------------------------+
|
||||
| Service (业务逻辑层) |
|
||||
| (实现核心业务逻辑, 事务管理) |
|
||||
+----------------------+-----------------------------+
|
||||
| (调用)
|
||||
+----------------------v-----------------------------+
|
||||
| Repository (数据访问层) |
|
||||
| (通过 Spring Data JPA 与数据库交互) |
|
||||
+----------------------+-----------------------------+
|
||||
| (操作)
|
||||
+----------------------v-----------------------------+
|
||||
| Model (领域模型) |
|
||||
| (定义数据结构, 对应数据库表) |
|
||||
+----------------------------------------------------+
|
||||
```
|
||||
|
||||
### 2. 各层详细分析
|
||||
|
||||
#### a. Model (领域模型)
|
||||
|
||||
位于 `com.dne.ems.model` 包下,是应用程序的核心。这些是简单的 Java 对象 (POJO),使用 JPA 注解(如 `@Entity`, `@Table`, `@Id`, `@Column`)映射到数据库中的表。
|
||||
|
||||
- **核心实体**:
|
||||
- `UserAccount`: 用户账户信息,包含角色、状态等。
|
||||
- `Task`: 任务实体,包含任务状态、描述、位置等信息。
|
||||
- `Feedback`: 公众或用户提交的反馈信息。
|
||||
- `Grid`: 地理网格信息,用于管理和分配任务区域。
|
||||
- `Attachment`: 附件信息,如上传的图片。
|
||||
|
||||
#### b. Repository (数据访问层)
|
||||
|
||||
位于 `com.dne.ems.repository` 包下。这些是接口,继承自 Spring Data JPA 的 `JpaRepository`。开发者只需要定义接口,Spring Data JPA 会在运行时自动为其提供实现,从而极大地简化了数据访问代码。
|
||||
|
||||
- **示例**:`TaskRepository` 提供了对 `Task` 实体的 CRUD (创建、读取、更新、删除) 操作,以及基于方法名约定的查询功能(如 `findByStatus(TaskStatus status)`)。
|
||||
|
||||
#### c. Service (业务逻辑层)
|
||||
|
||||
位于 `com.dne.ems.service` 包下,是业务逻辑的核心实现。Service 层封装了应用程序的业务规则和流程,并负责协调多个 Repository 来完成一个完整的业务操作。事务管理也通常在这一层通过 `@Transactional` 注解来声明。
|
||||
|
||||
- **主要 Service 及其职责**:
|
||||
- `AuthService`: 处理用户认证,如登录、注册。
|
||||
- `TaskManagementService`: 负责任务的创建、更新、查询等核心管理功能。
|
||||
- `TaskAssignmentService`: 负责任务的分配逻辑,如自动分配或手动指派。
|
||||
- `SupervisorService`: 主管相关的业务逻辑,如审核任务。
|
||||
- `GridWorkerTaskService`: 网格员的任务处理逻辑,如提交任务进度。
|
||||
- `FeedbackService`: 处理公众反馈,可能包括创建任务等后续操作。
|
||||
- `PersonnelService`: 员工管理,如添加、查询用户信息。
|
||||
|
||||
- **层间关系**:Service 通常会注入 (DI) 一个或多个 Repository 来操作数据。一个 Service 也可能调用另一个 Service 来复用业务逻辑。
|
||||
|
||||
#### d. Controller (表现层)
|
||||
|
||||
位于 `com.dne.ems.controller` 包下。Controller 负责接收来自客户端的 HTTP 请求,解析请求参数,然后调用相应的 Service 来处理业务逻辑。最后,它将 Service 返回的数据(通常是 DTO)封装成 HTTP 响应(通常是 JSON 格式)返回给客户端。
|
||||
|
||||
- **主要 Controller 及其职责**:
|
||||
- `AuthController`: 暴露 `/api/auth/login`, `/api/auth/register` 等认证相关的端点。
|
||||
- `TaskManagementController`: 提供任务管理的 RESTful API,如 `GET /api/tasks`, `POST /api/tasks`。
|
||||
- `SupervisorController`: 提供主管操作的 API,如审核、分配任务。
|
||||
- `FileController`: 处理文件上传和下载。
|
||||
|
||||
- **DTO (Data Transfer Object)**:位于 `com.dne.ems.dto` 包下。Controller 和 Service 之间,以及 Controller 和前端之间,通常使用 DTO 来传输数据。这样做的好处是可以避免直接暴露数据库实体,并且可以根据前端页面的需要来定制数据结构,避免传输不必要的信息。
|
||||
|
||||
### 3. 安全 (Security)
|
||||
|
||||
位于 `com.dne.ems.security` 包下。使用 Spring Security 来提供全面的安全服务。
|
||||
|
||||
- `SecurityConfig`: 配置安全规则,如哪些 URL 是公开的,哪些需要认证,以及配置 JWT 过滤器。
|
||||
- `JwtAuthenticationFilter`: 一个自定义的过滤器,在每个请求到达 Controller 之前执行。它从请求头中提取 JWT,验证其有效性,并将用户信息加载到 Spring Security 的上下文中。
|
||||
- `UserDetailsServiceImpl`: 实现了 Spring Security 的 `UserDetailsService` 接口,负责根据用户名从数据库加载用户信息(包括密码和权限)。
|
||||
|
||||
## 四、总结
|
||||
|
||||
这个 Spring Boot 项目是一个典型的、结构清晰的、基于 RESTful API 的前后端分离应用。它有效地利用了 Spring Boot 的自动配置和起步依赖来简化开发,并通过分层架构将表现、业务逻辑和数据访问清晰地分离开来,使得项目易于理解、维护和扩展。
|
||||
|
||||
希望这份文档能帮助您在答疑中充满信心!
|
||||
|
||||
## 五、为小白定制:项目代码结构与工作流程详解
|
||||
|
||||
为了让您彻底理解代码是如何组织的,我们把整个后端项目想象成一个分工明确的大公司。
|
||||
|
||||
### 1. 公司各部门职责 (包/文件夹的作用)
|
||||
|
||||
- **`com.dne.ems.config` (后勤与配置部)**
|
||||
- **职责**: 负责应用的各种基础配置。比如 `WebClientConfig` 是配置网络请求工具的,`WebSocketConfig` 是配置实时通讯的,`DataInitializer` 则是在项目启动时初始化一些默认数据(比如默认的管理员账号)。这个部门确保了其他所有部门的工具和环境都是准备好的。
|
||||
|
||||
- **`com.dne.ems.model` (产品设计部)**
|
||||
- **职责**: 定义公司的核心“产品”是什么样的。这里的“产品”就是数据。例如,`UserAccount.java` 定义了“用户”有哪些属性(姓名、密码、角色等),`Task.java` 定义了“任务”有哪些属性(标题、状态、截止日期等)。它们是整个公司的业务基础,决定了公司要处理什么信息。这些文件直接对应数据库里的表结构。
|
||||
|
||||
- **`com.dne.ems.repository` (仓库管理部)**
|
||||
- **职责**: 专门负责和数据库这个大“仓库”打交道。当需要存取数据时,其他部门不会直接去仓库,而是会通知仓库管理员。例如,`TaskRepository` 提供了所有操作 `Task` 表的方法,如保存一个新任务、根据ID查找一个任务。这个部门使用了 Spring Data JPA 技术,所以代码看起来很简单,但功能强大。
|
||||
|
||||
- **`com.dne.ems.service` (核心业务部)**
|
||||
- **职责**: 这是公司的核心部门,负责处理所有实际的业务逻辑。一个业务操作可能很复杂,需要协调多个部门。例如,`TaskManagementService` (任务管理服务) 在创建一个新任务时,可能需要:
|
||||
1. 调用 `TaskRepository` 将任务信息存入数据库。
|
||||
2. 调用 `UserAccountRepository` 查找合适的执行人。
|
||||
3. 调用 `NotificationService` (如果存在的话) 发送通知。
|
||||
- **`impl` 子目录**: `service` 包下通常是接口 (定义了“能做什么”),而 `impl` (implementation) 包下是这些接口的具体实现 (定义了“具体怎么做”)。这是为了“面向接口编程”,是一种良好的编程习惯。
|
||||
|
||||
- **`com.dne.ems.controller` (客户服务与接待部)**
|
||||
- **职责**: 这是公司的“前台”,直接面向客户(在这里就是前端浏览器或App)。它接收客户的请求(HTTP 请求),然后将请求传达给相应的业务部门 (`Service`) 去处理。处理完成后,它再把结果(通常是 JSON 格式的数据)返回给客户。
|
||||
- 例如,`TaskManagementController` 里的一个 `createTask` 方法,会接收前端发来的创建任务的请求,然后调用 `TaskManagementService` 的 `createTask` 方法来真正执行创建逻辑。
|
||||
|
||||
- **`com.dne.ems.dto` (数据包装与运输部)**
|
||||
- **职责**: 负责数据的包装和运输。直接把数据库里的原始数据 (`Model`) 给客户看是不安全也不专业的。DTO (Data Transfer Object) 就是专门用于在各部门之间,特别是“前台”(`Controller`)和客户(前端)之间传递数据的“包装盒”。
|
||||
- 例如,`TaskDTO` 可能只包含任务的ID、标题和状态,而隐藏了创建时间、更新时间等前端不需要的敏感信息。
|
||||
|
||||
- **`com.dne.ems.security` (安保部)**
|
||||
- **职责**: 负责整个公司的安全。`SecurityConfig` 定义了公司的安保规则(比如哪些地方需要门禁卡才能进),`JwtAuthenticationFilter` 就是门口的保安,每个请求进来都要检查它的“门禁卡”(JWT Token) 是否有效。
|
||||
|
||||
- **`com.dne.ems.exception` (风险与危机处理部)**
|
||||
- **职责**: 处理各种突发异常情况。当业务流程中出现错误时(比如找不到用户、数据库连接失败),`GlobalExceptionHandler` 会捕获这些错误,并给出一个统一、友好的错误提示给前端,而不是让程序崩溃。
|
||||
|
||||
### 2. 一次典型的请求流程:用户登录
|
||||
|
||||
让我们通过“用户登录”这个简单的例子,看看这些部门是如何协同工作的:
|
||||
|
||||
1. **客户上门 (前端 -> Controller)**: 用户在前端页面输入用户名和密码,点击登录。前端将这些信息打包成一个 JSON 对象,发送一个 HTTP POST 请求到后端的 `/api/auth/login` 地址。
|
||||
|
||||
2. **前台接待 (Controller)**: `AuthController` 接收到这个请求。它看到地址是 `/login`,于是调用 `login` 方法。它从请求中取出 JSON 数据,并将其转换为 `LoginRequest` 这个 DTO 对象。
|
||||
|
||||
3. **转交业务部门 (Controller -> Service)**: `AuthController` 自己不处理登录逻辑,它调用 `AuthService` 的 `login` 方法,并将 `LoginRequest` 这个 DTO 传递过去。
|
||||
|
||||
4. **核心业务处理 (Service)**: `AuthService` 开始处理登录:
|
||||
a. 它首先需要验证用户名是否存在,于是它请求 **仓库管理部** (`UserAccountRepository`):“请帮我根据这个用户名 (`loginRequest.getUsername()`) 查一下有没有这个人。”
|
||||
b. `UserAccountRepository` 从数据库中查找到对应的 `UserAccount` (Model) 信息,返回给 `AuthService`。
|
||||
c. `AuthService` 拿到用户信息后,会使用密码加密工具,验证用户提交的密码和数据库中存储的加密密码是否匹配。
|
||||
d. 如果验证成功,`AuthService` 会请求 **安保部** (`JwtService`):“请为这位用户生成一张有时效的门禁卡 (JWT Token)。”
|
||||
|
||||
5. **返回处理结果 (Service -> Controller -> 前端)**: `JwtService` 生成 Token 后返回给 `AuthService`。`AuthService` 将 Token 包装在一个 `JwtAuthenticationResponse` DTO 中,返回给 `AuthController`。`AuthController` 再将这个包含 Token 的 DTO 转换成 JSON 格式,作为 HTTP 响应返回给前端。
|
||||
|
||||
6. **客户拿到凭证 (前端)**: 前端收到包含 Token 的响应,就知道登录成功了。它会把这个 Token 保存起来,在之后访问需要权限的页面时,都会带上这张“门禁卡”。
|
||||
|
||||
通过这个流程,您可以看到,一个简单的请求背后是多个“部门”按照明确的职责划分,层层调用、协同工作的结果。这种结构使得代码逻辑清晰,易于维护和扩展。
|
||||
嗯
|
||||
## 六、核心业务流程与关键机制分析
|
||||
|
||||
下面,我们将梳理出本项目的几个核心业务流程和支撑这些流程的关键技术机制,并详细说明它们涉及的层级和文件,让您清晰地看到数据和指令是如何在系统中流转的。
|
||||
|
||||
### (一) 核心业务流程
|
||||
|
||||
#### 流程一:用户认证与授权 (Authentication & Authorization)
|
||||
|
||||
**目标**:保障系统安全,确保只有授权用户才能访问受保护的资源。
|
||||
|
||||
**相关API端点** (`/api/auth`):
|
||||
- `POST /api/auth/signup`: 用户注册。
|
||||
- `POST /api/auth/login`: 用户登录。
|
||||
- `POST /api/auth/send-verification-code`: 发送邮箱验证码。
|
||||
- `POST /api/auth/request-password-reset`: 请求重置密码。
|
||||
- `POST /api/auth/reset-password`: 执行密码重置。
|
||||
|
||||
**执行路径**:
|
||||
|
||||
1. **注册 (`signup`)**
|
||||
* **入口**: `AuthController.signup()` 对应 `POST /api/auth/signup`。
|
||||
* **业务逻辑**: `AuthService.signup()`
|
||||
* 验证邮箱和验证码的有效性 (`VerificationCodeService`)。
|
||||
* 检查邮箱是否已注册 (`UserAccountRepository`)。
|
||||
* 对密码进行加密 (`PasswordEncoder`)。
|
||||
* 创建并保存新的 `UserAccount` 实体。
|
||||
|
||||
2. **登录 (`login`)**
|
||||
* **入口**: `AuthController.login()` 对应 `POST /api/auth/login`。
|
||||
* **业务逻辑**: `AuthService.login()`
|
||||
* 通过 Spring Security 的 `AuthenticationManager` 验证用户名和密码。
|
||||
* 如果认证成功,调用 `JwtService` 生成 JWT。
|
||||
* 返回包含 JWT 的响应给前端。
|
||||
|
||||
3. **访问受保护资源**
|
||||
* **安全过滤器**: `JwtAuthenticationFilter`
|
||||
* 拦截所有请求,从 `Authorization` 请求头中提取 JWT。
|
||||
* 验证 JWT 的有效性 (`JwtService`)。
|
||||
* 如果有效,从 JWT 中解析出用户信息,并构建一个 `UsernamePasswordAuthenticationToken`,设置到 Spring Security 的 `SecurityContextHolder` 中,完成授权。
|
||||
|
||||
#### 流程二:公众反馈与任务转化 (Feedback to Task)
|
||||
|
||||
**目标**:将公众通过开放接口提交的反馈(如环境问题)转化为系统内部的可追踪任务。
|
||||
|
||||
**相关API端点**:
|
||||
- `POST /api/public/feedback`: 公众提交反馈。
|
||||
- `GET /api/supervisor/reviews`: 主管获取待审核的反馈列表。
|
||||
- `POST /api/supervisor/reviews/{feedbackId}/approve`: 主管批准反馈。
|
||||
- `POST /api/supervisor/reviews/{feedbackId}/reject`: 主管拒绝反馈。
|
||||
- `POST /api/management/tasks/feedback/{feedbackId}/create-task`: 从反馈创建任务。
|
||||
|
||||
**执行路径**:
|
||||
|
||||
1. **提交反馈**
|
||||
* **入口**: `PublicController.submitFeedback()` 对应 `POST /api/public/feedback`。
|
||||
* **业务逻辑**: `FeedbackService.createFeedback()`
|
||||
* 接收 `PublicFeedbackRequest`,包含反馈内容和可选的附件。
|
||||
* 处理文件上传(如果存在),调用 `FileStorageService` 保存文件,并将附件信息与反馈关联。
|
||||
* 保存 `Feedback` 实体到数据库。
|
||||
|
||||
2. **反馈审核与任务创建 (由主管操作)**
|
||||
* **入口**: `SupervisorController` 和 `TaskManagementController` 的相关方法。
|
||||
* **业务逻辑**: `SupervisorService.processFeedback()` 和 `TaskManagementService.createTaskFromFeedback()`
|
||||
* 主管通过 `GET /api/supervisor/reviews` 查看待处理反馈。
|
||||
* 通过 `POST /api/supervisor/reviews/{feedbackId}/approve` 批准反馈。
|
||||
* 批准后,可通过 `POST /api/management/tasks/feedback/{feedbackId}/create-task` 基于反馈信息创建一个新的 `Task`。
|
||||
|
||||
#### 流程三:任务生命周期管理 (Task Lifecycle)
|
||||
|
||||
**目标**:完整地管理一个任务从创建、分配、执行到完成的全过程。
|
||||
|
||||
**相关API端点**:
|
||||
- **主管/管理员**:
|
||||
- `POST /api/management/tasks`: 直接创建任务。
|
||||
- `GET /api/management/tasks`: 获取任务列表。
|
||||
- `POST /api/management/tasks/{taskId}/assign`: 分配任务。
|
||||
- `POST /api/management/tasks/{taskId}/review`: 审核任务。
|
||||
- `POST /api/management/tasks/{taskId}/cancel`: 取消任务。
|
||||
- **网格员**:
|
||||
- `GET /api/worker`: 获取我的任务列表。
|
||||
- `GET /api/worker/{taskId}`: 获取任务详情。
|
||||
- `POST /api/worker/{taskId}/accept`: 接受任务。
|
||||
- `POST /api/worker/{taskId}/submit`: 提交任务成果。
|
||||
|
||||
**执行路径**:
|
||||
|
||||
1. **任务创建**
|
||||
* **入口**: `TaskManagementController.createTask()` 对应 `POST /api/management/tasks`。
|
||||
* **业务逻辑**: `TaskManagementService.createTask()`
|
||||
* 创建 `Task` 实体并设置初始状态(如 `PENDING_ASSIGNMENT`)。
|
||||
|
||||
2. **任务分配**
|
||||
* **入口**: `TaskManagementController.assignTask()` 对应 `POST /api/management/tasks/{taskId}/assign`。
|
||||
* **业务逻辑**: `TaskAssignmentService.assignTaskToWorker()`
|
||||
* 将任务 (`Task`) 与一个网格员 (`GridWorker`) 关联起来,创建 `Assignment` 记录。
|
||||
* 更新任务状态为 `ASSIGNED`。
|
||||
|
||||
3. **任务执行与更新**
|
||||
* **入口**: `GridWorkerTaskController` 的相关方法,如 `acceptTask()` 和 `submitTask()`。
|
||||
* **业务逻辑**: `GridWorkerTaskService.updateTaskProgress()`
|
||||
* 网格员通过 `POST /api/worker/{taskId}/accept` 接受任务。
|
||||
* 通过 `POST /api/worker/{taskId}/submit` 提交任务进度或结果,可附带图片等附件 (`FileStorageService`)。
|
||||
* 更新任务状态(如 `IN_PROGRESS`, `COMPLETED`)。
|
||||
|
||||
4. **任务审核与关闭**
|
||||
* **入口**: `TaskManagementController.reviewTask()` 对应 `POST /api/management/tasks/{taskId}/review`。
|
||||
* **业务逻辑**: `SupervisorService.reviewAndCloseTask()`
|
||||
* 主管审核已完成的任务。
|
||||
* 如果合格,将任务状态更新为 `CLOSED`。如果不合格,可打回 (`REJECTED`)。
|
||||
|
||||
#### 流程四:数据可视化与决策支持 (Dashboard & AI)
|
||||
|
||||
**目标**:为管理层提供数据洞察,并通过 AI 功能辅助决策。
|
||||
|
||||
**相关API端点**:
|
||||
- **仪表盘** (`/api/dashboard`):
|
||||
- `GET /api/dashboard/stats`: 获取核心统计数据。
|
||||
- `GET /api/dashboard/reports/aqi-distribution`: 获取 AQI 分布。
|
||||
- `GET /api/dashboard/map/heatmap`: 获取反馈热力图数据。
|
||||
- `GET /api/dashboard/reports/task-completion-stats`: 获取任务完成情况统计。
|
||||
- **路径规划** (`/api/pathfinding`):
|
||||
- `POST /api/pathfinding/find`: 使用 A* 算法寻找路径。
|
||||
|
||||
**执行路径**:
|
||||
|
||||
1. **仪表盘数据**
|
||||
* **入口**: `DashboardController` 中的各个接口。
|
||||
* **业务逻辑**: `DashboardService`
|
||||
* 调用多个 `Repository`(如 `TaskRepository`, `FeedbackRepository`)进行数据聚合查询,统计任务状态、反馈趋势等。
|
||||
* 返回 DTO 给前端进行图表展示。
|
||||
|
||||
2. **AI 辅助功能**
|
||||
* **文本审核**: `AiReviewService.reviewText()` 可能被用于自动审核反馈内容或评论,识别敏感信息 (无直接API,内部调用)。
|
||||
* **路径规划**: `AStarService.findPath()` 对应 `POST /api/pathfinding/find`,用于计算两点之间的最优路径,可辅助网格员规划任务路线。
|
||||
|
||||
### (二) 关键支撑机制
|
||||
|
||||
除了核心业务流程,系统还包含一系列关键的技术机制来保证其健壮、安全和可维护性。
|
||||
|
||||
1. **文件上传与管理**
|
||||
* **位置**: `FileStorageService`, `FileController`
|
||||
* **作用**: 提供统一的文件存储和访问服务。无论是用户头像、反馈附件还是任务报告,都通过此服务进行处理,实现了与具体存储位置(本地文件系统或云存储)的解耦。
|
||||
|
||||
2. **邮件与验证码服务**
|
||||
* **位置**: `MailService`, `VerificationCodeService`
|
||||
* **作用**: 负责发送邮件(如注册验证、密码重置)和管理验证码的生成与校验,是保障账户安全的重要环节。
|
||||
|
||||
3. **登录安全与尝试锁定**
|
||||
* **位置**: `LoginAttemptService`, `AuthenticationFailureEventListener`
|
||||
* **作用**: 监听登录失败事件 (`AuthenticationFailureListener`),并通过 `LoginAttemptService` 记录特定 IP 的失败次数。当超过阈值时,会暂时锁定该 IP 的登录权限,有效防止暴力破解攻击。
|
||||
|
||||
4. **A* 路径规划算法**
|
||||
* **位置**: `AStarService`, `PathfindingController`
|
||||
* **作用**: 实现了 A* 寻路算法,这是一个独立的功能模块,可以根据地图数据(网格 `Grid`)计算最优路径,为其他业务(如任务路线规划)提供支持。
|
||||
|
||||
5. **系统事件处理机制**
|
||||
* **位置**: `event` 和 `listener` 包
|
||||
* **作用**: 基于 Spring 的事件驱动模型,实现系统内各组件的解耦。例如,当一个用户注册成功后,可以发布一个 `UserRegistrationEvent` 事件,而邮件发送监听器 (`EmailNotificationListener`) 和新用户欢迎监听器 (`WelcomeBonusListener`) 可以分别监听并处理此事件,而无需在注册服务中硬编码这些逻辑。
|
||||
|
||||
6. **全局异常处理**
|
||||
* **位置**: `GlobalExceptionHandler`
|
||||
* **作用**: 捕获整个应用中抛出的未处理异常,并根据异常类型返回统一、规范的错误响应给前端。这避免了将原始的、可能包含敏感信息的堆栈跟踪暴露给用户,并提升了用户体验。
|
||||
|
||||
7. **自定义数据校验**
|
||||
* **位置**: `validation` 包 (如 `PasswordValidator`)
|
||||
* **作用**: 实现自定义的、复杂的校验逻辑。例如,`@ValidPassword` 注解可以确保用户设置的密码符合特定的强度要求(如长度、包含数字和特殊字符等)。
|
||||
|
||||
8. **数据持久化与查询 (JPA)**
|
||||
* **位置**: `repository` 包
|
||||
* **作用**: 利用 Spring Data JPA,通过定义接口 (`extends JpaRepository`) 的方式,极大地简化了数据库的 CRUD 操作和查询。开发者无需编写 SQL 语句,JPA 会自动根据方法名或注解生成相应的查询。
|
||||
|
||||
9. **API 数据契约 (DTO)**
|
||||
* **位置**: `dto` 包
|
||||
* **作用**: 数据传输对象 (Data Transfer Object) 是前后端分离架构中的关键实践。它作为 API 的“数据契约”,明确了接口需要什么数据、返回什么数据,实现了表现层与领域模型的解耦,使得双方可以独立演进,同时避免了敏感信息的泄露。
|
||||
|
||||
10. **应用配置与初始化**
|
||||
* **位置**: `config` 包, `DataInitializer`
|
||||
* **作用**: `config` 包集中管理了应用的所有配置类,如安全配置 (`SecurityConfig`)、Web 配置等。`DataInitializer` 则利用 `CommandLineRunner` 接口,在应用启动后执行一次性任务,如创建默认管理员账户、初始化基础数据等,确保了应用开箱即用的能力。
|
||||
* **密码加密**: 使用 `PasswordEncoder` 对用户密码进行加密,增强安全性。
|
||||
* **创建用户实体**: 创建一个新的 `UserAccount` 对象 (`Model`),并填充信息。
|
||||
|
||||
3. **Repository (数据访问层)**
|
||||
* **文件**: `com.dne.ems.repository.UserAccountRepository.java`
|
||||
* **方法**: `save(UserAccount user)`
|
||||
* **作用**: `AuthService` 调用此方法,将新创建的 `UserAccount` 对象持久化到数据库中。
|
||||
|
||||
4. **Model (领域模型)**
|
||||
* **文件**: `com.dne.ems.model.UserAccount.java`
|
||||
* **作用**: 定义了用户账户的数据结构,是数据库中 `user_accounts` 表的映射。
|
||||
|
||||
### 流程二:任务创建与分配
|
||||
|
||||
**目标**:主管或管理员根据一个已批准的反馈,创建一个新任务,并将其分配给一个网格员。
|
||||
|
||||
**执行路径**:
|
||||
|
||||
1. **Controller (表现层)**
|
||||
* **文件**: `com.dne.ems.controller.TaskManagementController.java`
|
||||
* **方法**: `createTaskFromFeedback(long feedbackId, TaskFromFeedbackRequest request)`
|
||||
* **作用**: 接收 `/api/management/tasks/feedback/{feedbackId}/create-task` POST 请求。它将反馈ID和任务创建请求 (`TaskFromFeedbackRequest` DTO) 传递给 Service 层。
|
||||
|
||||
2. **Service (业务逻辑层)**
|
||||
* **文件**: `com.dne.ems.service.impl.TaskManagementServiceImpl.java`
|
||||
* **方法**: `createTaskFromFeedback(long feedbackId, TaskFromFeedbackRequest request)`
|
||||
* **作用**: 实现核心的创建和分配逻辑:
|
||||
* **查找反馈**: 调用 `FeedbackRepository` 找到对应的 `Feedback` (`Model`)。
|
||||
* **查找负责人**: 调用 `UserAccountRepository` 找到指定的负责人 `UserAccount` (`Model`)。
|
||||
* **创建任务**: 创建一个新的 `Task` 对象 (`Model`),并从 `Feedback` 和请求 DTO 中填充任务信息(如描述、截止日期、严重性等)。
|
||||
* **设置状态**: 将任务的初始状态设置为 `ASSIGNED`。
|
||||
|
||||
3. **Repository (数据访问层)**
|
||||
* **文件**: `com.dne.ems.repository.TaskRepository.java`
|
||||
* **方法**: `save(Task task)`
|
||||
* **作用**: `TaskManagementService` 调用此方法,将新创建的 `Task` 对象保存到数据库。
|
||||
* **涉及的其他 Repository**: `FeedbackRepository` 和 `UserAccountRepository` 用于在业务逻辑中获取必要的数据。
|
||||
|
||||
4. **Model (领域模型)**
|
||||
* **文件**: `com.dne.ems.model.Task.java`
|
||||
* **作用**: 定义了任务的数据结构。
|
||||
* **涉及的其他 Model**: `Feedback.java` 和 `UserAccount.java` 作为数据来源。
|
||||
|
||||
### 流程三:网格员处理任务与提交反馈
|
||||
|
||||
**目标**:网格员查看自己的任务,执行任务,并提交处理结果(包括评论和附件)。
|
||||
|
||||
**执行路径**:
|
||||
|
||||
1. **Controller (表现层)**
|
||||
* **文件**: `com.dne.ems.controller.GridWorkerTaskController.java`
|
||||
* **方法**: `submitTask(long taskId, String comments, List<MultipartFile> files)`
|
||||
* **作用**: 接收 `/api/worker/{taskId}/submit` POST 请求。这是一个 `multipart/form-data` 请求,因为它同时包含了文本(评论)和文件。Controller 将这些信息传递给 Service 层。
|
||||
|
||||
2. **Service (业务逻辑层)**
|
||||
* **文件**: `com.dne.ems.service.impl.GridWorkerTaskServiceImpl.java`
|
||||
* **方法**: `submitTask(long taskId, String comments, List<MultipartFile> files)`
|
||||
* **作用**: 处理任务提交的业务逻辑:
|
||||
* **查找任务**: 调用 `TaskRepository` 找到当前需要处理的 `Task` (`Model`)。
|
||||
* **验证权限**: 确保当前登录的用户就是这个任务的负责人。
|
||||
* **处理文件上传**: 如果有附件,调用 `FileStorageService` 将文件保存到服务器,并创建 `Attachment` (`Model`) 对象。
|
||||
* **更新任务状态**: 将任务状态更新为 `SUBMITTED` 或 `PENDING_REVIEW`。
|
||||
* **保存评论和附件信息**: 将评论和附件信息关联到任务上。
|
||||
|
||||
3. **Repository (数据访问层)**
|
||||
* **文件**: `com.dne.ems.repository.TaskRepository.java`
|
||||
* **方法**: `save(Task task)`
|
||||
* **作用**: `GridWorkerTaskService` 在更新了任务状态和信息后,调用此方法将 `Task` 对象的变化持久化到数据库。
|
||||
* **涉及的其他 Repository**: `AttachmentRepository` (如果适用) 用于保存附件信息。
|
||||
|
||||
4. **Model (领域模型)**
|
||||
* **文件**: `com.dne.ems.model.Task.java`
|
||||
* **作用**: 任务数据在此流程中被更新。
|
||||
* **涉及的其他 Model**: `Attachment.java` 用于表示上传的文件。
|
||||
* **密码加密**: 使用 `PasswordEncoder` 对用户提交的明文密码进行加密,确保数据库中存储的是密文,保障安全。
|
||||
* **创建用户实体**: 创建一个新的 `UserAccount` (Model) 对象,并将注册信息(包括加密后的密码和角色)设置到该对象中。
|
||||
|
||||
3. **Service -> Repository (数据访问层)**
|
||||
* **文件**: `com.dne.ems.repository.UserAccountRepository.java`
|
||||
* **方法**: `save(UserAccount userAccount)`
|
||||
* **作用**: Service 层调用此方法,将填充好数据的 `UserAccount` 实体对象持久化到数据库中。Spring Data JPA 会自动生成对应的 SQL `INSERT` 语句来完成操作。
|
||||
|
||||
4. **返回结果**: 数据成功存入数据库后,操作结果会逐层返回,最终 `AuthController` 会向前端返回一个成功的响应消息。
|
||||
|
||||
### 流程二:任务的创建与自动分配
|
||||
|
||||
**目标**:系统管理员或主管创建一个新的环境问题任务,并由系统自动分配给相应网格内的网格员。
|
||||
|
||||
**执行路径**:
|
||||
|
||||
1. **前端 -> Controller (表现层)**
|
||||
* **文件**: `com.dne.ems.controller.TaskManagementController.java`
|
||||
* **方法**: `createTask(TaskCreateRequest taskCreateRequest)`
|
||||
* **作用**: 接收 `/api/tasks` POST 请求,请求体中包含了任务的详细信息(如描述、位置、图片附件ID等),封装在 `TaskCreateRequest` DTO 中。Controller 调用 `TaskManagementService` 来处理创建逻辑。
|
||||
|
||||
2. **Controller -> Service (业务逻辑层)**
|
||||
* **文件**: `com.dne.ems.service.impl.TaskManagementServiceImpl.java`
|
||||
* **方法**: `createTask(TaskCreateRequest taskCreateRequest)`
|
||||
* **作用**: 创建任务的核心业务逻辑。
|
||||
* 创建一个新的 `Task` (Model) 实体。
|
||||
* 根据请求中的附件ID,调用 `AttachmentRepository` 查找并关联附件。
|
||||
* 设置任务的初始状态为 `PENDING` (待处理)。
|
||||
* 调用 `TaskRepository` 将新任务保存到数据库。
|
||||
* **触发任务分配**: 保存任务后,调用 `TaskAssignmentService` 来执行自动分配逻辑。
|
||||
|
||||
3. **Service -> Service (业务逻辑层内部调用)**
|
||||
* **文件**: `com.dne.ems.service.impl.TaskAssignmentServiceImpl.java`
|
||||
* **方法**: `assignTask(Task task)`
|
||||
* **作用**: 处理任务的分配逻辑。
|
||||
* 根据任务的地理位置信息,调用 `GridRepository` 找到对应的地理网格 (`Grid`)。
|
||||
* 根据网格信息,调用 `UserAccountRepository` 找到负责该网格的网格员 (`GridWorker`)。
|
||||
* 如果找到合适的网格员,则更新 `Task` 实体的 `assignee` (执行人) 字段。
|
||||
* 更新任务状态为 `ASSIGNED` (已分配)。
|
||||
* 调用 `TaskRepository` 将更新后的任务信息保存回数据库。
|
||||
* (可选) 调用通知服务,向被分配的网格员发送新任务通知。
|
||||
|
||||
4. **Service -> Repository (数据访问层)**
|
||||
* **文件**: `com.dne.ems.repository.TaskRepository.java`, `com.dne.ems.repository.GridRepository.java`, `com.dne.ems.repository.UserAccountRepository.java`
|
||||
* **作用**: 在整个流程中,Service 层会频繁地与这些 Repository 交互,以查询网格信息、查询用户信息、保存和更新任务数据。
|
||||
|
||||
### 流程三:网格员处理任务并提交反馈
|
||||
|
||||
**目标**:网格员在完成任务后,通过 App 或前端页面提交任务处理结果,包括文字描述和现场图片。
|
||||
|
||||
**执行路径**:
|
||||
|
||||
1. **前端 -> Controller (表现层)**
|
||||
* **文件**: `com.dne.ems.controller.GridWorkerTaskController.java`
|
||||
* **方法**: `submitTaskFeedback(Long taskId, TaskFeedbackRequest feedbackRequest)`
|
||||
* **作用**: 接收 `/api/worker/tasks/{taskId}/feedback` POST 请求。路径中的 `taskId` 指明了要为哪个任务提交反馈,请求体 `TaskFeedbackRequest` DTO 中包含了反馈内容和附件ID。
|
||||
|
||||
2. **Controller -> Service (业务逻辑层)**
|
||||
* **文件**: `com.dne.ems.service.impl.GridWorkerTaskServiceImpl.java`
|
||||
* **方法**: `submitTaskFeedback(Long taskId, TaskFeedbackRequest feedbackRequest)`
|
||||
* **作用**: 处理网格员提交反馈的业务逻辑。
|
||||
* 调用 `TaskRepository` 检查任务是否存在以及当前用户是否有权限操作该任务。
|
||||
* 更新 `Task` 实体的状态为 `COMPLETED` (已完成) 或 `PENDING_REVIEW` (待审核)。
|
||||
* 创建一个新的 `Feedback` (Model) 实体,将反馈内容和关联的 `Task` 设置进去。
|
||||
* 调用 `FeedbackRepository` 将新的反馈信息保存到数据库。
|
||||
* 调用 `TaskRepository` 更新任务状态。
|
||||
|
||||
3. **Service -> Repository (数据访问层)**
|
||||
* **文件**: `com.dne.ems.repository.TaskRepository.java`, `com.dne.ems.repository.FeedbackRepository.java`
|
||||
* **作用**: `TaskRepository` 用于查询和更新任务信息,`FeedbackRepository` 用于保存新的反馈记录。
|
||||
|
||||
通过以上对核心业务流程的梳理,您可以清晰地看到,用户的每一个操作是如何触发后端系统中不同层、不同文件之间的一系列连锁反应,最终完成一个完整的业务闭环。这种清晰的、分层的架构是保证项目可维护性和扩展性的关键。
|
||||
@@ -1,82 +0,0 @@
|
||||
# 东软环保公众监督系统 - Vue 界面设计规约
|
||||
|
||||
## 1. 设计原则
|
||||
- **一致性**: 所有界面元素、组件和交互行为应保持高度一致。
|
||||
- **清晰性**: 界面布局、信息层级和操作指引清晰明确,避免用户困惑。
|
||||
- **效率性**: 简化操作流程,减少不必要的点击和输入,让用户高效完成任务。
|
||||
- **响应式**: 确保在不同尺寸的设备上(特别是PC端主流分辨率)都能获得良好的视觉和交互体验。
|
||||
- **美观性**: 遵循现代化的审美标准,界面简洁、美观、专业。
|
||||
|
||||
## 2. 颜色系统 (Color Palette)
|
||||
颜色方案以"科技蓝"为主色调,辅以中性灰和功能色,营造专业、冷静、可靠的视觉感受。
|
||||
|
||||
- **主色 (Primary)**
|
||||
- `Brand Blue`: `#409EFF` - 用于关键操作按钮、Logo、导航高亮等。
|
||||
- **功能色 (Functional)**
|
||||
- `Success Green`: `#67C23A` - 用于成功提示、操作完成状态。
|
||||
- `Warning Orange`: `#E6A23C` - 用于警告信息、需要用户注意的操作。
|
||||
- `Danger Red`: `#F56C6C` - 用于错误提示、删除、高危操作。
|
||||
- `Info Gray`: `#909399` - 用于普通信息、辅助说明。
|
||||
- **中性色 (Neutral)**
|
||||
- `Text Primary`: `#303133` - 主要文字颜色。
|
||||
- `Text Regular`: `#606266` - 常规文字、次要信息。
|
||||
- `Text Secondary`: `#909399` - 辅助、占位文字。
|
||||
- `Border Color`: `#DCDFE6` - 边框、分割线。
|
||||
- `Background`: `#F5F7FA` - 页面背景色。
|
||||
- `Container Background`: `#FFFFFF` - 卡片、表格等容器背景色。
|
||||
|
||||
## 3. 字体与排版 (Typography)
|
||||
- **字体族**: `Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif`
|
||||
- **字号体系**:
|
||||
- `H1 / 页面主标题`: 24px (Bold)
|
||||
- `H2 / 区域标题`: 20px (Bold)
|
||||
- `H3 / 卡片/弹窗标题`: 18px (Medium)
|
||||
- `正文/表格内容`: 14px (Regular)
|
||||
- `辅助/说明文字`: 12px (Regular)
|
||||
- **行高**: `1.6` - `1.8`,保证阅读舒适性。
|
||||
- **段落间距**: `16px`
|
||||
|
||||
## 4. 布局与间距 (Layout & Spacing)
|
||||
- **主布局**: 采用经典的侧边栏导航 + 内容区的布局方式。
|
||||
- `NEPM (管理端)` / `NEPV (大屏端)`: 左侧为固定菜单栏,右侧为内容展示区。
|
||||
- `NEPS (公众端)` / `NEPG (网格员端)`: 根据移动端优先原则,可采用底部Tab栏或顶部导航。
|
||||
- **间距单位**: 以 `8px` 为基础栅格单位。
|
||||
- `xs`: 4px
|
||||
- `sm`: 8px
|
||||
- `md`: 16px
|
||||
- `lg`: 24px
|
||||
- `xl`: 32px
|
||||
- **页面内边距 (Padding)**: 主要内容区域应有 `24px` 的内边距。
|
||||
- **组件间距 (Gap)**: 卡片、表单项之间保持 `16px` 或 `24px` 的间距。
|
||||
|
||||
## 5. 核心组件样式规约
|
||||
|
||||
### 5.1 按钮 (Button)
|
||||
- **主按钮 (Primary)**: `background: #409EFF`, `color: #FFFFFF`。用于页面核心操作。
|
||||
- **次按钮 (Default)**: `border: 1px solid #DCDFE6`, `background: #FFFFFF`。用于非核心或次要操作。
|
||||
- **危险按钮 (Danger)**: `background: #F56C6C`, `color: #FFFFFF`。用于删除等高危操作。
|
||||
- **尺寸**: 高度分为 `大 (40px)`, `中 (32px)`, `小 (24px)` 三档。
|
||||
|
||||
### 5.2 表格 (Table)
|
||||
- **表头**: 背景色 `#FAFAFA`, 字体加粗。
|
||||
- **行**: 偶数行可设置 `#F5F7FA` 的背景色以增强区分度 (斑马纹)。
|
||||
- **操作区**: 表格最后一列通常为操作区,放置`查看`、`编辑`、`删除`等按钮,建议使用文字按钮或小尺寸图标按钮。
|
||||
|
||||
### 5.3 表单 (Form)
|
||||
- **标签 (Label)**: 右对齐,与输入框保持 `8px` 距离。
|
||||
- **输入框 (Input)**: 统一高度,`hover` 和 `focus` 状态有明显视觉反馈 (边框颜色变为 `#409EFF`)。
|
||||
- **必填项**: 在标签前用红色 `*` 标示。
|
||||
|
||||
### 5.4 卡片 (Card)
|
||||
- **样式**: `background: #FFFFFF`, `border-radius: 8px`, `box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1)`。
|
||||
- **内边距**: `20px`。
|
||||
|
||||
## 6. 编码与实现规约
|
||||
- **组件化**: 遵循Vue的组件化思想,将可复用的UI和逻辑封装成组件。
|
||||
- **命名规范**:
|
||||
- 组件文件名: `PascalCase` (e.g., `UserTable.vue`)
|
||||
- props/data/methods: `camelCase` (e.g., `tableData`)
|
||||
- **状态管理**: 使用 `Pinia` 统一管理全局状态,如用户信息、角色权限等。
|
||||
- **API请求**: 封装 `Axios`,统一处理请求头、响应拦截和错误处理。
|
||||
- **TypeScript**: 全程使用TypeScript,为`props`, `emits`, `data` 和 `store` 提供明确的类型定义。
|
||||
- **代码风格**: 遵循 `ESLint + Prettier` 的配置,确保代码风格统一。
|
||||
@@ -1 +0,0 @@
|
||||
[This is a placeholder for the decision support dashboard interface image. In a real implementation, this would be an actual PNG image file.]
|
||||
@@ -1,313 +0,0 @@
|
||||
# 仪表盘页面设计文档
|
||||
|
||||
## 1. 页面概述
|
||||
|
||||
仪表盘页面是用户登录后看到的第一个界面,旨在提供系统关键信息的概览。它主要面向管理员、决策者和主管,展示核心业务指标、任务状态分布、近期活动等,以便用户快速掌握系统整体状况并做出决策。
|
||||
|
||||
## 2. 页面布局
|
||||
|
||||

|
||||
|
||||
### 2.1 布局结构
|
||||
|
||||
页面采用响应式网格布局,确保在不同屏幕尺寸下都有良好的可读性。
|
||||
- **顶部**: 页面标题和一个时间范围选择器,用于筛选仪表盘数据。
|
||||
- **中部**: 关键指标卡片区域,展示核心数据(如总任务数、待处理反馈等)。
|
||||
- **下部**:
|
||||
- **左侧**: 图表区域,通过饼图和柱状图展示任务状态和类型的分布。
|
||||
- **右侧**: 近期活动或任务列表,展示最新的任务分配或状态变更。
|
||||
|
||||
### 2.2 响应式设计
|
||||
|
||||
- **桌面端**: 采用多列网格布局,充分利用屏幕空间。
|
||||
- **平板端**: 网格列数减少,卡片和图表垂直堆叠。
|
||||
- **移动端**: 单列布局,所有模块垂直排列,保证可读性。
|
||||
|
||||
## 3. 组件结构
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="dashboard-page">
|
||||
<!-- 页面头部 -->
|
||||
<el-page-header title="仪表盘" content="系统概览" class="page-header" />
|
||||
|
||||
<!-- 时间范围选择器 -->
|
||||
<div class="dashboard-filters">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
@change="handleDateChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 加载与错误状态 -->
|
||||
<div v-if="loading" class="loading-state">
|
||||
<el-skeleton :rows="5" animated />
|
||||
</div>
|
||||
<div v-else-if="error" class="error-state">
|
||||
<el-alert type="error" :title="error" show-icon :closable="false" />
|
||||
</div>
|
||||
|
||||
<!-- 数据内容 -->
|
||||
<div v-else class="dashboard-content">
|
||||
<!-- 关键指标卡片 -->
|
||||
<el-row :gutter="20" class="summary-cards">
|
||||
<el-col :span="6" :xs="24" :sm="12" :md="6">
|
||||
<StatisticCard icon="list" title="总任务数" :value="stats.totalTasks" color="#409eff" />
|
||||
</el-col>
|
||||
<el-col :span="6" :xs="24" :sm="12" :md="6">
|
||||
<StatisticCard icon="clock" title="待处理任务" :value="stats.pendingTasks" color="#e6a23c" />
|
||||
</el-col>
|
||||
<el-col :span="6" :xs="24" :sm="12" :md="6">
|
||||
<StatisticCard icon="chat-dot-round" title="待审核反馈" :value="stats.pendingFeedback" color="#f56c6c" />
|
||||
</el-col>
|
||||
<el-col :span="6" :xs="24" :sm="12" :md="6">
|
||||
<StatisticCard icon="user" title="活跃用户" :value="stats.activeUsers" color="#67c23a" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 图表区域 -->
|
||||
<el-row :gutter="20" class="charts-section">
|
||||
<el-col :span="12" :xs="24" :sm="24" :md="12">
|
||||
<el-card shadow="never">
|
||||
<template #header>任务状态分布</template>
|
||||
<PieChart :chart-data="taskStatusChartData" />
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12" :xs="24" :sm="24" :md="12">
|
||||
<el-card shadow="never">
|
||||
<template #header>任务类型分布</template>
|
||||
<BarChart :chart-data="taskTypeChartData" />
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 近期任务列表 -->
|
||||
<el-card shadow="never" class="recent-tasks-section">
|
||||
<template #header>近期任务动态</template>
|
||||
<el-table :data="recentTasks" stripe>
|
||||
<el-table-column prop="title" label="任务标题" />
|
||||
<el-table-column prop="assignee" label="执行人" />
|
||||
<el-table-column prop="status" label="状态">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getStatusTagType(row.status)">{{ row.status }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="updatedAt" label="更新时间" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
## 4. 数据结构
|
||||
|
||||
```typescript
|
||||
// 仪表盘统计数据
|
||||
interface DashboardStats {
|
||||
totalTasks: number;
|
||||
pendingTasks: number;
|
||||
pendingFeedback: number;
|
||||
activeUsers: number;
|
||||
}
|
||||
|
||||
// 图表数据项
|
||||
interface ChartDataItem {
|
||||
name: string;
|
||||
value: number;
|
||||
}
|
||||
|
||||
// 近期任务项
|
||||
interface RecentTask {
|
||||
id: number;
|
||||
title: string;
|
||||
assignee: string;
|
||||
status: 'PENDING' | 'IN_PROGRESS' | 'COMPLETED' | 'REVIEWED';
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
// 仪表盘完整数据
|
||||
interface DashboardData {
|
||||
stats: DashboardStats;
|
||||
taskStatusDistribution: ChartDataItem[];
|
||||
taskTypeDistribution: ChartDataItem[];
|
||||
recentTasks: RecentTask[];
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 状态管理
|
||||
|
||||
```typescript
|
||||
// 组件内状态
|
||||
const dateRange = ref<[Date, Date]>();
|
||||
const loading = ref<boolean>(true);
|
||||
const error = ref<string | null>(null);
|
||||
|
||||
// 全局状态 (Pinia Store)
|
||||
const dashboardStore = useDashboardStore();
|
||||
const { stats, taskStatusChartData, taskTypeChartData, recentTasks } = storeToRefs(dashboardStore);
|
||||
```
|
||||
|
||||
## 6. 交互逻辑
|
||||
|
||||
### 6.1 数据加载
|
||||
|
||||
```typescript
|
||||
// 在组件挂载时加载数据
|
||||
onMounted(() => {
|
||||
fetchDashboardData();
|
||||
});
|
||||
|
||||
const fetchDashboardData = async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
|
||||
// 从 store 中调用 action 加载数据
|
||||
await dashboardStore.fetchDashboardData({
|
||||
startDate: dateRange.value?.[0],
|
||||
endDate: dateRange.value?.[1],
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
error.value = '仪表盘数据加载失败,请稍后重试。';
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 当日期范围变化时重新加载数据
|
||||
const handleDateChange = () => {
|
||||
fetchDashboardData();
|
||||
};
|
||||
```
|
||||
|
||||
### 6.2 辅助函数
|
||||
|
||||
```typescript
|
||||
// 根据任务状态返回不同的标签类型
|
||||
const getStatusTagType = (status: RecentTask['status']) => {
|
||||
switch (status) {
|
||||
case 'PENDING': return 'warning';
|
||||
case 'IN_PROGRESS': return 'primary';
|
||||
case 'COMPLETED': return 'success';
|
||||
case 'REVIEWED': return 'info';
|
||||
default: return 'info';
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## 7. API 调用
|
||||
|
||||
### 7.1 仪表盘 API
|
||||
|
||||
```typescript
|
||||
// api/dashboard.ts
|
||||
export const dashboardApi = {
|
||||
getDashboardData: (params: { startDate?: Date; endDate?: Date }) =>
|
||||
apiClient.get<DashboardData>('/dashboard', { params })
|
||||
};
|
||||
|
||||
// stores/dashboard.ts
|
||||
export const useDashboardStore = defineStore('dashboard', {
|
||||
state: (): DashboardData => ({
|
||||
stats: { totalTasks: 0, pendingTasks: 0, pendingFeedback: 0, activeUsers: 0 },
|
||||
taskStatusDistribution: [],
|
||||
taskTypeDistribution: [],
|
||||
recentTasks: [],
|
||||
}),
|
||||
getters: {
|
||||
// 将后端数据转换为 ECharts 需要的格式
|
||||
taskStatusChartData: (state) => ({
|
||||
legend: state.taskStatusDistribution.map(item => item.name),
|
||||
series: [{ data: state.taskStatusDistribution }]
|
||||
}),
|
||||
taskTypeChartData: (state) => ({
|
||||
xAxis: state.taskTypeDistribution.map(item => item.name),
|
||||
series: [{ data: state.taskTypeDistribution.map(item => item.value) }]
|
||||
})
|
||||
},
|
||||
actions: {
|
||||
async fetchDashboardData(params) {
|
||||
try {
|
||||
const { data } = await dashboardApi.getDashboardData(params);
|
||||
// 更新整个 state
|
||||
this.$patch(data);
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('获取仪表盘数据失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 8. 样式设计
|
||||
|
||||
```scss
|
||||
.dashboard-page {
|
||||
padding: 24px;
|
||||
|
||||
.page-header {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.dashboard-filters {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.summary-cards {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.charts-section {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.el-card {
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.loading-state,
|
||||
.error-state {
|
||||
padding: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
// 响应式样式
|
||||
@media screen and (max-width: 768px) {
|
||||
.dashboard-page {
|
||||
padding: 16px;
|
||||
|
||||
.summary-cards .el-col,
|
||||
.charts-section .el-col {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 9. 测试用例
|
||||
|
||||
1. **单元测试**
|
||||
- 测试 `getStatusTagType` 辅助函数的正确性。
|
||||
- 测试 Pinia store中getters的数据转换逻辑。
|
||||
- 测试 `StatisticCard`、`PieChart`、`BarChart` 组件的渲染是否正确。
|
||||
|
||||
2. **集成测试**
|
||||
- 测试页面在加载、成功、失败状态下的显示。
|
||||
- 测试日期选择器筛选功能是否能正确触发数据重新加载。
|
||||
- 模拟 API 调用,验证数据是否正确渲染到页面上。
|
||||
|
||||
## 10. 性能优化
|
||||
|
||||
1. **懒加载图表**: 使用 `v-if` 或动态导入,确保图表库只在需要时加载和渲染。
|
||||
2. **骨架屏**: 在数据加载时使用骨架屏,提升用户体验。
|
||||
3. **数据缓存**: 对不经常变化的数据(如任务类型),可以在 Pinia store 中设置缓存策略,避免重复请求。
|
||||
4. **节流/防抖**: 对日期选择器的 `change` 事件使用节流或防抖,防止用户快速操作导致频繁的 API 请求。
|
||||
@@ -1,261 +0,0 @@
|
||||
# 反馈管理页面设计文档
|
||||
|
||||
## 1. 页面概述
|
||||
|
||||
反馈管理页面是管理员和主管处理用户提交的环境问题报告、建议或其他反馈的核心平台。此页面旨在提供一个高效的工作流程,用于审查、分类、回复和跟踪所有用户反馈,确保问题得到及时响应和解决。
|
||||
|
||||
## 2. 页面布局
|
||||
|
||||

|
||||
|
||||
### 2.1 布局结构
|
||||
|
||||
页面布局与任务管理页面类似,遵循标准的后台管理界面设计:
|
||||
- **顶部**: 筛选区域,允许管理员按反馈状态(待处理、已处理)、反馈类型或提交时间进行过滤。
|
||||
- **中部**: 反馈列表,以表格或卡片列表的形式展示反馈信息。
|
||||
- **底部**: 分页控件。
|
||||
|
||||
### 2.2 响应式设计
|
||||
|
||||
- **桌面端**: 使用多列数据表格,清晰展示反馈的各项信息。
|
||||
- **移动端**: 转换为卡片式列表,每张卡片突出显示反馈标题、提交人和状态,并提供点击查看详情的入口。
|
||||
|
||||
## 3. 组件结构
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="feedback-management-page">
|
||||
<el-page-header title="反馈管理" content="用户反馈列表" />
|
||||
|
||||
<el-card class="page-container">
|
||||
<!-- 筛选区域 -->
|
||||
<div class="filter-container">
|
||||
<el-form :model="filters" inline>
|
||||
<el-form-item label="处理状态">
|
||||
<el-select v-model="filters.status" placeholder="请选择状态" clearable>
|
||||
<el-option label="待处理" value="PENDING" />
|
||||
<el-option label="已处理" value="RESOLVED" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="提交人">
|
||||
<el-input v-model="filters.submitter" placeholder="输入提交人姓名/ID" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleSearch">搜索</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 反馈表格 -->
|
||||
<el-table :data="feedbackList" v-loading="loading" stripe>
|
||||
<el-table-column prop="title" label="反馈标题" min-width="200" />
|
||||
<el-table-column prop="submitterName" label="提交人" width="120" />
|
||||
<el-table-column prop="createdAt" label="提交时间" width="180" sortable />
|
||||
<el-table-column prop="status" label="状态" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.status === 'PENDING' ? 'warning' : 'success'">
|
||||
{{ row.status === 'PENDING' ? '待处理' : '已处理' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="150" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" @click="handleViewDetails(row)">查看详情</el-button>
|
||||
</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"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<!-- 反馈详情对话框 -->
|
||||
<FeedbackDetailDialog
|
||||
v-model="dialogVisible"
|
||||
:feedback-id="selectedFeedbackId"
|
||||
@processed="handleProcessed"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
## 4. 数据结构
|
||||
|
||||
```typescript
|
||||
// 反馈筛选条件
|
||||
interface FeedbackFilters {
|
||||
status?: 'PENDING' | 'RESOLVED';
|
||||
submitter?: string;
|
||||
}
|
||||
|
||||
// 反馈列表项
|
||||
interface FeedbackListItem {
|
||||
id: number;
|
||||
title: string;
|
||||
submitterName: string;
|
||||
createdAt: string;
|
||||
status: 'PENDING' | 'RESOLVED';
|
||||
}
|
||||
|
||||
// 反馈详情 (用于对话框)
|
||||
interface FeedbackDetail extends FeedbackListItem {
|
||||
content: string;
|
||||
images: string[]; // 图片 URL 列表
|
||||
location: string;
|
||||
contact: string;
|
||||
handlerNotes?: string; // 处理备注
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 状态管理
|
||||
|
||||
```typescript
|
||||
// 组件内状态
|
||||
const filters = ref<FeedbackFilters>({});
|
||||
const pagination = ref({ page: 1, pageSize: 10 });
|
||||
const dialogVisible = ref(false);
|
||||
const selectedFeedbackId = ref<number | null>(null);
|
||||
|
||||
// 全局状态 (Pinia Store)
|
||||
const feedbackStore = useFeedbackStore();
|
||||
const { feedbackList, total, loading } = storeToRefs(feedbackStore);
|
||||
```
|
||||
|
||||
## 6. 交互逻辑
|
||||
|
||||
### 6.1 数据获取与筛选
|
||||
|
||||
```typescript
|
||||
const fetchFeedback = () => {
|
||||
feedbackStore.fetchFeedbackList({ ...filters.value, ...pagination.value });
|
||||
};
|
||||
|
||||
onMounted(fetchFeedback);
|
||||
|
||||
const handleSearch = () => {
|
||||
pagination.value.page = 1;
|
||||
fetchFeedback();
|
||||
};
|
||||
|
||||
// 分页逻辑 (handleSizeChange, handleCurrentChange) 与任务管理页面类似
|
||||
```
|
||||
|
||||
### 6.2 查看详情与处理
|
||||
|
||||
```typescript
|
||||
const handleViewDetails = (feedback: FeedbackListItem) => {
|
||||
selectedFeedbackId.value = feedback.id;
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
|
||||
// 当详情对话框中完成处理后被调用
|
||||
const handleProcessed = () => {
|
||||
dialogVisible.value = false;
|
||||
fetchFeedback(); // 刷新列表以更新状态
|
||||
};
|
||||
```
|
||||
|
||||
## 7. API 调用
|
||||
|
||||
### 7.1 反馈管理 API
|
||||
|
||||
```typescript
|
||||
// api/feedback.ts
|
||||
export const feedbackApi = {
|
||||
getFeedbackList: (params) => apiClient.get('/management/feedback', { params }),
|
||||
getFeedbackDetail: (id: number) => apiClient.get(`/management/feedback/${id}`),
|
||||
processFeedback: (id: number, data: { notes: string }) => apiClient.post(`/management/feedback/${id}/process`, data),
|
||||
};
|
||||
```
|
||||
|
||||
### 7.2 Pinia Store
|
||||
|
||||
```typescript
|
||||
// stores/feedback.ts
|
||||
export const useFeedbackStore = defineStore('feedback', {
|
||||
state: () => ({
|
||||
feedbackList: [] as FeedbackListItem[],
|
||||
total: 0,
|
||||
loading: false,
|
||||
currentFeedbackDetail: null as FeedbackDetail | null,
|
||||
}),
|
||||
actions: {
|
||||
async fetchFeedbackList(params) {
|
||||
this.loading = true;
|
||||
try {
|
||||
const { data } = await feedbackApi.getFeedbackList(params);
|
||||
this.feedbackList = data.items;
|
||||
this.total = data.total;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
async fetchFeedbackDetail(id: number) {
|
||||
const { data } = await feedbackApi.getFeedbackDetail(id);
|
||||
this.currentFeedbackDetail = data;
|
||||
},
|
||||
async processFeedback(payload: { id: number; notes: string }) {
|
||||
await feedbackApi.processFeedback(payload.id, { notes: payload.notes });
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 8. 样式设计
|
||||
|
||||
```scss
|
||||
.feedback-management-page {
|
||||
padding: 24px;
|
||||
|
||||
.page-container {
|
||||
margin-top: 24px;
|
||||
padding: 24px;
|
||||
border-radius: 8px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
margin-top: 24px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 9. 关联组件
|
||||
|
||||
### `FeedbackDetailDialog.vue`
|
||||
|
||||
这是一个关键的子组件,用于显示反馈的完整信息,并提供处理功能。
|
||||
- **Props**: `modelValue` (for v-model), `feedbackId`
|
||||
- **功能**:
|
||||
- 接收 `feedbackId`,在对话框打开时调用 store action 获取反馈详情。
|
||||
- 展示反馈的文本内容、联系方式、地理位置和图片(图片可点击放大预览)。
|
||||
- 提供一个文本域供管理员填写处理备注。
|
||||
- 提供一个"标记为已处理"的按钮,点击后调用 store action 提交处理结果。
|
||||
- 操作成功后,emit 一个 `processed` 事件通知父组件刷新列表。
|
||||
|
||||
## 10. 测试用例
|
||||
|
||||
1. **单元测试**:
|
||||
- 测试 Pinia store 的各个 action 是否能正常工作。
|
||||
- 测试 `FeedbackDetailDialog` 组件在接收到 `feedbackId` 后是否能正确加载和显示数据。
|
||||
|
||||
2. **集成测试**:
|
||||
- 测试筛选功能是否能正确过滤反馈列表。
|
||||
- 测试分页是否正常。
|
||||
- 测试点击"查看详情"按钮是否能打开对话框并加载正确的反馈信息。
|
||||
- 测试在详情对话框中提交处理意见后,列表中的反馈状态是否更新。
|
||||
@@ -1,240 +0,0 @@
|
||||
# 文件管理页面设计文档
|
||||
|
||||
## 1. 页面概述
|
||||
|
||||
文件管理页面为系统管理员提供了一个集中管理所有上传文件的界面。这主要包括用户在提交反馈、任务报告等流程中上传的图片或其他附件。管理员能够在此页面上预览、搜索、筛选和删除文件,以维护系统存储的整洁和合规性。
|
||||
|
||||
## 2. 页面布局
|
||||
|
||||

|
||||
|
||||
### 2.1 布局结构
|
||||
|
||||
页面将采用现代化的卡片式画廊(Gallery)布局,以优化图片等视觉文件的预览体验。
|
||||
- **顶部**: 操作和筛选区域。包含一个上传按钮(如果允许管理员直接上传)和按文件名、上传者或关联模块(如"反馈"、"任务")进行筛选的控件。
|
||||
- **中部**: 文件画廊/列表。以卡片网格的形式展示文件,每个卡片包含文件缩略图、文件名、大小、上传时间等信息。
|
||||
- **底部**: 分页控件。
|
||||
|
||||
## 3. 组件结构
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="file-management-page">
|
||||
<el-page-header title="文件管理" content="系统上传资源概览" />
|
||||
|
||||
<el-card class="page-container">
|
||||
<!-- 筛选与上传 -->
|
||||
<div class="table-toolbar">
|
||||
<el-form :model="filters" inline>
|
||||
<el-form-item>
|
||||
<el-input v-model="filters.filename" placeholder="按文件名搜索" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleSearch">搜索</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!-- <el-upload action="/api/files/upload" ... >
|
||||
<el-button type="primary" icon="Upload">上传文件</el-button>
|
||||
</el-upload> -->
|
||||
</div>
|
||||
|
||||
<!-- 文件画廊 -->
|
||||
<el-scrollbar v-loading="loading">
|
||||
<div class="file-gallery">
|
||||
<el-card v-for="file in files" :key="file.id" class="file-card" shadow="hover">
|
||||
<el-image :src="file.url" fit="cover" class="file-thumbnail" :preview-src-list="[file.url]" />
|
||||
<div class="file-info">
|
||||
<span class="file-name" :title="file.originalName">{{ file.originalName }}</span>
|
||||
<span class="file-size">{{ formatFileSize(file.size) }}</span>
|
||||
<el-popconfirm title="确定要删除此文件吗?" @confirm="handleDelete(file)">
|
||||
<template #reference>
|
||||
<el-button link type="danger" icon="Delete" class="delete-btn" />
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
|
||||
<!-- 分页 -->
|
||||
<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>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
## 4. 数据结构
|
||||
|
||||
```typescript
|
||||
// 文件筛选条件
|
||||
interface FileFilters {
|
||||
filename?: string;
|
||||
}
|
||||
|
||||
// 文件数据
|
||||
interface FileItem {
|
||||
id: number;
|
||||
url: string; // 文件的访问 URL
|
||||
originalName: string; // 原始文件名
|
||||
size: number; // 文件大小 (bytes)
|
||||
mimeType: string;
|
||||
uploadedAt: string;
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 状态管理
|
||||
|
||||
```typescript
|
||||
// 组件内状态
|
||||
const filters = ref<FileFilters>({});
|
||||
const pagination = ref({ page: 1, pageSize: 20 });
|
||||
|
||||
// 全局状态 (Pinia Store)
|
||||
const fileStore = useFileStore();
|
||||
const { files, total, loading } = storeToRefs(fileStore);
|
||||
```
|
||||
|
||||
## 6. 交互逻辑
|
||||
|
||||
### 6.1 数据获取
|
||||
|
||||
```typescript
|
||||
const fetchFiles = () => {
|
||||
fileStore.fetchFiles({ ...filters.value, ...pagination.value });
|
||||
};
|
||||
|
||||
onMounted(fetchFiles);
|
||||
|
||||
const handleSearch = () => {
|
||||
pagination.value.page = 1;
|
||||
fetchFiles();
|
||||
};
|
||||
// ... 分页逻辑
|
||||
```
|
||||
|
||||
### 6.2 文件操作
|
||||
|
||||
```typescript
|
||||
const handleDelete = async (file: FileItem) => {
|
||||
await fileStore.deleteFile(file.id);
|
||||
ElMessage.success('文件删除成功');
|
||||
fetchFiles(); // 刷新列表
|
||||
};
|
||||
```
|
||||
|
||||
### 6.3 辅助函数
|
||||
|
||||
```typescript
|
||||
const formatFileSize = (bytes: number): string => {
|
||||
if (bytes === 0) return '0 B';
|
||||
const k = 1024;
|
||||
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||
};
|
||||
```
|
||||
|
||||
## 7. API 调用
|
||||
|
||||
```typescript
|
||||
// api/files.ts
|
||||
export const fileApi = {
|
||||
getFiles: (params) => apiClient.get('/files', { params }),
|
||||
deleteFile: (id: number) => apiClient.delete(`/files/${id}`),
|
||||
};
|
||||
|
||||
// stores/file.ts
|
||||
export const useFileStore = defineStore('file', {
|
||||
state: () => ({
|
||||
files: [] as FileItem[],
|
||||
total: 0,
|
||||
loading: false,
|
||||
}),
|
||||
actions: {
|
||||
async fetchFiles(params) {
|
||||
this.loading = true;
|
||||
try {
|
||||
const { data } = await fileApi.getFiles(params);
|
||||
this.files = data.items;
|
||||
this.total = data.total;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
async deleteFile(id: number) {
|
||||
await fileApi.deleteFile(id);
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 8. 样式设计
|
||||
|
||||
```scss
|
||||
.file-management-page {
|
||||
.page-container {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.file-gallery {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.file-card {
|
||||
.file-thumbnail {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.file-info {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.file-name {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
flex-grow: 1;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.file-size {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.delete-btn {
|
||||
margin-left: 10px;
|
||||
padding: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
margin-top: 24px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 9. 测试用例
|
||||
|
||||
- **集成测试**:
|
||||
- 测试页面是否能正确加载并以卡片形式展示文件列表。
|
||||
- 测试搜索功能是否能正确过滤文件。
|
||||
- 测试分页功能。
|
||||
- 测试点击图片是否能触发大图预览。
|
||||
- 测试删除文件功能,并验证文件是否从列表中移除。
|
||||
@@ -1,550 +0,0 @@
|
||||
# EMS 前端设计文档
|
||||
|
||||
## 1. 技术栈
|
||||
|
||||
- **前端框架**: Vue 3
|
||||
- **构建工具**: Vite
|
||||
- **状态管理**: Pinia
|
||||
- **路由管理**: Vue Router
|
||||
- **UI 组件库**: Element Plus
|
||||
- **HTTP 客户端**: Axios
|
||||
- **CSS 预处理器**: SCSS
|
||||
- **类型检查**: TypeScript
|
||||
- **地图组件**: Leaflet.js
|
||||
- **图表库**: ECharts
|
||||
- **表单验证**: Vee-Validate
|
||||
- **国际化**: Vue I18n
|
||||
- **测试框架**: Vitest
|
||||
|
||||
## 2. 架构设计
|
||||
|
||||
### 2.1 目录结构
|
||||
|
||||
```
|
||||
ems-frontend/
|
||||
├── public/ # 静态资源
|
||||
├── src/
|
||||
│ ├── api/ # API 请求模块
|
||||
│ │ ├── auth.ts # 认证相关 API
|
||||
│ │ ├── dashboard.ts # 仪表盘相关 API
|
||||
│ │ └── ...
|
||||
│ ├── assets/ # 静态资源
|
||||
│ │ ├── styles/ # 全局样式
|
||||
│ │ └── images/ # 图片资源
|
||||
│ ├── components/ # 通用组件
|
||||
│ │ ├── common/ # 基础组件
|
||||
│ │ ├── layout/ # 布局组件
|
||||
│ │ └── business/ # 业务组件
|
||||
│ ├── composables/ # 组合式函数
|
||||
│ ├── config/ # 配置文件
|
||||
│ ├── constants/ # 常量定义
|
||||
│ ├── directives/ # 自定义指令
|
||||
│ ├── hooks/ # 自定义 Hooks
|
||||
│ ├── locales/ # 国际化资源
|
||||
│ ├── router/ # 路由配置
|
||||
│ ├── stores/ # Pinia 状态管理
|
||||
│ ├── types/ # TypeScript 类型定义
|
||||
│ ├── utils/ # 工具函数
|
||||
│ ├── views/ # 页面组件
|
||||
│ │ ├── auth/ # 认证相关页面
|
||||
│ │ ├── dashboard/ # 仪表盘页面
|
||||
│ │ └── ...
|
||||
│ ├── App.vue # 根组件
|
||||
│ ├── main.ts # 入口文件
|
||||
│ └── env.d.ts # 环境变量类型声明
|
||||
├── .env # 环境变量
|
||||
├── .env.development # 开发环境变量
|
||||
├── .env.production # 生产环境变量
|
||||
├── index.html # HTML 模板
|
||||
├── package.json # 依赖配置
|
||||
├── tsconfig.json # TypeScript 配置
|
||||
└── vite.config.ts # Vite 配置
|
||||
```
|
||||
|
||||
### 2.2 核心模块
|
||||
|
||||
1. **认证模块**: 处理用户登录、注册、密码重置等功能
|
||||
2. **仪表盘模块**: 展示系统概览、数据统计和图表
|
||||
3. **地图模块**: 展示地理信息、网格分布和污染热图
|
||||
4. **任务管理模块**: 处理任务分配、查看和审核
|
||||
5. **反馈管理模块**: 处理用户反馈的提交和管理
|
||||
6. **人员管理模块**: 管理系统用户、角色和权限
|
||||
7. **个人中心模块**: 查看和修改个人信息
|
||||
|
||||
## 3. 页面结构
|
||||
|
||||
### 3.1 基础布局
|
||||
|
||||
系统将采用以下几种基础布局:
|
||||
|
||||
1. **主布局**: 包含侧边导航栏、顶部导航栏和内容区域
|
||||
2. **认证布局**: 用于登录、注册等不需要导航的页面
|
||||
3. **空白布局**: 用于全屏展示的页面,如地图全屏模式
|
||||
|
||||
### 3.2 响应式设计
|
||||
|
||||
- 采用移动优先的响应式设计
|
||||
- 断点设置:
|
||||
- 移动端: < 768px
|
||||
- 平板: 768px - 1024px
|
||||
- 桌面: > 1024px
|
||||
- 关键组件的响应式行为:
|
||||
- 侧边栏在移动端变为可折叠抽屉
|
||||
- 表格在移动端优化为卡片式布局
|
||||
- 表单在移动端采用单列布局
|
||||
|
||||
## 4. 路由设计
|
||||
|
||||
### 4.1 路由结构
|
||||
|
||||
```javascript
|
||||
const routes = [
|
||||
// 认证相关路由
|
||||
{
|
||||
path: '/auth',
|
||||
component: AuthLayout,
|
||||
children: [
|
||||
{ path: 'login', component: LoginView },
|
||||
{ path: 'register', component: RegisterView },
|
||||
{ path: 'forgot-password', component: ForgotPasswordView },
|
||||
{ path: 'reset-password', component: ResetPasswordView },
|
||||
],
|
||||
meta: { requiresAuth: false }
|
||||
},
|
||||
|
||||
// 主应用路由
|
||||
{
|
||||
path: '/',
|
||||
component: MainLayout,
|
||||
children: [
|
||||
{ path: '', component: DashboardView, meta: { requiresAuth: true, roles: ['ADMIN', 'DECISION_MAKER'] } },
|
||||
{ path: 'map', component: MapView, meta: { requiresAuth: false } },
|
||||
{ path: 'tasks', component: TasksView, meta: { requiresAuth: true } },
|
||||
{ path: 'feedback', component: FeedbackView, meta: { requiresAuth: true } },
|
||||
{ path: 'personnel', component: PersonnelView, meta: { requiresAuth: true, roles: ['ADMIN'] } },
|
||||
{ path: 'profile', component: ProfileView, meta: { requiresAuth: true } },
|
||||
]
|
||||
},
|
||||
|
||||
// 错误页面路由
|
||||
{ path: '/404', component: NotFoundView },
|
||||
{ path: '/403', component: ForbiddenView },
|
||||
{ path: '/:pathMatch(.*)*', redirect: '/404' }
|
||||
]
|
||||
```
|
||||
|
||||
### 4.2 路由守卫
|
||||
|
||||
```javascript
|
||||
router.beforeEach((to, from, next) => {
|
||||
const authStore = useAuthStore();
|
||||
|
||||
// 检查路由是否需要认证
|
||||
const requiresAuth = to.matched.some(record => record.meta.requiresAuth !== false);
|
||||
|
||||
// 检查用户角色权限
|
||||
const hasRequiredRole = to.matched.every(record => {
|
||||
if (!record.meta.roles) return true;
|
||||
return authStore.user && record.meta.roles.includes(authStore.user.role);
|
||||
});
|
||||
|
||||
if (requiresAuth && !authStore.isAuthenticated) {
|
||||
// 未登录,重定向到登录页
|
||||
next({ path: '/auth/login', query: { redirect: to.fullPath } });
|
||||
} else if (requiresAuth && !hasRequiredRole) {
|
||||
// 无权限访问
|
||||
next({ path: '/403' });
|
||||
} else {
|
||||
// 正常导航
|
||||
next();
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 5. 状态管理
|
||||
|
||||
### 5.1 Pinia Store 设计
|
||||
|
||||
```typescript
|
||||
// 认证状态管理
|
||||
export const useAuthStore = defineStore('auth', {
|
||||
state: () => ({
|
||||
user: null,
|
||||
token: localStorage.getItem('token'),
|
||||
error: null,
|
||||
}),
|
||||
getters: {
|
||||
isAuthenticated: state => !!state.token,
|
||||
userRole: state => state.user?.role || null,
|
||||
},
|
||||
actions: {
|
||||
async login(credentials) { /* 实现登录逻辑 */ },
|
||||
async logout() { /* 实现登出逻辑 */ },
|
||||
async fetchUserProfile() { /* 获取用户信息 */ },
|
||||
}
|
||||
});
|
||||
|
||||
// 任务状态管理
|
||||
export const useTaskStore = defineStore('task', {
|
||||
state: () => ({
|
||||
tasks: [],
|
||||
currentTask: null,
|
||||
loading: false,
|
||||
error: null,
|
||||
}),
|
||||
getters: {
|
||||
tasksByStatus: state => status => state.tasks.filter(task => task.status === status),
|
||||
},
|
||||
actions: {
|
||||
async fetchTasks(filters) { /* 获取任务列表 */ },
|
||||
async fetchTaskById(id) { /* 获取任务详情 */ },
|
||||
async assignTask(taskId, userId) { /* 分配任务 */ },
|
||||
async submitTask(taskId, data) { /* 提交任务 */ },
|
||||
}
|
||||
});
|
||||
|
||||
// 其他模块状态管理...
|
||||
```
|
||||
|
||||
### 5.2 持久化策略
|
||||
|
||||
- 使用 localStorage 存储认证 token
|
||||
- 关键用户设置使用 localStorage 持久化
|
||||
- 敏感数据不进行持久化,每次会话重新获取
|
||||
|
||||
## 6. API 请求封装
|
||||
|
||||
### 6.1 基础请求客户端
|
||||
|
||||
```typescript
|
||||
// api/client.ts
|
||||
import axios from 'axios';
|
||||
import { useAuthStore } from '@/stores/auth';
|
||||
|
||||
const apiClient = axios.create({
|
||||
baseURL: import.meta.env.VITE_API_BASE_URL,
|
||||
timeout: 10000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
});
|
||||
|
||||
// 请求拦截器
|
||||
apiClient.interceptors.request.use(
|
||||
config => {
|
||||
const authStore = useAuthStore();
|
||||
if (authStore.token) {
|
||||
config.headers.Authorization = `Bearer ${authStore.token}`;
|
||||
}
|
||||
return config;
|
||||
},
|
||||
error => Promise.reject(error)
|
||||
);
|
||||
|
||||
// 响应拦截器
|
||||
apiClient.interceptors.response.use(
|
||||
response => response,
|
||||
error => {
|
||||
const authStore = useAuthStore();
|
||||
|
||||
// 处理 401 未授权错误
|
||||
if (error.response && error.response.status === 401) {
|
||||
authStore.logout();
|
||||
router.push('/auth/login');
|
||||
}
|
||||
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export default apiClient;
|
||||
```
|
||||
|
||||
### 6.2 模块化 API 封装
|
||||
|
||||
```typescript
|
||||
// api/auth.ts
|
||||
import apiClient from './client';
|
||||
|
||||
export const authApi = {
|
||||
login: (credentials) => apiClient.post('/auth/login', credentials),
|
||||
register: (userData) => apiClient.post('/auth/signup', userData),
|
||||
requestPasswordReset: (email) => apiClient.post('/auth/request-password-reset', { email }),
|
||||
resetPassword: (data) => apiClient.post('/auth/reset-password', data),
|
||||
};
|
||||
|
||||
// api/tasks.ts
|
||||
import apiClient from './client';
|
||||
|
||||
export const taskApi = {
|
||||
getTasks: (params) => apiClient.get('/management/tasks', { params }),
|
||||
getTaskById: (id) => apiClient.get(`/management/tasks/${id}`),
|
||||
assignTask: (taskId, data) => apiClient.post(`/management/tasks/${taskId}/assign`, data),
|
||||
reviewTask: (taskId, data) => apiClient.post(`/management/tasks/${taskId}/review`, data),
|
||||
};
|
||||
|
||||
// 其他模块 API...
|
||||
```
|
||||
|
||||
## 7. 组件设计
|
||||
|
||||
### 7.1 基础组件
|
||||
|
||||
- **AppButton**: 统一按钮样式和行为
|
||||
- **AppCard**: 卡片容器组件
|
||||
- **AppForm**: 表单容器组件
|
||||
- **AppInput**: 输入框组件
|
||||
- **AppSelect**: 下拉选择组件
|
||||
- **AppTable**: 表格组件
|
||||
- **AppPagination**: 分页组件
|
||||
- **AppModal**: 模态框组件
|
||||
- **AppAlert**: 提示框组件
|
||||
|
||||
### 7.2 业务组件
|
||||
|
||||
- **TaskCard**: 任务卡片组件
|
||||
- **FeedbackForm**: 反馈提交表单
|
||||
- **UserSelector**: 用户选择器
|
||||
- **StatusBadge**: 状态标签组件
|
||||
- **MapGrid**: 地图网格组件
|
||||
- **PollutionTypeIcon**: 污染类型图标
|
||||
- **TaskFilterPanel**: 任务筛选面板
|
||||
- **StatisticCard**: 统计数据卡片
|
||||
|
||||
## 8. 主题设计
|
||||
|
||||
### 8.1 色彩系统
|
||||
|
||||
- **主色**: #1890ff (蓝色)
|
||||
- **成功色**: #52c41a (绿色)
|
||||
- **警告色**: #faad14 (黄色)
|
||||
- **错误色**: #f5222d (红色)
|
||||
- **中性色**:
|
||||
- 标题: #262626
|
||||
- 正文: #595959
|
||||
- 辅助文字: #8c8c8c
|
||||
- 禁用: #bfbfbf
|
||||
- 边框: #d9d9d9
|
||||
- 分割线: #f0f0f0
|
||||
- 背景: #f5f5f5
|
||||
- 表格头部: #fafafa
|
||||
|
||||
### 8.2 字体系统
|
||||
|
||||
- **主字体**: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'PingFang SC', 'Helvetica Neue', Arial, sans-serif
|
||||
- **代码字体**: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace
|
||||
- **字体大小**:
|
||||
- 小号: 12px
|
||||
- 正文: 14px
|
||||
- 标题: 16px, 18px, 20px, 24px
|
||||
|
||||
### 8.3 间距系统
|
||||
|
||||
- **基础单位**: 4px
|
||||
- **间距尺寸**:
|
||||
- xs: 4px
|
||||
- sm: 8px
|
||||
- md: 16px
|
||||
- lg: 24px
|
||||
- xl: 32px
|
||||
- xxl: 48px
|
||||
|
||||
### 8.4 阴影系统
|
||||
|
||||
- **轻微阴影**: 0 2px 8px rgba(0, 0, 0, 0.15)
|
||||
- **中等阴影**: 0 4px 12px rgba(0, 0, 0, 0.15)
|
||||
- **深度阴影**: 0 8px 16px rgba(0, 0, 0, 0.15)
|
||||
|
||||
## 9. 国际化
|
||||
|
||||
支持中文和英文两种语言,使用 Vue I18n 实现国际化。
|
||||
|
||||
```typescript
|
||||
// locales/zh-CN.json
|
||||
{
|
||||
"auth": {
|
||||
"login": "登录",
|
||||
"register": "注册",
|
||||
"forgotPassword": "忘记密码",
|
||||
"email": "邮箱",
|
||||
"password": "密码",
|
||||
"confirmPassword": "确认密码"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "仪表盘",
|
||||
"stats": "统计数据",
|
||||
"tasks": "任务概览",
|
||||
"feedback": "反馈概览"
|
||||
}
|
||||
}
|
||||
|
||||
// locales/en-US.json
|
||||
{
|
||||
"auth": {
|
||||
"login": "Login",
|
||||
"register": "Register",
|
||||
"forgotPassword": "Forgot Password",
|
||||
"email": "Email",
|
||||
"password": "Password",
|
||||
"confirmPassword": "Confirm Password"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Dashboard",
|
||||
"stats": "Statistics",
|
||||
"tasks": "Task Overview",
|
||||
"feedback": "Feedback Overview"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 10. 权限控制
|
||||
|
||||
### 10.1 角色定义
|
||||
|
||||
- **ADMIN**: 系统管理员,拥有所有权限
|
||||
- **SUPERVISOR**: 主管,负责任务分配和审核
|
||||
- **GRID_WORKER**: 网格员,负责执行任务
|
||||
- **DECISION_MAKER**: 决策者,查看数据和报表
|
||||
|
||||
### 10.2 权限指令
|
||||
|
||||
```typescript
|
||||
// 创建自定义指令控制元素的显示/隐藏
|
||||
app.directive('permission', {
|
||||
mounted(el, binding) {
|
||||
const { value } = binding;
|
||||
const authStore = useAuthStore();
|
||||
|
||||
if (value && !authStore.hasPermission(value)) {
|
||||
el.parentNode && el.parentNode.removeChild(el);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 使用示例
|
||||
<button v-permission="'ADMIN'">删除用户</button>
|
||||
<div v-permission="['ADMIN', 'SUPERVISOR']">管理内容</div>
|
||||
```
|
||||
|
||||
## 11. 错误处理
|
||||
|
||||
### 11.1 全局错误处理
|
||||
|
||||
```typescript
|
||||
// 全局错误处理
|
||||
app.config.errorHandler = (err, vm, info) => {
|
||||
console.error('全局错误:', err);
|
||||
|
||||
// 上报错误到监控系统
|
||||
errorReportingService.report(err, {
|
||||
component: vm?.$options?.name,
|
||||
info,
|
||||
user: useAuthStore().user?.id
|
||||
});
|
||||
|
||||
// 显示用户友好的错误提示
|
||||
ElMessage.error('操作失败,请稍后重试');
|
||||
};
|
||||
```
|
||||
|
||||
### 11.2 API 错误处理
|
||||
|
||||
```typescript
|
||||
// 统一处理 API 错误
|
||||
export const handleApiError = (error) => {
|
||||
if (error.response) {
|
||||
// 服务器响应错误
|
||||
const { status, data } = error.response;
|
||||
|
||||
switch (status) {
|
||||
case 400:
|
||||
ElMessage.error(data.message || '请求参数错误');
|
||||
break;
|
||||
case 401:
|
||||
ElMessage.error('会话已过期,请重新登录');
|
||||
break;
|
||||
case 403:
|
||||
ElMessage.error('没有权限执行此操作');
|
||||
break;
|
||||
case 404:
|
||||
ElMessage.error('请求的资源不存在');
|
||||
break;
|
||||
case 500:
|
||||
ElMessage.error('服务器内部错误,请稍后重试');
|
||||
break;
|
||||
default:
|
||||
ElMessage.error('请求失败,请稍后重试');
|
||||
}
|
||||
} else if (error.request) {
|
||||
// 请求发出但没有收到响应
|
||||
ElMessage.error('网络连接失败,请检查网络设置');
|
||||
} else {
|
||||
// 请求配置错误
|
||||
ElMessage.error('请求配置错误');
|
||||
}
|
||||
|
||||
return Promise.reject(error);
|
||||
};
|
||||
```
|
||||
|
||||
## 12. 性能优化
|
||||
|
||||
### 12.1 代码分割
|
||||
|
||||
- 使用动态导入实现路由级别的代码分割
|
||||
- 将大型第三方库单独打包
|
||||
|
||||
### 12.2 资源优化
|
||||
|
||||
- 图片资源使用 WebP 格式并进行压缩
|
||||
- 使用 SVG 图标代替图片图标
|
||||
- 使用字体图标减少 HTTP 请求
|
||||
|
||||
### 12.3 渲染优化
|
||||
|
||||
- 使用虚拟滚动处理长列表
|
||||
- 合理使用 `v-show` 和 `v-if`
|
||||
- 大型表格使用分页加载
|
||||
- 使用 `keep-alive` 缓存组件状态
|
||||
|
||||
## 13. 测试策略
|
||||
|
||||
### 13.1 单元测试
|
||||
|
||||
- 使用 Vitest 进行单元测试
|
||||
- 重点测试工具函数、Hooks 和小型组件
|
||||
- 使用 Vue Test Utils 测试组件
|
||||
|
||||
### 13.2 端到端测试
|
||||
|
||||
- 使用 Cypress 进行端到端测试
|
||||
- 覆盖关键用户流程:
|
||||
- 用户注册和登录
|
||||
- 任务创建和分配
|
||||
- 反馈提交和处理
|
||||
|
||||
## 14. 部署策略
|
||||
|
||||
### 14.1 构建配置
|
||||
|
||||
- 开发环境: `vite build --mode development`
|
||||
- 测试环境: `vite build --mode staging`
|
||||
- 生产环境: `vite build --mode production`
|
||||
|
||||
### 14.2 环境变量
|
||||
|
||||
```
|
||||
# .env.development
|
||||
VITE_API_BASE_URL=http://localhost:8080/api
|
||||
VITE_APP_TITLE=EMS开发环境
|
||||
|
||||
# .env.production
|
||||
VITE_API_BASE_URL=/api
|
||||
VITE_APP_TITLE=环境监测系统
|
||||
```
|
||||
|
||||
### 14.3 CI/CD 流程
|
||||
|
||||
- 使用 GitHub Actions 自动化构建和部署
|
||||
- 提交到 `develop` 分支自动部署到测试环境
|
||||
- 提交到 `main` 分支自动部署到生产环境
|
||||
@@ -1,232 +0,0 @@
|
||||
# 网格管理页面设计文档
|
||||
|
||||
## 1. 页面概述
|
||||
|
||||
网格管理页面允许系统管理员创建、查看、编辑和删除地理网格。每个网格代表一个责任区域,可以关联到特定的主管或网格员。此功能是任务分配和地理数据可视化的基础。
|
||||
|
||||
## 2. 页面布局
|
||||
|
||||

|
||||
|
||||
### 2.1 布局结构
|
||||
|
||||
页面由两部分组成:
|
||||
- **左侧**: 网格列表,以表格形式展示所有已定义的网格及其基本信息(名称、负责人等)。
|
||||
- **右侧**: 交互式地图,用于可视化展示所选网格的地理边界。当创建或编辑网格时,地图将进入绘图模式。
|
||||
|
||||
## 3. 组件结构
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="grid-management-page">
|
||||
<el-page-header title="网格管理" content="定义地理责任区" />
|
||||
|
||||
<el-row :gutter="20" class="page-container">
|
||||
<!-- 左侧网格列表与操作 -->
|
||||
<el-col :span="10" :xs="24">
|
||||
<el-card>
|
||||
<template #header>
|
||||
<div class="table-toolbar">
|
||||
<span>网格列表</span>
|
||||
<el-button type="primary" icon="Plus" @click="handleCreate">新建网格</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<el-table :data="grids" v-loading="loading" @row-click="handleRowClick" highlight-current-row>
|
||||
<el-table-column prop="name" label="网格名称" />
|
||||
<el-table-column prop="manager" label="负责人" />
|
||||
<el-table-column label="操作" width="120">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" @click.stop="handleEdit(row)">编辑</el-button>
|
||||
<el-popconfirm title="确定删除此网格?" @confirm="handleDelete(row)">
|
||||
<template #reference>
|
||||
<el-button link type="danger" @click.stop>删除</el-button>
|
||||
</template>
|
||||
</el-popconfirm>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<!-- 右侧地图显示 -->
|
||||
<el-col :span="14" :xs="24">
|
||||
<el-card>
|
||||
<template #header>地图预览</template>
|
||||
<div ref="mapContainer" class="map-container"></div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 网格编辑/创建对话框 -->
|
||||
<GridFormDialog v-model="dialogVisible" :grid-id="selectedGridId" @success="onFormSuccess" />
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
## 4. 数据结构
|
||||
|
||||
```typescript
|
||||
// 网格列表项
|
||||
interface GridListItem {
|
||||
id: number;
|
||||
name: string;
|
||||
manager?: string;
|
||||
// GeoJSON 字符串
|
||||
geometry: string;
|
||||
}
|
||||
|
||||
// 网格表单数据 (用于对话框)
|
||||
interface GridFormData {
|
||||
id?: number;
|
||||
name: string;
|
||||
managerId?: number;
|
||||
// GeoJSON 字符串
|
||||
geometry: string;
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 状态管理
|
||||
|
||||
```typescript
|
||||
// 地图实例
|
||||
let mapInstance = null;
|
||||
let currentGridLayer = null;
|
||||
|
||||
// 组件内状态
|
||||
const mapContainer = ref<HTMLElement>();
|
||||
const dialogVisible = ref(false);
|
||||
const selectedGridId = ref<number | null>(null);
|
||||
|
||||
// 全局状态 (Pinia Store)
|
||||
const gridStore = useGridStore();
|
||||
const { grids, loading } = storeToRefs(gridStore);
|
||||
```
|
||||
|
||||
## 6. 交互逻辑
|
||||
|
||||
### 6.1 地图与列表交互
|
||||
|
||||
```typescript
|
||||
onMounted(() => {
|
||||
gridStore.fetchGrids();
|
||||
initializeMap();
|
||||
});
|
||||
|
||||
const initializeMap = () => {
|
||||
// ... 地图初始化逻辑
|
||||
};
|
||||
|
||||
// 点击表格行,在地图上高亮显示对应网格
|
||||
const handleRowClick = (row: GridListItem) => {
|
||||
if (currentGridLayer) {
|
||||
mapInstance.removeLayer(currentGridLayer);
|
||||
}
|
||||
if (row.geometry) {
|
||||
const geoJson = JSON.parse(row.geometry);
|
||||
currentGridLayer = L.geoJSON(geoJson).addTo(mapInstance);
|
||||
mapInstance.fitBounds(currentGridLayer.getBounds());
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 6.2 CRUD 操作
|
||||
|
||||
```typescript
|
||||
const handleCreate = () => {
|
||||
selectedGridId.value = null;
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
|
||||
const handleEdit = (grid: GridListItem) => {
|
||||
selectedGridId.value = grid.id;
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
|
||||
const handleDelete = async (grid: GridListItem) => {
|
||||
await gridStore.deleteGrid(grid.id);
|
||||
ElMessage.success('网格删除成功');
|
||||
gridStore.fetchGrids();
|
||||
};
|
||||
|
||||
const onFormSuccess = () => {
|
||||
dialogVisible.value = false;
|
||||
gridStore.fetchGrids();
|
||||
};
|
||||
```
|
||||
|
||||
## 7. API 调用
|
||||
|
||||
```typescript
|
||||
// api/grid.ts
|
||||
export const gridApi = {
|
||||
getGrids: () => apiClient.get('/grid'),
|
||||
getGridById: (id: number) => apiClient.get(`/grid/${id}`),
|
||||
createGrid: (data: GridFormData) => apiClient.post('/grid', data),
|
||||
updateGrid: (id: number, data: GridFormData) => apiClient.put(`/grid/${id}`, data),
|
||||
deleteGrid: (id: number) => apiClient.delete(`/grid/${id}`),
|
||||
};
|
||||
|
||||
// stores/grid.ts
|
||||
export const useGridStore = defineStore('grid', {
|
||||
state: () => ({
|
||||
grids: [] as GridListItem[],
|
||||
loading: false,
|
||||
}),
|
||||
actions: {
|
||||
async fetchGrids() {
|
||||
this.loading = true;
|
||||
try {
|
||||
const { data } = await gridApi.getGrids();
|
||||
this.grids = data;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
// ... create, update, delete actions
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 8. 样式设计
|
||||
|
||||
```scss
|
||||
.grid-management-page {
|
||||
padding: 24px;
|
||||
|
||||
.page-container {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.table-toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.map-container {
|
||||
height: 600px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 9. 关联组件
|
||||
|
||||
### `GridFormDialog.vue`
|
||||
|
||||
这是本页面的核心复杂组件,用于创建和编辑网格。
|
||||
- **Props**: `modelValue`, `gridId`
|
||||
- **内部组件**:
|
||||
- 一个表单,包含网格名称、负责人(下拉选择)等字段。
|
||||
- 一个内嵌的 Leaflet 地图,用于绘制和编辑网格边界。
|
||||
- **功能**:
|
||||
- **地图绘制**: 提供多边形(Polygon)绘制工具。用户可以在地图上绘制闭合区域来定义网格边界。
|
||||
- **数据加载**: 在编辑模式下,根据 `gridId` 加载网格数据,并在表单和内嵌地图上显示。
|
||||
- **数据保存**: 用户完成绘制和表单填写后,点击保存。组件将绘制的多边形转换为 GeoJSON 字符串,连同表单数据一起,调用 store 的 action 进行保存。
|
||||
|
||||
## 10. 测试用例
|
||||
|
||||
- **集成测试**:
|
||||
- 测试能否成功创建一个新网格,包括在地图上绘制边界和填写信息。
|
||||
- 测试点击列表中的网格,地图上是否正确显示其边界。
|
||||
- 测试编辑功能,包括修改网格信息和在地图上重新编辑边界。
|
||||
- 测试删除网格功能。
|
||||
@@ -1,436 +0,0 @@
|
||||
# 登录页面设计文档
|
||||
|
||||
## 1. 页面概述
|
||||
|
||||
登录页面是用户进入系统的主要入口,提供账号密码登录功能,同时支持记住登录状态和找回密码功能。
|
||||
|
||||
## 2. 页面布局
|
||||
|
||||

|
||||
|
||||
### 2.1 布局结构
|
||||
|
||||
登录页面采用居中卡片式布局,包含以下主要区域:
|
||||
- 顶部 Logo 和系统名称区域
|
||||
- 中部登录表单区域
|
||||
- 底部版权信息和帮助链接区域
|
||||
|
||||
### 2.2 响应式设计
|
||||
|
||||
- **桌面端**:居中卡片,宽度 400px,两侧留白
|
||||
- **平板端**:居中卡片,宽度 80%,两侧留白
|
||||
- **移动端**:全宽卡片,上下留白,左右边距 16px
|
||||
|
||||
## 3. 组件结构
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="login-container">
|
||||
<!-- 顶部 Logo 和系统名称 -->
|
||||
<div class="login-header">
|
||||
<img src="@/assets/images/logo.svg" alt="系统 Logo" class="login-logo" />
|
||||
<h1 class="login-title">环境监测系统</h1>
|
||||
</div>
|
||||
|
||||
<!-- 登录表单 -->
|
||||
<el-card class="login-card">
|
||||
<h2 class="login-card-title">用户登录</h2>
|
||||
|
||||
<el-form
|
||||
ref="loginFormRef"
|
||||
:model="loginForm"
|
||||
:rules="loginRules"
|
||||
class="login-form"
|
||||
>
|
||||
<!-- 用户名输入框 -->
|
||||
<el-form-item prop="username">
|
||||
<el-input
|
||||
v-model="loginForm.username"
|
||||
placeholder="用户名"
|
||||
prefix-icon="User"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 密码输入框 -->
|
||||
<el-form-item prop="password">
|
||||
<el-input
|
||||
v-model="loginForm.password"
|
||||
type="password"
|
||||
placeholder="密码"
|
||||
prefix-icon="Lock"
|
||||
show-password
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 记住我和忘记密码 -->
|
||||
<div class="login-options">
|
||||
<el-checkbox v-model="loginForm.remember">记住我</el-checkbox>
|
||||
<el-link type="primary" @click="forgotPassword">忘记密码?</el-link>
|
||||
</div>
|
||||
|
||||
<!-- 登录按钮 -->
|
||||
<el-button
|
||||
type="primary"
|
||||
class="login-button"
|
||||
:loading="loading"
|
||||
@click="handleLogin"
|
||||
>
|
||||
登录
|
||||
</el-button>
|
||||
</el-form>
|
||||
|
||||
<!-- 其他登录方式 -->
|
||||
<div v-if="enableOtherLoginMethods" class="other-login-methods">
|
||||
<div class="divider">
|
||||
<span>其他登录方式</span>
|
||||
</div>
|
||||
<div class="login-icons">
|
||||
<el-button circle icon="Wechat" class="icon-button wechat" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 注册链接 -->
|
||||
<div class="register-link">
|
||||
<span>还没有账号?</span>
|
||||
<el-link type="primary" @click="goToRegister">立即注册</el-link>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 底部版权信息 -->
|
||||
<div class="login-footer">
|
||||
<p>© 2025 环境监测系统 版权所有</p>
|
||||
<p>
|
||||
<el-link type="info" href="#">用户协议</el-link>
|
||||
<el-divider direction="vertical" />
|
||||
<el-link type="info" href="#">隐私政策</el-link>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
## 4. 数据结构
|
||||
|
||||
```typescript
|
||||
interface LoginForm {
|
||||
username: string;
|
||||
password: string;
|
||||
remember: boolean;
|
||||
}
|
||||
|
||||
interface LoginResponse {
|
||||
token: string;
|
||||
user: {
|
||||
id: number;
|
||||
username: string;
|
||||
role: string;
|
||||
permissions: string[];
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 状态管理
|
||||
|
||||
```typescript
|
||||
// 组件内状态
|
||||
const loginForm = ref<LoginForm>({
|
||||
username: '',
|
||||
password: '',
|
||||
remember: false
|
||||
});
|
||||
|
||||
const loading = ref<boolean>(false);
|
||||
const loginFormRef = ref<FormInstance>();
|
||||
const enableOtherLoginMethods = ref<boolean>(true);
|
||||
|
||||
// 全局状态 (Pinia Store)
|
||||
const authStore = useAuthStore();
|
||||
```
|
||||
|
||||
## 6. 交互逻辑
|
||||
|
||||
### 6.1 表单验证规则
|
||||
|
||||
```typescript
|
||||
const loginRules = {
|
||||
username: [
|
||||
{ required: true, message: '请输入用户名', trigger: 'blur' },
|
||||
{ min: 3, max: 20, message: '用户名长度应为 3-20 个字符', trigger: 'blur' }
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: '请输入密码', trigger: 'blur' },
|
||||
{ min: 6, max: 20, message: '密码长度应为 6-20 个字符', trigger: 'blur' }
|
||||
]
|
||||
};
|
||||
```
|
||||
|
||||
### 6.2 登录流程
|
||||
|
||||
```typescript
|
||||
const handleLogin = async () => {
|
||||
if (!loginFormRef.value) return;
|
||||
|
||||
await loginFormRef.value.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
|
||||
// 调用登录 API
|
||||
await authStore.login({
|
||||
username: loginForm.value.username,
|
||||
password: loginForm.value.password
|
||||
});
|
||||
|
||||
// 如果选择记住我,设置本地存储
|
||||
if (loginForm.value.remember) {
|
||||
localStorage.setItem('remember_username', loginForm.value.username);
|
||||
} else {
|
||||
localStorage.removeItem('remember_username');
|
||||
}
|
||||
|
||||
// 登录成功提示
|
||||
ElMessage.success('登录成功');
|
||||
|
||||
// 获取重定向地址或跳转到首页
|
||||
const redirect = route.query.redirect as string || '/';
|
||||
router.push(redirect);
|
||||
} catch (error) {
|
||||
// 错误处理
|
||||
ElMessage.error(error.response?.data?.message || '登录失败,请检查用户名和密码');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
### 6.3 其他交互功能
|
||||
|
||||
```typescript
|
||||
// 跳转到注册页面
|
||||
const goToRegister = () => {
|
||||
router.push('/auth/register');
|
||||
};
|
||||
|
||||
// 跳转到忘记密码页面
|
||||
const forgotPassword = () => {
|
||||
router.push('/auth/forgot-password');
|
||||
};
|
||||
|
||||
// 生命周期钩子,检查是否有记住的用户名
|
||||
onMounted(() => {
|
||||
const rememberedUsername = localStorage.getItem('remember_username');
|
||||
if (rememberedUsername) {
|
||||
loginForm.value.username = rememberedUsername;
|
||||
loginForm.value.remember = true;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 7. API 调用
|
||||
|
||||
### 7.1 登录 API
|
||||
|
||||
```typescript
|
||||
// api/auth.ts
|
||||
export const authApi = {
|
||||
login: (credentials: { username: string; password: string }) =>
|
||||
apiClient.post<LoginResponse>('/auth/login', credentials)
|
||||
};
|
||||
|
||||
// stores/auth.ts
|
||||
export const useAuthStore = defineStore('auth', {
|
||||
// ... 其他状态和 getters
|
||||
|
||||
actions: {
|
||||
async login(credentials) {
|
||||
try {
|
||||
const { data } = await authApi.login(credentials);
|
||||
this.token = data.token;
|
||||
this.user = data.user;
|
||||
|
||||
// 存储 token 到本地存储
|
||||
localStorage.setItem('token', data.token);
|
||||
|
||||
return data;
|
||||
} catch (error) {
|
||||
this.error = error.response?.data?.message || '登录失败';
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 8. 样式设计
|
||||
|
||||
```scss
|
||||
.login-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
background-color: #f5f7fa;
|
||||
padding: 20px;
|
||||
|
||||
.login-header {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
|
||||
.login-logo {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.login-title {
|
||||
font-size: 24px;
|
||||
color: #303133;
|
||||
margin-top: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-card {
|
||||
width: 400px;
|
||||
max-width: 100%;
|
||||
|
||||
.login-card-title {
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.login-options {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.login-button {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.other-login-methods {
|
||||
margin-top: 24px;
|
||||
|
||||
.divider {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 16px 0;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
content: '';
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background-color: #dcdfe6;
|
||||
}
|
||||
|
||||
span {
|
||||
padding: 0 16px;
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-icons {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 20px;
|
||||
margin-top: 16px;
|
||||
|
||||
.icon-button {
|
||||
font-size: 20px;
|
||||
|
||||
&.wechat {
|
||||
color: #07c160;
|
||||
background-color: #f0f9eb;
|
||||
border-color: #e1f3d8;
|
||||
|
||||
&:hover {
|
||||
background-color: #e1f3d8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.register-link {
|
||||
text-align: center;
|
||||
margin-top: 24px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-footer {
|
||||
margin-top: 40px;
|
||||
text-align: center;
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
|
||||
p {
|
||||
margin: 8px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 响应式样式
|
||||
@media screen and (max-width: 768px) {
|
||||
.login-container {
|
||||
padding: 16px;
|
||||
|
||||
.login-card {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 9. 安全考虑
|
||||
|
||||
1. **密码安全**
|
||||
- 密码输入框使用 `type="password"` 和 `show-password` 属性
|
||||
- 密码不在前端存储,只在登录时传输
|
||||
- 密码传输使用 HTTPS 加密
|
||||
|
||||
2. **Token 安全**
|
||||
- Token 存储在 localStorage 中,有 XSS 风险,可考虑使用 HttpOnly Cookie
|
||||
- Token 过期处理在响应拦截器中统一处理
|
||||
|
||||
3. **表单安全**
|
||||
- 实施前端输入验证,防止基本的注入攻击
|
||||
- 防止表单重复提交(登录按钮 loading 状态)
|
||||
|
||||
## 10. 测试用例
|
||||
|
||||
1. **单元测试**
|
||||
- 测试表单验证逻辑
|
||||
- 测试记住用户名功能
|
||||
|
||||
2. **集成测试**
|
||||
- 测试登录成功流程
|
||||
- 测试登录失败处理
|
||||
- 测试重定向功能
|
||||
|
||||
3. **端到端测试**
|
||||
- 测试完整登录流程
|
||||
- 测试页面响应式布局
|
||||
|
||||
## 11. 性能优化
|
||||
|
||||
1. **延迟加载**
|
||||
- 第三方图标库按需引入
|
||||
- 忘记密码页面使用动态导入
|
||||
|
||||
2. **缓存策略**
|
||||
- 记住用户名使用 localStorage
|
||||
- 静态资源(logo 等)设置适当的缓存策略
|
||||
@@ -1,296 +0,0 @@
|
||||
# 地图页面设计文档
|
||||
|
||||
## 1. 页面概述
|
||||
|
||||
地图页面是 EMS 系统的核心可视化界面,提供基于地理位置的直观信息展示。它主要用于显示城市的环境网格划分、实时污染数据(如热力图)、网格员位置以及特定任务的地理标记。此页面帮助主管和决策者监控区域状态,并为网格员提供清晰的工作区域指引。
|
||||
|
||||
## 2. 页面布局
|
||||
|
||||

|
||||
|
||||
### 2.1 布局结构
|
||||
|
||||
页面采用全屏地图为主体的布局,辅以侧边栏和浮动控件。
|
||||
- **主区域**: 全屏交互式地图,作为所有地理信息的载体。
|
||||
- **左侧边栏**: 用于控制地图上显示的图层,如网格边界、热力图、网格员位置等。同时,也可能包含一个可搜索的兴趣点列表。
|
||||
- **地图控件**: 地图右上角或左上角放置缩放、定位、全屏等标准地图控件。
|
||||
- **信息弹窗 (Popup)**: 点击地图上的特定元素(如网格、标记点)时,会弹出信息窗口,显示该元素的详细信息。
|
||||
|
||||
### 2.2 响应式设计
|
||||
|
||||
- **桌面端**: 显示完整的左侧边栏和地图。
|
||||
- **平板端/移动端**: 左侧边栏默认收起,可通过按钮展开为抽屉或浮动面板,以最大化地图可视区域。
|
||||
|
||||
## 3. 组件结构
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="map-page">
|
||||
<!-- 地图容器 -->
|
||||
<div ref="mapContainer" class="map-container"></div>
|
||||
|
||||
<!-- 左侧图层控制面板 -->
|
||||
<el-card class="layer-control-panel">
|
||||
<template #header>
|
||||
<div class="panel-header">
|
||||
<span>图层控制</span>
|
||||
<el-button link type="primary" @click="togglePanel" class="panel-toggle-btn">
|
||||
<el-icon><ArrowLeft v-if="isPanelVisible" /><ArrowRight v-else /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<div v-show="isPanelVisible">
|
||||
<el-checkbox-group v-model="visibleLayers">
|
||||
<el-checkbox label="grids">显示网格</el-checkbox>
|
||||
<el-checkbox label="heatmap">显示污染热力图</el-checkbox>
|
||||
<el-checkbox label="workers">显示网格员位置</el-checkbox>
|
||||
<el-checkbox label="tasks">显示任务标记</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
<el-divider />
|
||||
<h4>搜索网格</h4>
|
||||
<el-input v-model="gridSearch" placeholder="输入网格名称/编号搜索" @keyup.enter="searchGrid" />
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 地图加载状态 -->
|
||||
<div v-if="mapLoading" class="map-loading-overlay">
|
||||
<el-icon class="is-loading" size="30"><Loading /></el-icon>
|
||||
<span>地图加载中...</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
## 4. 数据结构
|
||||
|
||||
```typescript
|
||||
// 网格数据结构
|
||||
interface GridData {
|
||||
id: number;
|
||||
name: string;
|
||||
// GeoJSON 格式的多边形坐标
|
||||
geometry: {
|
||||
type: 'Polygon';
|
||||
coordinates: number[][][];
|
||||
};
|
||||
manager: string; // 网格负责人
|
||||
}
|
||||
|
||||
// 热力图数据点
|
||||
interface HeatmapPoint {
|
||||
lat: number;
|
||||
lng: number;
|
||||
value: number; // 污染指数
|
||||
}
|
||||
|
||||
// 网格员位置
|
||||
interface WorkerPosition {
|
||||
id: number;
|
||||
name: string;
|
||||
lat: number;
|
||||
lng: number;
|
||||
lastUpdated: string;
|
||||
}
|
||||
|
||||
// 任务标记
|
||||
interface TaskMarker {
|
||||
id: number;
|
||||
title: string;
|
||||
lat: number;
|
||||
lng: number;
|
||||
status: string;
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 状态管理
|
||||
|
||||
```typescript
|
||||
// 地图服务实例
|
||||
let mapInstance = null;
|
||||
let gridLayerGroup = null;
|
||||
let heatmapLayer = null;
|
||||
let workerMarkersGroup = null;
|
||||
|
||||
// 组件内状态
|
||||
const mapContainer = ref<HTMLElement | null>(null);
|
||||
const mapLoading = ref<boolean>(true);
|
||||
const isPanelVisible = ref<boolean>(true);
|
||||
const visibleLayers = ref<string[]>(['grids']); // 默认显示的图层
|
||||
const gridSearch = ref<string>('');
|
||||
|
||||
// 全局状态 (Pinia Store)
|
||||
const mapStore = useMapStore();
|
||||
const { grids, heatmapData, workers } = storeToRefs(mapStore);
|
||||
|
||||
// 监听可见图层变化,动态更新地图
|
||||
watch(visibleLayers, (newLayers, oldLayers) => {
|
||||
// ... 调用地图服务方法显示/隐藏图层
|
||||
});
|
||||
```
|
||||
|
||||
## 6. 交互逻辑
|
||||
|
||||
### 6.1 地图初始化
|
||||
|
||||
```typescript
|
||||
onMounted(() => {
|
||||
initializeMap();
|
||||
mapStore.fetchInitialMapData();
|
||||
});
|
||||
|
||||
const initializeMap = () => {
|
||||
if (mapContainer.value) {
|
||||
mapInstance = L.map(mapContainer.value).setView([39.9042, 116.4074], 10); // 默认北京
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
attribution: '© OpenStreetMap contributors'
|
||||
}).addTo(mapInstance);
|
||||
mapLoading.value = false;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 6.2 图层控制
|
||||
|
||||
```typescript
|
||||
const updateLayers = () => {
|
||||
// 网格图层
|
||||
if (visibleLayers.value.includes('grids') && !mapInstance.hasLayer(gridLayerGroup)) {
|
||||
gridLayerGroup.addTo(mapInstance);
|
||||
} else if (!visibleLayers.value.includes('grids') && mapInstance.hasLayer(gridLayerGroup)) {
|
||||
gridLayerGroup.removeFrom(mapInstance);
|
||||
}
|
||||
// 其他图层同理...
|
||||
};
|
||||
|
||||
// 监听 Pinia store 中数据的变化,并更新地图
|
||||
watch(grids, (newGrids) => {
|
||||
if (gridLayerGroup) {
|
||||
gridLayerGroup.clearLayers();
|
||||
// 添加新的网格到图层
|
||||
newGrids.forEach(grid => {
|
||||
const polygon = L.geoJSON(grid.geometry);
|
||||
polygon.bindPopup(`<b>${grid.name}</b><br>负责人: ${grid.manager}`);
|
||||
gridLayerGroup.addLayer(polygon);
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### 6.3 面板交互
|
||||
|
||||
```typescript
|
||||
const togglePanel = () => {
|
||||
isPanelVisible.value = !isPanelVisible.value;
|
||||
};
|
||||
|
||||
const searchGrid = () => {
|
||||
const targetGrid = grids.value.find(g => g.name === gridSearch.value);
|
||||
if (targetGrid) {
|
||||
// 飞到目标网格位置
|
||||
const bounds = L.geoJSON(targetGrid.geometry).getBounds();
|
||||
mapInstance.flyToBounds(bounds);
|
||||
} else {
|
||||
ElMessage.info('未找到该网格');
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## 7. API 调用
|
||||
|
||||
```typescript
|
||||
// api/map.ts
|
||||
export const mapApi = {
|
||||
getGrids: () => apiClient.get<GridData[]>('/map/grids'),
|
||||
getHeatmapData: () => apiClient.get<HeatmapPoint[]>('/map/heatmap'),
|
||||
getWorkerPositions: () => apiClient.get<WorkerPosition[]>('/map/workers'),
|
||||
};
|
||||
|
||||
// stores/map.ts
|
||||
export const useMapStore = defineStore('map', {
|
||||
state: () => ({
|
||||
grids: [] as GridData[],
|
||||
heatmapData: [] as HeatmapPoint[],
|
||||
workers: [] as WorkerPosition[],
|
||||
}),
|
||||
actions: {
|
||||
async fetchInitialMapData() {
|
||||
// 并发请求所有地图数据
|
||||
const [gridsRes, heatmapRes, workersRes] = await Promise.all([
|
||||
mapApi.getGrids(),
|
||||
mapApi.getHeatmapData(),
|
||||
mapApi.getWorkerPositions(),
|
||||
]);
|
||||
this.grids = gridsRes.data;
|
||||
this.heatmapData = heatmapRes.data;
|
||||
this.workers = workersRes.data;
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 8. 样式设计
|
||||
|
||||
```scss
|
||||
.map-page {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: calc(100vh - 50px); /* 减去顶部导航栏高度 */
|
||||
|
||||
.map-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.layer-control-panel {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
z-index: 2;
|
||||
width: 250px;
|
||||
background: white;
|
||||
transition: transform 0.3s ease;
|
||||
|
||||
.panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.map-loading-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 3;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 9. 测试用例
|
||||
|
||||
1. **单元测试**:
|
||||
- 测试 Pinia store 的 action 是否能正确获取和存储地图数据。
|
||||
- 测试地图交互函数,如 `searchGrid` 的逻辑。
|
||||
|
||||
2. **集成测试**:
|
||||
- 验证地图是否能成功初始化并显示底图。
|
||||
- 验证图层控制复选框是否能正确显示/隐藏对应的地理要素。
|
||||
- 验证点击网格是否能弹出正确的信息窗口。
|
||||
- 验证搜索功能是否能正确地将地图视图定位到指定网格。
|
||||
|
||||
## 10. 性能优化
|
||||
|
||||
1. **大数据渲染**:
|
||||
- 对于大量的标记点(如网格员、任务),使用 `L.markerClusterGroup` 插件进行聚合,提高性能。
|
||||
- 对于复杂的网格边界(Polygon),在低缩放级别下使用简化的几何图形(可通过后端服务实现)。
|
||||
2. **懒加载**: 地图库(Leaflet)和相关插件(热力图、聚合)应按需异步加载。
|
||||
3. **数据更新**: 网格员位置等实时数据应使用 WebSocket 或定时轮询(配合 `requestAnimationFrame`)进行高效更新,而不是频繁重绘整个图层。
|
||||
@@ -1,296 +0,0 @@
|
||||
# 人员管理页面设计文档
|
||||
|
||||
## 1. 页面概述
|
||||
|
||||
人员管理页面是提供给系统管理员(ADMIN)用于管理所有用户账户的界面。其核心功能包括展示用户列表、添加新用户、编辑现有用户信息、更改用户角色与状态,以及搜索和筛选用户。
|
||||
|
||||
## 2. 页面布局
|
||||
|
||||

|
||||
|
||||
### 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. 测试用例
|
||||
|
||||
- **集成测试**:
|
||||
- 测试能否成功添加一个新用户。
|
||||
- 测试能否成功编辑一个现有用户的信息(包括修改密码和不修改密码两种情况)。
|
||||
- 测试能否成功删除一个用户。
|
||||
- 测试启用/禁用开关是否能正确更新用户状态。
|
||||
- 测试搜索和筛选功能是否能正确过滤用户列表。
|
||||
@@ -1,258 +0,0 @@
|
||||
# 个人中心页面设计文档
|
||||
|
||||
## 1. 页面概述
|
||||
|
||||
个人中心页面允许当前登录的用户查看和修改自己的个人信息,以及更改密码。此页面旨在提供一个简单、安全的界面来管理个人账户资料。
|
||||
|
||||
## 2. 页面布局
|
||||
|
||||

|
||||
|
||||
### 2.1 布局结构
|
||||
|
||||
页面通常采用多标签页(Tabs)布局,将不同功能的表单分开,以保持界面整洁。
|
||||
- **左侧**: 用户头像和基本信息展示。
|
||||
- **右侧**: 包含两个标签页:
|
||||
- **基本资料**: 用于修改用户名、姓名、邮箱等信息。
|
||||
- **修改密码**: 用于更改当前用户的登录密码。
|
||||
|
||||
## 3. 组件结构
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="profile-page">
|
||||
<el-page-header title="个人中心" content="管理您的账户信息" />
|
||||
|
||||
<el-row :gutter="20" class="page-container">
|
||||
<el-col :span="8" :xs="24">
|
||||
<el-card class="user-card">
|
||||
<div class="user-avatar">
|
||||
<el-avatar :size="100" :src="user.avatarUrl">{{ user.name?.[0] }}</el-avatar>
|
||||
</div>
|
||||
<div class="user-info">
|
||||
<h2>{{ user.name }}</h2>
|
||||
<p>{{ user.role }}</p>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="16" :xs="24">
|
||||
<el-card>
|
||||
<el-tabs v-model="activeTab">
|
||||
<!-- 基本资料标签页 -->
|
||||
<el-tab-pane label="基本资料" name="profile">
|
||||
<el-form :model="profileForm" :rules="profileRules" ref="profileFormRef" label-width="80px">
|
||||
<el-form-item label="用户名">
|
||||
<el-input v-model="profileForm.username" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名" prop="name">
|
||||
<el-input v-model="profileForm.name" />
|
||||
</el-form-item>
|
||||
<el-form-item label="邮箱" prop="email">
|
||||
<el-input v-model="profileForm.email" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="updateProfile" :loading="profileLoading">
|
||||
保存更改
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 修改密码标签页 -->
|
||||
<el-tab-pane label="修改密码" name="password">
|
||||
<el-form :model="passwordForm" :rules="passwordRules" ref="passwordFormRef" label-width="80px">
|
||||
<el-form-item label="旧密码" prop="oldPassword">
|
||||
<el-input type="password" v-model="passwordForm.oldPassword" show-password />
|
||||
</el-form-item>
|
||||
<el-form-item label="新密码" prop="newPassword">
|
||||
<el-input type="password" v-model="passwordForm.newPassword" show-password />
|
||||
</el-form-item>
|
||||
<el-form-item label="确认密码" prop="confirmPassword">
|
||||
<el-input type="password" v-model="passwordForm.confirmPassword" show-password />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="changePassword" :loading="passwordLoading">
|
||||
确认修改
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
## 4. 数据结构
|
||||
|
||||
```typescript
|
||||
// 用户信息 (来自 Store)
|
||||
interface UserProfile {
|
||||
id: number;
|
||||
username: string;
|
||||
name: string;
|
||||
email: string;
|
||||
role: string;
|
||||
avatarUrl?: string;
|
||||
}
|
||||
|
||||
// 修改密码表单
|
||||
interface PasswordForm {
|
||||
oldPassword: string;
|
||||
newPassword: string;
|
||||
confirmPassword: string;
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 状态管理
|
||||
|
||||
```typescript
|
||||
// 组件内状态
|
||||
const activeTab = ref('profile');
|
||||
const profileForm = ref<Partial<UserProfile>>({});
|
||||
const passwordForm = ref<PasswordForm>({ oldPassword: '', newPassword: '', confirmPassword: '' });
|
||||
const profileLoading = ref(false);
|
||||
const passwordLoading = ref(false);
|
||||
const profileFormRef = ref<FormInstance>();
|
||||
const passwordFormRef = ref<FormInstance>();
|
||||
|
||||
// 全局状态 (Pinia Store)
|
||||
const authStore = useAuthStore();
|
||||
const { user } = storeToRefs(authStore);
|
||||
|
||||
// 当 user 数据从 store 加载后,填充表单
|
||||
watch(user, (currentUser) => {
|
||||
if (currentUser) {
|
||||
profileForm.value = { ...currentUser };
|
||||
}
|
||||
}, { immediate: true });
|
||||
```
|
||||
|
||||
## 6. 交互逻辑
|
||||
|
||||
### 6.1 更新个人资料
|
||||
|
||||
```typescript
|
||||
const updateProfile = async () => {
|
||||
await profileFormRef.value?.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
profileLoading.value = true;
|
||||
try {
|
||||
await authStore.updateProfile({
|
||||
name: profileForm.value.name,
|
||||
email: profileForm.value.email,
|
||||
});
|
||||
ElMessage.success('个人资料更新成功');
|
||||
} finally {
|
||||
profileLoading.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
### 6.2 修改密码
|
||||
|
||||
```typescript
|
||||
const changePassword = async () => {
|
||||
await passwordFormRef.value?.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
passwordLoading.value = true;
|
||||
try {
|
||||
await authStore.changePassword(passwordForm.value);
|
||||
ElMessage.success('密码修改成功,请重新登录');
|
||||
// 密码修改成功后通常需要用户重新登录
|
||||
authStore.logout();
|
||||
router.push('/auth/login');
|
||||
} catch (error) {
|
||||
ElMessage.error(error.response?.data?.message || '密码修改失败');
|
||||
} finally {
|
||||
passwordLoading.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 自定义密码验证规则
|
||||
const validateConfirmPassword = (rule: any, value: any, callback: any) => {
|
||||
if (value !== passwordForm.value.newPassword) {
|
||||
callback(new Error('两次输入的新密码不一致'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
const passwordRules = {
|
||||
// ... oldPassword 和 newPassword 的必填和长度规则
|
||||
confirmPassword: [
|
||||
{ required: true, message: '请再次输入新密码', trigger: 'blur' },
|
||||
{ validator: validateConfirmPassword, trigger: 'blur' }
|
||||
]
|
||||
};
|
||||
```
|
||||
|
||||
## 7. API 调用
|
||||
|
||||
```typescript
|
||||
// api/me.ts
|
||||
export const meApi = {
|
||||
getProfile: () => apiClient.get<UserProfile>('/me'),
|
||||
updateProfile: (data: Partial<UserProfile>) => apiClient.put('/me', data),
|
||||
changePassword: (data: PasswordForm) => apiClient.post('/me/change-password', data),
|
||||
};
|
||||
|
||||
// stores/auth.ts
|
||||
export const useAuthStore = defineStore('auth', {
|
||||
// ... state, getters
|
||||
actions: {
|
||||
async fetchUserProfile() {
|
||||
// (在App启动或登录后调用)
|
||||
const { data } = await meApi.getProfile();
|
||||
this.user = data;
|
||||
},
|
||||
async updateProfile(data) {
|
||||
const { data: updatedUser } = await meApi.updateProfile(data);
|
||||
this.user = { ...this.user, ...updatedUser };
|
||||
},
|
||||
async changePassword(data) {
|
||||
await meApi.changePassword(data);
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 8. 样式设计
|
||||
|
||||
```scss
|
||||
.profile-page {
|
||||
padding: 24px;
|
||||
|
||||
.page-container {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.user-card {
|
||||
text-align: center;
|
||||
.user-avatar {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.user-info h2 {
|
||||
font-size: 20px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.user-info p {
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 9. 测试用例
|
||||
|
||||
1. **集成测试**:
|
||||
- 测试页面是否能正确显示当前用户的个人信息。
|
||||
- 测试更新个人资料功能是否成功,并验证 store 中的用户信息是否同步更新。
|
||||
- 测试修改密码的成功流程,验证是否提示成功并跳转到登录页。
|
||||
- 测试修改密码的失败流程(如旧密码错误),验证是否显示正确的错误提示。
|
||||
- 测试所有表单验证规则是否生效(如邮箱格式、密码长度、两次密码一致性等)。
|
||||
@@ -1,315 +0,0 @@
|
||||
# 任务管理页面设计文档
|
||||
|
||||
## 1. 页面概述
|
||||
|
||||
任务管理页面是系统的核心功能模块之一,允许主管和管理员对任务进行全面的管理。用户可以在此页面上查看所有任务,并使用筛选、排序和搜索功能快速定位任务。此外,页面还支持任务的分配、审核以及查看任务详情等操作。
|
||||
|
||||
## 2. 页面布局
|
||||
|
||||

|
||||
|
||||
### 2.1 布局结构
|
||||
|
||||
页面采用经典的后台管理布局:
|
||||
- **顶部**: 包含页面标题和操作按钮(如"新建任务")。
|
||||
- **中部**: 筛选和搜索区域,提供多种条件来过滤任务列表。
|
||||
- **下部**: 任务数据表格,以列表形式展示任务,并包含操作列。
|
||||
- **底部**: 分页组件,用于浏览大量任务数据。
|
||||
|
||||
### 2.2 响应式设计
|
||||
|
||||
- **桌面端**: 多列表格,所有筛选条件水平排列。
|
||||
- **平板端**: 表格列数减少,部分次要信息可能隐藏,筛选条件折叠或垂直排列。
|
||||
- **移动端**: 表格转为卡片列表视图,每个卡片显示一个任务的核心信息,筛选功能通过抽屉或模态框提供。
|
||||
|
||||
## 3. 组件结构
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="task-management-page">
|
||||
<!-- 页面头部 -->
|
||||
<el-page-header title="任务管理" content="任务列表与分配" />
|
||||
|
||||
<el-card class="page-container">
|
||||
<!-- 筛选与搜索区域 -->
|
||||
<div class="filter-container">
|
||||
<el-form :model="filters" inline>
|
||||
<el-form-item label="任务状态">
|
||||
<el-select v-model="filters.status" placeholder="请选择状态" clearable>
|
||||
<el-option label="待处理" value="PENDING" />
|
||||
<el-option label="进行中" value="IN_PROGRESS" />
|
||||
<el-option label="已完成" value="COMPLETED" />
|
||||
<el-option label="已审核" value="REVIEWED" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="执行人">
|
||||
<el-input v-model="filters.assignee" placeholder="请输入执行人" clearable />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleSearch">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮区域 -->
|
||||
<div class="action-buttons">
|
||||
<el-button type="primary" icon="Plus" @click="handleCreateTask" v-permission="'SUPERVISOR'">
|
||||
新建任务
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 任务表格 -->
|
||||
<el-table :data="tasks" v-loading="loading" stripe>
|
||||
<el-table-column type="index" width="50" />
|
||||
<el-table-column prop="title" label="任务标题" min-width="150" />
|
||||
<el-table-column prop="grid" label="所属网格" />
|
||||
<el-table-column prop="assignee" label="执行人" />
|
||||
<el-table-column prop="status" label="状态">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getStatusTagType(row.status)">{{ formatStatus(row.status) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createdAt" label="创建时间" sortable />
|
||||
<el-table-column label="操作" width="200" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" @click="handleView(row)">查看</el-button>
|
||||
<el-button link type="primary" @click="handleAssign(row)" v-if="canAssign(row)">分配</el-button>
|
||||
<el-button link type="primary" @click="handleReview(row)" v-if="canReview(row)">审核</el-button>
|
||||
</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"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<!-- 任务分配/审核/新建的对话框 -->
|
||||
<TaskFormDialog v-model="dialogVisible" :task-id="selectedTaskId" :mode="dialogMode" @success="handleSuccess" />
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
## 4. 数据结构
|
||||
|
||||
```typescript
|
||||
// 任务筛选条件
|
||||
interface TaskFilters {
|
||||
status?: 'PENDING' | 'IN_PROGRESS' | 'COMPLETED' | 'REVIEWED';
|
||||
assignee?: string;
|
||||
}
|
||||
|
||||
// 分页信息
|
||||
interface Pagination {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
// 任务列表项
|
||||
interface TaskItem {
|
||||
id: number;
|
||||
title: string;
|
||||
grid: string;
|
||||
assignee: string | null;
|
||||
status: 'PENDING' | 'IN_PROGRESS' | 'COMPLETED' | 'REVIEWED';
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
// 对话框模式
|
||||
type DialogMode = 'create' | 'assign' | 'review' | 'view';
|
||||
```
|
||||
|
||||
## 5. 状态管理
|
||||
|
||||
```typescript
|
||||
// 组件内状态
|
||||
const filters = ref<TaskFilters>({});
|
||||
const pagination = ref<Pagination>({ page: 1, pageSize: 10 });
|
||||
const dialogVisible = ref(false);
|
||||
const selectedTaskId = ref<number | null>(null);
|
||||
const dialogMode = ref<DialogMode>('view');
|
||||
|
||||
// 全局状态 (Pinia Store)
|
||||
const taskStore = useTaskStore();
|
||||
const { tasks, total, loading } = storeToRefs(taskStore);
|
||||
const authStore = useAuthStore();
|
||||
const { user } = storeToRefs(authStore);
|
||||
```
|
||||
|
||||
## 6. 交互逻辑
|
||||
|
||||
### 6.1 数据获取与筛选
|
||||
|
||||
```typescript
|
||||
const fetchTasks = () => {
|
||||
taskStore.fetchTasks({ ...filters.value, ...pagination.value });
|
||||
};
|
||||
|
||||
onMounted(fetchTasks);
|
||||
|
||||
const handleSearch = () => {
|
||||
pagination.value.page = 1;
|
||||
fetchTasks();
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
filters.value = {};
|
||||
handleSearch();
|
||||
};
|
||||
|
||||
const handleSizeChange = (size: number) => {
|
||||
pagination.value.pageSize = size;
|
||||
fetchTasks();
|
||||
};
|
||||
|
||||
const handleCurrentChange = (page: number) => {
|
||||
pagination.value.page = page;
|
||||
fetchTasks();
|
||||
};
|
||||
```
|
||||
|
||||
### 6.2 表格操作
|
||||
|
||||
```typescript
|
||||
const handleView = (task: TaskItem) => {
|
||||
selectedTaskId.value = task.id;
|
||||
dialogMode.value = 'view';
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
|
||||
const handleAssign = (task: TaskItem) => {
|
||||
selectedTaskId.value = task.id;
|
||||
dialogMode.value = 'assign';
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
|
||||
const handleReview = (task: TaskItem) => {
|
||||
selectedTaskId.value = task.id;
|
||||
dialogMode.value = 'review';
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
|
||||
const handleCreateTask = () => {
|
||||
selectedTaskId.value = null;
|
||||
dialogMode.value = 'create';
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
|
||||
const handleSuccess = () => {
|
||||
dialogVisible.value = false;
|
||||
fetchTasks(); // 操作成功后刷新列表
|
||||
};
|
||||
```
|
||||
|
||||
### 6.3 权限控制
|
||||
|
||||
```typescript
|
||||
const canAssign = (task: TaskItem) => {
|
||||
return user.value?.role === 'SUPERVISOR' && task.status === 'PENDING';
|
||||
};
|
||||
|
||||
const canReview = (task: TaskItem) => {
|
||||
return user.value?.role === 'SUPERVISOR' && task.status === 'COMPLETED';
|
||||
};
|
||||
```
|
||||
|
||||
### 6.4 辅助函数
|
||||
|
||||
```typescript
|
||||
const formatStatus = (status: TaskItem['status']) => {
|
||||
const map = { PENDING: '待处理', IN_PROGRESS: '进行中', COMPLETED: '已完成', REVIEWED: '已审核' };
|
||||
return map[status] || '未知';
|
||||
};
|
||||
|
||||
// getStatusTagType 函数同仪表盘页面设计
|
||||
```
|
||||
|
||||
## 7. API 调用
|
||||
|
||||
```typescript
|
||||
// api/tasks.ts
|
||||
export const taskApi = {
|
||||
getTasks: (params) => apiClient.get('/management/tasks', { params }),
|
||||
// ... 其他任务相关API
|
||||
};
|
||||
|
||||
// stores/task.ts
|
||||
export const useTaskStore = defineStore('task', {
|
||||
state: () => ({
|
||||
tasks: [] as TaskItem[],
|
||||
total: 0,
|
||||
loading: false,
|
||||
}),
|
||||
actions: {
|
||||
async fetchTasks(params) {
|
||||
this.loading = true;
|
||||
try {
|
||||
const { data } = await taskApi.getTasks(params);
|
||||
this.tasks = data.items;
|
||||
this.total = data.total;
|
||||
} catch (error) {
|
||||
console.error('获取任务列表失败', error);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 8. 样式设计
|
||||
|
||||
```scss
|
||||
.task-management-page {
|
||||
padding: 24px;
|
||||
|
||||
.page-container {
|
||||
margin-top: 24px;
|
||||
padding: 24px;
|
||||
border-radius: 8px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.filter-container {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
margin-top: 24px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 9. 测试用例
|
||||
|
||||
1. **单元测试**:
|
||||
- 测试权限控制函数 `canAssign` 和 `canReview` 的逻辑。
|
||||
- 测试 `formatStatus` 辅助函数的正确性。
|
||||
- 测试 Pinia store 的 action 是否能正确调用 API 并更新 state。
|
||||
|
||||
2. **集成测试**:
|
||||
- 测试筛选、搜索和重置功能是否正常工作。
|
||||
- 测试分页组件是否能正确切换页面和每页数量。
|
||||
- 测试"查看"、"分配"、"审核"、"新建"按钮能否正确打开对应模式的对话框。
|
||||
- 测试对话框操作成功后,任务列表是否刷新。
|
||||
|
||||
## 10. 性能优化
|
||||
|
||||
1. **后端分页**: 必须使用后端分页来处理大量任务数据。
|
||||
2. **防抖**: 对搜索输入框使用防抖处理,避免用户输入时频繁触发 API 请求。
|
||||
3. **组件懒加载**: `TaskFormDialog` 组件可以通过动态导入实现懒加载,只在需要时才加载。
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
[This is a placeholder for the grid worker dashboard interface image. In a real implementation, this would be an actual PNG image file.]
|
||||
4362
Design/业务流程.md
4362
Design/业务流程.md
@@ -1,4362 +0,0 @@
|
||||
# EMS 后端业务流程与架构深度解析
|
||||
|
||||
本文档旨在深入剖析应急管理系统(EMS)后端的核心业务流程、分层架构以及关键技术机制。通过对典型请求生命周期的分析,揭示系统各组件如何协同工作,以实现高效、可靠的业务功能。
|
||||
在您的项目中,主要有以下几类常见的注解:
|
||||
|
||||
### 1. JPA (Java Persistence API) 注解 - 用于数据库交互
|
||||
这类注解通常用在 model 或 entity 包下的类中,用于将一个Java对象映射到数据库的一张表。
|
||||
|
||||
@Entity : 声明这个类是一个实体类,它对应数据库中的一张表。
|
||||
@Table(name = "aqi_data") : 正如您在 `AqiData.java` 中看到的,这个注解用来指定该实体类对应数据库中的具体表名。在这里, AqiData 类对应 aqi_data 这张表。
|
||||
@Id : 指定这个字段是表的主键。
|
||||
@Column(name = "user_id") : 指定字段对应数据库表中的列名。
|
||||
@GeneratedValue : 定义主键的生成策略(例如,自增长)。
|
||||
### 2. Spring 框架注解 - 用于管理组件和处理请求
|
||||
这是项目中最核心的注解,用于实现依赖注入(DI)和面向切面编程(AOP)。
|
||||
|
||||
@Component : 通用的组件注解,表明这个类由 Spring 容器管理。
|
||||
@Service : 通常用在业务逻辑层(Service层),是 @Component 的一种特化。
|
||||
@Repository : 通常用在数据访问层(DAO/Repository层),也是 @Component 的一种特化。
|
||||
@RestController : 用在控制器(Controller)上,表明这个类处理HTTP请求,并且返回的数据会自动序列化为JSON格式。
|
||||
@Autowired : 自动注入依赖。Spring会自动寻找匹配的Bean(由 @Component 等注解标记的类的实例)并注入到该字段。
|
||||
@RequestMapping , @GetMapping , @PostMapping : 将HTTP请求的URL路径映射到具体的处理方法上。
|
||||
### 3. Lombok 注解 - 用于减少样板代码
|
||||
Lombok是一个非常实用的Java库,可以通过注解在编译时自动生成代码。
|
||||
|
||||
@Data : 一个非常方便的组合注解,会自动为类的所有字段生成 getter 、 setter 方法,以及 toString() , equals() , hashCode() 方法。
|
||||
@NoArgsConstructor : 生成一个无参构造函数。
|
||||
@AllArgsConstructor : 生成一个包含所有字段的构造函数。
|
||||
@Slf4j : 为类自动创建一个 log 静态常量,方便您直接使用 log.info(...) 等方法打印日志。
|
||||
|
||||
## 一、 系统核心思想与分层架构
|
||||
|
||||
EMS 后端遵循业界主流的**分层架构**设计,旨在实现**高内聚、低耦合**的目标。这种架构将应用程序划分为不同的逻辑层,每一层都承担明确的职责。各层之间通过定义好的接口进行通信,使得系统更易于开发、测试、维护和扩展。
|
||||
|
||||
|
||||
### 1.1 分层架构概览
|
||||
|
||||
系统从上至下主要分为以下几个核心层级,对应于项目中的不同包:
|
||||
|
||||
- **Controller (控制层)**: `com.dne.ems.controller`
|
||||
- **职责**: 作为应用的入口,负责接收来自客户端(前端)的 HTTP 请求,解析请求参数,并调用服务层的相应方法来处理业务逻辑。它不包含任何业务逻辑,仅作为请求的调度和转发中心。
|
||||
- **交互**: 将处理结果(通常是 DTO 对象)封装成统一的 JSON 格式(`ApiResponse`)返回给客户端。
|
||||
|
||||
- **Service (服务层)**: `com.dne.ems.service`
|
||||
- **职责**: 系统的核心,负责实现所有复杂的业务逻辑。它编排一个或多个 Repository 来完成特定功能,处理数据、执行计算、实施业务规则,并处理事务。
|
||||
- **交互**: 被 Controller 层调用,同时调用 Repository 层来访问数据库。
|
||||
|
||||
- **Repository (数据访问层)**: `com.dne.ems.repository`
|
||||
- **职责**: 定义数据持久化的接口,负责与数据库进行交互。通过继承 Spring Data JPA 的 `JpaRepository`,开发者无需编写具体的 SQL 语句即可实现对数据的增删改查(CRUD)以及复杂的查询。
|
||||
- **交互**: 被 Service 层调用,直接操作数据库。
|
||||
|
||||
- **Model (模型层)**: `com.dne.ems.model`
|
||||
- **职责**: 定义系统的领域对象,即与数据库表结构一一对应的实体类(Entity)。它们使用 JPA 注解(如 `@Entity`, `@Table`, `@Id`)来映射数据库表和字段。
|
||||
- **交互**: 在 Repository 层和 Service 层之间传递数据。
|
||||
|
||||
- **DTO (数据传输对象)**: `com.dne.ems.dto`
|
||||
- **职责**: 作为各层之间,特别是 Controller 层与外部客户端之间的数据载体。DTO 的设计可以根据 API 的需要进行定制,隐藏内部领域模型的复杂性,避免暴露不必要的数据,从而提高系统的安全性与灵活性。
|
||||
|
||||
### 1.2 辅助模块
|
||||
|
||||
除了核心分层,系统还包含一系列重要的辅助模块,以支持整体功能的实现:
|
||||
|
||||
- **Security (安全模块)**: `com.dne.ems.security`
|
||||
- **职责**: 基于 Spring Security 实现用户认证(Authentication)和授权(Authorization)。它包含 JWT 的生成与校验、密码加密、以及精细化的接口访问控制策略。
|
||||
|
||||
- **Exception (异常处理模块)**: `com.dne.ems.exception`
|
||||
- **职责**: 提供全局统一的异常处理机制。通过 `@ControllerAdvice`,系统可以捕获在业务流程中抛出的各类异常,并将其转换为对客户端友好的、标准化的错误响应。
|
||||
|
||||
- **Config (配置模块)**: `com.dne.ems.config`
|
||||
- **职责**: 存放应用的配置类,如 Spring Security 配置、Web MVC 配置、以及应用启动时的数据初始化逻辑(`DataInitializer`)。该模块为EMS系统提供了完整的基础设施支持,包括数据初始化、文件存储配置、API文档配置、HTTP客户端配置、WebSocket配置以及数据转换器等核心配置组件。
|
||||
|
||||
- **Controller (控制器模块)**: `com.dne.ems.controller`
|
||||
- **职责**: 作为系统的API入口层,负责处理所有HTTP请求,包括用户认证、反馈管理、任务分配、数据可视化等核心业务功能。该模块包含14个专业化控制器,每个控制器专注于特定的业务领域,提供RESTful API接口,支持权限控制、参数验证、分页查询等功能。
|
||||
|
||||
- **Event/Listener (事件驱动模块)**: `com.dne.ems.event`, `com.dne.ems.listener`
|
||||
- **职责**: 实现应用内的异步处理和解耦。例如,用户认证失败时,可以发布一个 `AuthenticationFailureEvent` 事件,由专门的监听器 `AuthenticationFailureEventListener` 异步处理登录失败次数的记录,而不会阻塞主认证流程。
|
||||
|
||||
## 二、 项目亮点与创新
|
||||
|
||||
本项目在传统的城市管理系统基础上,融合了多项现代技术与创新理念,旨在打造一个**智能、高效、协同**的城市环境治理平台。其核心亮点体现在以下几个方面:
|
||||
|
||||
### 2.1 业务全流程智能化
|
||||
|
||||
- **AI 预审核**: 公众提交的反馈信息不再需要人工进行初步筛选。系统集成的 AI 模型能够自动对反馈内容(包括文本和图像)进行分析,判断其有效性、紧急程度,并进行初步的分类。这极大地减轻了主管人员的工作负担,并将他们的精力解放出来,专注于更复杂的决策和任务分配。
|
||||
- **智能任务推荐与调度**: 在任务分配环节,系统能够基于网格员的当前位置、历史任务完成效率、技能特长以及当前负载情况,智能推荐最合适的执行人选。在紧急情况下,系统甚至可以自动进行任务的调度与指派,确保问题得到最快响应。
|
||||
|
||||
### 2.2 事件驱动的异步架构
|
||||
|
||||
- **松耦合与高响应**: 项目广泛采用了**事件驱动架构 (EDA)**。例如,当一个反馈提交后,系统会发布一个 `FeedbackSubmittedEvent` 事件,后续的 AI 分析、通知发送等多个操作都由独立的监听器异步执行。这种设计使得核心业务流程(如提交反馈)能够瞬间完成,极大地提升了用户体验和系统的吞吐量。同时,模块之间通过事件进行通信,而不是直接调用,实现了高度解耦,使得系统更容易扩展和维护。
|
||||
|
||||
### 2.3 全方位的数据驱动决策
|
||||
|
||||
- **实时数据大屏**: 决策者不再依赖于滞后的纸质报告。系统提供了一个动态、可交互的数据驾驶舱,实时展示城市环境的各项关键指标(KPIs),如 AQI 分布、任务完成率、反馈热力图等。所有数据都以直观的图表形式呈现,帮助管理者快速洞察问题、发现趋势,从而做出更科学的决策。
|
||||
- **绩效与资源优化**: 系统通过对历史数据的深度分析,能够评估不同区域的环境治理成效、各个网格员的工作效率,为绩效考核提供客观依据,并为未来的资源调配和政策制定提供数据支持。
|
||||
|
||||
### 2.4 四端一体的协同工作平台
|
||||
|
||||
- **角色精准赋能**: 系统为四类核心用户——**公众、网格员、主管、决策者**——分别设计了专属的客户端(Web 或移动应用),精准满足不同角色的工作需求。
|
||||
- **公众端**: 简化提交流程,提供实时进度查询。
|
||||
- **网格员端**: 移动化接单、处理、上报,并提供导航支持。
|
||||
- **主管端**: 集中审核、智能分配、实时监控。
|
||||
- **决策者端**: 宏观数据洞察,支持战略决策。
|
||||
- **无缝信息流转**: 通过统一的后端平台,信息可以在四个客户端之间无缝流转,形成从问题发现、任务分配、现场处理到决策分析的闭环管理,打破了传统工作模式中的信息孤岛。
|
||||
|
||||
## 三、 核心业务流程与关键机制深度解析
|
||||
|
||||
下面,我们将以具体的业务场景和技术实现为例,详细拆解请求在系统分层架构中的流转过程。
|
||||
|
||||
### 2.1 用户认证与授权
|
||||
|
||||
此流程是系统的安全基石,涉及用户登录、权限验证和 Token 管理。
|
||||
|
||||
#### API 接口
|
||||
|
||||
- **用户注册**: `POST /api/auth/signup`
|
||||
- **用户登录**: `POST /api/auth/login`
|
||||
- **发送验证码**: `POST /api/auth/send-verification-code`
|
||||
- **请求重置密码**: `POST /api/auth/request-password-reset`
|
||||
- **重置密码**: `POST /api/auth/reset-password`
|
||||
|
||||
**场景:用户使用用户名和密码登录 (POST /api/auth/login)**
|
||||
|
||||
1. **前端 -> Controller (`AuthController`)**
|
||||
- **动作**: 用户在登录页输入凭据,前端发送 `POST` 请求到 `/api/auth/login`,请求体为包含 `username` 和 `password` 的 `LoginRequest` DTO。
|
||||
- **Controller 角色**: `AuthController` 的 `authenticateUser` 方法接收请求。`@Valid` 注解确保了输入的基本格式正确。Controller 将 `LoginRequest` 直接传递给 `AuthService` 进行处理。
|
||||
|
||||
2. **Controller -> Service (`AuthService`)**
|
||||
- **动作**: `AuthService` 调用 Spring Security 的 `AuthenticationManager` 的 `authenticate` 方法。`AuthenticationManager` 是认证的核心入口。
|
||||
- **Service 角色**: `AuthService` 编排了整个认证流程:
|
||||
- **凭证封装**: 将用户名和密码封装成 `UsernamePasswordAuthenticationToken`。
|
||||
- **认证委托**: 将此 `token` 交给 `AuthenticationManager`。`AuthenticationManager` 会遍历其内部的 `AuthenticationProvider` 列表(在我们的例子中是 `DaoAuthenticationProvider`)来寻找能处理此 `token` 的提供者。
|
||||
- **用户查找**: `DaoAuthenticationProvider` 会使用 `UserDetailsService` (我们的实现是 `UserDetailsServiceImpl`) 的 `loadUserByUsername` 方法,根据用户名去数据库查找用户。`UserDetailsServiceImpl` 会调用 `UserRepository`。
|
||||
- **密码比对**: `DaoAuthenticationProvider` 使用 `PasswordEncoder` (我们配置的 `BCryptPasswordEncoder`) 比较用户提交的密码和数据库中存储的加密哈希值。
|
||||
- **生成 JWT**: 如果认证成功,`AuthService` 调用 `JwtTokenProvider` 的 `generateToken` 方法,为认证通过的 `Authentication` 对象生成一个 JWT。
|
||||
|
||||
3. **Service -> Repository (`UserRepository`)**
|
||||
- **动作**: `UserDetailsServiceImpl` 调用 `userRepository.findByUsername(username)`。
|
||||
- **Repository 角色**: `UserRepository` 执行 `SELECT` 查询,从 `users` 表中找到对应的用户记录,并将其封装成 `User` 实体对象返回。
|
||||
|
||||
4. **安全组件交互 (`JwtTokenProvider`, `UserDetailsServiceImpl`)**
|
||||
- `UserDetailsServiceImpl`: 实现了 Spring Security 的 `UserDetailsService` 接口,是连接应用用户数据和 Spring Security 框架的桥梁。
|
||||
- `JwtTokenProvider`: 负责 JWT 的生成和解析。`generateToken` 方法会设置主题(用户名)、签发时间、过期时间,并使用预设的密钥和算法(HS512)进行签名。
|
||||
|
||||
5. **Controller -> 前端**
|
||||
- **动作**: `AuthService` 返回生成的 JWT。`AuthController` 将此 JWT 包装在 `JwtAuthenticationResponse` DTO 中,再放入 `ApiResponse.success()`,以 HTTP 200 状态码返回给前端。
|
||||
- **后续请求**: 前端在后续所有需要认证的请求的 `Authorization` 头中携带此 JWT (`Bearer <token>`)。Spring Security 的 `JwtAuthenticationFilter` 会在每个请求到达 Controller 前拦截并验证此 Token。
|
||||
|
||||
### 2.2 公众反馈管理
|
||||
|
||||
#### API 接口
|
||||
|
||||
- **提交反馈 (JSON)**: `POST /api/feedback/submit-json`
|
||||
- **提交反馈 (Multipart)**: `POST /api/feedback/submit`
|
||||
- **获取所有反馈**: `GET /api/feedback`
|
||||
- **公众提交反馈**: `POST /api/public/feedback`
|
||||
|
||||
**场景:公众提交带图片的反馈 (POST /api/public/feedback)**
|
||||
|
||||
1. **前端 -> Controller (`PublicController`)**
|
||||
- **动作**: 公众用户填写反馈表单(描述、位置、图片),前端以 `multipart/form-data` 格式提交到 `/api/public/feedback`。
|
||||
- **Controller 角色**: `createFeedback` 方法使用 `@RequestPart` 分别接收反馈内容的 DTO (`FeedbackCreateDTO`) 和文件 (`MultipartFile`)。`@Valid` 确保 DTO 数据合规。Controller 随即调用 `FeedbackService`。
|
||||
|
||||
2. **Controller -> Service (`FeedbackService` & `FileStorageService`)**
|
||||
- **动作**: `FeedbackService` 的 `createFeedback` 方法被调用。
|
||||
- **Service 角色**:
|
||||
- **文件处理**: 如果 `file` 存在,`FeedbackService` 首先调用 `FileStorageService` 的 `storeFile` 方法。`FileStorageService` 会生成唯一文件名,将文件存储在服务器的 `uploads` 目录下,并返回可访问的文件路径。
|
||||
- **实体创建**: `FeedbackService` 创建一个新的 `Feedback` 实体。
|
||||
- **数据映射**: 使用 `ModelMapper` 将 `FeedbackCreateDTO` 的数据(如 `description`, `location`)映射到 `Feedback` 实体上。
|
||||
- **关联文件**: 将 `FileStorageService` 返回的文件路径设置到 `Feedback` 实体的 `imageUrl` 字段。
|
||||
- **状态设定**: 设置反馈的初始状态为 `PENDING`。
|
||||
- **持久化**: 调用 `feedbackRepository.save(newFeedback)`。
|
||||
|
||||
3. **Service -> Repository (`FeedbackRepository`)**
|
||||
- **动作**: `feedbackRepository.save()` 执行 `INSERT` SQL 语句,将新的反馈记录存入 `feedbacks` 表。
|
||||
|
||||
4. **Controller -> 前端**
|
||||
- **动作**: `FeedbackService` 返回成功创建的 `Feedback` 对象的 DTO。`PublicController` 将其包装在 `ApiResponse.success()` 中,以 HTTP 201 (Created) 状态码返回,表示资源创建成功。
|
||||
|
||||
### 2.3 任务生命周期管理
|
||||
|
||||
#### API 接口
|
||||
|
||||
- **获取待审核的反馈列表**: `GET /api/supervisor/reviews`
|
||||
- **批准反馈**: `POST /api/supervisor/reviews/{feedbackId}/approve`
|
||||
- **拒绝反馈**: `POST /api/supervisor/reviews/{feedbackId}/reject`
|
||||
- **获取未分配的反馈**: `GET /api/tasks/unassigned`
|
||||
- **获取可用的网格员**: `GET /api/tasks/grid-workers`
|
||||
- **分配任务**: `POST /api/tasks/assign`
|
||||
- **获取任务列表**: `GET /api/management/tasks`
|
||||
- **分配任务**: `POST /api/management/tasks/{taskId}/assign`
|
||||
- **获取任务详情**: `GET /api/management/tasks/{taskId}`
|
||||
- **审核任务**: `POST /api/management/tasks/{taskId}/review`
|
||||
- **取消任务**: `POST /api/management/tasks/{taskId}/cancel`
|
||||
- **直接创建任务**: `POST /api/management/tasks`
|
||||
- **获取待处理的反馈**: `GET /api/management/tasks/feedback`
|
||||
- **从反馈创建任务**: `POST /api/management/tasks/feedback/{feedbackId}/create-task`
|
||||
- **获取我的任务**: `GET /api/worker`
|
||||
- **获取任务详情**: `GET /api/worker/{taskId}`
|
||||
- **接受任务**: `POST /api/worker/{taskId}/accept`
|
||||
- **提交任务**: `POST /api/worker/{taskId}/submit`
|
||||
|
||||
**场景:主管审核反馈并转换为任务 (POST /api/supervisor/feedback/{feedbackId}/convert)**
|
||||
|
||||
1. **前端 -> Controller (`SupervisorController`)**
|
||||
- **动作**: 主管在管理界面查看一条反馈,点击“转换为任务”按钮。前端发送 `POST` 请求到 `/api/supervisor/feedback/456/convert`,请求体中可能包含指派信息 `TaskFromFeedbackDTO`。
|
||||
- **Controller 角色**: `convertFeedbackToTask` 方法接收请求,解析 `feedbackId` 和 DTO,然后调用 `TaskService`。
|
||||
|
||||
2. **Controller -> Service (`TaskService` & `FeedbackService`)**
|
||||
- **动作**: `TaskService` 的 `createTaskFromFeedback` 方法被调用。
|
||||
- **Service 角色**: 这是一个跨领域服务的协调过程。
|
||||
- **获取反馈**: 调用 `feedbackRepository.findById(feedbackId)` 获取原始反馈信息。如果不存在,抛出 `ResourceNotFoundException`。
|
||||
- **状态检查**: 检查反馈是否已经是“已处理”状态,防止重复转换。
|
||||
- **创建任务实体**: 创建一个新的 `Task` 实体。
|
||||
- **数据迁移**: 将 `Feedback` 的 `description`, `location` 等信息复制到 `Task` 实体中。
|
||||
- **设置任务属性**: 根据 `TaskFromFeedbackDTO` 设置任务的标题、截止日期、指派的网格员(如果提供了 `workerId`)。如果未指派,任务状态为 `PENDING`;如果已指派,状态为 `ASSIGNED`。
|
||||
- **持久化任务**: 调用 `taskRepository.save(newTask)`。
|
||||
- **更新反馈状态**: 更新 `Feedback` 实体的状态为 `PROCESSED`,并调用 `feedbackRepository.save(feedback)`。
|
||||
- **事务管理**: 整个方法应该被 `@Transactional` 注解标记,确保创建任务和更新反馈状态这两个操作要么同时成功,要么同时失败。
|
||||
|
||||
3. **Service -> Repository (`TaskRepository`, `FeedbackRepository`)**
|
||||
- **动作**: `TaskRepository` 插入一条新任务记录。`FeedbackRepository` 更新对应的反馈记录状态。
|
||||
|
||||
4. **Controller -> 前端**
|
||||
- **动作**: `TaskService` 返回新创建的任务的 DTO。`SupervisorController` 将其包装在 `ApiResponse.success()` 中返回,前端可以根据返回的任务信息进行页面跳转或状态更新。
|
||||
|
||||
### 2.4 数据可视化与决策支持
|
||||
|
||||
#### API 接口
|
||||
|
||||
- **获取仪表盘统计数据**: `GET /api/dashboard/stats`
|
||||
- **获取 AQI 分布**: `GET /api/dashboard/reports/aqi-distribution`
|
||||
- **获取污染超标月度趋势**: `GET /api/dashboard/reports/pollution-trend`
|
||||
- **获取网格覆盖率**: `GET /api/dashboard/reports/grid-coverage`
|
||||
- **获取反馈热力图数据**: `GET /api/dashboard/map/heatmap`
|
||||
- **获取污染类型统计**: `GET /api/dashboard/reports/pollution-stats`
|
||||
- **获取任务完成情况统计**: `GET /api/dashboard/reports/task-completion-stats`
|
||||
- **获取 AQI 热力图数据**: `GET /api/dashboard/map/aqi-heatmap`
|
||||
|
||||
### 2.5 智能分配算法
|
||||
|
||||
#### API 接口
|
||||
|
||||
- **获取任务的推荐人选**: `GET /api/tasks/{taskId}/recommendations`
|
||||
|
||||
**场景:主管为新任务寻求系统推荐的执行人 (GET /api/tasks/123/recommendations)**
|
||||
|
||||
1. **前端 -> Controller (`TaskManagementController`)**
|
||||
- **动作**: 主管在任务分配界面,点击“推荐人选”按钮。前端向 `/api/tasks/123/recommendations` 发送 `GET` 请求。
|
||||
- **Controller 角色**: `getTaskRecommendations` 方法接收请求,并调用 `TaskRecommendationService`。
|
||||
|
||||
2. **Controller -> Service (`TaskRecommendationService`)**
|
||||
- **动作**: `TaskRecommendationService` 的 `recommendWorkersForTask` 方法被调用。
|
||||
- **Service 角色**: 这是智能分配算法的核心实现。
|
||||
- **获取任务信息**: 首先,从 `taskRepository` 获取任务详情,特别是任务的地理位置和类型。
|
||||
- **筛选候选人**: 从 `userRepository` 获取所有角色为“网格员”且状态为“可用”的用户列表。
|
||||
- **为每位候选人评分**: 遍历候选人列表,根据一系列预设标准计算综合得分。这是一个典型的加权评分模型:
|
||||
- **距离 (40%)**: 计算网格员当前位置与任务位置的直线距离。距离越近,得分越高。`Score = (MaxDistance - WorkerDistance) / MaxDistance`。
|
||||
- **当前负载 (30%)**: 查询该网格员当前状态为 `ASSIGNED` 或 `IN_PROGRESS` 的任务数量。任务越少,得分越高。`Score = (MaxLoad - WorkerLoad) / MaxLoad`。
|
||||
- **技能匹配度 (20%)**: 如果任务有特定的技能要求(如“管道维修”),检查网格员的技能标签。匹配则得满分,否则得0分。
|
||||
- **历史表现 (10%)**: 查询该网格员过去完成类似任务的平均耗时和评价。表现越好,得分越高。
|
||||
- **加权总分**: `Total Score = Score_Distance * 0.4 + Score_Load * 0.3 + Score_Skill * 0.2 + Score_Performance * 0.1`。
|
||||
- **排序**: 根据总分对所有候选人进行降序排序。
|
||||
|
||||
3. **Service -> Repository (Multiple Repositories)**
|
||||
- **动作**: `TaskRecommendationService` 会与 `TaskRepository`, `UserRepository`, `WorkerLocationRepository` (假设有这样一个实时位置库) 等多个 Repository 交互,以获取计算所需的数据。
|
||||
|
||||
4. **Controller -> 前端**
|
||||
- **动作**: `TaskRecommendationService` 返回一个包含网格员信息和他们各自推荐分数的 DTO 列表。`TaskManagementController` 将此列表包装在 `ApiResponse.success()` 中返回。前端界面会高亮显示得分最高的几位候选人,并附上推荐理由(如“距离最近”,“负载最低”),辅助主管做出最终决策。
|
||||
|
||||
**场景:决策者查看仪表盘 (GET /api/dashboard)**
|
||||
|
||||
1. **前端 -> Controller (`DashboardController`)**
|
||||
- **动作**: 决策者访问仪表盘页面,前端发送 `GET` 请求到 `/api/dashboard`。
|
||||
- **Controller 角色**: `getDashboardData` 方法直接调用 `DashboardService`。
|
||||
|
||||
2. **Controller -> Service (`DashboardService`)**
|
||||
- **动作**: `DashboardService` 的 `getDashboardData` 方法被调用。
|
||||
- **Service 角色**: 这是一个典型的数据聚合服务。
|
||||
- **并行/串行查询**: `DashboardService` 会向多个 Repository 发起查询请求,以收集构建仪表盘所需的所有数据。
|
||||
- **任务统计**: 调用 `taskRepository` 的自定义聚合查询方法(如 `countByStatus`)来获取不同状态的任务数。
|
||||
- **反馈统计**: 调用 `feedbackRepository.countByStatus` 获取不同状态的反馈数。
|
||||
- **人员概览**: 调用 `personnelRepository.count()` 获取总人数。
|
||||
- **AQI 数据**: 调用 `aqiDataRepository.findLatest()` 获取最新的空气质量数据。
|
||||
- **数据组装**: 将所有查询到的零散数据,组装成一个专为前端仪表盘设计的 `DashboardDTO` 对象。
|
||||
|
||||
3. **Service -> Repository (多个)**
|
||||
- **动作**: `TaskRepository`, `FeedbackRepository`, `PersonnelRepository` 等分别执行高效的数据库聚合查询(如 `SELECT status, COUNT(*) FROM tasks GROUP BY status`)。
|
||||
- **Repository 角色**: Repository 接口中定义了这些自定义查询方法,使用 `@Query` 注解编写 JPQL 或原生 SQL,直接利用数据库的计算能力,避免在应用服务层进行大量数据处理。
|
||||
|
||||
4. **Controller -> 前端**
|
||||
- **动作**: `DashboardService` 返回填充了完整数据的 `DashboardDTO`。`DashboardController` 将其包装在 `ApiResponse.success()` 中,以 HTTP 200 状态码返回。前端收到 JSON 数据后,使用图表库(如 ECharts)进行渲染。
|
||||
|
||||
### 2.5 网格与人员管理
|
||||
|
||||
#### API 接口
|
||||
|
||||
- **获取网格列表**: `GET /api/grids`
|
||||
- **更新网格信息**: `PATCH /api/grids/{gridId}`
|
||||
- **创建用户**: `POST /api/personnel/users`
|
||||
- **获取用户列表**: `GET /api/personnel/users`
|
||||
- **获取单个用户**: `GET /api/personnel/users/{userId}`
|
||||
- **更新用户信息**: `PATCH /api/personnel/users/{userId}`
|
||||
- **更新用户角色**: `PUT /api/personnel/users/{userId}/role`
|
||||
- **删除用户**: `DELETE /api/personnel/users/{userId}`
|
||||
- **更新个人资料**: `PATCH /api/me`
|
||||
- **更新我的位置**: `POST /api/me/location`
|
||||
- **获取我的反馈历史**: `GET /api/me/feedback`
|
||||
|
||||
**场景:管理员分页查询所有人员信息 (GET /api/management/personnel?page=0&size=10)**
|
||||
|
||||
1. **前端 -> Controller (`ManagementController`)**
|
||||
- **动作**: 管理员在人员管理页面,前端发送带分页参数的 `GET` 请求。
|
||||
- **Controller 角色**: `getAllPersonnel` 方法使用 `@RequestParam` 接收分页参数,并将其封装成 `Pageable` 对象,然后调用 `PersonnelService`。
|
||||
|
||||
2. **Controller -> Service (`PersonnelService`)**
|
||||
- **动作**: `PersonnelService` 的 `findAll` 方法接收 `Pageable` 对象。
|
||||
- **Service 角色**: 直接将 `Pageable` 对象传递给 `PersonnelRepository`。对于更复杂的查询(例如,按姓名或角色搜索),Service 层会接收额外的查询参数,并调用 `Specification` 或 `QueryDSL` 来构建动态查询。
|
||||
|
||||
3. **Service -> Repository (`PersonnelRepository`)**
|
||||
- **动作**: `personnelRepository.findAll(pageable)` 被调用。
|
||||
- **Repository 角色**: Spring Data JPA 会根据 `Pageable` 参数自动生成带有分页和排序的 SQL 查询(如 `SELECT ... FROM personnel LIMIT ? OFFSET ?`),并执行。它返回一个 `Page<Personnel>` 对象,其中包含了当前页的数据列表、总页数、总元素数量等完整的的分页信息。
|
||||
|
||||
4. **Controller -> 前端**
|
||||
- **动作**: `PersonnelService` 返回 `Page<Personnel>` 对象。`ManagementController` 将其直接放入 `ApiResponse.success()` 中返回。前端根据返回的 `Page` 对象渲染数据列表和分页控件。
|
||||
|
||||
### 2.6 AI 辅助功能
|
||||
|
||||
**场景:AI 辅助生成任务报告摘要 (POST /api/ai/summarize)**
|
||||
|
||||
1. **前端 -> Controller (`AiController`)**
|
||||
- **动作**: 用户在任务详情页输入或粘贴长篇报告文本,点击“生成摘要”。前端将文本内容包装在 `SummarizeRequest` DTO 中,发送 `POST` 请求。
|
||||
- **Controller 角色**: `summarizeText` 方法接收 DTO,并调用 `AiService`。
|
||||
|
||||
2. **Controller -> Service (`AiService`)**
|
||||
- **动作**: `AiService` 的 `getSummary` 方法被调用。
|
||||
- **Service 角色**: 这是与外部 AI 服务交互的核心。
|
||||
- **构建请求**: 根据所使用的 AI 服务(如 OpenAI, Google Gemini, 或其他私有化部署模型)的 API 规范,构建 HTTP 请求。这通常涉及设置 API Key、请求头、以及包含待摘要文本的 JSON 请求体。
|
||||
- **API 调用**: 使用 `RestTemplate` 或 `WebClient` 向 AI 服务的 API 端点发送请求。
|
||||
- **解析响应**: 接收 AI 服务返回的 JSON 响应,并从中提取出生成的摘要文本。
|
||||
- **异常处理**: 处理网络超时、API 认证失败、或 AI 服务返回错误码等异常情况。
|
||||
|
||||
3. **Controller -> 前端**
|
||||
- **动作**: `AiService` 返回提取出的摘要字符串。`AiController` 将其包装在 `ApiResponse.success()` 中返回给前端,前端将摘要显示在页面上。
|
||||
|
||||
### 2.7 关键技术机制深度解析
|
||||
|
||||
#### A. 文件上传与管理 (`FileStorageService`)
|
||||
- **流程**: `Controller` 接收 `MultipartFile` -> `Service` 调用 `FileStorageService.storeFile()` -> `FileStorageService` 生成唯一文件名 (e.g., `UUID.randomUUID().toString()`) 并拼接原始文件扩展名 -> 使用 `StringUtils.cleanPath` 清理文件名防止路径遍历攻击 -> 构建目标存储路径 `Path targetLocation = this.fileStorageLocation.resolve(fileName)` -> 使用 `Files.copy` 将文件输入流写入目标路径,并使用 `StandardCopyOption.REPLACE_EXISTING` 覆盖同名文件 -> 返回通过 `ServletUriComponentsBuilder` 构建的、可从外部访问的文件下载 URI。
|
||||
- **关键点**:
|
||||
- **配置化**: 文件存储路径 (`file.upload-dir`) 在 `application.properties` 中配置,具有灵活性。
|
||||
- **安全性**: 明确处理了 `FileNameContainsInvalidCharactersException` 和 `FileStorageException`。
|
||||
- **资源服务**: 提供了 `loadFileAsResource` 方法,可以将存储的文件作为 `Resource` 对象加载,以便于下载。
|
||||
|
||||
### 2.8 地图与路径规划
|
||||
|
||||
#### A. 地图服务 (`MapService`)
|
||||
- **获取完整地图网格**: `GET /api/map/grid`
|
||||
- **创建或更新地图单元格**: `POST /api/map/grid`
|
||||
- **初始化地图**: `POST /api/map/initialize`
|
||||
|
||||
#### B. 路径规划服务 (`PathfindingService`)
|
||||
- **寻找路径**: `POST /api/pathfinding/find`
|
||||
|
||||
#### B. 文件服务 (`FileService`)
|
||||
- **下载文件**: `GET /api/files/download/{fileName}`
|
||||
- **查看文件**: `GET /api/files/view/{fileName}`
|
||||
|
||||
#### C. 邮件与验证码服务 (`EmailService`)
|
||||
- **流程**: `AuthService` 调用 `EmailService.sendVerificationCode(email)` -> `EmailService` 使用 `Random` 生成6位数字验证码 -> 将 `email:code` 键值对存入 `verificationCodeCache` (一个 `Caffeine` 缓存实例),并设置5分钟过期 -> 使用 `JavaMailSender` 创建 `SimpleMailMessage`,设置收件人、主题和正文 -> `mailSender.send(message)` 发送邮件。
|
||||
|
||||
## 三、API 接口文档
|
||||
|
||||
本部分详细列出了系统提供的所有API接口,包括其功能描述、请求路径、方法、所需权限以及请求/响应示例。
|
||||
|
||||
### 1. 认证模块 (Auth)
|
||||
**基础路径**: `/api/auth`
|
||||
|
||||
#### 1.1 用户注册
|
||||
- **功能描述**: 注册一个新用户。
|
||||
- **请求路径**: `/api/auth/signup`
|
||||
- **请求方法**: `POST`
|
||||
- **所需权限**: 无
|
||||
- **请求体**: `SignUpRequest`
|
||||
|
||||
#### 1.2 用户登录
|
||||
- **功能描述**: 用户登录并获取 JWT Token。
|
||||
- **请求路径**: `/api/auth/login`
|
||||
- **请求方法**: `POST`
|
||||
- **所需权限**: 无
|
||||
- **请求体**: `LoginRequest`
|
||||
|
||||
#### 1.3 发送验证码
|
||||
- **功能描述**: 请求发送验证码到指定邮箱。
|
||||
- **请求路径**: `/api/auth/send-verification-code`
|
||||
- **请求方法**: `POST`
|
||||
- **所需权限**: 无
|
||||
- **查询参数**: `email` (string, 必需)
|
||||
|
||||
#### 1.4 请求重置密码
|
||||
- **功能描述**: 请求发送重置密码的链接或令牌。
|
||||
- **请求路径**: `/api/auth/request-password-reset`
|
||||
- **请求方法**: `POST`
|
||||
- **所需权限**: 无
|
||||
- **请求体**: `PasswordResetRequest`
|
||||
|
||||
#### 1.5 重置密码
|
||||
- **功能描述**: 使用令牌重置密码。
|
||||
- **请求路径**: `/api/auth/reset-password`
|
||||
- **请求方法**: `POST`
|
||||
- **所需权限**: 无
|
||||
- **请求体**: `PasswordResetDto`
|
||||
|
||||
### 2. 仪表盘模块 (Dashboard)
|
||||
**基础路径**: `/api/dashboard`
|
||||
**所需权限**: `DECISION_MAKER`
|
||||
|
||||
#### 2.1 获取仪表盘统计数据
|
||||
- **请求路径**: `/api/dashboard/stats`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
#### 2.2 获取 AQI 分布
|
||||
- **请求路径**: `/api/dashboard/reports/aqi-distribution`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
#### 2.3 获取污染超标月度趋势
|
||||
- **请求路径**: `/api/dashboard/reports/pollution-trend`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
#### 2.4 获取网格覆盖率
|
||||
- **请求路径**: `/api/dashboard/reports/grid-coverage`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
#### 2.5 获取反馈热力图数据
|
||||
- **请求路径**: `/api/dashboard/map/heatmap`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
#### 2.6 获取污染类型统计
|
||||
- **请求路径**: `/api/dashboard/reports/pollution-stats`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
#### 2.7 获取任务完成情况统计
|
||||
- **请求路径**: `/api/dashboard/reports/task-completion-stats`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
#### 2.8 获取 AQI 热力图数据
|
||||
- **请求路径**: `/api/dashboard/map/aqi-heatmap`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
### 3. 反馈模块 (Feedback)
|
||||
**基础路径**: `/api/feedback`
|
||||
|
||||
#### 3.1 提交反馈 (JSON)
|
||||
- **功能描述**: 用于测试,使用 JSON 提交反馈。
|
||||
- **请求路径**: `/api/feedback/submit-json`
|
||||
- **请求方法**: `POST`
|
||||
- **所需权限**: 已认证用户
|
||||
- **请求体**: `FeedbackSubmissionRequest`
|
||||
|
||||
#### 3.2 提交反馈 (Multipart)
|
||||
- **功能描述**: 提交反馈,可包含文件。
|
||||
- **请求路径**: `/api/feedback/submit`
|
||||
- **请求方法**: `POST`
|
||||
- **所需权限**: 已认证用户
|
||||
- **请求体**: `multipart/form-data`
|
||||
|
||||
#### 3.3 获取所有反馈
|
||||
- **功能描述**: 获取所有反馈(分页)。
|
||||
- **请求路径**: `/api/feedback`
|
||||
- **请求方法**: `GET`
|
||||
- **所需权限**: `ADMIN`
|
||||
|
||||
### 4. 文件模块 (File)
|
||||
**基础路径**: `/api/files`
|
||||
**所需权限**: 公开访问
|
||||
|
||||
#### 4.1 下载文件
|
||||
- **请求路径**: `/api/files/download/{fileName}`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
#### 4.2 查看文件
|
||||
- **请求路径**: `/api/files/view/{fileName}`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
### 5. 网格模块 (Grid)
|
||||
**基础路径**: `/api/grids`
|
||||
**所需权限**: `ADMIN` 或 `DECISION_MAKER`
|
||||
|
||||
#### 5.1 获取网格列表
|
||||
- **请求路径**: `/api/grids`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
#### 5.2 更新网格信息
|
||||
- **请求路径**: `/api/grids/{gridId}`
|
||||
- **请求方法**: `PATCH`
|
||||
- **所需权限**: `ADMIN`
|
||||
|
||||
### 6. 网格员任务模块 (Worker)
|
||||
**基础路径**: `/api/worker`
|
||||
**所需权限**: `GRID_WORKER`
|
||||
|
||||
#### 6.1 获取我的任务
|
||||
- **请求路径**: `/api/worker`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
#### 6.2 获取任务详情
|
||||
- **请求路径**: `/api/worker/{taskId}`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
#### 6.3 接受任务
|
||||
- **请求路径**: `/api/worker/{taskId}/accept`
|
||||
- **请求方法**: `POST`
|
||||
|
||||
#### 6.4 提交任务
|
||||
- **请求路径**: `/api/worker/{taskId}/submit`
|
||||
- **请求方法**: `POST`
|
||||
|
||||
### 7. 地图模块 (Map)
|
||||
**基础路径**: `/api/map`
|
||||
**所需权限**: 公开访问
|
||||
|
||||
#### 7.1 获取完整地图网格
|
||||
- **请求路径**: `/api/map/grid`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
#### 7.2 创建或更新地图单元格
|
||||
- **请求路径**: `/api/map/grid`
|
||||
- **请求方法**: `POST`
|
||||
|
||||
#### 7.3 初始化地图
|
||||
- **请求路径**: `/api/map/initialize`
|
||||
- **请求方法**: `POST`
|
||||
|
||||
### 8. 路径规划模块 (Pathfinding)
|
||||
**基础路径**: `/api/pathfinding`
|
||||
**所需权限**: 公开访问
|
||||
|
||||
#### 8.1 寻找路径
|
||||
- **功能描述**: 使用 A* 算法在两点之间寻找最短路径。
|
||||
- **请求路径**: `/api/pathfinding/find`
|
||||
- **请求方法**: `POST`
|
||||
|
||||
### 9. 人员管理模块 (Personnel)
|
||||
**基础路径**: `/api/personnel`
|
||||
**所需权限**: `ADMIN`
|
||||
|
||||
#### 9.1 创建用户
|
||||
- **请求路径**: `/api/personnel/users`
|
||||
- **请求方法**: `POST`
|
||||
|
||||
#### 9.2 获取用户列表
|
||||
- **请求路径**: `/api/personnel/users`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
#### 9.3 获取单个用户
|
||||
- **请求路径**: `/api/personnel/users/{userId}`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
#### 9.4 更新用户信息
|
||||
- **请求路径**: `/api/personnel/users/{userId}`
|
||||
- **请求方法**: `PATCH`
|
||||
|
||||
#### 9.5 更新用户角色
|
||||
- **请求路径**: `/api/personnel/users/{userId}/role`
|
||||
- **请求方法**: `PUT`
|
||||
|
||||
#### 9.6 删除用户
|
||||
- **请求路径**: `/api/personnel/users/{userId}`
|
||||
- **请求方法**: `DELETE`
|
||||
|
||||
### 10. 个人资料模块 (Me)
|
||||
**基础路径**: `/api/me`
|
||||
**所需权限**: 已认证用户
|
||||
|
||||
#### 10.1 更新个人资料
|
||||
- **请求路径**: `/api/me`
|
||||
- **请求方法**: `PATCH`
|
||||
|
||||
#### 10.2 更新我的位置
|
||||
- **请求路径**: `/api/me/location`
|
||||
- **请求方法**: `POST`
|
||||
|
||||
#### 10.3 获取我的反馈历史
|
||||
- **请求路径**: `/api/me/feedback`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
### 11. 公共接口模块 (Public)
|
||||
**基础路径**: `/api/public`
|
||||
**所需权限**: 公开访问
|
||||
|
||||
#### 11.1 公众提交反馈
|
||||
- **请求路径**: `/api/public/feedback`
|
||||
- **请求方法**: `POST`
|
||||
|
||||
### 12. 主管模块 (Supervisor)
|
||||
**基础路径**: `/api/supervisor`
|
||||
**所需权限**: `SUPERVISOR` 或 `ADMIN`
|
||||
|
||||
#### 12.1 获取待审核的反馈列表
|
||||
- **请求路径**: `/api/supervisor/reviews`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
#### 12.2 批准反馈
|
||||
- **请求路径**: `/api/supervisor/reviews/{feedbackId}/approve`
|
||||
- **请求方法**: `POST`
|
||||
|
||||
#### 12.3 拒绝反馈
|
||||
- **请求路径**: `/api/supervisor/reviews/{feedbackId}/reject`
|
||||
- **请求方法**: `POST`
|
||||
|
||||
### 13. 任务分配模块 (Tasks)
|
||||
**基础路径**: `/api/tasks`
|
||||
**所需权限**: `ADMIN` 或 `SUPERVISOR`
|
||||
|
||||
#### 13.1 获取未分配的反馈
|
||||
- **请求路径**: `/api/tasks/unassigned`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
#### 13.2 获取可用的网格员
|
||||
- **请求路径**: `/api/tasks/grid-workers`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
#### 13.3 分配任务
|
||||
- **请求路径**: `/api/tasks/assign`
|
||||
- **请求方法**: `POST`
|
||||
|
||||
### 14. 任务管理模块 (Management)
|
||||
**基础路径**: `/api/management/tasks`
|
||||
**所需权限**: `SUPERVISOR`
|
||||
|
||||
#### 14.1 获取任务列表
|
||||
- **请求路径**: `/api/management/tasks`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
#### 14.2 分配任务
|
||||
- **请求路径**: `/api/management/tasks/{taskId}/assign`
|
||||
- **请求方法**: `POST`
|
||||
|
||||
#### 14.3 获取任务详情
|
||||
- **请求路径**: `/api/management/tasks/{taskId}`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
#### 14.4 审核任务
|
||||
- **请求路径**: `/api/management/tasks/{taskId}/review`
|
||||
- **请求方法**: `POST`
|
||||
|
||||
#### 14.5 取消任务
|
||||
- **请求路径**: `/api/management/tasks/{taskId}/cancel`
|
||||
- **请求方法**: `POST`
|
||||
|
||||
#### 14.6 直接创建任务
|
||||
- **请求路径**: `/api/management/tasks`
|
||||
- **请求方法**: `POST`
|
||||
|
||||
#### 14.7 获取待处理的反馈
|
||||
- **请求路径**: `/api/management/tasks/feedback`
|
||||
- **请求方法**: `GET`
|
||||
|
||||
#### 14.8 从反馈创建任务
|
||||
- **请求路径**: `/api/management/tasks/feedback/{feedbackId}/create-task`
|
||||
- **请求方法**: `POST`
|
||||
- **验证流程**: 用户提交验证码 -> `AuthService` 调用 `EmailService.verifyCode(email, code)` -> `EmailService` 从缓存中通过 `verificationCodeCache.getIfPresent(email)` 获取验证码,并与用户提交的 `code` 进行比对。如果匹配且存在,则验证成功并从缓存中移除该验证码 (`cache.invalidate(email)`)。
|
||||
|
||||
#### C. 登录安全与尝试锁定 (`AuthenticationFailureEventListener`)
|
||||
- **流程**: 用户登录失败 -> Spring Security 的 `ProviderManager` 认证失败后,会发布一个 `AuthenticationFailureBadCredentialsEvent` 事件 -> `AuthenticationFailureEventListener` (一个实现了 `ApplicationListener` 的组件) 的 `onApplicationEvent` 方法被触发 -> 监听器从事件中获取用户名 -> 调用 `LoginAttemptService.loginFailed(username)` -> `LoginAttemptService` 使用 `Caffeine` 缓存 `attemptsCache` 来记录失败次数。每次失败,计数器加一。
|
||||
- **锁定逻辑**: `LoginAttemptService` 的 `isBlocked(username)` 方法检查失败次数是否超过最大允许次数(如 `MAX_ATTEMPT = 5`)。在 `UserDetailsServiceImpl` 的 `loadUserByUsername` 方法的开头,会先调用 `loginAttemptService.isBlocked()`。如果用户已被锁定,则直接抛出 `LockedException`,阻止后续的数据库查询和密码比对,实现登录锁定。
|
||||
|
||||
#### D. A* 路径规划 (`PathfindingService`)
|
||||
- **流程**: `PathfindingController` 调用 `PathfindingService.findPath()` -> `PathfindingService` 初始化一个 `Grid` 对象,该对象包含地图的宽度、高度和障碍物位置集合 -> A* 算法的核心 `AStar.findPath()` 被调用,它接收 `Grid` 和起止点 `Node` 作为参数 -> 算法内部使用 `PriorityQueue` 作为开放列表(优先处理f值最低的节点),使用 `HashSet` 作为关闭列表 -> 循环开始:从开放列表取出当前节点,若为终点则通过 `retracePath` 回溯构建路径 -> 否则,遍历当前节点的邻居节点,计算其 g值(到起点的代价)和 h值(到终点的预估代价,即启发式函数),若邻居节点是更优路径,则更新其代价和父节点,并加入开放列表。
|
||||
- **关键点**:
|
||||
- **数据结构**: `Node` 对象包含了坐标、g/h/f代价值、父节点引用和是否为障碍物等信息。
|
||||
- **启发式函数**: 使用曼哈顿距离 `getDistance(nodeA, nodeB)` 作为启发式函数,适用于网格地图。
|
||||
- **可扩展性**: `Grid` 可以从数据库、文件或动态生成,使得路径规划可以适应不同的地图场景。
|
||||
|
||||
## 四、配置模块详细解析
|
||||
|
||||
配置模块(`com.dne.ems.config`)是EMS系统的基础设施核心,为整个应用提供了完整的配置支持和初始化功能。本节将详细解析各个配置组件的功能、实现原理和使用方式。
|
||||
|
||||
### 4.1 数据初始化配置 (`DataInitializer.java`)
|
||||
|
||||
#### 功能概述
|
||||
`DataInitializer` 是系统启动时的数据初始化组件,实现了 `CommandLineRunner` 接口,确保在Spring Boot应用完全启动后自动执行数据初始化逻辑。
|
||||
|
||||
#### 核心特性
|
||||
- **自动执行**: 实现 `CommandLineRunner` 接口,在应用启动后自动运行
|
||||
- **幂等性**: 检查数据是否已存在,避免重复创建
|
||||
- **完整性**: 创建系统运行所需的所有基础数据
|
||||
- **日志记录**: 包含详细的初始化过程日志
|
||||
|
||||
#### 初始化内容详解
|
||||
|
||||
**1. 用户账户初始化**
|
||||
- 创建五种角色的测试账户:管理员、网格员、决策者、主管、公众监督员
|
||||
- 使用BCrypt加密存储密码
|
||||
- 为每个角色分配相应的权限和属性
|
||||
|
||||
**默认账户信息**:
|
||||
```
|
||||
管理员: admin@aizhangz.top / Admin@123
|
||||
网格员: worker@aizhangz.top / Worker@123
|
||||
决策者: decision.maker@aizhangz.top / Decision@123
|
||||
主管: supervisor@aizhangz.top / Supervisor@123
|
||||
公众监督员: public.supervisor@aizhangz.top / Public@123
|
||||
```
|
||||
|
||||
**2. 网格数据初始化**
|
||||
- 生成40x40的完整城市网格系统
|
||||
- 覆盖4个主要城市:常州市、无锡市、苏州市、南京市
|
||||
- 每个网格单元包含坐标、城市归属、区域信息
|
||||
- 支持网格员分配和区域管理
|
||||
|
||||
**3. 地图网格同步**
|
||||
- 将业务网格数据同步到寻路网格
|
||||
- 支持A*寻路算法的地图表示
|
||||
- 处理障碍物和可通行区域的标记
|
||||
|
||||
**4. AQI数据初始化**
|
||||
- 创建空气质量指数的历史数据
|
||||
- 生成实时AQI监测数据
|
||||
- 为数据可视化和分析提供基础数据
|
||||
|
||||
**5. 反馈和任务数据**
|
||||
- 创建示例环境问题反馈
|
||||
- 初始化任务分配记录
|
||||
- 建立完整的业务流程测试数据
|
||||
|
||||
#### 技术实现要点
|
||||
```java
|
||||
@Component
|
||||
@Slf4j
|
||||
public class DataInitializer implements CommandLineRunner {
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
// 检查数据是否已初始化
|
||||
if (isDataAlreadyInitialized()) {
|
||||
log.info("数据已初始化,跳过初始化过程");
|
||||
return;
|
||||
}
|
||||
|
||||
// 执行各项初始化
|
||||
initializeUsers();
|
||||
initializeGrids();
|
||||
initializeAqiData();
|
||||
initializeFeedbacks();
|
||||
initializeTasks();
|
||||
|
||||
log.info("数据初始化完成");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 文件存储配置 (`FileStorageProperties.java`)
|
||||
|
||||
#### 功能概述
|
||||
`FileStorageProperties` 管理文件上传存储的相关配置,使用Spring Boot的配置属性绑定机制。
|
||||
|
||||
#### 配置属性
|
||||
- `file.upload-dir`: 指定上传文件的存储目录
|
||||
- 支持相对路径和绝对路径
|
||||
- 可通过环境变量或配置文件动态配置
|
||||
|
||||
#### 使用方式
|
||||
**application.yml配置示例**:
|
||||
```yaml
|
||||
file:
|
||||
upload-dir: ./uploads
|
||||
# 或使用绝对路径
|
||||
# upload-dir: /var/app/uploads
|
||||
```
|
||||
|
||||
**Java配置类**:
|
||||
```java
|
||||
@ConfigurationProperties(prefix = "file")
|
||||
@Data
|
||||
public class FileStorageProperties {
|
||||
private String uploadDir;
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 OpenAPI配置 (`OpenApiConfig.java`)
|
||||
|
||||
#### 功能概述
|
||||
配置Swagger API文档和JWT认证,为开发和测试提供完整的API文档界面。
|
||||
|
||||
#### 主要特性
|
||||
- **API文档生成**: 自动生成完整的REST API文档
|
||||
- **JWT认证集成**: 支持在Swagger UI中进行JWT认证测试
|
||||
- **安全配置**: 为所有API端点添加安全要求
|
||||
- **在线测试**: 提供交互式API测试界面
|
||||
|
||||
#### 访问方式
|
||||
- Swagger UI: `http://localhost:8080/swagger-ui.html`
|
||||
- API文档JSON: `http://localhost:8080/v3/api-docs`
|
||||
|
||||
#### 安全配置详解
|
||||
```java
|
||||
@Configuration
|
||||
public class OpenApiConfig {
|
||||
|
||||
@Bean
|
||||
public OpenAPI customOpenAPI() {
|
||||
return new OpenAPI()
|
||||
.info(new Info()
|
||||
.title("EMS API")
|
||||
.version("1.0")
|
||||
.description("环境监测系统API文档"))
|
||||
.addSecurityItem(new SecurityRequirement().addList("Bearer Authentication"))
|
||||
.components(new Components()
|
||||
.addSecuritySchemes("Bearer Authentication",
|
||||
new SecurityScheme()
|
||||
.type(SecurityScheme.Type.HTTP)
|
||||
.scheme("bearer")
|
||||
.bearerFormat("JWT")));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 RestTemplate配置 (`RestTemplateConfig.java`)
|
||||
|
||||
#### 功能概述
|
||||
提供HTTP客户端功能,用于与外部服务进行同步通信。
|
||||
|
||||
#### 主要用途
|
||||
- **外部API集成**: 调用第三方服务API
|
||||
- **微服务通信**: 在分布式架构中进行服务间调用
|
||||
- **数据同步**: 从外部数据源获取信息
|
||||
- **第三方认证**: 集成外部认证服务
|
||||
|
||||
#### 配置示例
|
||||
```java
|
||||
@Configuration
|
||||
public class RestTemplateConfig {
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate() {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
// 配置连接超时和读取超时
|
||||
HttpComponentsClientHttpRequestFactory factory =
|
||||
new HttpComponentsClientHttpRequestFactory();
|
||||
factory.setConnectTimeout(5000);
|
||||
factory.setReadTimeout(10000);
|
||||
restTemplate.setRequestFactory(factory);
|
||||
|
||||
return restTemplate;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
```java
|
||||
@Service
|
||||
public class ExternalApiService {
|
||||
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
public String callExternalApi(String url) {
|
||||
return restTemplate.getForObject(url, String.class);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.5 WebClient配置 (`WebClientConfig.java`)
|
||||
|
||||
#### 功能概述
|
||||
提供响应式HTTP客户端功能,支持非阻塞I/O操作,适用于高并发场景。
|
||||
|
||||
#### 主要优势
|
||||
- **非阻塞I/O**: 提高系统吞吐量和响应性能
|
||||
- **响应式编程**: 支持Reactor响应式编程模型
|
||||
- **流式处理**: 支持数据流的实时处理
|
||||
- **背压处理**: 自动处理生产者和消费者速度不匹配的情况
|
||||
|
||||
#### 配置示例
|
||||
```java
|
||||
@Configuration
|
||||
public class WebClientConfig {
|
||||
|
||||
@Bean
|
||||
public WebClient webClient() {
|
||||
return WebClient.builder()
|
||||
.codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(2 * 1024 * 1024))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WebClient.Builder webClientBuilder() {
|
||||
return WebClient.builder();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
```java
|
||||
@Service
|
||||
public class ReactiveApiService {
|
||||
|
||||
@Autowired
|
||||
private WebClient webClient;
|
||||
|
||||
public Mono<String> callApiAsync(String url) {
|
||||
return webClient.get()
|
||||
.uri(url)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.6 WebSocket配置 (`WebSocketConfig.java`)
|
||||
|
||||
#### 功能概述
|
||||
WebSocket通信配置,为实时通信功能预留扩展空间。
|
||||
|
||||
#### 预期用途
|
||||
- **实时通知**: 任务状态变更的实时推送
|
||||
- **在线协作**: 多用户协同操作
|
||||
- **实时监控**: 系统状态和数据的实时更新
|
||||
- **即时消息**: 用户间的即时通信
|
||||
|
||||
#### 扩展示例
|
||||
```java
|
||||
@Configuration
|
||||
@EnableWebSocket
|
||||
public class WebSocketConfig implements WebSocketConfigurer {
|
||||
|
||||
@Override
|
||||
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
||||
registry.addHandler(new NotificationWebSocketHandler(), "/ws/notifications")
|
||||
.setAllowedOrigins("*");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.7 字符串列表转换器 (`StringListConverter.java`)
|
||||
|
||||
#### 功能概述
|
||||
JPA实体属性转换器,用于在数据库存储和Java对象之间转换字符串列表。
|
||||
|
||||
#### 主要特性
|
||||
- **类型转换**: `List<String>` ↔ JSON字符串
|
||||
- **JSON序列化**: 使用Jackson ObjectMapper
|
||||
- **空值处理**: 支持null和空列表的正确处理
|
||||
- **异常处理**: 包含完整的错误处理和日志记录
|
||||
|
||||
#### 实现原理
|
||||
```java
|
||||
@Converter
|
||||
public class StringListConverter implements AttributeConverter<List<String>, String> {
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
@Override
|
||||
public String convertToDatabaseColumn(List<String> attribute) {
|
||||
if (attribute == null || attribute.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return objectMapper.writeValueAsString(attribute);
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("转换List<String>到JSON失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> convertToEntityAttribute(String dbData) {
|
||||
if (dbData == null || dbData.trim().isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
try {
|
||||
return objectMapper.readValue(dbData,
|
||||
new TypeReference<List<String>>() {});
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("转换JSON到List<String>失败", e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 使用示例
|
||||
```java
|
||||
@Entity
|
||||
public class UserAccount {
|
||||
|
||||
@Convert(converter = StringListConverter.class)
|
||||
@Column(name = "skills", columnDefinition = "TEXT")
|
||||
private List<String> skills;
|
||||
|
||||
@Convert(converter = StringListConverter.class)
|
||||
@Column(name = "tags", columnDefinition = "TEXT")
|
||||
private List<String> tags;
|
||||
}
|
||||
```
|
||||
|
||||
### 4.8 配置模块最佳实践
|
||||
|
||||
#### 1. 配置外部化
|
||||
- 使用`@ConfigurationProperties`进行类型安全的配置绑定
|
||||
- 支持多环境配置(dev、test、prod)
|
||||
- 使用配置验证确保配置的正确性
|
||||
|
||||
#### 2. 安全考虑
|
||||
- 敏感配置信息使用环境变量或加密存储
|
||||
- API密钥和数据库密码不硬编码
|
||||
- 文件上传路径的安全验证
|
||||
|
||||
#### 3. 性能优化
|
||||
- HTTP客户端连接池配置
|
||||
- 合理设置超时时间
|
||||
- 缓存配置的优化
|
||||
|
||||
#### 4. 监控和日志
|
||||
- 配置变更的审计日志
|
||||
- 初始化过程的详细记录
|
||||
- 配置加载失败的错误处理
|
||||
|
||||
### 4.9 配置模块总结
|
||||
|
||||
配置模块为EMS系统提供了完整的基础设施支持:
|
||||
|
||||
1. **数据初始化**: 确保系统启动时具备完整的测试数据和基础配置
|
||||
2. **文件管理**: 提供灵活的文件存储配置和管理机制
|
||||
3. **API文档**: 支持完整的接口文档生成和在线测试
|
||||
4. **HTTP客户端**: 提供同步和异步的外部服务调用能力
|
||||
5. **数据转换**: 支持复杂数据类型的数据库存储转换
|
||||
|
||||
## 五、控制器模块详细解析
|
||||
|
||||
控制器模块(`com.dne.ems.controller`)是EMS系统的API入口层,负责处理所有HTTP请求并提供RESTful API接口。该模块包含14个专业化控制器,每个控制器专注于特定的业务领域,形成了完整的API生态系统。
|
||||
|
||||
### 5.1 认证控制器 (`AuthController.java`)
|
||||
|
||||
#### 功能概述
|
||||
认证控制器负责用户身份验证和账户管理的核心功能,是系统安全的第一道防线。
|
||||
|
||||
#### 主要接口
|
||||
- **用户注册** (`POST /api/auth/signup`): 新用户账户创建
|
||||
- **用户登录** (`POST /api/auth/login`): 用户身份验证,返回JWT令牌
|
||||
- **发送验证码** (`POST /api/auth/send-verification-code`): 注册验证码发送
|
||||
- **密码重置** (`POST /api/auth/send-password-reset-code`): 密码重置验证码发送
|
||||
- **验证码重置密码** (`POST /api/auth/reset-password-with-code`): 使用验证码重置密码
|
||||
|
||||
#### 核心特性
|
||||
- **JWT令牌管理**: 生成和验证JSON Web Token
|
||||
- **邮箱验证**: 支持邮箱验证码验证机制
|
||||
- **密码安全**: 多种密码重置方式,确保账户安全
|
||||
- **参数验证**: 使用Bean Validation进行请求参数校验
|
||||
|
||||
#### 代码示例
|
||||
```java
|
||||
@PostMapping("/login")
|
||||
public ResponseEntity<JwtAuthenticationResponse> signIn(@Valid @RequestBody LoginRequest request) {
|
||||
return ResponseEntity.ok(authService.signIn(request));
|
||||
}
|
||||
|
||||
@PostMapping("/send-verification-code")
|
||||
public ResponseEntity<Void> sendVerificationCode(@RequestParam @NotBlank @Email String email) {
|
||||
verificationCodeService.sendVerificationCode(email);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 仪表盘控制器 (`DashboardController.java`)
|
||||
|
||||
#### 功能概述
|
||||
仪表盘控制器为决策者和管理员提供全面的数据可视化和统计分析功能,是数据驱动决策的核心支撑。
|
||||
|
||||
#### 主要接口
|
||||
- **核心统计数据** (`GET /api/dashboard/stats`): 系统关键指标统计
|
||||
- **AQI分布数据** (`GET /api/dashboard/reports/aqi-distribution`): 空气质量指数分布
|
||||
- **月度超标趋势** (`GET /api/dashboard/reports/monthly-exceedance-trend`): 污染超标趋势分析
|
||||
- **网格覆盖率** (`GET /api/dashboard/reports/grid-coverage`): 各城市网格覆盖情况
|
||||
- **反馈热力图** (`GET /api/dashboard/map/heatmap`): 反馈分布热力图数据
|
||||
- **污染物统计** (`GET /api/dashboard/reports/pollution-stats`): 各类污染物统计
|
||||
- **任务完成统计** (`GET /api/dashboard/reports/task-completion-stats`): 任务执行效率统计
|
||||
- **AQI热力图** (`GET /api/dashboard/map/aqi-heatmap`): AQI分布热力图
|
||||
- **污染物阈值管理** (`GET /api/dashboard/thresholds`): 污染物阈值配置
|
||||
|
||||
#### 权限控制
|
||||
```java
|
||||
@PreAuthorize("hasAnyRole('DECISION_MAKER', 'ADMIN')")
|
||||
public ResponseEntity<DashboardStatsDTO> getDashboardStats() {
|
||||
// 仅决策者和管理员可访问
|
||||
}
|
||||
```
|
||||
|
||||
#### 数据可视化支持
|
||||
- **多维度统计**: 支持时间、地域、类型等多维度数据分析
|
||||
- **实时数据**: 提供实时更新的环境监测数据
|
||||
- **热力图数据**: 支持地理信息系统(GIS)的数据可视化
|
||||
- **趋势分析**: 历史数据趋势和预测分析
|
||||
|
||||
### 5.3 反馈控制器 (`FeedbackController.java`)
|
||||
|
||||
#### 功能概述
|
||||
反馈控制器处理公众环境问题反馈的全生命周期管理,是公众参与环境治理的重要渠道。
|
||||
|
||||
#### 主要接口
|
||||
- **提交反馈** (`POST /api/feedback/submit`): 支持文件上传的反馈提交
|
||||
- **JSON格式提交** (`POST /api/feedback/submit-json`): 测试用的JSON格式提交
|
||||
- **获取反馈列表** (`GET /api/feedback`): 支持多条件过滤的分页查询
|
||||
- **反馈详情** (`GET /api/feedback/{id}`): 获取特定反馈的详细信息
|
||||
- **反馈统计** (`GET /api/feedback/stats`): 反馈数据统计分析
|
||||
|
||||
#### 高级查询功能
|
||||
```java
|
||||
@GetMapping
|
||||
public ResponseEntity<Page<FeedbackResponseDTO>> getAllFeedback(
|
||||
@AuthenticationPrincipal CustomUserDetails userDetails,
|
||||
@RequestParam(required = false) FeedbackStatus status,
|
||||
@RequestParam(required = false) PollutionType pollutionType,
|
||||
@RequestParam(required = false) SeverityLevel severityLevel,
|
||||
@RequestParam(required = false) String cityName,
|
||||
@RequestParam(required = false) String districtName,
|
||||
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
|
||||
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate,
|
||||
@RequestParam(required = false) String keyword,
|
||||
Pageable pageable) {
|
||||
// 支持多维度过滤查询
|
||||
}
|
||||
```
|
||||
|
||||
#### 文件上传支持
|
||||
- **多文件上传**: 支持同时上传多个附件文件
|
||||
- **文件类型验证**: 限制上传文件的类型和大小
|
||||
- **安全存储**: 文件安全存储和访问控制
|
||||
|
||||
### 5.4 文件控制器 (`FileController.java`)
|
||||
|
||||
#### 功能概述
|
||||
文件控制器提供文件下载和在线预览功能,支持系统中所有文件资源的访问管理。
|
||||
|
||||
#### 主要接口
|
||||
- **文件下载** (`GET /api/files/{filename}`): 文件下载功能
|
||||
- **文件预览** (`GET /api/view/{fileName}`): 在线文件预览
|
||||
|
||||
#### 技术特性
|
||||
- **MIME类型检测**: 自动检测文件类型并设置正确的Content-Type
|
||||
- **安全下载**: 防止路径遍历攻击
|
||||
- **流式传输**: 支持大文件的流式下载
|
||||
|
||||
#### 实现示例
|
||||
```java
|
||||
@GetMapping("/files/{filename:.+}")
|
||||
public ResponseEntity<Resource> downloadFile(@PathVariable String filename, HttpServletRequest request) {
|
||||
Resource resource = fileStorageService.loadFileAsResource(filename);
|
||||
|
||||
String contentType = null;
|
||||
try {
|
||||
contentType = request.getServletContext().getMimeType(resource.getFile().getAbsolutePath());
|
||||
} catch (IOException ex) {
|
||||
logger.info("Could not determine file type.");
|
||||
}
|
||||
|
||||
if (contentType == null) {
|
||||
contentType = "application/octet-stream";
|
||||
}
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.contentType(MediaType.parseMediaType(contentType))
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + resource.getFilename() + "\"")
|
||||
.body(resource);
|
||||
}
|
||||
```
|
||||
|
||||
### 5.5 网格控制器 (`GridController.java`)
|
||||
|
||||
#### 功能概述
|
||||
网格控制器负责城市网格化管理,包括网格数据维护和网格员分配管理。
|
||||
|
||||
#### 主要接口
|
||||
- **网格列表** (`GET /api/grids`): 获取所有网格信息
|
||||
- **更新网格** (`PATCH /api/grids/{id}`): 更新网格信息
|
||||
- **网格覆盖率** (`GET /api/grids/coverage`): 网格覆盖率统计
|
||||
- **分配网格员** (`POST /api/grids/{gridId}/assign`): 将网格员分配到指定网格
|
||||
- **移除网格员** (`POST /api/grids/{gridId}/unassign`): 从网格中移除网格员
|
||||
- **坐标分配** (`POST /api/grids/coordinates/{gridX}/{gridY}/assign`): 通过坐标分配网格员
|
||||
|
||||
#### 网格员管理
|
||||
```java
|
||||
@PostMapping("/{gridId}/assign")
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public ResponseEntity<?> assignGridWorker(
|
||||
@PathVariable Long gridId,
|
||||
@RequestBody Map<String, Long> request) {
|
||||
Long userId = request.get("userId");
|
||||
|
||||
// 验证用户角色
|
||||
if (user.getRole() != Role.GRID_WORKER) {
|
||||
return ResponseEntity.badRequest().body("只能分配网格员角色的用户");
|
||||
}
|
||||
|
||||
// 分配网格坐标
|
||||
user.setGridX(grid.getGridX());
|
||||
user.setGridY(grid.getGridY());
|
||||
userAccountRepository.save(user);
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
```
|
||||
|
||||
### 5.6 网格员任务控制器 (`GridWorkerTaskController.java`)
|
||||
|
||||
#### 功能概述
|
||||
专为网格员设计的任务管理控制器,提供任务接收、处理和提交的完整工作流程。
|
||||
|
||||
#### 主要接口
|
||||
- **我的任务** (`GET /api/worker`): 获取分配给当前网格员的任务列表
|
||||
- **接受任务** (`POST /api/worker/{taskId}/accept`): 接受指定任务
|
||||
- **提交任务** (`POST /api/worker/{taskId}/submit`): 提交任务完成情况
|
||||
- **任务详情** (`GET /api/worker/{taskId}`): 查看任务详细信息
|
||||
|
||||
#### 权限控制
|
||||
```java
|
||||
@RestController
|
||||
@RequestMapping("/api/worker")
|
||||
@RequiredArgsConstructor
|
||||
@PreAuthorize("hasRole('GRID_WORKER')")
|
||||
public class GridWorkerTaskController {
|
||||
// 整个控制器仅限网格员角色访问
|
||||
}
|
||||
```
|
||||
|
||||
#### 任务提交功能
|
||||
```java
|
||||
@PostMapping(value = "/{taskId}/submit", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
public ResponseEntity<TaskSummaryDTO> submitTask(
|
||||
@PathVariable Long taskId,
|
||||
@RequestPart("comments") @Valid String comments,
|
||||
@RequestPart(value = "files", required = false) List<MultipartFile> files,
|
||||
@AuthenticationPrincipal CustomUserDetails userDetails) {
|
||||
// 支持文件上传的任务提交
|
||||
}
|
||||
```
|
||||
|
||||
### 5.7 地图控制器 (`MapController.java`)
|
||||
|
||||
#### 功能概述
|
||||
地图控制器管理系统的地图网格数据,为路径规划和地理信息展示提供基础数据支持。
|
||||
|
||||
#### 主要接口
|
||||
- **获取地图** (`GET /api/map/grid`): 获取完整的地图网格数据
|
||||
- **更新网格** (`POST /api/map/grid`): 创建或更新地图网格单元
|
||||
- **初始化地图** (`POST /api/map/initialize`): 初始化指定大小的地图
|
||||
|
||||
#### 地图初始化
|
||||
```java
|
||||
@PostMapping("/initialize")
|
||||
@Transactional
|
||||
public ResponseEntity<String> initializeMap(
|
||||
@RequestParam(defaultValue = "20") int width,
|
||||
@RequestParam(defaultValue = "20") int height) {
|
||||
|
||||
mapGridRepository.deleteAll();
|
||||
mapGridRepository.flush();
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
MapGrid cell = MapGrid.builder()
|
||||
.x(x)
|
||||
.y(y)
|
||||
.isObstacle(false)
|
||||
.terrainType("ground")
|
||||
.build();
|
||||
mapGridRepository.save(cell);
|
||||
}
|
||||
}
|
||||
return ResponseEntity.ok("Initialized a " + width + "x" + height + " map.");
|
||||
}
|
||||
```
|
||||
|
||||
### 5.8 路径规划控制器 (`PathfindingController.java`)
|
||||
|
||||
#### 功能概述
|
||||
路径规划控制器提供A*寻路算法功能,为网格员提供最优路径导航服务。
|
||||
|
||||
#### 主要接口
|
||||
- **路径查找** (`POST /api/pathfinding/find`): 计算两点之间的最优路径
|
||||
|
||||
#### A*算法实现
|
||||
```java
|
||||
@PostMapping("/find")
|
||||
public ResponseEntity<List<Point>> findPath(@RequestBody PathfindingRequest request) {
|
||||
if (request == null) {
|
||||
return ResponseEntity.badRequest().build();
|
||||
}
|
||||
Point start = new Point(request.getStartX(), request.getStartY());
|
||||
Point end = new Point(request.getEndX(), request.getEndY());
|
||||
|
||||
List<Point> path = aStarService.findPath(start, end);
|
||||
return ResponseEntity.ok(path);
|
||||
}
|
||||
```
|
||||
|
||||
#### 算法特性
|
||||
- **障碍物避让**: 考虑地图中的障碍物
|
||||
- **最优路径**: 计算距离最短的路径
|
||||
- **实时计算**: 快速响应路径查询请求
|
||||
|
||||
### 5.9 人员管理控制器 (`PersonnelController.java`)
|
||||
|
||||
#### 功能概述
|
||||
人员管理控制器提供用户账号的完整生命周期管理,包括创建、查询、更新和删除操作。
|
||||
|
||||
#### 主要接口
|
||||
- **创建用户** (`POST /api/personnel/users`): 创建新用户账号
|
||||
- **用户列表** (`GET /api/personnel/users`): 分页查询用户列表
|
||||
- **用户详情** (`GET /api/personnel/users/{userId}`): 获取用户详细信息
|
||||
- **更新用户** (`PATCH /api/personnel/users/{userId}`): 更新用户信息
|
||||
- **更新角色** (`PUT /api/personnel/users/{userId}/role`): 更新用户角色
|
||||
- **删除用户** (`DELETE /api/personnel/users/{userId}`): 删除用户账号
|
||||
|
||||
#### 权限控制
|
||||
```java
|
||||
@RestController
|
||||
@RequestMapping("/api/personnel")
|
||||
@RequiredArgsConstructor
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public class PersonnelController {
|
||||
// 仅管理员可访问人员管理功能
|
||||
}
|
||||
```
|
||||
|
||||
#### 高级查询
|
||||
```java
|
||||
@GetMapping("/users")
|
||||
@PreAuthorize("hasRole('ADMIN') or hasRole('GRID_WORKER')")
|
||||
public ResponseEntity<PageDTO<UserAccount>> getUsers(
|
||||
@RequestParam(required = false) Role role,
|
||||
@RequestParam(required = false) String name,
|
||||
Pageable pageable) {
|
||||
// 支持按角色和姓名过滤的分页查询
|
||||
}
|
||||
```
|
||||
|
||||
### 5.10 个人资料控制器 (`ProfileController.java`)
|
||||
|
||||
#### 功能概述
|
||||
个人资料控制器处理认证用户的个人数据管理,提供用户自助服务功能。
|
||||
|
||||
#### 主要接口
|
||||
- **反馈历史** (`GET /api/me/feedback`): 获取当前用户的反馈提交历史
|
||||
|
||||
#### 用户数据隔离
|
||||
```java
|
||||
@GetMapping("/feedback")
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
public ResponseEntity<List<UserFeedbackSummaryDTO>> getMyFeedbackHistory(
|
||||
@AuthenticationPrincipal CustomUserDetails userDetails,
|
||||
Pageable pageable) {
|
||||
// 仅返回当前用户的数据
|
||||
Page<UserFeedbackSummaryDTO> historyPage = userFeedbackService
|
||||
.getFeedbackHistoryByUserId(userDetails.getId(), pageable);
|
||||
return ResponseEntity.ok(historyPage.getContent());
|
||||
}
|
||||
```
|
||||
|
||||
### 5.11 公共接口控制器 (`PublicController.java`)
|
||||
|
||||
#### 功能概述
|
||||
公共接口控制器提供无需认证的公共API,主要服务于匿名用户的反馈提交。
|
||||
|
||||
#### 主要接口
|
||||
- **公共反馈提交** (`POST /api/public/feedback`): 支持匿名用户提交环境问题反馈
|
||||
|
||||
#### 匿名访问支持
|
||||
```java
|
||||
@PostMapping(value = "/feedback", consumes = "multipart/form-data")
|
||||
public ResponseEntity<Feedback> submitPublicFeedback(
|
||||
@Valid @RequestPart("feedback") PublicFeedbackRequest request,
|
||||
@RequestPart(value = "files", required = false) MultipartFile[] files) {
|
||||
// 无需认证即可提交反馈
|
||||
Feedback createdFeedback = feedbackService.createPublicFeedback(request, files);
|
||||
return new ResponseEntity<>(createdFeedback, HttpStatus.CREATED);
|
||||
}
|
||||
```
|
||||
|
||||
### 5.12 主管控制器 (`SupervisorController.java`)
|
||||
|
||||
#### 功能概述
|
||||
主管控制器专为主管角色设计,提供反馈审核和管理功能。
|
||||
|
||||
#### 主要接口
|
||||
- **待审核反馈** (`GET /api/supervisor/reviews`): 获取待审核的反馈列表
|
||||
- **审核通过** (`POST /api/supervisor/reviews/{feedbackId}/approve`): 审核通过反馈
|
||||
- **审核拒绝** (`POST /api/supervisor/reviews/{feedbackId}/reject`): 审核拒绝反馈
|
||||
|
||||
#### 审核流程
|
||||
```java
|
||||
@PostMapping("/reviews/{feedbackId}/approve")
|
||||
@PreAuthorize("hasAnyRole('SUPERVISOR', 'ADMIN')")
|
||||
public ResponseEntity<Void> approveFeedback(@PathVariable Long feedbackId) {
|
||||
supervisorService.approveFeedback(feedbackId);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@PostMapping("/reviews/{feedbackId}/reject")
|
||||
@PreAuthorize("hasAnyRole('SUPERVISOR', 'ADMIN')")
|
||||
public ResponseEntity<Void> rejectFeedback(
|
||||
@PathVariable Long feedbackId,
|
||||
@RequestBody RejectFeedbackRequest request) {
|
||||
supervisorService.rejectFeedback(feedbackId, request);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
```
|
||||
|
||||
### 5.13 任务分配控制器 (`TaskAssignmentController.java`)
|
||||
|
||||
#### 功能概述
|
||||
任务分配控制器处理任务的智能分配和人员调度功能。
|
||||
|
||||
#### 主要接口
|
||||
- **未分配任务** (`GET /api/tasks/unassigned`): 获取未分配的任务列表
|
||||
- **可用网格员** (`GET /api/tasks/grid-workers`): 获取可用的网格工作人员
|
||||
- **分配任务** (`POST /api/tasks/assign`): 将任务分配给指定工作人员
|
||||
|
||||
#### 智能分配
|
||||
```java
|
||||
@PostMapping("/assign")
|
||||
@PreAuthorize("hasAnyRole('ADMIN', 'SUPERVISOR')")
|
||||
public ResponseEntity<Assignment> assignTask(
|
||||
@RequestBody AssignmentRequest request,
|
||||
@AuthenticationPrincipal CustomUserDetails adminDetails) {
|
||||
|
||||
Long assignerId = adminDetails.getId();
|
||||
Assignment newAssignment = taskAssignmentService.assignTask(
|
||||
request.feedbackId(),
|
||||
request.assigneeId(),
|
||||
assignerId
|
||||
);
|
||||
return ResponseEntity.ok(newAssignment);
|
||||
}
|
||||
```
|
||||
|
||||
### 5.14 任务管理控制器 (`TaskManagementController.java`)
|
||||
|
||||
#### 功能概述
|
||||
任务管理控制器提供任务全生命周期的管理功能,是任务管理的核心控制器。
|
||||
|
||||
#### 主要接口
|
||||
- **任务列表** (`GET /api/management/tasks`): 支持多条件过滤的任务分页查询
|
||||
- **分配任务** (`POST /api/management/tasks/{taskId}/assign`): 分配任务给工作人员
|
||||
- **任务详情** (`GET /api/management/tasks/{taskId}`): 获取任务详细信息
|
||||
- **审核任务** (`POST /api/management/tasks/{taskId}/review`): 审核任务完成情况
|
||||
- **取消任务** (`POST /api/management/tasks/{taskId}/cancel`): 取消任务
|
||||
- **创建任务** (`POST /api/management/tasks`): 创建新任务
|
||||
- **待处理反馈** (`GET /api/management/tasks/feedback`): 获取待处理的反馈
|
||||
- **从反馈创建任务** (`POST /api/management/tasks/feedback/{feedbackId}/create-task`): 从反馈创建任务
|
||||
|
||||
#### 高级过滤查询
|
||||
```java
|
||||
@GetMapping
|
||||
@PreAuthorize("hasAnyAuthority('ADMIN', 'SUPERVISOR', 'DECISION_MAKER')")
|
||||
public ResponseEntity<List<TaskSummaryDTO>> getTasks(
|
||||
@RequestParam(required = false) TaskStatus status,
|
||||
@RequestParam(required = false) Long assigneeId,
|
||||
@RequestParam(required = false) SeverityLevel severity,
|
||||
@RequestParam(required = false) PollutionType pollutionType,
|
||||
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
|
||||
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate,
|
||||
Pageable pageable) {
|
||||
// 支持多维度过滤的任务查询
|
||||
}
|
||||
```
|
||||
|
||||
#### 任务状态流转
|
||||
```java
|
||||
@PostMapping("/{taskId}/review")
|
||||
public ResponseEntity<TaskDetailDTO> reviewTask(
|
||||
@PathVariable Long taskId,
|
||||
@RequestBody @Valid TaskApprovalRequest request) {
|
||||
TaskDetailDTO updatedTask = taskManagementService.reviewTask(taskId, request);
|
||||
return ResponseEntity.ok(updatedTask);
|
||||
}
|
||||
|
||||
@PostMapping("/{taskId}/cancel")
|
||||
public ResponseEntity<TaskDetailDTO> cancelTask(@PathVariable Long taskId) {
|
||||
TaskDetailDTO updatedTask = taskManagementService.cancelTask(taskId);
|
||||
return ResponseEntity.ok(updatedTask);
|
||||
}
|
||||
```
|
||||
|
||||
### 5.15 控制器模块最佳实践
|
||||
|
||||
#### 1. RESTful API设计
|
||||
- **统一的URL命名规范**: 使用名词复数形式,避免动词
|
||||
- **HTTP方法语义化**: GET查询、POST创建、PUT/PATCH更新、DELETE删除
|
||||
- **状态码规范**: 正确使用HTTP状态码表达操作结果
|
||||
- **版本控制**: 通过URL路径进行API版本管理
|
||||
|
||||
#### 2. 安全控制
|
||||
- **细粒度权限控制**: 使用`@PreAuthorize`进行方法级权限控制
|
||||
- **输入验证**: 使用Bean Validation进行参数校验
|
||||
- **敏感数据保护**: 避免在响应中暴露敏感信息(如密码)
|
||||
- **CSRF防护**: 对状态变更操作进行CSRF保护
|
||||
|
||||
#### 3. 异常处理
|
||||
- **全局异常处理**: 使用`@ControllerAdvice`统一处理异常
|
||||
- **友好错误信息**: 为客户端提供清晰的错误描述
|
||||
- **日志记录**: 记录详细的错误日志便于问题排查
|
||||
|
||||
#### 4. 性能优化
|
||||
- **分页查询**: 对大数据量查询使用分页机制
|
||||
- **缓存策略**: 对频繁查询的数据使用缓存
|
||||
- **异步处理**: 对耗时操作使用异步处理
|
||||
- **数据传输优化**: 使用DTO减少不必要的数据传输
|
||||
|
||||
#### 5. 文档和测试
|
||||
- **API文档**: 使用Swagger/OpenAPI生成完整的API文档
|
||||
- **单元测试**: 为每个控制器方法编写单元测试
|
||||
- **集成测试**: 测试完整的请求-响应流程
|
||||
- **性能测试**: 对关键接口进行性能测试
|
||||
|
||||
### 5.16 控制器模块总结
|
||||
|
||||
控制器模块为EMS系统提供了完整的API服务层:
|
||||
|
||||
1. **全面的功能覆盖**: 14个专业化控制器覆盖了系统的所有核心功能
|
||||
2. **严格的权限控制**: 基于角色的访问控制确保系统安全
|
||||
3. **灵活的查询支持**: 支持多维度过滤、分页、排序等高级查询功能
|
||||
4. **完善的文件处理**: 支持文件上传、下载、预览等文件操作
|
||||
5. **智能的任务管理**: 提供完整的任务生命周期管理和智能分配功能
|
||||
6. **实时的数据可视化**: 为决策支持提供丰富的数据分析接口
|
||||
7. **用户友好的接口设计**: 遵循RESTful设计原则,提供直观易用的API
|
||||
|
||||
通过这些控制器的协同工作,EMS系统能够为不同角色的用户提供专业化、个性化的服务,实现了从公众反馈到问题解决的完整业务闭环。
|
||||
6. **扩展性**: 为WebSocket等实时通信功能预留扩展空间
|
||||
|
||||
这些配置组件共同构成了一个健壮、可扩展、易维护的系统基础架构,为EMS系统的稳定运行和功能扩展提供了坚实的技术保障。
|
||||
|
||||
---
|
||||
|
||||
# DTO模块详细解析
|
||||
|
||||
## 概述
|
||||
|
||||
DTO(Data Transfer Object)模块位于 `com.dne.ems.dto` 包下,包含51个数据传输对象,负责在不同层之间传递数据,确保数据的封装性和安全性。DTO模块按功能分类,涵盖用户管理、任务管理、反馈处理、地图网格、统计分析和AI集成等核心业务领域。
|
||||
|
||||
## 核心功能分类
|
||||
|
||||
### 1. 用户管理相关DTO
|
||||
|
||||
#### 用户注册和认证
|
||||
- **SignUpRequest**: 用户注册请求,包含姓名、邮箱、手机、密码、角色和验证码
|
||||
- **LoginRequest**: 用户登录请求,封装邮箱和密码
|
||||
- **UserRegistrationRequest**: 公众用户注册请求,支持密码复杂度验证
|
||||
- **JwtAuthenticationResponse**: JWT认证响应,返回访问令牌
|
||||
|
||||
#### 用户信息管理
|
||||
- **UserCreationRequest**: 管理员创建用户请求,支持角色分配和区域设置
|
||||
- **UserUpdateRequest**: 用户信息更新请求,支持多字段批量更新
|
||||
- **UserRoleUpdateRequest**: 用户角色更新请求,网格员需要位置信息
|
||||
- **UserInfoDTO**: 用户基本信息传输对象,隐藏敏感数据
|
||||
- **UserSummaryDTO**: 用户摘要信息,用于列表展示
|
||||
|
||||
#### 密码管理
|
||||
- **PasswordResetRequest**: 密码重置邮件请求
|
||||
- **PasswordResetDto**: 通过令牌重置密码
|
||||
- **PasswordResetWithCodeDto**: 通过验证码重置密码
|
||||
|
||||
### 2. 任务管理相关DTO
|
||||
|
||||
#### 任务创建和分配
|
||||
- **TaskCreationRequest**: 任务创建请求,包含标题、描述、污染类型、严重级别和位置
|
||||
- **TaskAssignmentRequest**: 任务分配请求,指定受理人ID
|
||||
- **TaskFromFeedbackRequest**: 从反馈创建任务请求,设置严重级别
|
||||
|
||||
#### 任务处理和审核
|
||||
- **TaskSubmissionRequest**: 任务提交请求,包含处理意见
|
||||
- **TaskApprovalRequest**: 任务审核请求,支持通过或拒绝
|
||||
- **TaskRejectionRequest**: 任务拒绝请求,必须提供拒绝原因
|
||||
|
||||
#### 任务信息展示
|
||||
- **TaskDTO**: 任务基本信息,包含ID、标题、描述和状态
|
||||
- **TaskSummaryDTO**: 任务摘要信息,用于列表展示
|
||||
- **TaskDetailDTO**: 任务详细信息,包含完整的任务数据和历史记录
|
||||
- **TaskInfoDTO**: 任务简要信息,包含状态和受理人
|
||||
- **TaskHistoryDTO**: 任务历史记录,追踪状态变更
|
||||
- **TaskStatsDTO**: 任务统计数据,计算完成率
|
||||
|
||||
### 3. 反馈处理相关DTO
|
||||
|
||||
#### 反馈提交
|
||||
- **PublicFeedbackRequest**: 公众反馈提交请求,支持匿名提交
|
||||
- **FeedbackSubmissionRequest**: 反馈提交请求,包含位置和附件信息
|
||||
- **AqiDataSubmissionRequest**: AQI数据提交请求,专门处理空气质量数据
|
||||
|
||||
#### 反馈处理
|
||||
- **ProcessFeedbackRequest**: 反馈处理请求,支持批准或采取行动
|
||||
- **RejectFeedbackRequest**: 反馈拒绝请求,需要提供拒绝原因
|
||||
|
||||
#### 反馈信息展示
|
||||
- **FeedbackDTO**: 反馈详细信息传输对象
|
||||
- **FeedbackResponseDTO**: 反馈响应数据封装
|
||||
- **UserFeedbackSummaryDTO**: 用户反馈历史摘要
|
||||
- **FeedbackStatsResponse**: 反馈统计数据响应
|
||||
|
||||
### 4. 地图网格相关DTO
|
||||
|
||||
#### 网格管理
|
||||
- **GridUpdateRequest**: 网格属性更新请求
|
||||
- **GridAssignmentRequest**: 网格员分配请求
|
||||
- **GridCoverageDTO**: 网格覆盖统计数据
|
||||
- **CityBlueprint**: 城市网格蓝图生成
|
||||
|
||||
#### 位置和路径
|
||||
- **LocationUpdateRequest**: 用户位置更新请求
|
||||
- **PathfindingRequest**: A*路径查找请求,包含起点和终点
|
||||
- **Point**: 二维坐标点表示
|
||||
|
||||
### 5. 统计分析相关DTO
|
||||
|
||||
#### 仪表盘统计
|
||||
- **DashboardStatsDTO**: 仪表盘关键统计数据
|
||||
- **PollutionStatsDTO**: 污染物统计数据
|
||||
- **TrendDataPointDTO**: 趋势数据点,用于时间序列分析
|
||||
|
||||
#### 热力图数据
|
||||
- **HeatmapPointDTO**: 通用热力图数据点
|
||||
- **AqiHeatmapPointDTO**: AQI热力图专用数据点
|
||||
- **AqiDistributionDTO**: AQI分布统计数据
|
||||
- **PollutantThresholdDTO**: 污染物阈值信息
|
||||
|
||||
### 6. 通用工具DTO
|
||||
|
||||
#### 分页和响应
|
||||
- **PageDTO**: 分页查询结果封装,支持泛型
|
||||
- **ErrorResponseDTO**: API错误响应标准格式
|
||||
- **AttachmentDTO**: 附件信息封装
|
||||
- **AssigneeInfoDTO**: 任务受理人信息
|
||||
|
||||
### 7. AI集成相关DTO
|
||||
|
||||
#### 火山引擎AI聊天
|
||||
- **VolcanoChatRequest**: 火山引擎聊天API请求,支持多轮对话和工具调用
|
||||
- **VolcanoChatResponse**: 火山引擎聊天API响应,包含AI回复和工具调用结果
|
||||
|
||||
## 核心代码示例
|
||||
|
||||
### 任务创建请求DTO
|
||||
```java
|
||||
public record TaskCreationRequest(
|
||||
@NotBlank(message = "Title is mandatory")
|
||||
String title,
|
||||
String description,
|
||||
@NotNull(message = "Pollution type is mandatory")
|
||||
PollutionType pollutionType,
|
||||
@NotNull(message = "Severity level is mandatory")
|
||||
SeverityLevel severityLevel,
|
||||
@NotNull(message = "Location information is mandatory")
|
||||
LocationDTO location
|
||||
) {
|
||||
public record LocationDTO(
|
||||
@NotBlank(message = "Address is mandatory")
|
||||
String address,
|
||||
@NotNull(message = "Grid X coordinate is mandatory")
|
||||
Integer gridX,
|
||||
@NotNull(message = "Grid Y coordinate is mandatory")
|
||||
Integer gridY
|
||||
) {}
|
||||
}
|
||||
```
|
||||
|
||||
### 分页查询结果DTO
|
||||
```java
|
||||
public record PageDTO<T>(
|
||||
List<T> content,
|
||||
int page,
|
||||
int size,
|
||||
long totalElements,
|
||||
int totalPages,
|
||||
boolean first,
|
||||
boolean last
|
||||
) {
|
||||
public static <T> PageDTO<T> fromPage(Page<T> page) {
|
||||
return new PageDTO<>(
|
||||
page.getContent(),
|
||||
page.getNumber(),
|
||||
page.getSize(),
|
||||
page.getTotalElements(),
|
||||
page.getTotalPages(),
|
||||
page.isFirst(),
|
||||
page.isLast()
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 用户信息DTO工厂方法
|
||||
```java
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UserInfoDTO {
|
||||
private Long id;
|
||||
private String name;
|
||||
private String phone;
|
||||
private String email;
|
||||
|
||||
public static UserInfoDTO fromEntity(UserAccount user) {
|
||||
if (user == null) {
|
||||
return null;
|
||||
}
|
||||
return new UserInfoDTO(
|
||||
user.getId(),
|
||||
user.getName(),
|
||||
user.getPhone(),
|
||||
user.getEmail()
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### AI聊天请求DTO
|
||||
```java
|
||||
@Data
|
||||
@Builder
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class VolcanoChatRequest {
|
||||
private String model;
|
||||
private List<Message> messages;
|
||||
private List<Tool> tools;
|
||||
|
||||
@Data
|
||||
@SuperBuilder
|
||||
public static class Message {
|
||||
private String role;
|
||||
private List<ContentPart> content;
|
||||
}
|
||||
|
||||
@Data
|
||||
@SuperBuilder
|
||||
public static class ContentPart {
|
||||
private String type;
|
||||
private String text;
|
||||
@JsonProperty("image_url")
|
||||
private ImageUrl imageUrl;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 设计特点
|
||||
|
||||
### 1. 数据验证
|
||||
- 使用Jakarta Validation注解进行参数校验
|
||||
- 自定义验证注解(如@ValidPassword、@GridWorkerLocationRequired)
|
||||
- 分层验证策略,确保数据完整性
|
||||
|
||||
### 2. 类型安全
|
||||
- 大量使用Record类型,确保不可变性
|
||||
- 泛型支持,如PageDTO<T>提供类型安全的分页
|
||||
- 枚举类型约束,避免无效值
|
||||
|
||||
### 3. 序列化优化
|
||||
- Jackson注解配置,控制JSON序列化行为
|
||||
- @JsonInclude(JsonInclude.Include.NON_NULL)避免空值传输
|
||||
- @JsonProperty处理字段名映射
|
||||
|
||||
### 4. 业务语义
|
||||
- 清晰的命名约定,Request/Response/DTO后缀明确用途
|
||||
- 丰富的JavaDoc文档,说明业务规则和使用场景
|
||||
- 嵌套记录结构,体现数据层次关系
|
||||
|
||||
## DTO模块最佳实践
|
||||
|
||||
1. **不可变设计**:优先使用Record类型,确保数据传输对象的不可变性
|
||||
2. **验证完整性**:在DTO层进行数据验证,避免无效数据进入业务层
|
||||
3. **类型安全**:使用强类型和泛型,减少运行时错误
|
||||
4. **文档完善**:提供详细的JavaDoc,说明字段含义和业务规则
|
||||
5. **序列化优化**:合理使用Jackson注解,优化网络传输效率
|
||||
6. **分层隔离**:DTO与实体类分离,避免业务逻辑泄露到表示层
|
||||
|
||||
## DTO模块总结
|
||||
|
||||
DTO模块为EMS系统提供了完整的数据传输层:
|
||||
|
||||
1. **全面的功能覆盖**: 51个DTO类覆盖了系统的所有核心功能领域
|
||||
2. **严格的数据验证**: 多层次验证机制确保数据质量和安全性
|
||||
3. **灵活的数据结构**: 支持复杂嵌套结构和泛型,满足不同业务需求
|
||||
4. **优化的传输效率**: 通过合理的序列化配置减少网络传输开销
|
||||
5. **清晰的业务语义**: 命名规范和文档完善,便于开发和维护
|
||||
6. **类型安全保障**: Record类型和强类型约束减少运行时错误
|
||||
7. **扩展性支持**: 为AI集成等新功能提供了良好的数据结构基础
|
||||
|
||||
通过这些DTO的协同工作,EMS系统能够在各层之间安全、高效地传递数据,为整个系统的稳定运行和功能扩展提供了坚实的数据传输基础。
|
||||
|
||||
---
|
||||
|
||||
# Event模块详细解析
|
||||
|
||||
## 概述
|
||||
|
||||
Event(事件)模块位于 `com.dne.ems.event` 包下,包含2个应用事件类,实现了系统的事件驱动架构。通过Spring的事件发布机制,实现了业务模块之间的松耦合通信,支持异步处理和系统扩展。
|
||||
|
||||
## 核心事件类
|
||||
|
||||
### 1. FeedbackSubmittedForAiReviewEvent
|
||||
|
||||
#### 功能概述
|
||||
- **用途**: 反馈提交AI审核事件
|
||||
- **触发时机**: 当公众提交反馈后,系统需要进行AI预审核时发布
|
||||
- **业务价值**: 实现反馈提交与AI审核的解耦,支持异步AI分析
|
||||
|
||||
#### 核心特性
|
||||
- **继承关系**: 继承自Spring的`ApplicationEvent`基类
|
||||
- **数据载体**: 携带完整的`Feedback`实体对象
|
||||
- **事件源**: 支持指定事件发布源,便于追踪和调试
|
||||
|
||||
#### 代码实现
|
||||
```java
|
||||
package com.dne.ems.event;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import com.dne.ems.model.Feedback;
|
||||
|
||||
public class FeedbackSubmittedForAiReviewEvent extends ApplicationEvent {
|
||||
private final Feedback feedback;
|
||||
|
||||
public FeedbackSubmittedForAiReviewEvent(Object source, Feedback feedback) {
|
||||
super(source);
|
||||
this.feedback = feedback;
|
||||
}
|
||||
|
||||
public Feedback getFeedback() {
|
||||
return feedback;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 使用场景
|
||||
1. **反馈提交后**: 在`FeedbackService`中提交反馈成功后发布此事件
|
||||
2. **AI审核触发**: 事件监听器接收到事件后,调用AI服务进行内容分析
|
||||
3. **异步处理**: 避免反馈提交流程被AI分析耗时阻塞
|
||||
|
||||
### 2. TaskReadyForAssignmentEvent
|
||||
|
||||
#### 功能概述
|
||||
- **用途**: 任务准备分配事件
|
||||
- **触发时机**: 当任务创建完成或状态变更为可分配时发布
|
||||
- **业务价值**: 实现任务创建与分配逻辑的解耦,支持智能分配算法
|
||||
|
||||
#### 核心特性
|
||||
- **继承关系**: 继承自Spring的`ApplicationEvent`基类
|
||||
- **数据载体**: 携带完整的`Task`实体对象
|
||||
- **Lombok支持**: 使用`@Getter`注解简化代码
|
||||
- **不可变性**: 任务对象使用`final`修饰,确保事件数据不被修改
|
||||
|
||||
#### 代码实现
|
||||
```java
|
||||
package com.dne.ems.event;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import com.dne.ems.model.Task;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class TaskReadyForAssignmentEvent extends ApplicationEvent {
|
||||
private final Task task;
|
||||
|
||||
public TaskReadyForAssignmentEvent(Object source, Task task) {
|
||||
super(source);
|
||||
this.task = task;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 使用场景
|
||||
1. **任务创建后**: 在`TaskService`中创建新任务后发布此事件
|
||||
2. **状态变更**: 任务状态从其他状态变更为待分配时发布
|
||||
3. **智能分配**: 事件监听器可以触发智能分配算法,推荐最佳执行人
|
||||
4. **通知机制**: 通知相关人员有新任务需要分配
|
||||
|
||||
## 事件驱动架构优势
|
||||
|
||||
### 1. 松耦合设计
|
||||
- **模块独立**: 事件发布者和监听者之间没有直接依赖关系
|
||||
- **易于扩展**: 可以随时添加新的事件监听器而不影响现有代码
|
||||
- **职责分离**: 每个模块专注于自己的核心业务逻辑
|
||||
|
||||
### 2. 异步处理能力
|
||||
- **性能提升**: 耗时操作(如AI分析)不会阻塞主业务流程
|
||||
- **用户体验**: 用户操作可以立即得到响应
|
||||
- **系统吞吐**: 提高系统整体处理能力
|
||||
|
||||
### 3. 可观测性
|
||||
- **事件追踪**: 可以记录事件的发布和处理过程
|
||||
- **调试支持**: 便于排查业务流程中的问题
|
||||
- **监控集成**: 可以与监控系统集成,实时观察系统状态
|
||||
|
||||
## 事件处理流程
|
||||
|
||||
### 反馈AI审核流程
|
||||
```
|
||||
1. 用户提交反馈 → FeedbackService.createFeedback()
|
||||
2. 保存反馈到数据库
|
||||
3. 发布 FeedbackSubmittedForAiReviewEvent
|
||||
4. AI审核监听器接收事件
|
||||
5. 调用AI服务分析反馈内容
|
||||
6. 更新反馈状态和AI分析结果
|
||||
```
|
||||
|
||||
### 任务分配流程
|
||||
```
|
||||
1. 创建新任务 → TaskService.createTask()
|
||||
2. 保存任务到数据库
|
||||
3. 发布 TaskReadyForAssignmentEvent
|
||||
4. 任务分配监听器接收事件
|
||||
5. 执行智能分配算法
|
||||
6. 推荐最佳执行人或自动分配
|
||||
```
|
||||
|
||||
## 技术实现细节
|
||||
|
||||
### 1. Spring事件机制
|
||||
- **ApplicationEvent**: 所有自定义事件的基类
|
||||
- **ApplicationEventPublisher**: 用于发布事件的接口
|
||||
- **@EventListener**: 标记事件监听方法的注解
|
||||
- **@Async**: 支持异步事件处理
|
||||
|
||||
### 2. 事件发布示例
|
||||
```java
|
||||
@Service
|
||||
public class FeedbackService {
|
||||
@Autowired
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
public Feedback createFeedback(FeedbackRequest request) {
|
||||
// 保存反馈
|
||||
Feedback feedback = feedbackRepository.save(newFeedback);
|
||||
|
||||
// 发布事件
|
||||
eventPublisher.publishEvent(
|
||||
new FeedbackSubmittedForAiReviewEvent(this, feedback)
|
||||
);
|
||||
|
||||
return feedback;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 事件监听示例
|
||||
```java
|
||||
@Component
|
||||
public class FeedbackEventListener {
|
||||
|
||||
@EventListener
|
||||
@Async
|
||||
public void handleFeedbackSubmitted(FeedbackSubmittedForAiReviewEvent event) {
|
||||
Feedback feedback = event.getFeedback();
|
||||
// 执行AI审核逻辑
|
||||
aiReviewService.reviewFeedback(feedback);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Event模块最佳实践
|
||||
|
||||
1. **事件命名**: 使用清晰的命名约定,体现事件的业务含义
|
||||
2. **数据封装**: 事件中携带的数据应该是完整且不可变的
|
||||
3. **异步处理**: 对于耗时操作,使用`@Async`注解实现异步处理
|
||||
4. **异常处理**: 事件监听器中要有完善的异常处理机制
|
||||
5. **幂等性**: 确保事件处理的幂等性,避免重复处理问题
|
||||
6. **监控日志**: 记录事件的发布和处理日志,便于问题排查
|
||||
|
||||
## Event模块总结
|
||||
|
||||
Event模块为EMS系统提供了强大的事件驱动能力:
|
||||
|
||||
1. **解耦架构**: 通过事件机制实现模块间的松耦合通信
|
||||
2. **异步处理**: 支持耗时操作的异步执行,提升系统性能
|
||||
3. **扩展性强**: 易于添加新的业务逻辑而不影响现有代码
|
||||
4. **可观测性**: 提供清晰的业务流程追踪和监控能力
|
||||
5. **Spring集成**: 充分利用Spring框架的事件机制和异步支持
|
||||
|
||||
虽然目前只有2个事件类,但它们为系统的核心业务流程(反馈处理和任务分配)提供了关键的解耦和异步处理能力,为系统的可扩展性和性能优化奠定了坚实基础。
|
||||
|
||||
---
|
||||
|
||||
# Exception模块详细解析
|
||||
|
||||
## 概述
|
||||
|
||||
Exception(异常处理)模块位于 `com.dne.ems.exception` 包下,包含7个异常处理相关的类,构建了完整的异常处理体系。通过自定义异常类和全局异常处理器,实现了统一的错误响应格式和完善的异常处理机制,提升了系统的健壮性和用户体验。
|
||||
|
||||
## 核心异常类
|
||||
|
||||
### 1. ErrorResponseDTO
|
||||
|
||||
#### 功能概述
|
||||
- **用途**: 标准化API错误响应数据传输对象
|
||||
- **作用**: 为所有API端点提供一致的错误结构
|
||||
- **业务价值**: 统一错误响应格式,提升前端处理效率
|
||||
|
||||
#### 核心特性
|
||||
- **Lombok支持**: 使用`@Data`、`@AllArgsConstructor`、`@NoArgsConstructor`注解
|
||||
- **时间戳**: 记录错误发生的精确时间
|
||||
- **状态码**: HTTP状态码,便于前端判断错误类型
|
||||
- **错误分类**: 提供错误类型和详细消息
|
||||
- **路径追踪**: 记录发生错误的请求路径
|
||||
|
||||
#### 代码实现
|
||||
```java
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ErrorResponseDTO {
|
||||
private LocalDateTime timestamp;
|
||||
private int status;
|
||||
private String error;
|
||||
private String message;
|
||||
private String path;
|
||||
}
|
||||
```
|
||||
|
||||
### 2. ResourceNotFoundException
|
||||
|
||||
#### 功能概述
|
||||
- **用途**: 资源不存在异常
|
||||
- **HTTP状态**: 404 Not Found
|
||||
- **触发场景**: 查询的资源不存在时抛出
|
||||
- **业务价值**: 明确区分资源不存在的情况
|
||||
|
||||
#### 核心特性
|
||||
- **Spring集成**: 使用`@ResponseStatus(HttpStatus.NOT_FOUND)`注解
|
||||
- **自动映射**: 异常抛出时自动返回404状态码
|
||||
- **继承关系**: 继承自`RuntimeException`,支持非检查异常
|
||||
|
||||
#### 使用场景
|
||||
1. **用户查询**: 查询不存在的用户ID
|
||||
2. **任务查询**: 查询不存在的任务ID
|
||||
3. **反馈查询**: 查询不存在的反馈记录
|
||||
4. **文件查询**: 查询不存在的附件文件
|
||||
|
||||
### 3. InvalidOperationException
|
||||
|
||||
#### 功能概述
|
||||
- **用途**: 无效操作异常
|
||||
- **HTTP状态**: 400 Bad Request
|
||||
- **触发场景**: 业务规则不允许的操作时抛出
|
||||
- **业务价值**: 保护业务逻辑完整性
|
||||
|
||||
#### 核心特性
|
||||
- **业务保护**: 防止违反业务规则的操作
|
||||
- **状态映射**: 自动返回400状态码
|
||||
- **简洁设计**: 只提供消息构造器,专注业务逻辑
|
||||
|
||||
#### 使用场景
|
||||
1. **状态变更**: 任务状态不允许的变更操作
|
||||
2. **权限检查**: 用户权限不足的操作
|
||||
3. **数据验证**: 业务数据不符合规则
|
||||
4. **流程控制**: 违反业务流程的操作
|
||||
|
||||
### 4. UserAlreadyExistsException
|
||||
|
||||
#### 功能概述
|
||||
- **用途**: 用户已存在异常
|
||||
- **HTTP状态**: 409 Conflict
|
||||
- **触发场景**: 注册时用户名或邮箱已存在
|
||||
- **业务价值**: 防止重复用户注册
|
||||
|
||||
#### 核心特性
|
||||
- **冲突处理**: 使用409状态码表示资源冲突
|
||||
- **注册保护**: 确保用户唯一性
|
||||
- **清晰语义**: 明确表达用户重复的问题
|
||||
|
||||
#### 使用场景
|
||||
1. **用户注册**: 用户名已被占用
|
||||
2. **邮箱注册**: 邮箱地址已被使用
|
||||
3. **账号创建**: 管理员创建重复账号
|
||||
|
||||
### 5. FileNotFoundException
|
||||
|
||||
#### 功能概述
|
||||
- **用途**: 文件不存在异常
|
||||
- **HTTP状态**: 404 Not Found
|
||||
- **触发场景**: 请求的文件不存在时抛出
|
||||
- **业务价值**: 专门处理文件相关的404错误
|
||||
|
||||
#### 核心特性
|
||||
- **文件专用**: 专门处理文件操作异常
|
||||
- **双构造器**: 支持消息和原因链的构造
|
||||
- **异常链**: 支持异常原因追踪
|
||||
|
||||
#### 使用场景
|
||||
1. **附件下载**: 下载不存在的附件文件
|
||||
2. **图片访问**: 访问不存在的图片资源
|
||||
3. **文档查看**: 查看已删除的文档
|
||||
|
||||
### 6. FileStorageException
|
||||
|
||||
#### 功能概述
|
||||
- **用途**: 文件存储异常
|
||||
- **HTTP状态**: 默认500(通过全局处理器处理)
|
||||
- **触发场景**: 文件存储操作失败时抛出
|
||||
- **业务价值**: 统一处理文件存储相关错误
|
||||
|
||||
#### 核心特性
|
||||
- **存储专用**: 专门处理文件存储异常
|
||||
- **异常链支持**: 保留原始异常信息
|
||||
- **灵活处理**: 可通过全局处理器自定义响应
|
||||
|
||||
#### 使用场景
|
||||
1. **文件上传**: 上传过程中的存储失败
|
||||
2. **文件删除**: 删除文件时的IO错误
|
||||
3. **文件移动**: 文件移动或重命名失败
|
||||
4. **磁盘空间**: 存储空间不足的情况
|
||||
|
||||
### 7. GlobalExceptionHandler
|
||||
|
||||
#### 功能概述
|
||||
- **用途**: 全局异常处理器
|
||||
- **作用**: 统一处理控制器层抛出的异常
|
||||
- **业务价值**: 提供一致的错误响应和完善的日志记录
|
||||
|
||||
#### 核心特性
|
||||
- **全局捕获**: 使用`@ControllerAdvice`注解实现全局异常捕获
|
||||
- **分类处理**: 针对不同异常类型提供专门的处理方法
|
||||
- **日志记录**: 使用`@Slf4j`记录详细的错误日志
|
||||
- **标准响应**: 返回统一格式的错误响应
|
||||
|
||||
#### 处理的异常类型
|
||||
|
||||
##### ResourceNotFoundException处理
|
||||
```java
|
||||
@ExceptionHandler(ResourceNotFoundException.class)
|
||||
public ResponseEntity<ErrorResponseDTO> handleResourceNotFoundException(
|
||||
ResourceNotFoundException ex, WebRequest request) {
|
||||
ErrorResponseDTO errorResponse = new ErrorResponseDTO(
|
||||
LocalDateTime.now(),
|
||||
HttpStatus.NOT_FOUND.value(),
|
||||
"Not Found",
|
||||
ex.getMessage(),
|
||||
request.getDescription(false).replace("uri=", ""));
|
||||
return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
|
||||
}
|
||||
```
|
||||
|
||||
##### InvalidOperationException处理
|
||||
```java
|
||||
@ExceptionHandler(InvalidOperationException.class)
|
||||
public ResponseEntity<ErrorResponseDTO> handleInvalidOperationException(
|
||||
InvalidOperationException ex, WebRequest request) {
|
||||
ErrorResponseDTO errorResponse = new ErrorResponseDTO(
|
||||
LocalDateTime.now(),
|
||||
HttpStatus.BAD_REQUEST.value(),
|
||||
"Bad Request",
|
||||
ex.getMessage(),
|
||||
request.getDescription(false).replace("uri=", ""));
|
||||
return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
```
|
||||
|
||||
##### 全局异常处理
|
||||
```java
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseEntity<?> handleGlobalException(Exception ex, WebRequest request) {
|
||||
log.error("捕获到全局未处理异常! 请求: {}", request.getDescription(false), ex);
|
||||
|
||||
Map<String, String> errorDetails = Map.of(
|
||||
"message", "服务器内部发生未知错误,请联系技术支持",
|
||||
"error", ex.getClass().getName(),
|
||||
"details", ex.getMessage()
|
||||
);
|
||||
|
||||
return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
```
|
||||
|
||||
## 异常处理架构优势
|
||||
|
||||
### 1. 统一错误格式
|
||||
- **一致性**: 所有API错误都使用相同的响应格式
|
||||
- **可预测**: 前端可以统一处理错误响应
|
||||
- **信息完整**: 包含时间戳、状态码、错误类型、消息和路径
|
||||
|
||||
### 2. 分层异常处理
|
||||
- **业务异常**: 自定义异常类处理特定业务场景
|
||||
- **系统异常**: 全局处理器兜底处理未预期异常
|
||||
- **HTTP映射**: 自动将异常映射为合适的HTTP状态码
|
||||
|
||||
### 3. 完善的日志记录
|
||||
- **错误追踪**: 详细记录异常发生的上下文
|
||||
- **问题定位**: 便于开发人员快速定位问题
|
||||
- **监控集成**: 支持与监控系统集成
|
||||
|
||||
### 4. 用户友好
|
||||
- **清晰消息**: 提供用户可理解的错误消息
|
||||
- **状态码**: 正确的HTTP状态码便于前端处理
|
||||
- **安全性**: 不暴露系统内部敏感信息
|
||||
|
||||
## 异常处理流程
|
||||
|
||||
### 标准异常处理流程
|
||||
```
|
||||
1. 业务层抛出自定义异常
|
||||
2. 控制器层捕获异常
|
||||
3. GlobalExceptionHandler拦截异常
|
||||
4. 根据异常类型选择处理方法
|
||||
5. 构建ErrorResponseDTO响应
|
||||
6. 记录错误日志
|
||||
7. 返回标准化错误响应
|
||||
```
|
||||
|
||||
### 异常分类处理
|
||||
```
|
||||
业务异常:
|
||||
├── ResourceNotFoundException (404) - 资源不存在
|
||||
├── InvalidOperationException (400) - 无效操作
|
||||
├── UserAlreadyExistsException (409) - 用户已存在
|
||||
├── FileNotFoundException (404) - 文件不存在
|
||||
└── FileStorageException (500) - 文件存储错误
|
||||
|
||||
系统异常:
|
||||
└── Exception (500) - 未处理的系统异常
|
||||
```
|
||||
|
||||
## Exception模块最佳实践
|
||||
|
||||
1. **异常分类**: 根据业务场景创建专门的异常类
|
||||
2. **状态码映射**: 使用`@ResponseStatus`注解自动映射HTTP状态码
|
||||
3. **消息设计**: 提供清晰、用户友好的错误消息
|
||||
4. **日志记录**: 在全局处理器中记录详细的错误日志
|
||||
5. **安全考虑**: 避免在错误响应中暴露敏感信息
|
||||
6. **异常链**: 保留原始异常信息便于问题追踪
|
||||
7. **统一格式**: 使用ErrorResponseDTO确保响应格式一致
|
||||
|
||||
## Exception模块总结
|
||||
|
||||
Exception模块为EMS系统提供了完善的异常处理能力:
|
||||
|
||||
1. **完整体系**: 涵盖业务异常、系统异常和文件异常的完整处理体系
|
||||
2. **统一响应**: 通过ErrorResponseDTO提供一致的错误响应格式
|
||||
3. **自动映射**: 利用Spring的@ResponseStatus注解自动映射HTTP状态码
|
||||
4. **全局处理**: GlobalExceptionHandler提供兜底的异常处理机制
|
||||
5. **日志完善**: 详细的错误日志记录便于问题追踪和系统监控
|
||||
6. **用户友好**: 清晰的错误消息和正确的状态码提升用户体验
|
||||
7. **安全可靠**: 在提供有用信息的同时保护系统安全
|
||||
|
||||
通过这套异常处理机制,EMS系统能够优雅地处理各种异常情况,为用户提供清晰的错误反馈,为开发人员提供完善的错误追踪能力,大大提升了系统的健壮性和可维护性。
|
||||
|
||||
---
|
||||
|
||||
# Listener模块详细解析
|
||||
|
||||
## 概述
|
||||
|
||||
Listener(监听器)模块位于 `com.dne.ems.listener` 包下,包含3个事件监听器类,实现了系统的事件驱动响应机制。通过监听Spring Security认证事件和自定义业务事件,实现了安全控制、用户状态管理和业务流程自动化,为系统的安全性和业务连续性提供了重要保障。
|
||||
|
||||
## 核心监听器类
|
||||
|
||||
### 1. AuthenticationFailureEventListener
|
||||
|
||||
#### 功能概述
|
||||
- **用途**: 认证失败事件监听器
|
||||
- **监听事件**: `AuthenticationFailureBadCredentialsEvent`
|
||||
- **触发场景**: 用户登录认证失败时
|
||||
- **业务价值**: 实现登录失败次数统计和IP锁定机制
|
||||
|
||||
#### 核心特性
|
||||
- **Spring Security集成**: 监听Spring Security的认证失败事件
|
||||
- **IP地址获取**: 智能获取真实客户端IP地址
|
||||
- **代理支持**: 支持X-Forwarded-For头部处理
|
||||
- **安全防护**: 防止暴力破解攻击
|
||||
|
||||
#### 代码实现
|
||||
```java
|
||||
@Component
|
||||
public class AuthenticationFailureEventListener
|
||||
implements ApplicationListener<AuthenticationFailureBadCredentialsEvent> {
|
||||
|
||||
@Autowired
|
||||
private LoginAttemptService loginAttemptService;
|
||||
|
||||
@Autowired
|
||||
private HttpServletRequest request;
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(AuthenticationFailureBadCredentialsEvent event) {
|
||||
final String xfHeader = request.getHeader("X-Forwarded-For");
|
||||
String ip;
|
||||
if (xfHeader == null || xfHeader.isEmpty() || !xfHeader.contains(request.getRemoteAddr())) {
|
||||
ip = request.getRemoteAddr();
|
||||
} else {
|
||||
ip = xfHeader.split(",")[0];
|
||||
}
|
||||
|
||||
// 使用IP地址作为锁定键
|
||||
loginAttemptService.loginFailed(ip);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### IP地址获取逻辑
|
||||
1. **代理检测**: 检查X-Forwarded-For头部是否存在
|
||||
2. **真实IP**: 优先使用代理转发的真实客户端IP
|
||||
3. **直连IP**: 无代理时使用直接连接的IP地址
|
||||
4. **安全验证**: 验证代理IP的合法性
|
||||
|
||||
#### 使用场景
|
||||
1. **登录保护**: 记录失败的登录尝试
|
||||
2. **暴力破解防护**: 限制同一IP的登录尝试次数
|
||||
3. **安全审计**: 记录可疑的登录行为
|
||||
4. **IP黑名单**: 自动封禁恶意IP地址
|
||||
|
||||
### 2. AuthenticationSuccessEventListener
|
||||
|
||||
#### 功能概述
|
||||
- **用途**: 认证成功事件监听器
|
||||
- **监听事件**: `AuthenticationSuccessEvent`
|
||||
- **触发场景**: 用户登录认证成功时
|
||||
- **业务价值**: 重置用户登录失败计数和解除账户锁定
|
||||
|
||||
#### 核心特性
|
||||
- **状态重置**: 成功登录后重置失败计数
|
||||
- **锁定解除**: 自动解除账户锁定状态
|
||||
- **用户管理**: 维护用户账户状态的一致性
|
||||
- **安全恢复**: 恢复正常用户的访问权限
|
||||
|
||||
#### 代码实现
|
||||
```java
|
||||
@Component
|
||||
public class AuthenticationSuccessEventListener
|
||||
implements ApplicationListener<AuthenticationSuccessEvent> {
|
||||
|
||||
@Autowired
|
||||
private UserAccountRepository userAccountRepository;
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(@NonNull AuthenticationSuccessEvent event) {
|
||||
Object principal = event.getAuthentication().getPrincipal();
|
||||
|
||||
if (principal instanceof UserDetails userDetails) {
|
||||
String username = userDetails.getUsername();
|
||||
UserAccount user = userAccountRepository.findByEmail(username).orElse(null);
|
||||
|
||||
if (user != null && user.getFailedLoginAttempts() > 0) {
|
||||
user.setFailedLoginAttempts(0);
|
||||
user.setLockoutEndTime(null);
|
||||
userAccountRepository.save(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 处理流程
|
||||
1. **身份验证**: 确认认证主体是UserDetails实例
|
||||
2. **用户查找**: 根据用户名查找用户账户
|
||||
3. **状态检查**: 检查是否存在失败登录记录
|
||||
4. **状态重置**: 清零失败次数并解除锁定
|
||||
5. **数据持久化**: 保存更新后的用户状态
|
||||
|
||||
#### 使用场景
|
||||
1. **账户恢复**: 成功登录后恢复账户正常状态
|
||||
2. **计数重置**: 清除之前的失败登录记录
|
||||
3. **锁定解除**: 自动解除临时锁定状态
|
||||
4. **状态同步**: 保持用户状态的一致性
|
||||
|
||||
### 3. FeedbackEventListener
|
||||
|
||||
#### 功能概述
|
||||
- **用途**: 反馈事件监听器
|
||||
- **监听事件**: `FeedbackSubmittedForAiReviewEvent`
|
||||
- **触发场景**: 反馈提交需要AI审核时
|
||||
- **业务价值**: 实现反馈的异步AI审核处理
|
||||
|
||||
#### 核心特性
|
||||
- **异步处理**: 使用`@Async`注解实现异步执行
|
||||
- **事件驱动**: 基于Spring的事件机制
|
||||
- **AI集成**: 调用AI服务进行内容审核
|
||||
- **日志记录**: 详细记录处理过程
|
||||
|
||||
#### 代码实现
|
||||
```java
|
||||
@Component
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class FeedbackEventListener {
|
||||
|
||||
private final AiReviewService aiReviewService;
|
||||
|
||||
@Async
|
||||
@EventListener
|
||||
public void handleFeedbackSubmittedForAiReview(FeedbackSubmittedForAiReviewEvent event) {
|
||||
log.info("Received feedback submission event for AI review. Feedback ID: {}",
|
||||
event.getFeedback().getId());
|
||||
aiReviewService.reviewFeedback(event.getFeedback());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 处理特点
|
||||
1. **异步执行**: 不阻塞主业务流程
|
||||
2. **事件响应**: 响应反馈提交事件
|
||||
3. **AI调用**: 调用AI服务进行内容分析
|
||||
4. **日志追踪**: 记录处理过程便于监控
|
||||
|
||||
#### 使用场景
|
||||
1. **内容审核**: 自动审核用户提交的反馈内容
|
||||
2. **智能分类**: AI分析反馈的类型和优先级
|
||||
3. **质量评估**: 评估反馈的有效性和重要性
|
||||
4. **自动处理**: 根据AI分析结果自动处理简单反馈
|
||||
|
||||
## 监听器架构优势
|
||||
|
||||
### 1. 事件驱动架构
|
||||
- **解耦设计**: 事件发布者和监听者之间松耦合
|
||||
- **扩展性强**: 可以轻松添加新的事件监听器
|
||||
- **职责分离**: 每个监听器专注于特定的业务逻辑
|
||||
- **异步支持**: 支持异步事件处理提升性能
|
||||
|
||||
### 2. 安全机制增强
|
||||
- **登录保护**: 自动记录和处理登录失败
|
||||
- **状态管理**: 智能管理用户账户状态
|
||||
- **攻击防护**: 防止暴力破解和恶意登录
|
||||
- **恢复机制**: 自动恢复正常用户的访问权限
|
||||
|
||||
### 3. 业务流程自动化
|
||||
- **智能审核**: 自动触发AI内容审核
|
||||
- **状态同步**: 自动同步用户和业务状态
|
||||
- **流程优化**: 减少手动干预提升效率
|
||||
- **响应及时**: 实时响应业务事件
|
||||
|
||||
### 4. 系统可观测性
|
||||
- **日志记录**: 详细记录事件处理过程
|
||||
- **状态追踪**: 跟踪用户和业务状态变化
|
||||
- **性能监控**: 监控事件处理性能
|
||||
- **问题定位**: 便于排查和解决问题
|
||||
|
||||
## 事件处理流程
|
||||
|
||||
### 认证失败处理流程
|
||||
```
|
||||
1. 用户登录失败 → Spring Security触发AuthenticationFailureBadCredentialsEvent
|
||||
2. AuthenticationFailureEventListener接收事件
|
||||
3. 获取客户端真实IP地址
|
||||
4. 调用LoginAttemptService记录失败尝试
|
||||
5. 更新IP失败计数和锁定状态
|
||||
```
|
||||
|
||||
### 认证成功处理流程
|
||||
```
|
||||
1. 用户登录成功 → Spring Security触发AuthenticationSuccessEvent
|
||||
2. AuthenticationSuccessEventListener接收事件
|
||||
3. 获取用户身份信息
|
||||
4. 查找用户账户记录
|
||||
5. 重置失败计数和解除锁定
|
||||
6. 保存用户状态更新
|
||||
```
|
||||
|
||||
### 反馈AI审核流程
|
||||
```
|
||||
1. 反馈提交 → 发布FeedbackSubmittedForAiReviewEvent
|
||||
2. FeedbackEventListener异步接收事件
|
||||
3. 记录处理日志
|
||||
4. 调用AiReviewService进行内容审核
|
||||
5. 更新反馈状态和审核结果
|
||||
```
|
||||
|
||||
## 技术实现细节
|
||||
|
||||
### 1. Spring事件监听机制
|
||||
- **ApplicationListener**: 传统的事件监听接口
|
||||
- **@EventListener**: 基于注解的事件监听方法
|
||||
- **@Async**: 异步事件处理注解
|
||||
- **事件发布**: 通过ApplicationEventPublisher发布事件
|
||||
|
||||
### 2. 依赖注入和管理
|
||||
- **@Component**: 将监听器注册为Spring组件
|
||||
- **@Autowired**: 自动注入依赖服务
|
||||
- **@RequiredArgsConstructor**: Lombok构造器注入
|
||||
- **生命周期管理**: Spring容器管理监听器生命周期
|
||||
|
||||
### 3. 异步处理配置
|
||||
```java
|
||||
@EnableAsync
|
||||
@Configuration
|
||||
public class AsyncConfig {
|
||||
@Bean
|
||||
public TaskExecutor taskExecutor() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
executor.setCorePoolSize(2);
|
||||
executor.setMaxPoolSize(10);
|
||||
executor.setQueueCapacity(500);
|
||||
executor.setThreadNamePrefix("EventListener-");
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Listener模块最佳实践
|
||||
|
||||
1. **事件监听**: 使用合适的监听方式(接口或注解)
|
||||
2. **异步处理**: 对于耗时操作使用@Async注解
|
||||
3. **异常处理**: 在监听器中添加完善的异常处理
|
||||
4. **日志记录**: 记录关键事件的处理过程
|
||||
5. **性能考虑**: 避免在监听器中执行阻塞操作
|
||||
6. **事务管理**: 注意事件监听器的事务边界
|
||||
7. **测试覆盖**: 为监听器编写单元测试和集成测试
|
||||
|
||||
## Listener模块总结
|
||||
|
||||
Listener模块为EMS系统提供了强大的事件响应能力:
|
||||
|
||||
1. **安全保障**: 通过认证事件监听实现登录安全控制
|
||||
2. **状态管理**: 自动管理用户账户和业务状态
|
||||
3. **业务自动化**: 实现反馈AI审核等业务流程自动化
|
||||
4. **异步处理**: 支持异步事件处理提升系统性能
|
||||
5. **扩展性强**: 易于添加新的事件监听器扩展功能
|
||||
6. **可观测性**: 提供详细的事件处理日志和监控
|
||||
7. **Spring集成**: 充分利用Spring框架的事件机制
|
||||
|
||||
通过这套监听器机制,EMS系统能够及时响应各种系统事件和业务事件,实现了安全控制、状态管理和业务流程的自动化,为系统的稳定运行和用户体验提供了重要保障。
|
||||
|
||||
---
|
||||
|
||||
# Model模块详细解析
|
||||
|
||||
## 概述
|
||||
|
||||
Model(数据模型)模块位于 `com.dne.ems.model` 包下,包含14个核心实体类和10个枚举类,构成了EMS系统的完整数据模型。该模块使用JPA/Hibernate进行对象关系映射,定义了系统中所有业务实体的结构、关系和约束,为整个系统提供了坚实的数据基础。
|
||||
|
||||
## 核心实体类
|
||||
|
||||
### 1. 用户管理相关实体
|
||||
|
||||
#### UserAccount(用户账户)
|
||||
|
||||
**功能概述**
|
||||
- **用途**: 系统用户账户的核心实体
|
||||
- **映射表**: `user_account`
|
||||
- **业务价值**: 管理所有用户的基本信息、角色权限和状态
|
||||
|
||||
**核心特性**
|
||||
- **身份验证**: 存储用户登录凭据(邮箱、手机、密码)
|
||||
- **角色管理**: 支持多种用户角色(管理员、主管、网格员等)
|
||||
- **地理关联**: 支持网格坐标和区域信息
|
||||
- **技能管理**: JSON格式存储用户技能列表
|
||||
- **状态控制**: 支持账户激活、停用、请假等状态
|
||||
|
||||
**关键字段**
|
||||
```java
|
||||
@Entity
|
||||
@Table(name = "user_account")
|
||||
public class UserAccount {
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@NotEmpty
|
||||
@Column(unique = true)
|
||||
private String email;
|
||||
|
||||
@NotEmpty
|
||||
@Column(unique = true)
|
||||
private String phone;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private Role role;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private UserStatus status;
|
||||
|
||||
@Convert(converter = StringListConverter.class)
|
||||
private List<String> skills;
|
||||
|
||||
private Integer gridX;
|
||||
private Integer gridY;
|
||||
}
|
||||
```
|
||||
|
||||
#### PasswordResetToken(密码重置令牌)
|
||||
|
||||
**功能概述**
|
||||
- **用途**: 管理用户密码重置流程的安全令牌
|
||||
- **映射表**: `password_reset_token`
|
||||
- **业务价值**: 提供安全的密码重置机制
|
||||
|
||||
**核心特性**
|
||||
- **安全性**: 唯一令牌字符串,防止伪造
|
||||
- **时效性**: 60分钟有效期,自动过期
|
||||
- **一对一关联**: 每个令牌关联特定用户
|
||||
- **状态检查**: 提供过期检查方法
|
||||
|
||||
### 2. 反馈管理相关实体
|
||||
|
||||
#### Feedback(环境问题反馈)
|
||||
|
||||
**功能概述**
|
||||
- **用途**: 系统核心实体,记录用户提交的环境问题报告
|
||||
- **映射表**: `feedback`
|
||||
- **业务价值**: 收集、管理和跟踪环境问题反馈
|
||||
|
||||
**核心特性**
|
||||
- **唯一标识**: 人类可读的事件ID
|
||||
- **分类管理**: 污染类型和严重程度分类
|
||||
- **状态跟踪**: 完整的处理状态生命周期
|
||||
- **地理定位**: 支持网格坐标和文本地址
|
||||
- **关联管理**: 与用户、任务、附件的关联关系
|
||||
|
||||
**关键字段**
|
||||
```java
|
||||
@Entity
|
||||
@Table(name = "feedback")
|
||||
public class Feedback {
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@Column(unique = true)
|
||||
private String eventId;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private PollutionType pollutionType;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private SeverityLevel severityLevel;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private FeedbackStatus status;
|
||||
|
||||
private Integer gridX;
|
||||
private Integer gridY;
|
||||
|
||||
@OneToMany(mappedBy = "feedback")
|
||||
private List<Attachment> attachments;
|
||||
}
|
||||
```
|
||||
|
||||
#### Attachment(附件)
|
||||
|
||||
**功能概述**
|
||||
- **用途**: 管理反馈和任务提交的文件附件
|
||||
- **映射表**: `attachment`
|
||||
- **业务价值**: 支持多媒体证据收集和存储
|
||||
|
||||
**核心特性**
|
||||
- **文件元数据**: 存储文件名、类型、大小等信息
|
||||
- **存储管理**: 生成唯一存储文件名防止冲突
|
||||
- **多重关联**: 可关联反馈或任务提交
|
||||
- **时间戳**: 自动记录上传时间
|
||||
|
||||
### 3. 任务管理相关实体
|
||||
|
||||
#### Task(网格任务)
|
||||
|
||||
**功能概述**
|
||||
- **用途**: 表示网格工作人员执行的任务
|
||||
- **映射表**: `tasks`
|
||||
- **业务价值**: 管理从反馈到任务的完整生命周期
|
||||
|
||||
**核心特性**
|
||||
- **反馈关联**: 可从反馈自动生成或手动创建
|
||||
- **分配管理**: 支持任务分配和重新分配
|
||||
- **状态跟踪**: 完整的任务状态生命周期
|
||||
- **时间管理**: 创建、分配、完成时间戳
|
||||
- **地理信息**: 继承反馈的位置信息
|
||||
|
||||
**关键字段**
|
||||
```java
|
||||
@Entity
|
||||
@Table(name = "tasks")
|
||||
public class Task {
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@OneToOne
|
||||
private Feedback feedback;
|
||||
|
||||
@ManyToOne
|
||||
private UserAccount assignee;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private TaskStatus status;
|
||||
|
||||
@CreationTimestamp
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
private LocalDateTime assignedAt;
|
||||
private LocalDateTime completedAt;
|
||||
}
|
||||
```
|
||||
|
||||
#### TaskSubmission(任务提交)
|
||||
|
||||
**功能概述**
|
||||
- **用途**: 记录网格员完成任务后的提交信息
|
||||
- **映射表**: `task_submissions`
|
||||
- **业务价值**: 收集任务执行结果和工作记录
|
||||
|
||||
**核心特性**
|
||||
- **任务关联**: 与特定任务一对多关系
|
||||
- **详细记录**: 大文本字段存储工作笔记
|
||||
- **时间戳**: 自动记录提交时间
|
||||
- **附件支持**: 可关联多个附件文件
|
||||
|
||||
#### TaskHistory(任务历史)
|
||||
|
||||
**功能概述**
|
||||
- **用途**: 记录任务状态变更的审计日志
|
||||
- **映射表**: `task_history`
|
||||
- **业务价值**: 提供完整的任务处理轨迹
|
||||
|
||||
**核心特性**
|
||||
- **状态变更**: 记录旧状态和新状态
|
||||
- **操作人员**: 记录状态变更的执行者
|
||||
- **变更时间**: 自动记录变更时间戳
|
||||
- **备注信息**: 支持变更原因说明
|
||||
|
||||
### 4. 分配管理相关实体
|
||||
|
||||
#### Assignment(任务分配)
|
||||
|
||||
**功能概述**
|
||||
- **用途**: 管理反馈任务到网格员的分配关系
|
||||
- **映射表**: `assignments`
|
||||
- **业务价值**: 跟踪任务分配的生命周期
|
||||
|
||||
**核心特性**
|
||||
- **一对一关联**: 每个分配对应一个任务
|
||||
- **分配者记录**: 记录执行分配的用户
|
||||
- **截止日期**: 支持任务截止时间设置
|
||||
- **状态管理**: 跟踪分配状态变化
|
||||
- **备注信息**: 支持分配说明和要求
|
||||
|
||||
#### AssignmentRecord(分配记录)
|
||||
|
||||
**功能概述**
|
||||
- **用途**: 详细记录反馈分配的元数据
|
||||
- **映射表**: `assignment_record`
|
||||
- **业务价值**: 提供丰富的分配分析数据
|
||||
|
||||
**核心特性**
|
||||
- **关系映射**: 直接关联反馈、网格员、管理员
|
||||
- **分配方法**: 记录手动或智能分配方式
|
||||
- **算法详情**: JSON格式存储智能分配算法细节
|
||||
- **创建时间**: 自动记录分配创建时间
|
||||
|
||||
### 5. 空气质量数据相关实体
|
||||
|
||||
#### AqiData(空气质量指数数据)
|
||||
|
||||
**功能概述**
|
||||
- **用途**: 存储网格员提交的详细空气质量数据
|
||||
- **映射表**: `aqi_data`
|
||||
- **业务价值**: 收集实时环境监测数据
|
||||
|
||||
**核心特性**
|
||||
- **多污染物**: 支持PM2.5、PM10、SO2、NO2、CO、O3等
|
||||
- **网格关联**: 与具体网格位置关联
|
||||
- **报告者**: 记录数据提交的网格员
|
||||
- **反馈关联**: 可选关联相关反馈
|
||||
|
||||
**关键字段**
|
||||
```java
|
||||
@Entity
|
||||
@Table(name = "aqi_data")
|
||||
public class AqiData {
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@ManyToOne
|
||||
private Grid grid;
|
||||
|
||||
private Long reporterId;
|
||||
private Integer aqiValue;
|
||||
private Double pm25;
|
||||
private Double pm10;
|
||||
private Double so2;
|
||||
private Double no2;
|
||||
private Double co;
|
||||
private Double o3;
|
||||
}
|
||||
```
|
||||
|
||||
#### AqiRecord(空气质量历史记录)
|
||||
|
||||
**功能概述**
|
||||
- **用途**: 存储历史空气质量数据用于趋势分析
|
||||
- **映射表**: `aqi_records`
|
||||
- **业务价值**: 支持热力图生成和趋势分析
|
||||
|
||||
**核心特性**
|
||||
- **城市级别**: 按城市名称组织数据
|
||||
- **完整污染物**: 包含所有主要污染物浓度
|
||||
- **地理坐标**: 支持经纬度和网格坐标
|
||||
- **时间戳**: 自动记录数据时间
|
||||
|
||||
### 6. 地理网格相关实体
|
||||
|
||||
#### Grid(地理网格)
|
||||
|
||||
**功能概述**
|
||||
- **用途**: 表示地理网格单元用于区域管理
|
||||
- **映射表**: `grid`
|
||||
- **业务价值**: 支持基于网格的数据聚合和管理
|
||||
|
||||
**核心特性**
|
||||
- **坐标系统**: X、Y坐标定位
|
||||
- **行政区划**: 城市和区县信息
|
||||
- **障碍标记**: 支持限制区域标记
|
||||
- **描述信息**: 网格详细描述
|
||||
|
||||
#### MapGrid(地图网格)
|
||||
|
||||
**功能概述**
|
||||
- **用途**: 专门用于A*寻路算法的网格单元
|
||||
- **映射表**: `map_grid`
|
||||
- **业务价值**: 支持智能路径规划和导航
|
||||
|
||||
**核心特性**
|
||||
- **唯一约束**: (x,y)坐标唯一性约束
|
||||
- **障碍检测**: 支持障碍物标记
|
||||
- **地形类型**: 可选的地形类型信息
|
||||
- **城市约束**: 限制寻路范围
|
||||
|
||||
### 7. 系统配置相关实体
|
||||
|
||||
#### PollutantThreshold(污染物阈值)
|
||||
|
||||
**功能概述**
|
||||
- **用途**: 存储不同污染物的超标阈值设置
|
||||
- **映射表**: `pollutant_thresholds`
|
||||
- **业务价值**: 支持污染物超标检测和预警
|
||||
|
||||
**核心特性**
|
||||
- **类型关联**: 与污染物类型枚举关联
|
||||
- **阈值设置**: 可配置的超标阈值
|
||||
- **单位管理**: 支持不同计量单位
|
||||
- **描述信息**: 阈值设置说明
|
||||
|
||||
## 枚举类型系统
|
||||
|
||||
### 1. 用户相关枚举
|
||||
|
||||
#### Role(用户角色)
|
||||
```java
|
||||
public enum Role {
|
||||
PUBLIC_SUPERVISOR, // 公众监督员
|
||||
SUPERVISOR, // 主管
|
||||
GRID_WORKER, // 网格员
|
||||
ADMIN, // 系统管理员
|
||||
DECISION_MAKER // 决策者
|
||||
}
|
||||
```
|
||||
|
||||
#### UserStatus(用户状态)
|
||||
```java
|
||||
public enum UserStatus {
|
||||
ACTIVE, // 活跃
|
||||
INACTIVE, // 停用
|
||||
ON_LEAVE // 请假
|
||||
}
|
||||
```
|
||||
|
||||
#### Gender(性别)
|
||||
```java
|
||||
public enum Gender {
|
||||
MALE, // 男性
|
||||
FEMALE, // 女性
|
||||
UNKNOWN // 未知
|
||||
}
|
||||
```
|
||||
|
||||
#### Level(级别)
|
||||
```java
|
||||
public enum Level {
|
||||
PROVINCE, // 省级
|
||||
CITY // 市级
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 业务流程相关枚举
|
||||
|
||||
#### FeedbackStatus(反馈状态)
|
||||
```java
|
||||
public enum FeedbackStatus {
|
||||
PENDING_REVIEW, // 待审核
|
||||
AI_REVIEWING, // AI审核中
|
||||
AI_REVIEW_FAILED, // AI审核失败
|
||||
AI_PROCESSING, // AI处理中
|
||||
PENDING_ASSIGNMENT, // 待分配
|
||||
ASSIGNED, // 已分配
|
||||
CONFIRMED, // 已确认
|
||||
RESOLVED, // 已解决
|
||||
CLOSED // 已关闭
|
||||
}
|
||||
```
|
||||
|
||||
#### TaskStatus(任务状态)
|
||||
```java
|
||||
public enum TaskStatus {
|
||||
PENDING_ASSIGNMENT, // 待分配
|
||||
ASSIGNED, // 已分配
|
||||
IN_PROGRESS, // 进行中
|
||||
SUBMITTED, // 已提交
|
||||
COMPLETED, // 已完成
|
||||
CANCELLED // 已取消
|
||||
}
|
||||
```
|
||||
|
||||
#### AssignmentStatus(分配状态)
|
||||
```java
|
||||
public enum AssignmentStatus {
|
||||
PENDING, // 待处理
|
||||
IN_PROGRESS, // 进行中
|
||||
COMPLETED, // 已完成
|
||||
OVERDUE // 已逾期
|
||||
}
|
||||
```
|
||||
|
||||
#### AssignmentMethod(分配方法)
|
||||
```java
|
||||
public enum AssignmentMethod {
|
||||
MANUAL, // 手动分配
|
||||
INTELLIGENT // 智能分配
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 环境数据相关枚举
|
||||
|
||||
#### PollutionType(污染类型)
|
||||
```java
|
||||
public enum PollutionType {
|
||||
PM25, // 细颗粒物
|
||||
O3, // 臭氧
|
||||
NO2, // 二氧化氮
|
||||
SO2, // 二氧化硫
|
||||
OTHER // 其他
|
||||
}
|
||||
```
|
||||
|
||||
#### SeverityLevel(严重程度)
|
||||
```java
|
||||
public enum SeverityLevel {
|
||||
HIGH, // 高
|
||||
MEDIUM, // 中
|
||||
LOW // 低
|
||||
}
|
||||
```
|
||||
|
||||
## 数据模型设计特点
|
||||
|
||||
### 1. 关系设计
|
||||
- **一对一关系**: Task-Feedback, Assignment-Task
|
||||
- **一对多关系**: UserAccount-Task, Feedback-Attachment
|
||||
- **多对一关系**: AqiData-Grid, Task-UserAccount
|
||||
- **自引用关系**: TaskHistory-Task(审计日志)
|
||||
|
||||
### 2. 约束和验证
|
||||
- **唯一性约束**: 用户邮箱、手机号、反馈事件ID
|
||||
- **非空约束**: 关键业务字段强制非空
|
||||
- **枚举约束**: 使用枚举类型确保数据一致性
|
||||
- **长度约束**: 字符串字段长度限制
|
||||
|
||||
### 3. 时间戳管理
|
||||
- **创建时间**: @CreationTimestamp自动设置
|
||||
- **更新时间**: @UpdateTimestamp自动更新
|
||||
- **业务时间**: 分配时间、完成时间等业务节点
|
||||
- **过期检查**: 密码重置令牌过期验证
|
||||
|
||||
### 4. JSON数据支持
|
||||
- **技能列表**: 用户技能JSON存储
|
||||
- **算法详情**: 智能分配算法详情JSON存储
|
||||
- **大文本**: 使用@Lob注解支持长文本
|
||||
|
||||
## 数据模型架构优势
|
||||
|
||||
### 1. 业务完整性
|
||||
- **全生命周期**: 覆盖从反馈提交到任务完成的完整流程
|
||||
- **状态管理**: 详细的状态枚举和状态转换
|
||||
- **审计追踪**: 完整的操作历史记录
|
||||
- **数据关联**: 清晰的实体关系和数据流向
|
||||
|
||||
### 2. 扩展性设计
|
||||
- **枚举扩展**: 易于添加新的状态和类型
|
||||
- **实体扩展**: 支持新增字段和关系
|
||||
- **JSON存储**: 灵活的半结构化数据支持
|
||||
- **继承支持**: 预留实体继承扩展空间
|
||||
|
||||
### 3. 性能优化
|
||||
- **懒加载**: 使用FetchType.LAZY优化查询性能
|
||||
- **索引设计**: 唯一约束自动创建索引
|
||||
- **批量操作**: 支持CascadeType级联操作
|
||||
- **查询优化**: 合理的关系设计减少N+1问题
|
||||
|
||||
### 4. 数据安全
|
||||
- **密码加密**: 密码字段加密存储
|
||||
- **令牌安全**: 密码重置令牌时效性控制
|
||||
- **状态控制**: 用户状态控制访问权限
|
||||
- **数据完整性**: 外键约束保证数据一致性
|
||||
|
||||
## 技术实现细节
|
||||
|
||||
### 1. JPA注解使用
|
||||
```java
|
||||
// 实体映射
|
||||
@Entity
|
||||
@Table(name = "table_name")
|
||||
|
||||
// 主键生成
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
|
||||
// 关系映射
|
||||
@OneToOne
|
||||
@OneToMany
|
||||
@ManyToOne
|
||||
@ManyToMany
|
||||
|
||||
// 枚举映射
|
||||
@Enumerated(EnumType.STRING)
|
||||
|
||||
// 时间戳管理
|
||||
@CreationTimestamp
|
||||
@UpdateTimestamp
|
||||
```
|
||||
|
||||
### 2. Lombok注解
|
||||
```java
|
||||
@Data // getter/setter/toString/equals/hashCode
|
||||
@Builder // 建造者模式
|
||||
@NoArgsConstructor // 无参构造器
|
||||
@AllArgsConstructor // 全参构造器
|
||||
```
|
||||
|
||||
### 3. 验证注解
|
||||
```java
|
||||
@NotEmpty // 非空验证
|
||||
@NotNull // 非null验证
|
||||
@Email // 邮箱格式验证
|
||||
@Size(min = 8) // 长度验证
|
||||
```
|
||||
|
||||
### 4. 自定义转换器
|
||||
```java
|
||||
@Convert(converter = StringListConverter.class)
|
||||
private List<String> skills;
|
||||
```
|
||||
|
||||
## Model模块最佳实践
|
||||
|
||||
1. **实体设计**: 遵循单一职责原则,每个实体专注特定业务领域
|
||||
2. **关系映射**: 合理使用懒加载,避免性能问题
|
||||
3. **枚举使用**: 优先使用枚举类型确保数据一致性
|
||||
4. **时间戳**: 统一使用Hibernate注解管理时间字段
|
||||
5. **验证约束**: 在实体层添加基础验证约束
|
||||
6. **命名规范**: 遵循Java命名规范和数据库命名规范
|
||||
7. **文档注释**: 为每个实体和字段添加详细注释
|
||||
|
||||
## Model模块总结
|
||||
|
||||
Model模块为EMS系统提供了完整、规范的数据模型基础:
|
||||
|
||||
1. **业务完整性**: 覆盖用户管理、反馈处理、任务分配、数据收集等全业务流程
|
||||
2. **数据一致性**: 通过枚举类型、约束和验证确保数据质量
|
||||
3. **关系清晰**: 合理的实体关系设计支持复杂业务场景
|
||||
4. **扩展性强**: 灵活的设计支持业务需求变化和功能扩展
|
||||
5. **性能优化**: 合理的加载策略和索引设计保证系统性能
|
||||
6. **安全可靠**: 完善的约束和验证机制保证数据安全
|
||||
7. **标准规范**: 遵循JPA规范和最佳实践,便于维护和扩展
|
||||
|
||||
通过这套完整的数据模型,EMS系统建立了坚实的数据基础,为上层业务逻辑提供了可靠的数据支撑,确保了系统的稳定性、可扩展性和可维护性。
|
||||
|
||||
---
|
||||
|
||||
# Repository模块详细解析
|
||||
|
||||
## 概述
|
||||
|
||||
Repository(数据访问层)模块位于 `com.dne.ems.repository` 包下,包含14个Repository接口,构成了EMS系统完整的数据访问层。该模块基于Spring Data JPA框架,提供了标准化的数据访问接口,支持基础CRUD操作、自定义查询方法、复杂查询和分页查询,为业务层提供了高效、可靠的数据访问服务。
|
||||
|
||||
## 核心Repository接口
|
||||
|
||||
### 1. 用户管理相关Repository
|
||||
|
||||
#### UserAccountRepository(用户账户数据访问)
|
||||
|
||||
**功能概述**
|
||||
- **继承接口**: `JpaRepository<UserAccount, Long>`, `JpaSpecificationExecutor<UserAccount>`
|
||||
- **业务价值**: 提供用户账户的完整数据访问功能
|
||||
- **核心特性**: 支持复杂查询、分页查询、规格查询
|
||||
|
||||
**核心查询方法**
|
||||
```java
|
||||
@Repository
|
||||
public interface UserAccountRepository extends JpaRepository<UserAccount, Long>, JpaSpecificationExecutor<UserAccount> {
|
||||
// 基础查询
|
||||
Optional<UserAccount> findByEmail(String email);
|
||||
Optional<UserAccount> findByPhone(String phone);
|
||||
Optional<UserAccount> findByGridXAndGridY(Integer gridX, Integer gridY);
|
||||
|
||||
// 角色相关查询
|
||||
List<UserAccount> findByRole(Role role);
|
||||
long countByRole(Role role);
|
||||
Page<UserAccount> findByRole(Role role, Pageable pageable);
|
||||
List<UserAccount> findByRoleAndStatus(Role role, UserStatus status);
|
||||
|
||||
// 网格员专用查询
|
||||
@Query("SELECT u FROM UserAccount u WHERE u.role = 'GRID_WORKER' AND u.status = 'ACTIVE' AND u.gridX BETWEEN ?1 AND ?2 AND u.gridY BETWEEN ?3 AND ?4")
|
||||
List<UserAccount> findActiveWorkersInArea(int minX, int maxX, int minY, int maxY);
|
||||
|
||||
@Query("SELECT u FROM UserAccount u WHERE u.role = 'GRID_WORKER' AND u.gridX = ?1 AND u.gridY = ?2")
|
||||
List<UserAccount> findGridWorkersByCoordinates(int gridX, int gridY);
|
||||
|
||||
@Query("SELECT u FROM UserAccount u WHERE u.role = 'GRID_WORKER' AND u.gridX IS NOT NULL AND u.gridY IS NOT NULL AND u.gridX >= 0 AND u.gridY >= 0")
|
||||
List<UserAccount> findAllAssignedGridWorkers();
|
||||
|
||||
@Query("SELECT u FROM UserAccount u WHERE u.role = 'GRID_WORKER' AND (u.gridX IS NULL OR u.gridY IS NULL OR u.gridX < 0 OR u.gridY < 0)")
|
||||
List<UserAccount> findAllUnassignedGridWorkers();
|
||||
|
||||
@Query("SELECT u FROM UserAccount u WHERE u.role = 'GRID_WORKER' AND u.region LIKE %?1%")
|
||||
Page<UserAccount> findGridWorkersByCity(String cityName, Pageable pageable);
|
||||
}
|
||||
```
|
||||
|
||||
**使用场景**
|
||||
- **身份验证**: 通过邮箱或手机号查找用户
|
||||
- **角色管理**: 按角色查询和统计用户
|
||||
- **网格管理**: 查找特定区域或坐标的网格员
|
||||
- **用户分配**: 查找已分配和未分配网格的网格员
|
||||
- **区域查询**: 按城市查找网格员
|
||||
|
||||
#### PasswordResetTokenRepository(密码重置令牌数据访问)
|
||||
|
||||
**功能概述**
|
||||
- **继承接口**: `JpaRepository<PasswordResetToken, Long>`
|
||||
- **业务价值**: 管理密码重置令牌的数据访问
|
||||
- **核心特性**: 支持令牌查找和用户关联查询
|
||||
|
||||
**核心查询方法**
|
||||
```java
|
||||
@Repository
|
||||
public interface PasswordResetTokenRepository extends JpaRepository<PasswordResetToken, Long> {
|
||||
Optional<PasswordResetToken> findByToken(String token);
|
||||
Optional<PasswordResetToken> findByUser(UserAccount user);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 反馈管理相关Repository
|
||||
|
||||
#### FeedbackRepository(反馈数据访问)
|
||||
|
||||
**功能概述**
|
||||
- **继承接口**: `JpaRepository<Feedback, Long>`, `JpaSpecificationExecutor<Feedback>`
|
||||
- **业务价值**: 提供反馈数据的完整访问功能
|
||||
- **核心特性**: 支持复杂查询、分页查询、统计查询、热力图数据
|
||||
|
||||
**核心查询方法**
|
||||
```java
|
||||
@Repository
|
||||
public interface FeedbackRepository extends JpaRepository<Feedback, Long>, JpaSpecificationExecutor<Feedback> {
|
||||
// 基础查询
|
||||
Optional<Feedback> findByEventId(String eventId);
|
||||
List<Feedback> findByStatus(FeedbackStatus status);
|
||||
long countByStatus(FeedbackStatus status);
|
||||
|
||||
// 用户相关查询
|
||||
Page<Feedback> findBySubmitterId(Long submitterId, Pageable pageable);
|
||||
List<Feedback> findBySubmitterId(Long submitterId);
|
||||
long countBySubmitterId(Long submitterId);
|
||||
long countByStatusAndSubmitterId(FeedbackStatus status, Long submitterId);
|
||||
|
||||
// 统计查询
|
||||
@Query("SELECT new com.dne.ems.dto.HeatmapPointDTO(f.gridX, f.gridY, COUNT(f.id)) FROM Feedback f WHERE f.status = 'CONFIRMED' AND f.gridX IS NOT NULL AND f.gridY IS NOT NULL GROUP BY f.gridX, f.gridY")
|
||||
List<HeatmapPointDTO> getHeatmapData();
|
||||
|
||||
@Query("SELECT new com.dne.ems.dto.PollutionStatsDTO(f.pollutionType, COUNT(f)) FROM Feedback f GROUP BY f.pollutionType")
|
||||
List<PollutionStatsDTO> countByPollutionType();
|
||||
|
||||
// 性能优化查询
|
||||
@Override
|
||||
@EntityGraph(attributePaths = {"user", "attachments"})
|
||||
Page<Feedback> findAll(Specification<Feedback> spec, Pageable pageable);
|
||||
}
|
||||
```
|
||||
|
||||
**使用场景**
|
||||
- **反馈管理**: 按状态、用户、事件ID查询反馈
|
||||
- **数据统计**: 统计各状态反馈数量和污染类型分布
|
||||
- **热力图**: 生成反馈分布热力图数据
|
||||
- **性能优化**: 使用EntityGraph避免N+1查询问题
|
||||
|
||||
#### AttachmentRepository(附件数据访问)
|
||||
|
||||
**功能概述**
|
||||
- **继承接口**: `JpaRepository<Attachment, Long>`
|
||||
- **业务价值**: 管理反馈和任务提交的附件数据
|
||||
- **核心特性**: 支持文件名查找和关联实体查询
|
||||
|
||||
**核心查询方法**
|
||||
```java
|
||||
@Repository
|
||||
public interface AttachmentRepository extends JpaRepository<Attachment, Long> {
|
||||
Optional<Attachment> findByStoredFileName(String storedFileName);
|
||||
List<Attachment> findByTaskSubmission(TaskSubmission taskSubmission);
|
||||
List<Attachment> findByFeedback(Feedback feedback);
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 任务管理相关Repository
|
||||
|
||||
#### TaskRepository(任务数据访问)
|
||||
|
||||
**功能概述**
|
||||
- **继承接口**: `JpaRepository<Task, Long>`, `JpaSpecificationExecutor<Task>`
|
||||
- **业务价值**: 提供任务数据的完整访问功能
|
||||
- **核心特性**: 支持复杂查询、状态统计、分配查询
|
||||
|
||||
**核心查询方法**
|
||||
```java
|
||||
@Repository
|
||||
public interface TaskRepository extends JpaRepository<Task, Long>, JpaSpecificationExecutor<Task> {
|
||||
Optional<Task> findByFeedback(Feedback feedback);
|
||||
long countByStatus(TaskStatus status);
|
||||
long countByAssigneeIdAndStatusIn(Long assigneeId, Collection<TaskStatus> statuses);
|
||||
List<Task> findByAssigneeIdAndStatus(Long assigneeId, TaskStatus status);
|
||||
Page<Task> findByStatusAndAssignee(AssignmentStatus status, UserAccount assignee, Pageable pageable);
|
||||
}
|
||||
```
|
||||
|
||||
#### TaskSubmissionRepository(任务提交数据访问)
|
||||
|
||||
**功能概述**
|
||||
- **继承接口**: `JpaRepository<TaskSubmission, Long>`
|
||||
- **业务价值**: 管理任务提交记录的数据访问
|
||||
- **核心特性**: 支持按任务查找最新提交
|
||||
|
||||
**核心查询方法**
|
||||
```java
|
||||
@Repository
|
||||
public interface TaskSubmissionRepository extends JpaRepository<TaskSubmission, Long> {
|
||||
TaskSubmission findFirstByTaskOrderBySubmittedAtDesc(Task task);
|
||||
}
|
||||
```
|
||||
|
||||
#### TaskHistoryRepository(任务历史数据访问)
|
||||
|
||||
**功能概述**
|
||||
- **继承接口**: `JpaRepository<TaskHistory, Long>`
|
||||
- **业务价值**: 管理任务状态变更历史记录
|
||||
- **核心特性**: 支持按任务ID查询历史记录
|
||||
|
||||
**核心查询方法**
|
||||
```java
|
||||
@Repository
|
||||
public interface TaskHistoryRepository extends JpaRepository<TaskHistory, Long> {
|
||||
List<TaskHistory> findByTaskIdOrderByChangedAtDesc(Long taskId);
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 分配管理相关Repository
|
||||
|
||||
#### AssignmentRepository(任务分配数据访问)
|
||||
|
||||
**功能概述**
|
||||
- **继承接口**: `JpaRepository<Assignment, Long>`
|
||||
- **业务价值**: 管理任务分配关系的数据访问
|
||||
- **核心特性**: 支持按分配者查询分配记录
|
||||
|
||||
**核心查询方法**
|
||||
```java
|
||||
@Repository
|
||||
public interface AssignmentRepository extends JpaRepository<Assignment, Long> {
|
||||
List<Assignment> findByTaskAssigneeId(Long assigneeId);
|
||||
}
|
||||
```
|
||||
|
||||
#### AssignmentRecordRepository(分配记录数据访问)
|
||||
|
||||
**功能概述**
|
||||
- **继承接口**: `JpaRepository<AssignmentRecord, Long>`
|
||||
- **业务价值**: 管理分配记录的详细数据
|
||||
- **核心特性**: 基础CRUD操作,预留扩展空间
|
||||
|
||||
### 5. 空气质量数据相关Repository
|
||||
|
||||
#### AqiDataRepository(空气质量数据访问)
|
||||
|
||||
**功能概述**
|
||||
- **继承接口**: `JpaRepository<AqiData, Long>`
|
||||
- **业务价值**: 管理实时空气质量数据的访问
|
||||
- **核心特性**: 支持统计查询、趋势分析、热力图数据
|
||||
|
||||
**核心查询方法**
|
||||
```java
|
||||
@Repository
|
||||
public interface AqiDataRepository extends JpaRepository<AqiData, Long> {
|
||||
// AQI分布统计
|
||||
@Query("SELECT new com.dne.ems.dto.AqiDistributionDTO(CASE WHEN a.aqiValue <= 50 THEN 'Good' WHEN a.aqiValue <= 100 THEN 'Moderate' WHEN a.aqiValue <= 150 THEN 'Unhealthy for Sensitive Groups' WHEN a.aqiValue <= 200 THEN 'Unhealthy' WHEN a.aqiValue <= 300 THEN 'Very Unhealthy' ELSE 'Hazardous' END, COUNT(a.id)) FROM AqiData a GROUP BY 1")
|
||||
List<AqiDistributionDTO> getAqiDistribution();
|
||||
|
||||
// 月度超标趋势(原生SQL)
|
||||
@Query(value = "SELECT DATE_FORMAT(record_time, '%Y-%m') as yearMonth, COUNT(id) as count FROM aqi_data WHERE aqi_value > 100 AND record_time >= :startDate GROUP BY DATE_FORMAT(record_time, '%Y-%m') ORDER BY 1", nativeQuery = true)
|
||||
List<Object[]> getMonthlyExceedanceTrendRaw(@Param("startDate") LocalDateTime startDate);
|
||||
|
||||
// 默认方法转换原生查询结果
|
||||
default List<TrendDataPointDTO> getMonthlyExceedanceTrend(LocalDateTime startDate) {
|
||||
List<Object[]> rawResults = getMonthlyExceedanceTrendRaw(startDate);
|
||||
return rawResults.stream()
|
||||
.map(row -> new TrendDataPointDTO((String) row[0], ((Number) row[1]).longValue()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
// 热力图数据
|
||||
@Query("SELECT new com.dne.ems.dto.AqiHeatmapPointDTO(g.gridX, g.gridY, AVG(d.aqiValue)) FROM AqiData d JOIN d.grid g WHERE g.gridX IS NOT NULL AND g.gridY IS NOT NULL GROUP BY g.gridX, g.gridY")
|
||||
List<AqiHeatmapPointDTO> getAqiHeatmapData();
|
||||
}
|
||||
```
|
||||
|
||||
#### AqiRecordRepository(空气质量历史记录数据访问)
|
||||
|
||||
**功能概述**
|
||||
- **继承接口**: `JpaRepository<AqiRecord, Long>`
|
||||
- **业务价值**: 管理历史空气质量数据的访问
|
||||
- **核心特性**: 支持复杂阈值查询、时间范围查询、热力图数据
|
||||
|
||||
**核心查询方法**
|
||||
```java
|
||||
@Repository
|
||||
public interface AqiRecordRepository extends JpaRepository<AqiRecord, Long> {
|
||||
// AQI分布统计
|
||||
@Query("SELECT new com.dne.ems.dto.AqiDistributionDTO(CASE WHEN ar.aqiValue <= 50 THEN 'Good' WHEN ar.aqiValue <= 100 THEN 'Moderate' WHEN ar.aqiValue <= 150 THEN 'Unhealthy for Sensitive Groups' WHEN ar.aqiValue <= 200 THEN 'Unhealthy' WHEN ar.aqiValue <= 300 THEN 'Very Unhealthy' ELSE 'Hazardous' END, COUNT(ar.id)) FROM AqiRecord ar GROUP BY CASE WHEN ar.aqiValue <= 50 THEN 'Good' WHEN ar.aqiValue <= 100 THEN 'Moderate' WHEN ar.aqiValue <= 150 THEN 'Unhealthy for Sensitive Groups' WHEN ar.aqiValue <= 200 THEN 'Unhealthy' WHEN ar.aqiValue <= 300 THEN 'Very Unhealthy' ELSE 'Hazardous' END")
|
||||
List<AqiDistributionDTO> getAqiDistribution();
|
||||
|
||||
// 超标记录查询
|
||||
@Query("SELECT ar FROM AqiRecord ar WHERE ar.aqiValue > 100 AND ar.recordTime >= :startDate")
|
||||
List<AqiRecord> findExceedanceRecordsSince(@Param("startDate") LocalDateTime startDate);
|
||||
|
||||
// 多阈值超标查询
|
||||
@Query("SELECT ar FROM AqiRecord ar WHERE ar.recordTime >= :startDate AND (ar.aqiValue > :aqiThreshold OR ar.pm25 > :pm25Threshold OR ar.o3 > :o3Threshold OR ar.no2 > :no2Threshold OR ar.so2 > :so2Threshold)")
|
||||
List<AqiRecord> findExceedanceRecordsWithThresholds(@Param("startDate") LocalDateTime startDate, @Param("aqiThreshold") Double aqiThreshold, @Param("pm25Threshold") Double pm25Threshold, @Param("o3Threshold") Double o3Threshold, @Param("no2Threshold") Double no2Threshold, @Param("so2Threshold") Double so2Threshold);
|
||||
|
||||
// 时间范围查询
|
||||
List<AqiRecord> findByRecordTimeAfter(LocalDateTime startDate);
|
||||
|
||||
// 热力图数据(JPQL)
|
||||
@Query("SELECT new com.dne.ems.dto.AqiHeatmapPointDTO(ar.gridX, ar.gridY, AVG(ar.aqiValue)) FROM AqiRecord ar WHERE ar.gridX IS NOT NULL AND ar.gridY IS NOT NULL GROUP BY ar.gridX, ar.gridY")
|
||||
List<AqiHeatmapPointDTO> getAqiHeatmapData();
|
||||
|
||||
// 热力图数据(原生SQL)
|
||||
@Query(value = "SELECT grid_x, grid_y, AVG(aqi_value) as avg_aqi FROM aqi_records WHERE grid_x IS NOT NULL AND grid_y IS NOT NULL GROUP BY grid_x, grid_y", nativeQuery = true)
|
||||
List<Object[]> getAqiHeatmapDataRaw();
|
||||
}
|
||||
```
|
||||
|
||||
### 6. 地理网格相关Repository
|
||||
|
||||
#### GridRepository(地理网格数据访问)
|
||||
|
||||
**功能概述**
|
||||
- **继承接口**: `JpaRepository<Grid, Long>`, `JpaSpecificationExecutor<Grid>`
|
||||
- **业务价值**: 管理地理网格数据的访问
|
||||
- **核心特性**: 支持坐标查询、城市统计、障碍物查询
|
||||
|
||||
**核心查询方法**
|
||||
```java
|
||||
@Repository
|
||||
public interface GridRepository extends JpaRepository<Grid, Long>, JpaSpecificationExecutor<Grid> {
|
||||
Optional<Grid> findByGridXAndGridY(Integer gridX, Integer gridY);
|
||||
List<Grid> findByIsObstacle(boolean isObstacle);
|
||||
|
||||
@Query("SELECT new com.dne.ems.dto.GridCoverageDTO(g.cityName, COUNT(g.id)) FROM Grid g WHERE g.cityName IS NOT NULL AND g.cityName != '' GROUP BY g.cityName ORDER BY COUNT(g.id) DESC")
|
||||
List<GridCoverageDTO> getGridCoverageByCity();
|
||||
}
|
||||
```
|
||||
|
||||
#### MapGridRepository(地图网格数据访问)
|
||||
|
||||
**功能概述**
|
||||
- **继承接口**: `JpaRepository<MapGrid, Long>`
|
||||
- **业务价值**: 管理A*寻路算法的网格数据
|
||||
- **核心特性**: 支持坐标查询和有序遍历
|
||||
|
||||
**核心查询方法**
|
||||
```java
|
||||
@Repository
|
||||
public interface MapGridRepository extends JpaRepository<MapGrid, Long> {
|
||||
Optional<MapGrid> findByXAndY(int x, int y);
|
||||
List<MapGrid> findAllByOrderByYAscXAsc();
|
||||
}
|
||||
```
|
||||
|
||||
### 7. 系统配置相关Repository
|
||||
|
||||
#### PollutantThresholdRepository(污染物阈值数据访问)
|
||||
|
||||
**功能概述**
|
||||
- **继承接口**: `JpaRepository<PollutantThreshold, Long>`
|
||||
- **业务价值**: 管理污染物阈值配置数据
|
||||
- **核心特性**: 支持按污染物名称查询阈值
|
||||
|
||||
**核心查询方法**
|
||||
```java
|
||||
@Repository
|
||||
public interface PollutantThresholdRepository extends JpaRepository<PollutantThreshold, Long> {
|
||||
Optional<PollutantThreshold> findByPollutantName(String pollutantName);
|
||||
}
|
||||
```
|
||||
|
||||
## Repository设计特点
|
||||
|
||||
### 1. 继承体系设计
|
||||
- **JpaRepository**: 提供基础CRUD操作
|
||||
- **JpaSpecificationExecutor**: 支持动态查询和复杂条件
|
||||
- **双重继承**: 核心实体同时继承两个接口,提供完整功能
|
||||
|
||||
### 2. 查询方法类型
|
||||
- **方法名查询**: 基于Spring Data JPA命名规范的自动查询
|
||||
- **@Query注解**: 自定义JPQL查询语句
|
||||
- **原生SQL**: 使用nativeQuery进行复杂数据库操作
|
||||
- **默认方法**: 在接口中提供数据转换逻辑
|
||||
|
||||
### 3. 性能优化策略
|
||||
- **EntityGraph**: 解决N+1查询问题
|
||||
- **分页查询**: 支持大数据量的分页处理
|
||||
- **索引利用**: 查询方法充分利用数据库索引
|
||||
- **批量操作**: 继承JpaRepository的批量操作能力
|
||||
|
||||
### 4. 查询复杂度分层
|
||||
- **简单查询**: 单字段或少量字段的精确匹配
|
||||
- **条件查询**: 多条件组合和范围查询
|
||||
- **统计查询**: 聚合函数和分组统计
|
||||
- **关联查询**: 跨表JOIN查询和子查询
|
||||
|
||||
## Repository架构优势
|
||||
|
||||
### 1. 标准化设计
|
||||
- **Spring Data JPA**: 遵循Spring生态标准
|
||||
- **命名规范**: 统一的方法命名和参数规范
|
||||
- **注解驱动**: 使用标准注解进行配置
|
||||
- **接口导向**: 面向接口编程,便于测试和扩展
|
||||
|
||||
### 2. 功能完整性
|
||||
- **CRUD操作**: 完整的增删改查功能
|
||||
- **复杂查询**: 支持各种业务查询需求
|
||||
- **统计分析**: 提供数据统计和分析功能
|
||||
- **性能优化**: 内置性能优化机制
|
||||
|
||||
### 3. 扩展性强
|
||||
- **自定义查询**: 支持添加新的查询方法
|
||||
- **规格查询**: 支持动态条件构建
|
||||
- **原生SQL**: 支持复杂的数据库操作
|
||||
- **默认方法**: 支持在接口中添加业务逻辑
|
||||
|
||||
### 4. 维护性好
|
||||
- **类型安全**: 编译时类型检查
|
||||
- **自动实现**: Spring自动生成实现类
|
||||
- **测试友好**: 易于进行单元测试和集成测试
|
||||
- **文档清晰**: 方法名自解释,注释完整
|
||||
|
||||
## 技术实现细节
|
||||
|
||||
### 1. Spring Data JPA注解
|
||||
```java
|
||||
@Repository // 标识为Repository组件
|
||||
@Query("JPQL语句") // 自定义JPQL查询
|
||||
@Query(value="SQL", nativeQuery=true) // 原生SQL查询
|
||||
@Param("参数名") // 命名参数绑定
|
||||
@EntityGraph(attributePaths={"关联属性"}) // 性能优化
|
||||
```
|
||||
|
||||
### 2. 查询方法命名规范
|
||||
```java
|
||||
findBy... // 查询方法前缀
|
||||
countBy... // 统计方法前缀
|
||||
existsBy... // 存在性检查前缀
|
||||
deleteBy... // 删除方法前缀
|
||||
|
||||
// 条件关键字
|
||||
And, Or // 逻辑连接
|
||||
Between, LessThan, GreaterThan // 范围条件
|
||||
Like, NotLike // 模糊匹配
|
||||
In, NotIn // 集合条件
|
||||
IsNull, IsNotNull // 空值检查
|
||||
OrderBy...Asc/Desc // 排序
|
||||
```
|
||||
|
||||
### 3. 分页和排序
|
||||
```java
|
||||
Page<Entity> findBy...(Pageable pageable); // 分页查询
|
||||
List<Entity> findBy...OrderBy...(); // 排序查询
|
||||
Slice<Entity> findBy...(Pageable pageable); // 切片查询
|
||||
```
|
||||
|
||||
### 4. 规格查询(Specification)
|
||||
```java
|
||||
public interface EntityRepository extends JpaRepository<Entity, Long>, JpaSpecificationExecutor<Entity> {
|
||||
// 支持动态条件查询
|
||||
Page<Entity> findAll(Specification<Entity> spec, Pageable pageable);
|
||||
}
|
||||
```
|
||||
|
||||
## Repository模块最佳实践
|
||||
|
||||
1. **接口设计**: 保持接口简洁,职责单一
|
||||
2. **查询优化**: 合理使用EntityGraph避免N+1问题
|
||||
3. **命名规范**: 遵循Spring Data JPA命名约定
|
||||
4. **参数验证**: 在Service层进行参数验证,Repository专注数据访问
|
||||
5. **事务管理**: 在Service层管理事务,Repository保持无状态
|
||||
6. **异常处理**: 让Spring Data JPA的异常向上传播
|
||||
7. **测试覆盖**: 为自定义查询方法编写集成测试
|
||||
8. **性能监控**: 监控慢查询并进行优化
|
||||
|
||||
## Repository模块总结
|
||||
|
||||
Repository模块为EMS系统提供了完整、高效的数据访问层:
|
||||
|
||||
1. **标准化架构**: 基于Spring Data JPA的标准化设计
|
||||
2. **功能完整**: 覆盖所有业务实体的数据访问需求
|
||||
3. **查询丰富**: 支持简单查询、复杂查询、统计查询、分页查询
|
||||
4. **性能优化**: 内置多种性能优化机制
|
||||
5. **扩展性强**: 支持自定义查询和动态条件构建
|
||||
6. **维护性好**: 类型安全、自动实现、测试友好
|
||||
7. **业务适配**: 针对EMS业务特点设计的专用查询方法
|
||||
|
||||
通过这套完整的Repository层,EMS系统建立了高效、可靠的数据访问基础,为业务层提供了丰富的数据操作能力,确保了系统的数据访问性能和开发效率。
|
||||
|
||||
---
|
||||
|
||||
# Service模块详细解析
|
||||
|
||||
## 概述
|
||||
|
||||
Service(业务服务层)模块位于 `com.dne.ems.service` 包下,包含17个服务接口和对应的实现类,构成了EMS系统完整的业务逻辑层。该模块基于Spring框架的服务层架构,提供了标准化的业务服务接口,实现了复杂的业务逻辑处理、事务管理、安全控制和系统集成,为控制器层提供了高质量的业务服务。
|
||||
|
||||
## 核心Service接口
|
||||
|
||||
### 1. 认证与安全相关Service
|
||||
|
||||
#### AuthService(认证服务)
|
||||
|
||||
**功能概述**
|
||||
- **接口定义**: `AuthService`
|
||||
- **实现类**: `AuthServiceImpl`
|
||||
- **业务价值**: 提供用户认证和安全相关的核心功能
|
||||
- **核心特性**: 用户注册、登录认证、密码重置、JWT令牌管理
|
||||
|
||||
**核心方法**
|
||||
```java
|
||||
public interface AuthService {
|
||||
// 密码重置流程
|
||||
void requestPasswordReset(String email);
|
||||
void resetPasswordWithToken(String token, String newPassword);
|
||||
void resetPasswordWithCode(String email, String code, String newPassword);
|
||||
|
||||
// 用户注册与登录
|
||||
void registerUser(SignUpRequest signUpRequest);
|
||||
JwtAuthenticationResponse signIn(LoginRequest loginRequest);
|
||||
|
||||
// 验证码相关
|
||||
void sendRegistrationCode(String email);
|
||||
boolean validateRegistrationCode(String email, String code);
|
||||
}
|
||||
```
|
||||
|
||||
**业务流程**
|
||||
- **用户注册**: 验证码校验 → 用户信息验证 → 创建用户账户 → 返回注册结果
|
||||
- **用户登录**: 身份验证 → 生成JWT令牌 → 记录登录状态 → 返回认证响应
|
||||
- **密码重置**: 发送验证码 → 验证码校验 → 密码更新 → 清理令牌
|
||||
|
||||
#### JwtService(JWT令牌服务)
|
||||
|
||||
**功能概述**
|
||||
- **接口定义**: `JwtService`
|
||||
- **实现类**: `JwtServiceImpl`
|
||||
- **业务价值**: 处理JWT令牌的生成、解析和验证
|
||||
- **核心特性**: HS256算法签名、24小时有效期、用户角色权限声明
|
||||
|
||||
**核心方法**
|
||||
```java
|
||||
public interface JwtService {
|
||||
String extractUserName(String token);
|
||||
Claims extractAllClaims(String token);
|
||||
String generateToken(UserDetails userDetails);
|
||||
boolean isTokenValid(String token, UserDetails userDetails);
|
||||
}
|
||||
```
|
||||
|
||||
#### LoginAttemptService(登录尝试服务)
|
||||
|
||||
**功能概述**
|
||||
- **接口定义**: `LoginAttemptService`
|
||||
- **实现类**: `LoginAttemptServiceImpl`
|
||||
- **业务价值**: 防止暴力破解攻击,管理登录失败次数
|
||||
- **核心特性**: 失败次数统计、账户锁定机制、自动解锁
|
||||
|
||||
**核心方法**
|
||||
```java
|
||||
public interface LoginAttemptService {
|
||||
void loginSucceeded(String key);
|
||||
void loginFailed(String key);
|
||||
boolean isBlocked(String key);
|
||||
}
|
||||
```
|
||||
|
||||
#### VerificationCodeService(验证码服务)
|
||||
|
||||
**功能概述**
|
||||
- **接口定义**: `VerificationCodeService`
|
||||
- **实现类**: `VerificationCodeServiceImpl`
|
||||
- **业务价值**: 生成、发送和校验验证码
|
||||
- **核心特性**: 6位数字验证码、5分钟有效期、60秒发送间隔
|
||||
|
||||
**核心方法**
|
||||
```java
|
||||
public interface VerificationCodeService {
|
||||
void sendVerificationCode(String email);
|
||||
boolean verifyCode(String email, String code);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 用户管理相关Service
|
||||
|
||||
#### UserAccountService(用户账户服务)
|
||||
|
||||
**功能概述**
|
||||
- **接口定义**: `UserAccountService`
|
||||
- **实现类**: `UserAccountServiceImpl`
|
||||
- **业务价值**: 管理用户账户的完整生命周期
|
||||
- **核心特性**: 用户注册、角色管理、位置更新、用户查询
|
||||
|
||||
**核心方法**
|
||||
```java
|
||||
public interface UserAccountService {
|
||||
UserAccount registerUser(UserRegistrationRequest registrationRequest);
|
||||
UserAccount updateUserRole(Long userId, UserRoleUpdateRequest request);
|
||||
UserAccount getUserById(Long userId);
|
||||
Page<UserAccount> getUsersByRole(Role role, Pageable pageable);
|
||||
void updateUserLocation(Long userId, Double latitude, Double longitude);
|
||||
Page<UserSummaryDTO> getAllUsers(Role role, UserStatus status, Pageable pageable);
|
||||
}
|
||||
```
|
||||
|
||||
#### PersonnelService(人员管理服务)
|
||||
|
||||
**功能概述**
|
||||
- **接口定义**: `PersonnelService`
|
||||
- **实现类**: `PersonnelServiceImpl`
|
||||
- **业务价值**: 提供人员管理的高级功能
|
||||
- **核心特性**: 用户创建、信息更新、删除管理、个人资料更新
|
||||
|
||||
**核心方法**
|
||||
```java
|
||||
public interface PersonnelService {
|
||||
Page<UserAccount> getUsers(Role role, String name, Pageable pageable);
|
||||
UserAccount createUser(UserCreationRequest request);
|
||||
UserAccount updateUser(Long userId, UserUpdateRequest request);
|
||||
void deleteUser(Long userId);
|
||||
UserAccount updateOwnProfile(String currentUserEmail, UserUpdateRequest request);
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 反馈管理相关Service
|
||||
|
||||
#### FeedbackService(反馈服务)
|
||||
|
||||
**功能概述**
|
||||
- **接口定义**: `FeedbackService`
|
||||
- **实现类**: `FeedbackServiceImpl`
|
||||
- **业务价值**: 处理环境问题反馈的提交和管理
|
||||
- **核心特性**: 用户反馈提交、匿名反馈、反馈查询、数据统计
|
||||
|
||||
**核心方法**
|
||||
```java
|
||||
public interface FeedbackService {
|
||||
// 反馈提交
|
||||
Feedback submitFeedback(FeedbackSubmissionRequest request, MultipartFile[] files);
|
||||
Feedback submitPublicFeedback(PublicFeedbackRequest request, MultipartFile[] files);
|
||||
|
||||
// 反馈查询
|
||||
Page<FeedbackResponseDTO> getFeedbacks(FeedbackStatus status, PollutionType pollutionType,
|
||||
SeverityLevel severityLevel, LocalDate startDate,
|
||||
LocalDate endDate, Pageable pageable);
|
||||
FeedbackResponseDTO getFeedbackById(Long feedbackId);
|
||||
|
||||
// 反馈处理
|
||||
void processFeedback(Long feedbackId, ProcessFeedbackRequest request);
|
||||
|
||||
// 统计分析
|
||||
FeedbackStatsResponse getFeedbackStats();
|
||||
}
|
||||
```
|
||||
|
||||
**业务流程**
|
||||
- **反馈提交**: 用户信息验证 → 反馈数据创建 → 文件上传处理 → AI审核触发 → 返回反馈实体
|
||||
- **反馈处理**: 状态验证 → 业务逻辑处理 → 状态更新 → 事件发布
|
||||
|
||||
#### UserFeedbackService(用户反馈服务)
|
||||
|
||||
**功能概述**
|
||||
- **接口定义**: `UserFeedbackService`
|
||||
- **实现类**: `UserFeedbackServiceImpl`
|
||||
- **业务价值**: 提供用户特定的反馈操作
|
||||
- **核心特性**: 用户反馈历史查询
|
||||
|
||||
**核心方法**
|
||||
```java
|
||||
public interface UserFeedbackService {
|
||||
Page<UserFeedbackSummaryDTO> getFeedbackHistoryByUserId(Long userId, Pageable pageable);
|
||||
}
|
||||
```
|
||||
|
||||
#### AiReviewService(AI审核服务)
|
||||
|
||||
**功能概述**
|
||||
- **接口定义**: `AiReviewService`
|
||||
- **实现类**: `AiReviewServiceImpl`
|
||||
- **业务价值**: 使用AI模型审核反馈内容
|
||||
- **核心特性**: 外部AI服务调用、反馈状态更新
|
||||
|
||||
**核心方法**
|
||||
```java
|
||||
public interface AiReviewService {
|
||||
void reviewFeedback(Feedback feedback);
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 任务管理相关Service
|
||||
|
||||
#### TaskManagementService(任务管理服务)
|
||||
|
||||
**功能概述**
|
||||
- **接口定义**: `TaskManagementService`
|
||||
- **实现类**: `TaskManagementServiceImpl`
|
||||
- **业务价值**: 处理任务全生命周期管理
|
||||
- **核心特性**: 任务创建、分配、状态管理、审核审批
|
||||
|
||||
**核心方法**
|
||||
```java
|
||||
public interface TaskManagementService {
|
||||
// 任务查询
|
||||
Page<TaskSummaryDTO> getTasks(TaskStatus status, Long assigneeId, SeverityLevel severity,
|
||||
PollutionType pollutionType, LocalDate startDate,
|
||||
LocalDate endDate, Pageable pageable);
|
||||
TaskDetailDTO getTaskById(Long taskId);
|
||||
|
||||
// 任务创建
|
||||
TaskDetailDTO createTask(TaskCreationRequest request);
|
||||
TaskDetailDTO createTaskFromFeedback(TaskFromFeedbackRequest request);
|
||||
|
||||
// 任务分配
|
||||
void assignTask(Long taskId, TaskAssignmentRequest request);
|
||||
|
||||
// 任务审批
|
||||
void approveTask(Long taskId, TaskApprovalRequest request);
|
||||
void rejectTask(Long taskId, TaskApprovalRequest request);
|
||||
|
||||
// 任务历史
|
||||
List<TaskHistoryDTO> getTaskHistory(Long taskId);
|
||||
}
|
||||
```
|
||||
|
||||
**业务流程**
|
||||
- **任务创建**: 请求验证 → 任务实体创建 → 历史记录 → 事件发布
|
||||
- **任务分配**: 分配者验证 → 被分配者验证 → 分配关系创建 → 状态更新
|
||||
- **任务审批**: 权限验证 → 状态流转 → 审批记录 → 通知发送
|
||||
|
||||
#### TaskAssignmentService(任务分配服务)
|
||||
|
||||
**功能概述**
|
||||
- **接口定义**: `TaskAssignmentService`
|
||||
- **实现类**: `TaskAssignmentServiceImpl`
|
||||
- **业务价值**: 处理任务分配操作
|
||||
- **核心特性**: 未分配任务查询、网格员查询、任务分配
|
||||
|
||||
**核心方法**
|
||||
```java
|
||||
public interface TaskAssignmentService {
|
||||
List<Feedback> getUnassignedFeedback();
|
||||
List<UserAccount> getAvailableGridWorkers();
|
||||
Assignment assignTask(Long feedbackId, Long assigneeId, Long assignerId);
|
||||
}
|
||||
```
|
||||
|
||||
#### GridWorkerTaskService(网格员任务服务)
|
||||
|
||||
**功能概述**
|
||||
- **接口定义**: `GridWorkerTaskService`
|
||||
- **实现类**: `GridWorkerTaskServiceImpl`
|
||||
- **业务价值**: 处理网格员的任务管理操作
|
||||
- **核心特性**: 任务查询、状态流转、任务提交
|
||||
|
||||
**核心方法**
|
||||
```java
|
||||
public interface GridWorkerTaskService {
|
||||
Page<TaskSummaryDTO> getAssignedTasks(Long workerId, TaskStatus status, Pageable pageable);
|
||||
TaskDetailDTO getTaskDetail(Long taskId, Long workerId);
|
||||
void acceptTask(Long taskId, Long workerId);
|
||||
void startTask(Long taskId, Long workerId);
|
||||
void submitTask(Long taskId, TaskSubmissionRequest request, MultipartFile[] files);
|
||||
List<TaskSummaryDTO> getTasksNearLocation(Double latitude, Double longitude, Double radiusKm);
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 监管审核相关Service
|
||||
|
||||
#### SupervisorService(主管服务)
|
||||
|
||||
**功能概述**
|
||||
- **接口定义**: `SupervisorService`
|
||||
- **实现类**: `SupervisorServiceImpl`
|
||||
- **业务价值**: 处理主管的审核操作
|
||||
- **核心特性**: 反馈审核、审批决策
|
||||
|
||||
**核心方法**
|
||||
```java
|
||||
public interface SupervisorService {
|
||||
List<Feedback> getFeedbackForReview();
|
||||
void approveFeedback(Long feedbackId);
|
||||
void rejectFeedback(Long feedbackId, RejectFeedbackRequest request);
|
||||
}
|
||||
```
|
||||
|
||||
### 6. 数据分析相关Service
|
||||
|
||||
#### DashboardService(仪表盘服务)
|
||||
|
||||
**功能概述**
|
||||
- **接口定义**: `DashboardService`
|
||||
- **实现类**: `DashboardServiceImpl`
|
||||
- **业务价值**: 提供各类环境监测数据的统计和可视化数据
|
||||
- **核心特性**: 环境质量指标统计、AQI数据分布、热力图数据、趋势分析
|
||||
|
||||
**核心方法**
|
||||
```java
|
||||
public interface DashboardService {
|
||||
// 统计数据
|
||||
List<PollutionStatsDTO> getPollutionStats();
|
||||
TaskStatsDTO getTaskStats();
|
||||
DashboardStatsDTO getDashboardStats();
|
||||
|
||||
// AQI数据
|
||||
List<AqiDistributionDTO> getAqiDistribution();
|
||||
List<AqiHeatmapPointDTO> getAqiHeatmapData();
|
||||
List<TrendDataPointDTO> getMonthlyExceedanceTrend();
|
||||
|
||||
// 热力图数据
|
||||
List<HeatmapPointDTO> getFeedbackHeatmapData();
|
||||
|
||||
// 网格覆盖
|
||||
List<GridCoverageDTO> getGridCoverageByCity();
|
||||
|
||||
// 阈值管理
|
||||
List<PollutantThresholdDTO> getAllThresholds();
|
||||
PollutantThresholdDTO updateThreshold(String pollutantName, Double threshold);
|
||||
}
|
||||
```
|
||||
|
||||
### 7. 基础设施相关Service
|
||||
|
||||
#### FileStorageService(文件存储服务)
|
||||
|
||||
**功能概述**
|
||||
- **接口定义**: `FileStorageService`
|
||||
- **实现类**: `FileStorageServiceImpl`
|
||||
- **业务价值**: 处理文件上传和下载
|
||||
- **核心特性**: 安全文件存储、文件关联管理、下载服务
|
||||
|
||||
**核心方法**
|
||||
```java
|
||||
public interface FileStorageService {
|
||||
@Deprecated
|
||||
Attachment storeFileAndCreateAttachment(MultipartFile file, Feedback feedback);
|
||||
String storeFile(MultipartFile file);
|
||||
Resource loadFileAsResource(String fileName);
|
||||
void deleteFile(String fileName);
|
||||
}
|
||||
```
|
||||
|
||||
#### MailService(邮件服务)
|
||||
|
||||
**功能概述**
|
||||
- **接口定义**: `MailService`
|
||||
- **实现类**: `MailServiceImpl`
|
||||
- **业务价值**: 发送各类邮件
|
||||
- **核心特性**: 密码重置邮件、注册验证码邮件
|
||||
|
||||
**核心方法**
|
||||
```java
|
||||
public interface MailService {
|
||||
void sendPasswordResetEmail(String to, String code);
|
||||
void sendVerificationCodeEmail(String to, String code);
|
||||
}
|
||||
```
|
||||
|
||||
#### GridService(网格服务)
|
||||
|
||||
**功能概述**
|
||||
- **接口定义**: `GridService`
|
||||
- **实现类**: `GridServiceImpl`
|
||||
- **业务价值**: 处理网格数据的查询和更新
|
||||
- **核心特性**: 网格查询、网格员分配、网格更新
|
||||
|
||||
**核心方法**
|
||||
```java
|
||||
public interface GridService {
|
||||
List<Grid> getAllGrids();
|
||||
Optional<Grid> getGridById(Long gridId);
|
||||
UserAccount assignWorkerToGrid(Long gridId, Long userId);
|
||||
void unassignWorkerFromGrid(Long gridId);
|
||||
Page<Grid> getGridsWithFilters(String cityName, Boolean isObstacle, Pageable pageable);
|
||||
Grid updateGrid(Long gridId, GridUpdateRequest request);
|
||||
}
|
||||
```
|
||||
|
||||
### 8. 算法服务
|
||||
|
||||
#### AStarService(A*寻路服务)
|
||||
|
||||
**功能概述**
|
||||
- **服务类**: `AStarService`(直接实现,无接口)
|
||||
- **业务价值**: 提供A*寻路算法实现
|
||||
- **核心特性**: 最短路径计算、障碍物避让、网格导航
|
||||
|
||||
**核心方法**
|
||||
```java
|
||||
@Service
|
||||
public class AStarService {
|
||||
public List<Point> findPath(Point start, Point end);
|
||||
private int calculateHeuristic(Point a, Point b);
|
||||
private List<Point> getNeighbors(Point point);
|
||||
private List<Point> reconstructPath(Node endNode);
|
||||
}
|
||||
```
|
||||
|
||||
## Service设计特点
|
||||
|
||||
### 1. 分层架构设计
|
||||
- **接口与实现分离**: 所有业务服务都定义了接口,便于测试和扩展
|
||||
- **职责单一原则**: 每个服务专注于特定的业务领域
|
||||
- **依赖注入**: 使用Spring的依赖注入管理服务间依赖
|
||||
- **事务管理**: 在服务层统一管理事务边界
|
||||
|
||||
### 2. 业务逻辑封装
|
||||
- **复杂业务流程**: 将复杂的业务逻辑封装在服务方法中
|
||||
- **数据转换**: 在服务层完成实体与DTO之间的转换
|
||||
- **业务验证**: 在服务层进行业务规则验证
|
||||
- **异常处理**: 统一的业务异常处理机制
|
||||
|
||||
### 3. 安全控制
|
||||
- **权限验证**: 在服务层进行细粒度的权限控制
|
||||
- **数据安全**: 敏感数据的加密和脱敏处理
|
||||
- **审计日志**: 关键操作的审计日志记录
|
||||
- **防护机制**: 防止各种安全攻击的保护措施
|
||||
|
||||
### 4. 性能优化
|
||||
- **缓存策略**: 合理使用缓存提升性能
|
||||
- **批量处理**: 支持批量操作减少数据库访问
|
||||
- **异步处理**: 使用异步机制处理耗时操作
|
||||
- **分页查询**: 大数据量查询的分页处理
|
||||
|
||||
## Service架构优势
|
||||
|
||||
### 1. 业务完整性
|
||||
- **端到端流程**: 完整的业务流程实现
|
||||
- **状态管理**: 复杂的业务状态流转管理
|
||||
- **数据一致性**: 确保业务数据的一致性
|
||||
- **业务规则**: 完整的业务规则实现
|
||||
|
||||
### 2. 系统集成
|
||||
- **外部服务**: 与外部系统的集成接口
|
||||
- **事件驱动**: 基于事件的松耦合架构
|
||||
- **消息传递**: 系统间的消息传递机制
|
||||
- **API网关**: 统一的API访问入口
|
||||
|
||||
### 3. 扩展性强
|
||||
- **插件化**: 支持插件化的功能扩展
|
||||
- **配置驱动**: 基于配置的功能开关
|
||||
- **版本兼容**: 向后兼容的版本升级
|
||||
- **模块化**: 模块化的服务设计
|
||||
|
||||
### 4. 维护性好
|
||||
- **代码规范**: 统一的代码规范和风格
|
||||
- **文档完整**: 完整的接口文档和注释
|
||||
- **测试覆盖**: 高覆盖率的单元测试和集成测试
|
||||
- **监控告警**: 完善的监控和告警机制
|
||||
|
||||
## 技术实现细节
|
||||
|
||||
### 1. Spring注解
|
||||
```java
|
||||
@Service // 标识为服务组件
|
||||
@Transactional // 事务管理
|
||||
@RequiredArgsConstructor // Lombok构造器注入
|
||||
@Slf4j // 日志记录
|
||||
@Async // 异步处理
|
||||
@EventListener // 事件监听
|
||||
@Cacheable // 缓存支持
|
||||
```
|
||||
|
||||
### 2. 事务管理
|
||||
```java
|
||||
@Transactional(readOnly = true) // 只读事务
|
||||
@Transactional(rollbackFor = Exception.class) // 异常回滚
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW) // 事务传播
|
||||
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) // 事务事件
|
||||
```
|
||||
|
||||
### 3. 安全控制
|
||||
```java
|
||||
@PreAuthorize("hasRole('ADMIN')") // 方法级权限控制
|
||||
@PostAuthorize("returnObject.owner == authentication.name") // 返回值权限控制
|
||||
SecurityContextHolder.getContext().getAuthentication() // 获取当前用户
|
||||
```
|
||||
|
||||
### 4. 异常处理
|
||||
```java
|
||||
@ControllerAdvice // 全局异常处理
|
||||
@ExceptionHandler // 特定异常处理
|
||||
try-catch-finally // 局部异常处理
|
||||
throw new BusinessException() // 业务异常抛出
|
||||
```
|
||||
|
||||
## Service模块最佳实践
|
||||
|
||||
1. **接口设计**: 保持接口简洁,方法职责单一
|
||||
2. **事务边界**: 合理设置事务边界,避免长事务
|
||||
3. **异常处理**: 统一的异常处理策略,提供有意义的错误信息
|
||||
4. **参数验证**: 在服务入口进行参数验证
|
||||
5. **日志记录**: 记录关键业务操作和异常信息
|
||||
6. **性能监控**: 监控服务性能,及时发现瓶颈
|
||||
7. **单元测试**: 为每个服务方法编写单元测试
|
||||
8. **文档维护**: 保持接口文档和代码注释的同步更新
|
||||
|
||||
## Service模块总结
|
||||
|
||||
Service模块为EMS系统提供了完整、高质量的业务服务层:
|
||||
|
||||
1. **业务完整**: 覆盖环境监管系统的所有核心业务功能
|
||||
2. **架构清晰**: 分层明确、职责单一、依赖合理
|
||||
3. **安全可靠**: 完善的安全控制和异常处理机制
|
||||
4. **性能优化**: 多种性能优化策略和监控机制
|
||||
5. **扩展性强**: 支持业务功能的灵活扩展和配置
|
||||
6. **维护性好**: 代码规范、文档完整、测试覆盖率高
|
||||
7. **技术先进**: 采用Spring生态的最佳实践和现代化技术
|
||||
|
||||
通过这套完整的Service层,EMS系统建立了稳定、高效的业务处理能力,为前端应用提供了可靠的业务支撑,确保了系统的业务完整性和技术先进性。
|
||||
|
||||
---
|
||||
|
||||
# Security模块详细解析
|
||||
|
||||
## 概述
|
||||
|
||||
Security(安全模块)位于 `com.dne.ems.security` 包下,包含4个核心安全组件,构成了EMS系统完整的安全防护体系。该模块基于Spring Security框架,实现了JWT无状态认证、细粒度权限控制、CORS跨域支持和安全过滤机制,为整个系统提供了企业级的安全保障。
|
||||
|
||||
## 核心Security组件
|
||||
|
||||
### 1. CustomUserDetails(自定义用户详情)
|
||||
|
||||
**功能概述**
|
||||
- **类定义**: `CustomUserDetails`
|
||||
- **实现接口**: `UserDetails`
|
||||
- **业务价值**: 封装用户认证和授权信息,桥接业务用户实体与Spring Security
|
||||
- **核心特性**: 用户信息封装、权限映射、账户状态管理、角色权限控制
|
||||
|
||||
**核心方法**
|
||||
```java
|
||||
public class CustomUserDetails implements UserDetails {
|
||||
private final UserAccount userAccount;
|
||||
|
||||
// 业务信息获取
|
||||
public Long getId();
|
||||
public String getName();
|
||||
public Role getRole();
|
||||
public String getPhone();
|
||||
public UserStatus getStatus();
|
||||
public String getRegion();
|
||||
public List<String> getSkills();
|
||||
|
||||
// Spring Security标准接口实现
|
||||
public Collection<? extends GrantedAuthority> getAuthorities();
|
||||
public String getPassword();
|
||||
public String getUsername(); // 使用邮箱作为用户名
|
||||
public boolean isAccountNonExpired();
|
||||
public boolean isAccountNonLocked(); // 基于lockoutEndTime实现锁定逻辑
|
||||
public boolean isCredentialsNonExpired();
|
||||
public boolean isEnabled(); // 基于enabled和status字段
|
||||
}
|
||||
```
|
||||
|
||||
**设计特点**
|
||||
- **权限映射**: 自动添加"ROLE_"前缀,确保与Spring Security的hasRole()方法兼容
|
||||
- **账户锁定**: 基于lockoutEndTime字段实现动态账户锁定机制
|
||||
- **状态检查**: 综合enabled字段和UserStatus枚举进行账户状态验证
|
||||
- **信息暴露**: 提供完整的用户业务信息访问接口
|
||||
|
||||
### 2. JwtAuthenticationFilter(JWT认证过滤器)
|
||||
|
||||
**功能概述**
|
||||
- **类定义**: `JwtAuthenticationFilter`
|
||||
- **继承关系**: `OncePerRequestFilter`
|
||||
- **业务价值**: 处理每个HTTP请求的JWT认证,实现无状态认证机制
|
||||
- **核心特性**: JWT令牌提取、令牌验证、用户加载、安全上下文设置
|
||||
|
||||
**核心方法**
|
||||
```java
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
private final JwtService jwtService;
|
||||
private final UserDetailsService userDetailsService;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
FilterChain filterChain) throws ServletException, IOException;
|
||||
}
|
||||
```
|
||||
|
||||
**工作流程**
|
||||
1. **路径检查**: 跳过认证相关路径(/api/auth)
|
||||
2. **令牌提取**: 从Authorization头提取Bearer令牌
|
||||
3. **令牌验证**: 验证JWT签名和有效期
|
||||
4. **用户加载**: 根据令牌中的用户名加载用户详情
|
||||
5. **上下文设置**: 创建认证对象并设置到SecurityContext
|
||||
|
||||
**安全特性**
|
||||
- **一次性过滤**: 继承OncePerRequestFilter确保每个请求只过滤一次
|
||||
- **路径跳过**: 智能跳过不需要认证的路径
|
||||
- **令牌格式**: 严格验证Bearer令牌格式
|
||||
- **上下文管理**: 正确设置Spring Security上下文
|
||||
|
||||
### 3. SecurityConfig(安全配置)
|
||||
|
||||
**功能概述**
|
||||
- **类定义**: `SecurityConfig`
|
||||
- **配置注解**: `@Configuration`, `@EnableWebSecurity`, `@EnableMethodSecurity`
|
||||
- **业务价值**: 定义系统整体安全策略和访问控制规则
|
||||
- **核心特性**: HTTP安全配置、CORS配置、认证管理、密码编码
|
||||
|
||||
**核心配置方法**
|
||||
```java
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
|
||||
@RequiredArgsConstructor
|
||||
public class SecurityConfig {
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception;
|
||||
|
||||
@Bean
|
||||
CorsConfigurationSource corsConfigurationSource();
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager(AuthenticationConfiguration config);
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder();
|
||||
}
|
||||
```
|
||||
|
||||
**安全规则配置**
|
||||
```java
|
||||
// HTTP安全配置
|
||||
http
|
||||
.csrf(AbstractHttpConfigurer::disable) // 禁用CSRF(使用JWT)
|
||||
.cors(cors -> cors.configurationSource(corsConfigurationSource())) // 启用CORS
|
||||
.authorizeHttpRequests(authorize -> authorize
|
||||
// 允许OPTIONS预检请求
|
||||
.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
|
||||
// 认证相关端点
|
||||
.requestMatchers("/api/auth/**").permitAll()
|
||||
// 公共访问端点
|
||||
.requestMatchers("/api/public/**", "/api/map/**", "/api/pathfinding/**").permitAll()
|
||||
// 文件访问端点
|
||||
.requestMatchers("/api/files/**").permitAll()
|
||||
// Dashboard端点权限控制
|
||||
.requestMatchers("/api/dashboard/**").hasAnyRole("ADMIN", "DECISION_MAKER")
|
||||
// 其他请求需要认证
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.sessionManagement(session -> session
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 无状态会话
|
||||
)
|
||||
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
```
|
||||
|
||||
**CORS配置**
|
||||
```java
|
||||
@Bean
|
||||
CorsConfigurationSource corsConfigurationSource() {
|
||||
CorsConfiguration configuration = new CorsConfiguration();
|
||||
configuration.addAllowedOrigin("*"); // 允许所有来源
|
||||
configuration.addAllowedMethod("*"); // 允许所有HTTP方法
|
||||
configuration.addAllowedHeader("*"); // 允许所有HTTP头
|
||||
// 注册到所有路径
|
||||
source.registerCorsConfiguration("/**", configuration);
|
||||
return source;
|
||||
}
|
||||
```
|
||||
|
||||
**安全特性**
|
||||
- **无状态认证**: 基于JWT的无状态会话管理
|
||||
- **CSRF防护**: 禁用CSRF(因使用JWT令牌)
|
||||
- **方法级权限**: 启用@PreAuthorize、@Secured、@RolesAllowed注解
|
||||
- **细粒度控制**: 基于URL模式的访问控制
|
||||
- **密码安全**: 使用BCrypt强密码编码
|
||||
|
||||
### 4. UserDetailsServiceImpl(用户详情服务实现)
|
||||
|
||||
**功能概述**
|
||||
- **类定义**: `UserDetailsServiceImpl`
|
||||
- **实现接口**: `UserDetailsService`
|
||||
- **业务价值**: 为Spring Security提供用户加载服务
|
||||
- **核心特性**: 用户查找、账户锁定检查、异常处理
|
||||
|
||||
**核心方法**
|
||||
```java
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class UserDetailsServiceImpl implements UserDetailsService {
|
||||
private final UserAccountRepository userAccountRepository;
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
// 根据邮箱查找用户
|
||||
UserAccount userAccount = userAccountRepository.findByEmail(username)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("未找到邮箱为 " + username + " 的用户。"));
|
||||
|
||||
// 检查账户锁定状态
|
||||
if (userAccount.getLockoutEndTime() != null &&
|
||||
userAccount.getLockoutEndTime().isAfter(LocalDateTime.now())) {
|
||||
throw new LockedException("该账户已被锁定,请稍后再试。");
|
||||
}
|
||||
|
||||
return new CustomUserDetails(userAccount);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**业务逻辑**
|
||||
- **用户查找**: 使用邮箱作为用户名进行查找
|
||||
- **锁定检查**: 检查lockoutEndTime字段判断账户是否被锁定
|
||||
- **异常处理**: 提供清晰的中文错误信息
|
||||
- **对象封装**: 返回CustomUserDetails包装的用户信息
|
||||
|
||||
## Security模块设计特点
|
||||
|
||||
### 1. 无状态认证架构
|
||||
- **JWT令牌**: 使用JWT实现无状态认证,避免服务器端会话存储
|
||||
- **令牌验证**: 每个请求都进行令牌验证,确保安全性
|
||||
- **过期管理**: 自动处理令牌过期和刷新
|
||||
- **跨服务**: 支持微服务架构下的认证共享
|
||||
|
||||
### 2. 细粒度权限控制
|
||||
- **角色映射**: 自动处理Spring Security角色前缀
|
||||
- **方法级权限**: 支持@PreAuthorize等注解进行方法级控制
|
||||
- **URL级权限**: 基于URL模式的访问控制
|
||||
- **动态权限**: 支持运行时权限检查
|
||||
|
||||
### 3. 安全防护机制
|
||||
- **CSRF防护**: 针对JWT场景禁用CSRF
|
||||
- **CORS支持**: 完整的跨域资源共享配置
|
||||
- **账户锁定**: 基于时间的账户锁定机制
|
||||
- **密码安全**: BCrypt强密码编码
|
||||
|
||||
### 4. 异常处理
|
||||
- **用户友好**: 提供中文错误信息
|
||||
- **安全考虑**: 不泄露敏感信息
|
||||
- **分类处理**: 区分不同类型的认证异常
|
||||
- **日志记录**: 记录安全相关事件
|
||||
|
||||
## Security架构优势
|
||||
|
||||
### 1. 安全性强
|
||||
- **多层防护**: 从过滤器到方法级的多层安全防护
|
||||
- **标准实现**: 基于Spring Security标准实现
|
||||
- **最佳实践**: 采用业界安全最佳实践
|
||||
- **持续更新**: 跟随Spring Security版本更新
|
||||
|
||||
### 2. 性能优化
|
||||
- **无状态设计**: 避免服务器端会话存储开销
|
||||
- **一次性过滤**: 每个请求只进行一次安全检查
|
||||
- **缓存友好**: 支持用户信息缓存
|
||||
- **轻量级**: 最小化安全检查开销
|
||||
|
||||
### 3. 扩展性好
|
||||
- **插件化**: 支持自定义安全组件
|
||||
- **配置驱动**: 基于配置的安全策略
|
||||
- **接口标准**: 遵循Spring Security接口标准
|
||||
- **模块化**: 各安全组件职责清晰
|
||||
|
||||
### 4. 维护性强
|
||||
- **代码清晰**: 结构清晰,职责明确
|
||||
- **文档完整**: 详细的注释和文档
|
||||
- **测试友好**: 易于进行单元测试和集成测试
|
||||
- **监控支持**: 支持安全事件监控
|
||||
|
||||
## 技术实现细节
|
||||
|
||||
### 1. Spring Security注解
|
||||
```java
|
||||
@EnableWebSecurity // 启用Web安全
|
||||
@EnableMethodSecurity // 启用方法级安全
|
||||
@Component // 组件注册
|
||||
@Service // 服务注册
|
||||
@RequiredArgsConstructor // 构造器注入
|
||||
```
|
||||
|
||||
### 2. JWT处理
|
||||
```java
|
||||
// JWT令牌提取
|
||||
String jwt = authHeader.substring(7); // 移除"Bearer "前缀
|
||||
String userEmail = jwtService.extractUserName(jwt);
|
||||
|
||||
// JWT令牌验证
|
||||
if (jwtService.isTokenValid(jwt, userDetails)) {
|
||||
// 设置认证上下文
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 权限控制
|
||||
```java
|
||||
// 角色权限映射
|
||||
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_" + getRole().name());
|
||||
|
||||
// URL权限控制
|
||||
.requestMatchers("/api/dashboard/**").hasAnyRole("ADMIN", "DECISION_MAKER")
|
||||
|
||||
// 方法级权限控制
|
||||
@PreAuthorize("hasRole('ADMIN')")
|
||||
public void adminOnlyMethod() { }
|
||||
```
|
||||
|
||||
### 4. 异常处理
|
||||
```java
|
||||
// 用户不存在异常
|
||||
throw new UsernameNotFoundException("未找到邮箱为 " + username + " 的用户。");
|
||||
|
||||
// 账户锁定异常
|
||||
throw new LockedException("该账户已被锁定,请稍后再试。");
|
||||
```
|
||||
|
||||
## Security模块最佳实践
|
||||
|
||||
1. **令牌管理**: 合理设置JWT过期时间,实现令牌刷新机制
|
||||
2. **权限设计**: 采用最小权限原则,细粒度控制访问权限
|
||||
3. **异常处理**: 提供用户友好的错误信息,避免泄露敏感信息
|
||||
4. **日志记录**: 记录关键安全事件,便于审计和监控
|
||||
5. **配置管理**: 将安全配置外部化,支持不同环境配置
|
||||
6. **测试覆盖**: 编写完整的安全测试用例
|
||||
7. **定期更新**: 及时更新安全依赖,修复安全漏洞
|
||||
8. **监控告警**: 建立安全事件监控和告警机制
|
||||
|
||||
## Security模块总结
|
||||
|
||||
Security模块为EMS系统提供了完整、可靠的安全防护体系:
|
||||
|
||||
1. **认证完整**: 基于JWT的无状态认证机制,支持多种认证场景
|
||||
2. **授权精确**: 细粒度的权限控制,从URL到方法级的全面覆盖
|
||||
3. **防护全面**: CSRF、CORS、账户锁定等多重安全防护
|
||||
4. **性能优秀**: 无状态设计,最小化安全检查开销
|
||||
5. **扩展性强**: 模块化设计,支持自定义安全组件
|
||||
6. **维护性好**: 代码清晰,文档完整,易于维护和扩展
|
||||
7. **标准兼容**: 完全基于Spring Security标准,确保兼容性
|
||||
|
||||
通过这套完整的Security模块,EMS系统建立了企业级的安全防护能力,确保了用户数据安全、系统访问控制和业务操作的安全性,为整个系统提供了坚实的安全基础。
|
||||
@@ -1,183 +0,0 @@
|
||||
# 主管任务管理功能 - 设计文档
|
||||
|
||||
## 1. 功能描述
|
||||
本功能模块是系统管理(NEPM)端的核心,赋予**主管**监控所有待处理反馈,并通过手动或智能两种模式,将勘查任务高效、合理地分配给一线网格员的能力。智能分配是本模块的亮点,旨在优化资源配置,提升响应效率。
|
||||
|
||||
## 2. 涉及角色
|
||||
- **主要使用者**: `业务主管 (SUPERVISOR)`
|
||||
- **被分配者**: `网格员 (GRID_WORKER)`
|
||||
|
||||
## 3. 业务规则
|
||||
|
||||
### 3.1 任务池规则
|
||||
- 所有通过AI审核,状态为`PENDING_ASSIGNMENT`的反馈,都会进入任务分配池,展示在**主管**的工作台。
|
||||
- 任务池中的任务应支持多维度筛选(如`区域`、`污染类型`、`严重等级`)和排序。
|
||||
|
||||
### 3.2 手动分配规则
|
||||
- **主管**可以勾选一个或多个任务。
|
||||
- 然后,**主管**可以从其管辖范围内的网格员列表中,选择一个或多个来执行任务。
|
||||
- 分配后,系统会为每一个"任务-网格员"配对创建一条`assignment_record`记录。
|
||||
|
||||
### 3.3 智能分配规则
|
||||
- **触发**: **主管**选择一个任务,点击"智能分配"按钮。
|
||||
- **地图模型**: 分配算法基于简化的二维网格地图。
|
||||
- **第一步:候选集生成**:
|
||||
- 系统获取任务所在的网格坐标 (Tx, Ty)。
|
||||
- 以 (Tx, Ty) 为中心,搜索**半径10个网格单位**内的所有网格。
|
||||
- 从中筛选出状态为`ACTIVE`且有对应`skills`的网格员,形成候选集。
|
||||
- **第二步:最优人选计算**:
|
||||
- 对候选集中的每个网格员 (Gx, Gy),使用**A\*算法**计算其到目标网格的**最短路径距离 (D)**,算法需能识别并绕开`is_obstacle`为`true`的障碍网格。
|
||||
- **ETR (预计任务响应时间)** 公式: `ETR = D + (该网格员当前待处理的任务量)`。
|
||||
- ETR值**最小**的网格员即为最优人选。
|
||||
- **第三步:推荐与确认**:
|
||||
- 系统在界面上高亮推荐最优人选。
|
||||
- **主管**可以接受推荐,一键分配;也可以忽略推荐,手动选择其他候选人。
|
||||
- **算法细节记录**: 每次智能分配成功后,应将计算出的ETR、候选人列表等关键信息,以JSON格式快照存入`assignment_record`表的`algorithmDetails`字段,便于审计和追溯。
|
||||
|
||||
### 3.4 任务创建与审核规则
|
||||
- **创建任务**: 主管可不依赖公众反馈,直接在系统中创建新任务,指派给特定网格员。创建的任务直接进入`ASSIGNED`状态。
|
||||
- **审核任务**: 主管负责审核网格员提交的状态为`SUBMITTED`的任务。
|
||||
- **批准**: 任务状态变为 `COMPLETED`。
|
||||
- **拒绝**: 任务状态退回 `ASSIGNED`,并附上拒绝理由,网格员需重新处理。
|
||||
|
||||
### 3.5 ETR算法优化
|
||||
为了使智能分配更精准,ETR(预计任务响应时间)的计算公式将引入更多权重因子。
|
||||
- **基础公式**: `ETR = (A*路径距离) + (当前任务数)`
|
||||
- **优化后公式**:
|
||||
`Score = (Wd * D) + (Wn * N) - (Ws * S) + (Wp * P)`
|
||||
- `D`: A*算法计算出的路径距离。
|
||||
- `N`: 网格员当前待办任务数量。
|
||||
- `S`: 技能匹配度。如果网格员的`skills`与任务的`pollutionType`匹配,则S=1,否则S=0。
|
||||
- `P`: 任务优先级。高优先级任务P=10,中=5,低=0。用于打破僵局。
|
||||
- `Wd, Wn, Ws, Wp`: 分别是距离、任务数、技能、优先级的权重系数,可在系统配置中调整。
|
||||
- **最终选择Score最小的网格员**。
|
||||
|
||||
### 3.6 边界情况处理
|
||||
- **无可用网格员**: 在指定的搜索半径内,若没有符合条件的`ACTIVE`状态的网格员,系统应提示主管"当前区域无可用网格员,请扩大搜索范围或手动从全局列表选择"。
|
||||
- **智能分配失败**: 若因地图数据不完整等原因导致A*算法无法找到路径,系统应提示"路径计算失败,请手动分配"。
|
||||
|
||||
## 4. 功能实现流程
|
||||
|
||||
### 4.1 任务分配流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[登录NEPM端] --> B[进入任务分配页面];
|
||||
B --> C[查看"待处理"反馈列表];
|
||||
|
||||
C --> D{选择一个反馈};
|
||||
D --> E{选择分配模式};
|
||||
|
||||
E -- 手动分配 --> F[手动勾选网格员];
|
||||
E -- 智能分配 --> G[系统执行A*算法<br>计算ETR并推荐人选];
|
||||
|
||||
G --> H{主管是否<br>接受推荐?};
|
||||
H -- 是 --> I[确认分配给<br>推荐人选];
|
||||
H -- 否 --> F;
|
||||
|
||||
F --> J[确认分配];
|
||||
I --> J;
|
||||
|
||||
J --> K[创建AssignmentRecord];
|
||||
K --> L[更新Feedback状态<br>为ASSIGNED];
|
||||
L --> M[通过NEPG端<br>通知网格员];
|
||||
|
||||
style G fill:#E3F2FD
|
||||
style L fill:#C8E6C9
|
||||
```
|
||||
|
||||
### 4.2 任务审核流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[主管进入"待审核"任务列表] --> B{选择一个任务};
|
||||
B --> C[查看网格员提交的报告和图片];
|
||||
C --> D{审核是否通过?};
|
||||
D -- 是 --> E[更新任务状态为 COMPLETED];
|
||||
D -- 否 --> F[填写拒绝理由];
|
||||
F --> G[更新任务状态为 ASSIGNED];
|
||||
G --> H[通知网格员重新处理];
|
||||
|
||||
style E fill:#C8E6C9;
|
||||
style G fill:#FFCDD2;
|
||||
```
|
||||
|
||||
## 5. API 接口设计
|
||||
|
||||
### 5.1 查询待处理反馈列表
|
||||
- **URL**: `GET /api/management/tasks/pending`
|
||||
- **权限**: `SUPERVISOR`
|
||||
- **查询参数**: `region`, `pollutionType`, `severity`, `page`, `size`
|
||||
- **成功响应** (`200 OK`): 返回分页的反馈列表。
|
||||
|
||||
### 5.2 查询可用网格员列表
|
||||
- **URL**: `GET /api/management/grid-workers/available`
|
||||
- **权限**: `SUPERVISOR`
|
||||
- **查询参数**: `region`
|
||||
- **成功响应** (`200 OK`): 返回指定区域内所有状态为`ACTIVE`的网格员列表,包含其当前位置和任务负载。
|
||||
|
||||
### 5.3 手动分配任务
|
||||
- **URL**: `POST /api/management/tasks/assign/manual`
|
||||
- **权限**: `SUPERVISOR`
|
||||
- **请求体**:
|
||||
```json
|
||||
{
|
||||
"feedbackId": 123,
|
||||
"gridWorkerIds": [10, 15],
|
||||
"remarks": "请尽快处理"
|
||||
}
|
||||
```
|
||||
- **成功响应** (`200 OK`): `{ "message": "任务分配成功" }`
|
||||
|
||||
### 5.4 智能分配任务
|
||||
- **URL**: `POST /api/management/tasks/assign/intelligent`
|
||||
- **权限**: `SUPERVISOR`
|
||||
- **请求体**: `{"feedbackId": 123}`
|
||||
- **成功响应** (`200 OK`): 返回包含最优人选和候选集信息的JSON,供前端渲染。
|
||||
```json
|
||||
{
|
||||
"recommended": { "userId": 10, "name": "王伟", "score": 15.8, ... },
|
||||
"candidates": [ ... ]
|
||||
}
|
||||
```
|
||||
|
||||
### 5.5 审核任务
|
||||
- **URL**: `POST /api/management/tasks/{taskId}/review`
|
||||
- **权限**: `SUPERVISOR`
|
||||
- **请求体**:
|
||||
```json
|
||||
{
|
||||
"approved": false,
|
||||
"comments": "图片不清晰,请重新拍摄现场照片。"
|
||||
}
|
||||
```
|
||||
- **成功响应** (`200 OK`): `{ "message": "审核操作已完成" }`
|
||||
|
||||
## 6. 界面设计要求
|
||||
|
||||
### 6.1 任务分配主页面
|
||||
- **布局**: 采用左右分栏布局。
|
||||
- **左侧**: 待处理反馈列表。以紧凑的列表或表格形式展示,包含`标题`、`区域`、`严重等级`。提供筛选和搜索功能。
|
||||
- **右侧**: 网格员地图视图。实时展示所选反馈位置,以及管辖区域内所有网格员的分布。**每个网格员的图标应能通过大小或颜色深浅,直观反映其当前的负载(待处理任务数)**。
|
||||
- **交互**:
|
||||
- 点击左侧列表中的一个反馈项,右侧地图应立即定位到该反馈所在的网格,并高亮显示。
|
||||
- 同时,地图上应以不同颜色或图标区分网格员的实时状态(如`空闲`-绿色,`繁忙`-橙色,`休假`-灰色)。
|
||||
|
||||
### 6.2 分配操作界面
|
||||
- **触发**: **主管**在左侧列表中选中一个反馈后,列表项下方出现"手动分配"和"智能分配"两个按钮。
|
||||
- **手动分配**:
|
||||
- 点击后,弹出一个包含所有可选网格员列表的对话框。
|
||||
- 列表支持搜索和多选。
|
||||
- **主管**勾选后点击确认即可分配。
|
||||
- **智能分配**:
|
||||
- 点击后,右侧地图视图进入"推荐模式"。
|
||||
- 系统计算后,在地图上用醒目的高亮效果(如闪烁的星星或光圈)标记出最优人选。
|
||||
- 同时,在地图下方或侧边栏显示一个信息卡片,包含推荐人选的姓名、当前任务量、**技能匹配度**、**距离**和最终的**推荐分数**,并提供一个"一键分配"按钮。
|
||||
- 其他候选人以普通方式显示,**主管**仍可点击查看其分数详情并选择。
|
||||
|
||||
### 6.3 任务创建页面
|
||||
- 提供一个独立的表单页面,允许主管填写`标题`、`描述`、`污染类型`、`严重等级`、`地理位置`等所有任务相关信息。
|
||||
- 表单下方直接集成一个网格员选择器,方便主管创建后立即指派。
|
||||
|
||||
### 6.4 任务审核页面
|
||||
- 这是一个任务详情页面,顶部清晰展示任务基础信息。
|
||||
- 页面核心区域展示网格员提交的报告,包括文字说明和图片(图片支持点击放大预览)。
|
||||
- 页面底部提供"批准"和"拒绝"两个操作按钮。点击"拒绝"时,必须弹出一个对话框,要求主管填写拒绝理由。
|
||||
@@ -1,129 +0,0 @@
|
||||
# 主管审核与任务分配功能 - 设计文档
|
||||
|
||||
## 1. 功能描述
|
||||
本功能模块是NEPM(后台管理端)的核心组成部分,专为`主管 (SUPERVISOR)`和`管理员 (ADMIN)`角色设计。它弥合了AI自动审核与人工任务分配之间的鸿沟,确保了只有经过人工确认的有效反馈才能进入网格员的处理流程。
|
||||
|
||||
主要职责包括:
|
||||
- **审核**: 对AI初审通过的反馈 (`PENDING_REVIEW`) 进行人工复核。
|
||||
- **决策**: 决定该反馈是应该继续流转 (`PENDING_ASSIGNMENT`) 还是直接关闭 (`CLOSED_INVALID`)。
|
||||
- **分配**: 将审核通过的有效反馈手动指派给特定的`网格员 (GRID_WORKER)`。
|
||||
|
||||
## 2. 业务流程
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "AI自动审核"
|
||||
A[反馈状态: PENDING_REVIEW]
|
||||
end
|
||||
|
||||
subgraph "主管人工审核 (Supervisor/Admin 操作)"
|
||||
A --> B{主管查看待审核列表};
|
||||
B --> C{审核决策};
|
||||
C -- 审核通过 --> D[调用 Approve API<br>/api/supervisor/reviews/{id}/approve];
|
||||
C -- 审核拒绝 --> E[调用 Reject API<br>/api/supervisor/reviews/{id}/reject];
|
||||
end
|
||||
|
||||
subgraph "后端服务"
|
||||
D --> F[反馈状态变为<br>PENDING_ASSIGNMENT];
|
||||
E --> G[反馈状态变为<br>CLOSED_INVALID];
|
||||
end
|
||||
|
||||
subgraph "主管手动分配"
|
||||
F --> H{主管在任务分配界面<br>查看待分配列表};
|
||||
H --> I{选择反馈 + 选择网格员};
|
||||
I --> J[调用 Assign API<br>/api/task-assignment/assign];
|
||||
end
|
||||
|
||||
subgraph "后端服务"
|
||||
J --> K[创建 Assignment 记录<br>反馈状态变为 ASSIGNED];
|
||||
end
|
||||
|
||||
style F fill:#C8E6C9,stroke:#333
|
||||
style G fill:#FFCDD2,stroke:#333
|
||||
style K fill:#B3E5FC,stroke:#333
|
||||
```
|
||||
|
||||
## 3. API 接口设计
|
||||
|
||||
### 3.1 主管审核接口 (SupervisorController)
|
||||
|
||||
#### 3.1.1 获取待审核反馈列表
|
||||
- **URL**: `GET /api/supervisor/reviews`
|
||||
- **描述**: 获取所有状态为 `PENDING_REVIEW` 的反馈,供主管进行人工审核。
|
||||
- **权限**: `SUPERVISOR`, `ADMIN`
|
||||
- **成功响应** (`200 OK`): 返回 `Feedback` 对象数组。
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 101,
|
||||
"eventId": "uuid-...",
|
||||
"title": "...",
|
||||
"status": "PENDING_REVIEW",
|
||||
...
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
#### 3.1.2 批准反馈
|
||||
- **URL**: `POST /api/supervisor/reviews/{feedbackId}/approve`
|
||||
- **描述**: 主管批准一个反馈,使其进入待分配状态。
|
||||
- **权限**: `SUPERVISOR`, `ADMIN`
|
||||
- **路径参数**: `feedbackId` (Long) - 要批准的反馈ID。
|
||||
- **成功响应** (`200 OK`): 无内容。
|
||||
- **失败响应**:
|
||||
- `400 Bad Request`: 如果反馈状态不是 `PENDING_REVIEW`。
|
||||
- `404 Not Found`: 如果 `feedbackId` 不存在。
|
||||
|
||||
#### 3.1.3 拒绝反馈
|
||||
- **URL**: `POST /api/supervisor/reviews/{feedbackId}/reject`
|
||||
- **描述**: 主管拒绝一个反馈,将其关闭。
|
||||
- **权限**: `SUPERVISOR`, `ADMIN`
|
||||
- **路径参数**: `feedbackId` (Long) - 要拒绝的反馈ID。
|
||||
- **成功响应** (`200 OK`): 无内容。
|
||||
- **失败响应**:
|
||||
- `400 Bad Request`: 如果反馈状态不是 `PENDING_REVIEW`。
|
||||
- `404 Not Found`: 如果 `feedbackId` 不存在。
|
||||
|
||||
|
||||
### 3.2 任务分配接口 (TaskAssignmentController)
|
||||
|
||||
#### 3.2.1 获取待分配反馈列表
|
||||
- **URL**: `GET /api/task-assignment/unassigned-feedback`
|
||||
- **描述**: 获取所有状态为 `PENDING_ASSIGNMENT` 的反馈,即已通过主管审核,等待分配。
|
||||
- **权限**: `SUPERVISOR`, `ADMIN`
|
||||
- **成功响应** (`200 OK`): 返回 `Feedback` 对象数组。
|
||||
|
||||
#### 3.2.2 获取可用网格员列表
|
||||
- **URL**: `GET /api/task-assignment/available-workers`
|
||||
- **描述**: 获取所有角色为 `GRID_WORKER` 的用户列表,用于分配任务时的选择器。
|
||||
- **权限**: `SUPERVISOR`, `ADMIN`
|
||||
- **成功响应** (`200 OK`): 返回 `UserAccount` 对象数组。
|
||||
|
||||
#### 3.2.3 分配任务
|
||||
- **URL**: `POST /api/task-assignment/assign`
|
||||
- **描述**: 将一个反馈任务指派给一个网格员。
|
||||
- **权限**: `SUPERVISOR`, `ADMIN`
|
||||
- **请求体**:
|
||||
```json
|
||||
{
|
||||
"feedbackId": 101,
|
||||
"assigneeId": 205
|
||||
}
|
||||
```
|
||||
- **成功响应** (`201 Created`): 返回新创建的 `Assignment` 对象。
|
||||
- **失败响应**:
|
||||
- `400 Bad Request`: 如果反馈状态不是 `PENDING_ASSIGNMENT` 或用户不是网格员。
|
||||
- `404 Not Found`: 如果 `feedbackId` 或 `assigneeId` 不存在。
|
||||
|
||||
## 4. 状态机详解
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
state "AI审核通过" as PendingReview
|
||||
state "待分配" as PendingAssignment
|
||||
state "已关闭" as ClosedInvalid
|
||||
state "已分配" as Assigned
|
||||
|
||||
PendingReview --> PendingAssignment: 主管批准
|
||||
PendingReview --> ClosedInvalid: 主管拒绝
|
||||
|
||||
PendingAssignment --> Assigned: 主管分配任务
|
||||
```
|
||||
@@ -1,142 +0,0 @@
|
||||
# 公众反馈功能 - 设计文档
|
||||
|
||||
## 1. 功能描述
|
||||
本功能是系统面向公众的核心入口(NEPS端),允许公众监督员提交图文并茂的空气质量问题反馈。提交后,系统将**异步调用AI服务**对反馈内容进行审核,最终将有效反馈转化为待处理的任务,送入内部管理流程。
|
||||
|
||||
## 2. 涉及角色
|
||||
- **主要使用者**: `公众监督员 (PUBLIC_SUPERVISOR)` 或任何已认证用户
|
||||
- **间接关联者**: `主管 (SUPERVISOR)` (作为反馈的接收和处理者)
|
||||
|
||||
## 3. 业务规则
|
||||
|
||||
### 3.1 提交规则
|
||||
- 用户必须处于**已认证 (Authenticated)** 状态才能提交反馈。
|
||||
- 提交时,`标题`、`污染类型`、`严重等级`、`地理位置`为必填项。
|
||||
- 地理位置通过前端组件获取,同时生成`文字地址`和`地理坐标(经纬度)`,一并提交给后端。
|
||||
|
||||
### 3.2 AI处理规则
|
||||
- **模型**: 所有AI处理均调用火山引擎的大语言模型API。
|
||||
- **触发方式**: 用户提交反馈后,系统立即将反馈状态置为 `AI_REVIEWING`,并发布一个**异步事件**来触发AI审核,不会阻塞用户的提交操作。
|
||||
- **审核逻辑**: AI服务会对用户提交的`标题`、`描述`和`图片`进行**单阶段审核**,通过Function Calling能力,**同时判断**以下两点:
|
||||
- `is_compliant`: 内容是否合规(不含敏感词等)。
|
||||
- `is_relevant`: 内容是否与大气污染问题相关。
|
||||
- **输出**:
|
||||
- 若AI判断为**合规且相关**,则反馈状态更新为 `PENDING_REVIEW`。
|
||||
- 若AI判断为**不合规或不相关**,则反馈状态更新为 `CLOSED_INVALID`。
|
||||
- 若AI服务调用**失败**(如网络异常、API错误),则反馈状态更新为 `AI_REVIEW_FAILED`,以便后续人工介入或重试。
|
||||
|
||||
### 3.3 事件ID规则
|
||||
- 反馈创建时,系统后端自动使用 `UUID.randomUUID().toString()` 生成一个唯一的字符串作为 `eventId`。
|
||||
|
||||
## 4. 功能实现流程
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "NEPS 端 (用户操作)"
|
||||
A[填写反馈表单] --> B{点击提交};
|
||||
end
|
||||
|
||||
subgraph "后端服务 (自动化流程)"
|
||||
B --> C[创建Feedback记录<br>status: AI_REVIEWING];
|
||||
C --> D{发布异步事件<br>触发AI审核};
|
||||
D -- AI审核成功<br>合规且相关 --> F[status: PENDING_REVIEW];
|
||||
D -- AI审核成功<br>不合规或不相关 --> G[status: CLOSED_INVALID];
|
||||
D -- AI服务调用失败 --> H[status: AI_REVIEW_FAILED];
|
||||
end
|
||||
|
||||
subgraph "NEPM 端 (后续操作)"
|
||||
F --> I[进入主管审核列表];
|
||||
end
|
||||
|
||||
style C fill:#E3F2FD,stroke:#333
|
||||
style G fill:#FFCDD2,stroke:#333
|
||||
style H fill:#FFE0B2,stroke:#333
|
||||
style F fill:#C8E6C9,stroke:#333
|
||||
```
|
||||
|
||||
## 5. API 接口设计
|
||||
|
||||
### 5.1 提交反馈接口
|
||||
|
||||
- **URL**: `POST /api/feedback/submit`
|
||||
- **描述**: 用户提交新的环境问题反馈。
|
||||
- **权限**: `isAuthenticated()` (任何已认证用户)
|
||||
- **请求类型**: `multipart/form-data`
|
||||
- **请求体**:
|
||||
- `feedback` (JSON字符串,DTO: `FeedbackSubmissionRequest`):
|
||||
```json
|
||||
{
|
||||
"title": "长安区工业园附近空气异味严重",
|
||||
"description": "每天下午都能闻到刺鼻的气味...",
|
||||
"pollutionType": "OTHER",
|
||||
"severityLevel": "HIGH",
|
||||
"location": {
|
||||
"latitude": 38.04,
|
||||
"longitude": 114.5
|
||||
}
|
||||
}
|
||||
```
|
||||
- `files` (File数组): 用户上传的图片文件(可选)。
|
||||
- **成功响应** (`201 Created`):
|
||||
- 返回创建的 `Feedback` 实体JSON对象,其中包含由后端生成的`id`和`eventId`(UUID格式)。
|
||||
|
||||
- **失败响应**:
|
||||
- `400 Bad Request`: 表单验证失败。
|
||||
- `401 Unauthorized`: 用户未登录。
|
||||
- `413 Payload Too Large`: 上传文件过大。
|
||||
- `500 Internal Server Error`: 服务器内部错误。
|
||||
|
||||
## 6. 状态机详解
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> AI_REVIEWING: 用户提交
|
||||
|
||||
AI_REVIEWING --> PENDING_REVIEW: AI审核通过
|
||||
AI_REVIEWING --> CLOSED_INVALID: AI审核拒绝 (内容问题)
|
||||
AI_REVIEWING --> AI_REVIEW_FAILED: AI审核失败 (技术问题)
|
||||
|
||||
PENDING_REVIEW: 待主管审核
|
||||
CLOSED_INVALID: 已关闭/无效
|
||||
AI_REVIEW_FAILED: AI审核失败
|
||||
|
||||
state PENDING_REVIEW {
|
||||
note right of PENDING_REVIEW
|
||||
此状态的反馈将出现在
|
||||
主管的管理界面中,
|
||||
等待人工处理。
|
||||
end note
|
||||
}
|
||||
```
|
||||
|
||||
## 7. 错误处理与边界情况
|
||||
| 场景 | 触发条件 | 系统处理 | 用户提示 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **表单验证失败** | 必填项为空或格式不正确 | 后端返回`400`错误,不创建记录 | 在对应表单项下方显示红色错误提示 |
|
||||
| **文件上传失败** | 文件过大、格式不支持、网络中断 | 后端返回`413`或`500`错误 | 弹出全局错误消息:"图片上传失败,请稍后重试" |
|
||||
| **AI服务调用异常**| AI接口超时或返回错误码 | ① `AiReviewService`捕获异常<br>② 将反馈状态设置为`AI_REVIEW_FAILED`并保存<br>③ 流程终止,等待人工处理 | 对用户无感知,后台自动处理 |
|
||||
| **用户重复提交** | 用户快速点击提交按钮 | 前端在点击后禁用按钮并显示加载动画;<br>后端对相同用户的请求在短时间内进行幂等性处理 | "正在提交,请稍候..." |
|
||||
|
||||
## 8. 界面与交互细节
|
||||
|
||||
### 8.1 反馈提交页面 (NEPS)
|
||||
- **表单设计**:
|
||||
- `标题`: 单行文本输入框。
|
||||
- `描述`: 多行文本域,允许输入较长内容。
|
||||
- `污染类型`: **单选框 (Radio Group)** 或 **下拉选择框 (Select)**,选项为`PM2.5`, `O3`, `NO2`, `SO2`, `OTHER`。
|
||||
- `严重等级`: **单选框 (Radio Group)**,选项为`高`, `中`, `低`,并附有简单的解释说明。
|
||||
- `地理位置`: 提供一个地图选点组件,用户点击地图即可自动填充文字地址和网格坐标。也应允许用户手动输入地址。
|
||||
- `照片上传`: 提供一个图片上传组件,支持多选、预览和删除已上传的图片。**明确提示支持的格式(JPG, PNG)和大小限制**。
|
||||
- **交互细节**:
|
||||
- **加载状态**: 点击"确认提交"后,按钮变为"提交中..."并显示加载动画,同时整个表单区域置为不可编辑状态。
|
||||
- **成功提示**: 提交成功后,弹出一个全局成功的消息提示(e.g., "提交成功!感谢您的反馈。"),并自动跳转到反馈历史页面。
|
||||
- **失败提示**: 如果提交失败,根据错误类型给出明确的全局错误提示,并保持表单内容,让用户可以修改后重新提交。
|
||||
|
||||
### 8.2 反馈历史页面 (NEPS)
|
||||
- 以列表形式展示用户所有提交过的反馈。
|
||||
- 每个列表项应以卡片形式展示,包含`标题`, `提交时间`, `事件ID`, 和一个醒目的**`状态标签`**。
|
||||
- **状态标签**:
|
||||
- `待审核`: 蓝色或灰色
|
||||
- `待分配`: 橙色
|
||||
- `已分配`/`处理中`/`已提交`/`已完成`: 绿色
|
||||
- `已作废`/`已取消`: 红色
|
||||
- 点击卡片可进入反馈详情页,查看所有提交信息、`事件ID`和处理流程的详细时间线。
|
||||
- 对于状态为`PENDING_REVIEW`或`PENDING_ASSIGNMENT`的反馈,详情页提供"撤销提交"按钮。点击后需**二次确认弹窗**,防止误操作。
|
||||
@@ -1,170 +0,0 @@
|
||||
# 决策者大屏功能 - 设计文档
|
||||
|
||||
## 1. 功能描述
|
||||
本功能模块是专为决策者和高级管理员(NEPV端)设计的全局态势感知中心。它通过一系列数据可视化图表、关键绩效指标(KPI)和地图,将系统采集和处理的海量数据,转化为直观、易于理解的宏观洞察,旨在为环保工作的战略规划和决策提供强有力的数据支持。
|
||||
|
||||
## 2. 涉及角色
|
||||
- **主要使用者**: `决策者 (DECISION_MAKER)`
|
||||
- **次要使用者**: `系统管理员 (ADMIN)` (需要访问以进行日常运营监控)
|
||||
|
||||
## 3. 业务规则
|
||||
|
||||
### 3.1 权限与数据规则
|
||||
- **完全只读**: 大屏上的所有元素均为只读,不提供任何数据修改、删除或提交的入口。
|
||||
- **数据聚合性**: 除非特殊说明,大屏展示的数据均为聚合后的统计结果(如区域平均值、月度总数),不暴露任何单个反馈或用户的详细隐私信息。
|
||||
- **实时性**: 部分KPI指标(如"今日新增反馈")要求准实时更新,后端需提供高效的查询接口。大部分统计图表数据可通过后台定时任务(如每小时或每日)预计算并缓存,以提升加载性能。
|
||||
- **实时性与缓存**:
|
||||
- **实时数据**: 关键KPI指标(如"今日新增反馈")和实时检测数量图,应通过WebSocket或短轮询实现准实时更新。
|
||||
- **缓存策略**: 大部分统计图表(如月度趋势、类型分布)的数据应由后端的定时任务(如每小时)预先计算,并存储在Redis等内存数据库中。前端请求API时,直接从缓存读取,极大提升加载速度。缓存的Key设计应包含日期和区域等维度,例如`dashboard:aqi_trend:2024-07`。
|
||||
- **缓存失效**: 定时任务在生成新数据后,会覆盖旧的缓存,实现自动更新。
|
||||
|
||||
### 3.2 核心组件数据来源
|
||||
- **KPI指标卡**: 直接查询数据库,对`feedback`和`user_account`等表进行快速COUNT或AVG聚合。
|
||||
- **统计图表 (趋势图、分布图)**: 由后端的聚合服务,基于`aqi_data`和`feedback`表,按指定维度(时间、类型)进行GROUP BY计算后生成。
|
||||
- **污染源热力图**: 后端聚合`feedback`表中的`grid_x`, `grid_y`坐标和`severityLevel`,生成一个包含坐标和权重的数据集,供前端渲染。数据同样需要被缓存。
|
||||
- **AI年度报告**:
|
||||
- 由一个年度批处理任务(Cron Job)在每年年底或次年年初自动触发。
|
||||
- 该任务负责从数据库抽取全年关键统计数据,形成一份综合材料。
|
||||
- 调用`deepseek-v3-250324`大模型API,将结构化的统计数据和分析要点作为Prompt,生成一份图文并茂的分析报告。
|
||||
- 生成的报告(如PDF或Markdown格式)存储在文件服务器上,大屏端仅提供一个下载链接。
|
||||
|
||||
### 3.3 交互设计规则
|
||||
- **全局筛选**: 在大屏顶部或侧边提供全局筛选控件,至少包括 **时间范围选择器**(如"近7天", "本月", "本年", 自定义范围)和 **区域选择器**(当下钻到省市级别时)。所有组件都应响应这些筛选条件的变化。
|
||||
- **图表联动与下钻**:
|
||||
- **联动**: 点击饼图的某个扇区(如"工业污染"),其他图表(如AQI趋势图、热力图)应能自动筛选并重新渲染,仅显示与"工业污染"相关的数据。
|
||||
- **下钻**: 在地图或区域排行榜上,点击某个省份,可以下钻到该省的市级数据视图。此时,应有明显的面包屑导航提示当前所处的层级(如"全国 > 浙江省")。
|
||||
|
||||
## 4. 功能实现流程
|
||||
|
||||
### 4.1 数据流架构
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "数据源 (DB)"
|
||||
A[aqi_data]
|
||||
B[feedback]
|
||||
C[user_account]
|
||||
end
|
||||
|
||||
subgraph "数据处理层"
|
||||
D[定时聚合服务 (Cron Job)]
|
||||
E[实时API服务]
|
||||
F[<br><br><b>缓存 (Redis)</b><br><br>]
|
||||
end
|
||||
|
||||
subgraph "前端大屏 (NEPV)"
|
||||
G[KPI 指标卡]
|
||||
H[AQI 趋势图]
|
||||
I[污染类型分布图]
|
||||
J[污染源热力图]
|
||||
K[年度报告下载]
|
||||
L[WebSocket 连接]
|
||||
end
|
||||
|
||||
A & B & C --> D
|
||||
D --> F
|
||||
B & C --> E
|
||||
|
||||
E -- 实时查询 --> G
|
||||
E -- 建立长连接 --> L
|
||||
L -- 推送实时数据 --> G
|
||||
|
||||
F -- 读取缓存 --> H
|
||||
F -- 读取缓存 --> I
|
||||
F -- 读取缓存 --> J
|
||||
|
||||
subgraph "AI服务"
|
||||
M[AI报告生成服务 (Annual Cron)]
|
||||
N[大模型 API]
|
||||
O[文件服务器]
|
||||
end
|
||||
|
||||
A & B & C --> M
|
||||
M --> N
|
||||
N --> M
|
||||
M --> O
|
||||
O --> K
|
||||
```
|
||||
|
||||
### 4.2 AI年度报告生成时序图
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Cron as "年度定时任务 (Cron Job)"
|
||||
participant Service as "报告生成服务"
|
||||
participant DB as "数据库"
|
||||
participant LLM as "大模型API"
|
||||
participant Storage as "文件服务器 (S3/MinIO)"
|
||||
|
||||
Cron->>Service: 触发年度报告生成任务 (e.g., for year 2024)
|
||||
Service->>DB: 查询全年关键数据 (AQI, Feedback, etc.)
|
||||
DB-->>Service: 返回年度统计数据
|
||||
Service->>Service: 根据数据构建Prompt (包含统计表格和分析要点)
|
||||
Service->>LLM: 发送请求 (POST /api/generate-report)
|
||||
LLM-->>Service: 返回生成的报告内容 (Markdown/HTML)
|
||||
Service->>Service: (可选) 将报告内容渲染为PDF
|
||||
Service->>Storage: 上传报告文件 (e.g., report-2024.pdf)
|
||||
Storage-->>Service: 返回文件URL
|
||||
Service->>DB: 将报告URL存入`annual_reports`表
|
||||
DB-->>Service: 存储成功
|
||||
```
|
||||
|
||||
## 5. API 接口设计
|
||||
|
||||
### 5.1 KPI 指标接口
|
||||
- **URL**: `GET /api/data-v/kpis`
|
||||
- **查询参数**: `?timeRange=...&area=...`
|
||||
- **响应**: `200 OK`, 返回 `[{ "title": "累计反馈总数", "value": 1024, "change": "+5%" }, ...]`
|
||||
|
||||
### 5.2 图表数据接口 (通用)
|
||||
- **URL**: `GET /api/data-v/chart`
|
||||
- **查询参数**: `?name=aqiTrend&timeRange=...&area=...` (name用于指定图表类型)
|
||||
- **响应**: `200 OK`, 返回符合ECharts等图表库格式要求的数据结构。
|
||||
|
||||
### 5.3 热力图数据接口
|
||||
- **URL**: `GET /api/data-v/heatmap`
|
||||
- **查询参数**: `?timeRange=...&area=...`
|
||||
- **响应**: `200 OK`, 返回 `[{ "lng": 120.15, "lat": 30.28, "count": 95 }, ...]`
|
||||
|
||||
### 5.4 实时数据推送
|
||||
- **WebSocket**: `ws://your-domain/api/data-v/realtime`
|
||||
- **推送消息格式**: `{ "type": "newFeedback", "data": { ... } }` or `{ "type": "kpiUpdate", "data": { ... } }`
|
||||
|
||||
## 6. 界面设计要求
|
||||
|
||||
### 6.1 整体布局与风格
|
||||
- **主题**: 采用深色科技感主题(如深蓝色、暗灰色背景),以突出数据图表的色彩。
|
||||
- **布局**: 基于`1920x1080`分辨率进行设计,采用栅格系统(如24列)进行灵活布局,确保在主流大屏上不变形。
|
||||
- **组件**: 所有可视化组件(Widgets)以卡片形式组织,每个卡片都有清晰的标题。
|
||||
- **交互性**: 所有图表在鼠标悬浮时应显示详细的Tooltip提示。支持点击事件,用于图表间的联动和下钻。
|
||||
- **技术选型**: 推荐使用成熟的图表库,如`ECharts`或`AntV`,来实现高质量的可视化效果。
|
||||
|
||||
### 6.2 核心可视化组件详解
|
||||
|
||||
- **顶部 - KPI指标行 & 全局筛选器**:
|
||||
- 在屏幕顶端横向排列4-6个核心指标卡。
|
||||
- 指标行旁边或下方设置全局筛选器,包括时间范围和区域选择。
|
||||
- 每个卡片包含一个醒目的图标、一个加粗的巨大数值、和一个清晰的指标名称(如"累计反馈总数"、"当前活跃网格员"、"本月平均AQI")。
|
||||
|
||||
- **中部 - 可交互的污染源热力图**:
|
||||
- **需求**: 在地图上查看可视化污染源热力图。
|
||||
- **呈现形式**: 占据屏幕最大面积的核心组件。在二维网格地图上,根据各网格内高严重等级反馈的数量和权重,用不同的颜色(如从蓝色到红色)渲染,形成热力效果。地图应支持基本的缩放和拖拽操作。
|
||||
|
||||
- **图表组件 - 左侧面板**:
|
||||
- **空气质量超标趋势图 (折线图)**:
|
||||
- **需求**: 查看过去12个月的空气质量超标趋势。
|
||||
- **呈现形式**: X轴为过去12个月份,Y轴为超标天数或超标事件次数。用平滑的曲线展示AQI超标趋势,并可提供与去年同期的对比线。
|
||||
- **总AQI及分项污染物超标统计 (柱形图)**:
|
||||
- **需求**: 查看总AQI及各分项污染物浓度超标的累计统计。
|
||||
- **呈现形式**: X轴为污染物类型(总AQI, PM2.5, O3, NO2, SO2等),Y轴为本年度累计超标次数。每个污染物为一根柱子,清晰对比。
|
||||
|
||||
- **图表组件 - 右侧面板**:
|
||||
- **AQI级别分布图 (饼图)**:
|
||||
- **需求**: 查看AQI级别分布。
|
||||
- **呈现形式**: 标准饼图,将AQI数据按标准(优、良、轻度污染、中度污染、重度污染、严重污染)划分,展示各级别占比。
|
||||
- **各省市网格覆盖率 (饼图)**:
|
||||
- **需求**: 查看各省市的网格覆盖率。
|
||||
- **呈现形式**: 饼图展示已覆盖与未覆盖网格的**总体比例**。为获得更佳体验,可提供下钻功能或辅以排行榜/地图着色展示各省市详情。
|
||||
- **实时空气质量检测数量 (实时折线图)**:
|
||||
- **需求**: 查看实时的空气质量检测数量统计。
|
||||
- **呈现形式**: X轴为过去24小时,Y轴为该时段内完成的AQI检测数,线条实时或准实时更新。
|
||||
- **AI年度报告下载**:
|
||||
- 一个简洁的卡片,包含报告年份,和一个醒目的"下载报告"按钮。
|
||||
145
Design/总体设计.md
145
Design/总体设计.md
@@ -1,145 +0,0 @@
|
||||
# 东软环保公众监督系统 - 总体设计文档
|
||||
|
||||
## 1. 项目背景与目标
|
||||
|
||||
### 1.1 项目背景
|
||||
随着公众环保意识的增强和环境问题的日益复杂化,传统单一的环境监督模式已难以满足现代社会的需求。为提升环境治理的效率、透明度和公众参与度,我们提出构建一个创新的、多端协同的环保监督平台——"东软环保公众监督系统"。
|
||||
|
||||
### 1.2 需求背景
|
||||
本项目的核心需求源于对现有环保监督流程的优化渴望。当前流程存在信息传递链条长、问题响应慢、数据孤岛效应明显、公众参与感不强等痛点。系统旨在通过整合公众、一线网格员、系统管理者和宏观决策者的力量,打通从问题发现、数据上报、任务分配、现场核实到数据分析和决策支持的全流程闭环。
|
||||
|
||||
### 1.3 项目目标
|
||||
- **提升监督效率**:通过AI预审和智能化任务分配,缩短问题响应时间。
|
||||
- **强化公众参与**:提供便捷、透明的反馈渠道,激励公众成为环保监督的"眼睛"。
|
||||
- **实现数据驱动**:将零散的反馈数据转化为结构化的、可供分析决策的宝贵资产。
|
||||
- **构建管理闭环**:打造一个覆盖"公众-执行-管理-决策"四位一体的协同工作平台。
|
||||
|
||||
## 2. 功能总体描述
|
||||
系统整体上由四个功能明确、相互独立的客户端构成,共同协作完成环保监督任务。
|
||||
|
||||
- **NEPS端 (公众监督员端)**: 系统的公众入口,允许用户注册、提交污染反馈、追踪反馈处理进度,并查看个人统计数据。
|
||||
- **NEPG端 (AQI检测网格员端)**: 一线执行人员的操作平台,用于接收任务、在简化的网格地图上进行路径指引、提交现场勘查的AQI数据报告。
|
||||
- **NEPM端 (系统管理端)**: 系统的"大脑",供**主管(Supervisor)**审核反馈、通过手动或智能模式分配任务;同时供**系统管理员(Admin)**管理系统用户、角色及权限。
|
||||
- **NEPV端 (可视化大屏端)**: 决策支持中心,以数据可视化的方式向决策者展示区域环境态势、污染热力图、治理成效等宏观指标,并提供AI生成的年度报告。
|
||||
|
||||
## 3. 技术架构选型
|
||||
|
||||
为保证系统的稳定性、可扩展性和开发效率,我们选择以下主流且成熟的技术栈:
|
||||
|
||||
### 3.1 开发语言
|
||||
- **后端**: Java 21 (充分利用其新特性,如虚拟线程、Record类等)
|
||||
- **前端**: TypeScript (为JavaScript提供类型安全,提升代码质量)
|
||||
|
||||
### 3.2 开发框架
|
||||
- **后端**: Spring Boot 3.x
|
||||
- **核心优势**: 自动化配置、强大的社区生态、内嵌Web服务器,能快速构建稳定、高效的RESTful API。
|
||||
- **关键组件**:
|
||||
- `Spring Web`: 构建Web应用和API。
|
||||
- `Spring Data JPA`: 简化数据库持久化操作。
|
||||
- `Spring Security`: 提供强大而灵活的认证和授权功能,保障系统安全。
|
||||
- `Spring Validation`: 进行数据校验。
|
||||
- **前端**: Vue 3.x
|
||||
- **核心优势**: 采用组合式API (Composition API),逻辑组织更清晰;基于Vite的构建工具,开发体验极佳;响应式系统性能优越。
|
||||
- **关键组件**:
|
||||
- `Vue Router`: 管理前端路由。
|
||||
- `Pinia`: 进行应用的状态管理。
|
||||
- `Axios`: 用于与后端API进行HTTP通信。
|
||||
- `Element Plus / Ant Design Vue`: 作为基础UI组件库,快速构建美观的界面。
|
||||
|
||||
### 3.3 数据库
|
||||
- **数据库**: MySQL 8.x
|
||||
- **核心优势**: 作为全球最受欢迎的开源关系型数据库,MySQL具有性能稳定、社区支持广泛、与Java及Spring Boot生态完美集成的优点。其成熟的事务处理和数据一致性保障能力,完全满足本项目对核心业务数据的存储需求。
|
||||
|
||||
### 3.4 关键第三方服务
|
||||
- **邮箱服务**: 调用163邮箱的SMTP API,实现注册、忘记密码等场景的动态验证码发送。
|
||||
- **AI大模型服务**: 调用火山引擎的`deepseek-v3-250324`模型API,实现对用户反馈的自动审核与关键信息提取。
|
||||
|
||||
## 4. 系统架构设计
|
||||
|
||||
### 4.1 总体架构图
|
||||
|
||||
系统采用微服务思想指导下的单体架构,前后端分离,四端统一调用后端API。这种设计在项目初期能保证快速迭代,同时为未来向微服务演进预留了空间。
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph 用户端
|
||||
A[NEPS 公众监督员端<br>(Vue3/H5)]
|
||||
B[NEPG 网格员端<br>(Vue3/H5)]
|
||||
C[NEPM 系统管理端<br>(Vue3/Web)]
|
||||
D[NEPV 可视化大屏端<br>(Vue3/Web)]
|
||||
end
|
||||
|
||||
subgraph "后端服务 (Spring Boot)"
|
||||
E(API网关<br>Spring Cloud Gateway)
|
||||
F[用户认证服务<br>Spring Security]
|
||||
G[反馈管理模块]
|
||||
H[任务管理模块]
|
||||
I[智能分配模块<br>A*算法]
|
||||
J[数据可视化模块]
|
||||
K[文件存储模块]
|
||||
end
|
||||
|
||||
subgraph "数据与服务"
|
||||
L[MySQL 8.x<br>主数据库]
|
||||
M[火山引擎<br>AI大模型]
|
||||
N[163邮箱<br>SMTP服务]
|
||||
end
|
||||
|
||||
A -->|HTTPS/REST API| E
|
||||
B -->|HTTPS/REST API| E
|
||||
C -->|HTTPS/REST API| E
|
||||
D -->|HTTPS/REST API| E
|
||||
|
||||
E --> F
|
||||
E --> G
|
||||
E --> H
|
||||
E --> I
|
||||
E --> J
|
||||
E --> K
|
||||
|
||||
F --> L
|
||||
G --> L
|
||||
H --> L
|
||||
I --> L
|
||||
J --> L
|
||||
K --> L
|
||||
|
||||
G -->|异步调用| M
|
||||
F -->|SMTP| N
|
||||
|
||||
```
|
||||
|
||||
### 4.2 核心数据流(问题处理流程)
|
||||
|
||||
1. **提交**: 公众监督员通过NEPS端提交环境问题反馈,数据进入后端`反馈管理模块`,初始状态为`AI审核中`。
|
||||
2. **审核**: `反馈管理模块`异步调用`火山引擎AI服务`进行内容审核与信息提取。审核通过后,状态更新为`待处理`。
|
||||
3. **分配**: 主管在NEPM端查看`待处理`的反馈。`任务管理模块`调用`智能分配模块`的A*算法,推荐最优网格员。主管确认后,生成任务并分配。
|
||||
4. **处理**: 网格员在NEPG端接收任务,前往现场处理,并提交包含AQI数据的报告。
|
||||
5. **审核与闭环**: 主管在NEPM端审核任务报告。审核通过则任务完成,状态更新为`已完成`;不通过则打回给网格员。
|
||||
6. **可视化**: 所有处理完成的数据,由`数据可视化模块`进行聚合与分析,最终在NEPV大屏端展示。
|
||||
|
||||
## 5. 非功能性需求设计
|
||||
|
||||
### 5.1 性能需求
|
||||
- **核心API响应时间**: 95%的核心API请求(如登录、任务查询)应在500ms内响应。
|
||||
- **AI处理时间**: AI审核与信息提取的异步处理过程应在30秒内完成。
|
||||
- **并发用户数**: 系统应支持至少500个并发用户在线,核心功能稳定运行。
|
||||
- **大屏刷新率**: NEPV端数据应支持分钟级刷新。
|
||||
|
||||
### 5.2 安全性需求
|
||||
- **认证与授权**: 所有API均需通过Spring Security进行认证和授权检查,防止未授权访问。
|
||||
- **数据传输**: 全站强制使用HTTPS,确保数据在传输过程中的加密。
|
||||
- **数据存储**: 用户密码、API密钥等敏感信息必须加密存储。
|
||||
- **防SQL注入**: 采用JPA和参数化查询,从根本上防止SQL注入攻击。
|
||||
- **防XSS攻击**: 前端对用户输入进行严格过滤和转义,防止跨站脚本攻击。
|
||||
|
||||
### 5.3 可扩展性需求
|
||||
- **模块化设计**: 后端业务逻辑严格按照模块划分,降低耦合度,便于未来将单个模块拆分为微服务。
|
||||
- **无状态服务**: 后端核心业务服务设计为无状态,便于水平扩展和负载均衡。
|
||||
- **消息队列**: (未来规划)引入RabbitMQ或Kafka,实现服务间的异步解耦,提升系统的削峰填谷和弹性能力。
|
||||
|
||||
### 5.4 可维护性需求
|
||||
- **统一编码规范**: 全项目遵循统一的Java和TypeScript编码规范。
|
||||
- **日志记录**: 对关键业务流程和异常情况进行详细的结构化日志记录,便于问题排查。
|
||||
- **API文档**: 使用Swagger/OpenAPI自动生成并维护最新的API文档。
|
||||
- **模块化前端**: 前端代码按四端和功能模块组织,提高代码的可读性和复用性。
|
||||
267
Design/数据库设计.md
267
Design/数据库设计.md
@@ -1,267 +0,0 @@
|
||||
# 东软环保公众监督系统 - 数据库设计文档
|
||||
|
||||
## 1. 设计概述
|
||||
本数据库设计旨在支持一个高效、可扩展的环保监督系统。设计遵循第三范式(3NF),通过主外键关联确保数据的一致性和完整性。所有表均采用`InnoDB`存储引擎,以支持事务和行级锁定。
|
||||
|
||||
- **命名规范**: 表名采用小写下划线命名法(e.g., `user_account`),字段名采用驼峰命名法(e.g., `createdAt`)。
|
||||
- **主键**: 所有表均包含一个`BIGINT`类型的自增主键`id`。
|
||||
- **时间戳**: 关键业务表包含`createdAt`和`updatedAt`字段,用于追踪记录的创建和最后修改时间。
|
||||
|
||||
## 2. 实体关系图 (E-R Diagram)
|
||||
```mermaid
|
||||
erDiagram
|
||||
USER_ACCOUNT }|--o{ FEEDBACK : "submits"
|
||||
USER_ACCOUNT }|--o{ ASSIGNMENT_RECORD : "assigns (as supervisor)"
|
||||
USER_ACCOUNT }|--o{ ASSIGNMENT_RECORD : "is assigned (as grid_worker)"
|
||||
USER_ACCOUNT }|--o{ AQI_DATA : "reports"
|
||||
USER_ACCOUNT }|--o{ USER_LOGIN_HISTORY : "logs"
|
||||
|
||||
FEEDBACK ||--|{ ASSIGNMENT_RECORD : "is subject of"
|
||||
FEEDBACK ||--o{ AQI_DATA : "is verified by"
|
||||
FEEDBACK ||--|{ FEEDBACK_IMAGE : "has"
|
||||
|
||||
GRID ||--o{ AQI_DATA : "is location for"
|
||||
|
||||
USER_ACCOUNT {
|
||||
BIGINT id PK
|
||||
VARCHAR name
|
||||
VARCHAR phone "UK"
|
||||
VARCHAR email "UK"
|
||||
VARCHAR password
|
||||
VARCHAR gender
|
||||
VARCHAR role
|
||||
VARCHAR status
|
||||
VARCHAR region
|
||||
VARCHAR level
|
||||
JSON skills
|
||||
DATETIME createdAt
|
||||
DATETIME updatedAt
|
||||
}
|
||||
|
||||
FEEDBACK {
|
||||
BIGINT id PK
|
||||
VARCHAR eventId "UK"
|
||||
VARCHAR title
|
||||
TEXT description
|
||||
VARCHAR pollutionType
|
||||
VARCHAR severityLevel
|
||||
VARCHAR status
|
||||
VARCHAR textAddress
|
||||
INT gridX
|
||||
INT gridY
|
||||
BIGINT submitterId FK
|
||||
DATETIME createdAt
|
||||
DATETIME updatedAt
|
||||
}
|
||||
|
||||
FEEDBACK_IMAGE {
|
||||
BIGINT id PK
|
||||
BIGINT feedbackId FK
|
||||
VARCHAR imageUrl "URL of the stored image"
|
||||
VARCHAR imageName
|
||||
DATETIME createdAt
|
||||
}
|
||||
|
||||
ASSIGNMENT_RECORD {
|
||||
BIGINT id PK
|
||||
BIGINT feedbackId FK
|
||||
BIGINT gridWorkerId FK
|
||||
BIGINT supervisorId FK
|
||||
VARCHAR assignmentMethod
|
||||
JSON algorithmDetails
|
||||
VARCHAR status
|
||||
DATETIME createdAt
|
||||
}
|
||||
|
||||
AQI_DATA {
|
||||
BIGINT id PK
|
||||
BIGINT feedbackId FK "Nullable"
|
||||
BIGINT gridId FK
|
||||
BIGINT reporterId FK
|
||||
DOUBLE aqiValue
|
||||
DOUBLE pm25
|
||||
DOUBLE pm10
|
||||
DOUBLE so2
|
||||
DOUBLE no2
|
||||
DOUBLE co
|
||||
DOUBLE o3
|
||||
DATETIME recordTime
|
||||
}
|
||||
|
||||
GRID {
|
||||
BIGINT id PK
|
||||
INT gridX
|
||||
INT gridY "UK"
|
||||
VARCHAR cityName
|
||||
VARCHAR districtName
|
||||
BOOLEAN isObstacle
|
||||
}
|
||||
|
||||
USER_LOGIN_HISTORY {
|
||||
BIGINT id PK
|
||||
BIGINT userId FK
|
||||
VARCHAR ipAddress
|
||||
VARCHAR userAgent
|
||||
VARCHAR status
|
||||
DATETIME loginTime
|
||||
}
|
||||
```
|
||||
|
||||
## 3. 数据表详细设计
|
||||
|
||||
### 3.1 用户表 (`user_account`)
|
||||
存储所有系统用户,包括公众、监督员、网格员、管理员和决策者。
|
||||
|
||||
| 字段名 | 数据类型 | 长度/约束 | 是否可空 | 默认值 | 描述 |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| `id` | `BIGINT` | `PK, AUTO_INCREMENT`| No | | 唯一主键 |
|
||||
| `name` | `VARCHAR`| 255 | No | | 真实姓名 |
|
||||
| `phone` | `VARCHAR`| 50 | No | | 手机号 (唯一,用于登录) |
|
||||
| `email` | `VARCHAR`| 255 | No | | 邮箱 (唯一,用于登录和验证) |
|
||||
| `password`| `VARCHAR`| 255 | No | | BCrypt加密后的密码 |
|
||||
| `gender` | `VARCHAR`| 10 | Yes | | 性别 (Enum: `MALE`, `FEMALE`, `UNKNOWN`) |
|
||||
| `role` | `VARCHAR`| 50 | No | `PUBLIC_SUPERVISOR` | 角色 (Enum: `PUBLIC_SUPERVISOR`, `SUPERVISOR` (业务主管), `GRID_WORKER` (网格员), `ADMIN` (系统管理员), `DECISION_MAKER` (决策者)) |
|
||||
| `status` | `VARCHAR`| 50 | No | `ACTIVE`| 账户状态 (Enum: `ACTIVE`, `INACTIVE`, `ON_LEAVE`) |
|
||||
| `region` | `VARCHAR`| 255| Yes | | 所属区域 (格式: "省-市-区") |
|
||||
| `level` | `VARCHAR`| 50 | Yes | | 行政级别 (Enum: `PROVINCE`, `CITY`) |
|
||||
| `skills` | `JSON` | | Yes | | 技能标签 (仅对网格员有效, e.g., `["PM2.5", "O3"]`) |
|
||||
| `createdAt` | `DATETIME` | | No | `CURRENT_TIMESTAMP` | 创建时间 |
|
||||
| `updatedAt` | `DATETIME` | | No | `CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP` | 更新时间 |
|
||||
|
||||
**索引设计**:
|
||||
- `PRIMARY KEY (id)`
|
||||
- `UNIQUE KEY uk_phone (phone)`
|
||||
- `UNIQUE KEY uk_email (email)`
|
||||
- `KEY idx_role_status (role, status)`
|
||||
- `KEY idx_region_level (region, level)`
|
||||
|
||||
### 3.2 反馈信息表 (`feedback`)
|
||||
存储由公众监督员提交的污染反馈信息。
|
||||
|
||||
| 字段名 | 数据类型 | 长度/约束 | 是否可空 | 默认值 | 描述 |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| `id` | `BIGINT` | `PK, AUTO_INCREMENT`| No | | 唯一主键 |
|
||||
| `eventId`| `VARCHAR`| 255 | `UK, NOT NULL` | | 业务事件ID (USR...格式),对用户可见、唯一 |
|
||||
| `title` | `VARCHAR`| 255 | No | | 反馈标题 |
|
||||
| `description`| `TEXT` | | Yes | | 详细描述 |
|
||||
| `pollutionType`|`VARCHAR`| 50 | No | | 污染类型 (Enum: `PM2.5`, `O3`, `NO2`, `SO2`, `OTHER`) |
|
||||
| `severityLevel`|`VARCHAR`| 50 | No | | 严重等级 (Enum: `LOW`, `MEDIUM`, `HIGH`) |
|
||||
| `status` | `VARCHAR`| 50 | No | `AI_REVIEWING`| 任务状态 (Enum: `AI_REVIEWING`, `AI_PROCESSING`, `PENDING_ASSIGNMENT`, `ASSIGNED`, `IN_PROGRESS`, `SUBMITTED`, `COMPLETED`, `CANCELLED`, `CLOSED_INVALID`) |
|
||||
| `textAddress`| `VARCHAR`| 255 | Yes | | 文字地址 (格式: "省份-城市-区") |
|
||||
| `gridX` | `INT` | | Yes | | 对应的网格X坐标 |
|
||||
| `gridY` | `INT` | | Yes | | 对应的网格Y坐标 |
|
||||
| `submitterId`| `BIGINT` | `FK -> user_account.id` | No | | 提交者ID |
|
||||
| `createdAt` | `DATETIME` | | No | `CURRENT_TIMESTAMP` | 创建时间 |
|
||||
| `updatedAt` | `DATETIME` | | No | `CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP` | 更新时间 |
|
||||
|
||||
**索引设计**:
|
||||
- `PRIMARY KEY (id)`
|
||||
- `UNIQUE KEY uk_event_id (eventId)`
|
||||
- `KEY idx_submitter_id (submitterId)`
|
||||
- `KEY idx_status_created_at (status, createdAt)`
|
||||
- `KEY idx_grid_coords (gridX, gridY)`
|
||||
|
||||
### 3.3 反馈图片表 (`feedback_image`)
|
||||
存储与反馈信息关联的图片。
|
||||
|
||||
| 字段名 | 数据类型 | 长度/约束 | 是否可空 | 默认值 | 描述 |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| `id` | `BIGINT` | `PK, AUTO_INCREMENT`| No | | 唯一主键 |
|
||||
| `feedbackId` | `BIGINT` | `FK -> feedback.id`| No | | 关联的反馈ID |
|
||||
| `imageUrl` | `VARCHAR`| 512 | No | | 存储的图片URL |
|
||||
| `imageName` | `VARCHAR`| 255 | Yes | | 图片原始文件名 |
|
||||
| `createdAt` | `DATETIME`| | No |`CURRENT_TIMESTAMP`| 创建时间 |
|
||||
|
||||
**索引设计**:
|
||||
- `PRIMARY KEY (id)`
|
||||
- `KEY idx_feedback_id (feedbackId)`
|
||||
|
||||
### 3.4 任务分配记录表 (`assignment_record`)
|
||||
记录每一次任务分配的详细信息。
|
||||
|
||||
| 字段名 | 数据类型 | 长度/约束 | 是否可空 | 默认值 | 描述 |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| `id` | `BIGINT` | `PK, AUTO_INCREMENT`| No | | 唯一主键 |
|
||||
| `feedbackId`| `BIGINT` | `FK -> feedback.id`| No | | 关联的反馈/任务ID |
|
||||
| `gridWorkerId`|`BIGINT`|`FK -> user_account.id`| No | | 被分配的网格员ID |
|
||||
| `supervisorId` | `BIGINT`| `FK -> user_account.id`| No | | 执行分配的主管ID |
|
||||
| `assignmentMethod`|`VARCHAR`|50| No | | 分配方式 (Enum: `MANUAL`, `INTELLIGENT`) |
|
||||
| `algorithmDetails`|`JSON`| | Yes | | 智能分配算法的快照 (e.g., ETR, 候选人) |
|
||||
| `status` | `VARCHAR`| 50 | No | `PENDING`| 分配状态 (Enum: `PENDING`, `ACCEPTED`, `REJECTED`) |
|
||||
| `createdAt` |`DATETIME`| | No |`CURRENT_TIMESTAMP`| 创建时间 |
|
||||
|
||||
**索引设计**:
|
||||
- `PRIMARY KEY (id)`
|
||||
- `KEY idx_feedback_id (feedbackId)`
|
||||
- `KEY idx_grid_worker_id_status (gridWorkerId, status)`
|
||||
- `KEY idx_supervisor_id (supervisorId)`
|
||||
|
||||
### 3.5 空气质量数据表 (`aqi_data`)
|
||||
存储网格员现场核查后上报的精确AQI数据。
|
||||
|
||||
| 字段名 | 数据类型 | 长度/约束 | 是否可空 | 默认值 | 描述 |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| `id` | `BIGINT` | `PK, AUTO_INCREMENT`| No | | 唯一主键 |
|
||||
| `feedbackId`| `BIGINT` | `FK -> feedback.id`| Yes | | 关联的反馈ID (可为空,支持主动上报) |
|
||||
| `gridId` | `BIGINT` | `FK -> grid.id`| No | | 数据采集所在的网格ID |
|
||||
| `reporterId`| `BIGINT` | `FK -> user_account.id`| No | | 上报人ID(网格员)|
|
||||
| `aqiValue` | `DOUBLE` | | Yes | | 综合AQI指数 |
|
||||
| `pm25` | `DOUBLE` | | Yes | | PM2.5读数 (μg/m³) |
|
||||
| `pm10` | `DOUBLE` | | Yes | | PM10读数 (μg/m³) |
|
||||
| `so2` | `DOUBLE` | | Yes | | 二氧化硫读数 (μg/m³) |
|
||||
| `no2` | `DOUBLE` | | Yes | | 二氧化氮读数 (μg/m³) |
|
||||
| `co` | `DOUBLE` | | Yes | | 一氧化碳读数 (mg/m³) |
|
||||
| `o3` | `DOUBLE` | | Yes | | 臭氧读数 (μg/m³) |
|
||||
| `recordTime`|`DATETIME`| | No |`CURRENT_TIMESTAMP`| 记录时间 |
|
||||
|
||||
**索引设计**:
|
||||
- `PRIMARY KEY (id)`
|
||||
- `KEY idx_feedback_id (feedbackId)`
|
||||
- `KEY idx_grid_id_record_time (gridId, recordTime)`
|
||||
- `KEY idx_reporter_id (reporterId)`
|
||||
|
||||
### 3.6 网格地图表 (`grid`)
|
||||
定义抽象的二维网格地图。
|
||||
|
||||
| 字段名 | 数据类型 | 长度/约束 | 是否可空 | 默认值 | 描述 |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| `id` | `BIGINT` | `PK, AUTO_INCREMENT`| No | | 唯一主键 |
|
||||
| `gridX` | `INT` | | No | | 网格X坐标 |
|
||||
| `gridY` | `INT` | | No | | 网格Y坐标 |
|
||||
| `cityName`| `VARCHAR`| 255 | Yes | | 所属城市 |
|
||||
| `districtName`|`VARCHAR`|255| Yes | | 所属区域 |
|
||||
| `isObstacle`|`BOOLEAN`| | No | `false`| 是否为障碍物 |
|
||||
|
||||
**索引设计**:
|
||||
- `PRIMARY KEY (id)`
|
||||
- `UNIQUE KEY uk_grid_coords (gridX, gridY)`
|
||||
- `KEY idx_city_district (cityName, districtName)`
|
||||
|
||||
### 3.7 用户登录历史表 (`user_login_history`)
|
||||
记录用户登录活动,用于安全审计。
|
||||
|
||||
| 字段名 | 数据类型 | 长度/约束 | 是否可空 | 默认值 | 描述 |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| `id` | `BIGINT` | `PK, AUTO_INCREMENT`| No | | 唯一主键 |
|
||||
| `userId` | `BIGINT` | `FK -> user_account.id`| No | | 登录用户ID |
|
||||
| `ipAddress`| `VARCHAR`| 100 | Yes | | 登录IP地址 |
|
||||
| `userAgent`| `VARCHAR`| 512 | Yes | | 浏览器或客户端信息 |
|
||||
| `status` | `VARCHAR`| 50 | No | | 登录状态 (Enum: `SUCCESS`, `FAILED_PASSWORD`, `FAILED_LOCKED`) |
|
||||
| `loginTime`| `DATETIME`| | No |`CURRENT_TIMESTAMP`| 登录时间 |
|
||||
|
||||
**索引设计**:
|
||||
- `PRIMARY KEY (id)`
|
||||
- `KEY idx_user_id_login_time (userId, loginTime)`
|
||||
- `KEY idx_ip_address (ipAddress)`
|
||||
|
||||
## 4. 初始化数据 (Seed Data)
|
||||
系统首次部署时,应向`user_account`表插入以下初始用户,以确保各角色可用。密码均为明文示例,实际存储时需加密。
|
||||
|
||||
| name | phone | email | password | role | status | region | level |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| "张建华"| "18800000001" | "zhang.jianguo@example.com"| "Admin@123456" | `ADMIN` | `ACTIVE` | "河北省" | `PROVINCE` |
|
||||
| "李志强"| "18800000002" | "li.zhiqiang@example.com" | "Admin@123456" | `ADMIN` | `ACTIVE` | "河北省-石家庄市"| `CITY` |
|
||||
| "王伟" | "18800000003" | "wang.wei@example.com" | "User@123456" | `GRID_WORKER`| `ACTIVE` | "河北省-石家庄市-长安区"| `CITY` |
|
||||
| "刘丽" | "18800000004" | "li.li@example.com" | "User@123456" | `SUPERVISOR`| `ACTIVE` | "河北省-石家庄市-裕华区"| `CITY` |
|
||||
| "陈思远"| "18800000005" | "chen.siyuan@example.com" | "User@123456" | `DECISION_MAKER`| `ACTIVE`| "全国" | `PROVINCE` |
|
||||
| "赵敏" | "18800000006" | "zhao.min@example.com" | "User@123456" | `PUBLIC_SUPERVISOR`|`ACTIVE`| "河北省-石家庄市-桥西区"| `CITY` |
|
||||
1439
Design/答辩稿.md
1439
Design/答辩稿.md
@@ -1,1439 +0,0 @@
|
||||
# EMS环境监测系统技术答辩稿
|
||||
|
||||
## 开场白
|
||||
|
||||
各位评委老师好!今天我将为大家展示一个基于Spring Boot微服务架构的智能环境监测系统(EMS)。这个系统不仅仅是一个简单的CRUD应用,而是一个融合了现代企业级开发最佳实践的复杂分布式系统。让我们一起探索这个系统背后的技术奥秘。
|
||||
|
||||
---
|
||||
|
||||
## 第一部分:架构设计的哲学思考
|
||||
|
||||
### 为什么选择分层架构?解耦的艺术
|
||||
|
||||
**设问**:在面对复杂的业务需求时,我们如何确保代码的可维护性和可扩展性?
|
||||
|
||||
答案就在于**分层架构**的设计哲学。我们的系统采用了经典的四层架构模式:
|
||||
|
||||
```
|
||||
Controller Layer (控制层) → Service Layer (业务层) → Repository Layer (数据访问层) → Model Layer (数据模型层)
|
||||
```
|
||||
|
||||
这种设计遵循了**单一职责原则**和**依赖倒置原则**,实现了真正的**高内聚、低耦合**。每一层都有明确的职责边界,层与层之间通过接口进行通信,这样的设计使得我们可以独立地修改某一层的实现,而不会影响到其他层。
|
||||
|
||||
**技术亮点**:我们使用了Spring的**依赖注入(DI)**容器来管理对象的生命周期,通过`@Autowired`注解实现了**控制反转(IoC)**,这是企业级应用开发的核心设计模式。
|
||||
|
||||
---
|
||||
|
||||
## 第二部分:Controller层的RESTful设计艺术
|
||||
|
||||
### 为什么我们需要14个专业化的Controller?
|
||||
|
||||
**设问**:传统的单体应用往往将所有功能堆砌在一个Controller中,这样做有什么问题?
|
||||
|
||||
我们的系统包含了14个专业化的Controller,每个Controller都专注于特定的业务领域:
|
||||
|
||||
#### AuthController - 认证控制器的安全哲学
|
||||
|
||||
```java
|
||||
@RestController
|
||||
@RequestMapping("/api/auth")
|
||||
@Validated
|
||||
public class AuthController {
|
||||
|
||||
@PostMapping("/login")
|
||||
public ResponseEntity<ApiResponse<JwtAuthenticationResponse>> authenticateUser(
|
||||
@Valid @RequestBody LoginRequest loginRequest) {
|
||||
// JWT令牌生成逻辑
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**技术深度解析**:
|
||||
- **@RestController**:这是Spring Boot的组合注解,等价于`@Controller + @ResponseBody`,自动将返回值序列化为JSON
|
||||
- **@Validated**:启用方法级别的参数验证,配合`@Valid`实现数据校验的**AOP切面编程**
|
||||
- **ResponseEntity**:提供了对HTTP响应的完全控制,包括状态码、头部信息和响应体
|
||||
|
||||
**设计思考**:为什么不直接返回对象,而要包装在`ApiResponse`中?这体现了**统一响应格式**的设计模式,确保前端能够以一致的方式处理所有API响应。
|
||||
|
||||
#### DashboardController - 数据可视化的技术挑战
|
||||
|
||||
**设问**:如何在不影响系统性能的前提下,为决策者提供实时的数据洞察?
|
||||
|
||||
```java
|
||||
@GetMapping("/stats")
|
||||
@PreAuthorize("hasRole('DECISION_MAKER')")
|
||||
public ResponseEntity<ApiResponse<DashboardStatsDTO>> getDashboardStats() {
|
||||
// 复杂的数据聚合逻辑
|
||||
}
|
||||
```
|
||||
|
||||
**技术亮点**:
|
||||
- **@PreAuthorize**:这是Spring Security的方法级安全注解,实现了**基于角色的访问控制(RBAC)**
|
||||
- **数据聚合优化**:我们在Repository层使用了复杂的JPQL查询和原生SQL,将计算下推到数据库层,避免了在应用层进行大量数据处理
|
||||
|
||||
---
|
||||
|
||||
## 第三部分:Service层的业务编排艺术
|
||||
|
||||
### 为什么业务逻辑需要如此复杂的编排?
|
||||
|
||||
**设问**:简单的CRUD操作为什么需要这么多Service类?这不是过度设计吗?
|
||||
|
||||
让我们看看`TaskManagementServiceImpl`的复杂性:
|
||||
|
||||
```java
|
||||
@Service
|
||||
@Transactional
|
||||
public class TaskManagementServiceImpl implements TaskManagementService {
|
||||
|
||||
@Autowired
|
||||
private TaskRepository taskRepository;
|
||||
|
||||
@Autowired
|
||||
private FeedbackRepository feedbackRepository;
|
||||
|
||||
@Autowired
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
@Override
|
||||
public TaskDTO createTaskFromFeedback(Long feedbackId, TaskFromFeedbackDTO dto) {
|
||||
// 1. 获取并验证反馈
|
||||
Feedback feedback = feedbackRepository.findById(feedbackId)
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Feedback not found"));
|
||||
|
||||
// 2. 业务规则验证
|
||||
if (feedback.getStatus() == FeedbackStatus.PROCESSED) {
|
||||
throw new BusinessException("Feedback already processed");
|
||||
}
|
||||
|
||||
// 3. 创建任务实体
|
||||
Task task = Task.builder()
|
||||
.title(dto.getTitle())
|
||||
.description(feedback.getDescription())
|
||||
.location(feedback.getLocation())
|
||||
.feedback(feedback)
|
||||
.status(TaskStatus.PENDING)
|
||||
.build();
|
||||
|
||||
// 4. 事务性操作
|
||||
Task savedTask = taskRepository.save(task);
|
||||
feedback.setStatus(FeedbackStatus.PROCESSED);
|
||||
feedbackRepository.save(feedback);
|
||||
|
||||
// 5. 发布领域事件
|
||||
eventPublisher.publishEvent(new TaskCreatedEvent(savedTask));
|
||||
|
||||
return modelMapper.map(savedTask, TaskDTO.class);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**技术深度解析**:
|
||||
|
||||
1. **@Transactional**:这是Spring的声明式事务管理,确保方法内的所有数据库操作要么全部成功,要么全部回滚,保证了数据的**ACID特性**
|
||||
|
||||
2. **Builder模式**:使用Lombok的`@Builder`注解生成建造者模式代码,提高了对象创建的可读性和安全性
|
||||
|
||||
3. **事件驱动架构**:通过`ApplicationEventPublisher`发布领域事件,实现了模块间的**松耦合**通信
|
||||
|
||||
4. **ModelMapper**:使用对象映射框架避免手动的属性拷贝,减少了样板代码
|
||||
|
||||
**设计哲学**:这种复杂性是必要的,因为它体现了**领域驱动设计(DDD)**的思想,每个Service都是一个业务能力的封装,确保了业务逻辑的完整性和一致性。
|
||||
|
||||
### AuthServiceImpl - 安全认证的技术堡垒
|
||||
|
||||
**设问**:在当今网络安全威胁日益严重的环境下,我们如何构建一个既安全又用户友好的认证系统?
|
||||
|
||||
```java
|
||||
@Service
|
||||
public class AuthServiceImpl implements AuthService {
|
||||
|
||||
@Autowired
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
@Autowired
|
||||
private JwtTokenProvider tokenProvider;
|
||||
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Override
|
||||
public JwtAuthenticationResponse authenticateUser(LoginRequest loginRequest) {
|
||||
// 1. Spring Security认证
|
||||
Authentication authentication = authenticationManager.authenticate(
|
||||
new UsernamePasswordAuthenticationToken(
|
||||
loginRequest.getUsername(),
|
||||
loginRequest.getPassword()
|
||||
)
|
||||
);
|
||||
|
||||
// 2. 设置安全上下文
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
|
||||
// 3. 生成JWT令牌
|
||||
String jwt = tokenProvider.generateToken(authentication);
|
||||
|
||||
return new JwtAuthenticationResponse(jwt);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**技术亮点**:
|
||||
|
||||
1. **AuthenticationManager**:Spring Security的核心认证管理器,支持多种认证提供者的**策略模式**
|
||||
|
||||
2. **JWT(JSON Web Token)**:无状态的令牌认证机制,支持分布式系统的**水平扩展**
|
||||
|
||||
3. **BCrypt密码编码**:使用自适应哈希算法,具有**盐值**和**工作因子**,抵御彩虹表攻击
|
||||
|
||||
---
|
||||
|
||||
## 第四部分:Repository层的数据访问艺术
|
||||
|
||||
### 为什么我们需要如此复杂的数据访问层?
|
||||
|
||||
**设问**:直接使用SQL不是更简单吗?为什么要引入这么多抽象层?
|
||||
|
||||
让我们看看`FeedbackRepository`的设计:
|
||||
|
||||
```java
|
||||
@Repository
|
||||
public interface FeedbackRepository extends JpaRepository<Feedback, Long>,
|
||||
JpaSpecificationExecutor<Feedback> {
|
||||
|
||||
// 方法名查询 - Spring Data JPA的魔法
|
||||
List<Feedback> findByStatus(FeedbackStatus status);
|
||||
Page<Feedback> findBySubmitterId(Long submitterId, Pageable pageable);
|
||||
|
||||
// 自定义JPQL查询 - 面向对象的查询语言
|
||||
@Query("SELECT new com.dne.ems.dto.HeatmapPointDTO(f.gridX, f.gridY, COUNT(f.id)) " +
|
||||
"FROM Feedback f WHERE f.status = 'CONFIRMED' " +
|
||||
"AND f.gridX IS NOT NULL AND f.gridY IS NOT NULL " +
|
||||
"GROUP BY f.gridX, f.gridY")
|
||||
List<HeatmapPointDTO> getHeatmapData();
|
||||
|
||||
// 性能优化 - EntityGraph解决N+1问题
|
||||
@Override
|
||||
@EntityGraph(attributePaths = {"user", "attachments"})
|
||||
Page<Feedback> findAll(Specification<Feedback> spec, Pageable pageable);
|
||||
}
|
||||
```
|
||||
|
||||
**技术深度解析**:
|
||||
|
||||
1. **Spring Data JPA**:这是Spring生态系统中的数据访问抽象层,它通过**代理模式**自动生成Repository实现类
|
||||
|
||||
2. **方法名查询**:基于方法名的**约定优于配置**原则,Spring会自动解析方法名并生成相应的查询
|
||||
|
||||
3. **JPQL(Java Persistence Query Language)**:面向对象的查询语言,具有数据库无关性
|
||||
|
||||
4. **EntityGraph**:JPA 2.1引入的性能优化特性,通过**预加载**策略解决N+1查询问题
|
||||
|
||||
5. **Specification模式**:实现了**动态查询**的构建,支持复杂的条件组合
|
||||
|
||||
### AqiDataRepository - 大数据处理的技术挑战
|
||||
|
||||
**设问**:面对海量的环境监测数据,我们如何确保查询性能?
|
||||
|
||||
```java
|
||||
@Repository
|
||||
public interface AqiDataRepository extends JpaRepository<AqiData, Long> {
|
||||
|
||||
// 复杂的统计查询
|
||||
@Query("SELECT new com.dne.ems.dto.AqiDistributionDTO(" +
|
||||
"CASE WHEN a.aqiValue <= 50 THEN 'Good' " +
|
||||
"WHEN a.aqiValue <= 100 THEN 'Moderate' " +
|
||||
"WHEN a.aqiValue <= 150 THEN 'Unhealthy for Sensitive Groups' " +
|
||||
"WHEN a.aqiValue <= 200 THEN 'Unhealthy' " +
|
||||
"WHEN a.aqiValue <= 300 THEN 'Very Unhealthy' " +
|
||||
"ELSE 'Hazardous' END, COUNT(a.id)) " +
|
||||
"FROM AqiData a GROUP BY 1")
|
||||
List<AqiDistributionDTO> getAqiDistribution();
|
||||
|
||||
// 原生SQL查询 - 性能优化
|
||||
@Query(value = "SELECT DATE_FORMAT(record_time, '%Y-%m') as yearMonth, " +
|
||||
"COUNT(id) as count FROM aqi_data " +
|
||||
"WHERE aqi_value > 100 AND record_time >= :startDate " +
|
||||
"GROUP BY DATE_FORMAT(record_time, '%Y-%m') ORDER BY 1",
|
||||
nativeQuery = true)
|
||||
List<Object[]> getMonthlyExceedanceTrendRaw(@Param("startDate") LocalDateTime startDate);
|
||||
|
||||
// 默认方法 - 数据转换
|
||||
default List<TrendDataPointDTO> getMonthlyExceedanceTrend(LocalDateTime startDate) {
|
||||
List<Object[]> rawResults = getMonthlyExceedanceTrendRaw(startDate);
|
||||
return rawResults.stream()
|
||||
.map(row -> new TrendDataPointDTO((String) row[0], ((Number) row[1]).longValue()))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**技术亮点**:
|
||||
|
||||
1. **原生SQL查询**:在需要极致性能时,我们使用原生SQL直接操作数据库
|
||||
|
||||
2. **默认方法**:Java 8的接口默认方法特性,允许我们在接口中提供数据转换逻辑
|
||||
|
||||
3. **Stream API**:函数式编程范式,提供了优雅的数据处理方式
|
||||
|
||||
4. **DTO投影**:直接将查询结果映射到DTO对象,避免了不必要的数据传输
|
||||
|
||||
---
|
||||
|
||||
## 第五部分:Security模块的安全防护体系
|
||||
|
||||
### 为什么安全性需要如此复杂的设计?
|
||||
|
||||
**设问**:在微服务架构中,我们如何构建一个既安全又高效的认证授权体系?
|
||||
|
||||
我们的安全模块包含四个核心组件:
|
||||
|
||||
#### JwtAuthenticationFilter - 无状态认证的守护者
|
||||
|
||||
```java
|
||||
@Component
|
||||
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
@Autowired
|
||||
private JwtService jwtService;
|
||||
|
||||
@Autowired
|
||||
private UserDetailsService userDetailsService;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
FilterChain filterChain) throws ServletException, IOException {
|
||||
|
||||
// 1. 提取JWT令牌
|
||||
String authHeader = request.getHeader("Authorization");
|
||||
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
String jwt = authHeader.substring(7);
|
||||
String username = jwtService.extractUsername(jwt);
|
||||
|
||||
// 2. 验证令牌并设置安全上下文
|
||||
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
|
||||
|
||||
if (jwtService.isTokenValid(jwt, userDetails)) {
|
||||
UsernamePasswordAuthenticationToken authToken =
|
||||
new UsernamePasswordAuthenticationToken(
|
||||
userDetails, null, userDetails.getAuthorities());
|
||||
|
||||
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||
SecurityContextHolder.getContext().setAuthentication(authToken);
|
||||
}
|
||||
}
|
||||
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**技术深度解析**:
|
||||
|
||||
1. **OncePerRequestFilter**:确保过滤器在每个请求中只执行一次,避免重复处理
|
||||
|
||||
2. **责任链模式**:FilterChain体现了责任链设计模式,每个过滤器处理特定的关注点
|
||||
|
||||
3. **ThreadLocal安全上下文**:SecurityContextHolder使用ThreadLocal存储认证信息,确保线程安全
|
||||
|
||||
4. **无状态设计**:JWT令牌包含了所有必要的用户信息,支持水平扩展
|
||||
|
||||
#### SecurityConfig - 安全策略的总指挥
|
||||
|
||||
```java
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableMethodSecurity(prePostEnabled = true)
|
||||
public class SecurityConfig {
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.csrf(csrf -> csrf.disable()) // 禁用CSRF(无状态应用)
|
||||
.sessionManagement(session ->
|
||||
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 无状态会话
|
||||
.authorizeHttpRequests(authz -> authz
|
||||
.requestMatchers("/api/auth/**", "/api/public/**").permitAll()
|
||||
.requestMatchers("/api/dashboard/**").hasRole("DECISION_MAKER")
|
||||
.requestMatchers("/api/supervisor/**").hasAnyRole("SUPERVISOR", "ADMIN")
|
||||
.requestMatchers("/api/worker/**").hasRole("GRID_WORKER")
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder(12); // 工作因子12,平衡安全性和性能
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**技术亮点**:
|
||||
|
||||
1. **@EnableMethodSecurity**:启用方法级安全控制,支持`@PreAuthorize`等注解
|
||||
|
||||
2. **流式API配置**:Spring Security 5.7+的新配置方式,更加直观和类型安全
|
||||
|
||||
3. **细粒度权限控制**:基于URL模式和角色的访问控制
|
||||
|
||||
4. **BCrypt算法**:自适应哈希算法,工作因子可调,抵御暴力破解
|
||||
|
||||
---
|
||||
|
||||
## 第六部分:Model层的领域建模艺术
|
||||
|
||||
### 为什么需要如此复杂的实体关系?
|
||||
|
||||
**设问**:简单的数据表不就够了吗?为什么要设计这么复杂的实体关系?
|
||||
|
||||
让我们看看`UserAccount`实体的设计:
|
||||
|
||||
```java
|
||||
@Entity
|
||||
@Table(name = "user_accounts")
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UserAccount {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(unique = true, nullable = false)
|
||||
@Email
|
||||
private String email;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Size(min = 8)
|
||||
private String password;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(nullable = false)
|
||||
private Role role;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Builder.Default
|
||||
private UserStatus status = UserStatus.ACTIVE;
|
||||
|
||||
// 网格坐标(用于网格员)
|
||||
private Integer gridX;
|
||||
private Integer gridY;
|
||||
|
||||
// 审计字段
|
||||
@CreationTimestamp
|
||||
@Column(updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@UpdateTimestamp
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
// 关系映射
|
||||
@OneToMany(mappedBy = "submitter", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
private List<Feedback> submittedFeedbacks = new ArrayList<>();
|
||||
|
||||
@OneToMany(mappedBy = "assignee", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
private List<Task> assignedTasks = new ArrayList<>();
|
||||
}
|
||||
```
|
||||
|
||||
**技术深度解析**:
|
||||
|
||||
1. **JPA注解体系**:
|
||||
- `@Entity`:标识为JPA实体
|
||||
- `@Table`:指定数据库表名
|
||||
- `@Id`和`@GeneratedValue`:主键策略
|
||||
- `@Column`:列约束和属性
|
||||
|
||||
2. **Lombok注解魔法**:
|
||||
- `@Data`:自动生成getter/setter/toString/equals/hashCode
|
||||
- `@Builder`:建造者模式,提高对象创建的可读性
|
||||
- `@NoArgsConstructor`和`@AllArgsConstructor`:构造器生成
|
||||
|
||||
3. **枚举映射**:`@Enumerated(EnumType.STRING)`确保数据库存储的是枚举的字符串值,提高可读性
|
||||
|
||||
4. **审计功能**:`@CreationTimestamp`和`@UpdateTimestamp`自动管理时间戳
|
||||
|
||||
5. **关系映射**:`@OneToMany`建立了实体间的关联关系,支持对象导航
|
||||
|
||||
### Feedback实体 - 复杂业务的数据载体
|
||||
|
||||
```java
|
||||
@Entity
|
||||
@Table(name = "feedbacks")
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Feedback {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(unique = true, nullable = false)
|
||||
private String eventId; // 业务唯一标识
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String description;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Builder.Default
|
||||
private FeedbackStatus status = FeedbackStatus.PENDING;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
private PollutionType pollutionType;
|
||||
|
||||
// 地理信息
|
||||
private String location;
|
||||
private Integer gridX;
|
||||
private Integer gridY;
|
||||
|
||||
// 关联关系
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "submitter_id")
|
||||
private UserAccount submitter;
|
||||
|
||||
@OneToOne(mappedBy = "feedback", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
private Task relatedTask;
|
||||
|
||||
@OneToMany(mappedBy = "feedback", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
private List<Attachment> attachments = new ArrayList<>();
|
||||
|
||||
// 自定义转换器
|
||||
@Convert(converter = StringListConverter.class)
|
||||
private List<String> tags = new ArrayList<>();
|
||||
}
|
||||
```
|
||||
|
||||
**设计亮点**:
|
||||
|
||||
1. **业务标识符**:`eventId`作为业务唯一标识,与技术主键`id`分离
|
||||
|
||||
2. **状态机模式**:`FeedbackStatus`枚举定义了反馈的生命周期状态
|
||||
|
||||
3. **地理信息建模**:支持文本地址和网格坐标两种定位方式
|
||||
|
||||
4. **自定义转换器**:`StringListConverter`将List<String>转换为数据库的JSON字段
|
||||
|
||||
---
|
||||
|
||||
## 第七部分:高级特性与算法实现
|
||||
|
||||
### A*寻路算法 - 智能路径规划的核心
|
||||
|
||||
**设问**:在复杂的城市环境中,我们如何为网格员规划最优的任务执行路径?
|
||||
|
||||
```java
|
||||
@Service
|
||||
public class AStarService {
|
||||
|
||||
public List<Point> findPath(Point start, Point goal, int[][] grid) {
|
||||
PriorityQueue<Node> openSet = new PriorityQueue<>(Comparator.comparingDouble(Node::getF));
|
||||
Set<Point> closedSet = new HashSet<>();
|
||||
Map<Point, Node> allNodes = new HashMap<>();
|
||||
|
||||
Node startNode = new Node(start, 0, heuristic(start, goal), null);
|
||||
openSet.add(startNode);
|
||||
allNodes.put(start, startNode);
|
||||
|
||||
while (!openSet.isEmpty()) {
|
||||
Node current = openSet.poll();
|
||||
|
||||
if (current.getPoint().equals(goal)) {
|
||||
return reconstructPath(current);
|
||||
}
|
||||
|
||||
closedSet.add(current.getPoint());
|
||||
|
||||
for (Point neighbor : getNeighbors(current.getPoint(), grid)) {
|
||||
if (closedSet.contains(neighbor) || isObstacle(neighbor, grid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double tentativeG = current.getG() + distance(current.getPoint(), neighbor);
|
||||
|
||||
Node neighborNode = allNodes.get(neighbor);
|
||||
if (neighborNode == null) {
|
||||
neighborNode = new Node(neighbor, tentativeG, heuristic(neighbor, goal), current);
|
||||
allNodes.put(neighbor, neighborNode);
|
||||
openSet.add(neighborNode);
|
||||
} else if (tentativeG < neighborNode.getG()) {
|
||||
neighborNode.setG(tentativeG);
|
||||
neighborNode.setF(tentativeG + neighborNode.getH());
|
||||
neighborNode.setParent(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptyList(); // 无路径
|
||||
}
|
||||
|
||||
private double heuristic(Point a, Point b) {
|
||||
// 曼哈顿距离启发式函数
|
||||
return Math.abs(a.getX() - b.getX()) + Math.abs(a.getY() - b.getY());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**算法亮点**:
|
||||
|
||||
1. **优先队列**:使用`PriorityQueue`实现开放集合,确保总是选择f值最小的节点
|
||||
|
||||
2. **启发式函数**:曼哈顿距离作为启发式函数,保证算法的最优性
|
||||
|
||||
3. **路径重构**:通过父节点指针重构最优路径
|
||||
|
||||
4. **空间复杂度优化**:使用HashMap存储所有节点,避免重复创建
|
||||
|
||||
### 智能任务推荐算法
|
||||
|
||||
**设问**:面对众多的网格员,我们如何智能地推荐最合适的任务执行者?
|
||||
|
||||
```java
|
||||
@Service
|
||||
public class TaskRecommendationService {
|
||||
|
||||
public List<WorkerRecommendationDTO> recommendWorkersForTask(Long taskId) {
|
||||
Task task = taskRepository.findById(taskId)
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Task not found"));
|
||||
|
||||
List<UserAccount> availableWorkers = userRepository
|
||||
.findByRoleAndStatus(Role.GRID_WORKER, UserStatus.ACTIVE);
|
||||
|
||||
return availableWorkers.stream()
|
||||
.map(worker -> calculateWorkerScore(worker, task))
|
||||
.sorted(Comparator.comparingDouble(WorkerRecommendationDTO::getScore).reversed())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private WorkerRecommendationDTO calculateWorkerScore(UserAccount worker, Task task) {
|
||||
double distanceScore = calculateDistanceScore(worker, task); // 40%权重
|
||||
double workloadScore = calculateWorkloadScore(worker); // 30%权重
|
||||
double skillScore = calculateSkillScore(worker, task); // 20%权重
|
||||
double performanceScore = calculatePerformanceScore(worker); // 10%权重
|
||||
|
||||
double totalScore = distanceScore * 0.4 + workloadScore * 0.3 +
|
||||
skillScore * 0.2 + performanceScore * 0.1;
|
||||
|
||||
return WorkerRecommendationDTO.builder()
|
||||
.workerId(worker.getId())
|
||||
.workerName(worker.getName())
|
||||
.score(totalScore)
|
||||
.distanceScore(distanceScore)
|
||||
.workloadScore(workloadScore)
|
||||
.skillScore(skillScore)
|
||||
.performanceScore(performanceScore)
|
||||
.build();
|
||||
}
|
||||
|
||||
private double calculateDistanceScore(UserAccount worker, Task task) {
|
||||
if (worker.getGridX() == null || worker.getGridY() == null) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double distance = Math.sqrt(
|
||||
Math.pow(worker.getGridX() - task.getGridX(), 2) +
|
||||
Math.pow(worker.getGridY() - task.getGridY(), 2)
|
||||
);
|
||||
|
||||
double maxDistance = 50.0; // 最大考虑距离
|
||||
return Math.max(0, (maxDistance - distance) / maxDistance);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**算法特点**:
|
||||
|
||||
1. **多维度评分**:综合考虑距离、工作负载、技能匹配和历史表现
|
||||
|
||||
2. **加权评分模型**:不同维度采用不同权重,可根据业务需求调整
|
||||
|
||||
3. **流式处理**:使用Stream API进行函数式编程,代码简洁高效
|
||||
|
||||
4. **可扩展性**:评分算法可以轻松添加新的评分维度
|
||||
|
||||
---
|
||||
|
||||
## 第八部分:事件驱动架构的异步魅力
|
||||
|
||||
### 为什么选择事件驱动架构?
|
||||
|
||||
**设问**:传统的同步调用方式有什么问题?为什么要引入事件驱动的复杂性?
|
||||
|
||||
让我们看看事件驱动架构的实现:
|
||||
|
||||
```java
|
||||
// 事件定义
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class TaskCreatedEvent extends ApplicationEvent {
|
||||
private final Task task;
|
||||
|
||||
public TaskCreatedEvent(Object source, Task task) {
|
||||
super(source);
|
||||
this.task = task;
|
||||
}
|
||||
}
|
||||
|
||||
// 事件发布
|
||||
@Service
|
||||
public class TaskManagementServiceImpl {
|
||||
|
||||
@Autowired
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
public TaskDTO createTask(TaskCreateDTO dto) {
|
||||
Task task = // ... 创建任务逻辑
|
||||
Task savedTask = taskRepository.save(task);
|
||||
|
||||
// 发布事件 - 异步处理
|
||||
eventPublisher.publishEvent(new TaskCreatedEvent(this, savedTask));
|
||||
|
||||
return modelMapper.map(savedTask, TaskDTO.class);
|
||||
}
|
||||
}
|
||||
|
||||
// 事件监听
|
||||
@Component
|
||||
public class TaskEventListener {
|
||||
|
||||
@Autowired
|
||||
private NotificationService notificationService;
|
||||
|
||||
@Autowired
|
||||
private AuditService auditService;
|
||||
|
||||
@EventListener
|
||||
@Async
|
||||
public void handleTaskCreated(TaskCreatedEvent event) {
|
||||
Task task = event.getTask();
|
||||
|
||||
// 异步发送通知
|
||||
notificationService.sendTaskAssignmentNotification(task);
|
||||
|
||||
// 异步记录审计日志
|
||||
auditService.logTaskCreation(task);
|
||||
|
||||
// 异步更新统计数据
|
||||
statisticsService.updateTaskStatistics(task);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**技术优势**:
|
||||
|
||||
1. **解耦合**:事件发布者和监听者之间没有直接依赖关系
|
||||
|
||||
2. **异步处理**:`@Async`注解实现异步执行,提高系统响应性
|
||||
|
||||
3. **可扩展性**:可以轻松添加新的事件监听器,不影响现有代码
|
||||
|
||||
4. **容错性**:某个监听器失败不会影响其他监听器的执行
|
||||
|
||||
---
|
||||
|
||||
## 第九部分:性能优化的技术手段
|
||||
|
||||
### 数据库查询优化策略
|
||||
|
||||
**设问**:面对大量的数据查询需求,我们如何确保系统的高性能?
|
||||
|
||||
#### 1. EntityGraph解决N+1查询问题
|
||||
|
||||
```java
|
||||
@Repository
|
||||
public interface FeedbackRepository extends JpaRepository<Feedback, Long> {
|
||||
|
||||
@EntityGraph(attributePaths = {"submitter", "attachments", "relatedTask"})
|
||||
@Query("SELECT f FROM Feedback f WHERE f.status = :status")
|
||||
List<Feedback> findByStatusWithDetails(@Param("status") FeedbackStatus status);
|
||||
}
|
||||
```
|
||||
|
||||
**技术原理**:EntityGraph告诉JPA在执行查询时一次性加载相关联的实体,避免了懒加载导致的N+1查询问题。
|
||||
|
||||
#### 2. 分页查询优化
|
||||
|
||||
```java
|
||||
@Service
|
||||
public class FeedbackService {
|
||||
|
||||
public Page<FeedbackDTO> getFeedbacks(FeedbackSearchCriteria criteria, Pageable pageable) {
|
||||
Specification<Feedback> spec = FeedbackSpecification.buildSpecification(criteria);
|
||||
Page<Feedback> feedbacks = feedbackRepository.findAll(spec, pageable);
|
||||
|
||||
return feedbacks.map(feedback -> modelMapper.map(feedback, FeedbackDTO.class));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**优化策略**:
|
||||
- 使用Specification动态构建查询条件
|
||||
- 利用数据库索引优化排序和过滤
|
||||
- 在DTO转换时避免加载不必要的关联数据
|
||||
|
||||
#### 3. 缓存策略
|
||||
|
||||
```java
|
||||
@Service
|
||||
public class UserService {
|
||||
|
||||
@Cacheable(value = "users", key = "#email")
|
||||
public UserAccount findByEmail(String email) {
|
||||
return userRepository.findByEmail(email)
|
||||
.orElseThrow(() -> new UserNotFoundException("User not found"));
|
||||
}
|
||||
|
||||
@CacheEvict(value = "users", key = "#user.email")
|
||||
public UserAccount updateUser(UserAccount user) {
|
||||
return userRepository.save(user);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**缓存优势**:
|
||||
- 减少数据库访问次数
|
||||
- 提高频繁查询的响应速度
|
||||
- 支持分布式缓存扩展
|
||||
|
||||
---
|
||||
|
||||
## 第十部分:系统的技术创新点
|
||||
|
||||
### 1. 智能AI预审核系统
|
||||
|
||||
**设问**:如何将人工智能技术融入到传统的政务系统中?
|
||||
|
||||
```java
|
||||
@Service
|
||||
public class AiReviewService {
|
||||
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
public AiReviewResult reviewFeedback(Feedback feedback) {
|
||||
// 构建AI分析请求
|
||||
AiAnalysisRequest request = AiAnalysisRequest.builder()
|
||||
.text(feedback.getDescription())
|
||||
.imageUrls(feedback.getAttachments().stream()
|
||||
.map(Attachment::getFileUrl)
|
||||
.collect(Collectors.toList()))
|
||||
.location(feedback.getLocation())
|
||||
.build();
|
||||
|
||||
// 调用AI服务
|
||||
ResponseEntity<AiAnalysisResponse> response = restTemplate.postForEntity(
|
||||
aiServiceUrl + "/analyze", request, AiAnalysisResponse.class);
|
||||
|
||||
AiAnalysisResponse analysisResult = response.getBody();
|
||||
|
||||
// 构建审核结果
|
||||
return AiReviewResult.builder()
|
||||
.isValid(analysisResult.getConfidence() > 0.8)
|
||||
.confidence(analysisResult.getConfidence())
|
||||
.category(analysisResult.getCategory())
|
||||
.urgencyLevel(analysisResult.getUrgencyLevel())
|
||||
.suggestedActions(analysisResult.getSuggestedActions())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**创新点**:
|
||||
- **多模态分析**:同时分析文本和图像内容
|
||||
- **智能分类**:自动识别问题类型和紧急程度
|
||||
- **置信度评估**:提供AI判断的可信度指标
|
||||
|
||||
### 2. 实时数据大屏技术
|
||||
|
||||
**设问**:如何为决策者提供实时、直观的数据洞察?
|
||||
|
||||
```java
|
||||
@RestController
|
||||
@RequestMapping("/api/dashboard")
|
||||
public class DashboardController {
|
||||
|
||||
@GetMapping("/realtime-stats")
|
||||
@PreAuthorize("hasRole('DECISION_MAKER')")
|
||||
public SseEmitter getRealtimeStats() {
|
||||
SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);
|
||||
|
||||
// 异步推送实时数据
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
while (true) {
|
||||
DashboardStatsDTO stats = dashboardService.getCurrentStats();
|
||||
emitter.send(SseEmitter.event()
|
||||
.name("stats-update")
|
||||
.data(stats));
|
||||
|
||||
Thread.sleep(5000); // 每5秒推送一次
|
||||
}
|
||||
} catch (Exception e) {
|
||||
emitter.completeWithError(e);
|
||||
}
|
||||
});
|
||||
|
||||
return emitter;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**技术特点**:
|
||||
- **Server-Sent Events (SSE)**:实现服务器主动推送数据
|
||||
- **异步处理**:使用CompletableFuture避免阻塞主线程
|
||||
- **实时性**:数据更新延迟控制在秒级
|
||||
|
||||
### 3. 地理信息系统集成
|
||||
|
||||
```java
|
||||
@Service
|
||||
public class GeoService {
|
||||
|
||||
public List<HeatmapPointDTO> generateHeatmapData(String dataType, LocalDateTime startTime) {
|
||||
switch (dataType) {
|
||||
case "feedback":
|
||||
return feedbackRepository.getHeatmapData();
|
||||
case "aqi":
|
||||
return aqiDataRepository.getAqiHeatmapData();
|
||||
case "task":
|
||||
return taskRepository.getTaskHeatmapData(startTime);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported data type: " + dataType);
|
||||
}
|
||||
}
|
||||
|
||||
public GridCoverageDTO calculateGridCoverage() {
|
||||
long totalGrids = gridRepository.count();
|
||||
long coveredGrids = gridRepository.countByIsObstacleFalse();
|
||||
|
||||
return GridCoverageDTO.builder()
|
||||
.totalGrids(totalGrids)
|
||||
.coveredGrids(coveredGrids)
|
||||
.coverageRate((double) coveredGrids / totalGrids * 100)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**GIS特性**:
|
||||
- **热力图生成**:基于地理坐标的数据可视化
|
||||
- **网格覆盖分析**:计算监测网络的覆盖率
|
||||
- **空间查询**:支持基于地理位置的数据查询
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## 第十一部分:系统的技术特色
|
||||
|
||||
### 设问:我们的系统有哪些值得关注的技术特点?
|
||||
|
||||
除了基础功能实现,我们的EMS系统还融入了一些实用的技术特色,让系统更加稳定和高效。
|
||||
|
||||
#### 1. 多任务处理能力
|
||||
|
||||
**应用场景**:当系统需要同时处理多个用户的请求时,比如多个网格员同时上报数据。
|
||||
|
||||
**解决方案**:我们使用了异步处理技术,让系统能够同时处理多个任务,提高响应速度。
|
||||
|
||||
```java
|
||||
// 异步任务配置
|
||||
@Configuration
|
||||
@EnableAsync
|
||||
public class AsyncConfig {
|
||||
|
||||
@Bean
|
||||
public ThreadPoolTaskExecutor taskExecutor() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
|
||||
// 设置合适的线程数量
|
||||
executor.setCorePoolSize(4);
|
||||
executor.setMaxPoolSize(8);
|
||||
executor.setQueueCapacity(100);
|
||||
|
||||
// 设置线程名称,方便调试
|
||||
executor.setThreadNamePrefix("EMS-Task-");
|
||||
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
}
|
||||
|
||||
// 异步任务示例
|
||||
@Service
|
||||
public class NotificationService {
|
||||
|
||||
@Async
|
||||
public void sendNotification(String message) {
|
||||
// 发送通知的逻辑
|
||||
System.out.println("发送通知: " + message);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**技术优势**:
|
||||
- **提高响应速度**:用户操作不会被耗时任务阻塞
|
||||
- **合理利用资源**:根据服务器性能配置线程数量
|
||||
- **便于问题排查**:通过线程名称快速定位问题
|
||||
|
||||
#### 2. 任务分配的安全机制
|
||||
|
||||
**应用场景**:当多个管理员同时分配同一个任务时,需要确保任务不会被重复分配。
|
||||
|
||||
**解决方案**:使用Redis实现任务锁定机制,确保同一时间只有一个操作能够分配特定任务。
|
||||
|
||||
```java
|
||||
@Component
|
||||
public class TaskLockService {
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
|
||||
/**
|
||||
* 尝试锁定任务
|
||||
*/
|
||||
public boolean lockTask(String taskId) {
|
||||
String lockKey = "task:lock:" + taskId;
|
||||
String lockValue = "locked";
|
||||
|
||||
// 设置锁,30秒后自动过期
|
||||
Boolean success = redisTemplate.opsForValue()
|
||||
.setIfAbsent(lockKey, lockValue, Duration.ofSeconds(30));
|
||||
|
||||
return Boolean.TRUE.equals(success);
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放任务锁
|
||||
*/
|
||||
public void unlockTask(String taskId) {
|
||||
String lockKey = "task:lock:" + taskId;
|
||||
redisTemplate.delete(lockKey);
|
||||
}
|
||||
}
|
||||
|
||||
// 任务分配服务
|
||||
@Service
|
||||
public class TaskAssignmentService {
|
||||
|
||||
@Autowired
|
||||
private TaskLockService lockService;
|
||||
|
||||
public boolean assignTask(Long taskId, Long workerId) {
|
||||
String taskIdStr = taskId.toString();
|
||||
|
||||
// 尝试锁定任务
|
||||
if (!lockService.lockTask(taskIdStr)) {
|
||||
throw new BusinessException("任务正在被处理,请稍后重试");
|
||||
}
|
||||
|
||||
try {
|
||||
// 检查任务状态
|
||||
Task task = taskRepository.findById(taskId)
|
||||
.orElseThrow(() -> new RuntimeException("任务不存在"));
|
||||
|
||||
if (task.getStatus() != TaskStatus.PENDING) {
|
||||
throw new BusinessException("任务已被分配");
|
||||
}
|
||||
|
||||
// 分配任务
|
||||
task.setAssigneeId(workerId);
|
||||
task.setStatus(TaskStatus.ASSIGNED);
|
||||
task.setAssignedAt(LocalDateTime.now());
|
||||
|
||||
taskRepository.save(task);
|
||||
|
||||
return true;
|
||||
|
||||
} finally {
|
||||
// 释放锁
|
||||
lockService.unlockTask(taskIdStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**技术优势**:
|
||||
- **防止重复分配**:确保任务分配的唯一性
|
||||
- **自动释放机制**:避免系统卡死
|
||||
- **简单可靠**:使用成熟稳定的技术方案
|
||||
|
||||
#### 3. 智能任务推荐功能
|
||||
|
||||
**应用场景**:当有新任务需要分配时,系统能够自动推荐最合适的网格员。
|
||||
|
||||
**解决方案**:根据不同的任务类型,使用不同的推荐规则来选择最合适的人员。
|
||||
|
||||
```java
|
||||
// 任务推荐服务
|
||||
@Service
|
||||
public class TaskRecommendationService {
|
||||
|
||||
/**
|
||||
* 推荐合适的网格员
|
||||
*/
|
||||
public List<WorkerRecommendation> recommendWorkers(Task task) {
|
||||
List<UserAccount> availableWorkers = getAvailableWorkers();
|
||||
|
||||
// 根据任务类型选择推荐方式
|
||||
if (task.isUrgent()) {
|
||||
return recommendByDistance(task, availableWorkers);
|
||||
} else {
|
||||
return recommendByExperience(task, availableWorkers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于距离推荐(紧急任务)
|
||||
*/
|
||||
private List<WorkerRecommendation> recommendByDistance(Task task, List<UserAccount> workers) {
|
||||
return workers.stream()
|
||||
.map(worker -> {
|
||||
double distance = calculateDistance(worker.getLocation(), task.getLocation());
|
||||
int score = (int) (100 - distance * 10); // 距离越近分数越高
|
||||
|
||||
return new WorkerRecommendation(
|
||||
worker.getId(),
|
||||
worker.getName(),
|
||||
score,
|
||||
"距离任务地点 " + String.format("%.1f", distance) + " 公里"
|
||||
);
|
||||
})
|
||||
.sorted((a, b) -> Integer.compare(b.getScore(), a.getScore()))
|
||||
.limit(5)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于经验推荐(普通任务)
|
||||
*/
|
||||
private List<WorkerRecommendation> recommendByExperience(Task task, List<UserAccount> workers) {
|
||||
return workers.stream()
|
||||
.map(worker -> {
|
||||
int completedTasks = getCompletedTaskCount(worker.getId(), task.getType());
|
||||
int score = Math.min(100, completedTasks * 10 + 50); // 经验越多分数越高
|
||||
|
||||
return new WorkerRecommendation(
|
||||
worker.getId(),
|
||||
worker.getName(),
|
||||
score,
|
||||
"已完成类似任务 " + completedTasks + " 次"
|
||||
);
|
||||
})
|
||||
.sorted((a, b) -> Integer.compare(b.getScore(), a.getScore()))
|
||||
.limit(5)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两点间距离(简化版)
|
||||
*/
|
||||
private double calculateDistance(String location1, String location2) {
|
||||
// 这里可以接入地图API计算实际距离
|
||||
// 现在返回模拟距离
|
||||
return Math.random() * 10; // 0-10公里
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取已完成任务数量
|
||||
*/
|
||||
private int getCompletedTaskCount(Long workerId, String taskType) {
|
||||
return taskRepository.countCompletedTasksByWorkerAndType(workerId, taskType);
|
||||
}
|
||||
}
|
||||
|
||||
// 推荐结果类
|
||||
public class WorkerRecommendation {
|
||||
private Long workerId;
|
||||
private String workerName;
|
||||
private int score;
|
||||
private String reason;
|
||||
|
||||
// 构造函数和getter/setter
|
||||
public WorkerRecommendation(Long workerId, String workerName, int score, String reason) {
|
||||
this.workerId = workerId;
|
||||
this.workerName = workerName;
|
||||
this.score = score;
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
// getter方法...
|
||||
}
|
||||
```
|
||||
|
||||
**技术优势**:
|
||||
- **智能推荐**:根据任务特点自动推荐合适人员
|
||||
- **多种策略**:紧急任务看距离,普通任务看经验
|
||||
- **简单易懂**:推荐逻辑清晰,便于维护和扩展
|
||||
|
||||
#### 4. 操作记录和审计功能
|
||||
|
||||
**应用场景**:政务系统需要记录所有重要操作,便于后续查询和审计。
|
||||
|
||||
**解决方案**:建立完整的操作日志系统,记录用户的每一个重要操作。
|
||||
|
||||
```java
|
||||
// 操作日志实体
|
||||
@Entity
|
||||
@Table(name = "operation_log")
|
||||
public class OperationLog {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String userId; // 操作用户
|
||||
private String userName; // 用户姓名
|
||||
private String operation; // 操作类型
|
||||
private String description; // 操作描述
|
||||
private String targetId; // 操作对象ID
|
||||
private String targetType; // 操作对象类型
|
||||
private String ipAddress; // IP地址
|
||||
private LocalDateTime createTime; // 操作时间
|
||||
|
||||
// 构造函数和getter/setter...
|
||||
}
|
||||
|
||||
// 操作日志服务
|
||||
@Service
|
||||
public class OperationLogService {
|
||||
|
||||
@Autowired
|
||||
private OperationLogRepository logRepository;
|
||||
|
||||
/**
|
||||
* 记录操作日志
|
||||
*/
|
||||
public void recordOperation(String operation, String description,
|
||||
String targetId, String targetType) {
|
||||
// 获取当前用户信息
|
||||
UserAccount currentUser = getCurrentUser();
|
||||
|
||||
OperationLog log = new OperationLog();
|
||||
log.setUserId(currentUser.getId().toString());
|
||||
log.setUserName(currentUser.getName());
|
||||
log.setOperation(operation);
|
||||
log.setDescription(description);
|
||||
log.setTargetId(targetId);
|
||||
log.setTargetType(targetType);
|
||||
log.setIpAddress(getClientIpAddress());
|
||||
log.setCreateTime(LocalDateTime.now());
|
||||
|
||||
logRepository.save(log);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询操作日志
|
||||
*/
|
||||
public List<OperationLog> queryLogs(String userId, String operation,
|
||||
LocalDateTime startTime, LocalDateTime endTime) {
|
||||
return logRepository.findByConditions(userId, operation, startTime, endTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端IP地址
|
||||
*/
|
||||
private String getClientIpAddress() {
|
||||
// 从请求中获取IP地址
|
||||
HttpServletRequest request = getCurrentRequest();
|
||||
String ip = request.getHeader("X-Forwarded-For");
|
||||
if (ip == null || ip.isEmpty()) {
|
||||
ip = request.getRemoteAddr();
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
}
|
||||
|
||||
// 使用示例:在任务分配时记录日志
|
||||
@Service
|
||||
public class TaskService {
|
||||
|
||||
@Autowired
|
||||
private OperationLogService logService;
|
||||
|
||||
public void assignTask(Long taskId, Long workerId) {
|
||||
// 执行任务分配逻辑
|
||||
// ...
|
||||
|
||||
// 记录操作日志
|
||||
logService.recordOperation(
|
||||
"TASK_ASSIGN",
|
||||
"将任务分配给网格员",
|
||||
taskId.toString(),
|
||||
"TASK"
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**技术优势**:
|
||||
- **完整记录**:记录所有重要操作,便于追溯
|
||||
- **详细信息**:包含操作人、时间、IP等关键信息
|
||||
- **便于查询**:支持按条件查询历史操作
|
||||
- **安全可靠**:确保操作的可追溯性和透明度
|
||||
---
|
||||
|
||||
## 第十二部分:系统总结与展望
|
||||
|
||||
### 设问:我们的EMS系统实现了什么目标?
|
||||
|
||||
通过以上的技术实现和功能展示,我们的环境监测系统(EMS)成功地解决了环境管理中的核心问题:
|
||||
|
||||
#### 1. 主要成果
|
||||
|
||||
**功能完整性**:
|
||||
- ✅ **数据采集与监测**:实时收集环境数据,支持多种数据源
|
||||
- ✅ **任务管理**:完整的任务分配、跟踪、完成流程
|
||||
- ✅ **用户权限管理**:多角色权限控制,确保系统安全
|
||||
- ✅ **数据可视化**:直观的图表展示,便于决策分析
|
||||
- ✅ **移动端支持**:网格员可通过手机APP进行现场操作
|
||||
|
||||
**技术特色**:
|
||||
- 🚀 **高性能**:异步处理技术提升系统响应速度
|
||||
- 🔒 **高安全性**:完善的权限控制和操作审计
|
||||
- 🎯 **智能推荐**:自动推荐最合适的处理人员
|
||||
- 📱 **用户友好**:简洁直观的界面设计
|
||||
|
||||
#### 2. 解决的实际问题
|
||||
|
||||
**环境管理痛点**:
|
||||
- **数据分散** → **统一平台管理**
|
||||
- **任务混乱** → **清晰的工作流程**
|
||||
- **响应缓慢** → **快速任务分配**
|
||||
- **监管困难** → **全程操作记录**
|
||||
|
||||
**技术实现亮点**:
|
||||
- **前后端分离**:Vue3 + Spring Boot,技术栈现代化
|
||||
- **数据库设计**:合理的表结构,支持复杂查询
|
||||
- **接口规范**:RESTful API设计,便于扩展
|
||||
- **代码质量**:清晰的分层架构,易于维护
|
||||
|
||||
#### 3. 未来发展方向
|
||||
|
||||
**功能扩展**:
|
||||
- 📊 **数据分析增强**:加入更多统计分析功能
|
||||
- 🤖 **智能化升级**:引入AI辅助决策
|
||||
- 📱 **移动端完善**:增加更多移动端功能
|
||||
- 🌐 **系统集成**:与其他政务系统对接
|
||||
|
||||
**技术优化**:
|
||||
- ⚡ **性能提升**:优化数据库查询,提升响应速度
|
||||
- 🔐 **安全加强**:增加更多安全防护措施
|
||||
- 📈 **监控完善**:加入系统监控和告警功能
|
||||
- 🔄 **自动化**:增加更多自动化处理流程
|
||||
|
||||
### 总结
|
||||
|
||||
我们的EMS系统不仅实现了环境监测的基本功能,更在技术实现上体现了现代软件开发的最佳实践。通过合理的架构设计、清晰的代码组织和用户友好的界面,为环境管理工作提供了有力的技术支撑。
|
||||
|
||||
这个项目展示了我们在**全栈开发**、**系统设计**、**数据库管理**等方面的综合能力,是一个真正能够投入实际使用的完整系统。
|
||||
|
||||
### 数据异常检测功能
|
||||
|
||||
为了保证环境数据的准确性,系统提供了简单有效的异常检测功能:
|
||||
|
||||
```java
|
||||
@Service
|
||||
public class DataValidationService {
|
||||
|
||||
/**
|
||||
* 检测异常数据
|
||||
*/
|
||||
public List<String> validateAqiData(List<AqiData> dataList) {
|
||||
List<String> warnings = new ArrayList<>();
|
||||
|
||||
for (AqiData data : dataList) {
|
||||
// 检查数值范围
|
||||
if (data.getAqiValue() < 0 || data.getAqiValue() > 500) {
|
||||
warnings.add("AQI数值异常: " + data.getAqiValue());
|
||||
}
|
||||
|
||||
// 检查PM2.5范围
|
||||
if (data.getPm25() < 0 || data.getPm25() > 1000) {
|
||||
warnings.add("PM2.5数值异常: " + data.getPm25());
|
||||
}
|
||||
}
|
||||
|
||||
return warnings;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据趋势分析
|
||||
*/
|
||||
public String analyzeTrend(List<AqiData> recentData) {
|
||||
if (recentData.size() < 2) {
|
||||
return "数据不足";
|
||||
}
|
||||
|
||||
double firstValue = recentData.get(0).getAqiValue();
|
||||
double lastValue = recentData.get(recentData.size() - 1).getAqiValue();
|
||||
|
||||
if (lastValue > firstValue * 1.2) {
|
||||
return "空气质量呈恶化趋势";
|
||||
} else if (lastValue < firstValue * 0.8) {
|
||||
return "空气质量呈改善趋势";
|
||||
} else {
|
||||
return "空气质量相对稳定";
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**功能特点**:
|
||||
- **数据校验**:检查环境数据是否在合理范围内
|
||||
- **趋势分析**:分析空气质量变化趋势
|
||||
- **预警提醒**:发现异常数据时及时提醒
|
||||
---
|
||||
|
||||
## 项目总结
|
||||
|
||||
### 🎯 主要成果
|
||||
|
||||
1. **功能完整性**
|
||||
- 实现了环境监测数据的全生命周期管理
|
||||
- 提供了直观的数据可视化界面
|
||||
- 支持多种数据导入导出格式
|
||||
|
||||
2. **技术特色**
|
||||
- 采用前后端分离架构,便于维护和扩展
|
||||
- 使用Spring Boot框架,开发效率高
|
||||
- 集成了地图展示功能,用户体验良好
|
||||
|
||||
3. **实用价值**
|
||||
- 解决了环境数据管理的实际需求
|
||||
- 提供了便民的在线查询服务
|
||||
- 支持数据分析和趋势预测
|
||||
|
||||
### 🚀 技术亮点
|
||||
|
||||
- **系统架构**:清晰的分层设计,易于理解和维护
|
||||
- **数据处理**:高效的数据存储和查询机制
|
||||
- **用户界面**:现代化的Web界面,操作简单直观
|
||||
- **安全性**:完善的用户认证和权限管理
|
||||
|
||||
### 📈 未来展望
|
||||
|
||||
1. **功能扩展**
|
||||
- 增加更多环境指标的监测
|
||||
- 支持移动端应用
|
||||
- 添加数据预警功能
|
||||
|
||||
2. **技术优化**
|
||||
- 提升系统性能和响应速度
|
||||
- 增强数据分析能力
|
||||
- 优化用户体验
|
||||
```
|
||||
|
||||
**谢谢各位老师的指导!**
|
||||
@@ -1,172 +0,0 @@
|
||||
# 网格员任务处理功能 - 设计文档
|
||||
|
||||
## 1. 功能描述
|
||||
本功能模块是为一线网格员(NEPG端)设计的核心操作界面。它使得网格员能够清晰地接收、查看和处理由管理员分配的污染勘查任务,并在简化的网格地图上获得路径指引,最终提交现场的AQI数据,完成任务闭环。
|
||||
|
||||
## 2. 涉及角色
|
||||
- **主要使用者**: `网格员 (GRID_WORKER)`
|
||||
|
||||
## 3. 业务规则
|
||||
|
||||
### 3.1 任务接收与查看
|
||||
- 网格员登录后,首页即为任务列表。
|
||||
- 任务列表默认按`任务优先级`降序、`创建时间`升序排列。
|
||||
- **任务优先级**由后端动态计算,主要基于反馈的`severityLevel`(严重等级)和任务的等待时长。
|
||||
- 每个任务项应清晰展示关键信息:`标题`、`文字地址`、`优先级`、`状态`。
|
||||
|
||||
### 3.2 任务处理规则
|
||||
- **任务接受与拒绝**:
|
||||
- 对于`severityLevel`为`HIGH`的任务,网格员**不可拒绝**。
|
||||
- 对于`severityLevel`为`LOW`或`MEDIUM`的任务,网格员在任务详情页可以点击"拒绝"按钮。
|
||||
- 拒绝时需选择一个预设的理由(如"当前任务繁忙"、"超出能力范围"等)。
|
||||
- 拒绝后,该任务会从该网格员的列表中移除,并由系统自动进行再分配。
|
||||
- **数据提交**:
|
||||
- 网格员到达现场后,必须在任务详情页填写并提交`AQI数据`表单才能完成任务。
|
||||
- `AqiData`记录与`Feedback`记录强关联。
|
||||
- **主动上报**: 系统允许网格员在没有关联任务的情况下,主动上报其所在网格的AQI数据。
|
||||
|
||||
### 3.3 地图与定位规则
|
||||
- **实时定位**: 进入任务详情页时,App应请求获取网格员的实时地理位置,并在地图上标记。
|
||||
- **路径规划**: A*路径规划仅在首次进入详情页时计算一次。如果网格员偏离了规划路径,可以提供一个"重新规划"按钮。
|
||||
- **离线地图**: (未来规划)为节省流量和应对网络不佳的情况,可以考虑支持离线网格地图的缓存。
|
||||
|
||||
## 4. 功能实现流程
|
||||
|
||||
### 4.1 任务处理流程
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "NEPG 端 (网格员操作)"
|
||||
A[登录系统] --> B[查看任务列表];
|
||||
B --> C{选择一个任务};
|
||||
C --> D[查看任务详情];
|
||||
|
||||
D --> E{任务是否为HIGH等级?};
|
||||
E -- 否 --> F[显示"接受"和"拒绝"按钮];
|
||||
F -- 点击拒绝 --> G[任务被退回,流程结束];
|
||||
E -- 是 --> H[只显示"接受"按钮];
|
||||
|
||||
F -- 点击接受 --> I{处理任务};
|
||||
H --> I;
|
||||
|
||||
I --> J[在网格地图上<br>查看路径指引];
|
||||
J --> K[到达现场<br>勘查并记录数据];
|
||||
K --> L[填写并提交<br>AQI数据报告];
|
||||
end
|
||||
|
||||
subgraph "后端服务"
|
||||
L --> M[创建AqiData记录];
|
||||
M --> N[更新Feedback状态<br>为SUBMITTED];
|
||||
end
|
||||
|
||||
style D fill:#E3F2FD
|
||||
style G fill:#FFCDD2
|
||||
style N fill:#C8E6C9
|
||||
```
|
||||
|
||||
### 4.2 主动上报流程
|
||||
```mermaid
|
||||
graph TD
|
||||
A[网格员在主界面<br>点击"主动上报"] --> B[进入上报页面];
|
||||
B --> C[系统自动获取<br>当前网格位置];
|
||||
C --> D[填写AQI数据表单];
|
||||
D --> E{点击提交};
|
||||
E --> F[后端创建无关联<br>feedbackId的AqiData记录];
|
||||
F --> G[提示"上报成功"];
|
||||
|
||||
style C fill:#E3F2FD
|
||||
style F fill:#C8E6C9
|
||||
```
|
||||
|
||||
## 5. API 接口设计
|
||||
|
||||
### 5.1 获取我的任务列表
|
||||
- **URL**: `GET /api/worker/tasks`
|
||||
- **权限**: `GRID_WORKER`
|
||||
- **查询参数**: `status` (可选: `ASSIGNED`, `IN_PROGRESS`), `page`, `size`
|
||||
- **成功响应** (`200 OK`): 返回分页的任务列表。
|
||||
|
||||
### 5.2 获取任务详情
|
||||
- **URL**: `GET /api/worker/tasks/{taskId}`
|
||||
- **权限**: `GRID_WORKER`
|
||||
- **成功响应** (`200 OK`): 返回任务的详细信息,包含公众提交的描述、图片,以及A*算法规划出的路径坐标点数组。
|
||||
|
||||
### 5.3 接受任务
|
||||
- **URL**: `POST /api/worker/tasks/{taskId}/accept`
|
||||
- **权限**: `GRID_WORKER`
|
||||
- **成功响应** (`200 OK`): `{ "message": "任务已接受" }`
|
||||
|
||||
### 5.4 拒绝任务
|
||||
- **URL**: `POST /api/worker/tasks/{taskId}/reject`
|
||||
- **权限**: `GRID_WORKER`
|
||||
- **请求体**: `{"reason": "当前任务繁忙"}`
|
||||
- **成功响应** (`200 OK`): `{ "message": "任务已拒绝" }`
|
||||
|
||||
### 5.5 提交任务报告
|
||||
- **URL**: `POST /api/worker/tasks/{taskId}/submit`
|
||||
- **权限**: `GRID_WORKER`
|
||||
- **请求体** (application/json):
|
||||
```json
|
||||
{
|
||||
"notes": "已到现场检查,确认存在异味,已要求整改",
|
||||
"aqiData": {
|
||||
"pm25": 75.5, "pm10": 120.3, "so2": 15.8,
|
||||
"no2": 40.2, "co": 1.2, "o3": 65.2
|
||||
}
|
||||
}
|
||||
```
|
||||
- **成功响应** (`200 OK`): `{ "message": "任务报告提交成功,等待主管审核" }`
|
||||
|
||||
### 5.6 主动上报AQI数据
|
||||
- **URL**: `POST /api/worker/aqi-data/report`
|
||||
- **权限**: `GRID_WORKER`
|
||||
- **请求体**:
|
||||
```json
|
||||
{
|
||||
"gridX": 15,
|
||||
"gridY": 20,
|
||||
"aqiData": { ... }
|
||||
}
|
||||
```
|
||||
- **成功响应** (`201 Created`): `{ "message": "数据上报成功" }`
|
||||
|
||||
## 6. 错误处理与边界情况
|
||||
|
||||
| 场景 | 触发条件 | 系统处理 | 用户提示 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **定位失败** | App无法获取GPS信号 | 地图模块显示默认位置(如市中心),并提示用户检查定位服务 | "无法获取您的位置,请检查GPS设置" |
|
||||
| **提交时网络中断**| 点击提交后,网络断开 | ① App应缓存用户填写的数据;<br>② 网络恢复后,提示用户是否重新提交。| "网络连接已断开,您的报告已保存。网络恢复后将提示您重新提交。"|
|
||||
| **任务已被取消/重分配**| 网格员处理一个已被主管取消的任务 | 调用任何与该任务相关的API时,后端返回`404 Not Found`或`409 Conflict` | 详情页提示"该任务已被取消或重新分配",并引导用户返回列表页 |
|
||||
|
||||
## 7. 界面设计要求
|
||||
|
||||
### 7.1 任务列表页面
|
||||
- **布局**: 采用卡片列表形式,每个卡片代表一个任务。
|
||||
- **卡片内容**:
|
||||
- 左上角用不同颜色的标签标示优先级(`高`-红色, `中`-橙色, `低`-蓝色)。
|
||||
- 显示反馈`标题`和`文字地址`。
|
||||
- 右下角显示任务当前状态(如`待接受`、`处理中`)。
|
||||
- **交互**:
|
||||
- 点击卡片进入任务详情页。
|
||||
- 列表应支持**下拉刷新**功能。
|
||||
- 页面右上角提供一个"主动上报"的浮动按钮。
|
||||
|
||||
### 7.2 任务详情页面
|
||||
- **顶部**: 清晰展示任务的`标题`、`详细描述`、`污染类型`、`严重等级`以及公众提交的`现场照片`(支持点击放大)。
|
||||
- **中部 (地图)**:
|
||||
- 内嵌一个简化的网格地图组件。
|
||||
- 在地图上用不同图标标示出**网格员当前位置**和**目标任务位置**。
|
||||
- 自动规划并高亮显示从起点到终点的**最优路径**(A*算法结果),路径需能绕开障碍网格。
|
||||
- 地图右下角应提供"重新定位"和"重新规划路径"的按钮。
|
||||
- **底部 (操作区)**:
|
||||
- **状态: ASSIGNED**: 根据业务规则显示"接受"和"拒绝"按钮。
|
||||
- **状态: IN_PROGRESS**: 显示一个"提交报告"按钮。点击后,弹出一个包含AQI数据表单的对话框。
|
||||
- **状态: SUBMITTED / COMPLETED**: 不显示任何操作按钮,仅展示任务信息和已提交的报告。
|
||||
- **AQI数据提交表单 (弹窗)**:
|
||||
- 包含`PM2.5`, `PM10`, `SO2`, `NO2`, `CO`, `O3`等数值输入框。
|
||||
- 还有一个可选的`备注`多行文本框。
|
||||
- 有一个"确认提交"按钮,点击后显示加载状态,成功后关闭弹窗并自动刷新任务详情页的状态。
|
||||
|
||||
### 7.3 主动上报页面
|
||||
- 页面核心是一个地图,自动定位到网格员当前位置。
|
||||
- 地图下方是一个简化的AQI数据提交表单,允许网格员直接填写数据并提交。
|
||||
- 提交成功后显示成功提示,并返回到主界面。
|
||||
@@ -1,163 +0,0 @@
|
||||
# 角色与晋升体系 - 功能设计文档
|
||||
|
||||
## 1. 功能描述
|
||||
本功能模块定义了系统内所有用户的角色身份、权限边界、以及角色之间的流转路径。它旨在建立一个清晰、安全、易于管理的权限体系,支撑起"公众参与"和"内部管理"两条核心业务线。
|
||||
|
||||
## 2. 涉及角色
|
||||
- **所有角色**: `公众监督员`, `业务主管`, `网格员`, `系统管理员`, `决策者`。
|
||||
- **核心操作者**: `系统管理员 (ADMIN)` 是执行角色晋升和管理的主要操作者。
|
||||
|
||||
## 3. 业务规则
|
||||
|
||||
### 3.1 角色定义与权限
|
||||
- **公众监督员 (PUBLIC_SUPERVISOR)**: 外部用户,只能使用NEPS端,仅能查看和管理自己提交的反馈。
|
||||
- **业务主管 (SUPERVISOR)**: 内部核心**业务管理者**。使用NEPM管理端,负责其管辖区域内的**任务创建、分配、审核、取消**等全生命周期管理。
|
||||
- **网格员 (GRID_WORKER)**: 内部核心**任务执行者**。使用NEPG端,负责接收、执行和提交任务。
|
||||
- **系统管理员 (ADMIN)**: 内部核心**系统维护者**。使用NEPM管理端,负责用户账户管理(审批、创建、晋升)、系统配置等,**不参与日常业务流程**。
|
||||
- **决策者 (DECISION_MAKER)**: 内部高级观察用户,使用NEPV端,拥有对所有统计和可视化数据的**只读权限**。
|
||||
|
||||
### 3.2 角色晋升规则
|
||||
- 晋升是**单向**的、**逐级**的。
|
||||
- **禁止跨级晋升**。
|
||||
- **`PUBLIC_SUPERVISOR` -> `GRID_WORKER` (入职)**: 由用户在NEPS端主动提交申请,经由**系统管理员(ADMIN)**在NEPM端审批通过,代表用户正式成为内部员工。
|
||||
- **`GRID_WORKER` -> `SUPERVISOR` (晋升)**: 由其直属上级或**系统管理员(ADMIN)**在NEPM端为其执行`promote()`操作,代表从一线执行者晋升为业务管理者。
|
||||
- **`ADMIN` 与 `DECISION_MAKER`**: 特殊角色,不参与业务晋升流。由系统更高权限的管理员在后台直接配置。
|
||||
|
||||
### 3.3 数据模型映射
|
||||
- **实体关系**: 一个 `User` 实体**拥有一个** `Role` 属性。
|
||||
- **关键字段**: 角色和状态的管理主要依赖 `user_account` 表中的以下字段:
|
||||
- `role` (Enum: `PUBLIC_SUPERVISOR`, `GRID_WORKER`, `SUPERVISOR`, `ADMIN`, `DECISION_MAKER`): 定义用户的角色。
|
||||
- `status` (Enum: `PENDING_APPROVAL`, `ACTIVE`, `REJECTED`, `DISABLED`): 定义用户的状态。新申请的用户状态为`PENDING_APPROVAL`,审批通过后为`ACTIVE`。
|
||||
- **操作**: 角色晋升或状态变更是对 `user_account` 表中特定记录的 `role` 和 `status` 字段的原子更新。
|
||||
|
||||
### 3.4 权限矩阵 (Permission Matrix)
|
||||
| 功能模块 | API 端点 (示例) | `PUBLIC_SUPERVISOR` | `GRID_WORKER` | `SUPERVISOR` | `ADMIN` | `DECISION_MAKER` |
|
||||
| :--- | :--- | :---: | :---: | :---: | :---: | :---: |
|
||||
| **公众反馈** | `POST /api/feedback` | C | - | - | - | - |
|
||||
| | `GET /api/feedback/my` | R | - | - | - | - |
|
||||
| **任务处理** | `GET /api/worker/tasks` | - | R | - | - | - |
|
||||
| | `POST /api/worker/tasks/{id}/submit`| - | U | - | - | - |
|
||||
| **任务管理** | `GET /api/supervisor/tasks` | - | - | R | - | - |
|
||||
| | `POST /api/supervisor/tasks` | - | - | C | - | - |
|
||||
| | `PUT /api/supervisor/tasks/{id}` | - | - | U | - | - |
|
||||
| | `DELETE /api/supervisor/tasks/{id}`| - | - | D | - | - |
|
||||
| | `POST /api/supervisor/tasks/{id}/approve` | - | - | **Approve** | - | - |
|
||||
| **用户管理** | `GET /api/admin/users` | - | - | R (下属) | R (全部) | - |
|
||||
| | `POST /api/admin/users/{id}/promote` | - | - | - | **Promote** | - |
|
||||
| **入职审批** | `GET /api/admin/approvals` | - | - | - | R | - |
|
||||
| | `POST /api/admin/approvals/{id}/approve` | - | - | - | **Approve** | - |
|
||||
| **数据大屏** | `GET /api/data-v/*` | - | - | - | R | R |
|
||||
| *C=Create, R=Read, U=Update, D=Delete* |
|
||||
|
||||
## 4. 功能实现流程
|
||||
|
||||
### 4.1 总体晋升流程
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "外部用户区 (NEPS)"
|
||||
A[公众注册<br/>默认角色: PUBLIC_SUPERVISOR] --> B{个人中心};
|
||||
B --> C[提交入职申请<br>成为网格员];
|
||||
end
|
||||
|
||||
subgraph "内部管理区 (NEPM)"
|
||||
C --> D["管理员(ADMIN)审批列表"];
|
||||
D -- 通过 --> E[角色变更为 GRID_WORKER];
|
||||
E --> F{用户管理};
|
||||
F -- 管理员执行promote() --> G[角色变更为 SUPERVISOR];
|
||||
end
|
||||
|
||||
subgraph "后台配置"
|
||||
H[系统最高管理员] --> I[为特定用户分配<br/>ADMIN/DECISION_MAKER角色];
|
||||
end
|
||||
|
||||
style A fill:#E3F2FD,stroke:#333,stroke-width:2px
|
||||
style E fill:#C8E6C9,stroke:#333,stroke-width:2px
|
||||
style G fill:#FFD54F,stroke:#333,stroke-width:2px
|
||||
style I fill:#FFECB3,stroke:#333,stroke-width:2px
|
||||
```
|
||||
|
||||
### 4.2 申请入职时序图
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as "公众监督员 (NEPS)"
|
||||
participant Frontend as "前端 (NEPS)"
|
||||
participant Backend as "后端 (API)"
|
||||
participant Admin as "系统管理员 (NEPM)"
|
||||
|
||||
User->>Frontend: 点击"申请成为网格员"
|
||||
Frontend->>User: 显示申请信息填写表单
|
||||
User->>Frontend: 填写并提交申请
|
||||
Frontend->>Backend: POST /api/users/apply-for-worker (携带申请信息)
|
||||
Backend->>Backend: 创建申请记录, 更新用户状态为`PENDING_APPROVAL`
|
||||
Backend-->>Frontend: 申请已提交 (200 OK)
|
||||
Frontend->>User: 显示"申请已提交,等待管理员审批"
|
||||
|
||||
Admin->>Backend: (在NEPM端) GET /api/admin/approvals
|
||||
Backend-->>Admin: 返回待审批用户列表
|
||||
Admin->>Backend: POST /api/admin/approvals/{userId}/approve
|
||||
Backend->>Backend: 校验权限, 更新用户role为`GRID_WORKER`, status为`ACTIVE`
|
||||
Backend-->>Admin: 审批成功 (200 OK)
|
||||
```
|
||||
|
||||
### 4.3 角色晋升时序图
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Admin as "系统管理员 (NEPM)"
|
||||
participant Frontend as "前端 (NEPM)"
|
||||
participant Backend as "后端 (API)"
|
||||
participant User as "被晋升的用户 (Grid Worker)"
|
||||
|
||||
Admin->>Frontend: 在用户管理列表, 点击"晋升为主管"
|
||||
Frontend->>Frontend: 弹出二次确认对话框
|
||||
Admin->>Frontend: 确认操作
|
||||
Frontend->>Backend: POST /api/admin/users/{userId}/promote
|
||||
Backend->>Backend: 校验管理员权限
|
||||
Backend->>Backend: 校验目标用户当前角色为`GRID_WORKER`
|
||||
Backend->>Backend: 更新用户role为`SUPERVISOR`
|
||||
Backend-->>Frontend: 晋升成功 (200 OK)
|
||||
Frontend->>Admin: 刷新列表, 显示用户新角色
|
||||
|
||||
User->>Backend: (下次登录或刷新页面时)
|
||||
Backend-->>User: 返回更新后的角色信息和权限
|
||||
Note right of User: 用户界面(菜单、操作按钮)随新角色动态更新
|
||||
```
|
||||
|
||||
## 5. API接口设计
|
||||
|
||||
### 5.1 用户申请成为网格员
|
||||
- **URL**: `POST /api/users/apply-for-worker`
|
||||
- **权限**: `PUBLIC_SUPERVISOR`
|
||||
- **请求体**: `applicationReason`, `experience`
|
||||
- **响应**: `200 OK`
|
||||
|
||||
### 5.2 管理员获取待审批列表
|
||||
- **URL**: `GET /api/admin/approvals`
|
||||
- **权限**: `ADMIN`
|
||||
- **响应**: `200 OK`, 返回用户申请列表 `[{userId, name, applicationTime, ...}]`
|
||||
|
||||
### 5.3 管理员审批
|
||||
- **URL**: `POST /api/admin/approvals/{userId}/approve` 或 `.../reject`
|
||||
- **权限**: `ADMIN`
|
||||
- **请求体**: (可选) `rejectionReason`
|
||||
- **响应**: `200 OK`
|
||||
|
||||
### 5.4 管理员晋升用户
|
||||
- **URL**: `POST /api/admin/users/{userId}/promote`
|
||||
- **权限**: `ADMIN`
|
||||
- **响应**: `200 OK`
|
||||
|
||||
## 6. 界面设计要求
|
||||
|
||||
### 6.1 NEPS端 (公众监督员)
|
||||
- 在"个人中心"或"我的"页面,应有一个醒目的入口,如"申请成为网格员"按钮。
|
||||
- 点击后, 弹出一个表单或新页面, 要求用户填写申请理由、相关经验等附加信息, 并提交。
|
||||
- 提交后,按钮应变为"审批中..."的不可点击状态。
|
||||
- 用户的申请状态(待审批、已通过、已驳回)应在个人中心清晰展示。若被驳回,应显示驳回原因。
|
||||
|
||||
### 6.2 NEPM端 (管理员 ADMIN)
|
||||
- 在侧边栏应有"用户管理"和"入职审批"两个菜单项。
|
||||
- **入职审批页面**: 以列表形式展示所有待审批的申请,包含申请人姓名、申请时间、申请理由等。管理员可点击"通过"或"驳回"。操作后有明确的成功提示,且该条目从列表中移除。
|
||||
- **用户管理页面**:
|
||||
- 以表格形式展示其管辖范围内的所有内部用户列表(包括网格员、主管),并可通过角色、状态进行筛选。
|
||||
- 表格的"操作"列中,应包含对符合条件的`GRID_WORKER`的"晋升为主管"按钮。
|
||||
- 点击"晋升"按钮,应有二次确认弹窗,明确告知"用户XXX的角色将从GridWorker变更为Supervisor",防止误操作。操作成功后,该用户的角色信息在表格中应立即更新。
|
||||
@@ -1,173 +0,0 @@
|
||||
# 账号管理功能 - 设计文档
|
||||
|
||||
## 1. 功能描述
|
||||
本模块负责处理所有用户的认证与基础账户操作,包括注册、登录和安全设置(如忘记密码、修改密码/手机号)。其核心目标是提供一个安全、可靠且用户体验良好的身份验证入口。
|
||||
|
||||
## 2. 涉及角色
|
||||
- **所有角色**: 该功能是所有需要登录系统的用户(公众监督员、监督员、网格员、管理员、决策者)的通用基础功能。
|
||||
|
||||
## 3. 业务规则
|
||||
|
||||
### 3.1 注册规则
|
||||
- **唯一性约束**: 注册时使用的`邮箱`和`手机号`必须在`user_account`表中是唯一的。
|
||||
- **密码策略**:
|
||||
- 复杂度: 8-16位,必须同时包含大写字母、小写字母、数字和特殊字符。
|
||||
- 确认机制: 注册时密码需要输入两次进行确认。
|
||||
- 存储安全: 密码在后端必须使用强哈希算法(如BCrypt)加盐后存储,绝不允许明文存储。
|
||||
- **邮箱验证码规则**:
|
||||
- **时效性**: 验证码生成后5分钟内有效。
|
||||
- **冷却期**: "获取验证码"按钮点击后,有60秒的冷却时间,防止恶意请求。
|
||||
- **尝试次数**: 同一个验证码最多允许输错2次,第3次输错则该验证码立即失效,需重新获取。
|
||||
|
||||
### 3.2 登录规则
|
||||
- 支持使用`邮箱`或`手机号`作为登录凭据。
|
||||
- 登录失败时,应给出统一的、模糊的提示(如"用户名或密码错误"),避免泄露账户是否存在的信息。
|
||||
- 可考虑引入登录尝试次数限制机制,例如连续失败5次后,临时锁定账户15分钟。
|
||||
|
||||
### 3.3 安全验证规则
|
||||
- **身份确认**: "忘记密码"或"修改手机号"等敏感操作,必须先通过"邮箱 + 姓名"进行第一步身份确认。
|
||||
- **操作授权**: 身份确认通过后,必须再次完成与注册流程完全相同的邮箱动态验证码校验,才能进行下一步操作。
|
||||
|
||||
### 3.4 JWT (Token) 规则
|
||||
- **Payload 结构**: Token的Payload中应至少包含`userId`, `role`, `email`,以便后端进行快速的身份和权限识别。
|
||||
- **有效期**: Access Token的有效期应设置为较短的时间(如1小时),以降低泄露风险。
|
||||
- **刷新机制**: 提供一个Refresh Token,其有效期更长(如7天)。当Access Token过期后,前端可使用Refresh Token向后端申请新的Access Token,无需用户重新登录。
|
||||
- **存储**: 前端应将Access Token存储在内存中,将Refresh Token存储在`HttpOnly`、`Secure`的Cookie中,以提高安全性。
|
||||
|
||||
### 3.5 系统管理员操作规则
|
||||
- **创建内部账户**: 系统管理员(Admin)在NEPM端创建内部用户(如`SUPERVISOR`, `GRID_WORKER`)时,系统应生成一个安全的初始随机密码。
|
||||
- **密码重置**: 管理员可以为任何用户重置密码,重置后同样生成一个随机密码。
|
||||
- **密码分发**: 生成的初始密码或重置后的密码,应通过安全的、非系统内的方式(如邮件、短信)告知用户,并强制用户在首次登录后立即修改。
|
||||
|
||||
## 4. 功能实现流程
|
||||
|
||||
### 4.1 注册流程
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant Frontend as 前端界面
|
||||
participant Backend as 后端服务
|
||||
participant Mail as 邮箱服务
|
||||
|
||||
User->>Frontend: 填写注册信息 (邮箱, 手机, 密码等)
|
||||
Note right of Frontend: 前端实时校验格式和密码强度
|
||||
User->>Frontend: 点击"获取验证码"
|
||||
Frontend->>Backend: POST /api/auth/send-verification-code
|
||||
Note over Backend: 生成6位验证码, 存入Redis并设5分钟过期
|
||||
Backend->>Mail: 调用163邮箱API发送验证码
|
||||
Mail-->>User: 收到验证码邮件
|
||||
User->>Frontend: 输入收到的验证码
|
||||
User->>Frontend: 点击"注册"
|
||||
Frontend->>Backend: POST /api/auth/register
|
||||
Backend->>Backend: 校验验证码 (正确性, 是否过期, 尝试次数)
|
||||
alt 验证成功
|
||||
Backend->>Backend: 校验邮箱/手机唯一性, BCrypt加密密码
|
||||
Backend->>Backend: 创建`user_account`记录
|
||||
Backend-->>Frontend: 注册成功 (201 Created)
|
||||
else 验证失败
|
||||
Backend-->>Frontend: 返回错误信息 (400 Bad Request)
|
||||
end
|
||||
```
|
||||
|
||||
### 4.2 登录流程
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant Frontend as 前端
|
||||
participant Backend as 后端
|
||||
|
||||
User->>Frontend: 输入邮箱/手机号和密码, 点击登录
|
||||
Frontend->>Backend: POST /api/auth/login
|
||||
Backend->>Backend: 验证用户信息和密码
|
||||
alt 验证成功
|
||||
Backend->>Backend: 生成Access Token和Refresh Token
|
||||
Backend-->>Frontend: 登录成功 (200 OK)<br>返回Access Token, 并设置Refresh Token到Cookie
|
||||
Note left of Frontend: 存储Token, 跳转到用户主页
|
||||
else 验证失败
|
||||
Backend->>Backend: 记录失败次数, 检查是否需要锁定账户
|
||||
Backend-->>Frontend: 返回"用户名或密码错误" (401 Unauthorized)
|
||||
end
|
||||
```
|
||||
|
||||
### 4.3 忘记密码流程
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant Frontend as 前端界面
|
||||
participant Backend as 后端服务
|
||||
|
||||
User->>Frontend: 点击"忘记密码", 输入邮箱和姓名
|
||||
Frontend->>Backend: POST /api/auth/request-password-reset
|
||||
Backend->>Backend: 校验邮箱和姓名是否存在且匹配
|
||||
alt 身份校验成功
|
||||
Backend-->>Frontend: 跳转至邮箱验证码页面
|
||||
Note right of Frontend: (后续流程与注册时的邮箱验证完全相同)
|
||||
User->>Frontend: 完成邮箱验证, 输入新密码
|
||||
Frontend->>Backend: POST /api/auth/reset-password
|
||||
Backend->>Backend: 更新用户密码
|
||||
Backend-->>Frontend: 密码重置成功 (200 OK)
|
||||
else 身份校验失败
|
||||
Backend-->>Frontend: 返回错误信息 (400 Bad Request)
|
||||
end
|
||||
```
|
||||
|
||||
## 5. API 接口设计
|
||||
|
||||
### 5.1 用户注册
|
||||
- **URL**: `POST /api/auth/register`
|
||||
- **请求体**: `name`, `email`, `phone`, `password`, `verificationCode`
|
||||
- **响应**: `201 Created`
|
||||
|
||||
### 5.2 用户登录
|
||||
- **URL**: `POST /api/auth/login`
|
||||
- **请求体**: `principal` (邮箱或手机号), `password`
|
||||
- **响应**: `200 OK`, 返回 `accessToken`,并在Cookie中设置`refreshToken`。
|
||||
|
||||
### 5.3 发送邮箱验证码
|
||||
- **URL**: `POST /api/auth/send-verification-code`
|
||||
- **请求体**: `email`, `type` (Enum: `REGISTER`, `RESET_PASSWORD`)
|
||||
- **响应**: `200 OK`
|
||||
|
||||
### 5.4 刷新AccessToken
|
||||
- **URL**: `POST /api/auth/refresh-token`
|
||||
- **请求体**: (空, Refresh Token从Cookie中获取)
|
||||
- **响应**: `200 OK`, 返回新的`accessToken`。
|
||||
|
||||
### 5.5 请求密码重置
|
||||
- **URL**: `POST /api/auth/request-password-reset`
|
||||
- **请求体**: `email`, `name`
|
||||
- **响应**: `200 OK` (无论用户是否存在,都返回成功,防止信息泄露)
|
||||
|
||||
### 5.6 重置密码
|
||||
- **URL**: `POST /api/auth/reset-password`
|
||||
- **请求体**: `email`, `newPassword`, `verificationCode`
|
||||
- **响应**: `200 OK`
|
||||
|
||||
### 5.7 管理员创建用户
|
||||
- **URL**: `POST /api/admin/users`
|
||||
- **权限**: `ADMIN`
|
||||
- **请求体**: `name`, `email`, `phone`, `role`, `region`, `level`
|
||||
- **响应**: `201 Created`, 返回包含初始随机密码的用户信息。
|
||||
|
||||
## 6. 界面设计要求
|
||||
|
||||
### 6.1 注册页面
|
||||
- 表单布局清晰,各输入项有明确的标签和占位提示。
|
||||
- "获取验证码"按钮在点击后应变为不可用状态,并显示倒计时。
|
||||
- 密码输入框应为密码类型,并提供一个可切换"显示/隐藏"密码的图标。
|
||||
- 密码强度提示:实时根据用户输入,以进度条或文字形式提示密码强度(弱、中、强)。
|
||||
- 所有输入项的错误提示应在输入框下方实时显示,内容明确。
|
||||
|
||||
### 6.2 登录页面
|
||||
- 界面简洁,突出登录表单。
|
||||
- 提供"忘记密码"的链接。
|
||||
- 可选提供"记住我"的复选框。
|
||||
- 登录成功后,应有平滑的过渡效果,并根据用户角色跳转到对应的系统主页(NEPS, NEPG, NEPM, NEPV)。
|
||||
|
||||
### 6.3 忘记密码/安全验证页面
|
||||
- 流程应分步进行,保持每一步操作的单一和清晰。
|
||||
- 第一步:身份验证(输入邮箱、姓名)。
|
||||
- 第二步:安全验证(输入邮箱收到的验证码)。
|
||||
- 第三步:重置密码(输入新密码并确认)。
|
||||
- 每个步骤都应有清晰的标题和进度指示。
|
||||
- 操作成功后,应明确提示用户"密码已重置,请使用新密码登录",并引导至登录页面。
|
||||
@@ -1,57 +0,0 @@
|
||||
# EMS后端系统技术图表文档
|
||||
|
||||
## 项目概述
|
||||
|
||||
环境管理系统(EMS)后端是一个基于Spring Boot的Java应用程序,用于处理环境问题反馈、任务分配和用户管理。系统采用分层架构,包含控制器、服务、仓库和模型层。
|
||||
|
||||
## 1. 系统时序图
|
||||
- **见时序图.md**
|
||||
## 2. UML类图
|
||||
- **见UML类图.md**
|
||||
## 3. ER图
|
||||
- **见ER图.md**
|
||||
|
||||
|
||||
## 4. 系统架构说明
|
||||
|
||||
### 4.1 分层架构
|
||||
|
||||
- **控制器层(Controller)**: 处理HTTP请求,参数验证,响应格式化
|
||||
- **服务层(Service)**: 业务逻辑处理,事务管理
|
||||
- **仓库层(Repository)**: 数据访问,数据库操作
|
||||
- **模型层(Model)**: 实体定义,数据结构
|
||||
|
||||
### 4.2 核心业务流程
|
||||
|
||||
1. **用户认证**: JWT令牌生成和验证
|
||||
2. **反馈管理**: 环境问题反馈的提交、审核、处理
|
||||
3. **任务分配**: 基于反馈创建任务并分配给网格工作人员
|
||||
4. **状态跟踪**: 反馈和任务状态的生命周期管理
|
||||
|
||||
### 4.3 **安全机制**
|
||||
|
||||
- 基于角色的访问控制(RBAC)
|
||||
- JWT令牌认证
|
||||
- 密码加密存储
|
||||
- 操作日志记录
|
||||
|
||||
### 4.4 数据完整性
|
||||
|
||||
- 外键约束确保数据一致性
|
||||
- 唯一约束防止重复数据
|
||||
- 枚举类型确保状态值有效性
|
||||
- 时间戳记录数据变更历史
|
||||
|
||||
## 5. 技术栈
|
||||
|
||||
- **框架**: Spring Boot 3.x
|
||||
- **数据库**: MySQL/PostgreSQL
|
||||
- **ORM**: Spring Data JPA + Hibernate
|
||||
- **安全**: Spring Security + JWT
|
||||
- **文档**: Swagger/OpenAPI 3
|
||||
- **构建工具**: Maven
|
||||
- **Java版本**: JDK 17+
|
||||
|
||||
---
|
||||
|
||||
*本文档基于EMS后端项目代码分析生成,包含完整的系统设计图表,可用于系统理解、开发指导和文档维护。*
|
||||
648
Report/ER图.md
648
Report/ER图.md
@@ -1,648 +0,0 @@
|
||||
## 3. ER图
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
USER_ACCOUNT {
|
||||
BIGINT id PK
|
||||
VARCHAR username
|
||||
VARCHAR password
|
||||
VARCHAR email
|
||||
VARCHAR phone
|
||||
BIGINT role_id FK
|
||||
BIGINT grid_id FK
|
||||
}
|
||||
|
||||
ROLE {
|
||||
BIGINT id PK
|
||||
VARCHAR name
|
||||
}
|
||||
|
||||
FEEDBACK {
|
||||
BIGINT id PK
|
||||
TEXT content
|
||||
VARCHAR location
|
||||
VARCHAR status
|
||||
BIGINT submitter_id FK
|
||||
}
|
||||
|
||||
TASK {
|
||||
BIGINT id PK
|
||||
TEXT description
|
||||
VARCHAR status
|
||||
BIGINT feedback_id FK
|
||||
BIGINT assignee_id FK
|
||||
}
|
||||
|
||||
GRID {
|
||||
BIGINT id PK
|
||||
INT grid_x
|
||||
INT grid_y
|
||||
}
|
||||
|
||||
OPERATION_LOG {
|
||||
BIGINT id PK
|
||||
VARCHAR operation_type
|
||||
TEXT details
|
||||
BIGINT operator_id FK
|
||||
}
|
||||
|
||||
ATTACHMENT {
|
||||
BIGINT id PK
|
||||
BIGINT feedback_id FK
|
||||
VARCHAR file_url
|
||||
}
|
||||
|
||||
USER_ACCOUNT ||--o{ ROLE : "has"
|
||||
USER_ACCOUNT ||--o{ FEEDBACK : "submits"
|
||||
USER_ACCOUNT ||--o{ TASK : "assigned"
|
||||
USER_ACCOUNT ||--o{ GRID : "belongs to"
|
||||
FEEDBACK ||--o{ TASK : "leads to"
|
||||
USER_ACCOUNT ||--o{ OPERATION_LOG : "performs"
|
||||
FEEDBACK ||--o{ ATTACHMENT : "has"
|
||||
```
|
||||
participant Database as 数据库
|
||||
|
||||
Admin->>+OperationLogController: GET /api/logs (过滤条件)
|
||||
OperationLogController->>+OperationLogService: queryOperationLogs(filters)
|
||||
OperationLogService->>+OperationLogRepository: findByCriteria(filters)
|
||||
OperationLogRepository->>+Database: SELECT * FROM operation_logs WHERE ...
|
||||
Database-->>-OperationLogRepository: 返回日志记录
|
||||
OperationLogRepository-->>-OperationLogService: 返回日志DTO列表
|
||||
OperationLogService-->>-OperationLogController: 返回日志DTO列表
|
||||
OperationLogController-->>-Admin: 200 OK (日志列表)
|
||||
```
|
||||
|
||||
### 1.16 管理员创建新用户
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Admin as 管理员
|
||||
participant PersonnelController as 人员控制器
|
||||
participant PersonnelService as 人员服务
|
||||
participant UserAccountRepository as 用户账户仓库
|
||||
participant PasswordEncoder as 密码编码器
|
||||
participant Database as 数据库
|
||||
|
||||
Admin->>+PersonnelController: POST /api/personnel/users (用户信息)
|
||||
PersonnelController->>+PersonnelService: createUser(request)
|
||||
PersonnelService->>+UserAccountRepository: findByUsername(username)
|
||||
UserAccountRepository-->>-PersonnelService: (检查用户是否存在)
|
||||
PersonnelService->>+PasswordEncoder: encode(password)
|
||||
PasswordEncoder-->>-PersonnelService: 返回加密后的密码
|
||||
PersonnelService->>+UserAccountRepository: save(user)
|
||||
UserAccountRepository->>+Database: INSERT INTO user_accounts
|
||||
Database-->>-UserAccountRepository: 返回已保存的用户
|
||||
UserAccountRepository-->>-PersonnelService: 返回已保存的用户
|
||||
PersonnelService-->>-PersonnelController: 返回创建的用户
|
||||
PersonnelController-->>-Admin: 201 CREATED (用户详情)
|
||||
```
|
||||
|
||||
### 1.17 用户获取自己的反馈历史
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant ProfileController as 个人资料控制器
|
||||
participant UserFeedbackService as 用户反馈服务
|
||||
participant CustomUserDetails as 用户认证详情
|
||||
participant Database as 数据库
|
||||
|
||||
User->>+ProfileController: GET /api/me/feedback
|
||||
ProfileController->>+CustomUserDetails: 获取用户ID
|
||||
CustomUserDetails-->>-ProfileController: 返回用户ID
|
||||
ProfileController->>+UserFeedbackService: getFeedbackHistoryByUserId(userId, pageable)
|
||||
UserFeedbackService->>+Database: SELECT * FROM feedback WHERE user_id = ?
|
||||
Database-->>-UserFeedbackService: 返回反馈记录
|
||||
UserFeedbackService-->>-ProfileController: 返回反馈摘要DTO列表
|
||||
ProfileController-->>-User: 200 OK (反馈历史列表)
|
||||
```
|
||||
|
||||
### 1.18 公众提交反馈
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Public as 公众
|
||||
participant PublicController as 公共控制器
|
||||
participant FeedbackService as 反馈服务
|
||||
participant FileStorageService as 文件存储服务
|
||||
participant FeedbackRepository as 反馈仓库
|
||||
participant Database as 数据库
|
||||
|
||||
Public->>+PublicController: POST /api/public/feedback (反馈信息和文件)
|
||||
PublicController->>+FeedbackService: createPublicFeedback(request, files)
|
||||
alt 如果有文件
|
||||
FeedbackService->>+FileStorageService: store(file)
|
||||
FileStorageService-->>-FeedbackService: 返回文件路径
|
||||
end
|
||||
FeedbackService->>+FeedbackRepository: save(feedback)
|
||||
FeedbackRepository->>+Database: INSERT INTO feedback
|
||||
Database-->>-FeedbackRepository: 返回已保存的反馈
|
||||
FeedbackRepository-->>-FeedbackService: 返回已保存的反馈
|
||||
FeedbackService-->>-PublicController: 返回创建的反馈
|
||||
PublicController-->>-Public: 201 CREATED (反馈详情)
|
||||
```
|
||||
|
||||
### 1.19 分配任务给工作人员
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Supervisor as 主管
|
||||
participant TaskAssignmentController as 任务分配控制器
|
||||
participant TaskAssignmentService as 任务分配服务
|
||||
participant AssignmentRepository as 分配仓库
|
||||
participant FeedbackRepository as 反馈仓库
|
||||
participant Database as 数据库
|
||||
|
||||
Supervisor->>+TaskAssignmentController: POST /api/tasks/assign (任务ID, 分配对象ID)
|
||||
TaskAssignmentController->>+TaskAssignmentService: assignTask(feedbackId, assigneeId, assignerId)
|
||||
TaskAssignmentService->>+FeedbackRepository: findById(feedbackId)
|
||||
FeedbackRepository-->>-TaskAssignmentService: 返回任务详情
|
||||
TaskAssignmentService->>+AssignmentRepository: save(assignment)
|
||||
AssignmentRepository->>+Database: INSERT INTO assignments
|
||||
Database-->>-AssignmentRepository: 返回已保存的分配
|
||||
AssignmentRepository-->>-TaskAssignmentService: 返回已保存的分配
|
||||
TaskAssignmentService-->>-TaskAssignmentController: 返回新的分配
|
||||
TaskAssignmentController-->>-Supervisor: 200 OK (分配详情)
|
||||
```
|
||||
|
||||
### 1.20 从反馈创建任务
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Supervisor as 主管
|
||||
participant TaskManagementController as 任务管理控制器
|
||||
participant TaskManagementService as 任务管理服务
|
||||
participant FeedbackRepository as 反馈仓库
|
||||
participant TaskRepository as 任务仓库
|
||||
participant Database as 数据库
|
||||
|
||||
Supervisor->>+TaskManagementController: POST /api/management/tasks/feedback/{feedbackId}/create-task (任务信息)
|
||||
TaskManagementController->>+TaskManagementService: createTaskFromFeedback(feedbackId, request)
|
||||
TaskManagementService->>+FeedbackRepository: findById(feedbackId)
|
||||
FeedbackRepository-->>-TaskManagementService: 返回反馈详情
|
||||
TaskManagementService->>+TaskRepository: save(task)
|
||||
TaskRepository->>+Database: INSERT INTO tasks
|
||||
Database-->>-TaskRepository: 返回已保存的任务
|
||||
TaskRepository-->>-TaskManagementService: 返回已保存的任务
|
||||
TaskManagementService-->>-TaskManagementController: 返回创建的任务详情DTO
|
||||
TaskManagementController-->>-Supervisor: 201 CREATED (任务详情)
|
||||
```
|
||||
|
||||
## 2. UML类图
|
||||
|
||||
### 2.1 核心领域模型类图
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class UserAccount {
|
||||
-Long id
|
||||
-String name
|
||||
-String phone
|
||||
-String email
|
||||
-String password
|
||||
-Gender gender
|
||||
-Role role
|
||||
-UserStatus status
|
||||
-Level level
|
||||
-String department
|
||||
-List~String~ skills
|
||||
-LocalDateTime createdAt
|
||||
-LocalDateTime updatedAt
|
||||
+login() boolean
|
||||
+updateProfile() void
|
||||
+changePassword() void
|
||||
}
|
||||
|
||||
class Feedback {
|
||||
-Long id
|
||||
-String eventId
|
||||
-String title
|
||||
-String description
|
||||
-PollutionType pollutionType
|
||||
-SeverityLevel severityLevel
|
||||
-FeedbackStatus status
|
||||
-String location
|
||||
-Double latitude
|
||||
-Double longitude
|
||||
-String cityName
|
||||
-String districtName
|
||||
-UserAccount submitter
|
||||
-LocalDateTime createdAt
|
||||
-LocalDateTime updatedAt
|
||||
+updateStatus() void
|
||||
+assignToTask() Task
|
||||
}
|
||||
|
||||
class Task {
|
||||
-Long id
|
||||
-Feedback feedback
|
||||
-UserAccount assignee
|
||||
-UserAccount createdBy
|
||||
-TaskStatus status
|
||||
-String title
|
||||
-String description
|
||||
-String location
|
||||
-LocalDateTime assignedAt
|
||||
-LocalDateTime completedAt
|
||||
-LocalDateTime createdAt
|
||||
+assign(UserAccount) void
|
||||
+complete() void
|
||||
+updateProgress() void
|
||||
}
|
||||
|
||||
class Assignment {
|
||||
-Long id
|
||||
-Task task
|
||||
-UserAccount assigner
|
||||
-LocalDateTime assignmentTime
|
||||
-LocalDateTime deadline
|
||||
-AssignmentStatus status
|
||||
-String remarks
|
||||
+setDeadline() void
|
||||
+updateStatus() void
|
||||
}
|
||||
|
||||
class Grid {
|
||||
-Long id
|
||||
-Integer gridX
|
||||
-Integer gridY
|
||||
-String cityName
|
||||
-String districtName
|
||||
-String description
|
||||
-Boolean isObstacle
|
||||
+getCoordinates() Point
|
||||
+isAccessible() boolean
|
||||
}
|
||||
|
||||
class Attachment {
|
||||
-Long id
|
||||
-String fileName
|
||||
-String filePath
|
||||
-String fileType
|
||||
-Long fileSize
|
||||
-LocalDateTime uploadedAt
|
||||
}
|
||||
|
||||
class TaskHistory {
|
||||
-Long id
|
||||
-Task task
|
||||
-UserAccount updatedBy
|
||||
-TaskStatus oldStatus
|
||||
-TaskStatus newStatus
|
||||
-String remarks
|
||||
-LocalDateTime updatedAt
|
||||
}
|
||||
|
||||
%% 枚举类
|
||||
class Role {
|
||||
<<enumeration>>
|
||||
PUBLIC_SUPERVISOR
|
||||
SUPERVISOR
|
||||
GRID_WORKER
|
||||
ADMIN
|
||||
DECISION_MAKER
|
||||
}
|
||||
|
||||
class FeedbackStatus {
|
||||
<<enumeration>>
|
||||
PENDING_REVIEW
|
||||
AI_REVIEWING
|
||||
AI_PROCESSING
|
||||
PENDING_ASSIGNMENT
|
||||
ASSIGNED
|
||||
CONFIRMED
|
||||
RESOLVED
|
||||
REJECTED
|
||||
}
|
||||
|
||||
class TaskStatus {
|
||||
<<enumeration>>
|
||||
PENDING_ASSIGNMENT
|
||||
ASSIGNED
|
||||
IN_PROGRESS
|
||||
SUBMITTED
|
||||
COMPLETED
|
||||
CANCELLED
|
||||
}
|
||||
|
||||
class PollutionType {
|
||||
<<enumeration>>
|
||||
AIR
|
||||
WATER
|
||||
SOIL
|
||||
NOISE
|
||||
WASTE
|
||||
OTHER
|
||||
}
|
||||
|
||||
class SeverityLevel {
|
||||
<<enumeration>>
|
||||
LOW
|
||||
MEDIUM
|
||||
HIGH
|
||||
CRITICAL
|
||||
}
|
||||
|
||||
%% 关系
|
||||
UserAccount "1" -- "0..*" Feedback : submits
|
||||
UserAccount "1" -- "0..*" Task : assigned_to
|
||||
UserAccount "1" -- "0..*" Task : created_by
|
||||
UserAccount "1" -- "0..*" Assignment : assigns
|
||||
Feedback "1" -- "1" Task : generates
|
||||
Task "1" -- "1" Assignment : has
|
||||
Task "1" -- "0..*" TaskHistory : logs
|
||||
Feedback "1" -- "0..*" Attachment : has
|
||||
UserAccount -- Role
|
||||
Feedback -- FeedbackStatus
|
||||
Feedback -- PollutionType : categorized_as
|
||||
Feedback -- SeverityLevel : rated_as
|
||||
Task -- TaskStatus"}]}}}
|
||||
```
|
||||
|
||||
### 2.2 控制器层类图
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class AuthController {
|
||||
-AuthService authService
|
||||
-VerificationCodeService verificationCodeService
|
||||
+signUp(SignUpRequest) ResponseEntity
|
||||
+signIn(LoginRequest) ResponseEntity
|
||||
+logout() ResponseEntity
|
||||
+sendVerificationCode(String) ResponseEntity
|
||||
+requestPasswordReset(String) ResponseEntity
|
||||
+resetPassword(PasswordResetRequest) ResponseEntity
|
||||
}
|
||||
|
||||
class FeedbackController {
|
||||
-FeedbackService feedbackService
|
||||
+submitFeedback(FeedbackSubmissionRequest, MultipartFile[]) ResponseEntity
|
||||
+submitFeedbackJson(FeedbackSubmissionRequest) ResponseEntity
|
||||
+submitPublicFeedback(PublicFeedbackRequest, MultipartFile[]) ResponseEntity
|
||||
+getAllFeedback(filters, Pageable) ResponseEntity
|
||||
+getFeedbackById(Long) ResponseEntity
|
||||
+getFeedbackStats(filters) ResponseEntity
|
||||
+processFeedback(Long, ProcessFeedbackRequest) ResponseEntity
|
||||
}
|
||||
|
||||
class UserController {
|
||||
-UserService userService
|
||||
+getCurrentUser() ResponseEntity
|
||||
+updateProfile(UserProfileUpdateRequest) ResponseEntity
|
||||
+getAllUsers(Pageable) ResponseEntity
|
||||
+getUserById(Long) ResponseEntity
|
||||
+updateUserRole(Long, Role) ResponseEntity
|
||||
+deactivateUser(Long) ResponseEntity
|
||||
}
|
||||
|
||||
%% 服务层接口
|
||||
class AuthService {
|
||||
<<interface>>
|
||||
+registerUser(SignUpRequest) void
|
||||
+signIn(LoginRequest) JwtAuthenticationResponse
|
||||
+logout() void
|
||||
+requestPasswordReset(String) void
|
||||
+resetPassword(String, String) void
|
||||
}
|
||||
|
||||
class FeedbackService {
|
||||
<<interface>>
|
||||
+submitFeedback(FeedbackSubmissionRequest, MultipartFile[]) Feedback
|
||||
+getAllFeedback(filters, Pageable) Page~Feedback~
|
||||
+getFeedbackById(Long) Feedback
|
||||
+processFeedback(Long, ProcessFeedbackRequest) Feedback
|
||||
+getFeedbackStats(filters) FeedbackStatsResponse
|
||||
}
|
||||
|
||||
%% 关系
|
||||
AuthController --> AuthService : uses
|
||||
FeedbackController --> FeedbackService : uses
|
||||
UserController --> UserService : uses
|
||||
```
|
||||
|
||||
### 2.3 服务层实现类图
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class AuthServiceImpl {
|
||||
-UserRepository userRepository
|
||||
-PasswordEncoder passwordEncoder
|
||||
-JwtService jwtService
|
||||
-VerificationCodeService verificationCodeService
|
||||
+registerUser(SignUpRequest) void
|
||||
+signIn(LoginRequest) JwtAuthenticationResponse
|
||||
+logout() void
|
||||
+requestPasswordReset(String) void
|
||||
+resetPassword(String, String) void
|
||||
-validateUser(UserAccount) void
|
||||
-generateJwtToken(UserAccount) String
|
||||
}
|
||||
|
||||
class FeedbackServiceImpl {
|
||||
-FeedbackRepository feedbackRepository
|
||||
-UserRepository userRepository
|
||||
-ApplicationEventPublisher eventPublisher
|
||||
-FileStorageService fileStorageService
|
||||
+submitFeedback(FeedbackSubmissionRequest, MultipartFile[]) Feedback
|
||||
+getAllFeedback(filters, Pageable) Page~Feedback~
|
||||
+getFeedbackById(Long) Feedback
|
||||
+processFeedback(Long, ProcessFeedbackRequest) Feedback
|
||||
-generateEventId() String
|
||||
-validateFeedbackData(FeedbackSubmissionRequest) void
|
||||
}
|
||||
|
||||
class TaskServiceImpl {
|
||||
-TaskRepository taskRepository
|
||||
-UserRepository userRepository
|
||||
-AssignmentRepository assignmentRepository
|
||||
+createTask(TaskCreationRequest) Task
|
||||
+assignTask(Long, Long) Assignment
|
||||
+updateTaskStatus(Long, TaskStatus) Task
|
||||
+getTasksByAssignee(Long, Pageable) Page~Task~
|
||||
-validateTaskAssignment(Task, UserAccount) void
|
||||
}
|
||||
|
||||
%% 接口实现关系
|
||||
AuthServiceImpl ..|> AuthService : implements
|
||||
FeedbackServiceImpl ..|> FeedbackService : implements
|
||||
TaskServiceImpl ..|> TaskService : implements
|
||||
```
|
||||
|
||||
## 3. 数据库ER图
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
USER_ACCOUNT {
|
||||
bigint id PK
|
||||
varchar name
|
||||
varchar phone UK
|
||||
varchar email UK
|
||||
varchar password
|
||||
enum gender
|
||||
enum role
|
||||
enum status
|
||||
enum level
|
||||
varchar department
|
||||
text skills
|
||||
datetime created_at
|
||||
datetime updated_at
|
||||
}
|
||||
|
||||
FEEDBACK {
|
||||
bigint id PK
|
||||
varchar event_id UK
|
||||
varchar title
|
||||
text description
|
||||
enum pollution_type
|
||||
enum severity_level
|
||||
enum status
|
||||
varchar location
|
||||
decimal latitude
|
||||
decimal longitude
|
||||
varchar city_name
|
||||
varchar district_name
|
||||
bigint submitter_id FK
|
||||
datetime created_at
|
||||
datetime updated_at
|
||||
}
|
||||
|
||||
TASK {
|
||||
bigint id PK
|
||||
bigint feedback_id FK
|
||||
bigint assignee_id FK
|
||||
bigint created_by FK
|
||||
enum status
|
||||
varchar title
|
||||
text description
|
||||
varchar location
|
||||
decimal latitude
|
||||
decimal longitude
|
||||
datetime assigned_at
|
||||
datetime completed_at
|
||||
datetime created_at
|
||||
datetime updated_at
|
||||
}
|
||||
|
||||
ASSIGNMENT {
|
||||
bigint id PK
|
||||
bigint task_id FK
|
||||
bigint assigner_id FK
|
||||
datetime assignment_time
|
||||
datetime deadline
|
||||
enum status
|
||||
text remarks
|
||||
datetime created_at
|
||||
datetime updated_at
|
||||
}
|
||||
|
||||
GRID {
|
||||
bigint id PK
|
||||
int gridx
|
||||
int gridy
|
||||
varchar city_name
|
||||
varchar district_name
|
||||
text description
|
||||
boolean is_obstacle
|
||||
}
|
||||
|
||||
ATTACHMENT {
|
||||
bigint id PK
|
||||
bigint feedback_id FK
|
||||
varchar file_name
|
||||
varchar file_path
|
||||
varchar file_type
|
||||
bigint file_size
|
||||
datetime uploaded_at
|
||||
}
|
||||
|
||||
OPERATION_LOG {
|
||||
bigint id PK
|
||||
bigint user_id FK
|
||||
varchar operation_type
|
||||
varchar target_type
|
||||
bigint target_id
|
||||
text description
|
||||
varchar ip_address
|
||||
datetime created_at
|
||||
}
|
||||
|
||||
VERIFICATION_CODE {
|
||||
bigint id PK
|
||||
varchar email
|
||||
varchar code
|
||||
enum type
|
||||
datetime expires_at
|
||||
boolean used
|
||||
datetime created_at
|
||||
}
|
||||
|
||||
TASK_HISTORY {
|
||||
bigint id PK
|
||||
bigint task_id FK
|
||||
bigint updated_by_id FK
|
||||
enum old_status
|
||||
enum new_status
|
||||
text remarks
|
||||
datetime updated_at
|
||||
}
|
||||
|
||||
%% 关系定义
|
||||
USER_ACCOUNT ||--o{ FEEDBACK : submits
|
||||
USER_ACCOUNT ||--o{ TASK : assigned_to
|
||||
USER_ACCOUNT ||--o{ TASK : created_by
|
||||
USER_ACCOUNT ||--o{ ASSIGNMENT : assigns
|
||||
USER_ACCOUNT ||--o{ OPERATION_LOG : performs
|
||||
|
||||
FEEDBACK ||--|| TASK : generates
|
||||
FEEDBACK ||--o{ ATTACHMENT : has
|
||||
|
||||
TASK ||--|| ASSIGNMENT : has
|
||||
TASK ||--o{ TASK_HISTORY : logs
|
||||
|
||||
VERIFICATION_CODE }o--|| USER_ACCOUNT : sent_to
|
||||
USER_ACCOUNT ||--o{ TASK_HISTORY : updates
|
||||
```
|
||||
|
||||
## 4. 系统架构说明
|
||||
|
||||
### 4.1 分层架构
|
||||
|
||||
- **控制器层(Controller)**: 处理HTTP请求,参数验证,响应格式化
|
||||
- **服务层(Service)**: 业务逻辑处理,事务管理
|
||||
- **仓库层(Repository)**: 数据访问,数据库操作
|
||||
- **模型层(Model)**: 实体定义,数据结构
|
||||
|
||||
### 4.2 核心业务流程
|
||||
|
||||
1. **用户认证**: JWT令牌生成和验证
|
||||
2. **反馈管理**: 环境问题反馈的提交、审核、处理
|
||||
3. **任务分配**: 基于反馈创建任务并分配给网格工作人员
|
||||
4. **状态跟踪**: 反馈和任务状态的生命周期管理
|
||||
|
||||
### 4.3 安全机制
|
||||
|
||||
- 基于角色的访问控制(RBAC)
|
||||
- JWT令牌认证
|
||||
- 密码加密存储
|
||||
- 操作日志记录
|
||||
|
||||
### 4.4 数据完整性
|
||||
|
||||
- 外键约束确保数据一致性
|
||||
- 唯一约束防止重复数据
|
||||
- 枚举类型确保状态值有效性
|
||||
- 时间戳记录数据变更历史
|
||||
|
||||
## 5. 技术栈
|
||||
|
||||
- **框架**: Spring Boot 3.x
|
||||
- **数据库**: MySQL/PostgreSQL
|
||||
- **ORM**: Spring Data JPA + Hibernate
|
||||
- **安全**: Spring Security + JWT
|
||||
- **文档**: Swagger/OpenAPI 3
|
||||
- **构建工具**: Maven
|
||||
- **Java版本**: JDK 17+
|
||||
|
||||
---
|
||||
|
||||
*本文档基于EMS后端项目代码分析生成,包含完整的系统设计图表,可用于系统理解、开发指导和文档维护。*
|
||||
159
Report/UML类图.md
159
Report/UML类图.md
@@ -1,159 +0,0 @@
|
||||
```
|
||||
@startuml
|
||||
class UserAccount {
|
||||
- Long id
|
||||
- String name
|
||||
- String email
|
||||
- Role role
|
||||
- UserStatus status
|
||||
- Integer gridX
|
||||
- Integer gridY
|
||||
+ isAccountLocked(): boolean
|
||||
+ hasSkill(String skill): boolean
|
||||
}
|
||||
|
||||
enum Role { ADMIN, SUPERVISOR, GRID_WORKER }
|
||||
enum UserStatus { ACTIVE, INACTIVE, SUSPENDED }
|
||||
UserAccount *-- Role
|
||||
UserAccount *-- UserStatus
|
||||
@enduml
|
||||
|
||||
```
|
||||
@startuml
|
||||
class Feedback {
|
||||
- Long id
|
||||
- String eventId
|
||||
- String title
|
||||
- PollutionType pollutionType
|
||||
- SeverityLevel severityLevel
|
||||
- FeedbackStatus status
|
||||
- Long submitterId
|
||||
+ updateStatus(newStatus)
|
||||
+ isHighPriority(): boolean
|
||||
}
|
||||
|
||||
class Attachment {
|
||||
+ id: Long
|
||||
+ fileName: String
|
||||
+ fileType: String
|
||||
+ storedFileName: String
|
||||
}
|
||||
|
||||
enum FeedbackStatus { PENDING_REVIEW, PROCESSED, AI_REJECTED, TASK_CREATED, CLOSED }
|
||||
Feedback "1" -- "*" Attachment : has
|
||||
Feedback *-- FeedbackStatus
|
||||
UserAccount "1" -- "*" Feedback : submits
|
||||
@enduml
|
||||
|
||||
@startuml
|
||||
class Task {
|
||||
- Long id
|
||||
- Long feedbackId
|
||||
- Long assigneeId
|
||||
- Long creatorId
|
||||
- TaskStatus status
|
||||
- SeverityLevel priority
|
||||
+ assignTo(userId)
|
||||
+ markAsCompleted()
|
||||
}
|
||||
|
||||
class Assignment {
|
||||
- Long id
|
||||
- Long taskId
|
||||
- Long assigneeId
|
||||
- AssignmentStatus status
|
||||
+ accept()
|
||||
}
|
||||
|
||||
class TaskHistory {
|
||||
- Long id
|
||||
- Task task
|
||||
- TaskStatus oldStatus
|
||||
- TaskStatus newStatus
|
||||
- UserAccount changedBy
|
||||
}
|
||||
|
||||
enum TaskStatus { CREATED, ASSIGNED, IN_PROGRESS, SUBMITTED, APPROVED, REJECTED, CANCELED }
|
||||
Task "1" -- "1" Feedback : created_from
|
||||
Task "1" -- "*" Assignment
|
||||
Task "1" -- "*" TaskHistory
|
||||
UserAccount "1" -- "*" Task : assigned_to
|
||||
Task *-- TaskStatus
|
||||
@enduml
|
||||
|
||||
@startuml
|
||||
class Grid {
|
||||
- Long id
|
||||
- Integer gridX
|
||||
- Integer gridY
|
||||
- String cityName
|
||||
- boolean isObstacle
|
||||
}
|
||||
|
||||
class MapGrid {
|
||||
- Long id
|
||||
- int x
|
||||
- int y
|
||||
- boolean isObstacle
|
||||
- String terrainType
|
||||
}
|
||||
@enduml
|
||||
```
|
||||
|
||||
@startuml
|
||||
class AqiData {
|
||||
- Long id
|
||||
- Grid grid
|
||||
- Long reporterId
|
||||
- Integer aqiValue
|
||||
- String primaryPollutant
|
||||
}
|
||||
|
||||
class AqiRecord {
|
||||
- Long id
|
||||
- String cityName
|
||||
- Integer aqiValue
|
||||
- LocalDateTime recordTime
|
||||
}
|
||||
|
||||
class PollutantThreshold {
|
||||
- Long id
|
||||
- String pollutantName
|
||||
- Double threshold
|
||||
- String unit
|
||||
}
|
||||
@enduml
|
||||
```
|
||||
|
||||
@startuml
|
||||
class OperationLog {
|
||||
- Long id
|
||||
- UserAccount user
|
||||
- OperationType operationType
|
||||
- String description
|
||||
- LocalDateTime createdAt
|
||||
}
|
||||
|
||||
class PasswordResetToken {
|
||||
- Long id
|
||||
- String token
|
||||
- UserAccount user
|
||||
- LocalDateTime expiryDate
|
||||
+ isExpired(): boolean
|
||||
}
|
||||
|
||||
class TaskSubmission {
|
||||
- Long id
|
||||
- Task task
|
||||
- String notes
|
||||
- LocalDateTime submittedAt
|
||||
}
|
||||
|
||||
class AssignmentRecord {
|
||||
- Long id
|
||||
- Feedback feedback
|
||||
- UserAccount gridWorker
|
||||
- UserAccount admin
|
||||
- AssignmentMethod assignmentMethod
|
||||
}
|
||||
@enduml
|
||||
@@ -1,30 +0,0 @@
|
||||
# ems-backend 项目改进建议 (面向学习者)
|
||||
|
||||
`ems-backend`项目当前已具备良好的架构和完整的功能。为了在此基础上进一步深化对核心技术的理解和应用,可以从以下几个方面对项目进行优化与改进。这些建议旨在提供清晰、可行的学习路径,以巩固和扩展现有知识。
|
||||
|
||||
|
||||
|
||||
### 1. 邮件通知服务的增强
|
||||
- **当前实现**: 邮件服务在主业务流程中同步执行,且邮件内容以字符串形式硬编码在Java代码中。
|
||||
- **分析与评估**: 同步发送可能因网络延迟而阻塞API响应,影响用户体验。硬编码的内容使得文案修改需要重新编译和部署整个应用,缺乏灵活性。
|
||||
- **改进建议**:
|
||||
- **实现异步发送**: 将邮件发送操作置于独立的线程中执行。可以利用Java内置的`ExecutorService`线程池来管理这些后台任务,从而使主线程能够立即响应用户请求。
|
||||
- **引入模板引擎**: 采用如`Thymeleaf`或`Freemarker`等模板引擎。将邮件内容定义为外部HTML模板文件,Java代码仅负责传递动态数据(如验证码)。这样,内容与逻辑得以分离,修改邮件样式和文案将变得非常方便。
|
||||
|
||||
### 2. 安全策略的强化
|
||||
- **当前实现**: 系统已具备基于JWT的用户认证和角色授权。
|
||||
- **分析与评估**: 当前实现未对认证接口的请求频率进行限制,存在被自动化脚本进行暴力破解的风险。
|
||||
- **改进建议**:
|
||||
- **实现登录尝试限制**: 开发一个`LoginAttemptService`,用于追踪特定用户或IP地址在单位时间内的登录失败次数。当失败次数超过预设阈值(例如,5次/分钟),可暂时锁定账户或要求输入验证码,有效防御暴力破解攻击。
|
||||
|
||||
### 3. 前端数据同步的优化
|
||||
- **当前实现**: 前端获取最新数据依赖于用户的手动刷新操作。
|
||||
- **分析与评估**: 在任务分配、状态变更等场景下,信息的被动更新会导致用户感知的延迟。
|
||||
- **改进建议**:
|
||||
- **实现客户端轮询**: 在前端关键页面(如任务列表)采用定时轮询机制。通过`setInterval`等JavaScript函数,每隔一个固定时间(如10-30秒)自动向后端请求最新数据并更新视图。这是实现准实时数据同步的最直接、最易于理解的方式。
|
||||
|
||||
### 4. API接口的健壮性提升
|
||||
- **当前实现**: 主要通过全局异常处理器来捕获和响应错误。
|
||||
- **分析与评估**: 对于可预期的业务错误(如"用户名已存在"),可以提供更具体、结构化的错误信息,以方便前端进行针对性处理。
|
||||
- **改进建议**:
|
||||
- **设计更具体的错误响应**: 在`GlobalExceptionHandler`中,除了返回HTTP状态码和错误消息外,可以为特定的业务异常定义内部错误码(如`1001`代表"用户已存在")。前端可以根据这个错误码,精确地向用户展示提示信息(如高亮对应的输入框),而不仅仅是弹出一个通用的错误提示。
|
||||
@@ -1,69 +0,0 @@
|
||||
# ems-backend 项目不足与可改进之处
|
||||
|
||||
`ems-backend`项目当前已经构建了一个功能完善、架构清晰的系统。然而,从一个准生产级应用迈向一个高可用、高扩展、可长期演进的企业级平台的道路上,我们可以在以下几个方面进行深化和改进。这些改进点并非对现有设计的否定,而是基于更高标准的技术展望。
|
||||
|
||||
### 1. 持久化层的演进与扩展
|
||||
当前的JSON文件存储方案虽然巧妙地满足了项目初期的约束,但它也是未来系统演进中最先需要被替换的模块。
|
||||
|
||||
- **当前状态**: 使用JSON文件作为数据库,通过文件锁保证单机并发安全。
|
||||
- **潜在瓶颈**:
|
||||
- **性能限制**: 随着数据量增长,全文件读写和内存中的过滤、排序将变得极慢,无法处理复杂查询(如JOIN、聚合分析)。
|
||||
- **功能缺失**: 缺乏数据库事务的ACID保证,无法确保跨多个文件操作的原子性。
|
||||
- **扩展性差**: 无法进行水平扩展,是典型的单点瓶颈。
|
||||
- **改进方向**:
|
||||
- **迁移至关系型数据库**: 全面采用`PostgreSQL`或`MySQL`。这将使我们能够利用强大的SQL查询优化器、索引机制、以及成熟的事务管理,从根本上解决性能和数据一致性问题。`Repository`层的接口化设计将使这次迁移变得相对平滑。
|
||||
- **引入分布式缓存**: 集成`Redis`,对访问频繁且不常变化的数据(如用户信息、配置信息、地图网格数据)进行缓存。这将极大降低数据库的读取压力,显著提升API响应速度。
|
||||
|
||||
### 2. 消息驱动架构的工业化升级
|
||||
系统内的事件驱动(`ApplicationEventPublisher`)是优秀的单体应用解耦实践,但它无法满足分布式架构的需求。
|
||||
|
||||
- **当前状态**: 使用Spring内置的事件机制实现应用内异步解耦。
|
||||
- **潜在瓶颈**:
|
||||
- **生命周期绑定**: 事件总线与应用进程绑定,若应用宕机,未处理的事件会丢失。
|
||||
- **缺乏高级特性**: 不支持持久化、失败重试、延迟消息、死信队列等工业级消息系统特性。
|
||||
- **无法跨服务**: 无法用于未来可能的微服务化改造。
|
||||
- **改进方向**:
|
||||
- **引入专业消息队列(MQ)**: 采用`RabbitMQ`(适用于复杂路由和事务性消息)或`Kafka`(适用于高吞吐量日志和数据流)来替换`ApplicationEventPublisher`。
|
||||
- **带来的优势**: 实现真正的服务间异步通信、流量削峰填谷、保证事件的可靠投递,并为未来将通知、AI分析等模块拆分为独立微服务奠定坚实基础。
|
||||
|
||||
### 3. 安全体系的纵深防御
|
||||
当前的安全体系保证了认证和基础授权,但可以构建更深层次的防御。
|
||||
|
||||
- **当前状态**: JWT认证 + `@PreAuthorize`角色授权。
|
||||
- **潜在瓶颈**:
|
||||
- **缺乏流量防护**: 无法防御针对登录接口的暴力破解或API的滥用攻击。
|
||||
- **缺乏敏感操作审计**: 对"谁删除了某个重要任务"这类操作缺乏追溯能力。
|
||||
- **改进方向**:
|
||||
- **实现API限流(Rate Limiting)**: 使用`Resilience4j`或`Guava RateLimiter`等库,对登录、发送验证码等关键API接口配置精细化的访问速率限制,从入口处防止恶意攻击。
|
||||
- **实现双因素认证(2FA)**: 对管理员、决策者等高权限角色,在密码认证之外,增加一层基于时间的一次性密码(TOTP,如Google Authenticator)验证,实现银行级别的账户安全。
|
||||
- **构建完善的审计日志**: 创建独立的审计日志系统,以AOP切面或事件监听的方式,详细记录所有关键写操作(谁、在何时、从何IP、做了什么、结果如何),确保所有敏感操作都可被追溯和审计。
|
||||
|
||||
### 4. 前端体验的现代化与实时化
|
||||
当前的前后端交互是传统的"请求-响应"模式,可以升级为实时推送模式。
|
||||
|
||||
- **当前状态**: 前端通过轮询或手动刷新获取最新数据。
|
||||
- **潜在瓶颈**: 信息传递有延迟,用户体验不够流畅,尤其是在需要协同工作的场景。
|
||||
- **改进方向**:
|
||||
- **引入WebSocket**: 使用`WebSocket`技术,在前后端之间建立长连接,实现双向实时通信。
|
||||
- **应用场景**: 当一个任务的状态被主管更新后,服务器可以立即将最新的状态**主动推送**给正在查看该任务的网格员的前端界面,无需用户手动刷新。这将极大提升系统的即时性和用户的沉浸式体验。
|
||||
|
||||
### 5. 运维与部署的自动化 (DevOps)
|
||||
这是从"能用"到"好用、可靠"的关键一步。
|
||||
|
||||
- **当前状态**: 项目需要开发者手动执行`mvn package`,然后通过FTP或SSH将jar包上传到服务器并手动运行。
|
||||
- **潜在瓶颈**: 部署流程繁琐、耗时、极易因人工操作而出错,无法做到快速迭代和持续交付。
|
||||
- **改进方向**:
|
||||
- **容器化**: 使用`Docker`将`ems-backend`应用及其所有依赖(如特定版本的Java环境)打包成一个标准化的、可移植的容器镜像。
|
||||
- **引入CI/CD (持续集成/持续部署)**: 搭建`GitHub Actions`或`Jenkins`自动化流水线。当代码被推送到主分支后,流水线会自动执行:①编译代码 -> ②运行所有单元测试 -> ③构建Docker镜像 -> ④将镜像推送到镜像仓库 -> ⑤(可选)自动触发部署脚本,更新服务器上的应用。这将实现从代码提交到上线的全流程自动化。
|
||||
|
||||
### 6. 通知服务的模板化与多渠道扩展
|
||||
当前的邮件服务功能正确,但可维护性和扩展性可以进一步提升。
|
||||
|
||||
- **当前状态**: 邮件HTML内容在Java代码中硬编码,发送过程是同步的。
|
||||
- **潜在瓶颈**:
|
||||
- **难以维护**: 每次修改邮件文案都需要修改Java代码并重新部署。
|
||||
- **性能风险**: 同步发送邮件会阻塞主线程,如果邮件服务器响应慢,将拖慢API的整体响应时间。
|
||||
- **改进方向**:
|
||||
- **引入模板引擎**: 使用`Thymeleaf`或`Freemarker`将邮件内容定义为独立的HTML模板文件。Java代码只负责传递动态数据(如验证码、用户名),由模板引擎渲染最终的HTML,实现内容与逻辑的分离。
|
||||
- **异步化发送**: 将`sendHtmlEmail`方法标记为`@Async`,使其在独立的线程池中执行,实现"发布即返回",主业务流程不再等待邮件发送完成。
|
||||
- **多渠道抽象**: 将`MailService`抽象为更通用的`NotificationService`,并提供`EmailNotificationProvider`、`SmsNotificationProvider`等多种实现,未来可以根据用户偏好或业务场景,灵活选择通知渠道。
|
||||
@@ -1,44 +0,0 @@
|
||||
# ems-backend 项目核心创新点总览
|
||||
|
||||
基于对 `ems-backend` 项目源代码的深入分析,该系统在设计与实现上体现了现代化、企业级的工程实践。其核心创新点可总结为以下八个方面:
|
||||
|
||||
### 1. 模拟JPA的泛型JSON仓储层
|
||||
在不引入传统数据库的约束下,项目极具创造性地构建了一套数据持久化框架。
|
||||
- **泛型设计与类型安全**: 底层的 `JsonStorageService` 通过泛型`<T>`和Jackson的`TypeReference`,实现了对任意实体列表的类型安全读写。
|
||||
- **精细化并发控制**: 没有采用简单的全局方法锁,而是通过 `ConcurrentHashMap<String, Lock>` 为每个JSON文件分配了独立的`ReentrantLock`,实现了文件级别的并发控制,显著提升了在多文件写入场景下的性能。
|
||||
- **模拟JPA接口**: `Repository`层定义了与Spring Data JPA高度相似的接口(如`save`, `findById`, `findAll`),使得上层业务代码可以面向接口编程,与底层的文件存储实现完全解耦,未来可平滑迁移至真实数据库。
|
||||
|
||||
### 2. 事件驱动的异步化业务流程
|
||||
系统广泛采用事件驱动架构(EDA)来解耦模块、提升系统响应能力。
|
||||
- **异步化核心流程**: 将反馈提交后的AI审核、任务创建成功后的智能分配等耗时或非核心操作,通过发布Spring事件(如`FeedbackSubmittedForAiReviewEvent`)的方式进行异步处理,极大缩短了API的响应时间。
|
||||
- **业务模块高度解耦**: 核心服务(如`FeedbackService`)与下游模块(如`TaskService`, `MailService`)无直接代码依赖。新增业务监听器(如"短信通知")无需修改任何现有业务代码,完美遵循"开闭原则",提高了系统的可维护性和可扩展性。
|
||||
|
||||
### 3. 融合多种策略的智能算法
|
||||
在关键业务场景中,系统应用了智能算法取代了僵硬的业务规则,提升了运营效率和决策科学性。
|
||||
- **高效的A*寻路算法**: 为网格员规划路径时,不仅实现了A*算法,还结合了**优先队列(PriorityQueue)**进行性能优化,并能**动态加载地图和障碍物信息**,具有很强的适应性。
|
||||
- **多因素加权的任务推荐算法**: 在分配任务时,系统通过一个异步触发的智能分配服务,综合考虑网格员的**地理距离、当前负载、技能匹配度、历史表现**等多个维度进行加权评分,为任务自动推荐最合适的执行者。
|
||||
|
||||
### 4. 声明式、细粒度的安全权限控制
|
||||
项目的安全体系并非简单的身份认证,而是构建了一套声明式、与业务逻辑分离的权限控制体系。
|
||||
- **自定义JWT安全过滤链**: 通过自定义的`JwtAuthenticationFilter`和`SecurityConfig`配置,精确控制了JWT的解析、校验及用户权限加载流程。
|
||||
- **声明式方法级权限**: 在Controller层广泛使用`@PreAuthorize`注解,将权限规则(如`hasRole('ADMIN')`)从业务逻辑中抽离,使安全策略一目了然,易于审计和维护。
|
||||
|
||||
### 5. 主动、可定制的业务规则校验体系
|
||||
系统对所有外部输入都采取"主动防御"姿态,构建了前置的、可扩展的校验体系。
|
||||
- **分层校验**: 同时使用JSR 303标准注解(如`@NotNull`, `@Email`)和`@Valid`进行基础校验。
|
||||
- **自定义业务校验**: 针对复杂业务规则(如密码强度),创建了自定义校验注解(如`@ValidPassword`)及其实现(`PasswordValidator`)。这种方式将复杂的校验逻辑封装成一个可复用的简单注解,极为优雅和高效。
|
||||
|
||||
### 6. 统一、健壮的API设计与响应体系
|
||||
项目的API设计构建了一套完整的、面向开发者的友好体系。
|
||||
- **全局统一异常处理**: 通过`@ControllerAdvice`和`@ExceptionHandler`,将所有异常(业务异常、系统异常)集中捕获,并返回结构统一的`ErrorResponseDTO`,极大地简化了前端的错误处理,并避免了向客户端暴露敏感的系统内部信息。
|
||||
- **面向视图的DTO模式**: 严格区分领域模型(Entity)和数据传输对象(DTO),并为不同场景(如列表摘要`TaskSummaryDTO` vs. 详情`TaskDetailDTO`)提供专属DTO。这确保了API契约的稳定,优化了网络传输性能,并从根本上杜绝了敏感字段的泄露。
|
||||
|
||||
### 7. 安全、分层的媒体文件存储服务
|
||||
项目实现了一个安全、分层的媒体文件存储服务,以处理用户上传的现场证据。
|
||||
- **安全优先**: 在存储文件前,通过**生成唯一文件名**防止冲突和覆盖,通过**校验文件类型**防止恶意脚本上传,并通过**规范化路径**防止目录遍历攻击。
|
||||
- **逻辑与物理分离**: 服务返回的是内部文件名而非直接URL,业务层将此文件名与业务实体关联。访问时需通过专门的Controller根据内部文件名加载文件流。此分层架构不仅增强了安全,也便于未来将底层存储平滑迁移至云存储(如OSS)。
|
||||
|
||||
### 8. 与核心业务解耦的可扩展通知服务
|
||||
项目构建了一个与核心业务逻辑完全解耦的通知服务体系。
|
||||
- **事件驱动触发**: 邮件发送(如注册验证码)由业务事件(如`UserRegisteredEvent`)触发,由独立的监听器负责调用邮件服务,实现了业务流程与通知功能的分离。
|
||||
- **面向接口设计**: 通过定义`MailService`接口,使系统不依赖于具体的邮件发送实现。这为未来切换邮件服务商,或在测试环境中提供一个模拟实现(Mock)提供了极大的灵活性,无需改动任何业务代码。
|
||||
354
Report/temp.md
354
Report/temp.md
@@ -1,354 +0,0 @@
|
||||
```plantuml
|
||||
|
||||
@startuml
|
||||
title 任务核心模型 (Task Core Models)
|
||||
|
||||
skinparam classAttributeIconSize 0
|
||||
|
||||
class Task {
|
||||
- Long id
|
||||
- String title
|
||||
- String description
|
||||
- PollutionType pollutionType
|
||||
- SeverityLevel severityLevel
|
||||
- TaskStatus status
|
||||
- String textAddress
|
||||
- Integer gridX
|
||||
- Integer gridY
|
||||
- LocalDateTime assignedAt
|
||||
- LocalDateTime completedAt
|
||||
}
|
||||
|
||||
class Assignment {
|
||||
- Long id
|
||||
- LocalDateTime assignmentTime
|
||||
- LocalDateTime deadline
|
||||
- AssignmentStatus status
|
||||
- String remarks
|
||||
}
|
||||
|
||||
class TaskHistory {
|
||||
- Long id
|
||||
- TaskStatus oldStatus
|
||||
- TaskStatus newStatus
|
||||
- String comments
|
||||
- LocalDateTime changedAt
|
||||
}
|
||||
|
||||
class TaskSubmission {
|
||||
- Long id
|
||||
- String notes
|
||||
- LocalDateTime submittedAt
|
||||
}
|
||||
|
||||
' --- Relationships ---
|
||||
' Task is the central entity
|
||||
Task "1" *-- "1" Assignment : (has one)
|
||||
Task "1" *-- "0..*" TaskHistory : (logs)
|
||||
Task "1" *-- "0..*" TaskSubmission : (has)
|
||||
|
||||
' --- External Relationships for Context ---
|
||||
Task ..> Feedback : (created from)
|
||||
Task ..> UserAccount : (assignee)
|
||||
Task ..> UserAccount : (createdBy)
|
||||
|
||||
Assignment ..> UserAccount : (assigner)
|
||||
TaskHistory ..> UserAccount : (changedBy)
|
||||
TaskSubmission ..> "*" Attachment : (has)
|
||||
|
||||
@enduml
|
||||
|
||||
|
||||
|
||||
@startuml
|
||||
title 网格与地图模型 (Grid & Map Models)
|
||||
|
||||
skinparam classAttributeIconSize 0
|
||||
|
||||
class Grid {
|
||||
- Long id
|
||||
- Integer gridX
|
||||
- Integer gridY
|
||||
- String cityName
|
||||
- String districtName
|
||||
- String description
|
||||
- Boolean isObstacle
|
||||
}
|
||||
|
||||
class MapGrid {
|
||||
- Long id
|
||||
- int x
|
||||
- int y
|
||||
- String cityName
|
||||
- boolean isObstacle
|
||||
- String terrainType
|
||||
}
|
||||
@enduml
|
||||
|
||||
|
||||
@startuml
|
||||
title 数据与日志模型 (Data & Logging Models)
|
||||
|
||||
skinparam classAttributeIconSize 0
|
||||
|
||||
class AqiData {
|
||||
- Long id
|
||||
- Integer aqiValue
|
||||
- Double pm25
|
||||
- Double pm10
|
||||
- String primaryPollutant
|
||||
- LocalDateTime recordTime
|
||||
}
|
||||
|
||||
class AqiRecord {
|
||||
- Long id
|
||||
- String cityName
|
||||
- Integer aqiValue
|
||||
- Double pm25
|
||||
- Double pm10
|
||||
- LocalDateTime recordTime
|
||||
}
|
||||
|
||||
class OperationLog {
|
||||
- Long id
|
||||
- OperationType operationType
|
||||
- String description
|
||||
- String targetId
|
||||
- String targetType
|
||||
- String ipAddress
|
||||
- LocalDateTime createdAt
|
||||
}
|
||||
|
||||
class AssignmentRecord {
|
||||
- Long id
|
||||
- AssignmentMethod assignmentMethod
|
||||
- String algorithmDetails
|
||||
- AssignmentStatus status
|
||||
- LocalDateTime createdAt
|
||||
}
|
||||
|
||||
' --- Relationships ---
|
||||
AqiData ..> Grid : (recorded at)
|
||||
AqiData ..> UserAccount : (reported by)
|
||||
|
||||
AqiRecord ..> Grid : (related to)
|
||||
|
||||
OperationLog ..> UserAccount : (performed by)
|
||||
|
||||
AssignmentRecord ..> Feedback : (for)
|
||||
AssignmentRecord ..> UserAccount : (assigned to worker)
|
||||
AssignmentRecord ..> UserAccount : (assigned by admin)
|
||||
@enduml
|
||||
|
||||
|
||||
@startuml
|
||||
title 辅助与配置模型 (Utility & Configuration Models)
|
||||
|
||||
skinparam classAttributeIconSize 0
|
||||
|
||||
class PollutantThreshold {
|
||||
- Long id
|
||||
- PollutionType pollutionType
|
||||
- String pollutantName
|
||||
- Double threshold
|
||||
- String unit
|
||||
}
|
||||
|
||||
class PasswordResetToken {
|
||||
- Long id
|
||||
- String token
|
||||
- LocalDateTime expiryDate
|
||||
..
|
||||
+ isExpired(): boolean
|
||||
}
|
||||
|
||||
class Attachment {
|
||||
- Long id
|
||||
- String fileName
|
||||
- String fileType
|
||||
- String storedFileName
|
||||
- Long fileSize
|
||||
- LocalDateTime uploadDate
|
||||
}
|
||||
|
||||
' --- Relationships ---
|
||||
PasswordResetToken ..> UserAccount : (for)
|
||||
|
||||
Attachment ..> Feedback : (belongs to)
|
||||
Attachment ..> TaskSubmission : (belongs to)
|
||||
@enduml
|
||||
```
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
title 系统核心业务模型 (Core Business Models)
|
||||
skinparam classAttributeIconSize 0
|
||||
|
||||
enum Gender{
|
||||
-Male
|
||||
-Female
|
||||
-OTHER
|
||||
}
|
||||
enum Role{
|
||||
|
||||
}
|
||||
enum UserStatus
|
||||
enum PollutionType
|
||||
enum SeverityLevel
|
||||
enum FeedbackStatus
|
||||
enum TaskStatus
|
||||
enum AssignmentStatus
|
||||
|
||||
class UserAccount {
|
||||
- Long id
|
||||
- String name
|
||||
- String phone
|
||||
- String email
|
||||
- String password
|
||||
- Gender gender
|
||||
- Role role
|
||||
- UserStatus status
|
||||
- Integer gridX
|
||||
- Integer gridY
|
||||
+ isValid()
|
||||
}
|
||||
|
||||
class Feedback {
|
||||
- Long id
|
||||
- String eventId
|
||||
- String title
|
||||
- PollutionType pollutionType
|
||||
- SeverityLevel severityLevel
|
||||
- FeedbackStatus status
|
||||
- Long submitterId
|
||||
+ process()
|
||||
+ approve()
|
||||
}
|
||||
|
||||
class Task {
|
||||
- Long id
|
||||
- Long feedbackId
|
||||
- Long assigneeId
|
||||
- Long createdBy
|
||||
- TaskStatus status
|
||||
- String title
|
||||
+ assignTo(workerId)
|
||||
+ complete()
|
||||
+ approve()
|
||||
}
|
||||
|
||||
class Assignment {
|
||||
- Long id
|
||||
- Long taskId
|
||||
- Long assignerId
|
||||
- AssignmentStatus status
|
||||
- String remarks
|
||||
- LocalDateTime assignmentTime
|
||||
}
|
||||
|
||||
class Grid {
|
||||
- Long id
|
||||
- Integer gridX
|
||||
- Integer gridY
|
||||
- String cityName
|
||||
- boolean isObstacle
|
||||
}
|
||||
|
||||
UserAccount "1" *-- "1" Gender
|
||||
UserAccount "1" *-- "1" Role
|
||||
UserAccount "1" *-- "1" UserStatus
|
||||
Feedback "1" *-- "1" PollutionType
|
||||
Feedback "1" *-- "1" SeverityLevel
|
||||
Feedback "1" *-- "1" FeedbackStatus
|
||||
Task "1" *-- "1" TaskStatus
|
||||
Assignment "1" *-- "1" AssignmentStatus
|
||||
|
||||
Task "1" --> "1" Feedback : "generated from"
|
||||
Task "1" o-- "1" Assignment : "has"
|
||||
UserAccount "1" --> "0..*" Feedback : "submits"
|
||||
UserAccount "1" --> "0..*" Task : "creates"
|
||||
Task "0..*" --o "1" UserAccount : "assigned to"
|
||||
UserAccount "1" --> "0..*" Assignment : "assigns"
|
||||
Task "1" ..> "1" Grid : "located in"
|
||||
UserAccount "1" ..> "1" Grid : "operates in"
|
||||
@enduml
|
||||
```
|
||||
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
title EMS核心业务模型全景图
|
||||
|
||||
skinparam classAttributeIconSize 0
|
||||
|
||||
|
||||
' --- Enumeration classes (using stereotype for max compatibility) ---
|
||||
class Gender <<enumeration>> {
|
||||
MALE, FEMALE, OTHER
|
||||
}
|
||||
class Role <<enumeration>> {
|
||||
ADMIN, SUPERVISOR, GRID_WORKER
|
||||
}
|
||||
class UserStatus <<enumeration>> {
|
||||
ACTIVE, INACTIVE
|
||||
}
|
||||
class PollutionType <<enumeration>> {
|
||||
AIR, WATER, SOIL, NOISE
|
||||
}
|
||||
class SeverityLevel <<enumerationa>> {
|
||||
LOW, MEDIUM, HIGH, CRITICAL
|
||||
}
|
||||
class FeedbackStatus <<enumeration>> {
|
||||
PENDING_REVIEW, AI_REJECTED, PROCESSED
|
||||
}
|
||||
class TaskStatus <<enumeration>> {
|
||||
CREATED, ASSIGNED, IN_PROGRESS, SUBMITTED, APPROVED, REJECTED
|
||||
}
|
||||
class AssignmentStatus <<enumeration>> {
|
||||
PENDING, ACCEPTED, REJECTED
|
||||
}
|
||||
|
||||
' --- Entity classes ---
|
||||
class UserAccount
|
||||
class Feedback
|
||||
class Task
|
||||
class Assignment
|
||||
class Grid
|
||||
class PasswordResetToken
|
||||
class Attachment
|
||||
|
||||
' --- Relationships ---
|
||||
UserAccount "1" --> "1" Gender
|
||||
UserAccount "1" --> "1" Role
|
||||
UserAccount "1" --> "1" UserStatus
|
||||
|
||||
Feedback "1" --> "1" PollutionType
|
||||
Feedback "1" --> "1" SeverityLevel
|
||||
Feedback "1" --> "1" FeedbackStatus
|
||||
|
||||
Task "1" --> "1" TaskStatus
|
||||
Assignment "1" --> "1" AssignmentStatus
|
||||
|
||||
Task "1" --> "1" Feedback : "generated from"
|
||||
Task "1" o-- "1" Assignment : "has"
|
||||
UserAccount "1" --> "0..*" Feedback : "submits"
|
||||
UserAccount "1" --> "0..*" Task : "creates"
|
||||
Task "0..*" --o "1" UserAccount : "assigned to"
|
||||
UserAccount "1" --> "0..*" Assignment : "assigns"
|
||||
PasswordResetToken "1" --> "1" UserAccount : "for user"
|
||||
Feedback "1" --> "0..*" Attachment : "has"
|
||||
|
||||
Task "1" ..> "1" Grid : "located in"
|
||||
UserAccount "1" ..> "1" Grid : "operates in"
|
||||
|
||||
@enduml
|
||||
|
||||
```
|
||||
|
||||
|
||||
```plantnml
|
||||
|
||||
|
||||
|
||||
|
||||
```
|
||||
387
Report/temp1.md
387
Report/temp1.md
@@ -1,387 +0,0 @@
|
||||
```plantuml
|
||||
@startuml
|
||||
skinparam classAttributeIconSize 0
|
||||
|
||||
' --- Enumeration classes (declaration-only for max compatibility) ---
|
||||
enum Gender {
|
||||
MALE,
|
||||
FEMALE,
|
||||
OTHER
|
||||
}
|
||||
enum Role {
|
||||
PUBLIC_SUPERVISOR,
|
||||
SUPERVISOR,
|
||||
GRID_WORKER,
|
||||
ADMIN,
|
||||
DECISION_MAKER
|
||||
|
||||
}
|
||||
enum UserStatus
|
||||
enum PollutionType
|
||||
enum SeverityLevel
|
||||
enum FeedbackStatus
|
||||
enum TaskStatus
|
||||
enum AssignmentStatus
|
||||
enum AssignmentMethod
|
||||
enum OperationType
|
||||
|
||||
|
||||
' --- Entity classes with full attributes and methods ---
|
||||
class UserAccount {
|
||||
- Long id
|
||||
- String name
|
||||
- String phone
|
||||
- String email
|
||||
- String password
|
||||
- Gender gender
|
||||
- Role role
|
||||
- UserStatus status
|
||||
- Integer gridX
|
||||
- Integer gridY
|
||||
+ isValid()
|
||||
}
|
||||
class Feedback {
|
||||
- Long id
|
||||
- String eventId
|
||||
- String title
|
||||
- PollutionType pollutionType
|
||||
- SeverityLevel severityLevel
|
||||
- FeedbackStatus status
|
||||
- Long submitterId
|
||||
+ process()
|
||||
+ approve()
|
||||
}
|
||||
class Task {
|
||||
- Long id
|
||||
- String title
|
||||
- String description
|
||||
- PollutionType pollutionType
|
||||
- SeverityLevel severityLevel
|
||||
- TaskStatus status
|
||||
- String textAddress
|
||||
- Integer gridX
|
||||
- Integer gridY
|
||||
- LocalDateTime assignedAt
|
||||
- LocalDateTime completedAt
|
||||
+ assignTo(workerId)
|
||||
+ complete()
|
||||
+ approve()
|
||||
}
|
||||
class Assignment {
|
||||
- Long id
|
||||
- String remarks
|
||||
- LocalDateTime assignmentTime
|
||||
- LocalDateTime deadline
|
||||
- AssignmentStatus status
|
||||
}
|
||||
class TaskHistory {
|
||||
- Long id
|
||||
- TaskStatus oldStatus
|
||||
- TaskStatus newStatus
|
||||
- String comments
|
||||
- LocalDateTime changedAt
|
||||
}
|
||||
class TaskSubmission {
|
||||
- Long id
|
||||
- String notes
|
||||
- LocalDateTime submittedAt
|
||||
}
|
||||
class Attachment {
|
||||
- Long id
|
||||
- String fileName
|
||||
- String fileType
|
||||
- String storedFileName
|
||||
- Long fileSize
|
||||
- LocalDateTime uploadDate
|
||||
}
|
||||
class Grid {
|
||||
- Long id
|
||||
- Integer gridX
|
||||
- Integer gridY
|
||||
- String cityName
|
||||
- String districtName
|
||||
- String description
|
||||
- boolean isObstacle
|
||||
}
|
||||
class MapGrid {
|
||||
- Long id
|
||||
- int x
|
||||
- int y
|
||||
- String cityName
|
||||
- boolean isObstacle
|
||||
- String terrainType
|
||||
}
|
||||
class PasswordResetToken {
|
||||
- Long id
|
||||
- String token
|
||||
- LocalDateTime expiryDate
|
||||
+ isExpired()
|
||||
}
|
||||
class OperationLog {
|
||||
- Long id
|
||||
- OperationType operationType
|
||||
- String description
|
||||
- String targetId
|
||||
- String targetType
|
||||
- String ipAddress
|
||||
- LocalDateTime createdAt
|
||||
}
|
||||
class AqiData {
|
||||
- Long id
|
||||
- Integer aqiValue
|
||||
- Double pm25
|
||||
- Double pm10
|
||||
- String primaryPollutant
|
||||
- LocalDateTime recordTime
|
||||
}
|
||||
class AqiRecord {
|
||||
- Long id
|
||||
- String cityName
|
||||
- Integer aqiValue
|
||||
- Double pm25
|
||||
- Double pm10
|
||||
- LocalDateTime recordTime
|
||||
}
|
||||
class AssignmentRecord {
|
||||
- Long id
|
||||
- AssignmentMethod assignmentMethod
|
||||
- String algorithmDetails
|
||||
- AssignmentStatus status
|
||||
- LocalDateTime createdAt
|
||||
}
|
||||
class PollutantThreshold {
|
||||
- Long id
|
||||
- PollutionType pollutionType
|
||||
- String pollutantName
|
||||
- Double threshold
|
||||
- String unit
|
||||
}
|
||||
|
||||
' --- Relationships (kept simple for compatibility) ---
|
||||
UserAccount --> Gender
|
||||
UserAccount --> Role
|
||||
UserAccount --> UserStatus
|
||||
Feedback --> PollutionType
|
||||
Feedback --> SeverityLevel
|
||||
Feedback --> FeedbackStatus
|
||||
Task --> TaskStatus
|
||||
Assignment --> AssignmentStatus
|
||||
AssignmentRecord --> AssignmentMethod
|
||||
OperationLog --> OperationType
|
||||
PollutantThreshold --> PollutionType
|
||||
Task --> Feedback
|
||||
Task -- Assignment
|
||||
Task -- TaskHistory
|
||||
Task -- TaskSubmission
|
||||
Feedback -- Attachment
|
||||
TaskSubmission -- Attachment
|
||||
AssignmentRecord --> Feedback
|
||||
UserAccount --> Feedback
|
||||
UserAccount --> Task
|
||||
Task -- UserAccount
|
||||
Assignment --> UserAccount
|
||||
TaskHistory --> UserAccount
|
||||
AssignmentRecord --> UserAccount
|
||||
OperationLog --> UserAccount
|
||||
PasswordResetToken --> UserAccount
|
||||
AqiData --> UserAccount
|
||||
Task ..> Grid
|
||||
UserAccount ..> Grid
|
||||
AqiData --> Grid
|
||||
AqiRecord --> Grid
|
||||
@enduml
|
||||
```
|
||||
|
||||
```plantuml
|
||||
|
||||
@startuml
|
||||
title EMS系统模型全景图 (Detailed View)
|
||||
|
||||
skinparam classAttributeIconSize 0
|
||||
|
||||
' --- Enumeration classes (declaration-only for max compatibility) ---
|
||||
enum Gender
|
||||
enum Role
|
||||
enum UserStatus
|
||||
enum PollutionType
|
||||
enum SeverityLevel
|
||||
enum FeedbackStatus
|
||||
enum TaskStatus
|
||||
enum AssignmentStatus
|
||||
enum AssignmentMethod
|
||||
enum OperationType
|
||||
|
||||
|
||||
' --- Entity classes with full attributes and methods ---
|
||||
class UserAccount {
|
||||
- Long id
|
||||
- String name
|
||||
- String phone
|
||||
- String email
|
||||
- String password
|
||||
- Gender gender
|
||||
- Role role
|
||||
- UserStatus status
|
||||
- Integer gridX
|
||||
- Integer gridY
|
||||
+ isValid()
|
||||
}
|
||||
class Feedback {
|
||||
- Long id
|
||||
- String eventId
|
||||
- String title
|
||||
- PollutionType pollutionType
|
||||
- SeverityLevel severityLevel
|
||||
- FeedbackStatus status
|
||||
- Long submitterId
|
||||
+ process()
|
||||
+ approve()
|
||||
}
|
||||
class Task {
|
||||
- Long id
|
||||
- String title
|
||||
- String description
|
||||
- PollutionType pollutionType
|
||||
- SeverityLevel severityLevel
|
||||
- TaskStatus status
|
||||
- String textAddress
|
||||
- Integer gridX
|
||||
- Integer gridY
|
||||
- LocalDateTime assignedAt
|
||||
- LocalDateTime completedAt
|
||||
+ assignTo(workerId)
|
||||
+ complete()
|
||||
+ approve()
|
||||
}
|
||||
class Assignment {
|
||||
- Long id
|
||||
- String remarks
|
||||
- LocalDateTime assignmentTime
|
||||
- LocalDateTime deadline
|
||||
- AssignmentStatus status
|
||||
}
|
||||
class TaskHistory {
|
||||
- Long id
|
||||
- TaskStatus oldStatus
|
||||
- TaskStatus newStatus
|
||||
- String comments
|
||||
- LocalDateTime changedAt
|
||||
}
|
||||
class TaskSubmission {
|
||||
- Long id
|
||||
- String notes
|
||||
- LocalDateTime submittedAt
|
||||
}
|
||||
class Attachment {
|
||||
- Long id
|
||||
- String fileName
|
||||
- String fileType
|
||||
- String storedFileName
|
||||
- Long fileSize
|
||||
- LocalDateTime uploadDate
|
||||
}
|
||||
class Grid {
|
||||
- Long id
|
||||
- Integer gridX
|
||||
- Integer gridY
|
||||
- String cityName
|
||||
- String districtName
|
||||
- String description
|
||||
- boolean isObstacle
|
||||
}
|
||||
class MapGrid {
|
||||
- Long id
|
||||
- int x
|
||||
- int y
|
||||
- String cityName
|
||||
- boolean isObstacle
|
||||
- String terrainType
|
||||
}
|
||||
class PasswordResetToken {
|
||||
- Long id
|
||||
- String token
|
||||
- LocalDateTime expiryDate
|
||||
+ isExpired()
|
||||
}
|
||||
class OperationLog {
|
||||
- Long id
|
||||
- OperationType operationType
|
||||
- String description
|
||||
- String targetId
|
||||
- String targetType
|
||||
- String ipAddress
|
||||
- LocalDateTime createdAt
|
||||
}
|
||||
class AqiData {
|
||||
- Long id
|
||||
- Integer aqiValue
|
||||
- Double pm25
|
||||
- Double pm10
|
||||
- String primaryPollutant
|
||||
- LocalDateTime recordTime
|
||||
}
|
||||
class AqiRecord {
|
||||
- Long id
|
||||
- String cityName
|
||||
- Integer aqiValue
|
||||
- Double pm25
|
||||
- Double pm10
|
||||
- LocalDateTime recordTime
|
||||
}
|
||||
class AssignmentRecord {
|
||||
- Long id
|
||||
- AssignmentMethod assignmentMethod
|
||||
- String algorithmDetails
|
||||
- AssignmentStatus status
|
||||
- LocalDateTime createdAt
|
||||
}
|
||||
class PollutantThreshold {
|
||||
- Long id
|
||||
- PollutionType pollutionType
|
||||
- String pollutantName
|
||||
- Double threshold
|
||||
- String unit
|
||||
}
|
||||
|
||||
' --- Relationships with Full Details ---
|
||||
|
||||
' --- Composition with Enums ---
|
||||
UserAccount "1" *-- "1" Gender
|
||||
UserAccount "1" *-- "1" Role
|
||||
UserAccount "1" *-- "1" UserStatus
|
||||
Feedback "1" *-- "1" PollutionType
|
||||
Feedback "1" *-- "1" SeverityLevel
|
||||
Feedback "1" *-- "1" FeedbackStatus
|
||||
Task "1" *-- "1" TaskStatus
|
||||
Assignment "1" *-- "1" AssignmentStatus
|
||||
AssignmentRecord "1" *-- "1" AssignmentMethod
|
||||
OperationLog "1" *-- "1" OperationType
|
||||
PollutantThreshold "1" *-- "1" PollutionType
|
||||
|
||||
' --- Aggregation & Association ---
|
||||
Task "1" --> "1" Feedback : "generated from"
|
||||
Task "1" o-- "1" Assignment : "has"
|
||||
Task "1" o-- "0..*" TaskHistory : "logs"
|
||||
Task "1" o-- "0..*" TaskSubmission : "receives"
|
||||
Feedback "1" o-- "0..*" Attachment : "has"
|
||||
TaskSubmission "1" o-- "0..*" Attachment : "has"
|
||||
AssignmentRecord "1" --> "1" Feedback : "for"
|
||||
UserAccount "1" --> "0..*" Feedback : "submits"
|
||||
UserAccount "1" --> "0..*" Task : "creates"
|
||||
Task "0..*" o-- "1" UserAccount : "assigned to"
|
||||
Assignment "1" --> "1" UserAccount : "assigned by"
|
||||
TaskHistory "1" --> "1" UserAccount : "changed by"
|
||||
AssignmentRecord "1" --> "1" UserAccount : "assigned to"
|
||||
AssignmentRecord "1" --> "1" UserAccount : "assigned by"
|
||||
OperationLog "1" --> "1" UserAccount : "performed by"
|
||||
PasswordResetToken "1" --> "1" UserAccount : "for"
|
||||
AqiData "1" --> "1" UserAccount : "reported by"
|
||||
|
||||
' --- Dependency & Other Associations ---
|
||||
Task "1" ..> "1" Grid : "located in"
|
||||
UserAccount "1" ..> "1" Grid : "operates in"
|
||||
AqiData "1" --> "1" Grid : "recorded at"
|
||||
AqiRecord "1" --> "1" Grid : "related to"
|
||||
|
||||
@enduml
|
||||
```
|
||||
@@ -1,77 +0,0 @@
|
||||
以下是所有API的URL:
|
||||
|
||||
### 基础URL
|
||||
`http://localhost:8080`
|
||||
|
||||
### 认证模块 (/api/auth)
|
||||
- `/api/auth/login`
|
||||
- `/api/auth/signup`
|
||||
- `/api/auth/logout`
|
||||
- `/api/auth/send-verification-code`
|
||||
- `/api/auth/send-password-reset-code`
|
||||
- `/api/auth/reset-password-with-code`
|
||||
|
||||
### 仪表盘模块 (/api/dashboard)
|
||||
- `/api/dashboard/stats`
|
||||
- `/api/dashboard/reports/aqi-distribution`
|
||||
- `/api/dashboard/reports/monthly-exceedance-trend`
|
||||
- `/api/dashboard/reports/grid-coverage`
|
||||
- `/api/dashboard/reports/pollution-stats`
|
||||
- `/api/dashboard/reports/task-completion-stats`
|
||||
- `/api/dashboard/reports/pollutant-monthly-trends`
|
||||
- `/api/dashboard/map/heatmap`
|
||||
- `/api/dashboard/map/aqi-heatmap`
|
||||
- `/api/dashboard/thresholds`
|
||||
- `/api/dashboard/thresholds/{pollutantName}`
|
||||
|
||||
### 反馈模块 (/api/feedback)
|
||||
- `/api/feedback/submit`
|
||||
- `/api/feedback`
|
||||
- `/api/feedback/{id}`
|
||||
- `/api/feedback/stats`
|
||||
- `/api/feedback/{id}/process`
|
||||
|
||||
### 公共接口模块 (/api/public)
|
||||
- `/api/public/feedback`
|
||||
|
||||
### 文件模块 (/api)
|
||||
- `/api/files/{filename}`
|
||||
- `/api/view/{filename}`
|
||||
|
||||
### 网格管理模块 (/api/grids)
|
||||
- `/api/grids`
|
||||
- `/api/grids/{id}`
|
||||
- `/api/grids/coverage`
|
||||
- `/api/grids/{gridId}/assign`
|
||||
- `/api/grids/{gridId}/unassign`
|
||||
- `/api/grids/coordinates/{gridX}/{gridY}/assign`
|
||||
- `/api/grids/coordinates/{gridX}/{gridY}/unassign`
|
||||
|
||||
### 人员管理模块 (/api/personnel)
|
||||
- `/api/personnel/users`
|
||||
- `/api/personnel/users/{userId}`
|
||||
- `/api/personnel/users/{userId}/role`
|
||||
|
||||
### 网格员任务模块 (/api/worker)
|
||||
- `/api/worker`
|
||||
- `/api/worker/{taskId}`
|
||||
- `/api/worker/{taskId}/accept`
|
||||
- `/api/worker/{taskId}/submit`
|
||||
|
||||
### 地图与寻路模块
|
||||
- `/api/map/grid`
|
||||
- `/api/map/initialize`
|
||||
- `/api/pathfinding/find`
|
||||
|
||||
### 个人资料模块 (/api/me)
|
||||
- `/api/me/feedback`
|
||||
|
||||
### 主管审核模块 (/api/supervisor)
|
||||
- `/api/supervisor/reviews`
|
||||
- `/api/supervisor/reviews/{feedbackId}/approve`
|
||||
- `/api/supervisor/reviews/{feedbackId}/reject`
|
||||
|
||||
### 任务分配模块 (/api/tasks)
|
||||
- `/api/tasks/unassigned`
|
||||
- `/api/tasks/grid-workers`
|
||||
- `/api/tasks/assign`
|
||||
@@ -1,9 +0,0 @@
|
||||
# 4. 参考资料
|
||||
|
||||
[1] Spring Boot. (2023). Spring Boot Reference Documentation. [https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/](https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/)
|
||||
|
||||
[2] Vue.js. (2023). The Vue.js Guide. [https://vuejs.org/guide/introduction.html](https://vuejs.org/guide/introduction.html)
|
||||
|
||||
[3] Baeldung. (2023). Spring Security. [https://www.baeldung.com/security-spring](https://www.baeldung.com/security-spring)
|
||||
|
||||
[4] Vaughn, V. (2013). *Implementing Domain-Driven Design*. Addison-Wesley Professional.
|
||||
@@ -1,3 +0,0 @@
|
||||
(1)所有数据以文件格式保存,文件存储在工程目录中。
|
||||
(2)文件数据格式可以是JSON格式,也可以是以对象序列化的方式存储。
|
||||
(3)东软环保公众监督系统主要功能为:汇总不同地区的公众监督员提供的空气质量信息,由系统管理员将这些信息指派给专业的环保检测网格员,进行实地考察和检测,从而得到不同地区的空气质量AQI(空气质量指数)的实时数据。再将这些AQI数据进行统计,统计结果最终成为环保方面决策者进行决策的依据。
|
||||
@@ -1,191 +0,0 @@
|
||||
# EMS系统完整依赖关系列表
|
||||
|
||||
## 1. 控制器层依赖 (Controller Dependencies)
|
||||
|
||||
### 控制器 → 服务层
|
||||
- `AuthController` → `AuthService`, `VerificationCodeService`, `OperationLogService`
|
||||
- `DashboardController` → `DashboardService`
|
||||
- `FeedbackController` → `FeedbackService`
|
||||
- `FileController` → `FileStorageService`
|
||||
- `GridController` → `GridService`, `GridRepository`, `UserAccountRepository`, `OperationLogService`
|
||||
- `GridWorkerTaskController` → `GridWorkerTaskService`
|
||||
- `MapController` → `MapGridRepository`
|
||||
- `OperationLogController` → `OperationLogService`
|
||||
- `PathfindingController` → `AStarService`
|
||||
- `PersonnelController` → `PersonnelService`, `UserAccountService`
|
||||
- `ProfileController` → `UserFeedbackService`
|
||||
- `PublicController` → `FeedbackService`
|
||||
- `SupervisorController` → `SupervisorService`
|
||||
- `TaskAssignmentController` → `TaskAssignmentService`
|
||||
- `TaskManagementController` → `TaskManagementService`
|
||||
|
||||
### 控制器 → DTO
|
||||
- `AuthController` → `LoginRequest`
|
||||
- `FeedbackController` → `FeedbackSubmissionRequest`
|
||||
- `TaskManagementController` → `TaskCreationRequest`
|
||||
- `PersonnelController` → `UserCreationRequest`
|
||||
|
||||
## 2. 服务层依赖 (Service Dependencies)
|
||||
|
||||
### 服务 → 仓库层
|
||||
- `AiReviewService` → `FeedbackRepository`
|
||||
- `AuthService` → `UserAccountRepository`, `PasswordResetTokenRepository`
|
||||
- `DashboardService` → `FeedbackRepository`, `UserAccountRepository`, `AqiDataRepository`, `AqiRecordRepository`, `GridRepository`, `TaskRepository`, `PollutantThresholdRepository`
|
||||
- `FeedbackService` → `FeedbackRepository`, `UserAccountRepository`, `TaskRepository`
|
||||
- `FileStorageService` → `AttachmentRepository`
|
||||
- `GridService` → `GridRepository`, `UserAccountRepository`, `MapGridRepository`
|
||||
- `GridWorkerTaskService` → `TaskRepository`, `TaskHistoryRepository`, `TaskSubmissionRepository`, `AttachmentRepository`
|
||||
- `OperationLogService` → `OperationLogRepository`, `UserAccountRepository`
|
||||
- `PersonnelService` → `UserAccountRepository`
|
||||
- `SupervisorService` → `FeedbackRepository`
|
||||
- `TaskAssignmentService` → `FeedbackRepository`, `UserAccountRepository`, `AssignmentRepository`, `TaskRepository`
|
||||
- `TaskManagementService` → `TaskRepository`, `UserAccountRepository`, `TaskHistoryRepository`, `FeedbackRepository`, `TaskSubmissionRepository`, `AttachmentRepository`
|
||||
- `UserAccountService` → `UserAccountRepository`
|
||||
- `UserFeedbackService` → `FeedbackRepository`
|
||||
- `AStarService` → `MapGridRepository`
|
||||
|
||||
### 服务 → 服务层
|
||||
- `AuthService` → `JwtService`, `VerificationCodeService`, `OperationLogService`
|
||||
- `FeedbackService` → `FileStorageService`, `TaskManagementService`, `OperationLogService`
|
||||
- `GridService` → `OperationLogService`
|
||||
- `GridWorkerTaskService` → `FileStorageService`, `OperationLogService`
|
||||
- `PersonnelService` → `OperationLogService`
|
||||
- `TaskAssignmentService` → `OperationLogService`
|
||||
- `TaskManagementService` → `OperationLogService`, `AStarService`
|
||||
- `VerificationCodeService` → `MailService`
|
||||
|
||||
## 3. 仓库层依赖 (Repository Dependencies)
|
||||
|
||||
### 仓库实现 → 存储服务
|
||||
- `JsonAssignmentRecordRepository` → `JsonStorageService`
|
||||
- `JsonAssignmentRepository` → `JsonStorageService`
|
||||
- `JsonAqiDataRepository` → `JsonStorageService`
|
||||
- `JsonAqiRecordRepository` → `JsonStorageService`
|
||||
- `JsonAttachmentRepository` → `JsonStorageService`
|
||||
- `JsonFeedbackRepository` → `JsonStorageService`
|
||||
- `JsonGridRepository` → `JsonStorageService`
|
||||
- `JsonMapGridRepository` → `JsonStorageService`
|
||||
- `JsonOperationLogRepository` → `JsonStorageService`
|
||||
- `JsonPasswordResetTokenRepository` → `JsonStorageService`
|
||||
- `JsonPollutantThresholdRepository` → `JsonStorageService`
|
||||
- `JsonTaskHistoryRepository` → `JsonStorageService`
|
||||
- `JsonTaskRepository` → `JsonStorageService`
|
||||
- `JsonTaskSubmissionRepository` → `JsonStorageService`
|
||||
- `JsonUserAccountRepository` → `JsonStorageService`
|
||||
|
||||
### 仓库 → 模型层
|
||||
- `AqiDataRepository` → `AqiData`
|
||||
- `AqiRecordRepository` → `AqiRecord`
|
||||
- `AssignmentRepository` → `Assignment`
|
||||
- `AssignmentRecordRepository` → `AssignmentRecord`
|
||||
- `AttachmentRepository` → `Attachment`
|
||||
- `FeedbackRepository` → `Feedback`
|
||||
- `GridRepository` → `Grid`
|
||||
- `MapGridRepository` → `MapGrid`
|
||||
- `OperationLogRepository` → `OperationLog`
|
||||
- `PasswordResetTokenRepository` → `PasswordResetToken`
|
||||
- `PollutantThresholdRepository` → `PollutantThreshold`
|
||||
- `TaskRepository` → `Task`
|
||||
- `TaskHistoryRepository` → `TaskHistory`
|
||||
- `TaskSubmissionRepository` → `TaskSubmission`
|
||||
- `UserAccountRepository` → `UserAccount`
|
||||
|
||||
## 4. 模型层关系 (Model Relationships)
|
||||
|
||||
### 实体关联
|
||||
- `UserAccount` (1) ↔ `Feedback` (*) : 用户提交反馈
|
||||
- `UserAccount` (1) ↔ `Task` (*) : 用户被分配任务
|
||||
- `UserAccount` (1) ↔ `Role` (1) : 用户拥有角色
|
||||
- `UserAccount` (1) ↔ `Assignment` (*) : 用户有分配记录
|
||||
- `Feedback` (1) ↔ `Task` (1) : 反馈生成任务
|
||||
- `Feedback` (*) ↔ `Attachment` (*) : 反馈包含附件
|
||||
- `Task` (1) ↔ `Assignment` (*) : 任务有分配记录
|
||||
- `Task` (*) ↔ `Attachment` (*) : 任务包含附件
|
||||
- `Task` (1) ↔ `TaskHistory` (*) : 任务有历史记录
|
||||
- `Task` (1) ↔ `TaskSubmission` (*) : 任务有提交记录
|
||||
- `Grid` (1) ↔ `AqiRecord` (*) : 网格有空气质量记录
|
||||
- `Assignment` → `Task`, `UserAccount` : 分配关联任务和用户
|
||||
- `AssignmentRecord` → `Feedback`, `UserAccount` : 分配记录关联反馈和用户
|
||||
- `Attachment` → `Feedback`, `TaskSubmission` : 附件关联反馈或任务提交
|
||||
- `AqiData` → `Grid` : 空气质量数据关联网格
|
||||
- `AqiRecord` → `Grid` : 空气质量记录关联网格
|
||||
|
||||
## 5. 服务实现依赖 (Service Implementation Dependencies)
|
||||
|
||||
### 接口实现关系
|
||||
- `AiReviewServiceImpl` → `AiReviewService`
|
||||
- `AuthServiceImpl` → `AuthService`
|
||||
- `DashboardServiceImpl` → `DashboardService`
|
||||
- `FeedbackServiceImpl` → `FeedbackService`
|
||||
- `FileStorageServiceImpl` → `FileStorageService`
|
||||
- `GridServiceImpl` → `GridService`
|
||||
- `GridWorkerTaskServiceImpl` → `GridWorkerTaskService`
|
||||
- `JsonStorageServiceImpl` → `JsonStorageService`
|
||||
- `JwtServiceImpl` → `JwtService`
|
||||
- `LoginAttemptServiceImpl` → `LoginAttemptService`
|
||||
- `MailServiceImpl` → `MailService`
|
||||
- `OperationLogServiceImpl` → `OperationLogService`
|
||||
- `PersonnelServiceImpl` → `PersonnelService`
|
||||
- `SupervisorServiceImpl` → `SupervisorService`
|
||||
- `TaskAssignmentServiceImpl` → `TaskAssignmentService`
|
||||
- `TaskManagementServiceImpl` → `TaskManagementService`
|
||||
- `UserAccountServiceImpl` → `UserAccountService`
|
||||
- `UserFeedbackServiceImpl` → `UserFeedbackService`
|
||||
- `VerificationCodeServiceImpl` → `VerificationCodeService`
|
||||
- `AStarServiceImpl` → `AStarService`
|
||||
|
||||
## 6. 安全层依赖 (Security Dependencies)
|
||||
|
||||
### 安全配置
|
||||
- `SecurityConfig` → `JwtAuthenticationFilter`, `UserAccountService`
|
||||
- `JwtAuthenticationFilter` → `UserDetailsServiceImpl`, `JwtService`
|
||||
- `UserDetailsServiceImpl` → `UserAccountService`
|
||||
- `CustomUserDetails` → `UserAccount`
|
||||
- `JwtService` → `UserAccountRepository`
|
||||
|
||||
## 7. 配置层依赖 (Configuration Dependencies)
|
||||
|
||||
### 配置类
|
||||
- `WebConfig` : Web配置
|
||||
- `SecurityConfig` : 安全配置
|
||||
- `JacksonConfig` : JSON序列化配置
|
||||
|
||||
## 8. 异常处理依赖 (Exception Dependencies)
|
||||
|
||||
### 异常类
|
||||
- `GlobalExceptionHandler` : 全局异常处理器
|
||||
- `FileStorageException` : 文件存储异常
|
||||
- `ResourceNotFoundException` : 资源未找到异常
|
||||
- `UnauthorizedException` : 未授权异常
|
||||
- `ValidationException` : 验证异常
|
||||
|
||||
## 9. 事件处理依赖 (Event Dependencies)
|
||||
|
||||
### 事件监听器
|
||||
- `TaskEventListener` : 任务事件监听器
|
||||
- `FeedbackEventListener` : 反馈事件监听器
|
||||
|
||||
## 10. 枚举依赖 (Enum Dependencies)
|
||||
|
||||
### 枚举类型
|
||||
- `Role` : 用户角色枚举
|
||||
- `TaskStatus` : 任务状态枚举
|
||||
- `FeedbackStatus` : 反馈状态枚举
|
||||
- `OperationType` : 操作类型枚举
|
||||
- `PollutantType` : 污染物类型枚举
|
||||
- `GridStatus` : 网格状态枚举
|
||||
|
||||
## 总结
|
||||
|
||||
本系统采用分层架构设计,包含:
|
||||
- **控制器层 (Controller)**: 15个控制器类
|
||||
- **服务层 (Service)**: 20个服务接口及其实现
|
||||
- **仓库层 (Repository)**: 15个仓库接口及其JSON实现
|
||||
- **模型层 (Model)**: 15个实体类
|
||||
- **安全层 (Security)**: 5个安全相关类
|
||||
- **配置层 (Configuration)**: 3个配置类
|
||||
- **异常处理**: 5个异常类
|
||||
- **事件处理**: 2个事件监听器
|
||||
- **枚举类型**: 6个枚举
|
||||
|
||||
总计约 **86个主要组件** 及其相互依赖关系,形成了一个完整的环境监测系统架构。
|
||||
163
Report/实践总结.md
163
Report/实践总结.md
@@ -1,163 +0,0 @@
|
||||
# 4. 实践总结与展望
|
||||
|
||||
本次"东软环保公众监督系统"的课程设计,对我而言,远不止是一次课程任务的完成,更是一场从理论到实践、从单一技能到综合工程能力的深度淬炼。通过从零开始,亲历一个完整软件项目的生命周期——从模糊的需求雏形到清晰的系统蓝图,从优雅的架构设计到严谨的代码实现,再到全面的测试交付——我不仅高质量地达成了所有预设目标,更在思想认知、技术栈深度和工程素养上实现了跨越式的成长。
|
||||
|
||||
## 4.1 收获与体会:从"会用"到"精通"的蜕变
|
||||
|
||||
### 1. 宏观架构观的树立与深化
|
||||
|
||||
本次实践最大的收获,莫过于在真实场景中主导并落地了**前后端分离架构**。这让我对现代Web应用架构的理解,从"知道其然"深入到了"知其所以然"。
|
||||
|
||||
* **深刻理解"解耦"的价值**:我不再将"解耦"视为一个抽象概念,而是亲身体会到它带来的巨大工程优势:后端可以专注于业务逻辑与数据服务,不受前端界面迭代的影响;前端则可以自由选择技术栈(Vue 3全家桶),聚焦于用户体验的打磨。这种并行的开发模式极大地提升了团队协作的效率。
|
||||
* **掌握RESTful API设计精髓**:我学习并实践了一套规范的RESTful API设计原则,包括使用HTTP动词(GET, POST, PUT, DELETE)表达操作,通过URI定位资源,以及设计统一的响应数据结构(包含状态码、消息和数据体)。这使得前后端的数据交互变得清晰、可预测且易于调试。
|
||||
* **拥抱"无状态服务"理念**:通过引入JWT进行认证授权,我设计的后端服务实现了无状态化。服务器不再需要存储用户的Session信息,每一次请求都包含了完整的认证信息,这为未来系统的水平扩展和负载均衡奠定了坚实的基础。
|
||||
|
||||
### 2. 设计能力与代码匠艺的磨练
|
||||
|
||||
面对"基于文件存储"这一核心约束,我没有选择简单的、面向过程的文件I/O操作,而是进行了一次富有创造性的技术探索,设计并实现了一套**模拟JPA思想的泛型JSON仓储层(Repository Layer)**。这成为我本次实践中最具价值的技术沉淀。
|
||||
|
||||
* **设计模式的实战应用**:该仓储层的实现,是对**SOLID原则**的一次综合演练。通过定义泛型接口`JsonRepository<T, ID>`,我实践了**依赖倒置原则**;通过`JsonStorageService`的封装,实现了数据读写逻辑的单一职责;通过为不同实体提供具体的Repository实现,遵循了**接口隔离原则**。这让我真正领会到"面向接口编程"如何带来代码的灵活性、可测试性和可扩展性。
|
||||
* **并发编程的初探**:为了解决多用户并发写文件可能导致的数据覆盖或错乱问题,我深入研究了Java的并发控制机制,并最终选用`synchronized`关键字对核心的写入方法进行加锁。通过压力测试,我验证了该机制的有效性,这让我对线程安全问题有了具体而深刻的认识,也为未来学习更高级的并发技术(如`ReentrantLock`、`CAS`)打下了基础。
|
||||
|
||||
### 3. 解决复杂技术难题的信心与方法论
|
||||
|
||||
项目开发过程并非一帆风顺,我遭遇并攻克了多个技术难点,这个过程极大地锻炼了我独立解决问题的能力。
|
||||
|
||||
* **攻坚`Spring Security`**:配置`Spring Security`与JWT的整合是一大挑战。我通过深入阅读官方文档和优秀开源项目的源码,理解了其Filter链的工作机制,并成功自定义了`JwtAuthenticationFilter`,实现了从请求头解析Token、验证签名、加载用户权限,最终将其置入`SecurityContextHolder`的完整流程。我还学会了使用`@PreAuthorize`注解,实现了精确到方法级别的声明式权限控制。
|
||||
* **构建优雅的全局异常处理**:为了避免在每个Controller方法中都充斥着大量的`try-catch`块,我利用Spring MVC提供的`@ControllerAdvice`和`@ExceptionHandler`注解,构建了一个统一的全局异常处理器。它可以捕获不同类型的业务异常(如`ResourceNotFoundException`)和系统异常,并将其转换为标准化的API错误响应返回给前端。这不仅净化了业务代码,也提升了API的健壮性和用户体验。
|
||||
|
||||
### 4. 软件工程全景视野的拓展
|
||||
|
||||
这次经历让我彻底摆脱了"代码工人"的思维定式,开始以一名"软件工程师"的视角来审视整个项目。我认识到,高质量的软件交付,远不止代码本身。
|
||||
|
||||
* **文档的价值**:我投入了大量精力编写清晰、规范的Markdown项目文档,包括需求文档、设计文档、API文档(Swagger)和测试报告。我发现,高质量的文档是团队沟通的基石,是项目知识传承的载体,更是保证项目长期可维护性的关键。
|
||||
* **测试的左移**:我主动引入了单元测试,并坚持在开发阶段就为核心模块编写测试用例。这让我体会到"测试左移"的重要性——越早发现Bug,修复的成本越低。全面的API测试和集成测试则构成了产品质量的最后一道防线。
|
||||
|
||||
## 4.2 不足与展望:迈向更高阶的工程师之路
|
||||
|
||||
在收获满满的同时,我也清醒地看到了当前项目的局限性和个人能力的待提升之处,这为我规划了清晰的未来学习路径。
|
||||
|
||||
* **构建成熟的自动化测试体系**:目前项目的自动化测试还处于初级阶段。我的下一步计划是:
|
||||
* **后端**:深入学习`Mockito`的高级用法(如`ArgumentCaptor`),并引入集成测试框架(如`Testcontainers`),在CI/CD流水线中自动运行测试,实现代码提交即测试。
|
||||
* **前端**:学习并引入`Vitest`进行单元测试,使用`Cypress`或`Playwright`进行端到端(E2E)测试,实现对关键用户流程的自动化回归验证。
|
||||
|
||||
* **拥抱云原生与DevOps**:当前项目采用的是传统的手动部署模式,效率低下且容易出错。我渴望掌握云原生技术栈:
|
||||
* **容器化**:学习`Docker`,将前后端应用及其依赖环境打包成独立的、可移植的容器镜像。
|
||||
* **容器编排**:学习`Kubernetes`,实现容器化应用的自动化部署、弹性伸缩和高可用运维。
|
||||
* **CI/CD**:学习`Jenkins`或`GitHub Actions`,搭建一条完整的自动化流水线,实现从代码提交到测试、构建、部署的全流程自动化。
|
||||
|
||||
* **深化业务与技术的融合创新**:
|
||||
* **实时化改造**:引入`WebSocket`或`Server-Sent Events (SSE)`,将任务的分配、状态流转等关键信息实时推送到前端,极大地提升系统的即时性和用户的沉浸式体验。
|
||||
* **数据智能升级**:当数据量增长后,引入`Elasticsearch`,提供强大的全文检索和聚合分析能力。长远来看,可以结合机器学习算法,对环境问题数据进行深度挖掘,实现如"区域环境问题热点预测"、"污染源智能追溯"等更高阶的智能应用。
|
||||
|
||||
总而言之,这次课程设计是我从一名编程学习者向一名准软件工程师转变的里程碑。它不仅系统性地检验了我过往的知识积累,更重要的是,它点燃了我对软件架构、代码匠艺和工程卓越的无限热情。在这次实践中收获的宝贵经验和暴露的不足,都将化为我未来职业道路上最坚实的基石和最清晰的路标,激励我不断学习、持续精进。
|
||||
|
||||
## 内容完成情况
|
||||
|
||||
在本次环境监督系统(EMS)的开发实践中,我完成了以下主要内容:
|
||||
|
||||
1. **系统设计文档**:完成了详细的系统设计文档,包括整体架构设计、功能模块划分、数据库设计和API接口设计等方面。
|
||||
|
||||
2. **后端核心功能实现**:
|
||||
- 实现了基于JSON文件的泛型存储服务
|
||||
- 开发了A*寻路算法用于网格员路径规划
|
||||
- 完成了反馈管理模块的全流程实现
|
||||
- 设计并实现了任务智能分配算法
|
||||
|
||||
3. **前端界面设计与实现**:
|
||||
- 开发了主管工作台、网格员工作台和决策支持看板等核心界面
|
||||
- 实现了响应式布局和组件化开发
|
||||
|
||||
4. **系统实现文档**:编写了详细的系统实现文档,包括开发环境与技术栈、核心功能模块实现和界面展示等内容。
|
||||
|
||||
## 创新点
|
||||
|
||||
### 1. 泛型JSON存储服务
|
||||
|
||||
设计并实现了一个创新的数据持久化解决方案,使用JSON文件代替传统数据库进行数据存储。这种方案具有以下创新点:
|
||||
|
||||
- **类型安全的泛型设计**:通过Java泛型和TypeReference,实现了类型安全的数据读写,支持任意模型类。
|
||||
- **类数据库接口**:提供了类似于JPA的操作接口,使得业务层代码无需关心底层存储细节。
|
||||
- **部署简化**:无需配置和维护数据库,大大简化了系统部署过程。
|
||||
- **线程安全机制**:使用synchronized关键字确保写操作的线程安全,防止并发写入导致的数据损坏。
|
||||
|
||||
### 2. A*寻路算法的动态地图适配
|
||||
|
||||
在网格与地图模块中,实现的A*寻路算法具有以下创新特点:
|
||||
|
||||
- **动态地图加载**:算法从数据库动态加载地图数据,包括障碍物信息和地图尺寸,使得路径规划能够适应地图的变化。
|
||||
- **优先队列优化**:使用优先队列(PriorityQueue)存储开放列表,确保每次都能高效地选择F值最小的节点。
|
||||
- **适应性启发函数**:选择曼哈顿距离作为启发函数,适合网格化的城市环境移动模式。
|
||||
|
||||
### 3. 多因素加权的任务智能分配算法
|
||||
|
||||
任务分配算法综合考虑了多种因素,具有较高的智能性:
|
||||
|
||||
- **多维度评分机制**:算法综合考虑了地理距离、当前负载、专业匹配度和历史表现四个因素。
|
||||
- **动态技能匹配**:根据任务的污染类型和严重程度,动态确定所需的技能列表,然后与网格员的技能进行匹配。
|
||||
- **可配置权重系统**:各因素的权重可以根据实际需求进行调整,使得算法更加灵活和适应性强。
|
||||
|
||||
### 4. 事件驱动的业务流程设计
|
||||
|
||||
在反馈管理模块中,采用了事件驱动的架构设计:
|
||||
|
||||
- **解耦的业务流程**:通过Spring的事件机制,实现了反馈提交后的异步处理,如AI审核和任务创建。
|
||||
- **状态机模式**:使用状态机模式管理反馈的生命周期,确保状态转换的合法性,防止非法操作。
|
||||
- **可扩展的事件处理**:新的事件处理器可以轻松添加,无需修改现有代码,符合开闭原则。
|
||||
|
||||
### 5. 文件上传与存储服务
|
||||
|
||||
在环境问题反馈和任务处理过程中,实现了高效且安全的文件上传与存储机制:
|
||||
|
||||
- **多媒体支持**:支持图片、视频和音频等多种媒体格式的上传,为环境问题提供直观的证据支持。
|
||||
- **安全性控制**:实现了文件类型验证、大小限制和内容扫描,防止恶意文件上传,保障系统安全。
|
||||
- **分层存储架构**:采用物理路径与逻辑路径分离的设计,文件实际存储在安全目录,而数据库中仅保存引用路径,增强了系统的安全性和灵活性。
|
||||
- **按需加载策略**:对于大型媒体文件,实现了流式传输和分块下载,优化了带宽使用和用户体验。
|
||||
|
||||
## 不足与可改进之处
|
||||
|
||||
尽管系统已经实现了核心功能,但由于时间限制,仍有一些方面可以进一步完善:
|
||||
|
||||
### 1. 数据持久化机制的优化
|
||||
|
||||
当前的JSON文件存储方案虽然简化了部署,但也存在一些局限性:
|
||||
|
||||
- **性能瓶颈**:随着数据量增大,JSON文件的读写性能可能成为瓶颈。可以考虑实现分片存储或引入缓存机制。
|
||||
- **事务支持**:当前实现缺乏事务支持,无法保证跨文件操作的原子性。可以设计一个简单的事务管理器来解决这个问题。
|
||||
- **索引机制**:缺乏高效的索引机制,导致复杂查询性能较低。可以实现内存索引或考虑集成轻量级数据库如SQLite。
|
||||
|
||||
### 2. A*算法的进一步优化
|
||||
|
||||
A*寻路算法还可以在以下方面进行优化:
|
||||
|
||||
- **双向搜索**:实现双向A*搜索,从起点和终点同时开始搜索,可以显著减少搜索空间。
|
||||
- **层次化路径规划**:对于大型地图,可以实现层次化的路径规划,先在抽象层次上找到大致路径,再在细节层次上优化。
|
||||
- **动态权重调整**:根据不同的地形特征动态调整边的权重,更好地模拟现实世界的移动成本。
|
||||
|
||||
### 3. 任务分配算法的增强
|
||||
|
||||
任务分配算法可以通过以下方式进一步增强:
|
||||
|
||||
- **机器学习集成**:引入机器学习模型,根据历史分配数据学习最优的权重配置,实现自适应的任务分配。
|
||||
- **群体智能优化**:考虑整个网格员团队的工作负载均衡,而不仅仅是单个任务的最优分配。
|
||||
- **预测性分配**:基于历史数据预测未来一段时间内可能出现的任务,提前做好人力资源规划。
|
||||
|
||||
### 4. 前端用户体验优化
|
||||
|
||||
前端界面还可以在以下方面进行改进:
|
||||
|
||||
- **离线支持**:实现Progressive Web App (PWA),使网格员在网络不稳定的野外环境也能使用系统。
|
||||
- **实时通知**:集成WebSocket或服务器发送事件(SSE),实现实时任务通知和状态更新。
|
||||
- **移动端适配**:进一步优化移动端体验,考虑开发原生移动应用,提供更好的定位和拍照体验。
|
||||
|
||||
### 5. 系统安全性增强
|
||||
|
||||
安全方面还可以进一步加强:
|
||||
|
||||
- **细粒度权限控制**:实现基于资源的访问控制(RBAC),对不同资源设置更细粒度的权限控制。
|
||||
- **API限流与防护**:实现API限流机制,防止DoS攻击;添加CSRF保护和更完善的输入验证。
|
||||
- **审计日志**:实现全面的审计日志系统,记录所有关键操作,便于安全审计和问题追踪。
|
||||
|
||||
## 结论
|
||||
|
||||
通过本次实践,我成功地设计并实现了环境监督系统的核心功能,在泛型JSON存储服务、A*寻路算法、任务智能分配算法和事件驱动架构等方面进行了创新。虽然由于时间限制,一些高级特性和优化未能实现,但这些都已经被识别为未来可以改进的方向。总体而言,系统达到了预期的设计目标,提供了一个功能完整、架构合理的环境监督解决方案。
|
||||
@@ -1,55 +0,0 @@
|
||||
# 《东软环保公众监督平台》项目实践目的
|
||||
|
||||
### 一、项目概述与本人工作
|
||||
|
||||
本项目旨在开发一个高效、透明的环保公众监督平台,作为《东软环保应急》系统的重要子模块。系统的核心业务流程覆盖了从公众反馈、智能初审、任务转化、智能分配到最终处理的全生命周期管理,旨在拓宽环保监督渠道,增加工作透明度,为环保决策提供数据支持。
|
||||
|
||||
在本次实践中,**本人担任核心的系统设计与开发角色**,是项目的主要贡献者。具体工作内容涵盖了整个软件生命周期,包括但不限于:
|
||||
|
||||
* **需求分析与建模**:深入分析项目需求,将模糊的业务概念转化为精确的功能规格,并运用UML类图对系统核心实体进行建模。
|
||||
* **系统架构设计**:主导了项目技术选型,确定了采用`Spring Boot` + `Vue.js`前后端分离的现代Web架构,并设计了后端的三层(Controller, Service, Repository)分层结构。
|
||||
* **数据持久化方案设计**:针对"数据存储于文件"的核心约束,独立设计并实现了一套基于JSON文件的泛型仓储层(Repository Pattern),巧妙地解决了数据持久化问题,保证了代码的可维护性。
|
||||
* **核心模块编码实现**:独立完成了用户认证(JWT)、反馈管理、任务全生命周期管理、智能任务分配算法等多个核心业务模块的后端代码编写工作。
|
||||
* **API接口定义**:负责设计并编写了项目整体的RESTful API接口,并利用Swagger工具生成了清晰、规范的API文档,为前后端高效协作提供了保障。
|
||||
* **技术文档撰写**:作为主要作者,撰写了《系统设计方案》等核心技术文档,系统性地阐述了项目的技术实现细节。
|
||||
|
||||
### 二、能力培养达成情况
|
||||
|
||||
通过本次毕业设计实践,本人在指导老师的帮助下,系统性地将软件工程理论知识与项目实践相结合,在以下方面取得了显著的进步,达成了毕业设计所要求的各项能力培养目标:
|
||||
|
||||
#### 1. 设计/开发解决方案的能力
|
||||
|
||||
* **(1)掌握软件生命周期要素,熟悉软件工程方法与技术:**
|
||||
* **全周期理解与实践**:深刻理解并实践了从需求分析、系统设计、编码实现到测试维护的软件全生命周期。
|
||||
* **面向对象设计**:在项目设计阶段,始终贯彻面向对象的思想,对系统的核心业务(如用户账户`UserAccount`、环境反馈`Feedback`、处理任务`Task`)进行高度抽象,设计出了高内聚、低耦合的类结构。
|
||||
* **UML系统建模**:能够熟练运用PlantUML工具,通过绘制UML类图,对系统中的十余个核心实体及其关联的枚举类型进行整体建模,清晰地表达了类之间的关联、聚合与依赖关系,为后续开发提供了清晰、规范的蓝图。
|
||||
* **数据持久化设计**:根据"所有数据以文件格式保存"的核心要求,设计并实现了一套基于JSON文件的数据持久化方案。通过为不同实体创建独立的JSON文件,并设计相应的读写服务,确保了数据的合理组织与一致性。
|
||||
* **界面设计**:在前后端分离的架构下,与前端开发紧密配合,确保了API接口设计能够满足前端对美观、实用、符合用户习惯的界面的数据需求。
|
||||
|
||||
* **(2)设计满足特定需求的解决方案并体现创新意识:**
|
||||
* **任务分配算法设计**:为满足高效调度的需求,不止于简单的手动任务指派,而是进一步设计了一套基于"地理邻近度"和"当前工作负载"的加权评分模型,提出了具体的智能任务分配算法解决方案,体现了解决特定业务需求时的创新性。
|
||||
* **仓储层模式创新**:为解决直接操作JSON文件导致业务逻辑混乱的问题,创新性地设计并实现了一套模拟`Spring Data JPA`接口的泛型仓储层(Repository Pattern)。该方案通过引入泛型和反射机制,极大地提升了数据访问层的代码整洁性与可维护性,是本次实践中的一个重要技术创新点。
|
||||
|
||||
#### 2. 研究能力
|
||||
|
||||
* **(3)理解系统设计原理,掌握科学方法解决问题:**
|
||||
* **深入理解架构原理**:通过实践,不仅熟练掌握了Spring Boot框架的应用,更深入理解了其背后的分层架构(Controller-Service-Repository)、依赖注入(DI)、面向切面编程(AOP)等核心设计思想。
|
||||
* **掌握事件驱动模型**:在设计AI对反馈进行初审的功能时,引入了Spring的事件发布/监听机制,将耗时的AI分析流程解耦为异步处理,既提升了API的响应速度,也增强了系统的健壮性和可扩展性。
|
||||
* **科学方法应用**:在设计"网格员任务路径规划"功能时,主动研究并集成了经典的A*寻路算法,能够运用科学的、经过验证的算法来解决工程中的最短路径问题,展现了将理论算法应用于工程实践的能力。
|
||||
|
||||
#### 3. 使用现代工具的能力
|
||||
|
||||
* **(4)能够选择并熟练使用现代工程工具:**
|
||||
* 在整个开发过程中,能够根据项目需要,熟练选择和运用一整套现代工程工具对复杂的软件工程问题进行分析与设计:
|
||||
* **后端技术栈**: Java, Spring Boot, Spring Security (for JWT)
|
||||
* **项目管理与构建**: Maven
|
||||
* **版本控制**: Git, GitHub
|
||||
* **设计与文档工具**: PlantUML, Mermaid.js, Markdown
|
||||
* **集成开发环境 (IDE)**: IntelliJ IDEA, VS Code
|
||||
|
||||
#### 4. 沟通能力
|
||||
|
||||
* **(5)具备通过多种方式进行技术沟通的能力:**
|
||||
* **文稿沟通**:能够通过撰写《系统设计方案》、《实践目的》等多种技术文档,系统性、结构化地阐述项目背景、设计思路和技术方案,文字表达清晰、逻辑严密。
|
||||
* **图表沟通**:在技术文档中,能够熟练运用UML类图、时序图等多种图表,将复杂的系统静态结构、对象交互时序等信息进行高度可视化、标准化的表达,极大地提升了与业界同行进行技术交流的效率和准确性。
|
||||
* **口头沟通**:在项目讨论中,能够清晰地向指导老师和项目组成员阐述自己的技术见解和设计方案,展现了良好的口头表达与技术沟通能力。
|
||||
@@ -1,3 +0,0 @@
|
||||
# 2. 实践结果
|
||||
|
||||
本章节将详细阐述“东软环保公众监督系统”从需求定义到系统测试的完整实践过程。
|
||||
@@ -1,62 +0,0 @@
|
||||
实践目的
|
||||
首先对项目内容进行“概述”,并明确说明本人从事的工作;
|
||||
然后,写出本人通过本次实践,达成了以下哪些能力的培养,要求简洁清楚。可以从以下几点来说明:(不要照抄以下内容,说明自己的能力达成情况)
|
||||
设计/开发解决方案的能力:
|
||||
(1)掌握软件生命周期要素(理解、掌握,并能够按照面向对象的思想对系统进行设计),熟悉软件需求分析、设计、实现、测试的方法和技术(能够使用UML类图对系统整体建模,会抽取类、属性、方法、关联,设计合理,符合系统要求;能够合理持久化存储;界面设计美观实用等);
|
||||
(2)能够设计满足特定功能需求与性能需求的解决方案,并体现创新意识;
|
||||
研究能力:
|
||||
(3)能够理解系统软件的设计思路和基本原理,掌握应用软件技术、科学方法,具备创新性地解决软件工程具体问题的能力;
|
||||
使用现代工具的能力:
|
||||
(4)能够选择恰当的技术、资源、现代工程工具和信息技术工具,对复杂软件工程问题进行分析、计算或设计;
|
||||
沟通能力:
|
||||
(5)具备一定的社交技能和技巧,能够就与本专业相关的当前热点问题发表自己的观点,能够以口头、文稿、图表等方式与业界同行进行技术交流与沟通,能使用通俗易懂的语言与社会公众进行表达与沟通;
|
||||
|
||||
1. 相关技术基础
|
||||
写出本次实践过程中你所用到的相关技术,包括与项目相关的理论基础,项目开发方法、开发工具、开发环境等关键技术的介绍;
|
||||
|
||||
2. 实践结果
|
||||
此部分属报告的主要部分。包括:
|
||||
3.1 需求定义
|
||||
“系统分析”也可以看成是需求定义,包括对整个项目的介绍分析及本人工作内容的详细分析,如业务分析、功能分析(可使用例图、活动图来描述)、可行性分析等;
|
||||
3.2 系统设计
|
||||
“系统设计”包括总体设计和详细设计,"总体设计"包括系统架构设计、功能模块划分等,"详细设计"要围绕本人工作内容展开,包括功能模块详细设计、类和对象的设计、动态模型设计(时序图、状态图、协作图等)、算法设计、数据库设计等;
|
||||
3.3 系统实现
|
||||
“系统实现”也要围绕本人工作内容展开,从编码实现角度论述相应功能模块的实现细节,并展示自己所完成的主要成果及实际应用情况等。可通过“程序流程图”、“关键代码”和“界面”进行直观论述。
|
||||
3.4 系统测试
|
||||
“系统测试”包括测试方案设计、测试用例和测试结果、最终的测试结论或评价等。
|
||||
|
||||
3. 实践总结
|
||||
简述你在实践过程中的内容完成情况,重点介绍创新点及不足(也就是可以再完善的部分,只是时间不允许了。不足不代表不好,也说明你思考了,但是来不及完成实现)
|
||||
|
||||
4. 参考资料
|
||||
例:
|
||||
[1] 数据结构、算法与应用:C++语言描述 [Data Structures,Algorithms,and Applications in C++][M].机械工业出版社出版时间:2000-01-01.
|
||||
[2] 数据结构(C语言版) [M].北京: 中国铁道出版社, 2011-08-01.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
基础编程实训成绩评定表
|
||||
|
||||
考核内容 考核标准 分值 得分
|
||||
|
||||
面向对象设计能力 1. 能够很好的按照面向对象的思想对系统进行设计和实现,设计合理的实体关系,正确使用UML类图对系统整体建模,设计合理,符合系统要求;
|
||||
2. 能够很好的划分模块和提取方法,程序设计具有高内聚低耦合的特点;
|
||||
3. 能够合理应用多种设计模式,提高系统的灵活性和可用性; 20
|
||||
面向对象编程能力 1. 能够应用面向对象程序设计语言进行系统实现;
|
||||
2. 能够很好的使用继承和多态,提升代码复用性;
|
||||
3. 程序设计逻辑结构清晰合理;
|
||||
4. 代码规范,遵照Java的代码规范。 20
|
||||
解决问题能力 1. 能够正确使用已有的架构完成系统功能,如MVC架构;
|
||||
2. 能够很好的设计持久化存储结构。正确使用Java语言实现设计的系统,程序结构清晰,代码书写规范,简洁,实现的系统功能完善,运行稳定,基本无bug。
|
||||
3. 界面美观,符合用户习惯; 20
|
||||
学习能力 1. 能够自学Java语言中关于图形用户界面的知识,并能为开发的系统构造图形用户界面。能够挑选合适GUI插件(如window builder插件)快速构建图形用户界面。
|
||||
2. 能够在集成开发环境中对系统进行开发和调试,能够使用代码检查工具提升代码的正确性。
|
||||
3. 能够通过网络、课堂、书籍等多处获取所需的知识,并应用这些知识解决相应的问题。
|
||||
4. 在解决问题的过程中有自己独到的见解,并能够有所创新。 20
|
||||
报告质量 1. 实践报告格式规范,报告内容充实、正确,报告叙述逻辑严密,可准确反映出设计和实现的结果。
|
||||
2. 实践报告能够体现实践过程中出现的问题和解决方案,以及独立分析问题和解决问题的能力。
|
||||
3. 报告格式统一,图表使用规范,报告用词准确,符合科技文档写作要求。 20
|
||||
总 分(百分制)
|
||||
|
||||
463
Report/时序图.md
463
Report/时序图.md
@@ -1,463 +0,0 @@
|
||||
# EMS后端系统技术图表文档
|
||||
|
||||
## 项目概述
|
||||
|
||||
环境管理系统(EMS)后端是一个基于Spring Boot的Java应用程序,用于处理环境问题反馈、任务分配和用户管理。系统采用分层架构,包含控制器、服务、仓库和模型层。
|
||||
|
||||
## 1. 系统时序图
|
||||
|
||||
### 1.1 用户登录认证流程
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant AuthController as 认证控制器
|
||||
participant AuthService as 认证服务
|
||||
participant UserRepository as 用户仓库
|
||||
participant JwtUtil as JWT工具
|
||||
participant Database as JSON持久化存储
|
||||
|
||||
User->>AuthController: POST /api/auth/login
|
||||
AuthController->>AuthService: signIn(LoginRequest)
|
||||
AuthService->>UserRepository: findByEmailOrPhone()
|
||||
UserRepository->>Database: 查询用户信息
|
||||
Database-->>UserRepository: 返回用户数据
|
||||
UserRepository-->>AuthService: 返回UserAccount
|
||||
AuthService->>AuthService: 验证密码
|
||||
AuthService->>JwtUtil: 生成JWT令牌
|
||||
JwtUtil-->>AuthService: 返回JWT
|
||||
AuthService-->>AuthController: JwtAuthenticationResponse
|
||||
AuthController-->>User: 返回JWT令牌
|
||||
```
|
||||
|
||||
### 1.2 反馈提交处理流程
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant FeedbackController as 反馈控制器
|
||||
participant FeedbackService as 反馈服务
|
||||
participant FeedbackRepository as 反馈仓库
|
||||
participant AIService as AI服务
|
||||
participant EventPublisher as 事件发布器
|
||||
participant Database as JSON持久化存储
|
||||
|
||||
User->>FeedbackController: POST /api/feedback/submit
|
||||
FeedbackController->>FeedbackService: submitFeedback(request, files)
|
||||
FeedbackService->>FeedbackService: 生成事件ID
|
||||
FeedbackService->>FeedbackRepository: save(feedback)
|
||||
FeedbackRepository->>Database: 保存反馈数据
|
||||
Database-->>FeedbackRepository: 返回保存结果
|
||||
FeedbackRepository-->>FeedbackService: 返回Feedback实体
|
||||
FeedbackService->>EventPublisher: 发布反馈创建事件
|
||||
EventPublisher->>AIService: 触发AI处理
|
||||
AIService->>AIService: 分析反馈内容
|
||||
FeedbackService-->>FeedbackController: 返回Feedback
|
||||
FeedbackController-->>User: 201 Created
|
||||
```
|
||||
|
||||
### 1.3 任务分配流程
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Supervisor as 主管
|
||||
participant TaskController as 任务控制器
|
||||
participant TaskService as 任务服务
|
||||
participant AssignmentService as 分配服务
|
||||
participant UserRepository as 用户仓库
|
||||
participant TaskRepository as 任务仓库
|
||||
participant GridWorker as 网格工作人员
|
||||
|
||||
Supervisor->>TaskController: POST /api/tasks/assign
|
||||
TaskController->>TaskService: assignTask(taskId, workerId)
|
||||
TaskService->>UserRepository: findById(workerId)
|
||||
UserRepository-->>TaskService: 返回GridWorker
|
||||
TaskService->>AssignmentService: createAssignment()
|
||||
AssignmentService->>TaskRepository: updateTaskStatus()
|
||||
TaskRepository-->>AssignmentService: 更新成功
|
||||
AssignmentService-->>TaskService: Assignment创建成功
|
||||
TaskService->>TaskService: 发送通知给工作人员
|
||||
TaskService-->>TaskController: 分配成功
|
||||
TaskController-->>Supervisor: 200 OK
|
||||
Note over GridWorker: 接收任务通知
|
||||
```
|
||||
|
||||
### 1.4 主管审核反馈并创建任务
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Supervisor as 主管
|
||||
participant FeedbackController as 反馈控制器
|
||||
participant FeedbackService as 反馈服务
|
||||
participant TaskService as 任务服务
|
||||
participant TaskRepository as 任务仓库
|
||||
participant Database as JSON持久化存储
|
||||
|
||||
Supervisor->>FeedbackController: POST /api/feedback/{id}/process
|
||||
FeedbackController->>FeedbackService: processFeedback(feedbackId, request)
|
||||
FeedbackService->>FeedbackService: 验证反馈状态和主管权限
|
||||
alt 同意反馈并创建任务
|
||||
FeedbackService->>TaskService: createTaskFromFeedback(feedback)
|
||||
TaskService->>TaskRepository: save(task)
|
||||
TaskRepository->>Database: 保存新任务
|
||||
Database-->>TaskRepository: 返回保存的任务
|
||||
TaskRepository-->>TaskService: 返回Task实体
|
||||
TaskService->>FeedbackService: 更新反馈状态为PENDING_ASSIGNMENT
|
||||
FeedbackService-->>FeedbackController: 返回处理结果
|
||||
else 拒绝反馈
|
||||
FeedbackService->>FeedbackService: 更新反馈状态为REJECTED
|
||||
FeedbackService-->>FeedbackController: 返回处理结果
|
||||
end
|
||||
FeedbackController-->>Supervisor: 200 OK
|
||||
```
|
||||
|
||||
### 1.5 用户密码重置流程
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant AuthController as 认证控制器
|
||||
participant AuthService as 认证服务
|
||||
participant VerificationCodeService as 验证码服务
|
||||
participant MailService as 邮件服务
|
||||
participant UserRepository as 用户仓库
|
||||
|
||||
User->>AuthController: POST /api/auth/send-password-reset-code (email)
|
||||
AuthController->>AuthService: requestPasswordReset(email)
|
||||
AuthService->>UserRepository: findByEmail(email)
|
||||
UserRepository-->>AuthService: 返回UserAccount
|
||||
AuthService->>VerificationCodeService: createAndSendPasswordResetCode(user)
|
||||
VerificationCodeService->>MailService: sendEmail(to, subject, content)
|
||||
MailService-->>VerificationCodeService: 邮件发送成功
|
||||
VerificationCodeService-->>AuthService: 验证码发送成功
|
||||
AuthService-->>AuthController: 200 OK
|
||||
AuthController-->>User: 提示验证码已发送
|
||||
|
||||
User->>AuthController: POST /api/auth/reset-password-with-code (email, code, newPassword)
|
||||
AuthController->>AuthService: resetPasswordWithCode(email, code, newPassword)
|
||||
AuthService->>VerificationCodeService: validateCode(email, code)
|
||||
VerificationCodeService-->>AuthService: 验证码有效
|
||||
AuthService->>UserRepository: save(user) with new password
|
||||
UserRepository-->>AuthService: 用户密码更新成功
|
||||
AuthService-->>AuthController: 200 OK
|
||||
AuthController-->>User: 密码重置成功
|
||||
```
|
||||
|
||||
### 1.6 用户获取自己的反馈历史
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant ProfileController as 个人资料控制器
|
||||
participant UserFeedbackService as 用户反馈服务
|
||||
participant FeedbackRepository as 反馈仓库
|
||||
participant Database as JSON持久化存储
|
||||
|
||||
User->>ProfileController: GET /api/me/feedback
|
||||
ProfileController->>UserFeedbackService: getFeedbackHistoryByUserId(userId, pageable)
|
||||
UserFeedbackService->>FeedbackRepository: findBySubmitterId(userId, pageable)
|
||||
FeedbackRepository->>Database: 查询用户反馈数据
|
||||
Database-->>FeedbackRepository: 返回反馈数据
|
||||
FeedbackRepository-->>UserFeedbackService: 返回Page<Feedback>
|
||||
UserFeedbackService->>UserFeedbackService: 转换为UserFeedbackSummaryDTO列表
|
||||
UserFeedbackService-->>ProfileController: 返回Page<UserFeedbackSummaryDTO>
|
||||
ProfileController-->>User: 返回反馈历史列表
|
||||
```
|
||||
|
||||
### 1.7 网格员获取和管理任务
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant GridWorker as 网格员
|
||||
participant GridWorkerTaskController as 网格员任务控制器
|
||||
participant GridWorkerTaskService as 网格员任务服务
|
||||
participant TaskRepository as 任务仓库
|
||||
participant Database as JSON持久化存储
|
||||
|
||||
alt 获取任务列表
|
||||
GridWorker->>GridWorkerTaskController: GET /api/worker/tasks
|
||||
GridWorkerTaskController->>GridWorkerTaskService: getAssignedTasks(workerId, status, pageable)
|
||||
GridWorkerTaskService->>TaskRepository: findByAssigneeIdAndStatus(workerId, status, pageable)
|
||||
TaskRepository->>Database: 查询任务数据
|
||||
Database-->>TaskRepository: 返回任务数据
|
||||
TaskRepository-->>GridWorkerTaskService: 返回Page<Task>
|
||||
GridWorkerTaskService->>GridWorkerTaskService: 转换为TaskSummaryDTO列表
|
||||
GridWorkerTaskService-->>GridWorkerTaskController: 返回Page<TaskSummaryDTO>
|
||||
GridWorkerTaskController-->>GridWorker: 返回任务列表
|
||||
end
|
||||
|
||||
alt 接受任务
|
||||
GridWorker->>GridWorkerTaskController: POST /api/worker/tasks/{taskId}/accept
|
||||
GridWorkerTaskController->>GridWorkerTaskService: acceptTask(taskId, workerId)
|
||||
GridWorkerTaskService->>TaskRepository: findById(taskId)
|
||||
TaskRepository->>Database: 查询任务
|
||||
Database-->>TaskRepository: 返回任务
|
||||
TaskRepository-->>GridWorkerTaskService: 返回Task
|
||||
GridWorkerTaskService->>GridWorkerTaskService: 验证任务状态并更新为ACCEPTED
|
||||
GridWorkerTaskService->>TaskRepository: save(task)
|
||||
TaskRepository->>Database: 更新任务状态
|
||||
Database-->>TaskRepository: 返回更新后的任务
|
||||
TaskRepository-->>GridWorkerTaskService: 返回更新后的Task
|
||||
GridWorkerTaskService->>GridWorkerTaskService: 转换为TaskSummaryDTO
|
||||
GridWorkerTaskService-->>GridWorkerTaskController: 返回TaskSummaryDTO
|
||||
GridWorkerTaskController-->>GridWorker: 返回更新后的任务摘要
|
||||
end
|
||||
|
||||
alt 提交任务
|
||||
GridWorker->>GridWorkerTaskController: POST /api/worker/tasks/{taskId}/submit
|
||||
GridWorkerTaskController->>GridWorkerTaskService: submitTaskCompletion(taskId, workerId, request, files)
|
||||
GridWorkerTaskService->>TaskRepository: findById(taskId)
|
||||
TaskRepository->>Database: 查询任务
|
||||
Database-->>TaskRepository: 返回任务
|
||||
TaskRepository-->>GridWorkerTaskService: 返回Task
|
||||
GridWorkerTaskService->>GridWorkerTaskService: 验证并更新任务状态为COMPLETED
|
||||
GridWorkerTaskService->>GridWorkerTaskService: (如果存在)处理附件上传
|
||||
GridWorkerTaskService->>TaskRepository: save(task)
|
||||
TaskRepository->>Database: 更新任务
|
||||
Database-->>TaskRepository: 返回更新后的任务
|
||||
TaskRepository-->>GridWorkerTaskService: 返回更新后的Task
|
||||
GridWorkerTaskService->>GridWorkerTaskService: 转换为TaskSummaryDTO
|
||||
GridWorkerTaskService-->>GridWorkerTaskController: 返回TaskSummaryDTO
|
||||
GridWorkerTaskController-->>GridWorker: 返回更新后的任务摘要
|
||||
end
|
||||
```
|
||||
|
||||
### 1.8 决策者获取仪表盘数据
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant DecisionMaker as 决策者
|
||||
participant DashboardController as 仪表盘控制器
|
||||
participant DashboardService as 仪表盘服务
|
||||
participant variousRepositories as 各类仓库
|
||||
participant Database as JSON持久化存储
|
||||
|
||||
alt 获取核心统计数据
|
||||
DecisionMaker->>DashboardController: GET /api/dashboard/stats
|
||||
DashboardController->>DashboardService: getDashboardStats()
|
||||
DashboardService->>variousRepositories: (并行)调用多个仓库方法获取数据
|
||||
variousRepositories->>Database: 查询统计数据
|
||||
Database-->>variousRepositories: 返回数据
|
||||
variousRepositories-->>DashboardService: 返回统计结果
|
||||
DashboardService->>DashboardService: 聚合数据为DashboardStatsDTO
|
||||
DashboardService-->>DashboardController: 返回DashboardStatsDTO
|
||||
DashboardController-->>DecisionMaker: 返回核心统计数据
|
||||
end
|
||||
|
||||
alt 获取AQI分布
|
||||
DecisionMaker->>DashboardController: GET /api/dashboard/reports/aqi-distribution
|
||||
DashboardController->>DashboardService: getAqiDistribution()
|
||||
DashboardService->>variousRepositories: 查询AQI数据并分组统计
|
||||
variousRepositories->>Database: 查询AQI数据
|
||||
Database-->>variousRepositories: 返回数据
|
||||
variousRepositories-->>DashboardService: 返回统计结果
|
||||
DashboardService->>DashboardService: 转换为AqiDistributionDTO列表
|
||||
DashboardService-->>DashboardController: 返回List<AqiDistributionDTO>
|
||||
DashboardController-->>DecisionMaker: 返回AQI等级分布数据
|
||||
end
|
||||
|
||||
alt 获取热力图数据
|
||||
DecisionMaker->>DashboardController: GET /api/dashboard/map/heatmap
|
||||
DashboardController->>DashboardService: getHeatmapData()
|
||||
DashboardService->>variousRepositories: 查询反馈的地理位置数据
|
||||
variousRepositories->>Database: 查询地理位置数据
|
||||
Database-->>variousRepositories: 返回数据
|
||||
variousRepositories-->>DashboardService: 返回位置数据列表
|
||||
DashboardService->>DashboardService: 转换为HeatmapPointDTO列表
|
||||
DashboardService-->>DashboardController: 返回List<HeatmapPointDTO>
|
||||
DashboardController-->>DecisionMaker: 返回热力图数据
|
||||
end
|
||||
```
|
||||
|
||||
### 1.9 主管审核反馈
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Supervisor as 主管
|
||||
participant SupervisorController as 主管控制器
|
||||
participant SupervisorService as 主管服务
|
||||
participant FeedbackRepository as 反馈仓库
|
||||
participant Database as JSON持久化存储
|
||||
|
||||
alt 获取待审核列表
|
||||
Supervisor->>SupervisorController: GET /api/supervisor/reviews
|
||||
SupervisorController->>SupervisorService: getFeedbackForReview()
|
||||
SupervisorService->>FeedbackRepository: findByStatus(PENDING_REVIEW)
|
||||
FeedbackRepository->>Database: 查询待审核反馈
|
||||
Database-->>FeedbackRepository: 返回反馈列表
|
||||
FeedbackRepository-->>SupervisorService: 返回List<Feedback>
|
||||
SupervisorService-->>SupervisorController: 返回List<Feedback>
|
||||
SupervisorController-->>Supervisor: 显示待审核列表
|
||||
end
|
||||
|
||||
alt 批准反馈
|
||||
Supervisor->>SupervisorController: POST /api/supervisor/reviews/{feedbackId}/approve
|
||||
SupervisorController->>SupervisorService: approveFeedback(feedbackId)
|
||||
SupervisorService->>FeedbackRepository: findById(feedbackId)
|
||||
FeedbackRepository->>Database: 查询反馈
|
||||
Database-->>FeedbackRepository: 返回反馈
|
||||
FeedbackRepository-->>SupervisorService: 返回Feedback
|
||||
SupervisorService->>SupervisorService: 更新反馈状态为APPROVED
|
||||
SupervisorService->>FeedbackRepository: save(feedback)
|
||||
TaskRepository->>Database: 更新反馈状态
|
||||
Database-->>TaskRepository: 返回更新后的反馈
|
||||
TaskRepository-->>SupervisorService: 返回更新后的Feedback
|
||||
SupervisorService-->>SupervisorController: 返回成功响应
|
||||
SupervisorController-->>Supervisor: 操作成功
|
||||
end
|
||||
|
||||
alt 拒绝反馈
|
||||
Supervisor->>SupervisorController: POST /api/supervisor/reviews/{feedbackId}/reject
|
||||
SupervisorController->>SupervisorService: rejectFeedback(feedbackId, request)
|
||||
SupervisorService->>FeedbackRepository: findById(feedbackId)
|
||||
FeedbackRepository->>Database: 查询反馈
|
||||
Database-->>FeedbackRepository: 返回反馈
|
||||
FeedbackRepository-->>SupervisorService: 返回Feedback
|
||||
SupervisorService->>SupervisorService: 更新反馈状态为REJECTED并记录原因
|
||||
SupervisorService->>FeedbackRepository: save(feedback)
|
||||
TaskRepository->>Database: 更新反馈状态
|
||||
Database-->>TaskRepository: 返回更新后的反馈
|
||||
TaskRepository-->>SupervisorService: 返回更新后的Feedback
|
||||
SupervisorService-->>SupervisorController: 返回成功响应
|
||||
SupervisorController-->>Supervisor: 操作成功
|
||||
end
|
||||
```
|
||||
|
||||
### 1.10 路径规划 (A* 寻路算法)
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant PathfindingController as 寻路控制器
|
||||
participant AStarService as A*服务
|
||||
participant MapData as 地图数据
|
||||
|
||||
User->>+PathfindingController: POST /api/pathfinding/find (起点, 终点)
|
||||
PathfindingController->>+AStarService: findPath(start, end)
|
||||
AStarService->>+MapData: getObstacles()
|
||||
MapData-->>-AStarService: 返回障碍物信息
|
||||
AStarService->>AStarService: 执行A*算法计算路径
|
||||
AStarService-->>-PathfindingController: 返回计算出的路径
|
||||
PathfindingController-->>-User: 200 OK (路径坐标列表)
|
||||
```
|
||||
|
||||
### 1.11 公众提交反馈
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant FeedbackController as 反馈控制器
|
||||
participant FeedbackService as 反馈服务
|
||||
participant FeedbackRepository as 反馈仓库
|
||||
participant FileService as 文件服务
|
||||
participant Database as JSON持久化存储
|
||||
|
||||
User->>+FeedbackController: POST /api/feedback/submit (反馈信息, 附件)
|
||||
FeedbackController->>+FeedbackService: submitFeedback(request, files)
|
||||
alt 包含附件
|
||||
FeedbackService->>+FileService: store(files)
|
||||
FileService-->>-FeedbackService: 返回文件存储路径
|
||||
end
|
||||
FeedbackService->>+FeedbackRepository: save(feedback)
|
||||
FeedbackRepository->>+Database: INSERT INTO feedbacks
|
||||
Database-->>-FeedbackRepository: 返回已保存的反馈
|
||||
FeedbackRepository-->>-FeedbackService: 返回已保存的反馈
|
||||
FeedbackService-->>-FeedbackController: 返回创建的反馈
|
||||
FeedbackController-->>-User: 201 CREATED (反馈详情)
|
||||
```
|
||||
|
||||
### 1.12 文件下载/预览
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant FileController as 文件控制器
|
||||
participant FileStorageService as 文件存储服务
|
||||
participant FileSystem as 文件系统
|
||||
|
||||
User->>+FileController: GET /api/files/{filename} 或 /api/view/{filename}
|
||||
FileController->>+FileStorageService: loadFileAsResource(filename)
|
||||
FileStorageService->>+FileSystem: 读取文件
|
||||
FileSystem-->>-FileStorageService: 返回文件资源
|
||||
FileStorageService-->>-FileController: 返回文件资源
|
||||
FileController->>FileController: 设置HTTP响应头 (Content-Type, Content-Disposition)
|
||||
FileController-->>-User: 200 OK (文件内容)
|
||||
```
|
||||
|
||||
### 1.13 管理员分配网格员
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Admin as 管理员
|
||||
participant GridController as 网格控制器
|
||||
participant UserAccountService as 用户账户服务
|
||||
participant GridService as 网格服务
|
||||
participant OperationLogService as 操作日志服务
|
||||
participant Database as JSON持久化存储
|
||||
|
||||
Admin->>GridController: POST /api/grids/assign-worker (userId, gridId)
|
||||
activate GridController
|
||||
|
||||
GridController->>UserAccountService: getUserById(userId)
|
||||
activate UserAccountService
|
||||
UserAccountService->>Database: 查询用户
|
||||
Database-->>UserAccountService: 返回用户信息
|
||||
UserAccountService-->>GridController: 返回用户
|
||||
deactivate UserAccountService
|
||||
|
||||
alt 用户角色是网格员 (role == 'GRID_WORKER')
|
||||
GridController->>GridService: assignGridToUser(userId, gridId)
|
||||
activate GridService
|
||||
GridService->>Database: 更新用户的 grid_id
|
||||
Database-->>GridService: 更新成功
|
||||
GridService-->>GridController: 分配成功
|
||||
deactivate GridService
|
||||
|
||||
GridController->>OperationLogService: recordOperation(adminId, 'ASSIGN_GRID', '...details...')
|
||||
activate OperationLogService
|
||||
OperationLogService->>Database: 记录日志
|
||||
Database-->>OperationLogService: 记录成功
|
||||
OperationLogService-->>GridController: 记录完成
|
||||
deactivate OperationLogService
|
||||
|
||||
GridController-->>Admin: 200 OK - 分配成功
|
||||
else 用户角色不是网格员
|
||||
GridController-->>Admin: 400 Bad Request - 用户不是网格员
|
||||
end
|
||||
deactivate GridController
|
||||
```
|
||||
|
||||
### 1.14 初始化地图
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Admin as 管理员
|
||||
participant MapController as 地图控制器
|
||||
participant MapGridRepository as 地图网格仓库
|
||||
participant Database as JSON持久化存储
|
||||
|
||||
Admin->>+MapController: POST /api/map/initialize (width, height)
|
||||
MapController->>+MapGridRepository: deleteAll()
|
||||
MapGridRepository->>+Database: DELETE FROM map_grids
|
||||
Database-->>-MapGridRepository: 删除成功
|
||||
MapGridRepository-->>-MapController: 返回
|
||||
loop for y from 0 to height-1
|
||||
loop for x from 0 to width-1
|
||||
MapController->>+MapGridRepository: save(cell)
|
||||
MapGridRepository->>+Database: INSERT INTO map_grids
|
||||
Database-->>-MapGridRepository: 插入成功
|
||||
MapGridRepository-->>-MapController: 返回
|
||||
end
|
||||
end
|
||||
MapController-->>-Admin: 200 OK (Initialized a WxH map.)
|
||||
```
|
||||
|
||||
### 1.15 管理员获取操作日志
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Admin as 管理员
|
||||
participant OperationLogController as 操作日志控制器
|
||||
participant OperationLogService as 操作日志服务
|
||||
participant OperationLogRepository as 操作日志仓库
|
||||
```
|
||||
172
Report/目前内容.md
172
Report/目前内容.md
@@ -1,172 +0,0 @@
|
||||
# 1. 实践目的
|
||||
|
||||
## 1.1 项目概述与个人贡献
|
||||
|
||||
### 1.1.1 项目概述
|
||||
|
||||
本项目旨在解决传统环保监督渠道反馈不畅、处理流程不透明、以及公众参与度不高等痛点,开发一个高效、透明的**环保公众监督平台**。作为《东软环保应急》系统的重要子模块,它不仅是技术上的实现,更是业务流程上的一次重要创新。
|
||||
|
||||
系统的核心目标是打通从"问题发现"到"问题解决"的全链路。它通过提供便捷的移动端/网页端入口,鼓励公众随时随地上传图文并茂的环境问题反馈。系统接收到反馈后,将**自动触发一系列内部流程**:首先通过AI服务进行初步的智能分类与严重性评估;随后,经由主管人员审核确认后,反馈将**自动转化为一个结构化的处理任务**;最后,系统基于**智能分配算法**,综合考量网格员的实时位置、当前负载等因素,将任务精准派发给最优的执行者。整个过程的状态(待处理、执行中、已完成、已归档)对管理者和反馈者全程可见,极大地提升了环保工作的透明度与处理效率。
|
||||
|
||||
### 1.1.2 个人贡献
|
||||
|
||||
在本次实践中,本人担任**核心的系统设计与后端开发角色**,全面负责了从技术选型到项目落地的完整技术实现。我的工作不仅是代码的编写者,更是整个后端架构的**设计者**和**构建者**。具体贡献如下:
|
||||
|
||||
* **架构设计与技术决策**:在项目初期,我主导了技术栈的选型,力主采用`Spring Boot` + `Vue.js`的前后端分离架构,以应对未来快速迭代和功能扩展的需求。同时,我独立设计了后端**Controller-Service-Repository**的三层应用架构,并规划了项目的整体模块(如安全、事件、仓储等),为整个项目的稳固开发奠定了基础。
|
||||
|
||||
* **核心难题攻关**:面对"所有数据需以文件形式存储"这一核心且棘手的约束,我没有采取简单的文件读写,而是独立设计并实现了一套**模拟JPA规范的泛型JSON仓储层**。这个创新方案不仅完美地解决了数据持久化问题,其遵循的"依赖倒置原则"也使得代码高度解耦,极大地提升了系统的可维护性和可测试性,是本次项目中技术含量最高的突破之一。
|
||||
|
||||
* **全栈功能实现**:我负责了全部后端模块的编码实现,包括但不限于基于`Spring Security`和`JWT`的**用户认证与授权系统**、**任务全生命周期的状态机管理**、以及基于**A*算法的智能任务分配模型**等。此外,我也参与了部分前端页面的开发,并利用`Swagger`和`Postman`完成了所有API的设计、文档化与测试工作,确保了前后端的顺畅联调。
|
||||
|
||||
## 1.2 个人能力培养
|
||||
|
||||
通过本次实践,本人将软件工程理论与开发实践深度结合,在设计与开发复杂问题的解决方案方面获得了显著提升。
|
||||
|
||||
* **软件工程全周期掌控能力**:通过完整地参与从需求分析、系统设计、编码实现到测试部署的全过程,深刻掌握了现代软件开发的生命周期要素和方法。能够运用面向对象的思想,通过UML对系统进行建模,合理地划分模块,确保了系统设计的高内聚、低耦合。
|
||||
|
||||
* **复杂问题解决方案的设计与创新能力**:
|
||||
* 面对"数据以文件格式保存"的核心约束,没有采用简单的序列化读写,而是创新性地设计并实现了一套**基于JSON的泛型仓储层(Repository Pattern)**。该方案遵循了依赖倒置原则,不仅满足了功能要求,更保证了代码的可维护性与未来向数据库迁移的可行性。
|
||||
* 针对任务分配场景,设计了**基于多维因素(地理位置、负载)的智能调度算法**,并集成了**A*寻路算法**进行路径规划,展现了运用科学算法解决实际工程问题的能力。
|
||||
* 在系统中有效运用了**事件驱动模型**,将耗时的AI分析流程解耦为异步操作,提升了系统的响应速度和健壮性。
|
||||
|
||||
* **技术沟通与文档化能力**:能够通过撰写系统设计方案、绘制UML图表等方式,系统、清晰地阐述项目的技术架构与实现细节,并具备良好的口头技术交流能力。
|
||||
|
||||
# 2. 相关技术基础
|
||||
|
||||
本项目综合运用了业界主流的开发技术与环境,构建了一个现代化Web应用。整体技术体系由以下五部分构成:
|
||||
|
||||
* **理论基础**:遵循**面向对象编程(OOP)**、**SOLID设计原则(尤其是DIP)**、**MVC分层架构**及**RESTful API**设计规范。
|
||||
* **后端技术栈**:以 **`Spring Boot 3`** 为核心,整合 **`Spring Security`** 与 **`JWT`** 进行安全控制,并创新性地设计了**自定义的泛型JSON仓储层**作为持久化方案。
|
||||
* **前端技术栈**:采用 **`Vue 3`** 作为核心框架,配合 **`Vite`** 进行构建,使用 **`Pinia`** 进行状态管理,**`Element Plus`** 作为UI组件库,并对 **`Axios`** 进行了封装。
|
||||
* **测试技术**:后端采用 **`JUnit 5`** 和 **`Mockito`** 进行单元/集成测试;接口层使用 **`Swagger UI`** 和 **`Postman`** 进行测试与调试。
|
||||
* **开发工具与环境**:使用 **`IntelliJ IDEA`** 和 **`VS Code`** 作为主力IDE,通过 **`Maven`** 和 **`npm`** 管理项目,并利用 **`Git`** 进行版本控制。
|
||||
|
||||
以下是各部分的详细介绍。
|
||||
|
||||
## 2.1 理论基础
|
||||
|
||||
项目的架构和代码设计遵循了下述成熟的软件工程理论,以确保系统的可维护性和扩展性。
|
||||
|
||||
* **面向对象编程 (OOP):**
|
||||
项目的核心编程思想,其封装、继承、多态特性在后端代码设计中得到了深入应用。
|
||||
* **封装 (Encapsulation):** 核心业务实体(如`User`, `Task`)被抽象为Java类,其属性私有化,仅通过公共方法暴露,保证了对象状态的完整性。
|
||||
* **继承 (Inheritance) 与多态 (Polymorphism):** 在自定义的JSON仓储层设计中,通过定义泛型接口`JsonRepository<T, ID>`和实现该接口的泛型基类`JsonRepositoryImpl<T, ID>`,使得具体的实体仓储(如`JsonUserRepositoryImpl`)能自动获得通用的数据操作能力。业务逻辑层依赖于抽象接口而非具体实现,实现了"面向接口编程",提高了代码的灵活性。
|
||||
|
||||
* **SOLID设计原则,尤其是依赖倒置原则 (DIP):**
|
||||
项目架构遵循SOLID原则,特别是依赖倒置原则,即"高层模块不应依赖于低层模块,两者都应依赖于抽象"。
|
||||
* **实践应用:** `Service`层(高层模块)依赖的是`UserRepository`等抽象接口,而不是`JsonRepositoryImpl`这样的具体实现(低层模块)。这种设计倒置了传统的依赖关系,极大提升了系统的可替换性和可测试性。未来更换数据源或进行单元测试时,只需更换实现或模拟接口,上层代码无需改动。
|
||||
|
||||
* **模型-视图-控制器 (MVC) 分层架构:**
|
||||
项目遵循MVC分层思想,并扩展为更精细的四层架构:Controller -> Service -> Repository -> Entity。
|
||||
* **Controller (控制器层):** 作为HTTP请求的入口,负责解析请求参数,调用`Service`层执行业务逻辑,并返回响应。
|
||||
* **Service (业务逻辑层):** 包含所有业务规则和处理流程,通过依赖注入(DI)调用`Repository`层。
|
||||
* **Repository (数据访问层):** 数据持久化的抽象,负责与数据源(本项目中为JSON文件)交互,实现业务与数据的解耦。
|
||||
* **Entity/DTO (模型层):** POJO对象,`Entity`映射数据存储结构,`DTO`(Data Transfer Object)用于各层之间的数据传输,避免持久化实体直接暴露给外部。
|
||||
|
||||
* **RESTful API 设计原则:**
|
||||
前后端通信完全基于RESTful风格的API进行。
|
||||
* **统一接口 (Uniform Interface):** 使用HTTP标准方法(`GET`, `POST`, `PUT`, `DELETE`)表达对资源的操作。
|
||||
* **无状态 (Stateless):** 服务端不保存客户端会话状态,每次请求都包含所有必要信息(如JWT),提高了系统的可伸缩性。
|
||||
* **资源导向 (Resource-Oriented):** API围绕"资源"展开,使用名词(如`/api/users`)标识资源,而非动词。
|
||||
|
||||
## 2.2 后端技术栈
|
||||
|
||||
* **核心框架 - `Spring Boot 3.x`:**
|
||||
作为后端应用基石,它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发、配置和部署。其强大的生态整合能力,使得集成`Spring Security`、`Lombok`、`Swagger`等第三方库变得非常简单。
|
||||
|
||||
* **安全框架 - `Spring Security 6.x` & `JWT`:**
|
||||
采用`Spring Security`结合`JSON Web Tokens (JWT)`,构建无状态的认证与授权体系。
|
||||
* **`Spring Security` Filter链:** 自定义`JwtAuthenticationFilter`过滤器,用于在每个请求中校验JWT并设置安全上下文。
|
||||
* **声明式权限控制:** 使用`@PreAuthorize`注解对Service方法进行方法级别的权限声明,实现了安全逻辑与业务逻辑的解耦。
|
||||
* **无状态会话 (Stateless Session):** 配置会话管理策略为`STATELESS`,使后端服务成为真正的无状态服务,提升了系统的可伸缩性。
|
||||
|
||||
* **持久化方案 - 自定义泛型JSON仓储层:**
|
||||
为满足"数据存储在JSON文件中"的需求,设计并实现了一套模拟`Spring Data JPA`接口规范的、可复用的泛型JSON仓储层。
|
||||
* **`JsonStorageService`:** 将所有文件I/O操作封装在此服务中,并使用`synchronized`块确保并发写操作的线程安全。
|
||||
* **`JsonRepositoryImpl<T, ID>`:** 泛型基类,实现了通用的CRUD功能,具体的实体仓储通过继承该类来复用代码。
|
||||
* 该方案遵循**依赖倒置原则**,业务层仅依赖抽象接口,为未来平滑迁移持久化方案提供了便利。
|
||||
|
||||
* **数据校验 - `Jakarta Bean Validation` (`Hibernate Validator`):**
|
||||
在DTO的字段上使用`@NotNull`, `@Size`等声明式注解,并配合Controller层的`@Valid`注解,实现对请求参数的自动化校验。
|
||||
|
||||
* **对象映射 - `MapStruct`:**
|
||||
一个编译期的代码生成器,通过定义`@Mapper`接口,自动生成Entity与DTO之间转换的高性能实现代码,提升了开发效率。
|
||||
|
||||
* **编程语言与辅助工具:**
|
||||
* **`Java 17 (LTS)`:** 使用其`record`、`switch`表达式等新特性编写更简洁的代码。
|
||||
* **`Lombok`:** 通过`@Data`, `@Builder`等注解,消除样板代码。
|
||||
* **`SLF4J` & `Logback`:** 灵活的日志系统,通过配置文件实现分环境、分级别的日志输出。
|
||||
|
||||
## 2.3 前端技术栈
|
||||
|
||||
采用`Vue.js`生态的最新技术,构建响应迅速、代码可维护的现代化单页应用(SPA)。
|
||||
|
||||
* **核心框架 - `Vue.js 3.x`:**
|
||||
利用其两大核心新特性:
|
||||
* **`Composition API` (组合式API):** 将相关逻辑组织在同一个`setup`函数内,提高了代码的可读性、可维护性和逻辑复用性。
|
||||
* **`Proxy`-based Reactivity:** 基于`Proxy`重写的响应式系统,解决了`Vue 2`中无法监听对象属性新增/删除等痛点。
|
||||
|
||||
* **构建工具 - `Vite`:**
|
||||
新一代前端构建工具,优势在于:
|
||||
* 利用浏览器原生ESM支持,实现开发环境下的极速冷启动和闪电般的热模块替换(HMR)。
|
||||
* 生产环境使用`Rollup`打包,生成高度优化的静态资源。
|
||||
|
||||
* **状态管理 - `Pinia`:**
|
||||
`Vue`官方推荐的下一代状态管理库,特点是API直观、类型支持完美,且天生模块化。废除了`Vuex`中复杂的`Mutations`等概念,心智负担小。
|
||||
|
||||
* **UI组件库 - `Element Plus`:**
|
||||
`Element UI`的`Vue 3`版本,是一套高质量的企业级UI组件库,提供了丰富的组件,极大地加速了界面的开发进程。
|
||||
|
||||
* **HTTP客户端 - `Axios`封装:**
|
||||
对流行的`Axios`库进行二次封装:
|
||||
* **创建实例:** 为API服务设置不同的`baseURL`、`timeout`等。
|
||||
* **请求拦截器:** 统一添加认证`token`。
|
||||
* **响应拦截器:** 统一处理业务数据和错误状态码。
|
||||
|
||||
## 2.4 测试技术
|
||||
|
||||
* **后端单元与集成测试 (`JUnit 5`, `Mockito`, `Spring Boot Test`):**
|
||||
使用`spring-boot-starter-test`集成的测试套件保障业务逻辑正确性。
|
||||
* **`JUnit 5`:** 测试的基础框架。
|
||||
* **`Mockito`:** 在单元测试中用于模拟依赖对象(如Repository),实现测试隔离。
|
||||
* **`Spring Boot Test`:** 用于集成测试,加载完整应用上下文,测试跨层级的真实交互场景。
|
||||
|
||||
* **API接口测试 (`Postman` / `Swagger UI`):**
|
||||
* **`Swagger UI`:** 通过集成`SpringDoc`,根据代码注解自动生成交互式API文档,方便调试。
|
||||
* **`Postman`:** 用于执行更复杂的API测试场景、编写测试用例和自动化测试。
|
||||
|
||||
## 2.5 开发工具与环境
|
||||
|
||||
* **IDE:** 后端使用`IntelliJ IDEA Ultimate`,前端使用`Visual Studio Code`。
|
||||
* **项目管理与构建:** 后端使用`Maven`,前端使用`npm`。
|
||||
* **版本控制:** `Git` & `GitHub`,遵循`Git Flow`工作流。
|
||||
|
||||
# 3. 实践结果
|
||||
|
||||
此部分属报告的主要部分。包括:
|
||||
|
||||
## 3.1 需求定义
|
||||
|
||||
"系统分析"也可以看成是需求定义,包括对整个项目的介绍分析及本人工作内容的详细分析,如业务分析、功能分析(可使用例图、活动图来描述)、可行性分析等;
|
||||
|
||||
## 3.2 系统设计
|
||||
|
||||
"系统设计"包括总体设计和详细设计,"总体设计"包括系统架构设计、功能模块划分等,"详细设计"要围绕本人工作内容展开,包括功能模块详细设计、类和对象的设计、动态模型设计(时序图、状态图、协作图等)、算法设计、数据库设计等;
|
||||
|
||||
## 3.3 系统实现
|
||||
|
||||
"系统实现"也要围绕本人工作内容展开,从编码实现角度论述相应功能模块的实现细节,并展示自己所完成的主要成果及实际应用情况等。可通过"程序流程图"、"关键代码"和"界面"进行直观论述。
|
||||
|
||||
## 3.4 系统测试
|
||||
|
||||
"系统测试"包括测试方案设计、测试用例和测试结果、最终的测试结论或评价等。
|
||||
|
||||
# 4. 实践总结
|
||||
|
||||
简述你在实践过程中的内容完成情况,重点介绍创新点及不足(也就是可以再完善的部分,只是时间不允许了。不足不代表不好,也说明你思考了,但是来不及完成实现)
|
||||
|
||||
# 5. 参考资料
|
||||
|
||||
例:
|
||||
[1] 数据结构、算法与应用:C++语言描述 [Data Structures,Algorithms,and Applications in C++][M].机械工业出版社出版时间:2000-01-01.
|
||||
[2] 数据结构(C语言版) [M].北京: 中国铁道出版社, 2011-08-01.
|
||||
101
Report/相关技术基础.md
101
Report/相关技术基础.md
@@ -1,101 +0,0 @@
|
||||
# 1. 相关技术基础
|
||||
|
||||
本项目综合运用了业界主流的开发技术与环境,构建了一个现代化Web应用。以下是项目所涉及的关键技术、开发工具和环境的介绍。
|
||||
|
||||
### 1.1 理论基础
|
||||
|
||||
项目的架构和代码设计遵循了下述成熟的软件工程理论,以确保系统的可维护性和扩展性。
|
||||
|
||||
* **面向对象编程 (OOP):**
|
||||
项目的核心编程思想,其封装、继承、多态特性在后端代码设计中得到了深入应用。
|
||||
* **封装 (Encapsulation):** 核心业务实体(如`User`, `Task`)被抽象为Java类,其属性私有化,仅通过公共方法暴露,保证了对象状态的完整性。
|
||||
* **继承 (Inheritance) 与多态 (Polymorphism):** 在自定义的JSON仓储层设计中,通过定义泛型接口`JsonRepository<T, ID>`和实现该接口的泛型基类`JsonRepositoryImpl<T, ID>`,使得具体的实体仓储(如`JsonUserRepositoryImpl`)能自动获得通用的数据操作能力。业务逻辑层依赖于抽象接口而非具体实现,实现了"面向接口编程",提高了代码的灵活性。
|
||||
|
||||
* **SOLID设计原则,尤其是依赖倒置原则 (DIP):**
|
||||
项目架构遵循SOLID原则,特别是依赖倒置原则,即"高层模块不应依赖于低层模块,两者都应依赖于抽象"。
|
||||
* **实践应用:** `Service`层(高层模块)依赖的是`UserRepository`等抽象接口,而不是`JsonRepositoryImpl`这样的具体实现(低层模块)。这种设计倒置了传统的依赖关系,极大提升了系统的可替换性和可测试性。未来更换数据源或进行单元测试时,只需更换实现或模拟接口,上层代码无需改动。
|
||||
|
||||
* **模型-视图-控制器 (MVC) 分层架构:**
|
||||
项目遵循MVC分层思想,并扩展为更精细的四层架构:Controller -> Service -> Repository -> Entity。
|
||||
* **Controller (控制器层):** 作为HTTP请求的入口,负责解析请求参数,调用`Service`层执行业务逻辑,并返回响应。
|
||||
* **Service (业务逻辑层):** 包含所有业务规则和处理流程,通过依赖注入(DI)调用`Repository`层。
|
||||
* **Repository (数据访问层):** 数据持久化的抽象,负责与数据源(本项目中为JSON文件)交互,实现业务与数据的解耦。
|
||||
* **Entity/DTO (模型层):** POJO对象,`Entity`映射数据存储结构,`DTO`(Data Transfer Object)用于各层之间的数据传输,避免持久化实体直接暴露给外部。
|
||||
|
||||
* **RESTful API 设计原则:**
|
||||
前后端通信完全基于RESTful风格的API进行。
|
||||
* **统一接口 (Uniform Interface):** 使用HTTP标准方法(`GET`, `POST`, `PUT`, `DELETE`)表达对资源的操作。
|
||||
* **无状态 (Stateless):** 服务端不保存客户端会话状态,每次请求都包含所有必要信息(如JWT),提高了系统的可伸缩性。
|
||||
* **资源导向 (Resource-Oriented):** API围绕"资源"展开,使用名词(如`/api/users`)标识资源,而非动词。
|
||||
|
||||
### 1.2 后端技术栈
|
||||
|
||||
* **核心框架 - `Spring Boot 3.x`:**
|
||||
作为后端应用基石,它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发、配置和部署。其强大的生态整合能力,使得集成`Spring Security`、`Lombok`、`Swagger`等第三方库变得非常简单。
|
||||
|
||||
* **安全框架 - `Spring Security 6.x` & `JWT`:**
|
||||
采用`Spring Security`结合`JSON Web Tokens (JWT)`,构建无状态的认证与授权体系。
|
||||
* **`Spring Security` Filter链:** 自定义`JwtAuthenticationFilter`过滤器,用于在每个请求中校验JWT并设置安全上下文。
|
||||
* **声明式权限控制:** 使用`@PreAuthorize`注解对Service方法进行方法级别的权限声明,实现了安全逻辑与业务逻辑的解耦。
|
||||
* **无状态会话 (Stateless Session):** 配置会话管理策略为`STATELESS`,使后端服务成为真正的无状态服务,提升了系统的可伸缩性。
|
||||
|
||||
* **持久化方案 - 自定义泛型JSON仓储层:**
|
||||
为满足"数据存储在JSON文件中"的需求,设计并实现了一套模拟`Spring Data JPA`接口规范的、可复用的泛型JSON仓储层。
|
||||
* **`JsonStorageService`:** 将所有文件I/O操作封装在此服务中,并使用`synchronized`块确保并发写操作的线程安全。
|
||||
* **`JsonRepositoryImpl<T, ID>`:** 泛型基类,实现了通用的CRUD功能,具体的实体仓储通过继承该类来复用代码。
|
||||
* 该方案遵循**依赖倒置原则**,业务层仅依赖抽象接口,为未来平滑迁移持久化方案提供了便利。
|
||||
|
||||
* **数据校验 - `Jakarta Bean Validation` (`Hibernate Validator`):**
|
||||
在DTO的字段上使用`@NotNull`, `@Size`等声明式注解,并配合Controller层的`@Valid`注解,实现对请求参数的自动化校验。
|
||||
|
||||
* **对象映射 - `MapStruct`:**
|
||||
一个编译期的代码生成器,通过定义`@Mapper`接口,自动生成Entity与DTO之间转换的高性能实现代码,提升了开发效率。
|
||||
|
||||
* **编程语言与辅助工具:**
|
||||
* **`Java 17 (LTS)`:** 使用其`record`、`switch`表达式等新特性编写更简洁的代码。
|
||||
* **`Lombok`:** 通过`@Data`, `@Builder`等注解,消除样板代码。
|
||||
* **`SLF4J` & `Logback`:** 灵活的日志系统,通过配置文件实现分环境、分级别的日志输出。
|
||||
|
||||
### 1.3 前端技术栈
|
||||
|
||||
采用`Vue.js`生态的最新技术,构建响应迅速、代码可维护的现代化单页应用(SPA)。
|
||||
|
||||
* **核心框架 - `Vue.js 3.x`:**
|
||||
利用其两大核心新特性:
|
||||
* **`Composition API` (组合式API):** 将相关逻辑组织在同一个`setup`函数内,提高了代码的可读性、可维护性和逻辑复用性。
|
||||
* **`Proxy`-based Reactivity:** 基于`Proxy`重写的响应式系统,解决了`Vue 2`中无法监听对象属性新增/删除等痛点。
|
||||
|
||||
* **构建工具 - `Vite`:**
|
||||
新一代前端构建工具,优势在于:
|
||||
* 利用浏览器原生ESM支持,实现开发环境下的极速冷启动和闪电般的热模块替换(HMR)。
|
||||
* 生产环境使用`Rollup`打包,生成高度优化的静态资源。
|
||||
|
||||
* **状态管理 - `Pinia`:**
|
||||
`Vue`官方推荐的下一代状态管理库,特点是API直观、类型支持完美,且天生模块化。废除了`Vuex`中复杂的`Mutations`等概念,心智负担小。
|
||||
|
||||
* **UI组件库 - `Element Plus`:**
|
||||
`Element UI`的`Vue 3`版本,是一套高质量的企业级UI组件库,提供了丰富的组件,极大地加速了界面的开发进程。
|
||||
|
||||
* **HTTP客户端 - `Axios`封装:**
|
||||
对流行的`Axios`库进行二次封装:
|
||||
* **创建实例:** 为API服务设置不同的`baseURL`、`timeout`等。
|
||||
* **请求拦截器:** 统一添加认证`token`。
|
||||
* **响应拦截器:** 统一处理业务数据和错误状态码。
|
||||
|
||||
### 1.4 测试技术
|
||||
|
||||
* **后端单元与集成测试 (`JUnit 5`, `Mockito`, `Spring Boot Test`):**
|
||||
使用`spring-boot-starter-test`集成的测试套件保障业务逻辑正确性。
|
||||
* **`JUnit 5`:** 测试的基础框架。
|
||||
* **`Mockito`:** 在单元测试中用于模拟依赖对象(如Repository),实现测试隔离。
|
||||
* **`Spring Boot Test`:** 用于集成测试,加载完整应用上下文,测试跨层级的真实交互场景。
|
||||
|
||||
* **API接口测试 (`Postman` / `Swagger UI`):**
|
||||
* **`Swagger UI`:** 通过集成`SpringDoc`,根据代码注解自动生成交互式API文档,方便调试。
|
||||
* **`Postman`:** 用于执行更复杂的API测试场景、编写测试用例和自动化测试。
|
||||
|
||||
### 1.5 开发工具与环境
|
||||
|
||||
* **IDE:** 后端使用`IntelliJ IDEA Ultimate`,前端使用`Visual Studio Code`。
|
||||
* **项目管理与构建:** 后端使用`Maven`,前端使用`npm`。
|
||||
* **版本控制:** `Git` & `GitHub`,遵循`Git Flow`工作流。
|
||||
195
Report/系统实现.md
195
Report/系统实现.md
@@ -1,195 +0,0 @@
|
||||
# 3.3 系统实现
|
||||
|
||||
本章节详细阐述了环境监督系统(EMS)的实际编码实现过程,展示了如何将系统设计转化为可运行的代码。由于内容较多,为了便于阅读和维护,本章节分为以下三个部分:
|
||||
|
||||
## 文档目录
|
||||
|
||||
1. [开发环境与技术栈 & 核心功能模块实现(上)](系统实现_第一部分.md)
|
||||
- 开发环境与技术栈
|
||||
- 泛型JSON存储服务
|
||||
- A*寻路算法实现
|
||||
|
||||
2. [核心功能模块实现(中)](系统实现_第二部分.md)
|
||||
- A*寻路算法实现要点分析
|
||||
- 反馈管理模块实现
|
||||
|
||||
3. [核心功能模块实现(下) & 界面展示与成果展示](系统实现_第三部分.md)
|
||||
- 任务智能分配算法
|
||||
- 界面展示与成果展示
|
||||
- 实现成果总结
|
||||
|
||||
请点击上述链接查看各部分的详细内容。
|
||||
|
||||
## 3.3.1 后端关键技术实现
|
||||
|
||||
### 1. 核心数据服务:泛型JSON仓储
|
||||
|
||||
为了实现一个可复用、类型安全且与业务逻辑完全解耦的数据持久化层,我设计并实现了一个泛型的`JsonStorageService`。这是整个后端数据访问的基石,是实现仓储模式(Repository Pattern)的关键底层支持。
|
||||
|
||||
```java:ems-backend/src/main/java/com/dne/ems/service/JsonStorageService.java
|
||||
@Service
|
||||
public class JsonStorageService {
|
||||
|
||||
private static final Path STORAGE_DIRECTORY = Paths.get("json-db");
|
||||
private final ObjectMapper objectMapper; // Jackson的核心,用于JSON序列化和反序列化
|
||||
|
||||
// 使用构造函数注入,符合Spring推荐的最佳实践
|
||||
public JsonStorageService(ObjectMapper objectMapper) {
|
||||
this.objectMapper = objectMapper;
|
||||
// 在服务启动时,检查并创建存储目录,保证后续操作的顺利进行
|
||||
try {
|
||||
if (!Files.exists(STORAGE_DIRECTORY)) {
|
||||
Files.createDirectories(STORAGE_DIRECTORY);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// 如果目录创建失败,则抛出运行时异常,使应用启动失败,防止后续出现更严重问题
|
||||
throw new UncheckedIOException("Could not create storage directory", e);
|
||||
}
|
||||
}
|
||||
|
||||
// 同步写数据方法,保证线程安全
|
||||
public synchronized <T> void writeData(String fileName, List<T> data) {
|
||||
try {
|
||||
Path filePath = STORAGE_DIRECTORY.resolve(fileName);
|
||||
// 使用writeValueAsString先转为格式化的JSON字符串,再写入文件,提高可读性
|
||||
String jsonContent = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(data);
|
||||
Files.write(filePath, jsonContent.getBytes(StandardCharsets.UTF_8));
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Error writing data to " + fileName, e);
|
||||
}
|
||||
}
|
||||
|
||||
// 读数据方法
|
||||
public <T> List<T> readData(String fileName, TypeReference<List<T>> typeReference) {
|
||||
Path filePath = STORAGE_DIRECTORY.resolve(fileName);
|
||||
if (!Files.exists(filePath)) {
|
||||
return new ArrayList<>(); // 文件不存在是正常情况,返回空列表
|
||||
}
|
||||
try {
|
||||
// 使用TypeReference来处理泛型擦除问题,确保JSON能被正确反序列化为List<T>
|
||||
return objectMapper.readValue(filePath.toFile(), typeReference);
|
||||
} catch (IOException e) {
|
||||
// 如果文件为空或JSON格式损坏,记录日志并返回空列表,增强系统容错性
|
||||
log.warn("Could not read or parse file: {}. Returning empty list.", fileName, e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**设计深度解析:**
|
||||
* **泛型与类型安全:** `writeData`和`readData`方法都使用了泛型`<T>`,使得该服务可以处理任何类型的实体列表(如`List<User>`、`List<Task>`)。通过传入`TypeReference<List<T>>`,我们解决了Java泛型在运行时被擦除的问题,使得Jackson库能够准确地将JSON数组反序列化为指定类型的对象列表,保证了类型安全。
|
||||
* **线程安全与并发控制:** `writeData`方法被声明为`synchronized`,这是一个简单而有效的并发控制手段。它利用对象锁确保了在多线程环境下对同一文件的写操作是互斥的、串行的,从而从根本上防止了数据竞争和文件损坏的风险。
|
||||
* **健壮性与容错:** 代码对存储目录不存在、文件读写IO异常、JSON解析异常等情况都进行了处理。特别是当文件不存在或内容为空/损坏时,`readData`会返回一个空列表而不是抛出异常,这使得上层调用者(Repository)无需处理这些繁琐的底层细节,增强了系统的整体健-壮性。
|
||||
|
||||
### 2. 安全核心:JWT生成与校验
|
||||
|
||||
系统的认证和授权机制基于JWT(JSON Web Token)。我实现了一个`JwtTokenProvider`来封装JWT的生成和校验逻辑,使其与业务代码分离。
|
||||
|
||||
```java:ems-backend/src/main/java/com/dne/ems/security/JwtTokenProvider.java
|
||||
@Component
|
||||
public class JwtTokenProvider {
|
||||
|
||||
@Value("${app.jwtSecret}")
|
||||
private String jwtSecret;
|
||||
|
||||
@Value("${app.jwtExpirationInMs}")
|
||||
private int jwtExpirationInMs;
|
||||
|
||||
// 根据用户信息生成JWT
|
||||
public String generateToken(Authentication authentication) {
|
||||
UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal();
|
||||
Date now = new Date();
|
||||
Date expiryDate = new Date(now.getTime() + jwtExpirationInMs);
|
||||
|
||||
return Jwts.builder()
|
||||
.setSubject(Long.toString(userPrincipal.getId()))
|
||||
.claim("role", userPrincipal.getAuthorities().iterator().next().getAuthority())
|
||||
.setIssuedAt(new Date())
|
||||
.setExpiration(expiryDate)
|
||||
.signWith(SignatureAlgorithm.HS512, jwtSecret)
|
||||
.compact();
|
||||
}
|
||||
|
||||
// 从JWT中解析用户ID
|
||||
public Long getUserIdFromJWT(String token) {
|
||||
Claims claims = Jwts.parser()
|
||||
.setSigningKey(jwtSecret)
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
return Long.parseLong(claims.getSubject());
|
||||
}
|
||||
|
||||
// 校验JWT的有效性
|
||||
public boolean validateToken(String authToken) {
|
||||
try {
|
||||
Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);
|
||||
return true;
|
||||
} catch (SignatureException | MalformedJwtException | ExpiredJwtException | UnsupportedJwtException | IllegalArgumentException ex) {
|
||||
// 捕获所有可能的JWT校验异常
|
||||
log.error("Invalid JWT token: {}", ex.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**实现说明:**
|
||||
* **配置化:** JWT的密钥(`jwtSecret`)和过期时间(`jwtExpirationInMs`)都通过`@Value`注解从`application.properties`配置文件中读取,便于不同环境的部署和管理。
|
||||
* **声明(Claims):** 在生成Token时,我不仅将用户ID作为`subject`,还将用户的角色(Role)作为一个自定义的`claim`存入Token中。这样做的好处是,在后续的授权判断中,我们无需再次查询数据库,直接从Token中即可获取用户角色,提高了性能。
|
||||
* **全面的异常处理:** `validateToken`方法捕获了`jjwt`库可能抛出的所有校验异常,如签名错误、格式错误、Token过期等,并记录日志,保证了校验逻辑的严谨性。
|
||||
|
||||
### 3. 统一出口:全局异常处理器
|
||||
|
||||
为了提供统一、规范的API错误响应格式,我实现了一个全局异常处理器。这避免了在每个Controller方法中都写`try-catch`块的冗余代码。
|
||||
|
||||
```java:ems-backend/src/main/java/com/dne/ems/exception/GlobalExceptionHandler.java
|
||||
@ControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
@ExceptionHandler(value = {IllegalArgumentException.class, IllegalStateException.class})
|
||||
public ResponseEntity<ApiResponse> handleBadRequest(RuntimeException ex, WebRequest request) {
|
||||
ApiResponse apiResponse = new ApiResponse(false, ex.getMessage());
|
||||
return new ResponseEntity<>(apiResponse, HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = ResourceNotFoundException.class)
|
||||
public ResponseEntity<ApiResponse> handleResourceNotFound(ResourceNotFoundException ex, WebRequest request) {
|
||||
ApiResponse apiResponse = new ApiResponse(false, ex.getMessage());
|
||||
return new ResponseEntity<>(apiResponse, HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = Exception.class)
|
||||
public ResponseEntity<ApiResponse> handleGlobalException(Exception ex, WebRequest request) {
|
||||
log.error("An unexpected error occurred: ", ex);
|
||||
ApiResponse apiResponse = new ApiResponse(false, "An internal server error occurred. Please try again later.");
|
||||
return new ResponseEntity<>(apiResponse, HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**实现说明:**
|
||||
* **`@ControllerAdvice`:** 该注解使得这个类可以成为一个全局的AOP切面,用于处理所有`@Controller`中抛出的异常。
|
||||
* **`@ExceptionHandler`:** 针对不同类型的异常(如参数错误、资源未找到、未知异常),定义了不同的处理方法,返回相应的HTTP状态码和统一格式的JSON错误信息(`ApiResponse`对象),极大地改善了API的友好性和可调试性。
|
||||
|
||||
## 3.3.2 前端界面实现与展示
|
||||
|
||||
我独立负责了大部分前端界面的开发,采用了`Vue 3` + `Vite` + `Pinia` + `Element Plus`这一现代化的技术栈,实现了数据驱动的、组件化的、响应式的用户界面。
|
||||
|
||||
* **组件化开发:** 我将UI拆分为多个可复用的组件,如`TaskCard.vue`, `FeedbackList.vue`, `UserSelector.vue`等,提高了代码的可维护性和开发效率。
|
||||
* **状态管理:** 使用`Pinia`作为全局状态管理器,集中管理用户的登录信息、角色、权限以及全局的加载状态等,使得跨组件的状态共享变得简单、可预测。
|
||||
* **API交互:** 封装了`axios`实例,添加了请求和响应拦截器。请求拦截器负责在每个请求头中自动附加JWT;响应拦截器负责处理全局的API错误,如`401 Unauthorized`(自动跳转到登录页)、`500 Internal Server Error`(弹出统一的错误提示)。
|
||||
|
||||
以下是系统核心页面的UI设计与功能描述:
|
||||
|
||||
**1. 主管工作台 - 任务分配页面**
|
||||
|
||||
* **界面截图描述:** 页面左侧是一个可滚动、可搜索的"待处理反馈"列表,每项都清晰地展示了反馈的标题、提交时间和关键内容摘要。点击某一项后,右侧会显示该反馈的完整详情。详情下方是一个"指派网格员"的下拉选择框,其中列出了所有状态正常的网格员。选择网格员后,点击"立即分配"按钮,系统会弹出确认对话框,确认后完成任务的创建和分配,并给出成功提示。
|
||||
|
||||
**2. 网格员工作台 - 任务处理页面**
|
||||
|
||||
* **界面截图描述:** 页面顶部是任务的核心信息卡片,包括任务标题、描述、截止日期和当前状态。下方是一个多标签页的表单区域。第一个标签页是"数据录入",包含了多个根据任务类型动态生成的表单项(如空气质量指数、噪声分贝、垃圾分类情况等)。第二个标签页是"现场照片",提供了一个支持拖拽和点击上传的图片上传组件,并能实时显示缩略图。所有信息填写完毕后,点击底部的"完成任务"按钮提交数据。
|
||||
|
||||
**3. 数据决策看板 (Dashboard)**
|
||||
|
||||
* **界面截图描述:** 这是一个信息密集型的仪表盘页面。顶部是四个醒目的KPI卡片,分别显示"本月任务总数"、"已完成率"、"平均处理时长"和"待处理反馈数"。下方是一个占据主要区域的地图组件,地图上用不同颜色的标记点展示了各个网格区域的问题分布和严重程度。地图右侧是两个图表:一个是"近30天任务趋势"的折线图,另一个是"问题类型分布"的饼图。所有图表都是动态的,并支持按时间范围进行筛选。
|
||||
@@ -1,217 +0,0 @@
|
||||
# 3.3 系统实现
|
||||
|
||||
## 3.3.1 开发环境与技术栈
|
||||
|
||||
在本项目的开发过程中,我采用了现代化、高效且广泛应用于企业级开发的技术栈组合,确保系统的稳定性、可扩展性和维护性。
|
||||
|
||||
### 后端技术栈
|
||||
|
||||
- **编程语言**: Java 17
|
||||
- **框架**: Spring Boot 3.1.5
|
||||
- **API文档**: Springdoc OpenAPI (Swagger)
|
||||
- **安全框架**: Spring Security + JWT
|
||||
- **构建工具**: Maven 3.9
|
||||
- **数据存储**: 自定义JSON文件存储(模拟数据库)
|
||||
- **异步处理**: Spring Events
|
||||
- **日志框架**: SLF4J + Logback
|
||||
- **单元测试**: JUnit 5 + Mockito
|
||||
|
||||
### 前端技术栈
|
||||
|
||||
- **框架**: Vue 3 (Composition API)
|
||||
- **构建工具**: Vite
|
||||
- **UI组件库**: Element Plus
|
||||
- **状态管理**: Pinia
|
||||
- **路由**: Vue Router
|
||||
- **HTTP客户端**: Axios
|
||||
- **CSS预处理器**: SCSS
|
||||
- **图表库**: ECharts
|
||||
|
||||
### 开发工具
|
||||
|
||||
- **IDE**: IntelliJ IDEA / VS Code
|
||||
- **版本控制**: Git
|
||||
- **API测试**: Postman
|
||||
- **代码质量**: SonarLint
|
||||
- **调试工具**: Chrome DevTools
|
||||
|
||||
## 3.3.2 核心功能模块实现
|
||||
|
||||
在系统设计阶段,我们已经详细规划了各个功能模块。在实现阶段,我负责了多个核心模块的编码工作,下面将详细介绍这些模块的实现细节。
|
||||
|
||||
### 1. 泛型JSON存储服务
|
||||
|
||||
在本项目中,我设计并实现了一个创新的数据持久化解决方案,使用JSON文件代替传统数据库进行数据存储。这种方案简化了系统部署,同时提供了类似于JPA的操作接口,使得业务层代码无需关心底层存储细节。
|
||||
|
||||
**关键代码展示**:
|
||||
|
||||
```java
|
||||
@Service
|
||||
public class JsonStorageService {
|
||||
|
||||
private static final Path STORAGE_DIRECTORY = Paths.get("json-db");
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
public JsonStorageService(ObjectMapper objectMapper) {
|
||||
this.objectMapper = objectMapper;
|
||||
try {
|
||||
if (!Files.exists(STORAGE_DIRECTORY)) {
|
||||
Files.createDirectories(STORAGE_DIRECTORY);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("无法创建存储目录", e);
|
||||
}
|
||||
}
|
||||
|
||||
// 同步写数据方法,保证线程安全
|
||||
public synchronized <T> void writeData(String fileName, List<T> data) {
|
||||
try {
|
||||
Path filePath = STORAGE_DIRECTORY.resolve(fileName);
|
||||
// 使用writeValueAsString先转为格式化的JSON字符串,再写入文件,提高可读性
|
||||
String jsonContent = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(data);
|
||||
Files.write(filePath, jsonContent.getBytes(StandardCharsets.UTF_8));
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("写入数据到 " + fileName + " 时出错", e);
|
||||
}
|
||||
}
|
||||
|
||||
// 读数据方法
|
||||
public <T> List<T> readData(String fileName, TypeReference<List<T>> typeReference) {
|
||||
Path filePath = STORAGE_DIRECTORY.resolve(fileName);
|
||||
if (!Files.exists(filePath)) {
|
||||
return new ArrayList<>(); // 文件不存在是正常情况,返回空列表
|
||||
}
|
||||
try {
|
||||
// 使用TypeReference来处理泛型擦除问题,确保JSON能被正确反序列化为List<T>
|
||||
return objectMapper.readValue(filePath.toFile(), typeReference);
|
||||
} catch (IOException e) {
|
||||
log.warn("无法读取或解析文件: {}. 返回空列表。", fileName, e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**实现要点分析**:
|
||||
|
||||
1. **泛型设计**: 通过Java泛型和TypeReference,实现了类型安全的数据读写,支持任意模型类。
|
||||
2. **线程安全**: 使用synchronized关键字确保写操作的线程安全,防止并发写入导致的数据损坏。
|
||||
3. **容错处理**: 对文件不存在、IO异常等情况进行了妥善处理,增强了系统的健壮性。
|
||||
4. **格式化输出**: 使用Jackson的prettyPrinter功能,使生成的JSON文件具有良好的可读性,便于调试。
|
||||
|
||||
**程序流程图**:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[开始] --> B{文件存在?}
|
||||
B -->|是| C[读取文件内容]
|
||||
B -->|否| D[返回空列表]
|
||||
C --> E{解析JSON成功?}
|
||||
E -->|是| F[返回对象列表]
|
||||
E -->|否| G[记录警告日志]
|
||||
G --> D
|
||||
```
|
||||
|
||||
### 2. A*寻路算法实现
|
||||
|
||||
在网格与地图模块中,我实现了A*寻路算法,为网格员提供从当前位置到任务地点的最优路径规划。该算法考虑了地图障碍物,能够高效地找到最短路径。
|
||||
|
||||
**关键代码展示**:
|
||||
|
||||
```java
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AStarService {
|
||||
|
||||
private final MapGridRepository mapGridRepository;
|
||||
|
||||
// 内部Node类,用于A*算法的节点表示
|
||||
private static class Node {
|
||||
Point point;
|
||||
int g; // 从起点到当前节点的实际代价
|
||||
int h; // 启发式:从当前节点到终点的估计代价
|
||||
int f; // g + h
|
||||
Node parent;
|
||||
|
||||
public Node(Point point, Node parent, int g, int h) {
|
||||
this.point = point;
|
||||
this.parent = parent;
|
||||
this.g = g;
|
||||
this.h = h;
|
||||
this.f = g + h;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 寻找两点间的最短路径,避开障碍物
|
||||
* 地图数据(包括尺寸和障碍物)从数据库动态加载
|
||||
*/
|
||||
public List<Point> findPath(Point start, Point end) {
|
||||
// 从数据库加载地图数据
|
||||
List<MapGrid> mapGrids = mapGridRepository.findAll();
|
||||
if (mapGrids.isEmpty()) {
|
||||
return Collections.emptyList(); // 无地图数据
|
||||
}
|
||||
|
||||
// 动态确定地图尺寸和障碍物
|
||||
int maxX = 0, maxY = 0;
|
||||
Set<Point> obstacles = new HashSet<>();
|
||||
for (MapGrid gridCell : mapGrids) {
|
||||
if (gridCell.isObstacle() || gridCell.getCityName() == null || gridCell.getCityName().trim().isEmpty()) {
|
||||
obstacles.add(new Point(gridCell.getX(), gridCell.getY()));
|
||||
}
|
||||
if (gridCell.getX() > maxX) maxX = gridCell.getX();
|
||||
if (gridCell.getY() > maxY) maxY = gridCell.getY();
|
||||
}
|
||||
final int mapWidth = maxX + 1;
|
||||
final int mapHeight = maxY + 1;
|
||||
|
||||
// A*算法核心实现
|
||||
PriorityQueue<Node> openSet = new PriorityQueue<>(Comparator.comparingInt(n -> n.f));
|
||||
Map<Point, Node> allNodes = new HashMap<>();
|
||||
|
||||
Node startNode = new Node(start, null, 0, calculateHeuristic(start, end));
|
||||
openSet.add(startNode);
|
||||
allNodes.put(start, startNode);
|
||||
|
||||
while (!openSet.isEmpty()) {
|
||||
Node currentNode = openSet.poll();
|
||||
|
||||
if (currentNode.point.equals(end)) {
|
||||
return reconstructPath(currentNode);
|
||||
}
|
||||
|
||||
for (Point neighborPoint : getNeighbors(currentNode.point, mapWidth, mapHeight)) {
|
||||
if (obstacles.contains(neighborPoint)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int tentativeG = currentNode.g + 1; // 相邻节点间距离为1
|
||||
|
||||
Node neighborNode = allNodes.get(neighborPoint);
|
||||
|
||||
if (neighborNode == null) {
|
||||
// 新节点
|
||||
int h = calculateHeuristic(neighborPoint, end);
|
||||
neighborNode = new Node(neighborPoint, currentNode, tentativeG, h);
|
||||
allNodes.put(neighborPoint, neighborNode);
|
||||
openSet.add(neighborNode);
|
||||
} else if (tentativeG < neighborNode.g) {
|
||||
// 找到更好的路径
|
||||
neighborNode.parent = currentNode;
|
||||
neighborNode.g = tentativeG;
|
||||
neighborNode.f = tentativeG + neighborNode.h;
|
||||
// 更新优先队列
|
||||
openSet.remove(neighborNode);
|
||||
openSet.add(neighborNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Collections.emptyList(); // 未找到路径
|
||||
}
|
||||
|
||||
// 计算启发式函数值(曼哈顿距离)
|
||||
private int calculateHeuristic(Point a, Point b) {
|
||||
return Math.abs(a.x() - b.x()) + Math.abs(a.y() - b.y());
|
||||
}
|
||||
}
|
||||
@@ -1,462 +0,0 @@
|
||||
### 4. 任务智能分配算法
|
||||
|
||||
任务分配是系统中的关键业务流程,我实现了一个智能分配算法,能够根据多种因素为任务选择最合适的网格员。该算法综合考虑了地理距离、当前负载、专业匹配度和历史表现等因素。
|
||||
|
||||
**关键代码展示**:
|
||||
|
||||
```java
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class TaskAssignmentServiceImpl implements TaskAssignmentService {
|
||||
|
||||
private final TaskRepository taskRepository;
|
||||
private final UserAccountRepository userAccountRepository;
|
||||
private final GridService gridService;
|
||||
private final WorkerStatsService workerStatsService;
|
||||
|
||||
/**
|
||||
* 为任务推荐最合适的网格员
|
||||
* 综合考虑地理距离、当前负载、专业匹配度和历史表现
|
||||
*/
|
||||
@Override
|
||||
public UserAccount recommendWorkerForTask(Task task, List<UserAccount> availableWorkers) {
|
||||
if (availableWorkers.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 权重配置
|
||||
final double DISTANCE_WEIGHT = 0.4; // 地理距离权重
|
||||
final double LOAD_WEIGHT = 0.3; // 当前负载权重
|
||||
final double SKILL_WEIGHT = 0.2; // 专业匹配度权重
|
||||
final double PERFORMANCE_WEIGHT = 0.1; // 历史表现权重
|
||||
|
||||
// 任务位置
|
||||
Point taskLocation = new Point(task.getGridX(), task.getGridY());
|
||||
|
||||
// 计算每个网格员的评分
|
||||
Map<UserAccount, Double> workerScores = new HashMap<>();
|
||||
|
||||
for (UserAccount worker : availableWorkers) {
|
||||
// 1. 地理距离评分
|
||||
Point workerLocation = new Point(worker.getGridX(), worker.getGridY());
|
||||
double distance = calculateDistance(workerLocation, taskLocation);
|
||||
double maxDistance = 10.0; // 最大考虑距离
|
||||
double distanceScore = Math.max(0, maxDistance - distance) / maxDistance;
|
||||
|
||||
// 2. 当前负载评分
|
||||
int currentTasks = taskRepository.countByAssigneeIdAndStatusIn(
|
||||
worker.getId(), Arrays.asList(TaskStatus.ASSIGNED, TaskStatus.IN_PROGRESS));
|
||||
int maxTasks = 5; // 最大任务数
|
||||
double loadScore = (double)(maxTasks - currentTasks) / maxTasks;
|
||||
|
||||
// 3. 专业匹配度评分
|
||||
double skillScore = calculateSkillMatch(worker, task);
|
||||
|
||||
// 4. 历史表现评分
|
||||
double completionRate = workerStatsService.getCompletionRate(worker.getId());
|
||||
double qualityRating = workerStatsService.getAverageQualityRating(worker.getId());
|
||||
double performanceScore = (completionRate * 0.7) + (qualityRating * 0.3);
|
||||
|
||||
// 5. 综合评分
|
||||
double totalScore = (distanceScore * DISTANCE_WEIGHT) +
|
||||
(loadScore * LOAD_WEIGHT) +
|
||||
(skillScore * SKILL_WEIGHT) +
|
||||
(performanceScore * PERFORMANCE_WEIGHT);
|
||||
|
||||
workerScores.put(worker, totalScore);
|
||||
}
|
||||
|
||||
// 选择评分最高的网格员
|
||||
return workerScores.entrySet().stream()
|
||||
.max(Map.Entry.comparingByValue())
|
||||
.map(Map.Entry::getKey)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两点间的距离
|
||||
* 使用曼哈顿距离,适合网格化的城市环境
|
||||
*/
|
||||
private double calculateDistance(Point a, Point b) {
|
||||
return Math.abs(a.x() - b.x()) + Math.abs(a.y() - b.y());
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算网格员技能与任务的匹配度
|
||||
* 返回0-1之间的分数,1表示完全匹配
|
||||
*/
|
||||
private double calculateSkillMatch(UserAccount worker, Task task) {
|
||||
// 获取工人的技能列表
|
||||
List<String> workerSkills = worker.getSkills();
|
||||
if (workerSkills == null || workerSkills.isEmpty()) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// 根据任务类型确定所需技能
|
||||
List<String> requiredSkills = determineRequiredSkills(task);
|
||||
if (requiredSkills.isEmpty()) {
|
||||
return 1.0; // 如果任务没有特定技能要求,则任何工人都完全匹配
|
||||
}
|
||||
|
||||
// 计算匹配的技能数量
|
||||
long matchedSkillsCount = requiredSkills.stream()
|
||||
.filter(skill -> workerSkills.contains(skill))
|
||||
.count();
|
||||
|
||||
// 返回匹配率
|
||||
return (double) matchedSkillsCount / requiredSkills.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据任务类型确定所需技能
|
||||
*/
|
||||
private List<String> determineRequiredSkills(Task task) {
|
||||
List<String> skills = new ArrayList<>();
|
||||
|
||||
// 根据污染类型添加相关技能
|
||||
switch (task.getPollutionType()) {
|
||||
case AIR:
|
||||
skills.add("air_quality_monitoring");
|
||||
skills.add("emissions_control");
|
||||
break;
|
||||
case WATER:
|
||||
skills.add("water_sampling");
|
||||
skills.add("water_treatment");
|
||||
break;
|
||||
case SOIL:
|
||||
skills.add("soil_testing");
|
||||
skills.add("land_remediation");
|
||||
break;
|
||||
case NOISE:
|
||||
skills.add("noise_measurement");
|
||||
skills.add("sound_insulation");
|
||||
break;
|
||||
default:
|
||||
skills.add("general_environmental");
|
||||
}
|
||||
|
||||
// 根据严重程度添加额外技能
|
||||
if (task.getSeverityLevel() == SeverityLevel.HIGH ||
|
||||
task.getSeverityLevel() == SeverityLevel.CRITICAL) {
|
||||
skills.add("emergency_response");
|
||||
}
|
||||
|
||||
return skills;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**实现要点分析**:
|
||||
|
||||
1. **多因素加权评分**: 算法综合考虑了地理距离、当前负载、专业匹配度和历史表现四个因素,通过加权计算得出每个网格员的综合得分。
|
||||
2. **技能匹配机制**: 根据任务的污染类型和严重程度,动态确定所需的技能列表,然后与网格员的技能进行匹配,计算匹配度。
|
||||
3. **可配置权重**: 各因素的权重可以根据实际需求进行调整,使得算法更加灵活和适应性强。
|
||||
4. **流式API**: 使用Java 8的Stream API进行最大值查找,代码简洁且高效。
|
||||
|
||||
**程序流程图**:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[开始] --> B[获取可用网格员列表]
|
||||
B --> C{列表为空?}
|
||||
C -->|是| D[返回null]
|
||||
C -->|否| E[遍历每个网格员]
|
||||
E --> F[计算地理距离评分]
|
||||
F --> G[计算当前负载评分]
|
||||
G --> H[计算专业匹配度评分]
|
||||
H --> I[计算历史表现评分]
|
||||
I --> J[计算综合评分]
|
||||
J --> K[记录网格员评分]
|
||||
K --> L{所有网格员已处理?}
|
||||
L -->|否| E
|
||||
L -->|是| M[返回评分最高的网格员]
|
||||
```
|
||||
|
||||
## 3.3.3 界面展示与成果展示
|
||||
|
||||
在前端实现方面,我采用了Vue 3和Element Plus组件库,打造了美观、易用且响应式的用户界面。下面展示几个核心界面及其功能实现。
|
||||
|
||||
### 1. 主管工作台 - 反馈审核与任务分配
|
||||
|
||||

|
||||
|
||||
**界面功能说明**:
|
||||
|
||||
1. **左侧反馈列表**: 展示所有待审核的反馈,支持按状态、类型和严重程度进行筛选。
|
||||
2. **右侧反馈详情**: 显示选中反馈的详细信息,包括标题、描述、位置和附件等。
|
||||
3. **智能推荐**: 系统自动推荐最合适的网格员,并显示推荐理由。
|
||||
4. **手动分配**: 主管可以覆盖系统推荐,手动选择其他网格员。
|
||||
5. **批量操作**: 支持批量审核和分配功能,提高工作效率。
|
||||
|
||||
**前端代码实现**:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="supervisor-dashboard">
|
||||
<el-row :gutter="20">
|
||||
<!-- 左侧反馈列表 -->
|
||||
<el-col :span="8">
|
||||
<el-card class="feedback-list">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>待处理反馈 ({{ totalItems }})</span>
|
||||
<el-input
|
||||
v-model="searchQuery"
|
||||
placeholder="搜索反馈..."
|
||||
prefix-icon="el-icon-search"
|
||||
clearable
|
||||
@input="handleSearch"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="feedbackList"
|
||||
@row-click="handleRowClick"
|
||||
highlight-current-row
|
||||
>
|
||||
<el-table-column prop="eventId" label="事件ID" width="120" />
|
||||
<el-table-column prop="title" label="标题" show-overflow-tooltip />
|
||||
<el-table-column prop="severityLevel" label="严重程度" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag :type="getSeverityType(scope.row.severityLevel)">
|
||||
{{ scope.row.severityLevel }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="120">
|
||||
<template #default="scope">
|
||||
<el-tag :type="getStatusType(scope.row.status)">
|
||||
{{ getStatusText(scope.row.status) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="pagination-container">
|
||||
<el-pagination
|
||||
background
|
||||
layout="prev, pager, next"
|
||||
:total="totalItems"
|
||||
:page-size="pageSize"
|
||||
@current-change="handlePageChange"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<!-- 右侧反馈详情 -->
|
||||
<el-col :span="16">
|
||||
<el-card v-if="selectedFeedback" class="feedback-detail">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>反馈详情</span>
|
||||
<div>
|
||||
<el-button
|
||||
type="success"
|
||||
icon="el-icon-check"
|
||||
@click="handleApprove"
|
||||
:disabled="!canApprove"
|
||||
>
|
||||
批准
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
icon="el-icon-close"
|
||||
@click="handleReject"
|
||||
:disabled="!canReject"
|
||||
>
|
||||
拒绝
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="标题">{{ selectedFeedback.title }}</el-descriptions-item>
|
||||
<el-descriptions-item label="事件ID">{{ selectedFeedback.eventId }}</el-descriptions-item>
|
||||
<el-descriptions-item label="污染类型">{{ selectedFeedback.pollutionType }}</el-descriptions-item>
|
||||
<el-descriptions-item label="严重程度">
|
||||
<el-tag :type="getSeverityType(selectedFeedback.severityLevel)">
|
||||
{{ selectedFeedback.severityLevel }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="提交时间">{{ formatDate(selectedFeedback.createdAt) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="位置">{{ selectedFeedback.textAddress }}</el-descriptions-item>
|
||||
<el-descriptions-item label="描述" :span="2">
|
||||
{{ selectedFeedback.description }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<!-- 附件展示 -->
|
||||
<div v-if="selectedFeedback.attachments && selectedFeedback.attachments.length > 0" class="attachments">
|
||||
<h3>附件</h3>
|
||||
<el-image
|
||||
v-for="(attachment, index) in selectedFeedback.attachments"
|
||||
:key="index"
|
||||
:src="attachment.filePath"
|
||||
:preview-src-list="getImageUrls()"
|
||||
fit="cover"
|
||||
class="attachment-image"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 任务分配表单 -->
|
||||
<div v-if="selectedFeedback.status === 'PENDING_ASSIGNMENT'" class="assignment-form">
|
||||
<h3>分配任务</h3>
|
||||
<el-form :model="assignmentForm" label-width="120px">
|
||||
<el-form-item label="选择网格员">
|
||||
<el-select v-model="assignmentForm.workerId" placeholder="选择网格员">
|
||||
<el-option
|
||||
v-for="worker in availableWorkers"
|
||||
:key="worker.id"
|
||||
:label="worker.name"
|
||||
:value="worker.id"
|
||||
>
|
||||
<div class="worker-option">
|
||||
<span>{{ worker.name }}</span>
|
||||
<small>
|
||||
{{ worker.isRecommended ? '(系统推荐)' : '' }}
|
||||
{{ worker.currentTasks }} 个任务
|
||||
</small>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleAssign" :loading="assignLoading">
|
||||
分配任务
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-empty v-else description="请选择一个反馈" />
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
### 2. 网格员工作台 - 任务执行
|
||||
|
||||

|
||||
|
||||
**界面功能说明**:
|
||||
|
||||
1. **任务列表**: 展示分配给当前网格员的所有任务,按状态和截止日期排序。
|
||||
2. **任务详情**: 显示选中任务的详细信息,包括位置、描述和附件等。
|
||||
3. **路径规划**: 集成A*寻路算法,为网格员提供从当前位置到任务地点的最优路径。
|
||||
4. **任务提交**: 提供表单和文件上传功能,让网格员提交任务处理结果。
|
||||
|
||||
### 3. 决策支持看板
|
||||
|
||||

|
||||
|
||||
**界面功能说明**:
|
||||
|
||||
1. **核心KPI**: 展示关键业务指标,如反馈总数、任务完成率、平均处理时长等。
|
||||
2. **热力图**: 基于地理位置的问题密度热力图,直观展示问题高发区域。
|
||||
3. **趋势图**: 展示过去30天的反馈和任务数量趋势,帮助决策者了解系统运行状况。
|
||||
4. **分布图**: 展示不同类型问题的分布情况,帮助决策者了解问题类型分布。
|
||||
|
||||
**前端代码实现**:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="dashboard-container">
|
||||
<el-row :gutter="20" class="kpi-row">
|
||||
<el-col :span="6" v-for="(item, index) in kpiData" :key="index">
|
||||
<el-card shadow="hover" class="kpi-card">
|
||||
<div class="kpi-icon">
|
||||
<i :class="item.icon"></i>
|
||||
</div>
|
||||
<div class="kpi-content">
|
||||
<div class="kpi-value">{{ item.value }}</div>
|
||||
<div class="kpi-label">{{ item.label }}</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" class="chart-row">
|
||||
<el-col :span="16">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>问题热力图</span>
|
||||
<el-select v-model="mapFilter" placeholder="筛选" size="small">
|
||||
<el-option label="全部问题" value="ALL" />
|
||||
<el-option label="空气污染" value="AIR" />
|
||||
<el-option label="水污染" value="WATER" />
|
||||
<el-option label="噪音污染" value="NOISE" />
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
<div class="map-container">
|
||||
<heatmap-component :data="heatmapData" :filter="mapFilter" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-card shadow="hover" class="chart-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>问题类型分布</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="chart-container">
|
||||
<pie-chart :data="typeDistribution" />
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="hover" class="chart-card" style="margin-top: 20px;">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>任务完成情况</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="chart-container">
|
||||
<progress-chart :data="taskCompletionData" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" class="chart-row">
|
||||
<el-col :span="24">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>过去30天趋势</span>
|
||||
<el-radio-group v-model="trendType" size="small">
|
||||
<el-radio-button label="feedback">反馈数量</el-radio-button>
|
||||
<el-radio-button label="tasks">任务数量</el-radio-button>
|
||||
<el-radio-button label="completion">完成率</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</template>
|
||||
<div class="chart-container">
|
||||
<trend-chart :data="trendData" :type="trendType" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
## 3.3.4 实现成果总结
|
||||
|
||||
通过系统实现阶段的工作,我成功地将系统设计阶段规划的功能转化为了可运行的代码,实现了环境监督系统的核心功能。主要成果包括:
|
||||
|
||||
1. **创新的数据持久化方案**: 设计并实现了基于JSON文件的数据存储服务,简化了系统部署,同时提供了类似JPA的操作接口。
|
||||
2. **高效的A*寻路算法**: 实现了能够考虑地图障碍物的A*寻路算法,为网格员提供最优路径规划。
|
||||
3. **智能的任务分配算法**: 开发了综合考虑多种因素的任务分配算法,能够为任务选择最合适的执行者。
|
||||
4. **完整的反馈管理流程**: 实现了反馈提交、AI审核、人工审核和任务创建的完整流程,支持多条件查询和文件上传。
|
||||
5. **直观的用户界面**: 设计并实现了美观、易用且响应式的用户界面,包括主管工作台、网格员工作台和决策支持看板等。
|
||||
|
||||
这些实现成果不仅满足了系统需求分析阶段定义的功能要求,也体现了系统设计阶段规划的架构和模块划分。系统的实现充分考虑了可维护性、可扩展性和用户体验,为后续的系统测试和部署奠定了坚实的基础。
|
||||
@@ -1,242 +0,0 @@
|
||||
**实现要点分析**:
|
||||
|
||||
1. **动态地图加载**: 算法从数据库动态加载地图数据,包括障碍物信息和地图尺寸,使得路径规划能够适应地图的变化。
|
||||
2. **优先队列优化**: 使用优先队列(PriorityQueue)存储开放列表,确保每次都能高效地选择F值最小的节点,大大提高了算法效率。
|
||||
3. **曼哈顿距离启发函数**: 选择曼哈顿距离作为启发函数,适合网格化的移动模式,能够准确估计网格间的距离。
|
||||
4. **路径重建**: 通过记录每个节点的父节点,实现了从终点回溯到起点的路径重建,返回完整的路径点列表。
|
||||
|
||||
**程序流程图**:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[开始] --> B[加载地图数据]
|
||||
B --> C[初始化开放列表和关闭列表]
|
||||
C --> D[将起点加入开放列表]
|
||||
D --> E{开放列表为空?}
|
||||
E -->|是| F[返回空路径]
|
||||
E -->|否| G[从开放列表取出F值最小的节点]
|
||||
G --> H{是终点?}
|
||||
H -->|是| I[重建并返回路径]
|
||||
H -->|否| J[处理相邻节点]
|
||||
J --> E
|
||||
```
|
||||
|
||||
**API接口**:
|
||||
|
||||
```java
|
||||
@RestController
|
||||
@RequestMapping("/api/pathfinding")
|
||||
@RequiredArgsConstructor
|
||||
public class PathfindingController {
|
||||
|
||||
private final AStarService aStarService;
|
||||
|
||||
@GetMapping("/find")
|
||||
@PreAuthorize("hasRole('GRID_WORKER')")
|
||||
public ResponseEntity<List<Point>> findPath(
|
||||
@RequestParam int startX, @RequestParam int startY,
|
||||
@RequestParam int endX, @RequestParam int endY) {
|
||||
|
||||
Point start = new Point(startX, startY);
|
||||
Point end = new Point(endX, endY);
|
||||
|
||||
List<Point> path = aStarService.findPath(start, end);
|
||||
return ResponseEntity.ok(path);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 反馈管理模块
|
||||
|
||||
反馈管理模块是系统的核心业务模块之一,负责处理用户提交的环境问题反馈。我实现了完整的反馈提交、审核和处理流程,包括多条件查询、状态流转和文件上传等功能。
|
||||
|
||||
**关键代码展示**:
|
||||
|
||||
```java
|
||||
@RestController
|
||||
@RequestMapping("/api/feedback")
|
||||
@RequiredArgsConstructor
|
||||
public class FeedbackController {
|
||||
|
||||
private final FeedbackService feedbackService;
|
||||
|
||||
/**
|
||||
* 提交反馈(正式接口)
|
||||
* 使用multipart/form-data格式提交反馈,支持附件上传
|
||||
*/
|
||||
@PostMapping(value = "/submit", consumes = {"multipart/form-data"})
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
public ResponseEntity<Feedback> submitFeedback(
|
||||
@Valid @RequestPart("feedback") FeedbackSubmissionRequest request,
|
||||
@RequestPart(value = "files", required = false) MultipartFile[] files,
|
||||
@AuthenticationPrincipal CustomUserDetails userDetails) {
|
||||
|
||||
Feedback createdFeedback = feedbackService.submitFeedback(request, files);
|
||||
return new ResponseEntity<>(createdFeedback, HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有反馈(分页+多条件过滤)
|
||||
* 支持按状态、污染类型、严重程度、地理位置、时间范围和关键词进行组合查询
|
||||
*/
|
||||
@GetMapping
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
public ResponseEntity<Page<FeedbackResponseDTO>> getAllFeedback(
|
||||
@AuthenticationPrincipal CustomUserDetails userDetails,
|
||||
@RequestParam(required = false) FeedbackStatus status,
|
||||
@RequestParam(required = false) PollutionType pollutionType,
|
||||
@RequestParam(required = false) SeverityLevel severityLevel,
|
||||
@RequestParam(required = false) String cityName,
|
||||
@RequestParam(required = false) String districtName,
|
||||
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate startDate,
|
||||
@RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate,
|
||||
@RequestParam(required = false) String keyword,
|
||||
Pageable pageable) {
|
||||
|
||||
Page<FeedbackResponseDTO> feedbackPage = feedbackService.getFeedback(
|
||||
userDetails, status, pollutionType, severityLevel, cityName, districtName,
|
||||
startDate, endDate, keyword, pageable);
|
||||
|
||||
return ResponseEntity.ok(feedbackPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理反馈 (例如, 批准)
|
||||
*/
|
||||
@PostMapping("/{id}/process")
|
||||
@PreAuthorize("hasAnyRole('ADMIN', 'SUPERVISOR')")
|
||||
public ResponseEntity<FeedbackResponseDTO> processFeedback(
|
||||
@PathVariable Long id,
|
||||
@Valid @RequestBody ProcessFeedbackRequest request) {
|
||||
FeedbackResponseDTO updatedFeedback = feedbackService.processFeedback(id, request);
|
||||
return ResponseEntity.ok(updatedFeedback);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**服务层实现**:
|
||||
|
||||
```java
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class FeedbackServiceImpl implements FeedbackService {
|
||||
|
||||
private final FeedbackRepository feedbackRepository;
|
||||
private final UserAccountRepository userAccountRepository;
|
||||
private final FileStorageService fileStorageService;
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
|
||||
@Override
|
||||
public Feedback submitFeedback(FeedbackSubmissionRequest request, MultipartFile[] files) {
|
||||
// 1. 获取当前用户
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
String email = authentication.getName();
|
||||
UserAccount user = userAccountRepository.findByEmail(email)
|
||||
.orElseThrow(() -> new ResourceNotFoundException("User", "email", email));
|
||||
|
||||
// 2. 创建反馈实体
|
||||
Feedback feedback = new Feedback();
|
||||
feedback.setTitle(request.getTitle());
|
||||
feedback.setDescription(request.getDescription());
|
||||
feedback.setPollutionType(request.getPollutionType());
|
||||
feedback.setSeverityLevel(request.getSeverityLevel());
|
||||
feedback.setLatitude(request.getLatitude());
|
||||
feedback.setLongitude(request.getLongitude());
|
||||
feedback.setTextAddress(request.getTextAddress());
|
||||
feedback.setGridX(request.getGridX());
|
||||
feedback.setGridY(request.getGridY());
|
||||
feedback.setStatus(FeedbackStatus.SUBMITTED);
|
||||
feedback.setSubmitter(user);
|
||||
feedback.setEventId(generateEventId());
|
||||
|
||||
// 3. 保存反馈
|
||||
Feedback savedFeedback = feedbackRepository.save(feedback);
|
||||
|
||||
// 4. 处理附件
|
||||
if (files != null && files.length > 0) {
|
||||
List<Attachment> attachments = new ArrayList<>();
|
||||
for (MultipartFile file : files) {
|
||||
String fileName = fileStorageService.storeFile(file);
|
||||
Attachment attachment = new Attachment();
|
||||
attachment.setFileName(fileName);
|
||||
attachment.setFilePath("/uploads/" + fileName);
|
||||
attachment.setFileType(file.getContentType());
|
||||
attachment.setFileSize(file.getSize());
|
||||
attachments.add(attachment);
|
||||
}
|
||||
savedFeedback.setAttachments(attachments);
|
||||
feedbackRepository.save(savedFeedback);
|
||||
}
|
||||
|
||||
// 5. 发布事件,触发AI审核
|
||||
eventPublisher.publishEvent(new FeedbackSubmittedEvent(savedFeedback));
|
||||
|
||||
return savedFeedback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeedbackResponseDTO processFeedback(Long id, ProcessFeedbackRequest request) {
|
||||
Feedback feedback = feedbackRepository.findById(id)
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Feedback", "id", id));
|
||||
|
||||
// 验证状态转换是否有效
|
||||
if (!isValidStatusTransition(feedback.getStatus(), request.getStatus())) {
|
||||
throw new IllegalStateException("Invalid status transition from " +
|
||||
feedback.getStatus() + " to " + request.getStatus());
|
||||
}
|
||||
|
||||
// 更新反馈状态
|
||||
feedback.setStatus(request.getStatus());
|
||||
|
||||
// 如果批准反馈,则更新为PENDING_ASSIGNMENT状态
|
||||
if (request.getStatus() == FeedbackStatus.APPROVED) {
|
||||
feedback.setStatus(FeedbackStatus.PENDING_ASSIGNMENT);
|
||||
}
|
||||
|
||||
Feedback updatedFeedback = feedbackRepository.save(feedback);
|
||||
|
||||
// 如果反馈被批准,发布事件通知任务管理模块
|
||||
if (request.getStatus() == FeedbackStatus.APPROVED) {
|
||||
eventPublisher.publishEvent(new FeedbackApprovedEvent(updatedFeedback));
|
||||
}
|
||||
|
||||
return mapToDTO(updatedFeedback);
|
||||
}
|
||||
|
||||
// 生成唯一的事件ID
|
||||
private String generateEventId() {
|
||||
return "EMS-" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + "-"
|
||||
+ UUID.randomUUID().toString().substring(0, 8).toUpperCase();
|
||||
}
|
||||
|
||||
// 验证状态转换是否有效
|
||||
private boolean isValidStatusTransition(FeedbackStatus current, FeedbackStatus next) {
|
||||
// 实现状态机逻辑
|
||||
switch (current) {
|
||||
case SUBMITTED:
|
||||
return next == FeedbackStatus.AI_REVIEWED;
|
||||
case AI_REVIEWED:
|
||||
return next == FeedbackStatus.PENDING_REVIEW;
|
||||
case PENDING_REVIEW:
|
||||
return next == FeedbackStatus.APPROVED || next == FeedbackStatus.REJECTED;
|
||||
case APPROVED:
|
||||
return next == FeedbackStatus.PENDING_ASSIGNMENT;
|
||||
case PENDING_ASSIGNMENT:
|
||||
return next == FeedbackStatus.ASSIGNED;
|
||||
case ASSIGNED:
|
||||
return next == FeedbackStatus.PROCESSED;
|
||||
case PROCESSED:
|
||||
return next == FeedbackStatus.CLOSED;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**实现要点分析**:
|
||||
|
||||
1. **多部分表单处理**: 使用`@RequestPart`注解同时处理JSON数据和文件上传,实现了富媒体反馈提交。
|
||||
2. **事件驱动架构**: 通过Spring的事件机制,实现了反馈提交后的异步处理,如AI审核和任务创建,提高了系统响应速度。
|
||||
3. **状态机模式**: 使用状态机模式管理反馈的生命周期,确保状态转换的合法性,防止非法操作。
|
||||
4. **多条件动态查询**: 实现了灵活的多条件组合查询,支持按状态、类型、严重程度、地理位置和时间范围等进行过滤。
|
||||
110
Report/系统测试.md
110
Report/系统测试.md
@@ -1,110 +0,0 @@
|
||||
# 3.4 系统测试
|
||||
|
||||
为确保系统交付质量,我制定并执行了一套覆盖从代码单元到用户场景、从功能正确性到非功能性需求的、多层次、全方位的测试策略。
|
||||
|
||||
## 3.4.1 后端测试
|
||||
|
||||
我主要负责后端的单元测试、集成测试和API接口测试,旨在从源头保证服务的稳定、可靠与安全。
|
||||
|
||||
### 1. 单元测试 (Unit Testing)
|
||||
|
||||
我坚持“测试驱动开发”(TDD)的理念,使用`JUnit 5`和`Mockito`框架为核心的`Service`层和`Repository`层的公共方法编写了详尽的单元测试。单元测试的目标是隔离验证最小代码单元(一个方法或一个类)的逻辑正确性。
|
||||
|
||||
**测试用例示例:`TaskAssignmentService`单元测试**
|
||||
|
||||
```java:ems-backend/src/test/java/com/dne/ems/service/TaskAssignmentServiceTest.java
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class TaskAssignmentServiceTest {
|
||||
|
||||
@Mock
|
||||
private FeedbackRepository feedbackRepository;
|
||||
@Mock
|
||||
private UserAccountRepository userAccountRepository;
|
||||
@Mock
|
||||
private TaskRepository taskRepository;
|
||||
@Mock
|
||||
private AssignmentRepository assignmentRepository;
|
||||
|
||||
@InjectMocks
|
||||
private TaskAssignmentServiceImpl taskAssignmentService;
|
||||
|
||||
@Test
|
||||
void assignTask_Success_ShouldReturnSavedAssignment() {
|
||||
// Arrange: 准备测试数据和模拟行为
|
||||
Feedback mockFeedback = new Feedback(1L, "Test", "Desc", FeedbackStatus.CONFIRMED, 101L);
|
||||
UserAccount mockAssignee = new UserAccount(202L, "worker", "pass", Role.GRID_WORKER);
|
||||
when(feedbackRepository.findById(1L)).thenReturn(Optional.of(mockFeedback));
|
||||
when(userAccountRepository.findById(202L)).thenReturn(Optional.of(mockAssignee));
|
||||
when(taskRepository.save(any(Task.class))).thenAnswer(i -> i.getArgument(0));
|
||||
when(assignmentRepository.save(any(Assignment.class))).thenAnswer(i -> i.getArgument(0));
|
||||
|
||||
// Act: 执行被测试的方法
|
||||
Assignment result = taskAssignmentService.assignTask(1L, 202L, 303L);
|
||||
|
||||
// Assert: 验证结果和交互
|
||||
assertNotNull(result);
|
||||
assertEquals(202L, result.getAssigneeId());
|
||||
verify(feedbackRepository, times(1)).save(any(Feedback.class)); // 验证Feedback状态是否被更新并保存
|
||||
assertEquals(FeedbackStatus.ASSIGNED, mockFeedback.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
void assignTask_FeedbackNotFound_ShouldThrowException() {
|
||||
// Arrange
|
||||
when(feedbackRepository.findById(99L)).thenReturn(Optional.empty());
|
||||
|
||||
// Act & Assert
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
taskAssignmentService.assignTask(99L, 202L, 303L);
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**测试策略说明:**
|
||||
* **Mocking:** 使用`Mockito`框架模拟(Mock)外部依赖(如各个Repository),使得测试可以专注于`Service`层自身的业务逻辑,而不受数据库或文件系统的影响。
|
||||
* **覆盖度:** 我为每个公共方法都编写了多个测试用例,覆盖了“成功路径”和各种“异常路径”(如输入非法、依赖返回空等),力求达到较高的代码覆盖率和逻辑覆盖率。
|
||||
|
||||
### 2. API接口测试 (API Testing)
|
||||
|
||||
我利用`SpringDoc`与`Swagger UI`的无缝集成,以及更专业的API测试工具`Postman`,对所有RESTful API进行了系统性的黑盒测试。
|
||||
|
||||
* **测试范围:** 覆盖了用户认证、权限管理、反馈生命周期、任务生命周期等所有核心模块的每一个API端点。
|
||||
* **测试方法:** 我为每个API编写了一系列测试用例,形成了一个`Postman`测试集(Collection),这使得测试可以被保存、共享和重复执行。
|
||||
|
||||
**API测试用例表示例 (扩展):**
|
||||
|
||||
| 用例ID | 模块 | 接口 | 场景描述 | 输入数据 | 预期HTTP状态 | 预期响应体关键内容 | 结果 |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| TC-API-001 | 任务管理 | `POST /api/assignments` | 成功分配任务 | 合法的`feedbackId`, `assigneeId` | `201 Created` | 返回新创建的`assignment`对象JSON | 通过 |
|
||||
| TC-API-002 | 任务管理 | `POST /api/assignments` | **异常**:反馈ID不存在 | `feedbackId: 9999` | `404 Not Found` | `"message": "Feedback with id 9999 not found"` | 通过 |
|
||||
| TC-API-003 | 任务管理 | `POST /api/assignments` | **异常**:指派的用户不是网格员 | `assigneeId`指向一个`ADMIN`角色的用户 | `400 Bad Request` | `"message": "User is not a grid worker"` | 通过 |
|
||||
| TC-API-004 | 任务管理 | `POST /api/assignments` | **异常**:反馈状态不正确 | `feedbackId`指向一个`PENDING`状态的反馈 | `400 Bad Request` | `"message": "Feedback is not in a CONFIRMED state"` | 通过 |
|
||||
| TC-API-005 | 安全 | `POST /api/assignments` | **安全**:无JWT令牌 | `Authorization`头为空 | `401 Unauthorized` | (空或错误提示) | 通过 |
|
||||
| TC-API-006 | 安全 | `POST /api/assignments` | **安全**:使用网格员角色的JWT | `Authorization`头为一个`GRID_WORKER`的JWT | `403 Forbidden` | (空或错误提示) | 通过 |
|
||||
|
||||
## 3.4.2 前端测试
|
||||
|
||||
我与负责前端的组员紧密协作,进行了全面的前端功能、UI/UX和兼容性测试。
|
||||
|
||||
* **手工功能测试:** 我们以用户故事(User Story)为驱动,模拟不同角色的用户(公众、网格员、主管、管理员),完整地执行了所有核心业务流程的端到端场景,确保功能符合需求规格。
|
||||
* **UI/UX测试:** 仔细检查了界面的布局、色彩、字体、图标和交互动效,确保其在主流浏览器(Chrome, Firefox, Edge)的不同版本和不同屏幕分辨率下(如`1920x1080`, `1366x768`)都能保持良好的一致性、美观度和用户体验。
|
||||
|
||||
## 3.4.3 集成与系统测试
|
||||
|
||||
在前后端分别完成各自的测试后,我们将整个系统部署到一台独立的测试服务器上,进行了端到端的集成测试和系统测试。
|
||||
|
||||
* **目的:** 验证前后端数据接口的正确性、API调用的顺畅性、以及在真实网络环境下整个系统业务流程的闭环。
|
||||
* **过程:** 我们共同执行了一套预先设计的系统级测试用例,这些用例模拟了真实世界中的复杂操作序列。例如:
|
||||
1. 公众用户A提交反馈 -> 主管B审核通过 -> 主管B将任务分配给网格员C -> 网格员C完成任务并提交数据 -> 主管B查看已完成的任务和数据。
|
||||
2. 并发测试:多个用户同时提交反馈或更新任务,验证后端`synchronized`机制是否有效防止了数据冲突。
|
||||
* **结果:** 通过严格的集成联调测试,我们发现并修复了若干在单元测试阶段难以暴露的问题(如跨域CORS配置问题、序列化/反序列化日期格式不一致问题、JWT刷新逻辑的边界条件等),最终确保了前后端系统的无缝集成和稳定运行。
|
||||
|
||||
## 3.4.4 非功能性测试
|
||||
|
||||
除了功能测试,我还对系统的部分非功能性需求进行了初步的探索性测试。
|
||||
|
||||
* **性能测试:** 使用`Apache JMeter`工具,对核心的登录和查询类API进行了简单的压力测试。模拟20个并发用户持续请求,观察到API的平均响应时间仍在200ms以内,CPU和内存占用率处于合理范围,初步证明系统具备应对一定并发访问的能力。
|
||||
* **安全测试:**
|
||||
* **权限测试:** 严格测试了不同角色的用户访问未授权API的情况,验证系统是否能正确返回`403 Forbidden`。
|
||||
* **输入验证:** 尝试提交包含恶意脚本(XSS)或SQL注入(虽然我们不是SQL数据库,但原理相通)的表单数据,验证后端是否有充分的输入清理和验证机制。
|
||||
@@ -1,38 +0,0 @@
|
||||
# 系统设计文档
|
||||
|
||||
本文档旨在详细阐述环境监督系统(EMS)的系统架构、功能模块和实现细节,为开发、测试和维护提供指导。
|
||||
|
||||
由于文档较长,为了便于阅读和维护,内容已被分割为以下几个部分:
|
||||
|
||||
## 文档目录
|
||||
|
||||
1. [总体设计](系统设计_第一部分.md)
|
||||
- 系统架构设计
|
||||
- 架构选型与原则
|
||||
- 后端架构
|
||||
- 前端架构
|
||||
- 功能模块划分
|
||||
|
||||
2. [功能模块详细设计](系统设计_第二部分.md)
|
||||
- 反馈管理模块
|
||||
- 任务管理模块
|
||||
- 用户与人员管理模块
|
||||
- 网格与地图模块
|
||||
- 决策支持模块
|
||||
|
||||
3. [类和对象的设计与动态模型设计](系统设计_第三部分.md)
|
||||
- UserAccount 类图
|
||||
- Feedback 类图
|
||||
- Task 类图
|
||||
- Grid 和 Assignment 类图
|
||||
- 核心时序图
|
||||
- 核心状态图
|
||||
|
||||
4. [算法设计与数据持久化设计](系统设计_第四部分.md)
|
||||
- A* 寻路算法
|
||||
- 任务智能分配算法
|
||||
- JSON文件存储架构
|
||||
- 核心JSON文件结构
|
||||
|
||||
**注意:** 所有图表均使用本地渲染的方式,无需在线渲染服务。
|
||||
|
||||
@@ -1,421 +0,0 @@
|
||||
# 系统设计文档
|
||||
|
||||
本文档旨在详细阐述环境监督系统(EMS)的系统架构、功能模块和实现细节,为开发、测试和维护提供指导。
|
||||
|
||||
## 1. 总体设计
|
||||
|
||||
总体设计旨在从宏观上描述系统的架构、设计原则和核心组成部分,为后续的详细设计奠定基础。
|
||||
|
||||
### 1.1 系统架构设计
|
||||
|
||||
#### 1.1.1 架构选型与原则
|
||||
|
||||
本系统采用业界成熟的 **前后端分离** 架构。该架构将用户界面(前端)与业务逻辑处理(后端)彻底分离,二者通过定义良好的 **RESTful API** 进行通信。这种模式的优势在于:
|
||||
- **并行开发**: 前后端团队可以并行开发、测试和部署,只需遵守统一的API约定,从而显著提升开发效率。
|
||||
- **技术栈灵活性**: 前后端可以独立选择最适合自身场景的技术栈,便于未来对任一端进行技术升级或重构。
|
||||
- **关注点分离**: 前端专注于用户体验和界面呈现,后端专注于业务逻辑、数据处理和系统安全,使得系统各部分职责更清晰,更易于维护。
|
||||
|
||||
在架构设计中,我们遵循了以下核心原则:
|
||||
- **高内聚,低耦合**: 将相关功能组织在独立的模块中,并最小化模块间的依赖。
|
||||
- **可扩展性**: 架构设计应能方便地横向扩展(增加更多服务器实例)和纵向扩展(增加新功能模块)。
|
||||
- **安全性**: 从设计之初就考虑认证、授权、数据加密和输入验证等安全问题。
|
||||
- **可维护性**: 采用清晰的代码分层、统一的编码规范和完善的文档,降低长期维护成本。
|
||||
|
||||
#### 1.1.2 后端架构
|
||||
|
||||
后端服务基于 **Spring Boot 3** 和 **Java 17** 构建,这是一个现代化、高性能的组合。其内部采用了经典的三层分层架构模式:
|
||||
|
||||
- **表现层 (Controller Layer)**: 负责接收前端的HTTP请求,使用 `@RestController` 定义RESTful API。此层负责解析HTTP请求、验证输入参数(使用JSR-303注解),并调用业务逻辑层处理请求,但不包含任何业务逻辑。
|
||||
- **业务逻辑层 (Service Layer)**: 系统的核心,使用 `@Service` 注解。它封装了所有的业务规则、流程控制和复杂计算。它通过调用数据访问层来操作数据,并通过事件发布等机制与其他服务进行解耦交互。
|
||||
- **数据访问层 (Repository/Persistence Layer)**: 负责与数据存储进行交互。本项目独创性地采用了一套基于JSON文件的持久化方案。通过自定义的`JsonStorageService`和一系列Repository类,模拟了类似JPA的接口,实现了对`users.json`, `tasks.json`等核心数据文件的增删改查(CRUD)操作。选择JSON文件存储简化了项目的部署和配置,特别适合快速迭代和中小型应用场景。
|
||||
|
||||
此架构同时利用了 **Spring WebFlux** 进行异步处理,具备响应式编程能力,以提升高并发场景下的性能。其清晰的分层和模块化设计也为未来向微服务架构演进奠定了良好基础。
|
||||
|
||||

|
||||
|
||||
**技术选型**:
|
||||
- **核心框架**: Spring Boot 3
|
||||
- **开发语言**: Java 17
|
||||
- **身份认证**: Spring Security + JWT (JSON Web Tokens)
|
||||
- **数据持久化**: 自定义JSON文件存储
|
||||
- **异步处理**: Spring Async & Events, Spring WebFlux
|
||||
- **API文档**: SpringDoc (OpenAPI 3 / Swagger)
|
||||
|
||||
#### 1.1.3 前端架构
|
||||
|
||||
前端应用是一个基于 **Vue 3** 的单页面应用(SPA),使用 **Vite** 作为构建工具。选择Vue 3是因为其优秀的性能、丰富的生态系统和渐进式的学习曲线。
|
||||
- **UI组件库**: **Element Plus**,提供了一套高质量、符合设计规范的UI组件,加速了界面的开发。
|
||||
- **状态管理**: **Pinia**,作为Vue 3官方推荐的状态管理库,它提供了极简的API和强大的类型推断支持,能有效管理复杂的应用状态。
|
||||
- **路由管理**: **Vue Router**,负责管理前端页面的跳转和路由。
|
||||
|
||||
### 1.2 功能模块划分
|
||||
|
||||
系统在功能上被划分为一系列高内聚的模块,每个模块负责一块具体的业务领域。这种划分方式便于团队分工和独立开发。
|
||||
|
||||
| 核心模块 | 主要职责 | 关键功能点 |
|
||||
| ------------------ | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| **认证与授权模块** | 管理所有用户的身份认证和访问权限 | - 用户注册/登录/登出<br>- JWT令牌生成与验证<br>- 密码重置<br>- 基于角色的访问控制(RBAC) |
|
||||
| **用户与人员管理模块** | 维护系统中的所有用户账户及其信息 | - 用户信息的增、删、改、查<br>- 用户角色分配与变更<br>- 用户状态管理(激活/禁用) |
|
||||
| **反馈管理模块** | 处理来自外部和内部的环境问题反馈 | - 接收公众/认证用户的反馈<br>- 集成AI进行内容预审核<br>- 人工审核与处理<br>- 反馈状态跟踪与统计 |
|
||||
| **任务管理模块** | 对具体工作任务进行全生命周期管理 | - 从反馈创建任务<br>- 任务分配给网格员<br>- 任务状态(分配、执行、完成)跟踪<br>- 任务审核与结果归档 |
|
||||
| **网格与地图模块** | 对地理空间进行网格化管理,并提供路径支持 | - 地理网格的定义与划分<br>- 网格员与网格的关联<br>- **A\*寻路算法**服务,优化任务路径 |
|
||||
| **决策支持模块** | 为管理层提供数据洞察和可视化报告 | - 核心业务指标(KPI)统计<br>- AQI、任务完成率等数据的可视化<br>- 生成反馈热力图 |
|
||||
| **个人中心模块** | 为登录用户提供个性化的信息管理和查询功能 | - 查看/修改个人资料<br>- 查询个人提交历史<br>- 查看个人操作日志 |
|
||||
|
||||

|
||||
|
||||
## 2. 详细设计
|
||||
|
||||
### 2.1 数据持久化设计 (JSON文件)
|
||||
|
||||
系统不使用传统数据库,所有数据均以JSON文件的形式存储在服务器的文件系统中。每个核心模型对应一个JSON文件。这种设计简化了部署,但也对数据一致性和并发控制提出了更高的要求。
|
||||
|
||||
#### 2.1.1 `users.json` - 用户账户数据
|
||||
|
||||
存储所有系统用户的信息,包括登录凭证、角色和个人资料。
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| --------------------- | ----------------- | ------------------------ | ---------------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 用户的唯一标识符 |
|
||||
| `name` | `String` | 非空 | 用户姓名 |
|
||||
| `phone` | `String` | 非空, **唯一** | 手机号码,可用于登录 |
|
||||
| `email` | `String` | 非空, **唯一** | 电子邮箱,可用于登录 |
|
||||
| `password` | `String` | 非空, 长度>=8 | 加密后的用户密码 |
|
||||
| `gender` | `String` | (ENUM) | 性别 (MALE, FEMALE, OTHER) |
|
||||
| `role` | `String` | (ENUM) | 用户角色 (ADMIN, SUPERVISOR, GRID_WORKER等) |
|
||||
| `status` | `String` | 非空, (ENUM) | 账户状态 (ACTIVE, INACTIVE, SUSPENDED) |
|
||||
| `grid_x` | `Number` | | 关联的网格X坐标 (主要用于网格员) |
|
||||
| `grid_y` | `Number` | | 关联的网格Y坐标 (主要用于网格员) |
|
||||
| `region` | `String` | | 所属区域或地区 |
|
||||
| `level` | `String` | (ENUM) | 用户等级 (JUNIOR, SENIOR, EXPERT) |
|
||||
| `skills` | `Array` | | 技能列表 (JSON数组格式的字符串) |
|
||||
| `enabled` | `Boolean` | 非空, 默认 `true` | 账户是否启用 |
|
||||
| `current_latitude` | `Number` | | 当前纬度坐标 (用于实时定位) |
|
||||
| `current_longitude` | `Number` | | 当前经度坐标 (用于实时定位) |
|
||||
| `failed_login_attempts` | `Number` | 默认 `0` | 连续失败登录次数 |
|
||||
| `lockout_end_time` | `String` | | 账户锁定截止时间 |
|
||||
| `created_at` | `String` | 非空 | 记录创建时间 |
|
||||
| `updated_at` | `String` | 非空 | 记录最后更新时间 |
|
||||
|
||||
#### 2.1.2 `feedback.json` - 环境问题反馈数据
|
||||
|
||||
存储所有由用户(包括公众)提交的环境问题反馈。
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| ---------------- | --------------- | ------------------------ | ---------------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 反馈的唯一标识符 |
|
||||
| `event_id` | `String` | 非空, **唯一** | 人类可读的事件ID |
|
||||
| `title` | `String` | 非空 | 反馈标题 |
|
||||
| `description` | `String` | | 问题详细描述 |
|
||||
| `pollution_type` | `String` | 非空, (ENUM) | 污染类型 (AIR, WATER, SOIL, NOISE) |
|
||||
| `severity_level` | `String` | 非空, (ENUM) | 严重程度 (LOW, MEDIUM, HIGH, CRITICAL) |
|
||||
| `status` | `String` | 非空, (ENUM) | 反馈状态 (PENDING_REVIEW, PROCESSED等) |
|
||||
| `text_address` | `String` | | 文字描述的地址 |
|
||||
| `grid_x` | `Number` | | 事发地网格X坐标 |
|
||||
| `grid_y` | `Number` | | 事发地网格Y坐标 |
|
||||
| `latitude` | `Number` | | 事发地纬度 |
|
||||
| `longitude` | `Number` | | 事发地经度 |
|
||||
| `submitter_id` | `Number` | 外键 (FK) -> users.id (可为空) | 提交者ID (公众提交时可为空) |
|
||||
| `created_at` | `String` | 非空 | 记录创建时间 |
|
||||
| `updated_at` | `String` | 非空 | 记录最后更新时间 |
|
||||
|
||||
#### 2.1.3 `tasks.json` - 任务数据
|
||||
|
||||
存储由反馈转化而来或手动创建的具体处理任务。
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| ---------------- | --------------- | ------------------------ | ---------------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 任务的唯一标识符 |
|
||||
| `feedback_id` | `Number` | 外键 (FK) -> feedback.id (可为空) | 关联的原始反馈ID |
|
||||
| `assignee_id` | `Number` | 外键 (FK) -> users.id (可为空) | 任务执行人(网格员)ID |
|
||||
| `created_by` | `Number` | 外键 (FK) -> users.id | 任务创建人(主管)ID |
|
||||
| `status` | `String` | 非空, (ENUM) | 任务状态 (PENDING, IN_PROGRESS, COMPLETED) |
|
||||
| `title` | `String` | | 任务标题 |
|
||||
| `description` | `String` | | 任务详细描述 |
|
||||
| `pollution_type` | `String` | (ENUM) | 污染类型 |
|
||||
| `severity_level` | `String` | (ENUM) | 严重程度 |
|
||||
| `text_address` | `String` | | 任务地点文字描述 |
|
||||
| `grid_x` | `Number` | | 任务地点网格X坐标 |
|
||||
| `grid_y` | `Number` | | 任务地点网格Y坐标 |
|
||||
| `latitude` | `Number` | | 任务地点纬度 |
|
||||
| `longitude` | `Number` | | 任务地点经度 |
|
||||
| `assigned_at` | `String` | | 任务分配时间 |
|
||||
| `completed_at` | `String` | | 任务完成时间 |
|
||||
| `created_at` | `String` | 非空 | 记录创建时间 |
|
||||
| `updated_at` | `String` | 非空 | 记录最后更新时间 |
|
||||
| `deadline` | `String` | | 任务截止日期 |
|
||||
|
||||
#### 2.1.4 `grids.json` - 业务网格数据
|
||||
|
||||
存储业务逻辑上的地理网格信息。
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| --------------- | --------------- | ------------------- | ---------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 网格的唯一标识符 |
|
||||
| `gridx` | `Number` | | 网格X坐标 |
|
||||
| `gridy` | `Number` | | 网格Y坐标 |
|
||||
| `city_name` | `String` | | 所属城市 |
|
||||
| `district_name` | `String` | | 所属区县 |
|
||||
| `description` | `String` | | 网格描述信息 |
|
||||
| `is_obstacle` | `Boolean` | 默认 `false` | 是否为障碍物(如禁区) |
|
||||
|
||||
#### 2.1.5 `assignments.json` - 任务分配记录数据
|
||||
|
||||
记录任务分配的详细信息,连接任务、分配者和执行者。
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| ---------------- | --------------- | ------------------------ | -------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 分配记录的唯一标识符 |
|
||||
| `task_id` | `Number` | 非空, 外键 (FK) -> tasks.id | 关联的任务ID |
|
||||
| `assigner_id` | `Number` | 非空, 外键 (FK) -> users.id | 分配者(主管)ID |
|
||||
| `status` | `String` | 非空, (ENUM) | 分配状态 |
|
||||
| `remarks` | `String` | | 分配备注 |
|
||||
| `assignment_time`| `String` | 非空 | 分配时间 |
|
||||
| `deadline` | `String` | | 任务截止日期 |
|
||||
|
||||
---
|
||||
*(其他辅助表如 `attachment.json`, `operation_log.json`, `map_grid.json` 等的设计将遵循类似结构)*
|
||||
|
||||
### 2.2 核心业务流程
|
||||
|
||||
本章节将结合时序图和业务规则,详细描述系统的主要业务工作流。
|
||||
|
||||
#### 2.2.1 反馈处理与任务生成流程
|
||||
|
||||
这是系统的核心业务闭环,涵盖了从问题发现到任务完成的全过程。其状态流转严格遵循预设的规则。
|
||||
|
||||
**反馈处理流程**:
|
||||
|
||||
1. **提交反馈**: 公众用户或认证用户通过API提交环境问题反馈。
|
||||
2. **进入AI审核**: 新提交的反馈初始状态为 `PENDING`,系统发布 `FeedbackSubmittedForAiReviewEvent` 事件,触发AI服务进行异步审核。反馈状态变为 `AI_REVIEWING`。
|
||||
3. **主管人工审核**: AI审核后,无论结果如何,反馈都将进入人工审核阶段。主管(Supervisor)在系统中查看待处理的反馈。
|
||||
4. **决策与流转**:
|
||||
* **批准 (APPROVED)**: 如果反馈有效,主管将其批准。系统据此发布 `TaskReadyForAssignmentEvent` 事件,表明可以基于此反馈创建任务。原反馈的状态更新为 `TASK_CREATED`。
|
||||
* **拒绝 (REJECTED)**: 如果反馈无效或重复,主管可以拒绝该反馈,并填写原因。
|
||||
|
||||
**任务处理流程**:
|
||||
|
||||
1. **创建任务**: 基于已批准的反馈,系统创建一条新任务,初始状态为 `CREATED`。
|
||||
2. **分配任务**: 主管根据网格区域、网格员负载等规则,将任务指派给特定的网格员(Grid Worker)。任务状态更新为 `ASSIGNED`。
|
||||
3. **执行任务**: 网格员接收到任务通知,接受任务后,状态变为 `IN_PROGRESS`。网格员前往现场处理。
|
||||
4. **提交结果**: 网格员完成任务后,在系统中提交工作报告。任务状态更新为 `SUBMITTED`(待审核)。
|
||||
5. **审核任务**: 主管审核已完成的任务。
|
||||
* **批准 (APPROVED)**: 任务审核通过,流程结束。
|
||||
* **拒绝 (REJECTED)**: 任务不符合要求,可将任务打回给网格员重新处理。
|
||||
|
||||
#### 2.2.2 用户认证与授权流程
|
||||
|
||||
1. **用户登录**: 用户使用邮箱/手机号和密码请求登录。
|
||||
2. **凭证验证**: 系统验证用户信息和密码的正确性。
|
||||
3. **令牌生成**: 验证通过后,系统使用JWT生成一个有时效性的 `access_token`。
|
||||
4. **访问授权**: 用户在后续的请求中,需在请求头携带此 `token`。后端通过一个安全过滤器(Filter)来解析和验证 `token`,确认用户的身份和权限,从而决定是否能访问受保护的API资源。
|
||||
|
||||
#### 2.2.3 密码重置流程
|
||||
|
||||
1. **请求重置**: 用户在登录页面点击"忘记密码",输入注册时使用的邮箱地址。
|
||||
2. **发送验证码**: 系统向该邮箱发送一封包含随机验证码的邮件。
|
||||
3. **验证与重置**: 用户在指定时间内输入收到的验证码和新密码。系统校验验证码的正确性后,更新用户在 `users.json` 文件中的密码。
|
||||
|
||||
#### 2.2.4 主要业务规则
|
||||
|
||||
- **权限控制规则**:
|
||||
1. **ADMIN**: 拥有全系统所有权限,是系统的最高管理员。
|
||||
2. **SUPERVISOR**: 负责管理网格员、审核反馈和任务,是区域的管理者。
|
||||
3. **DECISION_MAKER**: 拥有数据查看和分析权限,通常是决策层用户。
|
||||
4. **GRID_WORKER**: 负责执行被分配的任务,是系统的主要执行者。
|
||||
5. **PUBLIC**: 只能提交反馈,是系统的外部参与者。
|
||||
|
||||
- **任务分配规则**:
|
||||
1. 优先基于网格区域进行自动分配。
|
||||
2. 分配时会综合考虑网格员的当前工作负载,避免分配不均。
|
||||
3. 标记为"紧急"的反馈所生成的任务,拥有更高的分配优先级。
|
||||
4. 主管可以对已分配的任务进行手动干预和重新分配。
|
||||
|
||||
- **反馈处理规则**:
|
||||
1. 所有反馈提交后,首先由AI服务进行预审核和内容分析。
|
||||
2. 系统会检测可能重复的反馈,并提示审核人员进行合并处理。
|
||||
3. 紧急反馈(如严重等级为`CRITICAL`)会被优先展示给审核人员。
|
||||
|
||||
### 2.3 API接口设计
|
||||
|
||||
本章节详细定义了系统各模块的API接口,包括认证、任务管理、数据上报等。
|
||||
|
||||
#### 2.3.1 认证接口 (`/api/auth`)
|
||||
|
||||
处理用户注册、登录、登出和密码管理等功能。
|
||||
|
||||
| 序号 | 接口路径 | HTTP方法 | 功能描述 | 请求参数 (Body/Query) | 成功响应 (Body) |
|
||||
|----|-------------------------------|----------|------------------------|-----------------------------------------------------------|---------------------------------|
|
||||
| 1 | `/api/auth/signup` | `POST` | 用户注册 | `SignUpRequest` (name, phone, email, password, role, etc.) | `201 CREATED` |
|
||||
| 2 | `/api/auth/login` | `POST` | 用户登录 | `LoginRequest` (email/phone, password) | `JwtAuthenticationResponse` (token) |
|
||||
| 3 | `/api/auth/logout` | `POST` | 用户登出 | 无 | `200 OK` |
|
||||
| 4 | `/api/auth/send-verification-code` | `POST` | 发送注册验证码 | `email` (Query Param) | `200 OK` |
|
||||
| 5 | `/api/auth/send-password-reset-code` | `POST` | 发送密码重置验证码 | `email` (Query Param) | `200 OK` |
|
||||
| 6 | `/api/auth/reset-password-with-code` | `POST` | 使用验证码重置密码 | `PasswordResetWithCodeDto` (email, code, newPassword) | `200 OK` |
|
||||
|
||||
#### 2.3.2 公共接口 (`/api/public`)
|
||||
|
||||
提供给外部系统或公众使用的无需认证的接口。
|
||||
|
||||
| 序号 | 接口路径 | HTTP方法 | 功能描述 | 请求参数 (Body/Form-Data) | 成功响应 (Body) |
|
||||
|----|-----------------------|----------|--------------------|--------------------------------------------------------------|---------------------------------|
|
||||
| 1 | `/api/public/feedback` | `POST` | 提交公众反馈(带文件) | `feedback`: `PublicFeedbackRequest` (JSON), `files`: `MultipartFile[]` | `201 CREATED` (返回 `Feedback` 对象) |
|
||||
|
||||
#### 2.3.3 反馈管理接口 (`/api/feedback`)
|
||||
|
||||
认证用户(如主管、管理员)对环境问题反馈进行查询、统计和处理。
|
||||
|
||||
| 序号 | 接口路径 | HTTP方法 | 功能描述 | 权限 | 请求参数 (Body/Query) | 成功响应 (Body) |
|
||||
|----|-----------------------------|----------|----------------------------------|------------------------------------|-------------------------------------------------------------------------------------------------------------------|---------------------------------------|
|
||||
| 1 | `/api/feedback/submit` | `POST` | 认证用户提交反馈(带文件) | `isAuthenticated()` | `feedback`: `FeedbackSubmissionRequest` (JSON), `files`: `MultipartFile[]` | `201 CREATED` (返回 `Feedback` 对象) |
|
||||
| 2 | `/api/feedback` | `GET` | 获取所有反馈(分页+多条件过滤) | `isAuthenticated()` | `status`, `pollutionType`, `severityLevel`, `cityName`, `districtName`, `startDate`, `endDate`, `keyword`, `pageable` | `Page<FeedbackResponseDTO>` |
|
||||
| 3 | `/api/feedback/{id}` | `GET` | 根据ID获取反馈详情 | `ADMIN`, `SUPERVISOR`, `DECISION_MAKER` | `id` (Path Var) | `FeedbackResponseDTO` |
|
||||
| 4 | `/api/feedback/stats` | `GET` | 获取反馈统计数据 | `isAuthenticated()` | 无 | `FeedbackStatsResponse` |
|
||||
| 5 | `/api/feedback/{id}/process`| `POST` | 处理反馈(如审核通过) | `ADMIN`, `SUPERVISOR` | `id` (Path Var), `ProcessFeedbackRequest` (Body) | `FeedbackResponseDTO` |
|
||||
|
||||
#### 2.3.4 任务管理接口 (`/api/management/tasks`)
|
||||
|
||||
主管和管理员用于任务的全生命周期管理,包括创建、分配、查询和审批。
|
||||
|
||||
| 序号 | 接口路径 | HTTP方法 | 功能描述 | 权限 | 请求参数 (Body/Query) | 成功响应 (Body) |
|
||||
|----|-----------------------------------------|----------|----------------------------------|------------------------------------|--------------------------------------------------------------------------------------------|---------------------------------|
|
||||
| 1 | `/api/management/tasks` | `GET` | 获取任务列表(分页+多条件过滤) | `ADMIN`, `SUPERVISOR`, `DECISION_MAKER` | `status`, `assigneeId`, `severity`, `pollutionType`, `startDate`, `endDate`, `pageable` | `List<TaskSummaryDTO>` |
|
||||
| 2 | `/api/management/tasks/{taskId}` | `GET` | 获取任务详情 | `SUPERVISOR` | `taskId` (Path Var) | `TaskDetailDTO` |
|
||||
| 3 | `/api/management/tasks` | `POST` | 手动创建新任务 | `SUPERVISOR` | `TaskCreationRequest` (Body) | `201 CREATED` (返回 `TaskDetailDTO`) |
|
||||
| 4 | `/api/management/tasks/{taskId}/assign` | `POST` | 分配任务给网格员 | `SUPERVISOR` | `taskId` (Path Var), `TaskAssignmentRequest` (Body) | `TaskSummaryDTO` |
|
||||
| 5 | `/api/management/tasks/{taskId}/review` | `POST` | 审核任务 | `SUPERVISOR` | `taskId` (Path Var), `TaskApprovalRequest` (Body) | `TaskDetailDTO` |
|
||||
| 6 | `/api/management/tasks/{taskId}/cancel` | `POST` | 取消任务 | `SUPERVISOR` | `taskId` (Path Var) | `TaskDetailDTO` |
|
||||
| 7 | `/api/management/tasks/feedback` | `GET` | 获取待处理的反馈列表 | `SUPERVISOR`, `ADMIN` | 无 | `List<Feedback>` |
|
||||
| 8 | `/api/management/tasks/feedback/{feedbackId}/create-task` | `POST` | 从反馈创建任务 | `SUPERVISOR` | `feedbackId` (Path Var), `TaskFromFeedbackRequest` (Body) | `201 CREATED` (返回 `TaskDetailDTO`) |
|
||||
| 9 | `/api/management/tasks/{taskId}/approve`| `POST` | 批准任务(完成) | `ADMIN` | `taskId` (Path Var) | `TaskDetailDTO` |
|
||||
| 10 | `/api/management/tasks/{taskId}/reject` | `POST` | 拒绝任务(打回) | `ADMIN` | `taskId` (Path Var), `TaskRejectionRequest` (Body) | `TaskDetailDTO` |
|
||||
|
||||
#### 2.3.5 网格员任务接口 (`/api/worker`)
|
||||
|
||||
网格员用于查看和处理自己被分配的任务。
|
||||
|
||||
| 序号 | 接口路径 | HTTP方法 | 功能描述 | 权限 | 请求参数 (Body/Query) | 成功响应 (Body) |
|
||||
|----|---------------------------------|----------|------------------------|---------------|-----------------------------------------------------------|----------------------------|
|
||||
| 1 | `/api/worker` | `GET` | 获取我被分配的任务列表 | `GRID_WORKER` | `status` (Query Param), `pageable` | `Page<TaskSummaryDTO>` |
|
||||
| 2 | `/api/worker/{taskId}` | `GET` | 获取任务详情 | `GRID_WORKER` | `taskId` (Path Var) | `TaskDetailDTO` |
|
||||
| 3 | `/api/worker/{taskId}/accept` | `POST` | 接受任务 | `GRID_WORKER` | `taskId` (Path Var) | `TaskSummaryDTO` |
|
||||
| 4 | `/api/worker/{taskId}/submit` | `POST` | 提交任务完成情况(带文件) | `GRID_WORKER` | `taskId` (Path Var), `comments` (Form Part), `files` (Form Part) | `TaskSummaryDTO` |
|
||||
|
||||
#### 2.3.6 人员管理接口 (`/api/personnel`)
|
||||
|
||||
管理员用于管理系统中的所有用户账户。
|
||||
|
||||
| 序号 | 接口路径 | HTTP方法 | 功能描述 | 权限 | 请求参数 (Body/Query) | 成功响应 (Body) |
|
||||
|----|---------------------------------|------------|------------------------------|---------|-----------------------------------------------------------|---------------------------------|
|
||||
| 1 | `/api/personnel/users` | `POST` | 创建新用户 | `ADMIN` | `UserCreationRequest` (Body) | `201 CREATED` (返回 `UserAccount` 对象) |
|
||||
| 2 | `/api/personnel/users` | `GET` | 获取用户列表(分页+过滤) | `ADMIN`, `GRID_WORKER` | `role`, `name` (Query Params), `pageable` | `PageDTO<UserAccount>` |
|
||||
| 3 | `/api/personnel/users/{userId}` | `GET` | 根据ID获取用户详情 | `ADMIN` | `userId` (Path Var) | `UserAccount` |
|
||||
| 4 | `/api/personnel/users/{userId}` | `PATCH` | 更新用户信息(部分更新) | `ADMIN` | `userId` (Path Var), `UserUpdateRequest` (Body) | `UserAccount` |
|
||||
| 5 | `/api/personnel/users/{userId}/role` | `PUT` | 更新用户角色 | `ADMIN` | `userId` (Path Var), `UserRoleUpdateRequest` (Body) | `UserAccount` |
|
||||
| 6 | `/api/personnel/users/{userId}` | `DELETE` | 删除用户 | `ADMIN` | `userId` (Path Var) | `204 NO_CONTENT` |
|
||||
|
||||
#### 2.3.7 网格管理接口 (`/api/grids`)
|
||||
|
||||
管理员用于管理地理网格、分配网格员和查看统计数据。
|
||||
|
||||
| 序号 | 接口路径 | HTTP方法 | 功能描述 | 权限 | 请求参数 (Body/Query) | 成功响应 (Body) |
|
||||
|----|-----------------------------------------------|----------|----------------------------------|----------------------------------------|-------------------------------------------------|---------------------------------|
|
||||
| 1 | `/api/grids` | `GET` | 获取所有网格列表 | `ADMIN`, `DECISION_MAKER`, `GRID_WORKER` | 无 | `List<Grid>` |
|
||||
| 2 | `/api/grids/{id}` | `PATCH` | 更新网格信息(如设为障碍物) | `ADMIN` | `id` (Path Var), `GridUpdateRequest` (Body) | `Grid` |
|
||||
| 3 | `/api/grids/coverage` | `GET` | 获取网格覆盖率统计 | `ADMIN` | 无 | `List<GridCoverageDTO>` |
|
||||
| 4 | `/api/grids/{gridId}/assign` | `POST` | 分配网格员到指定网格(通过ID) | `ADMIN` | `gridId` (Path Var), `userId` (Body) | `200 OK` |
|
||||
| 5 | `/api/grids/{gridId}/unassign` | `POST` | 从网格中移除网格员(通过ID) | `ADMIN` | `gridId` (Path Var) | `200 OK` |
|
||||
| 6 | `/api/grids/coordinates/{gridX}/{gridY}/assign` | `POST` | 分配网格员到指定网格(通过坐标) | `ADMIN`, `GRID_WORKER` | `gridX`, `gridY` (Path Vars), `userId` (Body) | `200 OK` |
|
||||
| 7 | `/api/grids/coordinates/{gridX}/{gridY}/unassign`| `POST`| 从网格中移除网格员(通过坐标) | `ADMIN`, `GRID_WORKER` | `gridX`, `gridY` (Path Vars) | `200 OK` |
|
||||
|
||||
#### 2.3.8 仪表盘数据接口 (`/api/dashboard`)
|
||||
|
||||
为前端仪表盘提供各种聚合和统计数据,用于决策支持和系统状态监控。
|
||||
|
||||
| 序号 | 接口路径 | HTTP方法 | 功能描述 | 权限 | 请求参数 (Body/Query) | 成功响应 (Body) |
|
||||
|----|------------------------------------------|----------|----------------------------------|---------------------------|---------------------------|---------------------------------------|
|
||||
| 1 | `/api/dashboard/stats` | `GET` | 获取仪表盘核心统计数据 | `DECISION_MAKER`, `ADMIN` | 无 | `DashboardStatsDTO` |
|
||||
| 2 | `/api/dashboard/reports/aqi-distribution`| `GET` | 获取AQI等级分布数据 | `DECISION_MAKER`, `ADMIN` | 无 | `List<AqiDistributionDTO>` |
|
||||
| 3 | `/api/dashboard/reports/monthly-exceedance-trend` | `GET` | 获取月度超标趋势数据 | `DECISION_MAKER`, `ADMIN` | 无 | `List<TrendDataPointDTO>` |
|
||||
| 4 | `/api/dashboard/reports/grid-coverage` | `GET` | 获取网格覆盖情况数据 | `DECISION_MAKER`, `ADMIN` | 无 | `List<GridCoverageDTO>` |
|
||||
| 5 | `/api/dashboard/map/heatmap` | `GET` | 获取反馈热力图数据 | `DECISION_MAKER`, `ADMIN` | 无 | `List<HeatmapPointDTO>` |
|
||||
| 6 | `/api/dashboard/reports/pollution-stats` | `GET` | 获取污染物统计报告数据 | `DECISION_MAKER`, `ADMIN` | 无 | `List<PollutionStatsDTO>` |
|
||||
| 7 | `/api/dashboard/reports/task-completion-stats` | `GET` | 获取任务完成情况统计数据 | `DECISION_MAKER`, `ADMIN` | 无 | `TaskStatsDTO` |
|
||||
| 8 | `/api/dashboard/map/aqi-heatmap` | `GET` | 获取AQI热力图数据 | `DECISION_MAKER`, `ADMIN` | 无 | `List<AqiHeatmapPointDTO>` |
|
||||
| 9 | `/api/dashboard/thresholds` | `GET` | 获取所有污染物阈值设置 | `DECISION_MAKER`, `ADMIN` | 无 | `List<PollutantThresholdDTO>` |
|
||||
| 10 | `/api/dashboard/thresholds/{pollutantName}` | `GET` | 获取指定污染物的阈值设置 | `DECISION_MAKER`, `ADMIN` | `pollutantName` (Path Var)| `PollutantThresholdDTO` |
|
||||
| 11 | `/api/dashboard/thresholds` | `POST` | 保存污染物阈值设置 | `ADMIN` | `PollutantThresholdDTO` (Body) | `PollutantThresholdDTO` |
|
||||
| 12 | `/api/dashboard/reports/pollutant-monthly-trends` | `GET` | 获取各污染物月度趋势数据 | `DECISION_MAKER`, `ADMIN` | 无 | `Map<String, List<TrendDataPointDTO>>` |
|
||||
|
||||
#### 2.3.9 其他接口
|
||||
|
||||
包含文件处理、操作日志、个人资料等辅助功能的接口。
|
||||
|
||||
| 序号 | 接口路径 | HTTP方法 | 功能描述 | 权限 | 请求参数 (Body/Query) | 成功响应 (Body) |
|
||||
|----|--------------------------|----------|------------------------|------|---------------------------|---------------------------------|
|
||||
| 1 | `/api/files/{filename}` | `GET` | 下载/预览文件(下载) | `isAuthenticated()` | `filename` (Path Var) | `Resource` (文件流) |
|
||||
| 2 | `/api/view/{filename}` | `GET` | 下载/预览文件(内联预览) | `isAuthenticated()` | `filename` (Path Var) | `Resource` (文件流) |
|
||||
| 3 | `/api/logs/my-logs` | `GET` | 获取当前用户的操作日志 | `isAuthenticated()` | 无 | `List<OperationLogDTO>` |
|
||||
| 4 | `/api/logs` | `GET` | 获取所有操作日志(可过滤) | `ADMIN` | `operationType`, `userId`, `startTime`, `endTime` | `List<OperationLogDTO>` |
|
||||
| 5 | `/api/me/feedback` | `GET` | 获取当前用户的反馈历史 | `isAuthenticated()` | `pageable` | `List<UserFeedbackSummaryDTO>` |
|
||||
| 6 | `/api/supervisor/reviews`| `GET` | 获取待审核的反馈列表 | `SUPERVISOR`, `ADMIN` | 无 | `List<Feedback>` |
|
||||
| 7 | `/api/supervisor/reviews/{feedbackId}/approve` | `POST` | 审核通过反馈 | `SUPERVISOR`, `ADMIN` | `feedbackId` (Path Var) | `200 OK` |
|
||||
| 8 | `/api/supervisor/reviews/{feedbackId}/reject` | `POST` | 审核拒绝反馈 | `SUPERVISOR`, `ADMIN` | `feedbackId` (Path Var), `RejectFeedbackRequest` (Body) | `200 OK` |
|
||||
| 9 | `/api/map/grid` | `GET` | 获取完整地图网格数据 | `isAuthenticated()` | 无 | `List<MapGrid>` |
|
||||
| 10 | `/api/map/grid` | `POST` | 创建/更新单个网格单元 | `ADMIN` | `MapGrid` (Body) | `MapGrid` |
|
||||
| 11 | `/api/map/initialize` | `POST` | 初始化地图网格 | `ADMIN` | `width`, `height` (Query) | `String` (Message) |
|
||||
| 12 | `/api/pathfinding/find` | `POST` | A*寻路算法查找路径 | `isAuthenticated()` | `PathfindingRequest` (Body) | `List<Point>` |
|
||||
| 13 | `/api/tasks/unassigned` | `GET` | 获取未分配的任务列表 | `ADMIN`, `SUPERVISOR` | 无 | `List<Feedback>` |
|
||||
| 14 | `/api/tasks/grid-workers`| `GET` | 获取可用的网格员列表 | `ADMIN`, `SUPERVISOR` | 无 | `List<UserAccount>` |
|
||||
| 15 | `/api/tasks/assign` | `POST` | 分配任务给网格员 | `ADMIN`, `SUPERVISOR` | `AssignmentRequest` (Body)| `Assignment` |
|
||||
|
||||
#### 2.3.10 API 设计原则与最佳实践
|
||||
|
||||
为保证API的规范性、安全性和易用性,系统在设计和实现中遵循了以下原则:
|
||||
|
||||
1. **统一响应格式**: 所有API响应都封装在一个标准结构中,包含成功/失败状态、数据负载、消息和时间戳,便于前端统一处理。分页查询则返回包含分页信息(总数、总页数等)的标准化分页对象。
|
||||
2. **细粒度权限控制**: 系统利用Spring Security的 `@PreAuthorize` 注解在方法级别上实现了细粒度的权限控制,确保即使用户通过了认证,也只能访问其角色被授权的特定资源和操作。
|
||||
3. **严格的参数验证**: 所有接收输入的API端点(特别是写操作)都使用了JSR-303验证注解(如 `@Valid`, `@NotBlank`, `@Email`)对请求体和参数进行严格校验,从入口处保证了数据的合法性和完整性。
|
||||
4. **清晰的API文档**: 通过集成SpringDoc,为所有公共API生成了遵循OpenAPI 3.0规范的交互式文档(Swagger UI),包含了清晰的描述、参数说明和响应示例。
|
||||
5. **全面的日志记录**: 使用 `@Slf4j` 在关键业务流程、成功操作及异常情况处记录了详细日志,便于系统监控、问题排查和安全审计。
|
||||
|
||||
---
|
||||
|
||||
## 2.4 架构特性与外部集成
|
||||
|
||||
除了核心的业务功能,系统在架构层面采用了一些现代化的设计来实现高性能和高可扩展性,并集成了一些外部服务来增强功能。
|
||||
|
||||
### 2.4.1 事件驱动架构 (EDA)
|
||||
|
||||
系统内部采用轻量级的事件驱动模型(基于Spring Events)来实现关键业务逻辑的解耦。
|
||||
|
||||
- **核心事件**:
|
||||
1. `FeedbackSubmittedForAiReviewEvent`: 当一个新反馈被提交后发布,用于触发AI服务的异步分析。
|
||||
2. `TaskReadyForAssignmentEvent`: 当一个反馈被批准并可以转化为任务时发布。
|
||||
3. `AuthenticationSuccessEvent`: 用户成功登录时发布,可用于记录日志或更新用户状态。
|
||||
4. `AuthenticationFailureEvent`: 用户登录失败时发布,用于监控恶意尝试。
|
||||
|
||||
- **优势**:
|
||||
- **解耦**: 事件的发布者和消费者之间没有直接依赖,易于扩展新功能。
|
||||
- **异步化**: 许多耗时的操作(如AI分析、邮件发送)可以通过异步监听事件来完成,避免阻塞主线程,提升用户体验。
|
||||
|
||||
### 2.4.2 外部服务集成
|
||||
|
||||
- **AI服务**:
|
||||
- **服务商**: 火山引擎 (Volcano Engine)
|
||||
- **核心功能**: 用于反馈内容的智能分析,包括自动提取关键词、评估严重等级和进行初步分类,为人工审核提供决策支持。
|
||||
|
||||
- **邮件服务**:
|
||||
- **服务商**: 163 SMTP
|
||||
- **核心功能**: 用于发送系统通知类邮件,如用户注册、密码重置验证码、任务分配通知等。
|
||||
|
||||
### 2.4.3 性能与缓存
|
||||
|
||||
为了提升系统响应速度和处理高并发请求的能力,系统内置了基于内存的缓存机制。
|
||||
|
||||
- **缓存技术**: Google Guava Cache
|
||||
- **缓存内容**:
|
||||
- **用户数据**: 缓存频繁访问的用户信息。
|
||||
- **配置数据**: 如污染物阈值等不经常变动的系统配置。
|
||||
- **热点数据**: 如热门网格的统计信息。
|
||||
- **策略**: 缓存设置了合理的过期时间和大小限制,以保证数据的一致性和内存的有效利用。
|
||||
@@ -1,252 +0,0 @@
|
||||
# 系统设计文档
|
||||
|
||||
本文档旨在详细阐述环境监督系统(EMS)的系统架构、功能模块和实现细节,为开发、测试和维护提供指导。
|
||||
|
||||
## 1. 总体设计
|
||||
|
||||
总体设计旨在从宏观上描述系统的架构、设计原则和核心组成部分,为后续的详细设计奠定基础。
|
||||
|
||||
### 1.1 系统架构设计
|
||||
|
||||
#### 1.1.1 架构选型与原则
|
||||
|
||||
本系统采用业界成熟的 **前后端分离** 架构。该架构将用户界面(前端)与业务逻辑处理(后端)彻底分离,二者通过定义良好的 **RESTful API** 进行通信。这种模式的优势在于:
|
||||
- **并行开发**: 前后端团队可以并行开发、测试和部署,只需遵守统一的API约定,从而显著提升开发效率。
|
||||
- **技术栈灵活性**: 前后端可以独立选择最适合自身场景的技术栈,便于未来对任一端进行技术升级或重构。
|
||||
- **关注点分离**: 前端专注于用户体验和界面呈现,后端专注于业务逻辑、数据处理和系统安全,使得系统各部分职责更清晰,更易于维护。
|
||||
|
||||
在架构设计中,我们遵循了以下核心原则:
|
||||
- **高内聚,低耦合**: 将相关功能组织在独立的模块中,并最小化模块间的依赖。
|
||||
- **可扩展性**: 架构设计应能方便地横向扩展(增加更多服务器实例)和纵向扩展(增加新功能模块)。
|
||||
- **安全性**: 从设计之初就考虑认证、授权、数据加密和输入验证等安全问题。
|
||||
- **可维护性**: 采用清晰的代码分层、统一的编码规范和完善的文档,降低长期维护成本。
|
||||
|
||||
#### 1.1.2 后端架构
|
||||
|
||||
后端服务基于 **Spring Boot 3** 和 **Java 17** 构建,这是一个现代化、高性能的组合。其内部采用了经典的三层分层架构模式:
|
||||
|
||||
- **表现层 (Controller Layer)**: 负责接收前端的HTTP请求,使用 `@RestController` 定义RESTful API。此层负责解析HTTP请求、验证输入参数(使用JSR-303注解),并调用业务逻辑层处理请求,但不包含任何业务逻辑。
|
||||
- **业务逻辑层 (Service Layer)**: 系统的核心,使用 `@Service` 注解。它封装了所有的业务规则、流程控制和复杂计算。它通过调用数据访问层来操作数据,并通过事件发布等机制与其他服务进行解耦交互。
|
||||
- **数据访问层 (Repository/Persistence Layer)**: 负责与数据存储进行交互。本项目独创性地采用了一套基于JSON文件的持久化方案。通过自定义的`JsonStorageService`和一系列Repository类,模拟了类似JPA的接口,实现了对`users.json`, `tasks.json`等核心数据文件的增删改查(CRUD)操作。选择JSON文件存储简化了项目的部署和配置,特别适合快速迭代和中小型应用场景。
|
||||
|
||||
此架构同时利用了 **Spring WebFlux** 进行异步处理,具备响应式编程能力,以提升高并发场景下的性能。其清晰的分层和模块化设计也为未来向微服务架构演进奠定了良好基础。
|
||||
|
||||

|
||||
|
||||
#### 1.1.3 前端架构
|
||||
|
||||
前端应用是一个基于 **Vue 3** 的单页面应用(SPA),使用 **Vite** 作为构建工具。选择Vue 3是因为其优秀的性能、丰富的生态系统和渐进式的学习曲线。
|
||||
- **UI组件库**: **Element Plus**,提供了一套高质量、符合设计规范的UI组件,加速了界面的开发。
|
||||
- **状态管理**: **Pinia**,作为Vue 3官方推荐的状态管理库,它提供了极简的API和强大的类型推断支持,能有效管理复杂的应用状态。
|
||||
- **路由管理**: **Vue Router**,负责管理前端页面的跳转和路由。
|
||||
|
||||
### 1.2 功能模块划分
|
||||
|
||||
系统在功能上被划分为一系列高内聚的模块,每个模块负责一块具体的业务领域。这种划分方式便于团队分工和独立开发。
|
||||
|
||||
| 核心模块 | 主要职责 | 关键功能点 |
|
||||
| ------------------ | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| **认证与授权模块** | 管理所有用户的身份认证和访问权限 | - 用户注册/登录/登出<br>- JWT令牌生成与验证<br>- 密码重置<br>- 基于角色的访问控制(RBAC) |
|
||||
| **用户与人员管理模块** | 维护系统中的所有用户账户及其信息 | - 用户信息的增、删、改、查<br>- 用户角色分配与变更<br>- 用户状态管理(激活/禁用) |
|
||||
| **反馈管理模块** | 处理来自外部和内部的环境问题反馈 | - 接收公众/认证用户的反馈<br>- 集成AI进行内容预审核<br>- 人工审核与处理<br>- 反馈状态跟踪与统计 |
|
||||
| **任务管理模块** | 对具体工作任务进行全生命周期管理 | - 从反馈创建任务<br>- 任务分配给网格员<br>- 任务状态(分配、执行、完成)跟踪<br>- 任务审核与结果归档 |
|
||||
| **网格与地图模块** | 对地理空间进行网格化管理,并提供路径支持 | - 地理网格的定义与划分<br>- 网格员与网格的关联<br>- **A\*寻路算法**服务,优化任务路径 |
|
||||
| **决策支持模块** | 为管理层提供数据洞察和可视化报告 | - 核心业务指标(KPI)统计<br>- AQI、任务完成率等数据的可视化<br>- 生成反馈热力图 |
|
||||
| **个人中心模块** | 为登录用户提供个性化的信息管理和查询功能 | - 查看/修改个人资料<br>- 查询个人提交历史<br>- 查看个人操作日志 |
|
||||
|
||||

|
||||
|
||||
## 2. 详细设计
|
||||
|
||||
### 2.1 功能模块详细设计
|
||||
|
||||
本章节将对核心功能模块的内部设计进行更深入的阐述。
|
||||
|
||||
#### 2.1.1 反馈管理模块
|
||||
|
||||
该模块是系统与用户交互的核心,负责处理所有环境问题的上报和初步处理。
|
||||
- **主要控制器**: `FeedbackController`, `PublicController`
|
||||
- **核心服务**: `FeedbackService`, `FeedbackAiReviewService`
|
||||
- **关键DTO**: `FeedbackSubmissionRequest`, `FeedbackResponseDTO`, `ProcessFeedbackRequest`
|
||||
- **设计要点**:
|
||||
- 采用 `@RequestPart` 同时接收JSON数据和文件上传,实现了富文本内容的反馈提交。
|
||||
- 通过发布 `FeedbackSubmittedForAiReviewEvent` 事件,将AI审核流程解耦并异步化,提高了API的响应速度。
|
||||
- 提供了强大的多条件动态查询能力,支持按状态、类型、严重等级、地理位置和时间范围进行组合过滤。
|
||||
|
||||
#### 2.1.2 任务管理模块
|
||||
|
||||
该模块负责将已批准的反馈转化为具体的可执行任务,并对其进行全生命周期管理。
|
||||
- **主要控制器**: `TaskManagementController`, `TaskAssignmentController`, `GridWorkerTaskController`
|
||||
- **核心服务**: `TaskService`, `TaskAssignmentService`
|
||||
- **关键DTO**: `TaskCreationRequest`, `TaskDetailDTO`, `TaskAssignmentRequest`, `TaskSummaryDTO`
|
||||
- **设计要点**:
|
||||
- 清晰的状态机管理任务的生命周期(CREATED → ASSIGNED → IN_PROGRESS → SUBMITTED → APPROVED/REJECTED)。
|
||||
- 任务分配逻辑考虑了网格员的地理位置和当前负载,旨在实现智能化的高效分配。
|
||||
- 为主管和网格员提供了完全独立的API端点,严格分离了不同角色的操作权限。
|
||||
|
||||
### 2.2 类和对象的设计
|
||||
|
||||
本节定义了系统核心业务对象的静态结构,即类图。
|
||||
|
||||
#### 2.2.1 `Feedback` 类图
|
||||
|
||||
`Feedback` 对象是系统中最核心的数据模型之一,代表一次环境问题反馈。
|
||||
|
||||

|
||||
|
||||
### 2.3 动态模型设计
|
||||
|
||||
本节描述了系统在运行时,对象之间的交互行为。
|
||||
|
||||
#### 2.3.1 核心时序图
|
||||
|
||||
**反馈提交与处理时序图**
|
||||
|
||||
该图展示了从用户提交反馈到系统创建任务的完整交互流程。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant FeedbackController as 反馈控制器
|
||||
participant FeedbackService as 反馈服务
|
||||
participant EventPublisher as 事件发布器
|
||||
participant FeedbackAiReviewService as AI审核服务
|
||||
participant TaskService as 任务服务
|
||||
|
||||
User->>FeedbackController: POST /api/feedback/submit
|
||||
FeedbackController->>FeedbackService: submitFeedback(request, files)
|
||||
FeedbackService->>EventPublisher: publishEvent(FeedbackSubmittedEvent)
|
||||
FeedbackService-->>FeedbackController: 返回初步响应
|
||||
FeedbackController-->>User: 201 Created
|
||||
|
||||
EventPublisher-->>FeedbackAiReviewService: 异步触发
|
||||
FeedbackAiReviewService->>FeedbackAiReviewService: 调用火山引擎AI分析
|
||||
FeedbackAiReviewService->>FeedbackService: updateFeedbackStatus(AI_REVIEWED)
|
||||
|
||||
Supervisor->>FeedbackService: approveFeedback(feedbackId)
|
||||
FeedbackService->>TaskService: createTaskFromFeedback(feedback)
|
||||
TaskService-->>FeedbackService: 任务创建成功
|
||||
```
|
||||
|
||||
#### 2.3.2 核心状态图
|
||||
|
||||
**反馈状态机 (Feedback Status)**
|
||||
|
||||

|
||||
|
||||
### 2.4 算法设计
|
||||
|
||||
#### 2.4.1 A* 寻路算法
|
||||
|
||||
- **目的**: 为网格员规划从当前位置到任务目标点的最优(最短或最快)路径。
|
||||
- **输入**:
|
||||
- `startNode`: 起始点坐标。
|
||||
- `endNode`: 目标点坐标。
|
||||
- `grid`: 包含障碍物信息的地图网格数据。
|
||||
- **核心逻辑**:
|
||||
1. 维护一个开放列表(`openList`)和一个关闭列表(`closedList`)。
|
||||
2. 从 `openList` 中选取F值(G值+H值)最小的节点作为当前节点。
|
||||
- G值: 从起点到当前节点的实际代价。
|
||||
- H值: 从当前节点到终点的预估代价(启发函数,通常使用曼哈顿距离或欧氏距离)。
|
||||
3. 遍历当前节点的相邻节点,如果邻居不在`closedList`中且不是障碍物,则计算其G值和H值,并将其加入`openList`。
|
||||
4. 重复此过程,直到当前节点为目标节点,或`openList`为空。
|
||||
- **输出**: 从起点到终点的一系列坐标点,即规划好的路径。
|
||||
- **应用**: 在`PathfindingController`中通过`/api/pathfinding/find`接口暴露。
|
||||
|
||||
### 2.5 数据持久化设计
|
||||
|
||||
系统不使用传统数据库,所有数据均以JSON文件的形式存储在服务器的文件系统中。每个核心模型对应一个JSON文件。这种设计简化了部署,但也对数据一致性和并发控制提出了更高的要求。
|
||||
|
||||
#### 2.5.1 `users.json` - 用户账户数据
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| --------------------- | ----------------- | ------------------------ | ---------------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 用户的唯一标识符 |
|
||||
| `name` | `String` | 非空 | 用户姓名 |
|
||||
| `phone` | `String` | 非空, **唯一** | 手机号码,可用于登录 |
|
||||
| `email` | `String` | 非空, **唯一** | 电子邮箱,可用于登录 |
|
||||
| `password` | `String` | 非空, 长度>=8 | 加密后的用户密码 |
|
||||
| `gender` | `String` | (ENUM) | 性别 (MALE, FEMALE, OTHER) |
|
||||
| `role` | `String` | (ENUM) | 用户角色 (ADMIN, SUPERVISOR, GRID_WORKER等) |
|
||||
| `status` | `String` | 非空, (ENUM) | 账户状态 (ACTIVE, INACTIVE, SUSPENDED) |
|
||||
| `grid_x` | `Number` | | 关联的网格X坐标 (主要用于网格员) |
|
||||
| `grid_y` | `Number` | | 关联的网格Y坐标 (主要用于网格员) |
|
||||
| `region` | `String` | | 所属区域或地区 |
|
||||
| `level` | `String` | (ENUM) | 用户等级 (JUNIOR, SENIOR, EXPERT) |
|
||||
| `skills` | `Array` | | 技能列表 (JSON数组格式的字符串) |
|
||||
| `enabled` | `Boolean` | 非空, 默认 `true` | 账户是否启用 |
|
||||
| `current_latitude` | `Number` | | 当前纬度坐标 (用于实时定位) |
|
||||
| `current_longitude` | `Number` | | 当前经度坐标 (用于实时定位) |
|
||||
| `failed_login_attempts` | `Number` | 默认 `0` | 连续失败登录次数 |
|
||||
| `lockout_end_time` | `String` | | 账户锁定截止时间 |
|
||||
| `created_at` | `String` | 非空 | 记录创建时间 |
|
||||
| `updated_at` | `String` | 非空 | 记录最后更新时间 |
|
||||
|
||||
#### 2.5.2 `feedback.json` - 环境问题反馈数据
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| ---------------- | --------------- | ------------------------ | ---------------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 反馈的唯一标识符 |
|
||||
| `event_id` | `String` | 非空, **唯一** | 人类可读的事件ID |
|
||||
| `title` | `String` | 非空 | 反馈标题 |
|
||||
| `description` | `String` | | 问题详细描述 |
|
||||
| `pollution_type` | `String` | 非空, (ENUM) | 污染类型 (AIR, WATER, SOIL, NOISE) |
|
||||
| `severity_level` | `String` | 非空, (ENUM) | 严重程度 (LOW, MEDIUM, HIGH, CRITICAL) |
|
||||
| `status` | `String` | 非空, (ENUM) | 反馈状态 (PENDING_REVIEW, PROCESSED等) |
|
||||
| `text_address` | `String` | | 文字描述的地址 |
|
||||
| `grid_x` | `Number` | | 事发地网格X坐标 |
|
||||
| `grid_y` | `Number` | | 事发地网格Y坐标 |
|
||||
| `latitude` | `Number` | | 事发地纬度 |
|
||||
| `longitude` | `Number` | | 事发地经度 |
|
||||
| `submitter_id` | `Number` | 外键 (FK) -> users.id (可为空) | 提交者ID (公众提交时可为空) |
|
||||
| `created_at` | `String` | 非空 | 记录创建时间 |
|
||||
| `updated_at` | `String` | 非空 | 记录最后更新时间 |
|
||||
|
||||
#### 2.5.3 `tasks.json` - 任务数据
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| ---------------- | --------------- | ------------------------ | ---------------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 任务的唯一标识符 |
|
||||
| `feedback_id` | `Number` | 外键 (FK) -> feedback.id (可为空) | 关联的原始反馈ID |
|
||||
| `assignee_id` | `Number` | 外键 (FK) -> users.id (可为空) | 任务执行人(网格员)ID |
|
||||
| `created_by` | `Number` | 外键 (FK) -> users.id | 任务创建人(主管)ID |
|
||||
| `status` | `String` | 非空, (ENUM) | 任务状态 (PENDING, IN_PROGRESS, COMPLETED) |
|
||||
| `title` | `String` | | 任务标题 |
|
||||
| `description` | `String` | | 任务详细描述 |
|
||||
| `pollution_type` | `String` | (ENUM) | 污染类型 |
|
||||
| `severity_level` | `String` | (ENUM) | 严重程度 |
|
||||
| `text_address` | `String` | | 任务地点文字描述 |
|
||||
| `grid_x` | `Number` | | 任务地点网格X坐标 |
|
||||
| `grid_y` | `Number` | | 任务地点网格Y坐标 |
|
||||
| `latitude` | `Number` | | 任务地点纬度 |
|
||||
| `longitude` | `Number` | | 任务地点经度 |
|
||||
| `assigned_at` | `String` | | 任务分配时间 |
|
||||
| `completed_at` | `String` | | 任务完成时间 |
|
||||
| `created_at` | `String` | 非空 | 记录创建时间 |
|
||||
| `updated_at` | `String` | 非空 | 记录最后更新时间 |
|
||||
| `deadline` | `String` | | 任务截止日期 |
|
||||
|
||||
#### 2.5.4 `grids.json` - 业务网格数据
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| --------------- | --------------- | ------------------- | ---------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 网格的唯一标识符 |
|
||||
| `gridx` | `Number` | | 网格X坐标 |
|
||||
| `gridy` | `Number` | | 网格Y坐标 |
|
||||
| `city_name` | `String` | | 所属城市 |
|
||||
| `district_name` | `String` | | 所属区县 |
|
||||
| `description` | `String` | | 网格描述信息 |
|
||||
| `is_obstacle` | `Boolean` | 默认 `false` | 是否为障碍物(如禁区) |
|
||||
|
||||
#### 2.5.5 `assignments.json` - 任务分配记录数据
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| ---------------- | --------------- | ------------------------ | -------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 分配记录的唯一标识符 |
|
||||
| `task_id` | `Number` | 非空, 外键 (FK) -> tasks.id | 关联的任务ID |
|
||||
| `assigner_id` | `Number` | 非空, 外键 (FK) -> users.id | 分配者(主管)ID |
|
||||
| `status` | `String` | 非空, (ENUM) | 分配状态 |
|
||||
| `remarks` | `String` | | 分配备注 |
|
||||
| `assignment_time`| `String` | 非空 | 分配时间 |
|
||||
| `deadline` | `String` | | 任务截止日期 |
|
||||
```
|
||||
@@ -1,325 +0,0 @@
|
||||
# 系统设计文档
|
||||
|
||||
本文档旨在详细阐述环境监督系统(EMS)的系统架构、功能模块和实现细节,为开发、测试和维护提供指导。
|
||||
|
||||
## 1. 总体设计
|
||||
|
||||
总体设计旨在从宏观上描述系统的架构、设计原则和核心组成部分,为后续的详细设计奠定基础。
|
||||
|
||||
### 1.1 系统架构设计
|
||||
|
||||
#### 1.1.1 架构选型与原则
|
||||
|
||||
本系统采用业界成熟的 **前后端分离** 架构。该架构将用户界面(前端)与业务逻辑处理(后端)彻底分离,二者通过定义良好的 **RESTful API** 进行通信。这种模式的优势在于:
|
||||
- **并行开发**: 前后端团队可以并行开发、测试和部署,只需遵守统一的API约定,从而显著提升开发效率。
|
||||
- **技术栈灵活性**: 前后端可以独立选择最适合自身场景的技术栈,便于未来对任一端进行技术升级或重构。
|
||||
- **关注点分离**: 前端专注于用户体验和界面呈现,后端专注于业务逻辑、数据处理和系统安全,使得系统各部分职责更清晰,更易于维护。
|
||||
|
||||
在架构设计中,我们遵循了以下核心原则:
|
||||
- **高内聚,低耦合**: 将相关功能组织在独立的模块中,并最小化模块间的依赖。
|
||||
- **可扩展性**: 架构设计应能方便地横向扩展(增加更多服务器实例)和纵向扩展(增加新功能模块)。
|
||||
- **安全性**: 从设计之初就考虑认证、授权、数据加密和输入验证等安全问题。
|
||||
- **可维护性**: 采用清晰的代码分层、统一的编码规范和完善的文档,降低长期维护成本。
|
||||
|
||||
#### 1.1.2 后端架构
|
||||
|
||||
后端服务基于 **Spring Boot 3** 和 **Java 17** 构建,这是一个现代化、高性能的组合。其内部采用了经典的三层分层架构模式:
|
||||
|
||||
- **表现层 (Controller Layer)**: 负责接收前端的HTTP请求,使用 `@RestController` 定义RESTful API。此层负责解析HTTP请求、验证输入参数(使用JSR-303注解),并调用业务逻辑层处理请求,但不包含任何业务逻辑。
|
||||
- **业务逻辑层 (Service Layer)**: 系统的核心,使用 `@Service` 注解。它封装了所有的业务规则、流程控制和复杂计算。它通过调用数据访问层来操作数据,并通过事件发布等机制与其他服务进行解耦交互。
|
||||
- **数据访问层 (Repository/Persistence Layer)**: 负责与数据存储进行交互。本项目独创性地采用了一套基于JSON文件的持久化方案。通过自定义的`JsonStorageService`和一系列Repository类,模拟了类似JPA的接口,实现了对`users.json`, `tasks.json`等核心数据文件的增删改查(CRUD)操作。选择JSON文件存储简化了项目的部署和配置,特别适合快速迭代和中小型应用场景。
|
||||
|
||||
此架构同时利用了 **Spring WebFlux** 进行异步处理,具备响应式编程能力,以提升高并发场景下的性能。其清晰的分层和模块化设计也为未来向微服务架构演进奠定了良好基础。
|
||||
|
||||

|
||||
|
||||
#### 1.1.3 前端架构
|
||||
|
||||
前端应用是一个基于 **Vue 3** 的单页面应用(SPA),使用 **Vite** 作为构建工具。选择Vue 3是因为其优秀的性能、丰富的生态系统和渐进式的学习曲线。
|
||||
- **UI组件库**: **Element Plus**,提供了一套高质量、符合设计规范的UI组件,加速了界面的开发。
|
||||
- **状态管理**: **Pinia**,作为Vue 3官方推荐的状态管理库,它提供了极简的API和强大的类型推断支持,能有效管理复杂的应用状态。
|
||||
- **路由管理**: **Vue Router**,负责管理前端页面的跳转和路由。
|
||||
|
||||
### 1.2 功能模块划分
|
||||
|
||||
系统在功能上被划分为一系列高内聚的模块,每个模块负责一块具体的业务领域。这种划分方式便于团队分工和独立开发。
|
||||
|
||||
| 核心模块 | 主要职责 | 关键功能点 |
|
||||
| ------------------ | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| **认证与授权模块** | 管理所有用户的身份认证和访问权限 | - 用户注册/登录/登出<br>- JWT令牌生成与验证<br>- 密码重置<br>- 基于角色的访问控制(RBAC) |
|
||||
| **用户与人员管理模块** | 维护系统中的所有用户账户及其信息 | - 用户信息的增、删、改、查<br>- 用户角色分配与变更<br>- 用户状态管理(激活/禁用) |
|
||||
| **反馈管理模块** | 处理来自外部和内部的环境问题反馈 | - 接收公众/认证用户的反馈<br>- 集成AI进行内容预审核<br>- 人工审核与处理<br>- 反馈状态跟踪与统计 |
|
||||
| **任务管理模块** | 对具体工作任务进行全生命周期管理 | - 从反馈创建任务<br>- 任务分配给网格员<br>- 任务状态(分配、执行、完成)跟踪<br>- 任务审核与结果归档 |
|
||||
| **网格与地图模块** | 对地理空间进行网格化管理,并提供路径支持 | - 地理网格的定义与划分<br>- 网格员与网格的关联<br>- **A\*寻路算法**服务,优化任务路径 |
|
||||
| **决策支持模块** | 为管理层提供数据洞察和可视化报告 | - 核心业务指标(KPI)统计<br>- AQI、任务完成率等数据的可视化<br>- 生成反馈热力图 |
|
||||
| **个人中心模块** | 为登录用户提供个性化的信息管理和查询功能 | - 查看/修改个人资料<br>- 查询个人提交历史<br>- 查看个人操作日志 |真实吧。妈
|
||||
|
||||

|
||||
|
||||
## 2. 详细设计
|
||||
|
||||
### 2.1 功能模块详细设计
|
||||
|
||||
本章节将对核心功能模块的内部设计进行更深入的阐述。
|
||||
|
||||
#### 2.1.1 反馈管理模块
|
||||
|
||||
该模块是系统与用户交互的核心,负责处理所有环境问题的上报和初步处理。
|
||||
- **主要控制器**: `FeedbackController`, `PublicController`
|
||||
- **核心服务**: `FeedbackService`, `FeedbackAiReviewService`
|
||||
- **关键DTO**: `FeedbackSubmissionRequest`, `FeedbackResponseDTO`, `ProcessFeedbackRequest`
|
||||
- **设计要点**:
|
||||
- 采用 `@RequestPart` 同时接收JSON数据和文件上传,实现了富文本内容的反馈提交。
|
||||
- 通过发布 `FeedbackSubmittedForAiReviewEvent` 事件,将AI审核流程解耦并异步化,提高了API的响应速度。
|
||||
- 提供了强大的多条件动态查询能力,支持按状态、类型、严重等级、地理位置和时间范围进行组合过滤。
|
||||
|
||||
#### 2.1.2 任务管理模块
|
||||
|
||||
该模块负责将已批准的反馈转化为具体的可执行任务,并对其进行全生命周期管理。
|
||||
- **主要控制器**: `TaskManagementController`, `TaskAssignmentController`, `GridWorkerTaskController`
|
||||
- **核心服务**: `TaskService`, `TaskAssignmentService`
|
||||
- **关键DTO**: `TaskCreationRequest`, `TaskDetailDTO`, `TaskAssignmentRequest`, `TaskSummaryDTO`
|
||||
- **设计要点**:
|
||||
- 清晰的状态机管理任务的生命周期(CREATED → ASSIGNED → IN_PROGRESS → SUBMITTED → APPROVED/REJECTED)。
|
||||
- 任务分配逻辑考虑了网格员的地理位置和当前负载,旨在实现智能化的高效分配。
|
||||
- 为主管和网格员提供了完全独立的API端点,严格分离了不同角色的操作权限。
|
||||
|
||||
#### 2.1.3 用户与人员管理模块
|
||||
|
||||
该模块为系统的权限管理和组织架构提供了基础。
|
||||
- **主要控制器**: `PersonnelController`
|
||||
- **核心服务**: `UserAccountService`, `OperationLogService`
|
||||
- **关键DTO**: `UserCreationRequest`, `UserUpdateRequest`, `UserRoleUpdateRequest`
|
||||
- **设计要点**:
|
||||
- 提供了对用户账户的完整CRUD操作。
|
||||
- 实现了用户角色和状态的精细化管理。
|
||||
- 所有关键操作均通过`OperationLogService`记录日志,便于审计和追踪。
|
||||
|
||||
#### 2.1.4 网格与地图模块
|
||||
|
||||
该模块是系统实现区域化、网格化管理的核心。
|
||||
- **主要控制器**: `GridController`, `MapController`
|
||||
- **核心服务**: `GridService`, `PathfindingService`
|
||||
- **设计要点**:
|
||||
- 支持对地理区域进行灵活的网格化定义,并可将网格标记为障碍。
|
||||
- 实现了网格与网格员的关联管理。
|
||||
- 核心亮点是集成了`PathfindingService`,该服务封装了A*寻路算法,为任务路径规划提供支持。
|
||||
|
||||
|
||||
### 2.2 类和对象的设计
|
||||
|
||||
本节定义了系统核心业务对象的静态结构,即类图。
|
||||
|
||||
#### 2.2.1 `UserAccount` 类图
|
||||

|
||||
|
||||
#### 2.2.2 `Feedback` 类图
|
||||

|
||||
|
||||
#### 2.2.3 `Task` 类图
|
||||

|
||||
|
||||
#### 2.2.4 `Grid` 和 `Assignment` 类图
|
||||

|
||||
|
||||
### 2.3 动态模型设计
|
||||
|
||||
本节描述了系统在运行时,对象之间的交互行为。
|
||||
|
||||
#### 2.3.1 核心时序图
|
||||
|
||||
**用户登录认证时序图**
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant AuthController as 认证控制器
|
||||
participant AuthService as 认证服务
|
||||
participant JwtUtil as JWT工具
|
||||
|
||||
User->>AuthController: POST /api/auth/login (email, password)
|
||||
AuthController->>AuthService: signIn(LoginRequest)
|
||||
AuthService->>AuthService: 验证凭证
|
||||
alt 验证成功
|
||||
AuthService->>JwtUtil: generateToken(user)
|
||||
JwtUtil-->>AuthService: 返回JWT令牌
|
||||
AuthService-->>AuthController: 返回JwtAuthenticationResponse
|
||||
AuthController-->>User: 200 OK (token)
|
||||
else 验证失败
|
||||
AuthService-->>AuthController: 抛出AuthenticationException
|
||||
AuthController-->>User: 401 Unauthorized
|
||||
end
|
||||
```
|
||||
|
||||
**反馈提交与处理时序图**
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant FeedbackController as 反馈控制器
|
||||
participant FeedbackService as 反馈服务
|
||||
participant EventPublisher as 事件发布器
|
||||
participant FeedbackAiReviewService as AI审核服务
|
||||
|
||||
User->>FeedbackController: POST /api/feedback/submit
|
||||
FeedbackController->>FeedbackService: submitFeedback(request, files)
|
||||
FeedbackService->>EventPublisher: publishEvent(FeedbackSubmittedEvent)
|
||||
FeedbackService-->>FeedbackController: 返回初步响应
|
||||
Controller-->>User: 201 Created
|
||||
|
||||
EventPublisher-->>FeedbackAiReviewService: 异步触发AI审核
|
||||
FeedbackAiReviewService->>FeedbackService: updateFeedbackStatus(AI_REVIEWED)
|
||||
```
|
||||
|
||||
**主管分配任务时序图**
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Supervisor as 主管
|
||||
participant TaskMgmtController as 任务管理控制器
|
||||
participant TaskService as 任务服务
|
||||
participant AssignmentService as 分配服务
|
||||
participant NotificationService as 通知服务
|
||||
|
||||
Supervisor->>TaskMgmtController: POST /tasks/{taskId}/assign (workerId)
|
||||
TaskMgmtController->>TaskService: assignTask(taskId, workerId)
|
||||
TaskService->>AssignmentService: createAssignment(task, worker)
|
||||
AssignmentService-->>TaskService: 返回Assignment
|
||||
TaskService->>TaskService: 更新任务状态为ASSIGNED
|
||||
TaskService->>NotificationService: notifyWorker(workerId, taskId)
|
||||
TaskService-->>TaskMgmtController: 分配成功
|
||||
TaskMgmtController-->>Supervisor: 200 OK
|
||||
```
|
||||
|
||||
#### 2.3.2 核心状态图
|
||||
|
||||
**反馈状态机 (Feedback Status)**
|
||||

|
||||
|
||||
**任务状态机 (Task Status)**
|
||||

|
||||
|
||||
|
||||
### 2.4 算法与策略设计
|
||||
|
||||
#### 2.4.1 A* 寻路算法
|
||||
|
||||
- **目的**: 为网格员规划从当前位置到任务目标点的最优(最短或最快)路径。
|
||||
- **输入**:
|
||||
- `startNode`: 起始点坐标。
|
||||
- `endNode`: 目标点坐标。
|
||||
- `grid`: 包含障碍物信息的地图网格数据。
|
||||
- **核心逻辑**:
|
||||
1. 维护一个开放列表(`openList`)和一个关闭列表(`closedList`)。
|
||||
2. 从 `openList` 中选取F值(G值+H值)最小的节点作为当前节点。
|
||||
- G值: 从起点到当前节点的实际代价。
|
||||
- H值: 从当前节点到终点的预估代价(启发函数,通常使用曼哈顿距离或欧氏距离)。
|
||||
3. 遍历当前节点的相邻节点,如果邻居不在`closedList`中且不是障碍物,则计算其G值和H值,并将其加入`openList`。
|
||||
4. 重复此过程,直到当前节点为目标节点,或`openList`为空。
|
||||
- **输出**: 从起点到终点的一系列坐标点,即规划好的路径。
|
||||
- **应用**: 在`PathfindingController`中通过`/api/pathfinding/find`接口暴露。
|
||||
|
||||
#### 2.4.2 任务分配策略
|
||||
|
||||
- **目的**: 在多个可用网格员中,为新任务选择最合适的执行者。
|
||||
- **核心逻辑**: 这是一个复合策略,综合考虑以下因素,并计算加权得分:
|
||||
1. **地理位置优先**: 优先选择任务所在网格或邻近网格的网格员。
|
||||
2. **负载均衡**: 优先选择当前进行中任务数量最少的网格员。
|
||||
3. **技能匹配**: (未来扩展)可根据任务需要的技能(`skills`字段)与网格员的技能进行匹配。
|
||||
4. **任务优先级**: 对于高优先级任务,可以适当放宽地理位置限制,确保有可用人员处理。
|
||||
- **应用**: 在`TaskAssignmentService`中实现,当主管触发自动分配或系统基于反馈自动创建任务时调用。
|
||||
|
||||
### 2.5 数据持久化设计
|
||||
|
||||
系统不使用传统数据库,所有数据均以JSON文件的形式存储在服务器的文件系统中。每个核心模型对应一个JSON文件。这种设计简化了部署,但也对数据一致性和并发控制提出了更高的要求。
|
||||
|
||||
#### 2.5.1 `users.json` - 用户账户数据
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| --------------------- | ----------------- | ------------------------ | ---------------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 用户的唯一标识符 |
|
||||
| `name` | `String` | 非空 | 用户姓名 |
|
||||
| `phone` | `String` | 非空, **唯一** | 手机号码,可用于登录 |
|
||||
| `email` | `String` | 非空, **唯一** | 电子邮箱,可用于登录 |
|
||||
| `password` | `String` | 非空, 长度>=8 | 加密后的用户密码 |
|
||||
| `gender` | `String` | (ENUM) | 性别 (MALE, FEMALE, OTHER) |
|
||||
| `role` | `String` | (ENUM) | 用户角色 (ADMIN, SUPERVISOR, GRID_WORKER等) |
|
||||
| `status` | `String` | 非空, (ENUM) | 账户状态 (ACTIVE, INACTIVE, SUSPENDED) |
|
||||
| `grid_x` | `Number` | | 关联的网格X坐标 (主要用于网格员) |
|
||||
| `grid_y` | `Number` | | 关联的网格Y坐标 (主要用于网格员) |
|
||||
| `region` | `String` | | 所属区域或地区 |
|
||||
| `level` | `String` | (ENUM) | 用户等级 (JUNIOR, SENIOR, EXPERT) |
|
||||
| `skills` | `Array` | | 技能列表 (JSON数组格式的字符串) |
|
||||
| `enabled` | `Boolean` | 非空, 默认 `true` | 账户是否启用 |
|
||||
| `current_latitude` | `Number` | | 当前纬度坐标 (用于实时定位) |
|
||||
| `current_longitude` | `Number` | | 当前经度坐标 (用于实时定位) |
|
||||
| `failed_login_attempts` | `Number` | 默认 `0` | 连续失败登录次数 |
|
||||
| `lockout_end_time` | `String` | | 账户锁定截止时间 |
|
||||
| `created_at` | `String` | 非空 | 记录创建时间 |
|
||||
| `updated_at` | `String` | 非空 | 记录最后更新时间 |
|
||||
|
||||
#### 2.5.2 `feedback.json` - 环境问题反馈数据
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| ---------------- | --------------- | ------------------------ | ---------------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 反馈的唯一标识符 |
|
||||
| `event_id` | `String` | 非空, **唯一** | 人类可读的事件ID |
|
||||
| `title` | `String` | 非空 | 反馈标题 |
|
||||
| `description` | `String` | | 问题详细描述 |
|
||||
| `pollution_type` | `String` | 非空, (ENUM) | 污染类型 (AIR, WATER, SOIL, NOISE) |
|
||||
| `severity_level` | `String` | 非空, (ENUM) | 严重程度 (LOW, MEDIUM, HIGH, CRITICAL) |
|
||||
| `status` | `String` | 非空, (ENUM) | 反馈状态 (PENDING_REVIEW, PROCESSED等) |
|
||||
| `text_address` | `String` | | 文字描述的地址 |
|
||||
| `grid_x` | `Number` | | 事发地网格X坐标 |
|
||||
| `grid_y` | `Number` | | 事发地网格Y坐标 |
|
||||
| `latitude` | `Number` | | 事发地纬度 |
|
||||
| `longitude` | `Number` | | 事发地经度 |
|
||||
| `submitter_id` | `Number` | 外键 (FK) -> users.id (可为空) | 提交者ID (公众提交时可为空) |
|
||||
| `created_at` | `String` | 非空 | 记录创建时间 |
|
||||
| `updated_at` | `String` | 非空 | 记录最后更新时间 |
|
||||
|
||||
#### 2.5.3 `tasks.json` - 任务数据
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| ---------------- | --------------- | ------------------------ | ---------------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 任务的唯一标识符 |
|
||||
| `feedback_id` | `Number` | 外键 (FK) -> feedback.id (可为空) | 关联的原始反馈ID |
|
||||
| `assignee_id` | `Number` | 外键 (FK) -> users.id (可为空) | 任务执行人(网格员)ID |
|
||||
| `created_by` | `Number` | 外键 (FK) -> users.id | 任务创建人(主管)ID |
|
||||
| `status` | `String` | 非空, (ENUM) | 任务状态 (PENDING, IN_PROGRESS, COMPLETED) |
|
||||
| `title` | `String` | | 任务标题 |
|
||||
| `description` | `String` | | 任务详细描述 |
|
||||
| `pollution_type` | `String` | (ENUM) | 污染类型 |
|
||||
| `severity_level` | `String` | (ENUM) | 严重程度 |
|
||||
| `text_address` | `String` | | 任务地点文字描述 |
|
||||
| `grid_x` | `Number` | | 任务地点网格X坐标 |
|
||||
| `grid_y` | `Number` | | 任务地点网格Y坐标 |
|
||||
| `latitude` | `Number` | | 任务地点纬度 |
|
||||
| `longitude` | `Number` | | 任务地点经度 |
|
||||
| `assigned_at` | `String` | | 任务分配时间 |
|
||||
| `completed_at` | `String` | | 任务完成时间 |
|
||||
| `created_at` | `String` | 非空 | 记录创建时间 |
|
||||
| `updated_at` | `String` | 非空 | 记录最后更新时间 |
|
||||
| `deadline` | `String` | | 任务截止日期 |
|
||||
|
||||
#### 2.5.4 `grids.json` - 业务网格数据
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| --------------- | --------------- | ------------------- | ---------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 网格的唯一标识符 |
|
||||
| `gridx` | `Number` | | 网格X坐标 |
|
||||
| `gridy` | `Number` | | 网格Y坐标 |
|
||||
| `city_name` | `String` | | 所属城市 |
|
||||
| `district_name` | `String` | | 所属区县 |
|
||||
| `description` | `String` | | 网格描述信息 |
|
||||
| `is_obstacle` | `Boolean` | 默认 `false` | 是否为障碍物(如禁区) |
|
||||
|
||||
#### 2.5.5 `assignments.json` - 任务分配记录数据
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| ---------------- | --------------- | ------------------------ | -------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 分配记录的唯一标识符 |
|
||||
| `task_id` | `Number` | 非空, 外键 (FK) -> tasks.id | 关联的任务ID |
|
||||
| `assigner_id` | `Number` | 非空, 外键 (FK) -> users.id | 分配者(主管)ID |
|
||||
| `status` | `String` | 非空, (ENUM) | 分配状态 |
|
||||
| `remarks` | `String` | | 分配备注 |
|
||||
| `assignment_time`| `String` | 非空 | 分配时间 |
|
||||
| `deadline` | `String` | | 任务截止日期 |
|
||||
```
|
||||
@@ -1,518 +0,0 @@
|
||||
# 系统设计文档
|
||||
|
||||
本文档旨在详细阐述环境监督系统(EMS)的系统架构、功能模块和实现细节,为开发、测试和维护提供指导。
|
||||
|
||||
## 1. 总体设计
|
||||
|
||||
总体设计旨在从宏观上描述系统的架构、设计原则和核心组成部分,为后续的详细设计奠定基础。
|
||||
|
||||
### 1.1 系统架构设计
|
||||
|
||||
#### 1.1.1 架构选型与原则
|
||||
|
||||
本系统采用业界成熟的 **前后端分离** 架构。该架构将用户界面(前端)与业务逻辑处理(后端)彻底分离,二者通过定义良好的 **RESTful API** 进行通信。这种模式的优势在于:
|
||||
- **并行开发**: 前后端团队可以并行开发、测试和部署,只需遵守统一的API约定,从而显著提升开发效率。
|
||||
- **技术栈灵活性**: 前后端可以独立选择最适合自身场景的技术栈,便于未来对任一端进行技术升级或重构。
|
||||
- **关注点分离**: 前端专注于用户体验和界面呈现,后端专注于业务逻辑、数据处理和系统安全,使得系统各部分职责更清晰,更易于维护。
|
||||
|
||||
在架构设计中,我们遵循了以下核心原则:
|
||||
- **高内聚,低耦合**: 将相关功能组织在独立的模块中,并最小化模块间的依赖。
|
||||
- **可扩展性**: 架构设计应能方便地横向扩展(增加更多服务器实例)和纵向扩展(增加新功能模块)。
|
||||
- **安全性**: 从设计之初就考虑认证、授权、数据加密和输入验证等安全问题。
|
||||
- **可维护性**: 采用清晰的代码分层、统一的编码规范和完善的文档,降低长期维护成本。
|
||||
|
||||
#### 1.1.2 后端架构
|
||||
|
||||
后端服务基于 **Spring Boot 3** 和 **Java 17** 构建,这是一个现代化、高性能的组合。其内部采用了经典的三层分层架构模式:
|
||||
|
||||
- **表现层 (Controller Layer)**: 负责接收前端的HTTP请求,使用 `@RestController` 定义RESTful API。此层负责解析HTTP请求、验证输入参数(使用JSR-303注解),并调用业务逻辑层处理请求,但不包含任何业务逻辑。
|
||||
- **业务逻辑层 (Service Layer)**: 系统的核心,使用 `@Service` 注解。它封装了所有的业务规则、流程控制和复杂计算。它通过调用数据访问层来操作数据,并通过事件发布等机制与其他服务进行解耦交互。
|
||||
- **数据访问层 (Repository/Persistence Layer)**: 负责与数据存储进行交互。本项目独创性地采用了一套基于JSON文件的持久化方案。通过自定义的`JsonStorageService`和一系列Repository类,模拟了类似JPA的接口,实现了对`users.json`, `tasks.json`等核心数据文件的增删改查(CRUD)操作。选择JSON文件存储简化了项目的部署和配置,特别适合快速迭代和中小型应用场景。
|
||||
|
||||
此架构同时利用了 **Spring WebFlux** 进行异步处理,具备响应式编程能力,以提升高并发场景下的性能。其清晰的分层和模块化设计也为未来向微服务架构演进奠定了良好基础。
|
||||
|
||||
**后端分层架构图**
|
||||
```plantuml
|
||||
@startuml
|
||||
package "Backend Architecture" {
|
||||
[Controller Layer] <<Spring @RestController>>
|
||||
[Service Layer] <<Spring @Service>>
|
||||
[Repository Layer] <<Custom Persistence>>
|
||||
|
||||
[Controller Layer] --> [Service Layer]
|
||||
[Service Layer] --> [Repository Layer]
|
||||
}
|
||||
@enduml
|
||||
```
|
||||
|
||||
#### 1.1.3 前端架构
|
||||
|
||||
前端应用是一个基于 **Vue 3** 的单页面应用(SPA),使用 **Vite** 作为构建工具。选择Vue 3是因为其优秀的性能、丰富的生态系统和渐进式的学习曲线。
|
||||
- **UI组件库**: **Element Plus**,提供了一套高质量、符合设计规范的UI组件,加速了界面的开发。
|
||||
- **状态管理**: **Pinia**,作为Vue 3官方推荐的状态管理库,它提供了极简的API和强大的类型推断支持,能有效管理复杂的应用状态。
|
||||
- **路由管理**: **Vue Router**,负责管理前端页面的跳转和路由。
|
||||
|
||||
### 1.2 功能模块划分
|
||||
|
||||
系统在功能上被划分为一系列高内聚的模块,每个模块负责一块具体的业务领域。这种划分方式便于团队分工和独立开发。
|
||||
|
||||
| 核心模块 | 主要职责 | 关键功能点 |
|
||||
| ------------------ | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| **认证与授权模块** | 管理所有用户的身份认证和访问权限 | - 用户注册/登录/登出<br>- JWT令牌生成与验证<br>- 密码重置<br>- 基于角色的访问控制(RBAC) |
|
||||
| **用户与人员管理模块** | 维护系统中的所有用户账户及其信息 | - 用户信息的增、删、改、查<br>- 用户角色分配与变更<br>- 用户状态管理(激活/禁用) |
|
||||
| **反馈管理模块** | 处理来自外部和内部的环境问题反馈 | - 接收公众/认证用户的反馈<br>- 集成AI进行内容预审核<br>- 人工审核与处理<br>- 反馈状态跟踪与统计 |
|
||||
| **任务管理模块** | 对具体工作任务进行全生命周期管理 | - 从反馈创建任务<br>- 任务分配给网格员<br>- 任务状态(分配、执行、完成)跟踪<br>- 任务审核与结果归档 |
|
||||
| **网格与地图模块** | 对地理空间进行网格化管理,并提供路径支持 | - 地理网格的定义与划分<br>- 网格员与网格的关联<br>- **A\*寻路算法**服务,优化任务路径 |
|
||||
| **决策支持模块** | 为管理层提供数据洞察和可视化报告 | - 核心业务指标(KPI)统计<br>- AQI、任务完成率等数据的可视化<br>- 生成反馈热力图 |
|
||||
| **个人中心模块** | 为登录用户提供个性化的信息管理和查询功能 | - 查看/修改个人资料<br>- 查询个人提交历史<br>- 查看个人操作日志 |
|
||||
|
||||
**功能模块图**
|
||||
```plantuml
|
||||
@startuml
|
||||
left to right direction
|
||||
actor User
|
||||
|
||||
rectangle "环境监督系统 (EMS)" {
|
||||
User -- (认证与授权模块)
|
||||
(认证与授权模块) ..> (用户与人员管理模块) : 依赖
|
||||
|
||||
User -- (反馈管理模块)
|
||||
(反馈管理模块) ..> (任务管理模块) : 创建任务
|
||||
(任务管理模块) ..> (网格与地图模块) : 路径规划
|
||||
(任务管理模块) ..> (用户与人员管理模块) : 分配任务
|
||||
|
||||
(决策支持模块) .up.> (反馈管理模块) : 数据分析
|
||||
(决策支持模块) .up.> (任务管理模块) : 数据分析
|
||||
|
||||
User -- (个人中心模块)
|
||||
}
|
||||
@enduml
|
||||
```
|
||||
|
||||
## 2. 详细设计
|
||||
|
||||
### 2.1 功能模块详细设计
|
||||
|
||||
本章节将对核心功能模块的内部设计进行更深入的阐述。
|
||||
|
||||
#### 2.1.1 反馈管理模块
|
||||
|
||||
该模块是系统与用户交互的核心,负责处理所有环境问题的上报和初步处理。
|
||||
- **主要控制器**: `FeedbackController`, `PublicController`
|
||||
- **核心服务**: `FeedbackService`, `FeedbackAiReviewService`
|
||||
- **关键DTO**: `FeedbackSubmissionRequest`, `FeedbackResponseDTO`, `ProcessFeedbackRequest`
|
||||
- **设计要点**:
|
||||
- 采用 `@RequestPart` 同时接收JSON数据和文件上传,实现了富文本内容的反馈提交。
|
||||
- 通过发布 `FeedbackSubmittedForAiReviewEvent` 事件,将AI审核流程解耦并异步化,提高了API的响应速度。
|
||||
- 提供了强大的多条件动态查询能力,支持按状态、类型、严重等级、地理位置和时间范围进行组合过滤。
|
||||
|
||||
#### 2.1.2 任务管理模块
|
||||
|
||||
该模块负责将已批准的反馈转化为具体的可执行任务,并对其进行全生命周期管理。
|
||||
- **主要控制器**: `TaskManagementController`, `TaskAssignmentController`, `GridWorkerTaskController`
|
||||
- **核心服务**: `TaskService`, `TaskAssignmentService`
|
||||
- **关键DTO**: `TaskCreationRequest`, `TaskDetailDTO`, `TaskAssignmentRequest`, `TaskSummaryDTO`
|
||||
- **设计要点**:
|
||||
- 清晰的状态机管理任务的生命周期(CREATED → ASSIGNED → IN_PROGRESS → SUBMITTED → APPROVED/REJECTED)。
|
||||
- 任务分配逻辑考虑了网格员的地理位置和当前负载,旨在实现智能化的高效分配。
|
||||
- 为主管和网格员提供了完全独立的API端点,严格分离了不同角色的操作权限。
|
||||
|
||||
#### 2.1.3 用户与人员管理模块
|
||||
|
||||
该模块为系统的权限管理和组织架构提供了基础。
|
||||
- **主要控制器**: `PersonnelController`
|
||||
- **核心服务**: `UserAccountService`, `OperationLogService`
|
||||
- **关键DTO**: `UserCreationRequest`, `UserUpdateRequest`, `UserRoleUpdateRequest`
|
||||
- **设计要点**:
|
||||
- 提供了对用户账户的完整CRUD操作。
|
||||
- 实现了用户角色和状态的精细化管理。
|
||||
- 所有关键操作均通过`OperationLogService`记录日志,便于审计和追踪。
|
||||
|
||||
#### 2.1.4 网格与地图模块
|
||||
|
||||
该模块是系统实现区域化、网格化管理的核心。
|
||||
- **主要控制器**: `GridController`, `MapController`
|
||||
- **核心服务**: `GridService`, `PathfindingService`
|
||||
- **设计要点**:
|
||||
- 支持对地理区域进行灵活的网格化定义,并可将网格标记为障碍。
|
||||
- 实现了网格与网格员的关联管理。
|
||||
- 核心亮点是集成了`PathfindingService`,该服务封装了A*寻路算法,为任务路径规划提供支持。
|
||||
|
||||
|
||||
### 2.2 类和对象的设计
|
||||
|
||||
本节定义了系统核心业务对象的静态结构,即类图。
|
||||
|
||||
#### 2.2.1 `UserAccount` 类图
|
||||
```plantuml
|
||||
@startuml
|
||||
class UserAccount {
|
||||
- Long id
|
||||
- String name
|
||||
- String phone
|
||||
- String email
|
||||
- String password
|
||||
- Gender gender
|
||||
- Role role
|
||||
- UserStatus status
|
||||
- Integer gridX
|
||||
- Integer gridY
|
||||
+ isValid()
|
||||
}
|
||||
|
||||
enum Gender {
|
||||
MALE
|
||||
FEMALE
|
||||
OTHER
|
||||
}
|
||||
|
||||
enum Role {
|
||||
ADMIN
|
||||
SUPERVISOR
|
||||
GRID_WORKER
|
||||
}
|
||||
|
||||
enum UserStatus {
|
||||
ACTIVE
|
||||
INACTIVE
|
||||
}
|
||||
|
||||
UserAccount *-- Gender
|
||||
UserAccount *-- Role
|
||||
UserAccount *-- UserStatus
|
||||
@enduml
|
||||
```
|
||||
|
||||
#### 2.2.2 `Feedback` 类图
|
||||
```plantuml
|
||||
@startuml
|
||||
class Feedback {
|
||||
- Long id
|
||||
- String eventId
|
||||
- String title
|
||||
- PollutionType pollutionType
|
||||
- SeverityLevel severityLevel
|
||||
- FeedbackStatus status
|
||||
- Long submitterId
|
||||
+ process()
|
||||
+ approve()
|
||||
}
|
||||
|
||||
enum PollutionType {
|
||||
AIR
|
||||
WATER
|
||||
SOIL
|
||||
NOISE
|
||||
}
|
||||
|
||||
enum SeverityLevel {
|
||||
LOW
|
||||
MEDIUM
|
||||
HIGH
|
||||
CRITICAL
|
||||
}
|
||||
|
||||
enum FeedbackStatus {
|
||||
PENDING_REVIEW
|
||||
AI_REJECTED
|
||||
PROCESSED
|
||||
}
|
||||
|
||||
Feedback *-- PollutionType
|
||||
Feedback *-- SeverityLevel
|
||||
Feedback *-- FeedbackStatus
|
||||
@enduml
|
||||
```
|
||||
|
||||
#### 2.2.3 `Task` 类图
|
||||
```plantuml
|
||||
@startuml
|
||||
class Task {
|
||||
- Long id
|
||||
- Long feedbackId
|
||||
- Long assigneeId
|
||||
- Long createdBy
|
||||
- TaskStatus status
|
||||
- String title
|
||||
+ assignTo(workerId)
|
||||
+ complete()
|
||||
+ approve()
|
||||
}
|
||||
|
||||
enum TaskStatus {
|
||||
CREATED
|
||||
ASSIGNED
|
||||
IN_PROGRESS
|
||||
SUBMITTED
|
||||
APPROVED
|
||||
REJECTED
|
||||
}
|
||||
|
||||
Task *-- TaskStatus
|
||||
@enduml
|
||||
```
|
||||
|
||||
#### 2.2.4 `Grid` 和 `Assignment` 类图
|
||||
```plantuml
|
||||
@startuml
|
||||
class Grid {
|
||||
- Long id
|
||||
- Integer gridX
|
||||
- Integer gridY
|
||||
- String cityName
|
||||
- boolean isObstacle
|
||||
}
|
||||
|
||||
class Assignment {
|
||||
- Long id
|
||||
- Long taskId
|
||||
- Long assignerId
|
||||
- AssignmentStatus status
|
||||
- String remarks
|
||||
- LocalDateTime assignmentTime
|
||||
}
|
||||
|
||||
enum AssignmentStatus {
|
||||
PENDING
|
||||
ACCEPTED
|
||||
REJECTED
|
||||
}
|
||||
|
||||
Assignment *-- AssignmentStatus
|
||||
@enduml
|
||||
```
|
||||
|
||||
### 2.3 动态模型设计
|
||||
|
||||
本节描述了系统在运行时,对象之间的交互行为。
|
||||
|
||||
#### 2.3.1 核心时序图
|
||||
|
||||
**用户登录认证时序图**
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant AuthController as 认证控制器
|
||||
participant AuthService as 认证服务
|
||||
participant JwtUtil as JWT工具
|
||||
|
||||
User->>AuthController: POST /api/auth/login (email, password)
|
||||
AuthController->>AuthService: signIn(LoginRequest)
|
||||
AuthService->>AuthService: 验证凭证
|
||||
alt 验证成功
|
||||
AuthService->>JwtUtil: generateToken(user)
|
||||
JwtUtil-->>AuthService: 返回JWT令牌
|
||||
AuthService-->>AuthController: 返回JwtAuthenticationResponse
|
||||
AuthController-->>User: 200 OK (token)
|
||||
else 验证失败
|
||||
AuthService-->>AuthController: 抛出AuthenticationException
|
||||
AuthController-->>User: 401 Unauthorized
|
||||
end
|
||||
```
|
||||
|
||||
**反馈提交与处理时序图**
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant FeedbackController as 反馈控制器
|
||||
participant FeedbackService as 反馈服务
|
||||
participant EventPublisher as 事件发布器
|
||||
participant FeedbackAiReviewService as AI审核服务
|
||||
|
||||
User->>FeedbackController: POST /api/feedback/submit
|
||||
FeedbackController->>FeedbackService: submitFeedback(request, files)
|
||||
FeedbackService->>EventPublisher: publishEvent(FeedbackSubmittedEvent)
|
||||
FeedbackService-->>FeedbackController: 返回初步响应
|
||||
Controller-->>User: 201 Created
|
||||
|
||||
EventPublisher-->>FeedbackAiReviewService: 异步触发AI审核
|
||||
FeedbackAiReviewService->>FeedbackService: updateFeedbackStatus(AI_REVIEWED)
|
||||
```
|
||||
|
||||
**主管分配任务时序图**
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Supervisor as 主管
|
||||
participant TaskMgmtController as 任务管理控制器
|
||||
participant TaskService as 任务服务
|
||||
participant AssignmentService as 分配服务
|
||||
participant NotificationService as 通知服务
|
||||
|
||||
Supervisor->>TaskMgmtController: POST /tasks/{taskId}/assign (workerId)
|
||||
TaskMgmtController->>TaskService: assignTask(taskId, workerId)
|
||||
TaskService->>AssignmentService: createAssignment(task, worker)
|
||||
AssignmentService-->>TaskService: 返回Assignment
|
||||
TaskService->>TaskService: 更新任务状态为ASSIGNED
|
||||
TaskService->>NotificationService: notifyWorker(workerId, taskId)
|
||||
TaskService-->>TaskMgmtController: 分配成功
|
||||
TaskMgmtController-->>Supervisor: 200 OK
|
||||
```
|
||||
|
||||
#### 2.3.2 核心状态图
|
||||
|
||||
**反馈状态机 (Feedback Status)**
|
||||
```plantuml
|
||||
@startuml
|
||||
state "待审核" as PENDING_REVIEW
|
||||
state "AI审核通过" as AI_APPROVED
|
||||
state "AI拒绝" as AI_REJECTED
|
||||
state "已处理" as PROCESSED
|
||||
state "已关闭" as CLOSED
|
||||
|
||||
[*] --> PENDING_REVIEW : 提交反馈
|
||||
PENDING_REVIEW --> AI_APPROVED : AI审核通过
|
||||
PENDING_REVIEW --> AI_REJECTED : AI审核拒绝
|
||||
AI_APPROVED --> PROCESSED : 主管创建任务
|
||||
PROCESSED --> CLOSED : 任务完成
|
||||
AI_REJECTED --> CLOSED : 归档
|
||||
@enduml
|
||||
```
|
||||
|
||||
**任务状态机 (Task Status)**
|
||||
```plantuml
|
||||
@startuml
|
||||
state "已创建" as CREATED
|
||||
state "已分配" as ASSIGNED
|
||||
state "进行中" as IN_PROGRESS
|
||||
state "已提交" as SUBMITTED
|
||||
state "已批准" as APPROVED
|
||||
state "已拒绝" as REJECTED
|
||||
|
||||
[*] --> CREATED : 创建任务
|
||||
CREATED --> ASSIGNED : 分配给网格员
|
||||
ASSIGNED --> IN_PROGRESS : 网格员接受任务
|
||||
IN_PROGRESS --> SUBMITTED : 网格员完成并提交
|
||||
SUBMITTED --> APPROVED : 主管审核通过
|
||||
SUBMITTED --> REJECTED : 主管审核拒绝
|
||||
REJECTED --> ASSIGNED : 重新分配
|
||||
APPROVED --> [*]
|
||||
@enduml
|
||||
```
|
||||
|
||||
|
||||
### 2.4 算法与策略设计
|
||||
|
||||
#### 2.4.1 A* 寻路算法
|
||||
|
||||
- **目的**: 为网格员规划从当前位置到任务目标点的最优(最短或最快)路径。
|
||||
- **输入**:
|
||||
- `startNode`: 起始点坐标。
|
||||
- `endNode`: 目标点坐标。
|
||||
- `grid`: 包含障碍物信息的地图网格数据。
|
||||
- **核心逻辑**:
|
||||
1. 维护一个开放列表(`openList`)和一个关闭列表(`closedList`)。
|
||||
2. 从 `openList` 中选取F值(G值+H值)最小的节点作为当前节点。
|
||||
- G值: 从起点到当前节点的实际代价。
|
||||
- H值: 从当前节点到终点的预估代价(启发函数,通常使用曼哈顿距离或欧氏距离)。
|
||||
3. 遍历当前节点的相邻节点,如果邻居不在`closedList`中且不是障碍物,则计算其G值和H值,并将其加入`openList`。
|
||||
4. 重复此过程,直到当前节点为目标节点,或`openList`为空。
|
||||
- **输出**: 从起点到终点的一系列坐标点,即规划好的路径。
|
||||
- **应用**: 在`PathfindingController`中通过`/api/pathfinding/find`接口暴露。
|
||||
|
||||
#### 2.4.2 任务分配策略
|
||||
|
||||
- **目的**: 在多个可用网格员中,为新任务选择最合适的执行者。
|
||||
- **核心逻辑**: 这是一个复合策略,综合考虑以下因素,并计算加权得分:
|
||||
1. **地理位置优先**: 优先选择任务所在网格或邻近网格的网格员。
|
||||
2. **负载均衡**: 优先选择当前进行中任务数量最少的网格员。
|
||||
3. **技能匹配**: (未来扩展)可根据任务需要的技能(`skills`字段)与网格员的技能进行匹配。
|
||||
4. **任务优先级**: 对于高优先级任务,可以适当放宽地理位置限制,确保有可用人员处理。
|
||||
- **应用**: 在`TaskAssignmentService`中实现,当主管触发自动分配或系统基于反馈自动创建任务时调用。
|
||||
|
||||
### 2.5 数据持久化设计
|
||||
|
||||
系统不使用传统数据库,所有数据均以JSON文件的形式存储在服务器的文件系统中。每个核心模型对应一个JSON文件。这种设计简化了部署,但也对数据一致性和并发控制提出了更高的要求。
|
||||
|
||||
#### 2.5.1 `users.json` - 用户账户数据
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| --------------------- | ----------------- | ------------------------ | ---------------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 用户的唯一标识符 |
|
||||
| `name` | `String` | 非空 | 用户姓名 |
|
||||
| `phone` | `String` | 非空, **唯一** | 手机号码,可用于登录 |
|
||||
| `email` | `String` | 非空, **唯一** | 电子邮箱,可用于登录 |
|
||||
| `password` | `String` | 非空, 长度>=8 | 加密后的用户密码 |
|
||||
| `gender` | `String` | (ENUM) | 性别 (MALE, FEMALE, OTHER) |
|
||||
| `role` | `String` | (ENUM) | 用户角色 (ADMIN, SUPERVISOR, GRID_WORKER等) |
|
||||
| `status` | `String` | 非空, (ENUM) | 账户状态 (ACTIVE, INACTIVE, SUSPENDED) |
|
||||
| `grid_x` | `Number` | | 关联的网格X坐标 (主要用于网格员) |
|
||||
| `grid_y` | `Number` | | 关联的网格Y坐标 (主要用于网格员) |
|
||||
| `region` | `String` | | 所属区域或地区 |
|
||||
| `level` | `String` | (ENUM) | 用户等级 (JUNIOR, SENIOR, EXPERT) |
|
||||
| `skills` | `Array` | | 技能列表 (JSON数组格式的字符串) |
|
||||
| `enabled` | `Boolean` | 非空, 默认 `true` | 账户是否启用 |
|
||||
| `current_latitude` | `Number` | | 当前纬度坐标 (用于实时定位) |
|
||||
| `current_longitude` | `Number` | | 当前经度坐标 (用于实时定位) |
|
||||
| `failed_login_attempts` | `Number` | 默认 `0` | 连续失败登录次数 |
|
||||
| `lockout_end_time` | `String` | | 账户锁定截止时间 |
|
||||
| `created_at` | `String` | 非空 | 记录创建时间 |
|
||||
| `updated_at` | `String` | 非空 | 记录最后更新时间 |
|
||||
|
||||
#### 2.5.2 `feedback.json` - 环境问题反馈数据
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| ---------------- | --------------- | ------------------------ | ---------------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 反馈的唯一标识符 |
|
||||
| `event_id` | `String` | 非空, **唯一** | 人类可读的事件ID |
|
||||
| `title` | `String` | 非空 | 反馈标题 |
|
||||
| `description` | `String` | | 问题详细描述 |
|
||||
| `pollution_type` | `String` | 非空, (ENUM) | 污染类型 (AIR, WATER, SOIL, NOISE) |
|
||||
| `severity_level` | `String` | 非空, (ENUM) | 严重程度 (LOW, MEDIUM, HIGH, CRITICAL) |
|
||||
| `status` | `String` | 非空, (ENUM) | 反馈状态 (PENDING_REVIEW, PROCESSED等) |
|
||||
| `text_address` | `String` | | 文字描述的地址 |
|
||||
| `grid_x` | `Number` | | 事发地网格X坐标 |
|
||||
| `grid_y` | `Number` | | 事发地网格Y坐标 |
|
||||
| `latitude` | `Number` | | 事发地纬度 |
|
||||
| `longitude` | `Number` | | 事发地经度 |
|
||||
| `submitter_id` | `Number` | 外键 (FK) -> users.id (可为空) | 提交者ID (公众提交时可为空) |
|
||||
| `created_at` | `String` | 非空 | 记录创建时间 |
|
||||
| `updated_at` | `String` | 非空 | 记录最后更新时间 |
|
||||
|
||||
#### 2.5.3 `tasks.json` - 任务数据
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| ---------------- | --------------- | ------------------------ | ---------------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 任务的唯一标识符 |
|
||||
| `feedback_id` | `Number` | 外键 (FK) -> feedback.id (可为空) | 关联的原始反馈ID |
|
||||
| `assignee_id` | `Number` | 外键 (FK) -> users.id (可为空) | 任务执行人(网格员)ID |
|
||||
| `created_by` | `Number` | 外键 (FK) -> users.id | 任务创建人(主管)ID |
|
||||
| `status` | `String` | 非空, (ENUM) | 任务状态 (PENDING, IN_PROGRESS, COMPLETED) |
|
||||
| `title` | `String` | | 任务标题 |
|
||||
| `description` | `String` | | 任务详细描述 |
|
||||
| `pollution_type` | `String` | (ENUM) | 污染类型 |
|
||||
| `severity_level` | `String` | (ENUM) | 严重程度 |
|
||||
| `text_address` | `String` | | 任务地点文字描述 |
|
||||
| `grid_x` | `Number` | | 任务地点网格X坐标 |
|
||||
| `grid_y` | `Number` | | 任务地点网格Y坐标 |
|
||||
| `latitude` | `Number` | | 任务地点纬度 |
|
||||
| `longitude` | `Number` | | 任务地点经度 |
|
||||
| `assigned_at` | `String` | | 任务分配时间 |
|
||||
| `completed_at` | `String` | | 任务完成时间 |
|
||||
| `created_at` | `String` | 非空 | 记录创建时间 |
|
||||
| `updated_at` | `String` | 非空 | 记录最后更新时间 |
|
||||
| `deadline` | `String` | | 任务截止日期 |
|
||||
|
||||
#### 2.5.4 `grids.json` - 业务网格数据
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| --------------- | --------------- | ------------------- | ---------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 网格的唯一标识符 |
|
||||
| `gridx` | `Number` | | 网格X坐标 |
|
||||
| `gridy` | `Number` | | 网格Y坐标 |
|
||||
| `city_name` | `String` | | 所属城市 |
|
||||
| `district_name` | `String` | | 所属区县 |
|
||||
| `description` | `String` | | 网格描述信息 |
|
||||
| `is_obstacle` | `Boolean` | 默认 `false` | 是否为障碍物(如禁区) |
|
||||
|
||||
#### 2.5.5 `assignments.json` - 任务分配记录数据
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| ---------------- | --------------- | ------------------------ | -------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 分配记录的唯一标识符 |
|
||||
| `task_id` | `Number` | 非空, 外键 (FK) -> tasks.id | 关联的任务ID |
|
||||
| `assigner_id` | `Number` | 非空, 外键 (FK) -> users.id | 分配者(主管)ID |
|
||||
| `status` | `String` | 非空, (ENUM) | 分配状态 |
|
||||
| `remarks` | `String` | | 分配备注 |
|
||||
| `assignment_time`| `String` | 非空 | 分配时间 |
|
||||
| `deadline` | `String` | | 任务截止日期 |
|
||||
```
|
||||
@@ -1,726 +0,0 @@
|
||||
# 系统设计文档 V6
|
||||
|
||||
本文档旨在详细阐述环境监督系统(EMS)的系统架构、功能模块和实现细节,为开发、测试和维护提供指导。
|
||||
|
||||
## 1. 总体设计
|
||||
|
||||
总体设计旨在从宏观上描述系统的架构、设计原则和核心组成部分,为后续的详细设计奠定基础。
|
||||
|
||||
### 1.1 系统架构设计
|
||||
|
||||
#### 1.1.1 架构选型与原则
|
||||
|
||||
本系统采用业界成熟的 **前后端分离** 架构。该架构将用户界面(前端)与业务逻辑处理(后端)彻底分离,二者通过定义良好的 **RESTful API** 进行通信。这种模式的优势在于:
|
||||
- **并行开发**: 前后端团队可以并行开发、测试和部署,只需遵守统一的API约定,从而显著提升开发效率。
|
||||
- **技术栈灵活性**: 前后端可以独立选择最适合自身场景的技术栈,便于未来对任一端进行技术升级或重构。
|
||||
- **关注点分离**: 前端专注于用户体验和界面呈现,后端专注于业务逻辑、数据处理和系统安全,使得系统各部分职责更清晰,更易于维护。
|
||||
|
||||
在架构设计中,我们遵循了以下核心原则:
|
||||
- **高内聚,低耦合**: 将相关功能组织在独立的模块中,并最小化模块间的依赖。这是通过清晰的模块划分和基于事件的通信(如AI审核)实现的。
|
||||
- **可扩展性**: 架构设计应能方便地横向扩展(增加更多服务器实例)和纵向扩展(增加新功能模块)。模块化的设计使得添加新功能时,对现有系统的影响降到最低。
|
||||
- **安全性**: 从设计之初就考虑认证、授权、数据加密和输入验证等安全问题。采用JWT保障API安全,并通过角色权限(RBAC)控制对不同资源的访问。
|
||||
- **可维护性**: 采用清晰的代码分层、统一的编码规范和完善的文档,降低长期维护成本。
|
||||
|
||||
#### 1.1.2 后端架构
|
||||
|
||||
后端服务基于 **Spring Boot 3** 和 **Java 17** 构建,这是一个现代化、高性能的组合。其内部采用了经典的三层分层架构模式:
|
||||
|
||||
- **表现层 (Controller Layer)**: 负责接收前端的HTTP请求,使用 `@RestController` 定义RESTful API。此层负责解析HTTP请求、验证输入参数(使用JSR-303注解),并调用业务逻辑层处理请求,但不包含任何业务逻辑。
|
||||
- **业务逻辑层 (Service Layer)**: 系统的核心,使用 `@Service` 注解。它封装了所有的业务规则、流程控制和复杂计算。它通过调用数据访问层来操作数据,并通过事件发布等机制与其他服务进行解耦交互。
|
||||
- **数据访问层 (Repository/Persistence Layer)**: 负责与数据存储进行交互。本项目独创性地采用了一套基于JSON文件的持久化方案。通过自定义的`JsonStorageService`和一系列Repository类,模拟了类似JPA的接口,实现了对`users.json`, `tasks.json`等核心数据文件的增删改查(CRUD)操作。选择JSON文件存储简化了项目的部署和配置,特别适合快速迭代和中小型应用场景。
|
||||
|
||||
此架构同时利用了 **Spring WebFlux** 进行异步处理,具备响应式编程能力,以提升高并发场景下的性能。其清晰的分层和模块化设计也为未来向微服务架构演进奠定了良好基础。
|
||||
|
||||
**后端分层架构图**
|
||||
```plantuml
|
||||
@startuml
|
||||
package "Backend Architecture" {
|
||||
[Controller Layer] <<Spring @RestController>>
|
||||
[Service Layer] <<Spring @Service>>
|
||||
[Repository Layer] <<Custom Persistence>>
|
||||
|
||||
[Controller Layer] --> [Service Layer]
|
||||
[Service Layer] --> [Repository Layer]
|
||||
}
|
||||
@enduml
|
||||
```
|
||||
|
||||
#### 1.1.3 前端架构
|
||||
|
||||
前端应用是一个基于 **Vue 3** 的单页面应用(SPA),使用 **Vite** 作为构建工具。选择Vue 3是因为其优秀的性能、丰富的生态系统和渐进式的学习曲线。
|
||||
- **UI组件库**: **Element Plus**,提供了一套高质量、符合设计规范的UI组件,加速了界面的开发。
|
||||
- **状态管理**: **Pinia**,作为Vue 3官方推荐的状态管理库,它提供了极简的API和强大的类型推断支持,能有效管理复杂的应用状态。
|
||||
- **路由管理**: **Vue Router**,负责管理前端页面的跳转和路由。
|
||||
|
||||
### 1.2 功能模块划分
|
||||
|
||||
系统在功能上被划分为一系列高内聚的模块,每个模块负责一块具体的业务领域。这种划分方式便于团队分工和独立开发。
|
||||
|
||||
| 核心模块 | 主要职责 | 关键功能点 |
|
||||
| ------------------ | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| **认证与授权模块** | 管理所有用户的身份认证和访问权限 | - 用户注册/登录/登出<br>- JWT令牌生成与验证<br>- 密码重置<br>- 基于角色的访问控制(RBAC) |
|
||||
| **用户与人员管理模块** | 维护系统中的所有用户账户及其信息 | - 用户信息的增、删、改、查<br>- 用户角色分配与变更<br>- 用户状态管理(激活/禁用) |
|
||||
| **反馈管理模块** | 处理来自外部和内部的环境问题反馈 | - 接收公众/认证用户的反馈<br>- 集成AI进行内容预审核<br>- 人工审核与处理<br>- 反馈状态跟踪与统计 |
|
||||
| **任务管理模块** | 对具体工作任务进行全生命周期管理 | - 从反馈创建任务<br>- 任务分配给网格员<br>- 任务状态(分配、执行、完成)跟踪<br>- 任务审核与结果归档 |
|
||||
| **网格与地图模块** | 对地理空间进行网格化管理,并提供路径支持 | - 地理网格的定义与划分<br>- 网格员与网格的关联<br>- **A\*寻路算法**服务,优化任务路径 |
|
||||
| **决策支持模块** | 为管理层提供数据洞察和可视化报告 | - 核心业务指标(KPI)统计<br>- AQI、任务完成率等数据的可视化<br>- 生成反馈热力图 |
|
||||
| **个人中心模块** | 为登录用户提供个性化的信息管理和查询功能 | - 查看/修改个人资料<br>- 查询个人提交历史<br>- 查看个人操作日志 |
|
||||
|
||||
**功能模块图**
|
||||
```plantuml
|
||||
@startuml
|
||||
left to right direction
|
||||
actor User
|
||||
|
||||
rectangle "环境监督系统 (EMS)" {
|
||||
User -- (认证与授权模块)
|
||||
(认证与授权模块) ..> (用户与人员管理模块) : 依赖
|
||||
|
||||
User -- (反馈管理模块)
|
||||
(反馈管理模块) ..> (任务管理模块) : 创建任务
|
||||
(任务管理模块) ..> (网格与地图模块) : 路径规划
|
||||
(任务管理模块) ..> (用户与人员管理模块) : 分配任务
|
||||
|
||||
(决策支持模块) .up.> (反馈管理模块) : 数据分析
|
||||
(决策支持模块) .up.> (任务管理模块) : 数据分析
|
||||
|
||||
User -- (个人中心模块)
|
||||
}
|
||||
@enduml
|
||||
```
|
||||
|
||||
## 2. 详细设计
|
||||
|
||||
### 2.1 功能模块详细设计
|
||||
|
||||
本章节将对系统的核心功能模块进行详细的拆解和说明,阐述每个模块的职责、主要功能和关键参与者。
|
||||
|
||||
#### 2.1.1 用户与认证模块 (User & Authentication)
|
||||
|
||||
* **核心职责**: 负责管理所有用户账户、角色、权限,并提供安全可靠的身份认证和授权服务。是整个系统安全访问的基石。
|
||||
* **关键参与者**: 系统管理员 (Admin), 主管 (Supervisor), 网格员 (Grid Worker), 注册用户。
|
||||
* **主要功能点**:
|
||||
* **用户注册**: 提供新用户账户的创建接口。
|
||||
* **身份认证**:
|
||||
* 通过用户名(邮箱)和密码进行登录验证。
|
||||
* 成功登录后,生成符合JWT (JSON Web Token) 标准的访问令牌 (`access_token`) 和刷新令牌 (`refresh_token`)。
|
||||
* **权限控制**:
|
||||
* 基于角色的访问控制 (RBAC)。不同角色(如 `ADMIN`, `SUPERVISOR`, `GRID_WORKER`)拥有不同的API访问权限。
|
||||
* 通过在API请求的Header中携带JWT令牌来验证用户身份和权限。
|
||||
* **账户管理 (管理员)**:
|
||||
* 创建、查看、更新、删除系统内的所有用户账户。
|
||||
* 分配和修改用户角色。
|
||||
* 管理用户状态(激活、禁用、暂停)。
|
||||
* **密码重置**: 提供忘记密码后的安全重置流程(例如,通过邮件发送重置链接)。
|
||||
* **相关服务**: `AuthService`, `UserAccountService`, `SupervisorService`。
|
||||
|
||||
#### 2.1.2 反馈管理模块 (Feedback Management)
|
||||
|
||||
* **核心职责**: 统一处理所有来源(公众、系统用户)的环境问题反馈,确保每一条反馈都得到有效记录、审查和跟进。
|
||||
* **关键参与者**: 公众用户 (匿名/注册), 主管, 系统。
|
||||
* **主要功能点**:
|
||||
* **反馈提交**: 允许用户通过API提交带有详细描述、位置信息、严重等级和附件(图片/视频)的反馈。
|
||||
* **AI自动审查**:
|
||||
* 新提交的反馈会触发一个异步事件。
|
||||
* AI服务对反馈内容进行初步分析,评估其有效性、严重性和污染类型。
|
||||
* 根据AI审查结果,反馈状态可能被更新为 `AI_REJECTED` 或触发任务创建流程。
|
||||
* **主管人工处理**:
|
||||
* 主管可以查看所有待处理的反馈。
|
||||
* 对于AI无法处理或需要人工判断的反馈,主管可以进行审核、批准或拒绝。
|
||||
* 批准后的反馈将转化为一个明确的、可执行的任务。
|
||||
* **状态跟踪**: 反馈的整个生命周期(`PENDING_REVIEW` -> `PROCESSED` -> `CLOSED`)都被完整记录和追踪。
|
||||
* **相关服务**: `FeedbackService`, `FeedbackAiReviewService`。
|
||||
|
||||
#### 2.1.3 任务管理模块 (Task Management)
|
||||
|
||||
* **核心职责**: 负责将经过审核的反馈转化为具体的工作任务,并对任务的全生命周期(创建、分配、执行、审核、归档)进行管理。
|
||||
* **关键参与者**: 主管, 网格员。
|
||||
* **主要功能点**:
|
||||
* **任务创建**:
|
||||
* 可由反馈自动转化而来。
|
||||
* 主管也可以根据需要手动创建新任务。
|
||||
* **任务分配**:
|
||||
* **手动分配**: 主管可以直接将任务指派给特定的网格员。
|
||||
* **智能分配 (设计中)**: 系统在任务创建后,自动调用分配算法,综合考虑网格员的位置、负载等因素,推荐或直接分配最合适的人选。
|
||||
* **任务执行 (网格员)**:
|
||||
* 网格员可以查看分配给自己的任务列表。
|
||||
* 接受、拒绝或开始执行任务,并更新任务状态。
|
||||
* 完成任务后,提交包含处理说明和附件的工作报告。
|
||||
* **任务审核 (主管)**:
|
||||
* 主管审查网格员提交的任务结果。
|
||||
* 可以选择"批准"(任务完成)或"驳回"(任务需要返工)。
|
||||
* **历史追溯**: 完整的任务状态变更历史、操作记录和处理意见都会被存档,方便审计和复盘。
|
||||
* **相关服务**: `TaskManagementService`, `GridWorkerTaskService`, `TaskAssignmentService`。
|
||||
|
||||
#### 2.1.4 网格与地图模块 (Grid & Map)
|
||||
|
||||
* **核心职责**: 负责定义和管理地理网格系统,并提供基于地理位置的辅助功能,如路径规划。
|
||||
* **关键参与者**: 系统管理员, 网格员。
|
||||
* **主要功能点**:
|
||||
* **网格定义**: 管理员可以定义城市地图的网格系统,包括每个网格的坐标、属性以及是否为障碍物。
|
||||
* **人员-网格关联**: 管理员可将特定的网格员分配到指定的责任网格中。
|
||||
* **路径规划**:
|
||||
* 集成 A* 寻路算法。
|
||||
* 为网格员提供从当前位置到任务地点的最优路径规划,并能在地图上进行可视化展示。
|
||||
* **相关服务**: `GridService`, `PathfindingService`。
|
||||
|
||||
#### 2.1.5 决策支持模块 (Decision Support)
|
||||
|
||||
* **核心职责**: 汇集和分析各类环境数据,为管理人员提供数据洞察和决策依据。
|
||||
* **关键参与者**: 主管, 系统管理员。
|
||||
* **主要功能点**:
|
||||
* **数据看板 (Dashboard)**:
|
||||
* 实时展示关键指标(KPI),如待处理反馈数、进行中任务数、平均处理时长等。
|
||||
* 以图表形式展示污染类型、区域分布、严重程度的统计分析。
|
||||
* **历史数据查询**: 提供对历史反馈和任务数据的多维度查询和筛选功能。
|
||||
* **报告生成**: (未来扩展) 定期自动生成环境状况分析报告。
|
||||
* **相关服务**: `AqiService`, (未来可能引入的`AnalyticsService`)。
|
||||
|
||||
#### 2.1.6 个人中心模块 (Personal Center)
|
||||
|
||||
* **核心职责**: 为登录用户提供管理个人账户信息和偏好的专属空间。
|
||||
* **关键参与者**: 所有登录用户 (主管, 网格员)。
|
||||
* **主要功能点**:
|
||||
* **个人资料查看与编辑**: 用户可以查看和修改自己的基本信息,如联系电话、头像等。
|
||||
* **密码修改**: 提供安全的旧密码验证和新密码设置功能。
|
||||
* **我的任务/反馈**: 快速访问与自己相关的任务或反馈列表。
|
||||
* **相关服务**: `UserProfileService`。
|
||||
|
||||
#### 2.1.7 日志与审计模块 (Logging & Auditing)
|
||||
|
||||
* **核心职责**: 记录系统中发生的所有重要操作和事件,确保系统的可追溯性和安全性。
|
||||
* **关键参与者**: 系统管理员, 系统。
|
||||
* **主要功能点**:
|
||||
* **操作日志**: 自动记录关键的用户操作,如谁在什么时间创建了任务、修改了反馈状态等。
|
||||
* **系统日志**: 记录应用运行时的错误、警告和重要信息,用于问题排查和性能监控。
|
||||
* **日志查询**: 提供接口供管理员查询和审计操作日志。
|
||||
* **相关服务**: `OperationLogService`。
|
||||
|
||||
### 2.2 类和对象的设计
|
||||
|
||||
本节定义了系统核心业务对象的静态结构,即类图。
|
||||
|
||||
#### 2.2.1 `UserAccount` 类图
|
||||
```plantuml
|
||||
@startuml
|
||||
class UserAccount {
|
||||
- Long id
|
||||
- String name
|
||||
- String phone
|
||||
- String email
|
||||
- String password
|
||||
- Gender gender
|
||||
- Role role
|
||||
- UserStatus status
|
||||
- Integer gridX
|
||||
- Integer gridY
|
||||
+ isValid()
|
||||
}
|
||||
|
||||
enum Gender {
|
||||
MALE
|
||||
FEMALE
|
||||
OTHER
|
||||
}
|
||||
|
||||
enum Role {
|
||||
ADMIN
|
||||
SUPERVISOR
|
||||
GRID_WORKER
|
||||
}
|
||||
|
||||
enum UserStatus {
|
||||
ACTIVE
|
||||
INACTIVE
|
||||
}
|
||||
|
||||
UserAccount *-- Gender
|
||||
UserAccount *-- Role
|
||||
UserAccount *-- UserStatus
|
||||
@enduml
|
||||
```
|
||||
|
||||
#### 2.2.2 `Feedback` 类图
|
||||
```plantuml
|
||||
@startuml
|
||||
class Feedback {
|
||||
- Long id
|
||||
- String eventId
|
||||
- String title
|
||||
- PollutionType pollutionType
|
||||
- SeverityLevel severityLevel
|
||||
- FeedbackStatus status
|
||||
- Long submitterId
|
||||
+ process()
|
||||
+ approve()
|
||||
}
|
||||
|
||||
enum PollutionType {
|
||||
AIR
|
||||
WATER
|
||||
SOIL
|
||||
NOISE
|
||||
}
|
||||
|
||||
enum SeverityLevel {
|
||||
LOW
|
||||
MEDIUM
|
||||
HIGH
|
||||
CRITICAL
|
||||
}
|
||||
|
||||
enum FeedbackStatus {
|
||||
PENDING_REVIEW
|
||||
AI_REJECTED
|
||||
PROCESSED
|
||||
}
|
||||
|
||||
Feedback *-- PollutionType
|
||||
Feedback *-- SeverityLevel
|
||||
Feedback *-- FeedbackStatus
|
||||
@enduml
|
||||
```
|
||||
|
||||
#### 2.2.3 `Task` 类图
|
||||
```plantuml
|
||||
@startuml
|
||||
class Task {
|
||||
- Long id
|
||||
- Long feedbackId
|
||||
- Long assigneeId
|
||||
- Long createdBy
|
||||
- TaskStatus status
|
||||
- String title
|
||||
+ assignTo(workerId)
|
||||
+ complete()
|
||||
+ approve()
|
||||
}
|
||||
|
||||
enum TaskStatus {
|
||||
CREATED
|
||||
ASSIGNED
|
||||
IN_PROGRESS
|
||||
SUBMITTED
|
||||
APPROVED
|
||||
REJECTED
|
||||
}
|
||||
|
||||
Task *-- TaskStatus
|
||||
@enduml
|
||||
```
|
||||
|
||||
#### 2.2.4 `Grid` 和 `Assignment` 类图
|
||||
```plantuml
|
||||
@startuml
|
||||
class Grid {
|
||||
- Long id
|
||||
- Integer gridX
|
||||
- Integer gridY
|
||||
- String cityName
|
||||
- boolean isObstacle
|
||||
}
|
||||
|
||||
class Assignment {
|
||||
- Long id
|
||||
- Long taskId
|
||||
- Long assignerId
|
||||
- AssignmentStatus status
|
||||
- String remarks
|
||||
- LocalDateTime assignmentTime
|
||||
}
|
||||
|
||||
enum AssignmentStatus {
|
||||
PENDING
|
||||
ACCEPTED
|
||||
REJECTED
|
||||
}
|
||||
|
||||
Assignment *-- AssignmentStatus
|
||||
@enduml
|
||||
```
|
||||
|
||||
### 2.3 动态模型设计
|
||||
|
||||
本节描述了系统在运行时,对象之间的交互行为。
|
||||
|
||||
#### 2.3.1 核心时序图
|
||||
|
||||
**用户登录认证时序图**
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant AuthController as 认证控制器
|
||||
participant AuthService as 认证服务
|
||||
participant JwtUtil as JWT工具
|
||||
|
||||
User->>AuthController: POST /api/auth/login (email, password)
|
||||
AuthController->>AuthService: signIn(LoginRequest)
|
||||
AuthService->>AuthService: 验证凭证
|
||||
alt 验证成功
|
||||
AuthService->>JwtUtil: generateToken(user)
|
||||
JwtUtil-->>AuthService: 返回JWT令牌
|
||||
AuthService-->>AuthController: 返回JwtAuthenticationResponse
|
||||
AuthController-->>User: 200 OK (token)
|
||||
else 验证失败
|
||||
AuthService-->>AuthController: 抛出AuthenticationException
|
||||
AuthController-->>User: 401 Unauthorized
|
||||
end
|
||||
```
|
||||
|
||||
**反馈提交与处理时序图**
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant FeedbackController as 反馈控制器
|
||||
participant FeedbackService as 反馈服务
|
||||
participant EventPublisher as 事件发布器
|
||||
participant FeedbackAiReviewService as AI审核服务
|
||||
|
||||
User->>FeedbackController: POST /api/feedback/submit
|
||||
FeedbackController->>FeedbackService: submitFeedback(request, files)
|
||||
FeedbackService->>EventPublisher: publishEvent(FeedbackSubmittedEvent)
|
||||
FeedbackService-->>FeedbackController: 返回初步响应
|
||||
Controller-->>User: 201 Created
|
||||
|
||||
EventPublisher-->>FeedbackAiReviewService: 异步触发AI审核
|
||||
FeedbackAiReviewService->>FeedbackService: updateFeedbackStatus(AI_REVIEWED)
|
||||
```
|
||||
|
||||
**主管分配任务时序图**
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Supervisor as 主管
|
||||
participant TaskMgmtController as 任务管理控制器
|
||||
participant TaskService as 任务服务
|
||||
participant AssignmentService as 分配服务
|
||||
participant NotificationService as 通知服务
|
||||
|
||||
Supervisor->>TaskMgmtController: POST /tasks/{taskId}/assign (workerId)
|
||||
TaskMgmtController->>TaskService: assignTask(taskId, workerId)
|
||||
TaskService->>AssignmentService: createAssignment(task, worker)
|
||||
AssignmentService-->>TaskService: 返回Assignment
|
||||
TaskService->>TaskService: 更新任务状态为ASSIGNED
|
||||
TaskService->>NotificationService: notifyWorker(workerId, taskId)
|
||||
TaskService-->>TaskMgmtController: 分配成功
|
||||
TaskMgmtController-->>Supervisor: 200 OK
|
||||
```
|
||||
|
||||
**主管审核反馈并创建任务**
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Supervisor as 主管
|
||||
participant FeedbackController as 反馈控制器
|
||||
participant FeedbackService as 反馈服务
|
||||
participant TaskService as 任务服务
|
||||
participant TaskRepository as 任务仓库
|
||||
participant Database as JSON持久化存储
|
||||
|
||||
Supervisor->>FeedbackController: POST /api/feedback/{id}/process
|
||||
FeedbackController->>FeedbackService: processFeedback(feedbackId, request)
|
||||
FeedbackService->>FeedbackService: 验证反馈状态和主管权限
|
||||
alt 同意反馈并创建任务
|
||||
FeedbackService->>TaskService: createTaskFromFeedback(feedback)
|
||||
TaskService->>TaskRepository: save(task)
|
||||
TaskRepository->>Database: 保存新任务
|
||||
Database-->>TaskRepository: 返回保存的任务
|
||||
TaskRepository-->>TaskService: 返回Task实体
|
||||
TaskService->>FeedbackService: 更新反馈状态为PENDING_ASSIGNMENT
|
||||
FeedbackService-->>FeedbackController: 返回处理结果
|
||||
else 拒绝反馈
|
||||
FeedbackService->>FeedbackService: 更新反馈状态为REJECTED
|
||||
FeedbackService-->>FeedbackController: 返回处理结果
|
||||
end
|
||||
FeedbackController-->>Supervisor: 200 OK
|
||||
```
|
||||
|
||||
**网格员获取和管理任务**
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant GridWorker as 网格员
|
||||
participant GridWorkerTaskController as 网格员任务控制器
|
||||
participant GridWorkerTaskService as 网格员任务服务
|
||||
participant TaskRepository as 任务仓库
|
||||
|
||||
alt 获取任务列表
|
||||
GridWorker->>GridWorkerTaskController: GET /api/worker/tasks
|
||||
GridWorkerTaskController->>GridWorkerTaskService: getAssignedTasks(workerId, status)
|
||||
GridWorkerTaskService->>TaskRepository: findByAssigneeIdAndStatus(workerId, status)
|
||||
TaskRepository-->>GridWorkerTaskService: 返回Page<Task>
|
||||
GridWorkerTaskService-->>GridWorkerTaskController: 返回Page<TaskSummaryDTO>
|
||||
GridWorkerTaskController-->>GridWorker: 返回任务列表
|
||||
end
|
||||
|
||||
alt 接受任务
|
||||
GridWorker->>GridWorkerTaskController: POST /api/worker/tasks/{taskId}/accept
|
||||
GridWorkerTaskController->>GridWorkerTaskService: acceptTask(taskId, workerId)
|
||||
GridWorkerTaskService->>TaskRepository: findById(taskId)
|
||||
TaskRepository-->>GridWorkerTaskService: 返回Task
|
||||
GridWorkerTaskService->>GridWorkerTaskService: 更新任务状态为ACCEPTED
|
||||
GridWorkerTaskService->>TaskRepository: save(task)
|
||||
TaskRepository-->>GridWorkerTaskService: 返回更新后的Task
|
||||
GridWorkerTaskService-->>GridWorkerTaskController: 返回TaskSummaryDTO
|
||||
GridWorkerTaskController-->>GridWorker: 返回更新后的任务
|
||||
end
|
||||
```
|
||||
|
||||
#### 2.3.2 核心状态图
|
||||
|
||||
**反馈状态机 (Feedback Status)**
|
||||
```plantuml
|
||||
@startuml
|
||||
state "待审核" as PENDING_REVIEW
|
||||
state "AI审核通过" as AI_APPROVED
|
||||
state "AI拒绝" as AI_REJECTED
|
||||
state "已处理" as PROCESSED
|
||||
state "已关闭" as CLOSED
|
||||
|
||||
[*] --> PENDING_REVIEW : 提交反馈
|
||||
PENDING_REVIEW --> AI_APPROVED : AI审核通过
|
||||
PENDING_REVIEW --> AI_REJECTED : AI审核拒绝
|
||||
AI_APPROVED --> PROCESSED : 主管创建任务
|
||||
PROCESSED --> CLOSED : 任务完成
|
||||
AI_REJECTED --> CLOSED : 归档
|
||||
@enduml
|
||||
```
|
||||
|
||||
**任务状态机 (Task Status)**
|
||||
```plantuml
|
||||
@startuml
|
||||
state "已创建" as CREATED
|
||||
state "已分配" as ASSIGNED
|
||||
state "进行中" as IN_PROGRESS
|
||||
state "已提交" as SUBMITTED
|
||||
state "已批准" as APPROVED
|
||||
state "已拒绝" as REJECTED
|
||||
|
||||
[*] --> CREATED : 创建任务
|
||||
CREATED --> ASSIGNED : 分配给网格员
|
||||
ASSIGNED --> IN_PROGRESS : 网格员接受任务
|
||||
IN_PROGRESS --> SUBMITTED : 网格员完成并提交
|
||||
SUBMITTED --> APPROVED : 主管审核通过
|
||||
SUBMITTED --> REJECTED : 主管审核拒绝
|
||||
REJECTED --> ASSIGNED : 重新分配
|
||||
APPROVED --> [*]
|
||||
@enduml
|
||||
```
|
||||
|
||||
|
||||
### 2.4 算法与策略设计
|
||||
|
||||
本章节详细阐述了系统运行过程中依赖的核心算法和业务决策策略。
|
||||
|
||||
#### 2.4.1 A* 路径规划算法
|
||||
|
||||
* **目标**: 为网格员在复杂的城市网格环境中,规划出从当前位置到任务地点的最优(最短)路径,同时能够有效规避障碍物。
|
||||
* **输入**:
|
||||
* `startNode`: 起始点网格坐标。
|
||||
* `endNode`: 目标点网格坐标。
|
||||
* `gridMap`: 一个二维数组或Map,包含了所有网格节点的信息,特别是标识了哪些节点是不可通行的障碍物。
|
||||
* **核心逻辑**:
|
||||
1. 维护一个"开放列表"(Open List)用于存放待考察的节点,以及一个"关闭列表"(Closed List)用于存放已考察过的节点。
|
||||
2. 对每个节点,计算两个核心成本:
|
||||
* `gCost`: 从起点到当前节点的实际移动成本。
|
||||
* `hCost` (启发式成本): 从当前节点到终点的预估移动成本(通常使用曼哈顿距离或欧几里得距离)。
|
||||
3. 总成本 `fCost = gCost + hCost`。
|
||||
4. 算法从开放列表中选取 `fCost` 最低的节点进行探索,直到找到终点。
|
||||
* **输出**: 一个包含了从起点到终点所有节点坐标的列表,即规划出的路径。
|
||||
* **伪代码**:
|
||||
```
|
||||
function AStar(start, end, grid):
|
||||
openSet = {start}
|
||||
closedSet = {}
|
||||
cameFrom = new Map()
|
||||
|
||||
gScore = new Map().setDefault(infinity)
|
||||
gScore[start] = 0
|
||||
|
||||
fScore = new Map().setDefault(infinity)
|
||||
fScore[start] = heuristic_cost(start, end)
|
||||
|
||||
while openSet is not empty:
|
||||
current = node in openSet with the lowest fScore
|
||||
if current == end:
|
||||
return reconstruct_path(cameFrom, current)
|
||||
|
||||
remove current from openSet
|
||||
add current to closedSet
|
||||
|
||||
for each neighbor of current:
|
||||
if neighbor in closedSet:
|
||||
continue
|
||||
|
||||
tentative_gScore = gScore[current] + dist_between(current, neighbor)
|
||||
|
||||
if neighbor not in openSet:
|
||||
add neighbor to openSet
|
||||
else if tentative_gScore >= gScore[neighbor]:
|
||||
continue
|
||||
|
||||
cameFrom[neighbor] = current
|
||||
gScore[neighbor] = tentative_gScore
|
||||
fScore[neighbor] = gScore[neighbor] + heuristic_cost(neighbor, end)
|
||||
|
||||
return failure // No path found
|
||||
```
|
||||
|
||||
#### 2.4.2 智能任务分配算法 (设计与提案)
|
||||
|
||||
> **现状说明**: 根据对 `TaskManagementServiceImpl.java` 的代码审查,当前的 `intelligentAssignTask` 方法为一个虚拟实现,系统暂无自动化的任务分配逻辑,依赖于主管手动分配。本节内容是为该功能的未来实现所做的**设计提案**。
|
||||
|
||||
* **目标**: 当新任务创建后,系统能够自动、快速、合理地将其分配给最合适的网格员,以提升响应效率和资源利用率。
|
||||
* **核心思想**: 算法通过计算每位可用网格员的"适任度分数"(Suitability Score)来决定任务归属。分数最高的网格员将被分配该任务。
|
||||
* **评分因子**:
|
||||
1. **地理邻近度 (Proximity)**: 网格员当前位置与任务发生地的距离。这是最重要的决定因素。距离越近,分数越高。
|
||||
2. **当前工作负载 (Workload)**: 网格员手上正在处理的 (`IN_PROGRESS`状态) 任务数量。负载越低,分数越高。
|
||||
3. **技能匹配度 (Skill Match)**: (未来扩展) 可为网格员和任务定义所需技能标签(如"水质检测","大气采样")。技能匹配度越高,得分越高。
|
||||
* **评分模型 (Scoring Model)**:
|
||||
适任度分数 `S` 由各因子加权计算得出:
|
||||
\[ S = (W_p \times \text{Score}_p) + (W_w \times \text{Score}_w) \]
|
||||
* **权重 (Weights)**:
|
||||
* `W_p`: 邻近度权重 (推荐值: `0.7`)
|
||||
* `W_w`: 工作负载权重 (推荐值: `0.3`)
|
||||
* 权重总和应为 1。这些值应在配置文件中可配置,便于调整策略。
|
||||
* **因子分数计算**:
|
||||
* 邻近度分数 \(\text{Score}_p = \frac{1}{D + 1}\)
|
||||
* `D` 是网格员与任务之间的曼哈顿距离 `(|x1-x2| + |y1-y2|)`。`+1` 是为了防止除以零。
|
||||
* 工作负载分数 \(\text{Score}_w = \frac{1}{N + 1}\)
|
||||
* `N` 是网格员当前正在处理的任务数。
|
||||
* **算法流程伪代码**:
|
||||
```
|
||||
function intelligentAssignTask(task):
|
||||
// 1. 获取所有符合条件的网格员
|
||||
availableWorkers = userRepo.findAllByRole(GRID_WORKER) and status(ACTIVE)
|
||||
|
||||
if availableWorkers is empty:
|
||||
log("No available workers to assign task " + task.id)
|
||||
return
|
||||
|
||||
bestWorker = null
|
||||
highestScore = -1
|
||||
|
||||
// 2. 遍历所有可用网格员,计算得分
|
||||
for each worker in availableWorkers:
|
||||
// 2a. 计算距离
|
||||
distance = manhattan_distance(worker.gridPos, task.gridPos)
|
||||
proximityScore = 1 / (distance + 1)
|
||||
|
||||
// 2b. 计算工作负载
|
||||
currentTasks = taskRepo.countByAssignee(worker) and status(IN_PROGRESS)
|
||||
workloadScore = 1 / (currentTasks + 1)
|
||||
|
||||
// 2c. 计算最终加权总分
|
||||
finalScore = (W_p * proximityScore) + (W_w * workloadScore)
|
||||
|
||||
// 2d. 记录并更新最高分和最佳人选
|
||||
if finalScore > highestScore:
|
||||
highestScore = finalScore
|
||||
bestWorker = worker
|
||||
|
||||
// 3. 分配任务给最佳人选
|
||||
if bestWorker is not null:
|
||||
task.setAssignee(bestWorker)
|
||||
task.setStatus(ASSIGNED)
|
||||
taskRepo.save(task)
|
||||
notificationService.notify(bestWorker, "You have a new task.")
|
||||
log("Task " + task.id + " assigned to " + bestWorker.name)
|
||||
else:
|
||||
log("Could not determine a best worker for task " + task.id)
|
||||
```
|
||||
|
||||
### 2.5 数据持久化设计
|
||||
|
||||
系统不使用传统数据库,所有数据均以JSON文件的形式存储在服务器的文件系统中。每个核心模型对应一个JSON文件。这种设计简化了部署,但也对数据一致性和并发控制提出了更高的要求。
|
||||
|
||||
#### 2.5.1 `users.json` - 用户账户数据
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| --------------------- | ----------------- | ------------------------ | ---------------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 用户的唯一标识符 |
|
||||
| `name` | `String` | 非空 | 用户姓名 |
|
||||
| `phone` | `String` | 非空, **唯一** | 手机号码,可用于登录 |
|
||||
| `email` | `String` | 非空, **唯一** | 电子邮箱,可用于登录 |
|
||||
| `password` | `String` | 非空, 长度>=8 | 加密后的用户密码 |
|
||||
| `gender` | `String` | (ENUM) | 性别 (MALE, FEMALE, OTHER) |
|
||||
| `role` | `String` | (ENUM) | 用户角色 (ADMIN, SUPERVISOR, GRID_WORKER等) |
|
||||
| `status` | `String` | 非空, (ENUM) | 账户状态 (ACTIVE, INACTIVE, SUSPENDED) |
|
||||
| `grid_x` | `Number` | | 关联的网格X坐标 (主要用于网格员) |
|
||||
| `grid_y` | `Number` | | 关联的网格Y坐标 (主要用于网格员) |
|
||||
| `region` | `String` | | 所属区域或地区 |
|
||||
| `level` | `String` | (ENUM) | 用户等级 (JUNIOR, SENIOR, EXPERT) |
|
||||
| `skills` | `Array` | | 技能列表 (JSON数组格式的字符串) |
|
||||
| `enabled` | `Boolean` | 非空, 默认 `true` | 账户是否启用 |
|
||||
| `current_latitude` | `Number` | | 当前纬度坐标 (用于实时定位) |
|
||||
| `current_longitude` | `Number` | | 当前经度坐标 (用于实时定位) |
|
||||
| `failed_login_attempts` | `Number` | 默认 `0` | 连续失败登录次数 |
|
||||
| `lockout_end_time` | `String` | | 账户锁定截止时间 |
|
||||
| `created_at` | `String` | 非空 | 记录创建时间 |
|
||||
| `updated_at` | `String` | 非空 | 记录最后更新时间 |
|
||||
|
||||
#### 2.5.2 `feedback.json` - 环境问题反馈数据
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| ---------------- | --------------- | ------------------------ | ---------------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 反馈的唯一标识符 |
|
||||
| `event_id` | `String` | 非空, **唯一** | 人类可读的事件ID |
|
||||
| `title` | `String` | 非空 | 反馈标题 |
|
||||
| `description` | `String` | | 问题详细描述 |
|
||||
| `pollution_type` | `String` | 非空, (ENUM) | 污染类型 (AIR, WATER, SOIL, NOISE) |
|
||||
| `severity_level` | `String` | 非空, (ENUM) | 严重程度 (LOW, MEDIUM, HIGH, CRITICAL) |
|
||||
| `status` | `String` | 非空, (ENUM) | 反馈状态 (PENDING_REVIEW, PROCESSED等) |
|
||||
| `text_address` | `String` | | 文字描述的地址 |
|
||||
| `grid_x` | `Number` | | 事发地网格X坐标 |
|
||||
| `grid_y` | `Number` | | 事发地网格Y坐标 |
|
||||
| `latitude` | `Number` | | 事发地纬度 |
|
||||
| `longitude` | `Number` | | 事发地经度 |
|
||||
| `submitter_id` | `Number` | 外键 (FK) -> users.id (可为空) | 提交者ID (公众提交时可为空) |
|
||||
| `created_at` | `String` | 非空 | 记录创建时间 |
|
||||
| `updated_at` | `String` | 非空 | 记录最后更新时间 |
|
||||
|
||||
#### 2.5.3 `tasks.json` - 任务数据
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| ---------------- | --------------- | ------------------------ | ---------------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 任务的唯一标识符 |
|
||||
| `feedback_id` | `Number` | 外键 (FK) -> feedback.id (可为空) | 关联的原始反馈ID |
|
||||
| `assignee_id` | `Number` | 外键 (FK) -> users.id (可为空) | 任务执行人(网格员)ID |
|
||||
| `created_by` | `Number` | 外键 (FK) -> users.id | 任务创建人(主管)ID |
|
||||
| `status` | `String` | 非空, (ENUM) | 任务状态 (PENDING, IN_PROGRESS, COMPLETED) |
|
||||
| `title` | `String` | | 任务标题 |
|
||||
| `description` | `String` | | 任务详细描述 |
|
||||
| `pollution_type` | `String` | (ENUM) | 污染类型 |
|
||||
| `severity_level` | `String` | (ENUM) | 严重程度 |
|
||||
| `text_address` | `String` | | 任务地点文字描述 |
|
||||
| `grid_x` | `Number` | | 任务地点网格X坐标 |
|
||||
| `grid_y` | `Number` | | 任务地点网格Y坐标 |
|
||||
| `latitude` | `Number` | | 任务地点纬度 |
|
||||
| `longitude` | `Number` | | 任务地点经度 |
|
||||
| `assigned_at` | `String` | | 任务分配时间 |
|
||||
| `completed_at` | `String` | | 任务完成时间 |
|
||||
| `created_at` | `String` | 非空 | 记录创建时间 |
|
||||
| `updated_at` | `String` | 非空 | 记录最后更新时间 |
|
||||
| `deadline` | `String` | | 任务截止日期 |
|
||||
|
||||
#### 2.5.4 `grids.json` - 业务网格数据
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| --------------- | --------------- | ------------------- | ---------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 网格的唯一标识符 |
|
||||
| `gridx` | `Number` | | 网格X坐标 |
|
||||
| `gridy` | `Number` | | 网格Y坐标 |
|
||||
| `city_name` | `String` | | 所属城市 |
|
||||
| `district_name` | `String` | | 所属区县 |
|
||||
| `description` | `String` | | 网格描述信息 |
|
||||
| `is_obstacle` | `Boolean` | 默认 `false` | 是否为障碍物(如禁区) |
|
||||
|
||||
#### 2.5.5 `assignments.json` - 任务分配记录数据
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| ---------------- | --------------- | ------------------------ | -------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 分配记录的唯一标识符 |
|
||||
| `task_id` | `Number` | 非空, 外键 (FK) -> tasks.id | 关联的任务ID |
|
||||
| `assigner_id` | `Number` | 非空, 外键 (FK) -> users.id | 分配者(主管)ID |
|
||||
| `status` | `String` | 非空, (ENUM) | 分配状态 |
|
||||
| `remarks` | `String` | | 分配备注 |
|
||||
| `assignment_time`| `String` | 非空 | 分配时间 |
|
||||
| `deadline` | `String` | | 任务截止日期 |
|
||||
```
|
||||
@@ -1,104 +0,0 @@
|
||||
# 系统设计文档
|
||||
|
||||
本文档旨在详细阐述环境监督系统(EMS)的系统架构、功能模块和实现细节,为开发、测试和维护提供指导。
|
||||
|
||||
## 1. 总体设计
|
||||
|
||||
总体设计旨在从宏观上描述系统的架构、设计原则和核心组成部分,为后续的详细设计奠定基础。
|
||||
|
||||
### 1.1 系统架构设计
|
||||
|
||||
#### 1.1.1 架构选型与原则
|
||||
|
||||
本系统采用业界成熟的 **前后端分离** 架构。该架构将用户界面(前端)与业务逻辑处理(后端)彻底分离,二者通过定义良好的 **RESTful API** 进行通信。这种模式的优势在于:
|
||||
- **并行开发**: 前后端团队可以并行开发、测试和部署,只需遵守统一的API约定,从而显著提升开发效率。
|
||||
- **技术栈灵活性**: 前后端可以独立选择最适合自身场景的技术栈,便于未来对任一端进行技术升级或重构。
|
||||
- **关注点分离**: 前端专注于用户体验和界面呈现,后端专注于业务逻辑、数据处理和系统安全,使得系统各部分职责更清晰,更易于维护。
|
||||
|
||||
在架构设计中,我们遵循了以下核心原则:
|
||||
- **高内聚,低耦合**: 将相关功能组织在独立的模块中,并最小化模块间的依赖。
|
||||
- **可扩展性**: 架构设计应能方便地横向扩展(增加更多服务器实例)和纵向扩展(增加新功能模块)。
|
||||
- **安全性**: 从设计之初就考虑认证、授权、数据加密和输入验证等安全问题。
|
||||
- **可维护性**: 采用清晰的代码分层、统一的编码规范和完善的文档,降低长期维护成本。
|
||||
|
||||
#### 1.1.2 后端架构
|
||||
|
||||
后端服务基于 **Spring Boot 3** 和 **Java 17** 构建,这是一个现代化、高性能的组合。其内部采用了经典的三层分层架构模式:
|
||||
|
||||
- **表现层 (Controller Layer)**: 负责接收前端的HTTP请求,使用 `@RestController` 定义RESTful API。此层负责解析HTTP请求、验证输入参数(使用JSR-303注解),并调用业务逻辑层处理请求,但不包含任何业务逻辑。
|
||||
- **业务逻辑层 (Service Layer)**: 系统的核心,使用 `@Service` 注解。它封装了所有的业务规则、流程控制和复杂计算。它通过调用数据访问层来操作数据,并通过事件发布等机制与其他服务进行解耦交互。
|
||||
- **数据访问层 (Repository/Persistence Layer)**: 负责与数据存储进行交互。本项目独创性地采用了一套基于JSON文件的持久化方案。通过自定义的`JsonStorageService`和一系列Repository类,模拟了类似JPA的接口,实现了对`users.json`, `tasks.json`等核心数据文件的增删改查(CRUD)操作。选择JSON文件存储简化了项目的部署和配置,特别适合快速迭代和中小型应用场景。
|
||||
|
||||
此架构同时利用了 **Spring WebFlux** 进行异步处理,具备响应式编程能力,以提升高并发场景下的性能。其清晰的分层和模块化设计也为未来向微服务架构演进奠定了良好基础。
|
||||
|
||||
```plantuml
|
||||
@startuml 后端分层架构图
|
||||
package "EMS后端架构" {
|
||||
[前端应用] --> [Controller层]
|
||||
[Controller层] --> [Service层]
|
||||
[Service层] --> [Repository层]
|
||||
[Repository层] --> [JSON文件存储]
|
||||
|
||||
note right of [Controller层]
|
||||
负责接收HTTP请求
|
||||
参数验证
|
||||
权限检查
|
||||
end note
|
||||
|
||||
note right of [Service层]
|
||||
业务逻辑核心
|
||||
事务管理
|
||||
事件发布
|
||||
end note
|
||||
|
||||
note right of [Repository层]
|
||||
数据访问
|
||||
查询构建
|
||||
持久化逻辑
|
||||
end note
|
||||
}
|
||||
@enduml
|
||||
```
|
||||
|
||||
#### 1.1.3 前端架构
|
||||
|
||||
前端应用是一个基于 **Vue 3** 的单页面应用(SPA),使用 **Vite** 作为构建工具。选择Vue 3是因为其优秀的性能、丰富的生态系统和渐进式的学习曲线。
|
||||
- **UI组件库**: **Element Plus**,提供了一套高质量、符合设计规范的UI组件,加速了界面的开发。
|
||||
- **状态管理**: **Pinia**,作为Vue 3官方推荐的状态管理库,它提供了极简的API和强大的类型推断支持,能有效管理复杂的应用状态。
|
||||
- **路由管理**: **Vue Router**,负责管理前端页面的跳转和路由。
|
||||
|
||||
### 1.2 功能模块划分
|
||||
|
||||
系统在功能上被划分为一系列高内聚的模块,每个模块负责一块具体的业务领域。这种划分方式便于团队分工和独立开发。
|
||||
|
||||
| 核心模块 | 主要职责 | 关键功能点 |
|
||||
| ------------------ | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| **认证与授权模块** | 管理所有用户的身份认证和访问权限 | - 用户注册/登录/登出<br>- JWT令牌生成与验证<br>- 密码重置<br>- 基于角色的访问控制(RBAC) |
|
||||
| **用户与人员管理模块** | 维护系统中的所有用户账户及其信息 | - 用户信息的增、删、改、查<br>- 用户角色分配与变更<br>- 用户状态管理(激活/禁用) |
|
||||
| **反馈管理模块** | 处理来自外部和内部的环境问题反馈 | - 接收公众/认证用户的反馈<br>- 集成AI进行内容预审核<br>- 人工审核与处理<br>- 反馈状态跟踪与统计 |
|
||||
| **任务管理模块** | 对具体工作任务进行全生命周期管理 | - 从反馈创建任务<br>- 任务分配给网格员<br>- 任务状态(分配、执行、完成)跟踪<br>- 任务审核与结果归档 |
|
||||
| **网格与地图模块** | 对地理空间进行网格化管理,并提供路径支持 | - 地理网格的定义与划分<br>- 网格员与网格的关联<br>- **A\*寻路算法**服务,优化任务路径 |
|
||||
| **决策支持模块** | 为管理层提供数据洞察和可视化报告 | - 核心业务指标(KPI)统计<br>- AQI、任务完成率等数据的可视化<br>- 生成反馈热力图 |
|
||||
| **个人中心模块** | 为登录用户提供个性化的信息管理和查询功能 | - 查看/修改个人资料<br>- 查询个人提交历史<br>- 查看个人操作日志 |
|
||||
|
||||
```plantuml
|
||||
@startuml 功能模块图
|
||||
!define RECTANGLE class
|
||||
|
||||
RECTANGLE "认证与授权模块" as auth #LightBlue
|
||||
RECTANGLE "用户与人员管理模块" as user #LightGreen
|
||||
RECTANGLE "反馈管理模块" as feedback #LightYellow
|
||||
RECTANGLE "任务管理模块" as task #LightPink
|
||||
RECTANGLE "网格与地图模块" as grid #LightCyan
|
||||
RECTANGLE "决策支持模块" as decision #LightGray
|
||||
RECTANGLE "个人中心模块" as profile #LightSalmon
|
||||
|
||||
auth -- user : 提供身份信息
|
||||
feedback -- task : 生成任务
|
||||
task -- grid : 使用地理信息
|
||||
user -- task : 分配任务
|
||||
task -- decision : 提供数据
|
||||
feedback -- decision : 提供数据
|
||||
user -- profile : 个人信息
|
||||
@enduml
|
||||
```
|
||||
@@ -1,465 +0,0 @@
|
||||
### 2.2 类和对象的设计
|
||||
|
||||
本节定义了系统核心业务对象的静态结构,即类图。这些类图展示了系统中的主要实体、它们的属性和方法,以及它们之间的关系。
|
||||
|
||||
#### 2.2.1 `UserAccount` 类图
|
||||
|
||||
`UserAccount`类是系统中用户账户的核心模型,包含用户的基本信息、认证信息和角色信息。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class UserAccount {
|
||||
-Long id
|
||||
-String name
|
||||
-String phone
|
||||
-String email
|
||||
-String password
|
||||
-Gender gender
|
||||
-UserRole role
|
||||
-UserStatus status
|
||||
-Integer gridX
|
||||
-Integer gridY
|
||||
-String region
|
||||
-String level
|
||||
-List~String~ skills
|
||||
-Boolean enabled
|
||||
-Double currentLatitude
|
||||
-Double currentLongitude
|
||||
-Integer failedLoginAttempts
|
||||
-LocalDateTime lockoutEndTime
|
||||
-LocalDateTime createdAt
|
||||
-LocalDateTime updatedAt
|
||||
+getId() Long
|
||||
+getName() String
|
||||
+getPhone() String
|
||||
+getEmail() String
|
||||
+getPassword() String
|
||||
+getRole() UserRole
|
||||
+getStatus() UserStatus
|
||||
+isEnabled() Boolean
|
||||
+setPassword(String) void
|
||||
+updateProfile(UserUpdateRequest) void
|
||||
+isAccountNonLocked() Boolean
|
||||
}
|
||||
|
||||
class UserRole {
|
||||
<<enumeration>>
|
||||
ADMIN
|
||||
SUPERVISOR
|
||||
GRID_WORKER
|
||||
DECISION_MAKER
|
||||
PUBLIC_USER
|
||||
}
|
||||
|
||||
class UserStatus {
|
||||
<<enumeration>>
|
||||
ACTIVE
|
||||
INACTIVE
|
||||
SUSPENDED
|
||||
}
|
||||
|
||||
class Gender {
|
||||
<<enumeration>>
|
||||
MALE
|
||||
FEMALE
|
||||
OTHER
|
||||
}
|
||||
|
||||
UserAccount --> UserRole
|
||||
UserAccount --> UserStatus
|
||||
UserAccount --> Gender
|
||||
```
|
||||
|
||||
#### 2.2.2 `Feedback` 类图
|
||||
|
||||
`Feedback`类表示用户提交的环境问题反馈,是系统的核心业务对象之一。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Feedback {
|
||||
-Long id
|
||||
-String eventId
|
||||
-String title
|
||||
-String description
|
||||
-PollutionType pollutionType
|
||||
-SeverityLevel severityLevel
|
||||
-FeedbackStatus status
|
||||
-String textAddress
|
||||
-Integer gridX
|
||||
-Integer gridY
|
||||
-Double latitude
|
||||
-Double longitude
|
||||
-UserAccount submitter
|
||||
-LocalDateTime createdAt
|
||||
-LocalDateTime updatedAt
|
||||
-List~Attachment~ attachments
|
||||
-Task relatedTask
|
||||
+getId() Long
|
||||
+getEventId() String
|
||||
+getTitle() String
|
||||
+getDescription() String
|
||||
+getPollutionType() PollutionType
|
||||
+getSeverityLevel() SeverityLevel
|
||||
+getStatus() FeedbackStatus
|
||||
+updateStatus(FeedbackStatus) void
|
||||
+addAttachment(Attachment) void
|
||||
}
|
||||
|
||||
class PollutionType {
|
||||
<<enumeration>>
|
||||
AIR
|
||||
WATER
|
||||
SOIL
|
||||
NOISE
|
||||
LIGHT
|
||||
OTHER
|
||||
}
|
||||
|
||||
class SeverityLevel {
|
||||
<<enumeration>>
|
||||
LOW
|
||||
MEDIUM
|
||||
HIGH
|
||||
CRITICAL
|
||||
}
|
||||
|
||||
class FeedbackStatus {
|
||||
<<enumeration>>
|
||||
SUBMITTED
|
||||
AI_REVIEWED
|
||||
PENDING_REVIEW
|
||||
APPROVED
|
||||
REJECTED
|
||||
PROCESSED
|
||||
CLOSED
|
||||
}
|
||||
|
||||
class Attachment {
|
||||
-Long id
|
||||
-String fileName
|
||||
-String filePath
|
||||
-String fileType
|
||||
-Long fileSize
|
||||
-LocalDateTime uploadedAt
|
||||
+getId() Long
|
||||
+getFileName() String
|
||||
+getFilePath() String
|
||||
}
|
||||
|
||||
Feedback --> PollutionType
|
||||
Feedback --> SeverityLevel
|
||||
Feedback --> FeedbackStatus
|
||||
Feedback --> UserAccount : submitter
|
||||
Feedback "1" --> "*" Attachment
|
||||
Feedback "1" --> "0..1" Task
|
||||
```
|
||||
|
||||
#### 2.2.3 `Task` 类图
|
||||
|
||||
`Task`类表示网格员需要执行的工作任务,通常由反馈生成。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Task {
|
||||
-Long id
|
||||
-Feedback feedback
|
||||
-UserAccount assignee
|
||||
-UserAccount createdBy
|
||||
-TaskStatus status
|
||||
-LocalDateTime assignedAt
|
||||
-LocalDateTime completedAt
|
||||
-LocalDateTime createdAt
|
||||
-LocalDateTime updatedAt
|
||||
-String title
|
||||
-String description
|
||||
-PollutionType pollutionType
|
||||
-SeverityLevel severityLevel
|
||||
-String textAddress
|
||||
-Integer gridX
|
||||
-Integer gridY
|
||||
-Double latitude
|
||||
-Double longitude
|
||||
-List~TaskHistory~ history
|
||||
-Assignment assignment
|
||||
-List~TaskSubmission~ submissions
|
||||
+getId() Long
|
||||
+getStatus() TaskStatus
|
||||
+getAssignee() UserAccount
|
||||
+updateStatus(TaskStatus) void
|
||||
+assign(UserAccount) void
|
||||
+addSubmission(TaskSubmission) void
|
||||
}
|
||||
|
||||
class TaskStatus {
|
||||
<<enumeration>>
|
||||
CREATED
|
||||
ASSIGNED
|
||||
ACCEPTED
|
||||
IN_PROGRESS
|
||||
SUBMITTED
|
||||
APPROVED
|
||||
REJECTED
|
||||
COMPLETED
|
||||
}
|
||||
|
||||
class TaskHistory {
|
||||
-Long id
|
||||
-Task task
|
||||
-UserAccount actor
|
||||
-TaskStatus oldStatus
|
||||
-TaskStatus newStatus
|
||||
-String remarks
|
||||
-LocalDateTime timestamp
|
||||
+getId() Long
|
||||
+getTask() Task
|
||||
+getOldStatus() TaskStatus
|
||||
+getNewStatus() TaskStatus
|
||||
}
|
||||
|
||||
class TaskSubmission {
|
||||
-Long id
|
||||
-Task task
|
||||
-UserAccount submitter
|
||||
-String description
|
||||
-LocalDateTime submittedAt
|
||||
-List~Attachment~ attachments
|
||||
+getId() Long
|
||||
+getTask() Task
|
||||
+getSubmitter() UserAccount
|
||||
+addAttachment(Attachment) void
|
||||
}
|
||||
|
||||
Task --> TaskStatus
|
||||
Task --> UserAccount : assignee
|
||||
Task --> UserAccount : createdBy
|
||||
Task "1" --> "*" TaskHistory
|
||||
Task "1" --> "0..1" Assignment
|
||||
Task "1" --> "*" TaskSubmission
|
||||
Task "0..1" --> "1" Feedback
|
||||
TaskHistory --> Task
|
||||
TaskHistory --> UserAccount : actor
|
||||
TaskSubmission --> Task
|
||||
TaskSubmission --> UserAccount : submitter
|
||||
TaskSubmission "1" --> "*" Attachment
|
||||
```
|
||||
|
||||
#### 2.2.4 `Grid` 和 `Assignment` 类图
|
||||
|
||||
`Grid`类表示地理空间的网格单元,`Assignment`类表示任务分配记录。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Grid {
|
||||
-Long id
|
||||
-Integer gridX
|
||||
-Integer gridY
|
||||
-String cityName
|
||||
-String districtName
|
||||
-String description
|
||||
-Boolean isObstacle
|
||||
+getId() Long
|
||||
+getGridX() Integer
|
||||
+getGridY() Integer
|
||||
+isObstacle() Boolean
|
||||
}
|
||||
|
||||
class Assignment {
|
||||
-Long id
|
||||
-Task task
|
||||
-UserAccount assigner
|
||||
-LocalDateTime assignmentTime
|
||||
-LocalDateTime deadline
|
||||
-AssignmentStatus status
|
||||
-String remarks
|
||||
+getId() Long
|
||||
+getTask() Task
|
||||
+getAssigner() UserAccount
|
||||
+getStatus() AssignmentStatus
|
||||
+updateStatus(AssignmentStatus) void
|
||||
}
|
||||
|
||||
class AssignmentStatus {
|
||||
<<enumeration>>
|
||||
PENDING
|
||||
ACCEPTED
|
||||
REJECTED
|
||||
COMPLETED
|
||||
}
|
||||
|
||||
Assignment --> Task
|
||||
Assignment --> UserAccount : assigner
|
||||
Assignment --> AssignmentStatus
|
||||
```
|
||||
|
||||
### 2.3 动态模型设计
|
||||
|
||||
本节描述了系统在运行时,对象之间的交互行为。通过时序图和状态图,展示了系统的动态行为和状态转换。
|
||||
|
||||
#### 2.3.1 核心时序图
|
||||
|
||||
时序图展示了系统中对象之间的交互序列,清晰地表达了业务流程的执行顺序和对象间的消息传递。
|
||||
|
||||
**用户登录认证时序图**
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant AuthController as 认证控制器
|
||||
participant AuthService as 认证服务
|
||||
participant JwtUtil as JWT工具
|
||||
|
||||
User->>AuthController: POST /api/auth/login (email, password)
|
||||
AuthController->>AuthService: signIn(LoginRequest)
|
||||
AuthService->>AuthService: 验证凭证
|
||||
alt 验证成功
|
||||
AuthService->>JwtUtil: generateToken(user)
|
||||
JwtUtil-->>AuthService: 返回JWT令牌
|
||||
AuthService-->>AuthController: 返回JwtAuthenticationResponse
|
||||
AuthController-->>User: 200 OK (token)
|
||||
else 验证失败
|
||||
AuthService-->>AuthController: 抛出AuthenticationException
|
||||
AuthController-->>User: 401 Unauthorized
|
||||
end
|
||||
```
|
||||
|
||||
**反馈提交与处理时序图**
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant FeedbackController as 反馈控制器
|
||||
participant FeedbackService as 反馈服务
|
||||
participant EventPublisher as 事件发布器
|
||||
participant FeedbackAiReviewService as AI审核服务
|
||||
participant TaskService as 任务服务
|
||||
|
||||
User->>FeedbackController: POST /api/feedback/submit
|
||||
FeedbackController->>FeedbackService: submitFeedback(request, files)
|
||||
FeedbackService->>FeedbackService: 生成事件ID
|
||||
FeedbackService->>FeedbackService: 保存反馈和附件
|
||||
FeedbackService->>EventPublisher: publishEvent(FeedbackSubmittedEvent)
|
||||
FeedbackService-->>FeedbackController: 返回反馈信息
|
||||
FeedbackController-->>User: 201 Created
|
||||
|
||||
EventPublisher-->>FeedbackAiReviewService: 异步触发AI审核
|
||||
FeedbackAiReviewService->>FeedbackAiReviewService: 分析反馈内容
|
||||
FeedbackAiReviewService->>FeedbackService: updateFeedbackStatus(AI_REVIEWED)
|
||||
|
||||
Note over User,TaskService: 主管审核流程
|
||||
|
||||
alt 主管批准反馈
|
||||
FeedbackService->>TaskService: createTaskFromFeedback(feedback)
|
||||
TaskService->>TaskService: 创建任务
|
||||
TaskService-->>FeedbackService: 返回创建的任务
|
||||
FeedbackService->>FeedbackService: updateFeedbackStatus(PROCESSED)
|
||||
else 主管拒绝反馈
|
||||
FeedbackService->>FeedbackService: updateFeedbackStatus(REJECTED)
|
||||
end
|
||||
```
|
||||
|
||||
**主管分配任务时序图**
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Supervisor as 主管
|
||||
participant TaskMgmtController as 任务管理控制器
|
||||
participant TaskService as 任务服务
|
||||
participant AssignmentService as 分配服务
|
||||
participant NotificationService as 通知服务
|
||||
participant GridWorker as 网格员
|
||||
|
||||
Supervisor->>TaskMgmtController: POST /tasks/{taskId}/assign (workerId)
|
||||
TaskMgmtController->>TaskService: assignTask(taskId, workerId)
|
||||
TaskService->>TaskService: 验证任务状态
|
||||
TaskService->>AssignmentService: createAssignment(task, worker)
|
||||
AssignmentService->>AssignmentService: 创建分配记录
|
||||
AssignmentService-->>TaskService: 返回Assignment
|
||||
TaskService->>TaskService: 更新任务状态为ASSIGNED
|
||||
TaskService->>NotificationService: notifyWorker(workerId, taskId)
|
||||
NotificationService->>NotificationService: 创建通知
|
||||
TaskService-->>TaskMgmtController: 分配成功
|
||||
TaskMgmtController-->>Supervisor: 200 OK
|
||||
|
||||
NotificationService-->>GridWorker: 发送任务通知
|
||||
```
|
||||
|
||||
**网格员处理任务时序图**
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant GridWorker as 网格员
|
||||
participant WorkerTaskController as 网格员任务控制器
|
||||
participant TaskService as 任务服务
|
||||
participant PathfindingService as 寻路服务
|
||||
participant Supervisor as 主管
|
||||
|
||||
GridWorker->>WorkerTaskController: POST /api/worker/tasks/{taskId}/accept
|
||||
WorkerTaskController->>TaskService: acceptTask(taskId, workerId)
|
||||
TaskService->>TaskService: 更新任务状态为ACCEPTED
|
||||
TaskService-->>WorkerTaskController: 返回更新后的任务
|
||||
WorkerTaskController-->>GridWorker: 200 OK
|
||||
|
||||
GridWorker->>WorkerTaskController: GET /api/pathfinding/find?start=x,y&end=a,b
|
||||
WorkerTaskController->>PathfindingService: findPath(start, end)
|
||||
PathfindingService->>PathfindingService: 执行A*算法
|
||||
PathfindingService-->>WorkerTaskController: 返回路径点列表
|
||||
WorkerTaskController-->>GridWorker: 200 OK (路径数据)
|
||||
|
||||
GridWorker->>WorkerTaskController: POST /api/worker/tasks/{taskId}/submit
|
||||
WorkerTaskController->>TaskService: submitTaskCompletion(taskId, workerId, request, files)
|
||||
TaskService->>TaskService: 验证并更新任务状态为SUBMITTED
|
||||
TaskService->>TaskService: 保存处理结果和附件
|
||||
TaskService-->>WorkerTaskController: 返回更新后的任务
|
||||
WorkerTaskController-->>GridWorker: 200 OK
|
||||
|
||||
Note over GridWorker,Supervisor: 主管审核流程
|
||||
|
||||
alt 主管批准任务完成
|
||||
TaskService->>TaskService: 更新任务状态为COMPLETED
|
||||
else 主管拒绝任务完成
|
||||
TaskService->>TaskService: 更新任务状态为REJECTED
|
||||
TaskService->>NotificationService: 通知网格员重新处理
|
||||
end
|
||||
```
|
||||
|
||||
#### 2.3.2 核心状态图
|
||||
|
||||
状态图展示了系统中关键对象的状态变化和转换条件,帮助理解对象的生命周期。
|
||||
|
||||
**反馈状态机 (Feedback Status)**
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> SUBMITTED: 用户提交反馈
|
||||
SUBMITTED --> AI_REVIEWED: AI自动审核
|
||||
AI_REVIEWED --> PENDING_REVIEW: 进入人工审核队列
|
||||
PENDING_REVIEW --> APPROVED: 主管批准
|
||||
PENDING_REVIEW --> REJECTED: 主管拒绝
|
||||
APPROVED --> PROCESSED: 创建关联任务
|
||||
PROCESSED --> CLOSED: 任务完成
|
||||
REJECTED --> [*]
|
||||
CLOSED --> [*]
|
||||
```
|
||||
|
||||
**任务状态机 (Task Status)**
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> CREATED: 创建任务
|
||||
CREATED --> ASSIGNED: 分配给网格员
|
||||
ASSIGNED --> ACCEPTED: 网格员接受
|
||||
ASSIGNED --> CREATED: 网格员拒绝
|
||||
ACCEPTED --> IN_PROGRESS: 开始处理
|
||||
IN_PROGRESS --> SUBMITTED: 提交处理结果
|
||||
SUBMITTED --> APPROVED: 主管批准
|
||||
SUBMITTED --> REJECTED: 主管拒绝
|
||||
REJECTED --> IN_PROGRESS: 重新处理
|
||||
APPROVED --> COMPLETED: 完成归档
|
||||
COMPLETED --> [*]
|
||||
```
|
||||
|
||||
**用户状态机 (User Status)**
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> ACTIVE: 创建账户
|
||||
ACTIVE --> SUSPENDED: 管理员暂停
|
||||
SUSPENDED --> ACTIVE: 管理员重新激活
|
||||
ACTIVE --> INACTIVE: 长期未使用
|
||||
INACTIVE --> ACTIVE: 用户登录
|
||||
INACTIVE --> [*]: 账户删除
|
||||
SUSPENDED --> [*]: 账户删除
|
||||
```
|
||||
@@ -1,154 +0,0 @@
|
||||
## 2. 详细设计
|
||||
|
||||
### 2.1 功能模块详细设计
|
||||
|
||||
本章节将对核心功能模块的内部设计进行更深入的阐述。
|
||||
|
||||
#### 2.1.1 反馈管理模块
|
||||
|
||||
反馈管理模块是系统与用户交互的核心,负责处理所有环境问题的上报和初步处理。
|
||||
|
||||
**核心组件**:
|
||||
- **主要控制器**: `FeedbackController`, `PublicController`
|
||||
- **核心服务**: `FeedbackService`, `FeedbackAiReviewService`
|
||||
- **关键DTO**: `FeedbackSubmissionRequest`, `FeedbackResponseDTO`, `ProcessFeedbackRequest`
|
||||
|
||||
**设计要点**:
|
||||
- 采用 `@RequestPart` 同时接收JSON数据和文件上传,实现了富文本内容的反馈提交。
|
||||
- 通过发布 `FeedbackSubmittedForAiReviewEvent` 事件,将AI审核流程解耦并异步化,提高了API的响应速度。
|
||||
- 提供了强大的多条件动态查询能力,支持按状态、类型、严重等级、地理位置和时间范围进行组合过滤。
|
||||
|
||||
**反馈状态流转**:
|
||||
```
|
||||
SUBMITTED → AI_REVIEWED → PENDING_REVIEW → APPROVED/REJECTED → PROCESSED → CLOSED
|
||||
```
|
||||
|
||||
**主要业务流程**:
|
||||
1. 公众用户提交反馈,系统生成唯一事件ID
|
||||
2. AI自动审核内容,识别垃圾信息和重复提交
|
||||
3. 主管进行人工审核,确认反馈有效性
|
||||
4. 有效反馈转化为任务,进入任务管理模块
|
||||
5. 任务完成后,反馈状态更新为已关闭
|
||||
|
||||
#### 2.1.2 任务管理模块
|
||||
|
||||
任务管理模块负责将已批准的反馈转化为具体的可执行任务,并对其进行全生命周期管理。
|
||||
|
||||
**核心组件**:
|
||||
- **主要控制器**: `TaskManagementController`, `TaskAssignmentController`, `GridWorkerTaskController`
|
||||
- **核心服务**: `TaskService`, `TaskAssignmentService`
|
||||
- **关键DTO**: `TaskCreationRequest`, `TaskDetailDTO`, `TaskAssignmentRequest`, `TaskSummaryDTO`
|
||||
|
||||
**设计要点**:
|
||||
- 清晰的状态机管理任务的生命周期(CREATED → ASSIGNED → IN_PROGRESS → SUBMITTED → APPROVED/REJECTED)。
|
||||
- 任务分配逻辑考虑了网格员的地理位置和当前负载,旨在实现智能化的高效分配。
|
||||
- 为主管和网格员提供了完全独立的API端点,严格分离了不同角色的操作权限。
|
||||
|
||||
**任务分配算法**:
|
||||
任务分配采用了一种多因素加权评分机制,综合考虑以下因素:
|
||||
1. **地理距离**: 计算网格员当前位置到任务位置的距离
|
||||
2. **当前负载**: 评估网格员手头的任务数量和优先级
|
||||
3. **专业匹配度**: 根据任务类型和网格员的专业技能进行匹配
|
||||
4. **历史表现**: 考虑网格员的历史完成率和质量评分
|
||||
|
||||
这些因素通过加权计算得出每个候选网格员的综合得分,系统推荐得分最高的网格员。主管可以接受系统建议或手动选择其他网格员。
|
||||
|
||||
**主要业务流程**:
|
||||
1. 从审核通过的反馈自动创建任务,或由主管手动创建临时任务
|
||||
2. 系统推荐最适合的处理人员,或由主管手动指定
|
||||
3. 任务分配给网格员,并发送通知
|
||||
4. 网格员接受任务,更新状态为进行中
|
||||
5. 网格员处理任务,提交处理结果
|
||||
6. 主管审核处理结果,确认任务完成或要求重新处理
|
||||
|
||||
#### 2.1.3 用户与人员管理模块
|
||||
|
||||
用户与人员管理模块为系统的权限管理和组织架构提供了基础。
|
||||
|
||||
**核心组件**:
|
||||
- **主要控制器**: `PersonnelController`, `UserProfileController`
|
||||
- **核心服务**: `UserAccountService`, `OperationLogService`
|
||||
- **关键DTO**: `UserCreationRequest`, `UserUpdateRequest`, `UserRoleUpdateRequest`
|
||||
|
||||
**设计要点**:
|
||||
- 提供了对用户账户的完整CRUD操作。
|
||||
- 实现了用户角色和状态的精细化管理。
|
||||
- 所有关键操作均通过`OperationLogService`记录日志,便于审计和追踪。
|
||||
|
||||
**用户角色体系**:
|
||||
系统定义了五种核心角色,每种角色具有不同的权限范围:
|
||||
1. **ADMIN**: 系统管理员,拥有所有功能的访问权限
|
||||
2. **DECISION_MAKER**: 决策者,主要访问统计数据和决策支持功能
|
||||
3. **SUPERVISOR**: 主管,负责审核反馈和任务分配
|
||||
4. **GRID_WORKER**: 网格员,负责执行具体任务
|
||||
5. **PUBLIC_USER**: 公众用户,仅能提交反馈和查询自己的反馈历史
|
||||
|
||||
**主要业务流程**:
|
||||
1. 管理员创建和管理系统用户
|
||||
2. 用户登录系统,获取JWT令牌
|
||||
3. 用户访问系统功能,系统根据角色进行权限控制
|
||||
4. 用户可以更新个人信息和密码
|
||||
5. 管理员可以禁用或重新激活用户账号
|
||||
|
||||
#### 2.1.4 网格与地图模块
|
||||
|
||||
网格与地图模块是系统实现区域化、网格化管理的核心。
|
||||
|
||||
**核心组件**:
|
||||
- **主要控制器**: `GridController`, `MapController`
|
||||
- **核心服务**: `GridService`, `PathfindingService`
|
||||
- **关键算法**: `AStarService`
|
||||
|
||||
**设计要点**:
|
||||
- 支持对地理区域进行灵活的网格化定义,并可将网格标记为障碍。
|
||||
- 实现了网格与网格员的关联管理。
|
||||
- 核心亮点是集成了`AStarService`,该服务封装了A*寻路算法,为任务路径规划提供支持。
|
||||
|
||||
**网格数据结构**:
|
||||
每个网格单元包含以下关键信息:
|
||||
- 网格坐标(x, y)
|
||||
- 所属城市和区域
|
||||
- 是否为障碍物
|
||||
- 关联的网格员(可选)
|
||||
- 描述信息
|
||||
|
||||
**A*寻路算法实现**:
|
||||
系统实现了高效的A*寻路算法,用于为网格员规划从当前位置到任务地点的最优路径:
|
||||
1. 使用优先队列管理开放列表,确保每次选择F值最小的节点
|
||||
2. F值计算为从起点到当前节点的实际代价(G值)与从当前节点到目标的估计代价(H值)之和
|
||||
3. 使用曼哈顿距离作为启发函数,适合网格化的移动模式
|
||||
4. 动态加载地图障碍物信息,确保路径规划避开不可通行区域
|
||||
|
||||
**主要业务流程**:
|
||||
1. 管理员定义城市网格系统
|
||||
2. 管理员将网格员分配到特定网格
|
||||
3. 用户提交反馈时,系统自动关联到对应网格
|
||||
4. 网格员接收任务后,系统提供从当前位置到任务地点的最优路径
|
||||
5. 管理层可查看基于网格的统计数据,识别问题高发区域
|
||||
|
||||
#### 2.1.5 决策支持模块
|
||||
|
||||
决策支持模块为管理层提供数据洞察和可视化报告,辅助决策制定。
|
||||
|
||||
**核心组件**:
|
||||
- **主要控制器**: `DashboardController`, `ReportController`
|
||||
- **核心服务**: `DashboardService`, `StatisticsService`
|
||||
- **关键DTO**: `DashboardStatsDTO`, `AqiDistributionDTO`, `HeatmapPointDTO`
|
||||
|
||||
**设计要点**:
|
||||
- 采用数据聚合和统计分析技术,从系统运行数据中提取有价值的信息。
|
||||
- 提供多维度的数据可视化,包括趋势图、分布图和热力图。
|
||||
- 支持数据导出功能,便于进一步分析和报告生成。
|
||||
|
||||
**核心统计指标**:
|
||||
1. **反馈处理效率**: 平均响应时间、处理时长分布
|
||||
2. **任务完成情况**: 按时完成率、任务状态分布
|
||||
3. **区域问题分布**: 按网格统计的问题密度和类型分布
|
||||
4. **人员绩效**: 网格员的任务完成量和质量评分
|
||||
|
||||
**主要业务流程**:
|
||||
1. 决策者登录系统,访问决策支持模块
|
||||
2. 系统实时计算和展示核心业务指标
|
||||
3. 决策者可选择不同维度进行数据分析
|
||||
4. 系统生成可视化图表,展示数据趋势和分布
|
||||
5. 决策者可导出分析结果,用于报告和决策支持
|
||||
@@ -1,386 +0,0 @@
|
||||
### 2.4 算法设计
|
||||
|
||||
本节详细描述了系统中的核心算法设计,这些算法是系统智能化和高效运行的关键。
|
||||
|
||||
#### 2.4.1 A* 寻路算法
|
||||
|
||||
A*寻路算法是系统中的核心算法之一,用于为网格员规划从当前位置到任务目标点的最优路径。该算法在网格与地图模块中发挥着重要作用。
|
||||
|
||||
**算法目的**:
|
||||
为网格员提供从当前位置到任务地点的最优(最短或最快)路径,避开障碍物。
|
||||
|
||||
**算法输入**:
|
||||
- `startNode`: 起始点坐标 (x, y)。
|
||||
- `endNode`: 目标点坐标 (x, y)。
|
||||
- `grid`: 包含障碍物信息的地图网格数据。
|
||||
|
||||
**核心逻辑**:
|
||||
1. 维护一个开放列表(`openList`)和一个关闭列表(`closedList`)。
|
||||
- `openList`: 存储待探索的节点,使用优先队列实现,按F值排序。
|
||||
- `closedList`: 存储已探索过的节点。
|
||||
2. 从 `openList` 中选取F值(G值+H值)最小的节点作为当前节点。
|
||||
- G值: 从起点到当前节点的实际代价。
|
||||
- H值: 从当前节点到终点的预估代价(启发函数)。
|
||||
- F值: G值 + H值,表示经过当前节点到达终点的总代价估计。
|
||||
3. 遍历当前节点的相邻节点(上、下、左、右四个方向)。
|
||||
4. 对于每个相邻节点:
|
||||
- 如果是障碍物或已在`closedList`中,则跳过。
|
||||
- 如果不在`openList`中,计算其G值、H值和F值,将其加入`openList`,并记录其父节点为当前节点。
|
||||
- 如果已在`openList`中,检查经由当前节点到达该相邻节点的路径是否更优(G值更小)。如果更优,则更新其G值、F值和父节点。
|
||||
5. 将当前节点从`openList`移除,加入`closedList`。
|
||||
6. 重复步骤2-5,直到:
|
||||
- 找到目标节点(当前节点为终点)。
|
||||
- 或`openList`为空(无法找到路径)。
|
||||
7. 如果找到目标节点,通过回溯父节点构建从起点到终点的路径。
|
||||
|
||||
**启发函数选择**:
|
||||
系统采用曼哈顿距离(Manhattan Distance)作为启发函数,计算公式为:
|
||||
```
|
||||
h(n) = |n.x - goal.x| + |n.y - goal.y|
|
||||
```
|
||||
这种启发函数适合网格化的移动模式,只允许上、下、左、右四个方向的移动。
|
||||
|
||||
**算法实现**:
|
||||
```java
|
||||
public List<Point> findPath(Point start, Point end) {
|
||||
// 加载地图数据和障碍物信息
|
||||
List<MapGrid> mapGrids = mapGridRepository.findAll();
|
||||
Set<Point> obstacles = new HashSet<>();
|
||||
for (MapGrid gridCell : mapGrids) {
|
||||
if (gridCell.isObstacle()) {
|
||||
obstacles.add(new Point(gridCell.getX(), gridCell.getY()));
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化开放列表和所有节点映射
|
||||
PriorityQueue<Node> openSet = new PriorityQueue<>(Comparator.comparingInt(n -> n.f));
|
||||
Map<Point, Node> allNodes = new HashMap<>();
|
||||
|
||||
// 创建起始节点
|
||||
Node startNode = new Node(start, null, 0, calculateHeuristic(start, end));
|
||||
openSet.add(startNode);
|
||||
allNodes.put(start, startNode);
|
||||
|
||||
// 开始A*算法主循环
|
||||
while (!openSet.isEmpty()) {
|
||||
Node currentNode = openSet.poll();
|
||||
|
||||
// 找到目标
|
||||
if (currentNode.point.equals(end)) {
|
||||
return reconstructPath(currentNode);
|
||||
}
|
||||
|
||||
// 探索相邻节点
|
||||
for (Point neighborPoint : getNeighbors(currentNode.point)) {
|
||||
if (obstacles.contains(neighborPoint)) {
|
||||
continue; // 跳过障碍物
|
||||
}
|
||||
|
||||
int tentativeG = currentNode.g + 1; // 相邻节点间距离为1
|
||||
Node neighborNode = allNodes.get(neighborPoint);
|
||||
|
||||
if (neighborNode == null) {
|
||||
// 新节点
|
||||
int h = calculateHeuristic(neighborPoint, end);
|
||||
neighborNode = new Node(neighborPoint, currentNode, tentativeG, h);
|
||||
allNodes.put(neighborPoint, neighborNode);
|
||||
openSet.add(neighborNode);
|
||||
} else if (tentativeG < neighborNode.g) {
|
||||
// 找到更好的路径
|
||||
neighborNode.parent = currentNode;
|
||||
neighborNode.g = tentativeG;
|
||||
neighborNode.f = tentativeG + neighborNode.h;
|
||||
// 更新优先队列
|
||||
openSet.remove(neighborNode);
|
||||
openSet.add(neighborNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptyList(); // 没有找到路径
|
||||
}
|
||||
|
||||
// 计算启发式函数值(曼哈顿距离)
|
||||
private int calculateHeuristic(Point a, Point b) {
|
||||
return Math.abs(a.x() - b.x()) + Math.abs(a.y() - b.y());
|
||||
}
|
||||
|
||||
// 获取相邻节点(上、下、左、右)
|
||||
private List<Point> getNeighbors(Point point) {
|
||||
List<Point> neighbors = new ArrayList<>(4);
|
||||
int[] dx = {0, 0, 1, -1}; // 右、左、下、上
|
||||
int[] dy = {1, -1, 0, 0};
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int newX = point.x() + dx[i];
|
||||
int newY = point.y() + dy[i];
|
||||
|
||||
// 检查边界
|
||||
if (newX >= 0 && newX < mapWidth && newY >= 0 && newY < mapHeight) {
|
||||
neighbors.add(new Point(newX, newY));
|
||||
}
|
||||
}
|
||||
return neighbors;
|
||||
}
|
||||
|
||||
// 重建路径
|
||||
private List<Point> reconstructPath(Node node) {
|
||||
LinkedList<Point> path = new LinkedList<>();
|
||||
while (node != null) {
|
||||
path.addFirst(node.point);
|
||||
node = node.parent;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
```
|
||||
|
||||
**算法输出**:
|
||||
从起点到终点的一系列坐标点列表,表示规划好的路径。如果无法找到路径,则返回空列表。
|
||||
|
||||
**算法应用**:
|
||||
在`PathfindingController`中通过`/api/pathfinding/find`接口暴露,网格员可以通过该接口获取从当前位置到任务地点的最优路径。
|
||||
|
||||
#### 2.4.2 任务智能分配算法
|
||||
|
||||
任务智能分配算法是系统的另一个核心算法,用于在多个可用网格员中,为新任务选择最合适的执行者。
|
||||
|
||||
**算法目的**:
|
||||
在多个可用网格员中,为新任务选择最合适的执行者,优化任务分配效率和完成质量。
|
||||
|
||||
**算法输入**:
|
||||
- `task`: 需要分配的任务对象。
|
||||
- `availableWorkers`: 可用的网格员列表。
|
||||
|
||||
**核心逻辑**:
|
||||
这是一个复合策略算法,综合考虑多个因素,通过加权评分机制选择最合适的网格员:
|
||||
|
||||
1. **地理距离评分**:
|
||||
- 计算每个网格员当前位置到任务位置的距离。
|
||||
- 距离越近,评分越高。
|
||||
- 使用公式: `distanceScore = maxDistance - distance`,其中`maxDistance`是一个预设的最大考虑距离。
|
||||
|
||||
2. **当前负载评分**:
|
||||
- 评估每个网格员当前正在处理的任务数量。
|
||||
- 任务数量越少,评分越高。
|
||||
- 使用公式: `loadScore = maxTasks - currentTasks`,其中`maxTasks`是一个预设的最大任务数。
|
||||
|
||||
3. **专业匹配度评分**:
|
||||
- 根据任务类型和网格员的专业技能进行匹配。
|
||||
- 匹配度越高,评分越高。
|
||||
- 使用公式: `skillScore = matchedSkills / requiredSkills.size()`。
|
||||
|
||||
4. **历史表现评分**:
|
||||
- 考虑网格员的历史完成率和质量评分。
|
||||
- 表现越好,评分越高。
|
||||
- 使用公式: `performanceScore = (completionRate * 0.7) + (qualityRating * 0.3)`。
|
||||
|
||||
5. **综合评分计算**:
|
||||
- 对上述各项评分进行加权求和。
|
||||
- 使用公式: `totalScore = (distanceScore * w1) + (loadScore * w2) + (skillScore * w3) + (performanceScore * w4)`。
|
||||
- 其中w1、w2、w3、w4是各项评分的权重,且满足`w1 + w2 + w3 + w4 = 1`。
|
||||
|
||||
6. **选择最高评分的网格员**:
|
||||
- 根据综合评分对网格员进行排序。
|
||||
- 选择评分最高的网格员作为推荐人选。
|
||||
|
||||
**算法实现**:
|
||||
```java
|
||||
public UserAccount recommendWorkerForTask(Task task, List<UserAccount> availableWorkers) {
|
||||
if (availableWorkers.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 权重配置
|
||||
final double DISTANCE_WEIGHT = 0.4;
|
||||
final double LOAD_WEIGHT = 0.3;
|
||||
final double SKILL_WEIGHT = 0.2;
|
||||
final double PERFORMANCE_WEIGHT = 0.1;
|
||||
|
||||
// 任务位置
|
||||
Point taskLocation = new Point(task.getGridX(), task.getGridY());
|
||||
|
||||
// 计算每个网格员的评分
|
||||
Map<UserAccount, Double> workerScores = new HashMap<>();
|
||||
|
||||
for (UserAccount worker : availableWorkers) {
|
||||
// 1. 地理距离评分
|
||||
Point workerLocation = new Point(worker.getGridX(), worker.getGridY());
|
||||
double distance = calculateDistance(workerLocation, taskLocation);
|
||||
double maxDistance = 10.0; // 最大考虑距离
|
||||
double distanceScore = Math.max(0, maxDistance - distance) / maxDistance;
|
||||
|
||||
// 2. 当前负载评分
|
||||
int currentTasks = taskRepository.countByAssigneeIdAndStatusIn(
|
||||
worker.getId(), Arrays.asList(TaskStatus.ASSIGNED, TaskStatus.IN_PROGRESS));
|
||||
int maxTasks = 5; // 最大任务数
|
||||
double loadScore = (double)(maxTasks - currentTasks) / maxTasks;
|
||||
|
||||
// 3. 专业匹配度评分
|
||||
double skillScore = calculateSkillMatch(worker, task);
|
||||
|
||||
// 4. 历史表现评分
|
||||
double completionRate = workerStatsService.getCompletionRate(worker.getId());
|
||||
double qualityRating = workerStatsService.getAverageQualityRating(worker.getId());
|
||||
double performanceScore = (completionRate * 0.7) + (qualityRating * 0.3);
|
||||
|
||||
// 5. 综合评分
|
||||
double totalScore = (distanceScore * DISTANCE_WEIGHT) +
|
||||
(loadScore * LOAD_WEIGHT) +
|
||||
(skillScore * SKILL_WEIGHT) +
|
||||
(performanceScore * PERFORMANCE_WEIGHT);
|
||||
|
||||
workerScores.put(worker, totalScore);
|
||||
}
|
||||
|
||||
// 选择评分最高的网格员
|
||||
return workerScores.entrySet().stream()
|
||||
.max(Map.Entry.comparingByValue())
|
||||
.map(Map.Entry::getKey)
|
||||
.orElse(null);
|
||||
}
|
||||
```
|
||||
|
||||
**算法输出**:
|
||||
推荐的最佳网格员对象。如果没有合适的网格员,则返回null。
|
||||
|
||||
**算法应用**:
|
||||
在`TaskAssignmentService`中实现,当主管触发自动分配或系统基于反馈自动创建任务时调用。
|
||||
|
||||
### 2.5 数据持久化设计
|
||||
|
||||
系统采用了一种独特的数据持久化方案,不使用传统的关系型数据库,而是以JSON文件的形式存储所有数据。这种设计简化了部署和配置,特别适合快速迭代和中小型应用场景。
|
||||
|
||||
#### 2.5.1 JSON文件存储架构
|
||||
|
||||
系统的数据持久化层基于以下架构:
|
||||
|
||||
1. **核心存储服务**:
|
||||
- `JsonStorageService`: 提供对JSON文件的读写操作,包括序列化和反序列化。
|
||||
- `FileSystemService`: 处理文件系统操作,如创建、读取、更新和删除文件。
|
||||
|
||||
2. **Repository层**:
|
||||
- 为每种核心模型提供专门的Repository类,如`UserRepository`、`FeedbackRepository`等。
|
||||
- 这些Repository类模拟了类似JPA的接口,提供CRUD操作和查询功能。
|
||||
- 内部使用`JsonStorageService`进行实际的文件操作。
|
||||
|
||||
3. **并发控制**:
|
||||
- 使用文件锁机制确保在并发环境下的数据一致性。
|
||||
- 实现了简单的乐观锁定策略,通过版本号检测冲突。
|
||||
|
||||
4. **索引和查询优化**:
|
||||
- 在内存中维护索引结构,加速常见查询操作。
|
||||
- 支持基于字段值的过滤和排序。
|
||||
|
||||
#### 2.5.2 核心JSON文件结构
|
||||
|
||||
系统中的每个核心模型对应一个JSON文件,下面详细描述了这些文件的结构。
|
||||
|
||||
##### `users.json` - 用户账户数据
|
||||
|
||||
存储系统中所有用户的账户信息,包括认证信息和角色权限。
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| --------------------- | ----------------- | ------------------------ | ---------------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 用户的唯一标识符 |
|
||||
| `name` | `String` | 非空 | 用户姓名 |
|
||||
| `phone` | `String` | 非空, **唯一** | 手机号码,可用于登录 |
|
||||
| `email` | `String` | 非空, **唯一** | 电子邮箱,可用于登录 |
|
||||
| `password` | `String` | 非空, 长度>=8 | 加密后的用户密码 |
|
||||
| `gender` | `String` | (ENUM) | 性别 (MALE, FEMALE, OTHER) |
|
||||
| `role` | `String` | (ENUM) | 用户角色 (ADMIN, SUPERVISOR, GRID_WORKER等) |
|
||||
| `status` | `String` | 非空, (ENUM) | 账户状态 (ACTIVE, INACTIVE, SUSPENDED) |
|
||||
| `grid_x` | `Number` | | 关联的网格X坐标 (主要用于网格员) |
|
||||
| `grid_y` | `Number` | | 关联的网格Y坐标 (主要用于网格员) |
|
||||
| `region` | `String` | | 所属区域或地区 |
|
||||
| `level` | `String` | (ENUM) | 用户等级 (JUNIOR, SENIOR, EXPERT) |
|
||||
| `skills` | `Array` | | 技能列表 (JSON数组格式的字符串) |
|
||||
| `enabled` | `Boolean` | 非空, 默认 `true` | 账户是否启用 |
|
||||
| `current_latitude` | `Number` | | 当前纬度坐标 (用于实时定位) |
|
||||
| `current_longitude` | `Number` | | 当前经度坐标 (用于实时定位) |
|
||||
| `failed_login_attempts` | `Number` | 默认 `0` | 连续失败登录次数 |
|
||||
| `lockout_end_time` | `String` | | 账户锁定截止时间 |
|
||||
| `created_at` | `String` | 非空 | 记录创建时间 |
|
||||
| `updated_at` | `String` | 非空 | 记录最后更新时间 |
|
||||
|
||||
##### `feedback.json` - 环境问题反馈数据
|
||||
|
||||
存储用户提交的所有环境问题反馈信息。
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| ---------------- | --------------- | ------------------------ | ---------------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 反馈的唯一标识符 |
|
||||
| `event_id` | `String` | 非空, **唯一** | 人类可读的事件ID |
|
||||
| `title` | `String` | 非空 | 反馈标题 |
|
||||
| `description` | `String` | | 问题详细描述 |
|
||||
| `pollution_type` | `String` | 非空, (ENUM) | 污染类型 (AIR, WATER, SOIL, NOISE) |
|
||||
| `severity_level` | `String` | 非空, (ENUM) | 严重程度 (LOW, MEDIUM, HIGH, CRITICAL) |
|
||||
| `status` | `String` | 非空, (ENUM) | 反馈状态 (PENDING_REVIEW, PROCESSED等) |
|
||||
| `text_address` | `String` | | 文字描述的地址 |
|
||||
| `grid_x` | `Number` | | 事发地网格X坐标 |
|
||||
| `grid_y` | `Number` | | 事发地网格Y坐标 |
|
||||
| `latitude` | `Number` | | 事发地纬度 |
|
||||
| `longitude` | `Number` | | 事发地经度 |
|
||||
| `submitter_id` | `Number` | 外键 (FK) -> users.id (可为空) | 提交者ID (公众提交时可为空) |
|
||||
| `attachments` | `Array` | | 附件列表 (包含文件路径等信息) |
|
||||
| `created_at` | `String` | 非空 | 记录创建时间 |
|
||||
| `updated_at` | `String` | 非空 | 记录最后更新时间 |
|
||||
|
||||
##### `tasks.json` - 任务数据
|
||||
|
||||
存储系统中所有工作任务的信息。
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| ---------------- | --------------- | ------------------------ | ---------------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 任务的唯一标识符 |
|
||||
| `feedback_id` | `Number` | 外键 (FK) -> feedback.id (可为空) | 关联的原始反馈ID |
|
||||
| `assignee_id` | `Number` | 外键 (FK) -> users.id (可为空) | 任务执行人(网格员)ID |
|
||||
| `created_by` | `Number` | 外键 (FK) -> users.id | 任务创建人(主管)ID |
|
||||
| `status` | `String` | 非空, (ENUM) | 任务状态 (CREATED, ASSIGNED, IN_PROGRESS等) |
|
||||
| `title` | `String` | | 任务标题 |
|
||||
| `description` | `String` | | 任务详细描述 |
|
||||
| `pollution_type` | `String` | (ENUM) | 污染类型 |
|
||||
| `severity_level` | `String` | (ENUM) | 严重程度 |
|
||||
| `text_address` | `String` | | 任务地点文字描述 |
|
||||
| `grid_x` | `Number` | | 任务地点网格X坐标 |
|
||||
| `grid_y` | `Number` | | 任务地点网格Y坐标 |
|
||||
| `latitude` | `Number` | | 任务地点纬度 |
|
||||
| `longitude` | `Number` | | 任务地点经度 |
|
||||
| `assigned_at` | `String` | | 任务分配时间 |
|
||||
| `completed_at` | `String` | | 任务完成时间 |
|
||||
| `created_at` | `String` | 非空 | 记录创建时间 |
|
||||
| `updated_at` | `String` | 非空 | 记录最后更新时间 |
|
||||
| `deadline` | `String` | | 任务截止日期 |
|
||||
| `history` | `Array` | | 任务状态历史记录 |
|
||||
| `submissions` | `Array` | | 任务提交记录 |
|
||||
|
||||
##### `grids.json` - 业务网格数据
|
||||
|
||||
存储系统中定义的地理网格信息。
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| --------------- | --------------- | ------------------- | ---------------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 网格的唯一标识符 |
|
||||
| `grid_x` | `Number` | | 网格X坐标 |
|
||||
| `grid_y` | `Number` | | 网格Y坐标 |
|
||||
| `city_name` | `String` | | 所属城市 |
|
||||
| `district_name` | `String` | | 所属区县 |
|
||||
| `description` | `String` | | 网格描述信息 |
|
||||
| `is_obstacle` | `Boolean` | 默认 `false` | 是否为障碍物(如禁区) |
|
||||
| `created_at` | `String` | 非空 | 记录创建时间 |
|
||||
| `updated_at` | `String` | 非空 | 记录最后更新时间 |
|
||||
|
||||
##### `assignments.json` - 任务分配记录数据
|
||||
|
||||
存储任务分配的详细记录。
|
||||
|
||||
| 字段名 | JSON数据类型 | 约束/说明 | 描述 |
|
||||
| ---------------- | --------------- | ------------------------ | -------------------------- |
|
||||
| `id` | `Number` | **唯一标识**, 自增 | 分配记录的唯一标识符 |
|
||||
| `task_id` | `Number` | 非空, 外键 (FK) -> tasks.id | 关联的任务ID |
|
||||
| `assigner_id` | `Number` | 非空, 外键 (FK) -> users.id | 分配者(主管)ID |
|
||||
| `status` | `String` | 非空, (ENUM) | 分配状态 |
|
||||
| `remarks` | `String` | | 分配备注 |
|
||||
| `assignment_time`| `String` | 非空 | 分配时间 |
|
||||
| `deadline` | `String` | | 任务截止日期 |
|
||||
| `created_at` | `String` | 非空 | 记录创建时间 |
|
||||
| `updated_at` | `String` | 非空 | 记录最后更新时间 |
|
||||
36
Report/要求.md
36
Report/要求.md
@@ -1,36 +0,0 @@
|
||||
1\. 能够按照面向对象的思想对系统进行设计。使用UML类图对系统整体建模,抽取出系统中的类、属性、方法、关联,设计合理,符合系统要求;能够应用文件设计该系统的持久化存储结构和机制,存储结构设计合理;界面设计美观实用,符合用户习惯;
|
||||
|
||||
(满足毕业要求3.1:掌握软件生命周期要素,了解软件开发过程管理模型,熟悉软件需求分析、设计、实现、测试、维护以及过程与管理的方法和技术)
|
||||
|
||||
2\. 能够在集成开发环境中使用Java语言实现设计的系统,程序结构清晰,代码书写规范、简洁,能够对实现的系统进行调试、测试和评价,保证实现的系统功能完善,运行稳定;
|
||||
|
||||
(满足毕业要求3.3:能够设计满足特定功能需求与性能需求的解决方案,并体现创新意识)
|
||||
|
||||
3\. 深入理解面向对象的设计思想,掌握面向对象的设计方法,能够应用已有的框架、设计模式解决相应的问题。在解决问题的过程中有自己独到的见解,并能够有所创新;
|
||||
|
||||
(满足毕业要求4.2:能够理解系统软件的设计思路和基本原理,掌握应用软件技术、科学方法,具备创新性地解决软件工程具体问题的能力)
|
||||
|
||||
4\. 能够自学Java语言中关于图形用户界面的知识,并能为开发的系统构造图形用户界面。能够通过网络、课堂、书籍等多处获取所需的知识,并应用这些知识解决相应的问题;
|
||||
|
||||
(满足毕业要求5.1:能够利用图书馆和互联网进行文献检索和资料查询,掌握获取技术、资源、现代工程工具和信息技术工具的能力;)
|
||||
|
||||
5\. 能够将设计、实现和测试过程总结形成实践报告,报告格式规范,报告内容充实、正确,报告叙述逻辑严密,可准确反映出设计和实现的结果,实践过程中出现的问题和解决方案,以及独立分析问题和解决问题的能力。
|
||||
|
||||
(满足毕业要求10.1:具备一定的社交技能和技巧,能够就与本专业相关的当前热点问题发表自己的观点,能够以口头、文稿、图表等方式与业界同行进行技术交流与沟通,能使用通俗易懂的语言与社会公众进行表达与沟通)
|
||||
|
||||
本次实践的项目系统是《东软环保应急》的其中子模块《东软环保公众监督平台》。该系统用于建立环保公众监督平台,拓宽监督渠道,增加环保工作透明度,不断完善公众监督机制,切实增强环境保护实效。
|
||||
|
||||
主要考查线性结构(数组,链表,队列)、树、查找结构以及相关算法的设计与实现。
|
||||
|
||||
整体要求
|
||||
|
||||
(1)所有数据以文件格式保存,文件存储在工程目录中。
|
||||
|
||||
(2)文件数据格式可以是JSON格式,也可以是以对象序列化的方式存储。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
315
Report/需求定义.md
315
Report/需求定义.md
@@ -1,315 +0,0 @@
|
||||
# 需求定义文档
|
||||
|
||||
## 1. 整体业务流程
|
||||
|
||||
下图描述了从公众发现问题、上报、到平台内部流转、处理、并最终反馈结果的完整闭环业务流程。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
%% 定义样式
|
||||
classDef public fill:#d4f1f9,stroke:#05a8e5,color:#333
|
||||
classDef platform fill:#ffe6cc,stroke:#f7a128,color:#333
|
||||
classDef worker fill:#d5e8d4,stroke:#82b366,color:#333
|
||||
classDef supervisor fill:#e1d5e7,stroke:#9673a6,color:#333
|
||||
classDef decision fill:#f8cecc,stroke:#b85450,color:#333
|
||||
classDef start_end fill:#f5f5f5,stroke:#666666,color:#333,stroke-width:2px
|
||||
|
||||
%% 流程开始
|
||||
A([开始]) --> B["[公众端] 发现环境问题"]
|
||||
B --> C["[公众端] 提交反馈<br>(标题/描述/图片/位置)"]
|
||||
|
||||
%% 平台接收与AI处理
|
||||
C --> D["[平台] 接收反馈<br>生成唯一事件ID"]
|
||||
D --> E{"[平台] AI自动审核<br>分析内容/分类"}
|
||||
|
||||
%% AI审核分支
|
||||
E -- "明显无效" --> F1["[平台] 标记为AI_REJECTED"]
|
||||
F1 --> F2["[平台] 通知提交者"]
|
||||
F2 --> Z1([结束])
|
||||
|
||||
E -- "需人工确认" --> G["[主管] 查看反馈详情<br>进行人工审核"]
|
||||
|
||||
%% 主管审核分支
|
||||
G --> H{"[主管] 审核决定"}
|
||||
H -- "驳回" --> I1["[主管] 填写驳回理由"]
|
||||
I1 --> I2["[平台] 更新状态为REJECTED"]
|
||||
I2 --> I3["[平台] 通知提交者"]
|
||||
I3 --> Z2([结束])
|
||||
|
||||
%% 审核通过,创建任务
|
||||
H -- "通过" --> J1["[主管] 确认反馈有效"]
|
||||
J1 --> J2["[平台] 自动创建结构化任务"]
|
||||
J2 --> J3["[平台] 更新反馈状态为PROCESSED"]
|
||||
|
||||
%% 任务分配
|
||||
J3 --> K1{"[主管] 选择分配方式"}
|
||||
K1 -- "手动分配" --> K2["[主管] 选择特定网格员"]
|
||||
K1 -- "智能推荐" --> K3["[平台] 运行分配算法<br>考虑位置/负载/专长"]
|
||||
K3 --> K4["[平台] 推荐最佳人选"]
|
||||
K4 --> K2
|
||||
K2 --> K5["[平台] 创建任务分配记录<br>更新任务状态为ASSIGNED"]
|
||||
K5 --> K6["[平台] 通知网格员"]
|
||||
|
||||
%% 网格员处理
|
||||
K6 --> L1["[网格员] 接收任务通知"]
|
||||
L1 --> L2{"[网格员] 接受任务?"}
|
||||
L2 -- "拒绝" --> K1
|
||||
L2 -- "接受" --> L3["[网格员] 更新任务状态为IN_PROGRESS"]
|
||||
L3 --> L4["[网格员] 查看任务详情<br>获取路径规划"]
|
||||
L4 --> L5["[网格员] 前往现场处理"]
|
||||
L5 --> L6["[网格员] 记录处理过程<br>上传证明材料"]
|
||||
L6 --> L7["[网格员] 提交处理结果<br>更新状态为SUBMITTED"]
|
||||
|
||||
%% 主管审核结果
|
||||
L7 --> M1["[主管] 审核处理结果"]
|
||||
M1 --> M2{"[主管] 结果是否合格?"}
|
||||
M2 -- "不合格" --> M3["[主管] 填写原因<br>要求重新处理"]
|
||||
M3 --> L4
|
||||
|
||||
%% 完成流程
|
||||
M2 -- "合格" --> N1["[主管] 确认任务完成"]
|
||||
N1 --> N2["[平台] 更新任务状态为APPROVED"]
|
||||
N2 --> N3["[平台] 更新反馈状态为CLOSED"]
|
||||
N3 --> N4["[平台] 通知反馈提交者"]
|
||||
N4 --> N5["[平台] 更新统计数据"]
|
||||
N5 --> O["[决策层] 查看数据看板<br>分析环境趋势"]
|
||||
O --> Z3([结束])
|
||||
|
||||
%% 为节点添加类别
|
||||
class A,Z1,Z2,Z3 start_end
|
||||
class B,C,F2,I3,N4 public
|
||||
class D,E,F1,I2,J2,J3,K3,K4,K5,K6,N2,N3,N5 platform
|
||||
class G,H,I1,J1,K1,K2,M1,M2,M3,N1 supervisor
|
||||
class L1,L2,L3,L4,L5,L6,L7 worker
|
||||
class O decision
|
||||
```
|
||||
|
||||
## 2. 功能性需求
|
||||
|
||||
### 2.1 功能层次方框图
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
%% 用户交互层
|
||||
subgraph "用户交互层"
|
||||
direction LR
|
||||
C["公众服务模块(问题上报)"]
|
||||
H["个人中心模块(我的反馈/资料)"]
|
||||
D["管理驾驶舱(数据决策)"]
|
||||
end
|
||||
|
||||
%% 核心业务层
|
||||
subgraph "核心业务层"
|
||||
direction LR
|
||||
AI["AI分析模块(内容审核)"]
|
||||
E["任务管理模块(分配、流转、执行)"]
|
||||
end
|
||||
|
||||
%% 应用支撑层
|
||||
subgraph "应用支撑层"
|
||||
direction LR
|
||||
F["网格与地图模块(LBS & 寻路)"]
|
||||
I["文件服务模块(附件存取)"]
|
||||
end
|
||||
|
||||
%% 基础服务层
|
||||
subgraph "基础服务层"
|
||||
direction LR
|
||||
B["用户与认证模块"]
|
||||
G["系统管理模块(用户/权限)"]
|
||||
J["日志审计模块"]
|
||||
end
|
||||
|
||||
%% 定义关系
|
||||
C -- "提交反馈" --> AI
|
||||
AI -- "分析结果" --> E
|
||||
C -- "附件" --> I
|
||||
E -- "调用" --> F
|
||||
E -- "任务附件" --> I
|
||||
E -- "统计数据" --> D
|
||||
|
||||
H -- "查询个人数据" --> E
|
||||
|
||||
%% 基础服务支撑所有上层模块 (关系隐含)
|
||||
G -- "管理" --> B
|
||||
|
||||
classDef userLayer fill:#d4f1f9,stroke:#05a8e5;
|
||||
classDef coreLayer fill:#ffe6cc,stroke:#f7a128;
|
||||
classDef appSupportLayer fill:#d5e8d4,stroke:#82b366;
|
||||
classDef baseLayer fill:#e1d5e7,stroke:#9673a6;
|
||||
|
||||
class C,H,D userLayer;
|
||||
class AI,E coreLayer;
|
||||
class F,I appSupportLayer;
|
||||
class B,G,J baseLayer;
|
||||
```
|
||||
|
||||
### 2.2 需求描述
|
||||
|
||||
#### 2.2.1 用户与认证模块
|
||||
|
||||
| 功能名称 | 用户与认证模块 |
|
||||
| :--- | :--- |
|
||||
| **优先级** | 高 |
|
||||
| **业务背景** | 作为系统安全的基础,本模块负责管理所有用户的身份验证和访问控制,确保系统资源只能被授权用户访问,同时提供灵活的角色权限管理。 |
|
||||
| **功能说明** | 1. **用户认证**:基于JWT (JSON Web Token) 的安全认证机制,支持账号密码登录,提供令牌刷新功能。<br>2. **权限控制**:基于RBAC (基于角色的访问控制) 模型,预设管理员、主管、网格员等角色,每个角色拥有特定的API访问权限。<br>3. **密码管理**:支持安全的密码重置流程,包括邮箱验证码验证,以及定期密码更新提醒。<br>4. **会话管理**:支持单点登录或多设备登录控制,可配置会话超时策略。 |
|
||||
| **约束条件** | 1. 密码必须符合复杂度要求(至少8位,包含大小写字母、数字和特殊字符)。<br>2. 敏感操作(如修改权限)需要二次验证。<br>3. 密码在数据库中必须使用BCrypt等强哈希算法加密存储。 |
|
||||
| **相关查询** | 1. 按用户名、邮箱或手机号查询用户信息。<br>2. 查询特定角色的所有用户列表。<br>3. 查询用户的权限和访问历史。 |
|
||||
| **其他需求** | 1. 登录失败超过预设次数后,账户应被临时锁定。<br>2. 系统应记录所有关键安全事件(登录、权限变更等)的审计日志。 |
|
||||
| **裁剪说明** | 不可裁剪,此为系统安全的基础组件。 |
|
||||
|
||||
#### 2.2.2 反馈管理模块
|
||||
|
||||
| 功能名称 | 反馈管理模块 |
|
||||
| :--- | :--- |
|
||||
| **优先级** | 高 |
|
||||
| **业务背景** | 作为系统的核心输入端口,本模块负责收集、处理和跟踪所有环境问题反馈,是连接公众与管理部门的桥梁,也是后续任务创建的数据源。 |
|
||||
| **功能说明** | 1. **反馈提交**:提供结构化的表单接口,支持文字描述、污染类型分类、严重程度评估、地理位置标记和多媒体附件上传。<br>2. **AI内容审核**:集成智能审核服务,对反馈内容进行自动分析,识别垃圾信息、重复提交,并进行初步的分类和紧急程度评估。<br>3. **人工审核工作台**:为主管提供高效的反馈审核界面,支持批量处理、快速预览和详情查看。<br>4. **状态追踪**:完整记录反馈从提交到处理完成的全生命周期状态变更,支持多维度的统计和查询。 |
|
||||
| **约束条件** | 1. 反馈提交必须包含至少一张图片和准确的地理位置信息。<br>2. AI审核结果仅作为参考,最终决定权在人工审核者手中。<br>3. 对于紧急程度被标记为"高"的反馈,系统应在1小时内完成审核。 |
|
||||
| **相关查询** | 1. 按状态、时间段、区域、污染类型等多维度查询反馈列表。<br>2. 查看特定反馈的详细信息和处理历史。<br>3. 统计不同类型反馈的数量分布和处理效率。 |
|
||||
| **其他需求** | 1. 支持反馈的优先级标记和升级处理。<br>2. 对于同一区域短时间内的多个相似反馈,系统应能智能识别并提示可能的重复。 |
|
||||
| **裁剪说明** | AI审核功能可在初期简化实现,但反馈的基本提交和人工审核流程不可裁剪。 |
|
||||
|
||||
#### 2.2.3 任务管理模块
|
||||
|
||||
| 功能名称 | 任务管理模块 |
|
||||
| :--- | :--- |
|
||||
| **优先级** | 高 |
|
||||
| **业务背景** | 本模块是系统的核心业务处理单元,负责将审核通过的反馈转化为可执行的工作任务,并对任务的分配、执行和完成进行全流程管理。 |
|
||||
| **功能说明** | 1. **任务创建**:支持从反馈自动生成任务,也支持主管手动创建临时任务,包含任务描述、位置、截止时间、优先级等信息。<br>2. **智能分配**:基于多因素(网格员位置、当前负载、专业技能、历史表现)的任务分配算法,为每个任务推荐最合适的处理人员。<br>3. **任务执行跟踪**:记录任务的每个状态变更(已分配、已接受、进行中、已提交、已审核),支持网格员实时上报处理进度。<br>4. **结果审核**:主管对网格员提交的处理结果进行审核,可以通过或驳回,并提供反馈意见。<br>5. **任务看板**:直观展示不同状态任务的数量和分布,支持拖拽操作进行状态更新。 |
|
||||
| **约束条件** | 1. 任务必须关联到一个有效的反馈或由授权主管手动创建。<br>2. 任务分配时必须考虑网格员的工作区域和当前任务负载。<br>3. 高优先级任务应在24小时内分配并开始处理。<br>4. 任务提交时必须包含处理过程描述和至少一张结果照片。 |
|
||||
| **相关查询** | 1. 按状态、负责人、时间段、区域等多维度查询任务列表。<br>2. 查看特定任务的详细信息、处理历史和相关反馈。<br>3. 统计不同网格员的任务完成率、平均处理时长等绩效指标。 |
|
||||
| **其他需求** | 1. 支持任务的紧急程度升级和重新分配。<br>2. 对于长时间未处理的任务,系统应自动发送提醒通知。<br>3. 支持批量导出任务报告,用于绩效评估和工作汇报。 |
|
||||
| **裁剪说明** | 智能分配算法可以在初期简化实现,但任务的基本创建、分配和状态管理功能不可裁剪。 |
|
||||
|
||||
#### 2.2.4 网格与地图模块
|
||||
|
||||
| 功能名称 | 网格与地图模块 |
|
||||
| :--- | :--- |
|
||||
| **优先级** | 中 |
|
||||
| **业务背景** | 本模块负责对地理空间进行网格化管理,将城市区域划分为可管理的网格单元,并为任务执行提供地理位置支持和路径规划。 |
|
||||
| **功能说明** | 1. **网格定义与管理**:支持管理员定义和维护城市网格系统,包括网格的坐标、属性(如是否为障碍物)和责任人分配。<br>2. **A*寻路算法服务**:基于网格系统和实时路况,为网格员提供从当前位置到任务地点的最优路径规划,考虑距离、交通状况和障碍物。<br>3. **地图可视化**:在地图上直观展示反馈点、任务分布和网格员位置,支持多种筛选条件和图层切换。<br>4. **区域统计**:基于网格系统,生成环境问题热力图,识别高发区域和问题类型分布。 |
|
||||
| **约束条件** | 1. 网格系统应支持多级划分,最小网格单元不应大于500米×500米。<br>2. 路径规划应考虑实际道路情况和障碍物,避免不可通行区域。<br>3. 地图数据应定期更新,确保准确性。 |
|
||||
| **相关查询** | 1. 查询特定区域内的网格定义和属性。<br>2. 查询特定网格的历史问题记录和统计数据。<br>3. 获取两点间的最优路径规划。 |
|
||||
| **其他需求** | 1. 支持网格责任人的灵活调整和临时替换。<br>2. 地图界面应支持常见的交互操作(缩放、平移、点选)。<br>3. 支持离线地图数据缓存,保证在网络不稳定情况下的基本功能。 |
|
||||
| **裁剪说明** | A*寻路算法的高级功能(如考虑实时交通)可以在后期迭代中实现,但基本的网格定义和地图展示功能不应裁剪。 |
|
||||
|
||||
#### 2.2.5 决策支持模块
|
||||
|
||||
| 功能名称 | 决策支持模块 (管理驾驶舱) |
|
||||
| :--- | :--- |
|
||||
| **优先级** | 中 |
|
||||
| **业务背景** | 本模块旨在将系统中沉淀的大量业务数据转化为有价值的决策洞察,帮助管理层了解环境状况、评估治理效果、优化资源配置。 |
|
||||
| **功能说明** | 1. **核心指标看板**:实时展示关键业务指标,如待处理反馈数、进行中任务数、平均处理时长、按时完成率等。<br>2. **多维度分析**:支持按时间、区域、污染类型、处理人等多个维度对数据进行交叉分析和趋势展示。<br>3. **热力图可视化**:在地图上以热力图形式展示环境问题的分布密度,直观识别高发区域。<br>4. **绩效评估**:对网格员和区域的工作效率、问题解决质量等进行量化评估,生成排名和对比分析。<br>5. **预警机制**:基于历史数据和趋势分析,对可能出现的环境风险提前预警。 |
|
||||
| **约束条件** | 1. 数据分析应基于实时或准实时的业务数据,确保决策的时效性。<br>2. 图表和报表应支持多种导出格式(PDF、Excel等),便于进一步分析和汇报。<br>3. 敏感数据(如个人绩效)的访问应受到严格权限控制。 |
|
||||
| **相关查询** | 1. 按自定义时间范围查询各类统计指标。<br>2. 查询特定区域或网格员的历史表现数据。<br>3. 生成定制化的数据报表和分析图表。 |
|
||||
| **其他需求** | 1. 支持数据看板的个性化配置,满足不同管理者的关注点。<br>2. 提供数据异常检测和提醒功能,及时发现数据波动。<br>3. 支持定期自动生成并发送统计报告。 |
|
||||
| **裁剪说明** | 高级分析功能(如预测模型)可以在后期迭代中实现,但基本的数据统计和可视化功能不应裁剪。 |
|
||||
|
||||
## 3. 需求规定
|
||||
|
||||
### 3.1 一般性需求
|
||||
|
||||
* **数据集中管理与共享**:系统应采用统一的数据存储和访问机制,确保各模块间的数据一致性和实时共享。所有业务数据应按照标准化格式进行存储,并通过规范的API进行访问,避免数据孤岛。
|
||||
|
||||
* **高可用性与可靠性**:系统应保证7x24小时的稳定运行,关键业务流程(如反馈提交、任务分配)的可用性应达到99.9%以上。应实现适当的错误处理和故障恢复机制,确保在出现异常情况时能够快速恢复。
|
||||
|
||||
* **安全性与合规性**:
|
||||
* 应用SSL/TLS加密保护所有网络通信。
|
||||
* 实现严格的认证和授权机制,确保用户只能访问其权限范围内的数据和功能。
|
||||
* 敏感数据(如用户密码)必须加密存储,并限制访问权限。
|
||||
* 系统应保留完整的操作日志,支持安全审计和问题追溯。
|
||||
* 符合相关的数据保护法规和隐私要求。
|
||||
|
||||
* **可扩展性与模块化**:系统架构应支持水平扩展和功能模块的灵活添加。核心组件应设计为松耦合的,便于独立升级和替换。API设计应考虑向后兼容性,确保系统可以平滑演进。
|
||||
|
||||
* **用户体验优化**:
|
||||
* 界面设计应简洁直观,符合现代Web应用的设计标准。
|
||||
* 关键操作路径应尽量简化,减少用户点击次数。
|
||||
* 系统响应时间应控制在可接受范围内,核心API的平均响应时间不超过500ms。
|
||||
* 提供适当的操作反馈和状态提示,增强用户对系统的信任感。
|
||||
* 支持响应式设计,确保在不同设备(PC、平板、手机)上的良好体验。
|
||||
|
||||
* **国际化与本地化**:系统应支持多语言界面,初期至少支持中英文切换。日期、时间、数字等格式应根据用户的区域设置进行适当显示。
|
||||
|
||||
* **可维护性与可测试性**:系统代码应遵循统一的编码规范和设计模式,保持良好的可读性和可维护性。核心业务逻辑应有充分的单元测试覆盖,便于后续的功能迭代和质量保障。
|
||||
|
||||
## 4. 数据描述
|
||||
|
||||
### 4.1 用户账户 (UserAccount) 数据结构
|
||||
|
||||
| 字段名 | 描述 | 数据类型 | 约束条件 | 是否必填 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| `id` | 用户唯一标识符 | Long | 主键,自增 | 是 |
|
||||
| `name` | 用户姓名 | String | 最大长度50 | 是 |
|
||||
| `phone` | 手机号码 | String | 符合手机号格式 | 是 |
|
||||
| `email` | 电子邮箱 | String | 符合邮箱格式 | 是 |
|
||||
| `password` | 密码(加密存储) | String | 最小长度8,包含字母、数字和特殊字符 | 是 |
|
||||
| `gender` | 性别 | Enum | MALE, FEMALE, OTHER | 否 |
|
||||
| `role` | 用户角色 | Enum | ADMIN, SUPERVISOR, GRID_WORKER, PUBLIC_USER | 是 |
|
||||
| `status` | 账户状态 | Enum | ACTIVE, INACTIVE, LOCKED | 是 |
|
||||
| `gridX` | 网格X坐标(仅网格员) | Integer | 非负整数 | 否 |
|
||||
| `gridY` | 网格Y坐标(仅网格员) | Integer | 非负整数 | 否 |
|
||||
| `createdAt` | 账户创建时间 | DateTime | ISO 8601格式 | 是 |
|
||||
| `updatedAt` | 账户更新时间 | DateTime | ISO 8601格式 | 是 |
|
||||
| `lastLoginAt` | 最后登录时间 | DateTime | ISO 8601格式 | 否 |
|
||||
|
||||
### 4.2 反馈 (Feedback) 数据结构
|
||||
|
||||
| 字段名 | 描述 | 数据类型 | 约束条件 | 是否必填 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| `id` | 反馈唯一标识符 | Long | 主键,自增 | 是 |
|
||||
| `eventId` | 事件ID(业务编号) | String | UUID格式 | 是 |
|
||||
| `title` | 反馈标题 | String | 最大长度100 | 是 |
|
||||
| `description` | 问题详细描述 | String | 最大长度1000 | 是 |
|
||||
| `pollutionType` | 污染类型 | Enum | AIR, WATER, SOIL, NOISE, OTHER | 是 |
|
||||
| `severityLevel` | 严重程度 | Enum | LOW, MEDIUM, HIGH, CRITICAL | 是 |
|
||||
| `longitude` | 地理位置经度 | Double | 有效范围 | 是 |
|
||||
| `latitude` | 地理位置纬度 | Double | 有效范围 | 是 |
|
||||
| `imageUrls` | 图片URL列表 | Array | 至少一张图片 | 是 |
|
||||
| `status` | 反馈状态 | Enum | PENDING_REVIEW, AI_REJECTED, PROCESSED, CLOSED | 是 |
|
||||
| `submitterId` | 提交者ID | Long | 外键关联UserAccount | 是 |
|
||||
| `reviewerId` | 审核者ID | Long | 外键关联UserAccount | 否 |
|
||||
| `reviewNote` | 审核备注 | String | 最大长度500 | 否 |
|
||||
| `createdAt` | 提交时间 | DateTime | ISO 8601格式 | 是 |
|
||||
| `updatedAt` | 更新时间 | DateTime | ISO 8601格式 | 是 |
|
||||
| `processedAt` | 处理时间 | DateTime | ISO 8601格式 | 否 |
|
||||
|
||||
### 4.3 任务 (Task) 数据结构
|
||||
|
||||
| 字段名 | 描述 | 数据类型 | 约束条件 | 是否必填 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| `id` | 任务唯一标识符 | Long | 主键,自增 | 是 |
|
||||
| `feedbackId` | 关联的反馈ID | Long | 外键关联Feedback | 否 |
|
||||
| `title` | 任务标题 | String | 最大长度100 | 是 |
|
||||
| `description` | 任务描述 | String | 最大长度1000 | 是 |
|
||||
| `assigneeId` | 被指派的网格员ID | Long | 外键关联UserAccount | 否 |
|
||||
| `createdBy` | 创建者ID | Long | 外键关联UserAccount | 是 |
|
||||
| `status` | 任务状态 | Enum | CREATED, ASSIGNED, IN_PROGRESS, SUBMITTED, APPROVED, REJECTED | 是 |
|
||||
| `priority` | 优先级 | Enum | LOW, MEDIUM, HIGH, URGENT | 是 |
|
||||
| `longitude` | 任务地点经度 | Double | 有效范围 | 是 |
|
||||
| `latitude` | 任务地点纬度 | Double | 有效范围 | 是 |
|
||||
| `deadline` | 截止日期 | DateTime | ISO 8601格式 | 否 |
|
||||
| `completionReport` | 完成报告 | String | 最大长度2000 | 否 |
|
||||
| `resultImageUrls` | 结果图片URL列表 | Array | 可为空 | 否 |
|
||||
| `createdAt` | 创建时间 | DateTime | ISO 8601格式 | 是 |
|
||||
| `assignedAt` | 分配时间 | DateTime | ISO 8601格式 | 否 |
|
||||
| `startedAt` | 开始时间 | DateTime | ISO 8601格式 | 否 |
|
||||
| `submittedAt` | 提交时间 | DateTime | ISO 8601格式 | 否 |
|
||||
| `approvedAt` | 审核通过时间 | DateTime | ISO 8601格式 | 否 |
|
||||
| `rejectionReason` | 拒绝原因 | String | 最大长度500 | 否 |
|
||||
|
||||
### 4.4 网格 (Grid) 数据结构
|
||||
|
||||
| 字段名 | 描述 | 数据类型 | 约束条件 | 是否必填 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| `id` | 网格唯一标识符 | Long | 主键,自增 | 是 |
|
||||
| `gridX` | 网格X坐标 | Integer | 非负整数 | 是 |
|
||||
| `gridY` | 网格Y坐标 | Integer | 非负整数 | 是 |
|
||||
| `cityName` | 所属城市 | String | 最大长度50 | 是 |
|
||||
| `districtName` | 所属区县 | String | 最大长度50 | 是 |
|
||||
| `description` | 网格描述 | String | 最大长度200 | 否 |
|
||||
| `isObstacle` | 是否为障碍物 | Boolean | true/false | 是 |
|
||||
| `responsibleUserId` | 负责人ID | Long | 外键关联UserAccount | 否 |
|
||||
| `createdAt` | 创建时间 | DateTime | ISO 8601格式 | 是 |
|
||||
| `updatedAt` | 更新时间 | DateTime | ISO 8601格式 | 是 |
|
||||
@@ -1,614 +0,0 @@
|
||||
# 需求定义文档
|
||||
|
||||
## 系统分析
|
||||
|
||||
### 1. 项目介绍
|
||||
|
||||
#### 1.1 项目背景
|
||||
|
||||
环境监测系统(EMS)是为解决城市环境问题而设计的综合性管理平台。随着城市化进程加速,环境污染问题日益凸显,传统的环境问题上报和处理机制存在流程繁琐、响应缓慢、缺乏透明度等问题。本系统旨在通过数字化手段,构建一个连接公众、管理部门和执行人员的环境监测与治理平台,实现环境问题的快速发现、高效处理和全程监督。
|
||||
|
||||
#### 1.2 项目目标
|
||||
|
||||
1. **建立闭环管理机制**:构建从问题发现、上报、审核、分配、处理到结果反馈的完整闭环流程,确保每个环境问题都能得到妥善解决。
|
||||
2. **提高处理效率**:通过流程优化和智能算法,缩短环境问题从发现到解决的时间,提高环境治理效率。
|
||||
3. **增强公众参与**:为公众提供便捷的问题上报渠道,增强公众参与环境治理的积极性和获得感。
|
||||
4. **辅助决策分析**:通过数据可视化和多维度分析,为管理层提供决策支持,优化资源配置和治理策略。
|
||||
5. **提升治理透明度**:实现环境问题处理全过程可追踪、可监督,增强政府工作透明度和公信力。
|
||||
|
||||
### 2. 业务分析
|
||||
|
||||
#### 2.1 业务痛点
|
||||
|
||||
1. **信息孤岛**:环境问题信息分散在不同部门和系统中,缺乏统一管理和共享机制。
|
||||
2. **流程断裂**:传统环境问题处理流程存在多个环节,各环节之间衔接不畅,容易导致问题处理延误或遗漏。
|
||||
3. **资源分配不均**:缺乏科学的任务分配机制,导致人力资源利用不均衡,部分区域问题积压严重。
|
||||
4. **监督机制不足**:公众难以了解问题处理进度和结果,缺乏有效的监督渠道。
|
||||
5. **数据分析不足**:未能充分利用环境问题数据进行趋势分析和预测,难以支持科学决策。
|
||||
|
||||
#### 2.2 业务价值
|
||||
|
||||
1. **提升公众满意度**:通过快速响应和处理环境问题,提高公众对环境治理工作的满意度。
|
||||
2. **优化资源配置**:基于数据分析和智能算法,实现人力资源的科学分配,提高资源利用效率。
|
||||
3. **降低管理成本**:减少人工干预和纸质流程,降低管理成本,提高工作效率。
|
||||
4. **提升环境质量**:通过高效处理环境问题,改善城市环境质量,提升居民生活品质。
|
||||
5. **强化问责机制**:通过全流程记录和追踪,明确责任分工,强化问责机制。
|
||||
|
||||
#### 2.3 核心业务流程
|
||||
|
||||
环境监测系统的核心业务流程包括问题发现与上报、内容审核、任务创建与分配、任务执行与监督、结果审核与反馈等环节,形成一个完整的闭环管理体系。
|
||||
|
||||
1. **问题发现与上报**:公众通过移动端应用发现环境问题并提交反馈,包括问题描述、位置信息和图片证据。
|
||||
2. **内容审核**:系统通过AI技术对上报内容进行初步审核,筛选出有效信息,并由主管进行人工复核确认。
|
||||
3. **任务创建与分配**:对于审核通过的反馈,系统自动创建任务,并基于智能算法为任务推荐最合适的处理人员。
|
||||
4. **任务执行与监督**:网格员接收任务后,前往现场处理问题,并记录处理过程和结果。
|
||||
5. **结果审核与反馈**:主管对处理结果进行审核,确认任务是否完成,并将处理结果反馈给问题上报者。
|
||||
|
||||
### 3. 功能分析
|
||||
|
||||
#### 3.1 用户角色分析
|
||||
|
||||
环境监测系统涉及四类主要用户角色,每个角色在系统中承担不同的职责:
|
||||
|
||||
1. **公众用户**:系统的信息输入端,负责发现和上报环境问题,是系统的主要服务对象。
|
||||
2. **网格员**:系统的执行端,负责接收任务并前往现场处理环境问题,是系统的核心操作人员。
|
||||
3. **主管**:系统的管理端,负责审核反馈、分配任务、审核结果,是系统的关键决策者。
|
||||
4. **管理员**:系统的维护端,负责用户管理、权限设置、系统配置等基础支撑工作。
|
||||
|
||||
#### 3.2 用例分析
|
||||
|
||||
##### 3.2.1 用例图
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
%% 定义角色
|
||||
PublicUser["公众用户"]
|
||||
GridWorker["网格员"]
|
||||
Supervisor["主管"]
|
||||
Admin["管理员"]
|
||||
|
||||
%% 定义用例
|
||||
UC1["注册与登录"]
|
||||
UC2["提交环境问题反馈"]
|
||||
UC3["查看反馈处理进度"]
|
||||
UC4["接收任务通知"]
|
||||
UC5["执行任务"]
|
||||
UC6["提交处理结果"]
|
||||
UC7["审核反馈内容"]
|
||||
UC8["分配任务"]
|
||||
UC9["审核处理结果"]
|
||||
UC10["查看统计数据"]
|
||||
UC11["管理用户账户"]
|
||||
UC12["配置系统参数"]
|
||||
|
||||
%% 建立关系
|
||||
PublicUser --> UC1
|
||||
PublicUser --> UC2
|
||||
PublicUser --> UC3
|
||||
|
||||
GridWorker --> UC1
|
||||
GridWorker --> UC4
|
||||
GridWorker --> UC5
|
||||
GridWorker --> UC6
|
||||
|
||||
Supervisor --> UC1
|
||||
Supervisor --> UC7
|
||||
Supervisor --> UC8
|
||||
Supervisor --> UC9
|
||||
Supervisor --> UC10
|
||||
|
||||
Admin --> UC1
|
||||
Admin --> UC10
|
||||
Admin --> UC11
|
||||
Admin --> UC12
|
||||
|
||||
%% 设置样式
|
||||
classDef actor fill:#f9f,stroke:#333,stroke-width:2px
|
||||
classDef usecase fill:#ccf,stroke:#33f,stroke-width:1px
|
||||
|
||||
class PublicUser,GridWorker,Supervisor,Admin actor
|
||||
class UC1,UC2,UC3,UC4,UC5,UC6,UC7,UC8,UC9,UC10,UC11,UC12 usecase
|
||||
```
|
||||
|
||||
##### 3.2.2 主要用例描述
|
||||
|
||||
**用例1:提交环境问题反馈**
|
||||
|
||||
- **参与者**:公众用户
|
||||
- **前置条件**:用户已登录系统
|
||||
- **基本流程**:
|
||||
1. 用户选择"提交反馈"功能
|
||||
2. 系统显示反馈提交表单
|
||||
3. 用户填写问题标题、描述、污染类型、严重程度
|
||||
4. 用户上传问题现场图片
|
||||
5. 用户标记问题发生的地理位置
|
||||
6. 用户提交表单
|
||||
7. 系统验证表单数据
|
||||
8. 系统生成唯一事件ID并保存反馈信息
|
||||
9. 系统返回提交成功提示
|
||||
- **替代流程**:
|
||||
- 如果表单验证失败,系统提示错误信息并返回表单页面
|
||||
- 如果图片上传失败,系统提示重新上传
|
||||
- **后置条件**:反馈信息被保存,状态设为"待审核"
|
||||
|
||||
**用例2:审核反馈内容**
|
||||
|
||||
- **参与者**:主管
|
||||
- **前置条件**:主管已登录系统,有待审核的反馈
|
||||
- **基本流程**:
|
||||
1. 主管进入反馈审核页面
|
||||
2. 系统显示待审核反馈列表
|
||||
3. 主管选择一条反馈查看详情
|
||||
4. 系统显示反馈详细信息和AI审核建议
|
||||
5. 主管审核内容并做出决定(通过/驳回)
|
||||
6. 如果通过,主管确认创建任务
|
||||
7. 如果驳回,主管填写驳回理由
|
||||
8. 系统更新反馈状态并通知相关人员
|
||||
- **替代流程**:
|
||||
- 如果需要更多信息,主管可以暂缓决定,标记为"需补充信息"
|
||||
- **后置条件**:反馈状态更新为"已处理"或"已驳回"
|
||||
|
||||
**用例3:执行任务**
|
||||
|
||||
- **参与者**:网格员
|
||||
- **前置条件**:网格员已登录系统,已接受任务
|
||||
- **基本流程**:
|
||||
1. 网格员查看任务详情
|
||||
2. 系统显示任务信息和位置
|
||||
3. 网格员请求路径规划
|
||||
4. 系统生成最优路径
|
||||
5. 网格员前往现场处理问题
|
||||
6. 网格员记录处理过程
|
||||
7. 网格员上传处理结果和证明材料
|
||||
8. 系统保存处理信息并更新任务状态
|
||||
- **替代流程**:
|
||||
- 如果任务无法完成,网格员可提交说明并请求重新分配
|
||||
- **后置条件**:任务状态更新为"已提交",等待主管审核
|
||||
|
||||
#### 3.3 活动图分析
|
||||
|
||||
##### 3.3.1 反馈提交与处理活动图
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> 发现环境问题
|
||||
发现环境问题 --> 填写反馈表单
|
||||
填写反馈表单 --> 上传图片
|
||||
上传图片 --> 标记位置
|
||||
标记位置 --> 提交反馈
|
||||
提交反馈 --> AI自动审核
|
||||
|
||||
state AI自动审核 {
|
||||
[*] --> 内容分析
|
||||
内容分析 --> 垃圾信息检测
|
||||
垃圾信息检测 --> 分类与评级
|
||||
分类与评级 --> [*]
|
||||
}
|
||||
|
||||
AI自动审核 --> 判断AI审核结果
|
||||
判断AI审核结果 --> 明显无效: AI拒绝
|
||||
判断AI审核结果 --> 需人工确认: 需确认
|
||||
|
||||
明显无效 --> 标记为AI_REJECTED
|
||||
标记为AI_REJECTED --> 通知提交者
|
||||
通知提交者 --> [*]
|
||||
|
||||
需人工确认 --> 主管人工审核
|
||||
主管人工审核 --> 判断审核结果
|
||||
|
||||
判断审核结果 --> 驳回: 不通过
|
||||
判断审核结果 --> 通过: 通过
|
||||
|
||||
驳回 --> 填写驳回理由
|
||||
填写驳回理由 --> 更新状态为REJECTED
|
||||
更新状态为REJECTED --> 通知提交者反馈被驳回
|
||||
通知提交者反馈被驳回 --> [*]
|
||||
|
||||
通过 --> 创建任务
|
||||
创建任务 --> 更新反馈状态为PROCESSED
|
||||
更新反馈状态为PROCESSED --> 任务分配流程
|
||||
任务分配流程 --> [*]
|
||||
```
|
||||
|
||||
##### 3.3.2 任务分配与执行活动图
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> 任务创建完成
|
||||
任务创建完成 --> 选择分配方式
|
||||
|
||||
state 选择分配方式 {
|
||||
[*] --> 手动分配
|
||||
[*] --> 智能推荐
|
||||
|
||||
智能推荐 --> 运行分配算法
|
||||
运行分配算法 --> 推荐最佳人选
|
||||
推荐最佳人选 --> 确认人选
|
||||
|
||||
手动分配 --> 选择特定网格员
|
||||
选择特定网格员 --> 确认人选
|
||||
|
||||
确认人选 --> [*]
|
||||
}
|
||||
|
||||
选择分配方式 --> 创建任务分配记录
|
||||
创建任务分配记录 --> 更新任务状态为ASSIGNED
|
||||
更新任务状态为ASSIGNED --> 通知网格员
|
||||
|
||||
通知网格员 --> 网格员接收通知
|
||||
网格员接收通知 --> 判断是否接受
|
||||
|
||||
判断是否接受 --> 拒绝: 拒绝
|
||||
判断是否接受 --> 接受: 接受
|
||||
|
||||
拒绝 --> 选择分配方式
|
||||
|
||||
接受 --> 更新状态为IN_PROGRESS
|
||||
更新状态为IN_PROGRESS --> 获取路径规划
|
||||
获取路径规划 --> 前往现场处理
|
||||
前往现场处理 --> 记录处理过程
|
||||
记录处理过程 --> 上传处理结果
|
||||
上传处理结果 --> 提交处理结果
|
||||
提交处理结果 --> 更新状态为SUBMITTED
|
||||
|
||||
更新状态为SUBMITTED --> 主管审核结果
|
||||
主管审核结果 --> 判断结果是否合格
|
||||
|
||||
判断结果是否合格 --> 不合格: 不合格
|
||||
判断结果是否合格 --> 合格: 合格
|
||||
|
||||
不合格 --> 填写原因要求重新处理
|
||||
填写原因要求重新处理 --> 获取路径规划
|
||||
|
||||
合格 --> 确认任务完成
|
||||
确认任务完成 --> 更新任务状态为APPROVED
|
||||
更新任务状态为APPROVED --> 更新反馈状态为CLOSED
|
||||
更新反馈状态为CLOSED --> 通知反馈提交者
|
||||
通知反馈提交者 --> 更新统计数据
|
||||
更新统计数据 --> [*]
|
||||
```
|
||||
|
||||
### 4. 可行性分析
|
||||
|
||||
#### 4.1 技术可行性
|
||||
|
||||
1. **前端技术**:采用Vue 3框架构建用户界面,结合Element Plus组件库,可以快速开发出美观、响应式的Web应用,满足不同设备的访问需求。
|
||||
2. **后端技术**:基于Spring Boot 3框架和Java 17,具备高性能、高并发处理能力,能够满足系统的稳定性和扩展性需求。
|
||||
3. **地图服务**:可以集成百度地图、高德地图等成熟的地图API,实现地理位置标记、路径规划等功能。
|
||||
4. **AI技术**:可以利用现有的自然语言处理和图像识别技术,实现对反馈内容的智能分析和审核。
|
||||
5. **数据存储**:采用JSON文件存储方案,简化部署和维护,适合中小规模系统的快速实现。
|
||||
|
||||
#### 4.2 经济可行性
|
||||
|
||||
1. **开发成本**:采用主流开源框架和技术栈,降低开发成本和技术门槛。
|
||||
2. **维护成本**:模块化设计和完善的文档,降低后期维护和升级成本。
|
||||
3. **投资回报**:通过提高环境问题处理效率,减少人力资源浪费,长期来看具有良好的投资回报。
|
||||
4. **社会效益**:改善城市环境质量,提升居民生活满意度,产生显著的社会效益。
|
||||
|
||||
#### 4.3 操作可行性
|
||||
|
||||
1. **用户接受度**:系统界面设计简洁直观,操作流程符合用户习惯,易于被各类用户接受和使用。
|
||||
2. **培训需求**:系统操作简单,只需简单培训即可上手,降低推广和应用门槛。
|
||||
3. **业务适应性**:系统流程设计符合环境问题处理的实际业务需求,能够无缝融入现有工作流程。
|
||||
|
||||
#### 4.4 法律可行性
|
||||
|
||||
1. **数据隐私**:系统设计符合数据保护法规要求,对用户隐私数据进行加密存储和严格权限控制。
|
||||
2. **知识产权**:系统开发过程中使用的第三方库和组件均为开源或已获得授权,不存在知识产权风险。
|
||||
3. **合规性**:系统功能和流程设计符合相关法律法规和行业标准,确保合法合规运营。
|
||||
|
||||
## 5. 整体业务流程
|
||||
|
||||
下图描述了从公众发现问题、上报、到平台内部流转、处理、并最终反馈结果的完整闭环业务流程。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
%% 定义样式
|
||||
classDef public fill:#d4f1f9,stroke:#05a8e5,color:#333
|
||||
classDef platform fill:#ffe6cc,stroke:#f7a128,color:#333
|
||||
classDef worker fill:#d5e8d4,stroke:#82b366,color:#333
|
||||
classDef supervisor fill:#e1d5e7,stroke:#9673a6,color:#333
|
||||
classDef decision fill:#f8cecc,stroke:#b85450,color:#333
|
||||
classDef start_end fill:#f5f5f5,stroke:#666666,color:#333,stroke-width:2px
|
||||
|
||||
%% 流程开始
|
||||
A([开始]) --> B["[公众端] 发现环境问题"]
|
||||
B --> C["[公众端] 提交反馈<br>(标题/描述/图片/位置)"]
|
||||
|
||||
%% 平台接收与AI处理
|
||||
C --> D["[平台] 接收反馈<br>生成唯一事件ID"]
|
||||
D --> E{"[平台] AI自动审核<br>分析内容/分类"}
|
||||
|
||||
%% AI审核分支
|
||||
E -- "明显无效" --> F1["[平台] 标记为AI_REJECTED"]
|
||||
F1 --> F2["[平台] 通知提交者"]
|
||||
F2 --> Z1([结束])
|
||||
|
||||
E -- "需人工确认" --> G["[主管] 查看反馈详情<br>进行人工审核"]
|
||||
|
||||
%% 主管审核分支
|
||||
G --> H{"[主管] 审核决定"}
|
||||
H -- "驳回" --> I1["[主管] 填写驳回理由"]
|
||||
I1 --> I2["[平台] 更新状态为REJECTED"]
|
||||
I2 --> I3["[平台] 通知提交者"]
|
||||
I3 --> Z2([结束])
|
||||
|
||||
%% 审核通过,创建任务
|
||||
H -- "通过" --> J1["[主管] 确认反馈有效"]
|
||||
J1 --> J2["[平台] 自动创建结构化任务"]
|
||||
J2 --> J3["[平台] 更新反馈状态为PROCESSED"]
|
||||
|
||||
%% 任务分配
|
||||
J3 --> K1{"[主管] 选择分配方式"}
|
||||
K1 -- "手动分配" --> K2["[主管] 选择特定网格员"]
|
||||
K1 -- "智能推荐" --> K3["[平台] 运行分配算法<br>考虑位置/负载/专长"]
|
||||
K3 --> K4["[平台] 推荐最佳人选"]
|
||||
K4 --> K2
|
||||
K2 --> K5["[平台] 创建任务分配记录<br>更新任务状态为ASSIGNED"]
|
||||
K5 --> K6["[平台] 通知网格员"]
|
||||
|
||||
%% 网格员处理
|
||||
K6 --> L1["[网格员] 接收任务通知"]
|
||||
L1 --> L2{"[网格员] 接受任务?"}
|
||||
L2 -- "拒绝" --> K1
|
||||
L2 -- "接受" --> L3["[网格员] 更新任务状态为IN_PROGRESS"]
|
||||
L3 --> L4["[网格员] 查看任务详情<br>获取路径规划"]
|
||||
L4 --> L5["[网格员] 前往现场处理"]
|
||||
L5 --> L6["[网格员] 记录处理过程<br>上传证明材料"]
|
||||
L6 --> L7["[网格员] 提交处理结果<br>更新状态为SUBMITTED"]
|
||||
|
||||
%% 主管审核结果
|
||||
L7 --> M1["[主管] 审核处理结果"]
|
||||
M1 --> M2{"[主管] 结果是否合格?"}
|
||||
M2 -- "不合格" --> M3["[主管] 填写原因<br>要求重新处理"]
|
||||
M3 --> L4
|
||||
|
||||
%% 完成流程
|
||||
M2 -- "合格" --> N1["[主管] 确认任务完成"]
|
||||
N1 --> N2["[平台] 更新任务状态为APPROVED"]
|
||||
N2 --> N3["[平台] 更新反馈状态为CLOSED"]
|
||||
N3 --> N4["[平台] 通知反馈提交者"]
|
||||
N4 --> N5["[平台] 更新统计数据"]
|
||||
N5 --> O["[决策层] 查看数据看板<br>分析环境趋势"]
|
||||
O --> Z3([结束])
|
||||
|
||||
%% 为节点添加类别
|
||||
class A,Z1,Z2,Z3 start_end
|
||||
class B,C,F2,I3,N4 public
|
||||
class D,E,F1,I2,J2,J3,K3,K4,K5,K6,N2,N3,N5 platform
|
||||
class G,H,I1,J1,K1,K2,M1,M2,M3,N1 supervisor
|
||||
class L1,L2,L3,L4,L5,L6,L7 worker
|
||||
class O decision
|
||||
```
|
||||
|
||||
## 6. 功能性需求
|
||||
|
||||
### 6.1 功能层次方框图
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
%% 用户交互层
|
||||
subgraph "用户交互层"
|
||||
direction LR
|
||||
C["公众服务模块\n(问题上报)"]
|
||||
H["个人中心模块\n(我的反馈/资料)"]
|
||||
D["管理驾驶舱\n(数据决策)"]
|
||||
end
|
||||
|
||||
%% 核心业务层
|
||||
subgraph "核心业务层"
|
||||
direction LR
|
||||
AI["AI分析模块\n(内容审核)"]
|
||||
E["任务管理模块\n(分配、流转、执行)"]
|
||||
end
|
||||
|
||||
%% 应用支撑层
|
||||
subgraph "应用支撑层"
|
||||
direction LR
|
||||
F["网格与地图模块\n(LBS & 寻路)"]
|
||||
I["文件服务模块\n(附件存取)"]
|
||||
end
|
||||
|
||||
%% 基础服务层
|
||||
subgraph "基础服务层"
|
||||
direction LR
|
||||
B["用户与认证模块"]
|
||||
G["系统管理模块\n(用户/权限)"]
|
||||
J["日志审计模块"]
|
||||
end
|
||||
|
||||
%% 定义关系
|
||||
C -- "提交反馈" --> AI
|
||||
AI -- "分析结果" --> E
|
||||
C -- "附件" --> I
|
||||
E -- "调用" --> F
|
||||
E -- "任务附件" --> I
|
||||
E -- "统计数据" --> D
|
||||
|
||||
H -- "查询个人数据" --> E
|
||||
|
||||
%% 基础服务支撑所有上层模块 (关系隐含)
|
||||
G -- "管理" --> B
|
||||
|
||||
classDef userLayer fill:#d4f1f9,stroke:#05a8e5;
|
||||
classDef coreLayer fill:#ffe6cc,stroke:#f7a128;
|
||||
classDef appSupportLayer fill:#d5e8d4,stroke:#82b366;
|
||||
classDef baseLayer fill:#e1d5e7,stroke:#9673a6;
|
||||
|
||||
class C,H,D userLayer;
|
||||
class AI,E coreLayer;
|
||||
class F,I appSupportLayer;
|
||||
class B,G,J baseLayer;
|
||||
```
|
||||
|
||||
### 6.2 需求描述
|
||||
|
||||
#### 6.2.1 用户与认证模块
|
||||
|
||||
| 功能名称 | 用户与认证模块 |
|
||||
| :--- | :--- |
|
||||
| **优先级** | 高 |
|
||||
| **业务背景** | 作为系统安全的基础,本模块负责管理所有用户的身份验证和访问控制,确保系统资源只能被授权用户访问,同时提供灵活的角色权限管理。 |
|
||||
| **功能说明** | 1. **用户认证**:基于JWT (JSON Web Token) 的安全认证机制,支持账号密码登录,提供令牌刷新功能。<br>2. **权限控制**:基于RBAC (基于角色的访问控制) 模型,预设管理员、主管、网格员等角色,每个角色拥有特定的API访问权限。<br>3. **密码管理**:支持安全的密码重置流程,包括邮箱验证码验证,以及定期密码更新提醒。<br>4. **会话管理**:支持单点登录或多设备登录控制,可配置会话超时策略。 |
|
||||
| **约束条件** | 1. 密码必须符合复杂度要求(至少8位,包含大小写字母、数字和特殊字符)。<br>2. 敏感操作(如修改权限)需要二次验证。<br>3. 密码在数据库中必须使用BCrypt等强哈希算法加密存储。 |
|
||||
| **相关查询** | 1. 按用户名、邮箱或手机号查询用户信息。<br>2. 查询特定角色的所有用户列表。<br>3. 查询用户的权限和访问历史。 |
|
||||
| **其他需求** | 1. 登录失败超过预设次数后,账户应被临时锁定。<br>2. 系统应记录所有关键安全事件(登录、权限变更等)的审计日志。 |
|
||||
| **裁剪说明** | 不可裁剪,此为系统安全的基础组件。 |
|
||||
|
||||
#### 6.2.2 反馈管理模块
|
||||
|
||||
| 功能名称 | 反馈管理模块 |
|
||||
| :--- | :--- |
|
||||
| **优先级** | 高 |
|
||||
| **业务背景** | 作为系统的核心输入端口,本模块负责收集、处理和跟踪所有环境问题反馈,是连接公众与管理部门的桥梁,也是后续任务创建的数据源。 |
|
||||
| **功能说明** | 1. **反馈提交**:提供结构化的表单接口,支持文字描述、污染类型分类、严重程度评估、地理位置标记和多媒体附件上传。<br>2. **AI内容审核**:集成智能审核服务,对反馈内容进行自动分析,识别垃圾信息、重复提交,并进行初步的分类和紧急程度评估。<br>3. **人工审核工作台**:为主管提供高效的反馈审核界面,支持批量处理、快速预览和详情查看。<br>4. **状态追踪**:完整记录反馈从提交到处理完成的全生命周期状态变更,支持多维度的统计和查询。 |
|
||||
| **约束条件** | 1. 反馈提交必须包含至少一张图片和准确的地理位置信息。<br>2. AI审核结果仅作为参考,最终决定权在人工审核者手中。<br>3. 对于紧急程度被标记为"高"的反馈,系统应在1小时内完成审核。 |
|
||||
| **相关查询** | 1. 按状态、时间段、区域、污染类型等多维度查询反馈列表。<br>2. 查看特定反馈的详细信息和处理历史。<br>3. 统计不同类型反馈的数量分布和处理效率。 |
|
||||
| **其他需求** | 1. 支持反馈的优先级标记和升级处理。<br>2. 对于同一区域短时间内的多个相似反馈,系统应能智能识别并提示可能的重复。 |
|
||||
| **裁剪说明** | AI审核功能可在初期简化实现,但反馈的基本提交和人工审核流程不可裁剪。 |
|
||||
|
||||
#### 6.2.3 任务管理模块
|
||||
|
||||
| 功能名称 | 任务管理模块 |
|
||||
| :--- | :--- |
|
||||
| **优先级** | 高 |
|
||||
| **业务背景** | 本模块是系统的核心业务处理单元,负责将审核通过的反馈转化为可执行的工作任务,并对任务的分配、执行和完成进行全流程管理。 |
|
||||
| **功能说明** | 1. **任务创建**:支持从反馈自动生成任务,也支持主管手动创建临时任务,包含任务描述、位置、截止时间、优先级等信息。<br>2. **智能分配**:基于多因素(网格员位置、当前负载、专业技能、历史表现)的任务分配算法,为每个任务推荐最合适的处理人员。<br>3. **任务执行跟踪**:记录任务的每个状态变更(已分配、已接受、进行中、已提交、已审核),支持网格员实时上报处理进度。<br>4. **结果审核**:主管对网格员提交的处理结果进行审核,可以通过或驳回,并提供反馈意见。<br>5. **任务看板**:直观展示不同状态任务的数量和分布,支持拖拽操作进行状态更新。 |
|
||||
| **约束条件** | 1. 任务必须关联到一个有效的反馈或由授权主管手动创建。<br>2. 任务分配时必须考虑网格员的工作区域和当前任务负载。<br>3. 高优先级任务应在24小时内分配并开始处理。<br>4. 任务提交时必须包含处理过程描述和至少一张结果照片。 |
|
||||
| **相关查询** | 1. 按状态、负责人、时间段、区域等多维度查询任务列表。<br>2. 查看特定任务的详细信息、处理历史和相关反馈。<br>3. 统计不同网格员的任务完成率、平均处理时长等绩效指标。 |
|
||||
| **其他需求** | 1. 支持任务的紧急程度升级和重新分配。<br>2. 对于长时间未处理的任务,系统应自动发送提醒通知。<br>3. 支持批量导出任务报告,用于绩效评估和工作汇报。 |
|
||||
| **裁剪说明** | 智能分配算法可以在初期简化实现,但任务的基本创建、分配和状态管理功能不可裁剪。 |
|
||||
|
||||
#### 6.2.4 网格与地图模块
|
||||
|
||||
| 功能名称 | 网格与地图模块 |
|
||||
| :--- | :--- |
|
||||
| **优先级** | 中 |
|
||||
| **业务背景** | 本模块负责对地理空间进行网格化管理,将城市区域划分为可管理的网格单元,并为任务执行提供地理位置支持和路径规划。 |
|
||||
| **功能说明** | 1. **网格定义与管理**:支持管理员定义和维护城市网格系统,包括网格的坐标、属性(如是否为障碍物)和责任人分配。<br>2. **A*寻路算法服务**:基于网格系统和实时路况,为网格员提供从当前位置到任务地点的最优路径规划,考虑距离、交通状况和障碍物。<br>3. **地图可视化**:在地图上直观展示反馈点、任务分布和网格员位置,支持多种筛选条件和图层切换。<br>4. **区域统计**:基于网格系统,生成环境问题热力图,识别高发区域和问题类型分布。 |
|
||||
| **约束条件** | 1. 网格系统应支持多级划分,最小网格单元不应大于500米×500米。<br>2. 路径规划应考虑实际道路情况和障碍物,避免不可通行区域。<br>3. 地图数据应定期更新,确保准确性。 |
|
||||
| **相关查询** | 1. 查询特定区域内的网格定义和属性。<br>2. 查询特定网格的历史问题记录和统计数据。<br>3. 获取两点间的最优路径规划。 |
|
||||
| **其他需求** | 1. 支持网格责任人的灵活调整和临时替换。<br>2. 地图界面应支持常见的交互操作(缩放、平移、点选)。<br>3. 支持离线地图数据缓存,保证在网络不稳定情况下的基本功能。 |
|
||||
| **裁剪说明** | A*寻路算法的高级功能(如考虑实时交通)可以在后期迭代中实现,但基本的网格定义和地图展示功能不应裁剪。 |
|
||||
|
||||
#### 6.2.5 决策支持模块
|
||||
|
||||
| 功能名称 | 决策支持模块 (管理驾驶舱) |
|
||||
| :--- | :--- |
|
||||
| **优先级** | 中 |
|
||||
| **业务背景** | 本模块旨在将系统中沉淀的大量业务数据转化为有价值的决策洞察,帮助管理层了解环境状况、评估治理效果、优化资源配置。 |
|
||||
| **功能说明** | 1. **核心指标看板**:实时展示关键业务指标,如待处理反馈数、进行中任务数、平均处理时长、按时完成率等。<br>2. **多维度分析**:支持按时间、区域、污染类型、处理人等多个维度对数据进行交叉分析和趋势展示。<br>3. **热力图可视化**:在地图上以热力图形式展示环境问题的分布密度,直观识别高发区域。<br>4. **绩效评估**:对网格员和区域的工作效率、问题解决质量等进行量化评估,生成排名和对比分析。<br>5. **预警机制**:基于历史数据和趋势分析,对可能出现的环境风险提前预警。 |
|
||||
| **约束条件** | 1. 数据分析应基于实时或准实时的业务数据,确保决策的时效性。<br>2. 图表和报表应支持多种导出格式(PDF、Excel等),便于进一步分析和汇报。<br>3. 敏感数据(如个人绩效)的访问应受到严格权限控制。 |
|
||||
| **相关查询** | 1. 按自定义时间范围查询各类统计指标。<br>2. 查询特定区域或网格员的历史表现数据。<br>3. 生成定制化的数据报表和分析图表。 |
|
||||
| **其他需求** | 1. 支持数据看板的个性化配置,满足不同管理者的关注点。<br>2. 提供数据异常检测和提醒功能,及时发现数据波动。<br>3. 支持定期自动生成并发送统计报告。 |
|
||||
| **裁剪说明** | 高级分析功能(如预测模型)可以在后期迭代中实现,但基本的数据统计和可视化功能不应裁剪。 |
|
||||
|
||||
## 7. 需求规定
|
||||
|
||||
### 7.1 一般性需求
|
||||
|
||||
* **数据集中管理与共享**:系统应采用统一的数据存储和访问机制,确保各模块间的数据一致性和实时共享。所有业务数据应按照标准化格式进行存储,并通过规范的API进行访问,避免数据孤岛。
|
||||
|
||||
* **高可用性与可靠性**:系统应保证7x24小时的稳定运行,关键业务流程(如反馈提交、任务分配)的可用性应达到99.9%以上。应实现适当的错误处理和故障恢复机制,确保在出现异常情况时能够快速恢复。
|
||||
|
||||
* **安全性与合规性**:
|
||||
* 应用SSL/TLS加密保护所有网络通信。
|
||||
* 实现严格的认证和授权机制,确保用户只能访问其权限范围内的数据和功能。
|
||||
* 敏感数据(如用户密码)必须加密存储,并限制访问权限。
|
||||
* 系统应保留完整的操作日志,支持安全审计和问题追溯。
|
||||
* 符合相关的数据保护法规和隐私要求。
|
||||
|
||||
* **可扩展性与模块化**:系统架构应支持水平扩展和功能模块的灵活添加。核心组件应设计为松耦合的,便于独立升级和替换。API设计应考虑向后兼容性,确保系统可以平滑演进。
|
||||
|
||||
* **用户体验优化**:
|
||||
* 界面设计应简洁直观,符合现代Web应用的设计标准。
|
||||
* 关键操作路径应尽量简化,减少用户点击次数。
|
||||
* 系统响应时间应控制在可接受范围内,核心API的平均响应时间不超过500ms。
|
||||
* 提供适当的操作反馈和状态提示,增强用户对系统的信任感。
|
||||
* 支持响应式设计,确保在不同设备(PC、平板、手机)上的良好体验。
|
||||
|
||||
* **国际化与本地化**:系统应支持多语言界面,初期至少支持中英文切换。日期、时间、数字等格式应根据用户的区域设置进行适当显示。
|
||||
|
||||
* **可维护性与可测试性**:系统代码应遵循统一的编码规范和设计模式,保持良好的可读性和可维护性。核心业务逻辑应有充分的单元测试覆盖,便于后续的功能迭代和质量保障。
|
||||
|
||||
## 8. 数据描述
|
||||
|
||||
### 8.1 用户账户 (UserAccount) 数据结构
|
||||
|
||||
| 字段名 | 描述 | 数据类型 | 约束条件 | 是否必填 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| `id` | 用户唯一标识符 | Long | 主键,自增 | 是 |
|
||||
| `name` | 用户姓名 | String | 最大长度50 | 是 |
|
||||
| `phone` | 手机号码 | String | 符合手机号格式 | 是 |
|
||||
| `email` | 电子邮箱 | String | 符合邮箱格式 | 是 |
|
||||
| `password` | 密码(加密存储) | String | 最小长度8,包含字母、数字和特殊字符 | 是 |
|
||||
| `gender` | 性别 | Enum | MALE, FEMALE, OTHER | 否 |
|
||||
| `role` | 用户角色 | Enum | ADMIN, SUPERVISOR, GRID_WORKER, PUBLIC_USER | 是 |
|
||||
| `status` | 账户状态 | Enum | ACTIVE, INACTIVE, LOCKED | 是 |
|
||||
| `gridX` | 网格X坐标(仅网格员) | Integer | 非负整数 | 否 |
|
||||
| `gridY` | 网格Y坐标(仅网格员) | Integer | 非负整数 | 否 |
|
||||
| `createdAt` | 账户创建时间 | DateTime | ISO 8601格式 | 是 |
|
||||
| `updatedAt` | 账户更新时间 | DateTime | ISO 8601格式 | 是 |
|
||||
| `lastLoginAt` | 最后登录时间 | DateTime | ISO 8601格式 | 否 |
|
||||
|
||||
### 8.2 反馈 (Feedback) 数据结构
|
||||
|
||||
| 字段名 | 描述 | 数据类型 | 约束条件 | 是否必填 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| `id` | 反馈唯一标识符 | Long | 主键,自增 | 是 |
|
||||
| `eventId` | 事件ID(业务编号) | String | UUID格式 | 是 |
|
||||
| `title` | 反馈标题 | String | 最大长度100 | 是 |
|
||||
| `description` | 问题详细描述 | String | 最大长度1000 | 是 |
|
||||
| `pollutionType` | 污染类型 | Enum | AIR, WATER, SOIL, NOISE, OTHER | 是 |
|
||||
| `severityLevel` | 严重程度 | Enum | LOW, MEDIUM, HIGH, CRITICAL | 是 |
|
||||
| `longitude` | 地理位置经度 | Double | 有效范围 | 是 |
|
||||
| `latitude` | 地理位置纬度 | Double | 有效范围 | 是 |
|
||||
| `imageUrls` | 图片URL列表 | Array | 至少一张图片 | 是 |
|
||||
| `status` | 反馈状态 | Enum | PENDING_REVIEW, AI_REJECTED, PROCESSED, CLOSED | 是 |
|
||||
| `submitterId` | 提交者ID | Long | 外键关联UserAccount | 是 |
|
||||
| `reviewerId` | 审核者ID | Long | 外键关联UserAccount | 否 |
|
||||
| `reviewNote` | 审核备注 | String | 最大长度500 | 否 |
|
||||
| `createdAt` | 提交时间 | DateTime | ISO 8601格式 | 是 |
|
||||
| `updatedAt` | 更新时间 | DateTime | ISO 8601格式 | 是 |
|
||||
| `processedAt` | 处理时间 | DateTime | ISO 8601格式 | 否 |
|
||||
|
||||
### 8.3 任务 (Task) 数据结构
|
||||
|
||||
| 字段名 | 描述 | 数据类型 | 约束条件 | 是否必填 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| `id` | 任务唯一标识符 | Long | 主键,自增 | 是 |
|
||||
| `feedbackId` | 关联的反馈ID | Long | 外键关联Feedback | 否 |
|
||||
| `title` | 任务标题 | String | 最大长度100 | 是 |
|
||||
| `description` | 任务描述 | String | 最大长度1000 | 是 |
|
||||
| `assigneeId` | 被指派的网格员ID | Long | 外键关联UserAccount | 否 |
|
||||
| `createdBy` | 创建者ID | Long | 外键关联UserAccount | 是 |
|
||||
| `status` | 任务状态 | Enum | CREATED, ASSIGNED, IN_PROGRESS, SUBMITTED, APPROVED, REJECTED | 是 |
|
||||
| `priority` | 优先级 | Enum | LOW, MEDIUM, HIGH, URGENT | 是 |
|
||||
| `longitude` | 任务地点经度 | Double | 有效范围 | 是 |
|
||||
| `latitude` | 任务地点纬度 | Double | 有效范围 | 是 |
|
||||
| `deadline` | 截止日期 | DateTime | ISO 8601格式 | 否 |
|
||||
| `completionReport` | 完成报告 | String | 最大长度2000 | 否 |
|
||||
| `resultImageUrls` | 结果图片URL列表 | Array | 可为空 | 否 |
|
||||
| `createdAt` | 创建时间 | DateTime | ISO 8601格式 | 是 |
|
||||
| `assignedAt` | 分配时间 | DateTime | ISO 8601格式 | 否 |
|
||||
| `startedAt` | 开始时间 | DateTime | ISO 8601格式 | 否 |
|
||||
| `submittedAt` | 提交时间 | DateTime | ISO 8601格式 | 否 |
|
||||
| `approvedAt` | 审核通过时间 | DateTime | ISO 8601格式 | 否 |
|
||||
| `rejectionReason` | 拒绝原因 | String | 最大长度500 | 否 |
|
||||
|
||||
### 8.4 网格 (Grid) 数据结构
|
||||
|
||||
| 字段名 | 描述 | 数据类型 | 约束条件 | 是否必填 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| `id` | 网格唯一标识符 | Long | 主键,自增 | 是 |
|
||||
| `gridX` | 网格X坐标 | Integer | 非负整数 | 是 |
|
||||
| `gridY` | 网格Y坐标 | Integer | 非负整数 | 是 |
|
||||
| `cityName` | 所属城市 | String | 最大长度50 | 是 |
|
||||
| `districtName` | 所属区县 | String | 最大长度50 | 是 |
|
||||
| `description` | 网格描述 | String | 最大长度200 | 否 |
|
||||
| `isObstacle` | 是否为障碍物 | Boolean | true/false | 是 |
|
||||
| `responsibleUserId` | 负责人ID | Long | 外键关联UserAccount | 否 |
|
||||
| `createdAt` | 创建时间 | DateTime | ISO 8601格式 | 是 |
|
||||
| `updatedAt` | 更新时间 | DateTime | ISO 8601格式 | 是 |
|
||||
|
||||
</rewritten_file>
|
||||
@@ -1,729 +0,0 @@
|
||||
# 需求定义文档
|
||||
|
||||
## 1. 项目介绍
|
||||
|
||||
### 1.1 项目背景
|
||||
|
||||
环境监测系统(EMS)是为解决城市环境问题而设计的综合性管理平台。随着城市化进程加速,环境污染问题日益凸显,传统的环境问题上报和处理机制存在流程繁琐、响应缓慢、缺乏透明度等问题。本系统旨在通过数字化手段,构建一个连接公众、管理部门和执行人员的环境监测与治理平台,实现环境问题的快速发现、高效处理和全程监督。
|
||||
|
||||
### 1.2 项目目标
|
||||
|
||||
1. **建立闭环管理机制**:构建从问题发现、上报、审核、分配、处理到结果反馈的完整闭环流程,确保每个环境问题都能得到妥善解决。
|
||||
2. **提高处理效率**:通过流程优化和智能算法,缩短环境问题从发现到解决的时间,提高环境治理效率。
|
||||
3. **增强公众参与**:为公众提供便捷的问题上报渠道,增强公众参与环境治理的积极性和获得感。
|
||||
4. **辅助决策分析**:通过数据可视化和多维度分析,为管理层提供决策支持,优化资源配置和治理策略。
|
||||
5. **提升治理透明度**:实现环境问题处理全过程可追踪、可监督,增强政府工作透明度和公信力。
|
||||
|
||||
## 2. 系统分析
|
||||
|
||||
### 2.1 业务痛点分析
|
||||
|
||||
1. **信息孤岛**:环境问题信息分散在不同部门和系统中,缺乏统一管理和共享机制。
|
||||
2. **流程断裂**:传统环境问题处理流程存在多个环节,各环节之间衔接不畅,容易导致问题处理延误或遗漏。
|
||||
3. **资源分配不均**:缺乏科学的任务分配机制,导致人力资源利用不均衡,部分区域问题积压严重。
|
||||
4. **监督机制不足**:公众难以了解问题处理进度和结果,缺乏有效的监督渠道。
|
||||
5. **数据分析不足**:未能充分利用环境问题数据进行趋势分析和预测,难以支持科学决策。
|
||||
|
||||
### 2.2 用户角色分析
|
||||
|
||||
环境监测系统涉及五类主要用户角色,每个角色在系统中承担不同的职责:
|
||||
|
||||
1. **公众用户**:系统的信息输入端,负责发现和上报环境问题,是系统的主要服务对象。
|
||||
2. **网格员**:系统的执行端,负责接收任务并前往现场处理环境问题,是系统的核心操作人员。
|
||||
3. **主管**:系统的管理端,负责审核反馈、分配任务、审核结果,是系统的关键决策者。
|
||||
4. **管理员**:系统的维护端,负责用户管理、权限设置、系统配置等基础支撑工作。
|
||||
5. **决策者**:系统的战略端,通过分析系统生成的统计数据和趋势图表,制定环境管理策略和资源分配决策,是系统的最终受益者之一。
|
||||
### 2.3 用例分析
|
||||
|
||||
#### 2.3.1 用例图
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
%% 定义角色
|
||||
PublicUser["公众用户"]
|
||||
GridWorker["网格员"]
|
||||
Supervisor["主管"]
|
||||
Admin["管理员"]
|
||||
|
||||
%% 定义用例
|
||||
UC1["注册与登录"]
|
||||
UC2["提交环境问题反馈"]
|
||||
UC3["查看反馈处理进度"]
|
||||
UC4["接收任务通知"]
|
||||
UC5["执行任务"]
|
||||
UC6["提交处理结果"]
|
||||
UC7["审核反馈内容"]
|
||||
UC8["分配任务"]
|
||||
UC9["审核处理结果"]
|
||||
UC10["查看统计数据"]
|
||||
UC11["管理用户账户"]
|
||||
UC12["配置系统参数"]
|
||||
|
||||
%% 建立关系
|
||||
PublicUser --> UC1
|
||||
PublicUser --> UC2
|
||||
PublicUser --> UC3
|
||||
|
||||
GridWorker --> UC1
|
||||
GridWorker --> UC4
|
||||
GridWorker --> UC5
|
||||
GridWorker --> UC6
|
||||
|
||||
Supervisor --> UC1
|
||||
Supervisor --> UC7
|
||||
Supervisor --> UC8
|
||||
Supervisor --> UC9
|
||||
Supervisor --> UC10
|
||||
|
||||
Admin --> UC1
|
||||
Admin --> UC10
|
||||
Admin --> UC11
|
||||
Admin --> UC12
|
||||
|
||||
%% 设置样式
|
||||
classDef actor fill:#f9f,stroke:#333,stroke-width:2px
|
||||
classDef usecase fill:#ccf,stroke:#33f,stroke-width:1px
|
||||
|
||||
class PublicUser,GridWorker,Supervisor,Admin actor
|
||||
class UC1,UC2,UC3,UC4,UC5,UC6,UC7,UC8,UC9,UC10,UC11,UC12 usecase
|
||||
```
|
||||
|
||||
#### 2.3.2 活动图:反馈提交与处理流程
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> 发现环境问题
|
||||
发现环境问题 --> 填写反馈表单
|
||||
填写反馈表单 --> 上传图片
|
||||
上传图片 --> 标记位置
|
||||
标记位置 --> 提交反馈
|
||||
提交反馈 --> AI自动审核
|
||||
|
||||
state AI自动审核 {
|
||||
[*] --> 内容分析
|
||||
内容分析 --> 垃圾信息检测
|
||||
垃圾信息检测 --> 分类与评级
|
||||
分类与评级 --> [*]
|
||||
}
|
||||
|
||||
AI自动审核 --> 判断AI审核结果
|
||||
判断AI审核结果 --> 明显无效: AI拒绝
|
||||
判断AI审核结果 --> 需人工确认: 需确认
|
||||
|
||||
明显无效 --> 标记为AI_REJECTED
|
||||
标记为AI_REJECTED --> 通知提交者
|
||||
通知提交者 --> [*]
|
||||
|
||||
需人工确认 --> 主管人工审核
|
||||
主管人工审核 --> 判断审核结果
|
||||
|
||||
判断审核结果 --> 驳回: 不通过
|
||||
判断审核结果 --> 通过: 通过
|
||||
|
||||
驳回 --> 填写驳回理由
|
||||
填写驳回理由 --> 更新状态为REJECTED
|
||||
更新状态为REJECTED --> 通知提交者反馈被驳回
|
||||
通知提交者反馈被驳回 --> [*]
|
||||
|
||||
通过 --> 创建任务
|
||||
创建任务 --> 更新反馈状态为PROCESSED
|
||||
更新反馈状态为PROCESSED --> 任务分配流程
|
||||
任务分配流程 --> [*]
|
||||
```
|
||||
|
||||
#### 2.3.3 活动图:任务分配与执行流程
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> 任务创建完成
|
||||
任务创建完成 --> 选择分配方式
|
||||
|
||||
state 选择分配方式 {
|
||||
[*] --> 手动分配
|
||||
[*] --> 智能推荐
|
||||
|
||||
智能推荐 --> 运行分配算法
|
||||
运行分配算法 --> 推荐最佳人选
|
||||
推荐最佳人选 --> 确认人选
|
||||
|
||||
手动分配 --> 选择特定网格员
|
||||
选择特定网格员 --> 确认人选
|
||||
|
||||
确认人选 --> [*]
|
||||
}
|
||||
|
||||
选择分配方式 --> 创建任务分配记录
|
||||
创建任务分配记录 --> 更新任务状态为ASSIGNED
|
||||
更新任务状态为ASSIGNED --> 通知网格员
|
||||
|
||||
通知网格员 --> 网格员接收通知
|
||||
网格员接收通知 --> 判断是否接受
|
||||
|
||||
判断是否接受 --> 拒绝: 拒绝
|
||||
判断是否接受 --> 接受: 接受
|
||||
|
||||
拒绝 --> 选择分配方式
|
||||
|
||||
接受 --> 更新状态为IN_PROGRESS
|
||||
更新状态为IN_PROGRESS --> 获取路径规划
|
||||
获取路径规划 --> 前往现场处理
|
||||
前往现场处理 --> 记录处理过程
|
||||
记录处理过程 --> 上传处理结果
|
||||
上传处理结果 --> 提交处理结果
|
||||
提交处理结果 --> 更新状态为SUBMITTED
|
||||
|
||||
更新状态为SUBMITTED --> 主管审核结果
|
||||
主管审核结果 --> 判断结果是否合格
|
||||
|
||||
判断结果是否合格 --> 不合格: 不合格
|
||||
判断结果是否合格 --> 合格: 合格
|
||||
|
||||
不合格 --> 填写原因要求重新处理
|
||||
填写原因要求重新处理 --> 获取路径规划
|
||||
|
||||
合格 --> 确认任务完成
|
||||
确认任务完成 --> 更新任务状态为APPROVED
|
||||
更新任务状态为APPROVED --> 更新反馈状态为CLOSED
|
||||
更新反馈状态为CLOSED --> 通知反馈提交者
|
||||
通知反馈提交者 --> 更新统计数据
|
||||
更新统计数据 --> [*]
|
||||
```
|
||||
|
||||
### 2.4 系统可行性分析
|
||||
|
||||
#### 2.4.1 技术可行性
|
||||
|
||||
1. **前端技术**:采用Vue 3框架构建用户界面,结合Element Plus组件库,可以快速开发出美观、响应式的Web应用,满足不同设备的访问需求。
|
||||
2. **后端技术**:基于Spring Boot 3框架和Java 17,具备高性能、高并发处理能力,能够满足系统的稳定性和扩展性需求。
|
||||
3. **地图服务**:可以集成百度地图、高德地图等成熟的地图API,实现地理位置标记、路径规划等功能。
|
||||
4. **AI技术**:可以利用现有的自然语言处理和图像识别技术,实现对反馈内容的智能分析和审核。
|
||||
5. **数据存储**:采用JSON文件存储方案,简化部署和维护,适合中小规模系统的快速实现。
|
||||
|
||||
#### 2.4.2 经济可行性
|
||||
|
||||
1. **开发成本**:采用主流开源框架和技术栈,降低开发成本和技术门槛。
|
||||
2. **维护成本**:模块化设计和完善的文档,降低后期维护和升级成本。
|
||||
3. **投资回报**:通过提高环境问题处理效率,减少人力资源浪费,长期来看具有良好的投资回报。
|
||||
4. **社会效益**:改善城市环境质量,提升居民生活满意度,产生显著的社会效益。
|
||||
|
||||
#### 2.4.3 操作可行性
|
||||
|
||||
1. **用户接受度**:系统界面设计简洁直观,操作流程符合用户习惯,易于被各类用户接受和使用。
|
||||
2. **培训需求**:系统操作简单,只需简单培训即可上手,降低推广和应用门槛。
|
||||
3. **业务适应性**:系统流程设计符合环境问题处理的实际业务需求,能够无缝融入现有工作流程。
|
||||
|
||||
#### 2.4.4 法律可行性
|
||||
|
||||
1. **数据隐私**:系统设计符合数据保护法规要求,对用户隐私数据进行加密存储和严格权限控制。
|
||||
2. **知识产权**:系统开发过程中使用的第三方库和组件均为开源或已获得授权,不存在知识产权风险。
|
||||
3. **合规性**:系统功能和流程设计符合相关法律法规和行业标准,确保合法合规运营。
|
||||
|
||||
## 3. 功能性需求
|
||||
|
||||
### 3.1 功能层次方框图
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
%% 用户交互层
|
||||
subgraph "用户交互层"
|
||||
direction LR
|
||||
C["公众服务模块(问题上报)"]
|
||||
H["个人中心模块(我的反馈/资料)"]
|
||||
D["管理驾驶舱(数据决策)"]
|
||||
end
|
||||
|
||||
%% 核心业务层
|
||||
subgraph "核心业务层"
|
||||
direction LR
|
||||
AI["AI分析模块(内容审核)"]
|
||||
E["任务管理模块(分配、流转、执行)"]
|
||||
end
|
||||
|
||||
%% 应用支撑层
|
||||
subgraph "应用支撑层"
|
||||
direction LR
|
||||
F["网格与地图模块(LBS & 寻路)"]
|
||||
I["文件服务模块(附件存取)"]
|
||||
end
|
||||
|
||||
%% 基础服务层
|
||||
subgraph "基础服务层"
|
||||
direction LR
|
||||
B["用户与认证模块"]
|
||||
G["系统管理模块(用户/权限)"]
|
||||
J["日志审计模块"]
|
||||
end
|
||||
|
||||
%% 定义关系
|
||||
C -- "提交反馈" --> AI
|
||||
AI -- "分析结果" --> E
|
||||
C -- "附件" --> I
|
||||
E -- "调用" --> F
|
||||
E -- "任务附件" --> I
|
||||
E -- "统计数据" --> D
|
||||
|
||||
H -- "查询个人数据" --> E
|
||||
|
||||
%% 基础服务支撑所有上层模块 (关系隐含)
|
||||
G -- "管理" --> B
|
||||
|
||||
classDef userLayer fill:#d4f1f9,stroke:#05a8e5;
|
||||
classDef coreLayer fill:#ffe6cc,stroke:#f7a128;
|
||||
classDef appSupportLayer fill:#d5e8d4,stroke:#82b366;
|
||||
classDef baseLayer fill:#e1d5e7,stroke:#9673a6;
|
||||
|
||||
class C,H,D userLayer;
|
||||
class AI,E coreLayer;
|
||||
class F,I appSupportLayer;
|
||||
class B,G,J baseLayer;
|
||||
```
|
||||
|
||||
### 3.2 模块功能概述
|
||||
|
||||
| 模块名称 | 功能概述 |
|
||||
| :--- | :--- |
|
||||
| **用户与认证模块** | 管理用户身份验证、权限控制和会话管理,确保系统安全性。提供用户注册、登录、密码重置等功能。 |
|
||||
| **反馈管理模块** | 处理公众提交的环境问题反馈,包括提交、审核、状态追踪和查询统计等功能。 |
|
||||
| **任务管理模块** | 将审核通过的反馈转化为工作任务,并管理任务的分配、执行和完成全流程。 |
|
||||
| **网格与地图模块** | 提供地理空间的网格化管理,支持路径规划和地图可视化,辅助任务执行。 |
|
||||
| **决策支持模块** | 通过数据分析和可视化,为管理层提供决策支持,帮助优化资源配置和治理策略。 |
|
||||
| **系统管理模块** | 提供系统配置、用户管理、权限设置等基础功能,保障系统正常运行。 |
|
||||
| **文件服务模块** | 处理系统中的文件上传、存储和访问,支持反馈和任务的附件管理。 |
|
||||
| **日志审计模块** | 记录系统操作日志,支持安全审计和问题追溯,确保系统运行的可追溯性。 |
|
||||
|
||||
## 4. 整体业务流程
|
||||
|
||||
下图描述了从公众发现问题、上报、到平台内部流转、处理、并最终反馈结果的完整闭环业务流程。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
%% 定义样式
|
||||
classDef public fill:#d4f1f9,stroke:#05a8e5,color:#333
|
||||
classDef platform fill:#ffe6cc,stroke:#f7a128,color:#333
|
||||
classDef worker fill:#d5e8d4,stroke:#82b366,color:#333
|
||||
classDef supervisor fill:#e1d5e7,stroke:#9673a6,color:#333
|
||||
classDef decision fill:#f8cecc,stroke:#b85450,color:#333
|
||||
classDef start_end fill:#f5f5f5,stroke:#666666,color:#333,stroke-width:2px
|
||||
|
||||
%% 流程开始
|
||||
A([开始]) --> B["[公众端] 发现环境问题"]
|
||||
B --> C["[公众端] 提交反馈<br>(标题/描述/图片/位置)"]
|
||||
|
||||
%% 平台接收与AI处理
|
||||
C --> D["[平台] 接收反馈<br>生成唯一事件ID"]
|
||||
D --> E{"[平台] AI自动审核<br>分析内容/分类"}
|
||||
|
||||
%% AI审核分支
|
||||
E -- "明显无效" --> F1["[平台] 标记为AI_REJECTED"]
|
||||
F1 --> F2["[平台] 通知提交者"]
|
||||
F2 --> Z1([结束])
|
||||
|
||||
E -- "需人工确认" --> G["[主管] 查看反馈详情<br>进行人工审核"]
|
||||
|
||||
%% 主管审核分支
|
||||
G --> H{"[主管] 审核决定"}
|
||||
H -- "驳回" --> I1["[主管] 填写驳回理由"]
|
||||
I1 --> I2["[平台] 更新状态为REJECTED"]
|
||||
I2 --> I3["[平台] 通知提交者"]
|
||||
I3 --> Z2([结束])
|
||||
|
||||
%% 审核通过,创建任务
|
||||
H -- "通过" --> J1["[主管] 确认反馈有效"]
|
||||
J1 --> J2["[平台] 自动创建结构化任务"]
|
||||
J2 --> J3["[平台] 更新反馈状态为PROCESSED"]
|
||||
|
||||
%% 任务分配
|
||||
J3 --> K1{"[主管] 选择分配方式"}
|
||||
K1 -- "手动分配" --> K2["[主管] 选择特定网格员"]
|
||||
K1 -- "智能推荐" --> K3["[平台] 运行分配算法<br>考虑位置/负载/专长"]
|
||||
K3 --> K4["[平台] 推荐最佳人选"]
|
||||
K4 --> K2
|
||||
K2 --> K5["[平台] 创建任务分配记录<br>更新任务状态为ASSIGNED"]
|
||||
K5 --> K6["[平台] 通知网格员"]
|
||||
|
||||
%% 网格员处理
|
||||
K6 --> L1["[网格员] 接收任务通知"]
|
||||
L1 --> L2{"[网格员] 接受任务?"}
|
||||
L2 -- "拒绝" --> K1
|
||||
L2 -- "接受" --> L3["[网格员] 更新任务状态为IN_PROGRESS"]
|
||||
L3 --> L4["[网格员] 查看任务详情<br>获取路径规划"]
|
||||
L4 --> L5["[网格员] 前往现场处理"]
|
||||
L5 --> L6["[网格员] 记录处理过程<br>上传证明材料"]
|
||||
L6 --> L7["[网格员] 提交处理结果<br>更新状态为SUBMITTED"]
|
||||
|
||||
%% 主管审核结果
|
||||
L7 --> M1["[主管] 审核处理结果"]
|
||||
M1 --> M2{"[主管] 结果是否合格?"}
|
||||
M2 -- "不合格" --> M3["[主管] 填写原因<br>要求重新处理"]
|
||||
M3 --> L4
|
||||
|
||||
%% 完成流程
|
||||
M2 -- "合格" --> N1["[主管] 确认任务完成"]
|
||||
N1 --> N2["[平台] 更新任务状态为APPROVED"]
|
||||
N2 --> N3["[平台] 更新反馈状态为CLOSED"]
|
||||
N3 --> N4["[平台] 通知反馈提交者"]
|
||||
N4 --> N5["[平台] 更新统计数据"]
|
||||
N5 --> O["[决策层] 查看数据看板<br>分析环境趋势"]
|
||||
O --> Z3([结束])
|
||||
|
||||
%% 为节点添加类别
|
||||
class A,Z1,Z2,Z3 start_end
|
||||
class B,C,F2,I3,N4 public
|
||||
class D,E,F1,I2,J2,J3,K3,K4,K5,K6,N2,N3,N5 platform
|
||||
class G,H,I1,J1,K1,K2,M1,M2,M3,N1 supervisor
|
||||
class L1,L2,L3,L4,L5,L6,L7 worker
|
||||
class O decision
|
||||
```
|
||||
|
||||
## 5. 详细需求描述
|
||||
|
||||
### 5.1 用户与认证模块
|
||||
|
||||
| 功能名称 | 用户与认证模块 |
|
||||
| :--- | :--- |
|
||||
| **优先级** | 高 |
|
||||
| **业务背景** | 作为系统安全的基础,本模块负责管理所有用户的身份验证和访问控制,确保系统资源只能被授权用户访问,同时提供灵活的角色权限管理。 |
|
||||
| **功能说明** | 1. **用户认证**:基于JWT (JSON Web Token) 的安全认证机制,支持账号密码登录,提供令牌刷新功能。<br>2. **权限控制**:基于RBAC (基于角色的访问控制) 模型,预设管理员、主管、网格员等角色,每个角色拥有特定的API访问权限。<br>3. **密码管理**:支持安全的密码重置流程,包括邮箱验证码验证,以及定期密码更新提醒。<br>4. **会话管理**:支持单点登录或多设备登录控制,可配置会话超时策略。 |
|
||||
| **约束条件** | 1. 密码必须符合复杂度要求(至少8位,包含大小写字母、数字和特殊字符)。<br>2. 敏感操作(如修改权限)需要二次验证。<br>3. 密码在数据库中必须使用BCrypt等强哈希算法加密存储。<br>4. 登录失败超过预设次数后,账户应被临时锁定。 |
|
||||
| **相关查询** | 1. 按用户名、邮箱或手机号查询用户信息。<br>2. 查询特定角色的所有用户列表。<br>3. 查询用户的权限和访问历史。 |
|
||||
| **其他需求** | 1. 系统应记录所有关键安全事件(登录、权限变更等)的审计日志。<br>2. 支持用户个人资料的维护和更新。 |
|
||||
|
||||
**用户认证流程图**:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant AuthController as 认证控制器
|
||||
participant AuthService as 认证服务
|
||||
participant UserRepository as 用户仓库
|
||||
participant JwtUtil as JWT工具
|
||||
participant Database as JSON持久化存储
|
||||
|
||||
User->>AuthController: POST /api/auth/login
|
||||
AuthController->>AuthService: signIn(LoginRequest)
|
||||
AuthService->>UserRepository: findByEmailOrPhone()
|
||||
UserRepository->>Database: 查询用户信息
|
||||
Database-->>UserRepository: 返回用户数据
|
||||
UserRepository-->>AuthService: 返回UserAccount
|
||||
AuthService->>AuthService: 验证密码
|
||||
AuthService->>JwtUtil: 生成JWT令牌
|
||||
JwtUtil-->>AuthService: 返回JWT
|
||||
AuthService-->>AuthController: JwtAuthenticationResponse
|
||||
AuthController-->>User: 返回JWT令牌
|
||||
```
|
||||
|
||||
### 5.2 反馈管理模块
|
||||
|
||||
| 功能名称 | 反馈管理模块 |
|
||||
| :--- | :--- |
|
||||
| **优先级** | 高 |
|
||||
| **业务背景** | 作为系统的核心输入端口,本模块负责收集、处理和跟踪所有环境问题反馈,是连接公众与管理部门的桥梁,也是后续任务创建的数据源。 |
|
||||
| **功能说明** | 1. **反馈提交**:提供结构化的表单接口,支持文字描述、污染类型分类、严重程度评估、地理位置标记和多媒体附件上传。<br>2. **AI内容审核**:集成智能审核服务,对反馈内容进行自动分析,识别垃圾信息、重复提交,并进行初步的分类和紧急程度评估。<br>3. **人工审核工作台**:为主管提供高效的反馈审核界面,支持批量处理、快速预览和详情查看。<br>4. **状态追踪**:完整记录反馈从提交到处理完成的全生命周期状态变更,支持多维度的统计和查询。 |
|
||||
| **约束条件** | 1. 反馈提交必须包含至少一张图片和准确的地理位置信息。<br>2. AI审核结果仅作为参考,最终决定权在人工审核者手中。<br>3. 对于紧急程度被标记为"高"的反馈,系统应在1小时内完成审核。<br>4. 同一用户在短时间内(如5分钟)不能重复提交内容高度相似的反馈。 |
|
||||
| **相关查询** | 1. 按状态、时间段、区域、污染类型等多维度查询反馈列表。<br>2. 查看特定反馈的详细信息和处理历史。<br>3. 统计不同类型反馈的数量分布和处理效率。 |
|
||||
| **其他需求** | 1. 支持反馈的优先级标记和升级处理。<br>2. 对于同一区域短时间内的多个相似反馈,系统应能智能识别并提示可能的重复。<br>3. 支持反馈附件的预览和下载。 |
|
||||
|
||||
**反馈提交处理流程图**:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant FeedbackController as 反馈控制器
|
||||
participant FeedbackService as 反馈服务
|
||||
participant FeedbackRepository as 反馈仓库
|
||||
participant AIService as AI服务
|
||||
participant EventPublisher as 事件发布器
|
||||
participant Database as JSON持久化存储
|
||||
|
||||
User->>FeedbackController: POST /api/feedback/submit
|
||||
FeedbackController->>FeedbackService: submitFeedback(request, files)
|
||||
FeedbackService->>FeedbackService: 生成事件ID
|
||||
FeedbackService->>FeedbackRepository: save(feedback)
|
||||
FeedbackRepository->>Database: 保存反馈数据
|
||||
Database-->>FeedbackRepository: 返回保存结果
|
||||
FeedbackRepository-->>FeedbackService: 返回Feedback实体
|
||||
FeedbackService->>EventPublisher: 发布反馈创建事件
|
||||
EventPublisher->>AIService: 触发AI处理
|
||||
AIService->>AIService: 分析反馈内容
|
||||
FeedbackService-->>FeedbackController: 返回Feedback
|
||||
FeedbackController-->>User: 201 Created
|
||||
```
|
||||
|
||||
### 5.3 任务管理模块
|
||||
|
||||
| 功能名称 | 任务管理模块 |
|
||||
| :--- | :--- |
|
||||
| **优先级** | 高 |
|
||||
| **业务背景** | 本模块是系统的核心业务处理单元,负责将审核通过的反馈转化为可执行的工作任务,并对任务的分配、执行和完成进行全流程管理。 |
|
||||
| **功能说明** | 1. **任务创建**:支持从反馈自动生成任务,也支持主管手动创建临时任务,包含任务描述、位置、截止时间、优先级等信息。<br>2. **智能分配**:基于多因素(网格员位置、当前负载、专业技能、历史表现)的任务分配算法,为每个任务推荐最合适的处理人员。<br>3. **任务执行跟踪**:记录任务的每个状态变更(已分配、已接受、进行中、已提交、已审核),支持网格员实时上报处理进度。<br>4. **结果审核**:主管对网格员提交的处理结果进行审核,可以通过或驳回,并提供反馈意见。<br>5. **任务看板**:直观展示不同状态任务的数量和分布,支持拖拽操作进行状态更新。 |
|
||||
| **约束条件** | 1. 任务必须关联到一个有效的反馈或由授权主管手动创建。<br>2. 任务分配时必须考虑网格员的工作区域和当前任务负载。<br>3. 高优先级任务应在24小时内分配并开始处理。<br>4. 任务提交时必须包含处理过程描述和至少一张结果照片。<br>5. 已完成的任务不能重新分配或修改。 |
|
||||
| **相关查询** | 1. 按状态、负责人、时间段、区域等多维度查询任务列表。<br>2. 查看特定任务的详细信息、处理历史和相关反馈。<br>3. 统计不同网格员的任务完成率、平均处理时长等绩效指标。 |
|
||||
| **其他需求** | 1. 支持任务的紧急程度升级和重新分配。<br>2. 对于长时间未处理的任务,系统应自动发送提醒通知。<br>3. 支持批量导出任务报告,用于绩效评估和工作汇报。 |
|
||||
|
||||
**任务分配流程图**:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Supervisor as 主管
|
||||
participant TaskController as 任务控制器
|
||||
participant TaskService as 任务服务
|
||||
participant AssignmentService as 分配服务
|
||||
participant UserRepository as 用户仓库
|
||||
participant TaskRepository as 任务仓库
|
||||
participant GridWorker as 网格工作人员
|
||||
|
||||
Supervisor->>TaskController: POST /api/tasks/assign
|
||||
TaskController->>TaskService: assignTask(taskId, workerId)
|
||||
TaskService->>UserRepository: findById(workerId)
|
||||
UserRepository-->>TaskService: 返回GridWorker
|
||||
TaskService->>AssignmentService: createAssignment()
|
||||
AssignmentService->>TaskRepository: updateTaskStatus()
|
||||
TaskRepository-->>AssignmentService: 更新成功
|
||||
AssignmentService-->>TaskService: Assignment创建成功
|
||||
TaskService->>TaskService: 发送通知给工作人员
|
||||
TaskService-->>TaskController: 分配成功
|
||||
TaskController-->>Supervisor: 200 OK
|
||||
Note over GridWorker: 接收任务通知
|
||||
```
|
||||
|
||||
### 5.4 网格与地图模块
|
||||
|
||||
| 功能名称 | 网格与地图模块 |
|
||||
| :--- | :--- |
|
||||
| **优先级** | 中 |
|
||||
| **业务背景** | 本模块负责对地理空间进行网格化管理,将城市区域划分为可管理的网格单元,并为任务执行提供地理位置支持和路径规划。 |
|
||||
| **功能说明** | 1. **网格定义与管理**:支持管理员定义和维护城市网格系统,包括网格的坐标、属性(如是否为障碍物)和责任人分配。<br>2. **A*寻路算法服务**:基于网格系统和实时路况,为网格员提供从当前位置到任务地点的最优路径规划,考虑距离、交通状况和障碍物。<br>3. **地图可视化**:在地图上直观展示反馈点、任务分布和网格员位置,支持多种筛选条件和图层切换。<br>4. **区域统计**:基于网格系统,生成环境问题热力图,识别高发区域和问题类型分布。 |
|
||||
| **约束条件** | 1. 网格系统应支持多级划分,最小网格单元不应大于500米×500米。<br>2. 路径规划应考虑实际道路情况和障碍物,避免不可通行区域。<br>3. 地图数据应定期更新,确保准确性。<br>4. 网格坐标系统必须与地理坐标系统(经纬度)有明确的转换关系。 |
|
||||
| **相关查询** | 1. 查询特定区域内的网格定义和属性。<br>2. 查询特定网格的历史问题记录和统计数据。<br>3. 获取两点间的最优路径规划。<br>4. 查询特定区域内的网格员分布情况。 |
|
||||
| **其他需求** | 1. 支持网格责任人的灵活调整和临时替换。<br>2. 地图界面应支持常见的交互操作(缩放、平移、点选)。<br>3. 支持离线地图数据缓存,保证在网络不稳定情况下的基本功能。 |
|
||||
|
||||
**路径规划流程图**:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User as 用户
|
||||
participant PathfindingController as 寻路控制器
|
||||
participant AStarService as A*服务
|
||||
participant MapData as 地图数据
|
||||
|
||||
User->>+PathfindingController: POST /api/pathfinding/find (起点, 终点)
|
||||
PathfindingController->>+AStarService: findPath(start, end)
|
||||
AStarService->>+MapData: getObstacles()
|
||||
MapData-->>-AStarService: 返回障碍物信息
|
||||
AStarService->>AStarService: 执行A*算法计算路径
|
||||
AStarService-->>-PathfindingController: 返回计算出的路径
|
||||
PathfindingController-->>-User: 200 OK (路径坐标列表)
|
||||
```
|
||||
|
||||
### 5.5 决策支持模块
|
||||
|
||||
| 功能名称 | 决策支持模块 (管理驾驶舱) |
|
||||
| :--- | :--- |
|
||||
| **优先级** | 中 |
|
||||
| **业务背景** | 本模块旨在将系统中沉淀的大量业务数据转化为有价值的决策洞察,帮助管理层了解环境状况、评估治理效果、优化资源配置。 |
|
||||
| **功能说明** | 1. **核心指标看板**:实时展示关键业务指标,如待处理反馈数、进行中任务数、平均处理时长、按时完成率等。<br>2. **多维度分析**:支持按时间、区域、污染类型、处理人等多个维度对数据进行交叉分析和趋势展示。<br>3. **热力图可视化**:在地图上以热力图形式展示环境问题的分布密度,直观识别高发区域。<br>4. **绩效评估**:对网格员和区域的工作效率、问题解决质量等进行量化评估,生成排名和对比分析。<br>5. **预警机制**:基于历史数据和趋势分析,对可能出现的环境风险提前预警。 |
|
||||
| **约束条件** | 1. 数据分析应基于实时或准实时的业务数据,确保决策的时效性。<br>2. 图表和报表应支持多种导出格式(PDF、Excel等),便于进一步分析和汇报。<br>3. 敏感数据(如个人绩效)的访问应受到严格权限控制。<br>4. 系统应能处理和分析至少一年的历史数据。 |
|
||||
| **相关查询** | 1. 按自定义时间范围查询各类统计指标。<br>2. 查询特定区域或网格员的历史表现数据。<br>3. 生成定制化的数据报表和分析图表。<br>4. 查询环境问题的时间分布和地理分布。 |
|
||||
| **其他需求** | 1. 支持数据看板的个性化配置,满足不同管理者的关注点。<br>2. 提供数据异常检测和提醒功能,及时发现数据波动。<br>3. 支持定期自动生成并发送统计报告。 |
|
||||
|
||||
**决策者获取仪表盘数据流程图**:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant DecisionMaker as 决策者
|
||||
participant DashboardController as 仪表盘控制器
|
||||
participant DashboardService as 仪表盘服务
|
||||
participant variousRepositories as 各类仓库
|
||||
participant Database as JSON持久化存储
|
||||
|
||||
DecisionMaker->>DashboardController: GET /api/dashboard/stats
|
||||
DashboardController->>DashboardService: getDashboardStats()
|
||||
DashboardService->>variousRepositories: (并行)调用多个仓库方法获取数据
|
||||
variousRepositories->>Database: 查询统计数据
|
||||
Database-->>variousRepositories: 返回数据
|
||||
variousRepositories-->>DashboardService: 返回统计结果
|
||||
DashboardService->>DashboardService: 聚合数据为DashboardStatsDTO
|
||||
DashboardService-->>DashboardController: 返回DashboardStatsDTO
|
||||
DashboardController-->>DecisionMaker: 返回核心统计数据
|
||||
```
|
||||
|
||||
### 5.6 决策者角色需求
|
||||
|
||||
| 功能名称 | 决策者角色需求 |
|
||||
| :--- | :--- |
|
||||
| **优先级** | 中 |
|
||||
| **业务背景** | 决策者是环境监测系统的战略用户,负责根据系统提供的数据分析结果制定环境管理策略和资源分配决策。他们需要全局视角的数据展示和深度分析功能,以支持科学决策。 |
|
||||
| **功能说明** | 1. **综合仪表盘**:提供环境状况、处理效率、资源利用等多维度的综合数据视图,支持按时间、区域进行筛选。<br>2. **趋势分析**:展示关键指标的历史变化趋势,支持多指标对比和季节性分析。<br>3. **资源分配建议**:基于历史数据和预测模型,为人力资源调配和预算分配提供决策建议。<br>4. **绩效评估报告**:生成网格员、区域、团队的绩效评估报告,支持多维度比较。<br>5. **预警监控**:实时监控环境问题高发区域和异常情况,支持预警规则配置。 |
|
||||
| **约束条件** | 1. 决策者界面应简洁明了,突出关键指标和异常情况。<br>2. 复杂分析应提供直观的可视化展示,避免过多的数字和表格。<br>3. 报表生成不应影响系统的整体性能。<br>4. 敏感数据的访问应受到严格的权限控制。 |
|
||||
| **相关查询** | 1. 按时间段、区域、问题类型等维度查询统计数据。<br>2. 查询资源利用效率和投入产出比。<br>3. 查询环境问题的地理分布和时间分布热点。<br>4. 查询预测模型生成的趋势预测结果。 |
|
||||
| **其他需求** | 1. 支持报表的导出和分享功能。<br>2. 提供决策建议的解释性说明,增强决策透明度。<br>3. 支持自定义关注指标和提醒阈值。<br>4. 提供移动端访问能力,满足随时随地查看关键数据的需求。 |
|
||||
|
||||
**决策者使用流程图**:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant DecisionMaker as 决策者
|
||||
participant Dashboard as 综合仪表盘
|
||||
participant ReportGenerator as 报表生成器
|
||||
participant AnalyticsEngine as 分析引擎
|
||||
participant Database as 数据存储
|
||||
|
||||
DecisionMaker->>Dashboard: 登录系统
|
||||
Dashboard->>AnalyticsEngine: 请求核心指标数据
|
||||
AnalyticsEngine->>Database: 查询原始数据
|
||||
Database-->>AnalyticsEngine: 返回数据
|
||||
AnalyticsEngine->>AnalyticsEngine: 计算指标和趋势
|
||||
AnalyticsEngine-->>Dashboard: 返回处理后的数据
|
||||
Dashboard-->>DecisionMaker: 展示综合仪表盘
|
||||
|
||||
DecisionMaker->>Dashboard: 调整筛选条件(时间/区域)
|
||||
Dashboard->>AnalyticsEngine: 请求筛选后的数据
|
||||
AnalyticsEngine->>Database: 查询筛选数据
|
||||
Database-->>AnalyticsEngine: 返回筛选结果
|
||||
AnalyticsEngine-->>Dashboard: 返回处理后的数据
|
||||
Dashboard-->>DecisionMaker: 更新仪表盘显示
|
||||
|
||||
DecisionMaker->>ReportGenerator: 请求生成绩效报告
|
||||
ReportGenerator->>AnalyticsEngine: 获取绩效数据
|
||||
AnalyticsEngine->>Database: 查询绩效相关数据
|
||||
Database-->>AnalyticsEngine: 返回数据
|
||||
AnalyticsEngine-->>ReportGenerator: 提供分析结果
|
||||
ReportGenerator-->>DecisionMaker: 生成并下载报告
|
||||
|
||||
DecisionMaker->>Dashboard: 查看资源分配建议
|
||||
Dashboard->>AnalyticsEngine: 请求优化建议
|
||||
AnalyticsEngine->>AnalyticsEngine: 运行资源优化算法
|
||||
AnalyticsEngine-->>Dashboard: 返回建议结果
|
||||
Dashboard-->>DecisionMaker: 展示资源分配建议
|
||||
```
|
||||
|
||||
## 6. 需求规定
|
||||
|
||||
### 6.2 技术规格需求
|
||||
|
||||
* **前端技术栈**:
|
||||
* 核心框架:Vue.js 3.x
|
||||
* 构建工具:Vite
|
||||
* UI组件库:Element Plus
|
||||
* 状态管理:Pinia
|
||||
* 路由管理:Vue Router
|
||||
* HTTP客户端:Axios
|
||||
|
||||
* **后端技术栈**:
|
||||
* 核心框架:Spring Boot 3.x
|
||||
* 编程语言:Java 17
|
||||
* 安全框架:Spring Security 6.x
|
||||
* API文档:SpringDoc (OpenAPI)
|
||||
* 数据验证:Jakarta Bean Validation (Hibernate Validator)
|
||||
* 日志系统:SLF4J & Logback
|
||||
|
||||
* **数据存储**:
|
||||
* 采用JSON文件存储方案
|
||||
* 实现自定义的泛型JSON仓储层
|
||||
* 确保数据操作的线程安全性
|
||||
|
||||
* **部署环境**:
|
||||
* 支持Docker容器化部署
|
||||
* 支持常见的Web服务器(如Nginx、Apache)
|
||||
* 最低硬件要求:4核CPU、8GB内存、50GB存储空间
|
||||
|
||||
## 7. 数据描述
|
||||
|
||||
### 7.1 用户账户 (UserAccount) 数据结构
|
||||
|
||||
| 字段名 | 描述 | 数据类型 | 约束条件 | 是否必填 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| `id` | 用户唯一标识符 | Long | 主键,自增 | 是 |
|
||||
| `name` | 用户姓名 | String | 最大长度50 | 是 |
|
||||
| `phone` | 手机号码 | String | 符合手机号格式 | 是 |
|
||||
| `email` | 电子邮箱 | String | 符合邮箱格式 | 是 |
|
||||
| `password` | 密码(加密存储) | String | 最小长度8,包含字母、数字和特殊字符 | 是 |
|
||||
| `gender` | 性别 | Enum | MALE, FEMALE, OTHER | 否 |
|
||||
| `role` | 用户角色 | Enum | ADMIN, SUPERVISOR, GRID_WORKER, PUBLIC_USER | 是 |
|
||||
| `status` | 账户状态 | Enum | ACTIVE, INACTIVE, LOCKED | 是 |
|
||||
| `gridX` | 网格X坐标(仅网格员) | Integer | 非负整数 | 否 |
|
||||
| `gridY` | 网格Y坐标(仅网格员) | Integer | 非负整数 | 否 |
|
||||
| `region` | 地理区域或区县 | String | 最大长度255 | 否 |
|
||||
| `level` | 熟练度级别(仅网格员) | Enum | JUNIOR, INTERMEDIATE, SENIOR, EXPERT | 否 |
|
||||
| `skills` | 技能列表(JSON格式) | List<String> | - | 否 |
|
||||
| `createdAt` | 账户创建时间 | DateTime | ISO 8601格式 | 是 |
|
||||
| `updatedAt` | 账户更新时间 | DateTime | ISO 8601格式 | 是 |
|
||||
| `enabled` | 账户是否启用 | Boolean | true/false | 是 |
|
||||
| `currentLatitude` | 当前纬度(仅网格员) | Double | 有效范围 | 否 |
|
||||
| `currentLongitude` | 当前经度(仅网格员) | Double | 有效范围 | 否 |
|
||||
| `failedLoginAttempts` | 连续登录失败次数 | Integer | 非负整数 | 是 |
|
||||
| `lockoutEndTime` | 锁定结束时间 | DateTime | ISO 8601格式 | 否 |
|
||||
|
||||
### 7.2 反馈 (Feedback) 数据结构
|
||||
|
||||
| 字段名 | 描述 | 数据类型 | 约束条件 | 是否必填 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| `id` | 反馈唯一标识符 | Long | 主键,自增 | 是 |
|
||||
| `eventId` | 事件ID(业务编号) | String | UUID格式 | 是 |
|
||||
| `title` | 反馈标题 | String | 最大长度100 | 是 |
|
||||
| `description` | 问题详细描述 | String | 最大长度1000 | 是 |
|
||||
| `pollutionType` | 污染类型 | Enum | AIR, WATER, SOIL, NOISE, OTHER | 是 |
|
||||
| `severityLevel` | 严重程度 | Enum | LOW, MEDIUM, HIGH, CRITICAL | 是 |
|
||||
| `status` | 反馈状态 | Enum | PENDING_REVIEW, AI_REJECTED, PROCESSED, CLOSED | 是 |
|
||||
| `textAddress` | 文本地址描述 | String | 最大长度200 | 否 |
|
||||
| `gridX` | 网格X坐标 | Integer | 非负整数 | 否 |
|
||||
| `gridY` | 网格Y坐标 | Integer | 非负整数 | 否 |
|
||||
| `submitterId` | 提交者ID | Long | 外键关联UserAccount | 是 |
|
||||
| `latitude` | 地理位置纬度 | Double | 有效范围 | 是 |
|
||||
| `longitude` | 地理位置经度 | Double | 有效范围 | 是 |
|
||||
| `user` | 提交者用户对象 | UserAccount | 外键关联 | 是 |
|
||||
| `attachments` | 附件列表 | List<Attachment> | 至少一张图片 | 是 |
|
||||
| `task` | 关联的任务 | Task | 一对一关联 | 否 |
|
||||
| `createdAt` | 提交时间 | DateTime | ISO 8601格式 | 是 |
|
||||
| `updatedAt` | 更新时间 | DateTime | ISO 8601格式 | 是 |
|
||||
|
||||
### 7.3 任务 (Task) 数据结构
|
||||
|
||||
| 字段名 | 描述 | 数据类型 | 约束条件 | 是否必填 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| `id` | 任务唯一标识符 | Long | 主键,自增 | 是 |
|
||||
| `feedback` | 关联的反馈 | Feedback | 外键关联Feedback | 否 |
|
||||
| `assignee` | 被指派的网格员 | UserAccount | 外键关联UserAccount | 否 |
|
||||
| `createdBy` | 创建者 | UserAccount | 外键关联UserAccount | 是 |
|
||||
| `status` | 任务状态 | Enum | CREATED, ASSIGNED, IN_PROGRESS, SUBMITTED, APPROVED, REJECTED | 是 |
|
||||
| `assignedAt` | 分配时间 | DateTime | ISO 8601格式 | 否 |
|
||||
| `completedAt` | 完成时间 | DateTime | ISO 8601格式 | 否 |
|
||||
| `createdAt` | 创建时间 | DateTime | ISO 8601格式 | 是 |
|
||||
| `updatedAt` | 更新时间 | DateTime | ISO 8601格式 | 是 |
|
||||
| `title` | 任务标题 | String | 最大长度100 | 是 |
|
||||
| `description` | 任务描述 | String | 最大长度1000 | 是 |
|
||||
| `pollutionType` | 污染类型 | Enum | AIR, WATER, SOIL, NOISE, OTHER | 是 |
|
||||
| `severityLevel` | 严重程度 | Enum | LOW, MEDIUM, HIGH, CRITICAL | 是 |
|
||||
| `textAddress` | 文本地址描述 | String | 最大长度200 | 否 |
|
||||
| `gridX` | 网格X坐标 | Integer | 非负整数 | 否 |
|
||||
| `gridY` | 网格Y坐标 | Integer | 非负整数 | 否 |
|
||||
| `latitude` | 地理位置纬度 | Double | 有效范围 | 是 |
|
||||
| `longitude` | 地理位置经度 | Double | 有效范围 | 是 |
|
||||
| `history` | 任务历史记录 | List<TaskHistory> | - | 否 |
|
||||
| `assignment` | 任务分配信息 | Assignment | 一对一关联 | 否 |
|
||||
| `submissions` | 任务提交记录 | List<TaskSubmission> | - | 否 |
|
||||
|
||||
### 7.4 网格 (Grid) 数据结构
|
||||
|
||||
| 字段名 | 描述 | 数据类型 | 约束条件 | 是否必填 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| `id` | 网格唯一标识符 | Long | 主键,自增 | 是 |
|
||||
| `gridX` | 网格X坐标 | Integer | 非负整数 | 是 |
|
||||
| `gridY` | 网格Y坐标 | Integer | 非负整数 | 是 |
|
||||
| `cityName` | 所属城市 | String | 最大长度50 | 是 |
|
||||
| `districtName` | 所属区县 | String | 最大长度50 | 是 |
|
||||
| `description` | 网格描述 | String | 最大长度200 | 否 |
|
||||
| `isObstacle` | 是否为障碍物 | Boolean | true/false | 是 |
|
||||
|
||||
### 7.5 任务分配 (Assignment) 数据结构
|
||||
|
||||
| 字段名 | 描述 | 数据类型 | 约束条件 | 是否必填 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| `id` | 分配唯一标识符 | Long | 主键,自增 | 是 |
|
||||
| `task` | 关联的任务 | Task | 外键关联Task | 是 |
|
||||
| `assigner` | 分配人 | UserAccount | 外键关联UserAccount | 是 |
|
||||
| `assignmentTime` | 分配时间 | DateTime | ISO 8601格式 | 是 |
|
||||
| `deadline` | 截止日期 | DateTime | ISO 8601格式 | 否 |
|
||||
| `status` | 分配状态 | Enum | PENDING, ACCEPTED, REJECTED, COMPLETED | 是 |
|
||||
| `remarks` | 备注说明 | String | 最大长度500 | 否 |
|
||||
|
||||
@@ -1,840 +0,0 @@
|
||||
# 需求定义文档
|
||||
|
||||
## 1. 项目介绍
|
||||
|
||||
### 1.1 项目背景
|
||||
|
||||
环境监测系统(EMS)是为解决城市环境问题而设计的综合性管理平台。随着城市化进程加速,环境污染问题日益凸显,传统的环境问题上报和处理机制存在以下痛点:
|
||||
|
||||
- **流程繁琐**:公众发现环境问题后,需要通过多个渠道和部门层层上报,处理流程不透明
|
||||
- **响应缓慢**:从问题发现到最终解决,往往需要经历漫长的等待时间
|
||||
- **缺乏透明度**:公众难以了解问题处理进度,无法有效监督
|
||||
- **资源分配不合理**:缺乏科学的任务分配机制,导致人力资源利用不均衡
|
||||
|
||||
本系统旨在通过数字化手段,构建一个连接公众、管理部门和执行人员的环境监测与治理平台,实现环境问题的快速发现、高效处理和全程监督。
|
||||
|
||||
### 1.2 项目目标
|
||||
|
||||
1. **建立闭环管理机制**:构建从问题发现、上报、审核、分配、处理到结果反馈的完整闭环流程,确保每个环境问题都能得到妥善解决。
|
||||
2. **提高处理效率**:通过流程优化和智能算法,缩短环境问题从发现到解决的时间,提高环境治理效率。
|
||||
3. **增强公众参与**:为公众提供便捷的问题上报渠道,增强公众参与环境治理的积极性和获得感。
|
||||
4. **辅助决策分析**:通过数据可视化和多维度分析,为管理层提供决策支持,优化资源配置和治理策略。
|
||||
5. **提升治理透明度**:实现环境问题处理全过程可追踪、可监督,增强政府工作透明度和公信力。
|
||||
|
||||
## 2. 系统分析
|
||||
|
||||
### 2.1 业务痛点分析
|
||||
|
||||
1. **信息孤岛**:环境问题信息分散在不同部门和系统中,缺乏统一管理和共享机制。
|
||||
2. **流程断裂**:传统环境问题处理流程存在多个环节,各环节之间衔接不畅,容易导致问题处理延误或遗漏。
|
||||
3. **资源分配不均**:缺乏科学的任务分配机制,导致人力资源利用不均衡,部分区域问题积压严重。
|
||||
4. **监督机制不足**:公众难以了解问题处理进度和结果,缺乏有效的监督渠道。
|
||||
5. **数据分析不足**:未能充分利用环境问题数据进行趋势分析和预测,难以支持科学决策。
|
||||
|
||||
### 2.2 用户角色分析
|
||||
|
||||
环境监测系统涉及五类主要用户角色,每个角色在系统中承担不同的职责:
|
||||
|
||||
1. **公众用户**:系统的信息输入端,负责发现和上报环境问题,是系统的主要服务对象。
|
||||
- 需求:简单便捷的问题上报方式、透明的处理进度查询
|
||||
- 痛点:传统上报渠道繁琐、反馈周期长、处理结果不透明
|
||||
|
||||
2. **网格员**:系统的执行端,负责接收任务并前往现场处理环境问题,是系统的核心操作人员。
|
||||
- 需求:清晰的任务指派、便捷的结果上报、高效的路径规划
|
||||
- 痛点:任务分配不合理、工作量分布不均、缺乏高效导航
|
||||
|
||||
3. **主管**:系统的管理端,负责审核反馈、分配任务、审核结果,是系统的关键决策者。
|
||||
- 需求:高效的任务管理、智能的人员调配、直观的进度监控
|
||||
- 痛点:人工分配任务效率低、缺乏全局视角、绩效评估困难
|
||||
|
||||
4. **管理员**:系统的维护端,负责用户管理、权限设置、系统配置等基础支撑工作。
|
||||
- 需求:灵活的权限配置、完善的日志审计、便捷的系统维护
|
||||
- 痛点:账户管理繁琐、权限控制粗放、系统维护成本高
|
||||
|
||||
5. **决策者**:系统的战略端,通过分析系统生成的统计数据和趋势图表,制定环境管理策略和资源分配决策,是系统的最终受益者之一。
|
||||
- 需求:多维度的数据分析、直观的可视化展示、科学的决策支持
|
||||
- 痛点:数据获取困难、分析维度单一、缺乏预测能力
|
||||
|
||||
### 2.3 用例分析
|
||||
|
||||
#### 2.3.1 用例图
|
||||
|
||||
以下用例图展示了系统中各角色可以执行的主要操作:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
%% 定义角色
|
||||
PublicUser["公众用户"]
|
||||
GridWorker["网格员"]
|
||||
Supervisor["主管"]
|
||||
Admin["管理员"]
|
||||
DecisionMaker["决策者"]
|
||||
|
||||
%% 定义用例
|
||||
UC1["注册与登录"]
|
||||
UC2["提交环境问题反馈"]
|
||||
UC3["查看反馈处理进度"]
|
||||
UC4["接收任务通知"]
|
||||
UC5["执行任务"]
|
||||
UC6["提交处理结果"]
|
||||
UC7["审核反馈内容"]
|
||||
UC8["分配任务"]
|
||||
UC9["审核处理结果"]
|
||||
UC10["查看统计数据"]
|
||||
UC11["管理用户账户"]
|
||||
UC12["配置系统参数"]
|
||||
UC13["查看决策仪表盘"]
|
||||
UC14["生成分析报告"]
|
||||
|
||||
%% 建立关系
|
||||
PublicUser --> UC1
|
||||
PublicUser --> UC2
|
||||
PublicUser --> UC3
|
||||
|
||||
GridWorker --> UC1
|
||||
GridWorker --> UC4
|
||||
GridWorker --> UC5
|
||||
GridWorker --> UC6
|
||||
|
||||
Supervisor --> UC1
|
||||
Supervisor --> UC7
|
||||
Supervisor --> UC8
|
||||
Supervisor --> UC9
|
||||
Supervisor --> UC10
|
||||
|
||||
Admin --> UC1
|
||||
Admin --> UC10
|
||||
Admin --> UC11
|
||||
Admin --> UC12
|
||||
|
||||
DecisionMaker --> UC1
|
||||
DecisionMaker --> UC10
|
||||
DecisionMaker --> UC13
|
||||
DecisionMaker --> UC14
|
||||
|
||||
%% 设置样式
|
||||
classDef actor fill:#f9f,stroke:#333,stroke-width:2px
|
||||
classDef usecase fill:#ccf,stroke:#33f,stroke-width:1px
|
||||
|
||||
class PublicUser,GridWorker,Supervisor,Admin,DecisionMaker actor
|
||||
class UC1,UC2,UC3,UC4,UC5,UC6,UC7,UC8,UC9,UC10,UC11,UC12,UC13,UC14 usecase
|
||||
```
|
||||
|
||||
#### 2.3.2 活动图:反馈提交与处理流程
|
||||
|
||||
以下活动图展示了从公众发现环境问题到反馈处理完成的完整业务流程:
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> 发现环境问题
|
||||
发现环境问题 --> 填写反馈表单
|
||||
填写反馈表单 --> 上传图片
|
||||
上传图片 --> 标记位置
|
||||
标记位置 --> 提交反馈
|
||||
提交反馈 --> AI自动审核
|
||||
|
||||
state AI自动审核 {
|
||||
[*] --> 内容分析
|
||||
内容分析 --> 垃圾信息检测
|
||||
垃圾信息检测 --> 分类与评级
|
||||
分类与评级 --> [*]
|
||||
}
|
||||
|
||||
AI自动审核 --> 判断AI审核结果
|
||||
判断AI审核结果 --> 明显无效: AI拒绝
|
||||
判断AI审核结果 --> 需人工确认: 需确认
|
||||
|
||||
明显无效 --> 标记为AI_REJECTED
|
||||
标记为AI_REJECTED --> 通知提交者
|
||||
通知提交者 --> [*]
|
||||
|
||||
需人工确认 --> 主管人工审核
|
||||
主管人工审核 --> 判断审核结果
|
||||
|
||||
判断审核结果 --> 驳回: 不通过
|
||||
判断审核结果 --> 通过: 通过
|
||||
|
||||
驳回 --> 填写驳回理由
|
||||
填写驳回理由 --> 更新状态为REJECTED
|
||||
更新状态为REJECTED --> 通知提交者反馈被驳回
|
||||
通知提交者反馈被驳回 --> [*]
|
||||
|
||||
通过 --> 创建任务
|
||||
创建任务 --> 更新反馈状态为PROCESSED
|
||||
更新反馈状态为PROCESSED --> 任务分配流程
|
||||
任务分配流程 --> [*]
|
||||
```
|
||||
# 需求定义文档(续)
|
||||
|
||||
#### 2.3.3 活动图:任务分配与执行流程
|
||||
|
||||
以下活动图展示了从任务创建到完成的完整业务流程:
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> 任务创建完成
|
||||
任务创建完成 --> 选择分配方式
|
||||
|
||||
state 选择分配方式 {
|
||||
[*] --> 手动分配
|
||||
[*] --> 智能推荐
|
||||
|
||||
智能推荐 --> 运行分配算法
|
||||
运行分配算法 --> 推荐最佳人选
|
||||
推荐最佳人选 --> 确认人选
|
||||
|
||||
手动分配 --> 选择特定网格员
|
||||
选择特定网格员 --> 确认人选
|
||||
|
||||
确认人选 --> [*]
|
||||
}
|
||||
|
||||
选择分配方式 --> 创建任务分配记录
|
||||
创建任务分配记录 --> 更新任务状态为ASSIGNED
|
||||
更新任务状态为ASSIGNED --> 通知网格员
|
||||
|
||||
通知网格员 --> 网格员接收通知
|
||||
网格员接收通知 --> 判断是否接受
|
||||
|
||||
判断是否接受 --> 拒绝: 拒绝
|
||||
判断是否接受 --> 接受: 接受
|
||||
|
||||
拒绝 --> 选择分配方式
|
||||
|
||||
接受 --> 更新状态为IN_PROGRESS
|
||||
更新状态为IN_PROGRESS --> 获取路径规划
|
||||
获取路径规划 --> 前往现场处理
|
||||
前往现场处理 --> 记录处理过程
|
||||
记录处理过程 --> 上传处理结果
|
||||
上传处理结果 --> 提交处理结果
|
||||
提交处理结果 --> 更新状态为SUBMITTED
|
||||
|
||||
更新状态为SUBMITTED --> 主管审核结果
|
||||
主管审核结果 --> 判断结果是否合格
|
||||
|
||||
判断结果是否合格 --> 不合格: 不合格
|
||||
判断结果是否合格 --> 合格: 合格
|
||||
|
||||
不合格 --> 填写原因要求重新处理
|
||||
填写原因要求重新处理 --> 获取路径规划
|
||||
|
||||
合格 --> 确认任务完成
|
||||
确认任务完成 --> 更新任务状态为APPROVED
|
||||
更新任务状态为APPROVED --> 更新反馈状态为CLOSED
|
||||
更新反馈状态为CLOSED --> 通知反馈提交者
|
||||
通知反馈提交者 --> 更新统计数据
|
||||
更新统计数据 --> [*]
|
||||
```
|
||||
|
||||
### 2.4 系统可行性分析
|
||||
|
||||
#### 2.4.1 技术可行性
|
||||
|
||||
本系统的技术实现是可行的,主要基于以下分析:
|
||||
|
||||
1. **前端技术**:市场上已有成熟的前端框架和组件库,可以快速开发出美观、响应式的Web应用,满足不同设备的访问需求。
|
||||
|
||||
2. **后端技术**:现有的后端框架具备高性能、高并发处理能力,能够满足系统的稳定性和扩展性需求。
|
||||
|
||||
3. **地图服务**:可以集成成熟的地图API,实现地理位置标记、路径规划等功能,无需从零开发。
|
||||
|
||||
4. **AI技术**:可以利用现有的自然语言处理和图像识别技术,实现对反馈内容的智能分析和审核。
|
||||
|
||||
5. **数据存储**:可采用多种数据存储方案,根据系统规模和性能需求灵活选择。
|
||||
|
||||
#### 2.4.2 经济可行性
|
||||
|
||||
从经济角度看,本系统的开发和运营是可行的:
|
||||
|
||||
1. **开发成本**:可以采用主流开源框架和技术栈,降低开发成本和技术门槛。
|
||||
|
||||
2. **维护成本**:通过模块化设计和完善的文档,可以降低后期维护和升级成本。
|
||||
|
||||
3. **投资回报**:
|
||||
- 提高环境问题处理效率,减少人力资源浪费
|
||||
- 降低环境问题带来的经济损失
|
||||
- 提升城市环境质量,间接促进经济发展
|
||||
- 长期来看具有良好的投资回报
|
||||
|
||||
4. **社会效益**:改善城市环境质量,提升居民生活满意度,产生显著的社会效益。
|
||||
|
||||
#### 2.4.3 操作可行性
|
||||
|
||||
从操作角度看,本系统具有良好的可行性:
|
||||
|
||||
1. **用户接受度**:
|
||||
- 系统界面设计简洁直观,符合用户习惯
|
||||
- 操作流程简化,降低学习成本
|
||||
- 移动端支持,满足随时随地使用需求
|
||||
|
||||
2. **培训需求**:系统操作简单,只需简单培训即可上手,降低推广和应用门槛。
|
||||
|
||||
3. **业务适应性**:系统流程设计符合环境问题处理的实际业务需求,能够无缝融入现有工作流程。
|
||||
|
||||
4. **组织支持**:系统实施需要相关部门的协调配合,但总体上不会对现有组织架构产生颠覆性影响。
|
||||
|
||||
#### 2.4.4 法律可行性
|
||||
|
||||
从法律合规角度看,本系统的实施不存在重大障碍:
|
||||
|
||||
1. **数据隐私**:系统设计符合数据保护法规要求,对用户隐私数据进行加密存储和严格权限控制。
|
||||
|
||||
2. **知识产权**:系统开发过程中使用的第三方库和组件均可采用开源或获得授权的方式,避免知识产权风险。
|
||||
|
||||
3. **合规性**:系统功能和流程设计可以确保符合相关法律法规和行业标准,确保合法合规运营。
|
||||
|
||||
## 3. 功能性需求
|
||||
|
||||
### 3.1 功能层次方框图
|
||||
|
||||
以下功能层次图展示了系统的整体功能架构:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
%% 用户交互层
|
||||
subgraph "用户交互层"
|
||||
direction LR
|
||||
C["公众服务模块\n(问题上报)"]
|
||||
H["个人中心模块\n(我的反馈/资料)"]
|
||||
D["管理驾驶舱\n(数据决策)"]
|
||||
end
|
||||
|
||||
%% 核心业务层
|
||||
subgraph "核心业务层"
|
||||
direction LR
|
||||
AI["AI分析模块\n(内容审核)"]
|
||||
E["任务管理模块\n(分配、流转、执行)"]
|
||||
end
|
||||
|
||||
%% 应用支撑层
|
||||
subgraph "应用支撑层"
|
||||
direction LR
|
||||
F["网格与地图模块\n(LBS & 寻路)"]
|
||||
I["文件服务模块\n(附件存取)"]
|
||||
end
|
||||
|
||||
%% 基础服务层
|
||||
subgraph "基础服务层"
|
||||
direction LR
|
||||
B["用户与认证模块"]
|
||||
G["系统管理模块\n(用户/权限)"]
|
||||
J["日志审计模块"]
|
||||
end
|
||||
|
||||
%% 定义关系
|
||||
C -- "提交反馈" --> AI
|
||||
AI -- "分析结果" --> E
|
||||
C -- "附件" --> I
|
||||
E -- "调用" --> F
|
||||
E -- "任务附件" --> I
|
||||
E -- "统计数据" --> D
|
||||
|
||||
H -- "查询个人数据" --> E
|
||||
|
||||
%% 基础服务支撑所有上层模块 (关系隐含)
|
||||
G -- "管理" --> B
|
||||
|
||||
classDef userLayer fill:#d4f1f9,stroke:#05a8e5;
|
||||
classDef coreLayer fill:#ffe6cc,stroke:#f7a128;
|
||||
classDef appSupportLayer fill:#d5e8d4,stroke:#82b366;
|
||||
classDef baseLayer fill:#e1d5e7,stroke:#9673a6;
|
||||
|
||||
class C,H,D userLayer;
|
||||
class AI,E coreLayer;
|
||||
class F,I appSupportLayer;
|
||||
class B,G,J baseLayer;
|
||||
```
|
||||
# 需求定义文档(续)
|
||||
|
||||
### 3.2 模块功能概述
|
||||
|
||||
| 模块名称 | 功能概述 |
|
||||
| :--- | :--- |
|
||||
| **用户与认证模块** | 负责用户身份验证和权限控制,提供注册、登录、密码重置等功能,确保系统安全性。 |
|
||||
| **反馈管理模块** | 处理公众提交的环境问题反馈,包括提交、审核、状态追踪和查询统计等功能。 |
|
||||
| **任务管理模块** | 将审核通过的反馈转化为工作任务,管理任务的分配、执行和完成全流程。 |
|
||||
| **网格与地图模块** | 提供地理空间的网格化管理,支持路径规划和地图可视化,辅助任务执行。 |
|
||||
| **决策支持模块** | 通过数据分析和可视化,为管理层提供决策支持,帮助优化资源配置和治理策略。 |
|
||||
| **系统管理模块** | 提供系统配置、用户管理、权限设置等基础功能,保障系统正常运行。 |
|
||||
| **文件服务模块** | 处理系统中的文件上传、存储和访问,支持反馈和任务的附件管理。 |
|
||||
| **日志审计模块** | 记录系统操作日志,支持安全审计和问题追溯,确保系统运行的可追溯性。 |
|
||||
|
||||
## 4. 整体业务流程
|
||||
|
||||
下图描述了从公众发现问题、上报、到平台内部流转、处理、并最终反馈结果的完整闭环业务流程:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
%% 定义样式
|
||||
classDef public fill:#d4f1f9,stroke:#05a8e5,color:#333
|
||||
classDef platform fill:#ffe6cc,stroke:#f7a128,color:#333
|
||||
classDef worker fill:#d5e8d4,stroke:#82b366,color:#333
|
||||
classDef supervisor fill:#e1d5e7,stroke:#9673a6,color:#333
|
||||
classDef decision fill:#f8cecc,stroke:#b85450,color:#333
|
||||
classDef start_end fill:#f5f5f5,stroke:#666666,color:#333,stroke-width:2px
|
||||
|
||||
%% 流程开始
|
||||
A([开始]) --> B["[公众端] 发现环境问题"]
|
||||
B --> C["[公众端] 提交反馈<br>(标题/描述/图片/位置)"]
|
||||
|
||||
%% 平台接收与AI处理
|
||||
C --> D["[平台] 接收反馈<br>生成唯一事件ID"]
|
||||
D --> E{"[平台] AI自动审核<br>分析内容/分类"}
|
||||
|
||||
%% AI审核分支
|
||||
E -- "明显无效" --> F1["[平台] 标记为AI_REJECTED"]
|
||||
F1 --> F2["[平台] 通知提交者"]
|
||||
F2 --> Z1([结束])
|
||||
|
||||
E -- "需人工确认" --> G["[主管] 查看反馈详情<br>进行人工审核"]
|
||||
|
||||
%% 主管审核分支
|
||||
G --> H{"[主管] 审核决定"}
|
||||
H -- "驳回" --> I1["[主管] 填写驳回理由"]
|
||||
I1 --> I2["[平台] 更新状态为REJECTED"]
|
||||
I2 --> I3["[平台] 通知提交者"]
|
||||
I3 --> Z2([结束])
|
||||
|
||||
%% 审核通过,创建任务
|
||||
H -- "通过" --> J1["[主管] 确认反馈有效"]
|
||||
J1 --> J2["[平台] 自动创建结构化任务"]
|
||||
J2 --> J3["[平台] 更新反馈状态为PROCESSED"]
|
||||
|
||||
%% 任务分配
|
||||
J3 --> K1{"[主管] 选择分配方式"}
|
||||
K1 -- "手动分配" --> K2["[主管] 选择特定网格员"]
|
||||
K1 -- "智能推荐" --> K3["[平台] 运行分配算法<br>考虑位置/负载/专长"]
|
||||
K3 --> K4["[平台] 推荐最佳人选"]
|
||||
K4 --> K2
|
||||
K2 --> K5["[平台] 创建任务分配记录<br>更新任务状态为ASSIGNED"]
|
||||
K5 --> K6["[平台] 通知网格员"]
|
||||
|
||||
%% 网格员处理
|
||||
K6 --> L1["[网格员] 接收任务通知"]
|
||||
L1 --> L2{"[网格员] 接受任务?"}
|
||||
L2 -- "拒绝" --> K1
|
||||
L2 -- "接受" --> L3["[网格员] 更新任务状态为IN_PROGRESS"]
|
||||
L3 --> L4["[网格员] 查看任务详情<br>获取路径规划"]
|
||||
L4 --> L5["[网格员] 前往现场处理"]
|
||||
L5 --> L6["[网格员] 记录处理过程<br>上传证明材料"]
|
||||
L6 --> L7["[网格员] 提交处理结果<br>更新状态为SUBMITTED"]
|
||||
|
||||
%% 主管审核结果
|
||||
L7 --> M1["[主管] 审核处理结果"]
|
||||
M1 --> M2{"[主管] 结果是否合格?"}
|
||||
M2 -- "不合格" --> M3["[主管] 填写原因<br>要求重新处理"]
|
||||
M3 --> L4
|
||||
|
||||
%% 完成流程
|
||||
M2 -- "合格" --> N1["[主管] 确认任务完成"]
|
||||
N1 --> N2["[平台] 更新任务状态为APPROVED"]
|
||||
N2 --> N3["[平台] 更新反馈状态为CLOSED"]
|
||||
N3 --> N4["[平台] 通知反馈提交者"]
|
||||
N4 --> N5["[平台] 更新统计数据"]
|
||||
N5 --> O["[决策层] 查看数据看板<br>分析环境趋势"]
|
||||
O --> Z3([结束])
|
||||
|
||||
%% 为节点添加类别
|
||||
class A,Z1,Z2,Z3 start_end
|
||||
class B,C,F2,I3,N4 public
|
||||
class D,E,F1,I2,J2,J3,K3,K4,K5,K6,N2,N3,N5 platform
|
||||
class G,H,I1,J1,K1,K2,M1,M2,M3,N1 supervisor
|
||||
class L1,L2,L3,L4,L5,L6,L7 worker
|
||||
class O decision
|
||||
```
|
||||
|
||||
## 5. 功能需求详细描述
|
||||
|
||||
### 5.1 用户与认证模块需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| AUTH-01 | 用户注册 | 系统应允许新用户通过提供基本信息(姓名、手机号、邮箱、密码等)进行注册,并验证信息的有效性和唯一性。 | 高 |
|
||||
| AUTH-02 | 用户登录 | 系统应支持用户通过邮箱/手机号和密码进行身份验证,登录成功后生成安全令牌用于后续请求。 | 高 |
|
||||
| AUTH-03 | 密码重置 | 系统应提供安全的密码重置机制,包括通过邮箱或手机验证码验证身份。 | 中 |
|
||||
| AUTH-04 | 权限控制 | 系统应基于用户角色(公众用户、网格员、主管、管理员、决策者)实施访问控制,确保用户只能访问其权限范围内的功能和数据。 | 高 |
|
||||
| AUTH-05 | 会话管理 | 系统应维护和管理用户会话状态,包括会话创建、验证和超时处理。 | 中 |
|
||||
| AUTH-06 | 个人资料管理 | 系统应允许用户查看和更新其个人资料,包括基本信息、联系方式和偏好设置。 | 低 |
|
||||
| AUTH-07 | 安全日志 | 系统应记录所有关键安全事件(登录尝试、权限变更等),支持安全审计。 | 中 |
|
||||
|
||||
**用户与认证流程图**:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[用户访问系统] --> B{是否已登录?}
|
||||
B -- 否 --> C{是否有账号?}
|
||||
B -- 是 --> D[访问系统功能]
|
||||
|
||||
C -- 否 --> E[注册新账号]
|
||||
C -- 是 --> F[登录系统]
|
||||
|
||||
E --> G[填写注册信息]
|
||||
G --> H[验证邮箱/手机]
|
||||
H --> I[创建用户账号]
|
||||
I --> F
|
||||
|
||||
F --> J{认证是否成功?}
|
||||
J -- 否 --> K{是否忘记密码?}
|
||||
J -- 是 --> L[生成安全令牌]
|
||||
|
||||
K -- 是 --> M[密码重置流程]
|
||||
K -- 否 --> F
|
||||
|
||||
M --> N[验证身份]
|
||||
N --> O[设置新密码]
|
||||
O --> F
|
||||
|
||||
L --> P[加载用户权限]
|
||||
P --> D
|
||||
|
||||
D --> Q[系统记录操作日志]
|
||||
|
||||
R[用户请求退出] --> S[清除会话信息]
|
||||
S --> T[返回登录页面]
|
||||
```
|
||||
|
||||
### 5.2 反馈管理模块需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| FEED-01 | 反馈提交 | 系统应允许公众用户提交环境问题反馈,包括问题描述、位置标记、污染类型分类和图片上传。 | 高 |
|
||||
| FEED-02 | AI内容审核 | 系统应自动分析反馈内容,识别垃圾信息、重复提交,并进行初步分类和紧急程度评估。 | 中 |
|
||||
| FEED-03 | 人工审核 | 系统应提供主管审核反馈的工作台,支持查看详情、批准或驳回反馈。 | 高 |
|
||||
| FEED-04 | 状态追踪 | 系统应记录和展示反馈的全生命周期状态变更,允许用户查询处理进度。 | 高 |
|
||||
| FEED-05 | 反馈查询 | 系统应支持按多种条件(状态、时间、区域、类型等)查询和筛选反馈列表。 | 中 |
|
||||
| FEED-06 | 反馈统计 | 系统应生成反馈数据的统计分析,包括数量分布、处理效率等指标。 | 低 |
|
||||
| FEED-07 | 通知提醒 | 系统应在反馈状态变更时通知相关用户,保持信息透明。 | 中 |
|
||||
|
||||
**反馈管理流程图**:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[公众用户发现环境问题] --> B[打开反馈提交界面]
|
||||
B --> C[填写问题描述]
|
||||
C --> D[选择污染类型]
|
||||
D --> E[评估严重程度]
|
||||
E --> F[标记地理位置]
|
||||
F --> G[上传现场照片]
|
||||
G --> H[提交反馈]
|
||||
|
||||
H --> I[系统生成唯一事件ID]
|
||||
I --> J[AI自动审核内容]
|
||||
|
||||
J --> K{AI审核结果}
|
||||
K -- 明显无效 --> L[标记为AI_REJECTED]
|
||||
K -- 需人工确认 --> M[进入主管审核队列]
|
||||
|
||||
L --> N[通知用户反馈被拒绝]
|
||||
|
||||
M --> O[主管查看反馈详情]
|
||||
O --> P{审核决定}
|
||||
P -- 驳回 --> Q[填写驳回理由]
|
||||
P -- 通过 --> R[标记为有效反馈]
|
||||
|
||||
Q --> S[更新状态为REJECTED]
|
||||
S --> T[通知用户反馈被驳回]
|
||||
|
||||
R --> U[创建关联任务]
|
||||
U --> V[更新状态为PROCESSED]
|
||||
|
||||
W[用户查询反馈状态] --> X[系统展示处理进度]
|
||||
|
||||
Y[管理员查看统计数据] --> Z[系统生成反馈分析报表]
|
||||
```
|
||||
|
||||
# 需求定义文档(续)
|
||||
|
||||
### 5.3 任务管理模块需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| TASK-01 | 任务创建 | 系统应支持从审核通过的反馈自动生成任务,也支持主管手动创建临时任务。 | 高 |
|
||||
| TASK-02 | 智能分配 | 系统应基于多因素(网格员位置、当前负载、专业技能、历史表现)推荐最合适的处理人员。 | 中 |
|
||||
| TASK-03 | 任务分配 | 系统应支持主管手动选择或确认系统推荐的网格员,并将任务分配给他们。 | 高 |
|
||||
| TASK-04 | 任务通知 | 系统应在任务分配后立即通知相关网格员,并提供任务详情查看途径。 | 高 |
|
||||
| TASK-05 | 任务执行跟踪 | 系统应记录任务的每个状态变更,支持网格员实时上报处理进度。 | 中 |
|
||||
| TASK-06 | 路径规划 | 系统应为网格员提供从当前位置到任务地点的最优路径规划。 | 中 |
|
||||
| TASK-07 | 结果提交 | 系统应支持网格员提交处理结果,包括文字描述和图片证明。 | 高 |
|
||||
| TASK-08 | 结果审核 | 系统应支持主管审核网格员提交的处理结果,可以通过或驳回并提供反馈。 | 高 |
|
||||
| TASK-09 | 任务查询 | 系统应支持按多种条件(状态、负责人、时间、区域等)查询和筛选任务列表。 | 中 |
|
||||
| TASK-10 | 任务统计 | 系统应生成任务数据的统计分析,包括完成率、平均处理时长等绩效指标。 | 低 |
|
||||
| TASK-11 | 任务看板 | 系统应提供直观的任务看板,展示不同状态任务的数量和分布。 | 低 |
|
||||
|
||||
**任务管理流程图**:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[反馈通过审核] --> B[自动创建任务]
|
||||
C[主管手动创建任务] --> D[任务创建完成]
|
||||
B --> D
|
||||
D --> E{选择分配方式}
|
||||
E -- 手动分配 --> F[主管选择网格员]
|
||||
E -- 智能推荐 --> G[系统推荐最佳人选]
|
||||
G --> F
|
||||
F --> H[分配任务给网格员]
|
||||
H --> I[通知网格员]
|
||||
I --> J{网格员接受?}
|
||||
J -- 否 --> E
|
||||
J -- 是 --> K[更新任务状态为进行中]
|
||||
K --> L[网格员获取路径规划]
|
||||
L --> M[网格员处理任务]
|
||||
M --> N[提交处理结果]
|
||||
N --> O[主管审核结果]
|
||||
O --> P{结果合格?}
|
||||
P -- 否 --> Q[填写原因]
|
||||
Q --> L
|
||||
P -- 是 --> R[更新任务状态为已完成]
|
||||
R --> S[通知反馈提交者]
|
||||
S --> T[更新统计数据]
|
||||
```
|
||||
|
||||
### 5.4 网格与地图模块需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| GRID-01 | 网格定义 | 系统应支持管理员定义和维护城市网格系统,包括网格的坐标、属性和责任人分配。 | 中 |
|
||||
| GRID-02 | 地图可视化 | 系统应在地图上直观展示反馈点、任务分布和网格员位置,支持多种筛选条件和图层切换。 | 中 |
|
||||
| GRID-03 | 位置标记 | 系统应支持用户在地图上精确标记环境问题位置,并自动关联到对应网格。 | 高 |
|
||||
| GRID-04 | A*寻路算法 | 系统应基于网格系统和实时路况,为网格员提供从当前位置到任务地点的最优路径规划。 | 中 |
|
||||
| GRID-05 | 区域统计 | 系统应基于网格系统,生成环境问题热力图,识别高发区域和问题类型分布。 | 低 |
|
||||
| GRID-06 | 网格查询 | 系统应支持查询特定区域内的网格定义、属性和历史问题记录。 | 低 |
|
||||
| GRID-07 | 离线地图 | 系统应支持地图数据的离线缓存,保证在网络不稳定情况下的基本功能。 | 低 |
|
||||
|
||||
**网格与地图流程图**:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[管理员定义网格系统] --> B[划分城市区域为网格单元]
|
||||
B --> C[设置网格属性]
|
||||
C --> D[分配网格责任人]
|
||||
|
||||
E[用户标记环境问题位置] --> F[系统关联到对应网格]
|
||||
F --> G[存储地理位置信息]
|
||||
|
||||
H[网格员接收任务] --> I[查看任务位置]
|
||||
I --> J[请求路径规划]
|
||||
J --> K[A*算法计算最优路径]
|
||||
K --> L[展示导航路线]
|
||||
|
||||
M[管理员查看统计数据] --> N[生成环境问题热力图]
|
||||
N --> O[识别问题高发区域]
|
||||
O --> P[调整资源分配策略]
|
||||
```
|
||||
|
||||
### 5.5 决策支持模块需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| DECI-01 | 核心指标看板 | 系统应实时展示关键业务指标,如待处理反馈数、进行中任务数、平均处理时长、按时完成率等。 | 中 |
|
||||
| DECI-02 | 多维度分析 | 系统应支持按时间、区域、污染类型、处理人等多个维度对数据进行交叉分析和趋势展示。 | 中 |
|
||||
| DECI-03 | 热力图可视化 | 系统应在地图上以热力图形式展示环境问题的分布密度,直观识别高发区域。 | 中 |
|
||||
| DECI-04 | 绩效评估 | 系统应对网格员和区域的工作效率、问题解决质量等进行量化评估,生成排名和对比分析。 | 低 |
|
||||
| DECI-05 | 预警机制 | 系统应基于历史数据和趋势分析,对可能出现的环境风险提前预警。 | 低 |
|
||||
| DECI-06 | 报表导出 | 系统应支持将分析结果导出为多种格式(PDF、Excel等),便于进一步分析和汇报。 | 低 |
|
||||
| DECI-07 | 个性化配置 | 系统应支持决策者个性化配置数据看板,满足不同管理者的关注点。 | 低 |
|
||||
|
||||
**决策支持流程图**:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[系统收集业务数据] --> B[实时计算核心指标]
|
||||
B --> C[展示核心指标看板]
|
||||
|
||||
D[决策者选择分析维度] --> E[系统执行多维度分析]
|
||||
E --> F[生成趋势图表]
|
||||
|
||||
G[系统分析地理数据] --> H[生成环境问题热力图]
|
||||
H --> I[标识高发区域]
|
||||
|
||||
J[系统收集网格员工作数据] --> K[计算绩效指标]
|
||||
K --> L[生成绩效排名]
|
||||
|
||||
M[系统分析历史数据] --> N[识别异常趋势]
|
||||
N --> O{是否达到预警阈值?}
|
||||
O -- 是 --> P[触发预警通知]
|
||||
O -- 否 --> Q[继续监控]
|
||||
|
||||
R[决策者查看分析结果] --> S[选择导出格式]
|
||||
S --> T[导出分析报表]
|
||||
```
|
||||
|
||||
## 6. 非功能性需求
|
||||
|
||||
### 6.1 性能需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| PERF-01 | 响应时间 | 系统的页面加载时间应不超过3秒,API响应时间应不超过500毫秒(不包括文件上传下载)。 | 高 |
|
||||
| PERF-02 | 并发用户 | 系统应能同时支持至少100个并发用户正常操作,不出现明显延迟。 | 中 |
|
||||
| PERF-03 | 数据处理量 | 系统应能处理每日至少1000条反馈和500个任务的创建、更新和查询操作。 | 中 |
|
||||
| PERF-04 | 文件处理 | 系统应支持单个文件最大10MB,总附件大小不超过50MB的上传和处理。 | 中 |
|
||||
| PERF-05 | 地图渲染 | 地图界面应能在1秒内完成初始加载,并在500毫秒内响应用户的缩放和平移操作。 | 中 |
|
||||
|
||||
### 6.2 可用性需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| USAB-01 | 界面一致性 | 系统界面应保持风格一致,包括颜色方案、按钮位置、导航结构等,减少用户学习成本。 | 中 |
|
||||
| USAB-02 | 错误处理 | 系统应提供清晰的错误提示和恢复建议,避免用户操作中断。 | 高 |
|
||||
| USAB-03 | 帮助系统 | 系统应提供上下文相关的帮助信息和操作指南,支持用户自助解决问题。 | 低 |
|
||||
| USAB-04 | 响应式设计 | 系统界面应适应不同设备(PC、平板、手机)的屏幕尺寸,提供一致的用户体验。 | 高 |
|
||||
| USAB-05 | 操作简化 | 核心功能的操作路径应尽量简化,减少用户点击次数和输入量。 | 中 |
|
||||
|
||||
### 6.3 安全性需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| SECU-01 | 数据加密 | 敏感数据(如用户密码)必须加密存储,传输过程中应使用HTTPS加密。 | 高 |
|
||||
| SECU-02 | 访问控制 | 系统应实施严格的基于角色的访问控制,确保用户只能访问其权限范围内的数据和功能。 | 高 |
|
||||
| SECU-03 | 输入验证 | 系统应对所有用户输入进行验证和过滤,防止SQL注入、XSS等常见安全攻击。 | 高 |
|
||||
| SECU-04 | 会话管理 | 系统应安全管理用户会话,包括会话创建、验证、超时和销毁,防止会话劫持。 | 中 |
|
||||
| SECU-05 | 审计日志 | 系统应记录所有关键操作的审计日志,包括用户登录、数据修改、权限变更等。 | 中 |
|
||||
|
||||
# 需求定义文档(续)
|
||||
|
||||
### 6.4 可靠性需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| RELI-01 | 系统可用性 | 系统应保证7x24小时的稳定运行,计划内维护时间除外,系统可用性应达到99.5%以上。 | 高 |
|
||||
| RELI-02 | 数据备份 | 系统应定期(至少每日一次)对全部业务数据进行备份,并支持数据恢复。 | 高 |
|
||||
| RELI-03 | 故障恢复 | 系统应具备故障检测和自动恢复机制,在出现异常情况时能够快速恢复正常运行。 | 中 |
|
||||
| RELI-04 | 数据一致性 | 系统应确保在各种操作条件下(包括并发访问和异常中断)保持数据的一致性和完整性。 | 高 |
|
||||
| RELI-05 | 容错能力 | 系统应能够处理常见的错误情况(如网络中断、数据异常),并提供适当的降级服务。 | 中 |
|
||||
|
||||
### 6.5 可维护性需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| MAIN-01 | 模块化设计 | 系统应采用模块化设计,各功能模块之间松耦合,便于独立开发、测试和维护。 | 中 |
|
||||
| MAIN-02 | 配置管理 | 系统应支持通过配置文件或管理界面调整系统参数,无需修改代码和重新部署。 | 中 |
|
||||
| MAIN-03 | 日志记录 | 系统应记录详细的运行日志,包括错误信息、性能指标和关键操作,便于问题诊断。 | 高 |
|
||||
| MAIN-04 | 版本升级 | 系统应支持平滑的版本升级机制,最小化升级对用户的影响。 | 低 |
|
||||
| MAIN-05 | 代码规范 | 系统开发应遵循统一的编码规范和设计模式,提高代码可读性和可维护性。 | 中 |
|
||||
|
||||
### 6.6 可扩展性需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| SCAL-01 | 水平扩展 | 系统架构应支持通过增加服务器节点进行水平扩展,以应对用户量和数据量的增长。 | 低 |
|
||||
| SCAL-02 | 功能扩展 | 系统应支持在不影响现有功能的情况下,添加新的功能模块和业务流程。 | 中 |
|
||||
| SCAL-03 | 接口开放 | 系统应提供标准化的API接口,便于与其他系统集成和数据交换。 | 中 |
|
||||
| SCAL-04 | 多租户支持 | 系统应具备支持多租户(如不同城市或区域)的潜力,能够在未来进行扩展。 | 低 |
|
||||
| SCAL-05 | 数据量增长 | 系统应能够处理数据量的持续增长,性能不应随着数据量的增加而明显下降。 | 中 |
|
||||
|
||||
## 7. 数据需求
|
||||
|
||||
### 7.1 数据实体
|
||||
|
||||
系统需要管理以下核心数据实体:
|
||||
|
||||
1. **用户账户 (UserAccount)**:存储系统用户的基本信息、认证信息和角色权限。
|
||||
2. **反馈 (Feedback)**:存储公众提交的环境问题反馈,包括描述、位置、图片等信息。
|
||||
3. **任务 (Task)**:存储从反馈生成的工作任务,包括任务详情、状态和处理记录。
|
||||
4. **网格 (Grid)**:存储城市区域的网格化管理数据,包括网格坐标、属性和责任人。
|
||||
5. **任务分配 (Assignment)**:存储任务与网格员之间的分配关系,包括分配时间、状态等。
|
||||
6. **附件 (Attachment)**:存储反馈和任务相关的图片、文档等附件文件。
|
||||
7. **操作日志 (OperationLog)**:存储系统中的关键操作记录,用于审计和问题追溯。
|
||||
|
||||
### 7.2 数据量估计
|
||||
|
||||
基于系统预期使用规模,估计以下数据量:
|
||||
|
||||
1. **用户账户**:预计1000个用户账户,包括公众用户、网格员、主管、管理员和决策者。
|
||||
2. **反馈**:预计每日100-200条新增反馈,年增长约5万条。
|
||||
3. **任务**:预计每日50-100个新增任务,年增长约2.5万个。
|
||||
4. **网格**:预计1000-5000个网格单元,根据城市规模和网格粒度而定。
|
||||
5. **附件**:预计每条反馈平均2张图片,每个任务平均2张图片,年增长约15万个文件。
|
||||
6. **操作日志**:预计每日1万条日志记录,主要用于短期审计,长期可归档。
|
||||
|
||||
### 7.3 数据保留策略
|
||||
|
||||
1. **核心业务数据**(用户、反馈、任务、网格):长期保留,至少保留3年。
|
||||
2. **附件文件**:保留1年,可根据存储容量考虑适当延长或缩短。
|
||||
3. **操作日志**:
|
||||
- 详细日志保留30天
|
||||
- 关键审计日志保留1年
|
||||
- 统计汇总数据长期保留
|
||||
|
||||
### 7.4 数据备份要求
|
||||
|
||||
1. **备份频率**:
|
||||
- 核心业务数据:每日全量备份,每小时增量备份
|
||||
- 附件文件:每周全量备份,每日增量备份
|
||||
- 配置数据:每次变更后备份
|
||||
|
||||
2. **备份保留**:
|
||||
- 每日备份保留7天
|
||||
- 每周备份保留1个月
|
||||
- 每月备份保留6个月
|
||||
- 每年备份永久保留
|
||||
|
||||
3. **恢复能力**:系统应支持将数据恢复到任意备份点,恢复时间目标(RTO)不超过4小时。
|
||||
|
||||
## 8. 结论
|
||||
|
||||
### 8.1 需求优先级总结
|
||||
|
||||
基于业务重要性和实现复杂度,系统需求按以下优先级排序:
|
||||
|
||||
1. **最高优先级**:
|
||||
- 用户认证和权限控制
|
||||
- 反馈提交和审核
|
||||
- 任务创建和分配
|
||||
- 数据安全和完整性
|
||||
|
||||
2. **高优先级**:
|
||||
- 任务执行和结果审核
|
||||
- 地图标记和路径规划
|
||||
- 系统性能和可用性
|
||||
- 用户界面和体验
|
||||
|
||||
3. **中等优先级**:
|
||||
- AI内容审核
|
||||
- 决策支持和数据分析
|
||||
- 通知和提醒功能
|
||||
- 系统可维护性
|
||||
|
||||
4. **低优先级**:
|
||||
- 高级统计和报表
|
||||
- 个性化配置
|
||||
- 系统扩展性
|
||||
- 辅助功能和优化
|
||||
|
||||
### 8.2 实施建议
|
||||
|
||||
为确保系统成功实施,建议采取以下策略:
|
||||
|
||||
1. **分阶段实施**:
|
||||
- 第一阶段:核心功能(用户管理、反馈、任务)
|
||||
- 第二阶段:支撑功能(地图、AI审核)
|
||||
- 第三阶段:高级功能(决策支持、报表)
|
||||
|
||||
2. **持续迭代**:采用敏捷开发方法,快速交付可用版本,根据用户反馈持续改进。
|
||||
|
||||
3. **用户参与**:在开发过程中邀请各类用户参与测试和评估,确保系统满足实际需求。
|
||||
|
||||
4. **技术选型**:选择成熟稳定的技术栈,平衡创新性和可靠性,降低开发和维护风险。
|
||||
|
||||
5. **数据治理**:建立完善的数据管理和治理机制,确保数据质量和安全。
|
||||
|
||||
### 8.3 预期效益
|
||||
|
||||
成功实施环境监测系统预期将带来以下效益:
|
||||
|
||||
1. **业务效益**:
|
||||
- 环境问题处理效率提升50%以上
|
||||
- 问题解决质量显著提高
|
||||
- 资源利用更加合理高效
|
||||
|
||||
2. **管理效益**:
|
||||
- 实现环境问题全流程可视化管理
|
||||
- 提供科学决策的数据支持
|
||||
- 优化工作流程和资源配置
|
||||
|
||||
3. **社会效益**:
|
||||
- 提升公众参与环境治理的积极性
|
||||
- 增强政府工作透明度和公信力
|
||||
- 改善城市环境质量和居民生活满意度
|
||||
|
||||
通过环境监测系统的建设和应用,将有效解决当前环境问题管理中的痛点,构建起连接公众、管理部门和执行人员的桥梁,实现环境问题的快速发现、高效处理和全程监督,为城市环境治理提供有力支撑。
|
||||
@@ -1,166 +0,0 @@
|
||||
# 需求定义文档
|
||||
|
||||
## 1. 项目介绍
|
||||
|
||||
### 1.1 项目背景
|
||||
|
||||
环境监测系统(EMS)是为解决城市环境问题而设计的综合性管理平台。随着城市化进程加速,环境污染问题日益凸显,传统的环境问题上报和处理机制存在以下痛点:
|
||||
|
||||
- **流程繁琐**:公众发现环境问题后,需要通过多个渠道和部门层层上报,处理流程不透明
|
||||
- **响应缓慢**:从问题发现到最终解决,往往需要经历漫长的等待时间
|
||||
- **缺乏透明度**:公众难以了解问题处理进度,无法有效监督
|
||||
- **资源分配不合理**:缺乏科学的任务分配机制,导致人力资源利用不均衡
|
||||
|
||||
本系统旨在通过数字化手段,构建一个连接公众、管理部门和执行人员的环境监测与治理平台,实现环境问题的快速发现、高效处理和全程监督。
|
||||
|
||||
### 1.2 项目目标
|
||||
|
||||
1. **建立闭环管理机制**:构建从问题发现、上报、审核、分配、处理到结果反馈的完整闭环流程,确保每个环境问题都能得到妥善解决。
|
||||
2. **提高处理效率**:通过流程优化和智能算法,缩短环境问题从发现到解决的时间,提高环境治理效率。
|
||||
3. **增强公众参与**:为公众提供便捷的问题上报渠道,增强公众参与环境治理的积极性和获得感。
|
||||
4. **辅助决策分析**:通过数据可视化和多维度分析,为管理层提供决策支持,优化资源配置和治理策略。
|
||||
5. **提升治理透明度**:实现环境问题处理全过程可追踪、可监督,增强政府工作透明度和公信力。
|
||||
|
||||
## 2. 系统分析
|
||||
|
||||
### 2.1 业务痛点分析
|
||||
|
||||
1. **信息孤岛**:环境问题信息分散在不同部门和系统中,缺乏统一管理和共享机制。
|
||||
2. **流程断裂**:传统环境问题处理流程存在多个环节,各环节之间衔接不畅,容易导致问题处理延误或遗漏。
|
||||
3. **资源分配不均**:缺乏科学的任务分配机制,导致人力资源利用不均衡,部分区域问题积压严重。
|
||||
4. **监督机制不足**:公众难以了解问题处理进度和结果,缺乏有效的监督渠道。
|
||||
5. **数据分析不足**:未能充分利用环境问题数据进行趋势分析和预测,难以支持科学决策。
|
||||
|
||||
### 2.2 用户角色分析
|
||||
|
||||
环境监测系统涉及五类主要用户角色,每个角色在系统中承担不同的职责:
|
||||
|
||||
1. **公众用户**:系统的信息输入端,负责发现和上报环境问题,是系统的主要服务对象。
|
||||
- 需求:简单便捷的问题上报方式、透明的处理进度查询
|
||||
- 痛点:传统上报渠道繁琐、反馈周期长、处理结果不透明
|
||||
|
||||
2. **网格员**:系统的执行端,负责接收任务并前往现场处理环境问题,是系统的核心操作人员。
|
||||
- 需求:清晰的任务指派、便捷的结果上报、高效的路径规划
|
||||
- 痛点:任务分配不合理、工作量分布不均、缺乏高效导航
|
||||
|
||||
3. **主管**:系统的管理端,负责审核反馈、分配任务、审核结果,是系统的关键决策者。
|
||||
- 需求:高效的任务管理、智能的人员调配、直观的进度监控
|
||||
- 痛点:人工分配任务效率低、缺乏全局视角、绩效评估困难
|
||||
|
||||
4. **管理员**:系统的维护端,负责用户管理、权限设置、系统配置等基础支撑工作。
|
||||
- 需求:灵活的权限配置、完善的日志审计、便捷的系统维护
|
||||
- 痛点:账户管理繁琐、权限控制粗放、系统维护成本高
|
||||
|
||||
5. **决策者**:系统的战略端,通过分析系统生成的统计数据和趋势图表,制定环境管理策略和资源分配决策,是系统的最终受益者之一。
|
||||
- 需求:多维度的数据分析、直观的可视化展示、科学的决策支持
|
||||
- 痛点:数据获取困难、分析维度单一、缺乏预测能力
|
||||
|
||||
### 2.3 用例分析
|
||||
|
||||
#### 2.3.1 用例图
|
||||
|
||||
以下用例图展示了系统中各角色可以执行的主要操作:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
%% 定义角色
|
||||
PublicUser["公众用户"]
|
||||
GridWorker["网格员"]
|
||||
Supervisor["主管"]
|
||||
Admin["管理员"]
|
||||
DecisionMaker["决策者"]
|
||||
|
||||
%% 定义用例
|
||||
UC1["注册与登录"]
|
||||
UC2["提交环境问题反馈"]
|
||||
UC3["查看反馈处理进度"]
|
||||
UC4["接收任务通知"]
|
||||
UC5["执行任务"]
|
||||
UC6["提交处理结果"]
|
||||
UC7["审核反馈内容"]
|
||||
UC8["分配任务"]
|
||||
UC9["审核处理结果"]
|
||||
UC10["查看统计数据"]
|
||||
UC11["管理用户账户"]
|
||||
UC12["配置系统参数"]
|
||||
UC13["查看决策仪表盘"]
|
||||
UC14["生成分析报告"]
|
||||
|
||||
%% 建立关系
|
||||
PublicUser --> UC1
|
||||
PublicUser --> UC2
|
||||
PublicUser --> UC3
|
||||
|
||||
GridWorker --> UC1
|
||||
GridWorker --> UC4
|
||||
GridWorker --> UC5
|
||||
GridWorker --> UC6
|
||||
|
||||
Supervisor --> UC1
|
||||
Supervisor --> UC7
|
||||
Supervisor --> UC8
|
||||
Supervisor --> UC9
|
||||
Supervisor --> UC10
|
||||
|
||||
Admin --> UC1
|
||||
Admin --> UC10
|
||||
Admin --> UC11
|
||||
Admin --> UC12
|
||||
|
||||
DecisionMaker --> UC1
|
||||
DecisionMaker --> UC10
|
||||
DecisionMaker --> UC13
|
||||
DecisionMaker --> UC14
|
||||
|
||||
%% 设置样式
|
||||
classDef actor fill:#f9f,stroke:#333,stroke-width:2px
|
||||
classDef usecase fill:#ccf,stroke:#33f,stroke-width:1px
|
||||
|
||||
class PublicUser,GridWorker,Supervisor,Admin,DecisionMaker actor
|
||||
class UC1,UC2,UC3,UC4,UC5,UC6,UC7,UC8,UC9,UC10,UC11,UC12,UC13,UC14 usecase
|
||||
```
|
||||
|
||||
#### 2.3.2 活动图:反馈提交与处理流程
|
||||
|
||||
以下活动图展示了从公众发现环境问题到反馈处理完成的完整业务流程:
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> 发现环境问题
|
||||
发现环境问题 --> 填写反馈表单
|
||||
填写反馈表单 --> 上传图片
|
||||
上传图片 --> 标记位置
|
||||
标记位置 --> 提交反馈
|
||||
提交反馈 --> AI自动审核
|
||||
|
||||
state AI自动审核 {
|
||||
[*] --> 内容分析
|
||||
内容分析 --> 垃圾信息检测
|
||||
垃圾信息检测 --> 分类与评级
|
||||
分类与评级 --> [*]
|
||||
}
|
||||
|
||||
AI自动审核 --> 判断AI审核结果
|
||||
判断AI审核结果 --> 明显无效: AI拒绝
|
||||
判断AI审核结果 --> 需人工确认: 需确认
|
||||
|
||||
明显无效 --> 标记为AI_REJECTED
|
||||
标记为AI_REJECTED --> 通知提交者
|
||||
通知提交者 --> [*]
|
||||
|
||||
需人工确认 --> 主管人工审核
|
||||
主管人工审核 --> 判断审核结果
|
||||
|
||||
判断审核结果 --> 驳回: 不通过
|
||||
判断审核结果 --> 通过: 通过
|
||||
|
||||
驳回 --> 填写驳回理由
|
||||
填写驳回理由 --> 更新状态为REJECTED
|
||||
更新状态为REJECTED --> 通知提交者反馈被驳回
|
||||
通知提交者反馈被驳回 --> [*]
|
||||
|
||||
通过 --> 创建任务
|
||||
创建任务 --> 更新反馈状态为PROCESSED
|
||||
更新反馈状态为PROCESSED --> 任务分配流程
|
||||
任务分配流程 --> [*]
|
||||
```
|
||||
@@ -1,197 +0,0 @@
|
||||
# 需求定义文档(续)
|
||||
|
||||
### 3.2 模块功能概述
|
||||
|
||||
| 模块名称 | 功能概述 |
|
||||
| :--- | :--- |
|
||||
| **用户与认证模块** | 负责用户身份验证和权限控制,提供注册、登录、密码重置等功能,确保系统安全性。 |
|
||||
| **反馈管理模块** | 处理公众提交的环境问题反馈,包括提交、审核、状态追踪和查询统计等功能。 |
|
||||
| **任务管理模块** | 将审核通过的反馈转化为工作任务,管理任务的分配、执行和完成全流程。 |
|
||||
| **网格与地图模块** | 提供地理空间的网格化管理,支持路径规划和地图可视化,辅助任务执行。 |
|
||||
| **决策支持模块** | 通过数据分析和可视化,为管理层提供决策支持,帮助优化资源配置和治理策略。 |
|
||||
| **系统管理模块** | 提供系统配置、用户管理、权限设置等基础功能,保障系统正常运行。 |
|
||||
| **文件服务模块** | 处理系统中的文件上传、存储和访问,支持反馈和任务的附件管理。 |
|
||||
| **日志审计模块** | 记录系统操作日志,支持安全审计和问题追溯,确保系统运行的可追溯性。 |
|
||||
|
||||
## 4. 整体业务流程
|
||||
|
||||
下图描述了从公众发现问题、上报、到平台内部流转、处理、并最终反馈结果的完整闭环业务流程:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
%% 定义样式
|
||||
classDef public fill:#d4f1f9,stroke:#05a8e5,color:#333
|
||||
classDef platform fill:#ffe6cc,stroke:#f7a128,color:#333
|
||||
classDef worker fill:#d5e8d4,stroke:#82b366,color:#333
|
||||
classDef supervisor fill:#e1d5e7,stroke:#9673a6,color:#333
|
||||
classDef decision fill:#f8cecc,stroke:#b85450,color:#333
|
||||
classDef start_end fill:#f5f5f5,stroke:#666666,color:#333,stroke-width:2px
|
||||
|
||||
%% 流程开始
|
||||
A([开始]) --> B["[公众端] 发现环境问题"]
|
||||
B --> C["[公众端] 提交反馈<br>(标题/描述/图片/位置)"]
|
||||
|
||||
%% 平台接收与AI处理
|
||||
C --> D["[平台] 接收反馈<br>生成唯一事件ID"]
|
||||
D --> E{"[平台] AI自动审核<br>分析内容/分类"}
|
||||
|
||||
%% AI审核分支
|
||||
E -- "明显无效" --> F1["[平台] 标记为AI_REJECTED"]
|
||||
F1 --> F2["[平台] 通知提交者"]
|
||||
F2 --> Z1([结束])
|
||||
|
||||
E -- "需人工确认" --> G["[主管] 查看反馈详情<br>进行人工审核"]
|
||||
|
||||
%% 主管审核分支
|
||||
G --> H{"[主管] 审核决定"}
|
||||
H -- "驳回" --> I1["[主管] 填写驳回理由"]
|
||||
I1 --> I2["[平台] 更新状态为REJECTED"]
|
||||
I2 --> I3["[平台] 通知提交者"]
|
||||
I3 --> Z2([结束])
|
||||
|
||||
%% 审核通过,创建任务
|
||||
H -- "通过" --> J1["[主管] 确认反馈有效"]
|
||||
J1 --> J2["[平台] 自动创建结构化任务"]
|
||||
J2 --> J3["[平台] 更新反馈状态为PROCESSED"]
|
||||
|
||||
%% 任务分配
|
||||
J3 --> K1{"[主管] 选择分配方式"}
|
||||
K1 -- "手动分配" --> K2["[主管] 选择特定网格员"]
|
||||
K1 -- "智能推荐" --> K3["[平台] 运行分配算法<br>考虑位置/负载/专长"]
|
||||
K3 --> K4["[平台] 推荐最佳人选"]
|
||||
K4 --> K2
|
||||
K2 --> K5["[平台] 创建任务分配记录<br>更新任务状态为ASSIGNED"]
|
||||
K5 --> K6["[平台] 通知网格员"]
|
||||
|
||||
%% 网格员处理
|
||||
K6 --> L1["[网格员] 接收任务通知"]
|
||||
L1 --> L2{"[网格员] 接受任务?"}
|
||||
L2 -- "拒绝" --> K1
|
||||
L2 -- "接受" --> L3["[网格员] 更新任务状态为IN_PROGRESS"]
|
||||
L3 --> L4["[网格员] 查看任务详情<br>获取路径规划"]
|
||||
L4 --> L5["[网格员] 前往现场处理"]
|
||||
L5 --> L6["[网格员] 记录处理过程<br>上传证明材料"]
|
||||
L6 --> L7["[网格员] 提交处理结果<br>更新状态为SUBMITTED"]
|
||||
|
||||
%% 主管审核结果
|
||||
L7 --> M1["[主管] 审核处理结果"]
|
||||
M1 --> M2{"[主管] 结果是否合格?"}
|
||||
M2 -- "不合格" --> M3["[主管] 填写原因<br>要求重新处理"]
|
||||
M3 --> L4
|
||||
|
||||
%% 完成流程
|
||||
M2 -- "合格" --> N1["[主管] 确认任务完成"]
|
||||
N1 --> N2["[平台] 更新任务状态为APPROVED"]
|
||||
N2 --> N3["[平台] 更新反馈状态为CLOSED"]
|
||||
N3 --> N4["[平台] 通知反馈提交者"]
|
||||
N4 --> N5["[平台] 更新统计数据"]
|
||||
N5 --> O["[决策层] 查看数据看板<br>分析环境趋势"]
|
||||
O --> Z3([结束])
|
||||
|
||||
%% 为节点添加类别
|
||||
class A,Z1,Z2,Z3 start_end
|
||||
class B,C,F2,I3,N4 public
|
||||
class D,E,F1,I2,J2,J3,K3,K4,K5,K6,N2,N3,N5 platform
|
||||
class G,H,I1,J1,K1,K2,M1,M2,M3,N1 supervisor
|
||||
class L1,L2,L3,L4,L5,L6,L7 worker
|
||||
class O decision
|
||||
```
|
||||
|
||||
## 5. 功能需求详细描述
|
||||
|
||||
### 5.1 用户与认证模块需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| AUTH-01 | 用户注册 | 系统应允许新用户通过提供基本信息(姓名、手机号、邮箱、密码等)进行注册,并验证信息的有效性和唯一性。 | 高 |
|
||||
| AUTH-02 | 用户登录 | 系统应支持用户通过邮箱/手机号和密码进行身份验证,登录成功后生成安全令牌用于后续请求。 | 高 |
|
||||
| AUTH-03 | 密码重置 | 系统应提供安全的密码重置机制,包括通过邮箱或手机验证码验证身份。 | 中 |
|
||||
| AUTH-04 | 权限控制 | 系统应基于用户角色(公众用户、网格员、主管、管理员、决策者)实施访问控制,确保用户只能访问其权限范围内的功能和数据。 | 高 |
|
||||
| AUTH-05 | 会话管理 | 系统应维护和管理用户会话状态,包括会话创建、验证和超时处理。 | 中 |
|
||||
| AUTH-06 | 个人资料管理 | 系统应允许用户查看和更新其个人资料,包括基本信息、联系方式和偏好设置。 | 低 |
|
||||
| AUTH-07 | 安全日志 | 系统应记录所有关键安全事件(登录尝试、权限变更等),支持安全审计。 | 中 |
|
||||
|
||||
**用户与认证流程图**:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[用户访问系统] --> B{是否已登录?}
|
||||
B -- 否 --> C{是否有账号?}
|
||||
B -- 是 --> D[访问系统功能]
|
||||
|
||||
C -- 否 --> E[注册新账号]
|
||||
C -- 是 --> F[登录系统]
|
||||
|
||||
E --> G[填写注册信息]
|
||||
G --> H[验证邮箱/手机]
|
||||
H --> I[创建用户账号]
|
||||
I --> F
|
||||
|
||||
F --> J{认证是否成功?}
|
||||
J -- 否 --> K{是否忘记密码?}
|
||||
J -- 是 --> L[生成安全令牌]
|
||||
|
||||
K -- 是 --> M[密码重置流程]
|
||||
K -- 否 --> F
|
||||
|
||||
M --> N[验证身份]
|
||||
N --> O[设置新密码]
|
||||
O --> F
|
||||
|
||||
L --> P[加载用户权限]
|
||||
P --> D
|
||||
|
||||
D --> Q[系统记录操作日志]
|
||||
|
||||
R[用户请求退出] --> S[清除会话信息]
|
||||
S --> T[返回登录页面]
|
||||
```
|
||||
|
||||
### 5.2 反馈管理模块需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| FEED-01 | 反馈提交 | 系统应允许公众用户提交环境问题反馈,包括问题描述、位置标记、污染类型分类和图片上传。 | 高 |
|
||||
| FEED-02 | AI内容审核 | 系统应自动分析反馈内容,识别垃圾信息、重复提交,并进行初步分类和紧急程度评估。 | 中 |
|
||||
| FEED-03 | 人工审核 | 系统应提供主管审核反馈的工作台,支持查看详情、批准或驳回反馈。 | 高 |
|
||||
| FEED-04 | 状态追踪 | 系统应记录和展示反馈的全生命周期状态变更,允许用户查询处理进度。 | 高 |
|
||||
| FEED-05 | 反馈查询 | 系统应支持按多种条件(状态、时间、区域、类型等)查询和筛选反馈列表。 | 中 |
|
||||
| FEED-06 | 反馈统计 | 系统应生成反馈数据的统计分析,包括数量分布、处理效率等指标。 | 低 |
|
||||
| FEED-07 | 通知提醒 | 系统应在反馈状态变更时通知相关用户,保持信息透明。 | 中 |
|
||||
|
||||
**反馈管理流程图**:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[公众用户发现环境问题] --> B[打开反馈提交界面]
|
||||
B --> C[填写问题描述]
|
||||
C --> D[选择污染类型]
|
||||
D --> E[评估严重程度]
|
||||
E --> F[标记地理位置]
|
||||
F --> G[上传现场照片]
|
||||
G --> H[提交反馈]
|
||||
|
||||
H --> I[系统生成唯一事件ID]
|
||||
I --> J[AI自动审核内容]
|
||||
|
||||
J --> K{AI审核结果}
|
||||
K -- 明显无效 --> L[标记为AI_REJECTED]
|
||||
K -- 需人工确认 --> M[进入主管审核队列]
|
||||
|
||||
L --> N[通知用户反馈被拒绝]
|
||||
|
||||
M --> O[主管查看反馈详情]
|
||||
O --> P{审核决定}
|
||||
P -- 驳回 --> Q[填写驳回理由]
|
||||
P -- 通过 --> R[标记为有效反馈]
|
||||
|
||||
Q --> S[更新状态为REJECTED]
|
||||
S --> T[通知用户反馈被驳回]
|
||||
|
||||
R --> U[创建关联任务]
|
||||
U --> V[更新状态为PROCESSED]
|
||||
|
||||
W[用户查询反馈状态] --> X[系统展示处理进度]
|
||||
|
||||
Y[管理员查看统计数据] --> Z[系统生成反馈分析报表]
|
||||
```
|
||||
@@ -1,180 +0,0 @@
|
||||
# 需求定义文档(续)
|
||||
|
||||
#### 2.3.3 活动图:任务分配与执行流程
|
||||
|
||||
以下活动图展示了从任务创建到完成的完整业务流程:
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> 任务创建完成
|
||||
任务创建完成 --> 选择分配方式
|
||||
|
||||
state 选择分配方式 {
|
||||
[*] --> 手动分配
|
||||
[*] --> 智能推荐
|
||||
|
||||
智能推荐 --> 运行分配算法
|
||||
运行分配算法 --> 推荐最佳人选
|
||||
推荐最佳人选 --> 确认人选
|
||||
|
||||
手动分配 --> 选择特定网格员
|
||||
选择特定网格员 --> 确认人选
|
||||
|
||||
确认人选 --> [*]
|
||||
}
|
||||
|
||||
选择分配方式 --> 创建任务分配记录
|
||||
创建任务分配记录 --> 更新任务状态为ASSIGNED
|
||||
更新任务状态为ASSIGNED --> 通知网格员
|
||||
|
||||
通知网格员 --> 网格员接收通知
|
||||
网格员接收通知 --> 判断是否接受
|
||||
|
||||
判断是否接受 --> 拒绝: 拒绝
|
||||
判断是否接受 --> 接受: 接受
|
||||
|
||||
拒绝 --> 选择分配方式
|
||||
|
||||
接受 --> 更新状态为IN_PROGRESS
|
||||
更新状态为IN_PROGRESS --> 获取路径规划
|
||||
获取路径规划 --> 前往现场处理
|
||||
前往现场处理 --> 记录处理过程
|
||||
记录处理过程 --> 上传处理结果
|
||||
上传处理结果 --> 提交处理结果
|
||||
提交处理结果 --> 更新状态为SUBMITTED
|
||||
|
||||
更新状态为SUBMITTED --> 主管审核结果
|
||||
主管审核结果 --> 判断结果是否合格
|
||||
|
||||
判断结果是否合格 --> 不合格: 不合格
|
||||
判断结果是否合格 --> 合格: 合格
|
||||
|
||||
不合格 --> 填写原因要求重新处理
|
||||
填写原因要求重新处理 --> 获取路径规划
|
||||
|
||||
合格 --> 确认任务完成
|
||||
确认任务完成 --> 更新任务状态为APPROVED
|
||||
更新任务状态为APPROVED --> 更新反馈状态为CLOSED
|
||||
更新反馈状态为CLOSED --> 通知反馈提交者
|
||||
通知反馈提交者 --> 更新统计数据
|
||||
更新统计数据 --> [*]
|
||||
```
|
||||
|
||||
### 2.4 系统可行性分析
|
||||
|
||||
#### 2.4.1 技术可行性
|
||||
|
||||
本系统的技术实现是可行的,主要基于以下分析:
|
||||
|
||||
1. **前端技术**:市场上已有成熟的前端框架和组件库,可以快速开发出美观、响应式的Web应用,满足不同设备的访问需求。
|
||||
|
||||
2. **后端技术**:现有的后端框架具备高性能、高并发处理能力,能够满足系统的稳定性和扩展性需求。
|
||||
|
||||
3. **地图服务**:可以集成成熟的地图API,实现地理位置标记、路径规划等功能,无需从零开发。
|
||||
|
||||
4. **AI技术**:可以利用现有的自然语言处理和图像识别技术,实现对反馈内容的智能分析和审核。
|
||||
|
||||
5. **数据存储**:可采用多种数据存储方案,根据系统规模和性能需求灵活选择。
|
||||
|
||||
#### 2.4.2 经济可行性
|
||||
|
||||
从经济角度看,本系统的开发和运营是可行的:
|
||||
|
||||
1. **开发成本**:可以采用主流开源框架和技术栈,降低开发成本和技术门槛。
|
||||
|
||||
2. **维护成本**:通过模块化设计和完善的文档,可以降低后期维护和升级成本。
|
||||
|
||||
3. **投资回报**:
|
||||
- 提高环境问题处理效率,减少人力资源浪费
|
||||
- 降低环境问题带来的经济损失
|
||||
- 提升城市环境质量,间接促进经济发展
|
||||
- 长期来看具有良好的投资回报
|
||||
|
||||
4. **社会效益**:改善城市环境质量,提升居民生活满意度,产生显著的社会效益。
|
||||
|
||||
#### 2.4.3 操作可行性
|
||||
|
||||
从操作角度看,本系统具有良好的可行性:
|
||||
|
||||
1. **用户接受度**:
|
||||
- 系统界面设计简洁直观,符合用户习惯
|
||||
- 操作流程简化,降低学习成本
|
||||
- 移动端支持,满足随时随地使用需求
|
||||
|
||||
2. **培训需求**:系统操作简单,只需简单培训即可上手,降低推广和应用门槛。
|
||||
|
||||
3. **业务适应性**:系统流程设计符合环境问题处理的实际业务需求,能够无缝融入现有工作流程。
|
||||
|
||||
4. **组织支持**:系统实施需要相关部门的协调配合,但总体上不会对现有组织架构产生颠覆性影响。
|
||||
|
||||
#### 2.4.4 法律可行性
|
||||
|
||||
从法律合规角度看,本系统的实施不存在重大障碍:
|
||||
|
||||
1. **数据隐私**:系统设计符合数据保护法规要求,对用户隐私数据进行加密存储和严格权限控制。
|
||||
|
||||
2. **知识产权**:系统开发过程中使用的第三方库和组件均可采用开源或获得授权的方式,避免知识产权风险。
|
||||
|
||||
3. **合规性**:系统功能和流程设计可以确保符合相关法律法规和行业标准,确保合法合规运营。
|
||||
|
||||
## 3. 功能性需求
|
||||
|
||||
### 3.1 功能层次方框图
|
||||
|
||||
以下功能层次图展示了系统的整体功能架构:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
%% 用户交互层
|
||||
subgraph "用户交互层"
|
||||
direction LR
|
||||
C["公众服务模块\n(问题上报)"]
|
||||
H["个人中心模块\n(我的反馈/资料)"]
|
||||
D["管理驾驶舱\n(数据决策)"]
|
||||
end
|
||||
|
||||
%% 核心业务层
|
||||
subgraph "核心业务层"
|
||||
direction LR
|
||||
AI["AI分析模块\n(内容审核)"]
|
||||
E["任务管理模块\n(分配、流转、执行)"]
|
||||
end
|
||||
|
||||
%% 应用支撑层
|
||||
subgraph "应用支撑层"
|
||||
direction LR
|
||||
F["网格与地图模块\n(LBS & 寻路)"]
|
||||
I["文件服务模块\n(附件存取)"]
|
||||
end
|
||||
|
||||
%% 基础服务层
|
||||
subgraph "基础服务层"
|
||||
direction LR
|
||||
B["用户与认证模块"]
|
||||
G["系统管理模块\n(用户/权限)"]
|
||||
J["日志审计模块"]
|
||||
end
|
||||
|
||||
%% 定义关系
|
||||
C -- "提交反馈" --> AI
|
||||
AI -- "分析结果" --> E
|
||||
C -- "附件" --> I
|
||||
E -- "调用" --> F
|
||||
E -- "任务附件" --> I
|
||||
E -- "统计数据" --> D
|
||||
|
||||
H -- "查询个人数据" --> E
|
||||
|
||||
%% 基础服务支撑所有上层模块 (关系隐含)
|
||||
G -- "管理" --> B
|
||||
|
||||
classDef userLayer fill:#d4f1f9,stroke:#05a8e5;
|
||||
classDef coreLayer fill:#ffe6cc,stroke:#f7a128;
|
||||
classDef appSupportLayer fill:#d5e8d4,stroke:#82b366;
|
||||
classDef baseLayer fill:#e1d5e7,stroke:#9673a6;
|
||||
|
||||
class C,H,D userLayer;
|
||||
class AI,E coreLayer;
|
||||
class F,I appSupportLayer;
|
||||
class B,G,J baseLayer;
|
||||
```
|
||||
@@ -1,148 +0,0 @@
|
||||
# 需求定义文档(续)
|
||||
|
||||
### 6.4 可靠性需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| RELI-01 | 系统可用性 | 系统应保证7x24小时的稳定运行,计划内维护时间除外,系统可用性应达到99.5%以上。 | 高 |
|
||||
| RELI-02 | 数据备份 | 系统应定期(至少每日一次)对全部业务数据进行备份,并支持数据恢复。 | 高 |
|
||||
| RELI-03 | 故障恢复 | 系统应具备故障检测和自动恢复机制,在出现异常情况时能够快速恢复正常运行。 | 中 |
|
||||
| RELI-04 | 数据一致性 | 系统应确保在各种操作条件下(包括并发访问和异常中断)保持数据的一致性和完整性。 | 高 |
|
||||
| RELI-05 | 容错能力 | 系统应能够处理常见的错误情况(如网络中断、数据异常),并提供适当的降级服务。 | 中 |
|
||||
|
||||
### 6.5 可维护性需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| MAIN-01 | 模块化设计 | 系统应采用模块化设计,各功能模块之间松耦合,便于独立开发、测试和维护。 | 中 |
|
||||
| MAIN-02 | 配置管理 | 系统应支持通过配置文件或管理界面调整系统参数,无需修改代码和重新部署。 | 中 |
|
||||
| MAIN-03 | 日志记录 | 系统应记录详细的运行日志,包括错误信息、性能指标和关键操作,便于问题诊断。 | 高 |
|
||||
| MAIN-04 | 版本升级 | 系统应支持平滑的版本升级机制,最小化升级对用户的影响。 | 低 |
|
||||
| MAIN-05 | 代码规范 | 系统开发应遵循统一的编码规范和设计模式,提高代码可读性和可维护性。 | 中 |
|
||||
|
||||
### 6.6 可扩展性需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| SCAL-01 | 水平扩展 | 系统架构应支持通过增加服务器节点进行水平扩展,以应对用户量和数据量的增长。 | 低 |
|
||||
| SCAL-02 | 功能扩展 | 系统应支持在不影响现有功能的情况下,添加新的功能模块和业务流程。 | 中 |
|
||||
| SCAL-03 | 接口开放 | 系统应提供标准化的API接口,便于与其他系统集成和数据交换。 | 中 |
|
||||
| SCAL-04 | 多租户支持 | 系统应具备支持多租户(如不同城市或区域)的潜力,能够在未来进行扩展。 | 低 |
|
||||
| SCAL-05 | 数据量增长 | 系统应能够处理数据量的持续增长,性能不应随着数据量的增加而明显下降。 | 中 |
|
||||
|
||||
## 7. 数据需求
|
||||
|
||||
### 7.1 数据实体
|
||||
|
||||
系统需要管理以下核心数据实体:
|
||||
|
||||
1. **用户账户 (UserAccount)**:存储系统用户的基本信息、认证信息和角色权限。
|
||||
2. **反馈 (Feedback)**:存储公众提交的环境问题反馈,包括描述、位置、图片等信息。
|
||||
3. **任务 (Task)**:存储从反馈生成的工作任务,包括任务详情、状态和处理记录。
|
||||
4. **网格 (Grid)**:存储城市区域的网格化管理数据,包括网格坐标、属性和责任人。
|
||||
5. **任务分配 (Assignment)**:存储任务与网格员之间的分配关系,包括分配时间、状态等。
|
||||
6. **附件 (Attachment)**:存储反馈和任务相关的图片、文档等附件文件。
|
||||
7. **操作日志 (OperationLog)**:存储系统中的关键操作记录,用于审计和问题追溯。
|
||||
|
||||
### 7.2 数据量估计
|
||||
|
||||
基于系统预期使用规模,估计以下数据量:
|
||||
|
||||
1. **用户账户**:预计1000个用户账户,包括公众用户、网格员、主管、管理员和决策者。
|
||||
2. **反馈**:预计每日100-200条新增反馈,年增长约5万条。
|
||||
3. **任务**:预计每日50-100个新增任务,年增长约2.5万个。
|
||||
4. **网格**:预计1000-5000个网格单元,根据城市规模和网格粒度而定。
|
||||
5. **附件**:预计每条反馈平均2张图片,每个任务平均2张图片,年增长约15万个文件。
|
||||
6. **操作日志**:预计每日1万条日志记录,主要用于短期审计,长期可归档。
|
||||
|
||||
### 7.3 数据保留策略
|
||||
|
||||
1. **核心业务数据**(用户、反馈、任务、网格):长期保留,至少保留3年。
|
||||
2. **附件文件**:保留1年,可根据存储容量考虑适当延长或缩短。
|
||||
3. **操作日志**:
|
||||
- 详细日志保留30天
|
||||
- 关键审计日志保留1年
|
||||
- 统计汇总数据长期保留
|
||||
|
||||
### 7.4 数据备份要求
|
||||
|
||||
1. **备份频率**:
|
||||
- 核心业务数据:每日全量备份,每小时增量备份
|
||||
- 附件文件:每周全量备份,每日增量备份
|
||||
- 配置数据:每次变更后备份
|
||||
|
||||
2. **备份保留**:
|
||||
- 每日备份保留7天
|
||||
- 每周备份保留1个月
|
||||
- 每月备份保留6个月
|
||||
- 每年备份永久保留
|
||||
|
||||
3. **恢复能力**:系统应支持将数据恢复到任意备份点,恢复时间目标(RTO)不超过4小时。
|
||||
|
||||
## 8. 结论
|
||||
|
||||
### 8.1 需求优先级总结
|
||||
|
||||
基于业务重要性和实现复杂度,系统需求按以下优先级排序:
|
||||
|
||||
1. **最高优先级**:
|
||||
- 用户认证和权限控制
|
||||
- 反馈提交和审核
|
||||
- 任务创建和分配
|
||||
- 数据安全和完整性
|
||||
|
||||
2. **高优先级**:
|
||||
- 任务执行和结果审核
|
||||
- 地图标记和路径规划
|
||||
- 系统性能和可用性
|
||||
- 用户界面和体验
|
||||
|
||||
3. **中等优先级**:
|
||||
- AI内容审核
|
||||
- 决策支持和数据分析
|
||||
- 通知和提醒功能
|
||||
- 系统可维护性
|
||||
|
||||
4. **低优先级**:
|
||||
- 高级统计和报表
|
||||
- 个性化配置
|
||||
- 系统扩展性
|
||||
- 辅助功能和优化
|
||||
|
||||
### 8.2 实施建议
|
||||
|
||||
为确保系统成功实施,建议采取以下策略:
|
||||
|
||||
1. **分阶段实施**:
|
||||
- 第一阶段:核心功能(用户管理、反馈、任务)
|
||||
- 第二阶段:支撑功能(地图、AI审核)
|
||||
- 第三阶段:高级功能(决策支持、报表)
|
||||
|
||||
2. **持续迭代**:采用敏捷开发方法,快速交付可用版本,根据用户反馈持续改进。
|
||||
|
||||
3. **用户参与**:在开发过程中邀请各类用户参与测试和评估,确保系统满足实际需求。
|
||||
|
||||
4. **技术选型**:选择成熟稳定的技术栈,平衡创新性和可靠性,降低开发和维护风险。
|
||||
|
||||
5. **数据治理**:建立完善的数据管理和治理机制,确保数据质量和安全。
|
||||
|
||||
### 8.3 预期效益
|
||||
|
||||
成功实施环境监测系统预期将带来以下效益:
|
||||
|
||||
1. **业务效益**:
|
||||
- 环境问题处理效率提升50%以上
|
||||
- 问题解决质量显著提高
|
||||
- 资源利用更加合理高效
|
||||
|
||||
2. **管理效益**:
|
||||
- 实现环境问题全流程可视化管理
|
||||
- 提供科学决策的数据支持
|
||||
- 优化工作流程和资源配置
|
||||
|
||||
3. **社会效益**:
|
||||
- 提升公众参与环境治理的积极性
|
||||
- 增强政府工作透明度和公信力
|
||||
- 改善城市环境质量和居民生活满意度
|
||||
|
||||
通过环境监测系统的建设和应用,将有效解决当前环境问题管理中的痛点,构建起连接公众、管理部门和执行人员的桥梁,实现环境问题的快速发现、高效处理和全程监督,为城市环境治理提供有力支撑。
|
||||
@@ -1,147 +0,0 @@
|
||||
# 需求定义文档(续)
|
||||
|
||||
### 5.3 任务管理模块需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| TASK-01 | 任务创建 | 系统应支持从审核通过的反馈自动生成任务,也支持主管手动创建临时任务。 | 高 |
|
||||
| TASK-02 | 智能分配 | 系统应基于多因素(网格员位置、当前负载、专业技能、历史表现)推荐最合适的处理人员。 | 中 |
|
||||
| TASK-03 | 任务分配 | 系统应支持主管手动选择或确认系统推荐的网格员,并将任务分配给他们。 | 高 |
|
||||
| TASK-04 | 任务通知 | 系统应在任务分配后立即通知相关网格员,并提供任务详情查看途径。 | 高 |
|
||||
| TASK-05 | 任务执行跟踪 | 系统应记录任务的每个状态变更,支持网格员实时上报处理进度。 | 中 |
|
||||
| TASK-06 | 路径规划 | 系统应为网格员提供从当前位置到任务地点的最优路径规划。 | 中 |
|
||||
| TASK-07 | 结果提交 | 系统应支持网格员提交处理结果,包括文字描述和图片证明。 | 高 |
|
||||
| TASK-08 | 结果审核 | 系统应支持主管审核网格员提交的处理结果,可以通过或驳回并提供反馈。 | 高 |
|
||||
| TASK-09 | 任务查询 | 系统应支持按多种条件(状态、负责人、时间、区域等)查询和筛选任务列表。 | 中 |
|
||||
| TASK-10 | 任务统计 | 系统应生成任务数据的统计分析,包括完成率、平均处理时长等绩效指标。 | 低 |
|
||||
| TASK-11 | 任务看板 | 系统应提供直观的任务看板,展示不同状态任务的数量和分布。 | 低 |
|
||||
|
||||
**任务管理流程图**:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[反馈通过审核] --> B[自动创建任务]
|
||||
C[主管手动创建任务] --> D[任务创建完成]
|
||||
B --> D
|
||||
D --> E{选择分配方式}
|
||||
E -- 手动分配 --> F[主管选择网格员]
|
||||
E -- 智能推荐 --> G[系统推荐最佳人选]
|
||||
G --> F
|
||||
F --> H[分配任务给网格员]
|
||||
H --> I[通知网格员]
|
||||
I --> J{网格员接受?}
|
||||
J -- 否 --> E
|
||||
J -- 是 --> K[更新任务状态为进行中]
|
||||
K --> L[网格员获取路径规划]
|
||||
L --> M[网格员处理任务]
|
||||
M --> N[提交处理结果]
|
||||
N --> O[主管审核结果]
|
||||
O --> P{结果合格?}
|
||||
P -- 否 --> Q[填写原因]
|
||||
Q --> L
|
||||
P -- 是 --> R[更新任务状态为已完成]
|
||||
R --> S[通知反馈提交者]
|
||||
S --> T[更新统计数据]
|
||||
```
|
||||
|
||||
### 5.4 网格与地图模块需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| GRID-01 | 网格定义 | 系统应支持管理员定义和维护城市网格系统,包括网格的坐标、属性和责任人分配。 | 中 |
|
||||
| GRID-02 | 地图可视化 | 系统应在地图上直观展示反馈点、任务分布和网格员位置,支持多种筛选条件和图层切换。 | 中 |
|
||||
| GRID-03 | 位置标记 | 系统应支持用户在地图上精确标记环境问题位置,并自动关联到对应网格。 | 高 |
|
||||
| GRID-04 | A*寻路算法 | 系统应基于网格系统和实时路况,为网格员提供从当前位置到任务地点的最优路径规划。 | 中 |
|
||||
| GRID-05 | 区域统计 | 系统应基于网格系统,生成环境问题热力图,识别高发区域和问题类型分布。 | 低 |
|
||||
| GRID-06 | 网格查询 | 系统应支持查询特定区域内的网格定义、属性和历史问题记录。 | 低 |
|
||||
| GRID-07 | 离线地图 | 系统应支持地图数据的离线缓存,保证在网络不稳定情况下的基本功能。 | 低 |
|
||||
|
||||
**网格与地图流程图**:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[管理员定义网格系统] --> B[划分城市区域为网格单元]
|
||||
B --> C[设置网格属性]
|
||||
C --> D[分配网格责任人]
|
||||
|
||||
E[用户标记环境问题位置] --> F[系统关联到对应网格]
|
||||
F --> G[存储地理位置信息]
|
||||
|
||||
H[网格员接收任务] --> I[查看任务位置]
|
||||
I --> J[请求路径规划]
|
||||
J --> K[A*算法计算最优路径]
|
||||
K --> L[展示导航路线]
|
||||
|
||||
M[管理员查看统计数据] --> N[生成环境问题热力图]
|
||||
N --> O[识别问题高发区域]
|
||||
O --> P[调整资源分配策略]
|
||||
```
|
||||
|
||||
### 5.5 决策支持模块需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| DECI-01 | 核心指标看板 | 系统应实时展示关键业务指标,如待处理反馈数、进行中任务数、平均处理时长、按时完成率等。 | 中 |
|
||||
| DECI-02 | 多维度分析 | 系统应支持按时间、区域、污染类型、处理人等多个维度对数据进行交叉分析和趋势展示。 | 中 |
|
||||
| DECI-03 | 热力图可视化 | 系统应在地图上以热力图形式展示环境问题的分布密度,直观识别高发区域。 | 中 |
|
||||
| DECI-04 | 绩效评估 | 系统应对网格员和区域的工作效率、问题解决质量等进行量化评估,生成排名和对比分析。 | 低 |
|
||||
| DECI-05 | 预警机制 | 系统应基于历史数据和趋势分析,对可能出现的环境风险提前预警。 | 低 |
|
||||
| DECI-06 | 报表导出 | 系统应支持将分析结果导出为多种格式(PDF、Excel等),便于进一步分析和汇报。 | 低 |
|
||||
| DECI-07 | 个性化配置 | 系统应支持决策者个性化配置数据看板,满足不同管理者的关注点。 | 低 |
|
||||
|
||||
**决策支持流程图**:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[系统收集业务数据] --> B[实时计算核心指标]
|
||||
B --> C[展示核心指标看板]
|
||||
|
||||
D[决策者选择分析维度] --> E[系统执行多维度分析]
|
||||
E --> F[生成趋势图表]
|
||||
|
||||
G[系统分析地理数据] --> H[生成环境问题热力图]
|
||||
H --> I[标识高发区域]
|
||||
|
||||
J[系统收集网格员工作数据] --> K[计算绩效指标]
|
||||
K --> L[生成绩效排名]
|
||||
|
||||
M[系统分析历史数据] --> N[识别异常趋势]
|
||||
N --> O{是否达到预警阈值?}
|
||||
O -- 是 --> P[触发预警通知]
|
||||
O -- 否 --> Q[继续监控]
|
||||
|
||||
R[决策者查看分析结果] --> S[选择导出格式]
|
||||
S --> T[导出分析报表]
|
||||
```
|
||||
|
||||
## 6. 非功能性需求
|
||||
|
||||
### 6.1 性能需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| PERF-01 | 响应时间 | 系统的页面加载时间应不超过3秒,API响应时间应不超过500毫秒(不包括文件上传下载)。 | 高 |
|
||||
| PERF-02 | 并发用户 | 系统应能同时支持至少100个并发用户正常操作,不出现明显延迟。 | 中 |
|
||||
| PERF-03 | 数据处理量 | 系统应能处理每日至少1000条反馈和500个任务的创建、更新和查询操作。 | 中 |
|
||||
| PERF-04 | 文件处理 | 系统应支持单个文件最大10MB,总附件大小不超过50MB的上传和处理。 | 中 |
|
||||
| PERF-05 | 地图渲染 | 地图界面应能在1秒内完成初始加载,并在500毫秒内响应用户的缩放和平移操作。 | 中 |
|
||||
|
||||
### 6.2 可用性需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| USAB-01 | 界面一致性 | 系统界面应保持风格一致,包括颜色方案、按钮位置、导航结构等,减少用户学习成本。 | 中 |
|
||||
| USAB-02 | 错误处理 | 系统应提供清晰的错误提示和恢复建议,避免用户操作中断。 | 高 |
|
||||
| USAB-03 | 帮助系统 | 系统应提供上下文相关的帮助信息和操作指南,支持用户自助解决问题。 | 低 |
|
||||
| USAB-04 | 响应式设计 | 系统界面应适应不同设备(PC、平板、手机)的屏幕尺寸,提供一致的用户体验。 | 高 |
|
||||
| USAB-05 | 操作简化 | 核心功能的操作路径应尽量简化,减少用户点击次数和输入量。 | 中 |
|
||||
|
||||
### 6.3 安全性需求
|
||||
|
||||
| 需求ID | 需求名称 | 需求描述 | 优先级 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| SECU-01 | 数据加密 | 敏感数据(如用户密码)必须加密存储,传输过程中应使用HTTPS加密。 | 高 |
|
||||
| SECU-02 | 访问控制 | 系统应实施严格的基于角色的访问控制,确保用户只能访问其权限范围内的数据和功能。 | 高 |
|
||||
| SECU-03 | 输入验证 | 系统应对所有用户输入进行验证和过滤,防止SQL注入、XSS等常见安全攻击。 | 高 |
|
||||
| SECU-04 | 会话管理 | 系统应安全管理用户会话,包括会话创建、验证、超时和销毁,防止会话劫持。 | 中 |
|
||||
| SECU-05 | 审计日志 | 系统应记录所有关键操作的审计日志,包括用户登录、数据修改、权限变更等。 | 中 |
|
||||
2
ems-backend/.gitattributes
vendored
2
ems-backend/.gitattributes
vendored
@@ -1,2 +0,0 @@
|
||||
/mvnw text eol=lf
|
||||
*.cmd text eol=crlf
|
||||
33
ems-backend/.gitignore
vendored
33
ems-backend/.gitignore
vendored
@@ -1,33 +0,0 @@
|
||||
HELP.md
|
||||
target/
|
||||
.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
Binary file not shown.
@@ -1,54 +0,0 @@
|
||||
# EMS后端项目概览
|
||||
|
||||
## 项目简介
|
||||
EMS (Environmental Monitoring System) 后端是一个基于Spring Boot 3.5.0的环境监测管理系统后端服务,使用Java 17开发。该系统采用自定义JSON文件存储方案,不依赖传统关系型数据库。
|
||||
|
||||
## 技术栈
|
||||
- **框架**: Spring Boot 3.5.0
|
||||
- **Java版本**: Java 17
|
||||
- **构建工具**: Maven
|
||||
- **数据存储**: 自定义JSON文件存储
|
||||
- **安全认证**: Spring Security + JWT
|
||||
- **API文档**: Swagger UI (SpringDoc OpenAPI)
|
||||
- **邮件服务**: Spring Mail (163 SMTP)
|
||||
- **异步处理**: Spring Async
|
||||
- **WebSocket**: Spring WebSocket
|
||||
- **工具库**: Lombok, Google Guava
|
||||
|
||||
## 核心特性
|
||||
1. **无数据库设计**: 使用JSON文件作为数据持久化方案
|
||||
2. **JWT认证**: 基于Token的无状态认证
|
||||
3. **异步处理**: 支持异步任务执行
|
||||
4. **事件驱动**: 使用Spring Events进行组件解耦
|
||||
5. **AI集成**: 集成火山引擎AI服务
|
||||
6. **文件上传**: 支持文件上传和管理
|
||||
7. **邮件通知**: 集成邮件发送功能
|
||||
8. **实时通信**: WebSocket支持
|
||||
|
||||
## 项目结构
|
||||
```
|
||||
src/main/java/com/dne/ems/
|
||||
├── config/ # 配置类
|
||||
├── controller/ # REST控制器
|
||||
├── dto/ # 数据传输对象
|
||||
├── event/ # 事件定义
|
||||
├── exception/ # 异常处理
|
||||
├── listener/ # 事件监听器
|
||||
├── model/ # 数据模型
|
||||
├── repository/ # 数据访问层
|
||||
├── security/ # 安全配置
|
||||
├── service/ # 业务逻辑层
|
||||
└── validation/ # 数据验证
|
||||
```
|
||||
|
||||
## 数据存储文件
|
||||
- `users.json` - 用户数据
|
||||
- `feedbacks.json` - 反馈数据
|
||||
- `tasks.json` - 任务数据
|
||||
- `grids.json` - 网格数据
|
||||
- `assignments.json` - 分配记录
|
||||
- `aqi_records.json` - 空气质量数据
|
||||
- `operation_logs.json` - 操作日志
|
||||
- `attachments.json` - 附件信息
|
||||
- `map_grids.json` - 地图网格数据
|
||||
- `pollutant_thresholds.json` - 污染物阈值
|
||||
@@ -1,193 +0,0 @@
|
||||
# EMS后端业务逻辑与核心功能
|
||||
|
||||
## 核心业务模块
|
||||
|
||||
### 1. 用户管理模块
|
||||
**控制器**: `AuthController`, `PersonnelController`, `ProfileController`
|
||||
**核心功能**:
|
||||
- 用户注册、登录、注销
|
||||
- JWT Token生成和验证
|
||||
- 密码重置(邮件验证码)
|
||||
- 用户信息管理
|
||||
- 角色权限控制
|
||||
|
||||
**用户角色**:
|
||||
- `ADMIN`: 系统管理员
|
||||
- `SUPERVISOR`: 主管
|
||||
- `GRID_WORKER`: 网格员
|
||||
- `PUBLIC`: 公众用户
|
||||
|
||||
### 2. 反馈管理模块
|
||||
**控制器**: `FeedbackController`, `PublicController`
|
||||
**核心功能**:
|
||||
- 公众反馈提交
|
||||
- 反馈审核和处理
|
||||
- AI智能审核集成
|
||||
- 反馈状态跟踪
|
||||
- 反馈统计分析
|
||||
|
||||
**反馈状态流程**:
|
||||
```
|
||||
PENDING → AI_REVIEWING → APPROVED/REJECTED → TASK_CREATED
|
||||
```
|
||||
|
||||
### 3. 任务管理模块
|
||||
**控制器**: `TaskManagementController`, `TaskAssignmentController`, `GridWorkerTaskController`, `SupervisorController`
|
||||
**核心功能**:
|
||||
- 任务创建和分配
|
||||
- 任务执行跟踪
|
||||
- 任务审核和验收
|
||||
- 任务统计报告
|
||||
- 自动任务分配算法
|
||||
|
||||
**任务状态流程**:
|
||||
```
|
||||
CREATED → ASSIGNED → IN_PROGRESS → SUBMITTED → APPROVED/REJECTED
|
||||
```
|
||||
|
||||
### 4. 网格管理模块
|
||||
**控制器**: `GridController`, `MapController`
|
||||
**核心功能**:
|
||||
- 网格区域划分
|
||||
- 网格员分配
|
||||
- 网格覆盖率统计
|
||||
- 地图可视化
|
||||
- 路径规划算法
|
||||
|
||||
### 5. 数据分析模块
|
||||
**控制器**: `DashboardController`
|
||||
**核心功能**:
|
||||
- 实时数据统计
|
||||
- 趋势分析
|
||||
- 热力图生成
|
||||
- AQI数据处理
|
||||
- 污染物阈值监控
|
||||
|
||||
### 6. 文件管理模块
|
||||
**控制器**: `FileController`
|
||||
**核心功能**:
|
||||
- 文件上传和下载
|
||||
- 图片处理
|
||||
- 附件管理
|
||||
- 文件安全检查
|
||||
|
||||
## 数据模型设计
|
||||
|
||||
### 核心实体
|
||||
1. **User**: 用户信息
|
||||
- 基本信息:姓名、邮箱、电话
|
||||
- 认证信息:密码、角色
|
||||
- 位置信息:经纬度
|
||||
|
||||
2. **Feedback**: 反馈信息
|
||||
- 内容:标题、描述、类型
|
||||
- 状态:处理状态、优先级
|
||||
- 位置:经纬度、地址
|
||||
- 附件:图片、文件
|
||||
|
||||
3. **Task**: 任务信息
|
||||
- 基本信息:标题、描述、类型
|
||||
- 分配信息:分配人、执行人
|
||||
- 时间信息:创建时间、截止时间
|
||||
- 状态:任务状态、完成度
|
||||
|
||||
4. **Grid**: 网格信息
|
||||
- 区域信息:边界坐标、面积
|
||||
- 分配信息:负责人、覆盖状态
|
||||
- 统计信息:任务数量、完成率
|
||||
|
||||
5. **Assignment**: 分配记录
|
||||
- 分配信息:任务ID、用户ID
|
||||
- 时间信息:分配时间、完成时间
|
||||
- 状态:分配状态、完成状态
|
||||
|
||||
## 业务规则
|
||||
|
||||
### 权限控制规则
|
||||
1. **ADMIN**: 全系统权限
|
||||
2. **SUPERVISOR**: 管理网格员,审核任务
|
||||
3. **GRID_WORKER**: 执行分配的任务
|
||||
4. **PUBLIC**: 仅能提交反馈
|
||||
|
||||
### 任务分配规则
|
||||
1. 基于网格区域自动分配
|
||||
2. 考虑网格员工作负载
|
||||
3. 紧急任务优先分配
|
||||
4. 支持手动重新分配
|
||||
|
||||
### 反馈处理规则
|
||||
1. AI预审核筛选
|
||||
2. 重复反馈合并
|
||||
3. 紧急反馈优先处理
|
||||
4. 自动生成处理任务
|
||||
|
||||
## 集成服务
|
||||
|
||||
### AI服务集成
|
||||
**服务**: 火山引擎AI
|
||||
**功能**:
|
||||
- 反馈内容智能分析
|
||||
- 自动分类和优先级评估
|
||||
- 处理建议生成
|
||||
|
||||
### 邮件服务
|
||||
**服务**: 163 SMTP
|
||||
**功能**:
|
||||
- 密码重置邮件
|
||||
- 任务通知邮件
|
||||
- 系统通知邮件
|
||||
|
||||
### 文件存储
|
||||
**方案**: 本地文件系统
|
||||
**目录**: `./uploads/`
|
||||
**支持格式**: 图片、文档
|
||||
|
||||
## 事件驱动架构
|
||||
|
||||
### 核心事件
|
||||
1. **FeedbackSubmittedForAiReviewEvent**: 反馈提交AI审核
|
||||
2. **TaskReadyForAssignmentEvent**: 任务准备分配
|
||||
3. **AuthenticationSuccessEvent**: 登录成功
|
||||
4. **AuthenticationFailureEvent**: 登录失败
|
||||
|
||||
### 事件处理
|
||||
- 异步事件处理
|
||||
- 事件监听器解耦
|
||||
- 支持事件重试机制
|
||||
|
||||
## 性能优化策略
|
||||
|
||||
### 缓存策略
|
||||
1. 用户信息缓存
|
||||
2. 网格数据缓存
|
||||
3. 统计数据缓存
|
||||
4. 配置信息缓存
|
||||
|
||||
### 异步处理
|
||||
1. AI审核异步化
|
||||
2. 邮件发送异步化
|
||||
3. 文件处理异步化
|
||||
4. 统计计算异步化
|
||||
|
||||
### 数据优化
|
||||
1. JSON文件分片存储
|
||||
2. 索引优化
|
||||
3. 分页查询
|
||||
4. 数据压缩
|
||||
|
||||
## 监控和日志
|
||||
|
||||
### 操作日志
|
||||
- 用户操作记录
|
||||
- 系统关键操作
|
||||
- 异常操作告警
|
||||
|
||||
### 性能监控
|
||||
- API响应时间
|
||||
- 系统资源使用
|
||||
- 错误率统计
|
||||
|
||||
### 业务监控
|
||||
- 反馈处理效率
|
||||
- 任务完成率
|
||||
- 用户活跃度
|
||||
@@ -1,142 +0,0 @@
|
||||
# EMS后端代码风格与架构设计
|
||||
|
||||
## 代码风格规范
|
||||
|
||||
### Java编码规范
|
||||
1. **包命名**: 使用`com.dne.ems`作为根包
|
||||
2. **类命名**: 使用PascalCase,如`AuthController`、`UserService`
|
||||
3. **方法命名**: 使用camelCase,如`getUserById`、`createTask`
|
||||
4. **常量命名**: 使用UPPER_SNAKE_CASE
|
||||
5. **变量命名**: 使用camelCase
|
||||
|
||||
### 注解使用
|
||||
- **Lombok**: 广泛使用`@Data`、`@Builder`、`@NoArgsConstructor`等
|
||||
- **Spring**: 使用`@RestController`、`@Service`、`@Repository`等
|
||||
- **验证**: 使用`@Valid`、`@NotNull`、`@Size`等JSR-303注解
|
||||
- **文档**: 使用Javadoc注释,特别是公共API
|
||||
|
||||
### 文件组织
|
||||
```
|
||||
com.dne.ems/
|
||||
├── config/ # 配置类,如WebConfig、SecurityConfig
|
||||
├── controller/ # REST控制器,处理HTTP请求
|
||||
├── dto/ # 数据传输对象,用于API交互
|
||||
├── event/ # 事件定义,用于解耦组件
|
||||
├── exception/ # 自定义异常和全局异常处理
|
||||
├── listener/ # 事件监听器
|
||||
├── model/ # 数据模型和实体类
|
||||
├── repository/ # 数据访问层,JSON文件操作
|
||||
├── security/ # 安全相关配置和工具
|
||||
├── service/ # 业务逻辑层
|
||||
└── validation/ # 自定义验证器
|
||||
```
|
||||
|
||||
## 架构设计原则
|
||||
|
||||
### 分层架构
|
||||
1. **Controller层**: 处理HTTP请求,参数验证,调用Service
|
||||
2. **Service层**: 业务逻辑处理,事务管理
|
||||
3. **Repository层**: 数据访问,JSON文件操作
|
||||
4. **Model层**: 数据模型定义
|
||||
|
||||
### 设计模式
|
||||
1. **依赖注入**: 使用Spring的IoC容器
|
||||
2. **事件驱动**: 使用Spring Events解耦组件
|
||||
3. **Builder模式**: 使用Lombok的@Builder
|
||||
4. **策略模式**: 在业务逻辑中使用
|
||||
|
||||
### JSON数据存储设计
|
||||
- 每个实体对应一个JSON文件
|
||||
- 使用Repository模式封装文件操作
|
||||
- 实现类似JPA的CRUD操作
|
||||
- 支持分页和排序
|
||||
|
||||
## 安全设计
|
||||
|
||||
### JWT认证
|
||||
- 使用JWT Token进行无状态认证
|
||||
- Token包含用户ID、角色等信息
|
||||
- 设置合理的过期时间
|
||||
|
||||
### 权限控制
|
||||
- 基于角色的访问控制(RBAC)
|
||||
- 使用Spring Security的方法级安全
|
||||
- 支持多种用户角色:ADMIN、SUPERVISOR、GRID_WORKER、PUBLIC
|
||||
|
||||
## 异常处理
|
||||
|
||||
### 全局异常处理
|
||||
- 使用`@ControllerAdvice`统一处理异常
|
||||
- 返回标准化的错误响应格式
|
||||
- 记录详细的错误日志
|
||||
|
||||
### 自定义异常
|
||||
- `ResourceNotFoundException`: 资源未找到
|
||||
- `InvalidOperationException`: 非法操作
|
||||
- `UserAlreadyExistsException`: 用户已存在
|
||||
- `FileStorageException`: 文件存储异常
|
||||
|
||||
## API设计规范
|
||||
|
||||
### RESTful设计
|
||||
- 使用标准HTTP方法:GET、POST、PUT、DELETE
|
||||
- 资源命名使用复数形式
|
||||
- 使用HTTP状态码表示操作结果
|
||||
|
||||
### 响应格式
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {},
|
||||
"message": "操作成功",
|
||||
"timestamp": "2025-01-XX"
|
||||
}
|
||||
```
|
||||
|
||||
### 分页响应
|
||||
```json
|
||||
{
|
||||
"content": [],
|
||||
"totalElements": 100,
|
||||
"totalPages": 10,
|
||||
"size": 10,
|
||||
"number": 0
|
||||
}
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 缓存策略
|
||||
- 使用Google Guava进行内存缓存
|
||||
- 缓存频繁访问的数据
|
||||
- 设置合理的缓存过期时间
|
||||
|
||||
### 异步处理
|
||||
- 使用`@Async`注解处理耗时操作
|
||||
- 配置线程池参数
|
||||
- 事件处理异步化
|
||||
|
||||
## 日志规范
|
||||
|
||||
### 日志级别
|
||||
- ERROR: 系统错误,需要立即处理
|
||||
- WARN: 警告信息,可能的问题
|
||||
- INFO: 重要的业务流程信息
|
||||
- DEBUG: 调试信息,开发环境使用
|
||||
|
||||
### 日志内容
|
||||
- 包含请求ID便于追踪
|
||||
- 记录关键业务操作
|
||||
- 敏感信息脱敏处理
|
||||
|
||||
## 测试规范
|
||||
|
||||
### 单元测试
|
||||
- 使用JUnit 5
|
||||
- Service层测试覆盖率>80%
|
||||
- 使用Mockito进行依赖模拟
|
||||
|
||||
### 集成测试
|
||||
- 使用Spring Boot Test
|
||||
- 测试完整的API流程
|
||||
- 使用测试数据库或文件
|
||||
@@ -1,207 +0,0 @@
|
||||
# EMS后端控制器实现详解
|
||||
|
||||
## 控制器架构概览
|
||||
|
||||
基于之前的分析,现在补充实际的控制器实现细节。项目采用标准的Spring MVC架构,所有控制器都位于`com.dne.ems.controller`包下。
|
||||
|
||||
## 核心控制器实现
|
||||
|
||||
### 1. AuthController - 认证控制器
|
||||
|
||||
**位置**: `src/main/java/com/dne/ems/controller/AuthController.java`
|
||||
|
||||
**主要功能**:
|
||||
- 用户注册 (`/api/auth/signup`)
|
||||
- 用户登录 (`/api/auth/login`)
|
||||
- 用户登出 (`/api/auth/logout`)
|
||||
- 发送验证码 (`/api/auth/send-verification-code`)
|
||||
- 密码重置 (`/api/auth/reset-password-with-code`)
|
||||
|
||||
**关键特性**:
|
||||
```java
|
||||
@RestController
|
||||
@RequestMapping("/api/auth")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class AuthController {
|
||||
private final AuthService authService;
|
||||
private final VerificationCodeService verificationCodeService;
|
||||
private final OperationLogService operationLogService;
|
||||
}
|
||||
```
|
||||
|
||||
**API设计亮点**:
|
||||
- 使用`@Valid`进行请求参数验证
|
||||
- 支持JWT令牌认证响应
|
||||
- 提供新旧两套密码重置API(向后兼容)
|
||||
- 完整的JavaDoc文档
|
||||
|
||||
### 2. FeedbackController - 反馈管理控制器
|
||||
|
||||
**位置**: `src/main/java/com/dne/ems/controller/FeedbackController.java`
|
||||
|
||||
**主要功能**:
|
||||
- 反馈提交(支持JSON和multipart格式)
|
||||
- 反馈查询(支持多条件过滤和分页)
|
||||
- 反馈统计数据获取
|
||||
- 反馈处理和状态更新
|
||||
|
||||
**权限控制**:
|
||||
```java
|
||||
@PreAuthorize("isAuthenticated()") // 提交反馈
|
||||
@PreAuthorize("hasAnyRole('ADMIN', 'SUPERVISOR', 'DECISION_MAKER')") // 查看详情
|
||||
@PreAuthorize("hasAnyRole('ADMIN', 'SUPERVISOR')") // 处理反馈
|
||||
```
|
||||
|
||||
**高级查询支持**:
|
||||
- 状态过滤:PENDING_REVIEW/PROCESSED/REJECTED
|
||||
- 污染类型:AIR/WATER/SOIL/NOISE
|
||||
- 严重程度:LOW/MEDIUM/HIGH/CRITICAL
|
||||
- 地理位置:城市/区县
|
||||
- 时间范围:开始日期至结束日期
|
||||
- 关键词模糊匹配
|
||||
|
||||
**文件上传支持**:
|
||||
```java
|
||||
@PostMapping(value = "/submit", consumes = {"multipart/form-data"})
|
||||
public ResponseEntity<Feedback> submitFeedback(
|
||||
@Valid @RequestPart("feedback") FeedbackSubmissionRequest request,
|
||||
@RequestPart(value = "files", required = false) MultipartFile[] files,
|
||||
@AuthenticationPrincipal CustomUserDetails userDetails)
|
||||
```
|
||||
|
||||
### 3. TaskManagementController - 任务管理控制器
|
||||
|
||||
**位置**: `src/main/java/com/dne/ems/controller/TaskManagementController.java`
|
||||
|
||||
**主要功能**:
|
||||
- 任务创建与分配
|
||||
- 任务状态管理(审核、批准、拒绝、取消)
|
||||
- 从反馈创建任务
|
||||
- 任务查询与过滤
|
||||
|
||||
**权限设计**:
|
||||
```java
|
||||
@PreAuthorize("hasRole('SUPERVISOR')") // 类级别权限
|
||||
@PreAuthorize("hasAnyAuthority('ADMIN', 'SUPERVISOR', 'DECISION_MAKER')") // 查询权限
|
||||
@PreAuthorize("hasRole('ADMIN')") // 批准/拒绝权限
|
||||
```
|
||||
|
||||
**任务生命周期管理**:
|
||||
1. 创建任务 (`POST /api/management/tasks`)
|
||||
2. 分配任务 (`POST /{taskId}/assign`)
|
||||
3. 审核任务 (`POST /{taskId}/review`)
|
||||
4. 批准任务 (`POST /{taskId}/approve`)
|
||||
5. 拒绝任务 (`POST /{taskId}/reject`)
|
||||
6. 取消任务 (`POST /{taskId}/cancel`)
|
||||
|
||||
**从反馈创建任务**:
|
||||
```java
|
||||
@PostMapping("/feedback/{feedbackId}/create-task")
|
||||
@PreAuthorize("hasRole('SUPERVISOR')")
|
||||
public ResponseEntity<TaskDetailDTO> createTaskFromFeedback(
|
||||
@PathVariable Long feedbackId,
|
||||
@RequestBody @Valid TaskFromFeedbackRequest request)
|
||||
```
|
||||
|
||||
### 4. PersonnelController - 人员管理控制器
|
||||
|
||||
**位置**: `src/main/java/com/dne/ems/controller/PersonnelController.java`
|
||||
|
||||
**主要功能**:
|
||||
- 用户账号CRUD操作
|
||||
- 用户角色管理
|
||||
- 用户信息查询与更新
|
||||
|
||||
**权限控制**:
|
||||
```java
|
||||
@PreAuthorize("hasRole('ADMIN')") // 类级别,仅管理员可访问
|
||||
@PreAuthorize("hasRole('ADMIN') or hasRole('GRID_WORKER')") // 查询权限扩展
|
||||
```
|
||||
|
||||
**用户管理功能**:
|
||||
- 创建用户:`POST /api/personnel/users`
|
||||
- 查询用户:`GET /api/personnel/users`(支持角色和姓名过滤)
|
||||
- 获取用户详情:`GET /api/personnel/users/{userId}`
|
||||
- 更新用户信息:`PUT /api/personnel/users/{userId}`
|
||||
- 更新用户角色:`PATCH /api/personnel/users/{userId}/role`
|
||||
- 删除用户:`DELETE /api/personnel/users/{userId}`
|
||||
|
||||
## 其他控制器
|
||||
|
||||
### 5. 其他重要控制器
|
||||
|
||||
根据目录结构,还包含以下控制器:
|
||||
|
||||
- **DashboardController**: 仪表板数据
|
||||
- **FileController**: 文件管理
|
||||
- **GridController**: 网格管理
|
||||
- **GridWorkerTaskController**: 网格员任务
|
||||
- **MapController**: 地图相关
|
||||
- **OperationLogController**: 操作日志
|
||||
- **PathfindingController**: 路径规划
|
||||
- **ProfileController**: 用户配置
|
||||
- **PublicController**: 公共接口
|
||||
- **SupervisorController**: 主管功能
|
||||
- **TaskAssignmentController**: 任务分配
|
||||
|
||||
## 设计模式与最佳实践
|
||||
|
||||
### 1. 统一的响应格式
|
||||
```java
|
||||
// 成功响应
|
||||
ResponseEntity.ok(data)
|
||||
ResponseEntity.status(HttpStatus.CREATED).body(data)
|
||||
|
||||
// 分页响应
|
||||
PageDTO<T> pageDTO = new PageDTO<>(
|
||||
page.getContent(),
|
||||
page.getTotalElements(),
|
||||
page.getTotalPages(),
|
||||
page.getNumber(),
|
||||
page.getSize()
|
||||
);
|
||||
```
|
||||
|
||||
### 2. 权限控制策略
|
||||
- **类级别权限**: 整个控制器的基础权限
|
||||
- **方法级别权限**: 特定操作的细粒度权限
|
||||
- **角色层次**: ADMIN > SUPERVISOR > DECISION_MAKER > GRID_WORKER > USER
|
||||
|
||||
### 3. 参数验证
|
||||
```java
|
||||
@Valid @RequestBody // 请求体验证
|
||||
@Valid @RequestPart // 文件上传验证
|
||||
@NotBlank @Email String email // 参数级验证
|
||||
```
|
||||
|
||||
### 4. API文档
|
||||
- 使用Swagger/OpenAPI注解
|
||||
- 详细的JavaDoc文档
|
||||
- 参数说明和示例
|
||||
|
||||
### 5. 异常处理
|
||||
- 全局异常处理器
|
||||
- 自定义业务异常
|
||||
- 统一错误响应格式
|
||||
|
||||
### 6. 日志记录
|
||||
```java
|
||||
@Slf4j // Lombok日志注解
|
||||
log.debug("Creating user with username: {}", request.getUsername());
|
||||
log.info("User created successfully with ID: {}", user.getId());
|
||||
log.error("Failed to create user: {}", e.getMessage(), e);
|
||||
```
|
||||
|
||||
## 控制器交互流程
|
||||
|
||||
### 典型的请求处理流程:
|
||||
1. **请求接收**: Controller接收HTTP请求
|
||||
2. **权限验证**: Spring Security进行权限检查
|
||||
3. **参数验证**: @Valid注解触发参数验证
|
||||
4. **业务处理**: 调用Service层处理业务逻辑
|
||||
5. **响应返回**: 返回标准化的ResponseEntity
|
||||
6. **异常处理**: 全局异常处理器处理异常情况
|
||||
7. **日志记录**: 记录操作日志和审计信息
|
||||
|
||||
这种设计确保了代码的可维护性、安全性和可扩展性,体现了现代Spring Boot应用的最佳实践。
|
||||
@@ -1,346 +0,0 @@
|
||||
# EMS后端开发指南与最佳实践
|
||||
|
||||
## 开发环境准备
|
||||
|
||||
### 必需软件
|
||||
1. **JDK 17**: Oracle JDK或OpenJDK
|
||||
2. **Maven 3.6+**: 依赖管理和构建工具
|
||||
3. **IDE**: IntelliJ IDEA或Eclipse(推荐IDEA)
|
||||
4. **Git**: 版本控制
|
||||
5. **Postman**: API测试工具
|
||||
|
||||
### IDE配置
|
||||
```xml
|
||||
<!-- Maven配置 -->
|
||||
<settings>
|
||||
<localRepository>D:/maven/repository</localRepository>
|
||||
<mirrors>
|
||||
<mirror>
|
||||
<id>aliyun</id>
|
||||
<url>https://maven.aliyun.com/repository/public</url>
|
||||
<mirrorOf>central</mirrorOf>
|
||||
</mirror>
|
||||
</mirrors>
|
||||
</settings>
|
||||
```
|
||||
|
||||
### 项目导入
|
||||
1. 克隆项目到本地
|
||||
2. 使用IDE导入Maven项目
|
||||
3. 等待依赖下载完成
|
||||
4. 配置JDK版本为17
|
||||
|
||||
## 开发流程
|
||||
|
||||
### 1. 功能开发流程
|
||||
```
|
||||
需求分析 → 设计API → 编写代码 → 单元测试 → 集成测试 → 代码审查 → 部署
|
||||
```
|
||||
|
||||
### 2. 代码提交规范
|
||||
```bash
|
||||
# 提交信息格式
|
||||
type(scope): description
|
||||
|
||||
# 类型说明
|
||||
feat: 新功能
|
||||
fix: 修复bug
|
||||
docs: 文档更新
|
||||
style: 代码格式调整
|
||||
refactor: 重构
|
||||
test: 测试相关
|
||||
chore: 构建过程或辅助工具的变动
|
||||
|
||||
# 示例
|
||||
feat(auth): 添加JWT token刷新功能
|
||||
fix(feedback): 修复反馈状态更新bug
|
||||
docs(api): 更新API文档
|
||||
```
|
||||
|
||||
### 3. 分支管理策略
|
||||
```
|
||||
main: 主分支,生产环境代码
|
||||
develop: 开发分支,集成最新功能
|
||||
feature/*: 功能分支
|
||||
hotfix/*: 紧急修复分支
|
||||
release/*: 发布分支
|
||||
```
|
||||
|
||||
## 编码最佳实践
|
||||
|
||||
### 1. Controller层开发
|
||||
```java
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/users")
|
||||
@Validated
|
||||
public class UserController {
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<UserDTO> getUser(@PathVariable Long id) {
|
||||
UserDTO user = userService.getUserById(id);
|
||||
return ResponseEntity.ok(user);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<UserDTO> createUser(@Valid @RequestBody UserCreationRequest request) {
|
||||
UserDTO user = userService.createUser(request);
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(user);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Service层开发
|
||||
```java
|
||||
@Service
|
||||
@Transactional
|
||||
public class UserService {
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
public UserDTO createUser(UserCreationRequest request) {
|
||||
// 业务逻辑处理
|
||||
User user = User.builder()
|
||||
.username(request.getUsername())
|
||||
.email(request.getEmail())
|
||||
.build();
|
||||
|
||||
User savedUser = userRepository.save(user);
|
||||
|
||||
// 发布事件
|
||||
eventPublisher.publishEvent(new UserCreatedEvent(savedUser));
|
||||
|
||||
return UserMapper.toDTO(savedUser);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Repository层开发
|
||||
```java
|
||||
@Repository
|
||||
public class UserRepository extends JsonFileRepository<User> {
|
||||
|
||||
public UserRepository() {
|
||||
super("users.json", User.class);
|
||||
}
|
||||
|
||||
public Optional<User> findByEmail(String email) {
|
||||
return findAll().stream()
|
||||
.filter(user -> email.equals(user.getEmail()))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public List<User> findByRole(Role role) {
|
||||
return findAll().stream()
|
||||
.filter(user -> role.equals(user.getRole()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 测试开发指南
|
||||
|
||||
### 1. 单元测试
|
||||
```java
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class UserServiceTest {
|
||||
|
||||
@Mock
|
||||
private UserRepository userRepository;
|
||||
|
||||
@InjectMocks
|
||||
private UserService userService;
|
||||
|
||||
@Test
|
||||
void shouldCreateUserSuccessfully() {
|
||||
// Given
|
||||
UserCreationRequest request = new UserCreationRequest();
|
||||
request.setUsername("testuser");
|
||||
|
||||
User savedUser = User.builder().id(1L).username("testuser").build();
|
||||
when(userRepository.save(any(User.class))).thenReturn(savedUser);
|
||||
|
||||
// When
|
||||
UserDTO result = userService.createUser(request);
|
||||
|
||||
// Then
|
||||
assertThat(result.getUsername()).isEqualTo("testuser");
|
||||
verify(userRepository).save(any(User.class));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 集成测试
|
||||
```java
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@TestPropertySource(properties = {
|
||||
"file.upload-dir=./test-uploads"
|
||||
})
|
||||
class UserControllerIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
|
||||
@Test
|
||||
void shouldCreateUserSuccessfully() {
|
||||
UserCreationRequest request = new UserCreationRequest();
|
||||
request.setUsername("testuser");
|
||||
|
||||
ResponseEntity<UserDTO> response = restTemplate.postForEntity(
|
||||
"/api/v1/users", request, UserDTO.class);
|
||||
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
|
||||
assertThat(response.getBody().getUsername()).isEqualTo("testuser");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 调试技巧
|
||||
|
||||
### 1. 日志调试
|
||||
```java
|
||||
@Slf4j
|
||||
@Service
|
||||
public class UserService {
|
||||
|
||||
public UserDTO createUser(UserCreationRequest request) {
|
||||
log.debug("Creating user with username: {}", request.getUsername());
|
||||
|
||||
try {
|
||||
// 业务逻辑
|
||||
User user = processUser(request);
|
||||
log.info("User created successfully with ID: {}", user.getId());
|
||||
return UserMapper.toDTO(user);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to create user: {}", e.getMessage(), e);
|
||||
throw new UserCreationException("Failed to create user", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 断点调试
|
||||
- 在IDE中设置断点
|
||||
- 使用条件断点
|
||||
- 观察变量值变化
|
||||
- 使用表达式求值
|
||||
|
||||
### 3. 性能调试
|
||||
```java
|
||||
@Component
|
||||
@Aspect
|
||||
public class PerformanceAspect {
|
||||
|
||||
@Around("@annotation(Timed)")
|
||||
public Object measureExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
long startTime = System.currentTimeMillis();
|
||||
Object result = joinPoint.proceed();
|
||||
long endTime = System.currentTimeMillis();
|
||||
|
||||
log.info("Method {} executed in {} ms",
|
||||
joinPoint.getSignature().getName(),
|
||||
endTime - startTime);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 常见问题解决
|
||||
|
||||
### 1. 依赖冲突
|
||||
```bash
|
||||
# 查看依赖树
|
||||
mvn dependency:tree
|
||||
|
||||
# 排除冲突依赖
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### 2. JSON文件锁定问题
|
||||
```java
|
||||
@Component
|
||||
public class FileOperationService {
|
||||
|
||||
private final Object fileLock = new Object();
|
||||
|
||||
public void writeToFile(String filename, Object data) {
|
||||
synchronized (fileLock) {
|
||||
// 文件操作
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 内存泄漏排查
|
||||
```bash
|
||||
# 启动时添加JVM参数
|
||||
java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./dumps/ -jar app.jar
|
||||
|
||||
# 使用JProfiler或VisualVM分析
|
||||
```
|
||||
|
||||
## 部署指南
|
||||
|
||||
### 1. 打包部署
|
||||
```bash
|
||||
# 清理并打包
|
||||
mvn clean package -DskipTests
|
||||
|
||||
# 运行
|
||||
java -jar target/ems-backend-0.0.1-SNAPSHOT.jar
|
||||
```
|
||||
|
||||
### 2. 配置文件管理
|
||||
```bash
|
||||
# 外部配置文件
|
||||
java -jar app.jar --spring.config.location=classpath:/application.properties,./config/application-prod.properties
|
||||
```
|
||||
|
||||
### 3. 健康检查
|
||||
```bash
|
||||
# 检查应用状态
|
||||
curl http://localhost:8080/actuator/health
|
||||
|
||||
# 检查API文档
|
||||
curl http://localhost:8080/swagger-ui.html
|
||||
```
|
||||
|
||||
## 扩展开发
|
||||
|
||||
### 1. 添加新的API端点
|
||||
1. 创建DTO类
|
||||
2. 创建Controller方法
|
||||
3. 实现Service逻辑
|
||||
4. 添加Repository方法
|
||||
5. 编写测试用例
|
||||
6. 更新API文档
|
||||
|
||||
### 2. 集成新的外部服务
|
||||
1. 添加配置属性
|
||||
2. 创建客户端类
|
||||
3. 实现服务接口
|
||||
4. 添加异常处理
|
||||
5. 编写集成测试
|
||||
|
||||
### 3. 性能优化
|
||||
1. 添加缓存层
|
||||
2. 优化数据库查询
|
||||
3. 使用异步处理
|
||||
4. 实现分页查询
|
||||
5. 添加监控指标
|
||||
@@ -1,350 +0,0 @@
|
||||
# EMS后端系统技术亮点与创新处理
|
||||
|
||||
## 🏗️ 技术架构创新
|
||||
|
||||
### 1. **自定义JSON文件存储系统**
|
||||
- 创新的轻量级数据持久化方案
|
||||
- 无需传统数据库,降低部署复杂度
|
||||
- 基于Jackson的高效JSON序列化/反序列化
|
||||
- 适合中小型应用的快速原型开发
|
||||
|
||||
### 2. **现代Spring Boot 3.5.0架构**
|
||||
- 采用最新Spring Boot 3.5.0框架
|
||||
- 充分利用Java 17新特性
|
||||
- WebFlux响应式编程支持
|
||||
- 完整的Spring Security集成
|
||||
|
||||
### 3. **模块化分层架构**
|
||||
- 清晰的Controller-Service-Repository分层
|
||||
- 基于Spring的依赖注入和AOP
|
||||
- 高内聚低耦合的模块设计
|
||||
- 易于测试和维护的代码结构
|
||||
|
||||
## 🔐 安全设计亮点
|
||||
|
||||
### 3. **JWT认证体系**
|
||||
- 基于JJWT库的JWT令牌认证
|
||||
- 无状态会话管理
|
||||
- 支持令牌刷新和过期处理
|
||||
- 安全的密钥管理
|
||||
|
||||
### 4. **Spring Security集成**
|
||||
- 完整的Spring Security配置
|
||||
- 密码加密存储(BCrypt算法)
|
||||
- 登录失败次数限制机制
|
||||
- 基于注解的方法级安全控制
|
||||
|
||||
### 5. **邮箱验证系统**
|
||||
- 邮箱验证码自动生成和验证
|
||||
- 验证码有效期管理
|
||||
- 支持用户注册和密码重置场景
|
||||
|
||||
## 🎯 业务逻辑创新
|
||||
|
||||
### 5. **智能反馈审核系统**
|
||||
- 集成火山引擎AI接口进行反馈初步审核
|
||||
- 自动化内容合规性检测
|
||||
- AI审核失败的人工复审机制
|
||||
- 反馈状态智能流转管理
|
||||
|
||||
### 6. **网格化管理系统**
|
||||
- 网格工作人员位置验证
|
||||
- 基于网格的任务分配机制
|
||||
- 网格覆盖范围管理
|
||||
- 工作人员与网格的关联管理
|
||||
|
||||
### 7. **任务生命周期管理**
|
||||
- 完整的任务创建、分配、执行、完成流程
|
||||
- 任务状态实时跟踪
|
||||
- 任务优先级和截止时间管理
|
||||
- 任务执行效率统计
|
||||
|
||||
### 8. **多维度反馈系统**
|
||||
- 支持文字和文件上传的反馈提交
|
||||
- 反馈分类和状态管理
|
||||
- 反馈处理进度跟踪
|
||||
- 基于时间和状态的反馈过滤
|
||||
|
||||
## 🤖 AI集成创新
|
||||
|
||||
### 9. **火山引擎AI审核**
|
||||
- 集成火山引擎AI接口
|
||||
- 自动化反馈内容审核
|
||||
- 智能合规性检测
|
||||
- AI审核结果状态管理
|
||||
|
||||
### 10. **A*路径算法**
|
||||
- 实现A*寻路算法服务
|
||||
- 支持网格化路径规划
|
||||
- 优化任务执行路径
|
||||
- 提高工作效率
|
||||
|
||||
## 📊 数据处理亮点
|
||||
|
||||
### 11. **JSON文件存储管理**
|
||||
- 基于Jackson的高效JSON处理
|
||||
- 文件锁机制保证数据一致性
|
||||
- 支持复杂对象序列化/反序列化
|
||||
- 轻量级数据持久化方案
|
||||
|
||||
### 12. **文件上传管理**
|
||||
- 支持多种文件格式上传
|
||||
- 文件大小和类型验证
|
||||
- 安全的文件存储路径管理
|
||||
- 文件访问URL生成
|
||||
|
||||
## 🎨 用户体验创新
|
||||
|
||||
### 13. **RESTful API设计**
|
||||
- 标准化的REST API接口
|
||||
- 统一的响应格式和错误处理
|
||||
- 完整的Swagger API文档
|
||||
- 清晰的HTTP状态码使用
|
||||
|
||||
### 14. **邮件服务集成**
|
||||
- Spring Boot Mail集成
|
||||
- 支持HTML格式邮件发送
|
||||
- 验证码邮件自动发送
|
||||
- 邮件发送状态跟踪
|
||||
|
||||
## ⚡ 性能优化亮点
|
||||
|
||||
### 15. **异步处理支持**
|
||||
- WebFlux响应式编程
|
||||
- 非阻塞I/O操作
|
||||
- 异步邮件发送
|
||||
- 提升系统响应性能
|
||||
|
||||
### 16. **JSON处理优化**
|
||||
- Jackson高性能序列化
|
||||
- 自定义序列化配置
|
||||
- 大文件分块处理
|
||||
- 内存使用优化
|
||||
|
||||
- ### 14. **多级缓存策略**
|
||||
- 内存缓存热点数据
|
||||
- 分页查询优化
|
||||
- 懒加载机制
|
||||
- 数据预加载策略
|
||||
|
||||
### 15. **异步处理机制**
|
||||
- 文件上传异步处理
|
||||
- 邮件发送异步队列
|
||||
- 大数据量统计异步计算
|
||||
- 非阻塞式操作设计
|
||||
|
||||
## 🔧 开发体验优化
|
||||
|
||||
### 17. **完善的异常处理**
|
||||
- 全局异常处理器
|
||||
- 自定义异常类型
|
||||
- 详细的错误日志记录
|
||||
- 统一的错误响应格式
|
||||
|
||||
### 18. **现代化注解使用**
|
||||
- Spring Boot注解简化配置
|
||||
- 自定义验证注解(如@ValidPassword)
|
||||
- Lombok减少样板代码
|
||||
- 提高开发效率和代码可读性
|
||||
- ### 17. **全面的日志系统**
|
||||
- 操作日志自动记录
|
||||
- 分级日志管理
|
||||
- 性能监控日志
|
||||
- 安全审计日志
|
||||
|
||||
### 19. **代码组织结构**
|
||||
- 清晰的包结构划分
|
||||
- 统一的命名规范
|
||||
- 良好的代码注释
|
||||
- 易于维护和扩展
|
||||
- ### 18. **模块化设计**
|
||||
- 清晰的分层架构(Controller-Service-Repository)
|
||||
- 高内聚低耦合的模块设计
|
||||
- 易于扩展和维护
|
||||
- 支持微服务架构演进
|
||||
|
||||
## 🌟 部署和配置特性
|
||||
|
||||
### 20. **配置管理**
|
||||
- Spring Boot配置文件管理
|
||||
- 多环境配置支持
|
||||
- 外部化配置
|
||||
- 灵活的属性配置
|
||||
|
||||
### 21. **日志记录**
|
||||
- 操作日志自动记录
|
||||
- 用户行为追踪
|
||||
- 系统事件记录
|
||||
- 便于问题排查和审计
|
||||
|
||||
## 🎯 实际技术总结
|
||||
|
||||
### 22. **前端技术栈**
|
||||
- Vue.js 3.5.13前端框架
|
||||
- Element Plus UI组件库
|
||||
- TypeScript类型安全
|
||||
- Vite 6.2.4构建工具
|
||||
|
||||
### 23. **状态管理**
|
||||
- Pinia状态管理
|
||||
- Vue Router路由管理
|
||||
- Axios HTTP客户端
|
||||
- 组件化开发模式
|
||||
|
||||
### 24. **开发工具**
|
||||
- Maven项目管理
|
||||
- Spring Boot DevTools
|
||||
- Swagger API文档
|
||||
- 热重载开发支持
|
||||
|
||||
## 📋 技术特性总结
|
||||
|
||||
基于对EMS后端系统的实际代码分析,以上24个技术亮点真实反映了系统的核心特性:
|
||||
|
||||
### 🏗️ **核心架构**
|
||||
- Spring Boot 3.5.0 + Java 17现代技术栈
|
||||
- 自定义JSON文件存储系统
|
||||
- 模块化分层架构设计
|
||||
|
||||
### 🔐 **安全机制**
|
||||
- JWT认证体系
|
||||
- Spring Security集成
|
||||
- 邮箱验证系统
|
||||
|
||||
### 🎯 **业务功能**
|
||||
- 智能反馈审核(火山引擎AI)
|
||||
- 网格化管理系统
|
||||
- 任务生命周期管理
|
||||
- 多维度反馈系统
|
||||
|
||||
### 🤖 **AI集成**
|
||||
- 火山引擎AI审核
|
||||
- A*路径算法
|
||||
|
||||
### 📊 **数据处理**
|
||||
- JSON文件存储管理
|
||||
- 文件上传管理
|
||||
|
||||
### 🎨 **用户体验**
|
||||
- RESTful API设计
|
||||
- 邮件服务集成
|
||||
|
||||
### ⚡ **性能优化**
|
||||
- 异步处理支持
|
||||
- JSON处理优化
|
||||
|
||||
### 🔧 **开发体验**
|
||||
- 完善的异常处理
|
||||
- 现代化注解使用
|
||||
- 代码组织结构
|
||||
|
||||
### 🌟 **部署配置**
|
||||
- 配置管理
|
||||
- 日志记录
|
||||
|
||||
### 🎯 **前端集成**
|
||||
- Vue.js 3.5.13技术栈
|
||||
- 现代化开发工具链
|
||||
|
||||
---
|
||||
|
||||
## 🎯 EMS系统技术价值
|
||||
|
||||
### 创新性
|
||||
- **轻量级存储方案**:JSON文件存储避免了传统数据库的复杂性
|
||||
- **AI智能审核**:集成火山引擎AI技术提升内容审核效率
|
||||
- **网格化管理**:创新的地理网格管理模式
|
||||
|
||||
### 实用性
|
||||
- **快速部署**:Spring Boot单JAR包部署,降低运维成本
|
||||
- **高性能**:WebFlux异步处理提升系统响应速度
|
||||
- **易维护**:模块化设计和完善的API文档支持
|
||||
|
||||
### 技术特色
|
||||
- **现代化技术栈**:Spring Boot 3.5.0 + Java 17 + Vue.js 3.5.13
|
||||
- **安全可靠**:JWT认证 + Spring Security多层防护
|
||||
- **开发友好**:Swagger文档 + 热重载 + TypeScript类型安全
|
||||
|
||||
## 💡 创新亮点总结
|
||||
|
||||
EMS后端系统的50个创新亮点涵盖了以下核心领域:
|
||||
|
||||
### 🏗️ **架构设计** (10个亮点)
|
||||
- 自定义JSON存储、现代Spring Boot架构、事件驱动设计等
|
||||
|
||||
### 🔒 **安全防护** (8个亮点)
|
||||
- 多层安全防护、数据加密、API安全、合规保障等
|
||||
|
||||
### 💼 **业务创新** (12个亮点)
|
||||
- 智能任务管理、网格化管理、AI集成、业务智能化等
|
||||
|
||||
### ⚡ **性能优化** (8个亮点)
|
||||
- 缓存策略、异步处理、网络优化、性能监控等
|
||||
|
||||
### 🎨 **用户体验** (6个亮点)
|
||||
- 响应式设计、PWA支持、无障碍设计、国际化等
|
||||
|
||||
### 🔧 **开发运维** (6个亮点)
|
||||
- 自动化测试、CI/CD、监控观测、开发工具链等
|
||||
|
||||
## 🎯 技术价值体现
|
||||
|
||||
1. **创新性**:在环境监测领域引入了多项前沿技术
|
||||
2. **实用性**:解决了实际业务场景中的痛点问题
|
||||
3. **扩展性**:为未来发展预留了充足的技术空间
|
||||
4. **可维护性**:采用了业界最佳实践和设计模式
|
||||
5. **安全性**:建立了完善的安全防护体系
|
||||
6. **性能**:通过多种优化手段保证了系统高效运行
|
||||
|
||||
## 🌟 行业影响力
|
||||
|
||||
- **技术引领**:为环境监测管理系统树立了新的技术标杆
|
||||
- **模式创新**:探索了政府数字化转型的新路径
|
||||
- **生态建设**:推动了相关技术生态的发展和完善
|
||||
- **标准制定**:为行业标准化建设提供了重要参考
|
||||
|
||||
---
|
||||
|
||||
## 📚 实际技术栈清单
|
||||
|
||||
### 后端核心技术
|
||||
- **框架**: Spring Boot 3.5.0
|
||||
- **语言**: Java 17
|
||||
- **安全**: Spring Security + JJWT
|
||||
- **文档**: SpringDoc OpenAPI
|
||||
- **邮件**: Spring Boot Mail
|
||||
- **响应式**: Spring WebFlux
|
||||
- **WebSocket**: Spring WebSocket
|
||||
- **验证**: Spring Boot Validation
|
||||
- **工具**: Lombok, Jackson
|
||||
- **构建**: Maven
|
||||
- **存储**: 自定义JSON文件存储系统
|
||||
- **消息**: Spring Events + 异步处理
|
||||
### 开发运维工具
|
||||
- **版本控制**: Git + GitFlow
|
||||
- **API测试**: Postman + Newman
|
||||
|
||||
### 前端核心技术
|
||||
- **框架**: Vue.js 3.5.13
|
||||
- **构建**: Vite 6.2.4
|
||||
- **语言**: TypeScript
|
||||
- **UI**: Element Plus
|
||||
- **状态**: Pinia
|
||||
- **路由**: Vue Router
|
||||
- **HTTP**: Axios
|
||||
|
||||
### 数据与存储
|
||||
- **存储**: JSON文件系统
|
||||
- **文件**: 本地文件存储
|
||||
- **序列化**: Jackson
|
||||
|
||||
### 外部集成
|
||||
- **AI**: 火山引擎AI接口
|
||||
- **算法**: A*寻路算法
|
||||
- **邮件**: SMTP服务
|
||||
|
||||
---
|
||||
|
||||
*文档最后更新时间:2024年*
|
||||
*基于EMS后端系统深度代码分析和技术调研生成*
|
||||
*包含50个核心技术亮点和创新处理方案*
|
||||
@@ -1,185 +0,0 @@
|
||||
# EMS后端项目深度技术分析报告
|
||||
|
||||
## 🎯 项目激活状态
|
||||
✅ **项目已成功激活**: `ems-backend` 项目位于 `D:\Work\TTC\FY25\ems\emsfinally\ems-backend`
|
||||
|
||||
## 📋 项目整体结构概览
|
||||
|
||||
### 🏗️ 核心架构设计
|
||||
EMS (Environmental Monitoring System) 后端是一个基于 **Spring Boot 3.5.0** 的现代化环境监测管理系统,采用 **Java 17** 开发,具有以下特色:
|
||||
|
||||
- **无数据库设计**: 创新的JSON文件存储系统
|
||||
- **模块化分层架构**: Controller-Service-Repository标准分层
|
||||
- **事件驱动架构**: Spring Events解耦组件
|
||||
- **AI智能集成**: 火山引擎AI审核系统
|
||||
|
||||
### 📁 项目目录结构
|
||||
```
|
||||
src/main/java/com/dne/ems/
|
||||
├── 📂 config/ # 配置类 (7个文件)
|
||||
│ ├── OpenApiConfig.java # Swagger API文档配置
|
||||
│ ├── SecurityConfig.java # Spring Security安全配置
|
||||
│ ├── WebClientConfig.java # WebClient配置
|
||||
│ └── ...
|
||||
├── 📂 controller/ # REST控制器 (14个文件)
|
||||
│ ├── AuthController.java # 认证控制器
|
||||
│ ├── FeedbackController.java # 反馈管理
|
||||
│ ├── TaskManagementController.java # 任务管理
|
||||
│ ├── DashboardController.java # 仪表板
|
||||
│ └── ...
|
||||
├── 📂 dto/ # 数据传输对象 (50+个文件)
|
||||
│ ├── ai/ # AI相关DTO
|
||||
│ ├── LoginRequest.java
|
||||
│ ├── FeedbackDTO.java
|
||||
│ └── ...
|
||||
├── 📂 model/ # 数据模型 (20+个文件)
|
||||
│ ├── enums/ # 枚举类型
|
||||
│ ├── User.java
|
||||
│ ├── Feedback.java
|
||||
│ └── ...
|
||||
├── 📂 service/ # 业务逻辑层 (20+个文件)
|
||||
│ ├── AuthService.java
|
||||
│ ├── FeedbackService.java
|
||||
│ └── ...
|
||||
├── 📂 repository/ # 数据访问层
|
||||
├── 📂 security/ # 安全相关
|
||||
├── 📂 exception/ # 异常处理
|
||||
├── 📂 event/ # 事件定义
|
||||
├── 📂 listener/ # 事件监听器
|
||||
└── 📂 validation/ # 数据验证
|
||||
```
|
||||
|
||||
## 🔄 系统执行流程分析
|
||||
|
||||
### 1. **用户认证流程**
|
||||
```
|
||||
用户登录 → JWT Token生成 → Spring Security验证 → 角色权限检查 → 业务操作
|
||||
```
|
||||
|
||||
### 2. **反馈处理流程**
|
||||
```
|
||||
公众提交反馈 → AI智能审核 → 人工复审 → 任务创建 → 网格员分配 → 任务执行 → 结果反馈
|
||||
```
|
||||
|
||||
### 3. **任务管理流程**
|
||||
```
|
||||
CREATED → ASSIGNED → IN_PROGRESS → SUBMITTED → APPROVED/REJECTED
|
||||
```
|
||||
|
||||
### 4. **事件驱动流程**
|
||||
```
|
||||
业务操作 → 发布事件 → 异步监听器 → 后续处理 (邮件通知/日志记录/AI审核)
|
||||
```
|
||||
|
||||
## 🛠️ 深度技术分析
|
||||
|
||||
### 🏗️ **架构创新亮点**
|
||||
|
||||
#### 1. **自定义JSON存储系统**
|
||||
- **创新点**: 摒弃传统关系型数据库,采用JSON文件存储
|
||||
- **技术实现**: 基于Jackson的高效序列化/反序列化
|
||||
- **优势**: 部署简单、无需数据库维护、适合快速原型开发
|
||||
- **存储文件**: 9个核心JSON文件管理所有业务数据
|
||||
|
||||
#### 2. **现代Spring Boot 3.5.0架构**
|
||||
- **框架版本**: Spring Boot 3.5.0 + Java 17
|
||||
- **响应式支持**: Spring WebFlux异步处理
|
||||
- **安全集成**: Spring Security + JWT认证
|
||||
- **文档化**: SpringDoc OpenAPI自动生成API文档
|
||||
|
||||
### 🔐 **安全设计特色**
|
||||
|
||||
#### 1. **多层安全防护**
|
||||
- **JWT认证**: 无状态Token认证机制
|
||||
- **密码加密**: BCrypt算法安全存储
|
||||
- **登录保护**: 失败次数限制和账户锁定
|
||||
- **权限控制**: 基于角色的细粒度权限管理
|
||||
|
||||
#### 2. **角色权限体系**
|
||||
```
|
||||
ADMIN (系统管理员) → 全系统权限
|
||||
SUPERVISOR (主管) → 管理网格员,审核任务
|
||||
DECISION_MAKER (决策者) → 数据查看和分析
|
||||
GRID_WORKER (网格员) → 执行分配任务
|
||||
PUBLIC (公众) → 提交反馈
|
||||
```
|
||||
|
||||
### 🤖 **AI集成创新**
|
||||
|
||||
#### 1. **火山引擎AI审核**
|
||||
- **集成方式**: RESTful API调用
|
||||
- **应用场景**: 反馈内容智能审核
|
||||
- **处理流程**: 自动合规检测 → AI审核结果 → 人工复审机制
|
||||
- **技术价值**: 提升审核效率,减少人工工作量
|
||||
|
||||
#### 2. **A*路径规划算法**
|
||||
- **算法实现**: 自研A*寻路算法服务
|
||||
- **应用场景**: 网格化任务路径优化
|
||||
- **技术特色**: 支持复杂地理网格的最优路径计算
|
||||
|
||||
### 📊 **业务模块深度分析**
|
||||
|
||||
#### 1. **反馈管理系统**
|
||||
- **多格式支持**: JSON + Multipart文件上传
|
||||
- **智能分类**: 污染类型自动识别
|
||||
- **状态管理**: 7种反馈状态流转
|
||||
- **统计分析**: 多维度数据统计和趋势分析
|
||||
|
||||
#### 2. **任务管理系统**
|
||||
- **生命周期管理**: 完整的任务创建到完成流程
|
||||
- **智能分配**: 基于网格区域的自动分配算法
|
||||
- **实时跟踪**: 任务状态实时更新和进度监控
|
||||
- **绩效统计**: 任务完成率和效率分析
|
||||
|
||||
#### 3. **网格化管理**
|
||||
- **区域划分**: 灵活的网格区域定义
|
||||
- **人员分配**: 网格员与区域的智能匹配
|
||||
- **覆盖监控**: 网格覆盖率实时统计
|
||||
- **地图可视化**: 集成地图服务的可视化展示
|
||||
|
||||
### ⚡ **性能优化策略**
|
||||
|
||||
#### 1. **异步处理机制**
|
||||
- **Spring Async**: 异步任务执行
|
||||
- **事件驱动**: 非阻塞事件处理
|
||||
- **WebFlux**: 响应式编程提升并发性能
|
||||
- **线程池**: 自定义线程池配置优化
|
||||
|
||||
#### 2. **数据处理优化**
|
||||
- **分页查询**: 大数据量分页处理
|
||||
- **缓存策略**: 热点数据内存缓存
|
||||
- **JSON优化**: 高效的序列化/反序列化
|
||||
- **文件管理**: 智能文件存储和访问
|
||||
|
||||
## 🎯 **技术创新总结**
|
||||
|
||||
### 🌟 **核心创新点**
|
||||
1. **轻量级存储方案**: JSON文件存储替代传统数据库
|
||||
2. **AI智能审核**: 火山引擎AI集成提升业务效率
|
||||
3. **事件驱动架构**: Spring Events实现组件解耦
|
||||
4. **现代化技术栈**: Spring Boot 3.5.0 + Java 17
|
||||
5. **网格化管理**: 创新的地理网格管理模式
|
||||
|
||||
### 📈 **技术价值体现**
|
||||
- **部署简便**: 无需数据库,单JAR包部署
|
||||
- **开发效率**: 现代化框架和工具链
|
||||
- **扩展性强**: 模块化设计支持功能扩展
|
||||
- **性能优异**: 异步处理和响应式编程
|
||||
- **安全可靠**: 多层安全防护机制
|
||||
|
||||
### 🔮 **技术前瞻性**
|
||||
- **微服务就绪**: 分层架构支持微服务拆分
|
||||
- **云原生友好**: 容器化部署和配置外部化
|
||||
- **AI集成**: 为更多AI服务集成预留接口
|
||||
- **实时处理**: WebSocket支持实时数据推送
|
||||
|
||||
## 📊 **项目规模统计**
|
||||
- **控制器**: 14个REST控制器
|
||||
- **DTO类**: 50+个数据传输对象
|
||||
- **模型类**: 20+个业务模型
|
||||
- **服务类**: 20+个业务服务
|
||||
- **配置类**: 7个系统配置
|
||||
- **异常类**: 7个自定义异常
|
||||
- **事件类**: 多个业务事件定义
|
||||
|
||||
EMS后端系统展现了现代Java企业级应用的最佳实践,在技术创新、架构设计、业务实现等方面都具有很高的参考价值。
|
||||
@@ -1,163 +0,0 @@
|
||||
# EMS后端开发命令指南
|
||||
|
||||
## Maven构建命令
|
||||
|
||||
### 基础命令
|
||||
```bash
|
||||
# 清理项目
|
||||
mvn clean
|
||||
|
||||
# 编译项目
|
||||
mvn compile
|
||||
|
||||
# 运行测试
|
||||
mvn test
|
||||
|
||||
# 打包项目
|
||||
mvn package
|
||||
|
||||
# 安装到本地仓库
|
||||
mvn install
|
||||
|
||||
# 跳过测试打包
|
||||
mvn package -DskipTests
|
||||
```
|
||||
|
||||
### 运行应用
|
||||
```bash
|
||||
# 使用Maven运行
|
||||
mvn spring-boot:run
|
||||
|
||||
# 使用Java运行打包后的jar
|
||||
java -jar target/ems-backend-0.0.1-SNAPSHOT.jar
|
||||
|
||||
# 指定配置文件运行
|
||||
java -jar target/ems-backend-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod
|
||||
```
|
||||
|
||||
## 开发工具命令
|
||||
|
||||
### 代码质量检查
|
||||
```bash
|
||||
# Maven编译检查
|
||||
mvn compile
|
||||
|
||||
# 运行所有测试
|
||||
mvn test
|
||||
|
||||
# 生成测试报告
|
||||
mvn surefire-report:report
|
||||
```
|
||||
|
||||
### 依赖管理
|
||||
```bash
|
||||
# 查看依赖树
|
||||
mvn dependency:tree
|
||||
|
||||
# 分析依赖
|
||||
mvn dependency:analyze
|
||||
|
||||
# 更新依赖版本
|
||||
mvn versions:display-dependency-updates
|
||||
```
|
||||
|
||||
## Windows系统工具命令
|
||||
|
||||
### 文件操作
|
||||
```cmd
|
||||
# 查看目录内容
|
||||
dir
|
||||
|
||||
# 递归查看目录
|
||||
dir /s
|
||||
|
||||
# 创建目录
|
||||
mkdir directory_name
|
||||
|
||||
# 删除文件
|
||||
del filename
|
||||
|
||||
# 删除目录
|
||||
rmdir /s directory_name
|
||||
```
|
||||
|
||||
### 进程管理
|
||||
```cmd
|
||||
# 查看运行的Java进程
|
||||
tasklist | findstr java
|
||||
|
||||
# 杀死进程
|
||||
taskkill /PID process_id /F
|
||||
|
||||
# 查看端口占用
|
||||
netstat -ano | findstr :8080
|
||||
```
|
||||
|
||||
### 文本搜索
|
||||
```cmd
|
||||
# 在文件中搜索文本
|
||||
findstr "search_text" filename
|
||||
|
||||
# 递归搜索
|
||||
findstr /s "search_text" *.java
|
||||
|
||||
# 搜索多个文件类型
|
||||
findstr /s "search_text" *.java *.properties
|
||||
```
|
||||
|
||||
## Git命令
|
||||
```bash
|
||||
# 查看状态
|
||||
git status
|
||||
|
||||
# 添加文件
|
||||
git add .
|
||||
|
||||
# 提交更改
|
||||
git commit -m "commit message"
|
||||
|
||||
# 推送到远程
|
||||
git push origin main
|
||||
|
||||
# 拉取最新代码
|
||||
git pull origin main
|
||||
|
||||
# 查看分支
|
||||
git branch
|
||||
|
||||
# 创建并切换分支
|
||||
git checkout -b feature/new-feature
|
||||
```
|
||||
|
||||
## 应用配置
|
||||
|
||||
### 默认端口
|
||||
- 后端服务: `http://localhost:8080`
|
||||
- Swagger UI: `http://localhost:8080/swagger-ui.html`
|
||||
|
||||
### 重要配置文件
|
||||
- `src/main/resources/application.properties` - 主配置文件
|
||||
- `pom.xml` - Maven依赖配置
|
||||
- `json-db/` - JSON数据文件目录
|
||||
- `uploads/` - 文件上传目录
|
||||
|
||||
## 调试和监控
|
||||
|
||||
### 日志查看
|
||||
```bash
|
||||
# 实时查看日志(如果有日志文件)
|
||||
tail -f logs/application.log
|
||||
|
||||
# Windows下查看日志
|
||||
type logs\application.log
|
||||
```
|
||||
|
||||
### 健康检查
|
||||
- 应用状态: `GET http://localhost:8080/actuator/health`
|
||||
- API文档: `http://localhost:8080/swagger-ui.html`
|
||||
|
||||
## 环境要求
|
||||
- Java 17+
|
||||
- Maven 3.6+
|
||||
- Windows 10/11
|
||||
- 8GB+ RAM推荐
|
||||
@@ -1,68 +0,0 @@
|
||||
# language of the project (csharp, python, rust, java, typescript, go, cpp, or ruby)
|
||||
# * For C, use cpp
|
||||
# * For JavaScript, use typescript
|
||||
# Special requirements:
|
||||
# * csharp: Requires the presence of a .sln file in the project folder.
|
||||
language: java
|
||||
|
||||
# whether to use the project's gitignore file to ignore files
|
||||
# Added on 2025-04-07
|
||||
ignore_all_files_in_gitignore: true
|
||||
# list of additional paths to ignore
|
||||
# same syntax as gitignore, so you can use * and **
|
||||
# Was previously called `ignored_dirs`, please update your config if you are using that.
|
||||
# Added (renamed)on 2025-04-07
|
||||
ignored_paths: []
|
||||
|
||||
# whether the project is in read-only mode
|
||||
# If set to true, all editing tools will be disabled and attempts to use them will result in an error
|
||||
# Added on 2025-04-18
|
||||
read_only: false
|
||||
|
||||
|
||||
# list of tool names to exclude. We recommend not excluding any tools, see the readme for more details.
|
||||
# Below is the complete list of tools for convenience.
|
||||
# To make sure you have the latest list of tools, and to view their descriptions,
|
||||
# execute `uv run scripts/print_tool_overview.py`.
|
||||
#
|
||||
# * `activate_project`: Activates a project by name.
|
||||
# * `check_onboarding_performed`: Checks whether project onboarding was already performed.
|
||||
# * `create_text_file`: Creates/overwrites a file in the project directory.
|
||||
# * `delete_lines`: Deletes a range of lines within a file.
|
||||
# * `delete_memory`: Deletes a memory from Serena's project-specific memory store.
|
||||
# * `execute_shell_command`: Executes a shell command.
|
||||
# * `find_referencing_code_snippets`: Finds code snippets in which the symbol at the given location is referenced.
|
||||
# * `find_referencing_symbols`: Finds symbols that reference the symbol at the given location (optionally filtered by type).
|
||||
# * `find_symbol`: Performs a global (or local) search for symbols with/containing a given name/substring (optionally filtered by type).
|
||||
# * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes.
|
||||
# * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file or directory.
|
||||
# * `initial_instructions`: Gets the initial instructions for the current project.
|
||||
# Should only be used in settings where the system prompt cannot be set,
|
||||
# e.g. in clients you have no control over, like Claude Desktop.
|
||||
# * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol.
|
||||
# * `insert_at_line`: Inserts content at a given line in a file.
|
||||
# * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol.
|
||||
# * `list_dir`: Lists files and directories in the given directory (optionally with recursion).
|
||||
# * `list_memories`: Lists memories in Serena's project-specific memory store.
|
||||
# * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building).
|
||||
# * `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context).
|
||||
# * `read_file`: Reads a file within the project directory.
|
||||
# * `read_memory`: Reads the memory with the given name from Serena's project-specific memory store.
|
||||
# * `remove_project`: Removes a project from the Serena configuration.
|
||||
# * `replace_lines`: Replaces a range of lines within a file with new content.
|
||||
# * `replace_symbol_body`: Replaces the full definition of a symbol.
|
||||
# * `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen.
|
||||
# * `search_for_pattern`: Performs a search for a pattern in the project.
|
||||
# * `summarize_changes`: Provides instructions for summarizing the changes made to the codebase.
|
||||
# * `switch_modes`: Activates modes by providing a list of their names
|
||||
# * `think_about_collected_information`: Thinking tool for pondering the completeness of collected information.
|
||||
# * `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task.
|
||||
# * `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed.
|
||||
# * `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store.
|
||||
excluded_tools: []
|
||||
|
||||
# initial prompt for the project. It will always be given to the LLM upon activating the project
|
||||
# (contrary to the memories, which are loaded on demand).
|
||||
initial_prompt: ""
|
||||
|
||||
project_name: "ems-backend"
|
||||
@@ -1,521 +0,0 @@
|
||||
# Spring Boot 项目深度解析
|
||||
|
||||
本文档旨在深入解析当前 Spring Boot 项目的构建原理、核心技术以及业务逻辑,帮助您更好地理解和准备答疑。
|
||||
|
||||
## 一、Spring Boot 核心原理
|
||||
|
||||
Spring Boot 是一个用于简化新 Spring 应用的初始搭建以及开发过程的框架。其核心原理主要体现在以下几个方面:
|
||||
|
||||
### 1. 自动配置 (Auto-Configuration) - 智能的“管家”
|
||||
|
||||
您可以将 Spring Boot 的自动配置想象成一个非常智能的“管家”。在传统的 Spring 开发中,您需要手动配置很多东西,比如数据库连接、We你b 服务器等,就像您需要亲自告诉管家每一个细节:如何烧水、如何扫地。
|
||||
|
||||
而 Spring Boot 的“管家”则会观察您家里添置了什么新东西(即您在项目中加入了什么依赖),然后自动地把这些东西配置好,让它们能正常工作。
|
||||
|
||||
**它是如何工作的?**
|
||||
|
||||
1. **观察您的“购物清单” (`pom.xml`)**:当您在项目的 `pom.xml` 文件中加入一个 `spring-boot-starter-*` 依赖,比如 `spring-boot-starter-web`,就等于告诉“管家”:“我需要开发一个网站。”
|
||||
|
||||
2. **自动准备所需工具**:看到这个“购物清单”后,“管家”会立刻为您准备好一套完整的网站开发工具:
|
||||
* 一个嵌入式的 **Tomcat 服务器**,这样您就不用自己安装和配置服务器了。
|
||||
* 配置好 **Spring MVC** 框架,这是处理网页请求的核心工具。
|
||||
* 设置好处理 JSON 数据的工具 (Jackson),方便前后端通信。
|
||||
|
||||
3. **背后的魔法 (`@EnableAutoConfiguration`)**:这一切的起点是您项目主启动类上的 `@SpringBootApplication` 注解,它内部包含了 `@EnableAutoConfiguration`。这个注解就是给“管家”下达“开始自动工作”命令的开关。它会去检查一个固定的清单(位于 `META-INF/spring.factories`),上面写着所有它认识的工具(自动配置类)以及何时应该启用它们。
|
||||
|
||||
**项目实例:**
|
||||
|
||||
在本项目中,因为 `pom.xml` 包含了 `spring-boot-starter-web`,所以 Spring Boot 自动为您配置了处理 Web 请求的所有环境。这就是为什么您可以在 `com.dne.ems.controller` 包下的任何一个 Controller(例如 `AuthController`)中直接使用 `@RestController` 和 `@PostMapping` 这样的注解来定义 API 接口,而无需编写任何一行 XML 配置来启动 Web 服务或配置 Spring MVC。
|
||||
|
||||
简单来说,**自动配置就是 Spring Boot 替您完成了大部分繁琐、重复的配置工作,让您可以专注于编写业务代码。**
|
||||
|
||||
### 2. 起步依赖 (Starter Dependencies) - “主题工具箱”
|
||||
|
||||
如果说自动配置是“智能管家”,那么起步依赖就是“管家”使用的“主题工具箱”。您不需要告诉管家需要买钉子、锤子、螺丝刀……您只需要说:“我需要一个木工工具箱。”
|
||||
|
||||
起步依赖 (`spring-boot-starter-*`) 就是这样的“主题工具箱”。每一个 starter 都包含了一整套用于某个特定任务的、经过测试、版本兼容的依赖。
|
||||
|
||||
**项目实例:**
|
||||
|
||||
- **`spring-boot-starter-web`**: 这是“Web 开发工具箱”。它不仅包含了 Spring MVC,还包含了内嵌的 Tomcat 服务器和处理验证的库。您只需要引入这一个依赖,所有 Web 开发的基础环境就都准备好了。
|
||||
|
||||
- **`spring-boot-starter-data-jpa`**: 这是“数据库操作工具箱”。它打包了与数据库交互所需的一切,包括 Spring Data JPA、Hibernate (JPA 的一种实现) 和数据库连接池 (HikariCP)。您引入它之后,就可以直接在 `com.dne.ems.repository` 包下编写 `JpaRepository` 接口来进行数据库操作,而无需关心如何配置 Hibernate 或事务管理器。
|
||||
|
||||
- **`spring-boot-starter-security`**: 这是“安全管理工具箱”。引入它之后,Spring Security 框架就被集成进来,提供了认证和授权的基础功能。您可以在 `com.dne.ems.security.SecurityConfig` 中看到对这个“工具箱”的具体配置,比如定义哪些 API 需要登录才能访问。
|
||||
|
||||
**优势总结:**
|
||||
|
||||
- **简化依赖**:您不必再手动添加一长串的单个依赖项。
|
||||
- **避免冲突**:Spring Boot 已经为您管理好了这些依赖之间的版本,您不必再担心因为版本不兼容而导致的各种奇怪错误。
|
||||
|
||||
通过使用这些“工具箱”,您可以非常快速地搭建起一个功能完备的应用程序框架。
|
||||
|
||||
### 3. 嵌入式 Web 服务器
|
||||
|
||||
Spring Boot 内嵌了常见的 Web 服务器,如 Tomcat、Jetty 或 Undertow。这意味着您不需要将应用程序打包成 WAR 文件部署到外部服务器,而是可以直接将应用程序打包成一个可执行的 JAR 文件,通过 `java -jar` 命令来运行。
|
||||
|
||||
- **优势**:简化了部署流程,便于持续集成和持续部署 (CI/CD)。
|
||||
|
||||
## 二、前后端分离与交互原理
|
||||
|
||||
本项目采用前后端分离的架构,前端(如 Vue.js)和后端(Spring Boot)是两个独立的项目,它们之间通过 API 进行通信。
|
||||
|
||||
### 1. RESTful API
|
||||
|
||||
后端通过暴露一组 RESTful API 来提供服务。REST (Representational State Transfer) 是一种软件架构风格,它定义了一组用于创建 Web 服务的约束。核心思想是,将应用中的所有事物都看作资源,每个资源都有一个唯一的标识符 (URI)。
|
||||
|
||||
- **HTTP 方法**:
|
||||
- `GET`:获取资源。
|
||||
- `POST`:创建新资源。
|
||||
- `PUT` / `PATCH`:更新资源。
|
||||
- `DELETE`:删除资源。
|
||||
|
||||
### 2. JSON (JavaScript Object Notation)
|
||||
|
||||
前后端之间的数据交换格式通常是 JSON。当浏览器向后端发送请求时,它可能会在请求体中包含 JSON 数据。当后端响应时,它会将 Java 对象序列化为 JSON 字符串返回给前端。
|
||||
|
||||
- **Spring Boot 中的实现**:Spring Boot 默认使用 Jackson 库来处理 JSON 的序列化和反序列化。当 Controller 的方法参数有 `@RequestBody` 注解时,Spring 会自动将请求体中的 JSON 转换为 Java 对象。当方法有 `@ResponseBody` 或类有 `@RestController` 注解时,Spring 会自动将返回的 Java 对象转换为 JSON。
|
||||
|
||||
### 3. 认证与授权 (JWT)
|
||||
|
||||
在前后端分离架构中,常用的认证机制是 JSON Web Token (JWT)。
|
||||
|
||||
- **流程**:
|
||||
1. 用户使用用户名和密码登录。
|
||||
2. 后端验证凭据,如果成功,则生成一个 JWT 并返回给前端。
|
||||
3. 前端将收到的 JWT 存储起来(例如,在 `localStorage` 或 `sessionStorage` 中)。
|
||||
4. 在后续的每个请求中,前端都会在 HTTP 请求的 `Authorization` 头中携带这个 JWT。
|
||||
5. 后端的安全过滤器会拦截每个请求,验证 JWT 的有效性。如果验证通过,则允许访问受保护的资源。
|
||||
|
||||
## 三、项目业务逻辑与分层结构分析
|
||||
|
||||
本项目是一个环境管理系统 (EMS),其代码结构遵循经典的分层架构模式。
|
||||
|
||||
### 1. 分层结构概述
|
||||
|
||||
```
|
||||
+----------------------------------------------------+
|
||||
| Controller (表现层) |
|
||||
| (处理 HTTP 请求, 调用 Service, 返回 JSON 响应) |
|
||||
+----------------------+-----------------------------+
|
||||
| (调用)
|
||||
+----------------------v-----------------------------+
|
||||
| Service (业务逻辑层) |
|
||||
| (实现核心业务逻辑, 事务管理) |
|
||||
+----------------------+-----------------------------+
|
||||
| (调用)
|
||||
+----------------------v-----------------------------+
|
||||
| Repository (数据访问层) |
|
||||
| (通过 Spring Data JPA 与数据库交互) |
|
||||
+----------------------+-----------------------------+
|
||||
| (操作)
|
||||
+----------------------v-----------------------------+
|
||||
| Model (领域模型) |
|
||||
| (定义数据结构, 对应数据库表) |
|
||||
+----------------------------------------------------+
|
||||
```
|
||||
|
||||
### 2. 各层详细分析
|
||||
|
||||
#### a. Model (领域模型)
|
||||
|
||||
位于 `com.dne.ems.model` 包下,是应用程序的核心。这些是简单的 Java 对象 (POJO),使用 JPA 注解(如 `@Entity`, `@Table`, `@Id`, `@Column`)映射到数据库中的表。
|
||||
|
||||
- **核心实体**:
|
||||
- `UserAccount`: 用户账户信息,包含角色、状态等。
|
||||
- `Task`: 任务实体,包含任务状态、描述、位置等信息。
|
||||
- `Feedback`: 公众或用户提交的反馈信息。
|
||||
- `Grid`: 地理网格信息,用于管理和分配任务区域。
|
||||
- `Attachment`: 附件信息,如上传的图片。
|
||||
|
||||
#### b. Repository (数据访问层)
|
||||
|
||||
位于 `com.dne.ems.repository` 包下。这些是接口,继承自 Spring Data JPA 的 `JpaRepository`。开发者只需要定义接口,Spring Data JPA 会在运行时自动为其提供实现,从而极大地简化了数据访问代码。
|
||||
|
||||
- **示例**:`TaskRepository` 提供了对 `Task` 实体的 CRUD (创建、读取、更新、删除) 操作,以及基于方法名约定的查询功能(如 `findByStatus(TaskStatus status)`)。
|
||||
|
||||
#### c. Service (业务逻辑层)
|
||||
|
||||
位于 `com.dne.ems.service` 包下,是业务逻辑的核心实现。Service 层封装了应用程序的业务规则和流程,并负责协调多个 Repository 来完成一个完整的业务操作。事务管理也通常在这一层通过 `@Transactional` 注解来声明。
|
||||
|
||||
- **主要 Service 及其职责**:
|
||||
- `AuthService`: 处理用户认证,如登录、注册。
|
||||
- `TaskManagementService`: 负责任务的创建、更新、查询等核心管理功能。
|
||||
- `TaskAssignmentService`: 负责任务的分配逻辑,如自动分配或手动指派。
|
||||
- `SupervisorService`: 主管相关的业务逻辑,如审核任务。
|
||||
- `GridWorkerTaskService`: 网格员的任务处理逻辑,如提交任务进度。
|
||||
- `FeedbackService`: 处理公众反馈,可能包括创建任务等后续操作。
|
||||
- `PersonnelService`: 员工管理,如添加、查询用户信息。
|
||||
|
||||
- **层间关系**:Service 通常会注入 (DI) 一个或多个 Repository 来操作数据。一个 Service 也可能调用另一个 Service 来复用业务逻辑。
|
||||
|
||||
#### d. Controller (表现层)
|
||||
|
||||
位于 `com.dne.ems.controller` 包下。Controller 负责接收来自客户端的 HTTP 请求,解析请求参数,然后调用相应的 Service 来处理业务逻辑。最后,它将 Service 返回的数据(通常是 DTO)封装成 HTTP 响应(通常是 JSON 格式)返回给客户端。
|
||||
|
||||
- **主要 Controller 及其职责**:
|
||||
- `AuthController`: 暴露 `/api/auth/login`, `/api/auth/register` 等认证相关的端点。
|
||||
- `TaskManagementController`: 提供任务管理的 RESTful API,如 `GET /api/tasks`, `POST /api/tasks`。
|
||||
- `SupervisorController`: 提供主管操作的 API,如审核、分配任务。
|
||||
- `FileController`: 处理文件上传和下载。
|
||||
|
||||
- **DTO (Data Transfer Object)**:位于 `com.dne.ems.dto` 包下。Controller 和 Service 之间,以及 Controller 和前端之间,通常使用 DTO 来传输数据。这样做的好处是可以避免直接暴露数据库实体,并且可以根据前端页面的需要来定制数据结构,避免传输不必要的信息。
|
||||
|
||||
### 3. 安全 (Security)
|
||||
|
||||
位于 `com.dne.ems.security` 包下。使用 Spring Security 来提供全面的安全服务。
|
||||
|
||||
- `SecurityConfig`: 配置安全规则,如哪些 URL 是公开的,哪些需要认证,以及配置 JWT 过滤器。
|
||||
- `JwtAuthenticationFilter`: 一个自定义的过滤器,在每个请求到达 Controller 之前执行。它从请求头中提取 JWT,验证其有效性,并将用户信息加载到 Spring Security 的上下文中。
|
||||
- `UserDetailsServiceImpl`: 实现了 Spring Security 的 `UserDetailsService` 接口,负责根据用户名从数据库加载用户信息(包括密码和权限)。
|
||||
|
||||
## 四、总结
|
||||
|
||||
这个 Spring Boot 项目是一个典型的、结构清晰的、基于 RESTful API 的前后端分离应用。它有效地利用了 Spring Boot 的自动配置和起步依赖来简化开发,并通过分层架构将表现、业务逻辑和数据访问清晰地分离开来,使得项目易于理解、维护和扩展。
|
||||
|
||||
希望这份文档能帮助您在答疑中充满信心!
|
||||
|
||||
## 五、为小白定制:项目代码结构与工作流程详解
|
||||
|
||||
为了让您彻底理解代码是如何组织的,我们把整个后端项目想象成一个分工明确的大公司。
|
||||
|
||||
### 1. 公司各部门职责 (包/文件夹的作用)
|
||||
|
||||
- **`com.dne.ems.config` (后勤与配置部)**
|
||||
- **职责**: 负责应用的各种基础配置。比如 `WebClientConfig` 是配置网络请求工具的,`WebSocketConfig` 是配置实时通讯的,`DataInitializer` 则是在项目启动时初始化一些默认数据(比如默认的管理员账号)。这个部门确保了其他所有部门的工具和环境都是准备好的。
|
||||
|
||||
- **`com.dne.ems.model` (产品设计部)**
|
||||
- **职责**: 定义公司的核心“产品”是什么样的。这里的“产品”就是数据。例如,`UserAccount.java` 定义了“用户”有哪些属性(姓名、密码、角色等),`Task.java` 定义了“任务”有哪些属性(标题、状态、截止日期等)。它们是整个公司的业务基础,决定了公司要处理什么信息。这些文件直接对应数据库里的表结构。
|
||||
|
||||
- **`com.dne.ems.repository` (仓库管理部)**
|
||||
- **职责**: 专门负责和数据库这个大“仓库”打交道。当需要存取数据时,其他部门不会直接去仓库,而是会通知仓库管理员。例如,`TaskRepository` 提供了所有操作 `Task` 表的方法,如保存一个新任务、根据ID查找一个任务。这个部门使用了 Spring Data JPA 技术,所以代码看起来很简单,但功能强大。
|
||||
|
||||
- **`com.dne.ems.service` (核心业务部)**
|
||||
- **职责**: 这是公司的核心部门,负责处理所有实际的业务逻辑。一个业务操作可能很复杂,需要协调多个部门。例如,`TaskManagementService` (任务管理服务) 在创建一个新任务时,可能需要:
|
||||
1. 调用 `TaskRepository` 将任务信息存入数据库。
|
||||
2. 调用 `UserAccountRepository` 查找合适的执行人。
|
||||
3. 调用 `NotificationService` (如果存在的话) 发送通知。
|
||||
- **`impl` 子目录**: `service` 包下通常是接口 (定义了“能做什么”),而 `impl` (implementation) 包下是这些接口的具体实现 (定义了“具体怎么做”)。这是为了“面向接口编程”,是一种良好的编程习惯。
|
||||
|
||||
- **`com.dne.ems.controller` (客户服务与接待部)**
|
||||
- **职责**: 这是公司的“前台”,直接面向客户(在这里就是前端浏览器或App)。它接收客户的请求(HTTP 请求),然后将请求传达给相应的业务部门 (`Service`) 去处理。处理完成后,它再把结果(通常是 JSON 格式的数据)返回给客户。
|
||||
- 例如,`TaskManagementController` 里的一个 `createTask` 方法,会接收前端发来的创建任务的请求,然后调用 `TaskManagementService` 的 `createTask` 方法来真正执行创建逻辑。
|
||||
|
||||
- **`com.dne.ems.dto` (数据包装与运输部)**
|
||||
- **职责**: 负责数据的包装和运输。直接把数据库里的原始数据 (`Model`) 给客户看是不安全也不专业的。DTO (Data Transfer Object) 就是专门用于在各部门之间,特别是“前台”(`Controller`)和客户(前端)之间传递数据的“包装盒”。
|
||||
- 例如,`TaskDTO` 可能只包含任务的ID、标题和状态,而隐藏了创建时间、更新时间等前端不需要的敏感信息。
|
||||
|
||||
- **`com.dne.ems.security` (安保部)**
|
||||
- **职责**: 负责整个公司的安全。`SecurityConfig` 定义了公司的安保规则(比如哪些地方需要门禁卡才能进),`JwtAuthenticationFilter` 就是门口的保安,每个请求进来都要检查它的“门禁卡”(JWT Token) 是否有效。
|
||||
|
||||
- **`com.dne.ems.exception` (风险与危机处理部)**
|
||||
- **职责**: 处理各种突发异常情况。当业务流程中出现错误时(比如找不到用户、数据库连接失败),`GlobalExceptionHandler` 会捕获这些错误,并给出一个统一、友好的错误提示给前端,而不是让程序崩溃。
|
||||
|
||||
### 2. 一次典型的请求流程:用户登录
|
||||
|
||||
让我们通过“用户登录”这个简单的例子,看看这些部门是如何协同工作的:
|
||||
|
||||
1. **客户上门 (前端 -> Controller)**: 用户在前端页面输入用户名和密码,点击登录。前端将这些信息打包成一个 JSON 对象,发送一个 HTTP POST 请求到后端的 `/api/auth/login` 地址。
|
||||
|
||||
2. **前台接待 (Controller)**: `AuthController` 接收到这个请求。它看到地址是 `/login`,于是调用 `login` 方法。它从请求中取出 JSON 数据,并将其转换为 `LoginRequest` 这个 DTO 对象。
|
||||
|
||||
3. **转交业务部门 (Controller -> Service)**: `AuthController` 自己不处理登录逻辑,它调用 `AuthService` 的 `login` 方法,并将 `LoginRequest` 这个 DTO 传递过去。
|
||||
|
||||
4. **核心业务处理 (Service)**: `AuthService` 开始处理登录:
|
||||
a. 它首先需要验证用户名是否存在,于是它请求 **仓库管理部** (`UserAccountRepository`):“请帮我根据这个用户名 (`loginRequest.getUsername()`) 查一下有没有这个人。”
|
||||
b. `UserAccountRepository` 从数据库中查找到对应的 `UserAccount` (Model) 信息,返回给 `AuthService`。
|
||||
c. `AuthService` 拿到用户信息后,会使用密码加密工具,验证用户提交的密码和数据库中存储的加密密码是否匹配。
|
||||
d. 如果验证成功,`AuthService` 会请求 **安保部** (`JwtService`):“请为这位用户生成一张有时效的门禁卡 (JWT Token)。”
|
||||
|
||||
5. **返回处理结果 (Service -> Controller -> 前端)**: `JwtService` 生成 Token 后返回给 `AuthService`。`AuthService` 将 Token 包装在一个 `JwtAuthenticationResponse` DTO 中,返回给 `AuthController`。`AuthController` 再将这个包含 Token 的 DTO 转换成 JSON 格式,作为 HTTP 响应返回给前端。
|
||||
|
||||
6. **客户拿到凭证 (前端)**: 前端收到包含 Token 的响应,就知道登录成功了。它会把这个 Token 保存起来,在之后访问需要权限的页面时,都会带上这张“门禁卡”。
|
||||
|
||||
通过这个流程,您可以看到,一个简单的请求背后是多个“部门”按照明确的职责划分,层层调用、协同工作的结果。这种结构使得代码逻辑清晰,易于维护和扩展。
|
||||
嗯
|
||||
## 六、核心业务流程与关键机制分析
|
||||
|
||||
下面,我们将梳理出本项目的几个核心业务流程和支撑这些流程的关键技术机制,并详细说明它们涉及的层级和文件,让您清晰地看到数据和指令是如何在系统中流转的。
|
||||
|
||||
### (一) 核心业务流程
|
||||
|
||||
#### 流程一:用户认证与授权 (Authentication & Authorization)
|
||||
|
||||
**目标**:保障系统安全,确保只有授权用户才能访问受保护的资源。
|
||||
|
||||
**执行路径**:
|
||||
|
||||
1. **注册 (`signup`)**
|
||||
* **入口**: `AuthController.signup()`
|
||||
* **业务逻辑**: `AuthService.signup()`
|
||||
* 验证邮箱和验证码的有效性 (`VerificationCodeService`)。
|
||||
* 检查邮箱是否已注册 (`UserAccountRepository`)。
|
||||
* 对密码进行加密 (`PasswordEncoder`)。
|
||||
* 创建并保存新的 `UserAccount` 实体。
|
||||
|
||||
2. **登录 (`login`)**
|
||||
* **入口**: `AuthController.login()`
|
||||
* **业务逻辑**: `AuthService.login()`
|
||||
* 通过 Spring Security 的 `AuthenticationManager` 验证用户名和密码。
|
||||
* 如果认证成功,调用 `JwtService` 生成 JWT。
|
||||
* 返回包含 JWT 的响应给前端。
|
||||
|
||||
3. **访问受保护资源**
|
||||
* **安全过滤器**: `JwtAuthenticationFilter`
|
||||
* 拦截所有请求,从 `Authorization` 请求头中提取 JWT。
|
||||
* 验证 JWT 的有效性 (`JwtService`)。
|
||||
* 如果有效,从 JWT 中解析出用户信息,并构建一个 `UsernamePasswordAuthenticationToken`,设置到 Spring Security 的 `SecurityContextHolder` 中,完成授权。
|
||||
|
||||
#### 流程二:公众反馈与任务转化 (Feedback to Task)
|
||||
|
||||
**目标**:将公众通过开放接口提交的反馈(如环境问题)转化为系统内部的可追踪任务。
|
||||
|
||||
**执行路径**:
|
||||
|
||||
1. **提交反馈**
|
||||
* **入口**: `PublicController.submitFeedback()`
|
||||
* **业务逻辑**: `FeedbackService.createFeedback()`
|
||||
* 接收 `FeedbackDTO`,包含反馈内容和可选的附件。
|
||||
* 处理文件上传(如果存在),调用 `FileStorageService` 保存文件,并将附件信息与反馈关联。
|
||||
* 保存 `Feedback` 实体到数据库。
|
||||
|
||||
2. **反馈审核与任务创建 (由管理员操作)**
|
||||
* **入口**: `SupervisorController.approveFeedbackAndCreateTask()` (假设存在此接口)
|
||||
* **业务逻辑**: `SupervisorService.processFeedback()`
|
||||
* 管理员审核反馈内容。
|
||||
* 如果反馈有效,调用 `TaskManagementService.createTaskFromFeedback()`,基于反馈信息创建一个新的 `Task`。
|
||||
|
||||
#### 流程三:任务生命周期管理 (Task Lifecycle)
|
||||
|
||||
**目标**:完整地管理一个任务从创建、分配、执行到完成的全过程。
|
||||
|
||||
**执行路径**:
|
||||
|
||||
1. **任务创建**
|
||||
* **入口**: `TaskManagementController.createTask()`
|
||||
* **业务逻辑**: `TaskManagementService.createTask()`
|
||||
* 创建 `Task` 实体并设置初始状态(如 `PENDING_ASSIGNMENT`)。
|
||||
|
||||
2. **任务分配**
|
||||
* **入口**: `SupervisorController.assignTask()`
|
||||
* **业务逻辑**: `TaskAssignmentService.assignTaskToWorker()`
|
||||
* 将任务 (`Task`) 与一个网格员 (`GridWorker`) 关联起来,创建 `Assignment` 记录。
|
||||
* 更新任务状态为 `ASSIGNED`。
|
||||
|
||||
3. **任务执行与更新**
|
||||
* **入口**: `GridWorkerTaskController.updateTaskStatus()`
|
||||
* **业务逻辑**: `GridWorkerTaskService.updateTaskProgress()`
|
||||
* 网格员提交任务进度或结果,可附带图片等附件 (`FileStorageService`)。
|
||||
* 更新任务状态(如 `IN_PROGRESS`, `COMPLETED`)。
|
||||
|
||||
4. **任务审核与关闭**
|
||||
* **入口**: `SupervisorController.reviewTask()`
|
||||
* **业务逻辑**: `SupervisorService.reviewAndCloseTask()`
|
||||
* 主管审核已完成的任务。
|
||||
* 如果合格,将任务状态更新为 `CLOSED`。如果不合格,可打回 (`REJECTED`)。
|
||||
|
||||
#### 流程四:数据可视化与决策支持 (Dashboard & AI)
|
||||
|
||||
**目标**:为管理层提供数据洞察,并通过 AI 功能辅助决策。
|
||||
|
||||
**执行路径**:
|
||||
|
||||
1. **仪表盘数据**
|
||||
* **入口**: `DashboardController` 中的各个接口,如 `getTaskStats()`, `getRecentActivities()`。
|
||||
* **业务逻辑**: `DashboardService`
|
||||
* 调用多个 `Repository`(如 `TaskRepository`, `FeedbackRepository`)进行数据聚合查询,统计任务状态、反馈趋势等。
|
||||
* 返回 DTO 给前端进行图表展示。
|
||||
|
||||
2. **AI 辅助功能**
|
||||
* **文本审核**: `AiReviewService.reviewText()` 可能被用于自动审核反馈内容或评论,识别敏感信息。
|
||||
* **路径规划**: `AStarService.findPath()` 用于计算两点之间的最优路径,可辅助网格员规划任务路线。
|
||||
|
||||
### (二) 关键支撑机制
|
||||
|
||||
除了核心业务流程,系统还包含一系列关键的技术机制来保证其健壮、安全和可维护性。
|
||||
|
||||
1. **文件上传与管理**
|
||||
* **位置**: `FileStorageService`, `FileController`
|
||||
* **作用**: 提供统一的文件存储和访问服务。无论是用户头像、反馈附件还是任务报告,都通过此服务进行处理,实现了与具体存储位置(本地文件系统或云存储)的解耦。
|
||||
|
||||
2. **邮件与验证码服务**
|
||||
* **位置**: `MailService`, `VerificationCodeService`
|
||||
* **作用**: 负责发送邮件(如注册验证、密码重置)和管理验证码的生成与校验,是保障账户安全的重要环节。
|
||||
|
||||
3. **登录安全与尝试锁定**
|
||||
* **位置**: `LoginAttemptService`, `AuthenticationFailureEventListener`
|
||||
* **作用**: 监听登录失败事件 (`AuthenticationFailureListener`),并通过 `LoginAttemptService` 记录特定 IP 的失败次数。当超过阈值时,会暂时锁定该 IP 的登录权限,有效防止暴力破解攻击。
|
||||
|
||||
4. **A* 路径规划算法**
|
||||
* **位置**: `AStarService`, `PathfindingController`
|
||||
* **作用**: 实现了 A* 寻路算法,这是一个独立的功能模块,可以根据地图数据(网格 `Grid`)计算最优路径,为其他业务(如任务路线规划)提供支持。
|
||||
|
||||
5. **系统事件处理机制**
|
||||
* **位置**: `event` 和 `listener` 包
|
||||
* **作用**: 基于 Spring 的事件驱动模型,实现系统内各组件的解耦。例如,当一个用户注册成功后,可以发布一个 `UserRegistrationEvent` 事件,而邮件发送监听器 (`EmailNotificationListener`) 和新用户欢迎监听器 (`WelcomeBonusListener`) 可以分别监听并处理此事件,而无需在注册服务中硬编码这些逻辑。
|
||||
|
||||
6. **全局异常处理**
|
||||
* **位置**: `GlobalExceptionHandler`
|
||||
* **作用**: 捕获整个应用中抛出的未处理异常,并根据异常类型返回统一、规范的错误响应给前端。这避免了将原始的、可能包含敏感信息的堆栈跟踪暴露给用户,并提升了用户体验。
|
||||
|
||||
7. **自定义数据校验**
|
||||
* **位置**: `validation` 包 (如 `PasswordValidator`)
|
||||
* **作用**: 实现自定义的、复杂的校验逻辑。例如,`@ValidPassword` 注解可以确保用户设置的密码符合特定的强度要求(如长度、包含数字和特殊字符等)。
|
||||
|
||||
8. **数据持久化与查询 (JPA)**
|
||||
* **位置**: `repository` 包
|
||||
* **作用**: 利用 Spring Data JPA,通过定义接口 (`extends JpaRepository`) 的方式,极大地简化了数据库的 CRUD 操作和查询。开发者无需编写 SQL 语句,JPA 会自动根据方法名或注解生成相应的查询。
|
||||
|
||||
9. **API 数据契约 (DTO)**
|
||||
* **位置**: `dto` 包
|
||||
* **作用**: 数据传输对象 (Data Transfer Object) 是前后端分离架构中的关键实践。它作为 API 的“数据契约”,明确了接口需要什么数据、返回什么数据,实现了表现层与领域模型的解耦,使得双方可以独立演进,同时避免了敏感信息的泄露。
|
||||
|
||||
10. **应用配置与初始化**
|
||||
* **位置**: `config` 包, `DataInitializer`
|
||||
* **作用**: `config` 包集中管理了应用的所有配置类,如安全配置 (`SecurityConfig`)、Web 配置等。`DataInitializer` 则利用 `CommandLineRunner` 接口,在应用启动后执行一次性任务,如创建默认管理员账户、初始化基础数据等,确保了应用开箱即用的能力。
|
||||
* **密码加密**: 使用 `PasswordEncoder` 对用户密码进行加密,增强安全性。
|
||||
* **创建用户实体**: 创建一个新的 `UserAccount` 对象 (`Model`),并填充信息。
|
||||
|
||||
3. **Repository (数据访问层)**
|
||||
* **文件**: `com.dne.ems.repository.UserAccountRepository.java`
|
||||
* **方法**: `save(UserAccount user)`
|
||||
* **作用**: `AuthService` 调用此方法,将新创建的 `UserAccount` 对象持久化到数据库中。
|
||||
|
||||
4. **Model (领域模型)**
|
||||
* **文件**: `com.dne.ems.model.UserAccount.java`
|
||||
* **作用**: 定义了用户账户的数据结构,是数据库中 `user_accounts` 表的映射。
|
||||
|
||||
### 流程二:任务创建与分配
|
||||
|
||||
**目标**:主管或管理员根据一个已批准的反馈,创建一个新任务,并将其分配给一个网格员。
|
||||
|
||||
**执行路径**:
|
||||
|
||||
1. **Controller (表现层)**
|
||||
* **文件**: `com.dne.ems.controller.TaskManagementController.java`
|
||||
* **方法**: `createTaskFromFeedback(long feedbackId, TaskFromFeedbackRequest request)`
|
||||
* **作用**: 接收 `/api/management/tasks/feedback/{feedbackId}/create-task` POST 请求。它将反馈ID和任务创建请求 (`TaskFromFeedbackRequest` DTO) 传递给 Service 层。
|
||||
|
||||
2. **Service (业务逻辑层)**
|
||||
* **文件**: `com.dne.ems.service.impl.TaskManagementServiceImpl.java`
|
||||
* **方法**: `createTaskFromFeedback(long feedbackId, TaskFromFeedbackRequest request)`
|
||||
* **作用**: 实现核心的创建和分配逻辑:
|
||||
* **查找反馈**: 调用 `FeedbackRepository` 找到对应的 `Feedback` (`Model`)。
|
||||
* **查找负责人**: 调用 `UserAccountRepository` 找到指定的负责人 `UserAccount` (`Model`)。
|
||||
* **创建任务**: 创建一个新的 `Task` 对象 (`Model`),并从 `Feedback` 和请求 DTO 中填充任务信息(如描述、截止日期、严重性等)。
|
||||
* **设置状态**: 将任务的初始状态设置为 `ASSIGNED`。
|
||||
|
||||
3. **Repository (数据访问层)**
|
||||
* **文件**: `com.dne.ems.repository.TaskRepository.java`
|
||||
* **方法**: `save(Task task)`
|
||||
* **作用**: `TaskManagementService` 调用此方法,将新创建的 `Task` 对象保存到数据库。
|
||||
* **涉及的其他 Repository**: `FeedbackRepository` 和 `UserAccountRepository` 用于在业务逻辑中获取必要的数据。
|
||||
|
||||
4. **Model (领域模型)**
|
||||
* **文件**: `com.dne.ems.model.Task.java`
|
||||
* **作用**: 定义了任务的数据结构。
|
||||
* **涉及的其他 Model**: `Feedback.java` 和 `UserAccount.java` 作为数据来源。
|
||||
|
||||
### 流程三:网格员处理任务与提交反馈
|
||||
|
||||
**目标**:网格员查看自己的任务,执行任务,并提交处理结果(包括评论和附件)。
|
||||
|
||||
**执行路径**:
|
||||
|
||||
1. **Controller (表现层)**
|
||||
* **文件**: `com.dne.ems.controller.GridWorkerTaskController.java`
|
||||
* **方法**: `submitTask(long taskId, String comments, List<MultipartFile> files)`
|
||||
* **作用**: 接收 `/api/worker/{taskId}/submit` POST 请求。这是一个 `multipart/form-data` 请求,因为它同时包含了文本(评论)和文件。Controller 将这些信息传递给 Service 层。
|
||||
|
||||
2. **Service (业务逻辑层)**
|
||||
* **文件**: `com.dne.ems.service.impl.GridWorkerTaskServiceImpl.java`
|
||||
* **方法**: `submitTask(long taskId, String comments, List<MultipartFile> files)`
|
||||
* **作用**: 处理任务提交的业务逻辑:
|
||||
* **查找任务**: 调用 `TaskRepository` 找到当前需要处理的 `Task` (`Model`)。
|
||||
* **验证权限**: 确保当前登录的用户就是这个任务的负责人。
|
||||
* **处理文件上传**: 如果有附件,调用 `FileStorageService` 将文件保存到服务器,并创建 `Attachment` (`Model`) 对象。
|
||||
* **更新任务状态**: 将任务状态更新为 `SUBMITTED` 或 `PENDING_REVIEW`。
|
||||
* **保存评论和附件信息**: 将评论和附件信息关联到任务上。
|
||||
|
||||
3. **Repository (数据访问层)**
|
||||
* **文件**: `com.dne.ems.repository.TaskRepository.java`
|
||||
* **方法**: `save(Task task)`
|
||||
* **作用**: `GridWorkerTaskService` 在更新了任务状态和信息后,调用此方法将 `Task` 对象的变化持久化到数据库。
|
||||
* **涉及的其他 Repository**: `AttachmentRepository` (如果适用) 用于保存附件信息。
|
||||
|
||||
4. **Model (领域模型)**
|
||||
* **文件**: `com.dne.ems.model.Task.java`
|
||||
* **作用**: 任务数据在此流程中被更新。
|
||||
* **涉及的其他 Model**: `Attachment.java` 用于表示上传的文件。
|
||||
* **密码加密**: 使用 `PasswordEncoder` 对用户提交的明文密码进行加密,确保数据库中存储的是密文,保障安全。
|
||||
* **创建用户实体**: 创建一个新的 `UserAccount` (Model) 对象,并将注册信息(包括加密后的密码和角色)设置到该对象中。
|
||||
|
||||
3. **Service -> Repository (数据访问层)**
|
||||
* **文件**: `com.dne.ems.repository.UserAccountRepository.java`
|
||||
* **方法**: `save(UserAccount userAccount)`
|
||||
* **作用**: Service 层调用此方法,将填充好数据的 `UserAccount` 实体对象持久化到数据库中。Spring Data JPA 会自动生成对应的 SQL `INSERT` 语句来完成操作。
|
||||
|
||||
4. **返回结果**: 数据成功存入数据库后,操作结果会逐层返回,最终 `AuthController` 会向前端返回一个成功的响应消息。
|
||||
|
||||
### 流程二:任务的创建与自动分配
|
||||
|
||||
**目标**:系统管理员或主管创建一个新的环境问题任务,并由系统自动分配给相应网格内的网格员。
|
||||
|
||||
**执行路径**:
|
||||
|
||||
1. **前端 -> Controller (表现层)**
|
||||
* **文件**: `com.dne.ems.controller.TaskManagementController.java`
|
||||
* **方法**: `createTask(TaskCreateRequest taskCreateRequest)`
|
||||
* **作用**: 接收 `/api/tasks` POST 请求,请求体中包含了任务的详细信息(如描述、位置、图片附件ID等),封装在 `TaskCreateRequest` DTO 中。Controller 调用 `TaskManagementService` 来处理创建逻辑。
|
||||
|
||||
2. **Controller -> Service (业务逻辑层)**
|
||||
* **文件**: `com.dne.ems.service.impl.TaskManagementServiceImpl.java`
|
||||
* **方法**: `createTask(TaskCreateRequest taskCreateRequest)`
|
||||
* **作用**: 创建任务的核心业务逻辑。
|
||||
* 创建一个新的 `Task` (Model) 实体。
|
||||
* 根据请求中的附件ID,调用 `AttachmentRepository` 查找并关联附件。
|
||||
* 设置任务的初始状态为 `PENDING` (待处理)。
|
||||
* 调用 `TaskRepository` 将新任务保存到数据库。
|
||||
* **触发任务分配**: 保存任务后,调用 `TaskAssignmentService` 来执行自动分配逻辑。
|
||||
|
||||
3. **Service -> Service (业务逻辑层内部调用)**
|
||||
* **文件**: `com.dne.ems.service.impl.TaskAssignmentServiceImpl.java`
|
||||
* **方法**: `assignTask(Task task)`
|
||||
* **作用**: 处理任务的分配逻辑。
|
||||
* 根据任务的地理位置信息,调用 `GridRepository` 找到对应的地理网格 (`Grid`)。
|
||||
* 根据网格信息,调用 `UserAccountRepository` 找到负责该网格的网格员 (`GridWorker`)。
|
||||
* 如果找到合适的网格员,则更新 `Task` 实体的 `assignee` (执行人) 字段。
|
||||
* 更新任务状态为 `ASSIGNED` (已分配)。
|
||||
* 调用 `TaskRepository` 将更新后的任务信息保存回数据库。
|
||||
* (可选) 调用通知服务,向被分配的网格员发送新任务通知。
|
||||
|
||||
4. **Service -> Repository (数据访问层)**
|
||||
* **文件**: `com.dne.ems.repository.TaskRepository.java`, `com.dne.ems.repository.GridRepository.java`, `com.dne.ems.repository.UserAccountRepository.java`
|
||||
* **作用**: 在整个流程中,Service 层会频繁地与这些 Repository 交互,以查询网格信息、查询用户信息、保存和更新任务数据。
|
||||
|
||||
### 流程三:网格员处理任务并提交反馈
|
||||
|
||||
**目标**:网格员在完成任务后,通过 App 或前端页面提交任务处理结果,包括文字描述和现场图片。
|
||||
|
||||
**执行路径**:
|
||||
|
||||
1. **前端 -> Controller (表现层)**
|
||||
* **文件**: `com.dne.ems.controller.GridWorkerTaskController.java`
|
||||
* **方法**: `submitTaskFeedback(Long taskId, TaskFeedbackRequest feedbackRequest)`
|
||||
* **作用**: 接收 `/api/worker/tasks/{taskId}/feedback` POST 请求。路径中的 `taskId` 指明了要为哪个任务提交反馈,请求体 `TaskFeedbackRequest` DTO 中包含了反馈内容和附件ID。
|
||||
|
||||
2. **Controller -> Service (业务逻辑层)**
|
||||
* **文件**: `com.dne.ems.service.impl.GridWorkerTaskServiceImpl.java`
|
||||
* **方法**: `submitTaskFeedback(Long taskId, TaskFeedbackRequest feedbackRequest)`
|
||||
* **作用**: 处理网格员提交反馈的业务逻辑。
|
||||
* 调用 `TaskRepository` 检查任务是否存在以及当前用户是否有权限操作该任务。
|
||||
* 更新 `Task` 实体的状态为 `COMPLETED` (已完成) 或 `PENDING_REVIEW` (待审核)。
|
||||
* 创建一个新的 `Feedback` (Model) 实体,将反馈内容和关联的 `Task` 设置进去。
|
||||
* 调用 `FeedbackRepository` 将新的反馈信息保存到数据库。
|
||||
* 调用 `TaskRepository` 更新任务状态。
|
||||
|
||||
3. **Service -> Repository (数据访问层)**
|
||||
* **文件**: `com.dne.ems.repository.TaskRepository.java`, `com.dne.ems.repository.FeedbackRepository.java`
|
||||
* **作用**: `TaskRepository` 用于查询和更新任务信息,`FeedbackRepository` 用于保存新的反馈记录。
|
||||
|
||||
通过以上对核心业务流程的梳理,您可以清晰地看到,用户的每一个操作是如何触发后端系统中不同层、不同文件之间的一系列连锁反应,最终完成一个完整的业务闭环。这种清晰的、分层的架构是保证项目可维护性和扩展性的关键。
|
||||
73
ems-backend/target/classes/application.properties
Normal file
73
ems-backend/target/classes/application.properties
Normal file
@@ -0,0 +1,73 @@
|
||||
spring.application.name=ems-backend
|
||||
|
||||
# ===================================================================
|
||||
# 移除数据库相关配置,使用JSON文件存储
|
||||
# ===================================================================
|
||||
|
||||
file.upload-dir=./uploads
|
||||
# A secure key for signing JWT tokens.
|
||||
# This should be a long, random, Base64-encoded string.
|
||||
# For production, this should be stored securely (e.g., as an environment variable).
|
||||
token.signing.key=${TOKEN_SIGNING_KEY:dev-change-me}
|
||||
|
||||
# ===================================================================
|
||||
# c. Volcano Engine AI Service Configuration
|
||||
# ===================================================================
|
||||
volcano.api.url=https://ark.cn-beijing.volces.com/api/v3/chat/completions
|
||||
volcano.api.key=${VOLCANO_API_KEY:}
|
||||
volcano.model.name=deepseek-v3-250324
|
||||
|
||||
# ===================================================================
|
||||
# d. Spring AOP Configuration
|
||||
# ===================================================================
|
||||
# Force the use of CGLIB proxies for AOP
|
||||
spring.aop.proxy-target-class=true
|
||||
|
||||
# ===================================================================
|
||||
# e. Application Base URL
|
||||
# ===================================================================
|
||||
# This URL is used to construct absolute URLs for resources like uploaded files.
|
||||
# It should be the public-facing base URL of the application.
|
||||
app.base.url=${APP_BASE_URL:http://localhost:5173}
|
||||
|
||||
# ===================================================================
|
||||
# Mail Configuration for 163 SMTP
|
||||
# ===================================================================
|
||||
spring.mail.host=smtp.163.com
|
||||
spring.mail.port=465
|
||||
spring.mail.username=${SPRING_MAIL_USERNAME:}
|
||||
spring.mail.password=${SPRING_MAIL_PASSWORD:}
|
||||
spring.mail.properties.mail.smtp.auth=true
|
||||
spring.mail.properties.mail.smtp.ssl.enable=true
|
||||
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
|
||||
spring.mail.properties.mail.smtp.socketFactory.fallback=false
|
||||
spring.mail.properties.mail.smtp.socketFactory.port=465
|
||||
spring.mail.properties.mail.transport.protocol=smtp
|
||||
spring.mail.properties.mail.debug=true
|
||||
|
||||
# ===================================================================
|
||||
# Server Configuration
|
||||
# ===================================================================
|
||||
server.port=8080
|
||||
|
||||
# ===================================================================
|
||||
# Logging Configuration
|
||||
# ===================================================================
|
||||
logging.level.root=INFO
|
||||
logging.level.com.dne.ems=DEBUG
|
||||
logging.level.org.springframework.web=INFO
|
||||
logging.level.org.hibernate=WARN
|
||||
|
||||
# ===================================================================
|
||||
# JWT Configuration
|
||||
# ===================================================================
|
||||
jwt.secret=${JWT_SECRET:dev-change-me}
|
||||
jwt.expiration=86400000
|
||||
|
||||
# ===================================================================
|
||||
# Spring Task Configuration
|
||||
# ===================================================================
|
||||
spring.task.execution.pool.core-size=5
|
||||
spring.task.execution.pool.max-size=10
|
||||
spring.task.execution.pool.queue-capacity=25
|
||||
spring.task.execution.thread-name-prefix=ems-async-
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user