diff --git a/.gitignore b/.gitignore index 7175c78d4..ee2cfd052 100644 --- a/.gitignore +++ b/.gitignore @@ -4,10 +4,7 @@ # dependencies node_modules/ - -# build -.next/ -dist/ +.idea/ # build .next @@ -22,9 +19,14 @@ apps/fo/.next/**/* #.env* .qodo +# next-agents-md +.next-docs/ + pnpm-lock.yaml settings.json .npmrc .cursor +.agent - +apps/**/tsconfig.tsbuildinfo +logs/ diff --git a/.husky/pre-push b/.husky/pre-push index 0ddfdb46e..2adeaead9 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -3,4 +3,8 @@ BRANCH=$(git rev-parse --abbrev-ref HEAD) if [ "$BRANCH" != "main" ]; then exit 0 fi +echo "Branch: $BRANCH" +echo "Changed packages (dry-run):" +pnpm turbo run build --filter="...[origin/$BRANCH]" --dry-run +echo "Starting build..." pnpm turbo run build --filter="...[origin/$BRANCH]" diff --git a/apps/_template/.env.example b/apps/_template/.env.example index b2d706024..f9794a6f8 100644 --- a/apps/_template/.env.example +++ b/apps/_template/.env.example @@ -3,3 +3,6 @@ NEXT_PUBLIC_PORT= NEXT_PUBLIC_PROXY_HOST= NEXT_PUBLIC_SITE_ID= NEXT_PUBLIC_SERVER_API_URL= + +# 401 시 브라우저 리다이렉트 대상 +NEXT_PUBLIC_AUTH_LOGIN_REDIRECT_URL=/auth/login diff --git a/apps/_template/package.json b/apps/_template/package.json index fb27f8af7..17b53990f 100644 --- a/apps/_template/package.json +++ b/apps/_template/package.json @@ -25,7 +25,7 @@ }, "devDependencies": { "eslint": "^9.0.0", - "eslint-config-next": "15.4.0", + "eslint-config-next": "15.3.8", "postcss": "^8.4.49", "prettier": "^3.4.2", "prettier-plugin-tailwindcss": "^0.6.11", diff --git a/apps/cm/package.json b/apps/cm/package.json index 9d4e1da8f..bde698393 100644 --- a/apps/cm/package.json +++ b/apps/cm/package.json @@ -52,7 +52,7 @@ "@types/node": "^22.13.1", "@types/webpack": "^5.28.5", "eslint": "^9.0.0", - "eslint-config-next": "15.4.0", + "eslint-config-next": "15.3.8", "postcss": "^8.4.49", "prettier": "^3.4.2", "prettier-plugin-tailwindcss": "^0.6.11", diff --git a/apps/cm/src/entities/auth/lib/auth-wrapper.tsx b/apps/cm/src/entities/auth/lib/auth-wrapper.tsx index 1aa4f8e61..5366696f7 100644 --- a/apps/cm/src/entities/auth/lib/auth-wrapper.tsx +++ b/apps/cm/src/entities/auth/lib/auth-wrapper.tsx @@ -5,16 +5,15 @@ import { useRouter } from "next/navigation"; import { client } from "@/shared/api"; import type { IUserInfo } from "@/shared/store"; import { getCookie, useUserStore } from "@/shared/lib"; +import { isAtLoginRedirectUrl } from "@common/network"; import { ENDPOINT, AUTH_USER_ID } from "@/shared/config"; -import { LoginApi } from "../api/login-service"; const AuthWrapper = ({ children }: { children: React.ReactNode }) => { const router = useRouter(); const { userInfo, setUserInfo } = useUserStore((state) => state); async function authCheck() { - // 로그인 페이지에서는 인증 체크를 건너뜀 - if (window.location.pathname === '/auth/login') { + if (isAtLoginRedirectUrl("/auth/login")) { return; } @@ -35,13 +34,8 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => { await authCheck(); } catch (error) { console.error(error); - - try { - await LoginApi.silentRefresh(); - await authCheck(); - } catch (refreshError) { - console.error("Token refresh failed:", refreshError); - setUserInfo(null); + setUserInfo(null); + if (!isAtLoginRedirectUrl("/auth/login")) { router.push("/auth/login"); } } diff --git a/apps/cm/src/pages/auth/login/ui/login-page.tsx b/apps/cm/src/pages/auth/login/ui/login-page.tsx index fed7be4ad..297d28a8f 100644 --- a/apps/cm/src/pages/auth/login/ui/login-page.tsx +++ b/apps/cm/src/pages/auth/login/ui/login-page.tsx @@ -145,11 +145,11 @@ function LoginPage() {

