新增后台接单排行榜支持周期与自定义区间筛选

This commit is contained in:
yml2213
2026-08-22 09:48:09 +08:00
parent ed81122047
commit f1e219d1ef
8 changed files with 383 additions and 0 deletions
@@ -277,3 +277,145 @@ function buildWorkerAcceptedOrdersCountSql() {
) AS completed_orders
`
}
export type AdminLeaderboardPeriod = 'all' | 'daily' | 'weekly' | 'monthly'
/** 后台排行榜:预置周期按上海时区自然日/周/月计算;from/to 为自定义区间(YYYY-MM-DD,含起止日)。 */
export async function listAdminWorkerLeaderboard(input: {
period: AdminLeaderboardPeriod
limit: number
fromDate?: string | null
toDate?: string | null
}): Promise<
Array<{
rank: number
workerId: number
username: string
displayName: string
levelName: string
workerStatus: string
acceptedOrderCount: number
rewardAmount: number
lastAcceptedAt: string | null
}>
> {
const limit = Math.min(100, Math.max(1, Math.floor(Number(input.limit || 50))))
const periodUnit =
input.period === 'daily'
? 'day'
: input.period === 'weekly'
? 'week'
: input.period === 'monthly'
? 'month'
: ''
const result = await query<{
rank: number
worker_id: number
username: string
display_name: string
level_name: string | null
worker_status: string
accepted_order_count: number
reward_amount: string | number
last_accepted_at: Date | string | null
}>(
`
WITH leaderboard_window AS (
SELECT
CASE
WHEN $1::text <> '' THEN date_trunc($1::text, CURRENT_TIMESTAMP AT TIME ZONE 'Asia/Shanghai')
AT TIME ZONE 'Asia/Shanghai'
WHEN $2::date IS NOT NULL THEN $2::date::timestamp AT TIME ZONE 'Asia/Shanghai'
ELSE NULL
END AS starts_at,
CASE
WHEN $1::text = 'day' THEN (date_trunc('day', CURRENT_TIMESTAMP AT TIME ZONE 'Asia/Shanghai')
AT TIME ZONE 'Asia/Shanghai') + INTERVAL '1 day'
WHEN $1::text = 'week' THEN (date_trunc('week', CURRENT_TIMESTAMP AT TIME ZONE 'Asia/Shanghai')
AT TIME ZONE 'Asia/Shanghai') + INTERVAL '7 days'
WHEN $1::text = 'month' THEN (date_trunc('month', CURRENT_TIMESTAMP AT TIME ZONE 'Asia/Shanghai')
AT TIME ZONE 'Asia/Shanghai') + INTERVAL '1 month'
WHEN $3::date IS NOT NULL THEN ($3::date + 1)::timestamp AT TIME ZONE 'Asia/Shanghai'
ELSE NULL
END AS ends_at
),
accepted_totals AS (
SELECT
worker_id,
COUNT(DISTINCT order_key)::int AS accepted_order_count,
SUM(reward_amount)::bigint AS reward_amount,
MAX(last_accepted_at) AS last_accepted_at
FROM (
SELECT
assigned_worker_id AS worker_id,
COALESCE(
'order:' || NULLIF(order_id::text, ''),
'platform_order:' || NULLIF(BTRIM(platform_order_id), ''),
'work_order:' || id::text
) AS order_key,
reward_amount,
MAX(accepted_at) AS last_accepted_at
FROM work_orders
CROSS JOIN leaderboard_window
WHERE assigned_worker_id IS NOT NULL
AND status = 'accepted'
AND (starts_at IS NULL OR (accepted_at >= starts_at AND accepted_at < ends_at))
GROUP BY assigned_worker_id, order_key, reward_amount
UNION ALL
SELECT
wos.worker_id,
COALESCE(
'order:' || NULLIF(wo.order_id::text, ''),
'platform_order:' || NULLIF(BTRIM(wo.platform_order_id), ''),
'work_order:' || wo.id::text
) AS order_key,
wos.share_reward AS reward_amount,
MAX(wos.accepted_at) AS last_accepted_at
FROM work_order_shares wos
INNER JOIN work_orders wo ON wo.id = wos.work_order_id
CROSS JOIN leaderboard_window
WHERE wos.status = 'accepted'
AND (starts_at IS NULL OR (wos.accepted_at >= starts_at AND wos.accepted_at < ends_at))
GROUP BY wos.worker_id, order_key, wos.share_reward
) AS accepted_records
GROUP BY worker_id
),
ranked_workers AS (
SELECT
ROW_NUMBER() OVER (
ORDER BY totals.accepted_order_count DESC, totals.last_accepted_at DESC NULLS LAST, wu.id ASC
)::int AS rank,
wu.id AS worker_id,
wu.username,
wu.display_name,
wu.status AS worker_status,
wl.name AS level_name,
totals.accepted_order_count,
totals.reward_amount,
totals.last_accepted_at
FROM worker_users wu
INNER JOIN accepted_totals totals ON totals.worker_id = wu.id
LEFT JOIN worker_levels wl ON wl.id = wu.level_id
)
SELECT rank, worker_id, username, display_name, level_name, worker_status,
accepted_order_count, reward_amount, last_accepted_at
FROM ranked_workers
ORDER BY rank ASC
LIMIT $4
`,
[periodUnit, input.fromDate || null, input.toDate || null, limit],
)
return result.rows.map((row) => ({
rank: Number(row.rank || 0),
workerId: Number(row.worker_id || 0),
username: String(row.username || '').trim(),
displayName: String(row.display_name || '').trim(),
levelName: String(row.level_name || '').trim(),
workerStatus: String(row.worker_status || ''),
acceptedOrderCount: Number(row.accepted_order_count || 0),
rewardAmount: Number(row.reward_amount || 0),
lastAcceptedAt: row.last_accepted_at ? new Date(row.last_accepted_at).toISOString() : null,
}))
}