fix(expiry): 已过期资产不再从到期统计中消失,总览页改为到期日历

get_expiring/get_overview 去掉 expiry_date>=today 下界(仅排除已注销)并新增 overdue_count;renewal_service 续费提醒纳入已过期、文案区分已过期N天/今天到期/N天后;dashboard 用到期日历逐条显示具体到期日与倒计时;api.js 新增 Fmt.countdownText 统一文案。
This commit is contained in:
gouki
2026-09-18 08:41:21 +00:00
parent c5982a5706
commit cbb32ea3b0
4 changed files with 66 additions and 19 deletions
+14 -4
View File
@@ -16,8 +16,9 @@ _SKIP_STATUS = {AssetStatus.CANCELLED}
def get_expiring_assets(session: Session, threshold_days: int) -> list:
"""返回 threshold_days 天内到期的资产列表 [(asset, days), ...],按剩余天数升序
"""返回 threshold_days 天内到期(含已过期未处理)的资产列表 [(asset, days), ...],按剩余天数升序
到期日不设下界:过了续费日仍未注销/续费的资产,提醒不能就此消失。
性能优化:日期范围与状态过滤均下推到 SQL 层。
"""
today = date.today()
@@ -25,7 +26,6 @@ def get_expiring_assets(session: Session, threshold_days: int) -> list:
assets = session.exec(
select(Asset).where(
Asset.expiry_date.is_not(None),
Asset.expiry_date >= today,
Asset.expiry_date <= deadline,
Asset.status.notin_(_SKIP_STATUS),
)
@@ -39,9 +39,19 @@ def build_renewal_message(expiring: list, threshold_days: int) -> str:
"""生成续费提醒消息(纯文本,兼容 Telegram/邮件)"""
if not expiring:
return ""
lines = [f"⏰ 资产续费提醒({threshold_days} 天内到期,共 {len(expiring)} 项)", ""]
overdue = sum(1 for _, d in expiring if d < 0)
if overdue:
head = f"⏰ 资产续费提醒(已过期 {overdue} 项 + {threshold_days} 天内到期 {len(expiring) - overdue} 项)"
else:
head = f"⏰ 资产续费提醒({threshold_days} 天内到期,共 {len(expiring)} 项)"
lines = [head, ""]
for asset, days in expiring:
tag = "(已过期)" if days == 0 else f"({days} 天后)"
if days < 0:
tag = f"(已过期 {-days} 天)"
elif days == 0:
tag = "(今天到期)"
else:
tag = f"({days} 天后)"
lines.append(f"• {asset.name} [{asset.provider}] {tag} 到期 {asset.expiry_date}")
return "\n".join(lines)