feat(WEB): 글로벌 검색, 토큰 갱신 개선, 템플릿 기능 확장
- CommandMenuSearch 컴포넌트 추가 (Cmd+K 글로벌 메뉴 검색) - AuthenticatedLayout: 검색 통합, 모바일/데스크톱 스켈레톤 분리 - middleware: 토큰 갱신 후 리다이렉트 방식으로 변경 (race condition 방지) - IntegratedDetailTemplate: stickyButtons 옵션 추가 (하단 고정 버튼) - UniversalListPage: 컬럼 정렬 기능 추가 (sortBy, sortOrder) - Sidebar: 축소 모드 패딩/간격 최적화 - 각종 컴포넌트 버그 수정 및 경로 정규화 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,12 +2,14 @@
|
||||
|
||||
import { useState, useMemo } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { List, Edit, Wrench, Package } from 'lucide-react';
|
||||
import { List, Edit, Wrench, Package, ArrowLeft } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { PageLayout } from '@/components/organisms/PageLayout';
|
||||
import { PageHeader } from '@/components/organisms/PageHeader';
|
||||
import { ProcessWorkLogPreviewModal } from './ProcessWorkLogPreviewModal';
|
||||
import { useMenuStore } from '@/store/menuStore';
|
||||
import type { Process } from '@/types/process';
|
||||
import { MATCHING_TYPE_OPTIONS } from '@/types/process';
|
||||
|
||||
@@ -18,6 +20,7 @@ interface ProcessDetailProps {
|
||||
export function ProcessDetail({ process }: ProcessDetailProps) {
|
||||
const router = useRouter();
|
||||
const [workLogModalOpen, setWorkLogModalOpen] = useState(false);
|
||||
const sidebarCollapsed = useMenuStore((state) => state.sidebarCollapsed);
|
||||
|
||||
// 패턴 규칙과 개별 품목 분리
|
||||
const { patternRules, individualItems } = useMemo(() => {
|
||||
@@ -51,49 +54,38 @@ export function ProcessDetail({ process }: ProcessDetailProps) {
|
||||
return (
|
||||
<PageLayout>
|
||||
{/* 헤더 */}
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<div className="flex items-center gap-3">
|
||||
<Wrench className="h-6 w-6" />
|
||||
<h1 className="text-xl font-semibold">공정 상세</h1>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" onClick={handleList}>
|
||||
<List className="h-4 w-4 mr-2" />
|
||||
목록
|
||||
</Button>
|
||||
<Button onClick={handleEdit}>
|
||||
<Edit className="h-4 w-4 mr-2" />
|
||||
수정
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<PageHeader
|
||||
title="공정 상세"
|
||||
icon={Wrench}
|
||||
/>
|
||||
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-6 pb-24">
|
||||
{/* 기본 정보 */}
|
||||
<Card>
|
||||
<CardHeader className="bg-muted/50">
|
||||
<CardTitle className="text-base">기본 정보</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="pt-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">공정코드</div>
|
||||
{/* 반응형 6열 그리드: PC 6열, 태블릿 4열, 작은태블릿 2열, 모바일 1열 */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-6">
|
||||
<div className="space-y-1 lg:col-span-2">
|
||||
<div className="text-sm text-muted-foreground">공정코드</div>
|
||||
<div className="font-medium">{process.processCode}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">공정명</div>
|
||||
<div className="space-y-1 lg:col-span-2">
|
||||
<div className="text-sm text-muted-foreground">공정명</div>
|
||||
<div className="font-medium">{process.processName}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">공정구분</div>
|
||||
<div className="space-y-1">
|
||||
<div className="text-sm text-muted-foreground">공정구분</div>
|
||||
<Badge variant="secondary">{process.processType}</Badge>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">담당부서</div>
|
||||
<div className="space-y-1">
|
||||
<div className="text-sm text-muted-foreground">담당부서</div>
|
||||
<div className="font-medium">{process.department}</div>
|
||||
</div>
|
||||
<div className="md:col-span-2">
|
||||
<div className="text-sm text-muted-foreground mb-1">작업일지 양식</div>
|
||||
<div className="space-y-1 lg:col-span-2">
|
||||
<div className="text-sm text-muted-foreground">작업일지 양식</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium">
|
||||
{process.workLogTemplate || '-'}
|
||||
@@ -115,13 +107,13 @@ export function ProcessDetail({ process }: ProcessDetailProps) {
|
||||
<CardTitle className="text-base">등록 정보</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="pt-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">등록일</div>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-6">
|
||||
<div className="space-y-1 lg:col-span-3">
|
||||
<div className="text-sm text-muted-foreground">등록일</div>
|
||||
<div className="font-medium">{process.createdAt}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">최종수정일</div>
|
||||
<div className="space-y-1 lg:col-span-3">
|
||||
<div className="text-sm text-muted-foreground">최종수정일</div>
|
||||
<div className="font-medium">{process.updatedAt}</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -249,25 +241,37 @@ export function ProcessDetail({ process }: ProcessDetailProps) {
|
||||
<CardHeader className="bg-muted/50">
|
||||
<CardTitle className="text-base">작업 정보</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="pt-6 space-y-4">
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">필요인원</div>
|
||||
<div className="font-medium">{process.requiredWorkers}명</div>
|
||||
</div>
|
||||
{process.equipmentInfo && (
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">설비정보</div>
|
||||
<div className="font-medium">{process.equipmentInfo}</div>
|
||||
<CardContent className="pt-6">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-6">
|
||||
<div className="space-y-1">
|
||||
<div className="text-sm text-muted-foreground">필요인원</div>
|
||||
<div className="font-medium">{process.requiredWorkers}명</div>
|
||||
</div>
|
||||
<div className="space-y-1 lg:col-span-2">
|
||||
<div className="text-sm text-muted-foreground">설비정보</div>
|
||||
<div className="font-medium">{process.equipmentInfo || '-'}</div>
|
||||
</div>
|
||||
<div className="space-y-1 lg:col-span-3">
|
||||
<div className="text-sm text-muted-foreground">설명</div>
|
||||
<div className="font-medium">{process.description || '-'}</div>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">설명</div>
|
||||
<div className="font-medium">{process.description || '-'}</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* 하단 액션 버튼 (sticky) */}
|
||||
<div className={`fixed bottom-6 ${sidebarCollapsed ? 'left-[156px]' : 'left-[316px]'} right-[48px] px-6 py-3 bg-background/95 backdrop-blur rounded-xl border shadow-lg z-50 transition-all duration-300 flex items-center justify-between`}>
|
||||
<Button variant="outline" onClick={handleList}>
|
||||
<ArrowLeft className="h-4 w-4 mr-2" />
|
||||
목록으로
|
||||
</Button>
|
||||
<Button onClick={handleEdit}>
|
||||
<Edit className="h-4 w-4 mr-2" />
|
||||
수정
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* 작업일지 양식 미리보기 모달 */}
|
||||
<ProcessWorkLogPreviewModal
|
||||
open={workLogModalOpen}
|
||||
|
||||
Reference in New Issue
Block a user