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>
This commit is contained in:
lzh
2026-03-27 16:09:07 +08:00
parent 1d09a50643
commit 06d701ed5e
4 changed files with 178 additions and 83 deletions

View File

@@ -21,6 +21,9 @@ public interface ErrorCodeConstants {
ErrorCode SECURITY_ORDER_TYPE_MISMATCH = new ErrorCode(1_020_003_001, "工单类型不匹配,期望安保工单");
ErrorCode SECURITY_AREA_USER_DUPLICATE = new ErrorCode(1_020_003_002, "该安保人员已绑定到此区域");
ErrorCode SECURITY_AREA_USER_NOT_FOUND = new ErrorCode(1_020_003_003, "绑定记录不存在");
ErrorCode SECURITY_ASSIGNEE_NOT_BOUND_TO_AREA = new ErrorCode(1_020_003_004, "目标安保人员未绑定到工单所属区域或已停用");
ErrorCode SECURITY_ORDER_STATUS_NOT_ALLOW_DISPATCH = new ErrorCode(1_020_003_005, "当前工单状态不允许手动派单,仅 PENDING 状态可操作");
ErrorCode SECURITY_ORDER_PRIORITY_UPGRADE_NOT_ALLOWED = new ErrorCode(1_020_003_006, "已完成或已取消的工单不允许升级优先级");
// ========== 区域设备关联 1-020-002-000 ============
ErrorCode DEVICE_NOT_FOUND = new ErrorCode(1_020_002_000, "设备不存在");

View File

@@ -1,16 +1,13 @@
package com.viewsh.module.ops.controller.admin;
import com.viewsh.framework.apilog.core.annotation.ApiAccessLog;
import com.viewsh.framework.common.pojo.CommonResult;
import com.viewsh.framework.common.pojo.PageResult;
import com.viewsh.framework.common.util.object.BeanUtils;
import com.viewsh.module.ops.controller.admin.vo.OpsOrderAcceptReqVO;
import com.viewsh.module.ops.controller.admin.vo.OpsOrderCompleteReqVO;
import com.viewsh.module.ops.controller.admin.vo.OpsOrderPauseReqVO;
import com.viewsh.module.ops.controller.admin.vo.OpsOrderResumeReqVO;
import com.viewsh.module.ops.service.order.dto.*;
import com.viewsh.module.ops.dal.dataobject.workorder.OpsOrderDO;
import com.viewsh.module.ops.enums.OperatorTypeEnum;
import com.viewsh.module.ops.service.order.OpsOrderService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
@@ -27,9 +24,16 @@ import static com.viewsh.framework.common.pojo.CommonResult.success;
/**
* 管理后台 - 通用工单 Controller
* <p>
* 职责边界:提供所有工单类型(保洁/安保/工程/客服)通用的 CRUD、状态转换接口
* 保洁条线特有的业务操作(手动完单、优先级升级、时间线查询等)请使用
* {@link com.viewsh.module.ops.controller.admin.clean.CleanWorkOrderController}。
* 职责边界:提供工单查询、元数据维护、设备/人员驱动的状态操作
* <p>
* <strong>手动业务动作(创建/派单/完单/取消)必须通过业务条线控制器:</strong>
* <ul>
* <li>保洁 → {@link com.viewsh.module.ops.controller.admin.clean.CleanWorkOrderController}</li>
* <li>安保 → {@link com.viewsh.module.ops.controller.admin.security.SecurityOrderController}</li>
* </ul>
* <p>
* 本控制器不再暴露 create/assign/complete/cancel 动作接口,
* 避免调用方绕过条线入口导致审计、校验、副作用处理不一致。
*
* @author lzh
*/
@@ -43,31 +47,7 @@ public class OpsOrderController {
@Resource
private OpsOrderService opsOrderService;
@PostMapping("/create")
@Operation(summary = "创建工单")
@Parameter(name = "createReq", description = "创建请求", required = true)
@PreAuthorize("@ss.hasPermission('ops:order:create')")
public CommonResult<Long> createOrder(@Valid @RequestBody OpsOrderCreateReqDTO createReq) {
Long orderId = opsOrderService.createOrder(createReq);
return success(orderId);
}
@PutMapping("/update")
@Operation(summary = "更新工单")
@PreAuthorize("@ss.hasPermission('ops:order:update')")
public CommonResult<Boolean> updateOrder(@Valid @RequestBody OpsOrderUpdateReqDTO updateReq) {
opsOrderService.updateOrder(updateReq);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除工单")
@Parameter(name = "id", description = "工单ID", required = true)
@PreAuthorize("@ss.hasPermission('ops:order:delete')")
public CommonResult<Boolean> deleteOrder(@RequestParam("id") Long id) {
opsOrderService.deleteOrder(id);
return success(true);
}
// ==================== 查询接口 ====================
@GetMapping("/get")
@Operation(summary = "获得工单详情")
@@ -86,57 +66,6 @@ public class OpsOrderController {
return success(BeanUtils.toBean(pageResult, OpsOrderRespDTO.class));
}
@PostMapping("/assign")
@Operation(summary = "分配工单")
@PreAuthorize("@ss.hasPermission('ops:order:assign')")
public CommonResult<Boolean> assignOrder(@Valid @RequestBody OpsOrderAssignReqDTO assignReq) {
opsOrderService.assignOrder(assignReq, OperatorTypeEnum.ADMIN, null);
return success(true);
}
@PostMapping("/accept")
@Operation(summary = "接单")
@PreAuthorize("@ss.hasPermission('ops:order:accept')")
public CommonResult<Boolean> acceptOrder(@Valid @RequestBody OpsOrderAcceptReqVO reqVO) {
opsOrderService.acceptOrder(reqVO.getOrderId(), reqVO.getUserId());
return success(true);
}
@PostMapping("/complete")
@Operation(summary = "完成工单")
@PreAuthorize("@ss.hasPermission('ops:order:complete')")
public CommonResult<Boolean> completeOrder(@Valid @RequestBody OpsOrderCompleteReqVO reqVO) {
OpsOrderCompleteReqDTO completeReq = new OpsOrderCompleteReqDTO();
completeReq.setOrderId(reqVO.getOrderId());
completeReq.setRemark(reqVO.getRemark());
opsOrderService.completeOrder(completeReq, reqVO.getUserId());
return success(true);
}
@PostMapping("/pause")
@Operation(summary = "暂停工单")
@PreAuthorize("@ss.hasPermission('ops:order:pause')")
public CommonResult<Boolean> pauseOrder(@Valid @RequestBody OpsOrderPauseReqVO reqVO) {
opsOrderService.pauseOrder(reqVO.getOrderId(), reqVO.getUserId(), reqVO.getReason());
return success(true);
}
@PostMapping("/resume")
@Operation(summary = "恢复工单")
@PreAuthorize("@ss.hasPermission('ops:order:resume')")
public CommonResult<Boolean> resumeOrder(@Valid @RequestBody OpsOrderResumeReqVO reqVO) {
opsOrderService.resumeOrder(reqVO.getOrderId(), reqVO.getUserId());
return success(true);
}
@PostMapping("/cancel")
@Operation(summary = "取消工单")
@PreAuthorize("@ss.hasPermission('ops:order:cancel')")
public CommonResult<Boolean> cancelOrder(@Valid @RequestBody OpsOrderCancelReqDTO cancelReq) {
opsOrderService.cancelOrder(cancelReq.getId(), cancelReq.getReason(), OperatorTypeEnum.ADMIN, null);
return success(true);
}
@GetMapping("/business-logs/{orderId}")
@Operation(summary = "获取工单业务日志")
@Parameter(name = "orderId", description = "工单ID", required = true)
@@ -146,4 +75,48 @@ public class OpsOrderController {
return success(logs);
}
// ==================== 元数据维护 ====================
@PutMapping("/update")
@Operation(summary = "更新工单")
@PreAuthorize("@ss.hasPermission('ops:order:update')")
public CommonResult<Boolean> updateOrder(@Valid @RequestBody OpsOrderUpdateReqDTO updateReq) {
opsOrderService.updateOrder(updateReq);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除工单")
@Parameter(name = "id", description = "工单ID", required = true)
@PreAuthorize("@ss.hasPermission('ops:order:delete')")
public CommonResult<Boolean> deleteOrder(@RequestParam("id") Long id) {
opsOrderService.deleteOrder(id);
return success(true);
}
// ==================== 设备/人员驱动的状态操作 ====================
@PostMapping("/accept")
@Operation(summary = "接单", description = "设备/人员主动接单,非管理员手动动作")
@PreAuthorize("@ss.hasPermission('ops:order:accept')")
public CommonResult<Boolean> acceptOrder(@Valid @RequestBody OpsOrderAcceptReqVO reqVO) {
opsOrderService.acceptOrder(reqVO.getOrderId(), reqVO.getUserId());
return success(true);
}
@PostMapping("/pause")
@Operation(summary = "暂停工单", description = "P0 打断等场景,非管理员手动动作")
@PreAuthorize("@ss.hasPermission('ops:order:pause')")
public CommonResult<Boolean> pauseOrder(@Valid @RequestBody OpsOrderPauseReqVO reqVO) {
opsOrderService.pauseOrder(reqVO.getOrderId(), reqVO.getUserId(), reqVO.getReason());
return success(true);
}
@PostMapping("/resume")
@Operation(summary = "恢复工单", description = "P0 完成后恢复,非管理员手动动作")
@PreAuthorize("@ss.hasPermission('ops:order:resume')")
public CommonResult<Boolean> resumeOrder(@Valid @RequestBody OpsOrderResumeReqVO reqVO) {
opsOrderService.resumeOrder(reqVO.getOrderId(), reqVO.getUserId());
return success(true);
}
}

View File

@@ -3,6 +3,9 @@ package com.viewsh.module.ops.controller.admin.clean;
import com.viewsh.framework.common.pojo.CommonResult;
import com.viewsh.framework.security.core.util.SecurityFrameworkUtils;
import com.viewsh.module.ops.api.clean.OrderTimelineRespDTO;
import com.viewsh.module.ops.environment.service.cleanorder.dto.CleanManualCancelReqDTO;
import com.viewsh.module.ops.environment.service.cleanorder.dto.CleanManualCreateReqDTO;
import com.viewsh.module.ops.environment.service.cleanorder.dto.CleanManualDispatchReqDTO;
import com.viewsh.module.ops.environment.service.cleanorder.dto.ManualCompleteOrderReqDTO;
import com.viewsh.module.ops.environment.service.cleanorder.dto.UpgradePriorityReqDTO;
import com.viewsh.module.ops.environment.service.badge.BadgeDeviceStatusService;
@@ -69,11 +72,51 @@ public class CleanWorkOrderController {
@PreAuthorize("@ss.hasPermission('ops:clean:order:upgrade')")
public CommonResult<Boolean> upgradePriority(
@Valid @RequestBody UpgradePriorityReqDTO req) {
req.setOperatorId(SecurityFrameworkUtils.getLoginUserId());
cleanWorkOrderService.upgradePriority(req);
return success(true);
}
@PostMapping("/manual-upgrade-priority")
@Operation(summary = "手动升级工单优先级(规范路径)", description = "等同于 /upgrade-priority推荐使用此路径")
@PreAuthorize("@ss.hasPermission('ops:clean:order:upgrade')")
public CommonResult<Boolean> manualUpgradePriority(
@Valid @RequestBody UpgradePriorityReqDTO req) {
req.setOperatorId(SecurityFrameworkUtils.getLoginUserId());
cleanWorkOrderService.upgradePriority(req);
return success(true);
}
@PostMapping("/manual-create")
@Operation(summary = "手动创建保洁工单")
@PreAuthorize("@ss.hasPermission('ops:clean:order:create')")
public CommonResult<Long> manualCreateOrder(
@Valid @RequestBody CleanManualCreateReqDTO req) {
req.setOperatorId(SecurityFrameworkUtils.getLoginUserId());
Long orderId = cleanWorkOrderService.manualCreateOrder(req);
return success(orderId);
}
@PostMapping("/manual-dispatch")
@Operation(summary = "手动派单")
@PreAuthorize("@ss.hasPermission('ops:clean:order:dispatch')")
public CommonResult<Boolean> manualDispatch(
@Valid @RequestBody CleanManualDispatchReqDTO req) {
req.setOperatorId(SecurityFrameworkUtils.getLoginUserId());
cleanWorkOrderService.manualDispatch(req);
return success(true);
}
@PostMapping("/manual-cancel")
@Operation(summary = "手动取消工单")
@PreAuthorize("@ss.hasPermission('ops:clean:order:cancel')")
public CommonResult<Boolean> manualCancelOrder(
@Valid @RequestBody CleanManualCancelReqDTO req) {
req.setOperatorId(SecurityFrameworkUtils.getLoginUserId());
cleanWorkOrderService.manualCancelOrder(req);
return success(true);
}
@PostMapping("/repair-device-status")
@Operation(summary = "修复工牌设备状态", description = "当设备状态残留为BUSY但关联工单已完成/取消时修复设备状态为IDLE")
@Parameter(name = "deviceId", description = "设备ID", required = true)

View File

@@ -6,7 +6,10 @@ import com.viewsh.module.ops.controller.admin.security.vo.SecurityOrderAutoCompl
import com.viewsh.module.ops.controller.admin.security.vo.SecurityOrderCompleteReqVO;
import com.viewsh.module.ops.controller.admin.security.vo.SecurityOrderConfirmReqVO;
import com.viewsh.module.ops.controller.admin.security.vo.SecurityOrderCreateReqVO;
import com.viewsh.module.ops.controller.admin.security.vo.SecurityOrderCancelReqVO;
import com.viewsh.module.ops.controller.admin.security.vo.SecurityOrderDispatchReqVO;
import com.viewsh.module.ops.controller.admin.security.vo.SecurityOrderIdReqVO;
import com.viewsh.module.ops.controller.admin.security.vo.SecurityOrderUpgradePriorityReqVO;
import com.viewsh.module.ops.security.service.securityorder.SecurityOrderCompleteReqDTO;
import com.viewsh.module.ops.security.service.securityorder.SecurityOrderCreateReqDTO;
import com.viewsh.module.ops.security.service.securityorder.SecurityOrderService;
@@ -56,6 +59,7 @@ public class SecurityOrderController {
.roiId(reqVO.getRoiId())
.imageUrl(reqVO.getImageUrl())
.sourceType(reqVO.getSourceType())
.operatorId(SecurityFrameworkUtils.getLoginUserId())
.build();
Long orderId = securityOrderService.createSecurityOrder(dto);
return success(orderId);
@@ -91,6 +95,78 @@ public class SecurityOrderController {
return success(true);
}
@PostMapping("/dispatch")
@Operation(summary = "手动派单", description = "管理员指定安保人员进行派单,绕过自动调度")
@PreAuthorize("@ss.hasPermission('ops:security-order:dispatch')")
public CommonResult<Boolean> manualDispatch(@Valid @RequestBody SecurityOrderDispatchReqVO reqVO) {
securityOrderService.manualDispatch(
reqVO.getOrderId(), reqVO.getAssigneeId(),
SecurityFrameworkUtils.getLoginUserId(), reqVO.getRemark());
return success(true);
}
@PostMapping("/upgrade-priority")
@Operation(summary = "升级优先级", description = "管理员手动升级工单优先级,队列中的工单会重算分数")
@PreAuthorize("@ss.hasPermission('ops:security-order:update')")
public CommonResult<Boolean> upgradePriority(@Valid @RequestBody SecurityOrderUpgradePriorityReqVO reqVO) {
securityOrderService.upgradePriority(
reqVO.getOrderId(), reqVO.getPriority(),
SecurityFrameworkUtils.getLoginUserId());
return success(true);
}
@PostMapping("/manual-cancel")
@Operation(summary = "手动取消工单", description = "管理员手动取消安保工单")
@PreAuthorize("@ss.hasPermission('ops:security-order:cancel')")
public CommonResult<Boolean> manualCancelOrder(@Valid @RequestBody SecurityOrderCancelReqVO reqVO) {
securityOrderService.manualCancel(
reqVO.getOrderId(), reqVO.getReason(),
SecurityFrameworkUtils.getLoginUserId());
return success(true);
}
@PostMapping("/manual-dispatch")
@Operation(summary = "手动派单(规范路径)", description = "等同于 /dispatch推荐使用此路径")
@PreAuthorize("@ss.hasPermission('ops:security-order:dispatch')")
public CommonResult<Boolean> manualDispatchNormalized(@Valid @RequestBody SecurityOrderDispatchReqVO reqVO) {
securityOrderService.manualDispatch(
reqVO.getOrderId(), reqVO.getAssigneeId(),
SecurityFrameworkUtils.getLoginUserId(), reqVO.getRemark());
return success(true);
}
@PostMapping("/manual-upgrade-priority")
@Operation(summary = "手动升级优先级(规范路径)", description = "等同于 /upgrade-priority推荐使用此路径")
@PreAuthorize("@ss.hasPermission('ops:security-order:update')")
public CommonResult<Boolean> manualUpgradePriorityNormalized(@Valid @RequestBody SecurityOrderUpgradePriorityReqVO reqVO) {
securityOrderService.upgradePriority(
reqVO.getOrderId(), reqVO.getPriority(),
SecurityFrameworkUtils.getLoginUserId());
return success(true);
}
@PostMapping("/manual-create")
@Operation(summary = "手动创建安保工单(规范路径)", description = "等同于 /create推荐使用此路径")
@PreAuthorize("@ss.hasPermission('ops:security-order:create')")
public CommonResult<Long> manualCreateOrder(@Valid @RequestBody SecurityOrderCreateReqVO reqVO) {
SecurityOrderCreateReqDTO dto = SecurityOrderCreateReqDTO.builder()
.title(reqVO.getTitle())
.description(reqVO.getDescription())
.priority(reqVO.getPriority())
.areaId(reqVO.getAreaId())
.alarmId(reqVO.getAlarmId())
.alarmType(reqVO.getAlarmType())
.cameraId(reqVO.getCameraId())
.cameraName(reqVO.getCameraName())
.roiId(reqVO.getRoiId())
.imageUrl(reqVO.getImageUrl())
.sourceType(reqVO.getSourceType())
.operatorId(SecurityFrameworkUtils.getLoginUserId())
.build();
Long orderId = securityOrderService.createSecurityOrder(dto);
return success(orderId);
}
@PostMapping("/false-alarm")
@Operation(summary = "误报标记", description = "将安保工单标记为误报并完成")
@PreAuthorize("@ss.hasPermission('ops:security-order:complete')")