Files
smartClean/docs/architecture-flow.md
xqzp2026 8373460096 feat: 添加自动化部署方案(Docker + 远程服务器两套方案)
- 新增 deploy/docker/:Docker 本机模拟部署,含 Dockerfile、docker-compose、deploy.sh 一键脚本
- 新增 deploy/remote/:远程服务器部署,含 SSH 自动上传、重启、回滚脚本
- 新增 deploy/README.md:完整使用手册,含现状分析、落地调整工作清单、命令速查
- 新增 build.sh/start.sh:本地构建和启动脚本(含飞书通知)
- 新增前端 .env.docker 环境配置,API 指向测试服务器
- 前端 package.json 新增 build-docker 命令
- 更新 .gitignore:排除 IDE 配置、SQL 数据、Docker 敏感文件
- 前端 UI 样式优化(多个页面组件)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 18:41:15 +09:30

58 KiB
Raw Permalink Blame History

智慧清洁 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:<type>:<planId> → xxlJobId                                  │
│                                                                             │
└───────────────────────────────┬─────────────────────────────────────────────┘
                                │ XXL-Job 定时触发
                                ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 阶段二:任务生成 (Task 服务 - PlanTimeTask)                                  │
│                                                                             │
│  planCreateTask 触发                                                        │
│       │                                                                     │
│       ▼                                                                     │
│  ① 检查节假日 (Holiday表)                                                    │
│       │  eliminate_type=1 且为节假日 → 跳过                                   │
│       ▼                                                                     │
│  ② 检查禁用标志                                                              │
│       │  Redis GET Disable:d:<districtId>:<taskTypeId>                       │
│       │  如果 "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                        │
│                                                                             │
└──────────┬──────────────────────────────┬───────────────────────────────────┘
           │                              │
           ▼                              ▼
┌────────────────────────┐  ┌──────────────────────────────────────────────┐
│ 阶段四AAPP推送        │  │ 阶段四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_<districtId>        │
│                                             │
│         ┌──────────┐                        │
│         │ 手机 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:<districtId> (DB4)                   │
│    如果 "0" → 跳过                                           │
│ ③ 检查禁用标志:                                               │
│    Redis GET Disable:d/t/p:<id>:<taskTypeId> (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:<userId> ← 位置信息     │        │
│    ├────────────────────────────────────────────────┤        │
│    │ 同一位置停留 < 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:<mobile> ← 原状态         │
│ ⑥ 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                                       │
└──────────────────────────┬───────────────────────────────────┘
                           │
                           ▼
┌──────────────────────────────────────────────────────────────┐
│ 页面组件渲染                                                  │
│                                                              │
│ <qu-table>                                                   │
│   遍历 state.fields → 动态生成 <el-table-column>             │
│   字段不在权限列表 → 不渲染该列                                │
│                                                              │
│ <qu-button-group>                                            │
│   遍历 state.buttons → 动态生成 <el-button>                  │
│   按钮不在权限列表 → 不渲染该按钮                              │
└──────────────────────────────────────────────────────────────┘

九、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)   │       │:<userId> │
│(设备告警)│          │(完成队列)│ │    │ │(系统配置)│       │(实时位置) │
└───┬────┘          └────┬─────┘ └────┘ └──────────┘       └──────────┘
    │                    │
    ▼                    ▼
┌────────┐          ┌──────────┐
│生成    │          │完成后    │
│维护任务│          │处理逻辑  │
└────────┘          └──────────┘