修复首页风险预告与实际发送的排序不一致问题
atRisk.js 之前只按 fireInDays 排序,同一天内多条提醒的先后完全未定义, 和 reminder.js 实际发送时「当天>提前、重要程度降序」的规则对不上,导致 额度卡在中间时首页提示的风险人名和定时任务实际跳过的人不一致。 - 把 importanceRank 从 reminder.js 抽到共享的 src/importance.js,两处复用 - atRisk.js 的 computeAtRisk 排序改为三段式:fireInDays 升序 → 同天内 kind(当天优先于提前)→ 同 kind 内重要程度降序 - 补充 atRisk.test.js 用例覆盖「同一天多条事件、额度只够一部分」场景
This commit is contained in:
+11
-3
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
const { getNextOccurrence, daysBetween } = require('./occurrence')
|
||||
const { importanceRank } = require('./importance')
|
||||
|
||||
// 预警窗口。太短则提示不及时,太长会拿几个月后的事惊扰用户,两个月是折中。
|
||||
const LOOKAHEAD_DAYS = 60
|
||||
@@ -43,14 +44,21 @@ function expandEvents(anniv, today = new Date()) {
|
||||
|
||||
/**
|
||||
* 算出有风险的提醒
|
||||
* 排序用「时间先后」而非重要程度——跨天的额度就是先到先消耗。
|
||||
* 重要程度只在同一天内比较(那部分逻辑在 reminder.js)。
|
||||
*
|
||||
* 排序必须与 reminder.js 的 runForUser 完全一致,否则首页提示的人名会跟
|
||||
* 定时任务实际跳过的人对不上:条数一样、人名却错了,用户会去补错人的额度。
|
||||
* 排序规则:先按 fireInDays 升序(跨天的额度是先到先消耗),
|
||||
* 同一天内再按「当天 > 提前」,然后按重要程度降序(重要程度权重见 importance.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)
|
||||
.sort((x, y) => {
|
||||
if (x.fireInDays !== y.fireInDays) return x.fireInDays - y.fireInDays
|
||||
if (x.kind !== y.kind) return x.kind === 'onDay' ? -1 : 1
|
||||
return importanceRank(x.importance) - importanceRank(y.importance)
|
||||
})
|
||||
|
||||
const safeCount = Math.max(0, balance)
|
||||
const atRisk = events.slice(safeCount)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 重要程度排序权重(纯函数)
|
||||
*
|
||||
* 从 reminder.js 抽出,供「定时发送」(reminder.js)与「风险预警」(atRisk.js)
|
||||
* 共用同一套排序权重,避免两处各写一套、后续改一处忘了改另一处导致排序不一致。
|
||||
*/
|
||||
|
||||
// 重要程度排序权重,未知值排最后
|
||||
const IMPORTANCE_RANK = { high: 0, medium: 1, low: 2 }
|
||||
function importanceRank(v) {
|
||||
return IMPORTANCE_RANK[v] === undefined ? 3 : IMPORTANCE_RANK[v]
|
||||
}
|
||||
|
||||
module.exports = { importanceRank }
|
||||
@@ -3,6 +3,7 @@ const db = require('./db')
|
||||
const wx = require('./wx')
|
||||
const occurrence = require('./occurrence')
|
||||
const quota = require('./quota')
|
||||
const { importanceRank } = require('./importance')
|
||||
|
||||
const TEMPLATE_ID = process.env.WX_TEMPLATE_ID
|
||||
const MINIPROGRAM_STATE = process.env.WX_MINIPROGRAM_STATE || 'formal'
|
||||
@@ -43,12 +44,6 @@ const insertLog = db.prepare(`
|
||||
VALUES (@anniversaryId, @personName, @typeName, @daysUntil, @sendDate, @status, @error)
|
||||
`)
|
||||
|
||||
// 重要程度排序权重,未知值排最后
|
||||
const IMPORTANCE_RANK = { high: 0, medium: 1, low: 2 }
|
||||
function importanceRank(v) {
|
||||
return IMPORTANCE_RANK[v] === undefined ? 3 : IMPORTANCE_RANK[v]
|
||||
}
|
||||
|
||||
// 43101 = 用户拒收或下发次数不足,是我们与微信侧对账的唯一信号
|
||||
function isQuotaError(err) {
|
||||
return err && err.errcode === 43101
|
||||
|
||||
Reference in New Issue
Block a user