From 52a85f7f9e83ae69a17174d96097acc4d2d5c4c1 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Sat, 1 Aug 2026 15:22:25 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=85=E5=80=BC=E7=94=B3=E8=AF=B7=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E4=BB=98=E6=AC=BE=E5=87=AD=E8=AF=81=E4=B8=8E=E4=BB=98?= =?UTF-8?q?=E6=AC=BE=E6=97=B6=E9=97=B4=EF=BC=8C=E7=AE=A1=E7=90=86=E7=AB=AF?= =?UTF-8?q?=E5=8F=AF=E6=A0=B8=E5=AF=B9=E5=90=8E=E5=AE=A1=E6=A0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 打手端充值表单新增付款时间(必填)与付款凭证上传(最多5张) - 后端存储 paidAt 与 proofFiles 归一化数据 - 管理端资金申请列表新增付款凭证缩略图列,审核弹窗展示付款时间与凭证预览 --- .../worker-platform-service.ts | 28 ++++++++++++ .../pages/admin/AdminWorkerPlatformPage.tsx | 45 +++++++++++++++++++ .../src/pages/worker/WorkerProfilePage.tsx | 26 +++++++++++ apps/frontend/src/services/worker.ts | 2 + 4 files changed, 101 insertions(+) diff --git a/apps/backend/src/services/worker-platform/worker-platform-service.ts b/apps/backend/src/services/worker-platform/worker-platform-service.ts index c83e88f7..c8e2d3e1 100644 --- a/apps/backend/src/services/worker-platform/worker-platform-service.ts +++ b/apps/backend/src/services/worker-platform/worker-platform-service.ts @@ -468,6 +468,8 @@ export async function createWorkerRechargeRequest( } const note = String(payload.note || payload.remark || '').trim() + const proofFiles = normalizeProofFiles(payload.proofFiles || payload.proofFilesList) + const paidAt = String(payload.paidAt || '').trim() const created = await createWorkerFinanceRequest({ workerId: worker.id, requestType: 'recharge', @@ -480,6 +482,8 @@ export async function createWorkerRechargeRequest( source: 'worker_profile_recharge', username: worker.username, phone: worker.phone || '', + paidAt: paidAt || null, + proofFiles, financeConfig: { channelName: financeConfig.recharge.channelName, accountName: financeConfig.recharge.accountName, @@ -2350,6 +2354,30 @@ function normalizeAmountFen(value: unknown, fallback: number): number { return Math.round(parsed * 100) } +function normalizeProofFiles(value: unknown): Array> { + if (!Array.isArray(value)) return [] + const files: Array> = [] + for (const item of value) { + if (!item || typeof item !== 'object') continue + const file = item as Record + const url = String(file.url || '').trim() + if (!url) continue + files.push({ + url, + thumbnailUrl: String(file.thumbnailUrl || file.thumbnail_url || '').trim(), + mediumUrl: String(file.mediumUrl || file.medium_url || '').trim(), + objectKey: String(file.objectKey || file.object_key || '').trim(), + originalFilename: String( + file.originalFilename || file.original_filename || file.name || '', + ).trim(), + contentType: String(file.contentType || file.content_type || '').trim(), + sizeBytes: Number(file.sizeBytes || file.size_bytes || 0), + }) + if (files.length >= 10) break + } + return files +} + function isIgnorableWorkerAuthError(error: unknown) { return IGNORABLE_WORKER_AUTH_ERROR_CODES.has( String((error as { errorCode?: string })?.errorCode || '').trim(), diff --git a/apps/frontend/src/pages/admin/AdminWorkerPlatformPage.tsx b/apps/frontend/src/pages/admin/AdminWorkerPlatformPage.tsx index ca888042..7ac78b7d 100644 --- a/apps/frontend/src/pages/admin/AdminWorkerPlatformPage.tsx +++ b/apps/frontend/src/pages/admin/AdminWorkerPlatformPage.tsx @@ -1617,6 +1617,16 @@ function FinancePanel() { minWidth: 240, render: (_, row) => renderFinanceRequestAccount(row), }, + { + title: '付款凭证', + minWidth: 140, + render: (_, row) => + row.requestType === 'recharge' ? ( + + ) : ( + '-' + ), + }, { title: '备注', minWidth: 260, @@ -1851,6 +1861,18 @@ function FinancePanel() { {renderFinanceRequestAccountText(reviewState.request)} + {reviewState.request.requestType === 'recharge' ? ( + <> + + {getRechargePaidAt(reviewState.request) + ? formatAdminDateTime(getRechargePaidAt(reviewState.request)) + : '-'} + + + + + + ) : null} {reviewState.request.note || '-'} @@ -2370,6 +2392,29 @@ function getRechargeSnapshot(request: WorkerFinanceRequest) { } } +function getRechargeProofs(request: WorkerFinanceRequest): UploadedFile[] { + if (request.requestType !== 'recharge') return [] + const payload = asRecord(request.payload) + const rawFiles = Array.isArray(payload.proofFiles) ? payload.proofFiles : [] + return rawFiles + .map((item) => { + const file = asRecord(item) + const url = String(file.url || '').trim() + if (!url) return null + return { + url, + mediumUrl: String(file.mediumUrl || '').trim(), + thumbnailUrl: String(file.thumbnailUrl || '').trim(), + } as UploadedFile + }) + .filter((item): item is UploadedFile => Boolean(item)) +} + +function getRechargePaidAt(request: WorkerFinanceRequest): string { + const payload = asRecord(request.payload) + return String(payload.paidAt || '').trim() +} + function formatFinanceChannel(channel: string) { if (channel === 'alipay') return '支付宝' if (channel === 'wechat') return '微信收款' diff --git a/apps/frontend/src/pages/worker/WorkerProfilePage.tsx b/apps/frontend/src/pages/worker/WorkerProfilePage.tsx index 8be89513..f7be84d2 100644 --- a/apps/frontend/src/pages/worker/WorkerProfilePage.tsx +++ b/apps/frontend/src/pages/worker/WorkerProfilePage.tsx @@ -17,6 +17,7 @@ import { Button, Card, Col, + DatePicker, Descriptions, Empty, Form, @@ -38,6 +39,7 @@ import type { TableColumnsType } from 'antd' import { useState } from 'react' import { useNavigate } from 'react-router' +import ImageUpload from '@/components/files/ImageUpload' import { changeWorkerPassword, createWorkerRechargeRequest, @@ -48,6 +50,7 @@ import { logoutWorker, } from '@/services/worker' import type { + UploadedFile, WorkerFinanceRequest, WorkerProfileSummary, WorkerUser, @@ -59,6 +62,8 @@ import { clearWorkerSession } from '@/utils/worker-auth' type RechargeFormValues = { amount?: number note?: string + paidAt?: string + proofFiles?: UploadedFile[] } type WithdrawFormValues = { @@ -224,6 +229,8 @@ export default function WorkerProfilePage() { await createWorkerRechargeRequest({ amount: values.amount, note: String(values.note || '').trim(), + paidAt: values.paidAt || '', + proofFiles: values.proofFiles || [], }) message.success('充值申请已提交,请等待管理员处理') setRechargeOpen(false) @@ -842,6 +849,25 @@ export default function WorkerProfilePage() { > + + + + + + ) { export function createWorkerRechargeRequest(payload: { amount?: number note?: string + paidAt?: string + proofFiles?: UploadedFile[] }) { return apiPost<{ request: WorkerFinanceRequest }>( '/api/v1/worker/profile/recharge-requests',