@dssp/dkpi 1.0.0-alpha.7 → 1.0.0-alpha.71

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 (232) hide show
  1. package/KPI-STATISTICS-SERVICE.md +233 -0
  2. package/_index.html +0 -5
  3. package/assets/favicon.ico +0 -0
  4. package/assets/images/project-image.png +0 -0
  5. package/assets/manifest/apple-1024.png +0 -0
  6. package/assets/manifest/apple-120.png +0 -0
  7. package/assets/manifest/apple-152.png +0 -0
  8. package/assets/manifest/apple-167.png +0 -0
  9. package/assets/manifest/apple-180.png +0 -0
  10. package/assets/manifest/apple-touch-icon.png +0 -0
  11. package/assets/manifest/badge-128x128.png +0 -0
  12. package/assets/manifest/chrome-splashscreen-icon-384x384.png +0 -0
  13. package/assets/manifest/chrome-touch-icon-192x192.png +0 -0
  14. package/assets/manifest/icon-128x128.png +0 -0
  15. package/assets/manifest/icon-192x192.png +0 -0
  16. package/assets/manifest/icon-512x512.png +0 -0
  17. package/assets/manifest/icon-72x72.png +0 -0
  18. package/assets/manifest/icon-96x96.png +0 -0
  19. package/assets/manifest/image-metaog.png +0 -0
  20. package/assets/manifest/maskable_icon.png +0 -0
  21. package/assets/manifest/ms-icon-144x144.png +0 -0
  22. package/assets/manifest/ms-touch-icon-144x144-precomposed.png +0 -0
  23. package/assets/videos/intro.mp4 +0 -0
  24. package/dist-client/bootstrap.js +64 -4
  25. package/dist-client/bootstrap.js.map +1 -1
  26. package/dist-client/components/kpi-2d-lookup-chart.d.ts +43 -0
  27. package/dist-client/components/kpi-2d-lookup-chart.js +253 -0
  28. package/dist-client/components/kpi-2d-lookup-chart.js.map +1 -0
  29. package/dist-client/components/kpi-boxplot-chart.d.ts +24 -0
  30. package/dist-client/components/kpi-boxplot-chart.js +291 -0
  31. package/dist-client/components/kpi-boxplot-chart.js.map +1 -0
  32. package/dist-client/components/kpi-lookup-chart.d.ts +53 -0
  33. package/dist-client/components/kpi-lookup-chart.js +430 -0
  34. package/dist-client/components/kpi-lookup-chart.js.map +1 -0
  35. package/dist-client/components/kpi-mini-trend-chart.d.ts +14 -0
  36. package/dist-client/components/kpi-mini-trend-chart.js +148 -0
  37. package/dist-client/components/kpi-mini-trend-chart.js.map +1 -0
  38. package/dist-client/components/kpi-radar-chart.d.ts +17 -0
  39. package/dist-client/components/kpi-radar-chart.js +259 -0
  40. package/dist-client/components/kpi-radar-chart.js.map +1 -0
  41. package/dist-client/components/kpi-single-boxplot-chart.d.ts +24 -0
  42. package/dist-client/components/kpi-single-boxplot-chart.js +391 -0
  43. package/dist-client/components/kpi-single-boxplot-chart.js.map +1 -0
  44. package/dist-client/components/kpi-trend-chart.d.ts +25 -0
  45. package/dist-client/components/kpi-trend-chart.js +220 -0
  46. package/dist-client/components/kpi-trend-chart.js.map +1 -0
  47. package/dist-client/components/sv-pagenation-control.d.ts +18 -0
  48. package/dist-client/components/sv-pagenation-control.js +142 -0
  49. package/dist-client/components/sv-pagenation-control.js.map +1 -0
  50. package/dist-client/google-map/common-google-map.d.ts +35 -0
  51. package/dist-client/google-map/common-google-map.js +345 -0
  52. package/dist-client/google-map/common-google-map.js.map +1 -0
  53. package/dist-client/google-map/google-map-loader.d.ts +6 -0
  54. package/dist-client/google-map/google-map-loader.js +23 -0
  55. package/dist-client/google-map/google-map-loader.js.map +1 -0
  56. package/dist-client/icons/menu-icons.d.ts +6 -0
  57. package/dist-client/icons/menu-icons.js +42 -0
  58. package/dist-client/icons/menu-icons.js.map +1 -1
  59. package/dist-client/pages/kpi-admin/dssp-kpi-list-page.d.ts +22 -0
  60. package/dist-client/pages/kpi-admin/dssp-kpi-list-page.js +57 -0
  61. package/dist-client/pages/kpi-admin/dssp-kpi-list-page.js.map +1 -0
  62. package/dist-client/pages/kpi-admin/dssp-kpi-overview.d.ts +46 -0
  63. package/dist-client/pages/kpi-admin/dssp-kpi-overview.js +378 -0
  64. package/dist-client/pages/kpi-admin/dssp-kpi-overview.js.map +1 -0
  65. package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.d.ts +20 -0
  66. package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.js +445 -0
  67. package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.js.map +1 -0
  68. package/dist-client/pages/kpi-admin/kpi-system-guide.d.ts +18 -0
  69. package/dist-client/pages/kpi-admin/kpi-system-guide.js +535 -0
  70. package/dist-client/pages/kpi-admin/kpi-system-guide.js.map +1 -0
  71. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.d.ts +18 -0
  72. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js +259 -0
  73. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js.map +1 -0
  74. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.d.ts +22 -0
  75. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js +346 -0
  76. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js.map +1 -0
  77. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.d.ts +26 -0
  78. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js +433 -0
  79. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js.map +1 -0
  80. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.d.ts +8 -0
  81. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js +78 -0
  82. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js.map +1 -0
  83. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.d.ts +38 -0
  84. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js +851 -0
  85. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js.map +1 -0
  86. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.d.ts +42 -0
  87. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js +316 -0
  88. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js.map +1 -0
  89. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.d.ts +28 -0
  90. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js +497 -0
  91. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js.map +1 -0
  92. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.d.ts +18 -0
  93. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js +131 -0
  94. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js.map +1 -0
  95. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.d.ts +52 -0
  96. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js +798 -0
  97. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js.map +1 -0
  98. package/dist-client/pages/kpi-dashboard/kpi-dashboard.d.ts +63 -0
  99. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js +1089 -0
  100. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js.map +1 -0
  101. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.d.ts +12 -0
  102. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js +82 -0
  103. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js.map +1 -0
  104. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.d.ts +11 -0
  105. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js +65 -0
  106. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js.map +1 -0
  107. package/dist-client/pages/kpi-dashboard/kpi-list-summary.d.ts +13 -0
  108. package/dist-client/pages/kpi-dashboard/kpi-list-summary.js +115 -0
  109. package/dist-client/pages/kpi-dashboard/kpi-list-summary.js.map +1 -0
  110. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.d.ts +15 -0
  111. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js +147 -0
  112. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js.map +1 -0
  113. package/dist-client/pages/kpi-dashboard/kpi-value-entry.d.ts +7 -0
  114. package/dist-client/pages/kpi-dashboard/kpi-value-entry.js +86 -0
  115. package/dist-client/pages/kpi-dashboard/kpi-value-entry.js.map +1 -0
  116. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.d.ts +57 -0
  117. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js +719 -0
  118. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js.map +1 -0
  119. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.d.ts +23 -0
  120. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js +76 -0
  121. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js.map +1 -0
  122. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.d.ts +68 -0
  123. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js +380 -0
  124. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js.map +1 -0
  125. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.d.ts +12 -0
  126. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js +174 -0
  127. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js.map +1 -0
  128. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.d.ts +40 -0
  129. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js +190 -0
  130. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js.map +1 -0
  131. package/dist-client/pages/kpi-value/kpi-value-importer.d.ts +23 -0
  132. package/dist-client/pages/kpi-value/kpi-value-importer.js +93 -0
  133. package/dist-client/pages/kpi-value/kpi-value-importer.js.map +1 -0
  134. package/dist-client/pages/kpi-value/kpi-value-list-page.d.ts +71 -0
  135. package/dist-client/pages/kpi-value/kpi-value-list-page.js +464 -0
  136. package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -0
  137. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.d.ts +14 -0
  138. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js +339 -0
  139. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js.map +1 -0
  140. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.d.ts +14 -0
  141. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js +276 -0
  142. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js.map +1 -0
  143. package/dist-client/pages/project-complete-tabs/pc-tab3-upload.d.ts +18 -0
  144. package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js +307 -0
  145. package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js.map +1 -0
  146. package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.d.ts +18 -0
  147. package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.js +433 -0
  148. package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.js.map +1 -0
  149. package/dist-client/pages/sv-project-complete.d.ts +21 -0
  150. package/dist-client/pages/sv-project-complete.js +213 -0
  151. package/dist-client/pages/sv-project-complete.js.map +1 -0
  152. package/dist-client/pages/sv-project-completed-list.d.ts +27 -0
  153. package/dist-client/pages/sv-project-completed-list.js +416 -0
  154. package/dist-client/pages/sv-project-completed-list.js.map +1 -0
  155. package/dist-client/pages/sv-project-detail.d.ts +46 -0
  156. package/dist-client/pages/sv-project-detail.js +1236 -0
  157. package/dist-client/pages/sv-project-detail.js.map +1 -0
  158. package/dist-client/pages/sv-project-list.d.ts +165 -0
  159. package/dist-client/pages/sv-project-list.js +488 -0
  160. package/dist-client/pages/sv-project-list.js.map +1 -0
  161. package/dist-client/route.d.ts +1 -1
  162. package/dist-client/route.js +35 -1
  163. package/dist-client/route.js.map +1 -1
  164. package/dist-client/shared/complete-api.d.ts +8 -0
  165. package/dist-client/shared/complete-api.js +177 -0
  166. package/dist-client/shared/complete-api.js.map +1 -0
  167. package/dist-client/shared/func.d.ts +2 -0
  168. package/dist-client/shared/func.js +22 -0
  169. package/dist-client/shared/func.js.map +1 -0
  170. package/dist-client/themes/dark.css +24 -24
  171. package/dist-client/themes/light.css +23 -23
  172. package/dist-client/tsconfig.tsbuildinfo +1 -1
  173. package/dist-client/viewparts/menu-tools.d.ts +40 -5
  174. package/dist-client/viewparts/menu-tools.js +289 -34
  175. package/dist-client/viewparts/menu-tools.js.map +1 -1
  176. package/dist-server/index.d.ts +2 -0
  177. package/dist-server/index.js +5 -0
  178. package/dist-server/index.js.map +1 -1
  179. package/dist-server/migrations/index.d.ts +1 -0
  180. package/dist-server/migrations/index.js +12 -0
  181. package/dist-server/migrations/index.js.map +1 -0
  182. package/dist-server/scripts/calculate-kpi-scores.d.ts +10 -0
  183. package/dist-server/scripts/calculate-kpi-scores.js +333 -0
  184. package/dist-server/scripts/calculate-kpi-scores.js.map +1 -0
  185. package/dist-server/scripts/load-grade-data-migration.d.ts +14 -0
  186. package/dist-server/scripts/load-grade-data-migration.js +279 -0
  187. package/dist-server/scripts/load-grade-data-migration.js.map +1 -0
  188. package/dist-server/scripts/propagate-parent-kpi-values.d.ts +14 -0
  189. package/dist-server/scripts/propagate-parent-kpi-values.js +786 -0
  190. package/dist-server/scripts/propagate-parent-kpi-values.js.map +1 -0
  191. package/dist-server/scripts/recalculate-by-project-name.d.ts +2 -0
  192. package/dist-server/scripts/recalculate-by-project-name.js +72 -0
  193. package/dist-server/scripts/recalculate-by-project-name.js.map +1 -0
  194. package/dist-server/service/index.d.ts +4 -0
  195. package/dist-server/service/index.js +20 -0
  196. package/dist-server/service/index.js.map +1 -0
  197. package/dist-server/service/kpi-metric-value/index.d.ts +4 -0
  198. package/dist-server/service/kpi-metric-value/index.js +8 -0
  199. package/dist-server/service/kpi-metric-value/index.js.map +1 -0
  200. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.d.ts +74 -0
  201. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +687 -0
  202. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -0
  203. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.d.ts +7 -0
  204. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js +52 -0
  205. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js.map +1 -0
  206. package/dist-server/service/kpi-stat/index.d.ts +4 -0
  207. package/dist-server/service/kpi-stat/index.js +8 -0
  208. package/dist-server/service/kpi-stat/index.js.map +1 -0
  209. package/dist-server/service/kpi-stat/kpi-stat-query.d.ts +12 -0
  210. package/dist-server/service/kpi-stat/kpi-stat-query.js +662 -0
  211. package/dist-server/service/kpi-stat/kpi-stat-query.js.map +1 -0
  212. package/dist-server/service/kpi-stat/kpi-stat-types.d.ts +32 -0
  213. package/dist-server/service/kpi-stat/kpi-stat-types.js +180 -0
  214. package/dist-server/service/kpi-stat/kpi-stat-types.js.map +1 -0
  215. package/dist-server/service/kpi-value/index.d.ts +3 -0
  216. package/dist-server/service/kpi-value/index.js +7 -0
  217. package/dist-server/service/kpi-value/index.js.map +1 -0
  218. package/dist-server/service/kpi-value/kpi-value-query.d.ts +8 -0
  219. package/dist-server/service/kpi-value/kpi-value-query.js +69 -0
  220. package/dist-server/service/kpi-value/kpi-value-query.js.map +1 -0
  221. package/dist-server/tsconfig.tsbuildinfo +1 -1
  222. package/kpi-module-service-tests.md +1286 -0
  223. package/kpi-module-test-report.md +676 -0
  224. package/kpi-module-unit-test-detailed-report.md +925 -0
  225. package/kpi-module-unit-tests-detailed.md +1452 -0
  226. package/package.json +67 -55
  227. package/recalculate-batch.sh +64 -0
  228. package/recalculate-projects-range.sh +98 -0
  229. package/schema.graphql +2514 -455
  230. package/things-factory.config.js +11 -1
  231. package/views/auth-page.html +0 -1
  232. package/views/public/home.html +0 -1
