feat(task): 任务中心扫码接单(多端) —— 服务端任务状态机/端口/迁移
- Task 加 task_code/tags/display_priority/claimed_by/claimed_at/doing_at;新增 TaskClaim 流水表。
- TaskService 加 claimed/doing/completed 状态机(claim/start_doing/complete),grab 并入 claim。
- TaskRepository 加 list_published/get_by_code/update/claim/set_doing + TaskClaimRepository;挂 Database。
- 端口:
· opc /tasks/grab-by-code、/tasks/{id}/doing、/tasks/{id}/complete
· operator POST /tasks(auto task_code) + PATCH /tasks/:id
· park /park/api/tasks(大屏展示,含 scan_payload 二维码载荷)
· training /api/tasks/claim-by-code、/api/tasks/my(小程序 C 端账号→OPC 身份 find-or-create 领单)
- 迁移 0008(tasks 加列 + task_claims)已应用+stamp;seed 补 task_code/tags/grab demo。
- tests/test_task_claim.py(自包含内存库, 状态机+流水+list_published), 直接 async 校验通过。
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -18,11 +18,49 @@ class TaskService:
|
||||
self.db = db
|
||||
|
||||
async def grab(self, task_id: str, actor: dict) -> dict:
|
||||
"""抢单:仅 published + grab 模式可抢,抢后置 in_progress。"""
|
||||
"""抢单(兼容旧入口):published + grab → claimed,记录接单流水。"""
|
||||
return await self.claim_by_id(task_id, actor, source="grab")
|
||||
|
||||
async def claim(self, task_code: str, actor: dict, source: str = "scan") -> dict:
|
||||
"""扫码/按短码接单:解析 task_code 后领单。"""
|
||||
task = await self.db.tasks.get_by_code(task_code)
|
||||
if task is None:
|
||||
raise HTTPException(status_code=404, detail="任务不存在")
|
||||
return await self.claim_by_id(task["id"], actor, source=source)
|
||||
|
||||
async def claim_by_id(self, task_id: str, actor: dict, source: str) -> dict:
|
||||
"""published + grab 模式 → claimed(claimed_by/claimed_at + TaskClaim 流水)。"""
|
||||
task = await self.db.tasks.get(task_id)
|
||||
if task is None or task["status"] != "published" or task["mode"] != "grab":
|
||||
raise HTTPException(status_code=400, detail="任务不可抢单")
|
||||
return await self.db.tasks.set_status(task_id, "in_progress")
|
||||
if task is None:
|
||||
raise HTTPException(status_code=404, detail="任务不存在")
|
||||
if task["status"] != "published":
|
||||
raise HTTPException(status_code=400, detail="任务不可接单")
|
||||
if task["mode"] != "grab":
|
||||
raise HTTPException(status_code=400, detail="任务不支持扫码接单")
|
||||
updated = await self.db.tasks.claim(task_id, actor["id"])
|
||||
await self.db.task_claims.create(
|
||||
task_id, actor["id"],
|
||||
actor.get("nickname") or actor.get("username", ""), source,
|
||||
)
|
||||
return updated
|
||||
|
||||
async def start_doing(self, task_id: str, actor: dict) -> dict:
|
||||
"""claimed → doing。"""
|
||||
task = await self.db.tasks.get(task_id)
|
||||
if task is None:
|
||||
raise HTTPException(status_code=404, detail="任务不存在")
|
||||
if task["status"] != "claimed":
|
||||
raise HTTPException(status_code=400, detail="任务未接单,无法开始")
|
||||
return await self.db.tasks.set_doing(task_id)
|
||||
|
||||
async def complete(self, task_id: str, actor: dict) -> dict:
|
||||
"""doing → completed。"""
|
||||
task = await self.db.tasks.get(task_id)
|
||||
if task is None:
|
||||
raise HTTPException(status_code=404, detail="任务不存在")
|
||||
if task["status"] != "doing":
|
||||
raise HTTPException(status_code=400, detail="任务未在进行中,无法完成")
|
||||
return await self.db.tasks.set_status(task_id, "completed")
|
||||
|
||||
async def bid(self, task_id: str, actor: dict, quote: int, plan: str) -> dict:
|
||||
"""投标:仅 published + bid 模式可投。"""
|
||||
|
||||
Reference in New Issue
Block a user