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 fc0d871f..57cc33f2 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 @@ -167,6 +167,10 @@ test('clears old alert rows and inspector evidence when the event scope changes' expect(screen.getByLabelText('告警触发证据')).toHaveTextContent('触发值90 km/h阈值条件> 80 km/h,持续 60 秒超限幅度+10 km/h'); expect(screen.getByText('1 条记录').closest('.semi-tag')).toBeInTheDocument(); expect(screen.getByText('可操作').closest('.semi-tag')).toBeInTheDocument(); + const dispositionCard = view.container.querySelector('.v2-alert-disposition-card'); + const progressCard = view.container.querySelector('.v2-alert-progress-card'); + expect(dispositionCard).toHaveAttribute('aria-label', '告警处置操作'); + expect(dispositionCard?.compareDocumentPosition(progressCard!)).toBe(Node.DOCUMENT_POSITION_FOLLOWING); expect(view.container.querySelector('.v2-alert-technical-collapse.semi-collapse')).toBeInTheDocument(); expect(screen.getByText('技术详情')).toBeInTheDocument(); expect(view.container.querySelector('.v2-alert-inspector-heading')).toHaveClass('v2-workspace-panel-header'); @@ -244,7 +248,12 @@ test('renders only selectable Semi alert cards on mobile', async () => { expect(action).toHaveAttribute('aria-expanded', 'true'); expect(await screen.findByRole('dialog', { name: '告警事件详情' })).toBeInTheDocument(); expect(document.querySelector('.v2-alert-detail-sidesheet')).toHaveClass('semi-sidesheet-bottom'); - expect(document.querySelector('.v2-alert-detail-sidesheet .semi-sidesheet-inner')).toHaveStyle({ height: 'min(86dvh, 760px)' }); + expect(document.querySelector('.v2-alert-detail-sidesheet .semi-sidesheet-inner')).toHaveStyle({ height: 'min(90dvh, 800px)' }); + expect(document.querySelector('.v2-alert-detail-sidesheet .v2-alert-inspector-heading')).not.toBeInTheDocument(); + const mobileDisposition = document.querySelector('.v2-alert-detail-sidesheet .v2-alert-disposition-card'); + const mobileProgress = document.querySelector('.v2-alert-detail-sidesheet .v2-alert-progress-card'); + expect(mobileDisposition).toHaveAttribute('aria-label', '告警处置操作'); + expect(mobileDisposition?.compareDocumentPosition(mobileProgress!)).toBe(Node.DOCUMENT_POSITION_FOLLOWING); expect(screen.getByLabelText('告警触发证据')).toHaveTextContent('超限幅度+10 km/h'); expect(await screen.findByText('mobile-event')).toBeInTheDocument(); fireEvent.click(screen.getByRole('button', { name: '关闭告警详情' })); 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 f933ad99..9cdfd409 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/AlertsPage.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/AlertsPage.tsx @@ -115,7 +115,8 @@ const AlertEventTable = memo(function AlertEventTable({ rows, selectedID, compac function EventInspector({ event, note, acting, actionError, editable, onNote, onAction, onClose, sheet = false }: { event?: AlertEvent; note: string; acting: boolean; actionError?: string; editable: boolean; onNote: (value: string) => void; onAction: (action: 'acknowledge' | 'close' | 'ignore') => void; onClose: () => void; sheet?: boolean }) { if (!event) return } title="选择告警事件" description="查看触发证据、状态时间线和处置动作。" />; const actionCount = event.actions?.length ?? 0; - return {sheet ? null : } aria-label="关闭告警详情" onClick={onClose} />}>} /> + return + {!sheet ? } aria-label="关闭告警详情" onClick={onClose} />>} /> : null} @@ -134,12 +135,12 @@ function EventInspector({ event, note, acting, actionError, editable, onNote, on 规则判断{event.ruleName} + 处置与备注{editable ? '可操作' : '只读'}} headerLine aria-label="告警处置操作"> + {editable ? <>{actionError ? {actionError} : null} onAction('acknowledge')}>确认告警 onAction('close')}>关闭 onAction('ignore')}>忽略> : 当前为只读角色,可查看完整证据与处置记录。} + 处理进度{actionCount ? `${actionCount} 条记录` : '待处置'}} headerLine> {event.actions?.length ? {event.actions.map((item, index) => {item.actor} · }>{actionLabels[item.action] ?? item.action}{item.note ? {item.note} : null})} : } - 处置与备注{editable ? '可操作' : '只读'}} headerLine> - {editable ? <>{actionError ? {actionError} : null} onAction('acknowledge')}>确认告警 onAction('close')}>关闭 onAction('ignore')}>忽略> : 当前为只读角色,可查看完整证据与处置记录。} - 告警详情{selectedEvent ? `${selectedEvent.plate || selectedEvent.vin} · ${selectedEvent.ruleName}` : '证据、状态与处置履历'}} onCancel={closeDetail} > 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 ea6dbd07..bbd6c779 100644 --- a/vehicle-data-platform/apps/web/src/v2/styles/workspace.css +++ b/vehicle-data-platform/apps/web/src/v2/styles/workspace.css @@ -1941,6 +1941,31 @@ padding-bottom: 14px; } + .v2-alert-inspector.is-sheet .v2-alert-inspector-content { + gap: 8px; + padding: 8px 8px 14px; + } + + .v2-alert-inspector.is-sheet .v2-alert-disposition-card > .semi-card-header { + min-height: 40px; + } + + .v2-alert-inspector.is-sheet .v2-alert-disposition-card > .semi-card-body { + padding: 8px !important; + } + + .v2-alert-inspector.is-sheet .v2-alert-disposition-card .semi-input-textarea { + min-height: 52px; + } + + .v2-alert-inspector.is-sheet .v2-alert-disposition-card .v2-alert-actions { + margin-top: 7px; + } + + .v2-alert-inspector.is-sheet .v2-alert-disposition-card .v2-alert-actions > .semi-button { + min-height: 38px; + } + .v2-access-governance-summary > .semi-card-body { grid-template-columns: 1fr; } @@ -7630,6 +7655,89 @@ padding: 10px !important; } +.v2-alert-disposition-card { + border-color: #cfe0f7 !important; + box-shadow: 0 6px 18px rgba(18, 104, 243, .06) !important; +} + +.v2-alert-disposition-card > .semi-card-header { + background: linear-gradient(90deg, #f4f8ff 0%, #fff 72%); +} + +.v2-alert-disposition-card .v2-alert-actions { + margin-top: 9px; +} + +.v2-alert-disposition-card .v2-alert-actions > .semi-button { + min-height: 36px; + border-radius: 8px; +} + +.v2-alert-inspector:not(.is-sheet) .v2-alert-inspector-content { + gap: 8px; + padding: 8px; +} + +.v2-alert-inspector:not(.is-sheet) > .semi-card-body > .v2-alert-inspector-heading { + min-height: 64px; + padding: 8px 11px; +} + +.v2-alert-inspector:not(.is-sheet) > .semi-card-body > .v2-alert-inspector-heading > .v2-workspace-panel-copy { + gap: 2px; +} + +.v2-alert-inspector:not(.is-sheet) > .semi-card-body > .v2-alert-inspector-heading > .v2-workspace-panel-actions { + max-width: none; + align-items: center; + flex-direction: row; + gap: 6px; +} + +.v2-alert-inspector:not(.is-sheet) .v2-alert-focus-identity { + min-height: 68px; + padding: 9px 11px; +} + +.v2-alert-inspector:not(.is-sheet) .v2-alert-focus-facts > span { + min-height: 48px; + padding: 6px 9px; +} + +.v2-alert-inspector:not(.is-sheet) .v2-alert-focus-card .v2-alert-evidence { + padding: 8px; +} + +.v2-alert-inspector:not(.is-sheet) .v2-alert-focus-card .v2-alert-evidence > .v2-alert-evidence-value > .semi-card-body { + min-height: 62px; + padding-block: 6px; +} + +.v2-alert-inspector:not(.is-sheet) .v2-alert-focus-rule { + min-height: 34px; + padding-block: 5px; +} + +.v2-alert-inspector:not(.is-sheet) .v2-alert-disposition-card > .semi-card-header { + min-height: 40px; +} + +.v2-alert-inspector:not(.is-sheet) .v2-alert-disposition-card > .semi-card-body { + padding: 8px !important; +} + +.v2-alert-inspector:not(.is-sheet) .v2-alert-disposition-card .semi-input-textarea { + min-height: 48px; +} + +.v2-alert-inspector:not(.is-sheet) .v2-alert-disposition-card .v2-alert-actions { + margin-top: 7px; +} + +.v2-alert-inspector:not(.is-sheet) .v2-alert-disposition-card .v2-alert-actions > .semi-button { + min-height: 34px; +} + .v2-alert-inspector > .semi-card-body > .v2-alert-links { min-height: 50px; padding: 7px 10px;
{actionError}
当前为只读角色,可查看完整证据与处置记录。
{item.note}