feat: I/I 분석 화면 엑셀 파일 업로드 시 Json 변환 기능 구현 및 title 수정
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
export const TEST_UUID= '2d4b151d-1828-41e0-91d9-4cd28ea1cc7e'
|
||||
import { z } from "zod";
|
||||
|
||||
// 수용가-맨홀 매칭결과 (아직 안함)
|
||||
export const MatchingResultZod = z.object({
|
||||
anls_sn: z.number(),
|
||||
mhl_mng_no: z.string(), // 일련번호 0 포함인지? number? string?
|
||||
rcptr_no: z.string(),
|
||||
});
|
||||
|
||||
export type MatchingResultZodType = z.infer<typeof MatchingResultZod>;
|
||||
|
||||
export const excelToMatchingResultData = (excelData: any) => {
|
||||
const MatchingResultData: MatchingResultZodType[] = excelData.map((item: any) => {
|
||||
|
||||
return {
|
||||
anls_sn: Number(item["NO"]),
|
||||
mhl_mng_no: String(item["FTR_IDN"]), // 임시값이라 추후 수정 필요
|
||||
rcptr_no: String(item["수용가"]),
|
||||
};
|
||||
}).filter((el: any) => el !== undefined);
|
||||
return MatchingResultData;
|
||||
};
|
||||
|
||||
// 시간패턴
|
||||
export const timePatternZod = z.object({
|
||||
hr_id: z.number(),
|
||||
rt: z.number().nullish(),
|
||||
});
|
||||
|
||||
export type timePatternZodType = z.infer<typeof timePatternZod>;
|
||||
|
||||
export const excelToTimePatternData = (excelData: any) => {
|
||||
const timePatternData: timePatternZodType[] = excelData.map((item: any) => {
|
||||
|
||||
return {
|
||||
hr_id: Number(item["시간"]),
|
||||
rt: Number(item["비율"]),
|
||||
};
|
||||
}).filter((el: any) => el !== undefined);
|
||||
return timePatternData;
|
||||
};
|
||||
|
||||
// 유량자료
|
||||
export const flowRateZod = z.object({
|
||||
ppl_mng_no: z.string(),
|
||||
mtrng_dt: z.number(), // type 뭘로 해야할지 Date? timeStamp임
|
||||
oilq: z.number().nullish(),
|
||||
});
|
||||
|
||||
export type flowRateZodType = z.infer<typeof flowRateZod>;
|
||||
|
||||
export const excelToflowRateData = (excelData: any) => {
|
||||
const flowRateData: flowRateZodType[] = excelData.map((item: any) => {
|
||||
|
||||
return {
|
||||
ppl_mng_no: String(item["관로번호"]),
|
||||
mtrng_dt: new Date(item["시간"]).toISOString(), // type 뭘로 해야할지 Date? timeStamp임
|
||||
oilq: Number(item["유량(㎥/h)"]),
|
||||
};
|
||||
}).filter((el: any) => el !== undefined);
|
||||
return flowRateData;
|
||||
};
|
||||
@@ -4,6 +4,8 @@ import { SearchDiv, SearchFormLeft, SelectBox, SearchFormRight, Form, UiTable }
|
||||
import ListDiv from '@common/business_components/ui/list_div'
|
||||
import { Button } from '@common/components/ui'
|
||||
import React, { type ReactNode } from 'react'
|
||||
import { SelectBox2 } from '@common/business_components/ui/select/index-2'
|
||||
|
||||
type TitleName = {
|
||||
mainTitle: string
|
||||
firstCardTitle: string
|
||||
@@ -12,6 +14,7 @@ type TitleName = {
|
||||
type SelectBox = {
|
||||
labelNm?: Label
|
||||
searchChk?: boolean
|
||||
title?: string // SearchDiv의 제목 (선택 사항)
|
||||
}
|
||||
type Label = {
|
||||
first: string
|
||||
@@ -41,15 +44,30 @@ type BaseLayout = {
|
||||
const BaseLayout = ({ children, titleName, form, onSubmitEvent, graphBtn = false, searchBox }: BaseLayout) => {
|
||||
return (
|
||||
<ContentLayout title={titleName.mainTitle}>
|
||||
<SearchDiv>
|
||||
<SearchFormLeft>
|
||||
<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>
|
||||
{searchBox?.searchChk ? <SearchFormRight><Button>조회</Button></SearchFormRight> : null}
|
||||
</SearchDiv>
|
||||
<ListDiv>
|
||||
{/* searchBox.title이 있으면 h3 태그로 제목을 표시합니다. */}
|
||||
{searchBox?.title && (
|
||||
<div className="card-header">
|
||||
<h3 className="text-2xl font-medium">{searchBox.title}</h3>
|
||||
<div>
|
||||
{graphBtn ? <Button className="!mr-[1.2rem]">다운로드</Button> : null}
|
||||
{/* 그래프 있을 시 */}
|
||||
{graphBtn ? <Button className="!mr-[1.2rem]">삭제</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center w-full">
|
||||
<div className="flex-1">
|
||||
<SearchFormLeft>
|
||||
<SelectBox2 label={searchBox?.labelNm?.first ?? ''} selectArray={[{ text: '한강 유역청', val: '1' }]} className="col-span-2" onSelectValue={(val) => { }} selectClass={undefined} />
|
||||
<SelectBox2 label={searchBox?.labelNm?.second ?? ''} selectArray={[{ text: '경기도', val: '1' }]} className="col-span-2" onSelectValue={() => { }} selectClass='' />
|
||||
<SelectBox2 label={searchBox?.labelNm?.third ?? ''} selectArray={[{ text: '양평군', val: '1' }]} className="col-span-3" onSelectValue={() => { }} selectClass='' />
|
||||
<SelectBox2 label={searchBox?.labelNm?.fourth ?? ''} selectArray={[{ text: '양평하수처리장', val: '1' }]} className="col-span-3" onSelectValue={() => { }} selectClass='' />
|
||||
</SearchFormLeft>
|
||||
</div>
|
||||
{searchBox?.searchChk ? <SearchFormRight><Button>조회</Button></SearchFormRight> : null}
|
||||
</div>
|
||||
</ListDiv>
|
||||
<ListDiv>
|
||||
<div className="card-header">
|
||||
<h3 className="text-2xl font-medium">{titleName.firstCardTitle}</h3>
|
||||
@@ -68,18 +86,20 @@ const BaseLayout = ({ children, titleName, form, onSubmitEvent, graphBtn = false
|
||||
</form>
|
||||
</Form>
|
||||
</ListDiv>
|
||||
{children?.[1] != null ? <ListDiv>
|
||||
<div className="card-header flex items-center justify-between">
|
||||
<h3 className="text-2xl font-medium">{titleName?.secondCardTitle}</h3>
|
||||
<div>
|
||||
{graphBtn ? <Button className="!mr-[1.2rem]">다운로드</Button> : null}
|
||||
{/* 그래프 있을 시 */}
|
||||
{graphBtn ? <Button className="!mr-[1.2rem]">삭제</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
<div className="card !m-[1.2rem]">{children?.[1]}</div>
|
||||
</ListDiv> : null}
|
||||
</ContentLayout>
|
||||
{
|
||||
children?.[1] != null ? <ListDiv>
|
||||
<div className="card-header flex items-center justify-between">
|
||||
<h3 className="text-2xl font-medium">{titleName?.secondCardTitle}</h3>
|
||||
<div>
|
||||
{graphBtn ? <Button className="!mr-[1.2rem]">다운로드</Button> : null}
|
||||
{/* 그래프 있을 시 */}
|
||||
{graphBtn ? <Button className="!mr-[1.2rem]">삭제</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
<div className="card !m-[1.2rem]">{children?.[1]}</div>
|
||||
</ListDiv> : null
|
||||
}
|
||||
</ContentLayout >
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
'use client'
|
||||
import React, { useState } from 'react'
|
||||
import { FormField, SelectBox } from '@common/business_components/ui'
|
||||
import React, { useRef, useState } from 'react'
|
||||
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 { filePicked, FileUpload } from '@common/business_components/ui'
|
||||
import { excelToflowRateData, excelToMatchingResultData, excelToTimePatternData } from '../../components/lib/utils/excelToJson'
|
||||
import { postData } from '@/components/lib/api'
|
||||
|
||||
const formSchema = z.object({
|
||||
managenm: z.string(),
|
||||
region: z.string(),
|
||||
@@ -14,7 +17,7 @@ const formSchema = z.object({
|
||||
inputdate: z.coerce.date(),
|
||||
rtkSource: z.string(),
|
||||
suyeongaPlace: z.string(),
|
||||
pattern : z.string()
|
||||
pattern: z.string()
|
||||
})
|
||||
const region: { text: string, val: number }[] = [{ text: '양평', val: 1 }, { text: '강남', val: 2 }, { text: 'test', val: 3 }]
|
||||
const IrSetting = () => {
|
||||
@@ -30,35 +33,106 @@ const IrSetting = () => {
|
||||
pattern: ""
|
||||
}
|
||||
})
|
||||
const [file1, setFile1] = useState<File | null>(null);
|
||||
const [file2, setFile2] = useState<File | null>(null);
|
||||
const [file3, setFile3] = useState<File | null>(null);
|
||||
const [file4, setFile4] = useState<File | null>(null);
|
||||
const [selectedDate, setSelectedDate] = useState(new Date())
|
||||
const fileInputRef1 = useRef<HTMLInputElement>(null)
|
||||
const fileInputRef2 = useRef<HTMLInputElement>(null)
|
||||
const fileInputRef3 = useRef<HTMLInputElement>(null)
|
||||
const fileInputRef4 = useRef<HTMLInputElement>(null)
|
||||
|
||||
// 버튼 클릭 핸들러
|
||||
const handleAnalysisClick = async () => {
|
||||
const file1 = fileInputRef1.current?.files?.[0]
|
||||
const file2 = fileInputRef2.current?.files?.[0]
|
||||
const file3 = fileInputRef3.current?.files?.[0]
|
||||
|
||||
if (!file1 || !file2 || !file3) {
|
||||
alert('모든 파일을 선택해주세요.')
|
||||
return
|
||||
}
|
||||
|
||||
let json2: any = null;
|
||||
let json3: any = null;
|
||||
|
||||
await filePicked(file2, 0).then((res) => {
|
||||
if (res !== undefined) json2 = excelToMatchingResultData(res);
|
||||
});
|
||||
await filePicked(file3, 0).then((res) => {
|
||||
if (res !== undefined) json3 = excelToTimePatternData(res);
|
||||
});
|
||||
|
||||
|
||||
console.log(file1)
|
||||
console.log(json2)
|
||||
console.log(json3)
|
||||
}
|
||||
|
||||
|
||||
// 버튼 클릭 핸들러
|
||||
const handleUploadClick = async () => {
|
||||
const file4 = fileInputRef4.current?.files?.[0];
|
||||
|
||||
if (!file4) {
|
||||
alert('파일을 선택해주세요.')
|
||||
return
|
||||
}
|
||||
let json4: any = null;
|
||||
await filePicked(file4, 0).then((res) => {
|
||||
console.log(res);
|
||||
if (res !== undefined) json4 = excelToflowRateData(res);
|
||||
});
|
||||
console.log(json4);
|
||||
|
||||
// json4가 존재하면 postData로 백엔드에 전송
|
||||
if (json4) {
|
||||
try {
|
||||
const response = await postData('your-backend-endpoint', json4); // 'your-backend-endpoint'를 실제 API 경로로 변경
|
||||
console.log('업로드 결과:', response);
|
||||
alert('업로드가 완료되었습니다.');
|
||||
} catch (error) {
|
||||
console.error('업로드 실패:', error);
|
||||
alert('업로드에 실패했습니다.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<BaseLayout titleName={{ mainTitle: '침입수 산정', firstCardTitle: '실측자료 등록', secondCardTitle: '침입수 분석자료 입력' }} form={form} onSubmitEvent={() => { }} graphBtn={false}>
|
||||
<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='pattern' 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>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<FormSection name='region' form={form} titleNm='○ 파일위치'>
|
||||
<div className="w-[150px]">
|
||||
<Input id="fileNm" type="file" />
|
||||
<>
|
||||
<BaseLayout titleName={{ mainTitle: '침입수 분석', firstCardTitle: '침입수 분석 자료 입력', secondCardTitle: '실측자료 등록' }} form={form} onSubmitEvent={() => { }} graphBtn={false} searchBox={{ title: '분석 대장지역 선택' }} >
|
||||
<div className="grid gap-4">
|
||||
<FormSection name='suyeongaPlace' form={form} titleNm='▷ 오수관망도'><div className="">
|
||||
<Input id="fileNm" ref={fileInputRef1} type="file" />
|
||||
</div></FormSection>
|
||||
<FormSection name='suyeonga' form={form} titleNm='▷ 수용가-맨홀 매칭결과'><div className="w-[150px]">
|
||||
<Input id="fileNm" ref={fileInputRef2} type="file" accept=".xls, .xlsx, .xlsm, .xltx" />
|
||||
</div></FormSection>
|
||||
<FormSection name='pattern' form={form} titleNm='▷ 오수량 시간패턴'><div className="w-[150px]">
|
||||
<Input id="fileNm" ref={fileInputRef3} type="file" accept=".xls, .xlsx, .xlsm, .xltx" />
|
||||
</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>
|
||||
<FormSection name='analysis information' form={form} titleNm='▷ 분석 정보'><Input className="h-[3.2rem] text-center text-xl w-[150px]" /></FormSection>
|
||||
<div className="flex justify-center mt-1">
|
||||
<Button type="submit" onClick={handleAnalysisClick}>침입수분석 실행</Button>
|
||||
</div>
|
||||
</FormSection>
|
||||
</div>
|
||||
</BaseLayout>
|
||||
</div>
|
||||
<div className="flex items-center gap-24">
|
||||
<FormSection name='region' form={form} titleNm='▷ 유량자료 등록'>
|
||||
<div className="w-[150px]">
|
||||
<Input id="fileNm" ref={fileInputRef4} type="file" accept=".xls, .xlsx, .xlsm, .xltx" />
|
||||
</div>
|
||||
</FormSection>
|
||||
<div className='mt-1'>
|
||||
<Button type="submit" onClick={handleUploadClick}>자료 업로드</Button>
|
||||
</div>
|
||||
</div>
|
||||
</BaseLayout>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -88,17 +88,17 @@ export default function RTKForm() {
|
||||
}
|
||||
const [selectedDate, setSelectedDate] = useState(new Date())
|
||||
return (
|
||||
<BaseLayout titleName={{ mainTitle: 'RDII 분석', firstCardTitle: 'RDII 분석자료 입력' }} form={form} onSubmitEvent={() => { }} graphBtn={false}>
|
||||
<BaseLayout searchBox={{ title: '분석 대장지역 선택' }} titleName={{ mainTitle: 'RDII 분석', firstCardTitle: 'RDII 분석자료 입력', secondCardTitle: '실측자료 등록' }} 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>
|
||||
<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>
|
||||
@@ -132,23 +132,24 @@ export default function RTKForm() {
|
||||
</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>
|
||||
<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>
|
||||
<FormSection name='rate' form={form} titleNm='○ 분석 정보'><Input className="h-[3.2rem] text-center text-xl w-[150px]" /></FormSection>
|
||||
</div>
|
||||
<div className="flex justify-end mt-1">
|
||||
<Button type="submit">RDII분석 실행</Button>
|
||||
</div>
|
||||
<div className="flex justify-end mt-1">
|
||||
<Button type="submit">RDII분석 실행</Button>
|
||||
</div>
|
||||
</div>
|
||||
]}
|
||||
</BaseLayout >
|
||||
|
||||
@@ -57,7 +57,7 @@ const Result = () => {
|
||||
}
|
||||
})
|
||||
return (
|
||||
<BaseLayout searchBox={{labelNm: {first: "분석기간",second: "침입수",third: "처리장",fourth: "처리구역",},searchChk: true,}} titleName={{ mainTitle: '분석결과', firstCardTitle: '분석이력', secondCardTitle:'RDII 산정결과 현황'}} form={form} onSubmitEvent={() => { }} graphBtn={true}>
|
||||
<BaseLayout searchBox={{labelNm: {first: "분석기간",second: "분석구분",third: "하수처리장",fourth: "하수처리구역",},searchChk: true,}} titleName={{ mainTitle: '분석결과', firstCardTitle: '분석이력', secondCardTitle:'RDII 산정결과 현황'}} form={form} onSubmitEvent={() => { }} graphBtn={true}>
|
||||
{[<div key='table1'>
|
||||
<div className="mb-[1.2rem] text-xl font-medium">○ 침입수 산정결과 현황</div>
|
||||
<UiTable
|
||||
|
||||
Reference in New Issue
Block a user