refactor(dealer): 重构经销商申请和团队管理功能

-优化了经销商申请流程,简化了表单和提交逻辑
-重新设计了团队管理页面,优化了成员展示和统计功能
- 移除了不必要的功能和冗余代码,提高了代码可维护性- 调整了 API接口调用,确保数据处理的正确性和一致性
This commit is contained in:
2025-09-09 21:02:05 +08:00
parent bfab2b190a
commit b2d79ab052
4 changed files with 217 additions and 177 deletions

View File

@@ -36,5 +36,6 @@ export interface ShopDealerReferee {
export interface ShopDealerRefereeParam extends PageParam { export interface ShopDealerRefereeParam extends PageParam {
id?: number; id?: number;
dealerId?: number; dealerId?: number;
deleted?: number;
keywords?: string; keywords?: string;
} }

View File

@@ -1,21 +1,16 @@
import {useEffect, useState, useRef} from "react"; import {useEffect, useState, useRef} from "react";
import {Loading, CellGroup, Cell, Input, Form, Avatar, Button, Space} from '@nutui/nutui-react-taro' import {Loading, CellGroup, Input, Form, Avatar, Button, Space} from '@nutui/nutui-react-taro'
import {Edit} from '@nutui/icons-react-taro' import {Edit} from '@nutui/icons-react-taro'
import Taro from '@tarojs/taro' import Taro from '@tarojs/taro'
import {View, Text} from '@tarojs/components' import {View} from '@tarojs/components'
import FixedButton from "@/components/FixedButton"; import FixedButton from "@/components/FixedButton";
import {useUser} from "@/hooks/useUser"; import {useUser} from "@/hooks/useUser";
import {ShopDealerApply} from "@/api/shop/shopDealerApply/model";
import {
addShopDealerApply,
pageShopDealerApply,
updateShopDealerApply
} from "@/api/shop/shopDealerApply";
import {getShopDealerUser} from "@/api/shop/shopDealerUser";
import {TenantId} from "@/config/app"; import {TenantId} from "@/config/app";
import {updateUser} from "@/api/system/user"; import {updateUser} from "@/api/system/user";
import {User} from "@/api/system/user/model"; import {User} from "@/api/system/user/model";
import {getStoredInviteParams, handleInviteRelation} from "@/utils/invite"; import {getStoredInviteParams, handleInviteRelation} from "@/utils/invite";
import {addShopDealerUser} from "@/api/shop/shopDealerUser";
import {listUserRole, updateUserRole} from "@/api/system/userRole";
// 类型定义 // 类型定义
interface ChooseAvatarEvent { interface ChooseAvatarEvent {
@@ -35,22 +30,6 @@ const AddUserAddress = () => {
const [loading, setLoading] = useState<boolean>(true) const [loading, setLoading] = useState<boolean>(true)
const [FormData, setFormData] = useState<User>() const [FormData, setFormData] = useState<User>()
const formRef = useRef<any>(null) const formRef = useRef<any>(null)
const [isEditMode, setIsEditMode] = useState<boolean>(false)
const [existingApply, setExistingApply] = useState<ShopDealerApply | null>(null)
// 获取审核状态文字
const getApplyStatusText = (status?: number) => {
switch (status) {
case 10:
return '待审核'
case 20:
return '审核通过'
case 30:
return '驳回'
default:
return '未知状态'
}
}
const reload = async () => { const reload = async () => {
const inviteParams = getStoredInviteParams() const inviteParams = getStoredInviteParams()
@@ -60,39 +39,16 @@ const AddUserAddress = () => {
refereeId: Number(inviteParams.inviter), refereeId: Number(inviteParams.inviter),
}) })
} }
// 判断用户是否登录
if (!user?.userId) {
return false;
}
// 查询当前用户ID是否已有申请记录
try {
const res = await pageShopDealerApply({userId: user?.userId});
if (res && res.count > 0) {
setIsEditMode(true);
setExistingApply(res.list[0]);
// 如果有记录,填充表单数据
setFormData(res.list[0]);
setLoading(false)
} else {
setIsEditMode(false);
setExistingApply(null);
setLoading(false)
}
} catch (error) {
setLoading(true)
console.error('查询申请记录失败:', error);
setIsEditMode(false);
setExistingApply(null);
}
} }
const uploadAvatar = ({detail}: ChooseAvatarEvent) => { const uploadAvatar = ({detail}: ChooseAvatarEvent) => {
// 先更新本地显示的头像 // 先更新本地显示的头像(临时显示)
setFormData({ const tempFormData = {
...FormData, ...FormData,
avatar: `${detail.avatarUrl}`, avatar: `${detail.avatarUrl}`,
}) }
setFormData(tempFormData)
Taro.uploadFile({ Taro.uploadFile({
url: 'https://server.websoft.top/api/oss/upload', url: 'https://server.websoft.top/api/oss/upload',
@@ -105,20 +61,46 @@ const AddUserAddress = () => {
success: async (res) => { success: async (res) => {
const data = JSON.parse(res.data); const data = JSON.parse(res.data);
if (data.code === 0) { if (data.code === 0) {
const finalAvatarUrl = `${data.data.thumbnail}`
try { try {
// 使用 useUser hook 的 updateUser 方法更新头像 // 使用 useUser hook 的 updateUser 方法更新头像
await updateUser({ await updateUser({
avatar: `${data.data.thumbnail}` avatar: finalAvatarUrl
})
Taro.showToast({
title: '头像上传成功',
icon: 'success',
duration: 1500
}) })
// 由于 useEffect 监听了 user 变化FormData 会自动同步更新
} catch (error) { } catch (error) {
console.error('更新头像失败:', error) console.error('更新用户头像失败:', error)
// 如果更新失败,恢复原来的头像 }
// 无论用户信息更新是否成功都要更新本地FormData
const finalFormData = {
...tempFormData,
avatar: finalAvatarUrl
}
setFormData(finalFormData)
// 同步更新表单字段
if (formRef.current) {
formRef.current.setFieldsValue({
avatar: finalAvatarUrl
})
}
} else {
// 上传失败,恢复原来的头像
setFormData({ setFormData({
...FormData, ...FormData,
avatar: user?.avatar || '' avatar: user?.avatar || ''
}) })
} Taro.showToast({
title: '上传失败',
icon: 'error'
})
} }
}, },
fail: (error) => { fail: (error) => {
@@ -139,32 +121,60 @@ const AddUserAddress = () => {
// 提交表单 // 提交表单
const submitSucceed = async (values: any) => { const submitSucceed = async (values: any) => {
try { try {
// 验证必填字段
if (!values.phone && !FormData?.phone) {
Taro.showToast({
title: '请先获取手机号',
icon: 'error'
});
return;
}
if (!values.realName && !FormData?.nickname) {
Taro.showToast({
title: '请填写昵称',
icon: 'error'
});
return;
}
if (!values.avatar && !FormData?.avatar) {
Taro.showToast({
title: '请上传头像',
icon: 'error'
});
return;
}
const roles = await listUserRole({userId: user?.userId})
console.log(roles, 'roles...')
// 准备提交的数据 // 准备提交的数据
const submitData = { await updateUser({
...values, userId: user?.userId,
realName: values.realName || user?.nickname, nickname: values.realName || FormData?.nickname,
mobile: user?.phone, phone: values.phone || FormData?.phone,
refereeId: values.refereeId || FormData?.refereeId, avatar: values.avatar || FormData?.avatar,
applyStatus: 10, refereeId: values.refereeId || FormData?.refereeId
auditTime: undefined });
};
await getShopDealerUser(submitData.refereeId);
// 如果是编辑模式添加现有申请的id await addShopDealerUser({
if (isEditMode && existingApply?.applyId) { userId: user?.userId,
submitData.applyId = existingApply.applyId; realName: values.realName || FormData?.nickname,
mobile: values.phone || FormData?.phone,
refereeId: values.refereeId || FormData?.refereeId
})
if (roles.length > 0) {
await updateUserRole({
...roles[0],
roleId: 1848
})
} }
// 执行新增或更新操作
if (isEditMode) {
await updateShopDealerApply(submitData);
} else {
await addShopDealerApply(submitData);
}
Taro.showToast({ Taro.showToast({
title: `${isEditMode ? '提交' : '提交'}成功`, title: `注册成功`,
icon: 'success' icon: 'success'
}); });
@@ -174,20 +184,24 @@ const AddUserAddress = () => {
} catch (error) { } catch (error) {
console.error('验证邀请人失败:', error); console.error('验证邀请人失败:', error);
return Taro.showToast({
title: '邀请人ID不存在',
icon: 'error'
});
} }
} }
// 获取微信昵称 // 获取微信昵称
const getWxNickname = (nickname: string) => { const getWxNickname = (nickname: string) => {
// 更新表单数据 // 更新表单数据
setFormData({ const updatedFormData = {
...FormData, ...FormData,
nickname: nickname nickname: nickname
}); }
setFormData(updatedFormData);
// 同步更新表单字段
if (formRef.current) {
formRef.current.setFieldsValue({
realName: nickname
})
}
} }
/* 获取用户手机号 */ /* 获取用户手机号 */
@@ -225,18 +239,34 @@ const AddUserAddress = () => {
// 登录成功 // 登录成功
const token = res.data.data.access_token; const token = res.data.data.access_token;
const userData = res.data.data.user; const userData = res.data.data.user;
console.log(userData,'userData...') console.log(userData, 'userData...')
// 使用useUser Hook的loginUser方法更新状态 // 使用useUser Hook的loginUser方法更新状态
loginUser(token, userData); loginUser(token, userData);
if(userData.phone){ if (userData.phone) {
console.log('手机号已获取',userData.phone) console.log('手机号已获取', userData.phone)
setFormData({ const updatedFormData = {
...FormData,
...userData, ...userData,
phone: userData.phone phone: userData.phone
}
setFormData(updatedFormData)
// 更新表单字段值
if (formRef.current) {
formRef.current.setFieldsValue({
phone: userData.phone,
realName: userData.nickname || FormData?.nickname,
avatar: userData.avatar || FormData?.avatar
}) })
} }
Taro.showToast({
title: '手机号获取成功',
icon: 'success',
duration: 1500
})
}
// 处理邀请关系 // 处理邀请关系
@@ -290,6 +320,18 @@ const AddUserAddress = () => {
}) })
}, [user?.userId]); // 依赖用户ID当用户变化时重新加载 }, [user?.userId]); // 依赖用户ID当用户变化时重新加载
// 当FormData变化时同步更新表单字段值
useEffect(() => {
if (formRef.current && FormData) {
formRef.current.setFieldsValue({
refereeId: FormData.refereeId,
phone: FormData.phone,
avatar: FormData.avatar,
realName: FormData.nickname
});
}
}, [FormData]);
if (loading) { if (loading) {
return <Loading className={'px-2'}></Loading> return <Loading className={'px-2'}></Loading>
} }
@@ -311,7 +353,12 @@ const AddUserAddress = () => {
</Form.Item> </Form.Item>
<Form.Item name="phone" label="手机号" initialValue={FormData?.phone} required> <Form.Item name="phone" label="手机号" initialValue={FormData?.phone} required>
<View className="flex items-center justify-between"> <View className="flex items-center justify-between">
<Input placeholder="请填写手机号" disabled={true} maxLength={11}/> <Input
placeholder="请填写手机号"
disabled={true}
maxLength={11}
value={FormData?.phone || ''}
/>
<Button style={{color: '#ffffff'}} open-type="getPhoneNumber" onGetPhoneNumber={handleGetPhoneNumber}> <Button style={{color: '#ffffff'}} open-type="getPhoneNumber" onGetPhoneNumber={handleGetPhoneNumber}>
<Space> <Space>
<Button size="small"></Button> <Button size="small"></Button>
@@ -320,18 +367,18 @@ const AddUserAddress = () => {
</View> </View>
</Form.Item> </Form.Item>
{ {
FormData?.phone && <Form.Item name="avatar" label="头像" initialValue={user?.avatar} required> FormData?.phone && <Form.Item name="avatar" label="头像" initialValue={FormData?.avatar} required>
<Button open-type="chooseAvatar" style={{height: '58px'}} onChooseAvatar={uploadAvatar}> <Button open-type="chooseAvatar" style={{height: '58px'}} onChooseAvatar={uploadAvatar}>
<Avatar src={FormData?.avatar} size="54"/> <Avatar src={FormData?.avatar || user?.avatar} size="54"/>
</Button> </Button>
</Form.Item> </Form.Item>
} }
<Form.Item name="realName" label="昵称" initialValue={user?.nickname} required> <Form.Item name="realName" label="昵称" initialValue={FormData?.nickname} required>
<Input <Input
type="nickname" type="nickname"
className="info-content__input" className="info-content__input"
placeholder="请输入昵称" placeholder="请输入昵称"
value={FormData?.nickname} value={FormData?.nickname || ''}
onInput={(e: InputEvent) => getWxNickname(e.detail.value)} onInput={(e: InputEvent) => getWxNickname(e.detail.value)}
/> />
</Form.Item> </Form.Item>
@@ -339,13 +386,11 @@ const AddUserAddress = () => {
</Form> </Form>
{/* 底部浮动按钮 */} {/* 底部浮动按钮 */}
{(!isEditMode) && (
<FixedButton <FixedButton
icon={<Edit/>} icon={<Edit/>}
text={isEditMode ? '保存修改' : '提交申请'} text={'立即注册'}
onClick={handleFixedButtonClick} onClick={handleFixedButtonClick}
/> />
)}
</> </>
); );

View File

@@ -1,7 +1,7 @@
import React, {useState, useEffect} from 'react' import React, {useState, useEffect} from 'react'
import {View, Text, Image} from '@tarojs/components' import {View, Text, Image} from '@tarojs/components'
import {Button, Loading} from '@nutui/nutui-react-taro' import {Button, Loading} from '@nutui/nutui-react-taro'
import {Share, Download, Copy, QrCode} from '@nutui/icons-react-taro' import {Download, QrCode} from '@nutui/icons-react-taro'
import Taro from '@tarojs/taro' import Taro from '@tarojs/taro'
import {useDealerUser} from '@/hooks/useDealerUser' import {useDealerUser} from '@/hooks/useDealerUser'
import {generateInviteCode} from '@/api/invite' import {generateInviteCode} from '@/api/invite'
@@ -115,52 +115,52 @@ const DealerQrcode: React.FC = () => {
} }
// 复制邀请信息 // 复制邀请信息
const copyInviteInfo = () => { // const copyInviteInfo = () => {
if (!dealerUser?.userId) { // if (!dealerUser?.userId) {
Taro.showToast({ // Taro.showToast({
title: '用户信息未加载', // title: '用户信息未加载',
icon: 'error' // icon: 'error'
}) // })
return // return
} // }
//
const inviteText = `🎉 邀请您加入我的团队! // const inviteText = `🎉 邀请您加入我的团队!
//
扫描小程序码或搜索"九云售电云"小程序,即可享受优质商品和服务! // 扫描小程序码或搜索"九云售电云"小程序,即可享受优质商品和服务!
//
💰 成为我的团队成员,一起赚取丰厚佣金 // 💰 成为我的团队成员,一起赚取丰厚佣金
🎁 新用户专享优惠等你来拿 // 🎁 新用户专享优惠等你来拿
//
邀请码:${dealerUser.userId} // 邀请码:${dealerUser.userId}
快来加入我们吧!` // 快来加入我们吧!`
//
Taro.setClipboardData({ // Taro.setClipboardData({
data: inviteText, // data: inviteText,
success: () => { // success: () => {
Taro.showToast({ // Taro.showToast({
title: '邀请信息已复制', // title: '邀请信息已复制',
icon: 'success' // icon: 'success'
}) // })
} // }
}) // })
} // }
// 分享小程序码 // 分享小程序码
const shareMiniProgramCode = () => { // const shareMiniProgramCode = () => {
if (!dealerUser?.userId) { // if (!dealerUser?.userId) {
Taro.showToast({ // Taro.showToast({
title: '用户信息未加载', // title: '用户信息未加载',
icon: 'error' // icon: 'error'
}) // })
return // return
} // }
//
// 小程序分享 // // 小程序分享
Taro.showShareMenu({ // Taro.showShareMenu({
withShareTicket: true, // withShareTicket: true,
showShareItems: ['shareAppMessage'] // showShareItems: ['shareAppMessage']
}) // })
} // }
if (!dealerUser) { if (!dealerUser) {
return ( return (
@@ -263,29 +263,29 @@ const DealerQrcode: React.FC = () => {
</Button> </Button>
</View> </View>
<View className={'my-2 bg-white'}> {/*<View className={'my-2 bg-white'}>*/}
<Button {/* <Button*/}
size="large" {/* size="large"*/}
block {/* block*/}
icon={<Copy/>} {/* icon={<Copy/>}*/}
onClick={copyInviteInfo} {/* onClick={copyInviteInfo}*/}
disabled={!dealerUser?.userId || loading} {/* disabled={!dealerUser?.userId || loading}*/}
> {/* >*/}
{/* 复制邀请信息*/}
</Button> {/* </Button>*/}
</View> {/*</View>*/}
<View className={'my-2 bg-white'}> {/*<View className={'my-2 bg-white'}>*/}
<Button {/* <Button*/}
size="large" {/* size="large"*/}
block {/* block*/}
fill="outline" {/* fill="outline"*/}
icon={<Share/>} {/* icon={<Share/>}*/}
onClick={shareMiniProgramCode} {/* onClick={shareMiniProgramCode}*/}
disabled={!dealerUser?.userId || loading} {/* disabled={!dealerUser?.userId || loading}*/}
> {/* >*/}
{/* 分享给好友*/}
</Button> {/* </Button>*/}
</View> {/*</View>*/}
</View> </View>
{/* 推广说明 */} {/* 推广说明 */}

View File

@@ -72,13 +72,13 @@ const DealerTeam: React.FC = () => {
// 获取订单统计 // 获取订单统计
const orderResult = await pageShopDealerOrder({ const orderResult = await pageShopDealerOrder({
page: 1, page: 1,
limit: 100,
userId: member.userId userId: member.userId
}) })
// 获取下级成员数量 // 获取下级成员数量
const subMembersResult = await listShopDealerReferee({ const subMembersResult = await listShopDealerReferee({
dealerId: member.userId dealerId: member.userId,
deleted: 0
}) })
let orderCount = 0 let orderCount = 0
@@ -218,12 +218,6 @@ const DealerTeam: React.FC = () => {
<Text className="font-semibold text-gray-800 mr-2"> <Text className="font-semibold text-gray-800 mr-2">
{member.nickname} {member.nickname}
</Text> </Text>
{canClick && (
<Text className="text-xs text-blue-500"></Text>
)}
{!canClick && member.subMembers && member.subMembers > 0 && levelStack.length >= 1 && (
<Text className="text-xs text-red-500"></Text>
)}
</View> </View>
<Text className="text-xs text-gray-500"> <Text className="text-xs text-gray-500">
{member.joinTime} {member.joinTime}