@vue-ui-kit/ant 1.2.0 → 1.4.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.
@@ -1,277 +1,285 @@
1
1
  <script generic="D = Recordable, F = Recordable" lang="ts" name="PGrid" setup>
2
- import { ColumnProps, PFormItemProps, PGridProps, ResponsePathConfig } from '#/antProxy'
3
- import { computed, useAttrs, ref, Ref, reactive, onMounted, watch, toRefs } from 'vue'
4
- import { debounce, get, isArray, isFunction, isString, merge, omit, toNumber } from 'lodash-es'
5
- import { eachTree } from '@/utils/treeHelper'
6
- import { message as $message } from 'ant-design-vue'
7
- import RenderAntItem from '@/components/RenderAntItem'
8
- import RenderTitleSlots from '@/components/RenderTitleSlots'
9
- import RenderDefaultSlots from '@/components/RenderDefaultSlots'
10
- import { v4 as uuid_v4 } from 'uuid'
11
- import { valued } from '@/utils/is'
12
- import RenderItemSlots from '@/components/RenderItemSlots'
13
- import { cleanCol, defaultItemResponsive, defaultLabelCol } from '@/utils/core'
14
- import Icon from '@/renders/Icon'
15
- import { $confirm } from '@/hooks/useMessage'
16
- import {
17
- Table as ATable,
18
- Button as AButton,
19
- Form as AForm,
20
- FormItem as AFormItem,
21
- Row as ARow,
22
- Col as ACol,
23
- Spin as ASpin,
24
- } from 'ant-design-vue'
25
- import { TablePaginationConfig } from 'ant-design-vue/es/table/interface'
2
+ import { ColumnProps, PFormItemProps, PGridProps, ResponsePathConfig } from '#/antProxy';
3
+ import { computed, useAttrs, ref, Ref, reactive, onMounted, watch, toRefs } from 'vue';
4
+ import { debounce, get, isArray, isFunction, isString, merge, omit, toNumber } from 'lodash-es';
5
+ import { eachTree } from '@/utils/treeHelper';
6
+ import { message as $message } from 'ant-design-vue';
7
+ import RenderAntItem from '@/components/RenderAntItem';
8
+ import RenderTitleSlots from '@/components/RenderTitleSlots';
9
+ import RenderDefaultSlots from '@/components/RenderDefaultSlots';
10
+ import { v4 as uuid_v4 } from 'uuid';
11
+ import { valued } from '@/utils/is';
12
+ import RenderItemSlots from '@/components/RenderItemSlots';
13
+ import { cleanCol, defaultItemResponsive, defaultLabelCol } from '@/utils/core';
14
+ import Icon from '@/renders/Icon';
15
+ import { $confirm } from '@/hooks/useMessage';
16
+ import {
17
+ Table as ATable,
18
+ Button as AButton,
19
+ Form as AForm,
20
+ FormItem as AFormItem,
21
+ Row as ARow,
22
+ Col as ACol,
23
+ Spin as ASpin,
24
+ Tooltip as ATooltip,
25
+ } from 'ant-design-vue';
26
+ import { TablePaginationConfig } from 'ant-design-vue/es/table/interface';
27
+ import { InfoCircleOutlined, DownOutlined } from '@ant-design/icons-vue';
26
28
 
