feat(services): 核心业务逻辑 — 接收/返工/裂变/记录/标签打印
task_service: - receive_task() — PENDING→WIP, 记录 received_at - reject_task() — →REJECTED + 自动返工闭环 - transfer_task() — →COMPLETED + 多路裂变 + virtual_warehouse入库 - add_task_record() — 图文记录追加 - 全链路 selectinload(Task.records) - 全部 now 改用 get_beijing_time() product_service: - create_product() — PG Sequence 自动生成16位HEX - update_overall_status() — 宏观状态校验+更新 - 扫码返回完整 task_tree (含 records) - order_no 自由文本→自动创建 ProductionOrder - update_product() 支持 order_no 编辑 label_service: - 480×360 工业级排版 (QR+名/规/单+底部通栏码) - simhei.ttf 34px/28px + stroke_width 描边 - TSPL Socket 发送到打标机
This commit is contained in:
@ -1,13 +1,13 @@
|
||||
"""任务服务 — 核心业务逻辑:接收、驳回返工、裂变转交、无限嵌套子任务"""
|
||||
from __future__ import annotations
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
from fastapi import HTTPException, status
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import selectinload
|
||||
|
||||
from app.models.task import Task, TASK_STATUS_PENDING, TASK_STATUS_WIP, TASK_STATUS_COMPLETED, TASK_STATUS_REJECTED
|
||||
from app.models.task import Task, TaskRecord, TASK_STATUS_PENDING, TASK_STATUS_WIP, TASK_STATUS_COMPLETED, TASK_STATUS_REJECTED
|
||||
from app.core.time_utils import get_beijing_time
|
||||
from app.models.product import Product
|
||||
from app.models.task_log import TaskLog
|
||||
from app.schemas.task import (
|
||||
@ -17,6 +17,8 @@ from app.schemas.task import (
|
||||
TaskRejectRequest,
|
||||
TaskTransferRequest,
|
||||
SubtaskCreate,
|
||||
TaskRecordCreate,
|
||||
TaskRecordResponse,
|
||||
TaskResponse,
|
||||
TaskCompleteResponse,
|
||||
TaskTransferResponse,
|
||||
@ -40,6 +42,7 @@ async def _get_task_or_404(db: AsyncSession, task_id: uuid.UUID) -> Task:
|
||||
selectinload(Task.child_tasks),
|
||||
selectinload(Task.parent_task),
|
||||
selectinload(Task.product),
|
||||
selectinload(Task.records),
|
||||
)
|
||||
.where(Task.id == task_id)
|
||||
)
|
||||
@ -56,7 +59,10 @@ async def _get_task_with_children_recursive(db: AsyncSession, task_id: uuid.UUID
|
||||
"""递归加载任务及其所有子孙任务"""
|
||||
result = await db.execute(
|
||||
select(Task)
|
||||
.options(selectinload(Task.child_tasks))
|
||||
.options(
|
||||
selectinload(Task.child_tasks),
|
||||
selectinload(Task.records),
|
||||
)
|
||||
.where(Task.id == task_id)
|
||||
)
|
||||
task = result.scalar_one_or_none()
|
||||
@ -71,7 +77,10 @@ async def _get_task_with_children_recursive(db: AsyncSession, task_id: uuid.UUID
|
||||
for child in t.child_tasks:
|
||||
child_result = await db.execute(
|
||||
select(Task)
|
||||
.options(selectinload(Task.child_tasks))
|
||||
.options(
|
||||
selectinload(Task.child_tasks),
|
||||
selectinload(Task.records),
|
||||
)
|
||||
.where(Task.id == child.id)
|
||||
)
|
||||
refreshed_child = child_result.scalar_one()
|
||||
@ -87,6 +96,8 @@ def _to_response(task: Task) -> TaskResponse:
|
||||
return TaskResponse(
|
||||
id=task.id,
|
||||
product_id=task.product_id,
|
||||
product_sn=task.product.serial_number if task.product else "",
|
||||
product_material=task.product.material_name or task.product.material_id or "" if task.product else "",
|
||||
parent_task_id=task.parent_task_id,
|
||||
task_name=task.task_name,
|
||||
assignee_id=task.assignee_id,
|
||||
@ -98,6 +109,7 @@ def _to_response(task: Task) -> TaskResponse:
|
||||
completed_at=task.completed_at,
|
||||
created_at=task.created_at,
|
||||
child_tasks=[_to_response(c) for c in task.child_tasks],
|
||||
records=[TaskRecordResponse.model_validate(r) for r in (task.records or [])],
|
||||
)
|
||||
|
||||
|
||||
@ -187,12 +199,19 @@ async def update_task(db: AsyncSession, task_id: uuid.UUID, data: TaskUpdate) ->
|
||||
|
||||
|
||||
async def get_all_tasks(
|
||||
db: AsyncSession, product_id: uuid.UUID | None = None, skip: int = 0, limit: int = 50
|
||||
db: AsyncSession, product_id: uuid.UUID | None = None,
|
||||
assignee_id: str | None = None, skip: int = 0, limit: int = 50
|
||||
) -> TaskListResponse:
|
||||
"""获取任务列表,可按产品筛选"""
|
||||
stmt = select(Task).options(selectinload(Task.child_tasks))
|
||||
"""获取任务列表,可按产品/负责人筛选"""
|
||||
stmt = select(Task).options(
|
||||
selectinload(Task.child_tasks),
|
||||
selectinload(Task.records),
|
||||
selectinload(Task.product),
|
||||
)
|
||||
if product_id:
|
||||
stmt = stmt.where(Task.product_id == product_id)
|
||||
if assignee_id:
|
||||
stmt = stmt.where(Task.assignee_id == assignee_id)
|
||||
stmt = stmt.offset(skip).limit(limit).order_by(Task.created_at.desc())
|
||||
|
||||
result = await db.execute(stmt)
|
||||
@ -225,7 +244,7 @@ async def receive_task(
|
||||
detail=f"只有待接收(PENDING)状态的任务可接收,当前状态: {task.status}",
|
||||
)
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
now = get_beijing_time()
|
||||
task.status = TASK_STATUS_WIP
|
||||
task.received_at = now
|
||||
|
||||
@ -269,7 +288,7 @@ async def reject_task(
|
||||
detail=f"任务状态为 {task.status},无法驳回",
|
||||
)
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
now = get_beijing_time()
|
||||
|
||||
# --- 1. 标记当前任务为已驳回 ---
|
||||
task.status = TASK_STATUS_REJECTED
|
||||
@ -364,7 +383,7 @@ async def transfer_task(
|
||||
detail=f"请等待相关子任务完成:{', '.join(incomplete_names)}",
|
||||
)
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
now = get_beijing_time()
|
||||
|
||||
# --- 动作 1:闭环当前节点 ---
|
||||
task.status = TASK_STATUS_COMPLETED
|
||||
@ -501,7 +520,7 @@ async def complete_task(
|
||||
detail=f"请等待相关子任务完成:{', '.join(incomplete_names)}",
|
||||
)
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
now = get_beijing_time()
|
||||
|
||||
# --- 3. 标记当前任务为已完成 ---
|
||||
task.status = TASK_STATUS_COMPLETED
|
||||
@ -591,3 +610,28 @@ async def create_subtask(
|
||||
await db.commit()
|
||||
|
||||
return _to_response(subtask)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 任务进度记录 — 随时备注/传图
|
||||
# ============================================================
|
||||
|
||||
async def add_task_record(
|
||||
db: AsyncSession, task_id: uuid.UUID, data: TaskRecordCreate
|
||||
) -> TaskResponse:
|
||||
"""追加进度记录(备注+图片),不改变任务状态"""
|
||||
import json
|
||||
|
||||
task = await _get_task_with_children_recursive(db, task_id)
|
||||
|
||||
record = TaskRecord(
|
||||
task_id=task_id,
|
||||
remark=data.remark or None,
|
||||
images=json.dumps(data.images) if data.images else None,
|
||||
)
|
||||
db.add(record)
|
||||
await db.commit()
|
||||
await db.refresh(record)
|
||||
|
||||
# 重新加载 task 带上新 record
|
||||
return await get_task(db, task_id)
|
||||
|
||||
Reference in New Issue
Block a user