@dssp/dkpi 1.0.0-alpha.87 → 1.0.0-alpha.89

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 (70) hide show
  1. package/_index.html +4 -4
  2. package/assets/helps/index.md +1 -1
  3. package/assets/manifest.json +2 -2
  4. package/dist-client/bootstrap.js +1 -1
  5. package/dist-client/bootstrap.js.map +1 -1
  6. package/dist-client/components/kpi-boxplot-chart.d.ts +7 -0
  7. package/dist-client/components/kpi-boxplot-chart.js +20 -5
  8. package/dist-client/components/kpi-boxplot-chart.js.map +1 -1
  9. package/dist-client/components/kpi-lookup-chart.js +1 -17
  10. package/dist-client/components/kpi-lookup-chart.js.map +1 -1
  11. package/dist-client/components/kpi-mini-trend-chart.d.ts +1 -1
  12. package/dist-client/components/kpi-mini-trend-chart.js +45 -13
  13. package/dist-client/components/kpi-mini-trend-chart.js.map +1 -1
  14. package/dist-client/components/kpi-radar-chart.js +2 -2
  15. package/dist-client/components/kpi-radar-chart.js.map +1 -1
  16. package/dist-client/components/kpi-single-boxplot-chart.d.ts +11 -0
  17. package/dist-client/components/kpi-single-boxplot-chart.js +45 -26
  18. package/dist-client/components/kpi-single-boxplot-chart.js.map +1 -1
  19. package/dist-client/components/kpi-step-lookup-chart.d.ts +33 -0
  20. package/dist-client/components/kpi-step-lookup-chart.js +181 -0
  21. package/dist-client/components/kpi-step-lookup-chart.js.map +1 -0
  22. package/dist-client/components/kpi-trend-chart.js +41 -20
  23. package/dist-client/components/kpi-trend-chart.js.map +1 -1
  24. package/dist-client/google-map/common-google-map.js +5 -1
  25. package/dist-client/google-map/common-google-map.js.map +1 -1
  26. package/dist-client/pages/kpi-admin/dssp-kpi-overview.d.ts +2 -1
  27. package/dist-client/pages/kpi-admin/dssp-kpi-overview.js +24 -9
  28. package/dist-client/pages/kpi-admin/dssp-kpi-overview.js.map +1 -1
  29. package/dist-client/pages/kpi-admin/kpi-system-guide.js +311 -158
  30. package/dist-client/pages/kpi-admin/kpi-system-guide.js.map +1 -1
  31. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.d.ts +8 -0
  32. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js +142 -56
  33. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js.map +1 -1
  34. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.d.ts +0 -9
  35. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js +6 -91
  36. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js.map +1 -1
  37. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.d.ts +2 -0
  38. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js +162 -69
  39. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js.map +1 -1
  40. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js +85 -41
  41. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js.map +1 -1
  42. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js +15 -7
  43. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js.map +1 -1
  44. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js +16 -25
  45. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js.map +1 -1
  46. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js +9 -13
  47. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js.map +1 -1
  48. package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.js +9 -15
  49. package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.js.map +1 -1
  50. package/dist-client/pages/sv-project-complete.js +7 -11
  51. package/dist-client/pages/sv-project-complete.js.map +1 -1
  52. package/dist-client/pages/sv-project-completed-list.js +4 -4
  53. package/dist-client/pages/sv-project-completed-list.js.map +1 -1
  54. package/dist-client/pages/sv-project-detail.d.ts +1 -0
  55. package/dist-client/pages/sv-project-detail.js +73 -55
  56. package/dist-client/pages/sv-project-detail.js.map +1 -1
  57. package/dist-client/pages/sv-project-list.js +15 -12
  58. package/dist-client/pages/sv-project-list.js.map +1 -1
  59. package/dist-client/tsconfig.tsbuildinfo +1 -1
  60. package/dist-client/viewparts/menu-tools.js +17 -3
  61. package/dist-client/viewparts/menu-tools.js.map +1 -1
  62. package/dist-server/service/kpi-stat/kpi-stat-query.js +20 -19
  63. package/dist-server/service/kpi-stat/kpi-stat-query.js.map +1 -1
  64. package/dist-server/tsconfig.tsbuildinfo +1 -1
  65. package/openapi/unstable.yaml +2 -2
  66. package/package.json +3 -3
  67. package/schema.graphql +20 -0
  68. package/translations/ko.json +2 -2
  69. package/views/auth-page.html +4 -4
  70. package/views/public/home.html +5 -5
