forked from gxwebsoft/mp-10550
feat(dealer): 添加分销商收益明细页面并优化订单管理功能
- 新增收益明细页面,支持下拉刷新和上拉加载更多 - 在app.config.ts中注册收益明细页面路由 - 更新API基础URL配置,统一使用mp-api域名 - 优化提交表单逻辑,确保refereeId参数为数字类型 - 修改订单页面,添加resourceId参数以正确过滤分销订单 - 修复订单号显示逻辑,优先使用接口返回的订单号 - 优化订单列表项点击事件,跳转到收益明细页面 - 更新客户名称显示格式,包含昵称和用户ID - 调整订单详情展示布局和信息内容
This commit is contained in:
@@ -3,19 +3,19 @@ export const ENV_CONFIG = {
|
||||
// 开发环境
|
||||
development: {
|
||||
// API_BASE_URL: 'http://127.0.0.1:9200/api',
|
||||
API_BASE_URL: 'https://cms-api.websoft.top/api',
|
||||
API_BASE_URL: 'https://mp-api.websoft.top/api',
|
||||
APP_NAME: '开发环境',
|
||||
DEBUG: 'true',
|
||||
},
|
||||
// 生产环境
|
||||
production: {
|
||||
API_BASE_URL: 'https://cms-api.websoft.top/api',
|
||||
API_BASE_URL: 'https://mp-api.websoft.top/api',
|
||||
APP_NAME: '桂乐淘',
|
||||
DEBUG: 'false',
|
||||
},
|
||||
// 测试环境
|
||||
test: {
|
||||
API_BASE_URL: 'https://cms-api.s209.websoft.top/api',
|
||||
API_BASE_URL: 'https://mp-api.s209.websoft.top/api',
|
||||
APP_NAME: '测试环境',
|
||||
DEBUG: 'true',
|
||||
}
|
||||
|
||||
@@ -31,5 +31,11 @@ export interface ShopDealerCapital {
|
||||
*/
|
||||
export interface ShopDealerCapitalParam extends PageParam {
|
||||
id?: number;
|
||||
// 仅查询当前分销商的收益/资金明细
|
||||
userId?: number;
|
||||
// 可选:按订单过滤
|
||||
orderId?: number;
|
||||
// 可选:资金流动类型过滤
|
||||
flowType?: number;
|
||||
keywords?: string;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@ export interface ShopDealerOrder {
|
||||
id?: number;
|
||||
// 买家用户ID
|
||||
userId?: number;
|
||||
nickname?: string;
|
||||
// 订单编号(部分接口会直接返回订单号字符串)
|
||||
orderNo?: string;
|
||||
// 订单ID
|
||||
orderId?: number;
|
||||
// 订单总金额(不含运费)
|
||||
@@ -47,5 +50,7 @@ export interface ShopDealerOrderParam extends PageParam {
|
||||
secondUserId?: number;
|
||||
thirdUserId?: number;
|
||||
userId?: number;
|
||||
// 数据权限/资源ID(通常传当前登录用户ID)
|
||||
resourceId?: number;
|
||||
keywords?: string;
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ export default {
|
||||
"apply/add",
|
||||
"withdraw/index",
|
||||
"orders/index",
|
||||
"capital/index",
|
||||
"team/index",
|
||||
"qrcode/index",
|
||||
"invite-stats/index",
|
||||
|
||||
@@ -127,7 +127,7 @@ const AddUserAddress = () => {
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
const submitSucceed = async (values: any) => {
|
||||
const submitSucceed = async (values: User) => {
|
||||
try {
|
||||
// 验证必填字段
|
||||
if (!values.phone && !FormData?.phone) {
|
||||
@@ -192,7 +192,7 @@ const AddUserAddress = () => {
|
||||
userId: user?.userId,
|
||||
realName: values.realName || FormData?.nickname,
|
||||
mobile: values.phone || FormData?.phone,
|
||||
refereeId: values.refereeId || FormData?.refereeId
|
||||
refereeId: Number(values.refereeId) || Number(FormData?.refereeId)
|
||||
})
|
||||
|
||||
if (roles.length > 0) {
|
||||
|
||||
4
src/dealer/capital/index.config.ts
Normal file
4
src/dealer/capital/index.config.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export default definePageConfig({
|
||||
navigationBarTitleText: '收益明细'
|
||||
})
|
||||
|
||||
2
src/dealer/capital/index.scss
Normal file
2
src/dealer/capital/index.scss
Normal file
@@ -0,0 +1,2 @@
|
||||
/* Intentionally empty: styling is done via utility classes. */
|
||||
|
||||
199
src/dealer/capital/index.tsx
Normal file
199
src/dealer/capital/index.tsx
Normal file
@@ -0,0 +1,199 @@
|
||||
import React, {useCallback, useEffect, useState} from 'react'
|
||||
import {View, Text, ScrollView} from '@tarojs/components'
|
||||
import {Empty, Tag, 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'
|
||||
|
||||
const PAGE_SIZE = 10
|
||||
|
||||
const DealerCapital: React.FC = () => {
|
||||
const {dealerUser} = useDealerUser()
|
||||
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [refreshing, setRefreshing] = useState(false)
|
||||
const [loadingMore, setLoadingMore] = useState(false)
|
||||
const [currentPage, setCurrentPage] = useState(1)
|
||||
const [hasMore, setHasMore] = useState(true)
|
||||
const [records, setRecords] = useState<ShopDealerCapital[]>([])
|
||||
|
||||
const getFlowTypeText = (flowType?: number) => {
|
||||
switch (flowType) {
|
||||
case 10:
|
||||
return '佣金收入'
|
||||
case 20:
|
||||
return '提现支出'
|
||||
case 30:
|
||||
return '转账支出'
|
||||
case 40:
|
||||
return '转账收入'
|
||||
default:
|
||||
return '资金变动'
|
||||
}
|
||||
}
|
||||
|
||||
const getFlowTypeTag = (flowType?: number) => {
|
||||
// 收入:success;支出:danger;其它:default
|
||||
if (flowType === 10 || flowType === 40) return 'success'
|
||||
if (flowType === 20 || flowType === 30) return 'danger'
|
||||
return 'default'
|
||||
}
|
||||
|
||||
const formatMoney = (flowType?: number, money?: string) => {
|
||||
const isIncome = flowType === 10 || flowType === 40
|
||||
const isExpense = flowType === 20 || flowType === 30
|
||||
const sign = isIncome ? '+' : isExpense ? '-' : ''
|
||||
return `${sign}${money || '0.00'}`
|
||||
}
|
||||
|
||||
const fetchRecords = 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: PAGE_SIZE,
|
||||
// 只显示与当前登录用户相关的收益明细
|
||||
userId: dealerUser.userId
|
||||
})
|
||||
|
||||
const list = result?.list || []
|
||||
if (page === 1) {
|
||||
setRecords(list)
|
||||
} else {
|
||||
setRecords(prev => [...prev, ...list])
|
||||
}
|
||||
|
||||
setHasMore(list.length === PAGE_SIZE)
|
||||
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 fetchRecords(1, true)
|
||||
}
|
||||
|
||||
const handleLoadMore = async () => {
|
||||
if (!loadingMore && hasMore) {
|
||||
await fetchRecords(currentPage + 1)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (dealerUser?.userId) {
|
||||
fetchRecords(1)
|
||||
}
|
||||
}, [fetchRecords, dealerUser?.userId])
|
||||
|
||||
if (!dealerUser) {
|
||||
return (
|
||||
<View className="bg-gray-50 min-h-screen flex items-center justify-center">
|
||||
<Loading/>
|
||||
<Text className="text-gray-500 mt-2">加载中...</Text>
|
||||
</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 && records.length === 0 ? (
|
||||
<View className="text-center py-8">
|
||||
<Loading/>
|
||||
<Text className="text-gray-500 mt-2">加载中...</Text>
|
||||
</View>
|
||||
) : records.length > 0 ? (
|
||||
<>
|
||||
{records.map((item) => (
|
||||
<View key={item.id} className="bg-white rounded-lg p-4 mb-3 shadow-sm">
|
||||
<View className="flex justify-between items-start mb-1">
|
||||
<Text className="font-semibold text-gray-800">
|
||||
{item.describe || '收益明细'}
|
||||
</Text>
|
||||
<Tag type={getFlowTypeTag(item.flowType)}>
|
||||
{getFlowTypeText(item.flowType)}
|
||||
</Tag>
|
||||
</View>
|
||||
|
||||
<View className="flex justify-between items-center mb-1">
|
||||
<Text className="text-sm text-gray-400">
|
||||
佣金收入
|
||||
</Text>
|
||||
<Text
|
||||
className={`text-sm font-semibold ${
|
||||
item.flowType === 10 || item.flowType === 40 ? 'text-green-600' :
|
||||
item.flowType === 20 || item.flowType === 30 ? 'text-red-500' :
|
||||
'text-gray-700'
|
||||
}`}
|
||||
>
|
||||
{formatMoney(item.flowType, item.money)}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View className="flex justify-between items-center">
|
||||
<Text className="text-sm text-gray-400">
|
||||
{/*用户:{item.userId ?? '-'}*/}
|
||||
</Text>
|
||||
<Text className="text-sm text-gray-400">
|
||||
{item.createTime || '-'}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
))}
|
||||
|
||||
{loadingMore && (
|
||||
<View className="text-center py-4">
|
||||
<Loading/>
|
||||
<Text className="text-gray-500 mt-1 text-sm">加载更多...</Text>
|
||||
</View>
|
||||
)}
|
||||
{!hasMore && records.length > 0 && (
|
||||
<View className="text-center py-4">
|
||||
<Text className="text-gray-400 text-sm">没有更多数据了</Text>
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<Empty description="暂无收益明细"/>
|
||||
)}
|
||||
</View>
|
||||
</ScrollView>
|
||||
</PullToRefresh>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
export default DealerCapital
|
||||
@@ -24,7 +24,8 @@ const DealerOrders: React.FC = () => {
|
||||
|
||||
// 获取订单数据
|
||||
const fetchOrders = useCallback(async (page: number = 1, isRefresh: boolean = false) => {
|
||||
if (!dealerUser?.userId) return
|
||||
// 需要当前登录用户ID(用于 resourceId 参数)
|
||||
if (!dealerUser || !dealerUser.userId) return
|
||||
|
||||
try {
|
||||
if (isRefresh) {
|
||||
@@ -37,14 +38,17 @@ const DealerOrders: React.FC = () => {
|
||||
|
||||
const result = await pageShopDealerOrder({
|
||||
page,
|
||||
limit: 10
|
||||
limit: 10,
|
||||
// 后端需要 resourceId=当前登录用户ID 才能正确过滤分销订单
|
||||
resourceId: dealerUser.userId
|
||||
})
|
||||
|
||||
if (result?.list) {
|
||||
const newOrders = result.list.map(order => ({
|
||||
...order,
|
||||
orderNo: `${order.orderId}`,
|
||||
customerName: `用户${order.userId}`,
|
||||
// 优先使用接口返回的订单号;没有则降级展示 orderId
|
||||
orderNo: order.orderNo ?? (order.orderId != null ? String(order.orderId) : undefined),
|
||||
customerName: `${order.nickname}${order.userId}`,
|
||||
userCommission: order.firstMoney || '0.00'
|
||||
}))
|
||||
|
||||
@@ -102,32 +106,37 @@ const DealerOrders: React.FC = () => {
|
||||
return 'warning'
|
||||
}
|
||||
|
||||
const handleGoCapital = () => {
|
||||
Taro.navigateTo({url: '/dealer/capital/index'})
|
||||
}
|
||||
|
||||
const renderOrderItem = (order: OrderWithDetails) => (
|
||||
<View key={order.id} className="bg-white rounded-lg p-4 mb-3 shadow-sm">
|
||||
<View
|
||||
key={order.id}
|
||||
className="bg-white rounded-lg p-4 mb-3 shadow-sm"
|
||||
onClick={handleGoCapital}
|
||||
>
|
||||
<View className="flex justify-between items-start mb-1">
|
||||
<Text className="font-semibold text-gray-800">
|
||||
订单号:{order.orderNo}
|
||||
订单号:{order.orderNo || '-'}
|
||||
</Text>
|
||||
<Tag type={getStatusColor(order.isSettled, order.isInvalid)}>
|
||||
{getStatusText(order.isSettled, order.isInvalid)}
|
||||
</Tag>
|
||||
</View>
|
||||
|
||||
<View className="flex justify-between items-center mb-1">
|
||||
<Text className="text-sm text-gray-400">
|
||||
订单金额:¥{order.orderPrice || '0.00'}
|
||||
</Text>
|
||||
<Text className="text-sm text-orange-500 font-semibold">
|
||||
我的佣金:¥{order.userCommission}
|
||||
</Text>
|
||||
</View>
|
||||
{/*<View className="flex justify-between items-center mb-1">*/}
|
||||
{/* <Text className="text-sm text-gray-400">*/}
|
||||
{/* 订单金额:¥{order.orderPrice || '0.00'}*/}
|
||||
{/* </Text>*/}
|
||||
{/*</View>*/}
|
||||
|
||||
<View className="flex justify-between items-center">
|
||||
<Text className="text-sm text-gray-400">
|
||||
客户:{order.customerName}
|
||||
{order.createTime}
|
||||
</Text>
|
||||
<Text className="text-sm text-gray-400">
|
||||
{order.createTime}
|
||||
订单金额:¥{order.orderPrice || '0.00'}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
Reference in New Issue
Block a user