@dssp/dkpi 1.0.0-alpha.81 → 1.0.0-alpha.84
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/components/kpi-lookup-chart.js +45 -12
- package/dist-client/components/kpi-lookup-chart.js.map +1 -1
- package/dist-client/entries/auth/checkin.js +7 -2
- package/dist-client/entries/auth/checkin.js.map +1 -1
- package/dist-client/pages/kpi-admin/kpi-system-guide.d.ts +1 -1
- package/dist-client/pages/kpi-admin/kpi-system-guide.js +29 -21
- package/dist-client/pages/kpi-admin/kpi-system-guide.js.map +1 -1
- package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js +1 -1
- package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js.map +1 -1
- package/dist-client/pages/project-complete-tabs/pc-tab1-plan.d.ts +5 -0
- package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js +38 -20
- package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js.map +1 -1
- package/dist-client/pages/sv-project-completed-list.js +3 -3
- package/dist-client/pages/sv-project-completed-list.js.map +1 -1
- package/dist-client/pages/sv-project-detail.js +22 -16
- package/dist-client/pages/sv-project-detail.js.map +1 -1
- package/dist-client/pages/sv-project-list.d.ts +1 -0
- package/dist-client/pages/sv-project-list.js +3 -3
- package/dist-client/pages/sv-project-list.js.map +1 -1
- package/dist-client/pages/sv-project-update.d.ts +5 -0
- package/dist-client/pages/sv-project-update.js +81 -261
- package/dist-client/pages/sv-project-update.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/shared/complete-api.js +4 -1
- package/dist-client/shared/complete-api.js.map +1 -1
- package/dist-client/shared/geo-group-mapping.d.ts +25 -0
- package/dist-client/shared/geo-group-mapping.js +189 -0
- package/dist-client/shared/geo-group-mapping.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/viewparts/menu-tools.js +39 -37
- package/dist-client/viewparts/menu-tools.js.map +1 -1
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +22 -11
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -1
- package/dist-server/service/kpi-metric-value/kpi-metric-value-query.d.ts +5 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js +7 -10
- package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js.map +1 -1
- package/dist-server/service/kpi-value/kpi-value-query.js +16 -3
- package/dist-server/service/kpi-value/kpi-value-query.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sv-project-detail.js","sourceRoot":"","sources":["../../client/pages/sv-project-detail.ts"],"names":[],"mappings":"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","sourcesContent":["import { navigate, PageLifecycle, PageView } from '@operato/shell'\nimport { ScrollbarStyles } from '@operato/styles'\nimport { css, html } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\nimport { Project, PROJECT_STATE, ProjectState } from './sv-project-list'\nimport { SITE_TYPE_DISPLAY } from '@dssp/project/dist-client/pages/project/project-list'\nimport { client } from '@operato/graphql'\nimport { getDomain } from '@things-factory/auth-base/dist-client/profiled'\nimport gql from 'graphql-tag'\nimport moment from 'moment-timezone'\nimport { isProjectTypeDomain, tenantHeaders } from '@dssp/project/dist-client/shared/domain-context'\nimport '../components/kpi-boxplot-chart'\nimport '../components/kpi-single-boxplot-chart'\nimport '../components/kpi-radar-chart'\nimport '../components/kpi-lookup-chart'\nimport '../components/kpi-2d-lookup-chart'\n\n@customElement('sv-project-detail')\nexport class SvProjectDetailPage extends ScopedElementsMixin(PageView) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n\n width: 100%;\n height: 100%;\n background-color: var(--md-sys-color-background, #f6f6f6);\n }\n\n /* content layout */\n div[content] {\n display: flex;\n gap: 35px;\n padding: 25px;\n }\n div[left] {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 20px;\n }\n div[right] {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 0 1px;\n }\n\n /* card */\n .card {\n background: #ffffff;\n border-radius: 10px;\n padding: 15px;\n box-shadow: 3px 3px 3px 0 rgba(0, 0, 0, 0.1);\n }\n .card-title {\n display: flex;\n align-items: center;\n gap: 5px;\n color: #35618e;\n font-weight: 700;\n }\n .triangle {\n width: 0;\n height: 0;\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-top: 8px solid #35618e;\n }\n\n /* left top info box */\n .bold {\n font-weight: bold;\n }\n .top-info {\n display: flex;\n gap: 10px;\n }\n .top-info img[pic] {\n width: 284px;\n height: 160px;\n object-fit: fill;\n background: #e5e7eb;\n }\n .top-info .info {\n display: flex;\n flex-direction: column;\n gap: 15px;\n padding: 10px 0;\n flex: 1;\n }\n .row {\n display: flex;\n align-items: center;\n gap: 10px;\n }\n .label {\n min-width: fit-content;\n color: #35618e;\n font-size: 16px;\n letter-spacing: -0.05em;\n }\n .value {\n color: #333;\n font-size: 16px;\n }\n .status-value {\n color: #4cbb49;\n font-weight: 700;\n }\n\n .address {\n color: #35618e;\n font-size: 16px;\n letter-spacing: -0.05em;\n }\n\n .detail-grid {\n display: grid;\n grid-template-columns: 284px 1fr;\n gap: 15px 10px;\n padding: 5px 0;\n }\n .detail-grid .grid-item .label {\n width: auto;\n }\n\n /* left second card (requests) */\n .sub-desc {\n color: #35618e;\n font-size: 14px;\n letter-spacing: -0.05em;\n margin-bottom: 8px;\n }\n .list-block {\n display: flex;\n flex-direction: column;\n gap: 5px;\n padding: 5px 25px;\n }\n .list-title {\n color: #212529;\n font-weight: 700;\n font-size: 16px;\n letter-spacing: -0.05em;\n }\n .list-text {\n color: #35618e;\n font-size: 16px;\n letter-spacing: -0.05em;\n margin-left: 8px;\n }\n .list-text .warn {\n margin-left: 10px;\n color: #e13232;\n\n md-icon {\n font-size: 17px;\n width: 13px;\n height: 13px;\n }\n }\n\n /* right buttons */\n .button-line {\n display: flex;\n justify-content: flex-end;\n gap: 10px;\n }\n .ghost-btn {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 5px 10px;\n background: #35618e;\n color: #ffffff;\n border-radius: 5px;\n box-shadow: 2px 2px 2px 0 rgba(0, 0, 0, 0.1);\n cursor: pointer;\n\n /* Material Symbols Outlined (stroke style) */\n md-icon {\n font-variation-settings:\n 'FILL' 0,\n 'wght' 300,\n 'GRAD' 0,\n 'opsz' 24;\n }\n }\n\n /* right KPI box */\n .kpi-box {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 15px;\n max-height: 420px;\n min-width: 560px;\n }\n .kpi-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n color: #35618e;\n font-weight: 700;\n font-size: 20px;\n letter-spacing: -0.05em;\n }\n .kpi-header div {\n display: flex;\n align-items: center;\n gap: 5px;\n }\n .kpi-desc {\n color: #35618e;\n font-size: 13px;\n letter-spacing: -0.05em;\n }\n .kpi-summary {\n display: flex;\n align-items: center;\n padding: 0 30px;\n max-height: 360px;\n gap: 20px;\n }\n .mini-boxplot {\n flex: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n position: relative;\n min-width: 120px;\n }\n .boxplot-area {\n flex: 1;\n width: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n background: #ffffff;\n }\n\n .boxplot-point {\n display: flex;\n flex-direction: column;\n align-items: center;\n color: #35618e;\n }\n .boxplot-point .value {\n font-size: 42px;\n font-weight: 800;\n color: #35618e;\n border-radius: 6px;\n }\n .boxplot-point .label {\n font-size: 14px;\n font-weight: 300;\n width: auto;\n }\n\n /* spider chart placeholder */\n .spider-area {\n flex: 5;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 10px;\n height: 100%;\n }\n\n /* group distribution */\n .group-box .desc {\n color: #35618e;\n font-size: 13px;\n letter-spacing: -0.05em;\n margin-top: 4px;\n }\n .group-chart {\n height: 300px;\n margin-top: 25px;\n }\n\n kpi-single-boxplot-chart {\n flex: 1;\n }\n\n /* KPI 메트릭 데이터 카드 */\n .metrics-card {\n background: #ffffff;\n border-radius: 10px;\n padding: 20px;\n box-shadow: 3px 3px 3px 0 rgba(0, 0, 0, 0.1);\n max-width: 100%;\n overflow: hidden;\n }\n .metrics-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n .metrics-header .title {\n display: flex;\n align-items: center;\n gap: 8px;\n color: #35618e;\n font-weight: 700;\n font-size: 18px;\n }\n .metrics-card .desc {\n color: #35618e;\n font-size: 13px;\n letter-spacing: -0.05em;\n margin-top: 4px;\n margin-bottom: 15px;\n }\n .metrics-content {\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n .metric-group {\n border-bottom: 1px dotted #ddd;\n padding-bottom: 12px;\n }\n .metric-group:last-child {\n border-bottom: none;\n padding-bottom: 0;\n }\n .metric-group-header {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 8px;\n color: #35618e;\n font-weight: 600;\n font-size: 16px;\n }\n .metric-group-icon {\n width: 20px;\n height: 20px;\n background: #35618e;\n border-radius: 3px;\n position: relative;\n }\n .metric-group-icon::before {\n content: '✓';\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n color: white;\n font-size: 12px;\n font-weight: bold;\n }\n .metric-items {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n gap: 8px 16px;\n padding-left: 28px;\n }\n .metric-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n font-size: 14px;\n }\n .metric-label {\n color: #333;\n flex: 1;\n }\n .metric-value {\n color: #35618e;\n font-weight: 600;\n min-width: 40px;\n text-align: right;\n }\n\n /* Popup overlay */\n .popup-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n }\n .popup-content {\n background: white;\n border-radius: 12px;\n padding: 24px;\n max-width: 800px;\n width: 90%;\n max-height: 80vh;\n overflow-y: auto;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);\n }\n .popup-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 2px solid #e0e0e0;\n }\n .popup-title {\n font-size: 20px;\n font-weight: 700;\n color: #35618e;\n }\n .popup-close {\n cursor: pointer;\n font-size: 24px;\n color: #999;\n background: none;\n border: none;\n padding: 4px 8px;\n }\n .popup-close:hover {\n color: #333;\n }\n .popup-chart-container {\n min-height: 400px;\n height: 500px;\n }\n .metric-label {\n cursor: pointer;\n }\n .metric-label:hover {\n opacity: 0.7;\n text-decoration: underline;\n }\n `\n ]\n\n get context() {\n return {\n title:\n !isProjectTypeDomain() && this.project\n ? `프로젝트 상세 정보 - ${this.project?.name}`\n : '프로젝트 상세 정보'\n }\n }\n\n @state() private project: Project = {} as Project\n @state() private kpiComprehensiveStats: any[] = []\n @state() private kpiYComprehensiveStats: any[] = []\n @state() private projectXKpiValues: any[] = []\n @state() private showScoreDistribution: boolean = false\n @state() private selectedKpi: any = null\n /** 이 프로젝트에 아직 한 번도 입력되지 않은 metric (active 한 manual/import 한정) */\n @state() private pendingMetrics: { id: string; name: string; description?: string }[] = []\n\n render() {\n return html`\n <div content>\n <div left>\n <div class=\"card\">\n <div class=\"card-title\">\n <div>${this.project.name}</div>\n <div class=\"triangle\"></div>\n </div>\n\n <div class=\"top-info\" style=\"margin-top: 10px;\">\n <img pic src=${this.project.mainPhoto?.fullpath || '/assets/images/project-image.png'} alt=\"project\" />\n <div class=\"info\">\n <div class=\"row\">\n <div class=\"label\">• 주소</div>\n <div class=\"value\">${this.project.buildingComplex?.address}</div>\n </div>\n <div class=\"row\">\n <div class=\"label\">• 공사기간</div>\n <div class=\"value\">${this.project.startDate} ~ ${this.project.endDate}</div>\n </div>\n <div class=\"row\">\n <div class=\"label\">• 현장상태</div>\n <div class=\"value status-value\">${PROJECT_STATE[this.project.state]}</div>\n </div>\n <div class=\"row\">\n <div class=\"label\">• 건폐율</div>\n <div class=\"value\">\n ${(this.project.buildingComplex as any)?.coverageRatio?.toLocaleString() || '-'} %\n </div>\n </div>\n <div class=\"row\">\n <div class=\"label\">• 현장유형</div>\n <div class=\"value\">\n ${(this.project.buildingComplex as any)?.siteType\n ? (SITE_TYPE_DISPLAY as any)[(this.project.buildingComplex as any).siteType] ||\n (this.project.buildingComplex as any).siteType\n : '-'}\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"detail-grid\">\n <div class=\"grid-item row\">\n <div class=\"label\">• 공사비</div>\n <div class=\"value\">${this.project.buildingComplex?.constructionCost?.toLocaleString() || '-'} 억원</div>\n </div>\n <div class=\"grid-item row\">\n <div class=\"label\">• 연면적</div>\n <div class=\"value\">${this.project.buildingComplex?.area?.toLocaleString() || '-'} ㎡</div>\n </div>\n <div class=\"grid-item row\">\n <div class=\"label\">• 용적률</div>\n <div class=\"value\">\n ${(this.project.buildingComplex as any)?.floorAreaRatio?.toLocaleString() || '-'} %\n </div>\n </div>\n <div class=\"grid-item row\">\n <div class=\"label\">• 투입인력</div>\n <div class=\"value\">\n ${(this.project.buildingComplex as any)?.workerCount?.toLocaleString() || '-'} 명\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"card\">\n <div class=\"card-title\">\n <div>입력 대기 중</div>\n <div class=\"triangle\"></div>\n </div>\n <div class=\"sub-desc\">\n 이 프로젝트에 아직 입력되지 않은 KPI 항목입니다. 해당 항목에 대한 데이터를 입력 해 주시기 바랍니다.\n </div>\n\n <div class=\"list-block\">\n <div class=\"list-title\">• 미입력 ${this.pendingMetrics.length}건</div>\n ${this.pendingMetrics.length === 0\n ? html`<div class=\"list-text\">모든 항목이 입력되었습니다.</div>`\n : this.pendingMetrics.map(\n m => html`\n <div\n class=\"list-text\"\n style=\"cursor: pointer;\"\n @click=${async () => {\n if (isProjectTypeDomain()) {\n navigate('project-complete')\n return\n }\n const id = this.project.id || (await this._resolveProjectIdFromDomain())\n if (id) navigate(`project-complete/${id}`)\n }}\n >\n # ${m.name}${m.description ? ` : ${m.description}` : ''}\n </div>\n `\n )}\n </div>\n </div>\n </div>\n\n <div right>\n ${html`\n <div class=\"button-line\">\n <div\n class=\"ghost-btn\"\n @click=${async () => {\n // project-type domain 에서는 대상 페이지가 subdomain 으로 자동 해석하므로 id 불필요\n if (isProjectTypeDomain()) {\n navigate('project-update')\n return\n }\n const id = this.project.id || (await this._resolveProjectIdFromDomain())\n if (id) navigate(`project-update/${id}`)\n }}\n >\n <md-icon slot=\"\">assignment</md-icon>\n <div>프로젝트 수정</div>\n </div>\n <div\n class=\"ghost-btn\"\n @click=${async () => {\n if (isProjectTypeDomain()) {\n navigate('project-complete')\n return\n }\n const id = this.project.id || (await this._resolveProjectIdFromDomain())\n if (id) navigate(`project-complete/${id}`)\n }}\n >\n <md-icon slot=\"\">assignment_turned_in</md-icon>\n <div>KPI 데이타입력</div>\n </div>\n </div>\n `}\n\n <div class=\"card kpi-box\">\n <div class=\"kpi-header\">\n <div>\n <div>종합 KPI</div>\n <div class=\"triangle\"></div>\n </div>\n <div class=\"kpi-desc\">프로젝트의 6개 성과를 종합한 종합 KPI포인트와 각 지표별 분포</div>\n </div>\n\n <div class=\"kpi-summary\">\n <div class=\"mini-boxplot\" title=\"boxplot placeholder\">\n <div class=\"boxplot-area\">\n <kpi-single-boxplot-chart .data=${this.getBoxPlotDataForProject(this.project)}></kpi-single-boxplot-chart>\n </div>\n\n <div class=\"boxplot-point\">\n <div class=\"value\">${this.project.kpi ? this.project.kpi.toFixed(1) : '-'}</div>\n <div class=\"label\">Point</div>\n </div>\n </div>\n\n <div class=\"spider-area\">\n <sv-kpi-radar-chart\n .data=${this.getRadarChartData().data}\n .categories=${this.getRadarChartData().categories}\n .currentGroup=${'프로젝트성과'}\n ></sv-kpi-radar-chart>\n </div>\n </div>\n </div>\n\n <div class=\"card group-box\">\n <div class=\"kpi-header\">\n <div>\n <div>그룹별 분포</div>\n <div class=\"triangle\"></div>\n </div>\n </div>\n <div class=\"desc\">\n Boxplot(박스플롯)은 각 카테고리별로 값의 분포(최소, 1사분위, 중앙값, 3사분위, 최대, 평균, 이상치 등)를 보여줍니다.\n 박스는 중앙 50% 구간, 수염은 전체 범위, 굵은 검정색 가로선은 중앙값(메디안), 초록색 원은 평균값(Mean)을 의미합니다.\n 이 프로젝트의 값은 진한 오렌지색 원으로 별도 강조되어 표시되며, 중앙값/평균과 다를 수 있습니다.\n </div>\n <div class=\"group-chart\">\n <sv-kpi-boxplot-chart .data=${this.getYKpiBoxplotData()}></sv-kpi-boxplot-chart>\n </div>\n </div>\n\n <div class=\"metrics-card\">\n <div class=\"metrics-header\">\n <div class=\"title\">\n <span>그룹별 상세 매트릭 데이터</span>\n <div class=\"triangle\"></div>\n </div>\n </div>\n <div class=\"desc\">\n 프로젝트의 6개 성과별 상세 주요 매트릭 데이터 (각 세부 항목을 클릭하시면 평가 기준표를 확인할 수 있습니다)\n </div>\n <div class=\"metrics-content\">\n ${Object.values(this.getMetricGroups()).map(\n group => html`\n <div class=\"metric-group\">\n <div class=\"metric-group-header\">\n <div class=\"metric-group-icon\"></div>\n <span>${group.name}</span>\n <span style=\"margin-left: 10px; color: #4caf50; font-weight: 700;\">[${group.score}]</span>\n </div>\n <div class=\"metric-items\">\n ${group.metrics.map(\n metric => html`\n <div class=\"metric-item\">\n <span\n class=\"metric-label\"\n @click=${() => this._onMetricLabelClick(metric)}\n title=\"클릭하시면 평가 기준표를 확인할 수 있습니다\"\n >\n ${metric.label}\n </span>\n <span class=\"metric-value\">${metric.value}</span>\n </div>\n `\n )}\n </div>\n </div>\n `\n )}\n </div>\n </div>\n </div>\n </div>\n\n ${this.showScoreDistribution && this.selectedKpi\n ? html`\n <div class=\"popup-overlay\" @click=${this._closePopup}>\n <div class=\"popup-content\" @click=${(e: Event) => e.stopPropagation()}>\n <div class=\"popup-header\">\n <div class=\"popup-title\">${this.selectedKpi.kpiName} — 성과 분포</div>\n <button class=\"popup-close\" @click=${this._closePopup}>×</button>\n </div>\n <div class=\"popup-chart-container\">\n ${/*\n * scoreType 기반 차트 분기:\n *\n * CUSTOM (X13 등): 2D 룩업 히트맵 — 단, 증강데이터에서는 value가\n * 이미 1~5 정수(룩업 결과)이므로 히트맵 대신 게이지로 폴백.\n * 실제 프로젝트에서는 value가 편차율(소수점)이므로 히트맵 표시.\n *\n * LOOKUP: 성과 분포 커브 (kpi-lookup-chart)\n * ASSESSMENT: 5단계 게이지 (kpi-lookup-chart 자동 감지)\n */ ''}\n ${(this.selectedKpi.scoreType === 'CUSTOM' ||\n this.selectedKpi.grades?.type === 'PROGRESS_DEVIATION_LOOKUP') &&\n this.selectedKpi.value !== null &&\n !(\n this.selectedKpi.value === Math.floor(this.selectedKpi.value) &&\n this.selectedKpi.value >= 1 &&\n this.selectedKpi.value <= 5\n )\n ? html`\n <kpi-2d-lookup-chart\n .grades=${this.selectedKpi.grades}\n .value=${this.selectedKpi.value}\n .progressRate=${this.project?.totalProgress ?? 50}\n unit=\"%\"\n kpiName=${this.selectedKpi.kpiName || ''}\n ></kpi-2d-lookup-chart>\n `\n : this._isAssessmentOrIntegerScore()\n ? this._renderAssessmentGrades()\n : html`\n <kpi-lookup-chart\n .grades=${this.selectedKpi.grades || []}\n .value=${this.selectedKpi.value}\n .scoreType=${this.selectedKpi.scoreType || ''}\n .valueType=${this.selectedKpi.valueType || ''}\n unit=${this.selectedKpi.unit || ''}\n ></kpi-lookup-chart>\n `}\n </div>\n </div>\n </div>\n `\n : ''}\n `\n }\n\n async pageUpdated(changes: any, lifecycle: PageLifecycle) {\n if (!this.active) return\n\n let projectId = lifecycle.resourceId\n\n // 프로젝트 테넌트 컨텍스트(/project/<code>/) 에서 진입한 경우 resourceId 가 비어있다.\n // 현재 도메인의 subdomain(= Project.code) 으로 프로젝트를 역조회.\n if (!projectId) {\n projectId = await this._resolveProjectIdFromDomain()\n }\n\n if (!projectId) return\n\n // initProject 의 GraphQL 응답을 기다리지 않고 project.id 를 즉시 채워서,\n // 링크의 `project-update/${project.id}` 가 절대 undefined 가 되지 않도록 보장.\n this.project = { ...this.project, id: projectId } as Project\n\n // 후속 query 들이 tenant 컨텍스트로 동작하도록 project.code 를 먼저 가볍게 resolve.\n // (tenant 컨텍스트에서 진입한 경우는 헤더 불필요 — tenantHeaders 가 빈 객체 반환.)\n if (!isProjectTypeDomain()) {\n await this._resolveProjectCode(projectId)\n }\n\n this.initProject(projectId)\n this.getKpiComprehensiveStats()\n this.getKpiYComprehensiveStats()\n this.getProjectXKpiValues(projectId)\n }\n\n private async _resolveProjectCode(projectId: string): Promise<void> {\n try {\n const resp = await client.query({\n query: gql`\n query ProjectCode($id: String!) {\n project(id: $id) {\n id\n code\n }\n }\n `,\n variables: { id: projectId }\n })\n const code = resp.data?.project?.code\n if (code) {\n this.project = { ...this.project, code } as Project\n }\n } catch (e) {\n console.warn('[project-detail] project.code resolve 실패', e)\n }\n }\n\n private async _resolveProjectIdFromDomain(): Promise<string> {\n const response = await client.query({\n query: gql`\n query CurrentProject {\n currentProject {\n id\n }\n }\n `\n })\n\n return response.data?.currentProject?.id || ''\n }\n\n async initProject(projectId: string = '') {\n const response = await client.query({\n query: gql`\n query Project($id: String!) {\n project(id: $id) {\n id\n code\n name\n state\n startDate\n endDate\n projectType\n mainPhoto {\n fullpath\n }\n totalProgress\n weeklyProgress\n kpi\n kpiValues {\n kpiName\n value\n }\n inspPassRate\n robotProgressRate\n structuralSafetyRate\n robotCount\n buildingComplex {\n id\n address\n latitude\n longitude\n area\n coverageRatio\n floorAreaRatio\n siteType\n workerCount\n clientCompany\n constructionCompany\n supervisoryCompany\n designCompany\n drawing {\n id\n name\n fullpath\n }\n constructionType\n constructionCost\n etc\n notice\n householdCount\n buildingCount\n virtualTourLink\n buildings {\n id\n name\n floorCount\n }\n }\n }\n }\n `,\n variables: { id: projectId },\n context: { headers: tenantHeaders((this.project as any)?.code) }\n })\n\n if (response.errors) return\n\n this.project = response.data?.project || ({} as Project)\n\n this.updateContext()\n this._loadPendingMetrics()\n }\n\n /**\n * 이 프로젝트의 미입력 KPI metric 들을 조회 — Step 1/2 와 동일 기준.\n * - 대상: active=true 인 manual/import metric (자동수집/외부API 제외)\n * - 판정:\n * · MONTH metric → 전월 row (periodType='MONTH', valueDate startsWith 전월) 없으면 pending\n * · 그 외 → (metric, periodType) 매칭 row 없으면 pending\n */\n private async _loadPendingMetrics() {\n if (!this.project?.id) {\n this.pendingMetrics = []\n return\n }\n\n try {\n // 1) Active manual/import metric 정의 목록 (periodType 포함)\n const metricsResp = await client.query({\n query: gql`\n query KpiMetrics {\n kpiMetrics {\n items {\n id\n name\n description\n periodType\n collectType\n active\n }\n }\n }\n `,\n context: { headers: tenantHeaders((this.project as any)?.code) }\n })\n // collectType 필터 제거 — Step 1/2 가 모든 metric 을 보여주므로 동일하게 전체 대상.\n // active=false 인 metric 만 제외.\n const targets = (metricsResp.data?.kpiMetrics?.items || []).filter((m: any) => m.active)\n if (targets.length === 0) {\n this.pendingMetrics = []\n return\n }\n\n // 2) 이 프로젝트의 모든 KpiMetricValue (value 도 가져와서 null/undefined 체크)\n const valuesResp = await client.query({\n query: gql`\n query KpiMetricValues($filters: [Filter!]) {\n kpiMetricValues(filters: $filters) {\n items {\n metricId\n periodType\n valueDate\n value\n }\n }\n }\n `,\n variables: { filters: [{ name: 'org', operator: 'eq', value: this.project.id }] },\n context: { headers: tenantHeaders((this.project as any)?.code) }\n })\n const values: any[] = valuesResp.data?.kpiMetricValues?.items || []\n const lastMonthYm = moment().tz('Asia/Seoul').subtract(1, 'month').format('YYYY-MM')\n\n // 3) Step 1/2 와 동일 기준으로 미입력 판정 — row 존재 AND value 존재 (null/undefined 아님).\n const hasValid = (v: any) => v.value !== null && v.value !== undefined\n this.pendingMetrics = targets.filter((m: any) => {\n if (m.periodType === 'MONTH') {\n return !values.some(\n v =>\n v.metricId === m.id &&\n v.periodType === 'MONTH' &&\n (v.valueDate || '').startsWith(lastMonthYm) &&\n hasValid(v)\n )\n }\n return !values.some(v => v.metricId === m.id && v.periodType === m.periodType && hasValid(v))\n })\n } catch (e) {\n console.error('[입력 대기 중] 조회 실패', e)\n this.pendingMetrics = []\n }\n }\n\n async getKpiComprehensiveStats() {\n try {\n const response = await client.query({\n query: gql`\n query GetKpiZValueComprehensiveStats {\n totalKpiZValueComprehensiveStats {\n minVal\n q1Val\n medVal\n q3Val\n maxVal\n }\n }\n `,\n context: { headers: tenantHeaders((this.project as any)?.code) }\n })\n\n this.kpiComprehensiveStats = response.data.totalKpiZValueComprehensiveStats || []\n } catch (error) {\n console.error('Failed to fetch KPI comprehensive stats:', error)\n this.kpiComprehensiveStats = []\n }\n }\n\n async getKpiYComprehensiveStats() {\n try {\n const response = await client.query({\n query: gql`\n query GetKpiYValueComprehensiveStats {\n totalKpiYValueComprehensiveStats {\n kpiName\n minVal\n q1Val\n medVal\n q3Val\n maxVal\n avgVal\n projectCount\n }\n }\n `,\n context: { headers: tenantHeaders((this.project as any)?.code) }\n })\n\n this.kpiYComprehensiveStats = response.data.totalKpiYValueComprehensiveStats || []\n } catch (error) {\n console.error('Failed to fetch KPI Y comprehensive stats:', error)\n this.kpiYComprehensiveStats = []\n }\n }\n\n async getProjectXKpiValues(projectId: string) {\n try {\n const response = await client.query({\n query: gql`\n query GetProjectXKpiValues($projectId: String!) {\n projectXKpiValues(projectId: $projectId) {\n id\n value\n valueDate\n kpi {\n id\n name\n description\n }\n }\n }\n `,\n variables: { projectId },\n context: { headers: tenantHeaders((this.project as any)?.code) }\n })\n\n this.projectXKpiValues = response.data.projectXKpiValues || []\n } catch (error) {\n console.error('Failed to fetch project X KPI values:', error)\n this.projectXKpiValues = []\n }\n }\n\n private _onMetricLabelClick(metric: any) {\n // metric.pattern을 사용하여 X-KPI 조회\n if (!metric.pattern) {\n console.warn('No pattern found for metric:', metric)\n return\n }\n\n // X-KPI 이름 패턴 (예: X11, X12, X21, ...)\n const kpiNamePattern = metric.pattern\n\n // 해당 KPI 정보 조회\n this._fetchKpiWithGradesByPattern(kpiNamePattern, metric.label)\n }\n\n private async _fetchKpiWithGradesByPattern(kpiNamePattern: string, displayName: string) {\n try {\n // X-KPI 이름 패턴으로 전체 이름 찾기 (projectXKpiValues에서)\n const kpiValue = this.projectXKpiValues.find(kv => kv.kpi?.name && kv.kpi.name.includes(kpiNamePattern))\n\n if (!kpiValue || !kpiValue.kpi) {\n console.warn(`No KPI found for pattern: ${kpiNamePattern}`)\n return\n }\n\n // GraphQL로 KPI 상세 정보 (grades 포함) 조회\n const response = await client.query({\n query: gql`\n query Kpi($id: String!) {\n kpi(id: $id) {\n id\n name\n grades\n scoreType\n valueType\n vizMeta\n }\n }\n `,\n variables: { id: kpiValue.kpi.id },\n context: { headers: tenantHeaders((this.project as any)?.code) }\n })\n\n if (response.errors || !response.data?.kpi) {\n console.error('KPI not found or error:', response.errors)\n return\n }\n\n const kpi = response.data.kpi\n\n // grades가 없으면 경고\n const is2D = kpi.grades && !Array.isArray(kpi.grades) && kpi.grades.type === 'PROGRESS_DEVIATION_LOOKUP'\n if (!kpi.grades || (!is2D && (!Array.isArray(kpi.grades) || kpi.grades.length === 0))) {\n console.warn(`No grades found for KPI: ${kpiValue.kpi.name}`)\n }\n\n this.selectedKpi = {\n kpiName: displayName,\n grades: kpi.grades || [],\n scoreType: kpi.scoreType || '',\n valueType: kpi.valueType || '',\n value: kpiValue.value ?? null,\n unit: kpi.vizMeta?.unit || ''\n }\n\n this.showScoreDistribution = true\n } catch (error) {\n console.error('Error fetching KPI:', error)\n }\n }\n\n /**\n * 등급 기준으로 표시할지 판별 (차트 대신 등급 설명 목록)\n *\n * - valueType=ASSESSED: 감리자 직접 평가 → 등급 설명\n * - CUSTOM/COMPOSITE이지만 value가 1~5 정수 (증강데이터): 등급 설명 + 히트맵\n * - grades가 배열이 아닌 경우 (2D lookup 객체): 등급 설명 + 히트맵\n */\n private _isAssessmentOrIntegerScore(): boolean {\n const kpi = this.selectedKpi\n if (!kpi) return false\n // valueType 기반 판별 (우선)\n if (kpi.valueType === 'ASSESSED') return true\n // CUSTOM/COMPOSITE이지만 value가 1~5 정수 (증강데이터)\n if (\n (kpi.scoreType === 'CUSTOM' || kpi.valueType === 'COMPOSITE') &&\n kpi.value !== null &&\n kpi.value === Math.floor(kpi.value) &&\n kpi.value >= 1 &&\n kpi.value <= 5\n )\n return true\n // grades가 배열이 아닌 경우 (2D lookup 객체)\n if (kpi.grades && !Array.isArray(kpi.grades)) return true\n return false\n }\n\n /** 등급 기준 표시 (ASSESSED / 1~5 정수 score) — 현재 값 강조 + CUSTOM은 2D 히트맵도 표시 */\n private _renderAssessmentGrades() {\n const kpi = this.selectedKpi\n const currentScore = kpi?.value != null ? Math.round(kpi.value) : 0\n const grades = Array.isArray(kpi?.grades) ? kpi.grades : []\n const colors = ['#e53935', '#ff9800', '#ffca28', '#66bb6a', '#2e7d32']\n const is2D = kpi?.scoreType === 'CUSTOM' || kpi?.valueType === 'COMPOSITE' ||\n (kpi?.grades && typeof kpi.grades === 'object' && !Array.isArray(kpi.grades) && kpi.grades.type === 'PROGRESS_DEVIATION_LOOKUP')\n\n // grades가 있으면 description 사용, 없으면 기본 라벨\n const defaultLabels = ['매우 미흡', '미흡', '보통', '양호', '우수']\n const items = [1, 2, 3, 4, 5].map(score => {\n const grade = grades.find((g: any) => g.score === score)\n return {\n score,\n desc: grade?.description || grade?.name || defaultLabels[score - 1],\n color: colors[score - 1],\n active: score === currentScore\n }\n })\n\n // ASSESSED(감리자 평가)이고 grades에 description이 있는 경우만 한 줄씩 상세 표시\n // X13 등 COMPOSITE/CUSTOM은 인라인 칩으로 간결하게\n const hasDescriptions = !is2D && grades.length > 0 && grades.some((g: any) => g.description)\n\n return html`\n <div style=\"padding: 20px;\">\n <div style=\"font-size: 1rem; font-weight: 700; margin-bottom: 16px; color: #333;\">\n 등급 기준 ${currentScore >= 1 ? html`<span style=\"color: ${colors[currentScore - 1]}; margin-left: 8px;\">현재: ${currentScore}점</span>` : ''}\n </div>\n ${hasDescriptions\n ? items.map(\n item => html`\n <div\n style=\"\n display: flex; align-items: center; gap: 10px;\n padding: 10px 14px; margin-bottom: 6px;\n border-radius: 8px;\n background: ${item.active ? item.color + '18' : '#f9f9f9'};\n border: 2px solid ${item.active ? item.color : 'transparent'};\n transition: all 0.2s;\n \"\n >\n <span\n style=\"\n width: 32px; height: 32px; border-radius: 50%;\n background: ${item.active ? item.color : '#e0e0e0'};\n color: ${item.active ? '#fff' : '#999'};\n display: flex; align-items: center; justify-content: center;\n font-weight: 700; font-size: 14px; flex-shrink: 0;\n \"\n >${item.score}</span>\n <span style=\"font-size: 0.9rem; color: ${item.active ? '#333' : '#666'}; font-weight: ${item.active ? '600' : '400'};\">\n ${item.desc}\n </span>\n </div>`\n )\n : html`\n <div style=\"display: flex; gap: 6px; flex-wrap: wrap;\">\n ${items.map(\n item => html`\n <span style=\"\n display: inline-flex; align-items: center; justify-content: center;\n width: 36px; height: 36px; border-radius: 50%;\n background: ${item.active ? item.color : '#e0e0e0'};\n color: ${item.active ? '#fff' : '#999'};\n font-weight: 700; font-size: 14px;\n border: 2px solid ${item.active ? item.color : 'transparent'};\n \">${item.score}</span>`\n )}\n </div>\n `}\n\n ${is2D && kpi?.grades?.rows\n ? html`\n <div style=\"margin-top: 20px; border-top: 1px solid #e0e0e0; padding-top: 16px;\">\n <div style=\"font-size: 0.9rem; font-weight: 700; color: #333; margin-bottom: 8px;\">\n 공정률 × 공기편차 성과 분포\n </div>\n <div style=\"height: 250px;\">\n <kpi-2d-lookup-chart\n .grades=${kpi.grades}\n .progressRate=${this.project?.totalProgress ?? 50}\n ></kpi-2d-lookup-chart>\n </div>\n </div>\n `\n : ''}\n </div>\n `\n }\n\n private _closePopup() {\n this.showScoreDistribution = false\n this.selectedKpi = null\n }\n\n private getMetricValue(kpiNamePattern: string): string {\n const kpiValue = this.projectXKpiValues.find(kv => kv.kpi?.name && kv.kpi.name.includes(kpiNamePattern))\n const value = kpiValue?.value || 0\n\n // 정수면 그대로, 소수면 최대 3자리까지만 표시\n if (Number.isInteger(value)) {\n return value.toString()\n } else {\n return value.toFixed(3).replace(/\\.?0+$/, '')\n }\n }\n\n private getYKpiScoreFormatted(kpiName: string): string {\n const value = this.getProjectYKpiValue(kpiName)\n if (value === 0) return '-'\n return (value * 100).toFixed(1)\n }\n\n private getMetricGroups() {\n return {\n Y1: {\n name: '일정성과 (Y1)',\n score: this.getYKpiScoreFormatted('Y1. 일정성과'),\n metrics: [\n { label: '연면적 대비 공사기간', pattern: 'X11', value: this.getMetricValue('X11') },\n { label: '설계변경 공기 증감률', pattern: 'X12', value: this.getMetricValue('X12') },\n { label: '일정 이탈 수준', pattern: 'X13', value: this.getMetricValue('X13') },\n { label: '일정성과 수준 평가', pattern: 'X14', value: this.getMetricValue('X14') }\n ]\n },\n Y2: {\n name: '비용성과 (Y2)',\n score: this.getYKpiScoreFormatted('Y2. 비용성과'),\n metrics: [\n { label: '연면적 대비 공사비', pattern: 'X21', value: this.getMetricValue('X21') },\n { label: '설계변경 공사비 증감', pattern: 'X22', value: this.getMetricValue('X22') },\n { label: '일정성과 수준 평가', pattern: 'X23', value: this.getMetricValue('X23') }\n ]\n },\n Y3: {\n name: '품질성과 (Y3)',\n score: this.getYKpiScoreFormatted('Y3. 품질성과'),\n metrics: [\n { label: '검측 불합격률', pattern: 'X33', value: this.getMetricValue('X33') },\n { label: '품질 SL-PA 결과', pattern: 'X34', value: this.getMetricValue('X34') },\n { label: '품질성과 수준 평가', pattern: 'X35', value: this.getMetricValue('X35') }\n ]\n },\n Y4: {\n name: '안전성과 (Y4)',\n score: this.getYKpiScoreFormatted('Y4. 안전성과'),\n metrics: [\n { label: '재해율', pattern: 'X41', value: this.getMetricValue('X41') },\n { label: '재해강도율', pattern: 'X42', value: this.getMetricValue('X42') },\n { label: '안전 SL-PA 결과', pattern: 'X43', value: this.getMetricValue('X43') },\n { label: '안전성과 수준 평가', pattern: 'X44', value: this.getMetricValue('X44') }\n ]\n },\n Y5: {\n name: '환경성과 (Y5)',\n score: this.getYKpiScoreFormatted('Y5. 환경성과'),\n metrics: [\n { label: '건설폐기물 발생량', pattern: 'X51', value: this.getMetricValue('X51') },\n { label: '환경성과 수준 평가', pattern: 'X52', value: this.getMetricValue('X52') }\n ]\n },\n Y6: {\n name: '생산성 성과 (Y6)',\n score: this.getYKpiScoreFormatted('Y6. 생산성성과'),\n metrics: [\n { label: '투입인력 생산성', pattern: 'X61', value: this.getMetricValue('X61') },\n { label: '생산성성과 수준 평가', pattern: 'X62', value: this.getMetricValue('X62') }\n ]\n }\n }\n }\n\n private getYKpiBoxplotData() {\n // KPI 카테고리 매핑 (Y-category KPI names to display categories)\n const categoryMapping: Record<string, string> = {\n Y01_productivity: '생산성과',\n Y02_schedule: '일정성과',\n Y03_cost: '비용성과',\n Y04_quality: '품질성과',\n Y05_safety: '안전성과',\n Y06_environment: '환경성과'\n }\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\n // Y-KPI 카테고리별로 통합된 통계 생성\n this.kpiYComprehensiveStats.forEach(stat => {\n const category = categoryMapping[stat.kpiName] || stat.kpiName\n\n data.push({\n org: category, // org 필드 사용 (boxplot 차트가 기대하는 필드명)\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: this.getProjectYKpiValue(stat.kpiName) * 100 // 현재 프로젝트의 실제 Y-KPI 값 (0~1 → 0~20)\n })\n })\n\n return data.sort((a, b) => a.org.localeCompare(b.org))\n }\n\n private getProjectYKpiValue(kpiName: string): number {\n // 현재 프로젝트의 kpiValues 배열에서 해당 KPI 값을 찾습니다\n const kpiValue = this.project?.kpiValues?.find(kv => kv.kpiName === kpiName)\n return kpiValue?.value || 0\n }\n\n private getRadarChartData() {\n // KPI 카테고리 매핑 (Y-category KPI names to display categories)\n const categoryMapping: Record<string, string> = {\n Y01_productivity: '생산성',\n Y02_schedule: '일정',\n Y03_cost: '비용',\n Y04_quality: '품질',\n Y05_safety: '안전',\n Y06_environment: '환경'\n }\n\n const data: Array<{ org: string; category: string; value: number }> = []\n const categories: string[] = []\n\n // Create baseline data from comprehensive stats (using avgVal as baseline)\n this.kpiYComprehensiveStats.forEach(stat => {\n const category = categoryMapping[stat.kpiName] || stat.kpiName\n if (!categories.includes(category)) {\n categories.push(category)\n }\n\n // Add baseline average\n data.push({\n org: '기준평균',\n category,\n value: Math.round(stat.avgVal * 100) // Scale to match expected range (0~1 → 0~20)\n })\n\n // Add current project performance (using project's individual values)\n data.push({\n org: '프로젝트성과',\n category,\n value: Math.round(this.getProjectYKpiValue(stat.kpiName) * 100) // Y-KPI 값 (0~1 → 0~20)\n })\n })\n\n return {\n data,\n categories:\n categories.length > 0\n ? categories\n : ['Y1. 일정성과', 'Y2. 비용성과', 'Y3. 품질성과', 'Y4. 안전성과', 'Y5. 환경성과', 'Y6. 생산성성과']\n }\n }\n\n private getBoxPlotDataForProject(project: Project) {\n // 프로젝트의 지역(geo_group)에 해당하는 통계 찾기\n const stats = this.kpiComprehensiveStats?.[0]\n\n if (!stats) {\n // 전체 통계의 평균값 사용 또는 기본값 반환\n const defaultStats = this.kpiComprehensiveStats.length > 0 ? this.kpiComprehensiveStats[0] : null\n if (defaultStats) {\n return {\n min: defaultStats.minVal,\n max: defaultStats.maxVal,\n mean: (defaultStats.q1Val + defaultStats.q3Val) / 2,\n median: defaultStats.medVal,\n q1: defaultStats.q1Val,\n q3: defaultStats.q3Val,\n value: project.kpi || 0\n }\n }\n\n // 완전한 기본값\n return {\n min: 0,\n max: 100,\n mean: 50,\n median: 50,\n q1: 25,\n q3: 75,\n value: project.kpi || 0\n }\n }\n\n return {\n min: stats.minVal * 100,\n max: stats.maxVal * 100,\n mean: ((stats.q1Val + stats.q3Val) / 2) * 100, // 대략적 평균값\n median: stats.medVal * 100,\n q1: stats.q1Val * 100,\n q3: stats.q3Val * 100,\n value: project.kpi || 0\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sv-project-detail.js","sourceRoot":"","sources":["../../client/pages/sv-project-detail.ts"],"names":[],"mappings":"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","sourcesContent":["import { navigate, PageLifecycle, PageView } from '@operato/shell'\nimport { ScrollbarStyles } from '@operato/styles'\nimport { css, html } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\nimport { Project, PROJECT_STATE, ProjectState } from './sv-project-list'\nimport { SITE_TYPE_DISPLAY } from '@dssp/project/dist-client/pages/project/project-list'\nimport { client } from '@operato/graphql'\nimport { getDomain } from '@things-factory/auth-base/dist-client/profiled'\nimport gql from 'graphql-tag'\nimport moment from 'moment-timezone'\nimport { isProjectTypeDomain, tenantHeaders } from '@dssp/project/dist-client/shared/domain-context'\nimport '../components/kpi-boxplot-chart'\nimport '../components/kpi-single-boxplot-chart'\nimport '../components/kpi-radar-chart'\nimport '../components/kpi-lookup-chart'\nimport '../components/kpi-2d-lookup-chart'\n\n@customElement('sv-project-detail')\nexport class SvProjectDetailPage extends ScopedElementsMixin(PageView) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n\n width: 100%;\n height: 100%;\n background-color: var(--md-sys-color-background, #f6f6f6);\n }\n\n /* content layout */\n div[content] {\n display: flex;\n gap: 35px;\n padding: 25px;\n }\n div[left] {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 20px;\n }\n div[right] {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 0 1px;\n }\n\n /* card */\n .card {\n background: #ffffff;\n border-radius: 10px;\n padding: 15px;\n box-shadow: 3px 3px 3px 0 rgba(0, 0, 0, 0.1);\n }\n .card-title {\n display: flex;\n align-items: center;\n gap: 5px;\n color: #35618e;\n font-weight: 700;\n }\n .triangle {\n width: 0;\n height: 0;\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-top: 8px solid #35618e;\n }\n\n /* left top info box */\n .bold {\n font-weight: bold;\n }\n .top-info {\n display: flex;\n gap: 10px;\n }\n .top-info img[pic] {\n width: 284px;\n height: 160px;\n object-fit: fill;\n background: #e5e7eb;\n }\n .top-info .info {\n display: flex;\n flex-direction: column;\n gap: 15px;\n padding: 10px 0;\n flex: 1;\n }\n .row {\n display: flex;\n align-items: center;\n gap: 10px;\n }\n .label {\n min-width: fit-content;\n color: #35618e;\n font-size: 16px;\n letter-spacing: -0.05em;\n }\n .value {\n color: #333;\n font-size: 16px;\n }\n .status-value {\n color: #4cbb49;\n font-weight: 700;\n }\n\n .address {\n color: #35618e;\n font-size: 16px;\n letter-spacing: -0.05em;\n }\n\n .detail-grid {\n display: grid;\n grid-template-columns: 284px 1fr;\n gap: 15px 10px;\n padding: 5px 0;\n }\n .detail-grid .grid-item .label {\n width: auto;\n }\n\n /* left second card (requests) */\n .sub-desc {\n color: #35618e;\n font-size: 14px;\n letter-spacing: -0.05em;\n margin-bottom: 8px;\n }\n .list-block {\n display: flex;\n flex-direction: column;\n gap: 5px;\n padding: 5px 25px;\n }\n .list-title {\n color: #212529;\n font-weight: 700;\n font-size: 16px;\n letter-spacing: -0.05em;\n }\n .list-text {\n color: #35618e;\n font-size: 16px;\n letter-spacing: -0.05em;\n margin-left: 8px;\n }\n .list-text .warn {\n margin-left: 10px;\n color: #e13232;\n\n md-icon {\n font-size: 17px;\n width: 13px;\n height: 13px;\n }\n }\n\n /* right buttons */\n .button-line {\n display: flex;\n justify-content: flex-end;\n gap: 10px;\n }\n .ghost-btn {\n display: flex;\n align-items: center;\n gap: 3px;\n padding: 5px 10px;\n background: #35618e;\n color: #ffffff;\n border-radius: 5px;\n box-shadow: 2px 2px 2px 0 rgba(0, 0, 0, 0.1);\n cursor: pointer;\n\n /* Material Symbols Outlined (stroke style) */\n md-icon {\n font-variation-settings:\n 'FILL' 0,\n 'wght' 300,\n 'GRAD' 0,\n 'opsz' 24;\n }\n }\n\n /* right KPI box */\n .kpi-box {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 15px;\n max-height: 420px;\n min-width: 560px;\n }\n .kpi-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n color: #35618e;\n font-weight: 700;\n font-size: 20px;\n letter-spacing: -0.05em;\n }\n .kpi-header div {\n display: flex;\n align-items: center;\n gap: 5px;\n }\n .kpi-desc {\n color: #35618e;\n font-size: 13px;\n letter-spacing: -0.05em;\n }\n .kpi-summary {\n display: flex;\n align-items: center;\n padding: 0 30px;\n max-height: 360px;\n gap: 20px;\n }\n .mini-boxplot {\n flex: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n position: relative;\n min-width: 120px;\n }\n .boxplot-area {\n flex: 1;\n width: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n background: #ffffff;\n }\n\n .boxplot-point {\n display: flex;\n flex-direction: column;\n align-items: center;\n color: #35618e;\n }\n .boxplot-point .value {\n font-size: 42px;\n font-weight: 800;\n color: #35618e;\n border-radius: 6px;\n }\n .boxplot-point .label {\n font-size: 14px;\n font-weight: 300;\n width: auto;\n }\n\n /* spider chart placeholder */\n .spider-area {\n flex: 5;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 10px;\n height: 100%;\n }\n\n /* group distribution */\n .group-box .desc {\n color: #35618e;\n font-size: 13px;\n letter-spacing: -0.05em;\n margin-top: 4px;\n }\n .group-chart {\n height: 300px;\n margin-top: 25px;\n }\n\n kpi-single-boxplot-chart {\n flex: 1;\n }\n\n /* KPI 메트릭 데이터 카드 */\n .metrics-card {\n background: #ffffff;\n border-radius: 10px;\n padding: 20px;\n box-shadow: 3px 3px 3px 0 rgba(0, 0, 0, 0.1);\n max-width: 100%;\n overflow: hidden;\n }\n .metrics-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n .metrics-header .title {\n display: flex;\n align-items: center;\n gap: 8px;\n color: #35618e;\n font-weight: 700;\n font-size: 18px;\n }\n .metrics-card .desc {\n color: #35618e;\n font-size: 13px;\n letter-spacing: -0.05em;\n margin-top: 4px;\n margin-bottom: 15px;\n }\n .metrics-content {\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n .metric-group {\n border-bottom: 1px dotted #ddd;\n padding-bottom: 12px;\n }\n .metric-group:last-child {\n border-bottom: none;\n padding-bottom: 0;\n }\n .metric-group-header {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-bottom: 8px;\n color: #35618e;\n font-weight: 600;\n font-size: 16px;\n }\n .metric-group-icon {\n width: 20px;\n height: 20px;\n background: #35618e;\n border-radius: 3px;\n position: relative;\n }\n .metric-group-icon::before {\n content: '✓';\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n color: white;\n font-size: 12px;\n font-weight: bold;\n }\n .metric-items {\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n gap: 8px 16px;\n padding-left: 28px;\n }\n .metric-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n font-size: 14px;\n }\n .metric-label {\n color: #333;\n flex: 1;\n }\n .metric-value {\n color: #35618e;\n font-weight: 600;\n min-width: 40px;\n text-align: right;\n }\n\n /* Popup overlay */\n .popup-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n }\n .popup-content {\n background: white;\n border-radius: 12px;\n padding: 24px;\n max-width: 800px;\n width: 90%;\n max-height: 80vh;\n overflow-y: auto;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);\n }\n .popup-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 20px;\n padding-bottom: 16px;\n border-bottom: 2px solid #e0e0e0;\n }\n .popup-title {\n font-size: 20px;\n font-weight: 700;\n color: #35618e;\n }\n .popup-close {\n cursor: pointer;\n font-size: 24px;\n color: #999;\n background: none;\n border: none;\n padding: 4px 8px;\n }\n .popup-close:hover {\n color: #333;\n }\n .popup-chart-container {\n min-height: 400px;\n height: 500px;\n }\n .metric-label {\n cursor: pointer;\n }\n .metric-label:hover {\n opacity: 0.7;\n text-decoration: underline;\n }\n `\n ]\n\n get context() {\n return {\n title:\n !isProjectTypeDomain() && this.project\n ? `프로젝트 상세 정보 - ${this.project?.name}`\n : '프로젝트 상세 정보'\n }\n }\n\n @state() private project: Project = {} as Project\n @state() private kpiComprehensiveStats: any[] = []\n @state() private kpiYComprehensiveStats: any[] = []\n @state() private projectXKpiValues: any[] = []\n @state() private showScoreDistribution: boolean = false\n @state() private selectedKpi: any = null\n /** 이 프로젝트에 아직 한 번도 입력되지 않은 metric (active 한 manual/import 한정) */\n @state() private pendingMetrics: { id: string; name: string; description?: string }[] = []\n\n render() {\n return html`\n <div content>\n <div left>\n <div class=\"card\">\n <div class=\"card-title\">\n <div>${this.project.name}</div>\n <div class=\"triangle\"></div>\n </div>\n\n <div class=\"top-info\" style=\"margin-top: 10px;\">\n <img pic src=${this.project.mainPhoto?.fullpath || '/assets/images/project-image.png'} alt=\"project\" />\n <div class=\"info\">\n <div class=\"row\">\n <div class=\"label\">• 주소</div>\n <div class=\"value\">${this.project.buildingComplex?.address}</div>\n </div>\n <div class=\"row\">\n <div class=\"label\">• 공사기간</div>\n <div class=\"value\">${this.project.startDate} ~ ${this.project.endDate}</div>\n </div>\n <div class=\"row\">\n <div class=\"label\">• 현장상태</div>\n <div class=\"value status-value\">${PROJECT_STATE[this.project.state]}</div>\n </div>\n <div class=\"row\">\n <div class=\"label\">• 유형</div>\n <div class=\"value\">\n ${(this.project as any).sectorType === 'PUBLIC'\n ? '공공'\n : (this.project as any).sectorType === 'PRIVATE'\n ? '민간'\n : '-'}\n </div>\n </div>\n <div class=\"row\">\n <div class=\"label\">• 용도</div>\n <div class=\"value\">\n ${(this.project as any).buildingUsage === 'RESIDENTIAL'\n ? '주거'\n : (this.project as any).buildingUsage === 'NON_RESIDENTIAL'\n ? '비주거'\n : '-'}\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"detail-grid\">\n <div class=\"grid-item row\">\n <div class=\"label\">• 공사비</div>\n <div class=\"value\">${this.project.buildingComplex?.constructionCost?.toLocaleString() || '-'} 억원</div>\n </div>\n <div class=\"grid-item row\">\n <div class=\"label\">• 연면적</div>\n <div class=\"value\">${this.project.buildingComplex?.area?.toLocaleString() || '-'} ㎡</div>\n </div>\n <div class=\"grid-item row\">\n <div class=\"label\">• 용적률</div>\n <div class=\"value\">\n ${(this.project.buildingComplex as any)?.floorAreaRatio?.toLocaleString() || '-'} %\n </div>\n </div>\n <div class=\"grid-item row\">\n <div class=\"label\">• 투입인력</div>\n <div class=\"value\">\n ${(this.project.buildingComplex as any)?.workerCount?.toLocaleString() || '-'} 명\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"card\">\n <div class=\"card-title\">\n <div>입력 대기 중</div>\n <div class=\"triangle\"></div>\n </div>\n <div class=\"sub-desc\">\n 이 프로젝트에 아직 입력되지 않은 KPI 항목입니다. 해당 항목에 대한 데이터를 입력 해 주시기 바랍니다.\n </div>\n\n <div class=\"list-block\">\n <div class=\"list-title\">• 미입력 ${this.pendingMetrics.length}건</div>\n ${this.pendingMetrics.length === 0\n ? html`<div class=\"list-text\">모든 항목이 입력되었습니다.</div>`\n : this.pendingMetrics.map(\n m => html`\n <div\n class=\"list-text\"\n style=\"cursor: pointer;\"\n @click=${async () => {\n if (isProjectTypeDomain()) {\n navigate('project-complete')\n return\n }\n const id = this.project.id || (await this._resolveProjectIdFromDomain())\n if (id) navigate(`project-complete/${id}`)\n }}\n >\n # ${m.name}\n </div>\n `\n )}\n </div>\n </div>\n </div>\n\n <div right>\n ${html`\n <div class=\"button-line\">\n <div\n class=\"ghost-btn\"\n @click=${async () => {\n // project-type domain 에서는 대상 페이지가 subdomain 으로 자동 해석하므로 id 불필요\n if (isProjectTypeDomain()) {\n navigate('project-update')\n return\n }\n const id = this.project.id || (await this._resolveProjectIdFromDomain())\n if (id) navigate(`project-update/${id}`)\n }}\n >\n <md-icon slot=\"\">assignment</md-icon>\n <div>프로젝트 수정</div>\n </div>\n <div\n class=\"ghost-btn\"\n @click=${async () => {\n if (isProjectTypeDomain()) {\n navigate('project-complete')\n return\n }\n const id = this.project.id || (await this._resolveProjectIdFromDomain())\n if (id) navigate(`project-complete/${id}`)\n }}\n >\n <md-icon slot=\"\">assignment_turned_in</md-icon>\n <div>KPI 데이타입력</div>\n </div>\n </div>\n `}\n\n <div class=\"card kpi-box\">\n <div class=\"kpi-header\">\n <div>\n <div>종합 KPI</div>\n <div class=\"triangle\"></div>\n </div>\n <div class=\"kpi-desc\">프로젝트의 6개 성과를 종합한 종합 KPI포인트와 각 지표별 분포</div>\n </div>\n\n <div class=\"kpi-summary\">\n <div class=\"mini-boxplot\" title=\"boxplot placeholder\">\n <div class=\"boxplot-area\">\n <kpi-single-boxplot-chart .data=${this.getBoxPlotDataForProject(this.project)}></kpi-single-boxplot-chart>\n </div>\n\n <div class=\"boxplot-point\">\n <div class=\"value\">${this.project.kpi ? this.project.kpi.toFixed(1) : '-'}</div>\n <div class=\"label\">Point</div>\n </div>\n </div>\n\n <div class=\"spider-area\">\n <sv-kpi-radar-chart\n .data=${this.getRadarChartData().data}\n .categories=${this.getRadarChartData().categories}\n .currentGroup=${'프로젝트성과'}\n ></sv-kpi-radar-chart>\n </div>\n </div>\n </div>\n\n <div class=\"card group-box\">\n <div class=\"kpi-header\">\n <div>\n <div>그룹별 분포</div>\n <div class=\"triangle\"></div>\n </div>\n </div>\n <div class=\"desc\">\n Boxplot(박스플롯)은 각 카테고리별로 값의 분포(최소, 1사분위, 중앙값, 3사분위, 최대, 평균, 이상치 등)를 보여줍니다.\n 박스는 중앙 50% 구간, 수염은 전체 범위, 굵은 검정색 가로선은 중앙값(메디안), 초록색 원은 평균값(Mean)을 의미합니다.\n 이 프로젝트의 값은 진한 오렌지색 원으로 별도 강조되어 표시되며, 중앙값/평균과 다를 수 있습니다.\n </div>\n <div class=\"group-chart\">\n <sv-kpi-boxplot-chart .data=${this.getYKpiBoxplotData()}></sv-kpi-boxplot-chart>\n </div>\n </div>\n\n <div class=\"metrics-card\">\n <div class=\"metrics-header\">\n <div class=\"title\">\n <span>그룹별 상세 매트릭 데이터</span>\n <div class=\"triangle\"></div>\n </div>\n </div>\n <div class=\"desc\">\n 프로젝트의 6개 성과별 상세 주요 매트릭 데이터 (각 세부 항목을 클릭하시면 평가 기준표를 확인할 수 있습니다)\n </div>\n <div class=\"metrics-content\">\n ${Object.values(this.getMetricGroups()).map(\n group => html`\n <div class=\"metric-group\">\n <div class=\"metric-group-header\">\n <div class=\"metric-group-icon\"></div>\n <span>${group.name}</span>\n <span style=\"margin-left: 10px; color: #4caf50; font-weight: 700;\">[${group.score}]</span>\n </div>\n <div class=\"metric-items\">\n ${group.metrics.map(\n metric => html`\n <div class=\"metric-item\">\n <span\n class=\"metric-label\"\n @click=${() => this._onMetricLabelClick(metric)}\n title=\"클릭하시면 평가 기준표를 확인할 수 있습니다\"\n >\n ${metric.label}\n </span>\n <span class=\"metric-value\">${metric.value}</span>\n </div>\n `\n )}\n </div>\n </div>\n `\n )}\n </div>\n </div>\n </div>\n </div>\n\n ${this.showScoreDistribution && this.selectedKpi\n ? html`\n <div class=\"popup-overlay\" @click=${this._closePopup}>\n <div class=\"popup-content\" @click=${(e: Event) => e.stopPropagation()}>\n <div class=\"popup-header\">\n <div class=\"popup-title\">${this.selectedKpi.kpiName} — 성과 분포</div>\n <button class=\"popup-close\" @click=${this._closePopup}>×</button>\n </div>\n <div class=\"popup-chart-container\">\n ${/*\n * scoreType 기반 차트 분기:\n *\n * CUSTOM (X13 등): 2D 룩업 히트맵 — 단, 증강데이터에서는 value가\n * 이미 1~5 정수(룩업 결과)이므로 히트맵 대신 게이지로 폴백.\n * 실제 프로젝트에서는 value가 편차율(소수점)이므로 히트맵 표시.\n *\n * LOOKUP: 성과 분포 커브 (kpi-lookup-chart)\n * ASSESSMENT: 5단계 게이지 (kpi-lookup-chart 자동 감지)\n */ ''}\n ${(this.selectedKpi.scoreType === 'CUSTOM' ||\n this.selectedKpi.grades?.type === 'PROGRESS_DEVIATION_LOOKUP') &&\n this.selectedKpi.value !== null &&\n !(\n this.selectedKpi.value === Math.floor(this.selectedKpi.value) &&\n this.selectedKpi.value >= 1 &&\n this.selectedKpi.value <= 5\n )\n ? html`\n <kpi-2d-lookup-chart\n .grades=${this.selectedKpi.grades}\n .value=${this.selectedKpi.value}\n .progressRate=${this.project?.totalProgress ?? 50}\n unit=\"%\"\n kpiName=${this.selectedKpi.kpiName || ''}\n ></kpi-2d-lookup-chart>\n `\n : this._isAssessmentOrIntegerScore()\n ? this._renderAssessmentGrades()\n : html`\n <kpi-lookup-chart\n .grades=${this.selectedKpi.grades || []}\n .value=${this.selectedKpi.value}\n .scoreType=${this.selectedKpi.scoreType || ''}\n .valueType=${this.selectedKpi.valueType || ''}\n unit=${this.selectedKpi.unit || ''}\n ></kpi-lookup-chart>\n `}\n </div>\n </div>\n </div>\n `\n : ''}\n `\n }\n\n async pageUpdated(changes: any, lifecycle: PageLifecycle) {\n if (!this.active) return\n\n let projectId = lifecycle.resourceId\n\n // 프로젝트 테넌트 컨텍스트(/project/<code>/) 에서 진입한 경우 resourceId 가 비어있다.\n // 현재 도메인의 subdomain(= Project.code) 으로 프로젝트를 역조회.\n if (!projectId) {\n projectId = await this._resolveProjectIdFromDomain()\n }\n\n if (!projectId) return\n\n // initProject 의 GraphQL 응답을 기다리지 않고 project.id 를 즉시 채워서,\n // 링크의 `project-update/${project.id}` 가 절대 undefined 가 되지 않도록 보장.\n this.project = { ...this.project, id: projectId } as Project\n\n // 후속 query 들이 tenant 컨텍스트로 동작하도록 project.code 를 먼저 가볍게 resolve.\n // (tenant 컨텍스트에서 진입한 경우는 헤더 불필요 — tenantHeaders 가 빈 객체 반환.)\n if (!isProjectTypeDomain()) {\n await this._resolveProjectCode(projectId)\n }\n\n this.initProject(projectId)\n this.getKpiComprehensiveStats()\n this.getKpiYComprehensiveStats()\n this.getProjectXKpiValues(projectId)\n }\n\n private async _resolveProjectCode(projectId: string): Promise<void> {\n try {\n const resp = await client.query({\n query: gql`\n query ProjectCode($id: String!) {\n project(id: $id) {\n id\n code\n }\n }\n `,\n variables: { id: projectId }\n })\n const code = resp.data?.project?.code\n if (code) {\n this.project = { ...this.project, code } as Project\n }\n } catch (e) {\n console.warn('[project-detail] project.code resolve 실패', e)\n }\n }\n\n private async _resolveProjectIdFromDomain(): Promise<string> {\n const response = await client.query({\n query: gql`\n query CurrentProject {\n currentProject {\n id\n }\n }\n `\n })\n\n return response.data?.currentProject?.id || ''\n }\n\n async initProject(projectId: string = '') {\n const response = await client.query({\n query: gql`\n query Project($id: String!) {\n project(id: $id) {\n id\n code\n name\n state\n startDate\n endDate\n projectType\n sectorType\n buildingUsage\n mainPhoto {\n fullpath\n }\n totalProgress\n weeklyProgress\n kpi\n kpiValues {\n kpiName\n value\n }\n inspPassRate\n robotProgressRate\n structuralSafetyRate\n robotCount\n buildingComplex {\n id\n address\n latitude\n longitude\n area\n coverageRatio\n floorAreaRatio\n siteType\n workerCount\n clientCompany\n constructionCompany\n supervisoryCompany\n designCompany\n drawing {\n id\n name\n fullpath\n }\n constructionType\n constructionCost\n etc\n notice\n householdCount\n buildingCount\n virtualTourLink\n buildings {\n id\n name\n floorCount\n }\n }\n }\n }\n `,\n variables: { id: projectId },\n context: { headers: tenantHeaders((this.project as any)?.code) }\n })\n\n if (response.errors) return\n\n this.project = response.data?.project || ({} as Project)\n\n this.updateContext()\n this._loadPendingMetrics()\n }\n\n /**\n * 이 프로젝트의 미입력 KPI metric 들을 조회 — Step 1/2 와 동일 기준.\n * - 대상: active=true 인 manual/import metric (자동수집/외부API 제외)\n * - 판정:\n * · MONTH metric → 전월 row (periodType='MONTH', valueDate startsWith 전월) 없으면 pending\n * · 그 외 → (metric, periodType) 매칭 row 없으면 pending\n */\n private async _loadPendingMetrics() {\n if (!this.project?.id) {\n this.pendingMetrics = []\n return\n }\n\n try {\n // 1) Active manual/import metric 정의 목록 (periodType 포함)\n const metricsResp = await client.query({\n query: gql`\n query KpiMetrics {\n kpiMetrics {\n items {\n id\n name\n description\n periodType\n collectType\n active\n }\n }\n }\n `,\n context: { headers: tenantHeaders((this.project as any)?.code) }\n })\n // collectType 필터 제거 — Step 1/2 가 모든 metric 을 보여주므로 동일하게 전체 대상.\n // active=false 인 metric 만 제외.\n const targets = (metricsResp.data?.kpiMetrics?.items || []).filter((m: any) => m.active)\n if (targets.length === 0) {\n this.pendingMetrics = []\n return\n }\n\n // 2) 이 프로젝트의 모든 KpiMetricValue (value 도 가져와서 null/undefined 체크)\n const valuesResp = await client.query({\n query: gql`\n query KpiMetricValues($filters: [Filter!]) {\n kpiMetricValues(filters: $filters) {\n items {\n metricId\n periodType\n valueDate\n value\n }\n }\n }\n `,\n variables: { filters: [{ name: 'org', operator: 'eq', value: this.project.id }] },\n context: { headers: tenantHeaders((this.project as any)?.code) }\n })\n const values: any[] = valuesResp.data?.kpiMetricValues?.items || []\n const lastMonthYm = moment().tz('Asia/Seoul').subtract(1, 'month').format('YYYY-MM')\n\n // 3) Step 1/2 와 동일 기준으로 미입력 판정 — row 존재 AND value 존재 (null/undefined 아님).\n const hasValid = (v: any) => v.value !== null && v.value !== undefined\n this.pendingMetrics = targets.filter((m: any) => {\n if (m.periodType === 'MONTH') {\n return !values.some(\n v =>\n v.metricId === m.id &&\n v.periodType === 'MONTH' &&\n (v.valueDate || '').startsWith(lastMonthYm) &&\n hasValid(v)\n )\n }\n return !values.some(v => v.metricId === m.id && v.periodType === m.periodType && hasValid(v))\n })\n } catch (e) {\n console.error('[입력 대기 중] 조회 실패', e)\n this.pendingMetrics = []\n }\n }\n\n async getKpiComprehensiveStats() {\n try {\n const response = await client.query({\n query: gql`\n query GetKpiZValueComprehensiveStats {\n totalKpiZValueComprehensiveStats {\n minVal\n q1Val\n medVal\n q3Val\n maxVal\n }\n }\n `,\n context: { headers: tenantHeaders((this.project as any)?.code) }\n })\n\n this.kpiComprehensiveStats = response.data.totalKpiZValueComprehensiveStats || []\n } catch (error) {\n console.error('Failed to fetch KPI comprehensive stats:', error)\n this.kpiComprehensiveStats = []\n }\n }\n\n async getKpiYComprehensiveStats() {\n try {\n const response = await client.query({\n query: gql`\n query GetKpiYValueComprehensiveStats {\n totalKpiYValueComprehensiveStats {\n kpiName\n minVal\n q1Val\n medVal\n q3Val\n maxVal\n avgVal\n projectCount\n }\n }\n `,\n context: { headers: tenantHeaders((this.project as any)?.code) }\n })\n\n this.kpiYComprehensiveStats = response.data.totalKpiYValueComprehensiveStats || []\n } catch (error) {\n console.error('Failed to fetch KPI Y comprehensive stats:', error)\n this.kpiYComprehensiveStats = []\n }\n }\n\n async getProjectXKpiValues(projectId: string) {\n try {\n const response = await client.query({\n query: gql`\n query GetProjectXKpiValues($projectId: String!) {\n projectXKpiValues(projectId: $projectId) {\n id\n value\n valueDate\n kpi {\n id\n name\n description\n }\n }\n }\n `,\n variables: { projectId },\n context: { headers: tenantHeaders((this.project as any)?.code) }\n })\n\n this.projectXKpiValues = response.data.projectXKpiValues || []\n } catch (error) {\n console.error('Failed to fetch project X KPI values:', error)\n this.projectXKpiValues = []\n }\n }\n\n private _onMetricLabelClick(metric: any) {\n // metric.pattern을 사용하여 X-KPI 조회\n if (!metric.pattern) {\n console.warn('No pattern found for metric:', metric)\n return\n }\n\n // X-KPI 이름 패턴 (예: X11, X12, X21, ...)\n const kpiNamePattern = metric.pattern\n\n // 해당 KPI 정보 조회\n this._fetchKpiWithGradesByPattern(kpiNamePattern, metric.label)\n }\n\n private async _fetchKpiWithGradesByPattern(kpiNamePattern: string, displayName: string) {\n try {\n // X-KPI 이름 패턴으로 전체 이름 찾기 (projectXKpiValues에서)\n const kpiValue = this.projectXKpiValues.find(kv => kv.kpi?.name && kv.kpi.name.includes(kpiNamePattern))\n\n if (!kpiValue || !kpiValue.kpi) {\n console.warn(`No KPI found for pattern: ${kpiNamePattern}`)\n return\n }\n\n // GraphQL로 KPI 상세 정보 (grades 포함) 조회\n const response = await client.query({\n query: gql`\n query Kpi($id: String!) {\n kpi(id: $id) {\n id\n name\n grades\n scoreType\n valueType\n vizMeta\n }\n }\n `,\n variables: { id: kpiValue.kpi.id },\n context: { headers: tenantHeaders((this.project as any)?.code) }\n })\n\n if (response.errors || !response.data?.kpi) {\n console.error('KPI not found or error:', response.errors)\n return\n }\n\n const kpi = response.data.kpi\n\n // grades가 없으면 경고\n const is2D = kpi.grades && !Array.isArray(kpi.grades) && kpi.grades.type === 'PROGRESS_DEVIATION_LOOKUP'\n if (!kpi.grades || (!is2D && (!Array.isArray(kpi.grades) || kpi.grades.length === 0))) {\n console.warn(`No grades found for KPI: ${kpiValue.kpi.name}`)\n }\n\n this.selectedKpi = {\n kpiName: displayName,\n grades: kpi.grades || [],\n scoreType: kpi.scoreType || '',\n valueType: kpi.valueType || '',\n value: kpiValue.value ?? null,\n unit: kpi.vizMeta?.unit || ''\n }\n\n this.showScoreDistribution = true\n } catch (error) {\n console.error('Error fetching KPI:', error)\n }\n }\n\n /**\n * 등급 기준으로 표시할지 판별 (차트 대신 등급 설명 목록)\n *\n * - valueType=ASSESSED: 감리자 직접 평가 → 등급 설명\n * - CUSTOM/COMPOSITE이지만 value가 1~5 정수 (증강데이터): 등급 설명 + 히트맵\n * - grades가 배열이 아닌 경우 (2D lookup 객체): 등급 설명 + 히트맵\n */\n private _isAssessmentOrIntegerScore(): boolean {\n const kpi = this.selectedKpi\n if (!kpi) return false\n // valueType 기반 판별 (우선)\n if (kpi.valueType === 'ASSESSED') return true\n // CUSTOM/COMPOSITE이지만 value가 1~5 정수 (증강데이터)\n if (\n (kpi.scoreType === 'CUSTOM' || kpi.valueType === 'COMPOSITE') &&\n kpi.value !== null &&\n kpi.value === Math.floor(kpi.value) &&\n kpi.value >= 1 &&\n kpi.value <= 5\n )\n return true\n // grades가 배열이 아닌 경우 (2D lookup 객체)\n if (kpi.grades && !Array.isArray(kpi.grades)) return true\n return false\n }\n\n /** 등급 기준 표시 (ASSESSED / 1~5 정수 score) — 현재 값 강조 + CUSTOM은 2D 히트맵도 표시 */\n private _renderAssessmentGrades() {\n const kpi = this.selectedKpi\n const currentScore = kpi?.value != null ? Math.round(kpi.value) : 0\n const grades = Array.isArray(kpi?.grades) ? kpi.grades : []\n const colors = ['#e53935', '#ff9800', '#ffca28', '#66bb6a', '#2e7d32']\n const is2D = kpi?.scoreType === 'CUSTOM' || kpi?.valueType === 'COMPOSITE' ||\n (kpi?.grades && typeof kpi.grades === 'object' && !Array.isArray(kpi.grades) && kpi.grades.type === 'PROGRESS_DEVIATION_LOOKUP')\n\n // grades가 있으면 description 사용, 없으면 기본 라벨\n const defaultLabels = ['매우 미흡', '미흡', '보통', '양호', '우수']\n const items = [1, 2, 3, 4, 5].map(score => {\n const grade = grades.find((g: any) => g.score === score)\n return {\n score,\n desc: grade?.description || grade?.name || defaultLabels[score - 1],\n color: colors[score - 1],\n active: score === currentScore\n }\n })\n\n // ASSESSED(감리자 평가)이고 grades에 description이 있는 경우만 한 줄씩 상세 표시\n // X13 등 COMPOSITE/CUSTOM은 인라인 칩으로 간결하게\n const hasDescriptions = !is2D && grades.length > 0 && grades.some((g: any) => g.description)\n\n return html`\n <div style=\"padding: 20px;\">\n <div style=\"font-size: 1rem; font-weight: 700; margin-bottom: 16px; color: #333;\">\n 등급 기준 ${currentScore >= 1 ? html`<span style=\"color: ${colors[currentScore - 1]}; margin-left: 8px;\">현재: ${currentScore}점</span>` : ''}\n </div>\n ${hasDescriptions\n ? items.map(\n item => html`\n <div\n style=\"\n display: flex; align-items: center; gap: 10px;\n padding: 10px 14px; margin-bottom: 6px;\n border-radius: 8px;\n background: ${item.active ? item.color + '18' : '#f9f9f9'};\n border: 2px solid ${item.active ? item.color : 'transparent'};\n transition: all 0.2s;\n \"\n >\n <span\n style=\"\n width: 32px; height: 32px; border-radius: 50%;\n background: ${item.active ? item.color : '#e0e0e0'};\n color: ${item.active ? '#fff' : '#999'};\n display: flex; align-items: center; justify-content: center;\n font-weight: 700; font-size: 14px; flex-shrink: 0;\n \"\n >${item.score}</span>\n <span style=\"font-size: 0.9rem; color: ${item.active ? '#333' : '#666'}; font-weight: ${item.active ? '600' : '400'};\">\n ${item.desc}\n </span>\n </div>`\n )\n : html`\n <div style=\"display: flex; gap: 6px; flex-wrap: wrap;\">\n ${items.map(\n item => html`\n <span style=\"\n display: inline-flex; align-items: center; justify-content: center;\n width: 36px; height: 36px; border-radius: 50%;\n background: ${item.active ? item.color : '#e0e0e0'};\n color: ${item.active ? '#fff' : '#999'};\n font-weight: 700; font-size: 14px;\n border: 2px solid ${item.active ? item.color : 'transparent'};\n \">${item.score}</span>`\n )}\n </div>\n `}\n\n ${is2D && kpi?.grades?.rows\n ? html`\n <div style=\"margin-top: 20px; border-top: 1px solid #e0e0e0; padding-top: 16px;\">\n <div style=\"font-size: 0.9rem; font-weight: 700; color: #333; margin-bottom: 8px;\">\n 공정률 × 공기편차 성과 분포\n </div>\n <div style=\"height: 250px;\">\n <kpi-2d-lookup-chart\n .grades=${kpi.grades}\n .progressRate=${this.project?.totalProgress ?? 50}\n ></kpi-2d-lookup-chart>\n </div>\n </div>\n `\n : ''}\n </div>\n `\n }\n\n private _closePopup() {\n this.showScoreDistribution = false\n this.selectedKpi = null\n }\n\n private getMetricValue(kpiNamePattern: string): string {\n const kpiValue = this.projectXKpiValues.find(kv => kv.kpi?.name && kv.kpi.name.includes(kpiNamePattern))\n const value = kpiValue?.value || 0\n\n // 정수면 그대로, 소수면 최대 3자리까지만 표시\n if (Number.isInteger(value)) {\n return value.toString()\n } else {\n return value.toFixed(3).replace(/\\.?0+$/, '')\n }\n }\n\n private getYKpiScoreFormatted(kpiName: string): string {\n const value = this.getProjectYKpiValue(kpiName)\n if (value === 0) return '-'\n return (value * 100).toFixed(1)\n }\n\n private getMetricGroups() {\n return {\n Y1: {\n name: '일정성과 (Y1)',\n score: this.getYKpiScoreFormatted('Y1. 일정성과'),\n metrics: [\n { label: '연면적 대비 공사기간', pattern: 'X11', value: this.getMetricValue('X11') },\n { label: '설계변경 공기 증감률', pattern: 'X12', value: this.getMetricValue('X12') },\n { label: '일정 이탈 수준', pattern: 'X13', value: this.getMetricValue('X13') },\n { label: '일정성과 수준 평가', pattern: 'X14', value: this.getMetricValue('X14') }\n ]\n },\n Y2: {\n name: '비용성과 (Y2)',\n score: this.getYKpiScoreFormatted('Y2. 비용성과'),\n metrics: [\n { label: '연면적 대비 공사비', pattern: 'X21', value: this.getMetricValue('X21') },\n { label: '설계변경 공사비 증감', pattern: 'X22', value: this.getMetricValue('X22') },\n { label: '일정성과 수준 평가', pattern: 'X23', value: this.getMetricValue('X23') }\n ]\n },\n Y3: {\n name: '품질성과 (Y3)',\n score: this.getYKpiScoreFormatted('Y3. 품질성과'),\n metrics: [\n { label: '검측 불합격률', pattern: 'X33', value: this.getMetricValue('X33') },\n { label: '품질 SL-PA 결과', pattern: 'X34', value: this.getMetricValue('X34') },\n { label: '품질성과 수준 평가', pattern: 'X35', value: this.getMetricValue('X35') }\n ]\n },\n Y4: {\n name: '안전성과 (Y4)',\n score: this.getYKpiScoreFormatted('Y4. 안전성과'),\n metrics: [\n { label: '재해율', pattern: 'X41', value: this.getMetricValue('X41') },\n { label: '재해강도율', pattern: 'X42', value: this.getMetricValue('X42') },\n { label: '안전 SL-PA 결과', pattern: 'X43', value: this.getMetricValue('X43') },\n { label: '안전성과 수준 평가', pattern: 'X44', value: this.getMetricValue('X44') }\n ]\n },\n Y5: {\n name: '환경성과 (Y5)',\n score: this.getYKpiScoreFormatted('Y5. 환경성과'),\n metrics: [\n { label: '건설폐기물 발생량', pattern: 'X51', value: this.getMetricValue('X51') },\n { label: '환경성과 수준 평가', pattern: 'X52', value: this.getMetricValue('X52') }\n ]\n },\n Y6: {\n name: '생산성 성과 (Y6)',\n score: this.getYKpiScoreFormatted('Y6. 생산성성과'),\n metrics: [\n { label: '투입인력 생산성', pattern: 'X61', value: this.getMetricValue('X61') },\n { label: '생산성성과 수준 평가', pattern: 'X62', value: this.getMetricValue('X62') }\n ]\n }\n }\n }\n\n private getYKpiBoxplotData() {\n // KPI 카테고리 매핑 (Y-category KPI names to display categories)\n const categoryMapping: Record<string, string> = {\n Y01_productivity: '생산성과',\n Y02_schedule: '일정성과',\n Y03_cost: '비용성과',\n Y04_quality: '품질성과',\n Y05_safety: '안전성과',\n Y06_environment: '환경성과'\n }\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\n // Y-KPI 카테고리별로 통합된 통계 생성\n this.kpiYComprehensiveStats.forEach(stat => {\n const category = categoryMapping[stat.kpiName] || stat.kpiName\n\n data.push({\n org: category, // org 필드 사용 (boxplot 차트가 기대하는 필드명)\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: this.getProjectYKpiValue(stat.kpiName) * 100 // 현재 프로젝트의 실제 Y-KPI 값 (0~1 → 0~20)\n })\n })\n\n return data.sort((a, b) => a.org.localeCompare(b.org))\n }\n\n private getProjectYKpiValue(kpiName: string): number {\n // 현재 프로젝트의 kpiValues 배열에서 해당 KPI 값을 찾습니다\n const kpiValue = this.project?.kpiValues?.find(kv => kv.kpiName === kpiName)\n return kpiValue?.value || 0\n }\n\n private getRadarChartData() {\n // KPI 카테고리 매핑 (Y-category KPI names to display categories)\n const categoryMapping: Record<string, string> = {\n Y01_productivity: '생산성',\n Y02_schedule: '일정',\n Y03_cost: '비용',\n Y04_quality: '품질',\n Y05_safety: '안전',\n Y06_environment: '환경'\n }\n\n const data: Array<{ org: string; category: string; value: number }> = []\n const categories: string[] = []\n\n // Create baseline data from comprehensive stats (using avgVal as baseline)\n this.kpiYComprehensiveStats.forEach(stat => {\n const category = categoryMapping[stat.kpiName] || stat.kpiName\n if (!categories.includes(category)) {\n categories.push(category)\n }\n\n // Add baseline average\n data.push({\n org: '기준평균',\n category,\n value: Math.round(stat.avgVal * 100) // Scale to match expected range (0~1 → 0~20)\n })\n\n // Add current project performance (using project's individual values)\n data.push({\n org: '프로젝트성과',\n category,\n value: Math.round(this.getProjectYKpiValue(stat.kpiName) * 100) // Y-KPI 값 (0~1 → 0~20)\n })\n })\n\n return {\n data,\n categories:\n categories.length > 0\n ? categories\n : ['Y1. 일정성과', 'Y2. 비용성과', 'Y3. 품질성과', 'Y4. 안전성과', 'Y5. 환경성과', 'Y6. 생산성성과']\n }\n }\n\n private getBoxPlotDataForProject(project: Project) {\n // 프로젝트의 지역(geo_group)에 해당하는 통계 찾기\n const stats = this.kpiComprehensiveStats?.[0]\n\n if (!stats) {\n // 전체 통계의 평균값 사용 또는 기본값 반환\n const defaultStats = this.kpiComprehensiveStats.length > 0 ? this.kpiComprehensiveStats[0] : null\n if (defaultStats) {\n return {\n min: defaultStats.minVal,\n max: defaultStats.maxVal,\n mean: (defaultStats.q1Val + defaultStats.q3Val) / 2,\n median: defaultStats.medVal,\n q1: defaultStats.q1Val,\n q3: defaultStats.q3Val,\n value: project.kpi || 0\n }\n }\n\n // 완전한 기본값\n return {\n min: 0,\n max: 100,\n mean: 50,\n median: 50,\n q1: 25,\n q3: 75,\n value: project.kpi || 0\n }\n }\n\n return {\n min: stats.minVal * 100,\n max: stats.maxVal * 100,\n mean: ((stats.q1Val + stats.q3Val) / 2) * 100, // 대략적 평균값\n median: stats.medVal * 100,\n q1: stats.q1Val * 100,\n q3: stats.q3Val * 100,\n value: project.kpi || 0\n }\n }\n}\n"]}
|
|
@@ -103,7 +103,7 @@ let SvProjectListPage = class SvProjectListPage extends ScopedElementsMixin(Page
|
|
|
103
103
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
104
104
|
const areaText = `연면적 : ${((_b = (_a = project === null || project === void 0 ? void 0 : project.buildingComplex) === null || _a === void 0 ? void 0 : _a.area) === null || _b === void 0 ? void 0 : _b.toLocaleString()) || '-'} ㎡`;
|
|
105
105
|
const costText = `공사비 : ${((_d = (_c = project === null || project === void 0 ? void 0 : project.buildingComplex) === null || _c === void 0 ? void 0 : _c.constructionCost) === null || _d === void 0 ? void 0 : _d.toLocaleString()) || '-'} 억원`;
|
|
106
|
-
const
|
|
106
|
+
const workerCountText = `투입인력 : ${((_f = (_e = project === null || project === void 0 ? void 0 : project.buildingComplex) === null || _e === void 0 ? void 0 : _e.workerCount) === null || _f === void 0 ? void 0 : _f.toLocaleString()) || '-'} M/M`;
|
|
107
107
|
return html `
|
|
108
108
|
<div tr @click=${() => navigate(`project-detail/${project.id}`)}>
|
|
109
109
|
<div td-pics>
|
|
@@ -115,7 +115,7 @@ let SvProjectListPage = class SvProjectListPage extends ScopedElementsMixin(Page
|
|
|
115
115
|
<div class="sub">주소 : ${((_h = project.buildingComplex) === null || _h === void 0 ? void 0 : _h.address) || ''}</div>
|
|
116
116
|
<div class="sub">착공~준공 : ${project.startDate} ~ ${project.endDate}</div>
|
|
117
117
|
</div>
|
|
118
|
-
<div td-etc>${areaText + '\n' + costText + '\n' +
|
|
118
|
+
<div td-etc>${areaText + '\n' + costText + '\n' + workerCountText}</div>
|
|
119
119
|
<div td-request>KPI입력 요청 ${(_j = this.pendingCounts[project.id]) !== null && _j !== void 0 ? _j : '-'}건</div>
|
|
120
120
|
<div td-kpi>
|
|
121
121
|
<kpi-single-boxplot-chart .data=${this.getBoxPlotDataForProject(project)}></kpi-single-boxplot-chart>
|
|
@@ -167,7 +167,7 @@ let SvProjectListPage = class SvProjectListPage extends ScopedElementsMixin(Page
|
|
|
167
167
|
area
|
|
168
168
|
clientCompany
|
|
169
169
|
constructionCost
|
|
170
|
-
|
|
170
|
+
workerCount
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
173
|
total
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sv-project-list.js","sourceRoot":"","sources":["../../client/pages/sv-project-list.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '../components/kpi-single-boxplot-chart'\n\nimport { navigate, PageView } from '@operato/shell'\nimport { css, html } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\nimport { client } from '@operato/graphql'\nimport { openPopup } from '@operato/layout'\nimport gql from 'graphql-tag'\nimport { Attachment } from '@things-factory/attachment-base'\nimport type { FileUpload } from 'graphql-upload/GraphQLUpload.js'\nimport '../components/sv-pagenation-control'\nimport '@dssp/project/dist-client/pages/project/popup/popup-project-create'\nimport { tenantHeaders } from '@dssp/project/dist-client/shared/domain-context'\nimport moment from 'moment-timezone'\n\nexport enum ProjectState {\n 'ONGOING' = '10',\n 'COMPLETED' = '20'\n}\nexport const PROJECT_STATE = {\n [ProjectState.ONGOING]: '진행중',\n [ProjectState.COMPLETED]: '완료'\n}\nexport enum BuildingInspectionStatus {\n WAIT = 'WAIT',\n OVERALL_WAIT = 'OVERALL_WAIT',\n REQUEST = 'REQUEST',\n OVERALL_REQUEST = 'OVERALL_REQUEST',\n PASS = 'PASS',\n FAIL = 'FAIL'\n}\nexport const BUILDING_INSPECTION_STATUS = {\n [BuildingInspectionStatus.WAIT]: '작업 완료',\n [BuildingInspectionStatus.OVERALL_WAIT]: '작업 완료',\n [BuildingInspectionStatus.REQUEST]: '감리 대기',\n [BuildingInspectionStatus.OVERALL_REQUEST]: '감리 대기',\n [BuildingInspectionStatus.PASS]: '검측 완료',\n [BuildingInspectionStatus.FAIL]: '조치 필요'\n}\n\nexport enum ProjectType {\n DSSP = 'DSSP',\n DCSP = 'DCSP',\n DKPI = 'DKPI'\n}\nexport interface KpiValuesObject {\n kpiName: string\n value: number\n}\nexport interface Project {\n id?: string\n name: string\n state: ProjectState\n startDate?: string\n endDate?: string\n mainPhoto?: Attachment\n mainPhotoUpload?: FileUpload\n totalProgress?: number\n weeklyProgress?: number\n kpi?: number\n kpiValues?: KpiValuesObject[]\n inspPassRate?: number\n robotProgressRate?: number\n structuralSafetyRate?: number\n robotCount?: number\n scheduleTable?: Attachment\n buildingComplex: BuildingComplex\n projectType?: ProjectType\n}\nexport interface BuildingComplex {\n id?: string\n address?: string\n latitude?: number\n longitude?: number\n area?: number\n constructionCompany?: string\n clientCompany?: string\n designCompany?: string\n supervisoryCompany?: string\n drawing?: Attachment\n drawingUpload?: FileUpload\n constructionType?: string\n constructionCost?: number\n etc?: string\n householdCount?: number\n buildingCount?: number\n notice?: string\n planXScale?: number\n planYScale?: number\n overallConstructorEmails?: string[]\n taskConstructorEmails?: string[]\n overallSupervisoryEmails?: string[]\n taskSupervisoryEmails?: string[]\n buildings?: Building[]\n}\nexport interface Building {\n id?: string\n name: string | undefined\n floorCount: number | undefined\n hasBasement?: boolean\n basementFloorCount?: number\n drawing?: Attachment\n drawingUpload?: FileUpload\n buildingLevels?: BuildingLevel[]\n}\n\nexport interface BuildingLevel {\n id?: string\n floor?: number\n floorDisplayName?: string\n mainDrawing?: Attachment\n mainDrawingImage?: string\n mainDrawingThumbnail?: string\n mainDrawingUpload?: FileUpload\n elevationDrawing?: Attachment\n elevationDrawingThumbnail?: string\n elevationDrawingUpload?: FileUpload\n rebarDistributionDrawing?: Attachment\n rebarDistributionDrawingThumbnail?: string\n rebarDistributionDrawingUpload?: FileUpload\n etcDrawings?: Attachment[]\n etcDrawingsUpload?: FileUpload[]\n building?: Building\n buildingInspections?: BuildingInspection[]\n}\n\nexport interface BuildingInspection {\n id?: string\n attatchments?: Attachment[]\n // buildingInspectionAttachments?: BuildingInspectionAttachment[]\n status?: BuildingInspectionStatus\n requestDate?: Date\n buildingLevel?: BuildingLevel\n checklist?: Checklist\n createdAt?: Date\n updatedAt?: Date\n deletedAt?: Date\n}\n\nexport interface Checklist {\n id: string\n name?: string\n documentNo?: string\n constructionType?: string\n constructionDetailType?: string\n location?: string\n constructionInspectorDate?: Date\n supervisorInspectorDate?: Date\n overallConstructorSignature?: string\n taskConstructorSignature?: string\n overallSupervisorySignature?: string\n taskSupervisorySignature?: string\n inspectionParts?: string[]\n // checklistItems?: ChecklistItem[]\n}\n\n@customElement('sv-project-list')\nexport class SvProjectListPage extends ScopedElementsMixin(PageView) {\n static styles = [\n css`\n :host {\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n\n width: 100%;\n height: 100%;\n background-color: var(--md-sys-color-background, #f6f6f6);\n\n --grid-record-emphasized-background-color: red;\n --grid-record-emphasized-color: yellow;\n }\n\n /* Material Symbols Outlined (stroke style) */\n md-icon {\n font-variation-settings:\n 'FILL' 0,\n 'wght' 400,\n 'GRAD' 0,\n 'opsz' 24;\n }\n\n /* Search bar (Figma: content > search bar) */\n div[header] {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: var(--spacing-large, 12px);\n margin-bottom: 0;\n padding: 12px 11px;\n border-radius: 7px;\n background-color: rgba(46, 164, 223, 0.1);\n border: 1px solid rgba(46, 164, 223, 0.3);\n }\n div[header] div[search] {\n display: flex;\n align-items: center;\n gap: 6px;\n min-width: 186px;\n }\n div[header] div[search] md-icon {\n color: #212529;\n }\n div[header] div[search] input[type='search'] {\n border: none;\n outline: none;\n background: transparent;\n font-size: 16px;\n color: #212529;\n padding: 2px 0;\n border-bottom: 1px solid rgba(0, 0, 0, 0.2);\n }\n div[header] .spacer {\n flex: 1;\n }\n div[header] div[count] {\n font-size: 16px;\n color: #000000;\n margin-right: 6px;\n }\n div[header] md-icon[view] {\n color: #35618e;\n cursor: pointer;\n }\n div[header] md-icon[add] {\n color: #4cbb49;\n cursor: pointer;\n }\n div[header] button[add-project] {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 8px 12px;\n background-color: #24be7b;\n color: white;\n border: none;\n border-radius: 7px;\n font-size: 14px;\n font-weight: bold;\n cursor: pointer;\n margin-left: 8px;\n }\n div[header] button[add-project]:hover {\n background-color: #1fa968;\n }\n div[header] button[add-project] md-icon {\n color: white;\n font-size: 18px;\n }\n\n /* Table (Figma: content > table) */\n div[table] {\n margin: var(--spacing-large, 12px);\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-top: 2px solid #0c4da2;\n border-radius: var(--md-sys-shape-corner-small, 5px);\n overflow: hidden;\n background: #ffffff;\n min-height: fit-content;\n }\n div[table-header] {\n display: grid;\n grid-template-columns: 150px 80px 1fr 220px 150px 100px;\n align-items: center;\n justify-items: center;\n height: 35px;\n background: #f3f3fa;\n padding: 0 25px;\n column-gap: 30px;\n }\n div[table-header] div[col] {\n font-size: 16px;\n color: #212529;\n line-height: 1.875em;\n }\n div[table-body] {\n display: block;\n }\n div[tr] {\n display: grid;\n grid-template-columns: 150px 80px 1fr 220px 150px 100px;\n align-items: center;\n justify-items: center;\n column-gap: 30px;\n padding: 12px 25px;\n background: #ffffff;\n border-top: 1px solid rgba(0, 0, 0, 0.15);\n cursor: pointer;\n }\n /* 좌측 정렬 요구사항 */\n div[td-info],\n div[td-etc] {\n justify-self: start;\n text-align: left;\n }\n div[td-pics] img[pic] {\n width: 150px;\n height: 90px;\n object-fit: fill;\n background: #e5e7eb;\n border-radius: 2px;\n }\n div[td-status] {\n font-weight: 700;\n font-size: 16px;\n color: #35618e;\n line-height: 1;\n }\n div[td-info] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n div[td-info] .name {\n font-weight: 700;\n font-size: 14px;\n color: #000000;\n }\n div[td-info] .sub {\n font-size: 14px;\n color: #000000;\n line-height: 1.7;\n }\n div[td-etc] {\n font-size: 16px;\n color: #212529;\n white-space: pre-line;\n }\n div[td-request] {\n font-weight: 700;\n font-size: 16px;\n color: #35618e;\n white-space: pre-line;\n }\n div[td-kpi] {\n display: flex;\n align-items: center;\n height: 100%;\n }\n div[td-kpi] .kpi-value {\n font-weight: 700;\n font-size: 22px;\n color: #35618e;\n width: 30px;\n }\n `\n ]\n\n get context() {\n return {\n title: '진행중 프로젝트'\n }\n }\n\n @state() private projectName: string = ''\n @state() private projectList: Project[] = []\n @state() private projectCount: number = 0\n @state() private currentPage: number = 1\n /** projectId → 미입력 KPI 건수 */\n @state() private pendingCounts: Record<string, number> = {}\n @state() private kpiComprehensiveStats: any[] = []\n\n private readonly pageLimit: number = 20\n\n get totalPages(): number {\n return Math.max(1, Math.ceil((this.projectCount || 0) / this.pageLimit))\n }\n\n render() {\n return html`\n <div header>\n <div search>\n <md-icon>manage_search</md-icon>\n <input\n type=\"search\"\n name=\"projectName\"\n placeholder=\"프로젝트명\"\n .value=${this.projectName}\n @input=${this._onInputChange}\n @keypress=${this._onKeypress}\n />\n </div>\n\n <span class=\"spacer\"></span>\n <div count>총 ${this.projectCount}건</div>\n\n <button add-project @click=${this._openCreateProjectPopup}>\n <md-icon>add</md-icon>\n 신규 프로젝트 생성\n </button>\n </div>\n\n <div table>\n <div table-header>\n <div col></div>\n <div col>현장상태</div>\n <div col>현장정보</div>\n <div col>기타정보</div>\n <div col>입력요청</div>\n <div col>종합KPI</div>\n </div>\n <div table-body>\n ${this.projectList?.map((project: Project) => {\n const areaText = `연면적 : ${project?.buildingComplex?.area?.toLocaleString() || '-'} ㎡`\n const costText = `공사비 : ${project?.buildingComplex?.constructionCost?.toLocaleString() || '-'} 억원`\n const householdCountText = `세대수 : ${project?.buildingComplex?.householdCount?.toLocaleString() || '-'} 세대`\n\n return html`\n <div tr @click=${() => navigate(`project-detail/${project.id}`)}>\n <div td-pics>\n <img pic src=${project.mainPhoto?.fullpath || '/assets/images/project-image.png'} alt=\"${project.name}\" />\n </div>\n <div td-status>${PROJECT_STATE[project.state]}</div>\n <div td-info>\n <div class=\"name\">${project.name}</div>\n <div class=\"sub\">주소 : ${project.buildingComplex?.address || ''}</div>\n <div class=\"sub\">착공~준공 : ${project.startDate} ~ ${project.endDate}</div>\n </div>\n <div td-etc>${areaText + '\\n' + costText + '\\n' + householdCountText}</div>\n <div td-request>KPI입력 요청 ${this.pendingCounts[project.id!] ?? '-'}건</div>\n <div td-kpi>\n <kpi-single-boxplot-chart .data=${this.getBoxPlotDataForProject(project)}></kpi-single-boxplot-chart>\n <span class=\"kpi-value\">${project.kpi?.toFixed(0) ?? '-'}</span>\n </div>\n </div>\n `\n })}\n </div>\n </div>\n <sv-pagenation-control\n .currentPage=${this.currentPage}\n .totalItems=${this.projectCount}\n .pageLimit=${this.pageLimit}\n @page-change=${(e: CustomEvent) => this._changePage(e.detail.page)}\n ></sv-pagenation-control>\n `\n }\n\n async pageUpdated(changes: any, lifecycle: any) {\n if (this.active) {\n this.getProjectList()\n this.getKpiComprehensiveStats()\n }\n }\n\n async getProjectList() {\n const response = await client.query({\n query: gql`\n query Projects($filters: [Filter!], $sortings: [Sorting!], $pagination: Pagination) {\n projects(filters: $filters, sortings: $sortings, pagination: $pagination) {\n items {\n id\n code\n name\n state\n startDate\n endDate\n mainPhoto {\n fullpath\n }\n totalProgress\n weeklyProgress\n kpi\n inspPassRate\n robotProgressRate\n structuralSafetyRate\n buildingComplex {\n address\n area\n clientCompany\n constructionCost\n householdCount\n }\n }\n total\n }\n }\n `,\n variables: {\n filters: [\n { name: 'name', operator: 'search', value: `%${this.projectName}%` },\n { name: 'state', operator: 'eq', value: ProjectState.ONGOING }\n ],\n sortings: [{ name: 'createdAt', desc: true }],\n pagination: { page: this.currentPage, limit: this.pageLimit }\n }\n })\n\n this.projectList = response.data.projects?.items || []\n this.projectCount = response.data.projects?.total || 0\n\n // 프로젝트별 \"입력 대기 중\" 건수 비동기 로드 — 결과 도착 시 그 row 만 업데이트\n this._loadPendingCounts()\n }\n\n /**\n * 각 프로젝트의 미입력 KPI metric 건수 산정 — sv-project-detail._loadPendingMetrics 와 동일 기준.\n * - metric 정의: admin 도메인 — 헤더 없이 한 번 조회\n * - 각 프로젝트의 KpiMetricValue: 그 프로젝트 tenant 도메인 — 프로젝트별로 헤더 적용해 병렬 조회\n * 결과는 this.pendingCounts 에 캐시, 렌더에서 표시.\n */\n private async _loadPendingCounts() {\n const projects = this.projectList || []\n if (projects.length === 0) return\n\n try {\n // 1) 사용자 직접 입력 대상 metric 만 (admin 도메인 한 번 조회)\n const metricsResp = await client.query({\n query: gql`\n query KpiMetrics {\n kpiMetrics {\n items {\n id\n periodType\n collectType\n active\n }\n }\n }\n `\n })\n const targets = (metricsResp.data?.kpiMetrics?.items || []).filter(\n (m: any) => m.active && m.collectType === 'MANUAL'\n )\n if (targets.length === 0) {\n this.pendingCounts = {}\n return\n }\n\n const lastMonthYm = moment().tz('Asia/Seoul').subtract(1, 'month').format('YYYY-MM')\n const hasValid = (v: any) => v.value !== null && v.value !== undefined\n\n // 2) 프로젝트별 KpiMetricValue 병렬 조회 — 각자의 tenant 도메인 헤더 적용\n const entries = await Promise.all(\n projects.map(async (p: any) => {\n if (!p?.id) return [p?.id, 0] as [string, number]\n try {\n const valuesResp = await client.query({\n query: gql`\n query KpiMetricValues($filters: [Filter!]) {\n kpiMetricValues(filters: $filters) {\n items {\n metricId\n periodType\n valueDate\n value\n }\n }\n }\n `,\n variables: { filters: [{ name: 'org', operator: 'eq', value: p.id }] },\n context: { headers: tenantHeaders(p.code) }\n })\n const values: any[] = valuesResp.data?.kpiMetricValues?.items || []\n const pending = targets.filter((m: any) => {\n if (m.periodType === 'MONTH') {\n return !values.some(\n v =>\n v.metricId === m.id &&\n v.periodType === 'MONTH' &&\n (v.valueDate || '').startsWith(lastMonthYm) &&\n hasValid(v)\n )\n }\n return !values.some(v => v.metricId === m.id && v.periodType === m.periodType && hasValid(v))\n })\n return [p.id, pending.length] as [string, number]\n } catch {\n return [p.id, 0] as [string, number]\n }\n })\n )\n this.pendingCounts = Object.fromEntries(entries)\n } catch (e) {\n console.error('[project-list] pending count 조회 실패', e)\n this.pendingCounts = {}\n }\n }\n\n // Input 요소의 값이 변경될 때 호출되는 콜백 함수\n private _onInputChange(event: InputEvent) {\n const target = event.target as HTMLInputElement\n this[target.name] = target.value\n if (target.name === 'projectName') {\n this.currentPage = 1\n }\n }\n\n // 검색창에서 엔터입력시 검색\n private _onKeypress(event: KeyboardEvent) {\n if (event.code === 'Enter') {\n this.currentPage = 1\n this.getProjectList()\n }\n }\n\n private _changePage(page: number) {\n const nextPage = Math.min(Math.max(1, page), this.totalPages)\n if (nextPage !== this.currentPage) {\n this.currentPage = nextPage\n this.getProjectList()\n }\n }\n\n async getKpiComprehensiveStats() {\n try {\n const response = await client.query({\n query: gql`\n query GetKpiZValueComprehensiveStats {\n totalKpiZValueComprehensiveStats {\n minVal\n q1Val\n medVal\n q3Val\n maxVal\n }\n }\n `\n })\n\n this.kpiComprehensiveStats = response.data.totalKpiZValueComprehensiveStats || []\n } catch (error) {\n console.error('Failed to fetch KPI comprehensive stats:', error)\n this.kpiComprehensiveStats = []\n }\n }\n\n private _openCreateProjectPopup() {\n openPopup(html`<popup-project-create .refreshFn=${this.getProjectList.bind(this)}></popup-project-create>`, {\n backdrop: true,\n size: 'small',\n title: '신규 프로젝트 생성'\n })\n }\n\n private getBoxPlotDataForProject(project: Project) {\n // 프로젝트의 지역(geo_group)에 해당하는 통계 찾기\n const stats = this.kpiComprehensiveStats?.[0]\n\n if (!stats) {\n // 전체 통계의 평균값 사용 또는 기본값 반환\n const defaultStats = this.kpiComprehensiveStats.length > 0 ? this.kpiComprehensiveStats[0] : null\n if (defaultStats) {\n return {\n min: defaultStats.minVal,\n max: defaultStats.maxVal,\n mean: (defaultStats.q1Val + defaultStats.q3Val) / 2,\n median: defaultStats.medVal,\n q1: defaultStats.q1Val,\n q3: defaultStats.q3Val,\n value: project.kpi || 0\n }\n }\n\n // 완전한 기본값\n return {\n min: 0,\n max: 100,\n mean: 50,\n median: 50,\n q1: 25,\n q3: 75,\n value: project.kpi || 0\n }\n }\n\n return {\n min: stats.minVal * 100,\n max: stats.maxVal * 100,\n mean: ((stats.q1Val + stats.q3Val) / 2) * 100, // 대략적 평균값\n median: stats.medVal * 100,\n q1: stats.q1Val * 100,\n q3: stats.q3Val * 100,\n value: project.kpi || 0\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sv-project-list.js","sourceRoot":"","sources":["../../client/pages/sv-project-list.ts"],"names":[],"mappings":";AAAA,OAAO,4BAA4B,CAAA;AACnC,OAAO,wCAAwC,CAAA;AAE/C,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AAC/B,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,GAAG,MAAM,aAAa,CAAA;AAG7B,OAAO,qCAAqC,CAAA;AAC5C,OAAO,oEAAoE,CAAA;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,iDAAiD,CAAA;AAC/E,OAAO,MAAM,MAAM,iBAAiB,CAAA;AAEpC,MAAM,CAAN,IAAY,YAGX;AAHD,WAAY,YAAY;IACtB,8BAAgB,CAAA;IAChB,gCAAkB,CAAA;AACpB,CAAC,EAHW,YAAY,KAAZ,YAAY,QAGvB;AACD,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,KAAK;IAC7B,CAAC,YAAY,CAAC,SAAS,CAAC,EAAE,IAAI;CAC/B,CAAA;AACD,MAAM,CAAN,IAAY,wBAOX;AAPD,WAAY,wBAAwB;IAClC,yCAAa,CAAA;IACb,yDAA6B,CAAA;IAC7B,+CAAmB,CAAA;IACnB,+DAAmC,CAAA;IACnC,yCAAa,CAAA;IACb,yCAAa,CAAA;AACf,CAAC,EAPW,wBAAwB,KAAxB,wBAAwB,QAOnC;AACD,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,CAAC,wBAAwB,CAAC,IAAI,CAAC,EAAE,OAAO;IACxC,CAAC,wBAAwB,CAAC,YAAY,CAAC,EAAE,OAAO;IAChD,CAAC,wBAAwB,CAAC,OAAO,CAAC,EAAE,OAAO;IAC3C,CAAC,wBAAwB,CAAC,eAAe,CAAC,EAAE,OAAO;IACnD,CAAC,wBAAwB,CAAC,IAAI,CAAC,EAAE,OAAO;IACxC,CAAC,wBAAwB,CAAC,IAAI,CAAC,EAAE,OAAO;CACzC,CAAA;AAED,MAAM,CAAN,IAAY,WAIX;AAJD,WAAY,WAAW;IACrB,4BAAa,CAAA;IACb,4BAAa,CAAA;IACb,4BAAa,CAAA;AACf,CAAC,EAJW,WAAW,KAAX,WAAW,QAItB;AAkHM,IAAM,iBAAiB,GAAvB,MAAM,iBAAkB,SAAQ,mBAAmB,CAAC,QAAQ,CAAC;IAA7D;;QAqMY,gBAAW,GAAW,EAAE,CAAA;QACxB,gBAAW,GAAc,EAAE,CAAA;QAC3B,iBAAY,GAAW,CAAC,CAAA;QACxB,gBAAW,GAAW,CAAC,CAAA;QACxC,6BAA6B;QACZ,kBAAa,GAA2B,EAAE,CAAA;QAC1C,0BAAqB,GAAU,EAAE,CAAA;QAEjC,cAAS,GAAW,EAAE,CAAA;IA0TzC,CAAC;IAxUC,IAAI,OAAO;QACT,OAAO;YACL,KAAK,EAAE,UAAU;SAClB,CAAA;IACH,CAAC;IAYD,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAA;IAC1E,CAAC;IAED,MAAM;;QACJ,OAAO,IAAI,CAAA;;;;;;;;qBAQM,IAAI,CAAC,WAAW;qBAChB,IAAI,CAAC,cAAc;wBAChB,IAAI,CAAC,WAAW;;;;;uBAKjB,IAAI,CAAC,YAAY;;qCAEH,IAAI,CAAC,uBAAuB;;;;;;;;;;;;;;;;YAgBrD,MAAA,IAAI,CAAC,WAAW,0CAAE,GAAG,CAAC,CAAC,OAAgB,EAAE,EAAE;;YAC3C,MAAM,QAAQ,GAAG,SAAS,CAAA,MAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,eAAe,0CAAE,IAAI,0CAAE,cAAc,EAAE,KAAI,GAAG,IAAI,CAAA;YACrF,MAAM,QAAQ,GAAG,SAAS,CAAA,MAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,eAAe,0CAAE,gBAAgB,0CAAE,cAAc,EAAE,KAAI,GAAG,KAAK,CAAA;YAClG,MAAM,eAAe,GAAG,UAAU,CAAA,MAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,eAAe,0CAAE,WAAW,0CAAE,cAAc,EAAE,KAAI,GAAG,MAAM,CAAA;YAEtG,OAAO,IAAI,CAAA;+BACQ,GAAG,EAAE,CAAC,QAAQ,CAAC,kBAAkB,OAAO,CAAC,EAAE,EAAE,CAAC;;iCAE5C,CAAA,MAAA,OAAO,CAAC,SAAS,0CAAE,QAAQ,KAAI,kCAAkC,SAAS,OAAO,CAAC,IAAI;;iCAEtF,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC;;sCAEvB,OAAO,CAAC,IAAI;0CACR,CAAA,MAAA,OAAO,CAAC,eAAe,0CAAE,OAAO,KAAI,EAAE;6CACnC,OAAO,CAAC,SAAS,MAAM,OAAO,CAAC,OAAO;;8BAErD,QAAQ,GAAG,IAAI,GAAG,QAAQ,GAAG,IAAI,GAAG,eAAe;2CACtC,MAAA,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,EAAG,CAAC,mCAAI,GAAG;;oDAE7B,IAAI,CAAC,wBAAwB,CAAC,OAAO,CAAC;4CAC9C,MAAA,MAAA,OAAO,CAAC,GAAG,0CAAE,OAAO,CAAC,CAAC,CAAC,mCAAI,GAAG;;;aAG7D,CAAA;QACH,CAAC,CAAC;;;;uBAIW,IAAI,CAAC,WAAW;sBACjB,IAAI,CAAC,YAAY;qBAClB,IAAI,CAAC,SAAS;uBACZ,CAAC,CAAc,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;;KAErE,CAAA;IACH,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAY,EAAE,SAAc;QAC5C,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,cAAc,EAAE,CAAA;YACrB,IAAI,CAAC,wBAAwB,EAAE,CAAA;QACjC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,cAAc;;QAClB,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;YAClC,KAAK,EAAE,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BT;YACD,SAAS,EAAE;gBACT,OAAO,EAAE;oBACP,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC,WAAW,GAAG,EAAE;oBACpE,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,CAAC,OAAO,EAAE;iBAC/D;gBACD,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;gBAC7C,UAAU,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE;aAC9D;SACF,CAAC,CAAA;QAEF,IAAI,CAAC,WAAW,GAAG,CAAA,MAAA,QAAQ,CAAC,IAAI,CAAC,QAAQ,0CAAE,KAAK,KAAI,EAAE,CAAA;QACtD,IAAI,CAAC,YAAY,GAAG,CAAA,MAAA,QAAQ,CAAC,IAAI,CAAC,QAAQ,0CAAE,KAAK,KAAI,CAAC,CAAA;QAEtD,mDAAmD;QACnD,IAAI,CAAC,kBAAkB,EAAE,CAAA;IAC3B,CAAC;IAED;;;;;OAKG;IACK,KAAK,CAAC,kBAAkB;;QAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,IAAI,EAAE,CAAA;QACvC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAM;QAEjC,IAAI,CAAC;YACH,8CAA8C;YAC9C,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;gBACrC,KAAK,EAAE,GAAG,CAAA;;;;;;;;;;;SAWT;aACF,CAAC,CAAA;YACF,MAAM,OAAO,GAAG,CAAC,CAAA,MAAA,MAAA,WAAW,CAAC,IAAI,0CAAE,UAAU,0CAAE,KAAK,KAAI,EAAE,CAAC,CAAC,MAAM,CAChE,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,WAAW,KAAK,QAAQ,CACnD,CAAA;YACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzB,IAAI,CAAC,aAAa,GAAG,EAAE,CAAA;gBACvB,OAAM;YACR,CAAC;YAED,MAAM,WAAW,GAAG,MAAM,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;YACpF,MAAM,QAAQ,GAAG,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,IAAI,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS,CAAA;YAEtE,uDAAuD;YACvD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,CAAM,EAAE,EAAE;;gBAC5B,IAAI,CAAC,CAAA,CAAC,aAAD,CAAC,uBAAD,CAAC,CAAE,EAAE,CAAA;oBAAE,OAAO,CAAC,CAAC,aAAD,CAAC,uBAAD,CAAC,CAAE,EAAE,EAAE,CAAC,CAAqB,CAAA;gBACjD,IAAI,CAAC;oBACH,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;wBACpC,KAAK,EAAE,GAAG,CAAA;;;;;;;;;;;eAWT;wBACD,SAAS,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE;wBACtE,OAAO,EAAE,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;qBAC5C,CAAC,CAAA;oBACF,MAAM,MAAM,GAAU,CAAA,MAAA,MAAA,UAAU,CAAC,IAAI,0CAAE,eAAe,0CAAE,KAAK,KAAI,EAAE,CAAA;oBACnE,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE;wBACxC,IAAI,CAAC,CAAC,UAAU,KAAK,OAAO,EAAE,CAAC;4BAC7B,OAAO,CAAC,MAAM,CAAC,IAAI,CACjB,CAAC,CAAC,EAAE,CACF,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,EAAE;gCACnB,CAAC,CAAC,UAAU,KAAK,OAAO;gCACxB,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC;gCAC3C,QAAQ,CAAC,CAAC,CAAC,CACd,CAAA;wBACH,CAAC;wBACD,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,UAAU,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;oBAC/F,CAAC,CAAC,CAAA;oBACF,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,OAAO,CAAC,MAAM,CAAqB,CAAA;gBACnD,CAAC;gBAAC,WAAM,CAAC;oBACP,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAqB,CAAA;gBACtC,CAAC;YACH,CAAC,CAAC,CACH,CAAA;YACD,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;QAClD,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,CAAC,CAAC,CAAA;YACtD,IAAI,CAAC,aAAa,GAAG,EAAE,CAAA;QACzB,CAAC;IACH,CAAC;IAED,gCAAgC;IACxB,cAAc,CAAC,KAAiB;QACtC,MAAM,MAAM,GAAG,KAAK,CAAC,MAA0B,CAAA;QAC/C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAA;QAChC,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YAClC,IAAI,CAAC,WAAW,GAAG,CAAC,CAAA;QACtB,CAAC;IACH,CAAC;IAED,iBAAiB;IACT,WAAW,CAAC,KAAoB;QACtC,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC3B,IAAI,CAAC,WAAW,GAAG,CAAC,CAAA;YACpB,IAAI,CAAC,cAAc,EAAE,CAAA;QACvB,CAAC;IACH,CAAC;IAEO,WAAW,CAAC,IAAY;QAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAA;QAC7D,IAAI,QAAQ,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;YAClC,IAAI,CAAC,WAAW,GAAG,QAAQ,CAAA;YAC3B,IAAI,CAAC,cAAc,EAAE,CAAA;QACvB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,wBAAwB;QAC5B,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;gBAClC,KAAK,EAAE,GAAG,CAAA;;;;;;;;;;SAUT;aACF,CAAC,CAAA;YAEF,IAAI,CAAC,qBAAqB,GAAG,QAAQ,CAAC,IAAI,CAAC,gCAAgC,IAAI,EAAE,CAAA;QACnF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,0CAA0C,EAAE,KAAK,CAAC,CAAA;YAChE,IAAI,CAAC,qBAAqB,GAAG,EAAE,CAAA;QACjC,CAAC;IACH,CAAC;IAEO,uBAAuB;QAC7B,SAAS,CAAC,IAAI,CAAA,oCAAoC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,0BAA0B,EAAE;YAC1G,QAAQ,EAAE,IAAI;YACd,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,YAAY;SACpB,CAAC,CAAA;IACJ,CAAC;IAEO,wBAAwB,CAAC,OAAgB;;QAC/C,kCAAkC;QAClC,MAAM,KAAK,GAAG,MAAA,IAAI,CAAC,qBAAqB,0CAAG,CAAC,CAAC,CAAA;QAE7C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,0BAA0B;YAC1B,MAAM,YAAY,GAAG,IAAI,CAAC,qBAAqB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;YACjG,IAAI,YAAY,EAAE,CAAC;gBACjB,OAAO;oBACL,GAAG,EAAE,YAAY,CAAC,MAAM;oBACxB,GAAG,EAAE,YAAY,CAAC,MAAM;oBACxB,IAAI,EAAE,CAAC,YAAY,CAAC,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC;oBACnD,MAAM,EAAE,YAAY,CAAC,MAAM;oBAC3B,EAAE,EAAE,YAAY,CAAC,KAAK;oBACtB,EAAE,EAAE,YAAY,CAAC,KAAK;oBACtB,KAAK,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;iBACxB,CAAA;YACH,CAAC;YAED,UAAU;YACV,OAAO;gBACL,GAAG,EAAE,CAAC;gBACN,GAAG,EAAE,GAAG;gBACR,IAAI,EAAE,EAAE;gBACR,MAAM,EAAE,EAAE;gBACV,EAAE,EAAE,EAAE;gBACN,EAAE,EAAE,EAAE;gBACN,KAAK,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;aACxB,CAAA;QACH,CAAC;QAED,OAAO;YACL,GAAG,EAAE,KAAK,CAAC,MAAM,GAAG,GAAG;YACvB,GAAG,EAAE,KAAK,CAAC,MAAM,GAAG,GAAG;YACvB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,UAAU;YACzD,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,GAAG;YAC1B,EAAE,EAAE,KAAK,CAAC,KAAK,GAAG,GAAG;YACrB,EAAE,EAAE,KAAK,CAAC,KAAK,GAAG,GAAG;YACrB,KAAK,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;SACxB,CAAA;IACH,CAAC;;AArgBM,wBAAM,GAAG;IACd,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA0LF;CACF,AA5LY,CA4LZ;AAQgB;IAAhB,KAAK,EAAE;;sDAAiC;AACxB;IAAhB,KAAK,EAAE;;sDAAoC;AAC3B;IAAhB,KAAK,EAAE;;uDAAiC;AACxB;IAAhB,KAAK,EAAE;;sDAAgC;AAEvB;IAAhB,KAAK,EAAE;;wDAAmD;AAC1C;IAAhB,KAAK,EAAE;;gEAA0C;AA3MvC,iBAAiB;IAD7B,aAAa,CAAC,iBAAiB,CAAC;GACpB,iBAAiB,CAugB7B","sourcesContent":["import '@material/web/icon/icon.js'\nimport '../components/kpi-single-boxplot-chart'\n\nimport { navigate, PageView } from '@operato/shell'\nimport { css, html } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\nimport { client } from '@operato/graphql'\nimport { openPopup } from '@operato/layout'\nimport gql from 'graphql-tag'\nimport { Attachment } from '@things-factory/attachment-base'\nimport type { FileUpload } from 'graphql-upload/GraphQLUpload.js'\nimport '../components/sv-pagenation-control'\nimport '@dssp/project/dist-client/pages/project/popup/popup-project-create'\nimport { tenantHeaders } from '@dssp/project/dist-client/shared/domain-context'\nimport moment from 'moment-timezone'\n\nexport enum ProjectState {\n 'ONGOING' = '10',\n 'COMPLETED' = '20'\n}\nexport const PROJECT_STATE = {\n [ProjectState.ONGOING]: '진행중',\n [ProjectState.COMPLETED]: '완료'\n}\nexport enum BuildingInspectionStatus {\n WAIT = 'WAIT',\n OVERALL_WAIT = 'OVERALL_WAIT',\n REQUEST = 'REQUEST',\n OVERALL_REQUEST = 'OVERALL_REQUEST',\n PASS = 'PASS',\n FAIL = 'FAIL'\n}\nexport const BUILDING_INSPECTION_STATUS = {\n [BuildingInspectionStatus.WAIT]: '작업 완료',\n [BuildingInspectionStatus.OVERALL_WAIT]: '작업 완료',\n [BuildingInspectionStatus.REQUEST]: '감리 대기',\n [BuildingInspectionStatus.OVERALL_REQUEST]: '감리 대기',\n [BuildingInspectionStatus.PASS]: '검측 완료',\n [BuildingInspectionStatus.FAIL]: '조치 필요'\n}\n\nexport enum ProjectType {\n DSSP = 'DSSP',\n DCSP = 'DCSP',\n DKPI = 'DKPI'\n}\nexport interface KpiValuesObject {\n kpiName: string\n value: number\n}\nexport interface Project {\n id?: string\n name: string\n state: ProjectState\n startDate?: string\n endDate?: string\n mainPhoto?: Attachment\n mainPhotoUpload?: FileUpload\n totalProgress?: number\n weeklyProgress?: number\n kpi?: number\n kpiValues?: KpiValuesObject[]\n inspPassRate?: number\n robotProgressRate?: number\n structuralSafetyRate?: number\n robotCount?: number\n scheduleTable?: Attachment\n buildingComplex: BuildingComplex\n projectType?: ProjectType\n}\nexport interface BuildingComplex {\n id?: string\n address?: string\n latitude?: number\n longitude?: number\n area?: number\n constructionCompany?: string\n clientCompany?: string\n designCompany?: string\n supervisoryCompany?: string\n drawing?: Attachment\n drawingUpload?: FileUpload\n constructionType?: string\n constructionCost?: number\n etc?: string\n householdCount?: number\n buildingCount?: number\n workerCount?: number\n notice?: string\n planXScale?: number\n planYScale?: number\n overallConstructorEmails?: string[]\n taskConstructorEmails?: string[]\n overallSupervisoryEmails?: string[]\n taskSupervisoryEmails?: string[]\n buildings?: Building[]\n}\nexport interface Building {\n id?: string\n name: string | undefined\n floorCount: number | undefined\n hasBasement?: boolean\n basementFloorCount?: number\n drawing?: Attachment\n drawingUpload?: FileUpload\n buildingLevels?: BuildingLevel[]\n}\n\nexport interface BuildingLevel {\n id?: string\n floor?: number\n floorDisplayName?: string\n mainDrawing?: Attachment\n mainDrawingImage?: string\n mainDrawingThumbnail?: string\n mainDrawingUpload?: FileUpload\n elevationDrawing?: Attachment\n elevationDrawingThumbnail?: string\n elevationDrawingUpload?: FileUpload\n rebarDistributionDrawing?: Attachment\n rebarDistributionDrawingThumbnail?: string\n rebarDistributionDrawingUpload?: FileUpload\n etcDrawings?: Attachment[]\n etcDrawingsUpload?: FileUpload[]\n building?: Building\n buildingInspections?: BuildingInspection[]\n}\n\nexport interface BuildingInspection {\n id?: string\n attatchments?: Attachment[]\n // buildingInspectionAttachments?: BuildingInspectionAttachment[]\n status?: BuildingInspectionStatus\n requestDate?: Date\n buildingLevel?: BuildingLevel\n checklist?: Checklist\n createdAt?: Date\n updatedAt?: Date\n deletedAt?: Date\n}\n\nexport interface Checklist {\n id: string\n name?: string\n documentNo?: string\n constructionType?: string\n constructionDetailType?: string\n location?: string\n constructionInspectorDate?: Date\n supervisorInspectorDate?: Date\n overallConstructorSignature?: string\n taskConstructorSignature?: string\n overallSupervisorySignature?: string\n taskSupervisorySignature?: string\n inspectionParts?: string[]\n // checklistItems?: ChecklistItem[]\n}\n\n@customElement('sv-project-list')\nexport class SvProjectListPage extends ScopedElementsMixin(PageView) {\n static styles = [\n css`\n :host {\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n\n width: 100%;\n height: 100%;\n background-color: var(--md-sys-color-background, #f6f6f6);\n\n --grid-record-emphasized-background-color: red;\n --grid-record-emphasized-color: yellow;\n }\n\n /* Material Symbols Outlined (stroke style) */\n md-icon {\n font-variation-settings:\n 'FILL' 0,\n 'wght' 400,\n 'GRAD' 0,\n 'opsz' 24;\n }\n\n /* Search bar (Figma: content > search bar) */\n div[header] {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: var(--spacing-large, 12px);\n margin-bottom: 0;\n padding: 12px 11px;\n border-radius: 7px;\n background-color: rgba(46, 164, 223, 0.1);\n border: 1px solid rgba(46, 164, 223, 0.3);\n }\n div[header] div[search] {\n display: flex;\n align-items: center;\n gap: 6px;\n min-width: 186px;\n }\n div[header] div[search] md-icon {\n color: #212529;\n }\n div[header] div[search] input[type='search'] {\n border: none;\n outline: none;\n background: transparent;\n font-size: 16px;\n color: #212529;\n padding: 2px 0;\n border-bottom: 1px solid rgba(0, 0, 0, 0.2);\n }\n div[header] .spacer {\n flex: 1;\n }\n div[header] div[count] {\n font-size: 16px;\n color: #000000;\n margin-right: 6px;\n }\n div[header] md-icon[view] {\n color: #35618e;\n cursor: pointer;\n }\n div[header] md-icon[add] {\n color: #4cbb49;\n cursor: pointer;\n }\n div[header] button[add-project] {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 8px 12px;\n background-color: #24be7b;\n color: white;\n border: none;\n border-radius: 7px;\n font-size: 14px;\n font-weight: bold;\n cursor: pointer;\n margin-left: 8px;\n }\n div[header] button[add-project]:hover {\n background-color: #1fa968;\n }\n div[header] button[add-project] md-icon {\n color: white;\n font-size: 18px;\n }\n\n /* Table (Figma: content > table) */\n div[table] {\n margin: var(--spacing-large, 12px);\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-top: 2px solid #0c4da2;\n border-radius: var(--md-sys-shape-corner-small, 5px);\n overflow: hidden;\n background: #ffffff;\n min-height: fit-content;\n }\n div[table-header] {\n display: grid;\n grid-template-columns: 150px 80px 1fr 220px 150px 100px;\n align-items: center;\n justify-items: center;\n height: 35px;\n background: #f3f3fa;\n padding: 0 25px;\n column-gap: 30px;\n }\n div[table-header] div[col] {\n font-size: 16px;\n color: #212529;\n line-height: 1.875em;\n }\n div[table-body] {\n display: block;\n }\n div[tr] {\n display: grid;\n grid-template-columns: 150px 80px 1fr 220px 150px 100px;\n align-items: center;\n justify-items: center;\n column-gap: 30px;\n padding: 12px 25px;\n background: #ffffff;\n border-top: 1px solid rgba(0, 0, 0, 0.15);\n cursor: pointer;\n }\n /* 좌측 정렬 요구사항 */\n div[td-info],\n div[td-etc] {\n justify-self: start;\n text-align: left;\n }\n div[td-pics] img[pic] {\n width: 150px;\n height: 90px;\n object-fit: fill;\n background: #e5e7eb;\n border-radius: 2px;\n }\n div[td-status] {\n font-weight: 700;\n font-size: 16px;\n color: #35618e;\n line-height: 1;\n }\n div[td-info] {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n div[td-info] .name {\n font-weight: 700;\n font-size: 14px;\n color: #000000;\n }\n div[td-info] .sub {\n font-size: 14px;\n color: #000000;\n line-height: 1.7;\n }\n div[td-etc] {\n font-size: 16px;\n color: #212529;\n white-space: pre-line;\n }\n div[td-request] {\n font-weight: 700;\n font-size: 16px;\n color: #35618e;\n white-space: pre-line;\n }\n div[td-kpi] {\n display: flex;\n align-items: center;\n height: 100%;\n }\n div[td-kpi] .kpi-value {\n font-weight: 700;\n font-size: 22px;\n color: #35618e;\n width: 30px;\n }\n `\n ]\n\n get context() {\n return {\n title: '진행중 프로젝트'\n }\n }\n\n @state() private projectName: string = ''\n @state() private projectList: Project[] = []\n @state() private projectCount: number = 0\n @state() private currentPage: number = 1\n /** projectId → 미입력 KPI 건수 */\n @state() private pendingCounts: Record<string, number> = {}\n @state() private kpiComprehensiveStats: any[] = []\n\n private readonly pageLimit: number = 20\n\n get totalPages(): number {\n return Math.max(1, Math.ceil((this.projectCount || 0) / this.pageLimit))\n }\n\n render() {\n return html`\n <div header>\n <div search>\n <md-icon>manage_search</md-icon>\n <input\n type=\"search\"\n name=\"projectName\"\n placeholder=\"프로젝트명\"\n .value=${this.projectName}\n @input=${this._onInputChange}\n @keypress=${this._onKeypress}\n />\n </div>\n\n <span class=\"spacer\"></span>\n <div count>총 ${this.projectCount}건</div>\n\n <button add-project @click=${this._openCreateProjectPopup}>\n <md-icon>add</md-icon>\n 신규 프로젝트 생성\n </button>\n </div>\n\n <div table>\n <div table-header>\n <div col></div>\n <div col>현장상태</div>\n <div col>현장정보</div>\n <div col>기타정보</div>\n <div col>입력요청</div>\n <div col>종합KPI</div>\n </div>\n <div table-body>\n ${this.projectList?.map((project: Project) => {\n const areaText = `연면적 : ${project?.buildingComplex?.area?.toLocaleString() || '-'} ㎡`\n const costText = `공사비 : ${project?.buildingComplex?.constructionCost?.toLocaleString() || '-'} 억원`\n const workerCountText = `투입인력 : ${project?.buildingComplex?.workerCount?.toLocaleString() || '-'} M/M`\n\n return html`\n <div tr @click=${() => navigate(`project-detail/${project.id}`)}>\n <div td-pics>\n <img pic src=${project.mainPhoto?.fullpath || '/assets/images/project-image.png'} alt=\"${project.name}\" />\n </div>\n <div td-status>${PROJECT_STATE[project.state]}</div>\n <div td-info>\n <div class=\"name\">${project.name}</div>\n <div class=\"sub\">주소 : ${project.buildingComplex?.address || ''}</div>\n <div class=\"sub\">착공~준공 : ${project.startDate} ~ ${project.endDate}</div>\n </div>\n <div td-etc>${areaText + '\\n' + costText + '\\n' + workerCountText}</div>\n <div td-request>KPI입력 요청 ${this.pendingCounts[project.id!] ?? '-'}건</div>\n <div td-kpi>\n <kpi-single-boxplot-chart .data=${this.getBoxPlotDataForProject(project)}></kpi-single-boxplot-chart>\n <span class=\"kpi-value\">${project.kpi?.toFixed(0) ?? '-'}</span>\n </div>\n </div>\n `\n })}\n </div>\n </div>\n <sv-pagenation-control\n .currentPage=${this.currentPage}\n .totalItems=${this.projectCount}\n .pageLimit=${this.pageLimit}\n @page-change=${(e: CustomEvent) => this._changePage(e.detail.page)}\n ></sv-pagenation-control>\n `\n }\n\n async pageUpdated(changes: any, lifecycle: any) {\n if (this.active) {\n this.getProjectList()\n this.getKpiComprehensiveStats()\n }\n }\n\n async getProjectList() {\n const response = await client.query({\n query: gql`\n query Projects($filters: [Filter!], $sortings: [Sorting!], $pagination: Pagination) {\n projects(filters: $filters, sortings: $sortings, pagination: $pagination) {\n items {\n id\n code\n name\n state\n startDate\n endDate\n mainPhoto {\n fullpath\n }\n totalProgress\n weeklyProgress\n kpi\n inspPassRate\n robotProgressRate\n structuralSafetyRate\n buildingComplex {\n address\n area\n clientCompany\n constructionCost\n workerCount\n }\n }\n total\n }\n }\n `,\n variables: {\n filters: [\n { name: 'name', operator: 'search', value: `%${this.projectName}%` },\n { name: 'state', operator: 'eq', value: ProjectState.ONGOING }\n ],\n sortings: [{ name: 'createdAt', desc: true }],\n pagination: { page: this.currentPage, limit: this.pageLimit }\n }\n })\n\n this.projectList = response.data.projects?.items || []\n this.projectCount = response.data.projects?.total || 0\n\n // 프로젝트별 \"입력 대기 중\" 건수 비동기 로드 — 결과 도착 시 그 row 만 업데이트\n this._loadPendingCounts()\n }\n\n /**\n * 각 프로젝트의 미입력 KPI metric 건수 산정 — sv-project-detail._loadPendingMetrics 와 동일 기준.\n * - metric 정의: admin 도메인 — 헤더 없이 한 번 조회\n * - 각 프로젝트의 KpiMetricValue: 그 프로젝트 tenant 도메인 — 프로젝트별로 헤더 적용해 병렬 조회\n * 결과는 this.pendingCounts 에 캐시, 렌더에서 표시.\n */\n private async _loadPendingCounts() {\n const projects = this.projectList || []\n if (projects.length === 0) return\n\n try {\n // 1) 사용자 직접 입력 대상 metric 만 (admin 도메인 한 번 조회)\n const metricsResp = await client.query({\n query: gql`\n query KpiMetrics {\n kpiMetrics {\n items {\n id\n periodType\n collectType\n active\n }\n }\n }\n `\n })\n const targets = (metricsResp.data?.kpiMetrics?.items || []).filter(\n (m: any) => m.active && m.collectType === 'MANUAL'\n )\n if (targets.length === 0) {\n this.pendingCounts = {}\n return\n }\n\n const lastMonthYm = moment().tz('Asia/Seoul').subtract(1, 'month').format('YYYY-MM')\n const hasValid = (v: any) => v.value !== null && v.value !== undefined\n\n // 2) 프로젝트별 KpiMetricValue 병렬 조회 — 각자의 tenant 도메인 헤더 적용\n const entries = await Promise.all(\n projects.map(async (p: any) => {\n if (!p?.id) return [p?.id, 0] as [string, number]\n try {\n const valuesResp = await client.query({\n query: gql`\n query KpiMetricValues($filters: [Filter!]) {\n kpiMetricValues(filters: $filters) {\n items {\n metricId\n periodType\n valueDate\n value\n }\n }\n }\n `,\n variables: { filters: [{ name: 'org', operator: 'eq', value: p.id }] },\n context: { headers: tenantHeaders(p.code) }\n })\n const values: any[] = valuesResp.data?.kpiMetricValues?.items || []\n const pending = targets.filter((m: any) => {\n if (m.periodType === 'MONTH') {\n return !values.some(\n v =>\n v.metricId === m.id &&\n v.periodType === 'MONTH' &&\n (v.valueDate || '').startsWith(lastMonthYm) &&\n hasValid(v)\n )\n }\n return !values.some(v => v.metricId === m.id && v.periodType === m.periodType && hasValid(v))\n })\n return [p.id, pending.length] as [string, number]\n } catch {\n return [p.id, 0] as [string, number]\n }\n })\n )\n this.pendingCounts = Object.fromEntries(entries)\n } catch (e) {\n console.error('[project-list] pending count 조회 실패', e)\n this.pendingCounts = {}\n }\n }\n\n // Input 요소의 값이 변경될 때 호출되는 콜백 함수\n private _onInputChange(event: InputEvent) {\n const target = event.target as HTMLInputElement\n this[target.name] = target.value\n if (target.name === 'projectName') {\n this.currentPage = 1\n }\n }\n\n // 검색창에서 엔터입력시 검색\n private _onKeypress(event: KeyboardEvent) {\n if (event.code === 'Enter') {\n this.currentPage = 1\n this.getProjectList()\n }\n }\n\n private _changePage(page: number) {\n const nextPage = Math.min(Math.max(1, page), this.totalPages)\n if (nextPage !== this.currentPage) {\n this.currentPage = nextPage\n this.getProjectList()\n }\n }\n\n async getKpiComprehensiveStats() {\n try {\n const response = await client.query({\n query: gql`\n query GetKpiZValueComprehensiveStats {\n totalKpiZValueComprehensiveStats {\n minVal\n q1Val\n medVal\n q3Val\n maxVal\n }\n }\n `\n })\n\n this.kpiComprehensiveStats = response.data.totalKpiZValueComprehensiveStats || []\n } catch (error) {\n console.error('Failed to fetch KPI comprehensive stats:', error)\n this.kpiComprehensiveStats = []\n }\n }\n\n private _openCreateProjectPopup() {\n openPopup(html`<popup-project-create .refreshFn=${this.getProjectList.bind(this)}></popup-project-create>`, {\n backdrop: true,\n size: 'small',\n title: '신규 프로젝트 생성'\n })\n }\n\n private getBoxPlotDataForProject(project: Project) {\n // 프로젝트의 지역(geo_group)에 해당하는 통계 찾기\n const stats = this.kpiComprehensiveStats?.[0]\n\n if (!stats) {\n // 전체 통계의 평균값 사용 또는 기본값 반환\n const defaultStats = this.kpiComprehensiveStats.length > 0 ? this.kpiComprehensiveStats[0] : null\n if (defaultStats) {\n return {\n min: defaultStats.minVal,\n max: defaultStats.maxVal,\n mean: (defaultStats.q1Val + defaultStats.q3Val) / 2,\n median: defaultStats.medVal,\n q1: defaultStats.q1Val,\n q3: defaultStats.q3Val,\n value: project.kpi || 0\n }\n }\n\n // 완전한 기본값\n return {\n min: 0,\n max: 100,\n mean: 50,\n median: 50,\n q1: 25,\n q3: 75,\n value: project.kpi || 0\n }\n }\n\n return {\n min: stats.minVal * 100,\n max: stats.maxVal * 100,\n mean: ((stats.q1Val + stats.q3Val) / 2) * 100, // 대략적 평균값\n median: stats.medVal * 100,\n q1: stats.q1Val * 100,\n q3: stats.q3Val * 100,\n value: project.kpi || 0\n }\n }\n}\n"]}
|
|
@@ -78,6 +78,11 @@ export declare class SvProjectUpdate extends SvProjectUpdate_base {
|
|
|
78
78
|
private _promoteTenant;
|
|
79
79
|
private _demoteTenant;
|
|
80
80
|
private _setBuilding;
|
|
81
|
+
/**
|
|
82
|
+
* 우편번호 입력 핸들러 — postalCode 갱신과 동시에 앞 2자리 prefix 로 geoGroup
|
|
83
|
+
* best-guess 자동 매핑. 매핑 안 되면 기존 값 유지.
|
|
84
|
+
*/
|
|
85
|
+
private _onPostalCodeChange;
|
|
81
86
|
private _onInputChange;
|
|
82
87
|
onCreateAttachment(e: CustomEvent): Promise<void>;
|
|
83
88
|
private _handleSelectionChange;
|