From 29b9ce959496a8421c50528694f9e2b126b20aa6 Mon Sep 17 00:00:00 2001 From: lingniu Date: Sat, 18 Jul 2026 17:20:25 +0800 Subject: [PATCH] refine Semi UI identity permissions --- .../apps/web/src/v2/pages/UsersPage.test.tsx | 8 + .../apps/web/src/v2/pages/UsersPage.tsx | 52 +++- .../apps/web/src/v2/styles/workspace.css | 249 ++++++++++++++++++ 3 files changed, 303 insertions(+), 6 deletions(-) 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 af4fe959..95983c09 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 @@ -72,8 +72,16 @@ test('deduplicates vehicle candidates by VIN and renders granted vehicles plate expect(document.querySelector('.v2-user-editor-form')).toHaveAttribute('id', 'v2-user-editor-form'); expect(screen.getAllByRole('tab')).toHaveLength(3); expect(document.querySelector('.v2-user-vehicle-section.semi-card')).toBeInTheDocument(); + fireEvent.click(screen.getByRole('tab', { name: '登录身份' })); + expect(screen.getByLabelText('登录身份摘要')).toHaveTextContent('登录账号customer-east不可修改'); + expect(screen.getByLabelText('登录身份摘要')).toHaveTextContent('客户显示名称华东客户已设置'); + expect(screen.getByRole('group', { name: '基础身份' })).toHaveTextContent('用于客户登录和平台内展示'); + expect(screen.getByRole('group', { name: '安全与系统映射' })).toHaveTextContent('密码留空则保持不变'); fireEvent.click(screen.getByRole('tab', { name: /菜单权限/ })); expect(screen.getByText('客户开放菜单').closest('.semi-tag')).toBeInTheDocument(); + expect(screen.getByLabelText('已开放 1 个菜单,共 4 个')).toHaveTextContent('客户工作台按最小权限开放'); + expect(screen.getAllByText('已开放')).toHaveLength(1); + expect(screen.getAllByText('未开放')).toHaveLength(3); fireEvent.click(screen.getByRole('tab', { name: /车辆权限/ })); expect(document.querySelector('.v2-user-vehicle-section .v2-user-section-title .semi-tag')).toHaveTextContent('1 辆'); const granted = await screen.findByRole('button', { name: '移除 粤A11111' }); 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 8dcf2d29..27390e5c 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/UsersPage.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/UsersPage.tsx @@ -433,17 +433,57 @@ export default function UsersPage() { setActiveSection(String(key) as EditorSection)}> -
- - - - +
+
+ 登录账号{draft.username || '待设置'} + {creating ? '新账号' : '不可修改'} +
+
+ 客户显示名称{draft.displayName || '待设置'} + {draft.displayName ? '已设置' : '待完善'} +
+
+ 身份来源{selected?.authProvider && selected.authProvider !== 'local' ? selected.authProvider : '本地账号'} + 可扩展 +
+
+
+
+ 基础身份用于客户登录和平台内展示 + 必填 +
+
+ + +
+
+
+
+ 安全与系统映射{creating ? '设置初始密码,并按需关联外部客户标识' : '密码留空则保持不变,客户标识用于后续系统对接'} + {creating ? '密码必填' : '按需修改'} +
+
+ + +
菜单权限{draft.menuKeys.length}} itemKey="menus"> 菜单权限 客户开放菜单} headerLine> -
{customerMenus.map((menu) => )}
+
+ 当前开放{draft.menuKeys.length} / {customerMenus.length} +

{draft.menuKeys.length === customerMenus.length ? '客户工作台已完整开放' : '客户工作台按最小权限开放'}客户登录后只会看到下方已开放菜单,变更保存后最多 30 秒生效。

