@things-factory/kpi 1.0.0-alpha.5 → 9.0.9

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 (309) hide show
  1. package/README.md +74 -0
  2. package/client/pages/kpi/kpi-list-page.ts +97 -47
  3. package/client/pages/kpi/kpi-overview-sample.ts +260 -0
  4. package/client/pages/kpi/kpi-overview.ts +271 -0
  5. package/client/pages/kpi-category/kpi-category-list-page.ts +39 -50
  6. package/client/pages/kpi-dashboard/kpi-alert-panel.ts +114 -0
  7. package/client/pages/kpi-dashboard/kpi-dashboard.ts +285 -0
  8. package/client/pages/kpi-dashboard/kpi-grade-visualization.ts +75 -0
  9. package/client/pages/kpi-dashboard/kpi-history-viewer.ts +58 -0
  10. package/client/pages/kpi-dashboard/kpi-list-summary.ts +100 -0
  11. package/client/pages/kpi-dashboard/kpi-performance-summary.ts +124 -0
  12. package/client/pages/kpi-dashboard/kpi-value-entry.ts +78 -0
  13. package/client/pages/kpi-grade/kpi-grade-list-page.ts +58 -68
  14. package/client/pages/kpi-history/kpi-history-list-page.ts +146 -0
  15. package/client/pages/kpi-metric/kpi-metric-list-page.ts +67 -63
  16. package/client/pages/kpi-value/kpi-value-list-page.ts +73 -72
  17. package/client/pages/kpi-value/kpi-value-manual-entry-form.ts +168 -0
  18. package/client/pages/kpi-value/kpi-value-manual-entry-page.ts +173 -0
  19. package/client/route.ts +35 -0
  20. package/dist-client/pages/kpi/kpi-importer.js +16 -17
  21. package/dist-client/pages/kpi/kpi-importer.js.map +1 -1
  22. package/dist-client/pages/kpi/kpi-list-page.js +128 -68
  23. package/dist-client/pages/kpi/kpi-list-page.js.map +1 -1
  24. package/dist-client/pages/kpi/kpi-overview-sample.d.ts +36 -0
  25. package/dist-client/pages/kpi/kpi-overview-sample.js +264 -0
  26. package/dist-client/pages/kpi/kpi-overview-sample.js.map +1 -0
  27. package/dist-client/pages/kpi/kpi-overview.d.ts +14 -0
  28. package/dist-client/pages/kpi/kpi-overview.js +290 -0
  29. package/dist-client/pages/kpi/kpi-overview.js.map +1 -0
  30. package/dist-client/pages/kpi-category/kpi-category-importer.js +16 -17
  31. package/dist-client/pages/kpi-category/kpi-category-importer.js.map +1 -1
  32. package/dist-client/pages/kpi-category/kpi-category-list-page.js +70 -71
  33. package/dist-client/pages/kpi-category/kpi-category-list-page.js.map +1 -1
  34. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.d.ts +18 -0
  35. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js +128 -0
  36. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js.map +1 -0
  37. package/dist-client/pages/kpi-dashboard/kpi-dashboard.d.ts +24 -0
  38. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js +305 -0
  39. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js.map +1 -0
  40. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.d.ts +12 -0
  41. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js +82 -0
  42. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js.map +1 -0
  43. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.d.ts +11 -0
  44. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js +65 -0
  45. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js.map +1 -0
  46. package/dist-client/pages/kpi-dashboard/kpi-list-summary.d.ts +13 -0
  47. package/dist-client/pages/kpi-dashboard/kpi-list-summary.js +115 -0
  48. package/dist-client/pages/kpi-dashboard/kpi-list-summary.js.map +1 -0
  49. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.d.ts +15 -0
  50. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js +139 -0
  51. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js.map +1 -0
  52. package/dist-client/pages/kpi-dashboard/kpi-value-entry.d.ts +7 -0
  53. package/dist-client/pages/kpi-dashboard/kpi-value-entry.js +86 -0
  54. package/dist-client/pages/kpi-dashboard/kpi-value-entry.js.map +1 -0
  55. package/dist-client/pages/kpi-grade/kpi-grade-importer.js +16 -17
  56. package/dist-client/pages/kpi-grade/kpi-grade-importer.js.map +1 -1
  57. package/dist-client/pages/kpi-grade/kpi-grade-list-page.js +89 -89
  58. package/dist-client/pages/kpi-grade/kpi-grade-list-page.js.map +1 -1
  59. package/dist-client/pages/kpi-history/kpi-history-list-page.d.ts +16 -0
  60. package/dist-client/pages/kpi-history/kpi-history-list-page.js +155 -0
  61. package/dist-client/pages/kpi-history/kpi-history-list-page.js.map +1 -0
  62. package/dist-client/pages/kpi-metric/kpi-metric-importer.js +16 -17
  63. package/dist-client/pages/kpi-metric/kpi-metric-importer.js.map +1 -1
  64. package/dist-client/pages/kpi-metric/kpi-metric-list-page.js +98 -84
  65. package/dist-client/pages/kpi-metric/kpi-metric-list-page.js.map +1 -1
  66. package/dist-client/pages/kpi-value/kpi-value-importer.js +16 -17
  67. package/dist-client/pages/kpi-value/kpi-value-importer.js.map +1 -1
  68. package/dist-client/pages/kpi-value/kpi-value-list-page.js +104 -93
  69. package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -1
  70. package/dist-client/pages/kpi-value/kpi-value-manual-entry-form.d.ts +14 -0
  71. package/dist-client/pages/kpi-value/kpi-value-manual-entry-form.js +201 -0
  72. package/dist-client/pages/kpi-value/kpi-value-manual-entry-form.js.map +1 -0
  73. package/dist-client/pages/kpi-value/kpi-value-manual-entry-page.d.ts +41 -0
  74. package/dist-client/pages/kpi-value/kpi-value-manual-entry-page.js +180 -0
  75. package/dist-client/pages/kpi-value/kpi-value-manual-entry-page.js.map +1 -0
  76. package/dist-client/route.d.ts +1 -1
  77. package/dist-client/route.js +27 -0
  78. package/dist-client/route.js.map +1 -1
  79. package/dist-client/tsconfig.tsbuildinfo +1 -1
  80. package/dist-server/index.d.ts +2 -1
  81. package/dist-server/index.js +2 -1
  82. package/dist-server/index.js.map +1 -1
  83. package/dist-server/migrations/1752188906708-SeedKpiCategory.d.ts +5 -0
  84. package/dist-server/migrations/1752188906708-SeedKpiCategory.js +56 -0
  85. package/dist-server/migrations/1752188906708-SeedKpiCategory.js.map +1 -0
  86. package/dist-server/migrations/1752190849681-SeedKpi.d.ts +5 -0
  87. package/dist-server/migrations/1752190849681-SeedKpi.js +107 -0
  88. package/dist-server/migrations/1752190849681-SeedKpi.js.map +1 -0
  89. package/dist-server/migrations/1752191090459-SeedKpiGrade.d.ts +5 -0
  90. package/dist-server/migrations/1752191090459-SeedKpiGrade.js +271 -0
  91. package/dist-server/migrations/1752191090459-SeedKpiGrade.js.map +1 -0
  92. package/dist-server/migrations/index.d.ts +1 -0
  93. package/dist-server/migrations/index.js +12 -0
  94. package/dist-server/migrations/index.js.map +1 -0
  95. package/dist-server/routes.d.ts +1 -0
  96. package/dist-server/routes.js +48 -0
  97. package/dist-server/routes.js.map +1 -1
  98. package/dist-server/service/index.d.ts +3 -4
  99. package/dist-server/service/index.js +4 -6
  100. package/dist-server/service/index.js.map +1 -1
  101. package/dist-server/service/kpi/aggregate-kpi.d.ts +8 -0
  102. package/dist-server/service/kpi/aggregate-kpi.js +88 -0
  103. package/dist-server/service/kpi/aggregate-kpi.js.map +1 -0
  104. package/dist-server/service/kpi/event-subscriber.d.ts +2 -0
  105. package/dist-server/service/kpi/event-subscriber.js +10 -0
  106. package/dist-server/service/kpi/event-subscriber.js.map +1 -1
  107. package/dist-server/service/kpi/index.d.ts +2 -1
  108. package/dist-server/service/kpi/kpi-formula.service.d.ts +24 -0
  109. package/dist-server/service/kpi/kpi-formula.service.js +64 -0
  110. package/dist-server/service/kpi/kpi-formula.service.js.map +1 -0
  111. package/dist-server/service/kpi/kpi-history.d.ts +6 -2
  112. package/dist-server/service/kpi/kpi-history.js +29 -11
  113. package/dist-server/service/kpi/kpi-history.js.map +1 -1
  114. package/dist-server/service/kpi/kpi-mutation.d.ts +2 -0
  115. package/dist-server/service/kpi/kpi-mutation.js +215 -10
  116. package/dist-server/service/kpi/kpi-mutation.js.map +1 -1
  117. package/dist-server/service/kpi/kpi-query.d.ts +10 -0
  118. package/dist-server/service/kpi/kpi-query.js +87 -3
  119. package/dist-server/service/kpi/kpi-query.js.map +1 -1
  120. package/dist-server/service/kpi/kpi-type.d.ts +14 -3
  121. package/dist-server/service/kpi/kpi-type.js +81 -18
  122. package/dist-server/service/kpi/kpi-type.js.map +1 -1
  123. package/dist-server/service/kpi/kpi.d.ts +14 -3
  124. package/dist-server/service/kpi/kpi.js +96 -19
  125. package/dist-server/service/kpi/kpi.js.map +1 -1
  126. package/dist-server/service/kpi-alert/index.d.ts +2 -0
  127. package/dist-server/service/kpi-alert/index.js +6 -0
  128. package/dist-server/service/kpi-alert/index.js.map +1 -0
  129. package/dist-server/service/kpi-alert/kpi-alert-query.d.ts +4 -0
  130. package/dist-server/service/kpi-alert/kpi-alert-query.js +71 -0
  131. package/dist-server/service/kpi-alert/kpi-alert-query.js.map +1 -0
  132. package/dist-server/service/kpi-alert/kpi-alert-type.d.ts +8 -0
  133. package/dist-server/service/kpi-alert/kpi-alert-type.js +33 -0
  134. package/dist-server/service/kpi-alert/kpi-alert-type.js.map +1 -0
  135. package/dist-server/service/kpi-category/kpi-category-mutation.d.ts +1 -1
  136. package/dist-server/service/kpi-category/kpi-category-mutation.js +36 -10
  137. package/dist-server/service/kpi-category/kpi-category-mutation.js.map +1 -1
  138. package/dist-server/service/kpi-category/kpi-category-query.d.ts +2 -0
  139. package/dist-server/service/kpi-category/kpi-category-query.js +18 -2
  140. package/dist-server/service/kpi-category/kpi-category-query.js.map +1 -1
  141. package/dist-server/service/kpi-category/kpi-category-type.d.ts +3 -5
  142. package/dist-server/service/kpi-category/kpi-category-type.js +16 -20
  143. package/dist-server/service/kpi-category/kpi-category-type.js.map +1 -1
  144. package/dist-server/service/kpi-category/kpi-category.d.ts +7 -9
  145. package/dist-server/service/kpi-category/kpi-category.js +40 -38
  146. package/dist-server/service/kpi-category/kpi-category.js.map +1 -1
  147. package/dist-server/service/kpi-grade/index.d.ts +1 -2
  148. package/dist-server/service/kpi-grade/index.js +2 -4
  149. package/dist-server/service/kpi-grade/index.js.map +1 -1
  150. package/dist-server/service/kpi-grade/kpi-grade-mutation.d.ts +1 -1
  151. package/dist-server/service/kpi-grade/kpi-grade-mutation.js +33 -10
  152. package/dist-server/service/kpi-grade/kpi-grade-mutation.js.map +1 -1
  153. package/dist-server/service/kpi-grade/kpi-grade-query.js +2 -2
  154. package/dist-server/service/kpi-grade/kpi-grade-query.js.map +1 -1
  155. package/dist-server/service/kpi-grade/kpi-grade-type.d.ts +13 -4
  156. package/dist-server/service/kpi-grade/kpi-grade-type.js +54 -18
  157. package/dist-server/service/kpi-grade/kpi-grade-type.js.map +1 -1
  158. package/dist-server/service/kpi-grade/kpi-grade.d.ts +8 -8
  159. package/dist-server/service/kpi-grade/kpi-grade.js +48 -40
  160. package/dist-server/service/kpi-grade/kpi-grade.js.map +1 -1
  161. package/dist-server/service/kpi-metric/aggregate-kpi-metric.d.ts +8 -0
  162. package/dist-server/service/kpi-metric/aggregate-kpi-metric.js +134 -0
  163. package/dist-server/service/kpi-metric/aggregate-kpi-metric.js.map +1 -0
  164. package/dist-server/service/kpi-metric/index.d.ts +1 -2
  165. package/dist-server/service/kpi-metric/index.js +2 -4
  166. package/dist-server/service/kpi-metric/index.js.map +1 -1
  167. package/dist-server/service/kpi-metric/kpi-metric-mutation.d.ts +1 -1
  168. package/dist-server/service/kpi-metric/kpi-metric-mutation.js +139 -13
  169. package/dist-server/service/kpi-metric/kpi-metric-mutation.js.map +1 -1
  170. package/dist-server/service/kpi-metric/kpi-metric-query.js +3 -3
  171. package/dist-server/service/kpi-metric/kpi-metric-query.js.map +1 -1
  172. package/dist-server/service/kpi-metric/kpi-metric-type.d.ts +17 -4
  173. package/dist-server/service/kpi-metric/kpi-metric-type.js +69 -11
  174. package/dist-server/service/kpi-metric/kpi-metric-type.js.map +1 -1
  175. package/dist-server/service/kpi-metric/kpi-metric.d.ts +11 -8
  176. package/dist-server/service/kpi-metric/kpi-metric.js +62 -37
  177. package/dist-server/service/kpi-metric/kpi-metric.js.map +1 -1
  178. package/dist-server/service/kpi-value/kpi-value-mutation.js +66 -11
  179. package/dist-server/service/kpi-value/kpi-value-mutation.js.map +1 -1
  180. package/dist-server/service/kpi-value/kpi-value-query.d.ts +2 -0
  181. package/dist-server/service/kpi-value/kpi-value-query.js +15 -2
  182. package/dist-server/service/kpi-value/kpi-value-query.js.map +1 -1
  183. package/dist-server/service/kpi-value/kpi-value-type.d.ts +19 -10
  184. package/dist-server/service/kpi-value/kpi-value-type.js +87 -24
  185. package/dist-server/service/kpi-value/kpi-value-type.js.map +1 -1
  186. package/dist-server/service/kpi-value/kpi-value.d.ts +15 -9
  187. package/dist-server/service/kpi-value/kpi-value.js +86 -32
  188. package/dist-server/service/kpi-value/kpi-value.js.map +1 -1
  189. package/dist-server/tsconfig.tsbuildinfo +1 -1
  190. package/implement-plan/01-entity-type-resolver.md +57 -0
  191. package/implement-plan/02-dataset-integration.md +35 -0
  192. package/implement-plan/03-kpivalue-automation.md +34 -0
  193. package/implement-plan/04-version-history.md +33 -0
  194. package/implement-plan/05-grade-visualization.md +33 -0
  195. package/implement-plan/06-graphql-frontend.md +30 -0
  196. package/implement-plan/07-test-docs.md +35 -0
  197. package/implement-plan/TODO.md +41 -0
  198. package/package.json +18 -6
  199. package/server/index.ts +2 -1
  200. package/server/migrations/1752188906708-SeedKpiCategory.ts +61 -0
  201. package/server/migrations/1752190849681-SeedKpi.ts +112 -0
  202. package/server/migrations/1752191090459-SeedKpiGrade.ts +270 -0
  203. package/server/migrations/index.ts +9 -0
  204. package/server/routes.ts +55 -0
  205. package/server/service/index.ts +4 -6
  206. package/server/service/kpi/aggregate-kpi.ts +82 -0
  207. package/server/service/kpi/event-subscriber.ts +12 -0
  208. package/server/service/kpi/kpi-formula.service.ts +63 -0
  209. package/server/service/kpi/kpi-history.ts +29 -21
  210. package/server/service/kpi/kpi-mutation.ts +194 -12
  211. package/server/service/kpi/kpi-query.ts +57 -2
  212. package/server/service/kpi/kpi-type.ts +72 -19
  213. package/server/service/kpi/kpi.ts +96 -20
  214. package/server/service/kpi-alert/index.ts +3 -0
  215. package/server/service/kpi-alert/kpi-alert-query.ts +59 -0
  216. package/server/service/kpi-alert/kpi-alert-type.ts +20 -0
  217. package/server/service/kpi-category/kpi-category-mutation.ts +17 -4
  218. package/server/service/kpi-category/kpi-category-query.ts +20 -3
  219. package/server/service/kpi-category/kpi-category-type.ts +17 -19
  220. package/server/service/kpi-category/kpi-category.ts +39 -37
  221. package/server/service/kpi-grade/index.ts +2 -4
  222. package/server/service/kpi-grade/kpi-grade-mutation.ts +13 -4
  223. package/server/service/kpi-grade/kpi-grade-query.ts +5 -2
  224. package/server/service/kpi-grade/kpi-grade-type.ts +46 -19
  225. package/server/service/kpi-grade/kpi-grade.ts +44 -38
  226. package/server/service/kpi-metric/aggregate-kpi-metric.ts +128 -0
  227. package/server/service/kpi-metric/index.ts +2 -4
  228. package/server/service/kpi-metric/kpi-metric-mutation.ts +123 -7
  229. package/server/service/kpi-metric/kpi-metric-query.ts +9 -3
  230. package/server/service/kpi-metric/kpi-metric-type.ts +56 -13
  231. package/server/service/kpi-metric/kpi-metric.ts +55 -35
  232. package/server/service/kpi-value/kpi-value-mutation.ts +52 -14
  233. package/server/service/kpi-value/kpi-value-query.ts +12 -2
  234. package/server/service/kpi-value/kpi-value-type.ts +80 -25
  235. package/server/service/kpi-value/kpi-value.ts +81 -29
  236. package/things-factory.config.js +12 -4
  237. package/translations/en.json +12 -1
  238. package/translations/ja.json +12 -1
  239. package/translations/ko.json +12 -1
  240. package/translations/ms.json +12 -1
  241. package/translations/zh.json +12 -1
  242. package/client/pages/kpe-metric/kpe-metric-importer.ts +0 -90
  243. package/client/pages/kpe-metric/kpe-metric-list-page.ts +0 -398
  244. package/client/pages/kpi-formula/kpi-formula-importer.ts +0 -90
  245. package/client/pages/kpi-formula/kpi-formula-list-page.ts +0 -398
  246. package/client/pages/metric/metric-importer.ts +0 -90
  247. package/client/pages/metric/metric-list-page.ts +0 -398
  248. package/dist-client/pages/kpe-metric/kpe-metric-importer.d.ts +0 -23
  249. package/dist-client/pages/kpe-metric/kpe-metric-importer.js +0 -93
  250. package/dist-client/pages/kpe-metric/kpe-metric-importer.js.map +0 -1
  251. package/dist-client/pages/kpe-metric/kpe-metric-list-page.d.ts +0 -66
  252. package/dist-client/pages/kpe-metric/kpe-metric-list-page.js +0 -370
  253. package/dist-client/pages/kpe-metric/kpe-metric-list-page.js.map +0 -1
  254. package/dist-client/pages/kpi-formula/kpi-formula-importer.d.ts +0 -23
  255. package/dist-client/pages/kpi-formula/kpi-formula-importer.js +0 -93
  256. package/dist-client/pages/kpi-formula/kpi-formula-importer.js.map +0 -1
  257. package/dist-client/pages/kpi-formula/kpi-formula-list-page.d.ts +0 -66
  258. package/dist-client/pages/kpi-formula/kpi-formula-list-page.js +0 -370
  259. package/dist-client/pages/kpi-formula/kpi-formula-list-page.js.map +0 -1
  260. package/dist-client/pages/metric/metric-importer.d.ts +0 -23
  261. package/dist-client/pages/metric/metric-importer.js +0 -93
  262. package/dist-client/pages/metric/metric-importer.js.map +0 -1
  263. package/dist-client/pages/metric/metric-list-page.d.ts +0 -66
  264. package/dist-client/pages/metric/metric-list-page.js +0 -370
  265. package/dist-client/pages/metric/metric-list-page.js.map +0 -1
  266. package/dist-server/service/kpi-formula/event-subscriber.d.ts +0 -7
  267. package/dist-server/service/kpi-formula/event-subscriber.js +0 -21
  268. package/dist-server/service/kpi-formula/event-subscriber.js.map +0 -1
  269. package/dist-server/service/kpi-formula/index.d.ts +0 -7
  270. package/dist-server/service/kpi-formula/index.js +0 -12
  271. package/dist-server/service/kpi-formula/index.js.map +0 -1
  272. package/dist-server/service/kpi-formula/kpi-formula-history.d.ts +0 -25
  273. package/dist-server/service/kpi-formula/kpi-formula-history.js +0 -128
  274. package/dist-server/service/kpi-formula/kpi-formula-history.js.map +0 -1
  275. package/dist-server/service/kpi-formula/kpi-formula-mutation.d.ts +0 -10
  276. package/dist-server/service/kpi-formula/kpi-formula-mutation.js +0 -128
  277. package/dist-server/service/kpi-formula/kpi-formula-mutation.js.map +0 -1
  278. package/dist-server/service/kpi-formula/kpi-formula-query.d.ts +0 -11
  279. package/dist-server/service/kpi-formula/kpi-formula-query.js +0 -79
  280. package/dist-server/service/kpi-formula/kpi-formula-query.js.map +0 -1
  281. package/dist-server/service/kpi-formula/kpi-formula-type.d.ts +0 -20
  282. package/dist-server/service/kpi-formula/kpi-formula-type.js +0 -77
  283. package/dist-server/service/kpi-formula/kpi-formula-type.js.map +0 -1
  284. package/dist-server/service/kpi-formula/kpi-formula.d.ts +0 -24
  285. package/dist-server/service/kpi-formula/kpi-formula.js +0 -109
  286. package/dist-server/service/kpi-formula/kpi-formula.js.map +0 -1
  287. package/dist-server/service/kpi-grade/event-subscriber.d.ts +0 -7
  288. package/dist-server/service/kpi-grade/event-subscriber.js +0 -21
  289. package/dist-server/service/kpi-grade/event-subscriber.js.map +0 -1
  290. package/dist-server/service/kpi-grade/kpi-grade-history.d.ts +0 -25
  291. package/dist-server/service/kpi-grade/kpi-grade-history.js +0 -128
  292. package/dist-server/service/kpi-grade/kpi-grade-history.js.map +0 -1
  293. package/dist-server/service/kpi-metric/event-subscriber.d.ts +0 -7
  294. package/dist-server/service/kpi-metric/event-subscriber.js +0 -21
  295. package/dist-server/service/kpi-metric/event-subscriber.js.map +0 -1
  296. package/dist-server/service/kpi-metric/kpi-metric-history.d.ts +0 -25
  297. package/dist-server/service/kpi-metric/kpi-metric-history.js +0 -128
  298. package/dist-server/service/kpi-metric/kpi-metric-history.js.map +0 -1
  299. package/server/service/kpi-formula/event-subscriber.ts +0 -17
  300. package/server/service/kpi-formula/index.ts +0 -9
  301. package/server/service/kpi-formula/kpi-formula-history.ts +0 -116
  302. package/server/service/kpi-formula/kpi-formula-mutation.ts +0 -137
  303. package/server/service/kpi-formula/kpi-formula-query.ts +0 -48
  304. package/server/service/kpi-formula/kpi-formula-type.ts +0 -55
  305. package/server/service/kpi-formula/kpi-formula.ts +0 -95
  306. package/server/service/kpi-grade/event-subscriber.ts +0 -17
  307. package/server/service/kpi-grade/kpi-grade-history.ts +0 -116
  308. package/server/service/kpi-metric/event-subscriber.ts +0 -17
  309. package/server/service/kpi-metric/kpi-metric-history.ts +0 -116
