dm: 수요신청현황 시도,시군구

This commit is contained in:
2026-05-07 10:47:15 +09:00
parent 0b300a2f0e
commit 2e3998976a
13 changed files with 93 additions and 68 deletions
@@ -1,6 +1,7 @@
"use client";
import Gis from "@common/business_components/ui/map/Gis";
import "@/app/commonOrigin.css";
import { useEffect, useRef, useState } from "react";
import { mapService } from "../service";
import GisApp from "@common/business_components/ui/map/lib/gis.core";
@@ -22,32 +22,36 @@ export default function SelectedFcltList({
const TableContent = (
<>
<thead className="bg-gray-100 text-gray-600 text-[11px] font-medium border-b border-cyan-800">
<thead className="bg-gray-100 text-gray-700 text-[13px]">
<tr>
<th className="px-2 py-1.5 text-left w-1/3">시설명</th>
<th className="px-2 py-1.5 text-right whitespace-nowrap">
처리량(㎥/일)
<th className="px-3 py-2 text-left border-b">시설명</th>
<th className="px-3 py-2 text-right border-b">
하수처리량
<br />
(㎥/일)
</th>
<th className="px-2 py-1.5 text-right whitespace-nowrap">
재이용량(㎥/일)
<th className="px-3 py-2 text-right border-b">
재이용량
<br />
(㎥/일)
</th>
<th className="px-2 py-1.5 text-center w-10">삭제</th>
<th className="px-3 py-2 border-b">삭제</th>
</tr>
</thead>
<tbody>
{data.map((item) => (
<tr key={item.pbnstRuseFcltId} className="border-b border-gray-100 last:border-none hover:bg-gray-50/50">
<td className="px-2 py-1.5 text-[11px] font-medium text-gray-800 break-keep">{item.ruseUtztnFcltNm}</td>
<td className="px-2 py-1.5 text-right text-[11px] text-gray-600">
<tr key={item.pbnstRuseFcltId} className="border-b last:border-none">
<td className="px-3 py-2 text-[12px]">{item.ruseUtztnFcltNm}</td>
<td className="px-3 py-2 text-right text-[12px]">
{Number(item.splyExtraCpct || 0).toLocaleString()}
</td>
<td className="px-2 py-1.5 text-right text-[11px] text-gray-600">
<td className="px-3 py-2 text-right text-[12px]">
{Number(item.ruseCpct || 0).toLocaleString()}
</td>
<td className="px-2 py-1.5 text-center">
<td className="px-3 py-2 text-center">
<button
onClick={() => handleDelete(item.pbnstRuseFcltId)}
className="text-gray-400 hover:text-red-500 text-[11px] font-bold transition-colors"
className="text-red-500 hover:text-red-700 text-sm font-bold"
aria-label="삭제"
title="삭제"
>
@@ -61,12 +65,12 @@ export default function SelectedFcltList({
);
return (
<div className="fixed right-20 top-[3.5rem] w-[22rem] max-h-[80vh] overflow-hidden bg-white/95 backdrop-blur-sm shadow-[0_4px_12px_rgba(0,0,0,0.1)] rounded-lg border border-gray-200 z-50 flex flex-col">
<h3 className="bg-cyan-700 text-white text-[13px] font-semibold p-2">
<div className="fixed right-40 top-[8rem] w-[40rem] max-h-[130rem] overflow-auto bg-white shadow-lg rounded p-4 border border-gray-300 z-50">
<h3 className="bg-cyan-700 text-white text-xl font-bold mb-2 p-2">
선택된 시설
</h3>
<div className="overflow-y-auto w-full">
<table className="w-full text-sm text-gray-800 border-t border-gray-200 table-fixed">
<div className="overflow-x-auto">
<table className="w-full text-sm text-gray-800 border border-gray-200">
{TableContent}
</table>
</div>
@@ -455,7 +455,7 @@ export default function DemandPlaceRegisterPage() {
}
alert("수요처 등록 완료!");
router.push("/apply/register");
router.push("/apply/dmdinfo"); // 수요정보등록
}
setPw("");
@@ -1,4 +1,3 @@
// app/(with-layout)/apply/register/page.tsx
/**
* 수요정보등록(수정) 화면
*
@@ -126,7 +126,7 @@ function DateInput({
}
export default function DemandStatusPage() {
const { getSdmInfoStatusList, updateSdmInfoData, Sdm, Common } = useDmStore((state) => state);
const { getSdmInfoStatusList, updateSdmInfoData, Sdm, Common, initializeCommonData } = useDmStore((state) => state);
const { successLogin, sdmInfoStatusList } = Sdm;
const { selectSidoData, selectSigunData } = Common;
@@ -154,8 +154,9 @@ export default function DemandStatusPage() {
}, []);
useEffect(() => {
getUseTypesData();
}, [getUseTypesData]);
getUseTypesData(); // 용도코드 조회
initializeCommonData(); // 시도, 시군구 조회
}, [getUseTypesData, initializeCommonData]);
useEffect(() => {
if (!successLogin && !isLoginStorageInfo) return;
+13 -2
View File
@@ -1,8 +1,11 @@
// apps/dm/app/(landing)/reuse/page.tsx
/**
* 대민 메인 페이지(첫페이지)
*/
"use client";
import { useMemo } from "react";
import { useEffect, useMemo } from "react";
import TopNav from "@/components/TopNav";
import { removeCookie } from "@/src/shared/lib";
import SideIndicator from "./SideIndicator";
import { useScrollSpy } from "./_hooks/useScrollSpy";
@@ -11,6 +14,9 @@ import IntroCards from "./_sections/IntroCards";
import Cases from "./_sections/Cases";
import ProcessFlow from "./_sections/ProcessFlow";
const CLAIM_NAME = "Authorization";
const AUTH_USER_ID = "token-id";
const LANDING_SECTIONS = [
{ id: "main", label: "Main" },
{
@@ -34,6 +40,11 @@ export default function ReuseLandingPage() {
const sectionIds = useMemo(() => LANDING_SECTIONS.map((s) => s.id), []);
const activeId = useScrollSpy(sectionIds);
useEffect(() => {
removeCookie(CLAIM_NAME);
removeCookie(AUTH_USER_ID);
}, []);
return (
<main className="bg-white">
+1 -1
View File
@@ -496,7 +496,7 @@ export const CommonReducer:(set:any)=>CommonAction=(set: any) => {
}
})
)},
fetchAnonymousMenu: async (siteId = REUSE_SITE_ID) => fetchAnonymousMenu(siteId)
fetchAnonymousMenu: async (siteId = REUSE_SITE_ID) => fetchAnonymousMenu(siteId),
}
}
export type CommonStore = CommonType & CommonAction;
+1 -1
View File
@@ -759,7 +759,7 @@ export const SdmReducer = (set: any): SdmActions => {
}
}))
},
// 용도 코드 조회 (WR018 : 하수재이용장외용도)
getUseTypesData: async () => {
//http://dev.onasys.co.kr:3000/server/cms-service/api/v1/lwpo-cds?lwpoCdNm=&sort=regDt,desc&upCd=WR018&page=0&size=10
+1 -1
View File
@@ -15,7 +15,7 @@ type Props = {
const defaultMenus: LnbMenu[] = [
{ label: "수요처", href: "/apply/dmdco" },
{ label: "수요정보등록", href: "/apply/register" },
{ label: "수요정보등록", href: "/apply/dmdinfo" },
{ label: "수요신청현황", href: "/apply/status" },
];
+15 -5
View File
@@ -1,3 +1,6 @@
/**
* 로그인 modal
*/
"use client";
import { useEffect, useId, useState } from "react";
@@ -42,6 +45,16 @@ export default function LoginModal({ open, onClose, onSuccess }: LoginModalProps
const [touched, setTouched] = useState<Partial<Record<FieldKey, boolean>>>({});
const [submitting, setSubmitting] = useState(false);
const resetForm = () => {
setBizNo("");
setWorkerNo("");
setNoWorker(true);
setPw("");
setErrors({});
setTouched({});
setSubmitting(false);
};
useEffect(() => {
if (!open) return;
const onKeyDown = (e: KeyboardEvent) => {
@@ -53,13 +66,10 @@ export default function LoginModal({ open, onClose, onSuccess }: LoginModalProps
const prev = document.body.style.overflow;
document.body.style.overflow = "hidden"; // 모달 오픈 시 배경 스크롤 방지
// 모달 오픈 시 에러/터치 초기화
setErrors({});
setTouched({});
return () => {
window.removeEventListener("keydown", onKeyDown);
document.body.style.overflow = prev;
resetForm();
};
}, [open, onClose]);
@@ -142,7 +152,7 @@ export default function LoginModal({ open, onClose, onSuccess }: LoginModalProps
const parsed = JSON.parse(sessionUser) as { dmdCoNm?: string };
onSuccess?.({ userName: parsed.dmdCoNm ?? "수요처" });
onClose();
router.refresh();
router.push("/apply/status");
}
} finally {
setSubmitting(false);
@@ -94,7 +94,7 @@ export default function SearchInputText({
value={textValue || ""}
onChange={handleInputChange}
onKeyDown={handleKeyDown}
className="w-full h-8 text-xs pl-2 pr-2 text-gray-600 border border-gray-300 rounded focus:outline-none focus:ring-1 focus:ring-blue-500"
className="w-full h-[3.2rem] !text-xl pl-3 text-gray-600 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder={`${label}을(를) 입력하세요`}
onClick={() => {
setTextValue("");
@@ -109,10 +109,10 @@ export default function SearchInputText({
searchList.map((item, index) => (
<div
key={index}
className={`w-full cursor-pointer px-3 py-2 text-left text-xs ${
className={`w-full cursor-pointer overflow-auto px-5 py-3 text-left !text-xl ${
highlightIndex === index
? "bg-blue-50"
: "hover:bg-gray-50"
? "bg-blue-100"
: "hover:bg-gray-100"
}`}
onClick={() => handleSuggestionClick(item.bscFctNm)}
role="button"
@@ -127,7 +127,7 @@ export default function SearchInputText({
</div>
))
) : (
<div className="text-xs w-full px-3 py-2 hover:bg-gray-50 cursor-pointer text-gray-500">
<div className="!text-xl w-full px-5 py-3 hover:bg-gray-100 cursor-pointer overflow-auto">
검색 결과가 없습니다.
</div>
)}
@@ -62,51 +62,50 @@ export function SearchBar({
);
return (
<div className="flex justify-center w-full px-4 py-2">
<div className="flex items-center w-auto shadow-md px-4 py-2 space-x-2 bg-white/95 backdrop-blur-sm rounded-lg text-sm border border-gray-200">
<div className="flex justify-center w-full px-4 py-3">
<div className="flex items-center w-full max-w-screen-lg rounded-xl bg-white shadow-md px-6 py-4 space-x-3">
<SelectBox
labelClass="w-[50px] text-xs font-medium text-gray-700"
className="w-[110px]"
labelClass="w-[40px]"
className="w-[200px]"
label="시도"
selectClass="rounded bg-white text-xs h-8"
selectClass="rounded-lg bg-white"
selectArray={Common.selectSidoData || []}
onSelectValue={(val) => onSelectValue(val.toString(), "ctpvCd")}
value={sidoValue || Common.selectSidoData[0]?.val || ""}
/>
<SelectBox
labelClass="w-[70px] text-xs font-medium text-gray-700"
className="w-[110px]"
labelClass="w-[65px]"
className="w-[200px]"
label="시군구"
selectClass="rounded bg-white text-xs h-8"
selectClass="rounded-lg bg-white"
selectArray={filteredSigunData || []}
onSelectValue={(val) => onSelectValue(val.toString(), "sggCd")}
value={sigunValue}
/>
<Label className="text-gray-700 text-xs font-medium pl-2 pr-1">하수재이용시설</Label>
<div className="w-[180px]">
<SearchInputText
label="시설명 입력"
initValue={undefined}
setValue={(searchNm?: string) => {
let sggOrCity = "";
if (searchNm) {
if (sigunValue === "0" || sigunValue === "") {
sggOrCity = sidoValue;
} else {
sggOrCity = sigunValue;
}
findRuseFclt(sggOrCity, searchNm);
<Label className="text-gray-600">하수재이용시설</Label>
<SearchInputText
label="시설명"
initValue={undefined}
setValue={(searchNm?: string) => {
let sggOrCity = "";
if (searchNm) {
if (sigunValue === "0" || sigunValue === "") {
sggOrCity = sidoValue;
} else {
sggOrCity = sigunValue;
}
}}
setRtnData={(rtnData: any) => {
setHasuPk(rtnData);
}}
searchList={map.ruseFcltList || []}
/>
</div>
findRuseFclt(sggOrCity, searchNm);
}
}}
setRtnData={(rtnData: any) => {
setHasuPk(rtnData);
}}
searchList={map.ruseFcltList || []}
/>
<Button
color="sky"
className="ml-2 text-white !h-8 !py-0 !px-3 !text-xs font-semibold rounded"
className="ml-2 text-white"
size="sm"
onClick={() => {
onApply();
}}
+1 -1
View File
@@ -8,7 +8,7 @@ const serverApiUrl = process.env.NEXT_PUBLIC_CS_SERVER_API_URL;
const GEOSERVER_URL = process.env.NEXT_PUBLIC_GEOSERVER_URL || "";
const LX_GEOSERVER_URL = process.env.NEXT_PUBLIC_LX_GEOSERVER_URL || "";
const GATEWAY_URL = process.env.NEXT_PUBLIC_GATEWAY_URL || "";
const SEWERAGE_API_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || "";
// const SEWERAGE_API_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || "";
const BUSINESS_JUSO_API_URL = process.env.NEXT_PUBLIC_FINDADRESS_URL || "";
const AdressKey = process.env.NEXT_PRIVATE_WR_ADDRESS_KEY || "";