@lx-frontend/wrap-element-ui 1.0.14 → 1.0.15-beta.0

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": "@lx-frontend/wrap-element-ui",
3
- "version": "1.0.14",
3
+ "version": "1.0.15-beta.0",
4
4
  "description": "wrap-element-ui",
5
5
  "author": "",
6
6
  "main": "src/components/index.ts",
@@ -23,6 +23,7 @@
23
23
  "src/components"
24
24
  ],
25
25
  "peerDependencies": {
26
+ "dayjs": "^1.11.13",
26
27
  "element-ui": "^2.15.14",
27
28
  "lodash": "^4.17.21",
28
29
  "vue": "~2.7.16"
@@ -51,6 +52,7 @@
51
52
  "ali-oss": "^6.20.0",
52
53
  "autoprefixer": "^10.4.19",
53
54
  "cross-env": "^7.0.3",
55
+ "dayjs": "^1.11.13",
54
56
  "eslint": "^8.57.0",
55
57
  "eslint-plugin-vue": "^9.27.0",
56
58
  "gulp": "^4.0.2",
@@ -1,5 +1,11 @@
1
1
  import { computed, nextTick, ref, Ref, watch } from 'vue'
2
- import { IColumnConfig, IEmits, IProps } from '../types';
2
+ import {
3
+ FilterListType,
4
+ IColumnConfig,
5
+ IEmits,
6
+ IFilterInput,
7
+ IProps
8
+ } from '../types';
3
9
 
4
10
  interface IUseColumnHeaderOperationParams {
5
11
  props: IProps
@@ -9,7 +15,6 @@ interface IUseColumnHeaderOperationParams {
9
15
  }
10
16
 
11
17
  export function useColumnHeaderOperation({ props, tableDomRef, emit, showingColumns }: IUseColumnHeaderOperationParams) {
12
-
13
18
  // column如果有sortable属性,点击列头部,会直接触发排序,为了在弹窗点确定时再触发排序,需要阻止点击立即排序
14
19
  // 所以,初始渲染时,将sortable设置为false,在触发排序逻辑时再设置成真实的值,再利用el-table自身的排序逻辑触发排序
15
20
  const inSorting = ref(false);
@@ -30,17 +35,19 @@ export function useColumnHeaderOperation({ props, tableDomRef, emit, showingColu
30
35
  const tempSummaryList = ref<string[]>([]);
31
36
  const summaryList = ref<string[]>([]);
32
37
 
33
- // 生效中的搜索配置 临时搜索配置
34
- const searchValue = ref<Record<string, string>>({});
35
- const tempSearchValue = ref<Record<string, string>>({});
36
-
37
- const isColumnFiltering = computed(() => Object.keys(tempFilteredValue.value).some(k => {
38
- const value = tempFilteredValue.value[k]
39
- if (!Array.isArray(value)) return value
40
- return value.length;
41
- }));
38
+ const isColumnFiltering = computed(() => {
39
+ return Object.keys(tempFilteredValue.value).some(
40
+ (key) => {
41
+ const value = tempFilteredValue.value[key]
42
+ if (Array.isArray(value)) return value.length
43
+ return value;
44
+ }
45
+ )
46
+ });
42
47
 
43
- const showColumnHeadSortIcon = (column: IColumnConfig) => column.filters || column.isColumnSortable || column.search || column.summary || column.doubleDatePicker;
48
+ const showColumnHeadSortIcon = ({ isColumnSortable, filters }: IColumnConfig) => {
49
+ return isColumnSortable || (filters && Array.isArray(filters) && filters.length > 0)
50
+ }
44
51
 
45
52
  watch(
46
53
  () => props.columnConfig,
@@ -72,41 +79,34 @@ export function useColumnHeaderOperation({ props, tableDomRef, emit, showingColu
72
79
  return sums
73
80
  }
74
81
 
75
- const isColumnHeadActive = (column: IColumnConfig) => {
76
- const hasPickerParams = !!(
77
- column.doubleDatePicker
78
- && (searchValue.value[column.doubleDatePicker.props[0]] || searchValue.value[column.doubleDatePicker.props[1]])
82
+ const isColumnHeadActive = ({ prop, filters, _sortable }: IColumnConfig) => {
83
+ const hasFilters = filters && Array.isArray(filters) && filters.length > 0
84
+ const currentFilterActive = hasFilters && filters?.some(
85
+ (item) => {
86
+ if (item.type === 'doubleDatePicker' || item.type === 'monthDayPicker') {
87
+ const [start, end] = item.prop
88
+ return !!(filteredValue.value[start] || filteredValue.value[end])
89
+ }
90
+
91
+ if (item.type === 'checkbox') {
92
+ return !!(filteredValue.value[item.prop] as any[]).length
93
+ }
94
+
95
+ return !!filteredValue.value[item.prop]
96
+ }
79
97
  )
80
98
 
81
- const isUseFilter = !!(column.filters && (Array.isArray(column.filters)
82
- ? (filteredValue.value[column.prop] as any[]).length
83
- : column.filters.type === 'radio'
84
- ? filteredValue.value[column.filters.prop || column.prop]
85
- : (filteredValue.value[column.filters.prop || column.prop] as any[]).length))
86
-
87
- const isUseSort = Array.isArray(column._sortable)
88
- ? column._sortable.some(v => v.prop === sortProp.value)
89
- : sortProp.value === column.prop
90
-
91
- const isUseSearch = Array.isArray(column.search)
92
- ? column.search?.some(v => {
93
- const props = typeof v.prop === 'string' ? [v.prop] : v.prop
94
- return props.some(p => searchValue.value[p])
95
- })
96
- : !!searchValue.value[column.prop]
97
-
98
- return isUseFilter
99
- || isUseSearch
100
- || hasPickerParams
101
- || isUseSort
102
- || summaryList.value.includes(column.prop);
99
+ const isUseSort = Array.isArray(_sortable)
100
+ ? _sortable.some(v => v.prop === sortProp.value)
101
+ : sortProp.value === prop
102
+
103
+ return currentFilterActive || isUseSort|| summaryList.value.includes(prop);
103
104
  }
104
105
 
105
106
  const handleHeaderPopoverShow = (column: IColumnConfig) => {
106
107
  // 关闭其他的排序和筛选弹窗(理论上不写也能关闭其他,但是就是有些列会出现两个弹窗同时出现的情况)
107
108
  closeSortAndFilterPopover(column.prop);
108
109
  tempFilteredValue.value = { ...filteredValue.value };
109
- tempSearchValue.value = { ...searchValue.value };
110
110
  tempSortType.value = sortType.value || '';
111
111
  tempSortProp.value = sortProp.value || '';
112
112
  // 临时合计项设置成实际的合计项
@@ -137,39 +137,33 @@ export function useColumnHeaderOperation({ props, tableDomRef, emit, showingColu
137
137
 
138
138
  const emitSearch = () => {
139
139
  const params: Record<string, any> = {};
140
- // 仅提交显示的列的相关数据
141
- showingColumns.value.forEach(prop => {
142
- const column = columnMap.value[prop]
143
- if (column.filters) {
144
- const _prop = (Array.isArray(column.filters) ? prop : column.filters.prop) || prop
145
- params[_prop] = filteredValue.value[_prop]
146
- }
147
- if (column.search) {
148
- if (Array.isArray(column.search)) {
149
- column.search.forEach(v => {
150
- const props = typeof v.prop === 'string' ? [v.prop] : v.prop
151
- props.forEach(p => {
152
- params[p] = searchValue.value[p]
153
- })
154
- })
140
+
141
+ const processFilter = (filters: FilterListType) => {
142
+ filters.forEach((item) => {
143
+ if (item.type === 'doubleDatePicker' || item.type === 'monthDayPicker') {
144
+ const [start, end] = item.prop
145
+ params[start] = filteredValue.value[start];
146
+ params[end] = filteredValue.value[end];
155
147
  } else {
156
- params[prop] = searchValue.value[prop]
148
+ params[item.prop] = filteredValue.value[item.prop];
157
149
  }
158
- }
159
- if (column.doubleDatePicker) {
160
- params[column.doubleDatePicker.props[0]] = searchValue.value[column.doubleDatePicker.props[0]]
161
- params[column.doubleDatePicker.props[1]] = searchValue.value[column.doubleDatePicker.props[1]]
162
- }
163
- })
150
+ });
151
+ }
152
+
153
+ // 仅提交显示的列的相关数据
154
+ showingColumns.value.forEach(prop => {
155
+ const { filters = [] } = columnMap.value[prop] as IColumnConfig;
156
+ processFilter(filters);
157
+ });
164
158
 
165
159
  if (props.colorFilterConfig) {
166
- const { prop } = props.colorFilterConfig
167
- params[prop] = filteredValue.value[prop]
160
+ const { filters = [] } = props.colorFilterConfig;
161
+ processFilter(filters);
168
162
  }
169
163
 
170
164
  Object.keys(params).forEach(key => {
171
- if (params[key] === undefined) delete params[key]
172
- })
165
+ if (params[key] === undefined) delete params[key];
166
+ });
173
167
 
174
168
  emit('search', {
175
169
  ...params,
@@ -177,33 +171,27 @@ export function useColumnHeaderOperation({ props, tableDomRef, emit, showingColu
177
171
  });
178
172
  };
179
173
 
180
- const handleHeaderOperationConfirm = async (column: IColumnConfig, scope) => {
181
- if (column.search) {
182
- // 校验
183
- if (Array.isArray(column.search)) {
184
- let validate = true;
185
- column.search.forEach(v => {
186
- if (!validate) return
187
- if (!('type' in v) || v.type === 'input') {
188
- if (!tempSearchValue.value[v.prop]) tempSearchValue.value[v.prop] = ''
189
- if (v.validator) {
190
- const result = v.validator(tempSearchValue.value[v.prop]?.trim());
191
- if (!result) validate = false;
192
- }
193
- } else if (v.type === 'doubleDatePicker' || v.type === 'slot') {
194
- if (v.validator) {
195
- const result = v.validator(tempSearchValue.value);
196
- if (!result) validate = false;
197
- }
198
- }
199
- })
200
- // 校验未通过
201
- if (!validate) return
202
- } else {
203
- if (!tempSearchValue.value[column.prop]) tempSearchValue.value[column.prop] = ''
204
- }
174
+
175
+ const handleHeaderOperationConfirm = async (column: IColumnConfig) => {
176
+ const inputFilters = (column.filters ?? []).filter(
177
+ (item): item is IFilterInput => item.type === 'input'
178
+ );
179
+
180
+ const hasValidatorError = inputFilters.some(
181
+ (item) => item.validator
182
+ && !item.validator((tempFilteredValue.value[item.prop] as string).trim())
183
+ )
184
+
185
+ if (hasValidatorError) {
186
+ return
205
187
  }
206
188
 
189
+ inputFilters.forEach(
190
+ (item) => {
191
+ if (!tempFilteredValue.value[item.prop]) tempFilteredValue.value[item.prop] = ''
192
+ }
193
+ )
194
+
207
195
  summaryList.value = [...tempSummaryList.value];
208
196
  sortProp.value = tempSortProp.value || '';
209
197
  sortType.value = tempSortType.value || null;
@@ -221,15 +209,8 @@ export function useColumnHeaderOperation({ props, tableDomRef, emit, showingColu
221
209
  }
222
210
 
223
211
  filteredValue.value = { ...tempFilteredValue.value };
224
- searchValue.value = Object.keys(tempSearchValue.value).reduce((pre, key) => {
225
- pre[key] = tempSearchValue.value[key]?.trim() ?? '';
226
- return pre;
227
- }, {});
228
212
 
229
213
  emitSearch();
230
-
231
- filterColumns(scope.store);
232
-
233
214
  closeSortAndFilterPopover();
234
215
  await nextTick()
235
216
  tableDomRef.value?.doLayout();
@@ -260,18 +241,27 @@ export function useColumnHeaderOperation({ props, tableDomRef, emit, showingColu
260
241
  }
261
242
 
262
243
  function handleResetFilterValue (column: IColumnConfig) {
263
- if (column.filters) {
264
- if (Array.isArray(column.filters)) {
265
- filteredValue.value[column.prop] = []
266
- } else if (column.filters.default) {
267
- filteredValue.value[column.filters.prop || column.prop] = column.filters.default
268
- } else {
269
- filteredValue.value[column.filters.prop || column.prop] = column.filters.type === 'radio' ? '' : []
270
- }
271
- }
244
+ (column.filters || [])
245
+ .forEach(
246
+ (item) => {
247
+ if (item.type === 'radio' || item.type === 'checkbox') {
248
+ if (item.defaultValue) {
249
+ filteredValue.value[item.prop] = item.defaultValue
250
+ } else {
251
+ filteredValue.value[item.prop] = item.type === 'radio' ? '' : []
252
+ }
253
+ } else if (item.type === 'doubleDatePicker' || item.type === 'monthDayPicker') {
254
+ const [start, end] = item.prop
255
+ filteredValue.value[start] = '';
256
+ filteredValue.value[end] = '';
257
+ } else {
258
+ filteredValue.value[item.prop] = ''
259
+ }
260
+ }
261
+ )
272
262
  }
273
263
 
274
- const handleHeaderOperationReset = async (column: IColumnConfig, scope) => {
264
+ const handleHeaderOperationReset = async (column: IColumnConfig) => {
275
265
  if (
276
266
  sortProp.value &&
277
267
  (Array.isArray(column._sortable)
@@ -285,94 +275,33 @@ export function useColumnHeaderOperation({ props, tableDomRef, emit, showingColu
285
275
  summaryList.value = summaryList.value.filter(item => item !== column.prop);
286
276
 
287
277
  handleResetFilterValue(column)
288
- if (column.search) {
289
- if (!Array.isArray(column.search)) {
290
- searchValue.value[column.prop] = '';
291
- } else {
292
- column.search.forEach(v => {
293
- const props = typeof v.prop === 'string' ? [v.prop] : v.prop
294
- props.forEach(p => {
295
- searchValue.value[p] = '';
296
- })
297
- })
298
- }
299
- }
300
- if (column.doubleDatePicker) {
301
- searchValue.value[column.doubleDatePicker.props[0]] = '';
302
- searchValue.value[column.doubleDatePicker.props[1]] = '';
303
- }
304
-
305
278
  emitSearch();
306
-
307
- filterColumns(scope.store);
308
-
309
279
  closeSortAndFilterPopover();
310
280
  await nextTick();
311
281
  tableDomRef.value?.doLayout();
312
282
  }
313
283
 
314
- const filterColumns = (store) => {
315
- if (!props.localFilter) return
316
- store.states.columns.forEach(column => {
317
- if (filteredValue.value[column.property]) {
318
- store.commit('filterChange', {
319
- column,
320
- values: filteredValue.value[column.property],
321
- });
322
- }
323
- });
324
-
325
- // 根据searchValue过滤数据
326
- const data = store.states.data.filter(item => {
327
- const flag = Object.keys(searchValue.value)
328
- .filter(key => searchValue.value[key])
329
- .reduce((pre, key) => {
330
- const value = searchValue.value[key];
331
-
332
- return pre && item[key] && `${item[key]}`.indexOf(value) > -1;
333
- }, true);
334
-
335
- return flag;
336
- });
337
-
338
- store.states.data = data;
339
- }
340
-
341
284
  const setSearchParams = (params: Record<string, any>) => {
342
- const _searchValue = {};
343
285
  const _filteredValue = {};
344
286
 
345
287
  // 设置搜索和过滤参数时,如果使用 showingColumns 遍历,会导致通过外部设置未显示的列的搜索和过滤参数丢失
346
- props.columnConfig.forEach(column => {
347
- if (column.search) {
348
- if (Array.isArray(column.search)) {
349
- column.search.forEach(v => {
350
- const props = typeof v.prop === 'string' ? [v.prop] : v.prop
351
- props.forEach(p => {
352
- _searchValue[p] = params[p];
353
- })
354
- });
355
- } else {
356
- _searchValue[column.prop] = params[column.prop] ?? '';
357
- }
358
- }
359
- if (column.filters) {
360
- const _prop = (Array.isArray(column.filters) ? column.prop : column.filters.prop) || column.prop
361
- const value = params[_prop] ?? (Array.isArray(column.filters) ? [] : column.filters.default);
362
- _filteredValue[_prop] = value;
363
- }
364
- if (column.doubleDatePicker) {
365
- _searchValue[column.doubleDatePicker.props[0]] = params[column.doubleDatePicker.props[0]] ?? '';
366
- _searchValue[column.doubleDatePicker.props[1]] = params[column.doubleDatePicker.props[1]] ?? '';
367
- }
288
+ [props.colorFilterConfig, ...props.columnConfig].forEach(column => {
289
+ (column?.filters ?? [])
290
+ .forEach(
291
+ (item) => {
292
+ if (item.type === 'doubleDatePicker' || item.type === 'monthDayPicker') {
293
+ const [start, end] = item.prop
294
+ _filteredValue[start] = params[start]
295
+ _filteredValue[end] = params[end]
296
+ } else if (item.type === 'checkbox') {
297
+ _filteredValue[item.prop] = params[item.prop] ?? item.defaultValue ?? []
298
+ } else {
299
+ _filteredValue[item.prop] = params[item.prop] ?? ''
300
+ }
301
+ }
302
+ )
368
303
  })
369
304
 
370
- if (props.colorFilterConfig) {
371
- const { prop, filters } = props.colorFilterConfig
372
- _filteredValue[prop] = params[prop] ?? (Array.isArray(filters) ? [] : filters?.default);
373
- }
374
-
375
- searchValue.value = { ...searchValue.value, ..._searchValue }
376
305
  filteredValue.value = { ...filteredValue.value, ..._filteredValue }
377
306
  }
378
307
 
@@ -390,13 +319,11 @@ export function useColumnHeaderOperation({ props, tableDomRef, emit, showingColu
390
319
  filteredValue,
391
320
  showColumnHeadSortIcon,
392
321
  tempSortProp,
393
- tempSearchValue,
394
322
  tempFilteredValue,
395
323
  tempSummaryList,
396
324
  tempSortType,
397
325
  sortProp,
398
326
  isColumnFiltering,
399
- searchValue,
400
327
  inSorting,
401
328
  }
402
329
  }
@@ -0,0 +1,45 @@
1
+ <!-- 复选框 -->
2
+ <template>
3
+ <div class="editable-table-sort-filter__filter">
4
+ <div class="editable-table-sort-filter__filter-title">
5
+ {{ config.label || '筛选' }}
6
+ </div>
7
+ <el-checkbox-group
8
+ class="editable-table-sort-filter__filter-checkbox-group"
9
+ :value="tempFilteredValue[config.prop]"
10
+ @input="val => emit('update:tempFilteredValue', config.prop, val)"
11
+ >
12
+ <el-checkbox
13
+ v-for="item in config.options"
14
+ :key="item.value"
15
+ :label="item.value"
16
+ :title="item.text"
17
+ class="editable-table-sort-filter__filter-checkbox"
18
+ >
19
+ <slot
20
+ name="filter-item"
21
+ v-bind="item"
22
+ >
23
+ {{ item.text }}
24
+ </slot>
25
+ </el-checkbox>
26
+ </el-checkbox-group>
27
+ </div>
28
+ </template>
29
+
30
+ <script setup lang="ts">
31
+ import { IFilterSelect } from '../../types';
32
+
33
+ defineProps<{
34
+ config: IFilterSelect
35
+ tempFilteredValue: Record<string, string>
36
+ }>()
37
+
38
+ const emit = defineEmits<{
39
+ (e: 'update:tempFilteredValue', key: string, value: string): void
40
+ }>()
41
+ </script>
42
+
43
+ <style scoped lang="less">
44
+
45
+ </style>
@@ -0,0 +1,56 @@
1
+ <!-- 单选框 -->
2
+ <template>
3
+ <div class="editable-table-sort-filter__filter">
4
+ <div class="editable-table-sort-filter__filter-title">
5
+ {{ config.label || '筛选' }}
6
+ </div>
7
+ <el-radio-group
8
+ style="display: flex;flex-direction: column;gap: 6px;"
9
+ :value="tempFilteredValue[config.prop]"
10
+ @input="val => emit('update:tempFilteredValue', config.prop, val)"
11
+ >
12
+ <el-radio
13
+ v-for="item in config.options"
14
+ :key="item.value"
15
+ :label="item.value"
16
+ :title="item.text"
17
+ >
18
+ <span class="color-option">
19
+ <span
20
+ class="icon"
21
+ :style="{ background: item.color }"
22
+ />
23
+ <span>{{ item.text }}</span>
24
+ </span>
25
+ </el-radio>
26
+ </el-radio-group>
27
+ </div>
28
+ </template>
29
+
30
+ <script setup lang="ts">
31
+ import { IFilterColorRadio } from '../../types';
32
+
33
+ defineProps<{
34
+ config: IFilterColorRadio
35
+ tempFilteredValue: Record<string, string>
36
+ }>()
37
+
38
+ const emit = defineEmits<{
39
+ (e: 'update:tempFilteredValue', key: string, value: string): void
40
+ }>()
41
+ </script>
42
+
43
+ <style scoped lang="less">
44
+ .color-option {
45
+ display: flex;
46
+ align-items: center;
47
+
48
+ .icon {
49
+ border-radius: 50%;
50
+ width: 1em;
51
+ height: 1em;
52
+ margin-right: 0.3em;
53
+ border: 1px solid #ccc;
54
+ }
55
+ }
56
+ </style>
@@ -0,0 +1,48 @@
1
+ <!-- 日期范围选择(分开的两个日期选择器) -->
2
+ <template>
3
+ <div class="editable-table-sort-filter__sort">
4
+ <div class="editable-table-sort-filter__search-title">
5
+ {{ config.label || '筛选' }}
6
+ </div>
7
+ <div
8
+ class="editable-table-sort-filter__date-picker-content"
9
+ style="display: flex;flex-direction: column;gap: 12px;"
10
+ >
11
+ <el-date-picker
12
+ @input="val => emit('update:tempFilteredValue', config.prop[0], val || '')"
13
+ :value="tempFilteredValue[config.prop[0]]"
14
+ value-format="yyyy-MM-dd"
15
+ format="yyyy-MM-dd"
16
+ type="date"
17
+ size="small"
18
+ placeholder="开始日期"
19
+ />
20
+ <el-date-picker
21
+ @input="val => emit('update:tempFilteredValue', config.prop[1], val || '')"
22
+ :value="tempFilteredValue[config.prop[1]]"
23
+ value-format="yyyy-MM-dd"
24
+ format="yyyy-MM-dd"
25
+ size="small"
26
+ type="date"
27
+ placeholder="结束日期"
28
+ />
29
+ </div>
30
+ </div>
31
+ </template>
32
+
33
+ <script setup lang="ts">
34
+ import { IFilterDoubleDatePicker } from '../../types';
35
+
36
+ defineProps<{
37
+ config: IFilterDoubleDatePicker
38
+ tempFilteredValue: Record<string, string>
39
+ }>()
40
+
41
+ const emit = defineEmits<{
42
+ (e: 'update:tempFilteredValue', key: string, value: string): void
43
+ }>()
44
+ </script>
45
+
46
+ <style scoped lang="less">
47
+
48
+ </style>
@@ -0,0 +1,26 @@
1
+ <template>
2
+ <div class="editable-table-sort-filter__search">
3
+ <div class="editable-table-sort-filter__search-title">
4
+ {{ config.label || '搜索' }}
5
+ </div>
6
+ <el-input
7
+ class="editable-table-sort-filter__search-input"
8
+ :placeholder="config.placeholder"
9
+ :value="tempFilteredValue[config.prop]"
10
+ @input="val => emit('update:tempFilteredValue', config.prop, val)"
11
+ />
12
+ </div>
13
+ </template>
14
+
15
+ <script setup lang="ts">
16
+ import { IFilterInput } from '../../types';
17
+
18
+ defineProps<{
19
+ config: IFilterInput
20
+ tempFilteredValue: Record<string, string>
21
+ }>()
22
+
23
+ const emit = defineEmits<{
24
+ (e: 'update:tempFilteredValue', key: string, value: string): void
25
+ }>()
26
+ </script>