@dssp/dkpi 1.0.0-alpha.65 → 1.0.0-alpha.67

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 (82) hide show
  1. package/_index.html +0 -5
  2. package/dist-client/components/kpi-2d-lookup-chart.d.ts +63 -0
  3. package/dist-client/components/kpi-2d-lookup-chart.js +470 -0
  4. package/dist-client/components/kpi-2d-lookup-chart.js.map +1 -0
  5. package/dist-client/google-map/common-google-map.js +10 -8
  6. package/dist-client/google-map/common-google-map.js.map +1 -1
  7. package/dist-client/pages/kpi-admin/dssp-kpi-list-page.d.ts +22 -0
  8. package/dist-client/pages/kpi-admin/dssp-kpi-list-page.js +57 -0
  9. package/dist-client/pages/kpi-admin/dssp-kpi-list-page.js.map +1 -0
  10. package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.d.ts +20 -0
  11. package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.js +445 -0
  12. package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.js.map +1 -0
  13. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.d.ts +6 -5
  14. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js +47 -68
  15. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js.map +1 -1
  16. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.d.ts +3 -2
  17. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js +79 -122
  18. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js.map +1 -1
  19. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.d.ts +3 -2
  20. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js +71 -107
  21. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js.map +1 -1
  22. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.d.ts +4 -0
  23. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js +246 -28
  24. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js.map +1 -1
  25. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.d.ts +4 -0
  26. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js +22 -207
  27. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js.map +1 -1
  28. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.d.ts +2 -0
  29. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js +84 -25
  30. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js.map +1 -1
  31. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.d.ts +16 -0
  32. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js +261 -31
  33. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js.map +1 -1
  34. package/dist-client/pages/kpi-dashboard/kpi-dashboard.d.ts +4 -0
  35. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js +66 -4
  36. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js.map +1 -1
  37. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.d.ts +1 -2
  38. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js +1 -2
  39. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js.map +1 -1
  40. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.d.ts +1 -2
  41. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js +1 -2
  42. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js.map +1 -1
  43. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.d.ts +1 -2
  44. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js +1 -2
  45. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js.map +1 -1
  46. package/dist-client/pages/kpi-value/kpi-value-list-page.d.ts +1 -2
  47. package/dist-client/pages/kpi-value/kpi-value-list-page.js +1 -2
  48. package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -1
  49. package/dist-client/pages/sv-project-detail.d.ts +1 -0
  50. package/dist-client/pages/sv-project-detail.js +26 -13
  51. package/dist-client/pages/sv-project-detail.js.map +1 -1
  52. package/dist-client/pages/sv-project-list.js +6 -6
  53. package/dist-client/pages/sv-project-list.js.map +1 -1
  54. package/dist-client/route.d.ts +1 -1
  55. package/dist-client/route.js +4 -0
  56. package/dist-client/route.js.map +1 -1
  57. package/dist-client/tsconfig.tsbuildinfo +1 -1
  58. package/dist-client/viewparts/menu-tools.d.ts +1 -2
  59. package/dist-client/viewparts/menu-tools.js +1 -2
  60. package/dist-client/viewparts/menu-tools.js.map +1 -1
  61. package/dist-server/scripts/calculate-kpi-scores.js +65 -3
  62. package/dist-server/scripts/calculate-kpi-scores.js.map +1 -1
  63. package/dist-server/scripts/load-grade-data-migration.d.ts +4 -0
  64. package/dist-server/scripts/load-grade-data-migration.js +95 -10
  65. package/dist-server/scripts/load-grade-data-migration.js.map +1 -1
  66. package/dist-server/scripts/propagate-parent-kpi-values.js +58 -4
  67. package/dist-server/scripts/propagate-parent-kpi-values.js.map +1 -1
  68. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.d.ts +6 -0
  69. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +57 -7
  70. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -1
  71. package/dist-server/service/kpi-stat/kpi-stat-query.d.ts +8 -5
  72. package/dist-server/service/kpi-stat/kpi-stat-query.js +228 -11
  73. package/dist-server/service/kpi-stat/kpi-stat-query.js.map +1 -1
  74. package/dist-server/service/kpi-stat/kpi-stat-types.d.ts +13 -0
  75. package/dist-server/service/kpi-stat/kpi-stat-types.js +51 -1
  76. package/dist-server/service/kpi-stat/kpi-stat-types.js.map +1 -1
  77. package/dist-server/tsconfig.tsbuildinfo +1 -1
  78. package/package.json +54 -54
  79. package/schema.graphql +95 -58
  80. package/things-factory.config.js +3 -1
  81. package/views/auth-page.html +0 -1
  82. package/views/public/home.html +0 -1
