feat: POP 작업상세 체크리스트 UI를 judgment_criteria 기반으로 매핑
- 백엔드: /api/pop/production/checklist-items/:processId 신규 추가
process_work_result ⟕ inspection_standard(judgment_criteria) LEFT JOIN으로
한 번에 반환 (inspection_code 미설정 시 null로 안전)
- 프론트: resolveInputType + normalizeByJudgmentCriteria + normalizeByDetailType
1순위: judgment_criteria (CAT_JC_01~04) → inspect/numeric_range/ox/select/text
2순위: detail_type 폴백
- checklist/equip_inspection → check(토글)
- inspection/equip_condition/production_result → inspect(숫자 키패드)
- lookup → input(텍스트)
- material_input → material(BOM 자재)
기존 canonical 값은 건드리지 않아 회귀 없음
- fetchData는 전용 API 사용 + 실패 시 기존 dataApi.getTableData로 폴백
This commit is contained in:
@@ -2969,3 +2969,84 @@ export const getMaterialInputs = async (req: AuthenticatedRequest, res: Response
|
||||
return res.status(500).json({ success: false, message: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 체크리스트 조회 (judgment_criteria 조인 포함)
|
||||
*
|
||||
* process_work_result를 조회하면서 inspection_standard.judgment_criteria를
|
||||
* LEFT JOIN으로 같이 반환한다.
|
||||
*
|
||||
* UI는 프론트의 resolveInputType()에서
|
||||
* 1순위: judgment_criteria (CAT_JC_01~04)
|
||||
* 2순위: detail_type 폴백
|
||||
* 으로 입력 UI를 결정한다.
|
||||
*/
|
||||
export const getChecklistItems = async (
|
||||
req: AuthenticatedRequest,
|
||||
res: Response
|
||||
) => {
|
||||
const pool = getPool();
|
||||
try {
|
||||
const companyCode = req.user!.companyCode;
|
||||
const { processId } = req.params;
|
||||
if (!processId) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ success: false, message: "processId 필수" });
|
||||
}
|
||||
|
||||
const result = await pool.query(
|
||||
`SELECT
|
||||
pwr.id,
|
||||
pwr.company_code,
|
||||
pwr.work_order_process_id,
|
||||
pwr.source_work_item_id,
|
||||
pwr.source_detail_id,
|
||||
pwr.work_phase,
|
||||
pwr.item_title,
|
||||
pwr.item_sort_order,
|
||||
pwr.detail_content,
|
||||
pwr.detail_type,
|
||||
pwr.detail_sort_order,
|
||||
pwr.is_required,
|
||||
pwr.inspection_code,
|
||||
pwr.inspection_method,
|
||||
pwr.unit,
|
||||
pwr.lower_limit,
|
||||
pwr.upper_limit,
|
||||
pwr.input_type,
|
||||
pwr.lookup_target,
|
||||
pwr.display_fields,
|
||||
pwr.duration_minutes,
|
||||
pwr.status,
|
||||
pwr.result_value,
|
||||
pwr.is_passed,
|
||||
pwr.remark,
|
||||
pwr.recorded_by,
|
||||
pwr.recorded_at,
|
||||
pwr.started_at,
|
||||
pwr.group_started_at,
|
||||
pwr.group_paused_at,
|
||||
pwr.group_total_paused_time,
|
||||
pwr.group_completed_at,
|
||||
ist.judgment_criteria
|
||||
FROM process_work_result pwr
|
||||
LEFT JOIN inspection_standard ist
|
||||
ON pwr.inspection_code = ist.inspection_code
|
||||
AND pwr.company_code = ist.company_code
|
||||
WHERE pwr.work_order_process_id = $1
|
||||
AND pwr.company_code = $2
|
||||
ORDER BY
|
||||
COALESCE(NULLIF(pwr.item_sort_order, '')::int, 0),
|
||||
COALESCE(NULLIF(pwr.detail_sort_order, '')::int, 0)`,
|
||||
[processId, companyCode]
|
||||
);
|
||||
|
||||
return res.json({ success: true, data: result.rows });
|
||||
} catch (error: any) {
|
||||
logger.error("[pop/production] checklist-items 조회 오류:", error);
|
||||
return res
|
||||
.status(500)
|
||||
.json({ success: false, message: error.message });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
getBomMaterials,
|
||||
saveMaterialInput,
|
||||
getMaterialInputs,
|
||||
getChecklistItems,
|
||||
} from "../controllers/popProductionController";
|
||||
|
||||
const router = Router();
|
||||
@@ -49,5 +50,6 @@ router.get("/rework-history/:woId", getReworkHistory);
|
||||
router.get("/bom-materials/:processId", getBomMaterials);
|
||||
router.post("/material-input", saveMaterialInput);
|
||||
router.get("/material-inputs/:processId", getMaterialInputs);
|
||||
router.get("/checklist-items/:processId", getChecklistItems);
|
||||
|
||||
export default router;
|
||||
|
||||
Reference in New Issue
Block a user