- codes.html, code-management.js 삭제 (tasks.html에서 동일 기능 제공) - 사이드바에서 코드 관리 링크 제거 - daily-work-report, tbm, workplace-management JS 모듈 분리 - common/security.js 추가 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
393 lines
9.9 KiB
JavaScript
393 lines
9.9 KiB
JavaScript
/**
|
|
* TBM - State Manager
|
|
* TBM 페이지의 전역 상태 관리
|
|
*/
|
|
|
|
class TbmState {
|
|
constructor() {
|
|
// 세션 데이터
|
|
this.allSessions = [];
|
|
this.todaySessions = [];
|
|
this.dateGroupedSessions = {};
|
|
this.allLoadedSessions = [];
|
|
this.loadedDaysCount = 7;
|
|
|
|
// 마스터 데이터
|
|
this.allWorkers = [];
|
|
this.allProjects = [];
|
|
this.allWorkTypes = [];
|
|
this.allTasks = [];
|
|
this.allSafetyChecks = [];
|
|
this.allWorkplaces = [];
|
|
this.allWorkplaceCategories = [];
|
|
|
|
// 현재 상태
|
|
this.currentUser = null;
|
|
this.currentSessionId = null;
|
|
this.currentTab = 'tbm-input';
|
|
|
|
// 작업자 관련
|
|
this.selectedWorkers = new Set();
|
|
this.workerTaskList = [];
|
|
this.selectedWorkersInModal = new Set();
|
|
this.currentEditingTaskLine = null;
|
|
|
|
// 작업장 선택 관련
|
|
this.selectedCategory = null;
|
|
this.selectedWorkplace = null;
|
|
this.selectedCategoryName = '';
|
|
this.selectedWorkplaceName = '';
|
|
|
|
// 일괄 설정 관련
|
|
this.isBulkMode = false;
|
|
this.bulkSelectedWorkers = new Set();
|
|
|
|
// 지도 관련
|
|
this.mapCanvas = null;
|
|
this.mapCtx = null;
|
|
this.mapImage = null;
|
|
this.mapRegions = [];
|
|
|
|
// 리스너
|
|
this.listeners = new Map();
|
|
|
|
console.log('[TbmState] 초기화 완료');
|
|
}
|
|
|
|
/**
|
|
* 상태 업데이트
|
|
*/
|
|
update(key, value) {
|
|
const prevValue = this[key];
|
|
this[key] = value;
|
|
this.notifyListeners(key, value, prevValue);
|
|
}
|
|
|
|
/**
|
|
* 리스너 등록
|
|
*/
|
|
subscribe(key, callback) {
|
|
if (!this.listeners.has(key)) {
|
|
this.listeners.set(key, []);
|
|
}
|
|
this.listeners.get(key).push(callback);
|
|
}
|
|
|
|
/**
|
|
* 리스너 알림
|
|
*/
|
|
notifyListeners(key, newValue, prevValue) {
|
|
const keyListeners = this.listeners.get(key) || [];
|
|
keyListeners.forEach(callback => {
|
|
try {
|
|
callback(newValue, prevValue);
|
|
} catch (error) {
|
|
console.error(`[TbmState] 리스너 오류 (${key}):`, error);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 현재 사용자 정보 가져오기
|
|
*/
|
|
getUser() {
|
|
if (!this.currentUser) {
|
|
const userInfo = localStorage.getItem('user');
|
|
this.currentUser = userInfo ? JSON.parse(userInfo) : null;
|
|
}
|
|
return this.currentUser;
|
|
}
|
|
|
|
/**
|
|
* Admin 여부 확인
|
|
*/
|
|
isAdminUser() {
|
|
const user = this.getUser();
|
|
if (!user) return false;
|
|
return user.role === 'Admin' || user.role === 'System Admin';
|
|
}
|
|
|
|
/**
|
|
* 탭 변경
|
|
*/
|
|
setCurrentTab(tab) {
|
|
const prevTab = this.currentTab;
|
|
this.currentTab = tab;
|
|
this.notifyListeners('currentTab', tab, prevTab);
|
|
}
|
|
|
|
/**
|
|
* 작업자 목록에 추가
|
|
*/
|
|
addWorkerToList(worker) {
|
|
this.workerTaskList.push({
|
|
worker_id: worker.worker_id,
|
|
worker_name: worker.worker_name,
|
|
job_type: worker.job_type,
|
|
tasks: [this.createEmptyTaskLine()]
|
|
});
|
|
this.notifyListeners('workerTaskList', this.workerTaskList, null);
|
|
}
|
|
|
|
/**
|
|
* 빈 작업 라인 생성
|
|
*/
|
|
createEmptyTaskLine() {
|
|
return {
|
|
task_line_id: this.generateUUID(),
|
|
project_id: null,
|
|
work_type_id: null,
|
|
task_id: null,
|
|
workplace_category_id: null,
|
|
workplace_id: null,
|
|
workplace_category_name: '',
|
|
workplace_name: '',
|
|
work_detail: null,
|
|
is_present: true
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 작업자에 작업 라인 추가
|
|
*/
|
|
addTaskLineToWorker(workerIndex) {
|
|
if (this.workerTaskList[workerIndex]) {
|
|
this.workerTaskList[workerIndex].tasks.push(this.createEmptyTaskLine());
|
|
this.notifyListeners('workerTaskList', this.workerTaskList, null);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 작업 라인 제거
|
|
*/
|
|
removeTaskLine(workerIndex, taskIndex) {
|
|
if (this.workerTaskList[workerIndex]?.tasks) {
|
|
this.workerTaskList[workerIndex].tasks.splice(taskIndex, 1);
|
|
this.notifyListeners('workerTaskList', this.workerTaskList, null);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 작업자 제거
|
|
*/
|
|
removeWorkerFromList(workerIndex) {
|
|
const removed = this.workerTaskList.splice(workerIndex, 1);
|
|
this.notifyListeners('workerTaskList', this.workerTaskList, null);
|
|
return removed[0];
|
|
}
|
|
|
|
/**
|
|
* 작업장 선택 초기화
|
|
*/
|
|
resetWorkplaceSelection() {
|
|
this.selectedCategory = null;
|
|
this.selectedWorkplace = null;
|
|
this.selectedCategoryName = '';
|
|
this.selectedWorkplaceName = '';
|
|
this.mapCanvas = null;
|
|
this.mapCtx = null;
|
|
this.mapImage = null;
|
|
this.mapRegions = [];
|
|
}
|
|
|
|
/**
|
|
* 일괄 설정 초기화
|
|
*/
|
|
resetBulkSettings() {
|
|
this.isBulkMode = false;
|
|
this.bulkSelectedWorkers.clear();
|
|
}
|
|
|
|
/**
|
|
* 날짜별 세션 그룹화
|
|
*/
|
|
groupSessionsByDate(sessions) {
|
|
this.dateGroupedSessions = {};
|
|
this.allLoadedSessions = [];
|
|
|
|
sessions.forEach(session => {
|
|
const date = this.formatDate(session.session_date);
|
|
if (!this.dateGroupedSessions[date]) {
|
|
this.dateGroupedSessions[date] = [];
|
|
}
|
|
this.dateGroupedSessions[date].push(session);
|
|
this.allLoadedSessions.push(session);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 날짜 포맷팅
|
|
*/
|
|
formatDate(dateString) {
|
|
if (!dateString) return '';
|
|
if (/^\d{4}-\d{2}-\d{2}$/.test(dateString)) {
|
|
return dateString;
|
|
}
|
|
const date = new Date(dateString);
|
|
const year = date.getFullYear();
|
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
const day = String(date.getDate()).padStart(2, '0');
|
|
return `${year}-${month}-${day}`;
|
|
}
|
|
|
|
/**
|
|
* UUID 생성
|
|
*/
|
|
generateUUID() {
|
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
|
const r = Math.random() * 16 | 0;
|
|
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
return v.toString(16);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 상태 초기화
|
|
*/
|
|
reset() {
|
|
this.workerTaskList = [];
|
|
this.selectedWorkers.clear();
|
|
this.selectedWorkersInModal.clear();
|
|
this.currentEditingTaskLine = null;
|
|
this.resetWorkplaceSelection();
|
|
this.resetBulkSettings();
|
|
}
|
|
|
|
/**
|
|
* 디버그 출력
|
|
*/
|
|
debug() {
|
|
console.log('[TbmState] 현재 상태:', {
|
|
allSessions: this.allSessions.length,
|
|
todaySessions: this.todaySessions.length,
|
|
allWorkers: this.allWorkers.length,
|
|
allProjects: this.allProjects.length,
|
|
workerTaskList: this.workerTaskList.length,
|
|
currentTab: this.currentTab
|
|
});
|
|
}
|
|
}
|
|
|
|
// 전역 인스턴스 생성
|
|
window.TbmState = new TbmState();
|
|
|
|
// 하위 호환성을 위한 전역 변수 프록시
|
|
const tbmStateProxy = window.TbmState;
|
|
|
|
Object.defineProperties(window, {
|
|
allSessions: {
|
|
get: () => tbmStateProxy.allSessions,
|
|
set: (v) => { tbmStateProxy.allSessions = v; }
|
|
},
|
|
todaySessions: {
|
|
get: () => tbmStateProxy.todaySessions,
|
|
set: (v) => { tbmStateProxy.todaySessions = v; }
|
|
},
|
|
allWorkers: {
|
|
get: () => tbmStateProxy.allWorkers,
|
|
set: (v) => { tbmStateProxy.allWorkers = v; }
|
|
},
|
|
allProjects: {
|
|
get: () => tbmStateProxy.allProjects,
|
|
set: (v) => { tbmStateProxy.allProjects = v; }
|
|
},
|
|
allWorkTypes: {
|
|
get: () => tbmStateProxy.allWorkTypes,
|
|
set: (v) => { tbmStateProxy.allWorkTypes = v; }
|
|
},
|
|
allTasks: {
|
|
get: () => tbmStateProxy.allTasks,
|
|
set: (v) => { tbmStateProxy.allTasks = v; }
|
|
},
|
|
allSafetyChecks: {
|
|
get: () => tbmStateProxy.allSafetyChecks,
|
|
set: (v) => { tbmStateProxy.allSafetyChecks = v; }
|
|
},
|
|
allWorkplaces: {
|
|
get: () => tbmStateProxy.allWorkplaces,
|
|
set: (v) => { tbmStateProxy.allWorkplaces = v; }
|
|
},
|
|
allWorkplaceCategories: {
|
|
get: () => tbmStateProxy.allWorkplaceCategories,
|
|
set: (v) => { tbmStateProxy.allWorkplaceCategories = v; }
|
|
},
|
|
currentUser: {
|
|
get: () => tbmStateProxy.currentUser,
|
|
set: (v) => { tbmStateProxy.currentUser = v; }
|
|
},
|
|
currentSessionId: {
|
|
get: () => tbmStateProxy.currentSessionId,
|
|
set: (v) => { tbmStateProxy.currentSessionId = v; }
|
|
},
|
|
selectedWorkers: {
|
|
get: () => tbmStateProxy.selectedWorkers,
|
|
set: (v) => { tbmStateProxy.selectedWorkers = v; }
|
|
},
|
|
workerTaskList: {
|
|
get: () => tbmStateProxy.workerTaskList,
|
|
set: (v) => { tbmStateProxy.workerTaskList = v; }
|
|
},
|
|
selectedWorkersInModal: {
|
|
get: () => tbmStateProxy.selectedWorkersInModal,
|
|
set: (v) => { tbmStateProxy.selectedWorkersInModal = v; }
|
|
},
|
|
currentEditingTaskLine: {
|
|
get: () => tbmStateProxy.currentEditingTaskLine,
|
|
set: (v) => { tbmStateProxy.currentEditingTaskLine = v; }
|
|
},
|
|
selectedCategory: {
|
|
get: () => tbmStateProxy.selectedCategory,
|
|
set: (v) => { tbmStateProxy.selectedCategory = v; }
|
|
},
|
|
selectedWorkplace: {
|
|
get: () => tbmStateProxy.selectedWorkplace,
|
|
set: (v) => { tbmStateProxy.selectedWorkplace = v; }
|
|
},
|
|
selectedCategoryName: {
|
|
get: () => tbmStateProxy.selectedCategoryName,
|
|
set: (v) => { tbmStateProxy.selectedCategoryName = v; }
|
|
},
|
|
selectedWorkplaceName: {
|
|
get: () => tbmStateProxy.selectedWorkplaceName,
|
|
set: (v) => { tbmStateProxy.selectedWorkplaceName = v; }
|
|
},
|
|
isBulkMode: {
|
|
get: () => tbmStateProxy.isBulkMode,
|
|
set: (v) => { tbmStateProxy.isBulkMode = v; }
|
|
},
|
|
bulkSelectedWorkers: {
|
|
get: () => tbmStateProxy.bulkSelectedWorkers,
|
|
set: (v) => { tbmStateProxy.bulkSelectedWorkers = v; }
|
|
},
|
|
dateGroupedSessions: {
|
|
get: () => tbmStateProxy.dateGroupedSessions,
|
|
set: (v) => { tbmStateProxy.dateGroupedSessions = v; }
|
|
},
|
|
allLoadedSessions: {
|
|
get: () => tbmStateProxy.allLoadedSessions,
|
|
set: (v) => { tbmStateProxy.allLoadedSessions = v; }
|
|
},
|
|
loadedDaysCount: {
|
|
get: () => tbmStateProxy.loadedDaysCount,
|
|
set: (v) => { tbmStateProxy.loadedDaysCount = v; }
|
|
},
|
|
mapRegions: {
|
|
get: () => tbmStateProxy.mapRegions,
|
|
set: (v) => { tbmStateProxy.mapRegions = v; }
|
|
},
|
|
mapCanvas: {
|
|
get: () => tbmStateProxy.mapCanvas,
|
|
set: (v) => { tbmStateProxy.mapCanvas = v; }
|
|
},
|
|
mapCtx: {
|
|
get: () => tbmStateProxy.mapCtx,
|
|
set: (v) => { tbmStateProxy.mapCtx = v; }
|
|
},
|
|
mapImage: {
|
|
get: () => tbmStateProxy.mapImage,
|
|
set: (v) => { tbmStateProxy.mapImage = v; }
|
|
}
|
|
});
|
|
|
|
console.log('[Module] tbm/state.js 로드 완료');
|