资金申请增加渠道筛选合计与审核留痕
This commit is contained in:
@@ -471,6 +471,8 @@ export type FinanceRequestListInput = {
|
||||
/** 申请时间区间(YYYY-MM-DD,上海时区,含起止日);后台列表筛选使用。 */
|
||||
createdFrom?: string
|
||||
createdTo?: string
|
||||
/** 收款渠道筛选:alipay / wechat */
|
||||
accountChannel?: string
|
||||
}
|
||||
|
||||
export type CreateWorkerInput = {
|
||||
|
||||
@@ -205,6 +205,7 @@ export async function listWorkerFinanceRequests({
|
||||
keyword = '',
|
||||
createdFrom = '',
|
||||
createdTo = '',
|
||||
accountChannel = '',
|
||||
}: FinanceRequestListInput = {}): Promise<{ items: WorkerFinanceRequestRow[]; total: number }> {
|
||||
const { whereClause, params } = buildWorkerFinanceRequestWhere({
|
||||
requestId,
|
||||
@@ -214,6 +215,7 @@ export async function listWorkerFinanceRequests({
|
||||
keyword,
|
||||
createdFrom,
|
||||
createdTo,
|
||||
accountChannel,
|
||||
})
|
||||
const totalResult = await query<{ total: number }>(
|
||||
`SELECT COUNT(*)::int AS total FROM worker_finance_requests wfr
|
||||
@@ -236,11 +238,46 @@ export async function listWorkerFinanceRequests({
|
||||
}
|
||||
}
|
||||
|
||||
/** 按当前列表筛选条件汇总各收款渠道的笔数与金额,供后台合计条展示。 */
|
||||
export async function summarizeWorkerFinanceRequests(
|
||||
input: FinanceRequestListInput = {},
|
||||
): Promise<Array<{ channel: string; count: number; amount: number }>> {
|
||||
const { whereClause, params } = buildWorkerFinanceRequestWhere({
|
||||
requestId: input.requestId || 0,
|
||||
workerId: input.workerId || 0,
|
||||
status: input.status || '',
|
||||
requestType: input.requestType || '',
|
||||
keyword: input.keyword || '',
|
||||
createdFrom: input.createdFrom || '',
|
||||
createdTo: input.createdTo || '',
|
||||
accountChannel: input.accountChannel || '',
|
||||
})
|
||||
const result = await query<{ channel: string; total: number; amount: string | number }>(
|
||||
`
|
||||
SELECT
|
||||
COALESCE(NULLIF(wfr.account_channel, ''), 'other') AS channel,
|
||||
COUNT(*)::int AS total,
|
||||
COALESCE(SUM(wfr.amount), 0)::bigint AS amount
|
||||
FROM worker_finance_requests wfr
|
||||
LEFT JOIN worker_users wu ON wu.id = wfr.worker_id
|
||||
${whereClause}
|
||||
GROUP BY 1
|
||||
`,
|
||||
params,
|
||||
)
|
||||
return result.rows.map((row) => ({
|
||||
channel: String(row.channel || 'other'),
|
||||
count: Number(row.total || 0),
|
||||
amount: Number(row.amount || 0),
|
||||
}))
|
||||
}
|
||||
|
||||
export async function reviewWorkerFinanceRequest(input: {
|
||||
requestId: number
|
||||
status: string
|
||||
reviewedNote: string
|
||||
now: string
|
||||
reviewedBy?: string
|
||||
}): Promise<{
|
||||
request: WorkerFinanceRequestRow | null
|
||||
failureReason: 'request_not_pending' | 'withdraw_insufficient' | null
|
||||
@@ -357,10 +394,24 @@ export async function reviewWorkerFinanceRequest(input: {
|
||||
status = $1,
|
||||
reviewed_note = $2,
|
||||
reviewed_at = $3,
|
||||
updated_at = $3
|
||||
updated_at = $3,
|
||||
payload_json = payload_json || $5::jsonb
|
||||
WHERE id = $4
|
||||
`,
|
||||
[input.status, input.reviewedNote, input.now, input.requestId],
|
||||
[
|
||||
input.status,
|
||||
input.reviewedNote,
|
||||
input.now,
|
||||
input.requestId,
|
||||
JSON.stringify({
|
||||
review: {
|
||||
by: String(input.reviewedBy || '').trim(),
|
||||
at: input.now,
|
||||
status: input.status,
|
||||
note: input.reviewedNote,
|
||||
},
|
||||
}),
|
||||
],
|
||||
)
|
||||
|
||||
return {
|
||||
@@ -421,9 +472,14 @@ function buildWorkerFinanceRequestWhere({
|
||||
keyword = '',
|
||||
createdFrom = '',
|
||||
createdTo = '',
|
||||
accountChannel = '',
|
||||
}: FinanceRequestListInput) {
|
||||
const filters: string[] = []
|
||||
const params: unknown[] = []
|
||||
if (accountChannel) {
|
||||
params.push(accountChannel)
|
||||
filters.push(`wfr.account_channel = $${params.length}`)
|
||||
}
|
||||
if (createdFrom) {
|
||||
params.push(createdFrom)
|
||||
filters.push(
|
||||
|
||||
@@ -272,6 +272,7 @@ export {
|
||||
listWorkerFinanceRequests,
|
||||
listWorkerWithdrawalAccounts,
|
||||
reviewWorkerFinanceRequest,
|
||||
summarizeWorkerFinanceRequests,
|
||||
upsertWorkerWithdrawalAccount,
|
||||
} from './worker-finance-repo.js'
|
||||
|
||||
|
||||
@@ -22,7 +22,12 @@ router.post(
|
||||
'/worker-platform/finance-requests/:requestId/review',
|
||||
requireAdminRoles(['admin', 'operator']),
|
||||
createJsonHandler(
|
||||
(req) => reviewAdminWorkerFinanceRequest(String(req.params.requestId || ''), req.body || {}),
|
||||
(req) =>
|
||||
reviewAdminWorkerFinanceRequest(
|
||||
String(req.params.requestId || ''),
|
||||
req.body || {},
|
||||
req.adminSession?.username || '',
|
||||
),
|
||||
{
|
||||
successMessage: '资金申请已处理',
|
||||
errorMessage: '处理资金申请失败',
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
summarizeWorkerFinanceRequests,
|
||||
addWorkerWalletCredit,
|
||||
getWorkerFinanceRequestById,
|
||||
listWorkerFinanceRequests,
|
||||
@@ -169,25 +170,39 @@ export async function listAdminWorkerFinanceRequests(query: JsonObject = {}) {
|
||||
const keyword = String(query.keyword || '').trim()
|
||||
const createdFrom = normalizeDateString(query.createdFrom)
|
||||
const createdTo = normalizeDateString(query.createdTo)
|
||||
const { items, total } = await listWorkerFinanceRequests({
|
||||
page,
|
||||
pageSize,
|
||||
const accountChannel = ['alipay', 'wechat'].includes(String(query.accountChannel || ''))
|
||||
? String(query.accountChannel)
|
||||
: ''
|
||||
const listFilters = {
|
||||
requestId,
|
||||
status,
|
||||
requestType,
|
||||
keyword,
|
||||
...(createdFrom ? { createdFrom } : {}),
|
||||
...(createdTo ? { createdTo } : {}),
|
||||
})
|
||||
...(accountChannel ? { accountChannel } : {}),
|
||||
}
|
||||
const [listResult, channels] = await Promise.all([
|
||||
listWorkerFinanceRequests({ page, pageSize, ...listFilters }),
|
||||
summarizeWorkerFinanceRequests(listFilters),
|
||||
])
|
||||
const { items, total } = listResult
|
||||
const summary = {
|
||||
channels,
|
||||
totalCount: channels.reduce((sum, item) => sum + item.count, 0),
|
||||
totalAmount: channels.reduce((sum, item) => sum + item.amount, 0),
|
||||
}
|
||||
return {
|
||||
items: items.map(mapFinanceRequest),
|
||||
pagination: { page, pageSize, total },
|
||||
summary,
|
||||
}
|
||||
}
|
||||
|
||||
export async function reviewAdminWorkerFinanceRequest(
|
||||
requestId: number | string,
|
||||
payload: JsonObject = {},
|
||||
reviewedBy = '',
|
||||
) {
|
||||
const current = await getWorkerFinanceRequestById(requestId)
|
||||
if (!current) {
|
||||
@@ -204,6 +219,7 @@ export async function reviewAdminWorkerFinanceRequest(
|
||||
status,
|
||||
reviewedNote,
|
||||
now: nowIso(),
|
||||
reviewedBy: String(reviewedBy || '').trim(),
|
||||
})
|
||||
|
||||
if (reviewed.failureReason === 'request_not_pending') {
|
||||
|
||||
Reference in New Issue
Block a user