242 lines
9.4 KiB
TypeScript
242 lines
9.4 KiB
TypeScript
import { mapSearchNavigationOptions } from "@/features/map-search/lib/map-navigation";
|
|
/**
|
|
* 📄 useBasicTab Hook
|
|
* 검색 모달 기본정보 탭 훅
|
|
*
|
|
* - 필터링된 시설물 데이터 조회 및 포맷팅
|
|
* - 테이블 셀 클릭 시 지도 피처 선택 및 줌 기능
|
|
* - 엑셀 다운로드 기능 (한글 헤더 지원)
|
|
* - CQL 필터 생성을 통한 쿼리 조건 설정
|
|
* - Zustand를 통한 상태 관리 및 로딩 처리
|
|
* - 데이터 매핑 및 코드 변환 (시도/시군구, 용도 등)
|
|
*
|
|
* 🔗 사용 API
|
|
* - 관망도 시설물 목록 조회: GET /api/v1/fclts (sewerage-service)
|
|
*/
|
|
import { requestGridExcel } from "@/shared/api/grid-export";
|
|
import { useFacilityCodeCatalog } from "@/entities/facility/lib/use-facility-code-catalog";
|
|
import { getData } from "@/shared/api/sewerage-api";
|
|
import { BASIC_TYPES } from "./basic-tab";
|
|
import { formatDisplayData } from "@/components/lib/utils/format-display-value";
|
|
import useStore from "@/entities/reference-data/model/reference-data-store";
|
|
import GisApp from "@common/business_components/ui/map/lib/gis.core";
|
|
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
|
import { useAlertStore } from "@/shared/lib";
|
|
import useSearchModalStore from "@/features/map-search/model/search-store";
|
|
import { swagePplCqlFilters } from "./swage-ppl";
|
|
import { swagePrcsFcltCqlFilters } from "./swage-prcs-fclt";
|
|
import { swagePrcsZoneCqlFilters } from "./swage-prcs-zone";
|
|
import { fldngWtlvMapCqlFilters } from "./fldng-wtlv-map";
|
|
import { swageMhlCqlFilters } from "./swage-mhl";
|
|
import { swagePmstnCqlFilters } from "./swage-pmstn";
|
|
import { stofcbrCqlFilters } from "./stofcbr";
|
|
import { postPopupMessageAndClose } from "@/features/window-popup/lib/popup-message";
|
|
import { WINDOW_POPUP_MESSAGE_TYPE } from "@/features/window-popup/model/types";
|
|
|
|
const isPopupWindow = () =>
|
|
typeof window !== "undefined" &&
|
|
!!window.opener &&
|
|
window.location.pathname.startsWith("/popup/");
|
|
|
|
export default function useBasicTab() {
|
|
const { MS_SWAGE_PPL_USE_CODES, MS_SWAGE_PPL_CODES, MS_SWAGE_PPL_SHAPE, MS_SWAGE_MHL_CODES, MS_SWAGE_MHL_USE_CODES } = useFacilityCodeCatalog();
|
|
const alert = useAlertStore((state) => state.setMessage);
|
|
const { confirm } = useConfirm();
|
|
const {
|
|
basicType,
|
|
tableData,
|
|
curPage,
|
|
todayYear,
|
|
todayMonth,
|
|
todayDate,
|
|
setIsSearchModalOpen,
|
|
setTableData,
|
|
setTableCount,
|
|
setIsLoading,
|
|
setAppliedBasicQuery,
|
|
} = useSearchModalStore();
|
|
const { ctpv, sgg } = useStore();
|
|
|
|
const fetchBasicFilteredData = async () => {
|
|
// 초기화 직후에도 이전 렌더의 조건을 사용하지 않도록 최신 스토어 값을 읽는다.
|
|
const { basicType, curPage } = useSearchModalStore.getState();
|
|
let cqlFilters: string[] = [];
|
|
const queryParams = new URLSearchParams({
|
|
lyrTypeNm: basicType,
|
|
page: `${curPage - 1}`,
|
|
size: "10",
|
|
});
|
|
// 현재 서버의 유하방향 배치 보강 옵션은 실패 시 목록 전체를 500으로 중단한다.
|
|
// 상세 유하방향 조회와 분리해 기본 정보검색 목록을 우선 정상 제공한다.
|
|
|
|
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_fldng_wtlv_map")
|
|
cqlFilters = fldngWtlvMapCqlFilters(); // 침수흔적도
|
|
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 totalCount = Number(res.count ?? 0);
|
|
|
|
// 🎯 각 아이템을 개별적으로 포맷팅하면서 일련번호 추가
|
|
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 ??
|
|
item?.stdgCd ??
|
|
formattedItem?.stdgCd ??
|
|
"",
|
|
)?.trim();
|
|
if (!ctpvCd && code) ctpvCd = code.slice(0, 2);
|
|
if (!sggCd && code) sggCd = code.slice(0, 5);
|
|
}
|
|
|
|
const matchedMqltCode =
|
|
basicType === "tb_ms_swage_ppl"
|
|
? MS_SWAGE_PPL_CODES.find(
|
|
(code) => code.val === item?.mqltCd?.trim(),
|
|
) // 하수관로 재질
|
|
: basicType === "tb_ms_swage_mhl"
|
|
? MS_SWAGE_MHL_CODES.find(
|
|
(code) => code.val === item?.mqltCd?.trim(),
|
|
) // 맨홀 재질
|
|
: undefined;
|
|
const matchedMhlUsgCode = MS_SWAGE_MHL_USE_CODES.find(
|
|
(code) => code.val === item?.usgCd,
|
|
); // 맨홀 용도
|
|
const matchedPplShpCode = MS_SWAGE_PPL_SHAPE.find(
|
|
(code) => code.val === item?.fcltyShpCd,
|
|
); // 하수관로 시설물형태코드
|
|
|
|
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,
|
|
scsYn:
|
|
item.scsYn === null || item.scsYn === undefined ? "N" : item?.scsYn, // scsYn이 null이면 'N'으로 변경
|
|
mqltCd: matchedMqltCode ? matchedMqltCode.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 || "-",
|
|
fcltyShpCd: matchedPplShpCode
|
|
? matchedPplShpCode.text
|
|
: item?.fcltyShpCd,
|
|
};
|
|
},
|
|
);
|
|
|
|
setTableData(dataWithRowNumber);
|
|
setTableCount(totalCount);
|
|
queryParams.delete("page");
|
|
queryParams.delete("size");
|
|
setAppliedBasicQuery({
|
|
basicType,
|
|
query: queryParams.toString(),
|
|
});
|
|
};
|
|
|
|
// 기본정보 테이블 cellClick 핸들러
|
|
const handleBasicCellClick = async (
|
|
index?: number | undefined,
|
|
headId?: String,
|
|
) => {
|
|
if (typeof index === "number") {
|
|
const row = tableData[index];
|
|
|
|
if (isPopupWindow()) {
|
|
postPopupMessageAndClose(
|
|
WINDOW_POPUP_MESSAGE_TYPE.MAP_SEARCH_SELECT_FEATURE,
|
|
{
|
|
layerNm: row.lyrTypeNm,
|
|
fid: String(row.fid),
|
|
},
|
|
);
|
|
return;
|
|
}
|
|
|
|
setIsLoading(true);
|
|
|
|
const layerNm = row.lyrTypeNm;
|
|
const fid = row.fid;
|
|
const core = GisApp.Module.layer as any;
|
|
await core.showSearchResultsFromGeoJSON(layerNm, fid, mapSearchNavigationOptions((GisApp.Module.core as any).map));
|
|
setIsLoading(false);
|
|
setIsSearchModalOpen(false); // SearchModal 닫기
|
|
}
|
|
};
|
|
|
|
// 기본정보 Excel 다운로드 핸들러
|
|
const basicExcelDownload = async () => {
|
|
if (tableData.length === 0) {
|
|
alert("다운로드 할 Excel 파일이 없습니다.\n조회 후 다시 시도해주세요.");
|
|
return;
|
|
}
|
|
|
|
if (
|
|
!(await confirm(
|
|
"파일 다운로드에는 2분 내외의 시간이 소요될 수 있습니다.\n파일 다운로드를 진행하시겠습니까?",
|
|
))
|
|
)
|
|
return;
|
|
|
|
await onDownload();
|
|
|
|
async function onDownload() {
|
|
setIsLoading(true);
|
|
|
|
try {
|
|
const appliedQuery = useSearchModalStore.getState().appliedBasicQuery;
|
|
if (!appliedQuery) throw new Error("화면 조회조건을 확인할 수 없습니다. 다시 조회해주세요.");
|
|
const params = new URLSearchParams(appliedQuery.query);
|
|
// 현재 페이지나 목록 배열을 보내지 않고 전체 조건과 표시명만 서버 작업으로 전달한다.
|
|
const label = BASIC_TYPES.find((type) => type.val === appliedQuery.basicType)?.text ?? "시설";
|
|
await requestGridExcel("v1/facilityExports", {
|
|
lyrTypeNm: appliedQuery.basicType,
|
|
cqlFilter: params.get("cqlFiter") ?? "",
|
|
sort: params.get("sort"),
|
|
ctpvNames: Object.fromEntries(ctpv.map((item) => [String(item.val).trim(), item.text])),
|
|
sggNames: Object.fromEntries(sgg.map((item) => [String(item.val).trim(), item.text])),
|
|
}, `${label} 조회 결과_${todayYear}${todayMonth}${todayDate}.xlsx`);
|
|
setIsLoading(false);
|
|
} catch (error) {
|
|
setIsLoading(false);
|
|
console.error("Excel 다운로드 중 오류 발생:", error);
|
|
alert("Excel 다운로드 중 오류가 발생했습니다. 다시 시도해주세요.");
|
|
}
|
|
}
|
|
};
|
|
|
|
return { fetchBasicFilteredData, handleBasicCellClick, basicExcelDownload };
|
|
}
|