Merge remote-tracking branch 'origin/main' into iipbs/sn/dev
@@ -52,9 +52,9 @@ const LinkForm = ({ form, linkSn, updateLinkInfo, handleInsertLink, deleteLink,
|
|||||||
if (await confirm(confirmMsg)) {
|
if (await confirm(confirmMsg)) {
|
||||||
if (linkSn) {
|
if (linkSn) {
|
||||||
updateLinkInfo?.(data);
|
updateLinkInfo?.(data);
|
||||||
} else {
|
} else {
|
||||||
handleInsertLink?.(data);
|
handleInsertLink?.(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ function LinkParamsPage() {
|
|||||||
const userUniqId = getCookie(AUTH_USER_ID) ?? "";
|
const userUniqId = getCookie(AUTH_USER_ID) ?? "";
|
||||||
const { setMessage: alert } = useAlertStore((state) => state);
|
const { setMessage: alert } = useAlertStore((state) => state);
|
||||||
|
|
||||||
const dbIdList = ['link0001', 'link0002'];
|
const dbIdList = ['link0001', 'link0002', 'link0007'];
|
||||||
|
|
||||||
// Link 목록 쿼리
|
// Link 목록 쿼리
|
||||||
const query = useQuery({
|
const query = useQuery({
|
||||||
|
|||||||
@@ -233,6 +233,7 @@ const Map = () => {
|
|||||||
<>
|
<>
|
||||||
<div className="bg-container">
|
<div className="bg-container">
|
||||||
<Gis
|
<Gis
|
||||||
|
height='h-screen'
|
||||||
treeData={treeData}
|
treeData={treeData}
|
||||||
isSearch={false}
|
isSearch={false}
|
||||||
gisMaps={gisMaps}
|
gisMaps={gisMaps}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { useDmStore } from "@/app/store";
|
import { useDmStore } from "@/app/store";
|
||||||
import {
|
import {
|
||||||
SearchDiv,
|
|
||||||
SearchFormLeft,
|
|
||||||
SelectBox,
|
SelectBox,
|
||||||
type SelectDataType,
|
type SelectDataType,
|
||||||
} from "@common/business_components/ui";
|
} from "@common/business_components/ui";
|
||||||
@@ -48,6 +46,7 @@ export function SearchBar({
|
|||||||
},
|
},
|
||||||
[Common.selectSigunData]
|
[Common.selectSigunData]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onSelectValue = useCallback(
|
const onSelectValue = useCallback(
|
||||||
(val: string, type: string) => {
|
(val: string, type: string) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -62,78 +61,58 @@ export function SearchBar({
|
|||||||
[initializeSigunData]
|
[initializeSigunData]
|
||||||
);
|
);
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// console.log("map.ruseFcltList ", map.ruseFcltList);
|
|
||||||
// }, [map.ruseFcltList]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="flex justify-center w-full px-4 py-3">
|
||||||
<div className="grid grid-cols-4 gap-4 ">
|
<div className="flex items-center w-full max-w-screen-lg rounded-xl bg-white shadow-md px-6 py-4 space-x-3">
|
||||||
<div className="col-span-4">
|
<SelectBox
|
||||||
<SearchDiv>
|
labelClass="w-[40px]"
|
||||||
<SearchFormLeft>
|
className="w-[200px]"
|
||||||
<div className="col-span-10 flex flex-row">
|
label="시도"
|
||||||
<SelectBox
|
selectClass="rounded-lg bg-white"
|
||||||
className="col-span-2 w-1/6 h-full text-2xl"
|
selectArray={Common.selectSidoData || []}
|
||||||
label="시도"
|
onSelectValue={(val) => onSelectValue(val.toString(), "ctpvCd")}
|
||||||
selectClass={""}
|
value={sidoValue || Common.selectSidoData[0]?.val || ""}
|
||||||
selectArray={Common.selectSidoData || []}
|
/>
|
||||||
onSelectValue={(val) =>
|
<SelectBox
|
||||||
onSelectValue(val.toString(), "ctpvCd")
|
labelClass="w-[65px]"
|
||||||
}
|
className="w-[200px]"
|
||||||
value={sidoValue || Common.selectSidoData[0]?.val || ""}
|
label="시군구"
|
||||||
/>
|
selectClass="rounded-lg bg-white"
|
||||||
<SelectBox
|
selectArray={filteredSigunData || []}
|
||||||
className="col-span-2 w-1/6 h-full text-2xl ml-10"
|
onSelectValue={(val) => onSelectValue(val.toString(), "sggCd")}
|
||||||
label="시군구"
|
value={sigunValue}
|
||||||
selectClass={""}
|
/>
|
||||||
selectArray={filteredSigunData || []}
|
<Label className="text-gray-600">하수재이용시설</Label>
|
||||||
onSelectValue={(val) =>
|
<SearchInputText
|
||||||
onSelectValue(val.toString(), "sggCd")
|
label="시설명"
|
||||||
}
|
initValue={undefined}
|
||||||
value={sigunValue}
|
setValue={(searchNm?: string) => {
|
||||||
/>
|
let sggOrCity = "";
|
||||||
<div className="col-span-6 flex flex-row items-center min-w-[27rem] ml-10">
|
if (searchNm) {
|
||||||
<Label className="text-xl justify-self-center mt-2 mx-3">
|
if (sigunValue === "0" || sigunValue === "") {
|
||||||
하수재이용시설
|
sggOrCity = sidoValue;
|
||||||
</Label>
|
} else {
|
||||||
<SearchInputText
|
sggOrCity = sigunValue;
|
||||||
label={"시설명"}
|
}
|
||||||
initValue={undefined}
|
findRuseFclt(sggOrCity, searchNm);
|
||||||
setValue={(searchNm?: string) => {
|
}
|
||||||
let sggOrCity = "";
|
}}
|
||||||
if (searchNm) {
|
setRtnData={(rtnData: any) => {
|
||||||
if (sigunValue === "0" || sigunValue === "") {
|
setHasuPk(rtnData);
|
||||||
sggOrCity = sidoValue;
|
}}
|
||||||
} else {
|
searchList={map.ruseFcltList || []}
|
||||||
sggOrCity = sigunValue;
|
/>
|
||||||
}
|
<Button
|
||||||
findRuseFclt(sggOrCity, searchNm);
|
color="sky"
|
||||||
}
|
className="ml-2 text-white"
|
||||||
}}
|
size="sm"
|
||||||
setRtnData={(rtnData: any) => {
|
onClick={() => {
|
||||||
setHasuPk(rtnData);
|
onApply();
|
||||||
}}
|
}}
|
||||||
searchList={map.ruseFcltList || []}
|
>
|
||||||
/>
|
적용
|
||||||
</div>
|
</Button>
|
||||||
<div className="flex flex-row space-x-2">
|
|
||||||
<Button
|
|
||||||
color="sky"
|
|
||||||
className="mt-2"
|
|
||||||
size={"sm"}
|
|
||||||
onClick={() => {
|
|
||||||
onApply();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
적용
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</SearchFormLeft>
|
|
||||||
</SearchDiv>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 919 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 810 B |
|
Before Width: | Height: | Size: 1016 B After Width: | Height: | Size: 896 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 837 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 790 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 855 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 923 B |
@@ -2,6 +2,7 @@ NEXT_PUBLIC_SITE_ID = FO
|
|||||||
NEXT_PUBLIC_PORT = 11300
|
NEXT_PUBLIC_PORT = 11300
|
||||||
NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11300
|
NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11300
|
||||||
NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
|
NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
|
||||||
|
#NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||||
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
|
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
|
||||||
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||||
NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
|
NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
NEXT_PUBLIC_SITE_ID = FO
|
NEXT_PUBLIC_SITE_ID = FO
|
||||||
NEXT_PUBLIC_PORT = 3000
|
NEXT_PUBLIC_PORT = 3000
|
||||||
NEXT_PUBLIC_PROXY_HOST = http://localhost:3000
|
NEXT_PUBLIC_PROXY_HOST = http://localhost:3000
|
||||||
NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
|
NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
|
||||||
|
#NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||||
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
|
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
|
||||||
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||||
NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
|
NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ NEXT_PUBLIC_SITE_ID = FO
|
|||||||
NEXT_PUBLIC_PORT = 11300
|
NEXT_PUBLIC_PORT = 11300
|
||||||
NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11300
|
NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11300
|
||||||
NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
|
NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
|
||||||
|
#NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||||
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
|
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
|
||||||
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||||
NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
|
NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import Gis from "@common/business_components/ui/map/Gis";
|
import Gis from "@common/business_components/ui/map/Gis";
|
||||||
import GisApp from "@common/business_components/ui/map/lib/gis.core";
|
import GisApp from "@common/business_components/ui/map/lib/gis.core";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
import { SearchBar } from "./searchBar/searchBar";
|
||||||
|
|
||||||
interface FeatureData {
|
interface FeatureData {
|
||||||
fid?: string;
|
fid?: string;
|
||||||
@@ -123,24 +124,15 @@ const Map = () => {
|
|||||||
setIsSearchModalOpen(false);
|
setIsSearchModalOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
// onCheckedLayersChange handler
|
|
||||||
const handleCheckedLayersChange = (
|
|
||||||
checkedIds: string[],
|
|
||||||
checkedNodesData: unknown[]
|
|
||||||
) => {
|
|
||||||
// Handle checked layers change if needed
|
|
||||||
console.log("Checked layers changed:", checkedIds, checkedNodesData);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-container">
|
<div className="bg-container">
|
||||||
<Gis
|
<Gis
|
||||||
treeData={treeData}
|
treeData={treeData}
|
||||||
isSearch={false}
|
isSearch={false}
|
||||||
gisMaps={gisMaps}
|
gisMaps={gisMaps}
|
||||||
isMiniMap={true}
|
isMiniMap={false}
|
||||||
searchView={null}
|
searchView={undefined}
|
||||||
detailView={null}
|
detailView={undefined}
|
||||||
onFeatureSelect={onFeatureSelect}
|
onFeatureSelect={onFeatureSelect}
|
||||||
setIsOpen={setIsOpen}
|
setIsOpen={setIsOpen}
|
||||||
setFeatureData={setFeatureData}
|
setFeatureData={setFeatureData}
|
||||||
@@ -148,9 +140,9 @@ const Map = () => {
|
|||||||
setIsSearchModalOpen={setIsSearchModalOpen}
|
setIsSearchModalOpen={setIsSearchModalOpen}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
isSearchModalOpen={isSearchModalOpen}
|
isSearchModalOpen={isSearchModalOpen}
|
||||||
onCheckedLayersChange={handleCheckedLayersChange}
|
onCheckedLayersChange={undefined}
|
||||||
imgVisble={false}
|
imgVisble={false}
|
||||||
searchBar={undefined}
|
searchBar={(props:any) => <SearchBar onFeatureSelect={onFeatureSelect} gisMaps={gisMaps} />}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
"use client";
|
||||||
|
import { SelectBox, type SelectDataType } from "@common/business_components/ui";
|
||||||
|
import { Button } from "@common/components/ui";
|
||||||
|
import { useCallback, useEffect, useState } from "react";
|
||||||
|
import { GEOSERVER_URL } from "@/src/shared/config/env";
|
||||||
|
|
||||||
|
interface SearchBarProps {
|
||||||
|
onFeatureSelect: (feature: any) => void;
|
||||||
|
gisMaps: React.RefObject<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SearchBar({ onFeatureSelect, gisMaps }: SearchBarProps) {
|
||||||
|
const [sidoValue, setSidoValue] = useState("0");
|
||||||
|
const [sigunValue, setSigunValue] = useState("0");
|
||||||
|
const [sidoData, setSidoData] = useState<SelectDataType[]>([{ text: "선택", val: "0" }]);
|
||||||
|
const [sigunData, setSigunData] = useState<SelectDataType[]>([{ text: "선택", val: "0" }]);
|
||||||
|
const [filteredSigunData, setFilteredSigunData] = useState<SelectDataType[]>([{ text: "선택", val: "0" }]);
|
||||||
|
const [facilityData, setFacilityData] = useState<SelectDataType[]>([{ text: "선택", val: "0" }]);
|
||||||
|
const [facilityValue, setFacilityValue] = useState("0");
|
||||||
|
|
||||||
|
const fetchSido = async () => {
|
||||||
|
const url = `/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo:tb_ms_ctpv&outputFormat=application/json&propertyName=mctpv_korn_nm,mctpv_cd`;
|
||||||
|
const res = await fetch(url);
|
||||||
|
const json = await res.json();
|
||||||
|
|
||||||
|
const list = json.features.map((f: any) => ({
|
||||||
|
text: f.properties.mctpv_korn_nm,
|
||||||
|
val: f.properties.mctpv_cd,
|
||||||
|
}));
|
||||||
|
setSidoData([{ text: "선택", val: "0" }, ...list]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchSigun = async () => {
|
||||||
|
const url = `/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo:tb_ms_sgg&outputFormat=application/json&propertyName=sgg_cd,sgg_korn_nm`;
|
||||||
|
const res = await fetch(url);
|
||||||
|
const json = await res.json();
|
||||||
|
|
||||||
|
const list = json.features.map((f: any) => ({
|
||||||
|
text: f.properties.sgg_korn_nm,
|
||||||
|
val: f.properties.sgg_cd,
|
||||||
|
}));
|
||||||
|
setSigunData(list);
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchFacilitiesBySggNm = async (sggNm: string) => {
|
||||||
|
const encodedSggNm = encodeURIComponent(sggNm);
|
||||||
|
const url = `/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=hasudo:tb_il_swage_prcs_fclt&outputFormat=application/json&cql_filter=sgg_nm='${encodedSggNm}'`;
|
||||||
|
const res = await fetch(url);
|
||||||
|
const json = await res.json();
|
||||||
|
|
||||||
|
const list = json.features.map((f: any) => ({
|
||||||
|
text: f.properties.swtrmt_fclt_nm ?? "(이름없음)",
|
||||||
|
val: f.id, // f.properties.swtrmt_fclt_cd 도 가능
|
||||||
|
}));
|
||||||
|
setFacilityData([{ text: "선택", val: "0" }, ...list]);
|
||||||
|
setFacilityValue("0");
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchSido();
|
||||||
|
fetchSigun();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const initializeSigunData = useCallback(
|
||||||
|
(sidoCd: string) => {
|
||||||
|
if (sidoCd === "0") {
|
||||||
|
setFilteredSigunData([{ text: "선택", val: "0" }]);
|
||||||
|
setSigunValue("0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const prefix = sidoCd.substring(0, 2);
|
||||||
|
const filtered = sigunData.filter((item) => item.val.startsWith(prefix));
|
||||||
|
setFilteredSigunData([{ text: "선택", val: "0" }, ...filtered]);
|
||||||
|
setSigunValue("0");
|
||||||
|
},
|
||||||
|
[sigunData]
|
||||||
|
);
|
||||||
|
|
||||||
|
const onSelectValue = useCallback(
|
||||||
|
(val: string, type: string) => {
|
||||||
|
if (type === "ctpvCd") {
|
||||||
|
setSidoValue(val);
|
||||||
|
initializeSigunData(val);
|
||||||
|
setFacilityData([{ text: "선택", val: "0" }]);
|
||||||
|
} else if (type === "sggCd") {
|
||||||
|
setSigunValue(val);
|
||||||
|
const sggNm = sigunData.find((item) => item.val === val)?.text || "";
|
||||||
|
if (sggNm) fetchFacilitiesBySggNm(sggNm);
|
||||||
|
} else if (type === "fcltCd") {
|
||||||
|
setFacilityValue(val);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[initializeSigunData, sigunData]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleSearch = () => {
|
||||||
|
if (!gisMaps.current || facilityValue === "0") return;
|
||||||
|
|
||||||
|
const layers = gisMaps.current.getLayers().getArray();
|
||||||
|
for (const layer of layers) {
|
||||||
|
const source = layer.getSource?.();
|
||||||
|
const feature = source?.getFeatureById?.(facilityValue);
|
||||||
|
if (feature) {
|
||||||
|
onFeatureSelect(feature);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
alert("해당 처리시설을 지도에서 찾을 수 없습니다.");
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="grid grid-cols-4 gap-4">
|
||||||
|
<div className="col-span-4">
|
||||||
|
<div className="card card-border flex">
|
||||||
|
<div className="col-span-10 flex flex-row">
|
||||||
|
<SelectBox
|
||||||
|
labelClass="w-[40px]"
|
||||||
|
className="mr-10 w-[200px]"
|
||||||
|
selectClass="rounded-lg bg-white"
|
||||||
|
label="시도"
|
||||||
|
selectArray={sidoData}
|
||||||
|
onSelectValue={(val) => onSelectValue(val.toString(), "ctpvCd")}
|
||||||
|
value={sidoValue}
|
||||||
|
/>
|
||||||
|
<SelectBox
|
||||||
|
labelClass="w-[65px]"
|
||||||
|
className="mr-10 w-[200px]"
|
||||||
|
selectClass="rounded-lg bg-white"
|
||||||
|
label="시군구"
|
||||||
|
selectArray={filteredSigunData}
|
||||||
|
onSelectValue={(val) => onSelectValue(val.toString(), "sggCd")}
|
||||||
|
value={sigunValue}
|
||||||
|
/>
|
||||||
|
<SelectBox
|
||||||
|
labelClass="w-[140px]"
|
||||||
|
className="mr-3 w-[250px]"
|
||||||
|
selectClass="rounded-lg bg-white"
|
||||||
|
label="하수처리시설"
|
||||||
|
selectArray={facilityData}
|
||||||
|
onSelectValue={(val) => onSelectValue(val.toString(), "fcltCd")}
|
||||||
|
value={facilityValue}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row space-x-2">
|
||||||
|
<Button
|
||||||
|
color="primary"
|
||||||
|
className="mx-2 mt-1 ml-10"
|
||||||
|
size={"sm"}
|
||||||
|
onClick={handleSearch}
|
||||||
|
>
|
||||||
|
조회
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 919 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 810 B |
|
Before Width: | Height: | Size: 1016 B After Width: | Height: | Size: 896 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 837 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 790 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 855 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 923 B |
@@ -2,8 +2,7 @@ export const SITE_ID = process.env.NEXT_PUBLIC_SITE_ID || "FO";
|
|||||||
export const PORT = process.env.NEXT_PUBLIC_PORT || "3000";
|
export const PORT = process.env.NEXT_PUBLIC_PORT || "3000";
|
||||||
export const PROXY_HOST = process.env.NEXT_PUBLIC_PROXY_HOST || `http://localhost:${PORT}`;
|
export const PROXY_HOST = process.env.NEXT_PUBLIC_PROXY_HOST || `http://localhost:${PORT}`;
|
||||||
export const SERVER_API_WR_URL = process.env.NEXT_PUBLIC_WR_SERVER_API_URL ||'http://con.mind-one.co.kr:11080/api/v1';
|
export const SERVER_API_WR_URL = process.env.NEXT_PUBLIC_WR_SERVER_API_URL ||'http://con.mind-one.co.kr:11080/api/v1';
|
||||||
//export const SERVER_API_URL = process.env.NEXT_PUBLIC_SERVER_API_URL||' http://con.mind-one.co.kr:11082/api/v1';
|
export const SERVER_API_URL = process.env.NEXT_PUBLIC_SERVER_API_URL||' http://con.mind-one.co.kr:11082/api/v1';
|
||||||
export const SERVER_API_URL = process.env.NEXT_PUBLIC_CS_SERVER_API_URL||' http://con.mind-one.co.kr:11082/api/v1';
|
|
||||||
export const SERVER_API_CS_URL = process.env.NEXT_PUBLIC_CS_SERVER_API_URL||'http://dev.onasys.co.kr:8000';
|
export const SERVER_API_CS_URL = process.env.NEXT_PUBLIC_CS_SERVER_API_URL||'http://dev.onasys.co.kr:8000';
|
||||||
export const CLAIM_NAME = process.env.NEXT_PUBLIC_CLAIM_NAME || "Authorization";
|
export const CLAIM_NAME = process.env.NEXT_PUBLIC_CLAIM_NAME || "Authorization";
|
||||||
export const ACCESS_TOKEN = process.env.NEXT_PUBLIC_ACCESS_TOKEN || "access-token";
|
export const ACCESS_TOKEN = process.env.NEXT_PUBLIC_ACCESS_TOKEN || "access-token";
|
||||||
|
|||||||
|
After Width: | Height: | Size: 919 B |
|
After Width: | Height: | Size: 810 B |
|
After Width: | Height: | Size: 896 B |
|
After Width: | Height: | Size: 837 B |
|
After Width: | Height: | Size: 790 B |
|
After Width: | Height: | Size: 855 B |
|
After Width: | Height: | Size: 923 B |
@@ -10,6 +10,8 @@ NEXT_PUBLIC_CLAIM_NAME = Authorization
|
|||||||
NEXT_PUBLIC_AUTH_USER_ID = token-id
|
NEXT_PUBLIC_AUTH_USER_ID = token-id
|
||||||
NEXT_PUBLIC_ACCESS_TOKEN = access-token
|
NEXT_PUBLIC_ACCESS_TOKEN = access-token
|
||||||
NEXT_PUBLIC_REFRESH_TOKEN = refresh-token
|
NEXT_PUBLIC_REFRESH_TOKEN = refresh-token
|
||||||
|
NEXT_PUBLIC_GEOSERVER_URL = http://rsone.iptime.org:10010/geoserver
|
||||||
|
NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { useEffect, useRef, useState, useCallback } from "react";
|
|||||||
import { mapService } from "../service";
|
import { mapService } from "../service";
|
||||||
import NewWindowPopup from "../newWindowPopup";
|
import NewWindowPopup from "../newWindowPopup";
|
||||||
import GisApp from "@common/business_components/ui/map/lib/gis.core";
|
import GisApp from "@common/business_components/ui/map/lib/gis.core";
|
||||||
|
import { SearchBar } from "../searchBar/searchBar";
|
||||||
|
|
||||||
const Map = () => {
|
const Map = () => {
|
||||||
const [treeData, setTreeData] = useState([]); // 초기값을 객체 또는 null로 설정
|
const [treeData, setTreeData] = useState([]); // 초기값을 객체 또는 null로 설정
|
||||||
@@ -61,24 +62,28 @@ const Map = () => {
|
|||||||
|
|
||||||
// 2. data가 OpenLayers Feature 인스턴스인지 확인
|
// 2. data가 OpenLayers Feature 인스턴스인지 확인
|
||||||
let foundFeature: any = null;
|
let foundFeature: any = null;
|
||||||
console.log(data)
|
console.log(data);
|
||||||
//console.log(data.getId())
|
//console.log(data.getId())
|
||||||
let featureId = data.fid;
|
let featureId = data.fid;
|
||||||
const layerName = data.layerNm;
|
const layerName = data.layerNm;
|
||||||
|
|
||||||
if (layerName === "재이용시설") {
|
if (layerName === "재이용시설") {
|
||||||
// 재이용시설
|
// 재이용시설
|
||||||
featureId = `${layerName}.${data.searchPk}`;
|
featureId = `${layerName}.${data.searchPk}`;
|
||||||
} else if ( //빗물이용시설, 중수도시설
|
} else if (
|
||||||
|
//빗물이용시설, 중수도시설
|
||||||
layerName === "빗물이용시설" ||
|
layerName === "빗물이용시설" ||
|
||||||
layerName == "tb_wr_rswtr_fclt"
|
layerName == "tb_wr_rswtr_fclt"
|
||||||
) {
|
) {
|
||||||
featureId = `${layerName}.${data.bdstInfoSn}`;
|
featureId = `${layerName}.${data.bdstInfoSn}`;
|
||||||
} else if (layerName === "tb_il_swage_prcs_fclt") { //하수처리시설
|
} else if (layerName === "tb_il_swage_prcs_fclt") {
|
||||||
|
//하수처리시설
|
||||||
featureId = `${layerName}.${data.bscFctCd}`;
|
featureId = `${layerName}.${data.bscFctCd}`;
|
||||||
} else if (layerName === "tb_wr_htdfl_fclt") { //온배수시설
|
} else if (layerName === "tb_wr_htdfl_fclt") {
|
||||||
|
//온배수시설
|
||||||
featureId = `${layerName}.${data.bdstRuseFcltSn}`;
|
featureId = `${layerName}.${data.bdstRuseFcltSn}`;
|
||||||
} else if (layerName == "tb_wr_ruse_fclt_dmd_co") { //수요처
|
} else if (layerName == "tb_wr_ruse_fclt_dmd_co") {
|
||||||
|
//수요처
|
||||||
featureId = `${layerName}.${data.dmdInfoId.replaceAll("-", "")}`;
|
featureId = `${layerName}.${data.dmdInfoId.replaceAll("-", "")}`;
|
||||||
} else {
|
} else {
|
||||||
console.warn("해당 레이어에 대한 featureId 매핑 없음", layerName);
|
console.warn("해당 레이어에 대한 featureId 매핑 없음", layerName);
|
||||||
@@ -120,17 +125,6 @@ const Map = () => {
|
|||||||
setIsSearchModalOpen(false);
|
setIsSearchModalOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
// MapSearchBar 래퍼 컴포넌트
|
|
||||||
// const CustomMapSearchBar = (props: any) => {
|
|
||||||
// return (
|
|
||||||
// <MapSearchBar
|
|
||||||
// {...props}
|
|
||||||
// searchType="공급처 후보지 조회"
|
|
||||||
// showApplyButton={false}
|
|
||||||
// />
|
|
||||||
// );
|
|
||||||
// };
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-container">
|
<div className="bg-container">
|
||||||
<Gis
|
<Gis
|
||||||
@@ -156,7 +150,24 @@ const Map = () => {
|
|||||||
isSearchModalOpen={isSearchModalOpen}
|
isSearchModalOpen={isSearchModalOpen}
|
||||||
onCheckedLayersChange={handleCheckedLayersChange}
|
onCheckedLayersChange={handleCheckedLayersChange}
|
||||||
imgVisble={true}
|
imgVisble={true}
|
||||||
searchBar={undefined}
|
searchBar={(props: any) => {
|
||||||
|
const facilityTypes = [
|
||||||
|
{ text: "하수처리시설", val: "tb_il_swage_prcs_fclt" },
|
||||||
|
{ text: "하수재이용시설", val: "tb_wr_bdst_ruse_fclt" },
|
||||||
|
{ text: "빗물이용시설", val: "tb_wr_rnwtr_utztn_fclt" },
|
||||||
|
{ text: "중수도시설", val: "tb_wr_rswtr_fclt" },
|
||||||
|
{ text: "온배수시설", val: "tb_wr_htdfl_fclt" },
|
||||||
|
{ text: "수요처", val: "tb_wr_ruse_fclt_dmd_co" },
|
||||||
|
{ text: "잠재수요처", val: "tb_wr_tmpr_dmd_co" },
|
||||||
|
];
|
||||||
|
return (
|
||||||
|
<SearchBar
|
||||||
|
onFeatureSelect={onFeatureSelect}
|
||||||
|
gisMaps={gisMaps}
|
||||||
|
facilityTypes={facilityTypes}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,299 @@
|
|||||||
|
"use client";
|
||||||
|
import { SelectBox, type SelectDataType } from "@common/business_components/ui";
|
||||||
|
import { Button } from "@common/components/ui";
|
||||||
|
import { useCallback, useEffect, useState } from "react";
|
||||||
|
import { SERVER_API_WR_URL } from "@/src/shared/config";
|
||||||
|
|
||||||
|
const geoserverUrl =
|
||||||
|
"/geoserver/hasudo/ows?service=WFS&version=1.0.0&request=GetFeature&outputFormat=application/json";
|
||||||
|
|
||||||
|
const FACILITY_TYPE_URL_MAP: Record<string, string> = {
|
||||||
|
tb_il_swage_prcs_fclt: geoserverUrl, //하수처리시설
|
||||||
|
tb_wr_bdst_ruse_fclt:
|
||||||
|
"/reuse-service/reuseFc/pubDetailList/{year}/{sggCd}/1/1000", //재이용시설 post
|
||||||
|
tb_wr_rnwtr_utztn_fclt: "/reuse-service/reuseFc/rainyInfoList/1/1000/{sggCd}", //빗물이용시설 get
|
||||||
|
tb_wr_rswtr_fclt: "/reuse-service/reuseFc/waterreuseFc/1/1000/{sggCd}", //중수도시설 get
|
||||||
|
tb_wr_htdfl_fclt: "/reuse-service/drain/facilityList/1/1000/{sggCd}", //온배수시설 get
|
||||||
|
tb_wr_ruse_fclt_dmd_co: "/reuse-service/reuseFc/request/1/1000/{sggCd}", //수요처 get
|
||||||
|
tb_wr_tmpr_dmd_co:
|
||||||
|
"/reuse-service/reuseFc/request/temp/1/1000/{sidoNm} {sggNm}", //잠재수요처 get
|
||||||
|
};
|
||||||
|
|
||||||
|
interface SearchBarProps {
|
||||||
|
onFeatureSelect: (feature: any) => void;
|
||||||
|
gisMaps: React.RefObject<any>;
|
||||||
|
facilityTypes: { text: string; val: string }[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SearchBar({
|
||||||
|
onFeatureSelect,
|
||||||
|
gisMaps,
|
||||||
|
facilityTypes,
|
||||||
|
}: SearchBarProps) {
|
||||||
|
const [sidoValue, setSidoValue] = useState("0");
|
||||||
|
const [sigunValue, setSigunValue] = useState("0");
|
||||||
|
const [sidoData, setSidoData] = useState<SelectDataType[]>([
|
||||||
|
{ text: "선택", val: "0" },
|
||||||
|
]);
|
||||||
|
const [sigunData, setSigunData] = useState<SelectDataType[]>([
|
||||||
|
{ text: "선택", val: "0" },
|
||||||
|
]);
|
||||||
|
const [filteredSigunData, setFilteredSigunData] = useState<SelectDataType[]>([
|
||||||
|
{ text: "선택", val: "0" },
|
||||||
|
]);
|
||||||
|
|
||||||
|
const [facilityData, setFacilityData] = useState<SelectDataType[]>([
|
||||||
|
{ text: "선택", val: "0" },
|
||||||
|
]);
|
||||||
|
const [facilityValue, setFacilityValue] = useState("0");
|
||||||
|
|
||||||
|
const [facilityType, setFacilityType] = useState(
|
||||||
|
facilityTypes?.length === 1 && facilityTypes[0] ? facilityTypes[0].val : "0"
|
||||||
|
);
|
||||||
|
|
||||||
|
//시도, 시군구 조회
|
||||||
|
const fetchSido = async () => {
|
||||||
|
const url = `/cms-service/api/v1/code/cache/ADSTDSTRCD/Y`;
|
||||||
|
const res = await fetch(url);
|
||||||
|
const json = await res.json();
|
||||||
|
const sidoList = json
|
||||||
|
.filter(
|
||||||
|
(item: any) =>
|
||||||
|
typeof item.lwpoCd === "string" && item.lwpoCd.length === 2
|
||||||
|
)
|
||||||
|
.map((feature: any) => ({
|
||||||
|
val: feature.lwpoCd,
|
||||||
|
text: feature.lwpoCdNm,
|
||||||
|
}));
|
||||||
|
setSidoData([{ text: "선택", val: "0" }, ...sidoList]);
|
||||||
|
|
||||||
|
const sigunList = json
|
||||||
|
.filter(
|
||||||
|
(item: any) =>
|
||||||
|
typeof item.lwpoCd === "string" && item.lwpoCd.length !== 2
|
||||||
|
)
|
||||||
|
.map((feature: any) => ({
|
||||||
|
val: feature.lwpoCd,
|
||||||
|
text: feature.lwpoCdNm,
|
||||||
|
}));
|
||||||
|
setSigunData(sigunList);
|
||||||
|
};
|
||||||
|
|
||||||
|
//시설명 콤보박스 조회
|
||||||
|
const fetchFacilitiesBySggNm = async (
|
||||||
|
sggCd: string,
|
||||||
|
sggNm: string,
|
||||||
|
sidoNm: string,
|
||||||
|
currentFacilityType?: string
|
||||||
|
) => {
|
||||||
|
const type = currentFacilityType ?? facilityType;
|
||||||
|
if (!type || type === "0") return;
|
||||||
|
|
||||||
|
const baseUrlTemplate = FACILITY_TYPE_URL_MAP[type];
|
||||||
|
if (!baseUrlTemplate) return;
|
||||||
|
|
||||||
|
const year = new Date().getFullYear().toString();
|
||||||
|
let url = baseUrlTemplate
|
||||||
|
.replace("{year}", year)
|
||||||
|
.replace("{sggCd}", sggCd)
|
||||||
|
.replace("{sidoNm}", encodeURIComponent(sidoNm))
|
||||||
|
.replace("{sggNm}", encodeURIComponent(sggNm));
|
||||||
|
|
||||||
|
let list: SelectDataType[] = [];
|
||||||
|
|
||||||
|
if (
|
||||||
|
type === "tb_il_swage_prcs_fclt" //하수처리시설
|
||||||
|
) {
|
||||||
|
const cqlFilter = `ctpv_nm='${encodeURIComponent(sidoNm)}' AND sgg_nm='${encodeURIComponent(sggNm)}'`;
|
||||||
|
url = `${url}&typeName=hasudo:${type}&cql_filter=${cqlFilter}`;
|
||||||
|
const res = await fetch(url);
|
||||||
|
const json = await res.json();
|
||||||
|
list = json.features.map((f: any) => ({
|
||||||
|
text: f.properties.swtrmt_fclt_nm ?? "(이름없음)",
|
||||||
|
val: f.id,
|
||||||
|
}));
|
||||||
|
} else if (
|
||||||
|
type === "tb_wr_bdst_ruse_fclt" // 재이용시설
|
||||||
|
) {
|
||||||
|
//재용에서 참조하는 하수처리시설 목록
|
||||||
|
const paramsRes = await fetch("/reuse-service/reuseFc/pubFc");
|
||||||
|
const paramsJson = await paramsRes.json();
|
||||||
|
const params = paramsJson.data;
|
||||||
|
|
||||||
|
const res = await fetch(url, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
accept: "application/json",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(params),
|
||||||
|
});
|
||||||
|
const json = await res.json();
|
||||||
|
list = (json.data || []).map((item: any) => ({
|
||||||
|
text: item.ruseUtztnFcltNm ?? "(이름없음)",
|
||||||
|
val: item.pbnstRuseFcltId,
|
||||||
|
}));
|
||||||
|
} else if (
|
||||||
|
type === "tb_wr_ruse_fclt_dmd_co" //수요처
|
||||||
|
) {
|
||||||
|
const res = await fetch(url);
|
||||||
|
const json = await res.json();
|
||||||
|
list = (json.data || []).map((item: any) => ({
|
||||||
|
text: item.dmdCoNm ?? "(이름없음)",
|
||||||
|
val: item.dmdInfoId,
|
||||||
|
}));
|
||||||
|
} else if (
|
||||||
|
type === "tb_wr_tmpr_dmd_co" //잠재수요처
|
||||||
|
) {
|
||||||
|
// GET 방식
|
||||||
|
const res = await fetch(url);
|
||||||
|
const json = await res.json();
|
||||||
|
list = (json.data || []).map((item: any) => ({
|
||||||
|
text: item.dmdCoNm ?? "(이름없음)",
|
||||||
|
val: item.fctryMngSn,
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
// GET 방식
|
||||||
|
const res = await fetch(url);
|
||||||
|
const json = await res.json();
|
||||||
|
list = (json.data || []).map((item: any) => ({
|
||||||
|
text: item.bdstNm ?? "(이름없음)",
|
||||||
|
val: item.bdstInfoSn,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
setFacilityData([{ text: "선택", val: "0" }, ...list]);
|
||||||
|
setFacilityValue("0");
|
||||||
|
};
|
||||||
|
|
||||||
|
//시도, 시군구 초기 데이터 조회
|
||||||
|
useEffect(() => {
|
||||||
|
fetchSido();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
//시군구 데이터 초기화
|
||||||
|
const initializeSigunData = useCallback(
|
||||||
|
(sidoCd: string) => {
|
||||||
|
if (sidoCd === "0") {
|
||||||
|
setFilteredSigunData([{ text: "선택", val: "0" }]);
|
||||||
|
setSigunValue("0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const prefix = sidoCd.substring(0, 2);
|
||||||
|
const filtered = sigunData.filter((item) => item.val.startsWith(prefix));
|
||||||
|
setFilteredSigunData([{ text: "선택", val: "0" }, ...filtered]);
|
||||||
|
setSigunValue("0");
|
||||||
|
},
|
||||||
|
[sigunData]
|
||||||
|
);
|
||||||
|
|
||||||
|
//콤보박스 선택시 연관 콤보박스 처리
|
||||||
|
const onSelectValue = useCallback(
|
||||||
|
(val: string, type: string) => {
|
||||||
|
if (type === "ctpvCd") {
|
||||||
|
setSidoValue(val);
|
||||||
|
initializeSigunData(val);
|
||||||
|
setFacilityData([{ text: "선택", val: "0" }]);
|
||||||
|
setFacilityValue("0");
|
||||||
|
} else if (type === "sggCd") {
|
||||||
|
setSigunValue(val);
|
||||||
|
const sidoNm =
|
||||||
|
sidoData.find((item) => item.val === sidoValue)?.text || "";
|
||||||
|
const sggNm = sigunData.find((item) => item.val === val)?.text || "";
|
||||||
|
const sggCd = sigunData.find((item) => item.val === val)?.val || "";
|
||||||
|
if (sggNm && sidoNm)
|
||||||
|
fetchFacilitiesBySggNm(sggCd, sggNm, sidoNm, facilityType);
|
||||||
|
} else if (type === "facilityType") {
|
||||||
|
setFacilityType(val);
|
||||||
|
setFacilityValue("0");
|
||||||
|
setFacilityData([{ text: "선택", val: "0" }]);
|
||||||
|
const sidoNm =
|
||||||
|
sidoData.find((item) => item.val === sidoValue)?.text || "";
|
||||||
|
const sggNm =
|
||||||
|
sigunData.find((item) => item.val === sigunValue)?.text || "";
|
||||||
|
const sggCd =
|
||||||
|
sigunData.find((item) => item.val === sigunValue)?.val || "";
|
||||||
|
if (sggNm && sidoNm) fetchFacilitiesBySggNm(sggCd, sggNm, sidoNm, val);
|
||||||
|
} else if (type === "fcltCd") {
|
||||||
|
setFacilityValue(val);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[initializeSigunData, sigunData, sigunValue, sidoData, sidoValue]
|
||||||
|
);
|
||||||
|
|
||||||
|
//조회 버튼 클릭
|
||||||
|
const handleSearch = () => {
|
||||||
|
if (!gisMaps.current || facilityValue === "0") return;
|
||||||
|
const layers = gisMaps.current.getLayers().getArray();
|
||||||
|
for (const layer of layers) {
|
||||||
|
const source = layer.getSource?.();
|
||||||
|
const feature = source?.getFeatureById?.(facilityValue);
|
||||||
|
if (feature) {
|
||||||
|
onFeatureSelect(feature);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
alert("해당 처리시설을 지도에서 찾을 수 없습니다.");
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="grid grid-cols-4 gap-4">
|
||||||
|
<div className="col-span-4">
|
||||||
|
<div className="card card-border flex">
|
||||||
|
<div className="col-span-10 flex flex-row">
|
||||||
|
{facilityTypes.length > 1 && (
|
||||||
|
<SelectBox
|
||||||
|
labelClass="w-[120px]"
|
||||||
|
className="mr-10 w-[190px]"
|
||||||
|
selectClass="rounded-lg bg-white"
|
||||||
|
label="시설물유형"
|
||||||
|
selectArray={[{ text: "선택", val: "0" }, ...facilityTypes]}
|
||||||
|
onSelectValue={(val) =>
|
||||||
|
onSelectValue(val.toString(), "facilityType")
|
||||||
|
}
|
||||||
|
value={facilityType}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<SelectBox
|
||||||
|
labelClass="w-[40px]"
|
||||||
|
className="mr-10 w-[150px]"
|
||||||
|
selectClass="rounded-lg bg-white"
|
||||||
|
label="시도"
|
||||||
|
selectArray={sidoData}
|
||||||
|
onSelectValue={(val) => onSelectValue(val.toString(), "ctpvCd")}
|
||||||
|
value={sidoValue}
|
||||||
|
/>
|
||||||
|
<SelectBox
|
||||||
|
labelClass="w-[65px]"
|
||||||
|
className="mr-10 w-[150px]"
|
||||||
|
selectClass="rounded-lg bg-white"
|
||||||
|
label="시군구"
|
||||||
|
selectArray={filteredSigunData}
|
||||||
|
onSelectValue={(val) => onSelectValue(val.toString(), "sggCd")}
|
||||||
|
value={sigunValue}
|
||||||
|
/>
|
||||||
|
<SelectBox
|
||||||
|
labelClass="w-[60px]"
|
||||||
|
className="mr-3 w-[180px]"
|
||||||
|
selectClass="rounded-lg bg-white"
|
||||||
|
label="시설명"
|
||||||
|
selectArray={facilityData}
|
||||||
|
onSelectValue={(val) => onSelectValue(val.toString(), "fcltCd")}
|
||||||
|
value={facilityValue}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row space-x-2">
|
||||||
|
<Button
|
||||||
|
color="primary"
|
||||||
|
className="mx-2 mt-1 ml-5"
|
||||||
|
size={"sm"}
|
||||||
|
onClick={handleSearch}
|
||||||
|
>
|
||||||
|
조회
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -17,35 +17,45 @@ import {
|
|||||||
UiModal,
|
UiModal,
|
||||||
UiTable,
|
UiTable,
|
||||||
type SelectDataType,
|
type SelectDataType,
|
||||||
|
type SheetParameter,
|
||||||
} from "@common/business_components/ui";
|
} from "@common/business_components/ui";
|
||||||
import ListDiv from "@common/business_components/ui/list_div";
|
import ListDiv from "@common/business_components/ui/list_div";
|
||||||
import { Button } from "@common/components/ui";
|
import { Button, Label } from "@common/components/ui";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { Toaster } from "react-hot-toast";
|
import toast, { Toaster } from "react-hot-toast";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
export default function RuseCaseMng() {
|
export default function RuseCaseMng() {
|
||||||
const { code, ruseCaseMng, selectRuseCaseMng } = useWrStore((state) => state);
|
const { code, ruseCaseMng, selectRuseCaseMng, ruseCaseMngInit } = useWrStore((state) => state);
|
||||||
const { ruseCaseMngList, status, count } = ruseCaseMng;
|
const { ruseCaseMngList, status, count, excelList } = ruseCaseMng;
|
||||||
const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>([]);
|
const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>([]);
|
||||||
const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" });
|
const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" });
|
||||||
|
|
||||||
const [sidoCd, setSidoCd] = useState<string>("");
|
const [sidoCd, setSidoCd] = useState<string>("");
|
||||||
const [sigunguCd, setSigunguCd] = useState<string>("");
|
const [sigunguCd, setSigunguCd] = useState<string>("");
|
||||||
const [selectUtz, setSelectUtz] = useState<string[] | []>(["조경용수"]);
|
// const [selectUtz, setSelectUtz] = useState<string[] | []>(["조경용수"]);
|
||||||
|
const [selectUtz, setSelectUtz] = useState<string>("");
|
||||||
const [name, setName] = useState<string>("");
|
const [name, setName] = useState<string>("");
|
||||||
|
const [resetPage, isResetPage] = useState(false);
|
||||||
|
const { t } = useTranslation('base');
|
||||||
|
|
||||||
// 물재이용사례 조회
|
// 물재이용사례 조회
|
||||||
const searchRuseCaseMng = async (pageNo: number, pageSize: number) => {
|
const searchRuseCaseMng = async (isExcel: boolean, pageNo: number, pageSize: number) => {
|
||||||
await selectRuseCaseMng(
|
await selectRuseCaseMng(
|
||||||
|
isExcel,
|
||||||
pageNo,
|
pageNo,
|
||||||
pageSize,
|
pageSize,
|
||||||
sidoCd ?? "",
|
sidoCd ?? "",
|
||||||
sigunguCd ?? "",
|
sigunguCd ?? "",
|
||||||
selectUtz[0] ?? "",
|
selectUtz ?? "",
|
||||||
name ?? ""
|
name ?? ""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
ruseCaseMngInit();
|
||||||
|
}, [])
|
||||||
|
|
||||||
// 시도 선택
|
// 시도 선택
|
||||||
const getSelCity = (val: string | number) => {
|
const getSelCity = (val: string | number) => {
|
||||||
const cityValue = String(val);
|
const cityValue = String(val);
|
||||||
@@ -69,91 +79,97 @@ export default function RuseCaseMng() {
|
|||||||
isModal: boolean;
|
isModal: boolean;
|
||||||
}>({ isModal: false });
|
}>({ isModal: false });
|
||||||
|
|
||||||
// 다운로드
|
|
||||||
const download = () => {
|
useEffect(() => {
|
||||||
searchRuseCaseMng(1, 10000);;
|
|
||||||
|
if (excelList !== undefined && excelList.length === 0) {
|
||||||
|
toast.error(t('excelDownErrMsg'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
fetch(`/sample_ruseCaseMng.xlsx`, {}).then(async (response) => {
|
fetch(`/sample_ruseCaseMng.xlsx`, {}).then(async (response) => {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw Error(response.statusText);
|
throw Error(response.statusText);
|
||||||
}
|
}
|
||||||
// 받은 파일 바인너리 처리
|
// 받은 파일 바인너리 처리
|
||||||
const blobRet = await response.arrayBuffer();
|
const blobRet = await response.arrayBuffer();
|
||||||
|
if(excelList){
|
||||||
const excelData1 = ruseCaseMngList.map((item) => {
|
const excelData1 = excelList.map((item) => {
|
||||||
return [
|
return [
|
||||||
item.ruseBizNm,
|
item.ruseBizNm,
|
||||||
item.bizBgngDate,
|
item.bizBgngDate,
|
||||||
item.bizEndDate,
|
item.bizEndDate,
|
||||||
item.splyFcltKnd,
|
item.splyFcltKnd,
|
||||||
item.splyFcltNm,
|
item.splyFcltNm,
|
||||||
item.splyFcltCpct,
|
item.splyFcltCpct,
|
||||||
item.dmdFcltNm,
|
item.dmdFcltNm,
|
||||||
item.dmdFcltAddr,
|
item.dmdFcltAddr,
|
||||||
item.ruseFcltCpct,
|
item.ruseFcltCpct,
|
||||||
item.ruseFcltPplLen,
|
item.ruseFcltPplLen,
|
||||||
item.ruseFcltUsg,
|
item.ruseFcltUsg,
|
||||||
item.ruseFcltSplyCpct,
|
item.ruseFcltSplyCpct,
|
||||||
item.ruseFcltPrcsMsrc,
|
item.ruseFcltPrcsMsrc,
|
||||||
item.grnteWqUsg,
|
item.grnteWqUsg,
|
||||||
item.grnteWqGrssClfg,
|
item.grnteWqGrssClfg,
|
||||||
item.grnteWqCombResdch,
|
item.grnteWqCombResdch,
|
||||||
item.grnteWqTrbt,
|
item.grnteWqTrbt,
|
||||||
item.grnteWqBod,
|
item.grnteWqBod,
|
||||||
item.grnteWqSmll,
|
item.grnteWqSmll,
|
||||||
item.grnteWqCrmty,
|
item.grnteWqCrmty,
|
||||||
item.grnteWqTn,
|
item.grnteWqTn,
|
||||||
item.grnteWqTp,
|
item.grnteWqTp,
|
||||||
item.grnteWqPh,
|
item.grnteWqPh,
|
||||||
item.grnteWqClIonQnt,
|
item.grnteWqClIonQnt,
|
||||||
item.grnteWqCndctStat,
|
item.grnteWqCndctStat,
|
||||||
item.grnteWqRmrk,
|
item.grnteWqRmrk,
|
||||||
item.reqBizGrssCst,
|
item.reqBizGrssCst,
|
||||||
item.reqBizReuseFcltCst,
|
item.reqBizReuseFcltCst,
|
||||||
item.reqBizPplCst,
|
item.reqBizPplCst,
|
||||||
item.reqBizArchCst,
|
item.reqBizArchCst,
|
||||||
item.reqBizMchnCst,
|
item.reqBizMchnCst,
|
||||||
item.reqBizMtrngCst,
|
item.reqBizMtrngCst,
|
||||||
item.reqBizGisCst,
|
item.reqBizGisCst,
|
||||||
item.reqBizCctvCst,
|
item.reqBizCctvCst,
|
||||||
item.reqBizCmcnCst,
|
item.reqBizCmcnCst,
|
||||||
item.reqBizWstCst,
|
item.reqBizWstCst,
|
||||||
item.reqBizDesignCst,
|
item.reqBizDesignCst,
|
||||||
item.reqBizSpvsCst,
|
item.reqBizSpvsCst,
|
||||||
item.reqBizSbsdCst,
|
item.reqBizSbsdCst,
|
||||||
item.reqBizEtc,
|
item.reqBizEtc,
|
||||||
item.prcmPlanGrssCst,
|
item.prcmPlanGrssCst,
|
||||||
item.prcmPlanNlep,
|
item.prcmPlanNlep,
|
||||||
item.prcmPlanLcep,
|
item.prcmPlanLcep,
|
||||||
item.prcmPlanBrdnCst,
|
item.prcmPlanBrdnCst,
|
||||||
item.prcmPlanEcqrRt,
|
item.prcmPlanEcqrRt,
|
||||||
item.clclnGrssCst,
|
item.clclnGrssCst,
|
||||||
item.clclnNlep,
|
item.clclnNlep,
|
||||||
item.clclnLcep,
|
item.clclnLcep,
|
||||||
item.clclnBrdnCst,
|
item.clclnBrdnCst,
|
||||||
item.clclnEcqrRt,
|
item.clclnEcqrRt,
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
const sheetParameter = [
|
const sheetParameter: SheetParameter[] = [
|
||||||
{
|
{
|
||||||
data: excelData1,
|
data: excelData1,
|
||||||
headerNum: 2,
|
headerNum: 2,
|
||||||
headerRange: 'A1:AX1',
|
headerRange: 'A1:AX1',
|
||||||
sheetName: '물재이용사례',
|
sheetName: '물재이용사례',
|
||||||
startCol: 'A'
|
startCol: 'A'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// 버퍼에 있는 엑셀데이터 전달 후 json으로 변환
|
||||||
|
await filePickedBlobArray(blobRet, '물재이용사례현황', sheetParameter);
|
||||||
}
|
}
|
||||||
];
|
|
||||||
// 버퍼에 있는 엑셀데이터 전달 후 json으로 변환
|
|
||||||
await filePickedBlobArray(blobRet, '물재이용사례현황', sheetParameter);
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
|
}, [excelList])
|
||||||
|
|
||||||
// 양식받기
|
// 양식받기
|
||||||
const sampleDownLoad = () => {
|
const sampleDownLoad = () => {
|
||||||
excelDownload(
|
excelDownload(
|
||||||
[[]],
|
[[]],
|
||||||
"물재이용사례 관리",
|
"물재이용사례 관리 등록양식",
|
||||||
"sample_ruseCaseMng.xlsx",
|
"sample_ruseCaseMng.xlsx",
|
||||||
"A1:AX1",
|
"A1:AX1",
|
||||||
2
|
2
|
||||||
@@ -161,7 +177,7 @@ export default function RuseCaseMng() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(status === 200){
|
if (status === 200) {
|
||||||
setIsExcelOpen({ isModal: false });
|
setIsExcelOpen({ isModal: false });
|
||||||
}
|
}
|
||||||
}, [status]);
|
}, [status]);
|
||||||
@@ -174,7 +190,7 @@ export default function RuseCaseMng() {
|
|||||||
<Title title={"물재이용사례 관리"} />
|
<Title title={"물재이용사례 관리"} />
|
||||||
<SearchDiv>
|
<SearchDiv>
|
||||||
<SearchFormLeft>
|
<SearchFormLeft>
|
||||||
<div className="col-span-8 flex flex-row">
|
<div className="col-span-8 flex flex-row items-center">
|
||||||
<SelectBox
|
<SelectBox
|
||||||
className="col-span-2 w-1/3 h-full text-2xl"
|
className="col-span-2 w-1/3 h-full text-2xl"
|
||||||
label="시도"
|
label="시도"
|
||||||
@@ -183,24 +199,28 @@ export default function RuseCaseMng() {
|
|||||||
onSelectValue={getSelCity}
|
onSelectValue={getSelCity}
|
||||||
/>
|
/>
|
||||||
<SelectBox
|
<SelectBox
|
||||||
className="col-span-2 w-1/3 h-full text-2xl"
|
className="col-span-2 w-1/3 h-full text-2xl ml-4"
|
||||||
label="시군구"
|
label="시군구"
|
||||||
selectClass={""}
|
selectClass={""}
|
||||||
selectArray={selectSgg || []}
|
selectArray={selectSgg || []}
|
||||||
onSelectValue={getSgg}
|
onSelectValue={getSgg}
|
||||||
/>
|
/>
|
||||||
<SelectBox
|
<SelectBox
|
||||||
className="col-span-2 w-1/3 h-full text-2xl"
|
className="col-span-2 w-1/3 h-full text-2xl ml-4"
|
||||||
label="용도"
|
label="용도"
|
||||||
selectClass={""}
|
selectClass={""}
|
||||||
selectArray={ruseUtzType}
|
selectArray={ruseUtzType}
|
||||||
onSelectValue={(val) => {
|
onSelectValue={(val) => {
|
||||||
if (val) setSelectUtz([String(val)]);
|
if (val) setSelectUtz(String(val));
|
||||||
}}
|
}}
|
||||||
|
value={selectUtz || ruseUtzType[0]?.val}
|
||||||
/>
|
/>
|
||||||
|
<Label className="w-28 text-xl ml-4 mr-6">
|
||||||
|
{"수요처명"}
|
||||||
|
</Label>
|
||||||
<SearchInput
|
<SearchInput
|
||||||
className={"text-2xl"}
|
className={"col-span-2 w-1/3 text-2xl"}
|
||||||
label="수요처명"
|
label=""
|
||||||
textValue={name}
|
textValue={name}
|
||||||
setText={(e) => {
|
setText={(e) => {
|
||||||
setName(e);
|
setName(e);
|
||||||
@@ -211,13 +231,29 @@ export default function RuseCaseMng() {
|
|||||||
<SearchFormRight className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2">
|
<SearchFormRight className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2">
|
||||||
<div className="space-y">
|
<div className="space-y">
|
||||||
<div className="flex flex-row space-x-2">
|
<div className="flex flex-row space-x-2">
|
||||||
<Button size={"sm"} onClick={() => { searchRuseCaseMng(1, 20) }}>
|
<Button size={"sm"} onClick={() => {
|
||||||
|
searchRuseCaseMng(false, 1, 10);
|
||||||
|
isResetPage(true);
|
||||||
|
}}>
|
||||||
조회
|
조회
|
||||||
</Button>
|
</Button>
|
||||||
<Button size={"sm"} onClick={() => { setIsExcelOpen({ isModal: true }); }}>
|
<Button size={"sm"} onClick={() => { setIsExcelOpen({ isModal: true }); }}>
|
||||||
엑셀등록
|
엑셀등록
|
||||||
</Button>
|
</Button>
|
||||||
<Button size={"sm"} onClick={() => { download() }}>
|
<Button size={"sm"} onClick={() => {
|
||||||
|
selectRuseCaseMng(
|
||||||
|
true,
|
||||||
|
1,
|
||||||
|
count,
|
||||||
|
sidoCd ?? "",
|
||||||
|
sigunguCd ?? "",
|
||||||
|
selectUtz ?? "",
|
||||||
|
name ?? ""
|
||||||
|
);
|
||||||
|
// download()
|
||||||
|
|
||||||
|
|
||||||
|
}} className={"green"}>
|
||||||
다운로드
|
다운로드
|
||||||
</Button>
|
</Button>
|
||||||
<Button size={"sm"} onClick={() => { sampleDownLoad() }}>
|
<Button size={"sm"} onClick={() => { sampleDownLoad() }}>
|
||||||
@@ -239,10 +275,12 @@ export default function RuseCaseMng() {
|
|||||||
headlist={ruseCaseMng.ruseHeadList}
|
headlist={ruseCaseMng.ruseHeadList}
|
||||||
pageSize={20}
|
pageSize={20}
|
||||||
total={count}
|
total={count}
|
||||||
cellClick={() => {}}
|
cellClick={undefined}
|
||||||
onPageChange={(pageNo: number) => {
|
onPageChange={(pageNo: number) => {
|
||||||
searchRuseCaseMng(pageNo, 10);
|
searchRuseCaseMng(false, pageNo, 10);
|
||||||
|
isResetPage(false)
|
||||||
}}
|
}}
|
||||||
|
resetPageNo={resetPage}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</ListDiv>
|
</ListDiv>
|
||||||
@@ -254,9 +292,9 @@ export default function RuseCaseMng() {
|
|||||||
<UiModal
|
<UiModal
|
||||||
open={isExcelOpen.isModal}
|
open={isExcelOpen.isModal}
|
||||||
onOpenChange={() => {
|
onOpenChange={() => {
|
||||||
setIsExcelOpen({ isModal: !isExcelOpen.isModal })
|
setIsExcelOpen({ isModal: !isExcelOpen.isModal })
|
||||||
}}
|
}}
|
||||||
bodyClass={"w-[40vw] max-w-none"}
|
bodyClass={"w-[35vw] max-w-none"}
|
||||||
body={<RuseCaseMngExcel />}
|
body={<RuseCaseMngExcel />}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import type { SelectDataType } from "@common/business_components/ui";
|
import type { SelectDataType } from "@common/business_components/ui";
|
||||||
import type { TableUpperProps } from "../../common/type/header";
|
import type { TableUpperProps } from "../../common/type/header";
|
||||||
|
|
||||||
//★☆★☆ 여기서부터 수정하기 ★☆★☆
|
|
||||||
export const ruseCaseHeadListExport: TableUpperProps[] = [
|
export const ruseCaseHeadListExport: TableUpperProps[] = [
|
||||||
{
|
{
|
||||||
id: "ruseBizNm",
|
id: "ruseBizNm",
|
||||||
@@ -358,6 +357,7 @@ export const ruseCaseHeadListExport: TableUpperProps[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const ruseUtzType: SelectDataType[] = [
|
export const ruseUtzType: SelectDataType[] = [
|
||||||
|
{ text: "전체", val: "0" },
|
||||||
{ text: "조경용수", val: "조경용수" },
|
{ text: "조경용수", val: "조경용수" },
|
||||||
{ text: "청소화장실용수", val: "청소화장실용수" },
|
{ text: "청소화장실용수", val: "청소화장실용수" },
|
||||||
{ text: "세척살수용수", val: "세척살수용수" },
|
{ text: "세척살수용수", val: "세척살수용수" },
|
||||||
|
|||||||
@@ -4,90 +4,93 @@ import type { TableUpperProps } from "../../common/type/header";
|
|||||||
import { ruseCaseHeadListExport } from "./headList";
|
import { ruseCaseHeadListExport } from "./headList";
|
||||||
export type ruseCaseState = {
|
export type ruseCaseState = {
|
||||||
ruseCaseMng: {
|
ruseCaseMng: {
|
||||||
ruseHeadList:TableUpperProps[];
|
ruseHeadList: TableUpperProps[];
|
||||||
ruseCaseMngList:ruseCaseMngExcelProps[];
|
ruseCaseMngList: ruseCaseMngExcelProps[];
|
||||||
status: number;
|
status: number;
|
||||||
count: number;
|
count: number;
|
||||||
|
excelList?: ruseCaseMngExcelProps[];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface ruseCaseMngExcelProps {
|
export interface ruseCaseMngExcelProps {
|
||||||
ruseBizNm: string,
|
ruseBizNm: string,
|
||||||
bizBgngDate: string,
|
bizBgngDate: string,
|
||||||
bizEndDate: string,
|
bizEndDate: string,
|
||||||
splyFcltKnd: string,
|
splyFcltKnd: string,
|
||||||
splyFcltNm: string,
|
splyFcltNm: string,
|
||||||
splyFcltCpct: number | 0 |'',
|
splyFcltCpct: number | 0 | '',
|
||||||
dmdFcltNm: string,
|
dmdFcltNm: string,
|
||||||
dmdFcltAddr: string,
|
dmdFcltAddr: string,
|
||||||
ruseFcltCpct: number | 0 |'',
|
ruseFcltCpct: number | 0 | '',
|
||||||
ruseFcltPplLen: string,
|
ruseFcltPplLen: string,
|
||||||
ruseFcltUsg: string,
|
ruseFcltUsg: string,
|
||||||
ruseFcltSplyCpct: number | 0 |'',
|
ruseFcltSplyCpct: number | 0 | '',
|
||||||
ruseFcltPrcsMsrc: string,
|
ruseFcltPrcsMsrc: string,
|
||||||
grnteWqUsg: string,
|
grnteWqUsg: string,
|
||||||
grnteWqGrssClfg: number | 0 |'',
|
grnteWqGrssClfg: number | 0 | '',
|
||||||
grnteWqCombResdch: number | 0 |'',
|
grnteWqCombResdch: number | 0 | '',
|
||||||
grnteWqTrbt: string,
|
grnteWqTrbt: string,
|
||||||
grnteWqBod: string,
|
grnteWqBod: string,
|
||||||
grnteWqSmll: string,
|
grnteWqSmll: string,
|
||||||
grnteWqCrmty: string,
|
grnteWqCrmty: string,
|
||||||
grnteWqTn: string,
|
grnteWqTn: string,
|
||||||
grnteWqTp: string,
|
grnteWqTp: string,
|
||||||
grnteWqPh: string,
|
grnteWqPh: string,
|
||||||
grnteWqClIonQnt: string,
|
grnteWqClIonQnt: string,
|
||||||
grnteWqCndctStat: string,
|
grnteWqCndctStat: string,
|
||||||
grnteWqRmrk: string,
|
grnteWqRmrk: string,
|
||||||
reqBizReuseFcltCst: number | 0 |'',
|
reqBizReuseFcltCst: number | 0 | '',
|
||||||
reqBizPplCst: number | 0 |'',
|
reqBizPplCst: number | 0 | '',
|
||||||
reqBizArchCst: number | 0 |'',
|
reqBizArchCst: number | 0 | '',
|
||||||
reqBizMchnCst: number | 0 |'',
|
reqBizMchnCst: number | 0 | '',
|
||||||
reqBizMtrngCst: number | 0 |'',
|
reqBizMtrngCst: number | 0 | '',
|
||||||
reqBizGisCst: number | 0 |'',
|
reqBizGisCst: number | 0 | '',
|
||||||
reqBizCctvCst: number | 0 |'',
|
reqBizCctvCst: number | 0 | '',
|
||||||
reqBizCmcnCst: number | 0 |'',
|
reqBizCmcnCst: number | 0 | '',
|
||||||
reqBizWstCst: number | 0 |'',
|
reqBizWstCst: number | 0 | '',
|
||||||
reqBizDesignCst: number | 0 |'',
|
reqBizDesignCst: number | 0 | '',
|
||||||
reqBizSpvsCst: number | 0 |'',
|
reqBizSpvsCst: number | 0 | '',
|
||||||
reqBizSbsdCst: number | 0 |'',
|
reqBizSbsdCst: number | 0 | '',
|
||||||
reqBizEtc: string,
|
reqBizEtc: string,
|
||||||
reqBizGrssCst: number | 0 |'',
|
reqBizGrssCst: number | 0 | '',
|
||||||
prcmPlanNlep: number | 0 |'',
|
prcmPlanNlep: number | 0 | '',
|
||||||
prcmPlanLcep: number | 0 |'',
|
prcmPlanLcep: number | 0 | '',
|
||||||
prcmPlanBrdnCst: number | 0 |'',
|
prcmPlanBrdnCst: number | 0 | '',
|
||||||
prcmPlanEcqrRt: number | 0 |'',
|
prcmPlanEcqrRt: number | 0 | '',
|
||||||
prcmPlanGrssCst: number | 0 |'',
|
prcmPlanGrssCst: number | 0 | '',
|
||||||
clclnNlep: number | 0 |'',
|
clclnNlep: number | 0 | '',
|
||||||
clclnLcep: number | 0 |'',
|
clclnLcep: number | 0 | '',
|
||||||
clclnBrdnCst: number | 0 |'',
|
clclnBrdnCst: number | 0 | '',
|
||||||
clclnEcqrRt: number | 0 |'',
|
clclnEcqrRt: number | 0 | '',
|
||||||
clclnGrssCst: number | 0 |'',
|
clclnGrssCst: number | 0 | '',
|
||||||
}
|
}
|
||||||
|
|
||||||
type ruseCaseActions = {
|
type ruseCaseActions = {
|
||||||
selectRuseCaseMng: (pageNo: number, pageSize: number, sidoCd: string, sigunguCd: string, usageCd : string, name: string) => Promise<void>;
|
ruseCaseMngInit: () => void;
|
||||||
|
selectRuseCaseMng: (isExcel: boolean, pageNo: number, pageSize: number, sidoCd: string, sigunguCd: string, usageCd: string, name: string) => Promise<void>;
|
||||||
insertRuseCaseMng: (data: any) => Promise<void>;
|
insertRuseCaseMng: (data: any) => Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchSearchRuseCaseMng = async (pageNo: number, pageSize: number, sidoCd: string, sigunguCd: string, usageCd : string, name: string) => {
|
export const fetchSearchRuseCaseMng = async (pageNo: number, pageSize: number, sidoCd: string, sigunguCd: string, usageCd: string, name: string) => {
|
||||||
const tailUrl = '/'+pageNo+'/'+pageSize+ ((sigunguCd !== '전체' && sigunguCd !=='') ? `/${sigunguCd}` : (sidoCd != '전체' && sidoCd != '') ? `/${sidoCd}` : `/0`) + (usageCd? `/${usageCd}` : '/0') + (name? `/${name}` : '');
|
const tailUrl = '/' + pageNo + '/' + pageSize + ((sigunguCd !== '전체' && sigunguCd !== '') ? `/${sigunguCd}` : (sidoCd != '전체' && sidoCd != '') ? `/${sidoCd}` : `/0`) + (usageCd ? `/${usageCd}` : '/0') + (name ? `/${name}` : '');
|
||||||
const resp = await getFetchWithCount(fetchType.WR,`/reuseFc/pubFcRuseCase${tailUrl}`);
|
const resp = await getFetchWithCount(fetchType.WR, `/reuseFc/pubFcRuseCase${tailUrl}`);
|
||||||
return {data:resp.data, count:resp.count};
|
return { data: resp.data, count: resp.count };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchInsertRuseCaseMng = async (data: any) => {
|
export const fetchInsertRuseCaseMng = async (data: any) => {
|
||||||
const response = await postFectch('/reuseFc/pubFcRuseCase', data, fetchType.WR);
|
const response = await postFectch('/reuseFc/pubFcRuseCase', data, fetchType.WR);
|
||||||
return {data:response.data, status:response.status};
|
return { data: response.data, status: response.status };
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ruseCaseType = ruseCaseState & ruseCaseActions;
|
export type ruseCaseType = ruseCaseState & ruseCaseActions;
|
||||||
|
|
||||||
export const ruseCaseStateExport: ruseCaseState = {
|
export const ruseCaseStateExport: ruseCaseState = {
|
||||||
ruseCaseMng: {
|
ruseCaseMng: {
|
||||||
ruseHeadList:ruseCaseHeadListExport,
|
ruseHeadList: ruseCaseHeadListExport,
|
||||||
ruseCaseMngList:[],
|
ruseCaseMngList: [],
|
||||||
status: 0,
|
status: 0,
|
||||||
count: 0,
|
count: 0,
|
||||||
|
excelList: undefined,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -95,8 +98,8 @@ export const ruseCaseActionsExport: (set: any) => ruseCaseActions = (
|
|||||||
set: any
|
set: any
|
||||||
) => {
|
) => {
|
||||||
return {
|
return {
|
||||||
selectRuseCaseMng: async (pageNo: number, pageSize: number, sidoCd: string, sigunguCd: string, usageCd : string, name: string) => {
|
ruseCaseMngInit: async () => {
|
||||||
const res = await fetchSearchRuseCaseMng(pageNo, pageSize, sidoCd, sigunguCd, usageCd, name);
|
const res = await getFetchWithCount(fetchType.WR, `/reuseFc/pubFcRuseCase/1/10/0/0`);
|
||||||
set((state: ruseCaseState) => ({
|
set((state: ruseCaseState) => ({
|
||||||
ruseCaseMng: {
|
ruseCaseMng: {
|
||||||
...state.ruseCaseMng,
|
...state.ruseCaseMng,
|
||||||
@@ -105,12 +108,35 @@ export const ruseCaseActionsExport: (set: any) => ruseCaseActions = (
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
selectRuseCaseMng: async (isExcel: boolean, pageNo: number, pageSize: number, sidoCd: string, sigunguCd: string, usageCd: string, name: string) => {
|
||||||
|
const res = await fetchSearchRuseCaseMng(pageNo, pageSize, sidoCd, sigunguCd, usageCd, name);
|
||||||
|
if (isExcel) {
|
||||||
|
set((state: ruseCaseState) => {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
ruseCaseMng: {
|
||||||
|
...state.ruseCaseMng,
|
||||||
|
count: res.count,
|
||||||
|
excelList: res.data
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
set((state: ruseCaseState) => ({
|
||||||
|
ruseCaseMng: {
|
||||||
|
...state.ruseCaseMng,
|
||||||
|
ruseCaseMngList: res.data,
|
||||||
|
count: res.count,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
insertRuseCaseMng: async (data: any) => {
|
insertRuseCaseMng: async (data: any) => {
|
||||||
const response = await fetchInsertRuseCaseMng(data);
|
const response = await fetchInsertRuseCaseMng(data);
|
||||||
if(response.status === 200){
|
if (response.status === 200) {
|
||||||
toast.success("물재이용사례 등록이 완료되었습니다. ");
|
toast.success("물재이용사례 등록이 완료되었습니다. ");
|
||||||
}else{
|
} else {
|
||||||
toast.error("물재이용사례 등록에 실패하였습니다. ");
|
toast.error("물재이용사례 등록에 실패하였습니다. ");
|
||||||
}
|
}
|
||||||
set((state: ruseCaseState) => ({
|
set((state: ruseCaseState) => ({
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
isInvalidNumber,
|
isInvalidNumber,
|
||||||
parseRawValue,
|
parseRawValue,
|
||||||
} from "@/components/lib/func/excelFunc";
|
} from "@/components/lib/func/excelFunc";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
export const useTypes = [
|
export const useTypes = [
|
||||||
"조경용수",
|
"조경용수",
|
||||||
"청소화장실용수",
|
"청소화장실용수",
|
||||||
@@ -16,6 +17,18 @@ export const useTypes = [
|
|||||||
"기타",
|
"기타",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
export const chkMngType =[
|
||||||
|
'위탁',
|
||||||
|
'자체'
|
||||||
|
]
|
||||||
|
export const chkSpwtPositnType = [
|
||||||
|
'유량계',
|
||||||
|
'수위계',
|
||||||
|
'펌프적산전력계',
|
||||||
|
'기타'
|
||||||
|
]
|
||||||
|
|
||||||
export type Buildingtype = {
|
export type Buildingtype = {
|
||||||
bdstInfoSn: number;
|
bdstInfoSn: number;
|
||||||
ctpvCd: 1;
|
ctpvCd: 1;
|
||||||
@@ -143,43 +156,56 @@ export const excelToRainChkData = (excelData: any, year: string) => {
|
|||||||
})
|
})
|
||||||
.filter((el: any) => el !== undefined);
|
.filter((el: any) => el !== undefined);
|
||||||
|
|
||||||
|
console.log("rainChkgdData", rainChkgdData);
|
||||||
if (rainChkgdData.length > 0) {
|
if (rainChkgdData.length > 0) {
|
||||||
rainChkgdData.forEach((rain: any) => {
|
rainChkgdData.forEach((rain: any) => {
|
||||||
const defaultMessage = `[시설명: ${rain.bdstNm}, 점검일: ${rain.chckYmd}, 이용용도: ${rain.guideDetails[0]?.utztnUsgCd}] 항목에서 `;
|
const defaultMessage = `[시설명: ${rain.bdstNm}, 점검일: ${rain.chckYmd}, 이용용도: ${rain.guideDetails[0]?.utztnUsgCd}] 항목에서 `;
|
||||||
|
|
||||||
if (rain.chckYmd && isInvalidDate(rain.chckYmd)) {
|
if (rain.chckYmd && isInvalidDate(rain.chckYmd)) {
|
||||||
issues.push(
|
issues.push(
|
||||||
defaultMessage + `점검일: 날짜 형식 아님 (${rain.chckYmd})`
|
defaultMessage + `점검일: 날짜 형식 아님 입력값 : (${rain.chckYmd})`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (rain.anlOperCst.length > 2 && isInvalidNumber(rain.anlOperCst)) {
|
if (rain.anlOperCst.length > 2 && isInvalidNumber(rain.anlOperCst)) {
|
||||||
issues.push(
|
issues.push(
|
||||||
defaultMessage +
|
defaultMessage +
|
||||||
` 연간운영비(원/년): 숫자 형식 아님 (${rain.anlOperCst})`
|
` 연간운영비(원/년): 숫자 형식 아님 /입력값:${rain.anlOperCst}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (rain.oilqMeasMthd.length > 1 && !chkMngType.includes(rain.oilqMeasMthd)) {
|
||||||
|
issues.push(
|
||||||
|
defaultMessage + `유량측정방법: 위탁 혹은 자체 만 허용) /입력값:${rain.oilqMeasMthd}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (rain.spwtPositn.length > 1 && !chkSpwtPositnType.includes(rain.spwtPositn)) {
|
||||||
|
issues.push(
|
||||||
|
defaultMessage + `측정위치: 유량계, 수위계, 펌프적산전력계, 기타 중 하나만 허용) /입력값:${rain.spwtPositn}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
rain.rainyDetails?.forEach((key) => {
|
rain.rainyDetails?.forEach((key) => {
|
||||||
if (key.ph?.length > 1 && isInvalidNumber(key.ph)) {
|
if (key.ph?.length > 1 && isInvalidNumber(key.ph)) {
|
||||||
issues.push(defaultMessage + `PH: 숫자 형식 아님 (${key.ph})`);
|
issues.push(defaultMessage + `PH: 숫자 형식 아님 /입력값:${key.ph}`);
|
||||||
}
|
}
|
||||||
if (key.trbt?.length > 1 && isInvalidNumber(key.trbt)) {
|
if (key.trbt?.length > 1 && isInvalidNumber(key.trbt)) {
|
||||||
issues.push(defaultMessage + `탁도: 숫자 형식 아님 (${key.trbt})`);
|
issues.push(defaultMessage + `탁도: 숫자 형식 아님 /입력값:${key.trbt}`);
|
||||||
}
|
}
|
||||||
if (key.grssClfg?.length > 1 && isInvalidNumber(key.grssClfg)) {
|
if (key.grssClfg?.length > 1 && isInvalidNumber(key.grssClfg)) {
|
||||||
issues.push(
|
issues.push(
|
||||||
defaultMessage + `총대장균군수: 숫자 형식 아님 (${key.grssClfg})`
|
defaultMessage + `총대장균군수: 숫자 형식 아님 /입력값:${key.grssClfg}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (key.levyAmt?.length > 1 && isInvalidNumber(key.levyAmt)) {
|
if (key.levyAmt?.length > 1 && isInvalidNumber(key.levyAmt)) {
|
||||||
issues.push(
|
issues.push(
|
||||||
defaultMessage +
|
defaultMessage +
|
||||||
`과태료부과금액(천원): 숫자 형식 아님 (${key.levyAmt})`
|
`과태료부과금액(천원): 숫자 형식 아님 /입력값:${key.levyAmt}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (key.vltnDt?.length > 2 && isInvalidDate(key.vltnDt)) {
|
if (key.vltnDt?.length > 2 && isInvalidDate(key.vltnDt)) {
|
||||||
issues.push(
|
issues.push(
|
||||||
defaultMessage +
|
defaultMessage +
|
||||||
`과태료 부과일(위반일): 날짜 형식 아님 (${key.vltnDt})`
|
`과태료 부과일(위반일): 날짜 형식 아님 /입력값:${key.vltnDt}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -188,17 +214,19 @@ export const excelToRainChkData = (excelData: any, year: string) => {
|
|||||||
if (isInvalidNumber(guide.splyUswtrUtztnQnt)) {
|
if (isInvalidNumber(guide.splyUswtrUtztnQnt)) {
|
||||||
issues.push(
|
issues.push(
|
||||||
defaultMessage +
|
defaultMessage +
|
||||||
`대체_${mm}: 숫자 형식 아님 (${guide.splyUswtrUtztnQnt})`
|
`대체_${mm}: 숫자 형식 아님 /입력값:${guide.splyUswtrUtztnQnt}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (isInvalidNumber(guide.ruseFcltUtztnQnt)) {
|
if (isInvalidNumber(guide.ruseFcltUtztnQnt)) {
|
||||||
issues.push(
|
issues.push(
|
||||||
defaultMessage +
|
defaultMessage +
|
||||||
`빗물_${mm}: 숫자 형식 아님 (${guide.ruseFcltUtztnQnt})`
|
`빗물_${mm}: 숫자 형식 아님 /입력값:${guide.ruseFcltUtztnQnt}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}else{
|
||||||
|
toast.error("데이터가 없습니다. 점검 데이터를 확인해주세요.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (issues.length > 0) {
|
if (issues.length > 0) {
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
import type { SelectDataType } from "@common/business_components/ui";
|
import type { SelectDataType } from "@common/business_components/ui";
|
||||||
import { useTypes, type Buildingtype } from "../rainChkgdn/excel";
|
import {
|
||||||
|
chkMngType,
|
||||||
|
chkSpwtPositnType,
|
||||||
|
useTypes,
|
||||||
|
type Buildingtype,
|
||||||
|
} from "../rainChkgdn/excel";
|
||||||
import { TEST_UUID } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
|
import { TEST_UUID } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
|
||||||
import type { rswtChkZodType } from ".";
|
import type { rswtChkZodType } from ".";
|
||||||
import {
|
import {
|
||||||
@@ -171,14 +176,14 @@ export const excelToRswtGuideData = (
|
|||||||
.filter((el: any) => el !== undefined);
|
.filter((el: any) => el !== undefined);
|
||||||
|
|
||||||
if (rswtChkgdData.length > 0) {
|
if (rswtChkgdData.length > 0) {
|
||||||
rswtExcelDataCheck(rswtChkgdData,issues)
|
rswtExcelDataCheck(rswtChkgdData, issues);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (issues.length > 0) {
|
if (issues.length > 0) {
|
||||||
return { data: [], issues };
|
return { data: [], issues };
|
||||||
}
|
}
|
||||||
|
|
||||||
return { data:rswtChkgdData, issues: [] };
|
return { data: rswtChkgdData, issues: [] };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const excelToRswtPolution = (excelData: any, issues: string[]) => {
|
export const excelToRswtPolution = (excelData: any, issues: string[]) => {
|
||||||
@@ -248,25 +253,25 @@ export const excelToRswtPolution = (excelData: any, issues: string[]) => {
|
|||||||
})
|
})
|
||||||
.filter((el: any) => el !== undefined);
|
.filter((el: any) => el !== undefined);
|
||||||
if (rswtChkgdData.length > 0) {
|
if (rswtChkgdData.length > 0) {
|
||||||
rswtExcelDataCheck(rswtChkgdData,issues)
|
rswtExcelDataCheck(rswtChkgdData, issues);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (issues.length > 0) {
|
if (issues.length > 0) {
|
||||||
return { data: [], issues };
|
return { data: [], issues };
|
||||||
}
|
}
|
||||||
|
|
||||||
return { data:rswtChkgdData, issues: [] };
|
return { data: rswtChkgdData, issues: [] };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const rswtExcelDataCheck = (
|
||||||
const rswtExcelDataCheck=(rswtChkgdData:rswtChkZodType[], issues:string[]) =>{
|
rswtChkgdData: rswtChkZodType[],
|
||||||
|
issues: string[]
|
||||||
|
) => {
|
||||||
rswtChkgdData.forEach((rswt: any) => {
|
rswtChkgdData.forEach((rswt: any) => {
|
||||||
const defaultMessage = `*중수도 수질 [NO: ${rswt.bdstRuseFcltSn}, 점검일: ${rswt.chckYmd}, 이용용도: ${rswt.utztnUsgCd}] 항목에서 `;
|
const defaultMessage = `*중수도 수질 [NO: ${rswt.bdstRuseFcltSn}, 점검일: ${rswt.chckYmd}, 이용용도: ${rswt.utztnUsgCd}] 항목에서 `;
|
||||||
|
|
||||||
if (rswt.chckYmd && isInvalidDate(rswt.chckYmd)) {
|
if (rswt.chckYmd && isInvalidDate(rswt.chckYmd)) {
|
||||||
issues.push(
|
issues.push(defaultMessage + `점검일: 날짜 형식 아님 (${rswt.chckYmd})`);
|
||||||
defaultMessage + `점검일: 날짜 형식 아님 (${rswt.chckYmd})`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (rswt.anlOperCst.length > 2 && isInvalidNumber(rswt.anlOperCst)) {
|
if (rswt.anlOperCst.length > 2 && isInvalidNumber(rswt.anlOperCst)) {
|
||||||
issues.push(
|
issues.push(
|
||||||
@@ -279,6 +284,25 @@ const rswtExcelDataCheck=(rswtChkgdData:rswtChkZodType[], issues:string[]) =>{
|
|||||||
defaultMessage + ` 처리용량(m³): 숫자 형식 아님 (${rswt.prcsCpct})`
|
defaultMessage + ` 처리용량(m³): 숫자 형식 아님 (${rswt.prcsCpct})`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
rswt.oilqMeasMthd.length > 1 &&
|
||||||
|
!chkMngType.includes(rswt.oilqMeasMthd)
|
||||||
|
) {
|
||||||
|
issues.push(
|
||||||
|
defaultMessage +
|
||||||
|
`유량측정방법: 위탁 혹은 자체 만 허용) /입력값:${rswt.oilqMeasMthd}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
rswt.spwtPositn.length > 1 &&
|
||||||
|
!chkSpwtPositnType.includes(rswt.spwtPositn)
|
||||||
|
) {
|
||||||
|
issues.push(
|
||||||
|
defaultMessage +
|
||||||
|
`측정위치: 유량계, 수위계, 펌프적산전력계, 기타 중 하나만 허용) /입력값:${rswt.spwtPositn}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (rswt?.rswtrPollutions && rswt?.rswtrPollutions.length > 0) {
|
if (rswt?.rswtrPollutions && rswt?.rswtrPollutions.length > 0) {
|
||||||
rswt.rswtrPollutions.forEach((pol) => {
|
rswt.rswtrPollutions.forEach((pol) => {
|
||||||
if (isInvalidNumber(pol.grssClfgUswtr)) {
|
if (isInvalidNumber(pol.grssClfgUswtr)) {
|
||||||
@@ -301,8 +325,7 @@ const rswtExcelDataCheck=(rswtChkgdData:rswtChkZodType[], issues:string[]) =>{
|
|||||||
}
|
}
|
||||||
if (isInvalidNumber(pol.bod)) {
|
if (isInvalidNumber(pol.bod)) {
|
||||||
issues.push(
|
issues.push(
|
||||||
defaultMessage +
|
defaultMessage + `${pol.node}분기_BOD: 숫자 형식 아님 (${pol.bod})`
|
||||||
`${pol.node}분기_BOD: 숫자 형식 아님 (${pol.bod})`
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (isInvalidNumber(pol.smll)) {
|
if (isInvalidNumber(pol.smll)) {
|
||||||
@@ -319,8 +342,7 @@ const rswtExcelDataCheck=(rswtChkgdData:rswtChkZodType[], issues:string[]) =>{
|
|||||||
}
|
}
|
||||||
if (isInvalidNumber(pol.tph)) {
|
if (isInvalidNumber(pol.tph)) {
|
||||||
issues.push(
|
issues.push(
|
||||||
defaultMessage +
|
defaultMessage + `${pol.node}분기_T-P: 숫자 형식 아님 (${pol.tph})`
|
||||||
`${pol.node}분기_T-P: 숫자 형식 아님 (${pol.tph})`
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (isInvalidNumber(pol.tn)) {
|
if (isInvalidNumber(pol.tn)) {
|
||||||
@@ -358,7 +380,5 @@ const rswtExcelDataCheck=(rswtChkgdData:rswtChkZodType[], issues:string[]) =>{
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
};
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
|
import { useWrStore } from "@/app/store";
|
||||||
import { coRegExcel } from "@/app/store/matDmd/coSttn/headList";
|
import { coRegExcel } from "@/app/store/matDmd/coSttn/headList";
|
||||||
import type { ruseCaseMngExcelProps } from "@/app/store/matDmd/ruseCaseMng/index";
|
|
||||||
import { reUseCaseNames } from "@/app/store/matDmd/ruseCaseMng/excel";
|
import { reUseCaseNames } from "@/app/store/matDmd/ruseCaseMng/excel";
|
||||||
import { filePicked, FileUpload, FormUi, Title } from "@common/business_components/ui";
|
import type { ruseCaseMngExcelProps } from "@/app/store/matDmd/ruseCaseMng/index";
|
||||||
import { Form, FormField } from "@common/business_components/ui/form";
|
import { filePicked, Title } from "@common/business_components/ui";
|
||||||
import { Button } from "@common/components/ui";
|
import { Form } from "@common/business_components/ui/form";
|
||||||
|
import { Button, Input } from "@common/components/ui";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import type { z } from "zod";
|
import type { z } from "zod";
|
||||||
import { useWrStore } from "@/app/store";
|
|
||||||
|
|
||||||
export default function RuseCaseMngExcel() {
|
export default function RuseCaseMngExcel() {
|
||||||
const { insertRuseCaseMng } = useWrStore((state) => state);
|
const { insertRuseCaseMng } = useWrStore((state) => state);
|
||||||
@@ -79,6 +79,7 @@ export default function RuseCaseMngExcel() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Object.keys(reUseCaseNames).forEach((key: string) => {
|
Object.keys(reUseCaseNames).forEach((key: string) => {
|
||||||
|
console.log("reUseCaseNames", reUseCaseNames)
|
||||||
if (item && reUseCaseNames[key] !== undefined) {
|
if (item && reUseCaseNames[key] !== undefined) {
|
||||||
const mappedKey = reUseCaseNames[key];
|
const mappedKey = reUseCaseNames[key];
|
||||||
if (mappedKey && object.hasOwnProperty(mappedKey)) {
|
if (mappedKey && object.hasOwnProperty(mappedKey)) {
|
||||||
@@ -146,23 +147,16 @@ export default function RuseCaseMngExcel() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<FormField
|
<div className="space-y-4 p-4">
|
||||||
control={form.control}
|
<Input
|
||||||
name="file"
|
type="file"
|
||||||
render={() => (
|
onChange={(e) => {
|
||||||
<FormUi label="">
|
const selectedFile = e.target.files?.[0];
|
||||||
<FileUpload
|
if (selectedFile) setFiles(selectedFile);
|
||||||
files={file ? [file] : []}
|
}}
|
||||||
setFiles={(files: File[] | null) => {
|
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
|
||||||
console.log("files", files)
|
/>
|
||||||
if (files && files?.length === 1) setFiles(files[0]);
|
</div>
|
||||||
}}
|
|
||||||
fileTypes=""
|
|
||||||
maxFiles={1}
|
|
||||||
></FileUpload>
|
|
||||||
</FormUi>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ const serverApiUrl = CS_URL;
|
|||||||
const GEOSERVER_URL = process.env.NEXT_PUBLIC_GEOSERVER_URL || "";
|
const GEOSERVER_URL = process.env.NEXT_PUBLIC_GEOSERVER_URL || "";
|
||||||
const LX_GEOSERVER_URL = process.env.NEXT_PUBLIC_LX_GEOSERVER_URL || "";
|
const LX_GEOSERVER_URL = process.env.NEXT_PUBLIC_LX_GEOSERVER_URL || "";
|
||||||
const SEWERAGE_API_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || "";
|
const SEWERAGE_API_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || "";
|
||||||
|
const REUSE_API_URL = process.env.NEXT_PUBLIC_WR_SERVER_API_URL || "";
|
||||||
|
|
||||||
export function middleware(req: NextRequest) {
|
export function middleware(req: NextRequest) {
|
||||||
const pathname = req.nextUrl.pathname;
|
const pathname = req.nextUrl.pathname;
|
||||||
@@ -135,6 +136,15 @@ export function middleware(req: NextRequest) {
|
|||||||
return NextResponse.rewrite(new URL(newUrl));
|
return NextResponse.rewrite(new URL(newUrl));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pathname.startsWith("/reuse-service")) {
|
||||||
|
const queryParams = searchParams.toString();
|
||||||
|
const newUrl = `${REUSE_API_URL}${pathname.replace("/reuse-service", "")}${
|
||||||
|
queryParams ? `?${queryParams}` : ""
|
||||||
|
}`;
|
||||||
|
console.log(`[Middleware] Rewriting from '/reuse-service' path to: ${newUrl}`);
|
||||||
|
return NextResponse.rewrite(new URL(newUrl));
|
||||||
|
}
|
||||||
|
|
||||||
return NextResponse.next();
|
return NextResponse.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,6 +156,7 @@ export const config = {
|
|||||||
"/attach-service/:path*",
|
"/attach-service/:path*",
|
||||||
"/geoserver/:path*",
|
"/geoserver/:path*",
|
||||||
"/sewerage-service/:path*",
|
"/sewerage-service/:path*",
|
||||||
|
"/reuse-service/:path*",
|
||||||
"/"
|
"/"
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 919 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 810 B |
|
Before Width: | Height: | Size: 1016 B After Width: | Height: | Size: 896 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 837 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 790 B |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 855 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 923 B |
@@ -1,323 +1,357 @@
|
|||||||
import { Search } from 'lucide-react';
|
import { Search } from "lucide-react";
|
||||||
import OlMap from 'ol/Map';
|
import OlMap from "ol/Map";
|
||||||
import View from 'ol/View';
|
import View from "ol/View";
|
||||||
import { defaults as defaultControls, OverviewMap } from 'ol/control';
|
import { defaults as defaultControls, OverviewMap } from "ol/control";
|
||||||
import { defaults } from 'ol/interaction';
|
import { defaults } from "ol/interaction";
|
||||||
import * as olProj from 'ol/proj';
|
import * as olProj from "ol/proj";
|
||||||
import { register } from 'ol/proj/proj4';
|
import { register } from "ol/proj/proj4";
|
||||||
import proj4 from 'proj4';
|
import proj4 from "proj4";
|
||||||
import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
import React, {
|
||||||
import GisMapToggle from './GisMapToggle';
|
createContext,
|
||||||
import GisSelect from './GisSelect';
|
useCallback,
|
||||||
import GisToolBar from './GisToolBar';
|
useContext,
|
||||||
import GisTree from './GisTree';
|
useEffect,
|
||||||
import './lib/css/gis.common.css';
|
useMemo,
|
||||||
import GisApp from './lib/gis.core';
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
|
import GisMapToggle from "./GisMapToggle";
|
||||||
|
import GisSelect from "./GisSelect";
|
||||||
|
import GisToolBar from "./GisToolBar";
|
||||||
|
import GisTree from "./GisTree";
|
||||||
|
import "./lib/css/gis.common.css";
|
||||||
|
import GisApp from "./lib/gis.core";
|
||||||
|
|
||||||
export const GisContext = createContext({ gisCore: null, gisMap: null, treeData: null, checkedLayerIds: null });
|
export const GisContext = createContext({
|
||||||
|
gisCore: null,
|
||||||
|
gisMap: null,
|
||||||
|
treeData: null,
|
||||||
|
checkedLayerIds: null,
|
||||||
|
});
|
||||||
export const useGisContext = () => useContext(GisContext);
|
export const useGisContext = () => useContext(GisContext);
|
||||||
export const searchUpperPpls = async (fcltMngNo) => {
|
export const searchUpperPpls = async (fcltMngNo) => {
|
||||||
const BASE_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || '';
|
const BASE_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || "";
|
||||||
|
const res = await fetch(`${BASE_URL}/v1/fcltmhl/upperPpls/${fcltMngNo}`, {
|
||||||
|
method: "GET",
|
||||||
|
});
|
||||||
|
|
||||||
const res = await fetch(`${BASE_URL}/v1/fcltmhl/upperPpls/${fcltMngNo}`, {
|
let data = null;
|
||||||
method: "GET",
|
if (res.ok) {
|
||||||
});
|
try {
|
||||||
|
// 응답이 비어있는지 확인
|
||||||
|
const contentLength = res.headers.get("content-length");
|
||||||
|
if (contentLength === "0")
|
||||||
|
alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
|
||||||
|
|
||||||
let data = null;
|
// 응답 텍스트를 먼저 가져와서 빈 문자열인지 확인
|
||||||
if (res.ok) {
|
const text = await res.text();
|
||||||
try {
|
if (!text || text.trim() === "")
|
||||||
// 응답이 비어있는지 확인
|
alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
|
||||||
const contentLength = res.headers.get('content-length');
|
|
||||||
if (contentLength === '0') alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
|
|
||||||
|
|
||||||
// 응답 텍스트를 먼저 가져와서 빈 문자열인지 확인
|
// JSON 파싱 시도
|
||||||
const text = await res.text();
|
data = JSON.parse(text);
|
||||||
if (!text || text.trim() === '') alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
|
} catch (error) {
|
||||||
|
console.error("JSON parsing error:", error);
|
||||||
|
alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// JSON 파싱 시도
|
const select = GisApp.Module.select;
|
||||||
data = JSON.parse(text);
|
const gisMap = GisApp.Module.core?.map;
|
||||||
} catch (error) {
|
let foundFeature = null;
|
||||||
console.error('JSON parsing error:', error);
|
|
||||||
alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const select = GisApp.Module.select;
|
data.forEach((item) => {
|
||||||
|
const pplMngNo = item.ppl_mng_no.trim();
|
||||||
|
|
||||||
const gisMap = GisApp.Module.core?.map;
|
gisMap
|
||||||
|
.getLayers()
|
||||||
|
.getArray()
|
||||||
|
.filter((e) => e.get("lyrTyNm") == "tb_ms_swage_ppl")
|
||||||
|
.forEach((layer) => {
|
||||||
|
const source = layer.getSource?.();
|
||||||
|
if (source?.getFeatures) {
|
||||||
|
const features = source.getFeatures();
|
||||||
|
for (const f of features) {
|
||||||
|
if (f.values_.fclt_mng_no.trim() === pplMngNo) {
|
||||||
|
foundFeature = f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let foundFeature = null;
|
if (foundFeature) select.selectMultiFeature(foundFeature, true);
|
||||||
|
});
|
||||||
|
|
||||||
data.forEach(item => {
|
if (!foundFeature) alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
|
||||||
const pplMngNo = item.ppl_mng_no.trim();
|
|
||||||
|
|
||||||
gisMap.getLayers().getArray().filter(e => e.get("lyrTyNm") == 'tb_ms_swage_ppl').forEach(layer => {
|
let geometry = foundFeature?.getGeometry();
|
||||||
const source = layer.getSource?.();
|
if (geometry) {
|
||||||
if (source?.getFeatures) {
|
let extent = geometry.getExtent();
|
||||||
const features = source.getFeatures();
|
|
||||||
for (const f of features) {
|
|
||||||
if (f.values_.fclt_mng_no.trim() === pplMngNo) {
|
|
||||||
foundFeature = f;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (foundFeature) select.selectMultiFeature(foundFeature, true);
|
gisMap.getView().fit(extent, {
|
||||||
});
|
duration: 300,
|
||||||
|
padding: [50, 50, 50, 50],
|
||||||
if (!foundFeature) alert(`해당 맨홀의 상류관로를 찾을 수 없습니다.`);
|
maxZoom: 14,
|
||||||
|
constrainResolution: true,
|
||||||
let geometry = foundFeature?.getGeometry();
|
nearest: true,
|
||||||
if (geometry) {
|
});
|
||||||
let extent = geometry.getExtent();
|
}
|
||||||
|
|
||||||
gisMap.getView().fit(extent, {
|
|
||||||
duration: 300,
|
|
||||||
padding: [50, 50, 50, 50],
|
|
||||||
maxZoom: 14,
|
|
||||||
constrainResolution: true,
|
|
||||||
nearest: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function Gis({
|
function Gis({
|
||||||
isOpen, //우측 상세 레이어 팝업
|
isOpen, //우측 상세 레이어 팝업
|
||||||
gisMaps,
|
gisMaps,
|
||||||
isSearchModalOpen,
|
isSearchModalOpen,
|
||||||
treeData = [],
|
treeData = [],
|
||||||
isSearch = false,
|
isSearch = false,
|
||||||
isMiniMap = false,
|
isMiniMap = false,
|
||||||
setIsOpen,
|
setIsOpen,
|
||||||
setFeatureData,
|
setFeatureData,
|
||||||
featureData,
|
featureData,
|
||||||
imgVisble = false,
|
imgVisble = false,
|
||||||
searchView: SearchView,
|
searchView: SearchView,
|
||||||
detailView: DetailView,
|
detailView: DetailView,
|
||||||
onFeatureSelect,
|
onFeatureSelect,
|
||||||
setIsSearchModalOpen,
|
setIsSearchModalOpen,
|
||||||
onCheckedLayersChange,
|
onCheckedLayersChange,
|
||||||
searchBar: SearchBar,
|
searchBar: SearchBar,
|
||||||
waterDepth: WaterDepth,
|
waterDepth: WaterDepth,,
|
||||||
|
height:height="h-[calc(100vh-10rem)]",
|
||||||
}) {
|
}) {
|
||||||
const mapRef = useRef();
|
const mapRef = useRef();
|
||||||
const [mapObject, setMapObject] = useState({});
|
const [mapObject, setMapObject] = useState({});
|
||||||
const [tabVisible, setTabVisible] = useState(true);
|
const [tabVisible, setTabVisible] = useState(true);
|
||||||
const [layerNm, setLayerNm] = useState('')
|
const [layerNm, setLayerNm] = useState("");
|
||||||
// const [isOpen, setIsOpen] = useState(false); // 팝업 열기/닫기 상태
|
// const [isOpen, setIsOpen] = useState(false); // 팝업 열기/닫기 상태
|
||||||
// const [featureData, setFeatureData] = useState(null) // 선택된 피쳐 데이터
|
// const [featureData, setFeatureData] = useState(null) // 선택된 피쳐 데이터
|
||||||
// const [isSearchModalOpen, setIsSearchModalOpen] = useState(false); // SearchModal 열림 상태
|
// const [isSearchModalOpen, setIsSearchModalOpen] = useState(false); // SearchModal 열림 상태
|
||||||
const gisCore = useMemo(() => new GisApp.core({ targetId: mapRef.current }), []);
|
const gisCore = useMemo(
|
||||||
const mapInstanceRef = useRef(null);
|
() => new GisApp.core({ targetId: mapRef.current }),
|
||||||
const checkedLayerIds = useRef([]);
|
[],
|
||||||
const layerNmRef = useRef('')
|
);
|
||||||
|
const mapInstanceRef = useRef(null);
|
||||||
|
const checkedLayerIds = useRef([]);
|
||||||
|
const layerNmRef = useRef("");
|
||||||
|
|
||||||
// 팝업 데이터를 저장할 상태와 오버레이 참조를 저장할 ref 추가
|
// 팝업 데이터를 저장할 상태와 오버레이 참조를 저장할 ref 추가
|
||||||
// const [facilityInfoPopupData, setFacilityInfoPopupData] = useState([]);
|
// const [facilityInfoPopupData, setFacilityInfoPopupData] = useState([]);
|
||||||
// const facilityOverlaysRef = useRef([]);
|
// const facilityOverlaysRef = useRef([]);
|
||||||
// 체크된 레이어 상태 관리
|
// 체크된 레이어 상태 관리
|
||||||
const [checkedLayers, setCheckedLayers] = useState([]);
|
const [checkedLayers, setCheckedLayers] = useState([]);
|
||||||
const [checkedLayersData, setCheckedLayersData] = useState([]);
|
const [checkedLayersData, setCheckedLayersData] = useState([]);
|
||||||
|
|
||||||
let gisMap = null;
|
let gisMap = null;
|
||||||
const closePopup = () => {
|
const closePopup = () => {
|
||||||
setIsOpen(false); // 팝업 닫기
|
setIsOpen(false); // 팝업 닫기
|
||||||
setFeatureData(null)
|
setFeatureData(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Feature Click Event
|
// Feature Click Event
|
||||||
const handleFeatureSelect = useCallback((data) => {
|
const handleFeatureSelect = useCallback(
|
||||||
onFeatureSelect?.(data); // 선택된 피쳐 데이터 콜백 호출
|
(data) => {
|
||||||
}, [mapInstanceRef]);
|
onFeatureSelect?.(data); // 선택된 피쳐 데이터 콜백 호출
|
||||||
|
},
|
||||||
|
[mapInstanceRef],
|
||||||
|
);
|
||||||
|
|
||||||
// 지도 생성 및 초기화
|
// 지도 생성 및 초기화
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!mapRef.current) return;
|
if (!mapRef.current) return;
|
||||||
if (mapInstanceRef.current) return; // 이미 생성된 맵이 있다면 중단
|
if (mapInstanceRef.current) return; // 이미 생성된 맵이 있다면 중단
|
||||||
|
|
||||||
// EPSG:5179 등록
|
// EPSG:5179 등록
|
||||||
proj4.defs([
|
proj4.defs([
|
||||||
[
|
[
|
||||||
'EPSG:5179',
|
"EPSG:5179",
|
||||||
'+proj=tmerc +lat_0=38 +lon_0=127.5 +k=0.9996 +x_0=1000000 +y_0=2000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs',
|
"+proj=tmerc +lat_0=38 +lon_0=127.5 +k=0.9996 +x_0=1000000 +y_0=2000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs",
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
register(proj4);
|
register(proj4);
|
||||||
|
|
||||||
// OpenLayers 지도 객체 생성
|
// OpenLayers 지도 객체 생성
|
||||||
const map = new OlMap({
|
const map = new OlMap({
|
||||||
layers: [gisCore.baseLayers['base'], gisCore.baseLayers['satellite']],
|
layers: [gisCore.baseLayers["base"], gisCore.baseLayers["satellite"]],
|
||||||
renderer: 'webgl',
|
renderer: "webgl",
|
||||||
target: mapRef.current,
|
target: mapRef.current,
|
||||||
interactions: defaults({ doubleClickZoom: false }),
|
interactions: defaults({ doubleClickZoom: false }),
|
||||||
controls: defaultControls({
|
controls: defaultControls({
|
||||||
zoom: false,
|
zoom: false,
|
||||||
rotate: false,
|
rotate: false,
|
||||||
attributionOptions: {
|
attributionOptions: {
|
||||||
collapsible: false,
|
collapsible: false,
|
||||||
},
|
},
|
||||||
}).extend([]),
|
}).extend([]),
|
||||||
view: new View({
|
view: new View({
|
||||||
projection: GisApp.TO_PROJ,
|
projection: GisApp.TO_PROJ,
|
||||||
zoom: gisCore.defaults.zoom,
|
zoom: gisCore.defaults.zoom,
|
||||||
center: olProj.transform(
|
center: olProj.transform(
|
||||||
[127.4875, 37.4916],
|
[127.4875, 37.4916],
|
||||||
GisApp.FROM_PROJ,
|
GisApp.FROM_PROJ,
|
||||||
GisApp.TO_PROJ
|
GisApp.TO_PROJ,
|
||||||
),
|
),
|
||||||
minZoom: gisCore.defaults.minZoom,
|
minZoom: gisCore.defaults.minZoom,
|
||||||
maxZoom: gisCore.defaults.maxZoom,
|
maxZoom: gisCore.defaults.maxZoom,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
gisMaps.current = map
|
gisMaps.current = map;
|
||||||
|
|
||||||
// 미니맵 추가
|
// 미니맵 추가
|
||||||
if (isMiniMap) {
|
if (isMiniMap) {
|
||||||
const overviewMap = new OverviewMap({
|
const overviewMap = new OverviewMap({
|
||||||
layers: [GisApp.Module.core.baseMiniMapLayers['base']],
|
layers: [GisApp.Module.core.baseMiniMapLayers["base"]],
|
||||||
view: new View({
|
view: new View({
|
||||||
projection: GisApp.TO_PROJ,
|
projection: GisApp.TO_PROJ,
|
||||||
minZoom: 9,
|
minZoom: 9,
|
||||||
}),
|
}),
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
collapseLabel: '\u00BB',
|
collapseLabel: "\u00BB",
|
||||||
label: '\u00AB',
|
label: "\u00AB",
|
||||||
});
|
});
|
||||||
map.addControl(overviewMap);
|
map.addControl(overviewMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 스케일 컨트롤 및 베이스 레이어 설정
|
// 스케일 컨트롤 및 베이스 레이어 설정
|
||||||
gisCore.__proto__.map = map;
|
gisCore.__proto__.map = map;
|
||||||
gisCore.scaleControl();
|
gisCore.scaleControl();
|
||||||
gisCore.changeBaseLayer('base');
|
gisCore.changeBaseLayer("base");
|
||||||
setMapObject({ map: map });
|
setMapObject({ map: map });
|
||||||
mapInstanceRef.current = map; // 생성 완료 플래그 설정
|
mapInstanceRef.current = map; // 생성 완료 플래그 설정
|
||||||
|
}, []);
|
||||||
|
|
||||||
}, []);
|
// treeData 변경 시 레이어 코드 생성
|
||||||
|
useEffect(() => {
|
||||||
|
if (!treeData || treeData.length === 0) return;
|
||||||
|
|
||||||
// treeData 변경 시 레이어 코드 생성
|
// 기존 오버레이 및 레이어 모두 삭제
|
||||||
useEffect(() => {
|
gisCore.deleteAllOverlay();
|
||||||
if (!treeData || treeData.length === 0) return;
|
gisCore.deleteAllLayer();
|
||||||
|
|
||||||
// 기존 오버레이 및 레이어 모두 삭제
|
// 트리 데이터를 레이어 코드 객체로 변환
|
||||||
gisCore.deleteAllOverlay();
|
const layerCode = gisCore.convertLayerInfosToLayerCode(treeData, "lyrSn");
|
||||||
gisCore.deleteAllLayer();
|
GisApp.layerCode = layerCode; // 전역 레이어 코드 설정
|
||||||
|
|
||||||
// 트리 데이터를 레이어 코드 객체로 변환
|
//setTreeData(data);
|
||||||
const layerCode = gisCore.convertLayerInfosToLayerCode(treeData, 'lyrSn');
|
// 편집 가능한 레이어 목록 생성
|
||||||
GisApp.layerCode = layerCode; // 전역 레이어 코드 설정
|
//const layerItems = getLayerItems(layerCode);
|
||||||
|
//setEditLayerItems(prev => [...layerItems])
|
||||||
|
}, [treeData]);
|
||||||
|
|
||||||
//setTreeData(data);
|
const getLayerItems = (layerCode) => {
|
||||||
// 편집 가능한 레이어 목록 생성
|
const layerItems = Object.entries(layerCode)
|
||||||
//const layerItems = getLayerItems(layerCode);
|
.filter(([key, obj], idx) => obj?.updtPsblYn === "Y")
|
||||||
//setEditLayerItems(prev => [...layerItems])
|
.map(([key, obj]) => ({
|
||||||
}, [treeData]);
|
...obj,
|
||||||
|
name: obj.lyrNm,
|
||||||
|
label: obj.lyrNm,
|
||||||
|
value: obj.lyrSn + "",
|
||||||
|
}))
|
||||||
|
.sort((a, b) => {
|
||||||
|
if (a.sortOrdr > b.sortOrdr) return 1;
|
||||||
|
if (a.sortOrdr < b.sortOrdr) return -1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
return layerItems;
|
||||||
|
};
|
||||||
|
|
||||||
const getLayerItems = (layerCode) => {
|
if (mapObject.map) {
|
||||||
const layerItems = Object.entries(layerCode)
|
try {
|
||||||
.filter(([key, obj], idx) => obj?.updtPsblYn === 'Y')
|
gisMap = mapObject.map;
|
||||||
.map(([key, obj]) => ({
|
} catch (e) {
|
||||||
...obj,
|
console.error("오류 발생:", e); // 시큐어코딩 관련 수정 : 오류 정보를 로그로 출력
|
||||||
name: obj.lyrNm,
|
}
|
||||||
label: obj.lyrNm,
|
}
|
||||||
value: obj.lyrSn + '',
|
|
||||||
}))
|
|
||||||
.sort((a, b) => {
|
|
||||||
if (a.sortOrdr > b.sortOrdr) return 1;
|
|
||||||
if (a.sortOrdr < b.sortOrdr) return -1;
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
return layerItems;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (mapObject.map) {
|
// 체크된 레이어 정보를 처리하는 함수
|
||||||
try {
|
const handleCheckedLayersChange = useCallback(
|
||||||
gisMap = mapObject.map;
|
(checkedIds, checkedNodesData) => {
|
||||||
} catch (e) {
|
setTimeout(() => {
|
||||||
console.error('오류 발생:', e); // 시큐어코딩 관련 수정 : 오류 정보를 로그로 출력
|
setCheckedLayers(checkedIds);
|
||||||
}
|
setCheckedLayersData(checkedNodesData);
|
||||||
}
|
onCheckedLayersChange?.(checkedIds, checkedNodesData);
|
||||||
|
}, 1000);
|
||||||
|
},
|
||||||
|
[onCheckedLayersChange],
|
||||||
|
);
|
||||||
|
|
||||||
// 체크된 레이어 정보를 처리하는 함수
|
return (
|
||||||
const handleCheckedLayersChange = useCallback((checkedIds, checkedNodesData) => {
|
<>
|
||||||
setTimeout(() => {
|
<GisContext.Provider
|
||||||
setCheckedLayers(checkedIds);
|
value={{
|
||||||
setCheckedLayersData(checkedNodesData);
|
gisCore,
|
||||||
onCheckedLayersChange?.(checkedIds, checkedNodesData);
|
gisMap: mapInstanceRef.current,
|
||||||
}, 1000);
|
treeData,
|
||||||
}, [onCheckedLayersChange]);
|
checkedLayerIds,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className={`relative flex ${height}`}>
|
||||||
|
<div
|
||||||
|
ref={mapRef}
|
||||||
|
className="gis-map relative flex-1"
|
||||||
|
style={{ height: "100%", padding: 0 }}
|
||||||
|
>
|
||||||
|
<GisTree
|
||||||
|
visible={tabVisible}
|
||||||
|
setVisible={setTabVisible}
|
||||||
|
onCheckedChange={handleCheckedLayersChange}
|
||||||
|
onLayerIconClick={(layerNm) => {
|
||||||
|
layerNmRef.current = layerNm;
|
||||||
|
setLayerNm(layerNm);
|
||||||
|
setIsOpen(true);
|
||||||
|
const dummyFeature = {
|
||||||
|
getProperties: () => ({}), // 최소 구조
|
||||||
|
};
|
||||||
|
onFeatureSelect(dummyFeature);
|
||||||
|
}}
|
||||||
|
imageVisible={imgVisble}
|
||||||
|
/>
|
||||||
|
|
||||||
return (
|
{/* DetailView가 존재할 때만 렌더링 isSearchModalOpen이 true면 visible=false로 팝업 숨김 */}
|
||||||
<>
|
{isOpen && !isSearchModalOpen && (
|
||||||
<GisContext.Provider value={{ gisCore, gisMap: mapInstanceRef.current, treeData, checkedLayerIds }}>
|
<DetailView
|
||||||
<div className="h-[calc(100vh-10rem)] flex relative">
|
featureData={featureData || { getProperties: () => ({}) }}
|
||||||
<div ref={mapRef} className="gis-map flex-1 relative" style={{ height: '100%', padding: 0 }} >
|
seletectedLayerNm={layerNm}
|
||||||
<GisTree
|
onClose={closePopup} // 닫기 콜백 전달
|
||||||
visible={tabVisible}
|
onFeatureSelect={handleFeatureSelect}
|
||||||
setVisible={setTabVisible}
|
/>
|
||||||
onCheckedChange={handleCheckedLayersChange}
|
)}
|
||||||
onLayerIconClick={(layerNm) => {
|
{/* SearchView가 존재할 때만 렌더링 */}
|
||||||
layerNmRef.current = layerNm
|
{SearchView && (
|
||||||
setLayerNm(layerNm); setIsOpen(true); const dummyFeature = {
|
<SearchView
|
||||||
getProperties: () => ({}), // 최소 구조
|
open={isSearchModalOpen}
|
||||||
};
|
onOpenChange={setIsSearchModalOpen}
|
||||||
onFeatureSelect(dummyFeature);
|
onFeatureSelect={handleFeatureSelect}
|
||||||
}}
|
/>
|
||||||
imageVisible={imgVisble}
|
)}
|
||||||
/>
|
{/* 시도/시군구 조회 영역 */}
|
||||||
|
{SearchBar && (
|
||||||
{/* DetailView가 존재할 때만 렌더링 isSearchModalOpen이 true면 visible=false로 팝업 숨김 */}
|
<div
|
||||||
{isOpen && !isSearchModalOpen && (
|
className="absolute left-1/2 top-4 z-30 -translate-x-1/2 rounded w-max"
|
||||||
<DetailView
|
>
|
||||||
featureData={featureData || { getProperties: () => ({}) }}
|
<SearchBar />
|
||||||
seletectedLayerNm={layerNm}
|
</div>
|
||||||
onClose={closePopup} // 닫기 콜백 전달
|
)}
|
||||||
onFeatureSelect={handleFeatureSelect}
|
<GisToolBar />
|
||||||
/>
|
<GisMapToggle />
|
||||||
)}
|
<GisSelect onFeatureSelect={handleFeatureSelect} />
|
||||||
{/* SearchView가 존재할 때만 렌더링 */}
|
|
||||||
{SearchView && (
|
|
||||||
<SearchView
|
|
||||||
open={isSearchModalOpen}
|
|
||||||
onOpenChange={setIsSearchModalOpen}
|
|
||||||
onFeatureSelect={handleFeatureSelect}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{/* 시도/시군구 조회 영역 */}
|
|
||||||
{SearchBar && (
|
|
||||||
<div className="absolute top-4 left-1/2 -translate-x-1/2 z-30 bg-gray-300 rounded " style={{ maxWidth: 'calc(100% - 2rem)' }}>
|
|
||||||
<SearchBar/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<GisToolBar />
|
|
||||||
<GisMapToggle />
|
|
||||||
<GisSelect onFeatureSelect={handleFeatureSelect} />
|
|
||||||
{typeof WaterDepth === "function" && <WaterDepth onClose={() => setIsOpen(false)} />}
|
{typeof WaterDepth === "function" && <WaterDepth onClose={() => setIsOpen(false)} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isSearch && (
|
{isSearch && (
|
||||||
<div className="absolute right-8 top-[305px] z-20">
|
<div className="absolute right-8 top-[305px] z-20">
|
||||||
<button
|
<button
|
||||||
onClick={() => setIsSearchModalOpen(true)}
|
onClick={() => setIsSearchModalOpen(true)}
|
||||||
className="overflow-hidden w-[40px] h-[40px] bg-white
|
className="flex h-[40px] w-[40px] items-center justify-center overflow-hidden rounded border border-[#9aa7b8] bg-white p-0 shadow-[0_0_5px_#999]"
|
||||||
border border-[#9aa7b8]
|
>
|
||||||
rounded
|
<Search size={24} className="text-gray-700" />
|
||||||
shadow-[0_0_5px_#999]
|
</button>
|
||||||
flex items-center justify-center
|
</div>
|
||||||
p-0
|
)}
|
||||||
"
|
</GisContext.Provider>
|
||||||
>
|
</>
|
||||||
<Search size={24} className="text-gray-700" />
|
);
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</GisContext.Provider>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default React.memo(Gis);
|
export default React.memo(Gis);
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ export default React.memo(function GisTree({ checkedNodes = [], setCheckedNodes
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className={`absolute top-0 left-0 w-[250px] h-[calc(100vh-10rem)] bg-white border-r border-gray-300 flex flex-col overflow-hidden transition-all duration-300 z-40
|
className={`absolute top-0 left-0 w-[250px] h-full bg-white border-r border-gray-300 flex flex-col overflow-hidden transition-all duration-300 z-40
|
||||||
${visible ? 'translate-x-0 opacity-100' : '-translate-x-full opacity-0 pointer-events-none'}`}
|
${visible ? 'translate-x-0 opacity-100' : '-translate-x-full opacity-0 pointer-events-none'}`}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -143,11 +143,11 @@ GisOlLayer.prototype = {
|
|||||||
let source;
|
let source;
|
||||||
|
|
||||||
let lyrTyNm = option.lyrTyNm;
|
let lyrTyNm = option.lyrTyNm;
|
||||||
if(lyrTyNm == 'tb_ms_flood_dngr_map'
|
if(lyrTyNm == 'tb_ms_flood_dngr_map' //침수위험지도
|
||||||
|| lyrTyNm == 'tb_ms_sbmrg_dngr_map'
|
|| lyrTyNm == 'tb_ms_sbmrg_dngr_map' //도시침수지도
|
||||||
|| lyrTyNm == 'tb_ms_swage_mhl'
|
|| lyrTyNm == 'tb_ms_swage_mhl' //맨홀
|
||||||
|| lyrTyNm == 'tb_ms_swage_ppl'
|
|| lyrTyNm == 'tb_ms_swage_ppl' //관로
|
||||||
|| lyrTyNm == 'tb_ms_swage_pmstn'
|
|| lyrTyNm == 'tb_ms_swage_pmstn' //펌프장
|
||||||
) {
|
) {
|
||||||
source = this.getVectorSourceBbox(option);
|
source = this.getVectorSourceBbox(option);
|
||||||
}else {
|
}else {
|
||||||
|
|||||||