@dssp/dkpi 1.0.0-alpha.99 → 1.0.0

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 (236) hide show
  1. package/package.json +55 -55
  2. package/dist-client/bootstrap.d.ts +0 -9
  3. package/dist-client/bootstrap.js +0 -272
  4. package/dist-client/bootstrap.js.map +0 -1
  5. package/dist-client/components/kpi-2d-lookup-chart.d.ts +0 -50
  6. package/dist-client/components/kpi-2d-lookup-chart.js +0 -263
  7. package/dist-client/components/kpi-2d-lookup-chart.js.map +0 -1
  8. package/dist-client/components/kpi-boxplot-chart.d.ts +0 -31
  9. package/dist-client/components/kpi-boxplot-chart.js +0 -306
  10. package/dist-client/components/kpi-boxplot-chart.js.map +0 -1
  11. package/dist-client/components/kpi-lookup-chart.d.ts +0 -58
  12. package/dist-client/components/kpi-lookup-chart.js +0 -464
  13. package/dist-client/components/kpi-lookup-chart.js.map +0 -1
  14. package/dist-client/components/kpi-mini-trend-chart.d.ts +0 -14
  15. package/dist-client/components/kpi-mini-trend-chart.js +0 -180
  16. package/dist-client/components/kpi-mini-trend-chart.js.map +0 -1
  17. package/dist-client/components/kpi-radar-chart.d.ts +0 -17
  18. package/dist-client/components/kpi-radar-chart.js +0 -259
  19. package/dist-client/components/kpi-radar-chart.js.map +0 -1
  20. package/dist-client/components/kpi-single-boxplot-chart.d.ts +0 -36
  21. package/dist-client/components/kpi-single-boxplot-chart.js +0 -417
  22. package/dist-client/components/kpi-single-boxplot-chart.js.map +0 -1
  23. package/dist-client/components/kpi-step-lookup-chart.d.ts +0 -33
  24. package/dist-client/components/kpi-step-lookup-chart.js +0 -181
  25. package/dist-client/components/kpi-step-lookup-chart.js.map +0 -1
  26. package/dist-client/components/kpi-trend-chart.d.ts +0 -25
  27. package/dist-client/components/kpi-trend-chart.js +0 -241
  28. package/dist-client/components/kpi-trend-chart.js.map +0 -1
  29. package/dist-client/components/sv-pagenation-control.d.ts +0 -18
  30. package/dist-client/components/sv-pagenation-control.js +0 -142
  31. package/dist-client/components/sv-pagenation-control.js.map +0 -1
  32. package/dist-client/entries/auth/checkin.d.ts +0 -38
  33. package/dist-client/entries/auth/checkin.js +0 -551
  34. package/dist-client/entries/auth/checkin.js.map +0 -1
  35. package/dist-client/entries/public/home.d.ts +0 -8
  36. package/dist-client/entries/public/home.js +0 -97
  37. package/dist-client/entries/public/home.js.map +0 -1
  38. package/dist-client/google-map/common-google-map.d.ts +0 -35
  39. package/dist-client/google-map/common-google-map.js +0 -349
  40. package/dist-client/google-map/common-google-map.js.map +0 -1
  41. package/dist-client/google-map/google-map-loader.d.ts +0 -6
  42. package/dist-client/google-map/google-map-loader.js +0 -23
  43. package/dist-client/google-map/google-map-loader.js.map +0 -1
  44. package/dist-client/icons/menu-icons.d.ts +0 -11
  45. package/dist-client/icons/menu-icons.js +0 -126
  46. package/dist-client/icons/menu-icons.js.map +0 -1
  47. package/dist-client/index.d.ts +0 -0
  48. package/dist-client/index.js +0 -2
  49. package/dist-client/index.js.map +0 -1
  50. package/dist-client/menu.d.ts +0 -23
  51. package/dist-client/menu.js +0 -59
  52. package/dist-client/menu.js.map +0 -1
  53. package/dist-client/pages/component/project-update-header.d.ts +0 -1
  54. package/dist-client/pages/component/project-update-header.js +0 -127
  55. package/dist-client/pages/component/project-update-header.js.map +0 -1
  56. package/dist-client/pages/kpi-admin/dssp-kpi-list-page.d.ts +0 -22
  57. package/dist-client/pages/kpi-admin/dssp-kpi-list-page.js +0 -57
  58. package/dist-client/pages/kpi-admin/dssp-kpi-list-page.js.map +0 -1
  59. package/dist-client/pages/kpi-admin/dssp-kpi-overview.d.ts +0 -47
  60. package/dist-client/pages/kpi-admin/dssp-kpi-overview.js +0 -393
  61. package/dist-client/pages/kpi-admin/dssp-kpi-overview.js.map +0 -1
  62. package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.d.ts +0 -20
  63. package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.js +0 -445
  64. package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.js.map +0 -1
  65. package/dist-client/pages/kpi-admin/kpi-system-guide.d.ts +0 -18
  66. package/dist-client/pages/kpi-admin/kpi-system-guide.js +0 -696
  67. package/dist-client/pages/kpi-admin/kpi-system-guide.js.map +0 -1
  68. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.d.ts +0 -18
  69. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js +0 -259
  70. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js.map +0 -1
  71. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.d.ts +0 -22
  72. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js +0 -346
  73. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js.map +0 -1
  74. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.d.ts +0 -26
  75. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js +0 -433
  76. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js.map +0 -1
  77. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.d.ts +0 -8
  78. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js +0 -78
  79. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js.map +0 -1
  80. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.d.ts +0 -46
  81. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js +0 -945
  82. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js.map +0 -1
  83. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.d.ts +0 -34
  84. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js +0 -238
  85. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js.map +0 -1
  86. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.d.ts +0 -37
  87. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js +0 -689
  88. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js.map +0 -1
  89. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.d.ts +0 -18
  90. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js +0 -131
  91. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js.map +0 -1
  92. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.d.ts +0 -57
  93. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js +0 -866
  94. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js.map +0 -1
  95. package/dist-client/pages/kpi-dashboard/kpi-dashboard.d.ts +0 -63
  96. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js +0 -1097
  97. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js.map +0 -1
  98. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.d.ts +0 -12
  99. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js +0 -82
  100. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js.map +0 -1
  101. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.d.ts +0 -11
  102. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js +0 -65
  103. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js.map +0 -1
  104. package/dist-client/pages/kpi-dashboard/kpi-list-summary.d.ts +0 -13
  105. package/dist-client/pages/kpi-dashboard/kpi-list-summary.js +0 -115
  106. package/dist-client/pages/kpi-dashboard/kpi-list-summary.js.map +0 -1
  107. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.d.ts +0 -15
  108. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js +0 -147
  109. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js.map +0 -1
  110. package/dist-client/pages/kpi-dashboard/kpi-value-entry.d.ts +0 -7
  111. package/dist-client/pages/kpi-dashboard/kpi-value-entry.js +0 -86
  112. package/dist-client/pages/kpi-dashboard/kpi-value-entry.js.map +0 -1
  113. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.d.ts +0 -57
  114. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js +0 -719
  115. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js.map +0 -1
  116. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.d.ts +0 -23
  117. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js +0 -76
  118. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js.map +0 -1
  119. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.d.ts +0 -68
  120. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js +0 -394
  121. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js.map +0 -1
  122. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.d.ts +0 -12
  123. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js +0 -174
  124. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js.map +0 -1
  125. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.d.ts +0 -40
  126. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js +0 -190
  127. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js.map +0 -1
  128. package/dist-client/pages/kpi-value/kpi-value-importer.d.ts +0 -23
  129. package/dist-client/pages/kpi-value/kpi-value-importer.js +0 -93
  130. package/dist-client/pages/kpi-value/kpi-value-importer.js.map +0 -1
  131. package/dist-client/pages/kpi-value/kpi-value-list-page.d.ts +0 -71
  132. package/dist-client/pages/kpi-value/kpi-value-list-page.js +0 -454
  133. package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +0 -1
  134. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.d.ts +0 -69
  135. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js +0 -790
  136. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js.map +0 -1
  137. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.d.ts +0 -22
  138. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js +0 -344
  139. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js.map +0 -1
  140. package/dist-client/pages/project-complete-tabs/pc-tab3-upload.d.ts +0 -21
  141. package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js +0 -335
  142. package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js.map +0 -1
  143. package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.d.ts +0 -51
  144. package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.js +0 -674
  145. package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.js.map +0 -1
  146. package/dist-client/pages/sv-project-complete.d.ts +0 -31
  147. package/dist-client/pages/sv-project-complete.js +0 -359
  148. package/dist-client/pages/sv-project-complete.js.map +0 -1
  149. package/dist-client/pages/sv-project-completed-list.d.ts +0 -27
  150. package/dist-client/pages/sv-project-completed-list.js +0 -416
  151. package/dist-client/pages/sv-project-completed-list.js.map +0 -1
  152. package/dist-client/pages/sv-project-detail.d.ts +0 -73
  153. package/dist-client/pages/sv-project-detail.js +0 -1501
  154. package/dist-client/pages/sv-project-detail.js.map +0 -1
  155. package/dist-client/pages/sv-project-list.d.ts +0 -175
  156. package/dist-client/pages/sv-project-list.js +0 -581
  157. package/dist-client/pages/sv-project-list.js.map +0 -1
  158. package/dist-client/pages/sv-project-update.d.ts +0 -91
  159. package/dist-client/pages/sv-project-update.js +0 -1150
  160. package/dist-client/pages/sv-project-update.js.map +0 -1
  161. package/dist-client/pages/sv-user-management.d.ts +0 -6
  162. package/dist-client/pages/sv-user-management.js +0 -224
  163. package/dist-client/pages/sv-user-management.js.map +0 -1
  164. package/dist-client/route.d.ts +0 -1
  165. package/dist-client/route.js +0 -58
  166. package/dist-client/route.js.map +0 -1
  167. package/dist-client/shared/complete-api.d.ts +0 -45
  168. package/dist-client/shared/complete-api.js +0 -272
  169. package/dist-client/shared/complete-api.js.map +0 -1
  170. package/dist-client/shared/func.d.ts +0 -2
  171. package/dist-client/shared/func.js +0 -22
  172. package/dist-client/shared/func.js.map +0 -1
  173. package/dist-client/shared/geo-group-mapping.d.ts +0 -25
  174. package/dist-client/shared/geo-group-mapping.js +0 -189
  175. package/dist-client/shared/geo-group-mapping.js.map +0 -1
  176. package/dist-client/shared/integration-fetch.d.ts +0 -35
  177. package/dist-client/shared/integration-fetch.js +0 -53
  178. package/dist-client/shared/integration-fetch.js.map +0 -1
  179. package/dist-client/shared/kpi-project-sync.d.ts +0 -16
  180. package/dist-client/shared/kpi-project-sync.js +0 -129
  181. package/dist-client/shared/kpi-project-sync.js.map +0 -1
  182. package/dist-client/themes/dark.css +0 -51
  183. package/dist-client/themes/light.css +0 -51
  184. package/dist-client/tsconfig.tsbuildinfo +0 -1
  185. package/dist-client/viewparts/menu-tools.d.ts +0 -62
  186. package/dist-client/viewparts/menu-tools.js +0 -554
  187. package/dist-client/viewparts/menu-tools.js.map +0 -1
  188. package/dist-client/viewparts/user-circle.d.ts +0 -5
  189. package/dist-client/viewparts/user-circle.js +0 -26
  190. package/dist-client/viewparts/user-circle.js.map +0 -1
  191. package/dist-server/index.d.ts +0 -2
  192. package/dist-server/index.js +0 -6
  193. package/dist-server/index.js.map +0 -1
  194. package/dist-server/migrations/index.d.ts +0 -1
  195. package/dist-server/migrations/index.js +0 -12
  196. package/dist-server/migrations/index.js.map +0 -1
  197. package/dist-server/scripts/calculate-kpi-scores.d.ts +0 -10
  198. package/dist-server/scripts/calculate-kpi-scores.js +0 -333
  199. package/dist-server/scripts/calculate-kpi-scores.js.map +0 -1
  200. package/dist-server/scripts/load-grade-data-migration.d.ts +0 -14
  201. package/dist-server/scripts/load-grade-data-migration.js +0 -279
  202. package/dist-server/scripts/load-grade-data-migration.js.map +0 -1
  203. package/dist-server/scripts/propagate-parent-kpi-values.d.ts +0 -14
  204. package/dist-server/scripts/propagate-parent-kpi-values.js +0 -786
  205. package/dist-server/scripts/propagate-parent-kpi-values.js.map +0 -1
  206. package/dist-server/scripts/recalculate-by-project-name.d.ts +0 -2
  207. package/dist-server/scripts/recalculate-by-project-name.js +0 -72
  208. package/dist-server/scripts/recalculate-by-project-name.js.map +0 -1
  209. package/dist-server/service/index.d.ts +0 -4
  210. package/dist-server/service/index.js +0 -20
  211. package/dist-server/service/index.js.map +0 -1
  212. package/dist-server/service/kpi-metric-value/index.d.ts +0 -4
  213. package/dist-server/service/kpi-metric-value/index.js +0 -8
  214. package/dist-server/service/kpi-metric-value/index.js.map +0 -1
  215. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.d.ts +0 -171
  216. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +0 -993
  217. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +0 -1
  218. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.d.ts +0 -12
  219. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js +0 -56
  220. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js.map +0 -1
  221. package/dist-server/service/kpi-stat/index.d.ts +0 -4
  222. package/dist-server/service/kpi-stat/index.js +0 -8
  223. package/dist-server/service/kpi-stat/index.js.map +0 -1
  224. package/dist-server/service/kpi-stat/kpi-stat-query.d.ts +0 -13
  225. package/dist-server/service/kpi-stat/kpi-stat-query.js +0 -751
  226. package/dist-server/service/kpi-stat/kpi-stat-query.js.map +0 -1
  227. package/dist-server/service/kpi-stat/kpi-stat-types.d.ts +0 -32
  228. package/dist-server/service/kpi-stat/kpi-stat-types.js +0 -180
  229. package/dist-server/service/kpi-stat/kpi-stat-types.js.map +0 -1
  230. package/dist-server/service/kpi-value/index.d.ts +0 -3
  231. package/dist-server/service/kpi-value/index.js +0 -7
  232. package/dist-server/service/kpi-value/index.js.map +0 -1
  233. package/dist-server/service/kpi-value/kpi-value-query.d.ts +0 -8
  234. package/dist-server/service/kpi-value/kpi-value-query.js +0 -90
  235. package/dist-server/service/kpi-value/kpi-value-query.js.map +0 -1
  236. package/dist-server/tsconfig.tsbuildinfo +0 -1
