feat: fetch subscription prices from server settings
- Add GET /api/v1/subscription/plans public endpoint (no auth needed) that reads prices from system_settings table - Subscribe-plans page now loads prices from server on show - Falls back to hardcoded defaults if API fails - Add api.getPlans() to miniprogram API module
这个提交包含在:
@@ -4,10 +4,7 @@ var config = require('../../config/env')
|
|||||||
Page({
|
Page({
|
||||||
data: {
|
data: {
|
||||||
statusBarHeight: 44,
|
statusBarHeight: 44,
|
||||||
plans: [
|
plans: [],
|
||||||
{ key: 'monthly', name: '月卡', price: 99, priceLabel: '¥99', desc: '约3.3元/天' },
|
|
||||||
{ key: 'yearly', name: '年卡', price: 899, priceLabel: '¥899', desc: '省¥289', tag: '推荐' }
|
|
||||||
],
|
|
||||||
selected: 'yearly',
|
selected: 'yearly',
|
||||||
purchasing: false,
|
purchasing: false,
|
||||||
subscription: null,
|
subscription: null,
|
||||||
@@ -28,9 +25,42 @@ Page({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onShow: function () {
|
onShow: function () {
|
||||||
|
this.loadPlans()
|
||||||
this.loadSubscription()
|
this.loadSubscription()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
loadPlans: function () {
|
||||||
|
var self = this
|
||||||
|
api.getPlans().then(function (data) {
|
||||||
|
var plans = (data.plans || []).filter(function (p) { return p.key !== 'trial' }).map(function (p) {
|
||||||
|
var daily = p.days > 0 ? (p.price / p.days).toFixed(1) : 0
|
||||||
|
return {
|
||||||
|
key: p.key,
|
||||||
|
name: p.name,
|
||||||
|
price: p.price,
|
||||||
|
priceLabel: '¥' + p.price,
|
||||||
|
desc: p.key === 'yearly' ? '省¥' + ((p.price / 12 * 12) > 0 ? Math.round(self._monthlyPrice(data.plans) * 12 - p.price) : '') : '约' + daily + '元/天',
|
||||||
|
tag: p.key === 'yearly' ? '推荐' : ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (plans.length > 0) self.setData({ plans: plans })
|
||||||
|
}).catch(function () {
|
||||||
|
self.setData({
|
||||||
|
plans: [
|
||||||
|
{ key: 'monthly', name: '月卡', price: 99, priceLabel: '¥99', desc: '约3.3元/天' },
|
||||||
|
{ key: 'yearly', name: '年卡', price: 899, priceLabel: '¥899', desc: '省¥289', tag: '推荐' }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
_monthlyPrice: function (plans) {
|
||||||
|
for (var i = 0; i < plans.length; i++) {
|
||||||
|
if (plans[i].key === 'monthly') return plans[i].price
|
||||||
|
}
|
||||||
|
return 99
|
||||||
|
},
|
||||||
|
|
||||||
loadSubscription: function () {
|
loadSubscription: function () {
|
||||||
var self = this
|
var self = this
|
||||||
api.getSubscription().then(function (sub) {
|
api.getSubscription().then(function (sub) {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ module.exports = {
|
|||||||
unbindDevice: function (deviceId) { return http.post('/api/v1/device/unbind', deviceId ? { device_id: deviceId } : {}) },
|
unbindDevice: function (deviceId) { return http.post('/api/v1/device/unbind', deviceId ? { device_id: deviceId } : {}) },
|
||||||
|
|
||||||
// Subscription
|
// Subscription
|
||||||
|
getPlans: function () { return http.get('/api/v1/subscription/plans') },
|
||||||
getSubscription: function () { return http.get('/api/v1/subscription') },
|
getSubscription: function () { return http.get('/api/v1/subscription') },
|
||||||
activateTrial: function () { return http.post('/api/v1/subscription/trial') },
|
activateTrial: function () { return http.post('/api/v1/subscription/trial') },
|
||||||
purchase: function (plan) { return http.post('/api/v1/subscription/purchase', { plan: plan }) },
|
purchase: function (plan) { return http.post('/api/v1/subscription/purchase', { plan: plan }) },
|
||||||
|
|||||||
@@ -13,6 +13,18 @@ const PLANS = {
|
|||||||
yearly: { amount: 899, days: 365 }
|
yearly: { amount: 899, days: 365 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
router.get('/subscription/plans', wrap(async (req, res) => {
|
||||||
|
const settingsDao = require('../dao/settings.dao')
|
||||||
|
const settings = await settingsDao.getAll()
|
||||||
|
res.json(ok({
|
||||||
|
plans: [
|
||||||
|
{ key: 'monthly', name: '月卡', price: Number(settings.monthly_price) || PLANS.monthly.amount, days: 30 },
|
||||||
|
{ key: 'yearly', name: '年卡', price: Number(settings.yearly_price) || PLANS.yearly.amount, days: 365 },
|
||||||
|
{ key: 'trial', name: '试用', price: 0, days: Number(settings.trial_days) || 7 }
|
||||||
|
]
|
||||||
|
}))
|
||||||
|
}))
|
||||||
|
|
||||||
router.get('/subscription', requireUser, wrap(async (req, res) => {
|
router.get('/subscription', requireUser, wrap(async (req, res) => {
|
||||||
const sub = await subscriptionDao.findActive(req.user.user_id)
|
const sub = await subscriptionDao.findActive(req.user.user_id)
|
||||||
if (!sub) return res.json(ok({ status: 'inactive', plan: 'none', remaining_days: 0 }))
|
if (!sub) return res.json(ok({ status: 'inactive', plan: 'none', remaining_days: 0 }))
|
||||||
|
|||||||
在新工单中引用
屏蔽一个用户