b91a366f51
Merge branch 'master' into feat/multi-tenant
2026-04-22 18:23:50 +08:00
3cfd342318
fix(ops): BADGE 绑定/解绑后即时同步工牌缓存
...
问题:
1. 设备先上线、后绑定为 BADGE 时,"可分配工牌"列表迟迟不出现该设备;
2. 已绑定区域的设备收不到工单(被分派策略过滤掉)。
根因:实时上线路径 BadgeDeviceStatusEventHandler.onMessage 在写
ops:badge:status:{deviceId} Redis 缓存前,先 isBadgeDevice() 校验
ops_area_device_relation 是否存在 BADGE 关系。设备如果在绑定前就上线,
事件被丢弃;建立关系后又没有任何机制回填 Redis,得等 5/30 分钟的
BadgeDeviceStatusSyncJob 对账才会被发现(线上日志可见 deviceId=58 在
绑定后 30 分钟才被对账修正:reason=定时对账修正-上线)。
解绑同样有反向缺口:关系记录删了但 Redis 缓存得等 24h TTL 自然过期,
期间 listAvailableBadges 仍可能返回该设备。
修复:在 ops-biz 引入 AreaDeviceBoundEvent / AreaDeviceUnboundEvent,
bindDevice / unbindDevice 成功后通过 ApplicationEventPublisher 发布;
environment-biz 新增 BadgeAreaBoundEventListener 仅订阅 BADGE 类型,
使用 @TransactionalEventListener(AFTER_COMMIT) + @Async 确保事务提交后
异步执行不阻塞接口:
- 绑定:单次调 IotDeviceQueryApi.getDevice 取齐 state + nickname +
deviceName,根据状态写 Redis(IDLE/OFFLINE);
- 解绑:直接调 BadgeDeviceStatusService.deleteBadgeStatus 清理 Redis。
依赖方向遵循 environment-biz → ops-biz;ops-biz 不反向依赖条线模块,
通过事件解耦,与现有 OrderStateChangedEvent 模式一致。
测试:
- AreaDeviceRelationServiceTest 补 iotDeviceQueryApi mock 让原本因缺
mock 而 RED 的 testBindDevice_TrafficCounter_Success 转绿;
- 新增对 bound / unbound 事件 publishEvent 调用的 verify。
- 全套 10/10 通过。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-04-22 18:04:47 +08:00
65ad3f35e5
Merge branch 'master' into feat/multi-tenant
...
吸收 master 今日 9 个工单链路修复:
- autoDispatchNext/dispatch 空闲兜底 + FOR UPDATE 并发防护
- 状态转换审计闭环(AFTER_COMMIT/AFTER_ROLLBACK)
- 队列楼层权重强优先 + 三级 baseline 兜底 + N+1 优化
- 工牌 nickname 回填
- CleanOrderAutoCancelJob 超时工单自动取消
2026-04-20 16:04:46 +08:00
c78759fd52
feat(ops): 新增保洁工单超时自动取消 Job + 集成测试
...
Java CI with Maven / build (11) (push) Has been cancelled
Java CI with Maven / build (17) (push) Has been cancelled
Java CI with Maven / build (8) (push) Has been cancelled
背景:保洁工单偶尔因设备离线/信标丢失导致卡在非终态(如 PENDING 超 12h 没派,
DISPATCHED 超 12h 没确认),靠人工清理成本高。补一个每小时跑的 XXL-Job 扫描关单。
实现:
- CleanOrderAutoCancelJob.scanAndCancel:
* 查询 update_time 距今超 timeoutHours(默认 12h)的 CLEAN 工单
* 状态白名单 = PENDING/QUEUED/DISPATCHED/CONFIRMED/ARRIVED,**排除 PAUSED**
(PAUSED 是 P0 打断的产物,应由 resumeInterruptedOrder 走状态机恢复,
此处若把它 CANCEL,会破坏 P0 完成后的 resume 链路)
* 调用 orderLifecycleManager.cancelOrder 走完整责任链,事件监听器负责
TTS 停播/设备关联回收/审计日志
* cancel 前再 selectById 做乐观校验:若 update_time 已刷新或状态已变
(COMPLETED/CANCELLED/PAUSED),跳过;避免候选装内存到实际 cancel
之间用户刚触达的工单被误杀
* 单单独立 try/catch 隔离,单条失败不断批
* batchSize 限流(默认 200),事件风暴防护
- application.yaml 补默认配置:viewsh.ops.clean.auto-cancel.{timeout-hours, batch-size}
- CleanOrderAutoCancelJobTest 覆盖 6 条不变量:
无候选零计数、全成功、部分失败不中断、乐观锁跳过 stale、终态跳过、PAUSED 跳过
XXL-Job 配置建议:
- JobHandler: cleanOrderAutoCancelJob
- Cron: 0 17 * * * ? (每小时 :17,避开整点尖峰)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-04-20 15:21:33 +08:00
323ddf27fb
fix(ops): 对账回填工牌 nickname,修复重启后派单人名降级为 deviceCode
...
根因:BadgeDeviceStatusSyncJob 硬编码 nickname=null,依赖 Redis 已有值。
重启后若 ops:badge:device:{deviceId} 的 nickname 丢失(TTL/清理/首次写入),
BadgeDeviceAreaAssignStrategy 会降级用 deviceCode,导致 assigneeName 变成 "43607737587"。
- SyncJob 注入 IotDeviceQueryApi,批量拉 IotDeviceSimpleRespDTO.nickname 做回填
- 状态一致但 Redis 缺 nickname 时也补写一次,覆盖最常见的重启路径
- AreaAssignStrategy 降级兜底改为 "工牌-尾号",避免再把裸 deviceCode 当人名暴露
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-04-20 13:50:00 +08:00
4d85659277
fix(ops): 修复同一工牌并行多单的状态错乱
...
线上观察:管理员手动取消一个僵尸 DISPATCHED 单会引发"越清越多"——
系统顺势派队列首条给仍在工作的保洁员,监听器再用"旧工单残留"机制
尝试取消当前正在执行的工单,该取消走 REQUIRES_NEW 独立事务且吞异常,
最终新单落地、旧单残留,同一设备挂多个非终态工单。
修复两处:
1. DispatchEngineImpl.autoDispatchNext 入口加设备空闲校验:
若执行人名下还有 DISPATCHED/CONFIRMED/ARRIVED/PAUSED 工单(排除
completedOrderId),直接早返回,不再派发。所有调用方(保洁/安保
handleCancelled、asyncCompleteAndDispatchNext、xxl-job 空闲扫描)
自动受保护。新增 OpsOrderMapper.selectActiveByAssignee。
2. BadgeDeviceStatusEventListener.handleDispatched 移除"残留取消":
旧逻辑用 REQUIRES_NEW 事务 + 吞异常,是对数据已错乱场景的暴力兜底,
失败时导致误杀。改为只打 ERROR 告警暴露问题,仅清理 Redis 关联。
真正的防线在 DispatchEngine 入口。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-04-20 10:54:54 +08:00
a2f500fa20
feat(tenant): 租户-项目两级架构 Phase 2 — IoT + Ops 业务迁移
...
DO 迁移 (15个 TenantBaseDO → ProjectBaseDO):
- IoT: IotDeviceDO
- Ops 核心: OpsOrderDO, OpsOrderEventDO, OpsOrderDispatchDO, OpsOrderQueueDO,
OpsBusAreaDO, OpsAreaDeviceRelationDO, OpsDeviceTrajectoryDO
- Ops 保洁: OpsOrderCleanExtDO, OpsCleanerStatusDO, OpsCleanerPerformanceMonthlyDO,
OpsInspectionRecordDO, OpsInspectionRecordItemDO
- Ops 安保: OpsOrderSecurityExtDO, OpsAreaSecurityUserDO
IoT 适配:
- IotDeviceRespDTO 新增 projectId 字段
- IotDeviceMessage 新增 projectId 字段
- IotDeviceMessageServiceImpl.appendDeviceMessage() 设置 projectId
- IotCleanRuleMessageHandler 嵌套 ProjectUtils.execute() 设置项目上下文
缓存改造:
- ProjectRedisCacheManager extends TenantRedisCacheManager,追加 :projectId 后缀
- ViewshTenantAutoConfiguration 替换为 ProjectRedisCacheManager
SQL 迁移脚本 (sql/mysql/project/):
- 01-create-tables.sql: system_project + system_user_project 建表
- 02-default-data.sql: 默认项目 + 用户关联回填
- 03-alter-business-tables.sql: 15 张表添加 project_id (NULL → 回填 → NOT NULL → 索引)
- 04-index-audit.sql: 现有索引审计 + project_id 补充建议
- 99-rollback.sql: 完整回滚方案
附带修复:
- fix(ops): UserDispatchStatusServiceImpl 添加缺失的 KEY_PREFIX 常量
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-04-16 22:27:34 +08:00
73e67dd3ec
Merge branch 'master' into feat/multi-tenant
...
Resolve conflicts by accepting master changes for:
- Jenkinsfile (CI/CD release/next branch support)
- OrderCodeGenerator (Redis seq sync fix)
- OrderCodeGeneratorTest (updated tests)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-04-16 18:08:14 +08:00
7707455a24
feat(ops): 手动派单放宽校验,支持跨区域和向忙碌设备派单
...
移除 canAcceptNewOrder、区域绑定和区域匹配校验,仅保留在线检查。
手动派单由调度员人工判断合理性,自动派单的校验仍在 BadgeDeviceAreaAssignStrategy 中完成。
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-04-13 23:18:54 +08:00
ea374d131a
feat(ops): 工牌状态返回昵称字段,手动派单支持传入设备名称
...
- BadgeStatusRespDTO 新增 nickname 字段,透传设备昵称
- CleanManualDispatchReqDTO 新增 assigneeName,派单时携带设备显示名
- CleanWorkOrderServiceImpl 将 assigneeName 传递给派单引擎
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-04-13 23:18:30 +08:00
705717a5b1
Merge branch 'master' into feat/multi-tenant
...
# Conflicts:
# viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/dal/redis/TrafficActiveOrderRedisDAO.java
# viewsh-module-ops/viewsh-module-environment-biz/src/main/java/com/viewsh/module/ops/environment/service/badge/BadgeDeviceStatusServiceImpl.java
# viewsh-module-ops/viewsh-module-ops-biz/src/main/java/com/viewsh/module/ops/service/dispatch/UserDispatchStatusServiceImpl.java
2026-04-13 14:35:27 +08:00
04c61a41db
fix(ops): 修复 CleanBadgeServiceImpl 调用不存在的 queryAreaNameById 方法导致编译失败
...
Java CI with Maven / build (11) (push) Has been cancelled
Java CI with Maven / build (17) (push) Has been cancelled
Java CI with Maven / build (8) (push) Has been cancelled
改用 OpsBusAreaDO.getAreaName() 获取区域名称
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-04-07 10:45:10 +08:00
54f78f8066
feat(ops): 工牌实时状态增加物理位置、电量和工单信息
...
BadgeRealtimeStatusRespDTO 新增物理位置(IoT 轨迹检测 RPC)、
电量(IoT 设备属性 RPC)、当前工单信息三个维度。
RPC 调用改为串行执行避免占用 ForkJoinPool 公共线程。
设备状态写入 Redis 时同步写入区域名称。
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com >
2026-04-05 15:26:43 +08:00
9ffaac5c91
feat(ops): 新增轨迹统计接口 summary/hourly-trend/area-stay-stats
...
- summary: KPI 卡片(作业时长、覆盖区域数、事件数、平均停留)
- hourly-trend: 按小时聚合出入趋势
- area-stay-stats: 区域停留分布(含 fullAreaName,按时长降序)
- deviceId 可选,不传则汇总全部设备
- selectByDateAndDevice 加 LIMIT 5000 安全上限
- 删除无调用方的 selectTimeline 方法
- enrichWithAreaInfo 改用 buildPaths 批量构建路径
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com >
2026-04-05 15:26:14 +08:00
da00f08262
fix(environment): 对账修复后同步清理 TTS 循环播报
...
Java CI with Maven / build (11) (push) Has been cancelled
Java CI with Maven / build (17) (push) Has been cancelled
Java CI with Maven / build (8) (push) Has been cancelled
- BadgeDeviceStatusSyncJob 在修复设备工单一致性后额外停止 TTS 循环\n- 避免工单已清除但语音循环标记残留,导致设备继续播报\n- 对 TTS 清理失败增加 warn 日志,避免影响主对账流程
2026-03-31 22:58:40 +08:00
1696aeb287
fix(clean): 取消工单前先清理客流活跃标记
...
- 调整 CANCELLED 事件处理顺序\n- 先移除 area 级活跃工单 Redis 标记,再执行后续取消逻辑\n- 避免后续取消处理异常时遗留错误的活跃状态
2026-03-31 22:57:44 +08:00
f0fa5f1c46
fix(clean): 补齐客流活跃工单缓存自愈逻辑
...
- 为客流活跃工单 Redis 标记补充 TTL,避免长期残留\n- 创建工单前命中 Redis 时回查 DB,自动清理终态脏数据并刷新过期状态\n- 新增启动校准器,服务启动时批量清理或刷新 area 级活跃工单缓存
2026-03-31 22:57:28 +08:00
bf5aa21648
feat(trajectory): 新增轨迹事件消费与落库模型
...
- 新增 ops_device_trajectory 表及轨迹数据对象、Mapper\n- 消费 trajectory-enter / trajectory-leave 事件并做幂等处理\n- 落地设备进入/离开区域记录,补充停留时长与离开原因字段\n- 在服务层封装轨迹写入、关闭未离场记录等核心逻辑
2026-03-31 22:56:18 +08:00
19cb25b0ea
refactor(ops): 15 个 DO 基类从 BaseDO 规范化为 TenantBaseDO
...
Java CI with Maven / build (11) (push) Has been cancelled
Java CI with Maven / build (17) (push) Has been cancelled
Java CI with Maven / build (8) (push) Has been cancelled
数据库表已有 tenant_id 列,拦截器实际可正常工作,但 DO 继承
BaseDO 语义不明确。统一改为 TenantBaseDO 以明确租户隔离语义。
ops-biz: OpsOrderDO, OpsOrderDispatchDO, OpsOrderEventDO,
OpsOrderQueueDO, OpsBusAreaDO, OpsAreaDeviceRelationDO,
OpsBusinessEventLogDO
environment-biz: OpsOrderCleanExtDO, OpsInspectionRecordDO,
OpsInspectionTemplateDO, OpsInspectionRecordItemDO,
OpsCleanerStatusDO, OpsCleanerPerformanceMonthlyDO
security-biz: OpsOrderSecurityExtDO, OpsAreaSecurityUserDO
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-03-30 11:42:09 +08:00
7d19e7bafa
fix(ops): RocketMQ 消费者添加租户上下文防御性兜底
...
6 个消费者添加 executeInTenantContext() 统一模式:当框架 Hook
未设置租户上下文时,从事件体 tenantId 字段兜底切换。
同步为 4 个事件 DTO 添加 tenantId 字段,去重 Key 迁移至
OpsRedisKeyBuilder.eventDedup() 实现租户隔离。
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-03-30 11:41:14 +08:00
df2d14ce26
feat(ops): 新增 OpsRedisKeyBuilder 统一管理 Redis Key 租户隔离
...
新建 OpsRedisKeyBuilder 集中式工具类,所有 Ops 模块 Redis Key 统一使用
:t{tenantId} 格式实现多租户隔离。迁移以下服务的 Key 构建:
- RedisOrderQueueServiceImpl(派单队列/信息/锁)
- UserDispatchStatusServiceImpl(调度状态)
- BadgeDeviceStatusServiceImpl(工牌状态)
- TrafficActiveOrderRedisDAO(客流活跃工单)
- TtsQueueConsumer(TTS 队列/锁/循环)
- OrderCodeGenerator(工单编码序号)
- AreaDeviceServiceImpl(区域设备配置缓存)
- TrafficStatisticsPersistJob(持久化锁)
- BadgeDeviceStatusRedisDAO(IoT 侧工牌状态)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-03-30 11:36:18 +08:00
edf0a3e645
fix(clean): 修复 CleanOrderEndToEndTest 编译错误
...
Java CI with Maven / build (11) (push) Has been cancelled
Java CI with Maven / build (17) (push) Has been cancelled
Java CI with Maven / build (8) (push) Has been cancelled
sendPriorityUpgradeNotification 已从 CleanOrderEventListener 移至
CleanOrderNotificationService,测试中 verify 目标未同步更新。
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-03-27 16:38:56 +08:00
55ef659364
feat(ops): 手动派单遵循执行人忙碌状态,忙碌时入队等待
...
ManualOrderActionFacade.dispatch:
- 新增 strategy.isAssigneeIdle() 判断,空闲→DISPATCHED,忙碌→QUEUED
- 不再无条件直接派发
OrderBusinessStrategy:
- 新增 isAssigneeIdle() 默认方法,默认返回 true
CleanOrderBusinessStrategy:
- isAssigneeIdle 通过 BadgeDeviceStatusService.isBusy() 判断设备忙碌
SecurityOrderBusinessStrategy:
- isAssigneeIdle 通过 UserDispatchStatusService.isIdle() 判断人员忙碌
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-03-27 16:37:30 +08:00
5d91097e75
feat(clean): 保洁条线接入 ManualOrderActionFacade
...
CleanOrderBusinessStrategy:
- validateDispatch: 校验设备在线/可接单/区域匹配
- afterUpgradePriority: adjustPriority + rebuildWaitingTasks + P0 通知
CleanWorkOrderServiceImpl:
- manualCreateOrder: 主表+扩展表+创建事件+审计日志
- manualDispatch/manualCancelOrder/manualCompleteOrder/upgradePriority: 委托 facade
- 所有入口统一 resolveUserName 传入 operatorName
UpgradePriorityReqDTO:新增 newPriority/operatorId 字段
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-03-27 16:08:20 +08:00
333329c29c
refactor(clean): 抽取 CleanOrderNotificationService,解除 listener 循环依赖
...
- 通知方法(语音播报/站内信)从 CleanOrderEventListener 迁移到 CleanOrderNotificationService
- CleanOrderServiceImpl 改为依赖 NotificationService 而非 Listener
- CleanOrderEventListener 补齐 QUEUED 和 PAUSED 状态的 business log
- 派单/取消日志从 handleDispatched/handleCancelled 内联改为独立 recordXxxLog 方法
- 硬编码字符串 "CLEAN" 统一替换为 WorkOrderTypeEnum.CLEAN.getType()
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-03-27 16:07:57 +08:00
e1d967a65e
feat(ops): 新增手动操作枚举与模型定义
...
引入统一手动动作基础设施:
- ManualActionTypeEnum: 手动动作类型(创建/派单/取消/完单/升级)
- OrderActionSourceEnum: 动作来源(管理后台/开放接口)
- OrderAuditPayloadKeys: 审计 payload 标准化 key
- OrderEventTypeEnum: 事件类型枚举值对齐状态机(DISPATCHED/QUEUED/CONFIRMED)
- OperatorContext: 统一操作人上下文
- *Command: 手动动作命令模型(Dispatch/Cancel/Complete/UpgradePriority)
- OrderBusinessStrategy: 条线策略接口
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-03-27 15:53:20 +08:00
47c768ec6f
feat(ops): 整改工单去重 — 已有活跃工单时升级优先级而非重复创建
...
- InspectionRectificationServiceImpl 先查区域活跃保洁工单:
排队中(PENDING/QUEUED)→升级一级优先级;已派发/已到达→静默跳过
- OpsOrderMapper 新增 selectActiveCleanOrder,使用枚举替代硬编码终态
- InspectionAsyncHandler 清理归属判定注释代码,替换为 TODO 标记
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-03-22 15:00:25 +08:00
f213510b03
refactor(ops): 巡检接口重构 — 位置校验前移、列表/详情分离、表单聚合
...
接口变更:
- 删除 POST /verify-location,位置校验改为前端本地蓝牙信标匹配
- 新增 GET /record/get 巡检记录详情(含明细项、照片)
- GET /list-by-area 升级为返回完整巡检表单(区域+检查项+信标配置)
- GET /record/page 返回类型改为 VO,新增区域全路径名称和巡检员姓名
- 提交和表单接口增加 inspector 角色校验
代码质量(Code Review 修复):
- 提取 buildAreaFullName 至 OpsBusAreaMapper 消除两个 Service 的重复
- 新增 buildAreaFullNameMap 批量方法,修复分页场景 N+1 查询
- getRecordDetail 中 adminUserApi 改用 getUserMap + try-catch 降级
- InspectionTemplateServiceImpl 去掉 ObjectMapper 依赖,直接 Map 取值
- RSSI 阈值取最宽松值逻辑添加语义注释
- 巡检错误码从 1-020-003 迁移至 1-020-004,修复与安保模块的码段冲突
- InspectionRecordDetailRespVO.photos 使用 @OssPresignUrl 自动预签名
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-03-22 15:00:07 +08:00
4a105da46e
refactor(ops): 提取巡检结果和归属判定枚举,替换硬编码常量
...
新增 InspectionResultEnum(合格/不合格)和 InspectionAttributionEnum
(个人责任/突发状况/正常),替换 InspectionRecordServiceImpl 和
InspectionAttributionServiceImpl 中的 private static final int 硬编码常量。
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-03-19 09:43:37 +08:00
a4ab24b29c
refactor(ops): 迁移 environment-biz DTO 至 service 层 dto 包
...
将 6 个保洁业务 DTO 从 dal.dataobject 包迁移至对应 service 层:
- cleanorder/dto/: ManualCompleteOrderReqDTO, UpgradePriorityReqDTO,
CleanOrderAutoCreateReqDTO, CleanOrderPauseReqDTO, CleanOrderResumeReqDTO
- badge/dto/: BadgeNotifyReqDTO
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-03-19 09:33:27 +08:00
c20a42f68a
feat(ops): 巡检记录新增快捷标签字段
...
巡检主记录和明细项新增 tags 字段(JSON 数组),支持巡检员在提交时
选择预设的快捷标签(如"地面污渍"、"垃圾未清理"),便于后续统计分析。
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com >
2026-03-19 09:22:25 +08:00
01e9a556ab
Merge branch 'master' of http://124.222.218.198:3000/XW-AIOT/aiot-platform-cloud into feature/cleaning-inspection
2026-03-18 23:01:09 +08:00
825c8eecca
refactor(ops): 提取 AreaPathBuilder 公共组件,消除保洁/安保 buildAreaPath 重复代码
...
将 CleanOrderServiceImpl 中的 buildAreaPath 私有方法提取到 ops-biz 公共层
AreaPathBuilder 组件,供各业务模块(保洁、安保等)共享使用。同时优化:
- 用正则 matches("\d+") 替代 try-catch NumberFormatException 做数字校验
- 增加相邻重复ID去重保护
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-03-15 10:30:03 +08:00
0345d0fe39
fix(ops): TTS 业务日志去除冗余"语音播报:"前缀
...
VoiceBroadcastService 和 TtsQueueConsumer 记录 TTS_SENT 日志时
直接使用播报文本内容,title 由 LogType.TTS_SENT 的 description
"语音播报"提供,避免 message 中重复出现。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-03-11 17:34:53 +08:00
6c8c57b932
fix(ops): 保洁工单日志去重,修复到岗/完成日志设备字段为 null
...
- AuditEventHandler 跳过 BEACON_ARRIVE_CONFIRMED 和
BEACON_COMPLETE_REQUESTED 审计事件,避免与状态变更日志重复
- recordOrderArrivedLog 当 payload 无 deviceKey 时从工单主表兜底,
null 字段不再输出
- recordOrderCompletedLog 同样增加 deviceKey 兜底逻辑
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-03-11 17:34:42 +08:00
5f804605c7
refactor(ops): 收口散落的 eventType 硬编码为 LogType 枚举引用
...
替换 CleanOrderCreateEventHandler、OrderLifecycleManagerImpl、
DispatchEngineImpl 中的字符串常量为 LogType.XXX.getCode(),
同时将 DispatchEngine 的 @BusinessLog description 改为"工单自动派发"。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-03-11 17:34:30 +08:00
713ae744ac
feat(ops): 客流阈值触发静默处理,工单完成时重置计数器防竞态
...
1. 已派发/已到达(DISPATCHED/CONFIRMED/ARRIVED)状态静默忽略客流触发,
仅排队中(PENDING/QUEUED)状态才升级优先级
2. 工单完成时先重置IoT客流计数器再清除活跃标记,防止残留计数
和MQ消息延迟导致的竞态误创建工单
3. 工单取消时仅清除活跃标记不重置计数器,保留客流数据以便尽快
重新触发
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-03-07 22:28:11 +08:00
a9fd9313cc
feat(ops): 重构派单队列评分逻辑,支持楼层差与等待老化综合排序
...
- 新增 QueueScoreCalculator/QueueScoreContext/QueueScoreResult,统一按优先级分 + 楼层差分 - 等待老化分计算队列总分,并将 PRIORITY_WEIGHT 调整为 1500
- OrderQueueService 新增 rebuildWaitingTasksByUserId 接口,OrderQueueServiceEnhanced 支持按执行人重算 WAITING 队列、以当前执行工单楼层为基准动态重排,并在事务提交后同步刷新 Redis
- RedisOrderQueueServiceImpl 支持持久化 baseFloorNo、targetFloorNo、floorDiff、waitMinutes、scoreUpdateTime 等评分明细,清队列时同时清理关联 Hash,避免脏数据残留
- DispatchEngineImpl、CleanerPriorityScheduleStrategy、BadgeDeviceScheduleStrategy 调整为非抢占式派单:P0 忙碌时仅入队等待,空闲时直接派发,自动派单前按总分重排并派发下一单
- CleanOrderServiceImpl 取消 P0 自动打断链路,升级到 P0 后仅重算等待队列并发送通知;补充 QueueScoreCalculatorTest、OrderQueueServiceEnhancedTest、CleanerPriorityScheduleStrategyTest、CleanOrderEndToEndTest 覆盖新行为
2026-03-07 21:15:10 +08:00
e3882e1c2f
fix(ops): code review 修复巡检模块6项问题
...
1. @Async 指定 ops-task-executor 线程池,避免使用默认线程池
2. 归属判定无工单/无标准时长时标记为 ATTRIBUTION_NORMAL(3),不再静默跳过
3. 补充 completionSeconds 字段语义注释和 standardDuration 单位转换说明
4. 整改工单默认时长 30 提取为 DEFAULT_RECTIFICATION_DURATION_MINUTES 常量
5. SQL 补充 idx_generated_order_id 和 idx_template_id 索引
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-03-05 20:40:36 +08:00
f70402587d
feat(ops): 巡检统计接口(合格率、不合格热点区域 TOP10)
...
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-03-05 20:13:13 +08:00
743875e65e
feat(ops): 巡检记录分页查询接口(按区域/巡检员/结果/时间筛选)
...
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-03-05 20:11:21 +08:00
23cf3b62b2
fix(ops): 修复巡检异步处理的 @Async 自调用和事务可见性问题
...
Code review 发现两个关键缺陷:
1. @Async 自调用:triggerAttributionAsync() 在同一类内调用,
Spring AOP 代理不生效,实际同步执行
2. 事务可见性:异步任务可能在事务提交前读取未持久化数据
修复方案:
- 提取 InspectionAsyncHandler(独立 @Component),@Async 通过代理生效
- 使用 TransactionSynchronizationManager.afterCommit() 确保事务提交后触发
- 修复 InspectionRectificationServiceImpl 的 null 安全问题
- 修复 InspectionTemplateServiceImpl 更新路径缺少 id 空校验
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-03-05 19:30:01 +08:00
162bf1d20d
feat(ops): 巡检整改工单自动创建(Task 7)
...
- InspectionRectificationService + Impl: 不合格巡检自动创建整改工单
- 复用 CleanOrderService.createAutoCleanOrder() 对接现有工单引擎
- sourceType = INSPECTION, priority = P1, cleaningType = SPOT
- generated_order_id 回写到巡检记录
- InspectionRecordServiceImpl: 异步流程增加整改工单创建步骤
- 归属判定与整改工单创建独立 try/catch,互不阻塞
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-03-05 19:23:34 +08:00
3120b1911d
feat(ops): 巡检归属判定异步服务(Task 6)
...
- InspectionAttributionService + Impl: 归属判定核心逻辑
- 回溯区域最近 COMPLETED 工单,获取 completionSeconds
- 与 ops_bus_area.standardDuration 比较判定责任归属
- T_stay >= threshold → 突发状况(2),< threshold → 个人责任(1)
- 判定结果回写 inspection_record(lastOrderId, stayDuration, attributionResult)
- InspectionRecordServiceImpl: 注入 AttributionService,异步调用含异常兜底
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-03-05 19:18:56 +08:00
e4dde8dbc1
feat(ops): 巡检结果提交接口(Task 5)
...
- InspectionRecordService + Impl: 提交巡检主记录+明细,同事务保存
- 自动判定 resultStatus:任一项不合格则整体不合格
- 不合格时异步触发归属判定(Task 6 占位)
- InspectionSubmitReqVO/ItemVO: 带校验注解的请求 VO
- InspectionRecordRespVO: 巡检记录响应 VO
- InspectionController 新增 POST /submit 端点
- ErrorCodeConstants 新增 INSPECTION_RECORD_NOT_FOUND
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-03-05 19:15:01 +08:00
fa45d94247
feat(ops): 蓝牙位置校验服务及接口(Task 4)
2026-03-05 17:07:48 +08:00
99651be386
feat(ops): 巡检模板CRUD及动态表单接口(Task 2+3)
2026-03-05 17:04:45 +08:00
7d1012bba7
fix(iot,ops): 修复退出检测停滞、TTS多租户重复播报,精简语音通知
...
Java CI with Maven / build (11) (push) Has been cancelled
Java CI with Maven / build (17) (push) Has been cancelled
Java CI with Maven / build (8) (push) Has been cancelled
1. 蓝牙信号缺失补偿:设备属性上报不含 bluetoothDevices 时注入 null,
避免 RSSI 滑动窗口因无数据停滞导致退出检测延迟
2. TTS 多租户去重:TtsQueueMessage 携带 tenantId,processSingleQueue
过滤非当前租户消息,解决 @TenantJob 导致同一播报被不同租户重复下发
3. 循环播报日志精简:仅在 broadcastLoop 启动时记录一次 TTS_SENT,
后续重复播报不再写入 ops_business_event_log
4. 移除离岗 TTS 警告和入队语音播报,减少不必要的设备干扰
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-02-27 13:09:56 +08:00
7c22fe998e
fix(ops): 统一 Redis 序列化为 StringRedisTemplate,修复跨模块/跨路径数据不兼容
...
Java CI with Maven / build (11) (push) Has been cancelled
Java CI with Maven / build (17) (push) Has been cancelled
Java CI with Maven / build (8) (push) Has been cancelled
BadgeDeviceStatusServiceImpl 和 RedisOrderQueueServiceImpl 原使用
RedisTemplate<String, Object>(Jackson JSON 序列化),但 Pipeline、
Lua 脚本写入的裸字符串与 Jackson 格式不兼容,导致:
- IoT 模块 StringRedisTemplate 读取工单状态比对失败(按键无法确认)
- 队列 entries() 反序列化失败(REMOVED 记录无法清理,持续报错)
修改内容:
- BadgeDeviceStatusServiceImpl: RedisTemplate → StringRedisTemplate
- RedisOrderQueueServiceImpl: RedisTemplate → StringRedisTemplate
- 所有写入值显式 String.valueOf(),读取用 parse 替代强转
- 修复 null 值写入 StringRedisSerializer 导致 NPE 的隐患
- application.yaml: TTS 播报间隔 6000ms → 3000ms
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-02-27 10:50:03 +08:00
c21c77c758
fix(ops): 修复按键播报延迟和循环停止失败问题
...
Java CI with Maven / build (11) (push) Has been cancelled
Java CI with Maven / build (17) (push) Has been cancelled
Java CI with Maven / build (8) (push) Has been cancelled
1. 播报间隔从6秒缩短为3秒
2. stopLoop 清除播报间隔锁,使后续播报可立即发送
3. 按键触发的播报改用 broadcastDirect 直接下发,不走队列
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com >
2026-02-26 18:04:36 +08:00