feat: [공정관리] React UI 트리 구조 + 공정 복제 기능

This commit is contained in:
김보곤
2026-03-21 21:20:43 +09:00
parent 59b45dc706
commit 2792cce733
4 changed files with 234 additions and 53 deletions

View File

@@ -40,6 +40,7 @@ import {
getDepartmentOptions,
getProcessSteps,
getDocumentTemplates,
getRootProcessOptions,
type DepartmentOption,
type DocumentTemplateOption,
} from './actions';
@@ -53,6 +54,12 @@ export function ProcessForm({ mode, initialData }: ProcessFormProps) {
const router = useRouter();
const isEdit = mode === 'edit';
// 부모 공정 상태
const [parentId, setParentId] = useState<number | undefined>(
initialData?.parentId ? Number(initialData.parentId) : undefined
);
const [rootProcessOptions, setRootProcessOptions] = useState<Array<{ id: string; processCode: string; processName: string }>>([]);
// 기본 정보 상태
const [processName, setProcessName] = useState(initialData?.processName || '');
const [processType, _setProcessType] = useState<ProcessType>(
@@ -152,18 +159,26 @@ export function ProcessForm({ mode, initialData }: ProcessFormProps) {
setShowRemoveAllDialog(false);
}, []);
// 부서 목록 + 문서양식 목록 로드
// 부서 목록 + 문서양식 목록 + 루트 공정 목록 로드
useEffect(() => {
const loadInitialData = async () => {
setIsDepartmentsLoading(true);
const [departments, templates] = await Promise.all([
const [departments, templates, rootProcesses] = await Promise.all([
getDepartmentOptions(),
getDocumentTemplates(),
getRootProcessOptions(),
]);
setDepartmentOptions(departments);
if (templates.success && templates.data) {
setDocumentTemplates(templates.data);
}
if (rootProcesses.success && rootProcesses.data) {
// 수정 모드에서 자기 자신은 제외
const filtered = isEdit && initialData?.id
? rootProcesses.data.filter(p => p.id !== initialData.id)
: rootProcesses.data;
setRootProcessOptions(filtered);
}
setIsDepartmentsLoading(false);
};
loadInitialData();
@@ -340,6 +355,7 @@ export function ProcessForm({ mode, initialData }: ProcessFormProps) {
}
const formData = {
parentId: parentId || undefined,
processName: processName.trim(),
processType,
processCategory: processCategory || undefined,
@@ -459,8 +475,28 @@ export function ProcessForm({ mode, initialData }: ProcessFormProps) {
/>
</div>
</div>
{/* Row 2: 구분 | 생산일자 | 상태 */}
{/* Row 2: 부모공정 | 구분 | 생산일자 | 상태 */}
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4 md:gap-6 mt-4 md:mt-6">
<div className="space-y-2">
<Label> </Label>
<Select
key={`parent-${parentId ?? 'none'}`}
value={parentId ? String(parentId) : 'none'}
onValueChange={(v) => setParentId(v === 'none' ? undefined : Number(v))}
>
<SelectTrigger>
<SelectValue placeholder="없음 (루트 공정)" />
</SelectTrigger>
<SelectContent>
<SelectItem value="none"> ( )</SelectItem>
{rootProcessOptions.map((opt) => (
<SelectItem key={opt.id} value={opt.id}>
[{opt.processCode}] {opt.processName}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label></Label>
<Select
@@ -825,6 +861,8 @@ export function ProcessForm({ mode, initialData }: ProcessFormProps) {
</>
),
[
parentId,
rootProcessOptions,
processName,
processType,
processCategory,