추가 수정사항 반영
1. 페이지네이션, 스크롤, 날짜 선택 ui 추가 2. 공통코드 조회 api 적용 (위성 조회, 등록 팝업 등) 3. 필수값 입력 메세지 추가
This commit is contained in:
부모
1c991d8229
커밋
81255c4839
@ -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{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); }
|
.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 {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); }
|
.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 .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);}
|
.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 {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);}
|
.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;
|
align-items: center;
|
||||||
z-index: 999;
|
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 {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 {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);}
|
.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 { fetchSatelliteVideoList, fetchSatelliteCsvFeatures } from '@/api/satelliteApi';
|
||||||
import { useSatelliteStore } from '@/stores/satelliteStore';
|
import { useSatelliteStore } from '@/stores/satelliteStore';
|
||||||
import { useMapStore } from '@/stores/mapStore';
|
import { useMapStore } from '@/stores/mapStore';
|
||||||
@ -11,6 +12,12 @@ const LIMIT = 10;
|
|||||||
export default function SatelliteImageManage() {
|
export default function SatelliteImageManage() {
|
||||||
const [isAccordionOpen, setIsAccordionOpen] = useState(false);
|
const [isAccordionOpen, setIsAccordionOpen] = useState(false);
|
||||||
|
|
||||||
|
// 공통코드 옵션
|
||||||
|
const [videoKindOptions, setVideoKindOptions] = useState([]);
|
||||||
|
const [videoOriginOptions, setVideoOriginOptions] = useState([]);
|
||||||
|
const [videoOrbitOptions, setVideoOrbitOptions] = useState([]);
|
||||||
|
const [videoCycleOptions, setVideoCycleOptions] = useState([]);
|
||||||
|
|
||||||
// 폼 필터 state
|
// 폼 필터 state
|
||||||
const [startDate, setStartDate] = useState('');
|
const [startDate, setStartDate] = useState('');
|
||||||
const [endDate, setEndDate] = useState('');
|
const [endDate, setEndDate] = useState('');
|
||||||
@ -42,6 +49,14 @@ export default function SatelliteImageManage() {
|
|||||||
const setOpacity = useSatelliteStore((s) => s.setOpacity);
|
const setOpacity = useSatelliteStore((s) => s.setOpacity);
|
||||||
const setBrightness = useSatelliteStore((s) => s.setBrightness);
|
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 toggleAccordion = () => setIsAccordionOpen((prev) => !prev);
|
||||||
|
|
||||||
const search = useCallback(async (targetPage) => {
|
const search = useCallback(async (targetPage) => {
|
||||||
@ -162,11 +177,11 @@ export default function SatelliteImageManage() {
|
|||||||
onChange={(e) => setSatelliteVideoKind(e.target.value)}
|
onChange={(e) => setSatelliteVideoKind(e.target.value)}
|
||||||
>
|
>
|
||||||
<option value="">전체</option>
|
<option value="">전체</option>
|
||||||
<option value="VIRS">VIIRS</option>
|
{videoKindOptions.map((opt) => (
|
||||||
<option value="ICEYE_SAR">ICEYE_SAR</option>
|
<option key={opt.commonCodeTypeNumber} value={opt.commonCodeTypeNumber}>
|
||||||
<option value="광학">광학</option>
|
{opt.commonCodeTypeName}
|
||||||
<option value="예약">예약</option>
|
</option>
|
||||||
<option value="RF">RF</option>
|
))}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
@ -176,10 +191,11 @@ export default function SatelliteImageManage() {
|
|||||||
onChange={(e) => setSatelliteVideoOrigin(e.target.value)}
|
onChange={(e) => setSatelliteVideoOrigin(e.target.value)}
|
||||||
>
|
>
|
||||||
<option value="">전체</option>
|
<option value="">전체</option>
|
||||||
<option value="국내/자동">국내/자동</option>
|
{videoOriginOptions.map((opt) => (
|
||||||
<option value="국내/수동">국내/수동</option>
|
<option key={opt.commonCodeTypeNumber} value={opt.commonCodeTypeNumber}>
|
||||||
<option value="국외/수동">국외/수동</option>
|
{opt.commonCodeTypeName}
|
||||||
<option value="기타">기타</option>
|
</option>
|
||||||
|
))}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
@ -191,10 +207,11 @@ export default function SatelliteImageManage() {
|
|||||||
onChange={(e) => setSatelliteVideoOrbit(e.target.value)}
|
onChange={(e) => setSatelliteVideoOrbit(e.target.value)}
|
||||||
>
|
>
|
||||||
<option value="">전체</option>
|
<option value="">전체</option>
|
||||||
<option value="저궤도">저궤도</option>
|
{videoOrbitOptions.map((opt) => (
|
||||||
<option value="중궤도">중궤도</option>
|
<option key={opt.commonCodeTypeNumber} value={opt.commonCodeTypeNumber}>
|
||||||
<option value="정지궤도">정지궤도</option>
|
{opt.commonCodeTypeName}
|
||||||
<option value="기타">기타</option>
|
</option>
|
||||||
|
))}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
@ -204,10 +221,11 @@ export default function SatelliteImageManage() {
|
|||||||
onChange={(e) => setSatelliteVideoTransmissionCycle(e.target.value)}
|
onChange={(e) => setSatelliteVideoTransmissionCycle(e.target.value)}
|
||||||
>
|
>
|
||||||
<option value="">전체</option>
|
<option value="">전체</option>
|
||||||
<option value="0">0</option>
|
{videoCycleOptions.map((opt) => (
|
||||||
<option value="10">10</option>
|
<option key={opt.commonCodeTypeNumber} value={opt.commonCodeTypeNumber}>
|
||||||
<option value="30">30</option>
|
{opt.commonCodeTypeName}
|
||||||
<option value="60">60</option>
|
</option>
|
||||||
|
))}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
|
import {createPortal} from "react-dom";
|
||||||
|
import { showToast } from '@/components/common/Toast';
|
||||||
import { fetchCommonCodeList } from '@/api/commonApi';
|
import { fetchCommonCodeList } from '@/api/commonApi';
|
||||||
import {
|
import {
|
||||||
|
fetchSatelliteCompanyList,
|
||||||
saveSatelliteManage,
|
saveSatelliteManage,
|
||||||
fetchSatelliteManageDetail,
|
fetchSatelliteManageDetail,
|
||||||
updateSatelliteManage,
|
updateSatelliteManage,
|
||||||
@ -16,6 +19,7 @@ export default function SatelliteManageRegisterPopup({ satelliteManageId, onClos
|
|||||||
const isEditMode = !!satelliteManageId;
|
const isEditMode = !!satelliteManageId;
|
||||||
|
|
||||||
const [sensorTypeOptions, setSensorTypeOptions] = useState([]);
|
const [sensorTypeOptions, setSensorTypeOptions] = useState([]);
|
||||||
|
const [companyOptions, setCompanyOptions] = useState([]);
|
||||||
|
|
||||||
const [companyNo, setCompanyNo] = useState('');
|
const [companyNo, setCompanyNo] = useState('');
|
||||||
const [satelliteName, setSatelliteName] = useState('');
|
const [satelliteName, setSatelliteName] = useState('');
|
||||||
@ -38,9 +42,13 @@ export default function SatelliteManageRegisterPopup({ satelliteManageId, onClos
|
|||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const codeList = await fetchCommonCodeList('000092');
|
const [codeList, companyList] = await Promise.all([
|
||||||
|
fetchCommonCodeList('000092'),
|
||||||
|
fetchSatelliteCompanyList(),
|
||||||
|
]);
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
setSensorTypeOptions(codeList);
|
setSensorTypeOptions(codeList);
|
||||||
|
setCompanyOptions(companyList);
|
||||||
|
|
||||||
if (satelliteManageId) {
|
if (satelliteManageId) {
|
||||||
const data = await fetchSatelliteManageDetail(satelliteManageId);
|
const data = await fetchSatelliteManageDetail(satelliteManageId);
|
||||||
@ -65,6 +73,15 @@ export default function SatelliteManageRegisterPopup({ satelliteManageId, onClos
|
|||||||
}, [satelliteManageId]);
|
}, [satelliteManageId]);
|
||||||
|
|
||||||
const handleSave = async () => {
|
const handleSave = async () => {
|
||||||
|
if (!companyNo) {
|
||||||
|
showToast('사업자명을 선택해주세요.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!satelliteName.trim()) {
|
||||||
|
showToast('위성명을 입력해주세요.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setIsSaving(true);
|
setIsSaving(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
@ -98,134 +115,140 @@ 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="popupUtillWrap" style={{ transform: `translate(calc(-50% + ${position.x}px), calc(-50% + ${position.y}px))` }}>
|
||||||
<div className="popupUtill">
|
<div className="popupUtill">
|
||||||
<div className="puHeader" onMouseDown={handleMouseDown} style={{ cursor: 'grab' }}>
|
<div className="puHeader" onMouseDown={handleMouseDown} style={{ cursor: 'grab' }}>
|
||||||
<span className="title">
|
<span className="title">
|
||||||
{isEditMode ? '위성 관리 상세' : '위성 관리 등록'}
|
{isEditMode ? '위성 관리 상세' : '위성 관리 등록'}
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="puClose"
|
className="puClose"
|
||||||
aria-label="닫기"
|
aria-label="닫기"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="puBody">
|
<div className="puBody">
|
||||||
{isLoading && <div className="loading">조회 중...</div>}
|
{isLoading && <div className="loading">조회 중...</div>}
|
||||||
{error && <div className="error">{error}</div>}
|
{error && <div className="error">{error}</div>}
|
||||||
|
|
||||||
{!isLoading && (
|
{!isLoading && (
|
||||||
<table className="table">
|
<table className="table">
|
||||||
<caption>위성 관리 등록 - 사업자명, 위성명, 센서 타입, 촬영 해상도, 주파수, 상세내역에 대한 내용을 등록하는 표입니다.</caption>
|
<caption>위성 관리 등록 - 사업자명, 위성명, 센서 타입, 촬영 해상도, 주파수, 상세내역에 대한 내용을 등록하는 표입니다.</caption>
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col style={{ width: '30%' }} />
|
<col style={{ width: '30%' }} />
|
||||||
<col style={{ width: '' }} />
|
<col style={{ width: '' }} />
|
||||||
</colgroup>
|
</colgroup>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">사업자명 <span className="required">*</span></th>
|
<th scope="row">사업자명 <span className="required">*</span></th>
|
||||||
<td>
|
<td>
|
||||||
<input
|
<select
|
||||||
type="text"
|
aria-label="사업자명"
|
||||||
placeholder="사업자명"
|
value={companyNo}
|
||||||
aria-label="사업자명"
|
onChange={(e) => setCompanyNo(e.target.value)}
|
||||||
value={companyNo}
|
>
|
||||||
onChange={(e) => setCompanyNo(e.target.value)}
|
<option value="">선택</option>
|
||||||
/>
|
{companyOptions.map((opt) => (
|
||||||
</td>
|
<option key={opt.companyNo} value={opt.companyNo}>
|
||||||
</tr>
|
{opt.companyName}
|
||||||
<tr>
|
</option>
|
||||||
<th scope="row">위성명 <span className="required">*</span></th>
|
))}
|
||||||
<td>
|
</select>
|
||||||
<input
|
</td>
|
||||||
type="text"
|
</tr>
|
||||||
placeholder="위성명"
|
<tr>
|
||||||
aria-label="위성명"
|
<th scope="row">위성명 <span className="required">*</span></th>
|
||||||
value={satelliteName}
|
<td>
|
||||||
onChange={(e) => setSatelliteName(e.target.value)}
|
<input
|
||||||
/>
|
type="text"
|
||||||
</td>
|
placeholder="위성명"
|
||||||
</tr>
|
aria-label="위성명"
|
||||||
<tr>
|
value={satelliteName}
|
||||||
<th scope="row">센서 타입</th>
|
onChange={(e) => setSatelliteName(e.target.value)}
|
||||||
<td>
|
/>
|
||||||
<select
|
</td>
|
||||||
aria-label="센서 타입"
|
</tr>
|
||||||
value={sensorType}
|
<tr>
|
||||||
onChange={(e) => setSensorType(e.target.value)}
|
<th scope="row">센서 타입</th>
|
||||||
>
|
<td>
|
||||||
<option value="">선택</option>
|
<select
|
||||||
{sensorTypeOptions.map((opt) => (
|
aria-label="센서 타입"
|
||||||
<option key={opt.commonCodeTypeNumber} value={opt.commonCodeTypeNumber}>
|
value={sensorType}
|
||||||
{opt.commonCodeTypeName}
|
onChange={(e) => setSensorType(e.target.value)}
|
||||||
</option>
|
>
|
||||||
))}
|
<option value="">선택</option>
|
||||||
</select>
|
{sensorTypeOptions.map((opt) => (
|
||||||
</td>
|
<option key={opt.commonCodeTypeNumber} value={opt.commonCodeTypeNumber}>
|
||||||
</tr>
|
{opt.commonCodeTypeName}
|
||||||
<tr>
|
</option>
|
||||||
<th scope="row">촬영 해상도</th>
|
))}
|
||||||
<td>
|
</select>
|
||||||
<input
|
</td>
|
||||||
type="text"
|
</tr>
|
||||||
placeholder="촬영 해상도"
|
<tr>
|
||||||
aria-label="촬영 해상도"
|
<th scope="row">촬영 해상도</th>
|
||||||
value={photoResolution}
|
<td>
|
||||||
onChange={(e) => setPhotoResolution(e.target.value)}
|
<input
|
||||||
/>
|
type="text"
|
||||||
</td>
|
placeholder="촬영 해상도"
|
||||||
</tr>
|
aria-label="촬영 해상도"
|
||||||
<tr>
|
value={photoResolution}
|
||||||
<th scope="row">주파수</th>
|
onChange={(e) => setPhotoResolution(e.target.value)}
|
||||||
<td>
|
/>
|
||||||
<input
|
</td>
|
||||||
type="text"
|
</tr>
|
||||||
placeholder="주파수"
|
<tr>
|
||||||
aria-label="주파수"
|
<th scope="row">주파수</th>
|
||||||
value={frequency}
|
<td>
|
||||||
onChange={(e) => setFrequency(e.target.value)}
|
<input
|
||||||
/>
|
type="text"
|
||||||
</td>
|
placeholder="주파수"
|
||||||
</tr>
|
aria-label="주파수"
|
||||||
<tr>
|
value={frequency}
|
||||||
<th scope="row">상세내역</th>
|
onChange={(e) => setFrequency(e.target.value)}
|
||||||
<td>
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">상세내역</th>
|
||||||
|
<td>
|
||||||
<textarea
|
<textarea
|
||||||
placeholder="내용을 입력하세요"
|
placeholder="내용을 입력하세요"
|
||||||
aria-label="상세내역"
|
aria-label="상세내역"
|
||||||
value={photoDetail}
|
value={photoDetail}
|
||||||
onChange={(e) => setPhotoDetail(e.target.value)}
|
onChange={(e) => setPhotoDetail(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="puFooter">
|
<div className="puFooter">
|
||||||
<div className="popBtnWrap">
|
<div className="popBtnWrap">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn basic"
|
className="btn basic"
|
||||||
onClick={handleSave}
|
onClick={handleSave}
|
||||||
disabled={isSaving}
|
disabled={isSaving}
|
||||||
>
|
>
|
||||||
{isSaving ? '저장 중...' : isEditMode ? '수정' : '저장'}
|
{isSaving ? '저장 중...' : isEditMode ? '수정' : '저장'}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn dark"
|
className="btn dark"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
>
|
>
|
||||||
취소
|
취소
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>,
|
||||||
</div>
|
document.body
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
|
import {createPortal} from "react-dom";
|
||||||
|
import { showToast } from '@/components/common/Toast';
|
||||||
import { fetchCommonCodeList } from '@/api/commonApi';
|
import { fetchCommonCodeList } from '@/api/commonApi';
|
||||||
import {
|
import {
|
||||||
saveSatelliteCompany,
|
saveSatelliteCompany,
|
||||||
@ -56,13 +58,13 @@ export default function SatelliteProviderRegisterPopup({ companyNo, onClose, onS
|
|||||||
|
|
||||||
// companyTypeName → companyTypeCode 역매핑
|
// companyTypeName → companyTypeCode 역매핑
|
||||||
const matchedType = codeList.find(
|
const matchedType = codeList.find(
|
||||||
(opt) => opt.commonCodeTypeName === data.companyTypeName
|
(opt) => opt.commonCodeTypeName === data.companyTypeName
|
||||||
);
|
);
|
||||||
setCompanyTypeCode(matchedType?.commonCodeTypeNumber || '');
|
setCompanyTypeCode(matchedType?.commonCodeTypeNumber || '');
|
||||||
|
|
||||||
// nationalCodeName → nationalCode 역매핑
|
// nationalCodeName → nationalCode 역매핑
|
||||||
const matchedNation = NATIONAL_OPTIONS.find(
|
const matchedNation = NATIONAL_OPTIONS.find(
|
||||||
(opt) => opt.name === data.nationalCodeName
|
(opt) => opt.name === data.nationalCodeName
|
||||||
);
|
);
|
||||||
setNationalCode(matchedNation?.code || '');
|
setNationalCode(matchedNation?.code || '');
|
||||||
|
|
||||||
@ -82,6 +84,19 @@ export default function SatelliteProviderRegisterPopup({ companyNo, onClose, onS
|
|||||||
}, [companyNo]);
|
}, [companyNo]);
|
||||||
|
|
||||||
const handleSave = async () => {
|
const handleSave = async () => {
|
||||||
|
if (!companyTypeCode) {
|
||||||
|
showToast('사업자 분류를 선택해주세요.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!companyName.trim()) {
|
||||||
|
showToast('사업자명을 입력해주세요.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!nationalCode) {
|
||||||
|
showToast('국가를 선택해주세요.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setIsSaving(true);
|
setIsSaving(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
@ -113,129 +128,130 @@ 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="popupUtillWrap" style={{ transform: `translate(calc(-50% + ${position.x}px), calc(-50% + ${position.y}px))` }}>
|
||||||
<div className="popupUtill">
|
<div className="popupUtill">
|
||||||
<div className="puHeader" onMouseDown={handleMouseDown} style={{ cursor: 'grab' }}>
|
<div className="puHeader" onMouseDown={handleMouseDown} style={{ cursor: 'grab' }}>
|
||||||
<span className="title">
|
<span className="title">
|
||||||
{isEditMode ? '위성 사업자 상세' : '위성 사업자 등록'}
|
{isEditMode ? '위성 사업자 상세' : '위성 사업자 등록'}
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="puClose"
|
className="puClose"
|
||||||
aria-label="닫기"
|
aria-label="닫기"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="puBody">
|
<div className="puBody">
|
||||||
{isLoading && <div className="loading">조회 중...</div>}
|
{isLoading && <div className="loading">조회 중...</div>}
|
||||||
{error && <div className="error">{error}</div>}
|
{error && <div className="error">{error}</div>}
|
||||||
|
|
||||||
{!isLoading && (
|
{!isLoading && (
|
||||||
<table className="table">
|
<table className="table">
|
||||||
<caption>
|
<caption>
|
||||||
위성 사업자 {isEditMode ? '상세' : '등록'} - 사업자 분류, 사업자명, 국가, 소재지, 상세내역에 대한 내용을 {isEditMode ? '조회/수정' : '등록'}하는 표입니다.
|
위성 사업자 {isEditMode ? '상세' : '등록'} - 사업자 분류, 사업자명, 국가, 소재지, 상세내역에 대한 내용을 {isEditMode ? '조회/수정' : '등록'}하는 표입니다.
|
||||||
</caption>
|
</caption>
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col style={{ width: '30%' }} />
|
<col style={{ width: '30%' }} />
|
||||||
<col style={{ width: '' }} />
|
<col style={{ width: '' }} />
|
||||||
</colgroup>
|
</colgroup>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">사업자 분류 <span className="required">*</span></th>
|
<th scope="row">사업자 분류 <span className="required">*</span></th>
|
||||||
<td>
|
<td>
|
||||||
<select
|
<select
|
||||||
aria-label="사업자 분류"
|
aria-label="사업자 분류"
|
||||||
value={companyTypeCode}
|
value={companyTypeCode}
|
||||||
onChange={(e) => setCompanyTypeCode(e.target.value)}
|
onChange={(e) => setCompanyTypeCode(e.target.value)}
|
||||||
>
|
>
|
||||||
<option value="">선택</option>
|
<option value="">선택</option>
|
||||||
{companyTypeOptions.map((opt) => (
|
{companyTypeOptions.map((opt) => (
|
||||||
<option key={opt.commonCodeTypeNumber} value={opt.commonCodeTypeNumber}>
|
<option key={opt.commonCodeTypeNumber} value={opt.commonCodeTypeNumber}>
|
||||||
{opt.commonCodeTypeName}
|
{opt.commonCodeTypeName}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">사업자명 <span className="required">*</span></th>
|
<th scope="row">사업자명 <span className="required">*</span></th>
|
||||||
<td>
|
<td>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="사업자명"
|
placeholder="사업자명"
|
||||||
aria-label="사업자명"
|
aria-label="사업자명"
|
||||||
value={companyName}
|
value={companyName}
|
||||||
onChange={(e) => setCompanyName(e.target.value)}
|
onChange={(e) => setCompanyName(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">국가 <span className="required">*</span></th>
|
<th scope="row">국가 <span className="required">*</span></th>
|
||||||
<td>
|
<td>
|
||||||
<select
|
<select
|
||||||
aria-label="국가"
|
aria-label="국가"
|
||||||
value={nationalCode}
|
value={nationalCode}
|
||||||
onChange={(e) => setNationalCode(e.target.value)}
|
onChange={(e) => setNationalCode(e.target.value)}
|
||||||
>
|
>
|
||||||
<option value="">선택</option>
|
<option value="">선택</option>
|
||||||
{NATIONAL_OPTIONS.map((opt) => (
|
{NATIONAL_OPTIONS.map((opt) => (
|
||||||
<option key={opt.code} value={opt.code}>
|
<option key={opt.code} value={opt.code}>
|
||||||
{opt.name}
|
{opt.name}
|
||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">소재지</th>
|
<th scope="row">소재지</th>
|
||||||
<td>
|
<td>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="소재지"
|
placeholder="소재지"
|
||||||
aria-label="소재지"
|
aria-label="소재지"
|
||||||
value={location}
|
value={location}
|
||||||
onChange={(e) => setLocation(e.target.value)}
|
onChange={(e) => setLocation(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">상세내역</th>
|
<th scope="row">상세내역</th>
|
||||||
<td>
|
<td>
|
||||||
<textarea
|
<textarea
|
||||||
placeholder="내용을 입력하세요"
|
placeholder="내용을 입력하세요"
|
||||||
aria-label="상세내역"
|
aria-label="상세내역"
|
||||||
value={companyDetail}
|
value={companyDetail}
|
||||||
onChange={(e) => setCompanyDetail(e.target.value)}
|
onChange={(e) => setCompanyDetail(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="puFooter">
|
<div className="puFooter">
|
||||||
<div className="popBtnWrap">
|
<div className="popBtnWrap">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn basic"
|
className="btn basic"
|
||||||
onClick={handleSave}
|
onClick={handleSave}
|
||||||
disabled={isSaving}
|
disabled={isSaving}
|
||||||
>
|
>
|
||||||
{isSaving ? '저장 중...' : isEditMode ? '수정' : '저장'}
|
{isSaving ? '저장 중...' : isEditMode ? '수정' : '저장'}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn dark"
|
className="btn dark"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
>
|
>
|
||||||
취소
|
취소
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>,
|
||||||
</div>
|
document.body
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
|
import {createPortal} from "react-dom";
|
||||||
|
import { showToast } from '@/components/common/Toast';
|
||||||
import {
|
import {
|
||||||
fetchSatelliteCompanyList,
|
fetchSatelliteCompanyList,
|
||||||
fetchSatelliteManageList,
|
fetchSatelliteManageList,
|
||||||
@ -120,6 +122,23 @@ export default function SatelliteRegisterPopup({ satelliteId, onClose, onSaved }
|
|||||||
}, [companyNo, isEditMode]);
|
}, [companyNo, isEditMode]);
|
||||||
|
|
||||||
const handleSave = async () => {
|
const handleSave = async () => {
|
||||||
|
if (!isEditMode && !satelliteManageId) {
|
||||||
|
showToast('사업자명/위성명을 선택해주세요.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!photographDate) {
|
||||||
|
showToast('영상 촬영일을 입력해주세요.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!isEditMode && !tifFile) {
|
||||||
|
showToast('위성영상파일을 선택해주세요.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!satelliteVideoName.trim()) {
|
||||||
|
showToast('위성영상명을 입력해주세요.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setIsSaving(true);
|
setIsSaving(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
@ -172,7 +191,7 @@ export default function SatelliteRegisterPopup({ satelliteId, onClose, onSaved }
|
|||||||
// setPhotographDate(changedFormat);
|
// setPhotographDate(changedFormat);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
return (
|
return createPortal(
|
||||||
<div className="popupUtillWrap" style={{ transform: `translate(calc(-50% + ${position.x}px), calc(-50% + ${position.y}px))` }}>
|
<div className="popupUtillWrap" style={{ transform: `translate(calc(-50% + ${position.x}px), calc(-50% + ${position.y}px))` }}>
|
||||||
<div className="popupUtill w61r">
|
<div className="popupUtill w61r">
|
||||||
<div className="puHeader" onMouseDown={handleMouseDown} style={{ cursor: 'grab' }}>
|
<div className="puHeader" onMouseDown={handleMouseDown} style={{ cursor: 'grab' }}>
|
||||||
@ -478,6 +497,7 @@ export default function SatelliteRegisterPopup({ satelliteId, onClose, onSaved }
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</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 {
|
.toogle {
|
||||||
|
|||||||
불러오는 중...
Reference in New Issue
Block a user