@things-factory/kpi 9.0.41 → 9.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ <svg width="26" height="29" viewBox="0 0 26 29" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M11.175 23.3996L6.36938 18.594L7.99613 16.9673L11.175 20.1461L17.5039 13.8173L19.1306 15.444L11.175 23.3996ZM2.71163 28.6729C1.95387 28.6729 1.3125 28.4104 0.7875 27.8854C0.2625 27.3604 0 26.719 0 25.9613V5.8845C0 5.12675 0.2625 4.48537 0.7875 3.96037C1.3125 3.43537 1.95387 3.17287 2.71163 3.17287H4.78838V0H7.09613V3.17287H18.4616V0H20.7116V3.17287H22.7884C23.5461 3.17287 24.1875 3.43537 24.7125 3.96037C25.2375 4.48537 25.5 5.12675 25.5 5.8845V25.9613C25.5 26.719 25.2375 27.3604 24.7125 27.8854C24.1875 28.4104 23.5461 28.6729 22.7884 28.6729H2.71163ZM2.71163 26.4229H22.7884C22.9039 26.4229 23.0096 26.3748 23.1056 26.2785C23.2019 26.1825 23.25 26.0767 23.25 25.9613V11.8845H2.25V25.9613C2.25 26.0767 2.29813 26.1825 2.39438 26.2785C2.49038 26.3748 2.59613 26.4229 2.71163 26.4229ZM2.25 9.6345H23.25V5.8845C23.25 5.769 23.2019 5.66325 23.1056 5.56725C23.0096 5.471 22.9039 5.42287 22.7884 5.42287H2.71163C2.59613 5.42287 2.49038 5.471 2.39438 5.56725C2.29813 5.66325 2.25 5.769 2.25 5.8845V9.6345Z" fill="#02A8A2"/>
3
+ </svg>
@@ -1,8 +1,7 @@
1
- import { html, css, LitElement } from 'lit'
1
+ import { html, css } from 'lit'
2
2
  import { customElement, state } from 'lit/decorators.js'
3
- import { marked } from 'marked'
4
- import { PageView, store } from '@operato/shell'
5
- import { i18next, localize } from '@operato/i18n'
3
+ import { PageView } from '@operato/shell'
4
+ import { i18next } from '@operato/i18n'
6
5
  import { client } from '@operato/graphql'
7
6
  import gql from 'graphql-tag'
8
7
 
@@ -28,65 +27,68 @@ const GET_KPI_OVERVIEW = gql`
28
27
  @customElement('kpi-overview')
29
28
  export class KpiOverview extends PageView {
30
29
  static styles = css`
30
+ :host {
31
+ display: block;
32
+ background: #f6f6f6;
33
+ box-sizing: border-box;
34
+ padding: 16px 24px;
35
+ }
31
36
  .overview-container {
32
- display: flex;
33
- gap: 32px;
34
- background: #f7f5fa;
35
- border-radius: 20px;
36
- padding: 32px;
37
- margin-bottom: 24px;
38
- align-items: stretch;
37
+ display: block;
38
+ margin: 8px 0 24px 0;
39
39
  }
40
40
  .overview-left {
41
- flex: 1;
42
- display: flex;
43
- flex-direction: column;
44
- justify-content: center;
41
+ display: block;
45
42
  }
46
43
  .overview-title {
47
- font-size: 2.8rem;
48
- font-weight: bold;
49
- margin-bottom: 24px;
44
+ color: #0c4da2;
45
+ font-size: 1.125rem;
46
+ font-weight: 700;
47
+ letter-spacing: -0.05em;
48
+ margin: 0 0 8px 0;
50
49
  }
