feat: 공정관리 규칙 UI 개선 및 품질인정심사시스템 경로 이동
- 자동 분류 규칙 리스트 UI 기획서대로 수정 - 번호, 개별 품목 지정 표시, 배지, 수정/삭제 버튼 - 규칙 수정 기능 추가 (기존 품목 체크 상태 유지) - 개별 품목 모달 UI 기획서대로 재구현 - 검색, 품목유형 필터, 체크박스 테이블 - 품질인정심사시스템 경로 이동 (dev → quality/qms) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useState, useCallback } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { X, Save, Plus, Wrench, Trash2, Loader2 } from 'lucide-react';
|
||||
import { X, Save, Plus, Wrench, Trash2, Loader2, Pencil } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
@@ -74,25 +74,53 @@ export function ProcessForm({ mode, initialData }: ProcessFormProps) {
|
||||
|
||||
// 규칙 모달 상태
|
||||
const [ruleModalOpen, setRuleModalOpen] = useState(false);
|
||||
const [editingRule, setEditingRule] = useState<ClassificationRule | undefined>(undefined);
|
||||
|
||||
// 규칙 추가
|
||||
const handleAddRule = useCallback(
|
||||
// 규칙 추가/수정
|
||||
const handleSaveRule = useCallback(
|
||||
(ruleData: Omit<ClassificationRule, 'id' | 'createdAt'>) => {
|
||||
const newRule: ClassificationRule = {
|
||||
...ruleData,
|
||||
id: `rule-${Date.now()}`,
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
setClassificationRules((prev) => [...prev, newRule]);
|
||||
if (editingRule) {
|
||||
// 수정 모드
|
||||
setClassificationRules((prev) =>
|
||||
prev.map((r) =>
|
||||
r.id === editingRule.id
|
||||
? { ...r, ...ruleData }
|
||||
: r
|
||||
)
|
||||
);
|
||||
} else {
|
||||
// 추가 모드
|
||||
const newRule: ClassificationRule = {
|
||||
...ruleData,
|
||||
id: `rule-${Date.now()}`,
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
setClassificationRules((prev) => [...prev, newRule]);
|
||||
}
|
||||
setEditingRule(undefined);
|
||||
},
|
||||
[]
|
||||
[editingRule]
|
||||
);
|
||||
|
||||
// 규칙 수정 모달 열기
|
||||
const handleEditRule = useCallback((rule: ClassificationRule) => {
|
||||
setEditingRule(rule);
|
||||
setRuleModalOpen(true);
|
||||
}, []);
|
||||
|
||||
// 규칙 삭제
|
||||
const handleDeleteRule = useCallback((ruleId: string) => {
|
||||
setClassificationRules((prev) => prev.filter((r) => r.id !== ruleId));
|
||||
}, []);
|
||||
|
||||
// 모달 닫기
|
||||
const handleModalClose = useCallback((open: boolean) => {
|
||||
setRuleModalOpen(open);
|
||||
if (!open) {
|
||||
setEditingRule(undefined);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 제출
|
||||
const handleSubmit = async () => {
|
||||
if (!processName.trim()) {
|
||||
@@ -273,45 +301,83 @@ export function ProcessForm({ mode, initialData }: ProcessFormProps) {
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
{classificationRules.map((rule) => (
|
||||
<div
|
||||
key={rule.id}
|
||||
className="flex items-center justify-between p-4 border rounded-lg"
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<Badge variant={rule.isActive ? 'default' : 'secondary'}>
|
||||
{rule.isActive ? '활성' : '비활성'}
|
||||
</Badge>
|
||||
<div>
|
||||
<div className="font-medium">
|
||||
{rule.ruleType}{' '}
|
||||
{
|
||||
MATCHING_TYPE_OPTIONS.find(
|
||||
(o) => o.value === rule.matchingType
|
||||
)?.label
|
||||
}{' '}
|
||||
"{rule.conditionValue}"
|
||||
</div>
|
||||
{rule.description && (
|
||||
<div className="text-sm text-muted-foreground">
|
||||
{rule.description}
|
||||
{classificationRules.map((rule, index) => {
|
||||
// 개별 품목인 경우 품목 개수 계산
|
||||
const isIndividual = rule.registrationType === 'individual';
|
||||
const itemCount = isIndividual
|
||||
? rule.conditionValue.split(',').filter(Boolean).length
|
||||
: 0;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={rule.id}
|
||||
className="flex items-start justify-between p-4 border rounded-lg"
|
||||
>
|
||||
<div className="flex gap-3">
|
||||
{/* 번호 */}
|
||||
<span className="text-muted-foreground font-medium mt-0.5">
|
||||
{index + 1}.
|
||||
</span>
|
||||
<div className="space-y-1">
|
||||
{/* 제목 */}
|
||||
<div className="font-medium">
|
||||
{isIndividual ? (
|
||||
<>개별 품목 지정 - {itemCount}개 품목</>
|
||||
) : (
|
||||
<>
|
||||
{rule.ruleType}{' '}
|
||||
{
|
||||
MATCHING_TYPE_OPTIONS.find(
|
||||
(o) => o.value === rule.matchingType
|
||||
)?.label
|
||||
}{' '}
|
||||
"{rule.conditionValue}"
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{/* 뱃지 + 우선순위 */}
|
||||
<div className="flex items-center gap-2">
|
||||
<Badge variant="secondary" className="text-xs">
|
||||
{isIndividual
|
||||
? `${itemCount}개 품목 배정됨`
|
||||
: rule.isActive
|
||||
? '활성'
|
||||
: '비활성'}
|
||||
</Badge>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
우선순위: {rule.priority}
|
||||
</span>
|
||||
</div>
|
||||
{/* 설명 */}
|
||||
<div className="text-sm text-muted-foreground">
|
||||
{isIndividual
|
||||
? `직접 선택한 품목 ${itemCount}개`
|
||||
: rule.description || ''}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* 수정/삭제 버튼 */}
|
||||
<div className="flex items-center gap-1">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => handleEditRule(rule)}
|
||||
className="h-8 w-8"
|
||||
>
|
||||
<Pencil className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => handleDeleteRule(rule.id)}
|
||||
className="h-8 w-8 text-muted-foreground hover:text-destructive"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Badge variant="outline">우선순위: {rule.priority}</Badge>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => handleDeleteRule(rule.id)}
|
||||
className="text-destructive hover:text-destructive"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
@@ -381,11 +447,12 @@ export function ProcessForm({ mode, initialData }: ProcessFormProps) {
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* 규칙 추가 모달 */}
|
||||
{/* 규칙 추가/수정 모달 */}
|
||||
<RuleModal
|
||||
open={ruleModalOpen}
|
||||
onOpenChange={setRuleModalOpen}
|
||||
onAdd={handleAddRule}
|
||||
onOpenChange={handleModalClose}
|
||||
onAdd={handleSaveRule}
|
||||
editRule={editingRule}
|
||||
/>
|
||||
</PageLayout>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user