Gate record features and storage entry points with invitation guidance; enforce record access in the backend. Add homepage greetings, right-swipe profile dismissal, and move the smoking switch to settings. Simplify API base configuration and remove the unused legacy tab bar component.
165 lines
6.3 KiB
JavaScript
165 lines
6.3 KiB
JavaScript
const { withRecordAccess } = require('../../utils/record-access');
|
|
const { withDataCache } = require('../../utils/page-cache');
|
|
const { tryLoginRenewal } = require('../../utils/subscribe');
|
|
const { getLayout } = require('../../utils/layout');
|
|
const { api } = require('../../utils/request');
|
|
|
|
function formatBytes(bytes) {
|
|
bytes = bytes || 0;
|
|
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
|
|
if (bytes < 1024 * 1024 * 1024) return (bytes / 1024 / 1024).toFixed(1) + ' MB';
|
|
return (bytes / 1024 / 1024 / 1024).toFixed(2) + ' GB';
|
|
}
|
|
|
|
Page(withRecordAccess(withDataCache({
|
|
onLoginSubscribeTap: function() { return tryLoginRenewal(); },
|
|
onResize: function () { this.setData(getLayout()); },
|
|
|
|
data: {
|
|
loading: true,
|
|
error: false,
|
|
usedBytes: 0,
|
|
usedText: '0 MB',
|
|
freeMb: 200,
|
|
freeText: '200 MB',
|
|
percent: 0,
|
|
overQuota: false,
|
|
isVip: false,
|
|
isUnlimited:false,
|
|
quotaText:"200 MB",
|
|
vipExpireText: '',
|
|
plans: [],
|
|
paying: false,
|
|
},
|
|
|
|
onLoad: function () { this._unloaded = false; this.setData(getLayout()); },
|
|
onUnload: function () { this._unloaded = true; },
|
|
onShow: function () { this.loadInfo(); },
|
|
onPullDownRefresh: function () { this.loadInfo().then(function () { wx.stopPullDownRefresh(); }); },
|
|
|
|
loadInfo: function () {
|
|
var self = this;
|
|
this.setData({ loading: true, error: false });
|
|
return api.storageInfo().then(function (d) {
|
|
var freeBytes = d.quota_bytes != null ? d.quota_bytes : (d.quotaBytes != null ? d.quotaBytes : (d.free_bytes || d.freeBytes || 0));
|
|
var unlimited=!!(d.is_unlimited || d.isUnlimited);
|
|
var usedBytes = d.used_bytes || d.usedBytes || 0;
|
|
var percent = freeBytes > 0 ? Math.min(100, Math.round(usedBytes / freeBytes * 100)) : 0;
|
|
var overQuota = usedBytes > freeBytes;
|
|
var plans = (d.plans || []).map(function (p) {
|
|
var cents = p.price_cents || p.priceCents || 0;
|
|
return {
|
|
key: p.key,
|
|
name: p.name,
|
|
priceCents:cents,
|
|
version:p.updated_at || p.updatedAt,
|
|
priceText: (cents / 100).toFixed(2),
|
|
unit: (p.months || (p.key==='year'?12:1))+'个月',
|
|
description: (Number(p.quota_mb != null ? p.quota_mb : p.quotaMb || 0)===0 ? '无限空间' : formatBytes(Number(p.quota_mb != null ? p.quota_mb : p.quotaMb)*1024*1024))+' · 有效期'+(p.months || (p.key==='year'?12:1))+'个月',
|
|
|
|
};
|
|
});
|
|
var vipExpireText = '';
|
|
if (d.is_vip || d.isVip) {
|
|
var expire = d.vip_expire_at || d.vipExpireAt ? String(d.vip_expire_at || d.vipExpireAt).slice(0, 10) : '';
|
|
vipExpireText = expire ? ('有效期至 ' + expire) : '已开通容量套餐';
|
|
}
|
|
self.setData({
|
|
loading: false,
|
|
usedBytes: usedBytes,
|
|
usedText: formatBytes(usedBytes),
|
|
freeMb: d.free_mb != null ? d.free_mb : (d.freeMb != null ? d.freeMb : 200),
|
|
freeText: formatBytes(freeBytes),
|
|
percent: percent,
|
|
overQuota: overQuota,
|
|
isVip: !!(d.is_vip || d.isVip),
|
|
isUnlimited:unlimited,
|
|
quotaText:unlimited?"无限空间":formatBytes(freeBytes),
|
|
vipExpireText: vipExpireText,
|
|
plans: plans,
|
|
});
|
|
}).catch(function (e) {
|
|
self.setData({ loading: false, error: true });
|
|
console.error('加载存储信息失败', e);
|
|
});
|
|
},
|
|
|
|
buyPlan: function (e) {
|
|
var key = e.currentTarget.dataset.key;
|
|
var self = this;
|
|
if (this.data.paying) return;
|
|
var plan = null;
|
|
for (var i = 0; i < this.data.plans.length; i++) {
|
|
if (this.data.plans[i].key === key) { plan = this.data.plans[i]; break; }
|
|
}
|
|
if (!plan) return;
|
|
|
|
wx.showLoading({ title: '下单中...', mask: true });
|
|
this.setData({ paying: true });
|
|
api.storageCreateOrder({ plan_key: key, expected_price_cents:plan.priceCents, expected_plan_version:plan.version }).then(function (order) {
|
|
wx.hideLoading();
|
|
if (order && order.pay_provider === 'wechat' && order.payment) {
|
|
self.callWechatPay(order);
|
|
return;
|
|
}
|
|
self.setData({ paying: false });
|
|
wx.showToast({ title: '支付参数不完整,请重新下单', icon: 'none' });
|
|
}).catch(function (err) {
|
|
wx.hideLoading();
|
|
self.setData({ paying: false });
|
|
wx.showToast({ title: (err && err.error) || '下单失败', icon: 'none' });
|
|
});
|
|
},
|
|
|
|
callWechatPay: function (order) {
|
|
var self = this;
|
|
var payment = order.payment;
|
|
if (!wx.requestPayment) {
|
|
this.setData({ paying: false });
|
|
wx.showToast({ title: '当前环境不支持微信支付,请使用微信真机', icon: 'none' });
|
|
return;
|
|
}
|
|
wx.requestPayment({
|
|
timeStamp: payment.time_stamp,
|
|
nonceStr: payment.nonce_str,
|
|
package: payment.package,
|
|
signType: payment.sign_type,
|
|
paySign: payment.pay_sign,
|
|
success: function () { return self.confirmWechatPayment(order.out_trade_no); },
|
|
fail: function (error) {
|
|
// Even a cashier error can occur after payment; query the server once.
|
|
var message = String(error && error.errMsg || '').indexOf('cancel') >= 0 ? '已取消支付' : '支付未完成';
|
|
return self.confirmWechatPayment(order.out_trade_no, message);
|
|
}
|
|
});
|
|
},
|
|
|
|
confirmWechatPayment: async function (number, failureMessage) {
|
|
if (this._confirming) return;
|
|
this._confirming = true;
|
|
try {
|
|
for (var attempt = 0; attempt < (failureMessage ? 1 : 5); attempt++) {
|
|
var result = await api.storageOrderStatus(number);
|
|
if (this._unloaded) return;
|
|
if (result.status === 'success') {
|
|
wx.showToast({ title: '支付成功,会员已开通', icon: 'success' });
|
|
await this.loadInfo();
|
|
return;
|
|
}
|
|
if (result.status === 'closed') {
|
|
wx.showToast({ title: '订单已关闭,请重新下单', icon: 'none' });
|
|
return;
|
|
}
|
|
if (!failureMessage && attempt < 4) await new Promise(function (resolve) { setTimeout(resolve, 1200); });
|
|
}
|
|
if (!this._unloaded) wx.showToast({ title: failureMessage || '支付结果确认中,请稍后刷新', icon: 'none' });
|
|
} catch (e) {
|
|
if (!this._unloaded) wx.showToast({ title: '支付结果暂未确认,请稍后刷新', icon: 'none' });
|
|
} finally {
|
|
this._confirming = false;
|
|
if (!this._unloaded) this.setData({ paying: false });
|
|
}
|
|
},
|
|
|
|
}, {loadInfo:['storageInfo']})));
|