Files
TK-FB-Project/api.hyungi.net/models/workplaceModel.js
Hyungi Ahn b6485e3140 feat: 대시보드 작업장 현황 지도 구현
- 실시간 작업장 현황을 지도로 시각화
- 작업장 관리 페이지에서 정의한 구역 정보 활용
- TBM 작업자 및 방문자 현황 표시

주요 변경사항:
- dashboard.html: 작업장 현황 섹션 추가 (기존 작업 현황 테이블 제거)
- workplace-status.js: 지도 렌더링 및 데이터 통합 로직 구현
- modern-dashboard.js: 삭제된 DOM 요소 조건부 체크 추가

시각화 방식:
- 인원 없음: 회색 테두리 + 작업장 이름
- 내부 작업자: 파란색 영역 + 인원 수
- 외부 방문자: 보라색 영역 + 인원 수
- 둘 다: 초록색 영역 + 총 인원 수

기술 구현:
- Canvas API 기반 사각형 영역 렌더링
- map-regions API를 통한 데이터 일관성 보장
- 클릭 이벤트로 상세 정보 모달 표시

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-29 15:46:47 +09:00

440 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.workplace_purpose, w.display_priority, 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.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.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.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
} = workplace;
const [result] = await db.query(
`UPDATE workplaces
SET category_id = ?, workplace_name = ?, description = ?, is_active = ?,
workplace_purpose = ?, display_priority = ?, updated_at = NOW()
WHERE workplace_id = ?`,
[category_id, workplace_name, description, is_active, workplace_purpose, display_priority, 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
};