diff --git a/viewsh-module-ops/viewsh-module-ops-api/src/main/java/com/viewsh/module/ops/enums/ErrorCodeConstants.java b/viewsh-module-ops/viewsh-module-ops-api/src/main/java/com/viewsh/module/ops/enums/ErrorCodeConstants.java
index 2c2359a..4d45f63 100644
--- a/viewsh-module-ops/viewsh-module-ops-api/src/main/java/com/viewsh/module/ops/enums/ErrorCodeConstants.java
+++ b/viewsh-module-ops/viewsh-module-ops-api/src/main/java/com/viewsh/module/ops/enums/ErrorCodeConstants.java
@@ -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, "设备不存在");
diff --git a/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/OpsOrderController.java b/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/OpsOrderController.java
index b183bf0..676f802 100644
--- a/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/OpsOrderController.java
+++ b/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/OpsOrderController.java
@@ -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
*
- * 职责边界:提供所有工单类型(保洁/安保/工程/客服)通用的 CRUD、状态转换接口。
- * 保洁条线特有的业务操作(手动完单、优先级升级、时间线查询等)请使用
- * {@link com.viewsh.module.ops.controller.admin.clean.CleanWorkOrderController}。
+ * 职责边界:仅提供工单查询、元数据维护、设备/人员驱动的状态操作。
+ *
+ * 手动业务动作(创建/派单/完单/取消)必须通过业务条线控制器:
+ *
+ * - 保洁 → {@link com.viewsh.module.ops.controller.admin.clean.CleanWorkOrderController}
+ * - 安保 → {@link com.viewsh.module.ops.controller.admin.security.SecurityOrderController}
+ *
+ *
+ * 本控制器不再暴露 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 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 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 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 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 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 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 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 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 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 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 deleteOrder(@RequestParam("id") Long id) {
+ opsOrderService.deleteOrder(id);
+ return success(true);
+ }
+
+ // ==================== 设备/人员驱动的状态操作 ====================
+
+ @PostMapping("/accept")
+ @Operation(summary = "接单", description = "设备/人员主动接单,非管理员手动动作")
+ @PreAuthorize("@ss.hasPermission('ops:order:accept')")
+ public CommonResult 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 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 resumeOrder(@Valid @RequestBody OpsOrderResumeReqVO reqVO) {
+ opsOrderService.resumeOrder(reqVO.getOrderId(), reqVO.getUserId());
+ return success(true);
+ }
}
diff --git a/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/clean/CleanWorkOrderController.java b/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/clean/CleanWorkOrderController.java
index 1b878d9..d81dce1 100644
--- a/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/clean/CleanWorkOrderController.java
+++ b/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/clean/CleanWorkOrderController.java
@@ -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 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 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 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 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 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)
diff --git a/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/security/SecurityOrderController.java b/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/security/SecurityOrderController.java
index 732f311..aa8acbc 100644
--- a/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/security/SecurityOrderController.java
+++ b/viewsh-module-ops/viewsh-module-ops-server/src/main/java/com/viewsh/module/ops/controller/admin/security/SecurityOrderController.java
@@ -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 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 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 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 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 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 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')")