diff --git a/src/models/UserSubscription.js b/src/models/UserSubscription.js index 1636549..84779ba 100644 --- a/src/models/UserSubscription.js +++ b/src/models/UserSubscription.js @@ -21,6 +21,11 @@ const userSubscriptionSchema = new mongoose.Schema({ type: String, default: '' }, + type: { + type: String, + enum: ['version-update', 'expiry-reminder'], + default: 'version-update' + }, status: { type: String, enum: ['active', 'expired', 'used'], @@ -37,11 +42,16 @@ const userSubscriptionSchema = new mongoose.Schema({ usedAt: { type: Date, default: null + }, + lastSentDay: { + type: Number, + default: null } }, { timestamps: true }); userSubscriptionSchema.index({ userId: 1, templateId: 1 }); +userSubscriptionSchema.index({ type: 1, status: 1 }); module.exports = mongoose.model('UserSubscription', userSubscriptionSchema); diff --git a/src/routes/subscribe.js b/src/routes/subscribe.js index 47541d4..9e86804 100644 --- a/src/routes/subscribe.js +++ b/src/routes/subscribe.js @@ -1,5 +1,6 @@ const express = require('express'); const UserSubscription = require('../models/UserSubscription'); +const UserEquity = require('../models/UserEquity'); const WechatSubscribeService = require('../services/wechatSubscribeService'); const { auth } = require('../middleware/auth'); @@ -113,4 +114,120 @@ router.post('/version-update', auth, async (req, res, next) => { } }); +router.post('/expiry-save', auth, async (req, res, next) => { + try { + const { templateId } = req.body; + + if (!templateId) { + return res.status(400).json({ + success: false, + error: 'templateId 不能为空' + }); + } + + const user = req.user; + + const existingSubscription = await UserSubscription.findOne({ + userId: user._id, + templateId, + type: 'expiry-reminder', + status: 'active' + }); + + if (existingSubscription) { + return res.json({ success: true, message: '已存在有效的到期提醒订阅' }); + } + + const subscription = new UserSubscription({ + userId: user._id, + openid: user.openid, + templateId, + type: 'expiry-reminder', + scene: '' + }); + + await subscription.save(); + + res.json({ success: true, message: '到期提醒订阅保存成功' }); + } catch (error) { + next(error); + } +}); + +router.post('/send-expiry-reminders', async (req, res, next) => { + try { + const now = new Date(); + const results = { total: 0, sent: 0, failed: 0, errors: [] }; + + const daysToCheck = [10, 3, 0]; + + for (const daysBefore of daysToCheck) { + const targetDate = new Date(now); + targetDate.setDate(targetDate.getDate() + daysBefore); + const targetDateStr = targetDate.toISOString().split('T')[0]; + + const subscriptions = await UserSubscription.find({ + type: 'expiry-reminder', + status: 'active', + lastSentDay: { $ne: daysBefore } + }); + + if (subscriptions.length === 0) continue; + + for (const sub of subscriptions) { + try { + const equities = await UserEquity.find({ + owner: sub.userId, + status: 'active', + expireDate: targetDateStr + }); + + for (const equity of equities) { + const dayLabel = daysBefore === 0 ? '今天' : `${daysBefore}天`; + const result = await WechatSubscribeService.sendExpiryReminderMessage({ + openid: sub.openid, + templateId: sub.templateId, + thing1: equity.platform, + thing2: `您的${equity.platform}${equity.type}将在${dayLabel}到期`, + phrase3: daysBefore === 0 ? '已到期' : '即将到期' + }); + + results.total++; + + if (result.success) { + results.sent++; + sub.lastSentDay = daysBefore; + await sub.save(); + } else { + results.failed++; + if (result.errcode === 43101 || result.errcode === 40037) { + sub.status = 'expired'; + sub.expiredAt = new Date(); + await sub.save(); + } + results.errors.push({ + openid: sub.openid, + platform: equity.platform, + error: result.errmsg + }); + } + } + } catch (subError) { + results.errors.push({ + openid: sub.openid, + error: subError.message + }); + } + } + } + + res.json({ + success: true, + data: results + }); + } catch (error) { + next(error); + } +}); + module.exports = router; diff --git a/src/services/wechatSubscribeService.js b/src/services/wechatSubscribeService.js index 7459b3b..bb47a52 100644 --- a/src/services/wechatSubscribeService.js +++ b/src/services/wechatSubscribeService.js @@ -81,6 +81,21 @@ class WechatSubscribeService { data }); } + + static async sendExpiryReminderMessage({ openid, templateId, thing1, thing2, phrase3 }) { + const data = { + thing1: { value: thing1 }, + thing2: { value: thing2 }, + phrase3: { value: phrase3 } + }; + + return this.sendSubscribeMessage({ + touser: openid, + templateId, + page: 'pages/profile/profile', + data + }); + } } module.exports = WechatSubscribeService;