@dssp/dkpi 1.0.0 → 1.0.1

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 (236) hide show
  1. package/dist-client/bootstrap.d.ts +9 -0
  2. package/dist-client/bootstrap.js +272 -0
  3. package/dist-client/bootstrap.js.map +1 -0
  4. package/dist-client/components/kpi-2d-lookup-chart.d.ts +50 -0
  5. package/dist-client/components/kpi-2d-lookup-chart.js +263 -0
  6. package/dist-client/components/kpi-2d-lookup-chart.js.map +1 -0
  7. package/dist-client/components/kpi-boxplot-chart.d.ts +31 -0
  8. package/dist-client/components/kpi-boxplot-chart.js +306 -0
  9. package/dist-client/components/kpi-boxplot-chart.js.map +1 -0
  10. package/dist-client/components/kpi-lookup-chart.d.ts +58 -0
  11. package/dist-client/components/kpi-lookup-chart.js +464 -0
  12. package/dist-client/components/kpi-lookup-chart.js.map +1 -0
  13. package/dist-client/components/kpi-mini-trend-chart.d.ts +14 -0
  14. package/dist-client/components/kpi-mini-trend-chart.js +180 -0
  15. package/dist-client/components/kpi-mini-trend-chart.js.map +1 -0
  16. package/dist-client/components/kpi-radar-chart.d.ts +17 -0
  17. package/dist-client/components/kpi-radar-chart.js +259 -0
  18. package/dist-client/components/kpi-radar-chart.js.map +1 -0
  19. package/dist-client/components/kpi-single-boxplot-chart.d.ts +36 -0
  20. package/dist-client/components/kpi-single-boxplot-chart.js +417 -0
  21. package/dist-client/components/kpi-single-boxplot-chart.js.map +1 -0
  22. package/dist-client/components/kpi-step-lookup-chart.d.ts +33 -0
  23. package/dist-client/components/kpi-step-lookup-chart.js +181 -0
  24. package/dist-client/components/kpi-step-lookup-chart.js.map +1 -0
  25. package/dist-client/components/kpi-trend-chart.d.ts +25 -0
  26. package/dist-client/components/kpi-trend-chart.js +241 -0
  27. package/dist-client/components/kpi-trend-chart.js.map +1 -0
  28. package/dist-client/components/sv-pagenation-control.d.ts +18 -0
  29. package/dist-client/components/sv-pagenation-control.js +142 -0
  30. package/dist-client/components/sv-pagenation-control.js.map +1 -0
  31. package/dist-client/entries/auth/checkin.d.ts +38 -0
  32. package/dist-client/entries/auth/checkin.js +551 -0
  33. package/dist-client/entries/auth/checkin.js.map +1 -0
  34. package/dist-client/entries/public/home.d.ts +8 -0
  35. package/dist-client/entries/public/home.js +97 -0
  36. package/dist-client/entries/public/home.js.map +1 -0
  37. package/dist-client/google-map/common-google-map.d.ts +35 -0
  38. package/dist-client/google-map/common-google-map.js +349 -0
  39. package/dist-client/google-map/common-google-map.js.map +1 -0
  40. package/dist-client/google-map/google-map-loader.d.ts +6 -0
  41. package/dist-client/google-map/google-map-loader.js +23 -0
  42. package/dist-client/google-map/google-map-loader.js.map +1 -0
  43. package/dist-client/icons/menu-icons.d.ts +11 -0
  44. package/dist-client/icons/menu-icons.js +126 -0
  45. package/dist-client/icons/menu-icons.js.map +1 -0
  46. package/dist-client/index.d.ts +0 -0
  47. package/dist-client/index.js +2 -0
  48. package/dist-client/index.js.map +1 -0
  49. package/dist-client/menu.d.ts +23 -0
  50. package/dist-client/menu.js +59 -0
  51. package/dist-client/menu.js.map +1 -0
  52. package/dist-client/pages/component/project-update-header.d.ts +1 -0
  53. package/dist-client/pages/component/project-update-header.js +127 -0
  54. package/dist-client/pages/component/project-update-header.js.map +1 -0
  55. package/dist-client/pages/kpi-admin/dssp-kpi-list-page.d.ts +22 -0
  56. package/dist-client/pages/kpi-admin/dssp-kpi-list-page.js +57 -0
  57. package/dist-client/pages/kpi-admin/dssp-kpi-list-page.js.map +1 -0
  58. package/dist-client/pages/kpi-admin/dssp-kpi-overview.d.ts +47 -0
  59. package/dist-client/pages/kpi-admin/dssp-kpi-overview.js +393 -0
  60. package/dist-client/pages/kpi-admin/dssp-kpi-overview.js.map +1 -0
  61. package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.d.ts +20 -0
  62. package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.js +445 -0
  63. package/dist-client/pages/kpi-admin/kpi-grade-2d-editor.js.map +1 -0
  64. package/dist-client/pages/kpi-admin/kpi-system-guide.d.ts +18 -0
  65. package/dist-client/pages/kpi-admin/kpi-system-guide.js +696 -0
  66. package/dist-client/pages/kpi-admin/kpi-system-guide.js.map +1 -0
  67. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.d.ts +18 -0
  68. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js +259 -0
  69. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js.map +1 -0
  70. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.d.ts +22 -0
  71. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js +346 -0
  72. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js.map +1 -0
  73. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.d.ts +26 -0
  74. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js +433 -0
  75. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js.map +1 -0
  76. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.d.ts +8 -0
  77. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js +78 -0
  78. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js.map +1 -0
  79. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.d.ts +46 -0
  80. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js +945 -0
  81. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js.map +1 -0
  82. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.d.ts +34 -0
  83. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js +238 -0
  84. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js.map +1 -0
  85. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.d.ts +37 -0
  86. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js +689 -0
  87. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js.map +1 -0
  88. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.d.ts +18 -0
  89. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js +131 -0
  90. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js.map +1 -0
  91. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.d.ts +57 -0
  92. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js +866 -0
  93. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js.map +1 -0
  94. package/dist-client/pages/kpi-dashboard/kpi-dashboard.d.ts +63 -0
  95. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js +1097 -0
  96. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js.map +1 -0
  97. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.d.ts +12 -0
  98. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js +82 -0
  99. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js.map +1 -0
  100. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.d.ts +11 -0
  101. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js +65 -0
  102. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js.map +1 -0
  103. package/dist-client/pages/kpi-dashboard/kpi-list-summary.d.ts +13 -0
  104. package/dist-client/pages/kpi-dashboard/kpi-list-summary.js +115 -0
  105. package/dist-client/pages/kpi-dashboard/kpi-list-summary.js.map +1 -0
  106. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.d.ts +15 -0
  107. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js +147 -0
  108. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js.map +1 -0
  109. package/dist-client/pages/kpi-dashboard/kpi-value-entry.d.ts +7 -0
  110. package/dist-client/pages/kpi-dashboard/kpi-value-entry.js +86 -0
  111. package/dist-client/pages/kpi-dashboard/kpi-value-entry.js.map +1 -0
  112. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.d.ts +57 -0
  113. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js +719 -0
  114. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js.map +1 -0
  115. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.d.ts +23 -0
  116. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js +76 -0
  117. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js.map +1 -0
  118. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.d.ts +68 -0
  119. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js +394 -0
  120. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js.map +1 -0
  121. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.d.ts +12 -0
  122. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js +174 -0
  123. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js.map +1 -0
  124. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.d.ts +40 -0
  125. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js +190 -0
  126. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js.map +1 -0
  127. package/dist-client/pages/kpi-value/kpi-value-importer.d.ts +23 -0
  128. package/dist-client/pages/kpi-value/kpi-value-importer.js +93 -0
  129. package/dist-client/pages/kpi-value/kpi-value-importer.js.map +1 -0
  130. package/dist-client/pages/kpi-value/kpi-value-list-page.d.ts +71 -0
  131. package/dist-client/pages/kpi-value/kpi-value-list-page.js +454 -0
  132. package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -0
  133. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.d.ts +69 -0
  134. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js +790 -0
  135. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js.map +1 -0
  136. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.d.ts +22 -0
  137. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js +344 -0
  138. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js.map +1 -0
  139. package/dist-client/pages/project-complete-tabs/pc-tab3-upload.d.ts +21 -0
  140. package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js +335 -0
  141. package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js.map +1 -0
  142. package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.d.ts +51 -0
  143. package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.js +693 -0
  144. package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.js.map +1 -0
  145. package/dist-client/pages/sv-project-complete.d.ts +31 -0
  146. package/dist-client/pages/sv-project-complete.js +359 -0
  147. package/dist-client/pages/sv-project-complete.js.map +1 -0
  148. package/dist-client/pages/sv-project-completed-list.d.ts +27 -0
  149. package/dist-client/pages/sv-project-completed-list.js +416 -0
  150. package/dist-client/pages/sv-project-completed-list.js.map +1 -0
  151. package/dist-client/pages/sv-project-detail.d.ts +73 -0
  152. package/dist-client/pages/sv-project-detail.js +1501 -0
  153. package/dist-client/pages/sv-project-detail.js.map +1 -0
  154. package/dist-client/pages/sv-project-list.d.ts +175 -0
  155. package/dist-client/pages/sv-project-list.js +581 -0
  156. package/dist-client/pages/sv-project-list.js.map +1 -0
  157. package/dist-client/pages/sv-project-update.d.ts +91 -0
  158. package/dist-client/pages/sv-project-update.js +1150 -0
  159. package/dist-client/pages/sv-project-update.js.map +1 -0
  160. package/dist-client/pages/sv-user-management.d.ts +6 -0
  161. package/dist-client/pages/sv-user-management.js +224 -0
  162. package/dist-client/pages/sv-user-management.js.map +1 -0
  163. package/dist-client/route.d.ts +1 -0
  164. package/dist-client/route.js +58 -0
  165. package/dist-client/route.js.map +1 -0
  166. package/dist-client/shared/complete-api.d.ts +45 -0
  167. package/dist-client/shared/complete-api.js +274 -0
  168. package/dist-client/shared/complete-api.js.map +1 -0
  169. package/dist-client/shared/func.d.ts +2 -0
  170. package/dist-client/shared/func.js +22 -0
  171. package/dist-client/shared/func.js.map +1 -0
  172. package/dist-client/shared/geo-group-mapping.d.ts +25 -0
  173. package/dist-client/shared/geo-group-mapping.js +189 -0
  174. package/dist-client/shared/geo-group-mapping.js.map +1 -0
  175. package/dist-client/shared/integration-fetch.d.ts +35 -0
  176. package/dist-client/shared/integration-fetch.js +53 -0
  177. package/dist-client/shared/integration-fetch.js.map +1 -0
  178. package/dist-client/shared/kpi-project-sync.d.ts +16 -0
  179. package/dist-client/shared/kpi-project-sync.js +129 -0
  180. package/dist-client/shared/kpi-project-sync.js.map +1 -0
  181. package/dist-client/themes/dark.css +51 -0
  182. package/dist-client/themes/light.css +51 -0
  183. package/dist-client/tsconfig.tsbuildinfo +1 -0
  184. package/dist-client/viewparts/menu-tools.d.ts +62 -0
  185. package/dist-client/viewparts/menu-tools.js +554 -0
  186. package/dist-client/viewparts/menu-tools.js.map +1 -0
  187. package/dist-client/viewparts/user-circle.d.ts +5 -0
  188. package/dist-client/viewparts/user-circle.js +26 -0
  189. package/dist-client/viewparts/user-circle.js.map +1 -0
  190. package/dist-server/index.d.ts +2 -0
  191. package/dist-server/index.js +6 -0
  192. package/dist-server/index.js.map +1 -0
  193. package/dist-server/migrations/index.d.ts +1 -0
  194. package/dist-server/migrations/index.js +12 -0
  195. package/dist-server/migrations/index.js.map +1 -0
  196. package/dist-server/scripts/calculate-kpi-scores.d.ts +10 -0
  197. package/dist-server/scripts/calculate-kpi-scores.js +333 -0
  198. package/dist-server/scripts/calculate-kpi-scores.js.map +1 -0
  199. package/dist-server/scripts/load-grade-data-migration.d.ts +14 -0
  200. package/dist-server/scripts/load-grade-data-migration.js +279 -0
  201. package/dist-server/scripts/load-grade-data-migration.js.map +1 -0
  202. package/dist-server/scripts/propagate-parent-kpi-values.d.ts +14 -0
  203. package/dist-server/scripts/propagate-parent-kpi-values.js +786 -0
  204. package/dist-server/scripts/propagate-parent-kpi-values.js.map +1 -0
  205. package/dist-server/scripts/recalculate-by-project-name.d.ts +2 -0
  206. package/dist-server/scripts/recalculate-by-project-name.js +72 -0
  207. package/dist-server/scripts/recalculate-by-project-name.js.map +1 -0
  208. package/dist-server/service/index.d.ts +4 -0
  209. package/dist-server/service/index.js +20 -0
  210. package/dist-server/service/index.js.map +1 -0
  211. package/dist-server/service/kpi-metric-value/index.d.ts +4 -0
  212. package/dist-server/service/kpi-metric-value/index.js +8 -0
  213. package/dist-server/service/kpi-metric-value/index.js.map +1 -0
  214. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.d.ts +198 -0
  215. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +1067 -0
  216. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -0
  217. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.d.ts +15 -0
  218. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js +72 -0
  219. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js.map +1 -0
  220. package/dist-server/service/kpi-stat/index.d.ts +4 -0
  221. package/dist-server/service/kpi-stat/index.js +8 -0
  222. package/dist-server/service/kpi-stat/index.js.map +1 -0
  223. package/dist-server/service/kpi-stat/kpi-stat-query.d.ts +13 -0
  224. package/dist-server/service/kpi-stat/kpi-stat-query.js +751 -0
  225. package/dist-server/service/kpi-stat/kpi-stat-query.js.map +1 -0
  226. package/dist-server/service/kpi-stat/kpi-stat-types.d.ts +32 -0
  227. package/dist-server/service/kpi-stat/kpi-stat-types.js +180 -0
  228. package/dist-server/service/kpi-stat/kpi-stat-types.js.map +1 -0
  229. package/dist-server/service/kpi-value/index.d.ts +3 -0
  230. package/dist-server/service/kpi-value/index.js +7 -0
  231. package/dist-server/service/kpi-value/index.js.map +1 -0
  232. package/dist-server/service/kpi-value/kpi-value-query.d.ts +8 -0
  233. package/dist-server/service/kpi-value/kpi-value-query.js +90 -0
  234. package/dist-server/service/kpi-value/kpi-value-query.js.map +1 -0
  235. package/dist-server/tsconfig.tsbuildinfo +1 -0
  236. package/package.json +5 -5
