feature/cctv-hns-enhancements #70

병합
nankyung feature/cctv-hns-enhancements 에서 develop 로 8 commits 를 머지했습니다 2026-03-06 07:38:26 +09:00
7개의 변경된 파일73개의 추가작업 그리고 6개의 파일을 삭제
Showing only changes of commit c3d3b82b60 - Show all commits

파일 보기

@ -16,7 +16,7 @@ import { BoardView } from '@tabs/board'
import { WeatherView } from '@tabs/weather'
import { IncidentsView } from '@tabs/incidents'
import { AdminView } from '@tabs/admin'
import { PreScatView } from '@tabs/scat'
import { ScatView } from '@tabs/scat'
import { RescueView } from '@tabs/rescue'
const GOOGLE_CLIENT_ID = import.meta.env.VITE_GOOGLE_CLIENT_ID || ''
@ -92,7 +92,7 @@ function App() {
case 'incidents':
return <IncidentsView />
case 'scat':
return <PreScatView />
return <ScatView />
case 'admin':
return <AdminView />
case 'rescue':

파일 보기

@ -46,7 +46,11 @@ const subMenuConfigs: Record<MainTab, SubMenuItem[] | null> = {
{ id: 'theory', label: '항공탐색 이론', icon: '📐' }
],
assets: null,
scat: null,
scat: [
{ id: 'survey', label: '해안오염 조사 평가', icon: '📋' },
{ id: 'distribution', label: '해양오염분포도', icon: '🗺' },
{ id: 'pre-scat', label: 'Pre-SCAT', icon: '🔍' }
],
incidents: null,
board: [
{ id: 'all', label: '전체', icon: '📋' },
@ -72,7 +76,7 @@ const subMenuState: Record<MainTab, string> = {
reports: 'report-list',
aerial: 'media',
assets: '',
scat: '',
scat: 'survey',
incidents: '',
board: 'all',
weather: '',

파일 보기

@ -73,9 +73,18 @@ export const useAuthStore = create<AuthState>((set, get) => ({
hasPermission: (resource: string, operation?: string) => {
const { user } = get()
if (!user) return false
const op = operation ?? 'READ'
// 정확한 리소스 권한 확인
const ops = user.permissions[resource]
if (!ops) return false
return ops.includes(operation ?? 'READ')
if (ops) return ops.includes(op)
// '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 }),

파일 보기

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

파일 보기

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

파일 보기

@ -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 { ScatView } from './components/ScatView'