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:
Hyungi Ahn
2026-02-25 08:45:55 +09:00
parent 64e3c1227d
commit 4581cddbc0
24 changed files with 112 additions and 932 deletions

View File

@@ -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;

View File

@@ -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);
})();

View File

@@ -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) {

View File

@@ -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() {

View File

@@ -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() {

View File

@@ -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', () => {

View File

@@ -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 전역 사용
// ========== 페이지 접근 권한 관리 ==========

View File

@@ -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 전역 사용
// ==================== 데이터 그룹핑 ====================

View File

@@ -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;

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 전역 사용
// ==================== 공정 관리 ====================

View File

@@ -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 전역 사용
// ==================== 네비게이션 ====================

View File

@@ -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 전역 사용

View File

@@ -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) {

View File

@@ -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 전역 사용

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 전역 사용
// ============================================
// 전역 함수 노출

View File

@@ -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;

View File

@@ -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 로드 완료');