@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,632 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import gql from 'graphql-tag';
3
+ import { LitElement, html, css, nothing } from 'lit';
4
+ import { customElement, property, state } from 'lit/decorators.js';
5
+ import { client } from '@operato/graphql';
6
+ import { ScrollbarStyles } from '@operato/styles';
7
+ import '../../../components/kpi-radar-chart.js';
8
+ import '../../../components/kpi-boxplot-chart.js';
9
+ import '../../../components/kpi-trend-chart.js';
10
+ let KpiRegionPopup = class KpiRegionPopup extends LitElement {
11
+ constructor() {
12
+ super(...arguments);
13
+ this.selectedRegion = null;
14
+ this.geoGroup = null; // 시군구 geo_group 코드 (있으면 시군구 쿼리 사용)
15
+ this.selectedCategory = '전체 KPI';
16
+ this.selectedChartType = 'boxplot';
17
+ this.selectedPeriod = '월';
18
+ this.startYearMonth = ''; // YYYY-MM 형식
19
+ this.endYearMonth = ''; // YYYY-MM 형식
20
+ this.monthlyTrendData = []; // 부모에서 전달받은 월별 추이 데이터
21
+ this.totalKpiStats = []; // 전체 KPI 통계 (비교용)
22
+ this.chartData = [];
23
+ this.chartCategories = [];
24
+ this.trendData = [];
25
+ this.regionKpiStats = [];
26
+ /** 시군구 모드일 때만 사용하는 해당 시군구 월별 추이 (광역 추이 monthlyTrendData 와 별개) */
27
+ this.sigunguTrendData = [];
28
+ }
29
+ updated(changedProperties) {
30
+ const regionChanged = changedProperties.has('selectedRegion') || changedProperties.has('geoGroup');
31
+ const periodChanged = changedProperties.has('startYearMonth') || changedProperties.has('endYearMonth');
32
+ if ((regionChanged || periodChanged) && this.selectedRegion) {
33
+ this.fetchRegionKpiStats();
34
+ }
35
+ // 추이 갱신: 시군구 모드면 시군구 전용 추이 조회, 아니면 부모가 준 광역(metro) 데이터로 생성
36
+ if (regionChanged || periodChanged || changedProperties.has('selectedCategory') || changedProperties.has('monthlyTrendData')) {
37
+ this._refreshTrend();
38
+ }
39
+ }
40
+ _refreshTrend() {
41
+ if (this.geoGroup) {
42
+ this.fetchSigunguTrend(); // 완료 후 내부에서 generateTrendData 호출
43
+ }
44
+ else {
45
+ this.generateTrendData();
46
+ }
47
+ }
48
+ /** 시군구(geo_group 코드) 단위 월별 추이 조회 → generateTrendData 재생성 */
49
+ async fetchSigunguTrend() {
50
+ var _a;
51
+ if (!this.geoGroup) {
52
+ this.sigunguTrendData = [];
53
+ this.generateTrendData();
54
+ return;
55
+ }
56
+ try {
57
+ const response = await client.query({
58
+ query: gql `
59
+ query GetSigunguTrend($geoGroup: String!, $startYearMonth: String, $endYearMonth: String) {
60
+ kpiZValueMonthlyTrendBySigungu(geoGroup: $geoGroup, startYearMonth: $startYearMonth, endYearMonth: $endYearMonth) {
61
+ geoGroup
62
+ yearMonth
63
+ avgVal
64
+ projectCount
65
+ }
66
+ }
67
+ `,
68
+ variables: {
69
+ geoGroup: this.geoGroup,
70
+ startYearMonth: this.startYearMonth || null,
71
+ endYearMonth: this.endYearMonth || null
72
+ }
73
+ });
74
+ this.sigunguTrendData = ((_a = response.data) === null || _a === void 0 ? void 0 : _a.kpiZValueMonthlyTrendBySigungu) || [];
75
+ }
76
+ catch (e) {
77
+ console.error('시군구 추이 조회 실패:', e);
78
+ this.sigunguTrendData = [];
79
+ }
80
+ this.generateTrendData();
81
+ }
82
+ async fetchRegionKpiStats() {
83
+ if (!this.selectedRegion)
84
+ return;
85
+ try {
86
+ let regionKpiStats;
87
+ if (this.geoGroup) {
88
+ // 시군구 모드: geo_group 코드로 조회
89
+ const response = await client.query({
90
+ query: gql `
91
+ query GetSigunguKpiStats($geoGroup: String!, $startYearMonth: String, $endYearMonth: String) {
92
+ kpiYValueStatsByGeoGroup(geoGroup: $geoGroup, startYearMonth: $startYearMonth, endYearMonth: $endYearMonth) {
93
+ kpiName
94
+ minVal
95
+ q1Val
96
+ medVal
97
+ q3Val
98
+ maxVal
99
+ avgVal
100
+ projectCount
101
+ }
102
+ }
103
+ `,
104
+ variables: {
105
+ geoGroup: this.geoGroup,
106
+ startYearMonth: this.startYearMonth,
107
+ endYearMonth: this.endYearMonth
108
+ }
109
+ });
110
+ regionKpiStats = response.data.kpiYValueStatsByGeoGroup || [];
111
+ }
112
+ else {
113
+ // 광역 모드: 광역시도 이름으로 조회
114
+ const response = await client.query({
115
+ query: gql `
116
+ query GetRegionKpiStats($metroArea: String!, $startYearMonth: String, $endYearMonth: String) {
117
+ kpiYValueStatsByMetroArea(metroArea: $metroArea, startYearMonth: $startYearMonth, endYearMonth: $endYearMonth) {
118
+ kpiName
119
+ minVal
120
+ q1Val
121
+ medVal
122
+ q3Val
123
+ maxVal
124
+ avgVal
125
+ projectCount
126
+ }
127
+ }
128
+ `,
129
+ variables: {
130
+ metroArea: this.selectedRegion,
131
+ startYearMonth: this.startYearMonth,
132
+ endYearMonth: this.endYearMonth
133
+ }
134
+ });
135
+ regionKpiStats = response.data.kpiYValueStatsByMetroArea || [];
136
+ }
137
+ this.regionKpiStats = regionKpiStats;
138
+ this.generateChartData();
139
+ }
140
+ catch (error) {
141
+ console.error('Failed to fetch region KPI stats:', error);
142
+ this.regionKpiStats = [];
143
+ this.generateChartData();
144
+ }
145
+ }
146
+ generateChartData() {
147
+ // kpiName 표기가 'Y1. 일정성과' / '일정성과(Y1)' 등으로 환경마다 달라 전체 문자열 매칭은 깨짐.
148
+ // Y1~Y6 코드만 추출해 짧은 라벨로 매핑.
149
+ const yLabelByCode = {
150
+ Y1: '일정',
151
+ Y2: '비용',
152
+ Y3: '품질',
153
+ Y4: '안전',
154
+ Y5: '환경',
155
+ Y6: '생산성'
156
+ };
157
+ const toCategory = (kpiName) => { var _a, _b; return yLabelByCode[(_b = (_a = (kpiName || '').match(/Y[1-6]/)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : ''] || kpiName; };
158
+ // 레이더 차트와 박스플롯은 항상 전체 Y-level KPI 표시 (selectedCategory 무시)
159
+ if (this.selectedChartType === 'radar') {
160
+ // 레이더 차트용 데이터 생성 — 지역 평균 단일 시리즈
161
+ // (전체평균 기준선은 지역 평균과 차별성이 적어 제거 → 단일 시리즈라 범례도 자동 미표시)
162
+ const data = [];
163
+ const categories = [];
164
+ // 카테고리 수집
165
+ this.regionKpiStats.forEach(stat => {
166
+ const category = toCategory(stat.kpiName);
167
+ if (!categories.includes(category)) {
168
+ categories.push(category);
169
+ }
170
+ });
171
+ // 지역 데이터 추가 (박스플롯과 동일 스케일·정밀도 — Math.round 제거해 수치 일치)
172
+ this.regionKpiStats.forEach(stat => {
173
+ const category = toCategory(stat.kpiName);
174
+ data.push({
175
+ org: this.selectedRegion || '지역',
176
+ category,
177
+ value: stat.avgVal * 100
178
+ });
179
+ });
180
+ this.chartCategories = categories.length > 0 ? categories : ['일정', '비용', '품질', '안전', '환경', '생산성'];
181
+ this.chartData = data;
182
+ }
183
+ else {
184
+ // 박스플롯용 데이터 생성
185
+ const data = [];
186
+ const categories = [];
187
+ this.regionKpiStats.forEach(stat => {
188
+ const category = toCategory(stat.kpiName);
189
+ if (!categories.includes(category)) {
190
+ categories.push(category);
191
+ }
192
+ data.push({
193
+ org: category,
194
+ min: stat.minVal * 100,
195
+ max: stat.maxVal * 100,
196
+ q1: stat.q1Val * 100,
197
+ q3: stat.q3Val * 100,
198
+ median: stat.medVal * 100,
199
+ mean: stat.avgVal * 100,
200
+ value: stat.avgVal * 100
201
+ });
202
+ });
203
+ this.chartCategories = categories.length > 0 ? categories : ['일정', '비용', '품질', '안전', '환경', '생산성'];
204
+ this.chartData = data;
205
+ }
206
+ }
207
+ generateTrendData() {
208
+ if (!this.selectedRegion)
209
+ return;
210
+ // 추이 데이터 소스: 시군구 모드면 시군구 전용 추이(sigunguTrendData), 아니면 광역(metro) 추이에서 해당 지역 필터.
211
+ const rows = this.geoGroup
212
+ ? this.sigunguTrendData
213
+ : this.monthlyTrendData.filter(d => d.geoGroup === this.selectedRegion);
214
+ // 월별 데이터를 YYYY-MM 기준 맵으로
215
+ const byMonth = new Map();
216
+ rows.forEach(d => byMonth.set(d.yearMonth, d));
217
+ // 선택 기간(start~end) 전체 월을 축으로 사용 — 데이터가 없는 월도 레코드(값 0)로 채워
218
+ // 전국 패널의 기간과 동일한 범위를 플로팅. (전체 기간 모드 등으로 start/end 가 비면 데이터 월만 사용)
219
+ const months = this.startYearMonth && this.endYearMonth
220
+ ? this.buildMonthRange(this.startYearMonth, this.endYearMonth)
221
+ : [...byMonth.keys()].sort();
222
+ let prev = null;
223
+ this.trendData = months.map(ym => {
224
+ const d = byMonth.get(ym);
225
+ const hasData = !!d;
226
+ // 데이터 없는 월은 0이 아니라 null — 0(실제 0점)과 구분하여 플로팅/표시에서 제외.
227
+ // 값은 반올림하지 않음(정수화하면 표의 소수점이 항상 .0 으로 나옴) — 표시 시 toFixed(1) 적용.
228
+ const value = hasData ? d.avgVal * 100 : null;
229
+ // 추이: 무데이터 'none', 직전 데이터 없으면(첫 점) 'flat', 그 외 실제 증감 비교
230
+ let trendDir;
231
+ if (!hasData) {
232
+ trendDir = 'none';
233
+ }
234
+ else if (prev === null) {
235
+ trendDir = 'flat';
236
+ }
237
+ else {
238
+ trendDir = value > prev ? 'up' : value < prev ? 'down' : 'flat';
239
+ }
240
+ if (hasData)
241
+ prev = value;
242
+ return {
243
+ date: ym, // YYYY-MM 형식
244
+ value,
245
+ color: value == null ? undefined : value > 60 ? '#4caf50' : value > 40 ? '#ff9800' : '#f44336',
246
+ trendDir
247
+ };
248
+ });
249
+ }
250
+ /** start~end(YYYY-MM) 사이 모든 월을 순서대로 반환. 잘못된 범위는 안전하게 종료. */
251
+ buildMonthRange(start, end) {
252
+ const [sy, sm] = start.split('-').map(Number);
253
+ const [ey, em] = end.split('-').map(Number);
254
+ if (!sy || !sm || !ey || !em)
255
+ return [];
256
+ const out = [];
257
+ let y = sy;
258
+ let m = sm;
259
+ for (let i = 0; i < 240; i++) {
260
+ out.push(`${y}-${String(m).padStart(2, '0')}`);
261
+ if (y === ey && m === em)
262
+ break;
263
+ if (y > ey || (y === ey && m > em))
264
+ break; // start > end 방어
265
+ m++;
266
+ if (m > 12) {
267
+ m = 1;
268
+ y++;
269
+ }
270
+ }
271
+ return out;
272
+ }
273
+ onClose() {
274
+ this.dispatchEvent(new CustomEvent('popup-close', {
275
+ bubbles: true,
276
+ composed: true
277
+ }));
278
+ }
279
+ onChartTypeChange(type) {
280
+ this.selectedChartType = type;
281
+ this.generateChartData();
282
+ }
283
+ render() {
284
+ if (!this.selectedRegion) {
285
+ return nothing;
286
+ }
287
+ return html `
288
+ <div class="popup-header">
289
+ <div class="popup-title">${this.selectedRegion} KPI</div>
290
+ <button class="popup-close" @click=${this.onClose}>×</button>
291
+ </div>
292
+ <div class="popup-content">
293
+ <!-- 종합 성과 -->
294
+ <div class="chart-section">
295
+ <div class="sub-title">종합 성과</div>
296
+ <div class="chart-toggle">
297
+ <button
298
+ class="toggle-button ${this.selectedChartType === 'boxplot' ? 'active' : ''}"
299
+ @click=${() => this.onChartTypeChange('boxplot')}
300
+ >
301
+ 박스플롯
302
+ </button>
303
+ <button
304
+ class="toggle-button ${this.selectedChartType === 'radar' ? 'active' : ''}"
305
+ @click=${() => this.onChartTypeChange('radar')}
306
+ >
307
+ 레이더차트
308
+ </button>
309
+ </div>
310
+ <div class="chart-container">
311
+ ${this.chartData.length === 0
312
+ ? html `<div
313
+ style="display:flex;align-items:center;justify-content:center;height:100%;color:#888;font-size:0.9rem;"
314
+ >
315
+ 선택한 기간에 데이터가 없습니다.
316
+ </div>`
317
+ : this.selectedChartType === 'boxplot'
318
+ ? html `
319
+ <sv-kpi-boxplot-chart
320
+ .data=${this.chartData}
321
+ .groups=${this.chartCategories}
322
+ .valueKey=${'value'}
323
+ .valueLabel=${this.selectedRegion || '지역'}
324
+ .showStatus=${false}
325
+ ></sv-kpi-boxplot-chart>
326
+ `
327
+ : html `
328
+ <sv-kpi-radar-chart
329
+ .data=${this.chartData}
330
+ .categories=${this.chartCategories}
331
+ .valueKey=${'value'}
332
+ ></sv-kpi-radar-chart>
333
+ `}
334
+ </div>
335
+ </div>
336
+
337
+ <!-- 기간별 성과 추이 -->
338
+ <div class="trend-section">
339
+ <div class="sub-title">기간별 성과 추이</div>
340
+ <div class="trend-chart-container" style="height: 200px; margin-bottom: 16px;">
341
+ <sv-kpi-trend-chart
342
+ .data=${this.trendData}
343
+ .lineColor=${'#2196f3'}
344
+ .strokeWidth=${2}
345
+ .showPoints=${false}
346
+ .pointRadius=${4}
347
+ ></sv-kpi-trend-chart>
348
+ </div>
349
+ <div class="trend-table">
350
+ <table style="width: 100%; border-collapse: collapse; font-size: 0.85rem;">
351
+ <thead style="position: sticky; top: 0; background: white; z-index: 1;">
352
+ <tr style="border-bottom: 2px solid #f1f3f4; background-color: #f8f9fa;">
353
+ <th style="padding: 8px; text-align: left; font-weight: 600;">날짜</th>
354
+ <th style="padding: 8px; text-align: right; font-weight: 600;">성과</th>
355
+ <th style="padding: 8px; text-align: center; font-weight: 600;">추이</th>
356
+ </tr>
357
+ </thead>
358
+ <tbody>
359
+ ${[...this.trendData].reverse().map((item) => html `
360
+ <tr style="border-bottom: 1px solid #f1f3f4;">
361
+ <td style="padding: 8px; font-size: 0.85rem;">${item.date}</td>
362
+ <td style="padding: 8px; text-align: right; font-size: 0.85rem; font-weight: 600;">
363
+ ${item.value != null ? item.value.toFixed(1) : '-'}
364
+ </td>
365
+ <td style="padding: 8px; text-align: center; font-size: 0.85rem;">
366
+ <span style="color: ${item.trendDir === 'up' ? '#e53935' : item.trendDir === 'down' ? '#2196f3' : '#999'};">
367
+ ${item.trendDir === 'up' ? '▲' : item.trendDir === 'down' ? '▼' : '–'}
368
+ </span>
369
+ </td>
370
+ </tr>
371
+ `)}
372
+ </tbody>
373
+ </table>
374
+ </div>
375
+ </div>
376
+ </div>
377
+ `;
378
+ }
379
+ };
380
+ KpiRegionPopup.styles = [
381
+ ScrollbarStyles,
382
+ css `
383
+ :host {
384
+ display: block;
385
+ position: absolute;
386
+ top: 0;
387
+ left: 402px;
388
+ width: 400px;
389
+ height: 100%;
390
+ background: #fff;
391
+ border-right: 1px solid #e0e0e0;
392
+ z-index: 1000;
393
+ overflow: hidden;
394
+ display: flex;
395
+ flex-direction: column;
396
+ box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
397
+ }
398
+ .popup-content {
399
+ padding: 20px;
400
+ overflow-y: auto;
401
+ flex: 1;
402
+ }
403
+ .popup-header {
404
+ display: flex;
405
+ justify-content: space-between;
406
+ align-items: center;
407
+ padding: 20px;
408
+ border-bottom: 1px solid #e0e0e0;
409
+ background: #fff;
410
+ height: 70px;
411
+ box-sizing: border-box;
412
+ }
413
+ .popup-title {
414
+ font-size: 1.2rem;
415
+ font-weight: bold;
416
+ color: #333;
417
+ }
418
+ .popup-close {
419
+ width: 32px;
420
+ height: 32px;
421
+ border: none;
422
+ background: #fff;
423
+ border-radius: 50%;
424
+ cursor: pointer;
425
+ display: flex;
426
+ align-items: center;
427
+ justify-content: center;
428
+ font-size: 1.2rem;
429
+ color: #666;
430
+ transition: all 0.2s;
431
+ }
432
+ .popup-close:hover {
433
+ background: #e9ecef;
434
+ color: #333;
435
+ }
436
+ .sub-title {
437
+ font-size: 1rem;
438
+ font-weight: 600;
439
+ margin-bottom: 16px;
440
+ color: #495057;
441
+ }
442
+ .chart-section {
443
+ background: #f8f9fa;
444
+ border-radius: 8px;
445
+ padding: 16px;
446
+ margin-bottom: 20px;
447
+ }
448
+ .chart-toggle {
449
+ display: flex;
450
+ gap: 8px;
451
+ margin-bottom: 16px;
452
+ }
453
+ .toggle-button {
454
+ padding: 8px 16px;
455
+ border: 1px solid #ced4da;
456
+ background: #fff;
457
+ border-radius: 6px;
458
+ cursor: pointer;
459
+ font-size: 0.9rem;
460
+ transition: all 0.2s;
461
+ }
462
+ .toggle-button.active {
463
+ background: #667eea;
464
+ color: white;
465
+ border-color: #667eea;
466
+ }
467
+ .chart-container {
468
+ height: 300px;
469
+ display: flex;
470
+ align-items: center;
471
+ justify-content: center;
472
+ background: white;
473
+ border-radius: 6px;
474
+ border: 1px solid #e9ecef;
475
+ }
476
+ .period-selector {
477
+ display: flex;
478
+ gap: 8px;
479
+ margin-bottom: 16px;
480
+ }
481
+ .period-button {
482
+ padding: 6px 12px;
483
+ border: 1px solid #ced4da;
484
+ background: #fff;
485
+ border-radius: 4px;
486
+ cursor: pointer;
487
+ font-size: 0.85rem;
488
+ transition: all 0.2s;
489
+ }
490
+ .period-button.active {
491
+ background: #667eea;
492
+ color: white;
493
+ border-color: #667eea;
494
+ }
495
+ .date-range-selector {
496
+ display: flex;
497
+ align-items: center;
498
+ gap: 8px;
499
+ margin-bottom: 16px;
500
+ }
501
+ .date-select {
502
+ padding: 6px 12px;
503
+ border: 1px solid #ced4da;
504
+ border-radius: 4px;
505
+ background: white;
506
+ font-size: 0.9rem;
507
+ }
508
+ `
509
+ ];
510
+ // geo_group → 광역시도 매핑 (시군구 모드에서 추이 데이터 조회용)
511
+ KpiRegionPopup.GEO_TO_METRO = {
512
+ '01': '서울특별시',
513
+ '02': '서울특별시',
514
+ '03': '서울특별시',
515
+ '04': '서울특별시',
516
+ '05': '서울특별시',
517
+ '06': '서울특별시',
518
+ '07': '서울특별시',
519
+ '08': '서울특별시',
520
+ '10': '경기도',
521
+ '11': '경기도',
522
+ '12': '경기도',
523
+ '13': '경기도',
524
+ '14': '경기도',
525
+ '15': '경기도',
526
+ '16': '경기도',
527
+ '17': '경기도',
528
+ '18': '경기도',
529
+ '21': '인천광역시',
530
+ '22': '인천광역시',
531
+ '23': '인천광역시',
532
+ '24': '강원도',
533
+ '25': '강원도',
534
+ '26': '강원도',
535
+ '33': '강원도',
536
+ '27': '충청북도',
537
+ '28': '충청북도',
538
+ '29': '충청북도',
539
+ '30': '세종특별자치시',
540
+ '31': '충청남도',
541
+ '32': '충청남도',
542
+ '34': '대전광역시',
543
+ '35': '대전광역시',
544
+ '36': '경상북도',
545
+ '37': '경상북도',
546
+ '38': '경상북도',
547
+ '39': '경상북도',
548
+ '40': '경상북도',
549
+ '41': '대구광역시',
550
+ '42': '대구광역시',
551
+ '43': '대구광역시',
552
+ '44': '울산광역시',
553
+ '45': '울산광역시',
554
+ '46': '부산광역시',
555
+ '47': '부산광역시',
556
+ '48': '부산광역시',
557
+ '49': '부산광역시',
558
+ '50': '경상남도',
559
+ '51': '경상남도',
560
+ '52': '경상남도',
561
+ '53': '경상남도',
562
+ '54': '전라북도',
563
+ '55': '전라북도',
564
+ '56': '전라북도',
565
+ '57': '전라남도',
566
+ '58': '전라남도',
567
+ '59': '전라남도',
568
+ '61': '광주광역시',
569
+ '62': '광주광역시',
570
+ '63': '제주특별자치도'
571
+ };
572
+ __decorate([
573
+ property({ type: String }),
574
+ __metadata("design:type", Object)
575
+ ], KpiRegionPopup.prototype, "selectedRegion", void 0);
576
+ __decorate([
577
+ property({ type: String }),
578
+ __metadata("design:type", Object)
579
+ ], KpiRegionPopup.prototype, "geoGroup", void 0);
580
+ __decorate([
581
+ property({ type: String }),
582
+ __metadata("design:type", Object)
583
+ ], KpiRegionPopup.prototype, "selectedCategory", void 0);
584
+ __decorate([
585
+ property({ type: String }),
586
+ __metadata("design:type", Object)
587
+ ], KpiRegionPopup.prototype, "selectedChartType", void 0);
588
+ __decorate([
589
+ property({ type: String }),
590
+ __metadata("design:type", Object)
591
+ ], KpiRegionPopup.prototype, "selectedPeriod", void 0);
592
+ __decorate([
593
+ property({ type: String }),
594
+ __metadata("design:type", Object)
595
+ ], KpiRegionPopup.prototype, "startYearMonth", void 0);
596
+ __decorate([
597
+ property({ type: String }),
598
+ __metadata("design:type", Object)
599
+ ], KpiRegionPopup.prototype, "endYearMonth", void 0);
600
+ __decorate([
601
+ property({ type: Array }),
602
+ __metadata("design:type", Array)
603
+ ], KpiRegionPopup.prototype, "monthlyTrendData", void 0);
604
+ __decorate([
605
+ property({ type: Array }),
606
+ __metadata("design:type", Array)
607
+ ], KpiRegionPopup.prototype, "totalKpiStats", void 0);
608
+ __decorate([
609
+ state(),
610
+ __metadata("design:type", Array)
611
+ ], KpiRegionPopup.prototype, "chartData", void 0);
612
+ __decorate([
613
+ state(),
614
+ __metadata("design:type", Array)
615
+ ], KpiRegionPopup.prototype, "chartCategories", void 0);
616
+ __decorate([
617
+ state(),
618
+ __metadata("design:type", Array)
619
+ ], KpiRegionPopup.prototype, "trendData", void 0);
620
+ __decorate([
621
+ state(),
622
+ __metadata("design:type", Array)
623
+ ], KpiRegionPopup.prototype, "regionKpiStats", void 0);
624
+ __decorate([
625
+ state(),
626
+ __metadata("design:type", Array)
627
+ ], KpiRegionPopup.prototype, "sigunguTrendData", void 0);
628
+ KpiRegionPopup = __decorate([
629
+ customElement('kpi-region-popup')
630
+ ], KpiRegionPopup);
631
+ export { KpiRegionPopup };
632
+ //# sourceMappingURL=kpi-region-popup.js.map