feat(WEB): 상태 뱃지 공통화 및 상세 페이지 훅 시스템 추가

공통화:
- status-config.ts 신규 추가 (상태 설정 중앙 관리)
- StatusBadge 컴포넌트 개선
- 뱃지 공통화 가이드 문서 추가

상세 페이지 훅 시스템:
- useDetailData, useDetailPageState, useDetailPermissions, useCRUDHandlers 훅 신규 추가
- hooks/index.ts 진입점 추가
- BillDetailV2 신규 컴포넌트 추가

리팩토링:
- 회계(매입/어음/거래처), 품목, 단가, 견적, 주문 상태 뱃지 공통화 적용
- 생산(작업지시서/대시보드/작업자화면), 품질(검사관리) 상태 뱃지 적용
- 공사관리(칸반/프로젝트카드) 상태 뱃지 적용
- 고객센터(문의관리), 인사(직원CSV업로드) 개선
- 리스트 페이지 공통화 현황 분석 문서 추가

상수 정리:
- lib/constants/ 디렉토리 추가

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
유병철
2026-02-05 15:57:49 +09:00
parent 07dd52aa7b
commit 2639724f9f
43 changed files with 2944 additions and 103 deletions

View File

@@ -13,6 +13,7 @@ import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Badge } from '@/components/ui/badge';
import { getPresetStyle } from '@/lib/utils/status-config';
import { NumberInput } from '@/components/ui/number-input';
import {
Table,
@@ -489,7 +490,7 @@ function BOMLineRow({
<TableCell colSpan={8} className="bg-blue-50 p-4">
<div className="space-y-3">
<div className="flex items-center gap-2">
<Badge variant="outline" className="bg-blue-100 text-blue-700">
<Badge variant="outline" className={getPresetStyle('info')}>
</Badge>
</div>

View File

@@ -9,6 +9,7 @@
import { useRouter } from 'next/navigation';
import type { ItemMaster } from '@/types/item';
import { ITEM_TYPE_LABELS, PART_TYPE_LABELS, PART_USAGE_LABELS, PRODUCT_CATEGORY_LABELS } from '@/types/item';
import { getItemTypeStyle } from '@/lib/utils/status-config';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Label } from '@/components/ui/label';
@@ -38,20 +39,11 @@ interface ItemDetailClientProps {
/**
* 품목 유형별 Badge 반환
* - 공통 유틸 getItemTypeStyle 사용
*/
function getItemTypeBadge(itemType: string) {
const badges: Record<string, { className: string }> = {
FG: { className: 'bg-purple-50 text-purple-700 border-purple-200' },
PT: { className: 'bg-orange-50 text-orange-700 border-orange-200' },
SM: { className: 'bg-green-50 text-green-700 border-green-200' },
RM: { className: 'bg-blue-50 text-blue-700 border-blue-200' },
CS: { className: 'bg-gray-50 text-gray-700 border-gray-200' },
};
const config = badges[itemType] || { className: '' };
return (
<Badge variant="outline" className={config.className}>
<Badge variant="outline" className={getItemTypeStyle(itemType)}>
{ITEM_TYPE_LABELS[itemType as keyof typeof ITEM_TYPE_LABELS]}
</Badge>
);

View File

@@ -8,6 +8,7 @@ import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Badge } from '@/components/ui/badge';
import { getPresetStyle } from '@/lib/utils/status-config';
import { NumberInput } from '@/components/ui/number-input';
import { CurrencyInput } from '@/components/ui/currency-input';
import {
@@ -332,7 +333,7 @@ export default function BOMSection({
<TableCell colSpan={9} className="bg-blue-50 p-4">
<div className="space-y-3">
<div className="flex items-center gap-2">
<Badge variant="outline" className="bg-blue-100 text-blue-700">
<Badge variant="outline" className={getPresetStyle('info')}>
</Badge>
</div>

View File

@@ -12,6 +12,7 @@ import { useState, useEffect, useRef, useMemo } from 'react';
import { useRouter } from 'next/navigation';
import type { ItemMaster } from '@/types/item';
import { ITEM_TYPE_LABELS } from '@/types/item';
import { getItemTypeStyle } from '@/lib/utils/status-config';
import { useCommonCodes } from '@/hooks/useCommonCodes';
import { Badge } from '@/components/ui/badge';
import { Checkbox } from '@/components/ui/checkbox';
@@ -46,20 +47,11 @@ function useDebounce<T>(value: T, delay: number): T {
/**
* 품목 유형별 Badge 색상 반환
* - 공통 유틸 getItemTypeStyle 사용
*/
function getItemTypeBadge(itemType: string) {
const badges: Record<string, { variant: 'default' | 'secondary' | 'outline' | 'destructive'; className: string }> = {
FG: { variant: 'default', className: 'bg-purple-100 text-purple-700 border-purple-200' },
PT: { variant: 'default', className: 'bg-orange-100 text-orange-700 border-orange-200' },
SM: { variant: 'default', className: 'bg-green-100 text-green-700 border-green-200' },
RM: { variant: 'default', className: 'bg-blue-100 text-blue-700 border-blue-200' },
CS: { variant: 'default', className: 'bg-gray-100 text-gray-700 border-gray-200' },
};
const config = badges[itemType] || { variant: 'outline' as const, className: '' };
return (
<Badge variant="outline" className={config.className}>
<Badge variant="outline" className={getItemTypeStyle(itemType)}>
{ITEM_TYPE_LABELS[itemType as keyof typeof ITEM_TYPE_LABELS]}
</Badge>
);

View File

@@ -10,6 +10,7 @@ import type { ItemMasterField } from '@/contexts/ItemMasterContext';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { getPresetStyle } from '@/lib/utils/status-config';
import { Plus, Edit, Trash2 } from 'lucide-react';
// 입력방식 옵션 (ItemMasterDataManagement에서 사용하는 상수)
@@ -95,7 +96,7 @@ export function MasterFieldTab({
<Badge variant="secondary" className="text-xs">{field.category}</Badge>
)}
{field.properties?.attributeType && field.properties.attributeType !== 'custom' && (
<Badge variant="default" className="text-xs bg-blue-500">
<Badge variant="default" className={`text-xs ${getPresetStyle('info')}`}>
{field.properties.attributeType === 'unit' ? '단위 연동' :
field.properties.attributeType === 'material' ? '재질 연동' : '표면처리 연동'}
</Badge>