@dssp/dkpi 1.0.0-alpha.9 → 1.0.0-alpha.90

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 (261) hide show
  1. package/KPI-STATISTICS-SERVICE.md +233 -0
  2. package/_index.html +4 -9
  3. package/assets/favicon.ico +0 -0
  4. package/assets/helps/index.md +1 -1
  5. package/assets/images/project-image.png +0 -0
  6. package/assets/manifest/apple-1024.png +0 -0
  7. package/assets/manifest/apple-120.png +0 -0
  8. package/assets/manifest/apple-152.png +0 -0
  9. package/assets/manifest/apple-167.png +0 -0
  10. package/assets/manifest/apple-180.png +0 -0
  11. package/assets/manifest/apple-touch-icon.png +0 -0
  12. package/assets/manifest/badge-128x128.png +0 -0
  13. package/assets/manifest/chrome-splashscreen-icon-384x384.png +0 -0
  14. package/assets/manifest/chrome-touch-icon-192x192.png +0 -0
  15. package/assets/manifest/icon-128x128.png +0 -0
  16. package/assets/manifest/icon-192x192.png +0 -0
  17. package/assets/manifest/icon-512x512.png +0 -0
  18. package/assets/manifest/icon-72x72.png +0 -0
  19. package/assets/manifest/icon-96x96.png +0 -0
  20. package/assets/manifest/image-metaog.png +0 -0
  21. package/assets/manifest/maskable_icon.png +0 -0
  22. package/assets/manifest/ms-icon-144x144.png +0 -0
  23. package/assets/manifest/ms-touch-icon-144x144-precomposed.png +0 -0
  24. package/assets/manifest.json +2 -2
  25. package/assets/videos/intro.mp4 +0 -0
  26. package/config/config.development.js +2 -1
  27. package/config/config.production.js +2 -1
  28. package/dist-client/bootstrap.d.ts +1 -0
  29. package/dist-client/bootstrap.js +75 -4
  30. package/dist-client/bootstrap.js.map +1 -1
  31. package/dist-client/components/kpi-2d-lookup-chart.d.ts +50 -0
  32. package/dist-client/components/kpi-2d-lookup-chart.js +263 -0
  33. package/dist-client/components/kpi-2d-lookup-chart.js.map +1 -0
  34. package/dist-client/components/kpi-boxplot-chart.d.ts +31 -0
  35. package/dist-client/components/kpi-boxplot-chart.js +306 -0
  36. package/dist-client/components/kpi-boxplot-chart.js.map +1 -0
  37. package/dist-client/components/kpi-lookup-chart.d.ts +58 -0
  38. package/dist-client/components/kpi-lookup-chart.js +459 -0
  39. package/dist-client/components/kpi-lookup-chart.js.map +1 -0
  40. package/dist-client/components/kpi-mini-trend-chart.d.ts +14 -0
  41. package/dist-client/components/kpi-mini-trend-chart.js +180 -0
  42. package/dist-client/components/kpi-mini-trend-chart.js.map +1 -0
  43. package/dist-client/components/kpi-radar-chart.d.ts +17 -0
  44. package/dist-client/components/kpi-radar-chart.js +259 -0
  45. package/dist-client/components/kpi-radar-chart.js.map +1 -0
  46. package/dist-client/components/kpi-single-boxplot-chart.d.ts +36 -0
  47. package/dist-client/components/kpi-single-boxplot-chart.js +417 -0
  48. package/dist-client/components/kpi-single-boxplot-chart.js.map +1 -0
  49. package/dist-client/components/kpi-step-lookup-chart.d.ts +33 -0
  50. package/dist-client/components/kpi-step-lookup-chart.js +181 -0
  51. package/dist-client/components/kpi-step-lookup-chart.js.map +1 -0
  52. package/dist-client/components/kpi-trend-chart.d.ts +25 -0
  53. package/dist-client/components/kpi-trend-chart.js +241 -0
  54. package/dist-client/components/kpi-trend-chart.js.map +1 -0
  55. package/dist-client/components/sv-pagenation-control.d.ts +18 -0
  56. package/dist-client/components/sv-pagenation-control.js +142 -0
  57. package/dist-client/components/sv-pagenation-control.js.map +1 -0
  58. package/dist-client/entries/auth/checkin.d.ts +38 -0
  59. package/dist-client/entries/auth/checkin.js +551 -0
  60. package/dist-client/entries/auth/checkin.js.map +1 -0
  61. package/dist-client/google-map/common-google-map.d.ts +35 -0
  62. package/dist-client/google-map/common-google-map.js +349 -0
  63. package/dist-client/google-map/common-google-map.js.map +1 -0
  64. package/dist-client/google-map/google-map-loader.d.ts +6 -0
  65. package/dist-client/google-map/google-map-loader.js +23 -0
  66. package/dist-client/google-map/google-map-loader.js.map +1 -0
  67. package/dist-client/icons/menu-icons.d.ts +6 -0
  68. package/dist-client/icons/menu-icons.js +42 -0
  69. package/dist-client/icons/menu-icons.js.map +1 -1
  70. package/dist-client/pages/component/project-update-header.d.ts +1 -0
  71. package/dist-client/pages/component/project-update-header.js +127 -0
  72. package/dist-client/pages/component/project-update-header.js.map +1 -0
  73. package/dist-client/pages/kpi-admin/dssp-kpi-list-page.d.ts +22 -0
  74. package/dist-client/pages/kpi-admin/dssp-kpi-list-page.js +57 -0
  75. package/dist-client/pages/kpi-admin/dssp-kpi-list-page.js.map +1 -0
  76. package/dist-client/pages/kpi-admin/dssp-kpi-overview.d.ts +47 -0
  77. package/dist-client/pages/kpi-admin/dssp-kpi-overview.js +393 -0
  78. package/dist-client/pages/kpi-admin/dssp-kpi-overview.js.map +1 -0
  79. package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.d.ts +20 -0
  80. package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.js +445 -0
  81. package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.js.map +1 -0
  82. package/dist-client/pages/kpi-admin/kpi-system-guide.d.ts +18 -0
  83. package/dist-client/pages/kpi-admin/kpi-system-guide.js +696 -0
  84. package/dist-client/pages/kpi-admin/kpi-system-guide.js.map +1 -0
  85. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.d.ts +18 -0
  86. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js +259 -0
  87. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js.map +1 -0
  88. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.d.ts +22 -0
  89. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js +346 -0
  90. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js.map +1 -0
  91. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.d.ts +26 -0
  92. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js +433 -0
  93. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js.map +1 -0
  94. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.d.ts +8 -0
  95. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js +78 -0
  96. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js.map +1 -0
  97. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.d.ts +46 -0
  98. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js +937 -0
  99. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js.map +1 -0
  100. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.d.ts +33 -0
  101. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js +231 -0
  102. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js.map +1 -0
  103. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.d.ts +35 -0
  104. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js +632 -0
  105. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js.map +1 -0
  106. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.d.ts +18 -0
  107. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js +131 -0
  108. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js.map +1 -0
  109. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.d.ts +52 -0
  110. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js +842 -0
  111. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js.map +1 -0
  112. package/dist-client/pages/kpi-dashboard/kpi-dashboard.d.ts +63 -0
  113. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js +1097 -0
  114. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js.map +1 -0
  115. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.d.ts +12 -0
  116. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js +82 -0
  117. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js.map +1 -0
  118. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.d.ts +11 -0
  119. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js +65 -0
  120. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js.map +1 -0
  121. package/dist-client/pages/kpi-dashboard/kpi-list-summary.d.ts +13 -0
  122. package/dist-client/pages/kpi-dashboard/kpi-list-summary.js +115 -0
  123. package/dist-client/pages/kpi-dashboard/kpi-list-summary.js.map +1 -0
  124. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.d.ts +15 -0
  125. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js +147 -0
  126. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js.map +1 -0
  127. package/dist-client/pages/kpi-dashboard/kpi-value-entry.d.ts +7 -0
  128. package/dist-client/pages/kpi-dashboard/kpi-value-entry.js +86 -0
  129. package/dist-client/pages/kpi-dashboard/kpi-value-entry.js.map +1 -0
  130. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.d.ts +57 -0
  131. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js +719 -0
  132. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js.map +1 -0
  133. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.d.ts +23 -0
  134. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js +76 -0
  135. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js.map +1 -0
  136. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.d.ts +68 -0
  137. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js +394 -0
  138. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js.map +1 -0
  139. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.d.ts +12 -0
  140. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js +174 -0
  141. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js.map +1 -0
  142. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.d.ts +40 -0
  143. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js +190 -0
  144. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js.map +1 -0
  145. package/dist-client/pages/kpi-value/kpi-value-importer.d.ts +23 -0
  146. package/dist-client/pages/kpi-value/kpi-value-importer.js +93 -0
  147. package/dist-client/pages/kpi-value/kpi-value-importer.js.map +1 -0
  148. package/dist-client/pages/kpi-value/kpi-value-list-page.d.ts +71 -0
  149. package/dist-client/pages/kpi-value/kpi-value-list-page.js +454 -0
  150. package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -0
  151. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.d.ts +66 -0
  152. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js +775 -0
  153. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js.map +1 -0
  154. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.d.ts +16 -0
  155. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js +337 -0
  156. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js.map +1 -0
  157. package/dist-client/pages/project-complete-tabs/pc-tab3-upload.d.ts +21 -0
  158. package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js +335 -0
  159. package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js.map +1 -0
  160. package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.d.ts +42 -0
  161. package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.js +635 -0
  162. package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.js.map +1 -0
  163. package/dist-client/pages/sv-project-complete.d.ts +25 -0
  164. package/dist-client/pages/sv-project-complete.js +259 -0
  165. package/dist-client/pages/sv-project-complete.js.map +1 -0
  166. package/dist-client/pages/sv-project-completed-list.d.ts +27 -0
  167. package/dist-client/pages/sv-project-completed-list.js +416 -0
  168. package/dist-client/pages/sv-project-completed-list.js.map +1 -0
  169. package/dist-client/pages/sv-project-detail.d.ts +70 -0
  170. package/dist-client/pages/sv-project-detail.js +1486 -0
  171. package/dist-client/pages/sv-project-detail.js.map +1 -0
  172. package/dist-client/pages/sv-project-list.d.ts +175 -0
  173. package/dist-client/pages/sv-project-list.js +581 -0
  174. package/dist-client/pages/sv-project-list.js.map +1 -0
  175. package/dist-client/pages/sv-project-update.d.ts +91 -0
  176. package/dist-client/pages/sv-project-update.js +1151 -0
  177. package/dist-client/pages/sv-project-update.js.map +1 -0
  178. package/dist-client/pages/sv-user-management.d.ts +1 -0
  179. package/dist-client/pages/sv-user-management.js +5 -0
  180. package/dist-client/pages/sv-user-management.js.map +1 -1
  181. package/dist-client/route.d.ts +1 -1
  182. package/dist-client/route.js +50 -2
  183. package/dist-client/route.js.map +1 -1
  184. package/dist-client/shared/complete-api.d.ts +37 -0
  185. package/dist-client/shared/complete-api.js +227 -0
  186. package/dist-client/shared/complete-api.js.map +1 -0
  187. package/dist-client/shared/func.d.ts +2 -0
  188. package/dist-client/shared/func.js +22 -0
  189. package/dist-client/shared/func.js.map +1 -0
  190. package/dist-client/shared/geo-group-mapping.d.ts +25 -0
  191. package/dist-client/shared/geo-group-mapping.js +189 -0
  192. package/dist-client/shared/geo-group-mapping.js.map +1 -0
  193. package/dist-client/shared/integration-fetch.d.ts +35 -0
  194. package/dist-client/shared/integration-fetch.js +53 -0
  195. package/dist-client/shared/integration-fetch.js.map +1 -0
  196. package/dist-client/themes/dark.css +24 -24
  197. package/dist-client/themes/light.css +23 -23
  198. package/dist-client/tsconfig.tsbuildinfo +1 -1
  199. package/dist-client/viewparts/menu-tools.d.ts +40 -5
  200. package/dist-client/viewparts/menu-tools.js +317 -52
  201. package/dist-client/viewparts/menu-tools.js.map +1 -1
  202. package/dist-server/index.d.ts +2 -0
  203. package/dist-server/index.js +5 -0
  204. package/dist-server/index.js.map +1 -1
  205. package/dist-server/migrations/index.d.ts +1 -0
  206. package/dist-server/migrations/index.js +12 -0
  207. package/dist-server/migrations/index.js.map +1 -0
  208. package/dist-server/scripts/calculate-kpi-scores.d.ts +10 -0
  209. package/dist-server/scripts/calculate-kpi-scores.js +333 -0
  210. package/dist-server/scripts/calculate-kpi-scores.js.map +1 -0
  211. package/dist-server/scripts/load-grade-data-migration.d.ts +14 -0
  212. package/dist-server/scripts/load-grade-data-migration.js +279 -0
  213. package/dist-server/scripts/load-grade-data-migration.js.map +1 -0
  214. package/dist-server/scripts/propagate-parent-kpi-values.d.ts +14 -0
  215. package/dist-server/scripts/propagate-parent-kpi-values.js +786 -0
  216. package/dist-server/scripts/propagate-parent-kpi-values.js.map +1 -0
  217. package/dist-server/scripts/recalculate-by-project-name.d.ts +2 -0
  218. package/dist-server/scripts/recalculate-by-project-name.js +72 -0
  219. package/dist-server/scripts/recalculate-by-project-name.js.map +1 -0
  220. package/dist-server/service/index.d.ts +4 -0
  221. package/dist-server/service/index.js +20 -0
  222. package/dist-server/service/index.js.map +1 -0
  223. package/dist-server/service/kpi-metric-value/index.d.ts +4 -0
  224. package/dist-server/service/kpi-metric-value/index.js +8 -0
  225. package/dist-server/service/kpi-metric-value/index.js.map +1 -0
  226. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.d.ts +171 -0
  227. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +983 -0
  228. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -0
  229. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.d.ts +12 -0
  230. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js +56 -0
  231. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js.map +1 -0
  232. package/dist-server/service/kpi-stat/index.d.ts +4 -0
  233. package/dist-server/service/kpi-stat/index.js +8 -0
  234. package/dist-server/service/kpi-stat/index.js.map +1 -0
  235. package/dist-server/service/kpi-stat/kpi-stat-query.d.ts +13 -0
  236. package/dist-server/service/kpi-stat/kpi-stat-query.js +727 -0
  237. package/dist-server/service/kpi-stat/kpi-stat-query.js.map +1 -0
  238. package/dist-server/service/kpi-stat/kpi-stat-types.d.ts +32 -0
  239. package/dist-server/service/kpi-stat/kpi-stat-types.js +180 -0
  240. package/dist-server/service/kpi-stat/kpi-stat-types.js.map +1 -0
  241. package/dist-server/service/kpi-value/index.d.ts +3 -0
  242. package/dist-server/service/kpi-value/index.js +7 -0
  243. package/dist-server/service/kpi-value/index.js.map +1 -0
  244. package/dist-server/service/kpi-value/kpi-value-query.d.ts +8 -0
  245. package/dist-server/service/kpi-value/kpi-value-query.js +90 -0
  246. package/dist-server/service/kpi-value/kpi-value-query.js.map +1 -0
  247. package/dist-server/tsconfig.tsbuildinfo +1 -1
  248. package/kpi-module-service-tests.md +1286 -0
  249. package/kpi-module-test-report.md +676 -0
  250. package/kpi-module-unit-test-detailed-report.md +925 -0
  251. package/kpi-module-unit-tests-detailed.md +1452 -0
  252. package/openapi/unstable.yaml +2 -2
  253. package/package.json +69 -55
  254. package/recalculate-batch.sh +64 -0
  255. package/recalculate-projects-range.sh +98 -0
  256. package/schema.graphql +3464 -458
  257. package/things-factory.config.js +12 -1
  258. package/translations/en.json +5 -1
  259. package/translations/ko.json +5 -1
  260. package/views/auth-page.html +4 -5
  261. package/views/public/home.html +5 -6
