Compare commits
21
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
def2867c28 | ||
|
|
96a50e4f5a | ||
|
|
96448b6427 | ||
|
|
0ef6aea502 | ||
|
|
33ad044ed3 | ||
|
|
c94b33b1b8 | ||
|
|
886561535e | ||
|
|
ebde6d433a | ||
|
|
556d3f33b6 | ||
|
|
f826f0fb3f | ||
|
|
11010099b4 | ||
|
|
17886b0f9d | ||
|
|
46c166a87c | ||
|
|
5b96245e7d | ||
|
|
6ba78d0923 | ||
|
|
15b6520ee1 | ||
|
|
ed53ad249c | ||
|
|
b67d1261ff | ||
|
|
cfde5d695f | ||
|
|
13ce985fe5 | ||
|
|
3e634fa575 |
@@ -1,8 +1,8 @@
|
|||||||
NEXT_PUBLIC_SITE_ID = DM
|
NEXT_PUBLIC_SITE_ID = DM
|
||||||
NEXT_PUBLIC_PORT = 3000
|
NEXT_PUBLIC_PORT = 11035
|
||||||
NEXT_PUBLIC_PROXY_HOST = http://localhost:3000
|
NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11035
|
||||||
NEXT_PUBLIC_DM_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
|
|
||||||
NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||||
|
NEXT_PUBLIC_DM_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
|
||||||
NEXT_PUBLIC_FO_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
|
NEXT_PUBLIC_FO_SERVER_API_URL = http://con.mind-one.co.kr:11082/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_CS_TUS_UPLOAD = /attach-service/api/v1/tus/upload
|
NEXT_PUBLIC_CS_TUS_UPLOAD = /attach-service/api/v1/tus/upload
|
||||||
|
|||||||
+2
-2
@@ -3,9 +3,9 @@ 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_PORT = 11035
|
NEXT_PUBLIC_PORT = 3005
|
||||||
#NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11035
|
#NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11035
|
||||||
NEXT_PUBLIC_PROXY_HOST = http://localhost:3000/
|
NEXT_PUBLIC_PROXY_HOST = http://localhost:3005/
|
||||||
NEXT_PUBLIC_DM_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
|
NEXT_PUBLIC_DM_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
|
||||||
NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
NEXT_PUBLIC_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||||
NEXT_PUBLIC_FO_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
|
NEXT_PUBLIC_FO_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import ListDiv from '@common/business_components/ui/list_div';
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { Toaster } from 'react-hot-toast';
|
import { Toaster } from 'react-hot-toast';
|
||||||
import SdmLogin from '../sdmLogin/page';
|
import SdmLogin from '../sdmLogin/page';
|
||||||
import type { DemandCompType } from '@/app/store/sdmMng';
|
import type { DemandCompBizType } from '@/app/store/sdmMng';
|
||||||
import TransValueFormat from '@/app/common/transValueFormat';
|
import TransValueFormat from '@/app/common/transValueFormat';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
|
|
||||||
@@ -31,8 +31,8 @@ export default function SdmApplyList({}: SdmApplyProps) {
|
|||||||
const {selectSidoData, selectSigunData} = Common;
|
const {selectSidoData, selectSigunData} = Common;
|
||||||
const [isLogin, setIsLogin] = useState(false);
|
const [isLogin, setIsLogin] = useState(false);
|
||||||
const [isLoginStorageInfo, setIsLoginStorageInfo] = useState(false);
|
const [isLoginStorageInfo, setIsLoginStorageInfo] = useState(false);
|
||||||
const [sdmApplyDetail, setSdmApplyDetail] = useState<DemandCompType>({} as DemandCompType);
|
const [sdmApplyDetail, setSdmApplyDetail] = useState<DemandCompBizType>({} as DemandCompBizType);
|
||||||
const [transformedList, setTransformedList] = useState<DemandCompType[]>([]);
|
const [transformedList, setTransformedList] = useState<DemandCompBizType[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('sessionStorage : ',sessionStorage.getItem('user'));
|
console.log('sessionStorage : ',sessionStorage.getItem('user'));
|
||||||
@@ -60,10 +60,10 @@ export default function SdmApplyList({}: SdmApplyProps) {
|
|||||||
// 데이터 변환을 위한 별도의 useEffect
|
// 데이터 변환을 위한 별도의 useEffect
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (sdmInfoStatusList.length > 0) {
|
if (sdmInfoStatusList.length > 0) {
|
||||||
const newTransformedList = sdmInfoStatusList.map((item: DemandCompType) => ({
|
const newTransformedList = sdmInfoStatusList.map((item: DemandCompBizType) => ({
|
||||||
...item,
|
...item,
|
||||||
ctpvCd: selectSidoData.find(sido => sido.val === item.ctpvCd?.trim())?.text || '',
|
ctpvCd: selectSidoData.find(sido => sido.val === item.ctpvCd?.trim())?.text || '',
|
||||||
sggCd: selectSigunData.find(sigun => sigun.val === item.sggCd?.trim())?.text || ''
|
sggCd: selectSigunData.find(sigun => sigun.val === item.sggCd?.trim())?.text || '',
|
||||||
}));
|
}));
|
||||||
setTransformedList(newTransformedList);
|
setTransformedList(newTransformedList);
|
||||||
}
|
}
|
||||||
@@ -73,6 +73,8 @@ export default function SdmApplyList({}: SdmApplyProps) {
|
|||||||
if (index !== undefined) {
|
if (index !== undefined) {
|
||||||
const selectedStatus = transformedList[index];
|
const selectedStatus = transformedList[index];
|
||||||
if (selectedStatus) {
|
if (selectedStatus) {
|
||||||
|
|
||||||
|
|
||||||
setSdmApplyDetail(selectedStatus);
|
setSdmApplyDetail(selectedStatus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,33 +123,33 @@ export default function SdmApplyList({}: SdmApplyProps) {
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.header}>총대장균군수(개/100ml)</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.header}>총대장균군수(개/100ml)</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.grssClfg} format="number"/>}</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.grssClfg ?? ''} format="number"/>}</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.header}>결합잔류염소(mg/L)</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.header}>결합잔류염소(mg/L)</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.combResdch} format="number"/>}</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.combResdch ?? ''} format="number"/>}</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.header}>탁도(NTU)</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.header}>탁도(NTU)</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.trbt} format="number"/>}</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.trbt ?? ''} format="number"/>}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.header}>생물학적 산소요구량(BOD)(mg/L)</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.header}>생물학적 산소요구량(BOD)(mg/L)</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.blgcOxygDmndQnt} format="number"/>}</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.blgcOxygDmndQnt ?? ''} format="number"/>}</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.header}>냄새</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.header}>냄새</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.smll} format="number"/>}</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.smll} format="number"/>}</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.header}>색도(도)</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.header}>색도(도)</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.crmty} format="number"/>}</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.crmty ?? ''} format="number"/>}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.header}>총질소(T-N)(mg/L)</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.header}>총질소(T-N)(mg/L)</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.tn} format="number"/>}</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.tn ?? ''} format="number"/>}</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.header}>총인(T-P)(mg/L)</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.header}>총인(T-P)(mg/L)</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.tph} format="number"/>}</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.tph ?? ''} format="number"/>}</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.header}>수소이온농도(pH)</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.header}>수소이온농도(pH)</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.ph} format="number"/>}</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.ph} format="number"/>}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.header}>염화물(mgCL/L)</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.header}>염화물(mgCL/L)</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.clIonQnt} format="number"/>}</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.clIonQnt ?? ''} format="number"/>}</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.header}>전기전도도(㎲/cm)</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.header}>전기전도도(㎲/cm)</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.cdtnv} format="number"/>}</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{<TransValueFormat value={sdmApplyDetail?.cdtnv ?? ''} format="number"/>}</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.header}>비고</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.header}>비고</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{sdmApplyDetail?.rmrk}</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{sdmApplyDetail?.rmrk}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@@ -156,11 +158,11 @@ export default function SdmApplyList({}: SdmApplyProps) {
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.header}>후보지1</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.header}>후보지1</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.cell}></TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{ sdmApplyDetail?.splyCndtList?.[0]?.ruseUtztnFcltNm ?? ""}</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.header}>후보지2</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.header}>후보지2</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.cell}></TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{sdmApplyDetail?.splyCndtList?.[1]?.ruseUtztnFcltNm ?? ""}</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.header}>후보지3</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.header}>후보지3</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.cell}></TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.cell}>{sdmApplyDetail?.splyCndtList?.[2]?.ruseUtztnFcltNm ?? ""}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
@@ -177,7 +179,7 @@ export default function SdmApplyList({}: SdmApplyProps) {
|
|||||||
<TableCell colSpan={1} className={TABLE_STYLES.header}>진행상태</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.header}>진행상태</TableCell>
|
||||||
<TableCell colSpan={2} className={TABLE_STYLES.cell}>{sdmApplyDetail?.status?.toString()}</TableCell>
|
<TableCell colSpan={2} className={TABLE_STYLES.cell}>{sdmApplyDetail?.status?.toString()}</TableCell>
|
||||||
<TableCell colSpan={1} className={TABLE_STYLES.header}>공급처매칭결과</TableCell>
|
<TableCell colSpan={1} className={TABLE_STYLES.header}>공급처매칭결과</TableCell>
|
||||||
<TableCell colSpan={2} className={TABLE_STYLES.cell}></TableCell>
|
<TableCell colSpan={2} className={TABLE_STYLES.cell}>{sdmApplyDetail?.ruseUtztnFcltNm??''}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useDmStore } from "@/app/store";
|
import { useDmStore } from "@/app/store";
|
||||||
import type { DemandCompType } from "@/app/store/sdmMng";
|
import type { DemandCompBizType } from "@/app/store/sdmMng";
|
||||||
import { SdmInfoRegForm } from "@/components/ui/sdmInfoInsertForm/component";
|
import { SdmInfoRegForm } from "@/components/ui/sdmInfoInsertForm/component";
|
||||||
import { UiModal } from "@common/business_components/ui/dialog_ui";
|
import { UiModal } from "@common/business_components/ui/dialog_ui";
|
||||||
import { Button } from "@common/components/ui";
|
import { Button } from "@common/components/ui";
|
||||||
@@ -9,126 +9,104 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
|||||||
import { useRouter, useSearchParams } from "next/navigation";
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
import { Suspense, useEffect, useState } from "react";
|
import { Suspense, useEffect, useState } from "react";
|
||||||
import { FormProvider, useForm, type SubmitHandler } from "react-hook-form";
|
import { FormProvider, useForm, type SubmitHandler } from "react-hook-form";
|
||||||
import { Toaster } from "react-hot-toast";
|
import toast, { Toaster } from "react-hot-toast";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
import SdmLogin from "../sdmLogin/page";
|
import SdmLogin from "../sdmLogin/page";
|
||||||
|
|
||||||
const sdmInfoFormSchema = z.object({
|
const sdmInfoFormSchema = z.object({
|
||||||
sdmNm: z.string()
|
sdmNm: z.string().min(1, "수요처를 선택해주세요"),
|
||||||
.min(1, "수요처를 선택해주세요"),
|
|
||||||
demandYmd: z.date().optional(),
|
demandYmd: z.date().optional(),
|
||||||
demandQnty: z.string()
|
demandQnty: z
|
||||||
|
.string()
|
||||||
.min(1, "요구수량을 입력해주세요")
|
.min(1, "요구수량을 입력해주세요")
|
||||||
.regex(/^[0-9]+$/, "요구수량은 숫자만 입력 가능합니다"),
|
.regex(/^[0-9]+$/, "요구수량은 숫자만 입력 가능합니다"),
|
||||||
usePurpose: z.string().optional(),
|
usePurpose: z.string().optional(),
|
||||||
money: z.string()
|
money: z.string().regex(/^[0-9]+$/, "희망단가는 숫자만 입력 가능합니다"),
|
||||||
.regex(/^[0-9]+$/, "희망단가는 숫자만 입력 가능합니다"),
|
|
||||||
/**요구수질 */
|
/**요구수질 */
|
||||||
reqWaterQlty: z.string().optional(),
|
reqWaterQlty: z.string().optional(),
|
||||||
grssClfg: z.string()
|
grssClfg: z.number().nullish(),
|
||||||
.min(1, "총대장균군수를 입력해주세요")
|
tn: z.number().nullish(),
|
||||||
.regex(/^[0-9]+$/, "총대장균군수는 숫자만 입력 가능합니다"),
|
combResdch: z.number().nullish(),
|
||||||
tn: z.string()
|
tph: z.number().nullish(),
|
||||||
.min(1, "총질소를 입력해주세요")
|
trbt: z.number().nullish(),
|
||||||
.regex(/^[0-9]+$/, "총질소는 숫자만 입력 가능합니다"),
|
ph: z.string().nullish(),
|
||||||
combResdch: z.string()
|
bod: z.number().nullish(),
|
||||||
.min(1, "결합잔류염소를 입력해주세요")
|
|
||||||
.regex(/^[0-9]+$/, "결합잔류염소는 숫자만 입력 가능합니다"),
|
|
||||||
tph: z.string()
|
|
||||||
.min(1, "총인산물을 입력해주세요")
|
|
||||||
.regex(/^[0-9]+$/, "총인산물은 숫자만 입력 가능합니다"),
|
|
||||||
trbt: z.string()
|
|
||||||
.min(1, "탁도를 입력해주세요")
|
|
||||||
.regex(/^[0-9]+$/, "탁도는 숫자만 입력 가능합니다"),
|
|
||||||
ph: z.string()
|
|
||||||
.min(1, "수소이온농도를 입력해주세요")
|
|
||||||
.regex(/^[0-9]+$/, "수소이온농도는 숫자만 입력 가능합니다"),
|
|
||||||
bod: z.string()
|
|
||||||
.min(1, "생물학적 산소요구량을 입력해주세요")
|
|
||||||
.regex(/^[0-9]+$/, "생물학적 산소요구량은 숫자만 입력 가능합니다"),
|
|
||||||
/**컬럼확인필요 */
|
/**컬럼확인필요 */
|
||||||
clIonQnt: z.string()
|
clIonQnt: z.number().nullish(),
|
||||||
.min(1, "염화물을 입력해주세요")
|
smll: z.string(),
|
||||||
.regex(/^[0-9]+$/, "염화물은 숫자만 입력 가능합니다"),
|
cdtnv: z.number().nullish(),
|
||||||
smll: z.string()
|
crmty: z.number().nullish(),
|
||||||
.min(1, "냄새를 입력해주세요")
|
|
||||||
.regex(/^[0-9]+$/, "냄새는 숫자만 입력 가능합니다"),
|
|
||||||
cdtnv: z.string()
|
|
||||||
.min(1, "전기전도도를 입력해주세요")
|
|
||||||
.regex(/^[0-9]+$/, "전기전도도는 숫자만 입력 가능합니다"),
|
|
||||||
crmty: z.string()
|
|
||||||
.min(1, "색도를 입력해주세요")
|
|
||||||
.regex(/^[0-9]+$/, "색도는 숫자만 입력 가능합니다"),
|
|
||||||
rmrk: z.string().optional(),
|
rmrk: z.string().optional(),
|
||||||
/* telno: z.string()
|
/* telno: z.string()
|
||||||
.min(8, "전화번호는 8자 이상 입력해주세요")
|
.min(8, "전화번호는 8자 이상 입력해주세요")
|
||||||
.max(12, "전화번호는 12자 이내로 입력해주세요")
|
.max(12, "전화번호는 12자 이내로 입력해주세요")
|
||||||
.regex(/^[0-9-]+$/, "전화번호는 숫자와 하이픈(-)만 입력 가능합니다"), */
|
.regex(/^[0-9-]+$/, "전화번호는 숫자와 하이픈(-)만 입력 가능합니다"), */
|
||||||
candidateTitle: z.array(z.object({
|
candidateTitle: z
|
||||||
ruseUtztnFcltNm: z.string(),
|
.array(
|
||||||
ruseUtztnFcltCd: z.string(),
|
z.object({
|
||||||
})).optional(),
|
ruseUtztnFcltNm: z.string(),
|
||||||
|
ruseUtztnFcltCd: z.string(),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type FormData = z.infer<typeof sdmInfoFormSchema>;
|
export type FormData = z.infer<typeof sdmInfoFormSchema>;
|
||||||
|
|
||||||
function SdmInfoInsertContent() {
|
function SdmInfoInsertContent() {
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const {insertSdmInfoData, Sdm ,setSubsInfo} = useDmStore((state) => state);
|
const { insertSdmInfoData, Sdm, setSubsInfo } = useDmStore((state) => state);
|
||||||
const { successLogin } = Sdm;
|
const { successLogin } = Sdm;
|
||||||
const [ismoneyDisabled, setIsmoneyDisabled] = useState(false);
|
const [ismoneyDisabled, setIsmoneyDisabled] = useState(false);
|
||||||
const formSchema = sdmInfoFormSchema;
|
const formSchema = sdmInfoFormSchema;
|
||||||
|
|
||||||
const [isLogin, setIsLogin] = useState(false);
|
const [isLogin, setIsLogin] = useState(false);
|
||||||
const [facilityName, setFacilityName] = useState<string>('');
|
const [facilityName, setFacilityName] = useState<string>("");
|
||||||
const [defaultValues, setDefaultValues] = useState<FormData>({
|
const [defaultValues, setDefaultValues] = useState<FormData>({
|
||||||
sdmNm: '',
|
sdmNm: "",
|
||||||
demandYmd: new Date(),
|
demandYmd: new Date(),
|
||||||
demandQnty: '',
|
demandQnty: "",
|
||||||
usePurpose: '',
|
usePurpose: "",
|
||||||
money: '',
|
money: "",
|
||||||
/**요구수질 */
|
/**요구수질 */
|
||||||
reqWaterQlty: '',
|
reqWaterQlty: "",
|
||||||
grssClfg: '',
|
grssClfg: null,
|
||||||
tn: '',
|
tn: null,
|
||||||
combResdch: '',
|
combResdch: null,
|
||||||
tph: '',
|
tph: null,
|
||||||
trbt: '',
|
trbt: null,
|
||||||
ph: '',
|
ph: null,
|
||||||
bod: '',
|
bod: null,
|
||||||
/**컬럼확인필요 */
|
/**컬럼확인필요 */
|
||||||
clIonQnt: '',
|
clIonQnt: null,
|
||||||
smll: '',
|
smll: "",
|
||||||
cdtnv: '',
|
cdtnv: null,
|
||||||
crmty: '',
|
crmty: null,
|
||||||
rmrk: '',
|
rmrk: "",
|
||||||
/** 후보지 제목 */
|
/** 후보지 제목 */
|
||||||
candidateTitle: [
|
candidateTitle: [
|
||||||
{ ruseUtztnFcltNm: '', ruseUtztnFcltCd: '' },
|
{ ruseUtztnFcltNm: "", ruseUtztnFcltCd: "" },
|
||||||
{ ruseUtztnFcltNm: '', ruseUtztnFcltCd: '' },
|
{ ruseUtztnFcltNm: "", ruseUtztnFcltCd: "" },
|
||||||
{ ruseUtztnFcltNm: '', ruseUtztnFcltCd: '' },
|
{ ruseUtztnFcltNm: "", ruseUtztnFcltCd: "" },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const user = sessionStorage.getItem('user');
|
const user = sessionStorage.getItem("user");
|
||||||
setDefaultValues(prev => ({
|
setDefaultValues((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
sdmNm: searchParams.get('dmdCoNm') || '',
|
sdmNm: searchParams.get("dmdCoNm") || "",
|
||||||
}));
|
}));
|
||||||
sessionStorage.setItem('user', searchParams.get('dmdInfoId') || '');
|
sessionStorage.setItem("user", searchParams.get("dmdInfoId") || "");
|
||||||
setIsLogin(user || searchParams.get('dmdInfoId') ? true : false);
|
setIsLogin(user || searchParams.get("dmdInfoId") ? true : false);
|
||||||
}, [searchParams]);
|
}, [searchParams]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const local = localStorage.getItem('user');
|
const local = localStorage.getItem("user");
|
||||||
if (local) {
|
if (local) {
|
||||||
setIsLogin(true);
|
setIsLogin(true);
|
||||||
}
|
}
|
||||||
setSubsInfo([]); // subsInfo 초기화 후보지 처음 화면 들어올때 초기화(스토어내 객체만)
|
setSubsInfo([]); // subsInfo 초기화 후보지 처음 화면 들어올때 초기화(스토어내 객체만)
|
||||||
|
|
||||||
}, [setSubsInfo]);
|
}, [setSubsInfo]);
|
||||||
|
|
||||||
const form = useForm<FormData>({
|
const form = useForm<FormData>({
|
||||||
@@ -139,98 +117,138 @@ function SdmInfoInsertContent() {
|
|||||||
|
|
||||||
const subsInfo = useDmStore((state) => state.map.subsInfo);
|
const subsInfo = useDmStore((state) => state.map.subsInfo);
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(() => {
|
||||||
//map.subsInfo 스토어 객체 값이 변경되면 해당 값이 폼에 자동으로 들어가도록 수정 대신 값이 있어야함
|
//map.subsInfo 스토어 객체 값이 변경되면 해당 값이 폼에 자동으로 들어가도록 수정 대신 값이 있어야함
|
||||||
if(subsInfo.length>0){
|
if (subsInfo.length > 0) {
|
||||||
form.setValue('candidateTitle', subsInfo)
|
form.setValue("candidateTitle", subsInfo);
|
||||||
}
|
}
|
||||||
|
}, [subsInfo, form]);
|
||||||
|
|
||||||
},[subsInfo, form])
|
//후보지 팝업 값 셋팅
|
||||||
|
useEffect(() => {
|
||||||
|
const handleMessage = (event: MessageEvent) => {
|
||||||
|
if (event.data?.type === "SET_SUBS_INFO") {
|
||||||
|
setSubsInfo(event.data.payload); // zustand로 값 설정
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//후보지 팝업 값 셋팅
|
window.addEventListener("message", handleMessage);
|
||||||
useEffect(() => {
|
return () => window.removeEventListener("message", handleMessage);
|
||||||
const handleMessage = (event: MessageEvent) => {
|
}, [setSubsInfo]);
|
||||||
if (event.data?.type === 'SET_SUBS_INFO') {
|
|
||||||
setSubsInfo(event.data.payload); // zustand로 값 설정
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener('message', handleMessage);
|
|
||||||
return () => window.removeEventListener('message', handleMessage);
|
|
||||||
}, [setSubsInfo]);
|
|
||||||
|
|
||||||
// 로그인 성공 시 모달 닫기 및 폼 업데이트
|
// 로그인 성공 시 모달 닫기 및 폼 업데이트
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (successLogin) {
|
if (successLogin) {
|
||||||
setIsLogin(true);
|
setIsLogin(true);
|
||||||
const user = sessionStorage.getItem('user');
|
const user = sessionStorage.getItem("user");
|
||||||
if (user) {
|
if (user) {
|
||||||
try {
|
try {
|
||||||
const userData = JSON.parse(user);
|
const userData = JSON.parse(user);
|
||||||
if (userData.dmdCoNm) {
|
if (userData.dmdCoNm) {
|
||||||
setFacilityName(userData.dmdCoNm);
|
setFacilityName(userData.dmdCoNm);
|
||||||
form.setValue('sdmNm', userData.dmdCoNm);
|
form.setValue("sdmNm", userData.dmdCoNm);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error parsing user data:', error);
|
console.error("Error parsing user data:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [successLogin, form]);
|
}, [successLogin, form]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log("Form state changed:", form.formState.errors);
|
||||||
|
}, [form.formState.errors]);
|
||||||
|
|
||||||
// 체크박스 상태가 변경될 때마다 money 필드의 에러를 초기화
|
// 체크박스 상태가 변경될 때마다 money 필드의 에러를 초기화
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (ismoneyDisabled) {
|
if (ismoneyDisabled) {
|
||||||
form.clearErrors('money');
|
form.clearErrors("money");
|
||||||
form.setValue('money', '');
|
form.setValue("money", "");
|
||||||
}
|
}
|
||||||
}, [ismoneyDisabled, form]);
|
}, [ismoneyDisabled, form]);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const onSubmit: SubmitHandler<FormData> = async (data) => {
|
const onSubmit: SubmitHandler<FormData> = async (data) => {
|
||||||
try {
|
try {
|
||||||
// Transform form data to match API schema
|
const dmSubsInfo = data.candidateTitle?.filter(
|
||||||
const apiData: DemandCompType = {
|
(item) => item.ruseUtztnFcltNm && item.ruseUtztnFcltCd
|
||||||
dmdInfoId: JSON.parse(sessionStorage.getItem('user') || '{}')?.dmdInfoId?.toString() || searchParams.get('dmdInfoId') + (searchParams.get('bznmTotNo') || ''),
|
);
|
||||||
dmdInfoFk: JSON.parse(sessionStorage.getItem('user') || '{}')?.dmdInfoId?.toString() || searchParams.get('dmdInfoId') + (searchParams.get('bznmTotNo') || ''),
|
// Transform form data to madata.candidateTitletch API schema
|
||||||
dmdCoNm: JSON.parse(sessionStorage.getItem('user') || '{}')?.dmdCoNm?.toString() || data.sdmNm,
|
const apiData: DemandCompBizType = {
|
||||||
ctpvCd: JSON.parse(sessionStorage.getItem('user') || '{}')?.ctpvCd?.toString() || searchParams.get('ctpvCd') || '',
|
dmdInfoId:
|
||||||
sggCd: JSON.parse(sessionStorage.getItem('user') || '{}')?.sggCd?.toString() || searchParams.get('sggCd') || '',
|
JSON.parse(
|
||||||
daddr: JSON.parse(sessionStorage.getItem('user') || '{}')?.daddr?.toString() || searchParams.get('daddr') || '',
|
sessionStorage.getItem("user") || "{}"
|
||||||
telno: JSON.parse(sessionStorage.getItem('user') || '{}')?.telno?.toString() || searchParams.get('telno') || '',
|
)?.dmdInfoId?.toString() ||
|
||||||
rgtr: JSON.parse(sessionStorage.getItem('user') || '{}')?.rgtr?.toString() || searchParams.get('rgtr') || '',
|
searchParams.get("dmdInfoId") + (searchParams.get("bznmTotNo") || ""),
|
||||||
useUsgCd: data.usePurpose || '',
|
dmdInfoFk:
|
||||||
wntUntprc: Number(data.money) || '',
|
JSON.parse(
|
||||||
|
sessionStorage.getItem("user") || "{}"
|
||||||
|
)?.dmdInfoId?.toString() ||
|
||||||
|
searchParams.get("dmdInfoId") + (searchParams.get("bznmTotNo") || ""),
|
||||||
|
dmdCoNm:
|
||||||
|
JSON.parse(
|
||||||
|
sessionStorage.getItem("user") || "{}"
|
||||||
|
)?.dmdCoNm?.toString() || data.sdmNm,
|
||||||
|
ctpvCd:
|
||||||
|
JSON.parse(
|
||||||
|
sessionStorage.getItem("user") || "{}"
|
||||||
|
)?.ctpvCd?.toString() ||
|
||||||
|
searchParams.get("ctpvCd") ||
|
||||||
|
"",
|
||||||
|
sggCd:
|
||||||
|
JSON.parse(
|
||||||
|
sessionStorage.getItem("user") || "{}"
|
||||||
|
)?.sggCd?.toString() ||
|
||||||
|
searchParams.get("sggCd") ||
|
||||||
|
"",
|
||||||
|
daddr:
|
||||||
|
JSON.parse(
|
||||||
|
sessionStorage.getItem("user") || "{}"
|
||||||
|
)?.daddr?.toString() ||
|
||||||
|
searchParams.get("daddr") ||
|
||||||
|
"",
|
||||||
|
telno:
|
||||||
|
JSON.parse(
|
||||||
|
sessionStorage.getItem("user") || "{}"
|
||||||
|
)?.telno?.toString() ||
|
||||||
|
searchParams.get("telno") ||
|
||||||
|
"",
|
||||||
|
rgtr:
|
||||||
|
JSON.parse(
|
||||||
|
sessionStorage.getItem("user") || "{}"
|
||||||
|
)?.rgtr?.toString() ||
|
||||||
|
searchParams.get("rgtr") ||
|
||||||
|
"",
|
||||||
|
useUsgCd: data.usePurpose || "",
|
||||||
|
wntUntprc: Number(data.money) || "",
|
||||||
dmndTmng: data.demandYmd || new Date(),
|
dmndTmng: data.demandYmd || new Date(),
|
||||||
dmndQty: Number(data.demandQnty) || '',
|
dmndQty: Number(data.demandQnty) || "",
|
||||||
grssClfg: Number(data.grssClfg) || '',
|
grssClfg: data.grssClfg === null ? -1 : Number(data.grssClfg),
|
||||||
tn: Number(data.tn) || '',
|
tn: Number(data.tn) || null,
|
||||||
combResdch: Number(data.combResdch) || '',
|
combResdch: Number(data.combResdch) || null,
|
||||||
tph: Number(data.tph) || '',
|
tph: Number(data.tph) || null,
|
||||||
trbt: Number(data.trbt) || '',
|
trbt: Number(data.trbt) || null,
|
||||||
ph: Number(data.ph) || '',
|
ph: data.ph || "",
|
||||||
blgcOxygDmndQnt: Number(data.bod) || '',
|
blgcOxygDmndQnt: Number(data.bod) ||null,
|
||||||
clIonQnt: Number(data.clIonQnt) || '',
|
clIonQnt: Number(data.clIonQnt) || null,
|
||||||
smll: Number(data.smll) || '',
|
smll: data.smll || "",
|
||||||
cdtnv: Number(data.cdtnv) || '',
|
cdtnv: Number(data.cdtnv) ||null,
|
||||||
crmty: Number(data.crmty) || '',
|
crmty: Number(data.crmty) || null,
|
||||||
rmrk: data.rmrk || '',
|
rmrk: data.rmrk || "",
|
||||||
bzmnNo: "",
|
bzmnNo: "",
|
||||||
dmdAplyPswd: "",
|
dmdAplyPswd: "",
|
||||||
index: 0,
|
index: 0,
|
||||||
reqDt: "",
|
reqDt: "",
|
||||||
dmdInfoSn: 0,
|
dmdInfoSn: 0,
|
||||||
status: '',
|
status: "",
|
||||||
splyCndtList: data.candidateTitle || [],
|
splyCndtList: dmSubsInfo || [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
await insertSdmInfoData(apiData);
|
await insertSdmInfoData(apiData);
|
||||||
|
setTimeout(() => {
|
||||||
|
router.push("/");
|
||||||
|
}, 1000); // 0.8초 후 이동
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error submitting form:', error);
|
console.error("Error submitting form:", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -253,8 +271,10 @@ const router = useRouter();
|
|||||||
/>
|
/>
|
||||||
<div className="flex justify-center pt-4">
|
<div className="flex justify-center pt-4">
|
||||||
<Button
|
<Button
|
||||||
|
color="sky"
|
||||||
|
size={"sm"}
|
||||||
type="submit"
|
type="submit"
|
||||||
className="w-40 bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-4 rounded-md transition-colors duration-200"
|
className="w-40 font-semibold py-2 px-4 rounded-md "
|
||||||
>
|
>
|
||||||
수요정보 등록
|
수요정보 등록
|
||||||
</Button>
|
</Button>
|
||||||
@@ -264,20 +284,21 @@ const router = useRouter();
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!isLogin ?
|
{!isLogin ? (
|
||||||
<UiModal
|
<UiModal
|
||||||
body={<SdmLogin />}
|
body={<SdmLogin />}
|
||||||
bodyClass="sm:max-w-[90vw] w-[530px] h-[430px]"
|
bodyClass="sm:max-w-[90vw] w-[530px] h-[430px]"
|
||||||
open={!isLogin}
|
open={!isLogin}
|
||||||
onOpenChange={(open) => {
|
onOpenChange={(open) => {
|
||||||
if (!open) {
|
if (!open) {
|
||||||
|
toast.dismiss();
|
||||||
router.push("/");
|
router.push("/");
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
noHeaderYn="Y"
|
noHeaderYn="Y"
|
||||||
noFooterYn="Y"
|
noFooterYn="Y"
|
||||||
/>
|
/>
|
||||||
: null}
|
) : null}
|
||||||
<Toaster position="top-center" />
|
<Toaster position="top-center" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -290,4 +311,3 @@ export default function MyForm() {
|
|||||||
</Suspense>
|
</Suspense>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useDmStore } from "@/app/store";
|
import { useDmStore } from "@/app/store";
|
||||||
import type { DemandCompType } from "@/app/store/sdmMng";
|
|
||||||
import SdmInsertForm from '@common/business_components/ui/sdmInsertForm';
|
import SdmInsertForm from '@common/business_components/ui/sdmInsertForm';
|
||||||
|
import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { useCallback, useEffect, useRef } from "react";
|
import { useCallback, useEffect, useRef } from "react";
|
||||||
import { Toaster } from "react-hot-toast";
|
import { Toaster } from "react-hot-toast";
|
||||||
@@ -44,15 +44,9 @@ export default function MyForm() {
|
|||||||
const handleInsertSdmData = useCallback((data: import('@common/business_components/ui/sdmInsertForm/form').DemandCompType) => {
|
const handleInsertSdmData = useCallback((data: import('@common/business_components/ui/sdmInsertForm/form').DemandCompType) => {
|
||||||
const convertedData: DemandCompType = {
|
const convertedData: DemandCompType = {
|
||||||
...data,
|
...data,
|
||||||
dmdInfoSn: '',
|
|
||||||
dmdInfoFk: '',
|
|
||||||
status: '',
|
|
||||||
splyCndtList: []
|
|
||||||
};
|
};
|
||||||
formDataRef.current = convertedData;
|
formDataRef.current = convertedData;
|
||||||
insertSdmData(convertedData).catch(error => {
|
insertSdmData(convertedData)
|
||||||
console.error('Error inserting SDM data:', error);
|
|
||||||
});
|
|
||||||
}, [insertSdmData]);
|
}, [insertSdmData]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -70,4 +64,3 @@ export default function MyForm() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ export default function WrAboutPage() {
|
|||||||
물재이용 필요성
|
물재이용 필요성
|
||||||
</h2>
|
</h2>
|
||||||
<section aria-labelledby="card2-desc" className="bg-white border border-gray-300 rounded-xl p-[60px] pt-[70px] pb-[70px] ">
|
<section aria-labelledby="card2-desc" className="bg-white border border-gray-300 rounded-xl p-[60px] pt-[70px] pb-[70px] ">
|
||||||
<h1 id="card2-desc" className="font-NotoSansKR text-[#ED5534] text-5xl font-semibold mb-8">물 재이용, 왜 필요한가요?</h1>
|
<h1 id="card2-desc" className="font-NotoSansKR text-[#D63F1F] text-5xl font-semibold mb-8">물 재이용, 왜 필요한가요?</h1>
|
||||||
<p className="font-NotoSansKR text-2xl font-normal mb-10 leading-relaxed">
|
<p className="font-NotoSansKR text-2xl font-normal mb-10 leading-relaxed">
|
||||||
빗물, 중수, 하수처리수는 지속적으로 이용 가능한 순환자원입니다.<br />
|
빗물, 중수, 하수처리수는 지속적으로 이용 가능한 순환자원입니다.<br />
|
||||||
물 재이용을 통한 효율적인 수자원 활용은 물 스트레스국가인 우리나라에서<br />가뭄대응능력 향상 및 하천수질보전을 위해 반드시 필요한 일입니다.
|
물 재이용을 통한 효율적인 수자원 활용은 물 스트레스국가인 우리나라에서<br />가뭄대응능력 향상 및 하천수질보전을 위해 반드시 필요한 일입니다.
|
||||||
@@ -237,7 +237,7 @@ export default function WrAboutPage() {
|
|||||||
하수 재이용
|
하수 재이용
|
||||||
</h2>
|
</h2>
|
||||||
<section aria-labelledby="card5-desc" className="bg-white border border-gray-300 rounded-xl p-[60px] pt-[70px] pb-[70px] ">
|
<section aria-labelledby="card5-desc" className="bg-white border border-gray-300 rounded-xl p-[60px] pt-[70px] pb-[70px] ">
|
||||||
<h1 id="card5-desc" className="font-NotoSansKR leading-snug text-[#0099A4] text-5xl font-bold mb-6">아직 할 일이 많은 하수처리수,<br />풍족하게 재이용할 수 있어요!</h1>
|
<h1 id="card5-desc" className="font-NotoSansKR leading-snug text-[#00818A] text-5xl font-bold mb-6">아직 할 일이 많은 하수처리수,<br />풍족하게 재이용할 수 있어요!</h1>
|
||||||
<p className="font-NotoSansKR text-2xl mb-10 leading-relaxed">사용하고 버려져 공공하수처리장으로 모여든 물은<br />용도에 맞는 처리 후 재이용 할 수 있습니다.</p>
|
<p className="font-NotoSansKR text-2xl mb-10 leading-relaxed">사용하고 버려져 공공하수처리장으로 모여든 물은<br />용도에 맞는 처리 후 재이용 할 수 있습니다.</p>
|
||||||
<Image
|
<Image
|
||||||
src="/img/wrAbout/img_05_1.png"
|
src="/img/wrAbout/img_05_1.png"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { CHART_FORM, MainChart, type ChartConfig } from '@common/business_components';
|
import { CHART_FORM, MainChart, type ChartConfig } from '@common/business_components';
|
||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState, useMemo, useCallback } from 'react';
|
||||||
|
|
||||||
interface RegionData {
|
interface RegionData {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -213,7 +213,7 @@ const WrStatusPage: React.FC = () => {
|
|||||||
{ region: '제주특별자치도', sewage: '8(1,666)', rainwater: '47(5,746)', reclaimed: '64(660)', thermal: '0' },
|
{ region: '제주특별자치도', sewage: '8(1,666)', rainwater: '47(5,746)', reclaimed: '64(660)', thermal: '0' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const regionData: RegionData[] = [
|
const regionData: RegionData[] = useMemo(() => [
|
||||||
{ name: '서울', x: 170, y: 140, values: [0.3, 0.3, 0.2, 0.2] },
|
{ name: '서울', x: 170, y: 140, values: [0.3, 0.3, 0.2, 0.2] },
|
||||||
{ name: '인천', x: 120, y: 150, values: [0.3, 0.3, 0.2, 0.2] },
|
{ name: '인천', x: 120, y: 150, values: [0.3, 0.3, 0.2, 0.2] },
|
||||||
{ name: '경기', x: 210, y: 210, values: [0.3, 0.3, 0.2, 0.2] },
|
{ name: '경기', x: 210, y: 210, values: [0.3, 0.3, 0.2, 0.2] },
|
||||||
@@ -231,7 +231,7 @@ const WrStatusPage: React.FC = () => {
|
|||||||
{ name: '울산', x: 450, y: 500, values: [0.3, 0.3, 0.2, 0.2] },
|
{ name: '울산', x: 450, y: 500, values: [0.3, 0.3, 0.2, 0.2] },
|
||||||
{ name: '부산', x: 420, y: 550, values: [0.3, 0.3, 0.2, 0.2] },
|
{ name: '부산', x: 420, y: 550, values: [0.3, 0.3, 0.2, 0.2] },
|
||||||
{ name: '제주', x: 60, y: 750, values: [0.3, 0.3, 0.2, 0.2] },
|
{ name: '제주', x: 60, y: 750, values: [0.3, 0.3, 0.2, 0.2] },
|
||||||
];
|
], []);
|
||||||
|
|
||||||
const handleMarkerClick = (regionId: string) => {
|
const handleMarkerClick = (regionId: string) => {
|
||||||
if (selectedRegion === regionId) {
|
if (selectedRegion === regionId) {
|
||||||
@@ -242,7 +242,7 @@ const WrStatusPage: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const createDonutMarker = (svg: SVGSVGElement, x: number, y: number, name: string, values: number[]) => {
|
const createDonutMarker = useCallback((svg: SVGSVGElement, x: number, y: number, name: string, values: number[]) => {
|
||||||
const colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FED16A'];
|
const colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FED16A'];
|
||||||
const radius = 26;
|
const radius = 26;
|
||||||
const innerRadius = 18;
|
const innerRadius = 18;
|
||||||
@@ -334,7 +334,7 @@ const WrStatusPage: React.FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
svg.appendChild(g);
|
svg.appendChild(g);
|
||||||
};
|
}, [handleMarkerClick, regionIdMap]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadSVG = async () => {
|
const loadSVG = async () => {
|
||||||
@@ -374,7 +374,7 @@ const WrStatusPage: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
loadSVG();
|
loadSVG();
|
||||||
}, []);
|
}, [createDonutMarker, regionData]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const svg = svgContainerRef.current?.querySelector('svg');
|
const svg = svgContainerRef.current?.querySelector('svg');
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ export default function RootLayout({
|
|||||||
}>) {
|
}>) {
|
||||||
return (
|
return (
|
||||||
<html lang="ko">
|
<html lang="ko">
|
||||||
|
<head>
|
||||||
|
<title>물재이용 대민</title>
|
||||||
|
</head>
|
||||||
<body>
|
<body>
|
||||||
{children}
|
{children}
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -2,12 +2,13 @@
|
|||||||
import type { SelectDataType } from "@common/business_components/ui";
|
import type { SelectDataType } from "@common/business_components/ui";
|
||||||
import type { TableUpperProps } from "../common";
|
import type { TableUpperProps } from "../common";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
|
import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form";
|
||||||
|
|
||||||
/**====================================
|
/**====================================
|
||||||
* Store - 타입
|
* Store - 타입
|
||||||
=====================================*/
|
=====================================*/
|
||||||
// 수요처 정보
|
// 수요처 정보
|
||||||
export type DemandCompType = {
|
export type DemandCompBizType = {
|
||||||
index : number | '';
|
index : number | '';
|
||||||
dmdInfoId : string | '';
|
dmdInfoId : string | '';
|
||||||
dmdInfoFk : string | '';
|
dmdInfoFk : string | '';
|
||||||
@@ -23,22 +24,23 @@ export type DemandCompType = {
|
|||||||
wntUntprc : number | '';
|
wntUntprc : number | '';
|
||||||
dmndTmng : Date | '';
|
dmndTmng : Date | '';
|
||||||
dmndQty : number | '';
|
dmndQty : number | '';
|
||||||
grssClfg : number | '';
|
grssClfg : number | null //총대장균군수
|
||||||
tn : number | '';
|
tn : number | null //총질소
|
||||||
combResdch : number | '';
|
combResdch : number | null //결합잔류염소
|
||||||
tph : number | '';
|
tph : number | null //총인
|
||||||
trbt : number | '';
|
trbt : number | null //탁도
|
||||||
ph : number | '';
|
ph : string | ''; //수소이온농
|
||||||
blgcOxygDmndQnt : number | '';
|
blgcOxygDmndQnt : number | null //생물학적산소요구량
|
||||||
clIonQnt : number | '';
|
clIonQnt : number | null //염화물
|
||||||
smll : number | '';
|
smll : string | ''; //냄새
|
||||||
cdtnv : number | '';
|
cdtnv : number | null; //전기전도도
|
||||||
crmty : number | '';
|
crmty : number | null //색도
|
||||||
rmrk : string | '';
|
rmrk : string | '';
|
||||||
reqDt : string | '';
|
reqDt : string | '';
|
||||||
dmdInfoSn : number | '';
|
dmdInfoSn : number | '';
|
||||||
status : string | '';
|
status : string | '';
|
||||||
splyCndtList:SupplyCandidate[]|[],
|
splyCndtList:SupplyCandidate[]|[],
|
||||||
|
ruseUtztnFcltNm?:string|''
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,7 +154,8 @@ export type MoneyDetailType = {
|
|||||||
clclnBrdnCst : string | '';
|
clclnBrdnCst : string | '';
|
||||||
clclnEcqrRt : string | '';
|
clclnEcqrRt : string | '';
|
||||||
}
|
}
|
||||||
|
// 규칙 타입 선언
|
||||||
|
export type DisableRulesType = Record<string, string[]>;
|
||||||
/**====================================
|
/**====================================
|
||||||
* Store - 데이터
|
* Store - 데이터
|
||||||
====================================*/
|
====================================*/
|
||||||
@@ -160,6 +163,131 @@ export type MoneyDetailType = {
|
|||||||
const demandCompList : DemandCompType[] = [
|
const demandCompList : DemandCompType[] = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
const disableRules: DisableRulesType = {
|
||||||
|
"청소": ["tn", 'tph',"clIonQnt" ,'cdtnv'],
|
||||||
|
"화장실용수": ["tn", 'tph',"clIonQnt" ,'cdtnv'],
|
||||||
|
"세척": ["combResdch", "crmty",'tph',"clIonQnt",'cdtnv'],
|
||||||
|
"살수": ["combResdch", "crmty",'tph',"clIonQnt",'cdtnv'],
|
||||||
|
"조경": ["combResdch", "crmty",'tph','cdtnv'],
|
||||||
|
"농업_간접용수": ["combResdch", "crmty",'tn','tph','clIonQnt'],
|
||||||
|
"농업_직접용수": ["combResdch", "crmty",'tn','tph','clIonQnt'],
|
||||||
|
"하천": ["combResdch", "trbt", "crmty" ,'clIonQnt','cdtnv'],
|
||||||
|
'공업':[]
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultRules: Record<string, object> = {
|
||||||
|
"청소": {
|
||||||
|
grssClfg: null,
|
||||||
|
combResdch:0.2,
|
||||||
|
trbt: 2,
|
||||||
|
bod: 5,
|
||||||
|
crmty: 20,
|
||||||
|
ph: "5.8~8.5",
|
||||||
|
tn:null,
|
||||||
|
tph: null,
|
||||||
|
clIonQnt: null,
|
||||||
|
cdtnv: null,
|
||||||
|
|
||||||
|
},
|
||||||
|
"화장실용수": {
|
||||||
|
grssClfg: null,
|
||||||
|
combResdch:0.2,
|
||||||
|
trbt: 2,
|
||||||
|
bod: 5,
|
||||||
|
crmty: 20,
|
||||||
|
ph: "5.8~8.5",
|
||||||
|
tn:null,
|
||||||
|
tph: null,
|
||||||
|
clIonQnt: null,
|
||||||
|
cdtnv: null,
|
||||||
|
},
|
||||||
|
"세척": {
|
||||||
|
grssClfg: null,
|
||||||
|
trbt: 2,
|
||||||
|
bod: 5,
|
||||||
|
ph: "5.8~8.5",
|
||||||
|
combResdch:null,
|
||||||
|
crmty:null,
|
||||||
|
tn:null,
|
||||||
|
tph: null,
|
||||||
|
clIonQnt: null,
|
||||||
|
cdtnv: null,
|
||||||
|
},
|
||||||
|
"살수": {
|
||||||
|
grssClfg: null,
|
||||||
|
trbt: 2,
|
||||||
|
bod: 5,
|
||||||
|
ph: "5.8~8.5",
|
||||||
|
combResdch:null,
|
||||||
|
crmty:null,
|
||||||
|
tn:null,
|
||||||
|
tph: null,
|
||||||
|
clIonQnt: null,
|
||||||
|
cdtnv: null,
|
||||||
|
},
|
||||||
|
"조경": {
|
||||||
|
grssClfg: null,
|
||||||
|
trbt: 2,
|
||||||
|
bod: 5,
|
||||||
|
ph: "5.8~8.5",
|
||||||
|
clIonQnt:250,
|
||||||
|
combResdch:null,
|
||||||
|
crmty:null,
|
||||||
|
tn:null,
|
||||||
|
tph: null,
|
||||||
|
cdtnv: null,
|
||||||
|
},
|
||||||
|
"농업_간접용수": {
|
||||||
|
grssClfg: null,
|
||||||
|
trbt: 5,
|
||||||
|
bod: 8,
|
||||||
|
ph: "5.8~8.5",
|
||||||
|
cdtnv:2000,
|
||||||
|
combResdch:null,
|
||||||
|
crmty:null,
|
||||||
|
tn:null,
|
||||||
|
tph: null,
|
||||||
|
clIonQnt: null,
|
||||||
|
},
|
||||||
|
"농업_직접용수": {
|
||||||
|
grssClfg: null,
|
||||||
|
trbt: 2,
|
||||||
|
bod: 8,
|
||||||
|
ph: "5.8~8.5",
|
||||||
|
cdtnv:700,
|
||||||
|
combResdch:null,
|
||||||
|
crmty:null,
|
||||||
|
tn:null,
|
||||||
|
tph: null,
|
||||||
|
clIonQnt: null,
|
||||||
|
},
|
||||||
|
"하천": {
|
||||||
|
grssClfg: 1000,
|
||||||
|
bod: 5,
|
||||||
|
tn: 10,
|
||||||
|
tph: 0.5,
|
||||||
|
ph: "5.8~8.5",
|
||||||
|
combResdch:null,
|
||||||
|
trbt:null,
|
||||||
|
crmty:null,
|
||||||
|
clIonQnt: null,
|
||||||
|
cdtnv:null
|
||||||
|
},
|
||||||
|
공업:{
|
||||||
|
grssClfg: null,
|
||||||
|
bod: null,
|
||||||
|
tn: null,
|
||||||
|
tph: null,
|
||||||
|
ph: "~",
|
||||||
|
combResdch:null,
|
||||||
|
trbt:null,
|
||||||
|
crmty:null,
|
||||||
|
clIonQnt: null,
|
||||||
|
cdtnv:null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 사용용도
|
// 사용용도
|
||||||
const useTypesData : SelectDataType[] = [
|
const useTypesData : SelectDataType[] = [
|
||||||
{ text: '청소', val: "청소" },
|
{ text: '청소', val: "청소" },
|
||||||
@@ -167,7 +295,8 @@ const useTypesData : SelectDataType[] = [
|
|||||||
{ text: "세척", val: "세척" },
|
{ text: "세척", val: "세척" },
|
||||||
{ text: "살수", val: "살수" },
|
{ text: "살수", val: "살수" },
|
||||||
{ text: "조경", val: "조경" },
|
{ text: "조경", val: "조경" },
|
||||||
{ text: "농업", val: "농업" },
|
{ text: "농업_간접용수", val: "농업_간접용수" },
|
||||||
|
{ text: "농업_직접용수", val: "농업_직접용수" },
|
||||||
{ text: "하천", val: "하천" },
|
{ text: "하천", val: "하천" },
|
||||||
{ text: "지하수", val: "지하수" },
|
{ text: "지하수", val: "지하수" },
|
||||||
{ text: "공업", val: "공업" },
|
{ text: "공업", val: "공업" },
|
||||||
@@ -280,7 +409,7 @@ const postSdmData = async (data: DemandCompType) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 수요정보 등록
|
// 수요정보 등록
|
||||||
const postSdmInfoData = async (data: DemandCompType) => {
|
const postSdmInfoData = async (data: DemandCompBizType) => {
|
||||||
try {
|
try {
|
||||||
await postFetch("/reuseFc/request/demandInfo", data);
|
await postFetch("/reuseFc/request/demandInfo", data);
|
||||||
toast.success('수요 정보 등록에 성공하였습니다.');
|
toast.success('수요 정보 등록에 성공하였습니다.');
|
||||||
@@ -360,7 +489,7 @@ const fetchGetSimilarCaseList = async (part: string, value: number|string) => {
|
|||||||
export type SdmActions = {
|
export type SdmActions = {
|
||||||
initializeSdmData: () => void;
|
initializeSdmData: () => void;
|
||||||
insertSdmData: (data: DemandCompType) => Promise<void>;
|
insertSdmData: (data: DemandCompType) => Promise<void>;
|
||||||
insertSdmInfoData: (data: DemandCompType) => Promise<void>;
|
insertSdmInfoData: (data: DemandCompBizType) => Promise<void>;
|
||||||
getDemandCompList: (searchText: string, pageCnt: number) => Promise<void>;
|
getDemandCompList: (searchText: string, pageCnt: number) => Promise<void>;
|
||||||
actionLogin: (data: DemandCompType) => Promise<void>;
|
actionLogin: (data: DemandCompType) => Promise<void>;
|
||||||
getSdmInfoStatusList: (dmdInfoId: string) => Promise<void>;
|
getSdmInfoStatusList: (dmdInfoId: string) => Promise<void>;
|
||||||
@@ -378,9 +507,10 @@ export type SdmType ={
|
|||||||
moneyDetailList: MoneyDetailType[];
|
moneyDetailList: MoneyDetailType[];
|
||||||
|
|
||||||
// 수요정보 신청현황
|
// 수요정보 신청현황
|
||||||
sdmInfoStatusList: DemandCompType[];
|
sdmInfoStatusList: DemandCompBizType[];
|
||||||
upHeadSdmInfoStatus: TableUpperProps[];
|
upHeadSdmInfoStatus: TableUpperProps[];
|
||||||
|
defaultRules: Record<string, object>
|
||||||
|
disableRules: DisableRulesType;
|
||||||
// 로그인관련
|
// 로그인관련
|
||||||
successNextPage : boolean;
|
successNextPage : boolean;
|
||||||
successLogin: boolean;
|
successLogin: boolean;
|
||||||
@@ -398,7 +528,10 @@ export const SdmState: SdmType = {
|
|||||||
moneyDetailList: moneyDetailList,
|
moneyDetailList: moneyDetailList,
|
||||||
// 수요정보 신청현황
|
// 수요정보 신청현황
|
||||||
sdmInfoStatusList: [],
|
sdmInfoStatusList: [],
|
||||||
|
defaultRules:defaultRules,
|
||||||
|
disableRules:disableRules,
|
||||||
upHeadSdmInfoStatus: upHeadSdmInfoStatus,
|
upHeadSdmInfoStatus: upHeadSdmInfoStatus,
|
||||||
|
|
||||||
// 로그인관련
|
// 로그인관련
|
||||||
successNextPage : false,
|
successNextPage : false,
|
||||||
successLogin: false,
|
successLogin: false,
|
||||||
@@ -428,7 +561,7 @@ export const SdmReducer = (set: any): SdmActions => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
insertSdmInfoData: async (data: DemandCompType) => {
|
insertSdmInfoData: async (data: DemandCompBizType) => {
|
||||||
postSdmInfoData(data);
|
postSdmInfoData(data);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -465,11 +598,13 @@ export const SdmReducer = (set: any): SdmActions => {
|
|||||||
}))
|
}))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const sdmInfoStatusList : DemandCompType[] = [];
|
const sdmInfoStatusList : DemandCompBizType[] = [];
|
||||||
|
|
||||||
res.demandInfo.map((el: DemandCompType, index: number) => {
|
res.demandInfo.map((el: DemandCompBizType, index: number) => {
|
||||||
const matchingInfo = res.demandMatchings.find((matching: DemandMatchings) => matching.dmdInfoSn === el.dmdInfoSn);
|
const matchingInfo = res.demandMatchings.find((matching: DemandMatchings) => matching.dmdInfoSn === el.dmdInfoSn);
|
||||||
const status = matchingInfo?.splyFcltFlg?.trim() === 'Sub' ? '검토' : matchingInfo?.splyFcltFlg?.trim() === 'matched' ? '매칭완료' : '신청';
|
const status = matchingInfo?.splyFcltFlg?.trim() === 'Sub' ? '검토' : matchingInfo?.splyFcltFlg?.trim() === 'matched' ? '매칭완료' : '신청';
|
||||||
|
const ruseUtztnFcltNm = matchingInfo?.ruseUtztnFcltNm ? matchingInfo.ruseUtztnFcltNm : '';
|
||||||
|
|
||||||
|
|
||||||
const tmpData = {
|
const tmpData = {
|
||||||
...el,
|
...el,
|
||||||
@@ -485,7 +620,9 @@ export const SdmReducer = (set: any): SdmActions => {
|
|||||||
useUsgCd: el.useUsgCd,
|
useUsgCd: el.useUsgCd,
|
||||||
dmndTmng: el.dmndTmng,
|
dmndTmng: el.dmndTmng,
|
||||||
dmdInfoSn : el.dmdInfoSn,
|
dmdInfoSn : el.dmdInfoSn,
|
||||||
status : status
|
status : status,
|
||||||
|
splyCndtList: el.splyCndtList,
|
||||||
|
ruseUtztnFcltNm: ruseUtztnFcltNm || ''
|
||||||
}
|
}
|
||||||
sdmInfoStatusList.push(tmpData);
|
sdmInfoStatusList.push(tmpData);
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -13,8 +13,10 @@ export const StoreZus = (initState: DmState= {
|
|||||||
...dmMapState,
|
...dmMapState,
|
||||||
}) => {
|
}) => {
|
||||||
return createStore<DmStore>()((set) => {
|
return createStore<DmStore>()((set) => {
|
||||||
tokenManager.setToken("site-id-key", 'DM');
|
if (typeof window !== "undefined") {
|
||||||
tokenManager.setToken("site-theme-key", 'green');
|
tokenManager.setToken("site-id-key", 'DM');
|
||||||
|
tokenManager.setToken("site-theme-key", 'green');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useDmStore } from '@/app/store';
|
import { useDmStore } from '@/app/store';
|
||||||
import type { DemandCompType } from '@/app/store/sdmMng';
|
import type { DemandCompType } from '@common/business_components/ui/sdmInsertForm/form';
|
||||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
type thisProps = {
|
type thisProps = {
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
export const sanitizeInput = (val: string, allowDecimal = false) => {
|
||||||
|
if (val === "") return ""; // 빈 값 허용
|
||||||
|
|
||||||
|
// 소숫점 허용
|
||||||
|
if (allowDecimal) {
|
||||||
|
// 숫자와 점만 허용
|
||||||
|
let cleaned = val.replace(/[^0-9.]/g, "");
|
||||||
|
// 소숫점 여러 개일 경우 첫 번째만 유지
|
||||||
|
const parts = cleaned.split(".");
|
||||||
|
if (parts.length > 2) {
|
||||||
|
cleaned = parts[0] + "." + parts.slice(1).join("");
|
||||||
|
}
|
||||||
|
return cleaned;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 정수만 허용
|
||||||
|
return val.replace(/[^0-9]/g, "");
|
||||||
|
};
|
||||||
@@ -118,14 +118,6 @@ export function SearchBar({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row space-x-2">
|
<div className="flex flex-row space-x-2">
|
||||||
<Button
|
|
||||||
color="red"
|
|
||||||
className="mx-2 mt-2"
|
|
||||||
size={"sm"}
|
|
||||||
onClick={() => {}}
|
|
||||||
>
|
|
||||||
후보지선택
|
|
||||||
</Button>
|
|
||||||
<Button
|
<Button
|
||||||
color="sky"
|
color="sky"
|
||||||
className="mt-2"
|
className="mt-2"
|
||||||
|
|||||||
@@ -1,28 +1,29 @@
|
|||||||
import { FormUi } from "@common/business_components/ui";
|
import { FormUi } from "@common/business_components/ui";
|
||||||
import type { ReactNode } from "react";
|
|
||||||
import type { ControllerRenderProps, FieldError, FieldValues, Path } from "react-hook-form";
|
import type { ControllerRenderProps, FieldError, FieldValues, Path } from "react-hook-form";
|
||||||
|
import { cloneElement, isValidElement } from "react";
|
||||||
|
|
||||||
interface AccessibleFormFieldProps<T extends FieldValues> {
|
interface AccessibleFormFieldProps<T extends FieldValues> {
|
||||||
field: ControllerRenderProps<T, Path<T>>;
|
field: ControllerRenderProps<T, Path<T>>;
|
||||||
label: string;
|
label: string;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
error?: FieldError;
|
error?: FieldError;
|
||||||
inputComponent: ReactNode;
|
isDisabled?: boolean;
|
||||||
|
inputComponent: React.ReactElement<{ disabled?: boolean }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AccessibleFormField<T extends FieldValues>({
|
export function AccessibleFormField<T extends FieldValues>({
|
||||||
label,
|
label,
|
||||||
required = false,
|
required = false,
|
||||||
error,
|
|
||||||
inputComponent,
|
inputComponent,
|
||||||
|
isDisabled = false,
|
||||||
}: AccessibleFormFieldProps<T>) {
|
}: AccessibleFormFieldProps<T>) {
|
||||||
const labelText = required ? `${label} *` : label;
|
const labelText = required ? `${label} *` : label;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormUi label={labelText}>
|
<FormUi label={labelText} isDisabled={isDisabled}>
|
||||||
<div>
|
<div>
|
||||||
{inputComponent}
|
{isValidElement(inputComponent)
|
||||||
|
? cloneElement(inputComponent, { disabled: isDisabled } as Partial<typeof inputComponent.props>)
|
||||||
|
: inputComponent}
|
||||||
{/* {error?.message && Array.from(new Set(error.message.split('\n'))).map((msg, idx) => (
|
{/* {error?.message && Array.from(new Set(error.message.split('\n'))).map((msg, idx) => (
|
||||||
<p key={idx} className="text-red-500 text-sm mt-1" role="alert">
|
<p key={idx} className="text-red-500 text-sm mt-1" role="alert">
|
||||||
{msg}
|
{msg}
|
||||||
|
|||||||
@@ -11,13 +11,20 @@ import {
|
|||||||
UiModal,
|
UiModal,
|
||||||
} from "@common/business_components";
|
} from "@common/business_components";
|
||||||
import { Input } from "@common/components";
|
import { Input } from "@common/components";
|
||||||
import { Button } from "@common/components/ui";
|
import { Button, Label } from "@common/components/ui";
|
||||||
import { useSearchParams } from "next/navigation";
|
import { useSearchParams } from "next/navigation";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import { AccessibleFormField } from "./AccessibleFormField";
|
import { AccessibleFormField } from "./AccessibleFormField";
|
||||||
import type { ControllerRenderProps, UseFormReturn, FieldError } from "react-hook-form";
|
import {
|
||||||
|
type ControllerRenderProps,
|
||||||
|
type UseFormReturn,
|
||||||
|
type FieldError,
|
||||||
|
useWatch,
|
||||||
|
} from "react-hook-form";
|
||||||
import SearchInputText from "../common/searhDemandInput/component";
|
import SearchInputText from "../common/searhDemandInput/component";
|
||||||
import type { DemandCompType } from "@/app/store/sdmMng";
|
import React from "react";
|
||||||
|
import { sanitizeInput } from "../common/utils/utils";
|
||||||
|
import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form";
|
||||||
|
|
||||||
export interface SdmInfoRegFormProps {
|
export interface SdmInfoRegFormProps {
|
||||||
form: UseFormReturn<FormData>;
|
form: UseFormReturn<FormData>;
|
||||||
@@ -35,12 +42,15 @@ export function SdmInfoRegForm({
|
|||||||
facilityName,
|
facilityName,
|
||||||
}: SdmInfoRegFormProps) {
|
}: SdmInfoRegFormProps) {
|
||||||
const { initializeCommonData, Sdm } = useDmStore((state) => state);
|
const { initializeCommonData, Sdm } = useDmStore((state) => state);
|
||||||
const { useTypesData } = Sdm;
|
const { useTypesData, defaultRules, disableRules } = Sdm;
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
|
|
||||||
const [sdmNmValue, setSdmNmValue] = useState<string>(
|
const [sdmNmValue, setSdmNmValue] = useState<string>(
|
||||||
searchParams.get("dmdCoNm") || ""
|
searchParams.get("dmdCoNm") || ""
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const [frontPHdata, setFrontPHdata] = useState("0");
|
||||||
|
const [backPHdata, setBackPHdata] = useState("0");
|
||||||
const [isBznmTotNoDisabled, setIsBznmTotNoDisabled] = useState(false);
|
const [isBznmTotNoDisabled, setIsBznmTotNoDisabled] = useState(false);
|
||||||
const [isSimilarCase, setIsSimilarCase] = useState(false);
|
const [isSimilarCase, setIsSimilarCase] = useState(false);
|
||||||
const [key, setKey] = useState(0);
|
const [key, setKey] = useState(0);
|
||||||
@@ -57,14 +67,15 @@ export function SdmInfoRegForm({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("candidateTitle ", form.getValues("candidateTitle"));
|
console.log("candidateTitle ", form.getValues("candidateTitle"));
|
||||||
}, [form.getValues("candidateTitle")]);
|
}, [form.getValues]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (useTypesData && useTypesData.length > 0) {
|
if (useTypesData && useTypesData.length > 0) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
form.setValue("usePurpose", useTypesData[0]?.val?.toString() || "");
|
form.setValue("usePurpose", useTypesData[0]?.val?.toString() || "");
|
||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
}, [useTypesData, form]);
|
}, [useTypesData, form.setValue, form]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (facilityName) {
|
if (facilityName) {
|
||||||
@@ -72,7 +83,7 @@ export function SdmInfoRegForm({
|
|||||||
form.setValue("sdmNm", facilityName);
|
form.setValue("sdmNm", facilityName);
|
||||||
setKey((prev) => prev + 1);
|
setKey((prev) => prev + 1);
|
||||||
}
|
}
|
||||||
}, [facilityName, form]);
|
}, [facilityName, form.setValue, form]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (searchParams.get("dmdCoNm")) {
|
if (searchParams.get("dmdCoNm")) {
|
||||||
@@ -80,7 +91,7 @@ export function SdmInfoRegForm({
|
|||||||
setSdmNmValue(searchParams.get("dmdCoNm") || "");
|
setSdmNmValue(searchParams.get("dmdCoNm") || "");
|
||||||
setKey((prev) => prev + 1);
|
setKey((prev) => prev + 1);
|
||||||
}
|
}
|
||||||
}, [searchParams, form]);
|
}, [searchParams, form.setValue, form]);
|
||||||
|
|
||||||
const searchCandidate = (e: React.MouseEvent) => {
|
const searchCandidate = (e: React.MouseEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -109,6 +120,54 @@ export function SdmInfoRegForm({
|
|||||||
onCheckboxChange?.(checked);
|
onCheckboxChange?.(checked);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const watchPH = form.getValues(`ph`);
|
||||||
|
if (watchPH && watchPH !== undefined) {
|
||||||
|
const [frontPH, backPH] = watchPH.split("~");
|
||||||
|
if (frontPH) {
|
||||||
|
setFrontPHdata(frontPH);
|
||||||
|
}
|
||||||
|
if (backPH) {
|
||||||
|
setBackPHdata(backPH);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setFrontPHdata("0");
|
||||||
|
setBackPHdata("0");
|
||||||
|
}
|
||||||
|
}, [form.getValues(`ph`)]);
|
||||||
|
|
||||||
|
const isSetPh = useCallback(
|
||||||
|
(typePHdata: string, index: number) => {
|
||||||
|
const PHdata = form.getValues("ph");
|
||||||
|
const isPH = PHdata?.split("~")[index] || "";
|
||||||
|
if (index == 0) {
|
||||||
|
form.setValue("ph", `${isPH}~${typePHdata}`);
|
||||||
|
setBackPHdata(typePHdata);
|
||||||
|
} else if (index == 1) {
|
||||||
|
form.setValue("ph", `${typePHdata}~${isPH}`);
|
||||||
|
setFrontPHdata(typePHdata);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[form]
|
||||||
|
);
|
||||||
|
|
||||||
|
const usePurpose = useWatch({ control: form.control, name: "usePurpose" });
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!usePurpose) return;
|
||||||
|
|
||||||
|
// Apply default values
|
||||||
|
const defaults = defaultRules[usePurpose];
|
||||||
|
|
||||||
|
console.log("usePurpose", usePurpose);
|
||||||
|
console.log("defaults", defaults);
|
||||||
|
if (defaults) {
|
||||||
|
Object.entries(defaults).forEach(([field, value]) => {
|
||||||
|
form.setValue(field as keyof FormData, value, { shouldDirty: true });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [form.getValues("usePurpose")]);
|
||||||
|
|
||||||
// 시설 선택시 이벤트
|
// 시설 선택시 이벤트
|
||||||
const selectComp = useCallback(
|
const selectComp = useCallback(
|
||||||
(rtnData: DemandCompType[]) => {
|
(rtnData: DemandCompType[]) => {
|
||||||
@@ -178,7 +237,6 @@ export function SdmInfoRegForm({
|
|||||||
required: true,
|
required: true,
|
||||||
component: (field) => (
|
component: (field) => (
|
||||||
<Input
|
<Input
|
||||||
placeholder="요구수량(㎥/d)을 입력하세요"
|
|
||||||
type="text"
|
type="text"
|
||||||
className="!text-xl text-gray-600"
|
className="!text-xl text-gray-600"
|
||||||
value={field.value as string}
|
value={field.value as string}
|
||||||
@@ -222,7 +280,6 @@ export function SdmInfoRegForm({
|
|||||||
isDisabled={isBznmTotNoDisabled}
|
isDisabled={isBznmTotNoDisabled}
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
placeholder="희망단가(원/㎥)을 입력하세요"
|
|
||||||
type="text"
|
type="text"
|
||||||
className="!text-xl text-gray-600"
|
className="!text-xl text-gray-600"
|
||||||
value={field.value as string}
|
value={field.value as string}
|
||||||
@@ -244,221 +301,7 @@ export function SdmInfoRegForm({
|
|||||||
required: true,
|
required: true,
|
||||||
component: undefined,
|
component: undefined,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "grssClfg",
|
|
||||||
label: "총대장균군수(개/100ml)",
|
|
||||||
formIndex: 1,
|
|
||||||
required: true,
|
|
||||||
component: (field) => (
|
|
||||||
<Input
|
|
||||||
placeholder="총대장균군수를 입력하세요"
|
|
||||||
type="text"
|
|
||||||
className="!text-xl text-gray-600"
|
|
||||||
value={field.value as string}
|
|
||||||
onChange={field.onChange}
|
|
||||||
onBlur={field.onBlur}
|
|
||||||
name={field.name}
|
|
||||||
ref={field.ref}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "tn",
|
|
||||||
label: "총질소(T-N)(mg/L)",
|
|
||||||
formIndex: 1,
|
|
||||||
required: true,
|
|
||||||
component: (field) => (
|
|
||||||
<Input
|
|
||||||
placeholder="총질소를 입력하세요"
|
|
||||||
type="text"
|
|
||||||
className="!text-xl text-gray-600"
|
|
||||||
value={field.value as string}
|
|
||||||
onChange={field.onChange}
|
|
||||||
onBlur={field.onBlur}
|
|
||||||
name={field.name}
|
|
||||||
ref={field.ref}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "combResdch",
|
|
||||||
label: "결합잔류염소(mg/L)",
|
|
||||||
formIndex: 1,
|
|
||||||
required: true,
|
|
||||||
component: (field) => (
|
|
||||||
<Input
|
|
||||||
placeholder="결합잔류염소를 입력하세요"
|
|
||||||
type="text"
|
|
||||||
className="!text-xl text-gray-600"
|
|
||||||
value={field.value as string}
|
|
||||||
onChange={field.onChange}
|
|
||||||
onBlur={field.onBlur}
|
|
||||||
name={field.name}
|
|
||||||
ref={field.ref}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "tph",
|
|
||||||
label: "총인(T-P)(mg/L)",
|
|
||||||
formIndex: 1,
|
|
||||||
required: true,
|
|
||||||
component: (field) => (
|
|
||||||
<Input
|
|
||||||
placeholder="총인을 입력하세요"
|
|
||||||
type="text"
|
|
||||||
className="!text-xl text-gray-600"
|
|
||||||
value={field.value as string}
|
|
||||||
onChange={field.onChange}
|
|
||||||
onBlur={field.onBlur}
|
|
||||||
name={field.name}
|
|
||||||
ref={field.ref}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "trbt",
|
|
||||||
label: "탁도(NTU)",
|
|
||||||
formIndex: 1,
|
|
||||||
required: true,
|
|
||||||
component: (field) => (
|
|
||||||
<Input
|
|
||||||
placeholder="탁도를 입력하세요"
|
|
||||||
type="text"
|
|
||||||
className="!text-xl text-gray-600"
|
|
||||||
value={field.value as string}
|
|
||||||
onChange={field.onChange}
|
|
||||||
onBlur={field.onBlur}
|
|
||||||
name={field.name}
|
|
||||||
ref={field.ref}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ph",
|
|
||||||
label: "수소이온농도(pH)",
|
|
||||||
formIndex: 1,
|
|
||||||
required: true,
|
|
||||||
component: (field) => (
|
|
||||||
<Input
|
|
||||||
placeholder="수소이온농도를 입력하세요"
|
|
||||||
type="text"
|
|
||||||
className="!text-xl text-gray-600"
|
|
||||||
value={field.value as string}
|
|
||||||
onChange={field.onChange}
|
|
||||||
onBlur={field.onBlur}
|
|
||||||
name={field.name}
|
|
||||||
ref={field.ref}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "bod",
|
|
||||||
label: "생물학적 산소요구량(BOD)(mg/L)",
|
|
||||||
formIndex: 1,
|
|
||||||
required: true,
|
|
||||||
component: (field) => (
|
|
||||||
<Input
|
|
||||||
placeholder="생물학적 산소요구량을 입력하세요"
|
|
||||||
type="text"
|
|
||||||
className="!text-xl text-gray-600"
|
|
||||||
value={field.value as string}
|
|
||||||
onChange={field.onChange}
|
|
||||||
onBlur={field.onBlur}
|
|
||||||
name={field.name}
|
|
||||||
ref={field.ref}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "clIonQnt",
|
|
||||||
label: "염화물(mgCL/L)",
|
|
||||||
formIndex: 1,
|
|
||||||
required: true,
|
|
||||||
component: (field) => (
|
|
||||||
<Input
|
|
||||||
placeholder="염화물을 입력하세요"
|
|
||||||
type="text"
|
|
||||||
className="!text-xl text-gray-600"
|
|
||||||
value={field.value as string}
|
|
||||||
onChange={field.onChange}
|
|
||||||
onBlur={field.onBlur}
|
|
||||||
name={field.name}
|
|
||||||
ref={field.ref}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "smll",
|
|
||||||
label: "냄새",
|
|
||||||
formIndex: 1,
|
|
||||||
required: true,
|
|
||||||
component: (field) => (
|
|
||||||
<Input
|
|
||||||
placeholder="냄새를 입력하세요"
|
|
||||||
type="text"
|
|
||||||
className="!text-xl text-gray-600"
|
|
||||||
value={field.value as string}
|
|
||||||
onChange={field.onChange}
|
|
||||||
onBlur={field.onBlur}
|
|
||||||
name={field.name}
|
|
||||||
ref={field.ref}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "cdtnv",
|
|
||||||
label: "전기전도도(㎲/cm)",
|
|
||||||
formIndex: 1,
|
|
||||||
required: true,
|
|
||||||
component: (field) => (
|
|
||||||
<Input
|
|
||||||
placeholder="전기전도도를 입력하세요"
|
|
||||||
type="text"
|
|
||||||
className="!text-xl text-gray-600"
|
|
||||||
value={field.value as string}
|
|
||||||
onChange={field.onChange}
|
|
||||||
onBlur={field.onBlur}
|
|
||||||
name={field.name}
|
|
||||||
ref={field.ref}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "crmty",
|
|
||||||
label: "색도(도)",
|
|
||||||
formIndex: 1,
|
|
||||||
required: true,
|
|
||||||
component: (field) => (
|
|
||||||
<Input
|
|
||||||
placeholder="색도를 입력하세요"
|
|
||||||
type="text"
|
|
||||||
className="!text-xl text-gray-600"
|
|
||||||
value={field.value as string}
|
|
||||||
onChange={field.onChange}
|
|
||||||
onBlur={field.onBlur}
|
|
||||||
name={field.name}
|
|
||||||
ref={field.ref}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "rmrk",
|
|
||||||
label: "비고",
|
|
||||||
formIndex: 1,
|
|
||||||
component: (field) => (
|
|
||||||
<Input
|
|
||||||
placeholder="비고를 입력하세요"
|
|
||||||
type="text"
|
|
||||||
className="!text-xl text-gray-600"
|
|
||||||
value={field.value as string}
|
|
||||||
onChange={field.onChange}
|
|
||||||
onBlur={field.onBlur}
|
|
||||||
name={field.name}
|
|
||||||
ref={field.ref}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "candidateTitle",
|
name: "candidateTitle",
|
||||||
label: CANDIDATE || "공급처 후보지 선택(필수아님)",
|
label: CANDIDATE || "공급처 후보지 선택(필수아님)",
|
||||||
@@ -466,10 +309,20 @@ export function SdmInfoRegForm({
|
|||||||
component: () => (
|
component: () => (
|
||||||
<div>
|
<div>
|
||||||
<div className="-mt-14 float-right flex gap-10">
|
<div className="-mt-14 float-right flex gap-10">
|
||||||
<Button className={"bg-gray-200"} onClick={searchCandidate}>
|
<Button
|
||||||
|
className="rounded-md"
|
||||||
|
color="sky"
|
||||||
|
size={"sm"}
|
||||||
|
onClick={searchCandidate}
|
||||||
|
>
|
||||||
후보지 조회
|
후보지 조회
|
||||||
</Button>
|
</Button>
|
||||||
<Button className={"bg-gray-200"} onClick={searchSimilarCase}>
|
<Button
|
||||||
|
className="rounded-md"
|
||||||
|
color="sky"
|
||||||
|
size={"sm"}
|
||||||
|
onClick={searchSimilarCase}
|
||||||
|
>
|
||||||
유사사례
|
유사사례
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@@ -495,9 +348,9 @@ export function SdmInfoRegForm({
|
|||||||
const normalFields = formFields.filter(
|
const normalFields = formFields.filter(
|
||||||
(f) => f.formIndex === 0 && f.component
|
(f) => f.formIndex === 0 && f.component
|
||||||
);
|
);
|
||||||
const groupFields = formFields.filter(
|
// const groupFields = formFields.filter(
|
||||||
(f) => f.formIndex === 1 && f.component
|
// (f) => f.formIndex === 1 && f.component
|
||||||
);
|
// );
|
||||||
const candidateFields = formFields.filter(
|
const candidateFields = formFields.filter(
|
||||||
(f) => f.formIndex === 2 && f.component
|
(f) => f.formIndex === 2 && f.component
|
||||||
);
|
);
|
||||||
@@ -512,17 +365,15 @@ export function SdmInfoRegForm({
|
|||||||
name={name}
|
name={name}
|
||||||
render={({ field }) =>
|
render={({ field }) =>
|
||||||
name === "money" ? (
|
name === "money" ? (
|
||||||
component(field)
|
// component(field)
|
||||||
|
<FormUi label={label + "*"}>{component(field)}</FormUi>
|
||||||
) : (
|
) : (
|
||||||
// <FormUi label={label}>
|
|
||||||
// {component(field)}
|
|
||||||
// </FormUi>
|
|
||||||
<AccessibleFormField
|
<AccessibleFormField
|
||||||
field={field}
|
field={field}
|
||||||
label={label}
|
label={label}
|
||||||
required={required}
|
required={required}
|
||||||
error={
|
error={
|
||||||
typeof form.formState.errors[name]?.message === 'string'
|
typeof form.formState.errors[name]?.message === "string"
|
||||||
? (form.formState.errors[name] as FieldError)
|
? (form.formState.errors[name] as FieldError)
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
@@ -534,37 +385,527 @@ export function SdmInfoRegForm({
|
|||||||
) : null
|
) : null
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{groupFields.length > 0 && (
|
<div className="mt-10">
|
||||||
<div className="mt-10">
|
<FormLabel className="text-xl">요구수질</FormLabel>
|
||||||
<FormLabel className="text-xl">요구수질</FormLabel>
|
<div className="grid grid-cols-2 gap-x-10 gap-y-6 mt-3 mb-3">
|
||||||
<div className="flex flex-wrap justify-start gap-10 mt-3 mb-3">
|
<FormField
|
||||||
{groupFields.map(({ name, label, component, required }) => (
|
control={form.control}
|
||||||
<div key={name} className="min-w-[180px]">
|
name={`grssClfg`}
|
||||||
<FormField
|
render={({ field }) => {
|
||||||
control={form.control}
|
const disabledFields = usePurpose ? disableRules[usePurpose] : [];
|
||||||
name={name}
|
const isDisabled = disabledFields
|
||||||
render={({ field }) => (
|
? disabledFields.includes(field.name)
|
||||||
// <FormUi label={label}>
|
: true;
|
||||||
// {component?.(field)}
|
return (
|
||||||
// </FormUi>
|
<FormUi
|
||||||
<AccessibleFormField
|
label={
|
||||||
field={field}
|
!isDisabled ? `총대장균군수(개/mg)*` : "총대장균군수(개/mg)"
|
||||||
label={label}
|
}
|
||||||
required={required}
|
>
|
||||||
error={
|
<div className="flex items-center gap-2">
|
||||||
typeof form.formState.errors[name]?.message === 'string'
|
<div className="relative flex-1 min-w-0">
|
||||||
? (form.formState.errors[name] as FieldError)
|
<Input
|
||||||
: undefined
|
type="text"
|
||||||
}
|
className="w-full pr-16 border py-2 text-right rounded-md"
|
||||||
inputComponent={component?.(field)}
|
placeholder=""
|
||||||
/>
|
onChange={(e) => {
|
||||||
)}
|
const inputValue = e.target.value.replace(
|
||||||
/>
|
/[^0-9]/g,
|
||||||
</div>
|
""
|
||||||
))}
|
); // 정수만
|
||||||
|
field.onChange(
|
||||||
|
inputValue === "" ? null : Number(inputValue)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
value={
|
||||||
|
field.value !== undefined && field.value !== null
|
||||||
|
? `${field.value}`
|
||||||
|
: "불검출"
|
||||||
|
}
|
||||||
|
maxLength={6}
|
||||||
|
disabled={isDisabled}
|
||||||
|
onBlur={field.onBlur}
|
||||||
|
name={field.name}
|
||||||
|
ref={field.ref}
|
||||||
|
/>
|
||||||
|
{/* TODO: 총대장균군수 확인 필요*/}
|
||||||
|
{field.value !== null ? (
|
||||||
|
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
|
||||||
|
이하
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormUi>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={`tn`}
|
||||||
|
render={({ field }) => {
|
||||||
|
const disabledFields = usePurpose ? disableRules[usePurpose] : [];
|
||||||
|
const isDisabled = disabledFields
|
||||||
|
? disabledFields.includes(field.name)
|
||||||
|
: true;
|
||||||
|
return (
|
||||||
|
<FormUi
|
||||||
|
label={
|
||||||
|
!isDisabled ? `총질소(T-N)(mg/L)*` : "총질소(T-N)(mg/L)"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="relative flex-1 min-w-0">
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
className="w-full pr-16 border py-2 text-right rounded-md"
|
||||||
|
placeholder=""
|
||||||
|
onChange={(e) => {
|
||||||
|
const inputValue = e.target.value.replace(
|
||||||
|
/[^0-9]/g,
|
||||||
|
""
|
||||||
|
); // 정수만
|
||||||
|
field.onChange(
|
||||||
|
inputValue === "" ? null : Number(inputValue)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
value={
|
||||||
|
field.value !== undefined && field.value !== null
|
||||||
|
? `${field.value}`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
maxLength={6}
|
||||||
|
disabled={isDisabled}
|
||||||
|
onBlur={field.onBlur}
|
||||||
|
name={field.name}
|
||||||
|
ref={field.ref}
|
||||||
|
/>
|
||||||
|
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
|
||||||
|
이하
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormUi>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={`combResdch`}
|
||||||
|
render={({ field }) => {
|
||||||
|
const disabledFields = usePurpose ? disableRules[usePurpose] : [];
|
||||||
|
const isDisabled = disabledFields
|
||||||
|
? disabledFields.includes(field.name)
|
||||||
|
: true;
|
||||||
|
return (
|
||||||
|
<FormUi
|
||||||
|
label={
|
||||||
|
!isDisabled ? `결합잔류염소(mg/L)*` : "결합잔류염소(mg/L)"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="relative flex-1 min-w-0">
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
className="w-full pr-16 border py-2 text-right rounded-md"
|
||||||
|
placeholder=""
|
||||||
|
onChange={(e) => {
|
||||||
|
const cleanValue = sanitizeInput(
|
||||||
|
e.target.value,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
field.onChange(
|
||||||
|
cleanValue === "" ? null : Number(cleanValue)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
value={field.value ?? ""}
|
||||||
|
maxLength={6}
|
||||||
|
disabled={isDisabled}
|
||||||
|
onBlur={field.onBlur}
|
||||||
|
name={field.name}
|
||||||
|
ref={field.ref}
|
||||||
|
/>
|
||||||
|
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
|
||||||
|
이상
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormUi>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={`tph`}
|
||||||
|
render={({ field }) => {
|
||||||
|
const disabledFields = usePurpose ? disableRules[usePurpose] : [];
|
||||||
|
const isDisabled = disabledFields
|
||||||
|
? disabledFields.includes(field.name)
|
||||||
|
: true;
|
||||||
|
return (
|
||||||
|
<FormUi
|
||||||
|
label={!isDisabled ? `총인(T-P)(mg/L)*` : "총인(T-P)(mg/L)"}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="relative flex-1 min-w-0">
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
className="w-full pr-16 border py-2 text-right rounded-md"
|
||||||
|
placeholder=""
|
||||||
|
onChange={(e) => {
|
||||||
|
const cleanValue = sanitizeInput(
|
||||||
|
e.target.value,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
field.onChange(
|
||||||
|
cleanValue === "" ? null : Number(cleanValue)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
value={field.value ?? ""}
|
||||||
|
maxLength={6}
|
||||||
|
disabled={isDisabled}
|
||||||
|
onBlur={field.onBlur}
|
||||||
|
name={field.name}
|
||||||
|
ref={field.ref}
|
||||||
|
/>
|
||||||
|
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
|
||||||
|
이하
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormUi>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={`trbt`}
|
||||||
|
render={({ field }) => {
|
||||||
|
const disabledFields = usePurpose ? disableRules[usePurpose] : [];
|
||||||
|
const isDisabled = disabledFields
|
||||||
|
? disabledFields.includes(field.name)
|
||||||
|
: true;
|
||||||
|
return (
|
||||||
|
<FormUi label={!isDisabled ? `탁도(NTU)*` : "탁도(NTU)"}>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="relative flex-1 min-w-0">
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
className="w-full pr-16 border py-2 text-right rounded-md"
|
||||||
|
placeholder=""
|
||||||
|
onChange={(e) => {
|
||||||
|
const inputValue = e.target.value.replace(
|
||||||
|
/[^0-9]/g,
|
||||||
|
""
|
||||||
|
); // 정수만
|
||||||
|
field.onChange(
|
||||||
|
inputValue === "" ? null : Number(inputValue)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
value={
|
||||||
|
field.value !== undefined && field.value !== null
|
||||||
|
? `${field.value}`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
maxLength={6}
|
||||||
|
disabled={isDisabled}
|
||||||
|
onBlur={field.onBlur}
|
||||||
|
name={field.name}
|
||||||
|
ref={field.ref}
|
||||||
|
/>
|
||||||
|
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
|
||||||
|
이하
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormUi>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div className="col-span-1">
|
||||||
|
<Label className="text-xl">수소이온농도(PH)</Label>
|
||||||
|
<div className="flex flex-row items-center gap-2">
|
||||||
|
<Input
|
||||||
|
className="!text-xl w-36"
|
||||||
|
placeholder=""
|
||||||
|
type="text"
|
||||||
|
onChange={(e) => {
|
||||||
|
const cleanValue = sanitizeInput(e.target.value, true);
|
||||||
|
isSetPh(cleanValue, 1);
|
||||||
|
}}
|
||||||
|
value={frontPHdata ?? ""}
|
||||||
|
maxLength={5}
|
||||||
|
/>
|
||||||
|
<span className="text-xl mx-2">~</span>
|
||||||
|
<Input
|
||||||
|
className="!text-xl w-36 "
|
||||||
|
placeholder=""
|
||||||
|
type="text"
|
||||||
|
onChange={(e) => {
|
||||||
|
const cleanValue = sanitizeInput(e.target.value, true);
|
||||||
|
isSetPh(cleanValue, 0);
|
||||||
|
}}
|
||||||
|
value={backPHdata ?? ""}
|
||||||
|
maxLength={5}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={`bod`}
|
||||||
|
render={({ field }) => {
|
||||||
|
const disabledFields = usePurpose ? disableRules[usePurpose] : [];
|
||||||
|
const isDisabled = disabledFields
|
||||||
|
? disabledFields.includes(field.name)
|
||||||
|
: true;
|
||||||
|
return (
|
||||||
|
<FormUi
|
||||||
|
label={
|
||||||
|
!isDisabled
|
||||||
|
? `생물학적 산소요구량(BOD)(mg/L)*`
|
||||||
|
: "생물학적 산소요구량(BOD)(mg/L)"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="relative flex-1 min-w-0">
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
className="w-full pr-16 border py-2 text-right rounded-md"
|
||||||
|
placeholder=""
|
||||||
|
onChange={(e) => {
|
||||||
|
const inputValue = e.target.value.replace(
|
||||||
|
/[^0-9]/g,
|
||||||
|
""
|
||||||
|
); // 정수만
|
||||||
|
field.onChange(
|
||||||
|
inputValue === "" ? null : Number(inputValue)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
value={
|
||||||
|
field.value !== undefined && field.value !== null
|
||||||
|
? `${field.value}`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
maxLength={6}
|
||||||
|
disabled={isDisabled}
|
||||||
|
onBlur={field.onBlur}
|
||||||
|
name={field.name}
|
||||||
|
ref={field.ref}
|
||||||
|
/>
|
||||||
|
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
|
||||||
|
이하
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormUi>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={`clIonQnt`}
|
||||||
|
render={({ field }) => {
|
||||||
|
const disabledFields = usePurpose ? disableRules[usePurpose] : [];
|
||||||
|
const isDisabled = disabledFields
|
||||||
|
? disabledFields.includes(field.name)
|
||||||
|
: true;
|
||||||
|
return (
|
||||||
|
<FormUi
|
||||||
|
label={!isDisabled ? `염화물(mgCL/L)*` : "염화물(mgCL/L)"}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="relative flex-1 min-w-0">
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
className="w-full pr-16 border py-2 text-right rounded-md"
|
||||||
|
placeholder=""
|
||||||
|
onChange={(e) => {
|
||||||
|
const inputValue = e.target.value.replace(
|
||||||
|
/[^0-9]/g,
|
||||||
|
""
|
||||||
|
); // 정수만
|
||||||
|
field.onChange(
|
||||||
|
inputValue === "" ? null : Number(inputValue)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
value={
|
||||||
|
field.value !== undefined && field.value !== null
|
||||||
|
? `${field.value}`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
maxLength={6}
|
||||||
|
disabled={isDisabled}
|
||||||
|
onBlur={field.onBlur}
|
||||||
|
name={field.name}
|
||||||
|
ref={field.ref}
|
||||||
|
/>
|
||||||
|
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
|
||||||
|
이하
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormUi>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={`smll`}
|
||||||
|
render={({ field }) => {
|
||||||
|
const disabledFields = usePurpose ? disableRules[usePurpose] : [];
|
||||||
|
const isDisabled = disabledFields
|
||||||
|
? disabledFields.includes(field.name)
|
||||||
|
: true;
|
||||||
|
return (
|
||||||
|
<FormUi label={!isDisabled ? `냄새*` : "냄새"}>
|
||||||
|
<SelectBox
|
||||||
|
className="!text-2xl rounded-md"
|
||||||
|
label={""}
|
||||||
|
selectClass={undefined}
|
||||||
|
selectArray={[
|
||||||
|
{ text: "불쾌하지않을것", val: "불쾌하지않을것" },
|
||||||
|
{ text: "해당사항없음", val: "해당사항없음" },
|
||||||
|
]}
|
||||||
|
onSelectValue={(val: string | number) => {
|
||||||
|
field.onChange(val.toString());
|
||||||
|
}}
|
||||||
|
value={field.value || "불쾌하지않을것"}
|
||||||
|
readOnly={isDisabled}
|
||||||
|
onBlur={field.onBlur}
|
||||||
|
ref={field.ref}
|
||||||
|
/>
|
||||||
|
</FormUi>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={`cdtnv`}
|
||||||
|
render={({ field }) => {
|
||||||
|
const disabledFields = usePurpose ? disableRules[usePurpose] : [];
|
||||||
|
const isDisabled = disabledFields
|
||||||
|
? disabledFields.includes(field.name)
|
||||||
|
: true;
|
||||||
|
return (
|
||||||
|
<FormUi
|
||||||
|
label={
|
||||||
|
!isDisabled ? `전기전도도(㎲/cm)*` : "전기전도도(㎲/cm)"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="relative flex-1 min-w-0">
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
className="w-full pr-16 border py-2 text-right rounded-md"
|
||||||
|
placeholder=""
|
||||||
|
onChange={(e) => {
|
||||||
|
const inputValue = e.target.value.replace(
|
||||||
|
/[^0-9]/g,
|
||||||
|
""
|
||||||
|
); // 정수만
|
||||||
|
field.onChange(
|
||||||
|
inputValue === "" ? null : Number(inputValue)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
value={
|
||||||
|
field.value !== undefined && field.value !== null
|
||||||
|
? `${field.value}`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
maxLength={6}
|
||||||
|
disabled={isDisabled}
|
||||||
|
onBlur={field.onBlur}
|
||||||
|
name={field.name}
|
||||||
|
ref={field.ref}
|
||||||
|
/>
|
||||||
|
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
|
||||||
|
이하
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormUi>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={`crmty`}
|
||||||
|
render={({ field }) => {
|
||||||
|
const disabledFields = usePurpose ? disableRules[usePurpose] : [];
|
||||||
|
const isDisabled = disabledFields
|
||||||
|
? disabledFields.includes(field.name)
|
||||||
|
: true;
|
||||||
|
return (
|
||||||
|
<FormUi label={!isDisabled ? `색도(도)*` : "색도(도)"}>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="relative flex-1 min-w-0">
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
className="w-full pr-16 border py-2 text-right rounded-md"
|
||||||
|
placeholder=""
|
||||||
|
onChange={(e) => {
|
||||||
|
const inputValue = e.target.value.replace(
|
||||||
|
/[^0-9]/g,
|
||||||
|
""
|
||||||
|
); // 정수만
|
||||||
|
field.onChange(
|
||||||
|
inputValue === "" ? null : Number(inputValue)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
value={
|
||||||
|
field.value !== undefined && field.value !== null
|
||||||
|
? `${field.value}`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
maxLength={6}
|
||||||
|
disabled={isDisabled}
|
||||||
|
onBlur={field.onBlur}
|
||||||
|
name={field.name}
|
||||||
|
ref={field.ref}
|
||||||
|
/>
|
||||||
|
<span className="text-xl absolute inset-y-0 right-3 flex items-center text-gray-500 pointer-events-none">
|
||||||
|
이하
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormUi>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name={`rmrk`}
|
||||||
|
render={({ field }) => {
|
||||||
|
return (
|
||||||
|
<FormUi label={"비고"}>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="relative flex-1 min-w-0">
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
className="w-full pr-16 border py-2 text-right rounded-md"
|
||||||
|
placeholder=""
|
||||||
|
onChange={(e) => {
|
||||||
|
field.onChange(e.target.value);
|
||||||
|
}}
|
||||||
|
value={
|
||||||
|
field.value !== undefined && field.value !== ""
|
||||||
|
? `${field.value}`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
onBlur={field.onBlur}
|
||||||
|
name={field.name}
|
||||||
|
ref={field.ref}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormUi>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
|
|
||||||
{candidateFields.map(({ name, label, component, required }, index) =>
|
{candidateFields.map(({ name, label, component, required }, index) =>
|
||||||
component ? (
|
component ? (
|
||||||
@@ -581,7 +922,7 @@ export function SdmInfoRegForm({
|
|||||||
label={label}
|
label={label}
|
||||||
required={required}
|
required={required}
|
||||||
error={
|
error={
|
||||||
typeof form.formState.errors[name]?.message === 'string'
|
typeof form.formState.errors[name]?.message === "string"
|
||||||
? (form.formState.errors[name] as FieldError)
|
? (form.formState.errors[name] as FieldError)
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import { useDmStore } from "@/app/store";
|
import { useDmStore } from "@/app/store";
|
||||||
import type { DemandCompType } from "@/app/store/sdmMng";
|
|
||||||
import { BZNM_TOT_NO, FormField, FormUi } from "@common/business_components";
|
import { BZNM_TOT_NO, FormField, FormUi } from "@common/business_components";
|
||||||
|
import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form";
|
||||||
import { Button, Input } from "@common/components";
|
import { Button, Input } from "@common/components";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { sha512 } from 'js-sha512';
|
import { sha512 } from 'js-sha512';
|
||||||
import { useEffect, useState, useMemo } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { FormProvider, useForm, type ControllerRenderProps } from "react-hook-form";
|
import { FormProvider, useForm, type ControllerRenderProps } from "react-hook-form";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
|
|
||||||
export function SdmLoginForm() {
|
export function SdmLoginForm() {
|
||||||
@@ -15,10 +16,10 @@ export function SdmLoginForm() {
|
|||||||
const formatBusinessNumber = (value: string) => {
|
const formatBusinessNumber = (value: string) => {
|
||||||
// 숫자만 추출
|
// 숫자만 추출
|
||||||
const digitsOnly = value.replace(/\D/g, "");
|
const digitsOnly = value.replace(/\D/g, "");
|
||||||
|
|
||||||
// 10자리까지만 처리
|
// 10자리까지만 처리
|
||||||
const limitedDigits = digitsOnly.slice(0, 10);
|
const limitedDigits = digitsOnly.slice(0, 10);
|
||||||
|
|
||||||
// 3-2-5 형식으로 포맷팅
|
// 3-2-5 형식으로 포맷팅
|
||||||
if (limitedDigits.length <= 3) {
|
if (limitedDigits.length <= 3) {
|
||||||
return limitedDigits;
|
return limitedDigits;
|
||||||
@@ -28,18 +29,18 @@ export function SdmLoginForm() {
|
|||||||
return `${limitedDigits.slice(0, 3)}-${limitedDigits.slice(3, 5)}-${limitedDigits.slice(5)}`;
|
return `${limitedDigits.slice(0, 3)}-${limitedDigits.slice(3, 5)}-${limitedDigits.slice(5)}`;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 스키마를 useMemo로 최적화
|
// 스키마를 useMemo로 최적화
|
||||||
const sdmLoginFormSchema = useMemo(() => z.object({
|
const sdmLoginFormSchema = useMemo(() => z.object({
|
||||||
dmdInfoId: z.string()
|
dmdInfoId: z.string()
|
||||||
.min(1, "사업자등록번호를 입력해주세요")
|
.min(1, "사업자등록번호를 입력해주세요")
|
||||||
.regex(/^\d{10}$/, "사업자등록번호는 10자리 숫자만 입력 가능합니다"),
|
.regex(/^\d{10}$/, "사업자등록번호는 10자리 숫자만 입력 가능합니다"),
|
||||||
bznmTotNo: isBznmTotNoDisabled
|
bznmTotNo: isBznmTotNoDisabled
|
||||||
? z.string().optional()
|
? z.string().optional()
|
||||||
: z.string().length(4, "종사업자등록번호는 4자리 숫자만 입력 가능합니다"),
|
: z.string().length(4, "종사업자등록번호는 4자리 숫자만 입력 가능합니다"),
|
||||||
password: z.string()
|
password: z.string()
|
||||||
.min(1, "비밀번호를 입력해주세요")
|
.min(1, "비밀번호를 입력해주세요")
|
||||||
.min(8, "비밀번호는 8자 이상 입력해주세요")
|
.min(8, "비밀번호는 8자 이상 입력해주세요")
|
||||||
.max(16, "비밀번호는 16자 이내로 입력해주세요"),
|
.max(16, "비밀번호는 16자 이내로 입력해주세요"),
|
||||||
rgtr: z.string().optional(),
|
rgtr: z.string().optional(),
|
||||||
dmdAplyPswd: z.string().optional(),
|
dmdAplyPswd: z.string().optional(),
|
||||||
@@ -47,7 +48,7 @@ export function SdmLoginForm() {
|
|||||||
|
|
||||||
type FormData = z.infer<typeof sdmLoginFormSchema>;
|
type FormData = z.infer<typeof sdmLoginFormSchema>;
|
||||||
type FieldComponent = (field: ControllerRenderProps<FormData, keyof FormData>) => JSX.Element;
|
type FieldComponent = (field: ControllerRenderProps<FormData, keyof FormData>) => JSX.Element;
|
||||||
|
|
||||||
const formSchema = sdmLoginFormSchema;
|
const formSchema = sdmLoginFormSchema;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -72,6 +73,26 @@ export function SdmLoginForm() {
|
|||||||
setIsBznmTotNoDisabled(checked);
|
setIsBznmTotNoDisabled(checked);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const initPassword = () => {
|
||||||
|
toast(
|
||||||
|
(t) => (
|
||||||
|
<div className="flex flex-col items-center">
|
||||||
|
<div className="text-2xl mb-2">
|
||||||
|
관리자(031-0000-0000)에게 비밀번호 초기화 요청을 유선으로 하시기 바랍니다.
|
||||||
|
</div>
|
||||||
|
<Button size={"sm"} onClick={() => toast.dismiss(t.id)}>
|
||||||
|
확인
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
{
|
||||||
|
id: "pwd-reset",
|
||||||
|
duration: Infinity,
|
||||||
|
position: "top-center",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const handleLogin = () => {
|
const handleLogin = () => {
|
||||||
const data = form.getValues();
|
const data = form.getValues();
|
||||||
const passwordStr = sha512.hex(data.password)
|
const passwordStr = sha512.hex(data.password)
|
||||||
@@ -82,61 +103,61 @@ export function SdmLoginForm() {
|
|||||||
}
|
}
|
||||||
actionLogin(param as unknown as DemandCompType);
|
actionLogin(param as unknown as DemandCompType);
|
||||||
};
|
};
|
||||||
|
|
||||||
const formFields: Array<{
|
const formFields: Array<{
|
||||||
name: keyof FormData;
|
name: keyof FormData;
|
||||||
label: string;
|
label: string;
|
||||||
component: FieldComponent | undefined;
|
component: FieldComponent | undefined;
|
||||||
}> = [
|
}> = [
|
||||||
{
|
{
|
||||||
name: "dmdInfoId",
|
name: "dmdInfoId",
|
||||||
label: "사업자등록번호",
|
label: "사업자등록번호",
|
||||||
component: (field) => (
|
component: (field) => (
|
||||||
<Input
|
<Input
|
||||||
placeholder="사업자등록번호를 입력하세요"
|
placeholder="사업자등록번호를 입력하세요"
|
||||||
type="text"
|
|
||||||
className="!mt-5 !mb-5 !text-xl text-gray-600"
|
|
||||||
{...field}
|
|
||||||
value={formatBusinessNumber(field.value as string)}
|
|
||||||
onChange={(e) => {
|
|
||||||
const dmdId = e.target.value.replace(/\D/g, "").slice(0, 10);
|
|
||||||
field.onChange(dmdId);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "bznmTotNo",
|
|
||||||
label: BZNM_TOT_NO || "종사업자등록번호",
|
|
||||||
component: (field) => (
|
|
||||||
<FormUi
|
|
||||||
label="종사업자등록번호"
|
|
||||||
onCheckboxChange={handleCheckboxChange}
|
|
||||||
isDisabled={isBznmTotNoDisabled}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
placeholder="여러사업장이 있을 경우 입력해주세요"
|
|
||||||
type="text"
|
type="text"
|
||||||
className="!mt-5 !text-xl text-gray-600"
|
className="!mt-5 !mb-5 !text-xl text-gray-600"
|
||||||
disabled={isBznmTotNoDisabled}
|
{...field}
|
||||||
|
value={formatBusinessNumber(field.value as string)}
|
||||||
|
onChange={(e) => {
|
||||||
|
const dmdId = e.target.value.replace(/\D/g, "").slice(0, 10);
|
||||||
|
field.onChange(dmdId);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "bznmTotNo",
|
||||||
|
label: BZNM_TOT_NO || "종사업자등록번호",
|
||||||
|
component: (field) => (
|
||||||
|
<FormUi
|
||||||
|
label="종사업자등록번호"
|
||||||
|
onCheckboxChange={handleCheckboxChange}
|
||||||
|
isDisabled={isBznmTotNoDisabled}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
placeholder="여러사업장이 있을 경우 입력해주세요"
|
||||||
|
type="text"
|
||||||
|
className="!mt-5 !text-xl text-gray-600"
|
||||||
|
disabled={isBznmTotNoDisabled}
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</FormUi>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "password",
|
||||||
|
label: "비밀번호",
|
||||||
|
component: (field) => (
|
||||||
|
<Input
|
||||||
|
placeholder="비밀번호를 입력하세요"
|
||||||
|
type="password"
|
||||||
|
className="!mt-5 !mb-5 !text-xl text-gray-600"
|
||||||
{...field}
|
{...field}
|
||||||
/>
|
/>
|
||||||
</FormUi>
|
)
|
||||||
)
|
}
|
||||||
},
|
];
|
||||||
{
|
|
||||||
name: "password",
|
|
||||||
label: "비밀번호",
|
|
||||||
component: (field) => (
|
|
||||||
<Input
|
|
||||||
placeholder="비밀번호를 입력하세요"
|
|
||||||
type="password"
|
|
||||||
className="!mt-5 !mb-5 !text-xl text-gray-600"
|
|
||||||
{...field}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -148,11 +169,11 @@ export function SdmLoginForm() {
|
|||||||
control={form.control}
|
control={form.control}
|
||||||
name={name}
|
name={name}
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
label==='종사업자등록번호' ?
|
label === '종사업자등록번호' ?
|
||||||
<>
|
<>
|
||||||
{component && component(field)}
|
{component && component(field)}
|
||||||
</>
|
</>
|
||||||
: <FormUi label={label}>
|
: <FormUi label={label}>
|
||||||
{component && component(field)}
|
{component && component(field)}
|
||||||
</FormUi>
|
</FormUi>
|
||||||
)}
|
)}
|
||||||
@@ -160,12 +181,15 @@ export function SdmLoginForm() {
|
|||||||
))}
|
))}
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
<div className="flex justify-center pt-4">
|
<div className="flex justify-center pt-4">
|
||||||
<Button
|
<div className="flex flex-col items-center">
|
||||||
onClick={handleLogin}
|
<Button
|
||||||
className="w-32 bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-4 rounded-md transition-colors duration-200"
|
onClick={handleLogin}
|
||||||
>
|
className="w-32 bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-4 rounded-md transition-colors duration-200"
|
||||||
로그인
|
>
|
||||||
</Button>
|
로그인
|
||||||
|
</Button>
|
||||||
|
<div className="text-xl mt-2 text-gray-400 cursor-pointer" onClick={initPassword}>비밀번호 초기화 요청</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev --turbopack",
|
"dev": "next dev -p 3005",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start:dm": "next start -p 3005",
|
||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 35 KiB |
Reference in New Issue
Block a user