evui 3.2.0 → 3.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "evui",
3
- "version": "3.2.0",
3
+ "version": "3.2.1",
4
4
  "description": "A EXEM Library project",
5
5
  "author": "exem <dev_client@ex-em.com>",
6
6
  "license": "MIT",
@@ -251,7 +251,7 @@
251
251
  </template>
252
252
 
253
253
  <script>
254
- import { reactive, toRefs, computed, watch, onMounted } from 'vue';
254
+ import { reactive, toRefs, computed, watch, onMounted, onActivated } from 'vue';
255
255
  import FilterWindow from './grid.filter.window';
256
256
  import Toolbar from './grid.toolbar';
257
257
  import {
@@ -334,13 +334,14 @@ export default {
334
334
  filterList: {},
335
335
  isFiltering: computed(() =>
336
336
  (props.option.useFilter === undefined ? true : props.option.useFilter)),
337
- isSearch: false,
338
337
  setFiltering: false,
339
338
  showFilterWindow: false,
340
339
  currentFilter: {
341
340
  column: {},
342
341
  items: [],
343
342
  },
343
+ isSearch: false,
344
+ searchWord: '',
344
345
  });
345
346
  const stores = reactive({
346
347
  viewStore: [],
@@ -428,7 +429,15 @@ export default {
428
429
  onCloseFilterWindow,
429
430
  onApplyFilter,
430
431
  setFilter,
431
- } = filterEvent({ filterInfo, stores, getColumnIndex });
432
+ onSearch,
433
+ } = filterEvent({
434
+ filterInfo,
435
+ stores,
436
+ checkInfo,
437
+ getColumnIndex,
438
+ getConvertValue,
439
+ updateVScroll,
440
+ });
432
441
 
433
442
  const {
434
443
  setStore,
@@ -461,9 +470,17 @@ export default {
461
470
  calculatedColumn();
462
471
  setStore(props.rows);
463
472
  });
473
+ onActivated(() => {
474
+ updateVScroll();
475
+ });
464
476
  const ROW_INDEX = 0;
465
477
  const ROW_CHECK_INDEX = 1;
466
478
  const ROW_DATA_INDEX = 2;
479
+ const clearCheckInfo = () => {
480
+ checkInfo.checkedRows = [];
481
+ checkInfo.checkedIndex.clear();
482
+ checkInfo.isHeaderChecked = false;
483
+ };
467
484
  watch(
468
485
  () => props.columns,
469
486
  () => {
@@ -494,24 +511,30 @@ export default {
494
511
  () => props.rows,
495
512
  (value) => {
496
513
  setStore(value);
514
+ if (filterInfo.isSearch) {
515
+ onSearch(filterInfo.searchWord);
516
+ }
497
517
  },
498
518
  );
499
519
  watch(
500
520
  () => props.checked,
501
- (value) => {
502
- checkInfo.checkedRows = value;
521
+ (checkedList) => {
522
+ checkInfo.checkedRows = checkedList;
503
523
  checkInfo.isHeaderChecked = false;
504
- let store = stores.originStore;
505
- if (filterInfo.isSearch && stores.searchStore) {
506
- store = stores.searchStore;
507
- }
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;
524
+ checkInfo.checkedIndex.clear();
525
+ if (checkedList.length) {
526
+ const store = stores.store;
527
+ store.forEach((row) => {
528
+ row[ROW_CHECK_INDEX] = checkedList.includes(row[ROW_DATA_INDEX]);
529
+ if (row[ROW_CHECK_INDEX]) {
530
+ checkInfo.checkedIndex.add(row[ROW_INDEX]);
531
+ }
532
+ });
533
+ if (checkedList.length === store.length) {
534
+ checkInfo.isHeaderChecked = true;
535
+ }
514
536
  }
537
+ updateVScroll();
515
538
  },
516
539
  );
517
540
  watch(
@@ -523,8 +546,15 @@ export default {
523
546
  watch(
524
547
  () => checkInfo.useCheckbox.mode,
525
548
  () => {
526
- checkInfo.checkedRows = [];
527
- checkInfo.isHeaderChecked = false;
549
+ clearCheckInfo();
550
+ },
551
+ );
552
+ watch(
553
+ () => props.checked.length,
554
+ (checkedSize) => {
555
+ if (!checkedSize) {
556
+ clearCheckInfo();
557
+ }
528
558
  },
529
559
  );
530
560
  watch(
@@ -553,64 +583,6 @@ export default {
553
583
  setStore([], false);
554
584
  },
555
585
  );
556
- let timer = null;
557
- const onSearch = (searchWord) => {
558
- if (timer) {
559
- clearTimeout(timer);
560
- }
561
- timer = setTimeout(() => {
562
- filterInfo.isSearch = false;
563
- if (searchWord) {
564
- const filterStores = stores.store.filter((row) => {
565
- let isShow = false;
566
- for (let ix = 0; ix < stores.orderedColumns.length; ix++) {
567
- const column = stores.orderedColumns[ix] || {};
568
- let columnValue = row[ROW_DATA_INDEX][ix];
569
- let columnType = column.type;
570
- if (columnValue) {
571
- if (typeof columnValue === 'object') {
572
- columnValue = columnValue[column.field];
573
- }
574
- if (!column.hide && (column?.searchable === undefined || column?.searchable)) {
575
- if (!columnType) {
576
- columnType = 'string';
577
- }
578
- columnValue = getConvertValue(columnType, columnValue).toString();
579
- isShow = columnValue.toLowerCase().includes(searchWord.toString().toLowerCase());
580
- if (isShow) {
581
- break;
582
- }
583
- }
584
- }
585
- }
586
- return isShow;
587
- });
588
- filterInfo.isSearch = true;
589
- stores.searchStore = JSON.parse(JSON.stringify(filterStores));
590
- } else {
591
- filterInfo.isSearch = false;
592
- }
593
- let store = stores.originStore;
594
- let checkSize = checkInfo.checkedRows.length;
595
- for (let ix = 0; ix < store.length; ix++) {
596
- if (checkInfo.checkedIndex.has(store[ix][ROW_INDEX])) {
597
- store[ix][ROW_CHECK_INDEX] = true;
598
- } else {
599
- store[ix][ROW_CHECK_INDEX] = false;
600
- }
601
- }
602
- if (filterInfo.isSearch && stores.searchStore) {
603
- store = stores.searchStore;
604
- checkSize = checkInfo.checkedIndex.size;
605
- }
606
- if (store.length && checkSize >= store.length) {
607
- checkInfo.isHeaderChecked = true;
608
- } else {
609
- checkInfo.isHeaderChecked = false;
610
- }
611
- setStore([], false);
612
- }, 500);
613
- };
614
586
  const isFilterButton = field => filterInfo.isFiltering && field !== 'db-icon' && field !== 'user-icon';
615
587
  return {
616
588
  showHeader,
@@ -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,57 @@ 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
+ filterInfo.searchWord = searchWord;
714
+ if (searchWord) {
715
+ stores.searchStore = stores.store.filter((row) => {
716
+ let isShow = false;
717
+ for (let ix = 0; ix < stores.orderedColumns.length; ix++) {
718
+ const column = stores.orderedColumns[ix] || {};
719
+ let columnValue = row[ROW_DATA_INDEX][ix];
720
+ const columnType = column.type || 'string';
721
+ if (columnValue) {
722
+ if (typeof columnValue === 'object') {
723
+ columnValue = columnValue[column.field];
724
+ }
725
+ if (!column.hide && (column?.searchable === undefined || column?.searchable)) {
726
+ columnValue = getConvertValue(columnType, columnValue).toString();
727
+ isShow = columnValue.toLowerCase().includes(searchWord.toString().toLowerCase());
728
+ if (isShow) {
729
+ break;
730
+ }
731
+ }
732
+ }
733
+ }
734
+ return isShow;
735
+ });
736
+ filterInfo.isSearch = true;
737
+ }
738
+ const store = stores.store;
739
+ let checkedCount = 0;
740
+ for (let ix = 0; ix < store.length; ix++) {
741
+ if (checkInfo.checkedIndex.has(store[ix][ROW_INDEX])) {
742
+ store[ix][ROW_CHECK_INDEX] = true;
743
+ checkedCount += 1;
744
+ } else {
745
+ store[ix][ROW_CHECK_INDEX] = false;
746
+ }
747
+ }
748
+ if (store.length && store.length === checkedCount) {
749
+ checkInfo.isHeaderChecked = true;
750
+ } else {
751
+ checkInfo.isHeaderChecked = false;
752
+ }
753
+ updateVScroll();
754
+ }, 500);
755
+ };
756
+ return { onClickFilter, onCloseFilterWindow, onApplyFilter, setFilter, onSearch };
712
757
  };
713
758
 
714
759
  export const contextMenuEvent = (params) => {
@@ -797,47 +842,40 @@ export const storeEvent = (params) => {
797
842
  * 전달된 데이터를 내부 store 및 속성에 저장한다.
798
843
  *
799
844
  * @param {array} value - row 데이터
800
- * @param {boolean} makeIndex - 인덱스 생성 유무
845
+ * @param {boolean} isMakeIndex - 인덱스 생성 유무
801
846
  */
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]]);
847
+ const setStore = (value, isMakeIndex = true) => {
848
+ const store = [];
849
+ let checked;
850
+ let selected = false;
851
+ if (isMakeIndex) {
852
+ let hasUnChecked = false;
853
+ for (let ix = 0; ix < value.length; ix++) {
854
+ checked = props.checked.includes(value[ix]);
855
+ if (!checked) {
856
+ hasUnChecked = true;
822
857
  }
823
-
824
- if (!selected) {
825
- selectInfo.selectedRow = [];
858
+ if (!selected && isEqual(selectInfo.selectedRow, value[ix])) {
859
+ selectInfo.selectedRow = value[ix];
860
+ selected = true;
826
861
  }
827
-
828
- checkInfo.isHeaderChecked = value.length > 0 ? !hasUnChecked : false;
829
- stores.originStore = store;
862
+ store.push([ix, checked, value[ix]]);
830
863
  }
831
- if (filterInfo.isFiltering) {
832
- setFilter();
864
+ if (!selected) {
865
+ selectInfo.selectedRow = [];
833
866
  }
834
- if (sortInfo.sortField) {
835
- setSort();
836
- }
837
- if (elementInfo.body?.clientHeight) {
838
- updateVScroll();
839
- }
840
- });
867
+ checkInfo.isHeaderChecked = value.length > 0 ? !hasUnChecked : false;
868
+ stores.originStore = store;
869
+ }
870
+ if (filterInfo.isFiltering) {
871
+ setFilter();
872
+ }
873
+ if (sortInfo.sortField) {
874
+ setSort();
875
+ }
876
+ if (elementInfo.body?.clientHeight) {
877
+ updateVScroll();
878
+ }
841
879
  };
842
880
  /**
843
881
  * 컴포넌트의 변경 데이터를 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 {
@@ -333,6 +333,12 @@ export default {
333
333
  onSearch,
334
334
  } = filterEvent({ checkInfo, stores, getConvertValue, calculatedColumn, updateVScroll });
335
335
 
336
+ onMounted(() => {
337
+ stores.treeStore = setTreeNodeStore();
338
+ });
339
+ onActivated(() => {
340
+ updateVScroll();
341
+ });
336
342
  watch(
337
343
  () => props.checked,
338
344
  (value) => {
@@ -362,8 +368,6 @@ export default {
362
368
  checkInfo.isHeaderChecked = false;
363
369
  },
364
370
  );
365
- stores.treeStore = setTreeNodeStore();
366
-
367
371
  watch(
368
372
  () => props.rows,
369
373
  (newData) => {