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>
This commit is contained in:
lzh
2026-03-05 19:15:01 +08:00
parent fa45d94247
commit e4dde8dbc1
7 changed files with 212 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
package com.viewsh.module.ops.environment.controller.admin.inspection.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 巡检记录 Response VO")
@Data
public class InspectionRecordRespVO {
@Schema(description = "巡检记录ID", example = "1024")
private Long id;
@Schema(description = "区域ID", example = "1")
private Long areaId;
@Schema(description = "巡检员用户ID", example = "100")
private Long inspectorId;
@Schema(description = "位置是否异常0正常 1异常", example = "0")
private Integer isLocationException;
@Schema(description = "巡检结果0不合格 1合格", example = "1")
private Integer resultStatus;
@Schema(description = "备注", example = "检查完成")
private String remark;
@Schema(description = "归属判定结果1个人责任 2突发状况 3正常", example = "3")
private Integer attributionResult;
@Schema(description = "整改工单ID", example = "2048")
private Long generatedOrderId;
@Schema(description = "创建时间")
private LocalDateTime createTime;
}

View File

@@ -0,0 +1,22 @@
package com.viewsh.module.ops.environment.controller.admin.inspection.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Schema(description = "管理后台 - 巡检提交明细项 VO")
@Data
public class InspectionSubmitItemVO {
@Schema(description = "模板检查项ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "模板检查项ID不能为空")
private Long templateId;
@Schema(description = "是否合格", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
@NotNull(message = "是否合格不能为空")
private Boolean isPassed;
@Schema(description = "备注", example = "地面有明显污渍")
private String remark;
}

View File

@@ -0,0 +1,31 @@
package com.viewsh.module.ops.environment.controller.admin.inspection.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.List;
@Schema(description = "管理后台 - 提交巡检结果 Request VO")
@Data
public class InspectionSubmitReqVO {
@Schema(description = "区域ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "区域ID不能为空")
private Long areaId;
@Schema(description = "位置是否异常0正常 1异常", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@NotNull(message = "位置异常标志不能为空")
private Integer isLocationException;
@Schema(description = "备注", example = "卫生间地面有污渍")
private String remark;
@Schema(description = "巡检明细项列表", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "巡检明细项不能为空")
@Valid
private List<InspectionSubmitItemVO> items;
}

View File

@@ -0,0 +1,19 @@
package com.viewsh.module.ops.environment.service.inspection;
import com.viewsh.module.ops.environment.controller.admin.inspection.vo.InspectionSubmitReqVO;
/**
* 巡检记录 Service 接口
*/
public interface InspectionRecordService {
/**
* 提交巡检结果
*
* @param submitReqVO 提交请求
* @param inspectorId 巡检员用户ID
* @return 巡检记录ID
*/
Long submitInspection(InspectionSubmitReqVO submitReqVO, Long inspectorId);
}

View File

@@ -0,0 +1,83 @@
package com.viewsh.module.ops.environment.service.inspection;
import com.viewsh.module.ops.environment.controller.admin.inspection.vo.InspectionSubmitItemVO;
import com.viewsh.module.ops.environment.controller.admin.inspection.vo.InspectionSubmitReqVO;
import com.viewsh.module.ops.environment.dal.dataobject.inspection.OpsInspectionRecordDO;
import com.viewsh.module.ops.environment.dal.dataobject.inspection.OpsInspectionRecordItemDO;
import com.viewsh.module.ops.environment.dal.mysql.inspection.OpsInspectionRecordItemMapper;
import com.viewsh.module.ops.environment.dal.mysql.inspection.OpsInspectionRecordMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.util.List;
/**
* 巡检记录 Service 实现
*/
@Service
@Validated
@Slf4j
public class InspectionRecordServiceImpl implements InspectionRecordService {
/** 巡检结果:合格 */
private static final int RESULT_STATUS_PASSED = 1;
/** 巡检结果:不合格 */
private static final int RESULT_STATUS_FAILED = 0;
@Resource
private OpsInspectionRecordMapper inspectionRecordMapper;
@Resource
private OpsInspectionRecordItemMapper inspectionRecordItemMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public Long submitInspection(InspectionSubmitReqVO submitReqVO, Long inspectorId) {
// 1. 判定巡检结果:任一项不合格 → 整体不合格
boolean allPassed = submitReqVO.getItems().stream()
.allMatch(InspectionSubmitItemVO::getIsPassed);
int resultStatus = allPassed ? RESULT_STATUS_PASSED : RESULT_STATUS_FAILED;
// 2. 保存巡检主记录
OpsInspectionRecordDO record = OpsInspectionRecordDO.builder()
.areaId(submitReqVO.getAreaId())
.inspectorId(inspectorId)
.isLocationException(submitReqVO.getIsLocationException())
.resultStatus(resultStatus)
.remark(submitReqVO.getRemark())
.build();
inspectionRecordMapper.insert(record);
// 3. 批量保存巡检明细
List<OpsInspectionRecordItemDO> items = submitReqVO.getItems().stream()
.map(itemVO -> OpsInspectionRecordItemDO.builder()
.recordId(record.getId())
.templateId(itemVO.getTemplateId())
.isPassed(itemVO.getIsPassed())
.remark(itemVO.getRemark())
.build())
.toList();
inspectionRecordItemMapper.insertBatch(items);
// 4. 不合格时异步触发归属判定Task 6 实现)
if (resultStatus == RESULT_STATUS_FAILED) {
triggerAttributionAsync(record.getId(), submitReqVO.getAreaId());
}
return record.getId();
}
/**
* 异步触发归属判定Task 6 实现完整逻辑)
*/
@Async
public void triggerAttributionAsync(Long recordId, Long areaId) {
log.info("[triggerAttributionAsync] 巡检不合格,触发归属判定: recordId={}, areaId={}", recordId, areaId);
// TODO: Task 6 实现 InspectionAttributionService 归属判定逻辑
}
}

View File

@@ -22,4 +22,8 @@ public interface ErrorCodeConstants {
ErrorCode DEVICE_TYPE_ALREADY_BOUND = new ErrorCode(1_020_002_002, "该区域已绑定{},一个区域只能绑定一个");
ErrorCode DEVICE_RELATION_NOT_FOUND = new ErrorCode(1_020_002_003, "设备关联关系不存在");
// ========== 巡检模块 1-020-003-000 ============
ErrorCode INSPECTION_TEMPLATE_NOT_FOUND = new ErrorCode(1_020_003_000, "巡检模板不存在");
ErrorCode INSPECTION_RECORD_NOT_FOUND = new ErrorCode(1_020_003_001, "巡检记录不存在");
}

View File

@@ -1,9 +1,12 @@
package com.viewsh.module.ops.controller.admin.inspection;
import com.viewsh.framework.common.pojo.CommonResult;
import com.viewsh.framework.security.core.util.SecurityFrameworkUtils;
import com.viewsh.module.ops.environment.controller.admin.inspection.vo.DetectedBeaconVO;
import com.viewsh.module.ops.environment.controller.admin.inspection.vo.InspectionSubmitReqVO;
import com.viewsh.module.ops.environment.controller.admin.inspection.vo.LocationVerifyResultVO;
import com.viewsh.module.ops.environment.service.inspection.InspectionLocationService;
import com.viewsh.module.ops.environment.service.inspection.InspectionRecordService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -29,6 +32,9 @@ public class InspectionController {
@Resource
private InspectionLocationService inspectionLocationService;
@Resource
private InspectionRecordService inspectionRecordService;
@PostMapping("/verify-location")
@Operation(summary = "蓝牙位置校验")
@Parameter(name = "areaId", description = "区域ID", required = true)
@@ -39,4 +45,12 @@ public class InspectionController {
return success(inspectionLocationService.verifyLocation(areaId, detectedBeacons));
}
@PostMapping("/submit")
@Operation(summary = "提交巡检结果")
@PreAuthorize("@ss.hasPermission('ops:inspection:create')")
public CommonResult<Long> submitInspection(@Valid @RequestBody InspectionSubmitReqVO submitReqVO) {
Long inspectorId = SecurityFrameworkUtils.getLoginUserId();
return success(inspectionRecordService.submitInspection(submitReqVO, inspectorId));
}
}