feat(pages): 添加多个页面配置和功能模块

- 新增 .editorconfig、.eslintrc、.gitignore 配置文件
- 添加管理员文章管理页面配置和功能实现
- 添加经销商申请注册页面配置和功能实现
- 添加经销商银行卡管理页面配置和功能实现
- 添加经销商客户管理页面配置和功能实现
- 添加用户地址管理页面配置和功能实现
- 添加用户聊天消息页面配置和功能实现
- 添加用户礼品管理页面配置和功能实现
This commit is contained in:
2026-01-08 13:36:06 +08:00
commit 43106acc27
548 changed files with 75931 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
export default definePageConfig({
navigationBarTitleText: '提现审核'
})

View File

@@ -0,0 +1,498 @@
import React, {useState, useEffect, useCallback} from 'react'
import {View, Text} from '@tarojs/components'
import {
Space,
Tabs,
Tag,
Empty,
ActionSheet,
Loading,
PullToRefresh,
Button,
Dialog,
Image,
TextArea
} from '@nutui/nutui-react-taro'
import Taro from '@tarojs/taro'
import {useDealerUser} from '@/hooks/useDealerUser'
import {pageShopDealerWithdraw, updateShopDealerWithdraw} from '@/api/shop/shopDealerWithdraw'
import type {ShopDealerWithdraw} from '@/api/shop/shopDealerWithdraw/model'
import {ShopDealerBank} from "@/api/shop/shopDealerBank/model";
import {listShopDealerBank} from "@/api/shop/shopDealerBank";
import {pushNoticeOfWithdrawalToAccount} from "@/api/sdy/sdyTemplateMessage";
import {uploadFile} from "@/api/system/file";
interface WithdrawRecordWithDetails extends ShopDealerWithdraw {
accountDisplay?: string
}
const DealerWithdraw: React.FC = () => {
const [activeTab, setActiveTab] = useState<string | number>('10')
const [loading, setLoading] = useState<boolean>(false)
const [refreshing, setRefreshing] = useState<boolean>(false)
const [banks, setBanks] = useState<any[]>([])
const [isVisible, setIsVisible] = useState<boolean>(false)
const [withdrawRecords, setWithdrawRecords] = useState<WithdrawRecordWithDetails[]>([])
const [rejectDialogVisible, setRejectDialogVisible] = useState<boolean>(false)
const [rejectReason, setRejectReason] = useState<string>('')
const [currentRecord, setCurrentRecord] = useState<ShopDealerWithdraw | null>(null)
const [payDialogVisible, setPayDialogVisible] = useState<boolean>(false)
const [paymentImages, setPaymentImages] = useState<string[]>([])
const {dealerUser} = useDealerUser()
// Tab 切换处理函数
const handleTabChange = (value: string | number) => {
console.log('Tab切换到:', value)
setActiveTab(value)
// activeTab变化会自动触发useEffect重新获取数据无需手动调用
}
// 获取提现记录
const fetchWithdrawRecords = useCallback(async () => {
if (!dealerUser?.userId) return
try {
setLoading(true)
const currentStatus = Number(activeTab)
const result = await pageShopDealerWithdraw({
page: 1,
limit: 100,
applyStatus: currentStatus // 后端筛选,提高性能
})
if (result?.list) {
const processedRecords = result.list.map(record => ({
...record,
accountDisplay: getAccountDisplay(record)
}))
setWithdrawRecords(processedRecords)
}
} catch (error) {
console.error('获取提现记录失败:', error)
Taro.showToast({
title: '获取提现记录失败',
icon: 'none'
})
} finally {
setLoading(false)
}
}, [dealerUser?.userId, activeTab])
function fetchBanks() {
listShopDealerBank({}).then(data => {
const list = data.map(d => {
d.name = d.bankName;
d.type = d.bankName;
return d;
})
setBanks(list.concat({
name: '管理银行卡',
type: 'add'
}))
})
}
// 格式化账户显示
const getAccountDisplay = (record: ShopDealerWithdraw) => {
if (record.payType === 10) {
return '微信钱包'
} else if (record.payType === 20 && record.alipayAccount) {
return `支付宝(${record.alipayAccount.slice(-4)})`
} else if (record.payType === 30 && record.bankCard) {
return `${record.bankName || '银行卡'}(尾号${record.bankCard.slice(-4)})`
}
return '未知账户'
}
// 刷新数据
const handleRefresh = async () => {
setRefreshing(true)
await Promise.all([fetchWithdrawRecords()])
setRefreshing(false)
}
const handleSelect = (item: ShopDealerBank) => {
if(item.type === 'add'){
return Taro.navigateTo({
url: '/dealer/bank/index'
})
}
setIsVisible(false)
}
// 审核通过
const handleApprove = async (record: ShopDealerWithdraw) => {
try {
await updateShopDealerWithdraw({
...record,
applyStatus: 20, // 审核通过
})
Taro.showToast({
title: '审核通过',
icon: 'success'
})
await fetchWithdrawRecords()
} catch (error: any) {
if (error !== 'cancel') {
console.error('审核通过失败:', error)
Taro.showToast({
title: error.message || '操作失败',
icon: 'none'
})
}
}
}
// 驳回申请
const handleReject = (record: ShopDealerWithdraw) => {
setCurrentRecord(record)
setRejectReason('')
setRejectDialogVisible(true)
}
// 确认驳回
const confirmReject = async () => {
if (!rejectReason.trim()) {
Taro.showToast({
title: '请输入驳回原因',
icon: 'none'
})
return
}
try {
await updateShopDealerWithdraw({
...currentRecord!,
applyStatus: 30, // 驳回
rejectReason: rejectReason.trim()
})
Taro.showToast({
title: '已驳回',
icon: 'success'
})
setRejectDialogVisible(false)
setCurrentRecord(null)
setRejectReason('')
await fetchWithdrawRecords()
} catch (error: any) {
console.error('驳回失败:', error)
Taro.showToast({
title: error.message || '操作失败',
icon: 'none'
})
}
}
// 确认打款 - 打开打款对话框
const handleConfirmPay = (record: ShopDealerWithdraw) => {
setCurrentRecord(record)
setPaymentImages([])
setPayDialogVisible(true)
}
// 上传打款凭证
const handleUploadPaymentImage = async () => {
try {
// 直接调用uploadFile它内部会处理图片选择和上传
const data = await uploadFile();
console.log(data.url, 'uploaded image url');
// 确保url存在再添加到状态中
if (data.url) {
// 将返回的图片URL添加到状态中
const newImages = [...paymentImages, data.url];
setPaymentImages(newImages.slice(0, 3));
} else {
Taro.showToast({
title: '图片上传失败未返回有效URL',
icon: 'none'
});
}
} catch (error) {
console.error('上传图片失败:', error);
Taro.showToast({
title: '上传失败: ' + (error instanceof Error ? error.message : '未知错误'),
icon: 'none'
});
}
}
// 删除打款凭证
const handleRemovePaymentImage = (index: number) => {
const newImages = paymentImages.filter((_, i) => i !== index)
setPaymentImages(newImages)
}
// 确认提交打款
const confirmPayment = async () => {
try {
await updateShopDealerWithdraw({
...currentRecord!,
applyStatus: 40, // 已打款
image: paymentImages.length > 0 ? JSON.stringify(paymentImages) : undefined
})
Taro.showToast({
title: '打款确认成功',
icon: 'success'
})
if(currentRecord){
await pushNoticeOfWithdrawalToAccount(currentRecord).then()
}
setPayDialogVisible(false)
setCurrentRecord(null)
setPaymentImages([])
await fetchWithdrawRecords()
} catch (error: any) {
console.error('确认打款失败:', error)
Taro.showToast({
title: error.message || '操作失败',
icon: 'none'
})
}
}
// 初始化加载数据
useEffect(() => {
if (dealerUser?.userId) {
fetchWithdrawRecords().then()
fetchBanks()
}
}, [fetchWithdrawRecords])
const getStatusText = (status?: number) => {
switch (status) {
case 40:
return '已到账'
case 20:
return '审核通过'
case 10:
return '待审核'
case 30:
return '已驳回'
default:
return '未知'
}
}
const getStatusColor = (status?: number) => {
switch (status) {
case 40:
return 'success'
case 20:
return 'success'
case 10:
return 'warning'
case 30:
return 'danger'
default:
return 'default'
}
}
const renderWithdrawRecords = () => {
console.log('渲染提现记录:', {loading, recordsCount: withdrawRecords.length, dealerUserId: dealerUser?.userId})
return (
<PullToRefresh
disabled={refreshing}
onRefresh={handleRefresh}
>
<View>
{loading ? (
<View className="text-center py-8">
<Loading/>
<Text className="text-gray-500 mt-2">...</Text>
</View>
) : withdrawRecords.length > 0 ? (
withdrawRecords.map(record => (
<View key={record.id} className="rounded-lg bg-gray-50 p-4 mb-3 shadow-sm">
<View className="flex justify-between items-start mb-3">
<Space direction={'vertical'}>
<Text className="font-semibold text-gray-800 mb-1">
¥{Number(record.money).toFixed(2)}
</Text>
<Text className="text-sm text-gray-500">
{record.comments}
</Text>
<Text className={'text-sm text-gray-500'}>
{record.bankAccount} {record.phone}
</Text>
</Space>
<Tag type={getStatusColor(record.applyStatus)}>
{getStatusText(record.applyStatus)}
</Tag>
</View>
<View className="text-xs text-gray-400">
<Text>{record.createTime}</Text>
{record.auditTime && (
<Text className="block mt-1">
{new Date(record.auditTime).toLocaleString()}
</Text>
)}
{record.rejectReason && (
<Text className="block mt-1 text-red-500">
{record.rejectReason}
</Text>
)}
</View>
{/* 操作按钮 */}
{record.applyStatus === 10 && (
<View className="flex gap-2 mt-3">
<Button
type="success"
size="small"
className="flex-1"
onClick={() => handleApprove(record)}
>
</Button>
<Button
type="danger"
size="small"
className="flex-1"
onClick={() => handleReject(record)}
>
</Button>
</View>
)}
{record.applyStatus === 20 && (
<View className="mt-3">
<Button
type="primary"
size="small"
block
onClick={() => handleConfirmPay(record)}
>
</Button>
</View>
)}
</View>
))
) : (
<Empty description="暂无提现记录"/>
)}
</View>
</PullToRefresh>
)
}
return (
<View className="bg-gray-50 min-h-screen">
<Tabs value={activeTab} onChange={handleTabChange}>
<Tabs.TabPane title="待审核" value="10">
{renderWithdrawRecords()}
</Tabs.TabPane>
<Tabs.TabPane title="已通过" value="20">
{renderWithdrawRecords()}
</Tabs.TabPane>
<Tabs.TabPane title="已打款" value="40">
{renderWithdrawRecords()}
</Tabs.TabPane>
<Tabs.TabPane title="已驳回" value="30">
{renderWithdrawRecords()}
</Tabs.TabPane>
</Tabs>
<ActionSheet
visible={isVisible}
options={banks}
onSelect={handleSelect}
onCancel={() => setIsVisible(false)}
/>
{/* 驳回原因对话框 */}
<Dialog
visible={rejectDialogVisible}
title="驳回原因"
onCancel={() => {
setRejectDialogVisible(false)
setCurrentRecord(null)
setRejectReason('')
}}
onConfirm={confirmReject}
>
<View className="p-4">
<TextArea
placeholder="请输入驳回原因"
value={rejectReason}
onChange={(value) => setRejectReason(value)}
maxLength={200}
rows={4}
/>
</View>
</Dialog>
{/* 打款凭证对话框 */}
<Dialog
visible={payDialogVisible}
title="确认打款"
onCancel={() => {
setPayDialogVisible(false)
setCurrentRecord(null)
setPaymentImages([])
}}
onConfirm={confirmPayment}
>
<View className="p-4">
<View className="mb-3 flex flex-col">
<Text className="text-sm text-gray-600">
¥{(Number(currentRecord?.money) - 3).toFixed(2)}
</Text>
<Text className="text-sm">
{currentRecord?.bankName}
</Text>
<Text className="text-sm">
{currentRecord?.bankAccount}
</Text>
<Text className="text-sm">
{currentRecord?.bankCard}
</Text>
</View>
<View className="mb-3">
<Text className="text-sm text-gray-600 mb-2 block">
3
</Text>
<View className="flex flex-wrap gap-2">
{paymentImages.map((img, index) => (
<View key={index} className="relative w-20 h-20">
<Image src={img} className="w-full h-full object-cover rounded" />
<View
className="absolute top-0 right-0 bg-red-500 text-white rounded-full w-5 h-5 flex items-center justify-center text-xs"
onClick={() => handleRemovePaymentImage(index)}
>
×
</View>
</View>
))}
{paymentImages.length < 3 && (
<View
className="w-20 h-20 border-2 border-dashed border-gray-300 rounded flex items-center justify-center"
onClick={handleUploadPaymentImage}
>
<Text className="text-2xl text-gray-400">+</Text>
</View>
)}
</View>
</View>
</View>
</Dialog>
</View>
)
}
export default DealerWithdraw

