refactor(ops): 代码格式化与 lint 修复

清理未使用的导入、修复格式化问题、优化 requiredSteps 为 Set 提升查找性能

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
lzh
2026-02-26 19:28:04 +08:00
parent 9bf042f817
commit b0e233cd95
5 changed files with 122 additions and 55 deletions

View File

@@ -7,14 +7,8 @@ import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
import { useAccess } from '@vben/access';
import { AuthenticationLoginExpiredModal, useVbenModal } from '@vben/common-ui';
import { VBEN_DOC_URL, VBEN_GITHUB_URL } from '@vben/constants';
import { isTenantEnable, useTabs, useWatermark } from '@vben/hooks';
import {
AntdProfileOutlined,
BookOpenText,
CircleHelp,
SvgGithubIcon,
} from '@vben/icons';
import { AntdProfileOutlined, CircleHelp } from '@vben/icons';
import {
BasicLayout,
Help,
@@ -25,7 +19,7 @@ import {
} from '@vben/layouts';
import { preferences } from '@vben/preferences';
import { useAccessStore, useUserStore } from '@vben/stores';
import { formatDateTime, openWindow } from '@vben/utils';
import { formatDateTime } from '@vben/utils';
import { message } from 'ant-design-vue';

View File

@@ -13,10 +13,7 @@ import { IconifyIcon } from '@vben/icons';
import { Button, message, Modal, Tag } from 'ant-design-vue';
import {
getTrafficRealtime,
getWorkspaceStats,
} from '#/api/ops/order-center';
import { getTrafficRealtime, getWorkspaceStats } from '#/api/ops/order-center';
import { BackgroundChart } from '../../../components/background-chart';
import { createBackgroundChartOptions } from './utils/chart-options';
@@ -325,12 +322,24 @@ onUnmounted(stopPolling);
<div :class="cardContentClasses.container">
<h3 :class="cardContentClasses.title">实时客流监测</h3>
<div :class="cardContentClasses.numberContainer">
<span :class="cardContentClasses.largeNumber">{{ formatNumber(trafficTotalIn) }}</span>
<Tag color="success" :class="`text-xs font-bold ${textShadowClasses.tag}`">+12%</Tag>
<span :class="cardContentClasses.largeNumber">{{
formatNumber(trafficTotalIn)
}}</span>
<Tag
color="success"
:class="`text-xs font-bold ${textShadowClasses.tag}`"
>
+12%
</Tag>
</div>
<p :class="cardContentClasses.description">预计高峰时间: 14:00</p>
</div>
<Button type="text" shape="circle" :class="buttonClasses.refresh" @click="handleRefreshStats">
<Button
type="text"
shape="circle"
:class="buttonClasses.refresh"
@click="handleRefreshStats"
>
<template #icon>
<IconifyIcon icon="ant-design:more-outlined" class="text-base" />
</template>
@@ -351,9 +360,15 @@ onUnmounted(stopPolling);
</div>
<div :class="taskListClasses.listContainer">
<div v-if="filteredTasks.length === 0" :class="taskListClasses.emptyState">
<div
v-if="filteredTasks.length === 0"
:class="taskListClasses.emptyState"
>
<div :class="taskListClasses.emptyContent">
<IconifyIcon icon="ant-design:check-circle-outlined" :class="taskListClasses.emptyIcon" />
<IconifyIcon
icon="ant-design:check-circle-outlined"
:class="taskListClasses.emptyIcon"
/>
<p>暂无待办任务</p>
</div>
</div>
@@ -367,7 +382,10 @@ onUnmounted(stopPolling);
<div :class="taskListClasses.taskContent">
<div :class="taskListClasses.taskLeft">
<div
:class="[taskListClasses.taskIcon, getPriorityConfig(task.priority).bg]"
:class="[
taskListClasses.taskIcon,
getPriorityConfig(task.priority).bg,
]"
>
<IconifyIcon
icon="ant-design:clock-circle-outlined"
@@ -376,7 +394,9 @@ onUnmounted(stopPolling);
/>
</div>
<div :class="taskListClasses.taskInfo">
<div :class="taskListClasses.taskTitle">{{ task.title }}</div>
<div :class="taskListClasses.taskTitle">
{{ task.title }}
</div>
<div :class="taskListClasses.taskMeta">
<span>{{ task.location }}</span>
<span v-if="task.createTime"> {{ task.createTime }}</span>
@@ -385,7 +405,10 @@ onUnmounted(stopPolling);
</div>
<Tag
:color="getPriorityConfig(task.priority).color"
:class="[taskListClasses.taskPriorityTag, getPriorityConfig(task.priority).border]"
:class="[
taskListClasses.taskPriorityTag,
getPriorityConfig(task.priority).border,
]"
>
{{ task.priority }}
</Tag>
@@ -399,7 +422,10 @@ onUnmounted(stopPolling);
@click.stop="handleTaskComplete(task.id)"
>
<template #icon>
<IconifyIcon icon="ant-design:check-circle-outlined" class="text-xs" />
<IconifyIcon
icon="ant-design:check-circle-outlined"
class="text-xs"
/>
</template>
</Button>
<Button
@@ -410,7 +436,10 @@ onUnmounted(stopPolling);
@click.stop="handleTaskDetail(task)"
>
<template #icon>
<IconifyIcon icon="ant-design:eye-outlined" class="text-xs" />
<IconifyIcon
icon="ant-design:eye-outlined"
class="text-xs"
/>
</template>
</Button>
<Button
@@ -421,7 +450,10 @@ onUnmounted(stopPolling);
@click.stop="handleTaskDelete(task.id)"
>
<template #icon>
<IconifyIcon icon="ant-design:delete-outlined" class="text-xs" />
<IconifyIcon
icon="ant-design:delete-outlined"
class="text-xs"
/>
</template>
</Button>
</div>
@@ -433,18 +465,33 @@ onUnmounted(stopPolling);
</div>
<!-- --- 右侧列 (40%) --- -->
<div class="flex h-full w-[40%] flex-none flex-col gap-5" style="padding-right: 1.25rem;">
<div
class="flex h-full w-[40%] flex-none flex-col gap-5"
style="padding-right: 1.25rem"
>
<!-- 卡片3: 工单趋势分析 -->
<GlassCard class="relative flex h-[35%] flex-col overflow-hidden p-6">
<div class="relative z-10 mb-2 flex items-start justify-between">
<div :class="cardContentClasses.container">
<h3 :class="cardContentClasses.title">工单趋势分析</h3>
<div :class="cardContentClasses.numberContainer">
<span :class="cardContentClasses.largeNumber">{{ todayOrderCount }}</span>
<Tag color="processing" :class="`text-xs font-bold ${textShadowClasses.tag}`">+{{ newOrderCount }} 新增</Tag>
<span :class="cardContentClasses.largeNumber">{{
todayOrderCount
}}</span>
<Tag
color="processing"
:class="`text-xs font-bold ${textShadowClasses.tag}`"
>
+{{ newOrderCount }} 新增
</Tag>
</div>
</div>
<Button type="text" size="small" :class="buttonClasses.viewAll" @click="message.info('查看全部工单')">
<Button
type="text"
size="small"
:class="buttonClasses.viewAll"
@click="message.info('查看全部工单')"
>
查看全部
</Button>
</div>
@@ -484,7 +531,14 @@ onUnmounted(stopPolling);
<!-- 神经网络背景图案 -->
<div :class="aiCardClasses.background">
<svg width="100%" height="100%">
<pattern id="grid" x="0" y="0" width="20" height="20" patternUnits="userSpaceOnUse">
<pattern
id="grid"
x="0"
y="0"
width="20"
height="20"
patternUnits="userSpaceOnUse"
>
<circle cx="1" cy="1" r="1" fill="white" />
</pattern>
<rect width="100%" height="100%" fill="url(#grid)" />
@@ -502,20 +556,34 @@ onUnmounted(stopPolling);
<div :class="aiCardClasses.leftContent">
<div class="mb-2 flex items-center gap-2">
<span :class="aiCardClasses.iconContainer">
<IconifyIcon icon="ant-design:robot-outlined" class="text-xs text-white" />
<IconifyIcon
icon="ant-design:robot-outlined"
class="text-xs text-white"
/>
</span>
<span :class="aiCardClasses.label">AI Agent</span>
</div>
<h3 :class="aiCardClasses.title">需要我帮你做什么吗</h3>
<Button type="primary" :class="aiCardClasses.button" @click="message.info('打开AI助手')">
<Button
type="primary"
:class="aiCardClasses.button"
@click="message.info('打开AI助手')"
>
使用AI助手
<IconifyIcon icon="ant-design:robot-outlined" :class="aiCardClasses.buttonIcon" />
<IconifyIcon
icon="ant-design:robot-outlined"
:class="aiCardClasses.buttonIcon"
/>
</Button>
</div>
<!-- 右侧图片 -->
<div :class="aiCardClasses.imageContainer">
<img :src="robotImage" alt="AI Robot" :class="aiCardClasses.image" />
<img
:src="robotImage"
alt="AI Robot"
:class="aiCardClasses.image"
/>
</div>
</GlassCard>
</div>
@@ -539,7 +607,10 @@ onUnmounted(stopPolling);
</div>
<div>
<div :class="modalClasses.label">优先级</div>
<Tag :color="getPriorityConfig(selectedTask.priority).color" class="px-2 py-1 text-xs font-bold uppercase">
<Tag
:color="getPriorityConfig(selectedTask.priority).color"
class="px-2 py-1 text-xs font-bold uppercase"
>
{{ selectedTask.priority }}
</Tag>
</div>

