diff --git a/vehicle-data-platform/apps/web/src/v2/pages/OperationsPage.test.tsx b/vehicle-data-platform/apps/web/src/v2/pages/OperationsPage.test.tsx index a892ebe0..c7264afa 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/OperationsPage.test.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/OperationsPage.test.tsx @@ -70,7 +70,9 @@ test('renders reconciliation queue, loads evidence on demand and records review expect(await screen.findByText('质量问题队列')).toBeInTheDocument(); expect(screen.getByRole('heading', { name: '运行与数据质量', level: 5 })).toBeInTheDocument(); - expect(screen.getByLabelText('运维质量操作')).toHaveClass('v2-workspace-command-bar', 'v2-ops-command-bar'); + expect(screen.getByLabelText('运维质量操作')).toHaveClass('v2-workspace-command-bar', 'v2-ops-command-bar', 'has-identity'); + expect(screen.getByLabelText('运维质量操作')).toHaveTextContent('运行治理'); + expect(screen.getByLabelText('运维质量操作').querySelector('.v2-workspace-command-icon.semi-avatar')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '刷新全局证据' })).toHaveClass('v2-workspace-mobile-tool-button', 'is-muted'); const navigation = screen.getByRole('navigation', { name: '运维质量视图' }); expect(navigation).toHaveClass('v2-ops-navigation'); diff --git a/vehicle-data-platform/apps/web/src/v2/pages/OperationsPage.tsx b/vehicle-data-platform/apps/web/src/v2/pages/OperationsPage.tsx index 6f6ca571..18caf091 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/OperationsPage.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/OperationsPage.tsx @@ -1,4 +1,4 @@ -import { IconRefresh, IconSearch, IconTickCircle } from '@douyinfe/semi-icons'; +import { IconPulse, IconRefresh, IconSearch, IconTickCircle } from '@douyinfe/semi-icons'; import { Button, Card, CardGroup, Checkbox, Descriptions, Empty, Input, Progress, Spin, Table, Tag, Typography } from '@douyinfe/semi-ui'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { FormEvent, useDeferredValue, useEffect, useMemo, useState } from 'react'; @@ -534,6 +534,8 @@ export default function OperationsPage() { } title="运行与数据质量" description="集中处理自动对账问题,按需诊断单车来源,并核对服务与协议健康;所有结论均可追溯。" status={data?.runtime.dataMode === 'production' ? '生产模式' : '状态待确认'} diff --git a/vehicle-data-platform/apps/web/src/v2/pages/UsersPage.test.tsx b/vehicle-data-platform/apps/web/src/v2/pages/UsersPage.test.tsx index a12b2eea..cb876260 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/UsersPage.test.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/UsersPage.test.tsx @@ -45,6 +45,9 @@ test('deduplicates vehicle candidates by VIN and renders granted vehicles plate const view = render(); const customer = await screen.findByRole('button', { name: /选择客户 华东客户/ }); + expect(screen.getByLabelText('账号管理操作')).toHaveClass('has-identity'); + expect(screen.getByLabelText('账号管理操作')).toHaveTextContent('访问治理'); + expect(screen.getByLabelText('账号管理操作').querySelector('.v2-workspace-command-icon.semi-avatar')).toBeInTheDocument(); expect(screen.getByLabelText('账号管理操作')).toHaveTextContent('客户访问治理'); expect(screen.getByLabelText('账号管理操作')).toHaveTextContent('变更最多 30 秒生效'); expect(view.container.querySelector('.v2-page-heading')).not.toBeInTheDocument(); diff --git a/vehicle-data-platform/apps/web/src/v2/pages/UsersPage.tsx b/vehicle-data-platform/apps/web/src/v2/pages/UsersPage.tsx index e4b790c2..10808930 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/UsersPage.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/UsersPage.tsx @@ -1,5 +1,5 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; -import { IconChevronRight, IconDelete, IconPlus, IconRefresh, IconSearch } from '@douyinfe/semi-icons'; +import { IconChevronRight, IconDelete, IconPlus, IconRefresh, IconSearch, IconUserGroup } from '@douyinfe/semi-icons'; import { Avatar, Button, Card, Checkbox, Collapse, Empty, Input, List, Select, Spin, Switch, Tabs, Tag, Typography } from '@douyinfe/semi-ui'; import { FormEvent, useDeferredValue, useEffect, useMemo, useState } from 'react'; import { api } from '../../api/client'; @@ -431,6 +431,8 @@ export default function UsersPage() { } title="客户访问治理" description="菜单与车辆按最小权限开放,变更最多 30 秒生效" status={`${customers.length} 个客户账号${attentionCustomerCount ? ` · ${attentionCustomerCount} 待完善` : ' · 权限就绪'}`} 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 27c2d885..52a60d16 100644 --- a/vehicle-data-platform/apps/web/src/v2/styles/workspace.css +++ b/vehicle-data-platform/apps/web/src/v2/styles/workspace.css @@ -27049,3 +27049,200 @@ display: none; } } + +/* + * Administration and operations identity convergence. + * Keep account authority and runtime health visually distinct while retaining + * the same Semi command anatomy and compact responsive behavior. + */ +.v2-user-discovery-shell > .v2-user-command-bar.has-identity { + min-height: 58px; + background: + radial-gradient(circle at 9% -100%, rgba(109, 91, 208, .1), transparent 46%), + linear-gradient(106deg, #fff 0%, #fdfcff 52%, #fbfdff 100%); + padding: 8px 10px 8px 12px; +} + +.v2-user-command-bar.has-identity .v2-workspace-command-copy { + min-width: 260px; +} + +.v2-user-command-bar.has-identity .v2-workspace-command-icon.semi-avatar { + width: 34px; + height: 34px; + flex-basis: 34px; + border-color: rgba(109, 91, 208, .13); + border-radius: 10px; + background: linear-gradient(145deg, #f5f2ff 0%, #eee9ff 100%); + color: #6656c8; + box-shadow: inset 0 1px rgba(255, 255, 255, .9), 0 5px 14px rgba(109, 91, 208, .07); +} + +.v2-user-command-bar.has-identity .v2-workspace-command-stack { + gap: 0; +} + +.v2-user-command-bar.has-identity .v2-workspace-command-eyebrow { + color: #8177af; + font-size: 7px; + line-height: 10px; +} + +.v2-user-command-bar.has-identity .v2-workspace-command-title { + color: #334155; + font-size: 14px; + font-weight: 760; + line-height: 18px; +} + +.v2-user-command-bar.has-identity .v2-workspace-command-description { + color: #8793a3; + font-size: 9px; + line-height: 12px; +} + +.v2-user-command-bar.has-identity .v2-workspace-command-actions > .semi-tag { + border-color: rgba(109, 91, 208, .1); + background: #f4f1ff; + color: #6656c8; +} + +.v2-ops-page > .v2-ops-command-bar.has-identity { + min-height: 60px; + background: + radial-gradient(circle at 8% -100%, rgba(16, 148, 110, .1), transparent 47%), + linear-gradient(108deg, #fff 0%, #fbfffd 52%, #fbfdff 100%); + padding: 8px 10px 8px 12px; +} + +.v2-ops-command-bar.has-identity .v2-workspace-command-copy { + min-width: 300px; +} + +.v2-ops-command-bar.has-identity .v2-workspace-command-icon.semi-avatar { + width: 34px; + height: 34px; + flex-basis: 34px; + border-color: rgba(16, 148, 110, .13); + border-radius: 10px; + background: linear-gradient(145deg, #edfbf6 0%, #e3f7ef 100%); + color: #0f8f68; + box-shadow: inset 0 1px rgba(255, 255, 255, .9), 0 5px 14px rgba(16, 148, 110, .07); +} + +.v2-ops-command-bar.has-identity .v2-workspace-command-stack { + gap: 0; +} + +.v2-ops-command-bar.has-identity .v2-workspace-command-eyebrow { + color: #5f8e7d; + font-size: 7px; + line-height: 10px; +} + +.v2-ops-command-bar.has-identity .v2-workspace-command-title { + color: #334155; + font-size: 14px; + font-weight: 760; + line-height: 18px; +} + +.v2-ops-command-bar.has-identity .v2-workspace-command-description { + max-width: 520px; + color: #8793a3; + font-size: 9px; + line-height: 12px; +} + +.v2-ops-command-bar.has-identity .v2-workspace-command-actions > .semi-tag { + border-color: rgba(16, 148, 110, .1); + background: #eaf8f3; + color: #0f7d5e; +} + +@media (min-width: 681px) and (max-width: 980px) { + .v2-user-command-bar.has-identity .v2-workspace-command-copy, + .v2-ops-command-bar.has-identity .v2-workspace-command-copy { + min-width: 210px; + } + + .v2-user-command-bar.has-identity .v2-workspace-command-description, + .v2-ops-command-bar.has-identity .v2-workspace-command-description { + display: none; + } +} + +@media (max-width: 680px) { + .v2-user-discovery-shell > .v2-user-command-bar.has-identity, + .v2-ops-page > .v2-ops-command-bar.has-identity { + min-height: 56px; + padding: 6px 7px 6px 9px; + } + + .v2-user-command-bar.has-identity .v2-workspace-command-copy, + .v2-ops-command-bar.has-identity .v2-workspace-command-copy { + min-width: 0; + gap: 7px; + } + + .v2-user-command-bar.has-identity .v2-workspace-command-icon.semi-avatar, + .v2-ops-command-bar.has-identity .v2-workspace-command-icon.semi-avatar { + width: 31px; + height: 31px; + flex-basis: 31px; + border-radius: 9px; + font-size: 13px; + } + + .v2-user-command-bar.has-identity .v2-workspace-command-eyebrow, + .v2-ops-command-bar.has-identity .v2-workspace-command-eyebrow { + font-size: 7px; + line-height: 9px; + } + + .v2-user-command-bar.has-identity .v2-workspace-command-title, + .v2-ops-command-bar.has-identity .v2-workspace-command-title { + font-size: 12px; + line-height: 15px; + } + + .v2-user-command-bar.has-identity .v2-workspace-command-description, + .v2-user-command-bar.has-identity .v2-workspace-command-meta, + .v2-ops-command-bar.has-identity .v2-workspace-command-description, + .v2-ops-command-bar.has-identity .v2-workspace-command-meta { + display: none; + } +} + +@media (max-width: 900px) and (max-height: 480px) and (orientation: landscape) { + .v2-ops-page > .v2-ops-command-bar.has-identity { + height: 44px; + min-height: 44px; + padding: 4px 5px 4px 8px; + } + + .v2-ops-command-bar.has-identity .v2-workspace-command-copy { + min-width: 0; + gap: 5px; + } + + .v2-ops-command-bar.has-identity .v2-workspace-command-icon.semi-avatar { + width: 28px; + height: 28px; + flex-basis: 28px; + border-radius: 8px; + font-size: 12px; + } + + .v2-ops-command-bar.has-identity .v2-workspace-command-eyebrow, + .v2-ops-command-bar.has-identity .v2-workspace-command-description, + .v2-ops-command-bar.has-identity .v2-workspace-command-status, + .v2-ops-command-bar.has-identity .v2-workspace-command-meta { + display: none; + } + + .v2-ops-command-bar.has-identity .v2-workspace-command-title { + font-size: 11px; + line-height: 14px; + } +}