feat(dealer): 新增提现审核与收益明细功能
- 新增提现审核页面,支持审核通过、驳回及打款确认操作 - 新增收款人实名认证校验逻辑- 新增收益明细页面,展示各类资金流动记录 - 新增新注册奖励资金流水类型 - 完善资金流水详情页面字段展示逻辑 - 新增银行账户管理入口-优化部分页面导航配置与权限控制
This commit is contained in:
16
src/api/sdy/sdyTemplateMessage/index.ts
Normal file
16
src/api/sdy/sdyTemplateMessage/index.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import request from '@/utils/request';
|
||||
import type { ApiResult } from '@/api';
|
||||
|
||||
/**
|
||||
* 升级为管理员
|
||||
* 推送模版消息
|
||||
*/
|
||||
export async function pushByUpdateAdmin(userId: number) {
|
||||
const res = await request.get<ApiResult<unknown>>(
|
||||
'/sdy/sdy-template-message/' + userId
|
||||
);
|
||||
if (res.code === 0) {
|
||||
return res.message;
|
||||
}
|
||||
return Promise.reject(new Error(res.message));
|
||||
}
|
||||
123
src/api/sdy/sdyTemplateMessage/model/index.ts
Normal file
123
src/api/sdy/sdyTemplateMessage/model/index.ts
Normal file
@@ -0,0 +1,123 @@
|
||||
import type { PageParam } from '@/api/index';
|
||||
|
||||
/**
|
||||
* 商品文章
|
||||
*/
|
||||
export interface ShopArticle {
|
||||
// 文章ID
|
||||
articleId?: number;
|
||||
// 文章标题
|
||||
title?: string;
|
||||
// 文章类型 0常规 1视频
|
||||
type?: number;
|
||||
// 模型
|
||||
model?: string;
|
||||
// 详情页模板
|
||||
detail?: string;
|
||||
// 文章分类ID
|
||||
categoryId?: number;
|
||||
// 上级id, 0是顶级
|
||||
parentId?: number;
|
||||
// 话题
|
||||
topic?: string;
|
||||
// 标签
|
||||
tags?: string;
|
||||
// 封面图
|
||||
image?: string;
|
||||
// 封面图宽
|
||||
imageWidth?: number;
|
||||
// 封面图高
|
||||
imageHeight?: number;
|
||||
// 付费金额
|
||||
price?: string;
|
||||
// 开始时间
|
||||
startTime?: string;
|
||||
// 结束时间
|
||||
endTime?: string;
|
||||
// 来源
|
||||
source?: string;
|
||||
// 产品概述
|
||||
overview?: string;
|
||||
// 虚拟阅读量(仅用作展示)
|
||||
virtualViews?: number;
|
||||
// 实际阅读量
|
||||
actualViews?: number;
|
||||
// 评分
|
||||
rate?: string;
|
||||
// 列表显示方式(10小图展示 20大图展示)
|
||||
showType?: number;
|
||||
// 访问密码
|
||||
password?: string;
|
||||
// 可见类型 0所有人 1登录可见 2密码可见
|
||||
permission?: number;
|
||||
// 发布来源客户端 (APP、H5、小程序等)
|
||||
platform?: string;
|
||||
// 文章附件
|
||||
files?: string;
|
||||
// 视频地址
|
||||
video?: string;
|
||||
// 接受的文件类型
|
||||
accept?: string;
|
||||
// 经度
|
||||
longitude?: string;
|
||||
// 纬度
|
||||
latitude?: string;
|
||||
// 所在省份
|
||||
province?: string;
|
||||
// 所在城市
|
||||
city?: string;
|
||||
// 所在辖区
|
||||
region?: string;
|
||||
// 街道地址
|
||||
address?: string;
|
||||
// 点赞数
|
||||
likes?: number;
|
||||
// 评论数
|
||||
commentNumbers?: number;
|
||||
// 提醒谁看
|
||||
toUsers?: string;
|
||||
// 作者
|
||||
author?: string;
|
||||
// 推荐
|
||||
recommend?: number;
|
||||
// 报名人数
|
||||
bmUsers?: number;
|
||||
// 用户ID
|
||||
userId?: number;
|
||||
// 项目ID
|
||||
projectId?: number;
|
||||
// 语言
|
||||
lang?: string;
|
||||
// 关联默认语言的文章ID
|
||||
langArticleId?: number;
|
||||
// 是否自动翻译
|
||||
translation?: string;
|
||||
// 编辑器类型 0 Markdown编辑器 1 富文本编辑器
|
||||
editor?: string;
|
||||
// pdf文件地址
|
||||
pdfUrl?: string;
|
||||
// 版本号
|
||||
version?: number;
|
||||
// 排序(数字越小越靠前)
|
||||
sortNumber?: number;
|
||||
// 备注
|
||||
comments?: string;
|
||||
// 状态, 0已发布, 1待审核 2已驳回 3违规内容
|
||||
status?: number;
|
||||
// 是否删除, 0否, 1是
|
||||
deleted?: number;
|
||||
// 租户id
|
||||
tenantId?: number;
|
||||
// 创建时间
|
||||
createTime?: string;
|
||||
// 修改时间
|
||||
updateTime?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品文章搜索条件
|
||||
*/
|
||||
export interface ShopArticleParam extends PageParam {
|
||||
articleId?: number;
|
||||
keywords?: string;
|
||||
}
|
||||
@@ -38,6 +38,8 @@ export interface ShopDealerWithdraw {
|
||||
createTime?: string;
|
||||
// 修改时间
|
||||
updateTime?: string;
|
||||
// 附件
|
||||
image?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,4 +49,5 @@ export interface ShopDealerWithdrawParam extends PageParam {
|
||||
id?: number;
|
||||
userId?: number;
|
||||
keywords?: string;
|
||||
applyStatus?: number; // 申请状态筛选
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ export interface UserVerify {
|
||||
*/
|
||||
export interface UserVerifyParam extends PageParam {
|
||||
id?: number;
|
||||
userId?: number;
|
||||
status?: number;
|
||||
keywords?: string;
|
||||
}
|
||||
|
||||
@@ -57,9 +57,11 @@ export default defineAppConfig({
|
||||
"index",
|
||||
"apply/add",
|
||||
"withdraw/index",
|
||||
"withdraw/admin",
|
||||
"orders/index",
|
||||
"capital/index",
|
||||
"capital/detail",
|
||||
"capital/record",
|
||||
"team/index",
|
||||
"qrcode/index",
|
||||
"invite-stats/index",
|
||||
|
||||
@@ -11,6 +11,7 @@ import {User} from "@/api/system/user/model";
|
||||
import {getStoredInviteParams, handleInviteRelation} from "@/utils/invite";
|
||||
import {addShopDealerUser} from "@/api/shop/shopDealerUser";
|
||||
import {listUserRole, updateUserRole} from "@/api/system/userRole";
|
||||
import {addShopDealerCapital} from "@/api/shop/shopDealerCapital";
|
||||
|
||||
// 类型定义
|
||||
interface ChooseAvatarEvent {
|
||||
@@ -202,6 +203,14 @@ const AddUserAddress = () => {
|
||||
})
|
||||
}
|
||||
|
||||
// 获得50元奖励
|
||||
await addShopDealerCapital({
|
||||
userId: user?.userId,
|
||||
flowType: 50,
|
||||
money: '50',
|
||||
toUserId: user?.refereeId,
|
||||
comments: '新人注册奖励'
|
||||
})
|
||||
|
||||
Taro.showToast({
|
||||
title: `注册成功`,
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
} from "@/api/shop/shopDealerBank";
|
||||
import FixedButton from "@/components/FixedButton";
|
||||
import {ShopDealerBank} from "@/api/shop/shopDealerBank/model";
|
||||
import {myUserVerify} from "@/api/system/userVerify";
|
||||
|
||||
const AddUserAddress = () => {
|
||||
const {params} = useRouter();
|
||||
@@ -21,6 +22,7 @@ const AddUserAddress = () => {
|
||||
const isEditMode = !!params.id
|
||||
const bankId = params.id ? Number(params.id) : undefined
|
||||
|
||||
|
||||
const reload = async () => {
|
||||
// 如果是编辑模式,加载地址数据
|
||||
if (isEditMode && bankId) {
|
||||
@@ -39,7 +41,19 @@ const AddUserAddress = () => {
|
||||
|
||||
// 提交表单
|
||||
const submitSucceed = async (values: any) => {
|
||||
console.log('.>>>>>>,....')
|
||||
console.log('.>>>>>>,....',values)
|
||||
|
||||
|
||||
const verify = await myUserVerify({userId: Taro.getStorageSync('UserId')})
|
||||
if(verify?.realName !== values.bankAccount){
|
||||
Taro.showToast({
|
||||
title: '收款人姓名与实名认证信息不一致!',
|
||||
icon: 'none'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
// 准备提交的数据
|
||||
const submitData = {
|
||||
|
||||
@@ -21,6 +21,7 @@ const DealerCapitalDetail = () => {
|
||||
if (index === 20) return '提现支出'
|
||||
if (index === 30) return '转账支出'
|
||||
if (index === 40) return '转账收入'
|
||||
if (index === 50) return '新注册奖励'
|
||||
return 'warning'
|
||||
}
|
||||
|
||||
@@ -55,9 +56,11 @@ const DealerCapitalDetail = () => {
|
||||
<Text className="text-sm my-1 text-gray-500">
|
||||
收益描述:{item.comments}
|
||||
</Text>
|
||||
{item.orderNo && (
|
||||
<Text className="text-sm my-1 text-gray-500">
|
||||
订单编号:{item.orderNo}
|
||||
</Text>
|
||||
)}
|
||||
<Text className="text-sm my-1 text-gray-500">
|
||||
创建时间:{item.createTime}
|
||||
</Text>
|
||||
|
||||
3
src/dealer/capital/record.config.ts
Normal file
3
src/dealer/capital/record.config.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export default definePageConfig({
|
||||
navigationBarTitleText: '收益明细'
|
||||
})
|
||||
180
src/dealer/capital/record.tsx
Normal file
180
src/dealer/capital/record.tsx
Normal file
@@ -0,0 +1,180 @@
|
||||
import React, {useState, useEffect, useCallback} from 'react'
|
||||
import {View, Text, ScrollView} from '@tarojs/components'
|
||||
import {Empty, PullToRefresh, Loading} from '@nutui/nutui-react-taro'
|
||||
import Taro from '@tarojs/taro'
|
||||
import {pageShopDealerCapital} from '@/api/shop/shopDealerCapital'
|
||||
import {useDealerUser} from '@/hooks/useDealerUser'
|
||||
import type {ShopDealerCapital} from '@/api/shop/shopDealerCapital/model'
|
||||
import navTo from "@/utils/common";
|
||||
import {pushByUpdateAdmin} from "@/api/sdy/sdyTemplateMessage";
|
||||
|
||||
const DealerCapital: React.FC = () => {
|
||||
const [loading, setLoading] = useState<boolean>(false)
|
||||
const [refreshing, setRefreshing] = useState<boolean>(false)
|
||||
const [loadingMore, setLoadingMore] = useState<boolean>(false)
|
||||
const [capital, setCapital] = useState<ShopDealerCapital[]>([])
|
||||
const [currentPage, setCurrentPage] = useState<number>(1)
|
||||
const [hasMore, setHasMore] = useState<boolean>(true)
|
||||
|
||||
const {dealerUser} = useDealerUser()
|
||||
|
||||
// 获取订单数据
|
||||
const fetchCapital = useCallback(async (page: number = 1, isRefresh: boolean = false) => {
|
||||
// if (!dealerUser?.userId) return
|
||||
|
||||
try {
|
||||
if (isRefresh) {
|
||||
setRefreshing(true)
|
||||
} else if (page === 1) {
|
||||
setLoading(true)
|
||||
} else {
|
||||
setLoadingMore(true)
|
||||
}
|
||||
|
||||
const result = await pageShopDealerCapital({
|
||||
page,
|
||||
limit: 10,
|
||||
userId: Taro.getStorageSync('UserId')
|
||||
})
|
||||
|
||||
if (result?.list) {
|
||||
const newCapital = result.list.map(item => ({
|
||||
...item,
|
||||
orderNo: item.orderNo
|
||||
}))
|
||||
|
||||
if (page === 1) {
|
||||
setCapital(newCapital)
|
||||
} else {
|
||||
setCapital(prev => [...prev, ...newCapital])
|
||||
}
|
||||
|
||||
setHasMore(newCapital.length === 10)
|
||||
setCurrentPage(page)
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取分销订单失败:', error)
|
||||
Taro.showToast({
|
||||
title: '获取订单失败',
|
||||
icon: 'error'
|
||||
})
|
||||
} finally {
|
||||
setLoading(false)
|
||||
setRefreshing(false)
|
||||
setLoadingMore(false)
|
||||
}
|
||||
}, [dealerUser?.userId])
|
||||
|
||||
// 下拉刷新
|
||||
const handleRefresh = async () => {
|
||||
await fetchCapital(1, true)
|
||||
}
|
||||
|
||||
// 加载更多
|
||||
const handleLoadMore = async () => {
|
||||
if (!loadingMore && hasMore) {
|
||||
await fetchCapital(currentPage + 1)
|
||||
}
|
||||
}
|
||||
|
||||
const getFlowType = (index?: number) => {
|
||||
if (index === 10) return '电费收益'
|
||||
if (index === 20) return '提现支出'
|
||||
if (index === 30) return '转账支出'
|
||||
if (index === 40) return '转账收入'
|
||||
if (index === 50) return '新注册奖励'
|
||||
return 'warning'
|
||||
}
|
||||
|
||||
// 初始化加载数据
|
||||
useEffect(() => {
|
||||
if (dealerUser?.userId) {
|
||||
fetchCapital(1)
|
||||
}
|
||||
pushByUpdateAdmin(34423).then()
|
||||
}, [fetchCapital])
|
||||
|
||||
const renderCapitalItem = (item: ShopDealerCapital) => (
|
||||
<View key={item.id} className="bg-white rounded-lg p-4 mb-3 shadow-sm"
|
||||
onClick={() => navTo(`/dealer/capital/detail?id=${item.id}`)}>
|
||||
<View className="flex justify-between items-start mb-1">
|
||||
<Text className="font-semibold text-gray-800">
|
||||
{getFlowType(item.flowType)}
|
||||
</Text>
|
||||
<Text className="text-lg text-orange-500 font-semibold">
|
||||
¥{Number(item.money).toFixed(2)}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{item.orderNo && (
|
||||
<View className="flex justify-between items-center mb-1">
|
||||
<Text className="text-sm text-gray-400">
|
||||
{item.orderNo}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
<View className="flex justify-between items-center mb-1">
|
||||
<Text className="text-sm text-gray-400">
|
||||
{item.createTime}
|
||||
</Text>
|
||||
<Text className="text-sm text-gray-400">
|
||||
我的收益:{item.money}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
</View>
|
||||
)
|
||||
|
||||
return (
|
||||
<View className="min-h-screen bg-gray-50">
|
||||
<PullToRefresh
|
||||
onRefresh={handleRefresh}
|
||||
disabled={refreshing}
|
||||
pullingText="下拉刷新"
|
||||
canReleaseText="释放刷新"
|
||||
refreshingText="刷新中..."
|
||||
completeText="刷新完成"
|
||||
>
|
||||
<ScrollView
|
||||
scrollY
|
||||
className={'h-screen'}
|
||||
onScrollToLower={handleLoadMore}
|
||||
lowerThreshold={50}
|
||||
>
|
||||
{/*账单列表*/}
|
||||
<View className="p-4">
|
||||
{loading && capital.length === 0 ? (
|
||||
<View className="text-center py-8">
|
||||
<Loading/>
|
||||
<Text className="text-gray-500 mt-2">加载中...</Text>
|
||||
</View>
|
||||
) : capital.length > 0 ? (
|
||||
<>
|
||||
{capital.map(renderCapitalItem)}
|
||||
{loadingMore && (
|
||||
<View className="text-center py-4">
|
||||
<Loading/>
|
||||
<Text className="text-gray-500 mt-1 text-sm">加载更多...</Text>
|
||||
</View>
|
||||
)}
|
||||
{!hasMore && capital.length > 0 && (
|
||||
<View className="text-center py-4">
|
||||
<Text className="text-gray-400 text-sm">没有更多数据了</Text>
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<Empty description="暂无收益" style={{
|
||||
backgroundColor: 'transparent'
|
||||
}}/>
|
||||
)}
|
||||
</View>
|
||||
</ScrollView>
|
||||
</PullToRefresh>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
export default DealerCapital
|
||||
@@ -228,6 +228,14 @@ const DealerIndex: React.FC = () => {
|
||||
</View>
|
||||
</Grid.Item>
|
||||
|
||||
<Grid.Item text="收益明细" onClick={() => navigateToPage('/dealer/capital/record')}>
|
||||
<View className="text-center">
|
||||
<View className="w-12 h-12 bg-blue-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
||||
<Purse color="#3b82f6" size="20"/>
|
||||
</View>
|
||||
</View>
|
||||
</Grid.Item>
|
||||
|
||||
<Grid.Item text={'提现申请'} onClick={() => navigateToPage('/dealer/withdraw/index')}>
|
||||
<View className="text-center">
|
||||
<View className="w-12 h-12 bg-green-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
||||
@@ -236,7 +244,7 @@ const DealerIndex: React.FC = () => {
|
||||
</View>
|
||||
</Grid.Item>
|
||||
|
||||
<Grid.Item text={'会员中心'} onClick={() => navigateToPage('/pages/user/user')}>
|
||||
<Grid.Item text={'实名认证'} onClick={() => navigateToPage('/user/userVerify/index')}>
|
||||
<View className="text-center">
|
||||
<View className="w-12 h-12 bg-purple-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
||||
<People color="#8b5cf6" size="20"/>
|
||||
@@ -251,6 +259,18 @@ const DealerIndex: React.FC = () => {
|
||||
</View>
|
||||
</View>
|
||||
</Grid.Item>
|
||||
{
|
||||
(dealerUser?.userId == 33658 || dealerUser?.userId == 33677) && (
|
||||
<Grid.Item text={'提现审核'} onClick={() => navigateToPage('/dealer/withdraw/admin')}>
|
||||
<View className="text-center">
|
||||
<View className="w-12 h-12 bg-red-50 rounded-xl flex items-center justify-center mx-auto mb-2">
|
||||
<Purse color="#10b981" size="20"/>
|
||||
</View>
|
||||
</View>
|
||||
</Grid.Item>
|
||||
)
|
||||
}
|
||||
|
||||
</Grid>
|
||||
|
||||
{/* 第二行功能 */}
|
||||
|
||||
3
src/dealer/withdraw/admin.config.ts
Normal file
3
src/dealer/withdraw/admin.config.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export default definePageConfig({
|
||||
navigationBarTitleText: '提现审核'
|
||||
})
|
||||
470
src/dealer/withdraw/admin.tsx
Normal file
470
src/dealer/withdraw/admin.tsx
Normal file
@@ -0,0 +1,470 @@
|
||||
import React, {useState, useEffect, useCallback} from 'react'
|
||||
import {View, Text} from '@tarojs/components'
|
||||
import {
|
||||
Space,
|
||||
Tabs,
|
||||
Tag,
|
||||
Empty,
|
||||
ActionSheet,
|
||||
Loading,
|
||||
PullToRefresh,
|
||||
Button,
|
||||
Dialog,
|
||||
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";
|
||||
|
||||
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 {
|
||||
const res = await Taro.chooseImage({
|
||||
count: 3 - paymentImages.length, // 最多3张
|
||||
sizeType: ['compressed'],
|
||||
sourceType: ['album', 'camera']
|
||||
})
|
||||
|
||||
// 这里应该上传到服务器,获取图片URL
|
||||
// 暂时使用本地路径演示
|
||||
const newImages = [...paymentImages, ...res.tempFilePaths]
|
||||
setPaymentImages(newImages.slice(0, 3))
|
||||
} catch (error) {
|
||||
console.error('选择图片失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 删除打款凭证
|
||||
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'
|
||||
})
|
||||
|
||||
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>
|
||||
</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">
|
||||
<Text className="text-sm text-gray-600">
|
||||
打款金额:¥{Number(currentRecord?.money || 0).toFixed(2)}
|
||||
</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">
|
||||
<img 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
|
||||
@@ -57,7 +57,7 @@ let baseUrl = Taro.getStorageSync('ApiUrl') || BaseUrl;
|
||||
|
||||
// 开发环境配置
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
baseUrl = 'http://localhost:9200/api'
|
||||
// baseUrl = 'http://localhost:9200/api'
|
||||
}
|
||||
|
||||
// 请求拦截器
|
||||
|
||||
Reference in New Issue
Block a user