feat: 当前位置100%动态主干化—与宏观状态同源,只跟主分支,静态字段仅兜底
This commit is contained in:
@ -392,10 +392,6 @@ async def get_all_products(
|
|||||||
result = await db.execute(stmt)
|
result = await db.execute(stmt)
|
||||||
products = result.scalars().all()
|
products = result.scalars().all()
|
||||||
|
|
||||||
# 批量查询当前位置对应的真实姓名
|
|
||||||
location_ids = [p.current_location_id for p in products if p.current_location_id]
|
|
||||||
name_map = _lookup_display_names(location_ids)
|
|
||||||
|
|
||||||
# 🔧 批量预计算 macro_status:一次性查出所有产品关联的任务状态
|
# 🔧 批量预计算 macro_status:一次性查出所有产品关联的任务状态
|
||||||
product_ids = [p.id for p in products]
|
product_ids = [p.id for p in products]
|
||||||
macro_map: dict[uuid.UUID, str] = {}
|
macro_map: dict[uuid.UUID, str] = {}
|
||||||
@ -420,52 +416,55 @@ async def get_all_products(
|
|||||||
for row in task_result:
|
for row in task_result:
|
||||||
macro_map[row[0]] = prio_to_status.get(row[1], None)
|
macro_map[row[0]] = prio_to_status.get(row[1], None)
|
||||||
|
|
||||||
# 🔧 动态宏观状态:只从主干任务中获取最高优先级任务的 task_name
|
# 🔧 动态主干状态+位置:只从主干任务中获取最高优先级任务的 task_name + assignee_id
|
||||||
overall_names: dict[uuid.UUID, str] = {}
|
overall_names: dict[uuid.UUID, str] = {}
|
||||||
|
main_assignees: dict[uuid.UUID, str] = {}
|
||||||
if product_ids:
|
if product_ids:
|
||||||
from sqlalchemy import func as sa_func2, case as sa_case2
|
from sqlalchemy import func as sa_func2, case as sa_case2
|
||||||
# 先找每个产品中优先级最高的主干任务ID
|
main_where = sa_func2.and_(
|
||||||
main_prio_stmt = (
|
Task.product_id.in_(product_ids),
|
||||||
select(
|
sa_func2.or_(
|
||||||
Task.product_id,
|
Task.parent_task_id.is_(None),
|
||||||
sa_func2.max(sa_case2(
|
Task.task_type.in_(["TRANSFER", "RECOVERY"]),
|
||||||
(Task.status == "WIP", 3),
|
),
|
||||||
(Task.status == "PENDING", 2),
|
|
||||||
(Task.status == "COMPLETED", 1),
|
|
||||||
else_=0,
|
|
||||||
)).label("prio"),
|
|
||||||
)
|
|
||||||
.where(
|
|
||||||
Task.product_id.in_(product_ids),
|
|
||||||
sa_func2.or_(
|
|
||||||
Task.parent_task_id.is_(None),
|
|
||||||
Task.task_type.in_(["TRANSFER", "RECOVERY"]),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.group_by(Task.product_id)
|
|
||||||
).subquery()
|
|
||||||
# 再 join 回去拿 task_name
|
|
||||||
name_stmt = (
|
|
||||||
select(Task.product_id, Task.task_name)
|
|
||||||
.join(main_prio_stmt, sa_func2.and_(
|
|
||||||
Task.product_id == main_prio_stmt.c.product_id,
|
|
||||||
sa_case2(
|
|
||||||
(Task.status == "WIP", 3),
|
|
||||||
(Task.status == "PENDING", 2),
|
|
||||||
(Task.status == "COMPLETED", 1),
|
|
||||||
else_=0,
|
|
||||||
) == main_prio_stmt.c.prio,
|
|
||||||
sa_func2.or_(
|
|
||||||
Task.parent_task_id.is_(None),
|
|
||||||
Task.task_type.in_(["TRANSFER", "RECOVERY"]),
|
|
||||||
),
|
|
||||||
))
|
|
||||||
.order_by(Task.created_at.desc())
|
|
||||||
.limit(1)
|
|
||||||
)
|
)
|
||||||
name_result = await db.execute(name_stmt)
|
prio_expr = sa_case2(
|
||||||
for row in name_result:
|
(Task.status == "WIP", 3),
|
||||||
overall_names[row[0]] = row[1]
|
(Task.status == "PENDING", 2),
|
||||||
|
(Task.status == "COMPLETED", 1),
|
||||||
|
else_=0,
|
||||||
|
)
|
||||||
|
# 子查询:每个产品最高优先级主干任务
|
||||||
|
max_prio = (
|
||||||
|
select(Task.product_id, sa_func2.max(prio_expr).label("prio"))
|
||||||
|
.where(main_where)
|
||||||
|
.group_by(Task.product_id)
|
||||||
|
).subquery("mp")
|
||||||
|
# JOIN 回 tasks 拿 task_name + assignee_id(同优先级取最新创建的)
|
||||||
|
main_stmt = (
|
||||||
|
select(Task.product_id, Task.task_name, Task.assignee_id)
|
||||||
|
.join(max_prio, sa_func2.and_(
|
||||||
|
Task.product_id == max_prio.c.product_id,
|
||||||
|
prio_expr == max_prio.c.prio,
|
||||||
|
))
|
||||||
|
.where(main_where)
|
||||||
|
.order_by(Task.product_id, Task.created_at.desc())
|
||||||
|
.distinct(Task.product_id) # PostgreSQL DISTINCT ON
|
||||||
|
)
|
||||||
|
main_result = await db.execute(main_stmt)
|
||||||
|
for row in main_result:
|
||||||
|
pid, tname, assignee = row[0], row[1], row[2]
|
||||||
|
overall_names[pid] = tname
|
||||||
|
if assignee: main_assignees[pid] = assignee
|
||||||
|
|
||||||
|
# 🔧 动态主干的 assignee_id → 查中文姓名
|
||||||
|
dynamic_location_ids = list(main_assignees.values())
|
||||||
|
dynamic_name_map = _lookup_display_names(dynamic_location_ids)
|
||||||
|
|
||||||
|
# 🔧 合并:静态位置姓名(兜底)+ 动态主干位置姓名(优先)
|
||||||
|
static_location_ids = [p.current_location_id for p in products if p.current_location_id]
|
||||||
|
merged_location_ids = list(set(static_location_ids + dynamic_location_ids))
|
||||||
|
merged_name_map = _lookup_display_names(merged_location_ids)
|
||||||
|
|
||||||
return [
|
return [
|
||||||
ProductResponse(
|
ProductResponse(
|
||||||
@ -480,14 +479,19 @@ async def get_all_products(
|
|||||||
category=p.category,
|
category=p.category,
|
||||||
material_type=p.material_type,
|
material_type=p.material_type,
|
||||||
parent_product_id=p.parent_product_id,
|
parent_product_id=p.parent_product_id,
|
||||||
current_location_id=p.current_location_id,
|
# 🔧 当前位置:动态主干assignee优先 → 静态兜底
|
||||||
|
current_location_id=(
|
||||||
|
main_assignees.get(p.id) # 动态主干
|
||||||
|
or p.current_location_id # 静态兜底
|
||||||
|
),
|
||||||
current_location_name=(
|
current_location_name=(
|
||||||
"仓库" if p.current_location_id == "virtual_warehouse"
|
"仓库" if (main_assignees.get(p.id) or p.current_location_id) == "virtual_warehouse"
|
||||||
else name_map.get(p.current_location_id) if p.current_location_id
|
else dynamic_name_map.get(main_assignees.get(p.id, ""))
|
||||||
|
or merged_name_map.get(p.current_location_id) if p.current_location_id
|
||||||
else None
|
else None
|
||||||
),
|
),
|
||||||
macro_status=macro_map.get(p.id) or p.status,
|
macro_status=macro_map.get(p.id) or p.status,
|
||||||
overall_status=overall_names.get(p.id) or p.overall_status, # 🔧 动态主干任务名优先
|
overall_status=overall_names.get(p.id) or p.overall_status,
|
||||||
status=p.status,
|
status=p.status,
|
||||||
created_at=p.created_at,
|
created_at=p.created_at,
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user