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
@@ -13,7 +13,7 @@ import {
assignChannelToOrderItems,
deleteChannelRule,
deleteChannelRules,
listChannelRules,
listChannelRulesPage,
listPendingChannelGroups,
switchChannelForOrderItems,
unlockChannel,
@@ -179,8 +179,10 @@ router.get(
requireAdminPermission('finance.view'),
createJsonHandler(
(req) =>
listChannelRules({
listChannelRulesPage({
channel: String(req.query.channel || ''),
page: Number(req.query.page),
pageSize: Number(req.query.pageSize),
...(req.query.enabled === undefined
? {}
: { enabled: String(req.query.enabled) !== 'false' }),
@@ -63,6 +63,13 @@ export type ChannelRule = {
enabled: boolean
}
export type ChannelRulePage = {
items: ChannelRule[]
total: number
page: number
pageSize: number
}
export type ChannelCandidateItem = {
id: number
provider: string
@@ -1033,12 +1040,12 @@ export async function assignChannelBySku(input: {
})
}
export async function listChannelRules(
input: {
channel?: string
enabled?: boolean
} = {},
): Promise<ChannelRule[]> {
type ChannelRuleFilterInput = {
channel?: string
enabled?: boolean
}
function buildChannelRuleFilter(input: ChannelRuleFilterInput) {
const params: unknown[] = []
const clauses: string[] = []
if (input.channel) {
@@ -1050,25 +1057,70 @@ export async function listChannelRules(
clauses.push(`enabled = $${params.length}`)
}
const where = clauses.length > 0 ? `WHERE ${clauses.join(' AND ')}` : ''
const rows = await query<ChannelRule>(
`
SELECT id, provider, shop_id, match_key_type, match_key, channel, priority, enabled
FROM (
SELECT id, ''::text AS provider, ''::text AS shop_id,
'internal_sku'::text AS match_key_type, internal_sku AS match_key,
channel, priority, enabled
FROM internal_sku_channels
) internal_rules
${where}
ORDER BY priority, channel, match_key
`,
params,
)
return rows.rows.map((row) => ({
return { where, params }
}
const CHANNEL_RULE_FROM_SQL = `
FROM (
SELECT id, ''::text AS provider, ''::text AS shop_id,
'internal_sku'::text AS match_key_type, internal_sku AS match_key,
channel, priority, enabled
FROM internal_sku_channels
) internal_rules
`
function mapChannelRule(row: ChannelRule): ChannelRule {
return {
...row,
id: Number(row.id),
priority: Number(row.priority),
}))
}
}
export async function listChannelRules(input: ChannelRuleFilterInput = {}): Promise<ChannelRule[]> {
const { where, params } = buildChannelRuleFilter(input)
const rows = await query<ChannelRule>(
`
SELECT id, provider, shop_id, match_key_type, match_key, channel, priority, enabled
${CHANNEL_RULE_FROM_SQL}
${where}
ORDER BY priority, channel, match_key, id
`,
params,
)
return rows.rows.map(mapChannelRule)
}
export async function listChannelRulesPage(
input: ChannelRuleFilterInput & { page?: number; pageSize?: number } = {},
): Promise<ChannelRulePage> {
const page = Math.max(1, Math.trunc(Number(input.page) || 1))
const pageSize = Math.min(100, Math.max(1, Math.trunc(Number(input.pageSize) || 20)))
const offset = (page - 1) * pageSize
const { where, params } = buildChannelRuleFilter(input)
const pageParams = [...params, pageSize, offset]
const [countResult, rows] = await Promise.all([
query<{ total: number }>(
`SELECT COUNT(*)::int AS total ${CHANNEL_RULE_FROM_SQL} ${where}`,
params,
),
query<ChannelRule>(
`
SELECT id, provider, shop_id, match_key_type, match_key, channel, priority, enabled
${CHANNEL_RULE_FROM_SQL}
${where}
ORDER BY priority, channel, match_key, id
LIMIT $${pageParams.length - 1} OFFSET $${pageParams.length}
`,
pageParams,
),
])
return {
items: rows.rows.map(mapChannelRule),
total: Number(countResult.rows[0]?.total || 0),
page,
pageSize,
}
}
export async function upsertChannelRule(input: {
@@ -23,6 +23,7 @@ test(
deleteChannelRules,
ensureVoucherRuleForSku,
listChannelRules,
listChannelRulesPage,
switchChannelForOrderItems,
upsertChannelRule,
} = await import('./channel-assign-service.js')
@@ -171,6 +172,16 @@ test(
assert.ok(
listedRules.some((rule) => rule.id === savedRule.id && rule.match_key === voucherSku),
)
const firstRulePage = await listChannelRulesPage({
channel: 'third_party_voucher',
enabled: true,
page: 1,
pageSize: 2,
})
assert.equal(firstRulePage.page, 1)
assert.equal(firstRulePage.pageSize, 2)
assert.ok(firstRulePage.items.length <= 2)
assert.equal(firstRulePage.total, listedRules.length)
const deletedRules = await deleteChannelRules([savedRule.id])
assert.equal(deletedRules.deletedCount, 1)
assert.deepEqual(deletedRules.deletedIds, [savedRule.id])