- 유역하수도 통합플랫폼 + 유역하수도통합플랫폼
- 통합관리시스템 + 하수도 포탈

-

유역하수도 통합플랫폼에 오신 것을 환영합니다.

+

유역하수도통합플랫폼 하수도 포탈에 오신 것을 환영합니다.

logo diff --git a/apps/common/features/next.config.ts b/apps/common/features/next.config.ts index 34965cf32..8a50ea611 100644 --- a/apps/common/features/next.config.ts +++ b/apps/common/features/next.config.ts @@ -1,6 +1,21 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { + output: "standalone", + experimental: { + proxyTimeout: 600000, + }, + eslint: { + ignoreDuringBuilds: true, + }, + typescript: { + ignoreBuildErrors: true, + }, + logging: { + fetches: { + fullUrl: true, + }, + }, async rewrites() { return { afterFiles: [ diff --git a/apps/common/features/package.json b/apps/common/features/package.json index 14a96b6f8..7118ae49d 100644 --- a/apps/common/features/package.json +++ b/apps/common/features/package.json @@ -46,7 +46,7 @@ "@types/node": "^22.13.1", "@types/webpack": "^5.28.5", "eslint": "^9", - "eslint-config-next": "15.1.7", + "eslint-config-next": "15.3.8", "postcss": "^8", "prettier": "^3.4.2", "prettier-plugin-tailwindcss": "^0.6.11", diff --git a/apps/common/features/src/entities/auth/lib/auth-wrapper.tsx b/apps/common/features/src/entities/auth/lib/auth-wrapper.tsx index e518f938a..d514569e0 100644 --- a/apps/common/features/src/entities/auth/lib/auth-wrapper.tsx +++ b/apps/common/features/src/entities/auth/lib/auth-wrapper.tsx @@ -4,13 +4,17 @@ import { useEffect } from "react"; import { client } from "@/shared/api"; import type { IUserInfo } from "@/shared/store"; import { getCookie, useUserStore } from "@/shared/lib"; +import { getAuthLoginRedirectUrl, isAtLoginRedirectUrl } from "@common/network"; import { ENDPOINT, AUTH_USER_ID } from "@/shared/config"; -import { LoginApi } from "../api/login-service"; const AuthWrapper = ({ children }: { children: React.ReactNode }) => { const { userInfo, setUserInfo } = useUserStore((state) => state); async function authCheck() { + if (isAtLoginRedirectUrl(getAuthLoginRedirectUrl())) { + return; + } + const userId = getCookie(AUTH_USER_ID); if (!userId) { throw new Error("Missing required authentication tokens"); @@ -28,8 +32,6 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => { await authCheck(); } catch (error) { console.error(error); - await LoginApi.silentRefresh(); - await authCheck(); } })(); }, []); diff --git a/apps/cs/.gitignore b/apps/cs/.gitignore index b63718b61..f80a96304 100644 --- a/apps/cs/.gitignore +++ b/apps/cs/.gitignore @@ -38,4 +38,5 @@ yarn-error.log* next-env.d.ts .env* -!.env.example \ No newline at end of file +!.env.example +/start_cs.log diff --git a/apps/cs/package.json b/apps/cs/package.json index 03ec06fcf..27f43fcc1 100644 --- a/apps/cs/package.json +++ b/apps/cs/package.json @@ -52,7 +52,7 @@ "@types/node": "^22.13.1", "@types/webpack": "^5.28.5", "eslint": "^9.0.0", - "eslint-config-next": "15.4.0", + "eslint-config-next": "15.3.8", "postcss": "^8.4.49", "prettier": "^3.4.2", "prettier-plugin-tailwindcss": "^0.6.11", diff --git a/apps/cs/src/entities/auth/lib/auth-wrapper.tsx b/apps/cs/src/entities/auth/lib/auth-wrapper.tsx index c0be4c2dd..57ae75c34 100644 --- a/apps/cs/src/entities/auth/lib/auth-wrapper.tsx +++ b/apps/cs/src/entities/auth/lib/auth-wrapper.tsx @@ -1,18 +1,24 @@ "use client"; import { useEffect } from "react"; -import { useRouter } from "next/navigation"; import { client } from "@/shared/api"; import type { IUserInfo } from "@/shared/store"; import { getCookie, useUserStore } from "@/shared/lib"; -import { ENDPOINT, AUTH_USER_ID } from "@/shared/config"; -import { LoginApi } from "../api/login-service"; +import { isAtLoginRedirectUrl } from "@common/network"; +import { + ENDPOINT, + AUTH_USER_ID, + AUTH_LOGIN_REDIRECT_URL, +} from "@/shared/config"; const AuthWrapper = ({ children }: { children: React.ReactNode }) => { - const router = useRouter(); const { userInfo, setUserInfo } = useUserStore((state) => state); async function authCheck() { + if (isAtLoginRedirectUrl(AUTH_LOGIN_REDIRECT_URL)) { + return; + } + const userId = getCookie(AUTH_USER_ID); if (!userId) { throw new Error("Missing required authentication tokens"); @@ -30,14 +36,9 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => { await authCheck(); } catch (error) { console.error(error); - - try { - await LoginApi.silentRefresh(); - await authCheck(); - } catch (refreshError) { - console.error("Token refresh failed:", refreshError); - setUserInfo(null); - router.push("/auth/login"); + setUserInfo(null); + if (!isAtLoginRedirectUrl(AUTH_LOGIN_REDIRECT_URL)) { + window.location.assign(AUTH_LOGIN_REDIRECT_URL); } } })(); diff --git a/apps/cs/src/pages/loginlog/ui/loginlog-page.tsx b/apps/cs/src/pages/loginlog/ui/loginlog-page.tsx index 7ae7990a1..d94d79c9a 100644 --- a/apps/cs/src/pages/loginlog/ui/loginlog-page.tsx +++ b/apps/cs/src/pages/loginlog/ui/loginlog-page.tsx @@ -39,10 +39,10 @@ function LoginlogPage() { const [presetDateRange, setPresetDateRange] = useState(""); const [dateRange, setDateRange] = useState(defaultDateRange); const [userId, setUserId] = useState(""); - const [errOcrnYn, setErrOcrnYn] = useState("N"); + const [errOcrnYn, setErrOcrnYn] = useState("ALL"); const [searchParams, setSearchParams] = useState({ userId: "", - errOcrnYn: "N", + errOcrnYn: "", searchDateFrom: dayjs().subtract(7, "day").format("YYYY-MM-DD"), searchDateTo: dayjs().format("YYYY-MM-DD"), sort: "lgnDt,desc", @@ -87,7 +87,7 @@ function LoginlogPage() { setSearchParams({ ...searchParams, userId, - errOcrnYn, + errOcrnYn: errOcrnYn === "ALL" ? "" : errOcrnYn, searchDateFrom: dateRange.from ? dayjs(dateRange.from).format("YYYY-MM-DD") : "", @@ -102,12 +102,12 @@ function LoginlogPage() { const handleReset = () => { setUserId(""); - setErrOcrnYn("N"); + setErrOcrnYn("ALL"); setDateRange(defaultDateRange); setSearchParams({ ...searchParams, userId: "", - errOcrnYn: "N", + errOcrnYn: "", searchDateFrom: dayjs().subtract(7, "day").format("YYYY-MM-DD"), searchDateTo: dayjs().format("YYYY-MM-DD"), }); @@ -180,6 +180,7 @@ function LoginlogPage() { + 전체 정상 오류 diff --git a/apps/cs/src/shared/config/env.ts b/apps/cs/src/shared/config/env.ts index c6373724f..95d1a4477 100644 --- a/apps/cs/src/shared/config/env.ts +++ b/apps/cs/src/shared/config/env.ts @@ -2,6 +2,8 @@ export const PORT = process.env.NEXT_PUBLIC_PORT || "3000"; export const PROXY_HOST = process.env.NEXT_PUBLIC_PROXY_HOST || `http://localhost:${PORT}`; export const SERVER_API_URL = process.env.NEXT_PUBLIC_SERVER_API_URL; +export const AUTH_LOGIN_REDIRECT_URL = + process.env.NEXT_PUBLIC_AUTH_LOGIN_REDIRECT_URL || "/auth/login"; export const SITE_ID = process.env.NEXT_PUBLIC_SITE_ID || "CS"; export const CLAIM_NAME = process.env.NEXT_PUBLIC_CLAIM_NAME || "Authorization"; export const ACCESS_TOKEN = diff --git a/apps/dc/package.json b/apps/dc/package.json index 747cdf91e..5835b9ab6 100644 --- a/apps/dc/package.json +++ b/apps/dc/package.json @@ -41,7 +41,7 @@ "@types/node": "^22.17.0", "@types/webpack": "^5.28.5", "eslint": "^9.0.0", - "eslint-config-next": "15.4.0", + "eslint-config-next": "15.3.8", "postcss": "^8.4.49", "prettier": "^3.4.2", "prettier-plugin-tailwindcss": "^0.6.11", diff --git a/apps/dc/src/entities/auth/lib/auth-wrapper.tsx b/apps/dc/src/entities/auth/lib/auth-wrapper.tsx index 1f196ed52..57ae75c34 100644 --- a/apps/dc/src/entities/auth/lib/auth-wrapper.tsx +++ b/apps/dc/src/entities/auth/lib/auth-wrapper.tsx @@ -1,20 +1,24 @@ "use client"; import { useEffect } from "react"; -import { useRouter } from "next/navigation"; import { client } from "@/shared/api"; import type { IUserInfo } from "@/shared/store"; import { getCookie, useUserStore } from "@/shared/lib"; -import { ENDPOINT, AUTH_USER_ID } from "@/shared/config"; -import { LoginApi } from "../api/login-service"; - -const CLAIM_NAME = process.env.NEXT_PUBLIC_CLAIM_NAME || "Authorization"; +import { isAtLoginRedirectUrl } from "@common/network"; +import { + ENDPOINT, + AUTH_USER_ID, + AUTH_LOGIN_REDIRECT_URL, +} from "@/shared/config"; const AuthWrapper = ({ children }: { children: React.ReactNode }) => { - const router = useRouter(); const { userInfo, setUserInfo } = useUserStore((state) => state); async function authCheck() { + if (isAtLoginRedirectUrl(AUTH_LOGIN_REDIRECT_URL)) { + return; + } + const userId = getCookie(AUTH_USER_ID); if (!userId) { throw new Error("Missing required authentication tokens"); @@ -32,14 +36,9 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => { await authCheck(); } catch (error) { console.error(error); - - try { - await LoginApi.silentRefresh(); - await authCheck(); - } catch (refreshError) { - console.error("Token refresh failed:", refreshError); - setUserInfo(null); - router.push("/auth/login"); + setUserInfo(null); + if (!isAtLoginRedirectUrl(AUTH_LOGIN_REDIRECT_URL)) { + window.location.assign(AUTH_LOGIN_REDIRECT_URL); } } })(); diff --git a/apps/dc/src/shared/config/env.ts b/apps/dc/src/shared/config/env.ts index 89d2c039c..9edea0e2d 100644 --- a/apps/dc/src/shared/config/env.ts +++ b/apps/dc/src/shared/config/env.ts @@ -3,10 +3,14 @@ export const PROXY_HOST = process.env.NEXT_PUBLIC_PROXY_HOST || `http://localhost:${PORT}`; export const SERVER_API_URL = process.env.NEXT_PUBLIC_SERVER_API_URL; -export const NEXT_PUBLIC_DC_SERVICE_API_URL = process.env.NEXT_PUBLIC_DC_SERVICE_API_URL || `http://localhost:${PORT}`; +export const NEXT_PUBLIC_DC_SERVICE_API_URL = + process.env.NEXT_PUBLIC_DC_SERVICE_API_URL || `http://localhost:${PORT}`; +export const AUTH_LOGIN_REDIRECT_URL = + process.env.NEXT_PUBLIC_AUTH_LOGIN_REDIRECT_URL || "/auth/login"; // Flask API URL -export const FLASK_API_URL = process.env.NEXT_PUBLIC_FLASK_API_URL || "http://localhost:5000"; +export const FLASK_API_URL = + process.env.NEXT_PUBLIC_FLASK_API_URL || "http://localhost:5000"; //export const SITE_ID = process.env.NEXT_PUBLIC_SITE_ID || "DC"; export const SITE_ID = "DC"; diff --git a/apps/dm/package.json b/apps/dm/package.json index 71d504f50..844e0b1aa 100644 --- a/apps/dm/package.json +++ b/apps/dm/package.json @@ -29,7 +29,7 @@ "@eslint/eslintrc": "^3", "@types/webpack": "^5.28.5", "eslint": "^9", - "eslint-config-next": "15.1.7", + "eslint-config-next": "15.3.8", "postcss": "^8", "tailwindcss": "^3.4.1", "typescript": "^5" diff --git a/apps/dm_new/app/(landing)/reuse/apply/status/page.tsx b/apps/dm_new/app/(landing)/reuse/apply/status/page.tsx index b69b0fdd9..3282f54a5 100644 --- a/apps/dm_new/app/(landing)/reuse/apply/status/page.tsx +++ b/apps/dm_new/app/(landing)/reuse/apply/status/page.tsx @@ -3,6 +3,7 @@ import { useEffect, useMemo, useRef, useState } from "react"; import SubPageHeader from "../../_components/SubPageHeader"; +//import { useDmStore } from "@/app/store"; type WaterDetail = { toc: string; @@ -114,12 +115,17 @@ type PairField = { label: string; value: string }; export default function DemandStatusPage() { const rows = useMemo(() => MOCK, []); - // ✅ rows가 빈 경우도 대비 (런타임 오류 방지) + // rows가 빈 경우도 대비 (런타임 오류 방지) const [selectedId, setSelectedId] = useState(rows[0]?.id ?? null); - // ✅ 상세영역 스크롤 이동용 + // 상세영역 스크롤 이동용 const detailRef = useRef(null); + // update + /* const updateSdmInfoData = useDmStore( + (state) => state.updateSdmInfoData + ); */ + // ✅ selected 계산 안정화 const selected = useMemo(() => { if (!rows.length) return null; diff --git a/apps/dm_new/app/(popup-layout)/map/popup/page.tsx b/apps/dm_new/app/(popup-layout)/map/popup/page.tsx index 1c625bcac..bdce68a87 100644 --- a/apps/dm_new/app/(popup-layout)/map/popup/page.tsx +++ b/apps/dm_new/app/(popup-layout)/map/popup/page.tsx @@ -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"; diff --git a/apps/dm_new/app/(with-layout)/apply/register/page.tsx b/apps/dm_new/app/(with-layout)/apply/register/page.tsx index 7a471d0fe..80faee50e 100644 --- a/apps/dm_new/app/(with-layout)/apply/register/page.tsx +++ b/apps/dm_new/app/(with-layout)/apply/register/page.tsx @@ -13,9 +13,10 @@ import { useRouter } from "next/navigation"; import SubPageHeader from "@/components/SubPageHeader"; import WaterQualityRefModal from "../modal/WaterQualityRefModal"; import CandidateSiteModal, { type CandidateSite } from "@/components/CandidateSiteModal"; -import { useDmStore} from "@/app/store"; +import { useDmStore } from "@/app/store"; import type { SdmInfoFormData } from "@/app/store/sdmMng"; import SimilarCaseModal, { type SimilarCaseDetail, type SimilarCaseRow } from "@/app/(landing)/reuse/apply/modal/SimilarCaseModal"; +import type { SubsInfo } from "@/app/store/map/type"; type PHRange = { min: string; max: string }; @@ -60,6 +61,7 @@ export default function DemandRegisterPage() { const [cand1, setCand1] = useState(""); const [cand2, setCand2] = useState(""); const [cand3, setCand3] = useState(""); + const [candidateList, setCandidateList] = useState([]); const useTypesData = useDmStore((state) => state.Sdm.useTypesData); const getUseTypesData = useDmStore((state) => state.getUseTypesData); @@ -121,16 +123,38 @@ export default function DemandRegisterPage() { getUseTypesData(); }, [getUseTypesData]); + useEffect(() => { + const handler = (event: MessageEvent) => { + if (!event.data) return; + + if (event.data.type === "SET_SUBS_INFO") { + const list = event.data.payload || []; + + // 최대 3개 + setCand1(list[0]?.ruseUtztnFcltNm || ""); + setCand2(list[1]?.ruseUtztnFcltNm || ""); + setCand3(list[2]?.ruseUtztnFcltNm || ""); + setCandidateList(list); + } + }; + + window.addEventListener("message", handler); + + return () => { + window.removeEventListener("message", handler); + }; + }, []); + // option // 'req':필수 / 'num' : 숫자 / 'num+[숫자] : 자릿수 - const validation = (val, text, option :string[]=[] ) => { - if(option.includes('req')){ - if(val.trim() === "" || val ===undefined) { - alert(`${text} 항목은 필수 입력값입니다.`); + const validation = (val, text, option: string[] = []) => { + if (option.includes('req')) { + if (val.trim() === "" || val === undefined) { + alert(`${text} 항목은 필수 입력값입니다.`); return false; } - }else{ - if(val.trim()===""){ + } else { + if (val.trim() === "") { return true; } } @@ -144,8 +168,7 @@ export default function DemandRegisterPage() { if (!regex.test(val)) { alert( - `${text}은(는) ${ - isDot ? "숫자 또는 소수" : "숫자" + `${text}은(는) ${isDot ? "숫자 또는 소수" : "숫자" }만 입력 가능합니다.` ); return false; @@ -230,29 +253,29 @@ export default function DemandRegisterPage() { }); // 데이터 저장 - const saveInfo = async() => { - if(!validation(reqQty, '요구수량', ['req', 'numDot'])) return false; - if(!validation(usePurpose, '사용용도', ['req'])) return false; - if(!validation(hopePrice, '희망단가', ['req', 'numDot'])) return false; - /* if(!noDetect && !validation(coliform, '총대장균군수', ['req','numDot'])) return false; - if(!validation(residualCl, ['req', '결합잔류염소', 'numDot'])) return false; - if(!validation(turbidity, '탁도', ['req', 'numDot'])) return false; - if(!validation(bod, '생물화학적산소요구량', ['req', 'numDot'])) return false; - if(!validation(odor, '냄새', ['req'])) return false; */ - + const saveInfo = async () => { + if (!validation(reqQty, '요구수량', ['req', 'numDot'])) return false; + if (!validation(usePurpose, '사용용도', ['req'])) return false; + if (!validation(hopePrice, '희망단가', ['req', 'numDot'])) return false; + /* if(!noDetect && !validation(coliform, '총대장균군수', ['req','numDot'])) return false; + if(!validation(residualCl, ['req', '결합잔류염소', 'numDot'])) return false; + if(!validation(turbidity, '탁도', ['req', 'numDot'])) return false; + if(!validation(bod, '생물화학적산소요구량', ['req', 'numDot'])) return false; + if(!validation(odor, '냄새', ['req'])) return false; */ + // 필수는 아니지만 숫자로는 들어와야함. - /* if(!validation(tn, '총질소', ['numDot'])) return false; - if(!validation(residualCl, '결합잔류염소', ['numDot'])) return false; - if(!validation(tp, '총인', ['numDot'])) return false; - if(!validation(ph.min, 'ph', ['numDot'])) return false; - if(!validation(ph.max, 'ph', ['numDot'])) return false; - if(!validation(chloride, '염화물', ['numDot'])) return false; - if(!validation(ec, '전기전도도', ['numDot'])) return false; */ - + /* if(!validation(tn, '총질소', ['numDot'])) return false; + if(!validation(residualCl, '결합잔류염소', ['numDot'])) return false; + if(!validation(tp, '총인', ['numDot'])) return false; + if(!validation(ph.min, 'ph', ['numDot'])) return false; + if(!validation(ph.max, 'ph', ['numDot'])) return false; + if(!validation(chloride, '염화물', ['numDot'])) return false; + if(!validation(ec, '전기전도도', ['numDot'])) return false; */ + const userStr = sessionStorage.getItem("user"); const user = userStr ? JSON.parse(userStr) : null; - if(user){ + if (user) { // 후보지 목록 (candsRef에 코드까지 보관됨) const splyCndtList = candsRef.current .filter((x) => x.name) @@ -261,25 +284,25 @@ export default function DemandRegisterPage() { ruseUtztnFcltCd: x.code, })); - const payload : SdmInfoFormData = { - dmndTmng : new Date(reqDate), - dmdInfoId : user.dmdInfoId, - dmndQty : Number(reqQty), - wntUntprc : Number(hopePrice), - useUsgCd : usePurpose, + const payload: SdmInfoFormData = { + dmndTmng: new Date(reqDate), + dmdInfoId: user.dmdInfoId, + dmndQty: Number(reqQty), + wntUntprc: Number(hopePrice), + useUsgCd: usePurpose, // 수질 - grssClfg : Number(coliform), - tn : Number(tn)||null, - combResdch: Number(residualCl)||null, - tph : Number(tp)||null, - trbt : Number(turbidity), - ph : ph.min||''+((ph.min||ph.max)?'~':'')+ph.max||'', - blgcOxygDmndQnt : Number(bod), - clIonQnt : Number(chloride)||null, - smll : odor, - cdtnv : Number(ec)||null, - crmty : Number(color)||null, - rmrk : remark, + grssClfg: Number(coliform), + tn: Number(tn) || null, + combResdch: Number(residualCl) || null, + tph: Number(tp) || null, + trbt: Number(turbidity), + ph: ph.min || '' + ((ph.min || ph.max) ? '~' : '') + ph.max || '', + blgcOxygDmndQnt: Number(bod), + clIonQnt: Number(chloride) || null, + smll: odor, + cdtnv: Number(ec) || null, + crmty: Number(color) || null, + rmrk: remark, splyCndtList, // 후보지 목록 추가 } const success = await insertSdmInfoData(payload); @@ -344,13 +367,13 @@ export default function DemandRegisterPage() { const fncSetOptionValue = (e: React.ChangeEvent) => { const value = e.target.value; initQualityForm(); - + switch (value) { // 청소화장실용도 case '01': setTp('0.2'); setTurbidity('2'); - setPh({min:'5.8', max:'8.5'}); + setPh({ min: '5.8', max: '8.5' }); setBod('5'); setColor('20'); break; @@ -358,14 +381,14 @@ export default function DemandRegisterPage() { case '02': setTp('0.2'); setTurbidity('2'); - setPh({min:'5.8', max:'8.5'}); + setPh({ min: '5.8', max: '8.5' }); setBod('5'); break; // 조경용도 case '03': setTp('0.2'); setTurbidity('2'); - setPh({min:'5.8', max:'8.5'}); + setPh({ min: '5.8', max: '8.5' }); setBod('5'); setChloride('250'); break; @@ -373,318 +396,318 @@ export default function DemandRegisterPage() { case '05': break; // 농업용도 - case '06' : + case '06': setTurbidity('5'); - setPh({min:'5.8', max:'8.5'}); + setPh({ min: '5.8', max: '8.5' }); setBod('8'); setEc('2000'); setFarmText("이하 (** 간접:2000,직접:700 )"); break; // 하천 등 유지보수 - case '07' : + case '07': setColiform('1000'); setTn('10'); setTp('0.5'); - setPh({min:'5.8', max:'8.5'}); + setPh({ min: '5.8', max: '8.5' }); setBod('5'); break; // 공업 case '08': - setPh({min:'5.8', max:'8.5'}); + setPh({ min: '5.8', max: '8.5' }); break; default: console.log('잘못된 선택입니다.'); } - + setUsePurpose(value); } return ( <> - -
- {/* 서브 타이틀 + 브레드크럼 */} - +
- {/* 컨텐츠 영역 */} -
+ {/* 서브 타이틀 + 브레드크럼 */} + - {/* 기본정보 테이블 */} -
- - - + {/* 컨텐츠 영역 */} +
- + {/* 기본정보 테이블 */} +
+ + + - - - + - + + + - - - + - + + + - - - -
+ - {/* 요구수질 섹션 타이틀 바 */} -
-
- 요구수질 - - {/* 수질기준참고 모달 */} - setOpenRef(false)} - imageSrc="/images/landing/water_quality_ref_1.png" - /> -
-
+ + + +
- {/* 요구수질 테이블 */} -
- {/* 1행 */} - - - -
- } - rightLabel="총질소(T-N)(mg/L)" - rightControl={ - - } - /> - - - {/* 2행 */} - } - rightLabel="총인(T-P)(mg/L)" - rightControl={ - - } - /> - - - {/* 3행 */} - - } - rightLabel="수소이온농도(pH)" - rightControl={ -
- setPh((p) => ({ ...p, min: v }))} - className="w-32" - /> - ~ - setPh((p) => ({ ...p, max: v }))} - className="w-32" - /> -
- } - /> - - - {/* 4행 */} - - 생물화학적산소요구량 -
- (BOD)(mg/L) - - } - /* leftRequired */ - leftControl={} - rightLabel="염화물(mgCL/L)" - rightControl={} - /> - - - {/* 5행 */} - setOdor(e.target.value)} - className="h-11 w-full max-w-[200px] rounded-md border border-neutral-300 bg-white px-3 text-sm outline-none focus:border-neutral-500" - > - - - - - } - rightLabel="전기전도도(µs/cm)" - rightControl={} - /> - - - {/* 6행 */} - } - rightLabel="비고" - rightControl={ -