evui 3.1.50 → 3.1.54

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.1.50",
3
+ "version": "3.1.54",
4
4
  "description": "A EXEM Library project",
5
5
  "author": "exem <dev_client@ex-em.com>",
6
6
  "license": "MIT",
@@ -2,19 +2,17 @@
2
2
  <div class="ev-calendar-wrapper">
3
3
  <div class="ev-calendar-date-area">
4
4
  <div class="ev-calendar-header">
5
- <div>
6
- <i
7
- class="ev-icon-s-arrow-left move-month-arrow"
8
- @click="clickPrevNextBtn('main', 'prev')"
9
- />
5
+ <div @click="clickPrevNextBtn('main', 'prev')">
6
+ <i class="ev-icon-s-arrow-left move-month-arrow" />
10
7
  </div>
11
8
  <span class="ev-calendar-year">{{ mainCalendarPageInfo.year }}</span>
12
9
  <span class="ev-calendar-month">{{ mainCalendarMonth }}</span>
13
- <div>
10
+ <div @click="clickPrevNextBtn('main', 'next')">
14
11
  <i
15
- class="ev-icon-s-arrow-right move-month-arrow"
16
- :class="{ disabled: isContinuousMonths }"
17
- @click="clickPrevNextBtn('main', 'next')"
12
+ :class="[
13
+ 'ev-icon-s-arrow-right move-month-arrow',
14
+ { disabled: isContinuousMonths },
15
+ ]"
18
16
  />
19
17
  </div>
20
18
  </div>
@@ -133,20 +131,18 @@
133
131
  class="ev-calendar-date-area"
134
132
  >
135
133
  <div class="ev-calendar-header">
136
- <div>
134
+ <div @click="clickPrevNextBtn('expanded', 'prev')">
137
135
  <i
138
- class="ev-icon-s-arrow-left move-month-arrow"
139
- :class="{ disabled: isContinuousMonths }"
140
- @click="clickPrevNextBtn('expanded', 'prev')"
136
+ :class="[
137
+ 'ev-icon-s-arrow-left move-month-arrow',
138
+ { disabled: isContinuousMonths },
139
+ ]"
141
140
  />
142
141
  </div>
143
142
  <span class="ev-calendar-year">{{ expandedCalendarPageInfo.year }}</span>
144
143
  <span class="ev-calendar-month">{{ expandedCalendarMonth }}</span>
145
- <div>
146
- <i
147
- class="ev-icon-s-arrow-right move-month-arrow"
148
- @click="clickPrevNextBtn('expanded', 'next')"
149
- />
144
+ <div @click="clickPrevNextBtn('expanded', 'next')">
145
+ <i class="ev-icon-s-arrow-right move-month-arrow" />
150
146
  </div>
151
147
  </div>
152
148
  <div class="ev-calendar-body">
@@ -429,6 +425,7 @@ export default {
429
425
  width: 20px;
430
426
  flex: 1;
431
427
  text-align: center;
428
+ cursor: pointer;
432
429
  }
433
430
 
