feat: 3-System 분리 프로젝트 초기 코드 작성
TK-FB(공장관리+신고)와 M-Project(부적합관리)를 3개 독립 시스템으로 분리하기 위한 전체 코드 구조 작성. - SSO 인증 서비스 (bcrypt + pbkdf2 이중 해시 지원) - System 1: 공장관리 (TK-FB 기반, 신고 코드 제거) - System 2: 신고 (TK-FB에서 workIssue 코드 추출) - System 3: 부적합관리 (M-Project 기반) - Gateway 포털 (path-based 라우팅) - 통합 docker-compose.yml 및 배포 스크립트 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
318
system1-factory/web/js/daily-work-report/index.js
Normal file
318
system1-factory/web/js/daily-work-report/index.js
Normal file
@@ -0,0 +1,318 @@
|
||||
/**
|
||||
* Daily Work Report - Module Loader
|
||||
* 작업보고서 모듈을 초기화하고 연결하는 메인 진입점
|
||||
*
|
||||
* 로드 순서:
|
||||
* 1. state.js - 전역 상태 관리
|
||||
* 2. utils.js - 유틸리티 함수
|
||||
* 3. api.js - API 클라이언트
|
||||
* 4. index.js - 이 파일 (메인 컨트롤러)
|
||||
*/
|
||||
|
||||
class DailyWorkReportController {
|
||||
constructor() {
|
||||
this.state = window.DailyWorkReportState;
|
||||
this.api = window.DailyWorkReportAPI;
|
||||
this.utils = window.DailyWorkReportUtils;
|
||||
this.initialized = false;
|
||||
|
||||
console.log('[Controller] DailyWorkReportController 생성');
|
||||
}
|
||||
|
||||
/**
|
||||
* 초기화
|
||||
*/
|
||||
async init() {
|
||||
if (this.initialized) {
|
||||
console.log('[Controller] 이미 초기화됨');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[Controller] 초기화 시작...');
|
||||
|
||||
try {
|
||||
// 이벤트 리스너 설정
|
||||
this.setupEventListeners();
|
||||
|
||||
// 기본 데이터 로드
|
||||
await this.api.loadAllData();
|
||||
|
||||
// TBM 탭이 기본
|
||||
await this.switchTab('tbm');
|
||||
|
||||
this.initialized = true;
|
||||
console.log('[Controller] 초기화 완료');
|
||||
|
||||
} catch (error) {
|
||||
console.error('[Controller] 초기화 실패:', error);
|
||||
window.showMessage?.('초기화 중 오류가 발생했습니다: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 이벤트 리스너 설정
|
||||
*/
|
||||
setupEventListeners() {
|
||||
// 탭 버튼
|
||||
const tbmBtn = document.getElementById('tbmReportTab');
|
||||
const completedBtn = document.getElementById('completedReportTab');
|
||||
|
||||
if (tbmBtn) {
|
||||
tbmBtn.addEventListener('click', () => this.switchTab('tbm'));
|
||||
}
|
||||
if (completedBtn) {
|
||||
completedBtn.addEventListener('click', () => this.switchTab('completed'));
|
||||
}
|
||||
|
||||
// 완료 보고서 날짜 변경
|
||||
const completedDateInput = document.getElementById('completedReportDate');
|
||||
if (completedDateInput) {
|
||||
completedDateInput.addEventListener('change', () => this.loadCompletedReports());
|
||||
}
|
||||
|
||||
console.log('[Controller] 이벤트 리스너 설정 완료');
|
||||
}
|
||||
|
||||
/**
|
||||
* 탭 전환
|
||||
*/
|
||||
async switchTab(tab) {
|
||||
this.state.setCurrentTab(tab);
|
||||
|
||||
const tbmBtn = document.getElementById('tbmReportTab');
|
||||
const completedBtn = document.getElementById('completedReportTab');
|
||||
const tbmSection = document.getElementById('tbmReportSection');
|
||||
const completedSection = document.getElementById('completedReportSection');
|
||||
|
||||
// 모든 탭 버튼 비활성화
|
||||
tbmBtn?.classList.remove('active');
|
||||
completedBtn?.classList.remove('active');
|
||||
|
||||
// 모든 섹션 숨기기
|
||||
if (tbmSection) tbmSection.style.display = 'none';
|
||||
if (completedSection) completedSection.style.display = 'none';
|
||||
|
||||
// 선택된 탭 활성화
|
||||
if (tab === 'tbm') {
|
||||
tbmBtn?.classList.add('active');
|
||||
if (tbmSection) tbmSection.style.display = 'block';
|
||||
await this.loadTbmData();
|
||||
} else if (tab === 'completed') {
|
||||
completedBtn?.classList.add('active');
|
||||
if (completedSection) completedSection.style.display = 'block';
|
||||
|
||||
// 오늘 날짜로 초기화
|
||||
const dateInput = document.getElementById('completedReportDate');
|
||||
if (dateInput) {
|
||||
dateInput.value = this.utils.getKoreaToday();
|
||||
}
|
||||
await this.loadCompletedReports();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TBM 데이터 로드
|
||||
*/
|
||||
async loadTbmData() {
|
||||
try {
|
||||
await this.api.loadIncompleteTbms();
|
||||
await this.api.loadDailyIssuesForTbms();
|
||||
|
||||
// 렌더링은 기존 함수 사용 (점진적 마이그레이션)
|
||||
if (typeof window.renderTbmWorkList === 'function') {
|
||||
window.renderTbmWorkList();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Controller] TBM 데이터 로드 오류:', error);
|
||||
window.showMessage?.('TBM 데이터를 불러오는 중 오류가 발생했습니다.', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 완료 보고서 로드
|
||||
*/
|
||||
async loadCompletedReports() {
|
||||
try {
|
||||
const dateInput = document.getElementById('completedReportDate');
|
||||
const date = dateInput?.value || this.utils.getKoreaToday();
|
||||
|
||||
const reports = await this.api.loadCompletedReports(date);
|
||||
|
||||
// 렌더링은 기존 함수 사용
|
||||
if (typeof window.renderCompletedReports === 'function') {
|
||||
window.renderCompletedReports(reports);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[Controller] 완료 보고서 로드 오류:', error);
|
||||
window.showMessage?.('완료 보고서를 불러오는 중 오류가 발생했습니다.', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TBM 작업보고서 제출
|
||||
*/
|
||||
async submitTbmWorkReport(index) {
|
||||
try {
|
||||
const tbm = this.state.incompleteTbms[index];
|
||||
if (!tbm) {
|
||||
throw new Error('TBM 데이터를 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
// 유효성 검사
|
||||
const totalHoursInput = document.getElementById(`totalHours_${index}`);
|
||||
const totalHours = parseFloat(totalHoursInput?.value);
|
||||
|
||||
if (!totalHours || totalHours <= 0) {
|
||||
window.showMessage?.('작업시간을 입력해주세요.', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
// 부적합 시간 계산
|
||||
const defects = this.state.tempDefects[index] || [];
|
||||
const errorHours = defects.reduce((sum, d) => sum + (parseFloat(d.defect_hours) || 0), 0);
|
||||
const regularHours = totalHours - errorHours;
|
||||
|
||||
if (regularHours < 0) {
|
||||
window.showMessage?.('부적합 시간이 총 작업시간을 초과할 수 없습니다.', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
// API 데이터 구성
|
||||
const user = this.state.getCurrentUser();
|
||||
const reportData = {
|
||||
tbm_session_id: tbm.session_id,
|
||||
tbm_assignment_id: tbm.assignment_id,
|
||||
worker_id: tbm.worker_id,
|
||||
project_id: tbm.project_id,
|
||||
work_type_id: tbm.work_type_id,
|
||||
report_date: this.utils.formatDateForApi(tbm.session_date),
|
||||
total_hours: totalHours,
|
||||
regular_hours: regularHours,
|
||||
error_hours: errorHours,
|
||||
work_status_id: errorHours > 0 ? 2 : 1,
|
||||
created_by: user?.user_id || user?.id,
|
||||
defects: defects.map(d => ({
|
||||
category_id: d.category_id,
|
||||
item_id: d.item_id,
|
||||
issue_report_id: d.issue_report_id,
|
||||
defect_hours: d.defect_hours,
|
||||
note: d.note
|
||||
}))
|
||||
};
|
||||
|
||||
const result = await this.api.submitTbmWorkReport(reportData);
|
||||
|
||||
window.showSaveResultModal?.(
|
||||
'success',
|
||||
'제출 완료',
|
||||
`${tbm.worker_name}의 작업보고서가 제출되었습니다.`
|
||||
);
|
||||
|
||||
// 목록 새로고침
|
||||
await this.loadTbmData();
|
||||
|
||||
} catch (error) {
|
||||
console.error('[Controller] 제출 오류:', error);
|
||||
window.showSaveResultModal?.(
|
||||
'error',
|
||||
'제출 실패',
|
||||
error.message || '작업보고서 제출 중 오류가 발생했습니다.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 세션 일괄 제출
|
||||
*/
|
||||
async batchSubmitSession(sessionKey) {
|
||||
const rows = document.querySelectorAll(`tr[data-session-key="${sessionKey}"][data-type="tbm"]`);
|
||||
const indices = [];
|
||||
|
||||
rows.forEach(row => {
|
||||
const index = parseInt(row.dataset.index);
|
||||
const totalHoursInput = document.getElementById(`totalHours_${index}`);
|
||||
if (totalHoursInput?.value && parseFloat(totalHoursInput.value) > 0) {
|
||||
indices.push(index);
|
||||
}
|
||||
});
|
||||
|
||||
if (indices.length === 0) {
|
||||
window.showMessage?.('제출할 항목이 없습니다. 작업시간을 입력해주세요.', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
const confirmed = confirm(`${indices.length}건의 작업보고서를 일괄 제출하시겠습니까?`);
|
||||
if (!confirmed) return;
|
||||
|
||||
let successCount = 0;
|
||||
let failCount = 0;
|
||||
|
||||
for (const index of indices) {
|
||||
try {
|
||||
await this.submitTbmWorkReport(index);
|
||||
successCount++;
|
||||
} catch (error) {
|
||||
failCount++;
|
||||
console.error(`[Controller] 일괄 제출 오류 (index: ${index}):`, error);
|
||||
}
|
||||
}
|
||||
|
||||
if (failCount === 0) {
|
||||
window.showSaveResultModal?.('success', '일괄 제출 완료', `${successCount}건이 성공적으로 제출되었습니다.`);
|
||||
} else {
|
||||
window.showSaveResultModal?.('warning', '일괄 제출 부분 완료', `성공: ${successCount}건, 실패: ${failCount}건`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 상태 디버그
|
||||
*/
|
||||
debug() {
|
||||
console.log('[Controller] 상태 디버그:');
|
||||
this.state.debug();
|
||||
}
|
||||
}
|
||||
|
||||
// 전역 인스턴스 생성
|
||||
window.DailyWorkReportController = new DailyWorkReportController();
|
||||
|
||||
// 하위 호환성: 기존 전역 함수들
|
||||
window.switchTab = (tab) => window.DailyWorkReportController.switchTab(tab);
|
||||
window.submitTbmWorkReport = (index) => window.DailyWorkReportController.submitTbmWorkReport(index);
|
||||
window.batchSubmitTbmSession = (sessionKey) => window.DailyWorkReportController.batchSubmitSession(sessionKey);
|
||||
|
||||
// 사용자 정보 함수
|
||||
window.getUser = () => window.DailyWorkReportState.getUser();
|
||||
window.getCurrentUser = () => window.DailyWorkReportState.getCurrentUser();
|
||||
|
||||
// 날짜 그룹 토글 (UI 함수)
|
||||
window.toggleDateGroup = function(dateStr) {
|
||||
const group = document.querySelector(`.date-group[data-date="${dateStr}"]`);
|
||||
if (!group) return;
|
||||
|
||||
const isExpanded = group.classList.contains('expanded');
|
||||
const content = group.querySelector('.date-group-content');
|
||||
const icon = group.querySelector('.date-toggle-icon');
|
||||
|
||||
if (isExpanded) {
|
||||
group.classList.remove('expanded');
|
||||
group.classList.add('collapsed');
|
||||
if (content) content.style.display = 'none';
|
||||
if (icon) icon.textContent = '▶';
|
||||
} else {
|
||||
group.classList.remove('collapsed');
|
||||
group.classList.add('expanded');
|
||||
if (content) content.style.display = 'block';
|
||||
if (icon) icon.textContent = '▼';
|
||||
}
|
||||
};
|
||||
|
||||
// DOMContentLoaded 이벤트에서 초기화
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// 약간의 지연 후 초기화 (다른 스크립트 로드 대기)
|
||||
setTimeout(() => {
|
||||
window.DailyWorkReportController.init();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
console.log('[Module] daily-work-report/index.js 로드 완료');
|
||||
Reference in New Issue
Block a user