refine Semi UI account workspace

This commit is contained in:
lingniu
2026-07-18 10:30:28 +08:00
parent 41b5c41998
commit 3cd19b276d
4 changed files with 458 additions and 65 deletions

View File

@@ -256,75 +256,83 @@ export default function UsersPage() {
};
return <div className="v2-user-admin">
<WorkspaceCommandBar
className="v2-user-command-bar"
ariaLabel="账号管理操作"
title="客户访问治理"
description="菜单与车辆按最小权限开放,变更最多 30 秒生效"
status={`${customers.length} 个客户账号`}
meta={<Typography.Text type="tertiary"> · </Typography.Text>}
actions={<Button theme="solid" icon={<IconPlus />} aria-label="新建客户账号" onClick={startCreate}></Button>}
/>
<WorkspaceFilterPanel
className="v2-user-filter-panel"
title="账号范围"
description="按客户名称、登录账号、客户标识与启停状态查找"
mobileSummary={`${customerStatus === 'all' ? '全部状态' : customerStatus === 'enabled' ? '启用账号' : '停用账号'}${customerKeyword.trim() ? ` · ${customerKeyword.trim()}` : ''}`}
expanded={!filtersCollapsed}
status={users.isPending ? '正在读取账号' : `${visibleCustomers.length} / ${customers.length} 个账号`}
statusColor={customerKeyword.trim() || customerStatus !== 'all' ? 'blue' : 'grey'}
collapsedLabel="修改"
onToggle={() => setFiltersCollapsed((value) => !value)}
>
<div className={`v2-user-filter-form${filtersCollapsed ? ' is-mobile-collapsed' : ''}`}>
<label className="v2-user-filter-keyword">
<span></span>
<Input className="v2-user-list-search" aria-label="搜索客户账号" prefix={<IconSearch />} showClear value={customerKeyword} onChange={setCustomerKeyword} placeholder="搜索名称、账号或客户标识" />
</label>
<label>
<span id="v2-user-status-filter-label"></span>
<Select
aria-labelledby="v2-user-status-filter-label"
value={customerStatus}
onChange={(value) => setCustomerStatus(String(value) as typeof customerStatus)}
optionList={[
{ value: 'all', label: '全部状态' },
{ value: 'enabled', label: '启用账号' },
{ value: 'disabled', label: '用账号' }
]}
/>
</label>
<Button
className="v2-user-filter-reset"
theme="light"
type="tertiary"
icon={<IconRefresh />}
aria-label="清空账号筛选"
disabled={!customerKeyword.trim() && customerStatus === 'all'}
onClick={() => {
setCustomerKeyword('');
setCustomerStatus('all');
}}
>
</Button>
</div>
</WorkspaceFilterPanel>
<div className="v2-user-discovery-shell">
<WorkspaceCommandBar
className="v2-user-command-bar"
ariaLabel="账号管理操作"
title="客户访问治理"
description="菜单与车辆按最小权限开放,变更最多 30 秒生效"
status={`${customers.length} 个客户账号`}
meta={<Typography.Text type="tertiary"> · </Typography.Text>}
actions={<Button theme="solid" icon={<IconPlus />} aria-label="新建客户账号" onClick={startCreate}></Button>}
/>
<WorkspaceFilterPanel
className="v2-user-filter-panel"
title="账号范围"
description="按客户名称、登录账号、客户标识与启停状态查找"
mobileSummary={`${customerStatus === 'all' ? '全部状态' : customerStatus === 'enabled' ? '启用账号' : '停用账号'}${customerKeyword.trim() ? ` · ${customerKeyword.trim()}` : ''}`}
expanded={!filtersCollapsed}
status={users.isPending ? '正在读取账号' : `${visibleCustomers.length} / ${customers.length} 个账号`}
statusColor={customerKeyword.trim() || customerStatus !== 'all' ? 'blue' : 'grey'}
collapsedLabel="修改"
onToggle={() => setFiltersCollapsed((value) => !value)}
>
<div className={`v2-user-filter-form${filtersCollapsed ? ' is-mobile-collapsed' : ''}`}>
<label className="v2-user-filter-keyword">
<span></span>
<Input className="v2-user-list-search" aria-label="搜索客户账号" prefix={<IconSearch />} showClear value={customerKeyword} onChange={setCustomerKeyword} placeholder="搜索名称、账号或客户标识" />
</label>
<label>
<span id="v2-user-status-filter-label"></span>
<Select
aria-labelledby="v2-user-status-filter-label"
value={customerStatus}
onChange={(value) => setCustomerStatus(String(value) as typeof customerStatus)}
optionList={[
{ value: 'all', label: '全部状态' },
{ value: 'enabled', label: '用账号' },
{ value: 'disabled', label: '停用账号' }
]}
/>
</label>
<Button
className="v2-user-filter-reset"
theme="light"
type="tertiary"
icon={<IconRefresh />}
aria-label="清空账号筛选"
disabled={!customerKeyword.trim() && customerStatus === 'all'}
onClick={() => {
setCustomerKeyword('');
setCustomerStatus('all');
}}
>
</Button>
</div>
</WorkspaceFilterPanel>
</div>
<div className={`v2-user-admin-grid${creating || selected ? ' is-editor-open' : ''}`}>
<Card className="v2-user-list" bodyStyle={{ padding: 0 }}>
<WorkspacePanelHeader
className="v2-user-directory-header"
title="客户权限目录"
description="当前范围内的账号、菜单与车辆授权摘要"
meta={<Tag color={visibleCustomers.length === customers.length ? 'grey' : 'blue'} type="light" size="small">{visibleCustomers.length} / {customers.length} </Tag>}
meta={<span className="v2-user-directory-summary">
<Tag color={visibleCustomers.length === customers.length ? 'grey' : 'blue'} type="light" size="small">{visibleCustomers.length} / {customers.length} </Tag>
<Typography.Text type="tertiary"> {enabledCustomers}</Typography.Text>
<Typography.Text type="tertiary"> {grantedVehicles}</Typography.Text>
</span>}
/>
<div className="v2-user-directory-body">
<div className="v2-user-directory-metrics" aria-label="客户账号概览">
<span className="is-primary"><small></small><strong>{enabledCustomers}</strong></span>
<span><small></small><strong>{customers.length - enabledCustomers}</strong></span>
<span><small></small><strong>{grantedVehicles}</strong></span>
</div>
{users.isPending ? <PanelLoading className="v2-user-list-loading" title="正在加载客户账号" description="账号目录和授权摘要就绪后会自动显示。" /> : customers.length === 0 ? <PanelEmpty className="v2-user-list-empty" title="还没有客户账号" description="创建客户账号后,可在这里配置菜单和车辆范围。" action={<Button theme="solid" onClick={startCreate}></Button>} /> : <>
{visibleCustomers.length ? <div className="v2-user-directory-columns" role="row" aria-label="客户账号目录列">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div> : null}
<div className="v2-customer-list-scroll" role="region" aria-label="客户账号目录,可上下滚动" tabIndex={0}>
<List
className="v2-customer-list"
@@ -341,9 +349,9 @@ export default function UsersPage() {
onClick={() => selectCustomer(user)}
>
<Avatar className="v2-user-avatar" color={user.status === 'enabled' ? 'light-blue' : 'grey'} shape="square" size="small">{user.displayName.slice(0, 1)}</Avatar>
<span className="v2-user-list-identity"><b>{user.displayName}</b><small>@{user.username}</small></span>
<span className="v2-user-list-facts"><small></small><b>{user.menuKeys.length} </b></span>
<span className="v2-user-list-facts"><small></small><b>{user.vehicles.length} </b></span>
<span className="v2-user-list-identity"><b>{user.displayName}</b><small>@{user.username}{user.customerRef ? ` · ${user.customerRef}` : ''}</small></span>
<span className="v2-user-list-facts is-menu"><small></small><b>{user.menuKeys.length} </b></span>
<span className="v2-user-list-facts is-vehicle"><small></small><b>{user.vehicles.length} </b></span>
<span className="v2-user-list-facts is-login"><small></small><b>{formatTime(user.lastLoginAt)}</b></span>
<span className="v2-user-list-trailing"><Tag className={`v2-user-status-tag is-${user.status}`} color={user.status === 'enabled' ? 'green' : 'grey'} type="light" size="small">{user.status === 'enabled' ? '启用' : '停用'}</Tag><IconChevronRight /></span>
</Button>