feat: 구매/안전 시스템 전면 개편 — tkpurchase 개편 + tksafety 신규 + 권한 보강

Phase 1: tkuser 협력업체 CRUD 이관 (읽기전용 → 전체 CRUD)
Phase 2: tkpurchase 개편 — 일용공 신청/확정, 작업일정, 업무현황, 계정관리, 협력업체 포털
Phase 3: tksafety 신규 시스템 — 방문관리 + 안전교육 신고
Phase 4: SSO 인증 보강 (partner_company_id JWT, 만료일 체크), 권한 테이블 기반 접근 제어

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-03-12 17:42:59 +09:00
parent a195dd1d50
commit b800792152
63 changed files with 5548 additions and 262 deletions

View File

@@ -70,6 +70,9 @@ function statusBadge(s) {
const [cls, label] = m[s] || ['badge-gray', s];
return `<span class="badge ${cls}">${label}</span>`;
}
function debounce(fn, ms) {
let t; return function(...args) { clearTimeout(t); t = setTimeout(() => fn.apply(this, args), ms); };
}
/* ===== Logout ===== */
function doLogout() {
@@ -83,8 +86,11 @@ function doLogout() {
function renderNavbar() {
const currentPage = location.pathname.replace(/\//g, '') || 'index.html';
const links = [
{ href: '/', icon: 'fa-door-open', label: '방문 관리', match: ['', 'index.html'] },
{ href: '/partner.html', icon: 'fa-building', label: '협력업체', match: ['partner.html'] },
{ href: '/', icon: 'fa-chart-line', label: '대시보드', match: ['', 'index.html'] },
{ href: '/daylabor.html', icon: 'fa-hard-hat', label: '일용공 신청', match: ['daylabor.html'] },
{ href: '/schedule.html', icon: 'fa-calendar-alt', label: '작업일정', match: ['schedule.html'] },
{ href: '/workreport.html', icon: 'fa-clipboard-list', label: '업무현황', match: ['workreport.html'] },
{ href: '/accounts.html', icon: 'fa-user-shield', label: '계정 관리', match: ['accounts.html'] },
];
const nav = document.getElementById('sideNav');
if (!nav) return;
@@ -110,8 +116,16 @@ function initAuth() {
id: decoded.user_id || decoded.id,
username: decoded.username || decoded.sub,
name: decoded.name || decoded.full_name,
role: (decoded.role || decoded.access_level || '').toLowerCase()
role: (decoded.role || decoded.access_level || '').toLowerCase(),
partner_company_id: decoded.partner_company_id || null,
department_id: decoded.department_id || null
};
// 협력업체 계정 → partner-portal로 분기
if (currentUser.partner_company_id && !location.pathname.includes('partner-portal')) {
location.href = '/partner-portal.html';
return false;
}
const dn = currentUser.name || currentUser.username;
const nameEl = document.getElementById('headerUserName');
const avatarEl = document.getElementById('headerUserAvatar');