@things-factory/kpi 9.0.30 → 9.0.32

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 (347) hide show
  1. package/README.md +1 -2
  2. package/client/charts/kpi-boxplot-chart.ts +182 -42
  3. package/client/charts/kpi-mini-trend-chart.ts +125 -0
  4. package/client/charts/kpi-radar-chart.ts +9 -9
  5. package/client/charts/kpi-trend-chart.ts +163 -0
  6. package/client/google-map/common-google-map.ts +45 -7
  7. package/client/google-map/google-map-loader.ts +1 -1
  8. package/client/pages/kpi/kpi-list-page.ts +196 -32
  9. package/client/pages/kpi/kpi-overview.ts +9 -11
  10. package/client/pages/kpi/kpi-tree-page.ts +409 -0
  11. package/client/pages/kpi/kpi-view.ts +187 -0
  12. package/client/pages/kpi-dashboard/cards/kpi-level1-card.ts +1 -1
  13. package/client/pages/kpi-dashboard/cards/kpi-level2-comparison.ts +1 -1
  14. package/client/pages/kpi-dashboard/cards/kpi-level3-comparison.ts +1 -1
  15. package/client/pages/kpi-dashboard/components/kpi-chart-toggle.ts +1 -2
  16. package/client/pages/kpi-dashboard/components/kpi-left-panel.ts +437 -0
  17. package/client/pages/kpi-dashboard/components/kpi-map-panel.ts +243 -30
  18. package/client/pages/kpi-dashboard/components/kpi-region-popup.ts +356 -0
  19. package/client/pages/kpi-dashboard/kpi-dashboard-map.ts +50 -592
  20. package/client/pages/kpi-dashboard/kpi-dashboard.ts +28 -30
  21. package/client/pages/kpi-history/kpi-history-list-page.ts +11 -11
  22. package/client/pages/kpi-metric/kpi-metric-list-page.ts +10 -2
  23. package/client/pages/kpi-metric-value/kpi-metric-value-editor-page.ts +7 -7
  24. package/client/pages/kpi-metric-value/kpi-metric-value-importer.ts +2 -2
  25. package/client/pages/kpi-metric-value/kpi-metric-value-list-page.ts +16 -8
  26. package/client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.ts +5 -5
  27. package/client/pages/kpi-statistic/kpi-statistic-editor-page.ts +1 -2
  28. package/client/pages/kpi-statistic/kpi-statistic-list-page.ts +10 -2
  29. package/client/pages/kpi-value/kpi-value-editor-page.ts +11 -7
  30. package/client/pages/kpi-value/kpi-value-list-page.ts +31 -7
  31. package/client/route.ts +2 -9
  32. package/design-entities.md +8 -12
  33. package/dist-client/charts/kpi-boxplot-chart.d.ts +2 -0
  34. package/dist-client/charts/kpi-boxplot-chart.js +168 -42
  35. package/dist-client/charts/kpi-boxplot-chart.js.map +1 -1
  36. package/dist-client/charts/kpi-mini-trend-chart.d.ts +14 -0
  37. package/dist-client/charts/kpi-mini-trend-chart.js +148 -0
  38. package/dist-client/charts/kpi-mini-trend-chart.js.map +1 -0
  39. package/dist-client/charts/kpi-radar-chart.js +9 -9
  40. package/dist-client/charts/kpi-radar-chart.js.map +1 -1
  41. package/dist-client/charts/kpi-trend-chart.d.ts +25 -0
  42. package/dist-client/charts/kpi-trend-chart.js +186 -0
  43. package/dist-client/charts/kpi-trend-chart.js.map +1 -0
  44. package/dist-client/google-map/common-google-map.js +40 -7
  45. package/dist-client/google-map/common-google-map.js.map +1 -1
  46. package/dist-client/google-map/google-map-loader.js +1 -1
  47. package/dist-client/google-map/google-map-loader.js.map +1 -1
  48. package/dist-client/pages/kpi/kpi-list-page.d.ts +19 -3
  49. package/dist-client/pages/kpi/kpi-list-page.js +188 -32
  50. package/dist-client/pages/kpi/kpi-list-page.js.map +1 -1
  51. package/dist-client/pages/kpi/kpi-overview.js +9 -11
  52. package/dist-client/pages/kpi/kpi-overview.js.map +1 -1
  53. package/dist-client/pages/kpi/kpi-tree-page.d.ts +59 -0
  54. package/dist-client/pages/kpi/kpi-tree-page.js +403 -0
  55. package/dist-client/pages/kpi/kpi-tree-page.js.map +1 -0
  56. package/dist-client/pages/kpi/kpi-view.d.ts +12 -0
  57. package/dist-client/pages/kpi/kpi-view.js +191 -0
  58. package/dist-client/pages/kpi/kpi-view.js.map +1 -0
  59. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js +1 -1
  60. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js.map +1 -1
  61. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js +1 -1
  62. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js.map +1 -1
  63. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js +1 -1
  64. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js.map +1 -1
  65. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js +1 -2
  66. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js.map +1 -1
  67. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.d.ts +24 -0
  68. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js +440 -0
  69. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js.map +1 -0
  70. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.d.ts +11 -1
  71. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js +243 -22
  72. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js.map +1 -1
  73. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.d.ts +23 -0
  74. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js +369 -0
  75. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js.map +1 -0
  76. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.d.ts +6 -15
  77. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js +47 -588
  78. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js.map +1 -1
  79. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js +28 -30
  80. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js.map +1 -1
  81. package/dist-client/pages/kpi-history/kpi-history-list-page.d.ts +6 -1
  82. package/dist-client/pages/kpi-history/kpi-history-list-page.js +11 -11
  83. package/dist-client/pages/kpi-history/kpi-history-list-page.js.map +1 -1
  84. package/dist-client/pages/kpi-metric/kpi-metric-list-page.d.ts +5 -0
  85. package/dist-client/pages/kpi-metric/kpi-metric-list-page.js +10 -2
  86. package/dist-client/pages/kpi-metric/kpi-metric-list-page.js.map +1 -1
  87. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.d.ts +1 -1
  88. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js +8 -8
  89. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js.map +1 -1
  90. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js +2 -2
  91. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js.map +1 -1
  92. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.d.ts +5 -0
  93. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js +16 -8
  94. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js.map +1 -1
  95. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.d.ts +1 -1
  96. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js +6 -6
  97. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js.map +1 -1
  98. package/dist-client/pages/kpi-statistic/kpi-statistic-editor-page.js +1 -2
  99. package/dist-client/pages/kpi-statistic/kpi-statistic-editor-page.js.map +1 -1
  100. package/dist-client/pages/kpi-statistic/kpi-statistic-list-page.d.ts +5 -0
  101. package/dist-client/pages/kpi-statistic/kpi-statistic-list-page.js +10 -2
  102. package/dist-client/pages/kpi-statistic/kpi-statistic-list-page.js.map +1 -1
  103. package/dist-client/pages/kpi-value/kpi-value-editor-page.d.ts +2 -1
  104. package/dist-client/pages/kpi-value/kpi-value-editor-page.js +16 -8
  105. package/dist-client/pages/kpi-value/kpi-value-editor-page.js.map +1 -1
  106. package/dist-client/pages/kpi-value/kpi-value-list-page.d.ts +5 -0
  107. package/dist-client/pages/kpi-value/kpi-value-list-page.js +31 -7
  108. package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -1
  109. package/dist-client/route.d.ts +1 -1
  110. package/dist-client/route.js +2 -8
  111. package/dist-client/route.js.map +1 -1
  112. package/dist-client/tsconfig.tsbuildinfo +1 -1
  113. package/dist-server/controllers/kpi-metric-value-provider.d.ts +1 -1
  114. package/dist-server/controllers/kpi-metric-value-provider.js +4 -4
  115. package/dist-server/controllers/kpi-metric-value-provider.js.map +1 -1
  116. package/dist-server/controllers/kpi-value-provider.d.ts +1 -1
  117. package/dist-server/controllers/kpi-value-provider.js +3 -3
  118. package/dist-server/controllers/kpi-value-provider.js.map +1 -1
  119. package/dist-server/migrations/1752190849680-seed-kpi-metrics.d.ts +6 -0
  120. package/dist-server/migrations/1752190849680-seed-kpi-metrics.js +101 -0
  121. package/dist-server/migrations/1752190849680-seed-kpi-metrics.js.map +1 -0
  122. package/dist-server/migrations/1752190849681-seed-kpi.d.ts +5 -0
  123. package/dist-server/migrations/1752190849681-seed-kpi.js +315 -0
  124. package/dist-server/migrations/1752190849681-seed-kpi.js.map +1 -0
  125. package/dist-server/migrations/1752192090123-add-grades-to-kpi.d.ts +7 -0
  126. package/dist-server/migrations/1752192090123-add-grades-to-kpi.js +51 -0
  127. package/dist-server/migrations/1752192090123-add-grades-to-kpi.js.map +1 -0
  128. package/dist-server/migrations/1752192090124-add-kpi-statistics.d.ts +5 -0
  129. package/dist-server/migrations/1752192090124-add-kpi-statistics.js +710 -0
  130. package/dist-server/migrations/1752192090124-add-kpi-statistics.js.map +1 -0
  131. package/dist-server/migrations/1752192090128-seed-kpi-org-scope.d.ts +6 -0
  132. package/dist-server/migrations/1752192090128-seed-kpi-org-scope.js +111 -0
  133. package/dist-server/migrations/1752192090128-seed-kpi-org-scope.js.map +1 -0
  134. package/dist-server/migrations/1752192090129-seed-kpi-values.d.ts +6 -0
  135. package/dist-server/migrations/1752192090129-seed-kpi-values.js +187 -0
  136. package/dist-server/migrations/1752192090129-seed-kpi-values.js.map +1 -0
  137. package/dist-server/migrations/grade-data/x11-performance-table.json +962 -0
  138. package/dist-server/migrations/grade-data/x12-performance-table.json +611 -0
  139. package/dist-server/migrations/grade-data/x14-performance-table.json +42 -0
  140. package/dist-server/migrations/grade-data/x21-performance-table.json +889 -0
  141. package/dist-server/migrations/grade-data/x22-performance-table.json +1064 -0
  142. package/dist-server/migrations/grade-data/x23-performance-table.json +42 -0
  143. package/dist-server/migrations/grade-data/x31-performance-table.json +644 -0
  144. package/dist-server/migrations/grade-data/x32-performance-table.json +993 -0
  145. package/dist-server/migrations/grade-data/x33-performance-table.json +195 -0
  146. package/dist-server/migrations/grade-data/x34-performance-table.json +12 -0
  147. package/dist-server/migrations/grade-data/x35-performance-table.json +42 -0
  148. package/dist-server/migrations/grade-data/x41-performance-table.json +825 -0
  149. package/dist-server/migrations/grade-data/x42-performance-table.json +786 -0
  150. package/dist-server/migrations/grade-data/x43-performance-table.json +12 -0
  151. package/dist-server/migrations/grade-data/x44-performance-table.json +42 -0
  152. package/dist-server/migrations/grade-data/x51-performance-table.json +924 -0
  153. package/dist-server/migrations/grade-data/x52-performance-table.json +42 -0
  154. package/dist-server/migrations/grade-data/x61-performance-table.json +261 -0
  155. package/dist-server/migrations/grade-data/x62-performance-table.json +42 -0
  156. package/dist-server/migrations/seed-data/kpi-metrics-seed.json +454 -0
  157. package/dist-server/migrations/seed-data/kpi-org-scope-seed.json +1676 -0
  158. package/dist-server/migrations/seed-data/kpi-values-seed.json +402 -0
  159. package/dist-server/migrations/seed-data/kpis-seed.json +488 -0
  160. package/dist-server/service/index.d.ts +3 -7
  161. package/dist-server/service/index.js +5 -12
  162. package/dist-server/service/index.js.map +1 -1
  163. package/dist-server/service/kpi/aggregate-kpi.js +30 -13
  164. package/dist-server/service/kpi/aggregate-kpi.js.map +1 -1
  165. package/dist-server/service/kpi/kpi-formula.service.d.ts +15 -0
  166. package/dist-server/service/kpi/kpi-formula.service.js +90 -0
  167. package/dist-server/service/kpi/kpi-formula.service.js.map +1 -1
  168. package/dist-server/service/kpi/kpi-history.d.ts +0 -3
  169. package/dist-server/service/kpi/kpi-history.js +0 -10
  170. package/dist-server/service/kpi/kpi-history.js.map +1 -1
  171. package/dist-server/service/kpi/kpi-mutation.d.ts +1 -1
  172. package/dist-server/service/kpi/kpi-mutation.js +57 -20
  173. package/dist-server/service/kpi/kpi-mutation.js.map +1 -1
  174. package/dist-server/service/kpi/kpi-query.d.ts +7 -3
  175. package/dist-server/service/kpi/kpi-query.js +126 -10
  176. package/dist-server/service/kpi/kpi-query.js.map +1 -1
  177. package/dist-server/service/kpi/kpi-type.d.ts +4 -2
  178. package/dist-server/service/kpi/kpi-type.js +12 -4
  179. package/dist-server/service/kpi/kpi-type.js.map +1 -1
  180. package/dist-server/service/kpi/kpi.d.ts +4 -3
  181. package/dist-server/service/kpi/kpi.js +20 -8
  182. package/dist-server/service/kpi/kpi.js.map +1 -1
  183. package/dist-server/service/kpi-metric/aggregate-kpi-metric.js +46 -11
  184. package/dist-server/service/kpi-metric/aggregate-kpi-metric.js.map +1 -1
  185. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.d.ts +1 -1
  186. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +6 -6
  187. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -1
  188. package/dist-server/service/kpi-metric-value/kpi-metric-value-type.d.ts +2 -2
  189. package/dist-server/service/kpi-metric-value/kpi-metric-value-type.js +4 -4
  190. package/dist-server/service/kpi-metric-value/kpi-metric-value-type.js.map +1 -1
  191. package/dist-server/service/kpi-metric-value/kpi-metric-value.d.ts +1 -1
  192. package/dist-server/service/kpi-metric-value/kpi-metric-value.js +3 -3
  193. package/dist-server/service/kpi-metric-value/kpi-metric-value.js.map +1 -1
  194. package/dist-server/service/kpi-org-scope/index.d.ts +9 -0
  195. package/dist-server/service/kpi-org-scope/index.js +14 -0
  196. package/dist-server/service/kpi-org-scope/index.js.map +1 -0
  197. package/dist-server/service/kpi-org-scope/kpi-org-scope-mutation.d.ts +8 -0
  198. package/dist-server/service/kpi-org-scope/kpi-org-scope-mutation.js +170 -0
  199. package/dist-server/service/kpi-org-scope/kpi-org-scope-mutation.js.map +1 -0
  200. package/dist-server/service/kpi-org-scope/kpi-org-scope-query.d.ts +14 -0
  201. package/dist-server/service/kpi-org-scope/kpi-org-scope-query.js +152 -0
  202. package/dist-server/service/kpi-org-scope/kpi-org-scope-query.js.map +1 -0
  203. package/dist-server/service/kpi-org-scope/kpi-org-scope-type.d.ts +26 -0
  204. package/dist-server/service/kpi-org-scope/kpi-org-scope-type.js +101 -0
  205. package/dist-server/service/kpi-org-scope/kpi-org-scope-type.js.map +1 -0
  206. package/dist-server/service/kpi-org-scope/kpi-org-scope.d.ts +26 -0
  207. package/dist-server/service/kpi-org-scope/kpi-org-scope.js +135 -0
  208. package/dist-server/service/kpi-org-scope/kpi-org-scope.js.map +1 -0
  209. package/dist-server/service/kpi-statistic/kpi-statistic.d.ts +1 -0
  210. package/dist-server/service/kpi-statistic/kpi-statistic.js +11 -0
  211. package/dist-server/service/kpi-statistic/kpi-statistic.js.map +1 -1
  212. package/dist-server/service/kpi-value/kpi-value-mutation.js +71 -7
  213. package/dist-server/service/kpi-value/kpi-value-mutation.js.map +1 -1
  214. package/dist-server/service/kpi-value/kpi-value-type.d.ts +4 -2
  215. package/dist-server/service/kpi-value/kpi-value-type.js +12 -4
  216. package/dist-server/service/kpi-value/kpi-value-type.js.map +1 -1
  217. package/dist-server/service/kpi-value/kpi-value.d.ts +3 -1
  218. package/dist-server/service/kpi-value/kpi-value.js +11 -5
  219. package/dist-server/service/kpi-value/kpi-value.js.map +1 -1
  220. package/dist-server/service/utils/value-date-util.d.ts +1 -0
  221. package/dist-server/service/utils/value-date-util.js +41 -0
  222. package/dist-server/service/utils/value-date-util.js.map +1 -1
  223. package/dist-server/tsconfig.json +10 -0
  224. package/dist-server/tsconfig.tsbuildinfo +1 -1
  225. package/package.json +7 -6
  226. package/server/@types/index.d.ts +11 -0
  227. package/server/controllers/kpi-metric-value-provider.ts +5 -5
  228. package/server/controllers/kpi-value-provider.ts +4 -4
  229. package/server/migrations/1752190849680-seed-kpi-metrics.ts +124 -0
  230. package/server/migrations/1752190849681-seed-kpi.ts +356 -0
  231. package/server/migrations/1752192090123-add-grades-to-kpi.ts +67 -0
  232. package/server/migrations/1752192090124-add-kpi-statistics.ts +719 -0
  233. package/server/migrations/1752192090128-seed-kpi-org-scope.ts +132 -0
  234. package/server/migrations/1752192090129-seed-kpi-values.ts +207 -0
  235. package/server/migrations/grade-data/x11-performance-table.json +962 -0
  236. package/server/migrations/grade-data/x12-performance-table.json +611 -0
  237. package/server/migrations/grade-data/x14-performance-table.json +42 -0
  238. package/server/migrations/grade-data/x21-performance-table.json +889 -0
  239. package/server/migrations/grade-data/x22-performance-table.json +1064 -0
  240. package/server/migrations/grade-data/x23-performance-table.json +42 -0
  241. package/server/migrations/grade-data/x31-performance-table.json +644 -0
  242. package/server/migrations/grade-data/x32-performance-table.json +993 -0
  243. package/server/migrations/grade-data/x33-performance-table.json +195 -0
  244. package/server/migrations/grade-data/x34-performance-table.json +12 -0
  245. package/server/migrations/grade-data/x35-performance-table.json +42 -0
  246. package/server/migrations/grade-data/x41-performance-table.json +825 -0
  247. package/server/migrations/grade-data/x42-performance-table.json +786 -0
  248. package/server/migrations/grade-data/x43-performance-table.json +12 -0
  249. package/server/migrations/grade-data/x44-performance-table.json +42 -0
  250. package/server/migrations/grade-data/x51-performance-table.json +924 -0
  251. package/server/migrations/grade-data/x52-performance-table.json +42 -0
  252. package/server/migrations/grade-data/x61-performance-table.json +261 -0
  253. package/server/migrations/grade-data/x62-performance-table.json +42 -0
  254. package/server/migrations/seed-data/kpi-metrics-seed.json +454 -0
  255. package/server/migrations/seed-data/kpi-org-scope-seed.json +1676 -0
  256. package/server/migrations/seed-data/kpi-values-seed.json +402 -0
  257. package/server/migrations/seed-data/kpis-seed.json +488 -0
  258. package/server/service/index.ts +5 -12
  259. package/server/service/kpi/aggregate-kpi.ts +31 -13
  260. package/server/service/kpi/kpi-formula.service.ts +101 -0
  261. package/server/service/kpi/kpi-history.ts +0 -8
  262. package/server/service/kpi/kpi-mutation.ts +59 -19
  263. package/server/service/kpi/kpi-query.ts +118 -8
  264. package/server/service/kpi/kpi-type.ts +10 -4
  265. package/server/service/kpi/kpi.ts +17 -7
  266. package/server/service/kpi-metric/aggregate-kpi-metric.ts +55 -11
  267. package/server/service/kpi-metric-value/kpi-metric-value-mutation.ts +6 -6
  268. package/server/service/kpi-metric-value/kpi-metric-value-type.ts +4 -4
  269. package/server/service/kpi-metric-value/kpi-metric-value.ts +3 -3
  270. package/server/service/kpi-org-scope/index.ts +11 -0
  271. package/server/service/kpi-org-scope/kpi-org-scope-mutation.ts +173 -0
  272. package/server/service/kpi-org-scope/kpi-org-scope-query.ts +127 -0
  273. package/server/service/kpi-org-scope/kpi-org-scope-type.ts +68 -0
  274. package/server/service/kpi-org-scope/kpi-org-scope.ts +123 -0
  275. package/server/service/kpi-statistic/kpi-statistic.ts +10 -0
  276. package/server/service/kpi-value/kpi-value-mutation.ts +73 -7
  277. package/server/service/kpi-value/kpi-value-type.ts +10 -4
  278. package/server/service/kpi-value/kpi-value.ts +10 -5
  279. package/server/service/utils/value-date-util.ts +47 -0
  280. package/server/types/global.d.ts +8 -0
  281. package/things-factory.config.js +1 -0
  282. package/translations/en.json +15 -3
  283. package/translations/ja.json +13 -3
  284. package/translations/ko.json +15 -3
  285. package/translations/ms.json +13 -3
  286. package/translations/zh.json +13 -3
  287. package/client/google-map/script-loader.ts +0 -173
  288. package/client/pages/kpi-category/kpi-category-importer.ts +0 -90
  289. package/client/pages/kpi-category/kpi-category-list-page.ts +0 -537
  290. package/client/pages/kpi-category/kpi-category-value-calculator.ts +0 -233
  291. package/client/pages/kpi-category-value/kpi-category-value-list-page.ts +0 -404
  292. package/dist-client/google-map/script-loader.d.ts +0 -3
  293. package/dist-client/google-map/script-loader.js +0 -144
  294. package/dist-client/google-map/script-loader.js.map +0 -1
  295. package/dist-client/pages/kpi-category/kpi-category-importer.d.ts +0 -23
  296. package/dist-client/pages/kpi-category/kpi-category-importer.js +0 -92
  297. package/dist-client/pages/kpi-category/kpi-category-importer.js.map +0 -1
  298. package/dist-client/pages/kpi-category/kpi-category-list-page.d.ts +0 -74
  299. package/dist-client/pages/kpi-category/kpi-category-list-page.js +0 -517
  300. package/dist-client/pages/kpi-category/kpi-category-list-page.js.map +0 -1
  301. package/dist-client/pages/kpi-category/kpi-category-value-calculator.d.ts +0 -13
  302. package/dist-client/pages/kpi-category/kpi-category-value-calculator.js +0 -256
  303. package/dist-client/pages/kpi-category/kpi-category-value-calculator.js.map +0 -1
  304. package/dist-client/pages/kpi-category-value/kpi-category-value-list-page.d.ts +0 -63
  305. package/dist-client/pages/kpi-category-value/kpi-category-value-list-page.js +0 -393
  306. package/dist-client/pages/kpi-category-value/kpi-category-value-list-page.js.map +0 -1
  307. package/dist-server/service/kpi-category/index.d.ts +0 -6
  308. package/dist-server/service/kpi-category/index.js +0 -10
  309. package/dist-server/service/kpi-category/index.js.map +0 -1
  310. package/dist-server/service/kpi-category/kpi-category-mutation.d.ts +0 -9
  311. package/dist-server/service/kpi-category/kpi-category-mutation.js +0 -221
  312. package/dist-server/service/kpi-category/kpi-category-mutation.js.map +0 -1
  313. package/dist-server/service/kpi-category/kpi-category-query.d.ts +0 -18
  314. package/dist-server/service/kpi-category/kpi-category-query.js +0 -115
  315. package/dist-server/service/kpi-category/kpi-category-query.js.map +0 -1
  316. package/dist-server/service/kpi-category/kpi-category-type.d.ts +0 -24
  317. package/dist-server/service/kpi-category/kpi-category-type.js +0 -100
  318. package/dist-server/service/kpi-category/kpi-category-type.js.map +0 -1
  319. package/dist-server/service/kpi-category/kpi-category.d.ts +0 -22
  320. package/dist-server/service/kpi-category/kpi-category.js +0 -106
  321. package/dist-server/service/kpi-category/kpi-category.js.map +0 -1
  322. package/dist-server/service/kpi-category-value/index.d.ts +0 -6
  323. package/dist-server/service/kpi-category-value/index.js +0 -10
  324. package/dist-server/service/kpi-category-value/index.js.map +0 -1
  325. package/dist-server/service/kpi-category-value/kpi-category-value-mutation.d.ts +0 -8
  326. package/dist-server/service/kpi-category-value/kpi-category-value-mutation.js +0 -102
  327. package/dist-server/service/kpi-category-value/kpi-category-value-mutation.js.map +0 -1
  328. package/dist-server/service/kpi-category-value/kpi-category-value-query.d.ts +0 -13
  329. package/dist-server/service/kpi-category-value/kpi-category-value-query.js +0 -91
  330. package/dist-server/service/kpi-category-value/kpi-category-value-query.js.map +0 -1
  331. package/dist-server/service/kpi-category-value/kpi-category-value-type.d.ts +0 -19
  332. package/dist-server/service/kpi-category-value/kpi-category-value-type.js +0 -73
  333. package/dist-server/service/kpi-category-value/kpi-category-value-type.js.map +0 -1
  334. package/dist-server/service/kpi-category-value/kpi-category-value.d.ts +0 -19
  335. package/dist-server/service/kpi-category-value/kpi-category-value.js +0 -91
  336. package/dist-server/service/kpi-category-value/kpi-category-value.js.map +0 -1
  337. package/helps/kpi/kpi-category.md +0 -160
  338. package/server/service/kpi-category/index.ts +0 -7
  339. package/server/service/kpi-category/kpi-category-mutation.ts +0 -217
  340. package/server/service/kpi-category/kpi-category-query.ts +0 -87
  341. package/server/service/kpi-category/kpi-category-type.ts +0 -73
  342. package/server/service/kpi-category/kpi-category.ts +0 -95
  343. package/server/service/kpi-category-value/index.ts +0 -7
  344. package/server/service/kpi-category-value/kpi-category-value-mutation.ts +0 -88
  345. package/server/service/kpi-category-value/kpi-category-value-query.ts +0 -62
  346. package/server/service/kpi-category-value/kpi-category-value-type.ts +0 -48
  347. package/server/service/kpi-category-value/kpi-category-value.ts +0 -79
