|
|
3e248fee8c
|
fix(ops): 补齐状态转换审计闭环,回滚场景也留痕到 bus_log
问题:ops_order_event 在主事务内写,事务 rollback 则整段记录消失;
若状态机转换抛异常或并发冲突被拒,线上只有控制台日志而无数据库审计,
运维难以追溯"是谁、在什么时候、尝试做了什么转换、为什么失败"。
设计:中央事件发布 + TransactionalEventListener 双阶段落盘
1. OrderTransitionAttemptedEvent(新)
覆盖 transition 成功、失败、FOR UPDATE 被拒三种情况,携带 orderId、
fromStatus、targetStatus、errorCode、errorMessage、causeSummary 等。
2. OrderLifecycleManagerImpl
- transition 成功分支:publishAttempt(success=true)
- transition 失败分支(context.hasError):publishAttempt(success=false,
errorCode=INVALID_TRANSITION, cause=摘要)
- dispatch FOR UPDATE 命中分支:publishAttempt(success=false,
errorCode=ASSIGNEE_HAS_ACTIVE_ORDER)
publishAttempt 内部 try/catch,审计失败不影响主流程。
3. OrderTransitionAuditListener(新)
- @TransactionalEventListener(AFTER_COMMIT, fallbackExecution=true)
主事务已提交,按事件本身的 success 写 bus_log;INFO 级。
- @TransactionalEventListener(AFTER_ROLLBACK) + @Transactional(REQUIRES_NEW)
主事务已回滚,事件里声称的 success 强制视为失败;独立事务写 bus_log
避免因主事务回滚而日志同样丢失。
- errorCode、fromStatus、targetStatus、reason、cause 全部落 payload。
- 冲突(ASSIGNEE_HAS_ACTIVE_ORDER)→ WARN;其他失败 → ERROR。
4. LogType 新增 TRANSITION_FAILED、DISPATCH_REJECTED。
5. EventLogRecorder 接口补 recordSync(实现类已有同名方法)。
运维查询:按 eventDomain='dispatch' + eventLevel IN ('WARN','ERROR')
即可一眼看出所有"尝试但未成功"的状态转换。errorCode 留在 payload JSON 内,
未升级为一等字段(后续如需聚合统计再迁移)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-04-20 13:11:28 +08:00 |
|
|
|
b534d79434
|
fix(ops): 派发入口加 FOR UPDATE 并发兜底,冲突时降级入队避免悬空
业务不变量:同一执行人在任一时刻最多只有 1 条活跃工单
(DISPATCHED/CONFIRMED/ARRIVED)。PAUSED 不纳入——P0 打断恢复
走 PAUSED→DISPATCHED,此处必须放行。
实现:
1. OpsOrderMapper.selectActiveByAssigneeForUpdate
查询 assignee 活跃工单并对命中行加 FOR UPDATE 排他锁。必须在
事务中调用。
2. OrderLifecycleManagerImpl.dispatch 入口校验
事务开启后立即执行 FOR UPDATE 查询,命中则返回带错误码
ASSIGNEE_HAS_ACTIVE_ORDER 的失败结果,不再执行责任链,
事务 commit 空操作、锁释放;并发竞争的第二个线程会阻塞到
第一个 commit 后看到活跃单,失败退出。
3. 新增 TransitionErrorCode 枚举 + OrderTransitionResult.errorCode
调用方可区分需降级的冲突与硬失败,避免把"可降级"的结果
直接抛给用户。
4. DispatchEngineImpl.executeDirectDispatch 降级逻辑
- 冲突 + 原状态 PENDING → 调 executeEnqueueOnly 降级到 QUEUED,
工单不悬空,等下一轮 autoDispatchNext 重挑。
- 冲突 + 原状态已是 QUEUED(并发另一路抢先派发时回滚保留)
→ 返回 fail 但不重复入队,天然等下一轮。
- 其他失败 → 照常 fail。
职责划分:
- 生命周期层负责"拒绝违反不变量的转换"
- 编排层负责"失败后给工单安置归宿"
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-04-20 11:52:38 +08:00 |
|
|
|
c24b1eb641
|
fix(ops): 直接派发加空闲兜底 + 队列同步按活跃状态过滤
1. 直接派发空闲兜底(补 autoDispatchNext 之外的另一条派发入口)
DispatchEngineImpl.executeDispatch 在 DIRECT_DISPATCH/PUSH_AND_ENQUEUE
前增加 MySQL 兜底校验:若执行人仍挂活跃工单(Redis 判空闲但 MySQL
不一致的场景),强制降级为 ENQUEUE_ONLY 让任务进队列等待下一轮
autoDispatchNext 接力。避免同一设备再次出现并行多单。
2. 队列同步按活跃状态过滤
syncUserQueueToRedis / getTasksByUserId 的 MySQL 回填路径此前调用
selectListByUserId 不过滤状态,会把历史 REMOVED 记录一并同步到
Redis(线上观察到设备 31 的 Redis ZSet 塞了 206 条、其中 205 条是
REMOVED)。新增 OpsOrderQueueMapper.selectActiveListByUserId,只返
回 WAITING/PROCESSING/PAUSED,两条同步链路改走此方法。原 selectList
ByUserId 保留给审计/统计场景。
未清理历史 REMOVED 记录,保留审计追溯。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
2026-04-20 11:22:18 +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 |
|
|
|
6bbd49355d
|
fix(ops): 修复工单编号生成器 Redis 序号与数据库不同步导致的重复编号问题
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
问题:Redis 重启或 key 过期后序号从 1 重新计数,与数据库已有编号冲突。
修复方案:
- 应用启动后首次生成时,从数据库查询当天最大序号校准 Redis
- 使用 Lua 脚本原子操作(校准 + 自增),避免并发竞态
- 后续调用走纯 Redis INCR,无额外数据库开销
- SQL 使用 deleted = b'0' 兼容 bit(1) 列类型
- LIKE 查询转义 % 和 _ 通配符
- 校准异常向上抛出,避免静默产生重复
- calibratedKeys 跨天自动清理旧条目
同步更新单元测试,覆盖校准、纯 Redis 自增、异常处理、SQL 转义等 13 个用例。
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-04-13 23:19:20 +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 |
|
|
|
a32a4375bc
|
build(ci): CI/CD 支持 release/next 预发布分支
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
- Jenkinsfile: Deploy 和 Health Check 阶段支持 release/next 分支
- release/next 部署到 staging 服务器(172.17.16.7),master 部署到 prod
- 仅 master 分支推送 latest 镜像标签,避免预发布覆盖生产镜像
- GitHub Actions 添加 release/next 分支触发构建
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-04-13 14:44:20 +08:00 |
|
|
|
1ca472ea93
|
feat(iot): 客流计数器支持累计值上报模式(CUMULATIVE)
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
TrafficThresholdConfig 新增 reportMode 字段,支持 INCREMENTAL(默认)和 CUMULATIVE 两种模式。
累计值设备通过 Redis 存储上次值自动算差值,处理首次上报跳过和设备重启归零场景。
现有增量设备无需改配置,行为完全兼容。
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-04-09 13:59:20 +08:00 |
|
|
|
c8ba3e63cb
|
feat(iot): 新增恒华D5客流摄像机编解码器,对接拌线人数统计(type=1)
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
走通用路由,新增 IotHenghuaD5Codec 解析 form-urlencoded 格式数据,
映射 InNum/OutNum 到 people_in/people_out,业务层完全复用现有客流阈值逻辑。
IotHttpUpstreamHandler 增加恒华D5 专用简洁响应。
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-04-07 14:59:53 +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 |
|
|
|
b379fc6741
|
feat(ops): timeline 接口 deviceId 改为可选,支持全设备查询
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
不传 deviceId 时查询该日期所有设备的轨迹记录,复用
selectByDateAndDevice 的 LIMIT 5000 安全上限。
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
|
2026-04-05 15:27:05 +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 |
|
|
|
368fa90156
|
refactor(ops): 轨迹区域展示改用 fullAreaName 替代 buildingName/floorNo
TrajectoryRespDTO 移除 buildingName、floorNo 字段,新增 fullAreaName
(完整路径如"A园区/A栋/3层/男卫")。AreaPathBuilder 新增 buildPaths
批量方法,一次查询所有父级区域避免 N+1;正则预编译为静态常量。
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
|
2026-04-05 15:25:47 +08:00 |
|
|
|
9780d6c3f7
|
fix(ops): 区域设备 RPC 接口添加 @TenantIgnore 解决定时任务调用时租户上下文缺失
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
IoT 模块 BeaconRegistryServiceImpl 每30分钟通过 Feign 调用 /beacons/all 接口,
因定时任务无租户上下文导致 TenantContextHolder NPE。对跨租户查询的方法添加
@TenantIgnore 注解忽略多租户过滤。
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-04-01 09:23:27 +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 |
|
|
|
5d46502fb9
|
fix(ops): 启动时恢复工单队列缓存
- 新增 OrderQueueInitializer\n- 服务启动时调用 QueueSyncService.forceSyncAll()\n- 在 Redis 队列数据丢失或过期后,自动用 MySQL 数据回填 Sorted Set
|
2026-03-31 22:58:25 +08:00 |
|
|
|
306303ab16
|
fix(ops): 启动时校准人员调度状态
- 为 UserDispatchStatusService 增加基于 DB 的重建能力\n- 扫描 Redis 中的人员调度 key,按实际活跃工单数修正 status、activeOrderCount、waitingTaskCount\n- 新增启动初始化器,服务启动时自动执行一次校准,缓解事件丢失导致的 BUSY 残留
|
2026-03-31 22:58:09 +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 |
|
|
|
d3eecc63ef
|
feat(trajectory): 新增轨迹后台查询与实时位置接口
- 新增轨迹分页、时间线、统计摘要等查询 DTO\n- 提供轨迹后台控制器,支持工牌下拉、轨迹查询、实时位置查询\n- 接入 TrajectoryStateApi 的 Feign 配置,打通 Ops 对 IoT 实时位置状态的读取
|
2026-03-31 22:56:49 +08:00 |
|
|
|
bf5aa21648
|
feat(trajectory): 新增轨迹事件消费与落库模型
- 新增 ops_device_trajectory 表及轨迹数据对象、Mapper\n- 消费 trajectory-enter / trajectory-leave 事件并做幂等处理\n- 落地设备进入/离开区域记录,补充停留时长与离开原因字段\n- 在服务层封装轨迹写入、关闭未离场记录等核心逻辑
|
2026-03-31 22:56:18 +08:00 |
|
|
|
11dcb57ff3
|
feat(trajectory): 新增轨迹检测与 Beacon 注册表
|
2026-03-31 22:53:06 +08:00 |
|
|
|
a9941a29a9
|
fix(ops): 状态机允许 CONFIRMED → COMPLETED,支持安保确认后直接完单
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
安保工单不需要信标到岗检测(ARRIVED),确认接单后可直接提交处理结果完成。
原规则 CONFIRMED → {ARRIVED, CANCELLED} 缺少 COMPLETED,导致安保人员完单报错:
"非法状态转换: CONFIRMED -> COMPLETED"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-03-27 17:11:49 +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 |
|
|
|
78396cf35a
|
fix(ops): 调度状态补偿 QUEUED→终态跳过 DISPATCHED 场景
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
UserDispatchStatusEventListener:
- assigneeId 兜底从工单主表获取(forceComplete 等 payload 缺失场景)
- QUEUED→COMPLETED/CANCELLED 补偿 decrementWaitingTaskCount
UserDispatchStatusServiceImpl:
- 新增 LUA_DECREMENT_WAITING 脚本,安全递减 waitingTaskCount(不低于 0)
OpsOrderEventService:新增 8 参数 recordEvent 重载(含 operatorName)
DispatchEngineServiceAdapter:reason 文案统一为"手动派单"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-03-27 16:09:30 +08:00 |
|
|
|
06d701ed5e
|
refactor(ops): 通用控制器收口,手动动作移至条线控制器
OpsOrderController:
- 移除 create/assign/complete/cancel 接口,避免绕过条线入口
- 保留查询、元数据维护、设备/人员驱动的状态操作(accept/pause/resume)
- 新增 business-logs 查询接口
CleanWorkOrderController:新增手动创建/派单/取消端点
SecurityOrderController:新增手动派单/取消/升级优先级端点
ErrorCodeConstants:新增安保条线错误码
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-03-27 16:09:07 +08:00 |
|
|
|
1d09a50643
|
feat(security): 安保条线接入 ManualOrderActionFacade
SecurityOrderBusinessStrategy:
- validateDispatch: 去除区域绑定强限制,允许跨区域派单,保留姓名回填
- afterUpgradePriority: 队列分数重算
SecurityOrderServiceImpl:
- manualDispatch: resolveUser 一次查询同时拿姓名和手机号
- manualCancel/upgradePriority: 委托 facade,传入 operatorName
- 手动创建走 OrderAuditService 审计(告警触发仅写业务日志)
SecurityOrderEventListener:
- 3 处 resolveOperatorName() 改为从 event.payload.operatorName 读取
- 移除 AdminUserApi 依赖,消除重复远程调用
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-03-27 16:08:48 +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 |
|
|
|
6e5366be57
|
feat(ops): OrderTransitionRequest 新增 operatorName,EventPublishHandler 透传到事件 payload
手动操作场景下 operatorName 沿 facade → request → EventPublishHandler → payload 透传,
listener 从 payload 直接读取,不再重复调用 AdminUserApi。
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-03-27 16:07:34 +08:00 |
|
|
|
6b01c29cb1
|
feat(ops): 新增统一手动动作门面与审计服务
ManualOrderActionFacade:
- 统一骨架:查单校验 → 条线前置 → 状态变更 → 条线后置
- dispatch 支持 PENDING/QUEUED 状态,用独立对象更新 assignee 避免覆盖状态机已写入的 status
- cancel/complete 走 transition() 透传 operatorName 到领域事件
- dispatch/cancel/complete 业务日志由 listener 统一记录,不重复写
OrderAuditService:
- 仅用于 create/upgradePriority(不经过状态机的手动动作)
- 只写 ops_business_event_log,不写 ops_order_event(时间轴只由状态机写)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-03-27 16:07:13 +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 |
|
|
|
4dffd21751
|
fix(security): 工单取消日志区分操作来源
根据 operatorType 区分日志描述:
- SYSTEM → "系统自动取消(原因)"
- ADMIN → "管理员手动取消(原因)"
- 其他 → "安保工单已取消(原因)"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-03-26 16:14:34 +08:00 |
|
|
|
4763caf2cc
|
fix(ops): 移除 OrderLifecycleManager 中重复的业务日志记录
LifecycleManager 是通用层,业务日志统一由各业务线 EventListener 负责。
移除 cancelOrder、completeOrder(ADMIN)、pauseOrder、resumeOrder 中的
eventLogRecorder 调用,避免与 SecurityOrderEventListener 等监听器产生
重复日志记录。保留 interruptOrder 的日志(P0 打断是通用机制)。
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-03-26 16:09:58 +08:00 |
|
|
|
bde680c188
|
fix(ops): VspNotifyClient 强制 HTTP/1.1,修复 h2c 升级导致 body 丢失
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
JDK 17 HttpClient 默认尝试 HTTP/2 升级(h2c),uvicorn 不支持 h2c
协商,处理 Upgrade 请求时丢弃 body,导致 Python 端收到空 {}。
强制 HTTP_1_1 禁用 h2c 升级。
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-03-26 16:04:32 +08:00 |
|
|
|
93bc1f10c3
|
fix(security): 规范安保工单事件日志,消除重复记录
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
修复前同一次派发产生 4 条 ORDER_DISPATCHED 日志的问题:
- 新增 ORDER_QUEUED 枚举,handleQueued 改用正确的 event_type
- handleArrived 改用 ORDER_ARRIVED(之前错用 ORDER_CONFIRM)
- 移除 onOrderCreated 中派单成功的重复日志(由状态监听统一记录)
- 移除 DispatchEngineImpl.dispatch 上的 @BusinessLog 注解(避免与
业务层 EventListener 日志重复)
- ORDER_DISPATCHED 描述改为"工单派发",ORDER_ARRIVED 改为"人员到达"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-03-26 15:30:42 +08:00 |
|
|
|
bd70f3bc8a
|
fix(ops): 修复队列脏数据导致工单永远排队无法派发
问题:autoCompleteOrder 直接调用 orderStateMachine.forceTransition,
绕过责任链导致队列记录残留 WAITING,autoDispatchNext 反复命中脏数据
失败,人员状态永远 BUSY,新工单全部 ENQUEUE_ONLY 形成死循环。
修复:
1. SecurityOrderServiceImpl 所有状态操作统一走 OrderLifecycleManager,
移除对 OrderStateMachine 的直接依赖
2. autoDispatchNext 增加循环遍历 + 工单状态校验,跳过并清理非 QUEUED
的脏队列记录,增加 maxSkip=50 防护上限
3. forceComplete 返回值校验,失败时抛异常而非静默继续
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-03-26 15:30:02 +08:00 |
|
|
|
8406a80655
|
feat(ops): OrderLifecycleManager 支持 forceComplete 强制完成工单
新增 forced 字段到 OrderTransitionRequest,StateTransitionHandler 根据
该字段选择 transition 或 forceTransition,确保强制状态转换也走完整
责任链(队列同步 + 事件发布),避免绕过 QueueSyncHandler 产生脏数据。
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-03-26 15:29:29 +08:00 |
|
|
|
c0c9854e73
|
fix(security): sendCard 改为 DISPATCHED 状态变更时发送 + @EventListener
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
- 将 sendCard 从 onOrderCreated 移至 handleDispatched
- 使用 @EventListener 替代 @TransactionalEventListener(AFTER_COMMIT)
确保 autoDispatchNext 场景的 DISPATCHED 事件也能触发
- PAUSED → DISPATCHED 恢复场景跳过重发
- 参考保洁模块 CleanOrderEventListener 的实现模式
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-03-26 14:06:31 +08:00 |
|
|
|
68b6f45d53
|
fix(ops): 修复 prod 环境 alarm-system 签名校验失败
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
prod profile 启动时 application-prod.yaml 为空,主 application.yaml
缺少 viewsh.signature.apps.alarm-system 配置,导致告警系统调用
SecurityOrderOpenController.createOrder 时报错:
[appId(alarm-system)] 找不到对应的 appSecret
将签名配置添加到主 application.yaml 作为所有环境的兜底。
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-03-25 16:48:09 +08:00 |
|
|
|
5c868c8003
|
chore(ops): 更新 vsp-notify 地址为 172.17.16.14
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
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-03-25 15:46:53 +08:00 |
|
|
|
394b644a4e
|
feat(security): 安保工单接入队列调度,支持入队等待和负载均衡
改造安保调度策略,接入 UserDispatchStatusService:
SecurityScheduleStrategy:
- 读 Redis 判断人员忙碌/空闲,决策 DIRECT_DISPATCH / PUSH_AND_ENQUEUE / ENQUEUE_ONLY
- PAUSED 状态视为忙碌,不给暂停中的人员推送新工单
- 替换原来的始终 DIRECT_DISPATCH 逻辑
SecurityAreaAssignStrategy:
- Pipeline 批量读 Redis 获取每人活跃工单数
- 选负载最轻的人员,同等负载取 sort 最小
SecurityOrderEventListener:
- 新增 QUEUED 分支,入队时写入 assignee 信息到扩展表
- 取消工单后自动派发下一个等待工单(兜底从 ops_order 表获取 assigneeId)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-03-25 15:46:19 +08:00 |
|
|
|
9115e03878
|
feat(ops): 新增通用人员调度状态服务 UserDispatchStatusService
基于 Redis Hash 维护人员维度的调度状态,供安保/工程/客服业务线共用。
与保洁的 BadgeDeviceStatusService(设备维度)并行。
核心设计:
- Redis Key: ops:user:dispatch:{userId},存储 status/activeOrderCount/waitingTaskCount 等
- 所有写操作使用 Lua 脚本原子执行,保证多业务线并发安全
- 事件监听器 @EventListener(事务内同步)自动排除 CLEAN 类型
- Redis 丢数据时降级为 IDLE,下一次事件自动重建(自愈)
新增文件:
- UserDispatchStatusDTO (ops-api)
- UserDispatchStatusService 接口 (ops-biz)
- UserDispatchStatusServiceImpl - Lua 脚本实现 (ops-biz)
- UserDispatchStatusEventListener - 通用事件监听 (ops-biz)
- UserAssigneeStatusAdapter - AssigneeStatus 适配器 (ops-biz)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-03-25 15:44:42 +08:00 |
|
|
|
53f51e7336
|
feat(security): 安保扩展表新增 assigned_user_phone 字段及迁移脚本
建表 SQL 补充 camera_name 和 assigned_user_phone 列;
新增增量迁移脚本 ops_order_security_ext_migrate_v1.2.sql。
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-03-25 14:27:04 +08:00 |
|
|
|
0dfc669488
|
feat(security): 安保派单补充处理人手机号,接口返回 phone 和 cameraName
- SecurityAreaAssignStrategy 注入 AdminUserApi,从用户表查询
nickname 和 mobile 替代冗余字段
- OpsOrderSecurityExtDO 新增 assignedUserPhone 字段
- SecurityOrderEventListener.handleDispatched 写入 assignedUserId、
assignedUserName、assignedUserPhone 到扩展表
- SecurityOrderExtQueryHandler 接口返回补充 assignedUserPhone 和
cameraName
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-03-25 14:26:54 +08:00 |
|
|
|
718d14e162
|
feat(ops): 派单链路全程传递 assigneeName 和 assigneePhone
AssigneeRecommendation、OrderDispatchContext、OrderTransitionRequest
新增 assigneePhone 字段;DispatchEngineImpl 在三条派单路径中传递
phone;EventPublishHandler 将 assigneeName 和 assigneePhone 写入
事件 payload,修复下游监听器取不到 assigneeName 的问题。
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-03-25 14:26:40 +08:00 |
|
|
|
4c48f72c66
|
feat(security): 安保人员列表接口补充昵称和手机号
区域安保人员查询接口批量关联 AdminUserApi,
在响应中填充 nickname 和 mobile 字段
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
2026-03-25 11:31:09 +08:00 |
|