feat(login): 任务列表支持分页、跨页全选与一键清空
任务量早就过了单页能装下的规模(库里 1.4 万条,单批就 177 条),但接口
硬编码 limit(200)、前端 pagination={false},于是「全选」其实只能选到前
200 条,失败任务清不干净。
- 接口加 page/page_size/status:不传 page 时仍返回裸数组(Cookie 页等
老调用方依赖这个契约,不能改);传了才返回 {items,total},total 供跨页全选。
- 删除支持 all_matching:按当前筛选条件删全部,不必先翻完所有页去勾。
- 前端:分页控件(20/50/100/200/500,记住选择)、状态筛选、表头
「选择全部 N 条(含其他页)」、「清空失败」一键操作。
两条护栏:
- **pending/running 一律不删** —— 删掉会让批次线程找不到记录;要停批次
走 /stop/{batch_id}。
- 不给任何条件就拒绝删除,绝不默认全删。
顺带:带 join 的 query 不能 bulk delete(SQLAlchemy 会拒绝),改成先查
id 再按主键删。
This commit is contained in:
@@ -52,6 +52,39 @@ live-hub-py/
|
||||
./deploy.sh reset # 重置所有数据(需二次确认)
|
||||
```
|
||||
|
||||
## 时区口径(查库前必读)
|
||||
|
||||
**全库时间列一律存 UTC 裸值**(`DATETIME`,无 `TIMESTAMP` 列、无 `CURRENT_TIMESTAMP` 默认值)。MySQL 容器以
|
||||
`--default-time-zone=+00:00` 启动,因此 **`NOW()` 返回的也是 UTC** —— 这**不是故障**,是刻意对齐存储口径。
|
||||
|
||||
| 层 | 看到的时间 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 数据库裸值 / `NOW()` | UTC | 命令行直连就是这个 |
|
||||
| ORM 读出(`UTCDateTime`) | `+00:00` aware | 读出来永远带时区,比较不会踩 naive/aware 的坑 |
|
||||
| HTTP 接口返回 | `...+00:00` | 前端按本地时区渲染 |
|
||||
| 前端显示 | 北京时间(UTC+8) | `dayjs` 自动转换 |
|
||||
| 应用日志 | 北京时间 | 容器内 `TZ=Asia/Shanghai` |
|
||||
|
||||
> ⚠️ **别拿 `SELECT NOW()` 当"真实时间"去和业务时间比对** —— 它比你手表慢 8 小时是正常的。
|
||||
> 已踩过一次:据此误判"数据库时区错了",实际端到端完全正确。
|
||||
|
||||
命令行查库要按北京时间看,用 `CONVERT_TZ`:
|
||||
|
||||
```sql
|
||||
SELECT id, status,
|
||||
CONVERT_TZ(created_at, '+00:00', '+08:00') AS 创建时间,
|
||||
CONVERT_TZ(finished_at, '+00:00', '+08:00') AS 完成时间
|
||||
FROM login_tasks ORDER BY id DESC LIMIT 10;
|
||||
```
|
||||
|
||||
按"北京时间某段"筛选用同样的换算,别直接写本地时间字面量:
|
||||
|
||||
```sql
|
||||
-- 查北京时间 10-03 09:00 之后的任务
|
||||
SELECT * FROM login_tasks
|
||||
WHERE created_at >= CONVERT_TZ('2026-10-03 09:00:00', '+08:00', '+00:00');
|
||||
```
|
||||
|
||||
## 运行时与密钥
|
||||
|
||||
生产是 **单个应用容器 + 内网 MySQL 8.4**。数据库不映射公网;本机 `./dev.sh` 通过 `127.0.0.1:3307` 连 compose 里的 MySQL。
|
||||
|
||||
Reference in New Issue
Block a user