@@ -15,6 +15,9 @@ let KpiLeftPanel = class KpiLeftPanel extends LitElement {
15
15
  this.mapData = [];
16
16
  this.startYearMonth = ''; // YYYY-MM 형식
17
17
  this.endYearMonth = ''; // YYYY-MM 형식
18
+ this.sectorType = '';
19
+ this.buildingUsage = '';
20
+ this.isAllPeriod = false;
18
21
  this.chartData = [];
19
22
  this.chartCategories = [];
20
23
  this.kpiYComprehensiveStats = [];
@@ -43,6 +46,16 @@ let KpiLeftPanel = class KpiLeftPanel extends LitElement {
43
46
  }
44
47
  connectedCallback() {
45
48
  super.connectedCallback();
49
+ // 기간 초기값이 비어있으면 현재 월 기준 12개월로 설정
50
+ if (!this.startYearMonth || !this.endYearMonth) {
51
+ const now = new Date();
52
+ const end = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
53
+ const start = new Date(now);
54
+ start.setMonth(start.getMonth() - 11);
55
+ const startStr = `${start.getFullYear()}-${String(start.getMonth() + 1).padStart(2, '0')}`;
56
+ this.startYearMonth = startStr;
57
+ this.endYearMonth = end;
58
+ }
46
59
  this.fetchKpiYComprehensiveStats();
47
60
  this.fetchRegionalKpiStats();
48
61
  this.fetchMonthlyTrendData();
@@ -51,7 +64,9 @@ let KpiLeftPanel = class KpiLeftPanel extends LitElement {
51
64
  // selectedCategory, startYearMonth, endYearMonth가 변경되면 데이터 다시 가져오기
52
65
  if (changedProperties.has('selectedCategory') ||
53
66
  changedProperties.has('startYearMonth') ||
54
- changedProperties.has('endYearMonth')) {
67
+ changedProperties.has('endYearMonth') ||
68
+ changedProperties.has('sectorType') ||
69
+ changedProperties.has('buildingUsage')) {
55
70
  // 기간 정보가 설정되어 있을 때만 조회 (빈 문자열이면 전체 기간)
56
71
  if (this.startYearMonth !== undefined && this.endYearMonth !== undefined) {
57
72
  this.fetchKpiYComprehensiveStats();
@@ -64,8 +79,18 @@ let KpiLeftPanel = class KpiLeftPanel extends LitElement {
64
79
  try {
65
80
  const response = await client.query({
66
81
  query: gql `
67
- query GetKpiYValueComprehensiveStats($startYearMonth: String, $endYearMonth: String) {
68
- totalKpiYValueComprehensiveStats(startYearMonth: $startYearMonth, endYearMonth: $endYearMonth) {
82
+ query GetKpiYValueComprehensiveStats(
83
+ $startYearMonth: String
84
+ $endYearMonth: String
85
+ $sectorType: String
86
+ $buildingUsage: String
87
+ ) {
88
+ totalKpiYValueComprehensiveStats(
89
+ startYearMonth: $startYearMonth
90
+ endYearMonth: $endYearMonth
91
+ sectorType: $sectorType
92
+ buildingUsage: $buildingUsage
93
+ ) {
69
94
  kpiName
70
95
  minVal
71
96
  q1Val
@@ -78,7 +103,9 @@ let KpiLeftPanel = class KpiLeftPanel extends LitElement {
78
103
  `,
79
104
  variables: {
80
105
  startYearMonth: this.startYearMonth,
81
- endYearMonth: this.endYearMonth
106
+ endYearMonth: this.endYearMonth,
107
+ sectorType: this.sectorType || null,
108
+ buildingUsage: this.buildingUsage || null
82
109
  }
83
110
  });
84
111
  this.kpiYComprehensiveStats = response.data.totalKpiYValueComprehensiveStats || [];
@@ -112,11 +139,19 @@ let KpiLeftPanel = class KpiLeftPanel extends LitElement {
112
139
  const kpiName = categoryToKpiName[this.selectedCategory];
113
140
  const response = await client.query({
114
141
  query: gql `
115
- query GetRegionalKpiStats($kpiName: String, $startYearMonth: String, $endYearMonth: String) {
142
+ query GetRegionalKpiStats(
143
+ $kpiName: String
144
+ $startYearMonth: String
145
+ $endYearMonth: String
146
+ $sectorType: String
147
+ $buildingUsage: String
148
+ ) {
116
149
  kpiZValueComprehensiveStatsByGeoGroup(
117
150
  kpiName: $kpiName
118
151
  startYearMonth: $startYearMonth
119
152
  endYearMonth: $endYearMonth
153
+ sectorType: $sectorType
154
+ buildingUsage: $buildingUsage
120
155
  ) {
121
156
  geoGroup
122
157
  avgVal
@@ -129,7 +164,9 @@ let KpiLeftPanel = class KpiLeftPanel extends LitElement {
129
164
  variables: {
130
165
  kpiName,
131
166
  startYearMonth: this.startYearMonth,
132
- endYearMonth: this.endYearMonth
167
+ endYearMonth: this.endYearMonth,
168
+ sectorType: this.sectorType || null,
169
+ buildingUsage: this.buildingUsage || null
133
170
  }
134
171
  });
135
172
  this.regionalKpiStats = response.data.kpiZValueComprehensiveStatsByGeoGroup || [];
@@ -161,8 +198,20 @@ let KpiLeftPanel = class KpiLeftPanel extends LitElement {
161
198
  const kpiName = categoryToKpiName[this.selectedCategory];
162
199
  const response = await client.query({
163
200
  query: gql `
164
- query GetMonthlyTrendData($kpiName: String, $startYearMonth: String, $endYearMonth: String) {
165
- kpiZValueMonthlyTrendByGeoGroup(kpiName: $kpiName, startYearMonth: $startYearMonth, endYearMonth: $endYearMonth) {
201
+ query GetMonthlyTrendData(
202
+ $kpiName: String
203
+ $startYearMonth: String
204
+ $endYearMonth: String
205
+ $sectorType: String
206
+ $buildingUsage: String
207
+ ) {
208
+ kpiZValueMonthlyTrendByGeoGroup(
209
+ kpiName: $kpiName
210
+ startYearMonth: $startYearMonth
211
+ endYearMonth: $endYearMonth
212
+ sectorType: $sectorType
213
+ buildingUsage: $buildingUsage
214
+ ) {
166
215
  geoGroup
167
216
  yearMonth
168
217
  avgVal
@@ -173,7 +222,9 @@ let KpiLeftPanel = class KpiLeftPanel extends LitElement {
173
222
  variables: {
174
223
  kpiName,
175
224
  startYearMonth: this.startYearMonth,
176
- endYearMonth: this.endYearMonth
225
+ endYearMonth: this.endYearMonth,
226
+ sectorType: this.sectorType || null,
227
+ buildingUsage: this.buildingUsage || null
177
228
  }
178
229
  });
179
230
  this.monthlyTrendData = response.data.kpiZValueMonthlyTrendByGeoGroup || [];
@@ -273,6 +324,13 @@ let KpiLeftPanel = class KpiLeftPanel extends LitElement {
273
324
  console.log('Boxplot chart categories:', this.chartCategories);
274
325
  }
275
326
  }
327
+ _onAllPeriodChange(e) {
328
+ this.isAllPeriod = e.target.checked;
329
+ if (this.isAllPeriod) {
330
+ this.startYearMonth = '';
331
+ this.endYearMonth = '';
332
+ }
333
+ }
276
334
  onCategoryChange(event) {
277
335
  const target = event.target;
278
336
  this.selectedCategory = target.value;
@@ -291,18 +349,83 @@ let KpiLeftPanel = class KpiLeftPanel extends LitElement {
291
349
  this.generateChartData();
292
350
  }
293
351
  onRegionClick(region) {
294
- this.dispatchEvent(new CustomEvent('region-click', {
352
+ // 지도를 해당 광역시도로 포커스
353
+ this.dispatchEvent(new CustomEvent('focus-region', {
295
354
  detail: { region },
296
355
  bubbles: true,
297
356
  composed: true
298
357
  }));
299
- }
300
- downloadExcel() {
301
- this.dispatchEvent(new CustomEvent('download-excel', {
358
+ // 팝업 열기
359
+ this.dispatchEvent(new CustomEvent('region-click', {
360
+ detail: { region },
302
361
  bubbles: true,
303
362
  composed: true
304
363
  }));
305
364
  }
365
+ downloadExcel() {
366
+ import('xlsx').then(XLSX => {
367
+ const filterLabel = [
368
+ this.selectedCategory,
369
+ this.sectorType === 'PUBLIC' ? '공공' : this.sectorType === 'PRIVATE' ? '민간' : '',
370
+ this.buildingUsage === 'RESIDENTIAL' ? '주거' : this.buildingUsage === 'NON_RESIDENTIAL' ? '비주거' : ''
371
+ ]
372
+ .filter(Boolean)
373
+ .join('_');
374
+ const period = this.isAllPeriod ? '전체기간' : `${this.startYearMonth}~${this.endYearMonth}`;
375
+ const wb = XLSX.utils.book_new();
376
+ // Sheet 1: 검색 조건
377
+ const condData = [
378
+ { 항목: 'KPI 카테고리', 값: this.selectedCategory },
379
+ { 항목: '사업 유형', 값: this.sectorType === 'PUBLIC' ? '공공' : this.sectorType === 'PRIVATE' ? '민간' : '전체' },
380
+ { 항목: '건물 용도', 값: this.buildingUsage === 'RESIDENTIAL' ? '주거' : this.buildingUsage === 'NON_RESIDENTIAL' ? '비주거' : '전체' },
381
+ { 항목: '기간', 값: this.isAllPeriod ? '전체 기간' : `${this.startYearMonth} ~ ${this.endYearMonth}` },
382
+ { 항목: '다운로드 일시', 값: new Date().toLocaleString('ko-KR') }
383
+ ];
384
+ const wsCond = XLSX.utils.json_to_sheet(condData);
385
+ wsCond['!cols'] = [{ wch: 16 }, { wch: 30 }];
386
+ XLSX.utils.book_append_sheet(wb, wsCond, '검색 조건');
387
+ // Sheet 2: 종합 성과
388
+ const yData = this.kpiYComprehensiveStats.map((s) => ({
389
+ KPI: s.kpiName,
390
+ 최소: Number((s.minVal * 100).toFixed(2)),
391
+ Q1: Number((s.q1Val * 100).toFixed(2)),
392
+ 중앙값: Number((s.medVal * 100).toFixed(2)),
393
+ Q3: Number((s.q3Val * 100).toFixed(2)),
394
+ 최대: Number((s.maxVal * 100).toFixed(2)),
395
+ 평균: Number((s.avgVal * 100).toFixed(2))
396
+ }));
397
+ const ws1 = XLSX.utils.json_to_sheet(yData);
398
+ ws1['!cols'] = [{ wch: 20 }, { wch: 10 }, { wch: 10 }, { wch: 10 }, { wch: 10 }, { wch: 10 }, { wch: 10 }];
399
+ XLSX.utils.book_append_sheet(wb, ws1, '종합 성과');
400
+ // Sheet 2: 시도별 성과
401
+ const rData = this.getSortedRegionData().map((item) => {
402
+ var _a;
403
+ const stat = this.regionalKpiStats.find((s) => s.geoGroup === item.region);
404
+ return {
405
+ 지역: item.region,
406
+ 'KPI 점수': Number(item.kpi) || 0,
407
+ '변동률(%)': Number(Number(item.change).toFixed(2)),
408
+ 프로젝트수: (_a = stat === null || stat === void 0 ? void 0 : stat.projectCount) !== null && _a !== void 0 ? _a : 0
409
+ };
410
+ });
411
+ const ws2 = XLSX.utils.json_to_sheet(rData);
412
+ ws2['!cols'] = [{ wch: 16 }, { wch: 12 }, { wch: 12 }, { wch: 12 }];
413
+ XLSX.utils.book_append_sheet(wb, ws2, '시도별 성과');
414
+ // Sheet 3: 월별 추이
415
+ if (this.monthlyTrendData.length > 0) {
416
+ const mData = this.monthlyTrendData.map((d) => ({
417
+ 지역: d.geoGroup,
418
+ 기간: d.yearMonth,
419
+ 평균: Number((d.avgVal * 100).toFixed(2)),
420
+ 프로젝트수: d.projectCount
421
+ }));
422
+ const ws3 = XLSX.utils.json_to_sheet(mData);
423
+ ws3['!cols'] = [{ wch: 16 }, { wch: 12 }, { wch: 10 }, { wch: 12 }];
424
+ XLSX.utils.book_append_sheet(wb, ws3, '월별 추이');
425
+ }
426
+ XLSX.writeFile(wb, `KPI_대시보드_${filterLabel}_${period}.xlsx`);
427
+ });
428
+ }
306
429
  // regionOrder에 따라 지역 데이터를 정렬
307
430
  getSortedRegionData() {
308
431
  // 실제 데이터를 기반으로 각 시도에 대한 데이터 생성
@@ -340,16 +463,81 @@ let KpiLeftPanel = class KpiLeftPanel extends LitElement {
340
463
  <button class="panel-close" style="visibility: hidden;">×</button>
341
464
  </div>
342
465
  <div class="panel-content">
343
- <!-- KPI 카테고리 선택 -->
344
- <select class="category-select" .value=${this.selectedCategory} @change=${this.onCategoryChange}>
345
- <option value="전체 KPI">전체 KPI</option>
346
- <option value="일정 성과">일정 성과</option>
347
- <option value="비용 성과">비용 성과</option>
348
- <option value="품질 성과">품질 성과</option>
349
- <option value="안전 성과">안전 성과</option>
350
- <option value="환경 성과">환경 성과</option>
351
- <option value="생산성 성과">생산성 성과</option>
352
- </select>
466
+ <!-- 필터: KPI / 사업유형 / 건물용도 -->
467
+ <div class="filter-row">
468
+ <span class="filter-label">KPI</span>
469
+ <select class="filter-select" .value=${this.selectedCategory} @change=${this.onCategoryChange}>
470
+ <option value="전체 KPI">전체 KPI</option>
471
+ <option value="일정 성과">일정</option>
472
+ <option value="비용 성과">비용</option>
473
+ <option value="품질 성과">품질</option>
474
+ <option value="안전 성과">안전</option>
475
+ <option value="환경 성과">환경</option>
476
+ <option value="생산성 성과">생산성</option>
477
+ </select>
478
+ <span class="filter-label">유형</span>
479
+ <select
480
+ class="filter-select"
481
+ .value=${this.sectorType}
482
+ @change=${(e) => {
483
+ this.sectorType = e.target.value;
484
+ }}
485
+ >
486
+ <option value="">전체</option>
487
+ <option value="PUBLIC">공공</option>
488
+ <option value="PRIVATE">민간</option>
489
+ </select>
490
+ <span class="filter-label">용도</span>
491
+ <select
492
+ class="filter-select"
493
+ .value=${this.buildingUsage}
494
+ @change=${(e) => {
495
+ this.buildingUsage = e.target.value;
496
+ }}
497
+ >
498
+ <option value="">전체</option>
499
+ <option value="RESIDENTIAL">주거</option>
500
+ <option value="NON_RESIDENTIAL">비주거</option>
501
+ </select>
502
+ </div>
503
+
504
+ <!-- 기간 필터 -->
505
+ <div class="filter-row">
506
+ <span class="filter-label">기간</span>
507
+ <select class="filter-select" ?disabled=${this.isAllPeriod} @change=${(e) => {
508
+ const y = e.target.value;
509
+ const m = this.startYearMonth.split('-')[1] || '01';
510
+ this.startYearMonth = `${y}-${m}`;
511
+ }}>
512
+ ${[2022, 2023, 2024, 2025, 2026].map(y => html `<option value="${y}" ?selected=${this.startYearMonth.startsWith(String(y))}>${y}</option>`)}
513
+ </select>
514
+ <select class="filter-select" ?disabled=${this.isAllPeriod} @change=${(e) => {
515
+ const y = this.startYearMonth.split('-')[0] || '2025';
516
+ const m = e.target.value.padStart(2, '0');
517
+ this.startYearMonth = `${y}-${m}`;
518
+ }}>
519
+ ${[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].map(m => html `<option value="${m}" ?selected=${parseInt(this.startYearMonth.split('-')[1]) === m}>${m}월</option>`)}
520
+ </select>
521
+ <span style="color:#6c757d;font-size:0.8rem;">~</span>
522
+ <select class="filter-select" ?disabled=${this.isAllPeriod} @change=${(e) => {
523
+ const y = e.target.value;
524
+ const m = this.endYearMonth.split('-')[1] || '12';
525
+ this.endYearMonth = `${y}-${m}`;
526
+ }}>
527
+ ${[2022, 2023, 2024, 2025, 2026].map(y => html `<option value="${y}" ?selected=${this.endYearMonth.startsWith(String(y))}>${y}</option>`)}
528
+ </select>
529
+ <select class="filter-select" ?disabled=${this.isAllPeriod} @change=${(e) => {
530
+ const y = this.endYearMonth.split('-')[0] || '2026';
531
+ const m = e.target.value.padStart(2, '0');
532
+ this.endYearMonth = `${y}-${m}`;
533
+ }}>
534
+ ${[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].map(m => html `<option value="${m}" ?selected=${parseInt(this.endYearMonth.split('-')[1]) === m}>${m}월</option>`)}
535
+ </select>
536
+ <label style="display:flex;align-items:center;gap:3px;cursor:pointer;">
537
+ <input type="checkbox" .checked=${this.isAllPeriod} @change=${this._onAllPeriodChange} style="cursor:pointer;" />
538
+ <span class="filter-label" style="min-width:auto;">전체</span>
539
+ </label>
540
+ </div>
353
541
 
354
542
  <!-- 종합 성과 -->
355
543
  <div class="chart-section">
@@ -585,13 +773,31 @@ KpiLeftPanel.styles = [
585
773
  .download-button:hover {
586
774
  background: #218838;
587
775
  }
588
- .category-select {
589
- width: 100%;
590
- padding: 8px 12px;
776
+ .filter-row {
777
+ display: flex;
778
+ align-items: center;
779
+ justify-content: space-between;
780
+ gap: 6px;
781
+ margin-bottom: 10px;
782
+ }
783
+ .filter-label {
784
+ font-size: 0.75rem;
785
+ font-weight: 600;
786
+ color: #495057;
787
+ white-space: nowrap;
788
+ }
789
+ .filter-select {
790
+ flex: 1;
791
+ min-width: 0;
792
+ padding: 4px 6px;
591
793
  border: 1px solid #ced4da;
592
- border-radius: 6px;
794
+ border-radius: 4px;
593
795
  background: white;
594
- margin-bottom: 20px;
796
+ font-size: 0.78rem;
797
+ }
798
+ .filter-select:focus {
799
+ outline: none;
800
+ border-color: #667eea;
595
801
  }
596
802
  `
597
803
  ];
@@ -615,6 +821,18 @@ __decorate([
615
821
  property({ type: String }),
616
822
  __metadata("design:type", Object)
617
823
  ], KpiLeftPanel.prototype, "endYearMonth", void 0);
824
+ __decorate([
825
+ property({ type: String }),
826
+ __metadata("design:type", Object)
827
+ ], KpiLeftPanel.prototype, "sectorType", void 0);
828
+ __decorate([
829
+ property({ type: String }),
830
+ __metadata("design:type", Object)
831
+ ], KpiLeftPanel.prototype, "buildingUsage", void 0);
832
+ __decorate([
833
+ state(),
834
+ __metadata("design:type", Object)
835
+ ], KpiLeftPanel.prototype, "isAllPeriod", void 0);
618
836
  __decorate([
619
837
  state(),
620
838
  __metadata("design:type", Array)
@@ -1 +1 @@
1
- {"version":3,"file":"kpi-left-panel.js","sourceRoot":"","sources":["../../../../client/pages/kpi-dashboard/components/kpi-left-panel.ts"],"names":[],"mappings":"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","sourcesContent":["import gql from 'graphql-tag'\nimport { LitElement, html, css } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { ScrollbarStyles } from '@operato/styles'\nimport { client } from '@operato/graphql'\n\nimport '../../../components/kpi-radar-chart.js'\nimport '../../../components/kpi-boxplot-chart.js'\nimport '../../../components/kpi-mini-trend-chart.js'\n\n@customElement('kpi-left-panel')\nexport class KpiLeftPanel extends LitElement {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: block;\n width: 400px;\n background: #fff;\n border-right: 1px solid #e0e0e0;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);\n }\n .panel-content {\n padding: 20px;\n overflow-y: auto;\n flex: 1;\n }\n .panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 20px;\n border-bottom: 1px solid #e0e0e0;\n background: #fff;\n height: 70px;\n box-sizing: border-box;\n }\n .panel-title {\n font-size: 1.3rem;\n font-weight: bold;\n color: #333;\n margin: 0;\n }\n .panel-close {\n width: 32px;\n height: 32px;\n border: none;\n background: #fff;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.2rem;\n color: #666;\n transition: all 0.2s;\n }\n .panel-close:hover {\n background: #e9ecef;\n color: #333;\n }\n .sub-title {\n font-size: 1rem;\n font-weight: 600;\n margin-bottom: 16px;\n color: #495057;\n }\n .chart-section {\n background: #f8f9fa;\n border-radius: 8px;\n padding: 16px;\n margin-bottom: 20px;\n }\n .chart-toggle {\n display: flex;\n gap: 8px;\n margin-bottom: 16px;\n }\n .toggle-button {\n padding: 8px 16px;\n border: 1px solid #ced4da;\n background: #fff;\n border-radius: 6px;\n cursor: pointer;\n font-size: 0.9rem;\n transition: all 0.2s;\n }\n .toggle-button.active {\n background: #667eea;\n color: white;\n border-color: #667eea;\n }\n .chart-container {\n height: 300px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: white;\n border-radius: 6px;\n border: 1px solid #e9ecef;\n }\n .performance-table {\n width: 100%;\n border-collapse: collapse;\n margin-top: 16px;\n }\n .performance-table th,\n .performance-table td {\n padding: 12px 8px;\n text-align: left;\n border-bottom: 1px solid #e9ecef;\n }\n .performance-table th {\n background: #f8f9fa;\n font-weight: 600;\n color: #495057;\n }\n .performance-table td {\n color: #333;\n }\n .change-rate {\n display: flex;\n align-items: center;\n gap: 4px;\n }\n .change-up {\n color: #dc3545;\n }\n .change-down {\n color: #198754;\n }\n .change-neutral {\n color: #6c757d;\n }\n .trend-chart {\n width: 60px;\n height: 30px;\n background: #f8f9fa;\n border-radius: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.8rem;\n color: #666;\n }\n .download-button {\n margin-top: 16px;\n padding: 8px 16px;\n background: #28a745;\n color: white;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n font-size: 0.9rem;\n display: flex;\n align-items: center;\n gap: 8px;\n }\n .download-button:hover {\n background: #218838;\n }\n .category-select {\n width: 100%;\n padding: 8px 12px;\n border: 1px solid #ced4da;\n border-radius: 6px;\n background: white;\n margin-bottom: 20px;\n }\n `\n ]\n\n @property({ type: String }) selectedCategory = '전체 KPI'\n @property({ type: String }) selectedChartType = 'boxplot'\n @property({ type: Array }) mapData: any[] = []\n @property({ type: String }) startYearMonth = '' // YYYY-MM 형식\n @property({ type: String }) endYearMonth = '' // YYYY-MM 형식\n\n @state() private chartData: any[] = []\n @state() private chartCategories: string[] = []\n @state() private kpiYComprehensiveStats: any[] = []\n @state() private regionalKpiStats: any[] = []\n @state() private monthlyTrendData: any[] = []\n\n // 행정안전부 행정구역코드 순서\n private readonly regionOrder = [\n '서울특별시',\n '부산광역시',\n '대구광역시',\n '인천광역시',\n '광주광역시',\n '대전광역시',\n '울산광역시',\n '세종특별자치시',\n '경기도',\n '강원도',\n '충청북도',\n '충청남도',\n '전라북도',\n '전라남도',\n '경상북도',\n '경상남도',\n '제주특별자치도'\n ]\n\n connectedCallback() {\n super.connectedCallback()\n this.fetchKpiYComprehensiveStats()\n this.fetchRegionalKpiStats()\n this.fetchMonthlyTrendData()\n }\n\n updated(changedProperties: Map<string, any>) {\n // selectedCategory, startYearMonth, endYearMonth가 변경되면 데이터 다시 가져오기\n if (\n changedProperties.has('selectedCategory') ||\n changedProperties.has('startYearMonth') ||\n changedProperties.has('endYearMonth')\n ) {\n // 기간 정보가 설정되어 있을 때만 조회 (빈 문자열이면 전체 기간)\n if (this.startYearMonth !== undefined && this.endYearMonth !== undefined) {\n this.fetchKpiYComprehensiveStats()\n this.fetchRegionalKpiStats()\n this.fetchMonthlyTrendData()\n }\n }\n }\n\n async fetchKpiYComprehensiveStats() {\n try {\n const response = await client.query({\n query: gql`\n query GetKpiYValueComprehensiveStats($startYearMonth: String, $endYearMonth: String) {\n totalKpiYValueComprehensiveStats(startYearMonth: $startYearMonth, endYearMonth: $endYearMonth) {\n kpiName\n minVal\n q1Val\n medVal\n q3Val\n maxVal\n avgVal\n }\n }\n `,\n variables: {\n startYearMonth: this.startYearMonth,\n endYearMonth: this.endYearMonth\n }\n })\n\n this.kpiYComprehensiveStats = response.data.totalKpiYValueComprehensiveStats || []\n console.log('KPI Y-Value Comprehensive Stats:', this.kpiYComprehensiveStats)\n\n // 부모에게 전체 Y-level KPI 통계 전달\n this.dispatchEvent(\n new CustomEvent('total-kpi-y-stats-loaded', {\n detail: { data: this.kpiYComprehensiveStats },\n bubbles: true,\n composed: true\n })\n )\n\n this.generateChartData()\n } catch (error) {\n console.error('Failed to fetch KPI Y comprehensive stats:', error)\n this.kpiYComprehensiveStats = []\n this.generateChartData()\n }\n }\n\n async fetchRegionalKpiStats() {\n try {\n // selectedCategory에 따라 kpiName 결정\n const categoryToKpiName: Record<string, string | null> = {\n '전체 KPI': null,\n '일정 성과': 'Y1. 일정성과',\n '비용 성과': 'Y2. 비용성과',\n '품질 성과': 'Y3. 품질성과',\n '안전 성과': 'Y4. 안전성과',\n '환경 성과': 'Y5. 환경성과',\n '생산성 성과': 'Y6. 생산성성과'\n }\n\n const kpiName = categoryToKpiName[this.selectedCategory]\n\n const response = await client.query({\n query: gql`\n query GetRegionalKpiStats($kpiName: String, $startYearMonth: String, $endYearMonth: String) {\n kpiZValueComprehensiveStatsByGeoGroup(\n kpiName: $kpiName\n startYearMonth: $startYearMonth\n endYearMonth: $endYearMonth\n ) {\n geoGroup\n avgVal\n minVal\n maxVal\n projectCount\n }\n }\n `,\n variables: {\n kpiName,\n startYearMonth: this.startYearMonth,\n endYearMonth: this.endYearMonth\n }\n })\n\n this.regionalKpiStats = response.data.kpiZValueComprehensiveStatsByGeoGroup || []\n console.log('Regional KPI Stats:', this.regionalKpiStats)\n\n // 부모에게 지역별 KPI 통계 전달\n this.dispatchEvent(\n new CustomEvent('regional-kpi-stats-loaded', {\n detail: { data: this.regionalKpiStats },\n bubbles: true,\n composed: true\n })\n )\n } catch (error) {\n console.error('Failed to fetch regional KPI stats:', error)\n this.regionalKpiStats = []\n }\n }\n\n async fetchMonthlyTrendData() {\n try {\n // selectedCategory에 따라 kpiName 결정\n const categoryToKpiName: Record<string, string | null> = {\n '전체 KPI': null,\n '일정 성과': 'Y1. 일정성과',\n '비용 성과': 'Y2. 비용성과',\n '품질 성과': 'Y3. 품질성과',\n '안전 성과': 'Y4. 안전성과',\n '환경 성과': 'Y5. 환경성과',\n '생산성 성과': 'Y6. 생산성성과'\n }\n\n const kpiName = categoryToKpiName[this.selectedCategory]\n\n const response = await client.query({\n query: gql`\n query GetMonthlyTrendData($kpiName: String, $startYearMonth: String, $endYearMonth: String) {\n kpiZValueMonthlyTrendByGeoGroup(kpiName: $kpiName, startYearMonth: $startYearMonth, endYearMonth: $endYearMonth) {\n geoGroup\n yearMonth\n avgVal\n projectCount\n }\n }\n `,\n variables: {\n kpiName,\n startYearMonth: this.startYearMonth,\n endYearMonth: this.endYearMonth\n }\n })\n\n this.monthlyTrendData = response.data.kpiZValueMonthlyTrendByGeoGroup || []\n console.log('Monthly Trend Data:', this.monthlyTrendData)\n\n // 부모에게 월별 추이 데이터 전달\n this.dispatchEvent(\n new CustomEvent('monthly-trend-data-loaded', {\n detail: { data: this.monthlyTrendData },\n bubbles: true,\n composed: true\n })\n )\n } catch (error) {\n console.error('Failed to fetch monthly trend data:', error)\n this.monthlyTrendData = []\n }\n }\n\n private getRegionTrendData(region: string): number[] {\n // 해당 지역의 최근 12개월 트렌드 데이터 추출\n const regionData = this.monthlyTrendData\n .filter(d => d.geoGroup === region)\n .sort((a, b) => a.yearMonth.localeCompare(b.yearMonth))\n .map(d => d.avgVal * 100) // 20배 스케일\n\n // 12개월 데이터가 없으면 빈 배열 반환\n return regionData.length > 0 ? regionData : []\n }\n\n private calculateChangeRate(region: string): number {\n // 해당 지역의 월별 데이터를 시간순으로 정렬\n const regionData = this.monthlyTrendData\n .filter(d => d.geoGroup === region)\n .sort((a, b) => a.yearMonth.localeCompare(b.yearMonth))\n\n if (regionData.length < 2) return 0\n\n // 가장 오래된 달과 가장 최근 달의 값 비교\n const oldestValue = regionData[0].avgVal\n const latestValue = regionData[regionData.length - 1].avgVal\n\n if (oldestValue === 0) return 0\n\n // 변동율 계산: (최근값 - 과거값) / 과거값 * 100\n return ((latestValue - oldestValue) / oldestValue) * 100\n }\n\n private generateChartData() {\n // KPI 이름을 카테고리로 매핑 및 축약\n const categoryMapping: Record<string, string> = {\n 'Y1. 일정성과': '일정',\n 'Y2. 비용성과': '비용',\n 'Y3. 품질성과': '품질',\n 'Y4. 안전성과': '안전',\n 'Y5. 환경성과': '환경',\n 'Y6. 생산성성과': '생산성'\n }\n\n console.log('generateChartData - selectedChartType:', this.selectedChartType)\n console.log('generateChartData - kpiYComprehensiveStats:', this.kpiYComprehensiveStats)\n\n if (this.selectedChartType === 'radar') {\n // 레이더 차트용 데이터 생성 (전체 평균만 표시)\n const data: Array<{ org: string; category: string; value: number }> = []\n const categories: string[] = []\n\n this.kpiYComprehensiveStats.forEach(stat => {\n const category = categoryMapping[stat.kpiName] || stat.kpiName\n if (!categories.includes(category)) {\n categories.push(category)\n }\n\n // 전체 평균 데이터만 표시 (비교 시리즈 없음)\n data.push({\n org: '전체평균',\n category,\n value: Math.round(stat.avgVal * 100)\n })\n })\n\n this.chartCategories = categories.length > 0 ? categories : ['일정', '비용', '품질', '안전', '환경', '생산성']\n this.chartData = data\n console.log('Radar chart data:', data)\n console.log('Radar chart categories:', this.chartCategories)\n } else {\n // 박스플롯용 데이터 생성 (sv-project-detail.ts의 getYKpiBoxplotData 참조)\n const data: Array<{\n org: string\n min: number\n max: number\n q1: number\n q3: number\n median: number\n mean: number\n value: number\n }> = []\n const categories: string[] = []\n\n this.kpiYComprehensiveStats.forEach(stat => {\n const category = categoryMapping[stat.kpiName] || stat.kpiName\n if (!categories.includes(category)) {\n categories.push(category)\n }\n data.push({\n org: category,\n min: stat.minVal * 100,\n max: stat.maxVal * 100,\n q1: stat.q1Val * 100,\n q3: stat.q3Val * 100,\n median: stat.medVal * 100,\n mean: stat.avgVal * 100,\n value: stat.avgVal * 100\n })\n })\n\n this.chartCategories = categories.length > 0 ? categories : ['일정', '비용', '품질', '안전', '환경', '생산성']\n this.chartData = data\n console.log('Boxplot chart data:', data)\n console.log('Boxplot chart categories:', this.chartCategories)\n }\n }\n\n private onCategoryChange(event: Event) {\n const target = event.target as HTMLSelectElement\n this.selectedCategory = target.value\n\n // 카테고리 변경 시 지역별 통계와 월별 추이 데이터만 다시 가져오기\n // 종합 성과(박스플롯/레이더)는 항상 전체 Y-level KPI를 표시\n this.fetchRegionalKpiStats()\n this.fetchMonthlyTrendData()\n\n this.dispatchEvent(\n new CustomEvent('category-change', {\n detail: { category: target.value },\n bubbles: true,\n composed: true\n })\n )\n }\n\n private onChartTypeChange(type: string) {\n this.selectedChartType = type\n this.generateChartData()\n }\n\n private onRegionClick(region: string) {\n this.dispatchEvent(\n new CustomEvent('region-click', {\n detail: { region },\n bubbles: true,\n composed: true\n })\n )\n }\n\n private downloadExcel() {\n this.dispatchEvent(\n new CustomEvent('download-excel', {\n bubbles: true,\n composed: true\n })\n )\n }\n\n // regionOrder에 따라 지역 데이터를 정렬\n private getSortedRegionData() {\n // 실제 데이터를 기반으로 각 시도에 대한 데이터 생성\n return this.regionOrder.map(regionName => {\n const stat = this.regionalKpiStats.find(s => s.geoGroup === regionName)\n const changeRate = this.calculateChangeRate(regionName)\n return {\n region: regionName,\n kpi: stat ? (stat.avgVal * 100).toFixed(1) : '-',\n change: changeRate.toFixed(2),\n trendData: this.getRegionTrendData(regionName),\n lat: 36.5,\n lng: 127.5\n }\n })\n }\n\n private getChangeRateClass(change: number): string {\n if (change > 0) return 'change-up'\n if (change < 0) return 'change-down'\n return 'change-neutral'\n }\n\n private getChangeIcon(change: number): string {\n if (change > 0) return '▲'\n if (change < 0) return '▼'\n return '─'\n }\n\n render() {\n return html`\n <div class=\"panel-header\">\n <div class=\"panel-title\">전국 KPI</div>\n <button class=\"panel-close\" style=\"visibility: hidden;\">×</button>\n </div>\n <div class=\"panel-content\">\n <!-- KPI 카테고리 선택 -->\n <select class=\"category-select\" .value=${this.selectedCategory} @change=${this.onCategoryChange}>\n <option value=\"전체 KPI\">전체 KPI</option>\n <option value=\"일정 성과\">일정 성과</option>\n <option value=\"비용 성과\">비용 성과</option>\n <option value=\"품질 성과\">품질 성과</option>\n <option value=\"안전 성과\">안전 성과</option>\n <option value=\"환경 성과\">환경 성과</option>\n <option value=\"생산성 성과\">생산성 성과</option>\n </select>\n\n <!-- 종합 성과 -->\n <div class=\"chart-section\">\n <div class=\"sub-title\">종합 성과</div>\n <div class=\"chart-toggle\">\n <button\n class=\"toggle-button ${this.selectedChartType === 'boxplot' ? 'active' : ''}\"\n @click=${() => this.onChartTypeChange('boxplot')}\n >\n 박스플롯\n </button>\n <button\n class=\"toggle-button ${this.selectedChartType === 'radar' ? 'active' : ''}\"\n @click=${() => this.onChartTypeChange('radar')}\n >\n 레이더차트\n </button>\n </div>\n <div class=\"chart-container\">\n ${this.selectedChartType === 'boxplot'\n ? html` <sv-kpi-boxplot-chart .data=${this.chartData} .valueKey=${'value'}></sv-kpi-boxplot-chart> `\n : html`\n <sv-kpi-radar-chart\n .data=${this.chartData}\n .categories=${this.chartCategories}\n .valueKey=${'value'}\n ></sv-kpi-radar-chart>\n `}\n </div>\n </div>\n\n <!-- 시도별 성과 -->\n <div class=\"chart-section\">\n <div class=\"sub-title\">시도별 성과</div>\n <table class=\"performance-table\">\n <thead>\n <tr>\n <th>지역명</th>\n <th>KPI</th>\n <th>변동률(%)</th>\n <th>성과 추이</th>\n </tr>\n </thead>\n <tbody>\n ${this.getSortedRegionData().map(\n (item: any) => html`\n <tr\n style=\"cursor: pointer; transition: background-color 0.2s;\"\n @click=${() => this.onRegionClick(item.region)}\n @mouseenter=${(e: Event) => ((e.target as HTMLElement).style.backgroundColor = '#f8f9fa')}\n @mouseleave=${(e: Event) => ((e.target as HTMLElement).style.backgroundColor = '')}\n >\n <td>${item.region}</td>\n <td>${item.kpi}</td>\n <td>\n <div class=\"change-rate ${this.getChangeRateClass(item.change)}\">\n ${this.getChangeIcon(item.change)}${Math.abs(item.change)}%\n </div>\n </td>\n <td>\n ${item.trendData && item.trendData.length > 0\n ? html`\n <sv-kpi-mini-trend-chart\n .data=${item.trendData}\n .width=${60}\n .height=${30}\n .lineColor=${'#2196f3'}\n .strokeWidth=${1.5}\n .showPoints=${true}\n .pointRadius=${1.5}\n ></sv-kpi-mini-trend-chart>\n `\n : html`<span style=\"color: #999;\">-</span>`}\n </td>\n </tr>\n `\n )}\n </tbody>\n </table>\n <button class=\"download-button\" @click=${this.downloadExcel}>📊 엑셀 다운로드</button>\n </div>\n </div>\n `\n }\n}\n"]}
1
+ {"version":3,"file":"kpi-left-panel.js","sourceRoot":"","sources":["../../../../client/pages/kpi-dashboard/components/kpi-left-panel.ts"],"names":[],"mappings":"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","sourcesContent":["import gql from 'graphql-tag'\nimport { LitElement, html, css } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { ScrollbarStyles } from '@operato/styles'\nimport { client } from '@operato/graphql'\n\nimport '../../../components/kpi-radar-chart.js'\nimport '../../../components/kpi-boxplot-chart.js'\nimport '../../../components/kpi-mini-trend-chart.js'\n\n@customElement('kpi-left-panel')\nexport class KpiLeftPanel extends LitElement {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: block;\n width: 400px;\n background: #fff;\n border-right: 1px solid #e0e0e0;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);\n }\n .panel-content {\n padding: 20px;\n overflow-y: auto;\n flex: 1;\n }\n .panel-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 20px;\n border-bottom: 1px solid #e0e0e0;\n background: #fff;\n height: 70px;\n box-sizing: border-box;\n }\n .panel-title {\n font-size: 1.3rem;\n font-weight: bold;\n color: #333;\n margin: 0;\n }\n .panel-close {\n width: 32px;\n height: 32px;\n border: none;\n background: #fff;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.2rem;\n color: #666;\n transition: all 0.2s;\n }\n .panel-close:hover {\n background: #e9ecef;\n color: #333;\n }\n .sub-title {\n font-size: 1rem;\n font-weight: 600;\n margin-bottom: 16px;\n color: #495057;\n }\n .chart-section {\n background: #f8f9fa;\n border-radius: 8px;\n padding: 16px;\n margin-bottom: 20px;\n }\n .chart-toggle {\n display: flex;\n gap: 8px;\n margin-bottom: 16px;\n }\n .toggle-button {\n padding: 8px 16px;\n border: 1px solid #ced4da;\n background: #fff;\n border-radius: 6px;\n cursor: pointer;\n font-size: 0.9rem;\n transition: all 0.2s;\n }\n .toggle-button.active {\n background: #667eea;\n color: white;\n border-color: #667eea;\n }\n .chart-container {\n height: 300px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: white;\n border-radius: 6px;\n border: 1px solid #e9ecef;\n }\n .performance-table {\n width: 100%;\n border-collapse: collapse;\n margin-top: 16px;\n }\n .performance-table th,\n .performance-table td {\n padding: 12px 8px;\n text-align: left;\n border-bottom: 1px solid #e9ecef;\n }\n .performance-table th {\n background: #f8f9fa;\n font-weight: 600;\n color: #495057;\n }\n .performance-table td {\n color: #333;\n }\n .change-rate {\n display: flex;\n align-items: center;\n gap: 4px;\n }\n .change-up {\n color: #dc3545;\n }\n .change-down {\n color: #198754;\n }\n .change-neutral {\n color: #6c757d;\n }\n .trend-chart {\n width: 60px;\n height: 30px;\n background: #f8f9fa;\n border-radius: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 0.8rem;\n color: #666;\n }\n .download-button {\n margin-top: 16px;\n padding: 8px 16px;\n background: #28a745;\n color: white;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n font-size: 0.9rem;\n display: flex;\n align-items: center;\n gap: 8px;\n }\n .download-button:hover {\n background: #218838;\n }\n .filter-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 6px;\n margin-bottom: 10px;\n }\n .filter-label {\n font-size: 0.75rem;\n font-weight: 600;\n color: #495057;\n white-space: nowrap;\n }\n .filter-select {\n flex: 1;\n min-width: 0;\n padding: 4px 6px;\n border: 1px solid #ced4da;\n border-radius: 4px;\n background: white;\n font-size: 0.78rem;\n }\n .filter-select:focus {\n outline: none;\n border-color: #667eea;\n }\n `\n ]\n\n @property({ type: String }) selectedCategory = '전체 KPI'\n @property({ type: String }) selectedChartType = 'boxplot'\n @property({ type: Array }) mapData: any[] = []\n @property({ type: String }) startYearMonth = '' // YYYY-MM 형식\n @property({ type: String }) endYearMonth = '' // YYYY-MM 형식\n @property({ type: String }) sectorType = ''\n @property({ type: String }) buildingUsage = ''\n\n @state() private isAllPeriod = false\n @state() private chartData: any[] = []\n @state() private chartCategories: string[] = []\n @state() private kpiYComprehensiveStats: any[] = []\n @state() private regionalKpiStats: any[] = []\n @state() private monthlyTrendData: any[] = []\n\n // 행정안전부 행정구역코드 순서\n private readonly regionOrder = [\n '서울특별시',\n '부산광역시',\n '대구광역시',\n '인천광역시',\n '광주광역시',\n '대전광역시',\n '울산광역시',\n '세종특별자치시',\n '경기도',\n '강원도',\n '충청북도',\n '충청남도',\n '전라북도',\n '전라남도',\n '경상북도',\n '경상남도',\n '제주특별자치도'\n ]\n\n connectedCallback() {\n super.connectedCallback()\n // 기간 초기값이 비어있으면 현재 월 기준 12개월로 설정\n if (!this.startYearMonth || !this.endYearMonth) {\n const now = new Date()\n const end = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`\n const start = new Date(now)\n start.setMonth(start.getMonth() - 11)\n const startStr = `${start.getFullYear()}-${String(start.getMonth() + 1).padStart(2, '0')}`\n this.startYearMonth = startStr\n this.endYearMonth = end\n }\n this.fetchKpiYComprehensiveStats()\n this.fetchRegionalKpiStats()\n this.fetchMonthlyTrendData()\n }\n\n updated(changedProperties: Map<string, any>) {\n // selectedCategory, startYearMonth, endYearMonth가 변경되면 데이터 다시 가져오기\n if (\n changedProperties.has('selectedCategory') ||\n changedProperties.has('startYearMonth') ||\n changedProperties.has('endYearMonth') ||\n changedProperties.has('sectorType') ||\n changedProperties.has('buildingUsage')\n ) {\n // 기간 정보가 설정되어 있을 때만 조회 (빈 문자열이면 전체 기간)\n if (this.startYearMonth !== undefined && this.endYearMonth !== undefined) {\n this.fetchKpiYComprehensiveStats()\n this.fetchRegionalKpiStats()\n this.fetchMonthlyTrendData()\n }\n }\n }\n\n async fetchKpiYComprehensiveStats() {\n try {\n const response = await client.query({\n query: gql`\n query GetKpiYValueComprehensiveStats(\n $startYearMonth: String\n $endYearMonth: String\n $sectorType: String\n $buildingUsage: String\n ) {\n totalKpiYValueComprehensiveStats(\n startYearMonth: $startYearMonth\n endYearMonth: $endYearMonth\n sectorType: $sectorType\n buildingUsage: $buildingUsage\n ) {\n kpiName\n minVal\n q1Val\n medVal\n q3Val\n maxVal\n avgVal\n }\n }\n `,\n variables: {\n startYearMonth: this.startYearMonth,\n endYearMonth: this.endYearMonth,\n sectorType: this.sectorType || null,\n buildingUsage: this.buildingUsage || null\n }\n })\n\n this.kpiYComprehensiveStats = response.data.totalKpiYValueComprehensiveStats || []\n console.log('KPI Y-Value Comprehensive Stats:', this.kpiYComprehensiveStats)\n\n // 부모에게 전체 Y-level KPI 통계 전달\n this.dispatchEvent(\n new CustomEvent('total-kpi-y-stats-loaded', {\n detail: { data: this.kpiYComprehensiveStats },\n bubbles: true,\n composed: true\n })\n )\n\n this.generateChartData()\n } catch (error) {\n console.error('Failed to fetch KPI Y comprehensive stats:', error)\n this.kpiYComprehensiveStats = []\n this.generateChartData()\n }\n }\n\n async fetchRegionalKpiStats() {\n try {\n // selectedCategory에 따라 kpiName 결정\n const categoryToKpiName: Record<string, string | null> = {\n '전체 KPI': null,\n '일정 성과': 'Y1. 일정성과',\n '비용 성과': 'Y2. 비용성과',\n '품질 성과': 'Y3. 품질성과',\n '안전 성과': 'Y4. 안전성과',\n '환경 성과': 'Y5. 환경성과',\n '생산성 성과': 'Y6. 생산성성과'\n }\n\n const kpiName = categoryToKpiName[this.selectedCategory]\n\n const response = await client.query({\n query: gql`\n query GetRegionalKpiStats(\n $kpiName: String\n $startYearMonth: String\n $endYearMonth: String\n $sectorType: String\n $buildingUsage: String\n ) {\n kpiZValueComprehensiveStatsByGeoGroup(\n kpiName: $kpiName\n startYearMonth: $startYearMonth\n endYearMonth: $endYearMonth\n sectorType: $sectorType\n buildingUsage: $buildingUsage\n ) {\n geoGroup\n avgVal\n minVal\n maxVal\n projectCount\n }\n }\n `,\n variables: {\n kpiName,\n startYearMonth: this.startYearMonth,\n endYearMonth: this.endYearMonth,\n sectorType: this.sectorType || null,\n buildingUsage: this.buildingUsage || null\n }\n })\n\n this.regionalKpiStats = response.data.kpiZValueComprehensiveStatsByGeoGroup || []\n console.log('Regional KPI Stats:', this.regionalKpiStats)\n\n // 부모에게 지역별 KPI 통계 전달\n this.dispatchEvent(\n new CustomEvent('regional-kpi-stats-loaded', {\n detail: { data: this.regionalKpiStats },\n bubbles: true,\n composed: true\n })\n )\n } catch (error) {\n console.error('Failed to fetch regional KPI stats:', error)\n this.regionalKpiStats = []\n }\n }\n\n async fetchMonthlyTrendData() {\n try {\n // selectedCategory에 따라 kpiName 결정\n const categoryToKpiName: Record<string, string | null> = {\n '전체 KPI': null,\n '일정 성과': 'Y1. 일정성과',\n '비용 성과': 'Y2. 비용성과',\n '품질 성과': 'Y3. 품질성과',\n '안전 성과': 'Y4. 안전성과',\n '환경 성과': 'Y5. 환경성과',\n '생산성 성과': 'Y6. 생산성성과'\n }\n\n const kpiName = categoryToKpiName[this.selectedCategory]\n\n const response = await client.query({\n query: gql`\n query GetMonthlyTrendData(\n $kpiName: String\n $startYearMonth: String\n $endYearMonth: String\n $sectorType: String\n $buildingUsage: String\n ) {\n kpiZValueMonthlyTrendByGeoGroup(\n kpiName: $kpiName\n startYearMonth: $startYearMonth\n endYearMonth: $endYearMonth\n sectorType: $sectorType\n buildingUsage: $buildingUsage\n ) {\n geoGroup\n yearMonth\n avgVal\n projectCount\n }\n }\n `,\n variables: {\n kpiName,\n startYearMonth: this.startYearMonth,\n endYearMonth: this.endYearMonth,\n sectorType: this.sectorType || null,\n buildingUsage: this.buildingUsage || null\n }\n })\n\n this.monthlyTrendData = response.data.kpiZValueMonthlyTrendByGeoGroup || []\n console.log('Monthly Trend Data:', this.monthlyTrendData)\n\n // 부모에게 월별 추이 데이터 전달\n this.dispatchEvent(\n new CustomEvent('monthly-trend-data-loaded', {\n detail: { data: this.monthlyTrendData },\n bubbles: true,\n composed: true\n })\n )\n } catch (error) {\n console.error('Failed to fetch monthly trend data:', error)\n this.monthlyTrendData = []\n }\n }\n\n private getRegionTrendData(region: string): number[] {\n // 해당 지역의 최근 12개월 트렌드 데이터 추출\n const regionData = this.monthlyTrendData\n .filter(d => d.geoGroup === region)\n .sort((a, b) => a.yearMonth.localeCompare(b.yearMonth))\n .map(d => d.avgVal * 100) // 20배 스케일\n\n // 12개월 데이터가 없으면 빈 배열 반환\n return regionData.length > 0 ? regionData : []\n }\n\n private calculateChangeRate(region: string): number {\n // 해당 지역의 월별 데이터를 시간순으로 정렬\n const regionData = this.monthlyTrendData\n .filter(d => d.geoGroup === region)\n .sort((a, b) => a.yearMonth.localeCompare(b.yearMonth))\n\n if (regionData.length < 2) return 0\n\n // 가장 오래된 달과 가장 최근 달의 값 비교\n const oldestValue = regionData[0].avgVal\n const latestValue = regionData[regionData.length - 1].avgVal\n\n if (oldestValue === 0) return 0\n\n // 변동율 계산: (최근값 - 과거값) / 과거값 * 100\n return ((latestValue - oldestValue) / oldestValue) * 100\n }\n\n private generateChartData() {\n // KPI 이름을 카테고리로 매핑 및 축약\n const categoryMapping: Record<string, string> = {\n 'Y1. 일정성과': '일정',\n 'Y2. 비용성과': '비용',\n 'Y3. 품질성과': '품질',\n 'Y4. 안전성과': '안전',\n 'Y5. 환경성과': '환경',\n 'Y6. 생산성성과': '생산성'\n }\n\n console.log('generateChartData - selectedChartType:', this.selectedChartType)\n console.log('generateChartData - kpiYComprehensiveStats:', this.kpiYComprehensiveStats)\n\n if (this.selectedChartType === 'radar') {\n // 레이더 차트용 데이터 생성 (전체 평균만 표시)\n const data: Array<{ org: string; category: string; value: number }> = []\n const categories: string[] = []\n\n this.kpiYComprehensiveStats.forEach(stat => {\n const category = categoryMapping[stat.kpiName] || stat.kpiName\n if (!categories.includes(category)) {\n categories.push(category)\n }\n\n // 전체 평균 데이터만 표시 (비교 시리즈 없음)\n data.push({\n org: '전체평균',\n category,\n value: Math.round(stat.avgVal * 100)\n })\n })\n\n this.chartCategories = categories.length > 0 ? categories : ['일정', '비용', '품질', '안전', '환경', '생산성']\n this.chartData = data\n console.log('Radar chart data:', data)\n console.log('Radar chart categories:', this.chartCategories)\n } else {\n // 박스플롯용 데이터 생성 (sv-project-detail.ts의 getYKpiBoxplotData 참조)\n const data: Array<{\n org: string\n min: number\n max: number\n q1: number\n q3: number\n median: number\n mean: number\n value: number\n }> = []\n const categories: string[] = []\n\n this.kpiYComprehensiveStats.forEach(stat => {\n const category = categoryMapping[stat.kpiName] || stat.kpiName\n if (!categories.includes(category)) {\n categories.push(category)\n }\n data.push({\n org: category,\n min: stat.minVal * 100,\n max: stat.maxVal * 100,\n q1: stat.q1Val * 100,\n q3: stat.q3Val * 100,\n median: stat.medVal * 100,\n mean: stat.avgVal * 100,\n value: stat.avgVal * 100\n })\n })\n\n this.chartCategories = categories.length > 0 ? categories : ['일정', '비용', '품질', '안전', '환경', '생산성']\n this.chartData = data\n console.log('Boxplot chart data:', data)\n console.log('Boxplot chart categories:', this.chartCategories)\n }\n }\n\n private _onAllPeriodChange(e: Event) {\n this.isAllPeriod = (e.target as HTMLInputElement).checked\n if (this.isAllPeriod) {\n this.startYearMonth = ''\n this.endYearMonth = ''\n }\n }\n\n private onCategoryChange(event: Event) {\n const target = event.target as HTMLSelectElement\n this.selectedCategory = target.value\n\n // 카테고리 변경 시 지역별 통계와 월별 추이 데이터만 다시 가져오기\n // 종합 성과(박스플롯/레이더)는 항상 전체 Y-level KPI를 표시\n this.fetchRegionalKpiStats()\n this.fetchMonthlyTrendData()\n\n this.dispatchEvent(\n new CustomEvent('category-change', {\n detail: { category: target.value },\n bubbles: true,\n composed: true\n })\n )\n }\n\n private onChartTypeChange(type: string) {\n this.selectedChartType = type\n this.generateChartData()\n }\n\n private onRegionClick(region: string) {\n // 지도를 해당 광역시도로 포커스\n this.dispatchEvent(\n new CustomEvent('focus-region', {\n detail: { region },\n bubbles: true,\n composed: true\n })\n )\n // 팝업 열기\n this.dispatchEvent(\n new CustomEvent('region-click', {\n detail: { region },\n bubbles: true,\n composed: true\n })\n )\n }\n\n private downloadExcel() {\n import('xlsx').then(XLSX => {\n const filterLabel = [\n this.selectedCategory,\n this.sectorType === 'PUBLIC' ? '공공' : this.sectorType === 'PRIVATE' ? '민간' : '',\n this.buildingUsage === 'RESIDENTIAL' ? '주거' : this.buildingUsage === 'NON_RESIDENTIAL' ? '비주거' : ''\n ]\n .filter(Boolean)\n .join('_')\n\n const period = this.isAllPeriod ? '전체기간' : `${this.startYearMonth}~${this.endYearMonth}`\n const wb = XLSX.utils.book_new()\n\n // Sheet 1: 검색 조건\n const condData = [\n { 항목: 'KPI 카테고리', 값: this.selectedCategory },\n { 항목: '사업 유형', 값: this.sectorType === 'PUBLIC' ? '공공' : this.sectorType === 'PRIVATE' ? '민간' : '전체' },\n { 항목: '건물 용도', 값: this.buildingUsage === 'RESIDENTIAL' ? '주거' : this.buildingUsage === 'NON_RESIDENTIAL' ? '비주거' : '전체' },\n { 항목: '기간', 값: this.isAllPeriod ? '전체 기간' : `${this.startYearMonth} ~ ${this.endYearMonth}` },\n { 항목: '다운로드 일시', 값: new Date().toLocaleString('ko-KR') }\n ]\n const wsCond = XLSX.utils.json_to_sheet(condData)\n wsCond['!cols'] = [{ wch: 16 }, { wch: 30 }]\n XLSX.utils.book_append_sheet(wb, wsCond, '검색 조건')\n\n // Sheet 2: 종합 성과\n const yData = this.kpiYComprehensiveStats.map((s: any) => ({\n KPI: s.kpiName,\n 최소: Number((s.minVal * 100).toFixed(2)),\n Q1: Number((s.q1Val * 100).toFixed(2)),\n 중앙값: Number((s.medVal * 100).toFixed(2)),\n Q3: Number((s.q3Val * 100).toFixed(2)),\n 최대: Number((s.maxVal * 100).toFixed(2)),\n 평균: Number((s.avgVal * 100).toFixed(2))\n }))\n const ws1 = XLSX.utils.json_to_sheet(yData)\n ws1['!cols'] = [{ wch: 20 }, { wch: 10 }, { wch: 10 }, { wch: 10 }, { wch: 10 }, { wch: 10 }, { wch: 10 }]\n XLSX.utils.book_append_sheet(wb, ws1, '종합 성과')\n\n // Sheet 2: 시도별 성과\n const rData = this.getSortedRegionData().map((item: any) => {\n const stat = this.regionalKpiStats.find((s: any) => s.geoGroup === item.region)\n return {\n 지역: item.region,\n 'KPI 점수': Number(item.kpi) || 0,\n '변동률(%)': Number(Number(item.change).toFixed(2)),\n 프로젝트수: stat?.projectCount ?? 0\n }\n })\n const ws2 = XLSX.utils.json_to_sheet(rData)\n ws2['!cols'] = [{ wch: 16 }, { wch: 12 }, { wch: 12 }, { wch: 12 }]\n XLSX.utils.book_append_sheet(wb, ws2, '시도별 성과')\n\n // Sheet 3: 월별 추이\n if (this.monthlyTrendData.length > 0) {\n const mData = this.monthlyTrendData.map((d: any) => ({\n 지역: d.geoGroup,\n 기간: d.yearMonth,\n 평균: Number((d.avgVal * 100).toFixed(2)),\n 프로젝트수: d.projectCount\n }))\n const ws3 = XLSX.utils.json_to_sheet(mData)\n ws3['!cols'] = [{ wch: 16 }, { wch: 12 }, { wch: 10 }, { wch: 12 }]\n XLSX.utils.book_append_sheet(wb, ws3, '월별 추이')\n }\n\n XLSX.writeFile(wb, `KPI_대시보드_${filterLabel}_${period}.xlsx`)\n })\n }\n\n // regionOrder에 따라 지역 데이터를 정렬\n private getSortedRegionData() {\n // 실제 데이터를 기반으로 각 시도에 대한 데이터 생성\n return this.regionOrder.map(regionName => {\n const stat = this.regionalKpiStats.find(s => s.geoGroup === regionName)\n const changeRate = this.calculateChangeRate(regionName)\n return {\n region: regionName,\n kpi: stat ? (stat.avgVal * 100).toFixed(1) : '-',\n change: changeRate.toFixed(2),\n trendData: this.getRegionTrendData(regionName),\n lat: 36.5,\n lng: 127.5\n }\n })\n }\n\n private getChangeRateClass(change: number): string {\n if (change > 0) return 'change-up'\n if (change < 0) return 'change-down'\n return 'change-neutral'\n }\n\n private getChangeIcon(change: number): string {\n if (change > 0) return '▲'\n if (change < 0) return '▼'\n return '─'\n }\n\n render() {\n return html`\n <div class=\"panel-header\">\n <div class=\"panel-title\">전국 KPI</div>\n <button class=\"panel-close\" style=\"visibility: hidden;\">×</button>\n </div>\n <div class=\"panel-content\">\n <!-- 필터: KPI / 사업유형 / 건물용도 -->\n <div class=\"filter-row\">\n <span class=\"filter-label\">KPI</span>\n <select class=\"filter-select\" .value=${this.selectedCategory} @change=${this.onCategoryChange}>\n <option value=\"전체 KPI\">전체 KPI</option>\n <option value=\"일정 성과\">일정</option>\n <option value=\"비용 성과\">비용</option>\n <option value=\"품질 성과\">품질</option>\n <option value=\"안전 성과\">안전</option>\n <option value=\"환경 성과\">환경</option>\n <option value=\"생산성 성과\">생산성</option>\n </select>\n <span class=\"filter-label\">유형</span>\n <select\n class=\"filter-select\"\n .value=${this.sectorType}\n @change=${(e: Event) => {\n this.sectorType = (e.target as HTMLSelectElement).value\n }}\n >\n <option value=\"\">전체</option>\n <option value=\"PUBLIC\">공공</option>\n <option value=\"PRIVATE\">민간</option>\n </select>\n <span class=\"filter-label\">용도</span>\n <select\n class=\"filter-select\"\n .value=${this.buildingUsage}\n @change=${(e: Event) => {\n this.buildingUsage = (e.target as HTMLSelectElement).value\n }}\n >\n <option value=\"\">전체</option>\n <option value=\"RESIDENTIAL\">주거</option>\n <option value=\"NON_RESIDENTIAL\">비주거</option>\n </select>\n </div>\n\n <!-- 기간 필터 -->\n <div class=\"filter-row\">\n <span class=\"filter-label\">기간</span>\n <select class=\"filter-select\" ?disabled=${this.isAllPeriod} @change=${(e: Event) => {\n const y = (e.target as HTMLSelectElement).value\n const m = this.startYearMonth.split('-')[1] || '01'\n this.startYearMonth = `${y}-${m}`\n }}>\n ${[2022, 2023, 2024, 2025, 2026].map(\n y => html`<option value=\"${y}\" ?selected=${this.startYearMonth.startsWith(String(y))}>${y}</option>`\n )}\n </select>\n <select class=\"filter-select\" ?disabled=${this.isAllPeriod} @change=${(e: Event) => {\n const y = this.startYearMonth.split('-')[0] || '2025'\n const m = (e.target as HTMLSelectElement).value.padStart(2, '0')\n this.startYearMonth = `${y}-${m}`\n }}>\n ${[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].map(\n m => html`<option value=\"${m}\" ?selected=${parseInt(this.startYearMonth.split('-')[1]) === m}>${m}월</option>`\n )}\n </select>\n <span style=\"color:#6c757d;font-size:0.8rem;\">~</span>\n <select class=\"filter-select\" ?disabled=${this.isAllPeriod} @change=${(e: Event) => {\n const y = (e.target as HTMLSelectElement).value\n const m = this.endYearMonth.split('-')[1] || '12'\n this.endYearMonth = `${y}-${m}`\n }}>\n ${[2022, 2023, 2024, 2025, 2026].map(\n y => html`<option value=\"${y}\" ?selected=${this.endYearMonth.startsWith(String(y))}>${y}</option>`\n )}\n </select>\n <select class=\"filter-select\" ?disabled=${this.isAllPeriod} @change=${(e: Event) => {\n const y = this.endYearMonth.split('-')[0] || '2026'\n const m = (e.target as HTMLSelectElement).value.padStart(2, '0')\n this.endYearMonth = `${y}-${m}`\n }}>\n ${[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].map(\n m => html`<option value=\"${m}\" ?selected=${parseInt(this.endYearMonth.split('-')[1]) === m}>${m}월</option>`\n )}\n </select>\n <label style=\"display:flex;align-items:center;gap:3px;cursor:pointer;\">\n <input type=\"checkbox\" .checked=${this.isAllPeriod} @change=${this._onAllPeriodChange} style=\"cursor:pointer;\" />\n <span class=\"filter-label\" style=\"min-width:auto;\">전체</span>\n </label>\n </div>\n\n <!-- 종합 성과 -->\n <div class=\"chart-section\">\n <div class=\"sub-title\">종합 성과</div>\n <div class=\"chart-toggle\">\n <button\n class=\"toggle-button ${this.selectedChartType === 'boxplot' ? 'active' : ''}\"\n @click=${() => this.onChartTypeChange('boxplot')}\n >\n 박스플롯\n </button>\n <button\n class=\"toggle-button ${this.selectedChartType === 'radar' ? 'active' : ''}\"\n @click=${() => this.onChartTypeChange('radar')}\n >\n 레이더차트\n </button>\n </div>\n <div class=\"chart-container\">\n ${this.selectedChartType === 'boxplot'\n ? html` <sv-kpi-boxplot-chart .data=${this.chartData} .valueKey=${'value'}></sv-kpi-boxplot-chart> `\n : html`\n <sv-kpi-radar-chart\n .data=${this.chartData}\n .categories=${this.chartCategories}\n .valueKey=${'value'}\n ></sv-kpi-radar-chart>\n `}\n </div>\n </div>\n\n <!-- 시도별 성과 -->\n <div class=\"chart-section\">\n <div class=\"sub-title\">시도별 성과</div>\n <table class=\"performance-table\">\n <thead>\n <tr>\n <th>지역명</th>\n <th>KPI</th>\n <th>변동률(%)</th>\n <th>성과 추이</th>\n </tr>\n </thead>\n <tbody>\n ${this.getSortedRegionData().map(\n (item: any) => html`\n <tr\n style=\"cursor: pointer; transition: background-color 0.2s;\"\n @click=${() => this.onRegionClick(item.region)}\n @mouseenter=${(e: Event) => ((e.target as HTMLElement).style.backgroundColor = '#f8f9fa')}\n @mouseleave=${(e: Event) => ((e.target as HTMLElement).style.backgroundColor = '')}\n >\n <td>${item.region}</td>\n <td>${item.kpi}</td>\n <td>\n <div class=\"change-rate ${this.getChangeRateClass(item.change)}\">\n ${this.getChangeIcon(item.change)}${Math.abs(item.change)}%\n </div>\n </td>\n <td>\n ${item.trendData && item.trendData.length > 0\n ? html`\n <sv-kpi-mini-trend-chart\n .data=${item.trendData}\n .width=${60}\n .height=${30}\n .lineColor=${'#2196f3'}\n .strokeWidth=${1.5}\n .showPoints=${true}\n .pointRadius=${1.5}\n ></sv-kpi-mini-trend-chart>\n `\n : html`<span style=\"color: #999;\">-</span>`}\n </td>\n </tr>\n `\n )}\n </tbody>\n </table>\n <button class=\"download-button\" @click=${this.downloadExcel}>📊 엑셀 다운로드</button>\n </div>\n </div>\n `\n }\n}\n"]}
@@ -8,7 +8,10 @@ declare global {
8
8
  export declare class KpiMapPanel extends LitElement {
9
9
  static styles: import("lit").CSSResult;
10
10
  selectedCategory: string;
11
+ sectorType: string;
12
+ buildingUsage: string;
11
13
  mapData: any[];
14
+ private static readonly DEFAULT_CENTER;
12
15
  private map;
13
16
  private isAllPeriod;
14
17
  private startYear;
@@ -30,6 +33,7 @@ export declare class KpiMapPanel extends LitElement {
30
33
  private onMapChange;
31
34
  private fitBoundsToSouthKorea;
32
35
  private onRegionClick;
36
+ focusOnLocation(lat: number, lng: number, zoom: number): void;
33
37
  private zoomIn;
34
38
  private zoomOut;
35
39
  private resetView;