绑定邀请码

This commit is contained in:
邹方成 2026-02-04 13:09:01 +08:00
parent 1cfa7e8322
commit cdfe233ea8
3 changed files with 148 additions and 40 deletions

View File

@ -271,6 +271,10 @@ export function getUserInvites(user_id, page = 1, page_size = 20) {
// 兼容性适配接口 (适配 pages/mine/index.vue) // 兼容性适配接口 (适配 pages/mine/index.vue)
// ============================================ // ============================================
export function bindInviter(invite_code) {
return authRequest({ url: '/api/app/users/inviter/bind', method: 'POST', data: { invite_code } })
}
// ============================================ // ============================================
// 用户信息修改 API // 用户信息修改 API
// ============================================ // ============================================

View File

@ -157,6 +157,12 @@
</view> </view>
<text class="menu-label">任务中心</text> <text class="menu-label">任务中心</text>
</view> </view>
<view class="menu-item" @click="showBindInviterPopup" v-if="!inviterId">
<view class="menu-icon-box">
<image class="menu-icon-img" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0OCIgaGVpZ2h0PSI0OCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiMzMzMiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0xMCAxMyxhNSw1IDAgMCwwIDcuNTQsLjU0bDMtM2E1LDUgMCAwLDAgLTcuMDctNy4wN2wtMS43MiwxLjcxIiAvPjxwYXRoIGQ9Ik0xNCAxMSxhNSw1IDAgMCwwIC03LjU0LC0uNTRsLTMsM2E1LDUgMCAwLDAgNy4wNyw3LjA3bDEuNzIsLTEuNzEiIC8+PC9zdmc+" mode="aspectFit"></image>
</view>
<text class="menu-label">填写邀请码</text>
</view>
<view class="menu-item" @click="toInvitesPage"> <view class="menu-item" @click="toInvitesPage">
<view class="menu-icon-box"> <view class="menu-icon-box">
<image class="menu-icon-img" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0OCIgaGVpZ2h0PSI0OCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiMzMzMiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0xNyAyMXYtMmE0IDQgMCAwIDAtNC00SDdhNCA0IDAgMCAwLTQgNHYyIj48L3BhdGg+PGNpcmNsZSBjeD0iMTAiIGN5PSI3IiByPSI0Ij48L2NpcmNsZT48cGF0aCBkPSJNMjMgMjF2LTJhNCA0IDAgMCAwLTMtMy4yNyI+PC9wYXRoPjxwYXRoIGQ9Ik0xNiAzLjEzYTQgNCAwIDAgMSAwIDcuNzUiPjwvcGF0aD48L3N2Zz4=" mode="aspectFit"></image> <image class="menu-icon-img" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0OCIgaGVpZ2h0PSI0OCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9IiMzMzMiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0xNyAyMXYtMmE0IDQgMCAwIDAtNC00SDdhNCA0IDAgMCAwLTQgNHYyIj48L3BhdGg+PGNpcmNsZSBjeD0iMTAiIGN5PSI3IiByPSI0Ij48L2NpcmNsZT48cGF0aCBkPSJNMjMgMjF2LTJhNCA0IDAgMCAwLTMtMy4yNyI+PC9wYXRoPjxwYXRoIGQ9Ik0xNiAzLjEzYTQgNCAwIDAgMSAwIDcuNzUiPjwvcGF0aD48L3N2Zz4=" mode="aspectFit"></image>
@ -492,13 +498,31 @@
</view> </view>
</view> </view>
<!-- 绑定邀请码弹窗 -->
<view class="popup-mask" v-if="bindInviterVisible" @tap="closeBindInviterPopup">
<view class="popup-content bind-inviter-popup" @tap.stop>
<view class="popup-header">
<text class="popup-title">填写邀请码</text>
<text class="close-btn" @tap="closeBindInviterPopup">×</text>
</view>
<view class="bind-inviter-body">
<view class="bind-desc">请输入好友的邀请码绑定后双方可获得奖励</view>
<view class="input-wrapper">
<input type="text" v-model="bindInviteCode" class="invite-code-input" placeholder="请输入邀请码" placeholder-class="input-placeholder" />
</view>
<button class="bind-btn" @tap="handleBindInviter">确认绑定</button>
</view>
</view>
</view>
</view> </view>
</template> </template>
<script> <script>
import { import {
getUserInfo, getUserStats, getPointsBalance, getUserPoints, getUserCoupons, getItemCards, getUserInfo, getUserStats, getPointsBalance, getUserPoints, getUserCoupons, getItemCards,
getUserTasks, getTaskProgress, getInviteRecords, modifyUser, getUserProfile, bindDouyinID, getPublicConfig getUserTasks, getTaskProgress, getInviteRecords, modifyUser, getUserProfile, bindDouyinID, getPublicConfig,
bindInviter
} from '../../api/appUser.js' } from '../../api/appUser.js'
import { checkPhoneBoundSync } from '../../utils/checkPhone.js' import { checkPhoneBoundSync } from '../../utils/checkPhone.js'
// #ifdef MP-TOUTIAO // #ifdef MP-TOUTIAO
@ -511,7 +535,7 @@ import customTabBar from '@/components/app-tab-bar.vue'
export default { export default {
components: { components: {
// #ifdef MP-TOUTIAO // #ifdef MP-TOUTIAO
customTabBarToutiao customTabBarToutiao,
// #endif // #endif
// #ifndef MP-TOUTIAO // #ifndef MP-TOUTIAO
customTabBar customTabBar
@ -524,9 +548,16 @@ export default {
avatar: '', avatar: '',
title: '', // title: '', //
inviteCode: '', inviteCode: '',
inviterId: 0,
inviterNickname: '',
inviterAvatar: '',
// Bind Inviter Popup
bindInviterVisible: false,
bindInviteCode: '',
mobile: '', // mobile: '', //
douyinUserId: '', // ID douyinUserId: '', // ID
douyinUserId: '', // ID
customerServiceQrCode: '', // customerServiceQrCode: '', //
customerServiceId: '0071112x', // IM customerServiceId: '0071112x', // IM
pointsBalance: 0, pointsBalance: 0,
@ -854,6 +885,9 @@ export default {
this.avatar = profile.avatar this.avatar = profile.avatar
this.title = profile.title || '' this.title = profile.title || ''
this.inviteCode = profile.invite_code this.inviteCode = profile.invite_code
this.inviterId = profile.inviter_id || 0
this.inviterNickname = profile.inviter_nickname || ''
this.inviterAvatar = profile.inviter_avatar || ''
this.pointsBalance = this.normalizePointsBalance(profile.balance) this.pointsBalance = this.normalizePointsBalance(profile.balance)
this.mobile = profile.mobile || '' this.mobile = profile.mobile || ''
this.douyinUserId = profile.douyin_user_id || '' this.douyinUserId = profile.douyin_user_id || ''
@ -865,6 +899,9 @@ export default {
cachedUser.avatar = profile.avatar cachedUser.avatar = profile.avatar
cachedUser.title = profile.title cachedUser.title = profile.title
cachedUser.invite_code = profile.invite_code cachedUser.invite_code = profile.invite_code
cachedUser.inviter_id = profile.inviter_id
cachedUser.inviter_nickname = profile.inviter_nickname
cachedUser.inviter_avatar = profile.inviter_avatar
cachedUser.mobile = profile.mobile cachedUser.mobile = profile.mobile
cachedUser.points_balance = this.pointsBalance cachedUser.points_balance = this.pointsBalance
uni.setStorageSync('user_info', cachedUser) uni.setStorageSync('user_info', cachedUser)
@ -882,9 +919,12 @@ export default {
return return
} }
// // ( API )
// ... ()
// profile inviterId
// inviterId
console.log('[Mine] profile API 无数据,使用降级逻辑') console.log('[Mine] profile API 无数据,使用降级逻辑')
//
const cachedUser = uni.getStorageSync('user_info') const cachedUser = uni.getStorageSync('user_info')
const cachedUserId = uni.getStorageSync('user_id') const cachedUserId = uni.getStorageSync('user_id')
@ -893,6 +933,11 @@ export default {
this.nickname = cachedUser.nickname this.nickname = cachedUser.nickname
this.avatar = cachedUser.avatar this.avatar = cachedUser.avatar
this.inviteCode = cachedUser.invite_code this.inviteCode = cachedUser.invite_code
// inviter
this.inviterId = cachedUser.inviter_id || 0
this.inviterNickname = cachedUser.inviter_nickname || ''
this.inviterAvatar = cachedUser.inviter_avatar || ''
this.title = cachedUser.title || '' this.title = cachedUser.title || ''
this.pointsBalance = this.normalizePointsBalance(cachedUser.points_balance) this.pointsBalance = this.normalizePointsBalance(cachedUser.points_balance)
this.mobile = cachedUser.mobile || cachedUser.phone || cachedUser.phone_number || '' this.mobile = cachedUser.mobile || cachedUser.phone || cachedUser.phone_number || ''
@ -901,43 +946,50 @@ export default {
this.userId = cachedUserId this.userId = cachedUserId
} }
// ... stats
if (this.userId) { if (this.userId) {
try { const s = await getUserStats(this.userId)
const balanceRes = await getPointsBalance(this.userId) if (s) this.stats = { ...this.stats, ...s }
if (balanceRes !== undefined) {
this.pointsBalance = this.normalizePointsBalance(balanceRes)
if (cachedUser) {
cachedUser.points_balance = this.pointsBalance
uni.setStorageSync('user_info', cachedUser)
}
}
} catch (e) {}
const s = await getUserStats(this.userId)
if (s) this.stats = { ...this.stats, ...s }
} else {
// userId getUserInfo (使)
const res = await getUserInfo()
if (res) {
this.userId = res.id
this.nickname = res.nickname
this.avatar = res.avatar
this.title = res.title || res.level_name || ''
this.inviteCode = res.invite_code
this.pointsBalance = this.normalizePointsBalance(res.points_balance)
this.mobile = res.mobile || res.phone || res.phone_number || ''
this.douyinUserId = res.douyin_user_id || ''
uni.setStorageSync('user_info', res)
uni.setStorageSync('user_id', res.id)
// Load stats
const s = await getUserStats(res.id)
if(s) this.stats = { ...this.stats, ...s }
}
} }
} catch (e) { } catch (e) {
console.error('[Mine] loadUserInfo 错误:', e) console.error('[Mine] loadUserInfo 错误:', e)
// If 401, maybe clear token }
},
showBindInviterPopup() {
if (!this.checkPhoneBound()) return
this.bindInviteCode = ''
this.bindInviterVisible = true
},
closeBindInviterPopup() {
this.bindInviterVisible = false
},
async handleBindInviter() {
const code = this.bindInviteCode.trim()
if (!code) {
uni.showToast({ title: '请输入邀请码', icon: 'none' })
return
}
//
if (code === this.inviteCode) {
uni.showToast({ title: '不能绑定自己的邀请码', icon: 'none' })
return
}
try {
uni.showLoading({ title: '绑定中...' })
await bindInviter(code)
uni.hideLoading()
uni.showToast({ title: '绑定成功', icon: 'success' })
this.bindInviterVisible = false
//
this.loadUserInfo()
} catch (err) {
uni.hideLoading()
uni.showToast({ title: err.message || '绑定失败', icon: 'none' })
} }
}, },
resetUser() { resetUser() {
@ -2271,6 +2323,58 @@ export default {
.invite-time { font-size: 22rpx; color: $text-tertiary; margin-top: 4rpx; } .invite-time { font-size: 22rpx; color: $text-tertiary; margin-top: 4rpx; }
.invite-status { font-size: 24rpx; color: #10B981; } .invite-status { font-size: 24rpx; color: #10B981; }
/* 绑定邀请码弹窗 */
.bind-inviter-popup {
width: 600rpx;
background: #fff;
border-radius: 24rpx;
overflow: hidden;
display: flex;
flex-direction: column;
}
.bind-inviter-body {
padding: 40rpx 30rpx 50rpx;
display: flex;
flex-direction: column;
align-items: center;
}
.bind-desc {
font-size: 28rpx;
color: #666;
margin-bottom: 40rpx;
text-align: center;
}
.input-wrapper {
width: 100%;
background: #F5F7FA;
border-radius: 12rpx;
padding: 24rpx;
margin-bottom: 50rpx;
box-sizing: border-box;
border: 1px solid #EBEEF5;
}
.invite-code-input {
width: 100%;
font-size: 32rpx;
color: #333;
text-align: center;
height: 48rpx;
line-height: 48rpx;
}
.bind-btn {
width: 100%;
height: 88rpx;
line-height: 88rpx;
background: linear-gradient(135deg, #FF6B00 0%, #FF9500 100%);
color: #fff;
font-size: 32rpx;
font-weight: bold;
border-radius: 44rpx;
}
.bind-btn:active {
opacity: 0.9;
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes zoomIn { from { transform: scale(0.9); opacity: 0; } to { transform: scale(1); opacity: 1; } } @keyframes zoomIn { from { transform: scale(0.9); opacity: 0; } to { transform: scale(1); opacity: 1; } }
</style> </style>

View File

@ -1,4 +1,4 @@
const BASE_URL = 'https://kdy.1024tool.vip' const BASE_URL = 'http://127.0.0.1:9991'
let authModalShown = false let authModalShown = false