Merge remote-tracking branch 'origin/iipbs/sn/dev' into iipbs-sn-map
This commit is contained in:
@@ -43,7 +43,7 @@ export const putData = async (url: string, data: object): Promise<any> => {
|
||||
return resData;
|
||||
};
|
||||
|
||||
export const getData = async (url: string): Promise<any> => {
|
||||
export const getData = async (url: string, data?: object): Promise<any> => {
|
||||
const res = await fetch(url.startsWith('/') ? `${url}` : `${BASE_URL}/${url}`, {
|
||||
method: "GET",
|
||||
});
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
const BASE_URL = process.env.NEXT_PUBLIC_SERVER_API_URL || '';
|
||||
|
||||
export const handleDownload = async (api:string, fileNm:string) => {
|
||||
try {
|
||||
const response = await fetch(api, {
|
||||
|
||||
@@ -5,8 +5,9 @@ type LayoutNode = {
|
||||
children : ReactNode
|
||||
title : string
|
||||
isLoading?: boolean
|
||||
className?: string
|
||||
}
|
||||
const ContentLayout = ({children, title, isLoading} : LayoutNode) => {
|
||||
const ContentLayout = ({children, title, isLoading, className} : LayoutNode) => {
|
||||
return (
|
||||
<MainDiv>
|
||||
<Title title={title} />
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useEffect, useState } from "react";
|
||||
|
||||
type UiTableProps = {
|
||||
headName: React.ReactNode | undefined;
|
||||
tableName1?: React.ReactNode | undefined;
|
||||
tableData: { [key: string]: string | number | boolean | object }[];
|
||||
headlist: UiHeadProps[];
|
||||
pageSize: number;
|
||||
@@ -14,6 +15,18 @@ type UiTableProps = {
|
||||
className?: string;
|
||||
resetPageNo?: boolean;
|
||||
isEditable?: boolean;
|
||||
tableName2?: React.ReactNode | undefined;
|
||||
tableData2?: { [key: string]: string | number | boolean | object }[];
|
||||
headlist2?: UiHeadProps[];
|
||||
pageSize2?: number;
|
||||
total2?: number;
|
||||
children2?: Record<string, React.ReactNode> | undefined;
|
||||
cellClick2?: ((index: number | undefined, headId: string) => void) | undefined;
|
||||
onPageChange2?: (page: number) => void;
|
||||
className2?: string;
|
||||
resetPageNo2?: boolean;
|
||||
isEditable2?: boolean;
|
||||
showSecondTable?: boolean;
|
||||
};
|
||||
|
||||
type UiHeadProps = {
|
||||
@@ -25,17 +38,30 @@ type UiHeadProps = {
|
||||
};
|
||||
|
||||
export function VerticalTable({
|
||||
headName,
|
||||
tableName1,
|
||||
tableData,
|
||||
headlist,
|
||||
pageSize,
|
||||
total,
|
||||
children,
|
||||
headName,
|
||||
cellClick,
|
||||
onPageChange,
|
||||
className = "",
|
||||
resetPageNo = false,
|
||||
isEditable = false,
|
||||
tableName2,
|
||||
tableData2,
|
||||
headlist2,
|
||||
pageSize2,
|
||||
total2,
|
||||
children2,
|
||||
cellClick2,
|
||||
onPageChange2,
|
||||
className2 = "",
|
||||
resetPageNo2 = false,
|
||||
isEditable2 = false,
|
||||
showSecondTable = false,
|
||||
}: UiTableProps) {
|
||||
const [cur, setCur] = useState<number>(1);
|
||||
const [formData, setFormData] = useState<{ [key: string]: string | number | boolean }>({});
|
||||
@@ -72,6 +98,9 @@ export function VerticalTable({
|
||||
</div>
|
||||
) : null}
|
||||
<div className={`card !m-[1.2rem] !p-0r ${className}`}>
|
||||
{tableName1 && ( // tableName prop이 있으면 표시
|
||||
<div className="text-xl font-semibold my-2 mx-3">{tableName1}</div>
|
||||
)}
|
||||
<Table variant="secondary">
|
||||
<TableBody className="text-center">
|
||||
{headlist?.map((head) => (
|
||||
@@ -115,6 +144,54 @@ export function VerticalTable({
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
{tableName2 && ( // tableName prop이 있으면 표시
|
||||
<div className="text-xl font-semibold mt-8 my-2 mx-3">{tableName2}</div>
|
||||
)}
|
||||
{showSecondTable && (
|
||||
<Table variant="secondary">
|
||||
<TableBody className="text-center">
|
||||
{headlist2?.map((head) => (
|
||||
<TableRow key={head.id}>
|
||||
{/* 컬럼 제목 */}
|
||||
<TableCell className="font-bold bg-blue-100 text-xs w-fit whitespace-nowrap">
|
||||
{head.title}
|
||||
</TableCell>
|
||||
{/* 데이터 값 또는 입력 필드 */}
|
||||
<TableCell className="text-xs">
|
||||
{children && children[head.id] ? children[head.id] : isEditable2 ? (
|
||||
head.type === "select" ? (
|
||||
<select
|
||||
id={head.id}
|
||||
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
|
||||
id={head.id}
|
||||
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}
|
||||
|
||||
+117
-72
@@ -1,13 +1,13 @@
|
||||
'use client'
|
||||
import { getData } from '@/components/lib/api'
|
||||
import { getData, deleteData } from '@/components/lib/api'
|
||||
import ContentLayout from '@/components/ui/contentLayout'
|
||||
import { GovSidoSigunguSearchForm } from '@/components/ui/govSidoSigunguSearchForm'
|
||||
import { Form, SearchFormRight, SelectBox } from '@common/business_components/ui'
|
||||
import { SidoSigunguSelectBox } from '../components/ui/SidoSigunguSelectBox'
|
||||
import { SelectBox2 } from '@common/business_components/ui/select/index-2'
|
||||
import { DatePicker, Form, SearchFormRight, SelectBox } from '@common/business_components/ui'
|
||||
import ListDiv from '@common/business_components/ui/list_div'
|
||||
import { SelectBox2 } from '@common/business_components/ui/select/index-2'
|
||||
import { Button, Label } from '@common/components/ui'
|
||||
import { useEffect, useState, type ReactNode } from 'react'
|
||||
import { handleDownload } from '@/components/lib/utils/fileDownload'
|
||||
|
||||
type TitleName = {
|
||||
mainTitle: string
|
||||
@@ -17,7 +17,8 @@ type TitleName = {
|
||||
type SelectBox = {
|
||||
labelNm?: Label
|
||||
searchChk?: boolean
|
||||
title?: string // SearchDiv의 제목 (선택 사항)
|
||||
title?: string;
|
||||
onSearchClick?: () => Promise<void>;
|
||||
}
|
||||
type Label = {
|
||||
first: string
|
||||
@@ -29,7 +30,7 @@ type Label = {
|
||||
interface ApiSelectOption {
|
||||
text: string;
|
||||
val: string;
|
||||
}
|
||||
}
|
||||
type BaseLayout = {
|
||||
children?: ReactNode[]
|
||||
titleName: TitleName
|
||||
@@ -38,6 +39,7 @@ type BaseLayout = {
|
||||
graphBtn?: boolean
|
||||
firstDivBtn?: boolean
|
||||
searchBox?: SelectBox
|
||||
showDatePicker?: boolean;
|
||||
enoCd?: string | number
|
||||
setEnoCd?: (enoCd: string) => void
|
||||
ctpvCd?: string | number
|
||||
@@ -48,6 +50,8 @@ type BaseLayout = {
|
||||
onSwageTreatmentPlantChange?: (value: string | number) => void;
|
||||
selectedSwageProcessingZone?: string | number;
|
||||
onSwageProcessingZoneChange?: (value: string | number) => void;
|
||||
aplcnYm?: Date
|
||||
setAplcnYm?: (aplcnYm: Date | undefined) => void;
|
||||
}
|
||||
// TODO: 나중에 이벤트 추가되면 파라미터 추가 필요 ?
|
||||
/**
|
||||
@@ -59,23 +63,26 @@ type BaseLayout = {
|
||||
* @param graphBtn : 하단에 그래프 버튼 유무 처리
|
||||
* @returns
|
||||
*/
|
||||
const BaseLayout = ({
|
||||
children,
|
||||
titleName,
|
||||
form,
|
||||
onSubmitEvent,
|
||||
graphBtn = false,
|
||||
const BaseLayout = ({
|
||||
children,
|
||||
titleName,
|
||||
form,
|
||||
onSubmitEvent,
|
||||
graphBtn = false,
|
||||
searchBox,
|
||||
showDatePicker = false,
|
||||
enoCd,
|
||||
setEnoCd,
|
||||
ctpvCd,
|
||||
setCtpvCd,
|
||||
sigungu,
|
||||
sigungu,
|
||||
setSigungu,
|
||||
selectedSwageTreatmentPlant,
|
||||
onSwageTreatmentPlantChange,
|
||||
selectedSwageProcessingZone,
|
||||
onSwageProcessingZoneChange,
|
||||
aplcnYm,
|
||||
setAplcnYm
|
||||
}: BaseLayout) => {
|
||||
|
||||
const defaultOption: ApiSelectOption = { val: '0', text: '선택' };
|
||||
@@ -83,6 +90,9 @@ const BaseLayout = ({
|
||||
const [processingZoneOptions, setProcessingZoneOptions] = useState<ApiSelectOption[]>([]);
|
||||
const [treatmentFacilityOptions, setTreatmentFacilityOptions] = useState<ApiSelectOption[]>([]);
|
||||
const [isLoadingAreaData, setIsLoadingAreaData] = useState<boolean>(false);
|
||||
const [atflId, setAtflId] = useState('')
|
||||
const [fileNm, setFileNm] = useState('')
|
||||
const [dcrpPplMtncBizSn, setDcrpPplMtncBizSn] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
@@ -159,66 +169,101 @@ const BaseLayout = ({
|
||||
fetchData();
|
||||
}, [sigungu]); // sigungu 상태가 변경될 때마다 실행
|
||||
|
||||
return (
|
||||
<ContentLayout title={titleName.mainTitle}>
|
||||
<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">
|
||||
<GovSidoSigunguSearchForm
|
||||
isShowPart={true}
|
||||
setRtnEnvPartValue={(val) => setEnoCd?.(val)}
|
||||
setRtnEnvPartSidoValue={(val) => setCtpvCd?.(val)}
|
||||
setRtnEnvPartSigunValue={setSigungu} // 선택된 시군구 값을 받을 콜백 함수 전달
|
||||
>
|
||||
<SelectBox2 label={"하수처리장"} value={selectedSwageTreatmentPlant} selectArray={treatmentFacilityOptions} className="col-span-3" selectClass="rounded-lg bg-white truncate" onSelectValue={(val) => onSwageTreatmentPlantChange?.(val)} />
|
||||
<SelectBox2 label={"하수처리구역"} value={selectedSwageProcessingZone} selectArray={processingZoneOptions} className="col-span-3" selectClass="rounded-lg bg-white truncate" onSelectValue={(val) => onSwageProcessingZoneChange?.(val)} />
|
||||
</GovSidoSigunguSearchForm>
|
||||
{searchBox?.searchChk ? <SearchFormRight><Button>조회</Button></SearchFormRight> : null}
|
||||
|
||||
</div>
|
||||
</ListDiv>
|
||||
<ListDiv>
|
||||
<div className="card-header">
|
||||
<h3 className="text-2xl font-medium">{titleName.firstCardTitle}</h3>
|
||||
<div>
|
||||
{graphBtn ? <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> : null}
|
||||
{/* 그래프 있을 시 */}
|
||||
{graphBtn ? <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> : null}
|
||||
</div>
|
||||
</div>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmitEvent)}>
|
||||
<div className="card !m-[1.2rem]">
|
||||
{/* 폼 정보 입력 칸 */}
|
||||
{children?.[0]}
|
||||
</div>
|
||||
</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="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> : null}
|
||||
{/* 그래프 있을 시 */}
|
||||
{graphBtn ? <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> : null}
|
||||
</div>
|
||||
</div>
|
||||
<div className="card !m-[1.2rem]">{children?.[1]}</div>
|
||||
</ListDiv> : null
|
||||
// 파일 다운로드
|
||||
const isChckFile = () => {
|
||||
if (fileNm === '' || fileNm === undefined) {
|
||||
alert('파일을 선택해주세요');
|
||||
return false
|
||||
}
|
||||
handleDownload(`/attach-service/api/v1/download/${atflId}`, fileNm)
|
||||
return true
|
||||
}
|
||||
// 파일 삭제
|
||||
const isDeleteFile = async () => {
|
||||
if (dcrpPplMtncBizSn === '' || dcrpPplMtncBizSn === undefined) {
|
||||
alert('삭제할 파일을 선택해주세요');
|
||||
return false
|
||||
}
|
||||
const data = await deleteData(`/attach-service/api/v1/atfl/attachments/${atflId}`)
|
||||
if (data) {
|
||||
const delData = await deleteData(`v1/dcrpPpl/${dcrpPplMtncBizSn}`);
|
||||
if (delData.status == 200) {
|
||||
alert('삭제되었습니다.')
|
||||
searchBox?.onSearchClick?.();
|
||||
} else {
|
||||
alert('삭제에 실패했습니다.')
|
||||
}
|
||||
</ContentLayout >
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Form {...form} className="min-h-screen flex flex-col">
|
||||
<ContentLayout title={titleName.mainTitle} className="flex-grow flex flex-col overflow-hidden">
|
||||
<ListDiv>
|
||||
{/* searchBox.title이 있으면 h3 태그로 제목을 표시합니다. */}
|
||||
{searchBox?.title && (
|
||||
<div className="card-header">
|
||||
<h3 className="text-2xl font-medium">{searchBox.title}</h3>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center w-full">
|
||||
{showDatePicker && ( // showDatePicker 값에 따라 DatePicker 렌더링
|
||||
<>
|
||||
<Label className="ml-4 w-20 text-xl text-gray-600 whitespace-nowrap">분석기간</Label>
|
||||
<DatePicker
|
||||
mode={"single"}
|
||||
field={{
|
||||
value: aplcnYm ?? new Date(),
|
||||
onChange: setAplcnYm ?? ((date: Date | undefined) => console.log("DatePicker onChange:", date))
|
||||
}}
|
||||
selectClass="ml-5 date-picker-trigger" />
|
||||
</>
|
||||
)}
|
||||
<GovSidoSigunguSearchForm
|
||||
isShowPart={true}
|
||||
setRtnEnvPartValue={(val) => setEnoCd?.(val)}
|
||||
setRtnEnvPartSidoValue={(val) => setCtpvCd?.(val)}
|
||||
setRtnEnvPartSigunValue={setSigungu} // 선택된 시군구 값을 받을 콜백 함수 전달
|
||||
>
|
||||
<SelectBox2 label={"하수처리장"} value={selectedSwageTreatmentPlant} selectArray={treatmentFacilityOptions} className="col-span-3" selectClass="rounded-lg bg-white truncate" onSelectValue={(val) => onSwageTreatmentPlantChange?.(val)} />
|
||||
<SelectBox2 label={"하수처리구역"} value={selectedSwageProcessingZone} selectArray={processingZoneOptions} className="col-span-3" selectClass="rounded-lg bg-white truncate" onSelectValue={(val) => onSwageProcessingZoneChange?.(val)} />
|
||||
</GovSidoSigunguSearchForm>
|
||||
{searchBox?.searchChk ? <SearchFormRight><Button onClick={searchBox.onSearchClick}>조회</Button></SearchFormRight> : null}
|
||||
</div>
|
||||
</ListDiv>
|
||||
<ListDiv>
|
||||
<div className="card-header">
|
||||
<h3 className="text-2xl font-medium">{titleName.firstCardTitle}</h3>
|
||||
<div>
|
||||
{graphBtn ? <Button className="px-4 py-2 !mr-[1.2rem] bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700" onClick={isChckFile}>파일 다운로드</Button> : null}
|
||||
{/* 그래프 있을 시 */}
|
||||
{graphBtn ? <Button className="px-4 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700 !mr-[1.2rem]" onClick={isDeleteFile}>삭제</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmitEvent)} className="flex-grow flex flex-col">
|
||||
<div className="card !m-[1.2rem] flex-grow flex flex-col">
|
||||
{/* 폼 정보 입력 칸 */}
|
||||
{children?.[0]}
|
||||
</div>
|
||||
</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="px-4 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700 !mr-[1.2rem]">파일 다운로드</Button> : null}
|
||||
{/* 그래프 있을 시 */}
|
||||
{graphBtn ? <Button className="px-4 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700 !mr-[1.2rem]">삭제</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
<div className="card !m-[1.2rem]">{children?.[1]}</div>
|
||||
</ListDiv> : null
|
||||
}
|
||||
</ContentLayout >
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -196,7 +196,7 @@ const IrSetting = () => {
|
||||
swageTmplntCd: select4.toString(), // 하수처리장코드
|
||||
swtrmtZoneCd: select5.toString(), // 하수처리구역코드
|
||||
aplcnYm: new Date(selectedDate).toISOString().substring(0, 7).replace("-", ""), // 적용연월
|
||||
dtrwSwtcRt: parseFloat(input1) || null, // 오수전환율 (숫자로 변환)
|
||||
drtwSwtcRt: parseFloat(input1) || null, // 오수전환율 (숫자로 변환)
|
||||
anlsInfo: input2, // 분석정보
|
||||
atflCd: file1?.atflCd, // 첨부파일CD (오수관망도)
|
||||
atflId: file1?.atflId, // 첨부파일ID (오수관망도)
|
||||
|
||||
+151
-59
@@ -1,89 +1,181 @@
|
||||
'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 { getData } from '@/components/lib/api'
|
||||
import { UiTable } from '@common/business_components/ui'
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { useState } from 'react'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import FormSection from '@/components/ui/formSection'
|
||||
import { z } from 'zod'
|
||||
import BaseLayout from '../BaseLayout'
|
||||
import { title } from 'process'
|
||||
|
||||
|
||||
interface ApiSelectOption {
|
||||
text: string;
|
||||
val: string;
|
||||
}
|
||||
|
||||
const formSchema = z.object({
|
||||
managenm: z.string(),
|
||||
region: z.string(),
|
||||
suyeonga: z.number(),
|
||||
inputdate: z.coerce.date(),
|
||||
rtkSource: z.string(),
|
||||
suyeongaPlace: z.string()
|
||||
enoCd: z.string().default('0'), // 환경청코드
|
||||
ctpvCd: z.string().default('0'), // 시도코드
|
||||
sggCd: z.object({ // 시군구
|
||||
val: z.string().default('0'),
|
||||
text: z.string().default('전체'),
|
||||
}).default({ val: '0', text: '전체' }),
|
||||
swageTmplntCd: z.string().default('0'), // 하수처리장
|
||||
swtrmtZoneCd: z.string().default('0'), // 하수처리구역
|
||||
aplcnYm: z.date().default(new Date()), // 분석일자 (DatePicker와 연동)
|
||||
})
|
||||
|
||||
type ResultFormValues = z.infer<typeof formSchema>
|
||||
|
||||
// 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: '분석자' }
|
||||
// { id: 'no', title: '번호' },
|
||||
{ id: 'inftwtAnlsSn', title: '분석번호' },
|
||||
{ id: 'swageTmplntNm', title: '하수처리장' },
|
||||
{ id: 'swtrmtZoneNm', title: '처리구역' },
|
||||
{ id: 'aplcnYm', title: '적용연월' },
|
||||
{ id: 'drtwSwtcRt', title: '오수 전환율' },
|
||||
{ id: 'anlsInfo', title: '침입수 분석정보' },
|
||||
{
|
||||
id: 'regDt',
|
||||
title: '분석일자',
|
||||
},
|
||||
{
|
||||
id: 'rgtrNm',
|
||||
title: '분석자',
|
||||
}
|
||||
]
|
||||
const tableColumn2 = [
|
||||
{ id: 'no', title: '번호' },
|
||||
{ id: 'analysis no', title: '분석번호' },
|
||||
{ id: 'hasu', title: '하수처리장' },
|
||||
{ id: 'guyeok', title: '처리구역' },
|
||||
{ id: 'sangsu', title: '상수 사용량' },
|
||||
{ id: 'rate', title: '오수 전환율' },
|
||||
{ id: 'rtx', title: 'RTX계수출처' },
|
||||
{ id: 'rtx', title: 'RTX 계수 출처' },
|
||||
{ id: 'rdii', title: 'RDII 기여면적' },
|
||||
{ id: 'water', title: '순오수량' },
|
||||
{ id: 'measureWater', title: '강우유출량' },
|
||||
{ id: 'ii', title: 'RDII(m2/d)' },
|
||||
{ id: 'rdii analysis info', title: 'RDII 분석정보' },
|
||||
{ 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>>({
|
||||
const form = useForm<ResultFormValues>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
managenm: "",
|
||||
region: "",
|
||||
suyeonga: 0,
|
||||
inputdate: new Date(),
|
||||
rtkSource: "",
|
||||
suyeongaPlace: ""
|
||||
enoCd: '0',
|
||||
ctpvCd: '0',
|
||||
sggCd: { val: '0', text: '전체' },
|
||||
swageTmplntCd: '0',
|
||||
swtrmtZoneCd: '0',
|
||||
aplcnYm: new Date(),
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const [tableData, setTableData] = useState<any[]>([]); // API 조회 결과 저장 상태
|
||||
const [totalData, setTotalData] = useState(0) //총 데이터 수
|
||||
const [rdiiResultData, setRdiiResultData] = useState<any[]>([]); // RDII 결과 저장 상태 (필요시)
|
||||
const [isLoadingResult, setIsLoadingResult] = useState<boolean>(false); // 로딩 상태
|
||||
|
||||
const handleSearchButtonClick = async () => {
|
||||
setIsLoadingResult(true);
|
||||
const formValues = form.getValues(); // react-hook-form에서 현재 값 가져오기
|
||||
|
||||
const inftwtAnlsSearchDto = {
|
||||
"aplcnYm": formValues.aplcnYm.toISOString().substring(0, 7).replace("-", ""),
|
||||
"enoCd": formValues.enoCd === '0' ? null : formValues.enoCd,
|
||||
"ctpvCd": formValues.ctpvCd === '0' ? null : formValues.ctpvCd,
|
||||
"sggCd": formValues.sggCd.val === '0' ? null : formValues.sggCd.val,
|
||||
// "swageTmplntCd": formValues.swageTmplntCd === '0' ? null : formValues.swageTmplntCd,
|
||||
"swtrmtZoneCd": formValues.swtrmtZoneCd === '0' ? null : formValues.swtrmtZoneCd,
|
||||
};
|
||||
|
||||
const queryParams = new URLSearchParams({
|
||||
page: '0',
|
||||
size: '10',
|
||||
sort: 'inftwtAnlsSn'
|
||||
});
|
||||
Object.entries(inftwtAnlsSearchDto).forEach(([key, value]) => {
|
||||
if (value !== undefined && value !== null && String(value).trim() !== '') { // undefined, null, 빈 문자열이 아닌 경우에만 추가
|
||||
queryParams.append(key, String(value));
|
||||
}
|
||||
});
|
||||
const queryString = queryParams.toString();
|
||||
|
||||
console.log("API: ", `v1/inftwtAnls${queryString ? `?${queryString}` : ''}`); // 디버깅용 로그
|
||||
try {
|
||||
const data = await getData(`v1/inftwtAnls${queryString ? `?${queryString}` : ''}`);
|
||||
setTableData(data.content || []);
|
||||
setTotalData(tableData.length);
|
||||
console.log("response:", data);
|
||||
console.log("response data:", data.content || []);
|
||||
} catch (error) {
|
||||
console.error("Error fetching analysis result data:", error);
|
||||
alert("분석결과 조회 중 오류가 발생했습니다.");
|
||||
setTableData([]);
|
||||
setTotalData(0);
|
||||
} finally {
|
||||
setIsLoadingResult(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<BaseLayout searchBox={{labelNm: {first: "분석기간",second: "분석구분",third: "하수처리장",fourth: "하수처리구역",},searchChk: true,}} titleName={{ mainTitle: '분석결과', firstCardTitle: '분석이력', secondCardTitle:'RDII 산정결과 현황'}} form={form} onSubmitEvent={() => { }} graphBtn={true}>
|
||||
{[<div key='table1'>
|
||||
<BaseLayout
|
||||
searchBox={{ title: '분석 대상지역 선택', searchChk: true, onSearchClick: handleSearchButtonClick }}
|
||||
titleName={{ mainTitle: '분석결과', firstCardTitle: '분석이력', secondCardTitle: 'RDII 산정결과 현황' }}
|
||||
form={form} // form 인스턴스 전달
|
||||
onSubmitEvent={() => { }} // BaseLayout의 form 태그에 연결될 onSubmit
|
||||
graphBtn={true}
|
||||
showDatePicker={true}
|
||||
enoCd={form.watch("enoCd")}
|
||||
setEnoCd={(val) => form.setValue("enoCd", val)}
|
||||
ctpvCd={form.watch("ctpvCd")}
|
||||
setCtpvCd={(val) => form.setValue("ctpvCd", val)}
|
||||
sigungu={form.watch("sggCd")}
|
||||
setSigungu={(val) => form.setValue("sggCd", val)}
|
||||
selectedSwageTreatmentPlant={form.watch("swageTmplntCd")}
|
||||
onSwageTreatmentPlantChange={(val) => form.setValue("swageTmplntCd", String(val))}
|
||||
selectedSwageProcessingZone={form.watch("swtrmtZoneCd")}
|
||||
onSwageProcessingZoneChange={(val) => form.setValue("swtrmtZoneCd", String(val))}
|
||||
aplcnYm={form.watch("aplcnYm")}
|
||||
setAplcnYm={(val) => {
|
||||
if (val instanceof Date) {
|
||||
form.setValue("aplcnYm", val)
|
||||
} else if (val) {
|
||||
form.setValue("aplcnYm", new Date(val))
|
||||
}
|
||||
}}
|
||||
// DatePicker는 BaseLayout 내부에서 form.watch("aplcnYm")과 form.setValue("aplcnYm", ...)을 사용하도록 수정 필요
|
||||
>
|
||||
{[<div key='table1' className="h-[55vh] flex flex-col p-4 border rounded-lg bg-white shadow-md">
|
||||
<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 className="flex-grow overflow-auto">
|
||||
<UiTable
|
||||
headName=''
|
||||
headlist={tableColumn}
|
||||
tableData={tableData}
|
||||
total={totalData}
|
||||
pageSize={10}
|
||||
children={undefined}
|
||||
cellClick={(e) => { }}
|
||||
onPageChange={(e) => { }}
|
||||
/>
|
||||
</div>
|
||||
</div>,
|
||||
<div key='table2'>
|
||||
<UiTable
|
||||
headName=''
|
||||
headlist={tableColumn2}
|
||||
tableData={[]}
|
||||
total={0}
|
||||
pageSize={10}
|
||||
children={undefined}
|
||||
cellClick={(e) => { }}
|
||||
onPageChange={(e) => { }}
|
||||
/>
|
||||
</div>
|
||||
]}
|
||||
// <div key='table2'>
|
||||
// <UiTable
|
||||
// headName=''
|
||||
// headlist={tableColumn2}
|
||||
// tableData={rdiiResultData}
|
||||
// total={rdiiResultData.length}
|
||||
// pageSize={10}
|
||||
// children={undefined}
|
||||
// cellClick={(e) => { }}
|
||||
// onPageChange={(e) => { }}
|
||||
// />
|
||||
// </div>
|
||||
]}
|
||||
</BaseLayout>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,11 @@ import Ssc from "../popupComponent/Ssc";
|
||||
import StormWaterPump from "../popupComponent/stormWaterPump";
|
||||
import SwtrmtFclt from "../popupComponent/SwtrmtFclt";
|
||||
|
||||
type LayerComponentProps = { featureData: any; chkMainSsc?: boolean };
|
||||
type LayerComponentProps = {
|
||||
featureData: any;
|
||||
chkMainSsc?: boolean;
|
||||
additionalData?: any;
|
||||
};
|
||||
type LayerContentMap = {
|
||||
[key: string]: {
|
||||
component?: React.FC<LayerComponentProps>;
|
||||
@@ -16,9 +20,7 @@ type LayerContentMap = {
|
||||
// 레이어 선택시 변경되는 팝업 컨텐츠 동적으로 변경하도록 작업
|
||||
const layerContentMap: LayerContentMap = {
|
||||
// TODO: gis데이터 추가되면 추가 작업 필요
|
||||
"하수처리시설": {
|
||||
component: SwtrmtFclt,
|
||||
},
|
||||
"하수처리시설": { component: SwtrmtFclt, },
|
||||
"하수처리구역": { },
|
||||
"우수토실":{component: Ssc,},
|
||||
"중점우수토실":{component: Ssc, }, // 중점우수토실 여부 설정
|
||||
|
||||
@@ -48,7 +48,7 @@ export const SwtrmtPrcsZoneCol = [
|
||||
// { id: 'sggCd', title: '시군구코드' },
|
||||
{ id: 'sggNm', title: '시군구명' },
|
||||
{ id: 'swtrmtFcltNm', title: '하수처리시설명' },
|
||||
]
|
||||
];
|
||||
|
||||
// 하수맨홀
|
||||
export const MsSwageMhlCol = [
|
||||
@@ -70,4 +70,59 @@ export const MsSwageMhlCol = [
|
||||
// { id: 'mqltCd', title: '재질코드' },
|
||||
{ id: 'altdVl', title: '표고값' },
|
||||
{ id: 'dpthlVl', title: '심도값' },
|
||||
{ id: 'instMngNo', title:'기관관리번호'}]
|
||||
{ id: 'instMngNo', title:'기관관리번호'}
|
||||
];
|
||||
|
||||
// 중점우수토실 측정지점
|
||||
export const untrtSwgRainCol1 = [
|
||||
{ id: 'manage_no', title: '관리번호' },
|
||||
{ id: 'swr_ppl_eqp_nm', title: '처리구역' },
|
||||
{ id: 'swr_ppl_trt_nm', title: '처리분구' },
|
||||
{ id: 'addr', title: '인근주소' },
|
||||
{ id: 'chmbr_xcnts', title: '토실 위도' },
|
||||
{ id: 'chmbr_ydnts', title: '토실 경도' }
|
||||
];
|
||||
|
||||
// 중점우수토실 측정지점 시설현황
|
||||
export const untrtSwgRainCol2 = [
|
||||
{ id: 'flwmtr_mesure_tp_etc', title: '구분' },
|
||||
{ id: 'discharge_pipe_spec', title: '방류관로 규격' },
|
||||
{ id: 'swr_ppl_eqp_ar', title: '배수구역 면적(m²)' },
|
||||
{ id: 'swr_trt_popl', title: '하수처리 인구(인)' },
|
||||
{ id: 'screen_instl_at', title: '스크린설치 여부' },
|
||||
{ id: 'weir_hg', title: '위어 높이(m)' },
|
||||
{ id: 'weir_lt', title: '위어 길이(m)' }
|
||||
];
|
||||
|
||||
// 중점우수토실 강우정보 (id값 틀릴 수 있음)
|
||||
export const untrtSwgRainCol3 = [
|
||||
{ id: 'rain_begin_dt', title: '강우시작일시' },
|
||||
{ id: 'rain_end_dt', title: '강우종료일시' },
|
||||
{ id: 'precdng_dry', title: '선행건기(h)' },
|
||||
{ id: 'rain_info', title: '강우정보' },
|
||||
{ id: 'rain_fall', title: '누적강우량(mm)' },
|
||||
{ id: 'cntnc_time', title: '지속시간(h)' },
|
||||
{ id: 'rain_in', title: '강우강도(mm/h)' }
|
||||
];
|
||||
|
||||
// 중점우수토실 측정정보 (id값 틀릴 수 있음)
|
||||
export const untrtSwgRainCol4 = [
|
||||
{ id: 'mesure_begin_dt', title: '측정시작일시' },
|
||||
{ id: 'mesure_end_dt', title: '측정종료일시' },
|
||||
{ id: 'mesure_intrvl', title: '측정간격(분)' },
|
||||
{ id: 'mesure_mhrls_instl_lc', title: '측정기기 설치위치' },
|
||||
{ id: 'flwmtr_combined', title: '유량계 종류 및 모델명' }, // 합쳐진 컬럼
|
||||
{ id: 'qltwtr_begin_dt', title: '채수시작일시' },
|
||||
{ id: 'qltwtr_end_dt', title: '채수종료일시' },
|
||||
{ id: 'qltwtr_co', title: '채수횟수' }
|
||||
];
|
||||
|
||||
// 중점우수토실 수량/수질측정 정보
|
||||
export const untrtSwgRainCol5 = [
|
||||
{ id: 'odr', title: '회차' },
|
||||
{ id: 'mesureDt', title: '측정일자' },
|
||||
{ id: 'mesureQy', title: '수량(m)' },
|
||||
{ id: 'mesureBod', title: 'BOD(mg/L)' },
|
||||
{ id: 'mesureToc', title: 'TOC(mg/L)' },
|
||||
{ id: 'mesureLoad', title: '오염부하량(kg)' }
|
||||
];
|
||||
@@ -1,18 +1,16 @@
|
||||
// 우수토실
|
||||
import Modal from '@/components/ui/modal';
|
||||
import { VerticalTable } from '@/components/ui/verticalTable';
|
||||
import { UiTable } from '@common/business_components/ui';
|
||||
import { UiModal, UiTable } from '@common/business_components/ui';
|
||||
import { Button, TableHead, TableRow } from '@common/components/ui';
|
||||
import React from 'react'
|
||||
const inputColumn = [
|
||||
{ id: "swtrmt_zone_cd", title: "처리구역", type: "input" },
|
||||
{ id: "mainSscYn", title: "중점우수토실 대상여부", type: "select", options: ['Y', 'N'] },
|
||||
];
|
||||
const headlist = [
|
||||
{ id: 'startrain', title: '강우시작일시' }, { id: 'endrain', title: '강우종료일시' }, { id: '선행건기', title: '선행건기(h)' }, { id: '강우정보', title: '강우정보' }, { id: '누적강우량', title: '누적강우량(mm)' }, { id: '지속시간', title: '지속시간(h)' }, { id: '강우강도', title: '강우강도(mm/h)' },
|
||||
]
|
||||
const headlist3 = [{ id: 'nm', title: '회차' }, { id: 'date', title: '측정일자' }, { id: 'measure', title: '수량(m)' }, { id: 'bod', title: 'BOD(mg/L)' }, { id: 'toc', title: 'TOC(mg/L)' }, { id: '오염부하량', title: '오염부하량(kg)' }]
|
||||
const Ssc = ({ featureData, chkMainSsc }: { featureData: any, chkMainSsc?: boolean}) => {
|
||||
import React from 'react';
|
||||
import { untrtSwgRainCol3, untrtSwgRainCol4, untrtSwgRainCol5 } from '../common/table';
|
||||
|
||||
const Ssc = ({ featureData, chkMainSsc, additionalData }: {
|
||||
featureData: any,
|
||||
chkMainSsc?: boolean,
|
||||
additionalData?: any
|
||||
}) => {
|
||||
console.log('Additional data received:', additionalData); // 추가 데이터 확인용
|
||||
|
||||
const [isModalOpen, setIsModalOpen] = React.useState(false);
|
||||
const openModal = () => {
|
||||
setIsModalOpen(true);
|
||||
@@ -20,45 +18,120 @@ const Ssc = ({ featureData, chkMainSsc }: { featureData: any, chkMainSsc?: boole
|
||||
const closeModal = () => {
|
||||
setIsModalOpen(false);
|
||||
};
|
||||
|
||||
// 데이터 전처리: 합쳐진 필드 추가
|
||||
const preprocessedData = featureData ? [{
|
||||
...featureData,
|
||||
flwmtr_combined: `${featureData.flwmtr_mesure_tp_etc || '-'} / ${featureData.flwmtr_knd || '-'}`
|
||||
}] : [];
|
||||
|
||||
const renderModalBody = () => (
|
||||
<div className='grid grid-cols-1 gap-4 p-4'>
|
||||
{/* 강우정보 테이블 */}
|
||||
<UiTable
|
||||
headName='강우정보'
|
||||
tableData={preprocessedData}
|
||||
headlist={untrtSwgRainCol3}
|
||||
pageSize={10}
|
||||
total={0}
|
||||
children={undefined}
|
||||
cellClick={undefined}
|
||||
onPageChange={function (page: number): void {
|
||||
console.log('Rain data page change:', page);
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 측정정보 테이블 */}
|
||||
<UiTable
|
||||
headName='측정정보'
|
||||
tableData={preprocessedData}
|
||||
headlist={untrtSwgRainCol4}
|
||||
pageSize={10}
|
||||
total={0}
|
||||
cellClick={undefined}
|
||||
onPageChange={function (page: number): void {
|
||||
console.log('Measure data page change:', page);
|
||||
}}
|
||||
>
|
||||
{/* 커스텀 헤더 */}
|
||||
<TableRow>
|
||||
<TableHead colSpan={5} className="text-center bg-blue-100 font-bold">수량</TableHead>
|
||||
<TableHead colSpan={3} className="text-center bg-blue-100 font-bold">수질</TableHead>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead className="text-center">측정시작일시</TableHead>
|
||||
<TableHead className="text-center">측정종료일시</TableHead>
|
||||
<TableHead className="text-center">측정간격(분)</TableHead>
|
||||
<TableHead className="text-center">측정기기설치위치</TableHead>
|
||||
<TableHead className="text-center">유량계 종류 및 모델명</TableHead>
|
||||
<TableHead className="text-center">채수시작일시</TableHead>
|
||||
<TableHead className="text-center">채수종료일시</TableHead>
|
||||
<TableHead className="text-center">채수횟수</TableHead>
|
||||
</TableRow>
|
||||
</UiTable>
|
||||
|
||||
{/* 수량/수질측정 정보 테이블 */}
|
||||
<UiTable
|
||||
headName='수량/수질측정 정보'
|
||||
tableData={additionalData}
|
||||
headlist={untrtSwgRainCol5}
|
||||
pageSize={10}
|
||||
total={additionalData.length}
|
||||
children={undefined}
|
||||
cellClick={undefined}
|
||||
onPageChange={function (page: number): void {
|
||||
console.log('Quality data page change:', page);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div><VerticalTable headName='자체 입력정보' tableData={[]} headlist={inputColumn} pageSize={0} total={0} children={undefined} cellClick={undefined} isEditable={true} onPageChange={function (page: number): void {
|
||||
throw new Error('Function not implemented.');
|
||||
}} />{!chkMainSsc ? null :
|
||||
<div>
|
||||
<div className="card-header">
|
||||
<h3 className="text-2xl mx-3 font-medium text-label">중점우수토실 운영정보</h3>
|
||||
<div>
|
||||
{/* <VerticalTable
|
||||
headName='자체 입력정보'
|
||||
tableData={[]}
|
||||
headlist={inputColumn}
|
||||
pageSize={0}
|
||||
total={0}
|
||||
children={undefined}
|
||||
cellClick={undefined}
|
||||
isEditable={true}
|
||||
onPageChange={function (page: number): void {
|
||||
throw new Error('Function not implemented.');
|
||||
}}
|
||||
/> */}
|
||||
|
||||
{!chkMainSsc ? null :
|
||||
<div>
|
||||
<div className="card-header">
|
||||
<h3 className="text-2xl mx-3 font-medium text-label">중점우수토실 운영정보</h3>
|
||||
</div>
|
||||
<Button
|
||||
className='mx-auto block w-64 mt-3 py-2 text-white rounded-sm text-sm font-medium hover:bg-blue-700 bg-blue-600'
|
||||
onClick={openModal}
|
||||
>
|
||||
상세보기
|
||||
</Button>
|
||||
|
||||
<UiModal
|
||||
open={isModalOpen}
|
||||
onOpenChange={setIsModalOpen}
|
||||
bodyClass={`
|
||||
h-[100vh]
|
||||
w-[60vw]
|
||||
max-w-none
|
||||
max-h-none
|
||||
overflow-visible
|
||||
z-[101]
|
||||
`}
|
||||
body={renderModalBody()}
|
||||
noHeaderYn='Y'
|
||||
noFooterYn='N'
|
||||
// footerContent={renderFooterContent()}
|
||||
/>
|
||||
</div>
|
||||
<Button className='mx-auto block w-64 mt-3 py-2 text-white rounded-sm text-sm font-medium hover:bg-blue-700 bg-blue-600' onClick={openModal}>상세보기</Button>
|
||||
<Modal isModalOpen={isModalOpen} setIsModalOpen={setIsModalOpen} closeModal={closeModal}>
|
||||
<div className='grid grid-col-3'><UiTable headName='강우정보' tableData={[]} headlist={headlist} pageSize={0} total={0} children={undefined} cellClick={undefined} onPageChange={function (page: number): void {
|
||||
throw new Error('Function not implemented.');
|
||||
}}></UiTable>
|
||||
<UiTable headName='측정정보' tableData={[]} headlist={[]} pageSize={0} total={0} cellClick={undefined} onPageChange={function (page: number): void {
|
||||
throw new Error('Function not implemented.');
|
||||
}}> {/* 커스텀 헤더 */}
|
||||
<TableRow>
|
||||
<TableHead colSpan={5} className="text-center bg-blue-100 font-bold">
|
||||
수량
|
||||
</TableHead>
|
||||
<TableHead colSpan={3} className="text-center bg-blue-100 font-bold">
|
||||
수질
|
||||
</TableHead>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead className="text-center">측정시작일시</TableHead>
|
||||
<TableHead className="text-center">측정종료일시</TableHead>
|
||||
<TableHead className="text-center">측정간격(분)</TableHead>
|
||||
<TableHead className="text-center">측정기기설치위치</TableHead>
|
||||
<TableHead className="text-center">유량계 종류 및 모델명</TableHead>
|
||||
<TableHead className="text-center">채수시작일시</TableHead>
|
||||
<TableHead className="text-center">채수종료일시</TableHead>
|
||||
<TableHead className="text-center">채수횟수</TableHead>
|
||||
</TableRow></UiTable>
|
||||
<UiTable headName='수량/수질측정 정보' tableData={[]} headlist={headlist3} pageSize={0} total={0} children={undefined} cellClick={undefined} onPageChange={function (page: number): void {
|
||||
throw new Error('Function not implemented.');
|
||||
}}></UiTable></div>
|
||||
</Modal>
|
||||
</div>}
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
'use client'
|
||||
import { VerticalTable } from "@/components/ui/verticalTable";
|
||||
import { Button, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@common/components/ui";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { SwtrmtFcltCol, SwtrmtPrcsZoneCol } from "./components/common/table";
|
||||
import { useGisContext } from "@common/business_components/ui/map/Gis";
|
||||
import { getData, putData } from "@/components/lib/api";
|
||||
import { getLayerContentComponent } from "./components/common";
|
||||
import Modal from "@/components/ui/modal";
|
||||
import { VerticalTable } from "@/components/ui/verticalTable";
|
||||
import { useGisContext } from "@common/business_components/ui/map/Gis";
|
||||
import { Button } from "@common/components/ui";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { getLayerContentComponent } from "./components/common";
|
||||
import { SwtrmtFcltCol, SwtrmtPrcsZoneCol, untrtSwgRainCol1, untrtSwgRainCol2 } from "./components/common/table";
|
||||
// TODO:
|
||||
const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void, featureData: any }) => {
|
||||
const { gisMap } = useGisContext() as unknown as { checkedLayerIds: React.MutableRefObject<number[]>; treeData: { lyrSn: number }[] | null; gisCore: any; gisMap: any; };
|
||||
@@ -15,13 +15,16 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
|
||||
? featureData.getId()
|
||||
: featureData.fid;
|
||||
const [layerNm, setLayerNm] = useState<string>(""); // 레이어 이름 상태
|
||||
const [tableData, setTableData] = useState<any>(null); // 피처 데이터 상태
|
||||
const [tableData, setTableData] = useState<any>(null); // 피처 데이터
|
||||
const [mntrngsData, setMntrngsData] = useState(false); // 수량/수질 측정 정보
|
||||
const [headlist, setHeadlist] = useState<{ id: string; title: string; }[]>([]); // 컬럼리스트 변경상태
|
||||
const [headlist2, setHeadlist2] = useState<{ id: string; title: string; }[]>([]); // 컬럼리스트 변경상태
|
||||
const [buttonChk, setButtonChk] = useState(true)
|
||||
const [fetchData, setfetchData] = useState<any>(); // api 호출여부
|
||||
const contentRef = useRef<HTMLDivElement>(null);
|
||||
const [isModalOpen, setIsModalOpen] = useState(false); // 모달 열기 상태
|
||||
const [chkMainSsc, setChkMainSsc] = useState(false); // 중점우수토실 여부
|
||||
|
||||
// 피쳐데이터의 현재 레이어 이름 가져오는 함수
|
||||
const getSelectedLayers = () => {
|
||||
let result = null;
|
||||
@@ -38,19 +41,21 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
|
||||
if (featureLayer.get('lyrNm') === null) {
|
||||
if (featureData.lyrTypeNm === 'tb_il_swage_prcs_fclt') result = '하수처리시설';
|
||||
else if (featureData.lyrTypeNm === 'tb_ms_swage_prcs_zone') result = '하수처리구역';
|
||||
else if (featureData.lyrTypeNm === 'om_dt_untrt_swg_rain') result = '중점우수토실';
|
||||
}
|
||||
else result = featureLayer.get('lyrNm');
|
||||
|
||||
|
||||
return result;
|
||||
// return featureLayer.get('lyrNm'); // 레이어 이름 출력
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
if (featureId) {
|
||||
const selectedLayerName = getSelectedLayers(); // 레이어 이름 가져오기
|
||||
setLayerNm(selectedLayerName); // 상태 업데이트
|
||||
const layerId = featureId.split('.')[0]
|
||||
const data = await getData(`v1/fclts/${featureId}?lyrTypeNm=${layerId}`);
|
||||
let data = await getData(`v1/fclts/${featureId}?lyrTypeNm=${layerId}`);
|
||||
setfetchData(data)
|
||||
switch (selectedLayerName) {
|
||||
case '하수처리시설':
|
||||
@@ -62,8 +67,20 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
|
||||
setButtonChk(false)
|
||||
break;
|
||||
case '중점우수토실':
|
||||
setHeadlist(untrtSwgRainCol1)
|
||||
setHeadlist2(untrtSwgRainCol2)
|
||||
setButtonChk(false)
|
||||
setChkMainSsc(true)
|
||||
|
||||
// 데이터 전처리: 합쳐진 필드 추가
|
||||
data = data ? {
|
||||
...data,
|
||||
discharge_pipe_spec: `직경: ${data.pipe_diameter || '-'} / 높이: ${data.pipe_hg || '-'} / 길이: ${data.pipe_lt || '-'}`
|
||||
} : {};
|
||||
|
||||
// 수량/수질측정 정보 데이터 호출
|
||||
const additionalResponse = await getData(`v1/onsemiro/swgRain/${data.adst_dstr_cd}/${data.manage_no}/mntrngs`);
|
||||
setMntrngsData(additionalResponse.content);
|
||||
break;
|
||||
case '우수토실':
|
||||
setButtonChk(true)
|
||||
@@ -88,25 +105,29 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
|
||||
}
|
||||
fetchData();
|
||||
}, [featureId]);
|
||||
|
||||
// 저장 시 모달 띄우기
|
||||
const handleSaveClick = () => {
|
||||
setIsModalOpen(true); // 모달 열기
|
||||
};
|
||||
|
||||
const handleModalSave = () => {
|
||||
setIsModalOpen(false); // 모달 닫기
|
||||
btnClickEvent(); // 저장 이벤트 실행
|
||||
};
|
||||
|
||||
const handleModalClose = () => {
|
||||
setIsModalOpen(false); // 모달 닫기
|
||||
};
|
||||
const btnClickEvent = async() => {
|
||||
|
||||
const btnClickEvent = async () => {
|
||||
const bodyData: Record<string, any> = {}
|
||||
if (buttonChk && contentRef.current) {
|
||||
const inputElements = contentRef.current.querySelectorAll('input');
|
||||
const selectElements = contentRef.current.querySelectorAll('select');
|
||||
// 카멜케이스 변환 함수
|
||||
const toCamelCase = (str: string) =>
|
||||
str.replace(/_([a-z])/g, (_, char) => char.toUpperCase());
|
||||
// 카멜케이스 변환 함수
|
||||
const toCamelCase = (str: string) =>
|
||||
str.replace(/_([a-z])/g, (_, char) => char.toUpperCase());
|
||||
// select 태그의 값 가져오기
|
||||
selectElements.forEach((select) => {
|
||||
const camelCaseId = toCamelCase(select.id);
|
||||
@@ -121,19 +142,19 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
|
||||
else if (layerNm === '우수토실') bodyData['lyrTypeNm'] = 'tb_ms_stofcbr'
|
||||
else if (layerNm === '오수펌프') bodyData['lyrTypeNm'] = 'tb_ms_swage_pmstn'
|
||||
else if (layerNm === '빗물펌프') bodyData['lyrTypeNm'] = 'tb_ms_swage_pmstn'
|
||||
else if(layerNm === '하수맨홀')bodyData['lyrTypeNm'] = 'tb_ms_swage_mnhl'
|
||||
else if (layerNm === '하수맨홀') bodyData['lyrTypeNm'] = 'tb_ms_swage_mnhl'
|
||||
bodyData['fid'] = featureId
|
||||
const data = await putData(`v1/fclts/${featureId}`, bodyData);
|
||||
if(data.status==200){
|
||||
alert('저장되었습니다')
|
||||
setTableData(data)
|
||||
setfetchData(data)
|
||||
if (data.status == 200) {
|
||||
alert('저장되었습니다')
|
||||
setTableData(data)
|
||||
setfetchData(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
const ContentComponent = layerNm ? getLayerContentComponent(layerNm) : null;
|
||||
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-[200]">
|
||||
<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-[50]">
|
||||
<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">{layerNm} 정보</h3>
|
||||
@@ -148,16 +169,40 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
|
||||
</button>
|
||||
</div>
|
||||
<div className="overflow-y-auto overflow-x-hidden flex-1" ref={contentRef}>
|
||||
<VerticalTable headName='LX 연계정보' tableData={[tableData]} headlist={headlist} pageSize={20} total={0} children={undefined} cellClick={undefined} onPageChange={function (page: number): void {
|
||||
throw new Error("Function not implemented.");
|
||||
}}></VerticalTable>
|
||||
<VerticalTable
|
||||
headName='LX 연계정보'
|
||||
tableName1={layerNm === '중점우수토실' ? "측정지점" : undefined}
|
||||
tableData={[tableData]}
|
||||
headlist={headlist}
|
||||
pageSize={20}
|
||||
total={0}
|
||||
children={undefined}
|
||||
cellClick={undefined}
|
||||
onPageChange={function (page: number): void {
|
||||
throw new Error("Function not implemented.");
|
||||
}}
|
||||
// 두 번째 테이블 조건부 props
|
||||
showSecondTable={layerNm === '중점우수토실' ? true : false}
|
||||
tableName2={layerNm === '중점우수토실' ? "시설현황" : undefined}
|
||||
tableData2={layerNm === '중점우수토실' && tableData ? [tableData] : []}
|
||||
headlist2={layerNm === '중점우수토실' ? headlist2 : undefined}
|
||||
pageSize2={20}
|
||||
total2={0}
|
||||
isEditable2={buttonChk}
|
||||
/>
|
||||
<div className="w-full mx-5 flex items-center justify-end space-x-2">
|
||||
{buttonChk ? <Button onClick={handleSaveClick} className="px-4 mr-5 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700">
|
||||
저장
|
||||
</Button> : null}
|
||||
</div>
|
||||
<Modal isModalOpen={isModalOpen} title="자체입력정보 저장" setIsModalOpen={setIsModalOpen} closeModal={handleModalClose} saveModal={handleModalSave}><div className="text-lg">정보를 저장하시겠습니까?</div></Modal>
|
||||
{ContentComponent && <ContentComponent featureData={fetchData} chkMainSsc={chkMainSsc} />}
|
||||
{ContentComponent &&
|
||||
<ContentComponent
|
||||
featureData={fetchData}
|
||||
chkMainSsc={chkMainSsc}
|
||||
additionalData={mntrngsData}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user