추가 수정사항 반영

1. 페이지네이션, 스크롤, 날짜 선택 ui 추가
2. 공통코드 조회 api 적용 (위성 조회, 등록 팝업 등)
3. 필수값 입력 메세지 추가
This commit is contained in:
jeonghyo.K 2026-02-11 16:49:26 +09:00
부모 1c991d8229
커밋 81255c4839
6개의 변경된 파일369개의 추가작업 그리고 257개의 파일을 삭제

파일 보기

@ -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);}

파일 보기

@ -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)}
>
<option value="">전체</option>
<option value="VIRS">VIIRS</option>
<option value="ICEYE_SAR">ICEYE_SAR</option>
<option value="광학">광학</option>
<option value="예약">예약</option>
<option value="RF">RF</option>
{videoKindOptions.map((opt) => (
<option key={opt.commonCodeTypeNumber} value={opt.commonCodeTypeNumber}>
{opt.commonCodeTypeName}
</option>
))}
</select>
</label>
<label>
@ -176,10 +191,11 @@ export default function SatelliteImageManage() {
onChange={(e) => setSatelliteVideoOrigin(e.target.value)}
>
<option value="">전체</option>
<option value="국내/자동">국내/자동</option>
<option value="국내/수동">국내/수동</option>
<option value="국외/수동">국외/수동</option>
<option value="기타">기타</option>
{videoOriginOptions.map((opt) => (
<option key={opt.commonCodeTypeNumber} value={opt.commonCodeTypeNumber}>
{opt.commonCodeTypeName}
</option>
))}
</select>
</label>
</li>
@ -191,10 +207,11 @@ export default function SatelliteImageManage() {
onChange={(e) => setSatelliteVideoOrbit(e.target.value)}
>
<option value="">전체</option>
<option value="저궤도">저궤도</option>
<option value="중궤도">중궤도</option>
<option value="정지궤도">정지궤도</option>
<option value="기타">기타</option>
{videoOrbitOptions.map((opt) => (
<option key={opt.commonCodeTypeNumber} value={opt.commonCodeTypeNumber}>
{opt.commonCodeTypeName}
</option>
))}
</select>
</label>
<label>
@ -204,10 +221,11 @@ export default function SatelliteImageManage() {
onChange={(e) => setSatelliteVideoTransmissionCycle(e.target.value)}
>
<option value="">전체</option>
<option value="0">0</option>
<option value="10">10</option>
<option value="30">30</option>
<option value="60">60</option>
{videoCycleOptions.map((opt) => (
<option key={opt.commonCodeTypeNumber} value={opt.commonCodeTypeNumber}>
{opt.commonCodeTypeName}
</option>
))}
</select>
</label>
</li>

파일 보기

@ -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,7 +115,7 @@ export default function SatelliteManageRegisterPopup({ satelliteManageId, onClos
}
};
return (
return createPortal(
<div className="popupUtillWrap" style={{ transform: `translate(calc(-50% + ${position.x}px), calc(-50% + ${position.y}px))` }}>
<div className="popupUtill">
<div className="puHeader" onMouseDown={handleMouseDown} style={{ cursor: 'grab' }}>
@ -128,13 +145,18 @@ export default function SatelliteManageRegisterPopup({ satelliteManageId, onClos
<tr>
<th scope="row">사업자명 <span className="required">*</span></th>
<td>
<input
type="text"
placeholder="사업자명"
<select
aria-label="사업자명"
value={companyNo}
onChange={(e) => setCompanyNo(e.target.value)}
/>
>
<option value="">선택</option>
{companyOptions.map((opt) => (
<option key={opt.companyNo} value={opt.companyNo}>
{opt.companyName}
</option>
))}
</select>
</td>
</tr>
<tr>
@ -226,6 +248,7 @@ export default function SatelliteManageRegisterPopup({ satelliteManageId, onClos
</div>
</div>
</div>
</div>
</div>,
document.body
);
}

파일 보기

@ -1,4 +1,6 @@
import { useState, useEffect } from 'react';
import {createPortal} from "react-dom";
import { showToast } from '@/components/common/Toast';
import { fetchCommonCodeList } from '@/api/commonApi';
import {
saveSatelliteCompany,
@ -82,6 +84,19 @@ export default function SatelliteProviderRegisterPopup({ companyNo, onClose, onS
}, [companyNo]);
const handleSave = async () => {
if (!companyTypeCode) {
showToast('사업자 분류를 선택해주세요.');
return;
}
if (!companyName.trim()) {
showToast('사업자명을 입력해주세요.');
return;
}
if (!nationalCode) {
showToast('국가를 선택해주세요.');
return;
}
setIsSaving(true);
setError(null);
@ -113,7 +128,7 @@ export default function SatelliteProviderRegisterPopup({ companyNo, onClose, onS
}
};
return (
return createPortal(
<div className="popupUtillWrap" style={{ transform: `translate(calc(-50% + ${position.x}px), calc(-50% + ${position.y}px))` }}>
<div className="popupUtill">
<div className="puHeader" onMouseDown={handleMouseDown} style={{ cursor: 'grab' }}>
@ -236,6 +251,7 @@ export default function SatelliteProviderRegisterPopup({ companyNo, onClose, onS
</div>
</div>
</div>
</div>
</div>,
document.body
);
}

파일 보기

@ -1,4 +1,6 @@
import { useState, useEffect } from 'react';
import {createPortal} from "react-dom";
import { showToast } from '@/components/common/Toast';
import {
fetchSatelliteCompanyList,
fetchSatelliteManageList,
@ -120,6 +122,23 @@ export default function SatelliteRegisterPopup({ satelliteId, onClose, onSaved }
}, [companyNo, isEditMode]);
const handleSave = async () => {
if (!isEditMode && !satelliteManageId) {
showToast('사업자명/위성명을 선택해주세요.');
return;
}
if (!photographDate) {
showToast('영상 촬영일을 입력해주세요.');
return;
}
if (!isEditMode && !tifFile) {
showToast('위성영상파일을 선택해주세요.');
return;
}
if (!satelliteVideoName.trim()) {
showToast('위성영상명을 입력해주세요.');
return;
}
setIsSaving(true);
setError(null);
@ -172,7 +191,7 @@ export default function SatelliteRegisterPopup({ satelliteId, onClose, onSaved }
// setPhotographDate(changedFormat);
// }
return (
return createPortal(
<div className="popupUtillWrap" style={{ transform: `translate(calc(-50% + ${position.x}px), calc(-50% + ${position.y}px))` }}>
<div className="popupUtill w61r">
<div className="puHeader" onMouseDown={handleMouseDown} style={{ cursor: 'grab' }}>
@ -478,6 +497,7 @@ export default function SatelliteRegisterPopup({ satelliteId, onClose, onSaved }
</div>
</div>
</div>
</div>
</div>,
document.body
);
}

파일 보기

@ -416,6 +416,30 @@
}
}
// 위성/기상 메뉴 스크롤바 다크 테마
.tabBtm,
.tabBtmCnt {
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background: rgba(var(--white-rgb), 0.3);
border-radius: 3px;
&:hover {
background: rgba(var(--white-rgb), 0.5);
}
}
scrollbar-width: thin;
scrollbar-color: rgba(255, 255, 255, 0.3) transparent;
}
}
.toogle {