feat: 작업장 관리 기능 추가 (공장-작업장 계층 구조)
- 공장(카테고리) 및 작업장 CRUD API 구현 - 탭 기반 UI로 공장별 작업장 필터링 - 터치 최적화된 관리자 페이지 - DB 테이블: workplace_categories, workplaces - 관리자 메뉴에 작업장 관리 추가 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
314
api.hyungi.net/controllers/workplaceController.js
Normal file
314
api.hyungi.net/controllers/workplaceController.js
Normal file
@@ -0,0 +1,314 @@
|
||||
/**
|
||||
* 작업장 관리 컨트롤러
|
||||
*
|
||||
* 작업장 카테고리(공장) 및 작업장 CRUD API 엔드포인트 핸들러
|
||||
*
|
||||
* @author TK-FB-Project
|
||||
* @since 2026-01-26
|
||||
*/
|
||||
|
||||
const workplaceModel = require('../models/workplaceModel');
|
||||
const { ValidationError, NotFoundError, DatabaseError } = require('../utils/errors');
|
||||
const { asyncHandler } = require('../middlewares/errorHandler');
|
||||
const logger = require('../utils/logger');
|
||||
|
||||
// ==================== 카테고리(공장) 관련 ====================
|
||||
|
||||
/**
|
||||
* 카테고리 생성
|
||||
*/
|
||||
exports.createCategory = asyncHandler(async (req, res) => {
|
||||
const categoryData = req.body;
|
||||
|
||||
if (!categoryData.category_name) {
|
||||
throw new ValidationError('카테고리명은 필수 입력 항목입니다');
|
||||
}
|
||||
|
||||
logger.info('카테고리 생성 요청', { name: categoryData.category_name });
|
||||
|
||||
const id = await new Promise((resolve, reject) => {
|
||||
workplaceModel.createCategory(categoryData, (err, lastID) => {
|
||||
if (err) reject(new DatabaseError('카테고리 생성 중 오류가 발생했습니다'));
|
||||
else resolve(lastID);
|
||||
});
|
||||
});
|
||||
|
||||
logger.info('카테고리 생성 성공', { category_id: id });
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
data: { category_id: id },
|
||||
message: '카테고리가 성공적으로 생성되었습니다'
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 전체 카테고리 조회
|
||||
*/
|
||||
exports.getAllCategories = asyncHandler(async (req, res) => {
|
||||
const rows = await new Promise((resolve, reject) => {
|
||||
workplaceModel.getAllCategories((err, data) => {
|
||||
if (err) reject(new DatabaseError('카테고리 목록 조회 중 오류가 발생했습니다'));
|
||||
else resolve(data);
|
||||
});
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: rows,
|
||||
message: '카테고리 목록 조회 성공'
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 활성 카테고리만 조회
|
||||
*/
|
||||
exports.getActiveCategories = asyncHandler(async (req, res) => {
|
||||
const rows = await new Promise((resolve, reject) => {
|
||||
workplaceModel.getActiveCategories((err, data) => {
|
||||
if (err) reject(new DatabaseError('활성 카테고리 목록 조회 중 오류가 발생했습니다'));
|
||||
else resolve(data);
|
||||
});
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: rows,
|
||||
message: '활성 카테고리 목록 조회 성공'
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 단일 카테고리 조회
|
||||
*/
|
||||
exports.getCategoryById = asyncHandler(async (req, res) => {
|
||||
const categoryId = req.params.id;
|
||||
|
||||
const category = await new Promise((resolve, reject) => {
|
||||
workplaceModel.getCategoryById(categoryId, (err, data) => {
|
||||
if (err) reject(new DatabaseError('카테고리 조회 중 오류가 발생했습니다'));
|
||||
else resolve(data);
|
||||
});
|
||||
});
|
||||
|
||||
if (!category) {
|
||||
throw new NotFoundError('카테고리를 찾을 수 없습니다');
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: category,
|
||||
message: '카테고리 조회 성공'
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 카테고리 수정
|
||||
*/
|
||||
exports.updateCategory = asyncHandler(async (req, res) => {
|
||||
const categoryId = req.params.id;
|
||||
const categoryData = req.body;
|
||||
|
||||
if (!categoryData.category_name) {
|
||||
throw new ValidationError('카테고리명은 필수 입력 항목입니다');
|
||||
}
|
||||
|
||||
logger.info('카테고리 수정 요청', { category_id: categoryId });
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
workplaceModel.updateCategory(categoryId, categoryData, (err, result) => {
|
||||
if (err) reject(new DatabaseError('카테고리 수정 중 오류가 발생했습니다'));
|
||||
else resolve(result);
|
||||
});
|
||||
});
|
||||
|
||||
logger.info('카테고리 수정 성공', { category_id: categoryId });
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '카테고리가 성공적으로 수정되었습니다'
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 카테고리 삭제
|
||||
*/
|
||||
exports.deleteCategory = asyncHandler(async (req, res) => {
|
||||
const categoryId = req.params.id;
|
||||
|
||||
logger.info('카테고리 삭제 요청', { category_id: categoryId });
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
workplaceModel.deleteCategory(categoryId, (err, result) => {
|
||||
if (err) reject(new DatabaseError('카테고리 삭제 중 오류가 발생했습니다'));
|
||||
else resolve(result);
|
||||
});
|
||||
});
|
||||
|
||||
logger.info('카테고리 삭제 성공', { category_id: categoryId });
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '카테고리가 성공적으로 삭제되었습니다'
|
||||
});
|
||||
});
|
||||
|
||||
// ==================== 작업장 관련 ====================
|
||||
|
||||
/**
|
||||
* 작업장 생성
|
||||
*/
|
||||
exports.createWorkplace = asyncHandler(async (req, res) => {
|
||||
const workplaceData = req.body;
|
||||
|
||||
if (!workplaceData.workplace_name) {
|
||||
throw new ValidationError('작업장명은 필수 입력 항목입니다');
|
||||
}
|
||||
|
||||
logger.info('작업장 생성 요청', { name: workplaceData.workplace_name });
|
||||
|
||||
const id = await new Promise((resolve, reject) => {
|
||||
workplaceModel.createWorkplace(workplaceData, (err, lastID) => {
|
||||
if (err) reject(new DatabaseError('작업장 생성 중 오류가 발생했습니다'));
|
||||
else resolve(lastID);
|
||||
});
|
||||
});
|
||||
|
||||
logger.info('작업장 생성 성공', { workplace_id: id });
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
data: { workplace_id: id },
|
||||
message: '작업장이 성공적으로 생성되었습니다'
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 전체 작업장 조회
|
||||
*/
|
||||
exports.getAllWorkplaces = asyncHandler(async (req, res) => {
|
||||
const categoryId = req.query.category_id;
|
||||
|
||||
// 카테고리별 필터링
|
||||
if (categoryId) {
|
||||
const rows = await new Promise((resolve, reject) => {
|
||||
workplaceModel.getWorkplacesByCategory(categoryId, (err, data) => {
|
||||
if (err) reject(new DatabaseError('작업장 목록 조회 중 오류가 발생했습니다'));
|
||||
else resolve(data);
|
||||
});
|
||||
});
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
data: rows,
|
||||
message: '작업장 목록 조회 성공'
|
||||
});
|
||||
}
|
||||
|
||||
// 전체 조회
|
||||
const rows = await new Promise((resolve, reject) => {
|
||||
workplaceModel.getAllWorkplaces((err, data) => {
|
||||
if (err) reject(new DatabaseError('작업장 목록 조회 중 오류가 발생했습니다'));
|
||||
else resolve(data);
|
||||
});
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: rows,
|
||||
message: '작업장 목록 조회 성공'
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 활성 작업장만 조회
|
||||
*/
|
||||
exports.getActiveWorkplaces = asyncHandler(async (req, res) => {
|
||||
const rows = await new Promise((resolve, reject) => {
|
||||
workplaceModel.getActiveWorkplaces((err, data) => {
|
||||
if (err) reject(new DatabaseError('활성 작업장 목록 조회 중 오류가 발생했습니다'));
|
||||
else resolve(data);
|
||||
});
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: rows,
|
||||
message: '활성 작업장 목록 조회 성공'
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 단일 작업장 조회
|
||||
*/
|
||||
exports.getWorkplaceById = asyncHandler(async (req, res) => {
|
||||
const workplaceId = req.params.id;
|
||||
|
||||
const workplace = await new Promise((resolve, reject) => {
|
||||
workplaceModel.getWorkplaceById(workplaceId, (err, data) => {
|
||||
if (err) reject(new DatabaseError('작업장 조회 중 오류가 발생했습니다'));
|
||||
else resolve(data);
|
||||
});
|
||||
});
|
||||
|
||||
if (!workplace) {
|
||||
throw new NotFoundError('작업장을 찾을 수 없습니다');
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: workplace,
|
||||
message: '작업장 조회 성공'
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 작업장 수정
|
||||
*/
|
||||
exports.updateWorkplace = asyncHandler(async (req, res) => {
|
||||
const workplaceId = req.params.id;
|
||||
const workplaceData = req.body;
|
||||
|
||||
if (!workplaceData.workplace_name) {
|
||||
throw new ValidationError('작업장명은 필수 입력 항목입니다');
|
||||
}
|
||||
|
||||
logger.info('작업장 수정 요청', { workplace_id: workplaceId });
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
workplaceModel.updateWorkplace(workplaceId, workplaceData, (err, result) => {
|
||||
if (err) reject(new DatabaseError('작업장 수정 중 오류가 발생했습니다'));
|
||||
else resolve(result);
|
||||
});
|
||||
});
|
||||
|
||||
logger.info('작업장 수정 성공', { workplace_id: workplaceId });
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '작업장이 성공적으로 수정되었습니다'
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 작업장 삭제
|
||||
*/
|
||||
exports.deleteWorkplace = asyncHandler(async (req, res) => {
|
||||
const workplaceId = req.params.id;
|
||||
|
||||
logger.info('작업장 삭제 요청', { workplace_id: workplaceId });
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
workplaceModel.deleteWorkplace(workplaceId, (err, result) => {
|
||||
if (err) reject(new DatabaseError('작업장 삭제 중 오류가 발생했습니다'));
|
||||
else resolve(result);
|
||||
});
|
||||
});
|
||||
|
||||
logger.info('작업장 삭제 성공', { workplace_id: workplaceId });
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '작업장이 성공적으로 삭제되었습니다'
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user