375 lines
12 KiB
TypeScript
375 lines
12 KiB
TypeScript
/**
|
|
* 온배수시설 현황
|
|
*/
|
|
"use client";
|
|
import { useWrStore } from "@/app/store";
|
|
import { btnClass } from "@/app/store/common/code";
|
|
import type {
|
|
customRainBdst
|
|
} from "@/app/store/ruseFcltMng/fcltReg/rainReg";
|
|
import { htdflSttnSize } from "@/app/store/ruseFcltMng/fcltSttn/htdflSttn";
|
|
import {
|
|
excelDownloadNumStyle,
|
|
formatArchArea,
|
|
formatCommaNumber,
|
|
getCity,
|
|
tableData
|
|
} from "@/components/lib/func/common";
|
|
import { type SheetParameter } from "@common/business_components/ui";
|
|
import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal";
|
|
import HeadChModal from "@/components/ui/modal/sttn/headChModal/headChModal";
|
|
import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal";
|
|
import {
|
|
ContentsDiv,
|
|
SearchDiv,
|
|
SearchFormLeft,
|
|
SearchFormRight,
|
|
SearchInput,
|
|
SelectBox,
|
|
UiModal,
|
|
UiTable,
|
|
type SelectDataType
|
|
} from "@common/business_components/ui";
|
|
import ListDiv from "@common/business_components/ui/list_div";
|
|
import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan";
|
|
import { Button, Label } from "@common/components/ui";
|
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
import { useAlertStore } from "@/src/shared/lib";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
const defaultSigunOptions: SelectDataType[] = [{ text: "전체", val: "0" }];
|
|
|
|
export default function HtdflSttn() {
|
|
const { auth, code, htdflSttn, htdflSttnSearch, getLaeSeCdCheck } = useWrStore((state) => state);
|
|
const { laeSeCd } = auth; // 지자체구분코드
|
|
const { htdflSttnRes, htdflSttnResCount } = htdflSttn;
|
|
const initializedSearchKeyRef = useRef<string | null>(null);
|
|
const { t } = useTranslation('base');
|
|
const [pageNation, setPageNation] = useState(1);
|
|
const [isChHead, setIsChHead] = useState(false);
|
|
const [resetPage, isResetPage] = useState(false);
|
|
const [bdstTable, setBdstTable] = useState<customRainBdst[]>();
|
|
const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>(defaultSigunOptions)
|
|
const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" });
|
|
const [detailModal, setDetailModal] = useState<{
|
|
isOpen: boolean;
|
|
data: customRainBdst | undefined;
|
|
}>({ data: undefined, isOpen: false });
|
|
// const [bdstChgProps, setBdstChgProps] = useState<{
|
|
// isOpen: boolean;
|
|
// chBuilding: chgBuilding[];
|
|
// }>({ isOpen: false, chBuilding: [] });
|
|
const [fcltNm, setFcltNm] = useState<string>("");
|
|
const [appliedSearch, setAppliedSearch] = useState<{
|
|
conValue: string;
|
|
fcltNm: string;
|
|
} | null>(null);
|
|
const alert = useAlertStore((state) => state.setMessage);
|
|
const isAllAreaUser = laeSeCd === "0";
|
|
const isLaeSeCdReady =
|
|
laeSeCd === "0" || laeSeCd.length === 2 || laeSeCd.length === 5;
|
|
const fixedSidoValue =
|
|
!isAllAreaUser && laeSeCd?.length ? laeSeCd.slice(0, 2) : "";
|
|
const fixedSigunValue =
|
|
!isAllAreaUser && laeSeCd?.length === 5 ? laeSeCd : "0";
|
|
|
|
const getSelCity = (val: string | number) => {
|
|
const cityValue = String(val);
|
|
|
|
if (cityValue === "0") {
|
|
setSelectSgg(defaultSigunOptions);
|
|
setObjSearch({ city: cityValue, sgg: "" });
|
|
} else {
|
|
const data = getCity(cityValue, code.sggCd);
|
|
setSelectSgg(data.length > 0 ? data : defaultSigunOptions);
|
|
|
|
const firstSggVal = data.find(item => item.val === "0")?.val || (data[0]?.val ?? "");
|
|
setObjSearch({ city: cityValue, sgg: firstSggVal });
|
|
}
|
|
};
|
|
|
|
const getSgg = (val: string | number) => {
|
|
setObjSearch({ ...objSearch, sgg: String(val) })
|
|
};
|
|
|
|
const getConValue = useCallback((): string => {
|
|
if (!objSearch.city || objSearch.city === "0") {
|
|
return "0";
|
|
}
|
|
if (objSearch.sgg && objSearch.sgg !== "0") {
|
|
return String(objSearch.sgg);
|
|
}
|
|
return String(objSearch.city);
|
|
}, [objSearch]);
|
|
|
|
const getFixedConValue = useCallback((): string => {
|
|
if (laeSeCd === undefined || laeSeCd === "0") {
|
|
return getConValue();
|
|
}
|
|
|
|
return laeSeCd.length === 5 ? laeSeCd : laeSeCd.slice(0, 2);
|
|
}, [laeSeCd, getConValue]);
|
|
|
|
const cellClick = (index: number | undefined, headId: string) => {
|
|
if (
|
|
headId !== "chBuildingYn" &&
|
|
index !== undefined &&
|
|
bdstTable !== undefined
|
|
) {
|
|
setDetailModal({ isOpen: true, data: bdstTable[index] });
|
|
}
|
|
};
|
|
|
|
const excelClick = useCallback(async () => {
|
|
if (!isLaeSeCdReady || !appliedSearch) {
|
|
return;
|
|
}
|
|
|
|
const excelData = await htdflSttnSearch(
|
|
true,
|
|
1,
|
|
htdflSttnResCount,
|
|
appliedSearch.conValue,
|
|
appliedSearch.fcltNm,
|
|
code.cityCd,
|
|
code.sggCd
|
|
);
|
|
if (excelData && excelData.length > 0) {
|
|
const sheetArray: SheetParameter[] = [{
|
|
data: excelData,
|
|
headerNum: 3,
|
|
headerRange: "A1:R3",
|
|
sheetName: "sheet1",
|
|
startCol: "A",
|
|
decimalArray0: [6, 11, 13, 15],
|
|
}];
|
|
excelDownloadNumStyle(
|
|
"온배수시설 현황",
|
|
"sample_htdflSttn.xlsx",
|
|
sheetArray
|
|
);
|
|
return;
|
|
}
|
|
|
|
alert(t("excelDownErrMsg"));
|
|
}, [htdflSttnSearch, htdflSttnResCount, appliedSearch, code.cityCd, code.sggCd, isLaeSeCdReady, alert, t]);
|
|
|
|
useEffect(() => {
|
|
getLaeSeCdCheck();
|
|
}, [getLaeSeCdCheck]);
|
|
|
|
useEffect(() => {
|
|
if (!isLaeSeCdReady) {
|
|
return;
|
|
}
|
|
|
|
if (laeSeCd === "0") {
|
|
setSelectSgg(defaultSigunOptions);
|
|
setObjSearch({ city: "0", sgg: "" });
|
|
return;
|
|
}
|
|
|
|
const cityValue = laeSeCd.slice(0, 2);
|
|
const sigunOptions = getCity(cityValue, code.sggCd);
|
|
setSelectSgg(sigunOptions.length > 0 ? sigunOptions : defaultSigunOptions);
|
|
setObjSearch({
|
|
city: cityValue,
|
|
sgg: laeSeCd.length === 5 ? laeSeCd : "0",
|
|
});
|
|
}, [laeSeCd, code.sggCd, isLaeSeCdReady]);
|
|
|
|
useEffect(() => {
|
|
if (!isLaeSeCdReady) {
|
|
return;
|
|
}
|
|
|
|
const initialSearchKey = laeSeCd ?? "0";
|
|
if (initializedSearchKeyRef.current === initialSearchKey) {
|
|
return;
|
|
}
|
|
|
|
const initialConValue =
|
|
laeSeCd === undefined || laeSeCd === "0"
|
|
? "0"
|
|
: laeSeCd.length === 5
|
|
? laeSeCd
|
|
: laeSeCd.slice(0, 2);
|
|
|
|
initializedSearchKeyRef.current = initialSearchKey;
|
|
setAppliedSearch({
|
|
conValue: initialConValue,
|
|
fcltNm: "",
|
|
});
|
|
setPageNation(1);
|
|
}, [isLaeSeCdReady, laeSeCd]);
|
|
|
|
useEffect(() => {
|
|
if (!isLaeSeCdReady || !appliedSearch) {
|
|
return;
|
|
}
|
|
|
|
htdflSttnSearch(false, pageNation, htdflSttnSize, appliedSearch.conValue, appliedSearch.fcltNm, code.cityCd, code.sggCd);
|
|
isResetPage(false)
|
|
}, [pageNation, htdflSttnSearch, appliedSearch, code.cityCd, code.sggCd, isLaeSeCdReady]);
|
|
|
|
useEffect(() => {
|
|
const data = tableData(htdflSttnRes, { code });
|
|
const chData = data
|
|
.map((item: any) => ({
|
|
...item,
|
|
...item.reuseBuilding[0],
|
|
...item.reuseBuilding[0].htdflObj,
|
|
chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N",
|
|
archArea: formatArchArea(item?.archArea, 1),
|
|
prcsFcltCpct:
|
|
Number(item.reuseBuilding[0]?.htdflObj?.prcsFcltCpct) === -1
|
|
? "확인불가"
|
|
: formatCommaNumber(item.reuseBuilding[0]?.htdflObj?.prcsFcltCpct),
|
|
}))
|
|
.filter((item: any) => item.htdflObj !== undefined);
|
|
setBdstTable(chData);
|
|
}, [code, htdflSttnRes, htdflSttn.htdflSttHeadList]);
|
|
|
|
const handleSearch = useCallback(() => {
|
|
if (!isLaeSeCdReady) {
|
|
return;
|
|
}
|
|
|
|
setAppliedSearch({
|
|
conValue: String(getFixedConValue()),
|
|
fcltNm,
|
|
});
|
|
isResetPage(true);
|
|
setPageNation(1);
|
|
}, [fcltNm, getFixedConValue, isLaeSeCdReady]);
|
|
|
|
return (
|
|
<>
|
|
<ContentsDiv>
|
|
<div className="grid grid-cols-4 gap-4 ">
|
|
<div className="col-span-4">
|
|
|
|
<SearchDiv>
|
|
<SearchFormLeft>
|
|
<div className="col-span-10 flex flex-row">
|
|
<SelectBox
|
|
className="col-span-2 w-1/6 h-full text-2xl"
|
|
label="시도"
|
|
selectClass={""}
|
|
selectArray={
|
|
!isAllAreaUser && fixedSidoValue
|
|
? code.cityCd.filter((item) => item.val === fixedSidoValue)
|
|
: code.cityCd
|
|
}
|
|
value={objSearch.city || "0"}
|
|
onSelectValue={getSelCity}
|
|
/>
|
|
<SelectBox
|
|
className="col-span-2 w-1/6 h-full text-2xl ml-4"
|
|
label="시군구"
|
|
selectClass={""}
|
|
selectArray={
|
|
!isAllAreaUser && laeSeCd?.length === 5
|
|
? (selectSgg || defaultSigunOptions).filter((item) => item.val === "0" || item.val === fixedSigunValue)
|
|
: selectSgg || defaultSigunOptions
|
|
}
|
|
value={objSearch.sgg || "0"}
|
|
onSelectValue={getSgg}
|
|
/>
|
|
<div className="col-span-2 flex flex-row items-center space-x-2 ml-3">
|
|
<Label className="w-28 text-xl">
|
|
{"시설명"}
|
|
</Label>
|
|
<SearchInput
|
|
className={"w-full h-full text-2xl"}
|
|
label={""}
|
|
textValue={fcltNm || ""}
|
|
setText={setFcltNm}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</SearchFormLeft>
|
|
<SearchFormRight
|
|
className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 ">
|
|
<div className="flex flex-row space-x-2 items-center">
|
|
<Button
|
|
className={btnClass}
|
|
onClick={handleSearch}
|
|
>
|
|
조회
|
|
</Button>
|
|
<Button
|
|
className={`${btnClass} green`}
|
|
onClick={excelClick}
|
|
>
|
|
엑셀다운로드
|
|
</Button>
|
|
<Button
|
|
className={btnClass}
|
|
onClick={() => {
|
|
setIsChHead(true);
|
|
}}
|
|
>
|
|
조회항목설정
|
|
</Button>
|
|
</div>
|
|
</SearchFormRight>
|
|
</SearchDiv>
|
|
</div>
|
|
</div>
|
|
<div className="grid grid-cols-6 gap-4 ">
|
|
<div className="col-span-6">
|
|
<ListDiv>
|
|
<div className="h-full w-full overflow-x-scroll min-[1900px]:overflow-x-hidden">
|
|
<div className="w-[160%] min-[1900px]:w-[100%]">
|
|
<UiTable
|
|
headName={undefined}
|
|
tableData={bdstTable || []}
|
|
headlist={htdflSttn.htdflSttHeadList}
|
|
pageSize={htdflSttnSize}
|
|
total={htdflSttnResCount || 0}
|
|
cellClick={(index: number | undefined, headId: string) => {
|
|
cellClick(index ?? undefined, headId);
|
|
}}
|
|
onPageChange={setPageNation}
|
|
resetPageNo={resetPage}
|
|
widthFixed={true}
|
|
>
|
|
<HeadMakeColSpan upHeadList={htdflSttn.htdflSttNodeList} />
|
|
</UiTable>
|
|
</div>
|
|
</div>
|
|
</ListDiv>
|
|
</div>
|
|
</div>
|
|
<UiModal
|
|
open={isChHead}
|
|
onOpenChange={() => {
|
|
setIsChHead(!isChHead);
|
|
}}
|
|
bodyClass={""}
|
|
body={
|
|
<HeadChModal
|
|
type={"HTB"}
|
|
headList={htdflSttn.htdflSttHeadList.map((item) => ({
|
|
...item,
|
|
visible: item.visible ?? false,
|
|
}))}
|
|
onSaved={() => setIsChHead(false)}
|
|
/>
|
|
}
|
|
/>
|
|
<UiModal
|
|
open={detailModal.isOpen}
|
|
onOpenChange={() => {
|
|
setDetailModal({ ...detailModal, isOpen: !detailModal.isOpen });
|
|
}}
|
|
bodyClass={"w-[40vw] max-w-none max-h-[calc(100%-70px)]"}
|
|
body={<SttnDetailModal type={"HTB"} formObj={detailModal.data} />}
|
|
/>
|
|
</ContentsDiv>
|
|
</>
|
|
);
|
|
}
|
|
|