refactor(@vben/web-antd): 工单操作接口按业务线拆分(保洁/安保)
后端 OpsOrderController 移除了 assign/cancel/complete/create 通用接口, 改由 CleanWorkOrderController 和 SecurityOrderController 各自提供 manual-* 系列接口。 - 新增 api/ops/security/index.ts 安保工单操作 API - cleaning/index.ts 新增 manualCreate/Dispatch/Cancel/UpgradePriority - order-center/index.ts 移除 assignOrder/cancelOrder - 表单组件按工单类型路由到对应 API - cancel-form/upgrade-priority-form 支持 orderType 区分调用路径 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,29 @@ export namespace OpsCleaningApi {
|
||||
reason: string; // 升级原因
|
||||
}
|
||||
|
||||
/** 手动创建保洁工单请求 */
|
||||
export interface ManualCreateReq {
|
||||
title: string; // 工单标题
|
||||
description?: string; // 工单描述
|
||||
priority?: number; // 优先级
|
||||
areaId: number; // 区域ID
|
||||
cleaningType?: string; // 保洁类型
|
||||
expectedDuration?: number; // 预计作业时长(分钟)
|
||||
}
|
||||
|
||||
/** 手动派单请求 */
|
||||
export interface ManualDispatchReq {
|
||||
orderId: number; // 工单ID
|
||||
assigneeId: number; // 目标设备ID(工牌设备ID)
|
||||
remark?: string; // 派单备注
|
||||
}
|
||||
|
||||
/** 手动取消工单请求 */
|
||||
export interface ManualCancelReq {
|
||||
orderId: number; // 工单ID
|
||||
reason: string; // 取消原因
|
||||
}
|
||||
|
||||
/** 工牌通知请求 */
|
||||
export interface DeviceNotifyReq {
|
||||
badgeId: number; // 工牌设备ID
|
||||
@@ -143,11 +166,6 @@ export function getIotDeviceProperties(deviceId: number) {
|
||||
|
||||
// ==================== 保洁专属接口 ====================
|
||||
|
||||
/** 升级工单优先级 (P0 插队) */
|
||||
export function upgradePriority(data: OpsCleaningApi.UpgradePriorityReq) {
|
||||
return requestClient.post('/ops/clean/order/upgrade-priority', data);
|
||||
}
|
||||
|
||||
/** 发送工牌通知 (语音/震动) */
|
||||
export function sendDeviceNotify(data: OpsCleaningApi.DeviceNotifyReq) {
|
||||
return requestClient.post('/ops/clean/device/notify', data);
|
||||
@@ -189,3 +207,23 @@ export function getOrderBusinessLogs(orderId: number | string) {
|
||||
`/ops/order/business-logs/${orderId}`,
|
||||
);
|
||||
}
|
||||
|
||||
/** 手动创建保洁工单 */
|
||||
export function manualCreateOrder(data: OpsCleaningApi.ManualCreateReq) {
|
||||
return requestClient.post<number>('/ops/clean/order/manual-create', data);
|
||||
}
|
||||
|
||||
/** 手动派单(保洁) */
|
||||
export function manualDispatchOrder(data: OpsCleaningApi.ManualDispatchReq) {
|
||||
return requestClient.post('/ops/clean/order/manual-dispatch', data);
|
||||
}
|
||||
|
||||
/** 手动取消工单(保洁) */
|
||||
export function manualCancelOrder(data: OpsCleaningApi.ManualCancelReq) {
|
||||
return requestClient.post('/ops/clean/order/manual-cancel', data);
|
||||
}
|
||||
|
||||
/** 手动升级优先级(保洁,规范路径) */
|
||||
export function manualUpgradePriority(data: OpsCleaningApi.UpgradePriorityReq) {
|
||||
return requestClient.post('/ops/clean/order/manual-upgrade-priority', data);
|
||||
}
|
||||
|
||||
@@ -144,13 +144,6 @@ export namespace OpsOrderCenterApi {
|
||||
onlineBadgeCount: number; // 在线工牌数量
|
||||
}
|
||||
|
||||
/** 分配工单请求 */
|
||||
export interface AssignOrderReq {
|
||||
orderId: number; // 工单ID
|
||||
assigneeId: number; // 执行人ID
|
||||
remark?: string; // 备注
|
||||
}
|
||||
|
||||
/** 暂停工单请求 */
|
||||
export interface PauseOrderReq {
|
||||
orderId: number; // 工单ID
|
||||
@@ -164,11 +157,6 @@ export namespace OpsOrderCenterApi {
|
||||
userId: number; // 操作人ID
|
||||
}
|
||||
|
||||
/** 取消工单请求 */
|
||||
export interface CancelOrderReq {
|
||||
id: number; // 工单ID
|
||||
reason: string; // 取消原因
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 工单查询接口 ====================
|
||||
@@ -322,11 +310,9 @@ export function getTrafficTrend() {
|
||||
}
|
||||
|
||||
// ==================== 工单操作接口 ====================
|
||||
|
||||
/** 重新分配/派单 */
|
||||
export function assignOrder(data: OpsOrderCenterApi.AssignOrderReq) {
|
||||
return requestClient.post('/ops/order/assign', data);
|
||||
}
|
||||
// 注意: assignOrder 和 cancelOrder 已移至各业务线控制器
|
||||
// 保洁: 使用 cleaning/index.ts 中的 manualDispatchOrder / manualCancelOrder
|
||||
// 安保: 使用 security/index.ts 中的 manualDispatchSecurityOrder / manualCancelSecurityOrder
|
||||
|
||||
/** 暂停工单 */
|
||||
export function pauseOrder(data: OpsOrderCenterApi.PauseOrderReq) {
|
||||
@@ -337,8 +323,3 @@ export function pauseOrder(data: OpsOrderCenterApi.PauseOrderReq) {
|
||||
export function resumeOrder(data: OpsOrderCenterApi.ResumeOrderReq) {
|
||||
return requestClient.post('/ops/order/resume', data);
|
||||
}
|
||||
|
||||
/** 取消工单 */
|
||||
export function cancelOrder(data: OpsOrderCenterApi.CancelOrderReq) {
|
||||
return requestClient.post('/ops/order/cancel', data);
|
||||
}
|
||||
|
||||
90
apps/web-antd/src/api/ops/security/index.ts
Normal file
90
apps/web-antd/src/api/ops/security/index.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export namespace OpsSecurityOrderApi {
|
||||
/** 手动创建安保工单请求 */
|
||||
export interface ManualCreateReq {
|
||||
title: string; // 工单标题
|
||||
description?: string; // 工单描述
|
||||
priority?: number; // 优先级(0=P0紧急 1=P1重要 2=P2普通)
|
||||
areaId: number; // 区域ID
|
||||
imageUrl?: string; // 相关图片URL
|
||||
sourceType?: string; // 来源类型(ALARM=告警触发/MANUAL=手动创建)
|
||||
// 以下字段仅用于告警自动触发场景,手动创建时不传
|
||||
alarmId?: string; // 关联告警ID
|
||||
alarmType?: string; // 告警类型(intrusion/leave_post/fire/fence)
|
||||
cameraId?: string; // 摄像头ID
|
||||
cameraName?: string; // 摄像头名称
|
||||
roiId?: string; // ROI区域ID
|
||||
}
|
||||
|
||||
/** 手动派单请求 */
|
||||
export interface ManualDispatchReq {
|
||||
orderId: number; // 工单ID
|
||||
assigneeId: number; // 指定安保人员ID
|
||||
remark?: string; // 派单备注
|
||||
}
|
||||
|
||||
/** 手动取消工单请求 */
|
||||
export interface ManualCancelReq {
|
||||
orderId: number; // 工单ID
|
||||
reason: string; // 取消原因
|
||||
}
|
||||
|
||||
/** 手动完单请求 */
|
||||
export interface ManualCompleteReq {
|
||||
orderId: number; // 工单ID
|
||||
result: string; // 处理结果描述
|
||||
resultImgUrls?: string[]; // 处理结果图片URL列表
|
||||
}
|
||||
|
||||
/** 手动升级优先级请求 */
|
||||
export interface ManualUpgradePriorityReq {
|
||||
orderId: number; // 工单ID
|
||||
priority: number; // 目标优先级(0=P0, 1=P1, 2=P2)
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 安保工单操作 API ==========
|
||||
// 后端控制器: SecurityOrderController
|
||||
// 后端路径前缀: /ops/security/order
|
||||
|
||||
/** 手动创建安保工单 */
|
||||
export function manualCreateSecurityOrder(
|
||||
data: OpsSecurityOrderApi.ManualCreateReq,
|
||||
) {
|
||||
return requestClient.post<number>(
|
||||
'/ops/security/order/manual-create',
|
||||
data,
|
||||
);
|
||||
}
|
||||
|
||||
/** 手动派单(安保) */
|
||||
export function manualDispatchSecurityOrder(
|
||||
data: OpsSecurityOrderApi.ManualDispatchReq,
|
||||
) {
|
||||
return requestClient.post('/ops/security/order/manual-dispatch', data);
|
||||
}
|
||||
|
||||
/** 手动取消工单(安保) */
|
||||
export function manualCancelSecurityOrder(
|
||||
data: OpsSecurityOrderApi.ManualCancelReq,
|
||||
) {
|
||||
return requestClient.post('/ops/security/order/manual-cancel', data);
|
||||
}
|
||||
|
||||
/** 手动完单(安保) */
|
||||
export function manualCompleteSecurityOrder(
|
||||
data: OpsSecurityOrderApi.ManualCompleteReq,
|
||||
) {
|
||||
return requestClient.post('/ops/security/order/manual-complete', data);
|
||||
}
|
||||
|
||||
/** 手动升级优先级(安保) */
|
||||
export function manualUpgradePrioritySecurityOrder(
|
||||
data: OpsSecurityOrderApi.ManualUpgradePriorityReq,
|
||||
) {
|
||||
return requestClient.post(
|
||||
'/ops/security/order/manual-upgrade-priority',
|
||||
data,
|
||||
);
|
||||
}
|
||||
@@ -8,8 +8,7 @@ import { useVbenModal } from '@vben/common-ui';
|
||||
import { Avatar, Badge, Card, message, Spin } from 'ant-design-vue';
|
||||
|
||||
import { useVbenForm } from '#/adapter/form';
|
||||
import { getBadgeStatusList } from '#/api/ops/cleaning';
|
||||
import { assignOrder } from '#/api/ops/order-center';
|
||||
import { getBadgeStatusList, manualDispatchOrder } from '#/api/ops/cleaning';
|
||||
|
||||
defineOptions({ name: 'WorkOrderAssignForm' });
|
||||
|
||||
@@ -108,7 +107,7 @@ async function handleSubmit() {
|
||||
loading.value = true;
|
||||
try {
|
||||
const formData = await formApi.getValues();
|
||||
await assignOrder({
|
||||
await manualDispatchOrder({
|
||||
orderId: orderId.value!,
|
||||
assigneeId: selectedBadgeId.value,
|
||||
remark: formData.remark,
|
||||
|
||||
@@ -6,7 +6,8 @@ import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import { Alert, Input, message } from 'ant-design-vue';
|
||||
|
||||
import { cancelOrder } from '#/api/ops/order-center';
|
||||
import { manualCancelSecurityOrder } from '#/api/ops/security';
|
||||
import { manualCancelOrder } from '#/api/ops/cleaning';
|
||||
|
||||
defineOptions({ name: 'CancelOrderForm' });
|
||||
|
||||
@@ -15,12 +16,14 @@ const emit = defineEmits<{ success: [] }>();
|
||||
interface ModalData {
|
||||
orderId: number;
|
||||
orderCode: string;
|
||||
orderType?: string; // CLEAN | SECURITY
|
||||
title: string;
|
||||
}
|
||||
|
||||
const modalData = ref<ModalData>({
|
||||
orderId: 0,
|
||||
orderCode: '',
|
||||
orderType: undefined,
|
||||
title: '',
|
||||
});
|
||||
const reason = ref('');
|
||||
@@ -51,13 +54,25 @@ async function handleSubmit() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!modalData.value.orderType) {
|
||||
message.error('工单类型未知,无法取消');
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
modalApi.setState({ confirmLoading: true });
|
||||
try {
|
||||
await cancelOrder({
|
||||
id: modalData.value.orderId,
|
||||
reason: val,
|
||||
});
|
||||
if (modalData.value.orderType === 'SECURITY') {
|
||||
await manualCancelSecurityOrder({
|
||||
orderId: modalData.value.orderId,
|
||||
reason: val,
|
||||
});
|
||||
} else {
|
||||
await manualCancelOrder({
|
||||
orderId: modalData.value.orderId,
|
||||
reason: val,
|
||||
});
|
||||
}
|
||||
message.success('工单已取消');
|
||||
modalApi.close();
|
||||
emit('success');
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
Spin,
|
||||
} from 'ant-design-vue';
|
||||
|
||||
import { assignOrder } from '#/api/ops/order-center';
|
||||
import { manualDispatchSecurityOrder } from '#/api/ops/security';
|
||||
import { getUserPage } from '#/api/system/user';
|
||||
|
||||
defineOptions({ name: 'SecurityAssignForm' });
|
||||
@@ -114,7 +114,7 @@ async function handleSubmit() {
|
||||
loading.value = true;
|
||||
modalApi.setState({ confirmLoading: true });
|
||||
try {
|
||||
await assignOrder({
|
||||
await manualDispatchSecurityOrder({
|
||||
orderId: modalData.value.orderId,
|
||||
assigneeId: selectedUserId.value,
|
||||
remark: remark.value.trim() || undefined,
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { useVbenModal } from '@vben/common-ui';
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import { Alert, Input, message } from 'ant-design-vue';
|
||||
|
||||
import { upgradePriority } from '#/api/ops/cleaning';
|
||||
import { manualUpgradePriority } from '#/api/ops/cleaning';
|
||||
import { manualUpgradePrioritySecurityOrder } from '#/api/ops/security';
|
||||
|
||||
defineOptions({ name: 'UpgradePriorityForm' });
|
||||
|
||||
@@ -15,16 +16,19 @@ const emit = defineEmits<{ success: [] }>();
|
||||
interface ModalData {
|
||||
orderId: number;
|
||||
orderCode: string;
|
||||
orderType?: string; // CLEAN | SECURITY
|
||||
currentPriority: number;
|
||||
}
|
||||
|
||||
const modalData = ref<ModalData>({
|
||||
orderId: 0,
|
||||
orderCode: '',
|
||||
orderType: 'CLEAN',
|
||||
currentPriority: 2,
|
||||
});
|
||||
const reason = ref('');
|
||||
const loading = ref(false);
|
||||
const isSecurity = computed(() => modalData.value.orderType === 'SECURITY');
|
||||
|
||||
const [Modal, modalApi] = useVbenModal({
|
||||
onOpenChange: (isOpen) => {
|
||||
@@ -52,22 +56,30 @@ function getPriorityText(priority: number) {
|
||||
/** 提交表单 */
|
||||
async function handleSubmit() {
|
||||
const val = reason.value.trim();
|
||||
if (val.length < 5) {
|
||||
message.warning('升级原因至少5个字符');
|
||||
return;
|
||||
}
|
||||
if (val.length > 200) {
|
||||
message.warning('升级原因不能超过200字符');
|
||||
return;
|
||||
// 保洁需要填写升级原因,安保后端不接收 reason 字段
|
||||
if (!isSecurity.value) {
|
||||
if (val.length < 5) {
|
||||
message.warning('升级原因至少5个字符');
|
||||
return;
|
||||
}
|
||||
if (val.length > 200) {
|
||||
message.warning('升级原因不能超过200字符');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
modalApi.setState({ confirmLoading: true });
|
||||
try {
|
||||
await upgradePriority({
|
||||
orderId: modalData.value.orderId,
|
||||
reason: val,
|
||||
});
|
||||
await (modalData.value.orderType === 'SECURITY'
|
||||
? manualUpgradePrioritySecurityOrder({
|
||||
orderId: modalData.value.orderId,
|
||||
priority: 0, // P0紧急
|
||||
})
|
||||
: manualUpgradePriority({
|
||||
orderId: modalData.value.orderId,
|
||||
reason: val,
|
||||
}));
|
||||
message.success('已升级为P0紧急工单');
|
||||
modalApi.close();
|
||||
emit('success');
|
||||
@@ -115,8 +127,8 @@ async function handleSubmit() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 升级原因 -->
|
||||
<div class="uf-section">
|
||||
<!-- 升级原因(仅保洁需要) -->
|
||||
<div v-if="!isSecurity" class="uf-section">
|
||||
<div class="uf-section-title">升级原因</div>
|
||||
<Input.TextArea
|
||||
v-model:value="reason"
|
||||
|
||||
Reference in New Issue
Block a user