import { useState } from 'react' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { zodResolver } from '@hookform/resolvers/zod' import { useForm } from 'react-hook-form' import { Plus, Search, Edit, Trash2 } from 'lucide-react' import { toast } from 'react-toastify' import { Button } from '@/client/components/ui/button' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/client/components/ui/card' import { Input } from '@/client/components/ui/input' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/client/components/ui/table' import { Badge } from '@/client/components/ui/badge' import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/client/components/ui/dialog' import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/client/components/ui/form' import { DataTablePagination } from '@/client/admin-shadcn/components/DataTablePagination' import { expressCompanyClient } from '@/client/api' import type { InferRequestType, InferResponseType } from 'hono/client' import { CreateExpressCompanyDto, UpdateExpressCompanyDto } from '@/server/modules/logistics/express-company.schema' // 类型定义 type CreateRequest = InferRequestType['json'] type UpdateRequest = InferRequestType['json'] type ExpressCompanyResponse = InferResponseType['data'][0] // 表单Schema直接使用后端定义 const createFormSchema = CreateExpressCompanyDto const updateFormSchema = UpdateExpressCompanyDto export const ExpressCompaniesPage = () => { const queryClient = useQueryClient() // 状态管理 const [searchParams, setSearchParams] = useState({ page: 1, limit: 10, search: '' }) const [isModalOpen, setIsModalOpen] = useState(false) const [editingCompany, setEditingCompany] = useState(null) const [isCreateForm, setIsCreateForm] = useState(true) const [deleteDialogOpen, setDeleteDialogOpen] = useState(false) const [companyToDelete, setCompanyToDelete] = useState(null) // 表单实例 const createForm = useForm({ resolver: zodResolver(createFormSchema), defaultValues: { name: '', code: '', state: 1, sort: 100 }, }) const updateForm = useForm({ resolver: zodResolver(updateFormSchema), }) // 数据查询 const { data, isLoading, refetch } = useQuery({ queryKey: ['express-companies', searchParams], queryFn: async () => { const res = await expressCompanyClient.$get({ query: { page: searchParams.page, pageSize: searchParams.limit, keyword: searchParams.search, } }) if (res.status !== 200) throw new Error('获取快递公司列表失败') return await res.json() } }) // 创建快递公司 const createMutation = useMutation({ mutationFn: async (data: CreateRequest) => { const res = await expressCompanyClient.$post({ json: data }) if (res.status !== 201) throw new Error('创建快递公司失败') return await res.json() }, onSuccess: () => { toast.success('快递公司创建成功') setIsModalOpen(false) queryClient.invalidateQueries({ queryKey: ['express-companies'] }) createForm.reset() }, onError: (error) => { toast.error(error instanceof Error ? error.message : '创建失败,请重试') } }) // 更新快递公司 const updateMutation = useMutation({ mutationFn: async ({ id, data }: { id: number; data: UpdateRequest }) => { const res = await expressCompanyClient[':id']['$put']({ param: { id: id.toString() }, json: data }) if (res.status !== 200) throw new Error('更新快递公司失败') return await res.json() }, onSuccess: () => { toast.success('快递公司更新成功') setIsModalOpen(false) queryClient.invalidateQueries({ queryKey: ['express-companies'] }) }, onError: (error) => { toast.error(error instanceof Error ? error.message : '更新失败,请重试') } }) // 删除快递公司 const deleteMutation = useMutation({ mutationFn: async (id: number) => { const res = await expressCompanyClient[':id']['$delete']({ param: { id: id.toString() } }) if (res.status !== 204) throw new Error('删除快递公司失败') return res }, onSuccess: () => { toast.success('快递公司删除成功') setDeleteDialogOpen(false) queryClient.invalidateQueries({ queryKey: ['express-companies'] }) }, onError: (error) => { toast.error(error instanceof Error ? error.message : '删除失败,请重试') } }) // 业务逻辑函数 const handleSearch = () => { setSearchParams(prev => ({ ...prev, page: 1 })) } const handleCreateCompany = () => { setIsCreateForm(true) setEditingCompany(null) createForm.reset() setIsModalOpen(true) } const handleEditCompany = (company: ExpressCompanyResponse) => { setIsCreateForm(false) setEditingCompany(company) updateForm.reset({ name: company.name, code: company.code, state: company.state, sort: company.sort || undefined }) setIsModalOpen(true) } const handleDeleteCompany = (id: number) => { setCompanyToDelete(id) setDeleteDialogOpen(true) } const handleCreateSubmit = (data: CreateRequest) => { createMutation.mutate(data) } const handleUpdateSubmit = (data: UpdateRequest) => { if (editingCompany) { updateMutation.mutate({ id: editingCompany.id, data }) } } const confirmDelete = () => { if (companyToDelete) { deleteMutation.mutate(companyToDelete) } } // 渲染页面 if (isLoading) { return (

快递公司管理

) } return (
{/* 页面标题区域 */}

快递公司管理

{/* 搜索区域 */} 快递公司列表 管理系统中的快递公司信息
{ e.preventDefault(); handleSearch() }} className="flex gap-2">
setSearchParams(prev => ({ ...prev, search: e.target.value }))} className="pl-8" />
{/* 数据表格 */}
ID 公司名称 编号 状态 排序 创建时间 操作 {data?.data.map((company) => ( {company.id} {company.name} {company.code} {company.state === 1 ? '启用' : '禁用'} {company.sort || '-'} {new Date(company.createdAt).toLocaleDateString()}
))}
{data?.data.length === 0 && !isLoading && (

暂无快递公司数据

)} setSearchParams(prev => ({ ...prev, page, limit }))} />
{/* 创建/编辑模态框 */} {isCreateForm ? '创建快递公司' : '编辑快递公司'} {isCreateForm ? '创建一个新的快递公司' : '编辑现有快递公司信息'} {isCreateForm ? (
( 公司名称 * 例如:顺丰速运、中通快递等 )} /> ( 编号 * 例如:SF、ZTO等唯一标识 )} /> ( 状态 选择快递公司的使用状态 )} /> ( 排序 field.onChange(e.target.value ? parseInt(e.target.value) : null)} value={field.value || ''} /> 数字越大优先级越高 )} /> ) : (
( 公司名称 * 例如:顺丰速运、中通快递等 )} /> ( 编号 * 例如:SF、ZTO等唯一标识 )} /> ( 状态 选择快递公司的使用状态 )} /> ( 排序 field.onChange(e.target.value ? parseInt(e.target.value) : null)} value={field.value || ''} /> 数字越大优先级越高 )} /> )}
{/* 删除确认对话框 */} 确认删除 确定要删除这个快递公司吗?此操作无法撤销。
) } // 骨架屏组件 const Skeleton = ({ className }: { className?: string }) => (
)