Merge remote-tracking branch 'origin/iipbs/sn/dev' into iipbs-sn-map

This commit is contained in:
yschoi
2025-05-02 16:06:51 +09:00
23 changed files with 618 additions and 896 deletions
+32 -26
View File
@@ -1,10 +1,10 @@
"use client"
import { FileUpload, SelectBox } from '@common/business_components/ui';
import { Button } from '@common/components/ui';
import { Button, Input } from '@common/components/ui';
import React, { useState } from 'react'
const FileUploadForm = ({title}:{title:string}) => {
const FileUploadForm = ({ title }: { title: string }) => {
const [files, setFiles] = useState<File[] | null>(null);
const [selectedYear, setSelectedYear] = useState<string>('');
@@ -20,35 +20,41 @@ const FileUploadForm = ({title}:{title:string}) => {
<h3 className="text-2xl font-medium">{title}</h3>
</div>
<div className="card p-6">
<div className="flex items-center space-x-4">
<div className="w-[400px]">
<FileUpload
files={files}
setFiles={setFiles}
fileTypes=".xlsx,.xls"
/>
</div>
<div className="grid grid-col-2 items-center space-x-4">
<div className='flex'>
<SelectBox
className="w-50 mr-3 ml-4"
selectClass="rounded-lg bg-white"
label="년도"
selectArray={yearOptions}
onSelectValue={(value: string | number) => setSelectedYear(String(value))}
/><SelectBox
className="w-50"
selectClass="w-50 rounded-lg bg-white"
label="관리년도"
selectClass="rounded-lg bg-white"
label="분기"
selectArray={yearOptions}
onSelectValue={(value: string | number) => setSelectedYear(String(value))}
/>
<Button
className="px-4 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700"
size="sm"
onClick={() => {
if (!files?.[0] || !selectedYear) {
alert('파일과 등록년도를 선택해주세요.');
return;
}
// TODO: 파일 업로드 처리
console.log('Upload file:', files[0], 'Year:', selectedYear);
}}
>
등록
</Button>
</div>
<div className='flex mt-5 items-center'>
<div className="w-[200px] mr-4">
<Input id="file" type="file" />
</div>
<Button
className="px-4 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700"
size="sm"
onClick={() => {
if (!files?.[0] || !selectedYear) {
alert('파일과 등록년도를 선택해주세요.');
return;
}
// TODO: 파일 업로드 처리
console.log('Upload file:', files[0], 'Year:', selectedYear);
}}
>
등록
</Button>
</div>
</div>
</div>
</div>
+1 -1
View File
@@ -10,7 +10,7 @@ interface FormSectionProps {
const FormSection = ({ children, titleNm, form, name }: FormSectionProps) => {
return (
<div className="grid grid-cols-[120px_1fr] items-center">
<div className="grid grid-cols-[130px_1fr] items-center">
<div className="text-xl font-medium">{titleNm}</div>
<FormField
control={form.control}
+128
View File
@@ -0,0 +1,128 @@
import UiPageNations from "@common/business_components/ui/table/uiPageNations";
import { Table, TableBody, TableCell, TableRow } from "@common/components";
import { useEffect, useState } from "react";
type UiTableProps = {
headName: React.ReactNode | undefined;
tableData: { [key: string]: string | number | boolean | object }[];
headlist: UiHeadProps[];
pageSize: number;
total: number;
children: React.ReactNode | undefined;
cellClick: ((index: number | undefined, headId: string) => void) | undefined;
onPageChange: (page: number) => void;
className?: string;
resetPageNo?: boolean;
isEditable?: boolean;
};
type UiHeadProps = {
id: string;
title: string;
align?: string;
type?: string;
options?: string[];
};
export function VerticalTable({
tableData,
headlist,
pageSize,
total,
children,
headName,
cellClick,
onPageChange,
className = "",
resetPageNo = false,
isEditable = false,
}: UiTableProps) {
const [cur, setCur] = useState<number>(1);
const [formData, setFormData] = useState<{ [key: string]: string | number | boolean }>({});
useEffect(() => {
if (resetPageNo) {
setCur(1);
onPageChange(1);
}
}, [onPageChange, resetPageNo]);
useEffect(() => {
console.log('data',tableData)
if (tableData.length > 0 && tableData[0]) {
setFormData(tableData[0] as { [key: string]: string | number | boolean });
}
}, [tableData]);
const handleInputChange = (id: string, value: string | number | boolean) => {
setFormData((prev) => ({
...prev,
[id]: value,
}));
};
const handlePageChange = (page: number) => {
setCur(page);
onPageChange(page);
};
return (
<>
{headName ? (
<div className="card-header">
<h3 className="text-2xl mx-3 font-medium text-label">{headName}</h3>
</div>
) : null}
<div className={`card !m-[1.2rem] !p-0r ${className}`}>
<Table variant="secondary">
<TableBody className="text-center">
{headlist?.map((head) => (
<TableRow key={head.id}>
{/* 컬럼 제목 */}
<TableCell className="font-bold bg-blue-100 text-xs">
{head.title}
</TableCell>
{/* 데이터 값 또는 입력 필드 */}
<TableCell className="text-xs">
{isEditable ? (
head.type === "select" ? (
<select
value={formData[head.id] ?? "-"}
onChange={(e) => handleInputChange(head.id, e.target.value)}
className="w-full border border-gray-300 rounded-sm px-2 py-1 text-xl border-radius-0"
>
{head.options?.map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</select>
) : head.type === "input" ? (
<input
type="text"
value={formData[head.id] ?? ""}
onChange={(e) => handleInputChange(head.id, e.target.value)}
className="w-full text-xl border-radius-0 border border-gray-300 rounded-sm px-2 py-1"
/>
) : (
<span>{formData[head.id] ?? "-"}</span>
)
) : (
<span>{formData[head.id] ?? "-"}</span>
)}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
{total > 0 && (
<UiPageNations
total={total}
cur={cur}
pageSize={pageSize}
onPageChange={handlePageChange}
/>
)}
</div>
</>
);
}
+29 -39
View File
@@ -7,21 +7,26 @@ import React, { type ReactNode } from 'react'
type TitleName = {
mainTitle: string
firstCardTitle: string
secondCardTitle: string
secondCardTitle?: string
}
type TableInfoData = {
headList: { id: string; title: string; align?: string; }[]
tableData: { [key: string]: string | number | boolean | object }[];
cellClickFunc: Function
onPageChangeFunc: Function
type SelectBox = {
labelNm?:Label
searchChk?:boolean
}
type Label= {
first: string
second: string
third:string
fourth:string
}
type BaseLayout = {
children: ReactNode
children?: ReactNode[]
titleName: TitleName
form: any
onSubmitEvent: Function
graphBtn: boolean
tableInfoData: TableInfoData
graphBtn?: boolean
firstDivBtn?:boolean
searchBox?:SelectBox
}
// TODO: 나중에 이벤트 추가되면 파라미터 추가 필요 ?
/**
@@ -31,59 +36,44 @@ type BaseLayout = {
* @param form : zod 스키마
* @param onSubmitEvent : 폼 이벤트 처리
* @param graphBtn : 하단에 그래프 버튼 유무 처리
* @param tableInfoData : 하단 테이블 관련 props 항목
* @returns
*/
const BaseLayout = ({ children, titleName, form, onSubmitEvent, graphBtn, tableInfoData }: BaseLayout) => {
const BaseLayout = ({ children,titleName, form, onSubmitEvent, graphBtn=false, searchBox }: BaseLayout) => {
return (
<ContentLayout title={titleName.mainTitle}>
<SearchDiv>
<SearchFormLeft>
<SelectBox className="col-span-3" label='시설검색' selectArray={[{ text: '한강 유역청', val: '1' }]} onSelectValue={(val) => { }} selectClass={undefined} />
<SelectBox label='' selectArray={[{ text: '경기도', val: '1' }]} className="col-span-3" onSelectValue={() => { }} selectClass='' />
<SelectBox label='' selectArray={[{ text: '양평군', val: '1' }]} className="col-span-3" onSelectValue={() => { }} selectClass='' />
<SelectBox label='' selectArray={[{ text: '양평하수처리장', val: '1' }]} className="col-span-3" onSelectValue={() => { }} selectClass='' />
<SelectBox className="col-span-2" label={searchBox?.labelNm?.first ?? ''} selectArray={[{ text: '한강 유역청', val: '1' }]} onSelectValue={(val) => { }} selectClass={undefined} />
<SelectBox label={searchBox?.labelNm?.second ?? ''} selectArray={[{ text: '경기도', val: '1' }]} className="col-span-2" onSelectValue={() => { }} selectClass='' />
<SelectBox label={searchBox?.labelNm?.third ?? ''} selectArray={[{ text: '양평군', val: '1' }]} className="col-span-3" onSelectValue={() => { }} selectClass='' />
<SelectBox label={searchBox?.labelNm?.fourth ?? ''} selectArray={[{ text: '양평하수처리장', val: '1' }]} className="col-span-3" onSelectValue={() => { }} selectClass='' />
</SearchFormLeft>
<SearchFormRight>
<Button>조회</Button>
</SearchFormRight>
{searchBox?.searchChk ? <SearchFormRight><Button>조회</Button></SearchFormRight> : null}
</SearchDiv>
<ListDiv>
<div className="card-header">
<h3 className="text-2xl font-medium">{titleName.firstCardTitle}</h3>
<div>
{graphBtn ? <Button className="!mr-[1.2rem]">다운로드</Button> : null}
{/* 그래프 있을 시 */}
{graphBtn ? <Button className="!mr-[1.2rem]">삭제</Button> : null}
</div>
</div>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmitEvent)}>
<div className="card !m-[1.2rem]">
{/* 폼 정보 입력 칸 */}
{children}
<div className="flex justify-end mt-1">
<Button type="submit">자료업로드</Button>
</div>
{children?.[0]}
</div>
</form>
</Form>
</ListDiv>
<ListDiv>
{children?.[1] != null ? <ListDiv>
<div className="card-header flex items-center justify-between">
<h3 className="text-2xl font-medium">{titleName.secondCardTitle}</h3>
<div>
<Button className="!mr-[1.2rem]">삭제</Button>
{/* 그래프 있을 시 */}
{graphBtn ? <Button className="!mr-[1.2rem]">그래프</Button> : null}
</div>
</div>
<UiTable
headName=''
headlist={tableInfoData.headList}
tableData={tableInfoData.tableData}
total={0}
pageSize={10}
children={undefined}
cellClick={(e) => { tableInfoData.cellClickFunc(e) }}
onPageChange={(e) => { tableInfoData.onPageChangeFunc(e) }}
/>
</ListDiv>
<div className="card !m-[1.2rem]">{children?.[1]}</div>
</ListDiv> : null}
</ContentLayout>
)
}
-101
View File
@@ -1,101 +0,0 @@
"use client"
import { z } from "zod"
import { useForm, useFieldArray } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import { FormField, SelectBox } from "@common/business_components/ui"
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Input, DatePicker } from "@common/components/ui"
import React, { useState } from "react"
import BaseLayout from "@/ii/BaseLayout"
// zod 스키마 정의
const formSchema = z.object({
region: z.string(),
inputdate: z.coerce.date(),
rtkSource: z.string(),
})
const region:{text:string,val:number}[] = [{text:'양평', val:1},{text:'강남',val:2},{text:'test',val:3}]
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())
// 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 (
<BaseLayout titleName={{mainTitle: "관망도 등록",firstCardTitle: "SWMM5 파일 업로드",secondCardTitle: "SWMM 파일 업로드현황"}} form={form} onSubmitEvent={()=>{}} graphBtn={false} tableInfoData={{headList: rtxNmHeadlist, tableData: rtxNmDataList, cellClickFunc: ()=>{}, onPageChangeFunc: ()=>{}}} >
{/* 기본 정보 입력 폼 */}
<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 }) => (
<SelectBox label='' selectArray={region} onSelectValue={()=>{}} selectClass="" className="w-[150px]"/>
)}
/>
</div>
<div className="grid grid-cols-[120px_1fr] items-center">
<div className="text-xl font-medium">○ 입력일</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>
</BaseLayout>
)
}
-96
View File
@@ -1,96 +0,0 @@
'use client'
import React, { useState } from 'react'
import { z } from 'zod'
import { zodResolver } from '@hookform/resolvers/zod'
import { useForm } from 'react-hook-form'
import { FormField, SelectBox } from '@common/business_components/ui'
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, DatePicker, Input } from '@common/components/ui'
import BaseLayout from '@/ii/BaseLayout'
// zod 스키마 정의
const formSchema = z.object({
region: z.string(),
inputdate: z.coerce.date(),
rtkSource: z.string(),
})
const region:{text:string,val:number}[] = [{text:'양평', val:1},{text:'강남',val:2},{text:'test',val:3}]
const Page = () => {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
region: "",
inputdate: new Date(),
rtkSource: "",
}
})
// 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 [selectedDate, setSelectedDate] = useState(new Date())
return (
<BaseLayout titleName={{ mainTitle: '티센 폴리곤 등록', firstCardTitle: '맨홀별 티센 폴리곤(shape파일) 업로드', secondCardTitle: '수용가-맨홀 매칭 파일 업로드 현황' }} form={form} onSubmitEvent={() => { }} graphBtn={false} tableInfoData={{ headList:rtxNmHeadlist, tableData:rtxNmDataList, cellClickFunc: () => { }, onPageChangeFunc: () => { } }}>
<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 }) => (
<SelectBox label='' selectArray={region} onSelectValue={() => { } } selectClass={undefined} className='w-[150px]'/>
)}
/>
</div>
<div className="grid grid-cols-[120px_1fr] items-center">
<div className="text-xl font-medium">○ 입력일</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>
</BaseLayout>
)
}
export default Page
-99
View File
@@ -1,99 +0,0 @@
"use client"
import { z } from "zod"
import { FormField} from '@common/business_components/ui'
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, DatePicker, Input } from '@common/components/ui'
import React, { useState } from 'react'
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import BaseLayout from "@/ii/BaseLayout"
// zod 스키마 정의
const formSchema = z.object({
region: z.string(),
inputdate: z.coerce.date(),
rtkSource: z.string(),
})
function RegistForm() {
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' }
]
return (
<BaseLayout titleName={{ mainTitle: "수용가-맨홀 등록", firstCardTitle: "수용가-맨홀 매칭 Shape파일 업로드", secondCardTitle: "수용가-맨홀 매칭 Shape파일 업로드 현황" }} form={form} onSubmitEvent={onSubmit} graphBtn={false} tableInfoData={{
headList: rtxNmHeadlist, tableData: rtxNmDataList, cellClickFunc: () => { }, onPageChangeFunc: () => { }
}}>
{/* 기본 정보 입력 폼 */}
<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">○ 입력일</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>
</BaseLayout>
)
}
export default RegistForm
-114
View File
@@ -1,114 +0,0 @@
'use client'
import React, { useState } from 'react'
import BaseLayout from '../../BaseLayout'
import { FormField, SelectBox } from '@common/business_components/ui'
import { DatePicker, Input } from '@common/components/ui'
import { z } from 'zod'
import { zodResolver } from '@hookform/resolvers/zod'
import { useForm } from 'react-hook-form'
import FormSection from '@/components/ui/formSection'
const formSchema = z.object({
region: z.string(),
suyeonga: z.number(),
inputdate: z.coerce.date(),
rtkSource: z.string(),
})
const region: { text: string, val: number }[] = [{ text: '양평', val: 1 }, { text: '강남', val: 2 }, { text: 'test', val: 3 }]
const IrSetting = () => {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
region: "",
suyeonga: 0,
inputdate: new Date(),
rtkSource: "",
}
})
console.log('test')
// TODO: 임시 데이터
const rtxNmHeadlist = [
{ id: 'nm', title: '분석번호' },
{ id: 'hasu', title: '하수처리장' },
{ id: 'region', title: '처리구역' },
{ id: 'sangsu', title: '상수사용량' },
{ id: 'wjsghks', title: '오수 전환율' },
{ id: 'tnsdhtn', title: '순오수량' },
{ id: 'rkddn', title: '강우 유출량' },
{ id: 'rdii', title: 'RDII' }
]
const rtxNmDataList = [
{ "nm": '1', 'hasu': '', 'region': '처리', 'sangsu': '파일', 'wjsghks': '', 'tnsdhtn': '', 'rkddn': '', 'rdii': '' }
]
const [selectedDate, setSelectedDate] = useState(new Date())
return (
<BaseLayout titleName={{ mainTitle: '침입수 산정', firstCardTitle: '침입수 산정 기초자료 설정', secondCardTitle: '침입수 산정결과 현황' }} form={form} onSubmitEvent={() => { }} graphBtn={true} tableInfoData={{ headList: rtxNmHeadlist, tableData: rtxNmDataList, cellClickFunc: () => { }, onPageChangeFunc: () => { } }}>
<div className="grid grid-cols-2 gap-4">
<FormSection name='region' form={form} titleNm='○ 처리구역'><SelectBox label='' selectArray={region} onSelectValue={() => { }} selectClass={undefined} className='w-[150px]' /></FormSection>
<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-[3.2rem] text-center text-xl w-[150px]"
placeholder=""
{...field}
/>
)}
/>
</div>
<div className="grid grid-cols-[120px_1fr] items-center">
<div className="text-xl font-medium">○ 수용가 수</div>
<FormField
control={form.control}
name="suyeonga"
render={({ field }) => (
<SelectBox label='' selectArray={[]} onSelectValue={() => { }} selectClass={undefined} className='w-[150px]' />
)}
/>
</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="inputdate"
render={({ field }) => (
<DatePicker
selected={selectedDate}
onSelect={(date: Date | undefined) => { if (date) setSelectedDate(date) }}
mode={"single"} className='w-[150px]'
/>
)}
/>
</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>
</BaseLayout>
)
}
export default IrSetting
@@ -1,98 +0,0 @@
'use client'
import React, { useState } from 'react'
import BaseLayout from '../../BaseLayout'
import { FormField, SelectBox } from '@common/business_components/ui'
import { DatePicker, Input } from '@common/components/ui'
import { z } from 'zod'
import { zodResolver } from '@hookform/resolvers/zod'
import { useForm } from 'react-hook-form'
const formSchema = z.object({
region: z.string(),
inputdate: z.coerce.date(),
rtkSource: z.string(),
})
const region: { text: string, val: number }[] = [{ text: '양평', val: 1 }, { text: '강남', val: 2 }, { text: 'test', val: 3 }]
const MeasureDataUpload = () => {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
region: "",
inputdate: new Date(),
rtkSource: "",
}
})
// TODO: 임시 데이터
const rtxNmHeadlist = [
{ id: 'fileNm', title: '파일명' },
{ id: 'status', title: '상태' },
{ id: 'code', title: '지정코드' },
{ id: 'cjfl', title: '처리' },
{ id: 'add', title: '추가' },
{ id: 'update', title: '변경' },
{ id: 'error', title: '오류' },
{ id: 'skip', title: 'Skip' }
]
const rtxNmDataList = [
{ "status": '상태', 'code': '123824', 'cjfl': '처리', 'fileNm': '파일', 'add': '', 'update': '', 'error': '', 'skip': '' }
]
const [selectedDate, setSelectedDate] = useState(new Date())
return (
<BaseLayout titleName={{ mainTitle: '측정자료 등록', firstCardTitle: '하수측정자료 업로드', secondCardTitle: '하수측정자료 파일 업로드 현황' }} form={form} onSubmitEvent={() => { }} graphBtn={true} tableInfoData={{ headList: rtxNmHeadlist, tableData: rtxNmDataList, cellClickFunc: () => { }, onPageChangeFunc: () => { } }}>
<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 }) => (
<SelectBox label='' selectArray={region} onSelectValue={() => { }} selectClass={undefined} className='w-[150px]' />
)}
/>
</div>
<div className="grid grid-cols-[120px_1fr] items-center">
<div className="text-xl font-medium">○ 입력일</div>
<FormField
control={form.control}
name="inputdate"
render={({ field }) => (
<DatePicker
selected={selectedDate}
onSelect={(date: Date | undefined) => { if (date) setSelectedDate(date) }}
mode={"single"} className='w-[150px]'
/>
)}
/>
</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-[3.2rem] text-center text-xl w-[150px]"
placeholder=""
{...field}
/>
)}
/>
</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>
</BaseLayout>
)
}
export default MeasureDataUpload
+63
View File
@@ -0,0 +1,63 @@
'use client'
import React, { useState } from 'react'
import { FormField, SelectBox } from '@common/business_components/ui'
import { Button, DatePicker, Input } from '@common/components/ui'
import { z } from 'zod'
import { zodResolver } from '@hookform/resolvers/zod'
import { useForm } from 'react-hook-form'
import FormSection from '@/components/ui/formSection'
import BaseLayout from '../BaseLayout'
const formSchema = z.object({
managenm: z.string(),
region: z.string(),
suyeonga: z.number(),
inputdate: z.coerce.date(),
rtkSource: z.string(),
suyeongaPlace: z.string()
})
const region: { text: string, val: number }[] = [{ text: '양평', val: 1 }, { text: '강남', val: 2 }, { text: 'test', val: 3 }]
const IrSetting = () => {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
managenm: "",
region: "",
suyeonga: 0,
inputdate: new Date(),
rtkSource: "",
suyeongaPlace: ""
}
})
const [selectedDate, setSelectedDate] = useState(new Date())
return (
<BaseLayout titleName={{ mainTitle: '침입수 산정', firstCardTitle: '실측자료 등록', secondCardTitle: '침입수 분석자료 입력' }} form={form} onSubmitEvent={() => { }} graphBtn={false}>
<div className="grid grid-cols-2 gap-4">
<FormSection name='managenm' form={form} titleNm='○ 관로 관리번호'>
<DatePicker selected={selectedDate} onSelect={(date: Date | undefined) => { if (date) setSelectedDate(date);}} mode={"single"} />
</FormSection>
<FormSection name='region' form={form} titleNm='○ 파일위치'>
<div className="w-[150px]">
<Input id="fileNm" type="file" />
</div>
</FormSection>
</div>
<div className="grid gap-4">
<FormSection name='suyeongaPlace' form={form} titleNm='○ 오수관망도'><div className="w-[150px]">
<Input id="fileNm" type="file" />
</div></FormSection>
<FormSection name='suyeonga' form={form} titleNm='○ 수용가-맨홀 매칭결과'><div className="w-[150px]">
<Input id="fileNm" type="file" />
</div></FormSection>
<FormSection name='inputdate' form={form} titleNm='○ 실수사용량 적용기간'>
<DatePicker selected={selectedDate} onSelect={(date: Date | undefined) => { if (date) setSelectedDate(date) }} mode={"single"} />
</FormSection>
<FormSection name='rtkSource' form={form} titleNm='○ 오수전환율'><Input className="h-[3.2rem] text-center text-xl w-[150px]" /></FormSection>
<div className="flex justify-end mt-1">
<Button type="submit">침입수분석 실행</Button>
</div>
</div>
</BaseLayout>
)
}
export default IrSetting
@@ -1,15 +1,14 @@
"use client"
import { z } from "zod"
import { date, z } from "zod"
import { useForm, useFieldArray } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, FormUi, SearchDiv, SearchFormLeft, SearchFormRight, SelectBox } from "@common/business_components/ui"
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Input, Button } from "@common/components/ui"
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Input, Button, DatePicker } 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"
import React, { useState } from "react"
import BaseLayout from "@/ii/BaseLayout"
import FormSection from "@/components/ui/formSection"
// TODO: 컴포넌트 호출 ~ 필요 코드 수정해야댐
// zod 스키마 정의
const formSchema = z.object({
@@ -27,7 +26,11 @@ const formSchema = z.object({
Dmax: z.string(),
Drec: z.string(),
Do: z.string(),
}))
})),
suyeonga: z.string(),
rate: z.string(),
date: z.coerce.date(),
rain: z.string(),
})
export default function RTKForm() {
@@ -79,64 +82,23 @@ export default function RTKForm() {
{ 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)
}
const [selectedDate, setSelectedDate] = useState(new Date())
return (
<BaseLayout titleName={{ mainTitle: '모의정보 설정', firstCardTitle: '모의정보 설정', secondCardTitle: 'RTX계수 입력현황' }} form={form} onSubmitEvent={() => { }} graphBtn={false} tableInfoData={{ headList: rtxNmHeadlist, tableData: [{}], cellClickFunc: () => { }, onPageChangeFunc: () => { } }}>
<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 }) => (
<SelectBox label="" selectArray={[{ text: '양평', val: 1 }]} onSelectValue={() => { }} selectClass="" className="w-[150px]" />
)}
/>
</div>
<div className="grid grid-cols-[120px_1fr] items-center">
<div className="text-xl font-medium">○ RDII 기여면적(ha)</div>
<FormField
control={form.control}
name="rdiiArea"
render={({ field }) => (
<Input
className="h-10 text-center text-xl w-[150px]"
placeholder=""
type=""
{...field}
/>
)}
/>
</div>
<div className="grid grid-cols-[120px_1fr] items-center">
<div className="text-xl font-medium">○ RTK계수 출처</div>
<FormField
control={form.control}
name="rtkSource"
render={({ field }) => (
<Input
className="h-10 text-center text-xl w-[250px]"
placeholder=""
{...field}
/>
)}
/>
</div>
</div>
{/* 테이블 컨테이너 */}
<div className="mt-[1.2rem]">
<BaseLayout titleName={{ mainTitle: 'RDII 분석', firstCardTitle: 'RDII 분석자료 입력' }} form={form} onSubmitEvent={() => { }} graphBtn={false}>
{[<div className="space-y-[1.2rem]" key="form-section">
<div className="grid grid-cols-2 gap-4">
<FormSection name="rtkSource" form={form} titleNm="○ RTK계수 출처"><Input
className="h-10 text-center text-xl w-[150px]"
placeholder=""
/></FormSection>
<FormSection name="rdiiArea" form={form} titleNm="○ RDII 기여면적(ha)"><Input
className="h-10 text-center text-xl w-[150px]"
placeholder=""
/></FormSection></div>
<div className="grid grid-cols-2">
<div>
<div className="mb-[1.2rem] text-xl font-medium">○ 단위도 계수</div>
@@ -169,7 +131,26 @@ export default function RTKForm() {
</UiTable>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<FormSection name="suyeonga" form={form} titleNm="○ 오수관망도"><div className="w-[150px]">
<Input id="fileNm" type="file" />
</div></FormSection>
<FormSection name="regopm" form={form} titleNm="○ 수용가-맨홀 매칭결과"><div className="w-[150px]">
<Input id="fileNm2" type="file" />
</div></FormSection>
<FormSection name='date' form={form} titleNm='○ 실수사용량 적용기간'>
<DatePicker selected={selectedDate} onSelect={(date: Date | undefined) => { if (date) setSelectedDate(date) }} mode={"single"} />
</FormSection>
<FormSection name='rate' form={form} titleNm='○ 오수전환율'><Input className="h-[3.2rem] text-center text-xl w-[150px]" /></FormSection>
<FormSection name="rain" form={form} titleNm="○ 강우자료"><div className="w-[150px]">
<Input id="fileNm3" type="file" />
</div></FormSection>
</div>
<div className="flex justify-end mt-1">
<Button type="submit">RDII분석 실행</Button>
</div>
</div>
]}
</BaseLayout >
)
}
-54
View File
@@ -1,54 +0,0 @@
'use client'
import React, { useState } from 'react'
import BaseLayout from '../../BaseLayout'
import { FormField, SelectBox } from '@common/business_components/ui'
import { DatePicker, Input } from '@common/components/ui'
import { z } from 'zod'
import { zodResolver } from '@hookform/resolvers/zod'
import { useForm } from 'react-hook-form'
const formSchema = z.object({
region: z.string(),
})
const region: { text: string, val: number }[] = [{ text: '양평', val: 1 }, { text: '강남', val: 2 }, { text: 'test', val: 3 }]
const RainDataUpload = () => {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
region: "",
}
})
// TODO: 임시 데이터
const rtxNmHeadlist = [
{ id: 'fileNm', title: '파일명' },
{ id: 'status', title: '상태' },
{ id: 'code', title: '지정코드' },
{ id: 'cjfl', title: '처리' },
{ id: 'add', title: '추가' },
{ id: 'update', title: '변경' },
{ id: 'error', title: '오류' },
{ id: 'skip', title: 'Skip' }
]
const rtxNmDataList = [
{ "status": '상태', 'code': '123824', 'cjfl': '처리', 'fileNm': '파일', 'add': '', 'update': '', 'error': '', 'skip': '' }
]
return (
<BaseLayout titleName={{ mainTitle: '강우자료 등록', firstCardTitle: '강우자료 업로드', secondCardTitle: '강우자료 파일 업로드 현황' }} form={form} onSubmitEvent={() => { }} graphBtn={true} tableInfoData={{ headList: rtxNmHeadlist, tableData: rtxNmDataList, cellClickFunc: () => { }, onPageChangeFunc: () => { } }}>
<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 }) => (
<div className="w-[150px]">
<Input id="picture" type="file" />
</div>
)}
/>
</div>
</div>
</BaseLayout>
)
}
export default RainDataUpload
-149
View File
@@ -1,149 +0,0 @@
'use client'
import BaseLayout from '@/ii/BaseLayout'
import { FormField, SelectBox } from '@common/business_components/ui'
import { DatePicker, Input } from '@common/components/ui'
import { zodResolver } from '@hookform/resolvers/zod'
import React, { useState } from 'react'
import { useForm } from 'react-hook-form'
import { z } from 'zod'
const formSchema = z.object({
region: z.string(),
suyeonga:z.number(),
meter:z.string(),
inputdate: z.coerce.date(),
inpSource:z.string(),
rtkSource: z.string(),
})
const region: { text: string, val: number }[] = [{ text: '양평', val: 1 }, { text: '강남', val: 2 }, { text: 'test', val: 3 }]
const RdiiSetting = () => {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
region: "",
meter:"",
suyeonga:0,
inputdate: new Date(),
inpSource:"",
rtkSource: "",
}
})
// TODO: 임시 데이터
const rtxNmHeadlist = [
{ id: 'nm', title: '분석번호' },
{ id: 'hasu', title: '하수처리장' },
{ id: 'region', title: '처리구역' },
{ id: 'sangsu', title: '상수사용량' },
{ id: 'wjsghks', title: '오수 전환율' },
{ id: 'tnsdhtn', title: '순오수량' },
{ id: 'rkddn', title: '강우 유출량' },
{ id: 'rdii', title: 'RDII' }
]
const rtxNmDataList = [
{ "nm": '1', 'hasu': '', 'region': '처리', 'sangsu': '파일', 'wjsghks': '', 'tnsdhtn': '', 'rkddn': '', 'rdii': '' }
]
const [selectedDate, setSelectedDate] = useState(new Date())
return (
<BaseLayout titleName={{ mainTitle: 'RDII 산정', firstCardTitle: 'RDII산정 기초자료 설정', secondCardTitle: 'RDII 산정결과 현황' }} form={form} onSubmitEvent={() => { }} graphBtn={true} tableInfoData={{ headList: rtxNmHeadlist, tableData: rtxNmDataList, cellClickFunc: () => { }, onPageChangeFunc: () => { } }}>
<div className="grid grid-cols-3 gap-4">
<div className="grid grid-cols-[120px_1fr] items-center">
<div className="text-xl font-medium">○ 처리구역</div>
<FormField
control={form.control}
name="region"
render={({ field }) => (
<SelectBox label='' selectArray={region} onSelectValue={() => { }} selectClass={undefined} className='w-[150px]' />
)}
/>
</div>
<div className="grid grid-cols-[120px_1fr] items-center">
<div className="text-xl font-medium">○ 상수사용량 정보</div>
<FormField
control={form.control}
name="inputdate"
render={({ field }) => (
<DatePicker
selected={selectedDate}
onSelect={(date: Date | undefined) => { if (date) setSelectedDate(date) }}
mode={"single"} className='w-[150px]'
/>
)}
/>
</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">○ RDII 기여면적(ha)</div>
<FormField
control={form.control}
name="meter"
render={({ field }) => (
<Input
className="h-[3.2rem] text-center text-xl w-[150px]"
placeholder=""
{...field}
/>
)}
/>
</div>
<div className="grid grid-cols-[120px_1fr] items-center">
<div className="text-xl font-medium">○ 오수 전환율</div>
<FormField
control={form.control}
name="inpSource"
render={({ field }) => (
<Input
className="h-[3.2rem] text-center text-xl w-[150px]"
placeholder=""
{...field}
/>
)}
/>
</div>
<div className="grid grid-cols-[120px_1fr] items-center">
<div className="text-xl font-medium">○ 강우자료</div>
<FormField
control={form.control}
name="inpSource"
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="suyeonga"
render={({ field }) => (
<SelectBox label='' selectArray={[]} onSelectValue={() => { }} selectClass={undefined} className='w-[150px] h-[3.2rem]' />
)}
/>
</div>
<div className="grid grid-cols-[120px_1fr] items-center">
<div className="text-xl font-medium">○ 수용가-맨홀 매칭</div>
<FormField
control={form.control}
name="inpSource"
render={({ field }) => (
<SelectBox label='' selectArray={[{'text':'매칭(양평).shp','val':'1'}]} onSelectValue={() => { }} selectClass={undefined} className='h-[3.2rem] w-[150px]' />
)}
/>
</div>
</div>
</BaseLayout>
)
}
export default RdiiSetting
+64
View File
@@ -0,0 +1,64 @@
'use client'
import React, { useState } from 'react'
import { FormField, SelectBox, UiTable } from '@common/business_components/ui'
import { Button, DatePicker, Input } from '@common/components/ui'
import { z } from 'zod'
import { zodResolver } from '@hookform/resolvers/zod'
import { useForm } from 'react-hook-form'
import FormSection from '@/components/ui/formSection'
import BaseLayout from '../BaseLayout'
import { title } from 'process'
const formSchema = z.object({
managenm: z.string(),
region: z.string(),
suyeonga: z.number(),
inputdate: z.coerce.date(),
rtkSource: z.string(),
suyeongaPlace: z.string()
})
// TODO: 분석구분에 따라서 테이블 컬럼 변경필요
const tableColumn = [
{ id: 'no', title: '번호' },
{ id: 'hasu', title: '하수처리장' },
{ id: 'guyeok', title: '처리구역' },
{ id: 'sangsu', title: '상수 사용량' },
{ id: 'rate', title: '오수 전환율' },
{ id: 'water', title: '순오수량' },
{ id: 'measureWater', title: '측정하수량' },
{ id: 'ii', title: '침입수량' },
{ id: 'date', title: '분석일자' },
{ id: 'usr', title: '분석자' }
]
const tableInfoData = [{ 'no': '1', 'hasu': '양평하수처리장', 'guyeok': '양평', 'sangsu': '1000', 'rate': '0.5', 'water': '500', 'measureWater': '1000', 'ii': '500', 'date': '2023-10-01', 'usr': '홍길동' }]
const Result = () => {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
managenm: "",
region: "",
suyeonga: 0,
inputdate: new Date(),
rtkSource: "",
suyeongaPlace: ""
}
})
return (
<BaseLayout searchBox={{labelNm: {first: "분석기간",second: "침입수",third: "처리장",fourth: "처리구역",},searchChk: true,}} titleName={{ mainTitle: '분석결과', firstCardTitle: '분석이력' }} form={form} onSubmitEvent={() => { }} graphBtn={true}>
{[<div key='table1'>
<div className="mb-[1.2rem] text-xl font-medium">○ 침입수 산정결과 현황</div>
<UiTable
headName=''
headlist={tableColumn}
tableData={tableInfoData}
total={0}
pageSize={10}
children={undefined}
cellClick={(e) => { }}
onPageChange={(e) => { }}
/>
</div>]}
</BaseLayout>
)
}
export default Result
+130
View File
@@ -0,0 +1,130 @@
'use client'
import { VerticalTable } from "@/components/verticalTable";
import { Button, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@common/components/ui";
import { useState } from "react";
import { CommonTableColumn } from "./table";
const inputColumn = [
{ id: "title", title: "설치주제", type: "select", options: ["BTL", "재정사업"] },
{ id: "guyeok", title: "처리구역", type: "select", options: ["구역1", "구역2"] },
{ id: "basu", title: "배수구역", type: "input" },
{ id: "bungu", title: "배수분구", type: "input" },
{ id: "wltjs", title: "지선/간선", type: "select", options: ["지선", "간선"] },
{ id: "flow", title: "흐름방식", type: "select", options: ["자연유하", "압송"] },
{ id: "place", title: "매설위치", type: "select", options: ["도로", "하상"] },
];
const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, featureData:any }) => {
// TODO: 런타임 에러 해결 필요
const [repairData, setRepairData] = useState([
{ year: "2025", type: "개대체" },
{ year: "2025", type: "보수" },
]);
const [cleaningData, setCleaningData] = useState([
{ year: "2025", type: "청소" },
{ year: "2025", type: "준설" },
]);
const [inspectionData, setInspectionData] = useState([
{ year: "2025", type: "관로기술진단" },
{ year: "2025", type: "관로기술진단" },
]);
const handleInputChange = (section: string, index: number, field: string, value: string) => {
const updateData = (data: { year: string; type: string }[], setData: React.Dispatch<React.SetStateAction<{ year: string; type: string }[]>>) => {
const updated = [...data];
if (updated[index]) {
updated[index][field as keyof typeof updated[number]] = value;
}
setData(updated);
};
if (section === "repair") {
updateData(repairData, setRepairData);
} else if (section === "cleaning") {
updateData(cleaningData, setCleaningData);
} else if (section === "inspection") {
updateData(inspectionData, setInspectionData);
}
};
function transformFeatureDataToArray(featureData: any, keys: string[]) {
// 필요한 키만 추출하여 새로운 객체 생성
const transformedData = keys.reduce((acc, key) => {
acc[key] = featureData[key] !== undefined ? featureData[key] : "N/A"; // 값이 없으면 "N/A"로 처리
return acc;
}, {} as Record<string, any>);
// 배열로 감싸서 반환
return [transformedData];
}
const keys = CommonTableColumn.map((column) => column.id);
const transformedFeatureData = transformFeatureDataToArray(featureData, keys);
const renderSection = (title: string, data: { year: string; type: string }[], sectionKey: string) => (
<div>
{/* 섹션 제목 */}
<div className="card-header">
<h3 className="text-2xl mx-3 font-medium text-label">{title}</h3>
</div>
{/* 테이블 */}
<div className="card !m-[1.2rem] !p-0r">
<Table variant="secondary" className="w-full">
<TableHeader>
<TableRow>
<TableHead className="border border-gray-300 px-2 py-2 text-sm">년도</TableHead>
<TableHead className="border border-gray-300 px-2 py-2 text-sm">구분</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{data.map((row, index) => (
<TableRow key={index}>
<TableCell className="border border-gray-300 px-2 py-2 text-sm">
<input
type="text"
value={row.year}
onChange={(e) => handleInputChange(sectionKey, index, "year", e.target.value)}
className="w-full text-xl border-radius-0 px-3 py-2 text-base text-center leading-normal"
/>
</TableCell>
<TableCell className="border border-gray-300 px-2 py-2 text-sm text-center leading-normal">{row.type}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</div>
);
return (
<div id="popup" className="absolute top-0 right-0 w-[350px] h-[calc(100vh-10rem)] bg-white border-r border-gray-300 flex flex-col overflow-hidden transition-all duration-300 z-[1000]">
<div className="card-header bg-primary flex items-center justify-between p-4">
<div className="flex mx-3 flex-col">
<h3 className="text-2xl font-medium text-white text-label">하수관로 정보</h3>
<div className="font-medium text-white text-label">(00구 00리 하수관로)</div>
</div>
<button
onClick={onClose}
className="text-white hover:text-gray-700 focus:outline-none"
aria-label="닫기"
>
✕
</button>
</div>
<div className="overflow-y-auto flex-1">
<VerticalTable headName='LX 연계정보' tableData={transformedFeatureData} headlist={CommonTableColumn} pageSize={20} total={0} children={undefined} cellClick={undefined} onPageChange={function (page: number): void {
throw new Error("Function not implemented.");
}}></VerticalTable>
<VerticalTable headName='자체 입력정보' tableData={[]} headlist={inputColumn} pageSize={20} total={0} children={undefined} cellClick={undefined} isEditable={true} onPageChange={function (page: number): void {
throw new Error("Function not implemented.");
}}></VerticalTable>
{/* here */}
{renderSection("보수 및 갱신", repairData, "repair")}
{renderSection("청소 및 준설", cleaningData, "cleaning")}
{renderSection("점검 및 진단", inspectionData, "inspection")}
</div>
<div className="w-full mx-5 flex items-center justify-end space-x-2">
<Button className="px-4 mr-5 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700">
저장
</Button>
</div>
</div>
)
}
export default FeatureClickEventPopup;
+1
View File
@@ -10,6 +10,7 @@ import { mapService } from "@service";
const Map = () => {
const [treeData, setTreeData] = useState([]); // 초기값을 객체 또는 null로 설정
const [selectedFeature,setSelectedFeature] = useState(null); // 선택된 피처 상태
const fetchData = async () => {
try {
+40
View File
@@ -0,0 +1,40 @@
export const CommonTableColumn = [
{ id: 'swtrmt_fclt_cd', title: '하수처리시설코드' },
{ id: 'swtrmt_fclt_nm', title: '하수처리시설명' },
{ id: 'fclt_cpct', title: '시설용량' },
{ id: 'rgn_expln', title: '지역설명' },
{ id: 'cmcn_ymd', title: '준공일자' },
{ id: 'oprtng_strt_ymd', title: '가동개시일자' },
{ id: 'clsg_ymd', title: '폐쇄일자' },
{ id: 'prcs_msrc_cd', title: '처리공법코드' },
{ id: 'lae_cd', title: '지자체코드' },
{ id: 'lae_nm', title: '지자체명' },
{ id: 'ctpv_nm', title: '시도명' },
{ id: 'sgg_nm', title: '시군구명' },
{ id: 'sarea_cd', title: '권역코드' },
{ id: 'sarea_nm', title: '권역명' },
{ id: 'lrge_sarea_nm', title: '대권역명' },
{ id: 'rvr_nm', title: '하천명' },
{ id: 'addr', title: '주소' },
{ id: 'daddr', title: '상세주소' },
{ id: 'rdnm_addr', title: '도로명주소' },
{ id: 'dtl_rdnm_addr', title: '상세도로명주소' },
{ id: 'dschg_wtst_nm', title: '방류수계명' },
{ id: 'plln_area', title: '부지면적' },
{ id: 'mng_rprtv_bzenty_nm', title: '관리대행업제명' },
{ id: 'swtrmt_ppltn_cnt', title: '하수처리인구수' },
{ id: 'prcs_zone_area_sum', title: '처리구역면적합계' },
{ id: 'geom', title: 'geometry' },
{ id: 'xcrd', title: 'X좌표' },
{ id: 'ycrd', title: 'Y좌표' },
{ id: 'oprtng_stts_cd', title: '가동상태코드' },
{ id: 'rprs_msrc_cn', title: '대표공법내용' },
{ id: 'stty_crtr_bod', title: '법정기준생물화학적산소요구량' },
{ id: 'stty_crtr_toc', title: '법정기준TOC' },
{ id: 'stty_crtr_ss', title: '법정기준SS' },
{ id: 'stty_crtr_tn', title: '법정기준총질소' },
{ id: 'stty_crtr_tph', title: '법정기준총인' },
{ id: 'stty_crtr_clbcl_cnt', title: '법정기준대장균수' },
{ id: 'bsn_nm', title: '유역명' },
{ id: 'obsrvn_spt_cd', title: '관측지점코드' },
];
+5 -16
View File
@@ -5,19 +5,8 @@ import React, { useRef, useState } from 'react'
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: '파일명' },
{ id: 'manageYear', title: '기준년도' },
{ id: 'registDt', title: '등록 일자' },
{ id: 'registUsr', title: '등록자' }
import { tableData, tableHeadlist } from '../oldPp/page'
]
const tableData = [
{ 'no': '1', 'fileNm': '파일명', 'manageYear': '2023', 'registDt': '2025-04-16', 'registUsr': 'me' },
{ 'no': '2', 'fileNm': '파일명', 'manageYear': '2024', 'registDt': '2025-04-16', 'registUsr': 'me2' },
{ 'no': '3', 'fileNm': '파일명', 'manageYear': '2025', 'registDt': '2025-04-16', 'registUsr': 'me3' }
]
const Page = () => {
const [selectedDate, setSelectedDate] = useState(new Date())
const [company, setCompany] = useState('')
@@ -28,7 +17,7 @@ const Page = () => {
<SearchFormLeft>
<div className='flex items-center gap-4'>
<div className='flex items-center gap-2'>
<Label className="w-20 text-xl text-gray-600">수행기간</Label>
<Label className="w-20 text-xl text-gray-600">등록기간</Label>
<DatePicker mode={'single'}
selected={selectedDate}
onSelect={(date: Date | undefined) => { if (date) setSelectedDate(date) }} />
@@ -38,7 +27,7 @@ const Page = () => {
onSelect={(date: Date | undefined) => { if (date) setSelectedDate(date) }} />
</div>
<div className='flex items-center'>
<Label className="w-20 text-xl text-gray-600">수행사</Label>
<Label className="w-20 text-xl text-gray-600">등록자</Label>
<Input
className='w-[100px]'
value={company}
@@ -46,7 +35,7 @@ const Page = () => {
/>
</div>
<div className='flex items-center'>
<Label className="w-20 text-xl text-gray-600">사업명</Label>
<Label className="w-20 text-xl text-gray-600">파일명</Label>
<Input
className='w-[100px]'
value={pjNm}
@@ -67,7 +56,7 @@ const Page = () => {
<Button className="px-4 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700 !mr-[1.2rem]" size="sm" >삭제</Button>
</div>
</div>
<UiTable headName='' tableData={tableData} headlist={tableHeadlist} pageSize={20} total={20} children={undefined} cellClick={() => { }} onPageChange={function (page: number): void {
<UiTable headName='' tableData={tableData} headlist={tableHeadlist} pageSize={10} total={20} children={undefined} cellClick={() => { }} onPageChange={function (page: number): void {
throw new Error('Function not implemented.')
}}></UiTable>
</ListDiv>
+35 -9
View File
@@ -1,26 +1,36 @@
'use client'
import { ContentsDiv, MainDiv, SearchDiv, SearchFormLeft, SearchFormRight, SelectBox, Title, UiTable } from '@common/business_components/ui'
import { Button, DatePicker, Label } from '@common/components/ui'
import { Button, DatePicker, Input, Label } from '@common/components/ui'
import React, { useState } from 'react'
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 = [
export const tableHeadlist = [
{ id: 'no', title: 'NO' },
{ id: 'fileNm', title: '파일명' },
{ id: 'manageYear', title: '관리년도' },
{ id: 'manageYear', title: '년도' },
{ id: 'bungi', title: '분기' },
{ id: 'registDt', title: '등록 일자' },
{ id: 'registUsr', title: '등록자' }
]
const tableData = [
{ 'no': '1', 'fileNm': '파일명', 'manageYear': '2023', 'registDt': '2025-04-16', 'registUsr': 'me' },
{ 'no': '2', 'fileNm': '파일명', 'manageYear': '2024', 'registDt': '2025-04-16', 'registUsr': 'me2' },
{ 'no': '3', 'fileNm': '파일명', 'manageYear': '2025', 'registDt': '2025-04-16', 'registUsr': 'me3' }
export const tableData = [
{ 'no': '1', 'fileNm': '파일명', 'manageYear': '2023', 'registDt': '2025-04-16', 'registUsr': 'me', 'bungi': '1분기' },
{ 'no': '2', 'fileNm': '파일명', 'manageYear': '2024', 'registDt': '2025-04-16', 'registUsr': 'me2', 'bungi': '1분기' },
{ 'no': '3', 'fileNm': '파일명', 'manageYear': '2025', 'registDt': '2025-04-16', 'registUsr': 'me3', 'bungi': '1분기' },
{ 'no': '4', 'fileNm': '파일명', 'manageYear': '2025', 'registDt': '2025-04-16', 'registUsr': 'me3', 'bungi': '1분기' },
{ 'no': '5', 'fileNm': '파일명', 'manageYear': '2025', 'registDt': '2025-04-16', 'registUsr': 'me3', 'bungi': '1분기' },
{ 'no': '6', 'fileNm': '파일명', 'manageYear': '2025', 'registDt': '2025-04-16', 'registUsr': 'me3', 'bungi': '1분기' },
{ 'no': '7', 'fileNm': '파일명', 'manageYear': '2025', 'registDt': '2025-04-16', 'registUsr': 'me3', 'bungi': '1분기' },
{ 'no': '8', 'fileNm': '파일명', 'manageYear': '2025', 'registDt': '2025-04-16', 'registUsr': 'me3', 'bungi': '1분기' },
{ 'no': '9', 'fileNm': '파일명', 'manageYear': '2025', 'registDt': '2025-04-16', 'registUsr': 'me3', 'bungi': '1분기' },
{ 'no': '10', 'fileNm': '파일명', 'manageYear': '2025', 'registDt': '2025-04-16', 'registUsr': 'me3', 'bungi': '1분기' }
]
const Page = () => {
const [selectedDate, setSelectedDate] = useState<Date>(new Date());
const [company, setCompany] = useState('')
const [pjNm, setpjNm] = useState('')
return (
<ContentLayout title='노후 하수관로 정비사업'>
<SearchDiv>
@@ -35,6 +45,22 @@ const Page = () => {
<DatePicker mode={'single'}
selected={selectedDate}
onSelect={(date: Date | undefined) => { if (date) setSelectedDate(date) }} />
<div className='flex items-center'>
<Label className="w-20 text-xl text-gray-600">등록자</Label>
<Input
className='w-[100px]'
value={company}
onChange={(e) => setCompany(e.target.value)}
/>
</div>
<div className='flex items-center'>
<Label className="w-20 text-xl text-gray-600">파일명</Label>
<Input
className='w-[100px]'
value={pjNm}
onChange={(e) => setpjNm(e.target.value)}
/>
</div>
</div>
</div>
</SearchFormLeft>
@@ -43,14 +69,14 @@ const Page = () => {
</SearchFormRight>
</SearchDiv>
<ListDiv className="mt-4">
<div className="card-header flex items-center justify-between">
<div className="card-header flex items-center justify-between">
<h3 className="text-2xl font-medium">사업정보 등록현황</h3>
<div>
<Button className="px-4 py-2 !mr-[1.2rem] bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700" size="sm" >파일 다운로드</Button>
<Button className="px-4 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700 !mr-[1.2rem]" size="sm" >삭제</Button>
</div>
</div>
<UiTable headName='' tableData={tableData} headlist={tableHeadlist} pageSize={20} total={20} children={undefined} cellClick={() => { }} onPageChange={function (page: number): void {
<UiTable headName='' tableData={tableData} headlist={tableHeadlist} pageSize={10} total={20} children={undefined} cellClick={() => { }} onPageChange={function (page: number): void {
throw new Error('Function not implemented.')
}}></UiTable>
</ListDiv>
+3 -18
View File
@@ -14,24 +14,9 @@ export default function Home() {
</div>
<div><h3 className="text-2xl text-bold gap-4 mx-4">I/I 분석(기초정보 설정)</h3>
<div className="flex flex-row gap-4 p-4">
<Link href={"/ii/baseinfo/mock"}><Button>모의정보 설정</Button></Link>
<Link href={"/ii/baseinfo/observe"}><Button>관망도 등록</Button></Link>
<Link href={"/ii/baseinfo/polygon"}><Button>티센 폴리곤 등록</Button></Link>
<Link href={"/ii/baseinfo/regist"}><Button>수용가-맨홀 등록</Button></Link>
</div>
</div>
<div>
<h3 className="text-2xl text-bold gap-4 mx-4">I/I 분석(침입수 분석)</h3>
<div className="flex flex-row gap-4 p-4">
<Link href={"/ii/ir/measureDataUpload"}><Button>하수측정자료 업로드</Button></Link>
<Link href={"/ii/ir/irsetting"}><Button>침입수 산정</Button></Link>
</div>
</div>
<div>
<h3 className="text-2xl text-bold gap-4 mx-4">I/I 분석(RDII 분석)</h3>
<div className="flex flex-row gap-4 p-4">
<Link href={"/ii/rdii/rain"}><Button>강우자료 등록</Button></Link>
<Link href={"/ii/rdii/rdiisetting"}><Button>rdii 산정</Button></Link>
<Link href={"/ii/irsetting"}><Button>침입수 분석</Button></Link>
<Link href={"/ii/rdii"}><Button>RDII 분석</Button></Link>
<Link href={"/ii/result"}><Button>분석결과</Button></Link>
</div>
</div>
</div>
@@ -15,6 +15,7 @@ import GisToolBar from './GisToolBar';
import GisSelect from './GisSelect';
import GisTab from './GisTab';
import MapToggleBtn from './MapToggleBtn';
import FeatureClickEventPopup from '@/map/featureClickEventPopup';
export const GisContext = createContext({gisCore: null, gisMap: null, treeData:null});
export const useGisContext = () => useContext(GisContext);
@@ -22,8 +23,20 @@ export const useGisContext = () => useContext(GisContext);
function Gis({ treeData = [], isSearch = false }) {
const mapRef = useRef();
const gisCore = useMemo(() => new GisApp.core({ targetId: mapRef.current }), []);
const [tabVisible, setTabVisible] = useState(true);
const [gisMap, setGisMap] = useState(null);
const [tabVisible, setTabVisible] = useState(true);
const [isOpen, setIsOpen] = useState(false); // 팝업 열기/닫기 상태
const [featureData,setFeatureData] = useState(null) // 선택된 피쳐 데이터
const closePopup = () => {
setIsOpen(false); // 팝업 닫기
setFeatureData(null)
};
const handleFeatureSelect = (data) => {
console.log('check',data)
setFeatureData(data); // 선택된 피처 데이터 저장
setIsOpen(true); // 팝업 열기
};
//맵 생성 및 컨트롤 추가
useEffect(() => {
@@ -95,8 +108,8 @@ function Gis({ treeData = [], isSearch = false }) {
GisApp.layerCode = layerCode;
//setTreeData(data);
//const layerItems = getLayerItems(layerCode);
//setEditLayerItems(prev => [...layerItems]);
const layerItems = getLayerItems(layerCode);
//setEditLayerItems(prev => [...layerItems])
}, [treeData]);
//레이어 정렬
@@ -128,6 +141,13 @@ function Gis({ treeData = [], isSearch = false }) {
<GisContext.Provider value={{gisCore, gisMap, treeData}}>
<div className="h-[calc(100vh-10rem)] flex relative">
<GisTab visible={tabVisible} setVisible={setTabVisible} isSearch={isSearch} />
<GisContent onFeatureSelect={handleFeatureSelect}/>
{isOpen && featureData && (
<FeatureClickEventPopup
featureData={featureData}
onClose={closePopup} // 닫기 콜백 전달
/>
)}
<div ref={mapRef} className="gis-map flex-1 relative" style={{ height: '100%', padding: 0 }} />
<GisLonLat/>
<GisToolBar/>
@@ -8,7 +8,7 @@ import './lib/css/gis.edit.css';
import MapToggleBtn from './MapToggleBtn';
import GisEdit from './GisEdit';
export default function GisContent({ edit = false }) {
export default function GisContent({ edit = false,onFeatureSelect }) {
const { gisMap, gisCore } = useGisContext();
const [visibleComponents, setVisibleComponents] = useState({});
const addressResultLayer = useRef(null);
@@ -54,7 +54,7 @@ export default function GisContent({ edit = false }) {
{/* <MapToggleBtn useCesium={useCesium} /> */}
{/* { <GisLonLat /> */}
{/* <GisSelect clickFeature={clickFeature} /> */}
<GisSelect />
<GisSelect onFeatureSelect={onFeatureSelect}/>
{/* {edit && <GisEdit />} */}
</>
);
@@ -2,21 +2,31 @@ import React, { useCallback, useContext, useEffect, useRef, useState } from 'rea
import GisApp from './lib/gis.core';
import GisOlSelect from './lib/gis.select';
import { GisContext } from './Gis';
export default React.memo(function GisSelect({onFeatureClick}) {
export default React.memo(function GisSelect({ onFeatureSelect }) {
const { gisMap } = useContext(GisContext);
useEffect(() => {
if (!gisMap) return; // 아직 초기화 안 됐으면 아무것도 안 함
// useEffect(() => {
// if (!gisMap) return; // 아직 초기화 안 됐으면 아무것도 안 함
const select = new GisOlSelect(gisMap);
GisApp.Module.select = select;
// const select = new GisOlSelect(gisMap);
// GisApp.Module.select = select;
select.getSelectedInfo(function (features) {
if (features?.[0]) {
onFeatureClick?.(features[0]); // props로 넘긴 함수 실행
}
});
}, [gisMap, onFeatureClick]);
// select.getSelectedInfo(function (features) {
// if (features?.[0]) {
// onFeatureClick?.(features[0]); // props로 넘긴 함수 실행
// }
// });
// }, [gisMap, onFeatureClick]);
select.getSelectedInfo(function (features) {
//clickFeature(features[0]);
if(features.length > 0) {
const layer = features[0];
onFeatureSelect(layer.getProperties()); //피쳐 속성데이터 상위컴포넌트로 전달
}
});
return (
<>