tenghui-ui 2.2.0 → 2.2.2

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": "tenghui-ui",
3
- "version": "2.2.0",
3
+ "version": "2.2.2",
4
4
  "description": "vue 2x, tenghui-ui",
5
5
  "files": [
6
6
  "dist",
@@ -154,14 +154,14 @@
154
154
  </div>
155
155
  <el-date-picker :class="{ inline_content: inlineLabel }" :ref="type"
156
156
  v-model="modelForm[0]"
157
- v-bind="{ ...setDefaultAttrs($attrs), type: 'datetime' }"
157
+ v-bind="{ ...setDefaultAttrs($attrs), type: 'datetime', defaultTime: defaultTime ? defaultTime[0] : '' }"
158
158
  placeholder="请选择开始时间"
159
159
  v-on="$listeners">
160
160
  </el-date-picker>
161
161
  <span style="color: #dcdfe6">-</span>
162
162
  <el-date-picker :class="{ inline_content: inlineLabel }" :ref="type"
163
163
  v-model="modelForm[1]"
164
- v-bind="{ ...setDefaultAttrs($attrs), type: 'datetime' }"
164
+ v-bind="{ ...setDefaultAttrs($attrs), type: 'datetime', defaultTime: defaultTime ? defaultTime[1] : '' }"
165
165
  placeholder="请选择结束时间"
166
166
  v-on="$listeners">
167
167
  </el-date-picker>
@@ -309,7 +309,9 @@ export default {
309
309
 
310
310
  filterMethod: {
311
311
  type: Function
312
- }
312
+ },
313
+
314
+ defaultTime: [Array, String]
313
315
  },
