feat: 일일순회점검 시스템 구축 및 관리 기능 개선

- 일일순회점검 시스템 신규 구현
  - DB 테이블: patrol_checklist_items, daily_patrol_sessions, patrol_check_records, workplace_items, item_types
  - API: /api/patrol/* 엔드포인트
  - 프론트엔드: 지도 기반 작업장 점검 UI

- 설비 관리 기능 개선
  - 구매 관련 필드 추가 (구매일, 가격, 공급업체 등)
  - 설비 코드 자동 생성 (TKP-XXX 형식)

- 작업장 관리 개선
  - 레이아웃 이미지 업로드 기능
  - 마커 위치 저장 기능

- 부서 관리 기능 추가
- 사이드바 네비게이션 카테고리 재구성
- 이미지 401 오류 수정 (정적 파일 경로 처리)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-02-04 11:41:41 +09:00
parent 2e9d24faf2
commit 90d3e32992
101 changed files with 17421 additions and 7047 deletions

View File

@@ -0,0 +1,31 @@
// routes/departmentRoutes.js
const express = require('express');
const router = express.Router();
const departmentController = require('../controllers/departmentController');
const { requireAuth, requireRole } = require('../middlewares/authMiddleware');
// 부서 목록 조회 (인증 필요)
router.get('/', requireAuth, departmentController.getAll);
// 부서 상세 조회
router.get('/:id', requireAuth, departmentController.getById);
// 부서별 작업자 조회
router.get('/:id/workers', requireAuth, departmentController.getWorkers);
// 부서 생성 (관리자만)
router.post('/', requireAuth, requireRole(['Admin', 'System Admin']), departmentController.create);
// 부서 수정 (관리자만)
router.put('/:id', requireAuth, requireRole(['Admin', 'System Admin']), departmentController.update);
// 부서 삭제 (관리자만)
router.delete('/:id', requireAuth, requireRole(['Admin', 'System Admin']), departmentController.delete);
// 작업자 부서 이동 (관리자만)
router.post('/move-worker', requireAuth, requireRole(['Admin', 'System Admin']), departmentController.moveWorker);
// 여러 작업자 부서 일괄 이동 (관리자만)
router.post('/move-workers', requireAuth, requireRole(['Admin', 'System Admin']), departmentController.moveWorkers);
module.exports = router;

View File

@@ -18,6 +18,10 @@ router.get('/active/list', equipmentController.getActiveEquipments);
// READ 설비 유형 목록
router.get('/types', equipmentController.getEquipmentTypes);
// GET NEXT EQUIPMENT CODE - 다음 관리번호 자동 생성
// ?prefix=TKP (기본값: TKP)
router.get('/next-code', equipmentController.getNextEquipmentCode);
// READ 작업장별 설비
router.get('/workplace/:workplaceId', equipmentController.getEquipmentsByWorkplace);

View File

@@ -0,0 +1,73 @@
// patrolRoutes.js
// 일일순회점검 시스템 라우트
const express = require('express');
const router = express.Router();
const patrolController = require('../controllers/patrolController');
// ==================== 순회점검 세션 ====================
// 세션 목록 조회
// GET /patrol/sessions?patrol_date=2026-02-04&patrol_time=morning&category_id=1
router.get('/sessions', patrolController.getSessions);
// 세션 시작/조회 (POST로 생성하거나 기존 세션 반환)
// POST /patrol/sessions { patrol_date, patrol_time, category_id }
router.post('/sessions', patrolController.getOrCreateSession);
// 세션 상세 조회
router.get('/sessions/:sessionId', patrolController.getSession);
// 세션 완료
router.patch('/sessions/:sessionId/complete', patrolController.completeSession);
// 세션 메모 업데이트
router.patch('/sessions/:sessionId/notes', patrolController.updateSessionNotes);
// 세션별 작업장 점검 현황
router.get('/sessions/:sessionId/workplace-status', patrolController.getWorkplaceCheckStatus);
// ==================== 체크리스트 항목 ====================
// 체크리스트 항목 조회 (필터링 가능)
// GET /patrol/checklist?category_id=1&workplace_id=2
router.get('/checklist', patrolController.getChecklistItems);
// 체크리스트 항목 CRUD
router.post('/checklist', patrolController.createChecklistItem);
router.put('/checklist/:itemId', patrolController.updateChecklistItem);
router.delete('/checklist/:itemId', patrolController.deleteChecklistItem);
// ==================== 체크 기록 ====================
// 세션별 체크 기록 조회
// GET /patrol/sessions/:sessionId/records?workplace_id=1
router.get('/sessions/:sessionId/records', patrolController.getCheckRecords);
// 체크 기록 저장 (단건)
router.post('/sessions/:sessionId/records', patrolController.saveCheckRecord);
// 체크 기록 일괄 저장
router.post('/sessions/:sessionId/records/batch', patrolController.saveCheckRecords);
// ==================== 작업장 물품 현황 ====================
// 작업장별 물품 조회
router.get('/workplaces/:workplaceId/items', patrolController.getWorkplaceItems);
// 물품 CRUD
router.post('/workplaces/:workplaceId/items', patrolController.createWorkplaceItem);
router.put('/items/:itemId', patrolController.updateWorkplaceItem);
router.delete('/items/:itemId', patrolController.deleteWorkplaceItem);
// ==================== 물품 유형 ====================
// 물품 유형 목록
router.get('/item-types', patrolController.getItemTypes);
// ==================== 대시보드/통계 ====================
// 오늘 순회점검 현황
router.get('/today-status', patrolController.getTodayStatus);
module.exports = router;

View File

@@ -20,16 +20,25 @@ router.use(verifyToken);
/**
* 관리자 권한 확인 미들웨어
* role 또는 access_level로 관리자 확인
*/
const adminOnly = (req, res, next) => {
const userRole = req.user?.role?.toLowerCase();
if (req.user && (userRole === 'admin' || userRole === 'system' || userRole === 'system admin')) {
const accessLevel = req.user?.access_level?.toLowerCase();
// role 기반 확인
const isAdminByRole = userRole === 'admin' || userRole === 'system' || userRole === 'system admin';
// access_level 기반 확인 (role이 없는 경우 대비)
const isAdminByAccessLevel = accessLevel === 'admin' || accessLevel === 'system';
if (req.user && (isAdminByRole || isAdminByAccessLevel)) {
next();
} else {
logger.warn('관리자 권한 없는 접근 시도', {
userId: req.user?.user_id,
username: req.user?.username,
role: req.user?.role,
accessLevel: req.user?.access_level,
url: req.originalUrl
});
return res.status(403).json({
@@ -146,9 +155,12 @@ router.put('/:id/status', userController.updateUserStatus);
// 🔑 사용자 비밀번호 초기화 (000000)
router.post('/:id/reset-password', userController.resetUserPassword);
// 🗑️ 사용자 삭제
// 🗑️ 사용자 비활성화 (Soft Delete)
router.delete('/:id', userController.deleteUser);
// 💀 사용자 영구 삭제 (Hard Delete)
router.delete('/:id/permanent', userController.permanentDeleteUser);
// 🔐 사용자 페이지 접근 권한 업데이트 (Admin만)
router.put('/:id/page-access', userController.updateUserPageAccess);