完善个人中心资金功能

This commit is contained in:
yml2213
2026-07-28 10:41:46 +08:00
parent dca45afcc8
commit 2ab80c4df8
8 changed files with 1960 additions and 23 deletions
@@ -31,6 +31,8 @@ export type WorkerUserRow = {
level_permission_json?: string | Record<string, unknown>
available_amount?: number
frozen_deposit_amount?: number
total_credited_amount?: number
total_settled_amount?: number
}
export type WorkerWalletRow = {
@@ -43,6 +45,37 @@ export type WorkerWalletRow = {
updated_at: string
}
export type WorkerWalletLedgerRow = {
id: number
worker_id: number
ledger_type: string
amount: number
balance_after: number
frozen_after: number
related_work_order_id: number | null
audit_status: string
note: string
payload_json: string | Record<string, unknown>
created_at: string
}
export type WorkerFinanceRequestRow = {
id: number
worker_id: number
request_type: string
status: string
amount: number
account_channel: string
account_name: string
account_no: string
note: string
reviewed_note: string
payload_json: string | Record<string, unknown>
created_at: string
updated_at: string
reviewed_at: string | null
}
export type WorkCategoryRow = {
id: number
category_key: string
@@ -133,6 +166,21 @@ type ProductRuleListInput = {
keyword?: string
}
type WalletLedgerListInput = {
page?: number
pageSize?: number
workerId?: number
ledgerType?: string
}
type FinanceRequestListInput = {
page?: number
pageSize?: number
workerId?: number
status?: string
requestType?: string
}
type CreateWorkerInput = {
username: string
passwordHash: string
@@ -167,7 +215,9 @@ const WORKER_USER_SELECT = `
wl.name AS level_name,
wl.permission_json AS level_permission_json,
ww.available_amount,
ww.frozen_deposit_amount
ww.frozen_deposit_amount,
ww.total_credited_amount,
ww.total_settled_amount
FROM worker_users wu
LEFT JOIN worker_levels wl ON wl.id = wu.level_id
LEFT JOIN worker_wallets ww ON ww.worker_id = wu.id
@@ -333,6 +383,30 @@ export async function updateWorkerUser(
return getWorkerUserById(workerId)
}
export async function updateWorkerPassword(input: {
workerId: number
passwordHash: string
sessionVersion: number
now: string
}): Promise<WorkerUserRow | null> {
const result = await query<{ id: number }>(
`
UPDATE worker_users
SET
password_hash = $1,
session_version = $2,
updated_at = $3
WHERE id = $4
RETURNING id
`,
[input.passwordHash, input.sessionVersion, input.now, input.workerId],
)
if (!result.rows[0]) {
return null
}
return getWorkerUserById(input.workerId)
}
export async function incrementWorkerSessionVersion(
workerId: number | string,
now: string,
@@ -394,6 +468,38 @@ export async function getWorkerWallet(workerId: number | string): Promise<Worker
return result.rows[0] || null
}
export async function listWorkerWalletLedgers({
page = 1,
pageSize = 20,
workerId = 0,
ledgerType = '',
}: WalletLedgerListInput = {}): Promise<{ items: WorkerWalletLedgerRow[]; total: number }> {
const { whereClause, params } = buildWorkerWalletLedgerWhere({
workerId,
ledgerType,
})
const totalResult = await query<{ total: number }>(
`SELECT COUNT(*)::int AS total FROM worker_wallet_ledgers wwl ${whereClause}`,
params,
)
const offset = (page - 1) * pageSize
params.push(pageSize, offset)
const itemsResult = await query<WorkerWalletLedgerRow>(
`
SELECT *
FROM worker_wallet_ledgers wwl
${whereClause}
ORDER BY wwl.created_at DESC, wwl.id DESC
LIMIT $${params.length - 1} OFFSET $${params.length}
`,
params,
)
return {
items: itemsResult.rows,
total: Number(totalResult.rows[0]?.total || 0),
}
}
export async function addWorkerWalletCredit(input: {
workerId: number
amount: number
@@ -438,6 +544,121 @@ export async function addWorkerWalletCredit(input: {
})
}
export async function createWorkerFinanceRequest(input: {
workerId: number
requestType: string
amount: number
accountChannel: string
accountName: string
accountNo: string
note: string
payloadJson: string
now: string
}): Promise<WorkerFinanceRequestRow | null> {
const result = await query<WorkerFinanceRequestRow>(
`
INSERT INTO worker_finance_requests (
worker_id, request_type, status, amount,
account_channel, account_name, account_no,
note, reviewed_note, payload_json, created_at, updated_at
) VALUES ($1, $2, 'pending', $3, $4, $5, $6, $7, '', $8::jsonb, $9, $10)
RETURNING *
`,
[
input.workerId,
input.requestType,
input.amount,
input.accountChannel,
input.accountName,
input.accountNo,
input.note,
input.payloadJson,
input.now,
input.now,
],
)
return result.rows[0] || null
}
export async function listWorkerFinanceRequests({
page = 1,
pageSize = 20,
workerId = 0,
status = '',
requestType = '',
}: FinanceRequestListInput = {}): Promise<{ items: WorkerFinanceRequestRow[]; total: number }> {
const { whereClause, params } = buildWorkerFinanceRequestWhere({
workerId,
status,
requestType,
})
const totalResult = await query<{ total: number }>(
`SELECT COUNT(*)::int AS total FROM worker_finance_requests wfr ${whereClause}`,
params,
)
const offset = (page - 1) * pageSize
params.push(pageSize, offset)
const itemsResult = await query<WorkerFinanceRequestRow>(
`
SELECT *
FROM worker_finance_requests wfr
${whereClause}
ORDER BY wfr.created_at DESC, wfr.id DESC
LIMIT $${params.length - 1} OFFSET $${params.length}
`,
params,
)
return {
items: itemsResult.rows,
total: Number(totalResult.rows[0]?.total || 0),
}
}
export async function getWorkerFinanceRequestSummary(workerId: number | string) {
const result = await query<{
pending_withdraw_amount: number
approved_withdraw_amount: number
pending_recharge_amount: number
}>(
`
SELECT
COALESCE(
SUM(CASE WHEN request_type = 'withdraw' AND status = 'pending' THEN amount ELSE 0 END),
0
)::int AS pending_withdraw_amount,
COALESCE(
SUM(CASE WHEN request_type = 'withdraw' AND status = 'approved' THEN amount ELSE 0 END),
0
)::int AS approved_withdraw_amount,
COALESCE(
SUM(CASE WHEN request_type = 'recharge' AND status = 'pending' THEN amount ELSE 0 END),
0
)::int AS pending_recharge_amount
FROM worker_finance_requests
WHERE worker_id = $1
`,
[Number(workerId)],
)
return {
pendingWithdrawAmount: Number(result.rows[0]?.pending_withdraw_amount || 0),
approvedWithdrawAmount: Number(result.rows[0]?.approved_withdraw_amount || 0),
pendingRechargeAmount: Number(result.rows[0]?.pending_recharge_amount || 0),
}
}
export async function countWorkerAcceptedOrders(workerId: number | string): Promise<number> {
const result = await query<{ total: number }>(
`
SELECT COUNT(*)::int AS total
FROM work_orders
WHERE assigned_worker_id = $1
AND status = 'accepted'
`,
[Number(workerId)],
)
return Number(result.rows[0]?.total || 0)
}
export async function getWorkCategoryByKey(categoryKey: string): Promise<WorkCategoryRow | null> {
const result = await query<WorkCategoryRow>(
'SELECT * FROM work_categories WHERE category_key = $1 LIMIT 1',
@@ -1255,6 +1476,51 @@ function buildWorkOrderWhere({ status = '', keyword = '', workerId = 0 }: ListIn
}
}
function buildWorkerWalletLedgerWhere({
workerId = 0,
ledgerType = '',
}: WalletLedgerListInput) {
const filters: string[] = []
const params: unknown[] = []
if (workerId) {
params.push(workerId)
filters.push(`wwl.worker_id = $${params.length}`)
}
if (ledgerType) {
params.push(ledgerType)
filters.push(`wwl.ledger_type = $${params.length}`)
}
return {
whereClause: filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : '',
params,
}
}
function buildWorkerFinanceRequestWhere({
workerId = 0,
status = '',
requestType = '',
}: FinanceRequestListInput) {
const filters: string[] = []
const params: unknown[] = []
if (workerId) {
params.push(workerId)
filters.push(`wfr.worker_id = $${params.length}`)
}
if (status) {
params.push(status)
filters.push(`wfr.status = $${params.length}`)
}
if (requestType) {
params.push(requestType)
filters.push(`wfr.request_type = $${params.length}`)
}
return {
whereClause: filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : '',
params,
}
}
function buildWorkProductRuleWhere({ enabled = null, keyword = '' }: ProductRuleListInput) {
const filters: string[] = []
const params: unknown[] = []