fix(admin): 订单列表默认近7天并按支付时间筛选
避免无日期过滤时展示全库,关键词搜索不受日期限制;SSE 插入裁剪并尊重筛选,新单入库优先使用平台支付时间。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -15,8 +15,8 @@ test('订单列表综合筛选下推到总数和分页查询', async () => {
|
||||
executorKey: 'affiliate_dash',
|
||||
payStatus: 'paid',
|
||||
taskStatus: 'manual_review',
|
||||
dateFrom: '2026-09-01T00:00:00.000Z',
|
||||
dateTo: '2026-09-02T23:59:59.999Z',
|
||||
dateFrom: '2026-09-01',
|
||||
dateTo: '2026-09-02',
|
||||
})
|
||||
|
||||
assert.equal(result.total, 3)
|
||||
@@ -24,25 +24,37 @@ test('订单列表综合筛选下推到总数和分页查询', async () => {
|
||||
assert.match(calls[0]?.sql || '', /o\.platform_order_id.*ILIKE \$1/s)
|
||||
assert.match(calls[0]?.sql || '', /oi\.sku_code.*oi\.sku_name.*ILIKE \$1/s)
|
||||
assert.match(calls[0]?.sql || '', /kuaishouSendCode'.*itemTitle.*kuaishouSendCode'.*skuNick/s)
|
||||
assert.match(calls[0]?.sql || '', /o\.provider = \$2/)
|
||||
assert.match(calls[0]?.sql || '', /o\.pay_status = \$3/)
|
||||
assert.match(calls[0]?.sql || '', /ft\.task_status = \$4/)
|
||||
assert.match(calls[0]?.sql || '', /ft\.executor_key = \$5/)
|
||||
assert.match(calls[0]?.sql || '', /o\.created_at >= \$6/)
|
||||
assert.match(calls[0]?.sql || '', /o\.created_at <= \$7/)
|
||||
assert.deepEqual(calls[0]?.params, [
|
||||
'%皮肤店%',
|
||||
'91kaquan',
|
||||
'paid',
|
||||
'manual_review',
|
||||
'affiliate_dash',
|
||||
'2026-09-01T00:00:00.000Z',
|
||||
'2026-09-02T23:59:59.999Z',
|
||||
])
|
||||
assert.match(calls[1]?.sql || '', /LIMIT \$8 OFFSET \$9/)
|
||||
assert.match(calls[0]?.sql || '', /o\.provider IN \('91kaquan', 'open_91', '91'\)/)
|
||||
assert.match(calls[0]?.sql || '', /o\.pay_status = \$2/)
|
||||
assert.match(calls[0]?.sql || '', /ft\.task_status = \$3/)
|
||||
assert.match(calls[0]?.sql || '', /ft\.executor_key = \$4/)
|
||||
// 有关键词时不应用日期过滤
|
||||
assert.doesNotMatch(calls[0]?.sql || '', /paid_at/i)
|
||||
assert.deepEqual(calls[0]?.params, ['%皮肤店%', 'paid', 'manual_review', 'affiliate_dash'])
|
||||
assert.match(calls[1]?.sql || '', /LIMIT \$5 OFFSET \$6/)
|
||||
assert.deepEqual(calls[1]?.params, [...(calls[0]?.params || []), 10, 10])
|
||||
})
|
||||
|
||||
test('订单列表无关键词时按支付时间与中国时区日期筛选', async () => {
|
||||
const calls: Array<{ sql: string; params: unknown[] }> = []
|
||||
|
||||
await listOrdersWithExecutor(createExecutor(calls, 0), {
|
||||
dateFrom: '2026-09-01',
|
||||
dateTo: '2026-09-07',
|
||||
})
|
||||
|
||||
assert.match(
|
||||
calls[0]?.sql || '',
|
||||
/COALESCE\(o\.paid_at, o\.created_at\) >= \(\$1::date\)::timestamp AT TIME ZONE 'Asia\/Shanghai'/,
|
||||
)
|
||||
assert.match(
|
||||
calls[0]?.sql || '',
|
||||
/COALESCE\(o\.paid_at, o\.created_at\) < \(\(\$2::date \+ 1\)::timestamp AT TIME ZONE 'Asia\/Shanghai'\)/,
|
||||
)
|
||||
assert.deepEqual(calls[0]?.params, ['2026-09-01', '2026-09-07'])
|
||||
assert.match(calls[1]?.sql || '', /ORDER BY COALESCE\(o\.paid_at, o\.created_at\) DESC/)
|
||||
})
|
||||
|
||||
test('订单列表保留订单号和精确 SKU 旧筛选参数兼容', async () => {
|
||||
const calls: Array<{ sql: string; params: unknown[] }> = []
|
||||
|
||||
|
||||
@@ -295,8 +295,7 @@ export async function listOrdersWithExecutor(
|
||||
}
|
||||
|
||||
if (provider) {
|
||||
params.push(provider)
|
||||
filters.push(`o.provider = $${params.length}`)
|
||||
appendProviderFilter(filters, params, provider)
|
||||
}
|
||||
|
||||
if (platformOrderId) {
|
||||
@@ -339,14 +338,20 @@ export async function listOrdersWithExecutor(
|
||||
)
|
||||
}
|
||||
|
||||
if (dateFrom) {
|
||||
params.push(dateFrom)
|
||||
filters.push(`o.created_at >= $${params.length}`)
|
||||
// 有关键词时不限日期,避免默认近 N 天挡住搜单号/商品。
|
||||
const applyDateFilter = Boolean(dateFrom || dateTo) && !String(keyword || '').trim()
|
||||
if (applyDateFilter && dateFrom) {
|
||||
params.push(String(dateFrom).trim().slice(0, 10))
|
||||
filters.push(
|
||||
`COALESCE(o.paid_at, o.created_at) >= ($${params.length}::date)::timestamp AT TIME ZONE 'Asia/Shanghai'`,
|
||||
)
|
||||
}
|
||||
|
||||
if (dateTo) {
|
||||
params.push(dateTo)
|
||||
filters.push(`o.created_at <= $${params.length}`)
|
||||
if (applyDateFilter && dateTo) {
|
||||
params.push(String(dateTo).trim().slice(0, 10))
|
||||
filters.push(
|
||||
`COALESCE(o.paid_at, o.created_at) < (($${params.length}::date + 1)::timestamp AT TIME ZONE 'Asia/Shanghai')`,
|
||||
)
|
||||
}
|
||||
|
||||
const whereClause = filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : ''
|
||||
@@ -362,7 +367,7 @@ export async function listOrdersWithExecutor(
|
||||
SELECT o.*
|
||||
FROM orders o
|
||||
${whereClause}
|
||||
ORDER BY o.id DESC
|
||||
ORDER BY COALESCE(o.paid_at, o.created_at) DESC NULLS LAST, o.id DESC
|
||||
LIMIT $${params.length - 1} OFFSET $${params.length}
|
||||
`,
|
||||
params,
|
||||
@@ -373,3 +378,31 @@ export async function listOrdersWithExecutor(
|
||||
total: Number(totalResult.rows[0]?.total || 0),
|
||||
}
|
||||
}
|
||||
|
||||
/** 来源渠道筛选:兼容历史 provider / platform 多种写法。 */
|
||||
function appendProviderFilter(filters: string[], params: unknown[], provider: string) {
|
||||
const normalized = String(provider || '').trim().toLowerCase()
|
||||
if (!normalized) {
|
||||
return
|
||||
}
|
||||
|
||||
if (normalized === 'pdd') {
|
||||
filters.push(`(o.provider = 'pdd' OR o.platform = 'pdd')`)
|
||||
return
|
||||
}
|
||||
|
||||
if (normalized === '91' || normalized === '91kaquan' || normalized === 'open_91') {
|
||||
filters.push(
|
||||
`(o.provider IN ('91kaquan', 'open_91', '91') OR o.platform IN ('91kaquan', '91'))`,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if (normalized === 'kuaishou' || normalized === 'kuaishou-industry') {
|
||||
filters.push(`(o.provider LIKE 'kuaishou%' OR o.platform LIKE 'kuaishou%')`)
|
||||
return
|
||||
}
|
||||
|
||||
params.push(provider)
|
||||
filters.push(`(o.provider = $${params.length} OR o.platform = $${params.length})`)
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import { createHttpError } from '../../utils/http.js'
|
||||
import { formatFenToAmount, normalizeFen } from '../../utils/money.js'
|
||||
import {
|
||||
normalizeDateQuery,
|
||||
normalizeDateString,
|
||||
normalizePage,
|
||||
normalizePageSize,
|
||||
safeParseJson,
|
||||
@@ -94,8 +95,8 @@ export async function getAdminOrders(
|
||||
payStatus: String(query.payStatus || '').trim(),
|
||||
taskStatus: String(query.taskStatus || '').trim(),
|
||||
skuCode: String(query.skuCode || '').trim(),
|
||||
dateFrom: normalizeDateQuery(query.dateFrom),
|
||||
dateTo: normalizeDateQuery(query.dateTo, true),
|
||||
dateFrom: normalizeDateString(query.dateFrom),
|
||||
dateTo: normalizeDateString(query.dateTo),
|
||||
})
|
||||
|
||||
const orderIds = items.map((item) => Number(item.id)).filter((id) => id > 0)
|
||||
|
||||
@@ -156,7 +156,8 @@ export async function upsertOrderFromSource(
|
||||
: await createOrderWithExecutor(executor, {
|
||||
...basePayload,
|
||||
...mergedPayload,
|
||||
createdAt: now,
|
||||
// 优先用平台支付/成团时间,避免积压同步把历史单排成「刚刚入库」。
|
||||
createdAt: String(event.paidAt || now).trim() || now,
|
||||
updatedAt: now,
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user