@dssp/dkpi 1.0.0-alpha.5 → 1.0.0-alpha.51

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 (134) hide show
  1. package/assets/favicon.ico +0 -0
  2. package/assets/manifest/apple-1024.png +0 -0
  3. package/assets/manifest/apple-120.png +0 -0
  4. package/assets/manifest/apple-152.png +0 -0
  5. package/assets/manifest/apple-167.png +0 -0
  6. package/assets/manifest/apple-180.png +0 -0
  7. package/assets/manifest/apple-touch-icon.png +0 -0
  8. package/assets/manifest/badge-128x128.png +0 -0
  9. package/assets/manifest/chrome-splashscreen-icon-384x384.png +0 -0
  10. package/assets/manifest/chrome-touch-icon-192x192.png +0 -0
  11. package/assets/manifest/icon-128x128.png +0 -0
  12. package/assets/manifest/icon-192x192.png +0 -0
  13. package/assets/manifest/icon-512x512.png +0 -0
  14. package/assets/manifest/icon-72x72.png +0 -0
  15. package/assets/manifest/icon-96x96.png +0 -0
  16. package/assets/manifest/image-metaog.png +0 -0
  17. package/assets/manifest/maskable_icon.png +0 -0
  18. package/assets/manifest/ms-icon-144x144.png +0 -0
  19. package/assets/manifest/ms-touch-icon-144x144-precomposed.png +0 -0
  20. package/assets/videos/intro.mp4 +0 -0
  21. package/dist-client/bootstrap.js +64 -4
  22. package/dist-client/bootstrap.js.map +1 -1
  23. package/dist-client/components/kpi-boxplot-chart.d.ts +24 -0
  24. package/dist-client/components/kpi-boxplot-chart.js +328 -0
  25. package/dist-client/components/kpi-boxplot-chart.js.map +1 -0
  26. package/dist-client/components/kpi-radar-chart.d.ts +16 -0
  27. package/dist-client/components/kpi-radar-chart.js +139 -0
  28. package/dist-client/components/kpi-radar-chart.js.map +1 -0
  29. package/dist-client/components/kpi-single-boxplot-chart.d.ts +24 -0
  30. package/dist-client/components/kpi-single-boxplot-chart.js +317 -0
  31. package/dist-client/components/kpi-single-boxplot-chart.js.map +1 -0
  32. package/dist-client/components/sv-pagenation-control.d.ts +18 -0
  33. package/dist-client/components/sv-pagenation-control.js +142 -0
  34. package/dist-client/components/sv-pagenation-control.js.map +1 -0
  35. package/dist-client/icons/menu-icons.d.ts +6 -0
  36. package/dist-client/icons/menu-icons.js +42 -0
  37. package/dist-client/icons/menu-icons.js.map +1 -1
  38. package/dist-client/menu.d.ts +23 -1
  39. package/dist-client/menu.js +57 -2
  40. package/dist-client/menu.js.map +1 -1
  41. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.d.ts +58 -0
  42. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js +731 -0
  43. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js.map +1 -0
  44. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.d.ts +23 -0
  45. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js +76 -0
  46. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js.map +1 -0
  47. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.d.ts +69 -0
  48. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js +385 -0
  49. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js.map +1 -0
  50. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.d.ts +12 -0
  51. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js +174 -0
  52. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js.map +1 -0
  53. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.d.ts +41 -0
  54. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js +191 -0
  55. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js.map +1 -0
  56. package/dist-client/pages/kpi-value/kpi-value-importer.d.ts +23 -0
  57. package/dist-client/pages/kpi-value/kpi-value-importer.js +93 -0
  58. package/dist-client/pages/kpi-value/kpi-value-importer.js.map +1 -0
  59. package/dist-client/pages/kpi-value/kpi-value-list-page.d.ts +72 -0
  60. package/dist-client/pages/kpi-value/kpi-value-list-page.js +465 -0
  61. package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -0
  62. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.d.ts +13 -0
  63. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js +248 -0
  64. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js.map +1 -0
  65. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.d.ts +12 -0
  66. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js +242 -0
  67. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js.map +1 -0
  68. package/dist-client/pages/project-complete-tabs/pc-tab3-upload.d.ts +15 -0
  69. package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js +222 -0
  70. package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js.map +1 -0
  71. package/dist-client/pages/sv-project-complete.d.ts +20 -0
  72. package/dist-client/pages/sv-project-complete.js +207 -0
  73. package/dist-client/pages/sv-project-complete.js.map +1 -0
  74. package/dist-client/pages/sv-project-completed-list.d.ts +24 -0
  75. package/dist-client/pages/sv-project-completed-list.js +357 -0
  76. package/dist-client/pages/sv-project-completed-list.js.map +1 -0
  77. package/dist-client/pages/sv-project-detail.d.ts +16 -0
  78. package/dist-client/pages/sv-project-detail.js +558 -0
  79. package/dist-client/pages/sv-project-detail.js.map +1 -0
  80. package/dist-client/pages/sv-project-list.d.ts +157 -0
  81. package/dist-client/pages/sv-project-list.js +431 -0
  82. package/dist-client/pages/sv-project-list.js.map +1 -0
  83. package/dist-client/route.d.ts +1 -1
  84. package/dist-client/route.js +22 -1
  85. package/dist-client/route.js.map +1 -1
  86. package/dist-client/shared/complete-api.d.ts +8 -0
  87. package/dist-client/shared/complete-api.js +177 -0
  88. package/dist-client/shared/complete-api.js.map +1 -0
  89. package/dist-client/shared/func.d.ts +2 -0
  90. package/dist-client/shared/func.js +22 -0
  91. package/dist-client/shared/func.js.map +1 -0
  92. package/dist-client/themes/dark.css +24 -24
  93. package/dist-client/themes/light.css +23 -23
  94. package/dist-client/tsconfig.tsbuildinfo +1 -1
  95. package/dist-client/viewparts/menu-tools.d.ts +37 -1
  96. package/dist-client/viewparts/menu-tools.js +348 -15
  97. package/dist-client/viewparts/menu-tools.js.map +1 -1
  98. package/dist-server/index.d.ts +2 -0
  99. package/dist-server/index.js +5 -0
  100. package/dist-server/index.js.map +1 -1
  101. package/dist-server/migrations/index.d.ts +1 -0
  102. package/dist-server/migrations/index.js +12 -0
  103. package/dist-server/migrations/index.js.map +1 -0
  104. package/dist-server/scripts/calculate-kpi-scores.d.ts +10 -0
  105. package/dist-server/scripts/calculate-kpi-scores.js +271 -0
  106. package/dist-server/scripts/calculate-kpi-scores.js.map +1 -0
  107. package/dist-server/scripts/load-grade-data-migration.d.ts +10 -0
  108. package/dist-server/scripts/load-grade-data-migration.js +194 -0
  109. package/dist-server/scripts/load-grade-data-migration.js.map +1 -0
  110. package/dist-server/scripts/propagate-parent-kpi-values.d.ts +10 -0
  111. package/dist-server/scripts/propagate-parent-kpi-values.js +440 -0
  112. package/dist-server/scripts/propagate-parent-kpi-values.js.map +1 -0
  113. package/dist-server/service/index.d.ts +6 -0
  114. package/dist-server/service/index.js +21 -0
  115. package/dist-server/service/index.js.map +1 -0
  116. package/dist-server/service/kpi-metric-value/index.d.ts +4 -0
  117. package/dist-server/service/kpi-metric-value/index.js +8 -0
  118. package/dist-server/service/kpi-metric-value/index.js.map +1 -0
  119. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.d.ts +8 -0
  120. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +120 -0
  121. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -0
  122. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.d.ts +7 -0
  123. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js +47 -0
  124. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js.map +1 -0
  125. package/dist-server/service/kpi-value/index.d.ts +3 -0
  126. package/dist-server/service/kpi-value/index.js +7 -0
  127. package/dist-server/service/kpi-value/index.js.map +1 -0
  128. package/dist-server/service/kpi-value/kpi-value-query.d.ts +7 -0
  129. package/dist-server/service/kpi-value/kpi-value-query.js +47 -0
  130. package/dist-server/service/kpi-value/kpi-value-query.js.map +1 -0
  131. package/dist-server/tsconfig.tsbuildinfo +1 -1
  132. package/package.json +62 -51
  133. package/schema.graphql +11497 -3215
  134. package/things-factory.config.js +7 -1