View File

@@ -20,9 +20,10 @@ import { getDashboardStats } from '#/api/ops/order-center';
defineOptions({ name: 'CleaningWorkOrderDashboard' });
// ========== 保洁类型映射 ==========
const CLEANING_TYPE_MAP: Record<
// eslint-disable-next-line no-unused-vars
const _CLEANING_TYPE_MAP: Record<
string,
{ type: string; icon: string; color: string }
{ color: string; icon: string; type: string }
> = {
ROUTINE: { type: '日常保洁', icon: 'solar:broom-bold', color: '#1677ff' },
DEEP: { type: '深度保洁', icon: 'solar:multiply-bold', color: '#52c41a' },
@@ -74,9 +75,9 @@ interface DashboardStats {
// 功能类型工单排行
functionTypeRanking: Array<{
functionType: string;
completed: number;
count: number;
functionType: string;
rate: number;
}>;
}
@@ -98,8 +99,9 @@ const { renderEcharts: renderHourlyChart } = useEcharts(hourlyChartRef);
const { renderEcharts: renderTimeTrendChart } = useEcharts(timeTrendChartRef);
const { renderEcharts: renderFunnelChart } = useEcharts(funnelChartRef);
const { renderEcharts: renderHeatmapChart } = useEcharts(heatmapChartRef);
const { renderEcharts: renderFunctionTypeRankingChart } =
useEcharts(functionTypeRankingChartRef);
const { renderEcharts: renderFunctionTypeRankingChart } = useEcharts(
functionTypeRankingChartRef,
);
const statsData = ref<DashboardStats>({
pendingCount: 0,

View File

@@ -346,18 +346,24 @@ const showLeaveWarning = computed(() => {
/** 动态生成应该显示的状态步骤(根据 timeline 过滤) */
const visibleSteps = computed(() => {
// 必须显示的节点(主流程)
const requiredSteps = ['PENDING', 'DISPATCHED', 'CONFIRMED', 'ARRIVED', 'COMPLETED'];
const requiredSteps = new Set([
'ARRIVED',
'COMPLETED',
'CONFIRMED',
'DISPATCHED',
'PENDING',
]);
// timeline 中存在的状态
const timelineStatuses = new Set(timeline.value.map(t => t.status));
const timelineStatuses = new Set(timeline.value.map((t) => t.status));
// 当前状态
const currentStatus = order.value.status;
// 过滤出要显示的节点
return STATUS_STEPS.filter(step => {
return STATUS_STEPS.filter((step) => {
// 必须显示的节点
if (requiredSteps.includes(step.key)) return true;
if (requiredSteps.has(step.key)) return true;
// QUEUED 节点:只有在 timeline 中明确存在时才显示
if (step.key === 'QUEUED') {
@@ -376,7 +382,9 @@ const currentStepIndex = computed(() => {
// 暂停状态显示在到岗后
return visibleSteps.value.findIndex((s) => s.key === 'ARRIVED');
}
const index = visibleSteps.value.findIndex((s) => s.key === order.value.status);
const index = visibleSteps.value.findIndex(
(s) => s.key === order.value.status,
);
return Math.max(index, 0);
});

View File

@@ -153,9 +153,7 @@ defineExpose({ refresh: loadStats });
<div class="stats-content">
<div
class="stats-icon"
style="
--icon-color: #ff4d4f; --icon-bg: #fff1f0"
style="--icon-color: #ff4d4f; --icon-bg: #fff1f0"
>
<IconifyIcon icon="solar:clock-circle-bold-duotone" />
</div>
@@ -177,9 +175,7 @@ defineExpose({ refresh: loadStats });
<div class="stats-content">
<div
class="stats-icon"
style="
--icon-color: #1677ff; --icon-bg: #e6f4ff"
style="--icon-color: #1677ff; --icon-bg: #e6f4ff"
>
<IconifyIcon icon="solar:play-circle-bold-duotone" />
</div>
@@ -201,9 +197,7 @@ defineExpose({ refresh: loadStats });
<div class="stats-content">
<div
class="stats-icon"
style="
--icon-color: #52c41a; --icon-bg: #f6ffed"
style="--icon-color: #52c41a; --icon-bg: #f6ffed"
>
<IconifyIcon icon="solar:check-circle-bold-duotone" />
</div>
@@ -223,9 +217,7 @@ defineExpose({ refresh: loadStats });
<div class="stats-content">
<div
class="stats-icon"
style="
--icon-color: #722ed1; --icon-bg: #f9f0ff"
style="--icon-color: #722ed1; --icon-bg: #f9f0ff"
>
<IconifyIcon
icon="solar:users-group-two-rounded-bold-duotone"