27
- const props = defineProps<PGridProps<D, F>>()
28
- const {
29
- formConfig,
30
- pageConfig,
31
- columns,
32
- toolbarConfig,
33
- proxyConfig,
34
- tableConfig,
35
- selectConfig,
36
- scrollMode,
37
- } = toRefs(props)
38
- const loading = reactive({
39
- table: false,
40
- form: false,
41
- })
42
- const submitOnReset = true
43
- const boxEl = ref<HTMLDivElement>()
44
- const renderHeight = ref(500)
45
- const selectedRowKeys = ref<string[] | number[]>([])
46
- const innerToolbarHandler = (code: string) => {
47
- const { ajax } = proxyConfig.value!
48
- switch (code) {
49
- case 'multiDelete':
50
- if (ajax.multiDelete) {
51
- if (selectedRowKeys.value.length > 0) {
52
- $confirm({
53
- title: '警告',
54
- content: '确认删除选中的数据吗?',
55
- }).then(() => {
56
- loading.table = true
57
- ajax.multiDelete!(selectedRowKeys.value)
29
+ const props = defineProps<PGridProps<D, F>>();
30
+ const {
31
+ formConfig,
32
+ pageConfig,
33
+ columns,
34
+ toolbarConfig,
35
+ proxyConfig,
36
+ tableConfig,
37
+ selectConfig,
38
+ scrollMode,
39
+ } = toRefs(props);
40
+ const loading = reactive({
41
+ table: false,
42
+ toolbar: false,
43
+ form: false,
44
+ });
45
+ const submitOnReset = true;
46
+ const boxEl = ref<HTMLDivElement>();
47
+ const renderHeight = ref(500);
48
+ const selectedRowKeys = ref<string[] | number[]>([]);
49
+ const innerToolbarHandler = (code: string) => {
50
+ const { ajax } = proxyConfig.value!;
51
+ switch (code) {
52
+ case 'multiDelete':
53
+ if (ajax.multiDelete) {
54
+ if (selectedRowKeys.value.length > 0) {
55
+ $confirm({
56
+ title: '警告',
57
+ content: '确认删除选中的数据吗?',
58
+ }).then(() => {
59
+ loading.table = true;
60
+ loading.toolbar = true;
61
+ ajax.multiDelete!(selectedRowKeys.value)
58
62
  .then(() => {
59
- $message.success('删除成功')
60
- resetPage()
63
+ $message.success('删除成功');
64
+ resetPage();
61
65
  })
62
66
  .catch(() => {
63
- $message.error('删除失败')
67
+ $message.error('删除失败');
64
68
  })
65
69
  .finally(() => {
66
- loading.table = false
67
- })
68
- })
69
- } else {
70
- $message.warn('请选择要删除的数据')
70
+ loading.table = false;
71
+ loading.toolbar = false;
72
+ });
73
+ });
74
+ } else {
75
+ $message.warn('请选择要删除的数据');
76
+ }
71
77
  }
72
- }
73
- break
74
- }
75
- }
76
- const slotTitleColumns = computed(() => {
77
- const cols: ColumnProps<D>[] = []
78
- eachTree(columns.value, (col) => {
79
- if (col.slots && col.slots.title) {
80
- if (!col.field) {
81
- col.field = '__holder__' + cols.length
82
- }
83
- cols.push(col)
78
+ break;
84
79
  }
85
- })
86
- return cols
87
- })
88
- const formEl = ref()
89
- const tableEl = ref()
90
- const renderFormKey = ref(uuid_v4())
91
- const renderTableKey = ref(uuid_v4())
92
- const refreshForm = () => {
93
- renderFormKey.value = uuid_v4()
94
- }
95
- const refreshTable = () => {
96
- renderTableKey.value = uuid_v4()
97
- }
98
- const debounceRefreshForm = debounce(refreshForm, 100)
99
- const debounceRefreshTable = debounce(refreshTable, 100)
100
- const slotDefaultColumns = computed(() => {
101
- const cols: ColumnProps<D>[] = []
102
- eachTree(columns.value, (col) => {
103
- if ((col.slots && col.slots.default) || col.formatter || col.cellRender) {
104
- if (!col.field) {
105
- col.field = '__holder__' + cols.length
80
+ };
81
+ const slotTitleColumns = computed(() => {
82
+ const cols: ColumnProps<D>[] = [];
83
+ eachTree(columns.value ?? [], (col) => {
84
+ if (col.slots && col.slots.title) {
85
+ if (!col.field) {
86
+ col.field = '__holder__' + cols.length;
87
+ }
88
+ cols.push(col);
106
89
  }
107
- cols.push(col)
108
- }
109
- })
110
- return cols
111
- })
112
- const pagination = reactive<IPage>({
113
- page: 1,
114
- size: pageConfig.value?.pageSize ?? 10,
115
- })
116
- const dataSeed = ref(0)
117
- const totalCount = ref(0)
118
- const tableData = ref<D[]>([]) as Ref<D[]>
119
- const mode = computed<'list' | 'pagination' | 'bad'>(() =>
90
+ });
91
+ return cols;
92
+ });
93
+ const formEl = ref();
94
+ const tableEl = ref();
95
+ const renderFormKey = ref(uuid_v4());
96
+ const renderTableKey = ref(uuid_v4());
97
+ const refreshForm = () => {
98
+ renderFormKey.value = uuid_v4();
99
+ };
100
+ const refreshTable = () => {
101
+ renderTableKey.value = uuid_v4();
102
+ };
103
+ const debounceRefreshForm = debounce(refreshForm, 100);
104
+ const debounceRefreshTable = debounce(refreshTable, 100);
105
+ const slotDefaultColumns = computed(() => {
106
+ const cols: ColumnProps<D>[] = [];
107
+ eachTree(columns.value ?? [], (col) => {
108
+ if ((col.slots && col.slots.default) || col.formatter || col.cellRender) {
109
+ if (!col.field) {
110
+ col.field = '__holder__' + cols.length;
111
+ }
112
+ cols.push(col);
113
+ }
114
+ });
115
+ return cols;
116
+ });
117
+ const pagination = reactive<IPage>({
118
+ page: 1,
119
+ size: pageConfig.value?.pageSize ?? 10,
120
+ });
121
+ const dataSeed = ref(0);
122
+ const totalCount = ref(0);
123
+ const tableData = ref<D[]>([]) as Ref<D[]>;
124
+ const mode = computed<'list' | 'pagination' | 'bad'>(() =>
120
125
  proxyConfig.value && proxyConfig.value.ajax
121
- ? pageConfig.value
122
- ? 'pagination'
123
- : 'list'
124
- : 'bad',
125
- )
126
- const attrs = useAttrs()
127
- const emit = defineEmits([
128
- 'query',
129
- 'reset',
130
- 'update:tableData',
131
- 'toolbarButtonClick',
132
- 'toolbarToolClick',
133
- 'pick',
134
- ])
135
- const toolBtnClick = (code: string) => {
136
- emit('toolbarButtonClick', {
137
- data: tableData.value,
138
- code,
139
- selectedKeys: selectedRowKeys.value,
140
- })
141
- innerToolbarHandler(code)
142
- }
143
- const toolToolClick = (code: string) => {
144
- emit('toolbarToolClick', { data: tableData.value, code, selectedKeys: selectedRowKeys.value })
145
- innerToolbarHandler(code)
146
- }
147
- const queryFormData = ref<Partial<F>>({}) as Ref<Partial<F>>
148
- const pickRow = ({ row, field }: { row: D; field: string }) => {
149
- emit('pick', { row, field })
150
- }
151
- const resetQueryFormData = (lazy?: boolean) => {
152
- if (formConfig.value && formConfig.value.items.length > 0) {
153
- if (formConfig.value.customReset) {
154
- formConfig.value.customReset()
155
- } else {
156
- const obj: Partial<F> = {}
157
- eachTree(formConfig.value.items, (item) => {
158
- if (item.field && item.itemRender) {
159
- if (valued(item.itemRender.defaultValue)) {
160
- obj[item.field] = item.itemRender.defaultValue
161
- } else {
162
- obj[item.field] = undefined
126
+ ? pageConfig.value
127
+ ? 'pagination'
128
+ : 'list'
129
+ : 'bad',
130
+ );
131
+ const attrs = useAttrs();
132
+ const emit = defineEmits([
133
+ 'query',
134
+ 'reset',
135
+ 'update:tableData',
136
+ 'toolbarButtonClick',
137
+ 'toolbarToolClick',
138
+ 'pick',
139
+ ]);
140
+ const toolBtnClick = (code: string) => {
141
+ emit('toolbarButtonClick', {
142
+ data: tableData.value,
143
+ code,
144
+ selectedKeys: selectedRowKeys.value,
145
+ });
146
+ innerToolbarHandler(code);
147
+ };
148
+ const debounceToolBtnClick = debounce(toolBtnClick, 100);
149
+ const toolBtnMenuClick = ({ key }) => debounceToolBtnClick(key);
150
+ const toolToolClick = (code: string) => {
151
+ emit('toolbarToolClick', { data: tableData.value, code, selectedKeys: selectedRowKeys.value });
152
+ innerToolbarHandler(code);
153
+ };
154
+ const debounceToolToolClick = debounce(toolToolClick, 100);
155
+ const queryFormData = ref<Partial<F>>({}) as Ref<Partial<F>>;
156
+ const pickRow = ({ row, field }: { row: D; field: string }) => {
157
+ emit('pick', { row, field });
158
+ };
159
+ const resetQueryFormData = (lazy?: boolean) => {
160
+ if (formConfig.value && formConfig.value.items.length > 0) {
161
+ if (formConfig.value.customReset) {
162
+ formConfig.value.customReset();
163
+ } else {
164
+ const obj: Partial<F> = {};
165
+ eachTree(formConfig.value.items, (item) => {
166
+ if (item.field && item.itemRender) {
167
+ if (valued(item.itemRender.defaultValue)) {
168
+ obj[item.field] = item.itemRender.defaultValue;
169
+ } else {
170
+ obj[item.field] = undefined;
171
+ }
163
172
  }
164
- }
165
- })
166
- queryFormData.value = obj
173
+ });
174
+ queryFormData.value = obj;
175
+ }
176
+ refreshForm();
177
+ }
178
+
179
+ pagination.page = 1;
180
+ if (!lazy) {
181
+ debounceFetchData();
167
182
  }
168
- refreshForm()
169
- }
170
-
171
- pagination.page = 1
172
- if (!lazy) {
173
- debounceFetchData()
174
- }
175
- }
176
- const handleResponse = (response: Recordable, pathConfig?: ResponsePathConfig<D>) =>
183
+ };
184
+ const handleResponse = (response: Recordable, pathConfig?: ResponsePathConfig<D>) =>
177
185
  pathConfig
178
- ? {
186
+ ? {
179
187
  list: isString(pathConfig.list)
180
- ? get(response, pathConfig.list)
181
- : isFunction(pathConfig.list)
182
- ? pathConfig.list(response)
183
- : undefined,
188
+ ? get(response, pathConfig.list)
189
+ : isFunction(pathConfig.list)
190
+ ? pathConfig.list(response)
191
+ : undefined,
184
192
  total: isString(pathConfig.total)
185
- ? get(response, pathConfig.total)
186
- : isFunction(pathConfig.total)
187
- ? pathConfig.total(response)
188
- : undefined,
193
+ ? get(response, pathConfig.total)
194
+ : isFunction(pathConfig.total)
195
+ ? pathConfig.total(response)
196
+ : undefined,
189
197
  result: isString(pathConfig.result)
190
- ? get(response, pathConfig.result)
191
- : isFunction(pathConfig.result)
192
- ? pathConfig.result(response)
193
- : undefined,
198
+ ? get(response, pathConfig.result)
199
+ : isFunction(pathConfig.result)
200
+ ? pathConfig.result(response)
201
+ : undefined,
194
202
  message: isString(pathConfig.message)
195
- ? get(response, pathConfig.message)
196
- : isFunction(pathConfig.message)
197
- ? pathConfig.message(response)
198
- : undefined,
203
+ ? get(response, pathConfig.message)
204
+ : isFunction(pathConfig.message)
205
+ ? pathConfig.message(response)
206
+ : undefined,
199
207
  }
200
- : {
208
+ : {
201
209
  list: response,
202
- }
203
- const enoughSpacing = ref(true)
204
- const reload = () => {
205
- return resetQueryFormData()
206
- }
207
- const resetPage = () => {
208
- pagination.page = 1
209
- selectedRowKeys.value = []
210
- return fetchData()
211
- }
212
- /**
213
- * @description
214
- * @param p
215
- * @param _filters todo filters
216
- * @param _sorter todo sorter
217
- */
218
- const handleTableChange = (p: TablePaginationConfig, _filters, _sorter) => {
219
- pagination.page = p.current!
220
- pagination.size = p.pageSize!
221
- return fetchData()
222
- }
210
+ };
211
+ const enoughSpacing = ref(true);
212
+ const reload = () => {
213
+ return resetQueryFormData();
214
+ };
215
+ const resetPage = () => {
216
+ pagination.page = 1;
217
+ selectedRowKeys.value = [];
218
+ return fetchData();
219
+ };
220
+ /**
221
+ * @description
222
+ * @param p
223
+ * @param _filters todo filters
224
+ * @param _sorter todo sorter
225
+ */
226
+ const handleTableChange = (p: TablePaginationConfig, _filters, _sorter) => {
227
+ pagination.page = p.current!;
228
+ pagination.size = p.pageSize!;
229
+ return fetchData();
230
+ };
223
231
 
224
- const fetchData = () =>
232
+ const fetchData = () =>
225
233
  new Promise<D[]>((resolve) => {
226
234
  if (mode.value !== 'bad') {
227
- loading.form = true
228
- loading.table = true
229
- const { ajax } = proxyConfig.value!
235
+ loading.form = true;
236
+ loading.table = true;
237
+ const { ajax } = proxyConfig.value!;
230
238
  ajax
231
- .query({
232
- form: queryFormData.value,
233
- page: pagination,
234
- })
235
- .then((response) => {
236
- const { list, total, result, message } = handleResponse(
237
- response,
238
- proxyConfig.value!.response,
239
- )
240
- if (list) {
241
- tableData.value = list as D[]
242
- dataSeed.value++
243
- } else if (result) {
244
- tableData.value = result as D[]
245
- totalCount.value = total ?? result.length
246
- dataSeed.value++
247
- } else {
248
- tableData.value = []
249
- dataSeed.value++
250
- if (message) {
251
- $message.warn(message)
252
- }
239
+ .query({
240
+ form: queryFormData.value,
241
+ page: pagination,
242
+ })
243
+ .then((response) => {
244
+ const { list, total, result, message } = handleResponse(
245
+ response,
246
+ proxyConfig.value!.response,
247
+ );
248
+ if (list) {
249
+ tableData.value = list as D[];
250
+ dataSeed.value++;
251
+ } else if (result) {
252
+ tableData.value = result as D[];
253
+ totalCount.value = total ?? result.length;
254
+ dataSeed.value++;
255
+ } else {
256
+ tableData.value = [];
257
+ dataSeed.value++;
258
+ if (message) {
259
+ $message.warn(message);
253
260
  }
254
- resolve(tableData.value as D[])
255
- })
256
- .catch((e) => {
257
- console.error('fetchData error', e)
258
- resolve([] as D[])
259
- })
260
- .finally(() => {
261
- loading.form = false
262
- loading.table = false
263
- })
261
+ }
262
+ resolve(tableData.value as D[]);
263
+ })
264
+ .catch((e) => {
265
+ console.error('fetchData error', e);
266
+ resolve([] as D[]);
267
+ })
268
+ .finally(() => {
269
+ loading.form = false;
270
+ loading.table = false;
271
+ });
264
272
  }
265
- })
266
- const debounceFetchData = debounce(fetchData, 160)
267
- const passQuery = (params: Partial<F>) => {
268
- Object.assign(queryFormData.value, params)
269
- pagination.page = 1
270
- return debounceFetchData()
271
- }
272
- const pg = computed(() =>
273
+ });
274
+ const debounceFetchData = debounce(fetchData, 160);
275
+ const passQuery = (params: Partial<F>, lazy?: boolean) => {
276
+ Object.assign(queryFormData.value, params);
277
+ pagination.page = 1;
278
+ return lazy ? Promise.resolve() : debounceFetchData();
279
+ };
280
+ const pg = computed(() =>
273
281
  mode.value === 'pagination'
274
- ? {
282
+ ? {
275
283
  current: pagination.page,
276
284
  total: totalCount.value,
277
285
  pageSize: pagination.size,
@@ -279,122 +287,157 @@ const pg = computed(() =>
279
287
  showSizeChanger: true,
280
288
  showTotal: (total: number) => `共${total}条数据`,
281
289
  }
282
- : false,
283
- )
284
- const defaultTableConfig = {
285
- size: 'small',
286
- sticky: true,
287
- transformCellText: ({ text }) => {
288
- return isArray(text) && text.length === 0 ? '-' : text
289
- },
290
- }
291
- const tc = computed(() =>
290
+ : false,
291
+ );
292
+ const defaultTableConfig = {
293
+ size: 'small',
294
+ sticky: true,
295
+ transformCellText: ({ text }) => {
296
+ return isArray(text) && text.length === 0 ? '-' : text;
297
+ },
298
+ };
299
+ const tc = computed(() =>
292
300
  merge(
293
- {},
294
- defaultTableConfig,
295
- tableConfig?.value ?? {},
296
- selectConfig.value
297
- ? {
298
- rowSelection: {
299
- type: selectConfig.value.multiple ? 'checkbox' : 'radio',
300
- preserveSelectedRowKeys: true,
301
- selectedRowKeys: selectedRowKeys.value,
302
- onChange: (selectedKeys: string[] | number[]) => {
303
- selectedRowKeys.value = selectedKeys
304
- },
301
+ {},
302
+ defaultTableConfig,
303
+ tableConfig?.value ?? {},
304
+ selectConfig.value
305
+ ? {
306
+ rowSelection: {
307
+ type: selectConfig.value.multiple ? 'checkbox' : 'radio',
308
+ preserveSelectedRowKeys: true,
309
+ selectedRowKeys: selectedRowKeys.value,
310
+ onChange: (selectedKeys: string[] | number[]) => {
311
+ selectedRowKeys.value = selectedKeys;
305
312
  },
306
- }
307
- : {},
313
+ getCheckboxProps: selectConfig.value.getCheckboxProps,
314
+ },
315
+ }
316
+ : {},
308
317
  ),
309
- )
310
- /*omit({labelCol:defaultLabelCol,...formConfig},['items'])*/
311
- const fc = computed(() => omit({ labelCol: defaultLabelCol, ...formConfig.value }, ['items']))
312
- const handleFormSubmit = () => {
313
- resetPage()
314
- }
318
+ );
319
+ /*omit({labelCol:defaultLabelCol,...formConfig},['items'])*/
320
+ const fc = computed(() => omit({ labelCol: defaultLabelCol, ...formConfig.value }, ['items']));
321
+ const handleFormSubmit = () => {
322
+ resetPage();
323
+ };
315
324
 
316
- watch(
325
+ watch(
317
326
  () => formConfig.value,
318
327
  () => {
319
- debounceRefreshForm()
328
+ debounceRefreshForm();
320
329
  },
321
330
  { deep: true },
322
- )
323
- watch(
331
+ );
332
+ watch(
324
333
  () => [columns.value, proxyConfig.value, toolbarConfig.value],
325
334
  () => {
326
- debounceRefreshTable()
335
+ debounceRefreshTable();
327
336
  },
328
337
  { deep: true },
329
- )
330
- defineExpose({
331
- commitProxy: {
332
- query: debounceFetchData,
333
- reload,
334
- reloadPage: resetPage,
335
- passQuery,
336
- },
337
- $table: computed(() => tableEl.value),
338
- selectedRowKeys: computed(() => selectedRowKeys.value),
339
- $form: computed(() => formEl.value),
340
- })
341
- onMounted(() => {
342
- /*判断本组件所在容器DOM*/
343
- const pNode = boxEl.value?.parentElement
344
- const ph = pNode ? window.getComputedStyle(pNode).height : '0px'
345
- renderHeight.value = props.renderY ?? toNumber(ph.replace('px', '')) - (props.fitHeight ?? 170) - (!!props.toolbarConfig ? 30 : 0) - (Math.ceil((props.formConfig?.items?.length ?? 0) / 4) * 35)
346
- enoughSpacing.value = toNumber(ph.replace('px', '')) > 600
347
- resetQueryFormData(props.manualFetch)
348
- })
338
+ );
339
+ defineExpose({
340
+ commitProxy: {
341
+ query: debounceFetchData,
342
+ reload,
343
+ reloadPage: resetPage,
344
+ passQuery,
345
+ },
346
+ $table: computed(() => tableEl.value),
347
+ selectedRowKeys: computed(() => selectedRowKeys.value),
348
+ $form: computed(() => formEl.value),
349
+ setLoadings: (value: boolean) => {
350
+ loading.form = value;
351
+ loading.table = value;
352
+ loading.toolbar = value;
353
+ },
354
+ });
355
+ onMounted(() => {
356
+ /*判断本组件所在容器DOM*/
357
+ const pNode = boxEl.value?.parentElement;
358
+ const ph = pNode ? window.getComputedStyle(pNode).height : '0px';
359
+ renderHeight.value =
360
+ props.renderY ??
361
+ toNumber(ph.replace('px', '')) -
362
+ (props.fitHeight ?? 170) -
363
+ (!!props.toolbarConfig ? 30 : 0) -
364
+ Math.ceil((props.formConfig?.items?.length ?? 0) / 4) * 35;
365
+ enoughSpacing.value = toNumber(ph.replace('px', '')) > 600;
366
+ resetQueryFormData(props.manualFetch);
367
+ });
349
368
  </script>
350
369
  <template>
351
370
  <div ref="boxEl" class="h-full p-wrapper flex flex-col gap-8px overflow-y-auto" v-bind="attrs">
352
371
  <div v-if="mode === 'bad'">请检查配置</div>
353
372
  <template v-else>
354
373
  <div
355
- v-if="formConfig?.items?.some((s: PFormItemProps<F>) => s.field && s.itemRender)"
356
- class="p-pane p-form-wrapper"
374
+ v-if="formConfig?.items?.some((s: PFormItemProps<F>) => s.field && s.itemRender)"
375
+ class="p-pane p-form-wrapper"
357
376
  >
358
377
  <a-spin :spinning="loading.form">
359
378
  <a-form
360
- :key="renderFormKey"
361
- ref="formEl"
362
- :model="queryFormData"
363
- v-bind="fc"
364
- @submit="handleFormSubmit"
379
+ :key="renderFormKey"
380
+ ref="formEl"
381
+ :model="queryFormData"
382
+ v-bind="fc"
383
+ @submit="handleFormSubmit"
365
384
  >
366
385
  <a-row :gutter="[6, 12]">
367
386
  <a-col
368
- v-for="(item, idx) in formConfig!.items"
369
- :key="'_col_' + idx"
370
- v-bind="item.col ?? (item.span ? { span: item.span } : defaultItemResponsive)"
387
+ v-for="(item, idx) in formConfig!.items"
388
+ :key="'_col_' + idx"
389
+ v-bind="item.col ?? (item.span ? { span: item.span } : defaultItemResponsive)"
371
390
  >
372
391
  <a-form-item
373
- :key="'_item_' + idx"
374
- :class="`p-content-align-${item.align ?? 'left'}`"
375
- :label="item.title"
376
- :name="item.field"
377
- v-bind="omit(item, ['field', 'title', 'span', 'col', 'itemRender'])"
392
+ :key="'_item_' + idx"
393
+ :class="`p-content-align-${item.align ?? 'left'} ${item.forceRequired ? 'p-required' : ''}`"
394
+ :label="item.title"
395
+ :name="item.field"
396
+ v-bind="
397
+ omit(item, [
398
+ 'field',
399
+ 'title',
400
+ 'span',
401
+ 'col',
402
+ 'itemRender',
403
+ 'forceRequired',
404
+ 'tooltip',
405
+ ])
406
+ "
378
407
  >
379
408
  <render-item-slots
380
- v-if="item.slots?.default"
381
- :key="'_sl_'+(item.field??'_')+'_'+idx"
382
- :form-data="queryFormData"
383
- :item="item"
384
- :pass-trigger="() => {}"
409
+ v-if="item.slots?.default"
410
+ :key="'_sl_' + (item.field ?? '_') + '_' + idx"
411
+ :form-data="queryFormData"
412
+ :item="item"
413
+ :pass-trigger="() => {}"
385
414
  />
386
415
  <render-ant-item
387
- v-else-if="item.itemRender?.name"
388
- :key="'_re_'+(item.field??'_')+'_'+idx"
389
- :default-handler="{
416
+ v-else-if="item.itemRender?.name"
417
+ :key="'_re_' + (item.field ?? '_') + '_' + idx"
418
+ :default-handler="{
390
419
  reset: () => {
391
420
  resetQueryFormData(!submitOnReset);
392
421
  },
393
422
  }"
394
- :item-render="item.itemRender"
395
- :render-form-params="{ data: queryFormData, field: item.field }"
423
+ :item-render="item.itemRender"
424
+ :render-form-params="{ data: queryFormData, field: item.field }"
396
425
  />
397
426
  <span v-else></span>
427
+ <template #tooltip v-if="item.tooltipConfig">
428
+ <a-tooltip
429
+ v-if="isFunction(item.tooltipConfig.title)"
430
+ v-bind="omit(item.tooltipConfig, ['title'])"
431
+ >
432
+ <InfoCircleOutlined class="cursor-pointer py-4x px-2x" />
433
+ <template #title>
434
+ <div v-html="item.tooltipConfig.title()"></div>
435
+ </template>
436
+ </a-tooltip>
437
+ <a-tooltip v-else v-bind="item.tooltipConfig">
438
+ <InfoCircleOutlined class="cursor-pointer py-4x px-2x" />
439
+ </a-tooltip>
440
+ </template>
398
441
  </a-form-item>
399
442
  </a-col>
400
443
  </a-row>
@@ -402,69 +445,87 @@ onMounted(() => {
402
445
  </a-spin>
403
446
  </div>
404
447
  <div
405
- v-if="toolbarConfig"
406
- class="p-toolbar-wrapper flex items-center w-full justify-between p-theme-bg pt-8px px-16px"
448
+ v-if="toolbarConfig"
449
+ class="p-toolbar-wrapper flex items-center w-full justify-between p-theme-bg pt-8px px-16px"
407
450
  >
408
451
  <div class="flex items-center flex-1 gap-4px">
409
452
  <template v-if="toolbarConfig.buttons && toolbarConfig.buttons.length > 0">
410
- <a-button
411
- v-for="(btn, idx) in toolbarConfig.buttons"
412
- :key="idx"
453
+ <template v-for="(btn, idx) in toolbarConfig.buttons" :key="idx">
454
+ <a-dropdown v-if="btn.dropdowns && btn.dropdowns.length">
455
+ <template #overlay>
456
+ <a-menu @click="toolBtnMenuClick">
457
+ <a-menu-item v-for="sub in btn.dropdowns" :key="sub.code"
458
+ >{{ sub.content }}
459
+ </a-menu-item>
460
+ </a-menu>
461
+ </template>
462
+ <a-button :type="btn.type" :size="btn.size ?? 'small'" :loading="loading.toolbar">
463
+ <Icon v-if="btn.icon" :icon="btn.icon" />
464
+ {{ btn.content }}
465
+ <DownOutlined />
466
+ </a-button>
467
+ </a-dropdown>
468
+ <a-button
469
+ v-else-if="btn.code"
413
470
  :type="btn.type"
414
- size="small"
415
- @click="toolBtnClick(btn.code)"
416
- >
417
- <Icon v-if="btn.icon" :icon="btn.icon"/>
418
- {{ btn.content }}
419
- </a-button>
471
+ :size="btn.size ?? 'small'"
472
+ :loading="loading.toolbar"
473
+ @click="debounceToolBtnClick(btn.code)"
474
+ >
475
+ <Icon v-if="btn.icon" :icon="btn.icon" />
476
+ {{ btn.content }}
477
+ </a-button>
478
+ <div v-else></div>
479
+ </template>
420
480
  </template>
421
481
  </div>
422
482
  <span class="flex items-center gap-4px">
423
483
  <template v-if="toolbarConfig.tools && toolbarConfig.tools.length > 0">
424
484
  <a-button
425
- v-for="(tool, idx) in toolbarConfig.tools"
426
- :key="idx"
427
- :type="tool.type"
428
- size="small"
429
- @click="toolToolClick(tool.code)"
485
+ v-for="(tool, idx) in toolbarConfig.tools"
486
+ :key="idx"
487
+ :type="tool.type"
488
+ size="small"
489
+ @click="debounceToolToolClick(tool.code)"
490
+ :loading="loading.toolbar"
430
491
  >
431
- <Icon :icon="tool.icon"/>
492
+ <Icon :icon="tool.icon" />
432
493
  </a-button>
433
494
  </template>
434
495
  </span>
435
496
  </div>
436
497
  <div :class="`p-pane flex-1 ${enoughSpacing ? 'h-0' : ''} p-${scrollMode ?? 'inner'}-scroll`">
437
498
  <a-table
438
- :key="renderTableKey + '_table'"
439
- :row-key="rowKey ?? 'id'"
440
- ref="tableEl"
441
- :columns="columns.map((c) => cleanCol(c as Recordable))"
442
- :data-source="tableData"
443
- :loading="loading.table"
444
- :pagination="pg"
445
- v-bind="tc"
446
- :scroll="{
499
+ :key="renderTableKey + '_table'"
500
+ :row-key="rowKey ?? 'id'"
501
+ ref="tableEl"
502
+ :columns="(columns ?? []).map((c) => cleanCol(c as Recordable))"
503
+ :data-source="tableData"
504
+ :loading="loading.table"
505
+ :pagination="pg"
506
+ v-bind="tc"
507
+ :scroll="{
447
508
  x: 'max-content',
448
509
  y: renderHeight,
449
510
  }"
450
- @change="handleTableChange"
511
+ @change="handleTableChange"
451
512
  >
452
513
  <template v-if="slotTitleColumns.length > 0" #headerCell="{ column }">
453
514
  <render-title-slots
454
- v-if="slotTitleColumns.some((s) => column.key && s.field === column.key)"
455
- :key="renderTableKey + '_title_' + dataSeed + '_slot_' + column.key"
456
- :column="slotTitleColumns.find((f) => column.key && f.field === column.key)!"
515
+ v-if="slotTitleColumns.some((s) => column.key && s.field === column.key)"
516
+ :key="renderTableKey + '_title_' + dataSeed + '_slot_' + column.key"
517
+ :column="slotTitleColumns.find((f) => column.key && f.field === column.key)!"
457
518
  />
458
519
  </template>
459
520
  <template v-if="slotDefaultColumns.length > 0" #bodyCell="{ column, record, index }">
460
521
  <render-default-slots
461
- v-if="slotDefaultColumns.some((s) => column.key && s.field === column.key)"
462
- :key="renderTableKey + '_cell_' + dataSeed + '_slot_' + column.key"
463
- :column="slotDefaultColumns.find((f) => column.key && f.field === column.key)!"
464
- :default-handler="{ pick: pickRow }"
465
- :row="record"
466
- :row-index="index"
467
- :table-data="tableData as Recordable[]"
522
+ v-if="slotDefaultColumns.some((s) => column.key && s.field === column.key)"
523
+ :key="renderTableKey + '_cell_' + dataSeed + '_slot_' + column.key"
524
+ :column="slotDefaultColumns.find((f) => column.key && f.field === column.key)!"
525
+ :default-handler="{ pick: pickRow }"
526
+ :row="record"
527
+ :row-index="index"
528
+ :table-data="tableData as Recordable[]"
468
529
  />
469
530
  </template>
470
531
  </a-table>