diff --git a/backend-node/src/controllers/popProductionController.ts b/backend-node/src/controllers/popProductionController.ts
index 92cba89d..dabb2f1f 100644
--- a/backend-node/src/controllers/popProductionController.ts
+++ b/backend-node/src/controllers/popProductionController.ts
@@ -359,11 +359,21 @@ export const syncWorkInstructions = async (
});
// 미동기화 작업지시 조회: routing이 있지만 work_order_process가 없는 항목
+ // header에 routing 없으면 detail에서 가져옴 (PC가 detail에만 저장하는 경우 대응)
const unsyncedResult = await pool.query(
- `SELECT wi.id, wi.work_instruction_no, wi.routing, wi.qty
+ `SELECT wi.id, wi.work_instruction_no,
+ COALESCE(wi.routing, wid.routing_version_id) AS routing,
+ COALESCE(NULLIF(wi.qty, ''), wid.qty) AS qty,
+ COALESCE(wi.item_id, (SELECT id FROM item_info WHERE item_number = wid.item_number AND company_code = $1 LIMIT 1)) AS item_id
FROM work_instruction wi
+ LEFT JOIN LATERAL (
+ SELECT routing_version_id, qty, item_number
+ FROM work_instruction_detail
+ WHERE work_instruction_no = wi.work_instruction_no AND company_code = $1
+ LIMIT 1
+ ) wid ON true
WHERE wi.company_code = $1
- AND wi.routing IS NOT NULL
+ AND COALESCE(wi.routing, wid.routing_version_id) IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM work_order_process wop
WHERE wop.wo_id = wi.id AND wop.company_code = $1
@@ -373,6 +383,20 @@ export const syncWorkInstructions = async (
const unsynced = unsyncedResult.rows;
+ // header에 routing/qty/item_id가 비어있으면 자동 보정 (detail → header 동기화)
+ for (const wi of unsynced) {
+ await pool.query(
+ `UPDATE work_instruction SET
+ routing = COALESCE(routing, $2),
+ qty = COALESCE(NULLIF(qty, ''), $3),
+ item_id = COALESCE(item_id, $4),
+ updated_date = NOW()
+ WHERE id = $1 AND company_code = $5
+ AND (routing IS NULL OR qty IS NULL OR qty = '' OR item_id IS NULL)`,
+ [wi.id, wi.routing, wi.qty, wi.item_id, companyCode],
+ );
+ }
+
if (unsynced.length === 0) {
return res.json({
success: true,
diff --git a/frontend/components/pop/hardcoded/production/ProcessWork.tsx b/frontend/components/pop/hardcoded/production/ProcessWork.tsx
index 1675aad3..6f603e43 100644
--- a/frontend/components/pop/hardcoded/production/ProcessWork.tsx
+++ b/frontend/components/pop/hardcoded/production/ProcessWork.tsx
@@ -1208,34 +1208,45 @@ export function ProcessWork({ processId }: ProcessWorkProps) {
behavior: "smooth",
});
}}
- className={`w-full flex items-center gap-2 px-3 py-2 text-left transition-all ${
+ className={`w-full flex items-center gap-3 mx-2 mb-1.5 px-3 py-3 rounded-xl text-left transition-all ${
isSelected
- ? "border-l-[3px] border-l-gray-900 bg-white"
- : "border-l-[3px] border-l-transparent hover:bg-gray-50"
+ ? "bg-blue-50 border-2 border-blue-400 shadow-sm"
+ : isDone
+ ? "bg-green-50/50 border border-green-200"
+ : "bg-white border border-gray-200 hover:border-blue-300 hover:shadow-sm"
}`}
+ style={{ width: "calc(100% - 16px)" }}
>
{g.title}
{g.completed}/{g.total}
@@ -1259,15 +1270,16 @@ export function ProcessWork({ processId }: ProcessWorkProps) {
behavior: "smooth",
});
}}
- className={`w-full flex items-center gap-2 px-3 py-2.5 mb-2 text-left transition-all ${
+ className={`w-full flex items-center gap-3 mx-2 mb-1.5 px-3 py-3 rounded-xl text-left transition-all ${
activeSection === "material"
- ? "border-l-[3px] border-l-gray-900 bg-white"
- : "border-l-[3px] border-l-transparent hover:bg-gray-50"
+ ? "bg-blue-50 border-2 border-blue-400 shadow-sm"
+ : "bg-white border border-gray-200 hover:border-blue-300 hover:shadow-sm"
}`}
+ style={{ width: "calc(100% - 16px)" }}
>
- 📦
+ 📦
자재 투입