修复提现申请冻结余额
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
-- 提现申请改为"申请即冻结"资金模型:
|
||||
-- 1) worker_wallets 新增 frozen_withdraw_amount,申请提现立即从 available_amount 划转到该字段;
|
||||
-- 2) worker_finance_requests 新增 frozen_amount 标记该笔申请是否已冻结资金(0=旧数据未冻结),
|
||||
-- 审核通过/拒绝按此标记选择解冻或旧口径扣款,保证存量数据平滑过渡;
|
||||
-- 3) 仅对迁移后创建的申请生效,存量申请仍按旧口径在审核通过时扣款。
|
||||
|
||||
ALTER TABLE worker_wallets
|
||||
ADD COLUMN IF NOT EXISTS frozen_withdraw_amount INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
ALTER TABLE worker_finance_requests
|
||||
ADD COLUMN IF NOT EXISTS frozen_amount INTEGER NOT NULL DEFAULT 0;
|
||||
@@ -64,6 +64,7 @@ export type WorkerWalletRow = {
|
||||
worker_id: number
|
||||
available_amount: number
|
||||
frozen_deposit_amount: number
|
||||
frozen_withdraw_amount: number
|
||||
pending_unfreeze_amount: number
|
||||
total_credited_amount: number
|
||||
total_settled_amount: number
|
||||
@@ -204,6 +205,8 @@ export type WorkerFinanceRequestRow = {
|
||||
request_type: string
|
||||
status: string
|
||||
amount: number
|
||||
/** 申请时已冻结的资金额度;0 表示旧数据未冻结(迁移前遗留)。 */
|
||||
frozen_amount: number
|
||||
account_channel: string
|
||||
account_name: string
|
||||
account_no: string
|
||||
|
||||
@@ -67,6 +67,91 @@ export async function createWorkerFinanceRequest(input: {
|
||||
return result.rows[0] || null
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建提现申请并在同一事务内立即冻结资金:
|
||||
* available_amount 划入 frozen_withdraw_amount,杜绝"待提现 + 接单押金"双重占用余额。
|
||||
*/
|
||||
export async function createWorkerWithdrawRequestWithFreeze(input: {
|
||||
workerId: number
|
||||
amount: number
|
||||
accountChannel: string
|
||||
accountName: string
|
||||
accountNo: string
|
||||
note: string
|
||||
payloadJson: string
|
||||
now: string
|
||||
}): Promise<
|
||||
| {
|
||||
request: WorkerFinanceRequestRow | null
|
||||
failureReason: 'withdraw_insufficient'
|
||||
}
|
||||
| { request: WorkerFinanceRequestRow; failureReason: null }
|
||||
> {
|
||||
return withTransaction(async (client) => {
|
||||
await ensureWorkerWalletWithClient(client, Number(input.workerId), input.now)
|
||||
const wallet = await getWorkerWalletWithClient(client, Number(input.workerId))
|
||||
const availableAmount = Number(wallet?.available_amount || 0)
|
||||
const frozenWithdrawAmount = Number(wallet?.frozen_withdraw_amount || 0)
|
||||
|
||||
if (availableAmount < input.amount) {
|
||||
return { request: null, failureReason: 'withdraw_insufficient' }
|
||||
}
|
||||
|
||||
const nextAvailable = availableAmount - input.amount
|
||||
const nextFrozenWithdraw = frozenWithdrawAmount + input.amount
|
||||
await client.query(
|
||||
`
|
||||
UPDATE worker_wallets
|
||||
SET available_amount = $1, frozen_withdraw_amount = $2, updated_at = $3
|
||||
WHERE worker_id = $4
|
||||
`,
|
||||
[nextAvailable, nextFrozenWithdraw, input.now, Number(input.workerId)],
|
||||
)
|
||||
await client.query(
|
||||
`
|
||||
INSERT INTO worker_wallet_ledgers (
|
||||
worker_id, ledger_type, amount, balance_after, frozen_after,
|
||||
note, payload_json, created_at
|
||||
) VALUES ($1, 'withdraw_freeze', $2, $3, $4, $5, '{}'::jsonb, $6)
|
||||
`,
|
||||
[
|
||||
Number(input.workerId),
|
||||
-input.amount,
|
||||
nextAvailable,
|
||||
nextFrozenWithdraw,
|
||||
'提现申请冻结余额',
|
||||
input.now,
|
||||
],
|
||||
)
|
||||
|
||||
const createdResult = await client.query<WorkerFinanceRequestRow>(
|
||||
`
|
||||
INSERT INTO worker_finance_requests (
|
||||
worker_id, request_type, status, amount, frozen_amount,
|
||||
account_channel, account_name, account_no,
|
||||
note, reviewed_note, payload_json, created_at, updated_at
|
||||
) VALUES ($1, 'withdraw', 'pending', $2, $2, $3, $4, $5, $6, '', $7::jsonb, $8, $8)
|
||||
RETURNING *
|
||||
`,
|
||||
[
|
||||
Number(input.workerId),
|
||||
input.amount,
|
||||
input.accountChannel,
|
||||
input.accountName,
|
||||
input.accountNo,
|
||||
input.note,
|
||||
input.payloadJson,
|
||||
input.now,
|
||||
],
|
||||
)
|
||||
const request = createdResult.rows[0] || null
|
||||
if (!request) {
|
||||
throw new Error('提现申请创建失败')
|
||||
}
|
||||
return { request, failureReason: null }
|
||||
})
|
||||
}
|
||||
|
||||
export async function getWorkerWithdrawalAccount(
|
||||
workerId: number | string,
|
||||
accountChannel: string,
|
||||
@@ -314,20 +399,30 @@ export async function reviewWorkerFinanceRequest(input: {
|
||||
(current.request_type === 'withdraw' ? '提现申请审核通过' : '充值申请审核通过')
|
||||
|
||||
if (current.request_type === 'withdraw') {
|
||||
if (availableAmount < amount) {
|
||||
const plan = resolveWithdrawApprovalPlan({
|
||||
requestFrozenAmount: Number(current.frozen_amount || 0),
|
||||
frozenWithdrawAmount: Number(wallet?.frozen_withdraw_amount || 0),
|
||||
availableAmount,
|
||||
amount,
|
||||
})
|
||||
if (!plan.ok) {
|
||||
return {
|
||||
request: await getWorkerFinanceRequestByIdWithClient(client, input.requestId),
|
||||
failureReason: 'withdraw_insufficient',
|
||||
failureReason: plan.reason,
|
||||
}
|
||||
}
|
||||
const nextAvailable = availableAmount - amount
|
||||
await client.query(
|
||||
`
|
||||
UPDATE worker_wallets
|
||||
SET available_amount = $1, updated_at = $2
|
||||
WHERE worker_id = $3
|
||||
SET available_amount = $1, frozen_withdraw_amount = $2, updated_at = $3
|
||||
WHERE worker_id = $4
|
||||
`,
|
||||
[nextAvailable, input.now, Number(current.worker_id)],
|
||||
[
|
||||
plan.nextAvailableAmount,
|
||||
plan.nextFrozenWithdrawAmount,
|
||||
input.now,
|
||||
Number(current.worker_id),
|
||||
],
|
||||
)
|
||||
await client.query(
|
||||
`
|
||||
@@ -338,10 +433,10 @@ export async function reviewWorkerFinanceRequest(input: {
|
||||
`,
|
||||
[
|
||||
Number(current.worker_id),
|
||||
-amount,
|
||||
nextAvailable,
|
||||
frozenAmount,
|
||||
note,
|
||||
plan.ledgerAmount,
|
||||
plan.nextAvailableAmount,
|
||||
plan.nextFrozenWithdrawAmount,
|
||||
plan.mode === 'frozen' ? `${note}(申请时已冻结,本次确认打款)` : note,
|
||||
JSON.stringify({
|
||||
requestId: Number(current.id),
|
||||
requestType: current.request_type,
|
||||
@@ -385,6 +480,59 @@ export async function reviewWorkerFinanceRequest(input: {
|
||||
],
|
||||
)
|
||||
}
|
||||
} else if (
|
||||
input.status === 'rejected' &&
|
||||
current.request_type === 'withdraw' &&
|
||||
Number(current.frozen_amount || 0) > 0
|
||||
) {
|
||||
// 新口径:拒绝提现申请时把申请冻结的资金退回可用余额。
|
||||
await ensureWorkerWalletWithClient(client, Number(current.worker_id), input.now)
|
||||
const wallet = await getWorkerWalletWithClient(client, Number(current.worker_id))
|
||||
const release = resolveWithdrawRejectionPlan({
|
||||
requestFrozenAmount: Number(current.frozen_amount || 0),
|
||||
frozenWithdrawAmount: Number(wallet?.frozen_withdraw_amount || 0),
|
||||
availableAmount: Number(wallet?.available_amount || 0),
|
||||
})
|
||||
if (!release.ok) {
|
||||
return {
|
||||
request: await getWorkerFinanceRequestByIdWithClient(client, input.requestId),
|
||||
failureReason: release.reason,
|
||||
}
|
||||
}
|
||||
await client.query(
|
||||
`
|
||||
UPDATE worker_wallets
|
||||
SET available_amount = $1, frozen_withdraw_amount = $2, updated_at = $3
|
||||
WHERE worker_id = $4
|
||||
`,
|
||||
[
|
||||
release.nextAvailableAmount,
|
||||
release.nextFrozenWithdrawAmount,
|
||||
input.now,
|
||||
Number(current.worker_id),
|
||||
],
|
||||
)
|
||||
await client.query(
|
||||
`
|
||||
INSERT INTO worker_wallet_ledgers (
|
||||
worker_id, ledger_type, amount, balance_after, frozen_after,
|
||||
audit_status, note, payload_json, created_at
|
||||
) VALUES ($1, 'withdraw_release', $2, $3, $4, 'approved', $5, $6::jsonb, $7)
|
||||
`,
|
||||
[
|
||||
Number(current.worker_id),
|
||||
release.releaseAmount,
|
||||
release.nextAvailableAmount,
|
||||
release.nextFrozenWithdrawAmount,
|
||||
`${input.reviewedNote || '提现申请审核未通过'},冻结余额已退回`,
|
||||
JSON.stringify({
|
||||
requestId: Number(current.id),
|
||||
requestType: current.request_type,
|
||||
source: 'admin_finance_review',
|
||||
}),
|
||||
input.now,
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
await client.query(
|
||||
@@ -525,3 +673,72 @@ function buildWorkerFinanceRequestWhere({
|
||||
params,
|
||||
}
|
||||
}
|
||||
|
||||
export type WithdrawApprovalPlan =
|
||||
| {
|
||||
ok: true
|
||||
mode: 'frozen' | 'legacy'
|
||||
nextAvailableAmount: number
|
||||
nextFrozenWithdrawAmount: number
|
||||
ledgerAmount: number
|
||||
}
|
||||
| { ok: false; reason: 'withdraw_insufficient' }
|
||||
|
||||
/**
|
||||
* 提现审核通过的资金划转计划。
|
||||
* - frozen 模式(新数据):申请时已冻结,打款确认仅解冻,不动可用余额;
|
||||
* - legacy 模式(迁移前旧数据 frozen_amount=0):沿用"确认时从可用余额扣款"口径。
|
||||
*/
|
||||
export function resolveWithdrawApprovalPlan(input: {
|
||||
requestFrozenAmount: number
|
||||
frozenWithdrawAmount: number
|
||||
availableAmount: number
|
||||
amount: number
|
||||
}): WithdrawApprovalPlan {
|
||||
if (input.requestFrozenAmount > 0) {
|
||||
if (input.frozenWithdrawAmount < input.requestFrozenAmount) {
|
||||
return { ok: false, reason: 'withdraw_insufficient' }
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
mode: 'frozen',
|
||||
nextAvailableAmount: input.availableAmount,
|
||||
nextFrozenWithdrawAmount: input.frozenWithdrawAmount - input.requestFrozenAmount,
|
||||
ledgerAmount: 0,
|
||||
}
|
||||
}
|
||||
if (input.availableAmount < input.amount) {
|
||||
return { ok: false, reason: 'withdraw_insufficient' }
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
mode: 'legacy',
|
||||
nextAvailableAmount: input.availableAmount - input.amount,
|
||||
nextFrozenWithdrawAmount: input.frozenWithdrawAmount,
|
||||
ledgerAmount: -input.amount,
|
||||
}
|
||||
}
|
||||
|
||||
/** 提现审核拒绝时的资金退回计划。 */
|
||||
export function resolveWithdrawRejectionPlan(input: {
|
||||
requestFrozenAmount: number
|
||||
frozenWithdrawAmount: number
|
||||
availableAmount: number
|
||||
}):
|
||||
| {
|
||||
ok: true
|
||||
releaseAmount: number
|
||||
nextAvailableAmount: number
|
||||
nextFrozenWithdrawAmount: number
|
||||
}
|
||||
| { ok: false; reason: 'withdraw_insufficient' } {
|
||||
if (input.frozenWithdrawAmount < input.requestFrozenAmount) {
|
||||
return { ok: false, reason: 'withdraw_insufficient' }
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
releaseAmount: input.requestFrozenAmount,
|
||||
nextAvailableAmount: input.availableAmount + input.requestFrozenAmount,
|
||||
nextFrozenWithdrawAmount: input.frozenWithdrawAmount - input.requestFrozenAmount,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import test from 'node:test'
|
||||
|
||||
import { resolveWithdrawApprovalPlan, resolveWithdrawRejectionPlan } from './worker-finance-repo.js'
|
||||
|
||||
test('提现通过(新口径):申请时已冻结,确认打款只解冻不动可用余额', () => {
|
||||
const plan = resolveWithdrawApprovalPlan({
|
||||
requestFrozenAmount: 8_000,
|
||||
frozenWithdrawAmount: 8_000,
|
||||
availableAmount: 2_000,
|
||||
amount: 8_000,
|
||||
})
|
||||
assert.deepEqual(plan, {
|
||||
ok: true,
|
||||
mode: 'frozen',
|
||||
nextAvailableAmount: 2_000,
|
||||
nextFrozenWithdrawAmount: 0,
|
||||
ledgerAmount: 0,
|
||||
})
|
||||
})
|
||||
|
||||
test('提现通过(新口径):多笔待审时只解冻当前申请的冻结额度', () => {
|
||||
const plan = resolveWithdrawApprovalPlan({
|
||||
requestFrozenAmount: 3_000,
|
||||
frozenWithdrawAmount: 11_000,
|
||||
availableAmount: 5_000,
|
||||
amount: 3_000,
|
||||
})
|
||||
assert.deepEqual(plan, {
|
||||
ok: true,
|
||||
mode: 'frozen',
|
||||
nextAvailableAmount: 5_000,
|
||||
nextFrozenWithdrawAmount: 8_000,
|
||||
ledgerAmount: 0,
|
||||
})
|
||||
})
|
||||
|
||||
test('提现通过(新口径):冻结额度异常不足时拒绝并保持现状', () => {
|
||||
const plan = resolveWithdrawApprovalPlan({
|
||||
requestFrozenAmount: 8_000,
|
||||
frozenWithdrawAmount: 1_000,
|
||||
availableAmount: 9_000,
|
||||
amount: 8_000,
|
||||
})
|
||||
assert.deepEqual(plan, { ok: false, reason: 'withdraw_insufficient' })
|
||||
})
|
||||
|
||||
test('提现通过(旧数据兜底):未冻结申请沿用确认时扣款口径', () => {
|
||||
const plan = resolveWithdrawApprovalPlan({
|
||||
requestFrozenAmount: 0,
|
||||
frozenWithdrawAmount: 0,
|
||||
availableAmount: 10_000,
|
||||
amount: 8_000,
|
||||
})
|
||||
assert.deepEqual(plan, {
|
||||
ok: true,
|
||||
mode: 'legacy',
|
||||
nextAvailableAmount: 2_000,
|
||||
nextFrozenWithdrawAmount: 0,
|
||||
ledgerAmount: -8_000,
|
||||
})
|
||||
})
|
||||
|
||||
test('提现通过(旧数据兜底):可用余额不足时拒绝', () => {
|
||||
const plan = resolveWithdrawApprovalPlan({
|
||||
requestFrozenAmount: 0,
|
||||
frozenWithdrawAmount: 0,
|
||||
availableAmount: 5_000,
|
||||
amount: 8_000,
|
||||
})
|
||||
assert.deepEqual(plan, { ok: false, reason: 'withdraw_insufficient' })
|
||||
})
|
||||
|
||||
test('提现拒绝(新口径):冻结资金全额退回可用余额', () => {
|
||||
const plan = resolveWithdrawRejectionPlan({
|
||||
requestFrozenAmount: 8_000,
|
||||
frozenWithdrawAmount: 8_000,
|
||||
availableAmount: 2_000,
|
||||
})
|
||||
assert.deepEqual(plan, {
|
||||
ok: true,
|
||||
releaseAmount: 8_000,
|
||||
nextAvailableAmount: 10_000,
|
||||
nextFrozenWithdrawAmount: 0,
|
||||
})
|
||||
})
|
||||
|
||||
test('提现拒绝(新口径):多笔待审时只退回当前申请额度', () => {
|
||||
const plan = resolveWithdrawRejectionPlan({
|
||||
requestFrozenAmount: 3_000,
|
||||
frozenWithdrawAmount: 11_000,
|
||||
availableAmount: 4_000,
|
||||
})
|
||||
assert.deepEqual(plan, {
|
||||
ok: true,
|
||||
releaseAmount: 3_000,
|
||||
nextAvailableAmount: 7_000,
|
||||
nextFrozenWithdrawAmount: 8_000,
|
||||
})
|
||||
})
|
||||
|
||||
test('提现拒绝(旧数据):未冻结申请不退回资金', () => {
|
||||
const plan = resolveWithdrawRejectionPlan({
|
||||
requestFrozenAmount: 0,
|
||||
frozenWithdrawAmount: 0,
|
||||
availableAmount: 2_000,
|
||||
})
|
||||
assert.deepEqual(plan, {
|
||||
ok: true,
|
||||
releaseAmount: 0,
|
||||
nextAvailableAmount: 2_000,
|
||||
nextFrozenWithdrawAmount: 0,
|
||||
})
|
||||
})
|
||||
|
||||
test('提现拒绝: 冻结额度异常不足时保持申请待处理', () => {
|
||||
const plan = resolveWithdrawRejectionPlan({
|
||||
requestFrozenAmount: 8_000,
|
||||
frozenWithdrawAmount: 1_000,
|
||||
availableAmount: 9_000,
|
||||
})
|
||||
assert.deepEqual(plan, { ok: false, reason: 'withdraw_insufficient' })
|
||||
})
|
||||
@@ -251,7 +251,7 @@ export async function reviewAdminWorkerFinanceRequest(
|
||||
publishWorkerFinanceRealtimeChange({
|
||||
requestId: Number(reviewed.request.id),
|
||||
workerId: Number(reviewed.request.worker_id),
|
||||
walletChanged: reviewed.request.request_type === 'withdraw' && status === 'approved',
|
||||
walletChanged: reviewed.request.request_type === 'withdraw',
|
||||
})
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
countWorkerWithdrawRequestsOnDay,
|
||||
createWorkerFinanceRequest,
|
||||
getWorkerFinanceRequestSummary,
|
||||
createWorkerWithdrawRequestWithFreeze,
|
||||
getWorkerWithdrawalAccount,
|
||||
listDueDepositUnfreezes,
|
||||
releaseDepositUnfreeze,
|
||||
@@ -164,20 +164,9 @@ export async function createWorkerWithdrawRequest(
|
||||
})
|
||||
}
|
||||
|
||||
const financeSummary = await getWorkerFinanceRequestSummary(worker.id)
|
||||
const availableAmount = Number(worker.available_amount || 0)
|
||||
const availableForWithdraw = Math.max(0, availableAmount - financeSummary.pendingWithdrawAmount)
|
||||
if (amount > availableForWithdraw) {
|
||||
throw createHttpError('可提现余额不足,请先减少提现金额或等待已提交申请处理', {
|
||||
statusCode: 409,
|
||||
errorCode: 'worker_withdraw_amount_insufficient',
|
||||
})
|
||||
}
|
||||
|
||||
const note = String(payload.note || payload.remark || '').trim()
|
||||
const created = await createWorkerFinanceRequest({
|
||||
const created = await createWorkerWithdrawRequestWithFreeze({
|
||||
workerId: worker.id,
|
||||
requestType: 'withdraw',
|
||||
amount,
|
||||
accountChannel,
|
||||
accountName: withdrawalAccount.account_name,
|
||||
@@ -192,25 +181,30 @@ export async function createWorkerWithdrawRequest(
|
||||
}),
|
||||
now: nowIso(),
|
||||
})
|
||||
if (!created) {
|
||||
throw createHttpError('提现申请创建失败', {
|
||||
statusCode: 500,
|
||||
errorCode: 'worker_withdraw_request_create_failed',
|
||||
if (created.failureReason === 'withdraw_insufficient') {
|
||||
throw createHttpError('可提现余额不足,请先减少提现金额或等待已提交申请处理', {
|
||||
statusCode: 409,
|
||||
errorCode: 'worker_withdraw_amount_insufficient',
|
||||
})
|
||||
}
|
||||
const request = created.request
|
||||
await createWorkerWithdrawAdminNotification({
|
||||
requestId: Number(created.id),
|
||||
requestId: Number(request.id),
|
||||
workerName: worker.display_name || worker.username,
|
||||
amountFen: Number(created.amount || amount),
|
||||
channel: created.account_channel,
|
||||
amountFen: Number(request.amount || amount),
|
||||
channel: request.account_channel,
|
||||
})
|
||||
publishWorkerFinanceRealtimeChange({
|
||||
requestId: Number(created.id),
|
||||
requestId: Number(request.id),
|
||||
workerId: Number(worker.id),
|
||||
})
|
||||
publishWorkerWalletRealtimeChange(Number(worker.id))
|
||||
return {
|
||||
request: mapFinanceRequest(created),
|
||||
availableForWithdraw,
|
||||
request: mapFinanceRequest(request),
|
||||
availableForWithdraw: Math.max(
|
||||
0,
|
||||
Number(worker.available_amount || 0) - Number(request.amount || amount),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,9 @@ export function normalizeWalletLedgerType(value: unknown) {
|
||||
if (
|
||||
[
|
||||
'manual_credit',
|
||||
'withdraw_freeze',
|
||||
'withdraw_paid',
|
||||
'withdraw_release',
|
||||
'deposit_freeze',
|
||||
'deposit_release',
|
||||
'deposit_pending_unfreeze',
|
||||
|
||||
@@ -22,7 +22,9 @@ import { formatMoney, formatStatus, formatWorkerStatus, resolveStatusColor } fro
|
||||
/** 与打手端 worker-profile-view-utils 的流水文案保持一致;未知类型原样展示。 */
|
||||
const LEDGER_TYPE_LABELS: Record<string, string> = {
|
||||
manual_credit: '人工充值',
|
||||
withdraw_freeze: '提现冻结',
|
||||
withdraw_paid: '提现打款',
|
||||
withdraw_release: '提现退回',
|
||||
deposit_freeze: '冻结押金',
|
||||
deposit_release: '释放押金',
|
||||
deposit_pending_unfreeze: '待解冻金额',
|
||||
@@ -57,7 +59,9 @@ function resolveLedgerTagColor(ledgerType: string) {
|
||||
return 'red'
|
||||
if (['reward_settlement', 'sharing_reward'].includes(ledgerType)) return 'cyan'
|
||||
if (ledgerType === 'manual_credit') return 'blue'
|
||||
if (ledgerType === 'withdraw_freeze') return 'orange'
|
||||
if (ledgerType === 'withdraw_paid') return 'purple'
|
||||
if (ledgerType === 'withdraw_release') return 'green'
|
||||
return 'default'
|
||||
}
|
||||
|
||||
@@ -287,7 +291,7 @@ function LedgersSection({ workerId }: { workerId: number }) {
|
||||
render: (_, row) => formatMoney(row.balanceAfter),
|
||||
},
|
||||
{
|
||||
title: '冻结押金',
|
||||
title: '冻结金额',
|
||||
width: 110,
|
||||
render: (_, row) => formatMoney(row.frozenAfter),
|
||||
},
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
formatWithdrawChannel,
|
||||
maskAccountNo,
|
||||
renderRechargeRequestSummary,
|
||||
resolveLedgerFrozenAmountLabel,
|
||||
resolveLedgerTagColor,
|
||||
resolveRequestStatusColor,
|
||||
workerFinanceRequestColumns,
|
||||
@@ -26,7 +27,9 @@ import {
|
||||
const LEDGER_TYPE_OPTIONS = [
|
||||
{ value: '', label: '全部流水' },
|
||||
{ value: 'manual_credit', label: '人工充值' },
|
||||
{ value: 'withdraw_freeze', label: '提现冻结' },
|
||||
{ value: 'withdraw_paid', label: '提现打款' },
|
||||
{ value: 'withdraw_release', label: '提现退回' },
|
||||
{ value: 'deposit_freeze', label: '冻结押金' },
|
||||
{ value: 'deposit_release', label: '释放押金' },
|
||||
{ value: 'deposit_pending_unfreeze', label: '待解冻金额' },
|
||||
@@ -132,7 +135,9 @@ export function WorkerProfileMobileLedgerRecords({
|
||||
</div>
|
||||
<div className="worker-profile-record-row-meta">
|
||||
<span>变动后余额: {formatMoney(row.balanceAfter)}</span>
|
||||
<span>冻结押金: {formatMoney(row.frozenAfter)}</span>
|
||||
<span>
|
||||
{resolveLedgerFrozenAmountLabel(row.ledgerType)}: {formatMoney(row.frozenAfter)}
|
||||
</span>
|
||||
</div>
|
||||
{row.note ? <div className="worker-profile-record-note">说明: {row.note}</div> : null}
|
||||
{row.relatedPlatformOrderId ? (
|
||||
|
||||
@@ -11,12 +11,10 @@ import { formatDateTime } from '@/utils/date-time'
|
||||
|
||||
export function resolveAvailableForWithdraw(
|
||||
worker: WorkerUser | undefined,
|
||||
summary: WorkerProfileSummary | undefined,
|
||||
_summary: WorkerProfileSummary | undefined,
|
||||
) {
|
||||
return Math.max(
|
||||
0,
|
||||
Number(worker?.wallet.availableAmount || 0) - Number(summary?.pendingWithdrawAmount || 0),
|
||||
)
|
||||
// 提现申请即冻结 available_amount,可提现口径就是当前可用余额,无需再减待处理申请。
|
||||
return Math.max(0, Number(worker?.wallet.availableAmount || 0))
|
||||
}
|
||||
|
||||
export function resolveWorkerInitial(worker: WorkerUser | undefined) {
|
||||
@@ -49,7 +47,9 @@ export function resolveWorkerStatusColor(status: string) {
|
||||
export function formatLedgerType(ledgerType: string) {
|
||||
const labels: Record<string, string> = {
|
||||
manual_credit: '人工充值',
|
||||
withdraw_freeze: '提现冻结',
|
||||
withdraw_paid: '提现打款',
|
||||
withdraw_release: '提现退回',
|
||||
deposit_freeze: '冻结押金',
|
||||
deposit_release: '释放押金',
|
||||
deposit_pending_unfreeze: '待解冻金额',
|
||||
@@ -67,7 +67,9 @@ export function formatLedgerType(ledgerType: string) {
|
||||
|
||||
export function resolveLedgerTagColor(ledgerType: string) {
|
||||
if (ledgerType === 'manual_credit') return 'blue'
|
||||
if (ledgerType === 'withdraw_freeze') return 'orange'
|
||||
if (ledgerType === 'withdraw_paid') return 'purple'
|
||||
if (ledgerType === 'withdraw_release') return 'green'
|
||||
if (ledgerType === 'deposit_freeze') return 'gold'
|
||||
if (ledgerType === 'deposit_release') return 'green'
|
||||
if (ledgerType === 'deposit_pending_unfreeze') return 'orange'
|
||||
@@ -82,6 +84,12 @@ export function resolveLedgerTagColor(ledgerType: string) {
|
||||
return 'default'
|
||||
}
|
||||
|
||||
export function resolveLedgerFrozenAmountLabel(ledgerType: string) {
|
||||
return ['withdraw_freeze', 'withdraw_paid', 'withdraw_release'].includes(ledgerType)
|
||||
? '提现冻结'
|
||||
: '冻结押金'
|
||||
}
|
||||
|
||||
export function formatRequestType(requestType: string) {
|
||||
if (requestType === 'recharge') return '充值申请'
|
||||
if (requestType === 'withdraw') return '提现申请'
|
||||
@@ -180,7 +188,7 @@ export const workerLedgerColumns: TableColumnsType<WorkerWalletLedger> = [
|
||||
),
|
||||
},
|
||||
{ title: '余额', width: 120, render: (_, row) => formatMoney(row.balanceAfter) },
|
||||
{ title: '冻结押金', width: 120, render: (_, row) => formatMoney(row.frozenAfter) },
|
||||
{ title: '冻结金额', width: 120, render: (_, row) => formatMoney(row.frozenAfter) },
|
||||
{
|
||||
title: '说明',
|
||||
minWidth: 260,
|
||||
|
||||
Reference in New Issue
Block a user