@dssp/dkpi 1.0.0-alpha.65 → 1.0.0-alpha.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/_index.html +0 -5
- package/dist-client/components/kpi-2d-lookup-chart.d.ts +63 -0
- package/dist-client/components/kpi-2d-lookup-chart.js +470 -0
- package/dist-client/components/kpi-2d-lookup-chart.js.map +1 -0
- package/dist-client/google-map/common-google-map.js +10 -8
- package/dist-client/google-map/common-google-map.js.map +1 -1
- package/dist-client/pages/kpi-admin/dssp-kpi-list-page.d.ts +22 -0
- package/dist-client/pages/kpi-admin/dssp-kpi-list-page.js +57 -0
- package/dist-client/pages/kpi-admin/dssp-kpi-list-page.js.map +1 -0
- package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.d.ts +20 -0
- package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.js +445 -0
- package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.js.map +1 -0
- package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.d.ts +6 -5
- package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js +47 -68
- package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js.map +1 -1
- package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.d.ts +3 -2
- package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js +79 -122
- package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js.map +1 -1
- package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.d.ts +3 -2
- package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js +71 -107
- package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js.map +1 -1
- package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.d.ts +4 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js +246 -28
- package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js.map +1 -1
- package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.d.ts +4 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js +22 -207
- package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js.map +1 -1
- package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.d.ts +2 -0
- package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js +84 -25
- package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js.map +1 -1
- package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.d.ts +16 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js +261 -31
- package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js.map +1 -1
- package/dist-client/pages/kpi-dashboard/kpi-dashboard.d.ts +4 -0
- package/dist-client/pages/kpi-dashboard/kpi-dashboard.js +66 -4
- package/dist-client/pages/kpi-dashboard/kpi-dashboard.js.map +1 -1
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.d.ts +1 -2
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js +1 -2
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js.map +1 -1
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.d.ts +1 -2
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js +1 -2
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js.map +1 -1
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.d.ts +1 -2
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js +1 -2
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js.map +1 -1
- package/dist-client/pages/kpi-value/kpi-value-list-page.d.ts +1 -2
- package/dist-client/pages/kpi-value/kpi-value-list-page.js +1 -2
- package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -1
- package/dist-client/pages/sv-project-detail.d.ts +1 -0
- package/dist-client/pages/sv-project-detail.js +26 -13
- package/dist-client/pages/sv-project-detail.js.map +1 -1
- package/dist-client/pages/sv-project-list.js +6 -6
- package/dist-client/pages/sv-project-list.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/route.js +4 -0
- package/dist-client/route.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/viewparts/menu-tools.d.ts +1 -2
- package/dist-client/viewparts/menu-tools.js +1 -2
- package/dist-client/viewparts/menu-tools.js.map +1 -1
- package/dist-server/scripts/calculate-kpi-scores.js +65 -3
- package/dist-server/scripts/calculate-kpi-scores.js.map +1 -1
- package/dist-server/scripts/load-grade-data-migration.d.ts +4 -0
- package/dist-server/scripts/load-grade-data-migration.js +95 -10
- package/dist-server/scripts/load-grade-data-migration.js.map +1 -1
- package/dist-server/scripts/propagate-parent-kpi-values.js +58 -4
- package/dist-server/scripts/propagate-parent-kpi-values.js.map +1 -1
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.d.ts +6 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +57 -7
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -1
- package/dist-server/service/kpi-stat/kpi-stat-query.d.ts +8 -5
- package/dist-server/service/kpi-stat/kpi-stat-query.js +228 -11
- package/dist-server/service/kpi-stat/kpi-stat-query.js.map +1 -1
- package/dist-server/service/kpi-stat/kpi-stat-types.d.ts +13 -0
- package/dist-server/service/kpi-stat/kpi-stat-types.js +51 -1
- package/dist-server/service/kpi-stat/kpi-stat-types.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +54 -54
- package/schema.graphql +95 -58
- package/things-factory.config.js +3 -1
- package/views/auth-page.html +0 -1
- package/views/public/home.html +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kpi-grade-2d-editor.js","sourceRoot":"","sources":["../../../client/pages/kpi-admin/kpi-grade-2d-editor.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/button/filled-button.js'\nimport '@material/web/icon/icon.js'\nimport '@operato/data-grist/ox-grist.js'\n\nimport gql from 'graphql-tag'\nimport * as d3 from 'd3'\nimport { LitElement, css, html } from 'lit'\nimport { customElement, property, state, query } from 'lit/decorators.js'\nimport { client } from '@operato/graphql'\nimport { notify } from '@operato/layout'\nimport { CommonHeaderStyles } from '@operato/styles'\nimport { DataGrist, FetchOption } from '@operato/data-grist'\n\ninterface Grade2DRow {\n progressRate: number\n boundary5to4: number\n boundary4to3: number\n boundary3to2: number\n boundary2to1: number\n}\n\n// 점수 구간 정의 (높은 점수 = 좋음 = 낮은 공기편차)\nconst SCORE_ZONES = [\n { score: 5, label: '5점', color: '#1b5e20', fillColor: 'rgba(76,175,80,0.15)' },\n { score: 4, label: '4점', color: '#33691e', fillColor: 'rgba(139,195,74,0.15)' },\n { score: 3, label: '3점', color: '#e65100', fillColor: 'rgba(255,193,7,0.15)' },\n { score: 2, label: '2점', color: '#bf360c', fillColor: 'rgba(255,152,0,0.15)' },\n { score: 1, label: '1점', color: '#b71c1c', fillColor: 'rgba(244,67,54,0.15)' }\n]\n\nconst BOUNDARIES = [\n { key: 'boundary5to4' as const, label: '5점 기준선', subLabel: '이하 → 5점', color: '#4caf50' },\n { key: 'boundary4to3' as const, label: '4점 기준선', subLabel: '이하 → 4점', color: '#8bc34a' },\n { key: 'boundary3to2' as const, label: '3점 기준선', subLabel: '이하 → 3점', color: '#ff9800' },\n { key: 'boundary2to1' as const, label: '2점 기준선', subLabel: '이하 → 2점', color: '#f44336' }\n]\n\n@customElement('kpi-grade-2d-editor')\nexport class KpiGrade2dEditor extends LitElement {\n static styles = [\n CommonHeaderStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n height: 100%;\n background-color: var(--md-sys-color-surface);\n }\n\n .info-bar {\n display: flex;\n align-items: center;\n gap: 24px;\n padding: 8px 16px;\n background: var(--md-sys-color-surface-variant, #f5f5f5);\n border-bottom: 1px solid var(--md-sys-color-outline-variant, #ddd);\n font-size: 12px;\n color: var(--md-sys-color-on-surface-variant, #555);\n flex-shrink: 0;\n }\n\n .info-bar .rule {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .info-bar .arrow {\n color: #888;\n }\n\n .score-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n border-radius: 50%;\n font-size: 11px;\n font-weight: bold;\n color: #fff;\n }\n\n .chart-wrap {\n padding: 8px 16px 0;\n flex-shrink: 0;\n position: relative;\n }\n\n .chart-wrap svg {\n width: 100%;\n display: block;\n }\n\n .legend {\n display: flex;\n gap: 20px;\n padding: 4px 16px 8px;\n font-size: 12px;\n flex-shrink: 0;\n flex-wrap: wrap;\n }\n\n .legend-item {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .legend-line {\n width: 20px;\n height: 3px;\n border-radius: 2px;\n }\n\n .legend-sub {\n color: #888;\n font-size: 11px;\n }\n\n ox-grist {\n flex: 1;\n overflow: hidden;\n }\n\n .footer {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 8px 16px;\n border-top: 1px solid var(--md-sys-color-outline-variant, #ccc);\n flex-shrink: 0;\n }\n `\n ]\n\n @property({ type: Object }) kpi: any\n @state() private rows: Grade2DRow[] = []\n @state() private gristConfig: any = null\n @query('ox-grist') private grist!: DataGrist\n @query('svg') private svgEl!: SVGElement\n\n firstUpdated() {\n const grades = this.kpi?.grades\n this.rows = grades?.rows ? grades.rows.map((r: any) => ({ ...r })) : []\n\n this.gristConfig = {\n list: { fields: ['progressRate', 'boundary5to4', 'boundary4to3', 'boundary3to2', 'boundary2to1'] },\n columns: [\n { type: 'gutter', gutterName: 'sequence', fixed: true },\n {\n type: 'number',\n name: 'progressRate',\n header: '공정률 (%)',\n record: { editable: false },\n sortable: false,\n width: 90\n },\n {\n type: 'number',\n name: 'boundary5to4',\n header: '5점 기준선',\n record: { editable: true, align: 'right' },\n width: 110\n },\n {\n type: 'number',\n name: 'boundary4to3',\n header: '4점 기준선',\n record: { editable: true, align: 'right' },\n width: 110\n },\n {\n type: 'number',\n name: 'boundary3to2',\n header: '3점 기준선',\n record: { editable: true, align: 'right' },\n width: 110\n },\n {\n type: 'number',\n name: 'boundary2to1',\n header: '2점 기준선',\n record: { editable: true, align: 'right' },\n width: 110\n }\n ],\n rows: { selectable: false, appendable: false },\n pagination: { infinite: true }\n }\n\n requestAnimationFrame(() => this._drawChart(this.rows))\n }\n\n render() {\n return html`\n <div class=\"info-bar\">\n <span><strong>X축</strong>: 공정률 (%)</span>\n <span><strong>Y축</strong>: 공기편차 (%)</span>\n <span class=\"arrow\">|</span>\n <span class=\"rule\">\n 공기편차\n <span class=\"score-badge\" style=\"background:#4caf50\">5</span>\n 기준선 미만 → 5점,\n <span class=\"score-badge\" style=\"background:#8bc34a\">4</span>\n 기준선 미만 → 4점,\n <span class=\"score-badge\" style=\"background:#ff9800\">3</span>\n 기준선 미만 → 3점,\n <span class=\"score-badge\" style=\"background:#f44336\">2</span>\n 기준선 미만 → 2점, 초과 → 1점\n </span>\n </div>\n\n <div class=\"chart-wrap\">\n <svg height=\"220\"></svg>\n </div>\n\n <div class=\"legend\">\n ${BOUNDARIES.map(\n b => html`\n <div class=\"legend-item\">\n <div class=\"legend-line\" style=\"background:${b.color}\"></div>\n <span>${b.label}</span>\n <span class=\"legend-sub\">(${b.subLabel})</span>\n </div>\n `\n )}\n </div>\n\n <ox-grist\n .mode=${'GRID'}\n .config=${this.gristConfig}\n .fetchHandler=${this._fetchHandler.bind(this)}\n @change=${this._onGristChange}\n ></ox-grist>\n\n <div class=\"footer\">\n <md-filled-button @click=${this._save}>\n <md-icon slot=\"icon\">save</md-icon>\n 저장\n </md-filled-button>\n </div>\n `\n }\n\n private async _fetchHandler({ page, limit }: FetchOption) {\n return { total: this.rows.length, records: this.rows }\n }\n\n private _onGristChange() {\n this._drawChart(this._getCurrentRows())\n }\n\n private _getCurrentRows(): Grade2DRow[] {\n const records = this.grist?.dirtyData?.records\n if (!records || records.length === 0) return this.rows\n\n return records.map((r: any) => ({\n progressRate: r.progressRate,\n boundary5to4: Number(r.boundary5to4),\n boundary4to3: Number(r.boundary4to3),\n boundary3to2: Number(r.boundary3to2),\n boundary2to1: Number(r.boundary2to1)\n }))\n }\n\n private _drawChart(rows: Grade2DRow[]) {\n if (!this.svgEl || !rows.length) return\n\n const W = this.svgEl.clientWidth || 560\n const H = 220\n const m = { top: 16, right: 32, bottom: 36, left: 56 }\n const w = W - m.left - m.right\n const h = H - m.top - m.bottom\n\n const svg = d3.select(this.svgEl).attr('height', H)\n svg.selectAll('*').remove()\n\n const g = svg.append('g').attr('transform', `translate(${m.left},${m.top})`)\n\n const x = d3.scaleLinear().domain([0, 99]).range([0, w])\n\n const allVals = rows.flatMap(r => [r.boundary5to4, r.boundary4to3, r.boundary3to2, r.boundary2to1])\n const [yMin, yMax] = d3.extent(allVals) as [number, number]\n const pad = (yMax - yMin) * 0.15 || 5\n const y = d3.scaleLinear().domain([yMin - pad, yMax + pad]).range([h, 0])\n\n // 점수 구간 채우기 (5개 존)\n const zoneDefs: Array<{ y0: (r: Grade2DRow) => number; y1: (r: Grade2DRow) => number; fill: string; label: string }> = [\n { y0: _r => h, y1: r => y(r.boundary5to4), fill: 'rgba(76,175,80,0.12)', label: '5점' },\n { y0: r => y(r.boundary5to4), y1: r => y(r.boundary4to3), fill: 'rgba(139,195,74,0.12)', label: '4점' },\n { y0: r => y(r.boundary4to3), y1: r => y(r.boundary3to2), fill: 'rgba(255,193,7,0.12)', label: '3점' },\n { y0: r => y(r.boundary3to2), y1: r => y(r.boundary2to1), fill: 'rgba(255,152,0,0.12)', label: '2점' },\n { y0: r => y(r.boundary2to1), y1: _r => 0, fill: 'rgba(244,67,54,0.12)', label: '1점' }\n ]\n\n for (const zone of zoneDefs) {\n const area = d3.area<Grade2DRow>()\n .x(r => x(r.progressRate))\n .y0(zone.y0)\n .y1(zone.y1)\n .curve(d3.curveMonotoneX)\n\n g.append('path')\n .datum(rows)\n .attr('fill', zone.fill)\n .attr('d', area)\n }\n\n // 중간 공정률 지점에 점수 레이블\n const midRow = rows[Math.floor(rows.length / 2)]\n if (midRow) {\n const scoreColors = ['#2e7d32', '#558b2f', '#f57f17', '#e65100', '#c62828']\n const scorePositions = [\n (h + y(midRow.boundary5to4)) / 2,\n (y(midRow.boundary5to4) + y(midRow.boundary4to3)) / 2,\n (y(midRow.boundary4to3) + y(midRow.boundary3to2)) / 2,\n (y(midRow.boundary3to2) + y(midRow.boundary2to1)) / 2,\n y(midRow.boundary2to1) / 2\n ]\n const scoreLabels = ['5점', '4점', '3점', '2점', '1점']\n\n scorePositions.forEach((yPos, i) => {\n if (yPos > 4 && yPos < h - 4) {\n g.append('text')\n .attr('x', w - 4)\n .attr('y', yPos)\n .attr('text-anchor', 'end')\n .attr('dominant-baseline', 'middle')\n .attr('font-size', '10px')\n .attr('font-weight', 'bold')\n .attr('fill', scoreColors[i])\n .attr('opacity', 0.8)\n .text(scoreLabels[i])\n }\n })\n }\n\n // 격자선\n g.append('g')\n .attr('stroke', '#e0e0e0')\n .attr('stroke-dasharray', '2,3')\n .selectAll('line')\n .data(y.ticks(5))\n .join('line')\n .attr('x1', 0).attr('x2', w)\n .attr('y1', d => y(d)).attr('y2', d => y(d))\n\n // y=0 기준선 (공기편차 0%)\n const yZero = y(0)\n if (yZero >= 0 && yZero <= h) {\n g.append('line')\n .attr('x1', 0).attr('x2', w)\n .attr('y1', yZero).attr('y2', yZero)\n .attr('stroke', '#90a4ae')\n .attr('stroke-width', 1)\n .attr('stroke-dasharray', '4,2')\n g.append('text')\n .attr('x', -4)\n .attr('y', yZero)\n .attr('text-anchor', 'end')\n .attr('dominant-baseline', 'middle')\n .attr('font-size', '9px')\n .attr('fill', '#90a4ae')\n .text('0%')\n }\n\n // X축\n g.append('g')\n .attr('transform', `translate(0,${h})`)\n .call(d3.axisBottom(x).ticks(10).tickFormat(d => `${d}%`))\n .selectAll('text')\n .style('font-size', '10px')\n\n // X축 레이블\n g.append('text')\n .attr('x', w / 2)\n .attr('y', h + 30)\n .attr('text-anchor', 'middle')\n .attr('font-size', '11px')\n .attr('fill', '#666')\n .text('공정률 (%)')\n\n // Y축\n g.append('g')\n .call(d3.axisLeft(y).ticks(5))\n .selectAll('text')\n .style('font-size', '10px')\n\n // Y축 레이블\n g.append('text')\n .attr('transform', 'rotate(-90)')\n .attr('x', -h / 2)\n .attr('y', -44)\n .attr('text-anchor', 'middle')\n .attr('font-size', '11px')\n .attr('fill', '#666')\n .text('공기편차 (%)')\n\n // 4개 경계선\n for (const { key, color } of BOUNDARIES) {\n const line = d3\n .line<Grade2DRow>()\n .x(r => x(r.progressRate))\n .y(r => y(r[key]))\n .curve(d3.curveMonotoneX)\n\n g.append('path')\n .datum(rows)\n .attr('fill', 'none')\n .attr('stroke', color)\n .attr('stroke-width', 2)\n .attr('d', line)\n }\n }\n\n private _validate(rows: Grade2DRow[]): boolean {\n for (const row of rows) {\n const { progressRate: p, boundary5to4: b54, boundary4to3: b43, boundary3to2: b32, boundary2to1: b21 } = row\n if (!(b54 < b43 && b43 < b32 && b32 < b21)) {\n notify({\n message: `공정률 ${p}%행: 기준선 값이 잘못됐습니다. 5점 < 4점 < 3점 < 2점 기준선 순서여야 합니다.`,\n level: 'error'\n })\n return false\n }\n }\n return true\n }\n\n private async _save() {\n const rows = this._getCurrentRows()\n if (!this._validate(rows)) return\n\n const grades = { type: 'PROGRESS_DEVIATION_LOOKUP', rows }\n\n try {\n await client.mutate({\n mutation: gql`\n mutation ($id: String!, $patch: KpiPatch!) {\n updateKpi(id: $id, patch: $patch) {\n id\n grades\n scoreType\n }\n }\n `,\n variables: {\n id: this.kpi.id,\n patch: { grades, scoreType: 'CUSTOM' }\n }\n })\n\n this.rows = rows\n this._drawChart(rows)\n notify({ message: '저장되었습니다.' })\n } catch (e) {\n notify({ message: '저장 중 오류가 발생했습니다.', level: 'error' })\n }\n }\n}\n"]}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { LitElement } from 'lit';
|
|
2
2
|
export declare class KpiLevel1Card extends LitElement {
|
|
3
3
|
static styles: import("lit").CSSResult;
|
|
4
|
+
sectorType: string;
|
|
5
|
+
buildingUsage: string;
|
|
4
6
|
loading: boolean;
|
|
5
7
|
error: string;
|
|
6
8
|
totalScore: number;
|
|
7
9
|
grade: string;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
currentMonth: string;
|
|
10
|
+
projectCount: number;
|
|
11
|
+
minScore: number;
|
|
12
|
+
maxScore: number;
|
|
12
13
|
connectedCallback(): void;
|
|
13
|
-
|
|
14
|
+
updated(changedProperties: Map<string, unknown>): void;
|
|
14
15
|
private calculateGrade;
|
|
15
16
|
fetchTotalScore(): Promise<void>;
|
|
16
17
|
render(): import("lit-html").TemplateResult<1>;
|
|
@@ -1,31 +1,30 @@
|
|
|
1
1
|
import { __decorate, __metadata } from "tslib";
|
|
2
2
|
import { html, css } from 'lit';
|
|
3
|
-
import { customElement, state } from 'lit/decorators.js';
|
|
3
|
+
import { customElement, state, property } from 'lit/decorators.js';
|
|
4
4
|
import { LitElement } from 'lit';
|
|
5
5
|
import { client } from '@operato/graphql';
|
|
6
6
|
import gql from 'graphql-tag';
|
|
7
7
|
let KpiLevel1Card = class KpiLevel1Card extends LitElement {
|
|
8
8
|
constructor() {
|
|
9
9
|
super(...arguments);
|
|
10
|
+
this.sectorType = '';
|
|
11
|
+
this.buildingUsage = '';
|
|
10
12
|
this.loading = true;
|
|
11
13
|
this.error = '';
|
|
12
14
|
this.totalScore = 0;
|
|
13
15
|
this.grade = '';
|
|
14
|
-
this.
|
|
15
|
-
this.
|
|
16
|
-
this.
|
|
17
|
-
this.currentMonth = '';
|
|
16
|
+
this.projectCount = 0;
|
|
17
|
+
this.minScore = 0;
|
|
18
|
+
this.maxScore = 0;
|
|
18
19
|
}
|
|
19
20
|
connectedCallback() {
|
|
20
21
|
super.connectedCallback();
|
|
21
|
-
this.currentMonth = this.getCurrentMonth();
|
|
22
22
|
this.fetchTotalScore();
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return `${year}-${month}`;
|
|
24
|
+
updated(changedProperties) {
|
|
25
|
+
if (changedProperties.has('sectorType') || changedProperties.has('buildingUsage')) {
|
|
26
|
+
this.fetchTotalScore();
|
|
27
|
+
}
|
|
29
28
|
}
|
|
30
29
|
calculateGrade(score) {
|
|
31
30
|
if (score >= 90)
|
|
@@ -54,55 +53,32 @@ let KpiLevel1Card = class KpiLevel1Card extends LitElement {
|
|
|
54
53
|
try {
|
|
55
54
|
const response = await client.query({
|
|
56
55
|
query: gql `
|
|
57
|
-
query {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
median
|
|
65
|
-
kpi {
|
|
66
|
-
id
|
|
67
|
-
name
|
|
68
|
-
targetValue
|
|
69
|
-
unit
|
|
70
|
-
category: parent {
|
|
71
|
-
id
|
|
72
|
-
name
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
56
|
+
query KpiLevel1Stats($sectorType: String, $buildingUsage: String) {
|
|
57
|
+
kpiProjectStats(kpiNamePattern: "Z", sectorType: $sectorType, buildingUsage: $buildingUsage) {
|
|
58
|
+
kpiName
|
|
59
|
+
avgVal
|
|
60
|
+
minVal
|
|
61
|
+
maxVal
|
|
62
|
+
projectCount
|
|
76
63
|
}
|
|
77
64
|
}
|
|
78
|
-
|
|
65
|
+
`,
|
|
66
|
+
variables: {
|
|
67
|
+
sectorType: this.sectorType || null,
|
|
68
|
+
buildingUsage: this.buildingUsage || null
|
|
69
|
+
}
|
|
79
70
|
});
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (currentMonthStats.length === 0) {
|
|
84
|
-
this.error = '현재 월의 데이터가 없습니다.';
|
|
71
|
+
const stats = response.data.kpiProjectStats || [];
|
|
72
|
+
if (stats.length === 0) {
|
|
73
|
+
this.error = '데이터가 없습니다.';
|
|
85
74
|
return;
|
|
86
75
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
var _a;
|
|
90
|
-
const mean = stat.mean || 0;
|
|
91
|
-
const targetValue = ((_a = stat.kpi) === null || _a === void 0 ? void 0 : _a.targetValue) || 100;
|
|
92
|
-
if (targetValue === 0)
|
|
93
|
-
return 0;
|
|
94
|
-
// 목표 대비 달성률 계산 (최대 100점)
|
|
95
|
-
const achievement = Math.min((mean / targetValue) * 100, 100);
|
|
96
|
-
return Math.max(achievement, 0); // 음수 방지
|
|
97
|
-
});
|
|
98
|
-
this.totalScore = Math.round(scores.reduce((sum, score) => sum + score, 0) / scores.length);
|
|
76
|
+
const zStat = stats[0];
|
|
77
|
+
this.totalScore = Math.round(zStat.avgVal * 100);
|
|
99
78
|
this.grade = this.calculateGrade(this.totalScore);
|
|
100
|
-
this.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
this.totalCategories = categories.size;
|
|
104
|
-
// 평균 점수 계산
|
|
105
|
-
this.averageScore = Math.round(scores.reduce((sum, score) => sum + score, 0) / scores.length);
|
|
79
|
+
this.projectCount = zStat.projectCount;
|
|
80
|
+
this.minScore = Math.round(zStat.minVal * 100);
|
|
81
|
+
this.maxScore = Math.round(zStat.maxVal * 100);
|
|
106
82
|
}
|
|
107
83
|
catch (e) {
|
|
108
84
|
console.error('총점 데이터를 불러오지 못했습니다:', e);
|
|
@@ -133,20 +109,19 @@ let KpiLevel1Card = class KpiLevel1Card extends LitElement {
|
|
|
133
109
|
<div class="score-title">그룹 총점</div>
|
|
134
110
|
<div class="score-value">${this.totalScore}</div>
|
|
135
111
|
<div class="score-grade">${this.grade}</div>
|
|
136
|
-
<div class="score-period">${this.currentMonth} 기준</div>
|
|
137
112
|
|
|
138
113
|
<div class="score-details">
|
|
139
114
|
<div class="detail-item">
|
|
140
|
-
<div class="detail-value">${this.
|
|
141
|
-
<div class="detail-label"
|
|
115
|
+
<div class="detail-value">${this.projectCount}</div>
|
|
116
|
+
<div class="detail-label">분석 프로젝트</div>
|
|
142
117
|
</div>
|
|
143
118
|
<div class="detail-item">
|
|
144
|
-
<div class="detail-value">${this.
|
|
145
|
-
<div class="detail-label"
|
|
119
|
+
<div class="detail-value">${this.minScore}</div>
|
|
120
|
+
<div class="detail-label">최저</div>
|
|
146
121
|
</div>
|
|
147
122
|
<div class="detail-item">
|
|
148
|
-
<div class="detail-value">${this.
|
|
149
|
-
<div class="detail-label"
|
|
123
|
+
<div class="detail-value">${this.maxScore}</div>
|
|
124
|
+
<div class="detail-label">최고</div>
|
|
150
125
|
</div>
|
|
151
126
|
</div>
|
|
152
127
|
</div>
|
|
@@ -241,6 +216,14 @@ KpiLevel1Card.styles = css `
|
|
|
241
216
|
font-size: 1.1rem;
|
|
242
217
|
}
|
|
243
218
|
`;
|
|
219
|
+
__decorate([
|
|
220
|
+
property({ type: String }),
|
|
221
|
+
__metadata("design:type", String)
|
|
222
|
+
], KpiLevel1Card.prototype, "sectorType", void 0);
|
|
223
|
+
__decorate([
|
|
224
|
+
property({ type: String }),
|
|
225
|
+
__metadata("design:type", String)
|
|
226
|
+
], KpiLevel1Card.prototype, "buildingUsage", void 0);
|
|
244
227
|
__decorate([
|
|
245
228
|
state(),
|
|
246
229
|
__metadata("design:type", Object)
|
|
@@ -260,19 +243,15 @@ __decorate([
|
|
|
260
243
|
__decorate([
|
|
261
244
|
state(),
|
|
262
245
|
__metadata("design:type", Object)
|
|
263
|
-
], KpiLevel1Card.prototype, "
|
|
264
|
-
__decorate([
|
|
265
|
-
state(),
|
|
266
|
-
__metadata("design:type", Object)
|
|
267
|
-
], KpiLevel1Card.prototype, "totalCategories", void 0);
|
|
246
|
+
], KpiLevel1Card.prototype, "projectCount", void 0);
|
|
268
247
|
__decorate([
|
|
269
248
|
state(),
|
|
270
249
|
__metadata("design:type", Object)
|
|
271
|
-
], KpiLevel1Card.prototype, "
|
|
250
|
+
], KpiLevel1Card.prototype, "minScore", void 0);
|
|
272
251
|
__decorate([
|
|
273
252
|
state(),
|
|
274
253
|
__metadata("design:type", Object)
|
|
275
|
-
], KpiLevel1Card.prototype, "
|
|
254
|
+
], KpiLevel1Card.prototype, "maxScore", void 0);
|
|
276
255
|
KpiLevel1Card = __decorate([
|
|
277
256
|
customElement('kpi-level1-card')
|
|
278
257
|
], KpiLevel1Card);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kpi-level1-card.js","sourceRoot":"","sources":["../../../../client/pages/kpi-dashboard/cards/kpi-level1-card.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, css } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\nimport { LitElement } from 'lit'\nimport { client } from '@operato/graphql'\nimport gql from 'graphql-tag'\n\n@customElement('kpi-level1-card')\nexport class KpiLevel1Card extends LitElement {\n static styles = css`\n :host {\n display: block;\n }\n .score-card {\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n border-radius: 16px;\n padding: 32px;\n color: white;\n box-shadow: 0 8px 32px rgba(102, 126, 234, 0.3);\n text-align: center;\n position: relative;\n overflow: hidden;\n }\n .score-card::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(255, 255, 255, 0.1);\n border-radius: 16px;\n }\n .score-content {\n position: relative;\n z-index: 1;\n }\n .score-title {\n font-size: 1.2rem;\n font-weight: 600;\n margin-bottom: 16px;\n opacity: 0.9;\n }\n .score-value {\n font-size: 4rem;\n font-weight: bold;\n margin-bottom: 8px;\n text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);\n }\n .score-grade {\n font-size: 1.5rem;\n font-weight: 600;\n margin-bottom: 16px;\n opacity: 0.9;\n }\n .score-period {\n font-size: 0.9rem;\n opacity: 0.7;\n margin-bottom: 16px;\n }\n .score-details {\n display: flex;\n justify-content: space-around;\n margin-top: 24px;\n padding-top: 16px;\n border-top: 1px solid rgba(255, 255, 255, 0.2);\n }\n .detail-item {\n text-align: center;\n }\n .detail-value {\n font-size: 1.4rem;\n font-weight: bold;\n margin-bottom: 4px;\n }\n .detail-label {\n font-size: 0.8rem;\n opacity: 0.8;\n }\n .loading {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 200px;\n color: #666;\n font-size: 1.1rem;\n }\n .error {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 200px;\n color: #d32f2f;\n font-size: 1.1rem;\n }\n `\n\n @state() loading = true\n @state() error = ''\n @state() totalScore = 0\n @state() grade = ''\n @state() totalKpis = 0\n @state() totalCategories = 0\n @state() averageScore = 0\n @state() currentMonth = ''\n\n connectedCallback() {\n super.connectedCallback()\n this.currentMonth = this.getCurrentMonth()\n this.fetchTotalScore()\n }\n\n private getCurrentMonth(): string {\n const now = new Date()\n const year = now.getFullYear()\n const month = String(now.getMonth() + 1).padStart(2, '0')\n return `${year}-${month}`\n }\n\n private calculateGrade(score: number): string {\n if (score >= 90) return 'A+'\n if (score >= 85) return 'A'\n if (score >= 80) return 'A-'\n if (score >= 75) return 'B+'\n if (score >= 70) return 'B'\n if (score >= 65) return 'B-'\n if (score >= 60) return 'C+'\n if (score >= 55) return 'C'\n if (score >= 50) return 'C-'\n return 'D'\n }\n\n async fetchTotalScore() {\n this.loading = true\n this.error = ''\n\n try {\n const response = await client.query({\n query: gql`\n query {\n kpiStatistics {\n items {\n id\n valueDate\n periodType\n mean\n median\n kpi {\n id\n name\n targetValue\n unit\n category: parent {\n id\n name\n }\n }\n }\n }\n }\n `\n })\n\n const statistics = response.data.kpiStatistics.items || []\n\n // MONTH 타입의 현재 월 데이터만 필터링\n const currentMonthStats = statistics.filter(\n stat => stat.periodType === 'MONTH' && stat.valueDate === this.currentMonth\n )\n\n if (currentMonthStats.length === 0) {\n this.error = '현재 월의 데이터가 없습니다.'\n return\n }\n\n // 총점 계산 (평균값 기준)\n const scores = currentMonthStats.map(stat => {\n const mean = stat.mean || 0\n const targetValue = stat.kpi?.targetValue || 100\n\n if (targetValue === 0) return 0\n\n // 목표 대비 달성률 계산 (최대 100점)\n const achievement = Math.min((mean / targetValue) * 100, 100)\n return Math.max(achievement, 0) // 음수 방지\n })\n\n this.totalScore = Math.round(scores.reduce((sum, score) => sum + score, 0) / scores.length)\n this.grade = this.calculateGrade(this.totalScore)\n this.totalKpis = currentMonthStats.length\n\n // 카테고리 수 계산\n const categories = new Set(currentMonthStats.map(stat => stat.kpi?.category?.name).filter(Boolean))\n this.totalCategories = categories.size\n\n // 평균 점수 계산\n this.averageScore = Math.round(scores.reduce((sum, score) => sum + score, 0) / scores.length)\n } catch (e) {\n console.error('총점 데이터를 불러오지 못했습니다:', e)\n this.error = '총점 데이터를 불러오지 못했습니다.'\n } finally {\n this.loading = false\n }\n }\n\n render() {\n if (this.loading) {\n return html`\n <div class=\"score-card\">\n <div class=\"loading\">총점 계산 중...</div>\n </div>\n `\n }\n\n if (this.error) {\n return html`\n <div class=\"score-card\">\n <div class=\"error\">${this.error}</div>\n </div>\n `\n }\n\n return html`\n <div class=\"score-card\">\n <div class=\"score-content\">\n <div class=\"score-title\">그룹 총점</div>\n <div class=\"score-value\">${this.totalScore}</div>\n <div class=\"score-grade\">${this.grade}</div>\n <div class=\"score-period\">${this.currentMonth} 기준</div>\n\n <div class=\"score-details\">\n <div class=\"detail-item\">\n <div class=\"detail-value\">${this.totalKpis}</div>\n <div class=\"detail-label\">KPI</div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-value\">${this.totalCategories}</div>\n <div class=\"detail-label\">카테고리</div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-value\">${this.averageScore}</div>\n <div class=\"detail-label\">평균</div>\n </div>\n </div>\n </div>\n </div>\n `\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"kpi-level1-card.js","sourceRoot":"","sources":["../../../../client/pages/kpi-dashboard/cards/kpi-level1-card.ts"],"names":[],"mappings":"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","sourcesContent":["import { html, css } from 'lit'\nimport { customElement, state, property } from 'lit/decorators.js'\nimport { LitElement } from 'lit'\nimport { client } from '@operato/graphql'\nimport gql from 'graphql-tag'\n\n@customElement('kpi-level1-card')\nexport class KpiLevel1Card extends LitElement {\n static styles = css`\n :host {\n display: block;\n }\n .score-card {\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n border-radius: 16px;\n padding: 32px;\n color: white;\n box-shadow: 0 8px 32px rgba(102, 126, 234, 0.3);\n text-align: center;\n position: relative;\n overflow: hidden;\n }\n .score-card::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(255, 255, 255, 0.1);\n border-radius: 16px;\n }\n .score-content {\n position: relative;\n z-index: 1;\n }\n .score-title {\n font-size: 1.2rem;\n font-weight: 600;\n margin-bottom: 16px;\n opacity: 0.9;\n }\n .score-value {\n font-size: 4rem;\n font-weight: bold;\n margin-bottom: 8px;\n text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);\n }\n .score-grade {\n font-size: 1.5rem;\n font-weight: 600;\n margin-bottom: 16px;\n opacity: 0.9;\n }\n .score-period {\n font-size: 0.9rem;\n opacity: 0.7;\n margin-bottom: 16px;\n }\n .score-details {\n display: flex;\n justify-content: space-around;\n margin-top: 24px;\n padding-top: 16px;\n border-top: 1px solid rgba(255, 255, 255, 0.2);\n }\n .detail-item {\n text-align: center;\n }\n .detail-value {\n font-size: 1.4rem;\n font-weight: bold;\n margin-bottom: 4px;\n }\n .detail-label {\n font-size: 0.8rem;\n opacity: 0.8;\n }\n .loading {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 200px;\n color: #666;\n font-size: 1.1rem;\n }\n .error {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 200px;\n color: #d32f2f;\n font-size: 1.1rem;\n }\n `\n\n @property({ type: String }) sectorType: string = ''\n @property({ type: String }) buildingUsage: string = ''\n\n @state() loading = true\n @state() error = ''\n @state() totalScore = 0\n @state() grade = ''\n @state() projectCount = 0\n @state() minScore = 0\n @state() maxScore = 0\n\n connectedCallback() {\n super.connectedCallback()\n this.fetchTotalScore()\n }\n\n override updated(changedProperties: Map<string, unknown>) {\n if (changedProperties.has('sectorType') || changedProperties.has('buildingUsage')) {\n this.fetchTotalScore()\n }\n }\n\n private calculateGrade(score: number): string {\n if (score >= 90) return 'A+'\n if (score >= 85) return 'A'\n if (score >= 80) return 'A-'\n if (score >= 75) return 'B+'\n if (score >= 70) return 'B'\n if (score >= 65) return 'B-'\n if (score >= 60) return 'C+'\n if (score >= 55) return 'C'\n if (score >= 50) return 'C-'\n return 'D'\n }\n\n async fetchTotalScore() {\n this.loading = true\n this.error = ''\n\n try {\n const response = await client.query({\n query: gql`\n query KpiLevel1Stats($sectorType: String, $buildingUsage: String) {\n kpiProjectStats(kpiNamePattern: \"Z\", sectorType: $sectorType, buildingUsage: $buildingUsage) {\n kpiName\n avgVal\n minVal\n maxVal\n projectCount\n }\n }\n `,\n variables: {\n sectorType: this.sectorType || null,\n buildingUsage: this.buildingUsage || null\n }\n })\n\n const stats: any[] = response.data.kpiProjectStats || []\n\n if (stats.length === 0) {\n this.error = '데이터가 없습니다.'\n return\n }\n\n const zStat = stats[0]\n this.totalScore = Math.round(zStat.avgVal * 100)\n this.grade = this.calculateGrade(this.totalScore)\n this.projectCount = zStat.projectCount\n this.minScore = Math.round(zStat.minVal * 100)\n this.maxScore = Math.round(zStat.maxVal * 100)\n } catch (e) {\n console.error('총점 데이터를 불러오지 못했습니다:', e)\n this.error = '총점 데이터를 불러오지 못했습니다.'\n } finally {\n this.loading = false\n }\n }\n\n render() {\n if (this.loading) {\n return html`\n <div class=\"score-card\">\n <div class=\"loading\">총점 계산 중...</div>\n </div>\n `\n }\n\n if (this.error) {\n return html`\n <div class=\"score-card\">\n <div class=\"error\">${this.error}</div>\n </div>\n `\n }\n\n return html`\n <div class=\"score-card\">\n <div class=\"score-content\">\n <div class=\"score-title\">그룹 총점</div>\n <div class=\"score-value\">${this.totalScore}</div>\n <div class=\"score-grade\">${this.grade}</div>\n\n <div class=\"score-details\">\n <div class=\"detail-item\">\n <div class=\"detail-value\">${this.projectCount}</div>\n <div class=\"detail-label\">분석 프로젝트</div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-value\">${this.minScore}</div>\n <div class=\"detail-label\">최저</div>\n </div>\n <div class=\"detail-item\">\n <div class=\"detail-value\">${this.maxScore}</div>\n <div class=\"detail-label\">최고</div>\n </div>\n </div>\n </div>\n </div>\n `\n }\n}\n"]}
|
|
@@ -3,17 +3,18 @@ import '../../components/kpi-radar-chart';
|
|
|
3
3
|
import '../../components/kpi-boxplot-chart';
|
|
4
4
|
export declare class KpiLevel2Comparison extends LitElement {
|
|
5
5
|
static styles: import("lit").CSSResult;
|
|
6
|
+
sectorType: string;
|
|
7
|
+
buildingUsage: string;
|
|
6
8
|
loading: boolean;
|
|
7
9
|
error: string;
|
|
8
10
|
radarData: any[];
|
|
9
11
|
boxplotData: any[];
|
|
10
12
|
categories: string[];
|
|
11
|
-
currentMonth: string;
|
|
12
13
|
totalCategories: number;
|
|
13
14
|
totalKpis: number;
|
|
14
15
|
averageScore: number;
|
|
15
16
|
connectedCallback(): void;
|
|
16
|
-
|
|
17
|
+
updated(changedProperties: Map<string, unknown>): void;
|
|
17
18
|
fetchCategoryComparison(): Promise<void>;
|
|
18
19
|
private generateRadarData;
|
|
19
20
|
private generateBoxplotData;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __decorate, __metadata } from "tslib";
|
|
2
2
|
import { html, css } from 'lit';
|
|
3
|
-
import { customElement, state } from 'lit/decorators.js';
|
|
3
|
+
import { customElement, state, property } from 'lit/decorators.js';
|
|
4
4
|
import { LitElement } from 'lit';
|
|
5
5
|
import { client } from '@operato/graphql';
|
|
6
6
|
import gql from 'graphql-tag';
|
|
@@ -9,26 +9,25 @@ import '../../components/kpi-boxplot-chart';
|
|
|
9
9
|
let KpiLevel2Comparison = class KpiLevel2Comparison extends LitElement {
|
|
10
10
|
constructor() {
|
|
11
11
|
super(...arguments);
|
|
12
|
+
this.sectorType = '';
|
|
13
|
+
this.buildingUsage = '';
|
|
12
14
|
this.loading = true;
|
|
13
15
|
this.error = '';
|
|
14
16
|
this.radarData = [];
|
|
15
17
|
this.boxplotData = [];
|
|
16
18
|
this.categories = [];
|
|
17
|
-
this.currentMonth = '';
|
|
18
19
|
this.totalCategories = 0;
|
|
19
20
|
this.totalKpis = 0;
|
|
20
21
|
this.averageScore = 0;
|
|
21
22
|
}
|
|
22
23
|
connectedCallback() {
|
|
23
24
|
super.connectedCallback();
|
|
24
|
-
this.currentMonth = this.getCurrentMonth();
|
|
25
25
|
this.fetchCategoryComparison();
|
|
26
26
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return `${year}-${month}`;
|
|
27
|
+
updated(changedProperties) {
|
|
28
|
+
if (changedProperties.has('sectorType') || changedProperties.has('buildingUsage')) {
|
|
29
|
+
this.fetchCategoryComparison();
|
|
30
|
+
}
|
|
32
31
|
}
|
|
33
32
|
async fetchCategoryComparison() {
|
|
34
33
|
this.loading = true;
|
|
@@ -36,71 +35,46 @@ let KpiLevel2Comparison = class KpiLevel2Comparison extends LitElement {
|
|
|
36
35
|
try {
|
|
37
36
|
const response = await client.query({
|
|
38
37
|
query: gql `
|
|
39
|
-
query {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
percentile75
|
|
52
|
-
kpi {
|
|
53
|
-
id
|
|
54
|
-
name
|
|
55
|
-
targetValue
|
|
56
|
-
unit
|
|
57
|
-
category: parent {
|
|
58
|
-
id
|
|
59
|
-
name
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
38
|
+
query KpiLevel2Stats($sectorType: String, $buildingUsage: String) {
|
|
39
|
+
kpiProjectStats(kpiNamePattern: "X", sectorType: $sectorType, buildingUsage: $buildingUsage) {
|
|
40
|
+
kpiName
|
|
41
|
+
categoryName
|
|
42
|
+
minVal
|
|
43
|
+
q1Val
|
|
44
|
+
medVal
|
|
45
|
+
q3Val
|
|
46
|
+
maxVal
|
|
47
|
+
avgVal
|
|
48
|
+
stddevVal
|
|
49
|
+
projectCount
|
|
63
50
|
}
|
|
64
51
|
}
|
|
65
|
-
|
|
52
|
+
`,
|
|
53
|
+
variables: {
|
|
54
|
+
sectorType: this.sectorType || null,
|
|
55
|
+
buildingUsage: this.buildingUsage || null
|
|
56
|
+
}
|
|
66
57
|
});
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (currentMonthStats.length === 0) {
|
|
71
|
-
this.error = '현재 월의 데이터가 없습니다.';
|
|
58
|
+
const stats = response.data.kpiProjectStats || [];
|
|
59
|
+
if (stats.length === 0) {
|
|
60
|
+
this.error = '데이터가 없습니다.';
|
|
72
61
|
return;
|
|
73
62
|
}
|
|
74
|
-
//
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if ((
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
categoryStats.set(categoryName, []);
|
|
82
|
-
}
|
|
83
|
-
categoryStats.get(categoryName).push(stat);
|
|
84
|
-
}
|
|
63
|
+
// X-level KPIs를 categoryName(Y-level)으로 그룹화
|
|
64
|
+
const categoryMap = new Map();
|
|
65
|
+
stats.forEach(stat => {
|
|
66
|
+
const catName = stat.categoryName || '기타';
|
|
67
|
+
if (!categoryMap.has(catName))
|
|
68
|
+
categoryMap.set(catName, []);
|
|
69
|
+
categoryMap.get(catName).push(stat);
|
|
85
70
|
});
|
|
86
|
-
this.categories = Array.from(
|
|
71
|
+
this.categories = Array.from(categoryMap.keys());
|
|
87
72
|
this.totalCategories = this.categories.length;
|
|
88
|
-
this.totalKpis =
|
|
89
|
-
|
|
90
|
-
this.
|
|
91
|
-
|
|
92
|
-
this.
|
|
93
|
-
// 평균 점수 계산
|
|
94
|
-
const scores = currentMonthStats.map(stat => {
|
|
95
|
-
var _a;
|
|
96
|
-
const mean = stat.mean || 0;
|
|
97
|
-
const targetValue = ((_a = stat.kpi) === null || _a === void 0 ? void 0 : _a.targetValue) || 100;
|
|
98
|
-
if (targetValue === 0)
|
|
99
|
-
return 0;
|
|
100
|
-
const achievement = Math.min((mean / targetValue) * 100, 100);
|
|
101
|
-
return Math.max(achievement, 0);
|
|
102
|
-
});
|
|
103
|
-
this.averageScore = Math.round(scores.reduce((sum, score) => sum + score, 0) / scores.length);
|
|
73
|
+
this.totalKpis = stats.length;
|
|
74
|
+
this.generateRadarData(categoryMap);
|
|
75
|
+
this.generateBoxplotData(categoryMap);
|
|
76
|
+
const allAvg = stats.map(s => s.avgVal * 100);
|
|
77
|
+
this.averageScore = Math.round(allAvg.reduce((a, b) => a + b, 0) / allAvg.length);
|
|
104
78
|
}
|
|
105
79
|
catch (e) {
|
|
106
80
|
console.error('카테고리 비교 데이터를 불러오지 못했습니다:', e);
|
|
@@ -110,67 +84,46 @@ let KpiLevel2Comparison = class KpiLevel2Comparison extends LitElement {
|
|
|
110
84
|
this.loading = false;
|
|
111
85
|
}
|
|
112
86
|
}
|
|
113
|
-
generateRadarData(
|
|
87
|
+
generateRadarData(categoryMap) {
|
|
114
88
|
const result = [];
|
|
115
89
|
this.categories.forEach(category => {
|
|
116
|
-
const stats =
|
|
117
|
-
const
|
|
118
|
-
const
|
|
119
|
-
const
|
|
120
|
-
if (
|
|
121
|
-
result.push({
|
|
122
|
-
group: '평균',
|
|
123
|
-
category,
|
|
124
|
-
value: means.reduce((a, b) => a + b, 0) / means.length
|
|
125
|
-
});
|
|
90
|
+
const stats = categoryMap.get(category);
|
|
91
|
+
const avgVals = stats.map(s => s.avgVal).filter(v => v > 0);
|
|
92
|
+
const medVals = stats.map(s => s.medVal).filter(v => v > 0);
|
|
93
|
+
const stddevVals = stats.map(s => s.stddevVal).filter(v => v > 0);
|
|
94
|
+
if (avgVals.length > 0) {
|
|
95
|
+
result.push({ group: '평균', category, value: avgVals.reduce((a, b) => a + b, 0) / avgVals.length });
|
|
126
96
|
}
|
|
127
|
-
if (
|
|
128
|
-
result.push({
|
|
129
|
-
group: '중앙값',
|
|
130
|
-
category,
|
|
131
|
-
value: medians.reduce((a, b) => a + b, 0) / medians.length
|
|
132
|
-
});
|
|
97
|
+
if (medVals.length > 0) {
|
|
98
|
+
result.push({ group: '중앙값', category, value: medVals.reduce((a, b) => a + b, 0) / medVals.length });
|
|
133
99
|
}
|
|
134
|
-
if (
|
|
135
|
-
result.push({
|
|
136
|
-
group: '표준편차',
|
|
137
|
-
category,
|
|
138
|
-
value: stdDevs.reduce((a, b) => a + b, 0) / stdDevs.length
|
|
139
|
-
});
|
|
100
|
+
if (stddevVals.length > 0) {
|
|
101
|
+
result.push({ group: '표준편차', category, value: stddevVals.reduce((a, b) => a + b, 0) / stddevVals.length });
|
|
140
102
|
}
|
|
141
103
|
});
|
|
142
104
|
this.radarData = result;
|
|
143
105
|
}
|
|
144
|
-
generateBoxplotData(
|
|
106
|
+
generateBoxplotData(categoryMap) {
|
|
145
107
|
const result = [];
|
|
146
108
|
this.categories.forEach(category => {
|
|
147
|
-
const stats =
|
|
148
|
-
|
|
149
|
-
const
|
|
150
|
-
const
|
|
151
|
-
const
|
|
152
|
-
const
|
|
153
|
-
const
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
min,
|
|
166
|
-
q1,
|
|
167
|
-
median,
|
|
168
|
-
q3,
|
|
169
|
-
max,
|
|
170
|
-
mean,
|
|
171
|
-
value: mean
|
|
172
|
-
});
|
|
173
|
-
}
|
|
109
|
+
const stats = categoryMap.get(category);
|
|
110
|
+
const avgVals = stats.map(s => s.avgVal);
|
|
111
|
+
const medVals = stats.map(s => s.medVal);
|
|
112
|
+
const minVals = stats.map(s => s.minVal);
|
|
113
|
+
const maxVals = stats.map(s => s.maxVal);
|
|
114
|
+
const q1Vals = stats.map(s => s.q1Val);
|
|
115
|
+
const q3Vals = stats.map(s => s.q3Val);
|
|
116
|
+
const avg = (arr) => arr.reduce((a, b) => a + b, 0) / arr.length;
|
|
117
|
+
result.push({
|
|
118
|
+
group: category,
|
|
119
|
+
min: Math.min(...minVals),
|
|
120
|
+
q1: avg(q1Vals),
|
|
121
|
+
median: avg(medVals),
|
|
122
|
+
q3: avg(q3Vals),
|
|
123
|
+
max: Math.max(...maxVals),
|
|
124
|
+
mean: avg(avgVals),
|
|
125
|
+
value: avg(avgVals)
|
|
126
|
+
});
|
|
174
127
|
});
|
|
175
128
|
this.boxplotData = result;
|
|
176
129
|
}
|
|
@@ -219,7 +172,7 @@ let KpiLevel2Comparison = class KpiLevel2Comparison extends LitElement {
|
|
|
219
172
|
}
|
|
220
173
|
return html `
|
|
221
174
|
<div class="comparison-container">
|
|
222
|
-
<div class="comparison-title">카테고리 비교
|
|
175
|
+
<div class="comparison-title">카테고리 비교 분석</div>
|
|
223
176
|
|
|
224
177
|
<div class="charts-section">
|
|
225
178
|
<div class="chart-card">
|
|
@@ -346,6 +299,14 @@ KpiLevel2Comparison.styles = css `
|
|
|
346
299
|
color: #666;
|
|
347
300
|
}
|
|
348
301
|
`;
|
|
302
|
+
__decorate([
|
|
303
|
+
property({ type: String }),
|
|
304
|
+
__metadata("design:type", String)
|
|
305
|
+
], KpiLevel2Comparison.prototype, "sectorType", void 0);
|
|
306
|
+
__decorate([
|
|
307
|
+
property({ type: String }),
|
|
308
|
+
__metadata("design:type", String)
|
|
309
|
+
], KpiLevel2Comparison.prototype, "buildingUsage", void 0);
|
|
349
310
|
__decorate([
|
|
350
311
|
state(),
|
|
351
312
|
__metadata("design:type", Object)
|
|
@@ -366,10 +327,6 @@ __decorate([
|
|
|
366
327
|
state(),
|
|
367
328
|
__metadata("design:type", Array)
|
|
368
329
|
], KpiLevel2Comparison.prototype, "categories", void 0);
|
|
369
|
-
__decorate([
|
|
370
|
-
state(),
|
|
371
|
-
__metadata("design:type", Object)
|
|
372
|
-
], KpiLevel2Comparison.prototype, "currentMonth", void 0);
|
|
373
330
|
__decorate([
|
|
374
331
|
state(),
|
|
375
332
|
__metadata("design:type", Object)
|