feat: add expiry reminder subscription API (POST /subscribe/expiry-save) and send reminders endpoint
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user