314
316
  data() {
315
317
  return {
@@ -0,0 +1,598 @@
1
+ <template>
2
+ <div class="ui-search" ref="Search" v-loading="loadSearch">
3
+ <div class="ui-search__main" v-show="collspase">
4
+ <!-- <slot v-if="!useConfig"></slot> -->
5
+ <!-- <div v-else v-show="false"><slot></slot></div> -->
6
+ <template v-if="!loadSearch && useConfig">
7
+ <DefaultItem :ref="`Config_${vnode.ref || vnode.$options.propsData.label || index}`" v-for="(vnode, index) in childItems" :key="index" :vnode="vnode"></DefaultItem>
8
+ </template>
9
+ </div>
10
+ <div class="ui-search__footer" v-show="collspase">
11
+ <el-button size="small" icon="el-icon-refresh" @click="handleReset">重置</el-button>
12
+ <el-button style="margin-right: 10px;" size="small" icon="el-icon-search" type="primary" @click="handleQuery">查询</el-button>
13
+ <div style="align-self: flex-end;">
14
+ <el-popover
15
+ placement="bottom-start"
16
+ trigger="click"
17
+ popper-class="ui-search__popover"
18
+ v-if="showMore"
19
+ :offset="-172"
20
+ :width="containerWidth">
21
+ <div class="ui-more__select">
22
+ <el-row>
23
+ <el-col v-for="(vnode, index) in hideItems" :key="index" v-bind="{ span: 4, ...vnode.$attrs, ...vnode.$options.propsData }">
24
+ <template v-if="!loadSearch && useConfig">
25
+ <DefaultItem :vnode="vnode" :ref="`Config_${vnode.ref || vnode.$options.propsData.label || index}`"></DefaultItem>
26
+ </template>
27
+ <template v-else-if="!loadSearch">
28
+ <DefaultItem :vnode="vnode" :ref="`Config_${vnode.ref || vnode.$options.propsData.label || index}`"></DefaultItem>
29
+ </template>
30
+ </el-col>
31
+ </el-row>
32
+ </div>
33
+ <el-button slot="reference" class="ui-search__button--more" type="text">更多筛选 <i class="el-icon-caret-right"></i></el-button>
34
+ </el-popover>
35
+ </div>
36
+ <el-button v-if="useConfig" @click="handleShowConfig" class="ui-search__button--more" type="text">筛选配置 <i class="el-icon-setting"></i></el-button>
37
+ <Record :config-key="configKey" :current="searchLoc" />
38
+ <slot name="footer"></slot>
39
+ <div class="ui-search__cache" v-show="searchLoc.length" :title="searchLoc.map(v => `${v.label}:${v.valueLabel || v.value}`).join(';')">
40
+ <span v-for="(item, index) in searchLoc" :key="index">{{item.label}}:{{item.valueLabel || item.value}}</span>
41
+ </div>
42
+ </div>
43
+ <div v-show="!collspase" class="ui-collspase--cache">
44
+ <el-tooltip class="item" effect="dark"
45
+ popper-class="ui-search__cache__popper"
46
+ placement="bottom-start">
47
+ <div class="ui-search__cache" v-show="searchLoc.length">
48
+ <span v-for="(item, index) in searchLoc" :key="index">{{item.label}}:{{item.valueLabel || item.value}}</span>
49
+ </div>
50
+ <template v-slot:content>
51
+ <p style="line-height: 18px;">{{ searchLoc.map(v => `${v.label}:${v.valueLabel || v.value}`).join(';') }}</p>
52
+ </template>
53
+ </el-tooltip>
54
+ </div>
55
+ <div class="ui-collspase"
56
+ :class="{ 'ui-collspase--open': collspase }"
57
+ @click="collspase = !collspase">
58
+ <span :class="collspase ? 'el-icon-caret-top' : 'el-icon-caret-bottom'"></span>
59
+ </div>
60
+ <el-drawer
61
+ title="筛选配置"
62
+ direction="btt"
63
+ size="100%"
64
+ :withHeader="false"
65
+ :modal="false"
66
+ :modal-append-to-body="false"
67
+ :visible.sync="showConfig">
68
+ <div class="ui-search--sort">
69
+ <div class="ui-sort__content">
70
+ <el-checkbox-group v-model="checkItems" size="mini">
71
+ <draggable class="ui-draggable" v-model="sortItems"
72
+ animation="100" chosenClass="ui-dragmove">
73
+ <el-checkbox border :label="item" v-for="(item, index) in sortItems" :key="index"></el-checkbox>
74
+ </draggable>
75
+ </el-checkbox-group>
76
+ </div>
77
+ <div class="ui-sort__footer">
78
+ <el-button type="primary" size="mini" @click="handleRenderConfig">确认</el-button>
79
+ <el-button size="mini" @click="showConfig = !showConfig">取消</el-button>
80
+ </div>
81
+ </div>
82
+ </el-drawer>
83
+ </div>
84
+ </template>
85
+ <script>
86
+ import draggable from 'vuedraggable';
87
+ import Record from './Record.vue';
88
+ import DefaultItem from './DefaultItem.vue';
89
+ import { debounce } from 'throttle-debounce';
90
+ import { sleep } from '@/utils';
91
+ export default {
92
+ name: 'ComSearch',
93
+ components: {
94
+ draggable,
95
+ Record,
96
+ DefaultItem
97
+ },
98
+ props: {
99
+ searchCfg: {
100
+ type: Array,
101
+ default() {
102
+ return []
103
+ }
104
+ },
105
+
106
+ // flagId 为空则取路由
107
+ flagId: {
108
+ type: String,
109
+ default: ''
110
+ },
111
+
112
+ useConfig: {
113
+ type: Boolean,
114
+ default: true
115
+ }
116
+ },
117
+ data() {
118
+ return {
119
+ containerWidth: '200px',
120
+ hideItems: [],
121
+
122
+ // 默认的搜索条件
123
+ defaultVNode: [],
124
+ defaultItems: [],
125
+ showConfig: false,
126
+ checkItems: [],
127
+ sortItems: [],
128
+
129
+ loadSearch: false,
130
+
131
+ // 搜索缓存
132
+ searchLoc: [],
133
+
134
+ // 搜索items
135
+ childItems: [],
136
+
137
+ // 初始化
138
+ initLoad: false,
139
+
140
+ configKey: this.flagId || this.$route.path,
141
+
142
+ handleWindowResize: null,
143
+
144
+ waitTimeout: '',
145
+
146
+ searchHeight: '',
147
+ listenerSearchTimes: '',
148
+ collspase: true,
149
+ showTip: false
150
+ }
151
+ },
152
+ computed: {
153
+ showMore() {
154
+ return !!this.hideItems.length;
155
+ },
156
+ ConfigRefs() {
157
+ return Object.entries(this.$refs).reduce((temp, [key, ref]) => {
158
+ if (key.indexOf('Config_') > -1) {
159
+ const oKey = key.replace('Config_', '');
160
+ const oRefs = ref[0].$refs[oKey];
161
+ return {
162
+ ...temp,
163
+ ...(oRefs ? { [oKey]: oRefs.$refs[oRefs.type] } : {})
164
+ }
165
+ }
166
+ }, {});
167
+ }
168
+ },
169
+ methods: {
170
+ handleQuery() {
171
+
172
+ const empty = (value, type) => {
173
+ if (value) {
174
+ if (value instanceof Date) return false;
175
+
176
+ if (Array.isArray(value) && type == 'inputrange') {
177
+ return !value[0] && !value[1];
178
+ } else {
179
+ return value instanceof Object ? !Object.entries(value).length : false
180
+ }
181
+ } else if (typeof value === 'boolean') {
182
+ return false;
183
+ }
184
+ return true;
185
+ }
186
+
187
+ this.searchLoc = this.$children.reduce((temp, item) => {
188
+ if (item.label && !empty(item.modelForm, item.type)) {
189
+
190
+ let valueLabel;
191
+ if (item.options && Object.entries(item.options).length > 0) {
192
+ if (Array.isArray(item.modelForm)) {
193
+ valueLabel = item.modelForm.map(iv => item.selectOption.find(v => v.value == iv)?.label || iv)
194
+ } else {
195
+ valueLabel = item.selectOption.find(v => v.value == item.modelForm)?.label || item.modelForm
196
+ }
197
+ }
198
+
199
+ return [
200
+ ...temp,
201
+ {
202
+ label: item.label,
203
+ value: item.modelForm,
204
+ valueLabel
205
+ }
206
+ ]
207
+ } else {
208
+ return temp;
209
+ }
210
+ }, []);
211
+
212
+ const queryFn = this.$parent.handleQuery;
213
+ const SearchConfig = this.$UICONFIG ? this.$UICONFIG.searchConfig || {} : {};
214
+ if (queryFn) {
215
+ queryFn({ ...(SearchConfig.defaultParams || {}) });
216
+ } else {
217
+ this.$emit('query');
218
+ }
219
+ },
220
+ handleReset() {
221
+ const resetFn = this.$parent.handleReset;
222
+ if (resetFn) {
223
+ resetFn();
224
+ } else {
225
+ this.$emit('reset');
226
+ }
227
+ },
228
+
229
+ waitRenderItem() {
230
+ return new Promise((resolve) => {
231
+ clearTimeout(this.waitTimeout);
232
+ const itemEls = this.$refs.Search.querySelectorAll('.ui-form__item:not([class*=prepend] .ui-form__item)');
233
+ for (let i = 0; i < itemEls.length; i++) {
234
+ const el = itemEls[i];
235
+ if (el.getBoundingClientRect().right > 0) {
236
+ return resolve(true);
237
+ }
238
+ }
239
+
240
+ this.waitTimeout = setTimeout(async () => {
241
+ resolve(await this.waitRenderItem());
242
+ }, 100)
243
+ })
244
+ },
245
+
246
+ async handleLayoutItem(renderEle = false) {
247
+
248
+ await this.waitRenderItem();
249
+
250
+ const containerEl = this.$refs.Search;
251
+ const itemEls = containerEl.querySelectorAll('.ui-form__item:not([class*=prepend] .ui-form__item)');
252
+
253
+ // 重置item 状态
254
+ itemEls.forEach(ele => ele.className = ele.className.replace('ui-form__item--hide', ''))
255
+
256
+ const { right: containerRight } = containerEl.getBoundingClientRect();
257
+ this.containerWidth = containerEl.offsetWidth - 80;
258
+
259
+ if (this.useConfig) {
260
+ itemEls.forEach(ele => {
261
+ try {
262
+ const eleFlagLabel = ele.__vue__.label || ele.__vue__.$children[0].label;
263
+ if (!this.checkItems.includes(eleFlagLabel)) {
264
+ ele.style.display = 'none';
265
+ } else {
266
+ ele.style.display = 'block';
267
+ }
268
+ } catch(e) {
269
+ console.log(ele.__vue__, ele);
270
+ }
271
+ })
272
+ }
273
+
274
+ const hideEls = [];
275
+ itemEls.forEach(ele => {
276
+ const { right: itemRight } = ele.getBoundingClientRect();
277
+ if (itemRight > containerRight) {
278
+ ele.className = `${ele.className} ui-form__item--hide`;
279
+ hideEls.push(ele);
280
+ }
281
+ })
282
+ if (renderEle === true) return;
283
+
284
+ if (this.useConfig) {
285
+ this.hideItems = hideEls.map(item => {
286
+ return this.childItems.find((v, i) => {
287
+ const options = item.__vue__.vnode ? item.__vue__.vnode.$options : item.__vue__.$options;
288
+ return v.$options.propsData.label == options.propsData.label;
289
+ })
290
+ }).filter(item => !!item);
291
+ } else {
292
+ this.hideItems = this.$children.filter(item => item.$el.className.indexOf('ui-form__item--hide') > -1);
293
+ }
294
+ this.loadSearch = false;
295
+ },
296
+ changeOptions(item) {
297
+ this.$parent.changeOptions(item);
298
+ },
299
+
300
+ // 显示配置
301
+ handleShowConfig() {
302
+ this.showConfig = true;
303
+ },
304
+
305
+ // 渲染配置
306
+ async handleRenderConfig() {
307
+
308
+ // 配置存至缓存
309
+ const saveConfig = {
310
+ checkItems: this.checkItems,
311
+ sortItems: this.sortItems
312
+ }
313
+ localStorage.setItem(`SearchCfg__${this.configKey}`, JSON.stringify(saveConfig));
314
+
315
+ const sortItems = this.sortItems.map(item => {
316
+ const findItem = this.childItems.find(v => v.$options.propsData.label == item);
317
+ return findItem;
318
+ })
319
+
320
+ this.childItems = sortItems;
321
+
322
+ await this.$nextTick();
323
+
324
+ this.showConfig = false;
325
+ this.handleLayoutItem();
326
+ },
327
+
328
+ // 监听Search高度
329
+ listenerSearchHeight() {
330
+ this.searchHeight = this.$refs.Search.offsetHeight;
331
+ this.listenerSearchTimes = setInterval(() => {
332
+ if (this.searchHeight != this.$refs.Search.offsetHeight) {
333
+ this.searchHeight = this.$refs.Search.offsetHeight;
334
+ const findTableRes = this.$parent.$children.find(refItem => refItem.$options._componentTag == 'com-table');
335
+ findTableRes && findTableRes.handleRefreshHeight();
336
+ }
337
+ }, 200);
338
+ }
339
+ },
340
+ async mounted() {
341
+
342
+ // this.childItems = this.$slots.default.map(vnode => {
343
+ // return {
344
+ // componentOptions: vnode.componentOptions,
345
+ // $attrs: vnode.componentInstance.$attrs,
346
+ // constructor: vnode.componentInstance.constructor,
347
+ // $listeners: vnode.componentInstance.$listeners,
348
+ // $options: vnode.componentInstance.$options,
349
+ // $scopedSlots: vnode.componentInstance.$scopedSlots,
350
+ // $slots: vnode.componentInstance.$slots,
351
+ // staticStyle: vnode.data.staticStyle,
352
+ // ref: vnode.data.ref
353
+ // }
354
+ // });
355
+ console.log(this.$slots, 'this.$slots.default');
356
+ return;
357
+ this.initLoad = true;
358
+ await this.$nextTick();
359
+
360
+ if (this.useConfig) {
361
+
362
+ this.checkItems = this.childItems.map(item => item.$options.propsData.label);
363
+ this.sortItems = this.childItems.map(item => item.$options.propsData.label);
364
+ this.handleLayoutItem();
365
+
366
+
367
+ // 读取缓存配置
368
+ const locConfig = JSON.parse(localStorage.getItem(`SearchCfg__${this.configKey}`) || "{}");
369
+ if (locConfig.checkItems) {
370
+ await this.$nextTick();
371
+ this.checkItems = locConfig.checkItems;
372
+ this.sortItems = locConfig.sortItems;
373
+ this.handleRenderConfig();
374
+ }
375
+ } else {
376
+ this.loadSearch = false;
377
+ this.handleLayoutItem();
378
+ }
379
+
380
+ this.handleWindowResize = debounce(100, this.handleLayoutItem);
381
+
382
+ window.addEventListener('resize', this.handleWindowResize);
383
+
384
+ await sleep(300);
385
+ this.listenerSearchHeight();
386
+ },
387
+ activated() {
388
+ this.handleLayoutItem();
389
+ },
390
+ beforeDestroy() {
391
+ window.removeEventListener('resize', this.handleWindowResize);
392
+ clearInterval(this.listenerSearchTimes);
393
+ },
394
+ watch: {
395
+ childItems() {
396
+ this.loadSearch = true;
397
+ this.$nextTick().then(() => {
398
+ this.loadSearch = false;
399
+ })
400
+ },
401
+ hideItems(val, oldVal) {
402
+
403
+ if (oldVal.length == val.length && oldVal.length == 0) return;
404
+
405
+ this.loadSearch = true;
406
+ this.$nextTick().then(async () => {
407
+ this.loadSearch = false;
408
+
409
+ await this.$nextTick();
410
+ this.handleLayoutItem(true);
411
+ })
412
+ },
413
+ collspase() {
414
+ const findTableRes = this.$parent.$children.find(refItem => refItem.$options._componentTag == 'com-table');
415
+ findTableRes && findTableRes.handleRefreshHeight();
416
+ }
417
+ }
418
+ }
419
+ </script>
420
+ <style lang="less" scoped>
421
+ .ui-search {
422
+ // height: 138px;
423
+ box-sizing: border-box;
424
+ margin: 10px 10px 0 10px;
425
+ padding: 20px;
426
+ // box-shadow: 0 0 5px 2px #e7e7e7;
427
+ background-color: #FFF;
428
+ border: 1px solid @color-border;
429
+ border-radius: 4px;
430
+ box-shadow: 0 0 4px 2px #eee;
431
+ position: relative;
432
+ transition: all .1s linear;
433
+
434
+ /deep/ .el-drawer__wrapper {
435
+ position: absolute;
436
+ }
437
+
438
+ &__main {
439
+ display: flex;
440
+ }
441
+
442
+ &__footer {
443
+ display: flex;
444
+ margin-top: 10px;
445
+ align-items: center;
446
+ }
447
+
448
+ &__cache {
449
+ font-size: 12px;
450
+ // margin-left: auto;
451
+ text-overflow: ellipsis;
452
+ white-space: nowrap;
453
+ overflow: hidden;
454
+ border: 1px solid #f1f1f1;
455
+ padding: 5px;
456
+ background: #fefefe;
457
+ border-radius: 4px;
458
+ color: #666;
459
+ align-self: flex-end;
460
+ cursor: pointer;
461
+
462
+ span {
463
+ background-color: #f1f1f1;
464
+ padding: 2px 4px;
465
+ margin-left: 5px;
466
+ border-radius: 4px;
467
+
468
+ &:first-child {
469
+ margin-left: 0;
470
+ }
471
+ }
472
+ }
473
+
474
+ .ui-search__button {
475
+
476
+ &--more {
477
+ padding: 0 0 4px 0;
478
+ vertical-align: bottom;
479
+ border-bottom: 1px solid #409EFF;
480
+ border-radius: 0;
481
+ margin-right: 10px;
482
+ align-self: flex-end;
483
+ margin-bottom: 2px;
484
+ }
485
+ }
486
+
487
+ /deep/ .ui-form__item {
488
+ display: block;
489
+ min-width: 150px;
490
+
491
+ &--inputrange {
492
+ min-width: 160px;
493
+ }
494
+
495
+ &--hide {
496
+ display: none !important;
497
+ }
498
+
499
+ &--daterange {
500
+ min-width: 200px;
501
+ }
502
+ }
503
+
504
+ /deep/ .ui-item__label {
505
+ width: unset;
506
+ text-align: left;
507
+ margin-bottom: 5px;
508
+ }
509
+
510
+ /deep/ .el-cascader .el-input {
511
+ display: flex;
512
+ }
513
+
514
+ /deep/ .ui-input__range {
515
+ max-width: unset;
516
+ }
517
+
518
+ &--sort {
519
+ padding: 10px;
520
+ height: 100%;
521
+ display: flex;
522
+ flex-direction: column;
523
+ }
524
+
525
+ .ui-sort__content {
526
+
527
+ flex: 1;
528
+ margin-bottom: 10px;
529
+ border-bottom: 1px solid #f1f1f1;
530
+
531
+ .el-checkbox {
532
+ margin-right: 10px;
533
+ margin-left: 0 !important;
534
+ margin-bottom: 10px;
535
+ }
536
+ }
537
+
538
+ .ui-sort__footer {
539
+ // margin-top: auto;
540
+ }
541
+ }
542
+
543
+ .ui-more__select {
544
+
545
+ .el-col {
546
+ margin-bottom: 10px;
547
+ }
548
+
549
+ /deep/ .ui-input__range {
550
+ max-width: unset;
551
+ }
552
+
553
+ /deep/ .el-cascader .el-input {
554
+ display: flex;
555
+ }
556
+ }
557
+
558
+ .ui-dragmove {
559
+ background-color: #FFF;
560
+ }
561
+
562
+ .ui-collspase {
563
+ position: absolute;
564
+ width: 70px;
565
+ height: 20px;
566
+ text-align: center;
567
+ background-color: rgba(0,0,0,.3);
568
+ left: 50%;
569
+ margin-left: -35px;
570
+ color: #FFF;
571
+ transition: all .1s linear;
572
+ cursor: pointer;
573
+ line-height: 20px;
574
+ z-index: 2;
575
+ bottom: -20px;
576
+ border-radius: 0 0 35px 35px;
577
+
578
+ &:hover {
579
+ box-shadow: inset 0 0 10px 4px rgba(0,0,0,.4);
580
+ }
581
+
582
+ &--open {
583
+ bottom: 0;
584
+ border-radius: 35px 35px 0 0;
585
+ }
586
+
587
+ &--cache {
588
+ display: flex;
589
+ position: absolute;
590
+ top: 6px;
591
+ left: 0;
592
+ padding-left: 6px;
593
+ padding-right: 6px;
594
+ box-sizing: border-box;
595
+ width: 100%;
596
+ }
597
+ }
598
+ </style>
@@ -96,7 +96,7 @@
96
96
  ref="pageRef"
97
97
  layout="total, sizes, prev, pager, next, jumper"
98
98
  :current-page="Number(pageData.offset)"
99
- :page-sizes="pageSizes"
99
+ :page-sizes="defaultPageSizes"
100
100
  :page-size="Number(pageData.limit)"
101
101
  :total="Number(pageData.total)"
102
102
  @size-change="(val) => handlePageChange('limit', val)"
@@ -252,13 +252,16 @@ export default {
252
252
  hoverStyle: {
253
253
  type: Boolean,
254
254
  default: true
255
+ },
256
+ pageSizes: {
257
+ type: Array
255
258
  }
256
259
  },
257
260
 
258
261
  data() {
259
262
  return {
260
263
  isPresetProp,
261
- pageSizes: [20, 50, 100, 200, 500, 1000],
264
+ defaultPageSizes: [20, 50, 100, 200, 500, 1000],
262
265
  tableHeight: '',
263
266
  checkTab: '',
264
267
  useMaps: {},
@@ -397,6 +400,8 @@ export default {
397
400
  // 设置默认tab
398
401
  this.checkTab = this.defaultTab;
399
402
 
403
+ this.defaultPageSizes = this.pageSizes || this.$UICONFIG.pageSizes;
404
+
400
405
  // 默认map
401
406
  this.useMaps = JSON.parse(JSON.stringify(this.tableMap));
402
407
  },