feat(platform): streamline vehicle service dashboard

This commit is contained in:
lingniu
2026-07-05 12:32:04 +08:00
parent 993b1adb00
commit 0b7fc31d52
4 changed files with 143 additions and 100 deletions
@@ -1416,102 +1416,6 @@ export function Dashboard({
))}
</div>
</Card>
<Card bordered title="客户常用服务" style={{ marginBottom: 16 }}>
<div className="vp-customer-workflow-grid">
{customerHeroActions.map((item) => (
<button key={item.title} type="button" className="vp-customer-workflow-item" onClick={item.onClick} aria-label={`客户工作流 ${item.title}`}>
<div>
<Typography.Title heading={6} style={{ margin: 0 }}>{item.title}</Typography.Title>
<Typography.Text type="secondary">{item.detail}</Typography.Text>
</div>
<strong>{item.value}</strong>
<Tag color="blue">{item.action}</Tag>
</button>
))}
</div>
</Card>
<Card bordered title="今日车辆服务任务板" style={{ marginBottom: 16 }}>
<div className="vp-customer-task-grid">
{customerTaskBoard.map((item) => (
<div key={item.title} className="vp-customer-task-item">
<div className="vp-customer-task-head">
<Tag color={item.color}>{item.title}</Tag>
<strong>{item.value}</strong>
</div>
<Typography.Text type="secondary">{item.detail}</Typography.Text>
<Space wrap>
<Button
size="small"
theme="solid"
type="primary"
disabled={item.disabled}
aria-label={`今日任务 ${item.title} ${item.primaryAction}`}
onClick={item.onPrimary}
>
{item.primaryAction}
</Button>
<Button
size="small"
theme="light"
type="primary"
disabled={item.disabled && item.secondaryAction !== '复制处置卡'}
aria-label={`今日任务 ${item.title} ${item.secondaryAction}`}
onClick={item.onSecondary}
>
{item.secondaryAction}
</Button>
</Space>
</div>
))}
</div>
</Card>
<div className="vp-kpi-grid">
{kpis.map((item) => (
<Card key={item.label} bordered className="vp-kpi-card" bodyStyle={{ padding: 0 }}>
<button className="vp-kpi-button" type="button" onClick={() => onOpenVehicles(item.filters)} aria-label={`${item.label} ${item.value}`}>
<div className="vp-kpi-value">{item.value}</div>
<div className="vp-kpi-label">{item.label}</div>
</button>
</Card>
))}
</div>
<Card bordered title="车辆服务入口" style={{ marginBottom: 16 }}>
<div className="vp-service-entry-board">
<div className="vp-service-entry-summary">
<Space wrap>
<Tag color="blue">客户服务路径</Tag>
<Tag color="green">{vehicleServiceOnlineText(serviceSummary, summary)}</Tag>
<Tag color={(summary?.issueVehicles ?? 0) > 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警事件</Tag>
</Space>
<Typography.Title heading={5} style={{ margin: 0 }}>从车辆出发,完成监控、复盘、统计、导出和告警闭环</Typography.Title>
<Typography.Text type="secondary">
客户看到的是车辆服务结果;接入来源只在需要追溯时作为证据通道出现。
</Typography.Text>
<Space wrap>
<Button size="small" theme="solid" type="primary" onClick={() => onOpenVehicles({ online: 'online' })}>查看在线车辆</Button>
<Button size="small" theme="light" type="primary" onClick={copyCustomerServiceGuide}>复制客户服务说明</Button>
<Button size="small" theme="light" type="primary" onClick={exportDashboardSnapshot}>导出驾驶舱 CSV</Button>
<Button size="small" theme="light" type="tertiary" onClick={copyOperationsHandoff}>复制运营交接摘要</Button>
</Space>
</div>
<div className="vp-service-entry-grid">
{customerServicePathItems.map((item) => (
<button
key={item.title}
type="button"
className="vp-service-entry-item"
onClick={item.onClick}
aria-label={`车辆服务入口 ${item.title} ${item.action}`}
>
<Tag color={item.color}>{item.title}</Tag>
<strong>{item.value}</strong>
<span>{item.detail}</span>
<em>{item.action}</em>
</button>
))}
</div>
</div>
</Card>
<Card
bordered
title={<Space><span>自定义时间监控</span><Tag color="blue">{timeMonitorSummary}</Tag></Space>}
@@ -1542,7 +1446,7 @@ export function Dashboard({
<div className="vp-time-monitor-actions">
<Button theme="solid" type="primary" onClick={openTimeMonitorHistory}>查看轨迹</Button>
<Button theme="light" type="primary" onClick={openTimeMonitorMileage}>统计里程</Button>
<Button theme="light" type="primary" onClick={openTimeMonitorRaw}>导出原始记录</Button>
<Button theme="light" type="primary" onClick={openTimeMonitorRaw}>历史查询导出</Button>
<Button theme="light" type="warning" onClick={openTimeMonitorAlerts}>查看告警</Button>
</div>
<Typography.Text type="secondary">
@@ -1638,6 +1542,110 @@ export function Dashboard({
))}
</div>
</Card>
<details className="vp-dashboard-secondary-details">
<summary>
<span>更多车辆服务入口</span>
<small>常用服务、今日任务、KPI 和车辆入口默认收起,主页面优先保留地图、指挥台和时间窗监控。</small>
</summary>
<div className="vp-dashboard-secondary-body">
<Card bordered title="客户常用服务" style={{ marginBottom: 16 }}>
<div className="vp-customer-workflow-grid">
{customerHeroActions.map((item) => (
<button key={item.title} type="button" className="vp-customer-workflow-item" onClick={item.onClick} aria-label={`客户工作流 ${item.title}`}>
<div>
<Typography.Title heading={6} style={{ margin: 0 }}>{item.title}</Typography.Title>
<Typography.Text type="secondary">{item.detail}</Typography.Text>
</div>
<strong>{item.value}</strong>
<Tag color="blue">{item.action}</Tag>
</button>
))}
</div>
</Card>
<Card bordered title="今日车辆服务任务板" style={{ marginBottom: 16 }}>
<div className="vp-customer-task-grid">
{customerTaskBoard.map((item) => (
<div key={item.title} className="vp-customer-task-item">
<div className="vp-customer-task-head">
<Tag color={item.color}>{item.title}</Tag>
<strong>{item.value}</strong>
</div>
<Typography.Text type="secondary">{item.detail}</Typography.Text>
<Space wrap>
<Button
size="small"
theme="solid"
type="primary"
disabled={item.disabled}
aria-label={`今日任务 ${item.title} ${item.primaryAction}`}
onClick={item.onPrimary}
>
{item.primaryAction}
</Button>
<Button
size="small"
theme="light"
type="primary"
disabled={item.disabled && item.secondaryAction !== '复制处置卡'}
aria-label={`今日任务 ${item.title} ${item.secondaryAction}`}
onClick={item.onSecondary}
>
{item.secondaryAction}
</Button>
</Space>
</div>
))}
</div>
</Card>
<div className="vp-kpi-grid">
{kpis.map((item) => (
<Card key={item.label} bordered className="vp-kpi-card" bodyStyle={{ padding: 0 }}>
<button className="vp-kpi-button" type="button" onClick={() => onOpenVehicles(item.filters)} aria-label={`${item.label} ${item.value}`}>
<div className="vp-kpi-value">{item.value}</div>
<div className="vp-kpi-label">{item.label}</div>
</button>
</Card>
))}
</div>
<Card bordered title="车辆服务入口" style={{ marginBottom: 16 }}>
<div className="vp-service-entry-board">
<div className="vp-service-entry-summary">
<Space wrap>
<Tag color="blue">客户服务路径</Tag>
<Tag color="green">{vehicleServiceOnlineText(serviceSummary, summary)}</Tag>
<Tag color={(summary?.issueVehicles ?? 0) > 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警事件</Tag>
</Space>
<Typography.Title heading={5} style={{ margin: 0 }}>从车辆出发,完成监控、复盘、统计、导出和告警闭环</Typography.Title>
<Typography.Text type="secondary">
客户看到的是车辆服务结果;接入来源只在需要追溯时作为数据通道出现。
</Typography.Text>
<Space wrap>
<Button size="small" theme="solid" type="primary" onClick={() => onOpenVehicles({ online: 'online' })}>查看在线车辆</Button>
<Button size="small" theme="light" type="primary" onClick={copyCustomerServiceGuide}>复制客户服务说明</Button>
<Button size="small" theme="light" type="primary" onClick={exportDashboardSnapshot}>导出驾驶舱 CSV</Button>
<Button size="small" theme="light" type="tertiary" onClick={copyOperationsHandoff}>复制运营交接摘要</Button>
</Space>
</div>
<div className="vp-service-entry-grid">
{customerServicePathItems.map((item) => (
<button
key={item.title}
type="button"
className="vp-service-entry-item"
onClick={item.onClick}
aria-label={`车辆服务入口 ${item.title} ${item.action}`}
>
<Tag color={item.color}>{item.title}</Tag>
<strong>{item.value}</strong>
<span>{item.detail}</span>
<em>{item.action}</em>
</button>
))}
</div>
</div>
</Card>
</div>
</details>
<details className="vp-dashboard-evidence-details">
<summary>
<span>运维和证据层</span>