51
50
  .overview-desc {
52
- font-size: 1.2rem;
53
- color: #222;
54
- line-height: 1.6;
55
- }
56
- .overview-right {
57
- flex: 1;
58
- display: flex;
59
- align-items: center;
60
- justify-content: center;
61
- }
62
- .overview-img {
63
- width: 100%;
64
- max-width: 420px;
65
- border-radius: 12px;
66
- object-fit: cover;
67
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
51
+ font-size: 0.875rem;
52
+ color: #212529;
53
+ letter-spacing: -0.05em;
54
+ line-height: 1;
68
55
  }
69
56
  .group-tabs {
70
57
  display: flex;
71
- gap: 8px;
72
- margin: 0 0 16px 0;
73
- justify-content: center;
58
+ margin: 8px 0 0 0;
59
+ justify-content: flex-start;
74
60
  }
75
61
  .group-tab {
76
- padding: 10px 28px;
77
- border-radius: 16px 16px 0 0;
78
- background: #eee;
62
+ padding: 10px 15px;
63
+ border-radius: 8px 8px 0 0;
64
+ background: rgba(46, 164, 223, 0.1);
79
65
  cursor: pointer;
80
- font-size: 1.1rem;
81
- font-weight: 500;
66
+ font-size: 1rem;
67
+ font-weight: 400;
82
68
  border: none;
83
69
  outline: none;
84
70
  transition: background 0.2s;
85
71
  }
86
72
  .group-tab[selected] {
87
- background: #d6d6f7;
88
- color: #222;
89
- font-weight: bold;
73
+ background: #0c4da2;
74
+ color: #ffffff;
75
+ font-weight: 700;
76
+ box-shadow: 1px 0 0 0 rgba(0, 0, 0, 0.1);
77
+ }
78
+ .tab-icon {
79
+ display: inline-block;
80
+ width: 20px;
81
+ height: 20px;
82
+ border-radius: 2px;
83
+ background: #35618e;
84
+ vertical-align: middle;
85
+ }
86
+ .group-tab[selected] .tab-icon {
87
+ background: #ffffff;
88
+ }
89
+ .tab-label {
90
+ margin-left: 6px;
91
+ vertical-align: middle;
90
92
  }
