From e8f076c9140058f95738c7c0e16d37a411759e7a Mon Sep 17 00:00:00 2001 From: Guoguo Date: Wed, 29 Apr 2026 08:07:47 -0700 Subject: [PATCH] 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 --- .../pages/subscribe-plans/subscribe-plans.js | 38 +++++++++++++++++-- miniprogram/utils/api.js | 1 + server/src/routes/subscription.js | 12 ++++++ 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/miniprogram/pages/subscribe-plans/subscribe-plans.js b/miniprogram/pages/subscribe-plans/subscribe-plans.js index e49a055..03d63b5 100644 --- a/miniprogram/pages/subscribe-plans/subscribe-plans.js +++ b/miniprogram/pages/subscribe-plans/subscribe-plans.js @@ -4,10 +4,7 @@ var config = require('../../config/env') Page({ data: { statusBarHeight: 44, - plans: [ - { key: 'monthly', name: '月卡', price: 99, priceLabel: '¥99', desc: '约3.3元/天' }, - { key: 'yearly', name: '年卡', price: 899, priceLabel: '¥899', desc: '省¥289', tag: '推荐' } - ], + plans: [], selected: 'yearly', purchasing: false, subscription: null, @@ -28,9 +25,42 @@ Page({ }, onShow: function () { + this.loadPlans() 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 () { var self = this api.getSubscription().then(function (sub) { diff --git a/miniprogram/utils/api.js b/miniprogram/utils/api.js index 74b8d97..83b4bf5 100644 --- a/miniprogram/utils/api.js +++ b/miniprogram/utils/api.js @@ -17,6 +17,7 @@ module.exports = { unbindDevice: function (deviceId) { return http.post('/api/v1/device/unbind', deviceId ? { device_id: deviceId } : {}) }, // Subscription + getPlans: function () { return http.get('/api/v1/subscription/plans') }, getSubscription: function () { return http.get('/api/v1/subscription') }, activateTrial: function () { return http.post('/api/v1/subscription/trial') }, purchase: function (plan) { return http.post('/api/v1/subscription/purchase', { plan: plan }) }, diff --git a/server/src/routes/subscription.js b/server/src/routes/subscription.js index 555cf96..c166e13 100644 --- a/server/src/routes/subscription.js +++ b/server/src/routes/subscription.js @@ -13,6 +13,18 @@ const PLANS = { 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) => { const sub = await subscriptionDao.findActive(req.user.user_id) if (!sub) return res.json(ok({ status: 'inactive', plan: 'none', remaining_days: 0 }))