更新小程序隐私保护机制,新增手机号一键登录功能,用户需同意隐私协议后方可获取手机号。优化多个页面的登录交互,提升用户体验。调整相关配置以支持新功能。

This commit is contained in:
Alex-larget
2026-03-20 13:40:13 +08:00
parent 0bc32deb94
commit 385e47bc55
60 changed files with 2954 additions and 1669 deletions

View File

@@ -95,7 +95,10 @@ App({
this._privacyResolve = resolve
const pages = getCurrentPages()
const cur = pages[pages.length - 1]
if (cur && typeof cur.setData === 'function' && cur.route && (cur.route.includes('avatar-nickname') || cur.route.includes('profile-edit'))) {
const route = (cur && cur.route) || ''
const needPrivacyPages = ['avatar-nickname', 'profile-edit', 'read', 'my', 'gift-pay/detail', 'index', 'settings']
const needShow = needPrivacyPages.some(p => route.includes(p))
if (cur && typeof cur.setData === 'function' && needShow) {
cur.setData({ showPrivacyModal: true })
} else {
resolve({ event: 'disagree' })
@@ -413,12 +416,57 @@ App({
this.globalData.hasFullBook = userInfo.hasFullBook || false
this.globalData.isVip = userInfo.isVip || false
this.globalData.vipExpireDate = userInfo.vipExpireDate || ''
// 若手机号为空,后台静默刷新用户资料以同步最新手机号(可能在其他设备/页面已绑定)
if (!(userInfo.phone || '').trim()) {
this._refreshUserInfoIfPhoneEmpty()
}
}
} catch (e) {
console.error('检查登录状态失败:', e)
}
},
/**
* 手机号登录后:若响应中 user.phone 为空,从 profile 拉取最新资料并更新本地(后端已写入 DB
*/
async _syncPhoneFromProfileAfterLogin(userId) {
try {
if (!userId) return
const res = await this.request({ url: `/api/miniprogram/user/profile?userId=${userId}`, silent: true })
const profile = res?.data
if (!profile) return
const phone = (profile.phone || '').trim()
if (!phone) return
const updated = { ...this.globalData.userInfo, phone }
if (profile.wechatId != null) updated.wechatId = profile.wechatId
this.globalData.userInfo = updated
wx.setStorageSync('userInfo', updated)
wx.setStorageSync('user_phone', phone)
} catch (_) {}
},
/**
* 当本地 userInfo.phone 为空时,静默拉取 profile 并更新(用户可能在设置页或其他入口已绑定手机号)
*/
async _refreshUserInfoIfPhoneEmpty() {
try {
const userId = this.globalData.userInfo?.id
if (!userId) return
const res = await this.request({ url: `/api/miniprogram/user/profile?userId=${userId}`, silent: true })
const profile = res?.data
if (!profile) return
const phone = (profile.phone || '').trim()
if (!phone) return
const updated = { ...this.globalData.userInfo, phone }
if (profile.wechatId != null) updated.wechatId = profile.wechatId
this.globalData.userInfo = updated
wx.setStorageSync('userInfo', updated)
if (phone) wx.setStorageSync('user_phone', phone)
} catch (_) {
// 静默失败,不影响主流程
}
},
/**
* WSS 在线心跳(占位):登录后连接 ws发送 auth + 心跳,供管理端统计在线人数
* 容错任意异常均不向外抛出不影响登录、API 请求等核心功能
@@ -1026,6 +1074,13 @@ App({
wx.setStorageSync('userInfo', user)
wx.setStorageSync('token', res.data.token)
// 手机号登录后:若用户资料中手机号为空,从 profile 刷新并更新(后端已写入 DB可能响应中未带回
const phone = (user.phone || '').trim()
if (!phone) {
this._syncPhoneFromProfileAfterLogin(user.id)
} else {
wx.setStorageSync('user_phone', phone)
}
// 登录成功后绑定推荐码
const pendingRef = wx.getStorageSync('pendingReferralCode') || this.globalData.pendingReferralCode

View File

@@ -28,7 +28,8 @@
"pages/avatar-nickname/avatar-nickname",
"pages/gift-pay/detail",
"pages/gift-pay/list",
"pages/gift-pay/redemption-detail"
"pages/gift-pay/redemption-detail",
"pages/dev-login/dev-login"
],
"window": {
"backgroundTextStyle": "light",

View File

@@ -0,0 +1,80 @@
/**
* 卡若创业派对 - 开发登录页
* 临时:账户=手机号,密码可空,用于切换为对方账号调试
*/
const app = getApp()
const { checkAndExecute } = require('../../utils/ruleEngine.js')
Page({
data: {
statusBarHeight: 44,
account: '',
password: '',
loading: false
},
onLoad() {
this.setData({
statusBarHeight: app.globalData.statusBarHeight || 44
})
},
onAccountInput(e) {
this.setData({ account: (e.detail.value || '').trim() })
},
onPasswordInput(e) {
this.setData({ password: e.detail.value || '' })
},
goBack() {
app.goBackOrToHome()
},
async handleLogin() {
const { account, password, loading } = this.data
if (!account || loading) return
const phone = account.replace(/\s/g, '')
if (phone.length < 11) {
wx.showToast({ title: '请输入11位手机号', icon: 'none' })
return
}
this.setData({ loading: true })
try {
const res = await app.request('/api/miniprogram/dev/login-by-phone', {
method: 'POST',
data: { phone, password: password || '' }
})
if (res.success && res.data) {
const user = res.data.user
app.globalData.userInfo = user
app.globalData.isLoggedIn = true
app.globalData.purchasedSections = user.purchasedSections || []
app.globalData.hasFullBook = user.hasFullBook || false
app.globalData.isVip = user.isVip || false
app.globalData.vipExpireDate = user.vipExpireDate || ''
wx.setStorageSync('userInfo', user)
wx.setStorageSync('token', res.data.token)
const pendingRef = wx.getStorageSync('pendingReferralCode') || app.globalData.pendingReferralCode
if (pendingRef) {
app.bindReferralCode(pendingRef)
}
checkAndExecute('after_login', null)
setTimeout(() => app.checkVipContactRequiredAndGuide(), 1200)
wx.showToast({ title: '登录成功', icon: 'success' })
setTimeout(() => wx.switchTab({ url: '/pages/index/index' }), 800)
}
} catch (e) {
wx.showToast({ title: e.message || '登录失败', icon: 'none' })
} finally {
this.setData({ loading: false })
}
}
})

View File

@@ -0,0 +1,7 @@
{
"usingComponents": {
"icon": "/components/icon/icon"
},
"navigationStyle": "custom",
"navigationBarTitleText": "账户密码登录"
}

View File

@@ -0,0 +1,51 @@
<!--开发登录页 - 临时:账户=手机号,密码可空-->
<view class="page">
<view class="nav-bar" style="padding-top: {{statusBarHeight}}px;">
<view class="nav-back" bindtap="goBack">
<icon name="chevron-left" size="44" color="rgba(255,255,255,0.6)" customClass="back-icon"></icon>
</view>
<text class="nav-title">账户密码登录</text>
<view class="nav-placeholder"></view>
</view>
<view style="height: {{statusBarHeight + 44}}px;"></view>
<view class="content">
<view class="tip-banner">
<text class="tip-text">开发专用:输入对方手机号登录,密码可留空。仅开发环境可用。</text>
</view>
<view class="form-card">
<view class="form-item">
<text class="form-label">账户(手机号)</text>
<view class="form-input-wrap">
<input
class="form-input-inner"
type="number"
placeholder="请输入对方手机号"
placeholder-class="input-placeholder"
value="{{account}}"
bindinput="onAccountInput"
maxlength="11"
/>
</view>
</view>
<view class="form-item">
<text class="form-label">密码(可留空)</text>
<view class="form-input-wrap">
<input
class="form-input-inner"
type="text"
password="{{true}}"
placeholder="可选,留空即可"
placeholder-class="input-placeholder"
value="{{password}}"
bindinput="onPasswordInput"
/>
</view>
</view>
<view class="btn-primary {{!account || loading ? 'btn-disabled' : ''}}" bindtap="handleLogin">
{{loading ? '登录中...' : '登录'}}
</view>
</view>
</view>
</view>

View File

@@ -0,0 +1,23 @@
/* 开发登录页 */
.page { min-height: 100vh; background: #000; padding-bottom: 64rpx; }
.nav-bar { position: fixed; top: 0; left: 0; right: 0; z-index: 100; background: rgba(0,0,0,0.9); backdrop-filter: blur(40rpx); display: flex; align-items: center; justify-content: space-between; padding: 0 32rpx; height: 88rpx; }
.nav-back { width: 64rpx; height: 64rpx; background: #1c1c1e; border-radius: 50%; display: flex; align-items: center; justify-content: center; }
.back-icon { font-size: 40rpx; color: rgba(255,255,255,0.6); font-weight: 300; }
.nav-title { font-size: 34rpx; font-weight: 600; color: #fff; }
.nav-placeholder { width: 64rpx; }
.content { padding: 24rpx 16rpx; }
.tip-banner { background: rgba(255,165,0,0.1); border: 2rpx solid rgba(255,165,0,0.3); border-radius: 20rpx; padding: 20rpx 24rpx; margin-bottom: 24rpx; }
.tip-text { font-size: 24rpx; color: #FFA500; line-height: 1.5; }
.form-card { background: #1c1c1e; border-radius: 32rpx; padding: 32rpx; border: 2rpx solid rgba(0,206,209,0.2); }
.form-item { margin-bottom: 32rpx; }
.form-item:last-of-type { margin-bottom: 48rpx; }
.form-label { font-size: 28rpx; color: rgba(255,255,255,0.8); display: block; margin-bottom: 16rpx; }
.form-input-wrap { padding: 16rpx 24rpx; background: #1F2937; border: 2rpx solid rgba(255,255,255,0.1); border-radius: 24rpx; }
.form-input-inner { width: 100%; font-size: 28rpx; background: transparent; color: #fff; }
.input-placeholder { color: rgba(255,255,255,0.25); }
.btn-primary { padding: 32rpx; background: linear-gradient(135deg, #00CED1 0%, #20B2AA 100%); color: #000; font-size: 32rpx; font-weight: 600; text-align: center; border-radius: 28rpx; }
.btn-disabled { opacity: 0.5; }

View File

@@ -19,6 +19,7 @@ Page({
isSinglePageMode: false,
showLoginModal: false,
agreeProtocol: false,
showPrivacyModal: false,
// 创建态
isCreateMode: false,
giftQuantity: 1,
@@ -265,7 +266,7 @@ Page({
},
closeLoginModal() {
this.setData({ showLoginModal: false })
this.setData({ showLoginModal: false, showPrivacyModal: false })
},
toggleAgree() {
this.setData({ agreeProtocol: !this.data.agreeProtocol })
@@ -284,6 +285,13 @@ Page({
wx.showToast({ title: '登录失败', icon: 'none' })
}
},
handleAgreePrivacyForPhone() {
if (app._privacyResolve) {
app._privacyResolve({ buttonId: 'agree-privacy-btn', event: 'agree' })
app._privacyResolve = null
}
this.setData({ showPrivacyModal: false })
},
async handlePhoneLogin(e) {
if (!e.detail.code) return this.handleWechatLogin()
try {

View File

@@ -152,10 +152,14 @@
<view class="login-icon"><icon name="lock" size="80" color="#00CED1"></icon></view>
<text class="login-title">登录 卡若创业派对</text>
<text class="login-desc">登录后可免费领取并阅读</text>
<button class="btn-wechat {{agreeProtocol ? '' : 'btn-wechat-disabled'}}" bindtap="handleWechatLogin" disabled="{{!agreeProtocol}}">
<button id="agree-phone-btn" class="btn-wechat {{agreeProtocol ? '' : 'btn-wechat-disabled'}}" open-type="getPhoneNumber|agreePrivacyAuthorization" bindgetphonenumber="handlePhoneLogin" bindagreeprivacyauthorization="handleAgreePrivacyForPhone" disabled="{{!agreeProtocol}}">
<text class="btn-wechat-icon">微</text>
<text>微信快捷登录</text>
<text>手机号一键登录</text>
</button>
<view class="privacy-wechat-row" wx:if="{{showPrivacyModal}}">
<text class="privacy-wechat-desc">为获取手机号,请先同意《用户隐私保护指引》</text>
<button id="agree-privacy-btn" class="privacy-agree-btn" open-type="agreePrivacyAuthorization" bindagreeprivacyauthorization="handleAgreePrivacyForPhone">同意</button>
</view>
<view class="login-agree-row" catchtap="toggleAgree">
<view class="agree-checkbox {{agreeProtocol ? 'agree-checked' : ''}}"><icon wx:if="{{agreeProtocol}}" name="check" size="24" color="#34C759"></icon></view>
<text class="agree-text">我已阅读并同意</text>

View File

@@ -637,6 +637,10 @@
}
.btn-wechat-disabled { opacity: 0.5; }
.btn-wechat-icon { font-weight: 700; margin-right: 8rpx; }
.privacy-wechat-row { margin: 24rpx 0; padding: 24rpx; background: rgba(0,206,209,0.1); border-radius: 16rpx; }
.privacy-wechat-desc { display: block; font-size: 26rpx; color: rgba(255,255,255,0.8); margin-bottom: 16rpx; }
.privacy-agree-btn { width: 100%; padding: 20rpx; background: #07C160; color: #fff; font-size: 28rpx; border-radius: 16rpx; border: none; }
.privacy-agree-btn::after { border: none; }
.login-agree-row {
display: flex;
flex-wrap: wrap;

View File

@@ -61,6 +61,7 @@ Page({
// 链接卡若 - 留资弹窗
showLeadModal: false,
leadPhone: '',
showPrivacyModal: false,
// 展开状态(首页精选/最新)
featuredExpanded: false,
@@ -380,7 +381,7 @@ Page({
},
closeLeadModal() {
this.setData({ showLeadModal: false, leadPhone: '' })
this.setData({ showLeadModal: false, leadPhone: '', showPrivacyModal: false })
},
// 阻止弹窗内部点击事件冒泡到遮罩层
@@ -390,6 +391,15 @@ Page({
this.setData({ leadPhone: (e.detail.value || '').trim() })
},
// 微信隐私协议同意getPhoneNumber 需先同意)
onAgreePrivacyForLead() {
if (app._privacyResolve) {
app._privacyResolve({ buttonId: 'agree-privacy-btn', event: 'agree' })
app._privacyResolve = null
}
this.setData({ showPrivacyModal: false })
},
// 一键获取手机号(微信能力),成功后直接提交链接卡若
async onGetPhoneNumberForLead(e) {
if (e.detail.errMsg !== 'getPhoneNumber:ok') {

View File

@@ -161,7 +161,11 @@
<view class="lead-box" catchtap="stopPropagation">
<text class="lead-title">留下联系方式</text>
<text class="lead-desc">方便卡若与您联系</text>
<button class="lead-get-phone-btn" open-type="getPhoneNumber" bindgetphonenumber="onGetPhoneNumberForLead">一键获取手机号</button>
<button id="agree-lead-phone-btn" class="lead-get-phone-btn" open-type="getPhoneNumber|agreePrivacyAuthorization" bindgetphonenumber="onGetPhoneNumberForLead" bindagreeprivacyauthorization="onAgreePrivacyForLead">一键获取手机号</button>
<view class="privacy-wechat-row" wx:if="{{showPrivacyModal}}">
<text class="privacy-wechat-desc">为获取手机号,请先同意《用户隐私保护指引》</text>
<button id="agree-privacy-btn" class="privacy-agree-btn" open-type="agreePrivacyAuthorization" bindagreeprivacyauthorization="onAgreePrivacyForLead">同意</button>
</view>
<text class="lead-divider">或手动输入</text>
<view class="lead-input-wrap">
<input class="lead-input" placeholder="请输入手机号" type="number" maxlength="11" value="{{leadPhone}}" bindinput="onLeadPhoneInput"/>

View File

@@ -900,6 +900,10 @@
line-height: normal;
}
.lead-get-phone-btn::after { border: none; }
.privacy-wechat-row { margin: 24rpx 0; padding: 24rpx; background: rgba(0,206,209,0.1); border-radius: 16rpx; }
.privacy-wechat-desc { display: block; font-size: 26rpx; color: rgba(255,255,255,0.8); margin-bottom: 16rpx; }
.privacy-agree-btn { width: 100%; padding: 20rpx; background: #07C160; color: #fff; font-size: 28rpx; border-radius: 16rpx; border: none; }
.privacy-agree-btn::after { border: none; }
.lead-divider {
display: block;
font-size: 24rpx;

View File

@@ -63,6 +63,7 @@ Page({
isLoggingIn: false,
// 用户须主动勾选同意协议(审核要求:不得默认同意)
agreeProtocol: false,
showPrivacyModal: false,
// 修改昵称弹窗
showNicknameModal: false,
@@ -715,7 +716,7 @@ Page({
// 关闭登录弹窗
closeLoginModal() {
if (this.data.isLoggingIn) return
this.setData({ showLoginModal: false })
this.setData({ showLoginModal: false, showPrivacyModal: false })
},
// 微信登录(须已勾选同意协议,且做好错误处理避免审核报错)
@@ -742,6 +743,15 @@ Page({
}
},
// 微信隐私协议同意getPhoneNumber 需先同意)
handleAgreePrivacyForPhone() {
if (app._privacyResolve) {
app._privacyResolve({ buttonId: 'agree-privacy-btn', event: 'agree' })
app._privacyResolve = null
}
this.setData({ showPrivacyModal: false })
},
// 手机号登录(需要用户授权)
async handlePhoneLogin(e) {
// 检查是否有授权code

View File

@@ -16,7 +16,7 @@
<text wx:else class="guest-avatar-text">{{guestNickname[0] || '游'}}</text>
</view>
<text class="guest-name">{{guestNickname}}</text>
<view class="guest-login-btn" bindtap="showLogin">点击登录</view>
<view class="guest-login-btn" bindtap="showLogin">手机号一键登录</view>
</view>
<!-- 已登录:用户卡片(设计稿布局) -->
@@ -57,7 +57,7 @@
<text class="profile-stat-label">推荐好友</text>
</view>
<view class="profile-stat" wx:if="{{referralEnabled}}" bindtap="goToReferral">
<text class="profile-stat-val">{{earnings === '-' ? '--' : earnings}}</text>
<text class="profile-stat-val">{{pendingEarnings === '-' ? '--' : pendingEarnings}}</text>
<text class="profile-stat-label">我的收益</text>
</view>
<view class="profile-stat" wx:if="{{!auditMode}}" bindtap="handleMenuTap" data-id="wallet">
@@ -178,10 +178,14 @@
<view class="login-icon"><icon name="lock" size="80" color="#00CED1"></icon></view>
<text class="login-title">登录 卡若创业派对</text>
<text class="login-desc">登录后可购买章节、解锁更多内容</text>
<button class="btn-wechat {{agreeProtocol ? '' : 'btn-wechat-disabled'}}" bindtap="handleWechatLogin" disabled="{{isLoggingIn || !agreeProtocol}}">
<button id="agree-phone-btn" class="btn-wechat {{agreeProtocol ? '' : 'btn-wechat-disabled'}}" open-type="getPhoneNumber|agreePrivacyAuthorization" bindgetphonenumber="handlePhoneLogin" bindagreeprivacyauthorization="handleAgreePrivacyForPhone" disabled="{{isLoggingIn || !agreeProtocol}}">
<text class="btn-wechat-icon">微</text>
<text>{{isLoggingIn ? '登录中...' : '微信快捷登录'}}</text>
<text>{{isLoggingIn ? '登录中...' : '手机号一键登录'}}</text>
</button>
<view class="privacy-wechat-row" wx:if="{{showPrivacyModal}}">
<text class="privacy-wechat-desc">为获取手机号,请先同意《用户隐私保护指引》</text>
<button id="agree-privacy-btn" class="privacy-agree-btn" open-type="agreePrivacyAuthorization" bindagreeprivacyauthorization="handleAgreePrivacyForPhone">同意</button>
</view>
<view class="login-modal-cancel" bindtap="closeLoginModal">取消</view>
<view class="login-agree-row" catchtap="toggleAgree">
<view class="agree-checkbox {{agreeProtocol ? 'agree-checked' : ''}}"><icon wx:if="{{agreeProtocol}}" name="check" size="24" color="#34C759"></icon></view>

View File

@@ -225,6 +225,10 @@
.agree-text { color: rgba(255,255,255,0.6); }
.agree-link { color: #4FD1C5; text-decoration: underline; padding: 0 4rpx; }
.btn-wechat-disabled { opacity: 0.6; }
.privacy-wechat-row { margin: 24rpx 0; padding: 24rpx; background: rgba(0,206,209,0.1); border-radius: 16rpx; }
.privacy-wechat-desc { display: block; font-size: 26rpx; color: rgba(255,255,255,0.8); margin-bottom: 16rpx; }
.privacy-agree-btn { width: 100%; padding: 20rpx; background: #07C160; color: #fff; font-size: 28rpx; border-radius: 16rpx; border: none; }
.privacy-agree-btn::after { border: none; }
/* 头像弹窗 */
.avatar-modal .avatar-modal-title { display: block; font-size: 36rpx; font-weight: bold; color: #fff; text-align: center; margin-bottom: 16rpx; }

View File

@@ -75,6 +75,7 @@ Page({
giftRequestSn: '',
showLoginModal: false,
agreeProtocol: false,
showPrivacyModal: false,
showPosterModal: false,
isPaying: false,
isGeneratingPoster: false,
@@ -982,7 +983,7 @@ Page({
},
closeLoginModal() {
this.setData({ showLoginModal: false })
this.setData({ showLoginModal: false, showPrivacyModal: false })
},
toggleAgree() {
@@ -1018,6 +1019,16 @@ Page({
}
},
// 微信隐私协议同意getPhoneNumber 需先同意)
handleAgreePrivacyForPhone() {
const app = getApp()
if (app._privacyResolve) {
app._privacyResolve({ buttonId: 'agree-privacy-btn', event: 'agree' })
app._privacyResolve = null
}
this.setData({ showPrivacyModal: false })
},
// 【重构】手机号登录(标准流程)
async handlePhoneLogin(e) {
if (!e.detail.code) {

View File

@@ -131,7 +131,7 @@
<text class="paywall-desc">已阅读50%,登录后查看完整内容</text>
<view class="login-btn" bindtap="showLoginModal">
<text class="login-btn-text">立即登录</text>
<text class="login-btn-text">手机号一键登录</text>
</view>
</view>
@@ -341,11 +341,15 @@
<text class="login-title">登录 卡若创业派对</text>
<text class="login-desc">登录后可购买章节、解锁更多内容</text>
<button class="btn-wechat {{agreeProtocol ? '' : 'btn-wechat-disabled'}}" bindtap="handleWechatLogin" disabled="{{!agreeProtocol}}">
<button id="agree-phone-btn" class="btn-wechat {{agreeProtocol ? '' : 'btn-wechat-disabled'}}" open-type="getPhoneNumber|agreePrivacyAuthorization" bindgetphonenumber="handlePhoneLogin" bindagreeprivacyauthorization="handleAgreePrivacyForPhone" disabled="{{!agreeProtocol}}">
<text class="btn-wechat-icon">微</text>
<text>微信快捷登录</text>
<text>手机号一键登录</text>
</button>
<view class="privacy-wechat-row" wx:if="{{showPrivacyModal}}">
<text class="privacy-wechat-desc">为获取手机号,请先同意《用户隐私保护指引》</text>
<button id="agree-privacy-btn" class="privacy-agree-btn" open-type="agreePrivacyAuthorization" bindagreeprivacyauthorization="handleAgreePrivacyForPhone">同意</button>
</view>
<view class="login-agree-row" catchtap="toggleAgree">
<view class="agree-checkbox {{agreeProtocol ? 'agree-checked' : ''}}"><icon wx:if="{{agreeProtocol}}" name="check" size="24" color="#34C759"></icon></view>
<text class="agree-text">我已阅读并同意</text>

View File

@@ -1164,6 +1164,10 @@
padding: 0 4rpx;
}
.btn-wechat-disabled { opacity: 0.6; }
.privacy-wechat-row { margin: 24rpx 0; padding: 24rpx; background: rgba(0,206,209,0.1); border-radius: 16rpx; }
.privacy-wechat-desc { display: block; font-size: 26rpx; color: rgba(255,255,255,0.8); margin-bottom: 16rpx; }
.privacy-agree-btn { width: 100%; padding: 20rpx; background: #07C160; color: #fff; font-size: 28rpx; border-radius: 16rpx; border: none; }
.privacy-agree-btn::after { border: none; }
/* ===== 支付中加载 ===== */
.loading-box {

View File

@@ -30,7 +30,8 @@ Page({
// 绑定弹窗
showBindModal: false,
bindType: '', // phone | wechat | alipay
bindValue: ''
bindValue: '',
showPrivacyModal: false
},
onLoad() {
@@ -332,6 +333,15 @@ Page({
}
},
// 微信隐私协议同意getPhoneNumber 需先同意)
onAgreePrivacyForPhone() {
if (app._privacyResolve) {
app._privacyResolve({ buttonId: 'agree-privacy-btn', event: 'agree' })
app._privacyResolve = null
}
this.setData({ showPrivacyModal: false })
},
// 一键获取微信手机号button组件回调
async onGetPhoneNumber(e) {
console.log('[Settings] 获取手机号回调:', e.detail)
@@ -392,6 +402,11 @@ Page({
this.setData({ showBindModal: false })
},
// 跳转账户密码登录页(开发)
goToDevLogin() {
wx.navigateTo({ url: '/pages/dev-login/dev-login' })
},
// 打开切换账号弹窗(开发)
openSwitchAccountModal() {
this.setData({

View File

@@ -32,11 +32,15 @@
</view>
<view class="bind-right">
<icon wx:if="{{phoneNumber}}" name="check" size="36" color="#34C759" customClass="bind-check"></icon>
<button wx:else class="get-phone-btn" open-type="getPhoneNumber" bindgetphonenumber="onGetPhoneNumber">
<button wx:else id="agree-settings-phone-btn" class="get-phone-btn" open-type="getPhoneNumber|agreePrivacyAuthorization" bindgetphonenumber="onGetPhoneNumber" bindagreeprivacyauthorization="onAgreePrivacyForPhone">
一键获取
</button>
</view>
</view>
<view class="privacy-wechat-row" wx:if="{{showPrivacyModal}}">
<text class="privacy-wechat-desc">为获取手机号,请先同意《用户隐私保护指引》</text>
<button id="agree-privacy-btn" class="privacy-agree-btn" open-type="agreePrivacyAuthorization" bindagreeprivacyauthorization="onAgreePrivacyForPhone">同意</button>
</view>
<!-- 微信号 - 简化输入 -->
<view class="bind-item">
@@ -117,6 +121,13 @@
<text class="dev-switch-desc">输入 userId 切换为其他账号调试</text>
</view>
</view>
<view class="dev-switch-card" wx:if="{{isDevMode}}" bindtap="goToDevLogin">
<view class="dev-switch-inner">
<icon name="smartphone" size="40" color="#8e8e93" customClass="dev-switch-icon"></icon>
<text class="dev-switch-text">账户密码登录</text>
<text class="dev-switch-desc">输入对方手机号登录,密码可留空</text>
</view>
</view>
<view class="logout-btn" wx:if="{{isLoggedIn}}" bindtap="handleLogout">退出登录</view>
</view>

View File

@@ -49,6 +49,10 @@
line-height: normal;
}
.get-phone-btn::after { border: none; }
.privacy-wechat-row { margin: 24rpx 0; padding: 24rpx; background: rgba(0,206,209,0.1); border-radius: 16rpx; }
.privacy-wechat-desc { display: block; font-size: 26rpx; color: rgba(255,255,255,0.8); margin-bottom: 16rpx; }
.privacy-agree-btn { width: 100%; padding: 20rpx; background: #07C160; color: #fff; font-size: 28rpx; border-radius: 16rpx; border: none; }
.privacy-agree-btn::after { border: none; }
/* 自动提现卡片 */
.auto-withdraw-card { margin-top: 24rpx; }

View File

@@ -23,12 +23,19 @@
"condition": {
"miniprogram": {
"list": [
{
"name": "开发登录",
"pathName": "pages/dev-login/dev-login",
"query": "",
"scene": null,
"launchMode": "default"
},
{
"name": "pages/member-detail/member-detail",
"pathName": "pages/member-detail/member-detail",
"query": "id=ogpTW5cVMxd5afBBtXdvmeMO8aho",
"scene": null,
"launchMode": "default"
"launchMode": "default",
"scene": null
},
{
"name": "pages/my/my",