forked from gxwebsoft/mp-10550
refactor(dealer): 简化提现功能只支持微信钱包
- 移除支付宝和银行卡提现方式的选择 - 删除相关账户信息输入字段验证逻辑 - 简化提现表单只保留微信钱包选项 - 更新快速金额按钮配置 - 移除多余的状态管理变量 - 删除不再使用的 Radio 和 Cell 组件导入 - 移除提现
This commit is contained in:
@@ -1,184 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
import { render, fireEvent, waitFor } from '@testing-library/react'
|
|
||||||
import DealerWithdraw from '../index'
|
|
||||||
import { useDealerUser } from '@/hooks/useDealerUser'
|
|
||||||
import * as withdrawAPI from '@/api/shop/shopDealerWithdraw'
|
|
||||||
|
|
||||||
// Mock dependencies
|
|
||||||
jest.mock('@/hooks/useDealerUser')
|
|
||||||
jest.mock('@/api/shop/shopDealerWithdraw')
|
|
||||||
jest.mock('@tarojs/taro', () => ({
|
|
||||||
showToast: jest.fn(),
|
|
||||||
getStorageSync: jest.fn(() => 123),
|
|
||||||
}))
|
|
||||||
|
|
||||||
const mockUseDealerUser = useDealerUser as jest.MockedFunction<typeof useDealerUser>
|
|
||||||
const mockAddShopDealerWithdraw = withdrawAPI.addShopDealerWithdraw as jest.MockedFunction<typeof withdrawAPI.addShopDealerWithdraw>
|
|
||||||
const mockPageShopDealerWithdraw = withdrawAPI.pageShopDealerWithdraw as jest.MockedFunction<typeof withdrawAPI.pageShopDealerWithdraw>
|
|
||||||
|
|
||||||
describe('DealerWithdraw', () => {
|
|
||||||
const mockDealerUser = {
|
|
||||||
userId: 123,
|
|
||||||
money: '10000.00',
|
|
||||||
realName: '测试用户',
|
|
||||||
mobile: '13800138000'
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
mockUseDealerUser.mockReturnValue({
|
|
||||||
dealerUser: mockDealerUser,
|
|
||||||
loading: false,
|
|
||||||
error: null,
|
|
||||||
refresh: jest.fn()
|
|
||||||
})
|
|
||||||
|
|
||||||
mockPageShopDealerWithdraw.mockResolvedValue({
|
|
||||||
list: [],
|
|
||||||
count: 0
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.clearAllMocks()
|
|
||||||
})
|
|
||||||
|
|
||||||
test('应该正确显示可提现余额', () => {
|
|
||||||
const { getByText } = render(<DealerWithdraw />)
|
|
||||||
expect(getByText('10000.00')).toBeInTheDocument()
|
|
||||||
expect(getByText('可提现余额')).toBeInTheDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
test('应该验证最低提现金额', async () => {
|
|
||||||
mockAddShopDealerWithdraw.mockResolvedValue('success')
|
|
||||||
|
|
||||||
const { getByPlaceholderText, getByText } = render(<DealerWithdraw />)
|
|
||||||
|
|
||||||
// 输入低于最低金额的数值
|
|
||||||
const amountInput = getByPlaceholderText('请输入提现金额')
|
|
||||||
fireEvent.change(amountInput, { target: { value: '50' } })
|
|
||||||
|
|
||||||
// 选择提现方式
|
|
||||||
const wechatRadio = getByText('微信钱包')
|
|
||||||
fireEvent.click(wechatRadio)
|
|
||||||
|
|
||||||
// 提交表单
|
|
||||||
const submitButton = getByText('申请提现')
|
|
||||||
fireEvent.click(submitButton)
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(require('@tarojs/taro').showToast).toHaveBeenCalledWith({
|
|
||||||
title: '最低提现金额为100元',
|
|
||||||
icon: 'error'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test('应该验证提现金额不超过可用余额', async () => {
|
|
||||||
const { getByPlaceholderText, getByText } = render(<DealerWithdraw />)
|
|
||||||
|
|
||||||
// 输入超过可用余额的金额
|
|
||||||
const amountInput = getByPlaceholderText('请输入提现金额')
|
|
||||||
fireEvent.change(amountInput, { target: { value: '20000' } })
|
|
||||||
|
|
||||||
// 选择提现方式
|
|
||||||
const wechatRadio = getByText('微信钱包')
|
|
||||||
fireEvent.click(wechatRadio)
|
|
||||||
|
|
||||||
// 提交表单
|
|
||||||
const submitButton = getByText('申请提现')
|
|
||||||
fireEvent.click(submitButton)
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(require('@tarojs/taro').showToast).toHaveBeenCalledWith({
|
|
||||||
title: '提现金额超过可用余额',
|
|
||||||
icon: 'error'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test('应该验证支付宝账户信息完整性', async () => {
|
|
||||||
const { getByPlaceholderText, getByText } = render(<DealerWithdraw />)
|
|
||||||
|
|
||||||
// 输入有效金额
|
|
||||||
const amountInput = getByPlaceholderText('请输入提现金额')
|
|
||||||
fireEvent.change(amountInput, { target: { value: '1000' } })
|
|
||||||
|
|
||||||
// 选择支付宝提现
|
|
||||||
const alipayRadio = getByText('支付宝')
|
|
||||||
fireEvent.click(alipayRadio)
|
|
||||||
|
|
||||||
// 只填写账号,不填写姓名
|
|
||||||
const accountInput = getByPlaceholderText('请输入支付宝账号')
|
|
||||||
fireEvent.change(accountInput, { target: { value: 'test@alipay.com' } })
|
|
||||||
|
|
||||||
// 提交表单
|
|
||||||
const submitButton = getByText('申请提现')
|
|
||||||
fireEvent.click(submitButton)
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(require('@tarojs/taro').showToast).toHaveBeenCalledWith({
|
|
||||||
title: '请填写完整的支付宝信息',
|
|
||||||
icon: 'error'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test('应该成功提交微信提现申请', async () => {
|
|
||||||
mockAddShopDealerWithdraw.mockResolvedValue('success')
|
|
||||||
|
|
||||||
const { getByPlaceholderText, getByText } = render(<DealerWithdraw />)
|
|
||||||
|
|
||||||
// 输入有效金额
|
|
||||||
const amountInput = getByPlaceholderText('请输入提现金额')
|
|
||||||
fireEvent.change(amountInput, { target: { value: '1000' } })
|
|
||||||
|
|
||||||
// 选择微信提现
|
|
||||||
const wechatRadio = getByText('微信钱包')
|
|
||||||
fireEvent.click(wechatRadio)
|
|
||||||
|
|
||||||
// 提交表单
|
|
||||||
const submitButton = getByText('申请提现')
|
|
||||||
fireEvent.click(submitButton)
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(mockAddShopDealerWithdraw).toHaveBeenCalledWith({
|
|
||||||
userId: 123,
|
|
||||||
money: '1000',
|
|
||||||
payType: 10,
|
|
||||||
applyStatus: 10,
|
|
||||||
platform: 'MiniProgram'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
await waitFor(() => {
|
|
||||||
expect(require('@tarojs/taro').showToast).toHaveBeenCalledWith({
|
|
||||||
title: '提现申请已提交',
|
|
||||||
icon: 'success'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
test('快捷金额按钮应该正常工作', () => {
|
|
||||||
const { getByText, getByPlaceholderText } = render(<DealerWithdraw />)
|
|
||||||
|
|
||||||
// 点击快捷金额按钮
|
|
||||||
const quickAmountButton = getByText('500')
|
|
||||||
fireEvent.click(quickAmountButton)
|
|
||||||
|
|
||||||
// 验证金额输入框的值
|
|
||||||
const amountInput = getByPlaceholderText('请输入提现金额') as HTMLInputElement
|
|
||||||
expect(amountInput.value).toBe('500')
|
|
||||||
})
|
|
||||||
|
|
||||||
test('全部按钮应该设置为可用余额', () => {
|
|
||||||
const { getByText, getByPlaceholderText } = render(<DealerWithdraw />)
|
|
||||||
|
|
||||||
// 点击全部按钮
|
|
||||||
const allButton = getByText('全部')
|
|
||||||
fireEvent.click(allButton)
|
|
||||||
|
|
||||||
// 验证金额输入框的值
|
|
||||||
const amountInput = getByPlaceholderText('请输入提现金额') as HTMLInputElement
|
|
||||||
expect(amountInput.value).toBe('10000.00')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
import React, {useState, useRef, useEffect, useCallback} from 'react'
|
import React, {useState, useRef, useEffect, useCallback} from 'react'
|
||||||
import {View, Text} from '@tarojs/components'
|
import {View, Text} from '@tarojs/components'
|
||||||
import {
|
import {
|
||||||
Cell,
|
|
||||||
Space,
|
Space,
|
||||||
Button,
|
Button,
|
||||||
Form,
|
Form,
|
||||||
Input,
|
Input,
|
||||||
CellGroup,
|
CellGroup,
|
||||||
Radio,
|
|
||||||
Tabs,
|
Tabs,
|
||||||
Tag,
|
Tag,
|
||||||
Empty,
|
Empty,
|
||||||
@@ -89,7 +87,6 @@ const normalizeMoneyString = (money: unknown) => {
|
|||||||
|
|
||||||
const DealerWithdraw: React.FC = () => {
|
const DealerWithdraw: React.FC = () => {
|
||||||
const [activeTab, setActiveTab] = useState<string | number>('0')
|
const [activeTab, setActiveTab] = useState<string | number>('0')
|
||||||
const [selectedAccount, setSelectedAccount] = useState('')
|
|
||||||
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)
|
||||||
@@ -216,14 +213,6 @@ const DealerWithdraw: React.FC = () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!values.accountType) {
|
|
||||||
Taro.showToast({
|
|
||||||
title: '请选择提现方式',
|
|
||||||
icon: 'error'
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证提现金额
|
// 验证提现金额
|
||||||
const amount = parseFloat(String(values.amount))
|
const amount = parseFloat(String(values.amount))
|
||||||
const available = parseFloat(normalizeMoneyString(availableAmount).replace(/,/g, ''))
|
const available = parseFloat(normalizeMoneyString(availableAmount).replace(/,/g, ''))
|
||||||
@@ -252,50 +241,20 @@ const DealerWithdraw: React.FC = () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证账户信息
|
|
||||||
if (values.accountType === 'alipay') {
|
|
||||||
if (!values.account || !values.accountName) {
|
|
||||||
Taro.showToast({
|
|
||||||
title: '请填写完整的支付宝信息',
|
|
||||||
icon: 'error'
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else if (values.accountType === 'bank') {
|
|
||||||
if (!values.account || !values.accountName || !values.bankName) {
|
|
||||||
Taro.showToast({
|
|
||||||
title: '请填写完整的银行卡信息',
|
|
||||||
icon: 'error'
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setSubmitting(true)
|
setSubmitting(true)
|
||||||
|
|
||||||
const withdrawData: ShopDealerWithdraw = {
|
const withdrawData: ShopDealerWithdraw = {
|
||||||
userId: dealerUser.userId,
|
userId: dealerUser.userId,
|
||||||
money: values.amount,
|
money: values.amount,
|
||||||
payType: values.accountType === 'wechat' ? 10 :
|
// Only support WeChat wallet withdrawals.
|
||||||
values.accountType === 'alipay' ? 20 : 30,
|
payType: 10,
|
||||||
applyStatus: 10, // 待审核
|
applyStatus: 10, // 待审核
|
||||||
platform: 'MiniProgram'
|
platform: 'MiniProgram'
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据提现方式设置账户信息
|
|
||||||
if (values.accountType === 'alipay') {
|
|
||||||
withdrawData.alipayAccount = values.account
|
|
||||||
withdrawData.alipayName = values.accountName
|
|
||||||
} else if (values.accountType === 'bank') {
|
|
||||||
withdrawData.bankCard = values.account
|
|
||||||
withdrawData.bankAccount = values.accountName
|
|
||||||
withdrawData.bankName = values.bankName || '银行卡'
|
|
||||||
}
|
|
||||||
|
|
||||||
// WeChat wallet: backend should return `package_info`, frontend opens the "confirm receipt" page
|
// WeChat wallet: backend should return `package_info`, frontend opens the "confirm receipt" page
|
||||||
// for user to click "确认收款".
|
// for user to click "确认收款".
|
||||||
if (values.accountType === 'wechat') {
|
|
||||||
if (!canRequestMerchantTransferConfirm()) {
|
if (!canRequestMerchantTransferConfirm()) {
|
||||||
throw new Error('当前环境不支持微信收款确认,请在微信小程序内操作')
|
throw new Error('当前环境不支持微信收款确认,请在微信小程序内操作')
|
||||||
}
|
}
|
||||||
@@ -321,17 +280,9 @@ const DealerWithdraw: React.FC = () => {
|
|||||||
throw new Error(msg || '调起收款确认页失败,请稍后重试')
|
throw new Error(msg || '调起收款确认页失败,请稍后重试')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
await addShopDealerWithdraw(withdrawData)
|
|
||||||
Taro.showToast({
|
|
||||||
title: '提现申请已提交',
|
|
||||||
icon: 'success'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重置表单
|
// 重置表单
|
||||||
formRef.current?.resetFields()
|
formRef.current?.resetFields()
|
||||||
setSelectedAccount('')
|
|
||||||
|
|
||||||
// 刷新数据
|
// 刷新数据
|
||||||
await handleRefresh()
|
await handleRefresh()
|
||||||
@@ -350,7 +301,7 @@ const DealerWithdraw: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const quickAmounts = ['1','100', '300', '500', '1000']
|
const quickAmounts = ['0.2','100', '300', '500', '1000']
|
||||||
|
|
||||||
const setQuickAmount = (amount: string) => {
|
const setQuickAmount = (amount: string) => {
|
||||||
formRef.current?.setFieldsValue({amount})
|
formRef.current?.setFieldsValue({amount})
|
||||||
@@ -409,14 +360,6 @@ const DealerWithdraw: React.FC = () => {
|
|||||||
<Input
|
<Input
|
||||||
placeholder="请输入提现金额"
|
placeholder="请输入提现金额"
|
||||||
type="number"
|
type="number"
|
||||||
onChange={(value) => {
|
|
||||||
// 实时验证提现金额
|
|
||||||
const amount = parseFloat(String(value))
|
|
||||||
const available = parseFloat(normalizeMoneyString(availableAmount).replace(/,/g, ''))
|
|
||||||
if (!isNaN(amount) && amount > available) {
|
|
||||||
// 可以在这里添加实时提示,但不阻止输入
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
@@ -444,62 +387,11 @@ const DealerWithdraw: React.FC = () => {
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<Form.Item name="accountType" label="提现方式" required>
|
|
||||||
<Radio.Group
|
|
||||||
value={selectedAccount}
|
|
||||||
onChange={(value) => {
|
|
||||||
const next = String(value)
|
|
||||||
setSelectedAccount(next)
|
|
||||||
// Ensure Form gets the field value even when Radio.Group is controlled.
|
|
||||||
formRef.current?.setFieldsValue({accountType: next})
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Cell.Group>
|
|
||||||
<Cell>
|
|
||||||
<Radio value="wechat">微信钱包</Radio>
|
|
||||||
</Cell>
|
|
||||||
<Cell>
|
|
||||||
<Radio value="alipay">支付宝</Radio>
|
|
||||||
</Cell>
|
|
||||||
<Cell>
|
|
||||||
<Radio value="bank">银行卡</Radio>
|
|
||||||
</Cell>
|
|
||||||
</Cell.Group>
|
|
||||||
</Radio.Group>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
{selectedAccount === 'alipay' && (
|
|
||||||
<>
|
|
||||||
<Form.Item name="account" label="支付宝账号" required>
|
|
||||||
<Input placeholder="请输入支付宝账号"/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item name="accountName" label="支付宝姓名" required>
|
|
||||||
<Input placeholder="请输入支付宝实名姓名"/>
|
|
||||||
</Form.Item>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{selectedAccount === 'bank' && (
|
|
||||||
<>
|
|
||||||
<Form.Item name="bankName" label="开户银行" required>
|
|
||||||
<Input placeholder="请输入开户银行名称"/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item name="account" label="银行卡号" required>
|
|
||||||
<Input placeholder="请输入银行卡号"/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item name="accountName" label="开户姓名" required>
|
|
||||||
<Input placeholder="请输入银行卡开户姓名"/>
|
|
||||||
</Form.Item>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{selectedAccount === 'wechat' && (
|
|
||||||
<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>
|
||||||
|
|
||||||
<View className="mt-6 px-4">
|
<View className="mt-6 px-4">
|
||||||
@@ -508,7 +400,7 @@ const DealerWithdraw: React.FC = () => {
|
|||||||
type="primary"
|
type="primary"
|
||||||
nativeType="submit"
|
nativeType="submit"
|
||||||
loading={submitting}
|
loading={submitting}
|
||||||
disabled={submitting || !selectedAccount}
|
disabled={submitting}
|
||||||
>
|
>
|
||||||
{submitting ? '提交中...' : '申请提现'}
|
{submitting ? '提交中...' : '申请提现'}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
Reference in New Issue
Block a user