Merge remote-tracking branch 'origin/iipbs/sn/dev' into iipbs/sn/search
iipbs_sn / build (push) Waiting to run
iipbs_sn / build (push) Waiting to run
This commit is contained in:
@@ -7,13 +7,14 @@ import React, { useState } from 'react'
|
||||
const FileUploadForm = ({ title }: { title: string }) => {
|
||||
const [files, setFiles] = useState<File[] | null>(null);
|
||||
const [selectedYear, setSelectedYear] = useState<string>('');
|
||||
const [selectedQuarter, setSelectedQuarter] = useState<string>('');
|
||||
|
||||
// 현재 년도부터 10년 전까지의 년도 옵션 생성
|
||||
const yearOptions = Array.from({ length: 10 }, (_, i) => {
|
||||
const year = new Date().getFullYear() - i;
|
||||
return { text: `${year}년`, val: year.toString() };
|
||||
});
|
||||
|
||||
const quater = [{text: '1분기', val: '1'}, {text: '2분기', val: '2'}, {text: '3분기', val: '3'}, {text: '4분기', val: '4'}]
|
||||
return (
|
||||
<div>
|
||||
<div className='card-header'>
|
||||
@@ -32,8 +33,8 @@ const FileUploadForm = ({ title }: { title: string }) => {
|
||||
className="w-50"
|
||||
selectClass="rounded-lg bg-white"
|
||||
label="분기"
|
||||
selectArray={yearOptions}
|
||||
onSelectValue={(value: string | number) => setSelectedYear(String(value))}
|
||||
selectArray={quater}
|
||||
onSelectValue={(value: string | number) => setSelectedQuarter(String(value))}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex mt-5 items-center'>
|
||||
@@ -44,7 +45,7 @@ const FileUploadForm = ({ title }: { title: string }) => {
|
||||
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) {
|
||||
if (!files?.[0] || !selectedYear || !selectedQuarter) {
|
||||
alert('파일과 등록년도를 선택해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ const Modal: React.FC<ModalProps> = ({ isModalOpen, setIsModalOpen, title, child
|
||||
return (
|
||||
<Dialog open={isModalOpen} onOpenChange={setIsModalOpen}>
|
||||
<DialogOverlay className='z-[200]'/>
|
||||
<DialogContent className="w-auto max-w-[1200px] h-auto max-h-[450px] overflow-auto z-[1000]">
|
||||
<DialogContent className="w-auto max-w-[1200px] min-w-[400px] min-h-[300px] h-auto max-h-[450px] overflow-auto z-[1000]">
|
||||
{title ? <DialogHeader>
|
||||
<DialogTitle>{title}</DialogTitle>
|
||||
</DialogHeader> : null}
|
||||
|
||||
@@ -8,7 +8,7 @@ type UiTableProps = {
|
||||
headlist: UiHeadProps[];
|
||||
pageSize: number;
|
||||
total: number;
|
||||
children: React.ReactNode | undefined;
|
||||
children: Record<string, React.ReactNode> | undefined;
|
||||
cellClick: ((index: number | undefined, headId: string) => void) | undefined;
|
||||
onPageChange: (page: number) => void;
|
||||
className?: string;
|
||||
@@ -82,7 +82,7 @@ export function VerticalTable({
|
||||
</TableCell>
|
||||
{/* 데이터 값 또는 입력 필드 */}
|
||||
<TableCell className="text-xs">
|
||||
{isEditable ? (
|
||||
{children && children[head.id] ? children[head.id] : isEditable ? (
|
||||
head.type === "select" ? (
|
||||
<select
|
||||
value={formData[head.id] ?? "-"}
|
||||
|
||||
@@ -10,14 +10,14 @@ type TitleName = {
|
||||
secondCardTitle?: string
|
||||
}
|
||||
type SelectBox = {
|
||||
labelNm?:Label
|
||||
searchChk?:boolean
|
||||
labelNm?: Label
|
||||
searchChk?: boolean
|
||||
}
|
||||
type Label= {
|
||||
type Label = {
|
||||
first: string
|
||||
second: string
|
||||
third:string
|
||||
fourth:string
|
||||
third: string
|
||||
fourth: string
|
||||
}
|
||||
type BaseLayout = {
|
||||
children?: ReactNode[]
|
||||
@@ -25,8 +25,8 @@ type BaseLayout = {
|
||||
form: any
|
||||
onSubmitEvent: Function
|
||||
graphBtn?: boolean
|
||||
firstDivBtn?:boolean
|
||||
searchBox?:SelectBox
|
||||
firstDivBtn?: boolean
|
||||
searchBox?: SelectBox
|
||||
}
|
||||
// TODO: 나중에 이벤트 추가되면 파라미터 추가 필요 ?
|
||||
/**
|
||||
@@ -38,7 +38,7 @@ type BaseLayout = {
|
||||
* @param graphBtn : 하단에 그래프 버튼 유무 처리
|
||||
* @returns
|
||||
*/
|
||||
const BaseLayout = ({ children,titleName, form, onSubmitEvent, graphBtn=false, searchBox }: BaseLayout) => {
|
||||
const BaseLayout = ({ children, titleName, form, onSubmitEvent, graphBtn = false, searchBox }: BaseLayout) => {
|
||||
return (
|
||||
<ContentLayout title={titleName.mainTitle}>
|
||||
<SearchDiv>
|
||||
@@ -70,7 +70,12 @@ const BaseLayout = ({ children,titleName, form, onSubmitEvent, graphBtn=false, s
|
||||
</ListDiv>
|
||||
{children?.[1] != null ? <ListDiv>
|
||||
<div className="card-header flex items-center justify-between">
|
||||
<h3 className="text-2xl font-medium">{titleName.secondCardTitle}</h3>
|
||||
<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}
|
||||
|
||||
@@ -33,7 +33,7 @@ const IrSetting = () => {
|
||||
<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"} />
|
||||
<Input id="managenm" className="h-[3.2rem] text-center text-xl w-[150px]" />
|
||||
</FormSection>
|
||||
<FormSection name='region' form={form} titleNm='○ 파일위치'>
|
||||
<div className="w-[150px]">
|
||||
@@ -48,7 +48,7 @@ const IrSetting = () => {
|
||||
<FormSection name='suyeonga' form={form} titleNm='○ 수용가-맨홀 매칭결과'><div className="w-[150px]">
|
||||
<Input id="fileNm" type="file" />
|
||||
</div></FormSection>
|
||||
<FormSection name='inputdate' form={form} titleNm='○ 실수사용량 적용기간'>
|
||||
<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>
|
||||
|
||||
@@ -138,7 +138,7 @@ export default function RTKForm() {
|
||||
<FormSection name="regopm" form={form} titleNm="○ 수용가-맨홀 매칭결과"><div className="w-[150px]">
|
||||
<Input id="fileNm2" type="file" />
|
||||
</div></FormSection>
|
||||
<FormSection name='date' form={form} titleNm='○ 실수사용량 적용기간'>
|
||||
<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>
|
||||
|
||||
@@ -29,6 +29,20 @@ const tableColumn = [
|
||||
{ id: 'date', title: '분석일자' },
|
||||
{ id: 'usr', title: '분석자' }
|
||||
]
|
||||
const tableColumn2 = [
|
||||
{ id: 'no', title: '번호' },
|
||||
{ id: 'hasu', title: '하수처리장' },
|
||||
{ id: 'guyeok', title: '처리구역' },
|
||||
{ id: 'sangsu', title: '상수 사용량' },
|
||||
{ id: 'rate', title: '오수 전환율' },
|
||||
{ id: 'rtx', title: 'RTX계수출처' },
|
||||
{ id: 'rdii', title: 'RDII 기여면적' },
|
||||
{ id: 'water', title: '순오수량' },
|
||||
{ id: 'measureWater', title: '강우유출량' },
|
||||
{ id: 'ii', title: 'RDII(m2/d)' },
|
||||
{ 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>>({
|
||||
@@ -43,7 +57,7 @@ const Result = () => {
|
||||
}
|
||||
})
|
||||
return (
|
||||
<BaseLayout searchBox={{labelNm: {first: "분석기간",second: "침입수",third: "처리장",fourth: "처리구역",},searchChk: true,}} titleName={{ mainTitle: '분석결과', firstCardTitle: '분석이력' }} 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
|
||||
@@ -56,7 +70,20 @@ const Result = () => {
|
||||
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>
|
||||
]}
|
||||
</BaseLayout>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,21 +1,34 @@
|
||||
import MsSwagePpl from "../popupComponent/MsSwagePpl";
|
||||
import sewagePump from "../popupComponent/sewagePump";
|
||||
import smh from "../popupComponent/smh";
|
||||
import Ssc from "../popupComponent/Ssc";
|
||||
import StormWaterPump from "../popupComponent/stormWaterPump";
|
||||
import SwtrmtFclt from "../popupComponent/SwtrmtFclt";
|
||||
|
||||
type LayerComponentProps = { featureData: any };
|
||||
type LayerContentMap = {
|
||||
[key: string]: {
|
||||
component?: React.FC<LayerComponentProps>;
|
||||
props?: any;
|
||||
};
|
||||
};
|
||||
// 레이어 이름과 컴포넌트를 매핑
|
||||
const layerContentMap: { [key: string]: { component?: React.FC<any> ; props?: any; } } = {
|
||||
// 레이어 선택시 변경되는 팝업 컨텐츠 동적으로 변경하도록 작업
|
||||
const layerContentMap: LayerContentMap = {
|
||||
// TODO: gis데이터 추가되면 추가 작업 필요
|
||||
"하수처리시설": {
|
||||
component: SwtrmtFclt,
|
||||
component: MsSwagePpl,
|
||||
},
|
||||
"하수처리구역": {component: Ssc, },
|
||||
"중점우수토실":{component: Ssc,},
|
||||
"하수관로":{component: SwtrmtFclt,},
|
||||
"하수관로":{component: MsSwagePpl,},
|
||||
"하수맨홀":{component: smh,},
|
||||
"빗물펌프":{component:StormWaterPump},
|
||||
"오수펌프":{component:sewagePump},
|
||||
};
|
||||
|
||||
// 동적 컴포넌트 반환 함수
|
||||
export const getLayerContentComponent = (layerNm: string): React.FC => {
|
||||
export const getLayerContentComponent = (layerNm: string): React.FC<LayerComponentProps> | null => {
|
||||
const component = layerContentMap[layerNm];
|
||||
if (!component || !component.component) {
|
||||
// component가 없으면 null 반환
|
||||
|
||||
@@ -49,3 +49,25 @@ export const SwtrmtPrcsZoneCol = [
|
||||
{ id: 'sggNm', title: '시군구명' },
|
||||
{ id: 'swtrmtFcltNm', title: '하수처리시설명' },
|
||||
]
|
||||
|
||||
// 하수맨홀
|
||||
export const MsSwageMhlCol = [
|
||||
{ id: 'fid', title: 'FID' },
|
||||
{ id: 'geom', title: 'geometry' },
|
||||
{ id: 'ftreSmblCd', title: '지형지물부호코드' },
|
||||
{ id: 'mngNo', title: '관리번호' },
|
||||
{ id: 'pbadmsEmdCd', title: '행정읍면동코드' },
|
||||
{ id: 'mapshtNo', title: '도엽번호' },
|
||||
{ id: 'mngInstCd', title: '관리기관코드' },
|
||||
{ id: 'instlYmd', title: '설치일자' },
|
||||
{ id: 'lastDrdgnYmd', title: '최종준설일자' },
|
||||
{ id: 'usgCd', title: '용도코드' },
|
||||
{ id: 'fcltyShpCd', title: '시설물형태코드' },
|
||||
{ id: 'mhlKndCd', title: '맨홀종류코드' },
|
||||
{ id: 'swageMhDiam', title: '하수맨홀구경' },
|
||||
{ id: 'wdthLen', title: '가로길이' },
|
||||
{ id: 'vrtcLen', title: '세로길이' },
|
||||
{ id: 'mqltCd', title: '재질코드' },
|
||||
{ id: 'altdVl', title: '표고값' },
|
||||
{ id: 'dpthlVl', title: '심도값' },
|
||||
{ id: 'instMngNo', title:'기관관리번호'}]
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import { VerticalTable } from '@/components/ui/verticalTable';
|
||||
import React, { useState } from 'react'
|
||||
import InputSection from '../InputSection';
|
||||
import { handleInputChange } from '../common';
|
||||
// 하수관로
|
||||
// TODO: RDII 버튼인가 그거 팝업 두개 구현 필요
|
||||
const inputColumn = [
|
||||
{ id: "title", title: "설치주제", type: "select", options: ["BTL", "재정사업"] },
|
||||
{ id: "swtrmt_zone_cd", title: "처리구역", type: "select", options: ["구역1", "구역2"] },
|
||||
{ id: "basu", title: "배수구역", type: "input" },
|
||||
{ id: "mltv_dtdv_nm", title: "배수분구", type: "input" },
|
||||
{ id: "wltjs", title: "지선/간선", type: "select", options: ["지선", "간선"] },
|
||||
{ id: "flow", title: "흐름방식", type: "select", options: ["자연유하", "압송"] },
|
||||
{ id: "place", title: "매설위치", type: "select", options: ["도로", "하상"] },
|
||||
];
|
||||
const SwtrmtFclt = ({ featureData }: { featureData: any }) => {
|
||||
console.log("featureData", featureData);
|
||||
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 dataMap = {
|
||||
repair: { data: repairData, setData: setRepairData },
|
||||
cleaning: { data: cleaningData, setData: setCleaningData },
|
||||
inspection: { data: inspectionData, setData: setInspectionData },
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
<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>
|
||||
<InputSection title="보수 및 갱신" data={repairData} sectionKey="repair" onInputChange={(section, index, field, value) => handleInputChange(section, index, field, value, dataMap)} />
|
||||
<InputSection title="청소 및 준설" data={cleaningData} sectionKey="cleaning" onInputChange={(section, index, field, value) => handleInputChange(section, index, field, value, dataMap)} />
|
||||
<InputSection title="점검 및 진단" data={inspectionData} sectionKey="inspection" onInputChange={(section, index, field, value) => handleInputChange(section, index, field, value, dataMap)} /></div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SwtrmtFclt
|
||||
@@ -12,7 +12,7 @@ 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 = () => {
|
||||
const Ssc = ({ featureData }: { featureData: any }) => {
|
||||
const [isModalOpen, setIsModalOpen] = React.useState(false);
|
||||
const openModal = () => {
|
||||
setIsModalOpen(true);
|
||||
|
||||
@@ -1,44 +1,48 @@
|
||||
import Modal from '@/components/ui/modal';
|
||||
import { VerticalTable } from '@/components/ui/verticalTable';
|
||||
import { UiTable } from '@common/business_components/ui';
|
||||
import { Button, TableCell } from '@common/components/ui';
|
||||
import React, { useState } from 'react'
|
||||
import InputSection from '../InputSection';
|
||||
import { handleInputChange } from '../common';
|
||||
|
||||
// 하수처리시설
|
||||
// TODO: 컬럼에 보고서 엉 ? 이거 버튼누르면 팝업으로 상세화면 띄워주는 건지 확인 필요
|
||||
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 headList = [
|
||||
{ id: "title", title: "하수도정비 기본계획보고서" },
|
||||
{ id: "cad", title: "하수도대장 평면도" },]
|
||||
const modalHeadList = [
|
||||
{ id: "no", title: "번호" },
|
||||
{ id: "year", title: "승인연도" },
|
||||
{ id: "cad", title: '평면도'},
|
||||
{ id: "fileNm", title: "파일명" },
|
||||
{ id: "date", title: "입력시간" },
|
||||
]
|
||||
|
||||
const SwtrmtFclt = () => {
|
||||
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 dataMap = {
|
||||
repair: { data: repairData, setData: setRepairData },
|
||||
cleaning: { data: cleaningData, setData: setCleaningData },
|
||||
inspection: { data: inspectionData, setData: setInspectionData },
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [modalTitle, setModalTitle] = useState<string>('');
|
||||
const openModal = (title:string) => {
|
||||
setIsModalOpen(true);
|
||||
setModalTitle(title)
|
||||
};
|
||||
const closeModal = () => {
|
||||
setIsModalOpen(false);
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
<VerticalTable headName='자체 입력정보' tableData={[]} headlist={inputColumn} pageSize={20} total={0} children={undefined} cellClick={undefined} isEditable={true} onPageChange={function (page: number): void {
|
||||
<VerticalTable children={{
|
||||
title: <Button onClick={() => openModal('하수도정비 기본계획보고서')}>보고서</Button>,
|
||||
cad: <Button onClick={() => openModal('하수도대장 평면도')}>평면도</Button>,
|
||||
}} headName='디지털 자료관 연계정보' tableData={[]} headlist={headList} pageSize={20} total={0} cellClick={undefined} isEditable={true} onPageChange={function (page: number): void {
|
||||
throw new Error("Function not implemented.");
|
||||
}}></VerticalTable>
|
||||
<InputSection title="보수 및 갱신" data={repairData} sectionKey="repair" onInputChange={(section, index, field, value) => handleInputChange(section, index, field, value, dataMap)} />
|
||||
<InputSection title="청소 및 준설" data={cleaningData} sectionKey="cleaning" onInputChange={(section, index, field, value) => handleInputChange(section, index, field, value, dataMap)} />
|
||||
<InputSection title="점검 및 진단" data={inspectionData} sectionKey="inspection" onInputChange={(section, index, field, value) => handleInputChange(section, index, field, value, dataMap)} /></div>
|
||||
<Modal isModalOpen={isModalOpen} setIsModalOpen={setIsModalOpen} closeModal={closeModal}>
|
||||
<div className='grid grid-col-2'>
|
||||
<UiTable headName={modalTitle} tableData={[]} headlist={modalHeadList} pageSize={20} total={0} cellClick={undefined} children={undefined} onPageChange={function (page: number): void {
|
||||
throw new Error("Function not implemented.");
|
||||
}
|
||||
}></UiTable>
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { VerticalTable } from '@/components/ui/verticalTable';
|
||||
import React from 'react'
|
||||
const inputColumn = [
|
||||
{ id: "guyeok", title: "처리구역", type: "select", options: ["구역1", "구역2"] },
|
||||
{ id: "bungu", title: "배수분구", type: "input" },
|
||||
{ id: "freq", title: "설계빈도", type: "input" },
|
||||
]
|
||||
// 오수펌프
|
||||
const sewagePump = ({ featureData }: { featureData: any }) => {
|
||||
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.');
|
||||
}} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default sewagePump
|
||||
@@ -0,0 +1,17 @@
|
||||
import { VerticalTable } from '@/components/ui/verticalTable';
|
||||
import React from 'react'
|
||||
const inputColumn = [
|
||||
{ id: "guyeok", title: "처리구역", type: "select", options: ["구역1", "구역2"] },
|
||||
{ id: "bungu", title: "배수분구", type: "input" },
|
||||
]
|
||||
// 빗물펌프
|
||||
const StormWaterPump = ({ featureData }: { featureData: any }) => {
|
||||
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.');
|
||||
}} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default StormWaterPump
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
import { VerticalTable } from "@/components/ui/verticalTable";
|
||||
import { Button, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@common/components/ui";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { SwtrmtFcltCol, SwtrmtPrcsZoneCol } from "./components/common/table";
|
||||
import { useGisContext } from "@common/business_components/ui/map/Gis";
|
||||
import { getData } from "@/components/lib/api";
|
||||
@@ -16,7 +16,9 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
|
||||
const [layerNm, setLayerNm] = useState<string>(""); // 레이어 이름 상태
|
||||
const [tableData, setTableData] = useState<any>(null); // 피처 데이터 상태
|
||||
const [headlist, setHeadlist] = useState<{ id: string; title: string; }[]>([]); // 컬럼리스트 변경상태
|
||||
let [buttonChk, setButtonChk] = useState(true)
|
||||
const [buttonChk, setButtonChk] = useState(true)
|
||||
const [fetchData, setfetchData] = useState<any>(); // api 호출여부
|
||||
const contentRef = useRef<HTMLDivElement>(null);
|
||||
// 피쳐데이터의 현재 레이어 이름 가져오는 함수
|
||||
const getSelectedLayers = () => {
|
||||
let result = null;
|
||||
@@ -45,11 +47,12 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
|
||||
const selectedLayerName = getSelectedLayers(); // 레이어 이름 가져오기
|
||||
setLayerNm(selectedLayerName); // 상태 업데이트
|
||||
|
||||
const data = await getData(`v1/map/features/${featureId}`);
|
||||
const data = await getData(`v1/fclts/${featureId}`);
|
||||
setfetchData(data)
|
||||
switch (selectedLayerName) {
|
||||
case '하수처리시설':
|
||||
setHeadlist(SwtrmtFcltCol);
|
||||
setButtonChk(false)
|
||||
setButtonChk(true)
|
||||
break;
|
||||
case '하수처리구역':
|
||||
setHeadlist(SwtrmtPrcsZoneCol)
|
||||
@@ -64,7 +67,10 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
|
||||
case '하수관로':
|
||||
setButtonChk(true)
|
||||
break;
|
||||
case '하수맨홀':
|
||||
case '오수펌프':
|
||||
setButtonChk(true)
|
||||
break;
|
||||
case '빗물펌프':
|
||||
setButtonChk(true)
|
||||
break;
|
||||
default:
|
||||
@@ -75,6 +81,24 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
|
||||
}
|
||||
fetchData();
|
||||
}, [featureId]);
|
||||
// TODO: api 호출작업 필요(사용자 입력부분)
|
||||
const btnClickEvent = () => {
|
||||
if (buttonChk && contentRef.current) {
|
||||
const inputElements = contentRef.current.querySelectorAll('input');
|
||||
const selectElements = contentRef.current.querySelectorAll('select');
|
||||
// select 태그의 값 가져오기
|
||||
console.log("Select Elements:", selectElements);
|
||||
console.log("Input Elements:", inputElements);
|
||||
selectElements.forEach((select) => {
|
||||
console.log("Select Value:", select.value);
|
||||
});
|
||||
|
||||
// input 태그의 값 가져오기
|
||||
inputElements.forEach((input) => {
|
||||
console.log("Input Value:", input.value);
|
||||
});
|
||||
}
|
||||
}
|
||||
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]">
|
||||
@@ -91,16 +115,16 @@ const FeatureClickEventPopup = ({ onClose, featureData }: { onClose: () => void,
|
||||
✕
|
||||
</button>
|
||||
</div>
|
||||
<div className="overflow-y-auto flex-1">
|
||||
<div className="overflow-y-auto 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>
|
||||
<div className="w-full mx-5 flex items-center justify-end space-x-2">
|
||||
{buttonChk ? <Button className="px-4 mr-5 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700">
|
||||
{buttonChk ? <Button onClick={btnClickEvent} 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>
|
||||
{ContentComponent && <ContentComponent />}
|
||||
{ContentComponent && <ContentComponent featureData={fetchData} />}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -5,9 +5,13 @@ import { Button } from "@common/components/ui";
|
||||
export default function Home() {
|
||||
return (
|
||||
<div>
|
||||
<div><h3 className="text-2xl text-bold gap-4 mx-4">하수관망도</h3>
|
||||
<div className="flex flex-row gap-4 p-4">
|
||||
<Link href={"/map"}><Button>하수관망도</Button></Link>
|
||||
</div>
|
||||
</div>
|
||||
<div><h3 className="text-2xl text-bold gap-4 mx-4">운영정보 관리</h3>
|
||||
<div className="flex flex-row gap-4 p-4">
|
||||
<Link href={"/oper/pplines"}><Button>관로시설</Button></Link>
|
||||
<Link href={"/oper/floodPre"}><Button>도시침수 예방사업</Button></Link>
|
||||
<Link href={"/oper/oldPp"}><Button>노후 하수관로 정비사업</Button></Link>
|
||||
</div>
|
||||
|
||||
@@ -1,16 +1,84 @@
|
||||
import * as XLSX from 'xlsx';
|
||||
|
||||
type ExcelDownloadProps = {
|
||||
data : JSON | JSON[];
|
||||
fileName : string;
|
||||
sheetNameArray : string[];
|
||||
data: JSON | JSON[];
|
||||
fileName: string;
|
||||
sheetNameArray: string[];
|
||||
}
|
||||
|
||||
export const downloadExcel = ({ data, fileName = new Date().getTime().toString()+'.xlsx', sheetNameArray = ["Sheet1"] }: ExcelDownloadProps) => {
|
||||
const worksheet = XLSX.utils.json_to_sheet(Array.isArray(data) ? data : [data]);
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, sheetNameArray[0]);
|
||||
//let buffer = XLSX.write(workbook, { bookType: "xlsx", type: "buffer" });
|
||||
//XLSX.write(workbook, { bookType: "xlsx", type: "binary" });
|
||||
XLSX.writeFile(workbook, fileName+'.xlsx');
|
||||
};
|
||||
export const downloadExcel = ({ data, fileName = new Date().getTime().toString() + '.xlsx', sheetNameArray = ["Sheet1"] }: ExcelDownloadProps) => {
|
||||
const worksheet = XLSX.utils.json_to_sheet(Array.isArray(data) ? data : [data]);
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, sheetNameArray[0]);
|
||||
//let buffer = XLSX.write(workbook, { bookType: "xlsx", type: "buffer" });
|
||||
//XLSX.write(workbook, { bookType: "xlsx", type: "binary" });
|
||||
XLSX.writeFile(workbook, fileName + '.xlsx');
|
||||
};
|
||||
|
||||
|
||||
|
||||
export const filePicked=(oFile: File, headerNum:number=0):Promise<JSON | undefined> =>{
|
||||
// Create A File Reader HTML5
|
||||
const reader = new FileReader();
|
||||
return new Promise<JSON | undefined>((resolve, reject) => {
|
||||
// Ready The Event For When A File Gets Selected
|
||||
reader.onload = function (e) {
|
||||
const data = e.target?.result;
|
||||
if (!data) {
|
||||
console.error("Failed to read file: e.target.result is null");
|
||||
resolve(undefined);
|
||||
return;
|
||||
}
|
||||
const wb = XLSX.read(data, { type: 'binary' });
|
||||
let jsonXls: JSON | undefined;
|
||||
|
||||
//TODO 시트가 2개이상일 경우 마지막 시트의 데이터만 표출됨
|
||||
// Loop Over Each Sheet
|
||||
wb.SheetNames.forEach(function (sheetName) {
|
||||
// Obtain The Current Row As CSV
|
||||
const sheet = wb.Sheets[sheetName];
|
||||
|
||||
if (sheet) {
|
||||
jsonXls = XLSX.utils.sheet_to_json(sheet, { range: headerNum }) as unknown as JSON;
|
||||
} else {
|
||||
console.error(`Sheet "${sheetName}" is undefined.`);
|
||||
}
|
||||
});
|
||||
resolve(jsonXls);
|
||||
};
|
||||
|
||||
reader.onerror = function () {
|
||||
console.error("Error reading file");
|
||||
reject(undefined);
|
||||
};
|
||||
|
||||
// Tell JS To Start Reading The File.. You could delay this if desired
|
||||
reader.readAsBinaryString(oFile);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const filePickedBlob=(oFile: ArrayBuffer, data:[][],fileNm:string, headerNum:number=0):Promise<JSON | undefined> =>{
|
||||
// Create A File Reader HTML5
|
||||
return new Promise<JSON | undefined>(() => {
|
||||
// Ready The Event For When A File Gets Selected
|
||||
const wb = XLSX.read(oFile, { type: 'binary' });
|
||||
// Loop Over Each Sheet
|
||||
wb.SheetNames.forEach(function (sheetName, index) {
|
||||
// Obtain The Current Row As CSV
|
||||
if(index==0){
|
||||
const sheet = wb.Sheets[sheetName];
|
||||
if (sheet) {
|
||||
//오리진 확인 test 필요
|
||||
// const sheet = XLSX.utils.json_to_sheet(data);
|
||||
XLSX.utils.sheet_add_aoa(sheet, data, { origin: 'A'+headerNum });
|
||||
// XLSX.utils.book_append_sheet(wb, sheet, 'test');
|
||||
XLSX.writeFile(wb, `${fileNm}.xlsx`);
|
||||
} else {
|
||||
console.error(`Sheet "${sheetName}" is undefined.`);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -6,14 +6,22 @@ const dropZoneConfig = {
|
||||
maxSize: 1024 * 1024 * 4,
|
||||
multiple: true,
|
||||
};
|
||||
|
||||
|
||||
interface FileUploadProps {
|
||||
files: File[]; // 파일 배열
|
||||
setFiles: (files: File[] | null) => void; // 파일 배열 세터
|
||||
fileTypes?: string; // 옵션 (파일 확장자 문자열)
|
||||
}
|
||||
|
||||
export const FileUpload =
|
||||
(({ ...props }) => {
|
||||
({ files, setFiles, fileTypes }: FileUploadProps) => {
|
||||
return (
|
||||
<FileUploader
|
||||
value={props.files}
|
||||
onValueChange={props.setFiles}
|
||||
value={files}
|
||||
onValueChange={setFiles}
|
||||
dropzoneOptions={dropZoneConfig}
|
||||
acceptName={props?.fileTypes}
|
||||
acceptName={fileTypes}
|
||||
className="relative bg-background rounded-lg p-2"
|
||||
>
|
||||
<FileInput
|
||||
@@ -23,18 +31,18 @@ export const FileUpload =
|
||||
<div className="flex items-center justify-center flex-col p-8 w-full ">
|
||||
<CloudUpload className='text-gray-500 w-10 h-10' />
|
||||
<p className="mb-1 text-sm text-gray-500 dark:text-gray-400">
|
||||
<span className="font-semibold">Click to upload</span>
|
||||
or drag and drop
|
||||
<span className="font-semibold">클릭 후 업로드 </span>
|
||||
혹은 파일을 드래그 해주세요
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">
|
||||
{!props?.fileTypes?"SVG, PNG, JPG, GIF":props?.fileTypes}
|
||||
{!fileTypes?"SVG, PNG, JPG, GIF":fileTypes}
|
||||
</p>
|
||||
</div>
|
||||
</FileInput>
|
||||
<FileUploaderContent>
|
||||
{props.files &&
|
||||
props.files.length > 0 &&
|
||||
props.files.map((file:File, i:number) => (
|
||||
{files&&
|
||||
files.length > 0 &&
|
||||
files.map((file:File, i:number) => (
|
||||
<FileUploaderItem key={i} index={i}>
|
||||
<Paperclip className="h-4 w-4 stroke-current" />
|
||||
<span>{file.name}</span>
|
||||
@@ -43,4 +51,4 @@ export const FileUpload =
|
||||
</FileUploaderContent>
|
||||
</FileUploader>
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -1,20 +1,21 @@
|
||||
export * from "./chart";
|
||||
export * from "./date_picker";
|
||||
export * from "./dialog_ui";
|
||||
export * from "./excel_download";
|
||||
export * from "./file-upload";
|
||||
export * from "./form";
|
||||
export * from "./form_ui";
|
||||
export * from "./list_div";
|
||||
export * from "./main_content_div";
|
||||
export * from "./scroll";
|
||||
export * from "./search_base_form";
|
||||
export * from "./search_form";
|
||||
export * from "./search_form_left";
|
||||
export * from "./search_form_right";
|
||||
export * from "./search_input";
|
||||
export * from "./search_input_select";
|
||||
export * from "./select";
|
||||
export * from "./table";
|
||||
export * from "./main_content_div";
|
||||
export * from "./title";
|
||||
export * from "./search_form_left";
|
||||
export * from "./search_form_right";
|
||||
export * from "./table_div";
|
||||
export * from "./list_div";
|
||||
export * from "./tab";
|
||||
export * from "./dialog_ui";
|
||||
export * from "./excel_download";
|
||||
export * from "./table";
|
||||
export * from "./table_div";
|
||||
export * from "./title";
|
||||
|
||||
@@ -27,7 +27,7 @@ function Gis({ treeData = [], isSearch = false }) {
|
||||
const [featureData,setFeatureData] = useState(null) // 선택된 피쳐 데이터
|
||||
const [isSearchModalOpen, setIsSearchModalOpen] = useState(false); // SearchModal 열림 상태
|
||||
const gisCore = useMemo(() => new GisApp.core({ targetId: mapRef.current }), []);
|
||||
//const [treeData, setTreeData] = useState([]);
|
||||
const mapInstanceRef = useRef(null); // 맵 생성 여부를 추적할 ref
|
||||
const checkedLayerIds = useRef([]);
|
||||
let gisMap = null;
|
||||
const closePopup = () => {
|
||||
@@ -45,6 +45,7 @@ function Gis({ treeData = [], isSearch = false }) {
|
||||
|
||||
useEffect(() => {
|
||||
if (!mapRef.current) return;
|
||||
if (mapInstanceRef.current) return; // 이미 생성된 맵이 있다면 중단
|
||||
|
||||
// EPSG:5179 등록
|
||||
proj4.defs([
|
||||
@@ -55,7 +56,7 @@ function Gis({ treeData = [], isSearch = false }) {
|
||||
]);
|
||||
register(proj4);
|
||||
|
||||
//맵 생성성
|
||||
//맵 생성
|
||||
const map = new OlMap({
|
||||
layers: [gisCore.baseLayers['base'], gisCore.baseLayers['satellite']],
|
||||
renderer: 'webgl',
|
||||
@@ -99,10 +100,10 @@ function Gis({ treeData = [], isSearch = false }) {
|
||||
gisCore.scaleControl();
|
||||
gisCore.changeBaseLayer('base');
|
||||
setMapObject({ map: map });
|
||||
mapInstanceRef.current = map; // 생성 완료 플래그 설정
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
//if (!locgovCd) return null;
|
||||
if (!treeData || treeData.length === 0) return;
|
||||
|
||||
gisCore.deleteAllOverlay();
|
||||
@@ -141,7 +142,6 @@ function Gis({ treeData = [], isSearch = false }) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<GisContext.Provider value={{gisCore, gisMap, treeData, checkedLayerIds}}>
|
||||
@@ -156,9 +156,9 @@ function Gis({ treeData = [], isSearch = false }) {
|
||||
/>
|
||||
)}
|
||||
<div ref={mapRef} className="gis-map flex-1 relative" style={{ height: '100%', padding: 0 }} />
|
||||
<GisLonLat/>
|
||||
{/* <GisLonLat/>
|
||||
<GisToolBar/>
|
||||
<MapToggleBtn/>
|
||||
<MapToggleBtn/> */}
|
||||
</div>
|
||||
</GisContext.Provider>
|
||||
</>
|
||||
|
||||
@@ -8,7 +8,7 @@ import './lib/css/gis.edit.css';
|
||||
import MapToggleBtn from './MapToggleBtn';
|
||||
import GisEdit from './GisEdit';
|
||||
|
||||
export default function GisContent({ edit = false,onFeatureSelect }) {
|
||||
export default function GisContent({ edit = false, onFeatureSelect }) {
|
||||
const { gisMap, gisCore } = useGisContext();
|
||||
const [visibleComponents, setVisibleComponents] = useState({});
|
||||
const addressResultLayer = useRef(null);
|
||||
@@ -51,11 +51,10 @@ export default function GisContent({ edit = false,onFeatureSelect }) {
|
||||
return (
|
||||
<>
|
||||
{/*<GisTree />*/}
|
||||
{/* <MapToggleBtn useCesium={useCesium} /> */}
|
||||
{/* { <GisLonLat /> */}
|
||||
{/* <GisSelect clickFeature={clickFeature} /> */}
|
||||
<MapToggleBtn />
|
||||
<GisLonLat />
|
||||
<GisToolBar />
|
||||
<GisSelect onFeatureSelect={onFeatureSelect}/>
|
||||
{/* {edit && <GisEdit />} */}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,15 +1,29 @@
|
||||
import React from 'react';
|
||||
import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
|
||||
import GisApp from './lib/gis.core';
|
||||
import GisOlSelect from './lib/gis.select';
|
||||
import { useContext } from 'react';
|
||||
import { GisContext } from './Gis';
|
||||
|
||||
export default React.memo(function GisSelect({ onFeatureSelect }) {
|
||||
|
||||
const { gisMap } = useContext(GisContext);
|
||||
|
||||
|
||||
// useEffect(() => {
|
||||
// if (!gisMap) return; // 아직 초기화 안 됐으면 아무것도 안 함
|
||||
|
||||
// const select = new GisOlSelect(gisMap);
|
||||
// GisApp.Module.select = select;
|
||||
|
||||
// select.getSelectedInfo(function (features) {
|
||||
// if (features?.[0]) {
|
||||
// // onFeatureClick?.(features[0]); // props로 넘긴 함수 실행
|
||||
// onFeatureSelect(layer.getProperties()); //피쳐 속성데이터 상위컴포넌트로 전달
|
||||
// }
|
||||
// });
|
||||
// }, [gisMap, onFeatureSelect]);
|
||||
|
||||
const select = new GisOlSelect(gisMap);
|
||||
GisApp.Module.select = select;
|
||||
const reset = () => {
|
||||
select.reset();
|
||||
};
|
||||
|
||||
select.getSelectedInfo(function (features) {
|
||||
//clickFeature(features[0]);
|
||||
@@ -18,6 +32,7 @@ export default React.memo(function GisSelect({ onFeatureSelect }) {
|
||||
onFeatureSelect(layer); //피쳐 속성데이터 상위컴포넌트로 전달
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* <div className="select_control map_control_div ol-unselectable ol-control" style={{ pointerEvents: 'auto', zIndex: '1' }}>
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@common/components/ui/tabs";
|
||||
|
||||
export default React.memo(function GisTree({ checkedNodes = [], setCheckedNodes = () => {} }) {
|
||||
const { gisCore, treeData, checkedLayerIds } = useGisContext();
|
||||
const { gisCore, treeData } = useGisContext();
|
||||
const [checked, setChecked] = useState([]);
|
||||
const [expanded, setExpanded] = useState([]);
|
||||
const [nodes, setNodes] = useState([]);
|
||||
@@ -43,7 +43,6 @@ export default React.memo(function GisTree({ checkedNodes = [], setCheckedNodes
|
||||
const node = nodes[i];
|
||||
if (node.data.initEprssYn === 'Y') {
|
||||
values.push(node.data.lyrSn);
|
||||
checkedLayerIds?.current.push(node.data.lyrSn + '');
|
||||
}
|
||||
}
|
||||
return values;
|
||||
@@ -94,7 +93,6 @@ export default React.memo(function GisTree({ checkedNodes = [], setCheckedNodes
|
||||
}
|
||||
const allIds = nodes.map((n) => n.id);
|
||||
const unchecked = allIds.filter((nid) => !newChecked.includes(nid));
|
||||
checkedLayerIds.current = newChecked;
|
||||
gisCore.setLayerOnMap(newChecked, true);
|
||||
gisCore.setLayerOnMap(unchecked, false);
|
||||
return newChecked;
|
||||
|
||||
@@ -345,6 +345,7 @@ GisOlSelect.prototype = {
|
||||
this.selectInteraction.on('select', function (e) {
|
||||
if (!e.auto) {
|
||||
let features = me.selectInteraction.getFeatures();
|
||||
if(features.getArray().length == 0) return;
|
||||
let layers = [];
|
||||
for (let i in features.array_) {
|
||||
let feature = features.array_[0];
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
import { Button } from "@common/components/ui";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { SearchFormLeft, type EnvPartSelectDataType } from "../search_form_left";
|
||||
import { SearchFormRight } from "../search_form_right";
|
||||
import type { SelectDataType } from "../search_input_select";
|
||||
type SearchBaseType = {
|
||||
leftChildren:React.ReactNode;
|
||||
rightChildren:React.ReactNode;
|
||||
selectSidoData?: SelectDataType[] | [];
|
||||
selectSigunData?: SelectDataType[] | [];
|
||||
selectRegionData?: SelectDataType[] | [];
|
||||
selectUnitWaterShedData?: SelectDataType[] | [];
|
||||
selectMiddleRegionData?: SelectDataType[] | [];
|
||||
selectEnvPartData?: EnvPartSelectDataType[] | [];
|
||||
queryClick:(returnType:ReturnType) => void;
|
||||
excelName?:string;
|
||||
excelClick:(returnType:ReturnType) => void;
|
||||
initClick:() => void;
|
||||
btnClass:string;
|
||||
ref:React.RefObject<ReturnType>;
|
||||
}
|
||||
export type ReturnType = {
|
||||
partValue: string;
|
||||
sidoValue: string;
|
||||
sigunValue: string;
|
||||
regionValue: string;
|
||||
unitWaterShedValue: string;
|
||||
middleRegionValue: string;
|
||||
envPartValue: string;
|
||||
}
|
||||
|
||||
|
||||
function SearchBaseForm ({
|
||||
leftChildren,
|
||||
rightChildren,
|
||||
selectSidoData,
|
||||
selectSigunData,
|
||||
selectRegionData,
|
||||
selectUnitWaterShedData,
|
||||
selectMiddleRegionData,
|
||||
selectEnvPartData,
|
||||
btnClass,
|
||||
excelName,
|
||||
queryClick,
|
||||
excelClick,
|
||||
initClick,
|
||||
ref
|
||||
}: SearchBaseType) {
|
||||
const [partValue, setPartValue] = useState<string>("A");
|
||||
const [sidoValue, setSidoValue] = useState<string>("0");
|
||||
const [sigunValue, setSigunValue] = useState<string>("0");
|
||||
const [regionValue, setRegionValue] = useState<string>("0");
|
||||
const [untitWaterShedValue, setUntitWaterShedValue] = useState<string>("0");
|
||||
const [middleRegionValue, setMiddleRegionValue] = useState<string>("0");
|
||||
const [envPartValue, setEnvPartValue] = useState<string>("0");
|
||||
const [resetTrigger, setResetTrigger] = useState(false);
|
||||
const queryVal = () => {
|
||||
console.log("조회버튼 클릭");
|
||||
queryClick({
|
||||
partValue: partValue,
|
||||
sidoValue: sidoValue,
|
||||
sigunValue: sigunValue,
|
||||
regionValue: regionValue,
|
||||
unitWaterShedValue: untitWaterShedValue,
|
||||
middleRegionValue: middleRegionValue,
|
||||
envPartValue: envPartValue,
|
||||
});
|
||||
}
|
||||
const initVal = useCallback(() => {
|
||||
setResetTrigger(true);
|
||||
initClick();
|
||||
}, [setResetTrigger, initClick]);
|
||||
useEffect(() => {
|
||||
if (resetTrigger) {
|
||||
setResetTrigger(false);
|
||||
}
|
||||
}, [resetTrigger]);
|
||||
const excelDownload = () => {
|
||||
excelClick({
|
||||
partValue: partValue,
|
||||
sidoValue: sidoValue,
|
||||
sigunValue: sigunValue,
|
||||
regionValue: regionValue,
|
||||
unitWaterShedValue: untitWaterShedValue,
|
||||
middleRegionValue: middleRegionValue,
|
||||
envPartValue: envPartValue,
|
||||
})
|
||||
};
|
||||
useEffect(() => {
|
||||
if (ref && ref.current) {
|
||||
const customRef = ref.current;
|
||||
customRef.partValue = partValue;
|
||||
customRef.sidoValue = sidoValue;
|
||||
customRef.sigunValue = sigunValue;
|
||||
customRef.regionValue = regionValue;
|
||||
customRef.unitWaterShedValue = untitWaterShedValue;
|
||||
customRef.middleRegionValue = middleRegionValue;
|
||||
customRef.envPartValue = envPartValue;
|
||||
}
|
||||
}, [partValue, sidoValue, sigunValue, regionValue, untitWaterShedValue, middleRegionValue, envPartValue, ref]);
|
||||
return (
|
||||
<div className="flex card card-border !mt-6">
|
||||
<SearchFormLeft isShowPart={true}
|
||||
selectSidoData={selectSidoData}
|
||||
selectSigunData={selectSigunData}
|
||||
selectRegionData={selectRegionData}
|
||||
selectUnitWaterShedData={selectUnitWaterShedData}
|
||||
selectMiddleRegionData={selectMiddleRegionData}
|
||||
selectEnvPartData={selectEnvPartData}
|
||||
setRtnPartValue={setPartValue}
|
||||
setRtnSidoValue={setSidoValue}
|
||||
setRtnSigunValue={setSigunValue}
|
||||
setRtnRegionValue={setRegionValue}
|
||||
setRtnUnitWaterShedValue={setUntitWaterShedValue}
|
||||
setRtnMiddleRegionValue={setMiddleRegionValue}
|
||||
setRtnEnvPartValue={setEnvPartValue}
|
||||
setRtnEnvPartSidoValue={setSidoValue}
|
||||
setRtnEnvPartSigunValue={setSigunValue}
|
||||
resetTrigger={resetTrigger}
|
||||
>
|
||||
{leftChildren}
|
||||
</SearchFormLeft>
|
||||
<SearchFormRight>
|
||||
<Button className={btnClass} color="green" onClick={excelDownload}>
|
||||
{excelName?excelName:"엑셀다운로드"}
|
||||
</Button>
|
||||
<div>
|
||||
<Button className={btnClass} onClick={initVal}>
|
||||
초기화
|
||||
</Button>
|
||||
<Button className={btnClass} onClick={queryVal}>
|
||||
조회
|
||||
</Button>
|
||||
</div>
|
||||
{rightChildren}
|
||||
</SearchFormRight>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export { SearchBaseForm };
|
||||
|
||||
@@ -41,38 +41,41 @@ type SearchFormLeftProps = {
|
||||
resetTrigger?: boolean;
|
||||
}
|
||||
|
||||
type EnvPartSelectDataType = SelectDataType & {
|
||||
export type EnvPartSelectDataType = SelectDataType & {
|
||||
adstDliStrCd: string,
|
||||
}
|
||||
|
||||
const selectPartData:SelectDataType[] = [
|
||||
{ text: "행정별", val: '0' },
|
||||
{ text: "유역별", val: '01' },
|
||||
{ text: "환경청별", val: '02' },
|
||||
{ text: "행정별", val: 'A' },
|
||||
{ text: "유역별", val: 'R' },
|
||||
{ text: "환경청별", val: 'G' },
|
||||
];
|
||||
|
||||
function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], selectSigunData = [], selectRegionData = [], selectUnitWaterShedData = [], selectMiddleRegionData = [], selectEnvPartData = [], setRtnPartValue, setRtnSidoValue, setRtnSigunValue, setRtnRegionValue, setRtnUnitWaterShedValue, setRtnMiddleRegionValue, setRtnEnvPartValue, setRtnEnvPartSidoValue, setRtnEnvPartSigunValue, resetTrigger = false }: SearchFormLeftProps) {
|
||||
const [partValue, setPartValue] = useState<string>('0');
|
||||
const [showPart, setShowPart] = useState<string>('');
|
||||
/******************선택된 데이터******************/
|
||||
const [partValue, setPartValue] = useState<string>('A');
|
||||
//행정별 시도 시군구
|
||||
const [sidoValue, setSidoValue] = useState<string>('0');
|
||||
const [sigunValue, setSigunValue] = useState<string>('0');
|
||||
//유역별
|
||||
const [regionValue, setRegionValue] = useState<string>('0');
|
||||
const [unitWaterShedValue, setUnitWaterShedValue] = useState<string>('0');
|
||||
const [middleRegionValue, setMiddleRegionValue] = useState<string>('0');
|
||||
//환경청별 시도 시군구
|
||||
const [envPartValue, setEnvPartValue] = useState<string>('0');
|
||||
const [envPartSidoValue, setEnvPartSidoValue] = useState<string>('0');
|
||||
const [envPartSigunValue, setEnvPartSigunValue] = useState<string>('0');
|
||||
// 환경청
|
||||
const [filteredEnvPartSigunDataSelected, setFilteredEnvPartSigunDataSelected] = useState<SelectDataType[]>([]);
|
||||
|
||||
/****************** 셀렉트 리스트 데이터. ******************/
|
||||
// 조회된 조건에 맞는 시도 시군 유역
|
||||
const [filteredSigunData, setFilteredSigunData] = useState<SelectDataType[]>([{ text: "전체", val: '0' }]);
|
||||
const [filteredUnitWaterShedData, setFilteredUnitWaterShedData] = useState<SelectDataType[]>([{ text: "전체", val: '0' }]);
|
||||
const [filteredMiddleRegionData, setFilteredMiddleRegionData] = useState<SelectDataType[]>([{ text: "전체", val: '0' }]);
|
||||
|
||||
// 조회된 조건에 맞는 환경청 시도 시군
|
||||
const [filteredEnvPartData, setFilteredEnvPartData] = useState<EnvPartSelectDataType[]>([{ text: "전체", val: '0', adstDliStrCd:'' }]);
|
||||
const [filteredEnvPartSidoData, setFilteredEnvPartSidoData] = useState<EnvPartSelectDataType[]>([{ text: "전체", val: '0', adstDliStrCd:'' }]);
|
||||
const [filteredEnvPartSigunData, setFilteredEnvPartSigunData] = useState<SelectDataType[]>([{ text: "전체", val: '0' }]);
|
||||
|
||||
const [filteredEnvPartSigunDataSelected, setFilteredEnvPartSigunDataSelected] = useState<SelectDataType[]>([]);
|
||||
|
||||
// 시군구 세팅
|
||||
const initializeSigunData = (sidoCd: string) => {
|
||||
if (sidoCd === '0') {
|
||||
@@ -154,12 +157,10 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel
|
||||
setRtnPartValue(val);
|
||||
}
|
||||
// 구분
|
||||
if(val == '01') {
|
||||
setShowPart('01');
|
||||
if(val == 'R') {
|
||||
initializeMiddleRegionData('0');
|
||||
initializeUnitWaterShedData('0');
|
||||
} else if(val == '02') {
|
||||
setShowPart('02');
|
||||
} else if(val == 'G') {
|
||||
setFilteredEnvPartData([
|
||||
{ text: "전체", val: '0', adstDliStrCd:'' },
|
||||
...selectEnvPartData.filter((item: EnvPartSelectDataType) => item.val !== null && item.adstDliStrCd !== '')
|
||||
@@ -167,7 +168,6 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel
|
||||
setEnvPartValue('0');
|
||||
initializeCityDataByEnvPartSido('0');
|
||||
} else {
|
||||
setShowPart('0');
|
||||
initializeSigunData('0');
|
||||
onSelectValue(selectSigunData[0]?.val || '0', 'sigun');
|
||||
}
|
||||
@@ -225,7 +225,7 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel
|
||||
onSelectValue(filteredEnvPartSidoData[0]?.val || '0', 'envPartSido');
|
||||
break;
|
||||
case 'envPartSido' :
|
||||
setEnvPartSidoValue(val);
|
||||
setSidoValue(val);
|
||||
if (setRtnEnvPartSidoValue) {
|
||||
setRtnEnvPartSidoValue(val);
|
||||
}
|
||||
@@ -233,7 +233,7 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel
|
||||
onSelectValue(filteredEnvPartSigunData[0]?.val || '0', 'envPartSigun');
|
||||
break;
|
||||
case 'envPartSigun' :
|
||||
setEnvPartSigunValue(val);
|
||||
setSigunValue(val);
|
||||
if (setRtnEnvPartSigunValue) {
|
||||
setRtnEnvPartSigunValue(val);
|
||||
}
|
||||
@@ -243,16 +243,13 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel
|
||||
|
||||
// 리셋 함수
|
||||
const resetAllValues = () => {
|
||||
setPartValue('0');
|
||||
setShowPart('');
|
||||
setPartValue('A');
|
||||
setSidoValue('0');
|
||||
setSigunValue('0');
|
||||
setRegionValue('0');
|
||||
setUnitWaterShedValue('0');
|
||||
setMiddleRegionValue('0');
|
||||
setEnvPartValue('0');
|
||||
setEnvPartSidoValue('0');
|
||||
setEnvPartSigunValue('0');
|
||||
|
||||
setFilteredSigunData([{ text: "전체", val: '0' }]);
|
||||
setFilteredUnitWaterShedData([{ text: "전체", val: '0' }]);
|
||||
@@ -261,7 +258,7 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel
|
||||
setFilteredEnvPartSidoData([{ text: "전체", val: '0', adstDliStrCd: '' }]);
|
||||
setFilteredEnvPartSigunData([{ text: "전체", val: '0' }]);
|
||||
|
||||
if (setRtnPartValue) setRtnPartValue('0');
|
||||
if (setRtnPartValue) setRtnPartValue('A');
|
||||
if (setRtnSidoValue) setRtnSidoValue('0');
|
||||
if (setRtnSigunValue) setRtnSigunValue('0');
|
||||
if (setRtnRegionValue) setRtnRegionValue('0');
|
||||
@@ -287,17 +284,17 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel
|
||||
isShowPart ? (
|
||||
<div className="grid grid-cols-12 gap-5 w-11/12 m-4">
|
||||
<SelectBox className="col-span-3" label={'구분'} selectArray={selectPartData} onSelectValue={(val) => onSelectValue(val.toString(), 'part')} value={partValue} selectClass={undefined}/>
|
||||
{showPart === '01' ? (
|
||||
{partValue === 'R' ? (
|
||||
<>
|
||||
<SelectBox className="col-span-3" label={'유역'} selectArray={selectRegionData} onSelectValue={(val) => onSelectValue(val.toString(), 'region')} value={regionValue} selectClass={undefined}/>
|
||||
<SelectBox className="col-span-3" label={'단위유역'} selectArray={filteredUnitWaterShedData} onSelectValue={(val) => onSelectValue(val.toString(), 'unitWaterShed')} value={unitWaterShedValue} selectClass={undefined}/>
|
||||
<SelectBox className="col-span-3" label={'중권역'} selectArray={filteredMiddleRegionData} onSelectValue={(val) => onSelectValue(val.toString(), 'middleRegion')} value={middleRegionValue} selectClass={undefined}/>
|
||||
</>
|
||||
) : showPart === '02' ? (
|
||||
) : partValue === 'G' ? (
|
||||
<>
|
||||
<SelectBox className="col-span-3" label={'환경청'} selectArray={filteredEnvPartData} onSelectValue={(val) => onSelectValue(val.toString(), 'envPart')} value={envPartValue} selectClass={undefined}/>
|
||||
<SelectBox className="col-span-3" label={'시도'} selectArray={filteredEnvPartSidoData} onSelectValue={(val) => onSelectValue(val.toString(), 'envPartSido')} value={envPartSidoValue} selectClass={undefined}/>
|
||||
<SelectBox className="col-span-3" label={'시군구'} selectArray={filteredEnvPartSigunData} onSelectValue={(val) => onSelectValue(val.toString(), 'envPartSigun')} value={envPartSigunValue} selectClass={undefined}/>
|
||||
<SelectBox className="col-span-3" label={'시도'} selectArray={filteredEnvPartSidoData} onSelectValue={(val) => onSelectValue(val.toString(), 'envPartSido')} value={sidoValue} selectClass={undefined}/>
|
||||
<SelectBox className="col-span-3" label={'시군구'} selectArray={filteredEnvPartSigunData} onSelectValue={(val) => onSelectValue(val.toString(), 'envPartSigun')} value={sigunValue} selectClass={undefined}/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
@@ -315,4 +312,4 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel
|
||||
)
|
||||
}
|
||||
|
||||
export { SearchFormLeft };
|
||||
export { SearchFormLeft };
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import { TableHead, TableRow } from "@common/components/ui";
|
||||
|
||||
interface TableUpperProps {
|
||||
id: string;
|
||||
title: string;
|
||||
upName?: string;
|
||||
upSequnce?: number;
|
||||
row? : number;
|
||||
rowSpan?: number;
|
||||
colSpan?: number;
|
||||
}
|
||||
|
||||
const HeadMakeColSpan = ({ upHeadList }: { upHeadList: TableUpperProps[] }) => {
|
||||
const maxRow = upHeadList.reduce((max, head) => Math.max(max, head.row || 0), 0);
|
||||
|
||||
if(maxRow == 0){
|
||||
return (
|
||||
<>
|
||||
<TableRow className="bg-gray-50">
|
||||
{upHeadList.map((head: TableUpperProps) => {
|
||||
return (
|
||||
<TableHead
|
||||
key={head.id}
|
||||
colSpan={head.colSpan || 1}
|
||||
rowSpan={head.rowSpan || 1}
|
||||
style={{ whiteSpace: 'pre-line' }}
|
||||
className="bg-gray-50"
|
||||
>
|
||||
{head.title}
|
||||
</TableHead>
|
||||
);
|
||||
})}
|
||||
</TableRow>
|
||||
</>
|
||||
);
|
||||
}else{
|
||||
return (
|
||||
<>
|
||||
{Array.from({ length: maxRow + 1 }, (_, rowIndex) => (
|
||||
<TableRow key={rowIndex+ " headerRow"} className="bg-gray-50">
|
||||
{upHeadList.map((head: TableUpperProps) => {
|
||||
if (head.row === rowIndex) {
|
||||
return (
|
||||
<TableHead
|
||||
key={head.id}
|
||||
colSpan={head.colSpan || 1}
|
||||
rowSpan={head.rowSpan || 1}
|
||||
style={{ whiteSpace: 'pre-line' }}
|
||||
className="bg-gray-50"
|
||||
>
|
||||
{head.title}
|
||||
</TableHead>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</TableRow>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export { HeadMakeColSpan };
|
||||
@@ -1,18 +1,19 @@
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@common/components";
|
||||
import { Table, TableBody, TableCell, TableHeader, TableRow } from "@common/components";
|
||||
import { useEffect, useState } from "react";
|
||||
import { HeadMakeColSpan } from "./HeadMakeColSpan";
|
||||
import UiPageNations from "./uiPageNations";
|
||||
|
||||
type UiTableProps = {
|
||||
headName: React.ReactNode | undefined;
|
||||
tableData: { [key: string]: string | number | boolean | object}[];
|
||||
tableData: { [key: string]:any}[];
|
||||
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;
|
||||
children?: React.ReactNode | undefined;
|
||||
}
|
||||
|
||||
type UiHeadProps = {
|
||||
@@ -21,7 +22,7 @@ type UiHeadProps = {
|
||||
align?: string;
|
||||
}
|
||||
|
||||
export function UiTable({ tableData, headlist, pageSize, total, children, headName, cellClick, onPageChange, className = '', resetPageNo = false }: UiTableProps) {
|
||||
export function UiTable({ tableData, headlist, pageSize, total, headName, children, cellClick, onPageChange, className = '', resetPageNo = false }: UiTableProps) {
|
||||
const [cur, setCur] = useState<number>(1);
|
||||
const [idx, setIdx] = useState<number>(-1);
|
||||
|
||||
@@ -43,7 +44,7 @@ export function UiTable({ tableData, headlist, pageSize, total, children, headNa
|
||||
setIdx(index);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{headName ? <div className="card-header">
|
||||
@@ -52,30 +53,28 @@ export function UiTable({ tableData, headlist, pageSize, total, children, headNa
|
||||
<div className={`card !m-[1.2rem] !p-0r ${className}`}>
|
||||
<Table variant="secondary">
|
||||
<TableHeader className="font-bold">
|
||||
{children ? <>{children}</> : <TableRow>
|
||||
{headlist?.map((head) => (
|
||||
<TableHead key={head.id}>{head.title}</TableHead>
|
||||
))}
|
||||
</TableRow>}
|
||||
</TableHeader>
|
||||
<TableBody className='text-center'>
|
||||
{tableData?.map((el: { [key: string]: string | number | boolean | object}, index) => (
|
||||
<TableRow key={index + "row"}>
|
||||
{headlist?.map((head) => (
|
||||
<TableCell
|
||||
className={`${head.align === 'right' ? 'text-right' : head.align === 'center' ? 'text-center' : typeof el[head.id] === 'number' ? 'text-right' : 'text-center'} ${
|
||||
cellClick && idx === index ? '!font-[1000] cursor-pointer' :
|
||||
cellClick ? 'cursor-pointer' : ''
|
||||
}`}
|
||||
onClick={() => handleCellClick(index, head.id)}
|
||||
key={head.id + index}
|
||||
>
|
||||
{typeof el[head.id] === 'number' ? String(el[head.id]).replace(/\B(?=(\d{3})+(?!\d))/g, ",") : String(el[head.id] ?? '')}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
{children ? children : <HeadMakeColSpan upHeadList={headlist} />}
|
||||
</TableHeader>
|
||||
<TableBody className='text-center'>
|
||||
{tableData.length > 0 ? tableData?.map((el: { [key: string]: any}, index) => (
|
||||
<TableRow key={`row-${index}`}>
|
||||
{headlist?.map((head) => (
|
||||
head.id && head.id.length > 1 && (
|
||||
<TableCell
|
||||
className={`${head.align === 'right' ? 'text-right' : head.align === 'center' ? 'text-center' : typeof el[head.id] === 'number' ? 'text-right' : 'text-center'} ${
|
||||
cellClick && idx === index ? '!font-[1000] cursor-pointer' :
|
||||
cellClick ? 'cursor-pointer' : ''
|
||||
}`}
|
||||
onClick={() => handleCellClick(index, head.id)}
|
||||
key={`cell-${head.id}-${index}`}
|
||||
>
|
||||
{typeof el[head.id] === 'number' ? String(el[head.id]).replace(/\B(?=(\d{3})+(?!\d))/g, ",") : String(el[head.id] ?? '')}
|
||||
</TableCell>
|
||||
)
|
||||
))}
|
||||
</TableRow>
|
||||
)) : <></>}
|
||||
</TableBody>
|
||||
</Table>
|
||||
{total <= 0 ? <></> : <UiPageNations total={total} cur={cur} pageSize={pageSize} onPageChange={handlePageChange} />}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user