feat(WEB): 작업일지/검사성적서 버튼 공정 레벨 설정 연동
- Process 타입에 documentTemplateId, needsWorkLog 필드 추가 (ProcessStep에서 이동) - ProcessForm에 중간검사 양식/작업일지 설정 UI 추가 - StepForm에서 해당 UI 제거 - WorkerScreen 하단 버튼 조건부 렌더링: needsWorkLog/documentTemplateId 기반
This commit is contained in:
@@ -366,6 +366,7 @@ export default function WorkerScreen() {
|
||||
const [currentInspectionSetting, setCurrentInspectionSetting] = useState<InspectionSetting | undefined>();
|
||||
// 문서 템플릿 데이터 (document_template 기반 동적 검사용)
|
||||
const [inspectionTemplateData, setInspectionTemplateData] = useState<InspectionTemplateData | undefined>();
|
||||
const [inspectionDimensions, setInspectionDimensions] = useState<{ width?: number; height?: number }>({});
|
||||
|
||||
// 중간검사 체크 상태 관리: { [itemId]: boolean }
|
||||
const [inspectionCheckedMap, setInspectionCheckedMap] = useState<Record<string, boolean>>({});
|
||||
@@ -432,6 +433,15 @@ export default function WorkerScreen() {
|
||||
return 'screen';
|
||||
}, [activeTab, processListCache]);
|
||||
|
||||
// 선택된 공정의 작업일지/검사성적서 설정
|
||||
const activeProcessSettings = useMemo(() => {
|
||||
const process = processListCache.find((p) => p.id === activeTab);
|
||||
return {
|
||||
needsWorkLog: process?.needsWorkLog ?? false,
|
||||
hasDocumentTemplate: !!process?.documentTemplateId,
|
||||
};
|
||||
}, [activeTab, processListCache]);
|
||||
|
||||
// activeTab 변경 시 해당 공정의 중간검사 설정 조회
|
||||
useEffect(() => {
|
||||
if (processListCache.length === 0 || !activeTab) return;
|
||||
@@ -570,22 +580,60 @@ export default function WorkerScreen() {
|
||||
const itemNames = group.items.map((it) => it.itemName).filter(Boolean);
|
||||
const itemSummary = itemNames.length > 0 ? itemNames.join(', ') : '-';
|
||||
|
||||
apiItems.push({
|
||||
// 첫 번째 아이템의 options에서 사이즈/공정별 정보 추출
|
||||
const firstItem = group.items[0];
|
||||
const opts = (firstItem?.options || {}) as Record<string, unknown>;
|
||||
|
||||
const workItem: WorkItemData = {
|
||||
id: `${selectedOrder.id}-node-${nodeKey}`,
|
||||
apiItemId: group.items[0]?.id as number | undefined,
|
||||
apiItemId: firstItem?.id as number | undefined,
|
||||
workOrderId: selectedOrder.id,
|
||||
itemNo: index + 1,
|
||||
itemCode: selectedOrder.orderNo || '-',
|
||||
itemName: `${group.nodeName} : ${itemSummary}`,
|
||||
floor: '-',
|
||||
code: '-',
|
||||
width: 0,
|
||||
height: 0,
|
||||
floor: (opts.floor as string) || '-',
|
||||
code: (opts.code as string) || '-',
|
||||
width: (opts.width as number) || 0,
|
||||
height: (opts.height as number) || 0,
|
||||
quantity: group.totalQuantity,
|
||||
processType: activeProcessTabKey,
|
||||
steps,
|
||||
materialInputs: [],
|
||||
});
|
||||
};
|
||||
|
||||
// 공정별 추가 정보 추출
|
||||
if (opts.cutting_info) {
|
||||
const ci = opts.cutting_info as { width: number; sheets: number };
|
||||
workItem.cuttingInfo = { width: ci.width, sheets: ci.sheets };
|
||||
}
|
||||
if (opts.slat_info) {
|
||||
const si = opts.slat_info as { length: number; slat_count: number; joint_bar: number };
|
||||
workItem.slatInfo = { length: si.length, slatCount: si.slat_count, jointBar: si.joint_bar };
|
||||
}
|
||||
if (opts.bending_info) {
|
||||
const bi = opts.bending_info as {
|
||||
common: { kind: string; type: string; length_quantities: { length: number; quantity: number }[] };
|
||||
detail_parts: { part_name: string; material: string; barcy_info: string }[];
|
||||
};
|
||||
workItem.bendingInfo = {
|
||||
common: { kind: bi.common.kind, type: bi.common.type, lengthQuantities: bi.common.length_quantities || [] },
|
||||
detailParts: (bi.detail_parts || []).map(dp => ({ partName: dp.part_name, material: dp.material, barcyInfo: dp.barcy_info })),
|
||||
};
|
||||
}
|
||||
if (opts.is_wip) {
|
||||
workItem.isWip = true;
|
||||
const wi = opts.wip_info as { specification: string; length_quantity: string; drawing_url?: string } | undefined;
|
||||
if (wi) {
|
||||
workItem.wipInfo = { specification: wi.specification, lengthQuantity: wi.length_quantity, drawingUrl: wi.drawing_url };
|
||||
}
|
||||
}
|
||||
if (opts.is_joint_bar) {
|
||||
workItem.isJointBar = true;
|
||||
const jb = opts.slat_joint_bar_info as { specification: string; length: number; quantity: number } | undefined;
|
||||
if (jb) workItem.slatJointBarInfo = jb;
|
||||
}
|
||||
|
||||
apiItems.push(workItem);
|
||||
});
|
||||
} else if (selectedOrder) {
|
||||
// nodeGroups가 없는 경우 폴백 (단일 항목)
|
||||
@@ -868,6 +916,7 @@ export default function WorkerScreen() {
|
||||
createdAt: '',
|
||||
};
|
||||
setSelectedOrder(syntheticOrder);
|
||||
setInspectionDimensions({ width: item.width, height: item.height });
|
||||
|
||||
// 실제 API 아이템인 경우 검사 템플릿 로딩 시도
|
||||
if (item.workOrderId && !item.id.startsWith('mock-')) {
|
||||
@@ -1238,34 +1287,40 @@ export default function WorkerScreen() {
|
||||
</div>
|
||||
|
||||
{/* 하단 고정 버튼 */}
|
||||
<div className={`fixed bottom-4 left-4 right-4 px-4 py-3 bg-background/95 backdrop-blur rounded-xl border shadow-lg z-50 transition-all duration-300 md:bottom-6 md:px-6 md:right-[48px] ${sidebarCollapsed ? 'md:left-[156px]' : 'md:left-[316px]'}`}>
|
||||
<div className="flex gap-3">
|
||||
{hasWipItems ? (
|
||||
<Button
|
||||
onClick={handleInspection}
|
||||
className="flex-1 py-6 text-base font-medium bg-gray-900 hover:bg-gray-800"
|
||||
>
|
||||
작업일지 및 검사성적서 보기
|
||||
</Button>
|
||||
) : (
|
||||
<>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={handleWorkLog}
|
||||
className="flex-1 py-6 text-base font-medium"
|
||||
>
|
||||
작업일지 보기
|
||||
</Button>
|
||||
{(hasWipItems || activeProcessSettings.needsWorkLog || activeProcessSettings.hasDocumentTemplate) && (
|
||||
<div className={`fixed bottom-4 left-4 right-4 px-4 py-3 bg-background/95 backdrop-blur rounded-xl border shadow-lg z-50 transition-all duration-300 md:bottom-6 md:px-6 md:right-[48px] ${sidebarCollapsed ? 'md:left-[156px]' : 'md:left-[316px]'}`}>
|
||||
<div className="flex gap-3">
|
||||
{hasWipItems ? (
|
||||
<Button
|
||||
onClick={handleInspection}
|
||||
className="flex-1 py-6 text-base font-medium bg-gray-900 hover:bg-gray-800"
|
||||
>
|
||||
검사성적서 보기
|
||||
작업일지 및 검사성적서 보기
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
) : (
|
||||
<>
|
||||
{activeProcessSettings.needsWorkLog && (
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={handleWorkLog}
|
||||
className="flex-1 py-6 text-base font-medium"
|
||||
>
|
||||
작업일지 보기
|
||||
</Button>
|
||||
)}
|
||||
{activeProcessSettings.hasDocumentTemplate && (
|
||||
<Button
|
||||
onClick={handleInspection}
|
||||
className="flex-1 py-6 text-base font-medium bg-gray-900 hover:bg-gray-800"
|
||||
>
|
||||
검사성적서 보기
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 모달/다이얼로그 */}
|
||||
<CompletionConfirmDialog
|
||||
@@ -1328,6 +1383,7 @@ export default function WorkerScreen() {
|
||||
initialData={selectedOrder ? inspectionDataMap.get(selectedOrder.id) : undefined}
|
||||
onComplete={handleInspectionComplete}
|
||||
templateData={inspectionTemplateData}
|
||||
workItemDimensions={inspectionDimensions}
|
||||
/>
|
||||
</PageLayout>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user