@@ -0,0 +1,558 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import { navigate, PageView } from '@operato/shell';
3
+ import { css, html } from 'lit';
4
+ import { customElement, state } from 'lit/decorators.js';
5
+ import { ScopedElementsMixin } from '@open-wc/scoped-elements';
6
+ import { PROJECT_STATE } from './sv-project-list';
7
+ import { client } from '@operato/graphql';
8
+ import gql from 'graphql-tag';
9
+ import '../components/kpi-boxplot-chart';
10
+ import '../components/kpi-single-boxplot-chart';
11
+ import '../components/kpi-radar-chart';
12
+ let SvProjectDetailPage = class SvProjectDetailPage extends ScopedElementsMixin(PageView) {
13
+ constructor() {
14
+ super(...arguments);
15
+ this.project = {};
16
+ }
17
+ get context() {
18
+ return {
19
+ title: '프로젝트 상세 정보'
20
+ };
21
+ }
22
+ render() {
23
+ var _a, _b, _c, _d, _e, _f, _g, _h;
24
+ return html `
25
+ <div content>
26
+ <div left>
27
+ <div class="card">
28
+ <div class="card-title">
29
+ <div>${this.project.name}</div>
30
+ <div class="triangle"></div>
31
+ </div>
32
+
33
+ <div class="top-info" style="margin-top: 10px;">
34
+ <img pic src=${((_a = this.project.mainPhoto) === null || _a === void 0 ? void 0 : _a.fullpath) || '/assets/images/no-image.png'} alt="project" />
35
+ <div class="info">
36
+ <div class="address">• ${(_b = this.project.buildingComplex) === null || _b === void 0 ? void 0 : _b.address}</div>
37
+ <div class="row">
38
+ <div class="label">• 공사기간</div>
39
+ <div class="value">${this.project.startDate} ~ ${this.project.endDate}</div>
40
+ </div>
41
+ <div class="row">
42
+ <div class="label">• 현장상태</div>
43
+ <div class="value status-value">${PROJECT_STATE[this.project.state]}</div>
44
+ </div>
45
+ <div class="row">
46
+ <div class="label">• 요청상세</div>
47
+ <div class="value bold">???</div>
48
+ </div>
49
+ <div class="row">
50
+ <div class="label">• 알람</div>
51
+ <div class="value">???</div>
52
+ </div>
53
+ </div>
54
+ </div>
55
+
56
+ <div class="detail-grid">
57
+ <div class="grid-item row">
58
+ <div class="label">• 공사비</div>
59
+ <div class="value">${((_d = (_c = this.project.buildingComplex) === null || _c === void 0 ? void 0 : _c.constructionCost) === null || _d === void 0 ? void 0 : _d.toLocaleString()) || '-'} 원</div>
60
+ </div>
61
+ <div class="grid-item row">
62
+ <div class="label">• 연면적</div>
63
+ <div class="value">${((_f = (_e = this.project.buildingComplex) === null || _e === void 0 ? void 0 : _e.area) === null || _f === void 0 ? void 0 : _f.toLocaleString()) || '-'} ㎡</div>
64
+ </div>
65
+ <div class="grid-item row">
66
+ <div class="label">• 용적률</div>
67
+ <div class="value">??? %</div>
68
+ </div>
69
+ <div class="grid-item row">
70
+ <div class="label">• 투입인력</div>
71
+ <div class="value">??? 명</div>
72
+ </div>
73
+ </div>
74
+ </div>
75
+
76
+ <div class="card">
77
+ <div class="card-title">
78
+ <div>입력 대기 중</div>
79
+ <div class="triangle"></div>
80
+ </div>
81
+ <div class="sub-desc">
82
+ 현재 입력 기한이 도래했거나, 입력이 지연되고 있는 KPI 항목입니다. 해당 항목에 대한 데이터를 입력 해 주시기 바랍니다.
83
+ </div>
84
+
85
+ <div class="list-block">
86
+ <div class="list-title">• 입력 대기 중 2건</div>
87
+ <div class="list-text"># 2033312-Y5.1 : 검수자재 불합격률</div>
88
+ <div class="list-text"># 2033312-Y5.1 : 품질시험 불합격 건수</div>
89
+ </div>
90
+ <div class="list-block">
91
+ <div class="list-title">• 입력 기한 초과 1건</div>
92
+ <div class="list-text">
93
+ # 2033312-Y5.2 : 검측 불합격률 <span class="warn">2025.2.12 <md-icon>report</md-icon></span>
94
+ </div>
95
+ </div>
96
+ <div class="list-block">
97
+ <div class="list-title">• 입력 예정 4건</div>
98
+ <div class="list-text"># 2033320-Y4.32 : 연면적 대비 공기입력</div>
99
+ <div class="list-text"># 2012345-Y4.32 : 책임감리원의 일정성과 수준 평가</div>
100
+ <div class="list-text"># 2035641-Y5.22 : 설계 변경에 따른 공기 증감률</div>
101
+ <div class="list-text"># 2096412-Y5.31 : 현장별 일정 이탈 수준</div>
102
+ </div>
103
+ <div class="list-block">
104
+ <div class="list-title">• 입력 기한 없음 3건</div>
105
+ <div class="list-text"># 2033320-Y4.32 : 연면적 대비 공기입력</div>
106
+ <div class="list-text"># 2012345-Y4.32 : 책임감리원의 일정성과 수준 평가</div>
107
+ <div class="list-text"># 2035641-Y5.22 : 설계 변경에 따른 공기 증감률</div>
108
+ </div>
109
+ </div>
110
+ </div>
111
+
112
+ <div right>
113
+ ${html `
114
+ <div class="button-line">
115
+ <div class="ghost-btn" @click=${() => navigate(`project-update/${this.project.id}`)}>
116
+ <md-icon slot="">assignment</md-icon>
117
+ <div>프로젝트 수정</div>
118
+ </div>
119
+ <div class="ghost-btn" @click=${() => navigate(`project-complete/${this.project.id}`)}>
120
+ <md-icon slot="">assignment_turned_in</md-icon>
121
+ <div>프로젝트 완공 처리</div>
122
+ </div>
123
+ </div>
124
+ `}
125
+
126
+ <div class="card kpi-box">
127
+ <div class="kpi-header">
128
+ <div>
129
+ <div>종합 KPI</div>
130
+ <div class="triangle"></div>
131
+ </div>
132
+ <div class="kpi-desc">프로젝트의 6개 성과를 종합한 종합 KPI포인트와 각 지표별 분포</div>
133
+ </div>
134
+
135
+ <div class="kpi-summary">
136
+ <div class="mini-boxplot" title="boxplot placeholder">
137
+ <div class="boxplot-area">
138
+ <kpi-single-boxplot-chart
139
+ .data=${{
140
+ min: 0,
141
+ max: 100,
142
+ mean: 50,
143
+ median: 60,
144
+ q1: 25,
145
+ q3: 75,
146
+ value: this.project.kpi
147
+ }}
148
+ ></kpi-single-boxplot-chart>
149
+ </div>
150
+
151
+ <div class="boxplot-point">
152
+ <div class="value">${(_h = (_g = this.project.kpi) === null || _g === void 0 ? void 0 : _g.toFixed(1)) !== null && _h !== void 0 ? _h : '-'}</div>
153
+ <div class="label">Point</div>
154
+ </div>
155
+ </div>
156
+
157
+ <div class="spider-area">
158
+ <kpi-radar-chart
159
+ .data=${[
160
+ {
161
+ group: '평균',
162
+ category: '생산성 성과',
163
+ value: 41
164
+ },
165
+ {
166
+ group: '평균',
167
+ category: '일정 성과',
168
+ value: 26
169
+ },
170
+ {
171
+ group: '평균',
172
+ category: '비용 성과',
173
+ value: 30
174
+ },
175
+ {
176
+ group: '평균',
177
+ category: '품질 성과',
178
+ value: 21
179
+ },
180
+ {
181
+ group: '평균',
182
+ category: '안전 성과',
183
+ value: 33
184
+ },
185
+ {
186
+ group: '평균',
187
+ category: '환경 성과',
188
+ value: 15
189
+ }
190
+ ]}
191
+ .categories=${['생산성 성과', '일정 성과', '비용 성과', '품질 성과', '안전 성과', '환경 성과']}
192
+ .currentGroup=${'평균'}
193
+ ></kpi-radar-chart>
194
+ </div>
195
+ </div>
196
+ </div>
197
+
198
+ <div class="card group-box">
199
+ <div class="kpi-header">
200
+ <div>그룹별 분포</div>
201
+ <div class="triangle"></div>
202
+ </div>
203
+ <div class="desc">
204
+ Boxplot(박스플롯)은 각 카테고리별로 값의 분포(최소, 1사분위, 중앙값, 3사분위, 최대, 평균, 이상치 등)를 보여줍니다.
205
+ 박스는 중앙 50% 구간, 수염은 전체 범위, 굵은 검정색 가로선은 중앙값(메디안), 초록색 원은 평균값(Mean)을 의미합니다.
206
+ 이 프로젝트의 값은 진한 오렌지색 원으로 별도 강조되어 표시되며, 중앙값/평균과 다를 수 있습니다.
207
+ </div>
208
+ <div class="group-chart"></div>
209
+ </div>
210
+ </div>
211
+ </div>
212
+ `;
213
+ }
214
+ async pageUpdated(changes, lifecycle) {
215
+ if (this.active) {
216
+ await this.initProject(lifecycle.resourceId);
217
+ }
218
+ }
219
+ async initProject(projectId = '') {
220
+ var _a;
221
+ const response = await client.query({
222
+ query: gql `
223
+ query Project($id: String!) {
224
+ project(id: $id) {
225
+ id
226
+ name
227
+ state
228
+ startDate
229
+ endDate
230
+ projectType
231
+ mainPhoto {
232
+ fullpath
233
+ }
234
+ totalProgress
235
+ weeklyProgress
236
+ kpi
237
+ inspPassRate
238
+ robotProgressRate
239
+ structuralSafetyRate
240
+ robotCount
241
+ buildingComplex {
242
+ id
243
+ address
244
+ latitude
245
+ longitude
246
+ area
247
+ clientCompany
248
+ constructionCompany
249
+ supervisoryCompany
250
+ designCompany
251
+ drawing {
252
+ id
253
+ name
254
+ fullpath
255
+ }
256
+ constructionType
257
+ constructionCost
258
+ etc
259
+ notice
260
+ householdCount
261
+ buildingCount
262
+ virtualTourLink
263
+ buildings {
264
+ id
265
+ name
266
+ floorCount
267
+ }
268
+ }
269
+ }
270
+ }
271
+ `,
272
+ variables: { id: projectId }
273
+ });
274
+ if (response.errors)
275
+ return;
276
+ this.project = ((_a = response.data) === null || _a === void 0 ? void 0 : _a.project) || {};
277
+ }
278
+ };
279
+ SvProjectDetailPage.styles = [
280
+ css `
281
+ :host {
282
+ display: flex;
283
+ flex-direction: column;
284
+ overflow-y: auto;
285
+
286
+ width: 100%;
287
+ height: 100%;
288
+ background-color: var(--md-sys-color-background, #f6f6f6);
289
+ }
290
+
291
+ /* content layout */
292
+ div[content] {
293
+ display: flex;
294
+ gap: 35px;
295
+ padding: 25px;
296
+ }
297
+ div[left] {
298
+ flex: 1;
299
+ display: flex;
300
+ flex-direction: column;
301
+ gap: 20px;
302
+ }
303
+ div[right] {
304
+ flex: 1;
305
+ display: flex;
306
+ flex-direction: column;
307
+ gap: 20px;
308
+ padding: 0 1px;
309
+ }
310
+
311
+ /* card */
312
+ .card {
313
+ background: #ffffff;
314
+ border-radius: 10px;
315
+ padding: 15px;
316
+ box-shadow: 3px 3px 3px 0 rgba(0, 0, 0, 0.1);
317
+ }
318
+ .card-title {
319
+ display: flex;
320
+ align-items: center;
321
+ gap: 5px;
322
+ color: #35618e;
323
+ font-weight: 700;
324
+ }
325
+ .triangle {
326
+ width: 0;
327
+ height: 0;
328
+ border-left: 6px solid transparent;
329
+ border-right: 6px solid transparent;
330
+ border-top: 8px solid #35618e;
331
+ }
332
+
333
+ /* left top info box */
334
+ .bold {
335
+ font-weight: bold;
336
+ }
337
+ .top-info {
338
+ display: flex;
339
+ gap: 10px;
340
+ }
341
+ .top-info img[pic] {
342
+ width: 284px;
343
+ height: 160px;
344
+ object-fit: fill;
345
+ background: #e5e7eb;
346
+ }
347
+ .top-info .info {
348
+ display: flex;
349
+ flex-direction: column;
350
+ gap: 15px;
351
+ padding: 10px 0;
352
+ flex: 1;
353
+ }
354
+ .row {
355
+ display: flex;
356
+ align-items: center;
357
+ gap: 10px;
358
+ }
359
+ .label {
360
+ min-width: fit-content;
361
+ color: #35618e;
362
+ font-size: 16px;
363
+ letter-spacing: -0.05em;
364
+ }
365
+ .value {
366
+ color: #212529;
367
+ font-size: 16px;
368
+ }
369
+ .status-value {
370
+ color: #4cbb49;
371
+ font-weight: 700;
372
+ }
373
+
374
+ .address {
375
+ color: #35618e;
376
+ font-size: 16px;
377
+ letter-spacing: -0.05em;
378
+ }
379
+
380
+ .detail-grid {
381
+ display: grid;
382
+ grid-template-columns: 284px 1fr;
383
+ gap: 15px 10px;
384
+ padding: 5px 0;
385
+ }
386
+ .detail-grid .grid-item .label {
387
+ width: auto;
388
+ }
389
+
390
+ /* left second card (requests) */
391
+ .sub-desc {
392
+ color: #35618e;
393
+ font-size: 14px;
394
+ letter-spacing: -0.05em;
395
+ margin-bottom: 8px;
396
+ }
397
+ .list-block {
398
+ display: flex;
399
+ flex-direction: column;
400
+ gap: 5px;
401
+ padding: 5px 25px;
402
+ }
403
+ .list-title {
404
+ color: #212529;
405
+ font-weight: 700;
406
+ font-size: 16px;
407
+ letter-spacing: -0.05em;
408
+ }
409
+ .list-text {
410
+ color: #35618e;
411
+ font-size: 16px;
412
+ letter-spacing: -0.05em;
413
+ margin-left: 8px;
414
+ }
415
+ .list-text .warn {
416
+ margin-left: 10px;
417
+ color: #e13232;
418
+
419
+ md-icon {
420
+ font-size: 17px;
421
+ width: 13px;
422
+ height: 13px;
423
+ }
424
+ }
425
+
426
+ /* right buttons */
427
+ .button-line {
428
+ display: flex;
429
+ justify-content: flex-end;
430
+ gap: 10px;
431
+ }
432
+ .ghost-btn {
433
+ display: flex;
434
+ align-items: center;
435
+ gap: 3px;
436
+ padding: 5px 10px;
437
+ background: #35618e;
438
+ color: #ffffff;
439
+ border-radius: 5px;
440
+ box-shadow: 2px 2px 2px 0 rgba(0, 0, 0, 0.1);
441
+ cursor: pointer;
442
+
443
+ /* Material Symbols Outlined (stroke style) */
444
+ md-icon {
445
+ font-variation-settings:
446
+ 'FILL' 0,
447
+ 'wght' 300,
448
+ 'GRAD' 0,
449
+ 'opsz' 24;
450
+ }
451
+ }
452
+
453
+ /* right KPI box */
454
+ .kpi-box {
455
+ display: flex;
456
+ flex-direction: column;
457
+ gap: 10px;
458
+ padding: 15px;
459
+ max-height: 420px;
460
+ min-width: 560px;
461
+ }
462
+ .kpi-header {
463
+ display: flex;
464
+ align-items: center;
465
+ justify-content: space-between;
466
+ color: #35618e;
467
+ font-weight: 700;
468
+ font-size: 20px;
469
+ letter-spacing: -0.05em;
470
+ }
471
+ .kpi-header div {
472
+ display: flex;
473
+ align-items: center;
474
+ gap: 5px;
475
+ }
476
+ .kpi-desc {
477
+ color: #35618e;
478
+ font-size: 13px;
479
+ letter-spacing: -0.05em;
480
+ }
481
+ .kpi-summary {
482
+ display: flex;
483
+ align-items: center;
484
+ padding: 0 30px;
485
+ max-height: 360px;
486
+ }
487
+ .mini-boxplot {
488
+ flex: 1;
489
+ display: flex;
490
+ flex-direction: column;
491
+ height: 100%;
492
+ position: relative;
493
+ min-width: 120px;
494
+ }
495
+ .boxplot-area {
496
+ flex: 1;
497
+ width: 100%;
498
+ display: flex;
499
+ flex-direction: column;
500
+ align-items: center;
501
+ background: #ffffff;
502
+ }
503
+
504
+ .boxplot-point {
505
+ display: flex;
506
+ flex-direction: column;
507
+ align-items: center;
508
+ color: #35618e;
509
+ }
510
+ .boxplot-point .value {
511
+ font-size: 42px;
512
+ font-weight: 800;
513
+ color: #35618e;
514
+ border-radius: 6px;
515
+ }
516
+ .boxplot-point .label {
517
+ font-size: 14px;
518
+ font-weight: 300;
519
+ width: auto;
520
+ }
521
+
522
+ /* spider chart placeholder */
523
+ .spider-area {
524
+ flex: 5;
525
+ display: flex;
526
+ flex-direction: column;
527
+ align-items: center;
528
+ justify-content: center;
529
+ gap: 10px;
530
+ height: 100%;
531
+ }
532
+
533
+ /* group distribution */
534
+ .group-box .desc {
535
+ color: #35618e;
536
+ font-size: 13px;
537
+ letter-spacing: -0.05em;
538
+ margin-top: 4px;
539
+ }
540
+ .group-chart {
541
+ height: 205px;
542
+ margin-top: 25px;
543
+ }
544
+
545
+ kpi-single-boxplot-chart {
546
+ flex: 1;
547
+ }
548
+ `
549
+ ];
550
+ __decorate([
551
+ state(),
552
+ __metadata("design:type", Object)
553
+ ], SvProjectDetailPage.prototype, "project", void 0);
554
+ SvProjectDetailPage = __decorate([
555
+ customElement('sv-project-detail')
556
+ ], SvProjectDetailPage);
557
+ export { SvProjectDetailPage };
558
+ //# sourceMappingURL=sv-project-detail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sv-project-detail.js","sourceRoot":"","sources":["../../client/pages/sv-project-detail.ts"],"names":[],"mappings":"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","sourcesContent":["import { navigate, PageLifecycle, PageView } from '@operato/shell'\nimport { css, html } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\nimport { Project, PROJECT_STATE, ProjectState } from './sv-project-list'\nimport { client } from '@operato/graphql'\nimport gql from 'graphql-tag'\nimport '../components/kpi-boxplot-chart'\nimport '../components/kpi-single-boxplot-chart'\nimport '../components/kpi-radar-chart'\n\n@customElement('sv-project-detail')\nexport class SvProjectDetailPage extends ScopedElementsMixin(PageView) {\n static styles = [\n css`\n :host {\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n\n width: 100%;\n height: 100%;\n background-color: var(--md-sys-color-background, #f6f6f6);\n }\n\n /* content layout */\n div[content] {\n display: flex;\n gap: 35px;\n padding: 25px;\n }\n div[left] {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 20px;\n }\n div[right] {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 0 1px;\n }\n\n /* card */\n .card {\n background: #ffffff;\n border-radius: 10px;\n padding: 15px;\n box-shadow: 3px 3px 3px 0 rgba(0, 0, 0, 0.1);\n }\n .card-title {\n display: flex;\n align-items: center;\n gap: 5px;\n color: #35618e;\n font-weight: 700;\n }\n .triangle {\n width: 0;\n height: 0;\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-top: 8px solid #35618e;\n }\n\n /* left top info box */\n .bold {\n font-weight: bold;\n }\n .top-info {\n display: flex;\n gap: 10px;\n }\n .top-info img[pic] {\n width: 284px;\n height: 160px;\n object-fit: fill;\n background: #e5e7eb;\n }\n .top-info .info {\n display: flex;\n flex-direction: column;\n gap: 15px;\n padding: 10px 0;\n flex: 1;\n }\n .row {\n display: flex;\n align-items: center;\n gap: 10px;\n }\n .label {\n min-width: fit-content;\n color: #35618e;\n font-size: 16px;\n letter-spacing: -0.05em;\n }\n .value {\n color: #212529;\n font-size: 16px;\n }\n .status-value {\n color: #4cbb49;\n font-weight: 700;\n }\n\n .address {\n color: #35618e;\n font-size: 16px;\n letter-spacing: -0.05em;\n }\n\n .detail-grid {\n display: grid;\n grid-template-columns: 284px 1fr;\n gap: 15px 10px;\n padding: 5px 0;\n }\n .detail-grid .grid-item .label {\n width: auto;\n }\n\n /* left second card (requests) */\n .sub-desc {\n color: #35618e;\n font-size: 14px;\n letter-spacing: -0.05em;\n margin-bottom: 8px;\n }\n .list-block {\n display: flex;\n flex-direction: column;\n gap: 5px;\n padding: 5px 25px;\n }\n .list-title {\n color: #212529;\n font-weight: 700;\n font-size: 16px;\n letter-spacing: -0.05em;\n }\n .list-text {\n color: #35618e;\n font-size: 16px;\n letter-spacing: -0.05em;\n margin-left: 8px;\n }\n .list-text .warn {\n margin-left: 10px;\n color: #e13232;\n\n md-icon {\n font-size: 17px;\n width: 13px;\n height: 13px;\n }\n }\n\n /* right buttons */\n .button-line {\n display: flex;\n justify-content: flex-end;\n gap: 10px;\n }\n .ghost-btn {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 5px 10px;\n background: #35618e;\n color: #ffffff;\n border-radius: 5px;\n box-shadow: 2px 2px 2px 0 rgba(0, 0, 0, 0.1);\n cursor: pointer;\n\n /* Material Symbols Outlined (stroke style) */\n md-icon {\n font-variation-settings:\n 'FILL' 0,\n 'wght' 300,\n 'GRAD' 0,\n 'opsz' 24;\n }\n }\n\n /* right KPI box */\n .kpi-box {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 15px;\n max-height: 420px;\n min-width: 560px;\n }\n .kpi-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n color: #35618e;\n font-weight: 700;\n font-size: 20px;\n letter-spacing: -0.05em;\n }\n .kpi-header div {\n display: flex;\n align-items: center;\n gap: 5px;\n }\n .kpi-desc {\n color: #35618e;\n font-size: 13px;\n letter-spacing: -0.05em;\n }\n .kpi-summary {\n display: flex;\n align-items: center;\n padding: 0 30px;\n max-height: 360px;\n }\n .mini-boxplot {\n flex: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n position: relative;\n min-width: 120px;\n }\n .boxplot-area {\n flex: 1;\n width: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n background: #ffffff;\n }\n\n .boxplot-point {\n display: flex;\n flex-direction: column;\n align-items: center;\n color: #35618e;\n }\n .boxplot-point .value {\n font-size: 42px;\n font-weight: 800;\n color: #35618e;\n border-radius: 6px;\n }\n .boxplot-point .label {\n font-size: 14px;\n font-weight: 300;\n width: auto;\n }\n\n /* spider chart placeholder */\n .spider-area {\n flex: 5;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 10px;\n height: 100%;\n }\n\n /* group distribution */\n .group-box .desc {\n color: #35618e;\n font-size: 13px;\n letter-spacing: -0.05em;\n margin-top: 4px;\n }\n .group-chart {\n height: 205px;\n margin-top: 25px;\n }\n\n kpi-single-boxplot-chart {\n flex: 1;\n }\n `\n ]\n\n get context() {\n return {\n title: '프로젝트 상세 정보'\n }\n }\n\n @state() private project: Project = {} as Project\n\n render() {\n return html`\n <div content>\n <div left>\n <div class=\"card\">\n <div class=\"card-title\">\n <div>${this.project.name}</div>\n <div class=\"triangle\"></div>\n </div>\n\n <div class=\"top-info\" style=\"margin-top: 10px;\">\n <img pic src=${this.project.mainPhoto?.fullpath || '/assets/images/no-image.png'} alt=\"project\" />\n <div class=\"info\">\n <div class=\"address\">• ${this.project.buildingComplex?.address}</div>\n <div class=\"row\">\n <div class=\"label\">• 공사기간</div>\n <div class=\"value\">${this.project.startDate} ~ ${this.project.endDate}</div>\n </div>\n <div class=\"row\">\n <div class=\"label\">• 현장상태</div>\n <div class=\"value status-value\">${PROJECT_STATE[this.project.state]}</div>\n </div>\n <div class=\"row\">\n <div class=\"label\">• 요청상세</div>\n <div class=\"value bold\">???</div>\n </div>\n <div class=\"row\">\n <div class=\"label\">• 알람</div>\n <div class=\"value\">???</div>\n </div>\n </div>\n </div>\n\n <div class=\"detail-grid\">\n <div class=\"grid-item row\">\n <div class=\"label\">• 공사비</div>\n <div class=\"value\">${this.project.buildingComplex?.constructionCost?.toLocaleString() || '-'} 원</div>\n </div>\n <div class=\"grid-item row\">\n <div class=\"label\">• 연면적</div>\n <div class=\"value\">${this.project.buildingComplex?.area?.toLocaleString() || '-'} ㎡</div>\n </div>\n <div class=\"grid-item row\">\n <div class=\"label\">• 용적률</div>\n <div class=\"value\">??? %</div>\n </div>\n <div class=\"grid-item row\">\n <div class=\"label\">• 투입인력</div>\n <div class=\"value\">??? 명</div>\n </div>\n </div>\n </div>\n\n <div class=\"card\">\n <div class=\"card-title\">\n <div>입력 대기 중</div>\n <div class=\"triangle\"></div>\n </div>\n <div class=\"sub-desc\">\n 현재 입력 기한이 도래했거나, 입력이 지연되고 있는 KPI 항목입니다. 해당 항목에 대한 데이터를 입력 해 주시기 바랍니다.\n </div>\n\n <div class=\"list-block\">\n <div class=\"list-title\">• 입력 대기 중 2건</div>\n <div class=\"list-text\"># 2033312-Y5.1 : 검수자재 불합격률</div>\n <div class=\"list-text\"># 2033312-Y5.1 : 품질시험 불합격 건수</div>\n </div>\n <div class=\"list-block\">\n <div class=\"list-title\">• 입력 기한 초과 1건</div>\n <div class=\"list-text\">\n # 2033312-Y5.2 : 검측 불합격률 <span class=\"warn\">2025.2.12 <md-icon>report</md-icon></span>\n </div>\n </div>\n <div class=\"list-block\">\n <div class=\"list-title\">• 입력 예정 4건</div>\n <div class=\"list-text\"># 2033320-Y4.32 : 연면적 대비 공기입력</div>\n <div class=\"list-text\"># 2012345-Y4.32 : 책임감리원의 일정성과 수준 평가</div>\n <div class=\"list-text\"># 2035641-Y5.22 : 설계 변경에 따른 공기 증감률</div>\n <div class=\"list-text\"># 2096412-Y5.31 : 현장별 일정 이탈 수준</div>\n </div>\n <div class=\"list-block\">\n <div class=\"list-title\">• 입력 기한 없음 3건</div>\n <div class=\"list-text\"># 2033320-Y4.32 : 연면적 대비 공기입력</div>\n <div class=\"list-text\"># 2012345-Y4.32 : 책임감리원의 일정성과 수준 평가</div>\n <div class=\"list-text\"># 2035641-Y5.22 : 설계 변경에 따른 공기 증감률</div>\n </div>\n </div>\n </div>\n\n <div right>\n ${html`\n <div class=\"button-line\">\n <div class=\"ghost-btn\" @click=${() => navigate(`project-update/${this.project.id}`)}>\n <md-icon slot=\"\">assignment</md-icon>\n <div>프로젝트 수정</div>\n </div>\n <div class=\"ghost-btn\" @click=${() => navigate(`project-complete/${this.project.id}`)}>\n <md-icon slot=\"\">assignment_turned_in</md-icon>\n <div>프로젝트 완공 처리</div>\n </div>\n </div>\n `}\n\n <div class=\"card kpi-box\">\n <div class=\"kpi-header\">\n <div>\n <div>종합 KPI</div>\n <div class=\"triangle\"></div>\n </div>\n <div class=\"kpi-desc\">프로젝트의 6개 성과를 종합한 종합 KPI포인트와 각 지표별 분포</div>\n </div>\n\n <div class=\"kpi-summary\">\n <div class=\"mini-boxplot\" title=\"boxplot placeholder\">\n <div class=\"boxplot-area\">\n <kpi-single-boxplot-chart\n .data=${{\n min: 0,\n max: 100,\n mean: 50,\n median: 60,\n q1: 25,\n q3: 75,\n value: this.project.kpi\n }}\n ></kpi-single-boxplot-chart>\n </div>\n\n <div class=\"boxplot-point\">\n <div class=\"value\">${this.project.kpi?.toFixed(1) ?? '-'}</div>\n <div class=\"label\">Point</div>\n </div>\n </div>\n\n <div class=\"spider-area\">\n <kpi-radar-chart\n .data=${[\n {\n group: '평균',\n category: '생산성 성과',\n value: 41\n },\n {\n group: '평균',\n category: '일정 성과',\n value: 26\n },\n {\n group: '평균',\n category: '비용 성과',\n value: 30\n },\n {\n group: '평균',\n category: '품질 성과',\n value: 21\n },\n {\n group: '평균',\n category: '안전 성과',\n value: 33\n },\n {\n group: '평균',\n category: '환경 성과',\n value: 15\n }\n ]}\n .categories=${['생산성 성과', '일정 성과', '비용 성과', '품질 성과', '안전 성과', '환경 성과']}\n .currentGroup=${'평균'}\n ></kpi-radar-chart>\n </div>\n </div>\n </div>\n\n <div class=\"card group-box\">\n <div class=\"kpi-header\">\n <div>그룹별 분포</div>\n <div class=\"triangle\"></div>\n </div>\n <div class=\"desc\">\n Boxplot(박스플롯)은 각 카테고리별로 값의 분포(최소, 1사분위, 중앙값, 3사분위, 최대, 평균, 이상치 등)를 보여줍니다.\n 박스는 중앙 50% 구간, 수염은 전체 범위, 굵은 검정색 가로선은 중앙값(메디안), 초록색 원은 평균값(Mean)을 의미합니다.\n 이 프로젝트의 값은 진한 오렌지색 원으로 별도 강조되어 표시되며, 중앙값/평균과 다를 수 있습니다.\n </div>\n <div class=\"group-chart\"></div>\n </div>\n </div>\n </div>\n `\n }\n\n async pageUpdated(changes: any, lifecycle: PageLifecycle) {\n if (this.active) {\n await this.initProject(lifecycle.resourceId)\n }\n }\n\n async initProject(projectId: string = '') {\n const response = await client.query({\n query: gql`\n query Project($id: String!) {\n project(id: $id) {\n id\n name\n state\n startDate\n endDate\n projectType\n mainPhoto {\n fullpath\n }\n totalProgress\n weeklyProgress\n kpi\n inspPassRate\n robotProgressRate\n structuralSafetyRate\n robotCount\n buildingComplex {\n id\n address\n latitude\n longitude\n area\n clientCompany\n constructionCompany\n supervisoryCompany\n designCompany\n drawing {\n id\n name\n fullpath\n }\n constructionType\n constructionCost\n etc\n notice\n householdCount\n buildingCount\n virtualTourLink\n buildings {\n id\n name\n floorCount\n }\n }\n }\n }\n `,\n variables: { id: projectId }\n })\n\n if (response.errors) return\n\n this.project = response.data?.project || ({} as Project)\n }\n}\n"]}