第六阶段开发。

This commit is contained in:
zfjia committed 2026-11-12 13:36:24 +08:00
1 parent 35751b4f00
commit bacdd15f3a
93 files changed
+10190 -22

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
'$mysql' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
@@ -0,0 +1,204 @@
# 19 保洁与报修自动化(离寓触发 / 平板一键报修)
> 适用版本:apt-rev01(IT-5 之后增量)。
> 代码落点:`ruoyi-apt/.../job/**`、`dispatch/service/AptDutyStateServiceImpl`;库变更 `dev/sql/apt_rev01/28_job_automation.sql`。
## 0. 范围与结论
| 能力 | 触发方 | 自动化程度 | 人工介入 |
| --- | --- | --- | --- |
| 保洁工单 | 房间最后一名在寓人员登记离寓 | 自动建单(`source=AUTO`),无需管理员创建 | 保洁员在平板领取并执行 |
| 报修工单 | 房间平板「维修」按钮 | 一键建单,类别/优先级固定普通 | 维修工在平板领取并完成;后台可派单/取消 |
两条链路共用同一套状态流水 `apt_job_event` 与审计 `duty_operation_log`,做到「谁触发、谁执行、何时完成」全程可追溯。
## 1. 离寓判定逻辑
### 1.1 唯一口径(人员级)
以 `gy_jcxx` 业务事实判定,不使用任何缓存计数:
```
在寓人员 := gy_jcxx 中 deleted=0 AND finish_ly='0' AND sjlysj IS NULL 的记录
已离寓 := finish_ly='1'(同时 sjlysj 非空,由离寓命令写入)
```
- `finish_ly='1'` 仅由 `apt.duty.state` 唯一写入口(`MARK_LEAVE` 命令)产生,禁止其他模块直写。
- `FORCE_FINISH` 只置 `finish_jc=1`,**不**代表离寓,不触发保洁。
### 1.2 房间级判定
```
房间已全员离寓 := COUNT(在寓人员 WHERE fjh = 房间号) = 0
```
- 房号关联用 `gy_jcxx.fjh`(不是 `room_id`,历史数据只有房号)。
- 触发点每次只针对「被登记离寓人员所在房间」做一次判定,不做全库扫描。
- 计数查询走新增索引 `idx_jcxx_gyid_room_leave (gyid, fjh, finish_ly)`。
### 1.3 房间人数与房态同步
`gy_rooms.in_person_count` 不再靠 +1/-1 维护,离寓同事务内按上式**重算**:
```sql
UPDATE gy_rooms r
SET r.in_person_count = (SELECT COUNT(*) FROM gy_jcxx j
WHERE j.gyid=r.gyid AND j.fjh=r.room_no
AND j.deleted=0 AND j.finish_ly='0' AND j.sjlysj IS NULL),
r.state_version = r.state_version + 1
WHERE r.gyid=? AND r.room_no=? AND r.deleted=0
```
房态按优先级重算:`维修中(4) > 保洁中(6) > 待清扫(3) > 住满(2)/未满(5)/空闲(1)`。
- 最后一人离寓:房态直接置 **3 待清扫**(不落回 1 空闲),避免「已离寓但仍显示可入住」的窗口;
- 仍有在寓人员:按人数重算为 2/5;
- 存在未完成维修单:房态保持 4,保洁任务仍可生成但房态不被覆盖。
### 1.4 边界
| 场景 | 处理 |
| --- | --- |
| 房号为空/房间不存在 | 跳过联动并记 WARN,不影响离寓提交 |
| 平台同步的叫乘记录(未本地入住占床) | 重算以 `gy_jcxx` 为准,天然自愈 |
| 离寓后又有人入住 | 自动建单提交后复查人数,>0 则不建单(`OCCUPIED`) |
| 同一人重复登记离寓 | 条件更新未命中 → 40902,不重复触发 |
## 2. 工单自动触发机制
### 2.1 时序
```
值班台提交 MARK_LEAVE
└─ 事务内:updateMarkLeave(finish_ly=1, sjlysj) → insert gygl_ly_event
→ 取 fjh → syncRoomOccupancy(重算人数 + 房态置 3)
└─ 事务提交后(afterCommit):autoCreateCleanOnVacated(REQUIRES_NEW)
→ 复查在寓人数 >0 ? 放弃
→ 已有 PENDING/PROCESSING 任务 ? 返回该任务(duplicated=true)
→ 建单:source=AUTO、state=PENDING、assignee 为空
→ 写流水(operator=SYSTEM)+ 审计 CLEAN_AUTO_CREATE
```
- **为什么在提交后触发**:新事务读不到未提交的离寓结果,若同事务调用会误判「仍有人在寓」;
同时保证建单失败不回滚离寓这一核心事实(失败仅 WARN)。
- **为什么房态要在事务内先置 3**:提交到建单之间存在毫秒级窗口,先置 3 可避免房间被当成空闲。
### 2.2 幂等与并发
| 手段 | 说明 |
| --- | --- |
| 服务层先判 | 按 `selectActiveCleanTaskByRoom`(state in PENDING/PROCESSING)复用已有任务 |
| 库层兜底 | `gy_clean_task.active_room` 生成列 + `uk_cleantask_gyid_active_room` 唯一索引:同房同时只允许一条活跃任务 |
| 冲突返回 | 命中唯一键 → 捕获 `DuplicateKeyException`,重读活跃任务并返回 `duplicated=true` |
| 平板并发上报 | `reportClean` 同样走唯一键兜底,不会产出两条待清扫 |
### 2.3 触发失败降级
自动建单异常只记 WARN(不重试、不回滚离寓);房态已为 3,管理员可在「作业工单」页或由保洁平板手动上报补单。
## 3. 平板端操作流程
### 3.1 保洁
```
[系统] 最后一人离寓 → 自动建单 PENDING(未分配)
↓
[平板] GET /open/v1/tablet/jobs?type=CLEAN
返回:本人任务 + 未分配公共池(行内 pool=true)
↓
[平板] POST /clean/{taskId}/start → PROCESSING,assignee=当前设备绑定人员(领取即认领)
↓
[平板] POST /clean/{taskId}/finish → DONE,房态重算 1/2/5
```
- 人员类型为 `CLEANER` 时接口只返回/只允许保洁类任务;`REPAIRMAN` 反之;`BOTH` 两类均可。
- 手动 `POST /clean`(上报待清扫)保留为兜底,`source=TABLET`,同样受唯一键约束。
### 3.2 报修
```
[平板] 点击「维修」→ POST /open/v1/tablet/jobs/repair/quick { "roomNo": "101" }
后端固定 category=OTHER、priority=NORMAL,描述缺省「普通维修(平板一键报修)」
↓ REPORTED(房态 → 4 不能入住,disabled_reason=REPAIR:<orderId>)
[平板] GET /open/v1/tablet/jobs?type=REPAIR → 本人任务 + 未分配公共池
↓
[平板] POST /repair/{orderId}/start → IN_PROGRESS(未派单时自动认领)
↓
[平板] POST /repair/{orderId}/complete → DONE(result 缺省「已修复(平板提交)」)
房态重算;已完成的工单不允许重复回写
```
后台仍可 `POST /apt/workorder/repair/{orderId}/assign` 派单/改派、`/cancel` 取消;平板侧不提供改状态为「已完成」以外的越权入口。
## 4. 状态流转规则
### 4.1 保洁(`gy_clean_task.state`)
| 当前态 | 事件 | 目标态 | 条件 / 副作用 |
| --- | --- | --- | --- |
| — | 全员离寓自动建单 | PENDING | 同房无活跃任务;`source=AUTO`;房态 3 |
| — | 平板上报 | PENDING | 同房无活跃任务;`source=TABLET`;房态 3 |
| PENDING | 开始(平板) | PROCESSING | 条件更新 `state='PENDING'`;写 `assignee_staff_id`、`started_at`;房态 6 |
| PROCESSING | 结束(平板) | DONE | 条件更新 `state='PROCESSING'`;写 `finished_at`;房态重算 |
| PENDING/PROCESSING | 取消 | CANCELLED | 表结构允许,本期未开放接口(保留) |
### 4.2 维修(`apt_repair_order.state`)
| 当前态 | 事件 | 目标态 | 条件 / 副作用 |
| --- | --- | --- | --- |
| — | 一键报修 / 平板报修 | REPORTED | 同房无未完成工单;房态 4 + `REPAIR:<orderId>` |
| REPORTED | 后台派单 | ASSIGNED | 人员须 ACTIVE 且非 CLEANER |
| ASSIGNED | 后台改派 | ASSIGNED | 同上,刷新 `assigned_at` |
| REPORTED / ASSIGNED | 平板开始 | IN_PROGRESS | 条件更新;未派单自动认领;写 `started_at` |
| IN_PROGRESS | 平板完成 | DONE | 必填/缺省 `result`;写 `finished_at`、`duration_sec`;房态重算 |
| REPORTED / ASSIGNED / IN_PROGRESS | 后台取消 | CANCELLED | 写 `remark`;房态重算 |
### 4.3 通用约束
1. 所有迁移均为「条件更新 + 影响行数」,0 行即冲突:重复提交按幂等返回 `duplicated=true`,非法迁移返回 40902。
2. 平板执行人由 `X-Device-Code` 反查 `apt_staff`(仅 `state=ACTIVE`),请求体不接受 `staffId`/`gyid`。
3. 后台不提供「开始/完成」入口,状态推进只能由作业人员在平板完成。
4. 房态由服务层统一条件更新并递增 `state_version`,冲突重读一次后仍失败返回 40903。
## 5. 接口清单
### 5.1 平板(`/open/v1/tablet/jobs`,设备四要素鉴权)
| 方法 | 路径 | 说明 |
| --- | --- | --- |
| GET | `/` | 我的作业 + 公共池(`type`/`state`/`limit`,行内 `pool` 标识未分配) |
| POST | `/clean` | 手动上报待清扫(兜底,`source=TABLET`) |
| POST | `/clean/{taskId}/start` | 开始/领取保洁 |
| POST | `/clean/{taskId}/finish` | 结束保洁 |
| POST | `/repair` | 标准报修(可带类别/优先级/描述) |
| POST | `/repair/quick` | **一键报修**(仅房号,普通维修) |
| POST | `/repair/{orderId}/start` | 开始维修(未派单自动认领) |
| POST | `/repair/{orderId}/finish` | 完成维修(`result` 必填) |
| POST | `/repair/{orderId}/complete` | **一键完成**(`result` 可省略) |
### 5.2 后台(`/apt/workorder`、`/apt/staff`)
| 方法 | 路径 | 权限点 |
| --- | --- | --- |
| GET | `/apt/workorder/list` `/stats` `/{type}/{jobId}` | `apt:workorder:list` / `stats` / `query` |
| POST | `/apt/workorder/repair/{orderId}/assign` | `apt:workorder:assign` |
| POST | `/apt/workorder/repair/{orderId}/cancel` | `apt:workorder:handle` |
| CRUD | `/apt/staff/**` | `apt:staff:*` |
## 6. 可追溯性
| 载体 | 记录内容 |
| --- | --- |
| `apt_job_event` | 每次状态迁移:`from_state → to_state`、操作人(自动建单为 `SYSTEM`)、设备编码、备注(含 `LEAVE:<jcid>`) |
| `gy_clean_task.source` | `AUTO` / `TABLET` / `MANUAL`,可直接区分自动生成与人工上报 |
| `duty_operation_log` | 自动建单审计 `module=JOB, action=CLEAN_AUTO_CREATE`,detail 含房号、任务号、触发来源、在寓人数、traceId |
| `duty_manual_action` | 离寓命令的幂等键与结果 |
| `gygl_ly_event` | 离寓事实(`leave_type`) |
## 7. 已知边界与后续项
1. **退宿/换房链路尚未落地**:当前离寓入口只有值班台 `MARK_LEAVE`;后续退宿接口必须复用 `apt.duty.state` 与本文 §1/§2 的联动,禁止另写一套房态/建单逻辑。
2. **保洁取消无接口**:表结构支持 `CANCELLED`,如需「入住前取消待清扫」,应新增后台接口并写流水。
3. **待清扫房间仍可办理入住**:沿用既有房态规则(仅 4/6 阻断入住),因此「离寓→入住」窗口内可能不产生实际保洁;如需强制,应将 3 纳入入住阻断条件(需业务确认)。
4. **并发建单**:唯一索引已兜底,极端情况下可能出现「任务已建、人又入住」的短暂脏数据,由保洁结束后房态重算自愈。
5. **叫乘修正改房号不触发联动**:`correct` 允许未离寓记录修改 `fjh`,会改变房间归属但不会重算两端房态/保洁单;如需严格一致,应在修正后调用同一 `syncRoomOccupancy`,列入后续迭代。
@@ -0,0 +1,190 @@
# 20 第六轮开发(IT-6)交付说明:上报续传 + 人员 / 设备
> 迭代来源:`13-公寓端小步迭代开发计划.md` 表 13-16 `IT-6`、表 13-6 验收映射
> 里程碑:`M4`(叫乘人员管理)/ `M5`(设备管理)/ `D-1`~`D-3`(应用端最小集)
> 交付日期:2026-11-12
> 交付状态:**部分交付(后端链路已通,值班台入口与演练未完成)**,未就绪项见 §6
## 1. 范围与边界
### 1.1 本期已交付
| 项 | 内容 |
| --- | --- |
| 上报 outbox | 查询、状态汇总、失败重试(FAILED/DEAD → PENDING,沿用原 `idempotency_key`) |
| 水位 | `apt_report_watermark` 读写、`acked/current/lag` 对账视图、平台回执推进 |
| #14 心跳 | 设备心跳更新在线态、`last_heartbeat_at`、`clock_skew_ms`,>5s 标记超限 |
| 断网续报(#9/#8/#13) | `POST /open/v1/report/resume`:按原幂等键入队,`DUPLICATE` 视为成功 |
| M4 人员 | 列表 / 详情 / 关联 Tab(当前在住 + 最近 5 条叫乘 + 最近交路) |
| M4 只读 | `PUT /apt/person/{ryid}` 无条件 `40904 SNAPSHOT_READONLY` |
| M5 设备 | 档案 / 在线态 / 指令记录查询;指令只入队 `PENDING`、`protocol_confirmed=0` |
| M5 心跳 | `POST /open/v1/device/heartbeat`(设备四要素鉴权) |
| 配置 | `apt.report.*` 默认值与环境变量映射;`dispatch-enabled` 默认 `false` |
### 1.2 明确不做(沿用计划口径)
1. **#10 `LEDGER_OFFLINE`**:P2,本期不建账务接口 / 表 / 权限点。
2. **不新增业务表**:outbox / watermark / device_command 三表沿用 `IT-0` 基线 DDL,只加索引。
3. **不伪造设备 ACK**:现场协议未确认(Q-12),指令不置 `SENT/ACKED`。
4. **管理端不改队列态**:outbox 的 `SENT/DEAD` 只能由派发器与重试链路推进(CR-C10)。
## 2. 交付清单
### 2.1 后端(`dev/RuoYi-Vue-master/ruoyi-apt`)
| 文件 | 说明 |
| --- | --- |
| `report/domain/AptOutboxQuery.java` | outbox 过滤条件(bizType/bizId/state/时间/limit) |
| `report/domain/AptResumeEnvelope.java` | 续报信封(复用原 idempotencyKey) |
| `report/mapper/AptReportMapper.java` + `mapper/apt/AptReportMapper.xml` | outbox 列表/汇总/重试、水位 upsert/ack |
| `report/service/IAptReportService.java`、`AptReportServiceImpl.java` | 续报、重试白名单、水位视图、心跳 |
| `report/controller/AptReportController.java` | `/apt/report/**`(列表/统计/水位/重试/回执) |
| `report/controller/AptReportOpenController.java` | `/open/v1/report/resume` |
| `master/mapper/AptPersonMapper.java` + `mapper/apt/AptPersonMapper.xml` | 人员列表/详情/在住/最近叫乘/最近交路 |
| `master/service/IAptPersonService.java`、`AptPersonServiceImpl.java` | M4 读侧 + 快照只读拒绝 |
| `master/controller/AptPersonController.java` | `/apt/person/**`(含 `PUT` → 40904) |
| `device/domain/AptDeviceCommandRequest.java`、`AptDeviceHeartbeat.java` | 入队请求 / #14 心跳体 |
| `device/mapper/AptDeviceMapper.java` + `mapper/apt/AptDeviceMapper.xml` | `gy_sb` / `gy_sb_xt` / `apt_device_command` |
| `device/service/IAptDeviceService.java`、`AptDeviceServiceImpl.java` | 心跳、指令入队、重复命令幂等 |
| `device/controller/AptDeviceController.java` | `/apt/device/**` |
| `device/controller/AptDeviceOpenController.java` | `/open/v1/device/heartbeat` |
| `framework/config/AptProperties.java` | 新增 `report` 配置段 |
| `resources/apt-defaults.yml` | `APT_REPORT_*` 环境变量映射(`dispatch-enabled=false`) |
### 2.2 SQL(`dev/sql/apt_rev01`,已执行)
| 文件 | 说明 |
| --- | --- |
| `29_it6_permissions.sql` | 9 个 F 权限点(3250~3258)、超管绑定、2 个查询索引 |
执行校验(`29` 第 57~60 段):
| 段 | 期望 | 实测 |
| --- | --- | --- |
| 57 | 9 个权限点 | 9 |
| 58 | 超管绑定 9 | 9 |
| 59 | 2 个索引 | `idx_outbox_gyid_occurred`、`idx_devcmd_gyid_device_state` |
| 60 | 三表可读 | outbox 0 / watermark 1 / device_command 0 |
### 2.3 测试
| 文件 | 用例 |
| --- | --- |
| `test/.../report/AptReportServiceTest.java` | 6 例:重试白名单、水位差、心跳偏差、续报幂等 |
| `test/.../device/AptDeviceServiceTest.java` | 3 例:只入队 PENDING、停用拒绝、重复命令不重插 |
| `test/.../master/AptPersonServiceTest.java` | 3 例:关联组合、40904、404 |
全量回归:`mvn -o -pl ruoyi-apt -am test` → **246 passed / 0 failed**(本轮新增 12 例)。
## 3. 接口说明
### 3.1 管理端
| 接口 | 权限点 | 行为 |
| --- | --- | --- |
| `GET /apt/report/outbox` | `apt:report:list` | 队列列表,默认 100 / 上限 500,按 id 倒序 |
| `GET /apt/report/stats` | `apt:report:query` | `outbox{total,pending,sending,sent,failed,dead,maxWatermark}` + `watermark{}` |
| `GET /apt/report/watermark` | `apt:report:query` | `current/acked/lag/lastHeartbeatAt/clockSkewMs/阈值` |
| `POST /apt/report/outbox/{id}/requeue` | `apt:report:retry` | 仅 `FAILED/DEAD`;生成 `retryBatchId`,重试次数清零 |
| `POST /apt/report/watermark/ack/{acked}` | `apt:report:retry` | 只增不减,联调/派发器回执 |
| `GET /apt/person/list` | `apt:person:list` | keyword / roomNo / state,带当前在住房间 |
| `GET /apt/person/{ryid}` | `apt:person:query` | 人员详情 |
| `GET /apt/person/{ryid}/associations` | `apt:person:query` | 关联 Tab 数据 |
| `PUT /apt/person/{ryid}` | `apt:person:edit` | 固定 `40904`,审计 `PERSON_UPDATE_REJECTED` |
| `GET /apt/device/list` | `apt:device:list` | `gy_sb` + `gy_sb_xt` 在线态 |
| `GET /apt/device/{deviceCode}` | `apt:device:query` | 设备详情 |
| `GET /apt/device/{deviceCode}/commands` | `apt:device:query` | 指令记录 |
| `POST /apt/device/{deviceCode}/commands` | `apt:device:enqueue` | 入队 `PENDING`,停用设备 `40940` |
### 3.2 设备侧(`/open/v1/**`,设备四要素鉴权)
| 接口 | 行为 |
| --- | --- |
| `POST /open/v1/report/resume` | 批量续报,逐条 `ACCEPTED/DUPLICATE/REJECTED`;`DUPLICATE` 视为成功 |
| `POST /open/v1/device/heartbeat` | 刷新 `gy_sb_xt`、`last_seen_at`、水位与时钟偏差 |
续报响应示例:
```json
{
"code": 200,
"data": {
"accepted": 1,
"duplicated": 1,
"rejected": 0,
"items": [
{ "idempotencyKey": "KEY-1", "bizType": "CHECKIN", "bizId": "BIZ-1", "status": "DUPLICATE" }
]
}
}
```
## 4. 关键实现要点
### 4.1 队列与终态流水不互换
- `apt_report_outbox.state` 只表达本地队列态(`PENDING/SENDING/SENT/FAILED/DEAD`),
业务终态在 `apt_report_history`;本模块**不写 history**,也不按队列态推断业务事实。
- 重试复用原 `idempotency_key`,平台侧按 `PL-IDEMPOTENT-REPLAY` 视为成功,不产生新事实。
### 4.2 对账三维
| 维度 | 来源 |
| --- | --- |
| `count` 差异 | `stats.outbox` 各态计数 |
| `acked_watermark = current_watermark` | `watermark.lag = max(0, current-acked)` |
| `max(watermark)` 追平 | `stats.outbox.maxWatermark` |
### 4.3 心跳与偏差
- 心跳只写 `gy_sb_xt.online_state/heartbeat_at/app_version` 与 `gy_sb.last_seen_at`,
**不触碰指令态**;
- 水位取 `GREATEST(已有, 上报值)`,避免设备重启回退;
- 偏差阈值取 `apt.report.clock-skew-threshold-ms`(默认 5000ms),超限仅在响应中标记,
不自动改业务数据。
### 4.4 M4 快照只读
- 人员字段来自平台快照(`source_version`),本地无写入口;
- `PUT` 不接受任何可改字段,直接 `40904`,避免"部分可改"造成双写;
- 关联 Tab 数据实时取自 `gy_jcxx`(在住 = `finish_ly='0' AND sjlysj IS NULL`)。
### 4.5 M5 只入队
- 入队固定 `state='PENDING'`、`protocol_confirmed=0`;
- 重复 `commandId` 返回既有指令,`duplicated=true` 且状态如实返回(不强制改写);
- 停用设备拒绝入队(`40940 DEVICE_DISABLED`)。
## 5. 验证记录
| 项 | 方式 | 结果 |
| --- | --- | --- |
| 编译 | `mvn -o -pl ruoyi-apt -am -DskipTests compile` | BUILD SUCCESS |
| 单测 | `mvn -o -pl ruoyi-apt -am test` | 246 passed |
| SQL | `29_it6_permissions.sql` 第 57~60 段 | 全部符合期望 |
| 接口契约 | Controller 路径 / 权限点 / 错误码静态核对 | 与 §3 一致 |
尚未执行:断网 2h 演练、恢复 10min 追平、20 接口请求样例 → 落库断言基线(见 §6)。
## 6. 未就绪内容(必须记录的缺口)
| # | 未就绪项 | 现状 | 阻塞 / 依赖 | 建议排期 |
| --- | --- | --- | --- | --- |
| 1 | **`duty` 前端入口(D-1~D-3)** | 未创建 `src/entries/duty/**`,值班台仍用旧页 `JcXx.vue` | 前端排期;`IR-03` 要求不魔改全局动态路由 | IT-6 后半段 |
| 2 | **M4/M5 前端页面** | 仅后端接口,无人员关联 Tab / 设备指令页 | 同上 | IT-6 后半段 |
| 3 | **平台派发客户端 + 自动重试调度** | `dispatch-enabled=false`,outbox 只累积;无 Quartz 派发任务、无退避与 `DEAD` 判定 | Q-13 联调环境与凭据 | IT-6 后半段 / IT-8 |
| 4 | **#9 影子对账** | 未开启"只写不生效",未做连续 3 天零差异比对 | 依赖 #3 派发链路 | IT-8 收口 |
| 5 | **断网演练取证** | 未执行 2h 断网 / 恢复追平实测 | 需要完整环境与前端入口 | IT-8 |
| 6 | **20 接口回归基线** | 仅新增模块 12 例单测,未形成"请求样例 → 落库断言"全量基线 | 依赖联调环境 | IT-6 后半段 |
| 7 | **M5 指令下发 / ACK** | 协议未确认(Q-12),指令停留 `PENDING`,无 `SENT/ACKED` 通道 | 现场厂家协议 | IT-7 |
| 8 | **设备离线判定任务** | 心跳只写在线态,未实现"超时置 OFFLINE"的定时扫描 | 无 | IT-6 后半段 |
| 9 | **值班台看板(outbox/水位)** | 无界面,仅接口 | 依赖 #1 入口 | IT-6 后半段 |
| 10 | **Q-21/Q-22/Q-23/Q-25 签收** | 计划标注为 IT-6 依赖,交付时未见签收记录 | 业务/架构 | 试点前 |
## 7. 风险与后续
1. **Mock 口径**:`APT_REPORT_DISPATCH_ENABLED=false` 时 outbox 只累积,验收"恢复 ≤10min 清空"必须在开启派发的联调环境执行,不能用 Mock 数据代替。
2. **续报批量上限**:单次 200 条,超限直接 `40001`;平板侧需分批推送,避免一次提交被拒。
3. **人员关联性能**:列表用 3 个相关子查询取当前在住/交路/车号,人员量 >5k 时需改为窗口函数或冗余列(已建 `idx_jcxx_gyid_room_leave`,后续按实际数据量评估)。
4. **设备编码大小写**:统一按大写存储与匹配;设备端必须以大写 `X-Device-Code` 上报,否则 `40401`。
5. **与既有作业模块的边界**:`/apt/workorder`、`/apt/staff`(保洁/维修)不在 IT-6 范围内,其自动建单与平板链路不受本次改动影响。