From 2b5c3671177f50c3e9b885e5cfb52657f031c575 Mon Sep 17 00:00:00 2001 From: luoer Date: Fri, 17 Nov 2023 17:38:34 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E8=A1=A8=E6=A0=BC?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/AnForm/components/Form.tsx | 7 +- src/components/AnForm/hooks/useForm.tsx | 19 +- src/components/AnTable/components/Table.tsx | 103 ++++++--- .../{useModiyForm.ts => useModiyForm.tsx} | 0 src/components/AnTable/hooks/useSearchForm.ts | 73 ------- .../AnTable/hooks/useSearchForm.tsx | 97 +++++++++ src/components/AnTable/hooks/useTable.tsx | 76 +++++-- .../AnTable/hooks/useTableColumn.tsx | 4 + .../AnTable/hooks/useTableColumnIndex.tsx | 179 ++++++++++++++++ .../AnTable/hooks/useTablePlugin.tsx | 107 ++++++++++ .../AnTable/plugins/useColumnConfig.tsx | 196 ++++++++++++++++++ .../AnTable/plugins/useRefreshPlugin.tsx | 29 +++ .../AnTable/plugins/useSelectionPlugin.tsx | 59 ++++++ src/pages/home/home.vue | 150 +++++++++++++- src/types/auto-component.d.ts | 10 +- 15 files changed, 977 insertions(+), 132 deletions(-) rename src/components/AnTable/hooks/{useModiyForm.ts => useModiyForm.tsx} (100%) delete mode 100644 src/components/AnTable/hooks/useSearchForm.ts create mode 100644 src/components/AnTable/hooks/useSearchForm.tsx create mode 100644 src/components/AnTable/hooks/useTableColumnIndex.tsx create mode 100644 src/components/AnTable/hooks/useTablePlugin.tsx create mode 100644 src/components/AnTable/plugins/useColumnConfig.tsx create mode 100644 src/components/AnTable/plugins/useRefreshPlugin.tsx create mode 100644 src/components/AnTable/plugins/useSelectionPlugin.tsx diff --git a/src/components/AnForm/components/Form.tsx b/src/components/AnForm/components/Form.tsx index e4f34a1..8e3bfc3 100644 --- a/src/components/AnForm/components/Form.tsx +++ b/src/components/AnForm/components/Form.tsx @@ -76,9 +76,10 @@ export const AnForm = defineComponent({ {this.items.map(item => ( ))} - {this.submit && this.submitItem && ( - - )} + {this.$slots.submit?.(this.model, this.validate) || + (this.submit && this.submitItem && ( + + ))} ); }, diff --git a/src/components/AnForm/hooks/useForm.tsx b/src/components/AnForm/hooks/useForm.tsx index 658959e..fb79de5 100644 --- a/src/components/AnForm/hooks/useForm.tsx +++ b/src/components/AnForm/hooks/useForm.tsx @@ -6,18 +6,29 @@ export type FormUseOptions = Partial> & { * 表单项 * @example * ```ts - * [ - * { + * [{ * field: 'name', * label: '昵称', * setter: 'input' - * } - * ] + * }] * ``` */ items?: FormItem[]; }; +export function useFormProps(options: FormUseOptions) { + const _model = options.model ?? {}; + const _items = options.items ?? []; + const items = useItems(_items, _model); + const props = reactive({ + formProps: options.formProps ?? {}, + items: items.value, + submit: options.submit, + model: _model, + }); + return props; +} + /** * 构建表单组件的参数 */ diff --git a/src/components/AnTable/components/Table.tsx b/src/components/AnTable/components/Table.tsx index bd7d9a2..f759c88 100644 --- a/src/components/AnTable/components/Table.tsx +++ b/src/components/AnTable/components/Table.tsx @@ -1,4 +1,4 @@ -import { IAnForm } from '@/components/AnForm'; +import { AnForm, AnFormInstance, IAnForm } from '@/components/AnForm'; import AniEmpty from '@/components/empty/AniEmpty.vue'; import { FormModalProps } from '@/components/form'; import { @@ -8,9 +8,9 @@ import { Button, PaginationProps, } from '@arco-design/web-vue'; -import { merge } from 'lodash-es'; +import { isArray, isFunction, merge } from 'lodash-es'; import { PropType, defineComponent, ref } from 'vue'; -import { TableColumnConfig } from './TableColumnConfig'; +import { PluginContainer } from '../hooks/useTablePlugin'; type DataFn = (filter: { page: number; size: number; [key: string]: any }) => any | Promise; @@ -37,7 +37,7 @@ export const AnTable = defineComponent({ /** * 分页配置 */ - pagination: { + paging: { type: Object as PropType, }, /** @@ -64,24 +64,31 @@ export const AnTable = defineComponent({ tableProps: { type: Object as PropType['$props']>, }, + /** + * 插件列表 + */ + pluginer: { + type: Object as PropType, + required: true, + }, }, setup(props) { const loading = ref(false); const tableRef = ref>(); const renderData = ref([]); - const reloadData = () => loadData(); + const searchRef = ref(null); const useTablePaging = () => { const getPaging = () => { return { - page: props.pagination?.current ?? 1, - size: props.pagination?.pageSize ?? 10, + page: props.paging?.current ?? 1, + size: props.paging?.pageSize ?? 10, }; }; const setPaging = (paging: PaginationProps) => { - if (props.pagination) { - merge(props.pagination, paging); + if (props.paging) { + merge(props.paging, paging); } }; @@ -98,16 +105,24 @@ export const AnTable = defineComponent({ const { getPaging, setPaging, resetPaging } = useTablePaging(); - /** - * 加载数据 - * @param pagination 自定义分页 - */ const loadData = async () => { + if (await searchRef.value?.validate()) { + return; + } + const paging = getPaging(); - if (typeof props.data === 'function') { + const search = searchRef.value?.getModel() ?? {}; + + if (isArray(props.data)) { + // todo + } + + if (isFunction(props.data)) { try { loading.value = true; - const resData = await props.data({ ...paging }); + let params = { ...search, ...paging }; + params = props.pluginer?.callBeforeSearchHook(params) ?? params; + const resData = await props.data(params); const { data = [], total = 0 } = resData?.data || {}; renderData.value = data; setPaging({ total }); @@ -119,6 +134,15 @@ export const AnTable = defineComponent({ } }; + const reload = () => { + setPaging({ current: 1, pageSize: 10 }); + return loadData(); + }; + + const refresh = () => { + return loadData(); + }; + watchEffect(() => { if (Array.isArray(props.data)) { renderData.value = props.data; @@ -131,11 +155,13 @@ export const AnTable = defineComponent({ }); const onPageChange = (page: number) => { + props.pluginer?.callPageChangeHook(page); setPaging({ current: page }); loadData(); }; const onPageSizeChange = (size: number) => { + props.pluginer?.callSizeChangeHook(size); setPaging({ current: 1, pageSize: size }); loadData(); }; @@ -143,13 +169,18 @@ export const AnTable = defineComponent({ const state = { loading, tableRef, + searchRef, renderData, loadData, - reloadData, + reload, + refresh, onPageChange, onPageSizeChange, + props, }; + props.pluginer?.callSetupHook(state); + provide('ref:table', { ...state, ...props }); return state; @@ -159,16 +190,36 @@ export const AnTable = defineComponent({ return (
-
- -
-
-
- - + {this.pluginer?.actions && ( +
+ {this.pluginer.actions.map(Action => ( + + ))}
+ )} +
+ {this.search && ( + + {{ + submit: () => ( + + ), + }} + + )} +
+
+
{this.pluginer?.widgets && this.pluginer.widgets?.map(Widget => )}
@@ -179,7 +230,7 @@ export const AnTable = defineComponent({ {...this.tableProps} ref="tableRef" loading={this.loading} - pagination={this.pagination?.hide ? false : this.pagination} + pagination={this.paging?.hide ? false : this.paging} data={this.renderData} columns={this.columns} onPageChange={this.onPageChange} diff --git a/src/components/AnTable/hooks/useModiyForm.ts b/src/components/AnTable/hooks/useModiyForm.tsx similarity index 100% rename from src/components/AnTable/hooks/useModiyForm.ts rename to src/components/AnTable/hooks/useModiyForm.tsx diff --git a/src/components/AnTable/hooks/useSearchForm.ts b/src/components/AnTable/hooks/useSearchForm.ts deleted file mode 100644 index 60e4872..0000000 --- a/src/components/AnTable/hooks/useSearchForm.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { merge } from "lodash-es"; -import { FormUseOptions } from "../../AnForm"; -import { IAnFormItem } from "../../AnForm/components/FormItem"; -import { FormItem } from "../../AnForm/hooks/useItems"; - -export type ExtendFormItem = Partial< - FormItem & { - /** - * 从新建弹窗继承表单项 - * @example 'name' - */ - extend: string; - } ->; - -type SearchFormItem = ExtendFormItem & { - /** - * 是否点击图标后进行搜索 - * @default false - */ - searchable?: boolean; - /** - * 是否回车后进行查询 - * @default false - */ - enterable?: boolean; -}; - -export type SearchForm = Omit & { - /** - * 搜索表单项 - */ - items?: SearchFormItem[]; - /** - * 是否隐藏查询按钮 - * @default false - */ - hideSearch?: boolean; -}; - -export function useSearchForm(search: SearchForm, extendItems: IAnFormItem[] = []) { - const data: any[] = []; - const { items = [], hideSearch, ...rest } = search; - - for (const item of items) { - const { searchable, enterable, ...itemRest } = item; - let _item; - if (item.extend) { - const extend = extendItems.find((i) => i.field === item.extend); - if (extend) { - _item = merge({}, extend, itemRest); - } - } - if (searchable) { - (item as any).nodeProps.onSearch = () => null; - } - if (enterable) { - (item as any).nodeProps.onPressEnter = () => null; - } - data.push(_item); - } - - if (hideSearch) { - const index = data.findIndex((i) => i.type === "submit"); - if (index > -1) { - data.splice(index, 1); - } - } - - return { - items: data, - }; -} diff --git a/src/components/AnTable/hooks/useSearchForm.tsx b/src/components/AnTable/hooks/useSearchForm.tsx new file mode 100644 index 0000000..a06faf7 --- /dev/null +++ b/src/components/AnTable/hooks/useSearchForm.tsx @@ -0,0 +1,97 @@ +import { defaultsDeep, isArray, merge } from 'lodash-es'; +import { FormUseOptions } from '../../AnForm'; +import { IAnFormItem } from '../../AnForm/components/FormItem'; +import { FormItem, useItems } from '../../AnForm/hooks/useItems'; + +export type ExtendFormItem = Partial< + FormItem & { + /** + * 从新建弹窗继承表单项 + * @example 'name' + */ + extend: string; + } +>; + +type SearchFormItem = ExtendFormItem & { + /** + * 是否点击图标后进行搜索 + * @default false + */ + searchable?: boolean; + /** + * 是否回车后进行查询 + * @default false + */ + enterable?: boolean; +}; + +export type SearchFormObject = Omit & { + /** + * 搜索表单项 + */ + items?: SearchFormItem[]; + /** + * 是否隐藏查询按钮 + * @default false + */ + hideSearch?: boolean; +}; + +export type SearchForm = SearchFormObject | SearchFormItem[]; + +export function useSearchForm(search?: SearchForm, extendItems: IAnFormItem[] = []) { + if (!search) { + return ref(); + } + + if (isArray(search)) { + search = { items: search }; + } + + const { items: _items = [], hideSearch, model: _model, formProps: _formProps } = search; + const extendMap = extendItems.reduce((m, v) => ((m[v.field] = v), m), {} as Record); + + const props = ref({ + items: [] as IAnFormItem[], + model: _model ?? {}, + formProps: defaultsDeep({}, _formProps, { layout: 'inline' }), + }); + + const defualts: Partial = { + setter: 'input', + itemProps: { + hideLabel: true, + }, + setterProps: {}, + }; + + const items: any[] = []; + for (const _item of _items) { + const { searchable, enterable, field, extend, ...itemRest } = _item; + if ((field || extend) === 'submit' && hideSearch) { + continue; + } + let item: IAnFormItem = defaultsDeep({}, itemRest, defualts); + if (extend) { + const extendItem = extendMap[extend]; + if (extendItem) { + item = merge({}, extendItem, itemRest); + } + } + if (searchable) { + (item as any).nodeProps.onSearch = () => null; + } + if (enterable) { + (item as any).nodeProps.onPressEnter = () => null; + } + if (item.setterProps) { + (item.setterProps as any).placeholder = (item.setterProps as any).placeholder ?? item.label; + } + items.push(item); + } + + props.value.items = useItems(items, props.value.model).value; + + return props; +} diff --git a/src/components/AnTable/hooks/useTable.tsx b/src/components/AnTable/hooks/useTable.tsx index 031a895..56125c1 100644 --- a/src/components/AnTable/hooks/useTable.tsx +++ b/src/components/AnTable/hooks/useTable.tsx @@ -1,50 +1,98 @@ -import { FormModalUseOptions } from '../../AnForm/hooks/useFormModal'; +import { FormModalUseOptions, useFormModal } from '../../AnForm/hooks/useFormModal'; import { AnTable, TableProps } from '../components/Table'; import { ModifyForm } from './useModiyForm'; -import { SearchForm } from './useSearchForm'; +import { SearchForm, useSearchForm } from './useSearchForm'; import { TableColumn, useTableColumns } from './useTableColumn'; +import { AnTablePlugin, PluginContainer } from './useTablePlugin'; -export interface TableUseOptions extends Pick { +export interface TableUseOptions extends Pick { + /** + * 唯一ID + * @example + * ```ts + * 'UserTable' + * ``` + */ + id?: string; + /** + * 插件列表 + * @example + * ```ts + * [useRefresh()] + * ``` + */ + plugins?: AnTablePlugin[]; /** * 表格列 + * @example + * ```ts + * [{ + * dataIndex: 'title', + * title: '标题' + * }] + * ``` */ columns?: TableColumn[]; /** * 搜索表单 + * @example + * ```ts + * [{ + * field: 'name', + * label: '用户名称', + * setter: 'input' + * }] + * ``` */ search?: SearchForm; /** * 新建弹窗 + * @example + * ```ts + * { + * title: '添加用户', + * items: [], + * submit: (model) => {} + * } + * ``` */ create?: FormModalUseOptions; /** - * 新建弹窗 + * 修改弹窗 + * @example + * ```ts + * { + * extend: true, // 基于新建弹窗扩展 + * title: '修改用户', + * submit: (model) => {} + * } + * ``` */ modify?: ModifyForm; - /** - * 详情弹窗 - */ - detail?: any; - /** - * 批量删除 - */ - delete?: any; } export function useTable(options: TableUseOptions) { + const pluginer = new PluginContainer(options.plugins ?? []); + + options = pluginer.callOptionsHook(options); + const { columns } = useTableColumns(options.columns ?? []); const data = ref(options.data); - const pagination = ref({ hide: false, showTotal: true, showPageSize: true, ...(options.pagination ?? {}) }); + const pagination = ref({ hide: false, showTotal: true, showPageSize: true, ...(options.paging ?? {}) }); const tableProps = ref(options.tableProps ?? {}); const tableRef = ref | null>(null); + const searchProps = useSearchForm(options.search); + // const create = options.create && useFormModal(options.create); const AnTabler = () => ( (tableRef.value = el)} columns={columns.value} data={data.value} - pagination={pagination.value} + paging={pagination.value} tableProps={tableProps.value} + search={searchProps.value} + pluginer={pluginer} > ); diff --git a/src/components/AnTable/hooks/useTableColumn.tsx b/src/components/AnTable/hooks/useTableColumn.tsx index 6bba4e2..a6a933f 100644 --- a/src/components/AnTable/hooks/useTableColumn.tsx +++ b/src/components/AnTable/hooks/useTableColumn.tsx @@ -69,6 +69,10 @@ interface TableButtonColumn { type: 'button'; /** * 按钮列表 + * @example + * ```ts + * [{ text: '删除', onClick: (args) => api.user.rmUser(args.record.id) }] + * ``` */ buttons: TableColumnButton[]; } diff --git a/src/components/AnTable/hooks/useTableColumnIndex.tsx b/src/components/AnTable/hooks/useTableColumnIndex.tsx new file mode 100644 index 0000000..4ad7632 --- /dev/null +++ b/src/components/AnTable/hooks/useTableColumnIndex.tsx @@ -0,0 +1,179 @@ +import { Button, Checkbox, Divider, InputNumber, Popover, Scrollbar, Tag } from '@arco-design/web-vue'; +import { PropType } from 'vue'; + +interface Item { + dataIndex: string; + enable: boolean; + autoWidth: boolean; + width: number; + editable: boolean; + title: string; +} + +export const TableColumnConfig = defineComponent({ + props: { + columns: { + type: Object as PropType, + required: true, + }, + }, + setup(props) { + const checkAll = ref(false); + const visible = ref(false); + const items = ref([]); + const checked = computed(() => items.value.filter(i => i.enable)); + + const indeterminate = computed(() => { + const check = checked.value.length; + const total = items.value.length; + return 0 < check && check < total; + }); + + watch( + () => visible.value, + value => { + if (value) { + init(); + } else { + } + } + ); + + const init = () => { + const list: Item[] = []; + for (const column of props.columns) { + list.push({ + dataIndex: column.dataIndex, + title: column.title, + enable: true, + autoWidth: !column.width, + width: column.width ?? 60, + editable: !column.configable, + }); + } + items.value = list; + }; + + const onItemChange = () => { + if (checked.value.length === 0) { + checkAll.value = false; + return; + } + if (checked.value.length === items.value.length) { + checkAll.value = true; + } + }; + + const onCheckAllChange = (value: any) => { + for (const item of items.value) { + if (item.editable) { + item.enable = value; + } + } + }; + + const onReset = () => { + visible.value = false; + }; + + const onConfirm = () => { + visible.value = false; + }; + + const onItemUp = (index: number) => { + [items.value[index - 1], items.value[index]] = [items.value[index], items.value[index - 1]]; + }; + + const onItemDown = (index: number) => { + [items.value[index + 1], items.value[index]] = [items.value[index], items.value[index + 1]]; + }; + + return () => ( + + {{ + default: () => ( + + ), + content: () => ( + <> +
设置表格列
+ +
    + {items.value.map((item, index) => ( +
  • +
    + + {item.title} + + +
    +
    + + {{ + checkbox: ({ checked }: any) => ( + + 自适应 + + ), + }} + + + + 像素 +
    +
  • + ))} +
+
+
+
+ + 全选 + + + ({checked.value.length}/{items.value.length}) + +
+
+ + +
+
+ + ), + }} +
+ ); + }, +}); diff --git a/src/components/AnTable/hooks/useTablePlugin.tsx b/src/components/AnTable/hooks/useTablePlugin.tsx new file mode 100644 index 0000000..4f60ee1 --- /dev/null +++ b/src/components/AnTable/hooks/useTablePlugin.tsx @@ -0,0 +1,107 @@ +import { TableUseOptions } from './useTable'; + +export interface AnTablePlugin { + /** + * 插件ID(唯一) + * @example + * ```ts + * 'Plugin:Refresh' + * ``` + */ + id: string; + /** + * 提供给其他插件使用的变量 + * @example + * ```ts + * { isOk: true } + * ``` + */ + provide?: Recordable; + /** + * 组件钩子 + */ + onSetup?: (context: any) => void; + /** + * 钩子 + */ + options?: (options: TableUseOptions) => TableUseOptions | null | undefined | void; + /** + * 添加部件栏组件 + */ + widget?: () => any; + /** + * 添加操作栏组件 + */ + action?: () => any; + /** + * 搜索前处理 + * + */ + onBeforeSearch?: (args: { page: number; size: number; [key: string]: any }) => Recordable | null | undefined | void; + onPageChange?: (page: number) => void; + onSizeChange?: (size: number) => void; +} + +export class PluginContainer { + actions: any[] = []; + widgets: any[] = []; + + constructor(private plugins: AnTablePlugin[]) { + for (const plugin of plugins) { + const action = plugin.action?.(); + const widget = plugin.widget?.(); + if (action) { + this.actions.push(action); + } + if (widget) { + this.widgets.push(widget); + } + } + } + + callSetupHook(context: any) { + for (const plugin of this.plugins) { + plugin.onSetup?.(context); + } + } + + callOptionsHook(options: any) { + for (const plugin of this.plugins) { + options = plugin.options?.(options) ?? options; + } + return options; + } + + callActionHook(options: any) { + for (const plugin of this.plugins) { + options = plugin.options?.(options) ?? options; + } + return options; + } + + callWidgetHook(options: any) { + for (const plugin of this.plugins) { + options = plugin.options?.(options) ?? options; + } + return options; + } + + callBeforeSearchHook(options: any) { + for (const plugin of this.plugins) { + options = plugin.onBeforeSearch?.(options) ?? options; + } + return options; + } + + callPageChangeHook(page: number) { + for (const plugin of this.plugins) { + plugin.onPageChange?.(page); + } + } + + callSizeChangeHook(page: number) { + for (const plugin of this.plugins) { + plugin.onPageChange?.(page); + } + } +} diff --git a/src/components/AnTable/plugins/useColumnConfig.tsx b/src/components/AnTable/plugins/useColumnConfig.tsx new file mode 100644 index 0000000..e48e653 --- /dev/null +++ b/src/components/AnTable/plugins/useColumnConfig.tsx @@ -0,0 +1,196 @@ +import { Button, Checkbox, Divider, InputNumber, Popover, Scrollbar, Tag } from '@arco-design/web-vue'; +import { PropType } from 'vue'; +import { AnTablePlugin } from '../hooks/useTablePlugin'; + +interface Item { + dataIndex: string; + enable: boolean; + autoWidth: boolean; + width: number; + editable: boolean; + title: string; +} + +export const TableColumnConfig = defineComponent({ + props: { + columns: { + type: Object as PropType, + required: true, + }, + }, + setup(props) { + const checkAll = ref(false); + const visible = ref(false); + const items = ref([]); + const checked = computed(() => items.value.filter(i => i.enable)); + const indeterminate = computed(() => { + const check = checked.value.length; + const total = items.value.length; + return 0 < check && check < total; + }); + + watch( + () => visible.value, + value => { + if (value) { + init(); + } else { + } + } + ); + + const init = () => { + const list: Item[] = []; + for (const column of props.columns) { + list.push({ + dataIndex: column.dataIndex, + title: column.title, + enable: true, + autoWidth: !column.width, + width: column.width ?? 60, + editable: !column.configable, + }); + } + items.value = list; + }; + + const onItemChange = () => { + if (checked.value.length === 0) { + checkAll.value = false; + return; + } + if (checked.value.length === items.value.length) { + checkAll.value = true; + } + }; + + const onCheckAllChange = (value: any) => { + for (const item of items.value) { + if (item.editable) { + item.enable = value; + } + } + }; + + const onReset = () => { + visible.value = false; + }; + + const onConfirm = () => { + visible.value = false; + }; + + const onItemUp = (index: number) => { + [items.value[index - 1], items.value[index]] = [items.value[index], items.value[index - 1]]; + }; + + const onItemDown = (index: number) => { + [items.value[index + 1], items.value[index]] = [items.value[index], items.value[index + 1]]; + }; + + return () => ( + + {{ + default: () => ( + + ), + content: () => ( + <> +
设置表格列
+ +
    + {items.value.map((item, index) => ( +
  • +
    + + {item.title} + + +
    +
    + + {{ + checkbox: ({ checked }: any) => ( + + 自适应 + + ), + }} + + + + 像素 +
    +
  • + ))} +
+
+
+
+ + 全选 + + + ({checked.value.length}/{items.value.length}) + +
+
+ + +
+
+ + ), + }} +
+ ); + }, +}); + +/** + * 插件:表格列配置 + * @description 配置ID将缓存结果在本地 + */ +export function useColumnConfig(): AnTablePlugin { + let context: any; + return { + id: "columnconfig", + onSetup(args) { + context = args; + }, + widget() { + return () => ; + }, + }; +} diff --git a/src/components/AnTable/plugins/useRefreshPlugin.tsx b/src/components/AnTable/plugins/useRefreshPlugin.tsx new file mode 100644 index 0000000..e183518 --- /dev/null +++ b/src/components/AnTable/plugins/useRefreshPlugin.tsx @@ -0,0 +1,29 @@ +import { Button } from '@arco-design/web-vue'; +import { AnTablePlugin } from '../hooks/useTablePlugin'; + +/** + * 插件:添加刷新按钮 + * @description 位于搜索栏附近 + */ +export function useRefresh(): AnTablePlugin { + let context: any = {}; + + return { + id: 'refresh', + onSetup(ctx) { + context = ctx; + }, + widget() { + return () => { + const { loading, refresh } = context; + return ( + + ); + }; + }, + }; +} diff --git a/src/components/AnTable/plugins/useSelectionPlugin.tsx b/src/components/AnTable/plugins/useSelectionPlugin.tsx new file mode 100644 index 0000000..a1f1806 --- /dev/null +++ b/src/components/AnTable/plugins/useSelectionPlugin.tsx @@ -0,0 +1,59 @@ +import { cloneDeep, defaultsDeep, merge } from 'lodash-es'; +import { TableUseOptions } from '../hooks/useTable'; +import { AnTablePlugin } from '../hooks/useTablePlugin'; + +// declare module '@/components/AnTable/hooks/useTable' { +// interface TableUseOptions { +// todo?: string; +// } +// } + +const defaults: TableUseOptions = { + tableProps: { + rowSelection: { + showCheckedAll: true, + }, + }, +}; + +export function useSelection({ key = 'id', mode = 'key' } = {}): AnTablePlugin { + const selected = ref([]); + + return { + id: 'selection', + provide: { + selected, + }, + options(options) { + const opts: TableUseOptions = defaultsDeep({}, defaults); + + if (!opts.tableProps!.rowKey) { + opts.tableProps!.rowKey = key; + } + + if (mode === 'key') { + opts.tableProps!.onSelectionChange = rowkeys => { + selected.value = rowkeys as any[]; + }; + } + + if (mode === 'row') { + opts.tableProps!.onSelect = (rowkeys, rowkey, record) => { + const index = selected.value.findIndex((i: any) => i[key] == record[key]); + if (index > -1) { + selected.value.splice(index, 1); + } + }; + opts.tableProps!.onSelectAll = checked => { + if (checked) { + selected.value = cloneDeep([]); + } else { + selected.value = []; + } + }; + } + + return merge(options, opts); + }, + }; +} diff --git a/src/pages/home/home.vue b/src/pages/home/home.vue index fa248aa..b942e35 100644 --- a/src/pages/home/home.vue +++ b/src/pages/home/home.vue @@ -1,6 +1,5 @@