feat: 在制品附加信息补全 — 设备名称|规格型号|序列号|身份证
后端: WipTask 新增 spec_model, 查询关联 Product.spec_model 前端: 第二行格式改为 物料|规格|序列号:xxx|身份证:xxx
This commit is contained in:
@ -28,9 +28,10 @@ class WipTask(BaseModel):
|
||||
task_id: str
|
||||
task_name: str
|
||||
assignee: str
|
||||
product_sn: str
|
||||
product_sn: str # 16位HEX身份证
|
||||
external_serial: str | None # 业务序列号
|
||||
material_name: str # 物料名称
|
||||
material_name: str # 设备名称
|
||||
spec_model: str # 规格型号
|
||||
status: str
|
||||
received_at: str
|
||||
duration_hours: float
|
||||
@ -133,7 +134,7 @@ async def get_wip_tasks(db: AsyncSession, limit: int = 20) -> list[WipTask]:
|
||||
from app.core.time_utils import get_beijing_time, BEIJING_TZ
|
||||
|
||||
stmt = (
|
||||
select(Task, Product.serial_number, Product.external_serial, Product.material_name)
|
||||
select(Task, Product.serial_number, Product.external_serial, Product.material_name, Product.spec_model)
|
||||
.join(Product, Task.product_id == Product.id)
|
||||
.where(Task.status.in_([TASK_STATUS_PENDING, TASK_STATUS_WIP]))
|
||||
.limit(limit * 2)
|
||||
@ -149,7 +150,7 @@ async def get_wip_tasks(db: AsyncSession, limit: int = 20) -> list[WipTask]:
|
||||
|
||||
now = get_beijing_time()
|
||||
wip_list: list[WipTask] = []
|
||||
for task, product_sn, ext_sn, mat_name in rows:
|
||||
for task, product_sn, ext_sn, mat_name, spec in rows:
|
||||
start = task.received_at or task.created_at
|
||||
if start:
|
||||
if start.tzinfo is None:
|
||||
@ -169,6 +170,7 @@ async def get_wip_tasks(db: AsyncSession, limit: int = 20) -> list[WipTask]:
|
||||
product_sn=product_sn or "",
|
||||
external_serial=ext_sn or None,
|
||||
material_name=mat_name or "",
|
||||
spec_model=spec or "",
|
||||
status=task.status,
|
||||
received_at=recv_str,
|
||||
duration_hours=hours,
|
||||
|
||||
@ -86,8 +86,6 @@ function WipRow({ t }: { t: WipTask }) {
|
||||
window.open(`${base}/scan?sn=${t.product_sn}`, "_blank");
|
||||
}
|
||||
};
|
||||
const sn = t.external_serial || "未录入";
|
||||
const trace = t.product_sn ? t.product_sn.slice(-6) : "";
|
||||
return (
|
||||
<div
|
||||
onClick={handleClick}
|
||||
@ -109,11 +107,15 @@ function WipRow({ t }: { t: WipTask }) {
|
||||
{durationLabel(t.duration_hours)}
|
||||
</span>
|
||||
</div>
|
||||
{/* 附加信息行:物料名 + 序列号 + 身份证后6位 + 接收时间 */}
|
||||
<div className="mt-1.5 flex items-center gap-2 text-[11px] text-gray-400">
|
||||
{t.material_name && <span className="font-medium text-gray-500">{t.material_name}</span>}
|
||||
<span>SN: {sn}</span>
|
||||
<span className="font-mono text-gray-300">…{trace}</span>
|
||||
{/* 附加信息行 */}
|
||||
<div className="mt-1.5 flex items-center gap-1.5 text-[11px] text-gray-400">
|
||||
<span className="font-medium text-gray-500">{t.material_name || "未知设备"}</span>
|
||||
<span className="text-gray-300">|</span>
|
||||
<span>{t.spec_model || "无规格"}</span>
|
||||
<span className="text-gray-300">|</span>
|
||||
<span>序列号: {t.external_serial || "未录入"}</span>
|
||||
<span className="text-gray-300">|</span>
|
||||
<span className="font-mono text-gray-300">身份证: {t.product_sn}</span>
|
||||
{t.received_at && <span className="ml-auto">{t.received_at}</span>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -22,6 +22,7 @@ export interface WipTask {
|
||||
product_sn: string;
|
||||
external_serial: string | null;
|
||||
material_name: string;
|
||||
spec_model: string;
|
||||
status: string;
|
||||
received_at: string;
|
||||
duration_hours: number;
|
||||
|
||||
Reference in New Issue
Block a user