+ {draft.menuKeys.length ? '权限已配置' : '尚未开放'} +
+
{customerMenus.map((menu) => { + const selectedMenu = draft.menuKeys.includes(menu.key); + return ; + })}
车辆权限{draft.vehicleGrants.length}} itemKey="vehicles"> 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 ea093eb0..fb828e76 100644 --- a/vehicle-data-platform/apps/web/src/v2/styles/workspace.css +++ b/vehicle-data-platform/apps/web/src/v2/styles/workspace.css @@ -14184,3 +14184,252 @@ margin-top: 6px; } } + +/* + * Semi UI account identity and menu permissions: one shared hierarchy from + * account context to editable groups and the resulting customer workspace. + */ +.v2-user-editor-sidesheet .v2-user-identity-section > .semi-card-body, +.v2-user-editor-sidesheet .v2-user-menu-section > .semi-card-body { + display: grid; + gap: 12px; +} + +.v2-user-identity-overview { + display: grid; + overflow: hidden; + grid-template-columns: repeat(3, minmax(0, 1fr)); + border: 1px solid #dbe5f0; + border-radius: 10px; + background: linear-gradient(115deg, #f5f9ff 0%, #fbfdff 58%, #f7fbfa 100%); +} + +.v2-user-identity-overview > div { + display: flex; + min-width: 0; + min-height: 70px; + align-items: center; + justify-content: space-between; + gap: 8px; + padding: 12px 14px; +} + +.v2-user-identity-overview > div + div { + border-left: 1px solid #e1e9f2; +} + +.v2-user-identity-overview > div > span, +.v2-user-field-group > header > span { + display: grid; + min-width: 0; + gap: 3px; +} + +.v2-user-identity-overview small, +.v2-user-field-group > header small, +.v2-user-menu-overview small { + color: #7c8ca0; + font-size: 10px; + line-height: 1.45; +} + +.v2-user-identity-overview strong { + overflow: hidden; + color: #243b54; + font-size: 14px; + line-height: 1.45; + text-overflow: ellipsis; + white-space: nowrap; +} + +.v2-user-identity-overview .semi-tag, +.v2-user-field-group > header .semi-tag, +.v2-user-menu-overview > .semi-tag, +.v2-menu-permission-state.semi-tag { + min-height: 22px; + flex: 0 0 auto; + justify-content: center; + border-radius: 999px; + font-size: 9px; + font-weight: 700; +} + +.v2-user-field-group { + overflow: hidden; + border: 1px solid #e1e8f0; + border-radius: 10px; + background: #fff; +} + +.v2-user-field-group > header { + display: flex; + min-height: 52px; + align-items: center; + justify-content: space-between; + gap: 12px; + border-bottom: 1px solid #e8edf3; + background: #fbfcfe; + padding: 9px 12px; +} + +.v2-user-field-group > header strong { + color: #31465e; + font-size: 12px; +} + +.v2-user-field-group > .v2-user-fields { + gap: 12px; + padding: 12px; +} + +.v2-user-menu-overview { + display: grid; + min-height: 76px; + grid-template-columns: 116px minmax(0, 1fr) auto; + align-items: center; + gap: 16px; + border: 1px solid #d8e5f4; + border-radius: 10px; + background: linear-gradient(115deg, #edf5ff 0%, #f8fbff 62%, #f6fbf8 100%); + padding: 11px 14px; +} + +.v2-user-menu-overview > span, +.v2-user-menu-overview > p { + display: grid; + min-width: 0; + gap: 3px; + margin: 0; +} + +.v2-user-menu-overview > span { + border-right: 1px solid #d8e4f1; +} + +.v2-user-menu-overview > span strong { + color: #1268f3; + font-size: 24px; + line-height: 1; +} + +.v2-user-menu-overview > span i { + color: #74869b; + font-size: 11px; + font-style: normal; + font-weight: 600; +} + +.v2-user-menu-overview > p b { + color: #2d435b; + font-size: 12px; +} + +.v2-user-editor-sidesheet .v2-user-menu-section .v2-menu-permissions label { + display: grid; + grid-template-columns: auto minmax(0, 1fr) auto; + align-items: center; + gap: 11px; +} + +.v2-menu-permission-copy { + align-self: center; +} + +.v2-menu-permission-state.semi-tag { + min-width: 50px; +} + +@media (max-width: 680px) { + .v2-user-editor-sidesheet .v2-user-identity-section > .semi-card-header, + .v2-user-editor-sidesheet .v2-user-menu-section > .semi-card-header { + min-height: 42px; + } + + .v2-user-editor-sidesheet .v2-user-identity-section > .semi-card-body, + .v2-user-editor-sidesheet .v2-user-menu-section > .semi-card-body { + gap: 8px; + padding: 8px; + } + + .v2-user-identity-overview { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .v2-user-identity-overview > div { + min-height: 58px; + padding: 8px 9px; + } + + .v2-user-identity-overview > div:nth-child(3) { + grid-column: 1 / -1; + border-top: 1px solid #e1e9f2; + border-left: 0; + } + + .v2-user-identity-overview strong { + font-size: 12px; + } + + .v2-user-identity-overview .semi-tag { + min-width: 44px; + padding-inline: 6px; + } + + .v2-user-field-group > header { + min-height: 46px; + padding: 7px 9px; + } + + .v2-user-field-group > header small { + overflow: hidden; + max-width: 245px; + text-overflow: ellipsis; + white-space: nowrap; + } + + .v2-user-field-group > .v2-user-fields { + grid-template-columns: minmax(0, 1fr); + gap: 8px; + padding: 9px; + } + + .v2-user-menu-overview { + min-height: 70px; + grid-template-columns: 74px minmax(0, 1fr); + gap: 9px; + padding: 9px 10px; + } + + .v2-user-menu-overview > span strong { + font-size: 21px; + } + + .v2-user-menu-overview > p b { + font-size: 11px; + } + + .v2-user-menu-overview > p small { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .v2-user-menu-overview > .semi-tag { + display: none; + } + + .v2-user-editor-sidesheet .v2-user-menu-section .v2-menu-permissions { + gap: 7px; + } + + .v2-user-editor-sidesheet .v2-user-menu-section .v2-menu-permissions label { + min-height: 68px; + gap: 8px; + padding: 10px; + } + + .v2-menu-permission-state.semi-tag { + min-width: 46px; + padding-inline: 6px; + } +}