Files
Hyungi Ahn 733bb0cb35 feat: tkuser 통합 관리 서비스 + 전체 시스템 SSO 쿠키 인증 통합
- tkuser 서비스 신규 추가 (API + Web)
  - 사용자/권한/프로젝트/부서/작업자/작업장/설비/작업/휴가 통합 관리
  - 작업장 탭: 공장→작업장 드릴다운 네비게이션 + 구역지도 클릭 연동
  - 작업 탭: 공정(work_types)→작업(tasks) 계층 관리
  - 휴가 탭: 유형 관리 + 연차 배정(근로기준법 자동계산)
- 전 시스템 SSO 쿠키 인증으로 통합 (.technicalkorea.net 공유)
- System 2: 작업 이슈 리포트 기능 강화
- System 3: tkuser API 연동, 페이지 권한 체계 적용
- docker-compose에 tkuser-api, tkuser-web 서비스 추가
- ARCHITECTURE.md, DEPLOYMENT.md 문서 작성

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 13:45:52 +09:00

142 lines
5.0 KiB
JavaScript

/**
* Equipment Controller
*
* 설비 CRUD + 지도위치 + 사진
*/
const equipmentModel = require('../models/equipmentModel');
const path = require('path');
const fs = require('fs');
// ==================== 기본 CRUD ====================
async function getAll(req, res, next) {
try {
const filters = {};
if (req.query.workplace_id) filters.workplace_id = parseInt(req.query.workplace_id);
if (req.query.equipment_type) filters.equipment_type = req.query.equipment_type;
if (req.query.status) filters.status = req.query.status;
if (req.query.search) filters.search = req.query.search;
const equipments = await equipmentModel.getAll(filters);
res.json({ success: true, data: equipments });
} catch (err) { next(err); }
}
async function getById(req, res, next) {
try {
const eq = await equipmentModel.getById(parseInt(req.params.id));
if (!eq) return res.status(404).json({ success: false, error: '설비를 찾을 수 없습니다' });
res.json({ success: true, data: eq });
} catch (err) { next(err); }
}
async function getByWorkplace(req, res, next) {
try {
const equipments = await equipmentModel.getByWorkplace(parseInt(req.params.workplaceId));
res.json({ success: true, data: equipments });
} catch (err) { next(err); }
}
async function create(req, res, next) {
try {
const { equipment_code, equipment_name } = req.body;
if (!equipment_code || !equipment_name) return res.status(400).json({ success: false, error: '관리번호와 설비명은 필수입니다' });
const dup = await equipmentModel.checkDuplicateCode(equipment_code);
if (dup) return res.status(409).json({ success: false, error: '이미 존재하는 관리번호입니다' });
const eq = await equipmentModel.create(req.body);
res.status(201).json({ success: true, data: eq });
} catch (err) { next(err); }
}
async function update(req, res, next) {
try {
const id = parseInt(req.params.id);
if (req.body.equipment_code) {
const dup = await equipmentModel.checkDuplicateCode(req.body.equipment_code, id);
if (dup) return res.status(409).json({ success: false, error: '이미 존재하는 관리번호입니다' });
}
const eq = await equipmentModel.update(id, req.body);
if (!eq) return res.status(404).json({ success: false, error: '설비를 찾을 수 없습니다' });
res.json({ success: true, data: eq });
} catch (err) { next(err); }
}
async function remove(req, res, next) {
try {
await equipmentModel.remove(parseInt(req.params.id));
res.json({ success: true, message: '설비가 삭제되었습니다' });
} catch (err) { next(err); }
}
async function getTypes(req, res, next) {
try {
const types = await equipmentModel.getEquipmentTypes();
res.json({ success: true, data: types });
} catch (err) { next(err); }
}
async function getNextCode(req, res, next) {
try {
const code = await equipmentModel.getNextCode(req.query.prefix || 'TKP');
res.json({ success: true, data: code });
} catch (err) { next(err); }
}
// ==================== 지도 위치 ====================
async function updateMapPosition(req, res, next) {
try {
const id = parseInt(req.params.id);
const positionData = {
map_x_percent: req.body.map_x_percent,
map_y_percent: req.body.map_y_percent,
map_width_percent: req.body.map_width_percent,
map_height_percent: req.body.map_height_percent
};
if (req.body.workplace_id !== undefined) positionData.workplace_id = req.body.workplace_id;
const eq = await equipmentModel.updateMapPosition(id, positionData);
res.json({ success: true, data: eq });
} catch (err) { next(err); }
}
// ==================== 사진 ====================
async function addPhoto(req, res, next) {
try {
const equipmentId = parseInt(req.params.id);
if (!req.file) return res.status(400).json({ success: false, error: '사진 파일이 필요합니다' });
const photoData = {
photo_path: `/uploads/${req.file.filename}`,
description: req.body.description || null,
display_order: parseInt(req.body.display_order) || 0,
uploaded_by: req.user?.user_id || null
};
const result = await equipmentModel.addPhoto(equipmentId, photoData);
res.status(201).json({ success: true, data: result });
} catch (err) { next(err); }
}
async function getPhotos(req, res, next) {
try {
const results = await equipmentModel.getPhotos(parseInt(req.params.id));
res.json({ success: true, data: results });
} catch (err) { next(err); }
}
async function deletePhoto(req, res, next) {
try {
const result = await equipmentModel.deletePhoto(parseInt(req.params.photoId));
if (result.photo_path) {
const filePath = path.join(__dirname, '..', result.photo_path);
fs.unlink(filePath, () => {});
}
res.json({ success: true, message: '사진이 삭제되었습니다' });
} catch (err) { next(err); }
}
module.exports = {
getAll, getById, getByWorkplace, create, update, remove, getTypes, getNextCode,
updateMapPosition,
addPhoto, getPhotos, deletePhoto
};