@dssp/dcsp 1.0.2 → 1.0.5

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 (119) hide show
  1. package/dist-client/components/kpi-2d-lookup-chart.d.ts +50 -0
  2. package/dist-client/components/kpi-2d-lookup-chart.js +263 -0
  3. package/dist-client/components/kpi-2d-lookup-chart.js.map +1 -0
  4. package/dist-client/components/kpi-boxplot-chart.d.ts +31 -0
  5. package/dist-client/components/kpi-boxplot-chart.js +306 -0
  6. package/dist-client/components/kpi-boxplot-chart.js.map +1 -0
  7. package/dist-client/components/kpi-lookup-chart.d.ts +58 -0
  8. package/dist-client/components/kpi-lookup-chart.js +464 -0
  9. package/dist-client/components/kpi-lookup-chart.js.map +1 -0
  10. package/dist-client/components/kpi-mini-trend-chart.d.ts +14 -0
  11. package/dist-client/components/kpi-mini-trend-chart.js +180 -0
  12. package/dist-client/components/kpi-mini-trend-chart.js.map +1 -0
  13. package/dist-client/components/kpi-radar-chart.d.ts +17 -0
  14. package/dist-client/components/kpi-radar-chart.js +259 -0
  15. package/dist-client/components/kpi-radar-chart.js.map +1 -0
  16. package/dist-client/components/kpi-single-boxplot-chart.d.ts +36 -0
  17. package/dist-client/components/kpi-single-boxplot-chart.js +417 -0
  18. package/dist-client/components/kpi-single-boxplot-chart.js.map +1 -0
  19. package/dist-client/components/kpi-step-lookup-chart.d.ts +33 -0
  20. package/dist-client/components/kpi-step-lookup-chart.js +181 -0
  21. package/dist-client/components/kpi-step-lookup-chart.js.map +1 -0
  22. package/dist-client/components/kpi-trend-chart.d.ts +25 -0
  23. package/dist-client/components/kpi-trend-chart.js +241 -0
  24. package/dist-client/components/kpi-trend-chart.js.map +1 -0
  25. package/dist-client/google-map/common-google-map.d.ts +35 -0
  26. package/dist-client/google-map/common-google-map.js +349 -0
  27. package/dist-client/google-map/common-google-map.js.map +1 -0
  28. package/dist-client/google-map/google-map-loader.d.ts +6 -0
  29. package/dist-client/google-map/google-map-loader.js +23 -0
  30. package/dist-client/google-map/google-map-loader.js.map +1 -0
  31. package/dist-client/pages/kpi-admin/dssp-kpi-overview.d.ts +47 -0
  32. package/dist-client/pages/kpi-admin/dssp-kpi-overview.js +393 -0
  33. package/dist-client/pages/kpi-admin/dssp-kpi-overview.js.map +1 -0
  34. package/dist-client/pages/kpi-admin/kpi-system-guide.d.ts +18 -0
  35. package/dist-client/pages/kpi-admin/kpi-system-guide.js +696 -0
  36. package/dist-client/pages/kpi-admin/kpi-system-guide.js.map +1 -0
  37. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.d.ts +46 -0
  38. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js +945 -0
  39. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js.map +1 -0
  40. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.d.ts +34 -0
  41. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js +238 -0
  42. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js.map +1 -0
  43. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.d.ts +37 -0
  44. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js +689 -0
  45. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js.map +1 -0
  46. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.d.ts +57 -0
  47. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js +866 -0
  48. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js.map +1 -0
  49. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.d.ts +69 -0
  50. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js +790 -0
  51. package/dist-client/pages/project-complete-tabs/pc-tab1-plan.js.map +1 -0
  52. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.d.ts +22 -0
  53. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js +344 -0
  54. package/dist-client/pages/project-complete-tabs/pc-tab2-rating.js.map +1 -0
  55. package/dist-client/pages/project-complete-tabs/pc-tab3-upload.d.ts +21 -0
  56. package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js +335 -0
  57. package/dist-client/pages/project-complete-tabs/pc-tab3-upload.js.map +1 -0
  58. package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.d.ts +51 -0
  59. package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.js +693 -0
  60. package/dist-client/pages/project-complete-tabs/pc-tab4-monthly.js.map +1 -0
  61. package/dist-client/pages/sv-project-complete.d.ts +31 -0
  62. package/dist-client/pages/sv-project-complete.js +364 -0
  63. package/dist-client/pages/sv-project-complete.js.map +1 -0
  64. package/dist-client/pages/sv-project-detail.d.ts +73 -0
  65. package/dist-client/pages/sv-project-detail.js +1387 -0
  66. package/dist-client/pages/sv-project-detail.js.map +1 -0
  67. package/dist-client/route.d.ts +1 -1
  68. package/dist-client/route.js +15 -0
  69. package/dist-client/route.js.map +1 -1
  70. package/dist-client/shared/complete-api.d.ts +45 -0
  71. package/dist-client/shared/complete-api.js +274 -0
  72. package/dist-client/shared/complete-api.js.map +1 -0
  73. package/dist-client/shared/func.d.ts +2 -0
  74. package/dist-client/shared/func.js +22 -0
  75. package/dist-client/shared/func.js.map +1 -0
  76. package/dist-client/shared/integration-fetch.d.ts +35 -0
  77. package/dist-client/shared/integration-fetch.js +53 -0
  78. package/dist-client/shared/integration-fetch.js.map +1 -0
  79. package/dist-client/shared/kpi-project-sync.d.ts +16 -0
  80. package/dist-client/shared/kpi-project-sync.js +129 -0
  81. package/dist-client/shared/kpi-project-sync.js.map +1 -0
  82. package/dist-client/tsconfig.tsbuildinfo +1 -1
  83. package/dist-client/viewparts/menu-tools.d.ts +5 -0
  84. package/dist-client/viewparts/menu-tools.js +149 -16
  85. package/dist-client/viewparts/menu-tools.js.map +1 -1
  86. package/dist-server/index.d.ts +1 -0
  87. package/dist-server/index.js +4 -0
  88. package/dist-server/index.js.map +1 -1
  89. package/dist-server/service/index.d.ts +4 -0
  90. package/dist-server/service/index.js +19 -0
  91. package/dist-server/service/index.js.map +1 -0
  92. package/dist-server/service/kpi-metric-value/index.d.ts +4 -0
  93. package/dist-server/service/kpi-metric-value/index.js +8 -0
  94. package/dist-server/service/kpi-metric-value/index.js.map +1 -0
  95. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.d.ts +198 -0
  96. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +1067 -0
  97. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -0
  98. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.d.ts +15 -0
  99. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js +72 -0
  100. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js.map +1 -0
  101. package/dist-server/service/kpi-stat/index.d.ts +4 -0
  102. package/dist-server/service/kpi-stat/index.js +8 -0
  103. package/dist-server/service/kpi-stat/index.js.map +1 -0
  104. package/dist-server/service/kpi-stat/kpi-stat-query.d.ts +13 -0
  105. package/dist-server/service/kpi-stat/kpi-stat-query.js +751 -0
  106. package/dist-server/service/kpi-stat/kpi-stat-query.js.map +1 -0
  107. package/dist-server/service/kpi-stat/kpi-stat-types.d.ts +32 -0
  108. package/dist-server/service/kpi-stat/kpi-stat-types.js +126 -0
  109. package/dist-server/service/kpi-stat/kpi-stat-types.js.map +1 -0
  110. package/dist-server/service/kpi-value/index.d.ts +3 -0
  111. package/dist-server/service/kpi-value/index.js +7 -0
  112. package/dist-server/service/kpi-value/index.js.map +1 -0
  113. package/dist-server/service/kpi-value/kpi-value-query.d.ts +8 -0
  114. package/dist-server/service/kpi-value/kpi-value-query.js +90 -0
  115. package/dist-server/service/kpi-value/kpi-value-query.js.map +1 -0
  116. package/dist-server/tsconfig.tsbuildinfo +1 -1
  117. package/package.json +8 -7
  118. package/schema.graphql +1274 -22
  119. package/things-factory.config.js +7 -1
