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>
This commit is contained in:
@@ -45,7 +45,8 @@ CREATE TABLE `ops_inspection_record` (
|
|||||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `idx_area_id` (`area_id`),
|
KEY `idx_area_id` (`area_id`),
|
||||||
KEY `idx_inspector_id` (`inspector_id`)
|
KEY `idx_inspector_id` (`inspector_id`),
|
||||||
|
KEY `idx_generated_order_id` (`generated_order_id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='巡检主记录';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='巡检主记录';
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
@@ -65,5 +66,6 @@ CREATE TABLE `ops_inspection_record_item` (
|
|||||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `idx_record_id` (`record_id`)
|
KEY `idx_record_id` (`record_id`),
|
||||||
|
KEY `idx_template_id` (`template_id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='巡检明细';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='巡检明细';
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ public class InspectionAsyncHandler {
|
|||||||
/**
|
/**
|
||||||
* 异步处理不合格巡检的后续逻辑
|
* 异步处理不合格巡检的后续逻辑
|
||||||
*/
|
*/
|
||||||
@Async
|
@Async("ops-task-executor")
|
||||||
public void handleFailedInspection(Long recordId, Long areaId) {
|
public void handleFailedInspection(Long recordId, Long areaId) {
|
||||||
// 1. 归属判定
|
// 1. 归属判定
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ public class InspectionAttributionServiceImpl implements InspectionAttributionSe
|
|||||||
private static final int ATTRIBUTION_PERSONAL = 1;
|
private static final int ATTRIBUTION_PERSONAL = 1;
|
||||||
/** 归属判定:突发状况(停留时长达标) */
|
/** 归属判定:突发状况(停留时长达标) */
|
||||||
private static final int ATTRIBUTION_EMERGENCY = 2;
|
private static final int ATTRIBUTION_EMERGENCY = 2;
|
||||||
|
/** 归属判定:正常(合格巡检,无需判定) */
|
||||||
|
private static final int ATTRIBUTION_NORMAL = 3;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private OpsInspectionRecordMapper inspectionRecordMapper;
|
private OpsInspectionRecordMapper inspectionRecordMapper;
|
||||||
@@ -47,23 +49,26 @@ public class InspectionAttributionServiceImpl implements InspectionAttributionSe
|
|||||||
.last("LIMIT 1"));
|
.last("LIMIT 1"));
|
||||||
|
|
||||||
if (lastOrder == null) {
|
if (lastOrder == null) {
|
||||||
log.warn("[determineAttribution] 区域 {} 无已完成工单,跳过归属判定: recordId={}", areaId, recordId);
|
log.warn("[determineAttribution] 区域 {} 无已完成工单,标记为正常: recordId={}", areaId, recordId);
|
||||||
|
updateAttributionResult(recordId, null, null, ATTRIBUTION_NORMAL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 获取保洁员实际停留时长(秒)
|
// 2. 获取保洁员实际停留时长(秒)
|
||||||
|
// completionSeconds 记录的是工单从开始到完成的耗时,即实际作业时长
|
||||||
Integer stayDurationSeconds = lastOrder.getCompletionSeconds();
|
Integer stayDurationSeconds = lastOrder.getCompletionSeconds();
|
||||||
if (stayDurationSeconds == null) {
|
if (stayDurationSeconds == null) {
|
||||||
stayDurationSeconds = 0;
|
stayDurationSeconds = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 获取区域标准时长(分钟 → 秒)
|
// 3. 获取区域标准时长(standardDuration 单位为分钟,转换为秒)
|
||||||
OpsBusAreaDO area = opsBusAreaMapper.selectById(areaId);
|
OpsBusAreaDO area = opsBusAreaMapper.selectById(areaId);
|
||||||
if (area == null || area.getStandardDuration() == null) {
|
if (area == null || area.getStandardDuration() == null) {
|
||||||
log.warn("[determineAttribution] 区域 {} 无标准时长配置,跳过归属判定: recordId={}", areaId, recordId);
|
log.warn("[determineAttribution] 区域 {} 无标准时长配置,标记为正常: recordId={}", areaId, recordId);
|
||||||
|
updateAttributionResult(recordId, lastOrder.getId(), stayDurationSeconds, ATTRIBUTION_NORMAL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int standardDurationSeconds = area.getStandardDuration() * 60;
|
int standardDurationSeconds = area.getStandardDuration() * 60; // 分钟 → 秒
|
||||||
|
|
||||||
// 4. 判定归属
|
// 4. 判定归属
|
||||||
// T_stay >= clean_threshold → 突发状况(保洁员已做到位,不扣分)
|
// T_stay >= clean_threshold → 突发状况(保洁员已做到位,不扣分)
|
||||||
@@ -73,15 +78,20 @@ public class InspectionAttributionServiceImpl implements InspectionAttributionSe
|
|||||||
: ATTRIBUTION_PERSONAL;
|
: ATTRIBUTION_PERSONAL;
|
||||||
|
|
||||||
log.info("[determineAttribution] 归属判定完成: recordId={}, areaId={}, lastOrderId={}, " +
|
log.info("[determineAttribution] 归属判定完成: recordId={}, areaId={}, lastOrderId={}, " +
|
||||||
"stayDuration={}s, standardDuration={}s, result={}",
|
"stayDuration={}s, standardDuration={}s({}min), result={}",
|
||||||
recordId, areaId, lastOrder.getId(),
|
recordId, areaId, lastOrder.getId(),
|
||||||
stayDurationSeconds, standardDurationSeconds, attributionResult);
|
stayDurationSeconds, standardDurationSeconds, area.getStandardDuration(), attributionResult);
|
||||||
|
|
||||||
// 5. 回写巡检记录
|
// 5. 回写巡检记录
|
||||||
|
updateAttributionResult(recordId, lastOrder.getId(), stayDurationSeconds, attributionResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateAttributionResult(Long recordId, Long lastOrderId,
|
||||||
|
Integer stayDuration, int attributionResult) {
|
||||||
OpsInspectionRecordDO update = new OpsInspectionRecordDO();
|
OpsInspectionRecordDO update = new OpsInspectionRecordDO();
|
||||||
update.setId(recordId);
|
update.setId(recordId);
|
||||||
update.setLastOrderId(lastOrder.getId());
|
update.setLastOrderId(lastOrderId);
|
||||||
update.setStayDuration(stayDurationSeconds);
|
update.setStayDuration(stayDuration);
|
||||||
update.setAttributionResult(attributionResult);
|
update.setAttributionResult(attributionResult);
|
||||||
inspectionRecordMapper.updateById(update);
|
inspectionRecordMapper.updateById(update);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ import org.springframework.validation.annotation.Validated;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class InspectionRectificationServiceImpl implements InspectionRectificationService {
|
public class InspectionRectificationServiceImpl implements InspectionRectificationService {
|
||||||
|
|
||||||
|
/** 默认整改工单预计时长(分钟) */
|
||||||
|
private static final int DEFAULT_RECTIFICATION_DURATION_MINUTES = 30;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private CleanOrderService cleanOrderService;
|
private CleanOrderService cleanOrderService;
|
||||||
|
|
||||||
@@ -38,7 +41,7 @@ public class InspectionRectificationServiceImpl implements InspectionRectificati
|
|||||||
OpsBusAreaDO area = opsBusAreaMapper.selectById(areaId);
|
OpsBusAreaDO area = opsBusAreaMapper.selectById(areaId);
|
||||||
String areaName = (area != null) ? area.getAreaName() : "未知区域";
|
String areaName = (area != null) ? area.getAreaName() : "未知区域";
|
||||||
int expectedDuration = (area != null && area.getStandardDuration() != null)
|
int expectedDuration = (area != null && area.getStandardDuration() != null)
|
||||||
? area.getStandardDuration() : 30;
|
? area.getStandardDuration() : DEFAULT_RECTIFICATION_DURATION_MINUTES;
|
||||||
|
|
||||||
// 2. 构建整改工单请求
|
// 2. 构建整改工单请求
|
||||||
CleanOrderAutoCreateReqDTO createReq = new CleanOrderAutoCreateReqDTO();
|
CleanOrderAutoCreateReqDTO createReq = new CleanOrderAutoCreateReqDTO();
|
||||||
|
|||||||
Reference in New Issue
Block a user