const { request, getBaseUrl } = require('../../utils_new/request'); const util = require('../../utils/util'); Page({ data: { statusBarHeight: 20, navBarHeight: 44, totalNavHeight: 64, defaultAvatar: '/images/default-avatar.svg', loading: true, saving: false, uploading: false, genderRange: ['男', '女'], ageRanges: ['18-24岁', '25-35岁', '36-45岁', '46-55岁', '56岁以上'], isProfileCompleted: false, originalAvatar: '', avatarUploadTemp: '', form: { nickname: '', avatar: '', gender: 0, // 1: 男, 2: 女 age_range: '', region: '', phone: '' // 增加手机号显示 } }, onLoad() { const sys = wx.getSystemInfoSync(); const menu = wx.getMenuButtonBoundingClientRect(); const statusBarHeight = sys.statusBarHeight || 20; const navBarHeight = menu.height + (menu.top - statusBarHeight) * 2; this.setData({ statusBarHeight, navBarHeight, totalNavHeight: statusBarHeight + navBarHeight }); this.load(); }, onBack() { wx.navigateBack({ delta: 1 }); }, async load() { this.setData({ loading: true }); try { let profileData = { nickname: '', avatar: '', gender: 0, age_range: '', region: '', phone: '' }; let isProfileCompleted = false; try { const res = await request({ url: '/api/users/profile', method: 'GET' }); if (res.data && res.data.code === 0) { const data = res.data.data; profileData = { nickname: data.nickname || '', avatar: util.getFullImageUrl(data.avatar) || '', gender: Number(data.gender || 0), age_range: data.ageRange || data.age_range || '', region: data.region || '', phone: data.phone || '' }; isProfileCompleted = !!data.profile_completed; } } catch (err) { console.log('API load failed'); } this.setData({ form: profileData, isProfileCompleted, originalAvatar: profileData.avatar || '' }); } finally { this.setData({ loading: false }); } }, // 格式化图片地址,处理相对路径 formatImageUrl(url) { return util.getFullImageUrl(url); }, // 将完整URL转回相对路径 getRelativeUrl(url) { if (!url) return ''; if (url.startsWith('wxfile://') || url.startsWith('data:')) return ''; const baseUrl = getBaseUrl(); if (url.startsWith(baseUrl)) { return url.replace(baseUrl, ''); } try { if (url.startsWith('http://') || url.startsWith('https://')) { const parsed = new URL(url); const path = `${parsed.pathname}${parsed.search || ''}`; return path; } } catch (_) {} return url; }, onChooseAvatar(e) { if (e.detail.errMsg && e.detail.errMsg.indexOf('fail') !== -1) { console.error('头像选择失败:', e.detail.errMsg); // 如果是开发者工具的 Bug,提示用户重启 if (e.detail.errMsg.indexOf('not found') !== -1) { wx.showModal({ title: '上传提示', content: '微信开发者工具临时文件异常,请尝试重新点击或重启开发者工具。', showCancel: false }); } return; } const { avatarUrl } = e.detail; if (!avatarUrl) return; // 微信头像临时路径先显示,再上传 this.setData({ 'form.avatar': avatarUrl, avatarUploadTemp: avatarUrl }); this.uploadAvatar(avatarUrl); }, onNicknameInput(e) { this.setData({ 'form.nickname': e.detail.value }); }, onNicknameBlur(e) { this.setData({ 'form.nickname': e.detail.value }); }, onGenderChange(e) { const idx = Number(e.detail.value); const gender = idx + 1; // 0 -> 1 (男), 1 -> 2 (女) this.setData({ 'form.gender': gender }); }, onAgeRange(e) { const idx = Number(e.detail.value); const age_range = this.data.ageRanges[idx] || ''; this.setData({ 'form.age_range': age_range }); }, onRegion(e) { const regionArray = e.detail.value || []; const region = regionArray.join(' '); this.setData({ 'form.region': region, 'form.regionArray': regionArray }); }, uploadAvatar(filePath) { this.setData({ uploading: true }); const token = wx.getStorageSync('auth_token') || ''; const baseUrl = getBaseUrl(); // 获取设备ID const deviceId = wx.getStorageSync('deviceId') || wx.getStorageSync('user_id') || 'unknown'; wx.uploadFile({ url: `${baseUrl}/api/upload`, filePath, name: 'file', formData: { folder: 'avatars' }, header: { 'x-device-id': deviceId, ...(token ? { Authorization: `Bearer ${token}` } : {}) }, success: (res) => { try { const body = JSON.parse(res.data || '{}'); if (body.code === 0 && body.data?.url) { const fullUrl = this.formatImageUrl(body.data.url); this.setData({ 'form.avatar': fullUrl, avatarUploadTemp: '' }); wx.showToast({ title: '头像上传成功', icon: 'success' }); } else { wx.showToast({ title: body.message || '上传失败', icon: 'none' }); this.setData({ 'form.avatar': this.data.originalAvatar || '', avatarUploadTemp: '' }); } } catch (e) { wx.showToast({ title: '解析返回失败', icon: 'none' }); this.setData({ 'form.avatar': this.data.originalAvatar || '', avatarUploadTemp: '' }); } }, fail: (err) => { console.error('upload failed', err); wx.showToast({ title: '网络上传失败', icon: 'none' }); this.setData({ 'form.avatar': this.data.originalAvatar || '', avatarUploadTemp: '' }); }, complete: () => { this.setData({ uploading: false }); } }); }, onAvatarError() { this.setData({ 'form.avatar': this.data.defaultAvatar }); }, async save() { if (this.data.saving) return; if (this.data.uploading) { wx.showToast({ title: '头像上传中,请稍候', icon: 'none' }); return; } const form = this.data.form; const avatar = String(form.avatar || '').trim(); if (avatar.startsWith('wxfile://') || avatar.startsWith('data:')) { wx.showToast({ title: '头像尚未上传成功,请重新上传', icon: 'none' }); return; } // 验证完整信息 if (!form.avatar || form.avatar === this.data.defaultAvatar) { wx.showToast({ title: '请设置头像', icon: 'none' }); return; } if (!String(form.nickname || '').trim()) { wx.showToast({ title: '请输入昵称', icon: 'none' }); return; } if (form.gender !== 1 && form.gender !== 2) { wx.showToast({ title: '请选择性别', icon: 'none' }); return; } if (!form.age_range) { wx.showToast({ title: '请选择年龄段', icon: 'none' }); return; } if (!form.region) { wx.showToast({ title: '请选择所在地区', icon: 'none' }); return; } this.setData({ saving: true }); try { const payload = { nickname: String(form.nickname || '').trim(), avatar: this.getRelativeUrl(form.avatar), gender: Number(form.gender), age_range: form.age_range, ageRange: form.age_range, region: form.region, regionArray: Array.isArray(form.regionArray) ? form.regionArray : undefined }; const res = await request({ url: '/api/users/profile', method: 'PUT', data: payload }); const body = res.data || {}; const ok = (typeof body.code === 'number' && body.code === 0) || (typeof body.success === 'boolean' && body.success === true); if (!ok) throw new Error(body.message || body.error || '保存失败'); try { const rewardRes = await request({ url: '/api/love-points/profile-complete', method: 'POST', data: {} }); const rewardData = rewardRes.data || {}; const innerData = rewardData.data || {}; if (rewardData.success && (innerData.earned > 0 || innerData.alreadyClaimed)) { if (innerData.earned > 0) { wx.showToast({ title: rewardData.message || `获得 ${innerData.earned} 爱心值`, icon: 'success' }); } else { wx.showToast({ title: '保存成功', icon: 'success' }); } this.setData({ isProfileCompleted: true }); } else { wx.showToast({ title: '保存成功', icon: 'success' }); } } catch (_) { wx.showToast({ title: '保存成功', icon: 'success' }); } // CRITICAL: Refresh global user info to ensure avatar consistency const app = getApp(); if (app && app.refreshUserInfo) { app.refreshUserInfo(); } this.setData({ originalAvatar: form.avatar || '' }); setTimeout(() => wx.navigateBack({ delta: 1 }), 500); } catch (e) { wx.showToast({ title: e.message || '保存失败', icon: 'none' }); } finally { this.setData({ saving: false }); } } });