feat: api client, auth store, login, authed shell, data-table + CRUD kit
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
import { toast } from 'sonner'
|
||||
import type { FieldValues, Path, UseFormSetError } from 'react-hook-form'
|
||||
import { ApiError } from '@/api/client'
|
||||
|
||||
/**
|
||||
* Standard error handling: 422 field errors land on the form (when given),
|
||||
* everything else surfaces as a toast with the backend's localized message.
|
||||
*/
|
||||
export function handleApiError<T extends FieldValues>(
|
||||
error: unknown,
|
||||
setError?: UseFormSetError<T>,
|
||||
): void {
|
||||
if (error instanceof ApiError) {
|
||||
if (error.status === 422 && error.errors && setError) {
|
||||
for (const [field, messages] of Object.entries(error.errors)) {
|
||||
setError(field as Path<T>, { type: 'server', message: messages[0] })
|
||||
}
|
||||
return
|
||||
}
|
||||
toast.error(error.message || `请求失败(${error.code})`)
|
||||
return
|
||||
}
|
||||
toast.error('网络异常,请稍后重试')
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { keepPreviousData, useQuery } from '@tanstack/react-query'
|
||||
import { useEffect, useState } from 'react'
|
||||
import type { ListParams, PaginatedResponse } from '@/api/types'
|
||||
|
||||
/**
|
||||
* Standard list-page state: page / page_size wired to the backend's
|
||||
* Pagination envelope; changing filters snaps back to page 1.
|
||||
*/
|
||||
export function useListPage<T>(
|
||||
key: string,
|
||||
fetcher: (params: ListParams) => Promise<PaginatedResponse<T>>,
|
||||
filters: ListParams = {},
|
||||
) {
|
||||
const [page, setPage] = useState(1)
|
||||
const [pageSize, setPageSize] = useState(20)
|
||||
|
||||
const filterKey = JSON.stringify(filters)
|
||||
|
||||
useEffect(() => {
|
||||
setPage(1)
|
||||
}, [filterKey])
|
||||
|
||||
const query = useQuery({
|
||||
queryKey: [key, filterKey, page, pageSize],
|
||||
queryFn: () => fetcher({ ...filters, page, page_size: pageSize }),
|
||||
placeholderData: keepPreviousData,
|
||||
})
|
||||
|
||||
return {
|
||||
query,
|
||||
rows: query.data?.data ?? [],
|
||||
pagination: query.data?.pagination,
|
||||
loading: query.isPending,
|
||||
page,
|
||||
setPage,
|
||||
setPageSize: (size: number) => {
|
||||
setPageSize(size)
|
||||
setPage(1)
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user