forked from gxwebsoft/mp-10550
feat(dealer): 更新提现流程为审核后领取模式
- 添加新的API接口getShopDealerWithdraw和updateShopDealerWithdraw - 新增package_info相关字段用于微信确认收款流程 - 添加claimingId状态管理用于控制领取按钮 - 修改状态显示逻辑,将"审核通过"改为"待领取",颜色从success改为info - 移除直接调用微信收款确认的逻辑,改为先提交审核再领取 - 新增handleClaim函数处理提现领取流程 - 在提现记录中添加"立即领取"按钮,仅在待领取状态下显示 - 更新提现说明文案,明确审核后领取流程 - 调整记录列表界面布局,优化时间显示和按钮位置
This commit is contained in:
@@ -16,11 +16,20 @@ import {Wallet} from '@nutui/icons-react-taro'
|
|||||||
import {businessGradients} from '@/styles/gradients'
|
import {businessGradients} from '@/styles/gradients'
|
||||||
import Taro from '@tarojs/taro'
|
import Taro from '@tarojs/taro'
|
||||||
import {useDealerUser} from '@/hooks/useDealerUser'
|
import {useDealerUser} from '@/hooks/useDealerUser'
|
||||||
import {pageShopDealerWithdraw, addShopDealerWithdraw} from '@/api/shop/shopDealerWithdraw'
|
import {
|
||||||
|
pageShopDealerWithdraw,
|
||||||
|
addShopDealerWithdraw,
|
||||||
|
getShopDealerWithdraw,
|
||||||
|
updateShopDealerWithdraw
|
||||||
|
} from '@/api/shop/shopDealerWithdraw'
|
||||||
import type {ShopDealerWithdraw} from '@/api/shop/shopDealerWithdraw/model'
|
import type {ShopDealerWithdraw} from '@/api/shop/shopDealerWithdraw/model'
|
||||||
|
|
||||||
interface WithdrawRecordWithDetails extends ShopDealerWithdraw {
|
interface WithdrawRecordWithDetails extends ShopDealerWithdraw {
|
||||||
accountDisplay?: string
|
accountDisplay?: string
|
||||||
|
// Backend may include these fields for WeChat "confirm receipt" flow after approval.
|
||||||
|
package_info?: string
|
||||||
|
packageInfo?: string
|
||||||
|
package?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const extractPackageInfo = (result: unknown): string | null => {
|
const extractPackageInfo = (result: unknown): string | null => {
|
||||||
@@ -90,6 +99,7 @@ const DealerWithdraw: React.FC = () => {
|
|||||||
const [loading, setLoading] = useState<boolean>(false)
|
const [loading, setLoading] = useState<boolean>(false)
|
||||||
const [refreshing, setRefreshing] = useState<boolean>(false)
|
const [refreshing, setRefreshing] = useState<boolean>(false)
|
||||||
const [submitting, setSubmitting] = useState<boolean>(false)
|
const [submitting, setSubmitting] = useState<boolean>(false)
|
||||||
|
const [claimingId, setClaimingId] = useState<number | null>(null)
|
||||||
const [availableAmount, setAvailableAmount] = useState<string>('0.00')
|
const [availableAmount, setAvailableAmount] = useState<string>('0.00')
|
||||||
const [withdrawRecords, setWithdrawRecords] = useState<WithdrawRecordWithDetails[]>([])
|
const [withdrawRecords, setWithdrawRecords] = useState<WithdrawRecordWithDetails[]>([])
|
||||||
const formRef = useRef<any>(null)
|
const formRef = useRef<any>(null)
|
||||||
@@ -179,7 +189,7 @@ const DealerWithdraw: React.FC = () => {
|
|||||||
case 40:
|
case 40:
|
||||||
return '已到账'
|
return '已到账'
|
||||||
case 20:
|
case 20:
|
||||||
return '审核通过'
|
return '待领取'
|
||||||
case 10:
|
case 10:
|
||||||
return '待审核'
|
return '待审核'
|
||||||
case 30:
|
case 30:
|
||||||
@@ -194,7 +204,7 @@ const DealerWithdraw: React.FC = () => {
|
|||||||
case 40:
|
case 40:
|
||||||
return 'success'
|
return 'success'
|
||||||
case 20:
|
case 20:
|
||||||
return 'success'
|
return 'info'
|
||||||
case 10:
|
case 10:
|
||||||
return 'warning'
|
return 'warning'
|
||||||
case 30:
|
case 30:
|
||||||
@@ -253,33 +263,12 @@ const DealerWithdraw: React.FC = () => {
|
|||||||
platform: 'MiniProgram'
|
platform: 'MiniProgram'
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeChat wallet: backend should return `package_info`, frontend opens the "confirm receipt" page
|
// Security flow:
|
||||||
// for user to click "确认收款".
|
// 1) user submits => applyStatus=10 (待审核)
|
||||||
if (!canRequestMerchantTransferConfirm()) {
|
// 2) backend审核通过 => applyStatus=20 (待领取)
|
||||||
throw new Error('当前环境不支持微信收款确认,请在微信小程序内操作')
|
// 3) user goes to records to "领取" => applyStatus=40 (已到账)
|
||||||
}
|
await addShopDealerWithdraw(withdrawData)
|
||||||
|
Taro.showToast({title: '提现申请已提交,等待审核', icon: 'success'})
|
||||||
const createResult = await addShopDealerWithdraw(withdrawData)
|
|
||||||
const packageInfo = extractPackageInfo(createResult)
|
|
||||||
if (!packageInfo) {
|
|
||||||
throw new Error('后台未返回 package_info,无法调起微信收款确认页')
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await requestMerchantTransferConfirm(packageInfo)
|
|
||||||
Taro.showToast({
|
|
||||||
title: '已调起收款确认页',
|
|
||||||
icon: 'success'
|
|
||||||
})
|
|
||||||
} catch (e: any) {
|
|
||||||
const msg = String(e?.errMsg || e?.message || '')
|
|
||||||
if (/cancel/i.test(msg)) {
|
|
||||||
Taro.showToast({title: '已取消收款确认', icon: 'none'})
|
|
||||||
} else {
|
|
||||||
// Keep the original WeChat error for troubleshooting (e.g. "商户号错误").
|
|
||||||
throw new Error(msg || '调起收款确认页失败,请稍后重试')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重置表单
|
// 重置表单
|
||||||
formRef.current?.resetFields()
|
formRef.current?.resetFields()
|
||||||
@@ -301,6 +290,71 @@ const DealerWithdraw: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleClaim = async (record: WithdrawRecordWithDetails) => {
|
||||||
|
if (!record?.id) {
|
||||||
|
Taro.showToast({title: '记录不存在', icon: 'error'})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (record.applyStatus !== 20) {
|
||||||
|
Taro.showToast({title: '当前状态不可领取', icon: 'none'})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (record.payType !== 10) {
|
||||||
|
Taro.showToast({title: '仅支持微信提现领取', icon: 'none'})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (claimingId !== null) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
setClaimingId(record.id)
|
||||||
|
|
||||||
|
if (!canRequestMerchantTransferConfirm()) {
|
||||||
|
throw new Error('当前环境不支持微信收款确认,请在微信小程序内操作')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prefer getting package from the list record; if missing, query detail.
|
||||||
|
let packageInfo = extractPackageInfo(record as any)
|
||||||
|
if (!packageInfo) {
|
||||||
|
const detail = await getShopDealerWithdraw(record.id)
|
||||||
|
packageInfo = extractPackageInfo(detail as any)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!packageInfo) {
|
||||||
|
throw new Error('后台未返回 package_info,无法领取,请联系管理员')
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await requestMerchantTransferConfirm(packageInfo)
|
||||||
|
} catch (e: any) {
|
||||||
|
const msg = String(e?.errMsg || e?.message || '')
|
||||||
|
if (/cancel/i.test(msg)) {
|
||||||
|
Taro.showToast({title: '已取消领取', icon: 'none'})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
throw new Error(msg || '领取失败,请稍后重试')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Best-effort: ask backend to mark as "已到账".
|
||||||
|
try {
|
||||||
|
await updateShopDealerWithdraw({id: record.id, applyStatus: 40} as any)
|
||||||
|
} catch (e) {
|
||||||
|
// Backend may enforce state transitions; still refresh to reflect backend truth.
|
||||||
|
console.warn('更新提现状态失败:', e)
|
||||||
|
}
|
||||||
|
|
||||||
|
Taro.showToast({title: '领取成功', icon: 'success'})
|
||||||
|
await handleRefresh()
|
||||||
|
} catch (e: any) {
|
||||||
|
console.error('领取失败:', e)
|
||||||
|
Taro.showToast({title: e?.message || '领取失败', icon: 'error'})
|
||||||
|
} finally {
|
||||||
|
setClaimingId(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const quickAmounts = ['0.2','100', '300', '500', '1000']
|
const quickAmounts = ['0.2','100', '300', '500', '1000']
|
||||||
|
|
||||||
const setQuickAmount = (amount: string) => {
|
const setQuickAmount = (amount: string) => {
|
||||||
@@ -389,7 +443,7 @@ const DealerWithdraw: React.FC = () => {
|
|||||||
|
|
||||||
<View className="px-4 py-2">
|
<View className="px-4 py-2">
|
||||||
<Text className="text-sm text-gray-500">
|
<Text className="text-sm text-gray-500">
|
||||||
提现方式:微信钱包(提交后将拉起微信收款确认页,需要您点击“确认收款”后才会完成转账)
|
提现方式:微信钱包(提交后进入“待审核”,审核通过后请到“提现记录”点击“领取到微信零钱”完成收款确认)
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</CellGroup>
|
</CellGroup>
|
||||||
@@ -431,28 +485,46 @@ const DealerWithdraw: React.FC = () => {
|
|||||||
<Text className="font-semibold text-gray-800 mb-1">
|
<Text className="font-semibold text-gray-800 mb-1">
|
||||||
提现金额:¥{record.money}
|
提现金额:¥{record.money}
|
||||||
</Text>
|
</Text>
|
||||||
<Text className="text-sm text-gray-500">
|
{/*<Text className="text-sm text-gray-500">*/}
|
||||||
提现账户:{record.accountDisplay}
|
{/* 提现账户:{record.accountDisplay}*/}
|
||||||
</Text>
|
{/*</Text>*/}
|
||||||
</Space>
|
</Space>
|
||||||
<Tag type={getStatusColor(record.applyStatus)}>
|
<Tag background="#999999" type={getStatusColor(record.applyStatus)} plain>
|
||||||
{getStatusText(record.applyStatus)}
|
{getStatusText(record.applyStatus)}
|
||||||
</Tag>
|
</Tag>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View className="text-xs text-gray-400">
|
|
||||||
<Text>申请时间:{record.createTime}</Text>
|
{record.applyStatus === 20 && record.payType === 10 && (
|
||||||
{record.auditTime && (
|
<View className="flex justify-center">
|
||||||
<Text className="block mt-1">
|
<Button
|
||||||
审核时间:{new Date(record.auditTime).toLocaleString()}
|
size="small"
|
||||||
</Text>
|
type="primary"
|
||||||
|
loading={claimingId === record.id}
|
||||||
|
disabled={claimingId !== null}
|
||||||
|
onClick={() => handleClaim(record)}
|
||||||
|
>
|
||||||
|
立即领取
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
)}
|
)}
|
||||||
{record.rejectReason && (
|
|
||||||
<Text className="block mt-1 text-red-500">
|
<View className="flex justify-between items-center">
|
||||||
驳回原因:{record.rejectReason}
|
<View className="text-xs text-gray-400">
|
||||||
</Text>
|
<Text>创建时间:{record.createTime}</Text>
|
||||||
)}
|
{record.auditTime && (
|
||||||
</View>
|
<Text className="block mt-1">
|
||||||
|
审核时间:{record.auditTime}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
{record.rejectReason && (
|
||||||
|
<Text className="block mt-1 text-red-500">
|
||||||
|
驳回原因:{record.rejectReason}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
</View>
|
</View>
|
||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
Reference in New Issue
Block a user