@@ -1,6 +1,6 @@
1
- import { html, css } from 'lit'
1
+ import { LitElement, html, css, nothing } from 'lit'
2
2
  import { customElement, property, state } from 'lit/decorators.js'
3
- import { LitElement } from 'lit'
3
+
4
4
  import '../../../google-map/common-google-map.js'
5
5
 
6
6
  declare global {
@@ -56,6 +56,40 @@ export class KpiMapPanel extends LitElement {
56
56
  .category-button.active:hover {
57
57
  background: #5a6fd8;
58
58
  }
59
+ .period-form {
60
+ margin-top: 12px;
61
+ padding-top: 12px;
62
+ border-top: 1px solid #e9ecef;
63
+ }
64
+ .period-row {
65
+ display: flex;
66
+ align-items: center;
67
+ gap: 8px;
68
+ margin-bottom: 8px;
69
+ }
70
+ .period-label {
71
+ font-size: 0.85rem;
72
+ font-weight: 600;
73
+ color: #495057;
74
+ min-width: 40px;
75
+ }
76
+ .period-select {
77
+ padding: 4px 8px;
78
+ border: 1px solid #ced4da;
79
+ border-radius: 4px;
80
+ background: white;
81
+ font-size: 0.8rem;
82
+ cursor: pointer;
83
+ }
84
+ .period-select:focus {
85
+ outline: none;
86
+ border-color: #667eea;
87
+ }
88
+ .period-separator {
89
+ font-size: 0.85rem;
90
+ color: #6c757d;
91
+ margin: 0 4px;
92
+ }
59
93
  .map-container {
60
94
  flex: 1;
61
95
  position: relative;
@@ -86,7 +120,7 @@ export class KpiMapPanel extends LitElement {
86
120
  .map-control-button:hover {
87
121
  background: #f8f9fa;
88
122
  }
89
- .map-scale {
123
+ .map-scale-direction {
90
124
  position: absolute;
91
125
  bottom: 16px;
92
126
  right: 16px;
@@ -97,6 +131,15 @@ export class KpiMapPanel extends LitElement {
97
131
  font-size: 0.8rem;
98
132
  color: #666;
99
133
  z-index: 10;
134
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
135
+ text-align: center;
136
+ }
137
+ .north-arrow {
138
+ font-size: 1rem;
139
+ margin-bottom: 4px;
140
+ }
141
+ .scale-info {
142
+ font-size: 0.7rem;
100
143
  }
101
144
  common-google-map {
102
145
  width: 100%;
@@ -104,17 +147,14 @@ export class KpiMapPanel extends LitElement {
104
147
  }
105
148
  `
106
149
 
107
- @property({ type: String })
108
- selectedCategory = '전체 KPI'
109
-
110
- @property({ type: Array })
111
- mapData: any[] = []
150
+ @property({ type: String }) selectedCategory = '전체 KPI'
151
+ @property({ type: Array }) mapData: any[] = []
112
152
 
113
- @state()
114
- private map: any = null
115
-
116
- @state()
117
- private mapInitialized = false
153
+ @state() private map: any = null
154
+ @state() private startYear = '전체'
155
+ @state() private startMonth = '전체'
156
+ @state() private endYear = '전체'
157
+ @state() private endMonth = '전체'
118
158
 
119
159
  // mapData를 지도 마커 형식으로 변환
120
160
  get mapLocations() {
@@ -123,15 +163,56 @@ export class KpiMapPanel extends LitElement {
123
163
  lat: item.lat,
124
164
  lng: item.lng,
125
165
  title: item.region,
166
+ region: item.region, // 지역명 추가
167
+ // 커스텀 마커 콘텐츠 생성
168
+ markerContent: `
169
+ <div style="
170
+ background: white;
171
+ border-radius: 8px;
172
+ padding: 8px 12px;
173
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
174
+ border: 1px solid #e9ecef;
175
+ min-width: 80px;
176
+ text-align: center;
177
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
178
+ cursor: pointer;
179
+ ">
180
+ <div style="
181
+ font-size: 11px;
182
+ font-weight: 600;
183
+ color: #495057;
184
+ margin-bottom: 2px;
185
+ white-space: nowrap;
186
+ ">${item.region}</div>
187
+ <div style="
188
+ font-size: 13px;
189
+ font-weight: 700;
190
+ color: #212529;
191
+ margin-bottom: 2px;
192
+ ">${item.kpi}</div>
193
+ <div style="
194
+ font-size: 10px;
195
+ color: ${item.change > 0 ? '#dc3545' : '#198754'};
196
+ font-weight: 500;
197
+ ">${item.change > 0 ? '▲' : '▼'} ${Math.abs(item.change)}%</div>
198
+ </div>
199
+ `,
126
200
  content: `
127
- <div style="padding: 8px;">
128
- <h3 style="margin: 0 0 8px 0; font-size: 14px;">${item.region}</h3>
129
- <p style="margin: 0 0 4px 0; font-size: 12px;">KPI: ${item.kpi}</p>
130
- <p style="margin: 0; font-size: 12px; color: ${item.change > 0 ? '#dc3545' : '#198754'}">
131
- ${item.change > 0 ? '▲' : '▼'} ${Math.abs(item.change)}%
132
- </p>
133
- </div>
134
- `
201
+ <div style="padding: 12px; min-width: 200px;">
202
+ <h3 style="margin: 0 0 8px 0; font-size: 16px; color: #212529;">${item.region}</h3>
203
+ <div style="margin-bottom: 8px;">
204
+ <span style="font-size: 14px; color: #6c757d;">KPI: </span>
205
+ <span style="font-size: 16px; font-weight: 600; color: #212529;">${item.kpi}</span>
206
+ </div>
207
+ <div style="
208
+ font-size: 14px;
209
+ color: ${item.change > 0 ? '#dc3545' : '#198754'};
210
+ font-weight: 500;
211
+ ">
212
+ ${item.change > 0 ? '▲' : '▼'} ${Math.abs(item.change)}% 변화
213
+ </div>
214
+ </div>
215
+ `
135
216
  })) || []
136
217
  )
137
218
  }
@@ -148,7 +229,50 @@ export class KpiMapPanel extends LitElement {
148
229
 
149
230
  private onMapChange(event: CustomEvent) {
150
231
  this.map = event.detail
151
- this.mapInitialized = true
232
+ }
233
+
234
+ private onRegionClick(event: CustomEvent) {
235
+ this.dispatchEvent(
236
+ new CustomEvent('region-click', {
237
+ detail: event.detail,
238
+ bubbles: true,
239
+ composed: true
240
+ })
241
+ )
242
+ }
243
+
244
+ private zoomIn() {
245
+ if (this.map) {
246
+ this.map.setZoom(this.map.getZoom() + 1)
247
+ }
248
+ }
249
+
250
+ private zoomOut() {
251
+ if (this.map) {
252
+ this.map.setZoom(this.map.getZoom() - 1)
253
+ }
254
+ }
255
+
256
+ private resetView() {
257
+ if (this.map) {
258
+ this.map.setCenter({ lat: 36.5, lng: 127.5 })
259
+ this.map.setZoom(7)
260
+ }
261
+ }
262
+
263
+ private onPeriodChange() {
264
+ this.dispatchEvent(
265
+ new CustomEvent('period-change', {
266
+ detail: {
267
+ startYear: this.startYear,
268
+ startMonth: this.startMonth,
269
+ endYear: this.endYear,
270
+ endMonth: this.endMonth
271
+ },
272
+ bubbles: true,
273
+ composed: true
274
+ })
275
+ )
152
276
  }
153
277
 
154
278
  render() {
@@ -192,20 +316,100 @@ export class KpiMapPanel extends LitElement {
192
316
  환경 성과
193
317
  </button>
194
318
  </div>
319
+
320
+ <!-- 기간 선택 폼 -->
321
+ <div class="period-form">
322
+ <div class="period-row">
323
+ <span class="period-label">기간:</span>
324
+ <select
325
+ class="period-select"
326
+ .value=${this.startYear}
327
+ @change=${(e: Event) => {
328
+ this.startYear = (e.target as HTMLSelectElement).value
329
+ this.onPeriodChange()
330
+ }}
331
+ >
332
+ <option value="전체">전체</option>
333
+ <option value="2025">2025년</option>
334
+ <option value="2024">2024년</option>
335
+ <option value="2023">2023년</option>
336
+ <option value="2022">2022년</option>
337
+ </select>
338
+ <select
339
+ class="period-select"
340
+ .value=${this.startMonth}
341
+ @change=${(e: Event) => {
342
+ this.startMonth = (e.target as HTMLSelectElement).value
343
+ this.onPeriodChange()
344
+ }}
345
+ >
346
+ <option value="전체">전체</option>
347
+ <option value="1">1월</option>
348
+ <option value="2">2월</option>
349
+ <option value="3">3월</option>
350
+ <option value="4">4월</option>
351
+ <option value="5">5월</option>
352
+ <option value="6">6월</option>
353
+ <option value="7">7월</option>
354
+ <option value="8">8월</option>
355
+ <option value="9">9월</option>
356
+ <option value="10">10월</option>
357
+ <option value="11">11월</option>
358
+ <option value="12">12월</option>
359
+ </select>
360
+ <span class="period-separator">~</span>
361
+ <select
362
+ class="period-select"
363
+ .value=${this.endYear}
364
+ @change=${(e: Event) => {
365
+ this.endYear = (e.target as HTMLSelectElement).value
366
+ this.onPeriodChange()
367
+ }}
368
+ >
369
+ <option value="전체">전체</option>
370
+ <option value="2025">2025년</option>
371
+ <option value="2024">2024년</option>
372
+ <option value="2023">2023년</option>
373
+ <option value="2022">2022년</option>
374
+ </select>
375
+ <select
376
+ class="period-select"
377
+ .value=${this.endMonth}
378
+ @change=${(e: Event) => {
379
+ this.endMonth = (e.target as HTMLSelectElement).value
380
+ this.onPeriodChange()
381
+ }}
382
+ >
383
+ <option value="전체">전체</option>
384
+ <option value="1">1월</option>
385
+ <option value="2">2월</option>
386
+ <option value="3">3월</option>
387
+ <option value="4">4월</option>
388
+ <option value="5">5월</option>
389
+ <option value="6">6월</option>
390
+ <option value="7">7월</option>
391
+ <option value="8">8월</option>
392
+ <option value="9">9월</option>
393
+ <option value="10">10월</option>
394
+ <option value="11">11월</option>
395
+ <option value="12">12월</option>
396
+ </select>
397
+ </div>
398
+ </div>
195
399
  </div>
196
400
 
197
401
  <div class="map-container">
198
- <!-- 지도 컨트롤 -->
402
+ <!-- 지도 컨트롤 (오른쪽 상단) -->
199
403
  <div class="map-controls">
200
- <button class="map-control-button" title="확대">+</button>
201
- <button class="map-control-button" title="축소">-</button>
202
- <button class="map-control-button" title="뷰 초기화">⌖</button>
404
+ <button class="map-control-button" title="확대" @click=${() => this.zoomIn()}>+</button>
405
+ <button class="map-control-button" title="축소" @click=${() => this.zoomOut()}>-</button>
406
+ <button class="map-control-button" title="뷰 초기화" @click=${() => this.resetView()}>⌖</button>
203
407
  </div>
204
408
 
205
- <!-- 지도 스케일 -->
206
- <div class="map-scale">
207
- N<br />
208
- 25km
409
+ <!-- 스케일 및 방향 정보 (오른쪽 하단) -->
410
+ <div class="map-scale-direction">
411
+ <div class="north-arrow">↑ N</div>
412
+ <div class="scale-info">25km</div>
209
413
  </div>
210
414
 
211
415
  <!-- 공통 Google Maps 컴포넌트 사용 -->
@@ -214,7 +418,16 @@ export class KpiMapPanel extends LitElement {
214
418
  .zoom=${7}
215
419
  .locations=${this.mapLocations}
216
420
  .clusterZoom=${10}
421
+ .controls=${{
422
+ zoomControl: false,
423
+ mapTypeControl: false,
424
+ scaleControl: false,
425
+ streetViewControl: false,
426
+ rotateControl: false,
427
+ fullscreenControl: false
428
+ }}
217
429
  @map-change=${this.onMapChange}
430
+ @region-click=${this.onRegionClick}
218
431
  ></common-google-map>
219
432
  </div>
220
433
  `
@@ -0,0 +1,356 @@
1
+ import { LitElement, html, css, nothing } from 'lit'
2
+ import { customElement, property, state } from 'lit/decorators.js'
3
+
4
+ import '../../../charts/kpi-radar-chart.js'
5
+ import '../../../charts/kpi-boxplot-chart.js'
6
+ import '../../../charts/kpi-trend-chart.js'
7
+
8
+ @customElement('kpi-region-popup')
9
+ export class KpiRegionPopup extends LitElement {
10
+ static styles = css`
11
+ :host {
12
+ display: block;
13
+ position: absolute;
14
+ top: 0;
15
+ left: 402px;
16
+ width: 400px;
17
+ height: 100%;
18
+ background: #fff;
19
+ border-right: 1px solid #e0e0e0;
20
+ z-index: 1000;
21
+ overflow: hidden;
22
+ display: flex;
23
+ flex-direction: column;
24
+ box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
25
+ }
26
+ .popup-content {
27
+ padding: 20px;
28
+ overflow-y: auto;
29
+ flex: 1;
30
+ }
31
+ .popup-header {
32
+ display: flex;
33
+ justify-content: space-between;
34
+ align-items: center;
35
+ padding: 20px;
36
+ border-bottom: 1px solid #e0e0e0;
37
+ background: #fff;
38
+ height: 70px;
39
+ box-sizing: border-box;
40
+ }
41
+ .popup-title {
42
+ font-size: 1.2rem;
43
+ font-weight: bold;
44
+ color: #333;
45
+ }
46
+ .popup-close {
47
+ width: 32px;
48
+ height: 32px;
49
+ border: none;
50
+ background: #fff;
51
+ border-radius: 50%;
52
+ cursor: pointer;
53
+ display: flex;
54
+ align-items: center;
55
+ justify-content: center;
56
+ font-size: 1.2rem;
57
+ color: #666;
58
+ transition: all 0.2s;
59
+ }
60
+ .popup-close:hover {
61
+ background: #e9ecef;
62
+ color: #333;
63
+ }
64
+ .sub-title {
65
+ font-size: 1rem;
66
+ font-weight: 600;
67
+ margin-bottom: 16px;
68
+ color: #495057;
69
+ }
70
+ .chart-section {
71
+ background: #f8f9fa;
72
+ border-radius: 8px;
73
+ padding: 16px;
74
+ margin-bottom: 20px;
75
+ }
76
+ .chart-toggle {
77
+ display: flex;
78
+ gap: 8px;
79
+ margin-bottom: 16px;
80
+ }
81
+ .toggle-button {
82
+ padding: 8px 16px;
83
+ border: 1px solid #ced4da;
84
+ background: #fff;
85
+ border-radius: 6px;
86
+ cursor: pointer;
87
+ font-size: 0.9rem;
88
+ transition: all 0.2s;
89
+ }
90
+ .toggle-button.active {
91
+ background: #667eea;
92
+ color: white;
93
+ border-color: #667eea;
94
+ }
95
+ .chart-container {
96
+ height: 300px;
97
+ display: flex;
98
+ align-items: center;
99
+ justify-content: center;
100
+ background: white;
101
+ border-radius: 6px;
102
+ border: 1px solid #e9ecef;
103
+ }
104
+ .period-selector {
105
+ display: flex;
106
+ gap: 8px;
107
+ margin-bottom: 16px;
108
+ }
109
+ .period-button {
110
+ padding: 6px 12px;
111
+ border: 1px solid #ced4da;
112
+ background: #fff;
113
+ border-radius: 4px;
114
+ cursor: pointer;
115
+ font-size: 0.85rem;
116
+ transition: all 0.2s;
117
+ }
118
+ .period-button.active {
119
+ background: #667eea;
120
+ color: white;
121
+ border-color: #667eea;
122
+ }
123
+ .date-range-selector {
124
+ display: flex;
125
+ align-items: center;
126
+ gap: 8px;
127
+ margin-bottom: 16px;
128
+ }
129
+ .date-select {
130
+ padding: 6px 12px;
131
+ border: 1px solid #ced4da;
132
+ border-radius: 4px;
133
+ background: white;
134
+ font-size: 0.9rem;
135
+ }
136
+ `
137
+
138
+ @property({ type: String }) selectedRegion: string | null = null
139
+ @property({ type: String }) selectedChartType = 'boxplot'
140
+ @property({ type: String }) selectedPeriod = '월'
141
+ @property({ type: String }) startDate = '전체'
142
+ @property({ type: String }) endDate = '전체'
143
+
144
+ @state() private chartData: any[] = []
145
+ @state() private chartCategories: string[] = []
146
+ @state() private trendData: { date: string; value: number; color?: string }[] = []
147
+
148
+ connectedCallback() {
149
+ super.connectedCallback()
150
+ this.generateChartData()
151
+ this.generateTrendData()
152
+ }
153
+
154
+ private generateChartData() {
155
+ // 선택된 지역의 KPI 데이터 생성
156
+ const categories = ['일정 성과', '비용 성과', '품질 성과', '안전 성과', '환경 성과']
157
+ this.chartCategories = categories
158
+
159
+ if (this.selectedChartType === 'radar') {
160
+ // 레이더 차트용 데이터 생성
161
+ this.chartData = categories.map(category => ({
162
+ category,
163
+ value: Math.random() * 50 + 25, // 25-75 범위
164
+ group: this.selectedRegion || '전체'
165
+ }))
166
+ } else {
167
+ // 박스플롯용 데이터 생성
168
+ this.chartData = categories.map(category => {
169
+ const baseValue = Math.random() * 50 + 25 // 25-75 범위
170
+ const variation = Math.random() * 20 // 변동폭
171
+
172
+ // 각 카테고리별로 20개의 데이터 포인트 생성
173
+ const dataPoints: { value: number; group: string }[] = []
174
+ for (let i = 0; i < 20; i++) {
175
+ dataPoints.push({
176
+ value: baseValue + (Math.random() - 0.5) * variation,
177
+ group: category
178
+ })
179
+ }
180
+
181
+ // 통계값 계산
182
+ const values = dataPoints.map(d => d.value).sort((a, b) => a - b)
183
+ const min = Math.min(...values)
184
+ const max = Math.max(...values)
185
+ const q1 = values[Math.floor(values.length * 0.25)]
186
+ const q3 = values[Math.floor(values.length * 0.75)]
187
+ const median = values[Math.floor(values.length * 0.5)]
188
+ const mean = values.reduce((a, b) => a + b, 0) / values.length
189
+
190
+ return {
191
+ group: category,
192
+ min: min,
193
+ max: max,
194
+ q1: q1,
195
+ q3: q3,
196
+ median: median,
197
+ mean: mean,
198
+ value: mean
199
+ }
200
+ })
201
+ }
202
+ }
203
+
204
+ private generateTrendData() {
205
+ // 최근 30일간의 트렌드 데이터 생성
206
+ const today = new Date()
207
+ this.trendData = []
208
+
209
+ for (let i = 29; i >= 0; i--) {
210
+ const date = new Date(today)
211
+ date.setDate(date.getDate() - i)
212
+
213
+ // 기본값에서 약간의 변동을 주어 트렌드 생성
214
+ const baseValue = 50
215
+ const trend = Math.sin(i * 0.2) * 10 // 사인파로 변동
216
+ const noise = (Math.random() - 0.5) * 5 // 랜덤 노이즈
217
+ const value = Math.max(0, Math.min(100, baseValue + trend + noise))
218
+
219
+ this.trendData.push({
220
+ date: date.toISOString().split('T')[0], // YYYY-MM-DD 형식
221
+ value: Math.round(value),
222
+ color: value > 60 ? '#4caf50' : value > 40 ? '#ff9800' : '#f44336'
223
+ })
224
+ }
225
+ }
226
+
227
+ private onClose() {
228
+ this.dispatchEvent(
229
+ new CustomEvent('popup-close', {
230
+ bubbles: true,
231
+ composed: true
232
+ })
233
+ )
234
+ }
235
+
236
+ private onChartTypeChange(type: string) {
237
+ this.selectedChartType = type
238
+ this.generateChartData()
239
+ }
240
+
241
+ private onPeriodChange(period: string) {
242
+ this.dispatchEvent(
243
+ new CustomEvent('period-change', {
244
+ detail: { period },
245
+ bubbles: true,
246
+ composed: true
247
+ })
248
+ )
249
+ this.generateTrendData()
250
+ }
251
+
252
+ private onDateRangeChange() {
253
+ this.dispatchEvent(
254
+ new CustomEvent('date-range-change', {
255
+ detail: { startDate: this.startDate, endDate: this.endDate },
256
+ bubbles: true,
257
+ composed: true
258
+ })
259
+ )
260
+ }
261
+
262
+ render() {
263
+ if (!this.selectedRegion) {
264
+ return nothing
265
+ }
266
+
267
+ return html`
268
+ <div class="popup-header">
269
+ <div class="popup-title">${this.selectedRegion} KPI</div>
270
+ <button class="popup-close" @click=${this.onClose}>×</button>
271
+ </div>
272
+ <div class="popup-content">
273
+ <!-- 종합 성과 -->
274
+ <div class="chart-section">
275
+ <div class="sub-title">종합 성과</div>
276
+ <div class="chart-toggle">
277
+ <button
278
+ class="toggle-button ${this.selectedChartType === 'boxplot' ? 'active' : ''}"
279
+ @click=${() => this.onChartTypeChange('boxplot')}
280
+ >
281
+ 박스플롯
282
+ </button>
283
+ <button
284
+ class="toggle-button ${this.selectedChartType === 'radar' ? 'active' : ''}"
285
+ @click=${() => this.onChartTypeChange('radar')}
286
+ >
287
+ 레이더차트
288
+ </button>
289
+ </div>
290
+ <div class="chart-container">
291
+ ${this.selectedChartType === 'boxplot'
292
+ ? html`
293
+ <kpi-boxplot-chart
294
+ .data=${this.chartData}
295
+ .groups=${this.chartCategories}
296
+ .valueKey=${'value'}
297
+ .currentGroup=${this.selectedRegion || '전체'}
298
+ .independentScale=${true}
299
+ ></kpi-boxplot-chart>
300
+ `
301
+ : html`
302
+ <kpi-radar-chart
303
+ .data=${this.chartData}
304
+ .categories=${this.chartCategories}
305
+ .valueKey=${'value'}
306
+ .currentGroup=${this.selectedRegion || '전체'}
307
+ ></kpi-radar-chart>
308
+ `}
309
+ </div>
310
+ </div>
311
+
312
+ <!-- 기간별 성과 추이 -->
313
+ <div class="trend-section">
314
+ <div class="sub-title">기간별 성과 추이</div>
315
+ <div class="trend-chart-container" style="height: 200px; margin-bottom: 16px;">
316
+ <kpi-trend-chart
317
+ .data=${this.trendData}
318
+ .lineColor=${'#2196f3'}
319
+ .strokeWidth=${2}
320
+ .showPoints=${true}
321
+ .pointRadius=${4}
322
+ ></kpi-trend-chart>
323
+ </div>
324
+ <div class="trend-table">
325
+ <table style="width: 100%; border-collapse: collapse; font-size: 0.85rem;">
326
+ <thead>
327
+ <tr style="border-bottom: 2px solid #f1f3f4; background-color: #f8f9fa;">
328
+ <th style="padding: 8px; text-align: left; font-weight: 600;">날짜</th>
329
+ <th style="padding: 8px; text-align: right; font-weight: 600;">성과</th>
330
+ <th style="padding: 8px; text-align: center; font-weight: 600;">추이</th>
331
+ </tr>
332
+ </thead>
333
+ <tbody>
334
+ ${this.trendData.slice(-10).map(
335
+ (item: any) => html`
336
+ <tr style="border-bottom: 1px solid #f1f3f4;">
337
+ <td style="padding: 8px; font-size: 0.85rem;">${item.date}</td>
338
+ <td style="padding: 8px; text-align: right; font-size: 0.85rem; font-weight: 600;">
339
+ ${item.value}
340
+ </td>
341
+ <td style="padding: 8px; text-align: center; font-size: 0.85rem;">
342
+ <span style="color: ${item.color};">
343
+ ${item.value > 60 ? '▲' : item.value > 40 ? '▲' : '▼'}
344
+ </span>
345
+ </td>
346
+ </tr>
347
+ `
348
+ )}
349
+ </tbody>
350
+ </table>
351
+ </div>
352
+ </div>
353
+ </div>
354
+ `
355
+ }
356
+ }