refactor(ui): 账号列表页重做 —— 状态分布当筛选入口,砍掉重复与噪声
这页还是 S6 之前的老壳子:4 张统计卡有 3 张是装饰、状态与 CK 两列在说同一件事、
ID 单独占一列、绑定列 12 行全是「精? 电? 店?」。
## 统计卡 → 生命周期分布(可点击筛选)
原来:账号总数 / **标签数** / **已分配** / **未分配**。
标签数在筛选里就能看;已分配与未分配是一对冗余;而且它们都回答不了
「我该干什么」。现在按**生命周期状态**分布:总数 / 正常 / CK失效 / 待人工 /
未登录 / 已停用,**点一下就是「只看这些」**(`statusFilter`),计数为 0 的自动变淡。
后端 `accounts_summary` 相应扩出 `by_status` / `visible_total` /
`ck_invalid_count` / `no_cookie_count`。口径与列表一致:**归档不计入**。
## 表格列收敛
| 改动 | 理由 |
| --- | --- |
| **ID 列 → 并入「账号」小字** | 客服不看 ID,但报障时还要念得出来;合并后省一列宽度 |
| **CK 列 → 并入「状态」副行** | 生命周期状态里的「CK 失效」就是 CK 的结论,两列在说同一件事。合并后主标签给结论、副行小字给细节(检测时间 / `error` 这种「状态正常但没查明白」) |
| **绑定列:三个都 unknown 时显示「—」** | 满屏问号只是噪声,不如一眼看出「还没查过绑定」 |
| **「上传时间」→「导入时间」,精确到日** | 名字一直叫错;列表里只关心「哪一批」,时分秒是噪声(精确值挪进 tooltip) |
| **去掉「按状态筛选」下拉** | 上面卡片就是筛选入口,两处并存是重复(`STATUS_OPTIONS` 随之删除) |
## 验证
- `TZ=Asia/Shanghai`:**500 passed / 6 skipped**(+3 条 summary 用例)
- `TZ=UTC`(相关文件)82 passed;ruff 全绿
- 前端 build 通过、`npm run lint` **0 errors**
- 真实开发库:`by_status = {active: 4, imported: 8}`、`ck_invalid_count=0`、
`no_cookie_count=8`、`visible_total=12`(与库内实际一致)
未动(待确认):「显示凭据」开关与密码/邮箱/邮箱密码三列 —— 这是老「卖号」视图的残留,
默认关闭所以不占地方,但不确定现在的重登/检测流程还需不需要人工读凭据。
This commit is contained in:
@@ -298,8 +298,34 @@ def accounts_summary(
|
||||
.scalar()
|
||||
or 0
|
||||
)
|
||||
# 按**生命周期状态**分布:这才是可行动的(「有几个要处理」比「有几个标签」有用得多)。
|
||||
# 归档默认不计入(与列表默认口径一致 —— 归档就是「收起来别烦我」)。
|
||||
visible = query.filter(Account.status != STATUS_ARCHIVED)
|
||||
status_rows = (
|
||||
visible.with_entities(Account.status, func.count(Account.id))
|
||||
.group_by(Account.status)
|
||||
.all()
|
||||
)
|
||||
by_status = {str(row[0] or ""): int(row[1] or 0) for row in status_rows}
|
||||
visible_total = sum(by_status.values())
|
||||
return {
|
||||
"total": total,
|
||||
"visible_total": visible_total,
|
||||
# 生命周期分布(键是 6 状态的枚举值)
|
||||
"by_status": by_status,
|
||||
# 需要人关注的:CK 已被判失效的账号数(含待人工)
|
||||
"ck_invalid_count": int(
|
||||
visible.filter(Account.ck_check_status == "invalid")
|
||||
.with_entities(func.count(Account.id))
|
||||
.scalar()
|
||||
or 0
|
||||
),
|
||||
"no_cookie_count": int(
|
||||
visible.filter(or_(Account.cookie.is_(None), Account.cookie == ""))
|
||||
.with_entities(func.count(Account.id))
|
||||
.scalar()
|
||||
or 0
|
||||
),
|
||||
"assigned_count": assigned_count,
|
||||
"unassigned_count": max(0, total - assigned_count),
|
||||
"tag_count": tag_count,
|
||||
|
||||
Reference in New Issue
Block a user