feat(admin): 整合财务模块导航为侧边栏子菜单与顶部联动Tab
- 侧边栏收敛:将散落在运营分组下的销售毛利、商品与成本、钱包管理、收支明细整合入「财务」二级子菜单,并支持智能展开与角色权限隔离 - 顶部导航联动:新增 FinanceSubNav 通用组件,在销售毛利、商品与成本中心、钱包管理、收支明细 4 个页面顶部统一提供一键切换 Tab - 语义规范化:将原“财务”流水页面标题明确为“收支明细”,消除模块与页面的命名歧义 - 验证方式:npm run check 全量检查通过(Prettier、ESLint、tsc、单测 100% 通过),构建产物已同步至运行容器并验证路由与交互
This commit is contained in:
@@ -0,0 +1,93 @@
|
|||||||
|
import {
|
||||||
|
AccountBookOutlined,
|
||||||
|
ApartmentOutlined,
|
||||||
|
LineChartOutlined,
|
||||||
|
WalletOutlined,
|
||||||
|
} from '@ant-design/icons'
|
||||||
|
import { Tabs } from 'antd'
|
||||||
|
import type { TabsProps } from 'antd'
|
||||||
|
import { useLocation, useNavigate } from 'react-router'
|
||||||
|
import { getAdminRole } from '@/utils/admin-auth'
|
||||||
|
|
||||||
|
export const FINANCE_NAV_ITEMS = [
|
||||||
|
{
|
||||||
|
key: '/admin/sales-profit',
|
||||||
|
label: '销售毛利',
|
||||||
|
icon: <LineChartOutlined />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '/admin/cost-center',
|
||||||
|
label: '商品与成本中心',
|
||||||
|
icon: <ApartmentOutlined />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '/admin/fund',
|
||||||
|
label: '钱包管理',
|
||||||
|
icon: <WalletOutlined />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '/admin/finance',
|
||||||
|
label: '收支明细',
|
||||||
|
icon: <AccountBookOutlined />,
|
||||||
|
},
|
||||||
|
] as const
|
||||||
|
|
||||||
|
type FinanceNavKey = (typeof FINANCE_NAV_ITEMS)[number]['key']
|
||||||
|
|
||||||
|
type FinanceSubNavProps = {
|
||||||
|
current?: FinanceNavKey
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function FinanceSubNav({ current }: FinanceSubNavProps) {
|
||||||
|
const location = useLocation()
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const role = getAdminRole()
|
||||||
|
|
||||||
|
// 客服角色无完整财务权限,不展示财务联动 Tab
|
||||||
|
if (role === 'support') {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const activeKey =
|
||||||
|
current ||
|
||||||
|
FINANCE_NAV_ITEMS.find((item) => location.pathname.startsWith(item.key))?.key ||
|
||||||
|
'/admin/sales-profit'
|
||||||
|
|
||||||
|
const tabItems: TabsProps['items'] = FINANCE_NAV_ITEMS.map((item) => ({
|
||||||
|
key: item.key,
|
||||||
|
label: (
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
display: 'inline-flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 6,
|
||||||
|
fontSize: 15,
|
||||||
|
fontWeight: 500,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{item.icon}
|
||||||
|
{item.label}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="finance-sub-nav-wrapper"
|
||||||
|
style={{
|
||||||
|
background: '#fff',
|
||||||
|
padding: '6px 16px 0',
|
||||||
|
borderRadius: 8,
|
||||||
|
border: '1px solid #f0f0f0',
|
||||||
|
marginBottom: 4,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tabs
|
||||||
|
activeKey={activeKey}
|
||||||
|
onChange={(key) => navigate(key)}
|
||||||
|
items={tabItems}
|
||||||
|
style={{ marginBottom: -1 }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -168,52 +168,81 @@ export default function AdminLayout() {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const selectedKey = resolveSelectedKey(location.pathname)
|
||||||
|
const isFinanceKey = [
|
||||||
|
'/admin/sales-profit',
|
||||||
|
'/admin/cost-center',
|
||||||
|
'/admin/fund',
|
||||||
|
'/admin/finance',
|
||||||
|
].includes(selectedKey)
|
||||||
|
const [openKeys, setOpenKeys] = useState<string[]>(['sub-finance'])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isFinanceKey && !openKeys.includes('sub-finance')) {
|
||||||
|
setOpenKeys((prev) => [...prev, 'sub-finance'])
|
||||||
|
}
|
||||||
|
}, [isFinanceKey])
|
||||||
|
|
||||||
const menuItems = useMemo<MenuProps['items']>(() => {
|
const menuItems = useMemo<MenuProps['items']>(() => {
|
||||||
|
const financeSubItems: MenuProps['items'] = [
|
||||||
|
{ key: '/admin/sales-profit', icon: <LineChartOutlined />, label: '销售毛利' },
|
||||||
|
{ key: '/admin/cost-center', icon: <ApartmentOutlined />, label: '商品与成本' },
|
||||||
|
{ key: '/admin/fund', icon: <WalletOutlined />, label: '钱包管理' },
|
||||||
|
{ key: '/admin/finance', icon: <AccountBookOutlined />, label: '收支明细' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const financeSubMenu = {
|
||||||
|
key: 'sub-finance',
|
||||||
|
icon: <AccountBookOutlined />,
|
||||||
|
label: '财务',
|
||||||
|
children: financeSubItems,
|
||||||
|
}
|
||||||
|
|
||||||
const operationItems: MenuProps['items'] =
|
const operationItems: MenuProps['items'] =
|
||||||
role === 'finance'
|
role === 'finance'
|
||||||
? [
|
? [
|
||||||
{ key: '/admin/finance', icon: <AccountBookOutlined />, label: '财务' },
|
financeSubMenu,
|
||||||
{ key: '/admin/sales-profit', icon: <LineChartOutlined />, label: '销售毛利' },
|
|
||||||
{ key: '/admin/cost-center', icon: <ApartmentOutlined />, label: '商品与成本' },
|
|
||||||
{ key: '/admin/fund', icon: <WalletOutlined />, label: '钱包管理' },
|
|
||||||
{ key: '/admin/worker-platform', icon: <TrophyOutlined />, label: '资金审核' },
|
{ key: '/admin/worker-platform', icon: <TrophyOutlined />, label: '资金审核' },
|
||||||
]
|
]
|
||||||
: [
|
: role === 'support'
|
||||||
{ key: '/admin/dashboard', icon: <DashboardOutlined />, label: '概览' },
|
? [
|
||||||
{ key: '/admin/orders', icon: <OrderedListOutlined />, label: '订单' },
|
{ key: '/admin/dashboard', icon: <DashboardOutlined />, label: '概览' },
|
||||||
{
|
{ key: '/admin/orders', icon: <OrderedListOutlined />, label: '订单' },
|
||||||
key: '/admin/fund',
|
{
|
||||||
icon: <WalletOutlined />,
|
key: '/admin/fund',
|
||||||
label: role === 'support' ? '我的钱包' : '钱包管理',
|
icon: <WalletOutlined />,
|
||||||
},
|
label: '我的钱包',
|
||||||
...(role === 'support'
|
},
|
||||||
? []
|
{ key: '/admin/tasks', icon: <UnorderedListOutlined />, label: '任务' },
|
||||||
: [
|
{ key: '/admin/worker-platform', icon: <TrophyOutlined />, label: '接单平台' },
|
||||||
{ key: '/admin/finance', icon: <AccountBookOutlined />, label: '财务' },
|
{
|
||||||
{
|
key: '/admin/kuaishou-industry',
|
||||||
key: '/admin/sales-profit',
|
icon: <SafetyCertificateOutlined />,
|
||||||
icon: <LineChartOutlined />,
|
label: '电子凭证',
|
||||||
label: '销售毛利',
|
},
|
||||||
},
|
{
|
||||||
{
|
key: '/admin/douyin-mashida-certificates',
|
||||||
key: '/admin/cost-center',
|
icon: <SafetyCertificateOutlined />,
|
||||||
icon: <ApartmentOutlined />,
|
label: '抖音券核销',
|
||||||
label: '商品与成本',
|
},
|
||||||
},
|
]
|
||||||
]),
|
: [
|
||||||
{ key: '/admin/tasks', icon: <UnorderedListOutlined />, label: '任务' },
|
{ key: '/admin/dashboard', icon: <DashboardOutlined />, label: '概览' },
|
||||||
{ key: '/admin/worker-platform', icon: <TrophyOutlined />, label: '接单平台' },
|
{ key: '/admin/orders', icon: <OrderedListOutlined />, label: '订单' },
|
||||||
{
|
financeSubMenu,
|
||||||
key: '/admin/kuaishou-industry',
|
{ key: '/admin/tasks', icon: <UnorderedListOutlined />, label: '任务' },
|
||||||
icon: <SafetyCertificateOutlined />,
|
{ key: '/admin/worker-platform', icon: <TrophyOutlined />, label: '接单平台' },
|
||||||
label: '电子凭证',
|
{
|
||||||
},
|
key: '/admin/kuaishou-industry',
|
||||||
{
|
icon: <SafetyCertificateOutlined />,
|
||||||
key: '/admin/douyin-mashida-certificates',
|
label: '电子凭证',
|
||||||
icon: <SafetyCertificateOutlined />,
|
},
|
||||||
label: '抖音券核销',
|
{
|
||||||
},
|
key: '/admin/douyin-mashida-certificates',
|
||||||
]
|
icon: <SafetyCertificateOutlined />,
|
||||||
|
label: '抖音券核销',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
const items: MenuProps['items'] = [
|
const items: MenuProps['items'] = [
|
||||||
{
|
{
|
||||||
@@ -333,8 +362,6 @@ export default function AdminLayout() {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
const selectedKey = resolveSelectedKey(location.pathname)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout className="admin-shell">
|
<Layout className="admin-shell">
|
||||||
<Layout.Sider
|
<Layout.Sider
|
||||||
@@ -377,6 +404,8 @@ export default function AdminLayout() {
|
|||||||
mode="inline"
|
mode="inline"
|
||||||
inlineIndent={16}
|
inlineIndent={16}
|
||||||
selectedKeys={[selectedKey]}
|
selectedKeys={[selectedKey]}
|
||||||
|
openKeys={openKeys}
|
||||||
|
onOpenChange={(keys) => setOpenKeys(keys as string[])}
|
||||||
items={menuItems}
|
items={menuItems}
|
||||||
className="admin-menu"
|
className="admin-menu"
|
||||||
onClick={({ key }) => navigate(String(key))}
|
onClick={({ key }) => navigate(String(key))}
|
||||||
@@ -802,8 +831,10 @@ function playNotificationSound(kind: NotificationAlertKind) {
|
|||||||
|
|
||||||
function resolveSelectedKey(pathname: string) {
|
function resolveSelectedKey(pathname: string) {
|
||||||
if (pathname.startsWith('/admin/orders')) return '/admin/orders'
|
if (pathname.startsWith('/admin/orders')) return '/admin/orders'
|
||||||
if (pathname.startsWith('/admin/finance')) return '/admin/finance'
|
if (pathname.startsWith('/admin/sales-profit')) return '/admin/sales-profit'
|
||||||
if (pathname.startsWith('/admin/cost-center')) return '/admin/cost-center'
|
if (pathname.startsWith('/admin/cost-center')) return '/admin/cost-center'
|
||||||
|
if (pathname.startsWith('/admin/fund')) return '/admin/fund'
|
||||||
|
if (pathname.startsWith('/admin/finance')) return '/admin/finance'
|
||||||
if (pathname.startsWith('/admin/tasks')) return '/admin/tasks'
|
if (pathname.startsWith('/admin/tasks')) return '/admin/tasks'
|
||||||
if (pathname.startsWith('/admin/worker-platform')) return '/admin/worker-platform'
|
if (pathname.startsWith('/admin/worker-platform')) return '/admin/worker-platform'
|
||||||
if (pathname.startsWith('/admin/kuaishou-industry')) return '/admin/kuaishou-industry'
|
if (pathname.startsWith('/admin/kuaishou-industry')) return '/admin/kuaishou-industry'
|
||||||
|
|||||||
@@ -188,7 +188,11 @@ export function apiGet<T>(url: string, params?: Record<string, unknown>, options
|
|||||||
return request<T>({ method: 'GET', url, params, ...options })
|
return request<T>({ method: 'GET', url, params, ...options })
|
||||||
}
|
}
|
||||||
|
|
||||||
export function apiGetBlob(url: string, params?: Record<string, unknown>, options?: RequestOptions) {
|
export function apiGetBlob(
|
||||||
|
url: string,
|
||||||
|
params?: Record<string, unknown>,
|
||||||
|
options?: RequestOptions,
|
||||||
|
) {
|
||||||
return http.request<Blob, Blob>({
|
return http.request<Blob, Blob>({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url,
|
url,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { useState } from 'react'
|
|||||||
|
|
||||||
import { AdminRangePicker } from '@/components/admin/AdminDatePicker'
|
import { AdminRangePicker } from '@/components/admin/AdminDatePicker'
|
||||||
import PageHeader from '@/components/admin/PageHeader'
|
import PageHeader from '@/components/admin/PageHeader'
|
||||||
|
import FinanceSubNav from '@/components/admin/FinanceSubNav'
|
||||||
import dayjs from '@/lib/dayjs'
|
import dayjs from '@/lib/dayjs'
|
||||||
import {
|
import {
|
||||||
fetchAdminFinanceSummary,
|
fetchAdminFinanceSummary,
|
||||||
@@ -160,7 +161,8 @@ export default function AdminFinancePage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="page-stack">
|
<section className="page-stack">
|
||||||
<PageHeader title="财务" description="按日期查看订单收款、退款、打手结算和平台现金流。" />
|
<FinanceSubNav current="/admin/finance" />
|
||||||
|
<PageHeader title="收支明细" description="按日期查看订单收款、退款、打手结算和平台现金流。" />
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<Form<FinanceFilterForm>
|
<Form<FinanceFilterForm>
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import { useState } from 'react'
|
|||||||
|
|
||||||
import { AdminRangePicker } from '@/components/admin/AdminDatePicker'
|
import { AdminRangePicker } from '@/components/admin/AdminDatePicker'
|
||||||
import PageHeader from '@/components/admin/PageHeader'
|
import PageHeader from '@/components/admin/PageHeader'
|
||||||
|
import FinanceSubNav from '@/components/admin/FinanceSubNav'
|
||||||
import dayjs from '@/lib/dayjs'
|
import dayjs from '@/lib/dayjs'
|
||||||
import {
|
import {
|
||||||
fetchAdminSalesDailyFacts,
|
fetchAdminSalesDailyFacts,
|
||||||
@@ -98,7 +99,12 @@ export default function AdminSalesProfitPage() {
|
|||||||
function resetFilters() {
|
function resetFilters() {
|
||||||
form.resetFields()
|
form.resetFields()
|
||||||
setPage(1)
|
setPage(1)
|
||||||
setFilters({ dateFrom: defaultDateFrom, dateTo: defaultDateTo, provider: '', fulfillmentMode: '' })
|
setFilters({
|
||||||
|
dateFrom: defaultDateFrom,
|
||||||
|
dateTo: defaultDateTo,
|
||||||
|
provider: '',
|
||||||
|
fulfillmentMode: '',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function rebuildFacts() {
|
async function rebuildFacts() {
|
||||||
@@ -243,6 +249,7 @@ export default function AdminSalesProfitPage() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="page-stack">
|
<section className="page-stack">
|
||||||
|
<FinanceSubNav current="/admin/sales-profit" />
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title="销售毛利"
|
title="销售毛利"
|
||||||
description="按订单项归集收入与成本;未归一商品单独成行,成本缺失时毛利不直接用于决策。"
|
description="按订单项归集收入与成本;未归一商品单独成行,成本缺失时毛利不直接用于决策。"
|
||||||
|
|||||||
@@ -5,12 +5,7 @@
|
|||||||
* 不写渠道映射,也不维护游戏分类。
|
* 不写渠道映射,也不维护游戏分类。
|
||||||
* 成本按上游商品配置采购单价(cost_versions),并在改价/初次配置后重算成本快照。
|
* 成本按上游商品配置采购单价(cost_versions),并在改价/初次配置后重算成本快照。
|
||||||
*/
|
*/
|
||||||
import {
|
import { DownloadOutlined, EditOutlined, ReloadOutlined, SyncOutlined } from '@ant-design/icons'
|
||||||
DownloadOutlined,
|
|
||||||
EditOutlined,
|
|
||||||
ReloadOutlined,
|
|
||||||
SyncOutlined,
|
|
||||||
} from '@ant-design/icons'
|
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
App,
|
App,
|
||||||
@@ -267,11 +262,7 @@ export function AffiliateSkuPanel() {
|
|||||||
>
|
>
|
||||||
重算成本快照
|
重算成本快照
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button icon={<SyncOutlined />} loading={syncing} onClick={() => void syncProducts()}>
|
||||||
icon={<SyncOutlined />}
|
|
||||||
loading={syncing}
|
|
||||||
onClick={() => void syncProducts()}
|
|
||||||
>
|
|
||||||
同步自动发货商品
|
同步自动发货商品
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
@@ -478,7 +469,8 @@ export function AffiliateSkuPanel() {
|
|||||||
<Space direction="vertical" size={0}>
|
<Space direction="vertical" size={0}>
|
||||||
<Typography.Text strong>追溯至历史订单 (推荐)</Typography.Text>
|
<Typography.Text strong>追溯至历史订单 (推荐)</Typography.Text>
|
||||||
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
|
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
|
||||||
自近一个月业务起点(30 天前)生效,重算快照后可直接消除近一个月 cost_missing 异常
|
自近一个月业务起点(30 天前)生效,重算快照后可直接消除近一个月 cost_missing
|
||||||
|
异常
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
</Space>
|
</Space>
|
||||||
</Radio>
|
</Radio>
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import {
|
|||||||
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
||||||
|
|
||||||
import PageHeader from '@/components/admin/PageHeader'
|
import PageHeader from '@/components/admin/PageHeader'
|
||||||
|
import FinanceSubNav from '@/components/admin/FinanceSubNav'
|
||||||
import { usePersistedState } from '@/hooks/usePersistedState'
|
import { usePersistedState } from '@/hooks/usePersistedState'
|
||||||
import { fetchAdminCostCenterOptions, fetchAdminCostCenterOverview } from '@/services/admin'
|
import { fetchAdminCostCenterOptions, fetchAdminCostCenterOverview } from '@/services/admin'
|
||||||
import { hasAdminPermission } from '@/utils/admin-auth'
|
import { hasAdminPermission } from '@/utils/admin-auth'
|
||||||
@@ -121,6 +122,7 @@ export default function CostCenterShell() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<section className="page-stack">
|
<section className="page-stack">
|
||||||
|
<FinanceSubNav current="/admin/cost-center" />
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title="商品与成本中心"
|
title="商品与成本中心"
|
||||||
description="商品 SKU 先归一;成本在各来源自己的配置里维护(人工 SKU 消耗积分 / 自动发货采购价 / 接单模板发单金额),历史成本靠快照固化。"
|
description="商品 SKU 先归一;成本在各来源自己的配置里维护(人工 SKU 消耗积分 / 自动发货采购价 / 接单模板发单金额),历史成本靠快照固化。"
|
||||||
|
|||||||
@@ -618,7 +618,11 @@ export function ProductCatalogPanel() {
|
|||||||
style={{ padding: 0 }}
|
style={{ padding: 0 }}
|
||||||
onClick={() => canConfig && openSetProductPrice(row)}
|
onClick={() => canConfig && openSetProductPrice(row)}
|
||||||
>
|
>
|
||||||
{value > 0 ? `${value} 个版本 · 改价` : row.source === 'work_order' ? '配置结算成本' : '未配置 · 立即配置'}
|
{value > 0
|
||||||
|
? `${value} 个版本 · 改价`
|
||||||
|
: row.source === 'work_order'
|
||||||
|
? '配置结算成本'
|
||||||
|
: '未配置 · 立即配置'}
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@@ -1005,9 +1009,7 @@ export function ProductCatalogPanel() {
|
|||||||
<Form.Item
|
<Form.Item
|
||||||
name="amountYuan"
|
name="amountYuan"
|
||||||
label={
|
label={
|
||||||
pricingProduct.source === 'affiliate_dash'
|
pricingProduct.source === 'affiliate_dash' ? '采购单价(元)' : '标准结算单价(元)'
|
||||||
? '采购单价(元)'
|
|
||||||
: '标准结算单价(元)'
|
|
||||||
}
|
}
|
||||||
rules={[{ required: true, message: '请填写价格' }]}
|
rules={[{ required: true, message: '请填写价格' }]}
|
||||||
extra={
|
extra={
|
||||||
@@ -1050,7 +1052,10 @@ export function ProductCatalogPanel() {
|
|||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item noStyle shouldUpdate={(prev, curr) => prev.effectiveScope !== curr.effectiveScope}>
|
<Form.Item
|
||||||
|
noStyle
|
||||||
|
shouldUpdate={(prev, curr) => prev.effectiveScope !== curr.effectiveScope}
|
||||||
|
>
|
||||||
{({ getFieldValue }) =>
|
{({ getFieldValue }) =>
|
||||||
getFieldValue('effectiveScope') === 'custom' ? (
|
getFieldValue('effectiveScope') === 'custom' ? (
|
||||||
<Form.Item
|
<Form.Item
|
||||||
@@ -1069,11 +1074,7 @@ export function ProductCatalogPanel() {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
{pricingProduct.canonicalSku.startsWith('tpl:') ? (
|
{pricingProduct.canonicalSku.startsWith('tpl:') ? (
|
||||||
<Form.Item
|
<Form.Item name="syncOpenOrders" valuePropName="checked" style={{ marginBottom: 12 }}>
|
||||||
name="syncOpenOrders"
|
|
||||||
valuePropName="checked"
|
|
||||||
style={{ marginBottom: 12 }}
|
|
||||||
>
|
|
||||||
<Checkbox>
|
<Checkbox>
|
||||||
<strong>立即同步至接单大厅待抢单工单(推荐)</strong>
|
<strong>立即同步至接单大厅待抢单工单(推荐)</strong>
|
||||||
<div style={{ color: '#64748b', fontSize: 12 }}>
|
<div style={{ color: '#64748b', fontSize: 12 }}>
|
||||||
@@ -1084,11 +1085,7 @@ export function ProductCatalogPanel() {
|
|||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{pricingProduct.source === 'affiliate_dash' ? (
|
{pricingProduct.source === 'affiliate_dash' ? (
|
||||||
<Form.Item
|
<Form.Item name="syncSnapshots" valuePropName="checked" style={{ marginBottom: 12 }}>
|
||||||
name="syncSnapshots"
|
|
||||||
valuePropName="checked"
|
|
||||||
style={{ marginBottom: 12 }}
|
|
||||||
>
|
|
||||||
<Checkbox>
|
<Checkbox>
|
||||||
<strong>立即重算成本快照并回填历史(推荐)</strong>
|
<strong>立即重算成本快照并回填历史(推荐)</strong>
|
||||||
<div style={{ color: '#64748b', fontSize: 12 }}>
|
<div style={{ color: '#64748b', fontSize: 12 }}>
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import { PlatformCreditPanel } from './PlatformCreditPanel'
|
|||||||
import ImagePreviewList from '@/components/files/ImagePreviewList'
|
import ImagePreviewList from '@/components/files/ImagePreviewList'
|
||||||
import ImageUpload from '@/components/files/ImageUpload'
|
import ImageUpload from '@/components/files/ImageUpload'
|
||||||
import PageHeader from '@/components/admin/PageHeader'
|
import PageHeader from '@/components/admin/PageHeader'
|
||||||
|
import FinanceSubNav from '@/components/admin/FinanceSubNav'
|
||||||
import {
|
import {
|
||||||
confirmAdminFundReconciliation,
|
confirmAdminFundReconciliation,
|
||||||
createAdminFundAccount,
|
createAdminFundAccount,
|
||||||
@@ -875,6 +876,7 @@ export default function FundManagementView({ role }: { role: ManagementRole }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="page-stack">
|
<section className="page-stack">
|
||||||
|
<FinanceSubNav current="/admin/fund" />
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title="钱包管理"
|
title="钱包管理"
|
||||||
description="统管客服的南航 / 乐玩 / ROCK 积分钱包与备用金现金;可分配积分、发放现金、查看流水与对账。"
|
description="统管客服的南航 / 乐玩 / ROCK 积分钱包与备用金现金;可分配积分、发放现金、查看流水与对账。"
|
||||||
|
|||||||
@@ -164,7 +164,6 @@ export function syncAdminAffiliateDashCostSnapshots() {
|
|||||||
}>('/api/v1/admin/cost-center/affiliate-products/sync-snapshots', {}, { timeout: 300_000 })
|
}>('/api/v1/admin/cost-center/affiliate-products/sync-snapshots', {}, { timeout: 300_000 })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function updateAdminProductCatalog(productId: number, payload: Record<string, unknown>) {
|
export function updateAdminProductCatalog(productId: number, payload: Record<string, unknown>) {
|
||||||
return apiPatch<{ product: ProductCatalogItem }>(
|
return apiPatch<{ product: ProductCatalogItem }>(
|
||||||
`/api/v1/admin/cost-center/products/${productId}`,
|
`/api/v1/admin/cost-center/products/${productId}`,
|
||||||
@@ -504,4 +503,3 @@ export function syncAdminProductPrice(productId: number) {
|
|||||||
message: string
|
message: string
|
||||||
}>(`/api/v1/admin/cost-center/products/${productId}/sync-price`, {})
|
}>(`/api/v1/admin/cost-center/products/${productId}/sync-price`, {})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user