evui 3.4.32 → 3.4.34

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.4.32",
3
+ "version": "3.4.34",
4
4
  "description": "A EXEM Library project",
5
5
  "author": "exem <dev_client@ex-em.com>",
6
6
  "license": "MIT",
@@ -27,7 +27,8 @@
27
27
  "vue-resize-observer": "^2.0.15",
28
28
  "vue3-observe-visibility": "^0.1.2",
29
29
  "vue-router": "^4.0.0-0",
30
- "vuex": "^4.0.0-0"
30
+ "vuex": "^4.0.0-0",
31
+ "bignumber.js": "^9.1.2"
31
32
  },
32
33
  "devDependencies": {
33
34
  "@vue/cli-plugin-babel": "~4.5.0",
@@ -0,0 +1,67 @@
1
+ import BigNumber from 'bignumber.js';
2
+
3
+ /**
4
+ * Convert Number to BigNumber
5
+ * @param {Number} value
6
+ * @return {BigNumber}
7
+ */
8
+ function toBigNumber(value) { return new BigNumber(value); }
9
+
10
+ /**
11
+ * plus(+)
12
+ * @param {Number} num1
13
+ * @param {Number} num2
14
+ * @return {Number}
15
+ */
16
+ function bnPlus(num1, num2) {
17
+ return toBigNumber(num1).plus(toBigNumber(num2)).toNumber();
18
+ }
19
+
20
+ /**
21
+ * minus(-)
22
+ * @param {Number} num1
23
+ * @param {Number} num2
24
+ * @return {Number}
25
+ */
26
+ function bnMinus(num1, num2) {
27
+ return toBigNumber(num1).minus(toBigNumber(num2)).toNumber();
28
+ }
29
+
30
+ /**
31
+ * multiply(*)
32
+ * @param {Number} num1
33
+ * @param {Number} num2
34
+ * @return {Number}
35
+ */
36
+ function bnMultiply(num1, num2) {
37
+ return toBigNumber(num1).multipliedBy(toBigNumber(num2)).toNumber();
38
+ }
39
+
40
+ /**
41
+ * divide(/)
42
+ * @param {Number} dividend
43
+ * @param {Number} divisor
44
+ * @return {Number}
45
+ */
46
+ function bnDivide(dividend, divisor) {
47
+ return toBigNumber(dividend).dividedBy(toBigNumber((divisor))).toNumber();
48
+ }
49
+
50
+ /**
51
+ * floor
52
+ * @param {Number} num
53
+ * @param {Number} decimal
54
+ * @return {Number}
55
+ */
56
+ function bnFloor(num, decimal) {
57
+ return toBigNumber(num).decimalPlaces(decimal, BigNumber.ROUND_DOWN).toNumber();
58
+ }
59
+
60
+ export {
61
+ toBigNumber,
62
+ bnPlus,
63
+ bnMinus,
64
+ bnMultiply,
65
+ bnDivide,
66
+ bnFloor,
67
+ };
@@ -737,6 +737,7 @@ const modules = {
737
737
  items[sId] = item;
738
738
 
739
739
  const formattedTxt = this.getFormattedTooltipValue({
740
+ seriesId: sId,
740
741
  seriesName: sName,
741
742
  value: gdata,
742
743
  itemData: item.data,
@@ -774,12 +775,13 @@ const modules = {
774
775
 
775
776
  /**
776
777
  * get formatted value for tooltip
778
+ * @param seriesId
777
779
  * @param seriesName
778
780
  * @param value
779
781
  * @param itemData
780
782
  * @returns {string}
781
783
  */
782
- getFormattedTooltipValue({ seriesName, value, itemData }) {
784
+ getFormattedTooltipValue({ seriesId, seriesName, value, itemData }) {
783
785
  const opt = this.options;
784
786
  const isHorizontal = !!opt.horizontal;
785
787
  const tooltipOpt = opt.tooltip;
@@ -794,18 +796,21 @@ const modules = {
794
796
  value,
795
797
  name: seriesName,
796
798
  percentage: itemData?.percentage,
799
+ seriesId,
797
800
  });
798
801
  } else if (opt.type === 'heatMap') {
799
802
  formattedTxt = tooltipValueFormatter({
800
803
  x: itemData?.x,
801
804
  y: itemData?.y,
802
805
  value: value > -1 ? value : 'error',
806
+ seriesId,
803
807
  });
804
808
  } else {
805
809
  formattedTxt = tooltipValueFormatter({
806
810
  x: isHorizontal ? value : itemData?.x,
807
811
  y: isHorizontal ? itemData?.y : value,
808
812
  name: seriesName,
813
+ seriesId,
809
814
  });
810
815
  }
811
816
  }
@@ -848,6 +853,7 @@ const modules = {
848
853
  );
849
854
 
850
855
  const formattedValue = this.getFormattedTooltipValue({
856
+ seriesId: sId,
851
857
  seriesName: series.name,
852
858
  value: hasData?.o,
853
859
  itemData: hasData,
@@ -7,7 +7,7 @@
7
7
  class="ev-menu-li"
8
8
  :class="{ disabled: item.disabled }"
9
9
  @click="handleItemClick(item)"
10
- @mouseenter="!item.disabled ? mouseenterLi($event, item.children) : (() => {})()"
10
+ @mouseenter="mouseenterLi($event, item)"
11
11
  >
12
12
  <i
13
13
  v-if="!!item.iconClass"
@@ -190,14 +190,14 @@ export const useMenuList = () => {
190
190
  /**
191
191
  * 항목에 마우스엔터 시 발생하는 이벤트
192
192
  * @param e - 마우스 이벤트 (showChild에 넘김)
193
- * @param children - 자식 리스트
193
+ * @param item - 마우스오버된 메뉴
194
194
  * @returns null
195
195
  */
196
- const mouseenterLi = async (e, children) => {
197
- if (!children || !Array.isArray(children)) {
196
+ const mouseenterLi = async (e, item) => {
197
+ if (!item.children || !Array.isArray(item.children) || item.disabled) {
198
198
  hideChild();
199
199
  } else {
200
- await showChild(e, children);
200
+ await showChild(e, item.children);
201
201
  }
202
202
  };
203
203
 
@@ -801,6 +801,7 @@ export default {
801
801
  contextMenuItems: [],
802
802
  columnMenu: null,
803
803
  columnMenuItems: [],
804
+ hiddenColumnMenuItem: props.option.hiddenColumnMenuItem || {},
804
805
  customContextMenu: props.option.customContextMenu || [],
805
806
  gridSettingMenu: null,
806
807
  gridSettingContextMenuItems: [],
@@ -53,9 +53,9 @@
53
53
  </div>
54
54
  <div
55
55
  v-else
56
- :title="getSummaryValue(column, column.summaryType)"
56
+ :title="getSummaryValue(column)"
57
57
  >
58
- {{ getSummaryValue(column, column.summaryType)}}
58
+ {{ getSummaryValue(column)}}
59
59
  </div>
60
60
  </span>
61
61
  <span
@@ -71,6 +71,7 @@
71
71
  <script>
72
72
  import { computed, watch, ref, nextTick } from 'vue';
73
73
  import { numberWithComma } from '@/common/utils';
74
+ import { bnDivide, bnFloor, bnPlus } from '@/common/utils.bignumber';
74
75
 
75
76
  export default {
76
77
  name: 'EvGridSummary',
@@ -101,77 +102,119 @@ export default {
101
102
  },
102
103
  },
103
104
  setup(props) {
105
+ const DECIMAL = {
106
+ max: 20,
107
+ default: 3,
108
+ };
104
109
  const summaryRef = ref();
105
110
  const ROW_DATA_INDEX = 2;
106
111
  const stores = computed(() => props.stores);
107
112
  const columns = computed(() => props.orderedColumns);
108
113
  const showCheckbox = computed(() => props.useCheckbox);
109
114
  const styleInfo = computed(() => props.styleOption);
115
+
116
+ const getValidDecimal = (decimal) => {
117
+ if (decimal == null || decimal < 0) {
118
+ return DECIMAL.default;
119
+ }
120
+
121
+ if (decimal > DECIMAL.max) {
122
+ return DECIMAL.max;
123
+ }
124
+
125
+ return decimal;
126
+ };
127
+
110
128
  const getConvertValue = (column, value) => {
129
+ if (typeof value === 'string' && value.length === 0) {
130
+ return value;
131
+ }
132
+
133
+ const { type, decimal } = column;
111
134
  let convertValue = value;
112
135
 
113
- if (column.type === 'number') {
136
+ if (type === 'number') {
114
137
  convertValue = numberWithComma(value);
115
138
  convertValue = convertValue === false ? value : convertValue;
116
- } else if (column.type === 'float') {
117
- const floatValue = convertValue.toFixed(column.decimal ?? 3);
139
+ } else if (type === 'float') {
140
+ const floatValue = convertValue.toFixed(getValidDecimal(decimal ?? DECIMAL.default));
118
141
  convertValue = floatValue.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
119
142
  }
120
143
 
121
144
  return convertValue;
122
145
  };
146
+
123
147
  const getColumnIndex = field => columns.value.findIndex(column => column.field === field);
124
- const getSummaryValue = (column, summaryType) => {
148
+ const getSummaryValue = (column) => {
149
+ const {
150
+ type,
151
+ field,
152
+ summaryType,
153
+ summaryDecimal,
154
+ summaryOnlyTopParent,
155
+ } = column;
156
+
125
157
  let result = '';
126
- const columnIndex = getColumnIndex(column.field);
158
+ const columnIndex = getColumnIndex(field);
127
159
  if (columnIndex >= 0) {
128
160
  if (summaryType === 'count') {
129
161
  return stores.value.store.length;
130
162
  }
131
- if (column.type === 'number' || column.type === 'float') {
163
+ if (type === 'number' || type === 'float') {
132
164
  let columnValues = [];
133
165
  if (props.isTree) {
134
166
  columnValues = stores.value.store.reduce((acc, cur) => {
135
- if (column.summaryOnlyTopParent) {
136
- if (!cur.parent) {
137
- acc.push(cur.data?.[column.field]);
138
- }
139
- } else {
140
- acc.push(cur.data?.[column.field]);
167
+ if (summaryOnlyTopParent) {
168
+ if (!cur.parent) {
169
+ acc.push(cur.data?.[field]);
141
170
  }
142
- return acc;
143
- }, []);
171
+ } else {
172
+ acc.push(cur.data?.[field]);
173
+ }
174
+ return acc;
175
+ }, []);
144
176
  } else {
145
177
  columnValues = stores.value.store.map(row => row[ROW_DATA_INDEX][columnIndex]);
146
178
  }
147
179
  switch (summaryType) {
148
- case 'sum':
149
- result = columnValues.reduce((prev, curr) => {
180
+ case 'sum': {
181
+ const sumValue = columnValues.reduce((prev, curr) => {
150
182
  const value = Number(curr);
151
183
  if (!Number.isNaN(value)) {
152
- return prev + value;
184
+ return bnPlus(prev, value);
153
185
  }
154
186
  return prev;
155
187
  }, 0);
188
+
189
+ result = sumValue && bnFloor(
190
+ sumValue, getValidDecimal(summaryDecimal ?? DECIMAL.default),
191
+ );
156
192
  break;
157
- case 'average':
158
- result = columnValues.reduce((prev, curr) => {
193
+ }
194
+ case 'average': {
195
+ const sumValue = columnValues.reduce((prev, curr) => {
159
196
  const value = Number(curr);
160
197
  if (!Number.isNaN(value)) {
161
- return prev + value;
198
+ return bnPlus(prev, value);
162
199
  }
163
200
  return prev;
164
- }, 0) / columnValues.length;
165
- if (result % 1 !== 0) {
166
- result = result.toFixed(1);
167
- }
201
+ }, 0);
202
+ result = sumValue && bnFloor(
203
+ bnDivide(sumValue, columnValues.length),
204
+ getValidDecimal(summaryDecimal ?? DECIMAL.default),
205
+ );
168
206
  break;
169
- case 'max':
170
- result = Math.max(...columnValues);
207
+ }
208
+ case 'max': {
209
+ const filteredNullValues = columnValues.filter(value => value != null);
210
+ result = filteredNullValues.length ? Math.max(...filteredNullValues) : '';
171
211
  break;
172
- case 'min':
173
- result = Math.min(...columnValues);
212
+ }
213
+ case 'min': {
214
+ const filteredNullValues = columnValues.filter(value => value != null);
215
+ result = filteredNullValues.length ? Math.min(...filteredNullValues) : '';
174
216
  break;
217
+ }
175
218
  default:
176
219
  break;
177
220
  }
@@ -188,10 +231,7 @@ export default {
188
231
  fields.forEach((name, idx) => {
189
232
  const columnIndex = getColumnIndex(name);
190
233
  if (columnIndex >= 0) {
191
- const value = getSummaryValue(
192
- stores.value.orderedColumns[columnIndex],
193
- column.summaryType,
194
- );
234
+ const value = getSummaryValue(stores.value.orderedColumns[columnIndex]);
195
235
  result = result.replace(`{${idx}}`, value);
196
236
  }
197
237
  });
@@ -309,7 +309,6 @@ export const resizeEvent = (params) => {
309
309
  const minWidth = isRenderer(stores.orderedColumns[columnIndex])
310
310
  ? resizeInfo.rendererMinWidth : resizeInfo.minWidth;
311
311
  const columnRect = columnEl.getBoundingClientRect();
312
- const maxRight = bodyEl.getBoundingClientRect().right - headerLeft;
313
312
  const resizeLineEl = elementInfo.resizeLine;
314
313
  const minLeft = columnRect.left - headerLeft + minWidth;
315
314
  const startLeft = columnRect.right - headerLeft;
@@ -324,9 +323,7 @@ export const resizeEvent = (params) => {
324
323
  const handleMouseMove = (evt) => {
325
324
  const deltaLeft = evt.clientX - startMouseLeft;
326
325
  const proxyLeft = startLeft + deltaLeft;
327
- let resizeWidth = Math.max(minLeft, proxyLeft);
328
-
329
- resizeWidth = Math.min(maxRight, resizeWidth);
326
+ const resizeWidth = Math.max(minLeft, proxyLeft);
330
327
 
331
328
  resizeLineEl.style.left = `${resizeWidth}px`;
332
329
  };
@@ -1025,21 +1022,19 @@ export const contextMenuEvent = (params) => {
1025
1022
  const sortable = column.sortable === undefined ? true : column.sortable;
1026
1023
  const filterable = filterInfo.isFiltering
1027
1024
  && column.filterable === undefined ? true : column.filterable;
1028
- if (!sortable && !filterable) {
1029
- contextInfo.columnMenuItems = [];
1030
- return;
1031
- }
1032
- contextInfo.columnMenuItems = [
1025
+ const columnMenuItems = [
1033
1026
  {
1034
1027
  text: 'Ascending',
1035
1028
  iconClass: 'ev-icon-allow2-up',
1036
1029
  disabled: !sortable,
1030
+ hidden: contextInfo.hiddenColumnMenuItem?.ascending,
1037
1031
  click: () => onSort(column, 'asc'),
1038
1032
  },
1039
1033
  {
1040
1034
  text: 'Descending',
1041
1035
  iconClass: 'ev-icon-allow2-down',
1042
1036
  disabled: !sortable,
1037
+ hidden: contextInfo.hiddenColumnMenuItem?.descending,
1043
1038
  click: () => onSort(column, 'desc'),
1044
1039
  },
1045
1040
  {
@@ -1062,14 +1057,21 @@ export const contextMenuEvent = (params) => {
1062
1057
  filterInfo.filteringColumn = column;
1063
1058
  },
1064
1059
  disabled: !filterable,
1060
+ hidden: contextInfo.hiddenColumnMenuItem?.filter,
1065
1061
  },
1066
1062
  {
1067
1063
  text: 'Hide',
1068
1064
  iconClass: 'ev-icon-visibility-off',
1069
1065
  disabled: !useGridSetting.value || stores.orderedColumns.length === 1,
1066
+ hidden: contextInfo.hiddenColumnMenuItem?.hide,
1070
1067
  click: () => setColumnHidden(column.field),
1071
1068
  },
1072
1069
  ];
1070
+ contextInfo.columnMenuItems = [];
1071
+ if (!sortable && !filterable) {
1072
+ return;
1073
+ }
1074
+ contextInfo.columnMenuItems = columnMenuItems.filter(item => !item.hidden);
1073
1075
  }
1074
1076
  };
1075
1077
  /**
@@ -277,7 +277,11 @@ export const useDropdown = (param) => {
277
277
 
278
278
  watch(() => mv.value, (curr) => {
279
279
  if (props.multiple && props.checkable) {
280
- allCheck.value = curr.length === filteredItems.value.filter(item => !item.disabled).length;
280
+ if (curr.length === 0) {
281
+ allCheck.value = false;
282
+ } else {
283
+ allCheck.value = curr.length === filteredItems.value.filter(item => !item.disabled).length;
284
+ }
281
285
  changeDropboxPosition();
282
286
  }
283
287
  });