feat: 任务全景表格新增"最新动态"列

后端:
  - ProductResponse 新增 latest_record_time/content 字段
  - get_all_products 批量查询活跃任务(WIP/PENDING)的最新 task_records
  - 使用窗口函数 ROW_NUMBER() PARTITION BY product_id

前端:
  - AdminTasksPage: grid-cols-12→grid-cols-[14]
  - 表头+数据行新增"最新动态"列
  - Tooltip悬浮显示完整内容, 截断+灰字二级排版
This commit is contained in:
2026-08-12 15:43:33 +08:00
parent 1fdc607c07
commit 163d9c20bb
4 changed files with 53 additions and 9 deletions

View File

@ -461,6 +461,32 @@ async def get_all_products(
merged_location_ids = list(set(static_location_ids + dynamic_location_ids))
merged_name_map = _lookup_display_names(merged_location_ids)
# 🔧 批量查询每个产品活跃任务的最新记录
latest_record_map: dict[uuid.UUID, tuple] = {}
if product_ids:
from app.models.task import TaskRecord as TR
wip_pending_ids = select(Task.id).where(
and_(
Task.product_id.in_(product_ids),
Task.status.in_(["WIP", "PENDING"]),
)
).subquery()
ranked = (
select(TR.task_id, TR.remark, TR.created_at, Task.product_id,
func.row_number().over(
partition_by=Task.product_id,
order_by=TR.created_at.desc()
).label("rn"))
.join(Task, TR.task_id == Task.id)
.where(Task.id.in_(select(wip_pending_ids.c.id)))
).subquery()
rec_result = await db.execute(
select(ranked.c.product_id, ranked.c.created_at, ranked.c.remark)
.where(ranked.c.rn == 1)
)
for row in rec_result:
latest_record_map[row[0]] = (row[1], row[2])
return [
ProductResponse(
id=p.id,
@ -474,10 +500,8 @@ async def get_all_products(
category=p.category,
material_type=p.material_type,
parent_product_id=p.parent_product_id,
# 🔧 当前位置动态主干assignee优先 → 静态兜底
current_location_id=(
main_assignees.get(p.id) # 动态主干
or p.current_location_id # 静态兜底
main_assignees.get(p.id) or p.current_location_id
),
current_location_name=(
"仓库" if (main_assignees.get(p.id) or p.current_location_id) == "virtual_warehouse"
@ -489,6 +513,8 @@ async def get_all_products(
overall_status=overall_names.get(p.id) or p.overall_status,
status=p.status,
created_at=p.created_at,
latest_record_time=latest_record_map.get(p.id, (None, None))[0],
latest_record_content=latest_record_map.get(p.id, (None, None))[1],
)
for p in products
]