Merge branch 'iipbs/sn/dev'
This commit is contained in:
@@ -85,22 +85,20 @@ export const DmStatusReducer = (set: any): DmStatusActions => {
|
||||
|
||||
const boardData: DmStatusBoardType[] = data.data.map(
|
||||
(item: DmStatusDataType) => {
|
||||
const regionText = cityCd.find((city) => item.region === city.val);
|
||||
const regionText = item.sidoNm; //cityCd.find((city) => item.region === city.val);
|
||||
const sewage = item.sewage;
|
||||
const rainwater = item.rainwater;
|
||||
const reclaimed = item.reclaimed;
|
||||
const sewageCnt = item.sewageCnt;
|
||||
const rainwaterCnt = item.rainwaterCnt;
|
||||
const reclaimedCnt = item.reclaimedCnt;
|
||||
if (!regionText) console.log("item.region ", item.region);
|
||||
if (regionText && regionText.text) {
|
||||
|
||||
return {
|
||||
region: regionText ? regionText.text : item.region,
|
||||
sewage: sewageCnt + "(" + sewage + ")",
|
||||
rainwater: rainwaterCnt + "(" + rainwater + ")",
|
||||
reclaimed: reclaimedCnt + "(" + reclaimed + ")",
|
||||
region: regionText ? regionText : item.region,
|
||||
sewage: sewageCnt + "(" + sewage.toLocaleString() + ")",
|
||||
rainwater: rainwaterCnt + "(" + rainwater.toLocaleString() + ")",
|
||||
reclaimed: reclaimedCnt + "(" + reclaimed.toLocaleString() + ")",
|
||||
};
|
||||
}
|
||||
}
|
||||
).filter((item): item is DmStatusBoardType => item !== undefined);
|
||||
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
export type DmStatusDataType = {
|
||||
region: string;
|
||||
sidoNm: string; // 시도명
|
||||
region: string; // 시도코드
|
||||
sewage: string;
|
||||
rainwater: string;
|
||||
reclaimed: string;
|
||||
sewageCnt:string
|
||||
rainwaterCnt:string
|
||||
reclaimedCnt:string
|
||||
sewageCnt:string;
|
||||
rainwaterCnt:string;
|
||||
reclaimedCnt:string;
|
||||
};
|
||||
|
||||
export type DmStatusBoardType = {
|
||||
sidoNm: string; // 시도명
|
||||
region: string;
|
||||
sewage: string;
|
||||
rainwater: string;
|
||||
|
||||
@@ -209,10 +209,13 @@ export default function FacilityPrecipitation() {
|
||||
<ContentsDiv>
|
||||
<SearchBaseForm
|
||||
leftChildren={<>
|
||||
<SelectBox className="col-span-3" label={labelArray[3] as string} selectArray={selectUpdownData} onSelectValue={(val) => setFcltCpct(val.toString())} value={fcltCpct} selectClass={undefined} />
|
||||
<SelectBox className="col-span-3" label={labelArray[3] as string} selectArray={selectUpdownData}
|
||||
onSelectValue={(val) => setFcltCpct(val.toString())} value={fcltCpct} selectClass={undefined} />
|
||||
<SearchInput className={"col-span-3"} label={labelArray[4] as string} textValue={fcltyName} setText={setFcltyName} />
|
||||
<SelectBox className="col-span-3" label={labelArray[6] as string} selectArray={selectSearchYear} onSelectValue={(val) => setSearchYear(val.toString())} value={searchYear} selectClass={undefined} />
|
||||
<SelectBox className="col-span-3" label={labelArray[5] as string} selectArray={selectOperationData} onSelectValue={(val) => setOperationValue(val.toString())} value={operationValue} selectClass={undefined} />
|
||||
<SelectBox className="col-span-3" label={labelArray[6] as string} selectArray={selectSearchYear}
|
||||
onSelectValue={(val) => setSearchYear(val.toString())} value={searchYear} selectClass={undefined} />
|
||||
<SelectBox className="col-span-3" label={labelArray[5] as string} selectArray={selectOperationData}
|
||||
onSelectValue={(val) => setOperationValue(val.toString())} value={operationValue} selectClass={undefined} />
|
||||
</>}
|
||||
rightChildren={undefined}
|
||||
selectSidoData={selectSidoData}
|
||||
@@ -226,16 +229,19 @@ export default function FacilityPrecipitation() {
|
||||
excelClick={excelDownload}
|
||||
initClick={resetVal}
|
||||
ref={ref} isAdmin={false}/>
|
||||
<ListDiv>
|
||||
<LoadingOverlay isLoading={isLoading} />
|
||||
<div className="h-full w-full overflow-x-scroll min-[1200px]:overflow-x-hidden">
|
||||
<div className="w-[120%] min-[1200px]:w-[100%]">
|
||||
<UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)} headName={"시설별 강수현황"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} />
|
||||
<ListDiv>
|
||||
<LoadingOverlay isLoading={isLoading} />
|
||||
<div className="h-full w-full overflow-x-scroll min-[1200px]:overflow-x-hidden">
|
||||
<div className="w-[120%] min-[1200px]:w-[100%]">
|
||||
<UiTable cellClick={(index: number | undefined) => index !== undefined && cellClick(index)}
|
||||
headName={"시설별 강수현황"}
|
||||
tableData={mainList} headlist={upheadList} pageSize={10} total={total}
|
||||
resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} />
|
||||
</div>
|
||||
<UnderComment divHeight={"3"} commentArray={["강우일은 3mm 이상만 해당 / 강우영향일은 강우일 및 강우일 후 연속 2일간으로 정의"]} />
|
||||
</div>
|
||||
<UnderComment divHeight={"3"} commentArray={["강우일은 3mm 이상만 해당 / 강우영향일은 강우일 및 강우일 후 연속 2일간으로 정의"]} />
|
||||
</div>
|
||||
</ListDiv>
|
||||
</ContentsDiv>
|
||||
</ListDiv>
|
||||
</ContentsDiv>
|
||||
{selectedRow !== null && (
|
||||
<UiModal
|
||||
body={<PrecipitationModal searchYear={searchYear} fcltyName={fcltyNm} facilityCd={fcltyCd} detailList={gridListPrecipitationDetail}></PrecipitationModal>}
|
||||
|
||||
@@ -77,7 +77,7 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea
|
||||
useEffect(() => {
|
||||
const filteredYearData = setFilterAfterData(facilityWaterQltyYearList);
|
||||
setCopyYearList(filteredYearData as FacilityWaterQltyProps[]);
|
||||
setChongInWaterQltyYearList(filteredYearData as FacilityWaterQltyProps[]);
|
||||
setChongInWaterQltyYearList(facilityWaterQltyYearList);
|
||||
}, [facilityWaterQltyYearList]);
|
||||
|
||||
// 필터링 된 후 최대, 최소, 평균 값 계산
|
||||
@@ -344,8 +344,7 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea
|
||||
|
||||
const filterData = useCallback((returnType: ReturnType<FacilityWaterQltyProps>) => {
|
||||
const filteredData = setFilterAfterData(returnType.filteredList);
|
||||
setCopyYearList(filteredData as FacilityWaterQltyProps[]); // 처리시설 수질현황
|
||||
setChongInWaterQltyYearList(filteredData as FacilityWaterQltyProps[]); // 총인설비 수질현황
|
||||
setCopyYearList(filteredData as FacilityWaterQltyProps[]); // 처리시설/총인설비 수질현황
|
||||
}, []);
|
||||
|
||||
const excelDownload = () => {
|
||||
@@ -386,10 +385,10 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea
|
||||
prevExcelListRef.current = excelDownList;
|
||||
} else { // 총인설비 수질현황
|
||||
const excelDownList: modalChoinginExcelType[] = [];
|
||||
if (chongInWaterQltyYearList.length > 0) {
|
||||
chongInWaterQltyYearList.forEach((item) => {
|
||||
// if (copyYearList.length > 0) {
|
||||
// copyYearList.forEach((item) => {
|
||||
// if (chongInWaterQltyYearList.length > 0) {
|
||||
// chongInWaterQltyYearList.forEach((item) => {
|
||||
if (copyYearList.length > 0) {
|
||||
copyYearList.forEach((item) => {
|
||||
excelDownList.push({
|
||||
날짜: item.msrDt,
|
||||
"유입BOD(mg/L)": CommaToNumber(item.tpInflWqltBod),
|
||||
@@ -610,4 +609,4 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea
|
||||
</UITab>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +215,8 @@ export default function Rdi() {
|
||||
<LoadingOverlay isLoading={isLoading} />
|
||||
<div className="h-full w-full overflow-x-scroll min-[1200px]:overflow-x-hidden">
|
||||
<div className="w-[120%] min-[1200px]:w-[100%]">
|
||||
<UiTable cellClick={ undefined } headName={"RDII추정"} tableData={mainList} headlist={upheadList} pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} />
|
||||
<UiTable cellClick={ undefined } headName={"RDII추정"} tableData={mainList} headlist={upheadList}
|
||||
pageSize={10} total={total} resetPageNo={resetPage} onPageChange={handlePageChange} widthFixed={true} />
|
||||
</div>
|
||||
<UnderComment divHeight={"0"} commentArray={commentArray} />
|
||||
</div>
|
||||
|
||||
@@ -153,7 +153,9 @@ export const fetchFacilityRainDetailList = async (searchYear: string|undefined,
|
||||
}
|
||||
};
|
||||
|
||||
const fetchFacilityPrecipitationList = async (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => {
|
||||
const fetchFacilityPrecipitationList = async (pageNo: number, pageSize: number, searchYear: string, part?: string
|
||||
, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => {
|
||||
|
||||
const tailStr = '/'+pageNo + '/' + pageSize + '/' + searchYear + (part?'/' + part:'' ) + (nameCd?'/' + nameCd:'' ) + (fcltCpct?'/' + fcltCpct:'' ) + (operationValue?'/' + operationValue:'' ) + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') ;
|
||||
const url = '/fclt/rain' + tailStr;
|
||||
const res = await getFetch('fo', url);
|
||||
|
||||
@@ -24,6 +24,7 @@ import { Button, Label } from "@common/components/ui";
|
||||
import { useEffect, useState } from "react";
|
||||
import toast, { Toaster } from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import * as XLSX from "xlsx";
|
||||
|
||||
export default function RuseCaseMng() {
|
||||
const { code, ruseCaseMng, selectRuseCaseMng, ruseCaseMngInit } = useWrStore(
|
||||
@@ -76,7 +77,9 @@ export default function RuseCaseMng() {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (excelList !== undefined && excelList.length === 0) {
|
||||
if (!excelList) return;
|
||||
|
||||
if (excelList.length === 0) {
|
||||
toast.error(t("excelDownErrMsg"));
|
||||
return;
|
||||
}
|
||||
@@ -86,74 +89,93 @@ export default function RuseCaseMng() {
|
||||
}
|
||||
// 받은 파일 바인너리 처리
|
||||
const blobRet = await response.arrayBuffer();
|
||||
if (excelList) {
|
||||
const excelData1 = excelList.map((item) => {
|
||||
return [
|
||||
item.ruseBizNm,
|
||||
item.bizBgngDate,
|
||||
item.bizEndDate,
|
||||
item.splyFcltKnd,
|
||||
item.splyFcltNm,
|
||||
item.splyFcltCpct,
|
||||
item.dmdFcltNm,
|
||||
item.dmdFcltAddr,
|
||||
item.ruseFcltCpct,
|
||||
item.ruseFcltPplLen,
|
||||
item.ruseFcltUsg,
|
||||
item.ruseFcltSplyCpct,
|
||||
item.ruseFcltPrcsMsrc,
|
||||
item.grnteWqUsg,
|
||||
item.grnteWqGrssClfg,
|
||||
item.grnteWqCombResdch,
|
||||
item.grnteWqTrbt,
|
||||
item.grnteWqBod,
|
||||
item.grnteWqSmll,
|
||||
item.grnteWqCrmty,
|
||||
item.grnteWqTn,
|
||||
item.grnteWqTp,
|
||||
item.grnteWqPh,
|
||||
item.grnteWqClIonQnt,
|
||||
item.grnteWqCndctStat,
|
||||
item.grnteWqRmrk,
|
||||
item.reqBizGrssCst,
|
||||
item.reqBizReuseFcltCst,
|
||||
item.reqBizPplCst,
|
||||
item.reqBizArchCst,
|
||||
item.reqBizMchnCst,
|
||||
item.reqBizMtrngCst,
|
||||
item.reqBizGisCst,
|
||||
item.reqBizCctvCst,
|
||||
item.reqBizCmcnCst,
|
||||
item.reqBizWstCst,
|
||||
item.reqBizDesignCst,
|
||||
item.reqBizSpvsCst,
|
||||
item.reqBizSbsdCst,
|
||||
item.reqBizEtc,
|
||||
item.prcmPlanGrssCst,
|
||||
item.prcmPlanNlep,
|
||||
item.prcmPlanLcep,
|
||||
item.prcmPlanBrdnCst,
|
||||
item.prcmPlanEcqrRt,
|
||||
item.clclnGrssCst,
|
||||
item.clclnNlep,
|
||||
item.clclnLcep,
|
||||
item.clclnBrdnCst,
|
||||
item.clclnEcqrRt,
|
||||
];
|
||||
});
|
||||
|
||||
const sheetParameter: SheetParameter[] = [
|
||||
{
|
||||
data: excelData1,
|
||||
headerNum: 2,
|
||||
headerRange: "A1:AX1",
|
||||
sheetName: "물재이용사례",
|
||||
startCol: "A",
|
||||
},
|
||||
const replaceHeaderText = (text: string) =>
|
||||
text
|
||||
.replaceAll("사업시작일", "사업시작년")
|
||||
.replaceAll("사업종료일", "사업종료년");
|
||||
|
||||
const wb = XLSX.read(blobRet, { type: "array" });
|
||||
wb.SheetNames.forEach((sheetName) => {
|
||||
const sheet = wb.Sheets[sheetName];
|
||||
if (!sheet) return;
|
||||
|
||||
Object.keys(sheet).forEach((addr) => {
|
||||
if (addr.startsWith("!")) return;
|
||||
const cell = sheet[addr] as XLSX.CellObject | undefined;
|
||||
if (!cell || typeof cell.v !== "string") return;
|
||||
const next = replaceHeaderText(cell.v);
|
||||
if (next !== cell.v) cell.v = next;
|
||||
});
|
||||
});
|
||||
const updatedBlob = XLSX.write(wb, { bookType: "xlsx", type: "array" });
|
||||
|
||||
const excelData1 = excelList.map((item) => {
|
||||
return [
|
||||
item.ruseBizNm,
|
||||
item.bizBgngDate,
|
||||
item.bizEndDate,
|
||||
item.splyFcltKnd,
|
||||
item.splyFcltNm,
|
||||
item.splyFcltCpct,
|
||||
item.dmdFcltNm,
|
||||
item.dmdFcltAddr,
|
||||
item.ruseFcltCpct,
|
||||
item.ruseFcltPplLen,
|
||||
item.ruseFcltUsg,
|
||||
item.ruseFcltSplyCpct,
|
||||
item.ruseFcltPrcsMsrc,
|
||||
item.grnteWqUsg,
|
||||
item.grnteWqGrssClfg,
|
||||
item.grnteWqCombResdch,
|
||||
item.grnteWqTrbt,
|
||||
item.grnteWqBod,
|
||||
item.grnteWqSmll,
|
||||
item.grnteWqCrmty,
|
||||
item.grnteWqTn,
|
||||
item.grnteWqTp,
|
||||
item.grnteWqPh,
|
||||
item.grnteWqClIonQnt,
|
||||
item.grnteWqCndctStat,
|
||||
item.grnteWqRmrk,
|
||||
item.reqBizGrssCst,
|
||||
item.reqBizReuseFcltCst,
|
||||
item.reqBizPplCst,
|
||||
item.reqBizArchCst,
|
||||
item.reqBizMchnCst,
|
||||
item.reqBizMtrngCst,
|
||||
item.reqBizGisCst,
|
||||
item.reqBizCctvCst,
|
||||
item.reqBizCmcnCst,
|
||||
item.reqBizWstCst,
|
||||
item.reqBizDesignCst,
|
||||
item.reqBizSpvsCst,
|
||||
item.reqBizSbsdCst,
|
||||
item.reqBizEtc,
|
||||
item.prcmPlanGrssCst,
|
||||
item.prcmPlanNlep,
|
||||
item.prcmPlanLcep,
|
||||
item.prcmPlanBrdnCst,
|
||||
item.prcmPlanEcqrRt,
|
||||
item.clclnGrssCst,
|
||||
item.clclnNlep,
|
||||
item.clclnLcep,
|
||||
item.clclnBrdnCst,
|
||||
item.clclnEcqrRt,
|
||||
];
|
||||
// 버퍼에 있는 엑셀데이터 전달 후 json으로 변환
|
||||
await filePickedBlobArray(blobRet, "물재이용사례현황", sheetParameter);
|
||||
}
|
||||
});
|
||||
|
||||
const sheetParameter: SheetParameter[] = [
|
||||
{
|
||||
data: excelData1,
|
||||
headerNum: 2,
|
||||
headerRange: "A1:AX1",
|
||||
sheetName: "물재이용사례",
|
||||
startCol: "A",
|
||||
},
|
||||
];
|
||||
// 버퍼에 있는 엑셀데이터 전달 후 json으로 변환
|
||||
await filePickedBlobArray(updatedBlob, "물재이용사례현황", sheetParameter);
|
||||
});
|
||||
}, [excelList]);
|
||||
|
||||
@@ -299,8 +321,12 @@ export default function RuseCaseMng() {
|
||||
}}
|
||||
resetPageNo={resetPage}
|
||||
/>
|
||||
<span className="text-2xl font-bold text-gray-500">
|
||||
☞ 본 사례의 사업비는 재원협의 단계의 정보이므로, 최종확정된 비용이 아닙니다.
|
||||
</span>
|
||||
</div>
|
||||
</ListDiv>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</ContentsDiv>
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
/**
|
||||
* 재이용시설 등록 - 하수재이용 시설등록
|
||||
*
|
||||
* - layout.tsx에 의해 공통 레이아웃이 적용됨
|
||||
* - with-layout 적용
|
||||
* - 하수처리시설에 하수재이용 시설을 등록 한다.
|
||||
* - form으로 시설정보 및 차수별 정보의 컴포넌트 데이터를 관리한다
|
||||
* indexMng: 시설정보
|
||||
* indexBiz: 차수별 정보
|
||||
* 로 하수재이용 시설에 등록된 시설 및 차수별 정보를 관리한다.
|
||||
* 🔗 사용 API
|
||||
* 하수재이용시설을 등록 /reuseFc/pubFc
|
||||
* 첨부파일 삭제 /attach-service/api/v1/atfl/attachments/atflCd//
|
||||
* 첨부파일 다운로드 /attach-service/api/v1/atflcd/download/
|
||||
* */
|
||||
|
||||
"use client";
|
||||
import {
|
||||
ContentsDiv,
|
||||
@@ -35,18 +51,6 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
import { createDefaultPbnstItem } from "./utilsZod";
|
||||
import { useTranslation } from "react-i18next";
|
||||
/**
|
||||
* 재이용시설 등록 - 하수재이용 시설등록
|
||||
*
|
||||
* - layout.tsx에 의해 공통 레이아웃이 적용됨
|
||||
* - with-layout 적용
|
||||
* - 하수처리시설에 하수재이용 시설을 등록 한다.
|
||||
* - form으로 시설정보 및 차수별 정보의 컴포넌트 데이터를 관리한다
|
||||
* indexMng: 시설정보
|
||||
* indexBiz: 차수별 정보
|
||||
* 로 하수재이용 시설에 등록된 시설 및 차수별 정보를 관리한다.
|
||||
* */
|
||||
|
||||
export default function PublicReuseFaciltyInsert() {
|
||||
const {
|
||||
auth,
|
||||
@@ -104,7 +108,7 @@ export default function PublicReuseFaciltyInsert() {
|
||||
|
||||
useEffect(() => {
|
||||
if (useInitRef.current == true && laeSeCd !== undefined) {
|
||||
pubHasuInit("1", laeSeCd);
|
||||
pubHasuInit("1", laeSeCd); //page: string, sggOrCity: string
|
||||
}
|
||||
}, [useInitRef.current, laeSeCd]);
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/**
|
||||
* 온배수시설 현황
|
||||
*/
|
||||
"use client";
|
||||
|
||||
import { useWrStore } from "@/app/store";
|
||||
import { btnClass } from "@/app/store/common/code";
|
||||
import type {
|
||||
@@ -34,11 +36,9 @@ import toast, { Toaster } from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function HtdflSttn() {
|
||||
const { code, htdflSttn, htdflSttnSearch, initHtdfl } = useWrStore(
|
||||
(state) => state
|
||||
);
|
||||
const { auth, code, htdflSttn, htdflSttnSearch, initHtdfl } = useWrStore((state) => state);
|
||||
const { laeSeCd } = auth; // 지자체구분코드
|
||||
const { htdflSttnRes, htdflSttnResCount } = htdflSttn;
|
||||
|
||||
const isDownloadTriggered = useRef(false);
|
||||
const { t } = useTranslation('base');
|
||||
const [pageNation, setPageNation] = useState(1);
|
||||
@@ -57,6 +57,7 @@ export default function HtdflSttn() {
|
||||
// }>({ isOpen: false, chBuilding: [] });
|
||||
const [fcltNm, setFcltNm] = useState<string>("");
|
||||
|
||||
console.log("laeSeCd : ", laeSeCd);
|
||||
useEffect(() => {
|
||||
htdflSttnSearch(false, pageNation, htdflSttnSize, String(getConValue()), fcltNm, code.cityCd, code.sggCd);
|
||||
isResetPage(false)
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/**
|
||||
* 하수재이용 시설 현황
|
||||
* 재이용시설 현황 - 하수재이용시설 현황
|
||||
* - layout.tsx에 의해 공통 레이아웃이 적용됨
|
||||
* - with-layout 적용
|
||||
* 하수처리시설. 하수재이용시설 , 하수재이용시설 실적에 대한 정보를 확인한다.
|
||||
* 모달 : 테이블의 헤더를 원하는대로 조절해서 볼수 있다.
|
||||
* 클릭시 해당 재이용ㅇ
|
||||
* */
|
||||
"use client";
|
||||
import { useWrStore } from "@/app/store";
|
||||
import { btnClass } from "@/app/store/common/code";
|
||||
@@ -24,15 +33,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import toast, { Toaster } from "react-hot-toast";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
/**
|
||||
* 하수재이용 시설 현황
|
||||
* 재이용시설 현황 - 하수재이용시설 현황
|
||||
* - layout.tsx에 의해 공통 레이아웃이 적용됨
|
||||
* - with-layout 적용
|
||||
* 하수처리시설. 하수재이용시설 , 하수재이용시설 실적에 대한 정보를 확인한다.
|
||||
* 모달 : 테이블의 헤더를 원하는대로 조절해서 볼수 있다.
|
||||
* 클릭시 해당 재이용ㅇ
|
||||
* */
|
||||
|
||||
export default function PbnstSttn() {
|
||||
const {
|
||||
code,
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* 빗물재이용시설 현황
|
||||
*/
|
||||
"use client";
|
||||
import { useWrStore } from "@/app/store";
|
||||
import { btnClass } from "@/app/store/common/code";
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
/**
|
||||
* 중수도시설 현황
|
||||
*/
|
||||
"use client";
|
||||
import { useWrStore } from "@/app/store";
|
||||
import { btnClass } from "@/app/store/common/code";
|
||||
|
||||
@@ -10,7 +10,7 @@ export type authState = {
|
||||
regAuthrtYn: string;
|
||||
mdfcnAuthrtYn: string;
|
||||
delAuthrtYn: string;
|
||||
laeSeCd: string;
|
||||
laeSeCd: string; // 지자체구분코드
|
||||
myUUID?: string;
|
||||
};
|
||||
};
|
||||
@@ -72,6 +72,7 @@ export const authActionsExport: (set: any, get: any) => authActions = (
|
||||
return;
|
||||
}
|
||||
const infoMe = await getUserInfo();
|
||||
console.log(infoMe);
|
||||
const isLaeSeCd =
|
||||
infoMe.laeSeCd.slice(0, 2) === "G3" ? infoMe.laeSeCd.slice(2) : "0";
|
||||
|
||||
|
||||
@@ -11,14 +11,14 @@ export const ruseCaseHeadListExport: TableUpperProps[] = [
|
||||
},
|
||||
{
|
||||
id: "bizBgngDate",
|
||||
title: "사업시작일",
|
||||
title: "사업시작년",
|
||||
visible: true,
|
||||
row: 0,
|
||||
rowSpan: 2,
|
||||
},
|
||||
{
|
||||
id: "bizEndDate",
|
||||
title: "사업종료일",
|
||||
title: "사업종료년",
|
||||
visible: true,
|
||||
row: 0,
|
||||
rowSpan: 2,
|
||||
|
||||
@@ -118,7 +118,7 @@ const hasuListFetch = async (
|
||||
if (searchTxt) {
|
||||
url = url + `/${searchTxt}`;
|
||||
}
|
||||
const rainRes = await postFectch(url, data, fetchType.COMMON);
|
||||
const rainRes = await postFectch(url, data, fetchType.COMMON); // fo
|
||||
|
||||
const hasuList = rainRes.data.map((item: any) => {
|
||||
return {
|
||||
@@ -176,7 +176,7 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => {
|
||||
// 하수처리시설을 조회한다(운영실태)
|
||||
pubHasuInit: async (page: string, sggOrCity: string) => {
|
||||
try {
|
||||
const pbnstHasuRes = await hasuListFetch(page, sggOrCity);
|
||||
const pbnstHasuRes = await hasuListFetch(page, sggOrCity); // /prcsFclt/ruseInfo
|
||||
return set((state: pubFacState) => ({
|
||||
...state,
|
||||
pbnst: {
|
||||
|
||||
@@ -35,10 +35,11 @@ export type FilesType = {
|
||||
file: File;
|
||||
};
|
||||
|
||||
const diagramFileTypes = ".pdf,.jpg,.jpeg,.png,.bmp";
|
||||
|
||||
/**
|
||||
* 재이용시설 등록 - 하수재이용 시설등록
|
||||
* 재이용시설 등록 - 하수재이용 시설현황
|
||||
* 재이용시설 등록 - 하수재이용 시설현황
|
||||
* - layout.tsx에 의해 공통 레이아웃이 적용됨
|
||||
* - with-layout 적용
|
||||
* - 하수처리시설에 하수재이용 시설 시설 정보를 등록한다.
|
||||
@@ -459,7 +460,7 @@ export function PbnstMngForm({
|
||||
setFiles={(files: File[] | null) => {
|
||||
if (files) fileHandler(files, "relation");
|
||||
}}
|
||||
fileTypes=".pdf"
|
||||
fileTypes={diagramFileTypes}
|
||||
onFileClick={(index) => {
|
||||
fileDownLoad(
|
||||
relationfiles?.find(
|
||||
@@ -497,7 +498,7 @@ export function PbnstMngForm({
|
||||
setFiles={(files: File[] | null) => {
|
||||
if (files) fileHandler(files, "plan");
|
||||
}}
|
||||
fileTypes=".pdf"
|
||||
fileTypes={diagramFileTypes}
|
||||
onFileClick={(index) => {
|
||||
fileDownLoad(
|
||||
planFiles?.find(
|
||||
|
||||
@@ -2,5 +2,5 @@ import { clsx, type ClassValue } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
return twMerge(clsx(inputs)); //clsx 결과 (단순 합치기):twMerge 결과 (Tailwind 충돌 제거)
|
||||
}
|
||||
|
||||
@@ -93,6 +93,7 @@ export const FileUploader = forwardRef<
|
||||
".jpeg": "image/jpeg",
|
||||
".png": "image/png",
|
||||
".gif": "image/gif",
|
||||
".bmp": "image/bmp",
|
||||
".doc": "application/msword",
|
||||
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
".xls": "application/vnd.ms-excel",
|
||||
|
||||
@@ -15,6 +15,7 @@ export * from "./search_form_right";
|
||||
export * from "./search_input";
|
||||
export * from "./search_input_select";
|
||||
// export * from "./search_input_address";
|
||||
export * from "./search_address";
|
||||
export * from "./select";
|
||||
export * from "./tab";
|
||||
export * from "./table";
|
||||
@@ -24,4 +25,4 @@ export * from "./sdmInsertForm";
|
||||
export * from "./popover_ui";
|
||||
export * from "./date_month_picker";
|
||||
export * from "./date_picker_range"
|
||||
export * from "./map/GisOverlay";
|
||||
export * from "./map/GisOverlay";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Button, Input, Label } from "@common/components";
|
||||
import { Button, Input } from "@common/components";
|
||||
import { AsYouType } from "libphonenumber-js";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import type { ControllerRenderProps, UseFormReturn } from "react-hook-form";
|
||||
@@ -6,10 +6,7 @@ import { FormField } from "../form";
|
||||
import { FormUi } from "../form_ui";
|
||||
import { SelectBox } from "../select";
|
||||
import { SdmSearchForm } from "./sdmNameBox";
|
||||
import { UiModal, UiTable } from '../../ui';
|
||||
import type { Zip, ZipSearchParams } from "../search_input_address/zipService";
|
||||
import { findAddress } from "../search_input_address/findAddress";
|
||||
import { cn } from "@common/components";
|
||||
import { SearchAddressModal } from "../search_address/SearchAddressModal";
|
||||
|
||||
// 수요처 정보
|
||||
export type DemandCompType = {
|
||||
@@ -91,7 +88,6 @@ export function SdmRegForm({
|
||||
readOnly,
|
||||
openNetwork,
|
||||
}: SdmRegFormProps) {
|
||||
const PAGE_SIZE = 10;
|
||||
const [sidoValue, setSidoValue] = useState<string>("");
|
||||
const [sigunValue, setSigunValue] = useState<string>("");
|
||||
const [filteredSigunData, setFilteredSigunData] = useState<SelectDataType[]>([
|
||||
@@ -104,30 +100,6 @@ export function SdmRegForm({
|
||||
const [zipId, setZipId] = useState<number | undefined>(undefined);
|
||||
const [address, setAddress] = useState<string | undefined>("");
|
||||
const [detailedAddress, setDetailedAddress] = useState<string>("");
|
||||
const [curPage, setCurPage] = useState<number>(1);
|
||||
// 우편번호 검색 관련 상태
|
||||
const [zipSearchResults, setZipSearchResults] = useState<Zip[]>([]);
|
||||
const [zipTotalElements, setZipTotalElements] = useState<number>(-1);
|
||||
const [searchQuery, setSearchQuery] = useState<ZipSearchParams>({
|
||||
roadNm: "",
|
||||
bldgNoMno: null,
|
||||
bldgNoSno: null,
|
||||
page: curPage,
|
||||
size: PAGE_SIZE
|
||||
});
|
||||
const [isResetPage, setIsResetPage] = useState<boolean>(false);
|
||||
const [isResetSelection, setIsResetSelection] = useState<boolean>(false);
|
||||
const [selectedRowIndex, setSelectedRowIndex] = useState<number | undefined>(undefined);
|
||||
const [selectedZip, setSelectedZip] = useState<Zip>();
|
||||
const [isSelectedZip, setIsSelectedZip] = useState<boolean>(false);
|
||||
|
||||
const handleCellClick = (index: any, headId: any) => {
|
||||
console.log('index', index);
|
||||
console.log('headId', headId);
|
||||
setSelectedZip(zipSearchResults[index]);
|
||||
setIsSelectedZip(true);
|
||||
console.log('selectedZip', zipSearchResults[index]);
|
||||
};
|
||||
|
||||
const formatPhoneNumber = (value: string) => {
|
||||
const input = value;
|
||||
@@ -293,17 +265,6 @@ export function SdmRegForm({
|
||||
[orgBznmNo, setIsDuplicate],
|
||||
);
|
||||
|
||||
// 우편번호 선택 함수
|
||||
const handleSelectAddress = () => {
|
||||
setZipId(selectedZip?.zipId);
|
||||
setAddress(selectedZip?.zipAddr || "");
|
||||
setDetailedAddress("");
|
||||
setIsZipModalOpen(false);
|
||||
setSelectedZip(undefined);
|
||||
setIsSelectedZip(false);
|
||||
setSelectedRowIndex(undefined);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (updateList?.dmdInfoId) {
|
||||
form.reset(updateList);
|
||||
@@ -325,16 +286,6 @@ export function SdmRegForm({
|
||||
console.log("form.formState.errors ", form.formState.errors);
|
||||
}, [form.formState.errors]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("curPage ", curPage);
|
||||
searchQuery.page = curPage - 1;
|
||||
const fetchAddress = async () => {
|
||||
const result = await findAddress(searchQuery);
|
||||
setZipSearchResults(result?.content);
|
||||
};
|
||||
fetchAddress();
|
||||
}, [curPage]);
|
||||
|
||||
// 폼 제출 전에 주소 합치기
|
||||
useEffect(() => {
|
||||
// address와 detailedAddress를 합쳐서 daddr에 설정
|
||||
@@ -344,105 +295,6 @@ export function SdmRegForm({
|
||||
}
|
||||
}, [address, detailedAddress, form]);
|
||||
|
||||
const renderBody = () => (
|
||||
<>
|
||||
<form
|
||||
onSubmit={async (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const result = await findAddress(searchQuery);
|
||||
setZipSearchResults(result?.content);
|
||||
setZipTotalElements(result?.totalElements);
|
||||
}}
|
||||
className="mb-4 space-y-2"
|
||||
>
|
||||
{/* 검색 조건 부분 */}
|
||||
<div className="card card-border !m-0 flex flex-col gap-4 p-4">
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div className="flex flex-col">
|
||||
<Label className="mb-1 font-bold text-base">도로명</Label>
|
||||
<Input
|
||||
value={searchQuery.roadNm || ""}
|
||||
onChange={(e) =>
|
||||
setSearchQuery({
|
||||
...searchQuery,
|
||||
roadNm: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="예: 테헤란로"
|
||||
className="!text-[1.3rem]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col">
|
||||
<Label className="mb-1 text-base">건물본번</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={searchQuery.bldgNoMno ?? ""}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value
|
||||
? parseInt(e.target.value)
|
||||
: null;
|
||||
setSearchQuery({
|
||||
...searchQuery,
|
||||
bldgNoMno: value,
|
||||
});
|
||||
}}
|
||||
placeholder="예: 123"
|
||||
className="!text-[1.3rem]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col">
|
||||
<Label className="mb-1 text-base">건물부번</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={searchQuery.bldgNoSno ?? ""}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value
|
||||
? parseInt(e.target.value)
|
||||
: null;
|
||||
setSearchQuery({
|
||||
...searchQuery,
|
||||
bldgNoSno: value,
|
||||
});
|
||||
}}
|
||||
placeholder="예: 45"
|
||||
className="!text-[1.3rem]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button className="rounded-md" type="submit">검색</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{/* 검색 결과 부분 */}
|
||||
{zipTotalElements > 0 && (
|
||||
<UiTable
|
||||
headName=''
|
||||
tableData={zipSearchResults}
|
||||
headlist={[{ id: 'zoneNo', title: '우편번호' }, { id: 'zipAddr', title: '주소' }]}
|
||||
pageSize={PAGE_SIZE}
|
||||
total={zipTotalElements}
|
||||
cellClick={handleCellClick}
|
||||
onPageChange={setCurPage}
|
||||
resetPageNo={isResetPage}
|
||||
resetSelection={isResetSelection}
|
||||
index={selectedRowIndex}
|
||||
/>
|
||||
)}
|
||||
{zipTotalElements === 0 && (
|
||||
<div className={cn("flex h-96 flex-col items-center justify-center gap-4")}>
|
||||
<i className="diveicon di-info-circle text-3xl" />
|
||||
조회된 데이터가 없습니다.
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
|
||||
const formFields: Array<{
|
||||
name: keyof FormSchema;
|
||||
@@ -725,35 +577,14 @@ export function SdmRegForm({
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<UiModal
|
||||
headerTitle="주소 검색"
|
||||
headerTitleClass="text-2xl font-bold text-gray-900"
|
||||
<SearchAddressModal
|
||||
open={isZipModalOpen}
|
||||
onOpenChange={setIsZipModalOpen}
|
||||
bodyClass={`
|
||||
${zipTotalElements > -1 ? 'h-[80vh]' : 'h-[30vh]'}
|
||||
w-[30vw]
|
||||
min-w-[500px]
|
||||
max-w-[90vw]
|
||||
max-h-[85vh]
|
||||
overflow-y-auto
|
||||
!fixed
|
||||
!top-[50%]
|
||||
!left-[50%]
|
||||
!-translate-x-1/2
|
||||
!-translate-y-1/2
|
||||
z-[101]
|
||||
flex
|
||||
flex-col
|
||||
`}
|
||||
body={renderBody()}
|
||||
footerContent={
|
||||
<div className="w-full flex justify-center items-center gap-4">
|
||||
<Button className="rounded-md" size="lg" onClick={handleSelectAddress} disabled={!isSelectedZip}>선택</Button>
|
||||
<Button className="rounded-md" size="lg" onClick={() => setIsZipModalOpen(false)}>취소</Button>
|
||||
</div>
|
||||
}
|
||||
useDirectRender={true}
|
||||
onSelect={(zip) => {
|
||||
setZipId(zip.zipId);
|
||||
setAddress(zip.zipAddr || "");
|
||||
setDetailedAddress("");
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
import { Button, Input, Label, cn } from "@common/components";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { UiModal } from "../dialog_ui";
|
||||
import { UiTable } from "../table";
|
||||
import type { Zip, ZipSearchParams } from "./zipService";
|
||||
import { findAddress } from "./findAddress";
|
||||
|
||||
interface SearchAddressModalProps {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
onSelect: (zip: Zip) => void;
|
||||
}
|
||||
|
||||
export function SearchAddressModal({ open, onOpenChange, onSelect }: SearchAddressModalProps) {
|
||||
const PAGE_SIZE = 10;
|
||||
const [curPage, setCurPage] = useState<number>(1);
|
||||
const [zipSearchResults, setZipSearchResults] = useState<Zip[]>([]);
|
||||
const [zipTotalElements, setZipTotalElements] = useState<number>(-1);
|
||||
const [searchQuery, setSearchQuery] = useState<ZipSearchParams>({
|
||||
roadNm: "",
|
||||
bldgNoMno: null,
|
||||
bldgNoSno: null,
|
||||
page: 1,
|
||||
size: PAGE_SIZE
|
||||
});
|
||||
const [isResetPage, setIsResetPage] = useState<boolean>(false);
|
||||
const [isResetSelection] = useState<boolean>(false);
|
||||
const [selectedRowIndex, setSelectedRowIndex] = useState<number | undefined>(undefined);
|
||||
const [selectedZip, setSelectedZip] = useState<Zip>();
|
||||
const [isSelectedZip, setIsSelectedZip] = useState<boolean>(false);
|
||||
|
||||
// Initialize/Reset state when modal opens
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
setCurPage(1);
|
||||
setZipSearchResults([]);
|
||||
setZipTotalElements(-1);
|
||||
setSearchQuery({
|
||||
roadNm: "",
|
||||
bldgNoMno: null,
|
||||
bldgNoSno: null,
|
||||
page: 0,
|
||||
size: PAGE_SIZE
|
||||
});
|
||||
setSelectedZip(undefined);
|
||||
setIsSelectedZip(false);
|
||||
setSelectedRowIndex(undefined);
|
||||
setIsResetPage(true);
|
||||
setTimeout(() => setIsResetPage(false), 100);
|
||||
}
|
||||
}, [open]);
|
||||
|
||||
// Pagination Effect
|
||||
useEffect(() => {
|
||||
if (!open || zipTotalElements === -1) return;
|
||||
|
||||
// Correctly update query for pagination without mutation
|
||||
const nextPage = curPage - 1;
|
||||
if (searchQuery.page !== nextPage) {
|
||||
const newQuery = { ...searchQuery, page: nextPage };
|
||||
setSearchQuery(newQuery);
|
||||
|
||||
const fetchAddress = async () => {
|
||||
const result = await findAddress(newQuery);
|
||||
setZipSearchResults(result?.content || []);
|
||||
};
|
||||
fetchAddress();
|
||||
}
|
||||
}, [curPage, open, zipTotalElements]);
|
||||
|
||||
const handleCellClick = (index: any) => {
|
||||
setSelectedZip(zipSearchResults[index]);
|
||||
setIsSelectedZip(true);
|
||||
setSelectedRowIndex(index);
|
||||
};
|
||||
|
||||
const handleSearch = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const query = { ...searchQuery, page: 0 };
|
||||
setSearchQuery(query);
|
||||
setCurPage(1);
|
||||
setIsResetPage(true);
|
||||
|
||||
const result = await findAddress(query);
|
||||
setZipSearchResults(result?.content || []);
|
||||
setZipTotalElements(result?.totalElements || 0);
|
||||
|
||||
setTimeout(() => setIsResetPage(false), 100);
|
||||
};
|
||||
|
||||
const handleConfirm = () => {
|
||||
if (selectedZip) {
|
||||
onSelect(selectedZip);
|
||||
onOpenChange(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<UiModal
|
||||
headerTitle="주소 검색"
|
||||
headerTitleClass="text-2xl font-bold text-gray-900"
|
||||
open={open}
|
||||
onOpenChange={onOpenChange}
|
||||
bodyClass={`
|
||||
${zipTotalElements > -1 ? 'h-[80vh]' : 'h-[30vh]'}
|
||||
w-[30vw]
|
||||
min-w-[500px]
|
||||
max-w-[90vw]
|
||||
min-h-[235px]
|
||||
overflow-y-auto
|
||||
!fixed
|
||||
!top-[50%]
|
||||
!left-[50%]
|
||||
!-translate-x-1/2
|
||||
!-translate-y-1/2
|
||||
z-[101]
|
||||
flex
|
||||
flex-col
|
||||
`}
|
||||
body={
|
||||
<>
|
||||
<form
|
||||
onSubmit={handleSearch}
|
||||
className="mb-4 space-y-2"
|
||||
>
|
||||
<div className="card card-border !m-0 flex flex-col gap-4 p-4">
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div className="flex flex-col">
|
||||
<Label className="mb-1 font-bold text-base">도로명</Label>
|
||||
<Input
|
||||
value={searchQuery.roadNm || ""}
|
||||
onChange={(e) =>
|
||||
setSearchQuery({
|
||||
...searchQuery,
|
||||
roadNm: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="예: 테헤란로"
|
||||
className="!text-[1.3rem]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col">
|
||||
<Label className="mb-1 text-base">건물본번</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={searchQuery.bldgNoMno ?? ""}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value
|
||||
? parseInt(e.target.value)
|
||||
: null;
|
||||
setSearchQuery({
|
||||
...searchQuery,
|
||||
bldgNoMno: value,
|
||||
});
|
||||
}}
|
||||
placeholder="예: 123"
|
||||
className="!text-[1.3rem]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col">
|
||||
<Label className="mb-1 text-base">건물부번</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={searchQuery.bldgNoSno ?? ""}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value
|
||||
? parseInt(e.target.value)
|
||||
: null;
|
||||
setSearchQuery({
|
||||
...searchQuery,
|
||||
bldgNoSno: value,
|
||||
});
|
||||
}}
|
||||
placeholder="예: 45"
|
||||
className="!text-[1.3rem]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button className="rounded-md" type="submit">검색</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{zipTotalElements > 0 && (
|
||||
<UiTable
|
||||
headName=''
|
||||
tableData={zipSearchResults}
|
||||
headlist={[{ id: 'zoneNo', title: '우편번호' }, { id: 'zipAddr', title: '주소' }]}
|
||||
pageSize={PAGE_SIZE}
|
||||
total={zipTotalElements}
|
||||
cellClick={handleCellClick}
|
||||
onPageChange={setCurPage}
|
||||
resetPageNo={isResetPage}
|
||||
resetSelection={isResetSelection}
|
||||
index={selectedRowIndex}
|
||||
/>
|
||||
)}
|
||||
{zipTotalElements === 0 && (
|
||||
<div className={cn("flex h-96 flex-col items-center justify-center gap-4")}>
|
||||
<i className="diveicon di-info-circle text-3xl" />
|
||||
조회된 데이터가 없습니다.
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
footerContent={
|
||||
<div className="w-full flex justify-center items-center gap-4">
|
||||
<Button className="rounded-md" size="lg" onClick={handleConfirm} disabled={!isSelectedZip}>선택</Button>
|
||||
<Button className="rounded-md" size="lg" onClick={() => onOpenChange(false)}>취소</Button>
|
||||
</div>
|
||||
}
|
||||
useDirectRender={true}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
|
||||
// const Key = 'U01TX0FVVEgyMDI1MDgyODE0MTAxNzExNjEyMjA'
|
||||
// const addresssKey = 'devU01TX0FVVEgyMDI1MDgyNTEwMzkwNDExNjEwNTM='; //인증키 만료일은 2025-11-23
|
||||
|
||||
import type { Zip, ZipSearchParams } from "./zipService";
|
||||
|
||||
/**
|
||||
* 주소 API 응답 타입
|
||||
* https://business.juso.go.kr/addrlink/main.do 해당 사이트 참조
|
||||
*/
|
||||
export type AddressApiResponse = {
|
||||
results: {
|
||||
common: {
|
||||
errorMessage: string;
|
||||
countPerPage: string;
|
||||
totalCount: string;
|
||||
errorCode: string;
|
||||
currentPage: string;
|
||||
};
|
||||
juso: addressType[];
|
||||
};
|
||||
}
|
||||
|
||||
export type addressType = {
|
||||
detBdNmList: string;
|
||||
engAddr: string;
|
||||
rn: string;
|
||||
emdNm: string;
|
||||
zipNo: string;
|
||||
roadAddrPart2: string;
|
||||
emdNo: string;
|
||||
sggNm: string;
|
||||
jibunAddr: string;
|
||||
siNm: string;
|
||||
roadAddrPart1: string;
|
||||
bdNm: string;
|
||||
admCd: string;
|
||||
udrtYn: string;
|
||||
lnbrMnnm: string;
|
||||
roadAddr: string;
|
||||
lnbrSlno: string;
|
||||
buldMnnm: string;
|
||||
bdKdcd: string;
|
||||
liNm: string;
|
||||
rnMgtSn: string;
|
||||
mtYn: string;
|
||||
bdMgtSn: string;
|
||||
buldSlno: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 주소에 따른 검색
|
||||
* @param search : 검색어
|
||||
* @returns addressType[] 주소 배열
|
||||
*/
|
||||
export const findAddress = async (searchQuery: ZipSearchParams): Promise<any> => {
|
||||
if (!searchQuery) return [];
|
||||
|
||||
// 쿼리 파라미터 생성
|
||||
const params = new URLSearchParams();
|
||||
if (searchQuery.roadNm) params.append('roadNm', searchQuery.roadNm);
|
||||
if (searchQuery.bldgNoMno != null) params.append('bldgNoMno', searchQuery.bldgNoMno.toString());
|
||||
if (searchQuery.bldgNoSno != null) params.append('bldgNoSno', searchQuery.bldgNoSno.toString());
|
||||
if (searchQuery.page != null) params.append('page', searchQuery.page.toString());
|
||||
if (searchQuery.size != null) params.append('size', searchQuery.size.toString());
|
||||
|
||||
const url = `/cms-service/api/v1/zips?${params.toString()}`;
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) throw new Error('Network response was not ok');
|
||||
|
||||
const data = await response.json();
|
||||
if (data) return data
|
||||
else return [];
|
||||
} catch (error) {
|
||||
console.error('Error fetching address data:', error);
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const searchFilter = (search: string) => {
|
||||
|
||||
|
||||
if (search.length > 0) {
|
||||
//특수문자 제거
|
||||
const expText = /[%=><]/;
|
||||
if (expText.test(search) == true) {
|
||||
alert("특수문자를 입력 할수 없습니다.");
|
||||
search = search.split(expText).join("");
|
||||
return false;
|
||||
}
|
||||
|
||||
//특정문자열(sql예약어의 앞뒤공백포함) 제거
|
||||
const sqlArray = [
|
||||
//sql 예약어
|
||||
"OR", "SELECT", "INSERT", "DELETE", "UPDATE", "CREATE", "DROP", "EXEC",
|
||||
"UNION", "FETCH", "DECLARE", "TRUNCATE"
|
||||
]
|
||||
|
||||
let regex;
|
||||
for (let i = 0; i < sqlArray.length; i++) {
|
||||
regex = new RegExp(sqlArray[i] as string, "gi");
|
||||
|
||||
if (regex.test(search)) {
|
||||
alert("\"" + sqlArray[i] + "\"와(과) 같은 특정문자로 검색할 수 없습니다.");
|
||||
search = search.replace(regex, "");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from "./SearchAddressModal";
|
||||
export * from "./findAddress";
|
||||
export * from "./zipService";
|
||||
@@ -0,0 +1,66 @@
|
||||
interface SortConfig {
|
||||
empty: boolean;
|
||||
sorted: boolean;
|
||||
unsorted: boolean;
|
||||
}
|
||||
|
||||
interface PageableConfig {
|
||||
sort: SortConfig;
|
||||
offset: number;
|
||||
pageNumber: number;
|
||||
pageSize: number;
|
||||
paged: boolean;
|
||||
unpaged: boolean;
|
||||
}
|
||||
|
||||
export interface PageableList<T> {
|
||||
content: T[];
|
||||
pageable: PageableConfig;
|
||||
sort: SortConfig;
|
||||
totalPages: number;
|
||||
totalElements: number;
|
||||
number: number;
|
||||
numberOfElements: number;
|
||||
size: number;
|
||||
first: boolean;
|
||||
last: boolean;
|
||||
empty: boolean;
|
||||
}
|
||||
|
||||
export interface PageableParams {
|
||||
page?: number;
|
||||
size?: number;
|
||||
sort?: string;
|
||||
}
|
||||
|
||||
|
||||
export interface ZipSearchParams extends PageableParams {
|
||||
zoneNo?: string; // 구역번호
|
||||
ctpvNm?: string; // 시도명
|
||||
sggNm?: string; // 시군구명
|
||||
emdNm?: string; // 읍면동명
|
||||
roadNm?: string; // 도로명
|
||||
stdgNm?: string; // 법정동명
|
||||
dongNm?: string; // 행정동명
|
||||
bldgNoMno?: number | null; // 빌딩본번
|
||||
bldgNoSno?: number | null; // 빌딩딩부번
|
||||
lotnoMno?: number | null; // 지번본번
|
||||
lotnoSno?: number | null; // 지번부번
|
||||
}
|
||||
|
||||
export interface Zip {
|
||||
zipId: number;
|
||||
zoneNo: string;
|
||||
ctpvNm: string;
|
||||
sggNm: string;
|
||||
emdNm: string;
|
||||
roadNm: string;
|
||||
bldgNoMno: number;
|
||||
bldgNoSno: number;
|
||||
lotnoMno: number;
|
||||
lotnoSno: number;
|
||||
lotno: string;
|
||||
zipAddr: string;
|
||||
}
|
||||
|
||||
export type ZipList = PageableList<Zip>;
|
||||
@@ -119,7 +119,6 @@ export function UiTable({
|
||||
};
|
||||
|
||||
const leafCols = getLeafCols(headlist);
|
||||
|
||||
return (
|
||||
<>
|
||||
{headName ? (
|
||||
@@ -263,7 +262,11 @@ export function UiTable({
|
||||
<TableCell
|
||||
colSpan={
|
||||
headlist.filter((item) => item.visible != false).length -
|
||||
headlist.filter((item) => item.visible != false && item.colSpan).length
|
||||
headlist.filter(
|
||||
(item) =>
|
||||
item.visible != false &&
|
||||
(item.colSpan || ["A", "B", "C"].includes(item.id)),
|
||||
).length
|
||||
}
|
||||
className="h-24 text-center text-gray-500"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user