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>
This commit is contained in:
@@ -0,0 +1,21 @@
|
|||||||
|
package com.viewsh.module.ops.environment.service.inspection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巡检归属判定 Service 接口
|
||||||
|
*
|
||||||
|
* 当巡检结果为不合格时,异步执行归属判定:
|
||||||
|
* 1. 回溯该区域最近一个 COMPLETED 工单
|
||||||
|
* 2. 比较保洁员实际停留时长与区域标准时长
|
||||||
|
* 3. 判定责任归属并回写巡检记录
|
||||||
|
*/
|
||||||
|
public interface InspectionAttributionService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行归属判定
|
||||||
|
*
|
||||||
|
* @param recordId 巡检记录ID
|
||||||
|
* @param areaId 区域ID
|
||||||
|
*/
|
||||||
|
void determineAttribution(Long recordId, Long areaId);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package com.viewsh.module.ops.environment.service.inspection;
|
||||||
|
|
||||||
|
import com.viewsh.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||||
|
import com.viewsh.module.ops.dal.dataobject.area.OpsBusAreaDO;
|
||||||
|
import com.viewsh.module.ops.dal.dataobject.workorder.OpsOrderDO;
|
||||||
|
import com.viewsh.module.ops.dal.mysql.area.OpsBusAreaMapper;
|
||||||
|
import com.viewsh.module.ops.dal.mysql.workorder.OpsOrderMapper;
|
||||||
|
import com.viewsh.module.ops.environment.dal.dataobject.inspection.OpsInspectionRecordDO;
|
||||||
|
import com.viewsh.module.ops.environment.dal.mysql.inspection.OpsInspectionRecordMapper;
|
||||||
|
import com.viewsh.module.ops.enums.WorkOrderStatusEnum;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 巡检归属判定 Service 实现
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Validated
|
||||||
|
@Slf4j
|
||||||
|
public class InspectionAttributionServiceImpl implements InspectionAttributionService {
|
||||||
|
|
||||||
|
/** 归属判定:个人责任(停留时长不足) */
|
||||||
|
private static final int ATTRIBUTION_PERSONAL = 1;
|
||||||
|
/** 归属判定:突发状况(停留时长达标) */
|
||||||
|
private static final int ATTRIBUTION_EMERGENCY = 2;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private OpsInspectionRecordMapper inspectionRecordMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private OpsOrderMapper opsOrderMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private OpsBusAreaMapper opsBusAreaMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void determineAttribution(Long recordId, Long areaId) {
|
||||||
|
// 1. 回溯该区域最近一个 COMPLETED 工单
|
||||||
|
OpsOrderDO lastOrder = opsOrderMapper.selectOne(new LambdaQueryWrapperX<OpsOrderDO>()
|
||||||
|
.eq(OpsOrderDO::getAreaId, areaId)
|
||||||
|
.eq(OpsOrderDO::getStatus, WorkOrderStatusEnum.COMPLETED.getStatus())
|
||||||
|
.orderByDesc(OpsOrderDO::getEndTime)
|
||||||
|
.last("LIMIT 1"));
|
||||||
|
|
||||||
|
if (lastOrder == null) {
|
||||||
|
log.warn("[determineAttribution] 区域 {} 无已完成工单,跳过归属判定: recordId={}", areaId, recordId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 获取保洁员实际停留时长(秒)
|
||||||
|
Integer stayDurationSeconds = lastOrder.getCompletionSeconds();
|
||||||
|
if (stayDurationSeconds == null) {
|
||||||
|
stayDurationSeconds = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 获取区域标准时长(分钟 → 秒)
|
||||||
|
OpsBusAreaDO area = opsBusAreaMapper.selectById(areaId);
|
||||||
|
if (area == null || area.getStandardDuration() == null) {
|
||||||
|
log.warn("[determineAttribution] 区域 {} 无标准时长配置,跳过归属判定: recordId={}", areaId, recordId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int standardDurationSeconds = area.getStandardDuration() * 60;
|
||||||
|
|
||||||
|
// 4. 判定归属
|
||||||
|
// T_stay >= clean_threshold → 突发状况(保洁员已做到位,不扣分)
|
||||||
|
// T_stay < clean_threshold → 个人责任(保洁时长不足,扣信用分)
|
||||||
|
int attributionResult = stayDurationSeconds >= standardDurationSeconds
|
||||||
|
? ATTRIBUTION_EMERGENCY
|
||||||
|
: ATTRIBUTION_PERSONAL;
|
||||||
|
|
||||||
|
log.info("[determineAttribution] 归属判定完成: recordId={}, areaId={}, lastOrderId={}, " +
|
||||||
|
"stayDuration={}s, standardDuration={}s, result={}",
|
||||||
|
recordId, areaId, lastOrder.getId(),
|
||||||
|
stayDurationSeconds, standardDurationSeconds, attributionResult);
|
||||||
|
|
||||||
|
// 5. 回写巡检记录
|
||||||
|
OpsInspectionRecordDO update = new OpsInspectionRecordDO();
|
||||||
|
update.setId(recordId);
|
||||||
|
update.setLastOrderId(lastOrder.getId());
|
||||||
|
update.setStayDuration(stayDurationSeconds);
|
||||||
|
update.setAttributionResult(attributionResult);
|
||||||
|
inspectionRecordMapper.updateById(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -34,6 +34,9 @@ public class InspectionRecordServiceImpl implements InspectionRecordService {
|
|||||||
@Resource
|
@Resource
|
||||||
private OpsInspectionRecordItemMapper inspectionRecordItemMapper;
|
private OpsInspectionRecordItemMapper inspectionRecordItemMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private InspectionAttributionService inspectionAttributionService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public Long submitInspection(InspectionSubmitReqVO submitReqVO, Long inspectorId) {
|
public Long submitInspection(InspectionSubmitReqVO submitReqVO, Long inspectorId) {
|
||||||
@@ -72,12 +75,15 @@ public class InspectionRecordServiceImpl implements InspectionRecordService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 异步触发归属判定(Task 6 实现完整逻辑)
|
* 异步触发归属判定
|
||||||
*/
|
*/
|
||||||
@Async
|
@Async
|
||||||
public void triggerAttributionAsync(Long recordId, Long areaId) {
|
public void triggerAttributionAsync(Long recordId, Long areaId) {
|
||||||
log.info("[triggerAttributionAsync] 巡检不合格,触发归属判定: recordId={}, areaId={}", recordId, areaId);
|
try {
|
||||||
// TODO: Task 6 实现 InspectionAttributionService 归属判定逻辑
|
inspectionAttributionService.determineAttribution(recordId, areaId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("[triggerAttributionAsync] 归属判定异常: recordId={}, areaId={}", recordId, areaId, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user