434
431
  .move-month-arrow {
@@ -437,7 +434,6 @@ export default {
437
434
  line-height: 20px;
438
435
  color: #606266;
439
436
  text-align: center;
440
- cursor: pointer;
441
437
  &:hover {
442
438
  color: #3C81F6;
443
439
  }
@@ -213,14 +213,30 @@ export const getChangedValueByTimeFormat = (timeFormat, modelValue) => {
213
213
  return `${modelValue.split(' ')[0]} ${hourByTimeFormat}:${minByTimeFormat}:${secByTimeFormat}`;
214
214
  };
215
215
 
216
- const compareFromAndToDate = (calendarType, targetDate, modelValue) => {
216
+ const compareFromAndToDateTime = (mode, calendarType, targetDate, modelValue) => {
217
217
  if (!modelValue.length) {
218
218
  return false;
219
219
  }
220
- const fromDate = calendarType === 'main' ? targetDate : modelValue[0];
221
- const toDate = calendarType === 'expanded' ? targetDate : modelValue[1];
220
+ let fromDate = calendarType === 'main' ? targetDate : modelValue[0];
221
+ let toDate = calendarType === 'expanded' ? targetDate : modelValue[1];
222
+
223
+ let fromDateTime = fromDate;
224
+ let toDateTime = toDate;
225
+ if (!targetDate.split(' ')[1]) {
226
+ if (mode === 'dateTimeRange') {
227
+ fromDate = fromDateTime.split(' ')[0];
228
+ toDate = toDateTime.split(' ')[0];
229
+ const fromTime = modelValue[0].split(' ')[1];
230
+ const toTime = modelValue[1].split(' ')[1];
231
+ fromDateTime = `${fromDate} ${fromTime}`;
232
+ toDateTime = `${toDate} ${toTime}`;
233
+ } else {
234
+ fromDateTime = `${fromDate} 00:00:00`;
235
+ toDateTime = `${toDate} 23:59:59`;
236
+ }
237
+ }
222
238
 
223
- return +new Date(fromDate) > +new Date(toDate);
239
+ return new Date(fromDateTime).getTime() > +new Date(toDateTime).getTime();
224
240
  };
225
241
 
226
242
  /**
@@ -328,24 +344,11 @@ export const useModel = () => {
328
344
  && selectedValue.value[1]
329
345
  ) {
330
346
  const expandedValue = selectedValue.value[1];
331
- const fromDate = {
332
- year: getDateTimeInfoByType(selectedValue.value[0], 'year'),
333
- month: getDateTimeInfoByType(selectedValue.value[0], 'month'),
334
- };
335
347
  const toDate = {
336
348
  year: getDateTimeInfoByType(expandedValue, 'year'),
337
349
  month: getDateTimeInfoByType(expandedValue, 'month'),
338
350
  };
339
- // fromDate, toDate의 연, 월이 같은 경우의 확장된 달력 페이징 정보는 다음달로 세팅
340
- if (props.mode === 'dateRange' && (fromDate.year === toDate.year && fromDate.month === toDate.month)) {
341
- expandedCalendarPageInfo = reactive(getSideMonthCalendarInfo(
342
- 'next',
343
- mainCalendarPageInfo.year,
344
- mainCalendarPageInfo.month,
345
- ));
346
- } else {
347
- expandedCalendarPageInfo = reactive(toDate);
348
- }
351
+ expandedCalendarPageInfo = reactive(toDate);
349
352
 
350
353
  if (props.mode === 'dateTimeRange') {
351
354
  expandedCalendarPageInfo.hour = Math.floor(getDateTimeInfoByType(expandedValue, 'hour') / CELL_CNT_IN_ONE_PAGE) + 1 || 1;
@@ -377,11 +380,9 @@ export const useModel = () => {
377
380
  DAY_OF_THE_WEEK_NAME_LIST[props.dayOfTheWeekNotation]);
378
381
  // mode: dateRange에 두 달력이 연속적인 경우
379
382
  const isContinuousMonths = computed(
380
- () => (props.mode === 'dateRange'
381
- && (getSideMonthCalendarInfo('next', mainCalendarPageInfo.year, mainCalendarPageInfo.month).year === expandedCalendarPageInfo.year
382
- && getSideMonthCalendarInfo('next', mainCalendarPageInfo.year, mainCalendarPageInfo.month).month === expandedCalendarPageInfo.month))
383
- || (props.mode === 'dateTimeRange' && (mainCalendarPageInfo.year === expandedCalendarPageInfo.year
384
- && mainCalendarPageInfo.month === expandedCalendarPageInfo.month)),
383
+ () => ['dateRange', 'dateTimeRange'].includes(props.mode)
384
+ && (mainCalendarPageInfo.year === expandedCalendarPageInfo.year
385
+ && mainCalendarPageInfo.month === expandedCalendarPageInfo.month),
385
386
  );
386
387
 
387
388
  onBeforeMount(() => {
@@ -469,42 +470,22 @@ export const useCalendarDate = (param) => {
469
470
  // date 숫자 및 속성 세팅
470
471
  const setDateInfo = (monthType, i, j) => {
471
472
  currDate = formatDateTime({ year, month, date });
473
+ const isRangeMode = ['dateRange', 'dateTimeRange'].includes(props.mode);
472
474
  const isDisabled = disabledDate ? disabledDate(new Date(currDate)) : false;
473
- const isInvalidDate = props.mode === 'dateTimeRange'
474
- && compareFromAndToDate(calendarType, `${currDate} 00:00:00`, selectedValue.value);
475
- const inRangeCls = () => {
476
- if (['dateRange'].includes(props.mode) && selectedValue.value.length === 2) {
477
- if (getDateMs(selectedValue.value[0].split(' ')[0]) <= getDateMs(currDate)
478
- && getDateMs(currDate) <= getDateMs(selectedValue.value[1].split(' ')[0])
479
- ) {
480
- if (getDateMs(selectedValue.value[0]) === getDateMs(selectedValue.value[1])) {
481
- return ' in-range start-end-date';
482
- } else if (getDateMs(selectedValue.value[0]) === getDateMs(currDate)) {
483
- return ' in-range start-date';
484
- } else if (getDateMs(currDate) === getDateMs(selectedValue.value[1])) {
485
- return ' in-range end-date';
486
- }
487
- return ' in-range';
488
- }
489
- return '';
490
- }
491
- return '';
492
- };
475
+ const isInvalidDate = isRangeMode
476
+ && compareFromAndToDateTime(props.mode, calendarType, currDate, selectedValue.value);
493
477
 
494
- const isDateRangeSelected = props.mode === 'dateRange'
495
- && selectedValue.value?.map(v => v.split(' ')[0]).includes(currDate);
496
- // mode:dateTimeRange인 경우는 한 달력에 from, to 선택 못함
497
478
  const index = calendarType !== 'main' | 0;
498
- const isDateTimeRangeSelected = props.mode === 'dateTimeRange'
499
- && selectedValue.value.length > index && selectedValue.value[index].split(' ')[0].includes(currDate);
479
+ const isRangeSelected = isRangeMode && selectedValue.value.length > index
480
+ && selectedValue.value[index].split(' ')[0].includes(currDate);
500
481
 
501
482
  // mode가 dateRange일 때는 이전, 다음달에 selected 를 하지 않는다.
502
483
  calendarTableInfo[i][j] = {
503
- monthType: `${monthType}${isDisabled || isInvalidDate ? ' disabled' : ''}${inRangeCls()}`,
484
+ monthType: `${monthType}${isDisabled || isInvalidDate ? ' disabled' : ''}`,
504
485
  isToday: TODAY_YMD === currDate,
505
- isSelected: !['dateRange', 'dateTimeRange'].includes(props.mode)
506
- ? selectedValue.value?.includes(currDate)
507
- : monthType === '' && (isDateRangeSelected || isDateTimeRangeSelected),
486
+ isSelected: isRangeMode
487
+ ? monthType === '' && isRangeSelected
488
+ : selectedValue.value?.includes(currDate),
508
489
  year,
509
490
  month,
510
491
  date,
@@ -583,7 +564,12 @@ export const useCalendarDate = (param) => {
583
564
  }
584
565
 
585
566
  const targetDateTimeValue = `${date} ${lpadToTwoDigits(hour)}:${lpadToTwoDigits(min)}:${lpadToTwoDigits(sec)}`;
586
- return compareFromAndToDate(calendarType, targetDateTimeValue, selectedValue.value);
567
+ return compareFromAndToDateTime(
568
+ props.mode,
569
+ calendarType,
570
+ targetDateTimeValue,
571
+ selectedValue.value,
572
+ );
587
573
  };
588
574
 
589
575
  ['hour', 'min', 'sec'].forEach((v) => {
@@ -705,11 +691,11 @@ export const useEvent = (param) => {
705
691
  };
706
692
 
707
693
  /**
708
- * page를 Array로 담아 페이지 세팅
709
- * @param pageList
694
+ * value를 Array로 담아 페이지 세팅
695
+ * @param valueList
710
696
  */
711
- const updatePageList = (pageList) => {
712
- pageList?.forEach((currValue, index) => {
697
+ const updateCalendarPage = (valueList) => {
698
+ valueList?.forEach((currValue, index) => {
713
699
  const changeCalendarType = index === 0 ? 'main' : 'expanded';
714
700
  setCalendarPageInfo(changeCalendarType, {
715
701
  year: getDateTimeInfoByType(currValue, 'year'),
@@ -750,18 +736,11 @@ export const useEvent = (param) => {
750
736
  } else {
751
737
  calendarPageInfo = calendarType === 'expanded'
752
738
  ? expandedCalendarPageInfo : mainCalendarPageInfo;
753
- // 메인 달력 날짜 + 1Month
754
- const nextYearMonth = getSideMonthCalendarInfo(
755
- 'next',
756
- mainCalendarPageInfo.year,
757
- mainCalendarPageInfo.month,
758
- );
759
- const targetYearMonth = props.mode === 'dateRange' ? nextYearMonth : mainCalendarPageInfo;
739
+
760
740
  // 두 달력간의 연속 여부 (메인 달력 + 1Month === 확장된 달력)
761
- // 연속된 경우 mainCalendar와 expandedCalendar는 서로 같은 달로 이동 불가
762
741
  // mainCalendar Month < expandedCalendar Month
763
- const isContinuousMonths = expandedCalendarPageInfo.year === targetYearMonth.year
764
- && expandedCalendarPageInfo.month === targetYearMonth.month;
742
+ const isContinuousMonths = expandedCalendarPageInfo.year === mainCalendarPageInfo.year
743
+ && expandedCalendarPageInfo.month === mainCalendarPageInfo.month;
765
744
  if (type === 'prev') {
766
745
  if (isContinuousMonths && calendarType === 'expanded') {
767
746
  return;
@@ -831,6 +810,17 @@ export const useEvent = (param) => {
831
810
  }
832
811
  };
833
812
 
813
+ const setRangeModeDateByIndex = (currIndex, currDate) => {
814
+ if (compareFromAndToDateTime(props.mode, calendarType, currDate, selectedValue.value)) {
815
+ return false;
816
+ }
817
+
818
+ selectedValue.value[currIndex] = currDate;
819
+ moveDispCalendarMonth();
820
+ updateCalendarPage(selectedValue.value);
821
+ return true;
822
+ };
823
+
834
824
  switch (props.mode) {
835
825
  case 'date':
836
826
  selectedValue.value = CURR_DATE_STR;
@@ -905,28 +895,17 @@ export const useEvent = (param) => {
905
895
  break;
906
896
  }
907
897
  case 'dateRange': {
908
- const isMouseover = calendarEventName.value === 'mousemove';
909
- if (isMouseover) {
910
- calendarEventName.value = null;
911
- // throttle delay 보다 더 빠르게 날짜 클릭하는 경우
912
- if (selectedValue.value.length === 1) {
913
- selectedValue.value.push(CURR_DATE_STR);
914
- }
915
- emit('update:modelValue', [...selectedValue.value]);
916
- dateRangeClickedDate.value = '';
917
- setCalendarDate(calendarType);
898
+ if (!selectedValue.value.length) {
899
+ selectedValue.value.push(CURR_DATE_STR);
900
+ selectedValue.value.push(CURR_DATE_STR);
901
+ updateCalendarPage(selectedValue.value);
918
902
  } else {
919
- selectedValue.value.splice(0);
920
- calendarEventName.value = 'mousemove';
921
- dateRangeClickedDate.value = CURR_DATE_STR;
922
- selectedValue.value.push(dateRangeClickedDate.value);
923
- setCalendarDate('main');
924
- setCalendarDate('expanded');
903
+ setRangeModeDateByIndex(calendarType !== 'main' | 0, CURR_DATE_STR);
925
904
  }
905
+ emit('update:modelValue', [...selectedValue.value]);
926
906
  break;
927
907
  }
928
908
  case 'dateTimeRange': {
929
- const currIndex = calendarType !== 'main' | 0;
930
909
  if (!selectedValue.value.length) {
931
910
  let fromDate = `${CURR_DATE_STR} 00:00:00`;
932
911
  let toDate = `${CURR_DATE_STR} 00:00:00`;
@@ -943,19 +922,10 @@ export const useEvent = (param) => {
943
922
  selectedValue.value.push(fromDate);
944
923
  selectedValue.value.push(toDate);
945
924
 
946
- selectedValue.value?.forEach((currValue, index) => {
947
- setCalendarPageInfo(index === 0 ? 'main' : 'expanded', {
948
- year: getDateTimeInfoByType(currValue, 'year'),
949
- month: getDateTimeInfoByType(currValue, 'month'),
950
- hour: Math.floor(getDateTimeInfoByType(currValue, 'hour') / CELL_CNT_IN_ONE_PAGE) + 1,
951
- min: Math.floor(getDateTimeInfoByType(currValue, 'min') / CELL_CNT_IN_ONE_PAGE) + 1,
952
- sec: Math.floor(getDateTimeInfoByType(currValue, 'sec') / CELL_CNT_IN_ONE_PAGE) + 1,
953
- });
954
- });
955
- setCalendarDate('main');
956
- setCalendarDate('expanded');
925
+ updateCalendarPage(selectedValue.value);
957
926
  setHmsTime();
958
927
  } else {
928
+ const currIndex = calendarType !== 'main' | 0;
959
929
  const CURR_TIME_HMS = selectedValue.value[currIndex]?.split(' ')[1] || '00:00:00';
960
930
 
961
931
  let currDate = `${CURR_DATE_STR} ${CURR_TIME_HMS}`;
@@ -965,17 +935,7 @@ export const useEvent = (param) => {
965
935
  currDate,
966
936
  );
967
937
  }
968
-
969
- const fromDate = currIndex ? selectedValue.value[0] : currDate;
970
- const toDate = currIndex ? currDate : selectedValue.value[1];
971
-
972
- if (new Date(fromDate).getTime() > new Date(toDate).getTime()) {
973
- break;
974
- }
975
-
976
- selectedValue.value[currIndex] = currDate;
977
- moveDispCalendarMonth();
978
- setCalendarDate(calendarType);
938
+ setRangeModeDateByIndex(currIndex, currDate);
979
939
  }
980
940
  emit('update:modelValue', [...selectedValue.value]);
981
941
  break;
@@ -1049,7 +1009,7 @@ export const useEvent = (param) => {
1049
1009
  date: TODAY.getDate(),
1050
1010
  };
1051
1011
  let EXIST_MODEL = true;
1052
- let pageUpdateList = [];
1012
+ let valueListByUpdatePage = [];
1053
1013
 
1054
1014
  const getTimeValueByType = () => {
1055
1015
  let targetTimeValue;
@@ -1074,7 +1034,8 @@ export const useEvent = (param) => {
1074
1034
  } else if (timeType === 'sec') {
1075
1035
  START_IDX = SEC_START_IDX;
1076
1036
  }
1077
- return `${targetValue?.substr(0, START_IDX)}${lpadToTwoDigits(clickedNum)}${targetValue?.substr(START_IDX + REPLACE_TEXT_SIZE)}`;
1037
+ return `${targetValue?.substr(0, START_IDX)}`
1038
+ + `${lpadToTwoDigits(clickedNum)}${targetValue?.substr(START_IDX + REPLACE_TEXT_SIZE)}`;
1078
1039
  };
1079
1040
 
1080
1041
  if (props.mode === 'dateTime') {
@@ -1092,7 +1053,7 @@ export const useEvent = (param) => {
1092
1053
  );
1093
1054
  emit('update:modelValue', selectedValue.value);
1094
1055
  }
1095
- pageUpdateList.push(selectedValue.value);
1056
+ valueListByUpdatePage.push(selectedValue.value);
1096
1057
  } else {
1097
1058
  const index = calendarType !== 'main' | 0;
1098
1059
  if (!props.modelValue.length) {
@@ -1105,7 +1066,7 @@ export const useEvent = (param) => {
1105
1066
  }
1106
1067
 
1107
1068
  EXIST_MODEL = false;
1108
- pageUpdateList = selectedValue.value;
1069
+ valueListByUpdatePage = selectedValue.value;
1109
1070
  } else {
1110
1071
  let currDateTime = getChangedValue(props.modelValue[index]);
1111
1072
  if (timeFormat && timeFormat.length) {
@@ -1129,7 +1090,7 @@ export const useEvent = (param) => {
1129
1090
  setHmsTime();
1130
1091
  // dateTime의 v-model값이 없는 경우 time area를 클릭하였을 때 date의 값은 today로 세팅
1131
1092
  if (!EXIST_MODEL) {
1132
- updatePageList(pageUpdateList);
1093
+ updateCalendarPage(valueListByUpdatePage);
1133
1094
  }
1134
1095
  };
1135
1096
 
@@ -1207,16 +1168,16 @@ export const useEvent = (param) => {
1207
1168
  * Calendar Info 전체 업데이트
1208
1169
  */
1209
1170
  const resetCalendarInfo = () => {
1210
- let pageUpdateList = [];
1171
+ let valueListByUpdatePage = [];
1211
1172
 
1212
1173
  if (['date', 'dateTime'].includes(props.mode)) {
1213
- pageUpdateList.push(selectedValue.value);
1174
+ valueListByUpdatePage.push(selectedValue.value);
1214
1175
  } else {
1215
- pageUpdateList = selectedValue.value;
1176
+ valueListByUpdatePage = selectedValue.value;
1216
1177
  }
1217
1178
 
1218
1179
  if (['dateTime', 'dateTimeRange'].includes(props.mode)) {
1219
- updatePageList(pageUpdateList);
1180
+ updateCalendarPage(valueListByUpdatePage);
1220
1181
  setHmsTime();
1221
1182
  }
1222
1183
  };
@@ -8,7 +8,7 @@
8
8
  </template>
9
9
 
10
10
  <script>
11
- import { onMounted, onBeforeUnmount, watch } from 'vue';
11
+ import { onMounted, onBeforeUnmount, watch, onDeactivated } from 'vue';
12
12
  import { cloneDeep, isEqual, debounce } from 'lodash-es';
13
13
  import EvChart from './chart.core';
14
14
  import { useModel, useWrapper } from './uses';
@@ -85,7 +85,8 @@
85
85
 
86
86
  await watch(() => props.data, (chartData) => {
87
87
  const newData = getNormalizedData(chartData);
88
- const isUpdateSeries = !isEqual(newData, evChart.data);
88
+ const isUpdateSeries = !isEqual(newData.series, evChart.data.series)
89
+ || !isEqual(newData.groups, evChart.data.groups);
89
90
  evChart.data = cloneDeep(newData);
90
91
  evChart.update({
91
92
  updateSeries: isUpdateSeries,
@@ -98,6 +99,12 @@
98
99
  evChart.destroy();
99
100
  });
100
101
 
102
+ onDeactivated(() => {
103
+ if (evChart && 'hideTooltip' in evChart) {
104
+ evChart.hideTooltip();
105
+ }
106
+ });
107
+
101
108
  const redrawChart = () => {
102
109
  if (isInit) {
103
110
  evChart.update({
@@ -523,7 +523,7 @@ class EvChart {
523
523
  this.createSeriesSet(series, options.type, options.horizontal);
524
524
 
525
525
  if (this.legendDOM) {
526
- this.resetLegend();
526
+ this.updateLegend();
527
527
  }
528
528
  }
529
529
 
@@ -532,6 +532,7 @@ class EvChart {
532
532
 
533
533
  if (!updateSelTip.keepDomain) {
534
534
  this.lastTip.pos = null;
535
+ this.lastHitInfo = null;
535
536
  }
536
537
  }
537
538
 
@@ -714,6 +715,17 @@ class EvChart {
714
715
  target.removeChild(target.firstChild);
715
716
  }
716
717
  }
718
+
719
+ /**
720
+ * hide chart tooltip
721
+ *
722
+ * @returns {undefined}
723
+ */
724
+ hideTooltip() {
725
+ if (this.options.tooltip.use && this.tooltipDOM?.style) {
726
+ this.tooltipDOM.style.display = 'none';
727
+ }
728
+ }
717
729
  }
718
730
 
719
731
  export default EvChart;
@@ -102,10 +102,16 @@
102
102
  {{ column.caption }}
103
103
  </span>
104
104
  <!--Sort Icon-->
105
- <ev-icon
106
- v-if="sortField === column.field"
107
- :icon="`${sortOrder === 'desc' ? 'ev-icon-triangle-down' : 'ev-icon-triangle-up'}`"
108
- />
105
+ <template v-if="sortField === column.field">
106
+ <ev-icon
107
+ v-if="sortOrder === 'desc'"
108
+ icon="ev-icon-triangle-down"
109
+ />
110
+ <ev-icon
111
+ v-if="sortOrder === 'asc'"
112
+ icon="ev-icon-triangle-up"
113
+ />
114
+ </template>
109
115
  <!--Filter Button-->
110
116
  <span
111
117
  v-if="isFilterButton(column.field)"
@@ -387,7 +393,7 @@ export default {
387
393
  selectedRow: props.selected,
388
394
  });
389
395
  const sortInfo = reactive({
390
- setSorting: false,
396
+ isSorting: false,
391
397
  sortField: '',
392
398
  sortOrder: 'desc',
393
399
  });
@@ -473,11 +479,19 @@ export default {
473
479
  const ROW_CHECK_INDEX = 1;
474
480
  const ROW_DATA_INDEX = 2;
475
481
  watch(
476
- () => sortInfo.setSorting,
482
+ () => props.columns,
483
+ () => {
484
+ sortInfo.isSorting = false;
485
+ sortInfo.sortField = '';
486
+ setSort();
487
+ }, { deep: true },
488
+ );
489
+ watch(
490
+ () => sortInfo.isSorting,
477
491
  (value) => {
478
492
  if (value) {
479
493
  setStore(stores.originStore, false);
480
- sortInfo.setSorting = !value;
494
+ sortInfo.isSorting = !value;
481
495
  }
482
496
  },
483
497
  );
@@ -466,36 +466,50 @@ export const checkEvent = (params) => {
466
466
  export const sortEvent = (params) => {
467
467
  const { sortInfo, stores, getColumnIndex } = params;
468
468
  const { props } = getCurrentInstance();
469
+ function OrderQueue() {
470
+ this.orders = ['asc', 'desc', 'init'];
471
+ this.dequeue = () => this.orders.shift();
472
+ this.enqueue = o => this.orders.push(o);
473
+ }
474
+ const order = new OrderQueue();
469
475
  /**
470
476
  * sort 이벤트를 처리한다.
471
477
  *
472
478
  * @param {string} field - 컬럼 field
473
479
  */
474
480
  const onSort = (field) => {
475
- if (sortInfo.sortField === field) {
476
- sortInfo.sortOrder = sortInfo.sortOrder === 'desc' ? 'asc' : 'desc';
477
- } else {
481
+ if (sortInfo.sortField !== field) {
482
+ order.orders = ['asc', 'desc', 'init'];
478
483
  sortInfo.sortField = field;
479
- sortInfo.sortOrder = 'desc';
480
484
  }
485
+ sortInfo.sortOrder = order.dequeue();
486
+ order.enqueue(sortInfo.sortOrder);
481
487
 
482
- sortInfo.setSorting = true;
488
+ sortInfo.isSorting = true;
483
489
  };
484
490
  /**
485
491
  * 설정값에 따라 해당 컬럼 데이터에 대해 정렬한다.
486
492
  */
487
493
  const setSort = () => {
494
+ const setDesc = (a, b) => (a > b ? -1 : 1);
495
+ const setAsc = (a, b) => (a < b ? -1 : 1);
496
+ if (sortInfo.sortOrder === 'init' || (!sortInfo.sortField && !sortInfo.isSorting)) {
497
+ stores.store.sort((a, b) => {
498
+ if (typeof a[ROW_INDEX] === 'number') {
499
+ return setAsc(a[ROW_INDEX], b[ROW_INDEX]);
500
+ }
501
+ return 0;
502
+ });
503
+ return;
504
+ }
488
505
  const index = getColumnIndex(sortInfo.sortField);
489
- const desc = (a, b) => (a > b ? -1 : 1);
490
- const asc = (a, b) => (a < b ? -1 : 1);
491
- const type = props.columns[index].type || 'string';
492
- const sortFn = sortInfo.sortOrder === 'desc' ? desc : asc;
493
-
506
+ const type = props.columns[index]?.type || 'string';
507
+ const sortFn = sortInfo.sortOrder === 'desc' ? setDesc : setAsc;
494
508
  if (type === 'string') {
495
509
  stores.store.sort((a, b) => {
496
510
  if (typeof a[ROW_DATA_INDEX][index] === 'string') {
497
- return sortFn(a[ROW_DATA_INDEX][index].toLowerCase(),
498
- b[ROW_DATA_INDEX][index].toLowerCase());
511
+ return sortFn(a[ROW_DATA_INDEX][index]?.toLowerCase(),
512
+ b[ROW_DATA_INDEX][index]?.toLowerCase());
499
513
  }
500
514
  return 0;
501
515
  });
@@ -101,7 +101,7 @@
101
101
  </template>
102
102
 
103
103
  <script>
104
- import { ref, computed } from 'vue';
104
+ import { ref, computed, nextTick } from 'vue';
105
105
 
106
106
  export default {
107
107
  name: 'EvTextField',
@@ -205,7 +205,9 @@ export default {
205
205
  if (mv.value !== inputValue) {
206
206
  mv.value = inputValue;
207
207
  }
208
- emit('input', mv.value, e);
208
+ nextTick(() => {
209
+ emit('input', mv.value, e);
210
+ });
209
211
  };
210
212
  const changeMv = (e) => {
211
213
  emit('change', mv.value, e);