Files
HMDesign/examples/org-chart/create-p1-fixture.mjs

57 lines
4.3 KiB
JavaScript

import { writeFile } from 'node:fs/promises';
// Organization names were observed on Workdesk. Membership, employees and
// every count below are synthetic, not an export of production HR data.
const groups = [
['business-management', '사업관리', 'office', []],
['business-planning', '경영기획', 'office', ['경영기획 셀', '사업관리 셀']],
['talent-growth', '인재성장', 'office', ['HR기획 셀', '자산관리 셀']],
['integrated-system', '통합시스템 Div', 'div', ['IS 1팀', 'IS 2팀', 'IS 3팀']],
['design-planning', '디자인기획', 'office', ['UX 셀', '영상 셀', '편집 셀']],
['solution-sales', '솔루션영업', 'office', ['S/W 셀']],
];
const affiliations = [
['hanmac', '(주)한맥기술'], ['saman', '(주)삼안'], ['jangheon', '(주)장헌'],
['jangheon-industry', '장헌산업'], ['ptc', 'PTC'], ['halla', '한라산업개발'], ['baron', '바론컨설턴트'],
].map(([id, name]) => ({ id, name }));
const organizations = [{ id: 'general-planning', parentId: null, name: '총괄기획실', type: 'root', leaderId: 'mock-leader-00', displayOrder: 0 }];
// Invented display names only; never sourced from a Workdesk employee capture.
const names = [
'김솔', '이도윤', '박하준', '정지우', '최예린', '한준서', '오수아',
'강민서', '윤시우', '서다은', '배지안', '임서준', '송하린', '조유찬',
'신도하', '문예은', '권지호', '안채원', '유시온', '홍서아', '고은우',
'남하윤', '백도현', '노유나', '장태오', '양서진', '진서율', '구민재',
'전하은', '심이준', '차소율', '우지율', '손예준', '함다온', '허지유',
'황서우', '성유빈', '곽지후', '류다인', '하주원', '이봄',
];
const employees = [{ id: 'mock-leader-00', organizationId: 'general-planning', affiliationId: 'hanmac', name: names[0], position: '경영진', jobTitle: '실장', profileImage: null, workStatus: 'active' }];
let person = 1;
for (const [index, [id, name, type, cells]] of groups.entries()) {
const leaderId = `mock-leader-${String(index + 1).padStart(2, '0')}`;
organizations.push({ id, parentId: 'general-planning', name, type, leaderId, displayOrder: index });
employees.push({ id: leaderId, organizationId: id, affiliationId: ['hanmac', 'saman', 'baron'][index % 3], name: names[employees.length], position: '수석', jobTitle: type === 'div' ? '디비전장' : '팀장', profileImage: null, workStatus: 'active' });
const employeeOrganizations = cells.length ? cells.map((cell, cellIndex) => {
const childId = `${id}-${cellIndex + 1}`;
organizations.push({ id: childId, parentId: id, name: cell, type: cell.includes('팀') ? 'team' : 'cell', leaderId: null, displayOrder: cellIndex });
return childId;
}) : [id];
for (const childId of employeeOrganizations) for (let member = 0; member < (cells.length ? 3 : 1); member++) {
const employeeId = `mock-employee-${String(person).padStart(2, '0')}`;
const isTeamLeader = childId.startsWith('integrated-system-') && member === 0;
employees.push({ id: employeeId, organizationId: childId, affiliationId: ['hanmac', 'saman', 'ptc', 'baron'][person % 4], name: names[employees.length], position: ['책임', '선임', '연구'][member % 3], jobTitle: isTeamLeader ? '팀장' : null, profileImage: null, workStatus: person === 3 ? 'dispatched' : person === 25 ? 'onLeave' : 'active' });
if (isTeamLeader) organizations.find(item => item.id === childId).leaderId = employeeId;
person++;
}
}
const fixture = {
schemaVersion: '0.1-draft', organizations, employees, affiliations, relations: [],
presentation: {
title: '총괄기획실 조직도', description: '실제 조직명 · 가상 직원 정보 및 인원 통계 · 운영 인원수가 아닙니다.', hubText: '협업 · 소통 허브',
groups: { showEmployees: true, showSummary: true, showDispatched: true, showOnLeave: true, showAffiliations: true },
organizationOrder: ['general-planning', ...groups.map(([id]) => id)],
},
metadata: { asOfDate: '2026-10-12', dataVersion: 'p1-virtual-employees-v1', updateNote: '운영 HR 정보와 무관한 가상 구성' },
};
await writeFile(new URL('./data-p1.json', import.meta.url), `${JSON.stringify(fixture, null, 2)}\n`);
console.log(`P1 fixture: ${organizations.length} organizations / ${employees.length} synthetic employees`);