@@ -1,3 +1,4 @@
1
+ import '@material/web/icon/icon.js';
1
2
  import { LitElement } from 'lit';
2
3
  declare const MenuTools_base: (new (...args: any[]) => {
3
4
  _storeUnsubscribe: () => void;
@@ -9,8 +10,12 @@ export declare class MenuTools extends MenuTools_base {
9
10
  static styles: import("lit").CSSResult[];
10
11
  page?: string;
11
12
  width?: string;
13
+ openedMenuIndex: number | null;
12
14
  private menus;
13
15
  render(): import("lit-html").TemplateResult<1>;
16
+ connectedCallback(): void;
17
+ disconnectedCallback(): void;
18
+ private _closeSubmenu;
14
19
  stateChanged(state: any): void;
15
20
  }
16
21
  export {};
@@ -1,15 +1,40 @@
1
1
  import { __decorate, __metadata } from "tslib";
2
+ import '@material/web/icon/icon.js';
2
3
  import { css, html, LitElement } from 'lit';
3
4
  import { customElement, property } from 'lit/decorators.js';
4
5
  import { store, connect } from '@operato/shell';
5
- import { ICONS_PROGRESS, ICONS_COMPLETED, ICONS_SETTING } from '../icons/menu-icons';
6
+ import { ICONS_PROGRESS, ICONS_COMPLETED, ICONS_STATUS, ICONS_SETTING } from '../icons/menu-icons';
6
7
  let MenuTools = class MenuTools extends connect(store)(LitElement) {
7
8
  constructor() {
8
9
  super(...arguments);
10
+ this.openedMenuIndex = null;
9
11
  this.menus = [];
12
+ this._closeSubmenu = (e) => {
13
+ const path = e.composedPath();
14
+ if (path.includes(this)) {
15
+ // 내부 클릭이라도 실제 페이지로 이동하는 링크 클릭이면 닫는다.
16
+ const isNavLink = path.some(el => el instanceof HTMLAnchorElement &&
17
+ !!el.getAttribute('href') &&
18
+ el.getAttribute('href') !== 'javascript:void(0)');
19
+ if (!isNavLink)
20
+ return;
21
+ }
22
+ this.openedMenuIndex = null;
23
+ };
10
24
  }
11
25
  render() {
26
+ var _a;
12
27
  this.menus = [
28
+ {
29
+ name: 'KPI\nOversight',
30
+ path: 'kpi-overview',
31
+ icons: ICONS_STATUS,
32
+ submenus: [
33
+ { name: 'KPI 대시보드', path: 'kpi-dashboard-map', icon: 'dashboard' },
34
+ { name: 'KPI 개요', path: 'kpi-overview', icon: 'widget_small' },
35
+ { name: 'KPI 시스템 가이드', path: 'kpi-system-guide', icon: 'menu_book' }
36
+ ]
37
+ },
13
38
  {
14
39
  name: '진행중',
15
40
  path: 'project-list',
@@ -39,17 +64,54 @@ let MenuTools = class MenuTools extends connect(store)(LitElement) {
39
64
  var page = this.page || '';
40
65
  return html `
41
66
  <ul>
42
- ${this.menus.map(menu => html `
43
- <li>
44
- <a href=${menu.path} ?active=${!!~page.indexOf(menu.path)}>
45
- <img src=${!!~page.indexOf(menu.path) ? menu.icons[1] : menu.icons[0]} />
67
+ ${this.menus.map((menu, i) => {
68
+ /* 서브메뉴가 있으면 이동 대신 팝업을 연다 (dkpi 방식) */
69
+ const active = menu.submenus
70
+ ? menu.submenus.some(sub => !!~page.indexOf(sub.path))
71
+ : !!~page.indexOf(menu.path);
72
+ return html `
73
+ <li
74
+ @click=${menu.submenus
75
+ ? (e) => {
76
+ e.stopPropagation();
77
+ this.openedMenuIndex = i;
78
+ }
79
+ : undefined}
80
+ >
81
+ <a href=${menu.submenus ? 'javascript:void(0)' : menu.path} ?active=${active}>
82
+ <img src=${active ? menu.icons[1] : menu.icons[0]} />
46
83
  <div>${menu.name}</div>
47
84
  </a>
48
85
  </li>
49
- `)}
86
+ `;
87
+ })}
50
88
  </ul>
89
+ ${this.openedMenuIndex !== null && ((_a = this.menus[this.openedMenuIndex]) === null || _a === void 0 ? void 0 : _a.submenus)
90
+ ? html `
91
+ <div class="submenu-popup">
92
+ <ul>
93
+ ${this.menus[this.openedMenuIndex].submenus.map(sub => html `
94
+ <li>
95
+ <a href=${sub.path} ?active=${!!~page.indexOf(sub.path)}>
96
+ <md-icon>${sub.icon}</md-icon> ${sub.name}
97
+ </a>
98
+ </li>
99
+ `)}
100
+ </ul>
101
+ </div>
102
+ `
103
+ : ''}
51
104
  `;
52
105
  }
106
+ connectedCallback() {
107
+ super.connectedCallback();
108
+ // capture 단계로 등록 — stopPropagation 하는 다른 컴포넌트의 클릭에도 서브메뉴를 닫는다 (dkpi 방식)
109
+ window.addEventListener('click', this._closeSubmenu, true);
110
+ }
111
+ disconnectedCallback() {
112
+ window.removeEventListener('click', this._closeSubmenu, true);
113
+ super.disconnectedCallback();
114
+ }
53
115
  stateChanged(state) {
54
116
  this.page = state.route.page;
55
117
  this.width = state.layout.width;
@@ -58,6 +120,7 @@ let MenuTools = class MenuTools extends connect(store)(LitElement) {
58
120
  MenuTools.styles = [
59
121
  css `
60
122
  :host {
123
+ position: relative;
61
124
  display: flex;
62
125
  background-color: var(--secondary-color);
63
126
 
@@ -75,7 +138,8 @@ MenuTools.styles = [
75
138
  height: 100%;
76
139
  }
77
140
 
78
- ul {
141
+ /* 사이드바 메뉴 스타일 — 팝업 내부로 새지 않도록 직계 자식(> ul)으로 스코핑 */
142
+ :host > ul {
79
143
  display: flex;
80
144
  flex-direction: row;
81
145
 
@@ -86,24 +150,24 @@ MenuTools.styles = [
86
150
  overflow: none;
87
151
  }
88
152
 
89
- :host([width='NARROW']) ul {
153
+ :host([width='NARROW']) > ul {
90
154
  width: 100%;
91
155
  justify-content: space-around;
92
156
  }
93
157
 
94
- :host([width='WIDE']) ul {
158
+ :host([width='WIDE']) > ul {
95
159
  flex-direction: column;
96
160
  }
97
- :host([width='NARROW']) li {
161
+ :host([width='NARROW']) > ul > li {
98
162
  flex: 1;
99
163
  }
100
164
 
101
- :host([width='WIDE']) li {
165
+ :host([width='WIDE']) > ul > li {
102
166
  border-top: 1px solid rgba(255, 255, 255, 0.1);
103
167
  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
104
168
  }
105
169
 
106
- a {
170
+ :host > ul a {
107
171
  display: flex;
108
172
  flex-direction: column;
109
173
  padding: 5px 0px;
@@ -116,7 +180,7 @@ MenuTools.styles = [
116
180
  border-left: 2px solid transparent;
117
181
  }
118
182
 
119
- a[active] {
183
+ :host > ul a[active] {
120
184
  opacity: 1;
121
185
  color: var(--menu-tools-active-color);
122
186
  font-weight: bold;
@@ -124,7 +188,7 @@ MenuTools.styles = [
124
188
  border-left: 2px solid var(--menu-tools-active-color);
125
189
  }
126
190
 
127
- :host([width='NARROW']) a {
191
+ :host([width='NARROW']) > ul a {
128
192
  padding: 0px 0px 5px 0px;
129
193
  opacity: 0.8;
130
194
  color: var(--menu-tools-color);
@@ -132,7 +196,7 @@ MenuTools.styles = [
132
196
  border-top: 2px solid transparent;
133
197
  }
134
198
 
135
- :host([width='NARROW']) a[active] {
199
+ :host([width='NARROW']) > ul a[active] {
136
200
  opacity: 1;
137
201
  color: var(--menu-tools-active-color);
138
202
  font-weight: bold;
@@ -151,8 +215,73 @@ MenuTools.styles = [
151
215
  padding: 0;
152
216
  }
153
217
 
154
- div {
218
+ :host > ul div {
155
219
  font-size: 0.6em;
220
+ white-space: pre-line; /* 메뉴명 내 \n 줄바꿈 표현 */
221
+ }
222
+
223
+ /* dkpi menu-tools의 서브메뉴 팝업과 동일 구성 — 배경만 테마색(--secondary-color) 사용 */
224
+ .submenu-popup {
225
+ position: absolute;
226
+ left: 60px; /* 탑메뉴 width */
227
+ top: 0;
228
+ width: 220px;
229
+ height: 100%;
230
+ background: var(--secondary-color);
231
+ color: #fff;
232
+ box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);
233
+ z-index: 1000;
234
+ display: flex;
235
+ flex-direction: column;
236
+ border-radius: 0 10px 10px 0;
237
+ }
238
+
239
+ .submenu-popup ul {
240
+ list-style: none;
241
+ margin: 0;
242
+ padding: 0;
243
+ }
244
+
245
+ .submenu-popup li {
246
+ /* em 은 상속 기준에 따라 커질 수 있어 고정 크기 사용 */
247
+ font-size: 14px;
248
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
249
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1);
250
+ }
251
+
252
+ .submenu-popup li a {
253
+ color: var(--menu-tools-color);
254
+ opacity: 0.7;
255
+ text-decoration: none;
256
+ text-transform: capitalize;
257
+ display: flex;
258
+ flex-direction: row;
259
+ align-items: center;
260
+ gap: 12px;
261
+ transition: background 0.2s;
262
+ padding: 12px 16px;
263
+ border-left: 2px solid transparent;
264
+ }
265
+
266
+ .submenu-popup li a:hover {
267
+ background: rgba(0, 0, 0, 0.15);
268
+ }
269
+
270
+ .submenu-popup li a[active] {
271
+ opacity: 1;
272
+ color: var(--menu-tools-active-color);
273
+ font-weight: bold;
274
+ background-color: rgba(0, 0, 0, 0.15);
275
+ border-left: 2px solid var(--menu-tools-active-color);
276
+ }
277
+
278
+ .submenu-popup li a md-icon {
279
+ --md-icon-size: 20px;
280
+ color: rgba(255, 255, 255, 0.8);
281
+ }
282
+
283
+ .submenu-popup li a[active] md-icon {
284
+ color: var(--menu-tools-active-color);
156
285
  }
157
286
  `
158
287
  ];
@@ -164,6 +293,10 @@ __decorate([
164
293
  property({ type: String, reflect: true }),
165
294
  __metadata("design:type", String)
166
295
  ], MenuTools.prototype, "width", void 0);
296
+ __decorate([
297
+ property({ type: Number }),
298
+ __metadata("design:type", Object)
299
+ ], MenuTools.prototype, "openedMenuIndex", void 0);
167
300
  MenuTools = __decorate([
168
301
  customElement('menu-tools')
169
302
  ], MenuTools);
@@ -1 +1 @@
1
- {"version":3,"file":"menu-tools.js","sourceRoot":"","sources":["../../client/viewparts/menu-tools.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;AAElE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAE/C,OAAO,EAAE,cAAc,EAAE,eAAe,EAAiC,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAG5G,IAAM,SAAS,GAAf,MAAM,SAAU,SAAQ,OAAO,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC;IAAlD;;QA0GG,UAAK,GAAsD,EAAE,CAAA;IAqDvE,CAAC;IAnDC,MAAM;QACJ,IAAI,CAAC,KAAK,GAAG;YACX;gBACE,IAAI,EAAE,KAAK;gBACX,IAAI,EAAE,cAAc;gBACpB,KAAK,EAAE,cAAc;aACtB;YACD;gBACE,IAAI,EAAE,IAAI;gBACV,IAAI,EAAE,wBAAwB;gBAC9B,KAAK,EAAE,eAAe;aACvB;YACD,IAAI;YACJ,kBAAkB;YAClB,yBAAyB;YACzB,wBAAwB;YACxB,KAAK;YACL,IAAI;YACJ,iBAAiB;YACjB,+BAA+B;YAC/B,2BAA2B;YAC3B,KAAK;YACL;gBACE,IAAI,EAAE,IAAI;gBACV,IAAI,EAAE,sBAAsB;gBAC5B,KAAK,EAAE,aAAa;aACrB;SACF,CAAA;QAED,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,EAAE,CAAA;QAE1B,OAAO,IAAI,CAAA;;UAEL,IAAI,CAAC,KAAK,CAAC,GAAG,CACd,IAAI,CAAC,EAAE,CAAC,IAAI,CAAA;;wBAEE,IAAI,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;2BAC5C,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;uBAC9D,IAAI,CAAC,IAAI;;;WAGrB,CACF;;KAEJ,CAAA;IACH,CAAC;IAED,YAAY,CAAC,KAAK;QAChB,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAA;QAC5B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAA;IACjC,CAAC;;AA7JM,gBAAM,GAAG;IACd,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAkGF;CACF,AApGY,CAoGZ;AAE2B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;uCAAc;AACE;IAA1C,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;;wCAAe;AAxG9C,SAAS;IADrB,aAAa,CAAC,YAAY,CAAC;GACf,SAAS,CA+JrB","sourcesContent":["import { css, html, LitElement } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\n\nimport { store, connect } from '@operato/shell'\n\nimport { ICONS_PROGRESS, ICONS_COMPLETED, ICONS_STATUS, ICONS_OPERATING, ICONS_SETTING } from '../icons/menu-icons'\n\n@customElement('menu-tools')\nexport class MenuTools extends connect(store)(LitElement) {\n static styles = [\n css`\n :host {\n display: flex;\n background-color: var(--secondary-color);\n\n /* for narrow mode */\n flex-direction: column;\n width: 100%;\n --menu-tools-color: rgba(255, 255, 255, 0.9);\n --menu-tools-active-color: rgba(107, 178, 249, 1);\n }\n\n :host([width='WIDE']) {\n /* for wide mode */\n flex-direction: row;\n width: initial;\n height: 100%;\n }\n\n ul {\n display: flex;\n flex-direction: row;\n\n margin: auto;\n padding: 0;\n list-style: none;\n height: 100%;\n overflow: none;\n }\n\n :host([width='NARROW']) ul {\n width: 100%;\n justify-content: space-around;\n }\n\n :host([width='WIDE']) ul {\n flex-direction: column;\n }\n :host([width='NARROW']) li {\n flex: 1;\n }\n\n :host([width='WIDE']) li {\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n }\n\n a {\n display: flex;\n flex-direction: column;\n padding: 5px 0px;\n opacity: 0.7;\n align-items: center;\n text-align: center;\n text-decoration: none;\n text-transform: capitalize;\n color: var(--menu-tools-color);\n border-left: 2px solid transparent;\n }\n\n a[active] {\n opacity: 1;\n color: var(--menu-tools-active-color);\n font-weight: bold;\n background-color: rgba(0, 0, 0, 0.15);\n border-left: 2px solid var(--menu-tools-active-color);\n }\n\n :host([width='NARROW']) a {\n padding: 0px 0px 5px 0px;\n opacity: 0.8;\n color: var(--menu-tools-color);\n border-left: none;\n border-top: 2px solid transparent;\n }\n\n :host([width='NARROW']) a[active] {\n opacity: 1;\n color: var(--menu-tools-active-color);\n font-weight: bold;\n background-color: rgba(0, 0, 0, 0.15);\n border-left: none;\n border-top: 2px solid var(--menu-tools-active-color);\n }\n\n img {\n display: block;\n width: 35px;\n padding: 5px 10px 0px 10px;\n }\n\n :host([width='NARROW']) img {\n padding: 0;\n }\n\n div {\n font-size: 0.6em;\n }\n `\n ]\n\n @property({ type: String }) page?: string\n @property({ type: String, reflect: true }) width?: string\n\n private menus: { name: string; path: string; icons: string[] }[] = []\n\n render() {\n this.menus = [\n {\n name: '진행중',\n path: 'project-list',\n icons: ICONS_PROGRESS\n },\n {\n name: '완료',\n path: 'project-completed-list',\n icons: ICONS_COMPLETED\n },\n // {\n // name: '검측현황',\n // path: 'dssp-status',\n // icons: ICONS_STATUS\n // },\n // {\n // name: '공정표',\n // path: 'project-task-list',\n // icons: ICONS_OPERATING\n // },\n {\n name: '셋팅',\n path: 'project-setting-list',\n icons: ICONS_SETTING\n }\n ]\n\n var page = this.page || ''\n\n return html`\n <ul>\n ${this.menus.map(\n menu => html`\n <li>\n <a href=${menu.path} ?active=${!!~page.indexOf(menu.path)}>\n <img src=${!!~page.indexOf(menu.path) ? menu.icons[1] : menu.icons[0]} />\n <div>${menu.name}</div>\n </a>\n </li>\n `\n )}\n </ul>\n `\n }\n\n stateChanged(state) {\n this.page = state.route.page\n this.width = state.layout.width\n }\n}\n"]}
1
+ {"version":3,"file":"menu-tools.js","sourceRoot":"","sources":["../../client/viewparts/menu-tools.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\n\nimport { store, connect } from '@operato/shell'\n\nimport { ICONS_PROGRESS, ICONS_COMPLETED, ICONS_STATUS, ICONS_OPERATING, ICONS_SETTING } from '../icons/menu-icons'\n\n@customElement('menu-tools')\nexport class MenuTools extends connect(store)(LitElement) {\n static styles = [\n css`\n :host {\n position: relative;\n display: flex;\n background-color: var(--secondary-color);\n\n /* for narrow mode */\n flex-direction: column;\n width: 100%;\n --menu-tools-color: rgba(255, 255, 255, 0.9);\n --menu-tools-active-color: rgba(107, 178, 249, 1);\n }\n\n :host([width='WIDE']) {\n /* for wide mode */\n flex-direction: row;\n width: initial;\n height: 100%;\n }\n\n /* 사이드바 메뉴 스타일 — 팝업 내부로 새지 않도록 직계 자식(> ul)으로 스코핑 */\n :host > ul {\n display: flex;\n flex-direction: row;\n\n margin: auto;\n padding: 0;\n list-style: none;\n height: 100%;\n overflow: none;\n }\n\n :host([width='NARROW']) > ul {\n width: 100%;\n justify-content: space-around;\n }\n\n :host([width='WIDE']) > ul {\n flex-direction: column;\n }\n :host([width='NARROW']) > ul > li {\n flex: 1;\n }\n\n :host([width='WIDE']) > ul > li {\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n }\n\n :host > ul a {\n display: flex;\n flex-direction: column;\n padding: 5px 0px;\n opacity: 0.7;\n align-items: center;\n text-align: center;\n text-decoration: none;\n text-transform: capitalize;\n color: var(--menu-tools-color);\n border-left: 2px solid transparent;\n }\n\n :host > ul a[active] {\n opacity: 1;\n color: var(--menu-tools-active-color);\n font-weight: bold;\n background-color: rgba(0, 0, 0, 0.15);\n border-left: 2px solid var(--menu-tools-active-color);\n }\n\n :host([width='NARROW']) > ul a {\n padding: 0px 0px 5px 0px;\n opacity: 0.8;\n color: var(--menu-tools-color);\n border-left: none;\n border-top: 2px solid transparent;\n }\n\n :host([width='NARROW']) > ul a[active] {\n opacity: 1;\n color: var(--menu-tools-active-color);\n font-weight: bold;\n background-color: rgba(0, 0, 0, 0.15);\n border-left: none;\n border-top: 2px solid var(--menu-tools-active-color);\n }\n\n img {\n display: block;\n width: 35px;\n padding: 5px 10px 0px 10px;\n }\n\n :host([width='NARROW']) img {\n padding: 0;\n }\n\n :host > ul div {\n font-size: 0.6em;\n white-space: pre-line; /* 메뉴명 내 \\n 줄바꿈 표현 */\n }\n\n /* dkpi menu-tools의 서브메뉴 팝업과 동일 구성 — 배경만 테마색(--secondary-color) 사용 */\n .submenu-popup {\n position: absolute;\n left: 60px; /* 탑메뉴 width */\n top: 0;\n width: 220px;\n height: 100%;\n background: var(--secondary-color);\n color: #fff;\n box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);\n z-index: 1000;\n display: flex;\n flex-direction: column;\n border-radius: 0 10px 10px 0;\n }\n\n .submenu-popup ul {\n list-style: none;\n margin: 0;\n padding: 0;\n }\n\n .submenu-popup li {\n /* em 은 상속 기준에 따라 커질 수 있어 고정 크기 사용 */\n font-size: 14px;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n border-bottom: 1px solid rgba(0, 0, 0, 0.1);\n }\n\n .submenu-popup li a {\n color: var(--menu-tools-color);\n opacity: 0.7;\n text-decoration: none;\n text-transform: capitalize;\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: 12px;\n transition: background 0.2s;\n padding: 12px 16px;\n border-left: 2px solid transparent;\n }\n\n .submenu-popup li a:hover {\n background: rgba(0, 0, 0, 0.15);\n }\n\n .submenu-popup li a[active] {\n opacity: 1;\n color: var(--menu-tools-active-color);\n font-weight: bold;\n background-color: rgba(0, 0, 0, 0.15);\n border-left: 2px solid var(--menu-tools-active-color);\n }\n\n .submenu-popup li a md-icon {\n --md-icon-size: 20px;\n color: rgba(255, 255, 255, 0.8);\n }\n\n .submenu-popup li a[active] md-icon {\n color: var(--menu-tools-active-color);\n }\n `\n ]\n\n @property({ type: String }) page?: string\n @property({ type: String, reflect: true }) width?: string\n @property({ type: Number }) openedMenuIndex: number | null = null\n\n private menus: {\n name: string\n path: string\n icons: string[]\n submenus?: { name: string; path: string; icon: string }[]\n }[] = []\n\n render() {\n this.menus = [\n {\n name: 'KPI\\nOversight',\n path: 'kpi-overview',\n icons: ICONS_STATUS,\n submenus: [\n { name: 'KPI 대시보드', path: 'kpi-dashboard-map', icon: 'dashboard' },\n { name: 'KPI 개요', path: 'kpi-overview', icon: 'widget_small' },\n { name: 'KPI 시스템 가이드', path: 'kpi-system-guide', icon: 'menu_book' }\n ]\n },\n {\n name: '진행중',\n path: 'project-list',\n icons: ICONS_PROGRESS\n },\n {\n name: '완료',\n path: 'project-completed-list',\n icons: ICONS_COMPLETED\n },\n // {\n // name: '검측현황',\n // path: 'dssp-status',\n // icons: ICONS_STATUS\n // },\n // {\n // name: '공정표',\n // path: 'project-task-list',\n // icons: ICONS_OPERATING\n // },\n {\n name: '셋팅',\n path: 'project-setting-list',\n icons: ICONS_SETTING\n }\n ]\n\n var page = this.page || ''\n\n return html`\n <ul>\n ${this.menus.map((menu, i) => {\n /* 서브메뉴가 있으면 이동 대신 팝업을 연다 (dkpi 방식) */\n const active = menu.submenus\n ? menu.submenus.some(sub => !!~page.indexOf(sub.path))\n : !!~page.indexOf(menu.path)\n\n return html`\n <li\n @click=${menu.submenus\n ? (e: Event) => {\n e.stopPropagation()\n this.openedMenuIndex = i\n }\n : undefined}\n >\n <a href=${menu.submenus ? 'javascript:void(0)' : menu.path} ?active=${active}>\n <img src=${active ? menu.icons[1] : menu.icons[0]} />\n <div>${menu.name}</div>\n </a>\n </li>\n `\n })}\n </ul>\n ${this.openedMenuIndex !== null && this.menus[this.openedMenuIndex]?.submenus\n ? html`\n <div class=\"submenu-popup\">\n <ul>\n ${this.menus[this.openedMenuIndex].submenus!.map(\n sub => html`\n <li>\n <a href=${sub.path} ?active=${!!~page.indexOf(sub.path)}>\n <md-icon>${sub.icon}</md-icon> ${sub.name}\n </a>\n </li>\n `\n )}\n </ul>\n </div>\n `\n : ''}\n `\n }\n\n connectedCallback() {\n super.connectedCallback()\n // capture 단계로 등록 — stopPropagation 하는 다른 컴포넌트의 클릭에도 서브메뉴를 닫는다 (dkpi 방식)\n window.addEventListener('click', this._closeSubmenu, true)\n }\n\n disconnectedCallback() {\n window.removeEventListener('click', this._closeSubmenu, true)\n super.disconnectedCallback()\n }\n\n private _closeSubmenu = (e: MouseEvent) => {\n const path = e.composedPath()\n if (path.includes(this)) {\n // 내부 클릭이라도 실제 페이지로 이동하는 링크 클릭이면 닫는다.\n const isNavLink = path.some(\n el =>\n el instanceof HTMLAnchorElement &&\n !!el.getAttribute('href') &&\n el.getAttribute('href') !== 'javascript:void(0)'\n )\n if (!isNavLink) return\n }\n this.openedMenuIndex = null\n }\n\n stateChanged(state) {\n this.page = state.route.page\n this.width = state.layout.width\n }\n}\n"]}
@@ -0,0 +1 @@
1
+ export * from './service/index.js';
@@ -1 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./service/index.js"), exports);
1
5
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":"","sourcesContent":[""]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;AAAA,6DAAkC","sourcesContent":["export * from './service/index.js'\n"]}
@@ -0,0 +1,4 @@
1
+ export declare const entities: any[];
2
+ export declare const schema: {
3
+ resolverClasses: (typeof import("./kpi-stat/kpi-stat-query").KpiStatQuery | typeof import("./kpi-value/kpi-value-query").KpiValueQueryForProject | typeof import("./kpi-metric-value/kpi-metric-value-query").KpiMetricValueQuery | typeof import("./kpi-metric-value/kpi-metric-value-mutation").KpiMetricValueMutation)[];
4
+ };
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.schema = exports.entities = void 0;
4
+ /* IMPORT ENTITIES AND RESOLVERS */
5
+ const kpi_stat_1 = require("./kpi-stat");
6
+ const kpi_value_1 = require("./kpi-value");
7
+ const kpi_metric_value_1 = require("./kpi-metric-value");
8
+ exports.entities = [
9
+ /* ENTITIES */
10
+ ];
11
+ exports.schema = {
12
+ resolverClasses: [
13
+ /* RESOLVER CLASSES */
14
+ ...kpi_stat_1.resolvers,
15
+ ...kpi_value_1.resolvers,
16
+ ...kpi_metric_value_1.resolvers
17
+ ]
18
+ };
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;AAAA,mCAAmC;AACnC,yCAA0D;AAC1D,2CAA4D;AAC5D,yDAAyE;AAE5D,QAAA,QAAQ,GAAG;AACtB,cAAc;CACf,CAAA;AAEY,QAAA,MAAM,GAAG;IACpB,eAAe,EAAE;QACf,sBAAsB;QACtB,GAAG,oBAAgB;QACnB,GAAG,qBAAiB;QACpB,GAAG,4BAAuB;KAC3B;CACF,CAAA","sourcesContent":["/* IMPORT ENTITIES AND RESOLVERS */\nimport { resolvers as KpiStatResolvers } from './kpi-stat'\nimport { resolvers as KpiValueResolvers } from './kpi-value'\nimport { resolvers as KpiMetricValueResolvers } from './kpi-metric-value'\n\nexport const entities = [\n /* ENTITIES */\n]\n\nexport const schema = {\n resolverClasses: [\n /* RESOLVER CLASSES */\n ...KpiStatResolvers,\n ...KpiValueResolvers,\n ...KpiMetricValueResolvers\n ]\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import { KpiMetricValueQuery } from './kpi-metric-value-query';
2
+ import { KpiMetricValueMutation } from './kpi-metric-value-mutation';
3
+ export declare const resolvers: (typeof KpiMetricValueQuery | typeof KpiMetricValueMutation)[];
4
+ export declare const subscribers: any[];
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.subscribers = exports.resolvers = void 0;
4
+ const kpi_metric_value_query_1 = require("./kpi-metric-value-query");
5
+ const kpi_metric_value_mutation_1 = require("./kpi-metric-value-mutation");
6
+ exports.resolvers = [kpi_metric_value_query_1.KpiMetricValueQuery, kpi_metric_value_mutation_1.KpiMetricValueMutation];
7
+ exports.subscribers = [];
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/kpi-metric-value/index.ts"],"names":[],"mappings":";;;AAAA,qEAA8D;AAC9D,2EAAoE;AAEvD,QAAA,SAAS,GAAG,CAAC,4CAAmB,EAAE,kDAAsB,CAAC,CAAA;AACzD,QAAA,WAAW,GAAG,EAAE,CAAA","sourcesContent":["import { KpiMetricValueQuery } from './kpi-metric-value-query'\nimport { KpiMetricValueMutation } from './kpi-metric-value-mutation'\n\nexport const resolvers = [KpiMetricValueQuery, KpiMetricValueMutation]\nexport const subscribers = []\n"]}
@@ -0,0 +1,198 @@
1
+ import { KpiMetricValue, KpiMetricValuePatch } from '@things-factory/kpi';
2
+ import { Attachment, NewAttachment } from '@things-factory/attachment-base';
3
+ /**
4
+ * 외부 시스템 데이터 수집 결과 — 시스템별 한 row.
5
+ * UI "자동 수집" 버튼이 시나리오 호출 후 시스템별 성공·오류 표시에 사용.
6
+ */
7
+ declare class ExternalDataCollectionResult {
8
+ source: string;
9
+ label: string;
10
+ ok: boolean;
11
+ message: string;
12
+ data?: any;
13
+ }
14
+ export declare class KpiMetricValueMutation {
15
+ updateKpiMetricValuesCumulative(patches: KpiMetricValuePatch[], context: ResolverContext): Promise<KpiMetricValue[]>;
16
+ updateKpiMetricValuesAssessment(patches: KpiMetricValuePatch[], context: ResolverContext): Promise<KpiMetricValue[]>;
17
+ /**
18
+ * KpiMetricValue 의 unique 조합 (domain, metric, valueDate, org) 기준 진짜 upsert.
19
+ *
20
+ * 기존 mutation 의 `repo.save({...patch})` 는 patch.id 만 보고 update/insert 결정해
21
+ * 같은 metric × 같은 valueDate × 같은 org 인데 patch.id 가 새 UUID 인 경우 unique
22
+ * 인덱스 (ix_kpi_metric_value_latest) 위반 에러 또는 row 누적 위험. 정확한 upsert
23
+ * 동작을 보장하기 위해 조합 lookup → 기존 id 사용 → save.
24
+ *
25
+ * 월별 metric (periodType=MONTH, valueDate=YYYY-MM-01) 의 단일 row 정책을 자연 충족.
26
+ *
27
+ * **도메인 컨텍스트 스위치**: caller (운영자) 가 system 도메인일 수 있어 patch.org
28
+ * (= projectId) 로 프로젝트 테넌트 도메인을 lookup 해 그 컨텍스트로 저장. 모든
29
+ * patch 가 같은 projectId 라 가정 (한 번의 mutation = 한 프로젝트의 값들).
30
+ */
31
+ private upsertKpiMetricValues;
32
+ updateKpiMetricValuesSentiment(attachment: NewAttachment, context: ResolverContext): Promise<Attachment | null>;
33
+ /**
34
+ * FileUpload 스트림을 버퍼로 읽기
35
+ */
36
+ private readFileToBuffer;
37
+ /**
38
+ * Buffer로부터 FileUpload 객체 생성
39
+ */
40
+ private createFileUploadFromBuffer;
41
+ /**
42
+ * operator-runner 서비스 호출 (Buffer 사용)
43
+ */
44
+ private callOperatorRunnerServiceWithBuffer;
45
+ /**
46
+ * 메트릭 값 저장
47
+ */
48
+ private saveMetricValue;
49
+ finalizeProjectWithKpiRecalculation(projectId: string, context: ResolverContext): Promise<boolean>;
50
+ /**
51
+ * 완공 처리 없이 KPI 만 재계산 — 진행 중 프로젝트의 중간 결과 산정 용도.
52
+ * DB 에 이미 저장된 KpiMetricValue 만 가지고 formula 평가. 외부 시나리오 (juso/
53
+ * allbaro/kiscon) 자동 수집은 의도적으로 호출하지 않음 — 외부 수집은 사용자가
54
+ * "자동 수집" 버튼 (`collectProjectExternalData`) 으로 명시적으로 실행하는 흐름.
55
+ * 권한은 `kpi:recalculate` 로 분리해 finalize 보다 가볍게 부여 가능.
56
+ */
57
+ recalculateProjectKpi(projectId: string, context: ResolverContext): Promise<boolean>;
58
+ /**
59
+ * UI "자동 수집" 버튼 전용 mutation. 외부 시스템 3종 시나리오를 순차 호출하고
60
+ * 시스템별 성공/실패 + 메시지를 반환. UI 는 결과를 보고 카드별 상태 (성공·오류) 를 표시.
61
+ *
62
+ * 시나리오는 도메인 EnvVar (주소·자격증명·서비스키 등) 만으로 동작하므로 파라미터 X.
63
+ * 한 시스템 실패가 다른 시스템 수집을 막지 않도록 try/catch 로 격리.
64
+ *
65
+ * 운영 현실: 키스콘·올바로는 시공사 ID/PW 가 자주 미확보 → 오류 흔함. 세움터는 공공
66
+ * 데이터 서비스키만으로 동작 가능. UI 는 시스템별로 명확한 오류 메시지 노출.
67
+ */
68
+ collectProjectExternalData(projectId: string, context: ResolverContext): Promise<ExternalDataCollectionResult[]>;
69
+ /**
70
+ * 프로젝트 정보 수정 화면의 "정보 연동" 버튼 전용 — 세움터 수집.
71
+ * BuildingComplex 기본 속성 (area / floorAreaRatio / siteType / structureType /
72
+ * coverageRatio / householdCount 등) 자동 채움 목적.
73
+ *
74
+ * **완공/완공전 케이스 통합**: 완공 단지는 건축물대장, 완공 전(택지지구·정비사업 블록)
75
+ * 단지는 주택인허가에 연면적이 있다. `collectSaeumteo` 가 주소 하나로 대장 → (연면적
76
+ * 없으면) 인허가 순으로 시도해 하나의 세움터 결과로 반환.
77
+ *
78
+ * address 인자가 있으면 시나리오 실행 전에 canonical EnvVar 로 upsert — 운영자가 폼에서
79
+ * 방금 입력한 주소를 시나리오가 곧바로 사용. (블록형이면 `…블럭 (단지명)` 형태.)
80
+ *
81
+ * **도메인 스위치**: mutation 호출은 system / 운영자 도메인에서 일어나지만 시나리오·
82
+ * EnvVar 는 **프로젝트가 속한 도메인** 에 있어야 자연. project.domain 으로 컨텍스트
83
+ * 스위치 후 그 도메인에서 EnvVar upsert + 시나리오 실행.
84
+ */
85
+ collectProjectBasicInfo(projectId: string, address: string, context: ResolverContext): Promise<ExternalDataCollectionResult>;
86
+ /**
87
+ * mutation 호출이 system / 운영자 도메인에서 일어나도 시나리오·EnvVar 는 **프로젝트
88
+ * 테넌트 도메인** 에서 동작해야 자연. project.code 로 자식 (테넌트) 도메인을 찾아
89
+ * 컨텍스트 사본 만들어 반환.
90
+ *
91
+ * 테넌트 도메인 매핑: Domain.subdomain = project.code AND Domain.extType = 'project'
92
+ * (promoteProjectToTenant mutation 이 그렇게 생성). project.domain 자체는 부모
93
+ * 도메인이라 외부 연동 EnvVar 가 거기 있을 일이 없어 사용 부적합.
94
+ *
95
+ * 테넌트 도메인이 없거나 (= 아직 승격 안 됨) project.code 가 비어있으면 원본
96
+ * 컨텍스트 그대로 반환 (방어). project 자체가 없으면 throw.
97
+ */
98
+ private switchToProjectDomain;
99
+ /**
100
+ * 컨텍스트의 도메인에 EnvVar 1개 upsert. 시나리오가 도메인 EnvVar 를 우선 참조하는
101
+ * 정책이라, 폼에서 입력한 주소를 시나리오 입력으로 흘리는 다리 역할.
102
+ */
103
+ private upsertEnvVar;
104
+ /**
105
+ * 단일 시나리오 호출 + result unwrap + 실패 판정 — collectProjectExternalData 의
106
+ * loop 본체와 같은 로직을 1건짜리로 분리.
107
+ */
108
+ private runSingleScenario;
109
+ /**
110
+ * 외부 시스템 3종 시나리오 순차 실행 + 시스템별 결과 수집.
111
+ */
112
+ private runExternalDataScenariosWithResults;
113
+ /**
114
+ * 세움터 수집 — 완공/완공전 케이스를 **하나의 세움터 결과**로 통합.
115
+ *
116
+ * 완공 단지는 건축물대장(building-info)에, 완공 전(택지지구·정비사업 블록) 단지는
117
+ * 인허가에 연면적이 있다. 인허가는 **용도별로 소스가 갈린다**:
118
+ * - 주택(공동주택) → 주택인허가(housing-permit, 사업계획승인)
119
+ * - 비주택(복합·노유자·근생·업무 등) → 건축인허가(building-permit block, 건축허가)
120
+ * 주소 하나로 세 소스를 순차 시도 — **대장 → 주택인허가 → 건축인허가**. 각 블록 소스는
121
+ * nameFilter(사업명)가 실제로 매칭될 때만 값을 내고, 매칭 없으면 빈 결과로 통과하므로
122
+ * (태스크 레벨에서 미매칭=빈결과 보장) **순서와 무관하게 잘못된 소스를 집지 않는다**.
123
+ * 저장된 용도 필드는 신뢰불가(예: 노유자 복합시설도 building_usage=RESIDENTIAL)라
124
+ * 사전 라우팅 대신 이 nameFilter 기반 사슬을 쓴다. 출력 필드가 세 소스 동일
125
+ * (totArea→area 등)이라 downstream 매핑·클로버 방지는 그대로 동작.
126
+ *
127
+ * 주소 소스: `address` 인자(정보연동 버튼) 우선, 없으면 도메인 canonical EnvVar
128
+ * (`Step::건축물관리대장조회::address::query`). 각 시나리오가 자기 EnvVar 를 참조하므로
129
+ * canonical 주소를 세 키에 동기화한 뒤 실행 — **프로젝트당 주소 1개** 유지.
130
+ * (블록형 프로젝트는 canonical 에 `…블럭 (단지명)` 을 넣으면 juso 가 자동 분기.)
131
+ */
132
+ private collectSaeumteo;
133
+ /** 시나리오 result 에 유효한 연면적(area>0)이 있는지. 완공/완공전 채택 판정용. */
134
+ private hasArea;
135
+ /** 컨텍스트 도메인의 EnvVar 값 읽기 (없으면 undefined). */
136
+ private readEnvVar;
137
+ /**
138
+ * finalize 흐름용 시나리오 호출. 결과 형태 없이 진행만 — finalize 의 KPI 재계산이 곧
139
+ * 이어지므로 시스템별 결과를 클라이언트에 돌려줄 필요 없음. 실패는 warning 만.
140
+ */
141
+ private runExternalDataScenarios;
142
+ /**
143
+ * 프로젝트의 모든 KPI Value들을 계층적으로 재계산합니다.
144
+ * 1. 기존 KPI Value 삭제 (중복 방지)
145
+ * 2. Leaf KPIs (자식이 없는 KPI): formula 기반 계산
146
+ * 3. Parent KPIs (자식이 있는 KPI): 자식 KPI scores의 weighted average 계산
147
+ */
148
+ private recalculateProjectKpiValues;
149
+ /**
150
+ * 개별 KPI Value를 재계산합니다.
151
+ * 항상 최신 버전의 KPI를 사용하여 계산합니다.
152
+ */
153
+ private recalculateKpiValue;
154
+ /**
155
+ * scoreFormula를 사용한 성과 점수 계산
156
+ */
157
+ private calculateScoreFromFormula;
158
+ /**
159
+ * KPI의 grades lookup table을 이용한 성과 점수 변환
160
+ * 1D (기존 배열) 및 2D (X13 공정률×편차) lookup 모두 지원
161
+ */
162
+ private calculateScoreFromLookup;
163
+ /**
164
+ * 2D lookup table에서 점수 계산 (X13: 공정률 × 편차 → 점수 1~5)
165
+ *
166
+ * 단위 정합:
167
+ * - deviationValue (= KpiMetric '일정 이탈 수준' value): % 단위 (예: 2.5 = 2.5%).
168
+ * - row.boundary*: ratio 단위 (예: 0.025 = 2.5%).
169
+ * - 비교 전 deviationValue 를 /100 해서 ratio 로 변환.
170
+ */
171
+ private calculateScoreFrom2DLookup;
172
+ /**
173
+ * KpiValue의 성과 점수 계산 및 저장
174
+ * @param context.progressRate X13 등 2D lookup KPI에 필요한 공정률 (0~100)
175
+ */
176
+ private calculateAndSaveScore;
177
+ /**
178
+ * Leaf KPI Value를 formula로 계산합니다.
179
+ * 참고: recalculateProjectKpiValues에서 호출 시 기존 값이 이미 삭제되었으므로 항상 새로 생성됩니다.
180
+ */
181
+ private recalculateLeafKpiValue;
182
+ /**
183
+ * Parent KPI Value를 계산합니다.
184
+ * 1. formula가 있으면 자식 KPI 값들을 변수로 사용하여 formula 계산
185
+ * 2. formula가 없으면 자식 KPI scores의 weighted average로 계산
186
+ * 참고: recalculateProjectKpiValues에서 호출 시 기존 값이 이미 삭제되었으므로 항상 새로 생성됩니다.
187
+ */
188
+ private recalculateParentKpiValue;
189
+ /**
190
+ * KPIs를 계층 레벨순으로 정렬합니다 (깊은 레벨부터)
191
+ */
192
+ private sortKpisByLevel;
193
+ /**
194
+ * 자식 KPI values의 weighted average를 계산합니다.
195
+ */
196
+ private calculateWeightedAverage;
197
+ }
198
+ export {};