Merge branch 'iipbs/sn/dev'
This commit is contained in:
@@ -4,7 +4,7 @@ import React, { useState, useEffect } from 'react'
|
|||||||
import InputSection from '../InputSection';
|
import InputSection from '../InputSection';
|
||||||
import { handleInputChange } from '../common';
|
import { handleInputChange } from '../common';
|
||||||
import { getData } from "@/components/lib/api";
|
import { getData } from "@/components/lib/api";
|
||||||
import useStore from '../../../../store/useStore';
|
import useStore from '@/store/useStore';
|
||||||
|
|
||||||
// 하수관로
|
// 하수관로
|
||||||
const inputColumn = [
|
const inputColumn = [
|
||||||
|
|||||||
@@ -8,37 +8,15 @@ import SearchModal from "./searchModal/searchModal";
|
|||||||
import FeatureClickEventPopup from "./components/popupComponent/featureClickEventPopup";
|
import FeatureClickEventPopup from "./components/popupComponent/featureClickEventPopup";
|
||||||
import { WaterDepth, WATER_DEPTH_LAYER_TYPES } from "./waterDepth/waterDepth";
|
import { WaterDepth, WATER_DEPTH_LAYER_TYPES } from "./waterDepth/waterDepth";
|
||||||
import { ProcSearchBar } from "@common/business_components/ui/map/searchBar";
|
import { ProcSearchBar } from "@common/business_components/ui/map/searchBar";
|
||||||
|
import useSearchModalStore from "@/store/useSearchModalStore";
|
||||||
|
|
||||||
// 타입 정의 추가
|
|
||||||
export type LyrStngProps = {
|
|
||||||
lyr_sn: string;
|
|
||||||
lyr_nm: string;
|
|
||||||
upper_lyr_sn: string;
|
|
||||||
drawOrdr: string;
|
|
||||||
flterSql: string;
|
|
||||||
gobjTy: string;
|
|
||||||
lyrTpNm: string;
|
|
||||||
useYn: string;
|
|
||||||
minViewSize: string;
|
|
||||||
iconNm: string;
|
|
||||||
lblAtrbNm: string;
|
|
||||||
fontNm: string;
|
|
||||||
fontIntnColor: string;
|
|
||||||
fontExtnColor: string;
|
|
||||||
fontExtnWdth: string;
|
|
||||||
lnWdth: string;
|
|
||||||
lnColor: string;
|
|
||||||
polgnColor: string;
|
|
||||||
initEprssYn: string;
|
|
||||||
clickPsblYn: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Map = () => {
|
const Map = () => {
|
||||||
|
const { isSearchModalOpen, setIsSearchModalOpen } = useSearchModalStore();
|
||||||
|
|
||||||
const [treeData, setTreeData] = useState([]); // 초기값을 객체 또는 null로 설정
|
const [treeData, setTreeData] = useState([]); // 초기값을 객체 또는 null로 설정
|
||||||
const [selectedFeature, setSelectedFeature] = useState(null); // 선택된 피처 상태
|
|
||||||
const gisMaps = useRef<any | null>(null);
|
const gisMaps = useRef<any | null>(null);
|
||||||
const [isOpen, setIsOpen] = useState(false); // 팝업 열기/닫기 상태
|
const [isOpen, setIsOpen] = useState(false); // 팝업 열기/닫기 상태
|
||||||
const [isSearchModalOpen, setIsSearchModalOpen] = useState(false); // SearchModal 열림 상태
|
|
||||||
const [featureData, setFeatureData] = useState(null); // 선택된 피쳐 데이터
|
const [featureData, setFeatureData] = useState(null); // 선택된 피쳐 데이터
|
||||||
const [showWaterDepth, setShowWaterDepth] = useState(false); // WaterDepth 표시 여부
|
const [showWaterDepth, setShowWaterDepth] = useState(false); // WaterDepth 표시 여부
|
||||||
const [isPlaying, setIsPlaying] = useState(false);
|
const [isPlaying, setIsPlaying] = useState(false);
|
||||||
@@ -148,12 +126,12 @@ const Map = () => {
|
|||||||
searchView={SearchModal}
|
searchView={SearchModal}
|
||||||
detailView={FeatureClickEventPopup}
|
detailView={FeatureClickEventPopup}
|
||||||
onFeatureSelect={onFeatureSelect}
|
onFeatureSelect={onFeatureSelect}
|
||||||
setIsOpen={setIsOpen}
|
|
||||||
setFeatureData={setFeatureData}
|
|
||||||
featureData={featureData}
|
featureData={featureData}
|
||||||
setIsSearchModalOpen={setIsSearchModalOpen}
|
setFeatureData={setFeatureData}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
|
setIsOpen={setIsOpen}
|
||||||
isSearchModalOpen={isSearchModalOpen}
|
isSearchModalOpen={isSearchModalOpen}
|
||||||
|
setIsSearchModalOpen={setIsSearchModalOpen}
|
||||||
onCheckedLayersChange={handleCheckedLayersChange}
|
onCheckedLayersChange={handleCheckedLayersChange}
|
||||||
searchBar={<ProcSearchBar gisMaps={gisMaps} facilityTypes={facilityTypes} />}
|
searchBar={<ProcSearchBar gisMaps={gisMaps} facilityTypes={facilityTypes} />}
|
||||||
waterDepth={showWaterDepth ? WaterDepth : undefined}
|
waterDepth={showWaterDepth ? WaterDepth : undefined}
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { YearRangeSelectBox } from '@/components/ui/YearRangeSelectBox';
|
|
||||||
import { SelectBox } from '@common/business_components/ui';
|
import { SelectBox } from '@common/business_components/ui';
|
||||||
import { Button, Label } from '@common/components';
|
import { Label } from '@common/components';
|
||||||
import SwagePpl from './swagePpl';
|
import SwagePpl from './swagePpl';
|
||||||
import SwagePrcsFclt from './swagePrcsFclt';
|
import SwagePrcsFclt from './swagePrcsFclt';
|
||||||
import SwagePrcsZone from './swagePrcsZone';
|
import SwagePrcsZone from './swagePrcsZone';
|
||||||
import SwageMhl from './swageMhl';
|
import SwageMhl from './swageMhl';
|
||||||
import SwagePmstn from './swagePmstn';
|
import SwagePmstn from './swagePmstn';
|
||||||
import Stofcbr from './stofcbr';
|
import Stofcbr from './stofcbr';
|
||||||
import { useSearchModal, type SearchModalProps } from './useSearchModal';
|
import useSearchModalStore from '@/store/useSearchModalStore';
|
||||||
import useSearchModalStore from '../../../store/useSearchModalStore';
|
|
||||||
|
|
||||||
|
|
||||||
// 기본정보 '구분' 선택 목록
|
// 기본정보 '구분' 선택 목록
|
||||||
@@ -22,7 +20,7 @@ export const BASIC_TYPES = [
|
|||||||
{ val: "tb_ms_stofcbr", text: "우수토실" },
|
{ val: "tb_ms_stofcbr", text: "우수토실" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const BasicTab: React.FC<SearchModalProps> = (props) => {
|
const BasicTab: React.FC = () => {
|
||||||
const { basicType, setBasicType } = useSearchModalStore();
|
const { basicType, setBasicType } = useSearchModalStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -45,12 +43,12 @@ const BasicTab: React.FC<SearchModalProps> = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* 조회 조건 */}
|
{/* 조회 조건 */}
|
||||||
{basicType === "tb_ms_swage_ppl" && (<SwagePpl {...props} />)} {/* 하수관로 */}
|
{basicType === "tb_ms_swage_ppl" && (<SwagePpl />)} {/* 하수관로 */}
|
||||||
{basicType === "tb_il_swage_prcs_fclt" && (<SwagePrcsFclt {...props} />)} {/* 하수처리시설 */}
|
{basicType === "tb_il_swage_prcs_fclt" && (<SwagePrcsFclt />)} {/* 하수처리시설 */}
|
||||||
{basicType === "tb_ms_swage_prcs_zone" && (<SwagePrcsZone {...props} />)} {/* 하수처리구역 */}
|
{basicType === "tb_ms_swage_prcs_zone" && (<SwagePrcsZone />)} {/* 하수처리구역 */}
|
||||||
{basicType === "tb_ms_swage_mhl" && (<SwageMhl {...props} />)} {/* 하수맨홀 */}
|
{basicType === "tb_ms_swage_mhl" && (<SwageMhl />)} {/* 하수맨홀 */}
|
||||||
{basicType === "tb_ms_swage_pmstn" && (<SwagePmstn {...props} />)} {/* 하수펌프장 */}
|
{basicType === "tb_ms_swage_pmstn" && (<SwagePmstn />)} {/* 하수펌프장 */}
|
||||||
{basicType === "tb_ms_stofcbr" && (<Stofcbr {...props} />)} {/* 우수토실 */}
|
{basicType === "tb_ms_stofcbr" && (<Stofcbr />)} {/* 우수토실 */}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,82 +1,22 @@
|
|||||||
import React from 'react';
|
import React, { use } from 'react';
|
||||||
import { YearRangeSelectBox } from '@/components/ui/YearRangeSelectBox';
|
import { YearRangeSelectBox } from '@/components/ui/YearRangeSelectBox';
|
||||||
import { SelectBox } from '@common/business_components/ui';
|
import { SelectBox } from '@common/business_components/ui';
|
||||||
import { Button, Input, Label } from '@common/components';
|
import { Button, Input, Label } from '@common/components';
|
||||||
import useStore from '../../../store/useStore';
|
import useStore from '../../../store/useStore';
|
||||||
import useSearchModalStore from '../../../store/useSearchModalStore';
|
import useSearchModalStore from '../../../store/useSearchModalStore';
|
||||||
import { useSearchModal, type SearchModalProps } from './useSearchModal';
|
import useSearchModal from './useSearchModal';
|
||||||
|
import useOperationTab from './useOperationTab';
|
||||||
// 운영정보 '구분' 선택 목록
|
|
||||||
export const WORK_TYPES = [
|
|
||||||
{ val: "['200', '201', '204']", text: "보수 및 갱신" },
|
|
||||||
{ val: "['100']", text: "점검 및 진단" },
|
|
||||||
{ val: "['203']", text: "청소 및 준설" },
|
|
||||||
];
|
|
||||||
// 운영정보 - 사업 현황
|
|
||||||
export const operationTableHeadlist = [
|
|
||||||
{ id: 'rowNumber', title: '일련번호' },
|
|
||||||
{ id: "bizInfoNm", title: "사업명" },
|
|
||||||
{ id: "flfmtBgngYmd", title: "수행시작일자" },
|
|
||||||
{ id: "flfmtEndYmd", title: "수행종료일자" },
|
|
||||||
{ id: "flfmtYr", title: "수행년도" },
|
|
||||||
{ id: "bizTypeCd", title: "사업유형" },
|
|
||||||
{ id: "bizAmt", title: "사업금액" },
|
|
||||||
];
|
|
||||||
// 운영정보 - 보수 및 갱신 결과표
|
|
||||||
export const operationMaintenanceTableHeadlist = [
|
|
||||||
{ 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: "사업구분" },
|
|
||||||
];
|
|
||||||
// 운영정보 - 청소 및 준설 결과표
|
|
||||||
export const operationCleaningTableHeadlist = [
|
|
||||||
{ 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: "설치일자" },
|
|
||||||
];
|
|
||||||
// 운영정보 - 점검 및 진단 결과표
|
|
||||||
export const operationInspectionTableHeadlist = [
|
|
||||||
{ 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 OperationTab: React.FC<SearchModalProps> = (props) => {
|
const OperationTab: React.FC = () => {
|
||||||
|
const { BIZ_TY_CD } = useStore();
|
||||||
const {
|
const {
|
||||||
workType, setWorkType,
|
workType, setWorkType,
|
||||||
var1, setVar1, var2, setVar2,
|
var1, setVar1, var2, setVar2,
|
||||||
yearFilter, setYearFilter,
|
yearFilter, setYearFilter,
|
||||||
} = useSearchModalStore();
|
} = useSearchModalStore();
|
||||||
const { handleSearch } = useSearchModal(props);
|
const { handleSearch } = useSearchModal();
|
||||||
|
const { WORK_TYPES } = useOperationTab();
|
||||||
const { BIZ_TY_CD } = useStore();
|
|
||||||
|
|
||||||
const BIZ_TY_CD_SELECT_ARRAY = BIZ_TY_CD.map(item => ({
|
const BIZ_TY_CD_SELECT_ARRAY = BIZ_TY_CD.map(item => ({
|
||||||
val: item.lwpoCd,
|
val: item.lwpoCd,
|
||||||
|
|||||||
@@ -1,108 +0,0 @@
|
|||||||
'use client'
|
|
||||||
import React, { useEffect, useState } from 'react';
|
|
||||||
|
|
||||||
import LoadingOverlay from '@/components/ui/LoadingBar';
|
|
||||||
import { getFileDownload, getDcFiles, useDcFiles } from './searchModalReportApi';
|
|
||||||
import { type ReportDataFile } from './searchModalReportApi';
|
|
||||||
import { useReportFileModalStore } from './searchModalReportApi'; // 모달 상태 관리 스토어
|
|
||||||
import { UiTable } from '@common/business_components/ui';
|
|
||||||
import { UiModal } from "@common/business_components";
|
|
||||||
|
|
||||||
type ModalOpenProp = {
|
|
||||||
clsfSystmSn: string, // 자료관 기본계획 일련번호
|
|
||||||
}
|
|
||||||
// 하수도정비 기본계획 보고서 파일목록
|
|
||||||
export const headlist = [
|
|
||||||
{ id: "no", title: "NO" },
|
|
||||||
{ id: "fileTitle", title: "파일명" },
|
|
||||||
{ id: "regDt", title: "등록일자" },
|
|
||||||
];
|
|
||||||
|
|
||||||
const ReportFiles: React.FC<ModalOpenProp> = ({ clsfSystmSn }: ModalOpenProp) => {
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
const [isResetPage, setIsResetPage] = useState<boolean>(false);
|
|
||||||
const [isResetSelection, setIsResetSelection] = useState<boolean>(false);
|
|
||||||
const { isOpen: isModalOpen, setIsOpen: setIsModalOpen } = useReportFileModalStore(); // 모달 상태 관리 스토어
|
|
||||||
const [files, setFiles] = useState<ReportDataFile[]>([]);
|
|
||||||
const [curPage, setCurPage] = useState(1);
|
|
||||||
|
|
||||||
const filesOrigin = useDcFiles(clsfSystmSn); // 자료관 기본계획 일련번호에 해당하는 파일 목록을 가져오기 위한 훅
|
|
||||||
useEffect(() => {
|
|
||||||
if (isModalOpen === true) {
|
|
||||||
getFiles(); // 파일 목록 조회
|
|
||||||
} else {
|
|
||||||
setFiles([]); // 모달이 닫힐 때 파일 목록 초기화
|
|
||||||
setCurPage(1); // 페이지를 1로 초기화
|
|
||||||
setIsResetPage(true); // 페이지를 초기화
|
|
||||||
setIsResetSelection(true); // 선택 초기화
|
|
||||||
}
|
|
||||||
}, [filesOrigin, isModalOpen, curPage]);
|
|
||||||
|
|
||||||
// 파일 목록 조회
|
|
||||||
const getFiles = async () => {
|
|
||||||
setIsLoading(true); // 로딩 시작
|
|
||||||
try {
|
|
||||||
//let data = await getDcFiles(clsfSystmSn);
|
|
||||||
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 !== "") {
|
|
||||||
getFileDownload(files[index].fileSn, fileName, filePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderBody = () => (
|
|
||||||
<>
|
|
||||||
<div className="flex-1 px-2 pb-2">
|
|
||||||
<LoadingOverlay isLoading={isLoading} />
|
|
||||||
<UiTable
|
|
||||||
headName={(() => {
|
|
||||||
return (<>조회 결과 ({filesOrigin.length.toLocaleString('ko-KR')})건</>);
|
|
||||||
})()
|
|
||||||
}
|
|
||||||
tableData={files}
|
|
||||||
headlist={headlist}
|
|
||||||
pageSize={10}
|
|
||||||
total={filesOrigin.length}
|
|
||||||
cellClick={handleCellClick}
|
|
||||||
onPageChange={setCurPage}
|
|
||||||
resetPageNo={isResetPage}
|
|
||||||
resetSelection={isResetSelection}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<UiModal
|
|
||||||
open={isModalOpen}
|
|
||||||
onOpenChange={setIsModalOpen}
|
|
||||||
headerTitle=""
|
|
||||||
bodyClass={`
|
|
||||||
min-h-[50vh] h-[570px]
|
|
||||||
min-w-[35vw] w-[400px]
|
|
||||||
max-w-none max-h-none
|
|
||||||
overflow-visible
|
|
||||||
z-[5000]
|
|
||||||
flex items-start
|
|
||||||
`}
|
|
||||||
body={renderBody()}
|
|
||||||
noFooterYn='Y'
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default React.memo(ReportFiles);
|
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
'use client'
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
import LoadingOverlay from '@/components/ui/LoadingBar';
|
||||||
|
import useReportTab from './useReportTab';
|
||||||
|
import { useReportTabStore } from '@/store/useReportTabStore';
|
||||||
|
import { UiTable } from '@common/business_components/ui';
|
||||||
|
import { UiModal } from "@common/business_components";
|
||||||
|
import useSearchModalStore from '@/store/useSearchModalStore';
|
||||||
|
|
||||||
|
type ModalOpenProp = { clsfSystmSn: string } // 자료관 기본계획 일련번호
|
||||||
|
const ReportFilesModal: React.FC<ModalOpenProp> = ({ clsfSystmSn }: ModalOpenProp) => {
|
||||||
|
// 하수도정비 기본계획 보고서 파일목록
|
||||||
|
const REPORT_FILES_HEADLIST = [
|
||||||
|
{ id: "no", title: "NO" },
|
||||||
|
{ id: "fileTitle", title: "파일명" },
|
||||||
|
{ id: "regDt", title: "등록일자" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const {
|
||||||
|
curPage, setCurPage,
|
||||||
|
isLoading,
|
||||||
|
isResetPage,
|
||||||
|
isResetSelection,
|
||||||
|
setIsResetPage,
|
||||||
|
setIsResetSelection
|
||||||
|
} = useSearchModalStore();
|
||||||
|
const {
|
||||||
|
isOpen: isModalOpen,
|
||||||
|
files,
|
||||||
|
dcFiles: filesOrigin,
|
||||||
|
setIsOpen: setIsModalOpen,
|
||||||
|
setFiles,
|
||||||
|
fetchDcFiles
|
||||||
|
} = useReportTabStore();
|
||||||
|
const { getFiles, handleCellClick } = useReportTab();
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchDcFiles(clsfSystmSn);
|
||||||
|
}, [clsfSystmSn]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isModalOpen === true) {
|
||||||
|
getFiles(); // 파일 목록 조회
|
||||||
|
} else {
|
||||||
|
setFiles([]); // 모달이 닫힐 때 파일 목록 초기화
|
||||||
|
setCurPage(1); // 페이지를 1로 초기화
|
||||||
|
setIsResetPage(true); // 페이지를 초기화
|
||||||
|
setIsResetSelection(true); // 선택 초기화
|
||||||
|
}
|
||||||
|
}, [filesOrigin, isModalOpen, curPage]);
|
||||||
|
|
||||||
|
const renderBody = () => (
|
||||||
|
<>
|
||||||
|
<div className="flex-1 px-2 pb-2">
|
||||||
|
<LoadingOverlay isLoading={isLoading} />
|
||||||
|
<UiTable
|
||||||
|
headName={(() => {
|
||||||
|
return (<>조회 결과 ({filesOrigin.length.toLocaleString('ko-KR')})건</>);
|
||||||
|
})()
|
||||||
|
}
|
||||||
|
tableData={files}
|
||||||
|
headlist={REPORT_FILES_HEADLIST}
|
||||||
|
pageSize={10}
|
||||||
|
total={filesOrigin.length}
|
||||||
|
cellClick={handleCellClick}
|
||||||
|
onPageChange={setCurPage}
|
||||||
|
resetPageNo={isResetPage}
|
||||||
|
resetSelection={isResetSelection}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<UiModal
|
||||||
|
open={isModalOpen}
|
||||||
|
onOpenChange={setIsModalOpen}
|
||||||
|
headerTitle=""
|
||||||
|
bodyClass={`
|
||||||
|
min-h-[50vh] h-[570px]
|
||||||
|
min-w-[35vw] w-[400px]
|
||||||
|
max-w-none max-h-none
|
||||||
|
overflow-visible
|
||||||
|
z-[5000]
|
||||||
|
flex items-start
|
||||||
|
`}
|
||||||
|
body={renderBody()}
|
||||||
|
noFooterYn='Y'
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(ReportFilesModal);
|
||||||
@@ -4,11 +4,11 @@ import { Button, Label } from '@common/components';
|
|||||||
import { YearRangeSelectBox } from '@/components/ui/YearRangeSelectBox';
|
import { YearRangeSelectBox } from '@/components/ui/YearRangeSelectBox';
|
||||||
import { SelectBox, UiTable } from '@common/business_components/ui';
|
import { SelectBox, UiTable } from '@common/business_components/ui';
|
||||||
import LoadingOverlay from '@/components/ui/LoadingBar';
|
import LoadingOverlay from '@/components/ui/LoadingBar';
|
||||||
import { addFileName, flattenFolders, getFileDownload, useDcTree, reportGubuns } from './searchModalReportApi';
|
import useReportTab from './useReportTab';
|
||||||
import useStore from '../../../store/useStore';
|
import useStore from '@/store/useStore';
|
||||||
import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox';
|
import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox';
|
||||||
import { useReportFileModalStore } from './searchModalReportApi'; // 모달 상태 관리 스토어
|
import { useReportTabStore } from '@/store/useReportTabStore';
|
||||||
import ReportFiles from './reportFiles'; // 파일목록모달
|
import ReportFilesModal from './reportFilesModal'; // 파일목록모달
|
||||||
|
|
||||||
|
|
||||||
// 하수도정비 기본계획 보고서
|
// 하수도정비 기본계획 보고서
|
||||||
@@ -42,13 +42,20 @@ const ReportTab: React.FC<ReportTabProps> = ({ open, isSearch = true, ctpvNm, sg
|
|||||||
const [ctpvCd, setCtpvCd] = useState('0');
|
const [ctpvCd, setCtpvCd] = useState('0');
|
||||||
const [sggCd, setSggCd] = useState('0');
|
const [sggCd, setSggCd] = useState('0');
|
||||||
const [reportGubun, setReportGubun] = useState("0");
|
const [reportGubun, setReportGubun] = useState("0");
|
||||||
// const [gubun, setGubun] = useState("");
|
|
||||||
const { isOpen: isModalOpen, setIsOpen: setIsModalOpen } = useReportFileModalStore(); // 모달 상태 관리 스토어
|
|
||||||
const [clsfSystmSn, setClsfSystmSn] = useState(''); // 자료관 기본계획 일련번호
|
const [clsfSystmSn, setClsfSystmSn] = useState(''); // 자료관 기본계획 일련번호
|
||||||
const { ctpv, sgg } = useStore();
|
|
||||||
|
|
||||||
// 하수정비기본계획 report
|
const { ctpv, sgg } = useStore();
|
||||||
const reportOriginData = useDcTree(""); //:Folder[]
|
const {
|
||||||
|
isOpen: isReportFilesModalOpen,
|
||||||
|
setIsOpen: setIsReportFilesModalOpen,
|
||||||
|
dcTree: reportOriginData,
|
||||||
|
fetchDcTree
|
||||||
|
} = useReportTabStore(); // 모달 상태 관리 스토어
|
||||||
|
const { REPORT_TYPES, flattenFolders, addFileName } = useReportTab();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchDcTree(""); // 하수정비기본계획 report
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// filterParams 초기화
|
// filterParams 초기화
|
||||||
@@ -105,12 +112,9 @@ const ReportTab: React.FC<ReportTabProps> = ({ open, isSearch = true, ctpvNm, sg
|
|||||||
const handleReportCellClick = (index: number | undefined) => {
|
const handleReportCellClick = (index: number | undefined) => {
|
||||||
if (typeof index === "number" && tableData[index]) {
|
if (typeof index === "number" && tableData[index]) {
|
||||||
const reportData = tableData[index];
|
const reportData = tableData[index];
|
||||||
const fileName = reportData.fileName;
|
|
||||||
const filePath = reportData.filePath;
|
|
||||||
if (reportData.fileSn !== "") {
|
if (reportData.fileSn !== "") {
|
||||||
//getFileDownload(reportData.fileSn, fileName, filePath);
|
|
||||||
setIsModalOpen(true); // 모달 열기
|
|
||||||
setClsfSystmSn(reportData.clsfSystmSn); // 자료관 기본계획 일련번호 설정
|
setClsfSystmSn(reportData.clsfSystmSn); // 자료관 기본계획 일련번호 설정
|
||||||
|
setIsReportFilesModalOpen(true); // 모달 열기
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -133,15 +137,16 @@ const ReportTab: React.FC<ReportTabProps> = ({ open, isSearch = true, ctpvNm, sg
|
|||||||
filterReportData = filterReportData.filter(item => item.sigungu === sigunguOption?.text);
|
filterReportData = filterReportData.filter(item => item.sigungu === sigunguOption?.text);
|
||||||
}
|
}
|
||||||
if (reportGubun !== "0") { // 보고서구분검색
|
if (reportGubun !== "0") { // 보고서구분검색
|
||||||
const reportGubunOption = reportGubuns.find((n) => n.val === reportGubun);
|
const reportGubunOption = REPORT_TYPES.find((n) => n.val === reportGubun);
|
||||||
filterReportData = filterReportData.filter(item => item.reportGubun === reportGubunOption?.text);
|
filterReportData = filterReportData.filter(item => item.reportGubun === reportGubunOption?.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (yearFilter.start != "" && yearFilter.end == "") //승인년도검색
|
const { start, end } = yearFilter;
|
||||||
|
if (start && !end) //승인년도검색
|
||||||
filterReportData = filterReportData.filter(item => (item.approvalYear) ? item.approvalYear >= yearFilter.start + "년" : null);
|
filterReportData = filterReportData.filter(item => (item.approvalYear) ? item.approvalYear >= yearFilter.start + "년" : null);
|
||||||
if (yearFilter.start == "" && yearFilter.end != "")
|
else if (!start && end)
|
||||||
filterReportData = filterReportData.filter(item => (item.approvalYear) ? item.approvalYear <= yearFilter.end + "년" : null);
|
filterReportData = filterReportData.filter(item => (item.approvalYear) ? item.approvalYear <= yearFilter.end + "년" : null);
|
||||||
if (yearFilter.start != "" && yearFilter.end != "") {
|
else if (start && end) {
|
||||||
filterReportData = filterReportData.filter(item => {
|
filterReportData = filterReportData.filter(item => {
|
||||||
return (item.approvalYear) ? item.approvalYear >= yearFilter.start + "년" && item.approvalYear <= yearFilter.end + "년" : null;
|
return (item.approvalYear) ? item.approvalYear >= yearFilter.start + "년" && item.approvalYear <= yearFilter.end + "년" : null;
|
||||||
});
|
});
|
||||||
@@ -194,7 +199,7 @@ const ReportTab: React.FC<ReportTabProps> = ({ open, isSearch = true, ctpvNm, sg
|
|||||||
<SelectBox className="w-44 mr-8"
|
<SelectBox className="w-44 mr-8"
|
||||||
selectClass="rounded-lg bg-white"
|
selectClass="rounded-lg bg-white"
|
||||||
label=""
|
label=""
|
||||||
selectArray={[...reportGubuns]}
|
selectArray={[...REPORT_TYPES]}
|
||||||
value={reportGubun} onSelectValue={val => setReportGubun(String(val))}
|
value={reportGubun} onSelectValue={val => setReportGubun(String(val))}
|
||||||
selectContentClass="z-[101]" labelClass='whitespace-nowrap text-xl text-gray-600 pr-2'
|
selectContentClass="z-[101]" labelClass='whitespace-nowrap text-xl text-gray-600 pr-2'
|
||||||
/>
|
/>
|
||||||
@@ -233,7 +238,7 @@ const ReportTab: React.FC<ReportTabProps> = ({ open, isSearch = true, ctpvNm, sg
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* 모달 컴포넌트 */}
|
{/* 모달 컴포넌트 */}
|
||||||
{isModalOpen && <ReportFiles clsfSystmSn={clsfSystmSn} />}
|
{isReportFilesModalOpen && <ReportFilesModal clsfSystmSn={clsfSystmSn} />}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,37 +1,24 @@
|
|||||||
import React, { useEffect, useMemo } from 'react';
|
|
||||||
import LoadingOverlay from '@/components/ui/LoadingBar';
|
import LoadingOverlay from '@/components/ui/LoadingBar';
|
||||||
import { UiModal, UITab, UiTable } from '@common/business_components/ui';
|
import { UiModal, UITab, UiTable } from '@common/business_components/ui';
|
||||||
import { Button } from '@common/components/ui';
|
import { Button } from '@common/components/ui';
|
||||||
import axios from 'axios';
|
import React, { useMemo } from 'react';
|
||||||
import {
|
|
||||||
ExclnSewagePumpCol2, MsSwageMhlCol2, MsSwagePplCol2, stofcbrCol2, SwtrmtFcltCol2, SwtrmtPrcsZoneCol2,
|
|
||||||
MS_SWAGE_PPL_USE_CODES, MS_SWAGE_MHL_CODES, MS_SWAGE_MHL_USE_CODES,
|
|
||||||
} from '../components/common/table';
|
|
||||||
import { getData } from "@/components/lib/api";
|
|
||||||
import BasicTab, { BASIC_TYPES } from './basicTab';
|
|
||||||
import OperationTab, { operationCleaningTableHeadlist, operationInspectionTableHeadlist, operationMaintenanceTableHeadlist, operationTableHeadlist, WORK_TYPES } from './operationTab';
|
|
||||||
import ReportTab from './reportTab';
|
|
||||||
import { formatDisplayData } from '@/components/lib/utils/formatDisplayValue';
|
|
||||||
import { Toaster } from "react-hot-toast";
|
import { Toaster } from "react-hot-toast";
|
||||||
import { useSearchModal, OPERATION_TABLE_SIZE, type SearchModalProps } from './useSearchModal';
|
|
||||||
import useSearchModalStore from '../../../store/useSearchModalStore';
|
import useSearchModalStore from '../../../store/useSearchModalStore';
|
||||||
|
import {
|
||||||
|
ExclnSewagePumpCol2, MsSwageMhlCol2, MsSwagePplCol2, stofcbrCol2, SwtrmtFcltCol2, SwtrmtPrcsZoneCol2
|
||||||
|
} from '../components/common/table';
|
||||||
|
import BasicTab, { BASIC_TYPES } from './basicTab';
|
||||||
|
import OperationTab from './operationTab';
|
||||||
|
import ReportTab from './reportTab';
|
||||||
|
import useSearchModal from './useSearchModal';
|
||||||
|
import useBasicTab from './useBasicTab';
|
||||||
|
import useOperationTab from './useOperationTab';
|
||||||
|
|
||||||
const SearchModal: React.FC<SearchModalProps> = (props) => {
|
const SearchModal: React.FC = () => {
|
||||||
const {
|
|
||||||
open, onOpenChange,
|
|
||||||
TABS,
|
|
||||||
handleSearch,
|
|
||||||
handleBasicCellClick,
|
|
||||||
handleOperationCellClick,
|
|
||||||
handleOperationResultCellClick,
|
|
||||||
basicExcelDownload,
|
|
||||||
operationExcelDownload,
|
|
||||||
operationResultExcelDownload,
|
|
||||||
viewMultipleFeature,
|
|
||||||
} = useSearchModal(props);
|
|
||||||
const {
|
const {
|
||||||
|
isSearchModalOpen, setIsSearchModalOpen,
|
||||||
activeTab, basicType, workType,
|
activeTab, basicType, workType,
|
||||||
tableData, detailTableData,
|
tableData, detailTableData,
|
||||||
tableCount, detailTableCount,
|
tableCount, detailTableCount,
|
||||||
curPage, detailCurPage,
|
curPage, detailCurPage,
|
||||||
isLoading, isDetailLoading,
|
isLoading, isDetailLoading,
|
||||||
@@ -40,6 +27,21 @@ const SearchModal: React.FC<SearchModalProps> = (props) => {
|
|||||||
setActiveTab,
|
setActiveTab,
|
||||||
setCurPage, setDetailCurPage,
|
setCurPage, setDetailCurPage,
|
||||||
} = useSearchModalStore();
|
} = useSearchModalStore();
|
||||||
|
const { TABS, viewMultipleFeature } = useSearchModal();
|
||||||
|
const { handleBasicCellClick, basicExcelDownload } = useBasicTab();
|
||||||
|
const {
|
||||||
|
WORK_TYPES,
|
||||||
|
OPERATION_TABLE_SIZE,
|
||||||
|
OPERATION_TABLE_HEADLIST,
|
||||||
|
MAINTENANACE_TABLE_HEADLIST,
|
||||||
|
CLEANING_TABLE_HEADLIST,
|
||||||
|
INSPECTION_TABLE_HEADLIST,
|
||||||
|
handleOperationCellClick,
|
||||||
|
handleOperationResultCellClick,
|
||||||
|
operationExcelDownload,
|
||||||
|
operationResultExcelDownload
|
||||||
|
} = useOperationTab();
|
||||||
|
|
||||||
|
|
||||||
const dynamicHeadlist: { id: string, title: string }[] = useMemo(() => {
|
const dynamicHeadlist: { id: string, title: string }[] = useMemo(() => {
|
||||||
if (activeTab === 'basic') { // 기본정보
|
if (activeTab === 'basic') { // 기본정보
|
||||||
@@ -52,16 +54,16 @@ const SearchModal: React.FC<SearchModalProps> = (props) => {
|
|||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
if (activeTab === 'operation') return operationTableHeadlist; // 운영정보
|
if (activeTab === 'operation') return OPERATION_TABLE_HEADLIST; // 운영정보
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}, [activeTab, basicType, workType]);
|
}, [activeTab, basicType, workType]);
|
||||||
|
|
||||||
const dynamicHeadlist2: { id: string, title: string }[] = useMemo(() => {
|
const dynamicHeadlist2: { id: string, title: string }[] = useMemo(() => {
|
||||||
if (activeTab === 'operation') {
|
if (activeTab === 'operation') {
|
||||||
if (workType === WORK_TYPES[0]?.val) return operationMaintenanceTableHeadlist; // 보수 및 갱신
|
if (workType === WORK_TYPES[0]?.val) return MAINTENANACE_TABLE_HEADLIST; // 보수 및 갱신
|
||||||
if (workType === WORK_TYPES[1]?.val) return operationInspectionTableHeadlist; // 점검 및 진단
|
if (workType === WORK_TYPES[1]?.val) return CLEANING_TABLE_HEADLIST; // 점검 및 진단
|
||||||
if (workType === WORK_TYPES[2]?.val) return operationCleaningTableHeadlist; // 청소 및 준설
|
if (workType === WORK_TYPES[2]?.val) return INSPECTION_TABLE_HEADLIST; // 청소 및 준설
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
@@ -79,20 +81,9 @@ const SearchModal: React.FC<SearchModalProps> = (props) => {
|
|||||||
}))}
|
}))}
|
||||||
onValueChange={(value: string) => setActiveTab(value)}
|
onValueChange={(value: string) => setActiveTab(value)}
|
||||||
/>
|
/>
|
||||||
{/* 기본정보 탭 */}
|
{activeTab === 'basic' && (<BasicTab />)} {/* 기본정보 탭 */}
|
||||||
{activeTab === 'basic' && (
|
{activeTab === 'operation' && (<OperationTab />)} {/* 운영정보 탭 */}
|
||||||
<BasicTab {...props} />
|
{activeTab === 'report' && (<ReportTab open={isSearchModalOpen} />)} {/* 하수도정비기본계획보고서 탭 */}
|
||||||
)}
|
|
||||||
{/* 운영정보 탭 */}
|
|
||||||
{activeTab === 'operation' && (
|
|
||||||
<OperationTab {...props} />
|
|
||||||
)}
|
|
||||||
{/* 하수도정비기본계획보고서 탭 */}
|
|
||||||
{activeTab === 'report' && (
|
|
||||||
<ReportTab
|
|
||||||
open={open}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
|
|
||||||
{/* 📋 결과 리스트 */}
|
{/* 📋 결과 리스트 */}
|
||||||
@@ -192,8 +183,8 @@ const SearchModal: React.FC<SearchModalProps> = (props) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<UiModal
|
<UiModal
|
||||||
open={open}
|
open={isSearchModalOpen}
|
||||||
onOpenChange={onOpenChange}
|
onOpenChange={setIsSearchModalOpen}
|
||||||
bodyClass={`
|
bodyClass={`
|
||||||
h-[100dvh]
|
h-[100dvh]
|
||||||
w-[60dvw]
|
w-[60dvw]
|
||||||
|
|||||||
@@ -1,198 +0,0 @@
|
|||||||
import { useState, useEffect } from 'react';
|
|
||||||
import { getDcData } from '@/components/lib/api';
|
|
||||||
import { create } from 'zustand';
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isYear = (value: string): boolean => {
|
|
||||||
return /^[0-9]{4}년$/.test(value);
|
|
||||||
};
|
|
||||||
export const reportGubuns = [{ val: '0', text: '전체' }, { val: '1', text: '보고서' }
|
|
||||||
, { val: '2', text: '요약보고서' }, { val: '3', text: '부록' }, { val: '4', text: '기타' }];
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
export function 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"
|
|
||||||
};
|
|
||||||
|
|
||||||
function traverse(
|
|
||||||
node: Folder,
|
|
||||||
path: { [key: string]: string | number },
|
|
||||||
level: number
|
|
||||||
) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getDcTree = async (clsfSystmNm: string) => {
|
|
||||||
const result = await getDcData("/api/v1/dc/clsf?clsfSystmNm=" + clsfSystmNm);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
export const useDcTree = (clsfSystmNm: string) => {
|
|
||||||
const [data, setData] = useState([]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const fetch = async () => {
|
|
||||||
const result = await getDcTree(clsfSystmNm);
|
|
||||||
if (result) {
|
|
||||||
setData(result);
|
|
||||||
}
|
|
||||||
console.log("useDcTree호출");
|
|
||||||
console.log("clsfSystmNm:", clsfSystmNm, "data:", result);
|
|
||||||
};
|
|
||||||
fetch();
|
|
||||||
}, [clsfSystmNm]);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getDcFiles = async (clsfSystmSn: string) : Promise<ReportDataFile[]> => {
|
|
||||||
if (!clsfSystmSn) {
|
|
||||||
console.error("clsfSystmSn is required to get files.");
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
const queryString = 'clsfSystmSn=' + clsfSystmSn;
|
|
||||||
const result = await getDcData(`/api/v1/dc/file${queryString ? `?${queryString}` : ''}`);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useDcFiles = (clsfSystmNm: string) => {
|
|
||||||
const [data, setData] = useState<ReportDataFile[]>([]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const fetch = async () => {
|
|
||||||
const result = await getDcFiles(clsfSystmNm);
|
|
||||||
if (result) {
|
|
||||||
setData(result);
|
|
||||||
}
|
|
||||||
console.log("useDcFiles 호출");
|
|
||||||
console.log("clsfSystmNm:", clsfSystmNm, "data:", result);
|
|
||||||
};
|
|
||||||
fetch();
|
|
||||||
}, [clsfSystmNm]);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 파일 이름 추가
|
|
||||||
export 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;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getDcFileprcs = async (fileSn: string) => {
|
|
||||||
const queryString = 'fileSn=' + fileSn;
|
|
||||||
const result = await getDcData(`/api/v1/dc/fileprcs${queryString ? `?${queryString}` : ''}`);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getDcFileDownload = async (filePath: string) => {
|
|
||||||
const queryString = 'filePath=' + encodeURIComponent(filePath);
|
|
||||||
const response = await fetch(`/dc-service/api/v1/dc/file/download?${queryString}`, {
|
|
||||||
method: 'GET',
|
|
||||||
});
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(`File download failed: ${response.status}`);
|
|
||||||
}
|
|
||||||
const blob = await response.blob(); // PDF, image 등은 blob으로 받아야 함
|
|
||||||
return blob;
|
|
||||||
};
|
|
||||||
export const fileDownload = (data: Blob, fileName: string) => { // Blob데이터 임시link로 연결
|
|
||||||
const url = window.URL.createObjectURL(data);
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = url;
|
|
||||||
link.download = fileName; // 원하는 파일명 지정
|
|
||||||
document.body.appendChild(link);
|
|
||||||
link.click();
|
|
||||||
link.remove();
|
|
||||||
window.URL.revokeObjectURL(url);
|
|
||||||
}
|
|
||||||
export const getFileDownload = async (fileSn: string, fileName: string, filePath: string) => {
|
|
||||||
if (filePath === "") alert("filePath 정보 없으므로 다운로드 불가:filesn" + fileSn);
|
|
||||||
const blobData = await getDcFileDownload(filePath); // 실제 다운로드 API
|
|
||||||
fileDownload(blobData, fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ModalStore {
|
|
||||||
isOpen: boolean;
|
|
||||||
setIsOpen: (open: boolean) => void;
|
|
||||||
}
|
|
||||||
export const useReportFileModalStore = create<ModalStore>((set) => ({
|
|
||||||
isOpen: false,
|
|
||||||
setIsOpen: (open: boolean) => set({ isOpen: open }),
|
|
||||||
}));
|
|
||||||
@@ -5,24 +5,16 @@ import { Button } from '@common/components';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox';
|
import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox';
|
||||||
import useSearchModalStore from '../../../store/useSearchModalStore';
|
import useSearchModalStore from '../../../store/useSearchModalStore';
|
||||||
import { useSearchModal, type SearchModalProps } from './useSearchModal';
|
import useSearchModal from './useSearchModal';
|
||||||
|
|
||||||
interface stofcbrCqlFiltersParams {
|
|
||||||
ctpvCd: string;
|
export const stofcbrCqlFilters = () => {
|
||||||
sggCd: string;
|
|
||||||
yearFilter: { start: string; end: string };
|
|
||||||
todayYear: string;
|
|
||||||
todayMonth: string;
|
|
||||||
todayDate: string;
|
|
||||||
getDateString: (year: string, month: string, day: string, defaultDate: string) => string;
|
|
||||||
}
|
|
||||||
export const stofcbrCqlFilters = (params: stofcbrCqlFiltersParams) => {
|
|
||||||
const {
|
const {
|
||||||
ctpvCd, sggCd,
|
ctpvCd, sggCd,
|
||||||
yearFilter,
|
yearFilter,
|
||||||
todayYear, todayMonth, todayDate,
|
todayYear, todayMonth, todayDate,
|
||||||
getDateString
|
getDateString
|
||||||
} = params;
|
} = useSearchModalStore.getState();
|
||||||
|
|
||||||
const cqlFilters: string[] = [];
|
const cqlFilters: string[] = [];
|
||||||
// 시도, 시군구
|
// 시도, 시군구
|
||||||
@@ -48,13 +40,13 @@ export const stofcbrCqlFilters = (params: stofcbrCqlFiltersParams) => {
|
|||||||
return cqlFilters;
|
return cqlFilters;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Stofcbr: React.FC<SearchModalProps> = (props) => {
|
const Stofcbr: React.FC = () => {
|
||||||
const {
|
const {
|
||||||
ctpvCd, setCtpvCd,
|
ctpvCd, setCtpvCd,
|
||||||
sggCd, setSggCd,
|
sggCd, setSggCd,
|
||||||
yearFilter, setYearFilter,
|
yearFilter, setYearFilter,
|
||||||
} = useSearchModalStore();
|
} = useSearchModalStore();
|
||||||
const { handleSearch } = useSearchModal(props);
|
const { handleSearch } = useSearchModal();
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -7,21 +7,10 @@ import { MS_SWAGE_MHL_USE_CODES } from '../components/common/table';
|
|||||||
import { SelectBox } from '@common/business_components/ui';
|
import { SelectBox } from '@common/business_components/ui';
|
||||||
import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox';
|
import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox';
|
||||||
import useSearchModalStore from '../../../store/useSearchModalStore';
|
import useSearchModalStore from '../../../store/useSearchModalStore';
|
||||||
import { useSearchModal, type SearchModalProps } from './useSearchModal';
|
import useSearchModal from './useSearchModal';
|
||||||
|
|
||||||
interface swageMhlCqlFiltersParams {
|
|
||||||
ctpvCd: string;
|
export const swageMhlCqlFilters = () => {
|
||||||
sggCd: string;
|
|
||||||
yearFilter: { start: string; end: string };
|
|
||||||
start1: string;
|
|
||||||
end1: string;
|
|
||||||
var1: string;
|
|
||||||
todayYear: string;
|
|
||||||
todayMonth: string;
|
|
||||||
todayDate: string;
|
|
||||||
getDateString: (year: string, month: string, day: string, defaultDate: string) => string;
|
|
||||||
}
|
|
||||||
export const swageMhlCqlFilters = (params: swageMhlCqlFiltersParams) => {
|
|
||||||
const {
|
const {
|
||||||
ctpvCd, sggCd,
|
ctpvCd, sggCd,
|
||||||
yearFilter,
|
yearFilter,
|
||||||
@@ -29,7 +18,7 @@ export const swageMhlCqlFilters = (params: swageMhlCqlFiltersParams) => {
|
|||||||
var1,
|
var1,
|
||||||
todayYear, todayMonth, todayDate,
|
todayYear, todayMonth, todayDate,
|
||||||
getDateString
|
getDateString
|
||||||
} = params;
|
} = useSearchModalStore.getState();
|
||||||
|
|
||||||
const cqlFilters: string[] = [];
|
const cqlFilters: string[] = [];
|
||||||
// 시도, 시군구
|
// 시도, 시군구
|
||||||
@@ -60,7 +49,7 @@ export const swageMhlCqlFilters = (params: swageMhlCqlFiltersParams) => {
|
|||||||
return cqlFilters;
|
return cqlFilters;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SwageMhl: React.FC<SearchModalProps> = (props) => {
|
const SwageMhl: React.FC = () => {
|
||||||
const {
|
const {
|
||||||
var1, setVar1,
|
var1, setVar1,
|
||||||
start1, setStart1, end1, setEnd1,
|
start1, setStart1, end1, setEnd1,
|
||||||
@@ -68,7 +57,7 @@ const SwageMhl: React.FC<SearchModalProps> = (props) => {
|
|||||||
sggCd, setSggCd,
|
sggCd, setSggCd,
|
||||||
yearFilter, setYearFilter,
|
yearFilter, setYearFilter,
|
||||||
} = useSearchModalStore();
|
} = useSearchModalStore();
|
||||||
const { handleSearch } = useSearchModal(props);
|
const { handleSearch } = useSearchModal();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
|
|||||||
@@ -5,29 +5,17 @@ import { Button, Input, Label } from '@common/components';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox';
|
import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox';
|
||||||
import useSearchModalStore from '../../../store/useSearchModalStore';
|
import useSearchModalStore from '../../../store/useSearchModalStore';
|
||||||
import { useSearchModal, type SearchModalProps } from './useSearchModal';
|
import useSearchModal from './useSearchModal';
|
||||||
|
|
||||||
interface swagePmstnCqlFiltersParams {
|
|
||||||
ctpvCd: string;
|
export const swagePmstnCqlFilters = () => {
|
||||||
sggCd: string;
|
|
||||||
yearFilter: { start: string; end: string };
|
|
||||||
start1: string;
|
|
||||||
start2: string;
|
|
||||||
end1: string;
|
|
||||||
end2: string;
|
|
||||||
todayYear: string;
|
|
||||||
todayMonth: string;
|
|
||||||
todayDate: string;
|
|
||||||
getDateString: (year: string, month: string, day: string, defaultDate: string) => string;
|
|
||||||
}
|
|
||||||
export const swagePmstnCqlFilters = (params: swagePmstnCqlFiltersParams) => {
|
|
||||||
const {
|
const {
|
||||||
ctpvCd, sggCd,
|
ctpvCd, sggCd,
|
||||||
yearFilter,
|
yearFilter,
|
||||||
start1, start2, end1, end2,
|
start1, start2, end1, end2,
|
||||||
todayYear, todayMonth, todayDate,
|
todayYear, todayMonth, todayDate,
|
||||||
getDateString
|
getDateString
|
||||||
} = params;
|
} = useSearchModalStore.getState();
|
||||||
|
|
||||||
const cqlFilters: string[] = [];
|
const cqlFilters: string[] = [];
|
||||||
// 시도, 시군구
|
// 시도, 시군구
|
||||||
@@ -63,7 +51,7 @@ export const swagePmstnCqlFilters = (params: swagePmstnCqlFiltersParams) => {
|
|||||||
return cqlFilters;
|
return cqlFilters;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SwagePmstn: React.FC<SearchModalProps> = (props) => {
|
const SwagePmstn: React.FC = () => {
|
||||||
const {
|
const {
|
||||||
start1, setStart1,
|
start1, setStart1,
|
||||||
end1, setEnd1,
|
end1, setEnd1,
|
||||||
@@ -71,7 +59,7 @@ const SwagePmstn: React.FC<SearchModalProps> = (props) => {
|
|||||||
sggCd, setSggCd,
|
sggCd, setSggCd,
|
||||||
yearFilter, setYearFilter,
|
yearFilter, setYearFilter,
|
||||||
} = useSearchModalStore();
|
} = useSearchModalStore();
|
||||||
const { handleSearch } = useSearchModal(props);
|
const { handleSearch } = useSearchModal();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
|
|||||||
@@ -4,29 +4,14 @@ import { YearRangeSelectBox } from '@/components/ui/YearRangeSelectBox';
|
|||||||
import { SelectBox } from '@common/business_components/ui';
|
import { SelectBox } from '@common/business_components/ui';
|
||||||
import { Button, Input, Label } from '@common/components';
|
import { Button, Input, Label } from '@common/components';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { MS_SWAGE_PPL_CODES, MS_SWAGE_PPL_USE_CODES } from '../components/common/table';
|
import { MS_SWAGE_PPL_USE_CODES } from '../components/common/table';
|
||||||
import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox';
|
import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox';
|
||||||
import useSearchModalStore from '../../../store/useSearchModalStore';
|
import useSearchModalStore from '../../../store/useSearchModalStore';
|
||||||
import { useSearchModal, type SearchModalProps } from './useSearchModal';
|
import useSearchModal from './useSearchModal';
|
||||||
|
|
||||||
|
|
||||||
interface swagePplCqlFiltersParams {
|
|
||||||
var1: string;
|
|
||||||
var2: string;
|
|
||||||
ctpvCd: string;
|
|
||||||
sggCd: string;
|
|
||||||
yearFilter: { start: string; end: string };
|
|
||||||
start1: string;
|
|
||||||
start2: string;
|
|
||||||
end1: string;
|
|
||||||
end2: string;
|
|
||||||
todayYear: string;
|
|
||||||
todayMonth: string;
|
|
||||||
todayDate: string;
|
|
||||||
getDateString: (year: string, month: string, day: string, defaultDate: string) => string;
|
|
||||||
}
|
|
||||||
// 하수관로용 CQL 필터 생성
|
// 하수관로용 CQL 필터 생성
|
||||||
export const swagePplCqlFilters = (params: swagePplCqlFiltersParams) => {
|
export const swagePplCqlFilters = () => {
|
||||||
const {
|
const {
|
||||||
var1, var2,
|
var1, var2,
|
||||||
ctpvCd, sggCd,
|
ctpvCd, sggCd,
|
||||||
@@ -34,7 +19,7 @@ export const swagePplCqlFilters = (params: swagePplCqlFiltersParams) => {
|
|||||||
start1, start2, end1, end2,
|
start1, start2, end1, end2,
|
||||||
todayYear, todayMonth, todayDate,
|
todayYear, todayMonth, todayDate,
|
||||||
getDateString
|
getDateString
|
||||||
} = params;
|
} = useSearchModalStore.getState();
|
||||||
|
|
||||||
const cqlFilters: string[] = [];
|
const cqlFilters: string[] = [];
|
||||||
if (var1) cqlFilters.push(`usg_cd='${var1}'`);
|
if (var1) cqlFilters.push(`usg_cd='${var1}'`);
|
||||||
@@ -69,14 +54,14 @@ export const swagePplCqlFilters = (params: swagePplCqlFiltersParams) => {
|
|||||||
return cqlFilters;
|
return cqlFilters;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SwagePpl: React.FC<SearchModalProps> = (props) => {
|
const SwagePpl: React.FC = () => {
|
||||||
const {
|
const {
|
||||||
var1, setVar1,
|
var1, setVar1,
|
||||||
start1, setStart1, end1, setEnd1,
|
start1, setStart1, end1, setEnd1,
|
||||||
ctpvCd, setCtpvCd, sggCd, setSggCd,
|
ctpvCd, setCtpvCd, sggCd, setSggCd,
|
||||||
yearFilter, setYearFilter,
|
yearFilter, setYearFilter,
|
||||||
} = useSearchModalStore();
|
} = useSearchModalStore();
|
||||||
const { handleSearch } = useSearchModal(props);
|
const { handleSearch } = useSearchModal();
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -5,29 +5,18 @@ import { YearRangeSelectBox } from '@/components/ui/YearRangeSelectBox';
|
|||||||
import { Button, Input, Label } from '@common/components';
|
import { Button, Input, Label } from '@common/components';
|
||||||
import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox';
|
import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox';
|
||||||
import useSearchModalStore from '../../../store/useSearchModalStore';
|
import useSearchModalStore from '../../../store/useSearchModalStore';
|
||||||
import { useSearchModal, type SearchModalProps } from './useSearchModal';
|
import useSearchModal from './useSearchModal';
|
||||||
|
|
||||||
|
|
||||||
interface swagePrcsFcltCqlFiltersParams {
|
|
||||||
ctpvName: string;
|
|
||||||
sggName: string;
|
|
||||||
yearFilter: { start: string; end: string };
|
|
||||||
start1: string;
|
|
||||||
end1: string;
|
|
||||||
todayYear: string;
|
|
||||||
todayMonth: string;
|
|
||||||
todayDate: string;
|
|
||||||
getDateString: (year: string, month: string, day: string, defaultDate: string) => string;
|
|
||||||
}
|
|
||||||
// 하수처리시설용 CQL 필터 생성
|
// 하수처리시설용 CQL 필터 생성
|
||||||
export const swagePrcsFcltCqlFilters = (params: swagePrcsFcltCqlFiltersParams) => {
|
export const swagePrcsFcltCqlFilters = () => {
|
||||||
const {
|
const {
|
||||||
ctpvName, sggName,
|
ctpvName, sggName,
|
||||||
yearFilter,
|
yearFilter,
|
||||||
start1, end1,
|
start1, end1,
|
||||||
todayYear, todayMonth, todayDate,
|
todayYear, todayMonth, todayDate,
|
||||||
getDateString
|
getDateString
|
||||||
} = params;
|
} = useSearchModalStore.getState();
|
||||||
|
|
||||||
const cqlFilters: string[] = [];
|
const cqlFilters: string[] = [];
|
||||||
// 가동개시일자 범위
|
// 가동개시일자 범위
|
||||||
@@ -65,14 +54,14 @@ export const swagePrcsFcltCqlFilters = (params: swagePrcsFcltCqlFiltersParams) =
|
|||||||
return cqlFilters;
|
return cqlFilters;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SwagePrcsFclt: React.FC<SearchModalProps> = (props) => {
|
const SwagePrcsFclt: React.FC = () => {
|
||||||
const {
|
const {
|
||||||
start1, setStart1, end1, setEnd1,
|
start1, setStart1, end1, setEnd1,
|
||||||
ctpvCd, setCtpvCd, setCtpvName,
|
ctpvCd, setCtpvCd, setCtpvName,
|
||||||
sggCd, setSggCd, setSggName,
|
sggCd, setSggCd, setSggName,
|
||||||
yearFilter, setYearFilter,
|
yearFilter, setYearFilter,
|
||||||
} = useSearchModalStore();
|
} = useSearchModalStore();
|
||||||
const { handleSearch } = useSearchModal(props);
|
const { handleSearch } = useSearchModal();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
|
|||||||
@@ -4,21 +4,15 @@ import React from 'react';
|
|||||||
import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox';
|
import { CtpvSggPrcsFcltSelectBox } from '@/components/ui/ctpvSggPrcsFcltSelectBox';
|
||||||
import { Button, Input, Label } from '@common/components';
|
import { Button, Input, Label } from '@common/components';
|
||||||
import useSearchModalStore from '../../../store/useSearchModalStore';
|
import useSearchModalStore from '../../../store/useSearchModalStore';
|
||||||
import { useSearchModal, type SearchModalProps } from './useSearchModal';
|
import useSearchModal from './useSearchModal';
|
||||||
|
|
||||||
|
|
||||||
interface swagePrcsZoneCqlFiltersParams {
|
|
||||||
ctpvCd: string;
|
|
||||||
sggCd: string;
|
|
||||||
var1: string;
|
|
||||||
var2: string;
|
|
||||||
}
|
|
||||||
// 하수처리구역용 CQL 필터 생성
|
// 하수처리구역용 CQL 필터 생성
|
||||||
export const swagePrcsZoneCqlFilters = (params: swagePrcsZoneCqlFiltersParams) => {
|
export const swagePrcsZoneCqlFilters = () => {
|
||||||
const {
|
const {
|
||||||
ctpvCd, sggCd,
|
ctpvCd, sggCd,
|
||||||
var1, var2
|
var1, var2
|
||||||
} = params;
|
} = useSearchModalStore.getState();
|
||||||
const cqlFilters: string[] = [];
|
const cqlFilters: string[] = [];
|
||||||
if (ctpvCd !== '' && ctpvCd !== '0') cqlFilters.push(`ctpv_cd='${ctpvCd?.trim()}'`);
|
if (ctpvCd !== '' && ctpvCd !== '0') cqlFilters.push(`ctpv_cd='${ctpvCd?.trim()}'`);
|
||||||
if (sggCd !== '' && sggCd !== '0') cqlFilters.push(`sgg_cd='${sggCd}'`);
|
if (sggCd !== '' && sggCd !== '0') cqlFilters.push(`sgg_cd='${sggCd}'`);
|
||||||
@@ -27,13 +21,13 @@ export const swagePrcsZoneCqlFilters = (params: swagePrcsZoneCqlFiltersParams) =
|
|||||||
return cqlFilters;
|
return cqlFilters;
|
||||||
};
|
};
|
||||||
|
|
||||||
const swagePrcsZone: React.FC<SearchModalProps> = (props) => {
|
const swagePrcsZone: React.FC = () => {
|
||||||
const {
|
const {
|
||||||
var1, setVar1, var2, setVar2,
|
var1, setVar1, var2, setVar2,
|
||||||
ctpvCd, setCtpvCd,
|
ctpvCd, setCtpvCd,
|
||||||
sggCd, setSggCd,
|
sggCd, setSggCd,
|
||||||
} = useSearchModalStore();
|
} = useSearchModalStore();
|
||||||
const { handleSearch } = useSearchModal(props);
|
const { handleSearch } = useSearchModal();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
|
|||||||
@@ -0,0 +1,329 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { downloadExcelWithKoreanHeaders } from '@common/business_components/ui';
|
||||||
|
import axios from 'axios';
|
||||||
|
import {
|
||||||
|
MS_SWAGE_PPL_USE_CODES, MS_SWAGE_MHL_CODES, MS_SWAGE_MHL_USE_CODES,
|
||||||
|
MsSwagePplExcelCol, SwtrmtFcltExcelCol, SwtrmtPrcsZoneExcelCol, MsSwageMhlExcelCol, ExclnSewagePumpExcelCol, stofcbrExcelCol
|
||||||
|
} from '../components/common/table';
|
||||||
|
import { getData } from "@/components/lib/api";
|
||||||
|
import { BASIC_TYPES } from './basicTab';
|
||||||
|
import { formatDisplayData } from '@/components/lib/utils/formatDisplayValue';
|
||||||
|
import useStore from '../../../store/useStore';
|
||||||
|
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 { swagePplCqlFilters } from './swagePpl';
|
||||||
|
import { swagePrcsFcltCqlFilters } from './swagePrcsFclt';
|
||||||
|
import { swagePrcsZoneCqlFilters } from './swagePrcsZone';
|
||||||
|
import { swageMhlCqlFilters } from './swageMhl';
|
||||||
|
import { swagePmstnCqlFilters } from './swagePmstn';
|
||||||
|
import { stofcbrCqlFilters } from './stofcbr';
|
||||||
|
|
||||||
|
|
||||||
|
export default function useBasicTab() {
|
||||||
|
const {
|
||||||
|
basicType,
|
||||||
|
tableData,
|
||||||
|
curPage,
|
||||||
|
todayYear, todayMonth, todayDate,
|
||||||
|
setIsSearchModalOpen,
|
||||||
|
setTableData,
|
||||||
|
setTableCount,
|
||||||
|
setIsLoading,
|
||||||
|
} = useSearchModalStore();
|
||||||
|
const { ctpv, sgg } = useStore();
|
||||||
|
|
||||||
|
const fetchBasicFilteredData = async () => {
|
||||||
|
let cqlFilters: string[] = [];
|
||||||
|
const queryParams = new URLSearchParams({
|
||||||
|
lyrTypeNm: basicType,
|
||||||
|
page: `${curPage - 1}`,
|
||||||
|
size: '10',
|
||||||
|
sort: 'string',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (basicType === 'tb_ms_swage_ppl') cqlFilters = swagePplCqlFilters(); // 하수관로
|
||||||
|
else if (basicType === 'tb_il_swage_prcs_fclt') cqlFilters = swagePrcsFcltCqlFilters(); // 하수처리시설
|
||||||
|
else if (basicType === 'tb_ms_swage_prcs_zone') cqlFilters = swagePrcsZoneCqlFilters(); // 하수처리구역
|
||||||
|
else if (basicType === 'tb_ms_swage_mhl') cqlFilters = swageMhlCqlFilters(); // 하수맨홀
|
||||||
|
else if (basicType === 'tb_ms_swage_pmstn') cqlFilters = swagePmstnCqlFilters(); // 하수펌프장
|
||||||
|
else if (basicType === 'tb_ms_stofcbr') cqlFilters = stofcbrCqlFilters(); // 우수토실
|
||||||
|
if (cqlFilters.length > 0) queryParams.append('cqlFiter', cqlFilters.join(' and '));
|
||||||
|
|
||||||
|
const res = await getData(`v1/fclts?${queryParams.toString()}`);
|
||||||
|
// const res = await axios.get(`${API_URL}/v1/fclts?${queryParams.toString()}`);
|
||||||
|
console.log('fetch res', res);
|
||||||
|
console.log('fetch res.data', res.data);
|
||||||
|
console.log('fetch res.count', res.count);
|
||||||
|
console.log('fetch res.length', res.length);
|
||||||
|
|
||||||
|
// 🎯 각 아이템을 개별적으로 포맷팅하면서 일련번호 추가
|
||||||
|
const dataWithRowNumber = (res.data || []).map((item: any, index: number) => {
|
||||||
|
// 🎯 먼저 각 아이템을 포맷팅
|
||||||
|
const formattedItem = formatDisplayData(item);
|
||||||
|
|
||||||
|
let ctpvCd = item?.ctpvNm ?? formattedItem?.ctpvNm ?? '';
|
||||||
|
let sggCd = item?.sggNm ?? formattedItem?.sggNm ?? '';
|
||||||
|
|
||||||
|
if (!ctpvCd || !sggCd) {
|
||||||
|
const code = String(item?.pbadmsEmdCd ?? formattedItem?.pbadmsEmdCd ?? '')?.trim();
|
||||||
|
if (!ctpvCd && code) ctpvCd = code.slice(0, 2);
|
||||||
|
if (!sggCd && code) sggCd = code.slice(0, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
const matchedMhlCode = MS_SWAGE_MHL_CODES.find(code => code.val === item?.mqltCd?.trim());
|
||||||
|
const matchedMhlUsgCode = MS_SWAGE_MHL_USE_CODES.find(code => code.val === item?.usgCd);
|
||||||
|
const ctpvNm = ctpv.find(code => code.val.trim() === ctpvCd)?.text || item?.ctpvNm;
|
||||||
|
const sggNm = sgg.find(code => code.val.trim() === sggCd)?.text || item?.sggNm;
|
||||||
|
const usgCdObj = MS_SWAGE_PPL_USE_CODES.find(code => code.val === item?.usgCd?.trim());
|
||||||
|
|
||||||
|
// 추가 처리 및 일련번호 추가
|
||||||
|
return {
|
||||||
|
...formattedItem,
|
||||||
|
rowNumber: (curPage - 1) * 10 + index + 1, // 1부터 시작하는 일련번호 추가
|
||||||
|
scsYn: item.scsYn === null || item.scsYn === undefined ? 'N' : item?.scsYn, // scsYn이 null이면 'N'으로 변경
|
||||||
|
mqltCd: matchedMhlCode ? matchedMhlCode.text : item?.mqltCd,
|
||||||
|
usgCd: matchedMhlUsgCode ? matchedMhlUsgCode.text : (usgCdObj ? usgCdObj.text : item?.usgCd),
|
||||||
|
ctpvNm: ctpvNm ?? '-',
|
||||||
|
sggNm: sggNm ?? '-',
|
||||||
|
swtrmt_zone_nm: item.swtrmtZoneNm || item.swtrmt_zone_nm || '-',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
setTableData(dataWithRowNumber);
|
||||||
|
setTableCount(res.count || []);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 기본정보 테이블 cellClick 핸들러
|
||||||
|
const handleBasicCellClick = async (index?: number | undefined, headId?: String) => {
|
||||||
|
if (typeof index === "number") {
|
||||||
|
setIsLoading(true);
|
||||||
|
|
||||||
|
const row = tableData[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 닫기
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 기본정보 Excel 다운로드 핸들러
|
||||||
|
const basicExcelDownload = async () => {
|
||||||
|
if (tableData.length === 0) {
|
||||||
|
alert("다운로드 할 Excel 파일이 없습니다.\n조회 후 다시 시도해주세요.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.dismiss("global-confirm-toast");
|
||||||
|
|
||||||
|
confirmToast(
|
||||||
|
"파일 다운로드에는 2분 내외의 시간이 소요될 수 있습니다.\n파일 다운로드를 진행하시겠습니까?",
|
||||||
|
onDownload ?? (() => { }),
|
||||||
|
"text-xl font-medium text-gray-800"
|
||||||
|
);
|
||||||
|
|
||||||
|
async function onDownload() {
|
||||||
|
setIsLoading(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const queryParams = new URLSearchParams({
|
||||||
|
lyrTypeNm: basicType,
|
||||||
|
size: '10000',
|
||||||
|
});
|
||||||
|
|
||||||
|
let cqlFilters: string[] = [];
|
||||||
|
let headerMapping: { [key: string]: string } = {};
|
||||||
|
let headerRange: string = "A1:F1";
|
||||||
|
|
||||||
|
switch (basicType) {
|
||||||
|
case 'tb_ms_swage_ppl': {
|
||||||
|
// 하수관로
|
||||||
|
cqlFilters = swagePplCqlFilters()
|
||||||
|
headerMapping = MsSwagePplExcelCol;
|
||||||
|
headerRange = "A1:M1";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'tb_il_swage_prcs_fclt': {
|
||||||
|
// 하수처리시설
|
||||||
|
cqlFilters = swagePrcsFcltCqlFilters();
|
||||||
|
headerMapping = SwtrmtFcltExcelCol;
|
||||||
|
headerRange = "A1:J1";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'tb_ms_swage_prcs_zone': {
|
||||||
|
// 하수처리구역
|
||||||
|
cqlFilters = swagePrcsZoneCqlFilters();
|
||||||
|
headerMapping = SwtrmtPrcsZoneExcelCol;
|
||||||
|
headerRange = "A1:D1";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'tb_ms_swage_mhl': {
|
||||||
|
// 하수맨홀
|
||||||
|
cqlFilters = swageMhlCqlFilters();
|
||||||
|
headerMapping = MsSwageMhlExcelCol;
|
||||||
|
headerRange = "A1:J1";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'tb_ms_swage_pmstn': {
|
||||||
|
// 하수펌프장
|
||||||
|
cqlFilters = swagePmstnCqlFilters();
|
||||||
|
headerMapping = ExclnSewagePumpExcelCol;
|
||||||
|
headerRange = "A1:J1";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'tb_ms_stofcbr': {
|
||||||
|
// 우수토실
|
||||||
|
cqlFilters = stofcbrCqlFilters();
|
||||||
|
headerMapping = stofcbrExcelCol;
|
||||||
|
headerRange = "A1:H1";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cqlFilters.length > 0) queryParams.append('cqlFiter', cqlFilters.join(' and '));
|
||||||
|
|
||||||
|
const res = await getData(`v1/fclts?${queryParams.toString()}`);
|
||||||
|
// const res = await axios.get(`${API_URL}/v1/fclts?${queryParams.toString()}`);
|
||||||
|
console.log('onDownload res', res);
|
||||||
|
|
||||||
|
const mhlUsgCdMap = new Map(MS_SWAGE_MHL_USE_CODES.map(code => [code.val?.trim(), code.text]));
|
||||||
|
const pplUsgCdMap = new Map(MS_SWAGE_PPL_USE_CODES.map(code => [code.val?.trim(), code.text]));
|
||||||
|
const ctpvMap = new Map(ctpv.map(code => [code.val?.trim(), code.text]));
|
||||||
|
const sggMap = new Map(sgg.map(code => [code.val?.trim(), code.text]));
|
||||||
|
|
||||||
|
const mappedContent = (res.data.data || []).map((item: any) => {
|
||||||
|
const formattedItem = formatDisplayData(item);
|
||||||
|
|
||||||
|
let ctpvCd = item?.ctpvCd ?? formattedItem?.ctpvCd ?? '';
|
||||||
|
let sggCd = item?.sggCd ?? formattedItem?.sggCd ?? '';
|
||||||
|
|
||||||
|
if (!ctpvCd || !sggCd) {
|
||||||
|
const code = String(item?.pbadmsEmdCd ?? formattedItem?.pbadmsEmdCd ?? '')?.trim();
|
||||||
|
if (!ctpvCd && code) ctpvCd = code.slice(0, 2);
|
||||||
|
if (!sggCd && code) sggCd = code.slice(0, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// trim 한 번만 수행
|
||||||
|
const trimmedUsgCd = item?.usgCd?.trim();
|
||||||
|
// const trimmedMqltCd = item?.mqltCd?.trim();
|
||||||
|
|
||||||
|
switch (basicType) {
|
||||||
|
case 'tb_ms_swage_ppl': {
|
||||||
|
// 하수관로
|
||||||
|
return {
|
||||||
|
fcltMngNo: formattedItem.fcltMngNo ?? item.fcltMngNo ?? '-',
|
||||||
|
instMngNo: formattedItem.instMngNo ?? item.instMngNo ?? '-',
|
||||||
|
ctpvNm: ctpvMap.get(ctpvCd) ?? item.ctpvNm ?? '-',
|
||||||
|
sggNm: sggMap.get(sggCd) ?? item.sggNm ?? '-',
|
||||||
|
swtrmt_zone_nm: formattedItem.swtrmt_zone_nm ?? item.swtrmt_zone_nm ?? '-',
|
||||||
|
instlYmd: formattedItem.instlYmd ?? item.instlYmd ?? '-',
|
||||||
|
usgCd: pplUsgCdMap.get(trimmedUsgCd) || item.usgCd || formattedItem.usgCd || '-',
|
||||||
|
pdmtVl: formattedItem.pdmtVl ?? item.pdmtVl ?? '-',
|
||||||
|
prlgVl: formattedItem.prlgVl ?? item.prlgVl ?? '-',
|
||||||
|
tmptDpth: formattedItem.tmptDpth ?? item.tmptDpth ?? '-',
|
||||||
|
tmptMhlMngNo: formattedItem.tmptMhlMngNo ?? item.tmptMhlMngNo ?? '-',
|
||||||
|
scendDpth: formattedItem.scendDpth ?? item.scendDpth ?? '-',
|
||||||
|
scendMhlMngNo: formattedItem.scendMhlMngNo ?? item.scendMhlMngNo ?? '-',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 'tb_il_swage_prcs_fclt': {
|
||||||
|
// 하수처리시설
|
||||||
|
return {
|
||||||
|
swtrmtFcltNm: formattedItem.swtrmtFcltNm ?? item.swtrmtFcltNm ?? '-',
|
||||||
|
fcltCpct: formattedItem.fcltCpct ?? item.fcltCpct ?? '-',
|
||||||
|
rgnExpln: formattedItem.rgnExpln ?? item.rgnExpln ?? '-',
|
||||||
|
oprtngStrtYmd: formattedItem.oprtngStrtYmd ?? item.oprtngStrtYmd ?? '-',
|
||||||
|
laeNm: formattedItem.laeNm ?? item.laeNm ?? '-',
|
||||||
|
sareaNm: formattedItem.sareaNm ?? item.sareaNm ?? '-',
|
||||||
|
rvrNm: formattedItem.rvrNm ?? item.rvrNm ?? '-',
|
||||||
|
dschgWtstNm: formattedItem.dschgWtstNm ?? item.dschgWtstNm ?? '-',
|
||||||
|
swtrmtPpltnCnt: formattedItem.swtrmtPpltnCnt ?? item.swtrmtPpltnCnt ?? '-',
|
||||||
|
rprsMsrcCn: formattedItem.rprsMsrcCn ?? item.rprsMsrcCn ?? '-'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 'tb_ms_swage_prcs_zone': {
|
||||||
|
// 하수처리구역
|
||||||
|
return {
|
||||||
|
swtrmtZoneNm: formattedItem.swtrmtZoneNm ?? item.swtrmtZoneNm ?? '-',
|
||||||
|
ctpvNm: ctpvMap.get(ctpvCd) ?? formattedItem.ctpvNm ?? '-',
|
||||||
|
sggNm: sggMap.get(sggCd) ?? formattedItem.sggNm ?? '-',
|
||||||
|
swtrmtFcltNm: formattedItem.swtrmtFcltNm ?? item.swtrmtFcltNm ?? '-'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 'tb_ms_swage_mhl': {
|
||||||
|
// 하수맨홀
|
||||||
|
return {
|
||||||
|
fcltMngNo: formattedItem.fcltMngNo ?? item.fcltMngNo ?? '-',
|
||||||
|
ctpvNm: ctpvMap.get(ctpvCd) ?? formattedItem.ctpvNm ?? '-',
|
||||||
|
sggNm: sggMap.get(sggCd) ?? formattedItem.sggNm ?? '-',
|
||||||
|
instlYmd: formattedItem.instlYmd ?? item.instlYmd ?? '-',
|
||||||
|
usgCd: mhlUsgCdMap.get(trimmedUsgCd) || item.usgCd || formattedItem.usgCd || '-',
|
||||||
|
swageMhlDiamVl: formattedItem.swageMhlDiamVl ?? item.swageMhlDiamVl ?? '-',
|
||||||
|
wdthLen: formattedItem.wdthLen ?? item.wdthLen ?? '-',
|
||||||
|
vrtcLen: formattedItem.vrtcLen ?? item.vrtcLen ?? '-',
|
||||||
|
altdVl: formattedItem.altdVl ?? item.altdVl ?? '-',
|
||||||
|
dpthlVl: formattedItem.dpthlVl ?? item.dpthlVl ?? '-'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 'tb_ms_swage_pmstn': {
|
||||||
|
// 하수펌프장
|
||||||
|
return {
|
||||||
|
fcltMngNo: formattedItem.fcltMngNo ?? item.fcltMngNo ?? '-',
|
||||||
|
ctpvNm: ctpvMap.get(ctpvCd) ?? formattedItem.ctpvNm ?? '-',
|
||||||
|
sggNm: sggMap.get(sggCd) ?? formattedItem.sggNm ?? '-',
|
||||||
|
swagePmstnNm: formattedItem.swagePmstnNm ?? item.swagePmstnNm ?? '-',
|
||||||
|
instlYmd: formattedItem.instlYmd ?? item.instlYmd ?? '-',
|
||||||
|
dailyPrcsCpct: formattedItem.dailyPrcsCpct ?? item.dailyPrcsCpct ?? '-',
|
||||||
|
maxImpndCpct: formattedItem.maxImpndCpct ?? item.maxImpndCpct ?? '-',
|
||||||
|
altdVl: formattedItem.altdVl ?? item.altdVl ?? '-',
|
||||||
|
wtlvVl: formattedItem.wtlvVl ?? item.wtlvVl ?? '-',
|
||||||
|
exclnWpmpAbltVl: formattedItem.exclnWpmpAbltVl ?? item.exclnWpmpAbltVl ?? '-'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 'tb_ms_stofcbr': {
|
||||||
|
// 우수토실
|
||||||
|
return {
|
||||||
|
fcltMngNo: formattedItem.fcltMngNo ?? item.fcltMngNo ?? '-',
|
||||||
|
mapshtNo: formattedItem.mapshtNo ?? item.mapshtNo ?? '-',
|
||||||
|
ctpvNm: ctpvMap.get(ctpvCd) ?? formattedItem.ctpvNm ?? '-',
|
||||||
|
sggNm: sggMap.get(sggCd) ?? formattedItem.sggNm ?? '-',
|
||||||
|
instlYmd: formattedItem.instlYmd ?? item.instlYmd ?? '-',
|
||||||
|
worflwWallHgt: formattedItem.worflwWallHgt ?? item.worflwWallHgt ?? '-',
|
||||||
|
swageMhlMngNo: formattedItem.swageMhlMngNo ?? item.swageMhlMngNo ?? '-',
|
||||||
|
drtnAngl: formattedItem.drtnAngl ?? item.drtnAngl ?? '-'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 선택된 행 데이터를 Excel 다운로드 형식으로 변환
|
||||||
|
const excelData = mappedContent; // 배열로 감싸서 전달
|
||||||
|
|
||||||
|
// 파일명 생성 (분석번호 기반)
|
||||||
|
const label = BASIC_TYPES.find((type) => type.val === basicType)?.text
|
||||||
|
const fileName = `${label} 조회 결과_${todayYear}${todayMonth}${todayDate}`;
|
||||||
|
|
||||||
|
console.log(`excelData: ${excelData}, label: ${label}, fileName: ${fileName}`);
|
||||||
|
|
||||||
|
await downloadExcelWithKoreanHeaders({
|
||||||
|
data: excelData as JSON[],
|
||||||
|
fileName: fileName,
|
||||||
|
sheetNameArray: [fileName],
|
||||||
|
headerRange: headerRange,
|
||||||
|
headerMapping: headerMapping
|
||||||
|
});
|
||||||
|
setIsLoading(false);
|
||||||
|
} catch (error) {
|
||||||
|
setIsLoading(false);
|
||||||
|
console.error("Excel 다운로드 중 오류 발생:", error);
|
||||||
|
alert("Excel 다운로드 중 오류가 발생했습니다. 다시 시도해주세요.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return { fetchBasicFilteredData, handleBasicCellClick, basicExcelDownload };
|
||||||
|
};
|
||||||
@@ -0,0 +1,439 @@
|
|||||||
|
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<string, string> = {
|
||||||
|
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<string, string> = {
|
||||||
|
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<string, string> = {
|
||||||
|
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<string, string> = {
|
||||||
|
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<string, string> = {
|
||||||
|
size: '10000',
|
||||||
|
bizId: String(detailBizId),
|
||||||
|
};
|
||||||
|
|
||||||
|
const apiStartTime = performance.now();
|
||||||
|
const res = await getData(`v1/bizInfo/fclts?${new URLSearchParams(RequestDTO).toString()}`);
|
||||||
|
const apiEndTime = performance.now();
|
||||||
|
|
||||||
|
const mappingStartTime = performance.now();
|
||||||
|
// 헤더 매핑 정의
|
||||||
|
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
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
import { getDcData } from '@/components/lib/api';
|
||||||
|
import { fileDownload } from '@/utils';
|
||||||
|
import { useReportTabStore } from '@/store/useReportTabStore';
|
||||||
|
import useSearchModalStore from '@/app/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<ReportDataFile[]> => {
|
||||||
|
if (!clsfSystmSn) {
|
||||||
|
console.error("clsfSystmSn is required to get files.");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const queryString = 'clsfSystmSn=' + clsfSystmSn;
|
||||||
|
const result = await getDcData(`/api/v1/dc/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/dc/file/download${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
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
import { getData } from "@/components/lib/api";
|
||||||
|
import { formatDisplayData } from '@/components/lib/utils/formatDisplayValue';
|
||||||
|
import useStore from '../../../store/useStore';
|
||||||
|
import GisApp from "@common/business_components/ui/map/lib/gis.core";
|
||||||
|
import useSearchModalStore from '../../../store/useSearchModalStore';
|
||||||
|
import useBasicTab from './useBasicTab';
|
||||||
|
import useOperationTab from './useOperationTab';
|
||||||
|
|
||||||
|
export default function useSearchModal() {
|
||||||
|
const {
|
||||||
|
activeTab, basicType, workType,
|
||||||
|
showTable,
|
||||||
|
tableData, detailTableData,
|
||||||
|
curPage, detailCurPage,
|
||||||
|
detailBizId,
|
||||||
|
var1, var2,
|
||||||
|
yearFilter,
|
||||||
|
todayYear, todayMonth, todayDate,
|
||||||
|
setIsSearchModalOpen,
|
||||||
|
setShowTable,
|
||||||
|
setTableData, setDetailTableData,
|
||||||
|
setTableCount, setDetailTableCount,
|
||||||
|
setCurPage,
|
||||||
|
setIsLoading,
|
||||||
|
setIsResetPage, setIsResetDetailPage,
|
||||||
|
setIsResetSelection, setIsResetDetailSelection,
|
||||||
|
setDetailBizId,
|
||||||
|
resetFilters,
|
||||||
|
getDateString
|
||||||
|
} = useSearchModalStore();
|
||||||
|
const { fetchBasicFilteredData } = useBasicTab();
|
||||||
|
const { OPERATION_TABLE_SIZE, handleOperationPageNation } = useOperationTab();
|
||||||
|
const { BIZ_TY_CD } = useStore();
|
||||||
|
|
||||||
|
const TABS = [
|
||||||
|
{ val: "basic", text: "기본정보" },
|
||||||
|
{ val: "operation", text: "운영정보" },
|
||||||
|
{ val: "report", text: "하수도정비기본계획보고서" },
|
||||||
|
];
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
resetFilters();
|
||||||
|
}, [activeTab, basicType, workType]);
|
||||||
|
|
||||||
|
// 페이지 변경 시마다 데이터 fetch
|
||||||
|
useEffect(() => {
|
||||||
|
setIsResetPage(false);
|
||||||
|
setIsResetDetailPage(true);
|
||||||
|
setDetailBizId(0);
|
||||||
|
console.log(`curPage: ${curPage}, showTable: ${showTable}`);
|
||||||
|
if (showTable && curPage > 1) fetchFilteredData();
|
||||||
|
}, [curPage]);
|
||||||
|
|
||||||
|
// 페이지 변경 시마다 데이터 fetch
|
||||||
|
useEffect(() => {
|
||||||
|
setIsResetDetailSelection(false);
|
||||||
|
if (showTable) handleOperationPageNation(Number(detailBizId));
|
||||||
|
}, [detailCurPage]);
|
||||||
|
|
||||||
|
// 검색 API 호출 함수
|
||||||
|
const fetchFilteredData = async () => {
|
||||||
|
setIsLoading(true); // 로딩 시작
|
||||||
|
setIsResetSelection(true); // 선택 초기화
|
||||||
|
setIsResetDetailSelection(true); // 선택 초기화
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (activeTab === 'basic') {
|
||||||
|
fetchBasicFilteredData();
|
||||||
|
|
||||||
|
} else if (activeTab === 'operation') {
|
||||||
|
const RequestDTO: Record<string, string> = {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
setShowTable(true);
|
||||||
|
setIsResetSelection(false);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('API ERROR:', err);
|
||||||
|
setTableData([]);
|
||||||
|
setIsResetSelection(false);
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false); // 로딩 종료
|
||||||
|
setIsResetSelection(false);
|
||||||
|
// setIsResetDetailSelection(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 조회 버튼 클릭 시 1페이지로 이동 및 데이터 초기화
|
||||||
|
const handleSearch = () => {
|
||||||
|
setCurPage(1); // 페이지를 1로 초기화
|
||||||
|
fetchFilteredData();
|
||||||
|
setIsResetPage(true); // 페이지를 초기화
|
||||||
|
setIsResetDetailPage(true); // 디테일 페이지를 초기화
|
||||||
|
setIsResetSelection(false); // 선택 초기화
|
||||||
|
setIsResetDetailSelection(false); // 선택 초기화
|
||||||
|
setShowTable(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 여러 시설 보기
|
||||||
|
const viewMultipleFeature = async () => {
|
||||||
|
if (activeTab === 'basic') {
|
||||||
|
if (!(tableData.length === 0)) {
|
||||||
|
setIsLoading(true);
|
||||||
|
|
||||||
|
const row = tableData[0];
|
||||||
|
const layerNm = row.lyrTypeNm;
|
||||||
|
const fids = tableData.map((item) => item.fid);
|
||||||
|
const core = GisApp.Module.layer as any;
|
||||||
|
await core.showMultipleSearchResultsFromGeoJSON(layerNm, fids);
|
||||||
|
setIsLoading(false);
|
||||||
|
setIsSearchModalOpen(false);
|
||||||
|
}
|
||||||
|
} else if (activeTab === 'operation') {
|
||||||
|
if (!(detailTableData.length === 0)) {
|
||||||
|
setIsLoading(true);
|
||||||
|
|
||||||
|
const row = detailTableData[0];
|
||||||
|
const layerNm = row.lyrTypeNm;
|
||||||
|
const fids = detailTableData.map((item) => item.fid);
|
||||||
|
const core = GisApp.Module.layer as any;
|
||||||
|
await core.showMultipleSearchResultsFromGeoJSON(layerNm, fids);
|
||||||
|
setIsLoading(false);
|
||||||
|
setIsSearchModalOpen(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { TABS, getDateString, handleSearch, viewMultipleFeature };
|
||||||
|
};
|
||||||
@@ -1,841 +0,0 @@
|
|||||||
import { useEffect, useState } from 'react';
|
|
||||||
import { downloadExcelWithKoreanHeaders } from '@common/business_components/ui';
|
|
||||||
import axios from 'axios';
|
|
||||||
import {
|
|
||||||
MS_SWAGE_PPL_CODES, MS_SWAGE_PPL_USE_CODES, MS_SWAGE_MHL_CODES, MS_SWAGE_MHL_USE_CODES,
|
|
||||||
MsSwagePplExcelCol, SwtrmtFcltExcelCol, SwtrmtPrcsZoneExcelCol, MsSwageMhlExcelCol, ExclnSewagePumpExcelCol, stofcbrExcelCol
|
|
||||||
} from '../components/common/table';
|
|
||||||
import { getData } from "@/components/lib/api";
|
|
||||||
import { BASIC_TYPES } from './basicTab';
|
|
||||||
import { WORK_TYPES } from './operationTab';
|
|
||||||
import { formatDisplayData } from '@/components/lib/utils/formatDisplayValue';
|
|
||||||
import useStore from '../../../store/useStore';
|
|
||||||
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 { swagePplCqlFilters } from './swagePpl';
|
|
||||||
import { swagePrcsFcltCqlFilters } from './swagePrcsFclt';
|
|
||||||
import { swagePrcsZoneCqlFilters } from './swagePrcsZone';
|
|
||||||
import { swageMhlCqlFilters } from './swageMhl';
|
|
||||||
import { swagePmstnCqlFilters } from './swagePmstn';
|
|
||||||
import { stofcbrCqlFilters } from './stofcbr';
|
|
||||||
|
|
||||||
const API_URL = `${process.env.NEXT_PUBLIC_SEWERAGE_API_URL}`;
|
|
||||||
export const OPERATION_TABLE_SIZE = 5;
|
|
||||||
|
|
||||||
export interface SearchModalProps {
|
|
||||||
open: boolean;
|
|
||||||
onOpenChange: (open: boolean) => void;
|
|
||||||
onFeatureSelect: (row: any) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useSearchModal({ open, onOpenChange, onFeatureSelect }: SearchModalProps) {
|
|
||||||
const {
|
|
||||||
activeTab, basicType, workType,
|
|
||||||
showTable,
|
|
||||||
tableData, detailTableData,
|
|
||||||
curPage, detailCurPage,
|
|
||||||
detailBizId,
|
|
||||||
ctpvCd, ctpvName, sggCd, sggName,
|
|
||||||
start1, start2, end1, end2,
|
|
||||||
var1, var2,
|
|
||||||
yearFilter,
|
|
||||||
todayYear, todayMonth, todayDate,
|
|
||||||
setShowTable,
|
|
||||||
setTableData, setDetailTableData,
|
|
||||||
setTableCount, setDetailTableCount,
|
|
||||||
setCurPage, setDetailCurPage,
|
|
||||||
setIsLoading, setIsDetailLoading,
|
|
||||||
setIsResetPage, setIsResetDetailPage,
|
|
||||||
setIsResetSelection, setIsResetDetailSelection,
|
|
||||||
setDetailBizId,
|
|
||||||
resetFilters,
|
|
||||||
getDateString
|
|
||||||
} = useSearchModalStore();
|
|
||||||
const { ctpv, sgg, BIZ_TY_CD } = useStore();
|
|
||||||
|
|
||||||
const TABS = [
|
|
||||||
{ val: "basic", text: "기본정보" },
|
|
||||||
{ val: "operation", text: "운영정보" },
|
|
||||||
{ val: "report", text: "하수도정비기본계획보고서" },
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
resetFilters();
|
|
||||||
}, [activeTab, basicType, workType]);
|
|
||||||
|
|
||||||
// 페이지 변경 시마다 데이터 fetch
|
|
||||||
useEffect(() => {
|
|
||||||
setIsResetPage(false);
|
|
||||||
setIsResetDetailPage(true);
|
|
||||||
setDetailBizId(0);
|
|
||||||
if (showTable) fetchFilteredData();
|
|
||||||
}, [curPage]);
|
|
||||||
|
|
||||||
// 페이지 변경 시마다 데이터 fetch
|
|
||||||
useEffect(() => {
|
|
||||||
setIsResetDetailSelection(false);
|
|
||||||
if (showTable) handleOperationPageNation(Number(detailBizId));
|
|
||||||
}, [detailCurPage]);
|
|
||||||
|
|
||||||
|
|
||||||
// 검색 API 호출 함수
|
|
||||||
const fetchFilteredData = async () => {
|
|
||||||
setIsLoading(true); // 로딩 시작
|
|
||||||
setIsResetSelection(true); // 선택 초기화
|
|
||||||
setIsResetDetailSelection(true); // 선택 초기화
|
|
||||||
|
|
||||||
try {
|
|
||||||
let cqlFilters: string[] = [];
|
|
||||||
if (activeTab === 'basic') {
|
|
||||||
const queryParams = new URLSearchParams({
|
|
||||||
lyrTypeNm: basicType,
|
|
||||||
page: `${curPage - 1}`,
|
|
||||||
size: '10',
|
|
||||||
sort: 'string',
|
|
||||||
});
|
|
||||||
|
|
||||||
if (basicType === 'tb_ms_swage_prcs_zone') cqlFilters = swagePrcsZoneCqlFilters({
|
|
||||||
ctpvCd, sggCd,
|
|
||||||
var1, var2
|
|
||||||
}); // 하수처리구역
|
|
||||||
else if (basicType === 'tb_il_swage_prcs_fclt') cqlFilters = swagePrcsFcltCqlFilters({
|
|
||||||
ctpvName, sggName,
|
|
||||||
yearFilter,
|
|
||||||
start1, end1,
|
|
||||||
todayYear, todayMonth, todayDate,
|
|
||||||
getDateString
|
|
||||||
}); // 하수처리시설
|
|
||||||
else if (basicType === 'tb_ms_swage_ppl') cqlFilters = swagePplCqlFilters({
|
|
||||||
var1, var2,
|
|
||||||
ctpvCd, sggCd,
|
|
||||||
yearFilter,
|
|
||||||
start1, start2, end1, end2,
|
|
||||||
todayYear, todayMonth, todayDate,
|
|
||||||
getDateString
|
|
||||||
}); // 하수관로
|
|
||||||
else if (basicType === 'tb_ms_swage_mhl') cqlFilters = swageMhlCqlFilters({
|
|
||||||
ctpvCd, sggCd,
|
|
||||||
yearFilter,
|
|
||||||
start1, end1,
|
|
||||||
var1,
|
|
||||||
todayYear, todayMonth, todayDate,
|
|
||||||
getDateString
|
|
||||||
}); // 하수맨홀
|
|
||||||
else if (basicType === 'tb_ms_swage_pmstn') cqlFilters = swagePmstnCqlFilters({
|
|
||||||
ctpvCd, sggCd,
|
|
||||||
yearFilter,
|
|
||||||
start1, start2, end1, end2,
|
|
||||||
todayYear, todayMonth, todayDate,
|
|
||||||
getDateString
|
|
||||||
}); // 하수펌프장
|
|
||||||
else if (basicType === 'tb_ms_stofcbr') cqlFilters = stofcbrCqlFilters({
|
|
||||||
ctpvCd, sggCd,
|
|
||||||
yearFilter,
|
|
||||||
todayYear, todayMonth, todayDate,
|
|
||||||
getDateString
|
|
||||||
}); // 우수토실
|
|
||||||
|
|
||||||
if (cqlFilters.length > 0) queryParams.append('cqlFiter', cqlFilters.join(' and '));
|
|
||||||
|
|
||||||
const res = await axios.get(`${API_URL}/v1/fclts?${queryParams.toString()}`);
|
|
||||||
|
|
||||||
// 🎯 각 아이템을 개별적으로 포맷팅하면서 일련번호 추가
|
|
||||||
const dataWithRowNumber = (res.data.data || []).map((item: any, index: number) => {
|
|
||||||
// 🎯 먼저 각 아이템을 포맷팅
|
|
||||||
const formattedItem = formatDisplayData(item);
|
|
||||||
|
|
||||||
let ctpvCd = item?.ctpvNm ?? formattedItem?.ctpvNm ?? '';
|
|
||||||
let sggCd = item?.sggNm ?? formattedItem?.sggNm ?? '';
|
|
||||||
|
|
||||||
if (!ctpvCd || !sggCd) {
|
|
||||||
const code = String(item?.pbadmsEmdCd ?? formattedItem?.pbadmsEmdCd ?? '')?.trim();
|
|
||||||
if (!ctpvCd && code) ctpvCd = code.slice(0, 2);
|
|
||||||
if (!sggCd && code) sggCd = code.slice(0, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
const matchedMhlCode = MS_SWAGE_MHL_CODES.find(code => code.val === item?.mqltCd?.trim());
|
|
||||||
const matchedMhlUsgCode = MS_SWAGE_MHL_USE_CODES.find(code => code.val === item?.usgCd);
|
|
||||||
const ctpvNm = ctpv.find(code => code.val.trim() === ctpvCd)?.text || item?.ctpvNm;
|
|
||||||
const sggNm = sgg.find(code => code.val.trim() === sggCd)?.text || item?.sggNm;
|
|
||||||
const usgCdObj = MS_SWAGE_PPL_USE_CODES.find(code => code.val === item?.usgCd?.trim());
|
|
||||||
|
|
||||||
// 추가 처리 및 일련번호 추가
|
|
||||||
return {
|
|
||||||
...formattedItem,
|
|
||||||
rowNumber: (curPage - 1) * 10 + index + 1, // 1부터 시작하는 일련번호 추가
|
|
||||||
scsYn: item.scsYn === null || item.scsYn === undefined ? 'N' : item?.scsYn, // scsYn이 null이면 'N'으로 변경
|
|
||||||
mqltCd: matchedMhlCode ? matchedMhlCode.text : item?.mqltCd,
|
|
||||||
usgCd: matchedMhlUsgCode ? matchedMhlUsgCode.text : (usgCdObj ? usgCdObj.text : item?.usgCd),
|
|
||||||
ctpvNm: ctpvNm ?? '-',
|
|
||||||
sggNm : sggNm ?? '-',
|
|
||||||
swtrmt_zone_nm: item.swtrmtZoneNm || item.swtrmt_zone_nm || '-',
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
setTableData(dataWithRowNumber);
|
|
||||||
setTableCount(res.data.count || []);
|
|
||||||
|
|
||||||
} else if (activeTab === 'operation') {
|
|
||||||
const RequestDTO: Record<string, string> = {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
setShowTable(true);
|
|
||||||
setIsResetSelection(false);
|
|
||||||
} catch (err) {
|
|
||||||
console.error('API ERROR:', err);
|
|
||||||
setTableData([]);
|
|
||||||
setIsResetSelection(false);
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false); // 로딩 종료
|
|
||||||
setIsResetSelection(false);
|
|
||||||
// setIsResetDetailSelection(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 조회 버튼 클릭 시 1페이지로 이동 및 데이터 초기화
|
|
||||||
const handleSearch = () => {
|
|
||||||
setCurPage(1); // 페이지를 1로 초기화
|
|
||||||
fetchFilteredData();
|
|
||||||
setIsResetPage(true); // 페이지를 초기화
|
|
||||||
setIsResetDetailPage(true); // 디테일 페이지를 초기화
|
|
||||||
setIsResetSelection(false); // 선택 초기화
|
|
||||||
setIsResetDetailSelection(false); // 선택 초기화
|
|
||||||
setShowTable(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 기본정보 테이블 cellClick 핸들러
|
|
||||||
const handleBasicCellClick = async (index?: number | undefined, headId?: String) => {
|
|
||||||
if (typeof index === "number") {
|
|
||||||
setIsLoading(true);
|
|
||||||
|
|
||||||
const row = tableData[index];
|
|
||||||
const layerNm = row.lyrTypeNm;
|
|
||||||
const fid = row.fid;
|
|
||||||
const core = GisApp.Module.layer as any;
|
|
||||||
await core.showSearchResultsFromGeoJSON(layerNm, fid);
|
|
||||||
setIsLoading(false);
|
|
||||||
onOpenChange(false); // SearchModal 닫기
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// 운영정보 테이블 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<string, string> = {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// 운영정보 디테일 테이블 페이지네이션 핸들러
|
|
||||||
const handleOperationPageNation = async (index?: number | undefined) => {
|
|
||||||
if (typeof index === "number") {
|
|
||||||
setIsDetailLoading(true);
|
|
||||||
try {
|
|
||||||
const RequestDTO: Record<string, string> = {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
onOpenChange(false); // SearchModal 닫기
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 기본정보 Excel 다운로드 핸들러
|
|
||||||
const basicExcelDownload = 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 queryParams = new URLSearchParams({
|
|
||||||
lyrTypeNm: basicType,
|
|
||||||
size: '10000',
|
|
||||||
});
|
|
||||||
|
|
||||||
let cqlFilters: string[] = [];
|
|
||||||
let headerMapping: { [key: string]: string } = {};
|
|
||||||
let headerRange: string = "A1:F1";
|
|
||||||
|
|
||||||
switch (basicType) {
|
|
||||||
case 'tb_ms_swage_ppl': {
|
|
||||||
// 하수관로
|
|
||||||
cqlFilters = swagePplCqlFilters({
|
|
||||||
var1, var2,
|
|
||||||
ctpvCd, sggCd,
|
|
||||||
yearFilter,
|
|
||||||
start1, start2, end1, end2,
|
|
||||||
todayYear, todayMonth, todayDate,
|
|
||||||
getDateString
|
|
||||||
})
|
|
||||||
headerMapping = MsSwagePplExcelCol;
|
|
||||||
headerRange = "A1:M1";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'tb_il_swage_prcs_fclt': {
|
|
||||||
// 하수처리시설
|
|
||||||
cqlFilters = swagePrcsFcltCqlFilters({
|
|
||||||
ctpvName, sggName,
|
|
||||||
yearFilter,
|
|
||||||
start1, end1,
|
|
||||||
todayYear, todayMonth, todayDate,
|
|
||||||
getDateString
|
|
||||||
});
|
|
||||||
headerMapping = SwtrmtFcltExcelCol;
|
|
||||||
headerRange = "A1:J1";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'tb_ms_swage_prcs_zone': {
|
|
||||||
// 하수처리구역
|
|
||||||
cqlFilters = swagePrcsZoneCqlFilters({
|
|
||||||
ctpvCd, sggCd,
|
|
||||||
var1, var2
|
|
||||||
});
|
|
||||||
headerMapping = SwtrmtPrcsZoneExcelCol;
|
|
||||||
headerRange = "A1:D1";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'tb_ms_swage_mhl': {
|
|
||||||
// 하수맨홀
|
|
||||||
cqlFilters = swageMhlCqlFilters({
|
|
||||||
ctpvCd, sggCd,
|
|
||||||
yearFilter,
|
|
||||||
start1, end1,
|
|
||||||
var1,
|
|
||||||
todayYear, todayMonth, todayDate,
|
|
||||||
getDateString
|
|
||||||
});
|
|
||||||
headerMapping = MsSwageMhlExcelCol;
|
|
||||||
headerRange = "A1:J1";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'tb_ms_swage_pmstn': {
|
|
||||||
// 하수펌프장
|
|
||||||
cqlFilters = swagePmstnCqlFilters({
|
|
||||||
ctpvCd, sggCd,
|
|
||||||
yearFilter,
|
|
||||||
start1, start2, end1, end2,
|
|
||||||
todayYear, todayMonth, todayDate,
|
|
||||||
getDateString
|
|
||||||
});
|
|
||||||
headerMapping = ExclnSewagePumpExcelCol;
|
|
||||||
headerRange = "A1:J1";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'tb_ms_stofcbr': {
|
|
||||||
// 우수토실
|
|
||||||
cqlFilters = stofcbrCqlFilters({
|
|
||||||
ctpvCd, sggCd,
|
|
||||||
yearFilter,
|
|
||||||
todayYear, todayMonth, todayDate,
|
|
||||||
getDateString
|
|
||||||
});
|
|
||||||
headerMapping = stofcbrExcelCol;
|
|
||||||
headerRange = "A1:H1";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cqlFilters.length > 0) queryParams.append('cqlFiter', cqlFilters.join(' and '));
|
|
||||||
|
|
||||||
const res = await axios.get(`${API_URL}/v1/fclts?${queryParams.toString()}`);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// const mhlCdMap = new Map(MS_SWAGE_MHL_CODES.map(code => [code.val?.trim(), code.text]));
|
|
||||||
const mhlUsgCdMap = new Map(MS_SWAGE_MHL_USE_CODES.map(code => [code.val?.trim(), code.text]));
|
|
||||||
const pplUsgCdMap = new Map(MS_SWAGE_PPL_USE_CODES.map(code => [code.val?.trim(), code.text]));
|
|
||||||
const ctpvMap = new Map(ctpv.map(code => [code.val?.trim(), code.text]));
|
|
||||||
const sggMap = new Map(sgg.map(code => [code.val?.trim(), code.text]));
|
|
||||||
|
|
||||||
const mappedContent = (res.data.data || []).map((item: any) => {
|
|
||||||
const formattedItem = formatDisplayData(item);
|
|
||||||
|
|
||||||
let ctpvCd = item?.ctpvCd ?? formattedItem?.ctpvCd ?? '';
|
|
||||||
let sggCd = item?.sggCd ?? formattedItem?.sggCd ?? '';
|
|
||||||
|
|
||||||
if (!ctpvCd || !sggCd) {
|
|
||||||
const code = String(item?.pbadmsEmdCd ?? formattedItem?.pbadmsEmdCd ?? '')?.trim();
|
|
||||||
if (!ctpvCd && code) ctpvCd = code.slice(0, 2);
|
|
||||||
if (!sggCd && code) sggCd = code.slice(0, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
// trim 한 번만 수행
|
|
||||||
const trimmedUsgCd = item?.usgCd?.trim();
|
|
||||||
// const trimmedMqltCd = item?.mqltCd?.trim();
|
|
||||||
|
|
||||||
switch (basicType) {
|
|
||||||
case 'tb_ms_swage_ppl': {
|
|
||||||
// 하수관로
|
|
||||||
return {
|
|
||||||
fcltMngNo: formattedItem.fcltMngNo ?? item.fcltMngNo ?? '-',
|
|
||||||
instMngNo: formattedItem.instMngNo ?? item.instMngNo ?? '-',
|
|
||||||
ctpvNm: ctpvMap.get(ctpvCd) ?? item.ctpvNm ?? '-',
|
|
||||||
sggNm: sggMap.get(sggCd) ?? item.sggNm ?? '-',
|
|
||||||
swtrmt_zone_nm: formattedItem.swtrmt_zone_nm ?? item.swtrmt_zone_nm ?? '-',
|
|
||||||
instlYmd: formattedItem.instlYmd ?? item.instlYmd ?? '-',
|
|
||||||
usgCd: pplUsgCdMap.get(trimmedUsgCd) || item.usgCd || formattedItem.usgCd || '-',
|
|
||||||
pdmtVl: formattedItem.pdmtVl ?? item.pdmtVl ?? '-',
|
|
||||||
prlgVl: formattedItem.prlgVl ?? item.prlgVl ?? '-',
|
|
||||||
tmptDpth: formattedItem.tmptDpth ?? item.tmptDpth ?? '-',
|
|
||||||
tmptMhlMngNo: formattedItem.tmptMhlMngNo ?? item.tmptMhlMngNo ?? '-',
|
|
||||||
scendDpth: formattedItem.scendDpth ?? item.scendDpth ?? '-',
|
|
||||||
scendMhlMngNo: formattedItem.scendMhlMngNo ?? item.scendMhlMngNo ?? '-',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
case 'tb_il_swage_prcs_fclt': {
|
|
||||||
// 하수처리시설
|
|
||||||
return {
|
|
||||||
swtrmtFcltNm: formattedItem.swtrmtFcltNm ?? item.swtrmtFcltNm ?? '-',
|
|
||||||
fcltCpct: formattedItem.fcltCpct ?? item.fcltCpct ?? '-',
|
|
||||||
rgnExpln: formattedItem.rgnExpln ?? item.rgnExpln ?? '-',
|
|
||||||
oprtngStrtYmd: formattedItem.oprtngStrtYmd ?? item.oprtngStrtYmd ?? '-',
|
|
||||||
laeNm: formattedItem.laeNm ?? item.laeNm ?? '-',
|
|
||||||
sareaNm: formattedItem.sareaNm ?? item.sareaNm ?? '-',
|
|
||||||
rvrNm: formattedItem.rvrNm ?? item.rvrNm ?? '-',
|
|
||||||
dschgWtstNm: formattedItem.dschgWtstNm ?? item.dschgWtstNm ?? '-',
|
|
||||||
swtrmtPpltnCnt: formattedItem.swtrmtPpltnCnt ?? item.swtrmtPpltnCnt ?? '-',
|
|
||||||
rprsMsrcCn: formattedItem.rprsMsrcCn ?? item.rprsMsrcCn ?? '-'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
case 'tb_ms_swage_prcs_zone': {
|
|
||||||
// 하수처리구역
|
|
||||||
return {
|
|
||||||
swtrmtZoneNm: formattedItem.swtrmtZoneNm ?? item.swtrmtZoneNm ?? '-',
|
|
||||||
ctpvNm: ctpvMap.get(ctpvCd) ?? formattedItem.ctpvNm ?? '-',
|
|
||||||
sggNm: sggMap.get(sggCd) ?? formattedItem.sggNm ?? '-',
|
|
||||||
swtrmtFcltNm: formattedItem.swtrmtFcltNm ?? item.swtrmtFcltNm ?? '-'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
case 'tb_ms_swage_mhl': {
|
|
||||||
// 하수맨홀
|
|
||||||
return {
|
|
||||||
fcltMngNo: formattedItem.fcltMngNo ?? item.fcltMngNo ?? '-',
|
|
||||||
ctpvNm: ctpvMap.get(ctpvCd) ?? formattedItem.ctpvNm ?? '-',
|
|
||||||
sggNm: sggMap.get(sggCd) ?? formattedItem.sggNm ?? '-',
|
|
||||||
instlYmd: formattedItem.instlYmd ?? item.instlYmd ?? '-',
|
|
||||||
usgCd: mhlUsgCdMap.get(trimmedUsgCd) || item.usgCd || formattedItem.usgCd || '-',
|
|
||||||
swageMhlDiamVl: formattedItem.swageMhlDiamVl ?? item.swageMhlDiamVl ?? '-',
|
|
||||||
wdthLen: formattedItem.wdthLen ?? item.wdthLen ?? '-',
|
|
||||||
vrtcLen: formattedItem.vrtcLen ?? item.vrtcLen ?? '-',
|
|
||||||
altdVl: formattedItem.altdVl ?? item.altdVl ?? '-',
|
|
||||||
dpthlVl: formattedItem.dpthlVl ?? item.dpthlVl ?? '-'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
case 'tb_ms_swage_pmstn': {
|
|
||||||
// 하수펌프장
|
|
||||||
return {
|
|
||||||
fcltMngNo: formattedItem.fcltMngNo ?? item.fcltMngNo ?? '-',
|
|
||||||
ctpvNm: ctpvMap.get(ctpvCd) ?? formattedItem.ctpvNm ?? '-',
|
|
||||||
sggNm: sggMap.get(sggCd) ?? formattedItem.sggNm ?? '-',
|
|
||||||
swagePmstnNm: formattedItem.swagePmstnNm ?? item.swagePmstnNm ?? '-',
|
|
||||||
instlYmd: formattedItem.instlYmd ?? item.instlYmd ?? '-',
|
|
||||||
dailyPrcsCpct: formattedItem.dailyPrcsCpct ?? item.dailyPrcsCpct ?? '-',
|
|
||||||
maxImpndCpct: formattedItem.maxImpndCpct ?? item.maxImpndCpct ?? '-',
|
|
||||||
altdVl: formattedItem.altdVl ?? item.altdVl ?? '-',
|
|
||||||
wtlvVl: formattedItem.wtlvVl ?? item.wtlvVl ?? '-',
|
|
||||||
exclnWpmpAbltVl: formattedItem.exclnWpmpAbltVl ?? item.exclnWpmpAbltVl ?? '-'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
case 'tb_ms_stofcbr': {
|
|
||||||
// 우수토실
|
|
||||||
return {
|
|
||||||
fcltMngNo: formattedItem.fcltMngNo ?? item.fcltMngNo ?? '-',
|
|
||||||
mapshtNo: formattedItem.mapshtNo ?? item.mapshtNo ?? '-',
|
|
||||||
ctpvNm: ctpvMap.get(ctpvCd) ?? formattedItem.ctpvNm ?? '-',
|
|
||||||
sggNm: sggMap.get(sggCd) ?? formattedItem.sggNm ?? '-',
|
|
||||||
instlYmd: formattedItem.instlYmd ?? item.instlYmd ?? '-',
|
|
||||||
worflwWallHgt: formattedItem.worflwWallHgt ?? item.worflwWallHgt ?? '-',
|
|
||||||
swageMhlMngNo: formattedItem.swageMhlMngNo ?? item.swageMhlMngNo ?? '-',
|
|
||||||
drtnAngl: formattedItem.drtnAngl ?? item.drtnAngl ?? '-'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 선택된 행 데이터를 Excel 다운로드 형식으로 변환
|
|
||||||
const excelData = mappedContent; // 배열로 감싸서 전달
|
|
||||||
|
|
||||||
// 파일명 생성 (분석번호 기반)
|
|
||||||
const label = BASIC_TYPES.find((type) => type.val === basicType)?.text
|
|
||||||
const fileName = `${label} 조회 결과_${todayYear}${todayMonth}${todayDate}`;
|
|
||||||
|
|
||||||
await downloadExcelWithKoreanHeaders({
|
|
||||||
data: excelData as JSON[],
|
|
||||||
fileName: fileName,
|
|
||||||
sheetNameArray: [fileName],
|
|
||||||
headerRange: headerRange,
|
|
||||||
headerMapping: headerMapping
|
|
||||||
});
|
|
||||||
setIsLoading(false);
|
|
||||||
} catch (error) {
|
|
||||||
setIsLoading(false);
|
|
||||||
console.error("Excel 다운로드 중 오류 발생:", error);
|
|
||||||
alert("Excel 다운로드 중 오류가 발생했습니다. 다시 시도해주세요.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 운영정보 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<string, string> = {
|
|
||||||
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<string, string> = {
|
|
||||||
size: '10000',
|
|
||||||
bizId: String(detailBizId),
|
|
||||||
};
|
|
||||||
|
|
||||||
const apiStartTime = performance.now();
|
|
||||||
const res = await getData(`v1/bizInfo/fclts?${new URLSearchParams(RequestDTO).toString()}`);
|
|
||||||
const apiEndTime = performance.now();
|
|
||||||
|
|
||||||
const mappingStartTime = performance.now();
|
|
||||||
// 헤더 매핑 정의
|
|
||||||
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 다운로드 중 오류가 발생했습니다. 다시 시도해주세요.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 여러 시설 보기
|
|
||||||
const viewMultipleFeature = async () => {
|
|
||||||
if (activeTab === 'basic') {
|
|
||||||
if (!(tableData.length === 0)) {
|
|
||||||
setIsLoading(true);
|
|
||||||
|
|
||||||
const row = tableData[0];
|
|
||||||
const layerNm = row.lyrTypeNm;
|
|
||||||
const fids = tableData.map((item) => item.fid);
|
|
||||||
const core = GisApp.Module.layer as any;
|
|
||||||
await core.showMultipleSearchResultsFromGeoJSON(layerNm, fids);
|
|
||||||
setIsLoading(false);
|
|
||||||
onOpenChange(false);
|
|
||||||
}
|
|
||||||
} else if (activeTab === 'operation') {
|
|
||||||
if (!(detailTableData.length === 0)) {
|
|
||||||
setIsLoading(true);
|
|
||||||
|
|
||||||
const row = detailTableData[0];
|
|
||||||
const layerNm = row.lyrTypeNm;
|
|
||||||
const fids = detailTableData.map((item) => item.fid);
|
|
||||||
const core = GisApp.Module.layer as any;
|
|
||||||
await core.showMultipleSearchResultsFromGeoJSON(layerNm, fids);
|
|
||||||
setIsLoading(false);
|
|
||||||
onOpenChange(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
open, onOpenChange, onFeatureSelect,
|
|
||||||
TABS,
|
|
||||||
getDateString,
|
|
||||||
handleSearch,
|
|
||||||
handleBasicCellClick,
|
|
||||||
handleOperationCellClick,
|
|
||||||
handleOperationPageNation,
|
|
||||||
handleOperationResultCellClick,
|
|
||||||
basicExcelDownload,
|
|
||||||
operationExcelDownload,
|
|
||||||
operationResultExcelDownload,
|
|
||||||
viewMultipleFeature,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useRef, useEffect, useState } from "react";
|
|
||||||
import { Label } from "@common/components/ui/label";
|
import { Label } from "@common/components/ui/label";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
export const WATER_DEPTH_LAYER_TYPES: string[] = [
|
export const WATER_DEPTH_LAYER_TYPES: string[] = [
|
||||||
'tb_ms_flood_dngr_map',
|
'tb_ms_flood_dngr_map',
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ function FileUpload() {
|
|||||||
const [file, setFile] = useState(null);
|
const [file, setFile] = useState(null);
|
||||||
const [text, setText] = useState('');
|
const [text, setText] = useState('');
|
||||||
|
|
||||||
const handleFileChange = (e) => {
|
const handleFileChange = (e: any) => {
|
||||||
setFile(e.target.files[0]);
|
setFile(e.target.files[0]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleTextChange = (e) => {
|
const handleTextChange = (e: any) => {
|
||||||
setText(e.target.value);
|
setText(e.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ function FileUpload() {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const handleFindUser = (e) => {
|
const handleFindUser = () => {
|
||||||
const auth = getCookie("Authorization");
|
const auth = getCookie("Authorization");
|
||||||
if (auth) console.log("쿠키 auth : " + auth);
|
if (auth) console.log("쿠키 auth : " + auth);
|
||||||
fetch(SEWERAGE_URL+"/v1/inftwtAnls/users/65a00f65-8460-49af-98ec-042977e56f4b", {
|
fetch(SEWERAGE_URL+"/v1/inftwtAnls/users/65a00f65-8460-49af-98ec-042977e56f4b", {
|
||||||
@@ -37,7 +37,7 @@ function FileUpload() {
|
|||||||
console.log(data);
|
console.log(data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const handleFindUserOna = (e) => {
|
const handleFindUserOna = () => {
|
||||||
const auth = getCookie("Authorization");
|
const auth = getCookie("Authorization");
|
||||||
if (auth) console.log("쿠키 auth : " + auth);
|
if (auth) console.log("쿠키 auth : " + auth);
|
||||||
fetch("/server/user-service/api/v1/users/65a00f65-8460-49af-98ec-042977e56f4b").then((data) => {
|
fetch("/server/user-service/api/v1/users/65a00f65-8460-49af-98ec-042977e56f4b").then((data) => {
|
||||||
@@ -45,7 +45,7 @@ function FileUpload() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e: any) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if (!file) {
|
if (!file) {
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ const Page = () => {
|
|||||||
alert('파일을 선택해주세요')
|
alert('파일을 선택해주세요')
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
handleDownload(`/attach-service/api/v1/download/${atflId}`, fileNm)
|
handleDownload(`/attach-service/api/v1/download/${atflId}`, fileNm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 선택 파일 삭제
|
// 선택 파일 삭제
|
||||||
|
|||||||
@@ -80,12 +80,15 @@ export const deleteData = async (url: string, data?: object): Promise<any> => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// DC API 호출
|
// DC API 호출
|
||||||
export const getDcData = async (url: string, data?: object): Promise<any> => {
|
export const getDcData = async (url: string, resType: string = "json"): Promise<any> => {
|
||||||
const res = await fetch('/dc-service' + url, {
|
const res = await fetch('/dc-service' + url, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
});
|
});
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const data = await res.json();
|
let data;
|
||||||
|
if (resType === "json") data = await res.json();
|
||||||
|
else if (resType === "blob") data = await res.blob();
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
throw new Error('Failed to fetch data');
|
throw new Error('Failed to fetch data');
|
||||||
|
|||||||
@@ -1,28 +1,27 @@
|
|||||||
const BASE_URL = process.env.NEXT_PUBLIC_SERVER_API_URL || '';
|
const BASE_URL = process.env.NEXT_PUBLIC_SERVER_API_URL || '';
|
||||||
|
|
||||||
export const handleDownload = async (api:string, fileNm:string) => {
|
export const handleDownload = async (api: string, fileNm: string) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(api, {
|
const response = await fetch(api, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
});
|
});
|
||||||
if (!response.ok) {
|
if (!response.ok) throw new Error('파일 다운로드 실패');
|
||||||
throw new Error('파일 다운로드 실패');
|
|
||||||
}
|
|
||||||
|
|
||||||
const blob = await response.blob();
|
const blob = await response.blob();
|
||||||
const url = window.URL.createObjectURL(blob);
|
fileDownload(blob, fileNm);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('다운로드 중 오류 발생:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 다운로드를 트리거할 가짜 <a> 태그 생성
|
export const fileDownload = (data: Blob, fileName: string) => { // Blob데이터 임시link로 연결
|
||||||
const link = document.createElement('a');
|
const url = window.URL.createObjectURL(data);
|
||||||
link.href = url;
|
const link = document.createElement('a');
|
||||||
link.download = fileNm.normalize('NFC'); // 원하는 파일명 지정
|
link.href = url;
|
||||||
document.body.appendChild(link);
|
link.download = fileName; // 원하는 파일명 지정
|
||||||
link.click();
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
// 메모리 해제
|
// 메모리 해제
|
||||||
link.remove();
|
link.remove();
|
||||||
window.URL.revokeObjectURL(url);
|
window.URL.revokeObjectURL(url);
|
||||||
} catch (error) {
|
}
|
||||||
console.error('다운로드 중 오류 발생:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import useReportTab, { type Folder, type ReportDataFile } from '../(map-layout)/map/searchModal/useReportTab';
|
||||||
|
import { create } from 'zustand';
|
||||||
|
import { getDcData } from '@/components/lib/api';
|
||||||
|
|
||||||
|
interface useReportTabStoreType {
|
||||||
|
isOpen: boolean;
|
||||||
|
files: ReportDataFile[];
|
||||||
|
dcTree: Folder[];
|
||||||
|
dcFiles: ReportDataFile[];
|
||||||
|
setIsOpen: (open: boolean) => void;
|
||||||
|
setFiles: (files: ReportDataFile[]) => void;
|
||||||
|
fetchDcTree: (clsfSystmNm: string) => void;
|
||||||
|
fetchDcFiles: (clsfSystmNm: string) => void;
|
||||||
|
}
|
||||||
|
export const useReportTabStore = create<useReportTabStoreType>((set, get) => ({
|
||||||
|
isOpen: false,
|
||||||
|
files: [],
|
||||||
|
dcTree: [],
|
||||||
|
dcFiles: [],
|
||||||
|
setIsOpen: (open: boolean) => set({ isOpen: open }),
|
||||||
|
setFiles: (files: ReportDataFile[]) => set({ files }),
|
||||||
|
fetchDcTree: async (clsfSystmNm: string) => {
|
||||||
|
const { dcTree } = get();
|
||||||
|
try {
|
||||||
|
const result = await getDcData("/api/v1/dc/clsf?clsfSystmNm=" + clsfSystmNm);
|
||||||
|
if (result && JSON.stringify(result) !== JSON.stringify(dcTree))
|
||||||
|
set({ dcTree: result });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch DC tree:', error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fetchDcFiles: async (clsfSystmNm: string) => {
|
||||||
|
const { getDcFiles } = useReportTab();
|
||||||
|
const { dcFiles } = get();
|
||||||
|
try {
|
||||||
|
const result = await getDcFiles(clsfSystmNm);
|
||||||
|
if (result && JSON.stringify(result) !== JSON.stringify(dcFiles))
|
||||||
|
set({ dcFiles: result });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch DC files:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
@@ -23,6 +23,8 @@ const todayMonth = (today.getMonth() + 1).toString().padStart(2, "0");
|
|||||||
const todayDate = today.getDate().toString().padStart(2, "0");
|
const todayDate = today.getDate().toString().padStart(2, "0");
|
||||||
|
|
||||||
export interface SearchModalState {
|
export interface SearchModalState {
|
||||||
|
// 모달 열림 상태
|
||||||
|
isSearchModalOpen: boolean;
|
||||||
// 탭 관련
|
// 탭 관련
|
||||||
activeTab: string;
|
activeTab: string;
|
||||||
basicType: string;
|
basicType: string;
|
||||||
@@ -67,9 +69,9 @@ export interface SearchModalState {
|
|||||||
todayYear: string;
|
todayYear: string;
|
||||||
todayMonth: string;
|
todayMonth: string;
|
||||||
todayDate: string;
|
todayDate: string;
|
||||||
getDateString: (year: string, month: string, day: string, defaultDate: string) => string;
|
|
||||||
|
|
||||||
// setters
|
// setters
|
||||||
|
setIsSearchModalOpen: (open: boolean) => void;
|
||||||
setActiveTab: (tab: string) => void;
|
setActiveTab: (tab: string) => void;
|
||||||
setBasicType: (type: string) => void;
|
setBasicType: (type: string) => void;
|
||||||
setWorkType: (type: string) => void;
|
setWorkType: (type: string) => void;
|
||||||
@@ -98,11 +100,13 @@ export interface SearchModalState {
|
|||||||
setVar1: (val: string) => void;
|
setVar1: (val: string) => void;
|
||||||
setVar2: (val: string) => void;
|
setVar2: (val: string) => void;
|
||||||
setYearFilter: (filter: { start: string; end: string }) => void;
|
setYearFilter: (filter: { start: string; end: string }) => void;
|
||||||
// 초기화 액션
|
|
||||||
resetFilters: () => void;
|
getDateString: (year: string, month: string, day: string, defaultDate: string) => string;
|
||||||
|
resetFilters: () => void; // 초기화 액션
|
||||||
}
|
}
|
||||||
|
|
||||||
const useSearchModalStore = create<SearchModalState>((set) => ({
|
const useSearchModalStore = create<SearchModalState>((set) => ({
|
||||||
|
isSearchModalOpen: false,
|
||||||
activeTab: "basic",
|
activeTab: "basic",
|
||||||
basicType: "tb_ms_swage_ppl",
|
basicType: "tb_ms_swage_ppl",
|
||||||
workType: "['200', '201', '204']",
|
workType: "['200', '201', '204']",
|
||||||
@@ -135,7 +139,7 @@ const useSearchModalStore = create<SearchModalState>((set) => ({
|
|||||||
todayYear,
|
todayYear,
|
||||||
todayMonth,
|
todayMonth,
|
||||||
todayDate,
|
todayDate,
|
||||||
getDateString,
|
setIsSearchModalOpen: (isSearchModalOpen) => set({ isSearchModalOpen }),
|
||||||
setActiveTab: (tab) => set({ activeTab: tab }),
|
setActiveTab: (tab) => set({ activeTab: tab }),
|
||||||
setBasicType: (type) => set({ basicType: type }),
|
setBasicType: (type) => set({ basicType: type }),
|
||||||
setWorkType: (type) => set({ workType: type }),
|
setWorkType: (type) => set({ workType: type }),
|
||||||
@@ -164,7 +168,8 @@ const useSearchModalStore = create<SearchModalState>((set) => ({
|
|||||||
setVar1: (val) => set({ var1: val }),
|
setVar1: (val) => set({ var1: val }),
|
||||||
setVar2: (val) => set({ var2: val }),
|
setVar2: (val) => set({ var2: val }),
|
||||||
setYearFilter: (filter) => set({ yearFilter: filter }),
|
setYearFilter: (filter) => set({ yearFilter: filter }),
|
||||||
|
|
||||||
|
getDateString: getDateString,
|
||||||
// 초기화 액션
|
// 초기화 액션
|
||||||
resetFilters: () =>
|
resetFilters: () =>
|
||||||
set({
|
set({
|
||||||
|
|||||||
@@ -31,8 +31,10 @@
|
|||||||
"@common/business_components/*": ["../../../packages/common/business_components/src/*"],
|
"@common/business_components/*": ["../../../packages/common/business_components/src/*"],
|
||||||
"@common/network": ["../../../packages/common/network/"],
|
"@common/network": ["../../../packages/common/network/"],
|
||||||
"@common/config": ["../../../packages/common/config/dist/"],
|
"@common/config": ["../../../packages/common/config/dist/"],
|
||||||
"@utils": ["../app/components/lib/utils"],
|
"@/app/*": ["../app/*"],
|
||||||
"@/components/*": ["../app/components/*"]
|
"@/components/*": ["../app/components/*"],
|
||||||
|
"@/utils": ["../app/components/lib/utils"],
|
||||||
|
"@/store/*": ["../app/store/*"],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
|
|||||||
@@ -118,15 +118,21 @@ export default function LineBarchart({
|
|||||||
if (!isFinite(maxValue) || maxValue <= 0) {
|
if (!isFinite(maxValue) || maxValue <= 0) {
|
||||||
return { max: 0, ticks: [0] };
|
return { max: 0, ticks: [0] };
|
||||||
}
|
}
|
||||||
|
|
||||||
const exponent = Math.floor(Math.log10(maxValue));
|
const exponent = Math.floor(Math.log10(maxValue));
|
||||||
const base = Math.pow(10, exponent);
|
const base = Math.pow(10, exponent);
|
||||||
const fraction = maxValue / base;
|
const fraction = maxValue / base;
|
||||||
|
|
||||||
let niceFraction: number;
|
let niceFraction: number;
|
||||||
if (fraction <= 1) niceFraction = 1;
|
if (fraction <= 1) niceFraction = 1;
|
||||||
else if (fraction <= 2) niceFraction = 3;
|
else if (fraction <= 2) niceFraction = 2;
|
||||||
|
else if (fraction <= 3) niceFraction = 3;
|
||||||
|
else if (fraction <= 4) niceFraction = 4;
|
||||||
else if (fraction <= 5) niceFraction = 5;
|
else if (fraction <= 5) niceFraction = 5;
|
||||||
|
else if (fraction <= 6) niceFraction = 6;
|
||||||
|
else if (fraction <= 7) niceFraction = 7;
|
||||||
|
else if (fraction <= 8) niceFraction = 8;
|
||||||
|
else if (fraction <= 9) niceFraction = 9;
|
||||||
else niceFraction = 10;
|
else niceFraction = 10;
|
||||||
|
|
||||||
const niceMax = niceFraction * base; // round up to 1/2/5 * 10^k
|
const niceMax = niceFraction * base; // round up to 1/2/5 * 10^k
|
||||||
@@ -164,7 +170,7 @@ export default function LineBarchart({
|
|||||||
return (
|
return (
|
||||||
<text
|
<text
|
||||||
x={x - padding} // 맨 좌측 바깥
|
x={x - padding} // 맨 좌측 바깥
|
||||||
y={y + height / 2} // 수직 중앙
|
y={y + height / 2 - 12} // 수직 중앙
|
||||||
textAnchor="middle"
|
textAnchor="middle"
|
||||||
transform={`rotate(-90, ${x - padding}, ${y + height / 2})`}
|
transform={`rotate(-90, ${x - padding}, ${y + height / 2})`}
|
||||||
className="text-[12px] font-bold"
|
className="text-[12px] font-bold"
|
||||||
@@ -195,12 +201,12 @@ export default function LineBarchart({
|
|||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="h-[calc(100%-42px)] w-[calc(100%-40px)] ">
|
<div className="h-[calc(100%-42px)] w-[calc(100%-40px)] ">
|
||||||
<ChartContainer config={chartConfig ?? {}} className="h-full w-full">
|
<ChartContainer config={chartConfig ?? {}} className="h-full w-[100%] ml-5">
|
||||||
<ComposedChart
|
<ComposedChart
|
||||||
data={chartData}
|
data={chartData}
|
||||||
height={graphSize * 7.5}
|
height={graphSize * 7.5}
|
||||||
width={graphSize * 12.5}
|
width={graphSize * 12.5}
|
||||||
margin={{ top: 5, right: 30, left: 20, bottom: 5 }}
|
margin={{ top: 5, right: 20, left: 30, bottom: 5 }}
|
||||||
>
|
>
|
||||||
<CartesianGrid strokeDasharray="3 3" />
|
<CartesianGrid strokeDasharray="3 3" />
|
||||||
{setXAxisYearTick?
|
{setXAxisYearTick?
|
||||||
@@ -210,7 +216,7 @@ export default function LineBarchart({
|
|||||||
{/* 왼쪽 Y축: lineVal */}
|
{/* 왼쪽 Y축: lineVal */}
|
||||||
{yFieldText && <YAxis
|
{yFieldText && <YAxis
|
||||||
yAxisId="left"
|
yAxisId="left"
|
||||||
className="text-[12px] font-bold"
|
className="text-[12px] font-bold"
|
||||||
tickFormatter={(value) =>
|
tickFormatter={(value) =>
|
||||||
typeof value === "number" ? value.toLocaleString() : value
|
typeof value === "number" ? value.toLocaleString() : value
|
||||||
}
|
}
|
||||||
@@ -218,7 +224,6 @@ export default function LineBarchart({
|
|||||||
ticks={leftScale.ticks}
|
ticks={leftScale.ticks}
|
||||||
orientation="left"
|
orientation="left"
|
||||||
label={(props) => <CustomAxisText {...props} fieldText={yFieldText} position="left" />}
|
label={(props) => <CustomAxisText {...props} fieldText={yFieldText} position="left" />}
|
||||||
|
|
||||||
/>}
|
/>}
|
||||||
{/* 오른쪽 Y축: barVal */}
|
{/* 오른쪽 Y축: barVal */}
|
||||||
{yFieldText2 && <YAxis
|
{yFieldText2 && <YAxis
|
||||||
|
|||||||
@@ -316,11 +316,7 @@ function Gis({
|
|||||||
)}
|
)}
|
||||||
{/* SearchView가 존재할 때만 렌더링 */}
|
{/* SearchView가 존재할 때만 렌더링 */}
|
||||||
{SearchView && (
|
{SearchView && (
|
||||||
<SearchView
|
<SearchView />
|
||||||
open={isSearchModalOpen}
|
|
||||||
onOpenChange={setIsSearchModalOpen}
|
|
||||||
onFeatureSelect={handleFeatureSelect}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
{/* 시도/시군구 조회 영역 */}
|
{/* 시도/시군구 조회 영역 */}
|
||||||
{SearchBar && (
|
{SearchBar && (
|
||||||
|
|||||||
Reference in New Issue
Block a user