View File

@@ -0,0 +1,80 @@
import React, { useState } from 'react'
import { View, Text } from '@tarojs/components'
import { Tabs, Button } from '@nutui/nutui-react-taro'
/**
* 提现功能调试组件
* 用于测试 Tabs 组件的点击和切换功能
*/
const WithdrawDebug: React.FC = () => {
const [activeTab, setActiveTab] = useState<string | number>('0')
const [clickCount, setClickCount] = useState(0)
// Tab 切换处理函数
const handleTabChange = (value: string | number) => {
console.log('Tab切换:', { from: activeTab, to: value, type: typeof value })
setActiveTab(value)
setClickCount(prev => prev + 1)
}
// 手动切换测试
const manualSwitch = (tab: string | number) => {
console.log('手动切换到:', tab)
setActiveTab(tab)
setClickCount(prev => prev + 1)
}
return (
<View className="bg-gray-50 min-h-screen p-4">
<View className="bg-white rounded-lg p-4 mb-4">
<Text className="text-lg font-bold mb-2"></Text>
<Text className="block mb-1">Tab: {String(activeTab)}</Text>
<Text className="block mb-1">: {clickCount}</Text>
<Text className="block mb-1">Tab类型: {typeof activeTab}</Text>
</View>
<View className="bg-white rounded-lg p-4 mb-4">
<Text className="text-lg font-bold mb-2"></Text>
<View className="flex gap-2">
<Button size="small" onClick={() => manualSwitch('0')}>
</Button>
<Button size="small" onClick={() => manualSwitch('1')}>
</Button>
</View>
</View>
<View className="bg-white rounded-lg">
<Tabs value={activeTab} onChange={handleTabChange}>
<Tabs.TabPane title="申请提现" value="0">
<View className="p-4">
<Text className="text-center text-gray-600"></Text>
<Text className="text-center text-sm text-gray-400 mt-2">
Tab值: {String(activeTab)}
</Text>
</View>
</Tabs.TabPane>
<Tabs.TabPane title="提现记录" value="1">
<View className="p-4">
<Text className="text-center text-gray-600"></Text>
<Text className="text-center text-sm text-gray-400 mt-2">
Tab值: {String(activeTab)}
</Text>
</View>
</Tabs.TabPane>
</Tabs>
</View>
<View className="bg-white rounded-lg p-4 mt-4">
<Text className="text-lg font-bold mb-2"></Text>
<Text className="text-sm text-gray-500">
</Text>
</View>
</View>
)
}
export default WithdrawDebug

