@dssp/dkpi 1.0.0-alpha.65 → 1.0.0-alpha.67

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/_index.html +0 -5
  2. package/dist-client/components/kpi-2d-lookup-chart.d.ts +63 -0
  3. package/dist-client/components/kpi-2d-lookup-chart.js +470 -0
  4. package/dist-client/components/kpi-2d-lookup-chart.js.map +1 -0
  5. package/dist-client/google-map/common-google-map.js +10 -8
  6. package/dist-client/google-map/common-google-map.js.map +1 -1
  7. package/dist-client/pages/kpi-admin/dssp-kpi-list-page.d.ts +22 -0
  8. package/dist-client/pages/kpi-admin/dssp-kpi-list-page.js +57 -0
  9. package/dist-client/pages/kpi-admin/dssp-kpi-list-page.js.map +1 -0
  10. package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.d.ts +20 -0
  11. package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.js +445 -0
  12. package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.js.map +1 -0
  13. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.d.ts +6 -5
  14. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js +47 -68
  15. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js.map +1 -1
  16. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.d.ts +3 -2
  17. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js +79 -122
  18. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js.map +1 -1
  19. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.d.ts +3 -2
  20. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js +71 -107
  21. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js.map +1 -1
  22. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.d.ts +4 -0
  23. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js +246 -28
  24. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js.map +1 -1
  25. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.d.ts +4 -0
  26. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js +22 -207
  27. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js.map +1 -1
  28. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.d.ts +2 -0
  29. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js +84 -25
  30. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js.map +1 -1
  31. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.d.ts +16 -0
  32. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js +261 -31
  33. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js.map +1 -1
  34. package/dist-client/pages/kpi-dashboard/kpi-dashboard.d.ts +4 -0
  35. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js +66 -4
  36. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js.map +1 -1
  37. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.d.ts +1 -2
  38. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js +1 -2
  39. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js.map +1 -1
  40. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.d.ts +1 -2
  41. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js +1 -2
  42. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js.map +1 -1
  43. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.d.ts +1 -2
  44. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js +1 -2
  45. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js.map +1 -1
  46. package/dist-client/pages/kpi-value/kpi-value-list-page.d.ts +1 -2
  47. package/dist-client/pages/kpi-value/kpi-value-list-page.js +1 -2
  48. package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -1
  49. package/dist-client/pages/sv-project-detail.d.ts +1 -0
  50. package/dist-client/pages/sv-project-detail.js +26 -13
  51. package/dist-client/pages/sv-project-detail.js.map +1 -1
  52. package/dist-client/pages/sv-project-list.js +6 -6
  53. package/dist-client/pages/sv-project-list.js.map +1 -1
  54. package/dist-client/route.d.ts +1 -1
  55. package/dist-client/route.js +4 -0
  56. package/dist-client/route.js.map +1 -1
  57. package/dist-client/tsconfig.tsbuildinfo +1 -1
  58. package/dist-client/viewparts/menu-tools.d.ts +1 -2
  59. package/dist-client/viewparts/menu-tools.js +1 -2
  60. package/dist-client/viewparts/menu-tools.js.map +1 -1
  61. package/dist-server/scripts/calculate-kpi-scores.js +65 -3
  62. package/dist-server/scripts/calculate-kpi-scores.js.map +1 -1
  63. package/dist-server/scripts/load-grade-data-migration.d.ts +4 -0
  64. package/dist-server/scripts/load-grade-data-migration.js +95 -10
  65. package/dist-server/scripts/load-grade-data-migration.js.map +1 -1
  66. package/dist-server/scripts/propagate-parent-kpi-values.js +58 -4
  67. package/dist-server/scripts/propagate-parent-kpi-values.js.map +1 -1
  68. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.d.ts +6 -0
  69. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +57 -7
  70. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -1
  71. package/dist-server/service/kpi-stat/kpi-stat-query.d.ts +8 -5
  72. package/dist-server/service/kpi-stat/kpi-stat-query.js +228 -11
  73. package/dist-server/service/kpi-stat/kpi-stat-query.js.map +1 -1
  74. package/dist-server/service/kpi-stat/kpi-stat-types.d.ts +13 -0
  75. package/dist-server/service/kpi-stat/kpi-stat-types.js +51 -1
  76. package/dist-server/service/kpi-stat/kpi-stat-types.js.map +1 -1
  77. package/dist-server/tsconfig.tsbuildinfo +1 -1
  78. package/package.json +54 -54
  79. package/schema.graphql +95 -58
  80. package/things-factory.config.js +3 -1
  81. package/views/auth-page.html +0 -1
  82. package/views/public/home.html +0 -1
@@ -7,11 +7,10 @@ export declare function queryDataSets(): Promise<{
7
7
  active: boolean;
8
8
  }[]>;
9
9
  declare const MenuTools_base: (new (...args: any[]) => {
10
- _storeUnsubscribe: import("redux").Unsubscribe;
10
+ _storeUnsubscribe: () => void;
11
11
  connectedCallback(): void;
12
12
  disconnectedCallback(): void;
13
13
  stateChanged(_state: unknown): void;
14
- readonly isConnected: boolean;
15
14
  }) & typeof LitElement;
