diff --git a/src/hooks/async/useLoading.ts b/src/hooks/async/useLoading.ts new file mode 100644 index 0000000..19a2178 --- /dev/null +++ b/src/hooks/async/useLoading.ts @@ -0,0 +1,22 @@ +export function useLoading(initialValue = false) { + const loading = ref(initialValue); + + const setLoading = (value: boolean) => { + loading.value = value; + }; + + const withLoading = async (task: () => Promise) => { + loading.value = true; + try { + return await task(); + } finally { + loading.value = false; + } + }; + + return { + loading, + setLoading, + withLoading + }; +} diff --git a/src/hooks/dialog/useDialogState.ts b/src/hooks/dialog/useDialogState.ts new file mode 100644 index 0000000..015bffa --- /dev/null +++ b/src/hooks/dialog/useDialogState.ts @@ -0,0 +1,33 @@ +export function useDialogState(initialTitle = '') { + const dialog = reactive({ + visible: false, + title: initialTitle + }); + + const openDialog = (title?: string) => { + if (title !== undefined) { + dialog.title = title; + } + dialog.visible = true; + }; + + const closeDialog = () => { + dialog.visible = false; + }; + + const toggleDialog = () => { + dialog.visible = !dialog.visible; + }; + + const setTitle = (title: string) => { + dialog.title = title; + }; + + return { + dialog, + openDialog, + closeDialog, + toggleDialog, + setTitle + }; +} diff --git a/src/hooks/dialog/useFormDialog.ts b/src/hooks/dialog/useFormDialog.ts new file mode 100644 index 0000000..c8916d3 --- /dev/null +++ b/src/hooks/dialog/useFormDialog.ts @@ -0,0 +1,42 @@ +import type { Ref } from 'vue'; +import { useDialogState } from './useDialogState'; + +interface UseFormDialogOptions> { + form: Ref; + formRef?: Ref; + initialFormData: T; + initialTitle?: string; +} + +export function useFormDialog>(options: UseFormDialogOptions) { + const { form, formRef, initialFormData, initialTitle } = options; + const { dialog, openDialog, closeDialog, setTitle } = useDialogState(initialTitle); + + const resetForm = () => { + form.value = { ...initialFormData }; + formRef?.value?.resetFields(); + formRef?.value?.clearValidate?.(); + }; + + const openFormDialog = (title?: string) => { + resetForm(); + openDialog(title); + }; + + const showDialog = (title?: string) => { + openDialog(title); + }; + + const closeFormDialog = () => { + closeDialog(); + }; + + return { + dialog, + resetForm, + openDialog: openFormDialog, + showDialog, + closeDialog: closeFormDialog, + setTitle + }; +} diff --git a/src/hooks/form/useSearchReset.ts b/src/hooks/form/useSearchReset.ts new file mode 100644 index 0000000..8c261d3 --- /dev/null +++ b/src/hooks/form/useSearchReset.ts @@ -0,0 +1,43 @@ +import type { Ref } from 'vue'; + +interface UseSearchResetOptions> { + queryFormRef: Ref; + queryParams?: Ref; + pageNumKey?: keyof T; + pageSizeKey?: keyof T; + initialPageNum?: number; + initialPageSize?: number; + resetExtras?: () => void; + afterReset?: () => void; +} + +export function useSearchReset>(options: UseSearchResetOptions) { + const { + queryFormRef, + queryParams, + pageNumKey, + pageSizeKey, + initialPageNum = 1, + initialPageSize, + resetExtras, + afterReset + } = options; + + const resetQuery = () => { + queryFormRef.value?.resetFields(); + if (queryParams?.value) { + if (pageNumKey) { + queryParams.value[pageNumKey] = initialPageNum as T[keyof T]; + } + if (pageSizeKey && initialPageSize !== undefined) { + queryParams.value[pageSizeKey] = initialPageSize as T[keyof T]; + } + } + resetExtras?.(); + afterReset?.(); + }; + + return { + resetQuery + }; +} diff --git a/src/hooks/form/useSearchToggle.ts b/src/hooks/form/useSearchToggle.ts new file mode 100644 index 0000000..9c89d0a --- /dev/null +++ b/src/hooks/form/useSearchToggle.ts @@ -0,0 +1,17 @@ +export function useSearchToggle(initialValue = true) { + const showSearch = ref(initialValue); + + const toggleSearch = () => { + showSearch.value = !showSearch.value; + }; + + const setShowSearch = (value: boolean) => { + showSearch.value = value; + }; + + return { + showSearch, + toggleSearch, + setShowSearch + }; +} diff --git a/src/hooks/table/useTableSelection.ts b/src/hooks/table/useTableSelection.ts new file mode 100644 index 0000000..739e19d --- /dev/null +++ b/src/hooks/table/useTableSelection.ts @@ -0,0 +1,33 @@ +const isSelectableId = (value: unknown): value is string | number => { + return typeof value === 'string' || typeof value === 'number'; +}; + +export function useTableSelection(getRowId: (row: T) => ID) { + const ids = ref([]); + const selectedRows = ref([]); + const single = ref(true); + const multiple = ref(true); + + const handleSelectionChange = (selection: T[]) => { + selectedRows.value = selection; + ids.value = selection.map(getRowId).filter(isSelectableId) as ID[]; + single.value = selection.length !== 1; + multiple.value = selection.length === 0; + }; + + const clearSelection = () => { + selectedRows.value = []; + ids.value = []; + single.value = true; + multiple.value = true; + }; + + return { + ids, + selectedRows, + single, + multiple, + handleSelectionChange, + clearSelection + }; +} diff --git a/src/hooks/tree/useTreeCollapsed.ts b/src/hooks/tree/useTreeCollapsed.ts new file mode 100644 index 0000000..8e298eb --- /dev/null +++ b/src/hooks/tree/useTreeCollapsed.ts @@ -0,0 +1,17 @@ +export function useTreeCollapsed(initialValue = false) { + const treeCollapsed = ref(initialValue); + + const toggleCollapsed = () => { + treeCollapsed.value = !treeCollapsed.value; + }; + + const setCollapsed = (value: boolean) => { + treeCollapsed.value = value; + }; + + return { + treeCollapsed, + toggleCollapsed, + setCollapsed + }; +} diff --git a/src/views/demo/demo/index.vue b/src/views/demo/demo/index.vue index b99dc7b..80a1a11 100644 --- a/src/views/demo/demo/index.vue +++ b/src/views/demo/demo/index.vue @@ -138,26 +138,23 @@