支持后台修改打手提现信息

This commit is contained in:
yml2213
2026-08-17 11:28:23 +08:00
parent ea5c2a4105
commit 77ed97fe1f
6 changed files with 317 additions and 1 deletions
@@ -497,6 +497,38 @@ export async function createWorkerWithdrawalAccount(input: {
return result.rows[0] || null
}
export async function upsertWorkerWithdrawalAccount(input: {
workerId: number
accountChannel: string
accountName: string
accountNo: string
wechatQrCodeJson: string
now: string
}): Promise<WorkerWithdrawalAccountRow | null> {
const result = await query<WorkerWithdrawalAccountRow>(
`
INSERT INTO worker_withdrawal_accounts (
worker_id, account_channel, account_name, account_no, wechat_qr_code_json, created_at
) VALUES ($1, $2, $3, $4, $5::jsonb, $6)
ON CONFLICT (worker_id, account_channel) DO UPDATE
SET
account_name = EXCLUDED.account_name,
account_no = EXCLUDED.account_no,
wechat_qr_code_json = EXCLUDED.wechat_qr_code_json
RETURNING *
`,
[
input.workerId,
input.accountChannel,
input.accountName,
input.accountNo,
input.wechatQrCodeJson,
input.now,
],
)
return result.rows[0] || null
}
export async function getWorkerFinanceRequestById(
requestId: number | string,
): Promise<WorkerFinanceRequestRow | null> {
@@ -18,6 +18,7 @@ import {
getAdminWorkOrderEvents,
getAdminWorkOrderSharing,
listAdminWorkerFinanceRequests,
listAdminWorkerWithdrawalAccounts,
listAdminWorkCategories,
listAdminWorkProductRules,
listAdminWorkerLevels,
@@ -30,6 +31,7 @@ import {
resolveAdminProblemWorkOrder,
reviewAdminWorkerUser,
saveAdminWorkerFinanceConfig,
saveAdminWorkerWithdrawalAccount,
saveAdminWorkCategory,
saveAdminWorkProductRule,
saveAdminWorkerLevel,
@@ -227,6 +229,40 @@ router.post(
),
)
router.get(
'/worker-platform/workers/:workerId/withdrawal-accounts',
requireAdminRoles(['admin', 'operator']),
createJsonHandler((req) => listAdminWorkerWithdrawalAccounts(String(req.params.workerId || '')), {
successMessage: 'ok',
errorMessage: '读取打手提现信息失败',
scope: '[admin/worker-platform/workers/:workerId/withdrawal-accounts]',
}),
)
router.post(
'/worker-platform/workers/:workerId/withdrawal-accounts/:accountChannel',
requireAdminRoles(['admin', 'operator']),
createJsonHandler(
(req) =>
saveAdminWorkerWithdrawalAccount(
String(req.params.workerId || ''),
String(req.params.accountChannel || ''),
req.body || {},
),
{
successMessage: '打手提现信息已保存',
errorMessage: '保存打手提现信息失败',
scope: '[admin/worker-platform/workers/:workerId/withdrawal-accounts/:accountChannel]',
audit: (req) => ({
action: 'worker_withdrawal_account_saved',
targetType: 'worker',
targetId: String(req.params.workerId || ''),
data: { accountChannel: String(req.params.accountChannel || '') },
}),
},
),
)
router.get(
'/worker-platform/finance-config',
requireAdminRoles(['admin', 'operator', 'support']),
@@ -32,6 +32,7 @@ import {
listWorkProductRules,
listWorkerLevels,
listWorkerUsers,
listWorkerWithdrawalAccounts,
listWorkOrderShares,
listWorkOrderSharesByOrderIds,
sumPendingUnfreezeByOrderIds,
@@ -40,11 +41,13 @@ import {
updateWorkOrder,
updateWorkOrderBasic,
updateWorkerUser,
upsertWorkerWithdrawalAccount,
upsertWorkCategory,
upsertWorkProductRule,
upsertWorkerLevel,
type WorkOrderRow,
type WorkOrderShareRow,
type WorkerWithdrawalAccountRow,
} from '../../repositories/worker-platform/index.js'
import type { JsonObject } from '../../types/json.js'
import type { OrderItemRow, OrderRow } from '../../types/repository/rows.js'
@@ -53,6 +56,7 @@ import { randomId } from '../../utils/random.js'
import { nowIso } from '../../utils/time.js'
import { normalizePage, normalizePageSize, safeParseJson } from '../admin/admin-query-utils.js'
import { getWorkerFinanceConfig, saveWorkerFinanceConfig } from './worker-finance-config-service.js'
import { refreshUploadedFileUrls } from '../file-storage/file-storage-service.js'
import {
consumeIndustryVouchersBeforeWorkOrderAssign,
consumeIndustryVouchersBeforeWorkOrderPublish,
@@ -81,6 +85,7 @@ import {
normalizeMatchType,
normalizeOptionalId,
normalizePositiveInteger,
normalizeProofFiles,
normalizeProblemResolutionAction,
normalizeRequirementFields,
normalizeRequirementFieldsFromPayload,
@@ -91,6 +96,7 @@ import {
normalizeSubmittedFields,
normalizeUploadedFiles,
normalizeWorkerType,
normalizeWithdrawChannel,
resolveFreezeDepositAmount,
mapWorkOrderEvents,
resolveMatchingProductRule,
@@ -524,6 +530,71 @@ export async function creditAdminWorkerWallet(workerId: number | string, payload
return { wallet: mapWallet(wallet) }
}
export async function listAdminWorkerWithdrawalAccounts(workerId: number | string) {
const worker = await getRequiredWorker(workerId)
const items = await listWorkerWithdrawalAccounts(worker.id)
return {
worker: mapWorkerUser(worker),
items: items.map(mapAdminWorkerWithdrawalAccount),
}
}
export async function saveAdminWorkerWithdrawalAccount(
workerId: number | string,
accountChannelValue: unknown,
payload: JsonObject = {},
) {
const worker = await getRequiredWorker(workerId)
const accountChannel = normalizeWithdrawChannel(accountChannelValue)
const currentAccounts = await listWorkerWithdrawalAccounts(worker.id)
const current = currentAccounts.find((item) => item.account_channel === accountChannel)
const accountName = String(payload.accountName || payload.realName || '').trim()
const accountNo =
accountChannel === 'alipay' ? String(payload.accountNo || payload.account || '').trim() : ''
const uploadedWechatQrCode = normalizeProofFiles(
payload.wechatQrCodeImages || payload.wechatQrCodes,
)[0]
const wechatQrCodeImage =
accountChannel === 'wechat'
? uploadedWechatQrCode || safeParseJson(current?.wechat_qr_code_json)
: {}
if (!accountName) {
throw createHttpError('请填写收款人姓名', {
statusCode: 400,
errorCode: 'admin_worker_withdraw_account_name_required',
})
}
if (accountChannel === 'alipay' && !accountNo) {
throw createHttpError('请填写支付宝账号', {
statusCode: 400,
errorCode: 'admin_worker_withdraw_alipay_account_required',
})
}
if (accountChannel === 'wechat' && !String(wechatQrCodeImage.url || '').trim()) {
throw createHttpError('请上传微信收款二维码', {
statusCode: 400,
errorCode: 'admin_worker_withdraw_wechat_qr_required',
})
}
const saved = await upsertWorkerWithdrawalAccount({
workerId: worker.id,
accountChannel,
accountName,
accountNo,
wechatQrCodeJson: JSON.stringify(wechatQrCodeImage),
now: nowIso(),
})
if (!saved) {
throw createHttpError('保存打手提现信息失败', {
statusCode: 500,
errorCode: 'admin_worker_withdraw_account_save_failed',
})
}
return { account: mapAdminWorkerWithdrawalAccount(saved) }
}
export async function getAdminWorkerFinanceConfig() {
return getWorkerFinanceConfig()
}
@@ -599,6 +670,17 @@ export async function reviewAdminWorkerFinanceRequest(
}
}
function mapAdminWorkerWithdrawalAccount(account: WorkerWithdrawalAccountRow) {
const wechatQrCodeImage = refreshUploadedFileUrls(safeParseJson(account.wechat_qr_code_json))
return {
accountChannel: account.account_channel,
accountName: account.account_name,
accountNo: account.account_channel === 'alipay' ? account.account_no : '',
wechatQrCodeImage: String(wechatQrCodeImage.url || '').trim() ? wechatQrCodeImage : null,
createdAt: account.created_at,
}
}
export async function getAdminWorkOrderEvents(workOrderId: number | string) {
await getRequiredWorkOrder(workOrderId)
const events = await listWorkOrderEventsByOrderId(workOrderId)