@lx-frontend/wrap-element-ui 1.0.1-beta.1 → 1.0.1-beta.3

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,9 +1,9 @@
1
1
  {
2
2
  "name": "@lx-frontend/wrap-element-ui",
3
- "version": "1.0.1-beta.1",
3
+ "version": "1.0.1-beta.3",
4
4
  "description": "wrap-element-ui",
5
5
  "author": "",
6
- "main": "dist/index.mjs",
6
+ "main": "src/components/index.ts",
7
7
  "private": false,
8
8
  "scripts": {
9
9
  "clean": "rimraf dist",
@@ -18,7 +18,6 @@
18
18
  "lint": "eslint src"
19
19
  },
20
20
  "files": [
21
- "dist",
22
21
  "README.md",
23
22
  "package.json",
24
23
  "src/components"
@@ -180,6 +180,31 @@
180
180
  border-right: 2px #e4e8ef solid;
181
181
  }
182
182
  }
183
+
184
+ .el-table-filter,
185
+ th.el-table__cell .el-table__column-filter-trigger,
186
+ th.is-sortable .caret-wrapper {
187
+ display: none;
188
+ }
189
+
190
+ .el-table__body tr.current-row > td,
191
+ .el-table__body tr.hover-row > td {
192
+ background-color: #fafafa;
193
+ }
194
+
195
+ table tbody tr td {
196
+ & .el-date-editor.el-input {
197
+ width: 100%;
198
+ }
199
+
200
+ & .cell {
201
+ font-size: 14px;
202
+ }
203
+ }
204
+
205
+ .el-table__fixed-body-wrapper {
206
+ background: #fff;
207
+ }
183
208
  }
184
209
 
185
210
  .view-setting {
@@ -207,7 +232,7 @@
207
232
  padding: 0px;
208
233
 
209
234
  .el-dialog__body {
210
- max-height: 800px;
235
+ max-height: 70vh;
211
236
  }
212
237
 
213
238
  .el-dialog__body {
@@ -497,6 +522,12 @@
497
522
  background-color: @--theme-blue--;
498
523
  border-color: @--theme-blue--;
499
524
  }
525
+
526
+ .el-checkbox__input.is-checked .el-checkbox__inner,
527
+ .el-radio__input.is-checked .el-radio__inner {
528
+ background: #2468f2;
529
+ border-color: #2468f2;
530
+ }
500
531
  }
501
532
 
