feat: 페이지 구조 재구성 및 사이드바 네비게이션 구현
- 페이지 폴더 재구성: 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>
This commit is contained in:
@@ -409,6 +409,268 @@ const TbmController = {
|
||||
});
|
||||
},
|
||||
|
||||
// ==================== 필터링된 안전 체크리스트 (확장) ====================
|
||||
|
||||
/**
|
||||
* 세션에 맞는 필터링된 안전 체크 항목 조회
|
||||
* 기본 + 날씨 + 작업별 체크항목 통합
|
||||
*/
|
||||
getFilteredSafetyChecks: async (req, res) => {
|
||||
const { sessionId } = req.params;
|
||||
|
||||
try {
|
||||
// 날씨 정보 확인 (이미 저장된 경우 사용, 없으면 새로 조회)
|
||||
const weatherService = require('../services/weatherService');
|
||||
let weatherRecord = await weatherService.getWeatherRecord(sessionId);
|
||||
let weatherConditions = [];
|
||||
|
||||
if (weatherRecord && weatherRecord.weather_conditions) {
|
||||
weatherConditions = weatherRecord.weather_conditions;
|
||||
} else {
|
||||
// 날씨 정보가 없으면 현재 날씨 조회
|
||||
const currentWeather = await weatherService.getCurrentWeather();
|
||||
weatherConditions = await weatherService.determineWeatherConditions(currentWeather);
|
||||
// 날씨 기록 저장
|
||||
await weatherService.saveWeatherRecord(sessionId, currentWeather, weatherConditions);
|
||||
}
|
||||
|
||||
TbmModel.getFilteredSafetyChecks(sessionId, weatherConditions, (err, results) => {
|
||||
if (err) {
|
||||
console.error('필터링된 안전 체크 조회 오류:', err);
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '안전 체크리스트 조회 중 오류가 발생했습니다.',
|
||||
error: err.message
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: results
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('필터링된 안전 체크 조회 오류:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '안전 체크리스트 조회 중 오류가 발생했습니다.',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 현재 날씨 조회
|
||||
*/
|
||||
getCurrentWeather: async (req, res) => {
|
||||
try {
|
||||
const weatherService = require('../services/weatherService');
|
||||
const { nx, ny } = req.query;
|
||||
|
||||
const weatherData = await weatherService.getCurrentWeather(nx, ny);
|
||||
const conditions = await weatherService.determineWeatherConditions(weatherData);
|
||||
const conditionList = await weatherService.getWeatherConditionList();
|
||||
|
||||
// 현재 조건의 상세 정보 매핑
|
||||
const activeConditions = conditionList.filter(c => conditions.includes(c.condition_code));
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
...weatherData,
|
||||
conditions,
|
||||
conditionDetails: activeConditions
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('날씨 조회 오류:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '날씨 조회 중 오류가 발생했습니다.',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 세션 날씨 정보 저장
|
||||
*/
|
||||
saveSessionWeather: async (req, res) => {
|
||||
const { sessionId } = req.params;
|
||||
const { weatherConditions } = req.body;
|
||||
|
||||
try {
|
||||
const weatherService = require('../services/weatherService');
|
||||
|
||||
// 현재 날씨 조회
|
||||
const weatherData = await weatherService.getCurrentWeather();
|
||||
const conditions = weatherConditions || await weatherService.determineWeatherConditions(weatherData);
|
||||
|
||||
// 저장
|
||||
await weatherService.saveWeatherRecord(sessionId, weatherData, conditions);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '날씨 정보가 저장되었습니다.',
|
||||
data: { conditions }
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('날씨 저장 오류:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '날씨 저장 중 오류가 발생했습니다.',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 세션 날씨 정보 조회
|
||||
*/
|
||||
getSessionWeather: async (req, res) => {
|
||||
const { sessionId } = req.params;
|
||||
|
||||
try {
|
||||
const weatherService = require('../services/weatherService');
|
||||
const weatherRecord = await weatherService.getWeatherRecord(sessionId);
|
||||
|
||||
if (!weatherRecord) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '날씨 기록이 없습니다.'
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: weatherRecord
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('날씨 조회 오류:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '날씨 조회 중 오류가 발생했습니다.',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 날씨 조건 목록 조회
|
||||
*/
|
||||
getWeatherConditions: async (req, res) => {
|
||||
try {
|
||||
const weatherService = require('../services/weatherService');
|
||||
const conditions = await weatherService.getWeatherConditionList();
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: conditions
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('날씨 조건 조회 오류:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '날씨 조건 조회 중 오류가 발생했습니다.',
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// ==================== 안전 체크항목 관리 (관리자용) ====================
|
||||
|
||||
/**
|
||||
* 안전 체크 항목 생성
|
||||
*/
|
||||
createSafetyCheck: (req, res) => {
|
||||
const checkData = req.body;
|
||||
|
||||
if (!checkData.check_category || !checkData.check_item) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '카테고리와 체크 항목은 필수입니다.'
|
||||
});
|
||||
}
|
||||
|
||||
TbmModel.createSafetyCheck(checkData, (err, result) => {
|
||||
if (err) {
|
||||
console.error('안전 체크 항목 생성 오류:', err);
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '안전 체크 항목 생성 중 오류가 발생했습니다.',
|
||||
error: err.message
|
||||
});
|
||||
}
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
message: '안전 체크 항목이 생성되었습니다.',
|
||||
data: { check_id: result.insertId }
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 안전 체크 항목 수정
|
||||
*/
|
||||
updateSafetyCheck: (req, res) => {
|
||||
const { checkId } = req.params;
|
||||
const checkData = req.body;
|
||||
|
||||
TbmModel.updateSafetyCheck(checkId, checkData, (err, result) => {
|
||||
if (err) {
|
||||
console.error('안전 체크 항목 수정 오류:', err);
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '안전 체크 항목 수정 중 오류가 발생했습니다.',
|
||||
error: err.message
|
||||
});
|
||||
}
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '안전 체크 항목을 찾을 수 없습니다.'
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '안전 체크 항목이 수정되었습니다.'
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 안전 체크 항목 삭제 (비활성화)
|
||||
*/
|
||||
deleteSafetyCheck: (req, res) => {
|
||||
const { checkId } = req.params;
|
||||
|
||||
TbmModel.deleteSafetyCheck(checkId, (err, result) => {
|
||||
if (err) {
|
||||
console.error('안전 체크 항목 삭제 오류:', err);
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '안전 체크 항목 삭제 중 오류가 발생했습니다.',
|
||||
error: err.message
|
||||
});
|
||||
}
|
||||
|
||||
if (result.affectedRows === 0) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: '안전 체크 항목을 찾을 수 없습니다.'
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '안전 체크 항목이 삭제되었습니다.'
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
// ==================== 작업 인계 관련 ====================
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user