91
93
  .kpi-list {
92
94
  display: flex;
@@ -111,59 +113,133 @@ export class KpiOverview extends PageView {
111
113
  }
112
114
  .main-content {
113
115
  display: flex;
114
- gap: 32px;
115
- margin-top: 32px;
116
- align-items: flex-start;
117
- justify-content: center;
116
+ gap: 0;
117
+ align-items: stretch;
118
+ justify-content: stretch;
119
+ background: #fff;
120
+ border: 2px solid #0c4da2;
121
+ overflow: hidden;
118
122
  }
119
123
  .markdown {
120
124
  background: #fff;
121
- border-radius: 12px;
122
- padding: 40px 32px;
125
+ padding: 25px;
123
126
  min-height: 240px;
124
- flex: 2;
125
- font-size: 2rem;
126
- color: #222;
127
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
127
+ flex: 1 1 auto;
128
+ font-size: 0.875rem;
129
+ color: #212529;
130
+ }
131
+ .markdown p {
132
+ line-height: 1.7142857142857142;
133
+ margin: 0 0 12px 0;
128
134
  }
129
135
  .toc {
130
- flex: 1;
131
- background: #faf9fd;
132
- border-radius: 12px;
133
- padding: 32px 24px;
134
- font-size: 1.1rem;
135
- color: #444;
136
- min-width: 220px;
137
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
136
+ flex: 0 0 240px;
137
+ background: linear-gradient(180deg, rgba(137, 204, 237, 0.2) 0%, rgba(137, 204, 237, 0) 100%);
138
+ border-left: 1px solid rgba(46, 164, 223, 0.1);
139
+ padding: 30px 15px;
140
+ font-size: 1rem;
141
+ color: #212529;
142
+ }
143
+ .toc img {
144
+ width: 25px;
145
+ height: 25px;
146
+ }
147
+ .submenu-header {
148
+ display: flex;
149
+ align-items: center;
150
+ gap: 6px;
151
+ margin-bottom: 14px;
152
+ }
153
+ .submenu-icon {
154
+ width: 25.5px;
155
+ height: 28.67px;
156
+ border-radius: 2px;
157
+ background: #02a8a2;
158
+ flex: 0 0 auto;
159
+ }
160
+ .submenu-title {
161
+ font-weight: 700;
162
+ font-size: 1.25rem;
163
+ color: #0c4da2;
138
164
  }
139
165
  .toc-title {
140
- font-weight: bold;
141
- margin-bottom: 12px;
142
- font-size: 1.2rem;
166
+ color: #0c4da2;
167
+ font-size: 20px;
168
+ font-weight: 700;
169
+ line-height: 20px;
170
+ margin-bottom: 15px;
171
+ margin-top: 3px;
143
172
  }
144
173
  .toc-list {
145
- margin: 0 0 16px 0;
174
+ margin: 0 0 8px 0;
146
175
  padding: 0;
147
176
  list-style: none;
148
177
  }
149
178
  .toc-list li {
150
- margin-bottom: 6px;
179
+ margin-bottom: 10px;
151
180
  }
152
181
  .toc-btn {
153
182
  display: block;
154
- margin: 12px 0;
155
- padding: 8px 16px;
156
- border: 1px solid #aaa;
157
- border-radius: 8px;
158
- background: #fff;
159
- color: #333;
183
+ margin: 0;
184
+ padding: 8px 0 8px 12px;
185
+ border: none;
186
+ border-left: 3px solid transparent;
187
+ border-radius: 0;
188
+ background: transparent;
189
+ color: #212529;
160
190
  cursor: pointer;
161
191
  font-size: 1rem;
162
192
  text-align: left;
163
193
  transition: background 0.2s;
164
194
  }
165
195
  .toc-btn:hover {
166
- background: #f0f0f0;
196
+ background: rgba(0, 0, 0, 0.03);
197
+ }
198
+ .toc-btn[selected] {
199
+ border-left-color: #4cbb49;
200
+ font-weight: 700;
201
+ color: #212529;
202
+ }
203
+ .kpi-title {
204
+ font-size: 1.125rem;
205
+ font-weight: 700;
206
+ margin-bottom: 8px;
207
+ color: #02a8a2;
208
+ }
209
+ .kpi-formula {
210
+ margin: 3px 0 20px 0;
211
+ font-weight: 700;
212
+ color: #212529;
213
+ }
214
+ .subtitle {
215
+ display: inline-flex;
216
+ align-items: center;
217
+ gap: 6px;
218
+ margin-top: 20px;
219
+ font-weight: 700;
220
+ color: #0c4da2;
221
+ }
222
+ .subtitle img {
223
+ width: 15px;
224
+ height: 15px;
225
+ }
226
+ .subtitle-icon {
227
+ width: 20px;
228
+ height: 20px;
229
+ border-radius: 2px;
230
+ background: #02a8a2;
231
+ flex: 0 0 auto;
232
+ }
233
+ .grades-section {
234
+ margin-top: 16px;
235
+ background: #fff;
236
+ border-radius: 8px;
237
+ padding: 16px;
238
+ border: 2px solid #0c4da2;
239
+ }
240
+ .grades-section b {
241
+ display: block;
242
+ margin-bottom: 8px;
167
243
  }
168
244
  `
169
245
 
@@ -194,26 +270,19 @@ export class KpiOverview extends PageView {
194
270
  if (this.error) return html`<div>에러: ${this.error?.message}</div>`
195
271
  if (!this.kpiCategories.length) return html`<div>KPI 카테고리가 없습니다.</div>`
196
272
 
273
+ const selctedY = this.kpiCategories?.[this.selectedGroup] || ''
197
274
  const group = this.kpiCategories[this.selectedGroup] as any
198
275
  const kpi = group?.kpis?.[this.selectedKpi] as any
199
- const md = kpi?.description || '각 지표의 주요 소개 내용을 마크다운으로 입력하세요.'
200
276
 
201
277
  return html`
202
278
  <div class="overview-container">
203
279
  <div class="overview-left">
204
280
  <div class="overview-title">KPI개요</div>
205
281
  <div class="overview-desc">
206
- 건설현장 KPI 관리 시스템은 프로젝트 성과를 측정하고 모니터링하여 효율적인 공정 관리를 지원합니다.<br />
207
- 주요 지표를 통해 현장 생산성, 품질, 안전 등을 실시간으로 파악할 수 있습니다.
282
+ 건설현장 KPI관리 시스템은 프로젝트 성과를 측정하고, 모니터링하여 효율적인 공정 관리를 지원합니다. 주요
283
+ 지표를 통해 현장 생산성, 품질, 안전 등을 실시간으로 파악할 수 있습니다.
208
284
  </div>
209
285
  </div>
210
- <div class="overview-right">
211
- <img
212
- class="overview-img"
213
- src="https://images.unsplash.com/photo-1464983953574-0892a716854b?auto=format&fit=crop&w=600&q=80"
214
- alt="건설현장 안전"
215
- />
216
- </div>
217
286
  </div>
218
287
  <div class="group-tabs">
219
288
  ${this.kpiCategories.map(
@@ -233,31 +302,43 @@ export class KpiOverview extends PageView {
233
302
  </div>
234
303
  <div class="main-content">
235
304
  <div class="markdown">
236
- <div style="font-size:1.5rem;font-weight:bold;margin-bottom:16px;">${kpi?.name || ''}</div>
237
- <div style="margin-bottom:16px;">${kpi?.formula ? html`<b>산식:</b> ${kpi.formula}` : ''}</div>
238
- <div .innerHTML=${marked(md)}></div>
239
- ${kpi?.grades && Array.isArray(kpi.grades) && kpi.grades.length > 0
240
- ? html`<div style="margin-top:32px;">
241
- <b>등급 구간</b>
242
- <ul>
243
- ${kpi.grades.map(
244
- (g: any) => html`<li>${g.name}: ${g.minValue}~${g.maxValue} (${g.description || ''})</li>`
245
- )}
246
- </ul>
247
- </div>`
305
+ <div class="kpi-title">${kpi?.name || ''}</div>
306
+ <div>${kpi?.description || ''}</div>
307
+ ${kpi?.formula
308
+ ? html`
309
+ <div class="subtitle"><img src="/assets/images/green-calendar.svg" />주요산식</div>
310
+ <div class="kpi-formula">${kpi?.formula}</div>
311
+ `
248
312
  : ''}
249
313
  </div>
250
314
  <div class="toc">
251
- <div class="toc-title">목차</div>
315
+ <img src="/assets/images/green-calendar.svg" />
316
+ <div class="toc-title">${selctedY.name} 지표</div>
252
317
  <ul class="toc-list">
253
318
  ${group?.kpis?.map(
254
319
  (k, i) => html`
255
- <li><button class="toc-btn" @click=${() => (this.selectedKpi = i)}>${k.name}</button></li>
320
+ <li>
321
+ <button class="toc-btn" ?selected=${i === this.selectedKpi} @click=${() => (this.selectedKpi = i)}>
322
+ ${k.name}
323
+ </button>
324
+ </li>
256
325
  `
257
326
  )}
258
327
  </ul>
259
328
  </div>
260
329
  </div>
330
+ ${kpi?.grades && Array.isArray(kpi.grades) && kpi.grades.length > 0
331
+ ? html`
332
+ <div class="grades-section">
333
+ <b>등급 구간</b>
334
+ <ul>
335
+ ${kpi.grades.map(
336
+ (g: any) => html`<li>${g.name}: ${g.minValue}~${g.maxValue} (${g.description || ''})</li>`
337
+ )}
338
+ </ul>
339
+ </div>
340
+ `
341
+ : ''}
261
342
  `
262
343
  }
263
344
  }