Files
TK-FB-Project/api.hyungi.net/utils/hangulToRoman.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

167 lines
4.5 KiB
JavaScript

/**
* 한글 이름을 영문(로마자)으로 변환하는 유틸리티
*
* 사용 예시:
* hangulToRoman('홍길동') => 'hong.gildong'
* hangulToRoman('김철수') => 'kim.cheolsu'
*/
// 한글 로마자 변환 매핑 (국립국어원 표기법 기준)
const CHOSUNG_MAP = {
'ㄱ': 'g', 'ㄲ': 'kk', 'ㄴ': 'n', 'ㄷ': 'd', 'ㄸ': 'tt',
'ㄹ': 'r', 'ㅁ': 'm', 'ㅂ': 'b', 'ㅃ': 'pp', 'ㅅ': 's',
'ㅆ': 'ss', 'ㅇ': '', 'ㅈ': 'j', 'ㅉ': 'jj', 'ㅊ': 'ch',
'ㅋ': 'k', 'ㅌ': 't', 'ㅍ': 'p', 'ㅎ': 'h'
};
const JUNGSUNG_MAP = {
'ㅏ': 'a', 'ㅐ': 'ae', 'ㅑ': 'ya', 'ㅒ': 'yae', 'ㅓ': 'eo',
'ㅔ': 'e', 'ㅕ': 'yeo', 'ㅖ': 'ye', 'ㅗ': 'o', 'ㅘ': 'wa',
'ㅙ': 'wae', 'ㅚ': 'oe', 'ㅛ': 'yo', 'ㅜ': 'u', 'ㅝ': 'wo',
'ㅞ': 'we', 'ㅟ': 'wi', 'ㅠ': 'yu', 'ㅡ': 'eu', 'ㅢ': 'ui',
'ㅣ': 'i'
};
const JONGSUNG_MAP = {
'': '', 'ㄱ': 'k', 'ㄲ': 'k', 'ㄳ': 'k', 'ㄴ': 'n', 'ㄵ': 'n',
'ㄶ': 'n', 'ㄷ': 't', 'ㄹ': 'l', 'ㄺ': 'k', 'ㄻ': 'm', 'ㄼ': 'p',
'ㄽ': 'l', 'ㄾ': 'l', 'ㄿ': 'p', 'ㅀ': 'l', 'ㅁ': 'm', 'ㅂ': 'p',
'ㅄ': 'p', 'ㅅ': 't', 'ㅆ': 't', 'ㅇ': 'ng', 'ㅈ': 't', 'ㅊ': 't',
'ㅋ': 'k', 'ㅌ': 't', 'ㅍ': 'p', 'ㅎ': 't'
};
const CHOSUNG = [
'ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ',
'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'
];
const JUNGSUNG = [
'ㅏ', 'ㅐ', 'ㅑ', 'ㅒ', 'ㅓ', 'ㅔ', 'ㅕ', 'ㅖ', 'ㅗ', 'ㅘ',
'ㅙ', 'ㅚ', 'ㅛ', 'ㅜ', 'ㅝ', 'ㅞ', 'ㅟ', 'ㅠ', 'ㅡ', 'ㅢ', 'ㅣ'
];
const JONGSUNG = [
'', 'ㄱ', 'ㄲ', 'ㄳ', 'ㄴ', 'ㄵ', 'ㄶ', 'ㄷ', 'ㄹ', 'ㄺ',
'ㄻ', 'ㄼ', 'ㄽ', 'ㄾ', 'ㄿ', 'ㅀ', 'ㅁ', 'ㅂ', 'ㅄ', 'ㅅ',
'ㅆ', 'ㅇ', 'ㅈ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'
];
/**
* 한글 한 글자를 초성, 중성, 종성으로 분리
* @param {string} char - 한글 한 글자
* @returns {object} { cho, jung, jong }
*/
function decomposeHangul(char) {
const code = char.charCodeAt(0) - 0xAC00;
if (code < 0 || code > 11171) {
return null; // 한글이 아님
}
const choIndex = Math.floor(code / 588);
const jungIndex = Math.floor((code % 588) / 28);
const jongIndex = code % 28;
return {
cho: CHOSUNG[choIndex],
jung: JUNGSUNG[jungIndex],
jong: JONGSUNG[jongIndex]
};
}
/**
* 한글 이름을 로마자로 변환
* @param {string} koreanName - 한글 이름
* @returns {string} 로마자 이름 (예: 'hong.gildong')
*/
function hangulToRoman(koreanName) {
if (!koreanName || typeof koreanName !== 'string') {
return '';
}
// 공백 제거
const trimmed = koreanName.trim();
// 성과 이름 분리 (첫 글자를 성으로 간주)
const surname = trimmed[0];
const givenName = trimmed.substring(1);
// 각 부분을 로마자로 변환
const romanSurname = convertToRoman(surname);
const romanGivenName = convertToRoman(givenName);
// 점(.)으로 연결
return `${romanSurname}.${romanGivenName}`.toLowerCase();
}
/**
* 한글 문자열을 로마자로 변환
* @param {string} text - 한글 문자열
* @returns {string} 로마자 문자열
*/
function convertToRoman(text) {
let result = '';
for (let i = 0; i < text.length; i++) {
const char = text[i];
const decomposed = decomposeHangul(char);
if (decomposed) {
result += CHOSUNG_MAP[decomposed.cho] || '';
result += JUNGSUNG_MAP[decomposed.jung] || '';
result += JONGSUNG_MAP[decomposed.jong] || '';
} else {
// 한글이 아닌 경우 그대로 추가
result += char;
}
}
return result;
}
/**
* 사용자명 생성 (중복 확인 및 처리)
* @param {string} koreanName - 한글 이름
* @param {object} db - Database connection (mysql2 pool or knex)
* @returns {Promise<string>} 고유한 username
*/
async function generateUniqueUsername(koreanName, db) {
const baseUsername = hangulToRoman(koreanName);
let username = baseUsername;
let counter = 1;
// 중복 확인
while (true) {
let existing;
// mysql2 pool 또는 knex 모두 지원
if (typeof db === 'function') {
// Knex
existing = await db('users')
.where('username', username)
.first();
} else {
// mysql2 pool
const [rows] = await db.query('SELECT username FROM users WHERE username = ?', [username]);
existing = rows[0];
}
if (!existing) {
break; // 중복 없음
}
// 중복 시 숫자 추가
username = `${baseUsername}${counter}`;
counter++;
}
return username;
}
module.exports = {
hangulToRoman,
convertToRoman,
generateUniqueUsername,
decomposeHangul
};