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>
This commit is contained in:
@@ -35,7 +35,7 @@ const getAllCategories = async (callback) => {
|
||||
try {
|
||||
const db = await getDb();
|
||||
const [rows] = await db.query(
|
||||
`SELECT category_id, category_name, description, display_order, is_active, created_at, updated_at
|
||||
`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`
|
||||
);
|
||||
@@ -52,7 +52,7 @@ const getActiveCategories = async (callback) => {
|
||||
try {
|
||||
const db = await getDb();
|
||||
const [rows] = await db.query(
|
||||
`SELECT category_id, category_name, description, display_order, is_active, created_at, updated_at
|
||||
`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`
|
||||
@@ -70,7 +70,7 @@ 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, created_at, updated_at
|
||||
`SELECT category_id, category_name, description, display_order, is_active, layout_image, created_at, updated_at
|
||||
FROM workplace_categories
|
||||
WHERE category_id = ?`,
|
||||
[categoryId]
|
||||
@@ -91,14 +91,15 @@ const updateCategory = async (categoryId, category, callback) => {
|
||||
category_name,
|
||||
description,
|
||||
display_order,
|
||||
is_active
|
||||
is_active,
|
||||
layout_image
|
||||
} = category;
|
||||
|
||||
const [result] = await db.query(
|
||||
`UPDATE workplace_categories
|
||||
SET category_name = ?, description = ?, display_order = ?, is_active = ?, updated_at = NOW()
|
||||
SET category_name = ?, description = ?, display_order = ?, is_active = ?, layout_image = ?, updated_at = NOW()
|
||||
WHERE category_id = ?`,
|
||||
[category_name, description, display_order, is_active, categoryId]
|
||||
[category_name, description, display_order, is_active, layout_image, categoryId]
|
||||
);
|
||||
|
||||
callback(null, result);
|
||||
@@ -135,14 +136,16 @@ const createWorkplace = async (workplace, callback) => {
|
||||
category_id = null,
|
||||
workplace_name,
|
||||
description = null,
|
||||
is_active = true
|
||||
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)
|
||||
VALUES (?, ?, ?, ?)`,
|
||||
[category_id, workplace_name, description, is_active]
|
||||
(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);
|
||||
@@ -158,12 +161,12 @@ 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.created_at, w.updated_at,
|
||||
`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.workplace_id DESC`
|
||||
ORDER BY wc.display_order ASC, w.display_priority ASC, w.workplace_id DESC`
|
||||
);
|
||||
callback(null, rows);
|
||||
} catch (err) {
|
||||
@@ -178,7 +181,7 @@ 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,
|
||||
`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
|
||||
@@ -199,7 +202,7 @@ 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,
|
||||
`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
|
||||
@@ -221,7 +224,7 @@ 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,
|
||||
`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
|
||||
@@ -245,14 +248,17 @@ const updateWorkplace = async (workplaceId, workplace, callback) => {
|
||||
category_id,
|
||||
workplace_name,
|
||||
description,
|
||||
is_active
|
||||
is_active,
|
||||
workplace_purpose,
|
||||
display_priority
|
||||
} = workplace;
|
||||
|
||||
const [result] = await db.query(
|
||||
`UPDATE workplaces
|
||||
SET category_id = ?, workplace_name = ?, description = ?, is_active = ?, updated_at = NOW()
|
||||
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, workplaceId]
|
||||
[category_id, workplace_name, description, is_active, workplace_purpose, display_priority, workplaceId]
|
||||
);
|
||||
|
||||
callback(null, result);
|
||||
@@ -277,6 +283,134 @@ const deleteWorkplace = async (workplaceId, callback) => {
|
||||
}
|
||||
};
|
||||
|
||||
// ==================== 작업장 지도 영역 관련 ====================
|
||||
|
||||
/**
|
||||
* 작업장 지도 영역 생성
|
||||
*/
|
||||
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,
|
||||
@@ -293,5 +427,13 @@ module.exports = {
|
||||
getWorkplacesByCategory,
|
||||
getWorkplaceById,
|
||||
updateWorkplace,
|
||||
deleteWorkplace
|
||||
deleteWorkplace,
|
||||
|
||||
// 지도 영역
|
||||
createMapRegion,
|
||||
getMapRegionsByCategory,
|
||||
getMapRegionByWorkplace,
|
||||
updateMapRegion,
|
||||
deleteMapRegion,
|
||||
deleteMapRegionsByCategory
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user