fix(overview): 锁定核心高价值套装并修复未查询空值误判

- 高价值套装精确匹配「套装-兔兔白日梦」与「套装-狂战萌兔」,排除头盔/背包/手榴弹散件干扰
- 增加 is_suit_queried_expr,未查询或 NULL 账号严禁误判为双套均可兑换
- 修复前后端序列化空值保持,完善列表与详情页准入状态和判定依据展示
- 新增头盔排除与 NULL 统计防错回归单测,全量通过 689 个用例
This commit is contained in:
yml2213
2026-10-07 15:27:30 +08:00
parent 5405d4b1d1
commit 44b762ea8c
11 changed files with 202 additions and 112 deletions
+22 -8
View File
@@ -42,14 +42,28 @@ def suit_owned_expr(column, text: str):
)
def is_suit_queried_expr():
"""判断账号是否有效完成过高价值套装查询。
必须同时满足:
1. 有查询时间 overview_queried_at
2. high_value_owned 必须是有效 JSON 数组(排除 SQL NULL 与 JSON NULL)
"""
return and_(
Account.overview_queried_at.isnot(None),
Account.high_value_owned.isnot(None),
cast(Account.high_value_owned, String).like("[%"),
)
def value_tier_expr():
"""1–5 档。没查过、也没有任何资产信号时落在第 5 档。"""
queried = Account.overview_queried_at.isnot(None)
hv_queried = is_suit_queried_expr()
owns_bairimeng = suit_owned_expr(Account.high_value_owned, SUIT_BAIRIMENG)
owns_mengtu = suit_owned_expr(Account.high_value_owned, SUIT_MENGTU)
both_available = and_(queried, ~owns_bairimeng, ~owns_mengtu)
both_available = and_(hv_queried, ~owns_bairimeng, ~owns_mengtu)
one_available = and_(
queried,
hv_queried,
or_(
and_(~owns_bairimeng, owns_mengtu),
and_(owns_bairimeng, ~owns_mengtu),
@@ -59,7 +73,7 @@ def value_tier_expr():
(both_available, 1),
(or_(one_available, Account.points >= HIGH_VALUE_POINTS), 2),
(or_(Account.gold_balance > 0, Account.elite_opened.is_(True)), 3),
(queried, 4),
(Account.overview_queried_at.isnot(None), 4),
else_=5,
)
@@ -79,18 +93,18 @@ def suit_sort_rank_expr():
不掺积分、鱼翅。那是巡检分档的事,点这一列的人是在排套装。
"""
queried = Account.overview_queried_at.isnot(None)
hv_queried = is_suit_queried_expr()
owns_bairimeng = suit_owned_expr(Account.high_value_owned, SUIT_BAIRIMENG)
owns_mengtu = suit_owned_expr(Account.high_value_owned, SUIT_MENGTU)
both_available = and_(queried, ~owns_bairimeng, ~owns_mengtu)
both_available = and_(hv_queried, ~owns_bairimeng, ~owns_mengtu)
one_available = and_(
queried,
hv_queried,
or_(
and_(~owns_bairimeng, owns_mengtu),
and_(owns_bairimeng, ~owns_mengtu),
),
)
both_owned = and_(queried, owns_bairimeng, owns_mengtu)
both_owned = and_(hv_queried, owns_bairimeng, owns_mengtu)
return case(
(both_available, 0),
(one_available, 1),