Files
past-go/weapp/pages/settings/settings.js
T
CodeBuddy 3ce6edc9a1 feat: 存储空间管理、虚拟支付接入与容量守卫
- 新增存储空间管理:会员套餐配置、用户容量/到期管理、后台支付记录查询
- 接入个人主体小程序虚拟支付:下单/发货推送/兜底查单(query_order)
- 修复 adminStorageUsers 等接口鉴权、out_trade_no 长度、前端 requestVirtualPayment 参数
- 前端上传前容量预检,超容引导升级无限空间
- 我的页会员卡片展示「无限空间」与已用容量/到期时间
- 后台「存储空间管理」新增支付记录标签页
2026-10-26 23:07:09 +08:00

405 lines
13 KiB
JavaScript

const { getLayout } = require('../../utils/layout');
// pages/settings/settings.js
const { api, getImageUrl, API_BASE, uploadFileCompat } = require('../../utils/request');
const { requestSubscribe, getSubscribeStatus } = require('../../utils/subscribe');
const { guardStorageSpace } = require('../../utils/storage-guard');
Page({
onResize: function() { this.setData(getLayout()); },
data: {
showBgModal: false,
bgPreview: '',
bgFilePath: '',
hasPartner: false,
bindingKnown: false, bindingError:false,
// 解绑状态
unbindStatus: '', // '' / 'pending' / 'agreed' / 'rejected' / 'cancelled' / 'expired'
unbindIsRequester: false, // 当前用户是否是发起方
unbindRequesterName: '', // 发起方昵称
unbindRemaining: 0, // 剩余秒数
// 消息通知设置
showSubscribeModal: false,
subscribeStatus: {},
subscribeItems: [],
subscribeLoading: false,
// 打卡:抽烟打卡默认事件是否显示
smokingVisible: true,
// 我们past
showAboutModal: false,
// 联系我们
showContactModal: false,
},
onLoad: function() {
this.setData(getLayout());
this.refreshSmokingVisible();},
onPullDownRefresh: function() {
wx.stopPullDownRefresh();
},
onShow: async function() {
this.refreshSmokingVisible();
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);
}
},
goBind: function() {
getApp().globalData.openProfileBind = true;
wx.switchTab({ url: '/pages/profile/profile' });
},
// 加载解绑状态
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() {},
// ===== 抽烟打卡默认事件显示开关 =====
refreshSmokingVisible: function() {
var v = wx.getStorageSync('smokingVisible');
this.setData({ smokingVisible: (v === '' || v == null) ? true : !!v });
},
toggleSmoking: function(e) {
var visible = !!e.detail.value;
this.setData({ smokingVisible: visible });
wx.setStorageSync('smokingVisible', visible);
wx.showToast({ title: visible ? '已显示抽烟打卡' : '已隐藏抽烟打卡', icon: 'none' });
},
// ===== 消息通知管理(统一使用一个模板) =====
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 });
},
// ===== 联系我们 =====
showContactModal: function() {
this.setData({ showContactModal: true });
},
hideContactModal: function() {
this.setData({ showContactModal: false });
},
toggleSubscribe: async function(e) {
const type = 'notify';
const current = this.data.subscribeChecked;
// 防止重复点击
if (this._subscribing) return;
this._subscribing = true;
if (current) {
// 取消订阅
try {
await api.unsubscribeTemplate({ template_type: type });
this.setData({ subscribeChecked: false });
wx.setStorageSync('subscribed_notify', 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({ subscribeChecked: true });
wx.setStorageSync('subscribed_notify', true);
wx.showToast({ title: '已开启通知', icon: 'success' });
} else {
wx.showToast({ title: '订阅被拒绝,可在设置中重新开启', icon: 'none' });
}
} catch (e) {
wx.showToast({ title: '订阅失败', icon: 'none' });
}
}
this._subscribing = false;
},
renewSubscribe: async function() {
if (this._subscribing) return;
this._subscribing = true;
try {
const results = await requestSubscribe('notify');
if (results.notify) {
this.setData({ subscribeChecked: true });
wx.showToast({ title: '已订阅一次提醒', icon: 'success' });
} else {
wx.showToast({ title: '本次未授权提醒', icon: 'none' });
}
} catch (e) {
wx.showToast({ title: '订阅失败,请重试', icon: 'none' });
} 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(); },
});