@@ -1,945 +0,0 @@
1
- import { __decorate, __metadata } from "tslib";
2
- import gql from 'graphql-tag';
3
- import { LitElement, html, css } from 'lit';
4
- import { customElement, property, state } from 'lit/decorators.js';
5
- import { ScrollbarStyles } from '@operato/styles';
6
- import { client } from '@operato/graphql';
7
- import '../../../components/kpi-radar-chart.js';
8
- import '../../../components/kpi-boxplot-chart.js';
9
- import '../../../components/kpi-mini-trend-chart.js';
10
- let KpiLeftPanel = class KpiLeftPanel extends LitElement {
11
- constructor() {
12
- super(...arguments);
13
- this.selectedCategory = '전체 KPI';
14
- this.selectedChartType = 'boxplot';
15
- this.mapData = [];
16
- this.startYearMonth = ''; // YYYY-MM 형식
17
- this.endYearMonth = ''; // YYYY-MM 형식
18
- this.sectorType = '';
19
- this.buildingUsage = '';
20
- this.isAllPeriod = false;
21
- this.chartData = [];
22
- this.chartCategories = [];
23
- this.kpiYComprehensiveStats = [];
24
- this.regionalKpiStats = [];
25
- this.monthlyTrendData = [];
26
- // 행정안전부 행정구역코드 순서
27
- this.regionOrder = [
28
- '서울특별시',
29
- '부산광역시',
30
- '대구광역시',
31
- '인천광역시',
32
- '광주광역시',
33
- '대전광역시',
34
- '울산광역시',
35
- '세종특별자치시',
36
- '경기도',
37
- '강원도',
38
- '충청북도',
39
- '충청남도',
40
- '전라북도',
41
- '전라남도',
42
- '경상북도',
43
- '경상남도',
44
- '제주특별자치도'
45
- ];
46
- }
47
- connectedCallback() {
48
- super.connectedCallback();
49
- // 기간 초기값이 비어있으면 현재 월 기준 12개월로 설정
50
- if (!this.startYearMonth || !this.endYearMonth) {
51
- const now = new Date();
52
- const end = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
53
- const start = new Date(now);
54
- start.setMonth(start.getMonth() - 11);
55
- const startStr = `${start.getFullYear()}-${String(start.getMonth() + 1).padStart(2, '0')}`;
56
- this.startYearMonth = startStr;
57
- this.endYearMonth = end;
58
- }
59
- this.fetchKpiYComprehensiveStats();
60
- this.fetchRegionalKpiStats();
61
- this.fetchMonthlyTrendData();
62
- }
63
- updated(changedProperties) {
64
- // selectedCategory, startYearMonth, endYearMonth가 변경되면 데이터 다시 가져오기
65
- if (changedProperties.has('selectedCategory') ||
66
- changedProperties.has('startYearMonth') ||
67
- changedProperties.has('endYearMonth') ||
68
- changedProperties.has('sectorType') ||
69
- changedProperties.has('buildingUsage')) {
70
- // 기간 정보가 설정되어 있을 때만 조회 (빈 문자열이면 전체 기간)
71
- if (this.startYearMonth !== undefined && this.endYearMonth !== undefined) {
72
- this.fetchKpiYComprehensiveStats();
73
- this.fetchRegionalKpiStats();
74
- this.fetchMonthlyTrendData();
75
- }
76
- }
77
- }
78
- async fetchKpiYComprehensiveStats() {
79
- try {
80
- const response = await client.query({
81
- query: gql `
82
- query GetKpiYValueComprehensiveStats(
83
- $startYearMonth: String
84
- $endYearMonth: String
85
- $sectorType: String
86
- $buildingUsage: String
87
- ) {
88
- totalKpiYValueComprehensiveStats(
89
- startYearMonth: $startYearMonth
90
- endYearMonth: $endYearMonth
91
- sectorType: $sectorType
92
- buildingUsage: $buildingUsage
93
- ) {
94
- kpiName
95
- minVal
96
- q1Val
97
- medVal
98
- q3Val
99
- maxVal
100
- avgVal
101
- }
102
- }
103
- `,
104
- variables: {
105
- startYearMonth: this.startYearMonth,
106
- endYearMonth: this.endYearMonth,
107
- sectorType: this.sectorType || null,
108
- buildingUsage: this.buildingUsage || null
109
- }
110
- });
111
- this.kpiYComprehensiveStats = response.data.totalKpiYValueComprehensiveStats || [];
112
- // 부모에게 전체 Y-level KPI 통계 전달
113
- this.dispatchEvent(new CustomEvent('total-kpi-y-stats-loaded', {
114
- detail: { data: this.kpiYComprehensiveStats },
115
- bubbles: true,
116
- composed: true
117
- }));
118
- this.generateChartData();
119
- }
120
- catch (error) {
121
- console.error('Failed to fetch KPI Y comprehensive stats:', error);
122
- this.kpiYComprehensiveStats = [];
123
- this.generateChartData();
124
- }
125
- }
126
- async fetchRegionalKpiStats() {
127
- try {
128
- // selectedCategory에 따라 kpiName 결정
129
- const categoryToKpiName = {
130
- '전체 KPI': null,
131
- '일정 성과': '일정성과(Y1)',
132
- '비용 성과': '비용성과(Y2)',
133
- '품질 성과': '품질성과(Y3)',
134
- '안전 성과': 'Y4. 안전성과',
135
- '환경 성과': '환경성과(Y5)',
136
- '생산성 성과': '생산성성과(Y6)'
137
- };
138
- const kpiName = categoryToKpiName[this.selectedCategory];
139
- const response = await client.query({
140
- query: gql `
141
- query GetRegionalKpiStats(
142
- $kpiName: String
143
- $startYearMonth: String
144
- $endYearMonth: String
145
- $sectorType: String
146
- $buildingUsage: String
147
- ) {
148
- kpiZValueComprehensiveStatsByGeoGroup(
149
- kpiName: $kpiName
150
- startYearMonth: $startYearMonth
151
- endYearMonth: $endYearMonth
152
- sectorType: $sectorType
153
- buildingUsage: $buildingUsage
154
- ) {
155
- geoGroup
156
- avgVal
157
- minVal
158
- maxVal
159
- projectCount
160
- }
161
- }
162
- `,
163
- variables: {
164
- kpiName,
165
- startYearMonth: this.startYearMonth,
166
- endYearMonth: this.endYearMonth,
167
- sectorType: this.sectorType || null,
168
- buildingUsage: this.buildingUsage || null
169
- }
170
- });
171
- this.regionalKpiStats = response.data.kpiZValueComprehensiveStatsByGeoGroup || [];
172
- // 부모에게 지역별 KPI 통계 전달
173
- this.dispatchEvent(new CustomEvent('regional-kpi-stats-loaded', {
174
- detail: { data: this.regionalKpiStats },
175
- bubbles: true,
176
- composed: true
177
- }));
178
- }
179
- catch (error) {
180
- console.error('Failed to fetch regional KPI stats:', error);
181
- this.regionalKpiStats = [];
182
- }
183
- }
184
- async fetchMonthlyTrendData() {
185
- try {
186
- // selectedCategory에 따라 kpiName 결정
187
- const categoryToKpiName = {
188
- '전체 KPI': null,
189
- '일정 성과': '일정성과(Y1)',
190
- '비용 성과': '비용성과(Y2)',
191
- '품질 성과': '품질성과(Y3)',
192
- '안전 성과': 'Y4. 안전성과',
193
- '환경 성과': '환경성과(Y5)',
194
- '생산성 성과': '생산성성과(Y6)'
195
- };
196
- const kpiName = categoryToKpiName[this.selectedCategory];
197
- const response = await client.query({
198
- query: gql `
199
- query GetMonthlyTrendData(
200
- $kpiName: String
201
- $startYearMonth: String
202
- $endYearMonth: String
203
- $sectorType: String
204
- $buildingUsage: String
205
- ) {
206
- kpiZValueMonthlyTrendByGeoGroup(
207
- kpiName: $kpiName
208
- startYearMonth: $startYearMonth
209
- endYearMonth: $endYearMonth
210
- sectorType: $sectorType
211
- buildingUsage: $buildingUsage
212
- ) {
213
- geoGroup
214
- yearMonth
215
- avgVal
216
- projectCount
217
- }
218
- }
219
- `,
220
- variables: {
221
- kpiName,
222
- startYearMonth: this.startYearMonth,
223
- endYearMonth: this.endYearMonth,
224
- sectorType: this.sectorType || null,
225
- buildingUsage: this.buildingUsage || null
226
- }
227
- });
228
- this.monthlyTrendData = response.data.kpiZValueMonthlyTrendByGeoGroup || [];
229
- // 부모에게 월별 추이 데이터 전달
230
- this.dispatchEvent(new CustomEvent('monthly-trend-data-loaded', {
231
- detail: { data: this.monthlyTrendData },
232
- bubbles: true,
233
- composed: true
234
- }));
235
- }
236
- catch (error) {
237
- console.error('Failed to fetch monthly trend data:', error);
238
- this.monthlyTrendData = [];
239
- }
240
- }
241
- getRegionTrendData(region) {
242
- // 해당 지역 월별 값 맵 (20배 스케일)
243
- const byMonth = new Map();
244
- this.monthlyTrendData
245
- .filter(d => d.geoGroup === region)
246
- .forEach(d => byMonth.set(d.yearMonth, d.avgVal * 100));
247
- // 선택 기간 전체 월을 커버 — 데이터 없는 월은 null(0 아님). 기간 정보 없으면 데이터 월만.
248
- const months = this.startYearMonth && this.endYearMonth
249
- ? this._buildMonthRange(this.startYearMonth, this.endYearMonth)
250
- : [...byMonth.keys()].sort();
251
- return months.map(ym => (byMonth.has(ym) ? byMonth.get(ym) : null));
252
- }
253
- /** start~end(YYYY-MM) 사이 모든 월을 순서대로 반환 */
254
- _buildMonthRange(start, end) {
255
- const [sy, sm] = start.split('-').map(Number);
256
- const [ey, em] = end.split('-').map(Number);
257
- if (!sy || !sm || !ey || !em)
258
- return [];
259
- const out = [];
260
- let y = sy;
261
- let m = sm;
262
- for (let i = 0; i < 240; i++) {
263
- out.push(`${y}-${String(m).padStart(2, '0')}`);
264
- if (y === ey && m === em)
265
- break;
266
- if (y > ey || (y === ey && m > em))
267
- break;
268
- m++;
269
- if (m > 12) {
270
- m = 1;
271
- y++;
272
- }
273
- }
274
- return out;
275
- }
276
- calculateChangeRate(region) {
277
- // 해당 지역의 월별 데이터를 시간순으로 정렬
278
- const regionData = this.monthlyTrendData
279
- .filter(d => d.geoGroup === region)
280
- .sort((a, b) => a.yearMonth.localeCompare(b.yearMonth));
281
- if (regionData.length < 2)
282
- return 0;
283
- // 가장 오래된 달과 가장 최근 달의 값 비교
284
- const oldestValue = regionData[0].avgVal;
285
- const latestValue = regionData[regionData.length - 1].avgVal;
286
- if (oldestValue === 0)
287
- return 0;
288
- // 변동율 계산: (최근값 - 과거값) / 과거값 * 100
289
- return ((latestValue - oldestValue) / oldestValue) * 100;
290
- }
291
- generateChartData() {
292
- // kpiName 표기가 'Y1. 일정성과' / '일정성과(Y1)' 등으로 환경마다 달라 전체 문자열 매칭은 깨짐.
293
- // Y1~Y6 코드만 추출해 짧은 라벨로 매핑.
294
- const yLabelByCode = {
295
- Y1: '일정',
296
- Y2: '비용',
297
- Y3: '품질',
298
- Y4: '안전',
299
- Y5: '환경',
300
- Y6: '생산성'
301
- };
302
- 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; };
303
- if (this.selectedChartType === 'radar') {
304
- // 레이더 차트용 데이터 생성 (전체 평균만 표시)
305
- const data = [];
306
- const categories = [];
307
- this.kpiYComprehensiveStats.forEach(stat => {
308
- const category = toCategory(stat.kpiName);
309
- if (!categories.includes(category)) {
310
- categories.push(category);
311
- }
312
- // 전체 평균 데이터만 표시 (비교 시리즈 없음) — 박스플롯과 동일 정밀도(Math.round 제거)
313
- data.push({
314
- org: '전체평균',
315
- category,
316
- value: stat.avgVal * 100
317
- });
318
- });
319
- this.chartCategories = categories.length > 0 ? categories : ['일정', '비용', '품질', '안전', '환경', '생산성'];
320
- this.chartData = data;
321
- }
322
- else {
323
- // 박스플롯용 데이터 생성 (sv-project-detail.ts의 getYKpiBoxplotData 참조)
324
- const data = [];
325
- const categories = [];
326
- this.kpiYComprehensiveStats.forEach(stat => {
327
- const category = toCategory(stat.kpiName);
328
- if (!categories.includes(category)) {
329
- categories.push(category);
330
- }
331
- data.push({
332
- org: category,
333
- min: stat.minVal * 100,
334
- max: stat.maxVal * 100,
335
- q1: stat.q1Val * 100,
336
- q3: stat.q3Val * 100,
337
- median: stat.medVal * 100,
338
- mean: stat.avgVal * 100,
339
- value: stat.avgVal * 100
340
- });
341
- });
342
- this.chartCategories = categories.length > 0 ? categories : ['일정', '비용', '품질', '안전', '환경', '생산성'];
343
- this.chartData = data;
344
- }
345
- }
346
- _onAllPeriodChange(e) {
347
- this.isAllPeriod = e.target.checked;
348
- if (this.isAllPeriod) {
349
- // 전체: 시작 = 선택 가능한 가장 이른 월(2022-01), 종료 = 현재월 → 모든 데이터 포함하며 표시도 명확
350
- // (빈 문자열로 두면 드롭다운이 2022-01~2022-01 로 잘못 보이던 문제 방지)
351
- const now = new Date();
352
- this.startYearMonth = '2022-01';
353
- this.endYearMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
354
- }
355
- this._emitPeriodChange();
356
- }
357
- /** 시작월 설정 — 시작 > 종료(역전)면 종료를 시작에 맞춰 보정. (YYYY-MM 문자열 비교 = 시간순) */
358
- _setStartYearMonth(ym) {
359
- this.startYearMonth = ym;
360
- if (this.endYearMonth && this.startYearMonth > this.endYearMonth) {
361
- this.endYearMonth = this.startYearMonth;
362
- }
363
- this._emitPeriodChange();
364
- }
365
- /** 종료월 설정 — 종료 < 시작(역전)이면 시작을 종료에 맞춰 보정. */
366
- _setEndYearMonth(ym) {
367
- this.endYearMonth = ym;
368
- if (this.startYearMonth && this.endYearMonth < this.startYearMonth) {
369
- this.startYearMonth = this.endYearMonth;
370
- }
371
- this._emitPeriodChange();
372
- }
373
- /** 기간 변경을 부모로 전파 → 지역 팝업 등 다른 패널이 동일 기간을 쓰도록 동기화 */
374
- _emitPeriodChange() {
375
- this.dispatchEvent(new CustomEvent('period-change', {
376
- detail: { startYearMonth: this.startYearMonth, endYearMonth: this.endYearMonth, isAllPeriod: this.isAllPeriod },
377
- bubbles: true,
378
- composed: true
379
- }));
380
- }
381
- onCategoryChange(event) {
382
- const target = event.target;
383
- this.selectedCategory = target.value;
384
- // 카테고리 변경 시 지역별 통계와 월별 추이 데이터만 다시 가져오기
385
- // 종합 성과(박스플롯/레이더)는 항상 전체 Y-level KPI를 표시
386
- this.fetchRegionalKpiStats();
387
- this.fetchMonthlyTrendData();
388
- this.dispatchEvent(new CustomEvent('category-change', {
389
- detail: { category: target.value },
390
- bubbles: true,
391
- composed: true
392
- }));
393
- }
394
- onChartTypeChange(type) {
395
- this.selectedChartType = type;
396
- this.generateChartData();
397
- }
398
- onRegionClick(region) {
399
- // 지도를 해당 광역시도로 포커스
400
- this.dispatchEvent(new CustomEvent('focus-region', {
401
- detail: { region },
402
- bubbles: true,
403
- composed: true
404
- }));
405
- // 팝업 열기
406
- this.dispatchEvent(new CustomEvent('region-click', {
407
- detail: { region },
408
- bubbles: true,
409
- composed: true
410
- }));
411
- }
412
- downloadExcel() {
413
- import('xlsx').then(XLSX => {
414
- const filterLabel = [
415
- this.selectedCategory,
416
- this.sectorType === 'PUBLIC' ? '공공' : this.sectorType === 'PRIVATE' ? '민간' : '',
417
- this.buildingUsage === 'RESIDENTIAL' ? '주거' : this.buildingUsage === 'NON_RESIDENTIAL' ? '비주거' : ''
418
- ]
419
- .filter(Boolean)
420
- .join('_');
421
- const period = this.isAllPeriod ? '전체기간' : `${this.startYearMonth}~${this.endYearMonth}`;
422
- const wb = XLSX.utils.book_new();
423
- // Sheet 1: 검색 조건
424
- const condData = [
425
- { 항목: 'KPI 카테고리', 값: this.selectedCategory },
426
- { 항목: '사업 유형', 값: this.sectorType === 'PUBLIC' ? '공공' : this.sectorType === 'PRIVATE' ? '민간' : '전체' },
427
- {
428
- 항목: '건물 용도',
429
- 값: this.buildingUsage === 'RESIDENTIAL' ? '주거' : this.buildingUsage === 'NON_RESIDENTIAL' ? '비주거' : '전체'
430
- },
431
- { 항목: '기간', 값: this.isAllPeriod ? '전체 기간' : `${this.startYearMonth} ~ ${this.endYearMonth}` },
432
- { 항목: '다운로드 일시', 값: new Date().toLocaleString('ko-KR') }
433
- ];
434
- const wsCond = XLSX.utils.json_to_sheet(condData);
435
- wsCond['!cols'] = [{ wch: 16 }, { wch: 30 }];
436
- XLSX.utils.book_append_sheet(wb, wsCond, '검색 조건');
437
- // Sheet 2: 종합 성과
438
- const yData = this.kpiYComprehensiveStats.map((s) => ({
439
- KPI: s.kpiName,
440
- 최소: Number((s.minVal * 100).toFixed(2)),
441
- Q1: Number((s.q1Val * 100).toFixed(2)),
442
- 중앙값: Number((s.medVal * 100).toFixed(2)),
443
- Q3: Number((s.q3Val * 100).toFixed(2)),
444
- 최대: Number((s.maxVal * 100).toFixed(2)),
445
- 평균: Number((s.avgVal * 100).toFixed(2))
446
- }));
447
- const ws1 = XLSX.utils.json_to_sheet(yData);
448
- ws1['!cols'] = [{ wch: 20 }, { wch: 10 }, { wch: 10 }, { wch: 10 }, { wch: 10 }, { wch: 10 }, { wch: 10 }];
449
- XLSX.utils.book_append_sheet(wb, ws1, '종합 성과');
450
- // Sheet 2: 시도별 성과
451
- const rData = this.getSortedRegionData().map((item) => {
452
- var _a;
453
- const stat = this.regionalKpiStats.find((s) => s.geoGroup === item.region);
454
- return {
455
- 지역: item.region,
456
- 'KPI 점수': Number(item.kpi) || 0,
457
- '변동률(%)': Number(Number(item.change).toFixed(2)),
458
- 프로젝트수: (_a = stat === null || stat === void 0 ? void 0 : stat.projectCount) !== null && _a !== void 0 ? _a : 0
459
- };
460
- });
461
- const ws2 = XLSX.utils.json_to_sheet(rData);
462
- ws2['!cols'] = [{ wch: 16 }, { wch: 12 }, { wch: 12 }, { wch: 12 }];
463
- XLSX.utils.book_append_sheet(wb, ws2, '시도별 성과');
464
- // Sheet 3: 월별 추이
465
- if (this.monthlyTrendData.length > 0) {
466
- const mData = this.monthlyTrendData.map((d) => ({
467
- 지역: d.geoGroup,
468
- 기간: d.yearMonth,
469
- 평균: Number((d.avgVal * 100).toFixed(2)),
470
- 프로젝트수: d.projectCount
471
- }));
472
- const ws3 = XLSX.utils.json_to_sheet(mData);
473
- ws3['!cols'] = [{ wch: 16 }, { wch: 12 }, { wch: 10 }, { wch: 12 }];
474
- XLSX.utils.book_append_sheet(wb, ws3, '월별 추이');
475
- }
476
- XLSX.writeFile(wb, `KPI_대시보드_${filterLabel}_${period}.xlsx`);
477
- });
478
- }
479
- // regionOrder에 따라 지역 데이터를 정렬
480
- getSortedRegionData() {
481
- // 실제 데이터를 기반으로 각 시도에 대한 데이터 생성
482
- return this.regionOrder.map(regionName => {
483
- const stat = this.regionalKpiStats.find(s => s.geoGroup === regionName);
484
- const changeRate = this.calculateChangeRate(regionName);
485
- return {
486
- region: regionName,
487
- kpi: stat ? (stat.avgVal * 100).toFixed(1) : '-',
488
- change: changeRate.toFixed(2),
489
- trendData: this.getRegionTrendData(regionName),
490
- lat: 36.5,
491
- lng: 127.5
492
- };
493
- });
494
- }
495
- getChangeRateClass(change) {
496
- if (change > 0)
497
- return 'change-up';
498
- if (change < 0)
499
- return 'change-down';
500
- return 'change-neutral';
501
- }
502
- getChangeIcon(change) {
503
- if (change > 0)
504
- return '▲';
505
- if (change < 0)
506
- return '▼';
507
- return ''; // 변동 없음(0)이면 화살표 미표시
508
- }
509
- render() {
510
- return html `
511
- <div class="panel-header">
512
- <div class="panel-title">전국 KPI</div>
513
- <button class="panel-close" style="visibility: hidden;">×</button>
514
- </div>
515
- <div class="panel-content">
516
- <!-- 필터: KPI / 사업유형 / 건물용도 -->
517
- <div class="filter-row">
518
- <span class="filter-label">KPI</span>
519
- <select class="filter-select" .value=${this.selectedCategory} @change=${this.onCategoryChange}>
520
- <option value="전체 KPI">전체 KPI</option>
521
- <option value="일정 성과">일정</option>
522
- <option value="비용 성과">비용</option>
523
- <option value="품질 성과">품질</option>
524
- <option value="안전 성과">안전</option>
525
- <option value="환경 성과">환경</option>
526
- <option value="생산성 성과">생산성</option>
527
- </select>
528
- <span class="filter-label">유형</span>
529
- <select
530
- class="filter-select"
531
- .value=${this.sectorType}
532
- @change=${(e) => {
533
- this.sectorType = e.target.value;
534
- // 부모로 전파 → selectedSectorType 동기화 → 지역 팝업도 같은 유형 필터 사용
535
- this.dispatchEvent(new CustomEvent('sector-change', { detail: { sectorType: this.sectorType }, bubbles: true, composed: true }));
536
- }}
537
- >
538
- <option value="">전체</option>
539
- <option value="PUBLIC">공공</option>
540
- <option value="PRIVATE">민간</option>
541
- </select>
542
- <span class="filter-label">용도</span>
543
- <select
544
- class="filter-select"
545
- .value=${this.buildingUsage}
546
- @change=${(e) => {
547
- this.buildingUsage = e.target.value;
548
- // 부모로 전파 → selectedBuildingUsage 동기화 → 지역 팝업도 같은 용도 필터 사용
549
- this.dispatchEvent(new CustomEvent('usage-change', {
550
- detail: { buildingUsage: this.buildingUsage },
551
- bubbles: true,
552
- composed: true
553
- }));
554
- }}
555
- >
556
- <option value="">전체</option>
557
- <option value="RESIDENTIAL">주거</option>
558
- <option value="NON_RESIDENTIAL">비주거</option>
559
- </select>
560
- </div>
561
-
562
- <!-- 기간 필터 -->
563
- <div class="filter-row">
564
- <span class="filter-label">기간</span>
565
- <select
566
- class="filter-select"
567
- ?disabled=${this.isAllPeriod}
568
- @change=${(e) => {
569
- const y = e.target.value;
570
- const m = this.startYearMonth.split('-')[1] || '01';
571
- this._setStartYearMonth(`${y}-${m}`);
572
- }}
573
- >
574
- ${[2022, 2023, 2024, 2025, 2026].map(y => html `<option value="${y}" ?selected=${this.startYearMonth.startsWith(String(y))}>${y}</option>`)}
575
- </select>
576
- <select
577
- class="filter-select"
578
- ?disabled=${this.isAllPeriod}
579
- @change=${(e) => {
580
- const y = this.startYearMonth.split('-')[0] || '2025';
581
- const m = e.target.value.padStart(2, '0');
582
- this._setStartYearMonth(`${y}-${m}`);
583
- }}
584
- >
585
- ${[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].map(m => html `<option value="${m}" ?selected=${parseInt(this.startYearMonth.split('-')[1]) === m}>${m}월</option>`)}
586
- </select>
587
- <span style="color:#6c757d;font-size:0.8rem;">~</span>
588
- <select
589
- class="filter-select"
590
- ?disabled=${this.isAllPeriod}
591
- @change=${(e) => {
592
- const y = e.target.value;
593
- const m = this.endYearMonth.split('-')[1] || '12';
594
- this._setEndYearMonth(`${y}-${m}`);
595
- }}
596
- >
597
- ${[2022, 2023, 2024, 2025, 2026].map(y => html `<option value="${y}" ?selected=${this.endYearMonth.startsWith(String(y))}>${y}</option>`)}
598
- </select>
599
- <select
600
- class="filter-select"
601
- ?disabled=${this.isAllPeriod}
602
- @change=${(e) => {
603
- const y = this.endYearMonth.split('-')[0] || '2026';
604
- const m = e.target.value.padStart(2, '0');
605
- this._setEndYearMonth(`${y}-${m}`);
606
- }}
607
- >
608
- ${[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].map(m => html `<option value="${m}" ?selected=${parseInt(this.endYearMonth.split('-')[1]) === m}>${m}월</option>`)}
609
- </select>
610
- <label style="display:flex;align-items:center;gap:3px;cursor:pointer;">
611
- <input type="checkbox" .checked=${this.isAllPeriod} @change=${this._onAllPeriodChange} style="cursor:pointer;" />
612
- <span class="filter-label" style="min-width:auto;">전체</span>
613
- </label>
614
- </div>
615
-
616
- <!-- 종합 성과 -->
617
- <div class="chart-section">
618
- <div class="sub-title">성과영역별 KPI</div>
619
- <div class="chart-toggle">
620
- <button
621
- class="toggle-button ${this.selectedChartType === 'boxplot' ? 'active' : ''}"
622
- @click=${() => this.onChartTypeChange('boxplot')}
623
- >
624
- 박스플롯
625
- </button>
626
- <button
627
- class="toggle-button ${this.selectedChartType === 'radar' ? 'active' : ''}"
628
- @click=${() => this.onChartTypeChange('radar')}
629
- >
630
- 레이더차트
631
- </button>
632
- </div>
633
- <div class="chart-container">
634
- ${this.chartData.length === 0
635
- ? html `<div style="display:flex;align-items:center;justify-content:center;height:100%;color:#888;font-size:0.9rem;">
636
- 선택한 기간에 데이터가 없습니다.
637
- </div>`
638
- : this.selectedChartType === 'boxplot'
639
- ? html `
640
- <sv-kpi-boxplot-chart
641
- .data=${this.chartData}
642
- .valueKey=${'value'}
643
- .valueLabel=${'전국'}
644
- .showStatus=${false}
645
- ></sv-kpi-boxplot-chart>
646
- `
647
- : html `
648
- <sv-kpi-radar-chart
649
- .data=${this.chartData}
650
- .categories=${this.chartCategories}
651
- .valueKey=${'value'}
652
- ></sv-kpi-radar-chart>
653
- `}
654
- </div>
655
- </div>
656
-
657
- <!-- 시도별 성과 -->
658
- <div class="chart-section">
659
- <div class="sub-title">시도별 종합 KPI</div>
660
- <table class="performance-table">
661
- <thead>
662
- <tr>
663
- <th>지역명</th>
664
- <th>KPI</th>
665
- <th>변동률(%)</th>
666
- <th>성과 추이</th>
667
- </tr>
668
- </thead>
669
- <tbody>
670
- ${this.getSortedRegionData().map((item) => html `
671
- <tr
672
- style="cursor: pointer; transition: background-color 0.2s;"
673
- @click=${() => this.onRegionClick(item.region)}
674
- @mouseenter=${(e) => (e.target.style.backgroundColor = '#f8f9fa')}
675
- @mouseleave=${(e) => (e.target.style.backgroundColor = '')}
676
- >
677
- <td>${item.region}</td>
678
- <td>${item.kpi}</td>
679
- <td>
680
- <div class="change-rate ${this.getChangeRateClass(item.change)}">
681
- ${this.getChangeIcon(item.change)}${Math.abs(item.change)}%
682
- </div>
683
- </td>
684
- <td>
685
- ${item.trendData && item.trendData.length > 0
686
- ? html `
687
- <sv-kpi-mini-trend-chart
688
- .data=${item.trendData}
689
- .width=${60}
690
- .height=${30}
691
- .lineColor=${'#2196f3'}
692
- .strokeWidth=${1.5}
693
- .showPoints=${true}
694
- .pointRadius=${1.5}
695
- ></sv-kpi-mini-trend-chart>
696
- `
697
- : html `<span style="color: #999;">-</span>`}
698
- </td>
699
- </tr>
700
- `)}
701
- </tbody>
702
- </table>
703
- <button class="download-button" @click=${this.downloadExcel}>📊 엑셀 다운로드</button>
704
- </div>
705
- </div>
706
- `;
707
- }
708
- };
709
- KpiLeftPanel.styles = [
710
- ScrollbarStyles,
711
- css `
712
- :host {
713
- display: block;
714
- width: 400px;
715
- background: #fff;
716
- border-right: 1px solid #e0e0e0;
717
- overflow: hidden;
718
- display: flex;
719
- flex-direction: column;
720
- box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
721
- }
722
- .panel-content {
723
- padding: 20px;
724
- overflow-y: auto;
725
- flex: 1;
726
- }
727
- .panel-header {
728
- display: flex;
729
- justify-content: space-between;
730
- align-items: center;
731
- padding: 20px;
732
- border-bottom: 1px solid #e0e0e0;
733
- background: #fff;
734
- height: 70px;
735
- box-sizing: border-box;
736
- }
737
- .panel-title {
738
- font-size: 1.3rem;
739
- font-weight: bold;
740
- color: #333;
741
- margin: 0;
742
- }
743
- .panel-close {
744
- width: 32px;
745
- height: 32px;
746
- border: none;
747
- background: #fff;
748
- border-radius: 50%;
749
- cursor: pointer;
750
- display: flex;
751
- align-items: center;
752
- justify-content: center;
753
- font-size: 1.2rem;
754
- color: #666;
755
- transition: all 0.2s;
756
- }
757
- .panel-close:hover {
758
- background: #e9ecef;
759
- color: #333;
760
- }
761
- .sub-title {
762
- font-size: 1rem;
763
- font-weight: 600;
764
- margin-bottom: 16px;
765
- color: #495057;
766
- }
767
- .chart-section {
768
- background: #f8f9fa;
769
- border-radius: 8px;
770
- padding: 16px;
771
- margin-bottom: 20px;
772
- }
773
- .chart-toggle {
774
- display: flex;
775
- gap: 8px;
776
- margin-bottom: 16px;
777
- }
778
- .toggle-button {
779
- padding: 8px 16px;
780
- border: 1px solid #ced4da;
781
- background: #fff;
782
- border-radius: 6px;
783
- cursor: pointer;
784
- font-size: 0.9rem;
785
- transition: all 0.2s;
786
- }
787
- .toggle-button.active {
788
- background: #667eea;
789
- color: white;
790
- border-color: #667eea;
791
- }
792
- .chart-container {
793
- height: 300px;
794
- display: flex;
795
- align-items: center;
796
- justify-content: center;
797
- background: white;
798
- border-radius: 6px;
799
- border: 1px solid #e9ecef;
800
- }
801
- .performance-table {
802
- width: 100%;
803
- border-collapse: collapse;
804
- margin-top: 16px;
805
- }
806
- .performance-table th,
807
- .performance-table td {
808
- padding: 12px 8px;
809
- text-align: left;
810
- border-bottom: 1px solid #e9ecef;
811
- }
812
- .performance-table th {
813
- background: #f8f9fa;
814
- font-weight: 600;
815
- color: #495057;
816
- }
817
- .performance-table td {
818
- color: #333;
819
- }
820
- .change-rate {
821
- display: flex;
822
- align-items: center;
823
- gap: 4px;
824
- }
825
- .change-up {
826
- color: #dc3545;
827
- }
828
- .change-down {
829
- color: #2196f3;
830
- }
831
- .change-neutral {
832
- color: #6c757d;
833
- }
834
- .trend-chart {
835
- width: 60px;
836
- height: 30px;
837
- background: #f8f9fa;
838
- border-radius: 4px;
839
- display: flex;
840
- align-items: center;
841
- justify-content: center;
842
- font-size: 0.8rem;
843
- color: #666;
844
- }
845
- .download-button {
846
- margin-top: 16px;
847
- padding: 8px 16px;
848
- background: #28a745;
849
- color: white;
850
- border: none;
851
- border-radius: 6px;
852
- cursor: pointer;
853
- font-size: 0.9rem;
854
- display: flex;
855
- align-items: center;
856
- gap: 8px;
857
- }
858
- .download-button:hover {
859
- background: #218838;
860
- }
861
- .filter-row {
862
- display: flex;
863
- align-items: center;
864
- justify-content: space-between;
865
- gap: 6px;
866
- margin-bottom: 10px;
867
- }
868
- .filter-label {
869
- font-size: 0.75rem;
870
- font-weight: 600;
871
- color: #495057;
872
- white-space: nowrap;
873
- }
874
- .filter-select {
875
- flex: 1;
876
- min-width: 0;
877
- padding: 4px 6px;
878
- border: 1px solid #ced4da;
879
- border-radius: 4px;
880
- background: white;
881
- font-size: 0.78rem;
882
- }
883
- .filter-select:focus {
884
- outline: none;
885
- border-color: #667eea;
886
- }
887
- `
888
- ];
889
- __decorate([
890
- property({ type: String }),
891
- __metadata("design:type", Object)
892
- ], KpiLeftPanel.prototype, "selectedCategory", void 0);
893
- __decorate([
894
- property({ type: String }),
895
- __metadata("design:type", Object)
896
- ], KpiLeftPanel.prototype, "selectedChartType", void 0);
897
- __decorate([
898
- property({ type: Array }),
899
- __metadata("design:type", Array)
900
- ], KpiLeftPanel.prototype, "mapData", void 0);
901
- __decorate([
902
- property({ type: String }),
903
- __metadata("design:type", Object)
904
- ], KpiLeftPanel.prototype, "startYearMonth", void 0);
905
- __decorate([
906
- property({ type: String }),
907
- __metadata("design:type", Object)
908
- ], KpiLeftPanel.prototype, "endYearMonth", void 0);
909
- __decorate([
910
- property({ type: String }),
911
- __metadata("design:type", Object)
912
- ], KpiLeftPanel.prototype, "sectorType", void 0);
913
- __decorate([
914
- property({ type: String }),
915
- __metadata("design:type", Object)
916
- ], KpiLeftPanel.prototype, "buildingUsage", void 0);
917
- __decorate([
918
- state(),
919
- __metadata("design:type", Object)
920
- ], KpiLeftPanel.prototype, "isAllPeriod", void 0);
921
- __decorate([
922
- state(),
923
- __metadata("design:type", Array)
924
- ], KpiLeftPanel.prototype, "chartData", void 0);
925
- __decorate([
926
- state(),
927
- __metadata("design:type", Array)
928
- ], KpiLeftPanel.prototype, "chartCategories", void 0);
929
- __decorate([
930
- state(),
931
- __metadata("design:type", Array)
932
- ], KpiLeftPanel.prototype, "kpiYComprehensiveStats", void 0);
933
- __decorate([
934
- state(),
935
- __metadata("design:type", Array)
936
- ], KpiLeftPanel.prototype, "regionalKpiStats", void 0);
937
- __decorate([
938
- state(),
939
- __metadata("design:type", Array)
940
- ], KpiLeftPanel.prototype, "monthlyTrendData", void 0);
941
- KpiLeftPanel = __decorate([
942
- customElement('kpi-left-panel')
943
- ], KpiLeftPanel);
944
- export { KpiLeftPanel };
945
- //# sourceMappingURL=kpi-left-panel.js.map