feat:寄卖增加对接客服,页面移动到接单平台
This commit is contained in:
@@ -24,9 +24,6 @@ const AdminFinancePage = lazy(() => import('@/pages/admin/AdminFinancePage'))
|
||||
const AdminFinanceLedgerPage = lazy(() => import('@/pages/admin/AdminFinanceLedgerPage'))
|
||||
const AdminSalesProfitPage = lazy(() => import('@/pages/admin/AdminSalesProfitPage'))
|
||||
const AdminCostCenterPage = lazy(() => import('@/pages/admin/AdminCostCenterPage'))
|
||||
const AdminConsignmentContactsPage = lazy(
|
||||
() => import('@/pages/admin/AdminConsignmentContactsPage'),
|
||||
)
|
||||
const AdminFundPage = lazy(() => import('@/pages/admin/AdminFundPage'))
|
||||
const AdminAuditLogsPage = lazy(() => import('@/pages/admin/AdminAuditLogsPage'))
|
||||
const AdminKuaishouIndustryPage = lazy(() => import('@/pages/admin/AdminKuaishouIndustryPage'))
|
||||
@@ -161,6 +158,11 @@ function AdminApplication() {
|
||||
<Route path="fund" element={<AdminFundPage />} />
|
||||
</Route>
|
||||
<Route path="worker-platform" element={<AdminWorkerPlatformPage />} />
|
||||
{/* 旧「配置 → 对接客服」地址已并入接单平台 tab,书签继续可用。 */}
|
||||
<Route
|
||||
path="consignment-contacts"
|
||||
element={<Navigate to="/admin/worker-platform?tab=consignment-contacts" replace />}
|
||||
/>
|
||||
<Route element={<RequireRole roles={['admin', 'operator', 'support']} />}>
|
||||
<Route path="kuaishou-industry" element={<AdminKuaishouIndustryPage />} />
|
||||
<Route
|
||||
@@ -171,7 +173,6 @@ function AdminApplication() {
|
||||
</Route>
|
||||
<Route element={<RequireRole roles={['admin']} />}>
|
||||
<Route path="users" element={<AdminUsersPage />} />
|
||||
<Route path="consignment-contacts" element={<AdminConsignmentContactsPage />} />
|
||||
<Route path="platform-shops" element={<AdminPlatformShopsPage />} />
|
||||
<Route path="platform-fulfillment" element={<AdminPlatformFulfillmentPage />} />
|
||||
<Route path="audit-logs" element={<AdminAuditLogsPage />} />
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
ApartmentOutlined,
|
||||
BellOutlined,
|
||||
BugOutlined,
|
||||
CustomerServiceOutlined,
|
||||
DashboardOutlined,
|
||||
FileSearchOutlined,
|
||||
LogoutOutlined,
|
||||
@@ -284,11 +283,6 @@ export default function AdminLayout() {
|
||||
label: '配置',
|
||||
children: [
|
||||
{ key: '/admin/users', icon: <TeamOutlined />, label: '后台用户' },
|
||||
{
|
||||
key: '/admin/consignment-contacts',
|
||||
icon: <CustomerServiceOutlined />,
|
||||
label: '对接客服',
|
||||
},
|
||||
{ key: '/admin/platform-shops', icon: <SettingOutlined />, label: '平台配置' },
|
||||
{ key: '/admin/platform-fulfillment', icon: <ShopOutlined />, label: '履约配置' },
|
||||
],
|
||||
@@ -857,7 +851,8 @@ function resolveSelectedKey(pathname: string) {
|
||||
if (pathname.startsWith('/admin/finance')) return '/admin/finance'
|
||||
if (pathname.startsWith('/admin/tasks')) return '/admin/tasks'
|
||||
if (pathname.startsWith('/admin/worker-platform')) return '/admin/worker-platform'
|
||||
if (pathname.startsWith('/admin/consignment-contacts')) return '/admin/consignment-contacts'
|
||||
// 旧「配置 → 对接客服」地址已并入接单平台 tab,保留高亮兼容。
|
||||
if (pathname.startsWith('/admin/consignment-contacts')) return '/admin/worker-platform'
|
||||
if (pathname.startsWith('/admin/kuaishou-industry')) return '/admin/kuaishou-industry'
|
||||
if (pathname === '/admin/platform-shops') return '/admin/platform-shops'
|
||||
return pathname
|
||||
|
||||
@@ -15,6 +15,7 @@ import AfterSalesPanel, { type AfterSalesPanelHandle } from './panels/AfterSales
|
||||
import AnnouncementPanel from './panels/AnnouncementPanel'
|
||||
import CancelRequestsPanel from './panels/CancelRequestsPanel'
|
||||
import CategoriesPanel from './panels/CategoriesPanel'
|
||||
import ConsignmentContactsPanel from './panels/ConsignmentContactsPanel'
|
||||
import ConsignmentInventoryPanel from './panels/ConsignmentInventoryPanel'
|
||||
import ConsignmentSubmissionsPanel from './panels/ConsignmentSubmissionsPanel'
|
||||
import FeedbacksPanel from './panels/FeedbacksPanel'
|
||||
@@ -44,8 +45,10 @@ export default function AdminWorkerPlatformPage() {
|
||||
const isFinance = role === 'finance'
|
||||
const canViewConsignment = hasAdminPermission('consignment.view')
|
||||
const isConsignmentTab =
|
||||
activeTab === 'consignment-inventory' || activeTab === 'consignment-submissions'
|
||||
// 没有 consignment.view 时这两个 tab 不渲染,把 URL/localStorage 里的旧选择也拉回工单页,
|
||||
activeTab === 'consignment-inventory' ||
|
||||
activeTab === 'consignment-submissions' ||
|
||||
activeTab === 'consignment-contacts'
|
||||
// 没有 consignment.view 时这些 tab 不渲染,把 URL/localStorage 里的旧选择也拉回工单页,
|
||||
// 否则会落在一个空的 tab 内容上。
|
||||
const visibleActiveTab = isFinance
|
||||
? 'finance'
|
||||
@@ -113,6 +116,11 @@ export default function AdminWorkerPlatformPage() {
|
||||
label: '寄售仓库',
|
||||
children: <ConsignmentInventoryPanel />,
|
||||
},
|
||||
{
|
||||
key: 'consignment-contacts',
|
||||
label: '对接客服',
|
||||
children: <ConsignmentContactsPanel />,
|
||||
},
|
||||
{
|
||||
key: 'consignment-submissions',
|
||||
label: '寄卖提报审核',
|
||||
|
||||
+60
-43
@@ -16,8 +16,8 @@ import {
|
||||
} from 'antd'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import PageHeader from '@/components/admin/PageHeader'
|
||||
import PercentTable from '@/components/common/PercentTable'
|
||||
import { fetchAdminSession } from '@/services/admin/auth'
|
||||
import {
|
||||
createAdminConsignmentContact,
|
||||
deleteAdminConsignmentContact,
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
updateAdminConsignmentContact,
|
||||
} from '@/services/admin/consignment'
|
||||
import type { ConsignmentContactSupporter } from '@/types/consignment'
|
||||
import { resolveAdminPermission } from '@/utils/admin-auth'
|
||||
import { formatDateTime } from '@/utils/date-time'
|
||||
import type { TableColumnsType } from 'antd'
|
||||
|
||||
@@ -45,12 +46,12 @@ const ENABLED_FILTER_OPTIONS = [
|
||||
]
|
||||
|
||||
/**
|
||||
* 配置 → 对接客服。
|
||||
* 接单平台 → 对接客服。
|
||||
*
|
||||
* 独立名单(不复用后台账号):打手发布寄卖时必选,后台按人统计提成与快速联系。
|
||||
* 已被寄卖记录引用的客服只能禁用,不能删除,保证历史单归属不丢。
|
||||
*/
|
||||
export default function AdminConsignmentContactsPage() {
|
||||
export default function ConsignmentContactsPanel() {
|
||||
const { message, modal } = App.useApp()
|
||||
const queryClient = useQueryClient()
|
||||
const [form] = Form.useForm<ContactForm>()
|
||||
@@ -68,6 +69,18 @@ export default function AdminConsignmentContactsPage() {
|
||||
return () => window.clearTimeout(timer)
|
||||
}, [keywordInput])
|
||||
|
||||
const adminSessionQuery = useQuery({
|
||||
queryKey: ['admin-session'],
|
||||
queryFn: fetchAdminSession,
|
||||
retry: false,
|
||||
})
|
||||
// 写操作统一按 consignment.manage 门控:后端接口都挂了 requireAdminPermission,
|
||||
// 没有权限时按钮点了只会 403,所以直接从界面隐藏。
|
||||
const canManage = resolveAdminPermission(
|
||||
adminSessionQuery.data?.data.user.permissions,
|
||||
'consignment.manage',
|
||||
)
|
||||
|
||||
const query = useQuery({
|
||||
queryKey: ['admin-consignment-contacts', keyword, enabledFilter],
|
||||
queryFn: () =>
|
||||
@@ -195,6 +208,7 @@ export default function AdminConsignmentContactsPage() {
|
||||
<Switch
|
||||
size="small"
|
||||
checked={record.enabled}
|
||||
disabled={!canManage}
|
||||
loading={actionId === record.id}
|
||||
checkedChildren="启用"
|
||||
unCheckedChildren="禁用"
|
||||
@@ -216,52 +230,55 @@ export default function AdminConsignmentContactsPage() {
|
||||
title: '操作',
|
||||
key: 'actions',
|
||||
width: 140,
|
||||
render: (_, record) => (
|
||||
<Space size={4}>
|
||||
<Button size="small" type="link" onClick={() => openEdit(record)}>
|
||||
编辑
|
||||
</Button>
|
||||
<Button size="small" type="link" danger onClick={() => handleDelete(record)}>
|
||||
删除
|
||||
</Button>
|
||||
</Space>
|
||||
),
|
||||
render: (_, record) =>
|
||||
canManage ? (
|
||||
<Space size={4}>
|
||||
<Button size="small" type="link" onClick={() => openEdit(record)}>
|
||||
编辑
|
||||
</Button>
|
||||
<Button size="small" type="link" danger onClick={() => handleDelete(record)}>
|
||||
删除
|
||||
</Button>
|
||||
</Space>
|
||||
) : (
|
||||
<Text type="secondary">-</Text>
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PageHeader
|
||||
title="对接客服"
|
||||
description="打手发布寄卖时必须选择对接客服;本名单独立于后台账号,用于提成归属与联系。"
|
||||
extra={
|
||||
<Button type="primary" icon={<PlusOutlined />} onClick={openCreate}>
|
||||
新增对接客服
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
|
||||
<Card size="small" style={{ marginBottom: 16 }}>
|
||||
<Space wrap size={12}>
|
||||
<Input
|
||||
allowClear
|
||||
prefix={<SearchOutlined />}
|
||||
placeholder="搜索姓名 / 备注"
|
||||
value={keywordInput}
|
||||
onChange={(event) => setKeywordInput(event.target.value)}
|
||||
style={{ width: 280 }}
|
||||
/>
|
||||
<Select
|
||||
value={enabledFilter}
|
||||
options={ENABLED_FILTER_OPTIONS}
|
||||
onChange={setEnabledFilter}
|
||||
style={{ width: 140 }}
|
||||
/>
|
||||
<Button icon={<ReloadOutlined />} onClick={() => void query.refetch()}>
|
||||
刷新
|
||||
</Button>
|
||||
<Text type="secondary">
|
||||
共 {total} 个,本页启用 {enabledCount} 个
|
||||
<Space direction="vertical" size={10} style={{ width: '100%' }}>
|
||||
<Space wrap size={12}>
|
||||
<Input
|
||||
allowClear
|
||||
prefix={<SearchOutlined />}
|
||||
placeholder="搜索姓名 / 备注"
|
||||
value={keywordInput}
|
||||
onChange={(event) => setKeywordInput(event.target.value)}
|
||||
style={{ width: 280 }}
|
||||
/>
|
||||
<Select
|
||||
value={enabledFilter}
|
||||
options={ENABLED_FILTER_OPTIONS}
|
||||
onChange={setEnabledFilter}
|
||||
style={{ width: 140 }}
|
||||
/>
|
||||
<Button icon={<ReloadOutlined />} onClick={() => void query.refetch()}>
|
||||
刷新
|
||||
</Button>
|
||||
<Text type="secondary">
|
||||
共 {total} 个,本页启用 {enabledCount} 个
|
||||
</Text>
|
||||
{canManage ? (
|
||||
<Button type="primary" icon={<PlusOutlined />} onClick={openCreate}>
|
||||
新增对接客服
|
||||
</Button>
|
||||
) : null}
|
||||
</Space>
|
||||
<Text type="secondary" style={{ fontSize: 12 }}>
|
||||
打手发布寄卖时必须选择对接客服;已被寄卖记录使用的客服只能禁用,不能删除。
|
||||
</Text>
|
||||
</Space>
|
||||
</Card>
|
||||
@@ -14,6 +14,7 @@
|
||||
export const WORKER_PLATFORM_TAB_KEYS: readonly string[] = [
|
||||
'orders',
|
||||
'consignment-inventory',
|
||||
'consignment-contacts',
|
||||
'consignment-submissions',
|
||||
'leaderboard',
|
||||
'cancel-requests',
|
||||
@@ -38,6 +39,7 @@ export const WORKER_PLATFORM_TAB_KEYS: readonly string[] = [
|
||||
*/
|
||||
export const WORKER_PLATFORM_TAB_QUERY_KEYS: Record<string, string[][]> = {
|
||||
'consignment-inventory': [['admin-consignment-inventories'], ['admin-consignment-stats']],
|
||||
'consignment-contacts': [['admin-consignment-contacts']],
|
||||
'consignment-submissions': [
|
||||
['admin-consignment-submissions'],
|
||||
['admin-consignment-submissions-pending-total'],
|
||||
|
||||
@@ -18,6 +18,13 @@ test('风控 tab 必须被 isWorkerPlatformTab 接受(漏登记会导致点击
|
||||
assert.equal(isWorkerPlatformTab('risk-control'), true)
|
||||
})
|
||||
|
||||
test('对接客服 tab 必须被 isWorkerPlatformTab 接受,并登记切页刷新缓存', () => {
|
||||
assert.equal(isWorkerPlatformTab('consignment-contacts'), true)
|
||||
assert.deepEqual(WORKER_PLATFORM_TAB_QUERY_KEYS['consignment-contacts'], [
|
||||
['admin-consignment-contacts'],
|
||||
])
|
||||
})
|
||||
|
||||
test('每个登记了切页缓存的 tab 都必须在合法 tab 名单里', () => {
|
||||
const nonTabs = new Set(WORKER_PLATFORM_NON_TAB_QUERY_KEYS)
|
||||
for (const key of Object.keys(WORKER_PLATFORM_TAB_QUERY_KEYS)) {
|
||||
|
||||
Reference in New Issue
Block a user