@qin-ui/element-plus-pro 1.3.3 → 1.3.5
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/AI-CONTEXT.md +4 -4
- package/README.md +3 -2
- package/api.json +2 -2
- package/es/components/component-provider/constants/index.d.ts.map +1 -1
- package/es/components/component-provider/types/index.d.ts +3 -2
- package/es/components/component-provider/types/index.d.ts.map +1 -1
- package/es/components/form/components/BaseField/index.vue.d.ts.map +1 -1
- package/es/components/form/components/BaseFormItem/index.vue.d.ts +1 -1
- package/es/components/form/components/BaseFormItem/index.vue.d.ts.map +1 -1
- package/es/components/form/components/ProForm/index.vue.d.ts.map +1 -1
- package/es/components/form/components/SlotComponent/index.vue.d.ts.map +1 -1
- package/es/components/form/hooks/useGroupFieldAttrs.d.ts.map +1 -1
- package/es/components/form/types/index.d.ts +2 -2
- package/es/components/form/types/index.d.ts.map +1 -1
- package/es/components/table/components/ColumnControl.vue.d.ts.map +1 -1
- package/es/components/table/components/ProTable.vue.d.ts +30 -4
- package/es/components/table/components/ProTable.vue.d.ts.map +1 -1
- package/es/components/table/components/SearchForm.vue.d.ts +1 -1
- package/es/components/table/components/SearchForm.vue.d.ts.map +1 -1
- package/es/components/table/components/SizeControl.vue.d.ts +2 -2
- package/es/components/table/components/TableColumnRenderer.vue.d.ts.map +1 -1
- package/es/components/table/index.d.ts +4 -28
- package/es/components/table/index.d.ts.map +1 -1
- package/es/components/table/useTable.d.ts +1 -1
- package/es/element-plus-pro.css +12 -12
- package/es/index.js +410 -331
- package/es/index.js.map +1 -1
- package/es/shared/core/index.d.ts +1 -2
- package/es/shared/core/index.d.ts.map +1 -1
- package/es/shared/ui/index.d.ts +2 -2
- package/es/shared/ui/index.d.ts.map +1 -1
- package/package.json +5 -4
- package/src/components/component-provider/constants/index.ts +12 -0
- package/src/components/component-provider/types/index.ts +8 -2
- package/src/components/form/components/BaseField/index.vue +25 -9
- package/src/components/form/components/BaseField/utils/index.ts +1 -1
- package/src/components/form/components/BaseFormItem/index.vue +62 -8
- package/src/components/form/components/ProForm/index.vue +24 -12
- package/src/components/form/components/SlotComponent/index.vue +4 -3
- package/src/components/form/hooks/useGroupFieldAttrs.ts +8 -15
- package/src/components/form/types/index.ts +2 -8
- package/src/components/table/components/ColumnControl.vue +40 -37
- package/src/components/table/components/ProTable.vue +74 -18
- package/src/components/table/components/SearchForm.vue +5 -4
- package/src/components/table/components/TableColumnRenderer.vue +22 -9
- package/src/components/table/index.ts +10 -30
- package/src/components/table/useTable.ts +1 -1
- package/src/shared/core/index.ts +1 -2
- package/src/shared/ui/index.ts +2 -0
- package/tsconfig.json +23 -0
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
type PaginationProps,
|
|
38
38
|
Table as ElTable,
|
|
39
39
|
type TableProps,
|
|
40
|
+
type TableEmits,
|
|
40
41
|
tableProps,
|
|
41
42
|
paginationProps,
|
|
42
43
|
} from '../../../shared/ui';
|
|
@@ -52,7 +53,7 @@ import {
|
|
|
52
53
|
useSlots,
|
|
53
54
|
} from 'vue';
|
|
54
55
|
import { INJECT_CONFIG } from '../../component-provider/constants';
|
|
55
|
-
import
|
|
56
|
+
import ContainerFragment from '../../form/components/ContainerFragment/index.vue';
|
|
56
57
|
import type { ContainerComponent } from '../../form/types';
|
|
57
58
|
import SearchForm from './SearchForm.vue';
|
|
58
59
|
import type { SearchFormProps } from './SearchForm.vue';
|
|
@@ -66,12 +67,10 @@ import {
|
|
|
66
67
|
isPlainObject,
|
|
67
68
|
Path,
|
|
68
69
|
} from '../../../shared/core';
|
|
69
|
-
import
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
ColumnControl,
|
|
74
|
-
} from '.';
|
|
70
|
+
import DefaultSearchFormContainer from './DefaultSearchFormContainer.vue';
|
|
71
|
+
import DefaultTableContainer from './DefaultTableContainer.vue';
|
|
72
|
+
import SizeControl from './SizeControl.vue';
|
|
73
|
+
import ColumnControl from './ColumnControl.vue';
|
|
75
74
|
import type { Columns, ColumnControlConfig } from '../types';
|
|
76
75
|
import TableColumnRenderer from './TableColumnRenderer.vue';
|
|
77
76
|
|
|
@@ -119,7 +118,11 @@ type Props = {
|
|
|
119
118
|
columns?: Columns<RecordType>;
|
|
120
119
|
data?: RecordType[];
|
|
121
120
|
pagination?: false | Partial<PaginationProps>;
|
|
122
|
-
} & Omit<TableProps, 'data'>;
|
|
121
|
+
} & /* @vue-ignore */ Omit<TableProps, 'data'>;
|
|
122
|
+
|
|
123
|
+
type Emits = {} & /* @vue-ignore */ TableEmits<RecordType>;
|
|
124
|
+
|
|
125
|
+
defineEmits<Emits>();
|
|
123
126
|
|
|
124
127
|
const props = withDefaults(defineProps<Props>(), {
|
|
125
128
|
table: undefined,
|
|
@@ -142,8 +145,36 @@ const injectProps = computed(() => toValue(injectPropsRaw) || {});
|
|
|
142
145
|
|
|
143
146
|
const attrs = useAttrs() as Record<string, any>;
|
|
144
147
|
|
|
148
|
+
const PRO_TABLE_EXCLUDED_ATTR_KEYS = new Set([
|
|
149
|
+
'class',
|
|
150
|
+
'style',
|
|
151
|
+
'onSearch',
|
|
152
|
+
'onChange',
|
|
153
|
+
'onUpdate:size',
|
|
154
|
+
'onUpdate:loading',
|
|
155
|
+
'data',
|
|
156
|
+
'columns',
|
|
157
|
+
'size',
|
|
158
|
+
'pagination',
|
|
159
|
+
]);
|
|
160
|
+
|
|
161
|
+
const PRO_TABLE_PROVIDER_KEYS = new Set([
|
|
162
|
+
'pagination',
|
|
163
|
+
'searchFormConfig',
|
|
164
|
+
'control',
|
|
165
|
+
'immediateSearch',
|
|
166
|
+
'addIndexColumn',
|
|
167
|
+
'tableContainer',
|
|
168
|
+
]);
|
|
169
|
+
|
|
145
170
|
const injectTableAttrs = computed(() => {
|
|
146
|
-
|
|
171
|
+
const tableConfig: Record<string, any> = {};
|
|
172
|
+
for (const [key, value] of Object.entries(injectProps.value)) {
|
|
173
|
+
if (!PRO_TABLE_PROVIDER_KEYS.has(key)) {
|
|
174
|
+
tableConfig[key] = value;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return tableConfig as Partial<TableProps>;
|
|
147
178
|
});
|
|
148
179
|
|
|
149
180
|
const attrsTableProps = computed(() => {
|
|
@@ -153,15 +184,41 @@ const attrsTableProps = computed(() => {
|
|
|
153
184
|
) as Partial<TableProps>;
|
|
154
185
|
});
|
|
155
186
|
|
|
187
|
+
const restTableAttrs = computed(() => {
|
|
188
|
+
const rest: Record<string, any> = {};
|
|
189
|
+
for (const [key, value] of Object.entries(attrs)) {
|
|
190
|
+
if (!PRO_TABLE_EXCLUDED_ATTR_KEYS.has(key)) {
|
|
191
|
+
rest[key] = value;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return rest;
|
|
195
|
+
});
|
|
196
|
+
|
|
156
197
|
const size = defineModel<TableProps['size']>('size');
|
|
157
198
|
const loading = defineModel<boolean>('loading', { default: false });
|
|
158
199
|
|
|
159
200
|
// 递增序号做请求竞态守卫,仅最新一次请求可变更 loading
|
|
160
201
|
let searchSequence = 0;
|
|
202
|
+
let warnedSearchConfig = false;
|
|
203
|
+
const warnSearchConfig = (reason: string) => {
|
|
204
|
+
if (warnedSearchConfig) return;
|
|
205
|
+
warnedSearchConfig = true;
|
|
206
|
+
console.warn(`[ProTable] ${reason}`);
|
|
207
|
+
};
|
|
161
208
|
const _search = async () => {
|
|
162
|
-
|
|
209
|
+
if (props.search && attrs.onSearch) {
|
|
210
|
+
warnSearchConfig(
|
|
211
|
+
'同时配置了 :search prop 与 @search 监听,@search 监听不会被执行,请仅保留其一。'
|
|
212
|
+
);
|
|
213
|
+
}
|
|
163
214
|
const searchPromise = (props.search || attrs.onSearch)?.();
|
|
164
|
-
if (!isPromise(searchPromise))
|
|
215
|
+
if (!isPromise(searchPromise)) {
|
|
216
|
+
warnSearchConfig(
|
|
217
|
+
'search 未返回 Promise,本次查询不参与 loading 竞态管理(在途请求的 loading 状态保持不变)。'
|
|
218
|
+
);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
const seq = ++searchSequence;
|
|
165
222
|
loading.value = true;
|
|
166
223
|
try {
|
|
167
224
|
await searchPromise;
|
|
@@ -251,21 +308,19 @@ const normalizedRawColumns = computed(() => {
|
|
|
251
308
|
|
|
252
309
|
const computedDataSource = computed<any[]>(() => {
|
|
253
310
|
const attrsData = attrsTableProps.value.data as any[] | undefined;
|
|
254
|
-
return (
|
|
255
|
-
props.data ??
|
|
256
|
-
attrsData ??
|
|
257
|
-
toValue((props.table as any)?.dataSource) ??
|
|
258
|
-
toValue(props.table?.data) ??
|
|
259
|
-
[]
|
|
260
|
-
);
|
|
311
|
+
return props.data ?? attrsData ?? toValue(props.table?.data) ?? [];
|
|
261
312
|
});
|
|
262
313
|
|
|
263
314
|
const computedTableProps = computed<TableProps>(() => {
|
|
264
315
|
const merged = {
|
|
265
316
|
...injectTableAttrs.value,
|
|
317
|
+
...restTableAttrs.value,
|
|
266
318
|
...attrsTableProps.value,
|
|
267
319
|
} as TableProps;
|
|
268
320
|
delete (merged as any).data;
|
|
321
|
+
delete (merged as any).columns;
|
|
322
|
+
delete (merged as any).size;
|
|
323
|
+
delete (merged as any).pagination;
|
|
269
324
|
return merged;
|
|
270
325
|
});
|
|
271
326
|
|
|
@@ -313,6 +368,7 @@ const onCurrentChange = (current: number) => {
|
|
|
313
368
|
_search();
|
|
314
369
|
};
|
|
315
370
|
|
|
371
|
+
// 改变 pageSize 时重置回第 1 页并重新查询
|
|
316
372
|
const onSizeChange = (pageSize: number) => {
|
|
317
373
|
props.table?.setPageParam?.({ pageSize, current: 1 });
|
|
318
374
|
_search();
|
|
@@ -46,7 +46,7 @@ export type SearchFormProps = {
|
|
|
46
46
|
*
|
|
47
47
|
* 1. 内部渲染 ProForm,使用 table.searchForm 管理搜索条件
|
|
48
48
|
* 2. 支持 grid(网格)和 inline(行内)两种布局
|
|
49
|
-
* 3.
|
|
49
|
+
* 3. 网格布局下支持展开/折叠(溢出检测与初值自动展开见下方机制说明)
|
|
50
50
|
* 4. 提供搜索、重置、展开/折叠按钮(支持自定义)
|
|
51
51
|
*
|
|
52
52
|
* ## 展开/折叠机制
|
|
@@ -63,8 +63,8 @@ import {
|
|
|
63
63
|
type Component,
|
|
64
64
|
type DefineComponent,
|
|
65
65
|
} from 'vue';
|
|
66
|
-
import ProForm from '../../form';
|
|
67
|
-
import { type Form } from '../../form';
|
|
66
|
+
import ProForm from '../../form/components/ProForm/index.vue';
|
|
67
|
+
import { type Form } from '../../form/hooks/useForm';
|
|
68
68
|
import DownOutlined from './icons/DownOutlined.vue';
|
|
69
69
|
import { useLocale } from '../../../locale';
|
|
70
70
|
import { useSearchFormExpand } from '../../../shared/core';
|
|
@@ -122,6 +122,7 @@ const onReset = () => {
|
|
|
122
122
|
emit('reset');
|
|
123
123
|
};
|
|
124
124
|
|
|
125
|
+
// 查询按钮为 native-type=submit:点击与回车统一经表单 submit 事件触发
|
|
125
126
|
const onSearch = () => {
|
|
126
127
|
emit('search');
|
|
127
128
|
};
|
|
@@ -132,6 +133,7 @@ const onSearch = () => {
|
|
|
132
133
|
v-bind="layoutProps"
|
|
133
134
|
:form="props.form"
|
|
134
135
|
class="pro-table_search-form transition"
|
|
136
|
+
@submit.prevent="onSearch"
|
|
135
137
|
>
|
|
136
138
|
<Space alignment="start" class="pro-table_search-form_button-group">
|
|
137
139
|
<slot name="reset-button" :on-reset="onReset">
|
|
@@ -162,7 +164,6 @@ const onSearch = () => {
|
|
|
162
164
|
class="pro-table_search-form_search-button"
|
|
163
165
|
type="primary"
|
|
164
166
|
native-type="submit"
|
|
165
|
-
@click="onSearch"
|
|
166
167
|
>
|
|
167
168
|
{{ t('table.query') }}
|
|
168
169
|
</Button>
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
>
|
|
6
6
|
import { get, normalizePathKey } from '../../../shared/core';
|
|
7
7
|
import { TableColumn } from '../../../shared/ui';
|
|
8
|
-
import
|
|
8
|
+
import SlotComponent from '../../form/components/SlotComponent/index.vue';
|
|
9
9
|
import type { Column, Columns } from '../types';
|
|
10
|
-
import { computed } from 'vue';
|
|
10
|
+
import { computed, toRaw } from 'vue';
|
|
11
11
|
|
|
12
12
|
defineOptions({ name: 'TableColumnRenderer' });
|
|
13
13
|
|
|
@@ -18,9 +18,26 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
18
18
|
columns: () => [],
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
/*
|
|
22
|
+
* 无 key/prop 列的稳定渲染 key:以列原始对象为 key 分配自增 id,
|
|
23
|
+
* 列插删/重排/过滤时保持 key 与对象绑定,不随数组位置漂移
|
|
24
|
+
*/
|
|
25
|
+
let columnKeySeed = 0;
|
|
26
|
+
const columnKeyMap = new WeakMap<object, number>();
|
|
27
|
+
const getStableColumnKey = (column: unknown): number => {
|
|
28
|
+
const raw = toRaw(column as object);
|
|
29
|
+
let key = columnKeyMap.get(raw);
|
|
30
|
+
if (key === undefined) {
|
|
31
|
+
key = ++columnKeySeed;
|
|
32
|
+
columnKeyMap.set(raw, key);
|
|
33
|
+
}
|
|
34
|
+
return key;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const getColumnKey = (column: Column<D>) => {
|
|
22
38
|
const rawKey = column.key ?? column.prop;
|
|
23
|
-
if (rawKey === undefined || rawKey === null)
|
|
39
|
+
if (rawKey === undefined || rawKey === null)
|
|
40
|
+
return getStableColumnKey(column);
|
|
24
41
|
return normalizePathKey(rawKey);
|
|
25
42
|
};
|
|
26
43
|
|
|
@@ -35,7 +52,6 @@ const normalizedColumns = computed(() => {
|
|
|
35
52
|
});
|
|
36
53
|
|
|
37
54
|
const getColumnProps = (column: Column<D>) => {
|
|
38
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
39
55
|
const { hidden, render, key, children, ...rest } = column;
|
|
40
56
|
const prop = column.prop ? normalizePathKey(column.prop) : undefined;
|
|
41
57
|
const columnKey = key ? normalizePathKey(key) : prop;
|
|
@@ -49,10 +65,7 @@ const getColumnProps = (column: Column<D>) => {
|
|
|
49
65
|
</script>
|
|
50
66
|
|
|
51
67
|
<template>
|
|
52
|
-
<template
|
|
53
|
-
v-for="(column, index) in normalizedColumns"
|
|
54
|
-
:key="getColumnKey(column, index)"
|
|
55
|
-
>
|
|
68
|
+
<template v-for="column in normalizedColumns" :key="getColumnKey(column)">
|
|
56
69
|
<!-- 分组列(递归子列) -->
|
|
57
70
|
<TableColumn
|
|
58
71
|
v-if="column.children && column.children.length > 0"
|
|
@@ -1,38 +1,18 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import type { SearchFormProps } from './components/SearchForm.vue';
|
|
6
|
-
import type { Table } from './useTable';
|
|
1
|
+
import type {
|
|
2
|
+
ComponentExposed,
|
|
3
|
+
ComponentProps,
|
|
4
|
+
} from 'vue-component-type-helpers';
|
|
7
5
|
import ProTable from './components/ProTable.vue';
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
type
|
|
11
|
-
|
|
12
|
-
container?: ContainerComponent | false;
|
|
13
|
-
};
|
|
7
|
+
// 仅导出组件 Props 与实例类型,不导出裸组件
|
|
8
|
+
export type ProTableProps = ComponentProps<typeof ProTable>;
|
|
9
|
+
export type ProTableInstance = ComponentExposed<typeof ProTable>;
|
|
14
10
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
// instance
|
|
18
|
-
export type ProTableProps<T extends Table<any> = Table> = {
|
|
19
|
-
table?: T;
|
|
20
|
-
search?: () => Promise<unknown>;
|
|
21
|
-
addIndexColumn?: boolean;
|
|
22
|
-
immediateSearch?: boolean;
|
|
23
|
-
control?: boolean | Partial<Control>;
|
|
24
|
-
searchFormConfig?: SearchFormConfig;
|
|
25
|
-
tableContainer?: ContainerComponent | false;
|
|
26
|
-
columns?: Columns<ReturnTableRecord<T>>;
|
|
27
|
-
data?: ReturnTableRecord<T>[];
|
|
28
|
-
pagination?: false | Partial<PaginationProps>;
|
|
29
|
-
} & Omit<TableProps, 'data'>;
|
|
30
|
-
export type ProTableInstance = ComponentPublicInstance;
|
|
31
|
-
|
|
32
|
-
// types
|
|
11
|
+
// 仅导出核心列配置类型
|
|
33
12
|
export { type Column, type Columns } from './types';
|
|
13
|
+
export { type TableEmits } from '../../shared/ui';
|
|
34
14
|
|
|
35
|
-
//
|
|
15
|
+
// 仅导出核心表格 Hook 与类型
|
|
36
16
|
export { useTable, type Table } from './useTable';
|
|
37
17
|
|
|
38
18
|
export default ProTable;
|
|
@@ -31,7 +31,7 @@ import type { Ref } from 'vue';
|
|
|
31
31
|
* @property appendColumn - 在指定列后追加新列,传 undefined 在末尾追加
|
|
32
32
|
* @property prependColumn - 在指定列前插入新列,传 undefined 在开头插入
|
|
33
33
|
* @property setPageParam - 设置分页参数,支持部分更新和函数式更新
|
|
34
|
-
* @property resetQueryParams -
|
|
34
|
+
* @property resetQueryParams - 恢复分页与搜索条件到初始化时的快照(含自定义分页键,非固定回到第一页)
|
|
35
35
|
*
|
|
36
36
|
* @example
|
|
37
37
|
* ```ts
|
package/src/shared/core/index.ts
CHANGED
package/src/shared/ui/index.ts
CHANGED
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
type FormProps,
|
|
33
33
|
type FormItemProps,
|
|
34
34
|
type TableProps as _TableProps,
|
|
35
|
+
type TableEmits,
|
|
35
36
|
type TableColumnCtx as ColumnType,
|
|
36
37
|
type PaginationProps,
|
|
37
38
|
type RowProps as GridProps,
|
|
@@ -75,6 +76,7 @@ export {
|
|
|
75
76
|
type GridProps,
|
|
76
77
|
type GridItemProps,
|
|
77
78
|
type ColumnType,
|
|
79
|
+
type TableEmits,
|
|
78
80
|
};
|
|
79
81
|
|
|
80
82
|
export type TableProps = _TableProps<any>;
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ESNext",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"jsx": "preserve",
|
|
9
|
+
"resolveJsonModule": true,
|
|
10
|
+
"isolatedModules": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"lib": ["ESNext", "ES2022", "DOM"],
|
|
13
|
+
"baseUrl": ".",
|
|
14
|
+
"types": ["element-plus/global"],
|
|
15
|
+
"declaration": true,
|
|
16
|
+
"declarationMap": true,
|
|
17
|
+
"skipLibCheck": true,
|
|
18
|
+
"forceConsistentCasingInFileNames": true,
|
|
19
|
+
"noEmit": true
|
|
20
|
+
},
|
|
21
|
+
"include": ["src", "__tests__"],
|
|
22
|
+
"exclude": ["node_modules", "es"]
|
|
23
|
+
}
|