# 系统设计文档 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] <> [Service Layer] <> [Repository Layer] <> [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 功能模块划分 系统在功能上被划分为一系列高内聚的模块,每个模块负责一块具体的业务领域。这种划分方式便于团队分工和独立开发。 | 核心模块 | 主要职责 | 关键功能点 | | ------------------ | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | **认证与授权模块** | 管理所有用户的身份认证和访问权限 | - 用户注册/登录/登出
- JWT令牌生成与验证
- 密码重置
- 基于角色的访问控制(RBAC) | | **用户与人员管理模块** | 维护系统中的所有用户账户及其信息 | - 用户信息的增、删、改、查
- 用户角色分配与变更
- 用户状态管理(激活/禁用) | | **反馈管理模块** | 处理来自外部和内部的环境问题反馈 | - 接收公众/认证用户的反馈
- 集成AI进行内容预审核
- 人工审核与处理
- 反馈状态跟踪与统计 | | **任务管理模块** | 对具体工作任务进行全生命周期管理 | - 从反馈创建任务
- 任务分配给网格员
- 任务状态(分配、执行、完成)跟踪
- 任务审核与结果归档 | | **网格与地图模块** | 对地理空间进行网格化管理,并提供路径支持 | - 地理网格的定义与划分
- 网格员与网格的关联
- **A\*寻路算法**服务,优化任务路径 | | **决策支持模块** | 为管理层提供数据洞察和可视化报告 | - 核心业务指标(KPI)统计
- AQI、任务完成率等数据的可视化
- 生成反馈热力图 | | **个人中心模块** | 为登录用户提供个性化的信息管理和查询功能 | - 查看/修改个人资料
- 查询个人提交历史
- 查看个人操作日志 | **功能模块图** ```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 GridWorkerTaskService-->>GridWorkerTaskController: 返回Page 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` | | 任务截止日期 | ```