diff --git a/public/css/common.css b/public/css/common.css index 6f7b459c..2c5e9079 100644 --- a/public/css/common.css +++ b/public/css/common.css @@ -71,6 +71,8 @@ .schInput{height: 3.5rem; font-family: 'NanumSquare', sans-serif;font-size: var(--fs-m); color: var(--white);background-color: var(--tertiary1);padding: 0 1.2rem; border: 0;} .schInput::placeholder { color:rgba(var(--white-rgb),.3); } .dateInput {background:url(../images/ico_input_cal.svg) no-repeat center right .5rem/2.4rem; padding-right: 3rem; cursor: pointer;} +.dateInput { position: relative; } +.dateInput::-webkit-calendar-picker-indicator { opacity: 0; position: absolute; right: 0; width: 3rem; height: 100%;cursor: pointer; } .dateInput::placeholder { color:var(--white); } /* ========================= @@ -107,6 +109,15 @@ .colList.lineSB li a .title {font-size: var(--fs-m); font-weight: var(--fw-bold);} .colList.lineSB li a .meta {font-size: var(--fs-s); font-weight: var(--fw-regular); color:rgba(var(--white-rgb),.5);} +/* 페이지네이션 */ +.pagination {display: flex; align-items: center; justify-content: center; gap: .5rem; padding: 1.4rem 0;} +.pagination button {min-width: 2.8rem; height: 2.8rem; padding: 0 .6rem; border-radius: .4rem; background-color: var(--secondary1); color: var(--white); font-size: var(--fs-m); font-weight: var(--fw-bold); border: 1px solid var(--secondary3); cursor: pointer; transition: background-color .15s ease, border-color .15s ease;} +.pagination button:hover {background-color: var(--secondary3); border-color: var(--secondary4);} +.pagination button.on {background-color: var(--primary1); border-color: var(--primary1);} +.pagination button.on:hover {background-color: var(--primary2); border-color: var(--primary2);} +.pagination button.disabled {opacity: 0.4; cursor: default; pointer-events: none;} +.pagination .ellipsis {color: rgba(var(--white-rgb), .4); font-size: var(--fs-m); padding: 0 .2rem; user-select: none;} + /* 아코디언리스트 */ .accordionWrap {display: flex;flex-direction: column;transition: max-height 0.3s ease;} .accordionWrap .acdHeader {display: flex; justify-content: space-between; align-items: center; height: 4rem; background-color: var(--secondary1); padding: 1rem; border-bottom: .1rem solid var(--secondary3);} @@ -292,7 +303,7 @@ align-items: center; z-index: 999; } -.popupUtillWrap { position: absolute;top: 50%; left: 50%;transform: translate(-50%, -50%);z-index :85;} +.popupUtillWrap { position: fixed;top: 50%; left: 50%;transform: translate(-50%, -50%);z-index :100;} .popupUtill {display: flex; flex-direction: column; width: 52.5rem; height:auto;max-height: 80vh;overflow: hidden; background-color: var(--secondary2); border: .1rem solid var(--secondary3); padding:2.5rem 3rem;} .popupUtill > .puHeader {display: flex; justify-content: space-between; align-items: center; padding-bottom: 2rem;} .popupUtill > .puHeader > .title {font-weight: var(--fw-bold); font-size: var(--fs-xl);} diff --git a/src/satellite/components/SatelliteImageManage.jsx b/src/satellite/components/SatelliteImageManage.jsx index 4e909e7a..4dc146db 100644 --- a/src/satellite/components/SatelliteImageManage.jsx +++ b/src/satellite/components/SatelliteImageManage.jsx @@ -1,4 +1,5 @@ -import { useState, useCallback } from 'react'; +import { useState, useEffect, useCallback } from 'react'; +import { fetchCommonCodeList } from '@/api/commonApi'; import { fetchSatelliteVideoList, fetchSatelliteCsvFeatures } from '@/api/satelliteApi'; import { useSatelliteStore } from '@/stores/satelliteStore'; import { useMapStore } from '@/stores/mapStore'; @@ -11,6 +12,12 @@ const LIMIT = 10; export default function SatelliteImageManage() { const [isAccordionOpen, setIsAccordionOpen] = useState(false); + // 공통코드 옵션 + const [videoKindOptions, setVideoKindOptions] = useState([]); + const [videoOriginOptions, setVideoOriginOptions] = useState([]); + const [videoOrbitOptions, setVideoOrbitOptions] = useState([]); + const [videoCycleOptions, setVideoCycleOptions] = useState([]); + // 폼 필터 state const [startDate, setStartDate] = useState(''); const [endDate, setEndDate] = useState(''); @@ -42,6 +49,14 @@ export default function SatelliteImageManage() { const setOpacity = useSatelliteStore((s) => s.setOpacity); const setBrightness = useSatelliteStore((s) => s.setBrightness); + // 마운트 시 공통코드 로드 + useEffect(() => { + fetchCommonCodeList('000109').then(setVideoKindOptions).catch(() => setVideoKindOptions([])); + fetchCommonCodeList('000111').then(setVideoOriginOptions).catch(() => setVideoOriginOptions([])); + fetchCommonCodeList('000110').then(setVideoOrbitOptions).catch(() => setVideoOrbitOptions([])); + fetchCommonCodeList('000108').then(setVideoCycleOptions).catch(() => setVideoCycleOptions([])); + }, []); + const toggleAccordion = () => setIsAccordionOpen((prev) => !prev); const search = useCallback(async (targetPage) => { @@ -162,11 +177,11 @@ export default function SatelliteImageManage() { onChange={(e) => setSatelliteVideoKind(e.target.value)} > - - - - - + {videoKindOptions.map((opt) => ( + + ))} @@ -191,10 +207,11 @@ export default function SatelliteImageManage() { onChange={(e) => setSatelliteVideoOrbit(e.target.value)} > - - - - + {videoOrbitOptions.map((opt) => ( + + ))} diff --git a/src/satellite/components/SatelliteManageRegisterPopup.jsx b/src/satellite/components/SatelliteManageRegisterPopup.jsx index 23ef156c..8f787f1c 100644 --- a/src/satellite/components/SatelliteManageRegisterPopup.jsx +++ b/src/satellite/components/SatelliteManageRegisterPopup.jsx @@ -1,6 +1,9 @@ import { useState, useEffect } from 'react'; +import {createPortal} from "react-dom"; +import { showToast } from '@/components/common/Toast'; import { fetchCommonCodeList } from '@/api/commonApi'; import { + fetchSatelliteCompanyList, saveSatelliteManage, fetchSatelliteManageDetail, updateSatelliteManage, @@ -16,6 +19,7 @@ export default function SatelliteManageRegisterPopup({ satelliteManageId, onClos const isEditMode = !!satelliteManageId; const [sensorTypeOptions, setSensorTypeOptions] = useState([]); + const [companyOptions, setCompanyOptions] = useState([]); const [companyNo, setCompanyNo] = useState(''); const [satelliteName, setSatelliteName] = useState(''); @@ -38,9 +42,13 @@ export default function SatelliteManageRegisterPopup({ satelliteManageId, onClos setError(null); try { - const codeList = await fetchCommonCodeList('000092'); + const [codeList, companyList] = await Promise.all([ + fetchCommonCodeList('000092'), + fetchSatelliteCompanyList(), + ]); if (cancelled) return; setSensorTypeOptions(codeList); + setCompanyOptions(companyList); if (satelliteManageId) { const data = await fetchSatelliteManageDetail(satelliteManageId); @@ -65,6 +73,15 @@ export default function SatelliteManageRegisterPopup({ satelliteManageId, onClos }, [satelliteManageId]); const handleSave = async () => { + if (!companyNo) { + showToast('사업자명을 선택해주세요.'); + return; + } + if (!satelliteName.trim()) { + showToast('위성명을 입력해주세요.'); + return; + } + setIsSaving(true); setError(null); @@ -98,134 +115,140 @@ export default function SatelliteManageRegisterPopup({ satelliteManageId, onClos } }; - return ( -
-
-
+ return createPortal( +
+
+
{isEditMode ? '위성 관리 상세' : '위성 관리 등록'} -
+
-
- {isLoading &&
조회 중...
} - {error &&
{error}
} +
+ {isLoading &&
조회 중...
} + {error &&
{error}
} - {!isLoading && ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
위성 관리 등록 - 사업자명, 위성명, 센서 타입, 촬영 해상도, 주파수, 상세내역에 대한 내용을 등록하는 표입니다.
사업자명 * - setCompanyNo(e.target.value)} - /> -
위성명 * - setSatelliteName(e.target.value)} - /> -
센서 타입 - -
촬영 해상도 - setPhotoResolution(e.target.value)} - /> -
주파수 - setFrequency(e.target.value)} - /> -
상세내역 + {!isLoading && ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
위성 관리 등록 - 사업자명, 위성명, 센서 타입, 촬영 해상도, 주파수, 상세내역에 대한 내용을 등록하는 표입니다.
사업자명 * + +
위성명 * + setSatelliteName(e.target.value)} + /> +
센서 타입 + +
촬영 해상도 + setPhotoResolution(e.target.value)} + /> +
주파수 + setFrequency(e.target.value)} + /> +
상세내역