@@ -58,7 +58,7 @@ const EXTERNAL_SYSTEM_URLS = {
58
58
  '세움터(EAIS)': 'https://cloud.eais.go.kr',
59
59
  '키스콘(KISCON)': 'https://www.kiscon.net',
60
60
  '올바로(Allbaro)': 'https://www.allbaro.or.kr',
61
- '전자카드제': 'https://www.cw.or.kr'
61
+ 전자카드제: 'https://www.cw.or.kr'
62
62
  };
63
63
  const VALUE_TYPE_LABELS = {
64
64
  MEASURED: { label: '외부 수집', color: '#1976d2', icon: '📡' },
@@ -98,7 +98,7 @@ let KpiSystemGuide = class KpiSystemGuide extends PageView {
98
98
  for (const y of this.kpiRoot) {
99
99
  if (y.active === false)
100
100
  continue;
101
- for (const x of (y.kpis || [])) {
101
+ for (const x of y.kpis || []) {
102
102
  if (x.active === false)
103
103
  continue;
104
104
  if ((_a = x.formula) === null || _a === void 0 ? void 0 : _a.includes(`[${metricName}]`)) {
@@ -122,8 +122,7 @@ let KpiSystemGuide = class KpiSystemGuide extends PageView {
122
122
  return html `
123
123
  <div class="page-title">KPI 시스템 가이드</div>
124
124
  <div class="page-subtitle">
125
- 건축현장 성과평가 KPI 체계의 전체 구조, 산식, 메트릭 연관관계를 확인합니다.
126
- 모든 정보는 DB에서 실시간 조회됩니다.
125
+ 건축프로젝트 성과평가 KPI 체계의 전체 구조, 산식, 메트릭 연관관계를 확인합니다. 모든 정보는 DB에서 실시간 조회됩니다.
127
126
  </div>
128
127
 
129
128
  <!-- 범례 -->
@@ -140,44 +139,58 @@ let KpiSystemGuide = class KpiSystemGuide extends PageView {
140
139
  <div class="section-title">📊 KPI 계층 구조 (Z → Y → X)</div>
141
140
 
142
141
  <!-- Z 루트 -->
143
- <div class="z-node" @click=${() => this.showDetail({ name: 'Z. 전체스코어', description: 'Y1~Y6 가중합', formula: 'Y1×w1 + Y2×w2 + ... + Y6×w6', scoreType: 'DIRECT', valueType: 'CALCULATED' }, 'kpi')}>
142
+ <div
143
+ class="z-node"
144
+ @click=${() => this.showDetail({
145
+ name: 'Z. 전체스코어',
146
+ description: 'Y1~Y6 가중합',
147
+ formula: 'Y1×w1 + Y2×w2 + ... + Y6×w6',
148
+ scoreType: 'DIRECT',
149
+ valueType: 'CALCULATED'
150
+ }, 'kpi')}
151
+ >
144
152
  <div class="z-name">Z. 전체스코어</div>
145
- <div class="z-formula">= ${this.kpiRoot
153
+ <div class="z-formula">
154
+ =
155
+ ${this.kpiRoot
146
156
  .filter((y) => y.active !== false)
147
157
  .map((y) => `${y.name.split('.')[0]}×${y.weight}`)
148
- .join(' + ')}</div>
158
+ .join(' + ')}
159
+ </div>
149
160
  </div>
150
161
 
151
162
  <!-- Y 그룹들 (비활성 Y 제외) -->
152
- ${this.kpiRoot.filter((y) => y.active !== false).map((y) => {
163
+ ${this.kpiRoot
164
+ .filter((y) => y.active !== false)
165
+ .map((y) => {
153
166
  const activeKpis = (y.kpis || []).filter((x) => x.active !== false);
154
167
  return html `
155
- <div class="y-group">
156
- <div class="y-header" @click=${() => this.showDetail(y, 'kpi')}>
157
- <span class="y-name">${y.name}</span>
158
- <span class="y-weight">가중치: ${y.weight}</span>
159
- </div>
160
- <div class="y-body">
161
- ${y.formula ? html `<div class="y-formula">${y.formula}</div>` : ''}
162
- <div class="x-cards">
163
- ${activeKpis.map((x) => {
168
+ <div class="y-group">
169
+ <div class="y-header" @click=${() => this.showDetail(y, 'kpi')}>
170
+ <span class="y-name">${y.name}</span>
171
+ <span class="y-weight">가중치: ${y.weight}</span>
172
+ </div>
173
+ <div class="y-body">
174
+ ${y.formula ? html `<div class="y-formula">${y.formula}</div>` : ''}
175
+ <div class="x-cards">
176
+ ${activeKpis.map((x) => {
164
177
  const st = SCORE_TYPE_LABELS[x.scoreType] || { label: x.scoreType || '미설정', color: '#999' };
165
178
  const vt = VALUE_TYPE_LABELS[x.valueType] || { label: x.valueType || '미설정', color: '#999', icon: '?' };
166
179
  return html `
167
- <div class="x-card" @click=${() => this.showDetail(x, 'kpi')}>
168
- <div class="x-name">${x.name}</div>
169
- <div class="x-formula">${x.formula || '—'}</div>
170
- <div class="x-badges">
171
- <span class="badge badge-score">${st.label}</span>
172
- <span class="badge badge-value">${vt.icon} ${vt.label}</span>
180
+ <div class="x-card" @click=${() => this.showDetail(x, 'kpi')}>
181
+ <div class="x-name">${x.name}</div>
182
+ <div class="x-formula">${x.formula || '—'}</div>
183
+ <div class="x-badges">
184
+ <span class="badge badge-score">${st.label}</span>
185
+ <span class="badge badge-value">${vt.icon} ${vt.label}</span>
186
+ </div>
173
187
  </div>
174
- </div>
175
- `;
188
+ `;
176
189
  })}
190
+ </div>
177
191
  </div>
178
192
  </div>
179
- </div>
180
- `;
193
+ `;
181
194
  })}
182
195
  </div>
183
196
 
@@ -192,21 +205,26 @@ let KpiSystemGuide = class KpiSystemGuide extends PageView {
192
205
  <div class="section-title">📋 원천 메트릭 (${usedMetrics.length}개 사용)</div>
193
206
  <div class="metrics-grid">
194
207
  ${usedMetrics.map(({ m, usage }) => html `
195
- <div class="metric-card" @click=${() => this.showDetail(m, 'metric')}>
196
- <div class="metric-name">${m.name}</div>
197
- <div class="metric-unit">
198
- ${m.unit || '—'} ·
199
- ${m.collectType === 'EXTERNAL' && m.source
208
+ <div class="metric-card" @click=${() => this.showDetail(m, 'metric')}>
209
+ <div class="metric-name">${m.name}</div>
210
+ <div class="metric-unit">
211
+ ${m.unit || '—'} ·
212
+ ${m.collectType === 'EXTERNAL' && m.source
200
213
  ? EXTERNAL_SYSTEM_URLS[m.source]
201
- ? html `<a href="${EXTERNAL_SYSTEM_URLS[m.source]}" target="_blank" rel="noopener"
202
- style="color:#1976d2;text-decoration:none;" @click=${(e) => e.stopPropagation()}
203
- >${m.source} ↗</a>`
214
+ ? html `<a
215
+ href="${EXTERNAL_SYSTEM_URLS[m.source]}"
216
+ target="_blank"
217
+ rel="noopener"
218
+ style="color:#1976d2;text-decoration:none;"
219
+ @click=${(e) => e.stopPropagation()}
220
+ >${m.source} ↗</a
221
+ >`
204
222
  : m.source
205
223
  : m.collectType || 'MANUAL'}
224
+ </div>
225
+ <div class="metric-used">→ ${usage.join(', ')}</div>
206
226
  </div>
207
- <div class="metric-used">→ ${usage.join(', ')}</div>
208
- </div>
209
- `)}
227
+ `)}
210
228
  </div>
211
229
  </div>
212
230
  `;
@@ -221,15 +239,21 @@ let KpiSystemGuide = class KpiSystemGuide extends PageView {
221
239
  <div style="font-size:0.85rem;color:#555;">X-level 지표</div>
222
240
  </div>
223
241
  <div style="flex:1;min-width:200px;background:#e8f5e9;padding:16px;border-radius:8px;text-align:center;">
224
- <div style="font-size:2rem;font-weight:800;color:#2e7d32;">${this.kpiRoot.filter((y) => y.active !== false).length}</div>
242
+ <div style="font-size:2rem;font-weight:800;color:#2e7d32;">
243
+ ${this.kpiRoot.filter((y) => y.active !== false).length}
244
+ </div>
225
245
  <div style="font-size:0.85rem;color:#555;">Y-level 영역</div>
226
246
  </div>
227
247
  <div style="flex:1;min-width:200px;background:#fff3e0;padding:16px;border-radius:8px;text-align:center;">
228
- <div style="font-size:2rem;font-weight:800;color:#e65100;">${this.metrics.filter((m) => m.active && this.getMetricUsage(m.name).length > 0).length}</div>
248
+ <div style="font-size:2rem;font-weight:800;color:#e65100;">
249
+ ${this.metrics.filter((m) => m.active && this.getMetricUsage(m.name).length > 0).length}
250
+ </div>
229
251
  <div style="font-size:0.85rem;color:#555;">원천 메트릭</div>
230
252
  </div>
231
253
  <div style="flex:1;min-width:200px;background:#fce4ec;padding:16px;border-radius:8px;text-align:center;">
232
- <div style="font-size:2rem;font-weight:800;color:#c62828;">${allX.filter((x) => x.valueType === 'ASSESSED').length}</div>
254
+ <div style="font-size:2rem;font-weight:800;color:#c62828;">
255
+ ${allX.filter((x) => x.valueType === 'ASSESSED').length}
256
+ </div>
233
257
  <div style="font-size:0.85rem;color:#555;">감리자 평가 항목</div>
234
258
  </div>
235
259
  </div>
@@ -250,83 +274,112 @@ let KpiSystemGuide = class KpiSystemGuide extends PageView {
250
274
  <button class="popup-close" @click=${() => this.closeDetail()}>×</button>
251
275
  </div>
252
276
 
253
- ${d.description ? html `
254
- <div class="popup-row">
255
- <span class="popup-label">설명</span>
256
- <span class="popup-value">${d.description}</span>
257
- </div>
258
- ` : ''}
259
-
260
- ${isKpi ? html `
261
- ${d.formula ? html `
262
- <div class="popup-row"><span class="popup-label">산식</span></div>
263
- <div class="popup-formula">${d.formula}</div>
264
- ` : ''}
265
-
266
- ${d.scoreType ? html `
267
- <div class="popup-row">
268
- <span class="popup-label">Score 산정</span>
269
- <span class="popup-value" style="color:${(SCORE_TYPE_LABELS[d.scoreType] || {}).color || '#333'}">
270
- ${(SCORE_TYPE_LABELS[d.scoreType] || {}).label || d.scoreType}
271
- </span>
272
- </div>
273
- ` : ''}
274
-
275
- ${d.valueType ? html `
276
- <div class="popup-row">
277
- <span class="popup-label">Value 획득</span>
278
- <span class="popup-value" style="color:${(VALUE_TYPE_LABELS[d.valueType] || {}).color || '#333'}">
279
- ${(VALUE_TYPE_LABELS[d.valueType] || {}).icon || ''} ${(VALUE_TYPE_LABELS[d.valueType] || {}).label || d.valueType}
280
- </span>
281
- </div>
282
- ` : ''}
283
-
284
- ${d.weight ? html `
285
- <div class="popup-row">
286
- <span class="popup-label">가중치</span>
287
- <span class="popup-value">${d.weight}</span>
288
- </div>
289
- ` : ''}
277
+ ${d.description
278
+ ? html `
279
+ <div class="popup-row">
280
+ <span class="popup-label">설명</span>
281
+ <span class="popup-value">${d.description}</span>
282
+ </div>
283
+ `
284
+ : ''}
285
+ ${isKpi
286
+ ? html `
287
+ ${d.formula
288
+ ? html `
289
+ <div class="popup-row"><span class="popup-label">산식</span></div>
290
+ <div class="popup-formula">${d.formula}</div>
291
+ `
292
+ : ''}
293
+ ${d.scoreType
294
+ ? html `
295
+ <div class="popup-row">
296
+ <span class="popup-label">Score 산정</span>
297
+ <span class="popup-value" style="color:${(SCORE_TYPE_LABELS[d.scoreType] || {}).color || '#333'}">
298
+ ${(SCORE_TYPE_LABELS[d.scoreType] || {}).label || d.scoreType}
299
+ </span>
300
+ </div>
301
+ `
302
+ : ''}
303
+ ${d.valueType
304
+ ? html `
305
+ <div class="popup-row">
306
+ <span class="popup-label">Value 획득</span>
307
+ <span class="popup-value" style="color:${(VALUE_TYPE_LABELS[d.valueType] || {}).color || '#333'}">
308
+ ${(VALUE_TYPE_LABELS[d.valueType] || {}).icon || ''}
309
+ ${(VALUE_TYPE_LABELS[d.valueType] || {}).label || d.valueType}
310
+ </span>
311
+ </div>
312
+ `
313
+ : ''}
314
+ ${d.weight
315
+ ? html `
316
+ <div class="popup-row">
317
+ <span class="popup-label">가중치</span>
318
+ <span class="popup-value">${d.weight}</span>
319
+ </div>
320
+ `
321
+ : ''}
290
322
 
291
- <div style="margin-top:16px;padding-top:12px;border-top:1px solid #eee;">
292
- <span class="popup-link" @click=${() => { this.closeDetail(); navigate('kpi-overview'); }}>
293
- → KPI 개요에서 보기
294
- </span>
295
- &nbsp;&nbsp;
296
- <span class="popup-link" @click=${() => { this.closeDetail(); navigate('kpi-admin'); }}>
297
- → KPI 관리에서 편집
298
- </span>
299
- </div>
300
- ` : html `
301
- <div class="popup-row">
302
- <span class="popup-label">단위</span>
303
- <span class="popup-value">${d.unit || '—'}</span>
304
- </div>
305
- <div class="popup-row">
306
- <span class="popup-label">수집 방식</span>
307
- <span class="popup-value">${d.collectType || 'MANUAL'}</span>
308
- </div>
309
- <div class="popup-row">
310
- <span class="popup-label">데이터 소스</span>
311
- <span class="popup-value">
312
- ${d.source && EXTERNAL_SYSTEM_URLS[d.source]
313
- ? html `<a href="${EXTERNAL_SYSTEM_URLS[d.source]}" target="_blank" rel="noopener" style="color:#1976d2;">${d.source} ↗</a>`
314
- : d.source || '미설정'}
315
- </span>
316
- </div>
323
+ <div style="margin-top:16px;padding-top:12px;border-top:1px solid #eee;">
324
+ <span
325
+ class="popup-link"
326
+ @click=${() => {
327
+ this.closeDetail();
328
+ navigate('kpi-overview');
329
+ }}
330
+ >
331
+ → KPI 개요에서 보기
332
+ </span>
333
+ &nbsp;&nbsp;
334
+ <span
335
+ class="popup-link"
336
+ @click=${() => {
337
+ this.closeDetail();
338
+ navigate('kpi-admin');
339
+ }}
340
+ >
341
+ KPI 관리에서 편집
342
+ </span>
343
+ </div>
344
+ `
345
+ : html `
346
+ <div class="popup-row">
347
+ <span class="popup-label">단위</span>
348
+ <span class="popup-value">${d.unit || '—'}</span>
349
+ </div>
350
+ <div class="popup-row">
351
+ <span class="popup-label">수집 방식</span>
352
+ <span class="popup-value">${d.collectType || 'MANUAL'}</span>
353
+ </div>
354
+ <div class="popup-row">
355
+ <span class="popup-label">데이터 소스</span>
356
+ <span class="popup-value">
357
+ ${d.source && EXTERNAL_SYSTEM_URLS[d.source]
358
+ ? html `<a href="${EXTERNAL_SYSTEM_URLS[d.source]}" target="_blank" rel="noopener" style="color:#1976d2;"
359
+ >${d.source} ↗</a
360
+ >`
361
+ : d.source || '미설정'}
362
+ </span>
363
+ </div>
317
364
 
318
- <div style="margin-top:12px;">
319
- <div class="popup-label" style="margin-bottom:6px;">사용처:</div>
320
- ${this.getMetricUsage(d.name).map(kpi => html `<div style="font-size:0.85rem;color:#1976d2;margin-bottom:2px;">· ${kpi}</div>`)}
321
- ${this.getMetricUsage(d.name).length === 0 ? html `<div style="color:#ccc;font-size:0.85rem;">미사용</div>` : ''}
322
- </div>
365
+ <div style="margin-top:12px;">
366
+ <div class="popup-label" style="margin-bottom:6px;">사용처:</div>
367
+ ${this.getMetricUsage(d.name).map(kpi => html `<div style="font-size:0.85rem;color:#1976d2;margin-bottom:2px;">· ${kpi}</div>`)}
368
+ ${this.getMetricUsage(d.name).length === 0 ? html `<div style="color:#ccc;font-size:0.85rem;">미사용</div>` : ''}
369
+ </div>
323
370
 
324
- <div style="margin-top:16px;padding-top:12px;border-top:1px solid #eee;">
325
- <span class="popup-link" @click=${() => { this.closeDetail(); navigate('kpi-metric-value-list'); }}>
326
- → 메트릭 값 관리
327
- </span>
328
- </div>
329
- `}
371
+ <div style="margin-top:16px;padding-top:12px;border-top:1px solid #eee;">
372
+ <span
373
+ class="popup-link"
374
+ @click=${() => {
375
+ this.closeDetail();
376
+ navigate('kpi-metric-value-list');
377
+ }}
378
+ >
379
+ → 메트릭 값 관리
380
+ </span>
381
+ </div>
382
+ `}
330
383
  </div>
331
384
  </div>
332
385
  `;
@@ -360,7 +413,7 @@ KpiSystemGuide.styles = [
360
413
  border-radius: 12px;
361
414
  padding: 24px;
362
415
  margin-bottom: 24px;
363
- box-shadow: 0 2px 8px rgba(0,0,0,0.06);
416
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
364
417
  }
365
418
  .section-title {
366
419
  font-size: 1.1rem;
@@ -381,9 +434,19 @@ KpiSystemGuide.styles = [
381
434
  margin-bottom: 16px;
382
435
  cursor: pointer;
383
436
  }
384
- .z-node:hover { opacity: 0.95; }
385
- .z-name { font-size: 1.1rem; font-weight: 700; }
386
- .z-formula { font-size: 0.8rem; opacity: 0.8; margin-top: 4px; font-family: monospace; }
437
+ .z-node:hover {
438
+ opacity: 0.95;
439
+ }
440
+ .z-name {
441
+ font-size: 1.1rem;
442
+ font-weight: 700;
443
+ }
444
+ .z-formula {
445
+ font-size: 0.8rem;
446
+ opacity: 0.8;
447
+ margin-top: 4px;
448
+ font-family: monospace;
449
+ }
387
450
 
388
451
  /* Y 그룹 */
389
452
  .y-group {
@@ -401,15 +464,22 @@ KpiSystemGuide.styles = [
401
464
  align-items: center;
402
465
  cursor: pointer;
403
466
  }
404
- .y-header:hover { opacity: 0.95; }
405
- .y-name { font-weight: 700; font-size: 1rem; }
467
+ .y-header:hover {
468
+ opacity: 0.95;
469
+ }
470
+ .y-name {
471
+ font-weight: 700;
472
+ font-size: 1rem;
473
+ }
406
474
  .y-weight {
407
- background: rgba(255,255,255,0.2);
475
+ background: rgba(255, 255, 255, 0.2);
408
476
  padding: 2px 10px;
409
477
  border-radius: 12px;
410
478
  font-size: 0.8rem;
411
479
  }
412
- .y-body { padding: 12px; }
480
+ .y-body {
481
+ padding: 12px;
482
+ }
413
483
  .y-formula {
414
484
  font-size: 0.8rem;
415
485
  color: #555;
@@ -422,7 +492,11 @@ KpiSystemGuide.styles = [
422
492
  }
423
493
 
424
494
  /* X 카드 */
425
- .x-cards { display: flex; flex-wrap: wrap; gap: 8px; }
495
+ .x-cards {
496
+ display: flex;
497
+ flex-wrap: wrap;
498
+ gap: 8px;
499
+ }
426
500
  .x-card {
427
501
  flex: 1 1 220px;
428
502
  background: #fff;
@@ -435,23 +509,42 @@ KpiSystemGuide.styles = [
435
509
  }
436
510
  .x-card:hover {
437
511
  border-color: #1976d2;
438
- box-shadow: 0 2px 8px rgba(25,118,210,0.15);
512
+ box-shadow: 0 2px 8px rgba(25, 118, 210, 0.15);
513
+ }
514
+ .x-name {
515
+ font-weight: 600;
516
+ font-size: 0.85rem;
517
+ color: #333;
518
+ margin-bottom: 4px;
439
519
  }
440
- .x-name { font-weight: 600; font-size: 0.85rem; color: #333; margin-bottom: 4px; }
441
520
  .x-formula {
442
- font-size: 0.75rem; color: #888; font-family: monospace;
443
- white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
521
+ font-size: 0.75rem;
522
+ color: #888;
523
+ font-family: monospace;
524
+ white-space: nowrap;
525
+ overflow: hidden;
526
+ text-overflow: ellipsis;
444
527
  margin-bottom: 6px;
445
528
  }
446
- .x-badges { display: flex; gap: 4px; flex-wrap: wrap; }
529
+ .x-badges {
530
+ display: flex;
531
+ gap: 4px;
532
+ flex-wrap: wrap;
533
+ }
447
534
  .badge {
448
535
  font-size: 0.65rem;
449
536
  padding: 2px 6px;
450
537
  border-radius: 4px;
451
538
  font-weight: 600;
452
539
  }
453
- .badge-score { background: #e3f2fd; color: #1565c0; }
454
- .badge-value { background: #e8f5e9; color: #2e7d32; }
540
+ .badge-score {
541
+ background: #e3f2fd;
542
+ color: #1565c0;
543
+ }
544
+ .badge-value {
545
+ background: #e8f5e9;
546
+ color: #2e7d32;
547
+ }
455
548
 
456
549
  /* 메트릭 섹션 */
457
550
  .metrics-grid {
@@ -466,58 +559,118 @@ KpiSystemGuide.styles = [
466
559
  padding: 10px 14px;
467
560
  transition: all 0.2s;
468
561
  }
469
- .metric-card:hover { border-color: #4caf50; }
470
- .metric-name { font-weight: 600; font-size: 0.85rem; color: #333; }
471
- .metric-unit { font-size: 0.75rem; color: #888; }
562
+ .metric-card:hover {
563
+ border-color: #4caf50;
564
+ }
565
+ .metric-name {
566
+ font-weight: 600;
567
+ font-size: 0.85rem;
568
+ color: #333;
569
+ }
570
+ .metric-unit {
571
+ font-size: 0.75rem;
572
+ color: #888;
573
+ }
472
574
  .metric-used {
473
- font-size: 0.7rem; color: #1976d2; margin-top: 4px;
575
+ font-size: 0.7rem;
576
+ color: #1976d2;
577
+ margin-top: 4px;
474
578
  }
475
579
 
476
580
  /* 팝업 */
477
581
  .popup-overlay {
478
- position: fixed; top: 0; left: 0; right: 0; bottom: 0;
479
- background: rgba(0,0,0,0.3); z-index: 1000;
480
- display: flex; align-items: center; justify-content: center;
582
+ position: fixed;
583
+ top: 0;
584
+ left: 0;
585
+ right: 0;
586
+ bottom: 0;
587
+ background: rgba(0, 0, 0, 0.3);
588
+ z-index: 1000;
589
+ display: flex;
590
+ align-items: center;
591
+ justify-content: center;
481
592
  }
482
593
  .popup-box {
483
- background: #fff; border-radius: 12px; padding: 24px;
484
- min-width: 400px; max-width: 600px; max-height: 80vh;
485
- overflow-y: auto; box-shadow: 0 8px 32px rgba(0,0,0,0.2);
594
+ background: #fff;
595
+ border-radius: 12px;
596
+ padding: 24px;
597
+ min-width: 400px;
598
+ max-width: 600px;
599
+ max-height: 80vh;
600
+ overflow-y: auto;
601
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
486
602
  }
487
603
  .popup-title {
488
- font-size: 1.1rem; font-weight: 700; color: #1a237e;
489
- margin-bottom: 16px; display: flex; justify-content: space-between;
604
+ font-size: 1.1rem;
605
+ font-weight: 700;
606
+ color: #1a237e;
607
+ margin-bottom: 16px;
608
+ display: flex;
609
+ justify-content: space-between;
490
610
  }
491
611
  .popup-close {
492
- background: none; border: none; font-size: 1.2rem;
493
- cursor: pointer; color: #999;
612
+ background: none;
613
+ border: none;
614
+ font-size: 1.2rem;
615
+ cursor: pointer;
616
+ color: #999;
494
617
  }
495
618
  .popup-row {
496
- display: flex; gap: 8px; margin-bottom: 8px;
619
+ display: flex;
620
+ gap: 8px;
621
+ margin-bottom: 8px;
497
622
  font-size: 0.85rem;
498
623
  }
499
- .popup-label { color: #888; min-width: 100px; flex-shrink: 0; }
500
- .popup-value { color: #333; font-weight: 500; }
624
+ .popup-label {
625
+ color: #888;
626
+ min-width: 100px;
627
+ flex-shrink: 0;
628
+ }
629
+ .popup-value {
630
+ color: #333;
631
+ font-weight: 500;
632
+ }
501
633
  .popup-formula {
502
- background: #f5f5f5; padding: 10px; border-radius: 6px;
503
- font-family: monospace; font-size: 0.85rem; margin: 8px 0;
634
+ background: #f5f5f5;
635
+ padding: 10px;
636
+ border-radius: 6px;
637
+ font-family: monospace;
638
+ font-size: 0.85rem;
639
+ margin: 8px 0;
504
640
  word-break: break-all;
505
641
  }
506
642
  .popup-link {
507
- color: #1976d2; cursor: pointer; text-decoration: underline;
643
+ color: #1976d2;
644
+ cursor: pointer;
645
+ text-decoration: underline;
508
646
  font-size: 0.85rem;
509
647
  }
510
- .popup-link:hover { color: #0d47a1; }
648
+ .popup-link:hover {
649
+ color: #0d47a1;
650
+ }
511
651
 
512
652
  /* 범례 */
513
653
  .legend {
514
- display: flex; gap: 16px; flex-wrap: wrap;
515
- margin-bottom: 20px; padding: 12px 16px;
516
- background: #fff; border-radius: 8px;
517
- box-shadow: 0 1px 4px rgba(0,0,0,0.04);
654
+ display: flex;
655
+ gap: 16px;
656
+ flex-wrap: wrap;
657
+ margin-bottom: 20px;
658
+ padding: 12px 16px;
659
+ background: #fff;
660
+ border-radius: 8px;
661
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
662
+ }
663
+ .legend-group {
664
+ display: flex;
665
+ align-items: center;
666
+ gap: 4px;
667
+ font-size: 0.8rem;
668
+ }
669
+ .legend-title {
670
+ font-weight: 700;
671
+ color: #555;
672
+ margin-right: 4px;
518
673
  }
519
- .legend-group { display: flex; align-items: center; gap: 4px; font-size: 0.8rem; }
520
- .legend-title { font-weight: 700; color: #555; margin-right: 4px; }
521
674
  `
522
675
  ];
523
676
  __decorate([