@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.
- package/_index.html +0 -5
- package/dist-client/components/kpi-2d-lookup-chart.d.ts +63 -0
- package/dist-client/components/kpi-2d-lookup-chart.js +470 -0
- package/dist-client/components/kpi-2d-lookup-chart.js.map +1 -0
- package/dist-client/google-map/common-google-map.js +10 -8
- package/dist-client/google-map/common-google-map.js.map +1 -1
- package/dist-client/pages/kpi-admin/dssp-kpi-list-page.d.ts +22 -0
- package/dist-client/pages/kpi-admin/dssp-kpi-list-page.js +57 -0
- package/dist-client/pages/kpi-admin/dssp-kpi-list-page.js.map +1 -0
- package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.d.ts +20 -0
- package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.js +445 -0
- package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.d.ts +6 -5
- package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js +47 -68
- package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js.map +1 -1
- package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.d.ts +3 -2
- package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js +79 -122
- package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js.map +1 -1
- package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.d.ts +3 -2
- package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js +71 -107
- package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js.map +1 -1
- package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.d.ts +4 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js +246 -28
- package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js.map +1 -1
- package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.d.ts +4 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js +22 -207
- package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js.map +1 -1
- package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.d.ts +2 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js +84 -25
- package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js.map +1 -1
- package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.d.ts +16 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js +261 -31
- package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js.map +1 -1
- package/dist-client/pages/kpi-dashboard/kpi-dashboard.d.ts +4 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard.js +66 -4
- package/dist-client/pages/kpi-dashboard/kpi-dashboard.js.map +1 -1
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.d.ts +1 -2
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js +1 -2
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js.map +1 -1
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.d.ts +1 -2
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js +1 -2
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js.map +1 -1
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.d.ts +1 -2
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js +1 -2
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js.map +1 -1
- package/dist-client/pages/kpi-value/kpi-value-list-page.d.ts +1 -2
- package/dist-client/pages/kpi-value/kpi-value-list-page.js +1 -2
- package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -1
- package/dist-client/pages/sv-project-detail.d.ts +1 -0
- package/dist-client/pages/sv-project-detail.js +26 -13
- package/dist-client/pages/sv-project-detail.js.map +1 -1
- package/dist-client/pages/sv-project-list.js +6 -6
- package/dist-client/pages/sv-project-list.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/route.js +4 -0
- package/dist-client/route.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/viewparts/menu-tools.d.ts +1 -2
- package/dist-client/viewparts/menu-tools.js +1 -2
- package/dist-client/viewparts/menu-tools.js.map +1 -1
- package/dist-server/scripts/calculate-kpi-scores.js +65 -3
- package/dist-server/scripts/calculate-kpi-scores.js.map +1 -1
- package/dist-server/scripts/load-grade-data-migration.d.ts +4 -0
- package/dist-server/scripts/load-grade-data-migration.js +95 -10
- package/dist-server/scripts/load-grade-data-migration.js.map +1 -1
- package/dist-server/scripts/propagate-parent-kpi-values.js +58 -4
- package/dist-server/scripts/propagate-parent-kpi-values.js.map +1 -1
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.d.ts +6 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +57 -7
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -1
- package/dist-server/service/kpi-stat/kpi-stat-query.d.ts +8 -5
- package/dist-server/service/kpi-stat/kpi-stat-query.js +228 -11
- package/dist-server/service/kpi-stat/kpi-stat-query.js.map +1 -1
- package/dist-server/service/kpi-stat/kpi-stat-types.d.ts +13 -0
- package/dist-server/service/kpi-stat/kpi-stat-types.js +51 -1
- package/dist-server/service/kpi-stat/kpi-stat-types.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +54 -54
- package/schema.graphql +95 -58
- package/things-factory.config.js +3 -1
- package/views/auth-page.html +0 -1
- package/views/public/home.html +0 -1
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
var KpiMapPanel_1;
|
|
1
2
|
import { __decorate, __metadata } from "tslib";
|
|
2
3
|
import { LitElement, html, css } from 'lit';
|
|
3
4
|
import { customElement, property, state } from 'lit/decorators.js';
|
|
4
5
|
import '../../../google-map/common-google-map.js';
|
|
5
|
-
let KpiMapPanel = class KpiMapPanel extends LitElement {
|
|
6
|
+
let KpiMapPanel = KpiMapPanel_1 = class KpiMapPanel extends LitElement {
|
|
6
7
|
constructor() {
|
|
7
8
|
super(...arguments);
|
|
8
9
|
this.selectedCategory = '전체 KPI';
|
|
10
|
+
this.sectorType = '';
|
|
11
|
+
this.buildingUsage = '';
|
|
9
12
|
this.mapData = [];
|
|
10
13
|
this.map = null;
|
|
11
14
|
this.isAllPeriod = false; // 전체 기간 체크박스
|
|
@@ -130,6 +133,12 @@ let KpiMapPanel = class KpiMapPanel extends LitElement {
|
|
|
130
133
|
composed: true
|
|
131
134
|
}));
|
|
132
135
|
}
|
|
136
|
+
focusOnLocation(lat, lng, zoom) {
|
|
137
|
+
if (this.map) {
|
|
138
|
+
this.map.setCenter({ lat, lng });
|
|
139
|
+
this.map.setZoom(zoom);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
133
142
|
zoomIn() {
|
|
134
143
|
if (this.map) {
|
|
135
144
|
this.map.setZoom(this.map.getZoom() + 1);
|
|
@@ -160,138 +169,6 @@ let KpiMapPanel = class KpiMapPanel extends LitElement {
|
|
|
160
169
|
}
|
|
161
170
|
render() {
|
|
162
171
|
return html `
|
|
163
|
-
<div class="map-overlay">
|
|
164
|
-
<div class="category-buttons">
|
|
165
|
-
<button
|
|
166
|
-
class="category-button ${this.selectedCategory === '전체 KPI' ? 'active' : ''}"
|
|
167
|
-
@click=${() => this.onCategoryButtonClick('전체 KPI')}
|
|
168
|
-
>
|
|
169
|
-
전체 KPI
|
|
170
|
-
</button>
|
|
171
|
-
<button
|
|
172
|
-
class="category-button ${this.selectedCategory === '일정 성과' ? 'active' : ''}"
|
|
173
|
-
@click=${() => this.onCategoryButtonClick('일정 성과')}
|
|
174
|
-
>
|
|
175
|
-
일정 성과
|
|
176
|
-
</button>
|
|
177
|
-
<button
|
|
178
|
-
class="category-button ${this.selectedCategory === '비용 성과' ? 'active' : ''}"
|
|
179
|
-
@click=${() => this.onCategoryButtonClick('비용 성과')}
|
|
180
|
-
>
|
|
181
|
-
비용 성과
|
|
182
|
-
</button>
|
|
183
|
-
<button
|
|
184
|
-
class="category-button ${this.selectedCategory === '품질 성과' ? 'active' : ''}"
|
|
185
|
-
@click=${() => this.onCategoryButtonClick('품질 성과')}
|
|
186
|
-
>
|
|
187
|
-
품질 성과
|
|
188
|
-
</button>
|
|
189
|
-
<button
|
|
190
|
-
class="category-button ${this.selectedCategory === '안전 성과' ? 'active' : ''}"
|
|
191
|
-
@click=${() => this.onCategoryButtonClick('안전 성과')}
|
|
192
|
-
>
|
|
193
|
-
안전 성과
|
|
194
|
-
</button>
|
|
195
|
-
<button
|
|
196
|
-
class="category-button ${this.selectedCategory === '환경 성과' ? 'active' : ''}"
|
|
197
|
-
@click=${() => this.onCategoryButtonClick('환경 성과')}
|
|
198
|
-
>
|
|
199
|
-
환경 성과
|
|
200
|
-
</button>
|
|
201
|
-
<button
|
|
202
|
-
class="category-button ${this.selectedCategory === '생산성 성과' ? 'active' : ''}"
|
|
203
|
-
@click=${() => this.onCategoryButtonClick('생산성 성과')}
|
|
204
|
-
>
|
|
205
|
-
생산성 성과
|
|
206
|
-
</button>
|
|
207
|
-
</div>
|
|
208
|
-
|
|
209
|
-
<!-- 기간 선택 폼 -->
|
|
210
|
-
<div class="period-form">
|
|
211
|
-
<div class="period-row">
|
|
212
|
-
<span class="period-label">기간:</span>
|
|
213
|
-
<select
|
|
214
|
-
class="period-select"
|
|
215
|
-
.value=${this.startYear}
|
|
216
|
-
?disabled=${this.isAllPeriod}
|
|
217
|
-
@change=${(e) => {
|
|
218
|
-
this.startYear = e.target.value;
|
|
219
|
-
this.onPeriodChange();
|
|
220
|
-
}}
|
|
221
|
-
>
|
|
222
|
-
<option value="2025">2025년</option>
|
|
223
|
-
<option value="2024">2024년</option>
|
|
224
|
-
<option value="2023">2023년</option>
|
|
225
|
-
<option value="2022">2022년</option>
|
|
226
|
-
</select>
|
|
227
|
-
<select
|
|
228
|
-
class="period-select"
|
|
229
|
-
.value=${this.startMonth}
|
|
230
|
-
?disabled=${this.isAllPeriod}
|
|
231
|
-
@change=${(e) => {
|
|
232
|
-
this.startMonth = e.target.value;
|
|
233
|
-
this.onPeriodChange();
|
|
234
|
-
}}
|
|
235
|
-
>
|
|
236
|
-
<option value="1">1월</option>
|
|
237
|
-
<option value="2">2월</option>
|
|
238
|
-
<option value="3">3월</option>
|
|
239
|
-
<option value="4">4월</option>
|
|
240
|
-
<option value="5">5월</option>
|
|
241
|
-
<option value="6">6월</option>
|
|
242
|
-
<option value="7">7월</option>
|
|
243
|
-
<option value="8">8월</option>
|
|
244
|
-
<option value="9">9월</option>
|
|
245
|
-
<option value="10">10월</option>
|
|
246
|
-
<option value="11">11월</option>
|
|
247
|
-
<option value="12">12월</option>
|
|
248
|
-
</select>
|
|
249
|
-
<span class="period-separator">~</span>
|
|
250
|
-
<select
|
|
251
|
-
class="period-select"
|
|
252
|
-
.value=${this.endYear}
|
|
253
|
-
?disabled=${this.isAllPeriod}
|
|
254
|
-
@change=${(e) => {
|
|
255
|
-
this.endYear = e.target.value;
|
|
256
|
-
this.onPeriodChange();
|
|
257
|
-
}}
|
|
258
|
-
>
|
|
259
|
-
<option value="2025">2025년</option>
|
|
260
|
-
<option value="2024">2024년</option>
|
|
261
|
-
<option value="2023">2023년</option>
|
|
262
|
-
<option value="2022">2022년</option>
|
|
263
|
-
</select>
|
|
264
|
-
<select
|
|
265
|
-
class="period-select"
|
|
266
|
-
.value=${this.endMonth}
|
|
267
|
-
?disabled=${this.isAllPeriod}
|
|
268
|
-
@change=${(e) => {
|
|
269
|
-
this.endMonth = e.target.value;
|
|
270
|
-
this.onPeriodChange();
|
|
271
|
-
}}
|
|
272
|
-
>
|
|
273
|
-
<option value="1">1월</option>
|
|
274
|
-
<option value="2">2월</option>
|
|
275
|
-
<option value="3">3월</option>
|
|
276
|
-
<option value="4">4월</option>
|
|
277
|
-
<option value="5">5월</option>
|
|
278
|
-
<option value="6">6월</option>
|
|
279
|
-
<option value="7">7월</option>
|
|
280
|
-
<option value="8">8월</option>
|
|
281
|
-
<option value="9">9월</option>
|
|
282
|
-
<option value="10">10월</option>
|
|
283
|
-
<option value="11">11월</option>
|
|
284
|
-
<option value="12">12월</option>
|
|
285
|
-
</select>
|
|
286
|
-
|
|
287
|
-
<label style="display: flex; align-items: center; gap: 6px; cursor: pointer;">
|
|
288
|
-
<input type="checkbox" .checked=${this.isAllPeriod} @change=${this.onAllPeriodChange} style="cursor: pointer;" />
|
|
289
|
-
<span class="period-label" style="min-width: auto;">전체 기간</span>
|
|
290
|
-
</label>
|
|
291
|
-
</div>
|
|
292
|
-
</div>
|
|
293
|
-
</div>
|
|
294
|
-
|
|
295
172
|
<div class="map-container">
|
|
296
173
|
<!-- 지도 컨트롤 (오른쪽 상단) -->
|
|
297
174
|
<div class="map-controls">
|
|
@@ -308,10 +185,10 @@ let KpiMapPanel = class KpiMapPanel extends LitElement {
|
|
|
308
185
|
|
|
309
186
|
<!-- 공통 Google Maps 컴포넌트 사용 -->
|
|
310
187
|
<common-google-map
|
|
311
|
-
.center=${
|
|
188
|
+
.center=${KpiMapPanel_1.DEFAULT_CENTER}
|
|
312
189
|
.zoom=${7.2}
|
|
313
190
|
.locations=${this.mapLocations}
|
|
314
|
-
.clusterZoom=${
|
|
191
|
+
.clusterZoom=${13}
|
|
315
192
|
.controls=${{
|
|
316
193
|
zoomControl: false,
|
|
317
194
|
mapTypeControl: false,
|
|
@@ -335,77 +212,6 @@ KpiMapPanel.styles = css `
|
|
|
335
212
|
position: relative;
|
|
336
213
|
min-height: 500px;
|
|
337
214
|
}
|
|
338
|
-
.map-overlay {
|
|
339
|
-
position: absolute;
|
|
340
|
-
top: 16px;
|
|
341
|
-
left: 16px;
|
|
342
|
-
z-index: 10;
|
|
343
|
-
background: rgba(255, 255, 255, 0.95);
|
|
344
|
-
border-radius: 8px;
|
|
345
|
-
padding: 12px 16px;
|
|
346
|
-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
347
|
-
backdrop-filter: blur(4px);
|
|
348
|
-
}
|
|
349
|
-
.category-buttons {
|
|
350
|
-
display: flex;
|
|
351
|
-
gap: 8px;
|
|
352
|
-
flex-wrap: wrap;
|
|
353
|
-
}
|
|
354
|
-
.category-button {
|
|
355
|
-
padding: 6px 12px;
|
|
356
|
-
border: 1px solid #ced4da;
|
|
357
|
-
background: #fff;
|
|
358
|
-
border-radius: 4px;
|
|
359
|
-
cursor: pointer;
|
|
360
|
-
font-size: 0.85rem;
|
|
361
|
-
transition: all 0.2s;
|
|
362
|
-
white-space: nowrap;
|
|
363
|
-
}
|
|
364
|
-
.category-button.active {
|
|
365
|
-
background: #667eea;
|
|
366
|
-
color: white;
|
|
367
|
-
border-color: #667eea;
|
|
368
|
-
}
|
|
369
|
-
.category-button:hover {
|
|
370
|
-
background: #f8f9fa;
|
|
371
|
-
}
|
|
372
|
-
.category-button.active:hover {
|
|
373
|
-
background: #5a6fd8;
|
|
374
|
-
}
|
|
375
|
-
.period-form {
|
|
376
|
-
margin-top: 12px;
|
|
377
|
-
padding-top: 12px;
|
|
378
|
-
border-top: 1px solid #e9ecef;
|
|
379
|
-
}
|
|
380
|
-
.period-row {
|
|
381
|
-
display: flex;
|
|
382
|
-
align-items: center;
|
|
383
|
-
gap: 8px;
|
|
384
|
-
margin-bottom: 8px;
|
|
385
|
-
}
|
|
386
|
-
.period-label {
|
|
387
|
-
font-size: 0.85rem;
|
|
388
|
-
font-weight: 600;
|
|
389
|
-
color: #495057;
|
|
390
|
-
min-width: 40px;
|
|
391
|
-
}
|
|
392
|
-
.period-select {
|
|
393
|
-
padding: 4px 8px;
|
|
394
|
-
border: 1px solid #ced4da;
|
|
395
|
-
border-radius: 4px;
|
|
396
|
-
background: white;
|
|
397
|
-
font-size: 0.8rem;
|
|
398
|
-
cursor: pointer;
|
|
399
|
-
}
|
|
400
|
-
.period-select:focus {
|
|
401
|
-
outline: none;
|
|
402
|
-
border-color: #667eea;
|
|
403
|
-
}
|
|
404
|
-
.period-separator {
|
|
405
|
-
font-size: 0.85rem;
|
|
406
|
-
color: #6c757d;
|
|
407
|
-
margin: 0 4px;
|
|
408
|
-
}
|
|
409
215
|
.map-container {
|
|
410
216
|
flex: 1;
|
|
411
217
|
position: relative;
|
|
@@ -462,10 +268,19 @@ KpiMapPanel.styles = css `
|
|
|
462
268
|
height: 100%;
|
|
463
269
|
}
|
|
464
270
|
`;
|
|
271
|
+
KpiMapPanel.DEFAULT_CENTER = { lat: 36.0, lng: 127.8 };
|
|
465
272
|
__decorate([
|
|
466
273
|
property({ type: String }),
|
|
467
274
|
__metadata("design:type", Object)
|
|
468
275
|
], KpiMapPanel.prototype, "selectedCategory", void 0);
|
|
276
|
+
__decorate([
|
|
277
|
+
property({ type: String }),
|
|
278
|
+
__metadata("design:type", Object)
|
|
279
|
+
], KpiMapPanel.prototype, "sectorType", void 0);
|
|
280
|
+
__decorate([
|
|
281
|
+
property({ type: String }),
|
|
282
|
+
__metadata("design:type", Object)
|
|
283
|
+
], KpiMapPanel.prototype, "buildingUsage", void 0);
|
|
469
284
|
__decorate([
|
|
470
285
|
property({ type: Array }),
|
|
471
286
|
__metadata("design:type", Array)
|
|
@@ -494,7 +309,7 @@ __decorate([
|
|
|
494
309
|
state(),
|
|
495
310
|
__metadata("design:type", Object)
|
|
496
311
|
], KpiMapPanel.prototype, "endMonth", void 0);
|
|
497
|
-
KpiMapPanel = __decorate([
|
|
312
|
+
KpiMapPanel = KpiMapPanel_1 = __decorate([
|
|
498
313
|
customElement('kpi-map-panel')
|
|
499
314
|
], KpiMapPanel);
|
|
500
315
|
export { KpiMapPanel };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kpi-map-panel.js","sourceRoot":"","sources":["../../../../client/pages/kpi-dashboard/components/kpi-map-panel.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, html, css, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport '../../../google-map/common-google-map.js'\n\ndeclare global {\n interface Window {\n google: any\n }\n}\n\n@customElement('kpi-map-panel')\nexport class KpiMapPanel extends LitElement {\n static styles = css`\n :host {\n display: flex;\n background: #f8f9fa;\n overflow: hidden;\n position: relative;\n min-height: 500px;\n }\n .map-overlay {\n position: absolute;\n top: 16px;\n left: 16px;\n z-index: 10;\n background: rgba(255, 255, 255, 0.95);\n border-radius: 8px;\n padding: 12px 16px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n backdrop-filter: blur(4px);\n }\n .category-buttons {\n display: flex;\n gap: 8px;\n flex-wrap: wrap;\n }\n .category-button {\n padding: 6px 12px;\n border: 1px solid #ced4da;\n background: #fff;\n border-radius: 4px;\n cursor: pointer;\n font-size: 0.85rem;\n transition: all 0.2s;\n white-space: nowrap;\n }\n .category-button.active {\n background: #667eea;\n color: white;\n border-color: #667eea;\n }\n .category-button:hover {\n background: #f8f9fa;\n }\n .category-button.active:hover {\n background: #5a6fd8;\n }\n .period-form {\n margin-top: 12px;\n padding-top: 12px;\n border-top: 1px solid #e9ecef;\n }\n .period-row {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 8px;\n }\n .period-label {\n font-size: 0.85rem;\n font-weight: 600;\n color: #495057;\n min-width: 40px;\n }\n .period-select {\n padding: 4px 8px;\n border: 1px solid #ced4da;\n border-radius: 4px;\n background: white;\n font-size: 0.8rem;\n cursor: pointer;\n }\n .period-select:focus {\n outline: none;\n border-color: #667eea;\n }\n .period-separator {\n font-size: 0.85rem;\n color: #6c757d;\n margin: 0 4px;\n }\n .map-container {\n flex: 1;\n position: relative;\n overflow: hidden;\n }\n .map-controls {\n position: absolute;\n top: 16px;\n right: 16px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n z-index: 10;\n }\n .map-control-button {\n width: 40px;\n height: 40px;\n background: white;\n border: 1px solid #ced4da;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.2rem;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n }\n .map-control-button:hover {\n background: #f8f9fa;\n }\n .map-scale-direction {\n position: absolute;\n bottom: 16px;\n right: 16px;\n background: white;\n padding: 8px 12px;\n border-radius: 6px;\n border: 1px solid #ced4da;\n font-size: 0.8rem;\n color: #666;\n z-index: 10;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n text-align: center;\n }\n .north-arrow {\n font-size: 1rem;\n margin-bottom: 4px;\n }\n .scale-info {\n font-size: 0.7rem;\n }\n common-google-map {\n width: 100%;\n height: 100%;\n }\n `\n\n @property({ type: String }) selectedCategory = '전체 KPI'\n @property({ type: Array }) mapData: any[] = []\n\n @state() private map: any = null\n @state() private isAllPeriod = false // 전체 기간 체크박스\n @state() private startYear = ''\n @state() private startMonth = ''\n @state() private endYear = ''\n @state() private endMonth = ''\n\n connectedCallback() {\n super.connectedCallback()\n this.initializeDefaultPeriod()\n }\n\n private initializeDefaultPeriod() {\n const now = new Date()\n const currentYear = now.getFullYear()\n const currentMonth = now.getMonth() + 1 // 0-based이므로 +1\n\n // 12개월 전 계산\n const startDate = new Date(now)\n startDate.setMonth(startDate.getMonth() - 11) // 현재 월 포함 12개월\n const startYear = startDate.getFullYear()\n const startMonth = startDate.getMonth() + 1\n\n this.startYear = startYear.toString()\n this.startMonth = startMonth.toString()\n this.endYear = currentYear.toString()\n this.endMonth = currentMonth.toString()\n }\n\n private onAllPeriodChange(e: Event) {\n this.isAllPeriod = (e.target as HTMLInputElement).checked\n this.onPeriodChange()\n }\n\n // mapData를 지도 마커 형식으로 변환\n get mapLocations() {\n return (\n this.mapData?.map(item => ({\n lat: item.lat,\n lng: item.lng,\n title: item.region,\n region: item.region, // 지역명 추가\n // 커스텀 마커 콘텐츠 생성\n markerContent: `\n <div style=\"\n background: white;\n border-radius: 8px;\n padding: 8px 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n border: 1px solid #e9ecef;\n min-width: 80px;\n text-align: center;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n cursor: pointer;\n \">\n <div style=\"\n font-size: 11px;\n font-weight: 600;\n color: #495057;\n margin-bottom: 2px;\n white-space: nowrap;\n \">${item.region}</div>\n <div style=\"\n font-size: 13px;\n font-weight: 700;\n color: #212529;\n margin-bottom: 2px;\n \">${item.kpi}</div>\n <div style=\"\n font-size: 10px;\n color: ${item.change > 0 ? '#dc3545' : '#198754'};\n font-weight: 500;\n \">${item.change > 0 ? '▲' : '▼'} ${Math.abs(item.change)}%</div>\n </div>\n `,\n content: `\n <div style=\"padding: 12px; min-width: 200px;\">\n <h3 style=\"margin: 0 0 8px 0; font-size: 16px; color: #212529;\">${item.region}</h3>\n <div style=\"margin-bottom: 8px;\">\n <span style=\"font-size: 14px; color: #6c757d;\">KPI: </span>\n <span style=\"font-size: 16px; font-weight: 600; color: #212529;\">${item.kpi}</span>\n </div>\n <div style=\"\n font-size: 14px;\n color: ${item.change > 0 ? '#dc3545' : '#198754'};\n font-weight: 500;\n \">\n ${item.change > 0 ? '▲' : '▼'} ${Math.abs(item.change)}% 변화\n </div>\n </div>\n `\n })) || []\n )\n }\n\n private onCategoryButtonClick(category: string) {\n this.dispatchEvent(\n new CustomEvent('category-change', {\n detail: { category },\n bubbles: true,\n composed: true\n })\n )\n }\n\n private onMapChange(event: CustomEvent) {\n this.map = event.detail\n // 지도가 로드되면 남한 영역에 맞게 자동 조정\n this.fitBoundsToSouthKorea()\n }\n\n private fitBoundsToSouthKorea() {\n if (!this.map || !window.google) return\n\n // 남한의 실제 행정구역 경계 설정 (울릉도/독도 제외)\n const bounds = new window.google.maps.LatLngBounds()\n\n // 최북단: 강원도 고성 (DMZ 남쪽)\n bounds.extend(new window.google.maps.LatLng(38.3, 128.3))\n // 최남단: 제주도 남쪽\n bounds.extend(new window.google.maps.LatLng(33.1, 126.3))\n // 최서단: 전남 서쪽\n bounds.extend(new window.google.maps.LatLng(34.5, 125.1))\n // 최동단: 강원도 동해안\n bounds.extend(new window.google.maps.LatLng(37.5, 129.4))\n\n // 패딩을 추가하여 여유 공간 확보\n this.map.fitBounds(bounds, { top: 30, bottom: 30, left: 30, right: 30 })\n }\n\n private onRegionClick(event: CustomEvent) {\n this.dispatchEvent(\n new CustomEvent('region-click', {\n detail: event.detail,\n bubbles: true,\n composed: true\n })\n )\n }\n\n private zoomIn() {\n if (this.map) {\n this.map.setZoom(this.map.getZoom() + 1)\n }\n }\n\n private zoomOut() {\n if (this.map) {\n this.map.setZoom(this.map.getZoom() - 1)\n }\n }\n\n private resetView() {\n if (this.map) {\n this.fitBoundsToSouthKorea()\n }\n }\n\n private onPeriodChange() {\n this.dispatchEvent(\n new CustomEvent('period-change', {\n detail: {\n startYear: this.isAllPeriod ? null : this.startYear,\n startMonth: this.isAllPeriod ? null : this.startMonth,\n endYear: this.isAllPeriod ? null : this.endYear,\n endMonth: this.isAllPeriod ? null : this.endMonth,\n isAllPeriod: this.isAllPeriod\n },\n bubbles: true,\n composed: true\n })\n )\n }\n\n render() {\n return html`\n <div class=\"map-overlay\">\n <div class=\"category-buttons\">\n <button\n class=\"category-button ${this.selectedCategory === '전체 KPI' ? 'active' : ''}\"\n @click=${() => this.onCategoryButtonClick('전체 KPI')}\n >\n 전체 KPI\n </button>\n <button\n class=\"category-button ${this.selectedCategory === '일정 성과' ? 'active' : ''}\"\n @click=${() => this.onCategoryButtonClick('일정 성과')}\n >\n 일정 성과\n </button>\n <button\n class=\"category-button ${this.selectedCategory === '비용 성과' ? 'active' : ''}\"\n @click=${() => this.onCategoryButtonClick('비용 성과')}\n >\n 비용 성과\n </button>\n <button\n class=\"category-button ${this.selectedCategory === '품질 성과' ? 'active' : ''}\"\n @click=${() => this.onCategoryButtonClick('품질 성과')}\n >\n 품질 성과\n </button>\n <button\n class=\"category-button ${this.selectedCategory === '안전 성과' ? 'active' : ''}\"\n @click=${() => this.onCategoryButtonClick('안전 성과')}\n >\n 안전 성과\n </button>\n <button\n class=\"category-button ${this.selectedCategory === '환경 성과' ? 'active' : ''}\"\n @click=${() => this.onCategoryButtonClick('환경 성과')}\n >\n 환경 성과\n </button>\n <button\n class=\"category-button ${this.selectedCategory === '생산성 성과' ? 'active' : ''}\"\n @click=${() => this.onCategoryButtonClick('생산성 성과')}\n >\n 생산성 성과\n </button>\n </div>\n\n <!-- 기간 선택 폼 -->\n <div class=\"period-form\">\n <div class=\"period-row\">\n <span class=\"period-label\">기간:</span>\n <select\n class=\"period-select\"\n .value=${this.startYear}\n ?disabled=${this.isAllPeriod}\n @change=${(e: Event) => {\n this.startYear = (e.target as HTMLSelectElement).value\n this.onPeriodChange()\n }}\n >\n <option value=\"2025\">2025년</option>\n <option value=\"2024\">2024년</option>\n <option value=\"2023\">2023년</option>\n <option value=\"2022\">2022년</option>\n </select>\n <select\n class=\"period-select\"\n .value=${this.startMonth}\n ?disabled=${this.isAllPeriod}\n @change=${(e: Event) => {\n this.startMonth = (e.target as HTMLSelectElement).value\n this.onPeriodChange()\n }}\n >\n <option value=\"1\">1월</option>\n <option value=\"2\">2월</option>\n <option value=\"3\">3월</option>\n <option value=\"4\">4월</option>\n <option value=\"5\">5월</option>\n <option value=\"6\">6월</option>\n <option value=\"7\">7월</option>\n <option value=\"8\">8월</option>\n <option value=\"9\">9월</option>\n <option value=\"10\">10월</option>\n <option value=\"11\">11월</option>\n <option value=\"12\">12월</option>\n </select>\n <span class=\"period-separator\">~</span>\n <select\n class=\"period-select\"\n .value=${this.endYear}\n ?disabled=${this.isAllPeriod}\n @change=${(e: Event) => {\n this.endYear = (e.target as HTMLSelectElement).value\n this.onPeriodChange()\n }}\n >\n <option value=\"2025\">2025년</option>\n <option value=\"2024\">2024년</option>\n <option value=\"2023\">2023년</option>\n <option value=\"2022\">2022년</option>\n </select>\n <select\n class=\"period-select\"\n .value=${this.endMonth}\n ?disabled=${this.isAllPeriod}\n @change=${(e: Event) => {\n this.endMonth = (e.target as HTMLSelectElement).value\n this.onPeriodChange()\n }}\n >\n <option value=\"1\">1월</option>\n <option value=\"2\">2월</option>\n <option value=\"3\">3월</option>\n <option value=\"4\">4월</option>\n <option value=\"5\">5월</option>\n <option value=\"6\">6월</option>\n <option value=\"7\">7월</option>\n <option value=\"8\">8월</option>\n <option value=\"9\">9월</option>\n <option value=\"10\">10월</option>\n <option value=\"11\">11월</option>\n <option value=\"12\">12월</option>\n </select>\n\n <label style=\"display: flex; align-items: center; gap: 6px; cursor: pointer;\">\n <input type=\"checkbox\" .checked=${this.isAllPeriod} @change=${this.onAllPeriodChange} style=\"cursor: pointer;\" />\n <span class=\"period-label\" style=\"min-width: auto;\">전체 기간</span>\n </label>\n </div>\n </div>\n </div>\n\n <div class=\"map-container\">\n <!-- 지도 컨트롤 (오른쪽 상단) -->\n <div class=\"map-controls\">\n <button class=\"map-control-button\" title=\"확대\" @click=${() => this.zoomIn()}>+</button>\n <button class=\"map-control-button\" title=\"축소\" @click=${() => this.zoomOut()}>-</button>\n <button class=\"map-control-button\" title=\"뷰 초기화\" @click=${() => this.resetView()}>⌖</button>\n </div>\n\n <!-- 스케일 및 방향 정보 (오른쪽 하단) -->\n <div class=\"map-scale-direction\">\n <div class=\"north-arrow\">↑ N</div>\n <div class=\"scale-info\">25km</div>\n </div>\n\n <!-- 공통 Google Maps 컴포넌트 사용 -->\n <common-google-map\n .center=${{ lat: 36.0, lng: 127.8 }}\n .zoom=${7.2}\n .locations=${this.mapLocations}\n .clusterZoom=${10}\n .controls=${{\n zoomControl: false,\n mapTypeControl: false,\n scaleControl: false,\n streetViewControl: false,\n rotateControl: false,\n fullscreenControl: false\n }}\n @map-change=${this.onMapChange}\n @region-click=${this.onRegionClick}\n ></common-google-map>\n </div>\n `\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"kpi-map-panel.js","sourceRoot":"","sources":["../../../../client/pages/kpi-dashboard/components/kpi-map-panel.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, html, css, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport '../../../google-map/common-google-map.js'\n\ndeclare global {\n interface Window {\n google: any\n }\n}\n\n@customElement('kpi-map-panel')\nexport class KpiMapPanel extends LitElement {\n static styles = css`\n :host {\n display: flex;\n background: #f8f9fa;\n overflow: hidden;\n position: relative;\n min-height: 500px;\n }\n .map-container {\n flex: 1;\n position: relative;\n overflow: hidden;\n }\n .map-controls {\n position: absolute;\n top: 16px;\n right: 16px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n z-index: 10;\n }\n .map-control-button {\n width: 40px;\n height: 40px;\n background: white;\n border: 1px solid #ced4da;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.2rem;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n }\n .map-control-button:hover {\n background: #f8f9fa;\n }\n .map-scale-direction {\n position: absolute;\n bottom: 16px;\n right: 16px;\n background: white;\n padding: 8px 12px;\n border-radius: 6px;\n border: 1px solid #ced4da;\n font-size: 0.8rem;\n color: #666;\n z-index: 10;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n text-align: center;\n }\n .north-arrow {\n font-size: 1rem;\n margin-bottom: 4px;\n }\n .scale-info {\n font-size: 0.7rem;\n }\n common-google-map {\n width: 100%;\n height: 100%;\n }\n `\n\n @property({ type: String }) selectedCategory = '전체 KPI'\n @property({ type: String }) sectorType = ''\n @property({ type: String }) buildingUsage = ''\n @property({ type: Array }) mapData: any[] = []\n\n private static readonly DEFAULT_CENTER = { lat: 36.0, lng: 127.8 }\n\n @state() private map: any = null\n @state() private isAllPeriod = false // 전체 기간 체크박스\n @state() private startYear = ''\n @state() private startMonth = ''\n @state() private endYear = ''\n @state() private endMonth = ''\n\n connectedCallback() {\n super.connectedCallback()\n this.initializeDefaultPeriod()\n }\n\n private initializeDefaultPeriod() {\n const now = new Date()\n const currentYear = now.getFullYear()\n const currentMonth = now.getMonth() + 1 // 0-based이므로 +1\n\n // 12개월 전 계산\n const startDate = new Date(now)\n startDate.setMonth(startDate.getMonth() - 11) // 현재 월 포함 12개월\n const startYear = startDate.getFullYear()\n const startMonth = startDate.getMonth() + 1\n\n this.startYear = startYear.toString()\n this.startMonth = startMonth.toString()\n this.endYear = currentYear.toString()\n this.endMonth = currentMonth.toString()\n }\n\n private onAllPeriodChange(e: Event) {\n this.isAllPeriod = (e.target as HTMLInputElement).checked\n this.onPeriodChange()\n }\n\n // mapData를 지도 마커 형식으로 변환\n get mapLocations() {\n return (\n this.mapData?.map(item => ({\n lat: item.lat,\n lng: item.lng,\n title: item.region,\n region: item.region, // 지역명 추가\n // 커스텀 마커 콘텐츠 생성\n markerContent: `\n <div style=\"\n background: white;\n border-radius: 8px;\n padding: 8px 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n border: 1px solid #e9ecef;\n min-width: 80px;\n text-align: center;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n cursor: pointer;\n \">\n <div style=\"\n font-size: 11px;\n font-weight: 600;\n color: #495057;\n margin-bottom: 2px;\n white-space: nowrap;\n \">${item.region}</div>\n <div style=\"\n font-size: 13px;\n font-weight: 700;\n color: #212529;\n margin-bottom: 2px;\n \">${item.kpi}</div>\n <div style=\"\n font-size: 10px;\n color: ${item.change > 0 ? '#dc3545' : '#198754'};\n font-weight: 500;\n \">${item.change > 0 ? '▲' : '▼'} ${Math.abs(item.change)}%</div>\n </div>\n `,\n content: `\n <div style=\"padding: 12px; min-width: 200px;\">\n <h3 style=\"margin: 0 0 8px 0; font-size: 16px; color: #212529;\">${item.region}</h3>\n <div style=\"margin-bottom: 8px;\">\n <span style=\"font-size: 14px; color: #6c757d;\">KPI: </span>\n <span style=\"font-size: 16px; font-weight: 600; color: #212529;\">${item.kpi}</span>\n </div>\n <div style=\"\n font-size: 14px;\n color: ${item.change > 0 ? '#dc3545' : '#198754'};\n font-weight: 500;\n \">\n ${item.change > 0 ? '▲' : '▼'} ${Math.abs(item.change)}% 변화\n </div>\n </div>\n `\n })) || []\n )\n }\n\n private onCategoryButtonClick(category: string) {\n this.dispatchEvent(\n new CustomEvent('category-change', {\n detail: { category },\n bubbles: true,\n composed: true\n })\n )\n }\n\n private onMapChange(event: CustomEvent) {\n this.map = event.detail\n // 지도가 로드되면 남한 영역에 맞게 자동 조정\n this.fitBoundsToSouthKorea()\n }\n\n private fitBoundsToSouthKorea() {\n if (!this.map || !window.google) return\n\n // 남한의 실제 행정구역 경계 설정 (울릉도/독도 제외)\n const bounds = new window.google.maps.LatLngBounds()\n\n // 최북단: 강원도 고성 (DMZ 남쪽)\n bounds.extend(new window.google.maps.LatLng(38.3, 128.3))\n // 최남단: 제주도 남쪽\n bounds.extend(new window.google.maps.LatLng(33.1, 126.3))\n // 최서단: 전남 서쪽\n bounds.extend(new window.google.maps.LatLng(34.5, 125.1))\n // 최동단: 강원도 동해안\n bounds.extend(new window.google.maps.LatLng(37.5, 129.4))\n\n // 패딩을 추가하여 여유 공간 확보\n this.map.fitBounds(bounds, { top: 30, bottom: 30, left: 30, right: 30 })\n }\n\n private onRegionClick(event: CustomEvent) {\n this.dispatchEvent(\n new CustomEvent('region-click', {\n detail: event.detail,\n bubbles: true,\n composed: true\n })\n )\n }\n\n focusOnLocation(lat: number, lng: number, zoom: number) {\n if (this.map) {\n this.map.setCenter({ lat, lng })\n this.map.setZoom(zoom)\n }\n }\n\n private zoomIn() {\n if (this.map) {\n this.map.setZoom(this.map.getZoom() + 1)\n }\n }\n\n private zoomOut() {\n if (this.map) {\n this.map.setZoom(this.map.getZoom() - 1)\n }\n }\n\n private resetView() {\n if (this.map) {\n this.fitBoundsToSouthKorea()\n }\n }\n\n private onPeriodChange() {\n this.dispatchEvent(\n new CustomEvent('period-change', {\n detail: {\n startYear: this.isAllPeriod ? null : this.startYear,\n startMonth: this.isAllPeriod ? null : this.startMonth,\n endYear: this.isAllPeriod ? null : this.endYear,\n endMonth: this.isAllPeriod ? null : this.endMonth,\n isAllPeriod: this.isAllPeriod\n },\n bubbles: true,\n composed: true\n })\n )\n }\n\n render() {\n return html`\n <div class=\"map-container\">\n <!-- 지도 컨트롤 (오른쪽 상단) -->\n <div class=\"map-controls\">\n <button class=\"map-control-button\" title=\"확대\" @click=${() => this.zoomIn()}>+</button>\n <button class=\"map-control-button\" title=\"축소\" @click=${() => this.zoomOut()}>-</button>\n <button class=\"map-control-button\" title=\"뷰 초기화\" @click=${() => this.resetView()}>⌖</button>\n </div>\n\n <!-- 스케일 및 방향 정보 (오른쪽 하단) -->\n <div class=\"map-scale-direction\">\n <div class=\"north-arrow\">↑ N</div>\n <div class=\"scale-info\">25km</div>\n </div>\n\n <!-- 공통 Google Maps 컴포넌트 사용 -->\n <common-google-map\n .center=${KpiMapPanel.DEFAULT_CENTER}\n .zoom=${7.2}\n .locations=${this.mapLocations}\n .clusterZoom=${13}\n .controls=${{\n zoomControl: false,\n mapTypeControl: false,\n scaleControl: false,\n streetViewControl: false,\n rotateControl: false,\n fullscreenControl: false\n }}\n @map-change=${this.onMapChange}\n @region-click=${this.onRegionClick}\n ></common-google-map>\n </div>\n `\n }\n}\n"]}
|
|
@@ -5,6 +5,7 @@ import '../../../components/kpi-trend-chart.js';
|
|
|
5
5
|
export declare class KpiRegionPopup extends LitElement {
|
|
6
6
|
static styles: import("lit").CSSResult[];
|
|
7
7
|
selectedRegion: string | null;
|
|
8
|
+
geoGroup: string | null;
|
|
8
9
|
selectedCategory: string;
|
|
9
10
|
selectedChartType: string;
|
|
10
11
|
selectedPeriod: string;
|
|
@@ -19,6 +20,7 @@ export declare class KpiRegionPopup extends LitElement {
|
|
|
19
20
|
updated(changedProperties: Map<string, any>): void;
|
|
20
21
|
fetchRegionKpiStats(): Promise<void>;
|
|
21
22
|
private generateChartData;
|
|
23
|
+
private static readonly GEO_TO_METRO;
|
|
22
24
|
private generateTrendData;
|
|
23
25
|
private onClose;
|
|
24
26
|
private onChartTypeChange;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
var KpiRegionPopup_1;
|
|
1
2
|
import { __decorate, __metadata } from "tslib";
|
|
2
3
|
import gql from 'graphql-tag';
|
|
3
4
|
import { LitElement, html, css, nothing } from 'lit';
|
|
@@ -7,10 +8,11 @@ import { ScrollbarStyles } from '@operato/styles';
|
|
|
7
8
|
import '../../../components/kpi-radar-chart.js';
|
|
8
9
|
import '../../../components/kpi-boxplot-chart.js';
|
|
9
10
|
import '../../../components/kpi-trend-chart.js';
|
|
10
|
-
let KpiRegionPopup = class KpiRegionPopup extends LitElement {
|
|
11
|
+
let KpiRegionPopup = KpiRegionPopup_1 = class KpiRegionPopup extends LitElement {
|
|
11
12
|
constructor() {
|
|
12
13
|
super(...arguments);
|
|
13
14
|
this.selectedRegion = null;
|
|
15
|
+
this.geoGroup = null; // 시군구 geo_group 코드 (있으면 시군구 쿼리 사용)
|
|
14
16
|
this.selectedCategory = '전체 KPI';
|
|
15
17
|
this.selectedChartType = 'boxplot';
|
|
16
18
|
this.selectedPeriod = '월';
|
|
@@ -43,28 +45,58 @@ let KpiRegionPopup = class KpiRegionPopup extends LitElement {
|
|
|
43
45
|
if (!this.selectedRegion)
|
|
44
46
|
return;
|
|
45
47
|
try {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
48
|
+
let regionKpiStats;
|
|
49
|
+
if (this.geoGroup) {
|
|
50
|
+
// 시군구 모드: geo_group 코드로 조회
|
|
51
|
+
const response = await client.query({
|
|
52
|
+
query: gql `
|
|
53
|
+
query GetSigunguKpiStats($geoGroup: String!, $startYearMonth: String, $endYearMonth: String) {
|
|
54
|
+
kpiYValueStatsByGeoGroup(geoGroup: $geoGroup, startYearMonth: $startYearMonth, endYearMonth: $endYearMonth) {
|
|
55
|
+
kpiName
|
|
56
|
+
minVal
|
|
57
|
+
q1Val
|
|
58
|
+
medVal
|
|
59
|
+
q3Val
|
|
60
|
+
maxVal
|
|
61
|
+
avgVal
|
|
62
|
+
projectCount
|
|
63
|
+
}
|
|
58
64
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
`,
|
|
66
|
+
variables: {
|
|
67
|
+
geoGroup: this.geoGroup,
|
|
68
|
+
startYearMonth: this.startYearMonth,
|
|
69
|
+
endYearMonth: this.endYearMonth
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
regionKpiStats = response.data.kpiYValueStatsByGeoGroup || [];
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// 광역 모드: 광역시도 이름으로 조회
|
|
76
|
+
const response = await client.query({
|
|
77
|
+
query: gql `
|
|
78
|
+
query GetRegionKpiStats($metroArea: String!, $startYearMonth: String, $endYearMonth: String) {
|
|
79
|
+
kpiYValueStatsByMetroArea(metroArea: $metroArea, startYearMonth: $startYearMonth, endYearMonth: $endYearMonth) {
|
|
80
|
+
kpiName
|
|
81
|
+
minVal
|
|
82
|
+
q1Val
|
|
83
|
+
medVal
|
|
84
|
+
q3Val
|
|
85
|
+
maxVal
|
|
86
|
+
avgVal
|
|
87
|
+
projectCount
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
`,
|
|
91
|
+
variables: {
|
|
92
|
+
metroArea: this.selectedRegion,
|
|
93
|
+
startYearMonth: this.startYearMonth,
|
|
94
|
+
endYearMonth: this.endYearMonth
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
regionKpiStats = response.data.kpiYValueStatsByMetroArea || [];
|
|
98
|
+
}
|
|
99
|
+
this.regionKpiStats = regionKpiStats;
|
|
68
100
|
console.log('Region KPI Stats:', this.regionKpiStats);
|
|
69
101
|
this.generateChartData();
|
|
70
102
|
}
|
|
@@ -144,9 +176,12 @@ let KpiRegionPopup = class KpiRegionPopup extends LitElement {
|
|
|
144
176
|
generateTrendData() {
|
|
145
177
|
if (!this.selectedRegion)
|
|
146
178
|
return;
|
|
147
|
-
//
|
|
179
|
+
// 시군구 모드인 경우 소속 광역시도의 추이 데이터 사용
|
|
180
|
+
const trendRegion = this.geoGroup
|
|
181
|
+
? KpiRegionPopup_1.GEO_TO_METRO[this.geoGroup] || this.selectedRegion
|
|
182
|
+
: this.selectedRegion;
|
|
148
183
|
const regionTrendData = this.monthlyTrendData
|
|
149
|
-
.filter(d => d.geoGroup ===
|
|
184
|
+
.filter(d => d.geoGroup === trendRegion)
|
|
150
185
|
.sort((a, b) => a.yearMonth.localeCompare(b.yearMonth));
|
|
151
186
|
this.trendData = regionTrendData.map(d => {
|
|
152
187
|
const value = Math.round(d.avgVal * 100); // 20배 스케일
|
|
@@ -384,10 +419,34 @@ KpiRegionPopup.styles = [
|
|
|
384
419
|
}
|
|
385
420
|
`
|
|
386
421
|
];
|
|
422
|
+
// geo_group → 광역시도 매핑 (시군구 모드에서 추이 데이터 조회용)
|
|
423
|
+
KpiRegionPopup.GEO_TO_METRO = {
|
|
424
|
+
'01': '서울특별시', '02': '서울특별시', '03': '서울특별시', '04': '서울특별시',
|
|
425
|
+
'05': '서울특별시', '06': '서울특별시', '07': '서울특별시', '08': '서울특별시',
|
|
426
|
+
'10': '경기도', '11': '경기도', '12': '경기도', '13': '경기도', '14': '경기도',
|
|
427
|
+
'15': '경기도', '16': '경기도', '17': '경기도', '18': '경기도',
|
|
428
|
+
'21': '인천광역시', '22': '인천광역시', '23': '인천광역시',
|
|
429
|
+
'24': '강원도', '25': '강원도', '26': '강원도', '33': '강원도',
|
|
430
|
+
'27': '충청북도', '28': '충청북도', '29': '충청북도',
|
|
431
|
+
'30': '세종특별자치시', '31': '충청남도', '32': '충청남도',
|
|
432
|
+
'34': '대전광역시', '35': '대전광역시',
|
|
433
|
+
'36': '경상북도', '37': '경상북도', '38': '경상북도', '39': '경상북도', '40': '경상북도',
|
|
434
|
+
'41': '대구광역시', '42': '대구광역시', '43': '대구광역시',
|
|
435
|
+
'44': '울산광역시', '45': '울산광역시',
|
|
436
|
+
'46': '부산광역시', '47': '부산광역시', '48': '부산광역시', '49': '부산광역시',
|
|
437
|
+
'50': '경상남도', '51': '경상남도', '52': '경상남도', '53': '경상남도',
|
|
438
|
+
'54': '전라북도', '55': '전라북도', '56': '전라북도',
|
|
439
|
+
'57': '전라남도', '58': '전라남도', '59': '전라남도',
|
|
440
|
+
'61': '광주광역시', '62': '광주광역시', '63': '제주특별자치도'
|
|
441
|
+
};
|
|
387
442
|
__decorate([
|
|
388
443
|
property({ type: String }),
|
|
389
444
|
__metadata("design:type", Object)
|
|
390
445
|
], KpiRegionPopup.prototype, "selectedRegion", void 0);
|
|
446
|
+
__decorate([
|
|
447
|
+
property({ type: String }),
|
|
448
|
+
__metadata("design:type", Object)
|
|
449
|
+
], KpiRegionPopup.prototype, "geoGroup", void 0);
|
|
391
450
|
__decorate([
|
|
392
451
|
property({ type: String }),
|
|
393
452
|
__metadata("design:type", Object)
|
|
@@ -432,7 +491,7 @@ __decorate([
|
|
|
432
491
|
state(),
|
|
433
492
|
__metadata("design:type", Array)
|
|
434
493
|
], KpiRegionPopup.prototype, "regionKpiStats", void 0);
|
|
435
|
-
KpiRegionPopup = __decorate([
|
|
494
|
+
KpiRegionPopup = KpiRegionPopup_1 = __decorate([
|
|
436
495
|
customElement('kpi-region-popup')
|
|
437
496
|
], KpiRegionPopup);
|
|
438
497
|
export { KpiRegionPopup };
|