优化打手提现审核流程
This commit is contained in:
@@ -68,6 +68,7 @@ export default function FinancePanel() {
|
||||
const [page, setPage] = useState(1)
|
||||
const [pageSize, setPageSize] = useState(ADMIN_DEFAULT_PAGE_SIZE)
|
||||
const [savingConfig, setSavingConfig] = useState(false)
|
||||
const [configExpanded, setConfigExpanded] = useState(false)
|
||||
const [reviewing, setReviewing] = useState(false)
|
||||
const [reviewState, setReviewState] = useState<{
|
||||
action: FinanceReviewAction
|
||||
@@ -207,14 +208,16 @@ export default function FinancePanel() {
|
||||
render: (_, row) => renderFinanceRequestAccount(row),
|
||||
},
|
||||
{
|
||||
title: '付款凭证',
|
||||
title: '凭证/收款码',
|
||||
minWidth: 140,
|
||||
render: (_, row) =>
|
||||
row.requestType === 'recharge' ? (
|
||||
<ImagePreviewList files={getRechargeProofs(row)} size={48} />
|
||||
) : (
|
||||
'-'
|
||||
),
|
||||
render: (_, row) => (
|
||||
<ImagePreviewList
|
||||
files={
|
||||
row.requestType === 'recharge' ? getRechargeProofs(row) : getWechatWithdrawQrCode(row)
|
||||
}
|
||||
size={48}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
@@ -276,87 +279,102 @@ export default function FinancePanel() {
|
||||
bordered={false}
|
||||
loading={financeConfigQuery.isLoading}
|
||||
extra={
|
||||
<Button
|
||||
icon={<ReloadOutlined />}
|
||||
loading={financeConfigQuery.isFetching}
|
||||
onClick={() => financeConfigQuery.refetch()}
|
||||
>
|
||||
刷新
|
||||
</Button>
|
||||
<Space>
|
||||
<Button type="link" onClick={() => setConfigExpanded((expanded) => !expanded)}>
|
||||
{configExpanded ? '收起配置' : '展开配置'}
|
||||
</Button>
|
||||
<Button
|
||||
icon={<ReloadOutlined />}
|
||||
loading={financeConfigQuery.isFetching}
|
||||
onClick={() => financeConfigQuery.refetch()}
|
||||
>
|
||||
刷新
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
{financeConfigQuery.error ? (
|
||||
{configExpanded && financeConfigQuery.error ? (
|
||||
<Typography.Text type="danger">
|
||||
{financeConfigQuery.error instanceof Error
|
||||
? financeConfigQuery.error.message
|
||||
: '读取资金配置失败'}
|
||||
</Typography.Text>
|
||||
) : null}
|
||||
<Form
|
||||
form={configForm}
|
||||
layout="vertical"
|
||||
onFinish={submitFinanceConfig}
|
||||
initialValues={mapFinanceConfigToFormValues()}
|
||||
>
|
||||
<Card title="充值入口" size="small" style={{ marginBottom: 16 }}>
|
||||
<Form.Item label="开启充值申请" name={['recharge', 'enabled']} valuePropName="checked">
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item label="收款通道名称" name={['recharge', 'channelName']}>
|
||||
<Input placeholder="如:支付宝扫码、微信收款" />
|
||||
</Form.Item>
|
||||
<Form.Item label="收款人" name={['recharge', 'accountName']}>
|
||||
<Input placeholder="请输入收款人姓名" />
|
||||
</Form.Item>
|
||||
<Form.Item label="收款账号" name={['recharge', 'accountNo']}>
|
||||
<Input placeholder="请输入支付宝账号、微信号或银行卡号" />
|
||||
</Form.Item>
|
||||
<Form.Item label="收款二维码" name={['recharge', 'qrCodeImageList']}>
|
||||
<ImageUpload scene="worker-finance" scope="admin" maxCount={1} />
|
||||
</Form.Item>
|
||||
<Form.Item label="充值说明" name={['recharge', 'instructions']}>
|
||||
<Input.TextArea
|
||||
rows={4}
|
||||
placeholder="例如:转账后请填写付款时间、付款尾号、截图说明。"
|
||||
/>
|
||||
</Form.Item>
|
||||
</Card>
|
||||
{configExpanded ? (
|
||||
<Form
|
||||
form={configForm}
|
||||
layout="vertical"
|
||||
onFinish={submitFinanceConfig}
|
||||
initialValues={mapFinanceConfigToFormValues()}
|
||||
>
|
||||
<Card title="充值入口" size="small" style={{ marginBottom: 16 }}>
|
||||
<Form.Item
|
||||
label="开启充值申请"
|
||||
name={['recharge', 'enabled']}
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item label="收款通道名称" name={['recharge', 'channelName']}>
|
||||
<Input placeholder="如:支付宝扫码、微信收款" />
|
||||
</Form.Item>
|
||||
<Form.Item label="收款人" name={['recharge', 'accountName']}>
|
||||
<Input placeholder="请输入收款人姓名" />
|
||||
</Form.Item>
|
||||
<Form.Item label="收款账号" name={['recharge', 'accountNo']}>
|
||||
<Input placeholder="请输入支付宝账号、微信号或银行卡号" />
|
||||
</Form.Item>
|
||||
<Form.Item label="收款二维码" name={['recharge', 'qrCodeImageList']}>
|
||||
<ImageUpload scene="worker-finance" scope="admin" maxCount={1} />
|
||||
</Form.Item>
|
||||
<Form.Item label="充值说明" name={['recharge', 'instructions']}>
|
||||
<Input.TextArea
|
||||
rows={4}
|
||||
placeholder="例如:转账后请填写付款时间、付款尾号、截图说明。"
|
||||
/>
|
||||
</Form.Item>
|
||||
</Card>
|
||||
|
||||
<Card title="管理员联系" size="small" style={{ marginBottom: 16 }}>
|
||||
<Form.Item label="管理员微信二维码" name={['adminContact', 'wechatQrCodeImageList']}>
|
||||
<ImageUpload scene="worker-admin-contact" scope="admin" maxCount={1} />
|
||||
</Form.Item>
|
||||
</Card>
|
||||
<Card title="管理员联系" size="small" style={{ marginBottom: 16 }}>
|
||||
<Form.Item label="管理员微信二维码" name={['adminContact', 'wechatQrCodeImageList']}>
|
||||
<ImageUpload scene="worker-admin-contact" scope="admin" maxCount={1} />
|
||||
</Form.Item>
|
||||
</Card>
|
||||
|
||||
<Card title="押金与提现规则" size="small" style={{ marginBottom: 16 }}>
|
||||
<Form.Item
|
||||
label="押金解冻天数"
|
||||
name="depositUnfreezeDays"
|
||||
tooltip="有押金的工单验收通过后,押金进入待解冻,N 天后自动转入可用余额;0 表示验收通过立即释放"
|
||||
>
|
||||
<InputNumber min={0} max={30} step={1} addonAfter="天" />
|
||||
</Form.Item>
|
||||
<Typography.Text type="secondary">
|
||||
解冻期间如订单出现问题,可在"接单工单"中对已验收工单扣减待解冻押金(全额或部分)。
|
||||
</Typography.Text>
|
||||
</Card>
|
||||
<Card title="押金与提现规则" size="small" style={{ marginBottom: 16 }}>
|
||||
<Form.Item
|
||||
label="押金解冻天数"
|
||||
name="depositUnfreezeDays"
|
||||
tooltip="有押金的工单验收通过后,押金进入待解冻,N 天后自动转入可用余额;0 表示验收通过立即释放"
|
||||
>
|
||||
<InputNumber min={0} max={30} step={1} addonAfter="天" />
|
||||
</Form.Item>
|
||||
<Typography.Text type="secondary">
|
||||
解冻期间如订单出现问题,可在"接单工单"中对已验收工单扣减待解冻押金(全额或部分)。
|
||||
</Typography.Text>
|
||||
</Card>
|
||||
|
||||
<Card title="提现入口" size="small" style={{ marginBottom: 16 }}>
|
||||
<Form.Item label="开启提现申请" name={['withdraw', 'enabled']} valuePropName="checked">
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item label="提现说明" name={['withdraw', 'instructions']}>
|
||||
<Input.TextArea
|
||||
rows={4}
|
||||
placeholder="例如:每天 18:00 前审核,当日打款;银行卡请备注开户行。"
|
||||
/>
|
||||
</Form.Item>
|
||||
</Card>
|
||||
<Card title="提现入口" size="small" style={{ marginBottom: 16 }}>
|
||||
<Form.Item
|
||||
label="开启提现申请"
|
||||
name={['withdraw', 'enabled']}
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item label="提现说明" name={['withdraw', 'instructions']}>
|
||||
<Input.TextArea
|
||||
rows={4}
|
||||
placeholder="例如:每天 18:00 前审核,当日打款;银行卡请备注开户行。"
|
||||
/>
|
||||
</Form.Item>
|
||||
</Card>
|
||||
|
||||
<Button type="primary" htmlType="submit" loading={savingConfig}>
|
||||
保存配置
|
||||
</Button>
|
||||
</Form>
|
||||
<Button type="primary" htmlType="submit" loading={savingConfig}>
|
||||
保存配置
|
||||
</Button>
|
||||
</Form>
|
||||
) : null}
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
@@ -461,6 +479,16 @@ export default function FinancePanel() {
|
||||
<Descriptions.Item label="收款信息">
|
||||
{renderFinanceRequestAccountText(reviewState.request)}
|
||||
</Descriptions.Item>
|
||||
{reviewState.request.requestType === 'withdraw' &&
|
||||
reviewState.request.accountChannel === 'alipay' ? (
|
||||
<Descriptions.Item label="支付宝账号">
|
||||
{reviewState.request.accountNo ? (
|
||||
<Typography.Text copyable>{reviewState.request.accountNo}</Typography.Text>
|
||||
) : (
|
||||
'-'
|
||||
)}
|
||||
</Descriptions.Item>
|
||||
) : null}
|
||||
{reviewState.request.requestType === 'recharge' ? (
|
||||
<>
|
||||
<Descriptions.Item label="付款时间">
|
||||
@@ -473,6 +501,15 @@ export default function FinancePanel() {
|
||||
</Descriptions.Item>
|
||||
</>
|
||||
) : null}
|
||||
{reviewState.request.requestType === 'withdraw' &&
|
||||
reviewState.request.accountChannel === 'wechat' ? (
|
||||
<Descriptions.Item label="微信收款二维码">
|
||||
<ImagePreviewList
|
||||
files={getWechatWithdrawQrCode(reviewState.request)}
|
||||
size={88}
|
||||
/>
|
||||
</Descriptions.Item>
|
||||
) : null}
|
||||
<Descriptions.Item label="申请备注">
|
||||
{reviewState.request.note || '-'}
|
||||
</Descriptions.Item>
|
||||
@@ -551,7 +588,7 @@ function renderFinanceRequestAccount(request: WorkerFinanceRequest) {
|
||||
<div className="cell-stack">
|
||||
<Typography.Text>{renderFinanceRequestAccountText(request)}</Typography.Text>
|
||||
{request.requestType === 'withdraw' && request.accountNo ? (
|
||||
<Typography.Text type="secondary">{maskFinanceAccount(request.accountNo)}</Typography.Text>
|
||||
<Typography.Text copyable>{request.accountNo}</Typography.Text>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
@@ -606,6 +643,25 @@ function getRechargeProofs(request: WorkerFinanceRequest): UploadedFile[] {
|
||||
.filter((item): item is UploadedFile => Boolean(item))
|
||||
}
|
||||
|
||||
function getWechatWithdrawQrCode(request: WorkerFinanceRequest): UploadedFile[] {
|
||||
if (request.requestType !== 'withdraw' || request.accountChannel !== 'wechat') return []
|
||||
const payload = asRecord(request.payload)
|
||||
const file = asRecord(payload.wechatQrCodeImage)
|
||||
const url = String(file.url || '').trim()
|
||||
if (!url) return []
|
||||
return [
|
||||
{
|
||||
url,
|
||||
mediumUrl: String(file.mediumUrl || '').trim(),
|
||||
thumbnailUrl: String(file.thumbnailUrl || '').trim(),
|
||||
objectKey: String(file.objectKey || '').trim(),
|
||||
filename: String(file.filename || '').trim(),
|
||||
contentType: String(file.contentType || '').trim(),
|
||||
size: Number(file.size || 0),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
function getRechargePaidAt(request: WorkerFinanceRequest): string {
|
||||
const payload = asRecord(request.payload)
|
||||
return String(payload.paidAt || '').trim()
|
||||
|
||||
@@ -40,6 +40,7 @@ import ImageUpload from '@/components/files/ImageUpload'
|
||||
import {
|
||||
changeWorkerPassword,
|
||||
createWorkerRechargeRequest,
|
||||
createWorkerWithdrawalAccount,
|
||||
createWorkerWithdrawRequest,
|
||||
fetchWorkerFinanceRequests,
|
||||
fetchWorkerProfile,
|
||||
@@ -66,10 +67,15 @@ type RechargeFormValues = {
|
||||
|
||||
type WithdrawFormValues = {
|
||||
amount?: number
|
||||
accountChannel?: string
|
||||
note?: string
|
||||
}
|
||||
|
||||
type WithdrawalAccountFormValues = {
|
||||
accountChannel?: string
|
||||
accountName?: string
|
||||
accountNo?: string
|
||||
note?: string
|
||||
wechatQrCodeImages?: UploadedFile[]
|
||||
}
|
||||
|
||||
type PasswordFormValues = {
|
||||
@@ -94,14 +100,19 @@ export default function WorkerProfilePage() {
|
||||
const [requestStatus, setRequestStatus] = useState('')
|
||||
const [rechargeOpen, setRechargeOpen] = useState(false)
|
||||
const [withdrawOpen, setWithdrawOpen] = useState(false)
|
||||
const [withdrawalAccountOpen, setWithdrawalAccountOpen] = useState(false)
|
||||
const [passwordOpen, setPasswordOpen] = useState(false)
|
||||
const [contactOpen, setContactOpen] = useState(false)
|
||||
const [submittingRecharge, setSubmittingRecharge] = useState(false)
|
||||
const [submittingWithdraw, setSubmittingWithdraw] = useState(false)
|
||||
const [submittingWithdrawalAccount, setSubmittingWithdrawalAccount] = useState(false)
|
||||
const [submittingPassword, setSubmittingPassword] = useState(false)
|
||||
const [rechargeForm] = Form.useForm<RechargeFormValues>()
|
||||
const [withdrawForm] = Form.useForm<WithdrawFormValues>()
|
||||
const [withdrawalAccountForm] = Form.useForm<WithdrawalAccountFormValues>()
|
||||
const [passwordForm] = Form.useForm<PasswordFormValues>()
|
||||
const selectedWithdrawChannel = Form.useWatch('accountChannel', withdrawForm)
|
||||
const selectedWithdrawalAccountChannel = Form.useWatch('accountChannel', withdrawalAccountForm)
|
||||
|
||||
const profileQuery = useQuery({
|
||||
queryKey: ['worker-profile'],
|
||||
@@ -113,6 +124,10 @@ export default function WorkerProfilePage() {
|
||||
const summary = profileQuery.data?.data.summary
|
||||
const levelProgress = profileQuery.data?.data.levelProgress
|
||||
const financeConfig = profileQuery.data?.data.financeConfig
|
||||
const withdrawalAccounts = profileQuery.data?.data.withdrawalAccounts || []
|
||||
const selectedWithdrawalAccount = withdrawalAccounts.find(
|
||||
(account) => account.accountChannel === selectedWithdrawChannel,
|
||||
)
|
||||
const canUseFinanceActions = worker?.status === 'active'
|
||||
|
||||
async function copyInviteCode() {
|
||||
@@ -191,9 +206,26 @@ export default function WorkerProfilePage() {
|
||||
message.warning('当前提现入口暂未开放,请联系管理员')
|
||||
return
|
||||
}
|
||||
if (withdrawalAccounts.length === 0) {
|
||||
openWithdrawalAccountModal()
|
||||
return
|
||||
}
|
||||
withdrawForm.setFieldValue('accountChannel', withdrawalAccounts[0].accountChannel)
|
||||
setWithdrawOpen(true)
|
||||
}
|
||||
|
||||
function openWithdrawalAccountModal() {
|
||||
const nextChannel = ['alipay', 'wechat'].find(
|
||||
(channel) => !withdrawalAccounts.some((account) => account.accountChannel === channel),
|
||||
)
|
||||
if (!nextChannel) {
|
||||
message.info('支付宝和微信提现信息均已添加,修改请联系客服处理')
|
||||
return
|
||||
}
|
||||
withdrawalAccountForm.setFieldValue('accountChannel', nextChannel)
|
||||
setWithdrawalAccountOpen(true)
|
||||
}
|
||||
|
||||
async function submitRecharge(values: RechargeFormValues) {
|
||||
setSubmittingRecharge(true)
|
||||
try {
|
||||
@@ -222,9 +254,7 @@ export default function WorkerProfilePage() {
|
||||
try {
|
||||
await createWorkerWithdrawRequest({
|
||||
amount: values.amount,
|
||||
accountChannel: values.accountChannel,
|
||||
accountName: String(values.accountName || '').trim(),
|
||||
accountNo: String(values.accountNo || '').trim(),
|
||||
accountChannel: String(values.accountChannel || ''),
|
||||
note: String(values.note || '').trim(),
|
||||
})
|
||||
message.success('提现申请已提交,请等待管理员审核')
|
||||
@@ -241,6 +271,28 @@ export default function WorkerProfilePage() {
|
||||
}
|
||||
}
|
||||
|
||||
async function submitWithdrawalAccount(values: WithdrawalAccountFormValues) {
|
||||
setSubmittingWithdrawalAccount(true)
|
||||
try {
|
||||
await createWorkerWithdrawalAccount({
|
||||
accountChannel: String(values.accountChannel || ''),
|
||||
accountName: String(values.accountName || '').trim(),
|
||||
accountNo: String(values.accountNo || '').trim(),
|
||||
wechatQrCodeImages: values.wechatQrCodeImages || [],
|
||||
})
|
||||
message.success('提现信息已添加,该方式后续修改请联系客服处理')
|
||||
setWithdrawalAccountOpen(false)
|
||||
withdrawalAccountForm.resetFields()
|
||||
await refreshAll()
|
||||
withdrawForm.setFieldValue('accountChannel', String(values.accountChannel || ''))
|
||||
setWithdrawOpen(true)
|
||||
} catch (error) {
|
||||
message.error(error instanceof Error ? error.message : '添加提现信息失败')
|
||||
} finally {
|
||||
setSubmittingWithdrawalAccount(false)
|
||||
}
|
||||
}
|
||||
|
||||
async function submitPasswordChange(values: PasswordFormValues) {
|
||||
setSubmittingPassword(true)
|
||||
try {
|
||||
@@ -1055,6 +1107,15 @@ export default function WorkerProfilePage() {
|
||||
>
|
||||
提现申请
|
||||
</Button>
|
||||
{withdrawalAccounts.length < 2 ? (
|
||||
<Button
|
||||
icon={<BankOutlined />}
|
||||
disabled={!canUseFinanceActions}
|
||||
onClick={openWithdrawalAccountModal}
|
||||
>
|
||||
添加提现信息
|
||||
</Button>
|
||||
) : null}
|
||||
<Button icon={<LockOutlined />} onClick={() => setPasswordOpen(true)}>
|
||||
修改密码
|
||||
</Button>
|
||||
@@ -1122,6 +1183,37 @@ export default function WorkerProfilePage() {
|
||||
<Descriptions.Item label="提现中金额">
|
||||
{formatMoney(summary?.pendingWithdrawAmount)}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="提现信息" span={2}>
|
||||
{withdrawalAccounts.length > 0 ? (
|
||||
<Space direction="vertical" size={2}>
|
||||
{withdrawalAccounts.map((account) => (
|
||||
<Space key={account.accountChannel} wrap size={4}>
|
||||
<Typography.Text>
|
||||
{formatWithdrawChannel(account.accountChannel)}
|
||||
</Typography.Text>
|
||||
<Typography.Text>{account.accountName}</Typography.Text>
|
||||
<Typography.Text type="secondary">
|
||||
{account.accountChannel === 'wechat'
|
||||
? '已上传收款二维码'
|
||||
: account.accountNoMasked}
|
||||
</Typography.Text>
|
||||
<Typography.Text type="secondary">
|
||||
已锁定,修改请联系客服
|
||||
</Typography.Text>
|
||||
</Space>
|
||||
))}
|
||||
</Space>
|
||||
) : (
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
disabled={!canUseFinanceActions}
|
||||
onClick={openWithdrawalAccountModal}
|
||||
>
|
||||
添加提现信息
|
||||
</Button>
|
||||
)}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="免押额度">
|
||||
{formatMoney(worker.level?.permissions.depositFreeAmount || 0)}
|
||||
</Descriptions.Item>
|
||||
@@ -1387,6 +1479,69 @@ export default function WorkerProfilePage() {
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
title="添加提现信息"
|
||||
open={withdrawalAccountOpen}
|
||||
width={isMobile ? '92%' : 500}
|
||||
destroyOnHidden
|
||||
confirmLoading={submittingWithdrawalAccount}
|
||||
onCancel={() => {
|
||||
setWithdrawalAccountOpen(false)
|
||||
withdrawalAccountForm.resetFields()
|
||||
}}
|
||||
onOk={() => withdrawalAccountForm.submit()}
|
||||
>
|
||||
<Alert
|
||||
showIcon
|
||||
type="warning"
|
||||
message="支付宝和微信可分别添加一次;每种方式添加后均无法自行修改,如需修改请联系客服。"
|
||||
style={{ marginBottom: 16 }}
|
||||
/>
|
||||
<Form form={withdrawalAccountForm} layout="vertical" onFinish={submitWithdrawalAccount}>
|
||||
<Form.Item
|
||||
label="提现方式"
|
||||
name="accountChannel"
|
||||
rules={[{ required: true, message: '请选择提现方式' }]}
|
||||
>
|
||||
<Select
|
||||
options={[
|
||||
...(!withdrawalAccounts.some((account) => account.accountChannel === 'alipay')
|
||||
? [{ value: 'alipay', label: '支付宝' }]
|
||||
: []),
|
||||
...(!withdrawalAccounts.some((account) => account.accountChannel === 'wechat')
|
||||
? [{ value: 'wechat', label: '微信收款(仅支持 100 元及以下提现)' }]
|
||||
: []),
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="收款人姓名"
|
||||
name="accountName"
|
||||
rules={[{ required: true, message: '请输入收款人姓名' }]}
|
||||
>
|
||||
<Input placeholder="请输入真实姓名" />
|
||||
</Form.Item>
|
||||
{selectedWithdrawalAccountChannel === 'wechat' ? (
|
||||
<Form.Item
|
||||
label="微信收款二维码"
|
||||
name="wechatQrCodeImages"
|
||||
rules={[{ required: true, message: '请上传微信收款二维码' }]}
|
||||
extra="微信提现仅使用收款二维码,不需要填写微信账号。"
|
||||
>
|
||||
<ImageUpload scene="worker-withdrawal-wechat-qr" scope="worker" maxCount={1} />
|
||||
</Form.Item>
|
||||
) : (
|
||||
<Form.Item
|
||||
label="支付宝账号"
|
||||
name="accountNo"
|
||||
rules={[{ required: true, message: '请输入支付宝账号' }]}
|
||||
>
|
||||
<Input placeholder="请输入支付宝账号" />
|
||||
</Form.Item>
|
||||
)}
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
title="提现申请"
|
||||
open={withdrawOpen}
|
||||
@@ -1399,12 +1554,7 @@ export default function WorkerProfilePage() {
|
||||
}}
|
||||
onOk={() => withdrawForm.submit()}
|
||||
>
|
||||
<Form
|
||||
form={withdrawForm}
|
||||
layout="vertical"
|
||||
initialValues={{ accountChannel: 'alipay' }}
|
||||
onFinish={submitWithdraw}
|
||||
>
|
||||
<Form form={withdrawForm} layout="vertical" onFinish={submitWithdraw}>
|
||||
{financeConfig?.withdraw.instructions ? (
|
||||
<Alert
|
||||
showIcon
|
||||
@@ -1416,49 +1566,58 @@ export default function WorkerProfilePage() {
|
||||
<Alert
|
||||
showIcon
|
||||
type="warning"
|
||||
message={`每天限提现 1 次;有押金的工单验收通过后,押金需 ${Number(
|
||||
message={`每天最多提现 3 次(支付宝、微信共享次数);100 元及以下支持微信和支付宝,超过 100 元仅支持支付宝;有押金的工单验收通过后,押金需 ${Number(
|
||||
financeConfig?.depositUnfreezeDays ?? 3,
|
||||
)} 天解冻到账后方可提现。`}
|
||||
style={{ marginBottom: 16 }}
|
||||
/>
|
||||
<Descriptions column={1} bordered size="small" style={{ marginBottom: 16 }}>
|
||||
<Descriptions.Item label="提现账户">
|
||||
{formatWithdrawChannel(selectedWithdrawalAccount?.accountChannel || '')} ·{' '}
|
||||
{selectedWithdrawalAccount?.accountName || '-'} ·{' '}
|
||||
{selectedWithdrawalAccount?.accountChannel === 'wechat'
|
||||
? '收款二维码'
|
||||
: selectedWithdrawalAccount?.accountNoMasked || '-'}
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
<Form.Item label="可提现余额">
|
||||
<Typography.Text strong>
|
||||
{formatMoney(resolveAvailableForWithdraw(worker, summary))}
|
||||
</Typography.Text>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="提现金额"
|
||||
name="amount"
|
||||
rules={[{ required: true, message: '请输入提现金额' }]}
|
||||
>
|
||||
<InputNumber min={0.01} step={1} addonAfter="元" className="full-width" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="提现方式"
|
||||
name="accountChannel"
|
||||
rules={[{ required: true, message: '请选择提现方式' }]}
|
||||
>
|
||||
<Select
|
||||
options={[
|
||||
{ value: 'alipay', label: '支付宝' },
|
||||
{ value: 'wechat', label: '微信收款' },
|
||||
{ value: 'bank', label: '银行卡' },
|
||||
]}
|
||||
options={withdrawalAccounts.map((account) => ({
|
||||
value: account.accountChannel,
|
||||
label:
|
||||
account.accountChannel === 'wechat'
|
||||
? '微信收款 · 收款二维码'
|
||||
: `${formatWithdrawChannel(account.accountChannel)} · ${account.accountNoMasked}`,
|
||||
}))}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="收款人姓名"
|
||||
name="accountName"
|
||||
rules={[{ required: true, message: '请输入收款人姓名' }]}
|
||||
label="提现金额"
|
||||
name="amount"
|
||||
rules={[
|
||||
{ required: true, message: '请输入提现金额' },
|
||||
{
|
||||
validator(_, value) {
|
||||
if (Number(value || 0) > 100 && selectedWithdrawChannel !== 'alipay') {
|
||||
return Promise.reject(
|
||||
new Error('超过 100 元仅支持支付宝提现,请联系客服修改提现信息'),
|
||||
)
|
||||
}
|
||||
return Promise.resolve()
|
||||
},
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input placeholder="请输入真实姓名" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="收款账号"
|
||||
name="accountNo"
|
||||
rules={[{ required: true, message: '请输入收款账号' }]}
|
||||
>
|
||||
<Input placeholder="请输入支付宝账号、微信号或银行卡号" />
|
||||
<InputNumber min={0.01} step={1} addonAfter="元" className="full-width" />
|
||||
</Form.Item>
|
||||
<Form.Item label="备注说明" name="note">
|
||||
<Input.TextArea rows={4} placeholder="可补充到账要求、手机号、开户行等说明。" />
|
||||
|
||||
@@ -83,9 +83,7 @@ export function createWorkerRechargeRequest(payload: {
|
||||
|
||||
export function createWorkerWithdrawRequest(payload: {
|
||||
amount?: number
|
||||
accountChannel?: string
|
||||
accountName?: string
|
||||
accountNo?: string
|
||||
accountChannel: string
|
||||
note?: string
|
||||
}) {
|
||||
return apiPost<{ request: WorkerFinanceRequest }>(
|
||||
@@ -94,6 +92,15 @@ export function createWorkerWithdrawRequest(payload: {
|
||||
)
|
||||
}
|
||||
|
||||
export function createWorkerWithdrawalAccount(payload: {
|
||||
accountChannel: string
|
||||
accountName: string
|
||||
accountNo?: string
|
||||
wechatQrCodeImages?: UploadedFile[]
|
||||
}) {
|
||||
return apiPost('/api/v1/worker/profile/withdrawal-account', payload)
|
||||
}
|
||||
|
||||
export function changeWorkerPassword(payload: { currentPassword: string; newPassword: string }) {
|
||||
return apiPost<{ worker: WorkerUser; reloginRequired: boolean }>(
|
||||
'/api/v1/worker/profile/change-password',
|
||||
|
||||
@@ -105,12 +105,21 @@ export type WorkerFinanceConfig = {
|
||||
}
|
||||
}
|
||||
|
||||
export type WorkerWithdrawalAccount = {
|
||||
accountChannel: string
|
||||
accountName: string
|
||||
accountNoMasked: string
|
||||
wechatQrCodeImage: UploadedFile | null
|
||||
createdAt: string | null
|
||||
}
|
||||
|
||||
export type WorkerProfileResponse = {
|
||||
worker: WorkerUser
|
||||
permissions: Record<string, unknown>
|
||||
summary: WorkerProfileSummary
|
||||
levelProgress: WorkerLevelProgress | null
|
||||
financeConfig: WorkerFinanceConfig
|
||||
withdrawalAccounts: WorkerWithdrawalAccount[]
|
||||
/** 打手端订单详情是否展示流转记录(后台配置开关,默认关闭) */
|
||||
orderTimelineVisible?: boolean
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user