/** * ๐Ÿ“„ useReportTab Hook * ๊ฒ€์ƒ‰ ๋ชจ๋‹ฌ ๋ณด๊ณ ์„œ ํƒญ ํ›… * * - ๊ณ„์ธต์  ํด๋” ๊ตฌ์กฐ ํ‰ํƒ„ํ™” ๋ฐ ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜ * - ํŒŒ์ผ ๋ชฉ๋ก ์กฐํšŒ ๋ฐ ํŽ˜์ด์ง• ์ฒ˜๋ฆฌ * - ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ๊ธฐ๋Šฅ * - ์…€ ํด๋ฆญ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ * - Zustand๋ฅผ ํ†ตํ•œ ์ƒํƒœ ๊ด€๋ฆฌ ๋ฐ ๋กœ๋”ฉ ์ฒ˜๋ฆฌ * - ๋ฐ์ดํ„ฐ ๋งคํ•‘ ๋ฐ ์ฝ”๋“œ ๋ณ€ํ™˜ (์‹œ๋„/์‹œ๊ตฐ๊ตฌ, ๋ณด๊ณ ์„œ ์œ ํ˜• ๋“ฑ) * * ๐Ÿ”— ์‚ฌ์šฉ API * - ๋ณด๊ณ ์„œ ํŒŒ์ผ ์กฐํšŒ: GET /api/v1/file (dc-service) * - ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ: GET /api/v1/fileDownload (dc-service) */ import { getDcData } from '@/components/lib/api'; import { fileDownload } from '@/utils'; import { useReportTabStore } from '@/store/useReportTabStore'; import useSearchModalStore from '@/store/useSearchModalStore'; export type Folder = { clsfSystmSn: string; upClsfSystmSn: string; clsfSystmNm: string; children: Folder[]; }; export type FlattenedFolder = { [key: string]: string | number | undefined; }; export type SelectDataType = { text: string; val: string; sido?: string; // ์‹œ๋„ ์ฝ”๋“œ (์„ ํƒ ์‚ฌํ•ญ) } export type ReportDataFile = { no: number; fileTitle: string; regDt: string; fileSn: string; filePath: string; } export default function useReportTab() { const REPORT_TYPES = [ { val: '0', text: '์ „์ฒด' }, { val: '1', text: '๋ณด๊ณ ์„œ' }, { val: '2', text: '์š”์•ฝ๋ณด๊ณ ์„œ' }, { val: '3', text: '๋ถ€๋ก' }, { val: '4', text: '๊ธฐํƒ€' } ]; const { curPage, setIsLoading } = useSearchModalStore(); const { dcFiles: filesOrigin, files, setFiles } = useReportTabStore(); /** * Flatten a hierarchical folder structure into a flat array. * @param data - The hierarchical folder data to flatten. * @returns An array of flattened folders with their paths and levels. */ const flattenFolders = (data: Folder[]): FlattenedFolder[] => { const result: FlattenedFolder[] = []; const exceptNodeNm = ["๋ถ€๋ถ„", "ํ†ตํ•ฉ", "์ „์ฒด"]; const addNodeNm = ["๋ณด๊ณ ์„œ", "์š”์•ฝ๋ณด๊ณ ์„œ", "๋ถ€๋ก", "๊ธฐํƒ€"]; // level5 const columnNms: { [key: number]: string } = { 0: "root", 1: "sido", 2: "sigungu", 3: "approvalYear" , 4: "plantZoneGubun", 5: "reportGubun", 7: "fileName", 8: "regDate" }; const traverse = ( node: Folder, path: { [key: string]: string | number }, level: number ) => { const isYear = (value: string): boolean => { return /^[0-9]{4}๋…„$/.test(value); }; if (level === 2 && isYear(node.clsfSystmNm)) { level++; } if (level === 4 && addNodeNm.includes(node.clsfSystmNm)) { level++; // ๋ ˆ๋ฒจ์„ ์ฆ๊ฐ€์‹œ์ผœ ํ•˜์œ„๊ฐ’์— ์ถ”๊ฐ€๋˜๋„๋ก ํ•จ. } const newPath = { ...path, [`${columnNms[level]}`]: node.clsfSystmNm, }; if (node.children.length === 0) { newPath.no = result.length + 1; newPath.clsfSystmSn = node.clsfSystmSn; // ํŒŒ์ผ ์กฐํšŒ๋ฅผ ์œ„ํ•œ ๊ณ ์œ ๋ฒˆํ˜ธ result.push(newPath); } else { if (level === 4) { if (exceptNodeNm.includes(node.clsfSystmNm)) { level--; // ์ œ์™ธํ•  ๋…ธ๋“œ ์ด๋ฆ„์ธ ๊ฒฝ์šฐ, ํ˜„์žฌ์˜ ๋ ˆ๋ฒจ์— ํ•˜์œ„๊ฐ’์ด ์จ์ง€๋„๋ก ํ•จ. } } node.children.forEach((child) => { traverse(child, newPath, level + 1); }); } } if (data && data.length > 0 && data[0]?.clsfSystmNm == "๊ธฐ๋ณธ๊ณ„ํš") { // data๊ฐ€ ๋น„์–ด์žˆ์ง€ ์•Š๊ณ  children์ด ์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ ์ฒ˜๋ฆฌ data.forEach((root) => traverse(root, {}, 0)); } else { data.forEach((root) => traverse(root, {}, 1)); } return result; } const getDcFiles = async (clsfSystmSn: string): Promise => { if (!clsfSystmSn) { console.error("clsfSystmSn is required to get files."); return []; } const queryString = 'clsfSystmSn=' + clsfSystmSn; const result = await getDcData(`/api/v1/file${queryString ? `?${queryString}` : ''}`); return result; }; // ํŒŒ์ผ ์ด๋ฆ„ ์ถ”๊ฐ€ const addFileName = async (data: FlattenedFolder[]) => { const fileReportData = await Promise.all( data.map(async (item) => { const fileArr: ReportDataFile[] = await getDcFiles(String(item.clsfSystmSn)); let result: FlattenedFolder; if (fileArr.length > 0) { const f = fileArr[0]; const fCount = fileArr.length; result = { ...item, fileName: f?.fileTitle + " ์™ธ " + fCount + "๊ฑด", regDate: f?.regDt, fileSn: f?.fileSn, filePath: f?.filePath }; } else { result = { ...item, fileName: "", regDate: "", fileSn: "", filePath: "" }; } return result; }) ); return fileReportData; }; const getDcFileDownload = async (fileSn: string, fileName: string, filePath: string) => { if (filePath === "") { alert(`filePath ์ •๋ณด๊ฐ€ ์—†์œผ๋ฏ€๋กœ ๋‹ค์šด๋กœ๋“œ๊ฐ€ ๋ถˆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.\nfilesn: ${fileSn}`); return; } const queryString = 'filePath=' + encodeURIComponent(filePath); const responseBlob = await getDcData(`/api/v1/fileDownload${queryString ? `?${queryString}` : ''}`, "blob"); fileDownload(responseBlob, fileName); } // ํŒŒ์ผ ๋ชฉ๋ก ์กฐํšŒ const getFiles = async () => { setIsLoading(true); // ๋กœ๋”ฉ ์‹œ์ž‘ try { let data = filesOrigin; data = data?.slice((curPage - 1) * 10, curPage * 10); // paging data = data?.map((item, index) => ({ ...item, no: (curPage - 1) * 10 + index + 1 })); setFiles(data); } catch (error) { console.error("ํŒŒ์ผ ๋ชฉ๋ก ์กฐํšŒ ์—๋Ÿฌ:", error); } finally { setIsLoading(false); // ๋กœ๋”ฉ ์ข…๋ฃŒ } }; // cellClick ํ•ธ๋“ค๋Ÿฌ const handleCellClick = (index: number | undefined) => { if (typeof index === "number" && files[index]) { const fileName = files[index].fileTitle; const filePath = files[index].filePath; if (files[index].fileSn !== "") { getDcFileDownload(files[index].fileSn, fileName, filePath); } } }; return { REPORT_TYPES, flattenFolders, addFileName, getDcFiles, getDcFileDownload, getFiles, handleCellClick }; }