# 智慧清洁 SaaS 平台 - 系统流程架构图 ## 一、系统整体架构 ``` ┌─────────────────────────────────────────────────────────────────────────────────┐ │ 客户端层 │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Web 管理后台 │ │ 手机 APP │ │ 智能手表 │ │ │ │ (Vue 3 SPA) │ │ (Android/iOS)│ │ (IoT 设备) │ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │ │ HTTP/REST │ HTTP/REST │ MQTT │ └─────────┼───────────────────┼───────────────────┼──────────────────────────────┘ │ │ │ ▼ ▼ ▼ ┌─────────────────────────────────────────────────────────────────────────────────┐ │ 服务层 │ │ ┌─────────────────────────────────┐ ┌─────────────────────────────────┐ │ │ │ Web 服务 (端口 8095) │ │ Task 服务 (端口 8097) │ │ │ │ ┌───────────┐ ┌─────────────┐ │ │ ┌───────────┐ ┌────────────┐ │ │ │ │ │ Controller│ │ Interceptor │ │ │ │ XXL-Job │ │ @Scheduled │ │ │ │ │ │ (API) │ │ (认证签名) │ │ │ │ (定时任务) │ │ (消息队列) │ │ │ │ │ └─────┬─────┘ └──────┬──────┘ │ │ └─────┬─────┘ └─────┬──────┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ┌─────▼──────────────▼──────┐ │ │ ┌─────▼─────────────▼───────┐ │ │ │ │ │ Service 层 │ │ │ │ Service 层 │ │ │ │ │ └─────────────┬─────────────┘ │ │ └────────────┬──────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ ┌─────────────▼─────────────┐ │ │ ┌────────────▼──────────────┐ │ │ │ │ │ Mapper (MyBatis-Plus) │ │ │ │ Mapper (MyBatis-Plus) │ │ │ │ │ └─────────────┬─────────────┘ │ │ └────────────┬──────────────┘ │ │ │ └────────────────┼────────────────┘ └───────────────┼─────────────────┘ │ │ │ │ │ └───────────────────┼─────────────────────────────────────┼──────────────────────┘ │ │ ┌─────────▼─────────────────────────────────────▼──────────┐ │ 数据层 │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ MySQL DB1 │ │ MySQL DB2 │ │ Redis │ │ │ │ (基础信息) │ │ (业务数据) │ │ (DB4+DB5) │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ └─────────────────────────────────────────────────────────┘ ``` --- ## 二、Web 请求完整链路 ### 2.1 前端 HTTP 请求 → 后端响应 ``` ┌──────────────────────────────────────────────────────────────────────────────┐ │ 前端 (Vue 3 SPA) │ │ │ │ 用户操作 (点击按钮/提交表单) │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ ApiService (如 taskCenterService.js) │ │ │ │ 调用封装的 API 方法 │ │ │ └──────────────────────────┬──────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ requestUtils.js - Axios 请求拦截器 │ │ │ │ │ │ │ │ ① 从 sessionStorage 读取登录信息 (UUID, phone) │ │ │ │ ② 生成签名: MD5(MD5(uuid) + MD5(timestamp + phone)) │ │ │ │ ③ 设置请求头: │ │ │ │ - signature: 签名值 │ │ │ │ - uuid: 用户UUID │ │ │ │ - timestamp: 当前时间戳 │ │ │ │ - webId: 当前页面ID │ │ │ │ ④ 清除空值参数 │ │ │ │ ⑤ 设置 withCredentials: true │ │ │ └──────────────────────────┬──────────────────────────────────────┘ │ │ │ │ │ │ POST /api/xxx │ │ │ (通过 Vite proxy 代理到 localhost:8095) │ └─────────────────────────────┼────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 后端 Web 服务 (Spring Boot, 端口 8095) │ │ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ ① SystemInterceptor (请求拦截器) │ │ │ │ │ │ │ │ 排除路径: /login, /sms/sendCode, /doc.html, /swagger │ │ │ │ │ │ │ │ a. 提取请求头: uuid, signature, timestamp │ │ │ │ b. 验证时间戳 (10秒有效窗口) │ │ │ │ c. 从 Redis 查询登录态: │ │ │ │ Redis GET uuid → 获取用户信息(mobile等) │ │ │ │ d. 验证签名: │ │ │ │ 服务端重算 MD5 签名 vs 请求头签名 │ │ │ │ e. 验证通过 → 将用户信息存入 Request Attribute │ │ │ │ f. 验证失败 → 返回 code 104 (需重新登录) │ │ │ │ │ │ │ └──────────────────────────┬──────────────────────────────────────┘ │ │ │ 认证通过 │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ ② RepeatSubmitAspect (AOP 防重复提交) │ │ │ │ │ │ │ │ a. 生成锁 Key: "redis_lock_" + 请求路径 │ │ │ │ b. Redis SETNX 尝试加锁 (30秒过期) │ │ │ │ c. 获取锁 → 继续执行 │ │ │ │ d. 未获取锁 → 返回 "请勿重复提交" │ │ │ │ │ │ │ └──────────────────────────┬──────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ ③ Controller (如 TaskController) │ │ │ │ │ │ │ │ a. 接收请求参数 (@RequestBody / @RequestParam) │ │ │ │ b. 从 Request Attribute 获取当前用户信息 │ │ │ │ c. 调用 Service 层处理业务逻辑 │ │ │ │ │ │ │ └──────────────────────────┬──────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ ④ Service 层 │ │ │ │ │ │ │ │ a. 业务逻辑处理 │ │ │ │ b. 组合多个 Mapper 查询/更新 │ │ │ │ c. 操作 Redis 缓存 (读/写) │ │ │ │ d. 写入变更日志 (ChangeLog) │ │ │ │ │ │ │ └──────────────────────────┬──────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ ⑤ Mapper 层 (MyBatis-Plus) │ │ │ │ │ │ │ │ a. DB1 Mapper → MySQL xiaoqu_comples_d (基础数据) │ │ │ │ b. DB2 Mapper → MySQL xiaoqu_intellectual_d (业务数据) │ │ │ │ c. 支持分页查询 (IPage) │ │ │ │ d. 支持动态条件构造 (QueryWrapper) │ │ │ │ │ │ │ └──────────────────────────┬──────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ ⑥ SetUserAspect (AOP 审计日志) │ │ │ │ │ │ │ │ a. 记录操作人 (create_id / modify_id) │ │ │ │ b. 记录操作时间 (create_time / modify_time) │ │ │ │ c. 记录变更日志 (ChangeLog) │ │ │ │ │ │ │ └──────────────────────────┬──────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ ⑦ 构造响应 (统一返回格式) │ │ │ │ │ │ │ │ 成功: { code: 100, data: {...}, msg: "操作成功" } │ │ │ │ 失败: { code: 101, data: null, msg: "错误信息" } │ │ │ │ 未登录: { code: 104, data: null, msg: "请重新登录" } │ │ │ │ 指纹无效: { code: 113, data: null, msg: "指纹无效" } │ │ │ │ │ │ │ └──────────────────────────┬──────────────────────────────────────┘ │ │ │ │ └─────────────────────────────┼────────────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────────────────────┐ │ 前端 (Vue 3 SPA) │ │ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ requestUtils.js - Axios 响应拦截器 │ │ │ │ │ │ │ │ ① code == 100 → 返回 data 给业务组件 │ │ │ │ ② code == 104 → 清除 sessionStorage → 跳转登录页 │ │ │ │ ③ code == 113 → 指纹无效 → 跳转登录页 │ │ │ │ ④ 其他 code → 显示错误提示 (ElMessage) │ │ │ │ │ │ │ └──────────────────────────┬──────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ 页面组件渲染 │ │ │ │ │ │ │ │ a. qu-table 根据权限组动态渲染列 (fetchFields) │ │ │ │ b. qu-button-group 根据权限组动态渲染按钮 (fetchButtons) │ │ │ │ c. 数据绑定到 Vuex Store / 组件 data │ │ │ │ │ │ │ └─────────────────────────────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────────────────────────┘ ``` ### 2.2 登录认证流程 ``` 用户输入手机号 │ ▼ ┌──────────────┐ GET /sms/sendCode?mobile=xxx │ 获取验证码 │ ──────────────────────────────────► SendSmsController └──────┬───────┘ │ │ ▼ │ 生成验证码 → Redis SET │ 调用短信平台发送 │ ▼ ┌──────────────┐ POST /login {mobile, code} │ 提交登录 │ ──────────────────────────────────► LoginController └──────┬───────┘ │ │ ▼ │ ① 验证码校验 (Redis GET) │ ② 查询用户 (MySQL user表) │ ③ 生成 UUID │ ④ Redis SET uuid → 用户信息 (30天) │ ⑤ 记录登录日志 (login_log) │ ⑥ 返回: uuid + 用户信息 + 菜单权限 │ ▼ ┌──────────────┐ │ sessionStorage│ ← 存储 loginInfo(base64), uuid, phone │ 后续请求携带 │ → signature, uuid, timestamp 请求头 └──────────────┘ ``` --- ## 三、任务调度完整链路 ### 3.1 计划 → 任务生成 → 派单 → 推送 ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ 阶段一:计划创建与启用 (Web 服务) │ │ │ │ 管理员操作 (Web后台) │ │ │ │ │ ▼ │ │ POST /plan/addOrUpdatePlan │ │ │ │ │ ▼ │ │ PlanController → PlanService │ │ │ 保存计划: Plan + PlanObject + PlanOperation + PlanScenes │ │ │ + PlanUser + PlanWorkGroup │ │ ▼ │ │ POST /plan/enablePlan │ │ │ │ │ ▼ │ │ 创建 XXL-Job 定时任务 (planCreateTask) │ │ 设置 cron 表达式 (根据周期配置) │ │ Redis SET Plan:: → xxlJobId │ │ │ └───────────────────────────────┬─────────────────────────────────────────────┘ │ XXL-Job 定时触发 ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 阶段二:任务生成 (Task 服务 - PlanTimeTask) │ │ │ │ planCreateTask 触发 │ │ │ │ │ ▼ │ │ ① 检查节假日 (Holiday表) │ │ │ eliminate_type=1 且为节假日 → 跳过 │ │ ▼ │ │ ② 检查禁用标志 │ │ │ Redis GET Disable:d:: │ │ │ 如果 "1" → 存入 RebuildTask 等待恢复 │ │ ▼ │ │ ③ 生成任务 │ │ │ Redis LPUSH PlanTaskQueue ← planId │ │ ▼ │ │ ④ 计算下一次执行时间 │ │ │ 根据 circle_type (天/周/月) + circle_no 计算 │ │ │ 动态更新 XXL-Job cron 表达式 │ │ ▼ │ │ ⑤ 创建 TaskInfo 记录 (MySQL) │ │ │ 状态: status=0 (已生成) │ │ │ 关联: plan_id, district_id, task_type │ │ │ 创建: TaskScenes, TaskUser │ │ │ └───────────────────────────────┬─────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 阶段三:任务派单 (Task 服务 - TaskCorrelationSetTask, 每秒执行) │ │ │ │ Redis RPOP taskUserQueue │ │ │ │ │ ▼ │ │ ① 读取派单配置 │ │ │ Redis HMGET Dictionary: │ │ │ UserAppointFlag (是否指定人员) │ │ │ UserAreaFlag (是否限定区域) │ │ │ UserDutyFlag (是否按职责) │ │ ▼ │ │ ② 匹配可用人员 │ │ │ 查询: 用户状态=空闲, 所属站点, 技能匹配, 服务区域 │ │ │ 排序: 按优先级/距离 │ │ ▼ │ │ ③ 分配任务 │ │ │ 更新 TaskInfo.status = 1 (已匹配) / 2 (待抢单) / 3 (已接单) │ │ │ 创建/更新 TaskUser 记录 │ │ ▼ │ │ ④ 触发推送 │ │ │ Redis LPUSH taskPushQueue ← TaskPushInfo │ │ │ Redis LPUSH WatchTaskUserList ← taskUserId │ │ │ Redis LPUSH IntellectualTaskIdList ← taskId │ │ │ └──────────┬──────────────────────────────┬───────────────────────────────────┘ │ │ ▼ ▼ ┌────────────────────────┐ ┌──────────────────────────────────────────────┐ │ 阶段四A:APP推送 │ │ 阶段四B:手表推送 │ │ (TaskPushMessage, 每秒) │ │ (ScheduledTask, 每2秒) │ │ │ │ │ │ Redis RPOP │ │ Redis RPOP WatchTaskUserList │ │ taskPushQueue │ │ │ │ │ │ │ │ ▼ │ │ ▼ │ │ 构建 WatchTaskMessage │ │ 判断推送类型: │ │ (任务名/类型/位置/时间) │ │ status=1 新任务 │ │ │ │ │ status=2 抢单池 │ │ ▼ │ │ status=3 已接单 │ │ Redis LPUSH MqttWatchTaskMessage │ │ status=7/8 已取消 │ │ │ │ │ │ │ │ ▼ │ │ ▼ │ │ Redis RPOP MqttWatchTaskMessage │ │ 调用个推 SDK: │ │ │ │ │ 在线→NotificationTpl │ │ ▼ │ │ 离线→TransmissionTpl │ │ MQTT publish → 手表 (topic=imei) │ │ │ │ │ │ │ ▼ │ │ │ │ 保存 PushLog │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ ┌──────────┐ │ │ ┌──────────┐ │ │ │ 手机 APP │ │ │ │ 智能手表 │ │ │ │ 收到通知 │ │ │ │ 收到任务 │ │ │ └──────────┘ │ │ └──────────┘ │ └────────────────────────┘ └──────────────────────────────────────────────┘ ``` ### 3.2 任务状态变更推送流程 ``` 员工操作 (APP: 接单/开始/完成) │ ▼ Web API → 更新 TaskInfo.status │ ▼ Redis LPUSH IntellectualTaskIdList ← taskId │ ▼ (Task 服务, 每2秒) ┌─────────────────────────────────────────────┐ │ TodayDynamicMessage │ │ │ │ ① Redis LPOP IntellectualTaskIdList │ │ ② 查询 TaskInfo 详情 │ │ ③ 确定推送对象: │ │ - 代理人员 (Agent用户) │ │ - 物业管理员 │ │ - 任务分配人员 │ │ - 指派管理员 │ │ ④ 生成 TodayDynamic 记录 (MySQL) │ │ ⑤ Redis LPUSH MqttTaskStateMessage │ └──────────────────┬──────────────────────────┘ │ ▼ (每2秒) ┌─────────────────────────────────────────────┐ │ MqttTaskStateMessage │ │ │ │ ① Redis RPOP MqttTaskStateMessage │ │ ② 构建推送消息 │ │ ③ MQTT publish → mobile_ │ │ │ │ ┌──────────┐ │ │ │ 手机 APP │ ← 实时接收任务动态 │ │ └──────────┘ │ └─────────────────────────────────────────────┘ ``` --- ## 四、设备告警 → 维护任务流程 ``` ┌──────────────┐ │ IoT 设备 │ (纸巾机/空气净化器/传感器) │ 检测到异常 │ └──────┬───────┘ │ 告警数据 ▼ ┌──────────────────────────────────────────────────────────────┐ │ 设备告警 → Redis │ │ │ │ Redis LPUSH taskCommand ← TaskCommandInfo JSON │ │ { │ │ snCode: "设备SN", │ │ taskTypeId: 23, // 空气质量/纸巾不足等 │ │ districtId: 1, │ │ scenesId: 5 │ │ } │ └──────────────────────────┬───────────────────────────────────┘ │ ▼ (Task 服务 - TaskCreateQueue, 每秒) ┌──────────────────────────────────────────────────────────────┐ │ TaskCreateQueue.taskCommandHandle() │ │ │ │ ① Redis RPOP taskCommand (DB5) │ │ ② 检查任务开关: │ │ Redis GET DevTaskFlag: (DB4) │ │ 如果 "0" → 跳过 │ │ ③ 检查禁用标志: │ │ Redis GET Disable:d/t/p:: (DB4) │ │ 如果 "1" → 存入 RebuildTask 等待恢复 │ │ ④ 去重检查: │ │ 查询是否存在同设备未完成任务 │ │ 如果存在 → 跳过 │ │ ⑤ 创建 TaskInfo (MySQL): │ │ status=0, task_type=设备维护 │ │ 关联: sn_code, district_id, scenes_id │ │ ⑥ 创建 TaskScenes, TaskUser │ │ ⑦ Redis LPUSH taskPushQueue ← 推送消息 │ │ ⑧ Redis LPUSH WatchTaskUserList ← 手表任务 │ │ │ └──────────────────────────┬───────────────────────────────────┘ │ ▼ (走标准推送流程,同 3.1 阶段四) │ ┌────────────┼────────────┐ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ APP 通知 │ │ 手表提醒 │ │ Web 后台 │ │ 维护员收到│ │ 震动+语音 │ │ 任务列表 │ └──────────┘ └──────────┘ └──────────┘ ``` --- ## 五、MQTT 设备通信流程 ### 5.1 手表上下线监控 ``` 智能手表 │ │ MQTT connect/disconnect ▼ ┌──────────────────────────────────────────────┐ │ MQTT Broker (tcp://mqtt:1883) │ │ │ │ Topic: $SYS/brokers/+/clients/# │ │ 消息: {clientid:"watch_IMEI_xxx", │ │ connected_at: 1700000000} │ └──────────────────┬───────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────┐ │ PushCallback (MQTT 消息回调) │ │ │ │ ① 过滤: clientid 包含 "watch" │ │ ② 解析: connected_at / disconnected_at │ │ ③ Redis LPUSH WatchConnectList ← 连接事件 │ └──────────────────┬───────────────────────────┘ │ ▼ (每秒) ┌──────────────────────────────────────────────┐ │ ScheduledTask.WatchConnectList() │ │ │ │ ① Redis RPOP WatchConnectList │ │ ② 解析连接/断开: │ │ connected_at ≠ null → 上线 (status=1) │ │ disconnected_at ≠ null → 离线 (status=0) │ │ ③ 创建 WatchOffLog (MySQL) │ │ ④ 更新 Watch 表状态 (MySQL) │ └──────────────────────────────────────────────┘ ``` ### 5.2 蓝牙定位流程 ``` ┌──────────────┐ │ 智能手表 │ 持续扫描周围蓝牙信标 │ BLE 扫描 │ └──────┬───────┘ │ 信标数据: {mac, rssi, imei} ▼ ┌──────────────────────────────────────────────┐ │ 数据上报 → Redis │ │ Redis LPUSH BleutoothLocationQueue ← JSON │ └──────────────────┬───────────────────────────┘ │ ▼ (每秒) ┌──────────────────────────────────────────────────────────────┐ │ LocationTask.BleutoothLocationTask() │ │ │ │ ① Redis RPOP BleutoothLocationQueue │ │ ② 根据信标 MAC 查询 Beacon 表 → 获取位置信息 │ │ ③ RSSI 阈值判断: │ │ ┌────────────────────────────────────────────────┐ │ │ │ RSSI ≥ 阈值 (进入范围) │ │ │ │ → 保存 UserLocation (MySQL) │ │ │ │ → 创建 UserTrajectory (status=0, 进行中) │ │ │ │ → Redis SET Location: ← 位置信息 │ │ │ ├────────────────────────────────────────────────┤ │ │ │ 同一位置停留 < 5秒 │ │ │ │ → 更新 UserTrajectory.stay_time │ │ │ ├────────────────────────────────────────────────┤ │ │ │ 同一位置停留 ≥ 5秒 │ │ │ │ → 保存当前轨迹 (status=1, 完成) │ │ │ │ → 创建新的 UserTrajectory │ │ │ ├────────────────────────────────────────────────┤ │ │ │ RSSI < 阈值 (离开范围) │ │ │ │ → 记录离开时间 │ │ │ │ → 标记轨迹完成 (status=1) │ │ │ └────────────────────────────────────────────────┘ │ │ │ │ ④ 定位数据支撑: │ │ → Web 后台实时位置显示 │ │ → 人效分析报表 │ │ → 考勤打卡佐证 │ └──────────────────────────────────────────────────────────────┘ ``` --- ## 六、员工休息管理流程 ``` 员工点击 "休息" (APP) │ ▼ Web API → 创建休息请求 │ ▼ (Task 服务 - XXL-Job) ┌──────────────────────────────────────────────────────────────┐ │ userRestStartTask │ │ │ │ ① 创建 RestRecord (punchType=0, MySQL) │ │ ② 查询站点配置 → 获取休息时长 (默认60分钟) │ │ ③ Redis ZADD CleaningRestLastTime │ │ score=截止时间戳 value=userId │ │ ④ 更新 UserDistrictAttendance.workAtStatus=3 (休息中) │ │ ⑤ Redis SET CleaningUpWorkAtStatus: ← 原状态 │ │ ⑥ Redis LPUSH AttendanceStatusMessage ← 考勤消息 │ │ │ │ │ ▼ (ScheduledTask, 每秒) │ │ MQTT publish → 手表 (messageType=5, 关闭蓝牙) │ │ │ └──────────────────────────────┬───────────────────────────────┘ │ ┌──────────┴──────────┐ ▼ ▼ 正常结束休息 超时自动恢复 ┌─────────────────────────┐ ┌─────────────────────────┐ │ userRestEndTask │ │ restCountDown (每秒检查) │ │ (XXL-Job 定时触发) │ │ │ │ │ │ Redis ZRANGEBYSCORE │ │ ① RestRecord │ │ CleaningRestLastTime │ │ (punchType=1) │ │ 0 ~ 当前时间戳 │ │ ② 计算实际休息时长 │ │ │ │ │ ③ 恢复 workAtStatus │ │ ▼ │ │ (从 Redis 读取原状态) │ │ 发现超时员工 │ │ ④ 清除 Redis 标记 │ │ → 自动创建恢复记录 │ │ │ │ → 恢复 workAtStatus=2 │ └─────────────────────────┘ └─────────────────────────┘ ``` --- ## 七、数据导出流程 ``` 管理员点击 "导出" (Web 后台) │ ▼ POST /xxx/export │ ▼ ┌──────────────────────────────────────────────────────────────┐ │ Controller.export() │ │ │ │ ① 接收查询条件 (同列表查询) │ │ ② 查询权限组字段 (FieldWebpageAuthority) │ │ → 确定可导出的列 │ │ ③ Service 查询数据 (不分页, 全量) │ │ ④ 构造 Excel (Apache POI / EasyExcel) │ │ → 根据权限动态设置列 │ │ ⑤ 设置响应头: │ │ Content-Type: application/octet-stream │ │ Content-Disposition: attachment; filename=xxx.xlsx │ │ ⑥ 输出流写入 Response │ └──────────────────────────┬───────────────────────────────────┘ │ ▼ ┌──────────────┐ │ 浏览器下载 │ │ Excel 文件 │ └──────────────┘ ``` --- ## 八、权限动态加载流程 ``` 页面加载 / 路由切换 │ ▼ ┌──────────────────────────────────────────────────────────────┐ │ router-guard.js (路由守卫) │ │ │ │ ① 检查 sessionStorage 登录态 │ │ ② 读取路由 query: wId (页面ID), pageType │ │ ③ 触发 Vuex actions: │ │ store.dispatch('fetchFields', {wId, pageType}) │ │ store.dispatch('fetchButtons', {wId, pageType}) │ └──────────────────────────┬───────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────┐ │ Vuex Store │ │ │ │ fetchFields: │ │ POST /webPage/getFieldsByAuthority │ │ → 返回当前用户权限组下该页面可见字段列表 │ │ → 存入 state.fields │ │ │ │ fetchButtons: │ │ POST /webPage/getButtonsByAuthority │ │ → 返回当前用户权限组下该页面可见按钮列表 │ │ → 存入 state.buttons │ └──────────────────────────┬───────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────────┐ │ 页面组件渲染 │ │ │ │ │ │ 遍历 state.fields → 动态生成 │ │ 字段不在权限列表 → 不渲染该列 │ │ │ │ │ │ 遍历 state.buttons → 动态生成 │ │ 按钮不在权限列表 → 不渲染该按钮 │ └──────────────────────────────────────────────────────────────┘ ``` --- ## 九、Redis 消息队列数据流全景 ``` ┌─────────────┐ │ DB 4 │ └──────┬──────┘ │ ┌──────────────────────────────┬┼┬──────────────────────────────┐ │ │ ││ │ │ ▼ ▼ ▼▼ ▼ ▼ ┌────────┐ ┌──────────┐ ┌─────────────┐ ┌──────────┐ ┌────────────┐ │taskUser│ │taskPush │ │WatchTask │ │Mqtt │ │Bleutooth │ │Queue │ │Queue │ │UserList │ │TaskState │ │Location │ │ │ │ │ │ │ │Message │ │Queue │ └───┬────┘ └────┬─────┘ └──────┬──────┘ └────┬─────┘ └─────┬──────┘ │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ ┌────────┐ ┌──────────┐ ┌─────────────┐ ┌──────────┐ ┌────────────┐ │派单 │ │个推推送 │ │构建手表消息 │ │MQTT推送 │ │位置计算 │ │匹配 │ │APP通知 │ │ │ │到手机端 │ │轨迹记录 │ └────────┘ └──────────┘ └──────┬──────┘ └──────────┘ └────────────┘ │ ▼ ┌─────────────┐ │MqttWatch │ │TaskMessage │ └──────┬──────┘ │ ▼ ┌─────────────┐ │MQTT推送 │ │到手表 │ └─────────────┘ ┌─────────────┐ │ DB 5 │ └──────┬──────┘ │ ┌──────────────────────┬───────┼───────┬──────────────────────┐ │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ ┌────────┐ ┌──────────┐ ┌────┐ ┌──────────┐ ┌──────────┐ │task │ │Finish │ │实体│ │Dictionary│ │Location │ │Command │ │TaskQueue │ │缓存│ │ (Hash) │ │: │ │(设备告警)│ │(完成队列)│ │ │ │(系统配置)│ │(实时位置) │ └───┬────┘ └────┬─────┘ └────┘ └──────────┘ └──────────┘ │ │ ▼ ▼ ┌────────┐ ┌──────────┐ │生成 │ │完成后 │ │维护任务│ │处理逻辑 │ └────────┘ └──────────┘ ```