16
15
  export declare class MenuTools extends MenuTools_base {
17
16
  static styles: import("lit").CSSResult[];
@@ -3,8 +3,7 @@ import '@material/web/icon/icon.js';
3
3
  import gql from 'graphql-tag';
4
4
  import { css, html, LitElement } from 'lit';
5
5
  import { customElement, property, query, state } from 'lit/decorators.js';
6
- import { connect } from 'pwa-helpers';
7
- import { store } from '@operato/shell';
6
+ import { store, connect } from '@operato/shell';
8
7
  import { client } from '@operato/graphql';
9
8
  // import { ICONS_HOME, ICONS_KPIS, ICONS_INTEGRATION, ICONS_SETTING } from '../icons/menu-icons'
10
9
  export async function queryDataSets() {
@@ -1 +1 @@
1
- {"version":3,"file":"menu-tools.js","sourceRoot":"","sources":["../../client/viewparts/menu-tools.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport { connect } from 'pwa-helpers'\n\nimport { store } from '@operato/shell'\nimport { client } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\n\n// import { ICONS_HOME, ICONS_KPIS, ICONS_INTEGRATION, ICONS_SETTING } from '../icons/menu-icons'\nexport async function queryDataSets(): Promise<{ id: string; name: string; description: string; active: boolean }[]> {\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {\n responses: dataSets(filters: $filters, pagination: $pagination, sortings: $sortings) {\n items {\n id\n name\n description\n active\n summaryPeriod\n }\n total\n }\n }\n `,\n variables: {\n filters: [\n {\n name: 'active',\n operator: 'eq',\n value: true\n }\n ],\n pagination: {},\n sortings: []\n }\n })\n\n return response.data.responses.items\n}\n\n@customElement('menu-tools')\nexport class MenuTools extends connect(store)(LitElement) {\n static styles = [\n css`\n :host {\n position: relative;\n display: flex;\n background-color: var(--secondary-color);\n\n /* for narrow mode */\n flex-direction: column;\n width: 100%;\n --menu-tools-color: rgba(255, 255, 255, 0.9);\n --menu-tools-active-color: rgba(107, 178, 249, 1);\n }\n\n :host([width='WIDE']) {\n /* for wide mode */\n flex-direction: row;\n width: initial;\n height: 100%;\n }\n\n ul {\n display: flex;\n flex-direction: row;\n\n margin: auto;\n padding: 0;\n list-style: none;\n height: 100%;\n overflow: none;\n }\n\n :host([width='NARROW']) ul {\n width: 100%;\n justify-content: space-around;\n }\n\n :host([width='WIDE']) ul {\n flex-direction: column;\n }\n :host([width='NARROW']) li {\n flex: 1;\n }\n\n :host([width='WIDE']) li {\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n }\n\n a {\n display: flex;\n flex-direction: column;\n padding: 8px 8px 4px 8px;\n opacity: 0.7;\n align-items: center;\n text-align: center;\n text-decoration: none;\n text-transform: capitalize;\n color: var(--menu-tools-color);\n border-left: 2px solid transparent;\n\n --md-icon-size: 36px;\n }\n\n a[active] {\n opacity: 1;\n color: var(--menu-tools-active-color);\n font-weight: bold;\n background-color: rgba(0, 0, 0, 0.15);\n border-left: 2px solid var(--menu-tools-active-color);\n }\n\n :host([width='NARROW']) a {\n padding: 0px 0px 5px 0px;\n opacity: 0.8;\n color: var(--menu-tools-color);\n border-left: none;\n border-top: 2px solid transparent;\n }\n\n :host([width='NARROW']) a[active] {\n opacity: 1;\n color: var(--menu-tools-active-color);\n font-weight: bold;\n background-color: rgba(0, 0, 0, 0.15);\n border-left: none;\n border-top: 2px solid var(--menu-tools-active-color);\n }\n\n img {\n display: block;\n width: 35px;\n padding: 5px 10px 0px 10px;\n }\n\n :host([width='NARROW']) img {\n padding: 0;\n }\n\n div {\n font-size: 0.6em;\n }\n\n .submenu-popup {\n position: absolute;\n left: 60px; /* 탑메뉴 width */\n top: 0;\n width: 220px;\n height: 100%;\n background: linear-gradient(135deg, #1e293b 0%, #334155 100%);\n color: #fff;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);\n z-index: 1000;\n display: flex;\n flex-direction: column;\n border-radius: 0 10px 10px 0;\n }\n\n .submenu-popup ul {\n list-style: none;\n margin: 0;\n padding: 0;\n }\n\n .submenu-popup li {\n font-size: 1.1em;\n }\n\n .submenu-popup li a {\n color: #fff;\n text-decoration: none;\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: 12px;\n transition: background 0.2s;\n padding: 12px 16px;\n }\n\n .submenu-popup li a:hover {\n background: #333;\n }\n\n .submenu-popup li a md-icon {\n --md-icon-size: 20px;\n color: rgba(255, 255, 255, 0.8);\n }\n\n .submenu-popup li a[active] md-icon {\n color: var(--menu-tools-active-color);\n }\n .submenu-popup li {\n position: relative;\n }\n .subsubmenu {\n margin-left: 20px;\n margin-top: 8px;\n border-left: 2px solid rgba(255, 255, 255, 0.2);\n padding-left: 12px;\n }\n .subsubmenu li {\n padding: 8px 16px;\n font-size: 0.9em;\n }\n .subsubmenu li a {\n padding: 8px 12px;\n font-size: 0.85em;\n opacity: 0.8;\n }\n .subsubmenu li a:hover {\n opacity: 1;\n background: rgba(255, 255, 255, 0.1);\n }\n .subsubmenu li a[active] {\n opacity: 1;\n color: var(--menu-tools-active-color);\n background: rgba(107, 178, 249, 0.2);\n }\n .subsubmenu li a md-icon {\n --md-icon-size: 16px;\n }\n .expand-button {\n margin-left: auto;\n background: none;\n border: none;\n color: rgba(255, 255, 255, 0.6);\n cursor: pointer;\n padding: 4px;\n border-radius: 4px;\n transition: all 0.2s;\n }\n .expand-button:hover {\n color: rgba(255, 255, 255, 0.9);\n background: rgba(255, 255, 255, 0.1);\n }\n .expand-button md-icon {\n --md-icon-size: 16px;\n transition: transform 0.2s;\n }\n .expand-button.expanded md-icon {\n transform: rotate(90deg);\n }\n `\n ]\n\n @property({ type: String }) page?: string\n @property({ type: String, reflect: true }) width?: string\n\n @state() dataSets: any[] = []\n @state() menus: {\n name: string\n path: string\n icon: string\n active?: ({ path }: { path: string }) => boolean\n submenus?: {\n name: string\n path: string\n icon?: string\n active?: ({ path }: { path: string }) => boolean\n subsubmenus?: { name: string; path: string; icon?: string; active?: ({ path }: { path: string }) => boolean }[]\n }[]\n }[] = this.getMenus()\n\n private getMenus(): {\n name: string\n path: string\n icon: string\n active?: ({ path }: { path: string }) => boolean\n submenus?: {\n name: string\n path: string\n icon?: string\n active?: ({ path }: { path: string }) => boolean\n subsubmenus?: { name: string; path: string; icon?: string; active?: ({ path }: { path: string }) => boolean }[]\n }[]\n }[] {\n const dataSets = this.dataSets\n\n return [\n {\n name: '홈',\n path: 'project-list',\n icon: 'location_city',\n active: ({ path }) => /^project/.test(path),\n submenus: [\n { name: '프로젝트 목록', path: 'project-list', icon: 'autoplay' },\n { name: '완료 프로젝트 목록', path: 'project-completed-list', icon: 'stop_circle' }\n ]\n },\n {\n name: 'KPI',\n path: 'kpi-overview',\n icon: 'bar_chart',\n submenus: [\n { name: 'KPI 개요', path: 'kpi-overview', icon: 'widget_small' },\n // { name: 'KPI 성과판', path: 'kpi-dashboard', icon: 'dashboard' },\n // {\n // name: i18next.t('title.kpi statistic list'),\n // icon: 'candlestick_chart',\n // path: 'kpi-statistic-list'\n // },\n // {\n // name: i18next.t('title.kpi statistic editor'),\n // icon: 'edit_square',\n // path: 'kpi-statistic-editor'\n // },\n { name: 'KPI 목록', path: 'kpi-list', icon: 'readiness_score' },\n { name: 'KPI 값 목록', path: 'kpi-value-list', icon: 'heap_snapshot_multiple' },\n { name: 'KPI 메트릭 목록', path: 'kpi-metric-list', icon: 'data_exploration' },\n { name: 'KPI 메트릭 값 목록', path: 'kpi-metric-value-list', icon: 'heap_snapshot_multiple' },\n { name: 'KPI 매트릭 값 수동 입력', path: 'kpi-metric-value-manual-entry', icon: 'edit' }\n ]\n },\n {\n name: 'Data Set',\n path: 'data-set-list',\n icon: 'dataset',\n submenus: [\n { name: 'Data Set 목록', path: 'data-set-list', icon: 'dataset' },\n { name: 'Data Key 목록', path: 'data-key-set-list', icon: 'key' },\n { name: 'Data Sample 값 수동 입력', path: 'data-entry-list', icon: 'edit' },\n {\n name: 'Data Sample 목록',\n path: 'data-sample-list',\n icon: 'rule',\n subsubmenus:\n dataSets.map(item => {\n return {\n name: item.name,\n icon: 'checklist_rtl',\n path: `data-sample-search/${item.id}`\n }\n }) || []\n },\n {\n name: 'Data Summary 목록',\n path: 'data-summary-list',\n icon: 'functions',\n subsubmenus:\n dataSets\n .filter(item => item.active && item.summaryPeriod)\n .map(item => {\n return {\n name: item.name,\n icon: 'checklist',\n path: `data-summary-period/${item.id}`\n }\n }) || []\n }\n ]\n },\n {\n name: '시스템연계',\n path: 'project-task-list',\n icon: 'hub',\n submenus: [\n { name: '연계 현황', path: 'integration-monitor', icon: 'hub' },\n { name: '연계 설정', path: 'connection', icon: 'settings' },\n { name: '연계 시나리오', path: 'scenario', icon: 'hub' }\n ]\n },\n {\n name: '셋팅',\n path: 'users',\n icon: 'settings',\n submenus: [\n { name: '사용자 관리', path: 'users', icon: 'people' },\n { name: '환경 설정', path: 'setting', icon: 'settings' }\n ]\n }\n ]\n }\n\n @property({ type: Number }) openedMenuIndex: number | null = null\n @property({ type: Number }) openedSubmenuIndex: number | null = null\n @query('ul') menuUl!: HTMLUListElement\n @property({ type: Number }) submenuHeight: number | null = null\n\n render() {\n var page = this.page || ''\n return html`\n <ul>\n ${this.menus.map(\n (menu, i) => html`\n <li\n @click=${(e: Event) => {\n e.stopPropagation()\n this.openedMenuIndex = i\n this._setSubmenuHeight()\n }}\n >\n <a href=\"javascript:void(0)\" ?active=${this._isActiveMenu(page, menu)}>\n <md-icon>${menu.icon}</md-icon>\n <div>${menu.name}</div>\n </a>\n </li>\n `\n )}\n </ul>\n ${this.openedMenuIndex !== null\n ? html`\n <div class=\"submenu-popup\">\n <ul>\n ${this.menus[this.openedMenuIndex].submenus?.map(\n (sub, subIndex) => html`\n <li>\n <a\n href=${sub.subsubmenus ? 'javascript:void(0)' : sub.path}\n ?active=${this._isActiveSubmenu(page, sub)}\n @click=${sub.subsubmenus ? (e: Event) => e.preventDefault() : undefined}\n >\n ${sub.icon ? html`<md-icon>${sub.icon}</md-icon>` : ''} ${sub.name}\n ${sub.subsubmenus\n ? html`\n <button\n class=\"expand-button ${this.openedSubmenuIndex === subIndex ? 'expanded' : ''}\"\n @click=${(e: Event) => this._toggleSubsubmenu(e, subIndex)}\n >\n <md-icon>chevron_right</md-icon>\n </button>\n `\n : ''}\n </a>\n ${sub.subsubmenus && this.openedSubmenuIndex === subIndex\n ? html`\n <ul class=\"subsubmenu\">\n ${sub.subsubmenus.map(\n subsub => html`\n <li>\n <a href=${subsub.path} ?active=${this._isActiveSubsubmenu(page, subsub.path)}>\n ${subsub.icon ? html`<md-icon>${subsub.icon}</md-icon>` : ''} ${subsub.name}\n </a>\n </li>\n `\n )}\n </ul>\n `\n : ''}\n </li>\n `\n )}\n </ul>\n </div>\n `\n : ''}\n `\n }\n\n private _isActiveMenu(currentPage: string, menu: any): boolean {\n // 메인 메뉴의 기본 path 매칭 확인\n if (currentPage === menu.path) return true\n\n // 커스텀 active 함수가 있으면 추가로 확인\n if (menu.active && typeof menu.active === 'function') {\n if (menu.active({ path: currentPage })) return true\n }\n\n // 서브메뉴 중 하나라도 active인지 확인\n if (menu.submenus) {\n return menu.submenus.some((sub: any) => {\n // 서브메뉴 기본 path 매칭\n if (currentPage === sub.path || currentPage.startsWith(sub.path + '/')) return true\n\n // 서브메뉴에 커스텀 active 함수가 있으면 추가로 확인\n if (sub.active && typeof sub.active === 'function') {\n return sub.active({ path: currentPage })\n }\n\n return false\n })\n }\n\n return false\n }\n\n private _isActiveSubmenu(currentPage: string, submenu: any): boolean {\n // 기본 path 매칭 확인\n if (currentPage === submenu.path || currentPage.startsWith(submenu.path + '/')) return true\n\n // 커스텀 active 함수가 있으면 추가로 확인\n if (submenu.active && typeof submenu.active === 'function') {\n return submenu.active({ path: currentPage })\n }\n\n return false\n }\n\n async firstUpdated() {\n this._setSubmenuHeight()\n\n this.dataSets = await queryDataSets()\n this.menus = this.getMenus()\n }\n\n updated(changedProps: Map<string, any>) {\n if (changedProps.has('openedMenuIndex')) {\n this._setSubmenuHeight()\n }\n }\n\n _setSubmenuHeight() {\n if (this.menuUl) {\n this.submenuHeight = this.menuUl.clientHeight\n }\n }\n\n connectedCallback() {\n super.connectedCallback()\n window.addEventListener('click', this._closeSubmenu)\n }\n\n disconnectedCallback() {\n window.removeEventListener('click', this._closeSubmenu)\n super.disconnectedCallback()\n }\n\n private _closeSubmenu = () => {\n this.openedMenuIndex = null\n }\n\n private _toggleSubsubmenu(e: Event, subIndex: number) {\n e.stopPropagation()\n if (this.openedSubmenuIndex === subIndex) {\n this.openedSubmenuIndex = null\n } else {\n this.openedSubmenuIndex = subIndex\n }\n }\n\n private _isActiveSubsubmenu(currentPage: string, subsubmenu: any): boolean {\n // 기본 path 매칭 확인\n if (currentPage === subsubmenu.path || currentPage.startsWith(subsubmenu.path + '/')) return true\n\n // 커스텀 active 함수가 있으면 추가로 확인\n if (subsubmenu.active && typeof subsubmenu.active === 'function') {\n return subsubmenu.active({ path: currentPage })\n }\n\n return false\n }\n\n stateChanged(state: any) {\n this.page = state.route.page\n this.width = state.layout.width\n }\n}\n"]}
1
+ {"version":3,"file":"menu-tools.js","sourceRoot":"","sources":["../../client/viewparts/menu-tools.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport { store, connect } from '@operato/shell'\nimport { client } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\n\n// import { ICONS_HOME, ICONS_KPIS, ICONS_INTEGRATION, ICONS_SETTING } from '../icons/menu-icons'\nexport async function queryDataSets(): Promise<{ id: string; name: string; description: string; active: boolean }[]> {\n const response = await client.query({\n query: gql`\n query ($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {\n responses: dataSets(filters: $filters, pagination: $pagination, sortings: $sortings) {\n items {\n id\n name\n description\n active\n summaryPeriod\n }\n total\n }\n }\n `,\n variables: {\n filters: [\n {\n name: 'active',\n operator: 'eq',\n value: true\n }\n ],\n pagination: {},\n sortings: []\n }\n })\n\n return response.data.responses.items\n}\n\n@customElement('menu-tools')\nexport class MenuTools extends connect(store)(LitElement) {\n static styles = [\n css`\n :host {\n position: relative;\n display: flex;\n background-color: var(--secondary-color);\n\n /* for narrow mode */\n flex-direction: column;\n width: 100%;\n --menu-tools-color: rgba(255, 255, 255, 0.9);\n --menu-tools-active-color: rgba(107, 178, 249, 1);\n }\n\n :host([width='WIDE']) {\n /* for wide mode */\n flex-direction: row;\n width: initial;\n height: 100%;\n }\n\n ul {\n display: flex;\n flex-direction: row;\n\n margin: auto;\n padding: 0;\n list-style: none;\n height: 100%;\n overflow: none;\n }\n\n :host([width='NARROW']) ul {\n width: 100%;\n justify-content: space-around;\n }\n\n :host([width='WIDE']) ul {\n flex-direction: column;\n }\n :host([width='NARROW']) li {\n flex: 1;\n }\n\n :host([width='WIDE']) li {\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n }\n\n a {\n display: flex;\n flex-direction: column;\n padding: 8px 8px 4px 8px;\n opacity: 0.7;\n align-items: center;\n text-align: center;\n text-decoration: none;\n text-transform: capitalize;\n color: var(--menu-tools-color);\n border-left: 2px solid transparent;\n\n --md-icon-size: 36px;\n }\n\n a[active] {\n opacity: 1;\n color: var(--menu-tools-active-color);\n font-weight: bold;\n background-color: rgba(0, 0, 0, 0.15);\n border-left: 2px solid var(--menu-tools-active-color);\n }\n\n :host([width='NARROW']) a {\n padding: 0px 0px 5px 0px;\n opacity: 0.8;\n color: var(--menu-tools-color);\n border-left: none;\n border-top: 2px solid transparent;\n }\n\n :host([width='NARROW']) a[active] {\n opacity: 1;\n color: var(--menu-tools-active-color);\n font-weight: bold;\n background-color: rgba(0, 0, 0, 0.15);\n border-left: none;\n border-top: 2px solid var(--menu-tools-active-color);\n }\n\n img {\n display: block;\n width: 35px;\n padding: 5px 10px 0px 10px;\n }\n\n :host([width='NARROW']) img {\n padding: 0;\n }\n\n div {\n font-size: 0.6em;\n }\n\n .submenu-popup {\n position: absolute;\n left: 60px; /* 탑메뉴 width */\n top: 0;\n width: 220px;\n height: 100%;\n background: linear-gradient(135deg, #1e293b 0%, #334155 100%);\n color: #fff;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);\n z-index: 1000;\n display: flex;\n flex-direction: column;\n border-radius: 0 10px 10px 0;\n }\n\n .submenu-popup ul {\n list-style: none;\n margin: 0;\n padding: 0;\n }\n\n .submenu-popup li {\n font-size: 1.1em;\n }\n\n .submenu-popup li a {\n color: #fff;\n text-decoration: none;\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: 12px;\n transition: background 0.2s;\n padding: 12px 16px;\n }\n\n .submenu-popup li a:hover {\n background: #333;\n }\n\n .submenu-popup li a md-icon {\n --md-icon-size: 20px;\n color: rgba(255, 255, 255, 0.8);\n }\n\n .submenu-popup li a[active] md-icon {\n color: var(--menu-tools-active-color);\n }\n .submenu-popup li {\n position: relative;\n }\n .subsubmenu {\n margin-left: 20px;\n margin-top: 8px;\n border-left: 2px solid rgba(255, 255, 255, 0.2);\n padding-left: 12px;\n }\n .subsubmenu li {\n padding: 8px 16px;\n font-size: 0.9em;\n }\n .subsubmenu li a {\n padding: 8px 12px;\n font-size: 0.85em;\n opacity: 0.8;\n }\n .subsubmenu li a:hover {\n opacity: 1;\n background: rgba(255, 255, 255, 0.1);\n }\n .subsubmenu li a[active] {\n opacity: 1;\n color: var(--menu-tools-active-color);\n background: rgba(107, 178, 249, 0.2);\n }\n .subsubmenu li a md-icon {\n --md-icon-size: 16px;\n }\n .expand-button {\n margin-left: auto;\n background: none;\n border: none;\n color: rgba(255, 255, 255, 0.6);\n cursor: pointer;\n padding: 4px;\n border-radius: 4px;\n transition: all 0.2s;\n }\n .expand-button:hover {\n color: rgba(255, 255, 255, 0.9);\n background: rgba(255, 255, 255, 0.1);\n }\n .expand-button md-icon {\n --md-icon-size: 16px;\n transition: transform 0.2s;\n }\n .expand-button.expanded md-icon {\n transform: rotate(90deg);\n }\n `\n ]\n\n @property({ type: String }) page?: string\n @property({ type: String, reflect: true }) width?: string\n\n @state() dataSets: any[] = []\n @state() menus: {\n name: string\n path: string\n icon: string\n active?: ({ path }: { path: string }) => boolean\n submenus?: {\n name: string\n path: string\n icon?: string\n active?: ({ path }: { path: string }) => boolean\n subsubmenus?: { name: string; path: string; icon?: string; active?: ({ path }: { path: string }) => boolean }[]\n }[]\n }[] = this.getMenus()\n\n private getMenus(): {\n name: string\n path: string\n icon: string\n active?: ({ path }: { path: string }) => boolean\n submenus?: {\n name: string\n path: string\n icon?: string\n active?: ({ path }: { path: string }) => boolean\n subsubmenus?: { name: string; path: string; icon?: string; active?: ({ path }: { path: string }) => boolean }[]\n }[]\n }[] {\n const dataSets = this.dataSets\n\n return [\n {\n name: '홈',\n path: 'project-list',\n icon: 'location_city',\n active: ({ path }) => /^project/.test(path),\n submenus: [\n { name: '프로젝트 목록', path: 'project-list', icon: 'autoplay' },\n { name: '완료 프로젝트 목록', path: 'project-completed-list', icon: 'stop_circle' }\n ]\n },\n {\n name: 'KPI',\n path: 'kpi-overview',\n icon: 'bar_chart',\n submenus: [\n { name: 'KPI 개요', path: 'kpi-overview', icon: 'widget_small' },\n // { name: 'KPI 성과판', path: 'kpi-dashboard', icon: 'dashboard' },\n // {\n // name: i18next.t('title.kpi statistic list'),\n // icon: 'candlestick_chart',\n // path: 'kpi-statistic-list'\n // },\n // {\n // name: i18next.t('title.kpi statistic editor'),\n // icon: 'edit_square',\n // path: 'kpi-statistic-editor'\n // },\n { name: 'KPI 목록', path: 'kpi-list', icon: 'readiness_score' },\n { name: 'KPI 값 목록', path: 'kpi-value-list', icon: 'heap_snapshot_multiple' },\n { name: 'KPI 메트릭 목록', path: 'kpi-metric-list', icon: 'data_exploration' },\n { name: 'KPI 메트릭 값 목록', path: 'kpi-metric-value-list', icon: 'heap_snapshot_multiple' },\n { name: 'KPI 매트릭 값 수동 입력', path: 'kpi-metric-value-manual-entry', icon: 'edit' }\n ]\n },\n {\n name: 'Data Set',\n path: 'data-set-list',\n icon: 'dataset',\n submenus: [\n { name: 'Data Set 목록', path: 'data-set-list', icon: 'dataset' },\n { name: 'Data Key 목록', path: 'data-key-set-list', icon: 'key' },\n { name: 'Data Sample 값 수동 입력', path: 'data-entry-list', icon: 'edit' },\n {\n name: 'Data Sample 목록',\n path: 'data-sample-list',\n icon: 'rule',\n subsubmenus:\n dataSets.map(item => {\n return {\n name: item.name,\n icon: 'checklist_rtl',\n path: `data-sample-search/${item.id}`\n }\n }) || []\n },\n {\n name: 'Data Summary 목록',\n path: 'data-summary-list',\n icon: 'functions',\n subsubmenus:\n dataSets\n .filter(item => item.active && item.summaryPeriod)\n .map(item => {\n return {\n name: item.name,\n icon: 'checklist',\n path: `data-summary-period/${item.id}`\n }\n }) || []\n }\n ]\n },\n {\n name: '시스템연계',\n path: 'project-task-list',\n icon: 'hub',\n submenus: [\n { name: '연계 현황', path: 'integration-monitor', icon: 'hub' },\n { name: '연계 설정', path: 'connection', icon: 'settings' },\n { name: '연계 시나리오', path: 'scenario', icon: 'hub' }\n ]\n },\n {\n name: '셋팅',\n path: 'users',\n icon: 'settings',\n submenus: [\n { name: '사용자 관리', path: 'users', icon: 'people' },\n { name: '환경 설정', path: 'setting', icon: 'settings' }\n ]\n }\n ]\n }\n\n @property({ type: Number }) openedMenuIndex: number | null = null\n @property({ type: Number }) openedSubmenuIndex: number | null = null\n @query('ul') menuUl!: HTMLUListElement\n @property({ type: Number }) submenuHeight: number | null = null\n\n render() {\n var page = this.page || ''\n return html`\n <ul>\n ${this.menus.map(\n (menu, i) => html`\n <li\n @click=${(e: Event) => {\n e.stopPropagation()\n this.openedMenuIndex = i\n this._setSubmenuHeight()\n }}\n >\n <a href=\"javascript:void(0)\" ?active=${this._isActiveMenu(page, menu)}>\n <md-icon>${menu.icon}</md-icon>\n <div>${menu.name}</div>\n </a>\n </li>\n `\n )}\n </ul>\n ${this.openedMenuIndex !== null\n ? html`\n <div class=\"submenu-popup\">\n <ul>\n ${this.menus[this.openedMenuIndex].submenus?.map(\n (sub, subIndex) => html`\n <li>\n <a\n href=${sub.subsubmenus ? 'javascript:void(0)' : sub.path}\n ?active=${this._isActiveSubmenu(page, sub)}\n @click=${sub.subsubmenus ? (e: Event) => e.preventDefault() : undefined}\n >\n ${sub.icon ? html`<md-icon>${sub.icon}</md-icon>` : ''} ${sub.name}\n ${sub.subsubmenus\n ? html`\n <button\n class=\"expand-button ${this.openedSubmenuIndex === subIndex ? 'expanded' : ''}\"\n @click=${(e: Event) => this._toggleSubsubmenu(e, subIndex)}\n >\n <md-icon>chevron_right</md-icon>\n </button>\n `\n : ''}\n </a>\n ${sub.subsubmenus && this.openedSubmenuIndex === subIndex\n ? html`\n <ul class=\"subsubmenu\">\n ${sub.subsubmenus.map(\n subsub => html`\n <li>\n <a href=${subsub.path} ?active=${this._isActiveSubsubmenu(page, subsub.path)}>\n ${subsub.icon ? html`<md-icon>${subsub.icon}</md-icon>` : ''} ${subsub.name}\n </a>\n </li>\n `\n )}\n </ul>\n `\n : ''}\n </li>\n `\n )}\n </ul>\n </div>\n `\n : ''}\n `\n }\n\n private _isActiveMenu(currentPage: string, menu: any): boolean {\n // 메인 메뉴의 기본 path 매칭 확인\n if (currentPage === menu.path) return true\n\n // 커스텀 active 함수가 있으면 추가로 확인\n if (menu.active && typeof menu.active === 'function') {\n if (menu.active({ path: currentPage })) return true\n }\n\n // 서브메뉴 중 하나라도 active인지 확인\n if (menu.submenus) {\n return menu.submenus.some((sub: any) => {\n // 서브메뉴 기본 path 매칭\n if (currentPage === sub.path || currentPage.startsWith(sub.path + '/')) return true\n\n // 서브메뉴에 커스텀 active 함수가 있으면 추가로 확인\n if (sub.active && typeof sub.active === 'function') {\n return sub.active({ path: currentPage })\n }\n\n return false\n })\n }\n\n return false\n }\n\n private _isActiveSubmenu(currentPage: string, submenu: any): boolean {\n // 기본 path 매칭 확인\n if (currentPage === submenu.path || currentPage.startsWith(submenu.path + '/')) return true\n\n // 커스텀 active 함수가 있으면 추가로 확인\n if (submenu.active && typeof submenu.active === 'function') {\n return submenu.active({ path: currentPage })\n }\n\n return false\n }\n\n async firstUpdated() {\n this._setSubmenuHeight()\n\n this.dataSets = await queryDataSets()\n this.menus = this.getMenus()\n }\n\n updated(changedProps: Map<string, any>) {\n if (changedProps.has('openedMenuIndex')) {\n this._setSubmenuHeight()\n }\n }\n\n _setSubmenuHeight() {\n if (this.menuUl) {\n this.submenuHeight = this.menuUl.clientHeight\n }\n }\n\n connectedCallback() {\n super.connectedCallback()\n window.addEventListener('click', this._closeSubmenu)\n }\n\n disconnectedCallback() {\n window.removeEventListener('click', this._closeSubmenu)\n super.disconnectedCallback()\n }\n\n private _closeSubmenu = () => {\n this.openedMenuIndex = null\n }\n\n private _toggleSubsubmenu(e: Event, subIndex: number) {\n e.stopPropagation()\n if (this.openedSubmenuIndex === subIndex) {\n this.openedSubmenuIndex = null\n } else {\n this.openedSubmenuIndex = subIndex\n }\n }\n\n private _isActiveSubsubmenu(currentPage: string, subsubmenu: any): boolean {\n // 기본 path 매칭 확인\n if (currentPage === subsubmenu.path || currentPage.startsWith(subsubmenu.path + '/')) return true\n\n // 커스텀 active 함수가 있으면 추가로 확인\n if (subsubmenu.active && typeof subsubmenu.active === 'function') {\n return subsubmenu.active({ path: currentPage })\n }\n\n return false\n }\n\n stateChanged(state: any) {\n this.page = state.route.page\n this.width = state.layout.width\n }\n}\n"]}
@@ -4,11 +4,38 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.calculateKpiScores = calculateKpiScores;
5
5
  exports.listKpisWithLookupTables = listKpisWithLookupTables;
6
6
  const typeorm_1 = require("typeorm");
7
+ function isGrade2DLookup(grades) {
8
+ return grades && typeof grades === 'object' && !Array.isArray(grades) && grades.type === 'PROGRESS_DEVIATION_LOOKUP';
9
+ }
10
+ /**
11
+ * 2D lookup table에서 점수 계산 (X13: 공정률 × 편차 → 점수)
12
+ * @param deviationValue 편차율 (formula 결과)
13
+ * @param grades 2D lookup grades 객체
14
+ * @param progressRate 공정률 (0~100)
15
+ */
16
+ function calculate2DScore(deviationValue, grades, progressRate) {
17
+ if (!grades.rows || grades.rows.length === 0)
18
+ return null;
19
+ const progressIndex = Math.min(99, Math.max(0, Math.floor(progressRate)));
20
+ const row = grades.rows.find(r => r.progressRate === progressIndex);
21
+ if (!row)
22
+ return null;
23
+ if (deviationValue < row.boundary5to4)
24
+ return 5;
25
+ if (deviationValue < row.boundary4to3)
26
+ return 4;
27
+ if (deviationValue < row.boundary3to2)
28
+ return 3;
29
+ if (deviationValue < row.boundary2to1)
30
+ return 2;
31
+ return 1;
32
+ }
7
33
  /**
8
34
  * Calculate KPI scores based on lookup tables (grades)
9
35
  * Processes kpi-values and updates scores based on KPI grades
10
36
  */
11
37
  async function calculateKpiScores(specificKpiName, forceRecalculate = false) {
38
+ var _a;
12
39
  // Set NODE_ENV if not set
13
40
  if (!process.env.NODE_ENV) {
14
41
  process.env.NODE_ENV = 'development';
@@ -63,14 +90,30 @@ async function calculateKpiScores(specificKpiName, forceRecalculate = false) {
63
90
  let totalProcessed = 0;
64
91
  let totalUpdated = 0;
65
92
  let errorCount = 0;
93
+ // 2D lookup KPI (X13)에 필요한 Project entity 준비
94
+ let projectRepository = null;
95
+ const progressRateCache = new Map();
96
+ try {
97
+ const { Project } = require('@dssp/project');
98
+ projectRepository = getRepository(Project);
99
+ }
100
+ catch (_b) {
101
+ console.log('⚠️ @dssp/project not found — 2D lookup KPIs will use default progressRate');
102
+ }
66
103
  for (const kpi of kpis) {
67
104
  try {
68
105
  console.log(`\n📄 Processing KPI: ${kpi.name}`);
69
- if (!kpi.grades || !Array.isArray(kpi.grades) || kpi.grades.length === 0) {
106
+ const is2D = isGrade2DLookup(kpi.grades);
107
+ if (!is2D && (!kpi.grades || !Array.isArray(kpi.grades) || kpi.grades.length === 0)) {
70
108
  console.log(` ⚠️ No grades found, skipping`);
71
109
  continue;
72
110
  }
73
- console.log(` 📈 Lookup table: ${kpi.grades.length} grades`);
111
+ if (is2D) {
112
+ console.log(` 📈 2D Lookup table: ${kpi.grades.rows.length} rows`);
113
+ }
114
+ else {
115
+ console.log(` 📈 Lookup table: ${kpi.grades.length} grades`);
116
+ }
74
117
  // Get KPI values for this KPI
75
118
  let kpiValuesQuery = kpiValueRepository
76
119
  .createQueryBuilder('kpiValue')
@@ -90,7 +133,26 @@ async function calculateKpiScores(specificKpiName, forceRecalculate = false) {
90
133
  let updatedCount = 0;
91
134
  for (const kpiValue of kpiValues) {
92
135
  const value = kpiValue.value;
93
- const calculatedScore = calculateScoreFromGrades(value, kpi.grades);
136
+ let calculatedScore;
137
+ if (is2D) {
138
+ // 2D lookup: project의 totalProgress 조회
139
+ let progressRate = 50; // default
140
+ const projectId = kpiValue.group;
141
+ if (projectId && projectRepository) {
142
+ if (progressRateCache.has(projectId)) {
143
+ progressRate = progressRateCache.get(projectId);
144
+ }
145
+ else {
146
+ const project = await projectRepository.findOne({ where: { id: projectId } });
147
+ progressRate = (_a = project === null || project === void 0 ? void 0 : project.totalProgress) !== null && _a !== void 0 ? _a : 50;
148
+ progressRateCache.set(projectId, progressRate);
149
+ }
150
+ }
151
+ calculatedScore = calculate2DScore(value, kpi.grades, progressRate);
152
+ }
153
+ else {
154
+ calculatedScore = calculateScoreFromGrades(value, kpi.grades);
155
+ }
94
156
  if (calculatedScore !== null) {
95
157
  // Only update if the score is actually different
96
158
  if (kpiValue.score !== calculatedScore) {
@@ -1 +1 @@
1
- {"version":3,"file":"calculate-kpi-scores.js","sourceRoot":"","sources":["../../server/scripts/calculate-kpi-scores.ts"],"names":[],"mappings":";;;AAgCA,gDA2JC;AAmCD,4DAyDC;AArRD,qCAA0C;AA0B1C;;;GAGG;AACI,KAAK,UAAU,kBAAkB,CAAC,eAAwB,EAAE,gBAAgB,GAAG,KAAK;IACzF,0BAA0B;IAC1B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,QAAQ,GAAG,aAAa,CAAA;IACtC,CAAC;IAED,wCAAwC;IACxC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACjD,MAAM,SAAS,GAAG,OAAO,CAAC,6DAA6D,CAAC,CAAA;IACxF,MAAM,gBAAgB,GAAG,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IAEhD,IAAI,UAAU,CAAA;IAEd,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAA;IAEnD,IAAI,CAAC;QACH,0DAA0D;QAC1D,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAA;QAC3C,UAAU,GAAG,MAAM,IAAA,0BAAgB,gDAC9B,SAAS,GACT,gBAAgB,KACnB,OAAO,EAAE,KAAK,IACd,CAAA;QAEF,oDAAoD;QACpD,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAA;QAC1D,aAAa,CAAC,SAAS,EAAE,UAAU,CAAC,CAAA;QAEpC,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAA;QAEnC,8DAA8D;QAC9D,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAA;QAC1D,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;QAC9C,MAAM,aAAa,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA;QAExC,gDAAgD;QAChD,IAAI,kBAAkB,CAAA;QACtB,IAAI,CAAC;YACH,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;YACnD,kBAAkB,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;QAC9C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,6EAA6E,CAAC,CAAA;YAC5F,OAAM;QACR,CAAC;QAED,uCAAuC;QACvC,IAAI,SAAS,GAAG,aAAa;aAC1B,kBAAkB,CAAC,KAAK,CAAC;aACzB,iBAAiB,CAAC,YAAY,EAAE,QAAQ,CAAC;aACzC,KAAK,CAAC,wBAAwB,CAAC;aAC/B,QAAQ,CAAC,2BAA2B,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAA;QAElE,IAAI,eAAe,EAAE,CAAC;YACpB,SAAS,GAAG,SAAS,CAAC,QAAQ,CAAC,kBAAkB,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAA;YAC7E,OAAO,CAAC,GAAG,CAAC,+BAA+B,eAAe,EAAE,CAAC,CAAA;QAC/D,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAA;QAC1D,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,EAAE,CAAA;QAEtC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAA;YAC5D,OAAM;QACR,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,MAAM,0BAA0B,CAAC,CAAA;QAE9D,IAAI,cAAc,GAAG,CAAC,CAAA;QACtB,IAAI,YAAY,GAAG,CAAC,CAAA;QACpB,IAAI,UAAU,GAAG,CAAC,CAAA;QAElB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC;gBACH,OAAO,CAAC,GAAG,CAAC,wBAAwB,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;gBAE/C,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACzE,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAA;oBAC/C,SAAQ;gBACV,CAAC;gBAED,OAAO,CAAC,GAAG,CAAC,uBAAuB,GAAG,CAAC,MAAM,CAAC,MAAM,SAAS,CAAC,CAAA;gBAE9D,8BAA8B;gBAC9B,IAAI,cAAc,GAAG,kBAAkB;qBACpC,kBAAkB,CAAC,UAAU,CAAC;qBAC9B,iBAAiB,CAAC,cAAc,EAAE,KAAK,CAAC;qBACxC,KAAK,CAAC,iBAAiB,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC;qBAC3C,QAAQ,CAAC,4BAA4B,CAAC,CAAA;gBAEzC,IAAI,CAAC,gBAAgB,EAAE,CAAC;oBACtB,2CAA2C;oBAC3C,cAAc,GAAG,cAAc,CAAC,QAAQ,CAAC,gDAAgD,CAAC,CAAA;gBAC5F,CAAC;gBAED,MAAM,SAAS,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,CAAA;gBAEhD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAC3B,OAAO,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAA;oBAC7E,SAAQ;gBACV,CAAC;gBAED,OAAO,CAAC,GAAG,CAAC,oBAAoB,SAAS,CAAC,MAAM,mBAAmB,CAAC,CAAA;gBAEpE,IAAI,YAAY,GAAG,CAAC,CAAA;gBAEpB,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;oBACjC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAA;oBAC5B,MAAM,eAAe,GAAG,wBAAwB,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;oBAEnE,IAAI,eAAe,KAAK,IAAI,EAAE,CAAC;wBAC7B,iDAAiD;wBACjD,IAAI,QAAQ,CAAC,KAAK,KAAK,eAAe,EAAE,CAAC;4BACvC,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAA;4BAC/B,QAAQ,CAAC,KAAK,GAAG,eAAe,CAAA;4BAChC,MAAM,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;4BACvC,YAAY,EAAE,CAAA;4BAEd,OAAO,CAAC,GAAG,CAAC,iBAAiB,KAAK,YAAY,eAAe,SAAS,QAAQ,IAAI,MAAM,GAAG,CAAC,CAAA;wBAC9F,CAAC;oBACH,CAAC;yBAAM,CAAC;wBACN,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,sCAAsC,CAAC,CAAA;oBAC5E,CAAC;oBAED,cAAc,EAAE,CAAA;gBAClB,CAAC;gBAED,OAAO,CAAC,GAAG,CAAC,gBAAgB,YAAY,IAAI,SAAS,CAAC,MAAM,SAAS,CAAC,CAAA;gBACtE,YAAY,IAAI,YAAY,CAAA;YAE9B,CAAC;YAAC,OAAO,QAAQ,EAAE,CAAC;gBAClB,OAAO,CAAC,GAAG,CAAC,6BAA6B,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAA;gBACzE,UAAU,EAAE,CAAA;YACd,CAAC;QACH,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAA;QACnD,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,CAAC,MAAM,EAAE,CAAC,CAAA;QACnD,OAAO,CAAC,GAAG,CAAC,iCAAiC,cAAc,EAAE,CAAC,CAAA;QAC9D,OAAO,CAAC,GAAG,CAAC,wBAAwB,YAAY,EAAE,CAAC,CAAA;QACnD,OAAO,CAAC,GAAG,CAAC,gBAAgB,UAAU,EAAE,CAAC,CAAA;QAEzC,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,+DAA+D,CAAC,CAAA;QAC9E,CAAC;IAEH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,yCAAyC,EAAE,KAAK,CAAC,CAAA;QAC/D,MAAM,KAAK,CAAA;IACb,CAAC;YAAS,CAAC;QACT,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,UAAU,CAAC,KAAK,EAAE,CAAA;YACxB,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAA;QAC9C,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,wBAAwB,CAAC,KAAa,EAAE,MAAkB;IACjE,sCAAsC;IACtC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACvD,OAAO,KAAK,CAAC,KAAK,IAAI,CAAC,CAAA;QACzB,CAAC;IACH,CAAC;IAED,2EAA2E;IAC3E,IAAI,SAAS,GAAoB,IAAI,CAAA;IACrC,IAAI,YAAY,GAAG,CAAC,QAAQ,CAAA;IAE5B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,IAAI,KAAK,CAAC,QAAQ,GAAG,YAAY,EAAE,CAAC;YAC7D,SAAS,GAAG,KAAK,CAAA;YACjB,YAAY,GAAG,KAAK,CAAC,QAAQ,CAAA;QAC/B,CAAC;IACH,CAAC;IAED,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,SAAS,CAAC,KAAK,IAAI,CAAC,CAAA;IAC7B,CAAC;IAED,OAAO,IAAI,CAAA,CAAC,sDAAsD;AACpE,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,wBAAwB;IAC5C,0BAA0B;IAC1B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,QAAQ,GAAG,aAAa,CAAA;IACtC,CAAC;IAED,wCAAwC;IACxC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACjD,MAAM,SAAS,GAAG,OAAO,CAAC,6DAA6D,CAAC,CAAA;IACxF,MAAM,gBAAgB,GAAG,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IAEhD,IAAI,UAAU,CAAA;IAEd,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAA;QAC3C,UAAU,GAAG,MAAM,IAAA,0BAAgB,gDAC9B,SAAS,GACT,gBAAgB,KACnB,OAAO,EAAE,KAAK,IACd,CAAA;QAEF,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAA;QAC1D,aAAa,CAAC,SAAS,EAAE,UAAU,CAAC,CAAA;QAEpC,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAA;QAC1D,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;QAC9C,MAAM,aAAa,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA;QAExC,uBAAuB;QACvB,MAAM,IAAI,GAAG,MAAM,aAAa;aAC7B,kBAAkB,CAAC,KAAK,CAAC;aACzB,iBAAiB,CAAC,YAAY,EAAE,QAAQ,CAAC;aACzC,KAAK,CAAC,wBAAwB,CAAC;aAC/B,QAAQ,CAAC,2BAA2B,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;aAC/D,OAAO,EAAE,CAAA;QAEZ,OAAO,CAAC,GAAG,CAAC,+BAA+B,IAAI,CAAC,MAAM,MAAM,CAAC,CAAA;QAE7D,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAA;YACnD,OAAM;QACR,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YAC1B,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;YACrD,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI,KAAK,UAAU,UAAU,CAAC,CAAA;QAC7F,CAAC,CAAC,CAAA;QAEF,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,CAAC,MAAM,0BAA0B,CAAC,CAAA;IAEnE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAA;IAC/C,CAAC;YAAS,CAAC;QACT,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,UAAU,CAAC,KAAK,EAAE,CAAA;QAC1B,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAElC,IAAI,CAAC;QACH,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;OAmBX,CAAC,CAAA;YACF,OAAM;QACR,CAAC;QAED,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,MAAM,wBAAwB,EAAE,CAAA;YAChC,OAAM;QACR,CAAC;QAED,MAAM,gBAAgB,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;QACxE,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAA;QAE/D,IAAI,eAAe,EAAE,CAAC;YACpB,OAAO,CAAC,GAAG,CAAC,2CAA2C,eAAe,EAAE,CAAC,CAAA;YACzE,OAAO,CAAC,GAAG,CAAC,YAAY,gBAAgB,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,uBAAuB,EAAE,CAAC,CAAA;YAC/F,MAAM,kBAAkB,CAAC,eAAe,EAAE,gBAAgB,CAAC,CAAA;QAC7D,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,uDAAuD,CAAC,CAAA;YACpE,OAAO,CAAC,GAAG,CAAC,YAAY,gBAAgB,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,uBAAuB,EAAE,CAAC,CAAA;YAC/F,MAAM,kBAAkB,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAA;QACvD,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IAE1B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC;AAED,yBAAyB;AACzB,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,KAAU,EAAE,EAAE;IAC9C,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,CAAA;IAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA;AAEF,yBAAyB;AACzB,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC5B,IAAI,EAAE,CAAA;AACR,CAAC","sourcesContent":["#!/usr/bin/env ts-node\n\nimport { createConnection } from 'typeorm'\nimport * as fs from 'fs'\nimport * as path from 'path'\n\ninterface KpiGrade {\n name: string\n minValue: number\n maxValue: number\n score?: number\n color?: string\n description?: string\n}\n\ninterface KpiRecord {\n id: string\n name: string\n grades: KpiGrade[]\n}\n\ninterface KpiValueRecord {\n id: string\n value: number\n score?: number\n kpi: KpiRecord\n}\n\n/**\n * Calculate KPI scores based on lookup tables (grades)\n * Processes kpi-values and updates scores based on KPI grades\n */\nexport async function calculateKpiScores(specificKpiName?: string, forceRecalculate = false): Promise<void> {\n // Set NODE_ENV if not set\n if (!process.env.NODE_ENV) {\n process.env.NODE_ENV = 'development'\n }\n\n // Initialize Things-Factory environment\n const { config } = require('@things-factory/env')\n const ormconfig = require('@things-factory/shell/dist-server/initializers/ormconfig.js')\n const connectionConfig = config.get('ormconfig')\n\n let connection\n\n console.log('🚀 Starting KPI Score Calculation...')\n\n try {\n // Create database connection using Things-Factory pattern\n console.log('🔌 Connecting to database...')\n connection = await createConnection({\n ...ormconfig,\n ...connectionConfig,\n logging: false\n })\n\n // Register the connection with Things-Factory shell\n const { addDataSource } = require('@things-factory/shell')\n addDataSource('default', connection)\n\n console.log('✅ Database connected')\n\n // Now we can use getRepository with the registered connection\n const { getRepository } = require('@things-factory/shell')\n const { Kpi } = require('@things-factory/kpi')\n const kpiRepository = getRepository(Kpi)\n\n // Get KPI-Value repository (assuming it exists)\n let kpiValueRepository\n try {\n const { KpiValue } = require('@things-factory/kpi')\n kpiValueRepository = getRepository(KpiValue)\n } catch (error) {\n console.error('❌ KpiValue entity not found. Please ensure it exists in @things-factory/kpi')\n return\n }\n\n // Get KPIs with grades (lookup tables)\n let kpisQuery = kpiRepository\n .createQueryBuilder('kpi')\n .leftJoinAndSelect('kpi.domain', 'domain')\n .where('kpi.grades IS NOT NULL')\n .andWhere('domain.name = :domainName', { domainName: 'SYSTEM' })\n\n if (specificKpiName) {\n kpisQuery = kpisQuery.andWhere('kpi.name = :name', { name: specificKpiName })\n console.log(`🎯 Processing specific KPI: ${specificKpiName}`)\n } else {\n console.log('🎯 Processing all KPIs with lookup tables')\n }\n\n const kpis = await kpisQuery.getMany()\n\n if (kpis.length === 0) {\n console.log('⚠️ No KPIs found with lookup tables (grades)')\n return\n }\n\n console.log(`📊 Found ${kpis.length} KPIs with lookup tables`)\n\n let totalProcessed = 0\n let totalUpdated = 0\n let errorCount = 0\n\n for (const kpi of kpis) {\n try {\n console.log(`\\n📄 Processing KPI: ${kpi.name}`)\n \n if (!kpi.grades || !Array.isArray(kpi.grades) || kpi.grades.length === 0) {\n console.log(` ⚠️ No grades found, skipping`)\n continue\n }\n\n console.log(` 📈 Lookup table: ${kpi.grades.length} grades`)\n\n // Get KPI values for this KPI\n let kpiValuesQuery = kpiValueRepository\n .createQueryBuilder('kpiValue')\n .leftJoinAndSelect('kpiValue.kpi', 'kpi')\n .where('kpi.id = :kpiId', { kpiId: kpi.id })\n .andWhere('kpiValue.value IS NOT NULL')\n\n if (!forceRecalculate) {\n // Only process null or 0 scores by default\n kpiValuesQuery = kpiValuesQuery.andWhere('(kpiValue.score IS NULL OR kpiValue.score = 0)')\n }\n\n const kpiValues = await kpiValuesQuery.getMany()\n\n if (kpiValues.length === 0) {\n console.log(` ✅ No null/zero scores found (all values already calculated)`)\n continue\n }\n\n console.log(` 🔢 Processing ${kpiValues.length} null/zero scores`)\n\n let updatedCount = 0\n\n for (const kpiValue of kpiValues) {\n const value = kpiValue.value\n const calculatedScore = calculateScoreFromGrades(value, kpi.grades)\n\n if (calculatedScore !== null) {\n // Only update if the score is actually different\n if (kpiValue.score !== calculatedScore) {\n const oldScore = kpiValue.score\n kpiValue.score = calculatedScore\n await kpiValueRepository.save(kpiValue)\n updatedCount++\n \n console.log(` 📊 Value ${value} → Score ${calculatedScore} (was ${oldScore || 'null'})`)\n }\n } else {\n console.log(` ⚠️ Value ${value} is below all ranges in lookup table`)\n }\n\n totalProcessed++\n }\n\n console.log(` ✅ Updated ${updatedCount}/${kpiValues.length} values`)\n totalUpdated += updatedCount\n\n } catch (kpiError) {\n console.log(` ❌ Error processing KPI ${kpi.name}: ${kpiError.message}`)\n errorCount++\n }\n }\n\n console.log(`\\n🎉 KPI Score Calculation Complete!`)\n console.log(` 📊 KPIs processed: ${kpis.length}`)\n console.log(` 🔢 Total values processed: ${totalProcessed}`)\n console.log(` ✅ Scores updated: ${totalUpdated}`)\n console.log(` ❌ Errors: ${errorCount}`)\n\n if (errorCount > 0) {\n console.log(`\\n⚠️ Some KPIs had errors. Check the logs above for details.`)\n }\n\n } catch (error) {\n console.error(`❌ Fatal error during score calculation:`, error)\n throw error\n } finally {\n if (connection) {\n await connection.close()\n console.log('🔌 Database connection closed')\n }\n }\n}\n\n/**\n * Calculate score from grades lookup table\n * If exact range not found, use the score of the largest minValue that is <= value\n */\nfunction calculateScoreFromGrades(value: number, grades: KpiGrade[]): number | null {\n // First try to find exact range match\n for (const grade of grades) {\n if (value >= grade.minValue && value <= grade.maxValue) {\n return grade.score || 0\n }\n }\n \n // If no exact match, find the grade with largest minValue that is <= value\n let bestGrade: KpiGrade | null = null\n let bestMinValue = -Infinity\n \n for (const grade of grades) {\n if (grade.minValue <= value && grade.minValue > bestMinValue) {\n bestGrade = grade\n bestMinValue = grade.minValue\n }\n }\n \n if (bestGrade) {\n return bestGrade.score || 0\n }\n \n return null // Value is smaller than all minValues in lookup table\n}\n\n/**\n * List KPIs that have lookup tables (grades)\n */\nexport async function listKpisWithLookupTables(): Promise<void> {\n // Set NODE_ENV if not set\n if (!process.env.NODE_ENV) {\n process.env.NODE_ENV = 'development'\n }\n\n // Initialize Things-Factory environment\n const { config } = require('@things-factory/env')\n const ormconfig = require('@things-factory/shell/dist-server/initializers/ormconfig.js')\n const connectionConfig = config.get('ormconfig')\n\n let connection\n\n try {\n console.log('🔌 Connecting to database...')\n connection = await createConnection({\n ...ormconfig,\n ...connectionConfig,\n logging: false\n })\n\n const { addDataSource } = require('@things-factory/shell')\n addDataSource('default', connection)\n\n const { getRepository } = require('@things-factory/shell')\n const { Kpi } = require('@things-factory/kpi')\n const kpiRepository = getRepository(Kpi)\n\n // Get KPIs with grades\n const kpis = await kpiRepository\n .createQueryBuilder('kpi')\n .leftJoinAndSelect('kpi.domain', 'domain')\n .where('kpi.grades IS NOT NULL')\n .andWhere('domain.name = :domainName', { domainName: 'SYSTEM' })\n .getMany()\n\n console.log(`📁 KPIs with lookup tables (${kpis.length}):\\n`)\n\n if (kpis.length === 0) {\n console.log(' No KPIs found with lookup tables.')\n return\n }\n\n kpis.forEach((kpi, index) => {\n const gradeCount = kpi.grades ? kpi.grades.length : 0\n console.log(` ${(index + 1).toString().padStart(2)}: ${kpi.name} (${gradeCount} grades)`)\n })\n\n console.log(`\\n📈 Total: ${kpis.length} KPIs with lookup tables`)\n\n } catch (error) {\n console.error('❌ Error listing KPIs:', error)\n } finally {\n if (connection) {\n await connection.close()\n }\n }\n}\n\n/**\n * CLI execution when called directly\n */\nasync function main() {\n const args = process.argv.slice(2)\n\n try {\n if (args.includes('--help') || args.includes('-h')) {\n console.log(`\n🎯 KPI Score Calculator\n\nUsage:\n ts-node server/scripts/calculate-kpi-scores.ts [options] [kpiName]\n\nOptions:\n --list, -l List KPIs that have lookup tables\n --force, -f Force recalculate all scores (not just null/zero ones)\n --help, -h Show this help\n\nExamples:\n ts-node server/scripts/calculate-kpi-scores.ts # Calculate scores for null/zero values only\n ts-node server/scripts/calculate-kpi-scores.ts --force # Recalculate ALL scores\n ts-node server/scripts/calculate-kpi-scores.ts \"X11. 연면적 대비 공사기간\" # Calculate for specific KPI\n ts-node server/scripts/calculate-kpi-scores.ts --list # List KPIs with lookup tables\n\nNote: By default, only processes kpi-values with null or zero scores.\n Use --force to recalculate all scores.\n `)\n return\n }\n\n if (args.includes('--list') || args.includes('-l')) {\n await listKpisWithLookupTables()\n return\n }\n\n const forceRecalculate = args.includes('--force') || args.includes('-f')\n const specificKpiName = args.find(arg => !arg.startsWith('--'))\n \n if (specificKpiName) {\n console.log(`🎯 Calculating scores for specific KPI: ${specificKpiName}`)\n console.log(` Mode: ${forceRecalculate ? 'Force recalculate ALL' : 'Only null/zero scores'}`)\n await calculateKpiScores(specificKpiName, forceRecalculate)\n } else {\n console.log(`🎯 Calculating scores for all KPIs with lookup tables`)\n console.log(` Mode: ${forceRecalculate ? 'Force recalculate ALL' : 'Only null/zero scores'}`)\n await calculateKpiScores(undefined, forceRecalculate)\n }\n\n console.log('\\n✨ Done!')\n \n } catch (error) {\n console.error('\\n❌ Script failed:', error.message)\n process.exit(1)\n }\n}\n\n// Handle uncaught errors\nprocess.on('unhandledRejection', (error: any) => {\n console.error('❌ Unhandled error:', error.message || error)\n process.exit(1)\n})\n\n// Run if called directly\nif (require.main === module) {\n main()\n}"]}
1
+ {"version":3,"file":"calculate-kpi-scores.js","sourceRoot":"","sources":["../../server/scripts/calculate-kpi-scores.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env ts-node\n\nimport { createConnection } from 'typeorm'\nimport * as fs from 'fs'\nimport * as path from 'path'\n\ninterface KpiGrade {\n name: string\n minValue: number\n maxValue: number\n score?: number\n color?: string\n description?: string\n}\n\ninterface Grade2DRow {\n progressRate: number\n boundary5to4: number\n boundary4to3: number\n boundary3to2: number\n boundary2to1: number\n}\n\ninterface Grade2DLookup {\n type: 'PROGRESS_DEVIATION_LOOKUP'\n rows: Grade2DRow[]\n}\n\ninterface KpiRecord {\n id: string\n name: string\n grades: KpiGrade[] | Grade2DLookup | any\n}\n\ninterface KpiValueRecord {\n id: string\n value: number\n score?: number\n group?: string\n kpi: KpiRecord\n}\n\nfunction isGrade2DLookup(grades: any): grades is Grade2DLookup {\n return grades && typeof grades === 'object' && !Array.isArray(grades) && grades.type === 'PROGRESS_DEVIATION_LOOKUP'\n}\n\n/**\n * 2D lookup table에서 점수 계산 (X13: 공정률 × 편차 → 점수)\n * @param deviationValue 편차율 (formula 결과)\n * @param grades 2D lookup grades 객체\n * @param progressRate 공정률 (0~100)\n */\nfunction calculate2DScore(deviationValue: number, grades: Grade2DLookup, progressRate: number): number | null {\n if (!grades.rows || grades.rows.length === 0) return null\n\n const progressIndex = Math.min(99, Math.max(0, Math.floor(progressRate)))\n const row = grades.rows.find(r => r.progressRate === progressIndex)\n if (!row) return null\n\n if (deviationValue < row.boundary5to4) return 5\n if (deviationValue < row.boundary4to3) return 4\n if (deviationValue < row.boundary3to2) return 3\n if (deviationValue < row.boundary2to1) return 2\n return 1\n}\n\n/**\n * Calculate KPI scores based on lookup tables (grades)\n * Processes kpi-values and updates scores based on KPI grades\n */\nexport async function calculateKpiScores(specificKpiName?: string, forceRecalculate = false): Promise<void> {\n // Set NODE_ENV if not set\n if (!process.env.NODE_ENV) {\n process.env.NODE_ENV = 'development'\n }\n\n // Initialize Things-Factory environment\n const { config } = require('@things-factory/env')\n const ormconfig = require('@things-factory/shell/dist-server/initializers/ormconfig.js')\n const connectionConfig = config.get('ormconfig')\n\n let connection\n\n console.log('🚀 Starting KPI Score Calculation...')\n\n try {\n // Create database connection using Things-Factory pattern\n console.log('🔌 Connecting to database...')\n connection = await createConnection({\n ...ormconfig,\n ...connectionConfig,\n logging: false\n })\n\n // Register the connection with Things-Factory shell\n const { addDataSource } = require('@things-factory/shell')\n addDataSource('default', connection)\n\n console.log('✅ Database connected')\n\n // Now we can use getRepository with the registered connection\n const { getRepository } = require('@things-factory/shell')\n const { Kpi } = require('@things-factory/kpi')\n const kpiRepository = getRepository(Kpi)\n\n // Get KPI-Value repository (assuming it exists)\n let kpiValueRepository\n try {\n const { KpiValue } = require('@things-factory/kpi')\n kpiValueRepository = getRepository(KpiValue)\n } catch (error) {\n console.error('❌ KpiValue entity not found. Please ensure it exists in @things-factory/kpi')\n return\n }\n\n // Get KPIs with grades (lookup tables)\n let kpisQuery = kpiRepository\n .createQueryBuilder('kpi')\n .leftJoinAndSelect('kpi.domain', 'domain')\n .where('kpi.grades IS NOT NULL')\n .andWhere('domain.name = :domainName', { domainName: 'SYSTEM' })\n\n if (specificKpiName) {\n kpisQuery = kpisQuery.andWhere('kpi.name = :name', { name: specificKpiName })\n console.log(`🎯 Processing specific KPI: ${specificKpiName}`)\n } else {\n console.log('🎯 Processing all KPIs with lookup tables')\n }\n\n const kpis = await kpisQuery.getMany()\n\n if (kpis.length === 0) {\n console.log('⚠️ No KPIs found with lookup tables (grades)')\n return\n }\n\n console.log(`📊 Found ${kpis.length} KPIs with lookup tables`)\n\n let totalProcessed = 0\n let totalUpdated = 0\n let errorCount = 0\n\n // 2D lookup KPI (X13)에 필요한 Project entity 준비\n let projectRepository: any = null\n const progressRateCache = new Map<string, number>()\n\n try {\n const { Project } = require('@dssp/project')\n projectRepository = getRepository(Project)\n } catch {\n console.log('⚠️ @dssp/project not found — 2D lookup KPIs will use default progressRate')\n }\n\n for (const kpi of kpis) {\n try {\n console.log(`\\n📄 Processing KPI: ${kpi.name}`)\n\n const is2D = isGrade2DLookup(kpi.grades)\n\n if (!is2D && (!kpi.grades || !Array.isArray(kpi.grades) || kpi.grades.length === 0)) {\n console.log(` ⚠️ No grades found, skipping`)\n continue\n }\n\n if (is2D) {\n console.log(` 📈 2D Lookup table: ${kpi.grades.rows.length} rows`)\n } else {\n console.log(` 📈 Lookup table: ${kpi.grades.length} grades`)\n }\n\n // Get KPI values for this KPI\n let kpiValuesQuery = kpiValueRepository\n .createQueryBuilder('kpiValue')\n .leftJoinAndSelect('kpiValue.kpi', 'kpi')\n .where('kpi.id = :kpiId', { kpiId: kpi.id })\n .andWhere('kpiValue.value IS NOT NULL')\n\n if (!forceRecalculate) {\n // Only process null or 0 scores by default\n kpiValuesQuery = kpiValuesQuery.andWhere('(kpiValue.score IS NULL OR kpiValue.score = 0)')\n }\n\n const kpiValues = await kpiValuesQuery.getMany()\n\n if (kpiValues.length === 0) {\n console.log(` ✅ No null/zero scores found (all values already calculated)`)\n continue\n }\n\n console.log(` 🔢 Processing ${kpiValues.length} null/zero scores`)\n\n let updatedCount = 0\n\n for (const kpiValue of kpiValues) {\n const value = kpiValue.value\n let calculatedScore: number | null\n\n if (is2D) {\n // 2D lookup: project의 totalProgress 조회\n let progressRate = 50 // default\n const projectId = kpiValue.group\n if (projectId && projectRepository) {\n if (progressRateCache.has(projectId)) {\n progressRate = progressRateCache.get(projectId)!\n } else {\n const project = await projectRepository.findOne({ where: { id: projectId } })\n progressRate = project?.totalProgress ?? 50\n progressRateCache.set(projectId, progressRate)\n }\n }\n calculatedScore = calculate2DScore(value, kpi.grades as Grade2DLookup, progressRate)\n } else {\n calculatedScore = calculateScoreFromGrades(value, kpi.grades as KpiGrade[])\n }\n\n if (calculatedScore !== null) {\n // Only update if the score is actually different\n if (kpiValue.score !== calculatedScore) {\n const oldScore = kpiValue.score\n kpiValue.score = calculatedScore\n await kpiValueRepository.save(kpiValue)\n updatedCount++\n\n console.log(` 📊 Value ${value} → Score ${calculatedScore} (was ${oldScore || 'null'})`)\n }\n } else {\n console.log(` ⚠️ Value ${value} is below all ranges in lookup table`)\n }\n\n totalProcessed++\n }\n\n console.log(` ✅ Updated ${updatedCount}/${kpiValues.length} values`)\n totalUpdated += updatedCount\n\n } catch (kpiError) {\n console.log(` ❌ Error processing KPI ${kpi.name}: ${kpiError.message}`)\n errorCount++\n }\n }\n\n console.log(`\\n🎉 KPI Score Calculation Complete!`)\n console.log(` 📊 KPIs processed: ${kpis.length}`)\n console.log(` 🔢 Total values processed: ${totalProcessed}`)\n console.log(` ✅ Scores updated: ${totalUpdated}`)\n console.log(` ❌ Errors: ${errorCount}`)\n\n if (errorCount > 0) {\n console.log(`\\n⚠️ Some KPIs had errors. Check the logs above for details.`)\n }\n\n } catch (error) {\n console.error(`❌ Fatal error during score calculation:`, error)\n throw error\n } finally {\n if (connection) {\n await connection.close()\n console.log('🔌 Database connection closed')\n }\n }\n}\n\n/**\n * Calculate score from grades lookup table\n * If exact range not found, use the score of the largest minValue that is <= value\n */\nfunction calculateScoreFromGrades(value: number, grades: KpiGrade[]): number | null {\n // First try to find exact range match\n for (const grade of grades) {\n if (value >= grade.minValue && value <= grade.maxValue) {\n return grade.score || 0\n }\n }\n \n // If no exact match, find the grade with largest minValue that is <= value\n let bestGrade: KpiGrade | null = null\n let bestMinValue = -Infinity\n \n for (const grade of grades) {\n if (grade.minValue <= value && grade.minValue > bestMinValue) {\n bestGrade = grade\n bestMinValue = grade.minValue\n }\n }\n \n if (bestGrade) {\n return bestGrade.score || 0\n }\n \n return null // Value is smaller than all minValues in lookup table\n}\n\n/**\n * List KPIs that have lookup tables (grades)\n */\nexport async function listKpisWithLookupTables(): Promise<void> {\n // Set NODE_ENV if not set\n if (!process.env.NODE_ENV) {\n process.env.NODE_ENV = 'development'\n }\n\n // Initialize Things-Factory environment\n const { config } = require('@things-factory/env')\n const ormconfig = require('@things-factory/shell/dist-server/initializers/ormconfig.js')\n const connectionConfig = config.get('ormconfig')\n\n let connection\n\n try {\n console.log('🔌 Connecting to database...')\n connection = await createConnection({\n ...ormconfig,\n ...connectionConfig,\n logging: false\n })\n\n const { addDataSource } = require('@things-factory/shell')\n addDataSource('default', connection)\n\n const { getRepository } = require('@things-factory/shell')\n const { Kpi } = require('@things-factory/kpi')\n const kpiRepository = getRepository(Kpi)\n\n // Get KPIs with grades\n const kpis = await kpiRepository\n .createQueryBuilder('kpi')\n .leftJoinAndSelect('kpi.domain', 'domain')\n .where('kpi.grades IS NOT NULL')\n .andWhere('domain.name = :domainName', { domainName: 'SYSTEM' })\n .getMany()\n\n console.log(`📁 KPIs with lookup tables (${kpis.length}):\\n`)\n\n if (kpis.length === 0) {\n console.log(' No KPIs found with lookup tables.')\n return\n }\n\n kpis.forEach((kpi, index) => {\n const gradeCount = kpi.grades ? kpi.grades.length : 0\n console.log(` ${(index + 1).toString().padStart(2)}: ${kpi.name} (${gradeCount} grades)`)\n })\n\n console.log(`\\n📈 Total: ${kpis.length} KPIs with lookup tables`)\n\n } catch (error) {\n console.error('❌ Error listing KPIs:', error)\n } finally {\n if (connection) {\n await connection.close()\n }\n }\n}\n\n/**\n * CLI execution when called directly\n */\nasync function main() {\n const args = process.argv.slice(2)\n\n try {\n if (args.includes('--help') || args.includes('-h')) {\n console.log(`\n🎯 KPI Score Calculator\n\nUsage:\n ts-node server/scripts/calculate-kpi-scores.ts [options] [kpiName]\n\nOptions:\n --list, -l List KPIs that have lookup tables\n --force, -f Force recalculate all scores (not just null/zero ones)\n --help, -h Show this help\n\nExamples:\n ts-node server/scripts/calculate-kpi-scores.ts # Calculate scores for null/zero values only\n ts-node server/scripts/calculate-kpi-scores.ts --force # Recalculate ALL scores\n ts-node server/scripts/calculate-kpi-scores.ts \"X11. 연면적 대비 공사기간\" # Calculate for specific KPI\n ts-node server/scripts/calculate-kpi-scores.ts --list # List KPIs with lookup tables\n\nNote: By default, only processes kpi-values with null or zero scores.\n Use --force to recalculate all scores.\n `)\n return\n }\n\n if (args.includes('--list') || args.includes('-l')) {\n await listKpisWithLookupTables()\n return\n }\n\n const forceRecalculate = args.includes('--force') || args.includes('-f')\n const specificKpiName = args.find(arg => !arg.startsWith('--'))\n \n if (specificKpiName) {\n console.log(`🎯 Calculating scores for specific KPI: ${specificKpiName}`)\n console.log(` Mode: ${forceRecalculate ? 'Force recalculate ALL' : 'Only null/zero scores'}`)\n await calculateKpiScores(specificKpiName, forceRecalculate)\n } else {\n console.log(`🎯 Calculating scores for all KPIs with lookup tables`)\n console.log(` Mode: ${forceRecalculate ? 'Force recalculate ALL' : 'Only null/zero scores'}`)\n await calculateKpiScores(undefined, forceRecalculate)\n }\n\n console.log('\\n✨ Done!')\n \n } catch (error) {\n console.error('\\n❌ Script failed:', error.message)\n process.exit(1)\n }\n}\n\n// Handle uncaught errors\nprocess.on('unhandledRejection', (error: any) => {\n console.error('❌ Unhandled error:', error.message || error)\n process.exit(1)\n})\n\n// Run if called directly\nif (require.main === module) {\n main()\n}"]}
@@ -4,6 +4,10 @@
4
4
  * This can be called directly from migrations or other server-side scripts
5
5
  */
6
6
  export declare function loadKpiGradeData(specificFile?: string): Promise<void>;
7
+ /**
8
+ * X31/X32 KPI를 비활성화 (active = false, grades = null)
9
+ */
10
+ export declare function deactivateDeletedKpis(): Promise<void>;
7
11
  /**
8
12
  * List available grade data files
9
13
  */
@@ -2,11 +2,26 @@
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.loadKpiGradeData = loadKpiGradeData;
5
+ exports.deactivateDeletedKpis = deactivateDeletedKpis;
5
6
  exports.listGradeDataFiles = listGradeDataFiles;
6
7
  const tslib_1 = require("tslib");
7
8
  const typeorm_1 = require("typeorm");
8
9
  const fs = tslib_1.__importStar(require("fs"));
9
10
  const path = tslib_1.__importStar(require("path"));
11
+ /** X31/X32 비활성화 대상 KPI 이름 */
12
+ const DEACTIVATE_KPI_NAMES = ['X31. 품질시험 불합격률', 'X32. 검수자재 불합격률'];
13
+ function isGrade2DLookup(grades) {
14
+ return grades && typeof grades === 'object' && !Array.isArray(grades) && (grades.type === 'PROGRESS_DEVIATION_LOOKUP' || grades.type === 'PROGRESS_DEVIATION_LOOKUP');
15
+ }
16
+ function normalize2DGrades(grades) {
17
+ return Object.assign(Object.assign({}, grades), { type: 'PROGRESS_DEVIATION_LOOKUP' });
18
+ }
19
+ function getGradeCount(grades) {
20
+ if (isGrade2DLookup(grades)) {
21
+ return grades.rows.length;
22
+ }
23
+ return Array.isArray(grades) ? grades.length : 0;
24
+ }
10
25
  /**
11
26
  * Load KPI grade data from JSON files - Migration Style
12
27
  * This can be called directly from migrations or other server-side scripts
@@ -66,26 +81,40 @@ async function loadKpiGradeData(specificFile) {
66
81
  const filePath = path.join(gradeDataPath, file);
67
82
  const fileContent = fs.readFileSync(filePath, 'utf8');
68
83
  const gradeData = JSON.parse(fileContent);
69
- // Validate grade data structure
70
- if (!gradeData.kpiName || !gradeData.grades || !Array.isArray(gradeData.grades)) {
84
+ // Validate grade data structure (1D array or 2D lookup object)
85
+ if (!gradeData.kpiName || !gradeData.grades) {
71
86
  console.log(` ❌ Invalid structure - missing kpiName or grades`);
72
87
  errorCount++;
73
88
  continue;
74
89
  }
90
+ const is2D = isGrade2DLookup(gradeData.grades);
91
+ if (!is2D && !Array.isArray(gradeData.grades)) {
92
+ console.log(` ❌ Invalid grades format - expected array or 2d-lookup object`);
93
+ errorCount++;
94
+ continue;
95
+ }
96
+ const gradeCount = getGradeCount(gradeData.grades);
75
97
  console.log(` 🔍 KPI Name: ${gradeData.kpiName}`);
76
- console.log(` 📊 Grades: ${gradeData.grades.length} entries`);
98
+ console.log(` 📊 Grades: ${gradeCount} entries${is2D ? ' (2D lookup)' : ''}`);
77
99
  // Find KPI by name in SYSTEM domain
78
100
  const kpi = await kpiRepository.findOne({
79
101
  where: { name: gradeData.kpiName, domain: { name: 'SYSTEM' } },
80
102
  relations: ['domain']
81
103
  });
82
104
  if (kpi) {
83
- // Update grades data
84
- const originalGradesCount = kpi.grades ? kpi.grades.length : 0;
85
- kpi.grades = gradeData.grades;
105
+ // Update grades data (normalize 2D type string to 'PROGRESS_DEVIATION_LOOKUP')
106
+ const originalGradesCount = kpi.grades ? getGradeCount(kpi.grades) : 0;
107
+ if (is2D) {
108
+ kpi.grades = normalize2DGrades(gradeData.grades);
109
+ kpi.scoreType = 'CUSTOM';
110
+ }
111
+ else {
112
+ kpi.grades = gradeData.grades;
113
+ kpi.scoreType = 'LOOKUP';
114
+ }
86
115
  await kpiRepository.save(kpi);
87
- console.log(` ✅ Updated successfully`);
88
- console.log(` 📈 Grades: ${originalGradesCount} → ${gradeData.grades.length}`);
116
+ console.log(` ✅ Updated successfully (scoreType: ${kpi.scoreType})`);
117
+ console.log(` 📈 Grades: ${originalGradesCount} → ${gradeCount}`);
89
118
  successCount++;
90
119
  }
91
120
  else {
@@ -117,6 +146,54 @@ async function loadKpiGradeData(specificFile) {
117
146
  }
118
147
  }
119
148
  }
149
+ /**
150
+ * X31/X32 KPI를 비활성화 (active = false, grades = null)
151
+ */
152
+ async function deactivateDeletedKpis() {
153
+ if (!process.env.NODE_ENV) {
154
+ process.env.NODE_ENV = 'development';
155
+ }
156
+ const { config } = require('@things-factory/env');
157
+ const ormconfig = require('@things-factory/shell/dist-server/initializers/ormconfig.js');
158
+ const connectionConfig = config.get('ormconfig');
159
+ let connection;
160
+ console.log('🚫 Deactivating deleted KPIs (X31, X32)...');
161
+ try {
162
+ console.log('🔌 Connecting to database...');
163
+ connection = await (0, typeorm_1.createConnection)(Object.assign(Object.assign(Object.assign({}, ormconfig), connectionConfig), { logging: false }));
164
+ const { addDataSource } = require('@things-factory/shell');
165
+ addDataSource('default', connection);
166
+ const { getRepository } = require('@things-factory/shell');
167
+ const { Kpi } = require('@things-factory/kpi');
168
+ const kpiRepository = getRepository(Kpi);
169
+ for (const kpiName of DEACTIVATE_KPI_NAMES) {
170
+ const kpi = await kpiRepository.findOne({
171
+ where: { name: kpiName, domain: { name: 'SYSTEM' } },
172
+ relations: ['domain']
173
+ });
174
+ if (kpi) {
175
+ kpi.active = false;
176
+ kpi.grades = null;
177
+ await kpiRepository.save(kpi);
178
+ console.log(` ✅ Deactivated: ${kpiName}`);
179
+ }
180
+ else {
181
+ console.log(` ⚠️ KPI not found: ${kpiName}`);
182
+ }
183
+ }
184
+ console.log('\n🎉 Deactivation complete!');
185
+ }
186
+ catch (error) {
187
+ console.error('❌ Error deactivating KPIs:', error);
188
+ throw error;
189
+ }
190
+ finally {
191
+ if (connection) {
192
+ await connection.close();
193
+ console.log('🔌 Database connection closed');
194
+ }
195
+ }
196
+ }
120
197
  /**
121
198
  * List available grade data files
122
199
  */
@@ -154,16 +231,19 @@ Usage:
154
231
  ts-node server/scripts/load-grade-data-migration.ts [options] [fileName]
155
232
 
156
233
  Options:
157
- --list, -l List available grade data files
158
- --help, -h Show this help
234
+ --list, -l List available grade data files
235
+ --deactivate Deactivate X31/X32 KPIs (set active=false, grades=null)
236
+ --help, -h Show this help
159
237
 
160
238
  Examples:
161
239
  ts-node server/scripts/load-grade-data-migration.ts # Load all files
162
240
  ts-node server/scripts/load-grade-data-migration.ts x11-performance-table.json # Load specific file
163
241
  ts-node server/scripts/load-grade-data-migration.ts --list # List files
242
+ ts-node server/scripts/load-grade-data-migration.ts --deactivate # Deactivate X31/X32
164
243
 
165
244
  Note: This script connects to the database using the current Things-Factory configuration.
166
245
  Make sure the application is properly configured before running.
246
+ Supports both 1D array grades and 2D lookup grades (X13).
167
247
  `);
168
248
  return;
169
249
  }
@@ -171,6 +251,11 @@ Note: This script connects to the database using the current Things-Factory conf
171
251
  listGradeDataFiles();
172
252
  return;
173
253
  }
254
+ if (args.includes('--deactivate')) {
255
+ await deactivateDeletedKpis();
256
+ console.log('\n✨ Done!');
257
+ return;
258
+ }
174
259
  const specificFile = args.find(arg => !arg.startsWith('--'));
175
260
  if (specificFile) {
176
261
  console.log(`🎯 Loading specific file: ${specificFile}`);
@@ -1 +1 @@
1
- {"version":3,"file":"load-grade-data-migration.js","sourceRoot":"","sources":["../../server/scripts/load-grade-data-migration.ts"],"names":[],"mappings":";;;AAwBA,4CA+HC;AAKD,gDAsBC;;AAhLD,qCAA0C;AAC1C,+CAAwB;AACxB,mDAA4B;AAgB5B;;;GAGG;AACI,KAAK,UAAU,gBAAgB,CAAC,YAAqB;IAC1D,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAA;IAExD,0BAA0B;IAC1B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,QAAQ,GAAG,aAAa,CAAA;IACtC,CAAC;IAED,wCAAwC;IACxC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;IACjD,MAAM,SAAS,GAAG,OAAO,CAAC,6DAA6D,CAAC,CAAA;IACxF,MAAM,gBAAgB,GAAG,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IAEhD,IAAI,UAAU,CAAA;IAEd,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAA;IAC3C,OAAO,CAAC,GAAG,CAAC,wBAAwB,aAAa,EAAE,CAAC,CAAA;IAEpD,IAAI,CAAC;QACH,0DAA0D;QAC1D,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAA;QAC3C,UAAU,GAAG,MAAM,IAAA,0BAAgB,gDAC9B,SAAS,GACT,gBAAgB,KACnB,OAAO,EAAE,KAAK,IACd,CAAA;QAEF,oDAAoD;QACpD,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAA;QAC1D,aAAa,CAAC,SAAS,EAAE,UAAU,CAAC,CAAA;QAEpC,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAA;QAEnC,uCAAuC;QACvC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;YAClC,OAAO,CAAC,KAAK,CAAC,qCAAqC,aAAa,EAAE,CAAC,CAAA;YACnE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;QACnD,CAAC;QAED,uBAAuB;QACvB,IAAI,KAAe,CAAA;QACnB,IAAI,YAAY,EAAE,CAAC;YACjB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC;gBAC3D,MAAM,IAAI,KAAK,CAAC,mBAAmB,YAAY,EAAE,CAAC,CAAA;YACpD,CAAC;YACD,KAAK,GAAG,CAAC,YAAY,CAAC,CAAA;YACtB,OAAO,CAAC,GAAG,CAAC,8BAA8B,YAAY,EAAE,CAAC,CAAA;QAC3D,CAAC;aAAM,CAAC;YACN,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAA;YAC5E,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,CAAC,MAAM,mBAAmB,CAAC,CAAA;QAC1D,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAA;YACjD,OAAM;QACR,CAAC;QAED,IAAI,YAAY,GAAG,CAAC,CAAA;QACpB,IAAI,UAAU,GAAG,CAAC,CAAA;QAElB,8DAA8D;QAC9D,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAAA;QAC1D,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAA;QAC9C,MAAM,aAAa,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA;QAExC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,EAAE,CAAC,CAAA;gBAEvC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,CAAA;gBAC/C,MAAM,WAAW,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;gBACrD,MAAM,SAAS,GAAc,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;gBAEpD,gCAAgC;gBAChC,IAAI,CAAC,SAAS,CAAC,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;oBAChF,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAA;oBACjE,UAAU,EAAE,CAAA;oBACZ,SAAQ;gBACV,CAAC;gBAED,OAAO,CAAC,GAAG,CAAC,mBAAmB,SAAS,CAAC,OAAO,EAAE,CAAC,CAAA;gBACnD,OAAO,CAAC,GAAG,CAAC,iBAAiB,SAAS,CAAC,MAAM,CAAC,MAAM,UAAU,CAAC,CAAA;gBAE/D,oCAAoC;gBACpC,MAAM,GAAG,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC;oBACtC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;oBAC9D,SAAS,EAAE,CAAC,QAAQ,CAAC;iBACtB,CAAC,CAAA;gBAEF,IAAI,GAAG,EAAE,CAAC;oBACR,qBAAqB;oBACrB,MAAM,mBAAmB,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;oBAC9D,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,CAAA;oBAC7B,MAAM,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;oBAE7B,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAA;oBACxC,OAAO,CAAC,GAAG,CAAC,iBAAiB,mBAAmB,MAAM,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAA;oBAChF,YAAY,EAAE,CAAA;gBAChB,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,GAAG,CAAC,0CAA0C,SAAS,CAAC,OAAO,EAAE,CAAC,CAAA;oBAC1E,UAAU,EAAE,CAAA;gBACd,CAAC;YAEH,CAAC;YAAC,OAAO,SAAS,EAAE,CAAC;gBACnB,OAAO,CAAC,GAAG,CAAC,+BAA+B,SAAS,CAAC,OAAO,EAAE,CAAC,CAAA;gBAC/D,UAAU,EAAE,CAAA;YACd,CAAC;QACH,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAA;QACpD,OAAO,CAAC,GAAG,CAAC,sBAAsB,KAAK,CAAC,MAAM,EAAE,CAAC,CAAA;QACjD,OAAO,CAAC,GAAG,CAAC,oBAAoB,YAAY,EAAE,CAAC,CAAA;QAC/C,OAAO,CAAC,GAAG,CAAC,gBAAgB,UAAU,EAAE,CAAC,CAAA;QAEzC,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAA;QAC/E,CAAC;IAEH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,0CAA0C,EAAE,KAAK,CAAC,CAAA;QAChE,MAAM,KAAK,CAAA;IACb,CAAC;YAAS,CAAC;QACT,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,UAAU,CAAC,KAAK,EAAE,CAAA;YACxB,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAA;QAC9C,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAgB,kBAAkB;IAChC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAA;IAExD,IAAI,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAA;YAChD,OAAO,EAAE,CAAA;QACX,CAAC;QAED,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAA;QAElF,OAAO,CAAC,GAAG,CAAC,oCAAoC,aAAa,KAAK,CAAC,CAAA;QACnE,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YAC5B,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAA;QAClE,CAAC,CAAC,CAAA;QACF,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAA;QAEhD,OAAO,KAAK,CAAA;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,KAAK,CAAC,CAAA;QAC7D,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAElC,IAAI,CAAC;QACH,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;OAiBX,CAAC,CAAA;YACF,OAAM;QACR,CAAC;QAED,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,kBAAkB,EAAE,CAAA;YACpB,OAAM;QACR,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAA;QAE5D,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,6BAA6B,YAAY,EAAE,CAAC,CAAA;YACxD,MAAM,gBAAgB,CAAC,YAAY,CAAC,CAAA;QACtC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAA;YAC9C,MAAM,gBAAgB,EAAE,CAAA;QAC1B,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IAE1B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAA;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC;AAED,yBAAyB;AACzB,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC5B,IAAI,EAAE,CAAA;AACR,CAAC","sourcesContent":["#!/usr/bin/env ts-node\n\nimport { createConnection } from 'typeorm'\nimport * as fs from 'fs'\nimport * as path from 'path'\n\ninterface GradeData {\n kpiName: string\n version: number\n description: string\n grades: Array<{\n name: string\n minValue: number\n maxValue: number\n score?: number\n color?: string\n description?: string\n }>\n}\n\n/**\n * Load KPI grade data from JSON files - Migration Style\n * This can be called directly from migrations or other server-side scripts\n */\nexport async function loadKpiGradeData(specificFile?: string): Promise<void> {\n const gradeDataPath = path.join(__dirname, 'grade-data')\n \n // Set NODE_ENV if not set\n if (!process.env.NODE_ENV) {\n process.env.NODE_ENV = 'development'\n }\n\n // Initialize Things-Factory environment\n const { config } = require('@things-factory/env')\n const ormconfig = require('@things-factory/shell/dist-server/initializers/ormconfig.js')\n const connectionConfig = config.get('ormconfig')\n\n let connection\n\n console.log('🚀 Loading KPI Grade Data...')\n console.log(`📁 Source directory: ${gradeDataPath}`)\n\n try {\n // Create database connection using Things-Factory pattern\n console.log('🔌 Connecting to database...')\n connection = await createConnection({\n ...ormconfig,\n ...connectionConfig,\n logging: false\n })\n\n // Register the connection with Things-Factory shell\n const { addDataSource } = require('@things-factory/shell')\n addDataSource('default', connection)\n\n console.log('✅ Database connected')\n\n // Check if grade-data directory exists\n if (!fs.existsSync(gradeDataPath)) {\n console.error(`❌ Grade data directory not found: ${gradeDataPath}`)\n throw new Error('Grade data directory not found')\n }\n\n // Get files to process\n let files: string[]\n if (specificFile) {\n if (!fs.existsSync(path.join(gradeDataPath, specificFile))) {\n throw new Error(`File not found: ${specificFile}`)\n }\n files = [specificFile]\n console.log(`📄 Processing single file: ${specificFile}`)\n } else {\n files = fs.readdirSync(gradeDataPath).filter(file => file.endsWith('.json'))\n console.log(`📁 Found ${files.length} grade data files`)\n }\n\n if (files.length === 0) {\n console.log('⚠️ No JSON files found to process')\n return\n }\n\n let successCount = 0\n let errorCount = 0\n\n // Now we can use getRepository with the registered connection\n const { getRepository } = require('@things-factory/shell')\n const { Kpi } = require('@things-factory/kpi')\n const kpiRepository = getRepository(Kpi)\n\n for (const file of files) {\n try {\n console.log(`\\n📄 Processing: ${file}`)\n \n const filePath = path.join(gradeDataPath, file)\n const fileContent = fs.readFileSync(filePath, 'utf8')\n const gradeData: GradeData = JSON.parse(fileContent)\n\n // Validate grade data structure\n if (!gradeData.kpiName || !gradeData.grades || !Array.isArray(gradeData.grades)) {\n console.log(` ❌ Invalid structure - missing kpiName or grades`)\n errorCount++\n continue\n }\n\n console.log(` 🔍 KPI Name: ${gradeData.kpiName}`)\n console.log(` 📊 Grades: ${gradeData.grades.length} entries`)\n\n // Find KPI by name in SYSTEM domain\n const kpi = await kpiRepository.findOne({\n where: { name: gradeData.kpiName, domain: { name: 'SYSTEM' } },\n relations: ['domain']\n })\n\n if (kpi) {\n // Update grades data\n const originalGradesCount = kpi.grades ? kpi.grades.length : 0\n kpi.grades = gradeData.grades\n await kpiRepository.save(kpi)\n \n console.log(` ✅ Updated successfully`)\n console.log(` 📈 Grades: ${originalGradesCount} → ${gradeData.grades.length}`)\n successCount++\n } else {\n console.log(` ⚠️ KPI not found in SYSTEM domain: ${gradeData.kpiName}`)\n errorCount++\n }\n \n } catch (fileError) {\n console.log(` ❌ File processing error: ${fileError.message}`)\n errorCount++\n }\n }\n\n console.log(`\\n🎉 KPI Grade Data Loading Complete!`)\n console.log(` 📊 Total files: ${files.length}`)\n console.log(` ✅ Successful: ${successCount}`)\n console.log(` ❌ Errors: ${errorCount}`)\n\n if (errorCount > 0) {\n console.log(`\\n⚠️ Some files had errors. Check the logs above for details.`)\n }\n\n } catch (error) {\n console.error(`❌ Fatal error during grade data loading:`, error)\n throw error\n } finally {\n if (connection) {\n await connection.close()\n console.log('🔌 Database connection closed')\n }\n }\n}\n\n/**\n * List available grade data files\n */\nexport function listGradeDataFiles(): string[] {\n const gradeDataPath = path.join(__dirname, 'grade-data')\n \n try {\n if (!fs.existsSync(gradeDataPath)) {\n console.log('📁 Grade data directory not found')\n return []\n }\n \n const files = fs.readdirSync(gradeDataPath).filter(file => file.endsWith('.json'))\n \n console.log(`📁 Available grade data files in ${gradeDataPath}:\\n`)\n files.forEach((file, index) => {\n console.log(` ${(index + 1).toString().padStart(2)}: ${file}`)\n })\n console.log(`\\n📈 Total: ${files.length} files`)\n \n return files\n } catch (error) {\n console.error('❌ Error reading grade data directory:', error)\n return []\n }\n}\n\n/**\n * CLI execution when called directly\n */\nasync function main() {\n const args = process.argv.slice(2)\n\n try {\n if (args.includes('--help') || args.includes('-h')) {\n console.log(`\n🎯 KPI Grade Data Loader (Migration Style)\n\nUsage:\n ts-node server/scripts/load-grade-data-migration.ts [options] [fileName]\n\nOptions:\n --list, -l List available grade data files\n --help, -h Show this help\n\nExamples:\n ts-node server/scripts/load-grade-data-migration.ts # Load all files\n ts-node server/scripts/load-grade-data-migration.ts x11-performance-table.json # Load specific file\n ts-node server/scripts/load-grade-data-migration.ts --list # List files\n\nNote: This script connects to the database using the current Things-Factory configuration.\n Make sure the application is properly configured before running.\n `)\n return\n }\n\n if (args.includes('--list') || args.includes('-l')) {\n listGradeDataFiles()\n return\n }\n\n const specificFile = args.find(arg => !arg.startsWith('--'))\n \n if (specificFile) {\n console.log(`🎯 Loading specific file: ${specificFile}`)\n await loadKpiGradeData(specificFile)\n } else {\n console.log(`🎯 Loading all grade data files`)\n await loadKpiGradeData()\n }\n\n console.log('\\n✨ Done!')\n \n } catch (error) {\n console.error('\\n❌ Script failed:', error.message)\n process.exit(1)\n }\n}\n\n// Run if called directly\nif (require.main === module) {\n main()\n}"]}
1
+ {"version":3,"file":"load-grade-data-migration.js","sourceRoot":"","sources":["../../server/scripts/load-grade-data-migration.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env ts-node\n\nimport { createConnection } from 'typeorm'\nimport * as fs from 'fs'\nimport * as path from 'path'\n\ninterface GradeEntry {\n name: string\n minValue: number\n maxValue: number\n score?: number\n color?: string\n description?: string\n}\n\ninterface Grade2DLookup {\n type: 'PROGRESS_DEVIATION_LOOKUP' | 'PROGRESS_DEVIATION_LOOKUP'\n description?: string\n rows: Array<{\n progressRate: number\n boundary5to4: number\n boundary4to3: number\n boundary3to2: number\n boundary2to1: number\n }>\n}\n\ninterface GradeData {\n kpiName: string\n version: number\n description: string\n grades: GradeEntry[] | Grade2DLookup\n}\n\n/** X31/X32 비활성화 대상 KPI 이름 */\nconst DEACTIVATE_KPI_NAMES = ['X31. 품질시험 불합격률', 'X32. 검수자재 불합격률']\n\nfunction isGrade2DLookup(grades: any): grades is Grade2DLookup {\n return grades && typeof grades === 'object' && !Array.isArray(grades) && (grades.type === 'PROGRESS_DEVIATION_LOOKUP' || grades.type === 'PROGRESS_DEVIATION_LOOKUP')\n}\n\nfunction normalize2DGrades(grades: Grade2DLookup): Grade2DLookup {\n return { ...grades, type: 'PROGRESS_DEVIATION_LOOKUP' }\n}\n\nfunction getGradeCount(grades: GradeEntry[] | Grade2DLookup): number {\n if (isGrade2DLookup(grades)) {\n return grades.rows.length\n }\n return Array.isArray(grades) ? grades.length : 0\n}\n\n/**\n * Load KPI grade data from JSON files - Migration Style\n * This can be called directly from migrations or other server-side scripts\n */\nexport async function loadKpiGradeData(specificFile?: string): Promise<void> {\n const gradeDataPath = path.join(__dirname, 'grade-data')\n \n // Set NODE_ENV if not set\n if (!process.env.NODE_ENV) {\n process.env.NODE_ENV = 'development'\n }\n\n // Initialize Things-Factory environment\n const { config } = require('@things-factory/env')\n const ormconfig = require('@things-factory/shell/dist-server/initializers/ormconfig.js')\n const connectionConfig = config.get('ormconfig')\n\n let connection\n\n console.log('🚀 Loading KPI Grade Data...')\n console.log(`📁 Source directory: ${gradeDataPath}`)\n\n try {\n // Create database connection using Things-Factory pattern\n console.log('🔌 Connecting to database...')\n connection = await createConnection({\n ...ormconfig,\n ...connectionConfig,\n logging: false\n })\n\n // Register the connection with Things-Factory shell\n const { addDataSource } = require('@things-factory/shell')\n addDataSource('default', connection)\n\n console.log('✅ Database connected')\n\n // Check if grade-data directory exists\n if (!fs.existsSync(gradeDataPath)) {\n console.error(`❌ Grade data directory not found: ${gradeDataPath}`)\n throw new Error('Grade data directory not found')\n }\n\n // Get files to process\n let files: string[]\n if (specificFile) {\n if (!fs.existsSync(path.join(gradeDataPath, specificFile))) {\n throw new Error(`File not found: ${specificFile}`)\n }\n files = [specificFile]\n console.log(`📄 Processing single file: ${specificFile}`)\n } else {\n files = fs.readdirSync(gradeDataPath).filter(file => file.endsWith('.json'))\n console.log(`📁 Found ${files.length} grade data files`)\n }\n\n if (files.length === 0) {\n console.log('⚠️ No JSON files found to process')\n return\n }\n\n let successCount = 0\n let errorCount = 0\n\n // Now we can use getRepository with the registered connection\n const { getRepository } = require('@things-factory/shell')\n const { Kpi } = require('@things-factory/kpi')\n const kpiRepository = getRepository(Kpi)\n\n for (const file of files) {\n try {\n console.log(`\\n📄 Processing: ${file}`)\n \n const filePath = path.join(gradeDataPath, file)\n const fileContent = fs.readFileSync(filePath, 'utf8')\n const gradeData: GradeData = JSON.parse(fileContent)\n\n // Validate grade data structure (1D array or 2D lookup object)\n if (!gradeData.kpiName || !gradeData.grades) {\n console.log(` ❌ Invalid structure - missing kpiName or grades`)\n errorCount++\n continue\n }\n\n const is2D = isGrade2DLookup(gradeData.grades)\n if (!is2D && !Array.isArray(gradeData.grades)) {\n console.log(` ❌ Invalid grades format - expected array or 2d-lookup object`)\n errorCount++\n continue\n }\n\n const gradeCount = getGradeCount(gradeData.grades)\n console.log(` 🔍 KPI Name: ${gradeData.kpiName}`)\n console.log(` 📊 Grades: ${gradeCount} entries${is2D ? ' (2D lookup)' : ''}`)\n\n // Find KPI by name in SYSTEM domain\n const kpi = await kpiRepository.findOne({\n where: { name: gradeData.kpiName, domain: { name: 'SYSTEM' } },\n relations: ['domain']\n })\n\n if (kpi) {\n // Update grades data (normalize 2D type string to 'PROGRESS_DEVIATION_LOOKUP')\n const originalGradesCount = kpi.grades ? getGradeCount(kpi.grades) : 0\n if (is2D) {\n kpi.grades = normalize2DGrades(gradeData.grades as Grade2DLookup) as any\n kpi.scoreType = 'CUSTOM'\n } else {\n kpi.grades = gradeData.grades as any\n kpi.scoreType = 'LOOKUP'\n }\n await kpiRepository.save(kpi)\n\n console.log(` ✅ Updated successfully (scoreType: ${kpi.scoreType})`)\n console.log(` 📈 Grades: ${originalGradesCount} → ${gradeCount}`)\n successCount++\n } else {\n console.log(` ⚠️ KPI not found in SYSTEM domain: ${gradeData.kpiName}`)\n errorCount++\n }\n \n } catch (fileError) {\n console.log(` ❌ File processing error: ${fileError.message}`)\n errorCount++\n }\n }\n\n console.log(`\\n🎉 KPI Grade Data Loading Complete!`)\n console.log(` 📊 Total files: ${files.length}`)\n console.log(` ✅ Successful: ${successCount}`)\n console.log(` ❌ Errors: ${errorCount}`)\n\n if (errorCount > 0) {\n console.log(`\\n⚠️ Some files had errors. Check the logs above for details.`)\n }\n\n } catch (error) {\n console.error(`❌ Fatal error during grade data loading:`, error)\n throw error\n } finally {\n if (connection) {\n await connection.close()\n console.log('🔌 Database connection closed')\n }\n }\n}\n\n/**\n * X31/X32 KPI를 비활성화 (active = false, grades = null)\n */\nexport async function deactivateDeletedKpis(): Promise<void> {\n if (!process.env.NODE_ENV) {\n process.env.NODE_ENV = 'development'\n }\n\n const { config } = require('@things-factory/env')\n const ormconfig = require('@things-factory/shell/dist-server/initializers/ormconfig.js')\n const connectionConfig = config.get('ormconfig')\n\n let connection\n\n console.log('🚫 Deactivating deleted KPIs (X31, X32)...')\n\n try {\n console.log('🔌 Connecting to database...')\n connection = await createConnection({\n ...ormconfig,\n ...connectionConfig,\n logging: false\n })\n\n const { addDataSource } = require('@things-factory/shell')\n addDataSource('default', connection)\n\n const { getRepository } = require('@things-factory/shell')\n const { Kpi } = require('@things-factory/kpi')\n const kpiRepository = getRepository(Kpi)\n\n for (const kpiName of DEACTIVATE_KPI_NAMES) {\n const kpi = await kpiRepository.findOne({\n where: { name: kpiName, domain: { name: 'SYSTEM' } },\n relations: ['domain']\n })\n\n if (kpi) {\n kpi.active = false\n kpi.grades = null\n await kpiRepository.save(kpi)\n console.log(` ✅ Deactivated: ${kpiName}`)\n } else {\n console.log(` ⚠️ KPI not found: ${kpiName}`)\n }\n }\n\n console.log('\\n🎉 Deactivation complete!')\n } catch (error) {\n console.error('❌ Error deactivating KPIs:', error)\n throw error\n } finally {\n if (connection) {\n await connection.close()\n console.log('🔌 Database connection closed')\n }\n }\n}\n\n/**\n * List available grade data files\n */\nexport function listGradeDataFiles(): string[] {\n const gradeDataPath = path.join(__dirname, 'grade-data')\n \n try {\n if (!fs.existsSync(gradeDataPath)) {\n console.log('📁 Grade data directory not found')\n return []\n }\n \n const files = fs.readdirSync(gradeDataPath).filter(file => file.endsWith('.json'))\n \n console.log(`📁 Available grade data files in ${gradeDataPath}:\\n`)\n files.forEach((file, index) => {\n console.log(` ${(index + 1).toString().padStart(2)}: ${file}`)\n })\n console.log(`\\n📈 Total: ${files.length} files`)\n \n return files\n } catch (error) {\n console.error('❌ Error reading grade data directory:', error)\n return []\n }\n}\n\n/**\n * CLI execution when called directly\n */\nasync function main() {\n const args = process.argv.slice(2)\n\n try {\n if (args.includes('--help') || args.includes('-h')) {\n console.log(`\n🎯 KPI Grade Data Loader (Migration Style)\n\nUsage:\n ts-node server/scripts/load-grade-data-migration.ts [options] [fileName]\n\nOptions:\n --list, -l List available grade data files\n --deactivate Deactivate X31/X32 KPIs (set active=false, grades=null)\n --help, -h Show this help\n\nExamples:\n ts-node server/scripts/load-grade-data-migration.ts # Load all files\n ts-node server/scripts/load-grade-data-migration.ts x11-performance-table.json # Load specific file\n ts-node server/scripts/load-grade-data-migration.ts --list # List files\n ts-node server/scripts/load-grade-data-migration.ts --deactivate # Deactivate X31/X32\n\nNote: This script connects to the database using the current Things-Factory configuration.\n Make sure the application is properly configured before running.\n Supports both 1D array grades and 2D lookup grades (X13).\n `)\n return\n }\n\n if (args.includes('--list') || args.includes('-l')) {\n listGradeDataFiles()\n return\n }\n\n if (args.includes('--deactivate')) {\n await deactivateDeletedKpis()\n console.log('\\n✨ Done!')\n return\n }\n\n const specificFile = args.find(arg => !arg.startsWith('--'))\n \n if (specificFile) {\n console.log(`🎯 Loading specific file: ${specificFile}`)\n await loadKpiGradeData(specificFile)\n } else {\n console.log(`🎯 Loading all grade data files`)\n await loadKpiGradeData()\n }\n\n console.log('\\n✨ Done!')\n \n } catch (error) {\n console.error('\\n❌ Script failed:', error.message)\n process.exit(1)\n }\n}\n\n// Run if called directly\nif (require.main === module) {\n main()\n}"]}