diff --git a/vehicle-data-platform/apps/web/src/pages/Quality.tsx b/vehicle-data-platform/apps/web/src/pages/Quality.tsx
index 72ab0295..c89f7b3e 100644
--- a/vehicle-data-platform/apps/web/src/pages/Quality.tsx
+++ b/vehicle-data-platform/apps/web/src/pages/Quality.tsx
@@ -723,6 +723,8 @@ export function Quality({
const dispatchOwnerRows = alertDispatchOwnerRows(rules);
const priorityP0Count = priorityRows.filter((row) => row.priority === 'P0').length;
const priorityP1Count = priorityRows.filter((row) => row.priority === 'P1').length;
+ const focusIssue = priorityRows[0];
+ const focusLookup = focusIssue ? qualityIssueVehicleLookup(focusIssue) : undefined;
const activeRulesForImpact = rules.filter((row) => row.count > 0);
const storageWritable = !health || (health.tdengineWritable && health.mysqlWritable);
const capacityFindingCount = health?.capacityFindings?.length ?? 0;
@@ -972,6 +974,81 @@ export function Quality({
+
+
+
+
+
+ {focusIssue ? focusIssue.priority : '无待处置'}
+
+
+ {focusIssue ? qualityIssueLabel(focusIssue.issueType) : '车辆服务正常'}
+
+
+ {focusIssue?.vehicleLabel || '暂无优先车辆'}
+
+ {focusIssue
+ ? `${focusIssue.actionLabel}:${focusIssue.actionDetail || focusIssue.detail || '请结合实时、轨迹、RAW 和里程证据闭环。'}`
+ : '当前没有进入优先队列的车辆,保持实时监控并定期复核告警规则。'}
+
+
+
+
+
+
+
+ {[
+ {
+ label: '实时确认',
+ value: focusIssue ? '看在线' : '待命',
+ detail: '先确认车辆是否仍在线、最后上报来源和实时字段是否恢复。',
+ action: '实时状态',
+ color: focusIssue ? 'blue' as const : 'grey' as const,
+ disabled: !focusIssue || !focusLookup?.key || !onOpenRealtime,
+ onClick: () => focusIssue && openIssueRealtime(focusIssue)
+ },
+ {
+ label: '轨迹证据',
+ value: focusIssue ? '看前后' : '待命',
+ detail: '按告警发生日期打开轨迹,判断是否影响车辆定位和回放。',
+ action: '轨迹回放',
+ color: focusIssue ? 'green' as const : 'grey' as const,
+ disabled: !focusIssue || !focusLookup?.key || !onOpenHistory,
+ onClick: () => focusIssue && openIssueHistory(focusIssue)
+ },
+ {
+ label: '里程复核',
+ value: focusIssue ? '核统计' : '待命',
+ detail: '对同一天里程统计与轨迹证据做交叉校验,避免影响 BI。',
+ action: '里程统计',
+ color: focusIssue ? 'orange' as const : 'grey' as const,
+ disabled: !focusIssue || !focusLookup?.key || !onOpenMileage,
+ onClick: () => focusIssue && openIssueMileage(focusIssue)
+ },
+ {
+ label: '原始证据',
+ value: focusIssue ? '查RAW' : '待命',
+ detail: '保留原始帧和解析字段,给平台、客户和研发确认责任边界。',
+ action: 'RAW证据',
+ color: focusIssue ? 'blue' as const : 'grey' as const,
+ disabled: !focusIssue || !focusLookup?.key || !onOpenRaw,
+ onClick: () => focusIssue && openIssueRaw(focusIssue)
+ }
+ ].map((item) => (
+
+ {item.label}
+ {item.value}
+ {item.detail}
+
+
+ ))}
+
+
+
{[
{ label: '问题车辆', value: issueVehicleCount.toLocaleString() },
diff --git a/vehicle-data-platform/apps/web/src/styles/global.css b/vehicle-data-platform/apps/web/src/styles/global.css
index 33bf4890..98e470f7 100644
--- a/vehicle-data-platform/apps/web/src/styles/global.css
+++ b/vehicle-data-platform/apps/web/src/styles/global.css
@@ -1417,6 +1417,68 @@ button.vp-realtime-command-item:focus-visible {
line-height: 20px;
}
+.vp-alert-vehicle-task-board {
+ display: grid;
+ grid-template-columns: minmax(280px, 0.72fr) minmax(0, 1.28fr);
+ gap: 16px;
+}
+
+.vp-alert-vehicle-focus {
+ min-height: 172px;
+ padding: 12px;
+ border: 1px solid rgba(239, 68, 68, 0.24);
+ border-radius: var(--vp-radius);
+ background: #fff7f7;
+ display: grid;
+ gap: 10px;
+ align-content: start;
+}
+
+.vp-alert-vehicle-focus strong {
+ color: var(--vp-text);
+ font-size: 20px;
+ line-height: 26px;
+ font-weight: 700;
+ word-break: break-word;
+}
+
+.vp-alert-vehicle-focus span {
+ color: var(--vp-text-muted);
+ font-size: 13px;
+ line-height: 20px;
+}
+
+.vp-alert-vehicle-task-grid {
+ display: grid;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: 12px;
+}
+
+.vp-alert-vehicle-task-item {
+ min-height: 172px;
+ padding: 12px;
+ border: 1px solid var(--vp-border);
+ border-radius: var(--vp-radius);
+ background: #fbfcff;
+ display: grid;
+ gap: 10px;
+ align-content: start;
+}
+
+.vp-alert-vehicle-task-item strong {
+ color: var(--vp-text);
+ font-size: 20px;
+ line-height: 26px;
+ font-weight: 700;
+ word-break: break-word;
+}
+
+.vp-alert-vehicle-task-item span {
+ color: var(--vp-text-muted);
+ font-size: 13px;
+ line-height: 20px;
+}
+
.vp-alert-flow-item {
min-height: 96px;
padding: 12px;
@@ -3344,6 +3406,8 @@ button.vp-realtime-command-item:focus-visible {
.vp-alert-dispatch-grid,
.vp-alert-center-board,
.vp-alert-center-grid,
+ .vp-alert-vehicle-task-board,
+ .vp-alert-vehicle-task-grid,
.vp-alert-command-board,
.vp-alert-command-grid,
.vp-notification-coverage-board,
diff --git a/vehicle-data-platform/apps/web/src/test/App.test.tsx b/vehicle-data-platform/apps/web/src/test/App.test.tsx
index d7f7d569..ca9a188d 100644
--- a/vehicle-data-platform/apps/web/src/test/App.test.tsx
+++ b/vehicle-data-platform/apps/web/src/test/App.test.tsx
@@ -3727,6 +3727,13 @@ test('shows actionable priority queue on quality page', async () => {
render(
);
expect(await screen.findByText('处置优先队列')).toBeInTheDocument();
+ expect(screen.getByText('车辆风险处置任务板')).toBeInTheDocument();
+ expect(screen.getAllByText('粤A优先1 / VIN-P0-001').length).toBeGreaterThan(0);
+ expect(screen.getByText('实时确认')).toBeInTheDocument();
+ expect(screen.getAllByText('轨迹证据').length).toBeGreaterThan(0);
+ expect(screen.getByText('里程复核')).toBeInTheDocument();
+ expect(screen.getAllByText('原始证据').length).toBeGreaterThan(0);
+ expect(screen.getByText('先确认车辆是否仍在线、最后上报来源和实时字段是否恢复。')).toBeInTheDocument();
expect(screen.getAllByText('P0').length).toBeGreaterThan(0);
expect(screen.getAllByText('粤A优先1 / VIN-P0-001').length).toBeGreaterThan(0);
expect(screen.getAllByText('确认平台转发').length).toBeGreaterThan(0);