Files
HMDesign/examples/org-chart/create-expanded-fixtures.mjs

51 lines
3.6 KiB
JavaScript

import fs from 'node:fs/promises';
const companies = [
['hanmac', '한맥기술', '회장'], ['saman', '삼안', '사업총괄'], ['jangheon-industry', '장헌산업', '본부장'],
['jangheon', '장헌', '대표이사'], ['ptc', '피티씨', '총괄책임자'], ['halla', '한라산업개발', '사장'], ['baron', '바론컨설턴트', null],
];
for (const [size, count, companyCount, depth] of [['small', 20, 3, 2], ['medium', 100, 5, 3], ['large', 300, 7, 4]]) {
const organizations = [], employees = [], affiliations = [];
const addEmployee = (org, position, name) => {
const id = `virtual-${String(employees.length + 1).padStart(3, '0')}`;
employees.push({ id, organizationId: org.id, affiliationId: org.companyId, name: name ?? (employees.length === 5 ? '홍길동' : `가상직원 ${String(employees.length + 1).padStart(3, '0')}`), position, jobTitle: null, profileImage: null, workStatus: 'active' });
return id;
};
for (const [index, [companyId, companyName, position]] of companies.slice(0, companyCount).entries()) {
affiliations.push({ id: companyId, name: companyName });
const org = (suffix, parentId, name, type, order) => {
const node = { id: `${companyId}-${suffix}`, companyId, parentId, name, type, leaderId: null, displayOrder: order };
organizations.push(node); return node;
};
const root = org('root', null, `${companyName} · 가상 조직`, 'root', index);
if (position) root.leaderId = addEmployee(root, position, `가상책임자 ${index + 1}`);
for (let branch = 0; branch < 2; branch++) {
const division = org(`division-${branch}`, root.id, `가상 ${branch ? '지원' : '사업'}본부`, 'division', branch);
if (count > 20) division.leaderId = addEmployee(division, '본부장');
const office = org(`office-${branch}`, division.id, `가상 ${branch + 1}실`, 'office', 0);
if (depth >= 3) {
// Keep record order/IDs and weighted employee placement stable. Large
// examples use office -> team -> cell; no team may descend from a cell.
org(`cell-${branch}`, depth >= 4 ? `${companyId}-team-${branch}` : office.id, `가상 ${branch + 1}셀`, 'cell', 0);
if (depth >= 4) {
org(`team-${branch}`, office.id, `가상 ${branch + 1}팀`, 'team', 0);
if (branch === 0) org('team-sibling', office.id, '가상 협력팀', 'team', 1);
}
}
if (count > 20 && branch === 0) org('office-sibling', division.id, '가상 계획실', 'office', 1);
}
}
// Unequal groups: deterministic weighted membership; no random or live data.
const pool = organizations.filter(org => org.parentId !== null);
const weighted = pool.flatMap((org, index) => Array.from({ length: 1 + index % 4 }, () => org));
let cursor = 0;
while (employees.length < count) {
const org = weighted[cursor++ % weighted.length];
addEmployee(org, ['사원', '선임', '책임', '수석'][cursor % 4]);
}
const data = { schemaVersion: '0.1-draft', organizations, employees, affiliations, relations: [],
presentation: { title: '확장형 조직도 · 가상 데이터', description: '실제 직원 정보가 아닌 고정된 테스트 데이터입니다.', hubText: null,
groups: { showEmployees: true, showSummary: false, showDispatched: false, showOnLeave: false, showAffiliations: false }, organizationOrder: [] },
metadata: { asOfDate: '2026-10-12', dataVersion: `p5-23-${size}-${count}`, updateNote: '가상 데이터 · 운영 정보 아님' } };
await fs.writeFile(new URL(`./data-expanded-${size}.json`, import.meta.url), JSON.stringify(data, null, 2) + '\n');
}