@@ -0,0 +1,719 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import '@material/web/icon/icon.js';
3
+ import '@material/web/button/elevated-button.js';
4
+ import '@material/web/textfield/outlined-text-field.js';
5
+ import { CommonButtonStyles, CommonHeaderStyles, ScrollbarStyles } from '@operato/styles';
6
+ import { PageView, store, connect } from '@operato/shell';
7
+ import { css, html } from 'lit';
8
+ import { customElement, property, state } from 'lit/decorators.js';
9
+ import { ScopedElementsMixin } from '@open-wc/scoped-elements';
10
+ import { client } from '@operato/graphql';
11
+ import { i18next, localize } from '@operato/i18n';
12
+ import { notify } from '@operato/layout';
13
+ import gql from 'graphql-tag';
14
+ let KpiMetricValueEditorPage = class KpiMetricValueEditorPage extends connect(store)(localize(i18next)(ScopedElementsMixin(PageView))) {
15
+ constructor() {
16
+ super(...arguments);
17
+ this.org = '';
18
+ this.startDate = '';
19
+ this.endDate = '';
20
+ this.metrics = [];
21
+ this.dates = [];
22
+ this.loading = false;
23
+ this.error = '';
24
+ this.editingCell = null;
25
+ this._existingValues = [];
26
+ }
27
+ get context() {
28
+ return {
29
+ title: i18next.t('title.kpi metric value editor'),
30
+ actions: [
31
+ Object.assign({ title: i18next.t('button.save'), action: this._saveValues.bind(this) }, CommonButtonStyles.save),
32
+ Object.assign({ title: i18next.t('button.cancel'), action: this._cancel.bind(this) }, CommonButtonStyles.cancel)
33
+ ]
34
+ };
35
+ }
36
+ render() {
37
+ if (this.loading) {
38
+ return html `
39
+ <div class="loading">
40
+ <md-icon>hourglass_empty</md-icon>
41
+ <span>데이터를 불러오는 중...</span>
42
+ </div>
43
+ `;
44
+ }
45
+ if (this.error) {
46
+ return html `
47
+ <div class="error">
48
+ <md-icon>error</md-icon>
49
+ <span>${this.error}</span>
50
+ </div>
51
+ `;
52
+ }
53
+ return html `
54
+ <div class="header">
55
+ <div class="controls">
56
+ <md-outlined-text-field
57
+ label="그룹"
58
+ .value=${this.org}
59
+ @input=${(e) => (this.org = e.target.value)}
60
+ style="width: 150px;"
61
+ ></md-outlined-text-field>
62
+
63
+ <md-outlined-text-field
64
+ label="시작일"
65
+ type="date"
66
+ .value=${this.startDate}
67
+ @input=${(e) => (this.startDate = e.target.value)}
68
+ style="width: 150px;"
69
+ ></md-outlined-text-field>
70
+
71
+ <md-outlined-text-field
72
+ label="종료일"
73
+ type="date"
74
+ .value=${this.endDate}
75
+ @input=${(e) => (this.endDate = e.target.value)}
76
+ style="width: 150px;"
77
+ ></md-outlined-text-field>
78
+
79
+ <md-elevated-button @click=${this._loadData}>
80
+ <md-icon slot="icon">refresh</md-icon>
81
+ 새로고침
82
+ </md-elevated-button>
83
+ </div>
84
+ </div>
85
+
86
+ <div class="table-container">
87
+ <table style="border-collapse: collapse; width: 100%;">
88
+ <thead>
89
+ <tr>
90
+ <th
91
+ style="border: 1px solid #ccc; padding: 8px; background: #f5f5f5; min-width: 200px; left: 0; top: 0;"
92
+ class="metric-header"
93
+ >
94
+ Metric명
95
+ </th>
96
+ ${this.dates.map(date => html `
97
+ <th
98
+ style="border: 1px solid #ccc; padding: 8px; background: #f5f5f5; min-width: 80px; position: sticky; top: 0;"
99
+ >
100
+ ${this._formatDate(date)}
101
+ </th>
102
+ `)}
103
+ </tr>
104
+ </thead>
105
+ <tbody>
106
+ ${this.metrics.map(metric => html `
107
+ <tr>
108
+ <td
109
+ style="border: 1px solid #ccc; padding: 8px; background: #fff; min-width: 200px;"
110
+ class="metric-name"
111
+ >
112
+ ${metric.metricName}
113
+ <span
114
+ style="font-size: 10px; padding: 2px 6px; background: #e0e0e0; border-radius: 4px; margin-left: 8px;"
115
+ >${metric.periodType}</span
116
+ >
117
+ </td>
118
+ ${this.dates.map(date => html `
119
+ <td
120
+ style="border: 1px solid #ccc; padding: 8px; background: #e3f2fd; text-align: center; min-width: 80px; cursor: pointer;"
121
+ @click=${() => this._startEdit(metric.metricId, date)}
122
+ >
123
+ ${this._renderCellContent(metric, date)}
124
+ </td>
125
+ `)}
126
+ </tr>
127
+ `)}
128
+ </tbody>
129
+ </table>
130
+ </div>
131
+
132
+ <div class="legend">
133
+ <div class="legend-item">
134
+ <div class="legend-color" style="background: var(--md-sys-color-primary-container);"></div>
135
+ <span>편집 가능</span>
136
+ </div>
137
+ <div class="legend-item">
138
+ <div class="legend-color" style="background: var(--md-sys-color-secondary-container);"></div>
139
+ <span>하이라이트 (PeriodType에 따라)</span>
140
+ </div>
141
+ <div class="legend-item">
142
+ <div class="legend-color" style="background: var(--md-sys-color-surface-container);"></div>
143
+ <span>편집 불가</span>
144
+ </div>
145
+ </div>
146
+ `;
147
+ }
148
+ _renderCellContent(metric, date) {
149
+ var _a, _b, _c, _d, _e, _f, _g, _h;
150
+ const isEditing = ((_a = this.editingCell) === null || _a === void 0 ? void 0 : _a.metricId) === metric.metricId && ((_b = this.editingCell) === null || _b === void 0 ? void 0 : _b.date) === date;
151
+ // periodType에 따라 값을 가져오는 방식 결정
152
+ let value = null;
153
+ if (metric.periodType === 'DAY') {
154
+ // DAY인 경우 해당 날짜의 값을 사용
155
+ value = (_c = metric.values[date]) === null || _c === void 0 ? void 0 : _c.value;
156
+ }
157
+ else if (metric.periodType === 'WEEK') {
158
+ // WEEK인 경우 해당 주의 월요일의 값을 사용
159
+ const weekKey = this._getWeekKey(date);
160
+ value = (_d = metric.values[weekKey]) === null || _d === void 0 ? void 0 : _d.value;
161
+ }
162
+ else if (metric.periodType === 'MONTH') {
163
+ // MONTH인 경우 해당 월의 값을 사용
164
+ const monthKey = this._getMonthKey(date);
165
+ value = (_e = metric.values[monthKey]) === null || _e === void 0 ? void 0 : _e.value;
166
+ }
167
+ else if (metric.periodType === 'QUARTER') {
168
+ // QUARTER인 경우 해당 분기의 값을 사용
169
+ const quarterKey = this._getQuarterKey(date);
170
+ value = (_f = metric.values[quarterKey]) === null || _f === void 0 ? void 0 : _f.value;
171
+ }
172
+ else if (metric.periodType === 'YEAR') {
173
+ // YEAR인 경우 해당 연도의 값을 사용
174
+ const yearKey = this._getYearKey(date);
175
+ value = (_g = metric.values[yearKey]) === null || _g === void 0 ? void 0 : _g.value;
176
+ }
177
+ else {
178
+ // 기본값: DAY와 동일
179
+ value = (_h = metric.values[date]) === null || _h === void 0 ? void 0 : _h.value;
180
+ }
181
+ if (isEditing) {
182
+ return html `
183
+ <input
184
+ type="number"
185
+ step="0.01"
186
+ .value=${(value || '').toString()}
187
+ @blur=${(e) => this._finishEdit(metric.metricId, date, parseFloat(e.target.value) || 0)}
188
+ @keydown=${(e) => e.key === 'Enter' && e.target.blur()}
189
+ style="width: 100%; text-align: center; border: none; background: transparent;"
190
+ autofocus
191
+ />
192
+ `;
193
+ }
194
+ return html `
195
+ <div style="display: flex; flex-direction: column; gap: 2px;">
196
+ <span style="font-weight: 500; color: ${value !== null && value !== undefined ? 'inherit' : '#999'};">
197
+ ${value !== null && value !== undefined ? value.toLocaleString() : '클릭하여 입력'}
198
+ </span>
199
+ </div>
200
+ `;
201
+ }
202
+ _formatDate(date) {
203
+ const d = new Date(date);
204
+ return d.toLocaleDateString('ko-KR', { month: 'numeric', day: 'numeric' });
205
+ }
206
+ _startEdit(metricId, date) {
207
+ this.editingCell = { metricId, date };
208
+ }
209
+ _finishEdit(metricId, date, value) {
210
+ var _a;
211
+ const metric = this.metrics.find(m => m.metricId === metricId);
212
+ if (metric) {
213
+ // periodType에 따라 저장할 키 결정
214
+ let storageKey = date;
215
+ if (metric.periodType === 'WEEK') {
216
+ storageKey = this._getWeekKey(date);
217
+ }
218
+ else if (metric.periodType === 'MONTH') {
219
+ storageKey = this._getMonthKey(date);
220
+ }
221
+ else if (metric.periodType === 'QUARTER') {
222
+ storageKey = this._getQuarterKey(date);
223
+ }
224
+ else if (metric.periodType === 'YEAR') {
225
+ storageKey = this._getYearKey(date);
226
+ }
227
+ if (!metric.values[storageKey]) {
228
+ metric.values[storageKey] = { value: 0, isDirty: false };
229
+ }
230
+ // 값이 변경되었는지 확인
231
+ const originalValue = (_a = this._findExistingValue(metricId, storageKey)) === null || _a === void 0 ? void 0 : _a.value;
232
+ const isChanged = originalValue !== value;
233
+ metric.values[storageKey].value = value;
234
+ metric.values[storageKey].isDirty = isChanged;
235
+ }
236
+ this.editingCell = null;
237
+ }
238
+ async _loadData() {
239
+ if (!this.startDate || !this.endDate) {
240
+ this.error = '시작일, 종료일을 모두 입력해주세요.';
241
+ return;
242
+ }
243
+ this.loading = true;
244
+ this.error = '';
245
+ try {
246
+ // KPI Metric 목록 조회
247
+ const metricsResponse = await client.query({
248
+ query: gql `
249
+ query ($filters: [Filter!]) {
250
+ kpiMetrics(filters: $filters) {
251
+ items {
252
+ id
253
+ name
254
+ periodType
255
+ active
256
+ }
257
+ total
258
+ }
259
+ }
260
+ `,
261
+ variables: {
262
+ filters: [{ name: 'active', operator: 'eq', value: true }]
263
+ }
264
+ });
265
+ // KPI Metric Value 데이터 조회
266
+ const valuesResponse = await client.query({
267
+ query: gql `
268
+ query ($filters: [Filter!]) {
269
+ kpiMetricValues(filters: $filters) {
270
+ items {
271
+ id
272
+ metricId
273
+ valueDate
274
+ value
275
+ org
276
+ }
277
+ total
278
+ }
279
+ }
280
+ `,
281
+ variables: {
282
+ filters: [
283
+ ...(this.org ? [{ name: 'org', operator: 'eq', value: this.org }] : []),
284
+ { name: 'valueDate', operator: 'between', value: [this.startDate, this.endDate] }
285
+ ]
286
+ }
287
+ });
288
+ // 날짜 배열 생성
289
+ this.dates = this._generateDateArray(this.startDate, this.endDate);
290
+ // KPI Metric 목록을 기준으로 데이터 구성
291
+ this.metrics = metricsResponse.data.kpiMetrics.items.map((metric) => ({
292
+ metricId: metric.id,
293
+ metricName: metric.name,
294
+ periodType: metric.periodType,
295
+ values: {}
296
+ }));
297
+ // 기존 KPI Metric Value 데이터 저장
298
+ this._existingValues = valuesResponse.data.kpiMetricValues.items;
299
+ // KPI Metric Value 데이터를 해당 Metric에 매핑
300
+ valuesResponse.data.kpiMetricValues.items.forEach((value) => {
301
+ const metric = this.metrics.find(m => m.metricId === value.metricId);
302
+ if (metric) {
303
+ metric.values[value.valueDate] = {
304
+ value: value.value,
305
+ isDirty: false
306
+ };
307
+ }
308
+ });
309
+ // KPI Metric Value가 없는 Metric도 빈 값으로 초기화
310
+ this.metrics.forEach(metric => {
311
+ this.dates.forEach(date => {
312
+ if (!metric.values[date]) {
313
+ metric.values[date] = { value: null, isDirty: false };
314
+ }
315
+ });
316
+ });
317
+ this.requestUpdate();
318
+ }
319
+ catch (error) {
320
+ console.error('데이터 로드 중 오류:', error);
321
+ this.error = '데이터를 불러오는 중 오류가 발생했습니다.';
322
+ }
323
+ finally {
324
+ this.loading = false;
325
+ }
326
+ }
327
+ _generateDateArray(startDate, endDate) {
328
+ const dates = [];
329
+ const start = new Date(startDate);
330
+ const end = new Date(endDate);
331
+ // 일별로 생성 (기본)
332
+ for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
333
+ dates.push(d.toLocaleDateString('sv-SE'));
334
+ }
335
+ return dates;
336
+ }
337
+ async _saveValues() {
338
+ try {
339
+ const patches = [];
340
+ this.metrics.forEach(metric => {
341
+ Object.entries(metric.values).forEach(([date, data]) => {
342
+ // dirty 상태인 데이터만 처리
343
+ if (data.isDirty && data.value !== null && data.value !== undefined) {
344
+ const existingValue = this._findExistingValue(metric.metricId, date);
345
+ if (existingValue) {
346
+ patches.push({
347
+ id: existingValue.id,
348
+ value: data.value,
349
+ org: this.org,
350
+ cuFlag: 'M'
351
+ });
352
+ }
353
+ else {
354
+ const normalizedDate = this._normalizeDateByPeriodType(date, metric.periodType);
355
+ patches.push({
356
+ metricId: metric.metricId,
357
+ valueDate: normalizedDate,
358
+ value: data.value,
359
+ org: this.org,
360
+ cuFlag: '+'
361
+ });
362
+ }
363
+ }
364
+ });
365
+ });
366
+ if (patches.length === 0) {
367
+ notify({ message: '저장할 데이터가 없습니다.' });
368
+ return;
369
+ }
370
+ // 디버깅: patches 내용 확인
371
+ // 단일 mutation으로 생성과 업데이트 처리
372
+ const response = await client.mutate({
373
+ mutation: gql `
374
+ mutation ($patches: [KpiMetricValuePatch!]!) {
375
+ updateMultipleKpiMetricValue(patches: $patches) {
376
+ id
377
+ value
378
+ valueDate
379
+ metricId
380
+ }
381
+ }
382
+ `,
383
+ variables: { patches }
384
+ });
385
+ if (!response.errors) {
386
+ // 저장 후 dirty 상태 해제
387
+ response.data.updateMultipleKpiMetricValue.forEach((savedValue) => {
388
+ const metric = this.metrics.find(m => m.metricId === savedValue.metricId);
389
+ if (metric && metric.values[savedValue.valueDate]) {
390
+ metric.values[savedValue.valueDate].isDirty = false;
391
+ }
392
+ });
393
+ notify({ message: 'KPI Metric 값이 성공적으로 저장되었습니다.' });
394
+ this.requestUpdate();
395
+ }
396
+ }
397
+ catch (error) {
398
+ console.error('저장 중 오류:', error);
399
+ notify({ message: '저장 중 오류가 발생했습니다.' });
400
+ }
401
+ }
402
+ _findExistingValue(metricId, date) {
403
+ var _a;
404
+ // 기존 로드된 KPI Metric Value 데이터에서 찾기
405
+ return (_a = this._existingValues) === null || _a === void 0 ? void 0 : _a.find((v) => v.metricId === metricId && v.valueDate === date);
406
+ }
407
+ _getMonthKey(date) {
408
+ const dateObj = new Date(date);
409
+ return `${dateObj.getFullYear()}-${String(dateObj.getMonth() + 1).padStart(2, '0')}`;
410
+ }
411
+ _getQuarterKey(date) {
412
+ const dateObj = new Date(date);
413
+ const quarter = Math.floor(dateObj.getMonth() / 3) + 1;
414
+ return `${dateObj.getFullYear()}-Q${quarter}`;
415
+ }
416
+ _getYearKey(date) {
417
+ const dateObj = new Date(date);
418
+ return `${dateObj.getFullYear()}`;
419
+ }
420
+ _getWeekKey(date) {
421
+ const dateObj = new Date(date);
422
+ const dayOfWeek = dateObj.getDay();
423
+ const daysToMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1;
424
+ const monday = new Date(dateObj);
425
+ monday.setDate(dateObj.getDate() - daysToMonday);
426
+ return monday.toLocaleDateString('sv-SE');
427
+ }
428
+ _getMondayOfWeek(date) {
429
+ const dateObj = new Date(date);
430
+ const dayOfWeek = dateObj.getDay();
431
+ const daysToMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1;
432
+ const monday = new Date(dateObj);
433
+ monday.setDate(dateObj.getDate() - daysToMonday);
434
+ return monday.toLocaleDateString('sv-SE');
435
+ }
436
+ _getFirstDayOfMonth(date) {
437
+ const dateObj = new Date(date);
438
+ return new Date(dateObj.getFullYear(), dateObj.getMonth(), 1).toLocaleDateString('sv-SE');
439
+ }
440
+ _getFirstDayOfQuarter(date) {
441
+ const dateObj = new Date(date);
442
+ const quarter = Math.floor(dateObj.getMonth() / 3);
443
+ const firstMonthOfQuarter = quarter * 3;
444
+ return new Date(dateObj.getFullYear(), firstMonthOfQuarter, 1).toLocaleDateString('sv-SE');
445
+ }
446
+ _getFirstDayOfYear(date) {
447
+ const dateObj = new Date(date);
448
+ return new Date(dateObj.getFullYear(), 0, 1).toLocaleDateString('sv-SE');
449
+ }
450
+ _normalizeDateByPeriodType(date, periodType) {
451
+ const dateObj = new Date(date);
452
+ switch (periodType) {
453
+ case 'DAY':
454
+ return date; // 그대로 사용
455
+ case 'WEEK':
456
+ // 해당 주의 월요일로 설정
457
+ const dayOfWeek = dateObj.getDay();
458
+ const daysToMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1; // 일요일이면 6일 전, 아니면 dayOfWeek - 1
459
+ const monday = new Date(dateObj);
460
+ monday.setDate(dateObj.getDate() - daysToMonday);
461
+ const weeklyDate = monday.toLocaleDateString('sv-SE');
462
+ return weeklyDate;
463
+ case 'MONTH':
464
+ // 년-월 형식으로 설정 (예: "2025-01")
465
+ const monthlyDate = `${dateObj.getFullYear()}-${String(dateObj.getMonth() + 1).padStart(2, '0')}`;
466
+ return monthlyDate;
467
+ case 'QUARTER':
468
+ // 분기 형식으로 설정 (예: "2025-Q1")
469
+ const quarter = Math.floor(dateObj.getMonth() / 3) + 1;
470
+ const quarterlyDate = `${dateObj.getFullYear()}-Q${quarter}`;
471
+ return quarterlyDate;
472
+ case 'YEAR':
473
+ // 년도 형식으로 설정 (예: "2025")
474
+ const yearlyDate = `${dateObj.getFullYear()}`;
475
+ return yearlyDate;
476
+ default:
477
+ return date; // 기본값
478
+ }
479
+ }
480
+ _cancel() {
481
+ // 편집 취소 로직
482
+ this.editingCell = null;
483
+ this._loadData(); // 원본 데이터로 복원
484
+ }
485
+ async pageInitialized(lifecycle) {
486
+ // 기본값 설정 - 지난 1개월
487
+ if (!this.startDate) {
488
+ const today = new Date();
489
+ const oneMonthAgo = new Date(today.getFullYear(), today.getMonth() - 1, today.getDate());
490
+ this.startDate = oneMonthAgo.toLocaleDateString('sv-SE');
491
+ }
492
+ if (!this.endDate) {
493
+ const today = new Date();
494
+ this.endDate = today.toLocaleDateString('sv-SE');
495
+ }
496
+ // 페이지 초기화 시 자동으로 데이터 로드
497
+ await this._loadData();
498
+ }
499
+ };
500
+ KpiMetricValueEditorPage.styles = [
501
+ CommonHeaderStyles,
502
+ ScrollbarStyles,
503
+ css `
504
+ :host {
505
+ display: flex;
506
+ flex-direction: column;
507
+ padding: 20px;
508
+ overflow-x: auto;
509
+ }
510
+
511
+ .header {
512
+ display: flex;
513
+ gap: 16px;
514
+ align-items: center;
515
+ margin-bottom: 20px;
516
+ padding: 16px;
517
+ background: var(--md-sys-color-surface-container);
518
+ border-radius: 8px;
519
+ }
520
+
521
+ .controls {
522
+ display: flex;
523
+ gap: 12px;
524
+ align-items: center;
525
+ }
526
+
527
+ .table-container {
528
+ flex: 1;
529
+ overflow: auto;
530
+ border: 1px solid var(--md-sys-color-outline);
531
+ border-radius: 8px;
532
+ }
533
+
534
+ table {
535
+ width: 100%;
536
+ border-collapse: collapse;
537
+ min-width: max-content;
538
+ }
539
+
540
+ th {
541
+ background: var(--md-sys-color-surface-container-low);
542
+ font-weight: 500;
543
+ padding: 8px 12px;
544
+ border: 1px solid var(--md-sys-color-outline-variant);
545
+ min-width: 80px;
546
+ height: 120px;
547
+ vertical-align: middle;
548
+ }
549
+
550
+ td {
551
+ padding: 8px 12px;
552
+ border: 1px solid var(--md-sys-color-outline-variant);
553
+ min-width: 80px;
554
+ height: 60px;
555
+ text-align: right;
556
+ vertical-align: middle;
557
+ }
558
+
559
+ .metric-header {
560
+ position: sticky;
561
+ left: 0;
562
+ top: 0;
563
+ z-index: 3;
564
+ }
565
+
566
+ .metric-name {
567
+ position: sticky;
568
+ left: 0;
569
+ background: var(--md-sys-color-surface);
570
+ font-weight: 500;
571
+ min-width: 200px;
572
+ text-align: left;
573
+ z-index: 2;
574
+ }
575
+
576
+ tr:hover {
577
+ background: var(--md-sys-color-surface-container-high);
578
+ }
579
+
580
+ th.date-header {
581
+ position: sticky;
582
+ top: 0;
583
+ z-index: 2;
584
+ text-align: center;
585
+ font-size: 11px;
586
+ color: var(--md-sys-color-on-surface-variant);
587
+ writing-mode: vertical-rl;
588
+ text-orientation: mixed;
589
+ min-height: 120px;
590
+ display: flex;
591
+ align-items: center;
592
+ justify-content: center;
593
+ }
594
+
595
+ td.editable-cell {
596
+ cursor: pointer;
597
+ background: var(--md-sys-color-primary-container);
598
+ color: var(--md-sys-color-on-primary-container);
599
+ }
600
+
601
+ td.editable-cell:hover {
602
+ background: var(--md-sys-color-primary-container-high);
603
+ }
604
+
605
+ td.highlighted-cell {
606
+ background: var(--md-sys-color-secondary-container);
607
+ color: var(--md-sys-color-on-secondary-container);
608
+ font-weight: 500;
609
+ }
610
+
611
+ td.highlighted-cell:hover {
612
+ background: var(--md-sys-color-secondary-container-high);
613
+ }
614
+
615
+ td.disabled-cell {
616
+ background: var(--md-sys-color-surface-container);
617
+ color: var(--md-sys-color-on-surface-variant);
618
+ cursor: not-allowed;
619
+ }
620
+
621
+ .value-input {
622
+ width: 100%;
623
+ text-align: center;
624
+ border: none;
625
+ background: transparent;
626
+ color: inherit;
627
+ font-size: 12px;
628
+ padding: 2px;
629
+ }
630
+
631
+ .value-input:focus {
632
+ outline: 2px solid var(--md-sys-color-primary);
633
+ border-radius: 4px;
634
+ }
635
+
636
+ .period-type-badge {
637
+ font-size: 10px;
638
+ padding: 2px 6px;
639
+ border-radius: 4px;
640
+ background: var(--md-sys-color-tertiary-container);
641
+ color: var(--md-sys-color-on-tertiary-container);
642
+ margin-left: 8px;
643
+ }
644
+
645
+ .loading {
646
+ display: flex;
647
+ justify-content: center;
648
+ align-items: center;
649
+ height: 200px;
650
+ color: var(--md-sys-color-on-surface-variant);
651
+ }
652
+
653
+ .error {
654
+ color: var(--md-sys-color-error);
655
+ padding: 16px;
656
+ text-align: center;
657
+ }
658
+
659
+ .legend {
660
+ display: flex;
661
+ gap: 16px;
662
+ margin-top: 16px;
663
+ font-size: 12px;
664
+ }
665
+
666
+ .legend-item {
667
+ display: flex;
668
+ align-items: center;
669
+ gap: 4px;
670
+ }
671
+
672
+ .legend-color {
673
+ width: 16px;
674
+ height: 16px;
675
+ border-radius: 2px;
676
+ }
677
+ `
678
+ ];
679
+ __decorate([
680
+ property({ type: String }),
681
+ __metadata("design:type", String)
682
+ ], KpiMetricValueEditorPage.prototype, "org", void 0);
683
+ __decorate([
684
+ property({ type: String }),
685
+ __metadata("design:type", String)
686
+ ], KpiMetricValueEditorPage.prototype, "startDate", void 0);
687
+ __decorate([
688
+ property({ type: String }),
689
+ __metadata("design:type", String)
690
+ ], KpiMetricValueEditorPage.prototype, "endDate", void 0);
691
+ __decorate([
692
+ state(),
693
+ __metadata("design:type", Array)
694
+ ], KpiMetricValueEditorPage.prototype, "metrics", void 0);
695
+ __decorate([
696
+ state(),
697
+ __metadata("design:type", Array)
698
+ ], KpiMetricValueEditorPage.prototype, "dates", void 0);
699
+ __decorate([
700
+ state(),
701
+ __metadata("design:type", Boolean)
702
+ ], KpiMetricValueEditorPage.prototype, "loading", void 0);
703
+ __decorate([
704
+ state(),
705
+ __metadata("design:type", String)
706
+ ], KpiMetricValueEditorPage.prototype, "error", void 0);
707
+ __decorate([
708
+ state(),
709
+ __metadata("design:type", Object)
710
+ ], KpiMetricValueEditorPage.prototype, "editingCell", void 0);
711
+ __decorate([
712
+ state(),
713
+ __metadata("design:type", Array)
714
+ ], KpiMetricValueEditorPage.prototype, "_existingValues", void 0);
715
+ KpiMetricValueEditorPage = __decorate([
716
+ customElement('kpi-metric-value-editor-page')
717
+ ], KpiMetricValueEditorPage);
718
+ export { KpiMetricValueEditorPage };
719
+ //# sourceMappingURL=kpi-metric-value-editor-page.js.map