forked from gxwebsoft/mp-10550
feat(withdraw): 添加实名认证验证功能
- 在提现页面集成实名认证状态检查 - 添加 fetchVerifyStatus 函数用于获取认证状态 - 实现认证状态包括未知、已认证、未认证、审核中、已驳回 - 在提交提现前验证用户是否已完成实名认证 - 添加去认证按钮跳转到认证页面 - 优化订单详情和订单列表中的取消订单逻辑 - 修复用户认证页面的表单验证逻辑 - 添加真实姓名和身份证号输入字段到企业认证表单
This commit is contained in:
@@ -16,6 +16,8 @@ import {Wallet} from '@nutui/icons-react-taro'
|
||||
import {businessGradients} from '@/styles/gradients'
|
||||
import Taro from '@tarojs/taro'
|
||||
import {useDealerUser} from '@/hooks/useDealerUser'
|
||||
import {myUserVerify} from '@/api/system/userVerify'
|
||||
import {goTo} from '@/utils/navigation'
|
||||
import {
|
||||
pageShopDealerWithdraw,
|
||||
addShopDealerWithdraw,
|
||||
@@ -106,6 +108,8 @@ const DealerWithdraw: React.FC = () => {
|
||||
const formRef = useRef<any>(null)
|
||||
|
||||
const {dealerUser} = useDealerUser()
|
||||
const [verifyStatus, setVerifyStatus] = useState<'unknown' | 'verified' | 'unverified' | 'pending' | 'rejected'>('unknown')
|
||||
const [verifyStatusText, setVerifyStatusText] = useState<string>('')
|
||||
|
||||
// Tab 切换处理函数
|
||||
const handleTabChange = (value: string | number) => {
|
||||
@@ -185,6 +189,57 @@ const DealerWithdraw: React.FC = () => {
|
||||
}
|
||||
}, [fetchBalance, fetchWithdrawRecords])
|
||||
|
||||
// 判断实名认证状态:提现前必须完成实名认证(已通过)
|
||||
const fetchVerifyStatus = useCallback(async () => {
|
||||
// Fast path: some pages store this flag after login.
|
||||
if (String(Taro.getStorageSync('Certification')) === '1') {
|
||||
setVerifyStatus('verified')
|
||||
setVerifyStatusText('已实名认证')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const r = await myUserVerify({})
|
||||
if (!r) {
|
||||
setVerifyStatus('unverified')
|
||||
setVerifyStatusText('未实名认证')
|
||||
return
|
||||
}
|
||||
|
||||
const s = Number((r as any).status)
|
||||
const st = String((r as any).statusText || '')
|
||||
|
||||
// Common convention in this project: 0审核中/待审核, 1已通过, 2已驳回
|
||||
if (s === 1) {
|
||||
setVerifyStatus('verified')
|
||||
setVerifyStatusText(st || '已实名认证')
|
||||
return
|
||||
}
|
||||
if (s === 0) {
|
||||
setVerifyStatus('pending')
|
||||
setVerifyStatusText(st || '审核中')
|
||||
return
|
||||
}
|
||||
if (s === 2) {
|
||||
setVerifyStatus('rejected')
|
||||
setVerifyStatusText(st || '已驳回')
|
||||
return
|
||||
}
|
||||
|
||||
setVerifyStatus('unverified')
|
||||
setVerifyStatusText(st || '未实名认证')
|
||||
} catch (e) {
|
||||
console.warn('获取实名认证状态失败,将按未认证处理:', e)
|
||||
setVerifyStatus('unverified')
|
||||
setVerifyStatusText('未实名认证')
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (!dealerUser?.userId) return
|
||||
fetchVerifyStatus().then()
|
||||
}, [dealerUser?.userId, fetchVerifyStatus])
|
||||
|
||||
const getStatusText = (status?: number) => {
|
||||
switch (status) {
|
||||
case 40:
|
||||
@@ -224,6 +279,14 @@ const DealerWithdraw: React.FC = () => {
|
||||
return
|
||||
}
|
||||
|
||||
if (verifyStatus !== 'verified') {
|
||||
Taro.showToast({
|
||||
title: '请先完成实名认证',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 验证提现金额
|
||||
const amount = parseFloat(String(values.amount))
|
||||
const available = parseFloat(normalizeMoneyString(availableAmount).replace(/,/g, ''))
|
||||
@@ -366,8 +429,28 @@ const DealerWithdraw: React.FC = () => {
|
||||
return Number.isFinite(n) ? n.toFixed(2) : '0.00'
|
||||
}
|
||||
|
||||
const goVerify = () => {
|
||||
goTo('/user/userVerify/index')
|
||||
}
|
||||
|
||||
const renderWithdrawForm = () => (
|
||||
<View>
|
||||
{(verifyStatus === 'unverified' || verifyStatus === 'pending' || verifyStatus === 'rejected') && (
|
||||
<View className="rounded-lg bg-white px-4 py-3 mb-4 mx-4">
|
||||
<View className="flex items-center justify-between">
|
||||
<View className="flex flex-col">
|
||||
<Text className="text-sm text-red-500">提现前请先完成实名认证</Text>
|
||||
{verifyStatusText ? (
|
||||
<Text className="text-xs text-gray-500 mt-1">当前状态:{verifyStatusText}</Text>
|
||||
) : null}
|
||||
</View>
|
||||
<Text className="text-sm text-blue-600" onClick={goVerify}>
|
||||
去认证
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* 余额卡片 */}
|
||||
<View className="rounded-xl p-6 mb-6 text-white relative overflow-hidden" style={{
|
||||
background: businessGradients.dealer.header
|
||||
@@ -452,7 +535,7 @@ const DealerWithdraw: React.FC = () => {
|
||||
type="primary"
|
||||
nativeType="submit"
|
||||
loading={submitting}
|
||||
disabled={submitting}
|
||||
disabled={submitting || verifyStatus !== 'verified'}
|
||||
>
|
||||
{submitting ? '提交中...' : '申请提现'}
|
||||
</Button>
|
||||
|
||||
@@ -20,11 +20,13 @@ const OrderDetail = () => {
|
||||
// 处理支付超时
|
||||
const handlePaymentExpired = async () => {
|
||||
if (!order) return;
|
||||
if (!order.orderId) return;
|
||||
|
||||
try {
|
||||
// 自动取消过期订单
|
||||
await updateShopOrder({
|
||||
...order,
|
||||
// 只传最小字段,避免误取消/误走售后流程
|
||||
orderId: order.orderId,
|
||||
orderStatus: 2 // 已取消
|
||||
});
|
||||
|
||||
|
||||
@@ -362,13 +362,23 @@ function OrderList(props: OrderListProps) {
|
||||
// 确认取消订单
|
||||
const handleConfirmCancel = async () => {
|
||||
if (!orderToCancel) return;
|
||||
if (!orderToCancel.orderId) {
|
||||
Taro.showToast({
|
||||
title: '订单信息错误',
|
||||
icon: 'error'
|
||||
});
|
||||
setOrderToCancel(null);
|
||||
setCancelDialogVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setCancelDialogVisible(false);
|
||||
|
||||
// 更新订单状态为已取消,而不是删除订单
|
||||
await updateShopOrder({
|
||||
...orderToCancel,
|
||||
// 只传最小字段,避免误取消/误走售后流程
|
||||
orderId: orderToCancel.orderId,
|
||||
orderStatus: 2 // 已取消
|
||||
});
|
||||
|
||||
|
||||
@@ -53,17 +53,17 @@ function Index() {
|
||||
const submitSucceed = (values: any) => {
|
||||
console.log('提交表单', values);
|
||||
if (FormData.status != 2 && FormData.status != undefined) return false;
|
||||
if (FormData.type == 0) {
|
||||
if (!FormData.sfz1 || !FormData.sfz2) {
|
||||
if (FormData.type == 0 || FormData.type == 1) {
|
||||
if (!FormData.realName || !FormData.idCard) {
|
||||
Taro.showToast({
|
||||
title: '请上传身份证正反面',
|
||||
title: '请填写真实姓名和身份证号码',
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (!FormData.realName || !FormData.idCard) {
|
||||
if (!FormData.sfz1 || !FormData.sfz2) {
|
||||
Taro.showToast({
|
||||
title: '请填写真实姓名和身份证号码',
|
||||
title: '请上传身份证正反面',
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
@@ -85,13 +85,6 @@ function Index() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(!FormData.realName){
|
||||
Taro.showToast({
|
||||
title: '请填写真实姓名',
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
const saveOrUpdate = isUpdate ? updateUserVerify : addUserVerify;
|
||||
saveOrUpdate({...FormData, status: 0}).then(() => {
|
||||
Taro.showToast({title: `提交成功`, icon: 'success'})
|
||||
@@ -249,6 +242,54 @@ function Index() {
|
||||
// 企业类型
|
||||
FormData.type == 1 && (
|
||||
<>
|
||||
<Form.Item
|
||||
label={'真实姓名'}
|
||||
name="realName"
|
||||
required
|
||||
initialValue={FormData.realName}
|
||||
rules={[{message: '请输入真实姓名'}]}
|
||||
>
|
||||
<Input
|
||||
placeholder={'请输入真实姓名'}
|
||||
type="text"
|
||||
disabled={FormData.status != 2 && FormData.status != undefined}
|
||||
value={FormData?.realName}
|
||||
onChange={(value) => setFormData({...FormData, realName: value})}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={'身份证号码'}
|
||||
name="idCard"
|
||||
required
|
||||
initialValue={FormData.idCard}
|
||||
rules={[{message: '请输入身份证号码'}]}
|
||||
>
|
||||
<Input
|
||||
placeholder="请输入身份证号码"
|
||||
type="text"
|
||||
value={FormData?.idCard}
|
||||
disabled={FormData.status != 2 && FormData.status != undefined}
|
||||
maxLength={18}
|
||||
onChange={(value) => setFormData({...FormData, idCard: value})}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={'上传证件'}
|
||||
name="image"
|
||||
required
|
||||
rules={[{message: '请上传身份证正反面'}]}
|
||||
>
|
||||
<div className={'flex gap-2'}>
|
||||
<div onClick={uploadSfz1}>
|
||||
<Image src={FormData.sfz1} lazyLoad={false}
|
||||
radius="10%" width="80" height="80"/>
|
||||
</div>
|
||||
<div onClick={uploadSfz2}>
|
||||
<Image src={FormData.sfz2} mode={'scaleToFill'} lazyLoad={false}
|
||||
radius="10%" width="80" height="80"/>
|
||||
</div>
|
||||
</div>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={'主体名称'}
|
||||
name="name"
|
||||
@@ -260,6 +301,7 @@ function Index() {
|
||||
placeholder={'请输入主体名称'}
|
||||
type="text"
|
||||
value={FormData?.name}
|
||||
disabled={FormData.status != 2 && FormData.status != undefined}
|
||||
onChange={(value) => setFormData({...FormData, name: value})}
|
||||
/>
|
||||
</Form.Item>
|
||||
@@ -274,6 +316,7 @@ function Index() {
|
||||
placeholder="请输入营业执照号码"
|
||||
type="text"
|
||||
value={FormData?.zzCode}
|
||||
disabled={FormData.status != 2 && FormData.status != undefined}
|
||||
maxLength={18}
|
||||
onChange={(value) => setFormData({...FormData, zzCode: value})}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user