import type { ProductInspection, InspectionStats, InspectionCalendarItem, OrderSelectItem, OrderSettingItem, InspectionStatus, InspectionRequestDocument, InspectionReportDocument, ReportInspectionItem, ProductInspectionData, } from './types'; // ===== 상태/색상 매핑 ===== export const statusColorMap: Record = { 접수: 'bg-gray-100 text-gray-800', 진행중: 'bg-blue-100 text-blue-800', 완료: 'bg-green-100 text-green-800', }; export const statusCalendarColorMap: Record = { 접수: 'bg-blue-500', 진행중: 'bg-blue-700', 완료: 'bg-blue-400', }; export const judgmentColorMap: Record = { 합격: 'bg-green-100 text-green-800', 불합격: 'bg-red-100 text-red-800', }; // ===== 공통 관련자 정보 기본값 ===== const defaultConstructionSite = { siteName: '현장명', landLocation: '주소명', lotNumber: '', }; const defaultMaterialDistributor = { companyName: '회사명', companyAddress: '주소명', representativeName: '홍길동', phone: '02-1234-1234', }; const defaultConstructor = { companyName: '회사명', companyAddress: '주소명', name: '홍길동', phone: '02-1234-1234', }; const defaultSupervisor = { officeName: '회사명', officeAddress: '주소명', name: '홍길동', phone: '02-1234-1234', }; // ===== Mock 수주 선택 목록 (모달용) ===== export const mockOrderSelectItems: OrderSelectItem[] = [ { id: 'os-1', orderNumber: '123123', siteName: '현장명', deliveryDate: '2026-01-01', locationCount: 3 }, { id: 'os-2', orderNumber: '123123', siteName: '현장명', deliveryDate: '2026-01-01', locationCount: 3 }, { id: 'os-3', orderNumber: '123123', siteName: '현장명', deliveryDate: '2026-01-01', locationCount: 3 }, { id: 'os-4', orderNumber: '123123', siteName: '현장명', deliveryDate: '2026-01-01', locationCount: 3 }, { id: 'os-5', orderNumber: '123123', siteName: '현장명', deliveryDate: '2026-01-01', locationCount: 3 }, { id: 'os-6', orderNumber: '123123', siteName: '현장명', deliveryDate: '2026-01-01', locationCount: 3 }, { id: 'os-7', orderNumber: '123123', siteName: '현장명', deliveryDate: '2026-01-01', locationCount: 3 }, ]; // ===== Mock 수주 설정 항목 ===== const defaultOrderItems: OrderSettingItem[] = [ { id: 'oi-1', orderNumber: '123123', siteName: '현장명', deliveryDate: '2026-01-01', floor: '1층', symbol: '부호명', orderWidth: 4100, orderHeight: 2700, constructionWidth: 4100, constructionHeight: 2700, changeReason: '', }, { id: 'oi-2', orderNumber: '123123', siteName: '현장명', deliveryDate: '2026-01-01', floor: '2층', symbol: '부호명', orderWidth: 4100, orderHeight: 2700, constructionWidth: 4100, constructionHeight: 2700, changeReason: '', }, ]; // ===== Mock 제품검사 데이터 ===== export const mockInspections: ProductInspection[] = [ { id: '1', qualityDocNumber: '123123', siteName: '현장명', client: '회사명', locationCount: 5, requiredInfo: '완료', inspectionPeriod: '2026-01-01', inspector: '홍길동', status: '접수', author: '홍길동', receptionDate: '2026-01-01', manager: '홍길동', managerContact: '010-1234-1234', constructionSite: defaultConstructionSite, materialDistributor: defaultMaterialDistributor, constructorInfo: defaultConstructor, supervisor: defaultSupervisor, scheduleInfo: { visitRequestDate: '2026-01-01', startDate: '2026-01-01', endDate: '2026-01-01', inspector: '홍길동', sitePostalCode: '123', siteAddress: '서울특별시 서초구 서초대로 123', siteAddressDetail: '대한건물 12층 1201호', }, orderItems: defaultOrderItems, }, { id: '2', qualityDocNumber: '123123', siteName: '현장명', client: '회사명', locationCount: 5, requiredInfo: '4건 누락', inspectionPeriod: '2026-01-01~2026-01-02', inspector: '홍길동', status: '진행중', author: '홍길동', receptionDate: '2026-01-01', manager: '홍길동', managerContact: '010-1234-1234', constructionSite: defaultConstructionSite, materialDistributor: defaultMaterialDistributor, constructorInfo: defaultConstructor, supervisor: defaultSupervisor, scheduleInfo: { visitRequestDate: '2026-01-01', startDate: '2026-01-01', endDate: '2026-01-02', inspector: '홍길동', sitePostalCode: '123', siteAddress: '서울특별시 서초구 서초대로 123', siteAddressDetail: '대한건물 12층 1201호', }, orderItems: defaultOrderItems, }, { id: '3', qualityDocNumber: '123123', siteName: '현장명', client: '회사명', locationCount: 5, requiredInfo: '3건 누락', inspectionPeriod: '2026-01-01', inspector: '홍길동', status: '접수', author: '홍길동', receptionDate: '2026-01-01', manager: '홍길동', managerContact: '010-1234-1234', constructionSite: defaultConstructionSite, materialDistributor: defaultMaterialDistributor, constructorInfo: defaultConstructor, supervisor: defaultSupervisor, scheduleInfo: { visitRequestDate: '2026-01-01', startDate: '2026-01-01', endDate: '2026-01-01', inspector: '홍길동', sitePostalCode: '123', siteAddress: '서울특별시 서초구 서초대로 123', siteAddressDetail: '대한건물 12층 1201호', }, orderItems: defaultOrderItems, }, { id: '4', qualityDocNumber: '123123', siteName: '현장명', client: '회사명', locationCount: 5, requiredInfo: '완료', inspectionPeriod: '2026-01-01~2026-01-02', inspector: '홍길동', status: '완료', author: '홍길동', receptionDate: '2026-01-01', manager: '홍길동', managerContact: '010-1234-1234', constructionSite: defaultConstructionSite, materialDistributor: defaultMaterialDistributor, constructorInfo: defaultConstructor, supervisor: defaultSupervisor, scheduleInfo: { visitRequestDate: '2026-01-01', startDate: '2026-01-01', endDate: '2026-01-02', inspector: '홍길동', sitePostalCode: '123', siteAddress: '서울특별시 서초구 서초대로 123', siteAddressDetail: '대한건물 12층 1201호', }, orderItems: defaultOrderItems, }, { id: '5', qualityDocNumber: '123123', siteName: '현장명', client: '회사명', locationCount: 5, requiredInfo: '4건 누락', inspectionPeriod: '2026-01-01', inspector: '홍길동', status: '완료', author: '홍길동', receptionDate: '2026-01-01', manager: '홍길동', managerContact: '010-1234-1234', constructionSite: defaultConstructionSite, materialDistributor: defaultMaterialDistributor, constructorInfo: defaultConstructor, supervisor: defaultSupervisor, scheduleInfo: { visitRequestDate: '2026-01-01', startDate: '2026-01-01', endDate: '2026-01-01', inspector: '진행중', sitePostalCode: '123', siteAddress: '서울특별시 서초구 서초대로 123', siteAddressDetail: '대한건물 12층 1201호', }, orderItems: defaultOrderItems, }, { id: '6', qualityDocNumber: '123123', siteName: '현장명', client: '회사명', locationCount: 5, requiredInfo: '3건 누락', inspectionPeriod: '2026-01-01~2026-01-02', inspector: '홍길동', status: '접수', author: '홍길동', receptionDate: '2026-01-01', manager: '홍길동', managerContact: '010-1234-1234', constructionSite: defaultConstructionSite, materialDistributor: defaultMaterialDistributor, constructorInfo: defaultConstructor, supervisor: defaultSupervisor, scheduleInfo: { visitRequestDate: '2026-01-01', startDate: '2026-01-01', endDate: '2026-01-02', inspector: '홍길동', sitePostalCode: '123', siteAddress: '서울특별시 서초구 서초대로 123', siteAddressDetail: '대한건물 12층 1201호', }, orderItems: defaultOrderItems, }, { id: '7', qualityDocNumber: '123123', siteName: '현장명', client: '회사명', locationCount: 5, requiredInfo: '완료', inspectionPeriod: '2026-01-01', inspector: '홍길동', status: '완료', author: '홍길동', receptionDate: '2026-01-01', manager: '홍길동', managerContact: '010-1234-1234', constructionSite: defaultConstructionSite, materialDistributor: defaultMaterialDistributor, constructorInfo: defaultConstructor, supervisor: defaultSupervisor, scheduleInfo: { visitRequestDate: '2026-01-01', startDate: '2026-01-01', endDate: '2026-01-01', inspector: '홍길동', sitePostalCode: '123', siteAddress: '서울특별시 서초구 서초대로 123', siteAddressDetail: '대한건물 12층 1201호', }, orderItems: defaultOrderItems, }, ]; // ===== Mock 통계 ===== export const mockStats: InspectionStats = { receptionCount: 10, inProgressCount: 10, completedCount: 10, }; // ===== 통계 계산 ===== export const calculateStats = (inspections: ProductInspection[]): InspectionStats => { return { receptionCount: inspections.filter(i => i.status === '접수').length, inProgressCount: inspections.filter(i => i.status === '진행중').length, completedCount: inspections.filter(i => i.status === '완료').length, }; }; // ===== Mock 캘린더 데이터 ===== export const mockCalendarItems: InspectionCalendarItem[] = [ { id: 'cal-1', startDate: '2026-01-13', endDate: '2026-01-14', inspector: '홍길동', siteName: '현장명', status: '완료' }, { id: 'cal-2', startDate: '2026-01-15', endDate: '2026-01-17', inspector: '홍길동', siteName: '현장명', status: '진행중' }, { id: 'cal-3', startDate: '2026-01-23', endDate: '2026-01-25', inspector: '홍길동', siteName: '현장명', status: '진행중' }, { id: 'cal-4', startDate: '2026-01-26', endDate: '2026-01-26', inspector: '홍길동', siteName: '현장명', status: '접수' }, { id: 'cal-5', startDate: '2026-01-26', endDate: '2026-01-27', inspector: '홍길동', siteName: '현장명', status: '접수' }, { id: 'cal-6', startDate: '2026-01-27', endDate: '2026-01-28', inspector: '홍길동', siteName: '현장명', status: '접수' }, { id: 'cal-7', startDate: '2026-01-28', endDate: '2026-01-28', inspector: '홍길동', siteName: '현장명', status: '접수' }, ]; // ===== 수주 규격 비교 유틸 ===== export const isOrderSpecSame = (item: OrderSettingItem): boolean => { return item.orderWidth === item.constructionWidth && item.orderHeight === item.constructionHeight; }; export const calculateOrderSummary = (items: OrderSettingItem[]) => { const total = items.length; const same = items.filter(isOrderSpecSame).length; const changed = total - same; return { total, same, changed }; }; // ===== 빈 폼 기본값 ===== export const emptyConstructionSite = { siteName: '', landLocation: '', lotNumber: '', }; export const emptyMaterialDistributor = { companyName: '', companyAddress: '', representativeName: '', phone: '', }; export const emptyConstructor = { companyName: '', companyAddress: '', name: '', phone: '', }; export const emptySupervisor = { officeName: '', officeAddress: '', name: '', phone: '', }; export const emptyScheduleInfo = { visitRequestDate: '', startDate: '', endDate: '', inspector: '', sitePostalCode: '', siteAddress: '', siteAddressDetail: '', }; // ===== 문서 데이터 변환 헬퍼 ===== /** ProductInspection → InspectionRequestDocument 변환 */ export const buildRequestDocumentData = ( inspection: ProductInspection ): InspectionRequestDocument => ({ documentNumber: `REQ-${inspection.qualityDocNumber}`, createdDate: inspection.receptionDate, approvalLine: [ { role: '작성', name: inspection.author, department: '' }, { role: '승인', name: '', department: '' }, ], client: inspection.client, companyName: inspection.materialDistributor.companyName, manager: inspection.manager, orderNumber: inspection.orderItems[0]?.orderNumber || '', managerContact: inspection.managerContact, siteName: inspection.siteName, deliveryDate: '', siteAddress: `${inspection.scheduleInfo.siteAddress} ${inspection.scheduleInfo.siteAddressDetail}`.trim(), totalLocations: String(inspection.locationCount), receptionDate: inspection.receptionDate, visitRequestDate: inspection.scheduleInfo.visitRequestDate, constructionSite: inspection.constructionSite, materialDistributor: inspection.materialDistributor, constructorInfo: inspection.constructorInfo, supervisor: inspection.supervisor, priorNoticeItems: inspection.orderItems, }); /** Mock 검사항목 (제품검사성적서용) - 기획서 기반 상세 항목 */ export const mockReportInspectionItems: ReportInspectionItem[] = [ // 1. 겉모양 (5개 세부항목) — 항목1+2+3 병합: 육안검사/전수검사 (7행) { no: 1, category: '겉모양', subCategory: '가공상태', criteria: '사용상 해로운 결함이 없을 것', method: '육안검사', frequency: '전수검사', methodSpan: 7, freqSpan: 7, measuredValueSpan: 7 }, { no: 1, category: '겉모양', subCategory: '재봉상태', criteria: '내화실에 의해 견고하게 접합되어야 함', method: '', frequency: '' }, { no: 1, category: '겉모양', subCategory: '조립상태', criteria: '핸드링이 견고하게 조립되어야 함', method: '', frequency: '' }, { no: 1, category: '겉모양', subCategory: '연기차단재', criteria: '연기차단재 설치여부(케이스 W80, 가이드레일 W50(양쪽 설치))', method: '', frequency: '' }, { no: 1, category: '겉모양', subCategory: '하단마감재', criteria: '내부 무겁방절 설치 유무', method: '', frequency: '' }, // 2. 모터 { no: 2, category: '모터', criteria: '인정제품과 동일사양', method: '', frequency: '' }, // 3. 재질 { no: 3, category: '재질', criteria: 'WY-SC780 인쇄상태 확인', method: '', frequency: '' }, // 4. 치수(오픈사이즈) (4개 세부항목) — 항목4만 병합: 체크검사/전수검사 (4행) { no: 4, category: '치수\n(오픈사이즈)', subCategory: '길이', criteria: '수주 치수 ± 30mm', method: '체크검사', frequency: '전수검사', methodSpan: 4, freqSpan: 4, editable: true }, { no: 4, category: '치수\n(오픈사이즈)', subCategory: '높이', criteria: '수주 치수 ± 30mm', method: '', frequency: '', editable: true }, { no: 4, category: '치수\n(오픈사이즈)', subCategory: '가이드레일 간격', criteria: '10 ± 5mm (측정부위 @ 높이 100 이하)', method: '', frequency: '', editable: true }, { no: 4, category: '치수\n(오픈사이즈)', subCategory: '하단막대 간격', criteria: '간격 (③+④)\n가이드레일과 하단마감재 측 사이 25mm 이내', method: '', frequency: '', editable: true }, // 5. 작동테스트 — 판정 없음 { no: 5, category: '작동테스트', subCategory: '개폐성능', criteria: '작동 유무 확인\n(일부 및 완전폐쇄)', method: '', frequency: '', hideJudgment: true }, // 6. 내화시험 (3개 세부항목) — "비차열\n차열성" 3행 병합, 항목 6+7+8+9 검사방법/주기/판정 모두 병합 (10행) { no: 6, category: '내화시험', subCategory: '비차열\n차열성', subCategorySpan: 3, criteria: '6mm 균열게이지 관통 후 150mm 이동 유무', method: '공인\n시험기관\n시험\n성적서', frequency: '1회/5년', methodSpan: 10, freqSpan: 10, measuredValueSpan: 10, judgmentSpan: 10 }, { no: 6, category: '내화시험', criteria: '25mm 균열게이지 관통 유무', method: '', frequency: '' }, { no: 6, category: '내화시험', criteria: '10초 이상 지속되는 화염 발생 유무', method: '', frequency: '' }, // 7. 차연시험 — No.6의 span에 포함됨 { no: 7, category: '차연시험', subCategory: '공기누설량', criteria: '25Pa 일 때 공기누설량 0.9m³/min·m² 이하', method: '', frequency: '' }, // 8. 개폐시험 (5개 세부항목) — "평균속도" 2행 병합 (전도개폐 + 자중강화) { no: 8, category: '개폐시험', criteria: '개폐의 원활한 작동', method: '', frequency: '' }, { no: 8, category: '개폐시험', subCategory: '평균속도', subCategorySpan: 2, criteria: '전도개폐 2.5~6.5m/min', method: '', frequency: '' }, { no: 8, category: '개폐시험', criteria: '자중강화 3~7m/min', method: '', frequency: '' }, { no: 8, category: '개폐시험', criteria: '개폐 시 상부 및 하부 끝부분에서 자동정지', method: '', frequency: '' }, { no: 8, category: '개폐시험', criteria: '강화 중 임의의 위치에서 정지', method: '', frequency: '' }, // 9. 내충격시험 { no: 9, category: '내충격시험', criteria: '방화상 유해한 파괴, 박리 탈락 유무', method: '', frequency: '' }, ]; /** pass/fail → 적합/부적합 변환 */ const convertJudgment = (value: 'pass' | 'fail' | null): '적합' | '부적합' | undefined => { if (value === 'pass') return '적합'; if (value === 'fail') return '부적합'; return undefined; }; /** 검사 데이터를 검사항목에 매핑 */ const mapInspectionDataToItems = ( items: ReportInspectionItem[], inspectionData?: ProductInspectionData ): ReportInspectionItem[] => { if (!inspectionData) return items; return items.map((item) => { const newItem = { ...item }; // 겉모양 검사 매핑 if (item.category === '겉모양') { if (item.subCategory === '가공상태') { newItem.judgment = convertJudgment(inspectionData.appearanceProcessing); } else if (item.subCategory === '재봉상태') { newItem.judgment = convertJudgment(inspectionData.appearanceSewing); } else if (item.subCategory === '조립상태') { newItem.judgment = convertJudgment(inspectionData.appearanceAssembly); } else if (item.subCategory === '연기차단재') { newItem.judgment = convertJudgment(inspectionData.appearanceSmokeBarrier); } else if (item.subCategory === '하단마감재') { newItem.judgment = convertJudgment(inspectionData.appearanceBottomFinish); } } // 모터 매핑 if (item.category === '모터') { newItem.judgment = convertJudgment(inspectionData.motor); } // 재질 매핑 if (item.category === '재질') { newItem.judgment = convertJudgment(inspectionData.material); } // 치수 검사 매핑 if (item.category === '치수\n(오픈사이즈)') { if (item.subCategory === '길이') { newItem.measuredValue = inspectionData.lengthValue?.toString() || ''; newItem.judgment = convertJudgment(inspectionData.lengthJudgment); } else if (item.subCategory === '높이') { newItem.measuredValue = inspectionData.heightValue?.toString() || ''; newItem.judgment = convertJudgment(inspectionData.heightJudgment); } else if (item.subCategory === '가이드레일 간격') { newItem.measuredValue = inspectionData.guideRailGapValue?.toString() || ''; newItem.judgment = convertJudgment(inspectionData.guideRailGap); } else if (item.subCategory === '하단막대 간격') { newItem.measuredValue = inspectionData.bottomFinishGapValue?.toString() || ''; newItem.judgment = convertJudgment(inspectionData.bottomFinishGap); } } // 내화시험 매핑 if (item.category === '내화시험' && item.judgmentSpan) { newItem.judgment = convertJudgment(inspectionData.fireResistanceTest); } // 차연시험 매핑 if (item.category === '차연시험') { newItem.judgment = convertJudgment(inspectionData.smokeLeakageTest); } // 개폐시험 매핑 if (item.category === '개폐시험') { newItem.judgment = convertJudgment(inspectionData.openCloseTest); } // 내충격시험 매핑 if (item.category === '내충격시험') { newItem.judgment = convertJudgment(inspectionData.impactTest); } return newItem; }); }; /** ProductInspection → InspectionReportDocument 변환 */ export const buildReportDocumentData = ( inspection: ProductInspection, orderItems?: OrderSettingItem[] ): InspectionReportDocument => { // 검사 데이터가 있는 첫 번째 orderItem 찾기 const items = orderItems || inspection.orderItems; const itemWithData = items.find((item) => item.inspectionData); const inspectionData = itemWithData?.inspectionData; // 검사 항목에 검사 데이터 매핑 const mappedInspectionItems = mapInspectionDataToItems(mockReportInspectionItems, inspectionData); return { documentNumber: `RPT-${inspection.qualityDocNumber}`, createdDate: inspection.receptionDate, approvalLine: [ { role: '작성', name: inspection.scheduleInfo.inspector || inspection.author, department: '' }, { role: '승인', name: '', department: '' }, ], productName: inspectionData?.productName || '방화스크린', productLotNo: inspection.qualityDocNumber, productCode: '', lotSize: String(inspection.locationCount), client: inspection.client, inspectionDate: inspection.scheduleInfo.startDate, siteName: inspection.siteName, inspector: inspection.scheduleInfo.inspector, productImages: inspectionData?.productImages || [], inspectionItems: mappedInspectionItems, specialNotes: inspectionData?.specialNotes || '', finalJudgment: inspection.status === '완료' ? '합격' : '합격', }; }; /** 특정 OrderItem에 대한 InspectionReportDocument 빌드 (페이지네이션용) */ export const buildReportDocumentDataForItem = ( inspection: ProductInspection, orderItem: OrderSettingItem ): InspectionReportDocument => { const inspectionData = orderItem.inspectionData; // 검사 항목에 검사 데이터 매핑 const mappedInspectionItems = mapInspectionDataToItems(mockReportInspectionItems, inspectionData); return { documentNumber: `RPT-${inspection.qualityDocNumber}-${orderItem.floor}`, createdDate: inspection.receptionDate, approvalLine: [ { role: '작성', name: inspection.scheduleInfo.inspector || inspection.author, department: '' }, { role: '승인', name: '', department: '' }, ], productName: inspectionData?.productName || '방화스크린', productLotNo: `${inspection.qualityDocNumber}-${orderItem.floor}`, productCode: orderItem.symbol || '', lotSize: '1', client: inspection.client, inspectionDate: inspection.scheduleInfo.startDate, siteName: `${inspection.siteName} (${orderItem.floor})`, inspector: inspection.scheduleInfo.inspector, productImages: inspectionData?.productImages || [], inspectionItems: mappedInspectionItems, specialNotes: inspectionData?.specialNotes || '', finalJudgment: inspection.status === '완료' ? '합격' : '합격', }; };