feat(scat): 해안평가 서브메뉴 3개 추가 (해안오염 조사 평가, 해양오염분포도, Pre-SCAT)
- useSubMenu에 scat 서브메뉴 설정 추가 (survey, distribution, pre-scat) - ScatView wrapper 컴포넌트로 서브탭 분기 처리 - SurveyView, DistributionView placeholder 컴포넌트 생성 - hasPermission에 부모 리소스 fallback 로직 추가 (scat:survey → scat) - App.tsx에서 PreScatView → ScatView 교체 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
부모
618d898a6c
커밋
c3d3b82b60
@ -16,7 +16,7 @@ import { BoardView } from '@tabs/board'
|
|||||||
import { WeatherView } from '@tabs/weather'
|
import { WeatherView } from '@tabs/weather'
|
||||||
import { IncidentsView } from '@tabs/incidents'
|
import { IncidentsView } from '@tabs/incidents'
|
||||||
import { AdminView } from '@tabs/admin'
|
import { AdminView } from '@tabs/admin'
|
||||||
import { PreScatView } from '@tabs/scat'
|
import { ScatView } from '@tabs/scat'
|
||||||
import { RescueView } from '@tabs/rescue'
|
import { RescueView } from '@tabs/rescue'
|
||||||
|
|
||||||
const GOOGLE_CLIENT_ID = import.meta.env.VITE_GOOGLE_CLIENT_ID || ''
|
const GOOGLE_CLIENT_ID = import.meta.env.VITE_GOOGLE_CLIENT_ID || ''
|
||||||
@ -92,7 +92,7 @@ function App() {
|
|||||||
case 'incidents':
|
case 'incidents':
|
||||||
return <IncidentsView />
|
return <IncidentsView />
|
||||||
case 'scat':
|
case 'scat':
|
||||||
return <PreScatView />
|
return <ScatView />
|
||||||
case 'admin':
|
case 'admin':
|
||||||
return <AdminView />
|
return <AdminView />
|
||||||
case 'rescue':
|
case 'rescue':
|
||||||
|
|||||||
@ -46,7 +46,11 @@ const subMenuConfigs: Record<MainTab, SubMenuItem[] | null> = {
|
|||||||
{ id: 'theory', label: '항공탐색 이론', icon: '📐' }
|
{ id: 'theory', label: '항공탐색 이론', icon: '📐' }
|
||||||
],
|
],
|
||||||
assets: null,
|
assets: null,
|
||||||
scat: null,
|
scat: [
|
||||||
|
{ id: 'survey', label: '해안오염 조사 평가', icon: '📋' },
|
||||||
|
{ id: 'distribution', label: '해양오염분포도', icon: '🗺' },
|
||||||
|
{ id: 'pre-scat', label: 'Pre-SCAT', icon: '🔍' }
|
||||||
|
],
|
||||||
incidents: null,
|
incidents: null,
|
||||||
board: [
|
board: [
|
||||||
{ id: 'all', label: '전체', icon: '📋' },
|
{ id: 'all', label: '전체', icon: '📋' },
|
||||||
@ -72,7 +76,7 @@ const subMenuState: Record<MainTab, string> = {
|
|||||||
reports: 'report-list',
|
reports: 'report-list',
|
||||||
aerial: 'media',
|
aerial: 'media',
|
||||||
assets: '',
|
assets: '',
|
||||||
scat: '',
|
scat: 'survey',
|
||||||
incidents: '',
|
incidents: '',
|
||||||
board: 'all',
|
board: 'all',
|
||||||
weather: '',
|
weather: '',
|
||||||
|
|||||||
@ -73,9 +73,18 @@ export const useAuthStore = create<AuthState>((set, get) => ({
|
|||||||
hasPermission: (resource: string, operation?: string) => {
|
hasPermission: (resource: string, operation?: string) => {
|
||||||
const { user } = get()
|
const { user } = get()
|
||||||
if (!user) return false
|
if (!user) return false
|
||||||
|
const op = operation ?? 'READ'
|
||||||
|
// 정확한 리소스 권한 확인
|
||||||
const ops = user.permissions[resource]
|
const ops = user.permissions[resource]
|
||||||
if (!ops) return false
|
if (ops) return ops.includes(op)
|
||||||
return ops.includes(operation ?? 'READ')
|
// 'scat:survey' → 부모 'scat' 권한으로 fallback
|
||||||
|
const colonIdx = resource.indexOf(':')
|
||||||
|
if (colonIdx > 0) {
|
||||||
|
const parent = resource.substring(0, colonIdx)
|
||||||
|
const parentOps = user.permissions[parent]
|
||||||
|
if (parentOps) return parentOps.includes(op)
|
||||||
|
}
|
||||||
|
return false
|
||||||
},
|
},
|
||||||
|
|
||||||
clearError: () => set({ error: null, pendingMessage: null }),
|
clearError: () => set({ error: null, pendingMessage: null }),
|
||||||
|
|||||||
13
frontend/src/tabs/scat/components/DistributionView.tsx
Normal file
13
frontend/src/tabs/scat/components/DistributionView.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
function DistributionView() {
|
||||||
|
return (
|
||||||
|
<div className="flex w-full h-full bg-bg-0 items-center justify-center">
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="text-3xl opacity-20 mb-3">🗺</div>
|
||||||
|
<div className="text-sm font-bold text-text-2 font-korean mb-1">해양오염분포도</div>
|
||||||
|
<div className="text-xs text-text-3 font-korean">해양오염 분포도 기능이 준비 중입니다.</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DistributionView;
|
||||||
27
frontend/src/tabs/scat/components/ScatView.tsx
Normal file
27
frontend/src/tabs/scat/components/ScatView.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { useSubMenu } from '@common/hooks/useSubMenu';
|
||||||
|
import { PreScatView } from './PreScatView';
|
||||||
|
import SurveyView from './SurveyView';
|
||||||
|
import DistributionView from './DistributionView';
|
||||||
|
|
||||||
|
export function ScatView() {
|
||||||
|
const { activeSubTab } = useSubMenu('scat');
|
||||||
|
|
||||||
|
const renderContent = () => {
|
||||||
|
switch (activeSubTab) {
|
||||||
|
case 'survey':
|
||||||
|
return <SurveyView />;
|
||||||
|
case 'distribution':
|
||||||
|
return <DistributionView />;
|
||||||
|
case 'pre-scat':
|
||||||
|
return <PreScatView />;
|
||||||
|
default:
|
||||||
|
return <SurveyView />;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col h-full w-full bg-bg-0">
|
||||||
|
<div className="flex-1 overflow-auto">{renderContent()}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
frontend/src/tabs/scat/components/SurveyView.tsx
Normal file
13
frontend/src/tabs/scat/components/SurveyView.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
function SurveyView() {
|
||||||
|
return (
|
||||||
|
<div className="flex w-full h-full bg-bg-0 items-center justify-center">
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="text-3xl opacity-20 mb-3">📋</div>
|
||||||
|
<div className="text-sm font-bold text-text-2 font-korean mb-1">해안오염 조사 평가</div>
|
||||||
|
<div className="text-xs text-text-3 font-korean">해안오염 조사 및 평가 기능이 준비 중입니다.</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SurveyView;
|
||||||
@ -1 +1,2 @@
|
|||||||
export { PreScatView } from './components/PreScatView'
|
export { PreScatView } from './components/PreScatView'
|
||||||
|
export { ScatView } from './components/ScatView'
|
||||||
|
|||||||
불러오는 중...
Reference in New Issue
Block a user