@@ -0,0 +1,1150 @@
1
+ import { __decorate, __metadata } from "tslib";
2
+ import '@material/web/icon/icon.js';
3
+ import '@material/web/button/elevated-button.js';
4
+ import '@material/web/textfield/outlined-text-field.js';
5
+ import { PageView } from '@operato/shell';
6
+ import { css, html } from 'lit';
7
+ import { customElement, state } from 'lit/decorators.js';
8
+ import { ScopedElementsMixin } from '@open-wc/scoped-elements';
9
+ import { client } from '@operato/graphql';
10
+ import { notify } from '@operato/layout';
11
+ import { OxPrompt } from '@operato/popup';
12
+ import gql from 'graphql-tag';
13
+ import { SiteType } from '@dssp/project/dist-client/pages/project/project-list';
14
+ import '@dssp/project/dist-client/pages/lib/select2-component';
15
+ import './component/project-update-header';
16
+ import { isProjectTypeDomain, tenantHeaders } from '@dssp/project/dist-client/shared/domain-context';
17
+ import { inferGeoGroupFromPostalCode } from '../shared/geo-group-mapping';
18
+ import { syncProjectInfoToKpi } from '../shared/kpi-project-sync';
19
+ let SvProjectUpdate = class SvProjectUpdate extends ScopedElementsMixin(PageView) {
20
+ constructor() {
21
+ super(...arguments);
22
+ this.defaultProject = {
23
+ name: '',
24
+ documentNaming: '',
25
+ buildingComplex: {
26
+ address: '',
27
+ area: 0,
28
+ constructionCompany: '',
29
+ clientCompany: '',
30
+ supervisoryCompany: '',
31
+ designCompany: '',
32
+ constructionType: '',
33
+ buildings: []
34
+ }
35
+ };
36
+ this.projectId = '';
37
+ this.project = Object.assign({}, this.defaultProject);
38
+ this.selectedValues = [];
39
+ this.overallConstructorList = [];
40
+ this.taskConstructorList = [];
41
+ this.taskSupervisoryList = [];
42
+ this.overallSupervisoryList = [];
43
+ this.collectingBasicInfo = false;
44
+ /**
45
+ * 완료(COMPLETED) 상태 프로젝트를 진행중(ONGOING) 으로 되돌림.
46
+ * ProjectPatch 의 state 필드만 갱신 — 다른 폼 필드는 건드리지 않음.
47
+ */
48
+ this._onUnfinalize = async () => {
49
+ var _a, _b;
50
+ if (!((_a = this.project) === null || _a === void 0 ? void 0 : _a.id))
51
+ return;
52
+ const ok = await OxPrompt.open({
53
+ title: '완료 상태 해제',
54
+ confirmButton: { text: '확인' },
55
+ cancelButton: { text: '취소' }
56
+ });
57
+ if (!ok)
58
+ return;
59
+ const response = await client.mutate({
60
+ mutation: gql `
61
+ mutation UpdateProject($project: ProjectPatch!) {
62
+ updateProject(project: $project) {
63
+ id
64
+ state
65
+ }
66
+ }
67
+ `,
68
+ variables: { project: { id: this.project.id, state: 'ONGOING' } },
69
+ context: { headers: tenantHeaders((_b = this.project) === null || _b === void 0 ? void 0 : _b.code) }
70
+ });
71
+ if (!response.errors) {
72
+ notify({ message: '진행중 상태로 변경되었습니다.' });
73
+ await this.initProject(this.project.id);
74
+ }
75
+ };
76
+ }
77
+ get context() {
78
+ var _a, _b;
79
+ return {
80
+ title: !isProjectTypeDomain() && ((_a = this.project) === null || _a === void 0 ? void 0 : _a.name) ? `프로젝트 정보 관리 - ${(_b = this.project) === null || _b === void 0 ? void 0 : _b.name}` : '프로젝트 정보 관리'
81
+ };
82
+ }
83
+ render() {
84
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
85
+ return html `
86
+ <dkpi-project-update-header
87
+ .projectId=${this.project.id || ''}
88
+ .projectState=${this.project.state || ''}
89
+ title="프로젝트 정보 관리"
90
+ @custom-click=${this._saveProject}
91
+ @unfinalize=${this._onUnfinalize}
92
+ ></dkpi-project-update-header>
93
+
94
+ <div body>
95
+ <div project-info>
96
+ <h3>기본 정보</h3>
97
+ <div row>
98
+ <span>프로젝트명</span>
99
+ <span
100
+ ><md-outlined-text-field
101
+ type="text"
102
+ name="name"
103
+ project
104
+ .value=${this.project.name || ''}
105
+ @input=${this._onInputChange}
106
+ ></md-outlined-text-field>
107
+ </span>
108
+ </div>
109
+ <div row>
110
+ <span>프로젝트 주소</span>
111
+ <span class="address-row">
112
+ <md-outlined-text-field
113
+ type="text"
114
+ name="address"
115
+ building-complex
116
+ .value=${((_b = (_a = this.project) === null || _a === void 0 ? void 0 : _a.buildingComplex) === null || _b === void 0 ? void 0 : _b.address) || ''}
117
+ @input=${this._onInputChange}
118
+ ></md-outlined-text-field>
119
+ <md-elevated-button
120
+ class="info-link-btn"
121
+ ?disabled=${this.collectingBasicInfo}
122
+ @click=${() => this._collectBasicInfo()}
123
+ title="입력된 주소로 세움터 건축물대장 정보를 가져와 폼을 채웁니다"
124
+ >
125
+ ${this.collectingBasicInfo ? '연동 중…' : '🔗 정보 연동'}
126
+ </md-elevated-button>
127
+ </span>
128
+ </div>
129
+ <div row>
130
+ <span>우편번호</span>
131
+ <span>
132
+ <md-outlined-text-field
133
+ type="text"
134
+ name="postalCode"
135
+ project
136
+ .value=${this.project.postalCode || ''}
137
+ @input=${this._onPostalCodeChange}
138
+ ></md-outlined-text-field>
139
+ </span>
140
+ </div>
141
+ <div row>
142
+ <span>연면적</span>
143
+ <span align-end
144
+ ><md-outlined-text-field
145
+ type="text"
146
+ name="area"
147
+ numeric
148
+ building-complex
149
+ .value=${((_e = (_d = (_c = this.project) === null || _c === void 0 ? void 0 : _c.buildingComplex) === null || _d === void 0 ? void 0 : _d.area) === null || _e === void 0 ? void 0 : _e.toString()) || ''}
150
+ @input=${this._onInputChange}
151
+ suffix-text="㎡"
152
+ ></md-outlined-text-field>
153
+ </span>
154
+ </div>
155
+
156
+ <div row>
157
+ <span>용적률</span>
158
+ <span align-end>
159
+ <md-outlined-text-field
160
+ type="text"
161
+ name="floorAreaRatio"
162
+ numeric
163
+ building-complex
164
+ .value=${((_h = (_g = (_f = this.project) === null || _f === void 0 ? void 0 : _f.buildingComplex) === null || _g === void 0 ? void 0 : _g.floorAreaRatio) === null || _h === void 0 ? void 0 : _h.toString()) || ''}
165
+ @input=${this._onInputChange}
166
+ suffix-text="%"
167
+ ></md-outlined-text-field>
168
+ </span>
169
+ </div>
170
+
171
+ <div row>
172
+ <span>착공일정 ~ 준공일정(계획)</span>
173
+ <span
174
+ ><input
175
+ type="date"
176
+ name="startDate"
177
+ project
178
+ .value=${this.project.startDate || ''}
179
+ @input=${this._onInputChange}
180
+ max="9999-12-31"
181
+ />
182
+ ~
183
+ <input
184
+ type="date"
185
+ name="endDate"
186
+ project
187
+ .value=${this.project.endDate || ''}
188
+ @input=${this._onInputChange}
189
+ max="9999-12-31"
190
+ />
191
+ </span>
192
+ </div>
193
+
194
+ <div row>
195
+ <span>유형</span>
196
+ <span
197
+ ><md-filled-select name="sectorType" project @change=${this._onInputChange}>
198
+ <md-select-option ?selected=${!this.project.sectorType} value="">
199
+ <div slot="headline">선택</div>
200
+ </md-select-option>
201
+ <md-select-option ?selected=${this.project.sectorType === 'PUBLIC'} value="PUBLIC">
202
+ <div slot="headline">공공</div>
203
+ </md-select-option>
204
+ <md-select-option ?selected=${this.project.sectorType === 'PRIVATE'} value="PRIVATE">
205
+ <div slot="headline">민간</div>
206
+ </md-select-option>
207
+ </md-filled-select>
208
+ </span>
209
+ </div>
210
+ <div row>
211
+ <span>용도</span>
212
+ <span
213
+ ><md-filled-select name="buildingUsage" project @change=${this._onInputChange}>
214
+ <md-select-option ?selected=${!this.project.buildingUsage} value="">
215
+ <div slot="headline">선택</div>
216
+ </md-select-option>
217
+ <md-select-option ?selected=${this.project.buildingUsage === 'RESIDENTIAL'} value="RESIDENTIAL">
218
+ <div slot="headline">주거</div>
219
+ </md-select-option>
220
+ <md-select-option ?selected=${this.project.buildingUsage === 'NON_RESIDENTIAL'} value="NON_RESIDENTIAL">
221
+ <div slot="headline">비주거</div>
222
+ </md-select-option>
223
+ </md-filled-select>
224
+ </span>
225
+ </div>
226
+
227
+ <div row>
228
+ <span>발주처</span>
229
+ <span
230
+ ><md-outlined-text-field
231
+ type="text"
232
+ name="clientCompany"
233
+ building-complex
234
+ .value=${((_k = (_j = this.project) === null || _j === void 0 ? void 0 : _j.buildingComplex) === null || _k === void 0 ? void 0 : _k.clientCompany) || ''}
235
+ @input=${this._onInputChange}
236
+ ></md-outlined-text-field>
237
+ </span>
238
+ </div>
239
+ <div row>
240
+ <span>건설사</span>
241
+ <span
242
+ ><md-outlined-text-field
243
+ type="text"
244
+ name="constructionCompany"
245
+ building-complex
246
+ .value=${((_m = (_l = this.project) === null || _l === void 0 ? void 0 : _l.buildingComplex) === null || _m === void 0 ? void 0 : _m.constructionCompany) || ''}
247
+ @input=${this._onInputChange}
248
+ ></md-outlined-text-field>
249
+ </span>
250
+ </div>
251
+ <div row>
252
+ <span>설계사</span>
253
+ <span
254
+ ><md-outlined-text-field
255
+ type="text"
256
+ name="designCompany"
257
+ building-complex
258
+ .value=${((_p = (_o = this.project) === null || _o === void 0 ? void 0 : _o.buildingComplex) === null || _p === void 0 ? void 0 : _p.designCompany) || ''}
259
+ @input=${this._onInputChange}
260
+ ></md-outlined-text-field>
261
+ </span>
262
+ </div>
263
+ <div row>
264
+ <span>감리사</span>
265
+ <span
266
+ ><md-outlined-text-field
267
+ type="text"
268
+ name="supervisoryCompany"
269
+ building-complex
270
+ .value=${((_r = (_q = this.project) === null || _q === void 0 ? void 0 : _q.buildingComplex) === null || _r === void 0 ? void 0 : _r.supervisoryCompany) || ''}
271
+ @input=${this._onInputChange}
272
+ ></md-outlined-text-field>
273
+ </span>
274
+ </div>
275
+
276
+ <div row>
277
+ <span>대표사진 업로드</span>
278
+ <span>
279
+ <ox-input-image
280
+ name="mainPhoto"
281
+ value=${((_t = (_s = this.project) === null || _s === void 0 ? void 0 : _s.mainPhoto) === null || _t === void 0 ? void 0 : _t.fullpath) || ''}
282
+ @change=${this.onCreateAttachment.bind(this)}
283
+ ></ox-input-image>
284
+ </span>
285
+ </div>
286
+ <div row>
287
+ <span>계획공사비</span>
288
+ <span
289
+ ><md-outlined-text-field
290
+ type="text"
291
+ name="constructionCost"
292
+ numeric
293
+ building-complex
294
+ .value=${((_w = (_v = (_u = this.project) === null || _u === void 0 ? void 0 : _u.buildingComplex) === null || _v === void 0 ? void 0 : _v.constructionCost) === null || _w === void 0 ? void 0 : _w.toString()) || ''}
295
+ @input=${this._onInputChange}
296
+ suffix-text="억원"
297
+ ></md-outlined-text-field>
298
+ </span>
299
+ </div>
300
+ <div row>
301
+ <span>총 투입인력(M/M)</span>
302
+ <span
303
+ ><md-outlined-text-field
304
+ type="text"
305
+ name="workerCount"
306
+ numeric
307
+ building-complex
308
+ .value=${((_z = (_y = (_x = this.project) === null || _x === void 0 ? void 0 : _x.buildingComplex) === null || _y === void 0 ? void 0 : _y.workerCount) === null || _z === void 0 ? void 0 : _z.toString()) || ''}
309
+ @input=${this._onInputChange}
310
+ suffix-text="(M/M)"
311
+ ></md-outlined-text-field>
312
+ </span>
313
+ </div>
314
+ </div>
315
+
316
+ <div detail-info>
317
+ <div>
318
+ <h3>테넌트 관리</h3>
319
+ <div row>
320
+ <span>관리번호</span>
321
+ <span>
322
+ ${this.project.tenantDomain
323
+ ? html `<a href=${`/project/${this.project.code}/`} target="_blank" title="테넌트로 이동"
324
+ >${this.project.code} <md-icon style="font-size:14px;vertical-align:middle">open_in_new</md-icon></a
325
+ >`
326
+ : this.project.code
327
+ ? html `${this.project.code}`
328
+ : html `<span style="color:#999">미발번 (승격 시 자동 부여)</span>`}
329
+ </span>
330
+ </div>
331
+ <div row>
332
+ <span>현재 상태</span>
333
+ <span>
334
+ ${this.project.tenantDomain
335
+ ? html `<b style="color:#42b382">활성 테넌트</b>`
336
+ : this.project.code
337
+ ? html `<b style="color:#aa6633">강등됨</b> (재승격 시 ${this.project.code} 재사용)`
338
+ : html `<b style="color:#999">미승격</b>`}
339
+ </span>
340
+ </div>
341
+ <div row>
342
+ <span></span>
343
+ <span tenant-actions>
344
+ ${this.project.tenantDomain
345
+ ? html `<md-elevated-button @click=${this._demoteTenant} ?disabled=${!this.project.id}>
346
+ <md-icon slot="icon">link_off</md-icon>테넌트 강등
347
+ </md-elevated-button>`
348
+ : html `<md-elevated-button green @click=${this._promoteTenant} ?disabled=${!this.project.id}>
349
+ <md-icon slot="icon">verified</md-icon>테넌트 승격
350
+ </md-elevated-button>`}
351
+ </span>
352
+ </div>
353
+ </div>
354
+ </div>
355
+ </div>
356
+ `;
357
+ }
358
+ async pageInitialized(lifecycle) { }
359
+ async pageUpdated(changes, lifecycle) {
360
+ if (!this.active)
361
+ return;
362
+ this.projectId = await this._resolveProjectId(lifecycle.resourceId || '');
363
+ await this.initProject(this.projectId);
364
+ }
365
+ /**
366
+ * resourceId 를 정상 Project.id (UUID) 로 변환한다.
367
+ * - UUID 형식이면 그대로 사용
368
+ * - 그 외 (code 또는 비어있음) 에는 현재 테넌트 컨텍스트의 프로젝트 조회
369
+ */
370
+ async _resolveProjectId(resourceId) {
371
+ var _a, _b;
372
+ if (resourceId && resourceId.length === 36)
373
+ return resourceId;
374
+ const response = await client.query({
375
+ query: gql `
376
+ query CurrentProject {
377
+ currentProject {
378
+ id
379
+ }
380
+ }
381
+ `
382
+ });
383
+ return ((_b = (_a = response.data) === null || _a === void 0 ? void 0 : _a.currentProject) === null || _b === void 0 ? void 0 : _b.id) || '';
384
+ }
385
+ async initProject(projectId = '') {
386
+ var _a, _b, _c, _d;
387
+ const response = await client.query({
388
+ query: gql `
389
+ query Project($id: String!, $filters: [Filter!]) {
390
+ project(id: $id) {
391
+ id
392
+ code
393
+ state
394
+ tenantDomain {
395
+ id
396
+ subdomain
397
+ name
398
+ }
399
+ name
400
+ documentNaming
401
+ sectorType
402
+ buildingUsage
403
+ postalCode
404
+ geoGroup
405
+ startDate
406
+ endDate
407
+ mainPhoto {
408
+ fullpath
409
+ }
410
+ totalProgress
411
+ weeklyProgress
412
+ kpi
413
+ inspPassRate
414
+ robotProgressRate
415
+ structuralSafetyRate
416
+ robotCount
417
+ buildingComplex {
418
+ id
419
+ address
420
+ siteType
421
+ latitude
422
+ longitude
423
+ area
424
+ coverageRatio
425
+ floorAreaRatio
426
+ structureType
427
+ workerCount
428
+ designChangeCount
429
+ plannedProgress
430
+ actualProgress
431
+ clientCompany
432
+ constructionCompany
433
+ supervisoryCompany
434
+ designCompany
435
+ drawing {
436
+ id
437
+ name
438
+ }
439
+ constructionType
440
+ constructionCost
441
+ etc
442
+ notice
443
+ householdCount
444
+ buildingCount
445
+ overallConstructorEmails
446
+ taskConstructorEmails
447
+ overallSupervisoryEmails
448
+ taskSupervisoryEmails
449
+ virtualTourLink
450
+ buildings {
451
+ id
452
+ name
453
+ floorCount
454
+ hasBasement
455
+ basementFloorCount
456
+ }
457
+ }
458
+ }
459
+
460
+ employees(filters: $filters) {
461
+ items {
462
+ id
463
+ name
464
+ jobResponsibility
465
+ active
466
+ user {
467
+ id
468
+ name
469
+ email
470
+ }
471
+ }
472
+ }
473
+ }
474
+ `,
475
+ variables: {
476
+ id: projectId,
477
+ filters: [
478
+ {
479
+ name: 'active',
480
+ operator: 'eq',
481
+ value: true
482
+ },
483
+ {
484
+ name: 'userId',
485
+ operator: 'is_not_null',
486
+ value: ''
487
+ }
488
+ ]
489
+ },
490
+ context: { headers: tenantHeaders((_a = this.project) === null || _a === void 0 ? void 0 : _a.code) }
491
+ });
492
+ this.project = ((_b = response.data) === null || _b === void 0 ? void 0 : _b.project) || Object.assign({}, this.defaultProject);
493
+ const items = ((_d = (_c = response.data) === null || _c === void 0 ? void 0 : _c.employees) === null || _d === void 0 ? void 0 : _d.items) || [];
494
+ this.overallConstructorList = this._filterUserByPermission(items, 'OVERALL_CONSTRUCTOR');
495
+ this.taskConstructorList = this._filterUserByPermission(items, 'TASK_CONSTRUCTOR');
496
+ this.overallSupervisoryList = this._filterUserByPermission(items, 'OVERALL_SUPERVISORY');
497
+ this.taskSupervisoryList = this._filterUserByPermission(items, 'TASK_SUPERVISORY');
498
+ this.updateContext();
499
+ }
500
+ _filterUserByPermission(userList, permission) {
501
+ return userList
502
+ .filter(v => v.jobResponsibility == permission || v.jobResponsibility == 'ADMIN')
503
+ .map(v => ({ name: v.name, value: v.user.email }));
504
+ }
505
+ _stripTypename(obj) {
506
+ if (Array.isArray(obj)) {
507
+ return obj.map(item => this._stripTypename(item));
508
+ }
509
+ if (obj && typeof obj === 'object' && !(obj instanceof File)) {
510
+ const cleaned = {};
511
+ for (const [key, value] of Object.entries(obj)) {
512
+ if (key === '__typename')
513
+ continue;
514
+ cleaned[key] = this._stripTypename(value);
515
+ }
516
+ return cleaned;
517
+ }
518
+ return obj;
519
+ }
520
+ async _saveProject() {
521
+ var _a;
522
+ // 첨부 파일 필드 제거 (첨부 파일은 {filename}Upload 로 전송)
523
+ delete this.project.mainPhoto;
524
+ delete this.project.buildingComplex.drawing;
525
+ // ProjectPatch 입력 타입에 없는 표시 전용 필드 제거 (테넌트 승격 UI 표시용)
526
+ const projectCode = this.project.code; // 도메인 헤더 용으로 미리 보존
527
+ delete this.project.code;
528
+ delete this.project.tenantDomain;
529
+ // state 는 raw 값('10'/'20')으로 로드되지만 ProjectPatch 는 enum 키 기대 — 일반
530
+ // save 에서는 state 변경 의도 없으므로 patch 에서 제외. (state 변경은 _onUnfinalize 별도)
531
+ delete this.project.state;
532
+ // buildingComplex.siteType 가 SiteType enum 외 값 ('BUILDING' 같은 옛 잔재) 이면
533
+ // mutation validation 실패. enum 에 없으면 null 로 정정.
534
+ const validSiteTypes = new Set(Object.values(SiteType));
535
+ if (((_a = this.project.buildingComplex) === null || _a === void 0 ? void 0 : _a.siteType) && !validSiteTypes.has(this.project.buildingComplex.siteType)) {
536
+ this.project.buildingComplex.siteType = null;
537
+ }
538
+ const response = await client.mutate({
539
+ mutation: gql `
540
+ mutation UpdateProject($project: ProjectPatch!) {
541
+ updateProject(project: $project) {
542
+ id
543
+ }
544
+ }
545
+ `,
546
+ variables: {
547
+ project: this._stripTypename(this.project)
548
+ },
549
+ context: {
550
+ hasUpload: true,
551
+ headers: tenantHeaders(projectCode)
552
+ }
553
+ });
554
+ if (!response.errors) {
555
+ // 양방향 동기 — 연면적/용적률/투입인력/설계변경건을 KPI 기준정보(KpiMetricValue)에 반영하고,
556
+ // 공사일정(startDate/endDate)은 KPI "계획기간"(constructionPeriod)으로 단방향 반영.
557
+ // 보조 동기 실패가 저장 성공 UX 를 막지 않도록 warn 만.
558
+ try {
559
+ await syncProjectInfoToKpi(this.project, projectCode);
560
+ }
561
+ catch (e) {
562
+ console.warn('[프로젝트정보→KPI] KpiMetricValue 동기 실패', e);
563
+ }
564
+ notify({ message: '저장에 성공하였습니다.' });
565
+ }
566
+ }
567
+ /**
568
+ * 주소 옆 "정보 연동" 버튼 handler.
569
+ * - 현재 폼의 주소를 backend 로 보냄 → backend 가 EnvVar 갱신 + 세움터 시나리오 호출
570
+ * - 결과 (한글 raw + 숫자) 를 받아 BuildingComplex 폼 필드들에 매핑
571
+ * · siteType (한글) → SiteType enum 변환 (BC.siteType, enum 컬럼)
572
+ * · siteType (한글) → BC.constructionType 그대로 (자유 텍스트 컬럼)
573
+ * · area / floorAreaRatio / coverageRatio / householdCount / buildingCount /
574
+ * structureType → BC 동명 컬럼에 직접 대입
575
+ * · upperFloorCount / lowerFloorCount / bldNm / useAprDay / pmsDay → BC 컬럼
576
+ * 없음, 매핑 skip (참고용 콘솔 로그만)
577
+ */
578
+ async _collectBasicInfo() {
579
+ var _a, _b, _c, _d;
580
+ const address = (((_b = (_a = this.project) === null || _a === void 0 ? void 0 : _a.buildingComplex) === null || _b === void 0 ? void 0 : _b.address) || '').trim();
581
+ if (!address) {
582
+ notify({ message: '먼저 프로젝트 주소를 입력해 주세요.' });
583
+ return;
584
+ }
585
+ this.collectingBasicInfo = true;
586
+ try {
587
+ const response = await client.mutate({
588
+ mutation: gql `
589
+ mutation CollectProjectBasicInfo($projectId: String!, $address: String) {
590
+ collectProjectBasicInfo(projectId: $projectId, address: $address) {
591
+ source
592
+ label
593
+ ok
594
+ message
595
+ data
596
+ }
597
+ }
598
+ `,
599
+ variables: { projectId: this.project.id, address },
600
+ context: { headers: tenantHeaders((_c = this.project) === null || _c === void 0 ? void 0 : _c.code) }
601
+ });
602
+ if (response.errors) {
603
+ throw new Error(response.errors.map((e) => e.message).join('\n'));
604
+ }
605
+ const result = (_d = response.data) === null || _d === void 0 ? void 0 : _d.collectProjectBasicInfo;
606
+ if (!(result === null || result === void 0 ? void 0 : result.ok)) {
607
+ notify({ message: (result === null || result === void 0 ? void 0 : result.message) || '업데이트할 정보가 없습니다.' });
608
+ return;
609
+ }
610
+ const data = result.data || {};
611
+ this._applyBasicInfoToForm(data);
612
+ this.requestUpdate();
613
+ notify({ message: '외부 시스템에서 기본 정보를 가져왔습니다. 검토 후 [저장]을 눌러주세요.' });
614
+ }
615
+ catch (err) {
616
+ console.warn('[정보 연동] 실패', err);
617
+ notify({ message: '외부 시스템 연동이 일시적으로 안 됩니다.' });
618
+ }
619
+ finally {
620
+ this.collectingBasicInfo = false;
621
+ }
622
+ }
623
+ /**
624
+ * 한글 주용도명 → SiteType enum.
625
+ * - NFC normalize + 공백 제거로 보이지 않는 문자/표기 차이 대응
626
+ * - 매핑 미존재시 null
627
+ */
628
+ _siteTypeFromKorean(korean) {
629
+ if (!korean)
630
+ return null;
631
+ const KEYS = {
632
+ 공동주택: 'APARTMENT_COMPLEX',
633
+ 단독주택: 'DETACHED_HOUSE',
634
+ 제1종근린생활시설: 'NEIGHBORHOOD_FACILITY',
635
+ 제2종근린생활시설: 'NEIGHBORHOOD_FACILITY',
636
+ 근린생활시설: 'NEIGHBORHOOD_FACILITY',
637
+ 업무시설: 'OFFICE',
638
+ 판매시설: 'COMMERCIAL',
639
+ 교육연구시설: 'EDUCATION',
640
+ 의료시설: 'MEDICAL',
641
+ 문화및집회시설: 'CULTURAL',
642
+ 종교시설: 'RELIGIOUS',
643
+ 공장: 'INDUSTRIAL',
644
+ 창고시설: 'INDUSTRIAL',
645
+ 운수시설: 'TRANSPORT'
646
+ };
647
+ const key = korean.normalize('NFC').replace(/\s+/g, '').trim();
648
+ return KEYS[key] || null;
649
+ }
650
+ /**
651
+ * 시나리오 result data 를 폼에 매핑 — BuildingComplex 와 Project 양쪽.
652
+ * 빈 값(null/undefined/'')은 기존 값 유지 — 자동 수집이 사용자 입력을 무리하게 덮지 않도록.
653
+ */
654
+ _applyBasicInfoToForm(data) {
655
+ const bc = Object.assign({}, this.project.buildingComplex);
656
+ const setBC = (key, value) => {
657
+ if (value === null || value === undefined || value === '')
658
+ return;
659
+ bc[key] = value;
660
+ };
661
+ setBC('area', this._toNum(data.area));
662
+ setBC('floorAreaRatio', this._toNum(data.floorAreaRatio));
663
+ setBC('coverageRatio', this._toNum(data.coverageRatio));
664
+ setBC('householdCount', this._toNum(data.householdCount));
665
+ setBC('buildingCount', this._toNum(data.buildingCount));
666
+ setBC('structureType', data.structureType);
667
+ // siteType: 한글 → SiteType enum 매핑. 매핑 안 되면 BC.siteType 빈 채로.
668
+ if (data.siteType) {
669
+ const enumVal = this._siteTypeFromKorean(data.siteType);
670
+ if (enumVal)
671
+ bc.siteType = enumVal;
672
+ }
673
+ // Project 엔티티 컬럼 — 착공일/준공일.
674
+ // 세움터 useAprDay (사용승인일) = 준공으로 매핑. stcnsDay = 착공.
675
+ const project = Object.assign(Object.assign({}, this.project), { buildingComplex: bc });
676
+ if (data.startDate)
677
+ project.startDate = data.startDate;
678
+ if (data.endDate)
679
+ project.endDate = data.endDate;
680
+ this.project = project;
681
+ // 참고 메타 — BC/Project 직접 컬럼 없음, 콘솔로만 (permitDate=건축허가일, bldNm 등)
682
+ console.log('[정보 연동] meta:', JSON.stringify({
683
+ upperFloorCount: data.upperFloorCount,
684
+ lowerFloorCount: data.lowerFloorCount,
685
+ bldNm: data.bldNm,
686
+ permitDate: data.permitDate
687
+ }));
688
+ }
689
+ _toNum(v) {
690
+ if (v === null || v === undefined || v === '')
691
+ return null;
692
+ const n = Number(v);
693
+ return Number.isFinite(n) ? n : null;
694
+ }
695
+ async _promoteTenant() {
696
+ if (!this.project.id)
697
+ return;
698
+ if (!confirm('이 프로젝트를 테넌트로 승격하시겠습니까?\n승격 시 관리번호(YYYY-NNNNN)가 자동 발번되며 변경할 수 없습니다.')) {
699
+ return;
700
+ }
701
+ const response = await client.mutate({
702
+ mutation: gql `
703
+ mutation PromoteProjectToTenant($projectId: String!) {
704
+ promoteProjectToTenant(projectId: $projectId) {
705
+ id
706
+ code
707
+ }
708
+ }
709
+ `,
710
+ variables: { projectId: this.project.id }
711
+ });
712
+ if (!response.errors) {
713
+ notify({ message: `테넌트로 승격되었습니다. 관리번호: ${response.data.promoteProjectToTenant.code}` });
714
+ await this.initProject(this.projectId);
715
+ }
716
+ }
717
+ async _demoteTenant() {
718
+ if (!this.project.id)
719
+ return;
720
+ if (!confirm('이 프로젝트의 테넌트를 강등하시겠습니까?\n관리번호는 보존되며 재승격 시 같은 번호가 재사용됩니다.')) {
721
+ return;
722
+ }
723
+ const response = await client.mutate({
724
+ mutation: gql `
725
+ mutation DemoteProjectTenant($projectId: String!) {
726
+ demoteProjectTenant(projectId: $projectId)
727
+ }
728
+ `,
729
+ variables: { projectId: this.project.id }
730
+ });
731
+ if (!response.errors) {
732
+ notify({ message: '테넌트가 강등되었습니다.' });
733
+ await this.initProject(this.projectId);
734
+ }
735
+ }
736
+ // 동 적용 버튼을 누르면 입력한 수 만큼 해당 단지에 동 데이터 생성
737
+ _setBuilding() {
738
+ var _a, _b, _c, _d, _e;
739
+ const buildingCount = ((_b = (_a = this.project) === null || _a === void 0 ? void 0 : _a.buildingComplex) === null || _b === void 0 ? void 0 : _b.buildingCount) || 0;
740
+ const buildingInitData = { name: undefined, floorCount: undefined };
741
+ // 빌딩 데이터가 없으면 빈 배열 넣어줌
742
+ if (!((_e = (_d = (_c = this.project) === null || _c === void 0 ? void 0 : _c.buildingComplex) === null || _d === void 0 ? void 0 : _d.buildings) === null || _e === void 0 ? void 0 : _e.length)) {
743
+ this.project.buildingComplex.buildings = [];
744
+ }
745
+ if (this.project.buildingComplex.buildings.length >= buildingCount) {
746
+ // 동 수가 더 작게 들어오면 기존 배열을 필요한 크기만큼 잘라내기
747
+ this.project.buildingComplex.buildings = [...this.project.buildingComplex.buildings.slice(0, buildingCount)];
748
+ }
749
+ else {
750
+ // 동수가 더 크게 들어오면 기존 배열 + 빈 값을 채움
751
+ const additionalCount = buildingCount - this.project.buildingComplex.buildings.length;
752
+ const additionalBuildings = Array.from({ length: additionalCount }, () => (Object.assign({}, buildingInitData)));
753
+ this.project.buildingComplex.buildings = [...this.project.buildingComplex.buildings, ...additionalBuildings];
754
+ }
755
+ // 리렌더링
756
+ this.project = Object.assign({}, this.project);
757
+ }
758
+ // Input 요소의 값이 변경될 때 호출되는 콜백 함수
759
+ /**
760
+ * 우편번호 입력 핸들러 — postalCode 갱신과 동시에 앞 2자리 prefix 로 geoGroup
761
+ * best-guess 자동 매핑. 매핑 안 되면 기존 값 유지.
762
+ */
763
+ _onPostalCodeChange(event) {
764
+ const target = event.target;
765
+ const value = target.value;
766
+ this.project.postalCode = value;
767
+ const inferred = inferGeoGroupFromPostalCode(value);
768
+ if (inferred)
769
+ this.project.geoGroup = inferred;
770
+ }
771
+ _onInputChange(event, idx) {
772
+ const target = event.target;
773
+ let inputVal = target.value;
774
+ // 숫자 타입은 다른 문자 입력 제거
775
+ if (target.hasAttribute('numeric')) {
776
+ inputVal = Number(inputVal.replace(/[^\d.]/g, ''));
777
+ }
778
+ if (target.hasAttribute('project')) {
779
+ this.project[target.name] = inputVal;
780
+ // documentNaming 필드가 변경되면 실시간으로 미리보기 업데이트
781
+ if (target.name === 'documentNaming') {
782
+ this.requestUpdate();
783
+ }
784
+ }
785
+ else if (target.hasAttribute('building-complex')) {
786
+ this.project.buildingComplex[target.name] = inputVal;
787
+ }
788
+ else if (target.hasAttribute('building')) {
789
+ this.project.buildingComplex.buildings[idx][target.name] = inputVal;
790
+ }
791
+ }
792
+ // 이미지 업로드
793
+ async onCreateAttachment(e) {
794
+ const target = e.target;
795
+ const file = (target.name === 'mainPhoto' ? e.detail : e.detail[0]) || null;
796
+ if (target.name === 'mainPhoto') {
797
+ this.project.mainPhotoUpload = file;
798
+ }
799
+ else {
800
+ this.project.buildingComplex.drawingUpload = file;
801
+ }
802
+ }
803
+ _handleSelectionChange(e) {
804
+ const name = e.target.getAttribute('name');
805
+ const selectedValues = e.detail.selectedValues;
806
+ this.project.buildingComplex[name] = selectedValues;
807
+ }
808
+ _toggleBasement(idx) {
809
+ const building = this.project.buildingComplex.buildings[idx];
810
+ building.hasBasement = !building.hasBasement;
811
+ // 층 수가 0이거나 체크 해제시 지하층수 초기화 (플레이스 홀더 나오게 하기 위함)
812
+ if (building.basementFloorCount == 0 || !building.hasBasement) {
813
+ building.basementFloorCount = undefined;
814
+ }
815
+ this.project.buildingComplex.buildings[idx]['hasBasement'] = building.hasBasement;
816
+ this.requestUpdate();
817
+ }
818
+ };
819
+ SvProjectUpdate.styles = [
820
+ css `
821
+ :host {
822
+ display: grid;
823
+ grid-template-rows: 55px auto;
824
+ color: #4e5055;
825
+
826
+ width: 100%;
827
+ background-color: var(--md-sys-color-background, #f6f6f6);
828
+ overflow-y: auto;
829
+
830
+ --grid-record-emphasized-background-color: red;
831
+ --grid-record-emphasized-color: yellow;
832
+ }
833
+
834
+ md-outlined-text-field {
835
+ width: 100%;
836
+
837
+ --md-outlined-text-field-container-shape: 5px;
838
+ --md-outlined-text-field-outline-color: rgba(51, 51, 51, 0.2);
839
+ --md-outlined-text-field-focus-outline-color: #1f7fd9;
840
+ --md-outlined-text-field-focus-outline-width: 1px;
841
+ --md-sys-color-primary: #586878;
842
+ --md-outlined-text-field-input-text-size: 14px;
843
+ --md-outlined-field-bottom-space: 3px;
844
+ --md-outlined-field-top-space: 3px;
845
+ --md-outlined-field-leading-space: var(--spacing-medium, 8px);
846
+ --md-outlined-field-trailing-space: var(--spacing-medium, 8px);
847
+ }
848
+ select2-component {
849
+ width: 100%;
850
+ }
851
+ md-filled-select {
852
+ width: 100%;
853
+ --md-filled-select-text-field-container-color: transparent;
854
+ --md-filled-select-text-field-active-indicator-color: #999;
855
+ --md-filled-select-text-field-input-text-size: 14px;
856
+ --md-filled-select-text-field-input-text-line-height: 6px;
857
+ }
858
+ input[type='date'] {
859
+ border: 1px solid rgba(51, 51, 51, 0.2);
860
+ padding: var(--spacing-small, 4px) var(--spacing-medium, 8px);
861
+ border-radius: 5px;
862
+ }
863
+ md-outlined-text-field[type='textarea'] {
864
+ width: 100%;
865
+ height: 120px;
866
+ resize: none;
867
+ }
868
+
869
+ ox-input-image {
870
+ width: 120px;
871
+ height: 90px;
872
+ }
873
+ ox-input-file {
874
+ width: 120px;
875
+ height: 90px;
876
+ padding: 0;
877
+ }
878
+
879
+ div[body] {
880
+ display: flex;
881
+ margin: var(--spacing-large, 12px);
882
+ margin-top: 0;
883
+ gap: var(--spacing-medium, 8px);
884
+
885
+ & > div {
886
+ display: flex;
887
+ height: fit-content;
888
+ flex-direction: column;
889
+ padding: var(--spacing-large, 12px);
890
+ background-color: var(--md-sys-color-on-primary);
891
+ border: 1px solid #cccccc80;
892
+ border-radius: 5px;
893
+ gap: var(--spacing-medium, 8px);
894
+
895
+ h3 {
896
+ color: #2e79be;
897
+ font-size: 16px;
898
+ margin: 0px;
899
+ }
900
+
901
+ div[row] {
902
+ display: flex;
903
+ align-items: center;
904
+
905
+ span:first-child {
906
+ flex: 0.3;
907
+ text-align: right;
908
+ font-size: 14px;
909
+ }
910
+
911
+ span:last-child {
912
+ flex: 0.7;
913
+ display: flex;
914
+ gap: var(--spacing-medium, 8px);
915
+ margin-left: var(--spacing-medium, 8px);
916
+ align-items: center;
917
+
918
+ &.address-row {
919
+ md-outlined-text-field {
920
+ flex: 1;
921
+ }
922
+ .info-link-btn {
923
+ flex: 0 0 auto;
924
+ --md-elevated-button-container-color: #2e79be;
925
+ --md-elevated-button-label-text-color: #fff;
926
+ --md-elevated-button-container-height: 36px;
927
+ }
928
+ }
929
+
930
+ &[align-end] {
931
+ align-items: end;
932
+ }
933
+ }
934
+ }
935
+ }
936
+
937
+ div[project-info] {
938
+ flex: 0.55;
939
+ }
940
+
941
+ div[document-preview] {
942
+ width: 100%;
943
+ font-size: 12px;
944
+ color: #2e79be;
945
+ font-weight: 500;
946
+ background-color: #f8f9fa;
947
+ padding: 8px 12px;
948
+ border-radius: 4px;
949
+ border-left: 3px solid #2e79be;
950
+ margin-top: 4px;
951
+ }
952
+
953
+ div[detail-info] {
954
+ flex: 0.45;
955
+ padding: 0px;
956
+ gap: 10px;
957
+ background-color: transparent;
958
+ border: none;
959
+
960
+ & > div {
961
+ display: flex;
962
+ flex-direction: column;
963
+ gap: var(--spacing-medium, 8px);
964
+ border: 1px solid #cccccc80;
965
+ border-radius: 5px;
966
+ padding: var(--spacing-large, 12px);
967
+ background-color: var(--md-sys-color-on-primary);
968
+
969
+ md-outlined-text-field[type='text'] {
970
+ width: 60%;
971
+ }
972
+
973
+ md-elevated-button {
974
+ --md-elevated-button-container-height: 30px;
975
+ --md-elevated-button-container-color: var(--md-sys-color-on-primary);
976
+ --md-elevated-button-label-text-size: 16px;
977
+ }
978
+ hr {
979
+ border: 1px rgba(51, 51, 51, 0.1) dashed;
980
+ width: 100%;
981
+ margin-bottom: var(--spacing-tiny, 2px);
982
+ }
983
+ div[warn] {
984
+ font-size: 12px;
985
+ color: red;
986
+ margin-left: var(--spacing-small, 4px);
987
+ margin-bottom: var(--spacing-small, 4px);
988
+ }
989
+
990
+ md-outlined-button {
991
+ min-height: 30px;
992
+ padding: 0 var(--spacing-large, 12px);
993
+ box-shadow: 1px 1px 1px #0000001a;
994
+ --md-outlined-button-label-text-color: #586878;
995
+ --md-outlined-button-label-text-weight: bold;
996
+ --md-sys-color-outline: rgba(51, 51, 51, 0.2);
997
+ }
998
+
999
+ div[row] {
1000
+ span:first-child {
1001
+ flex: 0.2;
1002
+ }
1003
+ span:last-child {
1004
+ flex: 0.8;
1005
+ }
1006
+ }
1007
+
1008
+ div[separate-container] {
1009
+ display: grid;
1010
+ grid-template-columns: repeat(2, 1fr);
1011
+ gap: 8px 30px;
1012
+ margin-left: 15px;
1013
+
1014
+ md-outlined-text-field {
1015
+ width: 80px;
1016
+ }
1017
+
1018
+ & > div {
1019
+ display: flex;
1020
+ gap: 15px;
1021
+
1022
+ span[floor-row] {
1023
+ display: inline-flex;
1024
+ align-items: center;
1025
+ margin-left: 5px;
1026
+ }
1027
+
1028
+ span[floor-title] {
1029
+ min-width: 33px;
1030
+ margin-right: var(--spacing-small, 4px);
1031
+ }
1032
+ span:first-child {
1033
+ flex: 0.4;
1034
+ justify-content: flex-start;
1035
+ display: flex;
1036
+ }
1037
+ span:last-child {
1038
+ flex: 0.6;
1039
+ display: flex;
1040
+ align-items: center;
1041
+ padding-left: var(--spacing-medium, 8px);
1042
+ }
1043
+ }
1044
+
1045
+ div[basement-container] {
1046
+ display: flex;
1047
+ align-items: center;
1048
+ gap: 4px;
1049
+
1050
+ div[basement-checkbox] {
1051
+ display: flex;
1052
+ align-items: center;
1053
+ cursor: pointer;
1054
+
1055
+ md-icon {
1056
+ --md-icon-size: 25px;
1057
+ color: #808080;
1058
+ transition: opacity 0.2s ease;
1059
+ }
1060
+
1061
+ &[disabled] {
1062
+ cursor: not-allowed;
1063
+ opacity: 0.4;
1064
+
1065
+ md-icon {
1066
+ color: #cccccc;
1067
+ }
1068
+ }
1069
+
1070
+ &[checked] md-icon {
1071
+ background-color: #2e79be;
1072
+ color: white;
1073
+ border-radius: 3px;
1074
+ }
1075
+ }
1076
+
1077
+ md-outlined-text-field[basement-floor] {
1078
+ width: 70px;
1079
+ margin-left: var(--spacing-small, 4px);
1080
+ opacity: 1;
1081
+ transition: opacity 0.2s ease;
1082
+
1083
+ &[disabled] {
1084
+ opacity: 0.4;
1085
+ pointer-events: none;
1086
+ }
1087
+ }
1088
+ }
1089
+ }
1090
+
1091
+ &[project] {
1092
+ div[separate-container] {
1093
+ margin-left: 15px;
1094
+
1095
+ & > div {
1096
+ align-items: center;
1097
+
1098
+ span:first-child {
1099
+ flex: 0.4;
1100
+ min-width: 100px;
1101
+ }
1102
+ span:last-child {
1103
+ flex: 0.4;
1104
+ margin-left: 0;
1105
+ }
1106
+ }
1107
+ }
1108
+ }
1109
+ }
1110
+ }
1111
+ }
1112
+ `
1113
+ ];
1114
+ __decorate([
1115
+ state(),
1116
+ __metadata("design:type", String)
1117
+ ], SvProjectUpdate.prototype, "projectId", void 0);
1118
+ __decorate([
1119
+ state(),
1120
+ __metadata("design:type", Object)
1121
+ ], SvProjectUpdate.prototype, "project", void 0);
1122
+ __decorate([
1123
+ state(),
1124
+ __metadata("design:type", Array)
1125
+ ], SvProjectUpdate.prototype, "selectedValues", void 0);
1126
+ __decorate([
1127
+ state(),
1128
+ __metadata("design:type", Array)
1129
+ ], SvProjectUpdate.prototype, "overallConstructorList", void 0);
1130
+ __decorate([
1131
+ state(),
1132
+ __metadata("design:type", Array)
1133
+ ], SvProjectUpdate.prototype, "taskConstructorList", void 0);
1134
+ __decorate([
1135
+ state(),
1136
+ __metadata("design:type", Array)
1137
+ ], SvProjectUpdate.prototype, "taskSupervisoryList", void 0);
1138
+ __decorate([
1139
+ state(),
1140
+ __metadata("design:type", Array)
1141
+ ], SvProjectUpdate.prototype, "overallSupervisoryList", void 0);
1142
+ __decorate([
1143
+ state(),
1144
+ __metadata("design:type", Boolean)
1145
+ ], SvProjectUpdate.prototype, "collectingBasicInfo", void 0);
1146
+ SvProjectUpdate = __decorate([
1147
+ customElement('sv-project-update')
1148
+ ], SvProjectUpdate);
1149
+ export { SvProjectUpdate };
1150
+ //# sourceMappingURL=sv-project-update.js.map