@things-factory/kpi 9.0.41 → 9.0.42
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.
- package/assets/images/green-calendar.svg +3 -0
- package/client/pages/kpi/kpi-overview.ts +180 -99
- package/dist-client/assets/calendar.svg +3 -0
- package/dist-client/assets/check.svg +3 -0
- package/dist-client/assets/document.svg +3 -0
- package/dist-client/assets/green-calendar.svg +3 -0
- package/dist-client/assets/green_calendar.svg +3 -0
- package/dist-client/assets/leaf.svg +3 -0
- package/dist-client/assets/setting.svg +3 -0
- package/dist-client/assets/shield.svg +3 -0
- package/dist-client/pages/kpi/client/pages/kpi/kpi-overview.d.ts +0 -0
- package/dist-client/pages/kpi/client/pages/kpi/kpi-overview.js +2 -0
- package/dist-client/pages/kpi/client/pages/kpi/kpi-overview.js.map +1 -0
- package/dist-client/pages/kpi/kpi-overview.js +175 -94
- package/dist-client/pages/kpi/kpi-overview.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { __decorate, __metadata } from "tslib";
|
|
2
2
|
import { html, css } from 'lit';
|
|
3
3
|
import { customElement, state } from 'lit/decorators.js';
|
|
4
|
-
import { marked } from 'marked';
|
|
5
4
|
import { PageView } from '@operato/shell';
|
|
6
5
|
import { i18next } from '@operato/i18n';
|
|
7
6
|
import { client } from '@operato/graphql';
|
|
@@ -34,65 +33,68 @@ let KpiOverview = class KpiOverview extends PageView {
|
|
|
34
33
|
this.error = null;
|
|
35
34
|
}
|
|
36
35
|
static { this.styles = css `
|
|
36
|
+
:host {
|
|
37
|
+
display: block;
|
|
38
|
+
background: #f6f6f6;
|
|
39
|
+
box-sizing: border-box;
|
|
40
|
+
padding: 16px 24px;
|
|
41
|
+
}
|
|
37
42
|
.overview-container {
|
|
38
|
-
display:
|
|
39
|
-
|
|
40
|
-
background: #f7f5fa;
|
|
41
|
-
border-radius: 20px;
|
|
42
|
-
padding: 32px;
|
|
43
|
-
margin-bottom: 24px;
|
|
44
|
-
align-items: stretch;
|
|
43
|
+
display: block;
|
|
44
|
+
margin: 8px 0 24px 0;
|
|
45
45
|
}
|
|
46
46
|
.overview-left {
|
|
47
|
-
|
|
48
|
-
display: flex;
|
|
49
|
-
flex-direction: column;
|
|
50
|
-
justify-content: center;
|
|
47
|
+
display: block;
|
|
51
48
|
}
|
|
52
49
|
.overview-title {
|
|
53
|
-
|
|
54
|
-
font-
|
|
55
|
-
|
|
50
|
+
color: #0c4da2;
|
|
51
|
+
font-size: 1.125rem;
|
|
52
|
+
font-weight: 700;
|
|
53
|
+
letter-spacing: -0.05em;
|
|
54
|
+
margin: 0 0 8px 0;
|
|
56
55
|
}
|
|
57
56
|
.overview-desc {
|
|
58
|
-
font-size:
|
|
59
|
-
color: #
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
.overview-right {
|
|
63
|
-
flex: 1;
|
|
64
|
-
display: flex;
|
|
65
|
-
align-items: center;
|
|
66
|
-
justify-content: center;
|
|
67
|
-
}
|
|
68
|
-
.overview-img {
|
|
69
|
-
width: 100%;
|
|
70
|
-
max-width: 420px;
|
|
71
|
-
border-radius: 12px;
|
|
72
|
-
object-fit: cover;
|
|
73
|
-
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
|
|
57
|
+
font-size: 0.875rem;
|
|
58
|
+
color: #212529;
|
|
59
|
+
letter-spacing: -0.05em;
|
|
60
|
+
line-height: 1;
|
|
74
61
|
}
|
|
75
62
|
.group-tabs {
|
|
76
63
|
display: flex;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
justify-content: center;
|
|
64
|
+
margin: 8px 0 0 0;
|
|
65
|
+
justify-content: flex-start;
|
|
80
66
|
}
|
|
81
67
|
.group-tab {
|
|
82
|
-
padding: 10px
|
|
83
|
-
border-radius:
|
|
84
|
-
background:
|
|
68
|
+
padding: 10px 15px;
|
|
69
|
+
border-radius: 8px 8px 0 0;
|
|
70
|
+
background: rgba(46, 164, 223, 0.1);
|
|
85
71
|
cursor: pointer;
|
|
86
|
-
font-size:
|
|
87
|
-
font-weight:
|
|
72
|
+
font-size: 1rem;
|
|
73
|
+
font-weight: 400;
|
|
88
74
|
border: none;
|
|
89
75
|
outline: none;
|
|
90
76
|
transition: background 0.2s;
|
|
91
77
|
}
|
|
92
78
|
.group-tab[selected] {
|
|
93
|
-
background: #
|
|
94
|
-
color: #
|
|
95
|
-
font-weight:
|
|
79
|
+
background: #0c4da2;
|
|
80
|
+
color: #ffffff;
|
|
81
|
+
font-weight: 700;
|
|
82
|
+
box-shadow: 1px 0 0 0 rgba(0, 0, 0, 0.1);
|
|
83
|
+
}
|
|
84
|
+
.tab-icon {
|
|
85
|
+
display: inline-block;
|
|
86
|
+
width: 20px;
|
|
87
|
+
height: 20px;
|
|
88
|
+
border-radius: 2px;
|
|
89
|
+
background: #35618e;
|
|
90
|
+
vertical-align: middle;
|
|
91
|
+
}
|
|
92
|
+
.group-tab[selected] .tab-icon {
|
|
93
|
+
background: #ffffff;
|
|
94
|
+
}
|
|
95
|
+
.tab-label {
|
|
96
|
+
margin-left: 6px;
|
|
97
|
+
vertical-align: middle;
|
|
96
98
|
}
|
|
97
99
|
.kpi-list {
|
|
98
100
|
display: flex;
|
|
@@ -117,59 +119,133 @@ let KpiOverview = class KpiOverview extends PageView {
|
|
|
117
119
|
}
|
|
118
120
|
.main-content {
|
|
119
121
|
display: flex;
|
|
120
|
-
gap:
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
gap: 0;
|
|
123
|
+
align-items: stretch;
|
|
124
|
+
justify-content: stretch;
|
|
125
|
+
background: #fff;
|
|
126
|
+
border: 2px solid #0c4da2;
|
|
127
|
+
overflow: hidden;
|
|
124
128
|
}
|
|
125
129
|
.markdown {
|
|
126
130
|
background: #fff;
|
|
127
|
-
|
|
128
|
-
padding: 40px 32px;
|
|
131
|
+
padding: 25px;
|
|
129
132
|
min-height: 240px;
|
|
130
|
-
flex:
|
|
131
|
-
font-size:
|
|
132
|
-
color: #
|
|
133
|
-
|
|
133
|
+
flex: 1 1 auto;
|
|
134
|
+
font-size: 0.875rem;
|
|
135
|
+
color: #212529;
|
|
136
|
+
}
|
|
137
|
+
.markdown p {
|
|
138
|
+
line-height: 1.7142857142857142;
|
|
139
|
+
margin: 0 0 12px 0;
|
|
134
140
|
}
|
|
135
141
|
.toc {
|
|
136
|
-
flex:
|
|
137
|
-
background:
|
|
138
|
-
border-
|
|
139
|
-
padding:
|
|
140
|
-
font-size:
|
|
141
|
-
color: #
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
flex: 0 0 240px;
|
|
143
|
+
background: linear-gradient(180deg, rgba(137, 204, 237, 0.2) 0%, rgba(137, 204, 237, 0) 100%);
|
|
144
|
+
border-left: 1px solid rgba(46, 164, 223, 0.1);
|
|
145
|
+
padding: 30px 15px;
|
|
146
|
+
font-size: 1rem;
|
|
147
|
+
color: #212529;
|
|
148
|
+
}
|
|
149
|
+
.toc img {
|
|
150
|
+
width: 25px;
|
|
151
|
+
height: 25px;
|
|
152
|
+
}
|
|
153
|
+
.submenu-header {
|
|
154
|
+
display: flex;
|
|
155
|
+
align-items: center;
|
|
156
|
+
gap: 6px;
|
|
157
|
+
margin-bottom: 14px;
|
|
158
|
+
}
|
|
159
|
+
.submenu-icon {
|
|
160
|
+
width: 25.5px;
|
|
161
|
+
height: 28.67px;
|
|
162
|
+
border-radius: 2px;
|
|
163
|
+
background: #02a8a2;
|
|
164
|
+
flex: 0 0 auto;
|
|
165
|
+
}
|
|
166
|
+
.submenu-title {
|
|
167
|
+
font-weight: 700;
|
|
168
|
+
font-size: 1.25rem;
|
|
169
|
+
color: #0c4da2;
|
|
144
170
|
}
|
|
145
171
|
.toc-title {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
font-
|
|
172
|
+
color: #0c4da2;
|
|
173
|
+
font-size: 20px;
|
|
174
|
+
font-weight: 700;
|
|
175
|
+
line-height: 20px;
|
|
176
|
+
margin-bottom: 15px;
|
|
177
|
+
margin-top: 3px;
|
|
149
178
|
}
|
|
150
179
|
.toc-list {
|
|
151
|
-
margin: 0 0
|
|
180
|
+
margin: 0 0 8px 0;
|
|
152
181
|
padding: 0;
|
|
153
182
|
list-style: none;
|
|
154
183
|
}
|
|
155
184
|
.toc-list li {
|
|
156
|
-
margin-bottom:
|
|
185
|
+
margin-bottom: 10px;
|
|
157
186
|
}
|
|
158
187
|
.toc-btn {
|
|
159
188
|
display: block;
|
|
160
|
-
margin:
|
|
161
|
-
padding: 8px
|
|
162
|
-
border:
|
|
163
|
-
border-
|
|
164
|
-
|
|
165
|
-
|
|
189
|
+
margin: 0;
|
|
190
|
+
padding: 8px 0 8px 12px;
|
|
191
|
+
border: none;
|
|
192
|
+
border-left: 3px solid transparent;
|
|
193
|
+
border-radius: 0;
|
|
194
|
+
background: transparent;
|
|
195
|
+
color: #212529;
|
|
166
196
|
cursor: pointer;
|
|
167
197
|
font-size: 1rem;
|
|
168
198
|
text-align: left;
|
|
169
199
|
transition: background 0.2s;
|
|
170
200
|
}
|
|
171
201
|
.toc-btn:hover {
|
|
172
|
-
background:
|
|
202
|
+
background: rgba(0, 0, 0, 0.03);
|
|
203
|
+
}
|
|
204
|
+
.toc-btn[selected] {
|
|
205
|
+
border-left-color: #4cbb49;
|
|
206
|
+
font-weight: 700;
|
|
207
|
+
color: #212529;
|
|
208
|
+
}
|
|
209
|
+
.kpi-title {
|
|
210
|
+
font-size: 1.125rem;
|
|
211
|
+
font-weight: 700;
|
|
212
|
+
margin-bottom: 8px;
|
|
213
|
+
color: #02a8a2;
|
|
214
|
+
}
|
|
215
|
+
.kpi-formula {
|
|
216
|
+
margin: 3px 0 20px 0;
|
|
217
|
+
font-weight: 700;
|
|
218
|
+
color: #212529;
|
|
219
|
+
}
|
|
220
|
+
.subtitle {
|
|
221
|
+
display: inline-flex;
|
|
222
|
+
align-items: center;
|
|
223
|
+
gap: 6px;
|
|
224
|
+
margin-top: 20px;
|
|
225
|
+
font-weight: 700;
|
|
226
|
+
color: #0c4da2;
|
|
227
|
+
}
|
|
228
|
+
.subtitle img {
|
|
229
|
+
width: 15px;
|
|
230
|
+
height: 15px;
|
|
231
|
+
}
|
|
232
|
+
.subtitle-icon {
|
|
233
|
+
width: 20px;
|
|
234
|
+
height: 20px;
|
|
235
|
+
border-radius: 2px;
|
|
236
|
+
background: #02a8a2;
|
|
237
|
+
flex: 0 0 auto;
|
|
238
|
+
}
|
|
239
|
+
.grades-section {
|
|
240
|
+
margin-top: 16px;
|
|
241
|
+
background: #fff;
|
|
242
|
+
border-radius: 8px;
|
|
243
|
+
padding: 16px;
|
|
244
|
+
border: 2px solid #0c4da2;
|
|
245
|
+
}
|
|
246
|
+
.grades-section b {
|
|
247
|
+
display: block;
|
|
248
|
+
margin-bottom: 8px;
|
|
173
249
|
}
|
|
174
250
|
`; }
|
|
175
251
|
get context() {
|
|
@@ -193,25 +269,18 @@ let KpiOverview = class KpiOverview extends PageView {
|
|
|
193
269
|
return html `<div>에러: ${this.error?.message}</div>`;
|
|
194
270
|
if (!this.kpiCategories.length)
|
|
195
271
|
return html `<div>KPI 카테고리가 없습니다.</div>`;
|
|
272
|
+
const selctedY = this.kpiCategories?.[this.selectedGroup] || '';
|
|
196
273
|
const group = this.kpiCategories[this.selectedGroup];
|
|
197
274
|
const kpi = group?.kpis?.[this.selectedKpi];
|
|
198
|
-
const md = kpi?.description || '각 지표의 주요 소개 내용을 마크다운으로 입력하세요.';
|
|
199
275
|
return html `
|
|
200
276
|
<div class="overview-container">
|
|
201
277
|
<div class="overview-left">
|
|
202
278
|
<div class="overview-title">KPI개요</div>
|
|
203
279
|
<div class="overview-desc">
|
|
204
|
-
건설현장 KPI
|
|
205
|
-
|
|
280
|
+
건설현장 KPI관리 시스템은 프로젝트 성과를 측정하고, 모니터링하여 효율적인 공정 관리를 지원합니다. 주요
|
|
281
|
+
지표를 통해 현장 생산성, 품질, 안전 등을 실시간으로 파악할 수 있습니다.
|
|
206
282
|
</div>
|
|
207
283
|
</div>
|
|
208
|
-
<div class="overview-right">
|
|
209
|
-
<img
|
|
210
|
-
class="overview-img"
|
|
211
|
-
src="https://images.unsplash.com/photo-1464983953574-0892a716854b?auto=format&fit=crop&w=600&q=80"
|
|
212
|
-
alt="건설현장 안전"
|
|
213
|
-
/>
|
|
214
|
-
</div>
|
|
215
284
|
</div>
|
|
216
285
|
<div class="group-tabs">
|
|
217
286
|
${this.kpiCategories.map((g, i) => html `
|
|
@@ -229,27 +298,39 @@ let KpiOverview = class KpiOverview extends PageView {
|
|
|
229
298
|
</div>
|
|
230
299
|
<div class="main-content">
|
|
231
300
|
<div class="markdown">
|
|
232
|
-
<div
|
|
233
|
-
<div
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
<
|
|
238
|
-
|
|
239
|
-
${kpi.grades.map((g) => html `<li>${g.name}: ${g.minValue}~${g.maxValue} (${g.description || ''})</li>`)}
|
|
240
|
-
</ul>
|
|
241
|
-
</div>`
|
|
301
|
+
<div class="kpi-title">${kpi?.name || ''}</div>
|
|
302
|
+
<div>${kpi?.description || ''}</div>
|
|
303
|
+
${kpi?.formula
|
|
304
|
+
? html `
|
|
305
|
+
<div class="subtitle"><img src="/assets/images/green-calendar.svg" />주요산식</div>
|
|
306
|
+
<div class="kpi-formula">${kpi?.formula}</div>
|
|
307
|
+
`
|
|
242
308
|
: ''}
|
|
243
309
|
</div>
|
|
244
310
|
<div class="toc">
|
|
245
|
-
<
|
|
311
|
+
<img src="/assets/images/green-calendar.svg" />
|
|
312
|
+
<div class="toc-title">${selctedY.name} 지표</div>
|
|
246
313
|
<ul class="toc-list">
|
|
247
314
|
${group?.kpis?.map((k, i) => html `
|
|
248
|
-
<li
|
|
315
|
+
<li>
|
|
316
|
+
<button class="toc-btn" ?selected=${i === this.selectedKpi} @click=${() => (this.selectedKpi = i)}>
|
|
317
|
+
${k.name}
|
|
318
|
+
</button>
|
|
319
|
+
</li>
|
|
249
320
|
`)}
|
|
250
321
|
</ul>
|
|
251
322
|
</div>
|
|
252
323
|
</div>
|
|
324
|
+
${kpi?.grades && Array.isArray(kpi.grades) && kpi.grades.length > 0
|
|
325
|
+
? html `
|
|
326
|
+
<div class="grades-section">
|
|
327
|
+
<b>등급 구간</b>
|
|
328
|
+
<ul>
|
|
329
|
+
${kpi.grades.map((g) => html `<li>${g.name}: ${g.minValue}~${g.maxValue} (${g.description || ''})</li>`)}
|
|
330
|
+
</ul>
|
|
331
|
+
</div>
|
|
332
|
+
`
|
|
333
|
+
: ''}
|
|
253
334
|
`;
|
|
254
335
|
}
|
|
255
336
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kpi-overview.js","sourceRoot":"","sources":["../../../client/pages/kpi/kpi-overview.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAc,MAAM,KAAK,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAE,QAAQ,EAAS,MAAM,gBAAgB,CAAA;AAChD,OAAO,EAAE,OAAO,EAAY,MAAM,eAAe,CAAA;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,GAAG,MAAM,aAAa,CAAA;AAE7B,MAAM,gBAAgB,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;CAiB3B,CAAA;AAGM,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,QAAQ;IAAlC;;QAmJI,kBAAa,GAAG,CAAC,CAAA;QACjB,gBAAW,GAAG,CAAC,CAAA;QACf,kBAAa,GAAU,EAAE,CAAA;QACzB,YAAO,GAAG,IAAI,CAAA;QACd,UAAK,GAAiB,IAAI,CAAA;IAmFrC,CAAC;aAzOQ,WAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0IlB,AA1IY,CA0IZ;IAED,IAAI,OAAO;QACT,OAAO;YACL,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC;SACvC,CAAA;IACH,CAAC;IAQD,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC;YACH,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,CAAA;YAChE,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAA;YACvC,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA;QACtB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,KAAK,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;YAC1D,IAAI,CAAC,OAAO,GAAG,KAAK,CAAA;QACtB,CAAC;IACH,CAAC;IAED,MAAM;QACJ,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAA,YAAY,IAAI,CAAC,KAAK,EAAE,OAAO,QAAQ,CAAA;QAClE,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM;YAAE,OAAO,IAAI,CAAA,4BAA4B,CAAA;QAEvE,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,aAAa,CAAQ,CAAA;QAC3D,MAAM,GAAG,GAAG,KAAK,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,WAAW,CAAQ,CAAA;QAClD,MAAM,EAAE,GAAG,GAAG,EAAE,WAAW,IAAI,+BAA+B,CAAA;QAE9D,OAAO,IAAI,CAAA;;;;;;;;;;;;;;;;;;UAkBL,IAAI,CAAC,aAAa,CAAC,GAAG,CACtB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAA;;;0BAGE,CAAC,KAAK,IAAI,CAAC,aAAa;uBAC3B,GAAG,EAAE;YACZ,IAAI,CAAC,aAAa,GAAG,CAAC,CAAA;YACtB,IAAI,CAAC,WAAW,GAAG,CAAC,CAAA;QACtB,CAAC;;gBAEC,CAAC,CAAC,IAAI;;WAEX,CACF;;;;+EAIsE,GAAG,EAAE,IAAI,IAAI,EAAE;6CACjD,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAA,cAAc,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE;4BACpE,MAAM,CAAC,EAAE,CAAC;YAC1B,GAAG,EAAE,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;YACjE,CAAC,CAAC,IAAI,CAAA;;;oBAGE,GAAG,CAAC,MAAM,CAAC,GAAG,CACd,CAAC,CAAM,EAAE,EAAE,CAAC,IAAI,CAAA,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,WAAW,IAAI,EAAE,QAAQ,CAC3F;;qBAEE;YACT,CAAC,CAAC,EAAE;;;;;cAKF,KAAK,EAAE,IAAI,EAAE,GAAG,CAChB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAA;qDACyB,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI;eAC5E,CACF;;;;KAIR,CAAA;IACH,CAAC;;AAtFQ;IAAR,KAAK,EAAE;;kDAAkB;AACjB;IAAR,KAAK,EAAE;;gDAAgB;AACf;IAAR,KAAK,EAAE;;kDAA0B;AACzB;IAAR,KAAK,EAAE;;4CAAe;AACd;IAAR,KAAK,EAAE;;0CAA2B;AAvJxB,WAAW;IADvB,aAAa,CAAC,cAAc,CAAC;GACjB,WAAW,CA0OvB","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: kpisLevel1 {\n id\n name\n description\n active\n kpis: children {\n id\n name\n description\n formula\n active\n grades\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\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 && Array.isArray(kpi.grades) && kpi.grades.length > 0\n ? html`<div style=\"margin-top:32px;\">\n <b>등급 구간</b>\n <ul>\n ${kpi.grades.map(\n (g: any) => html`<li>${g.name}: ${g.minValue}~${g.maxValue} (${g.description || ''})</li>`\n )}\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"]}
|
|
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 } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\nimport { PageView } from '@operato/shell'\nimport { i18next } from '@operato/i18n'\nimport { client } from '@operato/graphql'\nimport gql from 'graphql-tag'\n\nconst GET_KPI_OVERVIEW = gql`\n query {\n kpiCategories: kpisLevel1 {\n id\n name\n description\n active\n kpis: children {\n id\n name\n description\n formula\n active\n grades\n }\n }\n }\n`\n\n@customElement('kpi-overview')\nexport class KpiOverview extends PageView {\n static styles = css`\n :host {\n display: block;\n background: #f6f6f6;\n box-sizing: border-box;\n padding: 16px 24px;\n }\n .overview-container {\n display: block;\n margin: 8px 0 24px 0;\n }\n .overview-left {\n display: block;\n }\n .overview-title {\n color: #0c4da2;\n font-size: 1.125rem;\n font-weight: 700;\n letter-spacing: -0.05em;\n margin: 0 0 8px 0;\n }\n .overview-desc {\n font-size: 0.875rem;\n color: #212529;\n letter-spacing: -0.05em;\n line-height: 1;\n }\n .group-tabs {\n display: flex;\n margin: 8px 0 0 0;\n justify-content: flex-start;\n }\n .group-tab {\n padding: 10px 15px;\n border-radius: 8px 8px 0 0;\n background: rgba(46, 164, 223, 0.1);\n cursor: pointer;\n font-size: 1rem;\n font-weight: 400;\n border: none;\n outline: none;\n transition: background 0.2s;\n }\n .group-tab[selected] {\n background: #0c4da2;\n color: #ffffff;\n font-weight: 700;\n box-shadow: 1px 0 0 0 rgba(0, 0, 0, 0.1);\n }\n .tab-icon {\n display: inline-block;\n width: 20px;\n height: 20px;\n border-radius: 2px;\n background: #35618e;\n vertical-align: middle;\n }\n .group-tab[selected] .tab-icon {\n background: #ffffff;\n }\n .tab-label {\n margin-left: 6px;\n vertical-align: middle;\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: 0;\n align-items: stretch;\n justify-content: stretch;\n background: #fff;\n border: 2px solid #0c4da2;\n overflow: hidden;\n }\n .markdown {\n background: #fff;\n padding: 25px;\n min-height: 240px;\n flex: 1 1 auto;\n font-size: 0.875rem;\n color: #212529;\n }\n .markdown p {\n line-height: 1.7142857142857142;\n margin: 0 0 12px 0;\n }\n .toc {\n flex: 0 0 240px;\n background: linear-gradient(180deg, rgba(137, 204, 237, 0.2) 0%, rgba(137, 204, 237, 0) 100%);\n border-left: 1px solid rgba(46, 164, 223, 0.1);\n padding: 30px 15px;\n font-size: 1rem;\n color: #212529;\n }\n .toc img {\n width: 25px;\n height: 25px;\n }\n .submenu-header {\n display: flex;\n align-items: center;\n gap: 6px;\n margin-bottom: 14px;\n }\n .submenu-icon {\n width: 25.5px;\n height: 28.67px;\n border-radius: 2px;\n background: #02a8a2;\n flex: 0 0 auto;\n }\n .submenu-title {\n font-weight: 700;\n font-size: 1.25rem;\n color: #0c4da2;\n }\n .toc-title {\n color: #0c4da2;\n font-size: 20px;\n font-weight: 700;\n line-height: 20px;\n margin-bottom: 15px;\n margin-top: 3px;\n }\n .toc-list {\n margin: 0 0 8px 0;\n padding: 0;\n list-style: none;\n }\n .toc-list li {\n margin-bottom: 10px;\n }\n .toc-btn {\n display: block;\n margin: 0;\n padding: 8px 0 8px 12px;\n border: none;\n border-left: 3px solid transparent;\n border-radius: 0;\n background: transparent;\n color: #212529;\n cursor: pointer;\n font-size: 1rem;\n text-align: left;\n transition: background 0.2s;\n }\n .toc-btn:hover {\n background: rgba(0, 0, 0, 0.03);\n }\n .toc-btn[selected] {\n border-left-color: #4cbb49;\n font-weight: 700;\n color: #212529;\n }\n .kpi-title {\n font-size: 1.125rem;\n font-weight: 700;\n margin-bottom: 8px;\n color: #02a8a2;\n }\n .kpi-formula {\n margin: 3px 0 20px 0;\n font-weight: 700;\n color: #212529;\n }\n .subtitle {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n margin-top: 20px;\n font-weight: 700;\n color: #0c4da2;\n }\n .subtitle img {\n width: 15px;\n height: 15px;\n }\n .subtitle-icon {\n width: 20px;\n height: 20px;\n border-radius: 2px;\n background: #02a8a2;\n flex: 0 0 auto;\n }\n .grades-section {\n margin-top: 16px;\n background: #fff;\n border-radius: 8px;\n padding: 16px;\n border: 2px solid #0c4da2;\n }\n .grades-section b {\n display: block;\n margin-bottom: 8px;\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\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 selctedY = this.kpiCategories?.[this.selectedGroup] || ''\n const group = this.kpiCategories[this.selectedGroup] as any\n const kpi = group?.kpis?.[this.selectedKpi] as any\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관리 시스템은 프로젝트 성과를 측정하고, 모니터링하여 효율적인 공정 관리를 지원합니다. 주요\n 지표를 통해 현장 생산성, 품질, 안전 등을 실시간으로 파악할 수 있습니다.\n </div>\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 class=\"kpi-title\">${kpi?.name || ''}</div>\n <div>${kpi?.description || ''}</div>\n ${kpi?.formula\n ? html`\n <div class=\"subtitle\"><img src=\"/assets/images/green-calendar.svg\" />주요산식</div>\n <div class=\"kpi-formula\">${kpi?.formula}</div>\n `\n : ''}\n </div>\n <div class=\"toc\">\n <img src=\"/assets/images/green-calendar.svg\" />\n <div class=\"toc-title\">${selctedY.name} 지표</div>\n <ul class=\"toc-list\">\n ${group?.kpis?.map(\n (k, i) => html`\n <li>\n <button class=\"toc-btn\" ?selected=${i === this.selectedKpi} @click=${() => (this.selectedKpi = i)}>\n ${k.name}\n </button>\n </li>\n `\n )}\n </ul>\n </div>\n </div>\n ${kpi?.grades && Array.isArray(kpi.grades) && kpi.grades.length > 0\n ? html`\n <div class=\"grades-section\">\n <b>등급 구간</b>\n <ul>\n ${kpi.grades.map(\n (g: any) => html`<li>${g.name}: ${g.minValue}~${g.maxValue} (${g.description || ''})</li>`\n )}\n </ul>\n </div>\n `\n : ''}\n `\n }\n}\n"]}
|