重构主导航栏父子菜单选中态与树形分支样式
This commit is contained in:
+26
-14
@@ -254,8 +254,8 @@ a:hover {
|
|||||||
.app-sidebar__item {
|
.app-sidebar__item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
min-height: 44px;
|
min-height: 40px;
|
||||||
padding: 10px 14px;
|
padding: 8px 12px;
|
||||||
border-radius: var(--radius-md);
|
border-radius: var(--radius-md);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@@ -263,7 +263,17 @@ a:hover {
|
|||||||
|
|
||||||
.app-sidebar__item:hover {
|
.app-sidebar__item:hover {
|
||||||
color: #2563eb;
|
color: #2563eb;
|
||||||
background: #eff6ff;
|
background: #f1f5f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-sidebar__item--parent-active {
|
||||||
|
color: #2563eb !important;
|
||||||
|
font-weight: 700;
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-sidebar__item--parent-active .app-sidebar__icon {
|
||||||
|
color: #2563eb !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-sidebar__item--active {
|
.app-sidebar__item--active {
|
||||||
@@ -328,28 +338,30 @@ a:hover {
|
|||||||
.app-sidebar__children {
|
.app-sidebar__children {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 4px;
|
gap: 2px;
|
||||||
margin-top: 4px;
|
margin: 2px 0 4px 22px;
|
||||||
padding-left: 36px;
|
padding-left: 10px;
|
||||||
|
border-left: 1.5px solid #e2e8f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-sidebar__child {
|
.app-sidebar__child {
|
||||||
min-height: 38px;
|
min-height: 34px;
|
||||||
padding: 8px 12px;
|
padding: 6px 12px;
|
||||||
border-radius: var(--radius-sm);
|
border-radius: 6px;
|
||||||
font-size: 13.5px;
|
font-size: 13px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
color: #64748b;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-sidebar__child:hover:not(:disabled) {
|
.app-sidebar__child:hover:not(:disabled) {
|
||||||
color: #2563eb;
|
color: #2563eb;
|
||||||
background: #eff6ff;
|
background: #f1f5f9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-sidebar__child--active {
|
.app-sidebar__child--active {
|
||||||
color: #1d4ed8 !important;
|
color: #2563eb !important;
|
||||||
background: #dbeafe !important;
|
background: #eff6ff !important;
|
||||||
font-weight: 600;
|
font-weight: 700;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-sidebar--collapsed .app-sidebar__brand {
|
.app-sidebar--collapsed .app-sidebar__brand {
|
||||||
|
|||||||
@@ -258,10 +258,12 @@ export default function MainLayout() {
|
|||||||
const isOpen = openKeys.includes(section.key)
|
const isOpen = openKeys.includes(section.key)
|
||||||
const isSelected = selectedKey === section.key
|
const isSelected = selectedKey === section.key
|
||||||
const hasSelectedChild = section.children?.some((child) => child.key === selectedKey)
|
const hasSelectedChild = section.children?.some((child) => child.key === selectedKey)
|
||||||
|
const isParentActive = hasSelectedChild
|
||||||
|
const isSingleActive = isSelected && !section.children?.length
|
||||||
return (
|
return (
|
||||||
<div className="app-sidebar__group" key={section.key}>
|
<div className="app-sidebar__group" key={section.key}>
|
||||||
<button
|
<button
|
||||||
className={`app-sidebar__item${isSelected || hasSelectedChild ? ' app-sidebar__item--active' : ''}${section.disabled ? ' app-sidebar__item--disabled' : ''}`}
|
className={`app-sidebar__item${isSingleActive ? ' app-sidebar__item--active' : ''}${isParentActive ? ' app-sidebar__item--parent-active' : ''}${section.disabled ? ' app-sidebar__item--disabled' : ''}`}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => toggleSection(section)}
|
onClick={() => toggleSection(section)}
|
||||||
title={collapsed ? section.label : undefined}
|
title={collapsed ? section.label : undefined}
|
||||||
|
|||||||
@@ -14,21 +14,13 @@ import {
|
|||||||
Typography,
|
Typography,
|
||||||
message,
|
message,
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import { GiftOutlined, PlusOutlined, ReloadOutlined, TeamOutlined, WalletOutlined } from '@ant-design/icons'
|
import { GiftOutlined, PlusOutlined, ReloadOutlined, WalletOutlined } from '@ant-design/icons'
|
||||||
import type { ColumnsType } from 'antd/es/table'
|
import type { ColumnsType } from 'antd/es/table'
|
||||||
import { useNavigate } from 'react-router-dom'
|
|
||||||
import { platformApi } from '../api'
|
import { platformApi } from '../api'
|
||||||
import type { Merchant, MerchantMember, PageResult, ProductCatalogItem, WalletAccount } from '../types'
|
import type { Merchant, PageResult, ProductCatalogItem, WalletAccount } from '../types'
|
||||||
import { formatDateTime } from '../utils/time'
|
import { formatDateTime } from '../utils/time'
|
||||||
import { PageHeader } from '../components/PageHeader'
|
import { PageHeader } from '../components/PageHeader'
|
||||||
|
|
||||||
const memberRoleOptions = [
|
|
||||||
{ value: 'owner', label: '负责人' },
|
|
||||||
{ value: 'operator', label: '运营' },
|
|
||||||
{ value: 'finance', label: '财务' },
|
|
||||||
{ value: 'viewer', label: '只读' },
|
|
||||||
]
|
|
||||||
|
|
||||||
const featureOptions = [
|
const featureOptions = [
|
||||||
{ value: 'products', label: '商品' },
|
{ value: 'products', label: '商品' },
|
||||||
{ value: 'orders', label: '订单' },
|
{ value: 'orders', label: '订单' },
|
||||||
@@ -38,12 +30,10 @@ const featureOptions = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
export default function PlatformMerchants() {
|
export default function PlatformMerchants() {
|
||||||
const navigate = useNavigate()
|
|
||||||
const [data, setData] = useState<PageResult<Merchant>>({ list: [], total: 0, page: 1, size: 10 })
|
const [data, setData] = useState<PageResult<Merchant>>({ list: [], total: 0, page: 1, size: 10 })
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [createOpen, setCreateOpen] = useState(false)
|
const [createOpen, setCreateOpen] = useState(false)
|
||||||
const [settingsOpen, setSettingsOpen] = useState(false)
|
const [settingsOpen, setSettingsOpen] = useState(false)
|
||||||
const [memberOpen, setMemberOpen] = useState(false)
|
|
||||||
const [assignOpen, setAssignOpen] = useState(false)
|
const [assignOpen, setAssignOpen] = useState(false)
|
||||||
const [assignLoading, setAssignLoading] = useState(false)
|
const [assignLoading, setAssignLoading] = useState(false)
|
||||||
const [assignSubmitting, setAssignSubmitting] = useState(false)
|
const [assignSubmitting, setAssignSubmitting] = useState(false)
|
||||||
@@ -57,7 +47,6 @@ export default function PlatformMerchants() {
|
|||||||
const [adjustWallet, setAdjustWallet] = useState<WalletAccount | null>(null)
|
const [adjustWallet, setAdjustWallet] = useState<WalletAccount | null>(null)
|
||||||
const [createForm] = Form.useForm()
|
const [createForm] = Form.useForm()
|
||||||
const [settingsForm] = Form.useForm()
|
const [settingsForm] = Form.useForm()
|
||||||
const [memberForm] = Form.useForm()
|
|
||||||
const [adjustForm] = Form.useForm()
|
const [adjustForm] = Form.useForm()
|
||||||
|
|
||||||
const load = useCallback(async (page = data.page, size = data.size) => {
|
const load = useCallback(async (page = data.page, size = data.size) => {
|
||||||
@@ -117,22 +106,6 @@ export default function PlatformMerchants() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const submitMember = async () => {
|
|
||||||
if (!selectedMerchant) return
|
|
||||||
const values = await memberForm.validateFields()
|
|
||||||
try {
|
|
||||||
await platformApi.addMember(selectedMerchant.id, {
|
|
||||||
user_id: values.user_id,
|
|
||||||
role: values.role as MerchantMember['role'],
|
|
||||||
is_default: values.is_default,
|
|
||||||
})
|
|
||||||
message.success('成员已添加')
|
|
||||||
setMemberOpen(false)
|
|
||||||
} catch (e) {
|
|
||||||
message.error(e instanceof Error ? e.message : '添加失败')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const openAdjust = async (record: Merchant) => {
|
const openAdjust = async (record: Merchant) => {
|
||||||
setSelectedMerchant(record)
|
setSelectedMerchant(record)
|
||||||
setAdjustOpen(true)
|
setAdjustOpen(true)
|
||||||
@@ -259,21 +232,10 @@ export default function PlatformMerchants() {
|
|||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
key: 'action',
|
key: 'action',
|
||||||
width: 240,
|
width: 180,
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<Space size={0}>
|
<Space size={0}>
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
size="small"
|
|
||||||
onClick={() => {
|
|
||||||
localStorage.setItem('merchant_id', String(record.id))
|
|
||||||
message.success('当前商户已切换')
|
|
||||||
navigate('/merchant-center')
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
进入
|
|
||||||
</Button>
|
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
size="small"
|
size="small"
|
||||||
@@ -306,19 +268,6 @@ export default function PlatformMerchants() {
|
|||||||
>
|
>
|
||||||
调整积分
|
调整积分
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
size="small"
|
|
||||||
icon={<TeamOutlined />}
|
|
||||||
onClick={() => {
|
|
||||||
setSelectedMerchant(record)
|
|
||||||
memberForm.resetFields()
|
|
||||||
memberForm.setFieldsValue({ role: 'operator', is_default: false })
|
|
||||||
setMemberOpen(true)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
成员
|
|
||||||
</Button>
|
|
||||||
</Space>
|
</Space>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@@ -328,7 +277,7 @@ export default function PlatformMerchants() {
|
|||||||
<div>
|
<div>
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title="平台商户管理"
|
title="平台商户管理"
|
||||||
subtitle="平台管理员维护各分销商户租户、分配商品库、配置手续费费率与授权成员"
|
subtitle="平台管理员维护各分销商户租户、分配商品库、配置手续费费率与积分调整"
|
||||||
breadcrumbs={[{ title: '商户管理' }]}
|
breadcrumbs={[{ title: '商户管理' }]}
|
||||||
extra={
|
extra={
|
||||||
<Space>
|
<Space>
|
||||||
@@ -508,26 +457,6 @@ export default function PlatformMerchants() {
|
|||||||
</Spin>
|
</Spin>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
<Modal
|
|
||||||
title={selectedMerchant ? `添加成员:${selectedMerchant.name}` : '添加成员'}
|
|
||||||
open={memberOpen}
|
|
||||||
onOk={submitMember}
|
|
||||||
onCancel={() => setMemberOpen(false)}
|
|
||||||
destroyOnClose
|
|
||||||
>
|
|
||||||
<Form form={memberForm} layout="vertical" style={{ marginTop: 16 }}>
|
|
||||||
<Form.Item name="user_id" label="用户 ID" rules={[{ required: true }]}>
|
|
||||||
<InputNumber min={1} precision={0} style={{ width: '100%' }} />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item name="role" label="角色" rules={[{ required: true }]}>
|
|
||||||
<Select options={memberRoleOptions} />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item name="is_default" label="默认商户">
|
|
||||||
<Select options={[{ value: true, label: '是' }, { value: false, label: '否' }]} />
|
|
||||||
</Form.Item>
|
|
||||||
</Form>
|
|
||||||
</Modal>
|
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
title={selectedMerchant ? `分配商品:${selectedMerchant.name}` : '分配商品'}
|
title={selectedMerchant ? `分配商品:${selectedMerchant.name}` : '分配商品'}
|
||||||
open={assignOpen}
|
open={assignOpen}
|
||||||
|
|||||||
Reference in New Issue
Block a user