@@ -0,0 +1,696 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import { html, css, nothing } from 'lit';
3
+ import { customElement, state } from 'lit/decorators.js';
4
+ import { PageView } from '@operato/shell';
5
+ import { ScrollbarStyles } from '@operato/styles';
6
+ import { client } from '@operato/graphql';
7
+ import { navigate } from '@operato/shell';
8
+ import gql from 'graphql-tag';
9
+ /**
10
+ * KPI 시스템 종합 안내 페이지
11
+ *
12
+ * DB에서 실시간으로 KPI 계층, 산식, 메트릭, scoreType/valueType 등을 조회하여
13
+ * 시스템 전체 구조를 한눈에 파악할 수 있는 매뉴얼 겸 라이브 대시보드.
14
+ */
15
+ const GET_KPI_SYSTEM = gql `
16
+ query {
17
+ kpiRoot: kpisLevel1 {
18
+ id
19
+ name
20
+ description
21
+ formula
22
+ weight
23
+ scoreType
24
+ valueType
25
+ active
26
+ kpis: children {
27
+ id
28
+ name
29
+ description
30
+ formula
31
+ weight
32
+ scoreType
33
+ valueType
34
+ active
35
+ grades
36
+ }
37
+ }
38
+ kpiMetrics {
39
+ items {
40
+ id
41
+ name
42
+ unit
43
+ source
44
+ collectType
45
+ active
46
+ }
47
+ }
48
+ }
49
+ `;
50
+ const SCORE_TYPE_LABELS = {
51
+ DIRECT: { label: 'DIRECT (변환 없음)', color: '#888' },
52
+ FORMULA: { label: 'FORMULA (수식 변환)', color: '#9c27b0' },
53
+ LOOKUP: { label: 'LOOKUP (등급표)', color: '#1976d2' },
54
+ CUSTOM: { label: 'CUSTOM (2D 룩업)', color: '#e65100' }
55
+ };
56
+ /** 외부 시스템 URL 매핑 */
57
+ const EXTERNAL_SYSTEM_URLS = {
58
+ '세움터(EAIS)': 'https://cloud.eais.go.kr',
59
+ '키스콘(KISCON)': 'https://www.kiscon.net',
60
+ '올바로(Allbaro)': 'https://www.allbaro.or.kr',
61
+ 전자카드제: 'https://www.cw.or.kr'
62
+ };
63
+ const VALUE_TYPE_LABELS = {
64
+ MEASURED: { label: '외부 수집', color: '#1976d2', icon: '📡' },
65
+ ASSESSED: { label: '감리자 평가', color: '#2e7d32', icon: '✍️' },
66
+ CALCULATED: { label: '산식 계산', color: '#9c27b0', icon: '🔢' },
67
+ COMPOSITE: { label: '복합 입력', color: '#e65100', icon: '🔀' }
68
+ };
69
+ let KpiSystemGuide = class KpiSystemGuide extends PageView {
70
+ constructor() {
71
+ super(...arguments);
72
+ this.kpiRoot = [];
73
+ this.metrics = [];
74
+ this.loading = true;
75
+ this.selectedDetail = null;
76
+ }
77
+ get context() {
78
+ return { title: 'KPI 시스템 가이드' };
79
+ }
80
+ async firstUpdated() {
81
+ var _a;
82
+ try {
83
+ const { data } = await client.query({ query: GET_KPI_SYSTEM });
84
+ this.kpiRoot = data.kpiRoot || [];
85
+ this.metrics = ((_a = data.kpiMetrics) === null || _a === void 0 ? void 0 : _a.items) || [];
86
+ }
87
+ catch (e) {
88
+ console.error('Failed to load KPI system data:', e);
89
+ }
90
+ finally {
91
+ this.loading = false;
92
+ }
93
+ }
94
+ /** 메트릭이 사용되는 KPI 목록 — 비활성 KPI/Y 그룹 제외 */
95
+ getMetricUsage(metricName) {
96
+ var _a;
97
+ const used = [];
98
+ for (const y of this.kpiRoot) {
99
+ if (y.active === false)
100
+ continue;
101
+ for (const x of y.kpis || []) {
102
+ if (x.active === false)
103
+ continue;
104
+ if ((_a = x.formula) === null || _a === void 0 ? void 0 : _a.includes(`[${metricName}]`)) {
105
+ used.push(x.name);
106
+ }
107
+ }
108
+ }
109
+ return used;
110
+ }
111
+ showDetail(item, type) {
112
+ this.selectedDetail = Object.assign(Object.assign({}, item), { _type: type });
113
+ }
114
+ closeDetail() {
115
+ this.selectedDetail = null;
116
+ }
117
+ render() {
118
+ if (this.loading)
119
+ return html `<div style="padding:40px;text-align:center;color:#888;">로딩 중...</div>`;
120
+ // Z 노드 (루트의 부모)
121
+ const allX = this.kpiRoot.flatMap((y) => (y.kpis || []).filter((x) => x.active !== false));
122
+ return html `
123
+ <div class="page-title">KPI 시스템 가이드</div>
124
+ <div class="page-subtitle">
125
+ 건축프로젝트 성과평가 KPI 체계의 전체 구조, 산식, 메트릭 연관관계를 확인합니다. 모든 정보는 DB에서 실시간 조회됩니다.
126
+ </div>
127
+
128
+ <!-- 범례 -->
129
+ <div class="legend">
130
+ <span class="legend-title">Score 산정:</span>
131
+ ${Object.entries(SCORE_TYPE_LABELS).map(([, v]) => html `<span class="legend-group"><span class="badge badge-score">${v.label}</span></span>`)}
132
+ <span style="width:16px"></span>
133
+ <span class="legend-title">Value 획득:</span>
134
+ ${Object.entries(VALUE_TYPE_LABELS).map(([, v]) => html `<span class="legend-group">${v.icon} <span class="badge badge-value">${v.label}</span></span>`)}
135
+ </div>
136
+
137
+ <!-- 1. KPI 계층 구조 -->
138
+ <div class="tree-section">
139
+ <div class="section-title">📊 KPI 계층 구조 (Z → Y → X)</div>
140
+
141
+ <!-- Z 루트 -->
142
+ <div
143
+ class="z-node"
144
+ @click=${() => this.showDetail({
145
+ name: 'Z. 전체스코어',
146
+ description: 'Y1~Y6 가중합',
147
+ formula: 'Y1×w1 + Y2×w2 + ... + Y6×w6',
148
+ scoreType: 'DIRECT',
149
+ valueType: 'CALCULATED'
150
+ }, 'kpi')}
151
+ >
152
+ <div class="z-name">Z. 전체스코어</div>
153
+ <div class="z-formula">
154
+ =
155
+ ${this.kpiRoot
156
+ .filter((y) => y.active !== false)
157
+ .map((y) => `${y.name.split('.')[0]}×${y.weight}`)
158
+ .join(' + ')}
159
+ </div>
160
+ </div>
161
+
162
+ <!-- Y 그룹들 (비활성 Y 제외) -->
163
+ ${this.kpiRoot
164
+ .filter((y) => y.active !== false)
165
+ .map((y) => {
166
+ const activeKpis = (y.kpis || []).filter((x) => x.active !== false);
167
+ return html `
168
+ <div class="y-group">
169
+ <div class="y-header" @click=${() => this.showDetail(y, 'kpi')}>
170
+ <span class="y-name">${y.name}</span>
171
+ <span class="y-weight">가중치: ${y.weight}</span>
172
+ </div>
173
+ <div class="y-body">
174
+ ${y.formula ? html `<div class="y-formula">${y.formula}</div>` : ''}
175
+ <div class="x-cards">
176
+ ${activeKpis.map((x) => {
177
+ const st = SCORE_TYPE_LABELS[x.scoreType] || { label: x.scoreType || '미설정', color: '#999' };
178
+ const vt = VALUE_TYPE_LABELS[x.valueType] || { label: x.valueType || '미설정', color: '#999', icon: '?' };
179
+ return html `
180
+ <div class="x-card" @click=${() => this.showDetail(x, 'kpi')}>
181
+ <div class="x-name">${x.name}</div>
182
+ <div class="x-formula">${x.formula || '—'}</div>
183
+ <div class="x-badges">
184
+ <span class="badge badge-score">${st.label}</span>
185
+ <span class="badge badge-value">${vt.icon} ${vt.label}</span>
186
+ </div>
187
+ </div>
188
+ `;
189
+ })}
190
+ </div>
191
+ </div>
192
+ </div>
193
+ `;
194
+ })}
195
+ </div>
196
+
197
+ <!-- 2. 원천 메트릭 — active=true 이면서 활성 KPI formula 에 실제 참조되는 것만 -->
198
+ ${(() => {
199
+ const usedMetrics = this.metrics
200
+ .filter((m) => m.active)
201
+ .map((m) => ({ m, usage: this.getMetricUsage(m.name) }))
202
+ .filter(({ usage }) => usage.length > 0);
203
+ return html `
204
+ <div class="tree-section">
205
+ <div class="section-title">📋 원천 메트릭 (${usedMetrics.length}개 사용)</div>
206
+ <div class="metrics-grid">
207
+ ${usedMetrics.map(({ m, usage }) => html `
208
+ <div class="metric-card" @click=${() => this.showDetail(m, 'metric')}>
209
+ <div class="metric-name">${m.name}</div>
210
+ <div class="metric-unit">
211
+ ${m.unit || '—'} ·
212
+ ${m.collectType === 'EXTERNAL' && m.source
213
+ ? EXTERNAL_SYSTEM_URLS[m.source]
214
+ ? html `<a
215
+ href="${EXTERNAL_SYSTEM_URLS[m.source]}"
216
+ target="_blank"
217
+ rel="noopener"
218
+ style="color:#1976d2;text-decoration:none;"
219
+ @click=${(e) => e.stopPropagation()}
220
+ >${m.source} ↗</a
221
+ >`
222
+ : m.source
223
+ : m.collectType || 'MANUAL'}
224
+ </div>
225
+ <div class="metric-used">→ ${usage.join(', ')}</div>
226
+ </div>
227
+ `)}
228
+ </div>
229
+ </div>
230
+ `;
231
+ })()}
232
+
233
+ <!-- 3. 시스템 요약 -->
234
+ <div class="tree-section">
235
+ <div class="section-title">📈 시스템 요약</div>
236
+ <div style="display:flex;gap:16px;flex-wrap:wrap;">
237
+ <div style="flex:1;min-width:200px;background:#e3f2fd;padding:16px;border-radius:8px;text-align:center;">
238
+ <div style="font-size:2rem;font-weight:800;color:#1565c0;">${allX.length}</div>
239
+ <div style="font-size:0.85rem;color:#555;">X-level 지표</div>
240
+ </div>
241
+ <div style="flex:1;min-width:200px;background:#e8f5e9;padding:16px;border-radius:8px;text-align:center;">
242
+ <div style="font-size:2rem;font-weight:800;color:#2e7d32;">
243
+ ${this.kpiRoot.filter((y) => y.active !== false).length}
244
+ </div>
245
+ <div style="font-size:0.85rem;color:#555;">Y-level 영역</div>
246
+ </div>
247
+ <div style="flex:1;min-width:200px;background:#fff3e0;padding:16px;border-radius:8px;text-align:center;">
248
+ <div style="font-size:2rem;font-weight:800;color:#e65100;">
249
+ ${this.metrics.filter((m) => m.active && this.getMetricUsage(m.name).length > 0).length}
250
+ </div>
251
+ <div style="font-size:0.85rem;color:#555;">원천 메트릭</div>
252
+ </div>
253
+ <div style="flex:1;min-width:200px;background:#fce4ec;padding:16px;border-radius:8px;text-align:center;">
254
+ <div style="font-size:2rem;font-weight:800;color:#c62828;">
255
+ ${allX.filter((x) => x.valueType === 'ASSESSED').length}
256
+ </div>
257
+ <div style="font-size:0.85rem;color:#555;">감리자 평가 항목</div>
258
+ </div>
259
+ </div>
260
+ </div>
261
+
262
+ <!-- 팝업 -->
263
+ ${this.selectedDetail ? this._renderDetailPopup() : nothing}
264
+ `;
265
+ }
266
+ _renderDetailPopup() {
267
+ const d = this.selectedDetail;
268
+ const isKpi = d._type === 'kpi';
269
+ return html `
270
+ <div class="popup-overlay" @click=${() => this.closeDetail()}>
271
+ <div class="popup-box" @click=${(e) => e.stopPropagation()}>
272
+ <div class="popup-title">
273
+ <span>${d.name}</span>
274
+ <button class="popup-close" @click=${() => this.closeDetail()}>×</button>
275
+ </div>
276
+
277
+ ${d.description
278
+ ? html `
279
+ <div class="popup-row">
280
+ <span class="popup-label">설명</span>
281
+ <span class="popup-value">${d.description}</span>
282
+ </div>
283
+ `
284
+ : ''}
285
+ ${isKpi
286
+ ? html `
287
+ ${d.formula
288
+ ? html `
289
+ <div class="popup-row"><span class="popup-label">산식</span></div>
290
+ <div class="popup-formula">${d.formula}</div>
291
+ `
292
+ : ''}
293
+ ${d.scoreType
294
+ ? html `
295
+ <div class="popup-row">
296
+ <span class="popup-label">Score 산정</span>
297
+ <span class="popup-value" style="color:${(SCORE_TYPE_LABELS[d.scoreType] || {}).color || '#333'}">
298
+ ${(SCORE_TYPE_LABELS[d.scoreType] || {}).label || d.scoreType}
299
+ </span>
300
+ </div>
301
+ `
302
+ : ''}
303
+ ${d.valueType
304
+ ? html `
305
+ <div class="popup-row">
306
+ <span class="popup-label">Value 획득</span>
307
+ <span class="popup-value" style="color:${(VALUE_TYPE_LABELS[d.valueType] || {}).color || '#333'}">
308
+ ${(VALUE_TYPE_LABELS[d.valueType] || {}).icon || ''}
309
+ ${(VALUE_TYPE_LABELS[d.valueType] || {}).label || d.valueType}
310
+ </span>
311
+ </div>
312
+ `
313
+ : ''}
314
+ ${d.weight
315
+ ? html `
316
+ <div class="popup-row">
317
+ <span class="popup-label">가중치</span>
318
+ <span class="popup-value">${d.weight}</span>
319
+ </div>
320
+ `
321
+ : ''}
322
+
323
+ <div style="margin-top:16px;padding-top:12px;border-top:1px solid #eee;">
324
+ <span
325
+ class="popup-link"
326
+ @click=${() => {
327
+ this.closeDetail();
328
+ navigate('kpi-overview');
329
+ }}
330
+ >
331
+ → KPI 개요에서 보기
332
+ </span>
333
+ &nbsp;&nbsp;
334
+ <span
335
+ class="popup-link"
336
+ @click=${() => {
337
+ this.closeDetail();
338
+ navigate('kpi-admin');
339
+ }}
340
+ >
341
+ → KPI 관리에서 편집
342
+ </span>
343
+ </div>
344
+ `
345
+ : html `
346
+ <div class="popup-row">
347
+ <span class="popup-label">단위</span>
348
+ <span class="popup-value">${d.unit || '—'}</span>
349
+ </div>
350
+ <div class="popup-row">
351
+ <span class="popup-label">수집 방식</span>
352
+ <span class="popup-value">${d.collectType || 'MANUAL'}</span>
353
+ </div>
354
+ <div class="popup-row">
355
+ <span class="popup-label">데이터 소스</span>
356
+ <span class="popup-value">
357
+ ${d.source && EXTERNAL_SYSTEM_URLS[d.source]
358
+ ? html `<a href="${EXTERNAL_SYSTEM_URLS[d.source]}" target="_blank" rel="noopener" style="color:#1976d2;"
359
+ >${d.source} ↗</a
360
+ >`
361
+ : d.source || '미설정'}
362
+ </span>
363
+ </div>
364
+
365
+ <div style="margin-top:12px;">
366
+ <div class="popup-label" style="margin-bottom:6px;">사용처:</div>
367
+ ${this.getMetricUsage(d.name).map(kpi => html `<div style="font-size:0.85rem;color:#1976d2;margin-bottom:2px;">· ${kpi}</div>`)}
368
+ ${this.getMetricUsage(d.name).length === 0 ? html `<div style="color:#ccc;font-size:0.85rem;">미사용</div>` : ''}
369
+ </div>
370
+
371
+ <div style="margin-top:16px;padding-top:12px;border-top:1px solid #eee;">
372
+ <span
373
+ class="popup-link"
374
+ @click=${() => {
375
+ this.closeDetail();
376
+ navigate('kpi-metric-value-list');
377
+ }}
378
+ >
379
+ → 메트릭 값 관리
380
+ </span>
381
+ </div>
382
+ `}
383
+ </div>
384
+ </div>
385
+ `;
386
+ }
387
+ };
388
+ KpiSystemGuide.styles = [
389
+ ScrollbarStyles,
390
+ css `
391
+ :host {
392
+ display: block;
393
+ overflow-y: auto;
394
+ background: #f5f6fa;
395
+ padding: 24px;
396
+ }
397
+
398
+ .page-title {
399
+ font-size: 1.5rem;
400
+ font-weight: 800;
401
+ color: #1a237e;
402
+ margin-bottom: 4px;
403
+ }
404
+ .page-subtitle {
405
+ font-size: 0.9rem;
406
+ color: #666;
407
+ margin-bottom: 24px;
408
+ }
409
+
410
+ /* 계층 트리 */
411
+ .tree-section {
412
+ background: #fff;
413
+ border-radius: 12px;
414
+ padding: 24px;
415
+ margin-bottom: 24px;
416
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
417
+ }
418
+ .section-title {
419
+ font-size: 1.1rem;
420
+ font-weight: 700;
421
+ color: #333;
422
+ margin-bottom: 16px;
423
+ display: flex;
424
+ align-items: center;
425
+ gap: 8px;
426
+ }
427
+
428
+ /* Z 루트 */
429
+ .z-node {
430
+ background: linear-gradient(135deg, #1a237e, #283593);
431
+ color: #fff;
432
+ border-radius: 10px;
433
+ padding: 16px 20px;
434
+ margin-bottom: 16px;
435
+ cursor: pointer;
436
+ }
437
+ .z-node:hover {
438
+ opacity: 0.95;
439
+ }
440
+ .z-name {
441
+ font-size: 1.1rem;
442
+ font-weight: 700;
443
+ }
444
+ .z-formula {
445
+ font-size: 0.8rem;
446
+ opacity: 0.8;
447
+ margin-top: 4px;
448
+ font-family: monospace;
449
+ }
450
+
451
+ /* Y 그룹 */
452
+ .y-group {
453
+ margin-bottom: 16px;
454
+ border: 1px solid #e0e0e0;
455
+ border-radius: 10px;
456
+ overflow: hidden;
457
+ }
458
+ .y-header {
459
+ background: linear-gradient(135deg, #0c4da2, #1565c0);
460
+ color: #fff;
461
+ padding: 12px 16px;
462
+ display: flex;
463
+ justify-content: space-between;
464
+ align-items: center;
465
+ cursor: pointer;
466
+ }
467
+ .y-header:hover {
468
+ opacity: 0.95;
469
+ }
470
+ .y-name {
471
+ font-weight: 700;
472
+ font-size: 1rem;
473
+ }
474
+ .y-weight {
475
+ background: rgba(255, 255, 255, 0.2);
476
+ padding: 2px 10px;
477
+ border-radius: 12px;
478
+ font-size: 0.8rem;
479
+ }
480
+ .y-body {
481
+ padding: 12px;
482
+ }
483
+ .y-formula {
484
+ font-size: 0.8rem;
485
+ color: #555;
486
+ background: #f8f9fa;
487
+ padding: 8px 12px;
488
+ border-radius: 6px;
489
+ font-family: monospace;
490
+ margin-bottom: 10px;
491
+ word-break: break-all;
492
+ }
493
+
494
+ /* X 카드 */
495
+ .x-cards {
496
+ display: flex;
497
+ flex-wrap: wrap;
498
+ gap: 8px;
499
+ }
500
+ .x-card {
501
+ flex: 1 1 220px;
502
+ background: #fff;
503
+ border: 1px solid #e8e8e8;
504
+ border-radius: 8px;
505
+ padding: 10px 14px;
506
+ cursor: pointer;
507
+ transition: all 0.2s;
508
+ min-width: 200px;
509
+ }
510
+ .x-card:hover {
511
+ border-color: #1976d2;
512
+ box-shadow: 0 2px 8px rgba(25, 118, 210, 0.15);
513
+ }
514
+ .x-name {
515
+ font-weight: 600;
516
+ font-size: 0.85rem;
517
+ color: #333;
518
+ margin-bottom: 4px;
519
+ }
520
+ .x-formula {
521
+ font-size: 0.75rem;
522
+ color: #888;
523
+ font-family: monospace;
524
+ white-space: nowrap;
525
+ overflow: hidden;
526
+ text-overflow: ellipsis;
527
+ margin-bottom: 6px;
528
+ }
529
+ .x-badges {
530
+ display: flex;
531
+ gap: 4px;
532
+ flex-wrap: wrap;
533
+ }
534
+ .badge {
535
+ font-size: 0.65rem;
536
+ padding: 2px 6px;
537
+ border-radius: 4px;
538
+ font-weight: 600;
539
+ }
540
+ .badge-score {
541
+ background: #e3f2fd;
542
+ color: #1565c0;
543
+ }
544
+ .badge-value {
545
+ background: #e8f5e9;
546
+ color: #2e7d32;
547
+ }
548
+
549
+ /* 메트릭 섹션 */
550
+ .metrics-grid {
551
+ display: grid;
552
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
553
+ gap: 10px;
554
+ }
555
+ .metric-card {
556
+ background: #fff;
557
+ border: 1px solid #e8e8e8;
558
+ border-radius: 8px;
559
+ padding: 10px 14px;
560
+ transition: all 0.2s;
561
+ }
562
+ .metric-card:hover {
563
+ border-color: #4caf50;
564
+ }
565
+ .metric-name {
566
+ font-weight: 600;
567
+ font-size: 0.85rem;
568
+ color: #333;
569
+ }
570
+ .metric-unit {
571
+ font-size: 0.75rem;
572
+ color: #888;
573
+ }
574
+ .metric-used {
575
+ font-size: 0.7rem;
576
+ color: #1976d2;
577
+ margin-top: 4px;
578
+ }
579
+
580
+ /* 팝업 */
581
+ .popup-overlay {
582
+ position: fixed;
583
+ top: 0;
584
+ left: 0;
585
+ right: 0;
586
+ bottom: 0;
587
+ background: rgba(0, 0, 0, 0.3);
588
+ z-index: 1000;
589
+ display: flex;
590
+ align-items: center;
591
+ justify-content: center;
592
+ }
593
+ .popup-box {
594
+ background: #fff;
595
+ border-radius: 12px;
596
+ padding: 24px;
597
+ min-width: 400px;
598
+ max-width: 600px;
599
+ max-height: 80vh;
600
+ overflow-y: auto;
601
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
602
+ }
603
+ .popup-title {
604
+ font-size: 1.1rem;
605
+ font-weight: 700;
606
+ color: #1a237e;
607
+ margin-bottom: 16px;
608
+ display: flex;
609
+ justify-content: space-between;
610
+ }
611
+ .popup-close {
612
+ background: none;
613
+ border: none;
614
+ font-size: 1.2rem;
615
+ cursor: pointer;
616
+ color: #999;
617
+ }
618
+ .popup-row {
619
+ display: flex;
620
+ gap: 8px;
621
+ margin-bottom: 8px;
622
+ font-size: 0.85rem;
623
+ }
624
+ .popup-label {
625
+ color: #888;
626
+ min-width: 100px;
627
+ flex-shrink: 0;
628
+ }
629
+ .popup-value {
630
+ color: #333;
631
+ font-weight: 500;
632
+ }
633
+ .popup-formula {
634
+ background: #f5f5f5;
635
+ padding: 10px;
636
+ border-radius: 6px;
637
+ font-family: monospace;
638
+ font-size: 0.85rem;
639
+ margin: 8px 0;
640
+ word-break: break-all;
641
+ }
642
+ .popup-link {
643
+ color: #1976d2;
644
+ cursor: pointer;
645
+ text-decoration: underline;
646
+ font-size: 0.85rem;
647
+ }
648
+ .popup-link:hover {
649
+ color: #0d47a1;
650
+ }
651
+
652
+ /* 범례 */
653
+ .legend {
654
+ display: flex;
655
+ gap: 16px;
656
+ flex-wrap: wrap;
657
+ margin-bottom: 20px;
658
+ padding: 12px 16px;
659
+ background: #fff;
660
+ border-radius: 8px;
661
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
662
+ }
663
+ .legend-group {
664
+ display: flex;
665
+ align-items: center;
666
+ gap: 4px;
667
+ font-size: 0.8rem;
668
+ }
669
+ .legend-title {
670
+ font-weight: 700;
671
+ color: #555;
672
+ margin-right: 4px;
673
+ }
674
+ `
675
+ ];
676
+ __decorate([
677
+ state(),
678
+ __metadata("design:type", Array)
679
+ ], KpiSystemGuide.prototype, "kpiRoot", void 0);
680
+ __decorate([
681
+ state(),
682
+ __metadata("design:type", Array)
683
+ ], KpiSystemGuide.prototype, "metrics", void 0);
684
+ __decorate([
685
+ state(),
686
+ __metadata("design:type", Object)
687
+ ], KpiSystemGuide.prototype, "loading", void 0);
688
+ __decorate([
689
+ state(),
690
+ __metadata("design:type", Object)
691
+ ], KpiSystemGuide.prototype, "selectedDetail", void 0);
692
+ KpiSystemGuide = __decorate([
693
+ customElement('kpi-system-guide')
694
+ ], KpiSystemGuide);
695
+ export { KpiSystemGuide };
696
+ //# sourceMappingURL=kpi-system-guide.js.map