forked from gxwebsoft/mp-10550
feat(invite): 优化邀请参数解析和处理逻辑
- 重构 invite 工具函数,增强参数解析能力 - 添加参数调试工具,便于排查问题 - 优化用户登录后的邀请关系处理流程- 调整 API调用,统一使用 dealerId替代 refereeId - 移除未使用的导入和冗余代码
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
export const ENV_CONFIG = {
|
export const ENV_CONFIG = {
|
||||||
// 开发环境
|
// 开发环境
|
||||||
development: {
|
development: {
|
||||||
API_BASE_URL: 'http://127.0.0.1:9200/api',
|
API_BASE_URL: 'https://cms-api.websoft.top/api',
|
||||||
APP_NAME: '开发环境',
|
APP_NAME: '开发环境',
|
||||||
DEBUG: 'true',
|
DEBUG: 'true',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import navTo from "@/utils/common";
|
|||||||
import {TenantId} from "@/config/app";
|
import {TenantId} from "@/config/app";
|
||||||
import {getMyAvailableCoupons} from "@/api/shop/shopUserCoupon";
|
import {getMyAvailableCoupons} from "@/api/shop/shopUserCoupon";
|
||||||
import {useUser} from "@/hooks/useUser";
|
import {useUser} from "@/hooks/useUser";
|
||||||
|
import {getStoredInviteParams} from "@/utils/invite";
|
||||||
|
|
||||||
function UserCard() {
|
function UserCard() {
|
||||||
const {getDisplayName, getRoleName} = useUser();
|
const {getDisplayName, getRoleName} = useUser();
|
||||||
@@ -134,6 +135,14 @@ function UserCard() {
|
|||||||
/* 获取用户手机号 */
|
/* 获取用户手机号 */
|
||||||
const handleGetPhoneNumber = ({detail}: {detail: {code?: string, encryptedData?: string, iv?: string}}) => {
|
const handleGetPhoneNumber = ({detail}: {detail: {code?: string, encryptedData?: string, iv?: string}}) => {
|
||||||
const {code, encryptedData, iv} = detail
|
const {code, encryptedData, iv} = detail
|
||||||
|
|
||||||
|
// 获取存储的邀请参数
|
||||||
|
const inviteParams = getStoredInviteParams()
|
||||||
|
const refereeId = inviteParams?.inviter ? parseInt(inviteParams.inviter) : 0
|
||||||
|
|
||||||
|
console.log('Admin UserCard组件登录时检测到的邀请参数:', inviteParams)
|
||||||
|
console.log('Admin UserCard组件推荐人ID:', refereeId)
|
||||||
|
|
||||||
Taro.login({
|
Taro.login({
|
||||||
success: function () {
|
success: function () {
|
||||||
if (code) {
|
if (code) {
|
||||||
@@ -145,7 +154,7 @@ function UserCard() {
|
|||||||
encryptedData,
|
encryptedData,
|
||||||
iv,
|
iv,
|
||||||
notVerifyPhone: true,
|
notVerifyPhone: true,
|
||||||
refereeId: 0,
|
refereeId: refereeId, // 使用解析出的推荐人ID
|
||||||
sceneType: 'save_referee',
|
sceneType: 'save_referee',
|
||||||
tenantId: TenantId
|
tenantId: TenantId
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import type { ApiResult, PageResult } from '@/api';
|
import type { ApiResult, PageResult } from '@/api';
|
||||||
|
import { BaseUrl } from '@/config/app';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 小程序码生成参数
|
* 小程序码生成参数
|
||||||
@@ -38,7 +39,7 @@ export interface InviteRelationParam {
|
|||||||
*/
|
*/
|
||||||
export interface BindRefereeParam {
|
export interface BindRefereeParam {
|
||||||
// 推荐人ID
|
// 推荐人ID
|
||||||
refereeId: number;
|
dealerId: number;
|
||||||
// 被推荐人ID (可选,如果不传则使用当前登录用户)
|
// 被推荐人ID (可选,如果不传则使用当前登录用户)
|
||||||
userId?: number;
|
userId?: number;
|
||||||
// 推荐来源
|
// 推荐来源
|
||||||
@@ -112,7 +113,7 @@ export async function generateMiniProgramCode(data: MiniProgramCodeParam) {
|
|||||||
try {
|
try {
|
||||||
const url = '/wx-login/getOrderQRCodeUnlimited/' + data.scene;
|
const url = '/wx-login/getOrderQRCodeUnlimited/' + data.scene;
|
||||||
// 由于接口直接返回图片buffer,我们直接构建完整的URL
|
// 由于接口直接返回图片buffer,我们直接构建完整的URL
|
||||||
return `${API_BASE_URL}${url}`;
|
return `${BaseUrl}${url}`;
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
throw new Error(error.message || '生成小程序码失败');
|
throw new Error(error.message || '生成小程序码失败');
|
||||||
}
|
}
|
||||||
@@ -155,7 +156,7 @@ export async function bindRefereeRelation(data: BindRefereeParam) {
|
|||||||
const res = await request.post<ApiResult<unknown>>(
|
const res = await request.post<ApiResult<unknown>>(
|
||||||
'/shop/shop-dealer-referee',
|
'/shop/shop-dealer-referee',
|
||||||
{
|
{
|
||||||
refereeId: data.refereeId,
|
dealerId: data.dealerId,
|
||||||
userId: data.userId,
|
userId: data.userId,
|
||||||
source: data.source || 'qrcode',
|
source: data.source || 'qrcode',
|
||||||
scene: data.scene
|
scene: data.scene
|
||||||
|
|||||||
20
src/app.ts
20
src/app.ts
@@ -6,7 +6,7 @@ import './app.scss'
|
|||||||
import {loginByOpenId} from "@/api/layout";
|
import {loginByOpenId} from "@/api/layout";
|
||||||
import {TenantId} from "@/config/app";
|
import {TenantId} from "@/config/app";
|
||||||
import {saveStorageByLoginUser} from "@/utils/server";
|
import {saveStorageByLoginUser} from "@/utils/server";
|
||||||
import {parseInviteParams, saveInviteParams, trackInviteSource, handleInviteRelation} from "@/utils/invite";
|
import {parseInviteParams, saveInviteParams, trackInviteSource, handleInviteRelation, debugInviteInfo} from "@/utils/invite";
|
||||||
|
|
||||||
function App(props: { children: any; }) {
|
function App(props: { children: any; }) {
|
||||||
const reload = () => {
|
const reload = () => {
|
||||||
@@ -57,12 +57,13 @@ function App(props: { children: any; }) {
|
|||||||
// 处理启动参数
|
// 处理启动参数
|
||||||
const handleLaunchOptions = (options: any) => {
|
const handleLaunchOptions = (options: any) => {
|
||||||
try {
|
try {
|
||||||
console.log('小程序启动参数:', options)
|
console.log('=== 小程序启动参数处理开始 ===')
|
||||||
|
console.log('完整启动参数:', JSON.stringify(options, null, 2))
|
||||||
|
|
||||||
// 解析邀请参数
|
// 解析邀请参数
|
||||||
const inviteParams = parseInviteParams(options)
|
const inviteParams = parseInviteParams(options)
|
||||||
if (inviteParams) {
|
if (inviteParams) {
|
||||||
console.log('检测到邀请参数:', inviteParams)
|
console.log('✅ 成功检测到邀请参数:', inviteParams)
|
||||||
|
|
||||||
// 保存邀请参数到本地存储
|
// 保存邀请参数到本地存储
|
||||||
saveInviteParams(inviteParams)
|
saveInviteParams(inviteParams)
|
||||||
@@ -73,12 +74,21 @@ function App(props: { children: any; }) {
|
|||||||
// 显示邀请提示
|
// 显示邀请提示
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
Taro.showToast({
|
Taro.showToast({
|
||||||
title: '检测到邀请信息',
|
title: `检测到邀请信息 ID:${inviteParams.inviter}`,
|
||||||
icon: 'success',
|
icon: 'success',
|
||||||
duration: 2000
|
duration: 3000
|
||||||
})
|
})
|
||||||
}, 1000)
|
}, 1000)
|
||||||
|
|
||||||
|
// 打印调试信息
|
||||||
|
setTimeout(() => {
|
||||||
|
debugInviteInfo()
|
||||||
|
}, 2000)
|
||||||
|
} else {
|
||||||
|
console.log('❌ 未检测到邀请参数')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('=== 小程序启动参数处理结束 ===')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('处理启动参数失败:', error)
|
console.error('处理启动参数失败:', error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ export const useUserData = (): UseUserDataReturn => {
|
|||||||
setLoading(true)
|
setLoading(true)
|
||||||
setError(null)
|
setError(null)
|
||||||
|
|
||||||
|
if(!Taro.getStorageSync('UserId')){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 并发请求所有数据
|
// 并发请求所有数据
|
||||||
const [userDataRes, couponsRes, giftCardsRes] = await Promise.all([
|
const [userDataRes, couponsRes, giftCardsRes] = await Promise.all([
|
||||||
getUserInfo(),
|
getUserInfo(),
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {TenantId} from "@/config/app";
|
|||||||
import {getOrganization} from "@/api/system/organization";
|
import {getOrganization} from "@/api/system/organization";
|
||||||
import {myUserVerify} from "@/api/system/userVerify";
|
import {myUserVerify} from "@/api/system/userVerify";
|
||||||
import { useShopInfo } from '@/hooks/useShopInfo';
|
import { useShopInfo } from '@/hooks/useShopInfo';
|
||||||
import {handleInviteRelation} from "@/utils/invite";
|
import {handleInviteRelation, getStoredInviteParams} from "@/utils/invite";
|
||||||
import {View,Text} from '@tarojs/components'
|
import {View,Text} from '@tarojs/components'
|
||||||
import MySearch from "./MySearch";
|
import MySearch from "./MySearch";
|
||||||
import './Header.scss';
|
import './Header.scss';
|
||||||
@@ -88,6 +88,14 @@ const Header = (props: any) => {
|
|||||||
/* 获取用户手机号 */
|
/* 获取用户手机号 */
|
||||||
const handleGetPhoneNumber = ({detail}: {detail: {code?: string, encryptedData?: string, iv?: string}}) => {
|
const handleGetPhoneNumber = ({detail}: {detail: {code?: string, encryptedData?: string, iv?: string}}) => {
|
||||||
const {code, encryptedData, iv} = detail
|
const {code, encryptedData, iv} = detail
|
||||||
|
|
||||||
|
// 获取存储的邀请参数
|
||||||
|
const inviteParams = getStoredInviteParams()
|
||||||
|
const refereeId = inviteParams?.inviter ? parseInt(inviteParams.inviter) : 0
|
||||||
|
|
||||||
|
console.log('登录时检测到的邀请参数:', inviteParams)
|
||||||
|
console.log('推荐人ID:', refereeId)
|
||||||
|
|
||||||
Taro.login({
|
Taro.login({
|
||||||
success: function () {
|
success: function () {
|
||||||
if (code) {
|
if (code) {
|
||||||
@@ -99,7 +107,7 @@ const Header = (props: any) => {
|
|||||||
encryptedData,
|
encryptedData,
|
||||||
iv,
|
iv,
|
||||||
notVerifyPhone: true,
|
notVerifyPhone: true,
|
||||||
refereeId: 0,
|
refereeId: refereeId, // 使用解析出的推荐人ID
|
||||||
sceneType: 'save_referee',
|
sceneType: 'save_referee',
|
||||||
tenantId: TenantId
|
tenantId: TenantId
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {myUserVerify} from "@/api/system/userVerify";
|
|||||||
import {User} from "@/api/system/user/model";
|
import {User} from "@/api/system/user/model";
|
||||||
import { useShopInfo } from '@/hooks/useShopInfo';
|
import { useShopInfo } from '@/hooks/useShopInfo';
|
||||||
import { useUser } from '@/hooks/useUser';
|
import { useUser } from '@/hooks/useUser';
|
||||||
import {handleInviteRelation} from "@/utils/invite";
|
import {handleInviteRelation, getStoredInviteParams} from "@/utils/invite";
|
||||||
import MySearch from "./MySearch";
|
import MySearch from "./MySearch";
|
||||||
import './Header.scss';
|
import './Header.scss';
|
||||||
|
|
||||||
@@ -74,6 +74,14 @@ const Header = (props: any) => {
|
|||||||
// 获取手机号授权
|
// 获取手机号授权
|
||||||
const handleGetPhoneNumber = ({detail}: {detail: {code?: string, encryptedData?: string, iv?: string}}) => {
|
const handleGetPhoneNumber = ({detail}: {detail: {code?: string, encryptedData?: string, iv?: string}}) => {
|
||||||
const {code, encryptedData, iv} = detail
|
const {code, encryptedData, iv} = detail
|
||||||
|
|
||||||
|
// 获取存储的邀请参数
|
||||||
|
const inviteParams = getStoredInviteParams()
|
||||||
|
const refereeId = inviteParams?.inviter ? parseInt(inviteParams.inviter) : 0
|
||||||
|
|
||||||
|
console.log('HeaderWithHook组件登录时检测到的邀请参数:', inviteParams)
|
||||||
|
console.log('HeaderWithHook组件推荐人ID:', refereeId)
|
||||||
|
|
||||||
Taro.login({
|
Taro.login({
|
||||||
success: function () {
|
success: function () {
|
||||||
if (code) {
|
if (code) {
|
||||||
@@ -85,7 +93,7 @@ const Header = (props: any) => {
|
|||||||
encryptedData,
|
encryptedData,
|
||||||
iv,
|
iv,
|
||||||
notVerifyPhone: true,
|
notVerifyPhone: true,
|
||||||
refereeId: 0,
|
refereeId: refereeId, // 使用解析出的推荐人ID
|
||||||
sceneType: 'save_referee',
|
sceneType: 'save_referee',
|
||||||
tenantId: TenantId
|
tenantId: TenantId
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {Input, Radio, Button} from '@nutui/nutui-react-taro'
|
|||||||
import {TenantId} from "@/config/app";
|
import {TenantId} from "@/config/app";
|
||||||
import './login.scss';
|
import './login.scss';
|
||||||
import {saveStorageByLoginUser} from "@/utils/server";
|
import {saveStorageByLoginUser} from "@/utils/server";
|
||||||
import {handleInviteRelation} from "@/utils/invite";
|
import {handleInviteRelation, getStoredInviteParams} from "@/utils/invite";
|
||||||
|
|
||||||
// 微信获取手机号回调参数类型
|
// 微信获取手机号回调参数类型
|
||||||
interface GetPhoneNumberDetail {
|
interface GetPhoneNumberDetail {
|
||||||
@@ -40,6 +40,14 @@ const Login = (props: LoginProps) => {
|
|||||||
/* 获取用户手机号 */
|
/* 获取用户手机号 */
|
||||||
const handleGetPhoneNumber = ({detail}: GetPhoneNumberEvent) => {
|
const handleGetPhoneNumber = ({detail}: GetPhoneNumberEvent) => {
|
||||||
const {code, encryptedData, iv} = detail
|
const {code, encryptedData, iv} = detail
|
||||||
|
|
||||||
|
// 获取存储的邀请参数
|
||||||
|
const inviteParams = getStoredInviteParams()
|
||||||
|
const refereeId = inviteParams?.inviter ? parseInt(inviteParams.inviter) : 0
|
||||||
|
|
||||||
|
console.log('Login组件登录时检测到的邀请参数:', inviteParams)
|
||||||
|
console.log('Login组件推荐人ID:', refereeId)
|
||||||
|
|
||||||
Taro.login({
|
Taro.login({
|
||||||
success: function () {
|
success: function () {
|
||||||
if (code) {
|
if (code) {
|
||||||
@@ -51,7 +59,7 @@ const Login = (props: LoginProps) => {
|
|||||||
encryptedData,
|
encryptedData,
|
||||||
iv,
|
iv,
|
||||||
notVerifyPhone: true,
|
notVerifyPhone: true,
|
||||||
refereeId: 0,
|
refereeId: refereeId, // 使用解析出的推荐人ID
|
||||||
sceneType: 'save_referee',
|
sceneType: 'save_referee',
|
||||||
tenantId: TenantId
|
tenantId: TenantId
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {TenantId} from "@/config/app";
|
|||||||
import {getMyAvailableCoupons} from "@/api/shop/shopUserCoupon";
|
import {getMyAvailableCoupons} from "@/api/shop/shopUserCoupon";
|
||||||
import {useUser} from "@/hooks/useUser";
|
import {useUser} from "@/hooks/useUser";
|
||||||
import {useUserData} from "@/hooks/useUserData";
|
import {useUserData} from "@/hooks/useUserData";
|
||||||
|
import {getStoredInviteParams} from "@/utils/invite";
|
||||||
|
|
||||||
function UserCard() {
|
function UserCard() {
|
||||||
const {
|
const {
|
||||||
@@ -151,6 +152,14 @@ function UserCard() {
|
|||||||
/* 获取用户手机号 */
|
/* 获取用户手机号 */
|
||||||
const handleGetPhoneNumber = ({detail}: {detail: {code?: string, encryptedData?: string, iv?: string}}) => {
|
const handleGetPhoneNumber = ({detail}: {detail: {code?: string, encryptedData?: string, iv?: string}}) => {
|
||||||
const {code, encryptedData, iv} = detail
|
const {code, encryptedData, iv} = detail
|
||||||
|
|
||||||
|
// 获取存储的邀请参数
|
||||||
|
const inviteParams = getStoredInviteParams()
|
||||||
|
const refereeId = inviteParams?.inviter ? parseInt(inviteParams.inviter) : 0
|
||||||
|
|
||||||
|
console.log('UserCard组件登录时检测到的邀请参数:', inviteParams)
|
||||||
|
console.log('UserCard组件推荐人ID:', refereeId)
|
||||||
|
|
||||||
Taro.login({
|
Taro.login({
|
||||||
success: function () {
|
success: function () {
|
||||||
if (code) {
|
if (code) {
|
||||||
@@ -162,7 +171,7 @@ function UserCard() {
|
|||||||
encryptedData,
|
encryptedData,
|
||||||
iv,
|
iv,
|
||||||
notVerifyPhone: true,
|
notVerifyPhone: true,
|
||||||
refereeId: 0,
|
refereeId: refereeId, // 使用解析出的推荐人ID
|
||||||
sceneType: 'save_referee',
|
sceneType: 'save_referee',
|
||||||
tenantId: TenantId
|
tenantId: TenantId
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -738,20 +738,20 @@ function OrderList(props: OrderListProps) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 待发货状态:显示申请退款 */}
|
{/* 待发货状态:显示申请退款 */}
|
||||||
{item.payStatus && item.deliveryStatus === 10 && item.orderStatus !== 2 && item.orderStatus !== 4 && (
|
{/*{item.payStatus && item.deliveryStatus === 10 && item.orderStatus !== 2 && item.orderStatus !== 4 && (*/}
|
||||||
<Button size={'small'} onClick={(e) => {
|
{/* <Button size={'small'} onClick={(e) => {*/}
|
||||||
e.stopPropagation();
|
{/* e.stopPropagation();*/}
|
||||||
applyRefund(item);
|
{/* applyRefund(item);*/}
|
||||||
}}>申请退款</Button>
|
{/* }}>申请退款</Button>*/}
|
||||||
)}
|
{/*)}*/}
|
||||||
|
|
||||||
{/* 待收货状态:显示查看物流和确认收货 */}
|
{/* 待收货状态:显示查看物流和确认收货 */}
|
||||||
{item.deliveryStatus === 20 && item.orderStatus !== 2 && (
|
{item.deliveryStatus === 20 && item.orderStatus !== 2 && (
|
||||||
<Space>
|
<Space>
|
||||||
<Button size={'small'} onClick={(e) => {
|
{/*<Button size={'small'} onClick={(e) => {*/}
|
||||||
e.stopPropagation();
|
{/* e.stopPropagation();*/}
|
||||||
viewLogistics(item);
|
{/* viewLogistics(item);*/}
|
||||||
}}>查看物流</Button>
|
{/*}}>查看物流</Button>*/}
|
||||||
<Button size={'small'} type="primary" onClick={(e) => {
|
<Button size={'small'} type="primary" onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
confirmReceive(item);
|
confirmReceive(item);
|
||||||
@@ -766,24 +766,24 @@ function OrderList(props: OrderListProps) {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
buyAgain(item);
|
buyAgain(item);
|
||||||
}}>再次购买</Button>
|
}}>再次购买</Button>
|
||||||
<Button size={'small'} onClick={(e) => {
|
{/*<Button size={'small'} onClick={(e) => {*/}
|
||||||
e.stopPropagation();
|
{/* e.stopPropagation();*/}
|
||||||
evaluateGoods(item);
|
{/* evaluateGoods(item);*/}
|
||||||
}}>评价商品</Button>
|
{/*}}>评价商品</Button>*/}
|
||||||
<Button size={'small'} onClick={(e) => {
|
{/*<Button size={'small'} onClick={(e) => {*/}
|
||||||
e.stopPropagation();
|
{/* e.stopPropagation();*/}
|
||||||
applyRefund(item);
|
{/* applyRefund(item);*/}
|
||||||
}}>申请退款</Button>
|
{/*}}>申请退款</Button>*/}
|
||||||
</Space>
|
</Space>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 退款/售后状态:显示查看进度和撤销申请 */}
|
{/* 退款/售后状态:显示查看进度和撤销申请 */}
|
||||||
{(item.orderStatus === 4 || item.orderStatus === 7) && (
|
{(item.orderStatus === 4 || item.orderStatus === 7) && (
|
||||||
<Space>
|
<Space>
|
||||||
<Button size={'small'} onClick={(e) => {
|
{/*<Button size={'small'} onClick={(e) => {*/}
|
||||||
e.stopPropagation();
|
{/* e.stopPropagation();*/}
|
||||||
viewProgress(item);
|
{/* viewProgress(item);*/}
|
||||||
}}>查看进度</Button>
|
{/*}}>查看进度</Button>*/}
|
||||||
</Space>
|
</Space>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
@@ -15,22 +15,41 @@ export interface InviteParams {
|
|||||||
*/
|
*/
|
||||||
export function parseInviteParams(options: any): InviteParams | null {
|
export function parseInviteParams(options: any): InviteParams | null {
|
||||||
try {
|
try {
|
||||||
|
console.log('开始解析邀请参数,完整options:', JSON.stringify(options))
|
||||||
|
|
||||||
|
// 优先从 query.scene 参数中解析邀请信息
|
||||||
|
let sceneStr = null
|
||||||
|
if (options.query && options.query.scene) {
|
||||||
|
sceneStr = typeof options.query.scene === 'string' ? options.query.scene : String(options.query.scene)
|
||||||
|
console.log('从query.scene解析参数:', sceneStr, '类型:', typeof sceneStr)
|
||||||
|
} else if (options.scene) {
|
||||||
|
// 兼容直接从 scene 参数解析
|
||||||
|
sceneStr = typeof options.scene === 'string' ? options.scene : String(options.scene)
|
||||||
|
console.log('从options.scene解析参数:', sceneStr, '类型:', typeof sceneStr)
|
||||||
|
}
|
||||||
|
|
||||||
// 从 scene 参数中解析邀请信息
|
// 从 scene 参数中解析邀请信息
|
||||||
if (options.scene) {
|
if (sceneStr) {
|
||||||
// 确保 scene 是字符串类型
|
|
||||||
const sceneStr = typeof options.scene === 'string' ? options.scene : String(options.scene)
|
|
||||||
console.log('解析scene参数:', sceneStr)
|
|
||||||
|
|
||||||
// 处理 uid_xxx 格式的邀请码
|
// 处理 uid_xxx 格式的邀请码
|
||||||
if (sceneStr.startsWith('uid_')) {
|
if (sceneStr.startsWith('uid_')) {
|
||||||
const inviterId = sceneStr.replace('uid_', '')
|
const inviterId = sceneStr.replace('uid_', '')
|
||||||
|
console.log('提取的邀请人ID:', inviterId)
|
||||||
|
|
||||||
if (inviterId && !isNaN(parseInt(inviterId))) {
|
if (inviterId && !isNaN(parseInt(inviterId))) {
|
||||||
console.log('检测到uid格式邀请码:', inviterId)
|
const parsedInviterId = parseInt(inviterId)
|
||||||
return {
|
console.log('检测到uid格式邀请码,邀请人ID:', parsedInviterId)
|
||||||
|
|
||||||
|
const inviteParams = {
|
||||||
inviter: inviterId,
|
inviter: inviterId,
|
||||||
source: 'qrcode',
|
source: 'qrcode',
|
||||||
t: Date.now().toString()
|
t: Date.now().toString()
|
||||||
}
|
}
|
||||||
|
console.log('返回的邀请参数:', inviteParams)
|
||||||
|
|
||||||
|
return inviteParams
|
||||||
|
} else {
|
||||||
|
console.log('邀请人ID无效:', inviterId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,6 +78,8 @@ export function parseInviteParams(options: any): InviteParams | null {
|
|||||||
console.log('检测到传统格式邀请码:', params)
|
console.log('检测到传统格式邀请码:', params)
|
||||||
return params
|
return params
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
console.log('options中没有scene参数或query.scene参数')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从 query 参数中解析邀请信息(兼容旧版本)
|
// 从 query 参数中解析邀请信息(兼容旧版本)
|
||||||
@@ -81,11 +102,17 @@ export function parseInviteParams(options: any): InviteParams | null {
|
|||||||
*/
|
*/
|
||||||
export function saveInviteParams(params: InviteParams) {
|
export function saveInviteParams(params: InviteParams) {
|
||||||
try {
|
try {
|
||||||
Taro.setStorageSync('invite_params', {
|
const saveData = {
|
||||||
...params,
|
...params,
|
||||||
timestamp: Date.now()
|
timestamp: Date.now()
|
||||||
})
|
}
|
||||||
console.log('邀请参数已保存:', params)
|
|
||||||
|
Taro.setStorageSync('invite_params', saveData)
|
||||||
|
console.log('邀请参数已保存到本地存储:', saveData)
|
||||||
|
|
||||||
|
// 验证保存是否成功
|
||||||
|
const saved = Taro.getStorageSync('invite_params')
|
||||||
|
console.log('验证保存结果:', saved)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('保存邀请参数失败:', error)
|
console.error('保存邀请参数失败:', error)
|
||||||
}
|
}
|
||||||
@@ -97,21 +124,28 @@ export function saveInviteParams(params: InviteParams) {
|
|||||||
export function getStoredInviteParams(): InviteParams | null {
|
export function getStoredInviteParams(): InviteParams | null {
|
||||||
try {
|
try {
|
||||||
const stored = Taro.getStorageSync('invite_params')
|
const stored = Taro.getStorageSync('invite_params')
|
||||||
|
console.log('从本地存储获取的邀请参数:', stored)
|
||||||
|
|
||||||
if (stored && stored.inviter) {
|
if (stored && stored.inviter) {
|
||||||
// 检查是否过期(24小时)
|
// 检查是否过期(24小时)
|
||||||
const now = Date.now()
|
const now = Date.now()
|
||||||
const expireTime = 24 * 60 * 60 * 1000 // 24小时
|
const expireTime = 24 * 60 * 60 * 1000 // 24小时
|
||||||
|
|
||||||
if (now - stored.timestamp < expireTime) {
|
if (now - stored.timestamp < expireTime) {
|
||||||
return {
|
const result = {
|
||||||
inviter: stored.inviter,
|
inviter: stored.inviter,
|
||||||
source: stored.source || 'unknown',
|
source: stored.source || 'unknown',
|
||||||
t: stored.t
|
t: stored.t
|
||||||
}
|
}
|
||||||
|
console.log('返回有效的邀请参数:', result)
|
||||||
|
return result
|
||||||
} else {
|
} else {
|
||||||
|
console.log('邀请参数已过期,清除本地存储')
|
||||||
// 过期则清除
|
// 过期则清除
|
||||||
clearInviteParams()
|
clearInviteParams()
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
console.log('本地存储中没有有效的邀请参数')
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -159,7 +193,7 @@ export async function handleInviteRelation(userId: number): Promise<boolean> {
|
|||||||
|
|
||||||
// 使用新的绑定推荐关系接口
|
// 使用新的绑定推荐关系接口
|
||||||
await bindRefereeRelation({
|
await bindRefereeRelation({
|
||||||
refereeId: inviterId,
|
dealerId: inviterId,
|
||||||
userId: userId,
|
userId: userId,
|
||||||
source: inviteParams.source || 'qrcode',
|
source: inviteParams.source || 'qrcode',
|
||||||
scene: inviteParams.source === 'qrcode' ? `uid_${inviterId}` : `inviter=${inviterId}&source=${inviteParams.source}&t=${inviteParams.t}`
|
scene: inviteParams.source === 'qrcode' ? `uid_${inviterId}` : `inviter=${inviterId}&source=${inviteParams.source}&t=${inviteParams.t}`
|
||||||
@@ -275,20 +309,68 @@ export function trackInviteSource(source: string, inviterId?: number) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调试工具:打印所有邀请相关的存储信息
|
||||||
|
*/
|
||||||
|
export function debugInviteInfo() {
|
||||||
|
try {
|
||||||
|
console.log('=== 邀请参数调试信息 ===')
|
||||||
|
|
||||||
|
// 获取启动参数
|
||||||
|
const launchOptions = Taro.getLaunchOptionsSync()
|
||||||
|
console.log('启动参数:', JSON.stringify(launchOptions, null, 2))
|
||||||
|
|
||||||
|
// 获取存储的邀请参数
|
||||||
|
const storedParams = Taro.getStorageSync('invite_params')
|
||||||
|
console.log('存储的邀请参数:', JSON.stringify(storedParams, null, 2))
|
||||||
|
|
||||||
|
// 获取用户信息
|
||||||
|
const userId = Taro.getStorageSync('UserId')
|
||||||
|
const userInfo = Taro.getStorageSync('userInfo')
|
||||||
|
console.log('用户ID:', userId)
|
||||||
|
console.log('用户信息:', JSON.stringify(userInfo, null, 2))
|
||||||
|
|
||||||
|
// 获取邀请统计
|
||||||
|
const inviteTracks = Taro.getStorageSync('invite_tracks')
|
||||||
|
console.log('邀请统计:', JSON.stringify(inviteTracks, null, 2))
|
||||||
|
|
||||||
|
console.log('=== 调试信息结束 ===')
|
||||||
|
|
||||||
|
return {
|
||||||
|
launchOptions,
|
||||||
|
storedParams,
|
||||||
|
userId,
|
||||||
|
userInfo,
|
||||||
|
inviteTracks
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取调试信息失败:', error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查并处理当前用户的邀请关系
|
* 检查并处理当前用户的邀请关系
|
||||||
* 用于在用户登录后立即检查是否需要建立邀请关系
|
* 用于在用户登录后立即检查是否需要建立邀请关系
|
||||||
*/
|
*/
|
||||||
export async function checkAndHandleInviteRelation(): Promise<boolean> {
|
export async function checkAndHandleInviteRelation(): Promise<boolean> {
|
||||||
try {
|
try {
|
||||||
|
// 打印调试信息
|
||||||
|
debugInviteInfo()
|
||||||
|
|
||||||
// 获取当前用户信息
|
// 获取当前用户信息
|
||||||
const userInfo = Taro.getStorageSync('userInfo')
|
const userInfo = Taro.getStorageSync('userInfo')
|
||||||
if (!userInfo || !userInfo.userId) {
|
const userId = Taro.getStorageSync('UserId')
|
||||||
|
|
||||||
|
const finalUserId = userId || userInfo?.userId
|
||||||
|
|
||||||
|
if (!finalUserId) {
|
||||||
console.log('用户未登录,无法处理邀请关系')
|
console.log('用户未登录,无法处理邀请关系')
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return await handleInviteRelation(userInfo.userId)
|
console.log('使用用户ID处理邀请关系:', finalUserId)
|
||||||
|
return await handleInviteRelation(parseInt(finalUserId))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('检查邀请关系失败:', error)
|
console.error('检查邀请关系失败:', error)
|
||||||
return false
|
return false
|
||||||
@@ -353,7 +435,7 @@ export async function bindReferee(refereeId: number, userId?: number, source: st
|
|||||||
}
|
}
|
||||||
|
|
||||||
await bindRefereeRelation({
|
await bindRefereeRelation({
|
||||||
refereeId: refereeId,
|
dealerId: refereeId,
|
||||||
userId: targetUserId,
|
userId: targetUserId,
|
||||||
source: source,
|
source: source,
|
||||||
scene: source === 'qrcode' ? `uid_${refereeId}` : undefined
|
scene: source === 'qrcode' ? `uid_${refereeId}` : undefined
|
||||||
|
|||||||
166
src/utils/test-invite.ts
Normal file
166
src/utils/test-invite.ts
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
/**
|
||||||
|
* 邀请参数解析测试工具
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { parseInviteParams } from './invite'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试不同格式的邀请参数解析
|
||||||
|
*/
|
||||||
|
export function testInviteParamsParsing() {
|
||||||
|
console.log('=== 开始测试邀请参数解析 ===')
|
||||||
|
|
||||||
|
// 测试用例1: uid_格式
|
||||||
|
const testCase1 = {
|
||||||
|
scene: 'uid_33103',
|
||||||
|
path: 'pages/index/index'
|
||||||
|
}
|
||||||
|
console.log('测试用例1 - uid格式:')
|
||||||
|
console.log('输入:', testCase1)
|
||||||
|
const result1 = parseInviteParams(testCase1)
|
||||||
|
console.log('输出:', result1)
|
||||||
|
console.log('预期: { inviter: "33103", source: "qrcode", t: "..." }')
|
||||||
|
console.log('结果:', result1?.inviter === '33103' && result1?.source === 'qrcode' ? '✅ 通过' : '❌ 失败')
|
||||||
|
console.log('')
|
||||||
|
|
||||||
|
// 测试用例2: 传统格式
|
||||||
|
const testCase2 = {
|
||||||
|
scene: 'inviter=12345&source=share&t=1640995200000',
|
||||||
|
path: 'pages/index/index'
|
||||||
|
}
|
||||||
|
console.log('测试用例2 - 传统格式:')
|
||||||
|
console.log('输入:', testCase2)
|
||||||
|
const result2 = parseInviteParams(testCase2)
|
||||||
|
console.log('输出:', result2)
|
||||||
|
console.log('预期: { inviter: "12345", source: "share", t: "1640995200000" }')
|
||||||
|
console.log('结果:', result2?.inviter === '12345' && result2?.source === 'share' ? '✅ 通过' : '❌ 失败')
|
||||||
|
console.log('')
|
||||||
|
|
||||||
|
// 测试用例3: 数字类型的scene
|
||||||
|
const testCase3 = {
|
||||||
|
scene: 1047, // 数字类型
|
||||||
|
path: 'pages/index/index'
|
||||||
|
}
|
||||||
|
console.log('测试用例3 - 数字类型scene:')
|
||||||
|
console.log('输入:', testCase3)
|
||||||
|
const result3 = parseInviteParams(testCase3)
|
||||||
|
console.log('输出:', result3)
|
||||||
|
console.log('预期: null (因为不是uid_格式)')
|
||||||
|
console.log('结果:', result3 === null ? '✅ 通过' : '❌ 失败')
|
||||||
|
console.log('')
|
||||||
|
|
||||||
|
// 测试用例4: 空参数
|
||||||
|
const testCase4 = {}
|
||||||
|
console.log('测试用例4 - 空参数:')
|
||||||
|
console.log('输入:', testCase4)
|
||||||
|
const result4 = parseInviteParams(testCase4)
|
||||||
|
console.log('输出:', result4)
|
||||||
|
console.log('预期: null')
|
||||||
|
console.log('结果:', result4 === null ? '✅ 通过' : '❌ 失败')
|
||||||
|
console.log('')
|
||||||
|
|
||||||
|
// 测试用例5: 无效的uid格式
|
||||||
|
const testCase5 = {
|
||||||
|
scene: 'uid_abc',
|
||||||
|
path: 'pages/index/index'
|
||||||
|
}
|
||||||
|
console.log('测试用例5 - 无效uid格式:')
|
||||||
|
console.log('输入:', testCase5)
|
||||||
|
const result5 = parseInviteParams(testCase5)
|
||||||
|
console.log('输出:', result5)
|
||||||
|
console.log('预期: null (因为abc不是数字)')
|
||||||
|
console.log('结果:', result5 === null ? '✅ 通过' : '❌ 失败')
|
||||||
|
console.log('')
|
||||||
|
|
||||||
|
// 测试用例6: referrer参数
|
||||||
|
const testCase6 = {
|
||||||
|
referrer: '99999',
|
||||||
|
path: 'pages/index/index'
|
||||||
|
}
|
||||||
|
console.log('测试用例6 - referrer参数:')
|
||||||
|
console.log('输入:', testCase6)
|
||||||
|
const result6 = parseInviteParams(testCase6)
|
||||||
|
console.log('输出:', result6)
|
||||||
|
console.log('预期: { inviter: "99999", source: "link" }')
|
||||||
|
console.log('结果:', result6?.inviter === '99999' && result6?.source === 'link' ? '✅ 通过' : '❌ 失败')
|
||||||
|
console.log('')
|
||||||
|
|
||||||
|
console.log('=== 邀请参数解析测试完成 ===')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模拟小程序启动场景测试
|
||||||
|
*/
|
||||||
|
export function simulateMiniProgramLaunch() {
|
||||||
|
console.log('=== 模拟小程序启动场景 ===')
|
||||||
|
|
||||||
|
// 模拟通过小程序码启动
|
||||||
|
const qrcodeOptions = {
|
||||||
|
path: 'pages/index/index',
|
||||||
|
scene: 'uid_33103',
|
||||||
|
shareTicket: undefined,
|
||||||
|
referrerInfo: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('模拟小程序码启动:')
|
||||||
|
console.log('启动参数:', qrcodeOptions)
|
||||||
|
|
||||||
|
const qrcodeResult = parseInviteParams(qrcodeOptions)
|
||||||
|
console.log('解析结果:', qrcodeResult)
|
||||||
|
|
||||||
|
if (qrcodeResult && qrcodeResult.inviter === '33103') {
|
||||||
|
console.log('✅ 小程序码邀请解析成功')
|
||||||
|
return qrcodeResult
|
||||||
|
} else {
|
||||||
|
console.log('❌ 小程序码邀请解析失败')
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证邀请参数格式
|
||||||
|
*/
|
||||||
|
export function validateInviteParams(params: any) {
|
||||||
|
console.log('=== 验证邀请参数格式 ===')
|
||||||
|
console.log('参数:', params)
|
||||||
|
|
||||||
|
if (!params) {
|
||||||
|
console.log('❌ 参数为空')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!params.inviter) {
|
||||||
|
console.log('❌ 缺少inviter字段')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNaN(parseInt(params.inviter))) {
|
||||||
|
console.log('❌ inviter不是有效数字')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!params.source) {
|
||||||
|
console.log('❌ 缺少source字段')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('✅ 邀请参数格式验证通过')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运行所有测试
|
||||||
|
*/
|
||||||
|
export function runAllTests() {
|
||||||
|
console.log('🚀 开始运行所有邀请参数测试')
|
||||||
|
|
||||||
|
testInviteParamsParsing()
|
||||||
|
|
||||||
|
const simulationResult = simulateMiniProgramLaunch()
|
||||||
|
|
||||||
|
if (simulationResult) {
|
||||||
|
validateInviteParams(simulationResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('🎉 所有测试完成')
|
||||||
|
}
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# 设置代理(根据你的 Clash Verge 配置)
|
|
||||||
export http_proxy=http://127.0.0.1:7897
|
|
||||||
export https_proxy=http://127.0.0.1:7897
|
|
||||||
|
|
||||||
# 启动 Claude Code
|
|
||||||
echo "🚀 启动 Claude Code..."
|
|
||||||
echo "📡 使用代理: $http_proxy"
|
|
||||||
|
|
||||||
npx @anthropic-ai/claude-code
|
|
||||||
Reference in New Issue
Block a user