- 페이지 폴더 재구성: safety/, attendance/ 폴더 신규 생성 - work/ → safety/: 이슈 신고, 출입 신청 관련 페이지 이동 - common/ → attendance/: 근태/휴가 관련 페이지 이동 - admin/ 정리: safety-* 파일들을 safety/로 이동 - 사이드바 네비게이션 메뉴 구현 - 카테고리별 메뉴: 작업관리, 안전관리, 근태관리, 시스템관리 - 접기/펼치기 기능 및 상태 저장 - 관리자 전용 메뉴 자동 표시/숨김 - 날씨 API 연동 (기상청 단기예보) - TBM 및 navbar에 현재 날씨 표시 - weatherService.js 추가 - 안전 체크리스트 확장 - 기본/날씨별/작업별 체크 유형 추가 - checklist-manage.html 페이지 추가 - 이슈 신고 시스템 구현 - workIssueController, workIssueModel, workIssueRoutes 추가 - DB 마이그레이션 파일 추가 (실행 대기) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
320 lines
11 KiB
JavaScript
320 lines
11 KiB
JavaScript
/**
|
|
* 페이지 구조 재구성 마이그레이션
|
|
* - 페이지 경로 업데이트 (safety/, attendance/ 폴더로 이동)
|
|
* - 카테고리 재분류
|
|
* - 역할별 기본 페이지 권한 테이블 생성
|
|
*/
|
|
|
|
exports.up = async function(knex) {
|
|
// 1. 페이지 경로 업데이트 - safety 폴더로 이동된 페이지들
|
|
const safetyPageUpdates = [
|
|
{
|
|
old_key: 'issue-report',
|
|
new_key: 'safety.issue_report',
|
|
new_path: '/pages/safety/issue-report.html',
|
|
new_category: 'safety',
|
|
new_name: '이슈 신고'
|
|
},
|
|
{
|
|
old_key: 'issue-list',
|
|
new_key: 'safety.issue_list',
|
|
new_path: '/pages/safety/issue-list.html',
|
|
new_category: 'safety',
|
|
new_name: '이슈 목록'
|
|
},
|
|
{
|
|
old_key: 'issue-detail',
|
|
new_key: 'safety.issue_detail',
|
|
new_path: '/pages/safety/issue-detail.html',
|
|
new_category: 'safety',
|
|
new_name: '이슈 상세'
|
|
},
|
|
{
|
|
old_key: 'visit-request',
|
|
new_key: 'safety.visit_request',
|
|
new_path: '/pages/safety/visit-request.html',
|
|
new_category: 'safety',
|
|
new_name: '방문 요청'
|
|
},
|
|
{
|
|
old_key: 'safety-management',
|
|
new_key: 'safety.management',
|
|
new_path: '/pages/safety/management.html',
|
|
new_category: 'safety',
|
|
new_name: '안전 관리'
|
|
},
|
|
{
|
|
old_key: 'safety-training-conduct',
|
|
new_key: 'safety.training_conduct',
|
|
new_path: '/pages/safety/training-conduct.html',
|
|
new_category: 'safety',
|
|
new_name: '안전교육 진행'
|
|
}
|
|
];
|
|
|
|
// 2. 페이지 경로 업데이트 - attendance 폴더로 이동된 페이지들
|
|
const attendancePageUpdates = [
|
|
{
|
|
old_key: 'daily-attendance',
|
|
new_key: 'attendance.daily',
|
|
new_path: '/pages/attendance/daily.html',
|
|
new_category: 'attendance',
|
|
new_name: '일일 출퇴근'
|
|
},
|
|
{
|
|
old_key: 'monthly-attendance',
|
|
new_key: 'attendance.monthly',
|
|
new_path: '/pages/attendance/monthly.html',
|
|
new_category: 'attendance',
|
|
new_name: '월간 근태'
|
|
},
|
|
{
|
|
old_key: 'annual-vacation-overview',
|
|
new_key: 'attendance.annual_overview',
|
|
new_path: '/pages/attendance/annual-overview.html',
|
|
new_category: 'attendance',
|
|
new_name: '연간 휴가 현황'
|
|
},
|
|
{
|
|
old_key: 'vacation-request',
|
|
new_key: 'attendance.vacation_request',
|
|
new_path: '/pages/attendance/vacation-request.html',
|
|
new_category: 'attendance',
|
|
new_name: '휴가 신청'
|
|
},
|
|
{
|
|
old_key: 'vacation-management',
|
|
new_key: 'attendance.vacation_management',
|
|
new_path: '/pages/attendance/vacation-management.html',
|
|
new_category: 'attendance',
|
|
new_name: '휴가 관리'
|
|
},
|
|
{
|
|
old_key: 'vacation-allocation',
|
|
new_key: 'attendance.vacation_allocation',
|
|
new_path: '/pages/attendance/vacation-allocation.html',
|
|
new_category: 'attendance',
|
|
new_name: '휴가 발생 입력'
|
|
}
|
|
];
|
|
|
|
// 3. admin 폴더 내 파일명 변경
|
|
const adminPageUpdates = [
|
|
{
|
|
old_key: 'attendance-report-comparison',
|
|
new_key: 'admin.attendance_report',
|
|
new_path: '/pages/admin/attendance-report.html',
|
|
new_category: 'admin',
|
|
new_name: '출퇴근-보고서 대조'
|
|
}
|
|
];
|
|
|
|
// 모든 업데이트 실행
|
|
const allUpdates = [...safetyPageUpdates, ...attendancePageUpdates, ...adminPageUpdates];
|
|
|
|
for (const update of allUpdates) {
|
|
await knex('pages')
|
|
.where('page_key', update.old_key)
|
|
.update({
|
|
page_key: update.new_key,
|
|
page_path: update.new_path,
|
|
category: update.new_category,
|
|
page_name: update.new_name
|
|
});
|
|
}
|
|
|
|
// 4. 안전 체크리스트 관리 페이지 추가 (새로 생성된 페이지)
|
|
const existingChecklistPage = await knex('pages')
|
|
.where('page_key', 'safety.checklist_manage')
|
|
.orWhere('page_key', 'safety-checklist-manage')
|
|
.first();
|
|
|
|
if (!existingChecklistPage) {
|
|
await knex('pages').insert({
|
|
page_key: 'safety.checklist_manage',
|
|
page_name: '안전 체크리스트 관리',
|
|
page_path: '/pages/safety/checklist-manage.html',
|
|
category: 'safety',
|
|
description: '안전 체크리스트 항목 관리',
|
|
is_admin_only: 1,
|
|
display_order: 50
|
|
});
|
|
}
|
|
|
|
// 5. 휴가 승인/직접입력 페이지 추가 (새로 생성된 페이지인 경우)
|
|
const vacationPages = [
|
|
{
|
|
page_key: 'attendance.vacation_approval',
|
|
page_name: '휴가 승인 관리',
|
|
page_path: '/pages/attendance/vacation-approval.html',
|
|
category: 'attendance',
|
|
description: '휴가 신청 승인/거부',
|
|
is_admin_only: 1,
|
|
display_order: 65
|
|
},
|
|
{
|
|
page_key: 'attendance.vacation_input',
|
|
page_name: '휴가 직접 입력',
|
|
page_path: '/pages/attendance/vacation-input.html',
|
|
category: 'attendance',
|
|
description: '관리자 휴가 직접 입력',
|
|
is_admin_only: 1,
|
|
display_order: 66
|
|
}
|
|
];
|
|
|
|
for (const page of vacationPages) {
|
|
const existing = await knex('pages').where('page_key', page.page_key).first();
|
|
if (!existing) {
|
|
await knex('pages').insert(page);
|
|
}
|
|
}
|
|
|
|
// 6. role_default_pages 테이블 생성 (역할별 기본 페이지 권한)
|
|
const tableExists = await knex.schema.hasTable('role_default_pages');
|
|
if (!tableExists) {
|
|
await knex.schema.createTable('role_default_pages', (table) => {
|
|
table.integer('role_id').unsigned().notNullable()
|
|
.references('id').inTable('roles').onDelete('CASCADE');
|
|
table.integer('page_id').unsigned().notNullable()
|
|
.references('id').inTable('pages').onDelete('CASCADE');
|
|
table.primary(['role_id', 'page_id']);
|
|
table.timestamps(true, true);
|
|
});
|
|
}
|
|
|
|
// 7. 기본 역할-페이지 매핑 데이터 삽입
|
|
// 역할 조회
|
|
const roles = await knex('roles').select('id', 'name');
|
|
const pages = await knex('pages').select('id', 'page_key', 'category');
|
|
|
|
const roleMap = {};
|
|
roles.forEach(r => { roleMap[r.name] = r.id; });
|
|
|
|
const pageMap = {};
|
|
pages.forEach(p => { pageMap[p.page_key] = p.id; });
|
|
|
|
// Worker 역할 기본 페이지 (대시보드, 작업보고서, 휴가신청)
|
|
const workerPages = [
|
|
'dashboard',
|
|
'work.report_create',
|
|
'work.report_view',
|
|
'attendance.vacation_request'
|
|
];
|
|
|
|
// Leader 역할 기본 페이지 (Worker + TBM, 안전, 근태 일부)
|
|
const leaderPages = [
|
|
...workerPages,
|
|
'work.tbm',
|
|
'work.analysis',
|
|
'safety.issue_report',
|
|
'safety.issue_list',
|
|
'attendance.daily',
|
|
'attendance.monthly'
|
|
];
|
|
|
|
// SafetyManager 역할 기본 페이지 (Leader + 안전 전체)
|
|
const safetyManagerPages = [
|
|
...leaderPages,
|
|
'safety.issue_detail',
|
|
'safety.visit_request',
|
|
'safety.management',
|
|
'safety.training_conduct',
|
|
'safety.checklist_manage'
|
|
];
|
|
|
|
// 역할별 페이지 매핑 삽입
|
|
const rolePageMappings = [];
|
|
|
|
if (roleMap['Worker']) {
|
|
workerPages.forEach(pageKey => {
|
|
if (pageMap[pageKey]) {
|
|
rolePageMappings.push({ role_id: roleMap['Worker'], page_id: pageMap[pageKey] });
|
|
}
|
|
});
|
|
}
|
|
|
|
if (roleMap['Leader']) {
|
|
leaderPages.forEach(pageKey => {
|
|
if (pageMap[pageKey]) {
|
|
rolePageMappings.push({ role_id: roleMap['Leader'], page_id: pageMap[pageKey] });
|
|
}
|
|
});
|
|
}
|
|
|
|
if (roleMap['SafetyManager']) {
|
|
safetyManagerPages.forEach(pageKey => {
|
|
if (pageMap[pageKey]) {
|
|
rolePageMappings.push({ role_id: roleMap['SafetyManager'], page_id: pageMap[pageKey] });
|
|
}
|
|
});
|
|
}
|
|
|
|
// 중복 제거 후 삽입
|
|
for (const mapping of rolePageMappings) {
|
|
const existing = await knex('role_default_pages')
|
|
.where('role_id', mapping.role_id)
|
|
.where('page_id', mapping.page_id)
|
|
.first();
|
|
|
|
if (!existing) {
|
|
await knex('role_default_pages').insert(mapping);
|
|
}
|
|
}
|
|
|
|
console.log('페이지 구조 재구성 완료');
|
|
console.log(`- 업데이트된 페이지: ${allUpdates.length}개`);
|
|
console.log(`- 역할별 기본 페이지 매핑: ${rolePageMappings.length}개`);
|
|
};
|
|
|
|
exports.down = async function(knex) {
|
|
// 1. role_default_pages 테이블 삭제
|
|
await knex.schema.dropTableIfExists('role_default_pages');
|
|
|
|
// 2. 페이지 경로 원복 - safety → work/admin
|
|
const safetyRevert = [
|
|
{ new_key: 'safety.issue_report', old_key: 'issue-report', old_path: '/pages/work/issue-report.html', old_category: 'work' },
|
|
{ new_key: 'safety.issue_list', old_key: 'issue-list', old_path: '/pages/work/issue-list.html', old_category: 'work' },
|
|
{ new_key: 'safety.issue_detail', old_key: 'issue-detail', old_path: '/pages/work/issue-detail.html', old_category: 'work' },
|
|
{ new_key: 'safety.visit_request', old_key: 'visit-request', old_path: '/pages/work/visit-request.html', old_category: 'work' },
|
|
{ new_key: 'safety.management', old_key: 'safety-management', old_path: '/pages/admin/safety-management.html', old_category: 'admin' },
|
|
{ new_key: 'safety.training_conduct', old_key: 'safety-training-conduct', old_path: '/pages/admin/safety-training-conduct.html', old_category: 'admin' },
|
|
];
|
|
|
|
// 3. 페이지 경로 원복 - attendance → common
|
|
const attendanceRevert = [
|
|
{ new_key: 'attendance.daily', old_key: 'daily-attendance', old_path: '/pages/common/daily-attendance.html', old_category: 'common' },
|
|
{ new_key: 'attendance.monthly', old_key: 'monthly-attendance', old_path: '/pages/common/monthly-attendance.html', old_category: 'common' },
|
|
{ new_key: 'attendance.annual_overview', old_key: 'annual-vacation-overview', old_path: '/pages/common/annual-vacation-overview.html', old_category: 'common' },
|
|
{ new_key: 'attendance.vacation_request', old_key: 'vacation-request', old_path: '/pages/common/vacation-request.html', old_category: 'common' },
|
|
{ new_key: 'attendance.vacation_management', old_key: 'vacation-management', old_path: '/pages/common/vacation-management.html', old_category: 'common' },
|
|
{ new_key: 'attendance.vacation_allocation', old_key: 'vacation-allocation', old_path: '/pages/common/vacation-allocation.html', old_category: 'common' },
|
|
];
|
|
|
|
// 4. admin 파일명 원복
|
|
const adminRevert = [
|
|
{ new_key: 'admin.attendance_report', old_key: 'attendance-report-comparison', old_path: '/pages/admin/attendance-report-comparison.html', old_category: 'admin' }
|
|
];
|
|
|
|
const allReverts = [...safetyRevert, ...attendanceRevert, ...adminRevert];
|
|
|
|
for (const revert of allReverts) {
|
|
await knex('pages')
|
|
.where('page_key', revert.new_key)
|
|
.update({
|
|
page_key: revert.old_key,
|
|
page_path: revert.old_path,
|
|
category: revert.old_category
|
|
});
|
|
}
|
|
|
|
// 5. 새로 추가된 페이지 삭제
|
|
await knex('pages').whereIn('page_key', [
|
|
'safety.checklist_manage',
|
|
'attendance.vacation_approval',
|
|
'attendance.vacation_input'
|
|
]).del();
|
|
|
|
console.log('페이지 구조 재구성 롤백 완료');
|
|
};
|