const app = getApp(); const util = require("../../utils/util"); Page({ data: { userInfo: null, ladderUser: null, currentStore: null, showQrcode: false, qrcodeImage: "", qrcodeLoading: false, // 完善资料弹框 showProfileModal: false, profileForm: { avatar: "", nickname: "", gender: 0, }, isEditMode: false, // true: 编辑模式,false: 完善模式(登录时) showGenderModal: false, registerGender: 0, // 活动公告(最近 10 条) announcements: [], }, normalizeLadderUser(ladderUser) { if (!ladderUser) return null; const matchCount = Number(ladderUser.matchCount || 0); const winCount = Number(ladderUser.winCount || 0); const loseCount = Math.max(matchCount - winCount, 0); const winRate = matchCount > 0 ? Math.round((winCount / matchCount) * 100) : 0; return Object.assign({}, ladderUser, { matchCount, winCount, loseCount, winRate, }); }, onLoad() { this.initData(); }, onShow() { // 检查门店是否切换 if (app.globalData.storeChanged) { app.globalData.storeChanged = false; this.refreshData(); } else { // 同步最新数据 this.setData({ userInfo: app.globalData.userInfo, ladderUser: this.normalizeLadderUser(app.globalData.ladderUser), currentStore: app.globalData.currentStore, }); this.fetchAnnouncements(); } }, async onPullDownRefresh() { try { await this.refreshData(); } finally { wx.stopPullDownRefresh(); } }, async initData() { // 先进行微信登录获取openid if (!app.globalData.wxLoginInfo) { try { await app.wxLogin(); } catch (e) { console.error("微信登录失败:", e); } } if (app.globalData.token) { await this.refreshData(); } }, async refreshData() { if (!app.globalData.token) return; try { const store = app.globalData.currentStore; // 传入当前门店 ID,获取该门店的积分和天梯信息 await app.getUserInfo(store?.storeId); // 有当前门店时,拉取该门店的天梯用户信息(确保战力数据与当前门店一致) if (store && store.storeId) { try { await app.getLadderUser(store.storeId); } catch (e) { console.error("获取天梯用户信息失败:", e); } } this.setData({ userInfo: app.globalData.userInfo, ladderUser: this.normalizeLadderUser(app.globalData.ladderUser), currentStore: app.globalData.currentStore, announcements: [], // 先清空,避免切换门店时短暂显示旧门店公告 }); await this.fetchAnnouncements(); } catch (e) { console.error("获取用户信息失败:", e); } }, // 获取当前门店的活动公告(最近 10 条) async fetchAnnouncements() { if (!app.globalData.token) return; const store = app.globalData.currentStore; if (!store || !store.storeId) return; try { const res = await app.request("/api/article", { limit: 10, store_id: store.storeId, }); const raw = res.data || []; const list = raw.map((a) => ({ id: a.id, title: a.title || "", isTop: !!a.isTop, timeText: a.createdAt ? util.formatDate(a.createdAt) : "", })); this.setData({ announcements: list }); } catch (e) { console.error("获取活动公告失败:", e); } }, // 获取手机号授权 async onGetPhoneNumber(e) { if (e.detail.errMsg !== "getPhoneNumber:ok") { wx.showToast({ title: "需要授权手机号才能登录", icon: "none" }); return; } try { wx.showLoading({ title: "登录中..." }); // 如果没有微信登录信息,先登录 if (!app.globalData.wxLoginInfo) { await app.wxLogin(); } const needGender = app.globalData.wxLoginInfo && app.globalData.wxLoginInfo.isNewUser; if ( needGender && !(this.data.registerGender === 1 || this.data.registerGender === 2) ) { this._pendingPhoneLogin = { encryptedData: e.detail.encryptedData, iv: e.detail.iv, }; wx.hideLoading(); this.setData({ showGenderModal: true }); return; } await this.doPhoneLogin( e.detail.encryptedData, e.detail.iv, needGender ? this.data.registerGender : undefined, ); // 获取门店信息 await app.ensureCurrentStore(); const userInfo = app.globalData.userInfo; this.setData({ userInfo: userInfo, ladderUser: this.normalizeLadderUser(app.globalData.ladderUser), currentStore: app.globalData.currentStore, }); await this.fetchAnnouncements(); // 检查是否需要完善资料(没有头像或昵称为默认值) const needProfile = !userInfo.avatar || userInfo.avatar === "" || !userInfo.nickname || userInfo.nickname === "新用户" || userInfo.nickname === ""; if (needProfile) { // 弹出完善资料弹框 this.setData({ showProfileModal: true, isEditMode: false, profileForm: { avatar: userInfo.avatar || "/images/avatar-default.svg", nickname: userInfo.nickname === "新用户" ? "" : userInfo.nickname || "", }, }); wx.showToast({ title: "登录成功,请完善资料", icon: "none" }); } else { wx.showToast({ title: "登录成功", icon: "success" }); } } catch (e) { console.error("登录失败:", e); wx.showToast({ title: e.message || "登录失败", icon: "none" }); } finally { wx.hideLoading(); } }, async doPhoneLogin(encryptedData, iv, gender) { const g = gender === 1 || gender === 2 ? gender : undefined; await app.phoneLogin(encryptedData, iv, g); this._pendingPhoneLogin = null; this.setData({ showGenderModal: false }); }, onSelectRegisterGender(e) { const gender = Number(e.currentTarget.dataset.gender); if (gender !== 1 && gender !== 2) return; this.setData({ registerGender: gender }); }, async onConfirmRegisterGender() { if (!(this.data.registerGender === 1 || this.data.registerGender === 2)) { wx.showToast({ title: "请选择性别", icon: "none" }); return; } const pending = this._pendingPhoneLogin; if (!pending) { this.setData({ showGenderModal: false }); return; } wx.showLoading({ title: "登录中..." }); try { await this.doPhoneLogin( pending.encryptedData, pending.iv, this.data.registerGender, ); await app.ensureCurrentStore(); const userInfo = app.globalData.userInfo; this.setData({ userInfo: userInfo, ladderUser: this.normalizeLadderUser(app.globalData.ladderUser), currentStore: app.globalData.currentStore, }); await this.fetchAnnouncements(); const needProfile = !userInfo.avatar || userInfo.avatar === "" || !userInfo.nickname || userInfo.nickname === "新用户" || userInfo.nickname === ""; if (needProfile) { this.setData({ showProfileModal: true, isEditMode: false, profileForm: { avatar: userInfo.avatar || "/images/avatar-default.svg", nickname: userInfo.nickname === "新用户" ? "" : userInfo.nickname || "", gender: userInfo.gender || 0, }, }); wx.showToast({ title: "登录成功,请完善资料", icon: "none" }); } else { wx.showToast({ title: "登录成功", icon: "success" }); } } catch (e) { console.error("登录失败:", e); wx.showToast({ title: e.message || "登录失败", icon: "none" }); } finally { wx.hideLoading(); } }, // 查看更多活动公告 goAnnouncementMore() { if (!app.globalData.token) { wx.showToast({ title: "请先登录", icon: "none" }); return; } wx.navigateTo({ url: "/pages/article/list/index", }); }, // 查看公告详情 goAnnouncementDetail(e) { const id = e.currentTarget.dataset.id; if (!id) return; wx.navigateTo({ url: `/pages/article/detail/index?id=${id}`, }); }, onCancelRegisterGender() { this._pendingPhoneLogin = null; this.setData({ showGenderModal: false, registerGender: 0 }); }, // 点击头像,打开编辑资料弹框 onTapAvatar() { if (!this.data.userInfo || !this.data.userInfo.phone) return; this.setData({ showProfileModal: true, isEditMode: true, profileForm: { avatar: this.data.userInfo.avatar || "/images/avatar-default.svg", nickname: this.data.userInfo.nickname || "", gender: this.data.userInfo.gender || 0, }, }); }, // 选择头像(新API:button open-type="chooseAvatar") async onChooseAvatarNew(e) { const avatarUrl = e.detail.avatarUrl; console.log('选择头像:', avatarUrl); // 检查是否是临时文件 if (avatarUrl && (avatarUrl.startsWith("wxfile://") || avatarUrl.startsWith("http://tmp") || avatarUrl.includes("/tmp/"))) { console.log('检测到临时头像,立即上传'); wx.showLoading({ title: "上传头像中..." }); try { const uploadedUrl = await this.uploadAvatar(avatarUrl); console.log('头像上传成功:', uploadedUrl); this.setData({ "profileForm.avatar": uploadedUrl, }); wx.hideLoading(); wx.showToast({ title: "头像上传成功", icon: "success", duration: 1500 }); } catch (uploadErr) { wx.hideLoading(); console.error("头像上传失败:", uploadErr); wx.showToast({ title: uploadErr.message || "头像上传失败", icon: "none", duration: 2000 }); // 上传失败,不设置头像 } } else { // 不是临时文件,直接使用 this.setData({ "profileForm.avatar": avatarUrl, }); } }, // 选择头像(使用 wx.chooseMedia) onChooseAvatar() { wx.chooseMedia({ count: 1, mediaType: ['image'], sourceType: ['album', 'camera'], sizeType: ['compressed'], success: (res) => { console.log('选择图片成功:', res); const tempFilePath = res.tempFiles[0].tempFilePath; this.setData({ "profileForm.avatar": tempFilePath, }); }, fail: (err) => { console.error('选择图片失败:', err); // 如果 chooseMedia 不支持,降级使用 chooseImage wx.chooseImage({ count: 1, sourceType: ['album', 'camera'], sizeType: ['compressed'], success: (res) => { console.log('选择图片成功(降级):', res); const tempFilePath = res.tempFilePaths[0]; this.setData({ "profileForm.avatar": tempFilePath, }); }, fail: (err) => { console.error('选择图片失败:', err); wx.showToast({ title: '选择图片失败', icon: 'none' }); } }); } }); }, // 输入昵称 onNicknameInput(e) { this.setData({ "profileForm.nickname": e.detail.value, }); }, onProfileGenderSelect(e) { const gender = Number(e.currentTarget.dataset.gender); if (gender !== 1 && gender !== 2) return; this.setData({ "profileForm.gender": gender, }); }, // 确认保存资料 async saveProfile() { const { avatar, nickname, gender } = this.data.profileForm; if (!nickname || nickname.trim() === "") { wx.showToast({ title: "请输入昵称", icon: "none" }); return; } wx.showLoading({ title: "保存中..." }); try { // 头像已经在选择时上传,这里直接使用 const avatarUrl = avatar; // 调用更新资料接口 const payload = { nickname: nickname.trim(), avatar: avatarUrl, }; if (gender === 1 || gender === 2) { payload.gender = gender; } console.log("保存资料请求:", payload); const res = await app.request("/api/user/profile", payload, "PUT"); // 更新本地数据(服务端已返回完整URL) const userInfo = Object.assign({}, this.data.userInfo, { nickname: (res.data && res.data.nickname) || nickname.trim(), avatar: (res.data && res.data.avatar) || avatarUrl, gender: (res.data && res.data.gender) || this.data.userInfo.gender || 0, }); app.globalData.userInfo = userInfo; this.setData({ userInfo: userInfo, showProfileModal: false, profileForm: { avatar: "", nickname: "", gender: 0 }, }); wx.hideLoading(); wx.showToast({ title: "保存成功", icon: "success" }); } catch (e) { wx.hideLoading(); console.error("保存资料失败:", e); wx.showToast({ title: e.message || "保存失败", icon: "none" }); } }, // 上传头像 async uploadAvatar(filePath) { return new Promise((resolve, reject) => { console.log('开始上传头像'); console.log('文件路径:', filePath); console.log('上传URL:', `${app.globalData.baseUrl}/api/upload/avatar`); console.log('Token:', app.globalData.token); if (!app.globalData.token) { reject(new Error('未登录,无法上传头像')); return; } wx.uploadFile({ url: `${app.globalData.baseUrl}/api/upload/avatar`, filePath: filePath, name: "file", header: { Authorization: `Bearer ${app.globalData.token}`, }, success: (res) => { try { console.log("上传头像响应状态:", res.statusCode); console.log("上传头像响应数据:", res.data); if (res.statusCode !== 200) { reject(new Error(`上传失败,状态码: ${res.statusCode}`)); return; } const data = JSON.parse(res.data); if (data.code === 0 && data.data && data.data.url) { console.log("头像上传成功:", data.data.url); resolve(data.data.url); } else { console.error("上传头像失败:", data); reject(new Error(data.message || "上传头像失败")); } } catch (e) { console.error("解析上传响应失败:", e); reject(new Error("上传头像失败")); } }, fail: (err) => { console.error("上传头像请求失败:", err); reject(new Error("上传头像失败,请检查网络")); }, }); }); }, // 关闭资料弹框 closeProfileModal() { // 如果是完善模式,提示用户 if (!this.data.isEditMode) { wx.showModal({ title: "提示", content: "完善资料后可以让好友更容易找到你,确定跳过?", confirmText: "跳过", cancelText: "继续完善", success: (res) => { if (res.confirm) { this.setData({ showProfileModal: false }); } }, }); } else { this.setData({ showProfileModal: false }); } }, async showMemberCode() { if (!this.data.userInfo || !this.data.userInfo.memberCode) return; this.setData({ showQrcode: true, qrcodeLoading: true, }); try { // 调用接口获取二维码 const res = await app.request("/api/user/qrcode"); if (res.data && res.data.qrcode) { this.setData({ qrcodeImage: res.data.qrcode, qrcodeLoading: false, }); } } catch (e) { console.error("获取二维码失败:", e); this.setData({ qrcodeLoading: false }); wx.showToast({ title: "获取二维码失败", icon: "none" }); } }, hideQrcode() { this.setData({ showQrcode: false, qrcodeImage: "", }); }, goTo(e) { const url = e.currentTarget.dataset.url; if (!app.globalData.token) { wx.showToast({ title: "请先登录", icon: "none" }); return; } wx.navigateTo({ url }); }, // 阻止事件冒泡 preventBubble() { // 空函数,仅用于阻止事件冒泡 }, });