feat(hns): HNS �м� �� UI ���� ? ���� ��Ʈ�� ��ġ ���� �� �м� ���� �������� ���Ǻ� ǥ�� #195
@ -9,10 +9,12 @@
|
|||||||
- 선박: 선박 검색 범위를 전체 캐시 대상으로 확대
|
- 선박: 선박 검색 범위를 전체 캐시 대상으로 확대
|
||||||
- HNS: 정보 레이어 패널 통합 (레이어 표시/불투명도/밝기/색상 제어)
|
- HNS: 정보 레이어 패널 통합 (레이어 표시/불투명도/밝기/색상 제어)
|
||||||
- HNS: 분석 생성 시 유출량·단위·예측 시간·알고리즘·기준 모델 파라미터 전달
|
- HNS: 분석 생성 시 유출량·단위·예측 시간·알고리즘·기준 모델 파라미터 전달
|
||||||
|
- HNS/사건사고: 분석 전용 뷰 모드에서 지도 오버레이 UI 요소 조건부 숨김 처리
|
||||||
|
|
||||||
### 변경
|
### 변경
|
||||||
- InfoLayerSection을 공통 컴포넌트로 이동 (prediction → common/layer)
|
- InfoLayerSection을 공통 컴포넌트로 이동 (prediction → common/layer)
|
||||||
- 기상 탭: 지도 오버레이 컨트롤 위치 우측 상단으로 조정
|
- 기상 탭: 지도 오버레이 컨트롤 위치 우측 상단으로 조정
|
||||||
|
- 지도 공통: 컨트롤 버튼 패널(줌 등) 위치 우측 → 좌측으로 변경
|
||||||
|
|
||||||
### 수정
|
### 수정
|
||||||
- 선박: 라우터 전체에 requireAuth 미들웨어 추가
|
- 선박: 라우터 전체에 requireAuth 미들웨어 추가
|
||||||
|
|||||||
@ -139,8 +139,8 @@ function MapOverlayControls({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* 우측 컨트롤 컬럼 */}
|
{/* 좌측 컨트롤 컬럼 */}
|
||||||
<div className="absolute top-[10px] right-[10px] z-10 flex flex-col gap-1">
|
<div className="absolute top-[10px] left-[10px] z-10 flex flex-col gap-1">
|
||||||
{/* 줌 */}
|
{/* 줌 */}
|
||||||
<button title="줌 인" onClick={() => map?.zoomIn()} className={btn}>
|
<button title="줌 인" onClick={() => map?.zoomIn()} className={btn}>
|
||||||
+
|
+
|
||||||
|
|||||||
@ -183,6 +183,7 @@ export function IncidentsView() {
|
|||||||
// Analysis view mode
|
// Analysis view mode
|
||||||
const [viewMode, setViewMode] = useState<ViewMode>('overlay');
|
const [viewMode, setViewMode] = useState<ViewMode>('overlay');
|
||||||
const [analysisActive, setAnalysisActive] = useState(true);
|
const [analysisActive, setAnalysisActive] = useState(true);
|
||||||
|
const isOverlayMode = !analysisActive || viewMode === 'overlay';
|
||||||
|
|
||||||
// 분할 뷰에서 사용할 체크된 원본 아이템들 (우측 패널에서 주입)
|
// 분할 뷰에서 사용할 체크된 원본 아이템들 (우측 패널에서 주입)
|
||||||
const [checkedPredItems, setCheckedPredItems] = useState<PredictionAnalysis[]>([]);
|
const [checkedPredItems, setCheckedPredItems] = useState<PredictionAnalysis[]>([]);
|
||||||
@ -797,6 +798,7 @@ export function IncidentsView() {
|
|||||||
<BaseMap
|
<BaseMap
|
||||||
center={[35.0, 127.8]}
|
center={[35.0, 127.8]}
|
||||||
zoom={7}
|
zoom={7}
|
||||||
|
showOverlays={isOverlayMode}
|
||||||
cursor={measureMode !== null || dischargeMode ? 'crosshair' : undefined}
|
cursor={measureMode !== null || dischargeMode ? 'crosshair' : undefined}
|
||||||
onMapClick={(lon, lat) => {
|
onMapClick={(lon, lat) => {
|
||||||
if (dischargeMode) {
|
if (dischargeMode) {
|
||||||
@ -845,7 +847,7 @@ export function IncidentsView() {
|
|||||||
</BaseMap>
|
</BaseMap>
|
||||||
|
|
||||||
{/* 선박 검색 */}
|
{/* 선박 검색 */}
|
||||||
{(allRealVessels.length > 0 || realVessels.length > 0) && !dischargeMode && measureMode === null && (
|
{isOverlayMode && (allRealVessels.length > 0 || realVessels.length > 0) && !dischargeMode && measureMode === null && (
|
||||||
<VesselSearchBar
|
<VesselSearchBar
|
||||||
vessels={allRealVessels.length > 0 ? allRealVessels : realVessels}
|
vessels={allRealVessels.length > 0 ? allRealVessels : realVessels}
|
||||||
onFlyTo={(v) => {
|
onFlyTo={(v) => {
|
||||||
@ -856,7 +858,7 @@ export function IncidentsView() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 호버 툴팁 */}
|
{/* 호버 툴팁 */}
|
||||||
{hoverInfo && (
|
{isOverlayMode && hoverInfo && (
|
||||||
<div
|
<div
|
||||||
className="absolute z-[1000] pointer-events-none rounded-md"
|
className="absolute z-[1000] pointer-events-none rounded-md"
|
||||||
style={{
|
style={{
|
||||||
@ -878,7 +880,7 @@ export function IncidentsView() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 오염물 배출 규정 토글 */}
|
{/* 오염물 배출 규정 토글 */}
|
||||||
<button
|
{isOverlayMode && <button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setDischargeMode(!dischargeMode);
|
setDischargeMode(!dischargeMode);
|
||||||
if (dischargeMode) setDischargeInfo(null);
|
if (dischargeMode) setDischargeInfo(null);
|
||||||
@ -886,7 +888,7 @@ export function IncidentsView() {
|
|||||||
className="absolute z-[500] cursor-pointer rounded-md text-caption font-bold font-korean"
|
className="absolute z-[500] cursor-pointer rounded-md text-caption font-bold font-korean"
|
||||||
style={{
|
style={{
|
||||||
top: 10,
|
top: 10,
|
||||||
right: 180,
|
right: 230,
|
||||||
padding: '6px 10px',
|
padding: '6px 10px',
|
||||||
background: 'var(--bg-base)',
|
background: 'var(--bg-base)',
|
||||||
border: '1px solid var(--stroke-default)',
|
border: '1px solid var(--stroke-default)',
|
||||||
@ -896,10 +898,10 @@ export function IncidentsView() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
배출규정 {dischargeMode ? 'ON' : 'OFF'}
|
배출규정 {dischargeMode ? 'ON' : 'OFF'}
|
||||||
</button>
|
</button>}
|
||||||
|
|
||||||
{/* 오염물 배출 규정 패널 */}
|
{/* 오염물 배출 규정 패널 */}
|
||||||
{dischargeMode && dischargeInfo && (
|
{isOverlayMode && dischargeMode && dischargeInfo && (
|
||||||
<DischargeZonePanel
|
<DischargeZonePanel
|
||||||
lat={dischargeInfo.lat}
|
lat={dischargeInfo.lat}
|
||||||
lon={dischargeInfo.lon}
|
lon={dischargeInfo.lon}
|
||||||
@ -910,7 +912,7 @@ export function IncidentsView() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 배출규정 모드 안내 */}
|
{/* 배출규정 모드 안내 */}
|
||||||
{dischargeMode && !dischargeInfo && (
|
{isOverlayMode && dischargeMode && !dischargeInfo && (
|
||||||
<div
|
<div
|
||||||
className="absolute z-[500] rounded-md text-label-2 font-korean font-semibold"
|
className="absolute z-[500] rounded-md text-label-2 font-korean font-semibold"
|
||||||
style={{
|
style={{
|
||||||
@ -930,7 +932,7 @@ export function IncidentsView() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* AIS Live Badge */}
|
{/* AIS Live Badge */}
|
||||||
<div
|
{isOverlayMode && <div
|
||||||
className="absolute top-[10px] right-[10px] z-[500] rounded-md"
|
className="absolute top-[10px] right-[10px] z-[500] rounded-md"
|
||||||
style={{
|
style={{
|
||||||
background: 'var(--bg-base)',
|
background: 'var(--bg-base)',
|
||||||
@ -956,11 +958,11 @@ export function IncidentsView() {
|
|||||||
<div className="text-fg-sub">사고 {filteredIncidents.length}</div>
|
<div className="text-fg-sub">사고 {filteredIncidents.length}</div>
|
||||||
<div className="text-fg-sub">방제선 {vesselStatus?.bangjeCount ?? 0}</div>
|
<div className="text-fg-sub">방제선 {vesselStatus?.bangjeCount ?? 0}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>}
|
||||||
|
|
||||||
{/* Legend */}
|
{/* Legend */}
|
||||||
<div
|
{isOverlayMode && <div
|
||||||
className="absolute bottom-[10px] left-[10px] z-[500] rounded-md flex flex-col gap-1.5"
|
className="absolute bottom-[10px] right-[10px] z-[500] rounded-md flex flex-col gap-1.5"
|
||||||
style={{
|
style={{
|
||||||
background: 'var(--bg-base)',
|
background: 'var(--bg-base)',
|
||||||
border: '1px solid var(--stroke-default)',
|
border: '1px solid var(--stroke-default)',
|
||||||
@ -998,10 +1000,10 @@ export function IncidentsView() {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>}
|
||||||
|
|
||||||
{/* 선박 팝업 패널 */}
|
{/* 선박 팝업 패널 */}
|
||||||
{vesselPopup && selectedVessel && !detailVessel && (
|
{isOverlayMode && vesselPopup && selectedVessel && !detailVessel && (
|
||||||
<VesselPopupPanel
|
<VesselPopupPanel
|
||||||
vessel={selectedVessel}
|
vessel={selectedVessel}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
@ -1015,7 +1017,7 @@ export function IncidentsView() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{detailVessel && (
|
{isOverlayMode && detailVessel && (
|
||||||
<VesselDetailModal vessel={detailVessel} onClose={() => setDetailVessel(null)} />
|
<VesselDetailModal vessel={detailVessel} onClose={() => setDetailVessel(null)} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -324,7 +324,7 @@ export function WeatherView() {
|
|||||||
</BaseMap>
|
</BaseMap>
|
||||||
|
|
||||||
{/* 레이어 컨트롤 */}
|
{/* 레이어 컨트롤 */}
|
||||||
<div className="absolute top-4 left-4 bg-bg-surface border border-stroke rounded-md shadow-md z-10 px-2.5 py-1.5">
|
<div className="absolute top-4 right-4 bg-bg-surface border border-stroke rounded-md shadow-md z-10 px-2.5 py-1.5">
|
||||||
<div className="text-caption font-semibold text-fg mb-1.5 font-korean">기상 레이어</div>
|
<div className="text-caption font-semibold text-fg mb-1.5 font-korean">기상 레이어</div>
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<label className="flex items-center gap-1.5 cursor-pointer">
|
<label className="flex items-center gap-1.5 cursor-pointer">
|
||||||
@ -385,7 +385,7 @@ export function WeatherView() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 범례 */}
|
{/* 범례 */}
|
||||||
<div className="absolute bottom-4 left-4 bg-bg-surface border border-stroke rounded-md shadow-md z-10 px-2.5 py-1.5 max-w-[180px]">
|
<div className="absolute bottom-4 right-4 bg-bg-surface border border-stroke rounded-md shadow-md z-10 px-2.5 py-1.5 max-w-[180px]">
|
||||||
<div className="text-caption text-fg mb-1.5 font-korean">기상 범례</div>
|
<div className="text-caption text-fg mb-1.5 font-korean">기상 범례</div>
|
||||||
<div className="flex flex-col gap-1.5 text-[8px]">
|
<div className="flex flex-col gap-1.5 text-[8px]">
|
||||||
{/* 바람 */}
|
{/* 바람 */}
|
||||||
|
|||||||
불러오는 중...
Reference in New Issue
Block a user