evui 3.1.38 → 3.1.42

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 (33) hide show
  1. package/dist/evui.common.js +2699 -970
  2. package/dist/evui.common.js.map +1 -1
  3. package/dist/evui.umd.js +2699 -970
  4. package/dist/evui.umd.js.map +1 -1
  5. package/dist/evui.umd.min.js +1 -1
  6. package/dist/evui.umd.min.js.map +1 -1
  7. package/package.json +1 -1
  8. package/src/components/calendar/Calendar.vue +194 -82
  9. package/src/components/calendar/uses.js +457 -138
  10. package/src/components/chart/chart.core.js +27 -23
  11. package/src/components/chart/element/element.bar.js +28 -20
  12. package/src/components/chart/element/element.line.js +13 -0
  13. package/src/components/chart/helpers/helpers.constant.js +27 -0
  14. package/src/components/chart/helpers/helpers.util.js +2 -2
  15. package/src/components/chart/plugins/plugins.interaction.js +5 -5
  16. package/src/components/chart/plugins/plugins.legend.js +6 -3
  17. package/src/components/chart/plugins/plugins.tooltip.js +14 -1
  18. package/src/components/chart/scale/scale.js +520 -56
  19. package/src/components/chart/scale/scale.linear.js +8 -0
  20. package/src/components/chart/scale/scale.logarithmic.js +8 -0
  21. package/src/components/chart/scale/scale.step.js +148 -69
  22. package/src/components/chart/scale/scale.time.category.js +8 -0
  23. package/src/components/chart/scale/scale.time.js +8 -0
  24. package/src/components/chart/uses.js +2 -2
  25. package/src/components/contextMenu/MenuList.vue +1 -1
  26. package/src/components/datePicker/DatePicker.vue +91 -29
  27. package/src/components/datePicker/uses.js +231 -21
  28. package/src/components/grid/Grid.vue +15 -10
  29. package/src/components/tabs/Tabs.vue +12 -11
  30. package/src/components/treeGrid/TreeGrid.vue +56 -2
  31. package/src/components/treeGrid/TreeGridNode.vue +10 -1
  32. package/src/components/treeGrid/treeGrid.toolbar.vue +26 -0
  33. package/src/components/treeGrid/uses.js +66 -6
@@ -2,12 +2,14 @@ import {
2
2
  ref, reactive, computed, watch,
3
3
  nextTick, getCurrentInstance,
4
4
  } from 'vue';
5
+ import { getChangedValueByTimeFormat } from '../calendar/uses';
5
6
 
6
7
  const dateReg = new RegExp(/[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])/);
7
8
  const dateTimeReg = new RegExp(/[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1]) (2[0-3]|[01][0-9]):[0-5][0-9]:[0-5][0-9]/);
8
9
 
