diff --git a/vehicle-data-platform/apps/web/src/v2/pages/AlertsPage.tsx b/vehicle-data-platform/apps/web/src/v2/pages/AlertsPage.tsx
index fba8c62d..2e1a48a8 100644
--- a/vehicle-data-platform/apps/web/src/v2/pages/AlertsPage.tsx
+++ b/vehicle-data-platform/apps/web/src/v2/pages/AlertsPage.tsx
@@ -89,20 +89,20 @@ function AlertTime({ value, className = '' }: { value?: string; className?: stri
const AlertEventTable = memo(function AlertEventTable({ rows, selectedID, compact, onSelect }: { rows: AlertEvent[]; selectedID: string; compact: boolean; onSelect: (id: string) => void }) {
const columns = useMemo(() => {
const allColumns = [
- { title: '级别', dataIndex: 'severity', width: 78, render: (_: AlertEvent['severity'], event: AlertEvent) => },
+ { title: '级别', dataIndex: 'severity', className: 'is-severity', width: 78, render: (_: AlertEvent['severity'], event: AlertEvent) => },
{
- title: '车牌 / VIN', dataIndex: 'plate', width: 132,
+ title: '车牌 / VIN', dataIndex: 'plate', className: 'is-vehicle', width: 132,
render: (_: string, event: AlertEvent) =>
{event.plate || '未绑定车牌'}{event.vin}
},
- { title: '规则', dataIndex: 'ruleName', width: 146, render: (value: string) => {value} },
- { title: '协议', dataIndex: 'protocol', width: 98, render: (value: string) => },
- { title: '触发时间', dataIndex: 'triggeredAt', width: 124, render: (value: string) => },
- { title: '状态', dataIndex: 'status', width: 78, render: (_: AlertEvent['status'], event: AlertEvent) => },
+ { title: '规则', dataIndex: 'ruleName', className: 'is-rule', width: 146, render: (value: string) => {value} },
+ { title: '协议', dataIndex: 'protocol', className: 'is-protocol', width: 98, render: (value: string) => },
+ { title: '触发时间', dataIndex: 'triggeredAt', className: 'is-triggered-at', width: 124, render: (value: string) => },
+ { title: '状态', dataIndex: 'status', className: 'is-status', width: 78, render: (_: AlertEvent['status'], event: AlertEvent) => },
{
- title: '触发证据', dataIndex: 'evidence', width: 150,
+ title: '触发证据', dataIndex: 'evidence', className: 'is-evidence', width: 150,
render: (_: unknown, event: AlertEvent) => {alertValue(event)}{thresholdText(event)}
},
- { title: '位置', dataIndex: 'location', width: 164, render: (value: string) => {value || '—'} },
+ { title: '位置', dataIndex: 'location', className: 'is-location', width: 164, render: (value: string) => {value || '—'} },
];
return compact
? allColumns
diff --git a/vehicle-data-platform/apps/web/src/v2/productionEntry.test.ts b/vehicle-data-platform/apps/web/src/v2/productionEntry.test.ts
index 047c9873..0b6c7947 100644
--- a/vehicle-data-platform/apps/web/src/v2/productionEntry.test.ts
+++ b/vehicle-data-platform/apps/web/src/v2/productionEntry.test.ts
@@ -47,6 +47,8 @@ describe('V2 production entry', () => {
expect(mainSource).toContain("window.history.scrollRestoration = 'manual'");
expect(workspaceStyles).toContain('.v2-navigation.semi-navigation .semi-navigation-item-icon-toggle-right:empty');
expect(workspaceStyles).toContain('.v2-mileage-source-trigger.semi-button .semi-button-content-right > b');
+ expect(workspaceStyles).toContain('.semi-table-row > .semi-table-row-cell:first-child::before');
+ expect(workspaceStyles).not.toContain('.semi-table-row::before');
});
test('renders a static boot shell and recovers when the React entry never becomes ready', () => {
diff --git a/vehicle-data-platform/apps/web/src/v2/styles/workspace.css b/vehicle-data-platform/apps/web/src/v2/styles/workspace.css
index 2327acbe..f97dbd8e 100644
--- a/vehicle-data-platform/apps/web/src/v2/styles/workspace.css
+++ b/vehicle-data-platform/apps/web/src/v2/styles/workspace.css
@@ -8923,7 +8923,7 @@
transition: background-color .16s ease, box-shadow .16s ease;
}
-.v2-alert-table-scroll .v2-alert-event-table .semi-table-tbody > .semi-table-row::before {
+.v2-alert-table-scroll .v2-alert-event-table .semi-table-tbody > .semi-table-row > .semi-table-row-cell:first-child::before {
position: absolute;
z-index: 2;
top: 7px;
@@ -8936,15 +8936,15 @@
pointer-events: none;
}
-.v2-alert-table-scroll .v2-alert-event-table .semi-table-tbody > .semi-table-row.is-severity-critical::before {
+.v2-alert-table-scroll .v2-alert-event-table .semi-table-tbody > .semi-table-row.is-severity-critical > .semi-table-row-cell:first-child::before {
background: #e5484d;
}
-.v2-alert-table-scroll .v2-alert-event-table .semi-table-tbody > .semi-table-row.is-severity-major::before {
+.v2-alert-table-scroll .v2-alert-event-table .semi-table-tbody > .semi-table-row.is-severity-major > .semi-table-row-cell:first-child::before {
background: #ed8d32;
}
-.v2-alert-table-scroll .v2-alert-event-table .semi-table-tbody > .semi-table-row.is-severity-minor::before {
+.v2-alert-table-scroll .v2-alert-event-table .semi-table-tbody > .semi-table-row.is-severity-minor > .semi-table-row-cell:first-child::before {
background: #d9a31d;
}
@@ -26143,6 +26143,24 @@
background: #edf5ff;
}
+.v2-alert-event-table.semi-table-wrapper :is(.semi-table-row-head, .semi-table-row-cell):is(.is-severity, .is-protocol, .is-triggered-at, .is-status) {
+ text-align: center;
+}
+
+.v2-alert-event-table .semi-table-row-cell.is-rule {
+ color: #31465f;
+ font-weight: 620;
+}
+
+.v2-alert-event-table .semi-table-row-cell.is-triggered-at .v2-alert-time {
+ color: #53667d;
+ font-variant-numeric: tabular-nums;
+}
+
+.v2-alert-event-table .semi-table-row-cell.is-location {
+ color: #607187;
+}
+
.v2-alert-event-evidence strong {
font-size: 13px;
}