feat(WEB): Phase 6 IntegratedDetailTemplate 마이그레이션 완료

Phase 6 마이그레이션 (41개 컴포넌트 완료):
- 건설/시공: 협력업체, 시공관리, 기성관리, 발주관리, 계약관리 등
- 영업: 견적관리(V2), 고객관리(V2), 수주관리
- 회계: 청구관리, 매입관리, 매출관리, 거래처관리, 악성채권 등
- 생산: 작업지시, 검수관리
- 출고: 출하관리
- 자재: 입고관리, 재고현황
- 고객센터: 문의관리, 이벤트관리, 공지관리
- 인사: 직원관리
- 설정: 권한관리

주요 변경사항:
- 34개 xxxConfig.ts 파일 생성 (설정 기반 페이지 구성)
- PageLayout/PageHeader → IntegratedDetailTemplate 통합
- 일관된 타이틀/버튼 영역 (목록, 상세, 수정, 삭제)
- 1112줄 코드 감소 (중복 제거)

프로젝트 공통화 현황 분석 문서 추가:
- 상세 페이지 62%, 목록 페이지 82% 공통화 달성
- 추가 공통화 기회 및 로드맵 정리

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
유병철
2026-01-20 15:51:02 +09:00
parent 6f457b28f3
commit 61e3a0ed60
71 changed files with 4743 additions and 4402 deletions

View File

@@ -2,14 +2,13 @@
/**
* 재고현황 상세 페이지
* IntegratedDetailTemplate 마이그레이션 완료 (2026-01-20)
* API 연동 버전 (2025-12-26)
*/
import { useState, useMemo, useCallback, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { Package, AlertCircle, List } from 'lucide-react';
import { ContentLoadingSpinner } from '@/components/ui/loading-spinner';
import { Button } from '@/components/ui/button';
import { AlertCircle } from 'lucide-react';
import { Badge } from '@/components/ui/badge';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import {
@@ -20,7 +19,8 @@ import {
TableHeader,
TableRow,
} from '@/components/ui/table';
import { PageLayout } from '@/components/organisms/PageLayout';
import { IntegratedDetailTemplate } from '@/components/templates/IntegratedDetailTemplate';
import { stockStatusConfig } from './stockStatusConfig';
import { ServerErrorPage } from '@/components/common/ServerErrorPage';
import { getStockById } from './actions';
import {
@@ -85,51 +85,26 @@ export function StockStatusDetail({ id }: StockStatusDetailProps) {
return detail.lots.reduce((sum, lot) => sum + lot.qty, 0);
}, [detail]);
// 목록으로 돌아가기
const handleGoBack = useCallback(() => {
router.push('/ko/material/stock-status');
}, [router]);
// 커스텀 헤더 액션 (품목코드와 상태 뱃지)
const customHeaderActions = useMemo(() => {
if (!detail) return null;
// 로딩 상태 표시
if (isLoading) {
return (
<PageLayout>
<ContentLoadingSpinner text="재고 정보를 불러오는 중..." />
</PageLayout>
<>
<span className="text-muted-foreground">{detail.itemCode}</span>
<Badge variant="outline" className="text-xs">
{STOCK_STATUS_LABELS[detail.status]}
</Badge>
</>
);
}
}, [detail]);
// 폼 콘텐츠 렌더링
const renderFormContent = useCallback(() => {
if (!detail) return null;
// 에러 상태 표시
if (error || !detail) {
return (
<ServerErrorPage
title="재고 정보를 불러올 수 없습니다"
message={error || '재고 정보를 찾을 수 없습니다.'}
onRetry={loadData}
showBackButton={true}
showHomeButton={true}
/>
);
}
return (
<PageLayout>
<div className="space-y-6">
{/* 헤더 */}
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<Package className="w-6 h-6" />
<h1 className="text-xl font-semibold"> </h1>
<span className="text-muted-foreground">{detail.itemCode}</span>
<Badge variant="outline" className="text-xs">
{STOCK_STATUS_LABELS[detail.status]}
</Badge>
</div>
<Button variant="outline" onClick={handleGoBack}>
<List className="h-4 w-4 mr-2" />
</Button>
</div>
{/* 기본 정보 */}
<Card>
<CardHeader className="pb-4">
@@ -289,6 +264,32 @@ export function StockStatusDetail({ id }: StockStatusDetailProps) {
</div>
)}
</div>
</PageLayout>
);
}, [detail, totalQty, oldestLot]);
// 에러 상태 표시
if (!isLoading && (error || !detail)) {
return (
<ServerErrorPage
title="재고 정보를 불러올 수 없습니다"
message={error || '재고 정보를 찾을 수 없습니다.'}
onRetry={loadData}
showBackButton={true}
showHomeButton={true}
/>
);
}
return (
<IntegratedDetailTemplate
config={stockStatusConfig}
mode="view"
initialData={detail || {}}
itemId={id}
isLoading={isLoading}
headerActions={customHeaderActions}
renderView={() => renderFormContent()}
renderForm={() => renderFormContent()}
/>
);
}