evui 3.3.20 → 3.3.23

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.3.20",
3
+ "version": "3.3.23",
4
4
  "description": "A EXEM Library project",
5
5
  "author": "exem <dev_client@ex-em.com>",
6
6
  "license": "MIT",
@@ -1,4 +1,5 @@
1
1
  import { defaultsDeep } from 'lodash-es';
2
+ import { truthy } from '@/common/utils';
2
3
  import { COLOR, BAR_OPTION } from '../helpers/helpers.constant';
3
4
  import Canvas from '../helpers/helpers.canvas';
4
5
  import Util from '../helpers/helpers.util';
@@ -359,13 +360,11 @@ class Bar {
359
360
  ctx.textAlign = isHorizontal && align !== 'center' ? 'left' : 'center';
360
361
 
361
362
  let value;
362
- const isStacked = !isNaN(data.o);
363
- if (data.o === null) {
364
- value = isHorizontal ? data.x : data.y;
365
- } else if (isStacked) {
363
+ const isStacked = truthy(this.stackIndex);
364
+ if (isStacked) {
366
365
  value = data.o;
367
366
  } else {
368
- value = '';
367
+ value = (isHorizontal ? data.x : data.y) ?? '';
369
368
  }
370
369
 
371
370
  let formattedTxt;
@@ -374,49 +373,73 @@ class Bar {
374
373
  }
375
374
 
376
375
  if (!formatter || typeof formattedTxt !== 'string') {
377
- formattedTxt = Util.labelSignFormat(value, decimalPoint);
376
+ formattedTxt = Util.labelSignFormat(value, decimalPoint) ?? '';
378
377
  }
379
378
 
380
- const vw = Math.round(ctx.measureText(formattedTxt).width);
381
- const vh = fontSize + 4;
379
+ const textWidth = Math.round(ctx.measureText(formattedTxt).width);
380
+ const textHeight = fontSize + 4;
382
381
  const minXPos = x + 10;
383
382
  const minYPos = y - 10;
383
+ const widthFreeSpaceToDraw = w - 10;
384
+ const heightFreeSpaceToDraw = Math.abs(h + 10);
384
385
  const centerX = x + (w / 2) <= minXPos ? minXPos : x + (w / 2);
385
386
  const centerY = y + (h / 2) >= minYPos ? minYPos : y + (h / 2);
386
387
  const centerYHorizontal = isHighlight ? y + (h / 2) : y - (h / 2);
387
388
 
388
389
  switch (align) {
389
- case 'start':
390
+ case 'start': {
390
391
  if (isHorizontal) {
391
- ctx.fillText(formattedTxt, minXPos, centerYHorizontal);
392
- } else {
392
+ if (textWidth < widthFreeSpaceToDraw) {
393
+ ctx.fillText(formattedTxt, minXPos, centerYHorizontal);
394
+ }
395
+ } else if (textHeight < heightFreeSpaceToDraw) {
393
396
  ctx.fillText(formattedTxt, centerX, minYPos);
394
397
  }
398
+
395
399
  break;
396
- case 'center':
400
+ }
401
+
402
+ case 'center': {
397
403
  if (isHorizontal) {
398
- ctx.fillText(formattedTxt, centerX, centerYHorizontal);
399
- } else {
404
+ if (textWidth < widthFreeSpaceToDraw) {
405
+ ctx.fillText(formattedTxt, centerX, centerYHorizontal);
406
+ }
407
+ } else if (textHeight < heightFreeSpaceToDraw) {
400
408
  ctx.fillText(formattedTxt, centerX, centerY);
401
409
  }
410
+
402
411
  break;
403
- case 'out':
412
+ }
413
+
414
+ case 'out': {
415
+ if (isStacked) {
416
+ console.warn('[EVUI][Bar Chart] In case of Stack Bar Chart, \'out\' of \'showValue\'\'s align is not supported.');
417
+ return;
418
+ }
419
+
404
420
  if (isHorizontal) {
405
421
  ctx.fillText(formattedTxt, minXPos + w, centerYHorizontal);
406
422
  } else {
407
- ctx.fillText(formattedTxt, centerX, y + h - (vh / 2));
423
+ ctx.fillText(formattedTxt, centerX, y + h - (textHeight / 2));
408
424
  }
425
+
409
426
  break;
410
- case 'end':
427
+ }
428
+
411
429
  default:
430
+ case 'end': {
412
431
  if (isHorizontal) {
413
- const xPos = x + w - (vw * 2);
414
- ctx.fillText(formattedTxt, xPos <= minXPos ? minXPos : xPos, centerYHorizontal);
415
- } else {
416
- const yPos = y + h + vh;
432
+ if (textWidth < widthFreeSpaceToDraw) {
433
+ const xPos = x + w - (textWidth * 2);
434
+ ctx.fillText(formattedTxt, xPos <= minXPos ? minXPos : xPos, centerYHorizontal);
435
+ }
436
+ } else if (textHeight < heightFreeSpaceToDraw) {
437
+ const yPos = y + h + textHeight;
417
438
  ctx.fillText(formattedTxt, centerX, yPos >= minYPos ? minYPos : yPos);
418
439
  }
440
+
419
441
  break;
442
+ }
420
443
  }
421
444
 
422
445
  ctx.restore();
@@ -15,7 +15,10 @@ class HeatMap {
15
15
 
16
16
  this.sId = sId;
17
17
  this.data = [];
18
- this.labels = {};
18
+ this.labels = {
19
+ x: [],
20
+ y: [],
21
+ };
19
22
  this.valueOpt = {};
20
23
  this.size = {
21
24
  w: 0,
@@ -137,7 +140,7 @@ class HeatMap {
137
140
  ctx.beginPath();
138
141
  if (this.stroke.show) {
139
142
  const { radius } = this.stroke;
140
- if (radius > 0) {
143
+ if (radius > 0 && radius < h && radius < w) {
141
144
  ctx.moveTo(x + radius, y);
142
145
  ctx.arcTo(x + w, y, x + w, y + h, radius);
143
146
  ctx.arcTo(x + w, y + h, x, y + h, radius);
@@ -698,9 +698,15 @@ const modules = {
698
698
  vector: { start: position[dataIndex - 1], end: position[dataIndex] },
699
699
  }));
700
700
 
701
+ const isEmptyVector = (arr => !arr || !Array.isArray(arr) || arr?.length !== 2);
702
+
701
703
  // canvas 의 클릭 위치값은 제 4 사분면의 위치이므로 clickedY, y1, y2 의 값은 음수를 취한다.
702
704
  if (isStackChart) {
703
705
  hitSeries = vectorList.find(({ vector }) => {
706
+ if (isEmptyVector(vector?.start) && isEmptyVector(vector?.end)) {
707
+ return false;
708
+ }
709
+
704
710
  const [x1, y1] = vector.start;
705
711
  const [x2, y2] = vector.end;
706
712
  const v1 = [x2 - x1, y1 - y2];
@@ -713,6 +719,10 @@ const modules = {
713
719
  })?.sId;
714
720
  } else {
715
721
  hitSeries = vectorList.find(({ vector }) => {
722
+ if (isEmptyVector(vector?.start) && isEmptyVector(vector?.end)) {
723
+ return false;
724
+ }
725
+
716
726
  const [x1, y1] = vector.start;
717
727
  const [x2, y2] = vector.end;
718
728
  const a = (y1 - y2) / (x2 - x1);
@@ -38,8 +38,10 @@ const modules = {
38
38
  this.createLegendLayout();
39
39
  this.createLegend();
40
40
  }
41
- const series = Object.values(this.seriesList)[0];
42
- this.setLegendStyle(series);
41
+
42
+ Object.values(this.seriesList).forEach((series) => {
43
+ this.setLegendStyle(series);
44
+ });
43
45
  this.initEvent();
44
46
 
45
47
  this.isInitLegend = true;
@@ -76,7 +78,12 @@ const modules = {
76
78
  return;
77
79
  }
78
80
 
79
- const { colorState } = Object.values(this.seriesList)[0];
81
+ const seriesList = Object.values(this.seriesList);
82
+ if (!seriesList.length) {
83
+ return;
84
+ }
85
+
86
+ const { colorState } = seriesList[0];
80
87
  const { start, end } = colorState[0];
81
88
 
82
89
  colorState[0].selectedValue = null;
@@ -102,7 +109,12 @@ const modules = {
102
109
  value = this.isSide ? 100 - value : value;
103
110
  const dir = isStart ? 'start' : 'end';
104
111
 
105
- const { colorState } = Object.values(this.seriesList)[0];
112
+ const seriesList = Object.values(this.seriesList);
113
+ if (!seriesList.length) {
114
+ return;
115
+ }
116
+
117
+ const { colorState } = seriesList[0];
106
118
  const { start, end } = colorState[0];
107
119
  if ((isStart && value > end) || (!isStart && value < start)) {
108
120
  return;
@@ -132,7 +144,12 @@ const modules = {
132
144
  this.onLegendBoxOver = (e) => {
133
145
  const type = e.target.dataset.type;
134
146
 
135
- const { colorState, valueOpt } = Object.values(this.seriesList)[0];
147
+ const seriesList = Object.values(this.seriesList);
148
+ if (!seriesList.length) {
149
+ return;
150
+ }
151
+
152
+ const { colorState, valueOpt } = seriesList[0];
136
153
  const state = colorState[0];
137
154
 
138
155
  let value = this.getSelectedValue(e);
@@ -170,7 +187,12 @@ const modules = {
170
187
  const targetDOM = lineDOM.getElementsByClassName('ev-chart-legend-thumb')[0];
171
188
  this.clearOverlay(targetDOM);
172
189
 
173
- const { colorState } = Object.values(this.seriesList)[0];
190
+ const seriesList = Object.values(this.seriesList);
191
+ if (!seriesList.length) {
192
+ return;
193
+ }
194
+
195
+ const { colorState } = seriesList[0];
174
196
  colorState[0].selectedValue = null;
175
197
 
176
198
  this.update({
@@ -210,8 +232,9 @@ const modules = {
210
232
  this.resetLegend();
211
233
  this.createLegend();
212
234
 
213
- const series = Object.values(this.seriesList)[0];
214
- this.setLegendStyle(series);
235
+ Object.values(this.seriesList).forEach((series) => {
236
+ this.setLegendStyle(series);
237
+ });
215
238
  },
216
239
 
217
240
  /**
@@ -249,6 +272,9 @@ const modules = {
249
272
  this.clearOverlay();
250
273
  const handleSize = this.legendHandleSize;
251
274
  const { min, max } = opt;
275
+ if (min === undefined || max === undefined) {
276
+ return;
277
+ }
252
278
 
253
279
  const targetDOM = this.containerDOM.getElementsByClassName('ev-chart-legend-line')[0];
254
280
 
@@ -326,6 +352,10 @@ const modules = {
326
352
  * @returns {undefined}
327
353
  */
328
354
  createLegend() {
355
+ if (!Object.values(this.seriesList).length) {
356
+ return;
357
+ }
358
+
329
359
  const opt = this.options.legend;
330
360
  this.isSide = !['top', 'bottom'].includes(opt.position);
331
361
  const legendSize = this.isSide ? opt.width : opt.height;
@@ -364,6 +394,7 @@ const modules = {
364
394
  const { valueOpt, colorState } = series;
365
395
 
366
396
  const { min, max, decimalPoint } = valueOpt;
397
+
367
398
  const { start, end } = colorState[0];
368
399
  const startColor = series.getColorForGradient(start);
369
400
  const endColor = series.getColorForGradient(end);
@@ -400,8 +431,10 @@ const modules = {
400
431
  const labelDOM = thumbDOM.getElementsByClassName('ev-chart-legend-label');
401
432
  labelDOM[0].style.cssText = `${labelStyle}0%;`;
402
433
  labelDOM[1].style.cssText = `${labelStyle}100%;`;
403
- labelDOM[0].innerText = this.isSide ? maxText : minText;
404
- labelDOM[1].innerText = this.isSide ? minText : maxText;
434
+ if (min !== undefined && max !== undefined) {
435
+ labelDOM[0].innerText = this.isSide ? maxText : minText;
436
+ labelDOM[1].innerText = this.isSide ? minText : maxText;
437
+ }
405
438
 
406
439
  const handleDOM = this.containerDOM.getElementsByClassName('ev-chart-legend-handle');
407
440
  handleDOM[0].style.cssText = defaultHandleStyle + startStyle;
@@ -524,8 +557,9 @@ const modules = {
524
557
  * @returns {undefined}
525
558
  */
526
559
  updateLegendContainerSize() {
527
- const series = Object.values(this.seriesList)[0];
528
- this.setLegendStyle(series);
560
+ Object.values(this.seriesList).forEach((series) => {
561
+ this.setLegendStyle(series);
562
+ });
529
563
  },
530
564
 
531
565
  /**
@@ -531,6 +531,7 @@ const modules = {
531
531
  const resizeStyle = this.resizeDOM?.style;
532
532
 
533
533
  let chartRect;
534
+ let legendPad;
534
535
  const title = opt?.title?.show ? opt?.title?.height : 0;
535
536
  const positionTop = title + opt?.legend?.height;
536
537
  const { top = 0, bottom = 0, left = 0, right = 0 } = opt?.legend?.padding ?? {};
@@ -545,9 +546,10 @@ const modules = {
545
546
  case 'top':
546
547
  wrapperStyle.padding = `${positionTop}px 0 0 0`;
547
548
  chartRect = this.chartDOM.getBoundingClientRect();
549
+ legendPad = parseInt(legendStyle.paddingTop) + parseInt(legendStyle.paddingBottom);
548
550
 
549
551
  boxStyle.width = '100%';
550
- boxStyle.height = `${opt.legend.height}px`;
552
+ boxStyle.height = `${opt.legend.height - legendPad}px`;
551
553
 
552
554
  legendStyle.top = `${title}px`;
553
555
  legendStyle.right = '';
@@ -555,7 +557,7 @@ const modules = {
555
557
  legendStyle.left = '';
556
558
 
557
559
  legendStyle.width = `${chartRect.width}px`;
558
- legendStyle.height = `${opt.legend.height + 4}px`; // 4 resize bar size
560
+ legendStyle.height = `${opt.legend.height + (resizeStyle ? 4 : 0)}px`; // 4 resize bar size
559
561
 
560
562
  if (resizeStyle) {
561
563
  resizeStyle.top = `${positionTop}px`;
@@ -598,9 +600,10 @@ const modules = {
598
600
  case 'bottom':
599
601
  wrapperStyle.padding = `${title}px 0 ${opt.legend.height}px 0`;
600
602
  chartRect = this.chartDOM.getBoundingClientRect();
603
+ legendPad = parseInt(legendStyle.paddingTop) + parseInt(legendStyle.paddingBottom);
601
604
 
602
605
  boxStyle.width = '100%';
603
- boxStyle.height = `${opt.legend.height}px`;
606
+ boxStyle.height = `${opt.legend.height - legendPad}px`;
604
607
 
605
608
  legendStyle.top = '';
606
609
  legendStyle.right = '';
@@ -608,7 +611,7 @@ const modules = {
608
611
  legendStyle.left = '0px';
609
612
 
610
613
  legendStyle.width = `${chartRect.width}px`;
611
- legendStyle.height = `${opt.legend.height + 4}px`; // 4 resize bar size
614
+ legendStyle.height = `${opt.legend.height + (resizeStyle ? 4 : 0)}px`; // 4 resize bar size
612
615
 
613
616
  if (resizeStyle) {
614
617
  resizeStyle.top = '';
@@ -1,9 +1,9 @@
1
- import { numberWithComma } from '@/common/utils';
1
+ import { numberWithComma, convertToPercent } from '@/common/utils';
2
2
  import debounce from '@/common/utils.debounce';
3
3
  import dayjs from 'dayjs';
4
4
  import Canvas from '../helpers/helpers.canvas';
5
5
  import Util from '../helpers/helpers.util';
6
- import { convertToPercent } from '../../../common/utils';
6
+
7
7
 
8
8
  const TITLE_HEIGHT = 30;
9
9
  const TEXT_HEIGHT = 14;
@@ -11,7 +11,7 @@ const LINE_SPACING = 8;
11
11
  const COLOR_MARGIN = 16;
12
12
  const VALUE_MARGIN = 50;
13
13
  const SCROLL_WIDTH = 17;
14
- const FONT_STYLE = 'normal normal lighter 14px Roboto';
14
+ let fontStyle = 'normal normal lighter 14px Roboto';
15
15
 
16
16
  const modules = {
17
17
  /**
@@ -34,6 +34,7 @@ const modules = {
34
34
  this.tooltipCtx = this.tooltipCanvas.getContext('2d');
35
35
 
36
36
  this.tooltipDOM.style.display = 'none';
37
+ this.setFontFamily();
37
38
 
38
39
  this.tooltipBodyDOM.appendChild(this.tooltipCanvas);
39
40
  this.tooltipDOM.appendChild(this.tooltipHeaderDOM);
@@ -52,6 +53,15 @@ const modules = {
52
53
  }
53
54
  },
54
55
 
56
+ /**
57
+ * set tooltip's font style
58
+ */
59
+ setFontFamily() {
60
+ const fontFamily = this.options?.tooltip?.fontFamily ?? 'Roboto';
61
+ fontStyle = `normal normal lighter 14px ${fontFamily}`;
62
+ this.tooltipHeaderDOM.style.fontFamily = fontFamily;
63
+ },
64
+
55
65
  /**
56
66
  * Set tooltip DOM's position and style
57
67
  * @param {object} hitInfo value and mouse position touched
@@ -73,7 +83,7 @@ const modules = {
73
83
 
74
84
  // calculate and decide width of canvas El(contentsWidth)
75
85
  ctx.save();
76
- ctx.font = FONT_STYLE;
86
+ ctx.font = fontStyle;
77
87
  const isHorizontal = !!this.options.horizontal;
78
88
  const label = isHorizontal ? items[hitInfo.hitId]?.data?.y : items[hitInfo.hitId]?.data?.x;
79
89
  const tooltipValue = label?.length > maxSeries.length ? label : maxSeries;
@@ -216,7 +226,7 @@ const modules = {
216
226
  x += boxPadding.l;
217
227
  y += boxPadding.t;
218
228
 
219
- ctx.font = FONT_STYLE;
229
+ ctx.font = fontStyle;
220
230
 
221
231
  const seriesList = [];
222
232
  seriesKeys.forEach((seriesName) => {
@@ -414,7 +424,7 @@ const modules = {
414
424
  const itemY = boxPadding.t + TEXT_HEIGHT + 2;
415
425
  const itemValue = hitItem.o > -1 ? hitItem.o : 'error';
416
426
 
417
- ctx.font = FONT_STYLE;
427
+ ctx.font = fontStyle;
418
428
 
419
429
  ctx.beginPath();
420
430
 
@@ -490,7 +500,7 @@ const modules = {
490
500
  x += boxPadding.l;
491
501
  y += boxPadding.t;
492
502
 
493
- ctx.font = FONT_STYLE;
503
+ ctx.font = fontStyle;
494
504
 
495
505
  const seriesList = [];
496
506
  seriesKeys.forEach((seriesName) => {
@@ -48,11 +48,16 @@ class StepScale extends Scale {
48
48
  if (this.rangeMode) {
49
49
  const { maxSteps } = range;
50
50
 
51
- while (numberOfSteps > maxSteps * 2) {
52
- interval *= 2;
53
- numberOfSteps = Math.round(numberOfSteps / interval);
51
+ if (maxSteps > 2) {
52
+ while (numberOfSteps > maxSteps * 2) {
53
+ interval *= 2;
54
+ numberOfSteps = Math.round(numberOfSteps / interval);
55
+ }
56
+ } else {
57
+ interval = this.labels.length;
54
58
  }
55
59
  }
60
+
56
61
  return {
57
62
  steps: numberOfSteps,
58
63
  interval,
@@ -223,7 +223,6 @@
223
223
 
224
224
  .ev-chart-tooltip-header {
225
225
  padding: 8px 16px 0 16px;
226
- font-family: Roboto, serif;
227
226
  overflow: hidden;
228
227
  font-size: 16px;
229
228
 
@@ -59,6 +59,7 @@ const DEFAULT_OPTIONS = {
59
59
  debouncedHide: false,
60
60
  useScrollbar: false,
61
61
  textOverflow: 'wrap',
62
+ fontFamily: 'Roboto',
62
63
  },
63
64
  indicator: {
64
65
  use: true,
@@ -263,7 +263,7 @@
263
263
  <grid-pagination
264
264
  v-if="usePage && !isInfinite"
265
265
  v-model="currentPage"
266
- :total="store.length"
266
+ :total="pageTotal"
267
267
  :per-page="perPage"
268
268
  :visible-page="visiblePage"
269
269
  :show-page-info="showPageInfo"
@@ -392,7 +392,7 @@ export default {
392
392
  startIndex: 0,
393
393
  prevPage: 0,
394
394
  currentPage: 0,
395
- total: computed(() => (props.option.page?.total || 0)),
395
+ pageTotal: computed(() => (props.option.page?.total || 0)),
396
396
  perPage: computed(() => (props.option.page?.perPage || 20)),
397
397
  visiblePage: computed(() => (props.option.page?.visiblePage || 8)),
398
398
  order: computed(() => (props.option.page?.order || 'center')),
@@ -963,7 +963,7 @@ export const pagingEvent = (params) => {
963
963
  currentPage: pageInfo.currentPage,
964
964
  prevPage: pageInfo.prevPage,
965
965
  startIndex: pageInfo.startIndex,
966
- total: pageInfo.total,
966
+ total: pageInfo.pageTotal,
967
967
  perPage: pageInfo.perPage,
968
968
  },
969
969
  sortInfo: {
@@ -118,10 +118,11 @@
118
118
  >
119
119
  <input
120
120
  v-if="filterable"
121
- v-model="filterTextRef"
122
121
  type="text"
123
122
  class="ev-input-query"
124
123
  :placeholder="searchPlaceholder"
124
+ :value="filterTextRef"
125
+ @input="changeFilterText"
125
126
  />
126
127
  <div
127
128
  ref="itemWrapper"
@@ -242,6 +243,7 @@ export default {
242
243
  filteredItems,
243
244
  clickSelectInput,
244
245
  clickOutsideDropbox,
246
+ changeFilterText,
245
247
  changeDropboxPosition,
246
248
  clickItem,
247
249
  selectedItemClass,
@@ -266,6 +268,7 @@ export default {
266
268
  filteredItems,
267
269
  clickSelectInput,
268
270
  clickOutsideDropbox,
271
+ changeFilterText,
269
272
  changeDropboxPosition,
270
273
  clickItem,
271
274
  selectedItemClass,
@@ -127,6 +127,13 @@ export const useDropdown = (param) => {
127
127
  return props.items.filter(v => v.name.toUpperCase().includes(trimText.toUpperCase())) || [];
128
128
  });
129
129
 
130
+ /**
131
+ * filterable 에서 text input 이벤트 핸들러
132
+ */
133
+ const changeFilterText = (e) => {
134
+ filterTextRef.value = e?.target?.value;
135
+ };
136
+
130
137
  /**
131
138
  * dropdown box 위치 변경하는 메소드
132
139
  */
@@ -255,6 +262,7 @@ export const useDropdown = (param) => {
255
262
  filteredItems,
256
263
  clickSelectInput,
257
264
  clickOutsideDropbox,
265
+ changeFilterText,
258
266
  changeDropboxPosition,
259
267
  clickItem,
260
268
  selectedItemClass,
@@ -178,7 +178,7 @@
178
178
  <grid-pagination
179
179
  v-if="usePage && !isInfinite"
180
180
  v-model="currentPage"
181
- :total="showTreeStore.length"
181
+ :total="pageTotal"
182
182
  :per-page="perPage"
183
183
  :visible-page="visiblePage"
184
184
  :show-page-info="showPageInfo"
@@ -290,7 +290,7 @@ export default {
290
290
  startIndex: 0,
291
291
  prevPage: 0,
292
292
  currentPage: 0,
293
- total: computed(() => (props.option.page?.total || 0)),
293
+ pageTotal: computed(() => (props.option.page?.total || 0)),
294
294
  perPage: computed(() => (props.option.page?.perPage || 20)),
295
295
  visiblePage: computed(() => (props.option.page?.visiblePage || 8)),
296
296
  order: computed(() => (props.option.page?.order || 'center')),
@@ -841,7 +841,7 @@ export const pagingEvent = (params) => {
841
841
  currentPage: pageInfo.currentPage,
842
842
  prevPage: pageInfo.prevPage,
843
843
  startIndex: pageInfo.startIndex,
844
- total: pageInfo.total,
844
+ total: pageInfo.pageTotal,
845
845
  perPage: pageInfo.perPage,
846
846
  },
847
847
  searchInfo: {