diff --git a/API文档.md b/API文档.md index da1b629..4bafbe4 100644 --- a/API文档.md +++ b/API文档.md @@ -486,6 +486,8 @@ Set-Cookie: auth_token=a1b2c3d4e5f6...; HttpOnly; Max-Age=31536000; SameSite=Lax ### GET /api/tasks/{account_id} **说明**: 按账号 ID 查询任务列表(不支持按 task_id 查询)。 +- 不传 `page/page_size`:返回任务数组(兼容旧版前端) +- 传 `page` 或 `page_size`:返回分页对象 **状态码**: @@ -500,8 +502,36 @@ Set-Cookie: auth_token=a1b2c3d4e5f6...; HttpOnly; Max-Age=31536000; SameSite=Lax | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | account_id | int | 是 | 账号 ID(即 `/api/accounts` 返回的 `id`) | +| status | string | 否 | 按状态过滤:`pending` / `dispatched` / `running` / `success` / `failed` / `cancelled` | +| limit | int | 否 | 兼容参数,不分页模式下表示最多返回条数;分页模式下可作为 `page_size` 默认值 | +| page | int | 否 | 分页页码(从 1 开始) | +| page_size | int | 否 | 每页条数,默认 20,最大 200 | -**成功响应** (200): 同上任务对象数组 +**成功响应** (200): +- 兼容模式:同上任务对象数组 +- 分页模式: +```json +{ + "total": 123, + "page": 1, + "page_size": 20, + "results": [ + { + "task_id": "3f113d90bb32", + "task_type": "check_login", + "status": "success", + "worker_id": "worker-1", + "account_name": "第一个", + "params": {}, + "progress": null, + "result": {}, + "error": null, + "created_at": "2026-03-01T20:00:00", + "updated_at": "2026-03-01T20:00:00" + } + ] +} +``` **失败响应** (404): ```json diff --git a/server/api/tasks.py b/server/api/tasks.py index 0de241e..5f606b0 100644 --- a/server/api/tasks.py +++ b/server/api/tasks.py @@ -56,6 +56,17 @@ def _parse_limit(raw_value, default: int = 50, max_value: int = 200) -> int: return min(value, max_value) +def _parse_positive_int(raw_value, default: int = 1) -> int: + """解析正整数参数。""" + try: + value = int(raw_value) + except (TypeError, ValueError): + return default + if value <= 0: + return default + return value + + def _parse_task_status(raw_status: Optional[str]) -> Optional[TaskStatus]: """解析任务状态。为空时返回 None。""" if not raw_status: @@ -122,7 +133,7 @@ def _is_task_log_for_account(task_log: TaskLog, account: BossAccount) -> bool: return False -def _list_tasks_by_account(account: BossAccount, task_status: Optional[TaskStatus], limit: int) -> list: +def _list_tasks_by_account(account: BossAccount, task_status: Optional[TaskStatus], limit: Optional[int] = 50) -> list: """ 聚合某账号的任务列表: 1) 内存任务(实时) @@ -142,7 +153,8 @@ def _list_tasks_by_account(account: BossAccount, task_status: Optional[TaskStatu db_qs = db_qs.filter(status=task_status.value) # 多取一些做过滤,避免因为条件匹配损耗导致结果太少 - for task_log in db_qs[: max(limit * 8, 200)]: + db_logs = db_qs if limit is None else db_qs[: max(limit * 8, 200)] + for task_log in db_logs: if not _is_task_log_for_account(task_log, account): continue if task_log.task_id in items_by_task_id: @@ -151,6 +163,8 @@ def _list_tasks_by_account(account: BossAccount, task_status: Optional[TaskStatu merged = list(items_by_task_id.values()) merged.sort(key=lambda item: item.get("created_at") or "", reverse=True) + if limit is None: + return merged return merged[:limit] @@ -284,7 +298,11 @@ def task_list(request): @api_view(["GET"]) def task_list_by_account(request, account_id: int): - """按账号 ID 查询任务列表(不支持按 task_id 查询)。""" + """ + 按账号 ID 查询任务列表(不支持按 task_id 查询)。 + - 兼容模式:不传 page/page_size 时,返回数组 + - 分页模式:传 page 或 page_size 时,返回 {total, page, page_size, results} + """ account = BossAccount.objects.filter(pk=account_id).first() if not account: return api_error(http_status.HTTP_404_NOT_FOUND, f"账号 {account_id} 不存在") @@ -294,5 +312,27 @@ def task_list_by_account(request, account_id: int): if st and task_status is None: return api_error(http_status.HTTP_400_BAD_REQUEST, f"不支持的任务状态: {st}") - limit = _parse_limit(request.query_params.get("limit", 50)) - return api_success(_list_tasks_by_account(account, task_status=task_status, limit=limit)) + # 旧接口兼容:默认返回数组,limit 控制条数 + enable_paging = ("page" in request.query_params) or ("page_size" in request.query_params) + if not enable_paging: + limit = _parse_limit(request.query_params.get("limit", 50)) + return api_success(_list_tasks_by_account(account, task_status=task_status, limit=limit)) + + page = _parse_positive_int(request.query_params.get("page"), default=1) + page_size = _parse_limit( + request.query_params.get("page_size", request.query_params.get("limit", 20)), + default=20, + max_value=200, + ) + + all_items = _list_tasks_by_account(account, task_status=task_status, limit=None) + total = len(all_items) + start = (page - 1) * page_size + end = start + page_size + + return api_success({ + "total": total, + "page": page, + "page_size": page_size, + "results": all_items[start:end], + })