/** * πŸ“„ useOperationTab Hook * 검색 λͺ¨λ‹¬ μœ μ§€κ΄€λ¦¬ 정보 νƒ­ ν›… * * - ν•„ν„°λ§λœ 사업 ν˜„ν™© 데이터 쑰회 및 ν¬λ§·νŒ… * - 사업 ν˜„ν™© ν…Œμ΄λΈ” μ…€ 클릭 μ‹œ 상세 κ²°κ³Όν‘œ 쑰회 * - κ²°κ³Όν‘œ μ…€ 클릭 μ‹œ 지도 ν”Όμ²˜ 선택 및 쀌 κΈ°λŠ₯ * - μ—‘μ…€ λ‹€μš΄λ‘œλ“œ κΈ°λŠ₯ (사업 ν˜„ν™© 및 κ²°κ³Όν‘œ) * - CQL ν•„ν„° 생성을 ν†΅ν•œ 쿼리 쑰건 μ„€μ • * - Zustandλ₯Ό ν†΅ν•œ μƒνƒœ 관리 및 λ‘œλ”© 처리 * - 데이터 λ§€ν•‘ 및 μ½”λ“œ λ³€ν™˜ (사업 μœ ν˜•, μš©λ„, 재질 λ“±) * * πŸ”— μ‚¬μš© API * - μœ μ§€κ΄€λ¦¬ 정보 λͺ©λ‘ 쑰회: GET /api/v1/bizInfo (sewerage-service) * - μœ μ§€κ΄€λ¦¬ 정보(사업정보) κ΄€λ ¨ μ‹œμ„€ λͺ©λ‘ 쑰회: GET /api/v1/bizInfo/fclts (sewerage-service) */ import { downloadExcelWithKoreanHeaders } from '@common/business_components/ui'; import { MS_SWAGE_PPL_CODES, MS_SWAGE_PPL_USE_CODES } from '../components/common/table'; import { getData } from "@/components/lib/api"; import { formatDisplayData } from '@/components/lib/utils/formatDisplayValue'; import GisApp from "@common/business_components/ui/map/lib/gis.core"; import { confirmToast } from '@/components/ui/toast' import { toast } from "react-hot-toast"; import useSearchModalStore from '@/store/useSearchModalStore'; import useStore from '@/store/useStore'; export default function useOperationTab() { const OPERATION_TABLE_SIZE = 5; const { workType, tableData, detailTableData, curPage, detailCurPage, detailBizId, var1, var2, yearFilter, todayYear, todayMonth, todayDate, setIsSearchModalOpen, setTableData, setDetailTableData, setTableCount, setDetailTableCount, setDetailCurPage, setIsLoading, setIsDetailLoading, setIsResetDetailPage, setIsResetDetailSelection, setDetailBizId, getDateString } = useSearchModalStore(); const { BIZ_TY_CD } = useStore(); const WORK_TYPES = [ // μœ μ§€κ΄€λ¦¬ 정보 'ꡬ뢄' 선택 λͺ©λ‘ { val: "['200', '201', '204']", text: "보수 및 κ°±μ‹ " }, { val: "['100']", text: "점검 및 진단" }, { val: "['203']", text: "μ²­μ†Œ 및 μ€€μ„€" }, ]; const OPERATION_TABLE_HEADLIST = [ // μœ μ§€κ΄€λ¦¬ 정보 - 사업 ν˜„ν™© { id: 'rowNumber', title: '일련번호' }, { id: "bizInfoNm", title: "사업λͺ…" }, { id: "flfmtBgngYmd", title: "μˆ˜ν–‰μ‹œμž‘μΌμž" }, { id: "flfmtEndYmd", title: "μˆ˜ν–‰μ’…λ£ŒμΌμž" }, { id: "flfmtYr", title: "μˆ˜ν–‰λ…„λ„" }, { id: "bizTypeCd", title: "μ‚¬μ—…μœ ν˜•" }, { id: "bizAmt", title: "μ‚¬μ—…κΈˆμ•‘" }, ]; const MAINTENANACE_TABLE_HEADLIST = [ // μœ μ§€κ΄€λ¦¬ 정보 - 보수 및 κ°±μ‹  κ²°κ³Όν‘œ { id: 'rowNumber', title: '일련번호' }, { id: "fcltMngNo", title: "κ΄€λ¦¬λ²ˆν˜Έ" }, { id: "swtrmt_zone_nm", title: "μ²˜λ¦¬κ΅¬μ—­" }, { id: "usgCd", title: "μš©λ„" }, // { id: "lgalDrblyr", title: "λ‚΄μš©μ—°μˆ˜" }, // { id: "acqsPrmpc", title: "μ·¨λ“κΈˆμ•‘" }, { id: "mqltCd", title: "재질" }, { id: "pdmtVl", title: "κ΄€κ²½(mm)" }, { id: "prlgVl", title: "μ—°μž₯(m)" }, { id: "instlYmd", title: "μ„€μΉ˜μΌμž" }, // { id: "instlYmd", title: "사업ꡬ뢄" }, ]; const CLEANING_TABLE_HEADLIST = [ // μœ μ§€κ΄€λ¦¬ 정보 - μ²­μ†Œ 및 μ€€μ„€ κ²°κ³Όν‘œ { id: 'rowNumber', title: '일련번호' }, { id: "fcltMngNo", title: "κ΄€λ¦¬λ²ˆν˜Έ" }, { id: "swtrmt_zone_nm", title: "μ²˜λ¦¬κ΅¬μ—­" }, { id: "usgCd", title: "μš©λ„" }, // { id: "lgalDrblyr", title: "λ‚΄μš©μ—°μˆ˜" }, // { id: "acqsPrmpc", title: "μ·¨λ“κΈˆμ•‘" }, { id: "mqltCd", title: "재질" }, { id: "pdmtVl", title: "κ΄€κ²½(mm)" }, { id: "prlgVl", title: "μ—°μž₯(m)" }, { id: "instlYmd", title: "μ„€μΉ˜μΌμž" }, ]; const INSPECTION_TABLE_HEADLIST = [ // μœ μ§€κ΄€λ¦¬ 정보 - 점검 및 진단 κ²°κ³Όν‘œ { id: 'rowNumber', title: '일련번호' }, { id: "fcltMngNo", title: "κ΄€λ¦¬λ²ˆν˜Έ" }, { id: "swtrmt_zone_nm", title: "μ²˜λ¦¬κ΅¬μ—­" }, { id: "usgCd", title: "μš©λ„" }, // { id: "riskEval", title: "μœ„ν—˜ν‰κ°€" }, // { id: "acqsPrmpc", title: "μ·¨λ“κΈˆμ•‘" }, // { id: "lgalDrblyr", title: "λ‚΄μš©μ—°μˆ˜" }, // { id: "remLife", title: "μž”μ‘΄μˆ˜λͺ…" }, { id: "mqltCd", title: "재질" }, { id: "pdmtVl", title: "κ΄€κ²½(mm)" }, { id: "prlgVl", title: "μ—°μž₯(m)" }, { id: "instlYmd", title: "μ„€μΉ˜μΌμž" }, { id: "strc_stts_grd", title: "ꡬ쑰적 μƒνƒœλ“±κΈ‰" }, { id: "oper_stts_grd", title: "운영적 μƒνƒœλ“±κΈ‰" }, ]; const fetchOperationFilteredData = async () => { const RequestDTO: Record = { page: `${curPage - 1}`, size: `${OPERATION_TABLE_SIZE}`, }; if (var1) RequestDTO.bizInfoNm = var1; if (var2 != '0' && var2) RequestDTO.bizTypeCd = var2; // μˆ˜ν–‰κΈ°κ°„ λ²”μœ„ const startDate = getDateString( yearFilter.start, '', '', "19000101", ); const endDate = getDateString( yearFilter.end, '', '', `${todayYear}${todayMonth}${todayDate}`, ); RequestDTO.fromflfmtEndYmd = startDate; RequestDTO.toflfmtEndYmd = endDate; // JSON.parse μ‚¬μš©μœΌλ‘œ λ¬Έμžμ—΄ -> λ°°μ—΄ λ³€ν™˜ RequestDTO.workTypes = JSON.parse(workType.replace(/'/g, '"')); const params = new URLSearchParams(RequestDTO).toString(); const res = await getData(`v1/bizInfo?${params}`); const mappedContent = (res.content || []).map((item: any, index: number) => { const formattedItem = formatDisplayData(item); const matched = BIZ_TY_CD.find(code => code.lwpoCd === item.bizTypeCd); return { ...formattedItem, rowNumber: (curPage - 1) * OPERATION_TABLE_SIZE + index + 1, // 1λΆ€ν„° μ‹œμž‘ν•˜λŠ” 일련번호 μΆ”κ°€ bizTypeCd: matched ? matched.lwpoCdNm : item.bizTypeCd, }; }); setTableData(mappedContent || []); setTableCount(res.totalElements || 0); setDetailTableData([]); setDetailTableCount(0); }; // μœ μ§€κ΄€λ¦¬ 정보 ν…Œμ΄λΈ” cellClick ν•Έλ“€λŸ¬ const handleOperationCellClick = async (index?: number | undefined, headId?: String) => { setIsResetDetailPage(true); // νŽ˜μ΄μ§€λ₯Ό 1둜 μ΄ˆκΈ°ν™” setIsResetDetailSelection(true); // 선택 μ΄ˆκΈ°ν™” setIsResetDetailPage(true); // λ””ν…ŒμΌ νŽ˜μ΄μ§€λ₯Ό μ΄ˆκΈ°ν™” if (typeof index === "number") { setIsDetailLoading(true); setDetailBizId(tableData[index].bizId); setDetailCurPage(1); // 상세 νŽ˜μ΄μ§€ μ΄ˆκΈ°ν™” try { const RequestDTO: Record = { page: `${detailCurPage - 1}`, size: `${OPERATION_TABLE_SIZE}`, bizId: tableData[index % OPERATION_TABLE_SIZE].bizId, }; RequestDTO.workTypes = JSON.parse(workType.replace(/'/g, '"')); const res = await getData(`v1/bizInfo/fclts?${new URLSearchParams(RequestDTO).toString()}`); const mappedData = (res.data || []).map((item: any, detailIndex: number) => { const formattedItem = formatDisplayData(item); const usgCdObj = MS_SWAGE_PPL_USE_CODES.find(code => code.val === item?.usgCd?.trim()); const mqltCdObj = MS_SWAGE_PPL_CODES.find(code => code.val === item?.mqltCd?.trim()); return { ...formattedItem, rowNumber: (detailCurPage - 1) * OPERATION_TABLE_SIZE + detailIndex + 1, usgCd: usgCdObj ? usgCdObj.text : item.usgCd, mqltCd: mqltCdObj ? mqltCdObj.text : item.mqltCd, swtrmt_zone_nm: item.swtrmt_zone_nm ? item.swtrmt_zone_nm : '-', }; }); setDetailTableData(mappedData); setDetailTableCount(res.count || 0); } catch (error) { console.error('μœ μ§€κ΄€λ¦¬ 정보 cellClick μ—λŸ¬:', error); } finally { setIsDetailLoading(false); setIsResetDetailPage(false); setIsResetDetailSelection(false); } } }; // μœ μ§€κ΄€λ¦¬ 정보 λ””ν…ŒμΌ ν…Œμ΄λΈ” cellClick ν•Έλ“€λŸ¬ const handleOperationResultCellClick = async (index?: number | undefined, headId?: String) => { if (typeof index === "number") { setIsLoading(true); const row = detailTableData[index]; const layerNm = row.lyrTypeNm; const fid = row.fid; const core = GisApp.Module.layer as any; await core.showSearchResultsFromGeoJSON(layerNm, fid); setIsLoading(false); setIsSearchModalOpen(false); // SearchModal λ‹«κΈ° } }; // μœ μ§€κ΄€λ¦¬ 정보 λ””ν…ŒμΌ ν…Œμ΄λΈ” νŽ˜μ΄μ§€λ„€μ΄μ…˜ ν•Έλ“€λŸ¬ const handleOperationPageNation = async (index?: number | undefined) => { if (typeof index === "number") { setIsDetailLoading(true); try { const RequestDTO: Record = { page: `${detailCurPage - 1}`, size: `${OPERATION_TABLE_SIZE}`, bizId: String(detailBizId), }; const res = await getData(`v1/bizInfo/fclts?${new URLSearchParams(RequestDTO).toString()}`); const mappedData = (res.data || []).map((item: any, detailIndex: number) => { const formattedItem = formatDisplayData(item); const usgCdObj = MS_SWAGE_PPL_USE_CODES.find(code => code.val === item?.usgCd?.trim()); const mqltCdObj = MS_SWAGE_PPL_CODES.find(code => code.val === item?.mqltCd?.trim()); return { ...formattedItem, rowNumber: (detailCurPage - 1) * OPERATION_TABLE_SIZE + detailIndex + 1, usgCd: usgCdObj ? usgCdObj.text : item.usgCd, mqltCd: mqltCdObj ? mqltCdObj.text : item.mqltCd, swtrmt_zone_nm: item.swtrmt_zone_nm ? item.swtrmt_zone_nm : '-', }; }); setDetailTableData(mappedData); setDetailTableCount(res.count || 0); } catch (error) { console.error('μœ μ§€κ΄€λ¦¬ 정보 νŽ˜μ΄μ§€λ„€μ΄μ…˜ μ—λŸ¬:', error); } finally { setIsDetailLoading(false); } } }; // μœ μ§€κ΄€λ¦¬ 정보 Excel λ‹€μš΄λ‘œλ“œ ν•Έλ“€λŸ¬ μΆ”κ°€ const operationExcelDownload = async () => { if (tableData.length === 0) { alert("λ‹€μš΄λ‘œλ“œ ν•  Excel 파일이 μ—†μŠ΅λ‹ˆλ‹€.\n쑰회 ν›„ λ‹€μ‹œ μ‹œλ„ν•΄μ£Όμ„Έμš”."); return; } toast.dismiss("global-confirm-toast"); confirmToast( "파일 λ‹€μš΄λ‘œλ“œμ—λŠ” 2λΆ„ λ‚΄μ™Έμ˜ μ‹œκ°„μ΄ μ†Œμš”λ  수 μžˆμŠ΅λ‹ˆλ‹€.\n파일 λ‹€μš΄λ‘œλ“œλ₯Ό μ§„ν–‰ν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ?", onAnalysis ?? (() => { }), "text-xl font-medium text-gray-800" ); async function onAnalysis() { setIsLoading(true); try { const RequestDTO: Record = { size: '10000', }; if (var1) RequestDTO.bizInfoNm = var1; if (var2 != '0' && var2) RequestDTO.bizTypeCd = var2; // μˆ˜ν–‰κΈ°κ°„ λ²”μœ„ const startDate = getDateString( yearFilter.start, '', '', "19000101", ); const endDate = getDateString( yearFilter.end, '', '', `${todayYear}${todayMonth}${todayDate}`, ); RequestDTO.fromflfmtEndYmd = startDate; RequestDTO.toflfmtEndYmd = endDate; // JSON.parse μ‚¬μš©μœΌλ‘œ λ¬Έμžμ—΄ -> λ°°μ—΄ λ³€ν™˜ RequestDTO.workTypes = JSON.parse(workType.replace(/'/g, '"')); const params = new URLSearchParams(RequestDTO).toString(); const res = await getData(`v1/bizInfo?${params}`); // 헀더 λ§€ν•‘ μ •μ˜ const headerMapping: { [key: string]: string } = { 'bizInfoNm': '사업λͺ…', 'flfmtBgngYmd': 'μˆ˜ν–‰μ‹œμž‘μΌμž', 'flfmtEndYmd': 'μˆ˜ν–‰μ’…λ£ŒμΌμž', 'flfmtYr': 'μˆ˜ν–‰λ…„λ„', 'bizTypeCd': 'μ‚¬μ—…μœ ν˜•', 'bizAmt': 'μ‚¬μ—…κΈˆμ•‘(원)', }; const bizTyCdMap = new Map(BIZ_TY_CD.map(code => [code.lwpoCd, code.lwpoCdNm])); const mappedContent = (res.content || []).map((item: any) => { const formattedItem = formatDisplayData(item); return { bizInfoNm: formattedItem.bizInfoNm ?? item.bizInfoNm ?? '', flfmtBgngYmd: formattedItem.flfmtBgngYmd ?? item.flfmtBgngYmd ?? '', flfmtEndYmd: formattedItem.flfmtEndYmd ?? item.flfmtEndYmd ?? '', flfmtYr: formattedItem.flfmtYr ?? item.flfmtYr ?? '', bizTypeCd: bizTyCdMap.get(item.bizTypeCd) || item.bizTypeCd || formattedItem.bizTypeCd || '', bizAmt: ((v) => (v === 0 || v === '0') ? '0' : (v ?? ''))(formattedItem.bizAmt ?? item.bizAmt), }; }); // μ„ νƒλœ ν–‰ 데이터λ₯Ό Excel λ‹€μš΄λ‘œλ“œ ν˜•μ‹μœΌλ‘œ λ³€ν™˜ const excelData = mappedContent; // λ°°μ—΄λ‘œ κ°μ‹Έμ„œ 전달 // 파일λͺ… 생성 (λΆ„μ„λ²ˆν˜Έ 기반) const label = WORK_TYPES.find((type) => type.val === workType)?.text const fileName = `${label} 사업 ν˜„ν™©_${todayYear}${todayMonth}${todayDate}`; await downloadExcelWithKoreanHeaders({ data: excelData as JSON[], fileName: fileName, sheetNameArray: [fileName], headerRange: "A1:F1", headerMapping: headerMapping }); setIsLoading(false); } catch (error) { setIsLoading(false); console.error("Excel λ‹€μš΄λ‘œλ“œ 쀑 였λ₯˜ λ°œμƒ:", error); alert("Excel λ‹€μš΄λ‘œλ“œ 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. λ‹€μ‹œ μ‹œλ„ν•΄μ£Όμ„Έμš”."); } } }; // μœ μ§€κ΄€λ¦¬ 정보 κ²°κ³Όν‘œ Excel λ‹€μš΄λ‘œλ“œ ν•Έλ“€λŸ¬ μΆ”κ°€ const operationResultExcelDownload = async () => { if (detailTableData.length === 0) { alert("λ‹€μš΄λ‘œλ“œ ν•  Excel 파일이 μ—†μŠ΅λ‹ˆλ‹€.\n쑰회 ν›„ λ‹€μ‹œ μ‹œλ„ν•΄μ£Όμ„Έμš”."); return; } toast.dismiss("global-confirm-toast"); confirmToast( "파일 λ‹€μš΄λ‘œλ“œμ—λŠ” 2λΆ„ λ‚΄μ™Έμ˜ μ‹œκ°„μ΄ μ†Œμš”λ  수 μžˆμŠ΅λ‹ˆλ‹€.\n파일 λ‹€μš΄λ‘œλ“œλ₯Ό μ§„ν–‰ν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ?", onAnalysis ?? (() => { }), "text-xl font-medium text-gray-800" ); async function onAnalysis() { setIsLoading(true); try { const RequestDTO: Record = { size: '100', bizId: String(detailBizId), }; const res = await getData(`v1/bizInfo/fclts?${new URLSearchParams(RequestDTO).toString()}`); // 헀더 λ§€ν•‘ μ •μ˜ const headerMapping: { [key: string]: string } = { 'fcltMngNo': 'κ΄€λ¦¬λ²ˆν˜Έ', 'swtrmt_zone_nm': 'μ²˜λ¦¬κ΅¬μ—­', 'usgCd': 'μš©λ„', 'mqltCd': '재질', 'pdmtVl': 'κ΄€κ²½(mm)', 'prlgVl': 'μ—°μž₯(m)', 'instlYmd': 'μ„€μΉ˜μΌμž', 'strc_stts_grd': 'ꡬ쑰적 μƒνƒœλ“±κΈ‰', 'oper_stts_grd': '운영적 μƒνƒœλ“±κΈ‰', }; const usgCdMap = new Map(MS_SWAGE_PPL_USE_CODES.map(code => [code.val, code.text])); const mqltCdMap = new Map(MS_SWAGE_PPL_CODES.map(code => [code.val, code.text])); // 🎯 단일 반볡문으둜 μ΅œμ ν™” - 각 μ•„μ΄ν…œλ§ˆλ‹€ ν•„μš”ν•œ ν•„λ“œλ§Œ 직접 λ§€ν•‘ const mappedData = (res.data || []).map((item: any) => { const formattedItem = formatDisplayData(item); // trim ν•œ 번만 μˆ˜ν–‰ const trimmedUsgCd = item?.usgCd?.trim(); const trimmedMqltCd = item?.mqltCd?.trim(); // zone κ°’ ν•œ 번만 계산 const zone = item.swtrmtZoneNm ?? formattedItem.swtrmt_zone_nm ?? item.swtrmt_zone_nm ?? ''; // 직접 λ§€ν•‘ - 반볡문 없이 ν•œ λ²ˆμ— 객체 생성 return { fcltMngNo: formattedItem.fcltMngNo ?? item.fcltMngNo ?? '', swtrmt_zone_nm: (zone === null || zone === '') ? '-' : zone, usgCd: usgCdMap.get(trimmedUsgCd) || item.usgCd || formattedItem.usgCd || '', mqltCd: mqltCdMap.get(trimmedMqltCd) || item.mqltCd || formattedItem.mqltCd || '', pdmtVl: formattedItem.pdmtVl ?? item.pdmtVl ?? '', prlgVl: formattedItem.prlgVl ?? item.prlgVl ?? '', instlYmd: formattedItem.instlYmd ?? item.instlYmd ?? '', strc_stts_grd: ((v) => (v === 0 || v === '0') ? '0' : (v ?? ''))(formattedItem.strc_stts_grd ?? item.strc_stts_grd), oper_stts_grd: ((v) => (v === 0 || v === '0') ? '0' : (v ?? ''))(formattedItem.oper_stts_grd ?? item.oper_stts_grd), }; }); // μ„ νƒλœ ν–‰ 데이터λ₯Ό Excel λ‹€μš΄λ‘œλ“œ ν˜•μ‹μœΌλ‘œ λ³€ν™˜ const excelData = mappedData; // λ°°μ—΄λ‘œ κ°μ‹Έμ„œ 전달 // 파일λͺ… 생성 (λΆ„μ„λ²ˆν˜Έ 기반) const label = WORK_TYPES.find((type) => type.val === workType)?.text const fileName = `${label} κ²°κ³Όν‘œ_${todayYear}${todayMonth}${todayDate}`; await downloadExcelWithKoreanHeaders({ data: excelData as JSON[], fileName: fileName, sheetNameArray: [fileName], headerRange: "A1:I1", headerMapping: headerMapping }); setIsLoading(false); } catch (error) { setIsLoading(false); console.error("Excel λ‹€μš΄λ‘œλ“œ 쀑 였λ₯˜ λ°œμƒ:", error); alert("Excel λ‹€μš΄λ‘œλ“œ 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. λ‹€μ‹œ μ‹œλ„ν•΄μ£Όμ„Έμš”."); } } }; return { WORK_TYPES, OPERATION_TABLE_HEADLIST, MAINTENANACE_TABLE_HEADLIST, CLEANING_TABLE_HEADLIST, INSPECTION_TABLE_HEADLIST, OPERATION_TABLE_SIZE, fetchOperationFilteredData, handleOperationCellClick, handleOperationResultCellClick, handleOperationPageNation, operationExcelDownload, operationResultExcelDownload }; };