feat(admin): 平台商户成员管理改用抽屉,消除商户视角切换与全局状态污染

- 交互重构:在「平台商户」与「平台账号」点击成员管理时,不再跳转路由或改写 localStorage.merchant_id,改为滑出 MerchantMembersDrawer 抽屉
- 抽屉能力:支持查看指定商户成员列表、新增成员(新建账号或关联已有账号)、修改角色与启用状态、移除成员
- 顶栏清理:彻底移除顶栏右上角的「当前商户:xxx」标签与「退出商户视角」按钮,超管登录自动清理任何残留上下文
- 后端补齐:新增平台专属 /api/platform/merchants/:id/members 与 roles 接口,平台操作不再依赖 X-Merchant-ID
- 验证:tsc -b && vite build 成功;全量 go test ./... 包含路由与鉴权回归测试 100% 通过
This commit is contained in:
yml2213
2026-10-06 21:13:37 +08:00
parent 3ec7febb8c
commit 8cc5d42d53
8 changed files with 562 additions and 38 deletions
+16 -4
View File
@@ -1,5 +1,4 @@
import { useCallback, useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import {
Button,
Checkbox,
@@ -23,6 +22,7 @@ import { platformApi } from '../api'
import type { Merchant, MerchantOwnerAccount, PageResult, ProductCatalogItem, WalletAccount } from '../types'
import { formatDateTime } from '../utils/time'
import { PageHeader } from '../components/PageHeader'
import { MerchantMembersDrawer } from '../components/MerchantMembersDrawer'
const featureOptions = [
{ value: 'products', label: '商品' },
@@ -33,9 +33,10 @@ const featureOptions = [
]
export default function PlatformMerchants() {
const navigate = useNavigate()
const [data, setData] = useState<PageResult<Merchant>>({ list: [], total: 0, page: 1, size: 10 })
const [loading, setLoading] = useState(false)
const [membersDrawerOpen, setMembersDrawerOpen] = useState(false)
const [membersDrawerMerchant, setMembersDrawerMerchant] = useState<Merchant | null>(null)
const [createOpen, setCreateOpen] = useState(false)
const [settingsOpen, setSettingsOpen] = useState(false)
const [assignOpen, setAssignOpen] = useState(false)
@@ -344,8 +345,8 @@ export default function PlatformMerchants() {
type="link"
size="small"
onClick={() => {
localStorage.setItem('merchant_id', String(record.id))
navigate('/merchant-members')
setMembersDrawerMerchant(record)
setMembersDrawerOpen(true)
}}
>
成员
@@ -752,6 +753,17 @@ export default function PlatformMerchants() {
</Typography.Text>
</Form>
</Modal>
<MerchantMembersDrawer
open={membersDrawerOpen}
merchantId={membersDrawerMerchant?.id ?? null}
merchantName={membersDrawerMerchant?.name}
merchantCode={membersDrawerMerchant?.code}
onClose={() => {
setMembersDrawerOpen(false)
setMembersDrawerMerchant(null)
}}
/>
</div>
)
}
+29 -7
View File
@@ -8,7 +8,7 @@ import type { MerchantMember, MerchantMemberGroup, PageResult, User } from '../t
import { formatDateTime } from '../utils/time'
import { useAuth } from '../store/authContext'
import { roleText } from './merchantCenterUtils'
import { useNavigate } from 'react-router-dom'
import { MerchantMembersDrawer } from '../components/MerchantMembersDrawer'
type AdminFormValues = {
username: string
@@ -19,7 +19,9 @@ type AdminFormValues = {
export default function PlatformUsers() {
const { user: currentUser } = useAuth()
const navigate = useNavigate()
const [drawerOpen, setDrawerOpen] = useState(false)
const [selectedMerchantId, setSelectedMerchantId] = useState<number | null>(null)
const [selectedMerchantName, setSelectedMerchantName] = useState<string>('')
const [tab, setTab] = useState('admins')
const [admins, setAdmins] = useState<PageResult<User>>({ list: [], total: 0, page: 1, size: 20 })
const [merchantAccounts, setMerchantAccounts] = useState<PageResult<MerchantMemberGroup>>({ list: [], total: 0, page: 1, size: 20 })
@@ -169,12 +171,21 @@ export default function PlatformUsers() {
{
title: '操作',
width: 160,
render: (_, record) => <Button type="link" size="small" onClick={() => {
localStorage.setItem('merchant_id', String(record.merchant_id))
navigate('/merchant-members')
}}>管理商户成员</Button>,
render: (_, record) => (
<Button
type="link"
size="small"
onClick={() => {
setSelectedMerchantId(record.merchant_id)
setSelectedMerchantName(record.merchant?.name || record.merchant?.code || `商户 #${record.merchant_id}`)
setDrawerOpen(true)
}}
>
管理商户成员
</Button>
),
},
], [navigate])
], [])
const items = useMemo(() => [
{
@@ -236,6 +247,17 @@ export default function PlatformUsers() {
{editingAdmin && <Form.Item label="账号状态" name="status" valuePropName="checked"><Switch checkedChildren="启用" unCheckedChildren="停用" /></Form.Item>}
</Form>
</Modal>
<MerchantMembersDrawer
open={drawerOpen}
merchantId={selectedMerchantId}
merchantName={selectedMerchantName}
onClose={() => {
setDrawerOpen(false)
setSelectedMerchantId(null)
setSelectedMerchantName('')
}}
/>
</div>
)
}