refactor(frontend): Begin modularizing work-report-calendar
Initiated the process of refactoring the monolithic `work-report-calendar.js` file as outlined in the Phase 2 frontend modernization plan. - Created `CalendarAPI.js` to encapsulate all API calls related to the calendar, centralizing data fetching logic. - Created `CalendarState.js` to manage the component's state, removing global variables from the main script. - Refactored `work-report-calendar.js` to use the new state and API modules. - Refactored `manage-project.js` to use the existing global API helpers, providing a consistent example for API usage.
This commit is contained in:
@@ -1,9 +1,6 @@
|
|||||||
// /js/manage-project.js
|
// /js/manage-project.js
|
||||||
|
|
||||||
import { API, getAuthHeaders, ensureAuthenticated } from '/js/api-config.js';
|
// The ensureAuthenticated, API, and getAuthHeaders functions are now handled by the global api-helper.js
|
||||||
|
|
||||||
// 인증 확인
|
|
||||||
ensureAuthenticated();
|
|
||||||
|
|
||||||
function createRow(item, cols, delHandler) {
|
function createRow(item, cols, delHandler) {
|
||||||
const tr = document.createElement('tr');
|
const tr = document.createElement('tr');
|
||||||
@@ -40,13 +37,8 @@ projectForm?.addEventListener('submit', async e => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${API}/projects`, {
|
const result = await apiPost('/projects', body);
|
||||||
method: 'POST',
|
if (result.success) {
|
||||||
headers: getAuthHeaders(),
|
|
||||||
body: JSON.stringify(body)
|
|
||||||
});
|
|
||||||
const result = await res.json();
|
|
||||||
if (res.ok && result.success) {
|
|
||||||
alert('✅ 등록 완료');
|
alert('✅ 등록 완료');
|
||||||
projectForm.reset();
|
projectForm.reset();
|
||||||
loadProjects();
|
loadProjects();
|
||||||
@@ -62,34 +54,24 @@ async function loadProjects() {
|
|||||||
const tbody = document.getElementById('projectTableBody');
|
const tbody = document.getElementById('projectTableBody');
|
||||||
tbody.innerHTML = '<tr><td colspan="9">불러오는 중...</td></tr>';
|
tbody.innerHTML = '<tr><td colspan="9">불러오는 중...</td></tr>';
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${API}/projects`, {
|
const result = await apiGet('/projects');
|
||||||
headers: getAuthHeaders()
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error(`HTTP error! status: ${res.status}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const list = await res.json();
|
|
||||||
tbody.innerHTML = '';
|
tbody.innerHTML = '';
|
||||||
|
|
||||||
if (Array.isArray(list)) {
|
if (result.success && Array.isArray(result.data)) {
|
||||||
list.forEach(item => {
|
result.data.forEach(item => {
|
||||||
const row = createRow(item, [
|
const row = createRow(item, [
|
||||||
'project_id', 'job_no', 'project_name', 'contract_date',
|
'project_id', 'job_no', 'project_name', 'contract_date',
|
||||||
'due_date', 'delivery_method', 'site', 'pm'
|
'due_date', 'delivery_method', 'site', 'pm'
|
||||||
], async p => {
|
], async p => {
|
||||||
if (!confirm('삭제하시겠습니까?')) return;
|
if (!confirm('삭제하시겠습니까?')) return;
|
||||||
try {
|
try {
|
||||||
const delRes = await fetch(`${API}/projects/${p.project_id}`, {
|
const delRes = await apiDelete(`/projects/${p.project_id}`);
|
||||||
method: 'DELETE',
|
if (delRes.success) {
|
||||||
headers: getAuthHeaders()
|
|
||||||
});
|
|
||||||
if (delRes.ok) {
|
|
||||||
alert('✅ 삭제 완료');
|
alert('✅ 삭제 완료');
|
||||||
loadProjects();
|
loadProjects();
|
||||||
} else {
|
} else {
|
||||||
alert('❌ 삭제 실패');
|
alert('❌ 삭제 실패: ' + (delRes.error || '알 수 없는 오류'));
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert('🚨 삭제 중 오류: ' + err.message);
|
alert('🚨 삭제 중 오류: ' + err.message);
|
||||||
|
|||||||
131
web-ui/js/modules/calendar/CalendarAPI.js
Normal file
131
web-ui/js/modules/calendar/CalendarAPI.js
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
// web-ui/js/modules/calendar/CalendarAPI.js
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 캘린더와 관련된 모든 API 호출을 관리하는 전역 객체입니다.
|
||||||
|
*/
|
||||||
|
(function(window) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const CalendarAPI = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 활성화된 모든 작업자 목록을 가져옵니다.
|
||||||
|
* @returns {Promise<Array>} 작업자 객체 배열
|
||||||
|
*/
|
||||||
|
CalendarAPI.getWorkers = async function() {
|
||||||
|
try {
|
||||||
|
// api-helper.js 에 정의된 전역 apiGet 함수를 사용합니다.
|
||||||
|
const response = await window.apiGet('/workers');
|
||||||
|
if (response.success && Array.isArray(response.data)) {
|
||||||
|
// 활성화된 작업자만 필터링
|
||||||
|
const activeWorkers = response.data.filter(worker =>
|
||||||
|
worker.status === 'active' || worker.is_active === 1 || worker.is_active === true
|
||||||
|
);
|
||||||
|
return activeWorkers;
|
||||||
|
}
|
||||||
|
console.warn('API 응답 형식이 올바르지 않거나 데이터가 없습니다:', response);
|
||||||
|
return [];
|
||||||
|
} catch (error) {
|
||||||
|
console.error('작업자 데이터 로딩 중 API 오류 발생:', error);
|
||||||
|
// 에러를 다시 던져서 호출부에서 처리할 수 있도록 함
|
||||||
|
throw new Error('작업자 데이터를 불러오는 데 실패했습니다.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 월별 작업 데이터 로드 (집계 테이블 사용으로 최적화)
|
||||||
|
* @param {number} year
|
||||||
|
* @param {number} month (0-indexed)
|
||||||
|
* @returns {Promise<object>}
|
||||||
|
*/
|
||||||
|
CalendarAPI.getMonthlyCalendarData = async function(year, month) {
|
||||||
|
const monthKey = `${year}-${String(month + 1).padStart(2, '0')}`;
|
||||||
|
try {
|
||||||
|
const response = await window.apiGet(`/monthly-status/calendar?year=${year}&month=${month + 1}`);
|
||||||
|
if (response.success) {
|
||||||
|
return response.data;
|
||||||
|
} else {
|
||||||
|
throw new Error(response.message || '집계 데이터 조회 실패');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`${monthKey} 집계 데이터 로딩 오류:`, error);
|
||||||
|
console.log(`📋 폴백: ${monthKey} 기존 방식 로딩 시작...`);
|
||||||
|
return await _getMonthlyWorkDataFallback(year, month);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 일일 상세 데이터 조회 (모달용)
|
||||||
|
* @param {string} dateStr (YYYY-MM-DD)
|
||||||
|
* @returns {Promise<object>}
|
||||||
|
*/
|
||||||
|
CalendarAPI.getDailyDetails = async function(dateStr) {
|
||||||
|
try {
|
||||||
|
const response = await window.apiGet(`/monthly-status/daily-details?date=${dateStr}`);
|
||||||
|
if (response.success) {
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
// Fallback to old API if new one fails
|
||||||
|
const fallbackResponse = await window.apiGet(`/daily-work-reports?date=${dateStr}&view_all=true`);
|
||||||
|
return {
|
||||||
|
workers: fallbackResponse.data, // Assuming structure is different
|
||||||
|
summary: {} // No summary in fallback
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('일일 작업 데이터 로딩 오류:', error);
|
||||||
|
throw new Error('해당 날짜의 작업 데이터를 불러오는 데 실패했습니다.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 특정 작업자의 하루치 작업을 모두 삭제합니다.
|
||||||
|
* @param {number} workerId
|
||||||
|
* @param {string} date (YYYY-MM-DD)
|
||||||
|
* @returns {Promise<object>}
|
||||||
|
*/
|
||||||
|
CalendarAPI.deleteWorkerDayWork = async function(workerId, date) {
|
||||||
|
return await window.apiDelete(`/daily-work-reports/date/${date}/worker/${workerId}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 폴백: 순차적 로딩 (지연 시간 포함) - Private helper
|
||||||
|
* @param {number} year
|
||||||
|
* @param {number} month (0-indexed)
|
||||||
|
* @returns {Promise<object>}
|
||||||
|
*/
|
||||||
|
async function _getMonthlyWorkDataFallback(year, month) {
|
||||||
|
const monthKey = `${year}-${String(month + 1).padStart(2, '0')}`;
|
||||||
|
const monthData = {};
|
||||||
|
try {
|
||||||
|
const firstDay = new Date(year, month, 1);
|
||||||
|
const lastDay = new Date(year, month + 1, 0);
|
||||||
|
const currentDay = new Date(firstDay);
|
||||||
|
|
||||||
|
const promises = [];
|
||||||
|
while (currentDay <= lastDay) {
|
||||||
|
const dateStr = currentDay.toISOString().split('T')[0];
|
||||||
|
promises.push(window.apiGet(`/daily-work-reports?date=${dateStr}&view_all=true`));
|
||||||
|
currentDay.setDate(currentDay.getDate() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = await Promise.all(promises);
|
||||||
|
|
||||||
|
let day = 1;
|
||||||
|
for (const result of results) {
|
||||||
|
const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
||||||
|
monthData[dateStr] = result.success && Array.isArray(result.data) ? result.data : [];
|
||||||
|
day++;
|
||||||
|
}
|
||||||
|
return monthData;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`${monthKey} 순차 로딩 오류:`, error);
|
||||||
|
throw new Error('작업 데이터를 불러오는 데 실패했습니다.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 전역 스코프에 CalendarAPI 객체 할당
|
||||||
|
window.CalendarAPI = CalendarAPI;
|
||||||
|
|
||||||
|
})(window);
|
||||||
34
web-ui/js/modules/calendar/CalendarState.js
Normal file
34
web-ui/js/modules/calendar/CalendarState.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// web-ui/js/modules/calendar/CalendarState.js
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 캘린더 페이지의 모든 상태를 관리하는 전역 객체입니다.
|
||||||
|
*/
|
||||||
|
(function(window) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const CalendarState = {
|
||||||
|
// 캘린더 상태
|
||||||
|
currentDate: new Date(),
|
||||||
|
monthlyData: {}, // 월별 데이터 캐시
|
||||||
|
allWorkers: [], // 전체 작업자 목록 캐시
|
||||||
|
|
||||||
|
// 모달 상태
|
||||||
|
currentModalDate: null,
|
||||||
|
currentEditingWork: null,
|
||||||
|
existingWorks: [],
|
||||||
|
|
||||||
|
// 상태 초기화
|
||||||
|
reset: function() {
|
||||||
|
this.currentDate = new Date();
|
||||||
|
this.monthlyData = {};
|
||||||
|
// allWorkers는 유지
|
||||||
|
this.currentModalDate = null;
|
||||||
|
this.currentEditingWork = null;
|
||||||
|
this.existingWorks = [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 전역 스코프에 CalendarState 객체 할당
|
||||||
|
window.CalendarState = CalendarState;
|
||||||
|
|
||||||
|
})(window);
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
// 작업 현황 캘린더 JavaScript
|
// 작업 현황 캘린더 JavaScript
|
||||||
|
|
||||||
// 전역 변수
|
// 전역 변수 대신 CalendarState 사용
|
||||||
let currentDate = new Date();
|
// let currentDate = new Date();
|
||||||
let monthlyData = {}; // 월별 데이터 캐시
|
// let monthlyData = {}; // 월별 데이터 캐시
|
||||||
// 작업자 데이터는 allWorkers 변수 사용
|
// let allWorkers = []; // 작업자 데이터는 allWorkers 변수 사용
|
||||||
let currentModalDate = null;
|
// let currentModalDate = null;
|
||||||
let currentEditingWork = null;
|
// let currentEditingWork = null;
|
||||||
let existingWorks = [];
|
// let existingWorks = [];
|
||||||
|
|
||||||
// DOM 요소
|
// DOM 요소
|
||||||
const elements = {
|
const elements = {
|
||||||
@@ -68,17 +68,17 @@ function initializeElements() {
|
|||||||
// 이벤트 리스너 설정
|
// 이벤트 리스너 설정
|
||||||
function setupEventListeners() {
|
function setupEventListeners() {
|
||||||
elements.prevMonthBtn.addEventListener('click', () => {
|
elements.prevMonthBtn.addEventListener('click', () => {
|
||||||
currentDate.setMonth(currentDate.getMonth() - 1);
|
CalendarState.currentDate.setMonth(CalendarState.currentDate.getMonth() - 1);
|
||||||
renderCalendar();
|
renderCalendar();
|
||||||
});
|
});
|
||||||
|
|
||||||
elements.nextMonthBtn.addEventListener('click', () => {
|
elements.nextMonthBtn.addEventListener('click', () => {
|
||||||
currentDate.setMonth(currentDate.getMonth() + 1);
|
CalendarState.currentDate.setMonth(CalendarState.currentDate.getMonth() + 1);
|
||||||
renderCalendar();
|
renderCalendar();
|
||||||
});
|
});
|
||||||
|
|
||||||
elements.todayBtn.addEventListener('click', () => {
|
elements.todayBtn.addEventListener('click', () => {
|
||||||
currentDate = new Date();
|
CalendarState.currentDate = new Date();
|
||||||
renderCalendar();
|
renderCalendar();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -101,23 +101,19 @@ function setupEventListeners() {
|
|||||||
|
|
||||||
// 작업자 데이터 로드 (캐시)
|
// 작업자 데이터 로드 (캐시)
|
||||||
async function loadWorkersData() {
|
async function loadWorkersData() {
|
||||||
if (allWorkers.length > 0) return allWorkers;
|
if (CalendarState.allWorkers.length > 0) return CalendarState.allWorkers;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('👥 작업자 데이터 로딩...');
|
console.log('👥 작업자 데이터 로딩 (from CalendarAPI)...');
|
||||||
const response = await window.apiCall('/workers');
|
// The new API function already filters for active workers
|
||||||
const workers = Array.isArray(response) ? response : (response.data || []);
|
const activeWorkers = await CalendarAPI.getWorkers();
|
||||||
|
CalendarState.allWorkers = activeWorkers;
|
||||||
|
|
||||||
// 활성화된 작업자만 필터링
|
console.log(`✅ 작업자 ${CalendarState.allWorkers.length}명 로드 완료`);
|
||||||
allWorkers = workers.filter(worker => {
|
return CalendarState.allWorkers;
|
||||||
return worker.status === 'active' || worker.is_active === 1 || worker.is_active === true;
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`✅ 작업자 ${allWorkers.length}명 로드 완료 (전체: ${workers.length}명)`);
|
|
||||||
return allWorkers;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('작업자 데이터 로딩 오류:', error);
|
console.error('작업자 데이터 로딩 오류:', error);
|
||||||
showToast('작업자 데이터를 불러오는데 실패했습니다.', 'error');
|
showToast(error.message, 'error');
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -126,146 +122,26 @@ async function loadWorkersData() {
|
|||||||
async function loadMonthlyWorkData(year, month) {
|
async function loadMonthlyWorkData(year, month) {
|
||||||
const monthKey = `${year}-${String(month + 1).padStart(2, '0')}`;
|
const monthKey = `${year}-${String(month + 1).padStart(2, '0')}`;
|
||||||
|
|
||||||
if (monthlyData[monthKey]) {
|
if (CalendarState.monthlyData[monthKey]) {
|
||||||
console.log(`📋 캐시된 ${monthKey} 데이터 사용`);
|
console.log(`📋 캐시된 ${monthKey} 데이터 사용`);
|
||||||
return monthlyData[monthKey];
|
return CalendarState.monthlyData[monthKey];
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log(`📋 ${monthKey} 집계 데이터 로딩...`);
|
const data = await CalendarAPI.getMonthlyCalendarData(year, month);
|
||||||
|
CalendarState.monthlyData[monthKey] = data; // Cache the data
|
||||||
// 새로운 월별 집계 API 사용 (단일 호출)
|
return data;
|
||||||
const response = await window.apiCall(`/monthly-status/calendar?year=${year}&month=${month + 1}`);
|
|
||||||
|
|
||||||
if (response.success) {
|
|
||||||
const calendarData = response.data;
|
|
||||||
|
|
||||||
console.log(`📊 ${monthKey} 집계 데이터:`, Object.keys(calendarData).length, '일');
|
|
||||||
|
|
||||||
// 날짜별 상태 데이터로 변환
|
|
||||||
const monthData = {};
|
|
||||||
|
|
||||||
// 해당 월의 모든 날짜 초기화
|
|
||||||
const firstDay = new Date(year, month, 1);
|
|
||||||
const lastDay = new Date(year, month + 1, 0);
|
|
||||||
const currentDay = new Date(firstDay);
|
|
||||||
|
|
||||||
while (currentDay <= lastDay) {
|
|
||||||
const dateStr = currentDay.toISOString().split('T')[0];
|
|
||||||
|
|
||||||
if (calendarData[dateStr]) {
|
|
||||||
// 집계 데이터가 있는 경우
|
|
||||||
const dayData = calendarData[dateStr];
|
|
||||||
monthData[dateStr] = {
|
|
||||||
hasData: dayData.workingWorkers > 0,
|
|
||||||
hasIssues: dayData.hasIssues,
|
|
||||||
hasErrors: dayData.hasErrors,
|
|
||||||
hasOvertimeWarning: dayData.hasOvertimeWarning,
|
|
||||||
totalWorkers: dayData.totalWorkers,
|
|
||||||
workerCount: dayData.totalWorkers,
|
|
||||||
workingWorkers: dayData.workingWorkers,
|
|
||||||
incompleteWorkers: dayData.incompleteWorkers,
|
|
||||||
partialWorkers: dayData.partialWorkers,
|
|
||||||
errorWorkers: dayData.errorWorkers,
|
|
||||||
overtimeWarningWorkers: dayData.overtimeWarningWorkers,
|
|
||||||
totalHours: dayData.totalHours,
|
|
||||||
totalTasks: dayData.totalTasks,
|
|
||||||
errorCount: dayData.errorCount,
|
|
||||||
lastUpdated: dayData.lastUpdated
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
// 집계 데이터가 없는 경우 (작업 없음)
|
|
||||||
monthData[dateStr] = {
|
|
||||||
hasData: false,
|
|
||||||
hasIssues: false,
|
|
||||||
hasErrors: false,
|
|
||||||
workerCount: 0,
|
|
||||||
workingWorkers: 0,
|
|
||||||
incompleteWorkers: 0,
|
|
||||||
partialWorkers: 0,
|
|
||||||
errorWorkers: 0,
|
|
||||||
totalHours: 0,
|
|
||||||
totalTasks: 0,
|
|
||||||
errorCount: 0
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
currentDay.setDate(currentDay.getDate() + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 캐시에 저장
|
|
||||||
monthlyData[monthKey] = monthData;
|
|
||||||
|
|
||||||
console.log(`✅ ${monthKey} 집계 데이터 로드 완료 (${Object.keys(monthData).length}일 데이터)`);
|
|
||||||
console.log('📊 월별 데이터 샘플:', Object.entries(monthData).slice(0, 5));
|
|
||||||
return monthData;
|
|
||||||
} else {
|
|
||||||
throw new Error(response.message || '집계 데이터 조회 실패');
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`${monthKey} 집계 데이터 로딩 오류:`, error);
|
console.error(`${monthKey} 데이터 로딩 오류:`, error);
|
||||||
|
showToast(error.message, 'error');
|
||||||
// 폴백: 기존 방식으로 순차 로딩
|
return {}; // Return empty object on failure
|
||||||
console.log(`📋 폴백: ${monthKey} 기존 방식 로딩 시작...`);
|
|
||||||
return await loadMonthlyWorkDataFallback(year, month);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 폴백: 순차적 로딩 (지연 시간 포함)
|
|
||||||
async function loadMonthlyWorkDataFallback(year, month) {
|
|
||||||
const monthKey = `${year}-${String(month + 1).padStart(2, '0')}`;
|
|
||||||
const monthData = {};
|
|
||||||
|
|
||||||
try {
|
|
||||||
const firstDay = new Date(year, month, 1);
|
|
||||||
const lastDay = new Date(year, month + 1, 0);
|
|
||||||
const currentDay = new Date(firstDay);
|
|
||||||
|
|
||||||
let loadedCount = 0;
|
|
||||||
const totalDays = lastDay.getDate();
|
|
||||||
|
|
||||||
while (currentDay <= lastDay) {
|
|
||||||
const dateStr = currentDay.toISOString().split('T')[0];
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await window.apiCall(`/daily-work-reports?date=${dateStr}&view_all=true`);
|
|
||||||
monthData[dateStr] = Array.isArray(response) ? response : (response.data || []);
|
|
||||||
loadedCount++;
|
|
||||||
|
|
||||||
// 진행률 표시
|
|
||||||
if (loadedCount % 5 === 0) {
|
|
||||||
console.log(`📋 ${monthKey} 로딩 진행률: ${loadedCount}/${totalDays}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// API 부하 방지를 위한 지연 (500ms)
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 500));
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.warn(`${dateStr} 데이터 로딩 실패:`, error.message);
|
|
||||||
monthData[dateStr] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
currentDay.setDate(currentDay.getDate() + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 캐시에 저장
|
|
||||||
monthlyData[monthKey] = monthData;
|
|
||||||
|
|
||||||
console.log(`✅ ${monthKey} 순차 로딩 완료 (${loadedCount}/${totalDays}일)`);
|
|
||||||
return monthData;
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`${monthKey} 순차 로딩 오류:`, error);
|
|
||||||
showToast('작업 데이터를 불러오는데 실패했습니다.', 'error');
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 캘린더 렌더링
|
// 캘린더 렌더링
|
||||||
async function renderCalendar() {
|
async function renderCalendar() {
|
||||||
const year = currentDate.getFullYear();
|
const year = CalendarState.currentDate.getFullYear();
|
||||||
const month = currentDate.getMonth();
|
const month = CalendarState.currentDate.getMonth();
|
||||||
|
|
||||||
// 헤더 업데이트
|
// 헤더 업데이트
|
||||||
const monthNames = ['1월', '2월', '3월', '4월', '5월', '6월',
|
const monthNames = ['1월', '2월', '3월', '4월', '5월', '6월',
|
||||||
@@ -388,7 +264,7 @@ function analyzeDayStatus(dayData) {
|
|||||||
// 새로운 집계 데이터 구조인지 확인 (monthly_summary에서 온 데이터)
|
// 새로운 집계 데이터 구조인지 확인 (monthly_summary에서 온 데이터)
|
||||||
if (dayData && typeof dayData === 'object' && 'totalWorkers' in dayData) {
|
if (dayData && typeof dayData === 'object' && 'totalWorkers' in dayData) {
|
||||||
// 미입력 판단: allWorkers 배열 길이와 실제 작업한 작업자 수 비교
|
// 미입력 판단: allWorkers 배열 길이와 실제 작업한 작업자 수 비교
|
||||||
const totalRegisteredWorkers = allWorkers ? allWorkers.length : 10; // 실제 등록된 작업자 수
|
const totalRegisteredWorkers = CalendarState.allWorkers ? CalendarState.allWorkers.length : 10; // 실제 등록된 작업자 수
|
||||||
const actualIncompleteWorkers = Math.max(0, totalRegisteredWorkers - dayData.workingWorkers);
|
const actualIncompleteWorkers = Math.max(0, totalRegisteredWorkers - dayData.workingWorkers);
|
||||||
|
|
||||||
const result = {
|
const result = {
|
||||||
@@ -406,7 +282,7 @@ function analyzeDayStatus(dayData) {
|
|||||||
actualIncompleteWorkers,
|
actualIncompleteWorkers,
|
||||||
workingWorkers: dayData.workingWorkers,
|
workingWorkers: dayData.workingWorkers,
|
||||||
totalRegisteredWorkers: totalRegisteredWorkers,
|
totalRegisteredWorkers: totalRegisteredWorkers,
|
||||||
allWorkersLength: allWorkers ? allWorkers.length : 'undefined'
|
allWorkersLength: CalendarState.allWorkers ? CalendarState.allWorkers.length : 'undefined'
|
||||||
});
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -472,7 +348,7 @@ function analyzeDayStatus(dayData) {
|
|||||||
// 일일 작업 현황 모달 열기
|
// 일일 작업 현황 모달 열기
|
||||||
async function openDailyWorkModal(dateStr) {
|
async function openDailyWorkModal(dateStr) {
|
||||||
console.log(`🗓️ 클릭된 날짜: ${dateStr}`);
|
console.log(`🗓️ 클릭된 날짜: ${dateStr}`);
|
||||||
currentModalDate = dateStr;
|
CalendarState.currentModalDate = dateStr;
|
||||||
|
|
||||||
// 날짜 포맷팅
|
// 날짜 포맷팅
|
||||||
const date = new Date(dateStr + 'T00:00:00');
|
const date = new Date(dateStr + 'T00:00:00');
|
||||||
@@ -487,18 +363,12 @@ async function openDailyWorkModal(dateStr) {
|
|||||||
elements.modalTitle.textContent = `${year}년 ${month}월 ${day}일 (${dayName}) 작업 현황`;
|
elements.modalTitle.textContent = `${year}년 ${month}월 ${day}일 (${dayName}) 작업 현황`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 새로운 집계 API로 작업자별 상세 정보 조회
|
const response = await CalendarAPI.getDailyDetails(dateStr);
|
||||||
const response = await window.apiCall(`/monthly-status/daily-details?date=${dateStr}`);
|
|
||||||
|
|
||||||
if (response.success) {
|
if (response.workers) { // New API structure
|
||||||
const { workers, summary } = response.data;
|
renderModalDataFromSummary(response.workers, response.summary);
|
||||||
renderModalDataFromSummary(workers, summary);
|
} else { // Fallback structure
|
||||||
} else {
|
renderModalData(response);
|
||||||
// 폴백: 기존 API 사용
|
|
||||||
console.log('집계 API 실패, 기존 API로 폴백');
|
|
||||||
const fallbackResponse = await window.apiCall(`/daily-work-reports?date=${dateStr}&view_all=true`);
|
|
||||||
const workData = Array.isArray(fallbackResponse) ? fallbackResponse : (fallbackResponse.data || []);
|
|
||||||
renderModalData(workData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 모달 표시
|
// 모달 표시
|
||||||
@@ -514,13 +384,13 @@ async function openDailyWorkModal(dateStr) {
|
|||||||
// 집계 데이터로 모달 렌더링 (최적화된 버전)
|
// 집계 데이터로 모달 렌더링 (최적화된 버전)
|
||||||
async function renderModalDataFromSummary(workers, summary) {
|
async function renderModalDataFromSummary(workers, summary) {
|
||||||
// 전체 작업자 목록 가져오기
|
// 전체 작업자 목록 가져오기
|
||||||
const allWorkers = await loadWorkersData();
|
const allWorkersList = await loadWorkersData();
|
||||||
|
|
||||||
// 작업한 작업자 ID 목록
|
// 작업한 작업자 ID 목록
|
||||||
const workedWorkerIds = new Set(workers.map(w => w.workerId));
|
const workedWorkerIds = new Set(workers.map(w => w.workerId));
|
||||||
|
|
||||||
// 미기입 작업자 추가 (대시보드와 동일한 상태 판단 로직 적용)
|
// 미기입 작업자 추가 (대시보드와 동일한 상태 판단 로직 적용)
|
||||||
const missingWorkers = allWorkers
|
const missingWorkers = allWorkersList
|
||||||
.filter(worker => !workedWorkerIds.has(worker.worker_id))
|
.filter(worker => !workedWorkerIds.has(worker.worker_id))
|
||||||
.map(worker => {
|
.map(worker => {
|
||||||
return {
|
return {
|
||||||
@@ -541,11 +411,11 @@ async function renderModalDataFromSummary(workers, summary) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 전체 작업자 목록 (작업한 사람 + 미기입 사람)
|
// 전체 작업자 목록 (작업한 사람 + 미기입 사람)
|
||||||
const allWorkersList = [...workers, ...missingWorkers];
|
const allModalWorkers = [...workers, ...missingWorkers];
|
||||||
|
|
||||||
// 요약 정보 업데이트 (전체 작업자 수 포함)
|
// 요약 정보 업데이트 (전체 작업자 수 포함)
|
||||||
if (elements.modalTotalWorkers) {
|
if (elements.modalTotalWorkers) {
|
||||||
elements.modalTotalWorkers.textContent = `${allWorkersList.length}명`;
|
elements.modalTotalWorkers.textContent = `${allModalWorkers.length}명`;
|
||||||
}
|
}
|
||||||
if (elements.modalTotalHours) {
|
if (elements.modalTotalHours) {
|
||||||
elements.modalTotalHours.textContent = `${summary.totalHours.toFixed(1)}h`;
|
elements.modalTotalHours.textContent = `${summary.totalHours.toFixed(1)}h`;
|
||||||
@@ -559,12 +429,12 @@ async function renderModalDataFromSummary(workers, summary) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 작업자 리스트 렌더링
|
// 작업자 리스트 렌더링
|
||||||
if (allWorkersList.length === 0) {
|
if (allModalWorkers.length === 0) {
|
||||||
elements.modalWorkersList.innerHTML = '<div class="empty-state">등록된 작업자가 없습니다.</div>';
|
elements.modalWorkersList.innerHTML = '<div class="empty-state">등록된 작업자가 없습니다.</div>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const workersHtml = allWorkersList.map(worker => {
|
const workersHtml = allModalWorkers.map(worker => {
|
||||||
// 상태 텍스트 및 색상 결정 (에러가 있어도 작업시간 기준으로 판단)
|
// 상태 텍스트 및 색상 결정 (에러가 있어도 작업시간 기준으로 판단)
|
||||||
let statusText = '미입력';
|
let statusText = '미입력';
|
||||||
let statusClass = 'incomplete';
|
let statusClass = 'incomplete';
|
||||||
@@ -603,13 +473,13 @@ async function renderModalDataFromSummary(workers, summary) {
|
|||||||
|
|
||||||
// 삭제 버튼 (관리자/그룹장만 표시, 작업이 있는 경우에만)
|
// 삭제 버튼 (관리자/그룹장만 표시, 작업이 있는 경우에만)
|
||||||
const deleteBtn = isAdmin && worker.totalWorkCount > 0 ? `
|
const deleteBtn = isAdmin && worker.totalWorkCount > 0 ? `
|
||||||
<button class="btn-delete-worker-work" onclick="event.stopPropagation(); deleteWorkerDayWork(${worker.workerId}, '${currentModalDate}', '${worker.workerName}')" title="이 작업자의 해당 날짜 작업 전체 삭제">
|
<button class="btn-delete-worker-work" onclick="event.stopPropagation(); deleteWorkerDayWork(${worker.workerId}, '${CalendarState.currentModalDate}', '${worker.workerName}')" title="이 작업자의 해당 날짜 작업 전체 삭제">
|
||||||
🗑️
|
🗑️
|
||||||
</button>
|
</button>
|
||||||
` : '';
|
` : '';
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="worker-card ${statusClass}" onclick="openWorkerModal(${worker.workerId}, '${currentModalDate}')">
|
<div class="worker-card ${statusClass}" onclick="openWorkerModal(${worker.workerId}, '${CalendarState.currentModalDate}')">
|
||||||
<div class="worker-avatar">
|
<div class="worker-avatar">
|
||||||
<div class="avatar-circle">
|
<div class="avatar-circle">
|
||||||
<span class="avatar-text">${initial}</span>
|
<span class="avatar-text">${initial}</span>
|
||||||
@@ -636,7 +506,7 @@ async function renderModalDataFromSummary(workers, summary) {
|
|||||||
</div>
|
</div>
|
||||||
<div class="worker-actions">
|
<div class="worker-actions">
|
||||||
${deleteBtn}
|
${deleteBtn}
|
||||||
<button class="btn-work-entry" onclick="event.stopPropagation(); openWorkerModal(${worker.workerId}, '${currentModalDate}')" title="작업입력">
|
<button class="btn-work-entry" onclick="event.stopPropagation(); openWorkerModal(${worker.workerId}, '${CalendarState.currentModalDate}')" title="작업입력">
|
||||||
작업입력
|
작업입력
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -789,7 +659,7 @@ function filterWorkersList() {
|
|||||||
function closeDailyWorkModal() {
|
function closeDailyWorkModal() {
|
||||||
elements.dailyWorkModal.style.display = 'none';
|
elements.dailyWorkModal.style.display = 'none';
|
||||||
document.body.style.overflow = '';
|
document.body.style.overflow = '';
|
||||||
currentModalDate = null;
|
CalendarState.currentModalDate = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 로딩 표시
|
// 로딩 표시
|
||||||
@@ -848,16 +718,16 @@ async function deleteWorkerDayWork(workerId, date, workerName) {
|
|||||||
showToast('작업을 삭제하는 중...', 'info');
|
showToast('작업을 삭제하는 중...', 'info');
|
||||||
|
|
||||||
// 날짜+작업자별 전체 삭제 API 호출
|
// 날짜+작업자별 전체 삭제 API 호출
|
||||||
const result = await window.apiCall(`/daily-work-reports/date/${date}/worker/${workerId}`, 'DELETE');
|
const result = await CalendarAPI.deleteWorkerDayWork(workerId, date);
|
||||||
|
|
||||||
console.log('✅ 작업 삭제 성공:', result);
|
console.log('✅ 작업 삭제 성공:', result);
|
||||||
showToast(`${workerName}의 ${date} 작업이 삭제되었습니다.`, 'success');
|
showToast(`${workerName}의 ${date} 작업이 삭제되었습니다.`, 'success');
|
||||||
|
|
||||||
// 모달 데이터 새로고침
|
// 모달 데이터 새로고침
|
||||||
await openDailyWorkModal(currentModalDate);
|
await openDailyWorkModal(CalendarState.currentModalDate);
|
||||||
|
|
||||||
// 캘린더도 새로고침
|
// 캘린더도 새로고침
|
||||||
await loadCalendarData();
|
await renderCalendar();
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('❌ 작업 삭제 실패:', error);
|
console.error('❌ 작업 삭제 실패:', error);
|
||||||
@@ -869,7 +739,7 @@ async function deleteWorkerDayWork(workerId, date, workerName) {
|
|||||||
async function openWorkerModal(workerId, date) {
|
async function openWorkerModal(workerId, date) {
|
||||||
try {
|
try {
|
||||||
// 작업자 정보 찾기
|
// 작업자 정보 찾기
|
||||||
const worker = allWorkers.find(w => w.worker_id === workerId);
|
const worker = CalendarState.allWorkers.find(w => w.worker_id === workerId);
|
||||||
if (!worker) {
|
if (!worker) {
|
||||||
showToast('작업자 정보를 찾을 수 없습니다.', 'error');
|
showToast('작업자 정보를 찾을 수 없습니다.', 'error');
|
||||||
return;
|
return;
|
||||||
@@ -1083,8 +953,8 @@ async function saveWorkEntry() {
|
|||||||
await renderCalendar();
|
await renderCalendar();
|
||||||
|
|
||||||
// 현재 열린 모달이 있다면 새로고침
|
// 현재 열린 모달이 있다면 새로고침
|
||||||
if (currentModalDate) {
|
if (CalendarState.currentModalDate) {
|
||||||
await openDailyWorkModal(currentModalDate);
|
await openDailyWorkModal(CalendarState.currentModalDate);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const action = editingWorkId ? '수정' : '저장';
|
const action = editingWorkId ? '수정' : '저장';
|
||||||
@@ -1106,7 +976,7 @@ function closeDailyWorkModal() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 전역 변수로 작업자 목록 저장
|
// 전역 변수로 작업자 목록 저장
|
||||||
let allWorkers = [];
|
// let allWorkers = []; // Now in CalendarState
|
||||||
|
|
||||||
// 시간 업데이트 함수
|
// 시간 업데이트 함수
|
||||||
function updateCurrentTime() {
|
function updateCurrentTime() {
|
||||||
@@ -1299,13 +1169,13 @@ async function loadExistingWorks(workerId, date) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
existingWorks = workerWorks;
|
CalendarState.existingWorks = workerWorks;
|
||||||
renderExistingWorks();
|
renderExistingWorks();
|
||||||
updateTabCounter();
|
updateTabCounter();
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('기존 작업 로드 오류:', error);
|
console.error('기존 작업 로드 오류:', error);
|
||||||
existingWorks = [];
|
CalendarState.existingWorks = [];
|
||||||
renderExistingWorks();
|
renderExistingWorks();
|
||||||
updateTabCounter();
|
updateTabCounter();
|
||||||
}
|
}
|
||||||
@@ -1313,7 +1183,7 @@ async function loadExistingWorks(workerId, date) {
|
|||||||
|
|
||||||
// 기존 작업 목록 렌더링
|
// 기존 작업 목록 렌더링
|
||||||
function renderExistingWorks() {
|
function renderExistingWorks() {
|
||||||
console.log('🎨 작업 목록 렌더링 시작:', existingWorks);
|
console.log('🎨 작업 목록 렌더링 시작:', CalendarState.existingWorks);
|
||||||
|
|
||||||
const existingWorkList = document.getElementById('existingWorkList');
|
const existingWorkList = document.getElementById('existingWorkList');
|
||||||
const noExistingWork = document.getElementById('noExistingWork');
|
const noExistingWork = document.getElementById('noExistingWork');
|
||||||
@@ -1326,15 +1196,15 @@ function renderExistingWorks() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 총 작업 시간 계산
|
// 총 작업 시간 계산
|
||||||
const totalHours = existingWorks.reduce((sum, work) => sum + parseFloat(work.work_hours || 0), 0);
|
const totalHours = CalendarState.existingWorks.reduce((sum, work) => sum + parseFloat(work.work_hours || 0), 0);
|
||||||
|
|
||||||
console.log(`📊 작업 통계: ${existingWorks.length}건, 총 ${totalHours}시간`);
|
console.log(`📊 작업 통계: ${CalendarState.existingWorks.length}건, 총 ${totalHours}시간`);
|
||||||
|
|
||||||
// 요약 정보 업데이트
|
// 요약 정보 업데이트
|
||||||
if (totalWorkCount) totalWorkCount.textContent = existingWorks.length;
|
if (totalWorkCount) totalWorkCount.textContent = CalendarState.existingWorks.length;
|
||||||
if (totalWorkHours) totalWorkHours.textContent = totalHours.toFixed(1);
|
if (totalWorkHours) totalWorkHours.textContent = totalHours.toFixed(1);
|
||||||
|
|
||||||
if (existingWorks.length === 0) {
|
if (CalendarState.existingWorks.length === 0) {
|
||||||
existingWorkList.style.display = 'none';
|
existingWorkList.style.display = 'none';
|
||||||
if (noExistingWork) noExistingWork.style.display = 'block';
|
if (noExistingWork) noExistingWork.style.display = 'block';
|
||||||
console.log('ℹ️ 작업이 없어서 빈 상태 표시');
|
console.log('ℹ️ 작업이 없어서 빈 상태 표시');
|
||||||
@@ -1345,7 +1215,7 @@ function renderExistingWorks() {
|
|||||||
if (noExistingWork) noExistingWork.style.display = 'none';
|
if (noExistingWork) noExistingWork.style.display = 'none';
|
||||||
|
|
||||||
// 각 작업 데이터 상세 로그
|
// 각 작업 데이터 상세 로그
|
||||||
existingWorks.forEach((work, index) => {
|
CalendarState.existingWorks.forEach((work, index) => {
|
||||||
console.log(`📋 작업 ${index + 1}:`, {
|
console.log(`📋 작업 ${index + 1}:`, {
|
||||||
id: work.id,
|
id: work.id,
|
||||||
project_name: work.project_name,
|
project_name: work.project_name,
|
||||||
@@ -1357,7 +1227,7 @@ function renderExistingWorks() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 작업 목록 HTML 생성
|
// 작업 목록 HTML 생성
|
||||||
const worksHtml = existingWorks.map((work, index) => {
|
const worksHtml = CalendarState.existingWorks.map((work, index) => {
|
||||||
const workItemHtml = `
|
const workItemHtml = `
|
||||||
<div class="work-item" data-work-id="${work.id}">
|
<div class="work-item" data-work-id="${work.id}">
|
||||||
<div class="work-item-header">
|
<div class="work-item-header">
|
||||||
@@ -1394,8 +1264,8 @@ function renderExistingWorks() {
|
|||||||
const renderedItems = existingWorkList.querySelectorAll('.work-item');
|
const renderedItems = existingWorkList.querySelectorAll('.work-item');
|
||||||
console.log(`✅ 렌더링 완료: ${renderedItems.length}개 작업 아이템이 DOM에 추가됨`);
|
console.log(`✅ 렌더링 완료: ${renderedItems.length}개 작업 아이템이 DOM에 추가됨`);
|
||||||
|
|
||||||
if (renderedItems.length !== existingWorks.length) {
|
if (renderedItems.length !== CalendarState.existingWorks.length) {
|
||||||
console.error(`⚠️ 렌더링 불일치: 데이터 ${existingWorks.length}건 vs DOM ${renderedItems.length}개`);
|
console.error(`⚠️ 렌더링 불일치: 데이터 ${CalendarState.existingWorks.length}건 vs DOM ${renderedItems.length}개`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1403,20 +1273,20 @@ function renderExistingWorks() {
|
|||||||
function updateTabCounter() {
|
function updateTabCounter() {
|
||||||
const existingTabBtn = document.querySelector('[data-tab="existing"]');
|
const existingTabBtn = document.querySelector('[data-tab="existing"]');
|
||||||
if (existingTabBtn) {
|
if (existingTabBtn) {
|
||||||
existingTabBtn.innerHTML = `📋 기존 작업 (${existingWorks.length}건)`;
|
existingTabBtn.innerHTML = `📋 기존 작업 (${CalendarState.existingWorks.length}건)`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 작업 수정
|
// 작업 수정
|
||||||
function editWork(workId) {
|
function editWork(workId) {
|
||||||
const work = existingWorks.find(w => w.id === workId);
|
const work = CalendarState.existingWorks.find(w => w.id === workId);
|
||||||
if (!work) {
|
if (!work) {
|
||||||
showToast('작업 정보를 찾을 수 없습니다.', 'error');
|
showToast('작업 정보를 찾을 수 없습니다.', 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 수정 모드로 전환
|
// 수정 모드로 전환
|
||||||
currentEditingWork = work;
|
CalendarState.currentEditingWork = work;
|
||||||
|
|
||||||
// 새 작업 탭으로 전환
|
// 새 작업 탭으로 전환
|
||||||
switchTab('new');
|
switchTab('new');
|
||||||
@@ -1439,7 +1309,7 @@ function editWork(workId) {
|
|||||||
|
|
||||||
// 작업 삭제 확인
|
// 작업 삭제 확인
|
||||||
function confirmDeleteWork(workId) {
|
function confirmDeleteWork(workId) {
|
||||||
const work = existingWorks.find(w => w.id === workId);
|
const work = CalendarState.existingWorks.find(w => w.id === workId);
|
||||||
if (!work) {
|
if (!work) {
|
||||||
showToast('작업 정보를 찾을 수 없습니다.', 'error');
|
showToast('작업 정보를 찾을 수 없습니다.', 'error');
|
||||||
return;
|
return;
|
||||||
@@ -1464,8 +1334,8 @@ async function deleteWorkById(workId) {
|
|||||||
await loadExistingWorks(workerId, date);
|
await loadExistingWorks(workerId, date);
|
||||||
|
|
||||||
// 현재 열린 모달이 있다면 새로고침
|
// 현재 열린 모달이 있다면 새로고침
|
||||||
if (currentModalDate) {
|
if (CalendarState.currentModalDate) {
|
||||||
await openDailyWorkModal(currentModalDate);
|
await openDailyWorkModal(CalendarState.currentModalDate);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showToast(response.message || '작업 삭제에 실패했습니다.', 'error');
|
showToast(response.message || '작업 삭제에 실패했습니다.', 'error');
|
||||||
@@ -1478,7 +1348,7 @@ async function deleteWorkById(workId) {
|
|||||||
|
|
||||||
// 작업 폼 초기화
|
// 작업 폼 초기화
|
||||||
function resetWorkForm() {
|
function resetWorkForm() {
|
||||||
currentEditingWork = null;
|
CalendarState.currentEditingWork = null;
|
||||||
|
|
||||||
// 폼 필드 초기화
|
// 폼 필드 초기화
|
||||||
document.getElementById('editingWorkId').value = '';
|
document.getElementById('editingWorkId').value = '';
|
||||||
@@ -1496,8 +1366,8 @@ function resetWorkForm() {
|
|||||||
|
|
||||||
// 작업 삭제 (수정 모드에서)
|
// 작업 삭제 (수정 모드에서)
|
||||||
function deleteWork() {
|
function deleteWork() {
|
||||||
if (currentEditingWork) {
|
if (CalendarState.currentEditingWork) {
|
||||||
confirmDeleteWork(currentEditingWork.id);
|
confirmDeleteWork(CalendarState.currentEditingWork.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -337,6 +337,8 @@
|
|||||||
<script src="/js/api-config.js?v=13"></script>
|
<script src="/js/api-config.js?v=13"></script>
|
||||||
<script src="/js/auth-check.js?v=13"></script>
|
<script src="/js/auth-check.js?v=13"></script>
|
||||||
<script src="/js/load-navbar.js?v=4"></script>
|
<script src="/js/load-navbar.js?v=4"></script>
|
||||||
|
<script src="/js/modules/calendar/CalendarState.js?v=1"></script>
|
||||||
|
<script src="/js/modules/calendar/CalendarAPI.js?v=1"></script>
|
||||||
<script src="/js/work-report-calendar.js?v=41"></script>
|
<script src="/js/work-report-calendar.js?v=41"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Reference in New Issue
Block a user