@@ -0,0 +1,264 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import { html, css } from 'lit';
3
+ import { customElement, state } from 'lit/decorators.js';
4
+ import { marked } from 'marked';
5
+ import { PageView } from '@operato/shell';
6
+ import { i18next } from '@operato/i18n';
7
+ let KpiOverview = class KpiOverview extends PageView {
8
+ constructor() {
9
+ super(...arguments);
10
+ this.selectedGroup = 0;
11
+ this.selectedKpi = 0;
12
+ this.kpiGroups = [
13
+ {
14
+ name: '일정성과 지표',
15
+ kpis: ['연면적 대비 공사기간', '설계변경에 따른 공기 증감률', '일정 이탈 수준', '일정성과 수준 평가']
16
+ },
17
+ {
18
+ name: '비용성과 지표',
19
+ kpis: ['연면적 대비 공사비', '설계변경에 따른 공사비 증감률', '비용성과 수준 평가']
20
+ },
21
+ {
22
+ name: '품질성과 지표',
23
+ kpis: ['품질시험 불합격률', '검수재 불합격률', '검측 불합격률', '품질 SL-PA 결과값', '품질성과 수준 평가']
24
+ },
25
+ {
26
+ name: '안전성과 지표',
27
+ kpis: ['재해율', '재해강도율', '안전 SL-PA 결과값', '안전성과 수준 평가']
28
+ },
29
+ {
30
+ name: '환경성과 지표',
31
+ kpis: ['건설폐기물 발생량', '환경성과 수준 평가']
32
+ },
33
+ {
34
+ name: '생산성과 지표',
35
+ kpis: ['투입인력 생산성', '생산성과 수준 평가']
36
+ }
37
+ ];
38
+ this.kpiDescriptions = {
39
+ '연면적 대비 공사기간': `# 연면적 대비 공사기간\n- 설명: 프로젝트의 전체 연면적 대비 실제 소요된 공사기간을 측정합니다.\n- 산식: 실제공사기간(개월) / (연면적/1000m2)\n- 데이터 표준형: 실제공사기간(개월) / (연면적/1000m2)\n- 활용: 대형 프로젝트의 일정 효율성 파악`,
40
+ '설계변경에 따른 공기 증감률': `# 설계변경에 따른 공기 증감률\n- 설명: 설계변경으로 인한 공기 단축 또는 증가 효과를 측정합니다.\n- 산식: (실제공사기간 - 계획공사기간) / 계획공사기간(개월)\n- 데이터 표준형: (실제공사기간 - 계획공사기간)(개월) / 계획공사기간(개월)`,
41
+ '일정 이탈 수준': `# 일정 이탈 수준\n- 설명: 계획 대비 실제 일정의 이탈 정도를 평가합니다.\n- 산식: Table(DART 등) 활용\n- 평가 방식: 1~5점 척도(감리자 평가)`,
42
+ '일정성과 수준 평가': `# 일정성과 수준 평가\n- 설명: 일정성과의 전반적인 수준을 감리자가 평가합니다.\n- 평가 방식: 감리자 1~5점 척도`,
43
+ '연면적 대비 공사비': `# 연면적 대비 공사비\n- 설명: 프로젝트의 전체 연면적 대비 실제 소요된 공사비를 측정합니다.\n- 산식: 실제공사비(억원) / (연면적/1000m2)\n- 데이터 표준형: 실제공사비(억원) / (연면적/1000m2)`,
44
+ '설계변경에 따른 공사비 증감률': `# 설계변경에 따른 공사비 증감률\n- 설명: 설계변경으로 인한 공사비 증감률을 측정합니다.\n- 산식: (실제공사비 - 계획공사비) / 계획공사비(억원)\n- 데이터 표준형: (실제공사비 - 계획공사비)(억원) / 계획공사비(억원)`,
45
+ '비용성과 수준 평가': `# 비용성과 수준 평가\n- 설명: 비용성과의 전반적인 수준을 감리자가 평가합니다.\n- 평가 방식: 감리자 1~5점 척도`,
46
+ '품질시험 불합격률': `# 품질시험 불합격률\n- 설명: 전체 품질시험 중 불합격 건수의 비율을 측정합니다.\n- 산식: 품질시험 불합격 건수(건) / (연면적/1000m2)`,
47
+ '검수재 불합격률': `# 검수재 불합격률\n- 설명: 검수재 중 불합격 건수의 비율을 측정합니다.\n- 산식: 검수재 불합격 건수(건) / (연면적/1000m2)`,
48
+ '검측 불합격률': `# 검측 불합격률\n- 설명: 전체 검측 중 불합격 건수의 비율을 측정합니다.\n- 산식: 품질검측 불합격 건수(건) / 품질검측 건수(건)`,
49
+ '품질 SL-PA 결과값': `# 품질 SL-PA 결과값\n- 설명: SL-PA(Safety Level - Performance Assessment)는 건설/안전 분야에서 안전관리 수준을 정량적으로 평가하는 대표 지표입니다.\n- 평가 방식: Python 활용 1~5점 척도`,
50
+ '품질성과 수준 평가': `# 품질성과 수준 평가\n- 설명: 품질성과의 전반적인 수준을 감리자가 평가합니다.\n- 평가 방식: 감리자 1~5점 척도`,
51
+ 재해율: `# 재해율\n- 설명: 연간 근로자 수 대비 재해 발생 건수의 비율을 측정합니다.\n- 산식: (재해 건수(건) / 연간 근로자 수(명)) * 100`,
52
+ 재해강도율: `# 재해강도율\n- 설명: 총 근로자 수와 연간 근로시간 대비 노동손실일수의 비율을 측정합니다.\n- 산식: (노동손실일수(일) / (총 근로자 수 * 1인당 연간 근로시간)) * 100`,
53
+ '안전 SL-PA 결과값': `# 안전 SL-PA 결과값\n- 설명: SL-PA(Safety Level - Performance Assessment)는 건설/안전 분야에서 **안전관리 수준**을 정량적으로 평가하는 대표 지표입니다.\n- 활용: 현장의 안전성과를 수치로 진단하고, 위험요소 개선 및 안전관리 정책 수립에 활용됩니다.\n- 평가 방식: Python 활용 1~5점 척도 (1점: 매우 미흡, 5점: 매우 우수)`,
54
+ '안전성과 수준 평가': `# 안전성과 수준 평가\n- 설명: 안전성과의 전반적인 수준을 감리자가 평가합니다.\n- 평가 방식: 감리자 1~5점 척도`,
55
+ '건설폐기물 발생량': `# 건설폐기물 발생량\n- 설명: 전체 건설폐기물 발생량을 측정합니다.\n- 산식: 총 건설 폐기물 발생량(ton) / (연면적/1000m2)`,
56
+ '환경성과 수준 평가': `# 환경성과 수준 평가\n- 설명: 환경성과의 전반적인 수준을 감리자가 평가합니다.\n- 평가 방식: 감리자 1~5점 척도`,
57
+ '투입인력 생산성': `# 투입인력 생산성\n- 설명: 투입 인력 대비 생산성을 측정합니다.\n- 산식: 투입인력(명) / (연면적/1000m2)`,
58
+ '생산성과 수준 평가': `# 생산성과 수준 평가\n- 설명: 생산성과의 전반적인 수준을 감리자가 평가합니다.\n- 평가 방식: 감리자 1~5점 척도`
59
+ };
60
+ }
61
+ static { this.styles = css `
62
+ .overview-container {
63
+ display: flex;
64
+ gap: 32px;
65
+ background: #f7f5fa;
66
+ border-radius: 20px;
67
+ padding: 32px;
68
+ margin-bottom: 24px;
69
+ align-items: stretch;
70
+ }
71
+ .overview-left {
72
+ flex: 1;
73
+ display: flex;
74
+ flex-direction: column;
75
+ justify-content: center;
76
+ }
77
+ .overview-title {
78
+ font-size: 2.8rem;
79
+ font-weight: bold;
80
+ margin-bottom: 24px;
81
+ }
82
+ .overview-desc {
83
+ font-size: 1.2rem;
84
+ color: #222;
85
+ line-height: 1.6;
86
+ }
87
+ .overview-right {
88
+ flex: 1;
89
+ display: flex;
90
+ align-items: center;
91
+ justify-content: center;
92
+ }
93
+ .overview-img {
94
+ width: 100%;
95
+ max-width: 420px;
96
+ border-radius: 12px;
97
+ object-fit: cover;
98
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
99
+ }
100
+ .group-tabs {
101
+ display: flex;
102
+ gap: 8px;
103
+ margin: 0 0 16px 0;
104
+ justify-content: center;
105
+ }
106
+ .group-tab {
107
+ padding: 10px 28px;
108
+ border-radius: 16px 16px 0 0;
109
+ background: #eee;
110
+ cursor: pointer;
111
+ font-size: 1.1rem;
112
+ font-weight: 500;
113
+ border: none;
114
+ outline: none;
115
+ transition: background 0.2s;
116
+ }
117
+ .group-tab[selected] {
118
+ background: #d6d6f7;
119
+ color: #222;
120
+ font-weight: bold;
121
+ }
122
+ .kpi-list {
123
+ display: flex;
124
+ gap: 8px;
125
+ margin: 0 0 32px 0;
126
+ justify-content: center;
127
+ }
128
+ .kpi-item {
129
+ padding: 8px 20px;
130
+ border-radius: 12px;
131
+ background: #f5f5f5;
132
+ cursor: pointer;
133
+ font-size: 1rem;
134
+ border: none;
135
+ outline: none;
136
+ transition: background 0.2s;
137
+ }
138
+ .kpi-item[selected] {
139
+ background: #bdf;
140
+ color: #222;
141
+ font-weight: bold;
142
+ }
143
+ .main-content {
144
+ display: flex;
145
+ gap: 32px;
146
+ margin-top: 32px;
147
+ align-items: flex-start;
148
+ justify-content: center;
149
+ }
150
+ .markdown {
151
+ background: #fff;
152
+ border-radius: 12px;
153
+ padding: 40px 32px;
154
+ min-height: 240px;
155
+ flex: 2;
156
+ font-size: 2rem;
157
+ color: #222;
158
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
159
+ }
160
+ .toc {
161
+ flex: 1;
162
+ background: #faf9fd;
163
+ border-radius: 12px;
164
+ padding: 32px 24px;
165
+ font-size: 1.1rem;
166
+ color: #444;
167
+ min-width: 220px;
168
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
169
+ }
170
+ .toc-title {
171
+ font-weight: bold;
172
+ margin-bottom: 12px;
173
+ font-size: 1.2rem;
174
+ }
175
+ .toc-list {
176
+ margin: 0 0 16px 0;
177
+ padding: 0;
178
+ list-style: none;
179
+ }
180
+ .toc-list li {
181
+ margin-bottom: 6px;
182
+ }
183
+ .toc-btn {
184
+ display: block;
185
+ margin: 12px 0;
186
+ padding: 8px 16px;
187
+ border: 1px solid #aaa;
188
+ border-radius: 8px;
189
+ background: #fff;
190
+ color: #333;
191
+ cursor: pointer;
192
+ font-size: 1rem;
193
+ text-align: left;
194
+ transition: background 0.2s;
195
+ }
196
+ .toc-btn:hover {
197
+ background: #f0f0f0;
198
+ }
199
+ `; }
200
+ get context() {
201
+ return {
202
+ title: i18next.t('title.kpi overview')
203
+ };
204
+ }
205
+ render() {
206
+ const group = this.kpiGroups[this.selectedGroup];
207
+ const kpi = group.kpis[this.selectedKpi];
208
+ const md = this.kpiDescriptions[kpi] || '각 지표의 주요 소개 내용을 마크다운으로 입력하세요.';
209
+ return html `
210
+ <div class="overview-container">
211
+ <div class="overview-left">
212
+ <div class="overview-title">KPI개요</div>
213
+ <div class="overview-desc">
214
+ 건설현장 KPI 관리 시스템은 프로젝트 성과를 측정하고 모니터링하여 효율적인 공정 관리를 지원합니다.<br />
215
+ 주요 지표를 통해 현장 생산성, 품질, 안전 등을 실시간으로 파악할 수 있습니다.
216
+ </div>
217
+ </div>
218
+ <div class="overview-right">
219
+ <img
220
+ class="overview-img"
221
+ src="https://images.unsplash.com/photo-1464983953574-0892a716854b?auto=format&fit=crop&w=600&q=80"
222
+ alt="건설현장 안전"
223
+ />
224
+ </div>
225
+ </div>
226
+ <div class="group-tabs">
227
+ ${this.kpiGroups.map((g, i) => html `
228
+ <button
229
+ class="group-tab"
230
+ ?selected=${i === this.selectedGroup}
231
+ @click=${() => {
232
+ this.selectedGroup = i;
233
+ this.selectedKpi = 0;
234
+ }}
235
+ >
236
+ ${g.name}
237
+ </button>
238
+ `)}
239
+ </div>
240
+ <div class="main-content">
241
+ <div class="markdown" .innerHTML=${marked(md)}></div>
242
+ <div class="toc">
243
+ <div class="toc-title">목차</div>
244
+ <ul class="toc-list">
245
+ ${group.kpis.map((k, i) => html ` <li><button class="toc-btn" @click=${() => (this.selectedKpi = i)}>${k}</button></li> `)}
246
+ </ul>
247
+ </div>
248
+ </div>
249
+ `;
250
+ }
251
+ };
252
+ __decorate([
253
+ state(),
254
+ __metadata("design:type", Object)
255
+ ], KpiOverview.prototype, "selectedGroup", void 0);
256
+ __decorate([
257
+ state(),
258
+ __metadata("design:type", Object)
259
+ ], KpiOverview.prototype, "selectedKpi", void 0);
260
+ KpiOverview = __decorate([
261
+ customElement('kpi-overview')
262
+ ], KpiOverview);
263
+ export { KpiOverview };
264
+ //# sourceMappingURL=kpi-overview-sample.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kpi-overview-sample.js","sourceRoot":"","sources":["../../../client/pages/kpi/kpi-overview-sample.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, css, LitElement } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\nimport { marked } from 'marked'\n\nimport { PageView, store } from '@operato/shell'\nimport { i18next, localize } from '@operato/i18n'\n\n@customElement('kpi-overview')\nexport class KpiOverview extends PageView {\n static styles = css`\n .overview-container {\n display: flex;\n gap: 32px;\n background: #f7f5fa;\n border-radius: 20px;\n padding: 32px;\n margin-bottom: 24px;\n align-items: stretch;\n }\n .overview-left {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n }\n .overview-title {\n font-size: 2.8rem;\n font-weight: bold;\n margin-bottom: 24px;\n }\n .overview-desc {\n font-size: 1.2rem;\n color: #222;\n line-height: 1.6;\n }\n .overview-right {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .overview-img {\n width: 100%;\n max-width: 420px;\n border-radius: 12px;\n object-fit: cover;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);\n }\n .group-tabs {\n display: flex;\n gap: 8px;\n margin: 0 0 16px 0;\n justify-content: center;\n }\n .group-tab {\n padding: 10px 28px;\n border-radius: 16px 16px 0 0;\n background: #eee;\n cursor: pointer;\n font-size: 1.1rem;\n font-weight: 500;\n border: none;\n outline: none;\n transition: background 0.2s;\n }\n .group-tab[selected] {\n background: #d6d6f7;\n color: #222;\n font-weight: bold;\n }\n .kpi-list {\n display: flex;\n gap: 8px;\n margin: 0 0 32px 0;\n justify-content: center;\n }\n .kpi-item {\n padding: 8px 20px;\n border-radius: 12px;\n background: #f5f5f5;\n cursor: pointer;\n font-size: 1rem;\n border: none;\n outline: none;\n transition: background 0.2s;\n }\n .kpi-item[selected] {\n background: #bdf;\n color: #222;\n font-weight: bold;\n }\n .main-content {\n display: flex;\n gap: 32px;\n margin-top: 32px;\n align-items: flex-start;\n justify-content: center;\n }\n .markdown {\n background: #fff;\n border-radius: 12px;\n padding: 40px 32px;\n min-height: 240px;\n flex: 2;\n font-size: 2rem;\n color: #222;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);\n }\n .toc {\n flex: 1;\n background: #faf9fd;\n border-radius: 12px;\n padding: 32px 24px;\n font-size: 1.1rem;\n color: #444;\n min-width: 220px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);\n }\n .toc-title {\n font-weight: bold;\n margin-bottom: 12px;\n font-size: 1.2rem;\n }\n .toc-list {\n margin: 0 0 16px 0;\n padding: 0;\n list-style: none;\n }\n .toc-list li {\n margin-bottom: 6px;\n }\n .toc-btn {\n display: block;\n margin: 12px 0;\n padding: 8px 16px;\n border: 1px solid #aaa;\n border-radius: 8px;\n background: #fff;\n color: #333;\n cursor: pointer;\n font-size: 1rem;\n text-align: left;\n transition: background 0.2s;\n }\n .toc-btn:hover {\n background: #f0f0f0;\n }\n `\n\n get context() {\n return {\n title: i18next.t('title.kpi overview')\n }\n }\n\n @state() selectedGroup = 0\n @state() selectedKpi = 0\n\n kpiGroups = [\n {\n name: '일정성과 지표',\n kpis: ['연면적 대비 공사기간', '설계변경에 따른 공기 증감률', '일정 이탈 수준', '일정성과 수준 평가']\n },\n {\n name: '비용성과 지표',\n kpis: ['연면적 대비 공사비', '설계변경에 따른 공사비 증감률', '비용성과 수준 평가']\n },\n {\n name: '품질성과 지표',\n kpis: ['품질시험 불합격률', '검수재 불합격률', '검측 불합격률', '품질 SL-PA 결과값', '품질성과 수준 평가']\n },\n {\n name: '안전성과 지표',\n kpis: ['재해율', '재해강도율', '안전 SL-PA 결과값', '안전성과 수준 평가']\n },\n {\n name: '환경성과 지표',\n kpis: ['건설폐기물 발생량', '환경성과 수준 평가']\n },\n {\n name: '생산성과 지표',\n kpis: ['투입인력 생산성', '생산성과 수준 평가']\n }\n ]\n\n kpiDescriptions = {\n '연면적 대비 공사기간': `# 연면적 대비 공사기간\\n- 설명: 프로젝트의 전체 연면적 대비 실제 소요된 공사기간을 측정합니다.\\n- 산식: 실제공사기간(개월) / (연면적/1000m2)\\n- 데이터 표준형: 실제공사기간(개월) / (연면적/1000m2)\\n- 활용: 대형 프로젝트의 일정 효율성 파악`,\n '설계변경에 따른 공기 증감률': `# 설계변경에 따른 공기 증감률\\n- 설명: 설계변경으로 인한 공기 단축 또는 증가 효과를 측정합니다.\\n- 산식: (실제공사기간 - 계획공사기간) / 계획공사기간(개월)\\n- 데이터 표준형: (실제공사기간 - 계획공사기간)(개월) / 계획공사기간(개월)`,\n '일정 이탈 수준': `# 일정 이탈 수준\\n- 설명: 계획 대비 실제 일정의 이탈 정도를 평가합니다.\\n- 산식: Table(DART 등) 활용\\n- 평가 방식: 1~5점 척도(감리자 평가)`,\n '일정성과 수준 평가': `# 일정성과 수준 평가\\n- 설명: 일정성과의 전반적인 수준을 감리자가 평가합니다.\\n- 평가 방식: 감리자 1~5점 척도`,\n '연면적 대비 공사비': `# 연면적 대비 공사비\\n- 설명: 프로젝트의 전체 연면적 대비 실제 소요된 공사비를 측정합니다.\\n- 산식: 실제공사비(억원) / (연면적/1000m2)\\n- 데이터 표준형: 실제공사비(억원) / (연면적/1000m2)`,\n '설계변경에 따른 공사비 증감률': `# 설계변경에 따른 공사비 증감률\\n- 설명: 설계변경으로 인한 공사비 증감률을 측정합니다.\\n- 산식: (실제공사비 - 계획공사비) / 계획공사비(억원)\\n- 데이터 표준형: (실제공사비 - 계획공사비)(억원) / 계획공사비(억원)`,\n '비용성과 수준 평가': `# 비용성과 수준 평가\\n- 설명: 비용성과의 전반적인 수준을 감리자가 평가합니다.\\n- 평가 방식: 감리자 1~5점 척도`,\n '품질시험 불합격률': `# 품질시험 불합격률\\n- 설명: 전체 품질시험 중 불합격 건수의 비율을 측정합니다.\\n- 산식: 품질시험 불합격 건수(건) / (연면적/1000m2)`,\n '검수재 불합격률': `# 검수재 불합격률\\n- 설명: 검수재 중 불합격 건수의 비율을 측정합니다.\\n- 산식: 검수재 불합격 건수(건) / (연면적/1000m2)`,\n '검측 불합격률': `# 검측 불합격률\\n- 설명: 전체 검측 중 불합격 건수의 비율을 측정합니다.\\n- 산식: 품질검측 불합격 건수(건) / 품질검측 건수(건)`,\n '품질 SL-PA 결과값': `# 품질 SL-PA 결과값\\n- 설명: SL-PA(Safety Level - Performance Assessment)는 건설/안전 분야에서 안전관리 수준을 정량적으로 평가하는 대표 지표입니다.\\n- 평가 방식: Python 활용 1~5점 척도`,\n '품질성과 수준 평가': `# 품질성과 수준 평가\\n- 설명: 품질성과의 전반적인 수준을 감리자가 평가합니다.\\n- 평가 방식: 감리자 1~5점 척도`,\n 재해율: `# 재해율\\n- 설명: 연간 근로자 수 대비 재해 발생 건수의 비율을 측정합니다.\\n- 산식: (재해 건수(건) / 연간 근로자 수(명)) * 100`,\n 재해강도율: `# 재해강도율\\n- 설명: 총 근로자 수와 연간 근로시간 대비 노동손실일수의 비율을 측정합니다.\\n- 산식: (노동손실일수(일) / (총 근로자 수 * 1인당 연간 근로시간)) * 100`,\n '안전 SL-PA 결과값': `# 안전 SL-PA 결과값\\n- 설명: SL-PA(Safety Level - Performance Assessment)는 건설/안전 분야에서 **안전관리 수준**을 정량적으로 평가하는 대표 지표입니다.\\n- 활용: 현장의 안전성과를 수치로 진단하고, 위험요소 개선 및 안전관리 정책 수립에 활용됩니다.\\n- 평가 방식: Python 활용 1~5점 척도 (1점: 매우 미흡, 5점: 매우 우수)`,\n '안전성과 수준 평가': `# 안전성과 수준 평가\\n- 설명: 안전성과의 전반적인 수준을 감리자가 평가합니다.\\n- 평가 방식: 감리자 1~5점 척도`,\n '건설폐기물 발생량': `# 건설폐기물 발생량\\n- 설명: 전체 건설폐기물 발생량을 측정합니다.\\n- 산식: 총 건설 폐기물 발생량(ton) / (연면적/1000m2)`,\n '환경성과 수준 평가': `# 환경성과 수준 평가\\n- 설명: 환경성과의 전반적인 수준을 감리자가 평가합니다.\\n- 평가 방식: 감리자 1~5점 척도`,\n '투입인력 생산성': `# 투입인력 생산성\\n- 설명: 투입 인력 대비 생산성을 측정합니다.\\n- 산식: 투입인력(명) / (연면적/1000m2)`,\n '생산성과 수준 평가': `# 생산성과 수준 평가\\n- 설명: 생산성과의 전반적인 수준을 감리자가 평가합니다.\\n- 평가 방식: 감리자 1~5점 척도`\n }\n\n render() {\n const group = this.kpiGroups[this.selectedGroup]\n const kpi = group.kpis[this.selectedKpi]\n const md = this.kpiDescriptions[kpi] || '각 지표의 주요 소개 내용을 마크다운으로 입력하세요.'\n\n return html`\n <div class=\"overview-container\">\n <div class=\"overview-left\">\n <div class=\"overview-title\">KPI개요</div>\n <div class=\"overview-desc\">\n 건설현장 KPI 관리 시스템은 프로젝트 성과를 측정하고 모니터링하여 효율적인 공정 관리를 지원합니다.<br />\n 주요 지표를 통해 현장 생산성, 품질, 안전 등을 실시간으로 파악할 수 있습니다.\n </div>\n </div>\n <div class=\"overview-right\">\n <img\n class=\"overview-img\"\n src=\"https://images.unsplash.com/photo-1464983953574-0892a716854b?auto=format&fit=crop&w=600&q=80\"\n alt=\"건설현장 안전\"\n />\n </div>\n </div>\n <div class=\"group-tabs\">\n ${this.kpiGroups.map(\n (g, i) => html`\n <button\n class=\"group-tab\"\n ?selected=${i === this.selectedGroup}\n @click=${() => {\n this.selectedGroup = i\n this.selectedKpi = 0\n }}\n >\n ${g.name}\n </button>\n `\n )}\n </div>\n <div class=\"main-content\">\n <div class=\"markdown\" .innerHTML=${marked(md)}></div>\n <div class=\"toc\">\n <div class=\"toc-title\">목차</div>\n <ul class=\"toc-list\">\n ${group.kpis.map(\n (k, i) => html` <li><button class=\"toc-btn\" @click=${() => (this.selectedKpi = i)}>${k}</button></li> `\n )}\n </ul>\n </div>\n </div>\n `\n }\n}\n"]}
@@ -0,0 +1,14 @@
1
+ import { PageView } from '@operato/shell';
2
+ export declare class KpiOverview extends PageView {
3
+ static styles: import("lit").CSSResult;
4
+ get context(): {
5
+ title: string;
6
+ };
7
+ selectedGroup: number;
8
+ selectedKpi: number;
9
+ kpiCategories: any[];
10
+ loading: boolean;
11
+ error: Error | null;
12
+ firstUpdated(): Promise<void>;
13
+ render(): import("lit-html").TemplateResult<1>;
14
+ }
@@ -0,0 +1,290 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import { html, css } from 'lit';
3
+ import { customElement, state } from 'lit/decorators.js';
4
+ import { marked } from 'marked';
5
+ import { PageView } from '@operato/shell';
6
+ import { i18next } from '@operato/i18n';
7
+ import { client } from '@operato/graphql';
8
+ import gql from 'graphql-tag';
9
+ const GET_KPI_OVERVIEW = gql `
10
+ query {
11
+ kpiCategories {
12
+ items {
13
+ id
14
+ name
15
+ description
16
+ active
17
+ kpis {
18
+ id
19
+ name
20
+ description
21
+ formula
22
+ active
23
+ grades {
24
+ id
25
+ name
26
+ minValue
27
+ maxValue
28
+ score
29
+ color
30
+ description
31
+ }
32
+ }
33
+ }
34
+ }
35
+ }
36
+ `;
37
+ let KpiOverview = class KpiOverview extends PageView {
38
+ constructor() {
39
+ super(...arguments);
40
+ this.selectedGroup = 0;
41
+ this.selectedKpi = 0;
42
+ this.kpiCategories = [];
43
+ this.loading = true;
44
+ this.error = null;
45
+ }
46
+ static { this.styles = css `
47
+ .overview-container {
48
+ display: flex;
49
+ gap: 32px;
50
+ background: #f7f5fa;
51
+ border-radius: 20px;
52
+ padding: 32px;
53
+ margin-bottom: 24px;
54
+ align-items: stretch;
55
+ }
56
+ .overview-left {
57
+ flex: 1;
58
+ display: flex;
59
+ flex-direction: column;
60
+ justify-content: center;
61
+ }
62
+ .overview-title {
63
+ font-size: 2.8rem;
64
+ font-weight: bold;
65
+ margin-bottom: 24px;
66
+ }
67
+ .overview-desc {
68
+ font-size: 1.2rem;
69
+ color: #222;
70
+ line-height: 1.6;
71
+ }
72
+ .overview-right {
73
+ flex: 1;
74
+ display: flex;
75
+ align-items: center;
76
+ justify-content: center;
77
+ }
78
+ .overview-img {
79
+ width: 100%;
80
+ max-width: 420px;
81
+ border-radius: 12px;
82
+ object-fit: cover;
83
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
84
+ }
85
+ .group-tabs {
86
+ display: flex;
87
+ gap: 8px;
88
+ margin: 0 0 16px 0;
89
+ justify-content: center;
90
+ }
91
+ .group-tab {
92
+ padding: 10px 28px;
93
+ border-radius: 16px 16px 0 0;
94
+ background: #eee;
95
+ cursor: pointer;
96
+ font-size: 1.1rem;
97
+ font-weight: 500;
98
+ border: none;
99
+ outline: none;
100
+ transition: background 0.2s;
101
+ }
102
+ .group-tab[selected] {
103
+ background: #d6d6f7;
104
+ color: #222;
105
+ font-weight: bold;
106
+ }
107
+ .kpi-list {
108
+ display: flex;
109
+ gap: 8px;
110
+ margin: 0 0 32px 0;
111
+ justify-content: center;
112
+ }
113
+ .kpi-item {
114
+ padding: 8px 20px;
115
+ border-radius: 12px;
116
+ background: #f5f5f5;
117
+ cursor: pointer;
118
+ font-size: 1rem;
119
+ border: none;
120
+ outline: none;
121
+ transition: background 0.2s;
122
+ }
123
+ .kpi-item[selected] {
124
+ background: #bdf;
125
+ color: #222;
126
+ font-weight: bold;
127
+ }
128
+ .main-content {
129
+ display: flex;
130
+ gap: 32px;
131
+ margin-top: 32px;
132
+ align-items: flex-start;
133
+ justify-content: center;
134
+ }
135
+ .markdown {
136
+ background: #fff;
137
+ border-radius: 12px;
138
+ padding: 40px 32px;
139
+ min-height: 240px;
140
+ flex: 2;
141
+ font-size: 2rem;
142
+ color: #222;
143
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
144
+ }
145
+ .toc {
146
+ flex: 1;
147
+ background: #faf9fd;
148
+ border-radius: 12px;
149
+ padding: 32px 24px;
150
+ font-size: 1.1rem;
151
+ color: #444;
152
+ min-width: 220px;
153
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
154
+ }
155
+ .toc-title {
156
+ font-weight: bold;
157
+ margin-bottom: 12px;
158
+ font-size: 1.2rem;
159
+ }
160
+ .toc-list {
161
+ margin: 0 0 16px 0;
162
+ padding: 0;
163
+ list-style: none;
164
+ }
165
+ .toc-list li {
166
+ margin-bottom: 6px;
167
+ }
168
+ .toc-btn {
169
+ display: block;
170
+ margin: 12px 0;
171
+ padding: 8px 16px;
172
+ border: 1px solid #aaa;
173
+ border-radius: 8px;
174
+ background: #fff;
175
+ color: #333;
176
+ cursor: pointer;
177
+ font-size: 1rem;
178
+ text-align: left;
179
+ transition: background 0.2s;
180
+ }
181
+ .toc-btn:hover {
182
+ background: #f0f0f0;
183
+ }
184
+ `; }
185
+ get context() {
186
+ return {
187
+ title: i18next.t('title.kpi overview')
188
+ };
189
+ }
190
+ async firstUpdated() {
191
+ try {
192
+ const { data } = await client.query({ query: GET_KPI_OVERVIEW });
193
+ this.kpiCategories = data.kpiCategories.items;
194
+ this.loading = false;
195
+ }
196
+ catch (e) {
197
+ this.error = e instanceof Error ? e : new Error(String(e));
198
+ this.loading = false;
199
+ }
200
+ }
201
+ render() {
202
+ if (this.error)
203
+ return html `<div>에러: ${this.error?.message}</div>`;
204
+ if (!this.kpiCategories.length)
205
+ return html `<div>KPI 카테고리가 없습니다.</div>`;
206
+ const group = this.kpiCategories[this.selectedGroup];
207
+ const kpi = group?.kpis?.[this.selectedKpi];
208
+ const md = kpi?.description || '각 지표의 주요 소개 내용을 마크다운으로 입력하세요.';
209
+ return html `
210
+ <div class="overview-container">
211
+ <div class="overview-left">
212
+ <div class="overview-title">KPI개요</div>
213
+ <div class="overview-desc">
214
+ 건설현장 KPI 관리 시스템은 프로젝트 성과를 측정하고 모니터링하여 효율적인 공정 관리를 지원합니다.<br />
215
+ 주요 지표를 통해 현장 생산성, 품질, 안전 등을 실시간으로 파악할 수 있습니다.
216
+ </div>
217
+ </div>
218
+ <div class="overview-right">
219
+ <img
220
+ class="overview-img"
221
+ src="https://images.unsplash.com/photo-1464983953574-0892a716854b?auto=format&fit=crop&w=600&q=80"
222
+ alt="건설현장 안전"
223
+ />
224
+ </div>
225
+ </div>
226
+ <div class="group-tabs">
227
+ ${this.kpiCategories.map((g, i) => html `
228
+ <button
229
+ class="group-tab"
230
+ ?selected=${i === this.selectedGroup}
231
+ @click=${() => {
232
+ this.selectedGroup = i;
233
+ this.selectedKpi = 0;
234
+ }}
235
+ >
236
+ ${g.name}
237
+ </button>
238
+ `)}
239
+ </div>
240
+ <div class="main-content">
241
+ <div class="markdown">
242
+ <div style="font-size:1.5rem;font-weight:bold;margin-bottom:16px;">${kpi?.name || ''}</div>
243
+ <div style="margin-bottom:16px;">${kpi?.formula ? html `<b>산식:</b> ${kpi.formula}` : ''}</div>
244
+ <div .innerHTML=${marked(md)}></div>
245
+ ${kpi?.grades?.length
246
+ ? html `<div style="margin-top:32px;">
247
+ <b>등급 구간</b>
248
+ <ul>
249
+ ${kpi.grades.map(g => html `<li>${g.name}: ${g.minValue}~${g.maxValue} (${g.description || ''})</li>`)}
250
+ </ul>
251
+ </div>`
252
+ : ''}
253
+ </div>
254
+ <div class="toc">
255
+ <div class="toc-title">목차</div>
256
+ <ul class="toc-list">
257
+ ${group?.kpis?.map((k, i) => html `
258
+ <li><button class="toc-btn" @click=${() => (this.selectedKpi = i)}>${k.name}</button></li>
259
+ `)}
260
+ </ul>
261
+ </div>
262
+ </div>
263
+ `;
264
+ }
265
+ };
266
+ __decorate([
267
+ state(),
268
+ __metadata("design:type", Object)
269
+ ], KpiOverview.prototype, "selectedGroup", void 0);
270
+ __decorate([
271
+ state(),
272
+ __metadata("design:type", Object)
273
+ ], KpiOverview.prototype, "selectedKpi", void 0);
274
+ __decorate([
275
+ state(),
276
+ __metadata("design:type", Array)
277
+ ], KpiOverview.prototype, "kpiCategories", void 0);
278
+ __decorate([
279
+ state(),
280
+ __metadata("design:type", Object)
281
+ ], KpiOverview.prototype, "loading", void 0);
282
+ __decorate([
283
+ state(),
284
+ __metadata("design:type", Object)
285
+ ], KpiOverview.prototype, "error", void 0);
286
+ KpiOverview = __decorate([
287
+ customElement('kpi-overview')
288
+ ], KpiOverview);
289
+ export { KpiOverview };
290
+ //# sourceMappingURL=kpi-overview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kpi-overview.js","sourceRoot":"","sources":["../../../client/pages/kpi/kpi-overview.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, css, LitElement } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\nimport { marked } from 'marked'\nimport { PageView, store } from '@operato/shell'\nimport { i18next, localize } from '@operato/i18n'\nimport { client } from '@operato/graphql'\nimport gql from 'graphql-tag'\n\nconst GET_KPI_OVERVIEW = gql`\n query {\n kpiCategories {\n items {\n id\n name\n description\n active\n kpis {\n id\n name\n description\n formula\n active\n grades {\n id\n name\n minValue\n maxValue\n score\n color\n description\n }\n }\n }\n }\n }\n`\n\n@customElement('kpi-overview')\nexport class KpiOverview extends PageView {\n static styles = css`\n .overview-container {\n display: flex;\n gap: 32px;\n background: #f7f5fa;\n border-radius: 20px;\n padding: 32px;\n margin-bottom: 24px;\n align-items: stretch;\n }\n .overview-left {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n }\n .overview-title {\n font-size: 2.8rem;\n font-weight: bold;\n margin-bottom: 24px;\n }\n .overview-desc {\n font-size: 1.2rem;\n color: #222;\n line-height: 1.6;\n }\n .overview-right {\n flex: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .overview-img {\n width: 100%;\n max-width: 420px;\n border-radius: 12px;\n object-fit: cover;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);\n }\n .group-tabs {\n display: flex;\n gap: 8px;\n margin: 0 0 16px 0;\n justify-content: center;\n }\n .group-tab {\n padding: 10px 28px;\n border-radius: 16px 16px 0 0;\n background: #eee;\n cursor: pointer;\n font-size: 1.1rem;\n font-weight: 500;\n border: none;\n outline: none;\n transition: background 0.2s;\n }\n .group-tab[selected] {\n background: #d6d6f7;\n color: #222;\n font-weight: bold;\n }\n .kpi-list {\n display: flex;\n gap: 8px;\n margin: 0 0 32px 0;\n justify-content: center;\n }\n .kpi-item {\n padding: 8px 20px;\n border-radius: 12px;\n background: #f5f5f5;\n cursor: pointer;\n font-size: 1rem;\n border: none;\n outline: none;\n transition: background 0.2s;\n }\n .kpi-item[selected] {\n background: #bdf;\n color: #222;\n font-weight: bold;\n }\n .main-content {\n display: flex;\n gap: 32px;\n margin-top: 32px;\n align-items: flex-start;\n justify-content: center;\n }\n .markdown {\n background: #fff;\n border-radius: 12px;\n padding: 40px 32px;\n min-height: 240px;\n flex: 2;\n font-size: 2rem;\n color: #222;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);\n }\n .toc {\n flex: 1;\n background: #faf9fd;\n border-radius: 12px;\n padding: 32px 24px;\n font-size: 1.1rem;\n color: #444;\n min-width: 220px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);\n }\n .toc-title {\n font-weight: bold;\n margin-bottom: 12px;\n font-size: 1.2rem;\n }\n .toc-list {\n margin: 0 0 16px 0;\n padding: 0;\n list-style: none;\n }\n .toc-list li {\n margin-bottom: 6px;\n }\n .toc-btn {\n display: block;\n margin: 12px 0;\n padding: 8px 16px;\n border: 1px solid #aaa;\n border-radius: 8px;\n background: #fff;\n color: #333;\n cursor: pointer;\n font-size: 1rem;\n text-align: left;\n transition: background 0.2s;\n }\n .toc-btn:hover {\n background: #f0f0f0;\n }\n `\n\n get context() {\n return {\n title: i18next.t('title.kpi overview')\n }\n }\n\n @state() selectedGroup = 0\n @state() selectedKpi = 0\n @state() kpiCategories: any[] = []\n @state() loading = true\n @state() error: Error | null = null\n\n async firstUpdated() {\n try {\n const { data } = await client.query({ query: GET_KPI_OVERVIEW })\n this.kpiCategories = data.kpiCategories.items\n this.loading = false\n } catch (e) {\n this.error = e instanceof Error ? e : new Error(String(e))\n this.loading = false\n }\n }\n\n render() {\n if (this.error) return html`<div>에러: ${this.error?.message}</div>`\n if (!this.kpiCategories.length) return html`<div>KPI 카테고리가 없습니다.</div>`\n\n const group = this.kpiCategories[this.selectedGroup] as any\n const kpi = group?.kpis?.[this.selectedKpi] as any\n const md = kpi?.description || '각 지표의 주요 소개 내용을 마크다운으로 입력하세요.'\n\n return html`\n <div class=\"overview-container\">\n <div class=\"overview-left\">\n <div class=\"overview-title\">KPI개요</div>\n <div class=\"overview-desc\">\n 건설현장 KPI 관리 시스템은 프로젝트 성과를 측정하고 모니터링하여 효율적인 공정 관리를 지원합니다.<br />\n 주요 지표를 통해 현장 생산성, 품질, 안전 등을 실시간으로 파악할 수 있습니다.\n </div>\n </div>\n <div class=\"overview-right\">\n <img\n class=\"overview-img\"\n src=\"https://images.unsplash.com/photo-1464983953574-0892a716854b?auto=format&fit=crop&w=600&q=80\"\n alt=\"건설현장 안전\"\n />\n </div>\n </div>\n <div class=\"group-tabs\">\n ${this.kpiCategories.map(\n (g, i) => html`\n <button\n class=\"group-tab\"\n ?selected=${i === this.selectedGroup}\n @click=${() => {\n this.selectedGroup = i\n this.selectedKpi = 0\n }}\n >\n ${g.name}\n </button>\n `\n )}\n </div>\n <div class=\"main-content\">\n <div class=\"markdown\">\n <div style=\"font-size:1.5rem;font-weight:bold;margin-bottom:16px;\">${kpi?.name || ''}</div>\n <div style=\"margin-bottom:16px;\">${kpi?.formula ? html`<b>산식:</b> ${kpi.formula}` : ''}</div>\n <div .innerHTML=${marked(md)}></div>\n ${kpi?.grades?.length\n ? html`<div style=\"margin-top:32px;\">\n <b>등급 구간</b>\n <ul>\n ${kpi.grades.map(g => html`<li>${g.name}: ${g.minValue}~${g.maxValue} (${g.description || ''})</li>`)}\n </ul>\n </div>`\n : ''}\n </div>\n <div class=\"toc\">\n <div class=\"toc-title\">목차</div>\n <ul class=\"toc-list\">\n ${group?.kpis?.map(\n (k, i) => html`\n <li><button class=\"toc-btn\" @click=${() => (this.selectedKpi = i)}>${k.name}</button></li>\n `\n )}\n </ul>\n </div>\n </div>\n `\n }\n}\n"]}
@@ -37,6 +37,21 @@ export class KpiCategoryImporter extends LitElement {
37
37
  ]
