feat(tkeg): tkeg BOM 자재관리 서비스 초기 세팅 (api + web + docker-compose)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
318
tkeg/web/src/hooks/useRevisionManagement.js
Normal file
318
tkeg/web/src/hooks/useRevisionManagement.js
Normal file
@@ -0,0 +1,318 @@
|
||||
/**
|
||||
* 리비전 관리 훅
|
||||
* - 리비전 세션 생성, 관리, 완료
|
||||
* - 자재 비교 및 변경사항 처리
|
||||
* - 리비전 히스토리 조회
|
||||
*/
|
||||
|
||||
import { useState, useCallback } from 'react';
|
||||
import api from '../api';
|
||||
|
||||
export const useRevisionManagement = () => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState(null);
|
||||
const [currentSession, setCurrentSession] = useState(null);
|
||||
const [sessionStatus, setSessionStatus] = useState(null);
|
||||
const [revisionHistory, setRevisionHistory] = useState([]);
|
||||
|
||||
// 에러 처리 헬퍼
|
||||
const handleError = useCallback((error, defaultMessage) => {
|
||||
console.error(defaultMessage, error);
|
||||
const errorMessage = error.response?.data?.detail || error.message || defaultMessage;
|
||||
setError(errorMessage);
|
||||
return { success: false, error: errorMessage };
|
||||
}, []);
|
||||
|
||||
// 리비전 세션 생성
|
||||
const createRevisionSession = useCallback(async (jobNo, currentFileId, previousFileId) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const response = await api.post('/revision-management/sessions', {
|
||||
job_no: jobNo,
|
||||
current_file_id: currentFileId,
|
||||
previous_file_id: previousFileId
|
||||
});
|
||||
|
||||
if (response.data.success) {
|
||||
setCurrentSession(response.data.data);
|
||||
console.log('✅ 리비전 세션 생성 완료:', response.data.data);
|
||||
return { success: true, data: response.data.data };
|
||||
} else {
|
||||
return handleError(new Error(response.data.message), '리비전 세션 생성 실패');
|
||||
}
|
||||
} catch (error) {
|
||||
return handleError(error, '리비전 세션 생성 중 오류 발생');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [handleError]);
|
||||
|
||||
// 세션 상태 조회
|
||||
const getSessionStatus = useCallback(async (sessionId) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const response = await api.get(`/revision-management/sessions/${sessionId}`);
|
||||
|
||||
if (response.data.success) {
|
||||
setSessionStatus(response.data.data);
|
||||
console.log('✅ 세션 상태 조회 완료:', response.data.data);
|
||||
return { success: true, data: response.data.data };
|
||||
} else {
|
||||
return handleError(new Error(response.data.message), '세션 상태 조회 실패');
|
||||
}
|
||||
} catch (error) {
|
||||
return handleError(error, '세션 상태 조회 중 오류 발생');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [handleError]);
|
||||
|
||||
// 카테고리별 자재 비교
|
||||
const compareCategory = useCallback(async (sessionId, category) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const response = await api.post(`/revision-management/sessions/${sessionId}/compare/${category}`);
|
||||
|
||||
if (response.data.success) {
|
||||
console.log(`✅ 카테고리 ${category} 비교 완료:`, response.data.data);
|
||||
return { success: true, data: response.data.data };
|
||||
} else {
|
||||
return handleError(new Error(response.data.message), `카테고리 ${category} 비교 실패`);
|
||||
}
|
||||
} catch (error) {
|
||||
return handleError(error, `카테고리 ${category} 비교 중 오류 발생`);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [handleError]);
|
||||
|
||||
// 세션 변경사항 조회
|
||||
const getSessionChanges = useCallback(async (sessionId, category = null) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const params = category ? { category } : {};
|
||||
const response = await api.get(`/revision-management/sessions/${sessionId}/changes`, { params });
|
||||
|
||||
if (response.data.success) {
|
||||
console.log('✅ 세션 변경사항 조회 완료:', response.data.data);
|
||||
return { success: true, data: response.data.data };
|
||||
} else {
|
||||
return handleError(new Error(response.data.message), '세션 변경사항 조회 실패');
|
||||
}
|
||||
} catch (error) {
|
||||
return handleError(error, '세션 변경사항 조회 중 오류 발생');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [handleError]);
|
||||
|
||||
// 리비전 액션 처리
|
||||
const processRevisionAction = useCallback(async (changeId, action, notes = null) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const response = await api.post(`/revision-management/changes/${changeId}/process`, {
|
||||
action,
|
||||
notes
|
||||
});
|
||||
|
||||
if (response.data.success) {
|
||||
console.log('✅ 리비전 액션 처리 완료:', response.data.data);
|
||||
return { success: true, data: response.data.data };
|
||||
} else {
|
||||
return handleError(new Error(response.data.message), '리비전 액션 처리 실패');
|
||||
}
|
||||
} catch (error) {
|
||||
return handleError(error, '리비전 액션 처리 중 오류 발생');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [handleError]);
|
||||
|
||||
// 세션 완료
|
||||
const completeSession = useCallback(async (sessionId) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const response = await api.post(`/revision-management/sessions/${sessionId}/complete`);
|
||||
|
||||
if (response.data.success) {
|
||||
setCurrentSession(null);
|
||||
setSessionStatus(null);
|
||||
console.log('✅ 리비전 세션 완료:', response.data.data);
|
||||
return { success: true, data: response.data.data };
|
||||
} else {
|
||||
return handleError(new Error(response.data.message), '리비전 세션 완료 실패');
|
||||
}
|
||||
} catch (error) {
|
||||
return handleError(error, '리비전 세션 완료 중 오류 발생');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [handleError]);
|
||||
|
||||
// 세션 취소
|
||||
const cancelSession = useCallback(async (sessionId, reason = null) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const params = reason ? { reason } : {};
|
||||
const response = await api.post(`/revision-management/sessions/${sessionId}/cancel`, null, { params });
|
||||
|
||||
if (response.data.success) {
|
||||
setCurrentSession(null);
|
||||
setSessionStatus(null);
|
||||
console.log('✅ 리비전 세션 취소:', response.data.data);
|
||||
return { success: true, data: response.data.data };
|
||||
} else {
|
||||
return handleError(new Error(response.data.message), '리비전 세션 취소 실패');
|
||||
}
|
||||
} catch (error) {
|
||||
return handleError(error, '리비전 세션 취소 중 오류 발생');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [handleError]);
|
||||
|
||||
// 리비전 히스토리 조회
|
||||
const getRevisionHistory = useCallback(async (jobNo) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const response = await api.get(`/revision-management/history/${jobNo}`);
|
||||
|
||||
if (response.data.success) {
|
||||
setRevisionHistory(response.data.data.history);
|
||||
console.log('✅ 리비전 히스토리 조회 완료:', response.data.data);
|
||||
return { success: true, data: response.data.data };
|
||||
} else {
|
||||
return handleError(new Error(response.data.message), '리비전 히스토리 조회 실패');
|
||||
}
|
||||
} catch (error) {
|
||||
return handleError(error, '리비전 히스토리 조회 중 오류 발생');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [handleError]);
|
||||
|
||||
// 리비전 요약 조회
|
||||
const getRevisionSummary = useCallback(async (sessionId) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const response = await api.get(`/revision-management/sessions/${sessionId}/summary`);
|
||||
|
||||
if (response.data.success) {
|
||||
console.log('✅ 리비전 요약 조회 완료:', response.data.data);
|
||||
return { success: true, data: response.data.data };
|
||||
} else {
|
||||
return handleError(new Error(response.data.message), '리비전 요약 조회 실패');
|
||||
}
|
||||
} catch (error) {
|
||||
return handleError(error, '리비전 요약 조회 중 오류 발생');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [handleError]);
|
||||
|
||||
// 지원 카테고리 조회
|
||||
const getSupportedCategories = useCallback(async () => {
|
||||
try {
|
||||
const response = await api.get('/revision-management/categories');
|
||||
if (response.data.success) {
|
||||
return { success: true, data: response.data.data.categories };
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('지원 카테고리 조회 실패:', error);
|
||||
}
|
||||
|
||||
// 기본 카테고리 반환
|
||||
return {
|
||||
success: true,
|
||||
data: [
|
||||
{ key: "PIPE", name: "배관", description: "파이프 및 배관 자재" },
|
||||
{ key: "FITTING", name: "피팅", description: "배관 연결 부품" },
|
||||
{ key: "FLANGE", name: "플랜지", description: "플랜지 및 연결 부품" },
|
||||
{ key: "VALVE", name: "밸브", description: "각종 밸브류" },
|
||||
{ key: "GASKET", name: "가스켓", description: "씰링 부품" },
|
||||
{ key: "BOLT", name: "볼트", description: "체결 부품" },
|
||||
{ key: "SUPPORT", name: "서포트", description: "지지대 및 구조물" },
|
||||
{ key: "SPECIAL", name: "특수자재", description: "특수 목적 자재" },
|
||||
{ key: "UNCLASSIFIED", name: "미분류", description: "분류되지 않은 자재" }
|
||||
]
|
||||
};
|
||||
}, []);
|
||||
|
||||
// 리비전 액션 목록 조회
|
||||
const getRevisionActions = useCallback(async () => {
|
||||
try {
|
||||
const response = await api.get('/revision-management/actions');
|
||||
if (response.data.success) {
|
||||
return { success: true, data: response.data.data.actions };
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('리비전 액션 조회 실패:', error);
|
||||
}
|
||||
|
||||
// 기본 액션 반환
|
||||
return {
|
||||
success: true,
|
||||
data: [
|
||||
{ key: "new_material", name: "신규 자재", description: "새로 추가된 자재" },
|
||||
{ key: "additional_purchase", name: "추가 구매", description: "구매된 자재의 수량 증가" },
|
||||
{ key: "inventory_transfer", name: "재고 이관", description: "구매된 자재의 수량 감소 또는 제거" },
|
||||
{ key: "purchase_cancel", name: "구매 취소", description: "미구매 자재의 제거" },
|
||||
{ key: "quantity_update", name: "수량 업데이트", description: "미구매 자재의 수량 변경" },
|
||||
{ key: "maintain", name: "유지", description: "변경사항 없음" }
|
||||
]
|
||||
};
|
||||
}, []);
|
||||
|
||||
// 상태 초기화
|
||||
const resetState = useCallback(() => {
|
||||
setCurrentSession(null);
|
||||
setSessionStatus(null);
|
||||
setRevisionHistory([]);
|
||||
setError(null);
|
||||
setLoading(false);
|
||||
}, []);
|
||||
|
||||
return {
|
||||
// 상태
|
||||
loading,
|
||||
error,
|
||||
currentSession,
|
||||
sessionStatus,
|
||||
revisionHistory,
|
||||
|
||||
// 액션
|
||||
createRevisionSession,
|
||||
getSessionStatus,
|
||||
compareCategory,
|
||||
getSessionChanges,
|
||||
processRevisionAction,
|
||||
completeSession,
|
||||
cancelSession,
|
||||
getRevisionHistory,
|
||||
getRevisionSummary,
|
||||
getSupportedCategories,
|
||||
getRevisionActions,
|
||||
resetState,
|
||||
|
||||
// 유틸리티
|
||||
clearError: () => setError(null)
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user