Browse Source

修复位置授权功能:添加requestLocationAuth、getUserLocation和reverseGeocode方法

pull/1/head
徐飞洋 2 months ago
parent
commit
e065ae6e58
  1. 404
      pages/index/index.js
  2. 41
      pages/index/index.wxml
  3. 14
      pages/index/index.wxss

404
pages/index/index.js

@ -814,6 +814,14 @@ Page({
// 查看商品详情
viewGoodsDetail: function(e) {
// 检查登录状态
if (this.data.needPhoneAuth) {
this.setData({
showOneKeyLoginModal: true
})
return;
}
const item = e.currentTarget.dataset.item
// 确保productId存在,优先使用id,其次使用productId
const productId = String(item.id || item.productId || '')
@ -1269,18 +1277,6 @@ Page({
}
}
});
} else {
wx.showModal({
title: '登录成功',
content: '欢迎使用鸡蛋贸易平台',
showCancel: false,
confirmText: '开始使用',
success(res) {
if (res.confirm) {
console.log('用户点击了开始使用');
}
}
});
}
// 用户登录成功,但已移除类型选择和跳转功能
@ -1952,62 +1948,384 @@ Page({
// 手机号授权处理
async onPhoneNumberResult(e) {
console.log('手机号授权结果:', e)
if (e.detail.errMsg === 'getPhoneNumber:ok') {
// 用户同意授权,获取加密数据
const phoneData = e.detail
wx.showLoading({ title: '获取手机号中...' })
// 首先检查用户是否拒绝授权
if (e.detail.errMsg !== 'getPhoneNumber:ok') {
console.log('用户拒绝授权手机号')
wx.showToast({
title: '您已拒绝授权,操作已取消',
icon: 'none'
})
// 直接返回,取消所有后续操作
return
}
wx.showLoading({
title: '登录中...',
mask: true
})
try {
// 引入API服务
const API = require('../../utils/api.js')
// 上传到服务器解密
const res = await API.uploadPhoneNumberData(phoneData)
// 1. 先执行微信登录获取code
const loginRes = await new Promise((resolve, reject) => {
wx.login({
success: resolve,
fail: reject
})
})
wx.hideLoading()
if (!loginRes.code) {
throw new Error('获取登录code失败')
}
console.log('获取登录code成功:', loginRes.code)
// 2. 使用code换取openid
const openidRes = await API.getOpenid(loginRes.code)
// 增强版响应处理逻辑,支持多种返回格式
let openid = null;
let userId = null;
let sessionKey = null;
// 优先从data字段获取数据
if (openidRes && openidRes.data && typeof openidRes.data === 'object') {
openid = openidRes.data.openid || openidRes.data.OpenID || null;
userId = openidRes.data.userId || openidRes.data.userid || null;
sessionKey = openidRes.data.session_key || openidRes.data.sessionKey || null;
}
// 如果data为空或不存在,尝试从响应对象直接获取
if (!openid && openidRes && typeof openidRes === 'object') {
console.warn('服务器返回格式可能不符合预期,data字段为空或不存在,但尝试从根对象提取信息:', openidRes);
openid = openidRes.openid || openidRes.OpenID || null;
userId = openidRes.userId || openidRes.userid || null;
sessionKey = openidRes.session_key || openidRes.sessionKey || null;
}
if (res.success && res.phoneNumber) {
console.log('获取手机号成功:', res.phoneNumber)
// 检查服务器状态信息
const isSuccess = openidRes && (openidRes.success === true || openidRes.code === 200);
// 保存手机号到用户信息
if (!openid) {
throw new Error('获取openid失败: ' + (openidRes && openidRes.message ? openidRes.message : '未知错误'))
}
// 存储openid和session_key
wx.setStorageSync('openid', openid)
if (sessionKey) {
wx.setStorageSync('sessionKey', sessionKey)
}
// 确保始终使用从服务器获取的正式用户ID,不再生成临时ID
if (userId) {
wx.setStorageSync('userId', userId)
} else {
const app = getApp();
if (app.globalData.userInfo && app.globalData.userInfo.userId) {
const serverUserId = String(app.globalData.userInfo.userId);
wx.setStorageSync('userId', serverUserId);
userId = serverUserId;
console.log('使用从全局获取的正式用户ID:', serverUserId);
} else {
console.warn('未找到有效的用户ID,请确保用户已授权登录');
}
}
console.log('获取openid成功并存储:', openid)
// 3. 上传手机号加密数据到服务器解密
const phoneData = {
...e.detail,
openid: openid,
sessionKey: sessionKey || ''
}
console.log('准备上传手机号加密数据到服务器')
const phoneRes = await API.uploadPhoneNumberData(phoneData)
// 改进手机号解密结果的处理逻辑
if (!phoneRes || (!phoneRes.success && !phoneRes.phoneNumber)) {
// 如果服务器返回格式不标准但包含手机号,也接受
if (!(phoneRes && phoneRes.phoneNumber)) {
throw new Error('获取手机号失败: ' + (phoneRes && phoneRes.message ? phoneRes.message : '未知错误'))
}
}
// 检查是否有手机号冲突
const hasPhoneConflict = phoneRes.phoneNumberConflict || false
const isNewPhone = phoneRes.isNewPhone || true
const phoneNumber = phoneRes.phoneNumber || null
console.log('手机号解密结果:', {
phoneNumber: phoneNumber,
hasPhoneConflict: hasPhoneConflict,
isNewPhone: isNewPhone
})
// 4. 获取用户微信名称和头像
let userProfile = null;
try {
userProfile = await new Promise((resolve, reject) => {
wx.getUserProfile({
desc: '用于完善会员资料',
success: resolve,
fail: reject
});
});
console.log('获取用户信息成功:', userProfile);
} catch (err) {
console.warn('获取用户信息失败:', err);
// 如果获取失败,使用默认值
}
// 5. 创建用户信息
const app = getApp()
const userInfo = app.globalData.userInfo || wx.getStorageSync('userInfo') || {}
userInfo.phoneNumber = res.phoneNumber
const existingUserInfo = app.globalData.userInfo || wx.getStorageSync('userInfo') || {}
const userInfo = {
// 优先使用最新获取的微信头像和昵称,如果没有获取到则使用本地存储的
name: (userProfile ? (userProfile.userInfo.name || userProfile.userInfo.nickName) : existingUserInfo.name) || '微信用户',
avatarUrl: (userProfile ? userProfile.userInfo.avatarUrl : existingUserInfo.avatarUrl) || 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0',
gender: (userProfile ? userProfile.userInfo.gender : existingUserInfo.gender) || 0,
country: (userProfile ? userProfile.userInfo.country : existingUserInfo.country) || '',
province: (userProfile ? userProfile.userInfo.province : existingUserInfo.province) || '',
city: (userProfile ? userProfile.userInfo.city : existingUserInfo.city) || '',
language: (userProfile ? userProfile.userInfo.language : existingUserInfo.language) || 'zh_CN',
phoneNumber: phoneNumber
}
// 6. 获取用户类型
const users = wx.getStorageSync('users') || {}
let currentUserType = users[userId] && users[userId].type ? users[userId].type : ''
// 如果没有用户类型,尝试从全局获取
if (!currentUserType) {
currentUserType = app.globalData.userType || ''
}
// 7. 保存用户信息并等待上传完成
console.log('开始保存用户信息并上传到服务器...')
await this.uploadUserInfoToServer(userInfo, userId, currentUserType)
console.log('用户信息保存并上传完成')
// 更新本地和全局用户信息
app.globalData.userInfo = userInfo
wx.setStorageSync('userInfo', userInfo)
// 获取userId
const userId = wx.getStorageSync('userId')
const users = wx.getStorageSync('users') || {}
const currentUserType = users[userId] && users[userId].type ? users[userId].type : ''
// 更新页面状态
this.setData({
needPhoneAuth: false,
userInfo: userInfo,
showOneKeyLoginModal: false
})
// 同时更新服务器用户信息,确保上传完成
console.log('开始更新服务器用户信息...')
if (!this.data.testMode) {
await this.uploadUserInfoToServer(userInfo, userId, currentUserType)
console.log('服务器用户信息更新完成')
} else {
console.log('测试模式下跳过服务器用户信息更新')
wx.hideLoading()
const that = this;
wx.showModal({
title: '登录成功',
content: '🥚 允许获取位置,为你优先展示附近新鲜鸡蛋供应商、自提门店及精准配送时效,无需手动填地址,位置信息仅用于优化购物体验,隐私有保障,放心开启~',
showCancel: true,
cancelText: '取消',
confirmText: '允许',
success(res) {
if (res.confirm) {
console.log('用户点击了允许');
that.requestLocationAuth();
} else if (res.cancel) {
console.log('用户点击了取消');
}
}
});
} catch (error) {
wx.hideLoading()
console.error('登录过程中发生错误:', error)
// 更具体的错误提示
let errorMsg = '登录失败,请重试'
if (error.message.includes('网络')) {
errorMsg = '网络连接失败,请检查网络后重试'
} else if (error.message.includes('服务器')) {
errorMsg = '服务器连接失败,请稍后重试'
} else if (error.message.includes('openid')) {
errorMsg = '获取登录信息失败,请重试'
} else if (error.message.includes('手机号')) {
errorMsg = '获取手机号失败,请重试'
}
wx.showToast({ title: '手机号绑定成功', icon: 'success' })
wx.showToast({
title: errorMsg,
icon: 'none',
duration: 3000
})
// 清除可能已经保存的不完整信息
try {
wx.removeStorageSync('openid')
wx.removeStorageSync('sessionKey')
wx.removeStorageSync('userId')
} catch (e) {
console.error('清除临时登录信息失败:', e)
}
}
},
// 上传用户信息到服务器
uploadUserInfoToServer(userInfo, userId, type) {
return new Promise((resolve, reject) => {
try {
const API = require('../../utils/api.js')
const openid = wx.getStorageSync('openid')
if (!userId || !openid) {
const error = new Error('缺少必要的用户信息');
console.error('用户信息上传失败:', error);
reject(error);
return;
}
const uploadData = {
userId: userId,
openid: openid,
name: userInfo.name,
avatarUrl: userInfo.avatarUrl,
phoneNumber: userInfo.phoneNumber,
type: type,
timestamp: Date.now()
}
API.uploadUserInfo(uploadData).then(res => {
console.log('用户信息上传成功:', res)
resolve(res);
}).catch(err => {
console.error('用户信息上传失败:', err)
reject(err);
})
} catch (error) {
console.error('上传用户信息时发生异常:', error);
reject(error);
}
});
},
// 请求位置授权
requestLocationAuth() {
const that = this;
wx.authorize({
scope: 'scope.userLocation',
success() {
that.setData({ hasLocationAuth: true });
that.getUserLocation();
},
fail() {
wx.showModal({
title: '需要位置授权',
content: '请在设置中开启位置授权',
showCancel: true,
cancelText: '取消',
confirmText: '去授权',
success: (res) => {
if (res.confirm) {
wx.openSetting({
success: (settingRes) => {
if (settingRes.authSetting['scope.userLocation']) {
that.setData({ hasLocationAuth: true });
that.getUserLocation();
} else {
console.error('获取手机号失败:', res)
wx.showToast({ title: '获取手机号失败', icon: 'none' })
that.setData({ hasLocationAuth: false });
wx.showToast({ title: '您已拒绝位置授权', icon: 'none' });
}
} catch (err) {
wx.hideLoading()
console.error('获取手机号失败:', err)
wx.showToast({ title: '获取手机号失败', icon: 'none' })
},
fail: () => {
that.setData({ hasLocationAuth: false });
wx.showToast({ title: '打开设置失败', icon: 'none' });
}
});
} else {
console.log('用户拒绝授权手机号')
that.setData({ hasLocationAuth: false });
}
}
});
}
});
},
// 获取用户当前位置
getUserLocation() {
const that = this;
wx.getSetting({
success(res) {
if (res.authSetting['scope.userLocation']) {
wx.showLoading({ title: '获取位置中...' });
wx.getLocation({
type: 'gcj02',
success(res) {
const latitude = res.latitude;
const longitude = res.longitude;
wx.setStorageSync('userLocation', { latitude, longitude });
let openid = wx.getStorageSync('openid');
if (!openid) {
const globalUserInfo = wx.getStorageSync('userInfo');
openid = globalUserInfo?.openid;
}
if (!openid) {
wx.hideLoading();
wx.showToast({ title: '位置上传失败,请先登录', icon: 'none' });
return;
}
that.reverseGeocode(latitude, longitude, openid);
},
fail() {
wx.hideLoading();
wx.showToast({ title: '获取位置失败', icon: 'none' });
}
});
}
}
});
},
// 逆地理编码
reverseGeocode(latitude, longitude, openid) {
const that = this;
wx.request({
url: `https://apis.map.qq.com/ws/geocoder/v1/?location=${latitude},${longitude}&key=OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77`,
success(res) {
wx.hideLoading();
if (res.data.status === 0) {
const address = res.data.result.address;
wx.setStorageSync('locationInfo', address);
const API = require('../../utils/api.js');
const locationUpdateData = {
openid: openid,
latitude: latitude,
longitude: longitude,
address: address
};
API.request('/api/user/update-location', 'POST', locationUpdateData)
.then(res => {
wx.showToast({ title: '位置更新成功', icon: 'success' });
}).catch(err => {
wx.showToast({ title: '位置上传失败', icon: 'none' });
});
} else {
wx.showToast({ title: '获取地址失败', icon: 'none' });
}
},
fail() {
wx.hideLoading();
wx.showToast({ title: '获取地址失败', icon: 'none' });
}
});
},

41
pages/index/index.wxml

@ -195,16 +195,9 @@
bindtap="onAdClick"
data-ad="ad_slot_1"
></image>
<view class="ad-badge">广告</view>
</view>
</view>
<!-- 无搜索结果提示 -->
<view wx:if="{{filteredGoods.length === 0 && !isLoading}}" class="empty-goods">
<text class="empty-icon">🔍</text>
<text class="empty-text">暂无相关商品</text>
<text class="empty-hint">试试调整搜索条件或地区筛选</text>
</view>
<!-- 正常商品列表 -->
<view
@ -261,7 +254,6 @@
bindtap="onAdClick"
data-ad="ad_slot_2"
></image>
<view class="ad-badge">广告</view>
</view>
</view>
@ -328,31 +320,30 @@
</view>
</scroll-view>
</view>
<!-- 未授权登录提示弹窗 -->
<view wx:if="{{showAuthModal}}" class="auth-modal-overlay">
<view class="auth-modal-container">
<view class="auth-modal-title">提示</view>
<view class="auth-modal-content">请先登录后再操作</view>
<view class="auth-modal-buttons">
<button class="auth-primary-button" bindtap="showOneKeyLogin">一键登录</button>
<button class="auth-cancel-button" bindtap="closeAuthModal">取消</button>
</view>
</view>
</view>
<!-- 一键登录弹窗 -->
<!-- 登录弹窗 -->
<view wx:if="{{showOneKeyLoginModal}}" class="auth-modal-overlay">
<view class="auth-modal-container">
<view class="auth-modal-title">授权登录</view>
<view class="auth-modal-content">请授权获取您的手机号用于登录</view>
<view class="auth-modal-content">授权您的手机号后才能查看商品详情</view>
<view class="auth-modal-buttons">
<button class="auth-primary-button" open-type="getPhoneNumber" bind:getphonenumber="onGetPhoneNumber">授权获取手机号</button>
<button class="auth-cancel-button" bindtap="closeOneKeyLoginModal">取消</button>
<button
class="auth-primary-button"
open-type="getPhoneNumber"
bindgetphonenumber="onPhoneNumberResult"
>
授权手机号
</button>
<button
class="auth-cancel-button"
bindtap="closeOneKeyLoginModal"
>
取消
</button>
</view>
</view>
</view>
<!-- 用户信息填写弹窗 -->
<view wx:if="{{showUserInfoForm}}" class="modal-overlay">
<view class="modal-container">

14
pages/index/index.wxss

@ -970,9 +970,9 @@ wx-button:not([size=mini]) {
.auth-modal-container {
background-color: #fff;
border-radius: 24rpx;
width: 85%;
max-width: 520rpx;
padding: 50rpx 40rpx;
width: 90%;
max-width: 600rpx;
padding: 50rpx 20rpx;
box-shadow: 0 12rpx 32rpx rgba(0, 0, 0, 0.18);
}
@ -1005,7 +1005,8 @@ wx-button:not([size=mini]) {
font-weight: 600;
line-height: 1.6;
border-radius: 12rpx;
padding: 24rpx 0;
padding: 30rpx 0;
width: 100%;
box-shadow: 0 4rpx 12rpx rgba(7, 193, 96, 0.3);
}
@ -1016,8 +1017,9 @@ wx-button:not([size=mini]) {
font-weight: 500;
line-height: 1.6;
border-radius: 12rpx;
padding: 24rpx 0;
border: 2rpx solid #e5e5e5;
padding: 30rpx 0;
width: 100%;
border: 4rpx solid #e5e5e5;
}
/* 头像选择样式 */

Loading…
Cancel
Save