@dssp/dkpi 1.0.0-alpha.58 → 1.0.0-alpha.59

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 (84) hide show
  1. package/dist-client/components/kpi-boxplot-chart.d.ts +1 -1
  2. package/dist-client/components/kpi-boxplot-chart.js +17 -17
  3. package/dist-client/components/kpi-boxplot-chart.js.map +1 -1
  4. package/dist-client/components/kpi-lookup-chart.d.ts +29 -0
  5. package/dist-client/components/kpi-lookup-chart.js +434 -0
  6. package/dist-client/components/kpi-lookup-chart.js.map +1 -0
  7. package/dist-client/components/kpi-mini-trend-chart.d.ts +14 -0
  8. package/dist-client/components/kpi-mini-trend-chart.js +148 -0
  9. package/dist-client/components/kpi-mini-trend-chart.js.map +1 -0
  10. package/dist-client/components/kpi-radar-chart.d.ts +1 -1
  11. package/dist-client/components/kpi-radar-chart.js +73 -55
  12. package/dist-client/components/kpi-radar-chart.js.map +1 -1
  13. package/dist-client/components/kpi-trend-chart.d.ts +25 -0
  14. package/dist-client/components/kpi-trend-chart.js +220 -0
  15. package/dist-client/components/kpi-trend-chart.js.map +1 -0
  16. package/dist-client/google-map/common-google-map.d.ts +35 -0
  17. package/dist-client/google-map/common-google-map.js +343 -0
  18. package/dist-client/google-map/common-google-map.js.map +1 -0
  19. package/dist-client/google-map/google-map-loader.d.ts +6 -0
  20. package/dist-client/google-map/google-map-loader.js +23 -0
  21. package/dist-client/google-map/google-map-loader.js.map +1 -0
  22. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.d.ts +17 -0
  23. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js +280 -0
  24. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js.map +1 -0
  25. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.d.ts +21 -0
  26. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js +389 -0
  27. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js.map +1 -0
  28. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.d.ts +25 -0
  29. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js +469 -0
  30. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js.map +1 -0
  31. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.d.ts +8 -0
  32. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js +78 -0
  33. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js.map +1 -0
  34. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.d.ts +34 -0
  35. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js +642 -0
  36. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js.map +1 -0
  37. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.d.ts +38 -0
  38. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js +501 -0
  39. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js.map +1 -0
  40. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.d.ts +26 -0
  41. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js +439 -0
  42. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js.map +1 -0
  43. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.d.ts +18 -0
  44. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js +131 -0
  45. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js.map +1 -0
  46. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.d.ts +36 -0
  47. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js +572 -0
  48. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js.map +1 -0
  49. package/dist-client/pages/kpi-dashboard/kpi-dashboard.d.ts +59 -0
  50. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js +1027 -0
  51. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js.map +1 -0
  52. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.d.ts +12 -0
  53. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js +82 -0
  54. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js.map +1 -0
  55. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.d.ts +11 -0
  56. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js +65 -0
  57. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js.map +1 -0
  58. package/dist-client/pages/kpi-dashboard/kpi-list-summary.d.ts +13 -0
  59. package/dist-client/pages/kpi-dashboard/kpi-list-summary.js +115 -0
  60. package/dist-client/pages/kpi-dashboard/kpi-list-summary.js.map +1 -0
  61. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.d.ts +15 -0
  62. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js +147 -0
  63. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js.map +1 -0
  64. package/dist-client/pages/kpi-dashboard/kpi-value-entry.d.ts +7 -0
  65. package/dist-client/pages/kpi-dashboard/kpi-value-entry.js +86 -0
  66. package/dist-client/pages/kpi-dashboard/kpi-value-entry.js.map +1 -0
  67. package/dist-client/pages/sv-project-detail.d.ts +6 -0
  68. package/dist-client/pages/sv-project-detail.js +170 -10
  69. package/dist-client/pages/sv-project-detail.js.map +1 -1
  70. package/dist-client/route.d.ts +1 -1
  71. package/dist-client/route.js +3 -0
  72. package/dist-client/route.js.map +1 -1
  73. package/dist-client/tsconfig.tsbuildinfo +1 -1
  74. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.d.ts +16 -0
  75. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +132 -16
  76. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -1
  77. package/dist-server/service/kpi-stat/kpi-stat-query.d.ts +6 -4
  78. package/dist-server/service/kpi-stat/kpi-stat-query.js +232 -22
  79. package/dist-server/service/kpi-stat/kpi-stat-query.js.map +1 -1
  80. package/dist-server/service/kpi-stat/kpi-stat-types.d.ts +6 -0
  81. package/dist-server/service/kpi-stat/kpi-stat-types.js +23 -1
  82. package/dist-server/service/kpi-stat/kpi-stat-types.js.map +1 -1
  83. package/dist-server/tsconfig.tsbuildinfo +1 -1
  84. package/package.json +3 -3
