feat(backend): 新增 /dashboard/wip-matrix 在制品交叉聚合接口
- 规格型号×人员/工序 的设备数量聚合(WIP/PENDING任务) - dimension 参数: assignee(中文姓名)/task_name(工序名) - 返回扁平数组含 count + assignees(该交叉点主负责人列表)
This commit is contained in:
@ -12,6 +12,7 @@ from app.services.dashboard_service import (
|
|||||||
get_rejected_tasks, RejectedTask,
|
get_rejected_tasks, RejectedTask,
|
||||||
get_user_operations, UserOperation,
|
get_user_operations, UserOperation,
|
||||||
get_user_operation_detail, OperationDetail,
|
get_user_operation_detail, OperationDetail,
|
||||||
|
get_wip_matrix, WipMatrixRow,
|
||||||
get_people_workload, PersonWorkload,
|
get_people_workload, PersonWorkload,
|
||||||
get_people_history, PersonHistoryRecord,
|
get_people_history, PersonHistoryRecord,
|
||||||
search_product_messages, ProductMessageList,
|
search_product_messages, ProductMessageList,
|
||||||
@ -100,6 +101,15 @@ async def user_operations_detail(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/wip-matrix", response_model=list[WipMatrixRow])
|
||||||
|
async def wip_matrix(
|
||||||
|
dimension: str = Query("assignee", description="聚合维度: assignee(人员) / task_name(工序)"),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
):
|
||||||
|
"""在制品分布透视表 — 规格型号 × 人员/工序 的设备数量交叉聚合"""
|
||||||
|
return await get_wip_matrix(db, dimension=dimension)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/people-workload", response_model=list[PersonWorkload])
|
@router.get("/people-workload", response_model=list[PersonWorkload])
|
||||||
async def people_workload(
|
async def people_workload(
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_db),
|
||||||
|
|||||||
@ -80,6 +80,13 @@ class OperationDetail(BaseModel):
|
|||||||
time: str # 操作时间 ISO(BEIJING_TZ)
|
time: str # 操作时间 ISO(BEIJING_TZ)
|
||||||
|
|
||||||
|
|
||||||
|
class WipMatrixRow(BaseModel):
|
||||||
|
spec_model: str # 规格型号(Y 轴)
|
||||||
|
dimension_key: str # 人员姓名 或 工序名称(X 轴)
|
||||||
|
count: int = 0 # 该交叉点的设备数量
|
||||||
|
assignees: list[str] = [] # 该交叉点涉及的主负责人(中文名,去重)
|
||||||
|
|
||||||
|
|
||||||
class PersonDevice(BaseModel):
|
class PersonDevice(BaseModel):
|
||||||
product_id: str
|
product_id: str
|
||||||
serial_number: str # 16位HEX身份证
|
serial_number: str # 16位HEX身份证
|
||||||
@ -593,6 +600,64 @@ async def get_user_operations(
|
|||||||
return items
|
return items
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# 在制品分布透视表(WIP Matrix:规格型号 × 人员/工序)
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
async def get_wip_matrix(
|
||||||
|
db: AsyncSession,
|
||||||
|
dimension: str = "assignee",
|
||||||
|
) -> list[WipMatrixRow]:
|
||||||
|
"""在制品交叉聚合:Y=规格型号,X=人员 或 工序,单元格=设备数量。
|
||||||
|
|
||||||
|
dimension:
|
||||||
|
- assignee: 按任务负责人聚合(dimension_key 为中文姓名)
|
||||||
|
- task_name: 按工序名聚合(dimension_key 为工序名,附主负责人)
|
||||||
|
"""
|
||||||
|
from app.models.task import Task, TASK_STATUS_WIP, TASK_STATUS_PENDING
|
||||||
|
from app.models.product import Product
|
||||||
|
|
||||||
|
dim_expr = Task.task_name if dimension == "task_name" else Task.assignee_id
|
||||||
|
|
||||||
|
stmt = (
|
||||||
|
select(
|
||||||
|
Product.spec_model,
|
||||||
|
dim_expr,
|
||||||
|
func.count(Product.id),
|
||||||
|
func.array_agg(func.distinct(Task.assignee_id)),
|
||||||
|
)
|
||||||
|
.join(Task, Task.product_id == Product.id)
|
||||||
|
.where(Task.status.in_([TASK_STATUS_WIP, TASK_STATUS_PENDING]))
|
||||||
|
.group_by(Product.spec_model, dim_expr)
|
||||||
|
.order_by(Product.spec_model, dim_expr)
|
||||||
|
)
|
||||||
|
result = await db.execute(stmt)
|
||||||
|
rows = result.all()
|
||||||
|
|
||||||
|
# 收集负责人 ID → 中文名
|
||||||
|
raw_ids: set[str] = set()
|
||||||
|
for r in rows:
|
||||||
|
for aid in (r[3] or []):
|
||||||
|
if aid:
|
||||||
|
raw_ids.add(aid)
|
||||||
|
name_map: dict[str, str] = {}
|
||||||
|
if raw_ids:
|
||||||
|
from app.services.mom_cache import get_display_names
|
||||||
|
name_map = get_display_names(list(raw_ids))
|
||||||
|
|
||||||
|
items: list[WipMatrixRow] = []
|
||||||
|
for spec, dim_key, cnt, assignee_ids in rows:
|
||||||
|
dim_display = name_map.get(dim_key or "", dim_key or "未分配") if dimension == "assignee" else (dim_key or "—")
|
||||||
|
assignees = [name_map.get(a, a) for a in (assignee_ids or []) if a] or []
|
||||||
|
items.append(WipMatrixRow(
|
||||||
|
spec_model=spec or "未知型号",
|
||||||
|
dimension_key=dim_display,
|
||||||
|
count=cnt or 0,
|
||||||
|
assignees=assignees,
|
||||||
|
))
|
||||||
|
return items
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# 人员操作明细(点击数字下钻 — 接收/转交/上传备注)
|
# 人员操作明细(点击数字下钻 — 接收/转交/上传备注)
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user