const { getLayout } = require('../../utils/layout'); // pages/settings/settings.js const { api, getImageUrl, API_BASE, uploadFileCompat } = require('../../utils/request'); const { requestSubscribe, getSubscribeStatus, isTemplateConfigured, subscribeErrorMessage } = require('../../utils/subscribe'); const { guardStorageSpace } = require('../../utils/storage-guard'); Page({ onResize: function() { this.setData(getLayout()); }, data: { smokingVisible:true, smokingKnown:false, smokingSaving:false, smokingError:false, showBgModal: false, bgPreview: '', bgFilePath: '', hasPartner: false, bindingKnown: false, bindingError:false, // 解绑状态 unbindStatus: '', // '' / 'pending' / 'agreed' / 'rejected' / 'cancelled' / 'expired' unbindIsRequester: false, // 当前用户是否是发起方 unbindRequesterName: '', // 发起方昵称 unbindRemaining: 0, // 剩余秒数 // 消息通知设置 showSubscribeModal: false, subscribeStatus: {}, notifyAvailable: typeof isTemplateConfigured === 'function' && isTemplateConfigured('notify'), subscribeItems: [], subscribeLoading: false, // 我们past showAboutModal: false, // 联系我们 showContactModal: false, }, onLoad: function() { this.setData(getLayout());}, onPullDownRefresh: function() { wx.stopPullDownRefresh(); }, onShow: async function() { this.loadSmokingPreference(); this.setData({ bindingKnown: false, bindingError:false }); try { var info = await api.coupleInfo(); var hasPartner = !!(info && !info.not_bound && info.id); this.setData({ hasPartner: hasPartner, bindingKnown: true }); if (hasPartner) { wx.setStorageSync('coupleId', info.id); this.loadUnbindStatus(); } else { wx.removeStorageSync('coupleId'); this.setData({ unbindStatus: '', unbindIsRequester: false, unbindRequesterName: '' }); } } catch (e) { this.setData({bindingError:true}); console.error('获取绑定状态失败', e); } }, loadSmokingPreference: async function() { try { const auth=await api.checkAuth(); this.setData({smokingVisible:Number(auth.user.smoking_card_visible)!==0,smokingKnown:true,smokingError:false}); } catch(error) { this.setData({smokingError:true}); } }, toggleSmoking: async function(e) { if (this.data.smokingSaving || !this.data.smokingKnown) return; const previous=this.data.smokingVisible; this.setData({smokingSaving:true}); try { const result=await api.smokingCardVisible({visible:e.detail.value?1:0}); this.setData({smokingVisible:Number(result.card_visible)===1}); } catch(error) { this.setData({smokingVisible:previous}); wx.showToast({title:error.error||'保存失败,请重试',icon:'none'}); } finally { this.setData({smokingSaving:false}); } }, goBind: function() { getApp().globalData.openProfileBind = true; wx.switchTab({ url: '/pages/profile/profile' }); }, deleteAccount: async function() { if(this._deletingAccount)return; if (this.data.hasPartner) { wx.showModal({title:'暂无法注销',content:'请先完成情侣解绑后再注销账号;处于解绑申请或72小时冷静期内,也需要等待解绑完成。',showCancel:false,confirmText:'知道了'}); return; } this._deletingAccount=true; try { const preview=await api.accountDeletionPreview(); const counts=preview.summary.counts; const text='已上传文件 '+counts.files+' 个,相册 '+counts.albums+' 个,照片 '+counts.photos+' 张,日记 '+counts.diaries+' 篇,记忆日 '+counts.timeline+' 条,打卡 '+counts.checkins+' 条,抽烟记录 '+counts.smoking+' 条,生理期日记录 '+counts.period+' 条。'; const labels={past_song:'歌曲',past_diary_comment:'评论',past_period_record:'生理期周期',past_period_sex_record:'亲密记录',past_storage_order:'订单',past_subscribe_template:'消息订阅'}; const more=Object.keys(labels).map(key=>labels[key]+' '+((preview.summary.record_counts||{})[key]||0)+' 条').join(','); const confirm=options=>new Promise(resolve=>wx.showModal({...options,success:r=>resolve(r.confirm),fail:()=>resolve(false)})); if(!await confirm({title:'注销账号前,请确认',content:text+' 其他数据:'+more+'。注销后,账号、所有内容及文件关联会被删除,无法恢复;剩余空间权益将失效。',confirmText:'继续注销',confirmColor:'#B74768'}))return; if(!await confirm({title:'最后一次确认',content:'确定永久注销并删除全部数据?独占文件将从存储中清理;与其他用户重复的物理文件只移除你的关联,不会删除他人的内容。',confirmText:'确认注销',confirmColor:'#B74768'}))return; wx.showLoading({title:'正在注销',mask:true}); await api.accountDelete({confirmed:true,confirmation_text:'注销并删除全部数据',confirmation_token:preview.confirmation_token}); getApp().finishAccountDeletion(); wx.reLaunch({url:'/pages/index/index'}); } catch(error) {wx.showToast({title:error.error||'注销失败,请稍后重试',icon:'none',duration:3000});} finally {wx.hideLoading();this._deletingAccount=false;} }, // 加载解绑状态 loadUnbindStatus: function() { var self = this; api.unbindStatus().then(function(res) { if (res && res.status && res.status !== 'none') { self.setData({ unbindStatus: res.status, unbindIsRequester: !!res.is_requester, unbindRequesterName: res.requester_name || '对方', unbindRemaining: res.remaining_seconds || 0 }); } else { self.setData({ unbindStatus: '', unbindIsRequester: false, unbindRequesterName: '' }); } }).catch(function() {}); }, noop: function() {}, // ===== 消息通知管理(按场景独立授权) ===== showSubscribeModal: async function() { this.setData({ showSubscribeModal: true, subscribeLoading: true }); try { // forceRefresh=true 确保从后端获取最新状态 const status = await getSubscribeStatus(true); this.setData({ subscribeStatus: status, subscribeChecked: !!status['notify'], subscribeLoading: false }); } catch (e) { this.setData({ subscribeLoading: false }); } }, hideSubscribeModal: function() { this.setData({ showSubscribeModal: false }); }, // ===== 我们past ===== showAboutModal: function() { this.setData({ showAboutModal: true }); }, hideAboutModal: function() { this.setData({ showAboutModal: false }); }, openPrivacyContract: function() { if (typeof wx.openPrivacyContract !== 'function') { wx.showToast({ title: '请升级微信后查看隐私协议', icon: 'none' }); return; } wx.openPrivacyContract({ fail: function() { wx.showToast({ title: '隐私协议暂时无法打开,请稍后重试', icon: 'none' }); } }); }, // ===== 联系我们 ===== showContactModal: function() { this.setData({ showContactModal: true }); }, hideContactModal: function() { this.setData({ showContactModal: false }); }, toggleSubscribe: async function(e) { const type = 'notify'; if (typeof isTemplateConfigured === 'function' && !isTemplateConfigured(type)) { wx.showToast({title:'该提醒暂未配置模板',icon:'none'}); return; } const field = 'subscribeChecked'; const current = this.data[field]; // 防止重复点击 if (this._subscribing) return; this._subscribing = true; if (current) { // 取消订阅 try { await api.unsubscribeTemplate({ template_type: type }); this.setData({ [field]: false }); wx.setStorageSync('subscribed_' + type, false); wx.showToast({ title: '已关闭通知', icon: 'success' }); } catch (e) { wx.showToast({ title: '操作失败', icon: 'none' }); } } else { // 请求订阅授权 try { const results = await requestSubscribe(type); if (results[type]) { this.setData({ [field]: true }); wx.setStorageSync('subscribed_' + type, true); wx.showToast({ title: '已开启通知', icon: 'success' }); } else { wx.showToast({ title: '订阅被拒绝,可在设置中重新开启', icon: 'none' }); } } catch (e) { wx.showModal({title:'无法订阅提醒',content:subscribeErrorMessage(e),showCancel:false}); } } this._subscribing = false; }, renewSubscribe: async function(e) { const type = 'notify'; const field = 'subscribeChecked'; if (this._subscribing) return; this._subscribing = true; try { const results = await requestSubscribe(type); if (results[type]) { this.setData({ [field]: true }); wx.showToast({ title: '已订阅一次提醒', icon: 'success' }); } else { wx.showToast({ title: '本次未授权提醒', icon: 'none' }); } } catch (e) { wx.showModal({title:'无法订阅提醒',content:subscribeErrorMessage(e),showCancel:false}); } finally { this._subscribing = false; } }, // ===== 背景图 ===== showBgModal: async function() { this.setData({ showBgModal: true, bgPreview: '', bgFilePath: '' }); try { var cfg = await api.getBgConfig(); if (!this.data.bgFilePath) this.setData({ bgPreview: cfg && cfg.image ? getImageUrl(cfg.image) : '' }); } catch (e) { console.error(e); } }, hideBgModal: function() { this.setData({ showBgModal: false }); }, // 背景编辑页左滑返回设置页面 bgTouchStartX: 0, bgTouchStartY: 0, onBgTouchStart: function(e) { this.bgTouchStartX = e.touches[0].clientX; this.bgTouchStartY = e.touches[0].clientY; }, onBgTouchEnd: function(e) { var dx = this.bgTouchStartX - e.changedTouches[0].clientX; var dy = Math.abs(this.bgTouchStartY - e.changedTouches[0].clientY); if (dx < 20 && dy < 20) return; if (Math.abs(dx) > dy && dx > 80) this.hideBgModal(); }, chooseBgImage: function() { var self = this; guardStorageSpace(0).then(function(ok) { if (!ok) return; wx.chooseImage({ count: 1, sizeType: ['compressed'], sourceType: ['album'], success: function(res) { self.setData({ bgPreview: res.tempFilePaths[0], bgFilePath: res.tempFilePaths[0] }); } }); }); }, saveBgImage: async function() { var fp = this.data.bgFilePath; if (!fp) { if (this.data.bgPreview) { wx.showToast({ title: '背景已设置', icon: 'success' }); this.hideBgModal(); return; } wx.showToast({ title: '请先选择图片', icon: 'none' }); return; } var self = this; wx.showLoading({ title: '上传中...' }); try { var data = await uploadFileCompat({ url: API_BASE + '/setBgImage', filePath: fp, name: 'bg', formData: {} }); wx.hideLoading(); if (data && data.path) { var imgUrl = getImageUrl(data.path); wx.showToast({ title: '背景已保存 ✨', icon: 'success' }); self.setData({ bgPreview: imgUrl, bgFilePath: '' }); self.hideBgModal(); } else { var errMsg = (data && data.error) || '上传失败'; if (data && data.code) errMsg += ' (错误码: ' + data.code + ')'; wx.showToast({ title: errMsg, icon: 'none' }); } } catch(e) { wx.hideLoading(); var errMsg = (e && e.error) || '上传失败'; if (e && e.code) errMsg += ' (错误码: ' + e.code + ')'; wx.showToast({ title: errMsg, icon: 'none' }); } }, removeBgImage: async function() { try { await api.deleteBgImage(); } catch(e) {} wx.showToast({ title: '已恢复默认', icon: 'success' }); this.setData({ bgPreview: '', bgFilePath: '' }); this.hideBgModal(); }, // ===== 解除绑定(根据状态显示不同操作)===== showUnbind: function() { var status = this.data.unbindStatus; var isRequester = this.data.unbindIsRequester; if (status === 'pending') { if (isRequester) { // 发起方:撤销解绑 this.doCancelUnbind(); } else { // 对方:同意或拒绝 this.doRespondUnbind(); } } else if (status === 'cooling') { wx.showToast({ title: '正在72小时冷静期', icon: 'none' }); wx.navigateTo({ url: '/pages/unbind/unbind' }); } else { // 无解绑请求或已结束:发起新解绑 this.doRequestUnbind(); } }, // 发起解绑请求 doRequestUnbind: function() { var self = this; wx.showModal({ title: '💔 解除绑定', content: '对方同意后进入72小时冷静期,期间任一方可取消。到期自动解绑并永久删除共同数据;个人抽烟记录保留。', cancelText: '取消', confirmText: '发起解绑', confirmColor: '#FF4757', success: function(res) { if (res.confirm) { wx.showLoading({ title: '发送请求...' }); api.unbindRequest().then(function() { wx.hideLoading(); wx.showToast({ title: '解绑请求已发送', icon: 'success' }); self.loadUnbindStatus(); wx.navigateTo({ url: '/pages/unbind/unbind' }); }).catch(function(err) { wx.hideLoading(); wx.showToast({ title: err.error || '操作失败', icon: 'none' }); }); } } }); }, // 撤销解绑请求 doCancelUnbind: function() { var self = this; wx.showModal({ title: '↩️ 撤销解绑', content: '取消后关系继续保留。确定取消解绑吗?', cancelText: '取消', confirmText: '撤销请求', confirmColor: '#FF6B9D', success: function(res) { if (res.confirm) { wx.showLoading({ title: '撤销中...' }); api.unbindCancel().then(function() { wx.hideLoading(); wx.showToast({ title: '已撤销解绑请求', icon: 'success' }); self.loadUnbindStatus(); }).catch(function(err) { wx.hideLoading(); wx.showToast({ title: err.error || '操作失败', icon: 'none' }); }); } } }); }, // 回应解绑请求(对方视角) doRespondUnbind: function() { var self = this; var name = this.data.unbindRequesterName; wx.showActionSheet({ itemList: ['✅ 同意解绑', '❌ 拒绝解绑'], success: function(res) { if (res.tapIndex === 0) { // 同意 wx.showModal({ title: '⚠️ 确认同意', content: name + ' 发起了解绑请求。同意后进入72小时冷静期,期间可取消;到期自动解绑并永久删除共同数据,个人抽烟记录保留。', cancelText: '取消', confirmText: '同意解绑', confirmColor: '#FF4757', success: function(r) { if (r.confirm) { wx.showLoading({ title: '处理中...' }); api.unbindRespond({ agree: true }).then(function() { wx.hideLoading(); wx.showToast({ title: '已进入72小时冷静期', icon: 'none' }); self.loadUnbindStatus(); wx.navigateTo({ url: '/pages/unbind/unbind' }); }).catch(function(err) { wx.hideLoading(); wx.showToast({ title: err.error || '操作失败', icon: 'none' }); }); } } }); } else if (res.tapIndex === 1) { // 拒绝 wx.showModal({ title: '拒绝解绑', content: '确定要拒绝 ' + name + ' 的解绑请求吗?', cancelText: '取消', confirmText: '拒绝', confirmColor: '#FF6B9D', success: function(r) { if (r.confirm) { wx.showLoading({ title: '处理中...' }); api.unbindRespond({ agree: false }).then(function() { wx.hideLoading(); wx.showToast({ title: '已拒绝解绑请求', icon: 'success' }); self.loadUnbindStatus(); }).catch(function(err) { wx.hideLoading(); wx.showToast({ title: err.error || '操作失败', icon: 'none' }); }); } } }); } } }); }, // 导航 goToHistory: function() { wx.navigateTo({ url: '/pages/history/history' }); }, goHome: function() { wx.switchTab({ url: '/pages/index/index' }); }, goToProfile: function() { wx.navigateBack(); }, });