🏢 시스템
@@ -334,36 +348,90 @@
return protocol + '//' + hostname + ':' + (ports[name] || 30000);
}
- // ===== Card Definitions =====
- var ALL_SHORTCUTS = [
- // 작업 관리
- { id: 'tbm', name: 'TBM', icon: '\uD83D\uDCCB', cat: '작업 관리', subdomain: 'tkfb', path: '/pages/work/tbm.html', pageKey: 's1.work.tbm' },
- { id: 'report', name: '작업보고서', icon: '\uD83D\uDCDD', cat: '작업 관리', subdomain: 'tkfb', path: '/pages/work/report-create.html', pageKey: 's1.work.report_create' },
- { id: 'analysis', name: '작업 분석', icon: '\uD83D\uDCCA', cat: '작업 관리', subdomain: 'tkfb', path: '/pages/work/analysis.html', pageKey: 's1.work.analysis' },
- { id: 'nonconformity', name: '부적합 현황', icon: '\u26A0\uFE0F', cat: '작업 관리', subdomain: 'tkfb', path: '/pages/work/nonconformity.html', pageKey: 's1.work.nonconformity' },
-
- // 공장 관리
- { id: 'repair', name: '시설설비 관리', icon: '\uD83D\uDD27', cat: '공장 관리', subdomain: 'tkfb', path: '/pages/admin/repair-management.html', pageKey: 's1.factory.repair_management' },
- { id: 'patrol', name: '일일순회점검', icon: '\uD83D\uDD0D', cat: '공장 관리', subdomain: 'tkfb', path: '/pages/inspection/daily-patrol.html', pageKey: 's1.inspection.daily_patrol' },
- { id: 'checkin', name: '출퇴근 체크', icon: '\u23F0', cat: '공장 관리', subdomain: 'tkfb', path: '/pages/attendance/checkin.html', pageKey: 's1.inspection.checkin' },
- { id: 'workstatus', name: '근무 현황', icon: '\uD83D\uDCBC', cat: '공장 관리', subdomain: 'tkfb', path: '/pages/attendance/work-status.html', pageKey: 's1.inspection.work_status' },
-
- // 근태 관리
- { id: 'vacation', name: '내 연차 정보', icon: '\uD83C\uDFD6\uFE0F', cat: '근태 관리', subdomain: 'tkfb', path: '/pages/attendance/my-vacation-info.html', pageKey: 's1.attendance.my_vacation_info' },
- { id: 'monthly', name: '월간 근태', icon: '\uD83D\uDCC6', cat: '근태 관리', subdomain: 'tkfb', path: '/pages/attendance/monthly.html', pageKey: 's1.attendance.monthly' },
- { id: 'leave', name: '휴가 신청', icon: '\uD83D\uDCC5', cat: '근태 관리', subdomain: 'tkfb', path: '/pages/attendance/vacation-request.html', pageKey: 's1.attendance.vacation_request' },
- { id: 'vacmgmt', name: '휴가 관리', icon: '\u2699\uFE0F', cat: '근태 관리', subdomain: 'tkfb', path: '/pages/attendance/vacation-management.html', pageKey: 's1.attendance.vacation_management' },
-
- // 신고·안전
- { id: 'issue', name: '안전신고', icon: '\uD83D\uDEA8', cat: '신고·안전', subdomain: 'tkreport', path: '/pages/safety/issue-report.html', accessKey: 'system2' },
- { id: 'visit', name: '방문 관리', icon: '\uD83D\uDEAA', cat: '신고·안전', subdomain: 'tksafety', pageKey: 'safety_visit_management' },
- { id: 'education', name: '안전교육', icon: '\uD83C\uDF93', cat: '신고·안전', subdomain: 'tksafety', path: '/education.html', pageKey: 'safety_visit_management' },
-
- // 구매·행정
- { id: 'daylabor', name: '일용공 신청', icon: '\uD83D\uDC77', cat: '구매·행정', subdomain: 'tkpurchase', path: '/daylabor.html', pageKey: 'purchasing_schedule' },
- { id: 'schedule', name: '작업일정', icon: '\uD83D\uDCC5', cat: '구매·행정', subdomain: 'tkpurchase', path: '/schedule.html', pageKey: 'purchasing_schedule' }
+ // ===== Banner Definitions =====
+ var BANNERS = [
+ {
+ id: 'notifications',
+ icon: '\uD83D\uDD14',
+ api: '/api/notifications/unread/count',
+ parse: function(data) {
+ var count = data.data && data.data.count;
+ return count > 0 ? { text: '\uBBF8\uD655\uC778 \uC54C\uB9BC ' + count + '\uAC74' } : null;
+ },
+ subdomain: 'tkfb',
+ path: '/pages/profile/notifications.html',
+ color: '#1a56db'
+ },
+ {
+ id: 'tbm',
+ icon: '\uD83D\uDCCB',
+ api: '/api/tbm/sessions/incomplete-reports',
+ parse: function(data) {
+ var items = data.data || data;
+ var count = Array.isArray(items) ? items.length : 0;
+ return count > 0 ? { text: '\uBBF8\uC81C\uCD9C TBM \uBCF4\uACE0 ' + count + '\uAC74' } : null;
+ },
+ subdomain: 'tkfb',
+ path: '/pages/work/tbm.html',
+ color: '#d97706',
+ requirePageKey: 's1.work.tbm'
+ },
+ {
+ id: 'vacation',
+ icon: '\uD83D\uDCC5',
+ api: '/api/vacation-requests/pending',
+ parse: function(data) {
+ var items = data.data || data;
+ var count = Array.isArray(items) ? items.length : 0;
+ return count > 0 ? { text: '\uD734\uAC00 \uC2B9\uC778 \uB300\uAE30 ' + count + '\uAC74' } : null;
+ },
+ subdomain: 'tkfb',
+ path: '/pages/attendance/vacation-management.html',
+ color: '#7c3aed',
+ requirePageKey: 's1.attendance.vacation_management'
+ }
];
+ // ===== Banner Loading =====
+ async function loadBanners(token, allowed) {
+ var container = document.getElementById('bannerList');
+ container.innerHTML = '';
+
+ var visible = BANNERS.filter(function(b) {
+ return !b.requirePageKey || allowed.has(b.requirePageKey);
+ });
+
+ var results = await Promise.allSettled(
+ visible.map(function(b) {
+ return fetch(b.api, { headers: { 'Authorization': 'Bearer ' + token } })
+ .then(function(r) { return r.ok ? r.json() : null; })
+ .then(function(data) { return data ? { banner: b, result: b.parse(data) } : null; });
+ })
+ );
+
+ var anyVisible = false;
+ results.forEach(function(r) {
+ if (r.status !== 'fulfilled' || !r.value || !r.value.result) return;
+ var b = r.value.banner;
+ var result = r.value.result;
+
+ var a = document.createElement('a');
+ a.className = 'banner-item';
+ a.style.borderLeftColor = b.color;
+ a.href = getSubdomainUrl(b.subdomain) + (b.path || '');
+ a.innerHTML = '
' + b.icon + ''
+ + '
' + result.text + ''
+ + '
\u203A';
+ container.appendChild(a);
+ anyVisible = true;
+ });
+
+ if (anyVisible) {
+ document.getElementById('bannerSection').style.display = '';
+ }
+ }
+
+ // ===== Card Definitions =====
var SYSTEM_CARDS = [
{ id: 'factory', name: '공장관리', icon: '\uD83C\uDFED', subdomain: 'tkfb', path: '/pages/dashboard.html', pageKey: 's1.dashboard', color: '#1a56db' },
{ id: 'report_sys', name: '신고', icon: '\uD83D\uDEA8', subdomain: 'tkreport', accessKey: 'system2', color: '#dc2626' },
@@ -434,30 +502,9 @@
var grid = document.getElementById(gridId);
grid.innerHTML = '';
-
- if (!isSystem && visible.length >= 10) {
- // 카테고리별 그룹핑
- var categories = [];
- var catMap = {};
- visible.forEach(function(c) {
- var cat = c.cat || '기타';
- if (!catMap[cat]) { catMap[cat] = []; categories.push(cat); }
- catMap[cat].push(c);
- });
- categories.forEach(function(cat) {
- var label = document.createElement('div');
- label.className = 'shortcut-cat-label';
- label.textContent = cat;
- grid.appendChild(label);
- catMap[cat].forEach(function(card) {
- grid.appendChild(createCardElement(card, false));
- });
- });
- } else {
- visible.forEach(function(card) {
- grid.appendChild(createCardElement(card, isSystem));
- });
- }
+ visible.forEach(function(card) {
+ grid.appendChild(createCardElement(card, isSystem));
+ });
document.getElementById(sectionId).style.display = '';
}
@@ -494,8 +541,8 @@
if (systemAccess.system3 !== false) allowed.add('issues_dashboard');
}
- // Render sections
- renderSection('shortcutSection', 'shortcutGrid', ALL_SHORTCUTS, allowed, systemAccess, false);
+ // Render banners + system cards
+ loadBanners(token, allowed);
renderSection('systemSection', 'systemGrid', SYSTEM_CARDS, allowed, systemAccess, true);
}