diff --git a/src/components/form/form-item.tsx b/src/components/form/form-item.tsx index 5647ae0..49e1b09 100644 --- a/src/components/form/form-item.tsx +++ b/src/components/form/form-item.tsx @@ -1,80 +1,90 @@ -import { FormItem as BaseFormItem, FieldRule, FormItemInstance, SelectOptionData } from "@arco-design/web-vue"; -import { NodeType, NodeUnion, nodeMap } from "./form-node"; -import { RuleMap } from "./form-rules"; - -export type FieldStringRule = keyof typeof RuleMap; -export type FieldObjectRule = FieldRule & { - disable?: (arg: { item: IFormItem; model: Record }) => boolean; -}; -export type FieldRuleType = FieldStringRule | FieldObjectRule; +import { FormItem as BaseFormItem, FormItemInstance, SelectOptionData } from "@arco-design/web-vue"; +import { NodeUnion, nodeMap } from "./form-node"; +import { FieldObjectRule, FieldRuleMap, Rule } from "./form-rules"; +import { PropType } from "vue"; +import { strOrFnRender } from "./util"; /** * 表单项 */ -export const FormItem = (props: any, { emit }: any) => { - const { item } = props; - const args = { - ...props, - field: item.field, - }; +export const FormItem = defineComponent({ + name: "AppnifyFormItem", + props: { + /** + * 表单项 + */ + item: { + type: Object as PropType, + required: true, + }, + /** + * 表单项数组 + */ + items: { + type: Array as PropType, + required: true, + }, + /** + * 表单数据 + */ + model: { + type: Object as PropType, + required: true, + }, + }, + setup(props) { + /** + * 校验规则 + */ + const rules = computed(() => props.item.rules?.filter((i) => !i.disable?.(props))); - const rules = computed(() => { - const result = []; - if (item.required) { - result.push(RuleMap.required); + /** + * 是否禁用 + */ + const disabled = computed(() => Boolean(props.item.disable?.(props))); + + if (props.item.visible && !props.item.visible(props as any)) { + return null; } - item.rules?.forEach((rule: any) => { - if (typeof rule === "string") { - result.push(RuleMap[rule as FieldStringRule]); - return; - } - if (!rule.disable) { - result.push(rule); - return; - } - if (!rule.disable({ model: props.model, item, items: props.items })) { - result.push(rule); - } - }); - return result; - }); - const disabled = computed(() => { - if (item.disable === undefined) { - return false; - } - if (typeof item.disable === "function") { - return item.disable(args); - } - return item.disable; - }); + /** + * 渲染函数 + */ + const render = () => { + const Item = props.item.component as any; + if (props.item.type === "custom") { + return ; + } + return ; + }; - if (item.visible && !item.visible(args)) { - return null; - } + /** + * 标签渲染 + */ + const label = strOrFnRender(props.item.label, props); - return ( - - {{ - default: () => { - if (item.component) { - return ; - } - const comp = nodeMap[item.type as NodeType]?.component; - if (!comp) { - return null; - } - if (item.type === "submit") { - return emit("submit")} onCancel={emit("cancel")} />; - } - return ; - }, - label: item.label && (() => (typeof item.label === "string" ? item.label : item.label?.(args))), - help: item.help && (() => (typeof item.help === "string" ? item.help : item.help?.(args))), - extra: item.extra && (() => (typeof item.extra === "string" ? item.extra : item.extra?.(args))), - }} - - ); + /** + * 帮助信息渲染函数 + */ + const help = strOrFnRender(props.item.help, props); + + /** + * 额外信息渲染函数 + */ + const extra = strOrFnRender(props.item.extra, props); + + return () => ( + + {{ default: render, label, help, extra }} + + ); + }, +}); + +type FormItemFnArg = { + item: T; + items: T[]; + model: Record; }; type FormItemBase = { @@ -105,7 +115,7 @@ type FormItemBase = { * 标签名 * @description 同FormItem组件的label属性 */ - label?: string | ((args: { item: IFormItem; model: Record }) => any); + label?: string | ((args: FormItemFnArg) => any); /** * 传递给`FormItem`组件的参数 @@ -136,45 +146,45 @@ type FormItemBase = { *``` * @see https://arco.design/vue/component/form#FieldRule */ - rules?: FieldRuleType[]; + rules?: FieldObjectRule[]; /** * 是否可见 * @description 动态控制表单项是否可见 */ - visible?: (arg: { item: IFormItem; model: Record }) => boolean; + visible?: (arg: FormItemFnArg) => boolean; /** * 是否禁用 * @description 动态控制表单项是否禁用 */ - disable?: (arg: { item: IFormItem; model: Record }) => boolean; + disable?: (arg: FormItemFnArg) => boolean; /** * 选项,数组或者函数 * @description 用于下拉框、单选框、多选框等组件, 支持动态加载 */ - options?: SelectOptionData[] | ((arg: { item: IFormItem; model: Record }) => Promise); + options?: SelectOptionData[] | ((arg: FormItemFnArg) => Promise); /** * 表单项内容的渲染函数 * @description 用于自定义表单项内容 */ - component?: (args: { item: IFormItem; model: Record; field: string }) => any; + component?: (args: FormItemFnArg) => any; /** * 帮助提示 * @description 同FormItem组件的help插槽 * @see https://arco.design/vue/component/form#form-item%20Slots */ - help?: string | ((args: { item: IFormItem; model: Record }) => any); + help?: string | ((args: FormItemFnArg) => any); /** * 额外内容 * @description 同FormItem组件的extra插槽 * @see https://arco.design/vue/component/form#form-item%20Slots */ - extra?: string | ((args: { item: IFormItem; model: Record }) => any); + extra?: string | ((args: FormItemFnArg) => any); }; export type IFormItem = FormItemBase & NodeUnion; diff --git a/src/components/form/form-node.tsx b/src/components/form/form-node.tsx index 2b0eb5f..990d844 100644 --- a/src/components/form/form-node.tsx +++ b/src/components/form/form-node.tsx @@ -224,7 +224,7 @@ export type NodeUnion = { /** * 输入框类型,默认为`input` */ - type: key; + type?: key; /** * 传递给`type`属性对应组件的参数 */ diff --git a/src/components/form/form-rules.ts b/src/components/form/form-rules.ts index ab02694..4ef0a4f 100644 --- a/src/components/form/form-rules.ts +++ b/src/components/form/form-rules.ts @@ -1,8 +1,10 @@ import { FieldRule } from "@arco-design/web-vue"; +import { isString } from "lodash-es"; -const defineRuleMap = >(ruleMap: T) => ruleMap; - -export const RuleMap = defineRuleMap({ +/** + * 内置规则 + */ +export const FieldRuleMap = defineRuleMap({ required: { required: true, message: "该项不能为空", @@ -44,3 +46,47 @@ export const RuleMap = defineRuleMap({ message: "至少包含大写字母、小写字母、数字和特殊字符", }, }); + +/** + * 字符串形式(枚举) + */ +export type FieldStringRule = keyof typeof FieldRuleMap; + +/** + * 对象形式 + */ +export type FieldObjectRule = FieldRule & { + disable?: (arg: { item: T; model: Record }) => boolean; +}; + +/** + * 完整类型 + */ +export type Rule = FieldStringRule | FieldObjectRule; + +/** + * 助手函数(获得TS提示) + */ +function defineRuleMap>(ruleMap: T) { + return ruleMap; +} + +/** + * 获取表单规则 + * @param item 表单项 + * @returns + */ +export const useFieldRules = [] }>(item: T) => { + const rules: FieldObjectRule[] = []; + if (item.required) { + rules.push(FieldRuleMap.required); + } + for (const rule of item.rules ?? []) { + if (isString(rule)) { + rules.push(FieldRuleMap[rule]); + } else { + rules.push(rule); + } + } + return rules; +}; diff --git a/src/components/form/form.tsx b/src/components/form/form.tsx index 6a8ec04..e4aa3b9 100644 --- a/src/components/form/form.tsx +++ b/src/components/form/form.tsx @@ -1,8 +1,8 @@ import { Form as BaseForm, FormInstance as BaseFormInstance, Message } from "@arco-design/web-vue"; -import { assign, cloneDeep, defaultsDeep } from "lodash-es"; +import { assign, cloneDeep, defaultsDeep, merge } from "lodash-es"; import { PropType } from "vue"; import { FormItem, IFormItem } from "./form-item"; -import { NodeType, nodeMap } from "./form-node"; +import { nodeMap } from "./form-node"; import { config } from "./form-config"; type SubmitFn = (arg: { model: Record; items: IFormItem[] }) => Promise; @@ -11,13 +11,13 @@ type SubmitFn = (arg: { model: Record; items: IFormItem[] }) => Pro * 表单组件 */ export const Form = defineComponent({ - name: "Form", + name: "AppnifyForm", props: { /** * 表单数据 */ model: { - type: Object as PropType>, + type: Object as PropType, default: () => reactive({}), }, /** @@ -45,11 +45,11 @@ export const Form = defineComponent({ const formRef = ref>(); const loading = ref(false); - props.items.forEach((item: any) => { - const node = nodeMap[item.type as NodeType]; + for (const item of props.items) { + const node = nodeMap[item.type] as any; defaultsDeep(item, { nodeProps: node?.nodeProps ?? {} }); (node as any)?.init?.({ item, model: props.model }); - }); + } const getItem = (field: string) => { return props.items.find((item) => item.field === field); @@ -64,7 +64,7 @@ export const Form = defineComponent({ }; const resetModel = () => { - assign(props.model, model); + assign(props.model, merge({}, model)); }; const submitForm = async () => { @@ -84,7 +84,7 @@ export const Form = defineComponent({ } }; - return { + const injected = { formRef, loading, getItem, @@ -93,6 +93,10 @@ export const Form = defineComponent({ setModel, getModel, }; + + provide("form1", injected); + + return injected; }, render() { (this.items as any).instance = this; @@ -104,9 +108,9 @@ export const Form = defineComponent({ }; return ( - + {this.items.map((item) => ( - + ))} ); diff --git a/src/components/form/hooks/types/Form.ts b/src/components/form/hooks/types/Form.ts new file mode 100644 index 0000000..0844c44 --- /dev/null +++ b/src/components/form/hooks/types/Form.ts @@ -0,0 +1,21 @@ +import { FormInstance } from "@arco-design/web-vue"; +import { FormItem, FormItemFnArg } from "./FormItem"; + +export type UseForm = { + /** + * 表单数据模型 + */ + model?: Recordable; + /** + * 表单项数组 + */ + items?: FormItem[]; + /** + * 提交表单 + */ + submit?: (arg: Omit) => PromiseLike; + /** + * 表单实例属性 + */ + formProps?: Partial; +}; diff --git a/src/components/form/hooks/types/FormItem.ts b/src/components/form/hooks/types/FormItem.ts new file mode 100644 index 0000000..4ad4b6c --- /dev/null +++ b/src/components/form/hooks/types/FormItem.ts @@ -0,0 +1,115 @@ +import { FormItemInstance, SelectOptionData } from "@arco-design/web-vue"; +import { Rule } from "../useRules"; +import { NodeUnion } from "../../form-node"; + +/** + * 函数参数 + */ +export type FormItemFnArg = { + item: T; + items: T[]; + model: Recordable; +}; + +/** + * 表单项基础 + */ +type BaseFormItem = { + /** + * 传递给`FormItem`组件的参数 + * @description 部分属性会不可用,如field、label、required、rules、disabled等 + */ + itemProps?: Omit; + + /** + * 是否可见 + * @description 动态控制表单项是否可见 + */ + visible?: (arg: FormItemFnArg) => boolean; + + /** + * 是否禁用 + * @description 动态控制表单项是否禁用 + */ + disable?: (arg: FormItemFnArg) => boolean; + + /** + * 选项,数组或者函数 + * @description 用于下拉框、单选框、多选框等组件, 支持动态加载 + */ + options?: SelectOptionData[] | ((arg: FormItemFnArg) => PromiseLike); +}; + +/** + * 表单项插槽 + */ +type BaseFormItemSlots = { + /** + * 渲染函数 + * @description 用于自定义表单项内容 + */ + render?: (args: FormItemFnArg) => any; + + /** + * 标签名 + * @description 同FormItem组件的label属性 + */ + label?: string | ((args: FormItemFnArg) => any); + + /** + * 帮助提示 + * @description 同FormItem组件的help插槽 + * @see https://arco.design/vue/component/form#form-item%20Slots + */ + help?: string | ((args: FormItemFnArg) => any); + + /** + * 额外内容 + * @description 同FormItem组件的extra插槽 + * @see https://arco.design/vue/component/form#form-item%20Slots + */ + extra?: string | ((args: FormItemFnArg) => any); +}; + +/** + * 表单项校验 + */ +type BaseFormItemRules = { + /** + * 是否必填 + * @description 默认值为false + */ + required?: boolean; + + /** + * 校验规则 + * @description 支持字符串(内置)、对象形式 + * @see https://arco.design/vue/component/form#FieldRule + */ + rules?: Rule[]; +}; + +/** + * 表单项数据 + */ +type BaseFormItemModel = { + /** + * 字段名,特殊语法在提交时会自动转换。 + * @example + * ```typescript + * '[v1,v2]' => { v1: 1, v2: 2 } + * ``` + */ + field: string; + + /** + * 初始值 + * @description 若指定该参数,将覆盖model中的同名属性。 + */ + initial?: any; +}; + +/** + * 表单项 + */ +export type FormItem = BaseFormItem & BaseFormItemModel & BaseFormItemRules & BaseFormItemSlots & NodeUnion; diff --git a/src/components/form/hooks/useForm.ts b/src/components/form/hooks/useForm.ts new file mode 100644 index 0000000..176ab17 --- /dev/null +++ b/src/components/form/hooks/useForm.ts @@ -0,0 +1,22 @@ +import { useModel } from "./useModel"; +import { useItems } from "./useItems"; +import { UseOptions } from "./interface"; +import { UseForm } from "./types/Form"; + +/** + * 构建表单组件的参数 + */ +export const useForm = (options: T) => { + const initModel = options.model ?? {}; + const { items, updateItemOptions } = useItems(options.items ?? [], initModel, Boolean(options.submit)); + const { model, resetModel, setModel, getModel } = useModel(initModel); + + return { + model, + items, + resetModel, + setModel, + getModel, + updateItemOptions, + }; +}; diff --git a/src/components/form/hooks/useItems.ts b/src/components/form/hooks/useItems.ts new file mode 100644 index 0000000..e63015a --- /dev/null +++ b/src/components/form/hooks/useItems.ts @@ -0,0 +1,52 @@ +import { merge } from "lodash-es"; +import { FormItem } from "./types/FormItem"; +import { nodeMap } from "../form-node"; +import { useRules } from "./useRules"; + +const ITEM: Partial = { + type: "input", +}; + +const SUBMIT_ITEM: FormItem = { + field: "id", + type: "submit", + itemProps: { + hideLabel: true, + }, +}; + +export function useItems(list: FormItem[], model: Recordable, submit: boolean) { + const items = ref([]); + let hasSubmit = false; + + for (const item of list) { + let target: Recordable = merge({}, nodeMap[item.type ?? "input"]); + + if (item.type === "submit") { + target = merge(item, SUBMIT_ITEM); + hasSubmit = true; + } + + target = merge(item, item); + target.rules = useRules(item); + + model[item.field] = model[item.field] ?? item.initial; + items.value.push(target as any); + } + + if (submit && !hasSubmit) { + items.value.push(merge({}, SUBMIT_ITEM)); + } + + const updateItemOptions = (field: string) => { + const item = items.value.find((i) => i.field === field); + if (item) { + (item as any)._updateOptions?.(); + } + }; + + return { + items, + updateItemOptions, + }; +} diff --git a/src/components/form/hooks/useModel.ts b/src/components/form/hooks/useModel.ts new file mode 100644 index 0000000..cbde7da --- /dev/null +++ b/src/components/form/hooks/useModel.ts @@ -0,0 +1,63 @@ +import { cloneDeep } from "lodash-es"; + +function formatModel(model: Recordable) { + const data: Recordable = {}; + for (const [key, val] of Object.entries(model)) { + // 数组类型 + if (/^\[.+\]$/.test(key)) { + const subkeysStr = key.replaceAll(/\s/g, "").match(/^\[(.+)\]$/)?.[1]; + if (!subkeysStr) { + data[key] = val; + continue; + } + const subkeys = subkeysStr.split(","); + subkeys.forEach((subkey, index) => { + if (/(.+)?:number$/.test(subkey)) { + subkey = subkey.replace(/:number$/, ""); + data[subkey] = val?.[index] && Number(val[index]); + return; + } + if (/(.+)?:boolean$/.test(subkey)) { + subkey = subkey.replace(/:boolean$/, ""); + data[subkey] = val?.[index] && Boolean(val[index]); + return; + } + data[subkey] = val?.[index]; + }); + continue; + } + // 默认类型 + data[key] = val; + } + return data; +} + +/** + * 表单数据管理 + * @param initial 初始值 + * @returns + */ +export function useModel(initial: Recordable) { + const model = ref({}); + + const resetModel = () => { + model.value = cloneDeep(initial); + }; + + const setModel = (data: Recordable) => { + for (const key of Object.keys(model.value)) { + model.value[key] = data[key]; + } + }; + + const getModel = () => { + return formatModel(model.value); + }; + + return { + model, + resetModel, + setModel, + getModel, + }; +} diff --git a/src/components/form/hooks/useRules.ts b/src/components/form/hooks/useRules.ts new file mode 100644 index 0000000..6182148 --- /dev/null +++ b/src/components/form/hooks/useRules.ts @@ -0,0 +1,92 @@ +import { FieldRule } from "@arco-design/web-vue"; +import { isString } from "lodash-es"; + +/** + * 内置规则 + */ +export const FieldRuleMap = defineRuleMap({ + required: { + required: true, + message: "该项不能为空", + }, + string: { + type: "string", + message: "请输入字符串", + }, + number: { + type: "number", + message: "请输入数字", + }, + email: { + type: "email", + message: "邮箱格式错误,示例: xx@abc.com", + }, + url: { + type: "url", + message: "URL格式错误, 示例: www.abc.com", + }, + ip: { + type: "ip", + message: "IP格式错误, 示例: 101.10.10.30", + }, + phone: { + match: /^(?:(?:\+|00)86)?1\d{10}$/, + message: "手机格式错误, 示例(11位): 15912345678", + }, + idcard: { + match: /^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/, + message: "身份证格式错误, 长度为15或18位", + }, + alphabet: { + match: /^[a-zA-Z]\w{4,15}$/, + message: "请输入英文字母, 长度为4~15位", + }, + password: { + match: /^\S*(?=\S{6,})(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[!@#$%^&*? ])\S*$/, + message: "至少包含大写字母、小写字母、数字和特殊字符", + }, +}); + +/** + * 字符串形式(枚举) + */ +export type FieldStringRule = keyof typeof FieldRuleMap; + +/** + * 对象形式 + */ +export type FieldObjectRule = FieldRule & { + disable?: (arg: { item: T; model: Record }) => boolean; +}; + +/** + * 完整类型 + */ +export type Rule = FieldStringRule | FieldObjectRule; + +/** + * 助手函数(获得TS提示) + */ +function defineRuleMap>(ruleMap: T) { + return ruleMap; +} + +/** + * 获取表单规则 + * @param item 表单项 + * @returns + */ +export const useRules = [] }>(item: T) => { + const rules: FieldObjectRule[] = []; + if (item.required) { + rules.push(FieldRuleMap.required); + } + for (const rule of item.rules ?? []) { + if (isString(rule)) { + rules.push(FieldRuleMap[rule]); + } else { + rules.push(rule); + } + } + return rules; +}; diff --git a/src/components/form/use-form.tsx b/src/components/form/use-form.tsx index dff6b47..3b1f570 100644 --- a/src/components/form/use-form.tsx +++ b/src/components/form/use-form.tsx @@ -1,6 +1,7 @@ import { FormInstance } from "@arco-design/web-vue"; import { IFormItem } from "./form-item"; -import { merge } from "lodash-es"; +import { useModel } from "./hooks/useModel"; +import { useItems } from "./hooks/useItems"; export type Options = { /** @@ -26,34 +27,16 @@ export type Options = { * @see src/components/form/use-form.tsx */ export const useForm = (options: Options) => { - const { model: _model = {} } = options; - const model: Record = { id: undefined, ..._model }; - const items: IFormItem[] = []; + const initModel = options.model ?? {}; + const { items, updateItemOptions } = useItems(options.items, initModel, Boolean(options.submit)); + const { model, resetModel, setModel, getModel } = useModel(initModel); - for (const item of options.items) { - if (!item.nodeProps) { - item.nodeProps = {} as any; - } - model[item.field] = model[item.field] ?? item.initial; - items.push(item); - } - - if (options.submit) { - const submit = items.find((item) => item.type === "submit") || {}; - items.push( - merge( - {}, - { - field: "id", - type: "submit", - itemProps: { - hideLabel: true, - }, - }, - submit - ) as any - ); - } - - return reactive({ ...options, model, items }) as any; + return { + model, + items, + resetModel, + setModel, + getModel, + updateItemOptions, + }; }; diff --git a/src/components/form/util.ts b/src/components/form/util.ts index 33d1d49..25bcf36 100644 --- a/src/components/form/util.ts +++ b/src/components/form/util.ts @@ -32,3 +32,21 @@ export function setModel(model: any, data: Record) { } } } + +/** + * 字符串或函数渲染 + * @param value 值 + * @param arg 参数 + * @returns + */ +export function strOrFnRender(value?: string | Function, arg?: any) { + if (typeof value === "string") { + return () => value; + } + if (typeof value === "function") { + return () => value(arg); + } + return null; +} + +export const falsy = () => false; diff --git a/src/components/table/table.tsx b/src/components/table/table.tsx index a5b17b9..933f3c6 100644 --- a/src/components/table/table.tsx +++ b/src/components/table/table.tsx @@ -1,11 +1,16 @@ -import { TableColumnData as BaseColumn, TableData as BaseData, Table as BaseTable } from "@arco-design/web-vue"; -import { merge } from "lodash-es"; +import { + TableColumnData as BaseColumn, + TableData as BaseData, + Table as BaseTable, + PaginationProps, +} from "@arco-design/web-vue"; +import { cloneDeep, isBoolean, isObject, merge } from "lodash-es"; import { PropType, computed, defineComponent, reactive, ref } from "vue"; import AniEmpty from "../empty/AniEmpty.vue"; import { Form, FormInstance, FormModal, FormModalInstance, FormModalProps, FormProps } from "../form"; import { config } from "./table.config"; -type DataFn = (search: Record, paging: { page: number; size: number }) => Promise; +type DataFn = (search: Record, paging: { page: number; size: number }) => PromiseLike; /** * 表格组件 @@ -32,8 +37,7 @@ export const Table = defineComponent({ * 分页参数配置 */ pagination: { - type: Object as PropType, - default: () => reactive(config.pagination), + type: [Boolean, Object] as PropType, }, /** * 搜索表单配置 @@ -73,6 +77,7 @@ export const Table = defineComponent({ const createRef = ref(); const modifyRef = ref(); const renderData = ref([]); + const paging = ref(merge({}, isObject(props.pagination) ? props.pagination : config.pagination)); const inlined = computed(() => (props.search?.items?.length ?? 0) <= config.searchInlineCount); const reloadData = () => loadData({ current: 1, pageSize: 10 }); const openModifyModal = (data: any) => modifyRef.value?.open(data); @@ -81,9 +86,8 @@ export const Table = defineComponent({ * 加载数据 * @param pagination 自定义分页 */ - const loadData = async (pagination: Partial = {}) => { - const merged = { ...props.pagination, ...pagination }; - const paging = { page: merged.current, size: merged.pageSize }; + const loadData = async (pagination: Partial = {}) => { + const { current: page = 1, pageSize: size = 10 } = { ...paging.value, ...pagination }; const model = searchRef.value?.getModel() ?? {}; // 本地加载 @@ -98,21 +102,21 @@ export const Table = defineComponent({ }); }); renderData.value = data; - props.pagination.total = renderData.value.length; - props.pagination.current = 1; + paging.value.total = renderData.value.length; + paging.value.current = 1; } // 远程加载 if (typeof props.data === "function") { try { loading.value = true; - const resData = await props.data(model, paging); + const resData = await props.data(model, { page, size }); const { data = [], total = 0 } = resData?.data || {}; renderData.value = data; - props.pagination.total = total; - props.pagination.current = paging.page; + paging.value.total = total; + paging.value.current = page; } catch (e) { - // todo + console.log(e); } finally { loading.value = false; } @@ -122,8 +126,8 @@ export const Table = defineComponent({ watchEffect(() => { if (Array.isArray(props.data)) { renderData.value = props.data; - props.pagination.total = props.data.length; - props.pagination.current = 1; + paging.value.total = props.data.length; + paging.value.current = 1; } }); @@ -143,6 +147,7 @@ export const Table = defineComponent({ createRef, modifyRef, renderData, + paging, loadData, reloadData, openModifyModal, @@ -177,7 +182,10 @@ export const Table = defineComponent({ )} {this.$slots.action?.()} -
{this.inlined &&
}
+
+ {this.inlined &&
} + {this.$slots.tool?.(this.renderData)} +
this.loadData({ current })} diff --git a/src/types/vite-env.d.ts b/src/types/vite-env.d.ts index ac9107e..eeec177 100644 --- a/src/types/vite-env.d.ts +++ b/src/types/vite-env.d.ts @@ -7,7 +7,9 @@ declare module "*.vue" { export default component; } -declare module 'numeral' { - const numeral: any +declare module "numeral" { + const numeral: any; export default numeral; -} \ No newline at end of file +} + +type Recordable = Record; \ No newline at end of file