- 일일순회점검 시스템 신규 구현 - 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>
441 lines
11 KiB
JavaScript
441 lines
11 KiB
JavaScript
const { getDb } = require('../dbPool');
|
|
|
|
// ==================== 카테고리(공장) 관련 ====================
|
|
|
|
/**
|
|
* 카테고리 생성
|
|
*/
|
|
const createCategory = async (category, callback) => {
|
|
try {
|
|
const db = await getDb();
|
|
const {
|
|
category_name,
|
|
description = null,
|
|
display_order = 0,
|
|
is_active = true
|
|
} = category;
|
|
|
|
const [result] = await db.query(
|
|
`INSERT INTO workplace_categories
|
|
(category_name, description, display_order, is_active)
|
|
VALUES (?, ?, ?, ?)`,
|
|
[category_name, description, display_order, is_active]
|
|
);
|
|
|
|
callback(null, result.insertId);
|
|
} catch (err) {
|
|
callback(err);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 모든 카테고리 조회
|
|
*/
|
|
const getAllCategories = async (callback) => {
|
|
try {
|
|
const db = await getDb();
|
|
const [rows] = await db.query(
|
|
`SELECT category_id, category_name, description, display_order, is_active, layout_image, created_at, updated_at
|
|
FROM workplace_categories
|
|
ORDER BY display_order ASC, category_id ASC`
|
|
);
|
|
callback(null, rows);
|
|
} catch (err) {
|
|
callback(err);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 활성 카테고리만 조회
|
|
*/
|
|
const getActiveCategories = async (callback) => {
|
|
try {
|
|
const db = await getDb();
|
|
const [rows] = await db.query(
|
|
`SELECT category_id, category_name, description, display_order, is_active, layout_image, created_at, updated_at
|
|
FROM workplace_categories
|
|
WHERE is_active = TRUE
|
|
ORDER BY display_order ASC, category_id ASC`
|
|
);
|
|
callback(null, rows);
|
|
} catch (err) {
|
|
callback(err);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* ID로 카테고리 조회
|
|
*/
|
|
const getCategoryById = async (categoryId, callback) => {
|
|
try {
|
|
const db = await getDb();
|
|
const [rows] = await db.query(
|
|
`SELECT category_id, category_name, description, display_order, is_active, layout_image, created_at, updated_at
|
|
FROM workplace_categories
|
|
WHERE category_id = ?`,
|
|
[categoryId]
|
|
);
|
|
callback(null, rows[0]);
|
|
} catch (err) {
|
|
callback(err);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 카테고리 수정
|
|
*/
|
|
const updateCategory = async (categoryId, category, callback) => {
|
|
try {
|
|
const db = await getDb();
|
|
const {
|
|
category_name,
|
|
description,
|
|
display_order,
|
|
is_active,
|
|
layout_image
|
|
} = category;
|
|
|
|
const [result] = await db.query(
|
|
`UPDATE workplace_categories
|
|
SET category_name = ?, description = ?, display_order = ?, is_active = ?, layout_image = ?, updated_at = NOW()
|
|
WHERE category_id = ?`,
|
|
[category_name, description, display_order, is_active, layout_image, categoryId]
|
|
);
|
|
|
|
callback(null, result);
|
|
} catch (err) {
|
|
callback(err);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 카테고리 삭제
|
|
*/
|
|
const deleteCategory = async (categoryId, callback) => {
|
|
try {
|
|
const db = await getDb();
|
|
const [result] = await db.query(
|
|
`DELETE FROM workplace_categories WHERE category_id = ?`,
|
|
[categoryId]
|
|
);
|
|
callback(null, result);
|
|
} catch (err) {
|
|
callback(err);
|
|
}
|
|
};
|
|
|
|
// ==================== 작업장 관련 ====================
|
|
|
|
/**
|
|
* 작업장 생성
|
|
*/
|
|
const createWorkplace = async (workplace, callback) => {
|
|
try {
|
|
const db = await getDb();
|
|
const {
|
|
category_id = null,
|
|
workplace_name,
|
|
description = null,
|
|
is_active = true,
|
|
workplace_purpose = null,
|
|
display_priority = 0
|
|
} = workplace;
|
|
|
|
const [result] = await db.query(
|
|
`INSERT INTO workplaces
|
|
(category_id, workplace_name, description, is_active, workplace_purpose, display_priority)
|
|
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
[category_id, workplace_name, description, is_active, workplace_purpose, display_priority]
|
|
);
|
|
|
|
callback(null, result.insertId);
|
|
} catch (err) {
|
|
callback(err);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 모든 작업장 조회 (카테고리 정보 포함)
|
|
*/
|
|
const getAllWorkplaces = async (callback) => {
|
|
try {
|
|
const db = await getDb();
|
|
const [rows] = await db.query(
|
|
`SELECT w.workplace_id, w.category_id, w.workplace_name, w.description, w.is_active, w.workplace_purpose, w.display_priority,
|
|
w.layout_image, w.created_at, w.updated_at,
|
|
wc.category_name
|
|
FROM workplaces w
|
|
LEFT JOIN workplace_categories wc ON w.category_id = wc.category_id
|
|
ORDER BY wc.display_order ASC, w.display_priority ASC, w.workplace_id DESC`
|
|
);
|
|
callback(null, rows);
|
|
} catch (err) {
|
|
callback(err);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 활성 작업장만 조회
|
|
*/
|
|
const getActiveWorkplaces = async (callback) => {
|
|
try {
|
|
const db = await getDb();
|
|
const [rows] = await db.query(
|
|
`SELECT w.workplace_id, w.category_id, w.workplace_name, w.description, w.is_active, w.workplace_purpose, w.display_priority,
|
|
w.layout_image, w.created_at, w.updated_at,
|
|
wc.category_name
|
|
FROM workplaces w
|
|
LEFT JOIN workplace_categories wc ON w.category_id = wc.category_id
|
|
WHERE w.is_active = TRUE
|
|
ORDER BY wc.display_order ASC, w.workplace_id DESC`
|
|
);
|
|
callback(null, rows);
|
|
} catch (err) {
|
|
callback(err);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 카테고리별 작업장 조회
|
|
*/
|
|
const getWorkplacesByCategory = async (categoryId, callback) => {
|
|
try {
|
|
const db = await getDb();
|
|
const [rows] = await db.query(
|
|
`SELECT w.workplace_id, w.category_id, w.workplace_name, w.description, w.is_active, w.workplace_purpose, w.display_priority,
|
|
w.layout_image, w.created_at, w.updated_at,
|
|
wc.category_name
|
|
FROM workplaces w
|
|
LEFT JOIN workplace_categories wc ON w.category_id = wc.category_id
|
|
WHERE w.category_id = ?
|
|
ORDER BY w.workplace_id DESC`,
|
|
[categoryId]
|
|
);
|
|
callback(null, rows);
|
|
} catch (err) {
|
|
callback(err);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* ID로 작업장 조회
|
|
*/
|
|
const getWorkplaceById = async (workplaceId, callback) => {
|
|
try {
|
|
const db = await getDb();
|
|
const [rows] = await db.query(
|
|
`SELECT w.workplace_id, w.category_id, w.workplace_name, w.description, w.is_active, w.workplace_purpose, w.display_priority,
|
|
w.layout_image, w.created_at, w.updated_at,
|
|
wc.category_name
|
|
FROM workplaces w
|
|
LEFT JOIN workplace_categories wc ON w.category_id = wc.category_id
|
|
WHERE w.workplace_id = ?`,
|
|
[workplaceId]
|
|
);
|
|
callback(null, rows[0]);
|
|
} catch (err) {
|
|
callback(err);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 작업장 수정
|
|
*/
|
|
const updateWorkplace = async (workplaceId, workplace, callback) => {
|
|
try {
|
|
const db = await getDb();
|
|
const {
|
|
category_id,
|
|
workplace_name,
|
|
description,
|
|
is_active,
|
|
workplace_purpose,
|
|
display_priority,
|
|
layout_image
|
|
} = workplace;
|
|
|
|
const [result] = await db.query(
|
|
`UPDATE workplaces
|
|
SET category_id = ?, workplace_name = ?, description = ?, is_active = ?,
|
|
workplace_purpose = ?, display_priority = ?, layout_image = ?, updated_at = NOW()
|
|
WHERE workplace_id = ?`,
|
|
[category_id, workplace_name, description, is_active, workplace_purpose, display_priority, layout_image, workplaceId]
|
|
);
|
|
|
|
callback(null, result);
|
|
} catch (err) {
|
|
callback(err);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 작업장 삭제
|
|
*/
|
|
const deleteWorkplace = async (workplaceId, callback) => {
|
|
try {
|
|
const db = await getDb();
|
|
const [result] = await db.query(
|
|
`DELETE FROM workplaces WHERE workplace_id = ?`,
|
|
[workplaceId]
|
|
);
|
|
callback(null, result);
|
|
} catch (err) {
|
|
callback(err);
|
|
}
|
|
};
|
|
|
|
// ==================== 작업장 지도 영역 관련 ====================
|
|
|
|
/**
|
|
* 작업장 지도 영역 생성
|
|
*/
|
|
const createMapRegion = async (region, callback) => {
|
|
try {
|
|
const db = await getDb();
|
|
const {
|
|
workplace_id,
|
|
category_id,
|
|
x_start,
|
|
y_start,
|
|
x_end,
|
|
y_end,
|
|
shape = 'rect',
|
|
polygon_points = null
|
|
} = region;
|
|
|
|
const [result] = await db.query(
|
|
`INSERT INTO workplace_map_regions
|
|
(workplace_id, category_id, x_start, y_start, x_end, y_end, shape, polygon_points)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
[workplace_id, category_id, x_start, y_start, x_end, y_end, shape, polygon_points]
|
|
);
|
|
|
|
callback(null, result.insertId);
|
|
} catch (err) {
|
|
callback(err);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 카테고리(공장)별 지도 영역 조회
|
|
*/
|
|
const getMapRegionsByCategory = async (categoryId, callback) => {
|
|
try {
|
|
const db = await getDb();
|
|
const [rows] = await db.query(
|
|
`SELECT mr.*, w.workplace_name, w.description
|
|
FROM workplace_map_regions mr
|
|
INNER JOIN workplaces w ON mr.workplace_id = w.workplace_id
|
|
WHERE mr.category_id = ? AND w.is_active = TRUE
|
|
ORDER BY mr.region_id ASC`,
|
|
[categoryId]
|
|
);
|
|
callback(null, rows);
|
|
} catch (err) {
|
|
callback(err);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 작업장별 지도 영역 조회
|
|
*/
|
|
const getMapRegionByWorkplace = async (workplaceId, callback) => {
|
|
try {
|
|
const db = await getDb();
|
|
const [rows] = await db.query(
|
|
`SELECT * FROM workplace_map_regions WHERE workplace_id = ?`,
|
|
[workplaceId]
|
|
);
|
|
callback(null, rows[0]);
|
|
} catch (err) {
|
|
callback(err);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 지도 영역 수정
|
|
*/
|
|
const updateMapRegion = async (regionId, region, callback) => {
|
|
try {
|
|
const db = await getDb();
|
|
const {
|
|
x_start,
|
|
y_start,
|
|
x_end,
|
|
y_end,
|
|
shape,
|
|
polygon_points
|
|
} = region;
|
|
|
|
const [result] = await db.query(
|
|
`UPDATE workplace_map_regions
|
|
SET x_start = ?, y_start = ?, x_end = ?, y_end = ?, shape = ?, polygon_points = ?, updated_at = NOW()
|
|
WHERE region_id = ?`,
|
|
[x_start, y_start, x_end, y_end, shape, polygon_points, regionId]
|
|
);
|
|
|
|
callback(null, result);
|
|
} catch (err) {
|
|
callback(err);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 지도 영역 삭제
|
|
*/
|
|
const deleteMapRegion = async (regionId, callback) => {
|
|
try {
|
|
const db = await getDb();
|
|
const [result] = await db.query(
|
|
`DELETE FROM workplace_map_regions WHERE region_id = ?`,
|
|
[regionId]
|
|
);
|
|
callback(null, result);
|
|
} catch (err) {
|
|
callback(err);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 작업장 영역 일괄 삭제 (카테고리별)
|
|
*/
|
|
const deleteMapRegionsByCategory = async (categoryId, callback) => {
|
|
try {
|
|
const db = await getDb();
|
|
const [result] = await db.query(
|
|
`DELETE FROM workplace_map_regions WHERE category_id = ?`,
|
|
[categoryId]
|
|
);
|
|
callback(null, result);
|
|
} catch (err) {
|
|
callback(err);
|
|
}
|
|
};
|
|
|
|
module.exports = {
|
|
// 카테고리
|
|
createCategory,
|
|
getAllCategories,
|
|
getActiveCategories,
|
|
getCategoryById,
|
|
updateCategory,
|
|
deleteCategory,
|
|
|
|
// 작업장
|
|
createWorkplace,
|
|
getAllWorkplaces,
|
|
getActiveWorkplaces,
|
|
getWorkplacesByCategory,
|
|
getWorkplaceById,
|
|
updateWorkplace,
|
|
deleteWorkplace,
|
|
|
|
// 지도 영역
|
|
createMapRegion,
|
|
getMapRegionsByCategory,
|
|
getMapRegionByWorkplace,
|
|
updateMapRegion,
|
|
deleteMapRegion,
|
|
deleteMapRegionsByCategory
|
|
};
|