feat(admin): 增加履约渠道批量删除并统一分页配置
This commit is contained in:
@@ -12,6 +12,7 @@ import {
|
|||||||
assignChannelBySku,
|
assignChannelBySku,
|
||||||
assignChannelToOrderItems,
|
assignChannelToOrderItems,
|
||||||
deleteChannelRule,
|
deleteChannelRule,
|
||||||
|
deleteChannelRules,
|
||||||
listChannelRules,
|
listChannelRules,
|
||||||
listPendingChannelGroups,
|
listPendingChannelGroups,
|
||||||
switchChannelForOrderItems,
|
switchChannelForOrderItems,
|
||||||
@@ -234,6 +235,22 @@ router.delete(
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
router.post(
|
||||||
|
'/fulfillment/rules/batch-delete',
|
||||||
|
requireAdminPermission('finance.config'),
|
||||||
|
createJsonHandler((req) => deleteChannelRules(Array.isArray(req.body?.ids) ? req.body.ids : []), {
|
||||||
|
successMessage: '渠道规则已批量删除',
|
||||||
|
errorMessage: '批量删除渠道规则失败',
|
||||||
|
scope: '[admin/fulfillment/rules/batch-delete]',
|
||||||
|
audit: (_req, data) => ({
|
||||||
|
action: 'fulfillment.batch_delete_rules',
|
||||||
|
targetType: 'internal_sku_channel',
|
||||||
|
targetId: '',
|
||||||
|
data: data as Record<string, unknown>,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
'/fulfillment/pipeline/status',
|
'/fulfillment/pipeline/status',
|
||||||
requireAdminPermission('finance.view'),
|
requireAdminPermission('finance.view'),
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import {
|
|||||||
} from './channel-types.js'
|
} from './channel-types.js'
|
||||||
import {
|
import {
|
||||||
deleteInternalSkuChannelById,
|
deleteInternalSkuChannelById,
|
||||||
|
deleteInternalSkuChannelsByIds,
|
||||||
planInternalSkuChannels,
|
planInternalSkuChannels,
|
||||||
setInternalSkuPrimaryChannel,
|
setInternalSkuPrimaryChannel,
|
||||||
upsertInternalSkuChannel,
|
upsertInternalSkuChannel,
|
||||||
@@ -1119,6 +1120,21 @@ export async function deleteChannelRule(ruleId: number): Promise<{ deleted: bool
|
|||||||
return { deleted: await deleteInternalSkuChannelById(id) }
|
return { deleted: await deleteInternalSkuChannelById(id) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function deleteChannelRules(idsInput: number[]): Promise<{
|
||||||
|
deletedCount: number
|
||||||
|
deletedIds: number[]
|
||||||
|
missingIds: number[]
|
||||||
|
}> {
|
||||||
|
if (!Array.isArray(idsInput) || idsInput.length === 0) {
|
||||||
|
throw createHttpError('请选择要删除的渠道规则', {
|
||||||
|
statusCode: 400,
|
||||||
|
errorCode: 'channel_rule_ids_required',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const result = await deleteInternalSkuChannelsByIds(idsInput)
|
||||||
|
return { deletedCount: result.deletedIds.length, ...result }
|
||||||
|
}
|
||||||
|
|
||||||
async function loadEnabledRules(): Promise<ChannelRule[]> {
|
async function loadEnabledRules(): Promise<ChannelRule[]> {
|
||||||
const rows = await query<ChannelRule>(
|
const rows = await query<ChannelRule>(
|
||||||
`
|
`
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ test(
|
|||||||
const { closeDb, query } = await import('../../db/client.js')
|
const { closeDb, query } = await import('../../db/client.js')
|
||||||
const {
|
const {
|
||||||
assignChannelByInternalSku,
|
assignChannelByInternalSku,
|
||||||
deleteChannelRule,
|
deleteChannelRules,
|
||||||
ensureVoucherRuleForSku,
|
ensureVoucherRuleForSku,
|
||||||
listChannelRules,
|
listChannelRules,
|
||||||
switchChannelForOrderItems,
|
switchChannelForOrderItems,
|
||||||
@@ -171,7 +171,9 @@ test(
|
|||||||
assert.ok(
|
assert.ok(
|
||||||
listedRules.some((rule) => rule.id === savedRule.id && rule.match_key === voucherSku),
|
listedRules.some((rule) => rule.id === savedRule.id && rule.match_key === voucherSku),
|
||||||
)
|
)
|
||||||
assert.equal((await deleteChannelRule(savedRule.id)).deleted, true)
|
const deletedRules = await deleteChannelRules([savedRule.id])
|
||||||
|
assert.equal(deletedRules.deletedCount, 1)
|
||||||
|
assert.deepEqual(deletedRules.deletedIds, [savedRule.id])
|
||||||
} finally {
|
} finally {
|
||||||
if (orderItemIds.length > 0) {
|
if (orderItemIds.length > 0) {
|
||||||
await query(`DELETE FROM cost_exception_items WHERE order_item_id = ANY($1::bigint[])`, [
|
await query(`DELETE FROM cost_exception_items WHERE order_item_id = ANY($1::bigint[])`, [
|
||||||
|
|||||||
@@ -203,3 +203,21 @@ export async function deleteInternalSkuChannelById(channelId: number): Promise<b
|
|||||||
const result = await query(`DELETE FROM internal_sku_channels WHERE id = $1`, [id])
|
const result = await query(`DELETE FROM internal_sku_channels WHERE id = $1`, [id])
|
||||||
return (result.rowCount || 0) > 0
|
return (result.rowCount || 0) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function deleteInternalSkuChannelsByIds(idsInput: number[]): Promise<{
|
||||||
|
deletedIds: number[]
|
||||||
|
missingIds: number[]
|
||||||
|
}> {
|
||||||
|
const ids = [...new Set(idsInput.map(Number).filter((id) => Number.isInteger(id) && id > 0))]
|
||||||
|
if (ids.length === 0) return { deletedIds: [], missingIds: [] }
|
||||||
|
const result = await query<{ id: number }>(
|
||||||
|
`DELETE FROM internal_sku_channels WHERE id = ANY($1::bigint[]) RETURNING id`,
|
||||||
|
[ids],
|
||||||
|
)
|
||||||
|
const deletedIds = result.rows.map((row) => Number(row.id))
|
||||||
|
const deleted = new Set(deletedIds)
|
||||||
|
return {
|
||||||
|
deletedIds,
|
||||||
|
missingIds: ids.filter((id) => !deleted.has(id)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import type { Dayjs } from 'dayjs'
|
|||||||
import { AdminRangePicker } from '@/components/admin/AdminDatePicker'
|
import { AdminRangePicker } from '@/components/admin/AdminDatePicker'
|
||||||
import FinanceSubNav from '@/components/admin/FinanceSubNav'
|
import FinanceSubNav from '@/components/admin/FinanceSubNav'
|
||||||
import PercentTable from '@/components/common/PercentTable'
|
import PercentTable from '@/components/common/PercentTable'
|
||||||
|
import { buildAdminTablePagination } from '@/utils/admin-pagination'
|
||||||
import dayjs from '@/lib/dayjs'
|
import dayjs from '@/lib/dayjs'
|
||||||
import {
|
import {
|
||||||
closeFinancePeriod,
|
closeFinancePeriod,
|
||||||
@@ -509,16 +510,15 @@ export default function AdminFinanceLedgerPage() {
|
|||||||
dataSource={entriesQuery.data?.data.items || []}
|
dataSource={entriesQuery.data?.data.items || []}
|
||||||
columns={entryColumns}
|
columns={entryColumns}
|
||||||
onRow={(row) => ({ onClick: () => setEntryDetail(row) })}
|
onRow={(row) => ({ onClick: () => setEntryDetail(row) })}
|
||||||
pagination={{
|
pagination={buildAdminTablePagination({
|
||||||
current: entryPage,
|
current: entryPage,
|
||||||
pageSize: entryPageSize,
|
pageSize: entryPageSize,
|
||||||
total: entriesQuery.data?.data.pagination.total || 0,
|
total: entriesQuery.data?.data.pagination.total || 0,
|
||||||
showSizeChanger: true,
|
|
||||||
onChange: (page, size) => {
|
onChange: (page, size) => {
|
||||||
setEntryPage(page)
|
setEntryPage(page)
|
||||||
setEntryPageSize(size)
|
setEntryPageSize(size)
|
||||||
},
|
},
|
||||||
}}
|
})}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
</Space>
|
</Space>
|
||||||
@@ -566,16 +566,15 @@ export default function AdminFinanceLedgerPage() {
|
|||||||
loading={reconciliationsQuery.isLoading}
|
loading={reconciliationsQuery.isLoading}
|
||||||
dataSource={reconciliationsQuery.data?.data.items || []}
|
dataSource={reconciliationsQuery.data?.data.items || []}
|
||||||
columns={reconColumns}
|
columns={reconColumns}
|
||||||
pagination={{
|
pagination={buildAdminTablePagination({
|
||||||
current: reconPage,
|
current: reconPage,
|
||||||
pageSize: reconPageSize,
|
pageSize: reconPageSize,
|
||||||
total: reconciliationsQuery.data?.data.pagination.total || 0,
|
total: reconciliationsQuery.data?.data.pagination.total || 0,
|
||||||
showSizeChanger: true,
|
|
||||||
onChange: (page, size) => {
|
onChange: (page, size) => {
|
||||||
setReconPage(page)
|
setReconPage(page)
|
||||||
setReconPageSize(size)
|
setReconPageSize(size)
|
||||||
},
|
},
|
||||||
}}
|
})}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -6,7 +6,12 @@
|
|||||||
* · 没有命中规则的新单落在「待分类」,收入进未分类桶,不产生成本噪音;
|
* · 没有命中规则的新单落在「待分类」,收入进未分类桶,不产生成本噪音;
|
||||||
* · 第三方卡券是「只统计」渠道:不建任务、不发领取页。
|
* · 第三方卡券是「只统计」渠道:不建任务、不发领取页。
|
||||||
*/
|
*/
|
||||||
import { PlusOutlined, ReloadOutlined, ThunderboltOutlined } from '@ant-design/icons'
|
import {
|
||||||
|
DeleteOutlined,
|
||||||
|
PlusOutlined,
|
||||||
|
ReloadOutlined,
|
||||||
|
ThunderboltOutlined,
|
||||||
|
} from '@ant-design/icons'
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
Button,
|
Button,
|
||||||
@@ -30,7 +35,7 @@ import PercentTable from '@/components/common/PercentTable'
|
|||||||
import FinanceSubNav from '@/components/admin/FinanceSubNav'
|
import FinanceSubNav from '@/components/admin/FinanceSubNav'
|
||||||
import {
|
import {
|
||||||
assignChannelBySku,
|
assignChannelBySku,
|
||||||
deleteChannelRule,
|
deleteChannelRules,
|
||||||
fetchChannelExceptions,
|
fetchChannelExceptions,
|
||||||
fetchChannelRules,
|
fetchChannelRules,
|
||||||
fetchPendingChannelGroups,
|
fetchPendingChannelGroups,
|
||||||
@@ -43,6 +48,11 @@ import {
|
|||||||
} from '@/services/admin'
|
} from '@/services/admin'
|
||||||
import { formatRedeemAmount } from '@/utils/redeem'
|
import { formatRedeemAmount } from '@/utils/redeem'
|
||||||
import { formatDateTime } from '@/utils/date-time'
|
import { formatDateTime } from '@/utils/date-time'
|
||||||
|
import {
|
||||||
|
ADMIN_DEFAULT_PAGE_SIZE,
|
||||||
|
buildAdminLocalTablePagination,
|
||||||
|
buildAdminTablePagination,
|
||||||
|
} from '@/utils/admin-pagination'
|
||||||
|
|
||||||
const CHANNEL_OPTIONS = [
|
const CHANNEL_OPTIONS = [
|
||||||
{ value: 'work_order', label: '接单平台' },
|
{ value: 'work_order', label: '接单平台' },
|
||||||
@@ -80,11 +90,13 @@ export default function AdminFulfillmentChannelPage() {
|
|||||||
function PendingPanel() {
|
function PendingPanel() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const [keyword, setKeyword] = useState('')
|
const [keyword, setKeyword] = useState('')
|
||||||
|
const [page, setPage] = useState(1)
|
||||||
|
const [pageSize, setPageSize] = useState(ADMIN_DEFAULT_PAGE_SIZE)
|
||||||
const [selections, setSelections] = useState<Record<string, string>>({})
|
const [selections, setSelections] = useState<Record<string, string>>({})
|
||||||
|
|
||||||
const query = useQuery({
|
const query = useQuery({
|
||||||
queryKey: ['fulfillment-pending', keyword],
|
queryKey: ['fulfillment-pending', keyword, page, pageSize],
|
||||||
queryFn: () => fetchPendingChannelGroups({ page: 1, pageSize: 100, keyword }),
|
queryFn: () => fetchPendingChannelGroups({ page, pageSize, keyword }),
|
||||||
})
|
})
|
||||||
|
|
||||||
const assignMutation = useMutation({
|
const assignMutation = useMutation({
|
||||||
@@ -191,7 +203,10 @@ function PendingPanel() {
|
|||||||
allowClear
|
allowClear
|
||||||
placeholder="SKU / 商品名"
|
placeholder="SKU / 商品名"
|
||||||
style={{ width: 220 }}
|
style={{ width: 220 }}
|
||||||
onSearch={(value) => setKeyword(value)}
|
onSearch={(value) => {
|
||||||
|
setKeyword(value)
|
||||||
|
setPage(1)
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Button icon={<ReloadOutlined />} onClick={() => void query.refetch()}>
|
<Button icon={<ReloadOutlined />} onClick={() => void query.refetch()}>
|
||||||
刷新
|
刷新
|
||||||
@@ -218,7 +233,15 @@ function PendingPanel() {
|
|||||||
loading={query.isFetching}
|
loading={query.isFetching}
|
||||||
dataSource={query.data?.data?.items || []}
|
dataSource={query.data?.data?.items || []}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
pagination={{ pageSize: 20, showSizeChanger: false }}
|
pagination={buildAdminTablePagination({
|
||||||
|
current: query.data?.data?.page || page,
|
||||||
|
pageSize: query.data?.data?.pageSize || pageSize,
|
||||||
|
total: query.data?.data?.total || 0,
|
||||||
|
onChange: (nextPage, nextPageSize) => {
|
||||||
|
setPage(nextPageSize !== pageSize ? 1 : nextPage)
|
||||||
|
setPageSize(nextPageSize)
|
||||||
|
},
|
||||||
|
})}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
)
|
)
|
||||||
@@ -227,6 +250,7 @@ function PendingPanel() {
|
|||||||
function RulesPanel() {
|
function RulesPanel() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
|
const [selectedRuleIds, setSelectedRuleIds] = useState<number[]>([])
|
||||||
const [form] = Form.useForm()
|
const [form] = Form.useForm()
|
||||||
|
|
||||||
const query = useQuery({
|
const query = useQuery({
|
||||||
@@ -246,14 +270,31 @@ function RulesPanel() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const deleteMutation = useMutation({
|
const deleteMutation = useMutation({
|
||||||
mutationFn: (id: number) => deleteChannelRule(id),
|
mutationFn: (ids: number[]) => deleteChannelRules(ids),
|
||||||
onSuccess: () => {
|
onSuccess: (result) => {
|
||||||
message.success('规则已删除')
|
const missingHint = result.data.missingIds.length
|
||||||
|
? `,${result.data.missingIds.length} 条已不存在`
|
||||||
|
: ''
|
||||||
|
message.success(`已删除 ${result.data.deletedCount} 条渠道规则${missingHint}`)
|
||||||
|
setSelectedRuleIds([])
|
||||||
void queryClient.invalidateQueries({ queryKey: ['fulfillment-rules'] })
|
void queryClient.invalidateQueries({ queryKey: ['fulfillment-rules'] })
|
||||||
|
void queryClient.invalidateQueries({ queryKey: ['fulfillment-pending'] })
|
||||||
},
|
},
|
||||||
onError: () => message.error('删除规则失败'),
|
onError: () => message.error('删除规则失败'),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function confirmDeleteRules(ids: number[]) {
|
||||||
|
if (ids.length === 0) return
|
||||||
|
Modal.confirm({
|
||||||
|
title: ids.length === 1 ? '删除渠道规则' : `批量删除 ${ids.length} 条渠道规则`,
|
||||||
|
content: '删除后会立即影响新订单的渠道判定;历史订单和成本数据不会被删除。',
|
||||||
|
okText: '确认删除',
|
||||||
|
okButtonProps: { danger: true },
|
||||||
|
cancelText: '取消',
|
||||||
|
onOk: () => deleteMutation.mutateAsync(ids),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ title: '作用范围', width: 110, render: () => <Tag color="blue">全局</Tag> },
|
{ title: '作用范围', width: 110, render: () => <Tag color="blue">全局</Tag> },
|
||||||
{
|
{
|
||||||
@@ -288,7 +329,7 @@ function RulesPanel() {
|
|||||||
danger
|
danger
|
||||||
size="small"
|
size="small"
|
||||||
loading={deleteMutation.isPending}
|
loading={deleteMutation.isPending}
|
||||||
onClick={() => deleteMutation.mutate(row.id)}
|
onClick={() => confirmDeleteRules([row.id])}
|
||||||
>
|
>
|
||||||
删除
|
删除
|
||||||
</Button>
|
</Button>
|
||||||
@@ -301,6 +342,15 @@ function RulesPanel() {
|
|||||||
title={`统一渠道配置(${query.data?.data?.length ?? 0})`}
|
title={`统一渠道配置(${query.data?.data?.length ?? 0})`}
|
||||||
extra={
|
extra={
|
||||||
<Space>
|
<Space>
|
||||||
|
<Button
|
||||||
|
danger
|
||||||
|
icon={<DeleteOutlined />}
|
||||||
|
disabled={selectedRuleIds.length === 0}
|
||||||
|
loading={deleteMutation.isPending}
|
||||||
|
onClick={() => confirmDeleteRules(selectedRuleIds)}
|
||||||
|
>
|
||||||
|
批量删除{selectedRuleIds.length ? ` (${selectedRuleIds.length})` : ''}
|
||||||
|
</Button>
|
||||||
<Button icon={<ReloadOutlined />} onClick={() => void query.refetch()}>
|
<Button icon={<ReloadOutlined />} onClick={() => void query.refetch()}>
|
||||||
刷新
|
刷新
|
||||||
</Button>
|
</Button>
|
||||||
@@ -320,7 +370,11 @@ function RulesPanel() {
|
|||||||
loading={query.isFetching}
|
loading={query.isFetching}
|
||||||
dataSource={query.data?.data || []}
|
dataSource={query.data?.data || []}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
pagination={{ pageSize: 20, showSizeChanger: false }}
|
rowSelection={{
|
||||||
|
selectedRowKeys: selectedRuleIds,
|
||||||
|
onChange: (keys) => setSelectedRuleIds(keys.map(Number)),
|
||||||
|
}}
|
||||||
|
pagination={buildAdminLocalTablePagination()}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
@@ -366,9 +420,11 @@ function RulesPanel() {
|
|||||||
|
|
||||||
function ExceptionsPanel() {
|
function ExceptionsPanel() {
|
||||||
const [reason, setReason] = useState('')
|
const [reason, setReason] = useState('')
|
||||||
|
const [page, setPage] = useState(1)
|
||||||
|
const [pageSize, setPageSize] = useState(ADMIN_DEFAULT_PAGE_SIZE)
|
||||||
const query = useQuery({
|
const query = useQuery({
|
||||||
queryKey: ['fulfillment-exceptions', reason],
|
queryKey: ['fulfillment-exceptions', reason, page, pageSize],
|
||||||
queryFn: () => fetchChannelExceptions({ reason, status: 'open', page: 1, pageSize: 100 }),
|
queryFn: () => fetchChannelExceptions({ reason, status: 'open', page, pageSize }),
|
||||||
})
|
})
|
||||||
|
|
||||||
const REASON_OPTIONS = [
|
const REASON_OPTIONS = [
|
||||||
@@ -408,7 +464,10 @@ function ExceptionsPanel() {
|
|||||||
style={{ width: 180 }}
|
style={{ width: 180 }}
|
||||||
value={reason}
|
value={reason}
|
||||||
options={REASON_OPTIONS}
|
options={REASON_OPTIONS}
|
||||||
onChange={setReason}
|
onChange={(value) => {
|
||||||
|
setReason(value)
|
||||||
|
setPage(1)
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<Button icon={<ReloadOutlined />} onClick={() => void query.refetch()}>
|
<Button icon={<ReloadOutlined />} onClick={() => void query.refetch()}>
|
||||||
刷新
|
刷新
|
||||||
@@ -422,7 +481,15 @@ function ExceptionsPanel() {
|
|||||||
loading={query.isFetching}
|
loading={query.isFetching}
|
||||||
dataSource={query.data?.data?.items || []}
|
dataSource={query.data?.data?.items || []}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
pagination={{ pageSize: 20, showSizeChanger: false }}
|
pagination={buildAdminTablePagination({
|
||||||
|
current: query.data?.data?.page || page,
|
||||||
|
pageSize: query.data?.data?.pageSize || pageSize,
|
||||||
|
total: query.data?.data?.total || 0,
|
||||||
|
onChange: (nextPage, nextPageSize) => {
|
||||||
|
setPage(nextPageSize !== pageSize ? 1 : nextPage)
|
||||||
|
setPageSize(nextPageSize)
|
||||||
|
},
|
||||||
|
})}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -27,25 +27,25 @@ import {
|
|||||||
setAdminProductPrice,
|
setAdminProductPrice,
|
||||||
} from '@/services/admin'
|
} from '@/services/admin'
|
||||||
import type { ProductCatalogItem } from '@/types/admin'
|
import type { ProductCatalogItem } from '@/types/admin'
|
||||||
|
import { ADMIN_DEFAULT_PAGE_SIZE, buildAdminTablePagination } from '@/utils/admin-pagination'
|
||||||
import { useCostCenter } from './CostCenterContext'
|
import { useCostCenter } from './CostCenterContext'
|
||||||
|
|
||||||
const PAGE_SIZE = 100
|
|
||||||
|
|
||||||
export default function VoucherSkuPanel() {
|
export default function VoucherSkuPanel() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const { canConfig, refreshAll } = useCostCenter()
|
const { canConfig, refreshAll } = useCostCenter()
|
||||||
const [page] = useState(1)
|
const [page, setPage] = useState(1)
|
||||||
|
const [pageSize, setPageSize] = useState(ADMIN_DEFAULT_PAGE_SIZE)
|
||||||
const [selected, setSelected] = useState<ProductCatalogItem | null>(null)
|
const [selected, setSelected] = useState<ProductCatalogItem | null>(null)
|
||||||
const [ensuringRules, setEnsuringRules] = useState(false)
|
const [ensuringRules, setEnsuringRules] = useState(false)
|
||||||
const [form] = Form.useForm<{ amountFen: number; changeReason?: string }>()
|
const [form] = Form.useForm<{ amountFen: number; changeReason?: string }>()
|
||||||
|
|
||||||
const query = useQuery({
|
const query = useQuery({
|
||||||
queryKey: ['cost-center-voucher-products', page],
|
queryKey: ['cost-center-voucher-products', page, pageSize],
|
||||||
queryFn: () =>
|
queryFn: () =>
|
||||||
fetchAdminProductCatalog({
|
fetchAdminProductCatalog({
|
||||||
carrierType: 'third_party_voucher',
|
carrierType: 'third_party_voucher',
|
||||||
page,
|
page,
|
||||||
pageSize: PAGE_SIZE,
|
pageSize,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -154,7 +154,15 @@ export default function VoucherSkuPanel() {
|
|||||||
loading={query.isFetching}
|
loading={query.isFetching}
|
||||||
dataSource={items}
|
dataSource={items}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
pagination={{ pageSize: 20, showSizeChanger: false }}
|
pagination={buildAdminTablePagination({
|
||||||
|
current: page,
|
||||||
|
pageSize,
|
||||||
|
total,
|
||||||
|
onChange: (nextPage, nextPageSize) => {
|
||||||
|
setPage(nextPageSize !== pageSize ? 1 : nextPage)
|
||||||
|
setPageSize(nextPageSize)
|
||||||
|
},
|
||||||
|
})}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Modal
|
<Modal
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import {
|
|||||||
import type { PlatformCreditAccount, PlatformCreditEntry, PlatformCreditOwner } from '@/types/admin'
|
import type { PlatformCreditAccount, PlatformCreditEntry, PlatformCreditOwner } from '@/types/admin'
|
||||||
import { hasAdminPermission } from '@/utils/admin-auth'
|
import { hasAdminPermission } from '@/utils/admin-auth'
|
||||||
import { formatAdminDateTime } from '@/utils/admin-time'
|
import { formatAdminDateTime } from '@/utils/admin-time'
|
||||||
|
import { buildAdminLocalTablePagination } from '@/utils/admin-pagination'
|
||||||
|
|
||||||
const PLATFORM_TAG_COLORS: Record<string, string> = {
|
const PLATFORM_TAG_COLORS: Record<string, string> = {
|
||||||
nanhang: 'blue',
|
nanhang: 'blue',
|
||||||
@@ -406,7 +407,7 @@ export function PlatformCreditPanel() {
|
|||||||
dataSource={visibleAccounts}
|
dataSource={visibleAccounts}
|
||||||
loading={accountsQuery.isLoading}
|
loading={accountsQuery.isLoading}
|
||||||
scroll={{ x: 1080 }}
|
scroll={{ x: 1080 }}
|
||||||
pagination={{ pageSize: 20, showSizeChanger: true }}
|
pagination={buildAdminLocalTablePagination()}
|
||||||
locale={{ emptyText: '还没有客服积分账户' }}
|
locale={{ emptyText: '还没有客服积分账户' }}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import {
|
|||||||
Typography,
|
Typography,
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import PercentTable from '@/components/common/PercentTable'
|
import PercentTable from '@/components/common/PercentTable'
|
||||||
|
import { buildAdminTablePagination } from '@/utils/admin-pagination'
|
||||||
import type { TableColumnsType } from 'antd'
|
import type { TableColumnsType } from 'antd'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
|
||||||
@@ -880,18 +881,16 @@ export default function ConsignmentInventoryPanel() {
|
|||||||
dataSource={items}
|
dataSource={items}
|
||||||
loading={inventoriesQuery.isLoading}
|
loading={inventoriesQuery.isLoading}
|
||||||
scroll={{ x: 1590 }}
|
scroll={{ x: 1590 }}
|
||||||
pagination={{
|
pagination={buildAdminTablePagination({
|
||||||
current: page,
|
current: page,
|
||||||
pageSize,
|
pageSize,
|
||||||
total,
|
total,
|
||||||
showSizeChanger: true,
|
|
||||||
pageSizeOptions: ['10', '20', '50', '100'],
|
|
||||||
showTotal: (t) => `共 ${t} 件物品`,
|
showTotal: (t) => `共 ${t} 件物品`,
|
||||||
onChange: (p, ps) => {
|
onChange: (p, ps) => {
|
||||||
setPage(p)
|
setPage(p)
|
||||||
setPageSize(ps)
|
setPageSize(ps)
|
||||||
},
|
},
|
||||||
}}
|
})}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import {
|
|||||||
App,
|
App,
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import PercentTable from '@/components/common/PercentTable'
|
import PercentTable from '@/components/common/PercentTable'
|
||||||
|
import { buildAdminTablePagination } from '@/utils/admin-pagination'
|
||||||
import type { TableColumnsType } from 'antd'
|
import type { TableColumnsType } from 'antd'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
|
||||||
@@ -474,17 +475,16 @@ export default function ConsignmentSubmissionsPanel() {
|
|||||||
dataSource={submissions}
|
dataSource={submissions}
|
||||||
loading={submissionsQuery.isLoading}
|
loading={submissionsQuery.isLoading}
|
||||||
scroll={{ x: 1490 }}
|
scroll={{ x: 1490 }}
|
||||||
pagination={{
|
pagination={buildAdminTablePagination({
|
||||||
current: submissionPage,
|
current: submissionPage,
|
||||||
pageSize: submissionPageSize,
|
pageSize: submissionPageSize,
|
||||||
total: submissionTotal,
|
total: submissionTotal,
|
||||||
showSizeChanger: true,
|
|
||||||
showTotal: (t) => `共 ${t} 条提报记录`,
|
showTotal: (t) => `共 ${t} 条提报记录`,
|
||||||
onChange: (p, ps) => {
|
onChange: (p, ps) => {
|
||||||
setSubmissionPage(p)
|
setSubmissionPage(p)
|
||||||
setSubmissionPageSize(ps)
|
setSubmissionPageSize(ps)
|
||||||
},
|
},
|
||||||
}}
|
})}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,11 @@ import {
|
|||||||
import type { KuaishouMatchSource, WorkProductMatchLog } from '@/types/worker-platform'
|
import type { KuaishouMatchSource, WorkProductMatchLog } from '@/types/worker-platform'
|
||||||
import type { AdminKuaishouIndustryShopOption } from '@/types/admin'
|
import type { AdminKuaishouIndustryShopOption } from '@/types/admin'
|
||||||
import { formatAdminDateTime } from '@/utils/admin-time'
|
import { formatAdminDateTime } from '@/utils/admin-time'
|
||||||
import { ADMIN_DEFAULT_PAGE_SIZE, buildAdminTablePagination } from '@/utils/admin-pagination'
|
import {
|
||||||
|
ADMIN_DEFAULT_PAGE_SIZE,
|
||||||
|
buildAdminLocalTablePagination,
|
||||||
|
buildAdminTablePagination,
|
||||||
|
} from '@/utils/admin-pagination'
|
||||||
import { formatMoney } from './shared'
|
import { formatMoney } from './shared'
|
||||||
|
|
||||||
export default function ProductMatchPanel() {
|
export default function ProductMatchPanel() {
|
||||||
@@ -366,7 +370,7 @@ export default function ProductMatchPanel() {
|
|||||||
loading={sourcesQuery.isLoading}
|
loading={sourcesQuery.isLoading}
|
||||||
columns={sourceColumns}
|
columns={sourceColumns}
|
||||||
dataSource={sources}
|
dataSource={sources}
|
||||||
pagination={{ pageSize: 10, showSizeChanger: false }}
|
pagination={buildAdminLocalTablePagination()}
|
||||||
size="small"
|
size="small"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
Tag,
|
Tag,
|
||||||
} from 'antd'
|
} from 'antd'
|
||||||
import PercentTable from '@/components/common/PercentTable'
|
import PercentTable from '@/components/common/PercentTable'
|
||||||
|
import { buildAdminTablePagination } from '@/utils/admin-pagination'
|
||||||
import type { ColumnsType } from 'antd/es/table'
|
import type { ColumnsType } from 'antd/es/table'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
@@ -635,16 +636,15 @@ export default function RiskControlPanel() {
|
|||||||
dataSource={bans?.items || []}
|
dataSource={bans?.items || []}
|
||||||
loading={bansQuery.isLoading}
|
loading={bansQuery.isLoading}
|
||||||
locale={{ emptyText: '暂无封禁记录' }}
|
locale={{ emptyText: '暂无封禁记录' }}
|
||||||
pagination={{
|
pagination={buildAdminTablePagination({
|
||||||
current: banPage,
|
current: banPage,
|
||||||
pageSize: banPageSize,
|
pageSize: banPageSize,
|
||||||
total: bans?.total || 0,
|
total: bans?.total || 0,
|
||||||
showSizeChanger: true,
|
|
||||||
onChange: (nextPage, nextPageSize) => {
|
onChange: (nextPage, nextPageSize) => {
|
||||||
setBanPage(nextPage)
|
setBanPage(nextPage)
|
||||||
setBanPageSize(nextPageSize)
|
setBanPageSize(nextPageSize)
|
||||||
},
|
},
|
||||||
}}
|
})}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
@@ -690,16 +690,15 @@ export default function RiskControlPanel() {
|
|||||||
columns={eventColumns}
|
columns={eventColumns}
|
||||||
dataSource={events?.items || []}
|
dataSource={events?.items || []}
|
||||||
loading={eventsQuery.isLoading}
|
loading={eventsQuery.isLoading}
|
||||||
pagination={{
|
pagination={buildAdminTablePagination({
|
||||||
current: page,
|
current: page,
|
||||||
pageSize,
|
pageSize,
|
||||||
total: events?.total || 0,
|
total: events?.total || 0,
|
||||||
showSizeChanger: true,
|
|
||||||
onChange: (nextPage, nextPageSize) => {
|
onChange: (nextPage, nextPageSize) => {
|
||||||
setPage(nextPage)
|
setPage(nextPage)
|
||||||
setPageSize(nextPageSize)
|
setPageSize(nextPageSize)
|
||||||
},
|
},
|
||||||
}}
|
})}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
</Space>
|
</Space>
|
||||||
|
|||||||
@@ -1697,7 +1697,7 @@ function AffiliateDashPlatformPanel() {
|
|||||||
<PercentTable<SkuMappingRow>
|
<PercentTable<SkuMappingRow>
|
||||||
rowKey={(row) => row.productNo}
|
rowKey={(row) => row.productNo}
|
||||||
size="small"
|
size="small"
|
||||||
pagination={{ pageSize: 10, showSizeChanger: false }}
|
pagination={buildAdminLocalTablePagination()}
|
||||||
dataSource={builtinSkuRows}
|
dataSource={builtinSkuRows}
|
||||||
columns={[
|
columns={[
|
||||||
{ title: '91 中文编码', dataIndex: 'productNo', key: 'productNo' },
|
{ title: '91 中文编码', dataIndex: 'productNo', key: 'productNo' },
|
||||||
|
|||||||
@@ -147,6 +147,14 @@ export function deleteChannelRule(ruleId: number) {
|
|||||||
return apiDelete<{ deleted: boolean }>(`/api/v1/admin/fulfillment/rules/${ruleId}`)
|
return apiDelete<{ deleted: boolean }>(`/api/v1/admin/fulfillment/rules/${ruleId}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function deleteChannelRules(ids: number[]) {
|
||||||
|
return apiPost<{
|
||||||
|
deletedCount: number
|
||||||
|
deletedIds: number[]
|
||||||
|
missingIds: number[]
|
||||||
|
}>('/api/v1/admin/fulfillment/rules/batch-delete', { ids })
|
||||||
|
}
|
||||||
|
|
||||||
export function fetchPipelineStatus() {
|
export function fetchPipelineStatus() {
|
||||||
return apiGet<FinancePipelineStatus[]>('/api/v1/admin/fulfillment/pipeline/status')
|
return apiGet<FinancePipelineStatus[]>('/api/v1/admin/fulfillment/pipeline/status')
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user