fix: 工作台、工单统计看板接口对接

This commit is contained in:
lzh
2026-02-10 18:13:21 +08:00
2 changed files with 48 additions and 130 deletions

View File

@@ -200,13 +200,22 @@ export interface DashboardStatsResp {
};
funnelData: Array<{ name: string; value: number }>;
heatmapData: { days: string[]; hours: string[]; data: number[][] };
areaRanking: Array<{
area: string;
functionTypeRanking: Array<{
functionType: string;
count: number;
completed: number;
rate: number;
}>;
durationStats: Array<{ type: string; avgDuration: number }>;
}
/** 近7天客流趋势响应 */
export interface TrafficTrendResp {
dates: string[];
inData: number[];
outData: number[];
netData: number[];
totalIn: number;
totalOut: number;
}
/** 实时客流响应 */
@@ -268,6 +277,13 @@ export function getWorkspaceStats() {
);
}
/** 获取近7天客流趋势统计 */
export function getTrafficTrend() {
return requestClient.get<TrafficTrendResp>(
'/ops/order-center/traffic-trend',
);
}
// ==================== 工单操作接口 ====================
/** 重新分配/派单 */

View File

@@ -58,28 +58,20 @@ interface DashboardStats {
// 工单处理漏斗
funnelData: Array<{ name: string; value: number }>;
// 时段热力图数据7天 x 24小时
// 时段热力图数据(7天 x 24小时
heatmapData: {
data: number[][]; // 7x24的二维数组
days: string[]; // 周一到周日
hours: string[]; // 0-23小时
};
// 区域工单排行
areaRanking: Array<{
area: string;
// 功能类型工单排行
functionTypeRanking: Array<{
functionType: string;
completed: number;
count: number;
rate: number;
}>;
// 工单作业时长统计
durationStats: Array<{
avgDuration: number; // 分钟
color: string;
icon: string;
type: string;
}>;
}
// ========== 响应式数据 ==========
@@ -92,17 +84,15 @@ const hourlyChartRef = ref();
const timeTrendChartRef = ref();
const funnelChartRef = ref();
const heatmapChartRef = ref();
const areaRankingChartRef = ref();
const durationChartRef = ref();
const functionTypeRankingChartRef = ref();
const { renderEcharts: renderTrendChart } = useEcharts(trendChartRef);
const { renderEcharts: renderHourlyChart } = useEcharts(hourlyChartRef);
const { renderEcharts: renderTimeTrendChart } = useEcharts(timeTrendChartRef);
const { renderEcharts: renderFunnelChart } = useEcharts(funnelChartRef);
const { renderEcharts: renderHeatmapChart } = useEcharts(heatmapChartRef);
const { renderEcharts: renderAreaRankingChart } =
useEcharts(areaRankingChartRef);
const { renderEcharts: renderDurationChart } = useEcharts(durationChartRef);
const { renderEcharts: renderFunctionTypeRankingChart } =
useEcharts(functionTypeRankingChartRef);
const statsData = ref<DashboardStats>({
pendingCount: 0,
@@ -129,8 +119,7 @@ const statsData = ref<DashboardStats>({
hours: [],
data: [],
},
areaRanking: [],
durationStats: [],
functionTypeRanking: [],
});
// ========== 空数据API失败时的fallback ==========
@@ -144,8 +133,7 @@ const EMPTY_STATS: DashboardStats = {
timeTrendData: { dates: [], responseTimeData: [], completionTimeData: [] },
funnelData: [],
heatmapData: { days: [], hours: [], data: [] },
areaRanking: [],
durationStats: [],
functionTypeRanking: [],
};
// ========== 图表配置 ==========
@@ -674,10 +662,10 @@ function getHeatmapChartOptions(): ECOption {
}
/**
* 区域工单排行图表配置
* 功能类型排行图表配置
*/
function getAreaRankingChartOptions(): ECOption {
const { areaRanking } = statsData.value;
function getFunctionTypeRankingChartOptions(): ECOption {
const { functionTypeRanking } = statsData.value;
return {
grid: {
left: '3%',
@@ -698,7 +686,7 @@ function getAreaRankingChartOptions(): ECOption {
},
yAxis: {
type: 'category',
data: areaRanking.map((item) => item.area),
data: functionTypeRanking.map((item) => item.functionType),
axisLabel: {
fontSize: 13,
color: '#595959',
@@ -713,7 +701,7 @@ function getAreaRankingChartOptions(): ECOption {
series: [
{
type: 'bar',
data: areaRanking.map((item) => ({
data: functionTypeRanking.map((item) => ({
value: item.count,
itemStyle: {
color: getCompletionRateColor(item.rate),
@@ -743,67 +731,6 @@ function getAreaRankingChartOptions(): ECOption {
}
}
/**
* 工单作业时长统计图表配置
*/
function getDurationChartOptions(): ECOption {
const { durationStats } = statsData.value;
return {
grid: {
left: '3%',
right: '18%',
top: '5%',
bottom: '3%',
containLabel: true,
},
xAxis: {
type: 'value',
max: 'dataMax',
splitLine: {
show: false,
},
axisLabel: {
show: false,
},
},
yAxis: {
type: 'category',
data: durationStats.map((item) => item.type),
axisLabel: {
fontSize: 13,
color: '#595959',
},
axisLine: {
show: false,
},
axisTick: {
show: false,
},
},
series: [
{
type: 'bar',
data: durationStats.map((item) => ({
value: item.avgDuration,
itemStyle: {
color: item.color,
borderRadius: [0, 6, 6, 0],
},
})),
barWidth: 18,
label: {
show: true,
position: 'right',
fontSize: 13,
color: '#262626',
fontWeight: 500,
formatter: (params: any) => `${params.value}分钟`,
},
},
],
};
}
// ========== 数据加载 ==========
/** 加载统计数据 */
@@ -811,20 +738,6 @@ async function loadStats() {
loading.value = true;
try {
const resp = await getDashboardStats();
// 映射 durationStats: 后端返回 type(枚举key) + avgDuration前端补充显示名、图标、颜色
const mappedDurationStats = (resp.durationStats || []).map((item) => {
const mapping = CLEANING_TYPE_MAP[item.type] || {
type: item.type,
icon: 'solar:broom-bold',
color: '#8c8c8c',
};
return {
type: mapping.type,
icon: mapping.icon,
color: mapping.color,
avgDuration: item.avgDuration,
};
});
statsData.value = {
pendingCount: resp.pendingCount,
@@ -836,8 +749,7 @@ async function loadStats() {
timeTrendData: resp.timeTrendData,
funnelData: resp.funnelData,
heatmapData: resp.heatmapData,
areaRanking: resp.areaRanking,
durationStats: mappedDurationStats,
functionTypeRanking: resp.functionTypeRanking,
};
// 渲染图表
@@ -848,8 +760,7 @@ async function loadStats() {
renderTimeTrendChart(getTimeTrendChartOptions());
renderFunnelChart(getFunnelChartOptions());
renderHeatmapChart(getHeatmapChartOptions());
renderAreaRankingChart(getAreaRankingChartOptions());
renderDurationChart(getDurationChartOptions());
renderFunctionTypeRankingChart(getFunctionTypeRankingChartOptions());
} catch {
// API失败时使用空数据作为fallback
statsData.value = { ...EMPTY_STATS };
@@ -983,9 +894,9 @@ onUnmounted(() => {
</Col>
<Col :xs="24" :lg="8">
<Card class="chart-card" title="工单时段分布">
<Card class="chart-card" title="今日工单时段分布">
<template #extra>
<Tooltip title="展示一天24小时各时段的工单数量分布">
<Tooltip title="展示今日24小时各时段的工单数量分布">
<IconifyIcon
icon="solar:info-circle-bold-duotone"
class="info-icon"
@@ -1040,13 +951,13 @@ onUnmounted(() => {
</Col>
</Row>
<!-- 第四行时段热力图 + 区域工单排行 + 工单作业时长 -->
<!-- 第四行时段热力图近7天 + 功能类型排行 -->
<Row :gutter="[12, 12]">
<!-- <EFBFBD><EFBFBD><EFBFBD>热力图 -->
<Col :xs="24" :md="8" :lg="8">
<!-- 段热力图近7天 -->
<Col :xs="24" :md="12" :lg="12">
<Card class="modern-card modern-card--heatmap">
<div class="modern-header">
<span class="modern-title">时段热力图</span>
<span class="modern-title">时段热力图近7天</span>
</div>
<Spin :spinning="chartLoading">
<EchartsUI ref="heatmapChartRef" class="modern-chart" />
@@ -1054,26 +965,17 @@ onUnmounted(() => {
</Card>
</Col>
<!-- 区域工单排行 -->
<Col :xs="24" :md="8" :lg="8">
<!-- 功能类型排行 -->
<Col :xs="24" :md="12" :lg="12">
<Card class="modern-card modern-card--ranking">
<div class="modern-header">
<span class="modern-title">区域工单排行</span>
<span class="modern-title">功能类型排行</span>
</div>
<Spin :spinning="chartLoading">
<EchartsUI ref="areaRankingChartRef" class="modern-chart" />
</Spin>
</Card>
</Col>
<!-- 工单作业时长统计 -->
<Col :xs="24" :md="8" :lg="8">
<Card class="modern-card modern-card--duration">
<div class="modern-header">
<span class="modern-title">作业时长统计</span>
</div>
<Spin :spinning="chartLoading">
<EchartsUI ref="durationChartRef" class="modern-chart" />
<EchartsUI
ref="functionTypeRankingChartRef"
class="modern-chart"
/>
</Spin>
</Card>
</Col>