refactor: 프론트엔드 유틸리티 함수 통합 (showToast, waitForApi, generateUUID)
- api-base.js에 4개 전역 유틸리티 추가 (showToast, formatDate, waitForApi, generateUUID) - 24개 파일에서 중복 정의 제거 (-932줄) - showToast: 18곳 중복 → 1곳 통합 (자동 컨테이너/스타일 생성) - waitForApi/waitForApiConfig/waitForApiCall: 5곳 → 1곳 통합 - generateUUID: tbm.js 중복 제거 - tbm/utils.js, workplace-management/utils.js: window 재정의 제거 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -537,35 +537,7 @@ function handleLogout() {
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 토스트 알림 ========== //
|
||||
function showToast(message, type = 'info', duration = 3000) {
|
||||
if (!elements.toastContainer) return;
|
||||
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast ${type}`;
|
||||
|
||||
const iconMap = {
|
||||
success: '✅',
|
||||
error: '❌',
|
||||
warning: '⚠️',
|
||||
info: 'ℹ️'
|
||||
};
|
||||
|
||||
toast.innerHTML = `
|
||||
<div class="toast-icon">${iconMap[type] || 'ℹ️'}</div>
|
||||
<div class="toast-message">${message}</div>
|
||||
<button class="toast-close" onclick="this.parentElement.remove()">×</button>
|
||||
`;
|
||||
|
||||
elements.toastContainer.appendChild(toast);
|
||||
|
||||
// 자동 제거
|
||||
setTimeout(() => {
|
||||
if (toast.parentElement) {
|
||||
toast.remove();
|
||||
}
|
||||
}, duration);
|
||||
}
|
||||
// showToast → api-base.js 전역 사용
|
||||
|
||||
// ========== 전역 함수 (HTML에서 호출) ========== //
|
||||
window.editUser = editUser;
|
||||
|
||||
@@ -148,5 +148,88 @@
|
||||
return response.json();
|
||||
};
|
||||
|
||||
// ==================== 공통 유틸리티 ====================
|
||||
|
||||
/**
|
||||
* Toast 알림 표시
|
||||
*/
|
||||
window.showToast = function(message, type, duration) {
|
||||
type = type || 'info';
|
||||
duration = duration || 3000;
|
||||
|
||||
var container = document.getElementById('toastContainer');
|
||||
if (!container) {
|
||||
container = document.createElement('div');
|
||||
container.id = 'toastContainer';
|
||||
container.style.cssText = 'position:fixed;top:20px;right:20px;z-index:9999;display:flex;flex-direction:column;gap:10px;';
|
||||
document.body.appendChild(container);
|
||||
}
|
||||
|
||||
if (!document.getElementById('toastStyles')) {
|
||||
var style = document.createElement('style');
|
||||
style.id = 'toastStyles';
|
||||
style.textContent =
|
||||
'.toast{display:flex;align-items:center;gap:12px;padding:12px 20px;background:#fff;border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,.15);opacity:0;transform:translateX(100px);transition:all .3s ease;min-width:250px;max-width:400px}' +
|
||||
'.toast.show{opacity:1;transform:translateX(0)}' +
|
||||
'.toast-success{border-left:4px solid #10b981}.toast-error{border-left:4px solid #ef4444}' +
|
||||
'.toast-warning{border-left:4px solid #f59e0b}.toast-info{border-left:4px solid #3b82f6}' +
|
||||
'.toast-icon{font-size:20px}.toast-message{font-size:14px;color:#374151}';
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
|
||||
var iconMap = { success: '\u2705', error: '\u274C', warning: '\u26A0\uFE0F', info: '\u2139\uFE0F' };
|
||||
var toast = document.createElement('div');
|
||||
toast.className = 'toast toast-' + type;
|
||||
toast.innerHTML = '<span class="toast-icon">' + (iconMap[type] || '\u2139\uFE0F') + '</span><span class="toast-message">' + message + '</span>';
|
||||
container.appendChild(toast);
|
||||
|
||||
setTimeout(function() { toast.classList.add('show'); }, 10);
|
||||
setTimeout(function() {
|
||||
toast.classList.remove('show');
|
||||
setTimeout(function() { toast.remove(); }, 300);
|
||||
}, duration);
|
||||
};
|
||||
|
||||
/**
|
||||
* 날짜를 YYYY-MM-DD 형식으로 변환
|
||||
*/
|
||||
window.formatDate = function(dateString) {
|
||||
if (!dateString) return '';
|
||||
if (/^\d{4}-\d{2}-\d{2}$/.test(dateString)) return dateString;
|
||||
var d = new Date(dateString);
|
||||
if (isNaN(d.getTime())) return '';
|
||||
var y = d.getFullYear();
|
||||
var m = String(d.getMonth() + 1).padStart(2, '0');
|
||||
var day = String(d.getDate()).padStart(2, '0');
|
||||
return y + '-' + m + '-' + day;
|
||||
};
|
||||
|
||||
/**
|
||||
* apiCall이 로드될 때까지 대기
|
||||
*/
|
||||
window.waitForApi = function(timeout) {
|
||||
timeout = timeout || 5000;
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (window.apiCall) return resolve();
|
||||
var elapsed = 0;
|
||||
var iv = setInterval(function() {
|
||||
elapsed += 50;
|
||||
if (window.apiCall) { clearInterval(iv); resolve(); }
|
||||
else if (elapsed >= timeout) { clearInterval(iv); reject(new Error('apiCall timeout')); }
|
||||
}, 50);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* UUID v4 생성
|
||||
*/
|
||||
window.generateUUID = function() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
var r = Math.random() * 16 | 0;
|
||||
var v = c === 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
};
|
||||
|
||||
console.log('API 설정 완료:', window.API_BASE_URL);
|
||||
})();
|
||||
|
||||
@@ -425,40 +425,7 @@ window.updateProgressSteps = function(currentStepNumber) {
|
||||
}
|
||||
};
|
||||
|
||||
// 토스트 메시지 (간단 버전)
|
||||
window.showToast = function(message, type = 'info', duration = 3000) {
|
||||
console.log(`[Toast] ${type}: ${message}`);
|
||||
|
||||
// 기존 토스트 제거
|
||||
const existingToast = document.querySelector('.toast-message');
|
||||
if (existingToast) {
|
||||
existingToast.remove();
|
||||
}
|
||||
|
||||
// 새 토스트 생성
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast-message toast-${type}`;
|
||||
toast.textContent = message;
|
||||
toast.style.cssText = `
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
padding: 12px 20px;
|
||||
border-radius: 8px;
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
z-index: 10000;
|
||||
animation: slideIn 0.3s ease;
|
||||
background-color: ${type === 'success' ? '#10b981' : type === 'error' ? '#ef4444' : type === 'warning' ? '#f59e0b' : '#3b82f6'};
|
||||
`;
|
||||
|
||||
document.body.appendChild(toast);
|
||||
|
||||
setTimeout(() => {
|
||||
toast.style.animation = 'slideOut 0.3s ease';
|
||||
setTimeout(() => toast.remove(), 300);
|
||||
}, duration);
|
||||
};
|
||||
// showToast → api-base.js 전역 사용
|
||||
|
||||
// 확인 다이얼로그
|
||||
window.showConfirmDialog = function(message, onConfirm, onCancel) {
|
||||
|
||||
@@ -7,21 +7,11 @@ let selectedWorkers = new Set();
|
||||
|
||||
// 페이지 초기화
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
await waitForApiConfig();
|
||||
await waitForApi();
|
||||
await loadDepartments();
|
||||
});
|
||||
|
||||
// API 설정 로드 대기
|
||||
async function waitForApiConfig() {
|
||||
let retryCount = 0;
|
||||
while (!window.apiCall && retryCount < 50) {
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
retryCount++;
|
||||
}
|
||||
if (!window.apiCall) {
|
||||
console.error('API 설정 로드 실패');
|
||||
}
|
||||
}
|
||||
// waitForApi → api-base.js 전역 사용
|
||||
|
||||
// 부서 목록 로드
|
||||
async function loadDepartments() {
|
||||
|
||||
@@ -33,24 +33,14 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
|
||||
// API 설정 후 데이터 로드
|
||||
waitForApiConfig().then(() => {
|
||||
waitForApi().then(() => {
|
||||
loadEquipmentData();
|
||||
loadFactories();
|
||||
loadRepairCategories();
|
||||
});
|
||||
});
|
||||
|
||||
// API 설정 대기
|
||||
function waitForApiConfig() {
|
||||
return new Promise(resolve => {
|
||||
const check = setInterval(() => {
|
||||
if (window.API_BASE_URL) {
|
||||
clearInterval(check);
|
||||
resolve();
|
||||
}
|
||||
}, 50);
|
||||
});
|
||||
}
|
||||
// waitForApi → api-base.js 전역 사용
|
||||
|
||||
// 뒤로가기
|
||||
function goBack() {
|
||||
|
||||
@@ -138,14 +138,7 @@ function renderWorkStatus(workers) {
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
// 🍞 토스트 메시지 (기존 modern-dashboard.js에 있다면 중복 주의, 없으면 사용)
|
||||
function showToast(message, type = 'info') {
|
||||
if (window.showToast) {
|
||||
window.showToast(message, type);
|
||||
} else {
|
||||
alert(message);
|
||||
}
|
||||
}
|
||||
// showToast → api-base.js 전역 사용
|
||||
|
||||
// 초기화
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
@@ -300,22 +300,7 @@ async function loadWorkerOptions() {
|
||||
}
|
||||
}
|
||||
|
||||
function showToast(message) {
|
||||
const toast = document.createElement('div');
|
||||
toast.textContent = message;
|
||||
toast.style.position = 'fixed';
|
||||
toast.style.bottom = '30px';
|
||||
toast.style.left = '50%';
|
||||
toast.style.transform = 'translateX(-50%)';
|
||||
toast.style.background = '#323232';
|
||||
toast.style.color = '#fff';
|
||||
toast.style.padding = '10px 20px';
|
||||
toast.style.borderRadius = '6px';
|
||||
toast.style.fontSize = '14px';
|
||||
toast.style.zIndex = 9999;
|
||||
document.body.appendChild(toast);
|
||||
setTimeout(() => toast.remove(), 2000);
|
||||
}
|
||||
// showToast → api-base.js 전역 사용
|
||||
|
||||
// ========== 페이지 접근 권한 관리 ==========
|
||||
|
||||
|
||||
@@ -18,21 +18,7 @@
|
||||
var workplacesByCategory = {};
|
||||
|
||||
// ==================== 유틸리티 ====================
|
||||
|
||||
// escapeHtml은 api-base.js에서 window.escapeHtml로 전역 제공
|
||||
|
||||
function waitForApi(timeout) {
|
||||
timeout = timeout || 5000;
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (window.apiCall) return resolve();
|
||||
var elapsed = 0;
|
||||
var interval = setInterval(function() {
|
||||
elapsed += 50;
|
||||
if (window.apiCall) { clearInterval(interval); resolve(); }
|
||||
else if (elapsed >= timeout) { clearInterval(interval); reject(new Error('apiCall timeout')); }
|
||||
}, 50);
|
||||
});
|
||||
}
|
||||
// escapeHtml, waitForApi → api-base.js 전역 사용
|
||||
|
||||
// ==================== 데이터 그룹핑 ====================
|
||||
|
||||
|
||||
@@ -806,35 +806,7 @@ function showErrorState() {
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 토스트 알림 ========== //
|
||||
function showToast(message, type = 'info', duration = 3000) {
|
||||
if (!elements.toastContainer) return;
|
||||
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast ${type}`;
|
||||
|
||||
const iconMap = {
|
||||
success: '✅',
|
||||
error: '❌',
|
||||
warning: '⚠️',
|
||||
info: 'ℹ️'
|
||||
};
|
||||
|
||||
toast.innerHTML = `
|
||||
<div class="toast-icon">${iconMap[type] || 'ℹ️'}</div>
|
||||
<div class="toast-message">${message}</div>
|
||||
<button class="toast-close" onclick="this.parentElement.remove()">×</button>
|
||||
`;
|
||||
|
||||
elements.toastContainer.appendChild(toast);
|
||||
|
||||
// 자동 제거
|
||||
setTimeout(() => {
|
||||
if (toast.parentElement) {
|
||||
toast.remove();
|
||||
}
|
||||
}, duration);
|
||||
}
|
||||
// showToast → api-base.js 전역 사용
|
||||
|
||||
// ========== 작업자 관련 액션 함수들 ========== //
|
||||
function openWorkerModal(workerId, workerName) {
|
||||
@@ -1388,7 +1360,6 @@ async function handleModalVacation(vacationType) {
|
||||
|
||||
// ========== 전역 함수 (HTML에서 호출) ========== //
|
||||
window.loadDashboardData = loadDashboardData;
|
||||
window.showToast = showToast;
|
||||
window.updateSummaryCards = updateSummaryCards;
|
||||
window.displayWorkers = displayWorkers;
|
||||
window.openWorkerModal = openWorkerModal;
|
||||
|
||||
@@ -557,59 +557,7 @@ async function deleteProjectById(projectId) {
|
||||
}
|
||||
}
|
||||
|
||||
// 토스트 메시지 표시
|
||||
function showToast(message, type = 'info') {
|
||||
// 기존 토스트 제거
|
||||
const existingToast = document.querySelector('.toast');
|
||||
if (existingToast) {
|
||||
existingToast.remove();
|
||||
}
|
||||
|
||||
// 새 토스트 생성
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast toast-${type}`;
|
||||
toast.textContent = message;
|
||||
|
||||
// 스타일 적용
|
||||
Object.assign(toast.style, {
|
||||
position: 'fixed',
|
||||
top: '20px',
|
||||
right: '20px',
|
||||
padding: '12px 24px',
|
||||
borderRadius: '8px',
|
||||
color: 'white',
|
||||
fontWeight: '500',
|
||||
zIndex: '1000',
|
||||
transform: 'translateX(100%)',
|
||||
transition: 'transform 0.3s ease'
|
||||
});
|
||||
|
||||
// 타입별 배경색
|
||||
const colors = {
|
||||
success: '#10b981',
|
||||
error: '#ef4444',
|
||||
warning: '#f59e0b',
|
||||
info: '#3b82f6'
|
||||
};
|
||||
toast.style.backgroundColor = colors[type] || colors.info;
|
||||
|
||||
document.body.appendChild(toast);
|
||||
|
||||
// 애니메이션
|
||||
setTimeout(() => {
|
||||
toast.style.transform = 'translateX(0)';
|
||||
}, 100);
|
||||
|
||||
// 자동 제거
|
||||
setTimeout(() => {
|
||||
toast.style.transform = 'translateX(100%)';
|
||||
setTimeout(() => {
|
||||
if (toast.parentNode) {
|
||||
toast.remove();
|
||||
}
|
||||
}, 300);
|
||||
}, 3000);
|
||||
}
|
||||
// showToast → api-base.js 전역 사용
|
||||
|
||||
// 전역 함수로 노출
|
||||
window.openProjectModal = openProjectModal;
|
||||
|
||||
@@ -831,42 +831,7 @@ async function addInlineCheck(tabType) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 토스트 메시지 표시
|
||||
*/
|
||||
function showToast(message, type = 'info') {
|
||||
// 기존 토스트 제거
|
||||
const existingToast = document.querySelector('.toast-message');
|
||||
if (existingToast) {
|
||||
existingToast.remove();
|
||||
}
|
||||
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast-message toast-${type}`;
|
||||
toast.textContent = message;
|
||||
toast.style.cssText = `
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
padding: 12px 24px;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
z-index: 9999;
|
||||
animation: fadeInUp 0.3s ease;
|
||||
${type === 'success' ? 'background: #10b981; color: white;' : ''}
|
||||
${type === 'error' ? 'background: #ef4444; color: white;' : ''}
|
||||
${type === 'info' ? 'background: #3b82f6; color: white;' : ''}
|
||||
`;
|
||||
|
||||
document.body.appendChild(toast);
|
||||
|
||||
setTimeout(() => {
|
||||
toast.style.animation = 'fadeOut 0.3s ease';
|
||||
setTimeout(() => toast.remove(), 300);
|
||||
}, 3000);
|
||||
}
|
||||
// showToast → api-base.js 전역 사용
|
||||
|
||||
// 모달 외부 클릭 시 닫기
|
||||
document.getElementById('checkModal')?.addEventListener('click', function(e) {
|
||||
|
||||
@@ -4,85 +4,7 @@ let currentStatus = 'pending';
|
||||
let requests = [];
|
||||
let currentRejectRequestId = null;
|
||||
|
||||
// ==================== Toast 알림 ====================
|
||||
|
||||
function showToast(message, type = 'info', duration = 3000) {
|
||||
const toastContainer = document.getElementById('toastContainer') || createToastContainer();
|
||||
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast toast-${type}`;
|
||||
|
||||
const iconMap = {
|
||||
success: '✅',
|
||||
error: '❌',
|
||||
warning: '⚠️',
|
||||
info: 'ℹ️'
|
||||
};
|
||||
|
||||
toast.innerHTML = `
|
||||
<span class="toast-icon">${iconMap[type] || 'ℹ️'}</span>
|
||||
<span class="toast-message">${message}</span>
|
||||
`;
|
||||
|
||||
toastContainer.appendChild(toast);
|
||||
|
||||
setTimeout(() => toast.classList.add('show'), 10);
|
||||
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('show');
|
||||
setTimeout(() => toast.remove(), 300);
|
||||
}, duration);
|
||||
}
|
||||
|
||||
function createToastContainer() {
|
||||
const container = document.createElement('div');
|
||||
container.id = 'toastContainer';
|
||||
container.style.cssText = `
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
`;
|
||||
|
||||
document.body.appendChild(container);
|
||||
|
||||
if (!document.getElementById('toastStyles')) {
|
||||
const style = document.createElement('style');
|
||||
style.id = 'toastStyles';
|
||||
style.textContent = `
|
||||
.toast {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 12px 20px;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
opacity: 0;
|
||||
transform: translateX(100px);
|
||||
transition: all 0.3s ease;
|
||||
min-width: 250px;
|
||||
max-width: 400px;
|
||||
}
|
||||
.toast.show {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
.toast-success { border-left: 4px solid #10b981; }
|
||||
.toast-error { border-left: 4px solid #ef4444; }
|
||||
.toast-warning { border-left: 4px solid #f59e0b; }
|
||||
.toast-info { border-left: 4px solid #3b82f6; }
|
||||
.toast-icon { font-size: 20px; }
|
||||
.toast-message { font-size: 14px; color: #374151; }
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
// showToast → api-base.js 전역 사용
|
||||
|
||||
// ==================== 초기화 ====================
|
||||
|
||||
@@ -436,7 +358,6 @@ function startTraining(requestId) {
|
||||
}
|
||||
|
||||
// 전역 함수로 노출
|
||||
window.showToast = showToast;
|
||||
window.switchTab = switchTab;
|
||||
window.viewDetail = viewDetail;
|
||||
window.closeDetailModal = closeDetailModal;
|
||||
|
||||
@@ -8,85 +8,7 @@ let isDrawing = false;
|
||||
let hasSignature = false;
|
||||
let savedSignatures = []; // 저장된 서명 목록
|
||||
|
||||
// ==================== Toast 알림 ====================
|
||||
|
||||
function showToast(message, type = 'info', duration = 3000) {
|
||||
const toastContainer = document.getElementById('toastContainer') || createToastContainer();
|
||||
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast toast-${type}`;
|
||||
|
||||
const iconMap = {
|
||||
success: '✅',
|
||||
error: '❌',
|
||||
warning: '⚠️',
|
||||
info: 'ℹ️'
|
||||
};
|
||||
|
||||
toast.innerHTML = `
|
||||
<span class="toast-icon">${iconMap[type] || 'ℹ️'}</span>
|
||||
<span class="toast-message">${message}</span>
|
||||
`;
|
||||
|
||||
toastContainer.appendChild(toast);
|
||||
|
||||
setTimeout(() => toast.classList.add('show'), 10);
|
||||
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('show');
|
||||
setTimeout(() => toast.remove(), 300);
|
||||
}, duration);
|
||||
}
|
||||
|
||||
function createToastContainer() {
|
||||
const container = document.createElement('div');
|
||||
container.id = 'toastContainer';
|
||||
container.style.cssText = `
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
`;
|
||||
|
||||
document.body.appendChild(container);
|
||||
|
||||
if (!document.getElementById('toastStyles')) {
|
||||
const style = document.createElement('style');
|
||||
style.id = 'toastStyles';
|
||||
style.textContent = `
|
||||
.toast {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 12px 20px;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
opacity: 0;
|
||||
transform: translateX(100px);
|
||||
transition: all 0.3s ease;
|
||||
min-width: 250px;
|
||||
max-width: 400px;
|
||||
}
|
||||
.toast.show {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
.toast-success { border-left: 4px solid #10b981; }
|
||||
.toast-error { border-left: 4px solid #ef4444; }
|
||||
.toast-warning { border-left: 4px solid #f59e0b; }
|
||||
.toast-info { border-left: 4px solid #3b82f6; }
|
||||
.toast-icon { font-size: 20px; }
|
||||
.toast-message { font-size: 14px; color: #374151; }
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
// showToast → api-base.js 전역 사용
|
||||
|
||||
// ==================== 초기화 ====================
|
||||
|
||||
@@ -544,7 +466,6 @@ function goBack() {
|
||||
}
|
||||
|
||||
// 전역 함수로 노출
|
||||
window.showToast = showToast;
|
||||
window.clearSignature = clearSignature;
|
||||
window.saveSignature = saveSignature;
|
||||
window.deleteSignature = deleteSignature;
|
||||
|
||||
@@ -358,31 +358,7 @@ function formatDate(dateString) {
|
||||
});
|
||||
}
|
||||
|
||||
// 토스트 알림
|
||||
function showToast(message, type = 'info') {
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast toast-${type}`;
|
||||
toast.textContent = message;
|
||||
toast.style.cssText = `
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
padding: 1rem 1.5rem;
|
||||
background: ${type === 'success' ? '#10b981' : type === 'error' ? '#ef4444' : '#3b82f6'};
|
||||
color: white;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
z-index: 10000;
|
||||
animation: slideIn 0.3s ease-out;
|
||||
`;
|
||||
|
||||
document.body.appendChild(toast);
|
||||
|
||||
setTimeout(() => {
|
||||
toast.style.animation = 'slideOut 0.3s ease-out';
|
||||
setTimeout(() => toast.remove(), 300);
|
||||
}, 3000);
|
||||
}
|
||||
// showToast → api-base.js 전역 사용
|
||||
|
||||
// ==================== 공정 관리 ====================
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
document.addEventListener('DOMContentLoaded', async function() {
|
||||
try {
|
||||
// apiCall이 준비될 때까지 대기
|
||||
await waitForApiCall();
|
||||
await waitForApi();
|
||||
|
||||
// 초기 데이터 로드
|
||||
await window.TbmAPI.loadInitialData();
|
||||
@@ -68,22 +68,7 @@
|
||||
}
|
||||
});
|
||||
|
||||
function waitForApiCall() {
|
||||
return new Promise(function(resolve) {
|
||||
if (typeof window.apiCall === 'function') {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
var checks = 0;
|
||||
var interval = setInterval(function() {
|
||||
checks++;
|
||||
if (typeof window.apiCall === 'function' || checks > 50) {
|
||||
clearInterval(interval);
|
||||
resolve();
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
// waitForApi → api-base.js 전역 사용
|
||||
|
||||
// ==================== 네비게이션 ====================
|
||||
|
||||
|
||||
@@ -1005,13 +1005,7 @@ window.saveTbmSession = saveTbmSession;
|
||||
|
||||
// ==================== 작업자 관리 ====================
|
||||
|
||||
// UUID 생성 함수
|
||||
function generateUUID() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
const r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
// generateUUID → api-base.js 전역 사용
|
||||
|
||||
// 작업자 카드 리스트 렌더링
|
||||
function renderWorkerTaskList() {
|
||||
@@ -3081,46 +3075,4 @@ async function saveHandover() {
|
||||
}
|
||||
window.saveHandover = saveHandover;
|
||||
|
||||
// 토스트 알림
|
||||
function showToast(message, type = 'info', duration = 3000) {
|
||||
const container = document.getElementById('toastContainer');
|
||||
if (!container) return;
|
||||
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast ${type}`;
|
||||
|
||||
const iconMap = {
|
||||
success: '✅',
|
||||
error: '❌',
|
||||
warning: '⚠️',
|
||||
info: 'ℹ️'
|
||||
};
|
||||
|
||||
toast.innerHTML = `
|
||||
<div class="toast-icon">${iconMap[type] || 'ℹ️'}</div>
|
||||
<div class="toast-message">${message}</div>
|
||||
<button class="toast-close" onclick="this.parentElement.remove()">×</button>
|
||||
`;
|
||||
|
||||
toast.style.cssText = `
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem 1.25rem;
|
||||
background: white;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1);
|
||||
margin-bottom: 0.75rem;
|
||||
min-width: 300px;
|
||||
animation: slideIn 0.3s ease-out;
|
||||
`;
|
||||
|
||||
container.appendChild(toast);
|
||||
|
||||
setTimeout(() => {
|
||||
if (toast.parentElement) {
|
||||
toast.style.animation = 'slideOut 0.3s ease-out';
|
||||
setTimeout(() => toast.remove(), 300);
|
||||
}
|
||||
}, duration);
|
||||
}
|
||||
// showToast → api-base.js 전역 사용
|
||||
|
||||
@@ -173,56 +173,8 @@ class TbmUtils {
|
||||
// 전역 인스턴스 생성
|
||||
window.TbmUtils = new TbmUtils();
|
||||
|
||||
// 하위 호환성: 기존 함수들
|
||||
// 하위 호환성: TBM 전용 유틸 (showToast, formatDate, waitForApi, generateUUID는 api-base.js 전역)
|
||||
window.getTodayKST = () => window.TbmUtils.getTodayKST();
|
||||
window.formatDate = (dateString) => window.TbmUtils.formatDate(dateString);
|
||||
|
||||
// 토스트 알림
|
||||
window.showToast = function(message, type = 'info', duration = 3000) {
|
||||
const container = document.getElementById('toastContainer');
|
||||
if (!container) {
|
||||
console.log(`[Toast] ${type}: ${message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast ${type}`;
|
||||
|
||||
const iconMap = {
|
||||
success: '✅',
|
||||
error: '❌',
|
||||
warning: '⚠️',
|
||||
info: 'ℹ️'
|
||||
};
|
||||
|
||||
toast.innerHTML = `
|
||||
<div class="toast-icon">${iconMap[type] || 'ℹ️'}</div>
|
||||
<div class="toast-message">${message}</div>
|
||||
<button class="toast-close" onclick="this.parentElement.remove()">×</button>
|
||||
`;
|
||||
|
||||
toast.style.cssText = `
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 1rem 1.25rem;
|
||||
background: white;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1);
|
||||
margin-bottom: 0.75rem;
|
||||
min-width: 300px;
|
||||
animation: slideIn 0.3s ease-out;
|
||||
`;
|
||||
|
||||
container.appendChild(toast);
|
||||
|
||||
setTimeout(() => {
|
||||
if (toast.parentElement) {
|
||||
toast.style.animation = 'slideOut 0.3s ease-out';
|
||||
setTimeout(() => toast.remove(), 300);
|
||||
}
|
||||
}, duration);
|
||||
};
|
||||
|
||||
// 카테고리별 그룹화
|
||||
window.groupChecksByCategory = function(checks) {
|
||||
|
||||
@@ -840,25 +840,4 @@ function closeModals() {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 토스트 메시지
|
||||
*/
|
||||
function showToast(message, type = 'info') {
|
||||
const container = document.getElementById('toastContainer');
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast toast-${type}`;
|
||||
toast.textContent = message;
|
||||
|
||||
container.appendChild(toast);
|
||||
|
||||
setTimeout(() => {
|
||||
toast.classList.add('show');
|
||||
}, 10);
|
||||
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('show');
|
||||
setTimeout(() => {
|
||||
container.removeChild(toast);
|
||||
}, 300);
|
||||
}, 3000);
|
||||
}
|
||||
// showToast → api-base.js 전역 사용
|
||||
|
||||
@@ -10,94 +10,7 @@ let canvas = null;
|
||||
let ctx = null;
|
||||
let layoutImage = null;
|
||||
|
||||
// ==================== Toast 알림 ====================
|
||||
|
||||
/**
|
||||
* Toast 메시지 표시
|
||||
*/
|
||||
function showToast(message, type = 'info', duration = 3000) {
|
||||
const toastContainer = document.getElementById('toastContainer') || createToastContainer();
|
||||
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast toast-${type}`;
|
||||
|
||||
const iconMap = {
|
||||
success: '✅',
|
||||
error: '❌',
|
||||
warning: '⚠️',
|
||||
info: 'ℹ️'
|
||||
};
|
||||
|
||||
toast.innerHTML = `
|
||||
<span class="toast-icon">${iconMap[type] || 'ℹ️'}</span>
|
||||
<span class="toast-message">${message}</span>
|
||||
`;
|
||||
|
||||
toastContainer.appendChild(toast);
|
||||
|
||||
// 애니메이션
|
||||
setTimeout(() => toast.classList.add('show'), 10);
|
||||
|
||||
// 자동 제거
|
||||
setTimeout(() => {
|
||||
toast.classList.remove('show');
|
||||
setTimeout(() => toast.remove(), 300);
|
||||
}, duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toast 컨테이너 생성
|
||||
*/
|
||||
function createToastContainer() {
|
||||
const container = document.createElement('div');
|
||||
container.id = 'toastContainer';
|
||||
container.style.cssText = `
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
`;
|
||||
|
||||
document.body.appendChild(container);
|
||||
|
||||
// Toast 스타일 추가
|
||||
if (!document.getElementById('toastStyles')) {
|
||||
const style = document.createElement('style');
|
||||
style.id = 'toastStyles';
|
||||
style.textContent = `
|
||||
.toast {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 12px 20px;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
opacity: 0;
|
||||
transform: translateX(100px);
|
||||
transition: all 0.3s ease;
|
||||
min-width: 250px;
|
||||
max-width: 400px;
|
||||
}
|
||||
.toast.show {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
.toast-success { border-left: 4px solid #10b981; }
|
||||
.toast-error { border-left: 4px solid #ef4444; }
|
||||
.toast-warning { border-left: 4px solid #f59e0b; }
|
||||
.toast-info { border-left: 4px solid #3b82f6; }
|
||||
.toast-icon { font-size: 20px; }
|
||||
.toast-message { font-size: 14px; color: #374151; }
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
// showToast, createToastContainer → api-base.js 전역 사용
|
||||
|
||||
// ==================== 초기화 ====================
|
||||
|
||||
@@ -523,7 +436,6 @@ function resetForm() {
|
||||
}
|
||||
|
||||
// 전역 함수로 노출
|
||||
window.showToast = showToast;
|
||||
window.openMapModal = openMapModal;
|
||||
window.closeMapModal = closeMapModal;
|
||||
window.loadWorkplaceMap = loadWorkplaceMap;
|
||||
|
||||
@@ -740,59 +740,7 @@ function formatDate(date) {
|
||||
return `${year}-${month}-${day}`;
|
||||
}
|
||||
|
||||
// 토스트 메시지 표시
|
||||
function showToast(message, type = 'info') {
|
||||
// 기존 토스트 제거
|
||||
const existingToast = document.querySelector('.toast');
|
||||
if (existingToast) {
|
||||
existingToast.remove();
|
||||
}
|
||||
|
||||
// 새 토스트 생성
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast toast-${type}`;
|
||||
toast.textContent = message;
|
||||
|
||||
// 스타일 적용
|
||||
Object.assign(toast.style, {
|
||||
position: 'fixed',
|
||||
top: '20px',
|
||||
right: '20px',
|
||||
padding: '12px 24px',
|
||||
borderRadius: '8px',
|
||||
color: 'white',
|
||||
fontWeight: '500',
|
||||
zIndex: '10000',
|
||||
transform: 'translateX(100%)',
|
||||
transition: 'transform 0.3s ease'
|
||||
});
|
||||
|
||||
// 타입별 배경색
|
||||
const colors = {
|
||||
success: '#10b981',
|
||||
error: '#ef4444',
|
||||
warning: '#f59e0b',
|
||||
info: '#3b82f6'
|
||||
};
|
||||
toast.style.backgroundColor = colors[type] || colors.info;
|
||||
|
||||
document.body.appendChild(toast);
|
||||
|
||||
// 애니메이션
|
||||
setTimeout(() => {
|
||||
toast.style.transform = 'translateX(0)';
|
||||
}, 100);
|
||||
|
||||
// 자동 제거
|
||||
setTimeout(() => {
|
||||
toast.style.transform = 'translateX(100%)';
|
||||
setTimeout(() => {
|
||||
if (toast.parentNode) {
|
||||
toast.remove();
|
||||
}
|
||||
}, 300);
|
||||
}, 3000);
|
||||
}
|
||||
// showToast → api-base.js 전역 사용
|
||||
|
||||
// 전역 함수로 노출
|
||||
window.switchAnalysisMode = switchAnalysisMode;
|
||||
|
||||
@@ -172,59 +172,7 @@ function navigateToPage(url) {
|
||||
}, 300);
|
||||
}
|
||||
|
||||
// 토스트 메시지 표시
|
||||
function showToast(message, type = 'info') {
|
||||
// 기존 토스트 제거
|
||||
const existingToast = document.querySelector('.toast');
|
||||
if (existingToast) {
|
||||
existingToast.remove();
|
||||
}
|
||||
|
||||
// 새 토스트 생성
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast toast-${type}`;
|
||||
toast.textContent = message;
|
||||
|
||||
// 스타일 적용
|
||||
Object.assign(toast.style, {
|
||||
position: 'fixed',
|
||||
top: '20px',
|
||||
right: '20px',
|
||||
padding: '12px 24px',
|
||||
borderRadius: '8px',
|
||||
color: 'white',
|
||||
fontWeight: '500',
|
||||
zIndex: '1000',
|
||||
transform: 'translateX(100%)',
|
||||
transition: 'transform 0.3s ease'
|
||||
});
|
||||
|
||||
// 타입별 배경색
|
||||
const colors = {
|
||||
success: '#10b981',
|
||||
error: '#ef4444',
|
||||
warning: '#f59e0b',
|
||||
info: '#3b82f6'
|
||||
};
|
||||
toast.style.backgroundColor = colors[type] || colors.info;
|
||||
|
||||
document.body.appendChild(toast);
|
||||
|
||||
// 애니메이션
|
||||
setTimeout(() => {
|
||||
toast.style.transform = 'translateX(0)';
|
||||
}, 100);
|
||||
|
||||
// 자동 제거
|
||||
setTimeout(() => {
|
||||
toast.style.transform = 'translateX(100%)';
|
||||
setTimeout(() => {
|
||||
if (toast.parentNode) {
|
||||
toast.remove();
|
||||
}
|
||||
}, 300);
|
||||
}, 3000);
|
||||
}
|
||||
// showToast → api-base.js 전역 사용
|
||||
|
||||
// 전역 함수로 노출
|
||||
window.navigateToPage = navigateToPage;
|
||||
|
||||
@@ -10,21 +10,11 @@ let currentEditingWorker = null;
|
||||
// 페이지 초기화
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
console.log('👥 작업자 관리 페이지 초기화 시작');
|
||||
await waitForApiConfig();
|
||||
await waitForApi();
|
||||
await loadDepartments();
|
||||
});
|
||||
|
||||
// API 설정 로드 대기
|
||||
async function waitForApiConfig() {
|
||||
let retryCount = 0;
|
||||
while (!window.apiCall && retryCount < 50) {
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
retryCount++;
|
||||
}
|
||||
if (!window.apiCall) {
|
||||
console.error('API 설정 로드 실패');
|
||||
}
|
||||
}
|
||||
// waitForApi → api-base.js 전역 사용
|
||||
|
||||
// ============================================
|
||||
// 부서 관련 함수
|
||||
@@ -573,53 +563,7 @@ function formatDate(dateString) {
|
||||
});
|
||||
}
|
||||
|
||||
// 토스트 메시지 표시
|
||||
function showToast(message, type = 'info') {
|
||||
const existingToast = document.querySelector('.toast');
|
||||
if (existingToast) {
|
||||
existingToast.remove();
|
||||
}
|
||||
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast toast-${type}`;
|
||||
toast.textContent = message;
|
||||
|
||||
Object.assign(toast.style, {
|
||||
position: 'fixed',
|
||||
top: '20px',
|
||||
right: '20px',
|
||||
padding: '12px 24px',
|
||||
borderRadius: '8px',
|
||||
color: 'white',
|
||||
fontWeight: '500',
|
||||
zIndex: '10000',
|
||||
transform: 'translateX(100%)',
|
||||
transition: 'transform 0.3s ease'
|
||||
});
|
||||
|
||||
const colors = {
|
||||
success: '#10b981',
|
||||
error: '#ef4444',
|
||||
warning: '#f59e0b',
|
||||
info: '#3b82f6'
|
||||
};
|
||||
toast.style.backgroundColor = colors[type] || colors.info;
|
||||
|
||||
document.body.appendChild(toast);
|
||||
|
||||
setTimeout(() => {
|
||||
toast.style.transform = 'translateX(0)';
|
||||
}, 100);
|
||||
|
||||
setTimeout(() => {
|
||||
toast.style.transform = 'translateX(100%)';
|
||||
setTimeout(() => {
|
||||
if (toast.parentNode) {
|
||||
toast.remove();
|
||||
}
|
||||
}, 300);
|
||||
}, 3000);
|
||||
}
|
||||
// showToast → api-base.js 전역 사용
|
||||
|
||||
// ============================================
|
||||
// 전역 함수 노출
|
||||
|
||||
@@ -903,59 +903,7 @@ function formatDate(dateString) {
|
||||
});
|
||||
}
|
||||
|
||||
// 토스트 메시지 표시
|
||||
function showToast(message, type = 'info') {
|
||||
// 기존 토스트 제거
|
||||
const existingToast = document.querySelector('.toast');
|
||||
if (existingToast) {
|
||||
existingToast.remove();
|
||||
}
|
||||
|
||||
// 새 토스트 생성
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast toast-${type}`;
|
||||
toast.textContent = message;
|
||||
|
||||
// 스타일 적용
|
||||
Object.assign(toast.style, {
|
||||
position: 'fixed',
|
||||
top: '20px',
|
||||
right: '20px',
|
||||
padding: '12px 24px',
|
||||
borderRadius: '8px',
|
||||
color: 'white',
|
||||
fontWeight: '500',
|
||||
zIndex: '1000',
|
||||
transform: 'translateX(100%)',
|
||||
transition: 'transform 0.3s ease'
|
||||
});
|
||||
|
||||
// 타입별 배경색
|
||||
const colors = {
|
||||
success: '#10b981',
|
||||
error: '#ef4444',
|
||||
warning: '#f59e0b',
|
||||
info: '#3b82f6'
|
||||
};
|
||||
toast.style.backgroundColor = colors[type] || colors.info;
|
||||
|
||||
document.body.appendChild(toast);
|
||||
|
||||
// 애니메이션
|
||||
setTimeout(() => {
|
||||
toast.style.transform = 'translateX(0)';
|
||||
}, 100);
|
||||
|
||||
// 자동 제거
|
||||
setTimeout(() => {
|
||||
toast.style.transform = 'translateX(100%)';
|
||||
setTimeout(() => {
|
||||
if (toast.parentNode) {
|
||||
toast.remove();
|
||||
}
|
||||
}, 300);
|
||||
}, 3000);
|
||||
}
|
||||
// showToast → api-base.js 전역 사용
|
||||
|
||||
// 전역 함수 및 변수로 노출 (다른 모듈에서 접근 가능하도록)
|
||||
// 모듈 시스템이 이미 정의했으면 건너뜀
|
||||
@@ -1604,7 +1552,6 @@ window.saveWorkplace = saveWorkplace;
|
||||
window.deleteWorkplace = deleteWorkplace;
|
||||
window.confirmDeleteWorkplace = confirmDeleteWorkplace;
|
||||
window.refreshWorkplaces = refreshWorkplaces;
|
||||
window.showToast = showToast;
|
||||
window.loadCategories = loadCategories;
|
||||
window.updateLayoutPreview = updateLayoutPreview;
|
||||
window.openWorkplaceMapModal = openWorkplaceMapModal;
|
||||
|
||||
@@ -94,61 +94,6 @@ class WorkplaceUtils {
|
||||
// 전역 인스턴스 생성
|
||||
window.WorkplaceUtils = new WorkplaceUtils();
|
||||
|
||||
// 하위 호환성: 기존 함수들
|
||||
window.formatDate = (dateString) => window.WorkplaceUtils.formatDate(dateString);
|
||||
|
||||
// 토스트 메시지 표시
|
||||
window.showToast = function(message, type = 'info') {
|
||||
// 기존 토스트 제거
|
||||
const existingToast = document.querySelector('.toast');
|
||||
if (existingToast) {
|
||||
existingToast.remove();
|
||||
}
|
||||
|
||||
// 새 토스트 생성
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `toast toast-${type}`;
|
||||
toast.textContent = message;
|
||||
|
||||
// 스타일 적용
|
||||
Object.assign(toast.style, {
|
||||
position: 'fixed',
|
||||
top: '20px',
|
||||
right: '20px',
|
||||
padding: '12px 24px',
|
||||
borderRadius: '8px',
|
||||
color: 'white',
|
||||
fontWeight: '500',
|
||||
zIndex: '1000',
|
||||
transform: 'translateX(100%)',
|
||||
transition: 'transform 0.3s ease'
|
||||
});
|
||||
|
||||
// 타입별 배경색
|
||||
const colors = {
|
||||
success: '#10b981',
|
||||
error: '#ef4444',
|
||||
warning: '#f59e0b',
|
||||
info: '#3b82f6'
|
||||
};
|
||||
toast.style.backgroundColor = colors[type] || colors.info;
|
||||
|
||||
document.body.appendChild(toast);
|
||||
|
||||
// 애니메이션
|
||||
setTimeout(() => {
|
||||
toast.style.transform = 'translateX(0)';
|
||||
}, 100);
|
||||
|
||||
// 자동 제거
|
||||
setTimeout(() => {
|
||||
toast.style.transform = 'translateX(100%)';
|
||||
setTimeout(() => {
|
||||
if (toast.parentNode) {
|
||||
toast.remove();
|
||||
}
|
||||
}, 300);
|
||||
}, 3000);
|
||||
};
|
||||
// showToast, formatDate → api-base.js 전역 사용
|
||||
|
||||
console.log('[Module] workplace-management/utils.js 로드 완료');
|
||||
|
||||
Reference in New Issue
Block a user