From 38a6eaa39ed5798e77a6316da8857b0b1951a270 Mon Sep 17 00:00:00 2001 From: lzh Date: Tue, 3 Feb 2026 21:37:05 +0800 Subject: [PATCH] =?UTF-8?q?feat(@vben/web-antd):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E4=BF=9D=E6=B4=81=E5=B7=A5=E5=8D=95=E7=AE=A1=E7=90=86=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 工单看板:优化数据展示和交互逻辑 - 工单列表:增强筛选和分页功能 - 分配表单:改进表单验证和用户体验 - 卡片视图:优化布局和视觉效果 - 数据配置:更新常量定义和类型 Co-Authored-By: Claude Sonnet 4.5 --- .../cleaning/work-order/dashboard/index.vue | 16 +- .../src/views/ops/cleaning/work-order/data.ts | 4 +- .../views/ops/cleaning/work-order/index.vue | 24 +- .../work-order/modules/assign-form.vue | 91 +++---- .../cleaning/work-order/modules/card-view.vue | 257 ++++++++++++++---- 5 files changed, 270 insertions(+), 122 deletions(-) diff --git a/apps/web-antd/src/views/ops/cleaning/work-order/dashboard/index.vue b/apps/web-antd/src/views/ops/cleaning/work-order/dashboard/index.vue index 7ed61a43f..09dc04cc8 100644 --- a/apps/web-antd/src/views/ops/cleaning/work-order/dashboard/index.vue +++ b/apps/web-antd/src/views/ops/cleaning/work-order/dashboard/index.vue @@ -13,7 +13,7 @@ import { getQuickStats } from '#/api/ops/order-center'; defineOptions({ name: 'CleaningWorkOrderDashboard' }); // ========== 模拟数据开关 ========== -const USE_MOCK_DATA = true; +const USE_MOCK_DATA = false; // ========== 数据类型定义 ========== interface DashboardStats { @@ -22,8 +22,8 @@ interface DashboardStats { inProgressCount: number; completedTodayCount: number; completedTotalCount: number; - onlineCleanerCount: number; - totalCleanerCount: number; + onlineBadgeCount: number; + totalBadgeCount: number; // 趋势数据(7天) trendData: { @@ -99,8 +99,8 @@ const statsData = ref({ inProgressCount: 0, completedTodayCount: 0, completedTotalCount: 0, - onlineCleanerCount: 0, - totalCleanerCount: 0, + onlineBadgeCount: 0, + totalBadgeCount: 0, trendData: { dates: [], createdData: [], @@ -131,8 +131,8 @@ const MOCK_STATS: DashboardStats = { inProgressCount: 15, completedTodayCount: 42, completedTotalCount: 1586, - onlineCleanerCount: 12, - totalCleanerCount: 18, + onlineBadgeCount: 12, + totalBadgeCount: 18, trendData: { dates: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'], createdData: [45, 52, 38, 65, 48, 55, 42], @@ -914,7 +914,7 @@ async function loadStats() { pendingCount: quickStats.pendingCount, inProgressCount: quickStats.inProgressCount, completedTodayCount: quickStats.completedTodayCount, - onlineCleanerCount: quickStats.onlineCleanerCount, + onlineBadgeCount: quickStats.onlineBadgeCount, }; } diff --git a/apps/web-antd/src/views/ops/cleaning/work-order/data.ts b/apps/web-antd/src/views/ops/cleaning/work-order/data.ts index 7af7d49ca..cfe4ad3d4 100644 --- a/apps/web-antd/src/views/ops/cleaning/work-order/data.ts +++ b/apps/web-antd/src/views/ops/cleaning/work-order/data.ts @@ -82,7 +82,7 @@ export const PRIORITY_STYLE_MAP: Record< label: 'P2', color: '#9E9E9E', bgColor: '#FAFAFA', - icon: '', + icon: 'lucide:info', // Added icon animation: false, }, }; @@ -137,6 +137,8 @@ export const TRIGGER_SOURCE_OPTIONS = [ /** 触发来源文本映射 */ export const TRIGGER_SOURCE_TEXT_MAP: Record = { IOT_BEACON: '蓝牙信标', + IOT_TRAFFIC: '客流阈值', + TRAFFIC: '客流阈值', PEOPLE_FLOW: '客流阈值', MANUAL: '手动创建', }; diff --git a/apps/web-antd/src/views/ops/cleaning/work-order/index.vue b/apps/web-antd/src/views/ops/cleaning/work-order/index.vue index a8549162b..7e1a76276 100644 --- a/apps/web-antd/src/views/ops/cleaning/work-order/index.vue +++ b/apps/web-antd/src/views/ops/cleaning/work-order/index.vue @@ -115,9 +115,11 @@ function handleTabChange(key: number | string) { const keyStr = String(key); activeTab.value = keyStr; const tabConfig = STATUS_TAB_OPTIONS.find((t) => t.key === keyStr); - queryParams.value.status = (tabConfig?.statuses ?? undefined) as - | OpsOrderCenterApi.OrderStatus[] - | undefined; + if (tabConfig) { + queryParams.value.status = tabConfig.statuses as + | OpsOrderCenterApi.OrderStatus[] + | undefined; + } handleSearch(); } @@ -175,7 +177,7 @@ async function handleNotify( try { await sendDeviceNotify({ - cleanerId: row.assigneeId, + badgeId: row.assigneeId, type: type === 'voice' ? OpsCleaningApi.NotifyType.VOICE @@ -212,7 +214,8 @@ function handleStatClick(statKey: string) { 'DISPATCHED', 'CONFIRMED', 'ARRIVED', - ] as OpsOrderCenterApi.OrderStatus[]; + 'QUEUED', + ]; break; } case 'pendingCount': { @@ -240,11 +243,18 @@ const [Grid, gridApi] = useVbenVxeGrid({ }: { page: { currentPage: number; pageSize: number }; }) => { - return await getOrderPage({ + const params = { pageNo: page.currentPage, pageSize: page.pageSize, ...queryParams.value, - }); + }; + + // 处理状态数组 + // 如果后端接收 List,通常不需要手动 join(','),直接传数组即可 + // axios/requestClient 会自动处理为 status=A&status=B 的形式 + // 这里移除 .join(',') 的逻辑,直接保留数组 + + return await getOrderPage(params); }, }, }, diff --git a/apps/web-antd/src/views/ops/cleaning/work-order/modules/assign-form.vue b/apps/web-antd/src/views/ops/cleaning/work-order/modules/assign-form.vue index 56008c481..08415d341 100644 --- a/apps/web-antd/src/views/ops/cleaning/work-order/modules/assign-form.vue +++ b/apps/web-antd/src/views/ops/cleaning/work-order/modules/assign-form.vue @@ -8,7 +8,7 @@ import { useVbenModal } from '@vben/common-ui'; import { Avatar, Badge, Card, message, Spin } from 'ant-design-vue'; import { useVbenForm } from '#/adapter/form'; -import { getCleanerStatusList } from '#/api/ops/cleaning'; +import { getBadgeStatusList } from '#/api/ops/cleaning'; import { assignOrder } from '#/api/ops/order-center'; defineOptions({ name: 'WorkOrderAssignForm' }); @@ -23,7 +23,7 @@ const [Modal, modalApi] = useVbenModal({ orderId.value = data.orderId; orderCode.value = data.orderCode; } - await loadCleaners(); + await loadBadges(); } }, onConfirm: handleSubmit, @@ -32,9 +32,9 @@ const [Modal, modalApi] = useVbenModal({ const orderId = ref(); const orderCode = ref(''); const loading = ref(false); -const cleanerLoading = ref(false); -const cleanerList = ref([]); -const selectedCleanerId = ref(); +const badgeLoading = ref(false); +const badgeList = ref([]); +const selectedBadgeId = ref(); const [Form, formApi] = useVbenForm({ schema: [ @@ -51,22 +51,22 @@ const [Form, formApi] = useVbenForm({ showDefaultActions: false, }); -/** 加载保洁员列表 */ -async function loadCleaners() { - cleanerLoading.value = true; +/** 加载工牌列表 */ +async function loadBadges() { + badgeLoading.value = true; try { - const res = await getCleanerStatusList(); - cleanerList.value = res.list || []; + const res = await getBadgeStatusList(); + badgeList.value = res || []; } catch { - cleanerList.value = []; + badgeList.value = []; } finally { - cleanerLoading.value = false; + badgeLoading.value = false; } } -/** 选择保洁员 */ -function selectCleaner(cleaner: OpsCleaningApi.CleanerStatusItem) { - selectedCleanerId.value = cleaner.userId; +/** 选择工牌 */ +function selectBadge(badge: OpsCleaningApi.BadgeStatusItem) { + selectedBadgeId.value = badge.deviceId; } /** 获取状态颜色 */ @@ -100,8 +100,8 @@ function getBatteryColor(level: number) { /** 提交表单 */ async function handleSubmit() { - if (!selectedCleanerId.value) { - message.warning('请选择执行人'); + if (!selectedBadgeId.value) { + message.warning('请选择执行工牌'); return; } @@ -110,7 +110,7 @@ async function handleSubmit() { const formData = await formApi.getValues(); await assignOrder({ orderId: orderId.value!, - assigneeId: selectedCleanerId.value, + assigneeId: selectedBadgeId.value, remark: formData.remark, }); message.success('派单成功'); @@ -121,9 +121,9 @@ async function handleSubmit() { } } -/** 可用保洁员(优先显示空闲) */ -const sortedCleaners = computed(() => { - return [...cleanerList.value].toSorted((a, b) => { +/** 可用工牌(优先显示空闲) */ +const sortedBadges = computed(() => { + return [...badgeList.value].toSorted((a, b) => { const order: Record = { IDLE: 0, BUSY: 1, @@ -147,65 +147,60 @@ const sortedCleaners = computed(() => { - +
-
选择执行人
- +
选择执行工牌
+
- + - {{ cleaner.userName?.charAt(0) }} + {{ badge.deviceKey?.charAt(0) || '?' }}
{{ - cleaner.userName + badge.deviceKey }} - {{ getStatusText(cleaner.status) }} + {{ getStatusText(badge.status) }}
- {{ cleaner.currentAreaName || '未知区域' }} + {{ badge.currentAreaName || '未知区域' }} - {{ cleaner.batteryLevel }}% + {{ badge.batteryLevel }}%
-
- 暂无可用保洁员 -
+
暂无可用工牌
@@ -217,11 +212,11 @@ const sortedCleaners = computed(() => {