feat(coupon-data): 领券数据看板加领券状态多选过滤

- coupon_data_report 加 statuses 参(status.in_ 过滤,与 app_env 同级),整视图联动
- 路由 /coupon-data 加多值 status 参(不传=全部);不影响 /coupons 按券表
- 新增 test_coupon_data_status_filter

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
guke
2026-07-08 16:00:59 +08:00
parent f984b07a0c
commit ffe2ba91fd
3 changed files with 37 additions and 1 deletions
+5
View File
@@ -127,6 +127,7 @@ def coupon_data_report(
date_to: str,
user: str | None = None,
app_env: str | None = None,
statuses: list[str] | None = None,
granularity: str = "day",
limit: int = 500,
offset: int = 0,
@@ -136,6 +137,8 @@ def coupon_data_report(
- user:手机号/昵称模糊搜(匹配不到任何用户 → 空结果)。
- app_env:prod/dev 精确;None=全部。
- statuses:领券状态多选(started/completed/failed/abandoned);None/空=全部。整个视图
(汇总/成功率/趋势/明细)按选中状态算,与 app_env 同级过滤(方案 A)。
- sort:time=发起时刻倒序(默认) / elapsed=全程耗时倒序(None 末尾)。
"""
by_hour = granularity == "hour"
@@ -158,6 +161,8 @@ def coupon_data_report(
)
if app_env is not None:
stmt = stmt.where(CouponSession.app_env == app_env)
if statuses:
stmt = stmt.where(CouponSession.status.in_(statuses))
if user_ids is not None:
stmt = stmt.where(CouponSession.user_id.in_(user_ids))
rows = list(db.execute(stmt).scalars())
+5 -1
View File
@@ -54,6 +54,10 @@ def get_coupon_data(
date_to: Annotated[str | None, Query(description="结束日 北京 YYYY-MM-DD,闭区间,默认=date_from")] = None,
user: Annotated[str | None, Query(description="用户手机号/昵称模糊搜;不传=全部")] = None,
app_env: Annotated[str, Query(description="prod(默认) / dev / all(全部环境)")] = "prod",
status: Annotated[
list[str] | None,
Query(description="领券状态多选 started/completed/failed/abandoned;不传=全部"),
] = None,
granularity: Annotated[
str, Query(description="day=按天 / hour=按小时(北京);区间>1 天建议 day")
] = "day",
@@ -75,7 +79,7 @@ def get_coupon_data(
env = None if app_env == "all" else app_env
result = coupon_data.coupon_data_report(
db, date_from=d_from.isoformat(), date_to=d_to.isoformat(),
user=user, app_env=env, granularity=granularity,
user=user, app_env=env, statuses=status, granularity=granularity,
limit=limit, offset=offset, sort=sort,
)
return CouponDataOut(