View File

@@ -0,0 +1,3 @@
export default definePageConfig({
navigationBarTitleText: '提现申请'
})

View File

@@ -0,0 +1,480 @@
import React, {useState, useEffect, useCallback} from 'react'
import {View, Text} from '@tarojs/components'
import {
Cell,
Space,
Button,
Input,
CellGroup,
Tabs,
Tag,
Empty,
ActionSheet,
Loading,
PullToRefresh
} from '@nutui/nutui-react-taro'
import {Wallet, ArrowRight} from '@nutui/icons-react-taro'
import {businessGradients} from '@/styles/gradients'
import Taro from '@tarojs/taro'
import {useDealerUser} from '@/hooks/useDealerUser'
import {pageShopDealerWithdraw, addShopDealerWithdraw} from '@/api/shop/shopDealerWithdraw'
import type {ShopDealerWithdraw} from '@/api/shop/shopDealerWithdraw/model'
import {ShopDealerBank} from "@/api/shop/shopDealerBank/model";
import {listShopDealerBank} from "@/api/shop/shopDealerBank";
import {listCmsWebsiteField} from "@/api/cms/cmsWebsiteField";
import {myUserVerify} from "@/api/system/userVerify";
import navTo from "@/utils/common";
import {pushWithdrawalReviewReminder} from "@/api/sdy/sdyTemplateMessage";
interface WithdrawRecordWithDetails extends ShopDealerWithdraw {
accountDisplay?: string
}
const DealerWithdraw: React.FC = () => {
const [activeTab, setActiveTab] = useState<string | number>('0')
const [loading, setLoading] = useState<boolean>(false)
const [refreshing, setRefreshing] = useState<boolean>(false)
const [submitting, setSubmitting] = useState<boolean>(false)
const [banks, setBanks] = useState<any[]>([])
const [bank, setBank] = useState<ShopDealerBank>()
const [isVisible, setIsVisible] = useState<boolean>(false)
const [availableAmount, setAvailableAmount] = useState<string>('0.00')
const [withdrawRecords, setWithdrawRecords] = useState<WithdrawRecordWithDetails[]>([])
const [withdrawAmount, setWithdrawAmount] = useState<string>('')
const [withdrawValue, setWithdrawValue] = useState<string>('')
const {dealerUser} = useDealerUser()
// Tab 切换处理函数
const handleTabChange = (value: string | number) => {
console.log('Tab切换到:', value)
setActiveTab(value)
// 如果切换到提现记录页面,刷新数据
if (String(value) === '1') {
fetchWithdrawRecords().then()
}
}
// 获取可提现余额
const fetchBalance = useCallback(async () => {
console.log(dealerUser, 'dealerUser...')
try {
setAvailableAmount(String(dealerUser?.money || '0.00'))
} catch (error) {
console.error('获取余额失败:', error)
}
}, [dealerUser])
// 获取提现记录
const fetchWithdrawRecords = useCallback(async () => {
if (!dealerUser?.userId) return
try {
setLoading(true)
const result = await pageShopDealerWithdraw({
page: 1,
limit: 100,
userId: dealerUser.userId
})
if (result?.list) {
const processedRecords = result.list.map(record => ({
...record,
accountDisplay: getAccountDisplay(record)
}))
setWithdrawRecords(processedRecords)
}
} catch (error) {
console.error('获取提现记录失败:', error)
Taro.showToast({
title: '获取提现记录失败',
icon: 'none'
})
} finally {
setLoading(false)
}
}, [dealerUser?.userId])
function fetchBanks() {
listShopDealerBank({}).then(data => {
const list = data.map(d => {
d.name = d.bankName;
d.type = d.bankName;
return d;
})
setBanks(list.concat({
name: '管理银行卡',
type: 'add'
}))
setBank(data[0])
})
}
// 格式化账户显示
const getAccountDisplay = (record: ShopDealerWithdraw) => {
if (record.payType === 10) {
return '微信钱包'
} else if (record.payType === 20 && record.alipayAccount) {
return `支付宝(${record.alipayAccount.slice(-4)})`
} else if (record.payType === 30 && record.bankCard) {
return `${record.bankName || '银行卡'}(尾号${record.bankCard.slice(-4)})`
}
return '未知账户'
}
// 刷新数据
const handleRefresh = async () => {
setRefreshing(true)
await Promise.all([fetchBalance(), fetchWithdrawRecords()])
setRefreshing(false)
}
const handleSelect = (item: ShopDealerBank) => {
if(item.type === 'add'){
return Taro.navigateTo({
url: '/dealer/bank/index'
})
}
setBank(item)
setIsVisible(false)
}
function fetchCmsField() {
listCmsWebsiteField({ name: 'WithdrawValue'}).then(res => {
if(res && res.length > 0){
const text = res[0].value;
setWithdrawValue(text || '')
}
})
}
// 初始化加载数据
useEffect(() => {
if (dealerUser?.userId) {
fetchBalance().then()
fetchWithdrawRecords().then()
fetchBanks()
fetchCmsField()
}
}, [fetchBalance, fetchWithdrawRecords])
const getStatusText = (status?: number) => {
switch (status) {
case 40:
return '已到账'
case 20:
return '审核通过'
case 10:
return '待审核'
case 30:
return '已驳回'
default:
return '未知'
}
}
const getStatusColor = (status?: number) => {
switch (status) {
case 40:
return 'success'
case 20:
return 'success'
case 10:
return 'warning'
case 30:
return 'danger'
default:
return 'default'
}
}
const handleSubmit = async () => {
if (!dealerUser?.userId) {
Taro.showToast({
title: '用户信息获取失败',
icon: 'none'
})
return
}
if (!bank) {
Taro.showToast({
title: '请选择提现银行卡',
icon: 'none'
})
return
}
// 验证提现金额
const amount = parseFloat(withdrawAmount)
const availableStr = String(availableAmount || '0')
const available = parseFloat(availableStr.replace(/,/g, ''))
if (isNaN(amount) || amount <= 0) {
Taro.showToast({
title: '请输入有效的提现金额',
icon: 'none'
})
return
}
if (amount < 100) {
Taro.showToast({
title: '最低提现金额为100元',
icon: 'none'
})
return
}
if (amount > available) {
Taro.showToast({
title: '提现金额超过可用余额',
icon: 'none'
})
return
}
// 验证银行卡信息
if (!bank.bankCard || !bank.bankAccount || !bank.bankName) {
Taro.showToast({
title: '银行卡信息不完整',
icon: 'none'
})
return
}
// 验证实名认证
const isChecked = await myUserVerify({})
if(!isChecked){
console.log(isChecked,'isCheckedisCheckedisCheckedisChecked');
return navTo(`/user/userVerify/index`,true)
}
if(isChecked.status === 0){
Taro.showToast({
title: '实名认证还在审核中...',
icon: 'none'
})
return false;
}
try {
setSubmitting(true)
const withdrawData: ShopDealerWithdraw = {
userId: dealerUser.userId,
money: withdrawAmount,
payType: 30, // 银行卡提现
applyStatus: 10, // 待审核
platform: 'MiniProgram',
bankCard: bank.bankCard,
bankAccount: bank.bankAccount,
bankName: bank.bankName,
comments: `提现费3元/笔,预计到账金额¥${calculateExpectedAmount(withdrawAmount)}`,
}
await addShopDealerWithdraw(withdrawData)
Taro.showToast({
title: '提现申请已提交',
icon: 'success'
})
await pushWithdrawalReviewReminder(withdrawData)
// 重置表单
setWithdrawAmount('')
// 刷新数据
await handleRefresh()
// 切换到提现记录页面
setActiveTab('1')
} catch (error: any) {
console.error('提现申请失败:', error)
Taro.showToast({
title: error.message || '提现申请失败',
icon: 'none'
})
} finally {
setSubmitting(false)
}
}
// 格式化金额
const formatMoney = (money?: string) => {
if (!money) return '0.00'
return parseFloat(money).toFixed(2)
}
// 计算预计到账金额
const calculateExpectedAmount = (amount: string) => {
if (!amount || isNaN(parseFloat(amount))) return '0.00'
const withdrawAmount = parseFloat(amount)
// 提现费率 16% + 3元
const feeRate = 0
const fixedFee = 3
const totalFee = withdrawAmount * feeRate + fixedFee
const expectedAmount = withdrawAmount - totalFee
return Math.max(0, expectedAmount).toFixed(2)
}
const renderWithdrawForm = () => (
<View>
{/* 余额卡片 */}
<View className="rounded-xl p-6 mb-6 text-white relative overflow-hidden" style={{
background: businessGradients.dealer.header
}}>
{/* 装饰背景 - 小程序兼容版本 */}
<View className="absolute top-0 right-0 w-24 h-24 rounded-full" style={{
backgroundColor: 'rgba(255, 255, 255, 0.1)',
right: '-12px',
top: '-12px'
}}></View>
<View className="flex items-center justify-between relative z-10">
<View className={'flex flex-col'}>
<Text className="text-2xl font-bold text-white">{formatMoney(dealerUser?.money)}</Text>
<Text className="text-white text-opacity-80 text-sm mb-1"></Text>
</View>
<View className="p-3 rounded-full" style={{
background: 'rgba(255, 255, 255, 0.2)'
}}>
<Wallet color="white" size="32"/>
</View>
</View>
<View className="mt-4 pt-4 relative z-10" style={{
borderTop: '1px solid rgba(255, 255, 255, 0.3)'
}}>
<Text className="text-white text-opacity-80 text-xs">
¥100
</Text>
</View>
</View>
<CellGroup>
<Cell style={{
padding: '36px 12px'
}} title={
<View className="flex items-center justify-between">
<Text className={'text-xl'}></Text>
<Input
placeholder="提现金额"
type="number"
maxLength={7}
value={withdrawAmount}
onChange={(value) => setWithdrawAmount(value)}
style={{
padding: '0 10px',
fontSize: '20px'
}}
/>
<Button fill="none" size={'small'} onClick={() => setWithdrawAmount(dealerUser?.money || '0')}><Text className={'text-blue-500'}></Text></Button>
</View>
}
/>
<Cell title={'提现到'} onClick={() => setIsVisible(true)} extra={
<View className="flex items-center justify-between gap-1">
{bank ? <Text className={'text-gray-800'}>{bank.bankName}</Text> : <Text className={'text-gray-400'}></Text>}
<ArrowRight className={'text-gray-300'} size={15}/>
</View>
}/>
<Cell title={'预计到账金额'} extra={
<View className="flex items-center justify-between gap-1">
<Text className={'text-orange-500 px-2 text-lg'}>¥{calculateExpectedAmount(withdrawAmount)}</Text>
</View>
}/>
<Cell title={<Text className={'text-gray-400'}>{withdrawValue}</Text>}/>
</CellGroup>
<View className="mt-6 px-4">
<Button
block
type="primary"
nativeType="submit"
loading={submitting}
disabled={submitting || !withdrawAmount || !bank}
onClick={handleSubmit}
>
{submitting ? '提交中...' : '申请提现'}
</Button>
</View>
</View>
)
const renderWithdrawRecords = () => {
console.log('渲染提现记录:', {loading, recordsCount: withdrawRecords.length, dealerUserId: dealerUser?.userId})
return (
<PullToRefresh
disabled={refreshing}
onRefresh={handleRefresh}
>
<View>
{loading ? (
<View className="text-center py-8">
<Loading/>
<Text className="text-gray-500 mt-2">...</Text>
</View>
) : withdrawRecords.length > 0 ? (
withdrawRecords.map(record => (
<View key={record.id} className="rounded-lg bg-gray-50 p-4 mb-3 shadow-sm">
<View className="flex justify-between items-start mb-3">
<Space direction={'vertical'}>
<Text className="font-semibold text-gray-800 mb-1">
¥{Number(record.money).toFixed(2)}
</Text>
<Text className="text-sm text-gray-500">
{record.comments}
</Text>
</Space>
<Tag type={getStatusColor(record.applyStatus)}>
{getStatusText(record.applyStatus)}
</Tag>
</View>
<View className="text-xs text-gray-400">
<Text>{record.createTime}</Text>
{record.auditTime && (
<Text className="block mt-1">
{new Date(record.auditTime).toLocaleString()}
</Text>
)}
{record.rejectReason && (
<Text className="block mt-1 text-red-500">
{record.rejectReason}
</Text>
)}
</View>
</View>
))
) : (
<Empty description="暂无提现记录"/>
)}
</View>
</PullToRefresh>
)
}
return (
<View className="bg-gray-50 min-h-screen">
<Tabs value={activeTab} onChange={handleTabChange}>
<Tabs.TabPane title="申请提现" value="0">
{renderWithdrawForm()}
</Tabs.TabPane>
<Tabs.TabPane title="提现记录" value="1">
{renderWithdrawRecords()}
</Tabs.TabPane>
</Tabs>
<ActionSheet
visible={isVisible}
options={banks}
onSelect={handleSelect}
onCancel={() => setIsVisible(false)}
/>
</View>
)
}
export default DealerWithdraw