import { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { format } from 'date-fns'; import { zhCN } from 'date-fns/locale'; import { toast } from 'sonner'; import { Plus, Search, Edit, Trash2, MapPin } from 'lucide-react'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { deliveryAddressClient } from '../api/deliveryAddressClient'; import { CreateDeliveryAddressDto, UpdateDeliveryAddressDto } from '@d8d/delivery-address-module/schemas'; import { Button } from '@d8d/shared-ui-components/components/ui/button'; import { Input } from '@d8d/shared-ui-components/components/ui/input'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@d8d/shared-ui-components/components/ui/card'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@d8d/shared-ui-components/components/ui/table'; import { Badge } from '@d8d/shared-ui-components/components/ui/badge'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@d8d/shared-ui-components/components/ui/dialog'; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@d8d/shared-ui-components/components/ui/form'; import { Switch } from '@d8d/shared-ui-components/components/ui/switch'; import { Skeleton } from '@d8d/shared-ui-components/components/ui/skeleton'; import { DataTablePagination } from '@d8d/shared-ui-components/components/admin/DataTablePagination'; import { UserSelector } from '@d8d/user-management-ui/components'; import { AreaSelect4Level } from '@d8d/area-management-ui/components'; import type { DeliveryAddress, DeliveryAddressQueryParams } from '../types/delivery-address'; import { DeliveryAddressState, DefaultAddressState } from '../types/delivery-address'; // 表单schema const createFormSchema = CreateDeliveryAddressDto; const updateFormSchema = UpdateDeliveryAddressDto; export const DeliveryAddressManagement: React.FC = () => { const queryClient = useQueryClient(); // 状态管理 const [searchParams, setSearchParams] = useState({ page: 1, limit: 10, search: '', userId: undefined, }); const [isModalOpen, setIsModalOpen] = useState(false); const [editingAddress, setEditingAddress] = useState(null); const [isCreateForm, setIsCreateForm] = useState(true); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [addressToDelete, setAddressToDelete] = useState(null); // 表单实例 const createForm = useForm({ resolver: zodResolver(createFormSchema), defaultValues: { userId: 0, name: '', phone: '', address: '', receiverProvince: 0, receiverCity: 0, receiverDistrict: 0, receiverTown: 0, isDefault: 0, }, }); const updateForm = useForm({ resolver: zodResolver(updateFormSchema), }); // 数据查询 const { data, isLoading, refetch } = useQuery({ queryKey: ['delivery-addresses', searchParams], queryFn: async () => { const res = await deliveryAddressClient.$get({ query: { page: searchParams.page, pageSize: searchParams.limit, keyword: searchParams.search, ...(searchParams.userId && { userId: searchParams.userId }), } }); if (res.status !== 200) throw new Error('获取收货地址列表失败'); return await res.json(); } }); // 创建地址 const createMutation = useMutation({ mutationFn: async (data: any) => { const res = await deliveryAddressClient.$post({ json: data }); if (res.status !== 201) throw new Error('创建失败'); return await res.json(); }, onSuccess: () => { toast.success('收货地址创建成功'); setIsModalOpen(false); refetch(); createForm.reset(); }, onError: (error) => { toast.error(error.message || '创建失败'); } }); // 更新地址 const updateMutation = useMutation({ mutationFn: async ({ id, data }: { id: number; data: any }) => { const res = await deliveryAddressClient[':id']['$put']({ param: { id }, json: data, }); if (res.status !== 200) throw new Error('更新失败'); return await res.json(); }, onSuccess: () => { toast.success('收货地址更新成功'); setIsModalOpen(false); refetch(); }, onError: (error) => { toast.error(error.message || '更新失败'); } }); // 删除地址 const deleteMutation = useMutation({ mutationFn: async (id: number) => { const res = await deliveryAddressClient[':id']['$delete']({ param: { id }, }); if (res.status !== 204) throw new Error('删除失败'); }, onSuccess: () => { toast.success('收货地址删除成功'); setDeleteDialogOpen(false); refetch(); }, onError: (error) => { toast.error(error.message || '删除失败'); } }); // 业务逻辑函数 const handleSearch = () => { setSearchParams(prev => ({ ...prev, page: 1 })); }; const handleCreateAddress = () => { setIsCreateForm(true); setEditingAddress(null); createForm.reset(); setIsModalOpen(true); }; const handleEditAddress = (address: DeliveryAddress) => { setIsCreateForm(false); setEditingAddress(address); updateForm.reset({ name: address.name, phone: address.phone, address: address.address, receiverProvince: address.receiverProvince, receiverCity: address.receiverCity, receiverDistrict: address.receiverDistrict, receiverTown: address.receiverTown, isDefault: address.isDefault, }); setIsModalOpen(true); }; const handleDeleteAddress = (id: number) => { setAddressToDelete(id); setDeleteDialogOpen(true); }; const confirmDelete = () => { if (addressToDelete) { deleteMutation.mutate(addressToDelete); } }; const handleCreateSubmit = (data: any) => { createMutation.mutate(data); }; const handleUpdateSubmit = (data: any) => { if (editingAddress) { updateMutation.mutate({ id: editingAddress.id, data }); } }; // 状态显示 const getStatusBadge = (status: DeliveryAddressState) => { switch (status) { case DeliveryAddressState.ACTIVE: return 正常; case DeliveryAddressState.DISABLED: return 禁用; case DeliveryAddressState.DELETED: return 删除; default: return 未知; } }; const getIsDefaultBadge = (isDefault: DefaultAddressState) => { return isDefault === DefaultAddressState.IS_DEFAULT ? ( 默认 ) : ( 非默认 ); }; // 格式化地址显示 const formatAddressDisplay = (address: DeliveryAddress) => { const parts = [ address.province?.name, address.city?.name, address.district?.name, address.town?.name, address.address ].filter(Boolean); return parts.join(' '); }; // 表格加载状态 const tableContent = isLoading ? ( 收货地址列表 加载中...
{[...Array(5)].map((_, i) => (
))}
) : ( 收货地址列表 共 {data?.data?.total || 0} 条收货地址记录 用户 收货人 手机号 地址 状态 默认地址 创建时间 操作 {data?.data?.list?.map((address: DeliveryAddress) => (
{address.user?.name || '未知用户'}
{address.name} {address.phone}
{formatAddressDisplay(address)}
{getStatusBadge(address.state)} {getIsDefaultBadge(address.isDefault)} {address.createdAt ? format(new Date(address.createdAt), 'yyyy-MM-dd HH:mm', { locale: zhCN }) : '-'}
))}
{data?.data?.total && data.data.total > 0 && (
setSearchParams(prev => ({ ...prev, page }))} onPageSizeChange={(limit) => setSearchParams(prev => ({ ...prev, limit, page: 1 }))} />
)}
); return (
{/* 页面标题 */}

用户收货地址

管理用户的收货地址信息

{/* 搜索区域 */} 搜索筛选 根据条件筛选收货地址
setSearchParams(prev => ({ ...prev, search: e.target.value }))} className="pl-8" />
setSearchParams(prev => ({ ...prev, userId: value }))} placeholder="选择用户" data-testid="search-user-selector" />
{/* 数据表格 */} {tableContent} {/* 创建/编辑模态框 */} {isCreateForm ? '创建收货地址' : '编辑收货地址'} {isCreateForm ? '创建一个新的收货地址' : '编辑现有收货地址信息'} {isCreateForm ? (
( 用户* )} />
( 收货人姓名* )} /> ( 手机号* )} />
( 详细地址* )} />
四级地址选择* createForm.setValue('receiverProvince', value)} onCityChange={(value) => createForm.setValue('receiverCity', value)} onDistrictChange={(value) => createForm.setValue('receiverDistrict', value)} onTownChange={(value) => createForm.setValue('receiverTown', value)} showLabels={false} />
(
设为默认地址 将此地址设为用户的默认收货地址
field.onChange(checked ? 1 : 0)} />
)} /> ) : (
( 收货人姓名* )} /> ( 手机号* )} /> ( 详细地址* )} />
四级地址选择* updateForm.setValue('receiverProvince', value)} onCityChange={(value) => updateForm.setValue('receiverCity', value)} onDistrictChange={(value) => updateForm.setValue('receiverDistrict', value)} onTownChange={(value) => updateForm.setValue('receiverTown', value)} showLabels={false} />
(
设为默认地址 将此地址设为用户的默认收货地址
field.onChange(checked ? 1 : 0)} />
)} /> )}
{/* 删除确认对话框 */} 确认删除 确定要删除这个收货地址吗?此操作无法撤销。
); };