@dssp/dkpi 1.0.0-alpha.5 → 1.0.0-alpha.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/assets/favicon.ico +0 -0
  2. package/assets/manifest/apple-1024.png +0 -0
  3. package/assets/manifest/apple-120.png +0 -0
  4. package/assets/manifest/apple-152.png +0 -0
  5. package/assets/manifest/apple-167.png +0 -0
  6. package/assets/manifest/apple-180.png +0 -0
  7. package/assets/manifest/apple-touch-icon.png +0 -0
  8. package/assets/manifest/badge-128x128.png +0 -0
  9. package/assets/manifest/chrome-splashscreen-icon-384x384.png +0 -0
  10. package/assets/manifest/chrome-touch-icon-192x192.png +0 -0
  11. package/assets/manifest/icon-128x128.png +0 -0
  12. package/assets/manifest/icon-192x192.png +0 -0
  13. package/assets/manifest/icon-512x512.png +0 -0
  14. package/assets/manifest/icon-72x72.png +0 -0
  15. package/assets/manifest/icon-96x96.png +0 -0
  16. package/assets/manifest/image-metaog.png +0 -0
  17. package/assets/manifest/maskable_icon.png +0 -0
  18. package/assets/manifest/ms-icon-144x144.png +0 -0
  19. package/assets/manifest/ms-touch-icon-144x144-precomposed.png +0 -0
  20. package/assets/videos/intro.mp4 +0 -0
  21. package/dist-client/bootstrap.js +64 -4
  22. package/dist-client/bootstrap.js.map +1 -1
  23. package/dist-client/components/kpi-single-boxplot-chart.d.ts +24 -0
  24. package/dist-client/components/kpi-single-boxplot-chart.js +317 -0
  25. package/dist-client/components/kpi-single-boxplot-chart.js.map +1 -0
  26. package/dist-client/components/sv-pagenation-control.d.ts +18 -0
  27. package/dist-client/components/sv-pagenation-control.js +142 -0
  28. package/dist-client/components/sv-pagenation-control.js.map +1 -0
  29. package/dist-client/icons/menu-icons.d.ts +6 -0
  30. package/dist-client/icons/menu-icons.js +42 -0
  31. package/dist-client/icons/menu-icons.js.map +1 -1
  32. package/dist-client/menu.d.ts +23 -1
  33. package/dist-client/menu.js +57 -2
  34. package/dist-client/menu.js.map +1 -1
  35. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.d.ts +58 -0
  36. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js +731 -0
  37. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js.map +1 -0
  38. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.d.ts +23 -0
  39. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js +76 -0
  40. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js.map +1 -0
  41. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.d.ts +69 -0
  42. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js +385 -0
  43. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js.map +1 -0
  44. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.d.ts +12 -0
  45. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js +174 -0
  46. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js.map +1 -0
  47. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.d.ts +41 -0
  48. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js +191 -0
  49. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js.map +1 -0
  50. package/dist-client/pages/kpi-value/kpi-value-importer.d.ts +23 -0
  51. package/dist-client/pages/kpi-value/kpi-value-importer.js +93 -0
  52. package/dist-client/pages/kpi-value/kpi-value-importer.js.map +1 -0
  53. package/dist-client/pages/kpi-value/kpi-value-list-page.d.ts +72 -0
  54. package/dist-client/pages/kpi-value/kpi-value-list-page.js +465 -0
  55. package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -0
  56. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.d.ts +13 -0
  57. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js +248 -0
  58. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js.map +1 -0
  59. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.d.ts +10 -0
  60. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js +229 -0
  61. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js.map +1 -0
  62. package/dist-client/pages/project-complete-tabs/pc-tab3-upload.d.ts +12 -0
  63. package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js +213 -0
  64. package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js.map +1 -0
  65. package/dist-client/pages/sv-project-complete.d.ts +22 -0
  66. package/dist-client/pages/sv-project-complete.js +213 -0
  67. package/dist-client/pages/sv-project-complete.js.map +1 -0
  68. package/dist-client/pages/sv-project-completed-list.d.ts +24 -0
  69. package/dist-client/pages/sv-project-completed-list.js +357 -0
  70. package/dist-client/pages/sv-project-completed-list.js.map +1 -0
  71. package/dist-client/pages/sv-project-detail.d.ts +13 -0
  72. package/dist-client/pages/sv-project-detail.js +494 -0
  73. package/dist-client/pages/sv-project-detail.js.map +1 -0
  74. package/dist-client/pages/sv-project-list.d.ts +157 -0
  75. package/dist-client/pages/sv-project-list.js +431 -0
  76. package/dist-client/pages/sv-project-list.js.map +1 -0
  77. package/dist-client/route.d.ts +1 -1
  78. package/dist-client/route.js +22 -1
  79. package/dist-client/route.js.map +1 -1
  80. package/dist-client/shared/complete-api.d.ts +5 -0
  81. package/dist-client/shared/complete-api.js +125 -0
  82. package/dist-client/shared/complete-api.js.map +1 -0
  83. package/dist-client/shared/func.d.ts +2 -0
  84. package/dist-client/shared/func.js +22 -0
  85. package/dist-client/shared/func.js.map +1 -0
  86. package/dist-client/themes/dark.css +24 -24
  87. package/dist-client/themes/light.css +23 -23
  88. package/dist-client/tsconfig.tsbuildinfo +1 -1
  89. package/dist-client/viewparts/menu-tools.d.ts +37 -1
  90. package/dist-client/viewparts/menu-tools.js +348 -15
  91. package/dist-client/viewparts/menu-tools.js.map +1 -1
  92. package/dist-server/index.d.ts +2 -0
  93. package/dist-server/index.js +5 -0
  94. package/dist-server/index.js.map +1 -1
  95. package/dist-server/migrations/index.d.ts +1 -0
  96. package/dist-server/migrations/index.js +12 -0
  97. package/dist-server/migrations/index.js.map +1 -0
  98. package/dist-server/scripts/calculate-kpi-scores.d.ts +10 -0
  99. package/dist-server/scripts/calculate-kpi-scores.js +271 -0
  100. package/dist-server/scripts/calculate-kpi-scores.js.map +1 -0
  101. package/dist-server/scripts/load-grade-data-migration.d.ts +10 -0
  102. package/dist-server/scripts/load-grade-data-migration.js +194 -0
  103. package/dist-server/scripts/load-grade-data-migration.js.map +1 -0
  104. package/dist-server/scripts/propagate-parent-kpi-values.d.ts +10 -0
  105. package/dist-server/scripts/propagate-parent-kpi-values.js +440 -0
  106. package/dist-server/scripts/propagate-parent-kpi-values.js.map +1 -0
  107. package/dist-server/service/index.d.ts +6 -0
  108. package/dist-server/service/index.js +21 -0
  109. package/dist-server/service/index.js.map +1 -0
  110. package/dist-server/service/kpi-metric-value/index.d.ts +4 -0
  111. package/dist-server/service/kpi-metric-value/index.js +8 -0
  112. package/dist-server/service/kpi-metric-value/index.js.map +1 -0
  113. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.d.ts +7 -0
  114. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +112 -0
  115. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -0
  116. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.d.ts +7 -0
  117. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js +47 -0
  118. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js.map +1 -0
  119. package/dist-server/service/kpi-value/index.d.ts +3 -0
  120. package/dist-server/service/kpi-value/index.js +7 -0
  121. package/dist-server/service/kpi-value/index.js.map +1 -0
  122. package/dist-server/service/kpi-value/kpi-value-query.d.ts +7 -0
  123. package/dist-server/service/kpi-value/kpi-value-query.js +47 -0
  124. package/dist-server/service/kpi-value/kpi-value-query.js.map +1 -0
  125. package/dist-server/tsconfig.tsbuildinfo +1 -1
  126. package/package.json +62 -51
  127. package/schema.graphql +11497 -3215
  128. package/things-factory.config.js +7 -1
