@things-factory/meta-ui 8.0.0-beta.9 → 8.0.0

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 (115) hide show
  1. package/client/bootstrap.ts +170 -0
  2. package/client/component/filter/filter-form-meta-code-select.ts +102 -0
  3. package/client/component/filter/filter-form-meta-object-select.ts +107 -0
  4. package/client/component/filter/filter-grist-meta-code-select.ts +97 -0
  5. package/client/component/filter/filter-grist-meta-object-select.ts +102 -0
  6. package/client/component/grist/editor/grist-editor-code-input.js +96 -0
  7. package/client/component/grist/editor/grist-editor-meta-code-selector.js +157 -0
  8. package/client/component/grist/editor/grist-editor-meta-object-selector.js +122 -0
  9. package/client/component/grist/renderer/grist-renderer-code-input.js +20 -0
  10. package/client/component/grist/renderer/grist-renderer-meta-code-selector.js +28 -0
  11. package/client/component/grist/renderer/grist-renderer-meta-object-selector.js +25 -0
  12. package/client/component/popup/code-input-editor-popup.js +111 -0
  13. package/client/component/popup/file-upload-popup.js +129 -0
  14. package/client/component/popup/meta-object-selector-popup.ts +356 -0
  15. package/client/component/popup/record-based-code-editor-popup.ts +141 -0
  16. package/client/dynamic-menus.ts +38 -0
  17. package/client/index.ts +18 -0
  18. package/client/load-components.ts +17 -0
  19. package/client/mixin/meta-base-mixin.js +323 -0
  20. package/client/mixin/meta-basic-grist-mixin.js +283 -0
  21. package/client/mixin/meta-button-mixin.js +116 -0
  22. package/client/mixin/meta-form-mixin.js +435 -0
  23. package/client/mixin/meta-grist-tab-mixin.js +335 -0
  24. package/client/mixin/meta-main-tab-mixin.js +267 -0
  25. package/client/mixin/meta-master-detail-mixin.js +395 -0
  26. package/client/mixin/meta-service-mixin.js +306 -0
  27. package/client/mixin/meta-tab-detail-mixin.js +283 -0
  28. package/client/mixin/meta-tab-mixin.js +190 -0
  29. package/client/pages/activity/meta-activity-define-page.js +422 -0
  30. package/client/pages/activity/meta-activity-list-page.js +262 -0
  31. package/client/pages/activity/meta-activity-viewer-element.js +35 -0
  32. package/client/pages/activity/meta-activity-writer-element.js +48 -0
  33. package/client/pages/activity/meta-activiy-mixin.js +79 -0
  34. package/client/pages/button-role/button-role-detail.js +50 -0
  35. package/client/pages/button-role/button-role-page.js +25 -0
  36. package/client/pages/doc-number/doc-number-page.js +24 -0
  37. package/client/pages/doc-number/next-doc-number-popup.js +25 -0
  38. package/client/pages/entity/config-entity.js +955 -0
  39. package/client/pages/entity/main-menu-selector.js +245 -0
  40. package/client/pages/history/history-copy-list-popup.js +145 -0
  41. package/client/pages/history/history-json-list-popup.js +159 -0
  42. package/client/pages/menu/dynamic-menu-template.js +92 -0
  43. package/client/pages/menu/dynamic-menu.ts +744 -0
  44. package/client/pages/menu/export-menu-popup.js +468 -0
  45. package/client/pages/meta-form-element.js +9 -0
  46. package/client/pages/meta-grist-element.js +12 -0
  47. package/client/pages/meta-grist-page.js +16 -0
  48. package/client/pages/meta-grist-tab-element.js +16 -0
  49. package/client/pages/meta-grist-tab-page.js +16 -0
  50. package/client/pages/meta-main-tab-element.js +12 -0
  51. package/client/pages/meta-main-tab-page.js +16 -0
  52. package/client/pages/meta-master-detail-element.js +12 -0
  53. package/client/pages/meta-master-detail-page.js +16 -0
  54. package/client/pages/meta-tab-detail-element.js +12 -0
  55. package/client/pages/meta-tab-detail-page.js +16 -0
  56. package/client/pages/meta-tab-element.js +15 -0
  57. package/client/pages/printer-device/printer-device-page.js +24 -0
  58. package/client/pages/template/doc-template-page.js +24 -0
  59. package/client/pages/template/template-file-page.js +24 -0
  60. package/client/pages/terms/config-terminology.js +214 -0
  61. package/client/pages/work-code/work-code-detail-popup.js +16 -0
  62. package/client/pages/work-code/work-code-page.js +23 -0
  63. package/client/route.ts +36 -0
  64. package/client/tsconfig.json +13 -0
  65. package/client/utils/grist-default-value.js +36 -0
  66. package/client/utils/meta-api.js +811 -0
  67. package/client/utils/meta-crypto.js +52 -0
  68. package/client/utils/meta-ui-util.js +3304 -0
  69. package/client/utils/rest-service-util.js +328 -0
  70. package/client/utils/service-util.js +1327 -0
  71. package/client/utils/terms-util.ts +119 -0
  72. package/client/utils/ui-util.js +338 -0
  73. package/client/utils/value-util.js +234 -0
  74. package/dist-client/tsconfig.tsbuildinfo +1 -1
  75. package/dist-client/utils/service-util.d.ts +2 -2
  76. package/dist-client/utils/service-util.js +4 -4
  77. package/dist-client/utils/service-util.js.map +1 -1
  78. package/dist-server/tsconfig.tsbuildinfo +1 -1
  79. package/package.json +24 -24
  80. package/server/activity/CommonActivity.ts +68 -0
  81. package/server/index.ts +3 -0
  82. package/server/routes.ts +61 -0
  83. package/server/service/button-role/button-role-mutation.ts +105 -0
  84. package/server/service/button-role/button-role-query.ts +53 -0
  85. package/server/service/button-role/button-role-type.ts +39 -0
  86. package/server/service/button-role/button-role.ts +61 -0
  87. package/server/service/button-role/index.ts +7 -0
  88. package/server/service/dynamic-menu/dynamic-menu-query.ts +270 -0
  89. package/server/service/dynamic-menu/dynamic-menu-type.ts +74 -0
  90. package/server/service/dynamic-menu/index.ts +3 -0
  91. package/server/service/entity-event-subscriber/entity-event-subscriber.ts +80 -0
  92. package/server/service/entity-event-subscriber/index.ts +3 -0
  93. package/server/service/index.ts +41 -0
  94. package/server/service/menu-button-auth/index.ts +7 -0
  95. package/server/service/menu-button-auth/menu-button-auth-mutation.ts +133 -0
  96. package/server/service/menu-button-auth/menu-button-auth-query.ts +138 -0
  97. package/server/service/menu-button-auth/menu-button-auth-type.ts +63 -0
  98. package/server/service/menu-button-auth/menu-button-auth.ts +92 -0
  99. package/server/service/meta-activity/index.ts +5 -0
  100. package/server/service/meta-activity/meta-activity-mutation.ts +191 -0
  101. package/server/service/meta-activity/meta-activity-query.ts +43 -0
  102. package/server/service/meta-activity/meta-activity-type.ts +56 -0
  103. package/server/service/set-translations/index.ts +3 -0
  104. package/server/service/set-translations/set-translation-resolver.ts +63 -0
  105. package/server/service/work-code/index.ts +6 -0
  106. package/server/service/work-code/work-code-mutation.ts +147 -0
  107. package/server/service/work-code/work-code-query.ts +67 -0
  108. package/server/service/work-code/work-code-type.ts +60 -0
  109. package/server/service/work-code/work-code.ts +83 -0
  110. package/server/service/work-code-detail/index.ts +6 -0
  111. package/server/service/work-code-detail/work-code-detail-mutation.ts +149 -0
  112. package/server/service/work-code-detail/work-code-detail-query.ts +59 -0
  113. package/server/service/work-code-detail/work-code-detail-type.ts +50 -0
  114. package/server/service/work-code-detail/work-code-detail.ts +82 -0
  115. package/server/tsconfig.json +9 -0
