feat: unify account permission workbenches
This commit is contained in:
@@ -67,10 +67,14 @@ test('deduplicates vehicle candidates by VIN and renders granted vehicles plate
|
|||||||
expect(document.querySelector('.v2-user-editor-sidesheet')).not.toBeInTheDocument();
|
expect(document.querySelector('.v2-user-editor-sidesheet')).not.toBeInTheDocument();
|
||||||
fireEvent.click(customer);
|
fireEvent.click(customer);
|
||||||
await waitFor(() => expect(customer).toHaveAttribute('aria-expanded', 'true'));
|
await waitFor(() => expect(customer).toHaveAttribute('aria-expanded', 'true'));
|
||||||
expect(screen.getByLabelText('账号权限概览')).toHaveTextContent('@customer-east菜单 1车辆 1最近登录 尚未登录权限就绪');
|
const accountSummary = screen.getByRole('list', { name: '客户账号详情摘要' });
|
||||||
|
expect(accountSummary).toHaveTextContent('登录账号@customer-east登录身份');
|
||||||
|
expect(accountSummary).toHaveTextContent('权限范围1 菜单 · 1 辆最小必要权限');
|
||||||
|
expect(accountSummary).toHaveTextContent('账号状态启用保存后最多 30 秒生效');
|
||||||
const editorSheet = document.querySelector<HTMLElement>('.v2-user-editor-sidesheet .semi-sidesheet-inner');
|
const editorSheet = document.querySelector<HTMLElement>('.v2-user-editor-sidesheet .semi-sidesheet-inner');
|
||||||
expect(editorSheet).toHaveAttribute('aria-label', '客户账号详情');
|
expect(editorSheet).toHaveAttribute('aria-label', '客户账号详情');
|
||||||
expect(editorSheet).toHaveStyle({ width: 'min(840px, 100vw)' });
|
expect(editorSheet).toHaveStyle({ width: 'min(840px, 100vw)' });
|
||||||
|
expect(editorSheet?.closest('.semi-sidesheet')).toHaveClass('v2-workspace-editor-sidesheet');
|
||||||
expect(document.querySelector('.v2-user-editor-sidesheet .v2-user-editor-tabs.semi-tabs')).toBeInTheDocument();
|
expect(document.querySelector('.v2-user-editor-sidesheet .v2-user-editor-tabs.semi-tabs')).toBeInTheDocument();
|
||||||
expect(document.querySelector('.v2-user-editor-form')).toHaveAttribute('id', 'v2-user-editor-form');
|
expect(document.querySelector('.v2-user-editor-form')).toHaveAttribute('id', 'v2-user-editor-form');
|
||||||
expect(screen.getAllByRole('tab')).toHaveLength(3);
|
expect(screen.getAllByRole('tab')).toHaveLength(3);
|
||||||
@@ -96,7 +100,14 @@ test('deduplicates vehicle candidates by VIN and renders granted vehicles plate
|
|||||||
fireEvent.click(screen.getByRole('button', { name: '调整 粤A11111 有效期' }));
|
fireEvent.click(screen.getByRole('button', { name: '调整 粤A11111 有效期' }));
|
||||||
expect(await screen.findByLabelText('粤A11111 启用时间')).toHaveValue('2026-06-05T00:00');
|
expect(await screen.findByLabelText('粤A11111 启用时间')).toHaveValue('2026-06-05T00:00');
|
||||||
expect(document.querySelectorAll('input[type="datetime-local"]')).toHaveLength(2);
|
expect(document.querySelectorAll('input[type="datetime-local"]')).toHaveLength(2);
|
||||||
expect(document.querySelector('.v2-user-grant-sidesheet .semi-sidesheet-inner')).toHaveAttribute('aria-label', '车辆授权有效期');
|
const grantSheet = document.querySelector('.v2-user-grant-sidesheet .semi-sidesheet-inner');
|
||||||
|
expect(grantSheet).toHaveAttribute('aria-label', '车辆授权有效期');
|
||||||
|
expect(grantSheet?.closest('.semi-sidesheet')).toHaveClass('v2-workspace-config-sidesheet');
|
||||||
|
const grantSummary = screen.getByRole('list', { name: '车辆授权有效期摘要' });
|
||||||
|
expect(grantSummary).toHaveTextContent('车牌粤A11111');
|
||||||
|
expect(grantSummary).toHaveTextContent('启用2026-06-05 00:00授权开始');
|
||||||
|
expect(grantSummary).toHaveTextContent('停用持续有效未设置结束时间');
|
||||||
|
expect(screen.getByRole('group', { name: '访问时间窗口' })).toHaveTextContent('只在授权区间内开放该车数据上海时间');
|
||||||
fireEvent.click(screen.getByRole('button', { name: '关闭车辆授权有效期' }));
|
fireEvent.click(screen.getByRole('button', { name: '关闭车辆授权有效期' }));
|
||||||
expect(document.querySelectorAll('input[type="datetime-local"]')).toHaveLength(0);
|
expect(document.querySelectorAll('input[type="datetime-local"]')).toHaveLength(0);
|
||||||
expect(document.querySelector('.v2-user-avatar')).toHaveClass('semi-avatar');
|
expect(document.querySelector('.v2-user-avatar')).toHaveClass('semi-avatar');
|
||||||
@@ -314,7 +325,7 @@ test('keeps granted vehicles primary and reveals mobile assignment tools on dema
|
|||||||
expect(screen.getByText('第 1–4 条,共 5 辆')).toBeInTheDocument();
|
expect(screen.getByText('第 1–4 条,共 5 辆')).toBeInTheDocument();
|
||||||
expect(document.querySelectorAll('.v2-assigned-vehicle-card.is-mobile-compact')).toHaveLength(4);
|
expect(document.querySelectorAll('.v2-assigned-vehicle-card.is-mobile-compact')).toHaveLength(4);
|
||||||
expect(document.querySelector('.v2-assigned-vehicle-interval')).toHaveAttribute('aria-label', '授权有效期:启用 2026-06-05 00:00;停用 持续有效');
|
expect(document.querySelector('.v2-assigned-vehicle-interval')).toHaveAttribute('aria-label', '授权有效期:启用 2026-06-05 00:00;停用 持续有效');
|
||||||
expect(document.querySelector('.v2-user-editor-last-login')).toHaveTextContent('最近登录');
|
expect(document.querySelector('.v2-user-editor-sidesheet .v2-workspace-config-title small')).toHaveTextContent('@customer-east · 最近登录');
|
||||||
|
|
||||||
fireEvent.click(toggle);
|
fireEvent.click(toggle);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
import { IconChevronRight, IconDelete, IconPlus, IconRefresh, IconSearch } from '@douyinfe/semi-icons';
|
import { IconChevronRight, IconDelete, IconPlus, IconRefresh, IconSearch } from '@douyinfe/semi-icons';
|
||||||
import { Avatar, Button, Card, Checkbox, Collapse, Empty, Input, List, Modal, Popconfirm, Select, SideSheet, Spin, Switch, Tabs, Tag, Typography } from '@douyinfe/semi-ui';
|
import { Avatar, Button, Card, Checkbox, Collapse, Empty, Input, List, Modal, Popconfirm, Select, Spin, Switch, Tabs, Tag, Typography } from '@douyinfe/semi-ui';
|
||||||
import { FormEvent, useDeferredValue, useEffect, useMemo, useState } from 'react';
|
import { FormEvent, useDeferredValue, useEffect, useMemo, useState } from 'react';
|
||||||
import { api } from '../../api/client';
|
import { api } from '../../api/client';
|
||||||
import type { AdminUser, CustomerUserInput, CustomerVehicleGrantInput } from '../../api/types';
|
import type { AdminUser, CustomerUserInput, CustomerVehicleGrantInput } from '../../api/types';
|
||||||
@@ -13,6 +13,7 @@ import { VehicleCandidateList } from '../shared/VehicleCandidateList';
|
|||||||
import { WorkspaceFilterPanel } from '../shared/WorkspaceFilterPanel';
|
import { WorkspaceFilterPanel } from '../shared/WorkspaceFilterPanel';
|
||||||
import { WorkspaceCommandBar } from '../shared/WorkspaceCommandBar';
|
import { WorkspaceCommandBar } from '../shared/WorkspaceCommandBar';
|
||||||
import { WorkspacePanelHeader } from '../shared/WorkspacePanelHeader';
|
import { WorkspacePanelHeader } from '../shared/WorkspacePanelHeader';
|
||||||
|
import { WorkspaceSideSheet, type WorkspaceSideSheetBadgeColor } from '../shared/WorkspaceSideSheet';
|
||||||
import { mergeVehicleCandidates } from '../shared/vehicleCandidates';
|
import { mergeVehicleCandidates } from '../shared/vehicleCandidates';
|
||||||
import { PanelEmpty, PanelLoading } from '../shared/AsyncState';
|
import { PanelEmpty, PanelLoading } from '../shared/AsyncState';
|
||||||
|
|
||||||
@@ -105,6 +106,11 @@ function customerScopeLabel(scope: CustomerScopeFilter) {
|
|||||||
return '全部状态';
|
return '全部状态';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function accessBadgeColor(color: CustomerAccessState['color']): WorkspaceSideSheetBadgeColor {
|
||||||
|
if (color === 'amber') return 'orange';
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
export default function UsersPage() {
|
export default function UsersPage() {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const mobileLayout = useMobileLayout();
|
const mobileLayout = useMobileLayout();
|
||||||
@@ -155,8 +161,6 @@ export default function UsersPage() {
|
|||||||
const hasUnsavedChanges = useMemo(() => draftSignature(draft) !== draftSignature(baselineDraft), [baselineDraft, draft]);
|
const hasUnsavedChanges = useMemo(() => draftSignature(draft) !== draftSignature(baselineDraft), [baselineDraft, draft]);
|
||||||
const draftAccessState = customerAccessState(draft.status, draft.menuKeys.length, draft.vehicleGrants.length);
|
const draftAccessState = customerAccessState(draft.status, draft.menuKeys.length, draft.vehicleGrants.length);
|
||||||
useSideSheetA11y(mobileFiltersOpen, '.v2-user-mobile-filter-sidesheet', 'v2-user-mobile-filters', '客户账号筛选', '关闭客户账号筛选');
|
useSideSheetA11y(mobileFiltersOpen, '.v2-user-mobile-filter-sidesheet', 'v2-user-mobile-filters', '客户账号筛选', '关闭客户账号筛选');
|
||||||
useSideSheetA11y(editorVisible, '.v2-user-editor-sidesheet', 'v2-user-editor-sheet', '客户账号详情', '关闭账号详情');
|
|
||||||
useSideSheetA11y(Boolean(editingGrant), '.v2-user-grant-sidesheet', 'v2-user-grant-window', '车辆授权有效期', '关闭车辆授权有效期');
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!creating && selected) {
|
if (!creating && selected) {
|
||||||
@@ -514,29 +518,33 @@ export default function UsersPage() {
|
|||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
<SideSheet
|
<WorkspaceSideSheet
|
||||||
className="v2-user-editor-sidesheet"
|
className="v2-user-editor-sidesheet"
|
||||||
|
variant="editor"
|
||||||
visible={editorVisible}
|
visible={editorVisible}
|
||||||
width={mobileLayout ? '100%' : 'min(840px, 100vw)'}
|
width={mobileLayout ? '100%' : 'min(840px, 100vw)'}
|
||||||
aria-label="客户账号详情"
|
ariaLabel="客户账号详情"
|
||||||
title={<div className="v2-user-editor-sheet-title">
|
closeLabel="关闭账号详情"
|
||||||
<span><strong>{creating ? '创建客户账号' : selected?.displayName}</strong>{creating ? <small>设置登录身份和最小必要权限</small> : <span className="v2-user-editor-context" aria-label="账号权限概览">
|
title={creating ? '创建客户账号' : selected?.displayName || '客户账号'}
|
||||||
<span className="is-account">@{selected?.username}</span>
|
description={creating ? '设置登录身份和最小必要权限' : `@${selected?.username || '—'} · 最近登录 ${formatTime(selected?.lastLoginAt)}`}
|
||||||
<span>菜单 <b>{draft.menuKeys.length}</b></span>
|
badge={draftAccessState.label}
|
||||||
<span>车辆 <b>{draft.vehicleGrants.length}</b></span>
|
badgeColor={accessBadgeColor(draftAccessState.color)}
|
||||||
<span className="v2-user-editor-last-login">最近登录 <b>{formatTime(selected?.lastLoginAt)}</b></span>
|
summaryItems={[
|
||||||
<Tag className="v2-user-editor-access-tag" color={draftAccessState.color} type="light" size="small">{draftAccessState.label}</Tag>
|
{ label: '登录账号', value: draft.username ? `@${draft.username}` : '待设置', detail: creating ? '创建后不可修改' : '登录身份', tone: 'primary' },
|
||||||
</span>}</span>
|
{ label: '权限范围', value: `${draft.menuKeys.length} 菜单 · ${draft.vehicleGrants.length} 辆`, detail: '最小必要权限', tone: draftAccessState.attention ? 'warning' : 'success' },
|
||||||
<label className="v2-user-status"><Switch aria-label={draft.status === 'enabled' ? '账号启用' : '账号停用'} checked={draft.status === 'enabled'} onChange={(checked) => setDraft((value) => ({ ...value, status: checked ? 'enabled' : 'disabled' }))} /><span>{draft.status === 'enabled' ? '账号启用' : '账号停用'}</span></label>
|
{
|
||||||
</div>}
|
label: '账号状态',
|
||||||
|
value: <span className="v2-user-editor-status-summary"><Switch aria-label={draft.status === 'enabled' ? '账号启用' : '账号停用'} checked={draft.status === 'enabled'} onChange={(checked) => setDraft((value) => ({ ...value, status: checked ? 'enabled' : 'disabled' }))} /><span>{draft.status === 'enabled' ? '启用' : '停用'}</span></span>,
|
||||||
|
detail: '保存后最多 30 秒生效',
|
||||||
|
tone: draft.status === 'enabled' ? 'success' : 'neutral'
|
||||||
|
}
|
||||||
|
]}
|
||||||
onCancel={requestCloseEditor}
|
onCancel={requestCloseEditor}
|
||||||
footer={<div className="v2-user-editor-sheet-footer">
|
footerNote={<span className="v2-user-save-state" role="status">
|
||||||
<span className="v2-user-save-state" role="status">
|
|
||||||
<Tag color={save.isError ? 'red' : hasUnsavedChanges ? 'amber' : 'green'} type="light" size="small">{save.isError ? '保存失败' : hasUnsavedChanges ? '待保存' : '已同步'}</Tag>
|
<Tag color={save.isError ? 'red' : hasUnsavedChanges ? 'amber' : 'green'} type="light" size="small">{save.isError ? '保存失败' : hasUnsavedChanges ? '待保存' : '已同步'}</Tag>
|
||||||
<Typography.Text className={`v2-user-feedback${save.isError ? ' is-error' : ''}`} type={save.isError ? 'danger' : 'tertiary'}>{feedback || (hasUnsavedChanges ? '更改仅保存在当前草稿,保存后最多 30 秒生效' : '账号与权限已和服务器同步')}</Typography.Text>
|
<Typography.Text className={`v2-user-feedback${save.isError ? ' is-error' : ''}`} type={save.isError ? 'danger' : 'tertiary'}>{feedback || (hasUnsavedChanges ? '更改仅保存在当前草稿,保存后最多 30 秒生效' : '账号与权限已和服务器同步')}</Typography.Text>
|
||||||
</span>
|
</span>}
|
||||||
<Button theme="solid" htmlType="submit" form="v2-user-editor-form" disabled={save.isPending || !hasUnsavedChanges}>{save.isPending ? '正在保存…' : creating ? '创建账号' : '保存权限'}</Button>
|
primaryAction={{ label: creating ? '创建账号' : '保存权限', onClick: persistDraft, disabled: save.isPending || !hasUnsavedChanges, loading: save.isPending }}
|
||||||
</div>}
|
|
||||||
>
|
>
|
||||||
{editorVisible ? <form id="v2-user-editor-form" className="v2-user-editor-form" onSubmit={submit}>
|
{editorVisible ? <form id="v2-user-editor-form" className="v2-user-editor-form" onSubmit={submit}>
|
||||||
<Tabs className="v2-user-editor-tabs" activeKey={activeSection} onChange={(key) => setActiveSection(String(key) as EditorSection)}>
|
<Tabs className="v2-user-editor-tabs" activeKey={activeSection} onChange={(key) => setActiveSection(String(key) as EditorSection)}>
|
||||||
@@ -680,25 +688,39 @@ export default function UsersPage() {
|
|||||||
</Tabs.TabPane>
|
</Tabs.TabPane>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</form> : null}
|
</form> : null}
|
||||||
</SideSheet>
|
</WorkspaceSideSheet>
|
||||||
<SideSheet
|
<WorkspaceSideSheet
|
||||||
className="v2-user-grant-sidesheet"
|
className="v2-user-grant-sidesheet"
|
||||||
|
variant="config"
|
||||||
visible={Boolean(editingGrant)}
|
visible={Boolean(editingGrant)}
|
||||||
|
placement={mobileLayout ? 'bottom' : 'right'}
|
||||||
width={420}
|
width={420}
|
||||||
aria-label="车辆授权有效期"
|
height={mobileLayout ? 'min(82dvh, 680px)' : undefined}
|
||||||
title={<div className="v2-user-grant-sheet-title"><strong>调整车辆有效期</strong><span>{editingGrant ? `${editingGrantPlate || '未登记车牌'} · ${editingGrant.vin}` : '车辆授权时间窗口'}</span></div>}
|
ariaLabel="车辆授权有效期"
|
||||||
|
closeLabel="关闭车辆授权有效期"
|
||||||
|
title="车辆授权有效期"
|
||||||
|
description={editingGrant ? `${editingGrantPlate || '未登记车牌'} · ${editingGrant.vin}` : '设置车辆可访问时间窗口'}
|
||||||
|
badge={editingGrant?.validTo ? '定时停用' : '持续有效'}
|
||||||
|
badgeColor={editingGrant?.validTo ? 'orange' : 'green'}
|
||||||
|
summaryItems={editingGrant ? [
|
||||||
|
{ label: '车牌', value: editingGrantPlate || '未登记车牌', tone: 'primary' },
|
||||||
|
{ label: '启用', value: formatGrantTime(editingGrant.validFrom), detail: '授权开始' },
|
||||||
|
{ label: '停用', value: editingGrant.validTo ? formatGrantTime(editingGrant.validTo) : '持续有效', detail: editingGrant.validTo ? '授权结束' : '未设置结束时间', tone: editingGrant.validTo ? 'warning' : 'success' }
|
||||||
|
] : []}
|
||||||
onCancel={() => setEditingGrantVIN('')}
|
onCancel={() => setEditingGrantVIN('')}
|
||||||
footer={<div className="v2-user-grant-sheet-footer"><Typography.Text type="tertiary">完成后仍需保存账号权限才会生效</Typography.Text><Button theme="solid" disabled={grantWindowInvalid} onClick={() => setEditingGrantVIN('')}>完成</Button></div>}
|
footerNote="完成后仍需保存账号权限才会生效"
|
||||||
|
primaryAction={{ label: '完成', onClick: () => setEditingGrantVIN(''), disabled: grantWindowInvalid }}
|
||||||
>
|
>
|
||||||
{editingGrant ? <div className="v2-user-grant-form">
|
{editingGrant ? <div className="v2-user-grant-form">
|
||||||
<Card className="v2-user-grant-summary" bodyStyle={{ padding: 0 }}>
|
<div className="v2-user-grant-field-group" role="group" aria-labelledby="v2-user-grant-window-heading">
|
||||||
<span><small>车牌</small><strong>{editingGrantPlate || '未登记车牌'}</strong></span>
|
<header><span><strong id="v2-user-grant-window-heading">访问时间窗口</strong><small>只在授权区间内开放该车数据</small></span><Tag color="blue" type="light" size="small">上海时间</Tag></header>
|
||||||
<span><small>VIN</small><strong>{editingGrant.vin}</strong></span>
|
<div>
|
||||||
</Card>
|
<label><span>启用时间</span><Input aria-label={`${editingGrantPlate || editingGrant.vin} 启用时间`} type="datetime-local" required value={editingGrant.validFrom} onChange={(value) => updateGrant(editingGrant.vin, { validFrom: value })} /></label>
|
||||||
<label><span>启用时间</span><Input aria-label={`${editingGrantPlate || editingGrant.vin} 启用时间`} type="datetime-local" required value={editingGrant.validFrom} onChange={(value) => updateGrant(editingGrant.vin, { validFrom: value })} /></label>
|
<label><span>停用时间(可选)</span><Input aria-label={`${editingGrantPlate || editingGrant.vin} 停用时间`} type="datetime-local" min={editingGrant.validFrom} value={editingGrant.validTo} onChange={(value) => updateGrant(editingGrant.vin, { validTo: value })} /></label>
|
||||||
<label><span>停用时间(可选)</span><Input aria-label={`${editingGrantPlate || editingGrant.vin} 停用时间`} type="datetime-local" min={editingGrant.validFrom} value={editingGrant.validTo} onChange={(value) => updateGrant(editingGrant.vin, { validTo: value })} /></label>
|
</div>
|
||||||
|
</div>
|
||||||
{grantWindowInvalid ? <p role="alert">请设置启用时间,并确保停用时间晚于启用时间。</p> : <p>不设置停用时间时,车辆授权将持续有效。</p>}
|
{grantWindowInvalid ? <p role="alert">请设置启用时间,并确保停用时间晚于启用时间。</p> : <p>不设置停用时间时,车辆授权将持续有效。</p>}
|
||||||
</div> : null}
|
</div> : null}
|
||||||
</SideSheet>
|
</WorkspaceSideSheet>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -263,7 +263,12 @@ describe('V2 production entry', () => {
|
|||||||
expect(corePageSources.UsersPage).toContain('<Card');
|
expect(corePageSources.UsersPage).toContain('<Card');
|
||||||
expect(corePageSources.UsersPage).toContain('<Card className="v2-user-list"');
|
expect(corePageSources.UsersPage).toContain('<Card className="v2-user-list"');
|
||||||
expect(corePageSources.UsersPage).toContain('className="v2-user-editor-sidesheet"');
|
expect(corePageSources.UsersPage).toContain('className="v2-user-editor-sidesheet"');
|
||||||
expect(corePageSources.UsersPage).toContain('useSideSheetA11y(editorVisible');
|
expect(corePageSources.UsersPage).toContain("from '../shared/WorkspaceSideSheet'");
|
||||||
|
expect(corePageSources.UsersPage).toContain('<WorkspaceSideSheet\n className="v2-user-editor-sidesheet"');
|
||||||
|
expect(corePageSources.UsersPage).toContain('<WorkspaceSideSheet\n className="v2-user-grant-sidesheet"');
|
||||||
|
expect(corePageSources.UsersPage).toContain('variant="editor"');
|
||||||
|
expect(corePageSources.UsersPage).toContain('variant="config"');
|
||||||
|
expect(corePageSources.UsersPage).not.toContain('useSideSheetA11y(editorVisible');
|
||||||
expect(corePageSources.UsersPage).toContain('<List');
|
expect(corePageSources.UsersPage).toContain('<List');
|
||||||
expect(corePageSources.UsersPage).toContain('<List.Item');
|
expect(corePageSources.UsersPage).toContain('<List.Item');
|
||||||
expect(corePageSources.UsersPage).toContain('className="v2-user-command-bar"');
|
expect(corePageSources.UsersPage).toContain('className="v2-user-command-bar"');
|
||||||
@@ -273,7 +278,7 @@ describe('V2 production entry', () => {
|
|||||||
expect(corePageSources.UsersPage).toContain('aria-expanded={selectedID === user.id && !creating}');
|
expect(corePageSources.UsersPage).toContain('aria-expanded={selectedID === user.id && !creating}');
|
||||||
expect(corePageSources.UsersPage).toContain('<Tabs className="v2-user-editor-tabs"');
|
expect(corePageSources.UsersPage).toContain('<Tabs className="v2-user-editor-tabs"');
|
||||||
expect(corePageSources.UsersPage).toContain('<Tabs.TabPane');
|
expect(corePageSources.UsersPage).toContain('<Tabs.TabPane');
|
||||||
expect(corePageSources.UsersPage).toContain("'关闭账号详情'");
|
expect(corePageSources.UsersPage).toContain('closeLabel="关闭账号详情"');
|
||||||
expect(corePageSources.UsersPage).toContain('<Card className="v2-user-editor-section v2-user-identity-section"');
|
expect(corePageSources.UsersPage).toContain('<Card className="v2-user-editor-section v2-user-identity-section"');
|
||||||
expect(corePageSources.UsersPage).toContain('<Card className="v2-user-editor-section v2-user-menu-section"');
|
expect(corePageSources.UsersPage).toContain('<Card className="v2-user-editor-section v2-user-menu-section"');
|
||||||
expect(corePageSources.UsersPage).toContain('v2-user-editor-section v2-user-vehicle-section');
|
expect(corePageSources.UsersPage).toContain('v2-user-editor-section v2-user-vehicle-section');
|
||||||
|
|||||||
@@ -21395,3 +21395,225 @@
|
|||||||
grid-column: auto;
|
grid-column: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Semi UI account editor workbenches: the account and grant editors now share
|
||||||
|
* the same title, summary and action hierarchy as the other configuration
|
||||||
|
* surfaces while preserving one focused scroll area.
|
||||||
|
*/
|
||||||
|
.v2-user-editor-sidesheet.v2-workspace-editor-sidesheet .semi-sidesheet-inner {
|
||||||
|
width: min(840px, 100vw) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-editor-sidesheet .v2-workspace-config-summary {
|
||||||
|
min-height: 72px;
|
||||||
|
grid-template-columns: minmax(0, 1.05fr) minmax(0, 1.15fr) minmax(0, .9fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-editor-sidesheet .v2-workspace-config-summary strong {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-editor-status-summary {
|
||||||
|
display: inline-flex;
|
||||||
|
min-width: 0;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-editor-status-summary > span {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-editor-sidesheet .v2-workspace-config-content {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-editor-sidesheet .v2-user-editor-form {
|
||||||
|
width: 100%;
|
||||||
|
flex: 1 1 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-editor-sidesheet .v2-workspace-config-footer > span {
|
||||||
|
display: flex;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-editor-sidesheet .v2-workspace-config-footer > div {
|
||||||
|
min-width: 132px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-editor-sidesheet .v2-workspace-config-footer > div > .semi-button {
|
||||||
|
width: 100%;
|
||||||
|
min-width: 132px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-sidesheet .v2-workspace-config-content {
|
||||||
|
padding: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-sidesheet .v2-workspace-config-summary {
|
||||||
|
grid-template-columns: minmax(0, .85fr) minmax(0, 1.1fr) minmax(0, 1.05fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-sidesheet .v2-workspace-config-summary strong {
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-form {
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-field-group {
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid #dce5ef;
|
||||||
|
border-radius: 11px;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 7px 22px rgba(31, 50, 76, .045);
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-field-group > header {
|
||||||
|
display: flex;
|
||||||
|
min-height: 54px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
border-bottom: 1px solid #e5ebf2;
|
||||||
|
background: linear-gradient(180deg, #fff 0%, #fbfcfe 100%);
|
||||||
|
padding: 10px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-field-group > header > span {
|
||||||
|
display: grid;
|
||||||
|
min-width: 0;
|
||||||
|
gap: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-field-group > header strong {
|
||||||
|
color: #2a4058;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-field-group > header small {
|
||||||
|
color: #8390a2;
|
||||||
|
font-size: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-field-group > header > .semi-tag {
|
||||||
|
min-height: 22px;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
border-radius: 999px;
|
||||||
|
font-size: 8px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-field-group > div {
|
||||||
|
display: grid;
|
||||||
|
gap: 13px;
|
||||||
|
padding: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-field-group label {
|
||||||
|
display: grid;
|
||||||
|
gap: 7px;
|
||||||
|
color: #53677f;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 650;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-field-group label > .semi-input-wrapper {
|
||||||
|
min-height: 42px;
|
||||||
|
border-color: #d5dfeb;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-sidesheet .v2-workspace-config-footer > div {
|
||||||
|
min-width: 96px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 680px) {
|
||||||
|
.v2-user-editor-sidesheet.v2-workspace-editor-sidesheet .semi-sidesheet-header {
|
||||||
|
min-height: 68px;
|
||||||
|
padding: 9px 11px 9px 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-editor-sidesheet .v2-workspace-config-title strong {
|
||||||
|
font-size: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-editor-sidesheet .v2-workspace-config-summary {
|
||||||
|
min-height: 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-editor-sidesheet .v2-workspace-config-summary > span {
|
||||||
|
padding: 7px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-editor-sidesheet .v2-workspace-config-summary strong {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-editor-sidesheet .v2-workspace-config-summary em {
|
||||||
|
font-size: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-editor-status-summary {
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-editor-status-summary > span {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-editor-sidesheet .v2-workspace-config-footer > span {
|
||||||
|
display: flex;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-editor-sidesheet .v2-workspace-config-footer > div {
|
||||||
|
min-width: 0;
|
||||||
|
flex: 1 1 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-editor-sidesheet .v2-workspace-config-footer > div > .semi-button {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-sidesheet.v2-workspace-config-sidesheet.semi-sidesheet-bottom .semi-sidesheet-inner {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-sidesheet .v2-workspace-config-title small {
|
||||||
|
max-width: 245px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-sidesheet .v2-workspace-config-summary {
|
||||||
|
min-height: 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-sidesheet .v2-workspace-config-summary > span {
|
||||||
|
padding: 7px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-sidesheet .v2-workspace-config-summary strong {
|
||||||
|
font-size: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-sidesheet .v2-workspace-config-content {
|
||||||
|
padding: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-field-group > header {
|
||||||
|
min-height: 48px;
|
||||||
|
padding: 8px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v2-user-grant-field-group > div {
|
||||||
|
gap: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user