新增财务申请时间类型筛选

This commit is contained in:
yml2213
2026-09-02 14:32:26 +08:00
parent bf167d98ed
commit 625df52992
8 changed files with 162 additions and 33 deletions
@@ -513,6 +513,9 @@ export type FinanceRequestListInput = {
/** 申请时间区间(YYYY-MM-DD 含全天,或 YYYY-MM-DD HH:mm:ss 精确到秒;上海时区);后台列表筛选使用。 */ /** 申请时间区间(YYYY-MM-DD 含全天,或 YYYY-MM-DD HH:mm:ss 精确到秒;上海时区);后台列表筛选使用。 */
createdFrom?: string createdFrom?: string
createdTo?: string createdTo?: string
/** 后台审核通过时间区间(上海时区);仅匹配已审核通过的申请。 */
reviewedFrom?: string
reviewedTo?: string
/** 收款渠道筛选:alipay / wechat */ /** 收款渠道筛选:alipay / wechat */
accountChannel?: string accountChannel?: string
} }
@@ -290,6 +290,8 @@ export async function listWorkerFinanceRequests({
keyword = '', keyword = '',
createdFrom = '', createdFrom = '',
createdTo = '', createdTo = '',
reviewedFrom = '',
reviewedTo = '',
accountChannel = '', accountChannel = '',
}: FinanceRequestListInput = {}): Promise<{ items: WorkerFinanceRequestRow[]; total: number }> { }: FinanceRequestListInput = {}): Promise<{ items: WorkerFinanceRequestRow[]; total: number }> {
const { whereClause, params } = buildWorkerFinanceRequestWhere({ const { whereClause, params } = buildWorkerFinanceRequestWhere({
@@ -300,6 +302,8 @@ export async function listWorkerFinanceRequests({
keyword, keyword,
createdFrom, createdFrom,
createdTo, createdTo,
reviewedFrom,
reviewedTo,
accountChannel, accountChannel,
}) })
const totalResult = await query<{ total: number }>( const totalResult = await query<{ total: number }>(
@@ -335,6 +339,8 @@ export async function summarizeWorkerFinanceRequests(
keyword: input.keyword || '', keyword: input.keyword || '',
createdFrom: input.createdFrom || '', createdFrom: input.createdFrom || '',
createdTo: input.createdTo || '', createdTo: input.createdTo || '',
reviewedFrom: input.reviewedFrom || '',
reviewedTo: input.reviewedTo || '',
accountChannel: input.accountChannel || '', accountChannel: input.accountChannel || '',
}) })
const result = await query<{ channel: string; total: number; amount: string | number }>( const result = await query<{ channel: string; total: number; amount: string | number }>(
@@ -612,7 +618,7 @@ async function getWorkerFinanceRequestByIdWithClient(
return result.rows[0] || null return result.rows[0] || null
} }
function buildWorkerFinanceRequestWhere({ export function buildWorkerFinanceRequestWhere({
requestId = 0, requestId = 0,
workerId = 0, workerId = 0,
status = '', status = '',
@@ -620,6 +626,8 @@ function buildWorkerFinanceRequestWhere({
keyword = '', keyword = '',
createdFrom = '', createdFrom = '',
createdTo = '', createdTo = '',
reviewedFrom = '',
reviewedTo = '',
accountChannel = '', accountChannel = '',
}: FinanceRequestListInput) { }: FinanceRequestListInput) {
const filters: string[] = [] const filters: string[] = []
@@ -642,6 +650,22 @@ function buildWorkerFinanceRequestWhere({
: `wfr.created_at < (($${params.length}::date + 1)::timestamp) AT TIME ZONE 'Asia/Shanghai'`, : `wfr.created_at < (($${params.length}::date + 1)::timestamp) AT TIME ZONE 'Asia/Shanghai'`,
) )
} }
if (reviewedFrom || reviewedTo) {
// “审核通过时间”只适用于已通过的申请;待处理、拒绝和取消记录不参与该时间筛选。
filters.push(`wfr.status = 'approved'`)
}
if (reviewedFrom) {
params.push(reviewedFrom)
filters.push(`wfr.reviewed_at >= ($${params.length}::timestamp) AT TIME ZONE 'Asia/Shanghai'`)
}
if (reviewedTo) {
params.push(reviewedTo)
filters.push(
reviewedTo.length > 10
? `wfr.reviewed_at <= ($${params.length}::timestamp) AT TIME ZONE 'Asia/Shanghai'`
: `wfr.reviewed_at < (($${params.length}::date + 1)::timestamp) AT TIME ZONE 'Asia/Shanghai'`,
)
}
if (requestId) { if (requestId) {
params.push(requestId) params.push(requestId)
filters.push(`wfr.id = $${params.length}`) filters.push(`wfr.id = $${params.length}`)
@@ -1,7 +1,32 @@
import assert from 'node:assert/strict' import assert from 'node:assert/strict'
import test from 'node:test' import test from 'node:test'
import { resolveWithdrawApprovalPlan, resolveWithdrawRejectionPlan } from './worker-finance-repo.js' import {
buildWorkerFinanceRequestWhere,
resolveWithdrawApprovalPlan,
resolveWithdrawRejectionPlan,
} from './worker-finance-repo.js'
test('资金申请列表支持按打手申请时间和后台审核通过时间筛选', () => {
const result = buildWorkerFinanceRequestWhere({
createdFrom: '2026-09-01 10:00:00',
createdTo: '2026-09-01 18:30:59',
reviewedFrom: '2026-09-02',
reviewedTo: '2026-09-03',
})
assert.deepEqual(result.params, [
'2026-09-01 10:00:00',
'2026-09-01 18:30:59',
'2026-09-02',
'2026-09-03',
])
assert.match(result.whereClause, /wfr\.created_at >= \(\$1::timestamp\)/)
assert.match(result.whereClause, /wfr\.created_at <= \(\$2::timestamp\)/)
assert.match(result.whereClause, /wfr\.status = 'approved'/)
assert.match(result.whereClause, /wfr\.reviewed_at >= \(\$3::timestamp\)/)
assert.match(result.whereClause, /wfr\.reviewed_at < \(\(\$4::date \+ 1\)::timestamp\)/)
})
test('提现通过(新口径):申请时已冻结,确认打款只解冻不动可用余额', () => { test('提现通过(新口径):申请时已冻结,确认打款只解冻不动可用余额', () => {
const plan = resolveWithdrawApprovalPlan({ const plan = resolveWithdrawApprovalPlan({
@@ -23,7 +23,9 @@ const FINANCE_EVENTS_CTE = `
o.total_amount::bigint AS amount, o.total_amount::bigint AS amount,
'订单收款'::text AS label, '订单收款'::text AS label,
o.platform_order_id::text AS reference_no, o.platform_order_id::text AS reference_no,
COALESCE(NULLIF(CONCAT_WS('/', NULLIF(o.provider, ''), NULLIF(o.platform, '')), ''), '其他')::text AS channel COALESCE(NULLIF(CONCAT_WS('/', NULLIF(o.provider, ''), NULLIF(o.platform, '')), ''), '其他')::text AS channel,
o.created_at AS request_created_at,
NULL::timestamptz AS request_reviewed_at
FROM orders o FROM orders o
WHERE o.pay_status IN ('paid', 'refunded') WHERE o.pay_status IN ('paid', 'refunded')
AND o.total_amount > 0 AND o.total_amount > 0
@@ -37,7 +39,9 @@ const FINANCE_EVENTS_CTE = `
o.total_amount::bigint, o.total_amount::bigint,
'订单退款'::text, '订单退款'::text,
o.platform_order_id::text, o.platform_order_id::text,
COALESCE(NULLIF(CONCAT_WS('/', NULLIF(o.provider, ''), NULLIF(o.platform, '')), ''), '其他')::text COALESCE(NULLIF(CONCAT_WS('/', NULLIF(o.provider, ''), NULLIF(o.platform, '')), ''), '其他')::text,
o.created_at,
NULL::timestamptz
FROM orders o FROM orders o
WHERE o.pay_status = 'refunded' WHERE o.pay_status = 'refunded'
AND o.total_amount > 0 AND o.total_amount > 0
@@ -53,7 +57,9 @@ const FINANCE_EVENTS_CTE = `
CASE WHEN wl.ledger_type IN ('reward_settlement', 'sharing_reward') CASE WHEN wl.ledger_type IN ('reward_settlement', 'sharing_reward')
THEN '打手报酬' ELSE '打手资金回收' END::text, THEN '打手报酬' ELSE '打手资金回收' END::text,
COALESCE(wl.related_work_order_id::text, ''), COALESCE(wl.related_work_order_id::text, ''),
'worker-platform'::text 'worker-platform'::text,
wl.created_at,
NULL::timestamptz
FROM worker_wallet_ledgers wl FROM worker_wallet_ledgers wl
WHERE wl.ledger_type IN ( WHERE wl.ledger_type IN (
'reward_settlement', 'sharing_reward', 'after_sales_deposit_deduction', 'reward_settlement', 'sharing_reward', 'after_sales_deposit_deduction',
@@ -70,7 +76,9 @@ const FINANCE_EVENTS_CTE = `
wfr.amount::bigint, wfr.amount::bigint,
'打手提现'::text, '打手提现'::text,
wfr.account_channel::text, wfr.account_channel::text,
COALESCE(NULLIF(wfr.account_channel, ''), '其他')::text COALESCE(NULLIF(wfr.account_channel, ''), '其他')::text,
wfr.created_at,
wfr.reviewed_at
FROM worker_finance_requests wfr FROM worker_finance_requests wfr
WHERE wfr.request_type = 'withdraw' WHERE wfr.request_type = 'withdraw'
AND wfr.status = 'approved' AND wfr.status = 'approved'
@@ -86,7 +94,9 @@ const FINANCE_EVENTS_CTE = `
wfr.amount::bigint, wfr.amount::bigint,
'打手充值'::text, '打手充值'::text,
wfr.account_channel::text, wfr.account_channel::text,
COALESCE(NULLIF(wfr.account_channel, ''), '其他')::text COALESCE(NULLIF(wfr.account_channel, ''), '其他')::text,
wfr.created_at,
wfr.reviewed_at
FROM worker_finance_requests wfr FROM worker_finance_requests wfr
WHERE wfr.request_type = 'recharge' WHERE wfr.request_type = 'recharge'
AND wfr.status = 'approved' AND wfr.status = 'approved'
@@ -102,7 +112,9 @@ const FINANCE_EVENTS_CTE = `
wasc.refunded_amount::bigint, wasc.refunded_amount::bigint,
'售后追缴退还'::text, '售后追缴退还'::text,
wasc.case_no::text, wasc.case_no::text,
'worker-platform'::text 'worker-platform'::text,
wasc.created_at,
NULL::timestamptz
FROM worker_after_sales_cases wasc FROM worker_after_sales_cases wasc
WHERE wasc.refunded_at IS NOT NULL WHERE wasc.refunded_at IS NOT NULL
AND wasc.refunded_amount > 0 AND wasc.refunded_amount > 0
@@ -111,6 +123,8 @@ const FINANCE_EVENTS_CTE = `
export async function getAdminFinanceSummary(payload: JsonObject = {}) { export async function getAdminFinanceSummary(payload: JsonObject = {}) {
const range = resolveFinanceRange(payload, nowIso()) const range = resolveFinanceRange(payload, nowIso())
const dateType = normalizeFinanceDateType(payload.dateType)
const eventDateExpression = resolveFinanceEventDateExpression(dateType)
const [dailyResult, snapshotResult] = await Promise.all([ const [dailyResult, snapshotResult] = await Promise.all([
query<FinanceDailyRow>( query<FinanceDailyRow>(
`${FINANCE_EVENTS_CTE} `${FINANCE_EVENTS_CTE}
@@ -126,10 +140,10 @@ export async function getAdminFinanceSummary(payload: JsonObject = {}) {
COALESCE(SUM(amount) FILTER (WHERE category = 'worker_recovery'), 0)::bigint AS worker_recovery_amount COALESCE(SUM(amount) FILTER (WHERE category = 'worker_recovery'), 0)::bigint AS worker_recovery_amount
FROM generate_series($3::timestamptz, $4::timestamptz - interval '1 day', interval '1 day') day FROM generate_series($3::timestamptz, $4::timestamptz - interval '1 day', interval '1 day') day
LEFT JOIN finance_events event LEFT JOIN finance_events event
ON event.occurred_at >= $1::timestamptz ON ${eventDateExpression} >= $1::timestamptz
AND event.occurred_at < $2::timestamptz AND ${eventDateExpression} < $2::timestamptz
AND event.occurred_at >= day AND ${eventDateExpression} >= day
AND event.occurred_at < day + interval '1 day' AND ${eventDateExpression} < day + interval '1 day'
GROUP BY day GROUP BY day
ORDER BY day DESC`, ORDER BY day DESC`,
[range.from, range.to, range.bucketFrom, range.bucketTo], [range.from, range.to, range.bucketFrom, range.bucketTo],
@@ -151,14 +165,14 @@ export async function getAdminFinanceSummary(payload: JsonObject = {}) {
const channelDailyResult = await query<FinanceChannelDailyRow>( const channelDailyResult = await query<FinanceChannelDailyRow>(
`${FINANCE_EVENTS_CTE} `${FINANCE_EVENTS_CTE}
SELECT SELECT
to_char(event.occurred_at AT TIME ZONE 'Asia/Shanghai', 'YYYY-MM-DD') AS day, to_char(${eventDateExpression} AT TIME ZONE 'Asia/Shanghai', 'YYYY-MM-DD') AS day,
event.channel, event.channel,
event.category, event.category,
COUNT(*)::int AS total, COUNT(*)::int AS total,
COALESCE(SUM(event.amount), 0)::bigint AS amount COALESCE(SUM(event.amount), 0)::bigint AS amount
FROM finance_events event FROM finance_events event
WHERE event.occurred_at >= $1::timestamptz WHERE ${eventDateExpression} >= $1::timestamptz
AND event.occurred_at < $2::timestamptz AND ${eventDateExpression} < $2::timestamptz
GROUP BY 1, 2, 3 GROUP BY 1, 2, 3
ORDER BY day DESC, event.channel ASC, event.category ASC`, ORDER BY day DESC, event.channel ASC, event.category ASC`,
[range.from, range.to], [range.from, range.to],
@@ -203,6 +217,8 @@ export async function getAdminFinanceSummary(payload: JsonObject = {}) {
export async function listAdminFinanceTransactions(payload: JsonObject = {}) { export async function listAdminFinanceTransactions(payload: JsonObject = {}) {
const range = resolveFinanceRange(payload, nowIso()) const range = resolveFinanceRange(payload, nowIso())
const dateType = normalizeFinanceDateType(payload.dateType)
const eventDateExpression = resolveFinanceEventDateExpression(dateType)
const page = normalizePositiveInt(payload.page, 1) const page = normalizePositiveInt(payload.page, 1)
const pageSize = Math.min(normalizePositiveInt(payload.pageSize, 20), 100) const pageSize = Math.min(normalizePositiveInt(payload.pageSize, 20), 100)
const category = String(payload.category || '').trim() const category = String(payload.category || '').trim()
@@ -226,8 +242,8 @@ export async function listAdminFinanceTransactions(payload: JsonObject = {}) {
`${FINANCE_EVENTS_CTE} `${FINANCE_EVENTS_CTE}
SELECT COUNT(*)::int AS total SELECT COUNT(*)::int AS total
FROM finance_events event FROM finance_events event
WHERE event.occurred_at >= $1 WHERE ${eventDateExpression} >= $1
AND event.occurred_at < $2${categoryClause}${channelClause}`, AND ${eventDateExpression} < $2${categoryClause}${channelClause}`,
params, params,
) )
const itemsParams = [...params, pageSize, offset] const itemsParams = [...params, pageSize, offset]
@@ -235,9 +251,9 @@ export async function listAdminFinanceTransactions(payload: JsonObject = {}) {
`${FINANCE_EVENTS_CTE} `${FINANCE_EVENTS_CTE}
SELECT category, source_id, occurred_at, amount, label, reference_no, channel SELECT category, source_id, occurred_at, amount, label, reference_no, channel
FROM finance_events event FROM finance_events event
WHERE event.occurred_at >= $1 WHERE ${eventDateExpression} >= $1
AND event.occurred_at < $2${categoryClause}${channelClause} AND ${eventDateExpression} < $2${categoryClause}${channelClause}
ORDER BY event.occurred_at DESC, event.source_id DESC ORDER BY ${eventDateExpression} DESC, event.source_id DESC
LIMIT $${itemsParams.length - 1} OFFSET $${itemsParams.length}`, LIMIT $${itemsParams.length - 1} OFFSET $${itemsParams.length}`,
itemsParams, itemsParams,
) )
@@ -385,6 +401,18 @@ function normalizePositiveInt(value: unknown, fallback: number) {
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback
} }
function normalizeFinanceDateType(value: unknown): 'occurred' | 'created' | 'reviewed' {
const normalized = String(value || '').trim()
if (normalized === 'created' || normalized === 'reviewed') return normalized
return 'occurred'
}
function resolveFinanceEventDateExpression(dateType: 'occurred' | 'created' | 'reviewed') {
if (dateType === 'created') return 'COALESCE(event.request_created_at, event.occurred_at)'
if (dateType === 'reviewed') return 'event.request_reviewed_at'
return 'event.occurred_at'
}
function normalizeDateTimeDate(value: string) { function normalizeDateTimeDate(value: string) {
const match = value.trim().match(/^(\d{4}-\d{2}-\d{2})/) const match = value.trim().match(/^(\d{4}-\d{2}-\d{2})/)
if (!match || Number.isNaN(Date.parse(`${match[1]}T00:00:00Z`))) return '' if (!match || Number.isNaN(Date.parse(`${match[1]}T00:00:00Z`))) return ''
@@ -170,6 +170,8 @@ export async function listAdminWorkerFinanceRequests(query: JsonObject = {}) {
const keyword = String(query.keyword || '').trim() const keyword = String(query.keyword || '').trim()
const createdFrom = normalizeDateTimeString(query.createdFrom) const createdFrom = normalizeDateTimeString(query.createdFrom)
const createdTo = normalizeDateTimeString(query.createdTo) const createdTo = normalizeDateTimeString(query.createdTo)
const reviewedFrom = normalizeDateTimeString(query.reviewedFrom)
const reviewedTo = normalizeDateTimeString(query.reviewedTo)
const accountChannel = ['alipay', 'wechat'].includes(String(query.accountChannel || '')) const accountChannel = ['alipay', 'wechat'].includes(String(query.accountChannel || ''))
? String(query.accountChannel) ? String(query.accountChannel)
: '' : ''
@@ -180,6 +182,8 @@ export async function listAdminWorkerFinanceRequests(query: JsonObject = {}) {
keyword, keyword,
...(createdFrom ? { createdFrom } : {}), ...(createdFrom ? { createdFrom } : {}),
...(createdTo ? { createdTo } : {}), ...(createdTo ? { createdTo } : {}),
...(reviewedFrom ? { reviewedFrom } : {}),
...(reviewedTo ? { reviewedTo } : {}),
...(accountChannel ? { accountChannel } : {}), ...(accountChannel ? { accountChannel } : {}),
} }
const [listResult, channels] = await Promise.all([ const [listResult, channels] = await Promise.all([
@@ -20,7 +20,11 @@ import { useState } from 'react'
import { AdminRangePicker } from '@/components/admin/AdminDatePicker' import { AdminRangePicker } from '@/components/admin/AdminDatePicker'
import PageHeader from '@/components/admin/PageHeader' import PageHeader from '@/components/admin/PageHeader'
import dayjs from '@/lib/dayjs' import dayjs from '@/lib/dayjs'
import { fetchAdminFinanceSummary, fetchAdminFinanceTransactions } from '@/services/admin' import {
fetchAdminFinanceSummary,
fetchAdminFinanceTransactions,
type AdminFinanceDateType,
} from '@/services/admin'
import type { import type {
AdminFinanceChannelDailyItem, AdminFinanceChannelDailyItem,
AdminFinanceDailyItem, AdminFinanceDailyItem,
@@ -30,7 +34,7 @@ import { ADMIN_DEFAULT_PAGE_SIZE, buildAdminTablePagination } from '@/utils/admi
import { formatAdminDateTime } from '@/utils/admin-time' import { formatAdminDateTime } from '@/utils/admin-time'
import { formatMoney } from './panels/shared' import { formatMoney } from './panels/shared'
type FinanceFilterForm = { dateRange?: unknown } type FinanceFilterForm = { dateRange?: unknown; dateType?: AdminFinanceDateType }
const CATEGORY_OPTIONS = [ const CATEGORY_OPTIONS = [
{ value: '', label: '全部账目' }, { value: '', label: '全部账目' },
@@ -45,7 +49,11 @@ const CATEGORY_OPTIONS = [
export default function AdminFinancePage() { export default function AdminFinancePage() {
const [form] = Form.useForm<FinanceFilterForm>() const [form] = Form.useForm<FinanceFilterForm>()
const [filters, setFilters] = useState({ dateFrom: '', dateTo: '' }) const [filters, setFilters] = useState<{
dateFrom: string
dateTo: string
dateType: AdminFinanceDateType
}>({ dateFrom: '', dateTo: '', dateType: 'occurred' })
const [category, setCategory] = useState('') const [category, setCategory] = useState('')
const [channel, setChannel] = useState('') const [channel, setChannel] = useState('')
const [channelSummaryFilter, setChannelSummaryFilter] = useState('') const [channelSummaryFilter, setChannelSummaryFilter] = useState('')
@@ -83,7 +91,7 @@ export default function AdminFinancePage() {
? dayjs(range[1]).second(59).format('YYYY-MM-DD HH:mm:ss') ? dayjs(range[1]).second(59).format('YYYY-MM-DD HH:mm:ss')
: '' : ''
setPage(1) setPage(1)
setFilters({ dateFrom, dateTo }) setFilters({ dateFrom, dateTo, dateType: values.dateType || 'occurred' })
} }
function resetFilters() { function resetFilters() {
@@ -92,7 +100,7 @@ export default function AdminFinancePage() {
setChannel('') setChannel('')
setChannelSummaryFilter('') setChannelSummaryFilter('')
setPage(1) setPage(1)
setFilters({ dateFrom: '', dateTo: '' }) setFilters({ dateFrom: '', dateTo: '', dateType: 'occurred' })
} }
const dailyColumns: TableColumnsType<AdminFinanceDailyItem> = [ const dailyColumns: TableColumnsType<AdminFinanceDailyItem> = [
@@ -161,7 +169,17 @@ export default function AdminFinancePage() {
className="filter-form" className="filter-form"
onFinish={applyFilters} onFinish={applyFilters}
> >
<Form.Item name="dateRange" label="账务日期"> <Form.Item name="dateType" label="时间类型" initialValue="occurred">
<Select
style={{ width: 160 }}
options={[
{ value: 'occurred', label: '账务发生时间' },
{ value: 'created', label: '打手申请时间' },
{ value: 'reviewed', label: '审核通过时间' },
]}
/>
</Form.Item>
<Form.Item name="dateRange" label="时间范围">
<AdminRangePicker showTime={{ format: 'HH:mm' }} format="YYYY-MM-DD HH:mm" /> <AdminRangePicker showTime={{ format: 'HH:mm' }} format="YYYY-MM-DD HH:mm" />
</Form.Item> </Form.Item>
<Form.Item> <Form.Item>
@@ -61,6 +61,7 @@ type FinanceConfigFormValues = {
} }
type FinanceReviewAction = 'approved' | 'rejected' | 'cancelled' type FinanceReviewAction = 'approved' | 'rejected' | 'cancelled'
type FinanceRequestDateType = 'created' | 'reviewed'
export default function FinancePanel() { export default function FinancePanel() {
const { message } = App.useApp() const { message } = App.useApp()
@@ -74,7 +75,8 @@ export default function FinancePanel() {
const [requestType, setRequestType] = useState('') const [requestType, setRequestType] = useState('')
const [keywordInput, setKeywordInput] = useState('') const [keywordInput, setKeywordInput] = useState('')
const [keyword, setKeyword] = useState('') const [keyword, setKeyword] = useState('')
const [createdRange, setCreatedRange] = useState<[string, string] | null>(null) const [requestDateType, setRequestDateType] = useState<FinanceRequestDateType>('created')
const [requestDateRange, setRequestDateRange] = useState<[string, string] | null>(null)
const [accountChannel, setAccountChannel] = useState('') const [accountChannel, setAccountChannel] = useState('')
const [page, setPage] = useState(1) const [page, setPage] = useState(1)
const [pageSize, setPageSize] = useState(ADMIN_DEFAULT_PAGE_SIZE) const [pageSize, setPageSize] = useState(ADMIN_DEFAULT_PAGE_SIZE)
@@ -116,8 +118,9 @@ export default function FinancePanel() {
keyword, keyword,
page, page,
pageSize, pageSize,
createdRange ? createdRange[0] : '', requestDateType,
createdRange ? createdRange[1] : '', requestDateRange ? requestDateRange[0] : '',
requestDateRange ? requestDateRange[1] : '',
accountChannel, accountChannel,
], ],
queryFn: () => queryFn: () =>
@@ -129,7 +132,11 @@ export default function FinancePanel() {
page, page,
pageSize, pageSize,
accountChannel, accountChannel,
...(createdRange ? { createdFrom: createdRange[0], createdTo: createdRange[1] } : {}), ...(requestDateRange
? requestDateType === 'created'
? { createdFrom: requestDateRange[0], createdTo: requestDateRange[1] }
: { reviewedFrom: requestDateRange[0], reviewedTo: requestDateRange[1] }
: {}),
}), }),
}) })
const financeRequestsPagination = financeRequestsQuery.data?.data.pagination const financeRequestsPagination = financeRequestsQuery.data?.data.pagination
@@ -507,16 +514,31 @@ export default function FinancePanel() {
setPage(1) setPage(1)
}} }}
/> />
<Select
value={requestDateType}
style={{ width: 150 }}
options={[
{ value: 'created', label: '申请提现时间' },
{ value: 'reviewed', label: '审核通过时间' },
]}
onChange={(nextType: FinanceRequestDateType) => {
setRequestDateType(nextType)
setPage(1)
}}
/>
<AdminRangePicker <AdminRangePicker
placeholder={['请选择时间范围', '请选择时间范围']}
format="YYYY-MM-DD HH:mm" format="YYYY-MM-DD HH:mm"
showTime={{ showTime={{
format: 'HH:mm', format: 'HH:mm',
defaultValue: [dayjs('00:00:00', 'HH:mm:ss'), dayjs('23:59:59', 'HH:mm:ss')], defaultValue: [dayjs('00:00:00', 'HH:mm:ss'), dayjs('23:59:59', 'HH:mm:ss')],
}} }}
value={createdRange ? [dayjs(createdRange[0]), dayjs(createdRange[1])] : null} value={
requestDateRange ? [dayjs(requestDateRange[0]), dayjs(requestDateRange[1])] : null
}
onChange={(dates) => { onChange={(dates) => {
const [start, end] = dates || [] const [start, end] = dates || []
setCreatedRange( setRequestDateRange(
start && end start && end
? [ ? [
// 起止各占满整分钟:开始 xx:00、结束 xx:59 // 起止各占满整分钟:开始 xx:00、结束 xx:59
+6 -1
View File
@@ -1,7 +1,11 @@
import { apiGet } from '@/lib/http' import { apiGet } from '@/lib/http'
import type { AdminFinanceSummary, AdminFinanceTransactionResult } from '@/types/admin/finance' import type { AdminFinanceSummary, AdminFinanceTransactionResult } from '@/types/admin/finance'
export function fetchAdminFinanceSummary(params: { dateFrom?: string; dateTo?: string } = {}) { export type AdminFinanceDateType = 'occurred' | 'created' | 'reviewed'
export function fetchAdminFinanceSummary(
params: { dateFrom?: string; dateTo?: string; dateType?: AdminFinanceDateType } = {},
) {
return apiGet<AdminFinanceSummary>('/api/v1/admin/finance/summary', params) return apiGet<AdminFinanceSummary>('/api/v1/admin/finance/summary', params)
} }
@@ -9,6 +13,7 @@ export function fetchAdminFinanceTransactions(
params: { params: {
dateFrom?: string dateFrom?: string
dateTo?: string dateTo?: string
dateType?: AdminFinanceDateType
category?: string category?: string
channel?: string channel?: string
page?: number page?: number