38
38
  };
39
39
  }
40
+ static { this.styles = [
41
+ ButtonContainerStyles,
42
+ css `
43
+ :host {
44
+ display: flex;
45
+ flex-direction: column;
46
+
47
+ background-color: #fff;
48
+ }
49
+
50
+ ox-grist {
51
+ flex: 1;
52
+ }
53
+ `
54
+ ]; }
40
55
  render() {
41
56
  return html `
42
57
  <ox-grist
@@ -53,7 +68,6 @@ export class KpiCategoryImporter extends LitElement {
53
68
  `;
54
69
  }
55
70
  async save() {
56
- var _a;
57
71
  const response = await client.mutate({
58
72
  mutation: gql `
59
73
  mutation importKpiCategories($kpiCategories: [KpiCategoryPatch!]!) {
@@ -62,26 +76,11 @@ export class KpiCategoryImporter extends LitElement {
62
76
  `,
63
77
  variables: { kpiCategories: this.kpiCategories }
64
78
  });
65
- if ((_a = response.errors) === null || _a === void 0 ? void 0 : _a.length)
79
+ if (response.errors?.length)
66
80
  return;
67
81
  this.dispatchEvent(new CustomEvent('imported'));
68
82
  }
69
83
  }
70
- KpiCategoryImporter.styles = [
71
- ButtonContainerStyles,
72
- css `
73
- :host {
74
- display: flex;
75
- flex-direction: column;
76
-
77
- background-color: #fff;
78
- }
79
-
80
- ox-grist {
81
- flex: 1;
82
- }
83
- `
84
- ];
85
84
  __decorate([
86
85
  property({ type: Array }),
87
86
  __metadata("design:type", Array)