diff --git a/apps/web-antd/src/views/ops/cleaning/work-order/detail/index.vue b/apps/web-antd/src/views/ops/cleaning/work-order/detail/index.vue index 2e3aa88cc..9c84d8438 100644 --- a/apps/web-antd/src/views/ops/cleaning/work-order/detail/index.vue +++ b/apps/web-antd/src/views/ops/cleaning/work-order/detail/index.vue @@ -30,6 +30,7 @@ import { import { getBadgeRealtimeStatus, + getOrderBusinessLogs, getOrderTimeline, manualCompleteOrder, sendDeviceNotify, @@ -55,33 +56,21 @@ defineOptions({ name: 'CleaningWorkOrderDetail' }); const route = useRoute(); const router = useRouter(); const { closeTabByKey } = useTabs(); -const id = Number(route.params.id) || 1; +const id = route.params.id as string; // ========== 模拟数据开关 ========== -const USE_MOCK_DATA = true; +const USE_MOCK_DATA = false; const loading = ref(true); const order = ref( {} as OpsOrderCenterApi.OrderDetail, ); const timeline = ref([]); -const businessLogs = ref([]); +const businessLogs = ref([]); const badgeStatus = ref(null); const refreshTimer = ref(); const showLogs = ref(false); -// ========== 业务日志类型定义 ========== -interface BusinessLog { - id: number; - type: 'alert' | 'device' | 'operation' | 'system'; - title: string; - content: string; - operator: string; - time: string; - status?: string; // 关联的状态阶段 - extra?: Record; -} - // ========== 状态流转步骤定义 ========== const STATUS_STEPS = [ { @@ -201,7 +190,7 @@ const MOCK_TIMELINE: OpsCleaningApi.TimelineItem[] = [ }, ]; -const MOCK_BUSINESS_LOGS: BusinessLog[] = [ +const MOCK_BUSINESS_LOGS: OpsCleaningApi.BusinessLog[] = [ { id: 1, type: 'system', @@ -269,10 +258,9 @@ const MOCK_BUSINESS_LOGS: BusinessLog[] = [ ]; const MOCK_BADGE_STATUS: OpsCleaningApi.BadgeRealtimeStatus = { - cleanerId: 2001, deviceId: 3001, deviceKey: 'badge_zhangsan_001', - status: 'BUSY' as OpsCleaningApi.CleanerStatus, + status: 'BUSY' as OpsCleaningApi.BadgeStatus, batteryLevel: 72, lastHeartbeatTime: new Date(Date.now() - 30 * 1000).toISOString(), rssi: -42, @@ -377,9 +365,12 @@ async function loadOrderDetail() { } else { order.value = await getOrderDetail(id); await Promise.all([loadTimeline(), loadBusinessLogs()]); - if (order.value.assigneeId) await loadBadgeStatus(); + if (order.value.assigneeId) { + await loadBadgeStatus(); + } } - } catch { + } catch (error) { + console.error('❌ 工单详情加载失败:', error); message.error('获取工单详情失败'); handleBack(); } finally { @@ -404,8 +395,12 @@ async function loadTimeline() { /** 加载业务日志 */ async function loadBusinessLogs() { try { - // TODO: 调用实际API - businessLogs.value = USE_MOCK_DATA ? [...MOCK_BUSINESS_LOGS] : []; + if (USE_MOCK_DATA) { + businessLogs.value = [...MOCK_BUSINESS_LOGS]; + } else { + const res = await getOrderBusinessLogs(id); + businessLogs.value = res.logs || []; + } } catch { businessLogs.value = []; } @@ -413,12 +408,17 @@ async function loadBusinessLogs() { /** 加载工牌状态 */ async function loadBadgeStatus() { - if (!order.value.assigneeId) return; + if (!order.value.assigneeId) { + return; + } try { - badgeStatus.value = USE_MOCK_DATA - ? { ...MOCK_BADGE_STATUS } - : await getBadgeRealtimeStatus(order.value.assigneeId); - } catch { + if (USE_MOCK_DATA) { + badgeStatus.value = { ...MOCK_BADGE_STATUS }; + } else { + badgeStatus.value = await getBadgeRealtimeStatus(order.value.assigneeId); + } + } catch (error) { + console.error('❌ 工牌状态加载失败:', error); badgeStatus.value = null; } } @@ -464,7 +464,7 @@ async function handleVoiceNotify() { if (!order.value.assigneeId) return; try { await sendDeviceNotify({ - cleanerId: order.value.assigneeId, + badgeId: order.value.assigneeId, type: 'VOICE' as OpsCleaningApi.NotifyType, content: `请注意:${order.value.title}`, }); @@ -478,7 +478,7 @@ async function handleVibrateNotify() { if (!order.value.assigneeId) return; try { await sendDeviceNotify({ - cleanerId: order.value.assigneeId, + badgeId: order.value.assigneeId, type: 'VIBRATE' as OpsCleaningApi.NotifyType, }); message.success('震动提醒已发送'); @@ -497,12 +497,40 @@ async function handleManualComplete() { } } -function getBatteryColor(level: number) { +function getBatteryColor(level: null | number) { + if (level === null) return '#d9d9d9'; // 灰色表示未知 if (level <= 20) return '#f5222d'; if (level <= 50) return '#fa8c16'; return '#52c41a'; } +/** 获取工牌状态文本(兼容大小写) */ +function getBadgeStatusText(status: string) { + const upperStatus = status?.toUpperCase(); + switch (upperStatus) { + case 'BUSY': { + return '作业中'; + } + case 'IDLE': { + return '空闲'; + } + case 'OFFLINE': { + return '离线'; + } + case 'PAUSED': { + return '暂停'; + } + default: { + return status || '未知'; + } + } +} + +/** 判断是否为忙碌状态(兼容大小写) */ +function isBusyStatus(status: string) { + return status?.toUpperCase() === 'BUSY'; +} + onMounted(async () => { if (!id && !USE_MOCK_DATA) { message.warning('参数错误'); @@ -719,7 +747,8 @@ onUnmounted(() => {
+ :style="{ color: getLogTypeConfig(log.type).color }" + > {{ log.title }} {{ @@ -943,7 +972,11 @@ onUnmounted(() => { icon="solar:bluetooth-wave-bold-duotone" class="text-blue-400" /> - {{ TRIGGER_SOURCE_TEXT_MAP[order.triggerSource!] || '-' }} + {{ + TRIGGER_SOURCE_TEXT_MAP[ + order.triggerSource || order.sourceType || '' + ] || '-' + }} @@ -984,23 +1017,25 @@ onUnmounted(() => { 执行人
-
+
- {{ order.assigneeName?.charAt(0) }} + {{ order.assigneeName?.charAt(0) || '?' }}
-
{{ order.assigneeName }}
+
+ {{ order.assigneeName || '未知' }} +
工号: {{ order.assigneeId }}
- {{ badgeStatus.status === 'BUSY' ? '作业中' : '空闲' }} + {{ getBadgeStatusText(badgeStatus.status) }}
@@ -1028,12 +1063,20 @@ onUnmounted(() => {
位置状态
- - {{ badgeStatus.isInArea ? '在区域内' : '已离开' }} - +
+ + {{ badgeStatus.isInArea ? '在区域内' : '已离开' }} + + + {{ badgeStatus.areaName }} + +
@@ -1047,24 +1090,28 @@ onUnmounted(() => {
电池电量
-
-
+
+
+
+
+ > + {{ badgeStatus.batteryLevel }}% +
- - {{ badgeStatus.batteryLevel }}% - + 未知
@@ -1076,7 +1123,10 @@ onUnmounted(() => {
信号强度
-
+
{ {{ badgeStatus.rssi }} dBm
+ 未知