feat(admin): store detail edit with login phone sync; tighten HQ UI
CI / verify (pull_request) Has been cancelled
CI / verify (pull_request) Has been cancelled
HQ store update now syncs store_account.phone for shop login; expand editable store fields. System version only for SUPER_ADMIN; permissions checklist layout polish. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -5,7 +5,6 @@ import {
|
||||
Card,
|
||||
Checkbox,
|
||||
Col,
|
||||
Divider,
|
||||
Form,
|
||||
Row,
|
||||
Select,
|
||||
@@ -36,6 +35,13 @@ const ROLE_LABELS = Object.fromEntries(HQ_ADMIN_ROLES.map((r) => [r.value, r.lab
|
||||
|
||||
const CATALOG_GROUPS = [...new Set(HQ_PERMISSION_CATALOG.map((p) => p.group ?? '其他'))];
|
||||
|
||||
function groupColSpan(itemCount: number): number {
|
||||
if (itemCount <= 2) return 12;
|
||||
if (itemCount === 3) return 8;
|
||||
if (itemCount === 4) return 6;
|
||||
return 8;
|
||||
}
|
||||
|
||||
function PermissionChecklist({
|
||||
value,
|
||||
onChange,
|
||||
@@ -54,19 +60,39 @@ function PermissionChecklist({
|
||||
>
|
||||
{CATALOG_GROUPS.map((group) => {
|
||||
const items = HQ_PERMISSION_CATALOG.filter((p) => (p.group ?? '其他') === group);
|
||||
const span = groupColSpan(items.length);
|
||||
const compact = items.length <= 3;
|
||||
return (
|
||||
<div key={group} style={{ marginBottom: 16 }}>
|
||||
<Typography.Text strong style={{ display: 'block', marginBottom: 8 }}>
|
||||
<div
|
||||
key={group}
|
||||
style={{
|
||||
marginBottom: 16,
|
||||
padding: '12px 16px',
|
||||
background: '#fafafa',
|
||||
borderRadius: 8,
|
||||
border: '1px solid #f0f0f0',
|
||||
}}
|
||||
>
|
||||
<Typography.Text strong style={{ display: 'block', marginBottom: 10 }}>
|
||||
{group}
|
||||
</Typography.Text>
|
||||
<Row gutter={[8, 8]}>
|
||||
{items.map((item) => (
|
||||
<Col key={item.key} span={8}>
|
||||
<Checkbox value={item.key}>{item.label}</Checkbox>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
<Divider style={{ margin: '12px 0 0' }} />
|
||||
{compact ? (
|
||||
<Space size={[24, 8]} wrap>
|
||||
{items.map((item) => (
|
||||
<Checkbox key={item.key} value={item.key}>
|
||||
{item.label}
|
||||
</Checkbox>
|
||||
))}
|
||||
</Space>
|
||||
) : (
|
||||
<Row gutter={[12, 10]}>
|
||||
{items.map((item) => (
|
||||
<Col key={item.key} xs={24} sm={12} md={span}>
|
||||
<Checkbox value={item.key}>{item.label}</Checkbox>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
@@ -88,6 +114,12 @@ export default function HqPermissionsPage() {
|
||||
const [accountLoading, setAccountLoading] = useState(false);
|
||||
const [accountSaving, setAccountSaving] = useState(false);
|
||||
|
||||
const selectedAccount = useMemo(
|
||||
() => accounts.find((a) => a.id === accountId),
|
||||
[accounts, accountId],
|
||||
);
|
||||
const selectedIsSuperAdmin = selectedAccount?.adminRole === 'SUPER_ADMIN';
|
||||
|
||||
const previewEffectiveKeys = useMemo(
|
||||
() => [...new Set([...roleInheritedKeys, ...accountKeys])],
|
||||
[roleInheritedKeys, accountKeys],
|
||||
@@ -243,32 +275,57 @@ export default function HqPermissionsPage() {
|
||||
<Alert type="info" showIcon message="请先选择要配置的 HQ 账户" />
|
||||
) : (
|
||||
<>
|
||||
<Space wrap style={{ marginBottom: 12 }}>
|
||||
<span>角色继承:</span>
|
||||
{roleInheritedKeys.map((key) => {
|
||||
const item = HQ_PERMISSION_CATALOG.find((p) => p.key === key);
|
||||
return (
|
||||
<Tag key={key} color="blue">
|
||||
{item?.group ? `${item.group}·${item.label}` : item?.label || key}
|
||||
</Tag>
|
||||
);
|
||||
})}
|
||||
</Space>
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
<span style={{ marginRight: 8 }}>角色继承:</span>
|
||||
{selectedIsSuperAdmin ? (
|
||||
<Tag color="blue">超级管理员基础权限(不含危险操作)</Tag>
|
||||
) : (
|
||||
<Space wrap size={[4, 4]}>
|
||||
{roleInheritedKeys.map((key) => {
|
||||
const item = HQ_PERMISSION_CATALOG.find((p) => p.key === key);
|
||||
return (
|
||||
<Tag key={key} color="blue">
|
||||
{item?.label || key}
|
||||
</Tag>
|
||||
);
|
||||
})}
|
||||
{!roleInheritedKeys.length ? (
|
||||
<Typography.Text type="secondary">无</Typography.Text>
|
||||
) : null}
|
||||
</Space>
|
||||
)}
|
||||
</div>
|
||||
<Typography.Paragraph type="secondary">
|
||||
下方勾选为用户专属追加权限(保存后与角色权限合并生效)。危险操作(删除用户/订单/城市)默认不授予,需在此勾选。
|
||||
</Typography.Paragraph>
|
||||
<PermissionChecklist value={accountKeys} onChange={setAccountKeys} />
|
||||
<Space wrap style={{ marginTop: 12 }}>
|
||||
<span>合并生效:</span>
|
||||
{previewEffectiveKeys.map((key) => {
|
||||
const item = HQ_PERMISSION_CATALOG.find((p) => p.key === (key as HqPermissionKey));
|
||||
return (
|
||||
<Tag key={key}>
|
||||
{item?.group ? `${item.group}·${item.label}` : item?.label || key}
|
||||
</Tag>
|
||||
);
|
||||
})}
|
||||
</Space>
|
||||
<div style={{ marginTop: 12 }}>
|
||||
<span style={{ marginRight: 8 }}>合并生效:</span>
|
||||
{selectedIsSuperAdmin ? (
|
||||
<Space wrap size={[4, 4]}>
|
||||
<Tag>基础权限(全部)</Tag>
|
||||
{accountKeys.map((key) => {
|
||||
const item = HQ_PERMISSION_CATALOG.find((p) => p.key === (key as HqPermissionKey));
|
||||
return (
|
||||
<Tag key={key} color="orange">
|
||||
{item?.label || key}
|
||||
</Tag>
|
||||
);
|
||||
})}
|
||||
</Space>
|
||||
) : (
|
||||
<Space wrap size={[4, 4]}>
|
||||
{previewEffectiveKeys.map((key) => {
|
||||
const item = HQ_PERMISSION_CATALOG.find((p) => p.key === (key as HqPermissionKey));
|
||||
return (
|
||||
<Tag key={key}>
|
||||
{item?.label || key}
|
||||
</Tag>
|
||||
);
|
||||
})}
|
||||
</Space>
|
||||
)}
|
||||
</div>
|
||||
<div style={{ marginTop: 16 }}>
|
||||
<Button type="primary" loading={accountSaving} onClick={() => void saveAccountPermissions()}>
|
||||
保存用户权限
|
||||
|
||||
Reference in New Issue
Block a user