20260707213510
This commit is contained in:
1 parent
f8e16efa83
commit
f94b5152ed
10 files changed
+918
-219
No files matched your search
@@ -1,56 +1,81 @@
|
||||
import dayjs from "dayjs";
|
||||
import { FinanceAutoRepeatType } from "@/types/finance";
|
||||
|
||||
// 判断今天是否应该执行
|
||||
/** repeat_date 以 ! 开头表示"排除模式":指定的日期/星期几不执行 */
|
||||
function isExcludeMode(repeatDate: string): boolean {
|
||||
return repeatDate.startsWith("!");
|
||||
}
|
||||
|
||||
/** 去掉排除前缀,返回干净的日期字符串 */
|
||||
function cleanRepeatDate(repeatDate: string): string {
|
||||
return isExcludeMode(repeatDate) ? repeatDate.slice(1) : repeatDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 粗粒度判断:从上次执行至今,是否"可能"有遗漏的触发日期
|
||||
* 只做时间周期级别的判断,不做具体日期匹配(日期匹配交给 shouldRunOnDate / getMissedDates)
|
||||
*/
|
||||
export function shouldRun(repeatType: number, repeatDate: string, lastRun: string | null | undefined): boolean {
|
||||
const today = dayjs();
|
||||
if (!lastRun) return true; // 从未执行过
|
||||
if (!lastRun) return true; // 从未执行过,需要尝试
|
||||
|
||||
const last = dayjs(lastRun);
|
||||
|
||||
// 排除模式下每天都是潜在触发日,简单判断 lastRun 不是今天即可
|
||||
if (isExcludeMode(repeatDate)) {
|
||||
return !last.isSame(today, "day");
|
||||
}
|
||||
|
||||
switch (repeatType) {
|
||||
case FinanceAutoRepeatType.Daily:
|
||||
return !last.isSame(today, "day");
|
||||
|
||||
case FinanceAutoRepeatType.Weekly: {
|
||||
// repeatDate = "1,3,5" → 周一三五
|
||||
const days = (repeatDate || "").split(",").map(Number);
|
||||
if (days.length === 0 || !days.includes(today.day())) return false;
|
||||
return true; // 今天在指定周几中,且上次执行不是今天(由外层 last_run 检查保证)
|
||||
const days = (repeatDate || "").split(",").map(Number).filter((d) => !isNaN(d));
|
||||
if (days.length === 0) return false;
|
||||
let check = today;
|
||||
for (let i = 0; i < 7; i++) {
|
||||
if (days.includes(check.day())) {
|
||||
return check.isAfter(last, "day");
|
||||
}
|
||||
check = check.subtract(1, "day");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
case FinanceAutoRepeatType.Monthly: {
|
||||
const dates = (repeatDate || "").split(",").map(Number);
|
||||
if (dates.length === 0 || !dates.includes(today.date())) return false;
|
||||
case FinanceAutoRepeatType.Monthly:
|
||||
return !last.isSame(today, "month");
|
||||
}
|
||||
|
||||
case FinanceAutoRepeatType.Quarterly: {
|
||||
const dates = (repeatDate || "").split(",").map(Number);
|
||||
if (dates.length === 0 || !dates.includes(today.date())) return false;
|
||||
case FinanceAutoRepeatType.Quarterly:
|
||||
return last.quarter() !== today.quarter() || last.year() !== today.year();
|
||||
}
|
||||
|
||||
case FinanceAutoRepeatType.Yearly: {
|
||||
// repeatDate = "3,15" → 3月15日
|
||||
const parts = (repeatDate || "").split(",").map(Number);
|
||||
if (parts.length !== 2 || parts[0] !== today.month() + 1 || parts[1] !== today.date()) return false;
|
||||
return last.year() !== today.year();
|
||||
}
|
||||
case FinanceAutoRepeatType.Yearly:
|
||||
// 支持同一年内多个触发日(如 3/15 和 6/1),不再仅按年份判断
|
||||
return last.isBefore(today, "day");
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取应该补记账的日期列表(从上次执行到今天)
|
||||
/**
|
||||
* 获取应该补记账的日期列表(从上次执行到今天)
|
||||
* 逐日遍历,通过 shouldRunOnDate 精确匹配触发日
|
||||
*/
|
||||
export function getMissedDates(
|
||||
repeatType: number,
|
||||
repeatDate: string,
|
||||
lastRun: string | null | undefined,
|
||||
): string[] {
|
||||
const today = dayjs();
|
||||
if (!lastRun) return [today.format("YYYY-MM-DD")];
|
||||
|
||||
// 首次执行:只在今天恰好是触发日时才创建账单
|
||||
if (!lastRun) {
|
||||
if (shouldRunOnDate(repeatType, repeatDate, today)) {
|
||||
return [today.format("YYYY-MM-DD")];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
const last = dayjs(lastRun);
|
||||
const dates: string[] = [];
|
||||
@@ -68,25 +93,43 @@ export function getMissedDates(
|
||||
}
|
||||
|
||||
function shouldRunOnDate(repeatType: number, repeatDate: string, date: dayjs.Dayjs): boolean {
|
||||
const exclude = isExcludeMode(repeatDate);
|
||||
const raw = cleanRepeatDate(repeatDate);
|
||||
|
||||
switch (repeatType) {
|
||||
case FinanceAutoRepeatType.Daily:
|
||||
return true;
|
||||
case FinanceAutoRepeatType.Daily: {
|
||||
if (!exclude || !raw) return true;
|
||||
// 每天 排除星期几(如 "!0" → 排除周日)
|
||||
const excludedDays = raw.split(",").map(Number).filter((d) => !isNaN(d));
|
||||
return !excludedDays.includes(date.day());
|
||||
}
|
||||
|
||||
case FinanceAutoRepeatType.Weekly: {
|
||||
const days = (repeatDate || "").split(",").map(Number);
|
||||
return days.includes(date.day());
|
||||
}
|
||||
case FinanceAutoRepeatType.Monthly: {
|
||||
const dates = (repeatDate || "").split(",").map(Number);
|
||||
return dates.includes(date.date());
|
||||
const days = raw.split(",").map(Number).filter((d) => !isNaN(d));
|
||||
if (days.length === 0) return false;
|
||||
const match = days.includes(date.day());
|
||||
return exclude ? !match : match;
|
||||
}
|
||||
|
||||
case FinanceAutoRepeatType.Monthly:
|
||||
case FinanceAutoRepeatType.Quarterly: {
|
||||
const dates = (repeatDate || "").split(",").map(Number);
|
||||
return dates.includes(date.date());
|
||||
const dates = raw.split(",").map(Number).filter((d) => !isNaN(d));
|
||||
if (dates.length === 0) return false;
|
||||
const match = dates.includes(date.date());
|
||||
return exclude ? !match : match;
|
||||
}
|
||||
|
||||
case FinanceAutoRepeatType.Yearly: {
|
||||
const parts = (repeatDate || "").split(",").map(Number);
|
||||
return parts.length === 2 && parts[0] === date.month() + 1 && parts[1] === date.date();
|
||||
// 月,日 成对存储,如 "3,15,6,1" → 3月15日 + 6月1日
|
||||
const parts = raw.split(",").map(Number).filter((n) => !isNaN(n));
|
||||
for (let i = 0; i < parts.length - 1; i += 2) {
|
||||
if (parts[i] === date.month() + 1 && parts[i + 1] === date.date()) {
|
||||
return exclude ? false : true;
|
||||
}
|
||||
}
|
||||
return exclude; // 排除模式未命中 → 执行;正常模式未命中 → 不执行
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -96,8 +139,6 @@ export const REPEAT_LABELS: Record<number, string> = {
|
||||
[FinanceAutoRepeatType.Daily]: "每天",
|
||||
[FinanceAutoRepeatType.Weekly]: "每周",
|
||||
[FinanceAutoRepeatType.Monthly]: "每月",
|
||||
[FinanceAutoRepeatType.Quarterly]: "每季度",
|
||||
[FinanceAutoRepeatType.Yearly]: "每年",
|
||||
};
|
||||
|
||||
export const WEEK_DAYS = [
|
||||
|
||||
Reference in new issue
Block a user