全面优化:小程序 + 后台管理
## 小程序优化 1. 我的页面: - 头像点击获取微信头像(button open-type="chooseAvatar") - 昵称点击直接修改 - 去掉"创业伙伴"图标 - ID优先显示微信号 2. 设置页面: - 一键获取微信手机号 - 微信号/支付宝绑定优化 ## 后台管理优化 1. 内容管理: - 章节编辑增加"免费章节"开关 - 保存时自动去重标题(如#1.2重复) 2. 用户管理: - 修复绑定关系显示(优先查referral_bindings表)
This commit is contained in:
@@ -41,6 +41,7 @@ interface EditingSection {
|
|||||||
isNew?: boolean
|
isNew?: boolean
|
||||||
partId?: string
|
partId?: string
|
||||||
chapterId?: string
|
chapterId?: string
|
||||||
|
isFree?: boolean // 是否免费章节
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ContentPage() {
|
export default function ContentPage() {
|
||||||
@@ -129,14 +130,21 @@ export default function ContentPage() {
|
|||||||
|
|
||||||
setIsSaving(true)
|
setIsSaving(true)
|
||||||
try {
|
try {
|
||||||
|
// 自动去掉内容中的重复标题(如# 1.2 xxx)
|
||||||
|
let content = editingSection.content || ''
|
||||||
|
// 匹配 # 数字.数字 开头的标题行并去掉
|
||||||
|
const titlePattern = new RegExp(`^#\\s*${editingSection.id}\\s+.*$`, 'm')
|
||||||
|
content = content.replace(titlePattern, '').trim()
|
||||||
|
|
||||||
const res = await fetch('/api/db/book', {
|
const res = await fetch('/api/db/book', {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
id: editingSection.id,
|
id: editingSection.id,
|
||||||
title: editingSection.title,
|
title: editingSection.title,
|
||||||
price: editingSection.price,
|
price: editingSection.isFree ? 0 : editingSection.price,
|
||||||
content: editingSection.content,
|
content: content,
|
||||||
|
isFree: editingSection.isFree || editingSection.price === 0,
|
||||||
saveToFile: true, // 同时保存到文件系统
|
saveToFile: true, // 同时保存到文件系统
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -760,7 +768,7 @@ export default function ContentPage() {
|
|||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
{editingSection && (
|
{editingSection && (
|
||||||
<div className="space-y-4 py-4">
|
<div className="space-y-4 py-4">
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-3 gap-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label className="text-gray-300">章节ID</Label>
|
<Label className="text-gray-300">章节ID</Label>
|
||||||
<Input
|
<Input
|
||||||
@@ -774,10 +782,29 @@ export default function ContentPage() {
|
|||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
className="bg-[#0a1628] border-gray-700 text-white"
|
className="bg-[#0a1628] border-gray-700 text-white"
|
||||||
value={editingSection.price}
|
value={editingSection.isFree ? 0 : editingSection.price}
|
||||||
onChange={(e) => setEditingSection({ ...editingSection, price: Number(e.target.value) })}
|
onChange={(e) => setEditingSection({ ...editingSection, price: Number(e.target.value), isFree: Number(e.target.value) === 0 })}
|
||||||
|
disabled={editingSection.isFree}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label className="text-gray-300">免费章节</Label>
|
||||||
|
<div className="flex items-center h-10">
|
||||||
|
<label className="flex items-center cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={editingSection.isFree || editingSection.price === 0}
|
||||||
|
onChange={(e) => setEditingSection({
|
||||||
|
...editingSection,
|
||||||
|
isFree: e.target.checked,
|
||||||
|
price: e.target.checked ? 0 : 1
|
||||||
|
})}
|
||||||
|
className="w-5 h-5 rounded border-gray-600 bg-[#0a1628] text-[#38bdac] focus:ring-[#38bdac]"
|
||||||
|
/>
|
||||||
|
<span className="ml-2 text-gray-400 text-sm">设为免费</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label className="text-gray-300">章节标题</Label>
|
<Label className="text-gray-300">章节标题</Label>
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* 用户绑定关系API
|
* 用户绑定关系API
|
||||||
* 获取指定用户的所有绑定用户列表
|
* 获取指定用户的所有绑定用户列表
|
||||||
|
*
|
||||||
|
* 优先从referral_bindings表查询,同时兼容users表的referred_by字段
|
||||||
*/
|
*/
|
||||||
import { NextResponse } from 'next/server'
|
import { NextResponse } from 'next/server'
|
||||||
import { query } from '@/lib/db'
|
import { query } from '@/lib/db'
|
||||||
@@ -31,55 +33,87 @@ export async function GET(request: Request) {
|
|||||||
code = userRows[0].referral_code
|
code = userRows[0].referral_code
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!code) {
|
let referrals: any[] = []
|
||||||
return NextResponse.json({
|
|
||||||
success: true,
|
// 1. 首先从referral_bindings表查询绑定关系
|
||||||
referrals: [],
|
try {
|
||||||
stats: {
|
const bindingsReferrals = await query(`
|
||||||
total: 0,
|
SELECT
|
||||||
purchased: 0,
|
rb.id as binding_id,
|
||||||
pendingEarnings: 0,
|
rb.referee_id,
|
||||||
totalEarnings: 0
|
rb.status as binding_status,
|
||||||
}
|
rb.binding_date,
|
||||||
})
|
rb.expiry_date,
|
||||||
|
rb.commission_amount,
|
||||||
|
u.id, u.nickname, u.avatar, u.phone, u.open_id,
|
||||||
|
u.has_full_book, u.purchased_sections,
|
||||||
|
u.created_at, u.updated_at,
|
||||||
|
DATEDIFF(rb.expiry_date, NOW()) as days_remaining
|
||||||
|
FROM referral_bindings rb
|
||||||
|
JOIN users u ON rb.referee_id = u.id
|
||||||
|
WHERE rb.referrer_id = ?
|
||||||
|
ORDER BY rb.binding_date DESC
|
||||||
|
`, [userId]) as any[]
|
||||||
|
|
||||||
|
if (bindingsReferrals.length > 0) {
|
||||||
|
referrals = bindingsReferrals
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log('[Referrals] referral_bindings表查询失败,使用users表')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询通过该推广码绑定的所有用户
|
// 2. 如果referral_bindings表没有数据,再从users表查询
|
||||||
const referrals = await query(`
|
if (referrals.length === 0 && code) {
|
||||||
SELECT
|
referrals = await query(`
|
||||||
id, nickname, avatar, phone, open_id,
|
SELECT
|
||||||
has_full_book, purchased_sections,
|
id, nickname, avatar, phone, open_id,
|
||||||
created_at, updated_at
|
has_full_book, purchased_sections,
|
||||||
FROM users
|
created_at, updated_at,
|
||||||
WHERE referred_by = ?
|
NULL as binding_status,
|
||||||
ORDER BY created_at DESC
|
NULL as binding_date,
|
||||||
`, [code]) as any[]
|
NULL as expiry_date,
|
||||||
|
NULL as days_remaining,
|
||||||
|
NULL as commission_amount
|
||||||
|
FROM users
|
||||||
|
WHERE referred_by = ?
|
||||||
|
ORDER BY created_at DESC
|
||||||
|
`, [code]) as any[]
|
||||||
|
}
|
||||||
|
|
||||||
// 统计信息
|
// 统计信息
|
||||||
const purchasedCount = referrals.filter(r => r.has_full_book || (r.purchased_sections && r.purchased_sections !== '[]')).length
|
const purchasedCount = referrals.filter(r =>
|
||||||
|
r.has_full_book ||
|
||||||
|
r.binding_status === 'converted' ||
|
||||||
|
(r.purchased_sections && r.purchased_sections !== '[]')
|
||||||
|
).length
|
||||||
|
|
||||||
// 查询该用户的收益信息
|
// 查询该用户的收益信息
|
||||||
const earningsRows = await query(`
|
const earningsRows = await query(`
|
||||||
SELECT earnings, pending_earnings, withdrawn_earnings
|
SELECT earnings, pending_earnings, withdrawn_earnings
|
||||||
FROM users WHERE ${userId ? 'id = ?' : 'referral_code = ?'}
|
FROM users WHERE id = ?
|
||||||
`, [userId || code]) as any[]
|
`, [userId]) as any[]
|
||||||
|
|
||||||
const earnings = earningsRows[0] || { earnings: 0, pending_earnings: 0, withdrawn_earnings: 0 }
|
const earnings = earningsRows[0] || { earnings: 0, pending_earnings: 0, withdrawn_earnings: 0 }
|
||||||
|
|
||||||
// 格式化返回数据
|
// 格式化返回数据
|
||||||
const formattedReferrals = referrals.map(r => ({
|
const formattedReferrals = referrals.map(r => ({
|
||||||
id: r.id,
|
id: r.referee_id || r.id,
|
||||||
nickname: r.nickname || '微信用户',
|
nickname: r.nickname || '微信用户',
|
||||||
avatar: r.avatar,
|
avatar: r.avatar,
|
||||||
phone: r.phone ? r.phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') : null,
|
phone: r.phone ? r.phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') : null,
|
||||||
hasOpenId: !!r.open_id,
|
hasOpenId: !!r.open_id,
|
||||||
hasPurchased: r.has_full_book || (r.purchased_sections && r.purchased_sections !== '[]'),
|
hasPurchased: r.has_full_book || r.binding_status === 'converted' || (r.purchased_sections && r.purchased_sections !== '[]'),
|
||||||
hasFullBook: !!r.has_full_book,
|
hasFullBook: !!r.has_full_book,
|
||||||
purchasedSections: typeof r.purchased_sections === 'string'
|
purchasedSections: typeof r.purchased_sections === 'string'
|
||||||
? JSON.parse(r.purchased_sections || '[]').length
|
? JSON.parse(r.purchased_sections || '[]').length
|
||||||
: 0,
|
: 0,
|
||||||
createdAt: r.created_at,
|
createdAt: r.binding_date || r.created_at,
|
||||||
status: r.has_full_book ? 'vip' : (r.purchased_sections && r.purchased_sections !== '[]' ? 'paid' : 'free')
|
bindingStatus: r.binding_status || 'active',
|
||||||
|
daysRemaining: r.days_remaining,
|
||||||
|
commission: parseFloat(r.commission_amount) || 0,
|
||||||
|
status: r.binding_status === 'converted' ? 'converted'
|
||||||
|
: r.has_full_book ? 'vip'
|
||||||
|
: (r.purchased_sections && r.purchased_sections !== '[]' ? 'paid' : 'active')
|
||||||
}))
|
}))
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
|
|||||||
@@ -102,138 +102,41 @@ Page({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 编辑用户资料(头像和昵称)
|
// 微信头像选择回调(button open-type="chooseAvatar")
|
||||||
editProfile() {
|
async onChooseAvatar(e) {
|
||||||
wx.showActionSheet({
|
const avatarUrl = e.detail.avatarUrl
|
||||||
itemList: ['获取微信头像', '获取微信昵称', '从相册选择头像', '手动输入昵称'],
|
if (!avatarUrl) return
|
||||||
success: (res) => {
|
|
||||||
if (res.tapIndex === 0) {
|
wx.showLoading({ title: '更新中...', mask: true })
|
||||||
this.getWechatAvatar()
|
|
||||||
} else if (res.tapIndex === 1) {
|
try {
|
||||||
this.getWechatNickname()
|
// 更新本地显示
|
||||||
} else if (res.tapIndex === 2) {
|
const userInfo = this.data.userInfo
|
||||||
this.chooseAvatar()
|
userInfo.avatar = avatarUrl
|
||||||
} else if (res.tapIndex === 3) {
|
this.setData({ userInfo })
|
||||||
this.editNickname()
|
app.globalData.userInfo = userInfo
|
||||||
}
|
wx.setStorageSync('userInfo', userInfo)
|
||||||
}
|
|
||||||
})
|
// 同步到服务器
|
||||||
|
await app.request('/api/user/update', {
|
||||||
|
method: 'POST',
|
||||||
|
data: { userId: userInfo.id, avatar: avatarUrl }
|
||||||
|
})
|
||||||
|
|
||||||
|
wx.hideLoading()
|
||||||
|
wx.showToast({ title: '头像已更新', icon: 'success' })
|
||||||
|
} catch (e) {
|
||||||
|
wx.hideLoading()
|
||||||
|
wx.showToast({ title: '更新失败', icon: 'none' })
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 获取微信头像(原生能力)
|
// 点击昵称修改
|
||||||
getWechatAvatar() {
|
|
||||||
// 使用chooseAvatar API(微信原生头像选择)
|
|
||||||
wx.chooseAvatar({
|
|
||||||
success: async (res) => {
|
|
||||||
const avatarUrl = res.avatarUrl
|
|
||||||
wx.showLoading({ title: '更新中...', mask: true })
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 更新本地显示
|
|
||||||
const userInfo = this.data.userInfo
|
|
||||||
userInfo.avatar = avatarUrl
|
|
||||||
this.setData({ userInfo })
|
|
||||||
app.globalData.userInfo = userInfo
|
|
||||||
wx.setStorageSync('userInfo', userInfo)
|
|
||||||
|
|
||||||
// 同步到服务器
|
|
||||||
await app.request('/api/user/update', {
|
|
||||||
method: 'POST',
|
|
||||||
data: { userId: userInfo.id, avatar: avatarUrl }
|
|
||||||
})
|
|
||||||
|
|
||||||
wx.hideLoading()
|
|
||||||
wx.showToast({ title: '头像已更新', icon: 'success' })
|
|
||||||
} catch (e) {
|
|
||||||
wx.hideLoading()
|
|
||||||
wx.showToast({ title: '更新失败', icon: 'none' })
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fail: () => {
|
|
||||||
wx.showToast({ title: '取消选择', icon: 'none' })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
// 获取微信昵称(原生能力)
|
|
||||||
getWechatNickname() {
|
|
||||||
// 引导用户在弹窗中输入微信昵称
|
|
||||||
wx.showModal({
|
|
||||||
title: '获取微信昵称',
|
|
||||||
content: '请在下方输入您的微信昵称',
|
|
||||||
editable: true,
|
|
||||||
placeholderText: '请输入微信昵称',
|
|
||||||
success: async (res) => {
|
|
||||||
if (res.confirm && res.content) {
|
|
||||||
const nickname = res.content.trim()
|
|
||||||
if (nickname.length < 1 || nickname.length > 20) {
|
|
||||||
wx.showToast({ title: '昵称1-20个字符', icon: 'none' })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新本地
|
|
||||||
const userInfo = this.data.userInfo
|
|
||||||
userInfo.nickname = nickname
|
|
||||||
this.setData({ userInfo })
|
|
||||||
app.globalData.userInfo = userInfo
|
|
||||||
wx.setStorageSync('userInfo', userInfo)
|
|
||||||
|
|
||||||
// 同步到服务器
|
|
||||||
try {
|
|
||||||
await app.request('/api/user/update', {
|
|
||||||
method: 'POST',
|
|
||||||
data: { userId: userInfo.id, nickname }
|
|
||||||
})
|
|
||||||
} catch (e) {
|
|
||||||
console.log('同步昵称到服务器失败', e)
|
|
||||||
}
|
|
||||||
|
|
||||||
wx.showToast({ title: '昵称已更新', icon: 'success' })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
// 从相册选择头像
|
|
||||||
chooseAvatar() {
|
|
||||||
wx.chooseMedia({
|
|
||||||
count: 1,
|
|
||||||
mediaType: ['image'],
|
|
||||||
sourceType: ['album', 'camera'],
|
|
||||||
success: async (res) => {
|
|
||||||
const tempFilePath = res.tempFiles[0].tempFilePath
|
|
||||||
wx.showLoading({ title: '上传中...', mask: true })
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 更新本地显示
|
|
||||||
const userInfo = this.data.userInfo
|
|
||||||
userInfo.avatar = tempFilePath
|
|
||||||
this.setData({ userInfo })
|
|
||||||
app.globalData.userInfo = userInfo
|
|
||||||
wx.setStorageSync('userInfo', userInfo)
|
|
||||||
|
|
||||||
// 同步到服务器
|
|
||||||
await app.request('/api/user/update', {
|
|
||||||
method: 'POST',
|
|
||||||
data: { userId: userInfo.id, avatar: tempFilePath }
|
|
||||||
})
|
|
||||||
|
|
||||||
wx.hideLoading()
|
|
||||||
wx.showToast({ title: '头像已更新', icon: 'success' })
|
|
||||||
} catch (e) {
|
|
||||||
wx.hideLoading()
|
|
||||||
wx.showToast({ title: '上传失败', icon: 'none' })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
// 手动输入昵称
|
|
||||||
editNickname() {
|
editNickname() {
|
||||||
wx.showModal({
|
wx.showModal({
|
||||||
title: '修改昵称',
|
title: '修改昵称',
|
||||||
editable: true,
|
editable: true,
|
||||||
placeholderText: '请输入新昵称',
|
placeholderText: '请输入昵称',
|
||||||
success: async (res) => {
|
success: async (res) => {
|
||||||
if (res.confirm && res.content) {
|
if (res.confirm && res.content) {
|
||||||
const newNickname = res.content.trim()
|
const newNickname = res.content.trim()
|
||||||
|
|||||||
@@ -27,8 +27,8 @@
|
|||||||
<!-- 用户卡片 - 已登录状态 -->
|
<!-- 用户卡片 - 已登录状态 -->
|
||||||
<view class="user-card card-gradient" wx:else>
|
<view class="user-card card-gradient" wx:else>
|
||||||
<view class="user-header-row">
|
<view class="user-header-row">
|
||||||
<!-- 头像可点击修改 -->
|
<!-- 头像点击获取微信头像 -->
|
||||||
<view class="avatar-wrapper" bindtap="editProfile">
|
<button class="avatar-btn" open-type="chooseAvatar" bindchooseavatar="onChooseAvatar">
|
||||||
<view class="avatar">
|
<view class="avatar">
|
||||||
<image class="avatar-img" wx:if="{{userInfo.avatar}}" src="{{userInfo.avatar}}" mode="aspectFill"/>
|
<image class="avatar-img" wx:if="{{userInfo.avatar}}" src="{{userInfo.avatar}}" mode="aspectFill"/>
|
||||||
<text class="avatar-text" wx:else>{{userInfo.nickname[0] || '微'}}</text>
|
<text class="avatar-text" wx:else>{{userInfo.nickname[0] || '微'}}</text>
|
||||||
@@ -36,19 +36,16 @@
|
|||||||
<view class="avatar-edit-hint">
|
<view class="avatar-edit-hint">
|
||||||
<text class="edit-icon">✎</text>
|
<text class="edit-icon">✎</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</button>
|
||||||
|
|
||||||
<!-- 用户信息 -->
|
<!-- 用户信息 - 点击昵称修改 -->
|
||||||
<view class="user-info-block">
|
<view class="user-info-block">
|
||||||
<view class="user-name-row">
|
<view class="user-name-row" bindtap="editNickname">
|
||||||
<text class="user-name">{{userInfo.nickname || '微信用户'}}</text>
|
<text class="user-name">{{userInfo.nickname || '微信用户'}}</text>
|
||||||
<!-- 创业伙伴标签 -->
|
<text class="edit-name-icon">✎</text>
|
||||||
<view class="user-badge-small">
|
|
||||||
<text class="badge-star">⭐</text>
|
|
||||||
<text class="badge-label">创业伙伴</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
<text class="user-id">ID: {{userIdShort}}</text>
|
<text class="user-wechat" wx:if="{{userInfo.wechatId}}">微信: {{userInfo.wechatId}}</text>
|
||||||
|
<text class="user-id" wx:else>ID: {{userIdShort}}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,20 @@
|
|||||||
margin-bottom: 36rpx;
|
margin-bottom: 36rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 头像按钮样式 */
|
||||||
|
.avatar-btn {
|
||||||
|
position: relative;
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
.avatar-btn::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
.avatar-wrapper {
|
.avatar-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
@@ -146,6 +160,18 @@
|
|||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.edit-name-icon {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: rgba(255,255,255,0.4);
|
||||||
|
margin-left: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-wechat {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #00CED1;
|
||||||
|
margin-top: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
.user-badge-small {
|
.user-badge-small {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -206,8 +206,10 @@ Page({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 获取微信手机号(需要button组件配合)
|
// 一键获取微信手机号(button组件回调)
|
||||||
async getPhoneNumber(e) {
|
async onGetPhoneNumber(e) {
|
||||||
|
console.log('[Settings] 获取手机号回调:', e.detail)
|
||||||
|
|
||||||
if (e.detail.errMsg !== 'getPhoneNumber:ok') {
|
if (e.detail.errMsg !== 'getPhoneNumber:ok') {
|
||||||
wx.showToast({ title: '授权失败', icon: 'none' })
|
wx.showToast({ title: '授权失败', icon: 'none' })
|
||||||
return
|
return
|
||||||
@@ -217,30 +219,44 @@ Page({
|
|||||||
// 需要将code发送到服务器解密获取手机号
|
// 需要将code发送到服务器解密获取手机号
|
||||||
const code = e.detail.code
|
const code = e.detail.code
|
||||||
if (!code) {
|
if (!code) {
|
||||||
wx.showToast({ title: '获取失败,请手动输入', icon: 'none' })
|
// 如果没有code,弹出手动输入
|
||||||
|
this.bindPhone()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wx.showLoading({ title: '获取中...', mask: true })
|
||||||
|
|
||||||
// 调用服务器解密手机号
|
// 调用服务器解密手机号
|
||||||
const res = await app.request('/api/wechat/phone', {
|
const res = await app.request('/api/miniprogram/phone', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: { code }
|
data: { code }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
wx.hideLoading()
|
||||||
|
|
||||||
if (res.success && res.phoneNumber) {
|
if (res.success && res.phoneNumber) {
|
||||||
wx.setStorageSync('user_phone', res.phoneNumber)
|
wx.setStorageSync('user_phone', res.phoneNumber)
|
||||||
this.setData({ phoneNumber: res.phoneNumber })
|
this.setData({ phoneNumber: res.phoneNumber })
|
||||||
|
|
||||||
|
// 更新用户信息
|
||||||
|
if (app.globalData.userInfo) {
|
||||||
|
app.globalData.userInfo.phone = res.phoneNumber
|
||||||
|
wx.setStorageSync('userInfo', app.globalData.userInfo)
|
||||||
|
}
|
||||||
|
|
||||||
// 同步到服务器
|
// 同步到服务器
|
||||||
this.syncProfileToServer()
|
this.syncProfileToServer()
|
||||||
|
|
||||||
wx.showToast({ title: '手机号绑定成功', icon: 'success' })
|
wx.showToast({ title: '手机号绑定成功', icon: 'success' })
|
||||||
} else {
|
} else {
|
||||||
wx.showToast({ title: '获取失败,请手动输入', icon: 'none' })
|
// 获取失败,弹出手动输入
|
||||||
|
this.bindPhone()
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
wx.hideLoading()
|
||||||
console.log('[Settings] 获取手机号失败:', e)
|
console.log('[Settings] 获取手机号失败:', e)
|
||||||
wx.showToast({ title: '获取失败,请手动输入', icon: 'none' })
|
// 获取失败,弹出手动输入
|
||||||
|
this.bindPhone()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="bind-list">
|
<view class="bind-list">
|
||||||
<!-- 手机号 -->
|
<!-- 手机号 - 使用微信一键获取 -->
|
||||||
<view class="bind-item">
|
<view class="bind-item">
|
||||||
<view class="bind-left">
|
<view class="bind-left">
|
||||||
<view class="bind-icon phone-icon">📱</view>
|
<view class="bind-icon phone-icon">📱</view>
|
||||||
@@ -32,12 +32,14 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="bind-right">
|
<view class="bind-right">
|
||||||
<text class="bind-check" wx:if="{{phoneNumber}}">✓</text>
|
<text class="bind-check" wx:if="{{phoneNumber}}">✓</text>
|
||||||
<text class="bind-btn" wx:else bindtap="bindPhone">去绑定</text>
|
<button wx:else class="get-phone-btn" open-type="getPhoneNumber" bindgetphonenumber="onGetPhoneNumber">
|
||||||
|
一键获取
|
||||||
|
</button>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 微信号 -->
|
<!-- 微信号 -->
|
||||||
<view class="bind-item">
|
<view class="bind-item" bindtap="bindWechat">
|
||||||
<view class="bind-left">
|
<view class="bind-left">
|
||||||
<view class="bind-icon wechat-icon">💬</view>
|
<view class="bind-icon wechat-icon">💬</view>
|
||||||
<view class="bind-info">
|
<view class="bind-info">
|
||||||
@@ -47,12 +49,12 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="bind-right">
|
<view class="bind-right">
|
||||||
<text class="bind-check" wx:if="{{wechatId}}">✓</text>
|
<text class="bind-check" wx:if="{{wechatId}}">✓</text>
|
||||||
<text class="bind-btn" wx:else bindtap="bindWechat">去绑定</text>
|
<text class="bind-btn" wx:else>去绑定</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 支付宝 -->
|
<!-- 支付宝 -->
|
||||||
<view class="bind-item">
|
<view class="bind-item" bindtap="bindAlipay">
|
||||||
<view class="bind-left">
|
<view class="bind-left">
|
||||||
<view class="bind-icon alipay-icon">💳</view>
|
<view class="bind-icon alipay-icon">💳</view>
|
||||||
<view class="bind-info">
|
<view class="bind-info">
|
||||||
@@ -62,7 +64,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="bind-right">
|
<view class="bind-right">
|
||||||
<text class="bind-check" wx:if="{{alipayAccount}}">✓</text>
|
<text class="bind-check" wx:if="{{alipayAccount}}">✓</text>
|
||||||
<text class="bind-btn" wx:else bindtap="bindAlipay">去绑定</text>
|
<text class="bind-btn" wx:else>去绑定</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -32,6 +32,18 @@
|
|||||||
.bind-check { color: #00CED1; font-size: 32rpx; }
|
.bind-check { color: #00CED1; font-size: 32rpx; }
|
||||||
.bind-btn { color: #00CED1; font-size: 26rpx; }
|
.bind-btn { color: #00CED1; font-size: 26rpx; }
|
||||||
|
|
||||||
|
/* 一键获取手机号按钮 */
|
||||||
|
.get-phone-btn {
|
||||||
|
padding: 12rpx 24rpx;
|
||||||
|
background: rgba(0,206,209,0.2);
|
||||||
|
border: 2rpx solid rgba(0,206,209,0.3);
|
||||||
|
border-radius: 16rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #00CED1;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
.get-phone-btn::after { border: none; }
|
||||||
|
|
||||||
/* 提现提示 */
|
/* 提现提示 */
|
||||||
.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-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; }
|
.tip-text { font-size: 24rpx; color: #FFA500; line-height: 1.5; }
|
||||||
|
|||||||
Reference in New Issue
Block a user