feat(invite): 重构邀请关系建立流程并优化相关功能
- 新增 bindRefereeRelation 接口替换原有的 createInviteRelation 接口 - 优化邀请参数解析逻辑,支持 uid_xxx 格式的邀请码 - 重构 handleInviteRelation 函数,使用新的绑定推荐关系接口 - 新增 checkAndHandleInviteRelation 和 manualHandleInviteRelation 函数 - 优化首页和订单列表的相关逻辑,以支持新的邀请关系建立流程 - 更新文档中的相关描述,如将"下级成员"改为"团队成员"
This commit is contained in:
@@ -61,7 +61,7 @@
|
|||||||
#### 新增功能
|
#### 新增功能
|
||||||
- 成员活跃状态标识
|
- 成员活跃状态标识
|
||||||
- 贡献佣金和订单数统计
|
- 贡献佣金和订单数统计
|
||||||
- 下级成员数量显示
|
- 团队成员数量显示
|
||||||
- 等级图标和颜色区分
|
- 等级图标和颜色区分
|
||||||
|
|
||||||
## 📊 技术改进
|
## 📊 技术改进
|
||||||
|
|||||||
@@ -33,6 +33,20 @@ export interface InviteRelationParam {
|
|||||||
inviteTime?: string;
|
inviteTime?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定推荐关系参数
|
||||||
|
*/
|
||||||
|
export interface BindRefereeParam {
|
||||||
|
// 推荐人ID
|
||||||
|
refereeId: number;
|
||||||
|
// 被推荐人ID (可选,如果不传则使用当前登录用户)
|
||||||
|
userId?: number;
|
||||||
|
// 推荐来源
|
||||||
|
source?: string;
|
||||||
|
// 场景值
|
||||||
|
scene?: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 邀请统计数据
|
* 邀请统计数据
|
||||||
*/
|
*/
|
||||||
@@ -120,7 +134,7 @@ export async function generateInviteCode(inviterId: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 建立邀请关系
|
* 建立邀请关系 (旧接口,保留兼容性)
|
||||||
*/
|
*/
|
||||||
export async function createInviteRelation(data: InviteRelationParam) {
|
export async function createInviteRelation(data: InviteRelationParam) {
|
||||||
const res = await request.post<ApiResult<unknown>>(
|
const res = await request.post<ApiResult<unknown>>(
|
||||||
@@ -133,6 +147,32 @@ export async function createInviteRelation(data: InviteRelationParam) {
|
|||||||
return Promise.reject(new Error(res.message));
|
return Promise.reject(new Error(res.message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定推荐关系 (新接口)
|
||||||
|
*/
|
||||||
|
export async function bindRefereeRelation(data: BindRefereeParam) {
|
||||||
|
try {
|
||||||
|
const res = await request.post<ApiResult<unknown>>(
|
||||||
|
'/shop/shop-dealer-referee',
|
||||||
|
{
|
||||||
|
refereeId: data.refereeId,
|
||||||
|
userId: data.userId,
|
||||||
|
source: data.source || 'qrcode',
|
||||||
|
scene: data.scene
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res.code === 0) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(res.message || '绑定推荐关系失败');
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('绑定推荐关系API调用失败:', error);
|
||||||
|
throw new Error(error.message || '绑定推荐关系失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理邀请场景值
|
* 处理邀请场景值
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ function AddCartBar() {
|
|||||||
navTo('/bszx/pay/pay?id=' + id)
|
navTo('/bszx/pay/pay?id=' + id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const reload = (id) => {
|
const reload = (id: number) => {
|
||||||
getCmsArticle(id).then(data => {
|
getCmsArticle(id).then(data => {
|
||||||
setArticle(data)
|
setArticle(data)
|
||||||
})
|
})
|
||||||
@@ -47,7 +47,7 @@ function AddCartBar() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const id = router?.params.id as number | undefined;
|
const id = router?.params.id as number | undefined;
|
||||||
setId(id)
|
setId(id)
|
||||||
reload(id);
|
reload(Number(id));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -126,9 +126,9 @@ const DealerQrcode: React.FC = () => {
|
|||||||
|
|
||||||
const inviteText = `🎉 邀请您加入我的团队!
|
const inviteText = `🎉 邀请您加入我的团队!
|
||||||
|
|
||||||
扫描小程序码或搜索"网宿小店"小程序,即可享受优质商品和服务!
|
扫描小程序码或搜索"时里院子市集"小程序,即可享受优质商品和服务!
|
||||||
|
|
||||||
💰 成为我的下级分销商,一起赚取丰厚佣金
|
💰 成为我的团队成员,一起赚取丰厚佣金
|
||||||
🎁 新用户专享优惠等你来拿
|
🎁 新用户专享优惠等你来拿
|
||||||
|
|
||||||
邀请码:${dealerUser.userId}
|
邀请码:${dealerUser.userId}
|
||||||
@@ -295,7 +295,7 @@ const DealerQrcode: React.FC = () => {
|
|||||||
<View className="flex items-start">
|
<View className="flex items-start">
|
||||||
<View className="w-2 h-2 bg-blue-500 rounded-full mt-2 mr-3 flex-shrink-0"></View>
|
<View className="w-2 h-2 bg-blue-500 rounded-full mt-2 mr-3 flex-shrink-0"></View>
|
||||||
<Text className="text-sm text-gray-600">
|
<Text className="text-sm text-gray-600">
|
||||||
好友通过您的二维码或链接注册成为您的下级分销商
|
好友通过您的二维码或链接注册成为您的团队成员
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View className="flex items-start">
|
<View className="flex items-start">
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ const DealerTeam: React.FC = () => {
|
|||||||
<Text className="text-sm font-semibold text-purple-600">
|
<Text className="text-sm font-semibold text-purple-600">
|
||||||
{member.subMembers}
|
{member.subMembers}
|
||||||
</Text>
|
</Text>
|
||||||
<Text className="text-xs text-gray-500">下级成员</Text>
|
<Text className="text-xs text-gray-500">团队成员</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {getShopInfo} from "@/api/layout";
|
|||||||
import {Sticky} from '@nutui/nutui-react-taro'
|
import {Sticky} from '@nutui/nutui-react-taro'
|
||||||
import Menu from "./Menu";
|
import Menu from "./Menu";
|
||||||
import Banner from "./Banner";
|
import Banner from "./Banner";
|
||||||
|
import {checkAndHandleInviteRelation, hasPendingInvite} from "@/utils/invite";
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
|
||||||
// import GoodsList from "./GoodsList";
|
// import GoodsList from "./GoodsList";
|
||||||
@@ -87,6 +88,23 @@ function Home() {
|
|||||||
getShopInfo().then(() => {
|
getShopInfo().then(() => {
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 检查是否有待处理的邀请关系
|
||||||
|
if (hasPendingInvite()) {
|
||||||
|
console.log('检测到待处理的邀请关系')
|
||||||
|
// 延迟处理,确保用户信息已加载
|
||||||
|
setTimeout(async () => {
|
||||||
|
try {
|
||||||
|
const success = await checkAndHandleInviteRelation()
|
||||||
|
if (success) {
|
||||||
|
console.log('首页邀请关系处理成功')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('首页邀请关系处理失败:', error)
|
||||||
|
}
|
||||||
|
}, 2000)
|
||||||
|
}
|
||||||
|
|
||||||
// Taro.getSetting:获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限。
|
// Taro.getSetting:获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限。
|
||||||
Taro.getSetting({
|
Taro.getSetting({
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {Avatar, Cell, Space, Empty, Tabs, Button, TabPane, Image} from '@nutui/nutui-react-taro'
|
import {Avatar, Cell, Space, Empty, Tabs, Button, TabPane, Image, Dialog} from '@nutui/nutui-react-taro'
|
||||||
import {useEffect, useState, CSSProperties} from "react";
|
import {useEffect, useState, useCallback, CSSProperties} from "react";
|
||||||
import {View, Text} from '@tarojs/components'
|
import {View, Text} from '@tarojs/components'
|
||||||
import Taro from '@tarojs/taro';
|
import Taro from '@tarojs/taro';
|
||||||
import {InfiniteLoading} from '@nutui/nutui-react-taro'
|
import {InfiniteLoading} from '@nutui/nutui-react-taro'
|
||||||
@@ -86,6 +86,7 @@ interface OrderListProps {
|
|||||||
onReload?: () => void;
|
onReload?: () => void;
|
||||||
searchParams?: ShopOrderParam;
|
searchParams?: ShopOrderParam;
|
||||||
showSearch?: boolean;
|
showSearch?: boolean;
|
||||||
|
onSearchParamsChange?: (params: ShopOrderParam) => void; // 新增:通知父组件参数变化
|
||||||
}
|
}
|
||||||
|
|
||||||
function OrderList(props: OrderListProps) {
|
function OrderList(props: OrderListProps) {
|
||||||
@@ -100,13 +101,17 @@ function OrderList(props: OrderListProps) {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
const [tapIndex, setTapIndex] = useState<string | number>(() => {
|
const [tapIndex, setTapIndex] = useState<number>(() => {
|
||||||
const initialIndex = getInitialTabIndex();
|
const initialIndex = getInitialTabIndex();
|
||||||
console.log('初始化tapIndex:', initialIndex, '对应statusFilter:', props.searchParams?.statusFilter);
|
console.log('初始化tapIndex:', initialIndex, '对应statusFilter:', props.searchParams?.statusFilter);
|
||||||
return initialIndex;
|
return initialIndex;
|
||||||
})
|
})
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [error, setError] = useState<string | null>(null)
|
const [error, setError] = useState<string | null>(null)
|
||||||
|
const [cancelDialogVisible, setCancelDialogVisible] = useState(false)
|
||||||
|
const [orderToCancel, setOrderToCancel] = useState<ShopOrder | null>(null)
|
||||||
|
const [confirmReceiveDialogVisible, setConfirmReceiveDialogVisible] = useState(false)
|
||||||
|
const [orderToConfirmReceive, setOrderToConfirmReceive] = useState<ShopOrder | null>(null)
|
||||||
|
|
||||||
// 获取订单状态文本
|
// 获取订单状态文本
|
||||||
const getOrderStatusText = (order: ShopOrder) => {
|
const getOrderStatusText = (order: ShopOrder) => {
|
||||||
@@ -174,7 +179,7 @@ function OrderList(props: OrderListProps) {
|
|||||||
return params;
|
return params;
|
||||||
};
|
};
|
||||||
|
|
||||||
const reload = async (resetPage = false, targetPage?: number) => {
|
const reload = useCallback(async (resetPage = false, targetPage?: number) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null); // 清除之前的错误
|
setError(null); // 清除之前的错误
|
||||||
const currentPage = resetPage ? 1 : (targetPage || page);
|
const currentPage = resetPage ? 1 : (targetPage || page);
|
||||||
@@ -228,18 +233,20 @@ function OrderList(props: OrderListProps) {
|
|||||||
ordersWithGoods.push(...batchResults);
|
ordersWithGoods.push(...batchResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 合并数据
|
// 使用函数式更新避免依赖 list
|
||||||
newList = resetPage ? ordersWithGoods : list?.concat(ordersWithGoods);
|
setList(prevList => {
|
||||||
|
const newList = resetPage ? ordersWithGoods : (prevList || []).concat(ordersWithGoods);
|
||||||
|
return newList;
|
||||||
|
});
|
||||||
|
|
||||||
// 正确判断是否还有更多数据
|
// 正确判断是否还有更多数据
|
||||||
const hasMoreData = res.list.length >= 10; // 假设每页10条数据
|
const hasMoreData = res.list.length >= 10; // 假设每页10条数据
|
||||||
setHasMore(hasMoreData);
|
setHasMore(hasMoreData);
|
||||||
} else {
|
} else {
|
||||||
newList = resetPage ? [] : list;
|
setList(prevList => resetPage ? [] : prevList);
|
||||||
setHasMore(false);
|
setHasMore(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
setList(newList || []);
|
|
||||||
setPage(currentPage);
|
setPage(currentPage);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -252,51 +259,77 @@ function OrderList(props: OrderListProps) {
|
|||||||
icon: 'none'
|
icon: 'none'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
}, [tapIndex, page, props.searchParams]); // 移除 list 依赖
|
||||||
|
|
||||||
const reloadMore = async () => {
|
const reloadMore = useCallback(async () => {
|
||||||
if (loading || !hasMore) return; // 防止重复加载
|
if (loading || !hasMore) return; // 防止重复加载
|
||||||
const nextPage = page + 1;
|
const nextPage = page + 1;
|
||||||
setPage(nextPage);
|
setPage(nextPage);
|
||||||
await reload(false, nextPage);
|
await reload(false, nextPage);
|
||||||
|
}, [loading, hasMore, page, reload]);
|
||||||
|
|
||||||
|
// 确认收货 - 显示确认对话框
|
||||||
|
const confirmReceive = (order: ShopOrder) => {
|
||||||
|
setOrderToConfirmReceive(order);
|
||||||
|
setConfirmReceiveDialogVisible(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 确认收货
|
// 确认收货 - 执行收货操作
|
||||||
const confirmReceive = async (order: ShopOrder) => {
|
const handleConfirmReceive = async () => {
|
||||||
|
if (!orderToConfirmReceive) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
setConfirmReceiveDialogVisible(false);
|
||||||
|
|
||||||
await updateShopOrder({
|
await updateShopOrder({
|
||||||
...order,
|
...orderToConfirmReceive,
|
||||||
deliveryStatus: 30, // 已收货
|
deliveryStatus: 30, // 已收货
|
||||||
orderStatus: 1 // 已完成
|
orderStatus: 1 // 已完成
|
||||||
});
|
});
|
||||||
|
|
||||||
Taro.showToast({
|
Taro.showToast({
|
||||||
title: '确认收货成功',
|
title: '确认收货成功',
|
||||||
|
icon: 'success'
|
||||||
});
|
});
|
||||||
|
|
||||||
await reload(true); // 重新加载列表
|
await reload(true); // 重新加载列表
|
||||||
props.onReload?.(); // 通知父组件刷新
|
props.onReload?.(); // 通知父组件刷新
|
||||||
|
|
||||||
|
// 清空状态
|
||||||
|
setOrderToConfirmReceive(null);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error('确认收货失败:', error);
|
||||||
Taro.showToast({
|
Taro.showToast({
|
||||||
title: '确认收货失败',
|
title: '确认收货失败',
|
||||||
|
icon: 'none'
|
||||||
});
|
});
|
||||||
|
// 重新显示对话框
|
||||||
|
setConfirmReceiveDialogVisible(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 取消订单
|
// 取消确认收货对话框
|
||||||
const cancelOrder = async (order: ShopOrder) => {
|
const handleCancelReceiveDialog = () => {
|
||||||
try {
|
setConfirmReceiveDialogVisible(false);
|
||||||
// 显示确认对话框
|
setOrderToConfirmReceive(null);
|
||||||
const result = await Taro.showModal({
|
};
|
||||||
title: '确认取消',
|
|
||||||
content: '确定要取消这个订单吗?',
|
|
||||||
confirmText: '确认取消',
|
|
||||||
cancelText: '我再想想'
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!result.confirm) return;
|
// 取消订单
|
||||||
|
const cancelOrder = (order: ShopOrder) => {
|
||||||
|
setOrderToCancel(order);
|
||||||
|
setCancelDialogVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 确认取消订单
|
||||||
|
const handleConfirmCancel = async () => {
|
||||||
|
if (!orderToCancel) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
setCancelDialogVisible(false);
|
||||||
|
|
||||||
// 更新订单状态为已取消,而不是删除订单
|
// 更新订单状态为已取消,而不是删除订单
|
||||||
await updateShopOrder({
|
await updateShopOrder({
|
||||||
...order,
|
...orderToCancel,
|
||||||
orderStatus: 2 // 已取消
|
orderStatus: 2 // 已取消
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -312,9 +345,17 @@ function OrderList(props: OrderListProps) {
|
|||||||
title: '取消订单失败',
|
title: '取消订单失败',
|
||||||
icon: 'error'
|
icon: 'error'
|
||||||
});
|
});
|
||||||
|
} finally {
|
||||||
|
setOrderToCancel(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 取消对话框的取消操作
|
||||||
|
const handleCancelDialog = () => {
|
||||||
|
setCancelDialogVisible(false);
|
||||||
|
setOrderToCancel(null);
|
||||||
|
};
|
||||||
|
|
||||||
// 立即支付
|
// 立即支付
|
||||||
const payOrder = async (order: ShopOrder) => {
|
const payOrder = async (order: ShopOrder) => {
|
||||||
try {
|
try {
|
||||||
@@ -389,7 +430,7 @@ function OrderList(props: OrderListProps) {
|
|||||||
timeStamp: result.timeStamp,
|
timeStamp: result.timeStamp,
|
||||||
nonceStr: result.nonceStr,
|
nonceStr: result.nonceStr,
|
||||||
package: result.package,
|
package: result.package,
|
||||||
signType: result.signType as any,
|
signType: (result.signType || 'MD5') as 'MD5' | 'HMAC-SHA256',
|
||||||
paySign: result.paySign,
|
paySign: result.paySign,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -435,7 +476,7 @@ function OrderList(props: OrderListProps) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
void reload(true); // 首次加载或tab切换时重置页码
|
void reload(true); // 首次加载或tab切换时重置页码
|
||||||
}, [tapIndex]); // 监听tapIndex变化
|
}, [tapIndex]); // 只监听tapIndex变化,避免reload依赖循环
|
||||||
|
|
||||||
// 监听外部statusFilter变化,同步更新tab索引
|
// 监听外部statusFilter变化,同步更新tab索引
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -459,7 +500,7 @@ function OrderList(props: OrderListProps) {
|
|||||||
setTapIndex(targetTabIndex);
|
setTapIndex(targetTabIndex);
|
||||||
// 不需要调用reload,因为tapIndex变化会触发reload
|
// 不需要调用reload,因为tapIndex变化会触发reload
|
||||||
}
|
}
|
||||||
}, [props.searchParams?.statusFilter]); // 监听statusFilter变化
|
}, [props.searchParams?.statusFilter, tapIndex]); // 监听statusFilter变化
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -477,7 +518,20 @@ function OrderList(props: OrderListProps) {
|
|||||||
}}
|
}}
|
||||||
value={tapIndex}
|
value={tapIndex}
|
||||||
onChange={(paneKey) => {
|
onChange={(paneKey) => {
|
||||||
setTapIndex(paneKey)
|
console.log('Tab切换:', paneKey, '类型:', typeof paneKey);
|
||||||
|
const newTapIndex = Number(paneKey);
|
||||||
|
setTapIndex(newTapIndex);
|
||||||
|
|
||||||
|
// 通知父组件更新 searchParams.statusFilter
|
||||||
|
const currentTab = tabs.find(tab => tab.index === newTapIndex);
|
||||||
|
if (currentTab && props.onSearchParamsChange) {
|
||||||
|
const newSearchParams = {
|
||||||
|
...props.searchParams,
|
||||||
|
statusFilter: currentTab.statusFilter
|
||||||
|
};
|
||||||
|
console.log('通知父组件更新searchParams:', newSearchParams);
|
||||||
|
props.onSearchParamsChange(newSearchParams);
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
@@ -533,8 +587,8 @@ function OrderList(props: OrderListProps) {
|
|||||||
{/* 订单列表 */}
|
{/* 订单列表 */}
|
||||||
{list.length > 0 && list
|
{list.length > 0 && list
|
||||||
?.filter((item) => {
|
?.filter((item) => {
|
||||||
// 如果是待付款标签页(tapIndex === 0),过滤掉支付已过期的订单
|
// 如果是待付款标签页(tapIndex === 1),过滤掉支付已过期的订单
|
||||||
if (tapIndex === 0 && !item.payStatus && item.orderStatus !== 2 && item.createTime) {
|
if (tapIndex === 1 && !item.payStatus && item.orderStatus !== 2 && item.createTime) {
|
||||||
return !isPaymentExpired(item.createTime);
|
return !isPaymentExpired(item.createTime);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -626,7 +680,7 @@ function OrderList(props: OrderListProps) {
|
|||||||
{item.deliveryStatus === 20 && (
|
{item.deliveryStatus === 20 && (
|
||||||
<Button size={'small'} type="primary" onClick={(e) => {
|
<Button size={'small'} type="primary" onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
void confirmReceive(item);
|
confirmReceive(item);
|
||||||
}}>确认收货</Button>
|
}}>确认收货</Button>
|
||||||
)}
|
)}
|
||||||
{/* 已完成状态:显示申请退款 */}
|
{/* 已完成状态:显示申请退款 */}
|
||||||
@@ -645,6 +699,30 @@ function OrderList(props: OrderListProps) {
|
|||||||
</InfiniteLoading>
|
</InfiniteLoading>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
{/* 取消订单确认对话框 */}
|
||||||
|
<Dialog
|
||||||
|
title="确认取消"
|
||||||
|
visible={cancelDialogVisible}
|
||||||
|
confirmText="确认取消"
|
||||||
|
cancelText="我再想想"
|
||||||
|
onConfirm={handleConfirmCancel}
|
||||||
|
onCancel={handleCancelDialog}
|
||||||
|
>
|
||||||
|
确定要取消这个订单吗?
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
{/* 确认收货确认对话框 */}
|
||||||
|
<Dialog
|
||||||
|
title="确认收货"
|
||||||
|
visible={confirmReceiveDialogVisible}
|
||||||
|
confirmText="确认收货"
|
||||||
|
cancelText="我再想想"
|
||||||
|
onConfirm={handleConfirmReceive}
|
||||||
|
onCancel={handleCancelReceiveDialog}
|
||||||
|
>
|
||||||
|
确定已经收到商品了吗?确认收货后订单将完成。
|
||||||
|
</Dialog>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ function Order() {
|
|||||||
<span>我的订单</span>
|
<span>我的订单</span>
|
||||||
</NavBar>
|
</NavBar>
|
||||||
{/* 搜索和筛选工具栏 */}
|
{/* 搜索和筛选工具栏 */}
|
||||||
<View className="bg-white px-4 py-3 flex justify-between items-center border-b border-gray-100">
|
<View className="bg-white px-4 py-3 flex justify-between items-center border-gray-100">
|
||||||
<View className="flex items-center">
|
<View className="flex items-center">
|
||||||
<Filter
|
<Filter
|
||||||
size={18}
|
size={18}
|
||||||
@@ -153,6 +153,10 @@ function Order() {
|
|||||||
onReload={() => reload(searchParams)}
|
onReload={() => reload(searchParams)}
|
||||||
searchParams={searchParams}
|
searchParams={searchParams}
|
||||||
showSearch={showSearch}
|
showSearch={showSearch}
|
||||||
|
onSearchParamsChange={(newParams) => {
|
||||||
|
console.log('父组件接收到searchParams变化:', newParams);
|
||||||
|
setSearchParams(newParams);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import Taro from '@tarojs/taro'
|
import Taro from '@tarojs/taro'
|
||||||
import { createInviteRelation } from '@/api/invite'
|
import { bindRefereeRelation } from '@/api/invite'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 邀请参数接口
|
* 邀请参数接口
|
||||||
@@ -19,7 +19,22 @@ export function parseInviteParams(options: any): InviteParams | null {
|
|||||||
if (options.scene) {
|
if (options.scene) {
|
||||||
// 确保 scene 是字符串类型
|
// 确保 scene 是字符串类型
|
||||||
const sceneStr = typeof options.scene === 'string' ? options.scene : String(options.scene)
|
const sceneStr = typeof options.scene === 'string' ? options.scene : String(options.scene)
|
||||||
|
console.log('解析scene参数:', sceneStr)
|
||||||
|
|
||||||
|
// 处理 uid_xxx 格式的邀请码
|
||||||
|
if (sceneStr.startsWith('uid_')) {
|
||||||
|
const inviterId = sceneStr.replace('uid_', '')
|
||||||
|
if (inviterId && !isNaN(parseInt(inviterId))) {
|
||||||
|
console.log('检测到uid格式邀请码:', inviterId)
|
||||||
|
return {
|
||||||
|
inviter: inviterId,
|
||||||
|
source: 'qrcode',
|
||||||
|
t: Date.now().toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理传统的 key=value&key=value 格式
|
||||||
const params: InviteParams = {}
|
const params: InviteParams = {}
|
||||||
const pairs = sceneStr.split('&')
|
const pairs = sceneStr.split('&')
|
||||||
|
|
||||||
@@ -40,7 +55,10 @@ export function parseInviteParams(options: any): InviteParams | null {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return params.inviter ? params : null
|
if (params.inviter) {
|
||||||
|
console.log('检测到传统格式邀请码:', params)
|
||||||
|
return params
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从 query 参数中解析邀请信息(兼容旧版本)
|
// 从 query 参数中解析邀请信息(兼容旧版本)
|
||||||
@@ -119,34 +137,61 @@ export function clearInviteParams() {
|
|||||||
*/
|
*/
|
||||||
export async function handleInviteRelation(userId: number): Promise<boolean> {
|
export async function handleInviteRelation(userId: number): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
|
console.log('开始处理邀请关系,当前用户ID:', userId)
|
||||||
|
|
||||||
const inviteParams = getStoredInviteParams()
|
const inviteParams = getStoredInviteParams()
|
||||||
if (!inviteParams || !inviteParams.inviter) {
|
if (!inviteParams || !inviteParams.inviter) {
|
||||||
|
console.log('没有找到邀请参数,跳过邀请关系建立')
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('找到邀请参数:', inviteParams)
|
||||||
|
|
||||||
const inviterId = parseInt(inviteParams.inviter)
|
const inviterId = parseInt(inviteParams.inviter)
|
||||||
if (isNaN(inviterId) || inviterId === userId) {
|
if (isNaN(inviterId) || inviterId === userId) {
|
||||||
// 邀请人ID无效或自己邀请自己
|
// 邀请人ID无效或自己邀请自己
|
||||||
|
console.log('邀请人ID无效或自己邀请自己,清除邀请参数')
|
||||||
clearInviteParams()
|
clearInviteParams()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 建立邀请关系
|
console.log(`准备建立邀请关系: ${inviterId} -> ${userId}`)
|
||||||
await createInviteRelation({
|
|
||||||
inviterId: inviterId,
|
// 使用新的绑定推荐关系接口
|
||||||
inviteeId: userId,
|
await bindRefereeRelation({
|
||||||
source: inviteParams.source || 'unknown',
|
refereeId: inviterId,
|
||||||
scene: `inviter=${inviterId}&source=${inviteParams.source}&t=${inviteParams.t}`,
|
userId: userId,
|
||||||
inviteTime: new Date().toISOString()
|
source: inviteParams.source || 'qrcode',
|
||||||
|
scene: inviteParams.source === 'qrcode' ? `uid_${inviterId}` : `inviter=${inviterId}&source=${inviteParams.source}&t=${inviteParams.t}`
|
||||||
})
|
})
|
||||||
|
|
||||||
// 清除本地存储的邀请参数
|
// 清除本地存储的邀请参数
|
||||||
clearInviteParams()
|
clearInviteParams()
|
||||||
|
|
||||||
console.log(`邀请关系建立成功: ${inviterId} -> ${userId}`)
|
console.log(`邀请关系建立成功: ${inviterId} -> ${userId}`)
|
||||||
|
|
||||||
|
// 显示成功提示
|
||||||
|
setTimeout(() => {
|
||||||
|
Taro.showToast({
|
||||||
|
title: '邀请关系建立成功',
|
||||||
|
icon: 'success',
|
||||||
|
duration: 2000
|
||||||
|
})
|
||||||
|
}, 500)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('建立邀请关系失败:', error)
|
console.error('建立邀请关系失败:', error)
|
||||||
|
|
||||||
|
// 显示错误提示
|
||||||
|
setTimeout(() => {
|
||||||
|
Taro.showToast({
|
||||||
|
title: '邀请关系建立失败',
|
||||||
|
icon: 'error',
|
||||||
|
duration: 2000
|
||||||
|
})
|
||||||
|
}, 500)
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -229,3 +274,111 @@ export function trackInviteSource(source: string, inviterId?: number) {
|
|||||||
console.error('统计邀请来源失败:', error)
|
console.error('统计邀请来源失败:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查并处理当前用户的邀请关系
|
||||||
|
* 用于在用户登录后立即检查是否需要建立邀请关系
|
||||||
|
*/
|
||||||
|
export async function checkAndHandleInviteRelation(): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
// 获取当前用户信息
|
||||||
|
const userInfo = Taro.getStorageSync('userInfo')
|
||||||
|
if (!userInfo || !userInfo.userId) {
|
||||||
|
console.log('用户未登录,无法处理邀请关系')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return await handleInviteRelation(userInfo.userId)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('检查邀请关系失败:', error)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动触发邀请关系建立
|
||||||
|
* 用于在特定页面或时机手动建立邀请关系
|
||||||
|
*/
|
||||||
|
export async function manualHandleInviteRelation(userId: number): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
console.log('手动触发邀请关系建立,用户ID:', userId)
|
||||||
|
|
||||||
|
const inviteParams = getStoredInviteParams()
|
||||||
|
if (!inviteParams || !inviteParams.inviter) {
|
||||||
|
console.log('没有待处理的邀请参数')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await handleInviteRelation(userId)
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
// 显示成功提示
|
||||||
|
Taro.showModal({
|
||||||
|
title: '邀请成功',
|
||||||
|
content: '您已成功加入邀请人的团队!',
|
||||||
|
showCancel: false,
|
||||||
|
confirmText: '知道了'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
} catch (error) {
|
||||||
|
console.error('手动处理邀请关系失败:', error)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 直接绑定推荐关系
|
||||||
|
* 用于直接调用绑定推荐关系接口
|
||||||
|
*/
|
||||||
|
export async function bindReferee(refereeId: number, userId?: number, source: string = 'qrcode'): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
console.log('直接绑定推荐关系:', { refereeId, userId, source })
|
||||||
|
|
||||||
|
// 如果没有传入userId,尝试从本地存储获取
|
||||||
|
let targetUserId = userId
|
||||||
|
if (!targetUserId) {
|
||||||
|
const userInfo = Taro.getStorageSync('userInfo')
|
||||||
|
if (userInfo && userInfo.userId) {
|
||||||
|
targetUserId = userInfo.userId
|
||||||
|
} else {
|
||||||
|
throw new Error('无法获取用户ID')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 防止自己推荐自己
|
||||||
|
if (refereeId === targetUserId) {
|
||||||
|
throw new Error('不能推荐自己')
|
||||||
|
}
|
||||||
|
|
||||||
|
await bindRefereeRelation({
|
||||||
|
refereeId: refereeId,
|
||||||
|
userId: targetUserId,
|
||||||
|
source: source,
|
||||||
|
scene: source === 'qrcode' ? `uid_${refereeId}` : undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(`推荐关系绑定成功: ${refereeId} -> ${targetUserId}`)
|
||||||
|
|
||||||
|
// 显示成功提示
|
||||||
|
Taro.showToast({
|
||||||
|
title: '推荐关系绑定成功',
|
||||||
|
icon: 'success',
|
||||||
|
duration: 2000
|
||||||
|
})
|
||||||
|
|
||||||
|
return true
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error('绑定推荐关系失败:', error)
|
||||||
|
|
||||||
|
// 显示错误提示
|
||||||
|
Taro.showToast({
|
||||||
|
title: error.message || '绑定推荐关系失败',
|
||||||
|
icon: 'error',
|
||||||
|
duration: 2000
|
||||||
|
})
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user