🔧 그룹 리더 대시보드 수정사항: - API 호출 방식 수정 (modern-dashboard.js) - 서버 API 요구사항에 맞는 데이터 구조 변경 - work_entries 배열 구조로 변경 - work_type_id → task_id 필드명 매핑 - 400 Bad Request 오류 해결 ⚡ 작업 분석 시스템 성능 최적화: - 중복 함수 제거 (isWeekend, isVacationProject 통합) - WorkAnalysisAPI 캐싱 시스템 구현 (5분 만료) - 네임스페이스 조직화 (utils, ui, analysis, render) - ErrorHandler 통합 에러 처리 시스템 - 성능 모니터링 및 메모리 누수 방지 - GPU 가속 CSS 애니메이션 추가 - 디바운스/스로틀 함수 적용 - 의미 없는 통계 카드 제거 📊 작업 분석 페이지 개선: - 프로그레스 바 애니메이션 - 토스트 알림 시스템 - 부드러운 전환 효과 - 반응형 최적화 - 메모리 사용량 모니터링
232 lines
7.0 KiB
JavaScript
232 lines
7.0 KiB
JavaScript
/**
|
|
* Work Analysis API Client Module
|
|
* 작업 분석 관련 모든 API 호출을 관리하는 모듈
|
|
*/
|
|
|
|
class WorkAnalysisAPIClient {
|
|
constructor() {
|
|
this.baseURL = window.API_BASE_URL || 'http://localhost:20005/api';
|
|
}
|
|
|
|
/**
|
|
* 기본 API 호출 메서드
|
|
* @param {string} endpoint - API 엔드포인트
|
|
* @param {string} method - HTTP 메서드
|
|
* @param {Object} data - 요청 데이터
|
|
* @returns {Promise<Object>} API 응답
|
|
*/
|
|
async apiCall(endpoint, method = 'GET', data = null) {
|
|
try {
|
|
const config = {
|
|
method,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
}
|
|
};
|
|
|
|
if (data && method !== 'GET') {
|
|
config.body = JSON.stringify(data);
|
|
}
|
|
|
|
console.log(`📡 API 호출: ${this.baseURL}${endpoint} (${method})`);
|
|
|
|
const response = await fetch(`${this.baseURL}${endpoint}`, config);
|
|
const result = await response.json();
|
|
|
|
if (!response.ok) {
|
|
throw new Error(result.message || `HTTP ${response.status}`);
|
|
}
|
|
|
|
console.log(`✅ API 성공: ${this.baseURL}${endpoint}`);
|
|
return result;
|
|
|
|
} catch (error) {
|
|
console.error(`❌ API 실패: ${this.baseURL}${endpoint}`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 날짜 범위 파라미터 생성
|
|
* @param {string} startDate - 시작일
|
|
* @param {string} endDate - 종료일
|
|
* @param {Object} additionalParams - 추가 파라미터
|
|
* @returns {URLSearchParams} URL 파라미터
|
|
*/
|
|
createDateParams(startDate, endDate, additionalParams = {}) {
|
|
const params = new URLSearchParams({
|
|
start: startDate,
|
|
end: endDate,
|
|
...additionalParams
|
|
});
|
|
return params;
|
|
}
|
|
|
|
// ========== 기본 통계 API ==========
|
|
|
|
/**
|
|
* 기본 통계 조회
|
|
*/
|
|
async getBasicStats(startDate, endDate, projectId = null) {
|
|
console.log('🔍 getBasicStats 호출:', startDate, '~', endDate, projectId ? `(프로젝트: ${projectId})` : '');
|
|
const params = this.createDateParams(startDate, endDate,
|
|
projectId ? { project_id: projectId } : {}
|
|
);
|
|
console.log('🌐 API 요청 URL:', `/work-analysis/stats?${params}`);
|
|
return await this.apiCall(`/work-analysis/stats?${params}`);
|
|
}
|
|
|
|
/**
|
|
* 일별 추이 조회
|
|
*/
|
|
async getDailyTrend(startDate, endDate, projectId = null) {
|
|
const params = this.createDateParams(startDate, endDate,
|
|
projectId ? { project_id: projectId } : {}
|
|
);
|
|
return await this.apiCall(`/work-analysis/daily-trend?${params}`);
|
|
}
|
|
|
|
/**
|
|
* 작업자별 통계 조회
|
|
*/
|
|
async getWorkerStats(startDate, endDate, projectId = null) {
|
|
const params = this.createDateParams(startDate, endDate,
|
|
projectId ? { project_id: projectId } : {}
|
|
);
|
|
return await this.apiCall(`/work-analysis/worker-stats?${params}`);
|
|
}
|
|
|
|
/**
|
|
* 프로젝트별 통계 조회
|
|
*/
|
|
async getProjectStats(startDate, endDate) {
|
|
const params = this.createDateParams(startDate, endDate);
|
|
return await this.apiCall(`/work-analysis/project-stats?${params}`);
|
|
}
|
|
|
|
// ========== 상세 분석 API ==========
|
|
|
|
/**
|
|
* 프로젝트별-작업유형별 분석
|
|
*/
|
|
async getProjectWorkTypeAnalysis(startDate, endDate, limit = 2000) {
|
|
const params = this.createDateParams(startDate, endDate, { limit });
|
|
return await this.apiCall(`/work-analysis/project-worktype-analysis?${params}`);
|
|
}
|
|
|
|
/**
|
|
* 최근 작업 데이터 조회
|
|
*/
|
|
async getRecentWork(startDate, endDate, limit = 2000) {
|
|
const params = this.createDateParams(startDate, endDate, { limit });
|
|
return await this.apiCall(`/work-analysis/recent-work?${params}`);
|
|
}
|
|
|
|
/**
|
|
* 오류 분석 데이터 조회
|
|
*/
|
|
async getErrorAnalysis(startDate, endDate) {
|
|
const params = this.createDateParams(startDate, endDate);
|
|
return await this.apiCall(`/work-analysis/error-analysis?${params}`);
|
|
}
|
|
|
|
// ========== 배치 API 호출 ==========
|
|
|
|
/**
|
|
* 여러 API를 병렬로 호출
|
|
* @param {Array} apiCalls - API 호출 배열
|
|
* @returns {Promise<Array>} 결과 배열
|
|
*/
|
|
async batchCall(apiCalls) {
|
|
console.log('🔄 배치 API 호출 시작:', apiCalls.length, '개');
|
|
|
|
const promises = apiCalls.map(async ({ name, method, ...args }) => {
|
|
try {
|
|
const result = await this[method](...args);
|
|
return { name, success: true, data: result };
|
|
} catch (error) {
|
|
console.warn(`⚠️ ${name} API 오류:`, error);
|
|
return { name, success: false, error: error.message, data: null };
|
|
}
|
|
});
|
|
|
|
const results = await Promise.all(promises);
|
|
console.log('✅ 배치 API 호출 완료');
|
|
|
|
return results.reduce((acc, result) => {
|
|
acc[result.name] = result;
|
|
return acc;
|
|
}, {});
|
|
}
|
|
|
|
/**
|
|
* 차트 데이터를 위한 배치 호출
|
|
*/
|
|
async getChartData(startDate, endDate, projectId = null) {
|
|
return await this.batchCall([
|
|
{
|
|
name: 'dailyTrend',
|
|
method: 'getDailyTrend',
|
|
startDate,
|
|
endDate,
|
|
projectId
|
|
},
|
|
{
|
|
name: 'workerStats',
|
|
method: 'getWorkerStats',
|
|
startDate,
|
|
endDate,
|
|
projectId
|
|
},
|
|
{
|
|
name: 'projectStats',
|
|
method: 'getProjectStats',
|
|
startDate,
|
|
endDate
|
|
},
|
|
{
|
|
name: 'errorAnalysis',
|
|
method: 'getErrorAnalysis',
|
|
startDate,
|
|
endDate
|
|
}
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 프로젝트 분포 분석을 위한 배치 호출
|
|
*/
|
|
async getProjectDistributionData(startDate, endDate) {
|
|
return await this.batchCall([
|
|
{
|
|
name: 'projectWorkType',
|
|
method: 'getProjectWorkTypeAnalysis',
|
|
startDate,
|
|
endDate
|
|
},
|
|
{
|
|
name: 'workerStats',
|
|
method: 'getWorkerStats',
|
|
startDate,
|
|
endDate
|
|
},
|
|
{
|
|
name: 'recentWork',
|
|
method: 'getRecentWork',
|
|
startDate,
|
|
endDate
|
|
}
|
|
]);
|
|
}
|
|
}
|
|
|
|
// 전역 인스턴스 생성
|
|
window.WorkAnalysisAPI = new WorkAnalysisAPIClient();
|
|
|
|
// 하위 호환성을 위한 전역 함수
|
|
window.apiCall = (endpoint, method, data) => {
|
|
return window.WorkAnalysisAPI.apiCall(endpoint, method, data);
|
|
};
|
|
|
|
// Export는 브라우저 환경에서 제거됨
|