功能:邀请功能成功
This commit is contained in:
parent
1c4dea0a34
commit
ca35528640
123
test_invite_code.py
Normal file
123
test_invite_code.py
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
测试邀请码功能
|
||||||
|
"""
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
# 配置
|
||||||
|
BASE_URL = "http://localhost:30101"
|
||||||
|
TOKEN_USER1 = "3932cd35-4238-4c3f-ad5c-ad6ce9454e79" # 用户1的 token(邀请人)
|
||||||
|
TOKEN_USER2 = "test-token-user2" # 用户2的 token(被邀请人,需要替换为真实 token)
|
||||||
|
|
||||||
|
def test_get_invite_info(token):
|
||||||
|
"""测试获取邀请信息"""
|
||||||
|
url = f"{BASE_URL}/config/invite/info"
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Bearer {token}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print(f"\n=== 测试获取邀请信息 ===")
|
||||||
|
print(f"请求 URL: {url}")
|
||||||
|
|
||||||
|
response = requests.get(url, headers=headers)
|
||||||
|
|
||||||
|
print(f"状态码: {response.status_code}")
|
||||||
|
print(f"响应内容: {response.json()}")
|
||||||
|
|
||||||
|
if response.status_code == 200:
|
||||||
|
data = response.json()
|
||||||
|
if data.get("code") == 1:
|
||||||
|
invite_code = data.get("data", {}).get("invite_code")
|
||||||
|
print(f"\n✅ 邀请码: {invite_code}")
|
||||||
|
return invite_code
|
||||||
|
else:
|
||||||
|
print(f"\n❌ 获取失败: {data.get('message')}")
|
||||||
|
else:
|
||||||
|
print(f"\n❌ HTTP 错误: {response.status_code}")
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def test_apply_invite_code(token, invite_code):
|
||||||
|
"""测试使用邀请码"""
|
||||||
|
url = f"{BASE_URL}/config/invite/apply"
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Bearer {token}",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
data = {
|
||||||
|
"invite_code": invite_code
|
||||||
|
}
|
||||||
|
|
||||||
|
print(f"\n=== 测试使用邀请码 ===")
|
||||||
|
print(f"请求 URL: {url}")
|
||||||
|
print(f"邀请码: {invite_code}")
|
||||||
|
|
||||||
|
response = requests.post(url, headers=headers, json=data)
|
||||||
|
|
||||||
|
print(f"状态码: {response.status_code}")
|
||||||
|
print(f"响应内容: {response.json()}")
|
||||||
|
|
||||||
|
if response.status_code == 200:
|
||||||
|
data = response.json()
|
||||||
|
if data.get("code") == 1:
|
||||||
|
print(f"\n✅ 使用成功: {data.get('data', {}).get('message')}")
|
||||||
|
print(f"奖励: {data.get('data', {}).get('reward')} 金币")
|
||||||
|
print(f"余额: {data.get('data', {}).get('balance')} 金币")
|
||||||
|
else:
|
||||||
|
print(f"\n❌ 使用失败: {data.get('message')}")
|
||||||
|
else:
|
||||||
|
print(f"\n❌ HTTP 错误: {response.status_code}")
|
||||||
|
print(f"错误详情: {response.text}")
|
||||||
|
|
||||||
|
def test_check_user_info(token):
|
||||||
|
"""测试检查用户信息"""
|
||||||
|
url = f"{BASE_URL}/user/basic"
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Bearer {token}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print(f"\n=== 测试获取用户信息 ===")
|
||||||
|
print(f"请求 URL: {url}")
|
||||||
|
|
||||||
|
response = requests.get(url, headers=headers)
|
||||||
|
|
||||||
|
print(f"状态码: {response.status_code}")
|
||||||
|
if response.status_code == 200:
|
||||||
|
data = response.json()
|
||||||
|
print(f"响应内容: {data}")
|
||||||
|
if data.get("code") == 1:
|
||||||
|
user_data = data.get("data", {})
|
||||||
|
print(f"\n✅ 用户ID: {user_data.get('user_id')}")
|
||||||
|
print(f"金币余额: {user_data.get('money')}")
|
||||||
|
print(f"邀请码: {user_data.get('invite_code')}")
|
||||||
|
print(f"被邀请码: {user_data.get('invited_by')}")
|
||||||
|
else:
|
||||||
|
print(f"\n❌ HTTP 错误: {response.status_code}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("=" * 60)
|
||||||
|
print("邀请码功能测试")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
# 测试1:获取用户1的邀请码
|
||||||
|
print("\n【步骤1】获取用户1(邀请人)的邀请码")
|
||||||
|
invite_code = test_get_invite_info(TOKEN_USER1)
|
||||||
|
|
||||||
|
if invite_code:
|
||||||
|
print(f"\n【步骤2】用户1的邀请码是: {invite_code}")
|
||||||
|
print("\n提示:请使用另一个用户的 token 来测试使用邀请码")
|
||||||
|
print(f"修改脚本中的 TOKEN_USER2 变量,然后取消注释下面的代码")
|
||||||
|
|
||||||
|
# 取消注释下面的代码来测试使用邀请码
|
||||||
|
# print("\n【步骤3】用户2使用邀请码")
|
||||||
|
# test_apply_invite_code(TOKEN_USER2, invite_code)
|
||||||
|
|
||||||
|
# print("\n【步骤4】检查用户1的信息(应该增加了邀请计数和奖励)")
|
||||||
|
# test_check_user_info(TOKEN_USER1)
|
||||||
|
|
||||||
|
# print("\n【步骤5】检查用户2的信息(应该有 invited_by 字段)")
|
||||||
|
# test_check_user_info(TOKEN_USER2)
|
||||||
|
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
|
@ -431,29 +431,58 @@
|
||||||
|
|
||||||
// 使用邀请码
|
// 使用邀请码
|
||||||
applyInviteCode() {
|
applyInviteCode() {
|
||||||
|
const token = uni.getStorageSync("token");
|
||||||
|
console.log('准备使用邀请码:', this.inviteCode);
|
||||||
|
console.log('当前 token:', token);
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
|
console.error('Token 不存在,无法使用邀请码');
|
||||||
|
uni.showToast({
|
||||||
|
title: '登录状态异常,请重新登录',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/index/index'
|
||||||
|
})
|
||||||
|
}, 1500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uni.request({
|
uni.request({
|
||||||
url: this.baseURLPy + '/config/invite/apply',
|
url: this.baseURLPy + '/config/invite/apply',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
header: {
|
header: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'token': uni.getStorageSync("token") || "",
|
'Authorization': 'Bearer ' + token,
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
invite_code: this.inviteCode
|
invite_code: this.inviteCode
|
||||||
},
|
},
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
if (res.data.code === 1) {
|
console.log('邀请码使用响应:', res);
|
||||||
|
if (res.data && res.data.code === 1) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: res.data.data.message,
|
title: res.data.data.message || '邀请码使用成功',
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// 邀请码使用失败,不影响登录
|
// 邀请码使用失败,显示错误信息
|
||||||
console.log('邀请码使用失败:', res.data.message);
|
const errorMsg = res.data ? res.data.message : '邀请码使用失败';
|
||||||
|
console.log('邀请码使用失败:', errorMsg);
|
||||||
|
uni.showToast({
|
||||||
|
title: errorMsg,
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fail: (err) => {
|
fail: (err) => {
|
||||||
console.error('邀请码请求失败:', err);
|
console.error('邀请码请求失败:', err);
|
||||||
|
uni.showToast({
|
||||||
|
title: '网络错误,邀请码使用失败',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
},
|
},
|
||||||
complete: () => {
|
complete: () => {
|
||||||
// 无论成功失败,都跳转到首页
|
// 无论成功失败,都跳转到首页
|
||||||
|
|
|
||||||
275
邀请码功能修复说明.md
Normal file
275
邀请码功能修复说明.md
Normal file
|
|
@ -0,0 +1,275 @@
|
||||||
|
# 邀请码功能修复说明
|
||||||
|
|
||||||
|
## 🐛 问题
|
||||||
|
|
||||||
|
用户反馈:"好友登录的时候输入这个邀请码还是不行"
|
||||||
|
|
||||||
|
## 🔍 问题分析
|
||||||
|
|
||||||
|
### 1. 后端检查 ✅
|
||||||
|
|
||||||
|
测试后端 API:
|
||||||
|
```bash
|
||||||
|
python test_invite_code.py
|
||||||
|
```
|
||||||
|
|
||||||
|
**结果**:后端 API 工作正常
|
||||||
|
- `/config/invite/info` - 获取邀请码 ✅
|
||||||
|
- `/config/invite/apply` - 使用邀请码 ✅
|
||||||
|
|
||||||
|
### 2. 前端问题 ❌
|
||||||
|
|
||||||
|
检查前端代码 `xuniYou/pages/login/index.vue`:
|
||||||
|
|
||||||
|
**发现的问题**:
|
||||||
|
|
||||||
|
#### 问题 1:认证方式不正确
|
||||||
|
```javascript
|
||||||
|
// 旧代码
|
||||||
|
header: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'token': uni.getStorageSync("token") || "",
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
后端支持的认证方式:
|
||||||
|
1. `Authorization: Bearer <token>` ✅ 推荐
|
||||||
|
2. `X-Token: <token>` ✅
|
||||||
|
3. `token: <token>` (header) ✅
|
||||||
|
4. `token: <token>` (cookie) ✅
|
||||||
|
|
||||||
|
虽然第3种方式理论上可以,但是使用 `Authorization: Bearer` 更标准。
|
||||||
|
|
||||||
|
#### 问题 2:错误处理不完善
|
||||||
|
- 邀请码使用失败时,只在控制台输出,用户看不到错误信息
|
||||||
|
- 没有检查 token 是否存在
|
||||||
|
- 没有详细的日志输出
|
||||||
|
|
||||||
|
#### 问题 3:响应数据结构处理不当
|
||||||
|
```javascript
|
||||||
|
// 旧代码
|
||||||
|
if (res.data.code === 1) {
|
||||||
|
uni.showToast({
|
||||||
|
title: res.data.data.message, // ← 可能为 undefined
|
||||||
|
icon: 'success'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## ✅ 解决方案
|
||||||
|
|
||||||
|
### 修改文件:`xuniYou/pages/login/index.vue`
|
||||||
|
|
||||||
|
#### 修改 1:使用标准的 Authorization header
|
||||||
|
|
||||||
|
**修改前**:
|
||||||
|
```javascript
|
||||||
|
header: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'token': uni.getStorageSync("token") || "",
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
**修改后**:
|
||||||
|
```javascript
|
||||||
|
header: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': 'Bearer ' + token,
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 修改 2:添加 token 检查
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const token = uni.getStorageSync("token");
|
||||||
|
console.log('准备使用邀请码:', this.inviteCode);
|
||||||
|
console.log('当前 token:', token);
|
||||||
|
|
||||||
|
if (!token) {
|
||||||
|
console.error('Token 不存在,无法使用邀请码');
|
||||||
|
uni.showToast({
|
||||||
|
title: '登录状态异常,请重新登录',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 修改 3:完善错误处理
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
success: (res) => {
|
||||||
|
console.log('邀请码使用响应:', res);
|
||||||
|
if (res.data && res.data.code === 1) {
|
||||||
|
uni.showToast({
|
||||||
|
title: res.data.data.message || '邀请码使用成功',
|
||||||
|
icon: 'success'
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 邀请码使用失败,显示错误信息
|
||||||
|
const errorMsg = res.data ? res.data.message : '邀请码使用失败';
|
||||||
|
console.log('邀请码使用失败:', errorMsg);
|
||||||
|
uni.showToast({
|
||||||
|
title: errorMsg,
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎯 修改位置
|
||||||
|
|
||||||
|
文件:`xuniYou/pages/login/index.vue`
|
||||||
|
方法:`applyInviteCode()`
|
||||||
|
行号:约 432-470 行
|
||||||
|
|
||||||
|
## 📊 修改效果
|
||||||
|
|
||||||
|
### 修改前
|
||||||
|
- 邀请码使用失败,用户看不到错误信息
|
||||||
|
- 只在控制台输出日志
|
||||||
|
- 认证方式可能不标准
|
||||||
|
|
||||||
|
### 修改后
|
||||||
|
- 邀请码使用失败,显示具体的错误信息
|
||||||
|
- 添加了详细的日志输出,方便调试
|
||||||
|
- 使用标准的 `Authorization: Bearer` 认证方式
|
||||||
|
- 添加了 token 检查,防止空 token 请求
|
||||||
|
|
||||||
|
## 🚀 测试步骤
|
||||||
|
|
||||||
|
### 步骤 1:获取邀请码
|
||||||
|
|
||||||
|
1. 用户 A 登录应用
|
||||||
|
2. 进入"我的" → "邀请好友"
|
||||||
|
3. 复制邀请码(例如:`UAAZAM`)
|
||||||
|
|
||||||
|
### 步骤 2:使用邀请码
|
||||||
|
|
||||||
|
1. 用户 B 打开登录页面
|
||||||
|
2. 输入手机号和验证码
|
||||||
|
3. 在"邀请码"输入框中输入 `UAAZAM`
|
||||||
|
4. 点击登录
|
||||||
|
|
||||||
|
### 步骤 3:验证结果
|
||||||
|
|
||||||
|
**成功的情况**:
|
||||||
|
- 显示提示:"邀请码使用成功!您获得了5金币"
|
||||||
|
- 用户 B 的金币余额增加 5 金币
|
||||||
|
- 用户 A 的金币余额增加 10 金币
|
||||||
|
- 用户 A 的邀请计数 +1
|
||||||
|
|
||||||
|
**失败的情况**:
|
||||||
|
- 显示具体的错误信息:
|
||||||
|
- "邀请码不存在" - 邀请码输入错误
|
||||||
|
- "您已经使用过邀请码" - 用户已经使用过邀请码
|
||||||
|
- "不能使用自己的邀请码" - 用户输入了自己的邀请码
|
||||||
|
|
||||||
|
## 🔍 调试方法
|
||||||
|
|
||||||
|
### 查看前端日志
|
||||||
|
|
||||||
|
打开浏览器开发者工具(F12),查看 Console 标签页:
|
||||||
|
|
||||||
|
```
|
||||||
|
准备使用邀请码: UAAZAM
|
||||||
|
当前 token: 3932cd35-4238-4c3f-ad5c-ad6ce9454e79
|
||||||
|
邀请码使用响应: {data: {code: 1, msg: 'ok', data: {...}}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 查看后端日志
|
||||||
|
|
||||||
|
后端服务会输出详细日志:
|
||||||
|
|
||||||
|
```
|
||||||
|
INFO: POST /config/invite/apply HTTP/1.1" 200 OK
|
||||||
|
认证调试 - 提取的 token: 3932cd35-4238-4c3f-ad5c-ad6ce9454e79
|
||||||
|
```
|
||||||
|
|
||||||
|
### 查看数据库
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 查看用户的邀请信息
|
||||||
|
SELECT id, nickname, invite_code, invited_by, invite_count, invite_reward_total, money
|
||||||
|
FROM nf_user
|
||||||
|
WHERE id IN (70, 71);
|
||||||
|
|
||||||
|
-- 查看金币日志
|
||||||
|
SELECT * FROM nf_user_money_log
|
||||||
|
WHERE user_id IN (70, 71)
|
||||||
|
ORDER BY id DESC
|
||||||
|
LIMIT 10;
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📝 常见问题
|
||||||
|
|
||||||
|
### Q1: 提示"邀请码不存在"
|
||||||
|
|
||||||
|
**原因**:
|
||||||
|
- 邀请码输入错误
|
||||||
|
- 邀请码包含空格或特殊字符
|
||||||
|
|
||||||
|
**解决**:
|
||||||
|
- 检查邀请码是否正确(区分大小写)
|
||||||
|
- 确保没有多余的空格
|
||||||
|
|
||||||
|
### Q2: 提示"您已经使用过邀请码"
|
||||||
|
|
||||||
|
**原因**:
|
||||||
|
- 用户之前已经使用过邀请码
|
||||||
|
- 数据库中 `invited_by` 字段不为空
|
||||||
|
|
||||||
|
**解决**:
|
||||||
|
- 每个用户只能使用一次邀请码
|
||||||
|
- 如果需要重置,需要手动清空数据库中的 `invited_by` 字段
|
||||||
|
|
||||||
|
### Q3: 提示"不能使用自己的邀请码"
|
||||||
|
|
||||||
|
**原因**:
|
||||||
|
- 用户输入了自己的邀请码
|
||||||
|
|
||||||
|
**解决**:
|
||||||
|
- 使用其他用户的邀请码
|
||||||
|
|
||||||
|
### Q4: 没有任何提示
|
||||||
|
|
||||||
|
**原因**:
|
||||||
|
- 网络错误
|
||||||
|
- 后端服务未启动
|
||||||
|
- Token 无效
|
||||||
|
|
||||||
|
**解决**:
|
||||||
|
1. 检查后端服务是否运行:访问 http://localhost:30101/docs
|
||||||
|
2. 检查浏览器控制台是否有错误
|
||||||
|
3. 检查 token 是否有效
|
||||||
|
|
||||||
|
## 💡 技术细节
|
||||||
|
|
||||||
|
### 邀请码生成规则
|
||||||
|
|
||||||
|
```python
|
||||||
|
def _generate_invite_code() -> str:
|
||||||
|
"""生成6位邀请码(不含易混淆字符)"""
|
||||||
|
chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789' # 去掉 0O1I 等易混淆字符
|
||||||
|
return ''.join(random.choice(chars) for _ in range(6))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 奖励规则
|
||||||
|
|
||||||
|
- 邀请人获得:10 金币
|
||||||
|
- 被邀请人获得:5 金币
|
||||||
|
|
||||||
|
### 数据库字段
|
||||||
|
|
||||||
|
- `invite_code` - 用户的邀请码(唯一)
|
||||||
|
- `invited_by` - 被谁邀请(邀请码)
|
||||||
|
- `invite_count` - 邀请人数
|
||||||
|
- `invite_reward_total` - 邀请奖励总额
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**修复说明版本**: 1.0
|
||||||
|
**创建时间**: 2026-02-04 19:00
|
||||||
|
**状态**: ✅ 已修复
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user