Files
TK-FB-Project/api.hyungi.net/controllers/vacationTypeController.js
Hyungi Ahn b6485e3140 feat: 대시보드 작업장 현황 지도 구현
- 실시간 작업장 현황을 지도로 시각화
- 작업장 관리 페이지에서 정의한 구역 정보 활용
- TBM 작업자 및 방문자 현황 표시

주요 변경사항:
- dashboard.html: 작업장 현황 섹션 추가 (기존 작업 현황 테이블 제거)
- workplace-status.js: 지도 렌더링 및 데이터 통합 로직 구현
- modern-dashboard.js: 삭제된 DOM 요소 조건부 체크 추가

시각화 방식:
- 인원 없음: 회색 테두리 + 작업장 이름
- 내부 작업자: 파란색 영역 + 인원 수
- 외부 방문자: 보라색 영역 + 인원 수
- 둘 다: 초록색 영역 + 총 인원 수

기술 구현:
- Canvas API 기반 사각형 영역 렌더링
- map-regions API를 통한 데이터 일관성 보장
- 클릭 이벤트로 상세 정보 모달 표시

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-29 15:46:47 +09:00

334 lines
9.4 KiB
JavaScript

/**
* vacationTypeController.js
* 휴가 유형 관련 컨트롤러
*/
const vacationTypeModel = require('../models/vacationTypeModel');
const vacationTypeController = {
/**
* 모든 활성 휴가 유형 조회
* GET /api/vacation-types
*/
async getAllTypes(req, res) {
try {
vacationTypeModel.getAll((err, results) => {
if (err) {
console.error('휴가 유형 조회 오류:', err);
return res.status(500).json({
success: false,
message: '휴가 유형을 조회하는 중 오류가 발생했습니다'
});
}
res.json({
success: true,
data: results
});
});
} catch (error) {
console.error('getAllTypes 오류:', error);
res.status(500).json({
success: false,
message: '서버 오류가 발생했습니다'
});
}
},
/**
* 시스템 기본 휴가 유형 조회
* GET /api/vacation-types/system
*/
async getSystemTypes(req, res) {
try {
vacationTypeModel.getSystemTypes((err, results) => {
if (err) {
console.error('시스템 휴가 유형 조회 오류:', err);
return res.status(500).json({
success: false,
message: '시스템 휴가 유형을 조회하는 중 오류가 발생했습니다'
});
}
res.json({
success: true,
data: results
});
});
} catch (error) {
console.error('getSystemTypes 오류:', error);
res.status(500).json({
success: false,
message: '서버 오류가 발생했습니다'
});
}
},
/**
* 특별 휴가 유형 조회
* GET /api/vacation-types/special
*/
async getSpecialTypes(req, res) {
try {
vacationTypeModel.getSpecialTypes((err, results) => {
if (err) {
console.error('특별 휴가 유형 조회 오류:', err);
return res.status(500).json({
success: false,
message: '특별 휴가 유형을 조회하는 중 오류가 발생했습니다'
});
}
res.json({
success: true,
data: results
});
});
} catch (error) {
console.error('getSpecialTypes 오류:', error);
res.status(500).json({
success: false,
message: '서버 오류가 발생했습니다'
});
}
},
/**
* 특별 휴가 유형 생성 (관리자만)
* POST /api/vacation-types
*/
async createType(req, res) {
try {
const {
type_code,
type_name,
deduct_days,
priority,
description
} = req.body;
// 필수 필드 검증
if (!type_code || !type_name || !deduct_days) {
return res.status(400).json({
success: false,
message: '필수 필드가 누락되었습니다 (type_code, type_name, deduct_days)'
});
}
// type_code 중복 체크
vacationTypeModel.getByCode(type_code, (err, existingTypes) => {
if (err) {
console.error('type_code 중복 체크 오류:', err);
return res.status(500).json({
success: false,
message: 'type_code 중복 체크 중 오류가 발생했습니다'
});
}
if (existingTypes && existingTypes.length > 0) {
return res.status(400).json({
success: false,
message: '이미 존재하는 type_code입니다'
});
}
// 특별 휴가 유형으로 생성
const typeData = {
type_code,
type_name,
deduct_days,
priority: priority || 50,
description: description || null,
is_special: true,
is_system: false,
is_active: true
};
vacationTypeModel.create(typeData, (err, result) => {
if (err) {
console.error('휴가 유형 생성 오류:', err);
return res.status(500).json({
success: false,
message: '휴가 유형을 생성하는 중 오류가 발생했습니다'
});
}
res.status(201).json({
success: true,
message: '특별 휴가 유형이 생성되었습니다',
data: { id: result.insertId }
});
});
});
} catch (error) {
console.error('createType 오류:', error);
res.status(500).json({
success: false,
message: '서버 오류가 발생했습니다'
});
}
},
/**
* 휴가 유형 수정 (관리자만)
* PUT /api/vacation-types/:id
*/
async updateType(req, res) {
try {
const { id } = req.params;
const {
type_name,
deduct_days,
priority,
description,
is_active
} = req.body;
// 먼저 해당 유형 조회
vacationTypeModel.getById(id, (err, types) => {
if (err) {
console.error('휴가 유형 조회 오류:', err);
return res.status(500).json({
success: false,
message: '휴가 유형을 조회하는 중 오류가 발생했습니다'
});
}
if (!types || types.length === 0) {
return res.status(404).json({
success: false,
message: '휴가 유형을 찾을 수 없습니다'
});
}
const type = types[0];
// 시스템 기본 휴가의 경우 제한적으로만 수정 가능
const updateData = {};
if (type.is_system) {
// 시스템 휴가는 priority와 description만 수정 가능
if (priority !== undefined) updateData.priority = priority;
if (description !== undefined) updateData.description = description;
} else {
// 특별 휴가는 모든 필드 수정 가능
if (type_name) updateData.type_name = type_name;
if (deduct_days !== undefined) updateData.deduct_days = deduct_days;
if (priority !== undefined) updateData.priority = priority;
if (description !== undefined) updateData.description = description;
if (is_active !== undefined) updateData.is_active = is_active;
}
if (Object.keys(updateData).length === 0) {
return res.status(400).json({
success: false,
message: '수정할 데이터가 없습니다'
});
}
updateData.updated_at = new Date();
vacationTypeModel.update(id, updateData, (err, result) => {
if (err) {
console.error('휴가 유형 수정 오류:', err);
return res.status(500).json({
success: false,
message: '휴가 유형을 수정하는 중 오류가 발생했습니다'
});
}
res.json({
success: true,
message: '휴가 유형이 수정되었습니다'
});
});
});
} catch (error) {
console.error('updateType 오류:', error);
res.status(500).json({
success: false,
message: '서버 오류가 발생했습니다'
});
}
},
/**
* 특별 휴가 유형 삭제 (관리자만, 시스템 기본 휴가는 삭제 불가)
* DELETE /api/vacation-types/:id
*/
async deleteType(req, res) {
try {
const { id } = req.params;
vacationTypeModel.delete(id, (err, result) => {
if (err) {
console.error('휴가 유형 삭제 오류:', err);
return res.status(500).json({
success: false,
message: '휴가 유형을 삭제하는 중 오류가 발생했습니다'
});
}
if (result.affectedRows === 0) {
return res.status(400).json({
success: false,
message: '삭제할 수 없습니다. 시스템 기본 휴가이거나 존재하지 않는 휴가 유형입니다'
});
}
res.json({
success: true,
message: '휴가 유형이 삭제되었습니다'
});
});
} catch (error) {
console.error('deleteType 오류:', error);
res.status(500).json({
success: false,
message: '서버 오류가 발생했습니다'
});
}
},
/**
* 휴가 유형 우선순위 일괄 업데이트 (관리자만)
* PUT /api/vacation-types/priorities
*/
async updatePriorities(req, res) {
try {
const { priorities } = req.body;
// priorities = [{ id: 1, priority: 10 }, { id: 2, priority: 20 }, ...]
if (!priorities || !Array.isArray(priorities)) {
return res.status(400).json({
success: false,
message: 'priorities 배열이 필요합니다'
});
}
vacationTypeModel.updatePriorities(priorities, (err, result) => {
if (err) {
console.error('우선순위 업데이트 오류:', err);
return res.status(500).json({
success: false,
message: '우선순위를 업데이트하는 중 오류가 발생했습니다'
});
}
res.json({
success: true,
message: '우선순위가 업데이트되었습니다',
data: { updated: result.affectedRows }
});
});
} catch (error) {
console.error('updatePriorities 오류:', error);
res.status(500).json({
success: false,
message: '서버 오류가 발생했습니다'
});
}
}
};
module.exports = vacationTypeController;