@dssp/dkpi 1.0.0-alpha.80 → 1.0.0-alpha.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-client/bootstrap.d.ts +1 -0
- package/dist-client/bootstrap.js +11 -0
- package/dist-client/bootstrap.js.map +1 -1
- package/dist-client/components/kpi-single-boxplot-chart.d.ts +3 -2
- package/dist-client/components/kpi-single-boxplot-chart.js +30 -23
- package/dist-client/components/kpi-single-boxplot-chart.js.map +1 -1
- package/dist-client/pages/component/project-update-header.d.ts +1 -0
- package/dist-client/pages/component/project-update-header.js +127 -0
- package/dist-client/pages/component/project-update-header.js.map +1 -0
- 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-metric-value/kpi-metric-value-list-page.d.ts +1 -1
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js +1 -1
- package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js.map +1 -1
- package/dist-client/pages/kpi-value/kpi-value-list-page.js +1 -1
- package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -1
- package/dist-client/pages/project-complete-tabs/pc-tab1-plan.d.ts +21 -2
- package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js +166 -134
- package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js.map +1 -1
- package/dist-client/pages/project-complete-tabs/pc-tab2-rating.d.ts +4 -2
- package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js +109 -44
- package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js.map +1 -1
- package/dist-client/pages/project-complete-tabs/pc-tab3-upload.d.ts +3 -0
- package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js +32 -4
- package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js.map +1 -1
- package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.d.ts +24 -0
- package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.js +365 -157
- package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.js.map +1 -1
- package/dist-client/pages/sv-project-complete.d.ts +4 -1
- package/dist-client/pages/sv-project-complete.js +43 -12
- package/dist-client/pages/sv-project-complete.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.d.ts +11 -0
- package/dist-client/pages/sv-project-detail.js +188 -46
- package/dist-client/pages/sv-project-detail.js.map +1 -1
- package/dist-client/pages/sv-project-list.d.ts +10 -0
- package/dist-client/pages/sv-project-list.js +96 -6
- package/dist-client/pages/sv-project-list.js.map +1 -1
- package/dist-client/pages/sv-project-update.d.ts +86 -0
- package/dist-client/pages/sv-project-update.js +1121 -0
- package/dist-client/pages/sv-project-update.js.map +1 -0
- package/dist-client/route.d.ts +1 -1
- package/dist-client/route.js +3 -0
- package/dist-client/route.js.map +1 -1
- package/dist-client/shared/complete-api.d.ts +10 -9
- package/dist-client/shared/complete-api.js +47 -19
- package/dist-client/shared/complete-api.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/viewparts/menu-tools.js +47 -54
- package/dist-client/viewparts/menu-tools.js.map +1 -1
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.d.ts +23 -0
- package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +72 -28
- 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.js +9 -2
- package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js.map +1 -1
- package/dist-server/service/kpi-stat/kpi-stat-query.js +19 -18
- package/dist-server/service/kpi-stat/kpi-stat-query.js.map +1 -1
- package/dist-server/service/kpi-value/kpi-value-query.js +2 -2
- package/dist-server/service/kpi-value/kpi-value-query.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/schema.graphql +13 -1
- package/things-factory.config.js +1 -0
- package/dist-client/shared/domain-context.d.ts +0 -7
- package/dist-client/shared/domain-context.js +0 -13
- package/dist-client/shared/domain-context.js.map +0 -1
|
@@ -3,6 +3,7 @@ import { css, html, LitElement } from 'lit';
|
|
|
3
3
|
import { customElement, property, state } from 'lit/decorators.js';
|
|
4
4
|
import { getProject, updateProjectCompleteStep3, getKpiMetrics, getKpiMetricValues } from '../../shared/complete-api';
|
|
5
5
|
import { notify } from '@operato/layout';
|
|
6
|
+
import { hasPrivilege } from '@things-factory/auth-base/dist-client';
|
|
6
7
|
let SvProjectCompleteTab3Upload = class SvProjectCompleteTab3Upload extends LitElement {
|
|
7
8
|
constructor() {
|
|
8
9
|
super(...arguments);
|
|
@@ -10,6 +11,17 @@ let SvProjectCompleteTab3Upload = class SvProjectCompleteTab3Upload extends LitE
|
|
|
10
11
|
this.attachment = {};
|
|
11
12
|
this.pendingFile = null;
|
|
12
13
|
this.slpaData = [];
|
|
14
|
+
/** kpi:sentiment — Step3 보고서 첨부/저장 권한 */
|
|
15
|
+
this.canSave = false;
|
|
16
|
+
}
|
|
17
|
+
async connectedCallback() {
|
|
18
|
+
super.connectedCallback();
|
|
19
|
+
this.canSave = await hasPrivilege({
|
|
20
|
+
category: 'kpi',
|
|
21
|
+
privilege: 'sentiment',
|
|
22
|
+
domainOwnerGranted: true,
|
|
23
|
+
superUserGranted: true
|
|
24
|
+
});
|
|
13
25
|
}
|
|
14
26
|
render() {
|
|
15
27
|
var _a, _b;
|
|
@@ -55,7 +67,13 @@ let SvProjectCompleteTab3Upload = class SvProjectCompleteTab3Upload extends LitE
|
|
|
55
67
|
|
|
56
68
|
<div class="button-line">
|
|
57
69
|
<div class="ghost-btn " @click=${this._reset}>초기화</div>
|
|
58
|
-
<div
|
|
70
|
+
<div
|
|
71
|
+
class="ghost-btn secondary ${this.canSave ? '' : 'disabled'}"
|
|
72
|
+
title=${this.canSave ? '' : 'kpi:sentiment 권한 필요'}
|
|
73
|
+
@click=${() => this.canSave && this._save()}
|
|
74
|
+
>
|
|
75
|
+
저장
|
|
76
|
+
</div>
|
|
59
77
|
</div>
|
|
60
78
|
</div>
|
|
61
79
|
`;
|
|
@@ -95,7 +113,8 @@ let SvProjectCompleteTab3Upload = class SvProjectCompleteTab3Upload extends LitE
|
|
|
95
113
|
}
|
|
96
114
|
}
|
|
97
115
|
async _uploadFile(file) {
|
|
98
|
-
|
|
116
|
+
var _a;
|
|
117
|
+
const response = await updateProjectCompleteStep3(file, this.project.id, (_a = this.project) === null || _a === void 0 ? void 0 : _a.code);
|
|
99
118
|
if (!response.errors) {
|
|
100
119
|
const uploaded = response.data.updateKpiMetricValuesSentiment;
|
|
101
120
|
this.attachment = uploaded;
|
|
@@ -105,13 +124,14 @@ let SvProjectCompleteTab3Upload = class SvProjectCompleteTab3Upload extends LitE
|
|
|
105
124
|
}
|
|
106
125
|
}
|
|
107
126
|
async _loadSlpaData() {
|
|
127
|
+
var _a, _b;
|
|
108
128
|
// KPI 메트릭들 가져오기
|
|
109
|
-
const kpiMetrics = await getKpiMetrics();
|
|
129
|
+
const kpiMetrics = await getKpiMetrics((_a = this.project) === null || _a === void 0 ? void 0 : _a.code);
|
|
110
130
|
// "SL-PA"가 포함된 메트릭들만 필터링
|
|
111
131
|
const slpaMetrics = kpiMetrics.filter(metric => metric.name.includes('SL-PA'));
|
|
112
132
|
if (slpaMetrics.length > 0) {
|
|
113
133
|
// 해당 프로젝트의 KPI 값들 가져오기
|
|
114
|
-
const kpiMetricValues = await getKpiMetricValues(this.project.id);
|
|
134
|
+
const kpiMetricValues = await getKpiMetricValues(this.project.id, (_b = this.project) === null || _b === void 0 ? void 0 : _b.code);
|
|
115
135
|
// SL-PA 메트릭들과 해당 값들을 매칭하여 표시용 데이터 생성
|
|
116
136
|
this.slpaData = slpaMetrics.map(metric => {
|
|
117
137
|
const metricValue = kpiMetricValues.find((item) => item.metricId === metric.id);
|
|
@@ -245,6 +265,10 @@ SvProjectCompleteTab3Upload.styles = [
|
|
|
245
265
|
.ghost-btn.secondary {
|
|
246
266
|
background: #24be7b;
|
|
247
267
|
}
|
|
268
|
+
.ghost-btn.disabled {
|
|
269
|
+
opacity: 0.45;
|
|
270
|
+
cursor: not-allowed;
|
|
271
|
+
}
|
|
248
272
|
|
|
249
273
|
.slpa-results {
|
|
250
274
|
margin-top: 20px;
|
|
@@ -300,6 +324,10 @@ __decorate([
|
|
|
300
324
|
state(),
|
|
301
325
|
__metadata("design:type", Array)
|
|
302
326
|
], SvProjectCompleteTab3Upload.prototype, "slpaData", void 0);
|
|
327
|
+
__decorate([
|
|
328
|
+
state(),
|
|
329
|
+
__metadata("design:type", Object)
|
|
330
|
+
], SvProjectCompleteTab3Upload.prototype, "canSave", void 0);
|
|
303
331
|
SvProjectCompleteTab3Upload = __decorate([
|
|
304
332
|
customElement('sv-pc-tab3-upload')
|
|
305
333
|
], SvProjectCompleteTab3Upload);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pc-tab3-upload.js","sourceRoot":"","sources":["../../../client/pages/project-complete-tabs/pc-tab3-upload.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { client } from '@operato/graphql'\nimport { gql } from '@apollo/client'\nimport { getProject, updateProjectCompleteStep3, getKpiMetrics, getKpiMetricValues } from '../../shared/complete-api'\nimport { notify } from '@operato/layout'\n\n@customElement('sv-pc-tab3-upload')\nexport class SvProjectCompleteTab3Upload extends LitElement {\n static styles = [\n css`\n :host {\n display: block;\n }\n .title {\n color: #212529;\n font-size: 13px;\n font-weight: 400;\n line-height: 24px;\n text-align: center;\n }\n\n .rows {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 8px 6px;\n }\n\n .upload-controls {\n display: flex;\n gap: 8px;\n justify-content: center;\n margin-bottom: 16px;\n\n ox-input-file {\n flex: 1;\n max-width: 500px;\n height: 210px;\n }\n }\n\n .attachment-list {\n display: flex;\n justify-content: center;\n margin-top: 8px;\n }\n\n .attachment-row {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 16px;\n padding: 24px 20px;\n border: 2px solid #e3f2fd;\n border-radius: 12px;\n background: linear-gradient(135deg, #f8fbff 0%, #e3f2fd 100%);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n min-width: 300px;\n max-width: 400px;\n }\n\n .file-icon {\n font-size: 40px;\n color: #d32f2f;\n line-height: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n width: auto;\n height: 48px;\n }\n\n .attachment-name {\n font-size: 16px;\n font-weight: 500;\n color: #1976d2;\n text-align: center;\n word-break: break-word;\n line-height: 1.4;\n }\n\n .delete-icon {\n cursor: pointer;\n color: #757575;\n background: rgba(117, 117, 117, 0.1);\n border-radius: 50%;\n padding: 8px;\n transition: all 0.2s ease;\n }\n\n .delete-icon:hover {\n color: #e57373;\n background: rgba(229, 115, 115, 0.15);\n transform: scale(1.1);\n }\n\n .button-line {\n display: flex;\n justify-content: center;\n gap: 10px;\n margin-top: 16px;\n }\n .ghost-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 10px;\n background: #35618e;\n color: #ffffff;\n border-radius: 5px;\n cursor: pointer;\n }\n .ghost-btn.secondary {\n background: #24be7b;\n }\n\n .slpa-results {\n margin-top: 20px;\n padding: 16px;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n background: #f8f9fa;\n }\n\n .slpa-title {\n font-size: 16px;\n font-weight: 600;\n color: #35618e;\n margin-bottom: 12px;\n }\n\n .slpa-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 8px 0;\n border-bottom: 1px solid #e0e0e0;\n }\n\n .slpa-item:last-child {\n border-bottom: none;\n }\n\n .slpa-label {\n font-weight: 500;\n color: #333;\n }\n\n .slpa-value {\n font-weight: 600;\n color: #1976d2;\n }\n `\n ]\n\n @property({ type: Object }) project: any = {}\n @state() attachment: any = {}\n @state() private pendingFile: File | null = null\n @state() slpaData: any[] = []\n\n render() {\n return html`\n <div class=\"title\">\n <div>\n 감리 최종 감리보고서의 종합의견서(PDF 형식)를 시스템에 업로드해 주세요.\n <br />\n 보고서에 포함된 텍스트와 평가 내용을 기반으로 기계 판독 및 AI 기반 프로젝트 평가가 자동으로 진행되므로, 반드시 최종\n 확정된 원본 파일을 제출해 주시기 바랍니다.\n </div>\n </div>\n\n <div class=\"rows\">\n ${this._getCurrentFile()\n ? html`\n <div class=\"attachment-list\">\n <div class=\"attachment-row\">\n <md-icon class=\"file-icon\">picture_as_pdf</md-icon>\n <div class=\"attachment-name\" title=\"${this._getCurrentFile()?.name}\">${this._getCurrentFile()?.name}</div>\n <md-icon class=\"delete-icon\" @click=${this._removeFile}>delete</md-icon>\n </div>\n </div>\n `\n : html`\n <div class=\"upload-controls\">\n <ox-input-file accept=\"application/pdf,.pdf\" hide-filelist @change=${this._onFileSelect}> </ox-input-file>\n </div>\n `}\n ${this.slpaData.length > 0\n ? html`\n <div class=\"slpa-results\">\n <div class=\"slpa-title\">AI 분석 결과 (SL-PA 관련 항목)</div>\n ${this.slpaData.map(\n item => html`\n <div class=\"slpa-item\">\n <div class=\"slpa-label\">${item.name}</div>\n <div class=\"slpa-value\">${item.value.toFixed(2)} ${item.unit || ''}</div>\n </div>\n `\n )}\n </div>\n `\n : ''}\n\n <div class=\"button-line\">\n <div class=\"ghost-btn \" @click=${this._reset}>초기화</div>\n <div class=\"ghost-btn secondary\" @click=${() => this._save()}>저장</div>\n </div>\n </div>\n `\n }\n\n willUpdate(changedProperties: Map<string, any>) {\n super.willUpdate(changedProperties)\n\n // project가 변경되고, project.id가 존재하면 데이터 로드\n if (changedProperties.has('project') && this.project?.id) {\n this._getProjectData()\n }\n }\n\n private _getCurrentFile() {\n return this.pendingFile || (this.attachment?.id ? this.attachment : null)\n }\n\n private async _save() {\n // 대기 중인 파일이 있으면 업로드\n if (this.pendingFile) {\n await this._uploadFile(this.pendingFile)\n this.pendingFile = null\n } else if (!this.pendingFile && !this.attachment?.id) {\n notify({ message: '파일은 필수입니다.' })\n }\n }\n\n private _removeFile() {\n this.pendingFile = null\n this.attachment = {}\n this.slpaData = [] // SL-PA 데이터도 초기화\n }\n\n private async _onFileSelect(e: CustomEvent) {\n const files = e.detail as File[]\n if (files.length > 0) {\n this.pendingFile = files[0]\n }\n }\n\n private async _uploadFile(file: File | null) {\n const response = await updateProjectCompleteStep3(file, this.project.id)\n if (!response.errors) {\n const uploaded = response.data.updateKpiMetricValuesSentiment\n this.attachment = uploaded\n notify({ message: '저장되었습니다.' })\n\n // PDF 업로드 후 SL-PA 관련 데이터를 가져와서 표시\n await this._loadSlpaData()\n }\n }\n\n private async _loadSlpaData() {\n // KPI 메트릭들 가져오기\n const kpiMetrics = await getKpiMetrics()\n\n // \"SL-PA\"가 포함된 메트릭들만 필터링\n const slpaMetrics = kpiMetrics.filter(metric => metric.name.includes('SL-PA'))\n\n if (slpaMetrics.length > 0) {\n // 해당 프로젝트의 KPI 값들 가져오기\n const kpiMetricValues = await getKpiMetricValues(this.project.id)\n\n // SL-PA 메트릭들과 해당 값들을 매칭하여 표시용 데이터 생성\n this.slpaData = slpaMetrics.map(metric => {\n const metricValue = kpiMetricValues.find((item: any) => item.metricId === metric.id)\n return {\n name: metric.name,\n value: metricValue?.value || 0,\n unit: metricValue?.unit || metric.unit || ''\n }\n })\n }\n }\n\n private _reset() {\n this.pendingFile = null\n this.slpaData = [] // SL-PA 데이터도 초기화\n this._getProjectData()\n }\n\n private async _getProjectData() {\n const project = await getProject(this.project.id)\n this.attachment = project.completeReport\n\n // 기존에 PDF가 업로드되어 있다면 SL-PA 데이터도 로드\n if (this.attachment?.id) {\n await this._loadSlpaData()\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"pc-tab3-upload.js","sourceRoot":"","sources":["../../../client/pages/project-complete-tabs/pc-tab3-upload.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { client } from '@operato/graphql'\nimport { gql } from '@apollo/client'\nimport { getProject, updateProjectCompleteStep3, getKpiMetrics, getKpiMetricValues } from '../../shared/complete-api'\nimport { notify } from '@operato/layout'\nimport { hasPrivilege } from '@things-factory/auth-base/dist-client'\n\n@customElement('sv-pc-tab3-upload')\nexport class SvProjectCompleteTab3Upload extends LitElement {\n static styles = [\n css`\n :host {\n display: block;\n }\n .title {\n color: #212529;\n font-size: 13px;\n font-weight: 400;\n line-height: 24px;\n text-align: center;\n }\n\n .rows {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 8px 6px;\n }\n\n .upload-controls {\n display: flex;\n gap: 8px;\n justify-content: center;\n margin-bottom: 16px;\n\n ox-input-file {\n flex: 1;\n max-width: 500px;\n height: 210px;\n }\n }\n\n .attachment-list {\n display: flex;\n justify-content: center;\n margin-top: 8px;\n }\n\n .attachment-row {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 16px;\n padding: 24px 20px;\n border: 2px solid #e3f2fd;\n border-radius: 12px;\n background: linear-gradient(135deg, #f8fbff 0%, #e3f2fd 100%);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n min-width: 300px;\n max-width: 400px;\n }\n\n .file-icon {\n font-size: 40px;\n color: #d32f2f;\n line-height: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n width: auto;\n height: 48px;\n }\n\n .attachment-name {\n font-size: 16px;\n font-weight: 500;\n color: #1976d2;\n text-align: center;\n word-break: break-word;\n line-height: 1.4;\n }\n\n .delete-icon {\n cursor: pointer;\n color: #757575;\n background: rgba(117, 117, 117, 0.1);\n border-radius: 50%;\n padding: 8px;\n transition: all 0.2s ease;\n }\n\n .delete-icon:hover {\n color: #e57373;\n background: rgba(229, 115, 115, 0.15);\n transform: scale(1.1);\n }\n\n .button-line {\n display: flex;\n justify-content: center;\n gap: 10px;\n margin-top: 16px;\n }\n .ghost-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 10px;\n background: #35618e;\n color: #ffffff;\n border-radius: 5px;\n cursor: pointer;\n }\n .ghost-btn.secondary {\n background: #24be7b;\n }\n .ghost-btn.disabled {\n opacity: 0.45;\n cursor: not-allowed;\n }\n\n .slpa-results {\n margin-top: 20px;\n padding: 16px;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n background: #f8f9fa;\n }\n\n .slpa-title {\n font-size: 16px;\n font-weight: 600;\n color: #35618e;\n margin-bottom: 12px;\n }\n\n .slpa-item {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 8px 0;\n border-bottom: 1px solid #e0e0e0;\n }\n\n .slpa-item:last-child {\n border-bottom: none;\n }\n\n .slpa-label {\n font-weight: 500;\n color: #333;\n }\n\n .slpa-value {\n font-weight: 600;\n color: #1976d2;\n }\n `\n ]\n\n @property({ type: Object }) project: any = {}\n @state() attachment: any = {}\n @state() private pendingFile: File | null = null\n @state() slpaData: any[] = []\n /** kpi:sentiment — Step3 보고서 첨부/저장 권한 */\n @state() canSave = false\n\n async connectedCallback() {\n super.connectedCallback()\n this.canSave = await hasPrivilege({\n category: 'kpi',\n privilege: 'sentiment',\n domainOwnerGranted: true,\n superUserGranted: true\n })\n }\n\n render() {\n return html`\n <div class=\"title\">\n <div>\n 감리 최종 감리보고서의 종합의견서(PDF 형식)를 시스템에 업로드해 주세요.\n <br />\n 보고서에 포함된 텍스트와 평가 내용을 기반으로 기계 판독 및 AI 기반 프로젝트 평가가 자동으로 진행되므로, 반드시 최종\n 확정된 원본 파일을 제출해 주시기 바랍니다.\n </div>\n </div>\n\n <div class=\"rows\">\n ${this._getCurrentFile()\n ? html`\n <div class=\"attachment-list\">\n <div class=\"attachment-row\">\n <md-icon class=\"file-icon\">picture_as_pdf</md-icon>\n <div class=\"attachment-name\" title=\"${this._getCurrentFile()?.name}\">${this._getCurrentFile()?.name}</div>\n <md-icon class=\"delete-icon\" @click=${this._removeFile}>delete</md-icon>\n </div>\n </div>\n `\n : html`\n <div class=\"upload-controls\">\n <ox-input-file accept=\"application/pdf,.pdf\" hide-filelist @change=${this._onFileSelect}> </ox-input-file>\n </div>\n `}\n ${this.slpaData.length > 0\n ? html`\n <div class=\"slpa-results\">\n <div class=\"slpa-title\">AI 분석 결과 (SL-PA 관련 항목)</div>\n ${this.slpaData.map(\n item => html`\n <div class=\"slpa-item\">\n <div class=\"slpa-label\">${item.name}</div>\n <div class=\"slpa-value\">${item.value.toFixed(2)} ${item.unit || ''}</div>\n </div>\n `\n )}\n </div>\n `\n : ''}\n\n <div class=\"button-line\">\n <div class=\"ghost-btn \" @click=${this._reset}>초기화</div>\n <div\n class=\"ghost-btn secondary ${this.canSave ? '' : 'disabled'}\"\n title=${this.canSave ? '' : 'kpi:sentiment 권한 필요'}\n @click=${() => this.canSave && this._save()}\n >\n 저장\n </div>\n </div>\n </div>\n `\n }\n\n willUpdate(changedProperties: Map<string, any>) {\n super.willUpdate(changedProperties)\n\n // project가 변경되고, project.id가 존재하면 데이터 로드\n if (changedProperties.has('project') && this.project?.id) {\n this._getProjectData()\n }\n }\n\n private _getCurrentFile() {\n return this.pendingFile || (this.attachment?.id ? this.attachment : null)\n }\n\n private async _save() {\n // 대기 중인 파일이 있으면 업로드\n if (this.pendingFile) {\n await this._uploadFile(this.pendingFile)\n this.pendingFile = null\n } else if (!this.pendingFile && !this.attachment?.id) {\n notify({ message: '파일은 필수입니다.' })\n }\n }\n\n private _removeFile() {\n this.pendingFile = null\n this.attachment = {}\n this.slpaData = [] // SL-PA 데이터도 초기화\n }\n\n private async _onFileSelect(e: CustomEvent) {\n const files = e.detail as File[]\n if (files.length > 0) {\n this.pendingFile = files[0]\n }\n }\n\n private async _uploadFile(file: File | null) {\n const response = await updateProjectCompleteStep3(file, this.project.id, this.project?.code)\n if (!response.errors) {\n const uploaded = response.data.updateKpiMetricValuesSentiment\n this.attachment = uploaded\n notify({ message: '저장되었습니다.' })\n\n // PDF 업로드 후 SL-PA 관련 데이터를 가져와서 표시\n await this._loadSlpaData()\n }\n }\n\n private async _loadSlpaData() {\n // KPI 메트릭들 가져오기\n const kpiMetrics = await getKpiMetrics(this.project?.code)\n\n // \"SL-PA\"가 포함된 메트릭들만 필터링\n const slpaMetrics = kpiMetrics.filter(metric => metric.name.includes('SL-PA'))\n\n if (slpaMetrics.length > 0) {\n // 해당 프로젝트의 KPI 값들 가져오기\n const kpiMetricValues = await getKpiMetricValues(this.project.id, this.project?.code)\n\n // SL-PA 메트릭들과 해당 값들을 매칭하여 표시용 데이터 생성\n this.slpaData = slpaMetrics.map(metric => {\n const metricValue = kpiMetricValues.find((item: any) => item.metricId === metric.id)\n return {\n name: metric.name,\n value: metricValue?.value || 0,\n unit: metricValue?.unit || metric.unit || ''\n }\n })\n }\n }\n\n private _reset() {\n this.pendingFile = null\n this.slpaData = [] // SL-PA 데이터도 초기화\n this._getProjectData()\n }\n\n private async _getProjectData() {\n const project = await getProject(this.project.id)\n this.attachment = project.completeReport\n\n // 기존에 PDF가 업로드되어 있다면 SL-PA 데이터도 로드\n if (this.attachment?.id) {\n await this._loadSlpaData()\n }\n }\n}\n"]}
|
|
@@ -2,17 +2,41 @@ import { LitElement } from 'lit';
|
|
|
2
2
|
export declare class SvProjectCompleteTab4Monthly extends LitElement {
|
|
3
3
|
static styles: import("lit").CSSResult[];
|
|
4
4
|
project: any;
|
|
5
|
+
/** 월별 metric 목록 (periodType=MONTH). KpiMetric admin 에 등록된 것 기준. */
|
|
6
|
+
monthlyMetrics: any[];
|
|
7
|
+
/** monthRows: { workDate:'YYYY-MM', values:{[metricId]:value}, originalValues, dirty }[] */
|
|
5
8
|
monthRows: any[];
|
|
6
9
|
addYear: number;
|
|
7
10
|
addMonth: number;
|
|
11
|
+
/** kpi:input — Step4 월별 데이터 저장 권한 (cumulative 와 같은 권한) */
|
|
12
|
+
canSave: boolean;
|
|
13
|
+
connectedCallback(): Promise<void>;
|
|
8
14
|
render(): import("lit-html").TemplateResult<1>;
|
|
9
15
|
willUpdate(changedProperties: Map<string, any>): void;
|
|
10
16
|
private _getYearRange;
|
|
11
17
|
private _isCurrentMonth;
|
|
18
|
+
/**
|
|
19
|
+
* 월별 metric 정의 + 그 프로젝트의 월별 KpiMetricValue 들을 조회해 그리드 row 구성.
|
|
20
|
+
*
|
|
21
|
+
* 1) KpiMetric where periodType=MONTH → monthlyMetrics
|
|
22
|
+
* 2) KpiMetricValue where org=projectId → 월별로 그룹핑하여 monthRows
|
|
23
|
+
*/
|
|
12
24
|
private _loadData;
|
|
25
|
+
/** project.startDate (YYYY-MM) ~ **전월** (YYYY-MM) 까지 매월 문자열 배열.
|
|
26
|
+
* 현재월은 의도적으로 제외 — 운영 원칙상 "이번달 데이터는 아직 입력 대상이 아님". */
|
|
27
|
+
private _generateExpectedMonths;
|
|
28
|
+
/** 셀 미입력 여부 — 값 없음 AND 그 월이 **전월** (직전 한 달) 인 경우만 pending.
|
|
29
|
+
* 과월 전체가 아니라 전월 한 달에 한해서만 강조 — 사용자 입력 흐름(이번 달에 지난달 데이터)과 일치. */
|
|
30
|
+
private _isCellPending;
|
|
31
|
+
/** metric 컬럼이 전 row 통틀어 한 번도 값이 없으면 헤더 강조. */
|
|
32
|
+
private _isMetricNeverEntered;
|
|
13
33
|
private _addMonth;
|
|
14
34
|
private _removeMonth;
|
|
15
35
|
private _onCellChange;
|
|
36
|
+
/**
|
|
37
|
+
* 저장 — dirty row 들 안의 변경된 cell 들을 KpiMetricValuePatch 로 모아
|
|
38
|
+
* updateKpiMetricValuesCumulative 한 번 호출 (backend upsert 가 unique 조합 처리).
|
|
39
|
+
*/
|
|
16
40
|
private _save;
|
|
17
41
|
private _reset;
|
|
18
42
|
}
|