9
10
  export const useModel = () => {
10
11
  const { props, emit } = getCurrentInstance();
12
+ const timeFormat = props.options?.timeFormat;
11
13
 
12
14
  // Select 컴포넌트의 v-model 값
13
15
  const mv = computed({
@@ -15,13 +17,42 @@ export const useModel = () => {
15
17
  if (!props.modelValue) {
16
18
  return (props.mode === 'date' || props.mode === 'dateTime') ? '' : [];
17
19
  }
20
+ if (['dateTime', 'dateTimeRange'].includes(props.mode) && timeFormat) {
21
+ if (props.mode === 'dateTime') {
22
+ return getChangedValueByTimeFormat(timeFormat, props.modelValue);
23
+ } else if (props.modelValue.length) {
24
+ const [fromTimeFormat, toTimeFormat] = timeFormat;
25
+ return [
26
+ getChangedValueByTimeFormat(fromTimeFormat, props.modelValue[0]),
27
+ getChangedValueByTimeFormat(toTimeFormat, props.modelValue[1]),
28
+ ];
29
+ }
30
+ }
18
31
  return props.modelValue;
19
32
  },
20
33
  set: value => emit('update:modelValue', value),
21
34
  });
22
35
 
23
36
  // mode: 'date' or 'dateTime'시 input box의 입력된 텍스트값
24
- const currentValue = ref(props.modelValue);
37
+ let currentValue;
38
+ if (['dateTimeRange', 'dateTime'].includes(props.mode) && timeFormat) {
39
+ if (props.mode === 'dateTimeRange' && props.modelValue.length) {
40
+ const [fromDate, toDate] = props.modelValue;
41
+ const [fromTimeFormat, toTimeFormat] = timeFormat;
42
+
43
+ props.modelValue = [
44
+ getChangedValueByTimeFormat(fromTimeFormat, fromDate),
45
+ getChangedValueByTimeFormat(toTimeFormat, toDate),
46
+ ];
47
+ currentValue = ref(props.modelValue);
48
+ } else if (props.mode === 'dateTime' && props.modelValue) {
49
+ currentValue = ref(getChangedValueByTimeFormat(timeFormat, props.modelValue));
50
+ } else {
51
+ currentValue = ref(props.modelValue);
52
+ }
53
+ } else {
54
+ currentValue = ref(props.modelValue);
55
+ }
25
56
 
26
57
  const validateValue = (curr) => {
27
58
  if (props.mode === 'date'
@@ -89,9 +120,8 @@ export const useModel = () => {
89
120
  };
90
121
  };
91
122
 
92
- export const useDropdown = (param) => {
123
+ export const useDropdown = () => {
93
124
  const { props } = getCurrentInstance();
94
- const { currentValue } = param;
95
125
 
96
126
  const isDropbox = ref(false);
97
127
  const datePicker = ref(null);
@@ -162,24 +192,6 @@ export const useDropdown = (param) => {
162
192
  isDropbox.value = false;
163
193
  };
164
194
 
165
- watch(
166
- () => props.modelValue,
167
- (curr) => {
168
- if (props.mode === 'dateMulti'
169
- && props?.options?.multiType === 'date'
170
- && props?.options?.multiDayLimit > curr.length
171
- ) {
172
- return;
173
- } else if (props.mode === 'dateTime') {
174
- currentValue.value = curr;
175
- return;
176
- } else if (props.mode === 'date') {
177
- currentValue.value = curr;
178
- }
179
- clickOutsideDropbox();
180
- },
181
- );
182
-
183
195
  return {
184
196
  isDropbox,
185
197
  datePicker,
@@ -191,3 +203,201 @@ export const useDropdown = (param) => {
191
203
  changeDropboxPosition,
192
204
  };
193
205
  };
206
+
207
+ export const useShortcuts = (param) => {
208
+ const { props } = getCurrentInstance();
209
+ const { mv, currentValue, clickOutsideDropbox } = param;
210
+
211
+ const usedShortcuts = reactive([]);
212
+ props.shortcuts?.forEach(({ value, label, shortcutDate }) => {
213
+ usedShortcuts.push({
214
+ key: value,
215
+ label,
216
+ shortcutDate,
217
+ isActive: false,
218
+ });
219
+ });
220
+
221
+ /**
222
+ * active 되어있는 shortcut 제거
223
+ */
224
+ const clearShortcuts = () => {
225
+ const targetShortcut = usedShortcuts.find(shortcut => shortcut.isActive);
226
+ if (targetShortcut) {
227
+ targetShortcut.isActive = false;
228
+ }
229
+ };
230
+
231
+ /**
232
+ * targetKey에 해당하는 shortcut을 active
233
+ * @param targetKey
234
+ */
235
+ const activeShortcut = (targetKey) => {
236
+ const targetShortcut = usedShortcuts.find(shortcut => shortcut.key === targetKey);
237
+ if (targetShortcut) {
238
+ targetShortcut.isActive = true;
239
+ }
240
+ };
241
+
242
+ /**
243
+ * 월, 일을 두자리 숫자로 보정
244
+ * @param num
245
+ * @returns {string|*}
246
+ */
247
+ const lpadToTwoDigits = (num) => {
248
+ if (num === null) {
249
+ return '00';
250
+ } else if (+num < 10) {
251
+ return `0${num}`;
252
+ }
253
+ return num;
254
+ };
255
+
256
+ /**
257
+ * 'YYYY-MM-DD' 형식으로 format
258
+ * @param targetDate
259
+ * @returns string
260
+ */
261
+ const formatDate = (targetDate) => {
262
+ const dateValue = targetDate ? new Date(targetDate) : new Date();
263
+ const year = dateValue.getFullYear();
264
+ const month = dateValue.getMonth() + 1;
265
+ const day = dateValue.getDate();
266
+ return `${year}-${lpadToTwoDigits(month)}-${lpadToTwoDigits(day)}`;
267
+ };
268
+
269
+ /**
270
+ * 'YYYY-MM-DD HH:mm:ss' 형식으로 format
271
+ * @param targetDateTime
272
+ * @returns string
273
+ */
274
+ const formatDateTime = (targetDateTime) => {
275
+ const dateTimeValue = targetDateTime ? new Date(targetDateTime) : new Date();
276
+ const hour = dateTimeValue.getHours();
277
+ const min = dateTimeValue.getMinutes();
278
+ const sec = dateTimeValue.getSeconds();
279
+ return `${formatDate(dateTimeValue)} ${lpadToTwoDigits(hour)}:${lpadToTwoDigits(min)}:${lpadToTwoDigits(sec)}`;
280
+ };
281
+
282
+ /**
283
+ * 시, 분, 초를 원하는 값으로 변환
284
+ * @param targetDate
285
+ * @param hour
286
+ * @param min
287
+ * @param sec
288
+ * @returns {Date}
289
+ */
290
+ const getChangedDateTime = (targetDate, hour, min, sec) => {
291
+ const dateTimeValue = new Date(targetDate);
292
+ dateTimeValue.setHours(hour);
293
+ dateTimeValue.setMinutes(min);
294
+ dateTimeValue.setSeconds(sec);
295
+ return dateTimeValue;
296
+ };
297
+
298
+ /**
299
+ * 초기 shortcut 세팅
300
+ * 해당하는 날짜면 active
301
+ */
302
+ const setActiveShortcut = () => {
303
+ clearShortcuts();
304
+
305
+ const isRange = ['dateRange', 'dateTimeRange'].includes(props.mode);
306
+
307
+ if (!usedShortcuts.length
308
+ || (props.mode === 'dateMulti' && props.options?.multiType !== 'date')
309
+ || (isRange && !mv.value.length)
310
+ || (!isRange && !mv.value)
311
+ ) {
312
+ return;
313
+ }
314
+
315
+ let targetKey;
316
+ if (isRange) {
317
+ const [fromDate, toDate] = mv.value;
318
+ const targetShortcut = usedShortcuts.find(({ shortcutDate }) => {
319
+ const [sFromDate, sToDate] = shortcutDate();
320
+ const isCorrectFromDate = formatDate(sFromDate) === formatDate(fromDate);
321
+ const isCorrectToDate = formatDate(sToDate) === formatDate(toDate);
322
+ return isCorrectFromDate && isCorrectToDate;
323
+ });
324
+ targetKey = targetShortcut?.key;
325
+ } else {
326
+ const date = formatDate(mv.value);
327
+ const targetShortcut = usedShortcuts.find(({ shortcutDate }) => {
328
+ const sDate = formatDate(shortcutDate());
329
+ return sDate === formatDate(date);
330
+ });
331
+ targetKey = targetShortcut?.key;
332
+ }
333
+
334
+ if (targetKey) {
335
+ activeShortcut(targetKey);
336
+ }
337
+ };
338
+
339
+ /**
340
+ * shortcut을 클릭했을 때 이벤트
341
+ * @param targetKey
342
+ */
343
+ const clickShortcut = (targetKey) => {
344
+ const isRange = ['dateRange', 'dateTimeRange'].includes(props.mode);
345
+ const targetShortcut = usedShortcuts.find(({ key }) => key === targetKey);
346
+
347
+ if (!targetShortcut) {
348
+ return;
349
+ }
350
+
351
+ const shortcutDate = targetShortcut.shortcutDate;
352
+
353
+ if (isRange) {
354
+ const [fromDate, toDate] = shortcutDate();
355
+ if (props.mode === 'dateTimeRange') {
356
+ const from = getChangedDateTime(fromDate, 0, 0, 0);
357
+ const to = getChangedDateTime(toDate, 0, 0, 0);
358
+ const [fromTimeFormat, toTimeFormat] = props.options?.timeFormat;
359
+
360
+ mv.value = [
361
+ getChangedValueByTimeFormat(fromTimeFormat, formatDateTime(from)),
362
+ getChangedValueByTimeFormat(toTimeFormat, formatDateTime(to)),
363
+ ];
364
+ } else {
365
+ mv.value = [formatDate(fromDate), formatDate(toDate)];
366
+ }
367
+ } else {
368
+ const sDate = shortcutDate();
369
+ mv.value = props.mode === 'dateTime'
370
+ ? getChangedValueByTimeFormat(
371
+ props.options?.timeFormat,
372
+ formatDateTime(getChangedDateTime(sDate, 0, 0, 0)))
373
+ : formatDate(sDate);
374
+ }
375
+
376
+ clearShortcuts();
377
+ };
378
+
379
+ watch(
380
+ () => props.modelValue,
381
+ (curr) => {
382
+ setActiveShortcut();
383
+ if (props.mode === 'dateMulti'
384
+ && props?.options?.multiType === 'date'
385
+ && props?.options?.multiDayLimit > curr.length
386
+ ) {
387
+ return;
388
+ } else if (props.mode === 'dateTime' || props.mode === 'dateTimeRange') {
389
+ currentValue.value = curr;
390
+ return;
391
+ } else if (props.mode === 'date') {
392
+ currentValue.value = curr;
393
+ }
394
+ clickOutsideDropbox();
395
+ },
396
+ );
397
+
398
+ return {
399
+ usedShortcuts,
400
+ clickShortcut,
401
+ setActiveShortcut,
402
+ };
403
+ };
@@ -469,7 +469,9 @@ export default {
469
469
  calculatedColumn();
470
470
  setStore(props.rows);
471
471
  });
472
-
472
+ const ROW_INDEX = 0;
473
+ const ROW_CHECK_INDEX = 1;
474
+ const ROW_DATA_INDEX = 2;
473
475
  watch(
474
476
  () => sortInfo.setSorting,
475
477
  (value) => {
@@ -497,15 +499,18 @@ export default {
497
499
  watch(
498
500
  () => props.checked,
499
501
  (value) => {
500
- const ROW_CHECK_INDEX = 1;
501
- const ROW_DATA_INDEX = 2;
502
+ checkInfo.checkedRows = value;
503
+ checkInfo.isHeaderChecked = false;
502
504
  let store = stores.originStore;
503
505
  if (filterInfo.isSearch && stores.searchStore) {
504
506
  store = stores.searchStore;
505
507
  }
506
- checkInfo.checkedRows = value;
507
- for (let ix = 0; ix < store.length; ix++) {
508
- store[ix][ROW_CHECK_INDEX] = value.includes(store[ix][ROW_DATA_INDEX]);
508
+ store.forEach((row) => {
509
+ row[ROW_CHECK_INDEX] = checkInfo.checkedRows.includes(row[ROW_DATA_INDEX]);
510
+ });
511
+ if (checkInfo.checkedRows.length
512
+ && store.length === checkInfo.checkedRows.length) {
513
+ checkInfo.isHeaderChecked = true;
509
514
  }
510
515
  },
511
516
  );
@@ -560,7 +565,7 @@ export default {
560
565
  let isShow = false;
561
566
  for (let ix = 0; ix < stores.orderedColumns.length; ix++) {
562
567
  const column = stores.orderedColumns[ix] || {};
563
- let columnValue = row[2][ix];
568
+ let columnValue = row[ROW_DATA_INDEX][ix];
564
569
  let columnType = column.type;
565
570
  if (columnValue) {
566
571
  if (typeof columnValue === 'object') {
@@ -588,10 +593,10 @@ export default {
588
593
  let store = stores.originStore;
589
594
  let checkSize = checkInfo.checkedRows.length;
590
595
  for (let ix = 0; ix < store.length; ix++) {
591
- if (checkInfo.checkedIndex.has(store[ix][0])) {
592
- store[ix][1] = true;
596
+ if (checkInfo.checkedIndex.has(store[ix][ROW_INDEX])) {
597
+ store[ix][ROW_CHECK_INDEX] = true;
593
598
  } else {
594
- store[ix][1] = false;
599
+ store[ix][ROW_CHECK_INDEX] = false;
595
600
  }
596
601
  }
597
602
  if (filterInfo.isSearch && stores.searchStore) {
@@ -1,5 +1,10 @@
1
1
  <template>
2
2
  <section
3
+ v-resize="onResize"
4
+ v-observe-visibility="{
5
+ callback: onResize,
6
+ once: true,
7
+ }"
3
8
  class="ev-tabs"
4
9
  :class="{
5
10
  closable,
@@ -85,7 +90,7 @@
85
90
  import {
86
91
  ref, reactive, computed,
87
92
  provide, triggerRef,
88
- onBeforeUpdate, nextTick, onUpdated,
93
+ onBeforeUpdate, nextTick,
89
94
  } from 'vue';
90
95
 
91
96
  export default {
@@ -215,16 +220,6 @@ export default {
215
220
  }
216
221
  });
217
222
 
218
- // 최초 렌더링 시 El의 너비 확인
219
- nextTick(() => {
220
- observeListEl();
221
- });
222
-
223
- // 화면 업데이트 시 El의 너비 확인
224
- onUpdated(() => {
225
- observeListEl();
226
- });
227
-
228
223
  /**
229
224
  * 탭 클릭 로직
230
225
  */
@@ -342,6 +337,10 @@ export default {
342
337
  tabCloneList.value.splice(0);
343
338
  };
344
339
 
340
+ const onResize = () => {
341
+ observeListEl();
342
+ };
343
+
345
344
  return {
346
345
  mv,
347
346
  computedTabList,
@@ -359,6 +358,8 @@ export default {
359
358
  dragendTab,
360
359
  dragSelectCls,
361
360
  selectIdxCls,
361
+
362
+ onResize,
362
363
  };
363
364
  },
364
365
  };
@@ -1,4 +1,22 @@
1
1
  <template>
2
+ <div
3
+ v-if="!!$slots.toolbar"
4
+ class="toolbar-wrapper"
5
+ :style="`width: ${gridWidth};`"
6
+ >
7
+ <!-- Toolbar -->
8
+ <toolbar v-if="!!$slots.toolbar" >
9
+ <template #toolbarWrapper>
10
+ <slot
11
+ name="toolbar"
12
+ :item="{
13
+ onSearch,
14
+ }"
15
+ >
16
+ </slot>
17
+ </template>
18
+ </toolbar>
19
+ </div>
2
20
  <div
3
21
  ref="grid-wrapper"
4
22
  v-resize="onResize"
@@ -76,10 +94,10 @@
76
94
  <table>
77
95
  <tbody>
78
96
  <tree-grid-node
79
- v-for="(item, idx) in viewStore"
97
+ v-for="(node, idx) in viewStore"
80
98
  :key="idx"
81
99
  :selected-data="selectedRow"
82
- :node-data="item"
100
+ :node-data="node"
83
101
  :use-checkbox="useCheckbox"
84
102
  :ordered-columns="orderedColumns"
85
103
  :expand-icon="option.expandIcon"
@@ -96,6 +114,26 @@
96
114
  @click-tree-data="onRowClick"
97
115
  @dbl-click-tree-data="onRowDblClick"
98
116
  >
117
+ <!-- cell renderer -->
118
+ <template
119
+ v-for="(column, cellIndex) in orderedColumns"
120
+ :key="cellIndex"
121
+ v-slot:[getSlotName(column.field)] = "{ item }"
122
+ >
123
+ <template v-if="!!$slots[column.field]">
124
+ <slot
125
+ :name="column.field"
126
+ :item="{
127
+ data: item.data,
128
+ fieldName: column.field
129
+ }"
130
+ >
131
+ </slot>
132
+ </template>
133
+ <template v-else>
134
+ <span :title="node[column.field]">{{node[column.field]}}</span>
135
+ </template>
136
+ </template>
99
137
  </tree-grid-node>
100
138
  <tr v-if="!viewStore.length">
101
139
  <td class="is-empty">No records</td>
@@ -126,6 +164,7 @@
126
164
  <script>
127
165
  import { reactive, toRefs, computed, watch, nextTick } from 'vue';
128
166
  import treeGridNode from './TreeGridNode';
167
+ import Toolbar from './treeGrid.toolbar';
129
168
  import {
130
169
  commonFunctions,
131
170
  scrollEvent,
@@ -134,12 +173,14 @@ import {
134
173
  checkEvent,
135
174
  contextMenuEvent,
136
175
  treeEvent,
176
+ filterEvent,
137
177
  } from './uses';
138
178
 
139
179
  export default {
140
180
  name: 'EvTreeGrid',
141
181
  components: {
142
182
  treeGridNode,
183
+ Toolbar,
143
184
  },
144
185
  props: {
145
186
  columns: {
@@ -287,6 +328,10 @@ export default {
287
328
  handleExpand,
288
329
  } = treeEvent({ stores, onResize });
289
330
 
331
+ const {
332
+ onSearch,
333
+ } = filterEvent({ stores, getConvertValue, calculatedColumn, updateVScroll });
334
+
290
335
  watch(
291
336
  () => props.checked,
292
337
  (value) => {
@@ -301,6 +346,12 @@ export default {
301
346
  }
302
347
  },
303
348
  );
349
+ watch(
350
+ () => props.selected,
351
+ (value) => {
352
+ selectInfo.selectedRow = value;
353
+ },
354
+ );
304
355
  watch(
305
356
  () => checkInfo.useCheckbox.mode,
306
357
  () => {
@@ -381,6 +432,7 @@ export default {
381
432
  'min-width': render ? `${resizeInfo.rendererMinWidth}px;` : `${resizeInfo.minWidth}px`,
382
433
  };
383
434
  };
435
+ const getSlotName = column => `${column}Node`;
384
436
 
385
437
  return {
386
438
  ...toRefs(styleInfo),
@@ -409,6 +461,7 @@ export default {
409
461
  onCheckAll,
410
462
  setContextMenu,
411
463
  onContextMenu,
464
+ onSearch,
412
465
  handleExpand,
413
466
  gridStyle,
414
467
  gridClass,
@@ -417,6 +470,7 @@ export default {
417
470
  isHeaderCheckbox,
418
471
  getColumnClass,
419
472
  getColumnStyle,
473
+ getSlotName,
420
474
  bodyStyle,
421
475
  };
422
476
  },
@@ -75,7 +75,16 @@
75
75
  <i></i>
76
76
  </span>
77
77
  </span>
78
- <span :title="node[column.field]">{{node[column.field]}}</span>
78
+ <!-- cell renderer -->
79
+ <template v-if="!!$slots[column.field + 'Node']">
80
+ <slot
81
+ :name="column.field + 'Node'"
82
+ :item="{
83
+ data: node.data,
84
+ }"
85
+ >
86
+ </slot>
87
+ </template>
79
88
  </div>
80
89
  </td>
81
90
  </template>
@@ -0,0 +1,26 @@
1
+ <template>
2
+ <div class="description tree-grid-toolbar">
3
+ <slot name="toolbarWrapper"></slot>
4
+ </div>
5
+ </template>
6
+
7
+ <script>
8
+ export default {
9
+ name: 'EvTreeGridToolbar',
10
+ };
11
+ </script>
12
+
13
+ <style lang="scss">
14
+ @import '../../style/index.scss';
15
+ .tree-grid-toolbar {
16
+ margin-bottom: 10px;
17
+ overflow: hidden;
18
+ }
19
+ .tree-grid-toolbar > .search {
20
+ float: right;
21
+ margin-right: 0;
22
+ }
23
+ .tree-grid-toolbar > .ev-button {
24
+ margin: 0 2px 0 2px;
25
+ }
26
+ </style>
@@ -572,29 +572,89 @@ export const treeEvent = (params) => {
572
572
  node.checked = false;
573
573
  node.index = index++;
574
574
  node.parent = parent;
575
+ node.isFilter = false;
575
576
  stores.treeStore.push(node);
576
-
577
577
  if (node.children && node.children.length > 0) {
578
578
  node.hasChild = true;
579
579
  setTreeStore(node.children, node.level + 1, node.show && node.expand, node);
580
580
  }
581
581
  });
582
582
  };
583
- const setExpandNode = (children, isShow) => {
583
+ const setExpandNode = (children, isShow, isFilter) => {
584
584
  children.forEach((nodeObj) => {
585
585
  const node = nodeObj;
586
- node.show = isShow;
587
-
586
+ node.show = isFilter && isShow ? node.isFilter : isShow;
588
587
  if (node.hasChild) {
589
- setExpandNode(node.children, node.show && node.expand);
588
+ setExpandNode(node.children, node.show && node.expand, node.isFilter);
590
589
  }
591
590
  });
592
591
  };
593
592
  const handleExpand = (node) => {
594
593
  const data = node;
595
594
  data.expand = !data.expand;
596
- setExpandNode(data.children, data.expand);
595
+ setExpandNode(data.children, data.expand, data.isFilter);
597
596
  onResize();
598
597
  };
599
598
  return { setTreeStore, handleExpand };
600
599
  };
600
+
601
+ export const filterEvent = (params) => {
602
+ const { stores, getConvertValue, calculatedColumn, updateVScroll } = params;
603
+ const makeParentShow = (data) => {
604
+ if (!data?.parent) {
605
+ return;
606
+ }
607
+ const { parent } = data;
608
+ parent.show = true;
609
+ parent.expand = true;
610
+ parent.isFilter = true;
611
+ makeParentShow(parent);
612
+ };
613
+ let timer = null;
614
+ const onSearch = (searchWord) => {
615
+ if (timer) {
616
+ clearTimeout(timer);
617
+ }
618
+ timer = setTimeout(() => {
619
+ stores.treeStore.forEach((row) => {
620
+ row.show = false;
621
+ row.isFilter = false;
622
+ });
623
+ if (searchWord) {
624
+ const filterStores = stores.treeStore.filter((row) => {
625
+ let isSameWord = false;
626
+ for (let ix = 0; ix < stores.orderedColumns.length; ix++) {
627
+ const column = stores.orderedColumns[ix] || {};
628
+ let columnValue = row[column.field];
629
+ let columnType = column.type;
630
+ if (columnValue) {
631
+ if (!columnType) {
632
+ columnType = 'string';
633
+ }
634
+ columnValue = getConvertValue(columnType, columnValue).toString();
635
+ isSameWord = columnValue.toLowerCase()
636
+ .includes(searchWord.toString().toLowerCase());
637
+ if (isSameWord) {
638
+ break;
639
+ }
640
+ }
641
+ }
642
+ return isSameWord;
643
+ });
644
+ filterStores.forEach((row) => {
645
+ row.show = true;
646
+ row.isFilter = true;
647
+ makeParentShow(row);
648
+ });
649
+ } else {
650
+ stores.treeStore.forEach((row) => {
651
+ row.show = true;
652
+ row.isFilter = false;
653
+ });
654
+ }
655
+ calculatedColumn();
656
+ updateVScroll();
657
+ }, 500);
658
+ };
659
+ return { onSearch };
660
+ };