evui 3.2.0 → 3.3.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.
@@ -1,4 +1,4 @@
1
- import { getCurrentInstance, nextTick } from 'vue';
1
+ import { getCurrentInstance } from 'vue';
2
2
  import { isEqual, uniqBy } from 'lodash-es';
3
3
  import { numberWithComma } from '@/common/utils';
4
4
 
@@ -368,7 +368,7 @@ export const clickEvent = (params) => {
368
368
  };
369
369
 
370
370
  export const checkEvent = (params) => {
371
- const { checkInfo, stores, filterInfo } = params;
371
+ const { checkInfo, stores } = params;
372
372
  const { emit } = getCurrentInstance();
373
373
  /**
374
374
  * row에 대한 체크 상태를 해제한다.
@@ -404,20 +404,12 @@ export const checkEvent = (params) => {
404
404
  }
405
405
  checkInfo.checkedIndex.add(row[ROW_INDEX]);
406
406
 
407
- let store = stores.originStore;
408
- let checkSize = checkInfo.checkedRows.length;
409
- if (filterInfo.isSearch && stores.searchStore) {
410
- store = stores.searchStore;
411
- checkSize = checkInfo.checkedIndex.size;
412
- }
413
- if (checkSize >= store.length) {
407
+ const store = stores.store;
408
+ const isAllChecked = store.every(d => d[ROW_CHECK_INDEX]);
409
+ if (store.length && isAllChecked) {
414
410
  checkInfo.isHeaderChecked = true;
415
411
  }
416
412
  } else {
417
- if (checkInfo.isHeaderChecked) {
418
- checkInfo.isHeaderChecked = false;
419
- }
420
-
421
413
  if (checkInfo.useCheckbox.mode === 'single') {
422
414
  checkInfo.checkedRows = [];
423
415
  checkInfo.checkedIndex.clear();
@@ -425,8 +417,8 @@ export const checkEvent = (params) => {
425
417
  checkInfo.checkedRows.splice(checkInfo.checkedRows.indexOf(row[ROW_DATA_INDEX]), 1);
426
418
  checkInfo.checkedIndex.delete(row[ROW_INDEX]);
427
419
  }
420
+ checkInfo.isHeaderChecked = false;
428
421
  }
429
-
430
422
  checkInfo.prevCheckedRow = row.slice();
431
423
  emit('update:checked', checkInfo.checkedRows);
432
424
  emit('check-row', event, row[ROW_INDEX], row[ROW_DATA_INDEX]);
@@ -437,28 +429,24 @@ export const checkEvent = (params) => {
437
429
  * @param {object} event - 이벤트 객체
438
430
  */
439
431
  const onCheckAll = (event) => {
440
- const status = checkInfo.isHeaderChecked;
441
- const checked = [];
442
- let item;
443
- let store = stores.originStore;
444
- if (filterInfo.isSearch && stores.searchStore) {
445
- store = stores.searchStore;
446
- }
447
- for (let ix = 0; ix < store.length; ix++) {
448
- item = store[ix];
449
- if (status) {
450
- checked.push(item[ROW_DATA_INDEX]);
451
- checkInfo.checkedIndex.add(item[ROW_INDEX]);
432
+ const isHeaderChecked = checkInfo.isHeaderChecked;
433
+ const store = stores.store;
434
+ store.forEach((row) => {
435
+ if (isHeaderChecked) {
436
+ if (!checkInfo.checkedRows.includes(row[ROW_DATA_INDEX])) {
437
+ checkInfo.checkedRows.push(row[ROW_DATA_INDEX]);
438
+ }
439
+ if (!checkInfo.checkedIndex.has(row[ROW_INDEX])) {
440
+ checkInfo.checkedIndex.add(row[ROW_INDEX]);
441
+ }
452
442
  } else {
453
- checkInfo.checkedIndex.clear();
443
+ checkInfo.checkedRows.splice(checkInfo.checkedRows.indexOf(row[ROW_DATA_INDEX]), 1);
444
+ checkInfo.checkedIndex.delete(row[ROW_INDEX]);
454
445
  }
455
-
456
- item[ROW_CHECK_INDEX] = status;
457
- }
458
-
459
- checkInfo.checkedRows = checked;
460
- emit('update:checked', checked);
461
- emit('check-all', event, checked);
446
+ row[ROW_CHECK_INDEX] = isHeaderChecked;
447
+ });
448
+ emit('update:checked', checkInfo.checkedRows);
449
+ emit('check-all', event, checkInfo.checkedRows);
462
450
  };
463
451
  return { onCheck, onCheckAll };
464
452
  };
@@ -530,7 +518,14 @@ export const sortEvent = (params) => {
530
518
 
531
519
  export const filterEvent = (params) => {
532
520
  const { props } = getCurrentInstance();
533
- const { filterInfo, stores, getColumnIndex } = params;
521
+ const {
522
+ filterInfo,
523
+ stores,
524
+ checkInfo,
525
+ getColumnIndex,
526
+ getConvertValue,
527
+ updateVScroll,
528
+ } = params;
534
529
  /**
535
530
  * 해당 컬럼에 대한 필터 팝업을 보여준다.
536
531
  *
@@ -708,7 +703,56 @@ export const filterEvent = (params) => {
708
703
  stores.filterStore = uniqBy(filterStore, JSON.stringify);
709
704
  }
710
705
  };
711
- return { onClickFilter, onCloseFilterWindow, onApplyFilter, setFilter };
706
+ let timer = null;
707
+ const onSearch = (searchWord) => {
708
+ if (timer) {
709
+ clearTimeout(timer);
710
+ }
711
+ timer = setTimeout(() => {
712
+ filterInfo.isSearch = false;
713
+ if (searchWord) {
714
+ stores.searchStore = stores.store.filter((row) => {
715
+ let isShow = false;
716
+ for (let ix = 0; ix < stores.orderedColumns.length; ix++) {
717
+ const column = stores.orderedColumns[ix] || {};
718
+ let columnValue = row[ROW_DATA_INDEX][ix];
719
+ const columnType = column.type || 'string';
720
+ if (columnValue) {
721
+ if (typeof columnValue === 'object') {
722
+ columnValue = columnValue[column.field];
723
+ }
724
+ if (!column.hide && (column?.searchable === undefined || column?.searchable)) {
725
+ columnValue = getConvertValue(columnType, columnValue).toString();
726
+ isShow = columnValue.toLowerCase().includes(searchWord.toString().toLowerCase());
727
+ if (isShow) {
728
+ break;
729
+ }
730
+ }
731
+ }
732
+ }
733
+ return isShow;
734
+ });
735
+ filterInfo.isSearch = true;
736
+ }
737
+ const store = stores.store;
738
+ let checkedCount = 0;
739
+ for (let ix = 0; ix < store.length; ix++) {
740
+ if (checkInfo.checkedIndex.has(store[ix][ROW_INDEX])) {
741
+ store[ix][ROW_CHECK_INDEX] = true;
742
+ checkedCount += 1;
743
+ } else {
744
+ store[ix][ROW_CHECK_INDEX] = false;
745
+ }
746
+ }
747
+ if (store.length && store.length === checkedCount) {
748
+ checkInfo.isHeaderChecked = true;
749
+ } else {
750
+ checkInfo.isHeaderChecked = false;
751
+ }
752
+ updateVScroll();
753
+ }, 500);
754
+ };
755
+ return { onClickFilter, onCloseFilterWindow, onApplyFilter, setFilter, onSearch };
712
756
  };
713
757
 
714
758
  export const contextMenuEvent = (params) => {
@@ -797,47 +841,40 @@ export const storeEvent = (params) => {
797
841
  * 전달된 데이터를 내부 store 및 속성에 저장한다.
798
842
  *
799
843
  * @param {array} value - row 데이터
800
- * @param {boolean} makeIndex - 인덱스 생성 유무
844
+ * @param {boolean} isMakeIndex - 인덱스 생성 유무
801
845
  */
802
- const setStore = (value, makeIndex = true) => {
803
- nextTick(() => {
804
- const store = [];
805
- let checked;
806
- let selected = false;
807
- if (makeIndex) {
808
- let hasUnChecked = false;
809
-
810
- for (let ix = 0; ix < value.length; ix++) {
811
- checked = props.checked.includes(value[ix]);
812
- if (!checked) {
813
- hasUnChecked = true;
814
- }
815
-
816
- if (!selected && isEqual(selectInfo.selectedRow, value[ix])) {
817
- selectInfo.selectedRow = value[ix];
818
- selected = true;
819
- }
820
-
821
- store.push([ix, checked, value[ix]]);
846
+ const setStore = (value, isMakeIndex = true) => {
847
+ const store = [];
848
+ let checked;
849
+ let selected = false;
850
+ if (isMakeIndex) {
851
+ let hasUnChecked = false;
852
+ for (let ix = 0; ix < value.length; ix++) {
853
+ checked = props.checked.includes(value[ix]);
854
+ if (!checked) {
855
+ hasUnChecked = true;
822
856
  }
823
-
824
- if (!selected) {
825
- selectInfo.selectedRow = [];
857
+ if (!selected && isEqual(selectInfo.selectedRow, value[ix])) {
858
+ selectInfo.selectedRow = value[ix];
859
+ selected = true;
826
860
  }
827
-
828
- checkInfo.isHeaderChecked = value.length > 0 ? !hasUnChecked : false;
829
- stores.originStore = store;
861
+ store.push([ix, checked, value[ix]]);
830
862
  }
831
- if (filterInfo.isFiltering) {
832
- setFilter();
863
+ if (!selected) {
864
+ selectInfo.selectedRow = [];
833
865
  }
834
- if (sortInfo.sortField) {
835
- setSort();
836
- }
837
- if (elementInfo.body?.clientHeight) {
838
- updateVScroll();
839
- }
840
- });
866
+ checkInfo.isHeaderChecked = value.length > 0 ? !hasUnChecked : false;
867
+ stores.originStore = store;
868
+ }
869
+ if (filterInfo.isFiltering) {
870
+ setFilter();
871
+ }
872
+ if (sortInfo.sortField) {
873
+ setSort();
874
+ }
875
+ if (elementInfo.body?.clientHeight) {
876
+ updateVScroll();
877
+ }
841
878
  };
842
879
  /**
843
880
  * 컴포넌트의 변경 데이터를 store에 업데이트한다.
@@ -162,7 +162,7 @@
162
162
  </template>
163
163
 
164
164
  <script>
165
- import { reactive, toRefs, computed, watch } from 'vue';
165
+ import { reactive, toRefs, computed, watch, onMounted, onActivated } from 'vue';
166
166
  import treeGridNode from './TreeGridNode';
167
167
  import Toolbar from './treeGrid.toolbar';
168
168
  import {
@@ -242,6 +242,7 @@ export default {
242
242
  resizeLine: null,
243
243
  'grid-wrapper': null,
244
244
  });
245
+ const searchValue = computed(() => (props.option.searchValue || ''));
245
246
  const stores = reactive({
246
247
  treeStore: [],
247
248
  viewStore: [],
@@ -333,20 +334,28 @@ export default {
333
334
  onSearch,
334
335
  } = filterEvent({ checkInfo, stores, getConvertValue, calculatedColumn, updateVScroll });
335
336
 
337
+ onMounted(() => {
338
+ stores.treeStore = setTreeNodeStore();
339
+ });
340
+ onActivated(() => {
341
+ updateVScroll();
342
+ });
336
343
  watch(
337
344
  () => props.checked,
338
- (value) => {
345
+ (checkedList) => {
339
346
  let store = stores.treeStore;
340
347
  if (stores.searchStore.length > 0) {
341
348
  store = stores.searchStore;
342
349
  }
343
- const isCheck = store.every(n => n.checked === true);
350
+ checkInfo.checkedRows = checkedList;
344
351
  checkInfo.isHeaderChecked = false;
345
- checkInfo.checkedRows = value;
346
- for (let ix = 0; ix < store.length; ix++) {
347
- store[ix].checked = value.includes(store[ix]);
352
+ if (store.length) {
353
+ store.forEach((row) => {
354
+ row.checked = checkedList.includes(row);
355
+ });
356
+ checkInfo.isHeaderChecked = store.every(n => n.checked === true);
348
357
  }
349
- checkInfo.isHeaderChecked = isCheck;
358
+ updateVScroll();
350
359
  },
351
360
  );
352
361
  watch(
@@ -362,8 +371,6 @@ export default {
362
371
  checkInfo.isHeaderChecked = false;
363
372
  },
364
373
  );
365
- stores.treeStore = setTreeNodeStore();
366
-
367
374
  watch(
368
375
  () => props.rows,
369
376
  (newData) => {
@@ -390,6 +397,12 @@ export default {
390
397
  onResize();
391
398
  },
392
399
  );
400
+ watch(
401
+ () => searchValue.value,
402
+ (value) => {
403
+ onSearch(value?.value ?? value);
404
+ }, { immediate: true },
405
+ );
393
406
  const gridStyle = computed(() => ({
394
407
  width: resizeInfo.gridWidth,
395
408
  height: resizeInfo.gridHeight,
@@ -655,10 +655,27 @@ export const filterEvent = (params) => {
655
655
  }
656
656
  const { parent } = data;
657
657
  parent.show = true;
658
- parent.expand = true;
659
658
  parent.isFilter = true;
660
659
  makeParentShow(parent);
661
660
  };
661
+ const makeChildShow = (data) => {
662
+ if (!data?.children) {
663
+ return;
664
+ }
665
+ const { children } = data;
666
+ children.forEach((node) => {
667
+ const childNode = node;
668
+ if (childNode.parent.show && childNode.parent.expand) {
669
+ childNode.show = true;
670
+ } else {
671
+ childNode.show = false;
672
+ }
673
+ childNode.isFilter = true;
674
+ if (childNode.hasChild) {
675
+ makeChildShow(childNode);
676
+ }
677
+ });
678
+ };
662
679
  let timer = null;
663
680
  const onSearch = (searchWord) => {
664
681
  if (timer) {
@@ -695,19 +712,28 @@ export const filterEvent = (params) => {
695
712
  });
696
713
  filterStores.forEach((row) => {
697
714
  row.show = true;
715
+ if (row.parent && !row.parent.expand) {
716
+ row.show = false;
717
+ }
698
718
  row.isFilter = true;
699
719
  makeParentShow(row);
720
+ makeChildShow(row);
700
721
  });
701
722
  } else {
702
723
  store.forEach((row) => {
703
724
  row.show = true;
704
725
  row.isFilter = false;
705
726
  });
727
+ store.forEach((row) => {
728
+ if (row.hasChild) {
729
+ makeChildShow(row);
730
+ }
731
+ });
706
732
  }
707
733
  if (stores.searchStore.length > 0) {
708
734
  store = stores.searchStore;
709
735
  }
710
- const isCheck = store.every(n => n.checked === true);
736
+ const isCheck = store.length > 0 && store.every(n => n.checked === true);
711
737
  checkInfo.isHeaderChecked = isCheck;
712
738
  calculatedColumn();
713
739
  updateVScroll();