新增订阅额度风险预警计算
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* 风险预警计算:算出未来一段时间内,有哪些提醒会因额度不足发不出去
|
||||
*
|
||||
* 首页拿这个结果给用户看「谁的提醒有风险」,而不是「还剩几次额度」——
|
||||
* 用户理解不了额度这种抽象概念,但看得懂人名。
|
||||
*/
|
||||
|
||||
const { getNextOccurrence, daysBetween } = require('./occurrence')
|
||||
|
||||
// 预警窗口。太短则提示不及时,太长会拿几个月后的事惊扰用户,两个月是折中。
|
||||
const LOOKAHEAD_DAYS = 60
|
||||
|
||||
/**
|
||||
* 把一条纪念日展开成未来窗口内的提醒事件
|
||||
* 每条纪念日最多产生两个事件:提前 N 天一个、当天一个
|
||||
*/
|
||||
function expandEvents(anniv, today = new Date()) {
|
||||
const next = getNextOccurrence(anniv, today)
|
||||
const onDayIn = daysBetween(next, today)
|
||||
const remindDays = anniv.remindDays || 0
|
||||
|
||||
const events = [{
|
||||
anniversaryId: anniv.id,
|
||||
personName: anniv.personName,
|
||||
kind: 'onDay',
|
||||
fireInDays: onDayIn,
|
||||
importance: anniv.importance
|
||||
}]
|
||||
|
||||
if (remindDays > 0) {
|
||||
events.push({
|
||||
anniversaryId: anniv.id,
|
||||
personName: anniv.personName,
|
||||
kind: 'ahead',
|
||||
fireInDays: onDayIn - remindDays,
|
||||
importance: anniv.importance
|
||||
})
|
||||
}
|
||||
|
||||
// 已经过去的(如提前提醒的时点早已过)和超出窗口的都不算
|
||||
return events.filter(e => e.fireInDays >= 0 && e.fireInDays <= LOOKAHEAD_DAYS)
|
||||
}
|
||||
|
||||
/**
|
||||
* 算出有风险的提醒
|
||||
* 排序用「时间先后」而非重要程度——跨天的额度就是先到先消耗。
|
||||
* 重要程度只在同一天内比较(那部分逻辑在 reminder.js)。
|
||||
*/
|
||||
function computeAtRisk(anniversaries, balance, today = new Date()) {
|
||||
const events = (anniversaries || [])
|
||||
.filter(a => a && a.remindEnabled)
|
||||
.flatMap(a => expandEvents(a, today))
|
||||
.sort((x, y) => x.fireInDays - y.fireInDays)
|
||||
|
||||
const safeCount = Math.max(0, balance)
|
||||
const atRisk = events.slice(safeCount)
|
||||
|
||||
const names = []
|
||||
for (const e of atRisk) {
|
||||
if (e.personName && !names.includes(e.personName)) names.push(e.personName)
|
||||
}
|
||||
|
||||
return { atRiskCount: atRisk.length, atRiskNames: names }
|
||||
}
|
||||
|
||||
module.exports = { LOOKAHEAD_DAYS, expandEvents, computeAtRisk }
|
||||
Reference in New Issue
Block a user