feat: 프로젝트별 작업 분포 Production Report 스타일 완성
✨ 주요 기능 - 프로젝트별 → 작업유형별 데이터 취합 및 표시 - Production Report 스타일 테이블 구현 - 연차/휴무 별도 처리 (주말 제외, 녹색 테마) - Job No. 정확한 표시 (중복 제거) 🔧 API 개선 - recent-work API에 job_no 필드 추가 - MySQL 쿼리 결과 처리 수정 (results[0] 사용) - Projects 테이블 대소문자 조인 문제 해결 🎨 UI/UX 개선 - 탭 기반 분석 인터페이스 - 색상 팔레트 개선 (파란색/녹색/노란색 계열) - 텍스트 방향 수정 (가로 표시) - 프로젝트별 합계 행 추가 📊 계산 로직 - 공수: 시간 ÷ 8 - 부하율: (개별 시간 ÷ 전체 시간) × 100% - 인건비: 공수 × 350,000원 - 주말 연차 자동 제외
This commit is contained in:
@@ -391,14 +391,24 @@ class WorkAnalysisController {
|
||||
const testResults = await db.query(testQuery, [start, end]);
|
||||
console.log('📊 데이터 확인:', testResults[0]);
|
||||
|
||||
// 프로젝트별-작업별 시간 분석 쿼리 (간단한 버전으로 테스트)
|
||||
// 먼저 간단한 테스트 쿼리로 데이터 확인
|
||||
const simpleQuery = `
|
||||
SELECT COUNT(*) as count, MIN(report_date) as min_date, MAX(report_date) as max_date
|
||||
FROM daily_work_reports
|
||||
WHERE report_date BETWEEN ? AND ?
|
||||
`;
|
||||
|
||||
const simpleResult = await db.query(simpleQuery, [start, end]);
|
||||
console.log('📊 기간 내 데이터 확인:', simpleResult[0][0]);
|
||||
|
||||
// 프로젝트별-작업별 시간 분석 쿼리 (work_types 테이블과 조인)
|
||||
const query = `
|
||||
SELECT
|
||||
COALESCE(p.project_id, 0) as project_id,
|
||||
COALESCE(p.project_name, 'Unknown Project') as project_name,
|
||||
COALESCE(p.project_id, dwr.project_id) as project_id,
|
||||
COALESCE(p.project_name, CONCAT('프로젝트 ', dwr.project_id)) as project_name,
|
||||
COALESCE(p.job_no, 'N/A') as job_no,
|
||||
dwr.work_type_id,
|
||||
CONCAT('Work Type ', dwr.work_type_id) as work_type_name,
|
||||
COALESCE(wt.name, CONCAT('작업유형 ', dwr.work_type_id)) as work_type_name,
|
||||
|
||||
-- 총 시간
|
||||
SUM(dwr.work_hours) as total_hours,
|
||||
@@ -421,18 +431,22 @@ class WorkAnalysisController {
|
||||
) as error_rate_percent
|
||||
|
||||
FROM daily_work_reports dwr
|
||||
LEFT JOIN projects p ON dwr.project_id = p.project_id
|
||||
LEFT JOIN Projects p ON dwr.project_id = p.project_id
|
||||
LEFT JOIN work_types wt ON dwr.work_type_id = wt.id
|
||||
WHERE dwr.report_date BETWEEN ? AND ?
|
||||
GROUP BY p.project_id, p.project_name, p.job_no, dwr.work_type_id
|
||||
ORDER BY p.project_name, dwr.work_type_id
|
||||
GROUP BY dwr.project_id, p.project_name, p.job_no, dwr.work_type_id, wt.name
|
||||
ORDER BY p.project_name, wt.name
|
||||
`;
|
||||
|
||||
const results = await db.query(query, [start, end]);
|
||||
console.log('📊 쿼리 결과 개수:', results[0].length);
|
||||
console.log('📊 첫 번째 결과:', results[0][0]);
|
||||
console.log('📊 모든 결과:', JSON.stringify(results[0], null, 2));
|
||||
|
||||
// 데이터를 프로젝트별로 그룹화
|
||||
const groupedData = {};
|
||||
|
||||
results.forEach(row => {
|
||||
results[0].forEach(row => {
|
||||
const projectKey = `${row.project_id}_${row.project_name}`;
|
||||
|
||||
if (!groupedData[projectKey]) {
|
||||
@@ -476,7 +490,7 @@ class WorkAnalysisController {
|
||||
// 전체 요약 통계
|
||||
const totalStats = {
|
||||
total_projects: Object.keys(groupedData).length,
|
||||
total_work_types: new Set(results.map(r => r.work_type_id)).size,
|
||||
total_work_types: new Set(results[0].map(r => r.work_type_id)).size,
|
||||
grand_total_hours: Object.values(groupedData).reduce((sum, p) => sum + p.total_project_hours, 0),
|
||||
grand_regular_hours: Object.values(groupedData).reduce((sum, p) => sum + p.total_regular_hours, 0),
|
||||
grand_error_hours: Object.values(groupedData).reduce((sum, p) => sum + p.total_error_hours, 0)
|
||||
|
||||
@@ -190,6 +190,7 @@ class WorkAnalysis {
|
||||
w.worker_name,
|
||||
dwr.project_id,
|
||||
p.project_name,
|
||||
p.job_no,
|
||||
dwr.work_type_id,
|
||||
wt.name as work_type_name,
|
||||
dwr.work_status_id,
|
||||
@@ -202,7 +203,7 @@ class WorkAnalysis {
|
||||
dwr.created_at
|
||||
FROM daily_work_reports dwr
|
||||
LEFT JOIN workers w ON dwr.worker_id = w.worker_id
|
||||
LEFT JOIN projects p ON dwr.project_id = p.project_id
|
||||
LEFT JOIN Projects p ON dwr.project_id = p.project_id
|
||||
LEFT JOIN work_types wt ON dwr.work_type_id = wt.id
|
||||
LEFT JOIN work_status_types wst ON dwr.work_status_id = wst.id
|
||||
LEFT JOIN error_types et ON dwr.error_type_id = et.id
|
||||
@@ -221,6 +222,7 @@ class WorkAnalysis {
|
||||
worker_name: row.worker_name || `작업자 ${row.worker_id}`,
|
||||
project_id: row.project_id,
|
||||
project_name: row.project_name || `프로젝트 ${row.project_id}`,
|
||||
job_no: row.job_no || 'N/A',
|
||||
work_type_id: row.work_type_id,
|
||||
work_type_name: row.work_type_name || `작업유형 ${row.work_type_id}`,
|
||||
work_status_id: row.work_status_id,
|
||||
|
||||
Reference in New Issue
Block a user