@@ -0,0 +1,213 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import { css, html, LitElement } from 'lit';
3
+ import { customElement, property } from 'lit/decorators.js';
4
+ import { client } from '@operato/graphql';
5
+ import { gql } from '@apollo/client';
6
+ let SvProjectCompleteTab3Upload = class SvProjectCompleteTab3Upload extends LitElement {
7
+ constructor() {
8
+ super(...arguments);
9
+ this.data = [];
10
+ this.project = {};
11
+ }
12
+ render() {
13
+ var _a, _b;
14
+ return html `
15
+ <div class="title">
16
+ <div>
17
+ 감리 최종 감리보고서의 종합의견서(PDF 형식)를 시스템에 업로드해 주세요.
18
+ <br />
19
+ 보고서에 포함된 텍스트와 평가 내용을 기반으로 기계 판독 및 AI 기반 프로젝트 평가가 자동으로 진행되므로, 반드시 최종
20
+ 확정된 원본 파일을 제출해 주시기 바랍니다.
21
+ </div>
22
+ </div>
23
+
24
+ <div class="rows">
25
+ <div class="upload-controls">
26
+ <ox-input-file accept="application/pdf,.pdf" hide-filelist @change=${this._onFileSelect} multiple="true">
27
+ </ox-input-file>
28
+ </div>
29
+
30
+ <div class="attachment-list">
31
+ ${!((_a = this.data) === null || _a === void 0 ? void 0 : _a.length)
32
+ ? html `<div class="empty-state">업로드된 파일이 없습니다.</div>`
33
+ : (_b = this.data) === null || _b === void 0 ? void 0 : _b.map(file => html `<div class="attachment-row">
34
+ <div class="attachment-name" title="${file.name}">${file.name}</div>
35
+ <md-icon class="delete-icon" @click=${() => this._deleteAttachment(file.id)}>delete</md-icon>
36
+ </div>`)}
37
+ </div>
38
+
39
+ <div class="button-line">
40
+ <div class="ghost-btn " @click=${this._reset}>초기화</div>
41
+ <div class="ghost-btn secondary" @click=${() => this._save()}>저장</div>
42
+ </div>
43
+ </div>
44
+ `;
45
+ }
46
+ _save() {
47
+ this.dispatchEvent(new CustomEvent('complete-tab-save', { detail: { data: this.data } }));
48
+ }
49
+ async _reset() {
50
+ var _a;
51
+ await ((_a = this.data) === null || _a === void 0 ? void 0 : _a.forEach(attachment => this._deleteAttachment(attachment.id)));
52
+ this.dispatchEvent(new CustomEvent('complete-tab-reset', { detail: { tab: 3 } }));
53
+ }
54
+ async _onFileSelect(e) {
55
+ const files = e.detail;
56
+ await this._uploadFiles(files);
57
+ }
58
+ async _uploadFiles(files) {
59
+ const response = await client.mutate({
60
+ mutation: gql `
61
+ mutation ($attachments: [NewAttachment!]!) {
62
+ createAttachments(attachments: $attachments) {
63
+ id
64
+ name
65
+ fullpath
66
+ }
67
+ }
68
+ `,
69
+ variables: {
70
+ attachments: files.map(file => {
71
+ var _a;
72
+ return ({
73
+ file,
74
+ refBy: (_a = this.project) === null || _a === void 0 ? void 0 : _a.id,
75
+ refType: 'ProjectCompleteReport'
76
+ });
77
+ })
78
+ },
79
+ context: {
80
+ hasUpload: true
81
+ }
82
+ });
83
+ if (!response.errors) {
84
+ const uploaded = response.data.createAttachments;
85
+ this.data = [...this.data, ...uploaded];
86
+ this.dispatchEvent(new CustomEvent('complete-data-change', { detail: { tab: 3, data: this.data } }));
87
+ }
88
+ }
89
+ async _deleteAttachment(attachmentId) {
90
+ var _a;
91
+ const response = await client.mutate({
92
+ mutation: gql `
93
+ mutation DeleteAttachment($deleteAttachmentId: String!) {
94
+ deleteAttachment(id: $deleteAttachmentId)
95
+ }
96
+ `,
97
+ variables: { deleteAttachmentId: attachmentId }
98
+ });
99
+ if (!response.errors) {
100
+ this.data = ((_a = this.data) === null || _a === void 0 ? void 0 : _a.filter(a => a.id !== attachmentId)) || [];
101
+ this.dispatchEvent(new CustomEvent('complete-data-change', { detail: { tab: 3, data: this.data } }));
102
+ }
103
+ }
104
+ };
105
+ SvProjectCompleteTab3Upload.styles = [
106
+ css `
107
+ :host {
108
+ display: block;
109
+ }
110
+ .title {
111
+ color: #212529;
112
+ font-size: 13px;
113
+ font-weight: 400;
114
+ line-height: 24px;
115
+ text-align: center;
116
+ }
117
+
118
+ .rows {
119
+ display: flex;
120
+ flex-direction: column;
121
+ gap: 12px;
122
+ padding: 8px 6px;
123
+ }
124
+
125
+ .upload-controls {
126
+ display: flex;
127
+ gap: 8px;
128
+ justify-content: center;
129
+ margin-bottom: 16px;
130
+
131
+ ox-input-file {
132
+ flex: 1;
133
+ max-width: 500px;
134
+ height: 210px;
135
+ }
136
+ }
137
+
138
+ .attachment-list {
139
+ position: relative;
140
+ z-index: 1;
141
+ display: flex;
142
+ min-height: 80px;
143
+ justify-content: center;
144
+ flex-direction: column;
145
+ gap: 8px;
146
+ border: 1px solid #eee;
147
+ border-radius: 8px;
148
+ padding: 12px;
149
+ margin-top: 8px;
150
+ }
151
+
152
+ .attachment-row {
153
+ display: grid;
154
+ grid-template-columns: 1fr auto;
155
+ align-items: center;
156
+ gap: 8px;
157
+ padding: 8px 10px;
158
+ border: 1px solid #ddd;
159
+ border-radius: 6px;
160
+ background: #fafafa;
161
+ }
162
+
163
+ .attachment-name {
164
+ font-size: 14px;
165
+ overflow: hidden;
166
+ white-space: nowrap;
167
+ text-overflow: ellipsis;
168
+ }
169
+
170
+ .empty-state {
171
+ text-align: center;
172
+ color: #666;
173
+ font-style: italic;
174
+ }
175
+
176
+ .delete-icon {
177
+ cursor: pointer;
178
+ }
179
+
180
+ .button-line {
181
+ display: flex;
182
+ justify-content: center;
183
+ gap: 10px;
184
+ margin-top: 16px;
185
+ }
186
+ .ghost-btn {
187
+ display: inline-flex;
188
+ align-items: center;
189
+ gap: 6px;
190
+ padding: 6px 10px;
191
+ background: #35618e;
192
+ color: #ffffff;
193
+ border-radius: 5px;
194
+ cursor: pointer;
195
+ }
196
+ .ghost-btn.secondary {
197
+ background: #24be7b;
198
+ }
199
+ `
200
+ ];
201
+ __decorate([
202
+ property({ type: Array }),
203
+ __metadata("design:type", Object)
204
+ ], SvProjectCompleteTab3Upload.prototype, "data", void 0);
205
+ __decorate([
206
+ property({ type: Object }),
207
+ __metadata("design:type", Object)
208
+ ], SvProjectCompleteTab3Upload.prototype, "project", void 0);
209
+ SvProjectCompleteTab3Upload = __decorate([
210
+ customElement('sv-pc-tab3-upload')
211
+ ], SvProjectCompleteTab3Upload);
212
+ export { SvProjectCompleteTab3Upload };
213
+ //# sourceMappingURL=pc-tab3-upload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pc-tab3-upload.js","sourceRoot":"","sources":["../../../client/pages/project-complete-tabs/pc-tab3-upload.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAS,MAAM,mBAAmB,CAAA;AAClE,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAA;AAG7B,IAAM,2BAA2B,GAAjC,MAAM,2BAA4B,SAAQ,UAAU;IAApD;;QAkGsB,SAAI,GAAQ,EAAE,CAAA;QACb,YAAO,GAAQ,EAAE,CAAA;IAkG/C,CAAC;IAhGC,MAAM;;QACJ,OAAO,IAAI,CAAA;;;;;;;;;;;;+EAYgE,IAAI,CAAC,aAAa;;;;;YAKrF,CAAC,CAAA,MAAA,IAAI,CAAC,IAAI,0CAAE,MAAM,CAAA;YAClB,CAAC,CAAC,IAAI,CAAA,+CAA+C;YACrD,CAAC,CAAC,MAAA,IAAI,CAAC,IAAI,0CAAE,GAAG,CACZ,IAAI,CAAC,EAAE,CACL,IAAI,CAAA;0DACoC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI;0DACvB,GAAG,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;yBACtE,CACV;;;;2CAI4B,IAAI,CAAC,MAAM;oDACF,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE;;;KAGjE,CAAA;IACH,CAAC;IAEO,KAAK;QACX,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,mBAAmB,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAA;IAC3F,CAAC;IAEO,KAAK,CAAC,MAAM;;QAClB,MAAM,CAAA,MAAA,IAAI,CAAC,IAAI,0CAAE,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAA,CAAA;QAC7E,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,oBAAoB,EAAE,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAA;IACnF,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,CAAc;QACxC,MAAM,KAAK,GAAG,CAAC,CAAC,MAAgB,CAAA;QAChC,MAAM,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;IAChC,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,KAAa;QACtC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC;YACnC,QAAQ,EAAE,GAAG,CAAA;;;;;;;;OAQZ;YACD,SAAS,EAAE;gBACT,WAAW,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;;oBAAC,OAAA,CAAC;wBAC9B,IAAI;wBACJ,KAAK,EAAE,MAAA,IAAI,CAAC,OAAO,0CAAE,EAAE;wBACvB,OAAO,EAAE,uBAAuB;qBACjC,CAAC,CAAA;iBAAA,CAAC;aACJ;YACD,OAAO,EAAE;gBACP,SAAS,EAAE,IAAI;aAChB;SACF,CAAC,CAAA;QAEF,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;YACrB,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAA;YAChD,IAAI,CAAC,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,CAAA;YACvC,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,sBAAsB,EAAE,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAA;QACtG,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAAC,YAAoB;;QAClD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC;YACnC,QAAQ,EAAE,GAAG,CAAA;;;;OAIZ;YACD,SAAS,EAAE,EAAE,kBAAkB,EAAE,YAAY,EAAE;SAChD,CAAC,CAAA;QAEF,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;YACrB,IAAI,CAAC,IAAI,GAAG,CAAA,MAAA,IAAI,CAAC,IAAI,0CAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,YAAY,CAAC,KAAI,EAAE,CAAA;YAC/D,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,sBAAsB,EAAE,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAA;QACtG,CAAC;IACH,CAAC;;AAnMM,kCAAM,GAAG;IACd,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA6FF;CACF,AA/FY,CA+FZ;AAE0B;IAA1B,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;;yDAAe;AACb;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;4DAAkB;AAnGlC,2BAA2B;IADvC,aAAa,CAAC,mBAAmB,CAAC;GACtB,2BAA2B,CAqMvC","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'\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 position: relative;\n z-index: 1;\n display: flex;\n min-height: 80px;\n justify-content: center;\n flex-direction: column;\n gap: 8px;\n border: 1px solid #eee;\n border-radius: 8px;\n padding: 12px;\n margin-top: 8px;\n }\n\n .attachment-row {\n display: grid;\n grid-template-columns: 1fr auto;\n align-items: center;\n gap: 8px;\n padding: 8px 10px;\n border: 1px solid #ddd;\n border-radius: 6px;\n background: #fafafa;\n }\n\n .attachment-name {\n font-size: 14px;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n }\n\n .empty-state {\n text-align: center;\n color: #666;\n font-style: italic;\n }\n\n .delete-icon {\n cursor: pointer;\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 ]\n\n @property({ type: Array }) data: any = []\n @property({ type: Object }) project: 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 <div class=\"upload-controls\">\n <ox-input-file accept=\"application/pdf,.pdf\" hide-filelist @change=${this._onFileSelect} multiple=\"true\">\n </ox-input-file>\n </div>\n\n <div class=\"attachment-list\">\n ${!this.data?.length\n ? html`<div class=\"empty-state\">업로드된 파일이 없습니다.</div>`\n : this.data?.map(\n file =>\n html`<div class=\"attachment-row\">\n <div class=\"attachment-name\" title=\"${file.name}\">${file.name}</div>\n <md-icon class=\"delete-icon\" @click=${() => this._deleteAttachment(file.id)}>delete</md-icon>\n </div>`\n )}\n </div>\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 private _save() {\n this.dispatchEvent(new CustomEvent('complete-tab-save', { detail: { data: this.data } }))\n }\n\n private async _reset() {\n await this.data?.forEach(attachment => this._deleteAttachment(attachment.id))\n this.dispatchEvent(new CustomEvent('complete-tab-reset', { detail: { tab: 3 } }))\n }\n\n private async _onFileSelect(e: CustomEvent) {\n const files = e.detail as File[]\n await this._uploadFiles(files)\n }\n\n private async _uploadFiles(files: File[]) {\n const response = await client.mutate({\n mutation: gql`\n mutation ($attachments: [NewAttachment!]!) {\n createAttachments(attachments: $attachments) {\n id\n name\n fullpath\n }\n }\n `,\n variables: {\n attachments: files.map(file => ({\n file,\n refBy: this.project?.id,\n refType: 'ProjectCompleteReport'\n }))\n },\n context: {\n hasUpload: true\n }\n })\n\n if (!response.errors) {\n const uploaded = response.data.createAttachments\n this.data = [...this.data, ...uploaded]\n this.dispatchEvent(new CustomEvent('complete-data-change', { detail: { tab: 3, data: this.data } }))\n }\n }\n\n private async _deleteAttachment(attachmentId: string) {\n const response = await client.mutate({\n mutation: gql`\n mutation DeleteAttachment($deleteAttachmentId: String!) {\n deleteAttachment(id: $deleteAttachmentId)\n }\n `,\n variables: { deleteAttachmentId: attachmentId }\n })\n\n if (!response.errors) {\n this.data = this.data?.filter(a => a.id !== attachmentId) || []\n this.dispatchEvent(new CustomEvent('complete-data-change', { detail: { tab: 3, data: this.data } }))\n }\n }\n}\n"]}
@@ -0,0 +1,22 @@
1
+ import '@material/web/icon/icon.js';
2
+ import { PageView } from '@operato/shell';
3
+ import './project-complete-tabs/pc-tab1-plan';
4
+ import './project-complete-tabs/pc-tab2-rating';
5
+ import './project-complete-tabs/pc-tab3-upload';
6
+ declare const SvProjectCompletePage_base: typeof PageView & import("@open-wc/dedupe-mixin").Constructor<import("@open-wc/scoped-elements/types/src/types").ScopedElementsHost>;
7
+ export declare class SvProjectCompletePage extends SvProjectCompletePage_base {
8
+ static styles: import("lit").CSSResult[];
9
+ get context(): {
10
+ title: string;
11
+ };
12
+ private activeTab;
13
+ private projectId;
14
+ private project;
15
+ private kpiCategories;
16
+ render(): import("lit-html").TemplateResult<1>;
17
+ pageUpdated(changes: any, lifecycle: any): Promise<void>;
18
+ initProject(projectId?: string): Promise<void>;
19
+ private _onTabClick;
20
+ private _onComplete;
21
+ }
22
+ export {};
@@ -0,0 +1,213 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import '@material/web/icon/icon.js';
3
+ import { navigate, PageView } from '@operato/shell';
4
+ import { css, html } from 'lit';
5
+ import { customElement, state } from 'lit/decorators.js';
6
+ import { ScopedElementsMixin } from '@open-wc/scoped-elements';
7
+ import './project-complete-tabs/pc-tab1-plan';
8
+ import './project-complete-tabs/pc-tab2-rating';
9
+ import './project-complete-tabs/pc-tab3-upload';
10
+ import { getProject, getKpiCategories } from '../shared/complete-api';
11
+ import { notify } from '@operato/layout';
12
+ let SvProjectCompletePage = class SvProjectCompletePage extends ScopedElementsMixin(PageView) {
13
+ constructor() {
14
+ super(...arguments);
15
+ this.activeTab = 1;
16
+ this.projectId = '';
17
+ this.project = {};
18
+ this.kpiCategories = [];
19
+ this._onTabClick = async (tabNumber) => {
20
+ if (tabNumber === this.activeTab)
21
+ return;
22
+ this.activeTab = tabNumber;
23
+ };
24
+ this._onComplete = () => {
25
+ console.log('완공 처리 요청', {
26
+ projectId: this.projectId
27
+ });
28
+ // TODO: 실제 완공 처리 API 호출 구현 필요
29
+ notify({ message: '완공 처리가 요청되었습니다.', level: 'info' });
30
+ };
31
+ }
32
+ get context() {
33
+ return {
34
+ title: '프로젝트 완공 처리'
35
+ };
36
+ }
37
+ render() {
38
+ return html `
39
+ <div class="page-header">
40
+ <div class="page-title">프로젝트 완공 처리</div>
41
+ <div class="triangle"></div>
42
+ <span class="spacer"></span>
43
+ <div class="ghost-btn" @click=${() => navigate(`project-detail/${this.projectId}`)}>
44
+ <md-icon>arrow_back</md-icon>
45
+ <div>상세로 돌아가기</div>
46
+ </div>
47
+ <div class="ghost-btn complete" @click=${this._onComplete}>
48
+ <md-icon>check_circle</md-icon>
49
+ <div>완공 처리</div>
50
+ </div>
51
+ </div>
52
+
53
+ <div class="card">
54
+ <div class="tabs">
55
+ <div class="tab" ?active=${this.activeTab === 1} @click=${() => this._onTabClick(1)}>
56
+ Step1. 프로젝트 기본정보 현행화
57
+ </div>
58
+ <div class="tab" ?active=${this.activeTab === 2} @click=${() => this._onTabClick(2)}>Step2. 프로젝트 완료 평가</div>
59
+ <div class="tab" ?active=${this.activeTab === 3} @click=${() => this._onTabClick(3)}>Step3. 준공 문서 업로드</div>
60
+ </div>
61
+
62
+ <div class="tab-body">
63
+ ${this.activeTab === 1
64
+ ? html `<sv-pc-tab1-plan .project=${this.project}></sv-pc-tab1-plan>`
65
+ : this.activeTab === 2
66
+ ? html `<sv-pc-tab2-rating .kpiCategories=${this.kpiCategories}></sv-pc-tab2-rating>`
67
+ : html `<sv-pc-tab3-upload .project=${this.project}></sv-pc-tab3-upload>`}
68
+ </div>
69
+ </div>
70
+ `;
71
+ }
72
+ async pageUpdated(changes, lifecycle) {
73
+ if (this.active) {
74
+ this.projectId = lifecycle.resourceId || '';
75
+ await this.initProject(this.projectId);
76
+ }
77
+ }
78
+ async initProject(projectId = '') {
79
+ const project = await getProject(projectId);
80
+ const kpiCategories = await getKpiCategories();
81
+ this.project = project; // View용 데이터
82
+ this.kpiCategories = kpiCategories; // View용 데이터
83
+ }
84
+ };
85
+ SvProjectCompletePage.styles = [
86
+ css `
87
+ :host {
88
+ display: flex;
89
+ flex-direction: column;
90
+ overflow-y: auto;
91
+
92
+ width: 100%;
93
+ height: 100%;
94
+ background-color: var(--md-sys-color-background, #f6f6f6);
95
+ }
96
+
97
+ .page-header {
98
+ display: flex;
99
+ align-items: center;
100
+ gap: 8px;
101
+ padding: 16px 20px 8px 20px;
102
+ }
103
+ .page-title {
104
+ color: #35618e;
105
+ font-weight: 700;
106
+ font-size: 22px;
107
+ letter-spacing: -0.05em;
108
+ }
109
+ .triangle {
110
+ width: 0;
111
+ height: 0;
112
+ border-left: 6px solid transparent;
113
+ border-right: 6px solid transparent;
114
+ border-top: 8px solid #35618e;
115
+ }
116
+
117
+ .card {
118
+ background: #ffffff;
119
+ border-radius: 8px;
120
+ padding: 12px;
121
+ box-shadow: 2px 2px 2px 0 rgba(0, 0, 0, 0.08);
122
+ margin: 0 20px 20px 20px;
123
+ }
124
+
125
+ .tabs {
126
+ display: flex;
127
+ justify-content: center;
128
+ padding: 0 12px 8px 12px;
129
+ border-bottom: 1px dashed rgba(0, 0, 0, 0.15);
130
+ }
131
+ .tab {
132
+ display: inline-flex;
133
+ align-items: center;
134
+ padding: 6px 14px;
135
+ border: 1px solid rgba(0, 0, 0, 0.12);
136
+ color: #35618e;
137
+ background: #f3f6f9;
138
+ cursor: pointer;
139
+ font-size: 14px;
140
+ letter-spacing: -0.02em;
141
+ }
142
+ .tab:first-child {
143
+ border-top-left-radius: 10px;
144
+ border-bottom-left-radius: 10px;
145
+ }
146
+ .tab:last-child {
147
+ border-top-right-radius: 10px;
148
+ border-bottom-right-radius: 10px;
149
+ }
150
+ /* 중간 탭 이중 보더 방지: 좌측 보더 제거 */
151
+ .tab + .tab {
152
+ border-left: 0;
153
+ }
154
+ .tab[active] {
155
+ background: #02a8a2;
156
+ color: #ffffff;
157
+ border-color: rgba(148, 163, 184, 0.5);
158
+ font-weight: 700;
159
+ }
160
+
161
+ .tab-body {
162
+ padding: 12px 8px 4px 8px;
163
+ }
164
+
165
+ .button-line {
166
+ display: flex;
167
+ justify-content: space-between;
168
+ align-items: center;
169
+ margin: 0 20px 10px 20px;
170
+ }
171
+ .spacer {
172
+ flex: 1;
173
+ }
174
+ .ghost-btn {
175
+ display: inline-flex;
176
+ align-items: center;
177
+ gap: 6px;
178
+ padding: 7px 12px;
179
+ background: #35618e;
180
+ color: #ffffff;
181
+ border-radius: 5px;
182
+ box-shadow: 2px 2px 2px 0 rgba(0, 0, 0, 0.1);
183
+ cursor: pointer;
184
+ }
185
+ .ghost-btn.secondary {
186
+ background: #3395f1;
187
+ }
188
+ .ghost-btn.complete {
189
+ background: #16a085;
190
+ }
191
+ `
192
+ ];
193
+ __decorate([
194
+ state(),
195
+ __metadata("design:type", Number)
196
+ ], SvProjectCompletePage.prototype, "activeTab", void 0);
197
+ __decorate([
198
+ state(),
199
+ __metadata("design:type", String)
200
+ ], SvProjectCompletePage.prototype, "projectId", void 0);
201
+ __decorate([
202
+ state(),
203
+ __metadata("design:type", Object)
204
+ ], SvProjectCompletePage.prototype, "project", void 0);
205
+ __decorate([
206
+ state(),
207
+ __metadata("design:type", Array)
208
+ ], SvProjectCompletePage.prototype, "kpiCategories", void 0);
209
+ SvProjectCompletePage = __decorate([
210
+ customElement('sv-project-complete')
211
+ ], SvProjectCompletePage);
212
+ export { SvProjectCompletePage };
213
+ //# sourceMappingURL=sv-project-complete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sv-project-complete.js","sourceRoot":"","sources":["../../client/pages/sv-project-complete.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\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'\n\nimport './project-complete-tabs/pc-tab1-plan'\nimport './project-complete-tabs/pc-tab2-rating'\nimport './project-complete-tabs/pc-tab3-upload'\nimport { getProject, getKpiCategories } from '../shared/complete-api'\nimport { notify } from '@operato/layout'\n\n@customElement('sv-project-complete')\nexport class SvProjectCompletePage 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\n .page-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 16px 20px 8px 20px;\n }\n .page-title {\n color: #35618e;\n font-weight: 700;\n font-size: 22px;\n letter-spacing: -0.05em;\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 .card {\n background: #ffffff;\n border-radius: 8px;\n padding: 12px;\n box-shadow: 2px 2px 2px 0 rgba(0, 0, 0, 0.08);\n margin: 0 20px 20px 20px;\n }\n\n .tabs {\n display: flex;\n justify-content: center;\n padding: 0 12px 8px 12px;\n border-bottom: 1px dashed rgba(0, 0, 0, 0.15);\n }\n .tab {\n display: inline-flex;\n align-items: center;\n padding: 6px 14px;\n border: 1px solid rgba(0, 0, 0, 0.12);\n color: #35618e;\n background: #f3f6f9;\n cursor: pointer;\n font-size: 14px;\n letter-spacing: -0.02em;\n }\n .tab:first-child {\n border-top-left-radius: 10px;\n border-bottom-left-radius: 10px;\n }\n .tab:last-child {\n border-top-right-radius: 10px;\n border-bottom-right-radius: 10px;\n }\n /* 중간 탭 이중 보더 방지: 좌측 보더 제거 */\n .tab + .tab {\n border-left: 0;\n }\n .tab[active] {\n background: #02a8a2;\n color: #ffffff;\n border-color: rgba(148, 163, 184, 0.5);\n font-weight: 700;\n }\n\n .tab-body {\n padding: 12px 8px 4px 8px;\n }\n\n .button-line {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin: 0 20px 10px 20px;\n }\n .spacer {\n flex: 1;\n }\n .ghost-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 7px 12px;\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 .ghost-btn.secondary {\n background: #3395f1;\n }\n .ghost-btn.complete {\n background: #16a085;\n }\n `\n ]\n\n get context() {\n return {\n title: '프로젝트 완공 처리'\n }\n }\n\n @state() private activeTab: number = 1\n @state() private projectId: string = ''\n @state() private project: any = {}\n @state() private kpiCategories: any[] = []\n\n render() {\n return html`\n <div class=\"page-header\">\n <div class=\"page-title\">프로젝트 완공 처리</div>\n <div class=\"triangle\"></div>\n <span class=\"spacer\"></span>\n <div class=\"ghost-btn\" @click=${() => navigate(`project-detail/${this.projectId}`)}>\n <md-icon>arrow_back</md-icon>\n <div>상세로 돌아가기</div>\n </div>\n <div class=\"ghost-btn complete\" @click=${this._onComplete}>\n <md-icon>check_circle</md-icon>\n <div>완공 처리</div>\n </div>\n </div>\n\n <div class=\"card\">\n <div class=\"tabs\">\n <div class=\"tab\" ?active=${this.activeTab === 1} @click=${() => this._onTabClick(1)}>\n Step1. 프로젝트 기본정보 현행화\n </div>\n <div class=\"tab\" ?active=${this.activeTab === 2} @click=${() => this._onTabClick(2)}>Step2. 프로젝트 완료 평가</div>\n <div class=\"tab\" ?active=${this.activeTab === 3} @click=${() => this._onTabClick(3)}>Step3. 준공 문서 업로드</div>\n </div>\n\n <div class=\"tab-body\">\n ${this.activeTab === 1\n ? html`<sv-pc-tab1-plan .project=${this.project}></sv-pc-tab1-plan>`\n : this.activeTab === 2\n ? html`<sv-pc-tab2-rating .kpiCategories=${this.kpiCategories}></sv-pc-tab2-rating>`\n : html`<sv-pc-tab3-upload .project=${this.project}></sv-pc-tab3-upload>`}\n </div>\n </div>\n `\n }\n\n async pageUpdated(changes: any, lifecycle: any) {\n if (this.active) {\n this.projectId = lifecycle.resourceId || ''\n await this.initProject(this.projectId)\n }\n }\n\n async initProject(projectId: string = '') {\n const project = await getProject(projectId)\n const kpiCategories = await getKpiCategories()\n\n this.project = project // View용 데이터\n this.kpiCategories = kpiCategories // View용 데이터\n }\n\n private _onTabClick = async (tabNumber: number) => {\n if (tabNumber === this.activeTab) return\n this.activeTab = tabNumber\n }\n\n private _onComplete = () => {\n console.log('완공 처리 요청', {\n projectId: this.projectId\n })\n // TODO: 실제 완공 처리 API 호출 구현 필요\n notify({ message: '완공 처리가 요청되었습니다.', level: 'info' })\n }\n}\n"]}
@@ -0,0 +1,24 @@
1
+ import '@material/web/icon/icon.js';
2
+ import '../components/kpi-single-boxplot-chart';
3
+ import { PageView } from '@operato/shell';
4
+ import '../components/sv-pagenation-control';
5
+ declare const SvProjectCompletedListPage_base: typeof PageView & import("@open-wc/dedupe-mixin").Constructor<import("@open-wc/scoped-elements/types/src/types").ScopedElementsHost>;
6
+ export declare class SvProjectCompletedListPage extends SvProjectCompletedListPage_base {
7
+ static styles: import("lit").CSSResult[];
8
+ get context(): {
9
+ title: string;
10
+ };
11
+ private projectName;
12
+ private projectList;
13
+ private projectCount;
14
+ private currentPage;
15
+ private readonly pageLimit;
16
+ get totalPages(): number;
17
+ render(): import("lit-html").TemplateResult<1>;
18
+ pageUpdated(changes: any, lifecycle: any): Promise<void>;
19
+ getProjectList(): Promise<void>;
20
+ private _onInputChange;
21
+ private _onKeypress;
22
+ private _changePage;
23
+ }
24
+ export {};