502
533
  .btn-pointer {
@@ -576,6 +607,8 @@
576
607
  margin-top: 12px;
577
608
 
578
609
  & .el-pagination {
610
+ padding: 0;
611
+
579
612
  .el-pager li.number {
580
613
  background-color: #fff;
581
614
  border: 1px solid #d6dbe3;
@@ -605,26 +638,7 @@
605
638
  }
606
639
  }
607
640
 
608
- .el-table__body tr.current-row > td,
609
- .el-table__body tr.hover-row > td {
610
- background-color: #fafafa;
611
- }
612
-
613
- .el-table-filter,
614
- th.el-table__cell .el-table__column-filter-trigger,
615
- th.is-sortable .caret-wrapper {
616
- display: none;
617
- }
618
641
 
619
- table tbody tr td {
620
- & .el-date-editor.el-input {
621
- width: 100%;
622
- }
623
-
624
- & .cell {
625
- font-size: 14px;
626
- }
627
- }
628
642
 
629
643
  .editable-table {
630
644
  & table th {
@@ -674,12 +688,6 @@ table tbody tr td {
674
688
  }
675
689
  }
676
690
 
677
- .el-select-dropdown {
678
- &__item {
679
- text-align: center;
680
- }
681
- }
682
-
683
691
  .el-dialog__header {
684
692
  display: flex;
685
693
  justify-content: space-between;
@@ -1,7 +1,10 @@
1
1
  <template>
2
2
  <div class="editable-table">
3
3
  <div class="view-setting">
4
- <div class="view-setting__btn-wrapper">
4
+ <div
5
+ v-if="!hideViewSettingBtn"
6
+ class="view-setting__btn-wrapper"
7
+ >
5
8
  <div
6
9
  class="view-setting__btn btn-pointer"
7
10
  @click="handleViewSettingShow"
@@ -17,6 +20,7 @@
17
20
  title="显示设置"
18
21
  :visible.sync="viewSettingVisible"
19
22
  width="750px"
23
+ top="12vh"
20
24
  :close-on-click-modal="false"
21
25
  :append-to-body="true"
22
26
  custom-class="view-setting__dialog"
@@ -51,8 +55,9 @@
51
55
  <div class="view-setting__content-right-frize">
52
56
  冻结前
53
57
  <el-input
54
- v-model="leftFixedColumnCount"
55
58
  class="view-setting__content-right-input"
59
+ :value="tempLeftFixedColumnCount"
60
+ @input="handleInputTempLeftFixedColumnCount"
56
61
  />
57
62
 
58
63
  </div>
@@ -218,7 +223,7 @@
218
223
  :key="column.prop + index"
219
224
  resizable
220
225
  class-name="editable-table__data-column"
221
- :filtered-value="filteredValue[column.prop] || []"
226
+ :filtered-value="Array.isArray(filteredValue[column.prop]) ? filteredValue[column.prop] : []"
222
227
  v-bind="getColumnBindProps(column)"
223
228
  >
224
229
  <template
@@ -267,7 +272,7 @@
267
272
  </div>
268
273
  </div>
269
274
  <div
270
- v-if="column.isColumnSearchAble"
275
+ v-if="column.search && !Array.isArray(column.search)"
271
276
  class="sort-filter__search"
272
277
  >
273
278
  <div class="sort-filter__search-title">
@@ -279,19 +284,41 @@
279
284
  placeholder="请输入内容"
280
285
  />
281
286
  </div>
287
+
282
288
  <div
283
- v-if="column.filters && column.filters.length > 0"
289
+ v-if="column.search && Array.isArray(column.search)"
290
+ class="sort-filter__search"
291
+ style="display: flex;flex-direction: column;gap: 12px;"
292
+ >
293
+ <div
294
+ v-for="item in column.search"
295
+ :key="item.prop"
296
+ >
297
+ <div class="sort-filter__search-title">
298
+ {{ item.label }}
299
+ </div>
300
+ <el-input
301
+ v-model="tempSearchValue[item.prop]"
302
+ class="sort-filter__search-input"
303
+ placeholder="请输入内容"
304
+ />
305
+ </div>
306
+ </div>
307
+
308
+ <div
309
+ v-if="column.filters && ((Array.isArray(column.filters) ? column.filters : column.filters.options).length > 0)"
284
310
  class="sort-filter__filter"
285
311
  >
286
312
  <div class="sort-filter__filter-title">
287
313
  筛选
288
314
  </div>
289
315
  <el-checkbox-group
316
+ v-if="column.filters && (Array.isArray(column.filters) || column.filters.type === 'checkbox')"
290
317
  v-model="tempFilteredValue[column.prop]"
291
318
  class="sort-filter__filter-checkbox-group"
292
319
  >
293
320
  <el-checkbox
294
- v-for="item in column.filters"
321
+ v-for="item in (Array.isArray(column.filters) ? column.filters : column.filters.options)"
295
322
  :key="item.value"
296
323
  :label="item.value"
297
324
  class="sort-filter__filter-checkbox"
@@ -304,6 +331,25 @@
304
331
  </slot>
305
332
  </el-checkbox>
306
333
  </el-checkbox-group>
334
+
335
+ <el-radio-group
336
+ v-if="column.filters && !Array.isArray(column.filters) && column.filters.type === 'radio'"
337
+ v-model="tempFilteredValue[column.prop]"
338
+ style="display: flex;flex-direction: column;gap: 6px;"
339
+ >
340
+ <el-radio
341
+ v-for="item in column.filters.options"
342
+ :key="item.value"
343
+ :label="item.value"
344
+ >
345
+ <slot
346
+ :name="column.prop + '-filter-item'"
347
+ v-bind="item"
348
+ >
349
+ {{ item.text }}
350
+ </slot>
351
+ </el-radio>
352
+ </el-radio-group>
307
353
  </div>
308
354
  <div
309
355
  v-if="column.summary"
@@ -339,7 +385,7 @@
339
385
  <el-button
340
386
  class="sort-filter__confirm-btn"
341
387
  type="primary"
342
- @click="handleHeaderOperationConfirm(scope)"
388
+ @click="handleHeaderOperationConfirm(column, scope)"
343
389
  >
344
390
  确定
345
391
  </el-button>
@@ -538,7 +584,7 @@
538
584
  :page-sizes="[10, 15, 30, 60, 100]"
539
585
  :page-size.sync="pageSize"
540
586
  :pager-count="11"
541
- :current-page.sync="currentPage"
587
+ :current-page="currentPage"
542
588
  :total="total"
543
589
  @size-change="handlePageSizeChange"
544
590
  @current-change="handleCurrPageChange"
@@ -565,7 +611,7 @@ interface IProps {
565
611
  dataList: ITableDataItem[];
566
612
  /** 列配置 */
567
613
  columnConfig: IColumnConfig[];
568
- /** 是否展示展开行 */
614
+ /** 是否展示展开行 */
569
615
  hasExpandRow?: boolean;
570
616
  /** 是否展示序号 */
571
617
  hasIndexColumn?: boolean;
@@ -585,6 +631,16 @@ interface IProps {
585
631
  dragSemiRange?: number;
586
632
  /** 是否显示加载 */
587
633
  loading?: boolean;
634
+ /** 是否隐藏显示设置按钮 */
635
+ hideViewSettingBtn?: boolean
636
+ /** 设置的缓存的key */
637
+ settingStorgeKey?: string
638
+ /** 前端排序,默认关闭 */
639
+ localSort?: boolean
640
+ /** 前端过滤,默认关闭 */
641
+ localFilter?: boolean
642
+ /** 页码 */
643
+ currentPage: number
588
644
  }
589
645
 
590
646
  interface IEmits {
@@ -606,6 +662,10 @@ interface IEmits {
606
662
  (e: 'row-edit-cancel', param: { row: any; page: number; size: number;}): void
607
663
  /** 页码改变 */
608
664
  (e: 'page-change', param: { page: number, size: number }): void
665
+ /** 查询 */
666
+ (e: 'search', param: Record<string, any>): void
667
+ /** 排序 */
668
+ (e: 'sort-change', param: { order: 'descending' | 'ascending' | null, prop: string }): void
609
669
  }
610
670
 
611
671
  const props = withDefaults(defineProps<IProps>(), {
@@ -620,7 +680,12 @@ const props = withDefaults(defineProps<IProps>(), {
620
680
  colorList: () => [],
621
681
  leftFixedCount: 1,
622
682
  dragSemiRange: 15,
623
- loading: false
683
+ loading: false,
684
+ hideViewSettingBtn: false,
685
+ settingStorgeKey: '',
686
+ localSort: false,
687
+ localFilter: false,
688
+ currentPage: 1,
624
689
  })
625
690
 
626
691
  // 同defineProps一样,不支持泛型参数从外部导入
@@ -640,16 +705,14 @@ const actualColumns = computed(() => {
640
705
  isColumnSortable: rawItem.sortable,
641
706
  sortable: inSorting.value ? rawItem.sortable : false
642
707
  };
643
- if (item) {
644
- if (cnt > 0) {
645
- item.fixed = 'left';
646
- // eslint-disable-next-line no-plusplus
647
- cnt--;
648
- } else {
649
- item.fixed = undefined;
650
- }
651
- res.push(item);
708
+ if (cnt > 0) {
709
+ item.fixed = 'left';
710
+ // eslint-disable-next-line no-plusplus
711
+ cnt--;
712
+ } else {
713
+ item.fixed = undefined;
652
714
  }
715
+ res.push(item);
653
716
  }
654
717
 
655
718
  // 使用默认操作项,添加默认操作列。该列在编辑模式下隐藏
@@ -675,9 +738,8 @@ const beforePageChange = () => {
675
738
  }
676
739
  const {
677
740
  pageSize,
678
- currentPage,
679
741
  handleCurrPageChange,
680
- handlePageSizeChange
742
+ handlePageSizeChange,
681
743
  } = usePagination({
682
744
  emit,
683
745
  beforePageChange
@@ -717,7 +779,7 @@ const {
717
779
  emit,
718
780
  tableDomRef,
719
781
  pageSize,
720
- currentPage,
782
+ props,
721
783
  hasExpandRow: props.hasExpandRow
722
784
  })
723
785
 
@@ -727,6 +789,8 @@ const {
727
789
  columnsToBeShown,
728
790
  viewSettingVisible,
729
791
  leftFixedColumnCount,
792
+ tempLeftFixedColumnCount,
793
+ handleInputTempLeftFixedColumnCount,
730
794
  handleViewSettingShow,
731
795
  handleViewSettingClose,
732
796
  handleViewSettingConfirm
@@ -739,6 +803,9 @@ const {
739
803
 
740
804
  /************ 列头部操作相关 ************ */
741
805
  const {
806
+ setSort,
807
+ clearSort,
808
+ setSearchParams,
742
809
  isColumnHeadActive,
743
810
  handleSort,
744
811
  handleHeaderPopoverShow,
@@ -756,11 +823,13 @@ const {
756
823
  sortingColumn,
757
824
  isColumnFiltering,
758
825
  searchValue,
759
- inSorting
826
+ inSorting,
760
827
  } = useColumnHeaderOperation({
761
828
  tableDomRef,
762
829
  sortFilterPopoverRef,
763
- props
830
+ props,
831
+ emit,
832
+ showingColumns,
764
833
  })
765
834
 
766
835
  /************ 表格行拖拽和显示设置列拖拽 ************ */
@@ -787,7 +856,6 @@ useDragSort({
787
856
  props,
788
857
  viewSettingDragSortOptions,
789
858
  beforeDragStart,
790
- currentPage,
791
859
  pageSize,
792
860
  currScope,
793
861
  tableDomRef,
@@ -798,18 +866,10 @@ const doTableLayout = async () => {
798
866
  tableDomRef.value?.doLayout();
799
867
  }
800
868
 
801
- watch(
802
- () => props.columnConfig,
803
- (val) => {
804
- showingColumns.value = val.map(c => c.prop);
805
- },
806
- { immediate: true }
807
- )
808
-
809
869
  // 过滤出自定义属性,将其它属性全部透传给 el-table-column
810
870
  const getColumnBindProps = (column: IColumnConfig) => {
811
871
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
812
- const { editAble, editType, slotName, inputType, options, ...rest } = column;
872
+ const { editAble, editType, slotName, inputType, options, filters, ...rest } = column;
813
873
  return rest;
814
874
  }
815
875
 
@@ -832,7 +892,20 @@ const handleColumnClose = (item) => {
832
892
 
833
893
  defineExpose({
834
894
  closeAllExpandedRows,
835
- elTableRef: tableDomRef
895
+ openViewSetting: handleViewSettingShow,
896
+ elTableRef: tableDomRef,
897
+ setSort,
898
+ clearSort,
899
+ setSearchParams,
900
+ })
901
+
902
+ // loading 结束和页码变化时滚动到顶部
903
+ watch([
904
+ () => props.loading,
905
+ () => props.currentPage,
906
+ ], ([loading]) => {
907
+ if (loading) return;
908
+ tableDomRef.value.$el.querySelector('.el-table__body-wrapper').scrollTop = 0
836
909
  })
837
910
 
838
911
  </script>
@@ -11,24 +11,40 @@ export interface IColumnConfigRequired {
11
11
  sortable?: boolean; // 该列是否允许排序,ture则表头弹窗会显示升降序按钮
12
12
  slotName?: string; // 如果要自定义,传入 slotName
13
13
  isAlwaysShow?: boolean; // 不可隐藏,显示设置中,该列不允许隐藏
14
- isColumnSearchAble?: boolean; // 列是否允许搜索,true则表头弹窗会多一个搜索框
14
+ /** 默认隐藏,显示设置中,该列默认隐藏 */
15
+ defaultHide?: boolean;
16
+ /** 列是否允许搜索,true则表头弹窗会多一个搜索框,一列中有多个搜索字段时传数组进行配置 */
17
+ search?: boolean | ISearchOptions
15
18
  summary?: boolean; // 是否可以显示该列的统计
16
19
  summaryMethod?: (values: any[]) => string | number; // 这一列的统计方法,values为该列的所有值
17
- // filters?: {value: string | number; text: string; [key: string]: any}[];
20
+ /** 过滤,传数组时默认复选框 */
21
+ filters?: {
22
+ type?: 'checkbox' | 'radio',
23
+ options: FiltersOption[]
24
+ default?: string | number | string[] | number[]
25
+ } | FiltersOption[]
18
26
  // 透传el-table column有的属性, https://element.eleme.cn/#/en-US/component/table#table-column-attributes
19
27
  [key: string]: any;
20
28
  }
21
29
 
30
+ type FiltersOption = { value: string | number; text: string; [key: string]: any }
31
+
32
+ type ISearchOptions = {
33
+ prop: string,
34
+ label: string,
35
+ validator?: (value: string) => boolean
36
+ }[]
37
+
22
38
  type IInputColumn = IColumnConfigRequired & {
23
39
  inputType: string | number;
24
40
  }
25
41
 
26
42
  type ISelectColumn = IColumnConfigRequired & {
27
- options: {key: string; value: string | number; [key: string]: any}[];
43
+ options: { key: string; value: string | number; [key: string]: any }[];
28
44
  }
29
45
 
30
- type IDateOnlyColumn = IColumnConfigRequired & {}
31
- type IDateTimeColumn = IColumnConfigRequired & {}
46
+ type IDateOnlyColumn = IColumnConfigRequired
47
+ type IDateTimeColumn = IColumnConfigRequired
32
48
 
33
49
  export type IColumnConfig = IInputColumn | ISelectColumn | IDateOnlyColumn | IDateTimeColumn
34
50
 
@@ -79,16 +95,22 @@ export interface IProps {
79
95
  leftFixedCount?: number;
80
96
  dragSemiRange?: number;
81
97
  loading?: boolean;
98
+ settingStorgeKey?: string
99
+ localSort?: boolean
100
+ localFilter?: boolean
101
+ currentPage: number
82
102
  }
83
103
 
84
104
  export interface IEmits {
85
105
  (e: 'selection-change', selection: any): void
86
- (e: 'row-bg-change', param: {colorId: number; row: ITableDataItem; rowIndex: number}): void
87
- (e: 'row-drag-drop', param: { row: any; fromIndex: number; toIndex: number; page: number; size: number;}): void
106
+ (e: 'row-bg-change', param: { colorId: number; row: ITableDataItem; rowIndex: number }): void
107
+ (e: 'row-drag-drop', param: { row: any; fromIndex: number; toIndex: number; page: number; size: number; }): void
88
108
  (e: 'row-delete', param: { row: any; index: number; page: number; size: number; }): void
89
- (e: 'row-edit', param: { row: any, index: number; page: number; size: number;}): void
90
- (e: 'row-pin-to-top', param: { row: any, rawIndex: number; page: number; size: number;}): void
109
+ (e: 'row-edit', param: { row: any, index: number; page: number; size: number; }): void
110
+ (e: 'row-pin-to-top', param: { row: any, rawIndex: number; page: number; size: number; }): void
91
111
  (e: 'row-edit-save', param: { page: number; size: number; row: any; changedData: Record<string, any>; }): void
92
- (e: 'row-edit-cancel', param: { row: any; page: number; size: number;}): void
112
+ (e: 'row-edit-cancel', param: { row: any; page: number; size: number; }): void
93
113
  (e: 'page-change', param: { page: number, size: number }): void
114
+ (e: 'search', param: Record<string, any>): void
115
+ (e: 'sort-change', param: { order: 'descending' | 'ascending' | null, prop: string }): void
94
116
  }
@@ -1,13 +1,15 @@
1
- import { computed, ref, watch, nextTick } from "vue"
2
- import { IColumnConfig, IProps } from './types';
1
+ import { computed, ref, watch, nextTick, Ref } from "vue"
2
+ import { IColumnConfig, IEmits, IProps } from './types';
3
3
 
4
4
  interface IUseColumnHeaderOperationParams {
5
5
  props: IProps
6
6
  tableDomRef: any
7
7
  sortFilterPopoverRef: any
8
+ emit: IEmits;
9
+ showingColumns: Ref<string[]>
8
10
  }
9
11
 
10
- export default function useColumnHeaderOperation({props, tableDomRef, sortFilterPopoverRef}: IUseColumnHeaderOperationParams) {
12
+ export default function useColumnHeaderOperation({ props, tableDomRef, sortFilterPopoverRef, emit, showingColumns }: IUseColumnHeaderOperationParams) {
11
13
 
12
14
  // column如果有sortable属性,点击列头部,会直接触发排序,为了在弹窗点确定时再触发排序,需要阻止点击立即排序
13
15
  // 所以,初始渲染时,将sortable设置为false,在触发排序逻辑时再设置成真实的值,再利用el-table自身的排序逻辑触发排序
@@ -22,8 +24,8 @@ export default function useColumnHeaderOperation({props, tableDomRef, sortFilter
22
24
  const tempSortingColumn = ref<IColumnConfig | null>(null);
23
25
 
24
26
  // 生效中的过滤配置 和 临时过滤配置
25
- const filteredValue = ref<Record<string, string[]>>({});
26
- const tempFilteredValue = ref<Record<string, string[]>>({});
27
+ const filteredValue = ref<Record<string, string | number | number[] | string[]>>({});
28
+ const tempFilteredValue = ref<Record<string, string | number | number[] | string[]>>({});
27
29
 
28
30
  // 生效中的统计配置 和 临时统计配置
29
31
  const tempSummaryList = ref<string[]>([]);
@@ -33,14 +35,17 @@ export default function useColumnHeaderOperation({props, tableDomRef, sortFilter
33
35
  const searchValue = ref<Record<string, string>>({});
34
36
  const tempSearchValue = ref<Record<string, string>>({});
35
37
 
36
- const isColumnFiltering = computed(() => Object.keys(tempFilteredValue.value).some(k => tempFilteredValue.value[k]?.length));
38
+ const isColumnFiltering = computed(() => Object.keys(tempFilteredValue.value).some(k => {
39
+ if (!Array.isArray(tempFilteredValue.value[k])) return tempFilteredValue.value[k]
40
+ return tempFilteredValue.value[k]?.length;
41
+ }));
37
42
 
38
- const showColumnHeadSortIcon = (column: IColumnConfig) => column.filters || column.isColumnSortable || column.isColumnSearchAble || column.summary;
43
+ const showColumnHeadSortIcon = (column: IColumnConfig) => column.filters || column.isColumnSortable || column.search || column.summary;
39
44
 
40
45
  watch(
41
46
  () => props.columnConfig,
42
47
  (val) => {
43
- filteredValue.value = val.reduce((prev, curr) => ({...prev, [curr.prop]: []}), {});
48
+ filteredValue.value = val.reduce((prev, curr) => ({ ...prev, [curr.prop]: [] }), {});
44
49
  tempFilteredValue.value = { ...filteredValue.value };
45
50
  },
46
51
  { immediate: true }
@@ -63,14 +68,24 @@ export default function useColumnHeaderOperation({props, tableDomRef, sortFilter
63
68
  sums[index] = summaryMethod(values);
64
69
  }
65
70
  })
66
-
71
+
67
72
  return sums
68
73
  }
69
74
 
70
75
  const isColumnHeadActive = (column: IColumnConfig) => {
71
- return filteredValue.value[column.prop]?.length ||
76
+ return (
77
+ column.filters && (Array.isArray(column.filters)
78
+ ? (filteredValue.value[column.prop] as any[]).length
79
+ : column.filters.type === 'radio'
80
+ ? filteredValue.value[column.prop]
81
+ : (filteredValue.value[column.prop] as any[]).length)
82
+ ) ||
83
+ (
84
+ column.search
85
+ ? Array.isArray(column.search) && column.search?.some(v => searchValue.value[v.prop])
86
+ : searchValue.value[column.prop]
87
+ ) ||
72
88
  sortingColumn.value?.prop === column.prop ||
73
- searchValue.value[column.prop] ||
74
89
  summaryList.value.includes(column.prop);
75
90
  }
76
91
 
@@ -82,7 +97,7 @@ export default function useColumnHeaderOperation({props, tableDomRef, sortFilter
82
97
  tempSortType.value = sortType.value;
83
98
  tempSortingColumn.value = sortingColumn.value ? { ...sortingColumn.value } as IColumnConfig : null;
84
99
  // 临时合计项设置成实际的合计项
85
- tempSummaryList.value = [ ...summaryList.value ];
100
+ tempSummaryList.value = [...summaryList.value];
86
101
  }
87
102
 
88
103
  const closeSortAndFilterPopover = (exceptProp?: string) => {
@@ -98,21 +113,81 @@ export default function useColumnHeaderOperation({props, tableDomRef, sortFilter
98
113
  tempSortingColumn.value = column;
99
114
  }
100
115
 
101
- const handleHeaderOperationConfirm = async (scope) => {
102
- summaryList.value = [ ...tempSummaryList.value ];
103
- sortingColumn.value = tempSortingColumn.value ? {...tempSortingColumn.value} : null;
116
+ const columnMap = computed(() => {
117
+ const obj: Record<string, IColumnConfig> = {}
118
+ props.columnConfig.forEach(column => {
119
+ obj[column.prop] = column
120
+ })
121
+ return obj
122
+ })
123
+
124
+ const emitSearch = () => {
125
+ const params: Record<string, any> = {};
126
+ // 仅提交显示的列的相关数据
127
+ showingColumns.value.forEach(prop => {
128
+ const column = columnMap.value[prop]
129
+ if (column.filters) {
130
+ params[prop] = filteredValue.value[prop]
131
+ }
132
+ if (column.search) {
133
+ if (Array.isArray(column.search)) {
134
+ column.search.forEach(v => {
135
+ params[v.prop] = searchValue.value[v.prop]
136
+ })
137
+ } else {
138
+ params[prop] = searchValue.value[prop]
139
+ }
140
+ }
141
+ })
142
+
143
+ Object.keys(params).forEach(key => {
144
+ if (params[key] === undefined) delete params[key]
145
+ })
146
+
147
+ emit('search', params);
148
+ };
149
+
150
+ const handleHeaderOperationConfirm = async (column: IColumnConfig, scope) => {
151
+ if (column.search) {
152
+ // 校验
153
+ if (Array.isArray(column.search)) {
154
+ let validate = true;
155
+ column.search.forEach(v => {
156
+ if (!tempSearchValue.value[v.prop]) tempSearchValue.value[v.prop] = ''
157
+ if (!validate) return
158
+ if (v.validator) {
159
+ const result = v.validator(tempSearchValue.value[v.prop]);
160
+ if (validate && !result) validate = false;
161
+ }
162
+ })
163
+ // 校验未通过
164
+ if (!validate) return
165
+ } else {
166
+ if (!tempSearchValue.value[column.prop]) tempSearchValue.value[column.prop] = ''
167
+ }
168
+ }
169
+
170
+ summaryList.value = [...tempSummaryList.value];
171
+ sortingColumn.value = tempSortingColumn.value ? { ...tempSortingColumn.value } : null;
104
172
  sortType.value = tempSortType.value;
105
- if (sortingColumn.value) {
106
- // 恢复列配置的sortable属性,只有列配置的sortable为true,才能用下面的sort方法
107
- inSorting.value = true;
108
- await nextTick();
109
- tableDomRef.value?.sort(sortingColumn.value.prop, sortType.value);
110
- inSorting.value = false
173
+
174
+ if (sortingColumn.value) { // 确认时提交排序
175
+ if (props.localSort) {
176
+ // 恢复列配置的sortable属性,只有列配置的sortable为true,才能用下面的sort方法
177
+ inSorting.value = true;
178
+ await nextTick();
179
+ tableDomRef.value?.sort(sortingColumn.value.prop, sortType.value);
180
+ inSorting.value = false
181
+ } else {
182
+ emit('sort-change', { order: sortType.value, prop: sortingColumn.value.prop });
183
+ }
111
184
  }
112
185
 
113
186
  filteredValue.value = { ...tempFilteredValue.value };
114
187
  searchValue.value = { ...tempSearchValue.value };
115
188
 
189
+ emitSearch();
190
+
116
191
  filterColumns(scope.store);
117
192
 
118
193
  closeSortAndFilterPopover();
@@ -120,18 +195,52 @@ export default function useColumnHeaderOperation({props, tableDomRef, sortFilter
120
195
  tableDomRef.value?.doLayout();
121
196
  }
122
197
 
123
- const handleHeaderOperationReset = async (column, scope) => {
124
- if (sortingColumn.value && sortingColumn.value.prop === column.prop) {
198
+ const clearSort = () => {
199
+ sortingColumn.value = null;
200
+ sortType.value = null;
201
+ if (props.localSort) { // 前端过滤
125
202
  tableDomRef.value?.clearSort();
126
- sortingColumn.value = null;
127
- sortType.value = null;
203
+ } else { // 接口过滤
204
+ emit('sort-change', { order: null, prop: '' });
205
+ }
206
+ }
207
+
208
+ const setSort = (params: { order: 'ascending' | 'descending', prop: string }) => {
209
+ const column = props.columnConfig.find(c => c.prop === params.prop);
210
+ if (column) {
211
+ sortingColumn.value = column;
212
+ sortType.value = params.order;
213
+ if (props.localSort) {
214
+ tableDomRef.value?.sort(params.prop, params.order);
215
+ }
216
+ }
217
+ }
218
+
219
+ const handleHeaderOperationReset = async (column: IColumnConfig, scope) => {
220
+ if (sortingColumn.value && sortingColumn.value.prop === column.prop) {
221
+ clearSort();
128
222
  }
129
223
 
130
224
  // 合计
131
225
  summaryList.value = summaryList.value.filter(item => item !== column.prop);
132
226
 
133
- filteredValue.value[column.prop] = [];
134
- searchValue.value[column.prop] = '';
227
+ if (column.filters) {
228
+ filteredValue.value[column.prop] = Array.isArray(column.filters)
229
+ ? []
230
+ : column.filters.default ?? []
231
+ }
232
+ if (column.search) {
233
+ if (!Array.isArray(column.search)) {
234
+ searchValue.value[column.prop] = '';
235
+ } else {
236
+ column.search.forEach(v => {
237
+ searchValue.value[v.prop] = '';
238
+ })
239
+ }
240
+ }
241
+
242
+ emitSearch();
243
+
135
244
  filterColumns(scope.store);
136
245
 
137
246
  closeSortAndFilterPopover();
@@ -140,6 +249,7 @@ export default function useColumnHeaderOperation({props, tableDomRef, sortFilter
140
249
  }
141
250
 
142
251
  const filterColumns = (store) => {
252
+ if (!props.localFilter) return
143
253
  store.states.columns.forEach(column => {
144
254
  if (filteredValue.value[column.property]) {
145
255
  store.commit('filterChange', {
@@ -165,7 +275,35 @@ export default function useColumnHeaderOperation({props, tableDomRef, sortFilter
165
275
  store.states.data = data;
166
276
  }
167
277
 
278
+ const setSearchParams = (params: Record<string, any>) => {
279
+ const _searchValue = {};
280
+ const _filteredValue = {};
281
+
282
+ // 设置搜索和过滤参数时,如果使用 showingColumns 遍历,会导致通过外部设置未显示的列的搜索和过滤参数丢失
283
+ props.columnConfig.forEach(column => {
284
+ if (column.search) {
285
+ if (Array.isArray(column.search)) {
286
+ column.search.forEach(v => {
287
+ _searchValue[v.prop] = params[v.prop];
288
+ });
289
+ } else {
290
+ _searchValue[column.prop] = params[column.prop] ?? '';
291
+ }
292
+ }
293
+ if (column.filters) {
294
+ const value = params[column.prop] ?? (Array.isArray(column.filters) ? [] : column.filters.default);
295
+ _filteredValue[column.prop] = value;
296
+ }
297
+ })
298
+
299
+ searchValue.value = { ...searchValue.value, ..._searchValue }
300
+ filteredValue.value = { ...filteredValue.value, ..._filteredValue }
301
+ }
302
+
168
303
  return {
304
+ setSort,
305
+ clearSort,
306
+ setSearchParams,
169
307
  isColumnHeadActive,
170
308
  handleHeaderPopoverShow,
171
309
  handleSort,
@@ -183,6 +321,6 @@ export default function useColumnHeaderOperation({props, tableDomRef, sortFilter
183
321
  sortingColumn,
184
322
  isColumnFiltering,
185
323
  searchValue,
186
- inSorting
324
+ inSorting,
187
325
  }
188
326
  }
@@ -1,15 +1,15 @@
1
1
  import { Ref, ref } from "vue"
2
- import { IEmits } from "./types"
2
+ import { IEmits, IProps } from "./types"
3
3
 
4
4
  interface IParams {
5
5
  emit: IEmits;
6
6
  pageSize: Ref<number>;
7
- currentPage: Ref<number>;
7
+ props: IProps
8
8
  tableDomRef: Ref<any>;
9
9
  hasExpandRow: boolean
10
10
  }
11
11
 
12
- export default function useDefaultOperation({emit, pageSize, currentPage, tableDomRef, hasExpandRow}: IParams) {
12
+ export default function useDefaultOperation({ emit, pageSize, props, tableDomRef, hasExpandRow }: IParams) {
13
13
  const operationPopoverRef = ref<any>(null);
14
14
  const editingRowData = ref<Record<string, any>>({});
15
15
  const editingRowIndex = ref<number>(-1);
@@ -18,7 +18,7 @@ export default function useDefaultOperation({emit, pageSize, currentPage, tableD
18
18
  emit('row-delete', {
19
19
  row,
20
20
  index,
21
- page: currentPage.value,
21
+ page: props.currentPage,
22
22
  size: pageSize.value
23
23
  })
24
24
  closeOperationPopover();
@@ -39,9 +39,9 @@ export default function useDefaultOperation({emit, pageSize, currentPage, tableD
39
39
  // 折叠所有展开的行
40
40
  closeAllExpandedRows();
41
41
  const { row, $index: index } = scope;
42
- editingRowData.value = {...row};
42
+ editingRowData.value = { ...row };
43
43
  editingRowIndex.value = index;
44
- emit('row-edit', { row, index, page: currentPage.value, size: pageSize.value});
44
+ emit('row-edit', { row, index, page: props.currentPage, size: pageSize.value });
45
45
  closeOperationPopover();
46
46
  }
47
47
 
@@ -52,9 +52,9 @@ export default function useDefaultOperation({emit, pageSize, currentPage, tableD
52
52
  ...dataList.slice(0, index),
53
53
  ...dataList.slice(index + 1)
54
54
  ];
55
- newList.unshift({...row, isPinned: true});
55
+ newList.unshift({ ...row, isPinned: true });
56
56
  store.states.data = newList;
57
- emit('row-pin-to-top', { row, rawIndex: index, page: currentPage.value, size: pageSize.value});
57
+ emit('row-pin-to-top', { row, rawIndex: index, page: props.currentPage, size: pageSize.value });
58
58
  closeOperationPopover();
59
59
  }
60
60
 
@@ -68,7 +68,7 @@ export default function useDefaultOperation({emit, pageSize, currentPage, tableD
68
68
  }
69
69
 
70
70
  emit('row-edit-save', {
71
- page: currentPage.value,
71
+ page: props.currentPage,
72
72
  size: pageSize.value,
73
73
  row,
74
74
  changedData
@@ -79,7 +79,7 @@ export default function useDefaultOperation({emit, pageSize, currentPage, tableD
79
79
  const handleEditCancel = (row) => {
80
80
  editingRowIndex.value = -1;
81
81
  editingRowData.value = {};
82
- emit('row-edit-cancel', { row, page: currentPage.value, size: pageSize.value});
82
+ emit('row-edit-cancel', { row, page: props.currentPage, size: pageSize.value });
83
83
  }
84
84
 
85
85
  return {
@@ -8,11 +8,10 @@ interface IUseDragSortParams {
8
8
  viewSettingDragSortOptions: Ref<IColumnConfig[]>
9
9
  beforeDragStart: () => boolean
10
10
  currScope: Ref<any>
11
- currentPage: Ref<number>
12
11
  pageSize: Ref<number>
13
12
  tableDomRef: Ref<any>
14
13
  }
15
- export default function useDragSort({props, emit, viewSettingDragSortOptions, currentPage, pageSize, beforeDragStart, currScope, tableDomRef }: IUseDragSortParams) {
14
+ export default function useDragSort({ props, emit, viewSettingDragSortOptions, pageSize, beforeDragStart, currScope, tableDomRef }: IUseDragSortParams) {
16
15
 
17
16
  const draggingData = ref<IDraggingData>({}); // 拖拽相关数据
18
17
  const isMouseDown = ref(false);
@@ -21,7 +20,7 @@ export default function useDragSort({props, emit, viewSettingDragSortOptions, cu
21
20
  const isOperating = ref(false);
22
21
 
23
22
  onMounted(() => {
24
- tableDomRef.value.$el.addEventListener('mousedown', () => {isOperating.value = true});
23
+ tableDomRef.value.$el.addEventListener('mousedown', () => { isOperating.value = true });
25
24
  document.addEventListener('mousedown', handleDocumentMouseDown);
26
25
  document.addEventListener('mousemove', handleDocumentMouseMove);
27
26
  document.addEventListener('mouseup', handleDocumentMouseUp);
@@ -201,7 +200,7 @@ export default function useDragSort({props, emit, viewSettingDragSortOptions, cu
201
200
  row: movedRow,
202
201
  fromIndex: draggingIndex,
203
202
  toIndex: dropIndex,
204
- page: currentPage.value,
203
+ page: props.currentPage,
205
204
  size: pageSize.value
206
205
  });
207
206
  // 清理工作
@@ -210,7 +209,7 @@ export default function useDragSort({props, emit, viewSettingDragSortOptions, cu
210
209
 
211
210
  const handleViewSettingDragMouseDown = (event, index) => {
212
211
  const rowDoms = [...document.getElementsByClassName('view-setting-draggable-item')]
213
- .reduce((pre, item, index) => ({...pre, [index]: [item]}), {});
212
+ .reduce((pre, item, index) => ({ ...pre, [index]: [item] }), {});
214
213
  draggingData.value.isDragging = true;
215
214
  draggingData.value.rowDoms = rowDoms;
216
215
  draggingData.value.draggingIndex = +index;
@@ -6,29 +6,26 @@ interface IParams {
6
6
  beforePageChange: () => void
7
7
  }
8
8
 
9
- export default function usePagination({emit, beforePageChange}: IParams) {
9
+ export default function usePagination({ emit, beforePageChange }: IParams) {
10
10
 
11
11
  const pageSize = ref(10);
12
- const currentPage = ref(1);
13
12
 
14
13
  const handlePageSizeChange = (size: number) => {
15
14
  pageSize.value = size;
16
- currentPage.value = 1;
17
15
  // searchValue.value = {};
18
16
  beforePageChange();
19
- emit('page-change', {size, page: currentPage.value});
17
+ emit('page-change', { size, page: 1 });
20
18
  }
21
19
 
22
20
  const handleCurrPageChange = (curr: number) => {
23
21
  // searchValue.value = {};
24
22
  beforePageChange();
25
- emit('page-change', {size: pageSize.value, page: curr});
23
+ emit('page-change', { size: pageSize.value, page: curr });
26
24
  }
27
25
 
28
26
  return {
29
27
  pageSize,
30
- currentPage,
31
28
  handlePageSizeChange,
32
- handleCurrPageChange
29
+ handleCurrPageChange,
33
30
  }
34
31
  }
@@ -6,7 +6,7 @@ interface IUseRowBgColorParams {
6
6
  emit: IEmits;
7
7
  }
8
8
 
9
- export default function useRowBgColor({colorList, emit}: IUseRowBgColorParams) {
9
+ export default function useRowBgColor({ colorList, emit }: IUseRowBgColorParams) {
10
10
  const colorPopoverRef = ref<any>(null);
11
11
 
12
12
  const isDefaultColor = (id: number) => {
@@ -31,11 +31,11 @@ export default function useRowBgColor({colorList, emit}: IUseRowBgColorParams) {
31
31
  const handleColorChange = async (colorId: number, scope) => {
32
32
  const { row, $index: rowIndex, store } = scope;
33
33
  const dataList = store.states.data;
34
- const curRow = {...dataList[rowIndex], colorId: +colorId};
34
+ const curRow = { ...dataList[rowIndex], colorId: +colorId };
35
35
  const newList = [...dataList];
36
36
  newList.splice(rowIndex, 1, curRow);
37
37
  store.states.data = newList;
38
- emit('row-bg-change', {colorId, row, rowIndex});
38
+ emit('row-bg-change', { colorId, row, rowIndex });
39
39
  await nextTick();
40
40
  // TODO: 为什么不是数组?为什么关闭弹窗不生效了?
41
41
  colorPopoverRef.value?.doClose();
@@ -1,4 +1,4 @@
1
- import { ref, nextTick, watch, ComputedRef, Ref, onMounted } from "vue"
1
+ import { ref, nextTick, watch, ComputedRef, Ref, onMounted, computed } from "vue"
2
2
  import { IColumnConfig, IProps } from "./types"
3
3
 
4
4
  interface IViewSettingParams {
@@ -13,12 +13,53 @@ export default function useViewSetting({ tableDomRef, showingColumns, actualColu
13
13
  const columnsToBeShown = ref<string[]>([]); // 显示设置弹窗中勾选的列
14
14
  const viewSettingVisible = ref(false);
15
15
  const leftFixedColumnCount = ref(0);
16
+ const tempLeftFixedColumnCount = ref(0);
17
+
18
+ const storageKey = computed(() => `@lx-frontend/wrap-element-ui/table_setting_cloumns/${props.settingStorgeKey || (location.pathname === '/' ? location.hash : location.pathname)}`);
19
+
20
+ const saveSettingToStorge = () => localStorage.setItem(storageKey.value, JSON.stringify({
21
+ showingColumns: showingColumns.value,
22
+ leftFixedColumnCount: leftFixedColumnCount.value
23
+ }));
24
+
25
+ watch(
26
+ () => props.columnConfig,
27
+ (val) => {
28
+ const _keys = new Set(props.columnConfig.map(c => (c.prop)));
29
+ const _cache = localStorage.getItem(storageKey.value);
30
+ const setColumns = () => (showingColumns.value = val.filter(v => !v.defaultHide).map(c => c.prop));
31
+ if (!_cache) {
32
+ setColumns();
33
+ leftFixedColumnCount.value = props.leftFixedCount as number;
34
+ } else {
35
+ try {
36
+ // 缓存数据字段可能随着更新导致对不上,清理无效数据,防止出问题
37
+ const cache = JSON.parse(_cache);
38
+ if (!cache.showingColumns || !Array.isArray(cache.showingColumns)) {
39
+ setColumns();
40
+ } else {
41
+ showingColumns.value = cache.showingColumns.filter(key => _keys.has(key));
42
+ }
43
+ const _leftFixedColumnCount = Number(cache?.leftFixedColumnCount)
44
+ leftFixedColumnCount.value = isNaN(_leftFixedColumnCount) ? (props.leftFixedCount as number) : _leftFixedColumnCount;
45
+ // 写入清理后的数据
46
+ saveSettingToStorge();
47
+ } catch (error) {
48
+ console.error(error);
49
+ localStorage.removeItem(storageKey.value);
50
+ setColumns();
51
+ }
52
+ }
53
+ },
54
+ { immediate: true }
55
+ )
16
56
 
17
57
  watch(
18
58
  () => columnsToBeShown.value,
19
59
  (val) => {
20
60
  viewSettingDragSortOptions.value = props.columnConfig
21
61
  .filter(c => val.includes(c.prop));
62
+ if (tempLeftFixedColumnCount.value > val.length) tempLeftFixedColumnCount.value = val.length
22
63
  },
23
64
  { immediate: true }
24
65
  )
@@ -39,6 +80,7 @@ export default function useViewSetting({ tableDomRef, showingColumns, actualColu
39
80
  const handleViewSettingShow = () => {
40
81
  viewSettingDragSortOptions.value = actualColumns.value
41
82
  .filter(c => columnsToBeShown.value.includes(c.prop));
83
+ tempLeftFixedColumnCount.value = leftFixedColumnCount.value;
42
84
  viewSettingVisible.value = true;
43
85
  }
44
86
 
@@ -51,15 +93,25 @@ export default function useViewSetting({ tableDomRef, showingColumns, actualColu
51
93
  const handleViewSettingConfirm = async () => {
52
94
  viewSettingVisible.value = false;
53
95
  showingColumns.value = viewSettingDragSortOptions.value.map(c => c.prop);
96
+ leftFixedColumnCount.value = tempLeftFixedColumnCount.value;
97
+ saveSettingToStorge()
54
98
  await nextTick();
55
99
  tableDomRef.value?.doLayout();
56
100
  }
57
101
 
102
+ const handleInputTempLeftFixedColumnCount = (value: string) => {
103
+ const _value = Number(value)
104
+ if (isNaN(_value)) return
105
+ tempLeftFixedColumnCount.value = Math.max(0, Math.min(columnsToBeShown.value.length, Math.floor(_value)))
106
+ }
107
+
58
108
  return {
59
109
  viewSettingDragSortOptions,
60
110
  columnsToBeShown,
61
111
  viewSettingVisible,
62
112
  leftFixedColumnCount,
113
+ tempLeftFixedColumnCount,
114
+ handleInputTempLeftFixedColumnCount,
63
115
  handleViewSettingShow,
64
116
  handleViewSettingClose,
65
117
  handleViewSettingConfirm