Files
tk-factory-services/user-management/api/models/equipmentModel.js
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

193 lines
8.0 KiB
JavaScript

/**
* Equipment Model
*
* equipments + equipment_photos CRUD (MariaDB)
*/
const { getPool } = require('./userModel');
// ==================== 기본 CRUD ====================
async function getAll(filters = {}) {
const db = getPool();
let sql = `SELECT e.*, w.workplace_name, c.category_name
FROM equipments e
LEFT JOIN workplaces w ON e.workplace_id = w.workplace_id
LEFT JOIN workplace_categories c ON w.category_id = c.category_id`;
const conditions = [];
const values = [];
if (filters.workplace_id) { conditions.push('e.workplace_id = ?'); values.push(filters.workplace_id); }
if (filters.equipment_type) { conditions.push('e.equipment_type = ?'); values.push(filters.equipment_type); }
if (filters.status) { conditions.push('e.status = ?'); values.push(filters.status); }
if (filters.search) {
conditions.push('(e.equipment_name LIKE ? OR e.equipment_code LIKE ?)');
const term = `%${filters.search}%`;
values.push(term, term);
}
if (conditions.length) sql += ' WHERE ' + conditions.join(' AND ');
sql += ' ORDER BY e.equipment_code ASC';
const [rows] = await db.query(sql, values);
return rows;
}
async function getById(id) {
const db = getPool();
const [rows] = await db.query(
`SELECT e.*, w.workplace_name, c.category_name
FROM equipments e
LEFT JOIN workplaces w ON e.workplace_id = w.workplace_id
LEFT JOIN workplace_categories c ON w.category_id = c.category_id
WHERE e.equipment_id = ?`,
[id]
);
return rows[0] || null;
}
async function getByWorkplace(workplaceId) {
const db = getPool();
const [rows] = await db.query(
`SELECT e.*, w.workplace_name
FROM equipments e
LEFT JOIN workplaces w ON e.workplace_id = w.workplace_id
WHERE e.workplace_id = ?
ORDER BY e.equipment_code ASC`,
[workplaceId]
);
return rows;
}
async function create(data) {
const db = getPool();
const [result] = await db.query(
`INSERT INTO equipments (equipment_code, equipment_name, equipment_type, model_name, manufacturer, supplier, purchase_price, installation_date, serial_number, specifications, status, notes, workplace_id, map_x_percent, map_y_percent, map_width_percent, map_height_percent)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[
data.equipment_code, data.equipment_name,
data.equipment_type || null, data.model_name || null,
data.manufacturer || null, data.supplier || null,
data.purchase_price || null, data.installation_date || null,
data.serial_number || null, data.specifications || null,
data.status || 'active', data.notes || null,
data.workplace_id || null,
data.map_x_percent || null, data.map_y_percent || null,
data.map_width_percent || null, data.map_height_percent || null
]
);
return getById(result.insertId);
}
async function update(id, data) {
const db = getPool();
const fields = [];
const values = [];
if (data.equipment_code !== undefined) { fields.push('equipment_code = ?'); values.push(data.equipment_code); }
if (data.equipment_name !== undefined) { fields.push('equipment_name = ?'); values.push(data.equipment_name); }
if (data.equipment_type !== undefined) { fields.push('equipment_type = ?'); values.push(data.equipment_type || null); }
if (data.model_name !== undefined) { fields.push('model_name = ?'); values.push(data.model_name || null); }
if (data.manufacturer !== undefined) { fields.push('manufacturer = ?'); values.push(data.manufacturer || null); }
if (data.supplier !== undefined) { fields.push('supplier = ?'); values.push(data.supplier || null); }
if (data.purchase_price !== undefined) { fields.push('purchase_price = ?'); values.push(data.purchase_price || null); }
if (data.installation_date !== undefined) { fields.push('installation_date = ?'); values.push(data.installation_date || null); }
if (data.serial_number !== undefined) { fields.push('serial_number = ?'); values.push(data.serial_number || null); }
if (data.specifications !== undefined) { fields.push('specifications = ?'); values.push(data.specifications || null); }
if (data.status !== undefined) { fields.push('status = ?'); values.push(data.status); }
if (data.notes !== undefined) { fields.push('notes = ?'); values.push(data.notes || null); }
if (data.workplace_id !== undefined) { fields.push('workplace_id = ?'); values.push(data.workplace_id || null); }
if (data.map_x_percent !== undefined) { fields.push('map_x_percent = ?'); values.push(data.map_x_percent); }
if (data.map_y_percent !== undefined) { fields.push('map_y_percent = ?'); values.push(data.map_y_percent); }
if (data.map_width_percent !== undefined) { fields.push('map_width_percent = ?'); values.push(data.map_width_percent); }
if (data.map_height_percent !== undefined) { fields.push('map_height_percent = ?'); values.push(data.map_height_percent); }
if (fields.length === 0) return getById(id);
values.push(id);
await db.query(`UPDATE equipments SET ${fields.join(', ')} WHERE equipment_id = ?`, values);
return getById(id);
}
async function remove(id) {
const db = getPool();
await db.query('DELETE FROM equipments WHERE equipment_id = ?', [id]);
}
async function getEquipmentTypes() {
const db = getPool();
const [rows] = await db.query(
'SELECT DISTINCT equipment_type FROM equipments WHERE equipment_type IS NOT NULL AND equipment_type != "" ORDER BY equipment_type ASC'
);
return rows.map(r => r.equipment_type);
}
async function getNextCode(prefix = 'TKP') {
const db = getPool();
const [rows] = await db.query(
'SELECT equipment_code FROM equipments WHERE equipment_code LIKE ? ORDER BY equipment_code DESC LIMIT 1',
[`${prefix}-%`]
);
if (!rows.length) return `${prefix}-001`;
const lastNum = parseInt(rows[0].equipment_code.replace(`${prefix}-`, ''), 10) || 0;
return `${prefix}-${String(lastNum + 1).padStart(3, '0')}`;
}
async function checkDuplicateCode(code, excludeId) {
const db = getPool();
let sql = 'SELECT equipment_id FROM equipments WHERE equipment_code = ?';
const values = [code];
if (excludeId) { sql += ' AND equipment_id != ?'; values.push(excludeId); }
const [rows] = await db.query(sql, values);
return rows.length > 0;
}
// ==================== 지도 위치 ====================
async function updateMapPosition(id, positionData) {
const db = getPool();
const fields = ['map_x_percent = ?', 'map_y_percent = ?', 'map_width_percent = ?', 'map_height_percent = ?'];
const values = [positionData.map_x_percent, positionData.map_y_percent, positionData.map_width_percent, positionData.map_height_percent];
if (positionData.workplace_id !== undefined) {
fields.push('workplace_id = ?');
values.push(positionData.workplace_id);
}
values.push(id);
await db.query(`UPDATE equipments SET ${fields.join(', ')} WHERE equipment_id = ?`, values);
return getById(id);
}
// ==================== 사진 ====================
async function addPhoto(equipmentId, photoData) {
const db = getPool();
const [result] = await db.query(
`INSERT INTO equipment_photos (equipment_id, photo_path, description, display_order, uploaded_by) VALUES (?, ?, ?, ?, ?)`,
[equipmentId, photoData.photo_path, photoData.description || null, photoData.display_order || 0, photoData.uploaded_by || null]
);
return { photo_id: result.insertId, equipment_id: equipmentId, ...photoData };
}
async function getPhotos(equipmentId) {
const db = getPool();
const [rows] = await db.query(
'SELECT * FROM equipment_photos WHERE equipment_id = ? ORDER BY display_order ASC, created_at ASC',
[equipmentId]
);
return rows;
}
async function deletePhoto(photoId) {
const db = getPool();
const [photo] = await db.query('SELECT photo_path FROM equipment_photos WHERE photo_id = ?', [photoId]);
await db.query('DELETE FROM equipment_photos WHERE photo_id = ?', [photoId]);
return { photo_id: photoId, photo_path: photo[0]?.photo_path };
}
module.exports = {
getAll, getById, getByWorkplace, create, update, remove,
getEquipmentTypes, getNextCode, checkDuplicateCode,
updateMapPosition,
addPhoto, getPhotos, deletePhoto
};