diff --git a/src/api/shop/shopDealerApply/model/index.ts b/src/api/shop/shopDealerApply/model/index.ts index f5c4e3a..1d7c0d4 100644 --- a/src/api/shop/shopDealerApply/model/index.ts +++ b/src/api/shop/shopDealerApply/model/index.ts @@ -48,6 +48,7 @@ export interface ShopDealerApply { export interface ShopDealerApplyParam extends PageParam { applyId?: number; type?: number; + dealerName?: string; mobile?: string; userId?: number; keywords?: string; diff --git a/src/dealer/apply/add.tsx b/src/dealer/apply/add.tsx index 13473ae..f862bf3 100644 --- a/src/dealer/apply/add.tsx +++ b/src/dealer/apply/add.tsx @@ -37,6 +37,14 @@ const AddUserAddress = () => { setFormData({ ...user, refereeId: Number(inviteParams.inviter), + // 清空昵称,强制用户手动输入 + nickname: '', + }) + } else { + // 如果没有邀请参数,也要确保昵称为空 + setFormData({ + ...user, + nickname: '', }) } } @@ -130,7 +138,9 @@ const AddUserAddress = () => { return; } - if (!values.realName && !FormData?.nickname) { + // 验证昵称:必须填写且不能是默认的微信昵称 + const nickname = values.realName || FormData?.nickname || ''; + if (!nickname || nickname.trim() === '') { Taro.showToast({ title: '请填写昵称', icon: 'error' @@ -138,6 +148,25 @@ const AddUserAddress = () => { return; } + // 检查是否为默认的微信昵称(常见的默认昵称) + const defaultNicknames = ['微信用户', 'WeChat User', '微信昵称']; + if (defaultNicknames.includes(nickname.trim())) { + Taro.showToast({ + title: '请填写真实昵称,不能使用默认昵称', + icon: 'error' + }); + return; + } + + // 验证昵称长度 + if (nickname.trim().length < 2) { + Taro.showToast({ + title: '昵称至少需要2个字符', + icon: 'error' + }); + return; + } + if (!values.avatar && !FormData?.avatar) { Taro.showToast({ title: '请上传头像', @@ -145,6 +174,7 @@ const AddUserAddress = () => { }); return; } + console.log(values,FormData) const roles = await listUserRole({userId: user?.userId}) console.log(roles, 'roles...') @@ -247,8 +277,11 @@ const AddUserAddress = () => { console.log('手机号已获取', userData.phone) const updatedFormData = { ...FormData, - ...userData, - phone: userData.phone + phone: userData.phone, + // 不自动填充微信昵称,保持用户已输入的昵称 + nickname: FormData?.nickname || '', + // 只在没有头像时才使用微信头像 + avatar: FormData?.avatar || userData.avatar } setFormData(updatedFormData) @@ -256,8 +289,9 @@ const AddUserAddress = () => { if (formRef.current) { formRef.current.setFieldsValue({ phone: userData.phone, - realName: userData.nickname || FormData?.nickname, - avatar: userData.avatar || FormData?.avatar + // 不覆盖用户已输入的昵称 + realName: FormData?.nickname || '', + avatar: FormData?.avatar || userData.avatar }) } @@ -373,11 +407,11 @@ const AddUserAddress = () => { } - + getWxNickname(e.detail.value)} /> diff --git a/src/dealer/customer/add.tsx b/src/dealer/customer/add.tsx index e922291..f9b9ba7 100644 --- a/src/dealer/customer/add.tsx +++ b/src/dealer/customer/add.tsx @@ -1,20 +1,19 @@ import {useEffect, useState, useRef} from "react"; import {Loading, CellGroup, Cell, Input, Form, Calendar} from '@nutui/nutui-react-taro' -import {Edit, Calendar as CalendarIcon} from '@nutui/icons-react-taro' +import {Edit} from '@nutui/icons-react-taro' import Taro from '@tarojs/taro' import {useRouter} from '@tarojs/taro' -import {View,Text} from '@tarojs/components' +import {View} from '@tarojs/components' import FixedButton from "@/components/FixedButton"; import {useUser} from "@/hooks/useUser"; import {ShopDealerApply} from "@/api/shop/shopDealerApply/model"; import { - addShopDealerApply, getShopDealerApply, + addShopDealerApply, getShopDealerApply, pageShopDealerApply, updateShopDealerApply } from "@/api/shop/shopDealerApply"; import { formatDateForDatabase, - extractDateForCalendar, - formatDateForDisplay + extractDateForCalendar } from "@/utils/dateUtils"; const AddShopDealerApply = () => { @@ -47,7 +46,6 @@ const AddShopDealerApply = () => { } - // 处理签约时间选择 const handleApplyTimeConfirm = (param: string) => { const selectedDate = param[3] // 选中的日期字符串 (YYYY-M-D) @@ -79,13 +77,13 @@ const AddShopDealerApply = () => { } const reload = async () => { - if(!params.id){ + if (!params.id) { return false; } // 查询当前用户ID是否已有申请记录 try { const dealerApply = await getShopDealerApply(Number(params.id)); - if(dealerApply){ + if (dealerApply) { setFormData(dealerApply) setIsEditMode(true); setExistingApply(dealerApply) @@ -109,49 +107,60 @@ const AddShopDealerApply = () => { } // 提交表单 - const submitSucceed = async (values: any) => { - try { - // 准备提交的数据 - const submitData = { - ...values, - realName: values.realName || user?.nickname, - mobile: user?.phone, - refereeId: 33534, - applyStatus: 10, - auditTime: undefined, - // 确保日期数据正确提交(使用数据库格式) - applyTime: values.applyTime || (applyTime ? formatDateForDatabase(applyTime) : ''), - contractTime: values.contractTime || (contractTime ? formatDateForDatabase(contractTime) : '') - }; + const submitSucceed = (values: any) => { - // 如果是编辑模式,添加现有申请的id - if (isEditMode && existingApply?.applyId) { - submitData.applyId = existingApply.applyId; + pageShopDealerApply({dealerName: values.dealerName, type: 4}).then((res) => { + if (res && res?.count > 0) { + Taro.showToast({ + title: '该客户已存在', + icon: 'error' + }); + return false; } + try { + // 准备提交的数据 + const submitData = { + ...values, + type: 4, + realName: values.realName || user?.nickname, + mobile: user?.phone, + refereeId: 33534, + applyStatus: 10, + auditTime: undefined, + // 确保日期数据正确提交(使用数据库格式) + applyTime: values.applyTime || (applyTime ? formatDateForDatabase(applyTime) : ''), + contractTime: values.contractTime || (contractTime ? formatDateForDatabase(contractTime) : '') + }; - // 执行新增或更新操作 - if (isEditMode) { - await updateShopDealerApply(submitData); - } else { - await addShopDealerApply(submitData); + // 如果是编辑模式,添加现有申请的id + if (isEditMode && existingApply?.applyId) { + submitData.applyId = existingApply.applyId; + } + + // 执行新增或更新操作 + if (isEditMode) { + updateShopDealerApply(submitData); + } else { + addShopDealerApply(submitData); + } + + Taro.showToast({ + title: `${isEditMode ? '提交' : '提交'}成功`, + icon: 'success' + }); + + setTimeout(() => { + Taro.navigateBack(); + }, 1000); + + } catch (error) { + console.error('验证邀请人失败:', error); + return Taro.showToast({ + title: '邀请人ID不存在', + icon: 'error' + }); } - - Taro.showToast({ - title: `${isEditMode ? '提交' : '提交'}成功`, - icon: 'success' - }); - - setTimeout(() => { - Taro.navigateBack(); - }, 1000); - - } catch (error) { - console.error('验证邀请人失败:', error); - return Taro.showToast({ - title: '邀请人ID不存在', - icon: 'error' - }); - } + }) } // 处理固定按钮点击事件 @@ -201,43 +210,43 @@ const AddShopDealerApply = () => { - - - - - !isEditMode && setShowApplyTimePicker(true)} - style={{ - cursor: isEditMode ? 'not-allowed' : 'pointer', - opacity: isEditMode ? 0.6 : 1 - }} - > - - - - {applyTime ? formatDateForDisplay(applyTime) : '请选择签约时间'} - - - - - - !isEditMode && setShowContractTimePicker(true)} - style={{ - cursor: isEditMode ? 'not-allowed' : 'pointer', - opacity: isEditMode ? 0.6 : 1 - }} - > - - - - {contractTime ? formatDateForDisplay(contractTime) : '请选择合同生效起止时间'} - - - - + {/**/} + {/* */} + {/**/} + {/**/} + {/* !isEditMode && setShowApplyTimePicker(true)}*/} + {/* style={{*/} + {/* cursor: isEditMode ? 'not-allowed' : 'pointer',*/} + {/* opacity: isEditMode ? 0.6 : 1*/} + {/* }}*/} + {/* >*/} + {/* */} + {/* */} + {/* */} + {/* {applyTime ? formatDateForDisplay(applyTime) : '请选择签约时间'}*/} + {/* */} + {/* */} + {/* */} + {/**/} + {/**/} + {/* !isEditMode && setShowContractTimePicker(true)}*/} + {/* style={{*/} + {/* cursor: isEditMode ? 'not-allowed' : 'pointer',*/} + {/* opacity: isEditMode ? 0.6 : 1*/} + {/* }}*/} + {/* >*/} + {/* */} + {/* */} + {/* */} + {/* {contractTime ? formatDateForDisplay(contractTime) : '请选择合同生效起止时间'}*/} + {/* */} + {/* */} + {/* */} + {/**/} {/**/} {/* */} {/**/} diff --git a/src/dealer/customer/index.tsx b/src/dealer/customer/index.tsx index f4dfb2c..31075b9 100644 --- a/src/dealer/customer/index.tsx +++ b/src/dealer/customer/index.tsx @@ -41,7 +41,7 @@ const CustomerIndex = () => { // 构建API参数,根据状态筛选 const params: any = { - type: 0, + type: 4, page: currentPage }; const applyStatus = mapCustomerStatusToApplyStatus(statusFilter || activeTab); @@ -126,10 +126,10 @@ const CustomerIndex = () => { try { // 并行获取各状态的数量 const [allRes, pendingRes, signedRes, cancelledRes] = await Promise.all([ - pageShopDealerApply({type: 0}), // 全部 - pageShopDealerApply({applyStatus: 10, type: 0}), // 跟进中 - pageShopDealerApply({applyStatus: 20, type: 0}), // 已签约 - pageShopDealerApply({applyStatus: 30, type: 0}) // 已取消 + pageShopDealerApply({type: 4}), // 全部 + pageShopDealerApply({applyStatus: 10, type: 4}), // 跟进中 + pageShopDealerApply({applyStatus: 20, type: 4}), // 已签约 + pageShopDealerApply({applyStatus: 30, type: 4}) // 已取消 ]); setStatusCounts({ diff --git a/src/dealer/team/index.tsx b/src/dealer/team/index.tsx index 2e95611..e6cb1ec 100644 --- a/src/dealer/team/index.tsx +++ b/src/dealer/team/index.tsx @@ -1,6 +1,7 @@ import React, {useState, useEffect, useCallback} from 'react' import {View, Text} from '@tarojs/components' -import {Space,Empty, Avatar, Button} from '@nutui/nutui-react-taro' +import {Phone} from '@nutui/icons-react-taro' +import {Space, Empty, Avatar, Button} from '@nutui/nutui-react-taro' import Taro from '@tarojs/taro' import {useDealerUser} from '@/hooks/useDealerUser' import {listShopDealerReferee} from '@/api/shop/shopDealerReferee' @@ -41,6 +42,90 @@ const DealerTeam: React.FC = () => { // 当前查看的用户名称 const [currentDealerName, setCurrentDealerName] = useState('') + // 异步加载成员统计数据 + const loadMemberStats = async (members: TeamMemberWithStats[]) => { + // 分批处理,避免过多并发请求 + const batchSize = 3 + for (let i = 0; i < members.length; i += batchSize) { + const batch = members.slice(i, i + batchSize) + + const batchStats = await Promise.all( + batch.map(async (member) => { + try { + // 并行获取订单统计和下级成员数量 + const [orderResult, subMembersResult] = await Promise.all([ + pageShopDealerOrder({ + page: 1, + userId: member.userId + }), + listShopDealerReferee({ + dealerId: member.userId, + deleted: 0 + }) + ]) + + let orderCount = 0 + let commission = '0.00' + let status: 'active' | 'inactive' = 'inactive' + + if (orderResult?.list) { + const orders = orderResult.list + orderCount = orders.length + commission = orders.reduce((sum, order) => { + const levelCommission = member.level === 1 ? order.firstMoney : + member.level === 2 ? order.secondMoney : + order.thirdMoney + return sum + parseFloat(levelCommission || '0') + }, 0).toFixed(2) + + // 判断活跃状态(30天内有订单为活跃) + const thirtyDaysAgo = new Date() + thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30) + const hasRecentOrder = orders.some(order => + new Date(order.createTime || '') > thirtyDaysAgo + ) + status = hasRecentOrder ? 'active' : 'inactive' + } + + return { + ...member, + orderCount, + commission, + status, + subMembers: subMembersResult?.length || 0 + } + } catch (error) { + console.error(`获取成员${member.userId}数据失败:`, error) + return { + ...member, + orderCount: 0, + commission: '0.00', + status: 'inactive' as const, + subMembers: 0 + } + } + }) + ) + + // 更新这一批成员的数据 + setTeamMembers(prevMembers => { + const updatedMembers = [...prevMembers] + batchStats.forEach(updatedMember => { + const index = updatedMembers.findIndex(m => m.userId === updatedMember.userId) + if (index !== -1) { + updatedMembers[index] = updatedMember + } + }) + return updatedMembers + }) + + // 添加小延迟,避免请求过于密集 + if (i + batchSize < members.length) { + await new Promise(resolve => setTimeout(resolve, 100)) + } + } + } + // 获取团队数据 const fetchTeamData = useCallback(async () => { if (!dealerUser?.userId && !dealerId) return @@ -54,6 +139,7 @@ const DealerTeam: React.FC = () => { }) if (refereeResult) { + console.log('团队成员原始数据:', refereeResult) // 处理团队成员数据 const processedMembers: TeamMemberWithStats[] = refereeResult.map(member => ({ ...member, @@ -65,60 +151,12 @@ const DealerTeam: React.FC = () => { joinTime: member.createTime })) - // 并行获取每个成员的订单统计和下级成员数量 - const memberStats = await Promise.all( - processedMembers.map(async (member) => { - try { - // 获取订单统计 - const orderResult = await pageShopDealerOrder({ - page: 1, - userId: member.userId - }) + // 先显示基础数据,然后异步加载详细统计 + setTeamMembers(processedMembers) + setLoading(false) - // 获取下级成员数量 - const subMembersResult = await listShopDealerReferee({ - dealerId: member.userId, - deleted: 0 - }) - - let orderCount = 0 - let commission = '0.00' - let status: 'active' | 'inactive' = 'inactive' - - if (orderResult?.list) { - const orders = orderResult.list - orderCount = orders.length - commission = orders.reduce((sum, order) => { - const levelCommission = member.level === 1 ? order.firstMoney : - member.level === 2 ? order.secondMoney : - order.thirdMoney - return sum + parseFloat(levelCommission || '0') - }, 0).toFixed(2) - - // 判断活跃状态(30天内有订单为活跃) - const thirtyDaysAgo = new Date() - thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30) - const hasRecentOrder = orders.some(order => - new Date(order.createTime || '') > thirtyDaysAgo - ) - status = hasRecentOrder ? 'active' : 'inactive' - } - - return { - ...member, - orderCount, - commission, - status, - subMembers: subMembersResult?.length || 0 - } - } catch (error) { - console.error(`获取成员${member.userId}数据失败:`, error) - return member - } - }) - ) - - setTeamMembers(memberStats) + // 异步加载每个成员的详细统计数据 + loadMemberStats(processedMembers) } } catch (error) { @@ -198,6 +236,10 @@ const DealerTeam: React.FC = () => { const renderMemberItem = (member: TeamMemberWithStats) => { // 判断是否可以点击:有下级成员且未达到层级限制 const canClick = member.subMembers && member.subMembers > 0 && levelStack.length < 1 + // 判断是否显示手机号:只有本级(levelStack.length === 0)才显示 + const showPhone = levelStack.length === 0 + // 判断数据是否还在加载中(初始值都是0或'0.00') + const isStatsLoading = member.orderCount === 0 && member.commission === '0.00' && member.subMembers === 0 return ( { }`} onClick={() => getNextUser(member)} > - - - - - - {member.nickname} + + + + + + + {member.nickname} + + + {/* 显示手机号(仅本级可见) */} + {showPhone && member.phone && ( + + {member.phone} + + + )} + + + 加入时间:{member.joinTime} - - 加入时间:{member.joinTime} - + + + + + 订单数 + + {isStatsLoading ? '-' : member.orderCount} + + + + 贡献佣金 + + {isStatsLoading ? '-' : `¥${member.commission}`} + + + + 团队成员 + + {isStatsLoading ? '-' : (member.subMembers || 0)} + + - - - - 订单数 - - {member.orderCount} - - - - 贡献佣金 - - ¥{member.commission} - - - - 团队成员 - - {member.subMembers || 0} - - - - ) } @@ -287,7 +338,7 @@ const DealerTeam: React.FC = () => { navTo(`/dealer/apply/add`,true)}]} + }} actions={[{text: '立即申请', onClick: () => navTo(`/dealer/apply/add`, true)}]} /> ) diff --git a/src/dealer/wechat/index.tsx b/src/dealer/wechat/index.tsx index 4098de3..1132e6e 100644 --- a/src/dealer/wechat/index.tsx +++ b/src/dealer/wechat/index.tsx @@ -1,6 +1,7 @@ import {useEffect, useState} from 'react' import {View, Text, Image} from '@tarojs/components' import {Tabs} from '@nutui/nutui-react-taro' +import Taro from '@tarojs/taro' import './index.scss' import {listCmsWebsiteField} from "@/api/cms/cmsWebsiteField"; import {CmsWebsiteField} from "@/api/cms/cmsWebsiteField/model"; @@ -9,15 +10,74 @@ const WechatService = () => { const [activeTab, setActiveTab] = useState('0') const [codes, setCodes] = useState([]) + // 长按保存二维码到相册 + const saveQRCodeToAlbum = (imageUrl: string) => { + // 首先下载图片到本地 + Taro.downloadFile({ + url: imageUrl, + success: (res) => { + if (res.statusCode === 200) { + // 保存图片到相册 + Taro.saveImageToPhotosAlbum({ + filePath: res.tempFilePath, + success: () => { + Taro.showToast({ + title: '保存成功', + icon: 'success', + duration: 2000 + }) + }, + fail: (error) => { + console.error('保存失败:', error) + if (error.errMsg.includes('auth deny')) { + Taro.showModal({ + title: '提示', + content: '需要您授权保存图片到相册', + showCancel: true, + cancelText: '取消', + confirmText: '去设置', + success: (modalRes) => { + if (modalRes.confirm) { + Taro.openSetting() + } + } + }) + } else { + Taro.showToast({ + title: '保存失败', + icon: 'error', + duration: 2000 + }) + } + } + }) + } else { + Taro.showToast({ + title: '图片下载失败', + icon: 'error', + duration: 2000 + }) + } + }, + fail: () => { + Taro.showToast({ + title: '图片下载失败', + icon: 'error', + duration: 2000 + }) + } + }) + } + const renderQRCode = (data: typeof codes[0]) => ( - saveQRCodeToAlbum(`${data.value}`)} /> {data.style && 联系电话:{data.style}} diff --git a/src/dealer/withdraw/index.tsx b/src/dealer/withdraw/index.tsx index fd49672..e8f6cc1 100644 --- a/src/dealer/withdraw/index.tsx +++ b/src/dealer/withdraw/index.tsx @@ -204,9 +204,9 @@ const DealerWithdraw: React.FC = () => { return } - if (amount < 10) { + if (amount < 100) { Taro.showToast({ - title: '最低提现金额为10元', + title: '最低提现金额为100元', icon: 'error' }) return @@ -316,7 +316,7 @@ const DealerWithdraw: React.FC = () => { borderTop: '1px solid rgba(255, 255, 255, 0.3)' }}> - 最低提现金额:¥10 + 最低提现金额:¥100 diff --git a/src/pages/index/Header.tsx b/src/pages/index/Header.tsx index a5afb84..d4fcdb7 100644 --- a/src/pages/index/Header.tsx +++ b/src/pages/index/Header.tsx @@ -193,6 +193,18 @@ const Header = (props: any) => { useEffect(() => { if (isLoggedIn && user) { console.log('用户信息已更新:', user); + // 检查是否设置头像和昵称 + if(user.nickname === '微信用户'){ + Taro.showToast({ + title: '请设置头像和昵称', + icon: 'none' + }) + setTimeout(() => { + Taro.navigateTo({ + url: '/user/profile/profile' + }); + }, 2000) + } } }, [user, isLoggedIn])