@@ -0,0 +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 * 20) // 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 * 20)\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 * 20,\n max: stat.maxVal * 20,\n q1: stat.q1Val * 20,\n q3: stat.q3Val * 20,\n median: stat.medVal * 20,\n mean: stat.avgVal * 20,\n value: stat.avgVal * 20\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 * 20).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"]}
@@ -0,0 +1,38 @@
1
+ import { LitElement } from 'lit';
2
+ import '../../../google-map/common-google-map.js';
3
+ declare global {
4
+ interface Window {
5
+ google: any;
6
+ }
7
+ }
8
+ export declare class KpiMapPanel extends LitElement {
9
+ static styles: import("lit").CSSResult;
10
+ selectedCategory: string;
11
+ mapData: any[];
12
+ private map;
13
+ private isAllPeriod;
14
+ private startYear;
15
+ private startMonth;
16
+ private endYear;
17
+ private endMonth;
18
+ connectedCallback(): void;
19
+ private initializeDefaultPeriod;
20
+ private onAllPeriodChange;
21
+ get mapLocations(): {
22
+ lat: any;
23
+ lng: any;
24
+ title: any;
25
+ region: any;
26
+ markerContent: string;
27
+ content: string;
28
+ }[];
29
+ private onCategoryButtonClick;
30
+ private onMapChange;
31
+ private fitBoundsToSouthKorea;
32
+ private onRegionClick;
33
+ private zoomIn;
34
+ private zoomOut;
35
+ private resetView;
36
+ private onPeriodChange;
37
+ render(): import("lit-html").TemplateResult<1>;
38
+ }
@@ -0,0 +1,501 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import { LitElement, html, css } from 'lit';
3
+ import { customElement, property, state } from 'lit/decorators.js';
4
+ import '../../../google-map/common-google-map.js';
5
+ let KpiMapPanel = class KpiMapPanel extends LitElement {
6
+ constructor() {
7
+ super(...arguments);
8
+ this.selectedCategory = '전체 KPI';
9
+ this.mapData = [];
10
+ this.map = null;
11
+ this.isAllPeriod = false; // 전체 기간 체크박스
12
+ this.startYear = '';
13
+ this.startMonth = '';
14
+ this.endYear = '';
15
+ this.endMonth = '';
16
+ }
17
+ connectedCallback() {
18
+ super.connectedCallback();
19
+ this.initializeDefaultPeriod();
20
+ }
21
+ initializeDefaultPeriod() {
22
+ const now = new Date();
23
+ const currentYear = now.getFullYear();
24
+ const currentMonth = now.getMonth() + 1; // 0-based이므로 +1
25
+ // 12개월 전 계산
26
+ const startDate = new Date(now);
27
+ startDate.setMonth(startDate.getMonth() - 11); // 현재 월 포함 12개월
28
+ const startYear = startDate.getFullYear();
29
+ const startMonth = startDate.getMonth() + 1;
30
+ this.startYear = startYear.toString();
31
+ this.startMonth = startMonth.toString();
32
+ this.endYear = currentYear.toString();
33
+ this.endMonth = currentMonth.toString();
34
+ }
35
+ onAllPeriodChange(e) {
36
+ this.isAllPeriod = e.target.checked;
37
+ this.onPeriodChange();
38
+ }
39
+ // mapData를 지도 마커 형식으로 변환
40
+ get mapLocations() {
41
+ var _a;
42
+ return (((_a = this.mapData) === null || _a === void 0 ? void 0 : _a.map(item => ({
43
+ lat: item.lat,
44
+ lng: item.lng,
45
+ title: item.region,
46
+ region: item.region, // 지역명 추가
47
+ // 커스텀 마커 콘텐츠 생성
48
+ markerContent: `
49
+ <div style="
50
+ background: white;
51
+ border-radius: 8px;
52
+ padding: 8px 12px;
53
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
54
+ border: 1px solid #e9ecef;
55
+ min-width: 80px;
56
+ text-align: center;
57
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
58
+ cursor: pointer;
59
+ ">
60
+ <div style="
61
+ font-size: 11px;
62
+ font-weight: 600;
63
+ color: #495057;
64
+ margin-bottom: 2px;
65
+ white-space: nowrap;
66
+ ">${item.region}</div>
67
+ <div style="
68
+ font-size: 13px;
69
+ font-weight: 700;
70
+ color: #212529;
71
+ margin-bottom: 2px;
72
+ ">${item.kpi}</div>
73
+ <div style="
74
+ font-size: 10px;
75
+ color: ${item.change > 0 ? '#dc3545' : '#198754'};
76
+ font-weight: 500;
77
+ ">${item.change > 0 ? '▲' : '▼'} ${Math.abs(item.change)}%</div>
78
+ </div>
79
+ `,
80
+ content: `
81
+ <div style="padding: 12px; min-width: 200px;">
82
+ <h3 style="margin: 0 0 8px 0; font-size: 16px; color: #212529;">${item.region}</h3>
83
+ <div style="margin-bottom: 8px;">
84
+ <span style="font-size: 14px; color: #6c757d;">KPI: </span>
85
+ <span style="font-size: 16px; font-weight: 600; color: #212529;">${item.kpi}</span>
86
+ </div>
87
+ <div style="
88
+ font-size: 14px;
89
+ color: ${item.change > 0 ? '#dc3545' : '#198754'};
90
+ font-weight: 500;
91
+ ">
92
+ ${item.change > 0 ? '▲' : '▼'} ${Math.abs(item.change)}% 변화
93
+ </div>
94
+ </div>
95
+ `
96
+ }))) || []);
97
+ }
98
+ onCategoryButtonClick(category) {
99
+ this.dispatchEvent(new CustomEvent('category-change', {
100
+ detail: { category },
101
+ bubbles: true,
102
+ composed: true
103
+ }));
104
+ }
105
+ onMapChange(event) {
106
+ this.map = event.detail;
107
+ // 지도가 로드되면 남한 영역에 맞게 자동 조정
108
+ this.fitBoundsToSouthKorea();
109
+ }
110
+ fitBoundsToSouthKorea() {
111
+ if (!this.map || !window.google)
112
+ return;
113
+ // 남한의 실제 행정구역 경계 설정 (울릉도/독도 제외)
114
+ const bounds = new window.google.maps.LatLngBounds();
115
+ // 최북단: 강원도 고성 (DMZ 남쪽)
116
+ bounds.extend(new window.google.maps.LatLng(38.3, 128.3));
117
+ // 최남단: 제주도 남쪽
118
+ bounds.extend(new window.google.maps.LatLng(33.1, 126.3));
119
+ // 최서단: 전남 서쪽
120
+ bounds.extend(new window.google.maps.LatLng(34.5, 125.1));
121
+ // 최동단: 강원도 동해안
122
+ bounds.extend(new window.google.maps.LatLng(37.5, 129.4));
123
+ // 패딩을 추가하여 여유 공간 확보
124
+ this.map.fitBounds(bounds, { top: 30, bottom: 30, left: 30, right: 30 });
125
+ }
126
+ onRegionClick(event) {
127
+ this.dispatchEvent(new CustomEvent('region-click', {
128
+ detail: event.detail,
129
+ bubbles: true,
130
+ composed: true
131
+ }));
132
+ }
133
+ zoomIn() {
134
+ if (this.map) {
135
+ this.map.setZoom(this.map.getZoom() + 1);
136
+ }
137
+ }
138
+ zoomOut() {
139
+ if (this.map) {
140
+ this.map.setZoom(this.map.getZoom() - 1);
141
+ }
142
+ }
143
+ resetView() {
144
+ if (this.map) {
145
+ this.fitBoundsToSouthKorea();
146
+ }
147
+ }
148
+ onPeriodChange() {
149
+ this.dispatchEvent(new CustomEvent('period-change', {
150
+ detail: {
151
+ startYear: this.isAllPeriod ? null : this.startYear,
152
+ startMonth: this.isAllPeriod ? null : this.startMonth,
153
+ endYear: this.isAllPeriod ? null : this.endYear,
154
+ endMonth: this.isAllPeriod ? null : this.endMonth,
155
+ isAllPeriod: this.isAllPeriod
156
+ },
157
+ bubbles: true,
158
+ composed: true
159
+ }));
160
+ }
161
+ render() {
162
+ 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
+ <div class="map-container">
296
+ <!-- 지도 컨트롤 (오른쪽 상단) -->
297
+ <div class="map-controls">
298
+ <button class="map-control-button" title="확대" @click=${() => this.zoomIn()}>+</button>
299
+ <button class="map-control-button" title="축소" @click=${() => this.zoomOut()}>-</button>
300
+ <button class="map-control-button" title="뷰 초기화" @click=${() => this.resetView()}>⌖</button>
301
+ </div>
302
+
303
+ <!-- 스케일 및 방향 정보 (오른쪽 하단) -->
304
+ <div class="map-scale-direction">
305
+ <div class="north-arrow">↑ N</div>
306
+ <div class="scale-info">25km</div>
307
+ </div>
308
+
309
+ <!-- 공통 Google Maps 컴포넌트 사용 -->
310
+ <common-google-map
311
+ .center=${{ lat: 36.0, lng: 127.8 }}
312
+ .zoom=${7.2}
313
+ .locations=${this.mapLocations}
314
+ .clusterZoom=${10}
315
+ .controls=${{
316
+ zoomControl: false,
317
+ mapTypeControl: false,
318
+ scaleControl: false,
319
+ streetViewControl: false,
320
+ rotateControl: false,
321
+ fullscreenControl: false
322
+ }}
323
+ @map-change=${this.onMapChange}
324
+ @region-click=${this.onRegionClick}
325
+ ></common-google-map>
326
+ </div>
327
+ `;
328
+ }
329
+ };
330
+ KpiMapPanel.styles = css `
331
+ :host {
332
+ display: flex;
333
+ background: #f8f9fa;
334
+ overflow: hidden;
335
+ position: relative;
336
+ min-height: 500px;
337
+ }
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
+ .map-container {
410
+ flex: 1;
411
+ position: relative;
412
+ overflow: hidden;
413
+ }
414
+ .map-controls {
415
+ position: absolute;
416
+ top: 16px;
417
+ right: 16px;
418
+ display: flex;
419
+ flex-direction: column;
420
+ gap: 8px;
421
+ z-index: 10;
422
+ }
423
+ .map-control-button {
424
+ width: 40px;
425
+ height: 40px;
426
+ background: white;
427
+ border: 1px solid #ced4da;
428
+ border-radius: 6px;
429
+ cursor: pointer;
430
+ display: flex;
431
+ align-items: center;
432
+ justify-content: center;
433
+ font-size: 1.2rem;
434
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
435
+ }
436
+ .map-control-button:hover {
437
+ background: #f8f9fa;
438
+ }
439
+ .map-scale-direction {
440
+ position: absolute;
441
+ bottom: 16px;
442
+ right: 16px;
443
+ background: white;
444
+ padding: 8px 12px;
445
+ border-radius: 6px;
446
+ border: 1px solid #ced4da;
447
+ font-size: 0.8rem;
448
+ color: #666;
449
+ z-index: 10;
450
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
451
+ text-align: center;
452
+ }
453
+ .north-arrow {
454
+ font-size: 1rem;
455
+ margin-bottom: 4px;
456
+ }
457
+ .scale-info {
458
+ font-size: 0.7rem;
459
+ }
460
+ common-google-map {
461
+ width: 100%;
462
+ height: 100%;
463
+ }
464
+ `;
465
+ __decorate([
466
+ property({ type: String }),
467
+ __metadata("design:type", Object)
468
+ ], KpiMapPanel.prototype, "selectedCategory", void 0);
469
+ __decorate([
470
+ property({ type: Array }),
471
+ __metadata("design:type", Array)
472
+ ], KpiMapPanel.prototype, "mapData", void 0);
473
+ __decorate([
474
+ state(),
475
+ __metadata("design:type", Object)
476
+ ], KpiMapPanel.prototype, "map", void 0);
477
+ __decorate([
478
+ state(),
479
+ __metadata("design:type", Object)
480
+ ], KpiMapPanel.prototype, "isAllPeriod", void 0);
481
+ __decorate([
482
+ state(),
483
+ __metadata("design:type", Object)
484
+ ], KpiMapPanel.prototype, "startYear", void 0);
485
+ __decorate([
486
+ state(),
487
+ __metadata("design:type", Object)
488
+ ], KpiMapPanel.prototype, "startMonth", void 0);
489
+ __decorate([
490
+ state(),
491
+ __metadata("design:type", Object)
492
+ ], KpiMapPanel.prototype, "endYear", void 0);
493
+ __decorate([
494
+ state(),
495
+ __metadata("design:type", Object)
496
+ ], KpiMapPanel.prototype, "endMonth", void 0);
497
+ KpiMapPanel = __decorate([
498
+ customElement('kpi-map-panel')
499
+ ], KpiMapPanel);
500
+ export { KpiMapPanel };
501
+ //# sourceMappingURL=kpi-map-panel.js.map