@@ -0,0 +1,395 @@
1
+ import { MetaApi } from '../utils/meta-api'
2
+ import { MetaUiUtil } from '../utils/meta-ui-util'
3
+ import { ValueUtil } from '../utils/value-util'
4
+ import { TermsUtil } from '../utils/terms-util'
5
+
6
+ import { MetaButtonMixin } from './meta-button-mixin'
7
+
8
+ /**
9
+ * @description 메뉴 메타 정보를 이용해 마스터 - 디테일 그리드 화면 구현
10
+ ************************************************************
11
+ * @param {Object} MetaButtonMixin
12
+ * @returns
13
+ */
14
+ export const MetaMasterDetailMixin = baseElement =>
15
+ class extends MetaButtonMixin(baseElement) {
16
+ /**
17
+ * @description 스타일 정의
18
+ **************************
19
+ * @returns {Array} 스타일
20
+ */
21
+ static get styles() {
22
+ return MetaApi.getBasicMasterDetailStyles()
23
+ }
24
+
25
+ /**
26
+ * @description 프로퍼티 정의
27
+ ****************************
28
+ * @returns {Object} 프로퍼티
29
+ */
30
+ static get properties() {
31
+ return {
32
+ /**
33
+ * @description 그리드 구성 정보
34
+ *****************************
35
+ * @type {Object}
36
+ */
37
+ gridConfig: Object,
38
+ /**
39
+ * @description 그리드 컬럼 구성 정보
40
+ *********************************
41
+ * @type {Array}
42
+ */
43
+ gridColumnConfig: Array,
44
+ /**
45
+ * @description 검색 폼 구성 정보
46
+ *******************************
47
+ * @type {Array}
48
+ */
49
+ searchConfig: Array,
50
+ /**
51
+ * @description 화면에서 사용되는 서치 폼 : grist, filter, not
52
+ *********************************************************
53
+ * @type {String}
54
+ */
55
+ searchFormElement: String,
56
+ /**
57
+ * @description 메뉴 메타 정보로 부터 추출한 후 그리스트를 위해 설정 정보 구성
58
+ *****************************************************************
59
+ * @type {Object}
60
+ */
61
+ gristConfigSet: Object,
62
+ /**
63
+ * @description 필터 폼 사용 여부
64
+ *****************************
65
+ * @type {Boolean}
66
+ */
67
+ useFilterForm: Boolean,
68
+ /**
69
+ * @description 모바일 기기에서 그리드 모드 : GRID, LIST, CARD
70
+ *********************************************************
71
+ * @type {String}
72
+ */
73
+ gridMobileMode: String,
74
+ /**
75
+ * @description 데스크탑에서 그리드 모드 : GRID, LIST, CARD
76
+ ******************************************************
77
+ * @type {String}
78
+ */
79
+ gridDeskMode: String,
80
+ /**
81
+ * @description 그리드 뷰 모드 : GRID, LIST, CARD
82
+ **********************************************
83
+ * @type {Array}
84
+ */
85
+ gridViewOptions: Array,
86
+ /**
87
+ * @description 현재 그리드 뷰 모드 : GRID, LIST, CARD
88
+ ***************************************************
89
+ * @type {String}
90
+ */
91
+ gridMode: String,
92
+ /**
93
+ * @description Infinity Page 사용 여부
94
+ **************************************
95
+ * @type {Boolean}
96
+ */
97
+ infinityPage: Boolean,
98
+ /**
99
+ * @description 그리스트 엘리먼트 ID
100
+ ********************************
101
+ * @type {String}
102
+ */
103
+ gristId: String,
104
+ /**
105
+ * @description 필터 폼 엘리먼트 ID
106
+ ********************************
107
+ * @type {String}
108
+ */
109
+ filterFormId: String,
110
+ /**
111
+ * @description detail 엘리먼트
112
+ ******************************
113
+ * @type {Object}
114
+ */
115
+ detailElement: Object
116
+ }
117
+ }
118
+
119
+ /**
120
+ * @description 그리스트
121
+ ***********************
122
+ * @returns {HTMLElement}
123
+ */
124
+ get grist() {
125
+ return this.renderRoot.querySelector(this.gristId)
126
+ }
127
+
128
+ /**
129
+ * @description 필터 폼
130
+ ***********************
131
+ * @returns {HTMLElement}
132
+ */
133
+ get filterForm() {
134
+ return this.shadowRoot?.querySelector(this.filterFormId)
135
+ }
136
+
137
+ /**
138
+ * @description 컨텍스트
139
+ ***********************
140
+ * @returns {HTMLElement}
141
+ */
142
+ get context() {
143
+ let ctx = MetaUiUtil.getContextObject(this)
144
+
145
+ if (ctx.actions) delete ctx.actions
146
+ if (ctx.exportable) delete ctx.exportable
147
+ if (ctx.importable) delete ctx.importable
148
+ return ctx
149
+ }
150
+
151
+ /******************************************************
152
+ * LifeCycle
153
+ ******************************************************/
154
+
155
+ /**
156
+ * @override connectedCallback
157
+ *******************************
158
+ */
159
+ async connectedCallback() {
160
+ // 그리스트, 필터 폼 ID 설정
161
+ this.gristId = 'ox-grist'
162
+ this.filterFormId = 'ox-filters-form-base'
163
+
164
+ // 메뉴 메타 정보 조회 및 기본 파싱
165
+ await this.getAndParseMenuMeta()
166
+
167
+ if (this.isElement) {
168
+ await this.parseGristConfigs()
169
+ }
170
+
171
+ if (this.activityDataSet) {
172
+ this.dataSet = (this.activityDataSet || {}).main
173
+ }
174
+
175
+ if (super.connectedCallback) {
176
+ await super.connectedCallback()
177
+ }
178
+ }
179
+
180
+ /**
181
+ * @override firstUpdated
182
+ **************************
183
+ */
184
+ async firstUpdated() {
185
+ if (super.firstUpdated) {
186
+ await super.firstUpdated()
187
+ }
188
+ }
189
+
190
+ /**
191
+ * @override pageInitialized
192
+ ****************************
193
+ */
194
+ async pageInitialized() {
195
+ if (this.isPage) {
196
+ await this.parseGristConfigs()
197
+ }
198
+
199
+ if (super.pageInitialized) {
200
+ await super.pageInitialized()
201
+ }
202
+ }
203
+
204
+ /**
205
+ * @override render
206
+ ********************
207
+ */
208
+ render() {
209
+ return MetaApi.getMasterDetailHtml(this)
210
+ }
211
+
212
+ /**
213
+ * @descrtiption 메뉴 메타에서 기본 그리드 정보 파싱 처리
214
+ ************************************************
215
+ * @param {Object} menuMeta 메뉴 메타 정보
216
+ */
217
+ parseBasicGridConfigs(menuMeta) {
218
+ this.gridConfig = menuMeta.grid
219
+ this.gridColumnConfig = menuMeta.grid_column
220
+ this.searchConfig = menuMeta.search
221
+ this.gridEmphasized = menuMeta.gridEmphasized
222
+ }
223
+
224
+ /**
225
+ * @descrtiption 그리스트 구성 정보 파싱 처리
226
+ ***************************************
227
+ */
228
+ async parseGristConfigs() {
229
+ // 그리드 설정 셋 파싱
230
+ this.gristConfigSet = await MetaApi.parseGridConfigSet(this)
231
+
232
+ // 마스터 그리드에 handlers > focus 이벤트를 등록
233
+ this.gristConfigSet.rows.handlers = this.gristConfigSet.rows.handlers || {}
234
+ let gristRowHandler = this.gristConfigSet.rows.handlers
235
+ gristRowHandler.focus = this.masterGridFocusEventHandler.bind(this)
236
+
237
+ // 마스터 그리드 옵션 처리
238
+ this.masterOption = JSON.parse(this.etcConfig.master_option || '{}')
239
+ let { split_filter = false } = this.masterOption
240
+ this.useMasterFilterForm = this.useFilterForm === true && split_filter === false ? true : false
241
+ this.useFilterForm = split_filter === true ? true : false
242
+
243
+ // 필터 폼 사용을 하지 않는다면
244
+ if (this.useFilterForm == false) {
245
+ // 검색 조건 초기값 설정이 있다면 검색 초기값을 등록해놓는다.
246
+ this.searchFieldValues = []
247
+
248
+ // 검색 조건이 있는 컬럼 정보로 부터 그리드의 검색 조건 정보를 구성
249
+ this.searchFields = this.gristConfigSet.columns
250
+ .filter(x => x.filter)
251
+ .map(x => {
252
+ // 검색 조건
253
+ let searchField = {
254
+ name: x.name,
255
+ type: x.filter.operator === 'search' ? 'search' : x.type,
256
+ label: x.header,
257
+ operator: x.filter.operator ? x.filter.operator : 'eq'
258
+ }
259
+
260
+ if (x.filter.options) {
261
+ searchField.options = x.filter.options
262
+ }
263
+
264
+ if (x.record.options) {
265
+ searchField.options = x.record.options
266
+ }
267
+
268
+ // 검색 조건 초기값이 있다면 설정
269
+ if (x.filter.value) {
270
+ this.searchFieldValues.push({
271
+ name: searchField.name,
272
+ operator: searchField.operator,
273
+ value: x.filter.value
274
+ })
275
+ }
276
+
277
+ delete x.filter
278
+ return searchField
279
+ })
280
+ }
281
+ }
282
+
283
+ /**
284
+ * @descrtiption 마스터 그리드에 대한 포커스 이벤트 핸들러 정의
285
+ *****************************************************
286
+ * @param {Array} columns
287
+ * @param {Object} data
288
+ * @param {Object} column
289
+ * @param {Object} record
290
+ * @param {Number} rowIndex
291
+ */
292
+ masterGridFocusEventHandler(columns, data, column, record, rowIndex) {
293
+ if (record.id && this.detailElement) {
294
+ this.detailElement.setParentId(record.id)
295
+ }
296
+ }
297
+
298
+ /********************************************************************
299
+ * C R U D Functions
300
+ ********************************************************************/
301
+
302
+ /**
303
+ * @descrtiption 데이터 조회
304
+ **************************
305
+ */
306
+ async fetch() {
307
+ await this.grist.fetch()
308
+ }
309
+
310
+ /**
311
+ * @descrtiption 데이터 조회 전 액션
312
+ ********************************
313
+ */
314
+ async beforeFetch({ page = 0, limit = 0, sortings = [], filters = [] }) {
315
+ if (this.detailElement && this.detailElement.clear) {
316
+ await this.detailElement.clear()
317
+ }
318
+
319
+ return true
320
+ }
321
+
322
+ /**
323
+ * @descrtiption 저장 처리
324
+ **************************
325
+ */
326
+ async save() {
327
+ let patches = MetaApi.patchesForUpdateMultiple(this.grist)
328
+ let result = ValueUtil.isNotEmpty(patches) ? await this.updateMultiple(patches) : false
329
+ if (result) {
330
+ this.fetch()
331
+ }
332
+ }
333
+
334
+ /**
335
+ * @descrtiption id 리스트로 데이터 조회
336
+ ************************************
337
+ */
338
+ async find() {
339
+ let ids = MetaApi.getSelectedIdList(this.grist, true)
340
+ return ValueUtil.isNotEmpty(ids) ? await this.findOne(ids[0]) : {}
341
+ }
342
+
343
+ /**
344
+ * @descrtiption 삭제 처리
345
+ **************************
346
+ */
347
+ async delete() {
348
+ let ids = MetaApi.getSelectedIdList(this.grist, true)
349
+ let result = ValueUtil.isNotEmpty(ids) ? await this.deleteByIds(ids) : false
350
+ if (result) {
351
+ this.fetch()
352
+ }
353
+ }
354
+
355
+ /**
356
+ * @descrtiption 익스포트 처리
357
+ ****************************
358
+ */
359
+ async export() {
360
+ let exportTitle = TermsUtil.tTitle(ValueUtil.getParams(this.menuInfo, 'title'))
361
+ return await MetaApi.exportableData(this.isElement, exportTitle, this.grist)
362
+ }
363
+
364
+ /**
365
+ * @descrtiption 임포트 처리
366
+ **************************
367
+ */
368
+ async import() {
369
+ // TODO
370
+ }
371
+
372
+ /**
373
+ * @descrtiption 그리드 데이터 리턴
374
+ *******************************
375
+ * @returns {Object}
376
+ */
377
+ getData() {
378
+ let records = this.grist.___data.records
379
+ records = JSON.parse(JSON.stringify(records))
380
+
381
+ records.forEach(record => {
382
+ let keys = Object.keys(record)
383
+ keys.forEach(x => {
384
+ if (x.startsWith('__')) {
385
+ delete record[x]
386
+ }
387
+ })
388
+ })
389
+
390
+ return {
391
+ main: records,
392
+ detail: this.detailElement.getData()
393
+ }
394
+ }
395
+ }
@@ -0,0 +1,306 @@
1
+ import { adjustFilters } from '@operato/utils'
2
+
3
+ import { MetaApi } from './../utils/meta-api'
4
+ import { ValueUtil } from './../utils/value-util'
5
+
6
+ import { MetaBaseMixin } from './meta-base-mixin'
7
+
8
+ /**
9
+ * @description 서비스 관련 믹스인
10
+ *******************************
11
+ */
12
+ export const MetaServiceMixin = (baseElement) => class extends MetaBaseMixin(baseElement) {
13
+
14
+ /**
15
+ * @description 프로퍼티 정의
16
+ ******************************
17
+ * @returns {Object} 프로퍼티
18
+ */
19
+ static get properties() {
20
+ return {
21
+ /**
22
+ * @description 메뉴 메타 정보에 설정한 Graphql 정보
23
+ **********************************************
24
+ * @type {Object}
25
+ */
26
+ gqlInfo: Object
27
+ }
28
+ }
29
+
30
+ /**
31
+ * @description 메뉴 메타 정보로 부터 서비스 구성 정보 파싱
32
+ **************************************************
33
+ * @param {Object} menuMeta
34
+ */
35
+ parseBasicServiceConfigs(menuMeta) {
36
+ this.gqlInfo = menuMeta.gql
37
+ }
38
+
39
+ /**
40
+ * @description 데이터 fetch 함수 정의
41
+ ***********************************
42
+ * @param {Object} { page : Number, limit : Number, sortings : Array, filters : Array)
43
+ * @returns {Object} { total : Number, records : Array }
44
+ */
45
+ async fetchHandler({ page = 0, limit = 0, sortings = [], filters = [] }) {
46
+ if(this.is_activity) {
47
+ return {
48
+ total: 0,
49
+ records: this.dataSet || []
50
+ };
51
+ }
52
+
53
+ if(this.infinityPage === true) {
54
+ page = 0;
55
+ limit = 0;
56
+ }
57
+
58
+ // 조회 전처리
59
+ if(this.beforeFetch) {
60
+ // return 이 false 이면 이 후 동작 취소
61
+ if(await this.beforeFetch({ page:page, limit:limit, sortings:sortings, filters:filters}) == false) {
62
+ return;
63
+ }
64
+ }
65
+
66
+ // 그리스트 구성 설정이 없으면 리턴
67
+ if (!this.gristConfigSet) return { total: 0, records: [] }
68
+
69
+ // 필터 처리
70
+ let formFilters = ValueUtil.isEmpty(filters)
71
+ ? (this.mainFilterForm ? ((await this.mainFilterForm.getQueryFilters()) || [])
72
+ : ((await this.filterForm?.getQueryFilters()) || []))
73
+ : filters
74
+
75
+ // 조회 함수
76
+ let queryFunc = ValueUtil.getParams(this.gqlInfo, 'query', 'list_func')
77
+ let queryFilters = ValueUtil.getParams(this.gqlInfo, 'query', 'filters')
78
+
79
+ // 조회 결과 에서 다른 필드로 변환 될 필드 ( ex) parent.name ==> parentName )
80
+ // 객체 조회 후 내용을 리스트에 표현 할때 사용 ...
81
+ let queryAfterSetFields = ValueUtil.getParams(this.gqlInfo, 'query', 'after_set_fields')
82
+
83
+ // 기본 조회 조건이 지정되어 있으면 filter에 추가
84
+ if (ValueUtil.isNotEmpty(queryFilters)) {
85
+ formFilters = adjustFilters(formFilters, queryFilters)
86
+ }
87
+
88
+ // 화면 이동으로 호출된 경우 filter 조건 추가
89
+ formFilters.push(...this.getPageNavigateParams());
90
+
91
+ // 엘리먼트의 경우 상위 데이터 parentId가 있다.
92
+ if (this.isElement && !this.mainFilterForm) {
93
+ let parentId = ValueUtil.getParams(this.gqlInfo, 'query', 'parent_id')
94
+
95
+ if (ValueUtil.isNotEmpty(parentId) && ValueUtil.isNotEmpty(this.parent_id)) {
96
+ formFilters = adjustFilters(formFilters, [{
97
+ name: parentId,
98
+ operator: 'eq',
99
+ value: this.parent_id
100
+ }])
101
+ } else {
102
+ return {
103
+ total:0,
104
+ records: []
105
+ }
106
+ }
107
+ }
108
+
109
+ // 그리스트 설정을 이용 한 조회 필드 생성시 skip 대상 필드
110
+ let selectSkipFields = Object.keys(queryAfterSetFields || {})
111
+
112
+ // 조회 컬럼 추출 후 조회
113
+ let selectFields = MetaApi.getSelectColumns(this.gristConfigSet.columns.filter(x => !selectSkipFields.includes(x.name)))
114
+
115
+ // 조회 실행
116
+ let result = {};
117
+
118
+ if(queryFunc.includes('$')) {
119
+ let scenarioName = queryFunc.replace('$', '');
120
+ let response = await MetaApi.callScenario(undefined, scenarioName, {
121
+ filters:formFilters,
122
+ pagination: { page, limit },
123
+ sortings
124
+ }, false)
125
+
126
+ result = response.data.runScenario.result.result;
127
+ } else {
128
+ result = await MetaApi.searchByPagination(queryFunc, formFilters, sortings, page, limit, selectFields);
129
+ }
130
+
131
+ // 조회 결과 가공
132
+ if (ValueUtil.isNotEmpty(queryAfterSetFields)) {
133
+ if (ValueUtil.isNotEmpty(result) && ValueUtil.isNotEmpty(result.records)) {
134
+ result.records.map(record => {
135
+ selectSkipFields.forEach(key => {
136
+ record[key] = ValueUtil.getParams(record, ...(queryAfterSetFields[key].split('.')))
137
+ })
138
+
139
+ return record
140
+ })
141
+ }
142
+ }
143
+
144
+ // 조회 후 처리
145
+ if(this.afterFetch) {
146
+ // return 이 false 이면 이 후 동작 취소
147
+ let afterFetchResult = await this.afterFetch({ page: page, limit: limit, sortings: sortings, filters: filters }, result);
148
+
149
+ if(afterFetchResult) {
150
+ return afterFetchResult;
151
+ }
152
+ }
153
+
154
+ return result
155
+ }
156
+
157
+ /**
158
+ * @description 페이지 이동 파라미터에 대한 처리
159
+ *****************************************
160
+ * @returns {Array} [{ name: '', operator: 'eq', value: '' }]
161
+ */
162
+ getPageNavigateParams() {
163
+ if(this.isPage == false) return [];
164
+
165
+ // 페이지의 경우만 URL 파라미터 추출
166
+ let navParams = this.lifecycle?.params ? this.lifecycle.params : {};
167
+ if(!navParams.pass) return [];
168
+
169
+ let passParams = navParams.pass;
170
+ let passObj = JSON.parse(passParams);
171
+
172
+ // Operator 결정
173
+ let operator = passObj.length == 1 ? 'eq' : 'in';
174
+
175
+ let paramFilterObj = {};
176
+ let paramFilters = [];
177
+
178
+ // passObj 0번 인덱스를 기준으로 필터 생성
179
+ Object.keys(passObj[0]).forEach(key => {
180
+ paramFilterObj[key] = {
181
+ name: key,
182
+ operator: operator,
183
+ value: operator === 'eq' ? passObj[0][key] : []
184
+ };
185
+ })
186
+
187
+ // 여러 Row 의 Parameter 처리
188
+ if(passObj.length > 1) {
189
+ passObj.forEach(record => {
190
+ Object.keys(record).forEach(key => {
191
+ paramFilterObj[key].value.push(record[key]);
192
+ })
193
+ })
194
+ }
195
+
196
+ // paramObj를 리스트로 변환
197
+ Object.keys(paramFilterObj).forEach(x => {
198
+ paramFilters.push(paramFilterObj[x]);
199
+ })
200
+
201
+ return paramFilters;
202
+ }
203
+
204
+ /**
205
+ * @description 레코드 ID로 데이터 조회
206
+ ***********************************
207
+ * @param {String} id
208
+ * @returns
209
+ */
210
+ async findOne(id) {
211
+ if(this.is_activity) {
212
+ return this.dataSet || {};
213
+ }
214
+
215
+ let findOneFunc = ValueUtil.getParams(this.gqlInfo, 'query', 'find_one_func')
216
+ // 조회 결과 에서 다른 필드로 변환 될 필드 ( ex) parent.name ==> parentName )
217
+ // 객체 조회 후 내용을 리스트에 표현 할때 사용 ...
218
+ let queryAfterSetFields = ValueUtil.getParams(this.gqlInfo, 'query', 'after_set_fields')
219
+
220
+ // 그리스트 설정을 이용 한 조회 필드 생성시 skip 대상 필드
221
+ let selectSkipFields = Object.keys(queryAfterSetFields || {})
222
+ let selectFields = MetaApi.getSelectColumns((this.gristConfigSet ? this.gristConfigSet : { columns: this.formConfigSet }).columns.filter(x => !selectSkipFields.includes(x.name)))
223
+
224
+ // 조회
225
+ let result = {};
226
+
227
+ if(findOneFunc.includes('$')) {
228
+ let scenarioName = findOneFunc.replace('$', '');
229
+ let response = await MetaApi.callScenario(undefined, scenarioName, {
230
+ id
231
+ }, false)
232
+
233
+ result = response.data.runScenario.result.result;
234
+ } else {
235
+ result = await MetaApi.findOne(findOneFunc, id, selectFields)
236
+ }
237
+
238
+ // 조회 결과 가공
239
+ if (ValueUtil.isNotEmpty(queryAfterSetFields)) {
240
+ if (ValueUtil.isNotEmpty(result)) {
241
+ selectSkipFields.forEach(key => {
242
+ result[key] = ValueUtil.getParams(result, ...(queryAfterSetFields[key].split('.')))
243
+ })
244
+ }
245
+ }
246
+
247
+ return result
248
+ }
249
+
250
+ /**
251
+ * @description 레코드 ID들(ids)로 부터 레코드 한꺼번에 삭제
252
+ ****************************************************
253
+ * @param {String} ids
254
+ * @returns {Boolean} 삭제 여부
255
+ */
256
+ async deleteByIds(ids) {
257
+ let deleteFunc = ValueUtil.getParams(this.gqlInfo, 'mutation', 'delete', 'func')
258
+ return await MetaApi.deleteListByIds(ids, deleteFunc)
259
+ }
260
+
261
+ /**
262
+ * @description 변경 데이터들 한꺼번에 추가 혹은 업데이트
263
+ ****************************************************
264
+ * @param {Array} params
265
+ */
266
+ async updateMultiple(params) {
267
+ let mutationFunc = ValueUtil.getParams(this.gqlInfo, 'mutation', 'multiple', 'func')
268
+ let skipToSaveFields = ValueUtil.getParams(this.gqlInfo, 'mutation', 'multiple', 'skip_fields')
269
+ let mutationType = ValueUtil.getParams(this.gqlInfo, 'mutation', 'multiple', 'type')
270
+ let patches = mutationType == 'ScalarObject' ? params.patches : params
271
+
272
+ // 저장시 필터링 되어야 될 필드 삭제
273
+ if (ValueUtil.isNotEmpty(skipToSaveFields)) {
274
+ skipToSaveFields = skipToSaveFields.map(f => { return f.includes('.') ? f.split('.') : f })
275
+
276
+ patches = patches.map(patch => {
277
+ skipToSaveFields.forEach(field => {
278
+ if (Array.isArray(field)) {
279
+ delete patch[field[0]][field[1]]
280
+ } else {
281
+ delete patch[field]
282
+ }
283
+ })
284
+ return patch
285
+ })
286
+ }
287
+
288
+ // 엘리먼트의 경우 상위 데이터 parentId가 있다.
289
+ if (this.isElement && ValueUtil.isNotEmpty(this.parent_id)) {
290
+ let parentId = ValueUtil.getParams(this.gqlInfo, 'mutation', 'multiple', 'parent_id')
291
+ if (ValueUtil.isNotEmpty(parentId)) {
292
+ patches.forEach(patch => {
293
+ if (parentId.includes('.')) {
294
+ let objFields = parentId.split('.')
295
+ patch[objFields[0]] = {};
296
+ patch[objFields[0]][objFields[1]] = this.parent_id
297
+ } else {
298
+ patch[parentId] = this.parent_id
299
+ }
300
+ })
301
+ }
302
+ }
303
+
304
+ return await MetaApi.updateMultiple(mutationFunc, params)
305
+ }
306
+ }