feat: [작업지시] 절곡 공정 단계를 BD 코드 종류에 따라 필터링

This commit is contained in:
김보곤
2026-03-21 08:00:05 +09:00
parent 73223539de
commit b783e44618
2 changed files with 61 additions and 1 deletions

View File

@@ -34,6 +34,7 @@ import {
SCREEN_PROCESS_STEPS,
SLAT_PROCESS_STEPS,
BENDING_PROCESS_STEPS,
filterBendingSteps,
type WorkOrder,
type ProcessType,
type ProcessStep,
@@ -56,13 +57,15 @@ function ProcessStepPills({
processType,
currentStep,
workSteps,
itemCodes,
}: {
processType: ProcessType;
currentStep: number;
workSteps?: ProcessStep[];
itemCodes?: string[];
}) {
// 동적 workSteps 우선 사용, 없으면 하드코딩 폴백
const steps = workSteps && workSteps.length > 0
let steps = workSteps && workSteps.length > 0
? workSteps
: processType === 'screen'
? SCREEN_PROCESS_STEPS
@@ -70,6 +73,11 @@ function ProcessStepPills({
? SLAT_PROCESS_STEPS
: BENDING_PROCESS_STEPS;
// 절곡 공정: BD 코드에 따라 필요한 단계만 필터링
if (processType === 'bending' && itemCodes && itemCodes.length > 0) {
steps = filterBendingSteps(itemCodes, BENDING_PROCESS_STEPS);
}
if (steps.length === 0) {
return <p className="text-gray-500"> .</p>;
}
@@ -495,6 +503,7 @@ export function WorkOrderDetail({ orderId }: WorkOrderDetailProps) {
processType={order.processType}
currentStep={order.currentStep}
workSteps={order.workSteps}
itemCodes={order.items?.map((i) => i.itemCode).filter(Boolean) as string[]}
/>
</div>

View File

@@ -95,6 +95,54 @@ export const BENDING_PROCESS_STEPS: { key: BendingProcessStep; label: string; or
{ key: 'inspection', label: '검사', order: 4 },
];
// BD 코드 종류코드 → 필요 작업단계 매핑
export const BENDING_STEP_MAP: Record<string, BendingProcessStep[]> = {
'R': ['guide_rail', 'inspection'], // 가이드레일-벽면
'S': ['guide_rail', 'inspection'], // 가이드레일-측면
'C': ['case', 'inspection'], // 케이스
'B': ['bottom_finish', 'inspection'], // 하단마감재-스크린
'T': ['bottom_finish', 'inspection'], // 하단마감재-철재
'L': ['guide_rail', 'inspection'], // L-Bar
'G': ['guide_rail', 'inspection'], // 연기차단재
};
/**
* BD 코드에서 종류코드 추출 (BD-{종류코드}{규격코드}-{길이코드})
* 예: BD-RS-30 → 'R', BD-CF-35 → 'C'
*/
export function extractBendingTypeCode(itemCode: string): string | null {
const match = itemCode.match(/^BD-([A-Z])/);
return match ? match[1] : null;
}
/**
* 작업지시 품목들의 BD 코드로 필요한 작업단계 필터링
* 여러 품목이면 합집합(union), BD 코드 아닌 품목이면 전체 반환
*/
export function filterBendingSteps(
itemCodes: string[],
allSteps: typeof BENDING_PROCESS_STEPS
): typeof BENDING_PROCESS_STEPS {
if (!itemCodes.length) return allSteps;
const neededKeys = new Set<string>();
let hasNonBdItem = false;
for (const code of itemCodes) {
const typeCode = extractBendingTypeCode(code);
if (typeCode && BENDING_STEP_MAP[typeCode]) {
BENDING_STEP_MAP[typeCode].forEach((k) => neededKeys.add(k));
} else {
hasNonBdItem = true;
}
}
// BD 코드가 아닌 품목이 있거나 매핑 결과가 없으면 전체 반환
if (hasNonBdItem || neededKeys.size === 0) return allSteps;
return allSteps.filter((step) => neededKeys.has(step.key));
}
// 품목 상태
export type ItemStatus = 'waiting' | 'in_progress' | 'completed';
@@ -109,6 +157,7 @@ export interface WorkOrderItem {
id: string;
no: number;
status: ItemStatus;
itemCode: string;
productName: string;
floorCode: string; // 층/부호
specification: string; // 규격
@@ -255,6 +304,7 @@ export interface WorkOrderItemApi {
id: number;
work_order_id: number;
item_id: number | null;
item?: { id: number; code: string } | null;
item_name: string;
specification: string | null;
quantity: number;
@@ -471,6 +521,7 @@ export function transformApiToFrontend(api: WorkOrderApi): WorkOrder {
id: String(item.id),
no: idx + 1,
status: (item.status as ItemStatus) || 'waiting',
itemCode: item.item?.code || '',
productName: item.item_name,
floorCode: [item.source_order_item?.floor_code, item.source_order_item?.symbol_code].filter(Boolean).join('/') || '-',
specification: item.specification || '-',