fix(admin): 修复履约渠道分页并统一列表分页状态

This commit is contained in:
yml2213
2026-11-02 19:49:31 +08:00
parent a7bac9c1d8
commit 3989b0a649
6 changed files with 177 additions and 39 deletions
@@ -1,5 +1,6 @@
import { Table as AntTable } from 'antd'
import type { TableProps } from 'antd'
import type { TablePaginationConfig, TableProps } from 'antd'
import { useEffect, useState } from 'react'
import { normalizePercentColumns } from '@/utils/percent-table-layout'
@@ -12,7 +13,56 @@ import { normalizePercentColumns } from '@/utils/percent-table-layout'
export default function PercentTable<RecordType extends object = Record<string, unknown>>(
props: TableProps<RecordType>,
) {
const { columns, scroll, tableLayout: _tableLayout, ...rest } = props
const { columns, scroll, tableLayout: _tableLayout, pagination, dataSource, ...rest } = props
const paginationConfig = pagination && typeof pagination === 'object' ? pagination : null
const paginationIsExternallyControlled = paginationConfig?.current !== undefined
// 本地分页也必须由组件持有 current;只交给 AntD 内部状态时,父级重渲染会丢失翻页。
const [localPagination, setLocalPagination] = useState(() => ({
current: 1,
pageSize: Number(paginationConfig?.defaultPageSize || paginationConfig?.pageSize || 10),
}))
useEffect(() => {
if (paginationIsExternallyControlled || !paginationConfig?.pageSize) return
const nextPageSize = Number(paginationConfig.pageSize)
if (!Number.isFinite(nextPageSize) || nextPageSize <= 0) return
setLocalPagination((current) =>
current.pageSize === nextPageSize ? current : { current: 1, pageSize: nextPageSize },
)
}, [paginationConfig?.pageSize, paginationIsExternallyControlled])
useEffect(() => {
if (paginationIsExternallyControlled || !paginationConfig) return
const total = Math.max(0, Number(paginationConfig.total ?? dataSource?.length ?? 0))
const maxPage = Math.max(1, Math.ceil(total / Math.max(1, localPagination.pageSize)))
if (localPagination.current > maxPage) {
setLocalPagination((current) => ({ ...current, current: maxPage }))
}
}, [
dataSource?.length,
localPagination.current,
localPagination.pageSize,
paginationConfig,
paginationIsExternallyControlled,
])
const resolvedPagination: TablePaginationConfig | false | undefined = paginationConfig
? paginationIsExternallyControlled
? paginationConfig
: {
...paginationConfig,
current: localPagination.current,
pageSize: localPagination.pageSize,
onChange: (nextPage, nextPageSize) => {
const normalizedPageSize = Math.max(1, Number(nextPageSize) || localPagination.pageSize)
setLocalPagination({
current: normalizedPageSize === localPagination.pageSize ? nextPage : 1,
pageSize: normalizedPageSize,
})
paginationConfig.onChange?.(nextPage, nextPageSize)
},
}
: pagination
const reservedPercent =
(props.rowSelection ? 4 : 0) +
(props.expandable && typeof props.expandable === 'object' ? 4 : 0)
@@ -24,7 +74,9 @@ export default function PercentTable<RecordType extends object = Record<string,
return (
<AntTable<RecordType>
{...rest}
dataSource={dataSource}
columns={normalizedColumns}
pagination={resolvedPagination}
tableLayout="fixed"
scroll={{ ...scrollConfig, x: '100%' }}
/>
@@ -29,7 +29,7 @@ import {
message,
} from 'antd'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { useState } from 'react'
import { useEffect, useState } from 'react'
import PercentTable from '@/components/common/PercentTable'
import FinanceSubNav from '@/components/admin/FinanceSubNav'
@@ -48,11 +48,7 @@ import {
} from '@/services/admin'
import { formatRedeemAmount } from '@/utils/redeem'
import { formatDateTime } from '@/utils/date-time'
import {
ADMIN_DEFAULT_PAGE_SIZE,
buildAdminLocalTablePagination,
buildAdminTablePagination,
} from '@/utils/admin-pagination'
import { ADMIN_DEFAULT_PAGE_SIZE, buildAdminTablePagination } from '@/utils/admin-pagination'
const CHANNEL_OPTIONS = [
{ value: 'work_order', label: '接单平台' },
@@ -251,12 +247,20 @@ function RulesPanel() {
const queryClient = useQueryClient()
const [open, setOpen] = useState(false)
const [selectedRuleIds, setSelectedRuleIds] = useState<number[]>([])
const [page, setPage] = useState(1)
const [pageSize, setPageSize] = useState(ADMIN_DEFAULT_PAGE_SIZE)
const [form] = Form.useForm()
const query = useQuery({
queryKey: ['fulfillment-rules'],
queryFn: () => fetchChannelRules(),
queryKey: ['fulfillment-rules', page, pageSize],
queryFn: () => fetchChannelRules({ page, pageSize }),
})
const ruleCount = query.data?.data?.total || 0
useEffect(() => {
const maxPage = Math.max(1, Math.ceil(ruleCount / pageSize))
if (page > maxPage) setPage(maxPage)
}, [page, pageSize, ruleCount])
const saveMutation = useMutation({
mutationFn: (values: Record<string, unknown>) => saveChannelRule(values as never),
@@ -339,7 +343,7 @@ function RulesPanel() {
return (
<Card
title={`统一渠道配置(${query.data?.data?.length ?? 0})`}
title={`统一渠道配置(${ruleCount})`}
extra={
<Space>
<Button
@@ -368,13 +372,21 @@ function RulesPanel() {
rowKey="id"
size="small"
loading={query.isFetching}
dataSource={query.data?.data || []}
dataSource={query.data?.data?.items || []}
columns={columns}
rowSelection={{
selectedRowKeys: selectedRuleIds,
onChange: (keys) => setSelectedRuleIds(keys.map(Number)),
}}
pagination={buildAdminLocalTablePagination()}
pagination={buildAdminTablePagination({
current: query.data?.data?.page || page,
pageSize: query.data?.data?.pageSize || pageSize,
total: ruleCount,
onChange: (nextPage, nextPageSize) => {
setPage(nextPageSize !== pageSize ? 1 : nextPage)
setPageSize(nextPageSize)
},
})}
/>
<Modal
@@ -31,6 +31,13 @@ export type ChannelRule = {
enabled: boolean
}
export type ChannelRuleListResult = {
items: ChannelRule[]
total: number
page: number
pageSize: number
}
export type ChannelException = {
id: number
reason: string
@@ -127,8 +134,10 @@ export function switchChannelForItems(payload: {
}>('/api/v1/admin/fulfillment/switch', payload)
}
export function fetchChannelRules(params: { channel?: string } = {}) {
return apiGet<ChannelRule[]>('/api/v1/admin/fulfillment/rules', params)
export function fetchChannelRules(
params: { channel?: string; page?: number; pageSize?: number } = {},
) {
return apiGet<ChannelRuleListResult>('/api/v1/admin/fulfillment/rules', params)
}
export function saveChannelRule(payload: {