diff --git a/apps/sn/app/components/ui/contentLayout.tsx b/apps/sn/app/components/ui/contentLayout.tsx new file mode 100644 index 000000000..738e26b16 --- /dev/null +++ b/apps/sn/app/components/ui/contentLayout.tsx @@ -0,0 +1,18 @@ +import { ContentsDiv, MainDiv, Title } from '@common/business_components/ui' +import React, { type ReactNode } from 'react' +type LayoutNode = { + children : ReactNode + title : string +} +const ContentLayout = ({children, title} : LayoutNode) => { + return ( + + + <ContentsDiv> + {children} + </ContentsDiv> + </MainDiv> + ) +} + +export default ContentLayout \ No newline at end of file diff --git a/apps/sn/app/components/fileUploadForm.tsx b/apps/sn/app/components/ui/fileUploadForm.tsx similarity index 100% rename from apps/sn/app/components/fileUploadForm.tsx rename to apps/sn/app/components/ui/fileUploadForm.tsx diff --git a/apps/sn/app/ii/mock/page.tsx b/apps/sn/app/ii/mock/page.tsx new file mode 100644 index 000000000..530e2049e --- /dev/null +++ b/apps/sn/app/ii/mock/page.tsx @@ -0,0 +1,214 @@ +"use client" + +import { z } from "zod" +import { useForm, useFieldArray } from "react-hook-form" +import { zodResolver } from "@hookform/resolvers/zod" +import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, FormUi } from "@common/business_components/ui" +import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Input, Button } from "@common/components/ui" +import { UiTable } from "@common/business_components/ui" +import React from "react" +import ContentLayout from "@/components/ui/contentLayout" +import ListDiv from "@common/business_components/ui/list_div" + +// zod 스키마 정의 +const formSchema = z.object({ + region: z.string(), + rdiiArea: z.string(), + rtkSource: z.string(), + unitFactors: z.array(z.object({ + response: z.string(), + R: z.string(), + T: z.string(), + K: z.string(), + })), + initialDepths: z.array(z.object({ + response: z.string(), + Dmax: z.string(), + Drec: z.string(), + Do: z.string(), + })) +}) + +export default function RTKForm() { + const form = useForm<z.infer<typeof formSchema>>({ + resolver: zodResolver(formSchema), + defaultValues: { + region: "", + rdiiArea: "", + rtkSource: "", + unitFactors: [ + { response: "Short-Term", R: "", T: "", K: "" }, + { response: "Medium-Term", R: "", T: "", K: "" }, + { response: "Long-Term", R: "", T: "", K: "" }, + ], + initialDepths: [ + { response: "Short-Term", Dmax: "", Drec: "", Do: "" }, + { response: "Medium-Term", Dmax: "", Drec: "", Do: "" }, + { response: "Long-Term", Dmax: "", Drec: "", Do: "" }, + ], + } + }) + + const { fields: unitFactorFields } = useFieldArray({ + control: form.control, + name: "unitFactors" + }) + + const { fields: initialDepthFields } = useFieldArray({ + control: form.control, + name: "initialDepths" + }) + + const onSubmit = (data: z.infer<typeof formSchema>) => { + console.log("✅ 제출 데이터:", data) + } + + // 단위도 계수 테이블 설정 + const unitFactorHeadlist = [ + { id: 'response', title: 'Response' }, + { id: 'R', title: 'R' }, + { id: 'T', title: 'T' }, + { id: 'K', title: 'K' } + ] + + // 초기 차단 깊이 테이블 설정 + const initialDepthHeadlist = [ + { id: 'response', title: 'Response' }, + { id: 'Dmax', title: 'Dmax' }, + { id: 'Drec', title: 'Drec' }, + { id: 'Do', title: 'Do' } + ] + const rtxNmHeadlist = [ + { id: 'no', title: '번호' }, + { id: 'hasu', title: '하수처리장' }, + { id: 'guyeok', title: '처리구역' }, + { id: 'cnfcj', title: '출처' }, + { id: 'time', title: '입력시간' } + ] + // 테이블 페이지 변경 핸들러 + const handlePageChange = (page: number) => { + console.log('Page changed:', page) + } + + return ( + <ContentLayout title="모의정보 설정"> + <ListDiv> + <div className="card-header"> + <h3 className="text-2xl font-medium">모의정보 설정</h3> + </div> + <Form {...form}> + <form onSubmit={form.handleSubmit(onSubmit)}> + <div className="card !m-[1.2rem]"> + {/* 기본 정보 입력 폼 */} + <div className="space-y-[1.2rem]"> + <FormField + control={form.control} + name="region" + render={({ field }) => ( + <FormUi label="○ 처리구역" className="flex items-center"> + <Select onValueChange={field.onChange} value={field.value}> + <SelectTrigger className="w-[150px]"> + <SelectValue placeholder="선택하세요" /> + </SelectTrigger> + <SelectContent> + <SelectItem value="양평">양평</SelectItem> + <SelectItem value="강남">강남</SelectItem> + <SelectItem value="마포">마포</SelectItem> + </SelectContent> + </Select> + </FormUi> + )} + /> + + <FormField + control={form.control} + name="rdiiArea" + render={({ field }) => ( + <FormUi label="○ RDII 기여면적(ha)" className="flex items-center"> + <Input + className="h-10 text-center text-xl w-[150px]" + placeholder="" + type="" + {...field} + /> + </FormUi> + )} + /> + + <FormField + control={form.control} + name="rtkSource" + render={({ field }) => ( + <FormUi label="○ RTK계수 출처" className="flex items-center"> + <Input + className="h-10 text-center text-xl w-[250px]" + placeholder="" + {...field} + /> + </FormUi> + )} + /> + </div> + + {/* 테이블 컨테이너 */} + <div className="mt-[1.2rem]"> + <div className="grid grid-cols-2"> + <div> + <div className="mb-[1.2rem] gap-[1.2rem] text-xl font-medium">○ 단위도 계수</div> + <UiTable + headName="" + className="w-[400px]" + tableData={unitFactorFields} + headlist={unitFactorHeadlist} + pageSize={10} + total={0} + onPageChange={handlePageChange} + cellClick={undefined} + > + {null} + </UiTable> + </div> + <div> + <div className="mb-[1.2rem] text-xl font-medium">○ 초기 차단 깊이</div> + <UiTable + headName="" + className="w-[400px]" + tableData={initialDepthFields} + headlist={initialDepthHeadlist} + pageSize={10} + total={0} + onPageChange={handlePageChange} + cellClick={undefined} + > + {null} + </UiTable> + </div> + </div> + </div> + + <div className="flex justify-end mt-[1.2rem]"> + <Button type="submit">저장</Button> + </div> + </div> + </form> + </Form> + </ListDiv> + <ListDiv> + <div className="card-header flex items-center justify-between"> + <h3 className="text-2xl font-medium">RTX계수 입력현황</h3> + <Button type="submit" className="!mx-[1.2rem]">삭제</Button> + </div> + <UiTable + headName='' + headlist={rtxNmHeadlist} + tableData={[]} + total={0} + pageSize={10} + children={undefined} + cellClick={() => { }} + onPageChange={() => { }} + /> + </ListDiv> + </ContentLayout> + ) +} diff --git a/apps/sn/app/ii/observe/page.tsx b/apps/sn/app/ii/observe/page.tsx new file mode 100644 index 000000000..55379f04e --- /dev/null +++ b/apps/sn/app/ii/observe/page.tsx @@ -0,0 +1,155 @@ +"use client" + +import { z } from "zod" +import { useForm, useFieldArray } from "react-hook-form" +import { zodResolver } from "@hookform/resolvers/zod" +import { FileUpload, Form, FormControl, FormField, FormItem, FormLabel, FormMessage, FormUi, SearchDiv, SearchFormLeft, SearchFormRight, SearchInput, SelectBox } from "@common/business_components/ui" +import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Input, Button, DatePicker, Label } from "@common/components/ui" +import { UiTable } from "@common/business_components/ui" +import React, { useState } from "react" +import ContentLayout from "@/components/ui/contentLayout" +import ListDiv from "@common/business_components/ui/list_div" + +// zod 스키마 정의 +const formSchema = z.object({ + region: z.string(), + inputdate: z.coerce.date(), + rtkSource: z.string(), +}) + +export default function RTKForm() { + const form = useForm<z.infer<typeof formSchema>>({ + resolver: zodResolver(formSchema), + defaultValues: { + region: "", + inputdate: new Date(), + rtkSource: "", + } + }) + const [selectedDate, setSelectedDate] = useState(new Date()) + const onSubmit = (data: z.infer<typeof formSchema>) => { + console.log("✅ 제출 데이터:", data) + } + // TODO: 임시 데이터 + const rtxNmHeadlist = [ + { id: 'no', title: '번호' }, + { id: 'hasu', title: '하수처리장' }, + { id: 'guyeok', title: '처리구역' }, + { id: 'fileNm', title: '파일명' }, + { id: 'time', title: '입력시간' } + ] + const rtxNmDataList = [ + { "no": '1', 'hasu': '하수처리장', 'guyeok': '처리구역', 'fileNm': '파일', 'time': '2025-04-18' } + ] + const handlePageChange = (page: number) => { + console.log('Page changed:', page) + } + + return ( + <ContentLayout title="관망도 등록"> + <SearchDiv> + <SearchFormRight> + <SelectBox label='시설검색' selectArray={[{ text: '한강 유역청', val: '1' }]} className='!mr-2' onSelectValue={() => { }} selectClass='w-[250px]' /> + <SelectBox label='' selectArray={[{ text: '경기도', val: '1' }]} className='!mr-2' onSelectValue={() => { }} selectClass='w-[200px]' /> + <SelectBox label='' selectArray={[{ text: '양평군', val: '1' }]} className='!mr-2' onSelectValue={() => { }} selectClass='w-[200px]' /> + <SelectBox label='' selectArray={[{ text: '양평하수처리장', val: '1' }]} className='' onSelectValue={() => { }} selectClass='w-[250px]' /> + </SearchFormRight> + </SearchDiv> + <ListDiv> + <div className="card-header"> + <h3 className="text-2xl font-medium">SWMM5 파일 업로드</h3> + </div> + <Form {...form}> + <form onSubmit={form.handleSubmit(onSubmit)}> + <div className="card !m-[1.2rem]"> + {/* 기본 정보 입력 폼 */} + <div className="space-y-[1.2rem]"> + <div className="grid grid-cols-[120px_1fr] items-center"> + <div className="text-xl font-medium">○ 처리구역</div> + <FormField + control={form.control} + name="region" + render={({ field }) => ( + <Select onValueChange={field.onChange} value={field.value}> + <SelectTrigger className="w-[150px]"> + <SelectValue placeholder="선택하세요" /> + </SelectTrigger> + <SelectContent> + <SelectItem value="양평">양평</SelectItem> + <SelectItem value="강남">강남</SelectItem> + <SelectItem value="마포">마포</SelectItem> + </SelectContent> + </Select> + )} + /> + </div> + + <div className="grid grid-cols-[120px_1fr] items-center"> + <div className="text-xl font-medium">○ RDII 기여면적(ha)</div> + <FormField + control={form.control} + name="inputdate" + render={({ field }) => ( + <DatePicker + selected={selectedDate} + onSelect={(date: Date | undefined) => { if (date) setSelectedDate(date) }} + mode={"single"} + /> + )} + /> + </div> + <div className="grid grid-cols-[120px_1fr] items-center"> + <div className="text-xl font-medium">○ 파일위치</div> + <FormField + control={form.control} + name="rtkSource" + render={({ field }) => ( + <div className="w-[150px]"> + <Input id="picture" type="file"/> + </div> + )} + /> + </div> + <div className="grid grid-cols-[120px_1fr] items-center"> + <div className="text-xl font-medium">○ 비고</div> + <FormField + control={form.control} + name="rtkSource" + render={({ field }) => ( + <Input + className="h-17 text-center text-xl w-[200px]" + placeholder="" + {...field} + /> + )} + /> + </div> + </div> + + + <div className="flex justify-end mt-1"> + <Button type="submit">자료업로드</Button> + </div> + </div> + </form> + </Form> + </ListDiv> + <ListDiv> + <div className="card-header flex items-center justify-between"> + <h3 className="text-2xl font-medium">SWMM 파일 업로드현황</h3> + <Button type="submit" className="!mx-[1.2rem]">삭제</Button> + </div> + <UiTable + headName='' + headlist={rtxNmHeadlist} + tableData={rtxNmDataList} + total={0} + pageSize={10} + children={undefined} + cellClick={() => { }} + onPageChange={() => { }} + /> + </ListDiv> + </ContentLayout> + ) +} diff --git a/apps/sn/app/oper/floodPre/page.tsx b/apps/sn/app/oper/floodPre/page.tsx index 79ef43f76..f24a0b274 100644 --- a/apps/sn/app/oper/floodPre/page.tsx +++ b/apps/sn/app/oper/floodPre/page.tsx @@ -2,8 +2,9 @@ import { ContentsDiv, MainDiv, SearchDiv, SearchFormLeft, SearchFormRight, SearchInput, Title, UiTable } from '@common/business_components/ui' import { Button, DatePicker, Input } from '@common/components/ui' import React, { useRef, useState } from 'react' -import FileUploadForm from '../../components/fileUploadForm' +import FileUploadForm from '../../components/ui/fileUploadForm' import ListDiv from '@common/business_components/ui/list_div' +import ContentLayout from '@/components/ui/contentLayout' const tableHeadlist = [ { id: 'no', title: 'NO' }, { id: 'fileNm', title: '파일명' }, @@ -22,9 +23,7 @@ const Page = () => { const [company, setCompany] = useState('') const [pjNm, setpjNm] = useState('') return ( - <MainDiv> - <Title title='도시침수 예방사업' /> - <ContentsDiv> + <ContentLayout title='도시침수 예방사업'> <SearchDiv> <SearchFormLeft> <div className='flex items-center space-x-4'> @@ -72,8 +71,7 @@ const Page = () => { <ListDiv className="mt-4"> <FileUploadForm title='도시침수 예방사업 사업추진현황 등록' /> </ListDiv> - </ContentsDiv> - </MainDiv> + </ContentLayout> ) } diff --git a/apps/sn/app/oper/oldPp/page.tsx b/apps/sn/app/oper/oldPp/page.tsx index cc0e00aeb..42b2a3e59 100644 --- a/apps/sn/app/oper/oldPp/page.tsx +++ b/apps/sn/app/oper/oldPp/page.tsx @@ -2,8 +2,9 @@ import { ContentsDiv, MainDiv, SearchDiv, SearchFormLeft, SearchFormRight, SelectBox, Title, UiTable } from '@common/business_components/ui' import { Button, DatePicker } from '@common/components/ui' import React, { useState } from 'react' -import FileUploadForm from '../../components/fileUploadForm' +import FileUploadForm from '../../components/ui/fileUploadForm' import ListDiv from '@common/business_components/ui/list_div' +import ContentLayout from '@/components/ui/contentLayout' // TODO: 임시 id const tableHeadlist = [ { id: 'no', title: 'NO' }, @@ -21,9 +22,7 @@ const tableData = [ const Page = () => { const [selectedDate, setSelectedDate] = useState<Date>(new Date()); return ( - <MainDiv> - <Title title='노후 하수관로 정비사업'/> - <ContentsDiv> + <ContentLayout title='노후 하수관로 정비사업'> <SearchDiv> <SearchFormLeft> <div className='flex items-center space-x-2'> @@ -51,8 +50,7 @@ const Page = () => { <ListDiv className="mt-4"> <FileUploadForm title='노후 하수관로 정비사업 주진현황 등록'/> </ListDiv> - </ContentsDiv> - </MainDiv> + </ContentLayout> ) }