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,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
enum: ['version-update', 'expiry-reminder'],
|
||||||
|
default: 'version-update'
|
||||||
|
},
|
||||||
status: {
|
status: {
|
||||||
type: String,
|
type: String,
|
||||||
enum: ['active', 'expired', 'used'],
|
enum: ['active', 'expired', 'used'],
|
||||||
@@ -37,11 +42,16 @@ const userSubscriptionSchema = new mongoose.Schema({
|
|||||||
usedAt: {
|
usedAt: {
|
||||||
type: Date,
|
type: Date,
|
||||||
default: null
|
default: null
|
||||||
|
},
|
||||||
|
lastSentDay: {
|
||||||
|
type: Number,
|
||||||
|
default: null
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
timestamps: true
|
timestamps: true
|
||||||
});
|
});
|
||||||
|
|
||||||
userSubscriptionSchema.index({ userId: 1, templateId: 1 });
|
userSubscriptionSchema.index({ userId: 1, templateId: 1 });
|
||||||
|
userSubscriptionSchema.index({ type: 1, status: 1 });
|
||||||
|
|
||||||
module.exports = mongoose.model('UserSubscription', userSubscriptionSchema);
|
module.exports = mongoose.model('UserSubscription', userSubscriptionSchema);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const UserSubscription = require('../models/UserSubscription');
|
const UserSubscription = require('../models/UserSubscription');
|
||||||
|
const UserEquity = require('../models/UserEquity');
|
||||||
const WechatSubscribeService = require('../services/wechatSubscribeService');
|
const WechatSubscribeService = require('../services/wechatSubscribeService');
|
||||||
const { auth } = require('../middleware/auth');
|
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;
|
module.exports = router;
|
||||||
|
|||||||
@@ -81,6 +81,21 @@ class WechatSubscribeService {
|
|||||||
data
|
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;
|
module.exports = WechatSubscribeService;
|
||||||
|
|||||||
Reference in New Issue
Block a user