文件
jw-beauty/miniprogram/pages/subscribe-plans/subscribe-plans.js
T
Guoguo 4466c53c7b feat(i18n): 剩余15页全量接入中英(登录/注册/扫码/绑定/佩戴/扫描/治疗/订阅/帮助等)
- 3 个并行 agent 各管 5 页,互不重叠命名空间
- 全 App 18 页均 i18n.bind,22 命名空间/400 键中英对齐
- 动态文案(时长/天数/价格/区域)JS 内 i18n.t 计算;区域标签复用 common.regions
2026-07-19 06:00:04 -07:00

240 行
7.8 KiB
JavaScript

var api = require('../../utils/api')
var i18n = require('../../i18n/index')
Page({
data: {
statusBarHeight: 44,
plans: [],
selected: 'yearly',
purchasing: false,
subscription: null,
subRemaining: 0,
subRemainingText: '',
loadingPlans: true
},
onBack: function () {
wx.navigateBack({
fail: function () {
wx.reLaunch({ url: '/pages/index/index' })
}
})
},
onLoad: function () {
var app = getApp()
this.setData({ statusBarHeight: app.globalData.statusBarHeight })
},
onShow: function () {
i18n.bind(this)
this.loadPlans()
this.loadSubscription()
},
planName: function (key) {
if (key === 'trial') return i18n.t('subPlans.planTrial')
if (key === 'monthly') return i18n.t('subPlans.planMonthly')
if (key === 'yearly') return i18n.t('subPlans.planYearly')
return key
},
loadPlans: function () {
var self = this
self.setData({ loadingPlans: true })
api.getPlans().then(function (data) {
var serverPlans = data.plans || []
var monthlyPrice = 99
for (var i = 0; i < serverPlans.length; i++) {
if (serverPlans[i].key === 'monthly') monthlyPrice = serverPlans[i].price
}
var plans = serverPlans.map(function (p) {
var daily = p.days > 0 ? (p.price / p.days).toFixed(1) : 0
var desc = ''
if (p.key === 'trial') desc = i18n.t('subPlans.descTrial', { days: p.days })
else if (p.key === 'yearly') desc = i18n.t('subPlans.descSave', { amount: Math.round(monthlyPrice * 12 - p.price) })
else desc = i18n.t('subPlans.descDaily', { price: daily })
return {
key: p.key,
name: self.planName(p.key),
price: p.price,
priceLabel: p.key === 'trial' ? i18n.t('subPlans.free') : '¥' + p.price,
desc: desc,
tag: p.key === 'yearly' ? i18n.t('subPlans.tagRecommend') : '',
disabled: false
}
})
if (plans.length > 0) self.setData({ plans: plans })
self.setData({ loadingPlans: false })
self.checkTrialUsed()
}).catch(function () {
self.setData({
loadingPlans: false,
plans: [
{ key: 'trial', name: self.planName('trial'), price: 0, priceLabel: i18n.t('subPlans.free'), desc: i18n.t('subPlans.descTrial', { days: 7 }), disabled: false },
{ key: 'monthly', name: self.planName('monthly'), price: 99, priceLabel: '¥99', desc: i18n.t('subPlans.descDaily', { price: '3.3' }) },
{ key: 'yearly', name: self.planName('yearly'), price: 899, priceLabel: '¥899', desc: i18n.t('subPlans.descSave', { amount: 289 }), tag: i18n.t('subPlans.tagRecommend') }
]
})
self.checkTrialUsed()
})
},
checkTrialUsed: function () {
var self = this
var sub = self.data.subscription
if (sub && sub.trial_used) {
var plans = self.data.plans.map(function (p) {
if (p.key === 'trial') return Object.assign({}, p, { disabled: true, tag: i18n.t('subPlans.tagUsed') })
return p
})
self.setData({ plans: plans })
if (self.data.selected === 'trial') self.setData({ selected: 'yearly' })
}
},
loadSubscription: function () {
var self = this
api.getSubscription().then(function (sub) {
var remaining = sub.remaining_days || 0
self.setData({
subscription: sub,
subRemaining: remaining,
subRemainingText: i18n.t('subPlans.daysValue', { days: remaining })
})
self.checkTrialUsed()
}).catch(function () {})
},
onAgreement: function () {
wx.showModal({ title: i18n.t('subPlans.tipTitle'), content: i18n.t('subPlans.agreementBuilding'), showCancel: false })
},
onSelect: function (e) {
this.setData({ selected: e.currentTarget.dataset.plan })
},
onPurchase: function () {
var self = this
var selected = this.data.selected
var plan = null
for (var i = 0; i < this.data.plans.length; i++) {
if (this.data.plans[i].key === selected) {
plan = this.data.plans[i]
break
}
}
if (!plan || plan.disabled) return
if (plan.key === 'trial') {
wx.showModal({
title: i18n.t('subPlans.activateTrialTitle'),
content: i18n.t('subPlans.activateTrialConfirm', { desc: plan.desc }),
success: function (res) {
if (res.confirm) self.doActivateTrial()
}
})
return
}
var isRenew = self.data.subscription && self.data.subscription.status === 'active' && self.data.subRemaining > 0
var planDays = plan.key === 'yearly' ? 365 : 30
var title = isRenew ? i18n.t('subPlans.confirmRenewTitle') : i18n.t('subPlans.confirmPayTitle')
var content = isRenew
? i18n.t('subPlans.renewContent', { days: planDays, price: plan.price })
: i18n.t('subPlans.payContent', { price: plan.price })
wx.showModal({
title: title,
content: content,
success: function (res) {
if (res.confirm) {
self.doPurchase(plan)
}
}
})
},
doActivateTrial: function () {
var self = this
self.setData({ purchasing: true })
api.activateTrial().then(function () {
self.setData({ purchasing: false })
wx.showToast({ title: i18n.t('subPlans.trialActivated'), icon: 'success' })
setTimeout(function () {
wx.redirectTo({ url: '/pages/subscribe-success/subscribe-success?plan=trial' })
}, 1000)
}).catch(function (err) {
self.setData({ purchasing: false })
wx.showToast({ title: err.message || i18n.t('subPlans.activateFailed'), icon: 'none' })
})
},
doPurchase: function (plan) {
var self = this
self.setData({ purchasing: true })
api.purchase(plan.key).then(function (data) {
if (!data.payment_params) {
self.setData({ purchasing: false })
wx.showToast({ title: i18n.t('subPlans.payUnavailable'), icon: 'none' })
return
}
var params = data.payment_params
self._currentOrderId = data.order_id
wx.requestPayment({
timeStamp: params.timeStamp,
nonceStr: params.nonceStr,
package: params.package,
signType: params.signType,
paySign: params.paySign,
success: function () {
// Payment dialog succeeded, sync order to confirm
self.syncAndRedirect(data.order_id, plan.key)
},
fail: function (err) {
self.setData({ purchasing: false })
var msg = (err.errMsg || '').indexOf('cancel') > -1 ? i18n.t('subPlans.payCancelled') : i18n.t('subPlans.payFailed')
wx.showToast({ title: msg, icon: 'none' })
}
})
}).catch(function (err) {
self.setData({ purchasing: false })
wx.showToast({ title: err.message || i18n.t('subPlans.createOrderFailed'), icon: 'none' })
})
},
syncAndRedirect: function (orderId, planKey) {
var self = this
var retryCount = 0
var maxRetries = 3
function pollSync() {
api.syncPaymentOrder(orderId).then(function (result) {
if (result.status === 'paid') {
self.setData({ purchasing: false })
wx.showToast({ title: i18n.t('subPlans.paySuccess'), icon: 'success' })
setTimeout(function () {
wx.redirectTo({ url: '/pages/subscribe-success/subscribe-success?plan=' + planKey })
}, 1000)
} else if (retryCount < maxRetries) {
retryCount++
setTimeout(pollSync, 2000)
} else {
self.setData({ purchasing: false })
wx.showToast({ title: i18n.t('subPlans.payProcessing'), icon: 'none' })
}
}).catch(function () {
if (retryCount < maxRetries) {
retryCount++
setTimeout(pollSync, 2000)
} else {
self.setData({ purchasing: false })
wx.showToast({ title: i18n.t('subPlans.payProcessing'), icon: 'none' })
}
})
}
pollSync()
}
})