diff --git a/vehicle-data-platform/apps/web/src/v2/pages/AlertsPage.test.tsx b/vehicle-data-platform/apps/web/src/v2/pages/AlertsPage.test.tsx index dd21c979..503a363c 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/AlertsPage.test.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/AlertsPage.test.tsx @@ -123,9 +123,12 @@ test('clears old alert rows and inspector evidence when the event scope changes' const view = render(); expect((await screen.findAllByText('旧告警车牌')).length).toBeGreaterThan(0); - for (const className of ['v2-alert-filter-card', 'v2-alert-kpis-card', 'v2-alert-table-card']) { + for (const className of ['v2-alert-filter-card', 'v2-alert-kpis-card', 'v2-alert-context-card', 'v2-alert-table-card']) { expect(view.container.querySelector(`.${className}.semi-card`)).toBeInTheDocument(); } + expect(view.container.querySelector('.v2-alert-navigation')).toBeInTheDocument(); + expect(screen.getByText('可处置事件')).toBeInTheDocument(); + expect(screen.queryByRole('heading', { level: 2, name: '告警中心' })).not.toBeInTheDocument(); expect(view.container.querySelector('.v2-alert-inspector')).not.toBeInTheDocument(); expect(view.container.querySelector('.v2-alert-workspace')).not.toHaveClass('is-inspector-open'); expect(view.container.querySelectorAll('.v2-alert-kpis .v2-metric-action')).toHaveLength(4); 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 d79d160b..adce4c76 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/AlertsPage.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/AlertsPage.tsx @@ -8,7 +8,6 @@ import type { AlertEvent, AlertNotification, AlertQuery, AlertRule, AlertRuleInp import { actionLabels, alertValue, canAct, formatAlertTime, operatorLabels, ruleCondition, severityLabels, statusLabels, thresholdText } from '../domain/alert'; import { InlineError, PanelEmpty, PanelLoading } from '../shared/AsyncState'; import { MetricActionButton } from '../shared/MetricActionButton'; -import { PageHeader } from '../shared/PageHeader'; import { SegmentedTabs } from '../shared/SegmentedTabs'; import { TablePagination } from '../shared/TablePagination'; import { WorkspacePanelHeader } from '../shared/WorkspacePanelHeader'; @@ -197,8 +196,8 @@ function EventWorkspace({ filters, draft, setDraft, setFilters, rules, unread, e {summary.isError ? summary.refetch()} /> : null} - -
{[ + +
{[ { label: '活跃告警', value: sums?.active, tone: 'active', status: '' }, { label: '未处理', value: sums?.unprocessed, tone: 'unprocessed', status: 'unprocessed' }, { label: '处理中', value: sums?.processing, tone: 'processing', status: 'processing' }, @@ -218,7 +217,12 @@ function EventWorkspace({ filters, draft, setDraft, setFilters, rules, unread, e {events.isError ? events.refetch()} /> : null}
- } onClick={() => Promise.all([events.refetch(), summary.refetch(), ...(selectedID ? [detail.refetch()] : [])])}>刷新} /> + } loading={events.isFetching} onClick={() => Promise.all([events.refetch(), summary.refetch(), ...(selectedID ? [detail.refetch()] : [])])}>刷新} + />
{mobileLayout ?
{rows.map((event) => )}
@@ -406,5 +410,5 @@ export default function AlertsPage() { const setTab = (next: Tab) => { setTabState(next); const copy = new URLSearchParams(params); copy.set('tab', next); setParams(copy, { replace: true }); }; const setFilters = (next: Filters) => { setFilterState(next); const copy = new URLSearchParams(); if (tab !== 'events') copy.set('tab', tab); Object.entries(next).forEach(([key, value]) => { if (value) copy.set(key, value); }); setParams(copy, { replace: true }); }; const tabs = [{ key: 'events' as const, label: '告警事件', icon: }, ...(admin ? [{ key: 'rules' as const, label: '规则配置' }] : []), { key: 'notifications' as const, label: '站内通知', icon: , count: unread || undefined }]; - return
{operator ? '可处置事件' : '只读查看'}} />{activeTab !== 'notifications' && rules.isError ? rules.refetch()} /> : null}{activeTab === 'rules' && metrics.isError ? metrics.refetch()} /> : null}{activeTab === 'events' ? : activeTab === 'rules' ? : }
; + return
{operator ? '可处置事件' : '只读查看'}{unread ? `${unread.toLocaleString('zh-CN')} 条未读` : '通知已读'}
{activeTab !== 'notifications' && rules.isError ? rules.refetch()} /> : null}{activeTab === 'rules' && metrics.isError ? metrics.refetch()} /> : null}{activeTab === 'events' ? : activeTab === 'rules' ? : }
; } 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 b5e8788e..26706a67 100644 --- a/vehicle-data-platform/apps/web/src/v2/productionEntry.test.ts +++ b/vehicle-data-platform/apps/web/src/v2/productionEntry.test.ts @@ -55,11 +55,11 @@ describe('V2 production entry', () => { expect(source).toContain("from '@douyinfe/semi-ui'"); expect(source).toContain(' { expect(corePageSources.AlertsPage).toContain(' .semi-button { + min-height: 32px; + border-radius: 6px; + font-size: 12px; +} + +.v2-alert-navigation-meta { + display: flex; + min-width: 0; + align-items: center; + justify-content: flex-end; + gap: 9px; + white-space: nowrap; +} + +.v2-alert-navigation-meta > .semi-typography { + color: #7d899a; + font-size: 11px; +} + +.v2-alert-navigation-meta > .semi-tag { + min-height: 24px; + border-radius: 6px; + font-size: 10px; +} + +.v2-alert-filter-card.semi-card, +.v2-alert-context-card.semi-card, +.v2-alert-table-card.semi-card, +.v2-alert-inspector.semi-card, +.v2-alert-rule-list.semi-card, +.v2-alert-rule-editor.semi-card, +.v2-alert-notifications.semi-card { + border-color: #dce4ed; + border-radius: 9px; + box-shadow: 0 3px 14px rgba(31, 53, 80, .045); +} + +.v2-alert-filter-card.semi-card { + overflow: visible; +} + +.v2-alert-filter-card > .semi-card-body > .v2-workspace-filter-heading { + display: none; +} + +.v2-alert-filter.v2-alert-filter-primary { + min-height: 60px; + grid-template-columns: minmax(250px, 1.45fr) minmax(122px, .62fr) minmax(136px, .68fr) auto auto auto; + gap: 8px; + padding: 9px 11px; +} + +.v2-alert-filter.v2-alert-filter-primary label { + gap: 4px; + font-size: 10px; +} + +.v2-alert-filter.v2-alert-filter-primary label > div, +.v2-alert-filter.v2-alert-filter-primary .semi-select, +.v2-alert-filter.v2-alert-filter-primary .semi-input-wrapper, +.v2-alert-filter.v2-alert-filter-primary > .semi-button { + min-height: 34px; + border-radius: 7px; +} + +.v2-alert-filter.v2-alert-filter-primary .semi-input, +.v2-alert-filter.v2-alert-filter-primary .semi-select-selection-text, +.v2-alert-filter.v2-alert-filter-primary > .semi-button { + font-size: 12px; +} + +.v2-alert-context-card.semi-card { + min-height: 64px; + flex: 0 0 auto; + overflow: hidden; +} + +.v2-alert-context-card > .semi-card-body { + display: grid; + height: 100%; + grid-template-columns: minmax(0, 1fr) 278px; +} + +.v2-alert-context-card .v2-alert-kpis, +.v2-alert-context-card .v2-alert-kpis .v2-metric-action-content { + min-height: 64px; +} + +.v2-alert-context-card .v2-alert-kpis small { + font-size: 10px; +} + +.v2-alert-context-card .v2-alert-kpis strong { + margin-top: 5px; + font-size: 19px; +} + +.v2-alert-context-card .v2-alert-secondary-states { + padding: 6px; + gap: 4px; +} + +.v2-alert-context-card .v2-alert-secondary-states > .semi-button { + border-radius: 6px; + padding: 5px 6px; +} + +.v2-alert-context-card .v2-alert-secondary-states span { + font-size: 9px; +} + +.v2-alert-context-card .v2-alert-secondary-states b { + font-size: 14px; +} + +.v2-alert-workspace { + min-height: 0; + flex: 1 1 0; + gap: 9px; +} + +.v2-alert-workspace.is-inspector-open { + grid-template-columns: minmax(680px, 1fr) 370px; +} + +.v2-alert-table-card > .semi-card-body > .v2-workspace-panel-header { + min-height: 48px; + padding: 7px 12px; +} + +.v2-alert-table-card .v2-workspace-panel-copy { + gap: 1px; +} + +.v2-alert-table-card .v2-workspace-panel-copy > h5.semi-typography { + font-size: 14px; +} + +.v2-alert-table-card .v2-workspace-panel-copy > .semi-typography { + color: #8793a4; + font-size: 9px; +} + +.v2-alert-table-card .v2-workspace-panel-actions > .semi-button { + min-height: 30px; + border-radius: 6px; + font-size: 11px; +} + +.v2-alert-table-scroll { + scrollbar-color: #aebdce transparent; + scrollbar-width: thin; +} + +.v2-alert-table-scroll::-webkit-scrollbar { + width: 10px; + height: 10px; +} + +.v2-alert-table-scroll::-webkit-scrollbar-thumb { + border: 2px solid transparent; + border-radius: 999px; + background: #aebdce; + background-clip: padding-box; +} + +.v2-alert-table-scroll .v2-alert-event-table.semi-table-wrapper .semi-table-thead > .semi-table-row > .semi-table-row-head { + height: 38px; + background: #f7f9fc; + font-size: 10px; +} + +.v2-alert-table-scroll .v2-alert-event-table.semi-table-wrapper .semi-table-tbody > .semi-table-row > .semi-table-row-cell { + height: 46px; + padding: 6px 9px; + font-size: 11px; +} + +.v2-alert-table-card > .semi-card-body > footer { + min-height: 42px; + padding: 5px 10px; +} + +.v2-alert-table-card > .semi-card-body > footer button, +.v2-alert-table-card > .semi-card-body > footer select { + height: 28px; + font-size: 11px; +} + +.v2-alert-inspector.semi-card { + background: #f7f9fc; +} + +.v2-alert-inspector > .semi-card-body { + display: flex; + height: 100%; + min-height: 0; + flex-direction: column; +} + +.v2-alert-inspector > .semi-card-body > .v2-alert-inspector-heading { + min-height: 58px; + padding: 8px 11px; +} + +.v2-alert-inspector-content { + min-height: 0; + flex: 1 1 auto; + gap: 0; + overflow: auto; + padding: 0 10px 10px; +} + +.v2-alert-inspector-content > .v2-alert-detail-card.semi-card { + flex: 0 0 auto; + overflow: visible; +} + +.v2-alert-detail-card.semi-card { + border-width: 0 0 1px; + border-color: #e4e9f0; + border-radius: 0; + background: transparent; + box-shadow: none; +} + +.v2-alert-detail-card > .semi-card-header { + min-height: 40px; + border-bottom: 0; + padding: 0 2px; +} + +.v2-alert-detail-card > .semi-card-body { + border: 1px solid #e1e7ef; + border-radius: 7px; + background: #fff; +} + +.v2-alert-detail-card.v2-alert-progress-card > .semi-card-body, +.v2-alert-detail-card.v2-alert-disposition-card > .semi-card-body { + padding: 10px !important; +} + +.v2-alert-inspector > .semi-card-body > .v2-alert-links { + min-height: 46px; + padding: 6px 10px; +} + +.v2-alert-inspector > .semi-card-body > .v2-alert-links a { + min-height: 32px; +} + +.v2-alert-rules { + min-height: 0; + flex: 1 1 0; + grid-template-columns: minmax(300px, 340px) minmax(600px, 1fr); + gap: 9px; +} + +.v2-alert-rule-list.semi-card, +.v2-alert-rule-editor.semi-card { + overflow: hidden; +} + +.v2-alert-rule-list > .semi-card-body, +.v2-alert-rule-editor > .semi-card-body, +.v2-alert-rule-editor-form { + height: 100%; + min-height: 0; +} + +.v2-alert-rule-list > .semi-card-body, +.v2-alert-rule-editor-form { + display: flex; + flex-direction: column; +} + +.v2-alert-rule-items, +.v2-alert-rule-editor-form { + min-height: 0; +} + +.v2-alert-rule-items { + flex: 1 1 auto; + overflow: auto; +} + +.v2-alert-rule-editor-form { + overflow: auto; +} + +.v2-alert-rule-list > .semi-card-body > .v2-alert-rule-list-heading, +.v2-alert-rule-editor-form > .v2-alert-rule-editor-heading { + min-height: 56px; + padding: 8px 12px; +} + +.v2-alert-rule-item.semi-button { + min-height: 68px; + padding: 8px 11px; +} + +.v2-alert-rule-copy > small { + margin-top: 5px; +} + +.v2-alert-rule-templates { + padding: 11px 12px; +} + +.v2-alert-template-card.semi-button { + min-height: 72px; + padding: 9px; +} + +.v2-rule-form-grid { + gap: 11px 13px; + padding: 13px 14px 16px; +} + +.v2-alert-rule-editor-form > footer { + position: sticky; + z-index: 3; + bottom: 0; + min-height: 56px; + background: rgba(255, 255, 255, .97); + padding: 8px 14px; + backdrop-filter: blur(10px); +} + +.v2-alert-notifications.semi-card { + min-height: 0; + flex: 1 1 0; + overflow: hidden; +} + +.v2-alert-notifications > .semi-card-body { + display: grid; + height: 100%; + min-height: 0; + max-height: none; + grid-template-rows: 54px minmax(0, 1fr) auto; + overflow: hidden; +} + +.v2-alert-notifications > .semi-card-body > .v2-workspace-panel-header { + min-height: 54px; + padding: 8px 12px; +} + +.v2-alert-notification-list { + min-height: 0; + overflow: auto; + padding: 9px; +} + +.v2-alert-notification-cards.semi-card-group { + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 9px; +} + +.v2-alert-channel-card.semi-card { + border-width: 1px 0 0; + border-radius: 0; + box-shadow: none; +} + +.v2-alert-channel-card > .semi-card-header { + min-height: 34px; + padding: 0 12px; +} + +.v2-alert-channel-descriptions.semi-descriptions { + padding: 5px 9px 8px; +} + +.v2-alert-channel-descriptions table { + width: 100%; +} + +.v2-alert-channel-descriptions tbody { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 6px; +} + +.v2-alert-channel-descriptions tr { + display: flex; + min-width: 0; + min-height: 32px; + align-items: center; + justify-content: space-between; + gap: 6px; + border: 1px solid #e4e9f0; + border-radius: 6px; + background: #fafbfd; + padding: 4px 7px; +} + +.v2-alert-channel-descriptions .semi-descriptions-item { + min-height: 0; + padding: 0; +} + +.v2-alert-channel-descriptions .semi-descriptions-item-th { + width: auto; + padding-right: 0; +} + +@media (max-width: 1180px) and (min-width: 681px) { + .v2-alert-filter.v2-alert-filter-primary { + grid-template-columns: minmax(220px, 1fr) 120px 130px auto auto auto; + } + + .v2-alert-filter.v2-alert-filter-primary > .semi-button { + padding-inline: 9px; + } +} + +@media (max-width: 900px) and (min-width: 681px) { + .v2-alert-page { + height: 100%; + min-height: 0; + overflow: hidden; + } + + .v2-alert-workspace { + display: grid; + min-height: 0; + flex: 1 1 0; + } + + .v2-alert-table-card { + min-height: 0; + } +} + +@media (max-width: 680px) { + .v2-alert-page { + gap: 8px; + overflow: auto; + padding: 8px 7px 16px; + } + + .v2-alert-navigation { + position: sticky; + z-index: 8; + top: 0; + min-height: 46px; + border-radius: 9px; + padding: 3px; + } + + .v2-alert-navigation .v2-alert-tabs.v2-segmented-tabs { + position: static; + width: 100%; + min-height: 38px; + grid-auto-columns: minmax(104px, 1fr); + overflow-x: auto; + } + + .v2-alert-navigation .v2-alert-tabs.v2-segmented-tabs > .semi-button { + min-height: 32px; + padding-inline: 7px; + font-size: 10px; + } + + .v2-alert-navigation-meta { + display: none; + } + + .v2-alert-filter-card > .semi-card-body > .v2-workspace-filter-heading { + display: flex; + } + + .v2-alert-filter.v2-alert-filter-primary { + min-height: 0; + grid-template-columns: 1fr 1fr; + gap: 8px; + padding: 9px; + } + + .v2-alert-filter.v2-alert-filter-primary label:first-child { + grid-column: 1 / -1; + } + + .v2-alert-filter.v2-alert-filter-primary > .semi-button { + min-height: 40px; + } + + .v2-alert-filter.v2-alert-filter-primary > .v2-secondary-button { + display: none; + } + + .v2-alert-context-card.semi-card { + min-height: 0; + } + + .v2-alert-context-card > .semi-card-body { + display: block; + } + + .v2-alert-context-card .v2-alert-kpis { + min-height: 88px; + grid-template-columns: repeat(4, minmax(0, 1fr)); + } + + .v2-alert-context-card .v2-alert-kpis .v2-metric-action, + .v2-alert-context-card .v2-alert-kpis .v2-metric-action-content { + min-height: 44px; + } + + .v2-alert-context-card .v2-alert-secondary-states { + border-top: 1px solid #e4e9f0; + border-left: 0; + padding: 4px; + } + + .v2-alert-context-card .v2-alert-secondary-states > .semi-button { + min-height: 40px; + padding: 3px 5px; + } + + .v2-alert-table-card { + min-height: 460px; + } + + .v2-alert-table-card > .semi-card-body > .v2-workspace-panel-header { + min-height: 58px; + align-items: flex-start; + padding: 8px; + } + + .v2-alert-table-card .v2-workspace-panel-copy > .semi-typography { + display: none; + } + + .v2-alert-mobile-list { + gap: 7px; + padding: 7px; + } + + .v2-alert-mobile-card-content { + padding: 11px; + } + + .v2-alert-mobile-card-content p { + margin: 6px 0; + } + + .v2-alert-mobile-card-content dl { + gap: 6px 10px; + padding-top: 7px; + } + + .v2-alert-mobile-card-content dl > div { + display: grid; + min-width: 0; + min-height: 24px; + grid-template-columns: auto minmax(0, 1fr); + align-items: center; + gap: 6px; + } + + .v2-alert-mobile-card-content dd { + min-width: 0; + margin: 0; + overflow: hidden; + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; + } + + .v2-alert-mobile-card-content footer { + margin-top: 6px; + } + + .v2-alert-rules { + display: flex; + flex: none; + flex-direction: column; + overflow: visible; + } + + .v2-alert-rule-list { + max-height: 270px; + } + + .v2-alert-rule-editor.semi-card, + .v2-alert-rule-editor-form { + overflow: visible; + } + + .v2-alert-rule-editor-form > footer { + position: static; + } + + .v2-alert-notifications.semi-card { + min-height: 540px; + flex: none; + } + + .v2-alert-notification-cards.semi-card-group { + grid-template-columns: 1fr; + } + + .v2-alert-channel-descriptions tbody { + display: table-row-group; + } + + .v2-alert-channel-descriptions tr { + display: table-row; + min-height: initial; + border: 0; + background: transparent; + padding: 0; + } + + .v2-alert-channel-descriptions .semi-descriptions-item { + min-height: 32px; + padding: 4px 0; + } + + .v2-alert-channel-descriptions .semi-descriptions-item-th { + width: 135px; + padding-right: 10px; + } +}