Showing
4 changed files
with
202 additions
and
31 deletions
| 1 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
| 2 | import { ReloadOutlined } from '@ant-design/icons-vue'; | 2 | import { ReloadOutlined } from '@ant-design/icons-vue'; |
| 3 | - import { Button, List, Tooltip } from 'ant-design-vue'; | 3 | + import { Button, List, Space, Tooltip } from 'ant-design-vue'; |
| 4 | import { reactive } from 'vue'; | 4 | import { reactive } from 'vue'; |
| 5 | import { ref } from 'vue'; | 5 | import { ref } from 'vue'; |
| 6 | + import { BasicForm, useForm } from '../../Form'; | ||
| 7 | + import { basicListProps } from './props'; | ||
| 8 | + import { ExtractPropTypes } from 'vue'; | ||
| 9 | + defineProps<ExtractPropTypes<typeof basicListProps>>(); | ||
| 10 | + | ||
| 11 | + const [registerForm] = useForm({ | ||
| 12 | + schemas: [ | ||
| 13 | + { | ||
| 14 | + field: '123', | ||
| 15 | + label: 'test', | ||
| 16 | + component: 'Input', | ||
| 17 | + }, | ||
| 18 | + ], | ||
| 19 | + labelWidth: 100, | ||
| 20 | + layout: 'inline', | ||
| 21 | + baseColProps: { span: 8 }, | ||
| 22 | + showAdvancedButton: true, | ||
| 23 | + compact: true, | ||
| 24 | + }); | ||
| 6 | 25 | ||
| 7 | const listElRef = ref<Nullable<ComponentElRef>>(null); | 26 | const listElRef = ref<Nullable<ComponentElRef>>(null); |
| 8 | 27 | ||
| 9 | - const pagination = reactive({}); | 28 | + const pagination = reactive({ size: 'small' }); |
| 10 | 29 | ||
| 11 | const loading = ref(false); | 30 | const loading = ref(false); |
| 12 | 31 | ||
| @@ -16,31 +35,48 @@ | @@ -16,31 +35,48 @@ | ||
| 16 | </script> | 35 | </script> |
| 17 | 36 | ||
| 18 | <template> | 37 | <template> |
| 19 | - <section class="bg-light-50 my-4 p-4 x dark:text-gray-300 dark:bg-dark-900"> | ||
| 20 | - <List | ||
| 21 | - ref="listElRef" | ||
| 22 | - :dataSource="dataSource" | ||
| 23 | - :pagination="pagination" | ||
| 24 | - :grid="{ gutter: 16, xs: 1, sm: 1, md: 1, lg: 2, xl: 2, xxl: 3, column: 3 }" | ||
| 25 | - :loading="loading" | ||
| 26 | - > | ||
| 27 | - <template #header> | ||
| 28 | - <section class="flex justify-between gap-4 min-h-12 items-center"> | ||
| 29 | - <div class="text-lg font-semibold"> | ||
| 30 | - <span>任务列表</span> | ||
| 31 | - </div> | ||
| 32 | - <Tooltip title="刷新"> | ||
| 33 | - <Button type="primary" @click="getDataSource"> | ||
| 34 | - <ReloadOutlined :spin="loading" /> | ||
| 35 | - </Button> | ||
| 36 | - </Tooltip> | ||
| 37 | - </section> | ||
| 38 | - </template> | ||
| 39 | - <template #renderItem="{ item }"> | ||
| 40 | - <List.Item :key="item.id"> | ||
| 41 | - <slot name="item" :item="item"></slot> | ||
| 42 | - </List.Item> | ||
| 43 | - </template> | ||
| 44 | - </List> | 38 | + <section class="basic-list-container"> |
| 39 | + <section class="mb-4 bg-light-50 p-2 x dark:text-gray-300 dark:bg-dark-900"> | ||
| 40 | + <BasicForm @register="registerForm" /> | ||
| 41 | + </section> | ||
| 42 | + <section class="bg-light-50 p-2 x dark:text-gray-300 dark:bg-dark-900"> | ||
| 43 | + <List | ||
| 44 | + ref="listElRef" | ||
| 45 | + :dataSource="dataSource" | ||
| 46 | + :pagination="pagination" | ||
| 47 | + :grid="{ gutter: 16, xs: 1, sm: 1, md: 1, lg: 2, xl: 2, xxl: 3, column: 3 }" | ||
| 48 | + :loading="loading" | ||
| 49 | + > | ||
| 50 | + <template #header> | ||
| 51 | + <section class="flex px-5 justify-between gap-4 min-h-12 items-center"> | ||
| 52 | + <div class="text-lg font-semibold"> | ||
| 53 | + <span>任务列表</span> | ||
| 54 | + </div> | ||
| 55 | + <Space> | ||
| 56 | + <slot name="toolbar"></slot> | ||
| 57 | + <Tooltip title="刷新"> | ||
| 58 | + <Button type="primary" @click="getDataSource"> | ||
| 59 | + <ReloadOutlined :spin="loading" /> | ||
| 60 | + </Button> | ||
| 61 | + </Tooltip> | ||
| 62 | + </Space> | ||
| 63 | + </section> | ||
| 64 | + </template> | ||
| 65 | + <template #renderItem="{ item }"> | ||
| 66 | + <List.Item :key="item.id"> | ||
| 67 | + <slot name="item" :item="item"></slot> | ||
| 68 | + </List.Item> | ||
| 69 | + </template> | ||
| 70 | + </List> | ||
| 71 | + </section> | ||
| 45 | </section> | 72 | </section> |
| 46 | </template> | 73 | </template> |
| 74 | + | ||
| 75 | +<style lang="less" scoped> | ||
| 76 | + .basic-list-container { | ||
| 77 | + :deep(.ant-list-header) { | ||
| 78 | + padding-top: 0; | ||
| 79 | + padding-bottom: 8px; | ||
| 80 | + } | ||
| 81 | + } | ||
| 82 | +</style> |
src/components/List/src/hooks/useListForm.ts
0 → 100644
| 1 | +import type { ComputedRef, Slots } from 'vue'; | ||
| 2 | +import type { BasicTableProps, FetchParams } from '../types/table'; | ||
| 3 | +import { unref, computed } from 'vue'; | ||
| 4 | +import type { FormProps } from '/@/components/Form'; | ||
| 5 | +import { isFunction } from '/@/utils/is'; | ||
| 6 | + | ||
| 7 | +export function useTableForm( | ||
| 8 | + propsRef: ComputedRef<BasicTableProps>, | ||
| 9 | + slots: Slots, | ||
| 10 | + fetch: (opt?: FetchParams | undefined) => Promise<void>, | ||
| 11 | + getLoading: ComputedRef<boolean | undefined> | ||
| 12 | +) { | ||
| 13 | + const getFormProps = computed((): Partial<FormProps> => { | ||
| 14 | + const { formConfig } = unref(propsRef); | ||
| 15 | + const { submitButtonOptions } = formConfig || {}; | ||
| 16 | + return { | ||
| 17 | + showAdvancedButton: true, | ||
| 18 | + ...formConfig, | ||
| 19 | + submitButtonOptions: { loading: unref(getLoading), ...submitButtonOptions }, | ||
| 20 | + compact: true, | ||
| 21 | + }; | ||
| 22 | + }); | ||
| 23 | + | ||
| 24 | + const getFormSlotKeys: ComputedRef<string[]> = computed(() => { | ||
| 25 | + const keys = Object.keys(slots); | ||
| 26 | + return keys | ||
| 27 | + .map((item) => (item.startsWith('form-') ? item : null)) | ||
| 28 | + .filter((item) => !!item) as string[]; | ||
| 29 | + }); | ||
| 30 | + | ||
| 31 | + function replaceFormSlotKey(key: string) { | ||
| 32 | + if (!key) return ''; | ||
| 33 | + return key?.replace?.(/form\-/, '') ?? ''; | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + function handleSearchInfoChange(info: Recordable) { | ||
| 37 | + const { handleSearchInfoFn } = unref(propsRef); | ||
| 38 | + if (handleSearchInfoFn && isFunction(handleSearchInfoFn)) { | ||
| 39 | + info = handleSearchInfoFn(info) || info; | ||
| 40 | + } | ||
| 41 | + fetch({ searchInfo: info, page: 1 }); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + return { | ||
| 45 | + getFormProps, | ||
| 46 | + replaceFormSlotKey, | ||
| 47 | + getFormSlotKeys, | ||
| 48 | + handleSearchInfoChange, | ||
| 49 | + }; | ||
| 50 | +} |
| 1 | -import { ComponentPropsOptions } from 'vue'; | 1 | +import { FormProps } from '../../Form'; |
| 2 | 2 | ||
| 3 | -export const props = { | 3 | +export const basicListProps = { |
| 4 | + immediate: { | ||
| 5 | + type: Boolean, | ||
| 6 | + default: true, | ||
| 7 | + }, | ||
| 8 | + searchInfo: { | ||
| 9 | + type: Object as PropType<Recordable>, | ||
| 10 | + }, | ||
| 11 | + formConfig: { | ||
| 12 | + type: Object as PropType<Partial<FormProps>>, | ||
| 13 | + default: null, | ||
| 14 | + }, | ||
| 4 | title: { | 15 | title: { |
| 5 | type: String, | 16 | type: String, |
| 6 | }, | 17 | }, |
| 7 | -} as ComponentPropsOptions; | 18 | + titleHelpMessage: { |
| 19 | + type: [String, Array] as PropType<string | string[]>, | ||
| 20 | + }, | ||
| 21 | + autoCreateKey: { | ||
| 22 | + type: Boolean, | ||
| 23 | + default: true, | ||
| 24 | + }, | ||
| 25 | + api: { | ||
| 26 | + type: Function as PropType<Fn<any, Promise<any>>>, | ||
| 27 | + }, | ||
| 28 | + beforeFetch: { | ||
| 29 | + type: Function as PropType<Fn>, | ||
| 30 | + }, | ||
| 31 | + afterFetch: { | ||
| 32 | + type: Function as PropType<Fn>, | ||
| 33 | + }, | ||
| 34 | + handleSearchInfoFn: { | ||
| 35 | + type: Function as PropType<Fn>, | ||
| 36 | + }, | ||
| 37 | +}; |
src/components/List/src/types/list.ts
0 → 100644
| 1 | +import { FormProps } from 'ant-design-vue/es/form/Form'; | ||
| 2 | + | ||
| 3 | +export interface BasicListProps { | ||
| 4 | + /** | ||
| 5 | + * @description 立即执行 | ||
| 6 | + */ | ||
| 7 | + immediate?: boolean; | ||
| 8 | + | ||
| 9 | + /** | ||
| 10 | + * @description 额外的请求参数 | ||
| 11 | + */ | ||
| 12 | + searchInfo?: Recordable; | ||
| 13 | + | ||
| 14 | + /** | ||
| 15 | + * @description 搜索表单 | ||
| 16 | + */ | ||
| 17 | + formConfig?: Partial<FormProps>; | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * @description 列表名 | ||
| 21 | + */ | ||
| 22 | + title?: string; | ||
| 23 | + | ||
| 24 | + /** | ||
| 25 | + * @description 列表标题帮助信息 | ||
| 26 | + */ | ||
| 27 | + titleHelpMessage?: string | string[]; | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * @description 自动创建key | ||
| 31 | + */ | ||
| 32 | + autoCreateKey?: boolean; | ||
| 33 | + | ||
| 34 | + /** | ||
| 35 | + * @description 请求接口 | ||
| 36 | + * @param args | ||
| 37 | + * @returns | ||
| 38 | + */ | ||
| 39 | + api?: (...args: any) => Promise<any>; | ||
| 40 | + | ||
| 41 | + /** | ||
| 42 | + * @description 请求前对参数处理 | ||
| 43 | + */ | ||
| 44 | + beforeFetch?: Fn; | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * @description 请求后对结果处理 | ||
| 48 | + */ | ||
| 49 | + afterFetch?: Fn; | ||
| 50 | + | ||
| 51 | + /** | ||
| 52 | + * @description 请求前处理搜索参数 | ||
| 53 | + */ | ||
| 54 | + handleSearchInfoFn?: Fn; | ||
| 55 | +} |