@dssp/dkpi 1.0.0-alpha.88 → 1.0.0-alpha.89
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-client/bootstrap.js +1 -1
- package/dist-client/bootstrap.js.map +1 -1
- package/dist-client/components/kpi-mini-trend-chart.d.ts +1 -1
- package/dist-client/components/kpi-mini-trend-chart.js +45 -13
- package/dist-client/components/kpi-mini-trend-chart.js.map +1 -1
- package/dist-client/components/kpi-single-boxplot-chart.d.ts +7 -3
- package/dist-client/components/kpi-single-boxplot-chart.js +25 -7
- package/dist-client/components/kpi-single-boxplot-chart.js.map +1 -1
- package/dist-client/components/kpi-trend-chart.js +39 -8
- package/dist-client/components/kpi-trend-chart.js.map +1 -1
- package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.d.ts +2 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js +32 -6
- package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js.map +1 -1
- package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js +20 -7
- package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js.map +1 -1
- package/dist-client/pages/sv-project-detail.js +8 -4
- package/dist-client/pages/sv-project-detail.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kpi-trend-chart.js","sourceRoot":"","sources":["../../client/components/kpi-trend-chart.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,KAAK,EAAE,MAAM,IAAI,CAAA;AAGjB,IAAM,eAAe,GAArB,MAAM,eAAgB,SAAQ,UAAU;IAAxC;;QACsB,SAAI,GAAsD,EAAE,CAAA;QAC3D,aAAQ,GAAW,OAAO,CAAA;QAC1B,YAAO,GAAW,MAAM,CAAA;QACxB,UAAK,GAAW,GAAG,CAAA;QACnB,WAAM,GAAW,GAAG,CAAA;QACpB,cAAS,GAAW,SAAS,CAAA;QAC7B,gBAAW,GAAW,CAAC,CAAA;QACtB,eAAU,GAAY,IAAI,CAAA;QAC3B,gBAAW,GAAW,CAAC,CAAA;QAE3C,eAAU,GAAG,CAAC,CAAA;QACd,gBAAW,GAAG,CAAC,CAAA;IA4KzB,CAAC;IAlIC,MAAM;QACJ,OAAO,IAAI,CAAA;;;;kBAIG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,KAAK;mBAC5B,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,MAAM;yBACzB,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,MAAM;;;;KAIpF,CAAA;IACH,CAAC;IAED,iBAAiB;QACf,KAAK,CAAC,iBAAiB,EAAE,CAAA;QACzB,IAAI,CAAC,cAAc,GAAG,IAAI,cAAc,CAAC,OAAO,CAAC,EAAE;YACjD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,MAAM,IAAI,GAAG,KAAK,CAAC,WAAW,CAAA;gBAC9B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,KAAK,CAAA;gBAC5B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,MAAM,CAAA;gBAC9B,IAAI,CAAC,aAAa,EAAE,CAAA;YACtB,CAAC;QACH,CAAC,CAAC,CAAA;QACF,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IACnC,CAAC;IAED,oBAAoB;;QAClB,MAAA,IAAI,CAAC,cAAc,0CAAE,UAAU,EAAE,CAAA;QACjC,KAAK,CAAC,oBAAoB,EAAE,CAAA;IAC9B,CAAC;IAED,OAAO;QACL,IAAI,CAAC,cAAc,EAAE,CAAA;IACvB,CAAC;IAED,cAAc;QACZ,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAM;QAEhD,MAAM,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAAA;QACpE,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAA;QAE3B,MAAM,MAAM,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAA;QAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,KAAK,CAAA;QAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,MAAM,CAAA;QAC9C,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,KAAK,CAAA;QACrD,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,CAAC,GAAG,GAAG,MAAM,CAAC,MAAM,CAAA;QAEvD,SAAS;QACT,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACrC,IAAI,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC/B,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC;YACxB,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,SAAS;SACjC,CAAC,CAAC,CAAA;QAEH,SAAS;QACT,MAAM,MAAM,GAAG,EAAE;aACd,SAAS,EAAE;aACX,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAiB,CAAC;aAC1D,KAAK,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAA;QAEzB,MAAM,MAAM,GAAG,EAAE;aACd,WAAW,EAAE;aACb,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC;aACpD,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAA;QAE1B,SAAS;QACT,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;QAC/C,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,aAAa,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,GAAG,GAAG,CAAC,CAAA;QAEtF,iCAAiC;QACjC,MAAM,UAAU,GAAG,CAAC,IAAU,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAA;QAE/D,MAAM,KAAK,GAAG,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,UAAiB,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAA;QAExG,MAAM,KAAK,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QAE1C,eAAe;QACf,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACV,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC;aACrB,IAAI,CAAC,WAAW,EAAE,eAAe,WAAW,GAAG,CAAC;aAChD,IAAI,CACH,EAAE;aACC,UAAU,CAAC,MAAM,CAAC;aAClB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;aACtC,QAAQ,CAAC,CAAC,WAAW,CAAC;aACtB,UAAU,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CACxB,CAAA;QAEH,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACV,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC;aACrB,IAAI,CAAC,WAAW,EAAE,eAAe,WAAW,GAAG,CAAC;aAChD,IAAI,CAAC,KAAK,CAAC;aACX,SAAS,CAAC,MAAM,CAAC;aACjB,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC;aAC3B,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC;aACnB,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC;aAClB,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,CAAA;QAEnC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAE/C,SAAS;QACT,MAAM,IAAI,GAAG,EAAE;aACZ,IAAI,EAAgD;aACpD,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;aACtB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;aACvB,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,CAAA;QAE3B,aAAa;QACb,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC;aACb,KAAK,CAAC,UAAU,CAAC;aACjB,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC;aAC3B,IAAI,CAAC,GAAG,EAAE,IAAW,CAAC;aACtB,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC;aAC9B,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,WAAW,CAAC,CAAA;QAEzC,cAAc;QACd,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC;iBACvB,IAAI,CAAC,UAAU,CAAC;iBAChB,KAAK,EAAE;iBACP,MAAM,CAAC,QAAQ,CAAC;iBAChB,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC;iBAC3B,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;iBAC/B,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;iBAChC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,WAAW,CAAC;iBAC3B,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;iBAC5B,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC1B,CAAC;IACH,CAAC;;AAxKM,sBAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqClB,AArCY,CAqCZ;AAnD0B;IAA1B,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;;6CAA6D;AAC3D;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;iDAA2B;AAC1B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;gDAAyB;AACxB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;8CAAoB;AACnB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;+CAAqB;AACpB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;kDAA8B;AAC7B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;oDAAwB;AACtB;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;;mDAA2B;AAC3B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;oDAAwB;AATxC,eAAe;IAD3B,aAAa,CAAC,oBAAoB,CAAC;GACvB,eAAe,CAwL3B","sourcesContent":["import { LitElement, html, css } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport * as d3 from 'd3'\n\n@customElement('sv-kpi-trend-chart')\nexport class SvKpiTrendChart extends LitElement {\n @property({ type: Array }) data: { date: string; value: number; color?: string }[] = []\n @property({ type: String }) valueKey: string = 'value'\n @property({ type: String }) dateKey: string = 'date'\n @property({ type: Number }) width: number = 400\n @property({ type: Number }) height: number = 200\n @property({ type: String }) lineColor: string = '#2196f3'\n @property({ type: Number }) strokeWidth: number = 2\n @property({ type: Boolean }) showPoints: boolean = true\n @property({ type: Number }) pointRadius: number = 4\n\n private chartWidth = 0\n private chartHeight = 0\n private resizeObserver?: ResizeObserver\n\n static styles = css`\n :host {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .chart-container {\n width: 100%;\n height: 100%;\n }\n\n .trend-line {\n fill: none;\n stroke-linecap: round;\n stroke-linejoin: round;\n }\n\n .data-point {\n fill: white;\n stroke-width: 2;\n }\n\n .axis line,\n .axis path,\n .grid line {\n stroke: #ddd;\n }\n\n .grid path {\n stroke: none;\n }\n\n .axis text {\n font-size: 10px;\n fill: #666;\n }\n `\n\n render() {\n return html`\n <div class=\"chart-container\">\n <svg\n id=\"trend-chart\"\n width=${this.chartWidth || this.width}\n height=${this.chartHeight || this.height}\n viewBox=\"0 0 ${this.chartWidth || this.width} ${this.chartHeight || this.height}\"\n preserveAspectRatio=\"xMidYMid meet\"\n ></svg>\n </div>\n `\n }\n\n connectedCallback() {\n super.connectedCallback()\n this.resizeObserver = new ResizeObserver(entries => {\n for (const entry of entries) {\n const rect = entry.contentRect\n this.chartWidth = rect.width\n this.chartHeight = rect.height\n this.requestUpdate()\n }\n })\n this.resizeObserver.observe(this)\n }\n\n disconnectedCallback() {\n this.resizeObserver?.disconnect()\n super.disconnectedCallback()\n }\n\n updated() {\n this.drawTrendChart()\n }\n\n drawTrendChart() {\n if (!this.data || this.data.length === 0) return\n\n const svg = d3.select(this.renderRoot.querySelector('#trend-chart'))\n svg.selectAll('*').remove()\n\n const margin = { top: 20, right: 20, bottom: 50, left: 40 }\n const width = this.chartWidth || this.width\n const height = this.chartHeight || this.height\n const chartWidth = width - margin.left - margin.right\n const chartHeight = height - margin.top - margin.bottom\n\n // 데이터 파싱\n const parsedData = this.data.map(d => ({\n date: new Date(d[this.dateKey]),\n value: +d[this.valueKey],\n color: d.color || this.lineColor\n }))\n\n // 스케일 설정\n const xScale = d3\n .scaleTime()\n .domain(d3.extent(parsedData, d => d.date) as [Date, Date])\n .range([0, chartWidth])\n\n const yScale = d3\n .scaleLinear()\n .domain([0, d3.max(parsedData, d => d.value) || 100])\n .range([chartHeight, 0])\n\n // SVG 설정\n svg.attr('width', width).attr('height', height)\n const g = svg.append('g').attr('transform', `translate(${margin.left},${margin.top})`)\n\n // 축은 항상 연-월(YYYY-MM) 표기 — 월/일 대신\n const timeFormat = (date: Date) => d3.timeFormat('%Y-%m')(date)\n\n const xAxis = d3.axisBottom(xScale).tickFormat(timeFormat as any).ticks(Math.min(parsedData.length, 10))\n\n const yAxis = d3.axisLeft(yScale).ticks(5)\n\n // X축 그리드 라인 추가\n g.append('g')\n .attr('class', 'grid')\n .attr('transform', `translate(0,${chartHeight})`)\n .call(\n d3\n .axisBottom(xScale)\n .ticks(Math.min(parsedData.length, 10))\n .tickSize(-chartHeight)\n .tickFormat(() => '')\n )\n\n g.append('g')\n .attr('class', 'axis')\n .attr('transform', `translate(0,${chartHeight})`)\n .call(xAxis)\n .selectAll('text')\n .style('text-anchor', 'end')\n .attr('dx', '-.5em')\n .attr('dy', '.3em')\n .attr('transform', 'rotate(-30)')\n\n g.append('g').attr('class', 'axis').call(yAxis)\n\n // 라인 생성기\n const line = d3\n .line<{ date: Date; value: number; color: string }>()\n .x(d => xScale(d.date))\n .y(d => yScale(d.value))\n .curve(d3.curveMonotoneX)\n\n // 트렌드 라인 그리기\n g.append('path')\n .datum(parsedData)\n .attr('class', 'trend-line')\n .attr('d', line as any)\n .attr('stroke', this.lineColor)\n .attr('stroke-width', this.strokeWidth)\n\n // 데이터 포인트 그리기\n if (this.showPoints) {\n g.selectAll('.data-point')\n .data(parsedData)\n .enter()\n .append('circle')\n .attr('class', 'data-point')\n .attr('cx', d => xScale(d.date))\n .attr('cy', d => yScale(d.value))\n .attr('r', this.pointRadius)\n .attr('stroke', d => d.color)\n .attr('fill', 'white')\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"kpi-trend-chart.js","sourceRoot":"","sources":["../../client/components/kpi-trend-chart.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, html, css } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport * as d3 from 'd3'\n\n@customElement('sv-kpi-trend-chart')\nexport class SvKpiTrendChart extends LitElement {\n @property({ type: Array }) data: { date: string; value: number; color?: string }[] = []\n @property({ type: String }) valueKey: string = 'value'\n @property({ type: String }) dateKey: string = 'date'\n @property({ type: Number }) width: number = 400\n @property({ type: Number }) height: number = 200\n @property({ type: String }) lineColor: string = '#2196f3'\n @property({ type: Number }) strokeWidth: number = 2\n @property({ type: Boolean }) showPoints: boolean = true\n @property({ type: Number }) pointRadius: number = 4\n\n private chartWidth = 0\n private chartHeight = 0\n private resizeObserver?: ResizeObserver\n\n static styles = css`\n :host {\n display: block;\n width: 100%;\n height: 100%;\n }\n\n .chart-container {\n width: 100%;\n height: 100%;\n }\n\n .trend-line {\n fill: none;\n stroke-linecap: round;\n stroke-linejoin: round;\n }\n\n .data-point {\n fill: white;\n stroke-width: 2;\n }\n\n .axis line,\n .axis path,\n .grid line {\n stroke: #ddd;\n }\n\n .grid path {\n stroke: none;\n }\n\n .axis text {\n font-size: 10px;\n fill: #666;\n }\n `\n\n render() {\n return html`\n <div class=\"chart-container\">\n <svg\n id=\"trend-chart\"\n width=${this.chartWidth || this.width}\n height=${this.chartHeight || this.height}\n viewBox=\"0 0 ${this.chartWidth || this.width} ${this.chartHeight || this.height}\"\n preserveAspectRatio=\"xMidYMid meet\"\n ></svg>\n </div>\n `\n }\n\n connectedCallback() {\n super.connectedCallback()\n this.resizeObserver = new ResizeObserver(entries => {\n for (const entry of entries) {\n const rect = entry.contentRect\n this.chartWidth = rect.width\n this.chartHeight = rect.height\n this.requestUpdate()\n }\n })\n this.resizeObserver.observe(this)\n }\n\n disconnectedCallback() {\n this.resizeObserver?.disconnect()\n super.disconnectedCallback()\n }\n\n updated() {\n this.drawTrendChart()\n }\n\n drawTrendChart() {\n if (!this.data || this.data.length === 0) return\n\n const svg = d3.select(this.renderRoot.querySelector('#trend-chart'))\n svg.selectAll('*').remove()\n\n const margin = { top: 20, right: 20, bottom: 50, left: 40 }\n const width = this.chartWidth || this.width\n const height = this.chartHeight || this.height\n const chartWidth = width - margin.left - margin.right\n const chartHeight = height - margin.top - margin.bottom\n\n // 데이터 파싱 — value 가 null/undefined 인 월은 '데이터 없음'(0 아님)으로 보존해 플로팅에서 제외\n const parsedData = this.data.map(d => ({\n date: new Date(d[this.dateKey]),\n value: d[this.valueKey] == null ? null : +d[this.valueKey],\n color: d.color || this.lineColor\n }))\n\n // 스케일 설정\n const xScale = d3\n .scaleTime()\n .domain(d3.extent(parsedData, d => d.date) as [Date, Date])\n .range([0, chartWidth])\n\n const yScale = d3\n .scaleLinear()\n .domain([0, d3.max(parsedData, d => (d.value == null ? undefined : d.value)) || 100])\n .range([chartHeight, 0])\n\n // SVG 설정\n svg.attr('width', width).attr('height', height)\n const g = svg.append('g').attr('transform', `translate(${margin.left},${margin.top})`)\n\n // 축은 항상 연-월(YYYY-MM) 표기 — 월/일 대신\n const timeFormat = (date: Date) => d3.timeFormat('%Y-%m')(date)\n\n const xAxis = d3.axisBottom(xScale).tickFormat(timeFormat as any).ticks(Math.min(parsedData.length, 10))\n\n const yAxis = d3.axisLeft(yScale).ticks(5)\n\n // X축 그리드 라인 추가\n g.append('g')\n .attr('class', 'grid')\n .attr('transform', `translate(0,${chartHeight})`)\n .call(\n d3\n .axisBottom(xScale)\n .ticks(Math.min(parsedData.length, 10))\n .tickSize(-chartHeight)\n .tickFormat(() => '')\n )\n\n g.append('g')\n .attr('class', 'axis')\n .attr('transform', `translate(0,${chartHeight})`)\n .call(xAxis)\n .selectAll('text')\n .style('text-anchor', 'end')\n .attr('dx', '-.5em')\n .attr('dy', '.3em')\n .attr('transform', 'rotate(-30)')\n\n g.append('g').attr('class', 'axis').call(yAxis)\n\n // 라인 생성기 — defined() 로 데이터 없는(null) 월은 선을 끊어 gap 처리\n const line = d3\n .line<{ date: Date; value: number | null; color: string }>()\n .defined(d => d.value != null)\n .x(d => xScale(d.date))\n .y(d => yScale(d.value as number))\n .curve(d3.curveMonotoneX)\n\n // 트렌드 라인(실선) — 연속 구간만 (defined() 로 null 월에서 끊김)\n g.append('path')\n .datum(parsedData)\n .attr('class', 'trend-line')\n .attr('d', line as any)\n .attr('stroke', this.lineColor)\n .attr('stroke-width', this.strokeWidth)\n .attr('fill', 'none')\n\n // 결손 구간 점선 다리 — 사이에 데이터 없는 월이 낀 두 데이터점을 점선으로 연결\n const present = parsedData.map((d, i) => ({ ...d, i })).filter(d => d.value != null)\n for (let k = 1; k < present.length; k++) {\n const a = present[k - 1]\n const b = present[k]\n if (b.i - a.i > 1) {\n g.append('line')\n .attr('x1', xScale(a.date))\n .attr('y1', yScale(a.value as number))\n .attr('x2', xScale(b.date))\n .attr('y2', yScale(b.value as number))\n .attr('stroke', this.lineColor)\n .attr('stroke-width', this.strokeWidth)\n .attr('stroke-dasharray', '4,3')\n }\n }\n\n // 뒷부분(기간 끝)에 데이터가 없으면 마지막 데이터값에서 기간 끝까지 같은 값으로 수평 점선 연장\n const lastPresent = present[present.length - 1]\n const lastAll = parsedData[parsedData.length - 1]\n if (lastPresent && lastAll && lastPresent.i < parsedData.length - 1) {\n g.append('line')\n .attr('x1', xScale(lastPresent.date))\n .attr('y1', yScale(lastPresent.value as number))\n .attr('x2', xScale(lastAll.date))\n .attr('y2', yScale(lastPresent.value as number)) // 같은 값(수평)\n .attr('stroke', this.lineColor)\n .attr('stroke-width', this.strokeWidth)\n .attr('stroke-dasharray', '4,3')\n }\n\n // 데이터 포인트 그리기 — 데이터 있는 월만 (null 월은 점 미표시)\n if (this.showPoints) {\n g.selectAll('.data-point')\n .data(parsedData.filter(d => d.value != null))\n .enter()\n .append('circle')\n .attr('class', 'data-point')\n .attr('cx', d => xScale(d.date))\n .attr('cy', d => yScale(d.value as number))\n .attr('r', this.pointRadius)\n .attr('stroke', d => d.color)\n .attr('fill', 'white')\n }\n }\n}\n"]}
|
|
@@ -24,6 +24,8 @@ export declare class KpiLeftPanel extends LitElement {
|
|
|
24
24
|
fetchRegionalKpiStats(): Promise<void>;
|
|
25
25
|
fetchMonthlyTrendData(): Promise<void>;
|
|
26
26
|
private getRegionTrendData;
|
|
27
|
+
/** start~end(YYYY-MM) 사이 모든 월을 순서대로 반환 */
|
|
28
|
+
private _buildMonthRange;
|
|
27
29
|
private calculateChangeRate;
|
|
28
30
|
private generateChartData;
|
|
29
31
|
private _onAllPeriodChange;
|
|
@@ -239,13 +239,39 @@ let KpiLeftPanel = class KpiLeftPanel extends LitElement {
|
|
|
239
239
|
}
|
|
240
240
|
}
|
|
241
241
|
getRegionTrendData(region) {
|
|
242
|
-
// 해당
|
|
243
|
-
const
|
|
242
|
+
// 해당 지역 월별 값 맵 (20배 스케일)
|
|
243
|
+
const byMonth = new Map();
|
|
244
|
+
this.monthlyTrendData
|
|
244
245
|
.filter(d => d.geoGroup === region)
|
|
245
|
-
.
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
246
|
+
.forEach(d => byMonth.set(d.yearMonth, d.avgVal * 100));
|
|
247
|
+
// 선택 기간 전체 월을 커버 — 데이터 없는 월은 null(0 아님). 기간 정보 없으면 데이터 월만.
|
|
248
|
+
const months = this.startYearMonth && this.endYearMonth
|
|
249
|
+
? this._buildMonthRange(this.startYearMonth, this.endYearMonth)
|
|
250
|
+
: [...byMonth.keys()].sort();
|
|
251
|
+
return months.map(ym => (byMonth.has(ym) ? byMonth.get(ym) : null));
|
|
252
|
+
}
|
|
253
|
+
/** start~end(YYYY-MM) 사이 모든 월을 순서대로 반환 */
|
|
254
|
+
_buildMonthRange(start, end) {
|
|
255
|
+
const [sy, sm] = start.split('-').map(Number);
|
|
256
|
+
const [ey, em] = end.split('-').map(Number);
|
|
257
|
+
if (!sy || !sm || !ey || !em)
|
|
258
|
+
return [];
|
|
259
|
+
const out = [];
|
|
260
|
+
let y = sy;
|
|
261
|
+
let m = sm;
|
|
262
|
+
for (let i = 0; i < 240; i++) {
|
|
263
|
+
out.push(`${y}-${String(m).padStart(2, '0')}`);
|
|
264
|
+
if (y === ey && m === em)
|
|
265
|
+
break;
|
|
266
|
+
if (y > ey || (y === ey && m > em))
|
|
267
|
+
break;
|
|
268
|
+
m++;
|
|
269
|
+
if (m > 12) {
|
|
270
|
+
m = 1;
|
|
271
|
+
y++;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return out;
|
|
249
275
|
}
|
|
250
276
|
calculateChangeRate(region) {
|
|
251
277
|
// 해당 지역의 월별 데이터를 시간순으로 정렬
|
|
@@ -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: #2196f3;\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\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\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\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 // kpiName 표기가 'Y1. 일정성과' / '일정성과(Y1)' 등으로 환경마다 달라 전체 문자열 매칭은 깨짐.\n // Y1~Y6 코드만 추출해 짧은 라벨로 매핑.\n const yLabelByCode: Record<string, string> = {\n Y1: '일정',\n Y2: '비용',\n Y3: '품질',\n Y4: '안전',\n Y5: '환경',\n Y6: '생산성'\n }\n const toCategory = (kpiName: string) => yLabelByCode[(kpiName || '').match(/Y[1-6]/)?.[0] ?? ''] || kpiName\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 = toCategory(stat.kpiName)\n if (!categories.includes(category)) {\n categories.push(category)\n }\n\n // 전체 평균 데이터만 표시 (비교 시리즈 없음) — 박스플롯과 동일 정밀도(Math.round 제거)\n data.push({\n org: '전체평균',\n category,\n value: stat.avgVal * 100\n })\n })\n\n this.chartCategories = categories.length > 0 ? categories : ['일정', '비용', '품질', '안전', '환경', '생산성']\n this.chartData = data\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 = toCategory(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 }\n }\n\n private _onAllPeriodChange(e: Event) {\n this.isAllPeriod = (e.target as HTMLInputElement).checked\n if (this.isAllPeriod) {\n // 전체: 시작 = 선택 가능한 가장 이른 월(2022-01), 종료 = 현재월 → 모든 데이터 포함하며 표시도 명확\n // (빈 문자열로 두면 드롭다운이 2022-01~2022-01 로 잘못 보이던 문제 방지)\n const now = new Date()\n this.startYearMonth = '2022-01'\n this.endYearMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`\n }\n this._emitPeriodChange()\n }\n\n /** 시작월 설정 — 시작 > 종료(역전)면 종료를 시작에 맞춰 보정. (YYYY-MM 문자열 비교 = 시간순) */\n private _setStartYearMonth(ym: string) {\n this.startYearMonth = ym\n if (this.endYearMonth && this.startYearMonth > this.endYearMonth) {\n this.endYearMonth = this.startYearMonth\n }\n this._emitPeriodChange()\n }\n\n /** 종료월 설정 — 종료 < 시작(역전)이면 시작을 종료에 맞춰 보정. */\n private _setEndYearMonth(ym: string) {\n this.endYearMonth = ym\n if (this.startYearMonth && this.endYearMonth < this.startYearMonth) {\n this.startYearMonth = this.endYearMonth\n }\n this._emitPeriodChange()\n }\n\n /** 기간 변경을 부모로 전파 → 지역 팝업 등 다른 패널이 동일 기간을 쓰도록 동기화 */\n private _emitPeriodChange() {\n this.dispatchEvent(\n new CustomEvent('period-change', {\n detail: { startYearMonth: this.startYearMonth, endYearMonth: this.endYearMonth, isAllPeriod: this.isAllPeriod },\n bubbles: true,\n composed: true\n })\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 {\n 항목: '건물 용도',\n 값: this.buildingUsage === 'RESIDENTIAL' ? '주거' : this.buildingUsage === 'NON_RESIDENTIAL' ? '비주거' : '전체'\n },\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 '' // 변동 없음(0)이면 화살표 미표시\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\n class=\"filter-select\"\n ?disabled=${this.isAllPeriod}\n @change=${(e: Event) => {\n const y = (e.target as HTMLSelectElement).value\n const m = this.startYearMonth.split('-')[1] || '01'\n this._setStartYearMonth(`${y}-${m}`)\n }}\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\n class=\"filter-select\"\n ?disabled=${this.isAllPeriod}\n @change=${(e: Event) => {\n const y = this.startYearMonth.split('-')[0] || '2025'\n const m = (e.target as HTMLSelectElement).value.padStart(2, '0')\n this._setStartYearMonth(`${y}-${m}`)\n }}\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\n class=\"filter-select\"\n ?disabled=${this.isAllPeriod}\n @change=${(e: Event) => {\n const y = (e.target as HTMLSelectElement).value\n const m = this.endYearMonth.split('-')[1] || '12'\n this._setEndYearMonth(`${y}-${m}`)\n }}\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\n class=\"filter-select\"\n ?disabled=${this.isAllPeriod}\n @change=${(e: Event) => {\n const y = this.endYearMonth.split('-')[0] || '2026'\n const m = (e.target as HTMLSelectElement).value.padStart(2, '0')\n this._setEndYearMonth(`${y}-${m}`)\n }}\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\">성과영역별 KPI</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.chartData.length === 0\n ? html`<div style=\"display:flex;align-items:center;justify-content:center;height:100%;color:#888;font-size:0.9rem;\">\n 선택한 기간에 데이터가 없습니다.\n </div>`\n : this.selectedChartType === 'boxplot'\n ? html`\n <sv-kpi-boxplot-chart\n .data=${this.chartData}\n .valueKey=${'value'}\n .valueLabel=${'전국'}\n .showStatus=${false}\n ></sv-kpi-boxplot-chart>\n `\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\">시도별 종합 KPI</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: #2196f3;\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\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\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\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 | null)[] {\n // 해당 지역 월별 값 맵 (20배 스케일)\n const byMonth = new Map<string, number>()\n this.monthlyTrendData\n .filter(d => d.geoGroup === region)\n .forEach(d => byMonth.set(d.yearMonth, d.avgVal * 100))\n\n // 선택 기간 전체 월을 커버 — 데이터 없는 월은 null(0 아님). 기간 정보 없으면 데이터 월만.\n const months =\n this.startYearMonth && this.endYearMonth\n ? this._buildMonthRange(this.startYearMonth, this.endYearMonth)\n : [...byMonth.keys()].sort()\n\n return months.map(ym => (byMonth.has(ym) ? (byMonth.get(ym) as number) : null))\n }\n\n /** start~end(YYYY-MM) 사이 모든 월을 순서대로 반환 */\n private _buildMonthRange(start: string, end: string): string[] {\n const [sy, sm] = start.split('-').map(Number)\n const [ey, em] = end.split('-').map(Number)\n if (!sy || !sm || !ey || !em) return []\n const out: string[] = []\n let y = sy\n let m = sm\n for (let i = 0; i < 240; i++) {\n out.push(`${y}-${String(m).padStart(2, '0')}`)\n if (y === ey && m === em) break\n if (y > ey || (y === ey && m > em)) break\n m++\n if (m > 12) {\n m = 1\n y++\n }\n }\n return out\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 // kpiName 표기가 'Y1. 일정성과' / '일정성과(Y1)' 등으로 환경마다 달라 전체 문자열 매칭은 깨짐.\n // Y1~Y6 코드만 추출해 짧은 라벨로 매핑.\n const yLabelByCode: Record<string, string> = {\n Y1: '일정',\n Y2: '비용',\n Y3: '품질',\n Y4: '안전',\n Y5: '환경',\n Y6: '생산성'\n }\n const toCategory = (kpiName: string) => yLabelByCode[(kpiName || '').match(/Y[1-6]/)?.[0] ?? ''] || kpiName\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 = toCategory(stat.kpiName)\n if (!categories.includes(category)) {\n categories.push(category)\n }\n\n // 전체 평균 데이터만 표시 (비교 시리즈 없음) — 박스플롯과 동일 정밀도(Math.round 제거)\n data.push({\n org: '전체평균',\n category,\n value: stat.avgVal * 100\n })\n })\n\n this.chartCategories = categories.length > 0 ? categories : ['일정', '비용', '품질', '안전', '환경', '생산성']\n this.chartData = data\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 = toCategory(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 }\n }\n\n private _onAllPeriodChange(e: Event) {\n this.isAllPeriod = (e.target as HTMLInputElement).checked\n if (this.isAllPeriod) {\n // 전체: 시작 = 선택 가능한 가장 이른 월(2022-01), 종료 = 현재월 → 모든 데이터 포함하며 표시도 명확\n // (빈 문자열로 두면 드롭다운이 2022-01~2022-01 로 잘못 보이던 문제 방지)\n const now = new Date()\n this.startYearMonth = '2022-01'\n this.endYearMonth = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`\n }\n this._emitPeriodChange()\n }\n\n /** 시작월 설정 — 시작 > 종료(역전)면 종료를 시작에 맞춰 보정. (YYYY-MM 문자열 비교 = 시간순) */\n private _setStartYearMonth(ym: string) {\n this.startYearMonth = ym\n if (this.endYearMonth && this.startYearMonth > this.endYearMonth) {\n this.endYearMonth = this.startYearMonth\n }\n this._emitPeriodChange()\n }\n\n /** 종료월 설정 — 종료 < 시작(역전)이면 시작을 종료에 맞춰 보정. */\n private _setEndYearMonth(ym: string) {\n this.endYearMonth = ym\n if (this.startYearMonth && this.endYearMonth < this.startYearMonth) {\n this.startYearMonth = this.endYearMonth\n }\n this._emitPeriodChange()\n }\n\n /** 기간 변경을 부모로 전파 → 지역 팝업 등 다른 패널이 동일 기간을 쓰도록 동기화 */\n private _emitPeriodChange() {\n this.dispatchEvent(\n new CustomEvent('period-change', {\n detail: { startYearMonth: this.startYearMonth, endYearMonth: this.endYearMonth, isAllPeriod: this.isAllPeriod },\n bubbles: true,\n composed: true\n })\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 {\n 항목: '건물 용도',\n 값: this.buildingUsage === 'RESIDENTIAL' ? '주거' : this.buildingUsage === 'NON_RESIDENTIAL' ? '비주거' : '전체'\n },\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 '' // 변동 없음(0)이면 화살표 미표시\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\n class=\"filter-select\"\n ?disabled=${this.isAllPeriod}\n @change=${(e: Event) => {\n const y = (e.target as HTMLSelectElement).value\n const m = this.startYearMonth.split('-')[1] || '01'\n this._setStartYearMonth(`${y}-${m}`)\n }}\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\n class=\"filter-select\"\n ?disabled=${this.isAllPeriod}\n @change=${(e: Event) => {\n const y = this.startYearMonth.split('-')[0] || '2025'\n const m = (e.target as HTMLSelectElement).value.padStart(2, '0')\n this._setStartYearMonth(`${y}-${m}`)\n }}\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\n class=\"filter-select\"\n ?disabled=${this.isAllPeriod}\n @change=${(e: Event) => {\n const y = (e.target as HTMLSelectElement).value\n const m = this.endYearMonth.split('-')[1] || '12'\n this._setEndYearMonth(`${y}-${m}`)\n }}\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\n class=\"filter-select\"\n ?disabled=${this.isAllPeriod}\n @change=${(e: Event) => {\n const y = this.endYearMonth.split('-')[0] || '2026'\n const m = (e.target as HTMLSelectElement).value.padStart(2, '0')\n this._setEndYearMonth(`${y}-${m}`)\n }}\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\">성과영역별 KPI</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.chartData.length === 0\n ? html`<div style=\"display:flex;align-items:center;justify-content:center;height:100%;color:#888;font-size:0.9rem;\">\n 선택한 기간에 데이터가 없습니다.\n </div>`\n : this.selectedChartType === 'boxplot'\n ? html`\n <sv-kpi-boxplot-chart\n .data=${this.chartData}\n .valueKey=${'value'}\n .valueLabel=${'전국'}\n .showStatus=${false}\n ></sv-kpi-boxplot-chart>\n `\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\">시도별 종합 KPI</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"]}
|
|
@@ -184,14 +184,27 @@ let KpiRegionPopup = KpiRegionPopup_1 = class KpiRegionPopup extends LitElement
|
|
|
184
184
|
let prev = null;
|
|
185
185
|
this.trendData = months.map(ym => {
|
|
186
186
|
const d = byMonth.get(ym);
|
|
187
|
-
const
|
|
188
|
-
//
|
|
189
|
-
|
|
190
|
-
|
|
187
|
+
const hasData = !!d;
|
|
188
|
+
// 데이터 없는 월은 0이 아니라 null — 0(실제 0점)과 구분하여 플로팅/표시에서 제외.
|
|
189
|
+
// 값은 반올림하지 않음(정수화하면 표의 소수점이 항상 .0 으로 나옴) — 표시 시 toFixed(1) 적용.
|
|
190
|
+
const value = hasData ? d.avgVal * 100 : null;
|
|
191
|
+
// 추이: 무데이터 'none', 직전 데이터 없으면(첫 점) 'flat', 그 외 실제 증감 비교
|
|
192
|
+
let trendDir;
|
|
193
|
+
if (!hasData) {
|
|
194
|
+
trendDir = 'none';
|
|
195
|
+
}
|
|
196
|
+
else if (prev === null) {
|
|
197
|
+
trendDir = 'flat';
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
trendDir = value > prev ? 'up' : value < prev ? 'down' : 'flat';
|
|
201
|
+
}
|
|
202
|
+
if (hasData)
|
|
203
|
+
prev = value;
|
|
191
204
|
return {
|
|
192
205
|
date: ym, // YYYY-MM 형식
|
|
193
206
|
value,
|
|
194
|
-
color: value > 60 ? '#4caf50' : value > 40 ? '#ff9800' : '#f44336',
|
|
207
|
+
color: value == null ? undefined : value > 60 ? '#4caf50' : value > 40 ? '#ff9800' : '#f44336',
|
|
195
208
|
trendDir
|
|
196
209
|
};
|
|
197
210
|
});
|
|
@@ -309,11 +322,11 @@ let KpiRegionPopup = KpiRegionPopup_1 = class KpiRegionPopup extends LitElement
|
|
|
309
322
|
<tr style="border-bottom: 1px solid #f1f3f4;">
|
|
310
323
|
<td style="padding: 8px; font-size: 0.85rem;">${item.date}</td>
|
|
311
324
|
<td style="padding: 8px; text-align: right; font-size: 0.85rem; font-weight: 600;">
|
|
312
|
-
${item.value.toFixed(1)}
|
|
325
|
+
${item.value != null ? item.value.toFixed(1) : '-'}
|
|
313
326
|
</td>
|
|
314
327
|
<td style="padding: 8px; text-align: center; font-size: 0.85rem;">
|
|
315
328
|
<span style="color: ${item.trendDir === 'up' ? '#e53935' : item.trendDir === 'down' ? '#2196f3' : '#999'};">
|
|
316
|
-
${item.trendDir === 'up' ? '▲' : item.trendDir === 'down' ? '▼' : ''}
|
|
329
|
+
${item.trendDir === 'up' ? '▲' : item.trendDir === 'down' ? '▼' : '–'}
|
|
317
330
|
</span>
|
|
318
331
|
</td>
|
|
319
332
|
</tr>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kpi-region-popup.js","sourceRoot":"","sources":["../../../../client/pages/kpi-dashboard/components/kpi-region-popup.ts"],"names":[],"mappings":"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","sourcesContent":["import gql from 'graphql-tag'\nimport { LitElement, html, css, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { client } from '@operato/graphql'\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport '../../../components/kpi-radar-chart.js'\nimport '../../../components/kpi-boxplot-chart.js'\nimport '../../../components/kpi-trend-chart.js'\n\n@customElement('kpi-region-popup')\nexport class KpiRegionPopup extends LitElement {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: block;\n position: absolute;\n top: 0;\n left: 402px;\n width: 400px;\n height: 100%;\n background: #fff;\n border-right: 1px solid #e0e0e0;\n z-index: 1000;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);\n }\n .popup-content {\n padding: 20px;\n overflow-y: auto;\n flex: 1;\n }\n .popup-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 .popup-title {\n font-size: 1.2rem;\n font-weight: bold;\n color: #333;\n }\n .popup-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 .popup-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 .period-selector {\n display: flex;\n gap: 8px;\n margin-bottom: 16px;\n }\n .period-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 }\n .period-button.active {\n background: #667eea;\n color: white;\n border-color: #667eea;\n }\n .date-range-selector {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 16px;\n }\n .date-select {\n padding: 6px 12px;\n border: 1px solid #ced4da;\n border-radius: 4px;\n background: white;\n font-size: 0.9rem;\n }\n `\n ]\n\n @property({ type: String }) selectedRegion: string | null = null\n @property({ type: String }) geoGroup: string | null = null // 시군구 geo_group 코드 (있으면 시군구 쿼리 사용)\n @property({ type: String }) selectedCategory = '전체 KPI'\n @property({ type: String }) selectedChartType = 'boxplot'\n @property({ type: String }) selectedPeriod = '월'\n @property({ type: String }) startYearMonth = '' // YYYY-MM 형식\n @property({ type: String }) endYearMonth = '' // YYYY-MM 형식\n @property({ type: Array }) monthlyTrendData: any[] = [] // 부모에서 전달받은 월별 추이 데이터\n @property({ type: Array }) totalKpiStats: any[] = [] // 전체 KPI 통계 (비교용)\n\n @state() private chartData: any[] = []\n @state() private chartCategories: string[] = []\n @state() private trendData: { date: string; value: number; color?: string; trendDir?: 'up' | 'down' | 'flat' }[] = []\n @state() private regionKpiStats: any[] = []\n\n updated(changedProperties: Map<string, any>) {\n if (changedProperties.has('selectedRegion') && this.selectedRegion) {\n this.fetchRegionKpiStats()\n this.generateTrendData()\n }\n\n // selectedCategory 또는 monthlyTrendData가 변경되면 추이 데이터 재생성\n if (changedProperties.has('selectedCategory') || changedProperties.has('monthlyTrendData')) {\n this.generateTrendData()\n }\n\n // 기간이 변경되면 차트 데이터 다시 가져오기\n if (changedProperties.has('startYearMonth') || changedProperties.has('endYearMonth')) {\n if (this.selectedRegion) {\n this.fetchRegionKpiStats()\n }\n // 기간이 바뀌면 추이도 그 기간 전체 축으로 다시 그림 (데이터 없는 월 포함)\n this.generateTrendData()\n }\n }\n\n async fetchRegionKpiStats() {\n if (!this.selectedRegion) return\n\n try {\n let regionKpiStats: any[]\n\n if (this.geoGroup) {\n // 시군구 모드: geo_group 코드로 조회\n const response = await client.query({\n query: gql`\n query GetSigunguKpiStats($geoGroup: String!, $startYearMonth: String, $endYearMonth: String) {\n kpiYValueStatsByGeoGroup(geoGroup: $geoGroup, startYearMonth: $startYearMonth, endYearMonth: $endYearMonth) {\n kpiName\n minVal\n q1Val\n medVal\n q3Val\n maxVal\n avgVal\n projectCount\n }\n }\n `,\n variables: {\n geoGroup: this.geoGroup,\n startYearMonth: this.startYearMonth,\n endYearMonth: this.endYearMonth\n }\n })\n regionKpiStats = response.data.kpiYValueStatsByGeoGroup || []\n } else {\n // 광역 모드: 광역시도 이름으로 조회\n const response = await client.query({\n query: gql`\n query GetRegionKpiStats($metroArea: String!, $startYearMonth: String, $endYearMonth: String) {\n kpiYValueStatsByMetroArea(metroArea: $metroArea, startYearMonth: $startYearMonth, endYearMonth: $endYearMonth) {\n kpiName\n minVal\n q1Val\n medVal\n q3Val\n maxVal\n avgVal\n projectCount\n }\n }\n `,\n variables: {\n metroArea: this.selectedRegion,\n startYearMonth: this.startYearMonth,\n endYearMonth: this.endYearMonth\n }\n })\n regionKpiStats = response.data.kpiYValueStatsByMetroArea || []\n }\n\n this.regionKpiStats = regionKpiStats\n this.generateChartData()\n } catch (error) {\n console.error('Failed to fetch region KPI stats:', error)\n this.regionKpiStats = []\n this.generateChartData()\n }\n }\n\n private generateChartData() {\n // kpiName 표기가 'Y1. 일정성과' / '일정성과(Y1)' 등으로 환경마다 달라 전체 문자열 매칭은 깨짐.\n // Y1~Y6 코드만 추출해 짧은 라벨로 매핑.\n const yLabelByCode: Record<string, string> = {\n Y1: '일정',\n Y2: '비용',\n Y3: '품질',\n Y4: '안전',\n Y5: '환경',\n Y6: '생산성'\n }\n const toCategory = (kpiName: string) => yLabelByCode[(kpiName || '').match(/Y[1-6]/)?.[0] ?? ''] || kpiName\n\n // 레이더 차트와 박스플롯은 항상 전체 Y-level KPI 표시 (selectedCategory 무시)\n if (this.selectedChartType === 'radar') {\n // 레이더 차트용 데이터 생성 — 지역 평균 단일 시리즈\n // (전체평균 기준선은 지역 평균과 차별성이 적어 제거 → 단일 시리즈라 범례도 자동 미표시)\n const data: Array<{ org: string; category: string; value: number }> = []\n const categories: string[] = []\n\n // 카테고리 수집\n this.regionKpiStats.forEach(stat => {\n const category = toCategory(stat.kpiName)\n if (!categories.includes(category)) {\n categories.push(category)\n }\n })\n\n // 지역 데이터 추가 (박스플롯과 동일 스케일·정밀도 — Math.round 제거해 수치 일치)\n this.regionKpiStats.forEach(stat => {\n const category = toCategory(stat.kpiName)\n data.push({\n org: this.selectedRegion || '지역',\n category,\n value: stat.avgVal * 100\n })\n })\n\n this.chartCategories = categories.length > 0 ? categories : ['일정', '비용', '품질', '안전', '환경', '생산성']\n this.chartData = data\n } else {\n // 박스플롯용 데이터 생성\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.regionKpiStats.forEach(stat => {\n const category = toCategory(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 }\n }\n\n // geo_group → 광역시도 매핑 (시군구 모드에서 추이 데이터 조회용)\n private static readonly GEO_TO_METRO: Record<string, string> = {\n '01': '서울특별시',\n '02': '서울특별시',\n '03': '서울특별시',\n '04': '서울특별시',\n '05': '서울특별시',\n '06': '서울특별시',\n '07': '서울특별시',\n '08': '서울특별시',\n '10': '경기도',\n '11': '경기도',\n '12': '경기도',\n '13': '경기도',\n '14': '경기도',\n '15': '경기도',\n '16': '경기도',\n '17': '경기도',\n '18': '경기도',\n '21': '인천광역시',\n '22': '인천광역시',\n '23': '인천광역시',\n '24': '강원도',\n '25': '강원도',\n '26': '강원도',\n '33': '강원도',\n '27': '충청북도',\n '28': '충청북도',\n '29': '충청북도',\n '30': '세종특별자치시',\n '31': '충청남도',\n '32': '충청남도',\n '34': '대전광역시',\n '35': '대전광역시',\n '36': '경상북도',\n '37': '경상북도',\n '38': '경상북도',\n '39': '경상북도',\n '40': '경상북도',\n '41': '대구광역시',\n '42': '대구광역시',\n '43': '대구광역시',\n '44': '울산광역시',\n '45': '울산광역시',\n '46': '부산광역시',\n '47': '부산광역시',\n '48': '부산광역시',\n '49': '부산광역시',\n '50': '경상남도',\n '51': '경상남도',\n '52': '경상남도',\n '53': '경상남도',\n '54': '전라북도',\n '55': '전라북도',\n '56': '전라북도',\n '57': '전라남도',\n '58': '전라남도',\n '59': '전라남도',\n '61': '광주광역시',\n '62': '광주광역시',\n '63': '제주특별자치도'\n }\n\n private generateTrendData() {\n if (!this.selectedRegion) return\n\n // 시군구 모드인 경우 소속 광역시도의 추이 데이터 사용\n const trendRegion = this.geoGroup ? KpiRegionPopup.GEO_TO_METRO[this.geoGroup] || this.selectedRegion : this.selectedRegion\n\n // 해당 지역의 월별 데이터를 YYYY-MM 기준 맵으로\n const byMonth = new Map<string, any>()\n this.monthlyTrendData.filter(d => d.geoGroup === trendRegion).forEach(d => byMonth.set(d.yearMonth, d))\n\n // 선택 기간(start~end) 전체 월을 축으로 사용 — 데이터가 없는 월도 레코드(값 0)로 채워\n // 전국 패널의 기간과 동일한 범위를 플로팅. (전체 기간 모드 등으로 start/end 가 비면 데이터 월만 사용)\n const months =\n this.startYearMonth && this.endYearMonth\n ? this.buildMonthRange(this.startYearMonth, this.endYearMonth)\n : [...byMonth.keys()].sort()\n\n let prev: number | null = null\n this.trendData = months.map(ym => {\n const d = byMonth.get(ym)\n const value = d ? Math.round(d.avgVal * 100) : 0 // 20배 스케일, 데이터 없으면 0\n // 직전 월 대비 증감 방향 — 추이 화살표/색상 기준 (값 임계치가 아니라 실제 증감)\n const trendDir: 'up' | 'down' | 'flat' = prev === null ? 'flat' : value > prev ? 'up' : value < prev ? 'down' : 'flat'\n prev = value\n return {\n date: ym, // YYYY-MM 형식\n value,\n color: value > 60 ? '#4caf50' : value > 40 ? '#ff9800' : '#f44336',\n trendDir\n }\n })\n }\n\n /** start~end(YYYY-MM) 사이 모든 월을 순서대로 반환. 잘못된 범위는 안전하게 종료. */\n private buildMonthRange(start: string, end: string): string[] {\n const [sy, sm] = start.split('-').map(Number)\n const [ey, em] = end.split('-').map(Number)\n if (!sy || !sm || !ey || !em) return []\n const out: string[] = []\n let y = sy\n let m = sm\n for (let i = 0; i < 240; i++) {\n out.push(`${y}-${String(m).padStart(2, '0')}`)\n if (y === ey && m === em) break\n if (y > ey || (y === ey && m > em)) break // start > end 방어\n m++\n if (m > 12) {\n m = 1\n y++\n }\n }\n return out\n }\n\n private onClose() {\n this.dispatchEvent(\n new CustomEvent('popup-close', {\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 render() {\n if (!this.selectedRegion) {\n return nothing\n }\n\n return html`\n <div class=\"popup-header\">\n <div class=\"popup-title\">${this.selectedRegion} KPI</div>\n <button class=\"popup-close\" @click=${this.onClose}>×</button>\n </div>\n <div class=\"popup-content\">\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.chartData.length === 0\n ? html`<div\n style=\"display:flex;align-items:center;justify-content:center;height:100%;color:#888;font-size:0.9rem;\"\n >\n 선택한 기간에 데이터가 없습니다.\n </div>`\n : this.selectedChartType === 'boxplot'\n ? html`\n <sv-kpi-boxplot-chart\n .data=${this.chartData}\n .groups=${this.chartCategories}\n .valueKey=${'value'}\n .valueLabel=${this.selectedRegion || '지역'}\n .showStatus=${false}\n ></sv-kpi-boxplot-chart>\n `\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=\"trend-section\">\n <div class=\"sub-title\">기간별 성과 추이</div>\n <div class=\"trend-chart-container\" style=\"height: 200px; margin-bottom: 16px;\">\n <sv-kpi-trend-chart\n .data=${this.trendData}\n .lineColor=${'#2196f3'}\n .strokeWidth=${2}\n .showPoints=${false}\n .pointRadius=${4}\n ></sv-kpi-trend-chart>\n </div>\n <div class=\"trend-table\">\n <table style=\"width: 100%; border-collapse: collapse; font-size: 0.85rem;\">\n <thead style=\"position: sticky; top: 0; background: white; z-index: 1;\">\n <tr style=\"border-bottom: 2px solid #f1f3f4; background-color: #f8f9fa;\">\n <th style=\"padding: 8px; text-align: left; font-weight: 600;\">날짜</th>\n <th style=\"padding: 8px; text-align: right; font-weight: 600;\">성과</th>\n <th style=\"padding: 8px; text-align: center; font-weight: 600;\">추이</th>\n </tr>\n </thead>\n <tbody>\n ${[...this.trendData].reverse().map(\n (item: any) => html`\n <tr style=\"border-bottom: 1px solid #f1f3f4;\">\n <td style=\"padding: 8px; font-size: 0.85rem;\">${item.date}</td>\n <td style=\"padding: 8px; text-align: right; font-size: 0.85rem; font-weight: 600;\">\n ${item.value.toFixed(1)}\n </td>\n <td style=\"padding: 8px; text-align: center; font-size: 0.85rem;\">\n <span style=\"color: ${item.trendDir === 'up' ? '#e53935' : item.trendDir === 'down' ? '#2196f3' : '#999'};\">\n ${item.trendDir === 'up' ? '▲' : item.trendDir === 'down' ? '▼' : ''}\n </span>\n </td>\n </tr>\n `\n )}\n </tbody>\n </table>\n </div>\n </div>\n </div>\n `\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"kpi-region-popup.js","sourceRoot":"","sources":["../../../../client/pages/kpi-dashboard/components/kpi-region-popup.ts"],"names":[],"mappings":"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","sourcesContent":["import gql from 'graphql-tag'\nimport { LitElement, html, css, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { client } from '@operato/graphql'\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport '../../../components/kpi-radar-chart.js'\nimport '../../../components/kpi-boxplot-chart.js'\nimport '../../../components/kpi-trend-chart.js'\n\n@customElement('kpi-region-popup')\nexport class KpiRegionPopup extends LitElement {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: block;\n position: absolute;\n top: 0;\n left: 402px;\n width: 400px;\n height: 100%;\n background: #fff;\n border-right: 1px solid #e0e0e0;\n z-index: 1000;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);\n }\n .popup-content {\n padding: 20px;\n overflow-y: auto;\n flex: 1;\n }\n .popup-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 .popup-title {\n font-size: 1.2rem;\n font-weight: bold;\n color: #333;\n }\n .popup-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 .popup-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 .period-selector {\n display: flex;\n gap: 8px;\n margin-bottom: 16px;\n }\n .period-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 }\n .period-button.active {\n background: #667eea;\n color: white;\n border-color: #667eea;\n }\n .date-range-selector {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 16px;\n }\n .date-select {\n padding: 6px 12px;\n border: 1px solid #ced4da;\n border-radius: 4px;\n background: white;\n font-size: 0.9rem;\n }\n `\n ]\n\n @property({ type: String }) selectedRegion: string | null = null\n @property({ type: String }) geoGroup: string | null = null // 시군구 geo_group 코드 (있으면 시군구 쿼리 사용)\n @property({ type: String }) selectedCategory = '전체 KPI'\n @property({ type: String }) selectedChartType = 'boxplot'\n @property({ type: String }) selectedPeriod = '월'\n @property({ type: String }) startYearMonth = '' // YYYY-MM 형식\n @property({ type: String }) endYearMonth = '' // YYYY-MM 형식\n @property({ type: Array }) monthlyTrendData: any[] = [] // 부모에서 전달받은 월별 추이 데이터\n @property({ type: Array }) totalKpiStats: any[] = [] // 전체 KPI 통계 (비교용)\n\n @state() private chartData: any[] = []\n @state() private chartCategories: string[] = []\n @state() private trendData: {\n date: string\n value: number | null\n color?: string\n trendDir?: 'up' | 'down' | 'flat' | 'none'\n }[] = []\n @state() private regionKpiStats: any[] = []\n\n updated(changedProperties: Map<string, any>) {\n if (changedProperties.has('selectedRegion') && this.selectedRegion) {\n this.fetchRegionKpiStats()\n this.generateTrendData()\n }\n\n // selectedCategory 또는 monthlyTrendData가 변경되면 추이 데이터 재생성\n if (changedProperties.has('selectedCategory') || changedProperties.has('monthlyTrendData')) {\n this.generateTrendData()\n }\n\n // 기간이 변경되면 차트 데이터 다시 가져오기\n if (changedProperties.has('startYearMonth') || changedProperties.has('endYearMonth')) {\n if (this.selectedRegion) {\n this.fetchRegionKpiStats()\n }\n // 기간이 바뀌면 추이도 그 기간 전체 축으로 다시 그림 (데이터 없는 월 포함)\n this.generateTrendData()\n }\n }\n\n async fetchRegionKpiStats() {\n if (!this.selectedRegion) return\n\n try {\n let regionKpiStats: any[]\n\n if (this.geoGroup) {\n // 시군구 모드: geo_group 코드로 조회\n const response = await client.query({\n query: gql`\n query GetSigunguKpiStats($geoGroup: String!, $startYearMonth: String, $endYearMonth: String) {\n kpiYValueStatsByGeoGroup(geoGroup: $geoGroup, startYearMonth: $startYearMonth, endYearMonth: $endYearMonth) {\n kpiName\n minVal\n q1Val\n medVal\n q3Val\n maxVal\n avgVal\n projectCount\n }\n }\n `,\n variables: {\n geoGroup: this.geoGroup,\n startYearMonth: this.startYearMonth,\n endYearMonth: this.endYearMonth\n }\n })\n regionKpiStats = response.data.kpiYValueStatsByGeoGroup || []\n } else {\n // 광역 모드: 광역시도 이름으로 조회\n const response = await client.query({\n query: gql`\n query GetRegionKpiStats($metroArea: String!, $startYearMonth: String, $endYearMonth: String) {\n kpiYValueStatsByMetroArea(metroArea: $metroArea, startYearMonth: $startYearMonth, endYearMonth: $endYearMonth) {\n kpiName\n minVal\n q1Val\n medVal\n q3Val\n maxVal\n avgVal\n projectCount\n }\n }\n `,\n variables: {\n metroArea: this.selectedRegion,\n startYearMonth: this.startYearMonth,\n endYearMonth: this.endYearMonth\n }\n })\n regionKpiStats = response.data.kpiYValueStatsByMetroArea || []\n }\n\n this.regionKpiStats = regionKpiStats\n this.generateChartData()\n } catch (error) {\n console.error('Failed to fetch region KPI stats:', error)\n this.regionKpiStats = []\n this.generateChartData()\n }\n }\n\n private generateChartData() {\n // kpiName 표기가 'Y1. 일정성과' / '일정성과(Y1)' 등으로 환경마다 달라 전체 문자열 매칭은 깨짐.\n // Y1~Y6 코드만 추출해 짧은 라벨로 매핑.\n const yLabelByCode: Record<string, string> = {\n Y1: '일정',\n Y2: '비용',\n Y3: '품질',\n Y4: '안전',\n Y5: '환경',\n Y6: '생산성'\n }\n const toCategory = (kpiName: string) => yLabelByCode[(kpiName || '').match(/Y[1-6]/)?.[0] ?? ''] || kpiName\n\n // 레이더 차트와 박스플롯은 항상 전체 Y-level KPI 표시 (selectedCategory 무시)\n if (this.selectedChartType === 'radar') {\n // 레이더 차트용 데이터 생성 — 지역 평균 단일 시리즈\n // (전체평균 기준선은 지역 평균과 차별성이 적어 제거 → 단일 시리즈라 범례도 자동 미표시)\n const data: Array<{ org: string; category: string; value: number }> = []\n const categories: string[] = []\n\n // 카테고리 수집\n this.regionKpiStats.forEach(stat => {\n const category = toCategory(stat.kpiName)\n if (!categories.includes(category)) {\n categories.push(category)\n }\n })\n\n // 지역 데이터 추가 (박스플롯과 동일 스케일·정밀도 — Math.round 제거해 수치 일치)\n this.regionKpiStats.forEach(stat => {\n const category = toCategory(stat.kpiName)\n data.push({\n org: this.selectedRegion || '지역',\n category,\n value: stat.avgVal * 100\n })\n })\n\n this.chartCategories = categories.length > 0 ? categories : ['일정', '비용', '품질', '안전', '환경', '생산성']\n this.chartData = data\n } else {\n // 박스플롯용 데이터 생성\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.regionKpiStats.forEach(stat => {\n const category = toCategory(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 }\n }\n\n // geo_group → 광역시도 매핑 (시군구 모드에서 추이 데이터 조회용)\n private static readonly GEO_TO_METRO: Record<string, string> = {\n '01': '서울특별시',\n '02': '서울특별시',\n '03': '서울특별시',\n '04': '서울특별시',\n '05': '서울특별시',\n '06': '서울특별시',\n '07': '서울특별시',\n '08': '서울특별시',\n '10': '경기도',\n '11': '경기도',\n '12': '경기도',\n '13': '경기도',\n '14': '경기도',\n '15': '경기도',\n '16': '경기도',\n '17': '경기도',\n '18': '경기도',\n '21': '인천광역시',\n '22': '인천광역시',\n '23': '인천광역시',\n '24': '강원도',\n '25': '강원도',\n '26': '강원도',\n '33': '강원도',\n '27': '충청북도',\n '28': '충청북도',\n '29': '충청북도',\n '30': '세종특별자치시',\n '31': '충청남도',\n '32': '충청남도',\n '34': '대전광역시',\n '35': '대전광역시',\n '36': '경상북도',\n '37': '경상북도',\n '38': '경상북도',\n '39': '경상북도',\n '40': '경상북도',\n '41': '대구광역시',\n '42': '대구광역시',\n '43': '대구광역시',\n '44': '울산광역시',\n '45': '울산광역시',\n '46': '부산광역시',\n '47': '부산광역시',\n '48': '부산광역시',\n '49': '부산광역시',\n '50': '경상남도',\n '51': '경상남도',\n '52': '경상남도',\n '53': '경상남도',\n '54': '전라북도',\n '55': '전라북도',\n '56': '전라북도',\n '57': '전라남도',\n '58': '전라남도',\n '59': '전라남도',\n '61': '광주광역시',\n '62': '광주광역시',\n '63': '제주특별자치도'\n }\n\n private generateTrendData() {\n if (!this.selectedRegion) return\n\n // 시군구 모드인 경우 소속 광역시도의 추이 데이터 사용\n const trendRegion = this.geoGroup ? KpiRegionPopup.GEO_TO_METRO[this.geoGroup] || this.selectedRegion : this.selectedRegion\n\n // 해당 지역의 월별 데이터를 YYYY-MM 기준 맵으로\n const byMonth = new Map<string, any>()\n this.monthlyTrendData.filter(d => d.geoGroup === trendRegion).forEach(d => byMonth.set(d.yearMonth, d))\n\n // 선택 기간(start~end) 전체 월을 축으로 사용 — 데이터가 없는 월도 레코드(값 0)로 채워\n // 전국 패널의 기간과 동일한 범위를 플로팅. (전체 기간 모드 등으로 start/end 가 비면 데이터 월만 사용)\n const months =\n this.startYearMonth && this.endYearMonth\n ? this.buildMonthRange(this.startYearMonth, this.endYearMonth)\n : [...byMonth.keys()].sort()\n\n let prev: number | null = null\n this.trendData = months.map(ym => {\n const d = byMonth.get(ym)\n const hasData = !!d\n // 데이터 없는 월은 0이 아니라 null — 0(실제 0점)과 구분하여 플로팅/표시에서 제외.\n // 값은 반올림하지 않음(정수화하면 표의 소수점이 항상 .0 으로 나옴) — 표시 시 toFixed(1) 적용.\n const value: number | null = hasData ? d.avgVal * 100 : null\n // 추이: 무데이터 'none', 직전 데이터 없으면(첫 점) 'flat', 그 외 실제 증감 비교\n let trendDir: 'up' | 'down' | 'flat' | 'none'\n if (!hasData) {\n trendDir = 'none'\n } else if (prev === null) {\n trendDir = 'flat'\n } else {\n trendDir = value! > prev ? 'up' : value! < prev ? 'down' : 'flat'\n }\n if (hasData) prev = value\n return {\n date: ym, // YYYY-MM 형식\n value,\n color: value == null ? undefined : value > 60 ? '#4caf50' : value > 40 ? '#ff9800' : '#f44336',\n trendDir\n }\n })\n }\n\n /** start~end(YYYY-MM) 사이 모든 월을 순서대로 반환. 잘못된 범위는 안전하게 종료. */\n private buildMonthRange(start: string, end: string): string[] {\n const [sy, sm] = start.split('-').map(Number)\n const [ey, em] = end.split('-').map(Number)\n if (!sy || !sm || !ey || !em) return []\n const out: string[] = []\n let y = sy\n let m = sm\n for (let i = 0; i < 240; i++) {\n out.push(`${y}-${String(m).padStart(2, '0')}`)\n if (y === ey && m === em) break\n if (y > ey || (y === ey && m > em)) break // start > end 방어\n m++\n if (m > 12) {\n m = 1\n y++\n }\n }\n return out\n }\n\n private onClose() {\n this.dispatchEvent(\n new CustomEvent('popup-close', {\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 render() {\n if (!this.selectedRegion) {\n return nothing\n }\n\n return html`\n <div class=\"popup-header\">\n <div class=\"popup-title\">${this.selectedRegion} KPI</div>\n <button class=\"popup-close\" @click=${this.onClose}>×</button>\n </div>\n <div class=\"popup-content\">\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.chartData.length === 0\n ? html`<div\n style=\"display:flex;align-items:center;justify-content:center;height:100%;color:#888;font-size:0.9rem;\"\n >\n 선택한 기간에 데이터가 없습니다.\n </div>`\n : this.selectedChartType === 'boxplot'\n ? html`\n <sv-kpi-boxplot-chart\n .data=${this.chartData}\n .groups=${this.chartCategories}\n .valueKey=${'value'}\n .valueLabel=${this.selectedRegion || '지역'}\n .showStatus=${false}\n ></sv-kpi-boxplot-chart>\n `\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=\"trend-section\">\n <div class=\"sub-title\">기간별 성과 추이</div>\n <div class=\"trend-chart-container\" style=\"height: 200px; margin-bottom: 16px;\">\n <sv-kpi-trend-chart\n .data=${this.trendData}\n .lineColor=${'#2196f3'}\n .strokeWidth=${2}\n .showPoints=${false}\n .pointRadius=${4}\n ></sv-kpi-trend-chart>\n </div>\n <div class=\"trend-table\">\n <table style=\"width: 100%; border-collapse: collapse; font-size: 0.85rem;\">\n <thead style=\"position: sticky; top: 0; background: white; z-index: 1;\">\n <tr style=\"border-bottom: 2px solid #f1f3f4; background-color: #f8f9fa;\">\n <th style=\"padding: 8px; text-align: left; font-weight: 600;\">날짜</th>\n <th style=\"padding: 8px; text-align: right; font-weight: 600;\">성과</th>\n <th style=\"padding: 8px; text-align: center; font-weight: 600;\">추이</th>\n </tr>\n </thead>\n <tbody>\n ${[...this.trendData].reverse().map(\n (item: any) => html`\n <tr style=\"border-bottom: 1px solid #f1f3f4;\">\n <td style=\"padding: 8px; font-size: 0.85rem;\">${item.date}</td>\n <td style=\"padding: 8px; text-align: right; font-size: 0.85rem; font-weight: 600;\">\n ${item.value != null ? item.value.toFixed(1) : '-'}\n </td>\n <td style=\"padding: 8px; text-align: center; font-size: 0.85rem;\">\n <span style=\"color: ${item.trendDir === 'up' ? '#e53935' : item.trendDir === 'down' ? '#2196f3' : '#999'};\">\n ${item.trendDir === 'up' ? '▲' : item.trendDir === 'down' ? '▼' : '–'}\n </span>\n </td>\n </tr>\n `\n )}\n </tbody>\n </table>\n </div>\n </div>\n </div>\n `\n }\n}\n"]}
|