|
|
@@ -0,0 +1,527 @@
|
|
|
+import { useState } from 'react';
|
|
|
+import { useQuery } from '@tanstack/react-query';
|
|
|
+import { useForm } from 'react-hook-form';
|
|
|
+import { zodResolver } from '@hookform/resolvers/zod';
|
|
|
+import { format } from 'date-fns';
|
|
|
+import { toast } from 'sonner';
|
|
|
+import { Search, Edit, Eye } from 'lucide-react';
|
|
|
+import { Skeleton } from '@/client/components/ui/skeleton';
|
|
|
+
|
|
|
+import { Button } from '@/client/components/ui/button';
|
|
|
+import { Input } from '@/client/components/ui/input';
|
|
|
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/client/components/ui/card';
|
|
|
+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, FormField, FormItem, FormLabel, FormMessage } from '@/client/components/ui/form';
|
|
|
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/client/components/ui/select';
|
|
|
+import { Textarea } from '@/client/components/ui/textarea';
|
|
|
+
|
|
|
+import { DataTablePagination } from '@/client/admin-shadcn/components/DataTablePagination';
|
|
|
+import { orderClient } from '@/client/api';
|
|
|
+import type { InferRequestType, InferResponseType } from 'hono/client';
|
|
|
+import { UpdateOrderDto } from '@/server/modules/orders/order.schema';
|
|
|
+
|
|
|
+// 类型定义
|
|
|
+type OrderResponse = InferResponseType<typeof orderClient.$get, 200>['data'][0];
|
|
|
+type UpdateRequest = InferRequestType<typeof orderClient[':id']['$put']>['json'];
|
|
|
+
|
|
|
+// 状态映射
|
|
|
+const orderStatusMap = {
|
|
|
+ 0: { label: '未发货', color: 'warning' },
|
|
|
+ 1: { label: '已发货', color: 'info' },
|
|
|
+ 2: { label: '收货成功', color: 'success' },
|
|
|
+ 3: { label: '已退货', color: 'destructive' },
|
|
|
+} as const;
|
|
|
+
|
|
|
+const payStatusMap = {
|
|
|
+ 0: { label: '未支付', color: 'warning' },
|
|
|
+ 1: { label: '支付中', color: 'info' },
|
|
|
+ 2: { label: '支付成功', color: 'success' },
|
|
|
+ 3: { label: '已退款', color: 'secondary' },
|
|
|
+ 4: { label: '支付失败', color: 'destructive' },
|
|
|
+ 5: { label: '订单关闭', color: 'destructive' },
|
|
|
+} as const;
|
|
|
+
|
|
|
+const orderTypeMap = {
|
|
|
+ 1: { label: '实物订单', color: 'default' },
|
|
|
+ 2: { label: '虚拟订单', color: 'secondary' },
|
|
|
+} as const;
|
|
|
+
|
|
|
+export const OrdersPage = () => {
|
|
|
+ const [searchParams, setSearchParams] = useState({
|
|
|
+ page: 1,
|
|
|
+ limit: 10,
|
|
|
+ search: '',
|
|
|
+ status: '',
|
|
|
+ payStatus: '',
|
|
|
+ });
|
|
|
+ const [isModalOpen, setIsModalOpen] = useState(false);
|
|
|
+ const [editingOrder, setEditingOrder] = useState<OrderResponse | null>(null);
|
|
|
+ const [detailModalOpen, setDetailModalOpen] = useState(false);
|
|
|
+ const [selectedOrder, setSelectedOrder] = useState<OrderResponse | null>(null);
|
|
|
+
|
|
|
+ // 表单实例
|
|
|
+ const updateForm = useForm<UpdateRequest>({
|
|
|
+ resolver: zodResolver(UpdateOrderDto),
|
|
|
+ defaultValues: {},
|
|
|
+ });
|
|
|
+
|
|
|
+ // 数据查询
|
|
|
+ const { data, isLoading, refetch } = useQuery({
|
|
|
+ queryKey: ['orders', searchParams],
|
|
|
+ queryFn: async () => {
|
|
|
+ const res = await orderClient.$get({
|
|
|
+ query: {
|
|
|
+ page: searchParams.page,
|
|
|
+ pageSize: searchParams.limit,
|
|
|
+ keyword: searchParams.search,
|
|
|
+ ...(searchParams.status && { filters: JSON.stringify({ state: parseInt(searchParams.status) }) }),
|
|
|
+ ...(searchParams.payStatus && { filters: JSON.stringify({ payState: parseInt(searchParams.payStatus) }) }),
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (res.status !== 200) throw new Error('获取订单列表失败');
|
|
|
+ return await res.json();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 处理搜索
|
|
|
+ const handleSearch = () => {
|
|
|
+ setSearchParams(prev => ({ ...prev, page: 1 }));
|
|
|
+ };
|
|
|
+
|
|
|
+ // 处理编辑订单
|
|
|
+ const handleEditOrder = (order: OrderResponse) => {
|
|
|
+ setEditingOrder(order);
|
|
|
+ updateForm.reset({
|
|
|
+ state: order.state,
|
|
|
+ payState: order.payState,
|
|
|
+ remark: order.remark || '',
|
|
|
+ });
|
|
|
+ setIsModalOpen(true);
|
|
|
+ };
|
|
|
+
|
|
|
+ // 处理查看详情
|
|
|
+ const handleViewDetails = (order: OrderResponse) => {
|
|
|
+ setSelectedOrder(order);
|
|
|
+ setDetailModalOpen(true);
|
|
|
+ };
|
|
|
+
|
|
|
+ // 处理更新订单
|
|
|
+ const handleUpdateSubmit = async (data: UpdateRequest) => {
|
|
|
+ if (!editingOrder) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const res = await orderClient[':id']['$put']({
|
|
|
+ param: { id: editingOrder.id.toString() },
|
|
|
+ json: data,
|
|
|
+ });
|
|
|
+
|
|
|
+ if (res.status === 200) {
|
|
|
+ toast.success('订单更新成功');
|
|
|
+ setIsModalOpen(false);
|
|
|
+ refetch();
|
|
|
+ } else {
|
|
|
+ const error = await res.json();
|
|
|
+ toast.error(error.message || '更新失败');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('更新订单失败:', error);
|
|
|
+ toast.error('更新失败,请重试');
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 格式化金额
|
|
|
+ const formatAmount = (amount: number) => {
|
|
|
+ return `¥${amount.toFixed(2)}`;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 获取状态颜色
|
|
|
+ const getStatusBadge = (status: number, type: 'order' | 'pay') => {
|
|
|
+ const map = type === 'order' ? orderStatusMap : payStatusMap;
|
|
|
+ const config = map[status as keyof typeof map] || { label: '未知', color: 'default' };
|
|
|
+
|
|
|
+ return <Badge variant={config.color as any}>{config.label}</Badge>;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 骨架屏
|
|
|
+ if (isLoading) {
|
|
|
+ return (
|
|
|
+ <div className="space-y-4">
|
|
|
+ <div className="flex justify-between items-center">
|
|
|
+ <div>
|
|
|
+ <h1 className="text-2xl font-bold">订单管理</h1>
|
|
|
+ <p className="text-muted-foreground">管理所有订单信息</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <Card>
|
|
|
+ <CardHeader>
|
|
|
+ <Skeleton className="h-6 w-1/4" />
|
|
|
+ </CardHeader>
|
|
|
+ <CardContent>
|
|
|
+ <div className="space-y-3">
|
|
|
+ {[...Array(5)].map((_, i) => (
|
|
|
+ <div key={i} className="flex gap-4">
|
|
|
+ <Skeleton className="h-10 flex-1" />
|
|
|
+ <Skeleton className="h-10 flex-1" />
|
|
|
+ <Skeleton className="h-10 flex-1" />
|
|
|
+ <Skeleton className="h-10 w-20" />
|
|
|
+ </div>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ </CardContent>
|
|
|
+ </Card>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div className="space-y-4">
|
|
|
+ {/* 页面标题 */}
|
|
|
+ <div className="flex justify-between items-center">
|
|
|
+ <div>
|
|
|
+ <h1 className="text-2xl font-bold">订单管理</h1>
|
|
|
+ <p className="text-muted-foreground">管理所有订单信息</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {/* 搜索区域 */}
|
|
|
+ <Card>
|
|
|
+ <CardHeader>
|
|
|
+ <CardTitle>订单列表</CardTitle>
|
|
|
+ <CardDescription>查看和管理所有订单</CardDescription>
|
|
|
+ </CardHeader>
|
|
|
+ <CardContent>
|
|
|
+ <div className="flex gap-4 mb-4">
|
|
|
+ <div className="relative flex-1 max-w-sm">
|
|
|
+ <Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
|
|
|
+ <Input
|
|
|
+ placeholder="搜索订单号、手机号、收货人姓名..."
|
|
|
+ value={searchParams.search}
|
|
|
+ onChange={(e) => setSearchParams(prev => ({ ...prev, search: e.target.value }))}
|
|
|
+ className="pl-8"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <Select
|
|
|
+ value={searchParams.status}
|
|
|
+ onValueChange={(value) => setSearchParams(prev => ({ ...prev, status: value, page: 1 }))}
|
|
|
+ >
|
|
|
+ <SelectTrigger className="w-32">
|
|
|
+ <SelectValue placeholder="订单状态" />
|
|
|
+ </SelectTrigger>
|
|
|
+ <SelectContent>
|
|
|
+ <SelectItem value="">全部</SelectItem>
|
|
|
+ <SelectItem value="0">未发货</SelectItem>
|
|
|
+ <SelectItem value="1">已发货</SelectItem>
|
|
|
+ <SelectItem value="2">收货成功</SelectItem>
|
|
|
+ <SelectItem value="3">已退货</SelectItem>
|
|
|
+ </SelectContent>
|
|
|
+ </Select>
|
|
|
+ <Select
|
|
|
+ value={searchParams.payStatus}
|
|
|
+ onValueChange={(value) => setSearchParams(prev => ({ ...prev, payStatus: value, page: 1 }))}
|
|
|
+ >
|
|
|
+ <SelectTrigger className="w-32">
|
|
|
+ <SelectValue placeholder="支付状态" />
|
|
|
+ </SelectTrigger>
|
|
|
+ <SelectContent>
|
|
|
+ <SelectItem value="">全部</SelectItem>
|
|
|
+ <SelectItem value="0">未支付</SelectItem>
|
|
|
+ <SelectItem value="1">支付中</SelectItem>
|
|
|
+ <SelectItem value="2">支付成功</SelectItem>
|
|
|
+ <SelectItem value="3">已退款</SelectItem>
|
|
|
+ <SelectItem value="4">支付失败</SelectItem>
|
|
|
+ <SelectItem value="5">订单关闭</SelectItem>
|
|
|
+ </SelectContent>
|
|
|
+ </Select>
|
|
|
+ <Button onClick={handleSearch}>
|
|
|
+ <Search className="h-4 w-4 mr-2" />
|
|
|
+ 搜索
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {/* 数据表格 */}
|
|
|
+ <div className="rounded-md border">
|
|
|
+ <Table>
|
|
|
+ <TableHeader>
|
|
|
+ <TableRow>
|
|
|
+ <TableHead>订单号</TableHead>
|
|
|
+ <TableHead>用户信息</TableHead>
|
|
|
+ <TableHead>收货人</TableHead>
|
|
|
+ <TableHead>金额</TableHead>
|
|
|
+ <TableHead>订单状态</TableHead>
|
|
|
+ <TableHead>支付状态</TableHead>
|
|
|
+ <TableHead>创建时间</TableHead>
|
|
|
+ <TableHead className="text-right">操作</TableHead>
|
|
|
+ </TableRow>
|
|
|
+ </TableHeader>
|
|
|
+ <TableBody>
|
|
|
+ {data?.data.map((order) => (
|
|
|
+ <TableRow key={order.id}>
|
|
|
+ <TableCell>
|
|
|
+ <div>
|
|
|
+ <p className="font-medium">{order.orderNo}</p>
|
|
|
+ <p className="text-sm text-muted-foreground">
|
|
|
+ {orderTypeMap[order.orderType as keyof typeof orderTypeMap]?.label}
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ </TableCell>
|
|
|
+ <TableCell>
|
|
|
+ <div>
|
|
|
+ <p>{order.user?.username || '-'}</p>
|
|
|
+ <p className="text-sm text-muted-foreground">{order.userPhone}</p>
|
|
|
+ </div>
|
|
|
+ </TableCell>
|
|
|
+ <TableCell>
|
|
|
+ <div>
|
|
|
+ <p>{order.recevierName || '-'}</p>
|
|
|
+ <p className="text-sm text-muted-foreground">{order.receiverMobile}</p>
|
|
|
+ </div>
|
|
|
+ </TableCell>
|
|
|
+ <TableCell>
|
|
|
+ <div>
|
|
|
+ <p className="font-medium">{formatAmount(order.payAmount)}</p>
|
|
|
+ <p className="text-sm text-muted-foreground">{formatAmount(order.amount)}</p>
|
|
|
+ </div>
|
|
|
+ </TableCell>
|
|
|
+ <TableCell>{getStatusBadge(order.state, 'order')}</TableCell>
|
|
|
+ <TableCell>{getStatusBadge(order.payState, 'pay')}</TableCell>
|
|
|
+ <TableCell>
|
|
|
+ {format(new Date(order.createdAt), 'yyyy-MM-dd HH:mm')}
|
|
|
+ </TableCell>
|
|
|
+ <TableCell className="text-right">
|
|
|
+ <div className="flex justify-end gap-2">
|
|
|
+ <Button
|
|
|
+ variant="ghost"
|
|
|
+ size="icon"
|
|
|
+ onClick={() => handleViewDetails(order)}
|
|
|
+ >
|
|
|
+ <Eye className="h-4 w-4" />
|
|
|
+ </Button>
|
|
|
+ <Button
|
|
|
+ variant="ghost"
|
|
|
+ size="icon"
|
|
|
+ onClick={() => handleEditOrder(order)}
|
|
|
+ >
|
|
|
+ <Edit className="h-4 w-4" />
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+ </TableCell>
|
|
|
+ </TableRow>
|
|
|
+ ))}
|
|
|
+ </TableBody>
|
|
|
+ </Table>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {data?.data.length === 0 && !isLoading && (
|
|
|
+ <div className="text-center py-8">
|
|
|
+ <p className="text-muted-foreground">暂无订单数据</p>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+
|
|
|
+ <DataTablePagination
|
|
|
+ currentPage={searchParams.page}
|
|
|
+ pageSize={searchParams.limit}
|
|
|
+ totalCount={data?.pagination.total || 0}
|
|
|
+ onPageChange={(page, limit) => setSearchParams(prev => ({ ...prev, page, limit }))}
|
|
|
+ />
|
|
|
+ </CardContent>
|
|
|
+ </Card>
|
|
|
+
|
|
|
+ {/* 编辑订单模态框 */}
|
|
|
+ <Dialog open={isModalOpen} onOpenChange={setIsModalOpen}>
|
|
|
+ <DialogContent className="sm:max-w-[500px] max-h-[90vh] overflow-y-auto">
|
|
|
+ <DialogHeader>
|
|
|
+ <DialogTitle>编辑订单</DialogTitle>
|
|
|
+ <DialogDescription>更新订单状态和备注信息</DialogDescription>
|
|
|
+ </DialogHeader>
|
|
|
+
|
|
|
+ <Form {...updateForm}>
|
|
|
+ <form onSubmit={updateForm.handleSubmit(handleUpdateSubmit)} className="space-y-4">
|
|
|
+ <FormField
|
|
|
+ control={updateForm.control}
|
|
|
+ name="state"
|
|
|
+ render={({ field }) => (
|
|
|
+ <FormItem>
|
|
|
+ <FormLabel>订单状态</FormLabel>
|
|
|
+ <Select onValueChange={(value) => field.onChange(parseInt(value))} value={field.value?.toString()}>
|
|
|
+ <FormControl>
|
|
|
+ <SelectTrigger>
|
|
|
+ <SelectValue placeholder="选择订单状态" />
|
|
|
+ </SelectTrigger>
|
|
|
+ </FormControl>
|
|
|
+ <SelectContent>
|
|
|
+ <SelectItem value="0">未发货</SelectItem>
|
|
|
+ <SelectItem value="1">已发货</SelectItem>
|
|
|
+ <SelectItem value="2">收货成功</SelectItem>
|
|
|
+ <SelectItem value="3">已退货</SelectItem>
|
|
|
+ </SelectContent>
|
|
|
+ </Select>
|
|
|
+ <FormMessage />
|
|
|
+ </FormItem>
|
|
|
+ )}
|
|
|
+ />
|
|
|
+
|
|
|
+ <FormField
|
|
|
+ control={updateForm.control}
|
|
|
+ name="payState"
|
|
|
+ render={({ field }) => (
|
|
|
+ <FormItem>
|
|
|
+ <FormLabel>支付状态</FormLabel>
|
|
|
+ <Select onValueChange={(value) => field.onChange(parseInt(value))} value={field.value?.toString()}>
|
|
|
+ <FormControl>
|
|
|
+ <SelectTrigger>
|
|
|
+ <SelectValue placeholder="选择支付状态" />
|
|
|
+ </SelectTrigger>
|
|
|
+ </FormControl>
|
|
|
+ <SelectContent>
|
|
|
+ <SelectItem value="0">未支付</SelectItem>
|
|
|
+ <SelectItem value="1">支付中</SelectItem>
|
|
|
+ <SelectItem value="2">支付成功</SelectItem>
|
|
|
+ <SelectItem value="3">已退款</SelectItem>
|
|
|
+ <SelectItem value="4">支付失败</SelectItem>
|
|
|
+ <SelectItem value="5">订单关闭</SelectItem>
|
|
|
+ </SelectContent>
|
|
|
+ </Select>
|
|
|
+ <FormMessage />
|
|
|
+ </FormItem>
|
|
|
+ )}
|
|
|
+ />
|
|
|
+
|
|
|
+ <FormField
|
|
|
+ control={updateForm.control}
|
|
|
+ name="remark"
|
|
|
+ render={({ field }) => (
|
|
|
+ <FormItem>
|
|
|
+ <FormLabel>管理员备注</FormLabel>
|
|
|
+ <FormControl>
|
|
|
+ <Textarea
|
|
|
+ placeholder="输入管理员备注信息..."
|
|
|
+ className="resize-none"
|
|
|
+ {...field}
|
|
|
+ />
|
|
|
+ </FormControl>
|
|
|
+ <FormMessage />
|
|
|
+ </FormItem>
|
|
|
+ )}
|
|
|
+ />
|
|
|
+
|
|
|
+ <DialogFooter>
|
|
|
+ <Button type="button" variant="outline" onClick={() => setIsModalOpen(false)}>
|
|
|
+ 取消
|
|
|
+ </Button>
|
|
|
+ <Button type="submit">保存</Button>
|
|
|
+ </DialogFooter>
|
|
|
+ </form>
|
|
|
+ </Form>
|
|
|
+ </DialogContent>
|
|
|
+ </Dialog>
|
|
|
+
|
|
|
+ {/* 订单详情模态框 */}
|
|
|
+ <Dialog open={detailModalOpen} onOpenChange={setDetailModalOpen}>
|
|
|
+ <DialogContent className="sm:max-w-[700px] max-h-[90vh] overflow-y-auto">
|
|
|
+ <DialogHeader>
|
|
|
+ <DialogTitle>订单详情</DialogTitle>
|
|
|
+ <DialogDescription>查看订单的详细信息</DialogDescription>
|
|
|
+ </DialogHeader>
|
|
|
+
|
|
|
+ {selectedOrder && (
|
|
|
+ <div className="space-y-4">
|
|
|
+ <div className="grid grid-cols-2 gap-4">
|
|
|
+ <div>
|
|
|
+ <h4 className="font-medium mb-2">订单信息</h4>
|
|
|
+ <div className="space-y-2 text-sm">
|
|
|
+ <div className="flex justify-between">
|
|
|
+ <span className="text-muted-foreground">订单号:</span>
|
|
|
+ <span>{selectedOrder.orderNo}</span>
|
|
|
+ </div>
|
|
|
+ <div className="flex justify-between">
|
|
|
+ <span className="text-muted-foreground">订单类型:</span>
|
|
|
+ <span>{orderTypeMap[selectedOrder.orderType as keyof typeof orderTypeMap]?.label}</span>
|
|
|
+ </div>
|
|
|
+ <div className="flex justify-between">
|
|
|
+ <span className="text-muted-foreground">订单金额:</span>
|
|
|
+ <span>{formatAmount(selectedOrder.amount)}</span>
|
|
|
+ </div>
|
|
|
+ <div className="flex justify-between">
|
|
|
+ <span className="text-muted-foreground">实付金额:</span>
|
|
|
+ <span>{formatAmount(selectedOrder.payAmount)}</span>
|
|
|
+ </div>
|
|
|
+ <div className="flex justify-between">
|
|
|
+ <span className="text-muted-foreground">运费:</span>
|
|
|
+ <span>{formatAmount(selectedOrder.freightAmount)}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div>
|
|
|
+ <h4 className="font-medium mb-2">状态信息</h4>
|
|
|
+ <div className="space-y-2 text-sm">
|
|
|
+ <div className="flex justify-between">
|
|
|
+ <span className="text-muted-foreground">订单状态:</span>
|
|
|
+ <span>{getStatusBadge(selectedOrder.state, 'order')}</span>
|
|
|
+ </div>
|
|
|
+ <div className="flex justify-between">
|
|
|
+ <span className="text-muted-foreground">支付状态:</span>
|
|
|
+ <span>{getStatusBadge(selectedOrder.payState, 'pay')}</span>
|
|
|
+ </div>
|
|
|
+ <div className="flex justify-between">
|
|
|
+ <span className="text-muted-foreground">支付方式:</span>
|
|
|
+ <span>{selectedOrder.payType === 1 ? '积分' : selectedOrder.payType === 2 ? '礼券' : '未选择'}</span>
|
|
|
+ </div>
|
|
|
+ <div className="flex justify-between">
|
|
|
+ <span className="text-muted-foreground">创建时间:</span>
|
|
|
+ <span>{format(new Date(selectedOrder.createdAt), 'yyyy-MM-dd HH:mm')}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div className="grid grid-cols-2 gap-4">
|
|
|
+ <div>
|
|
|
+ <h4 className="font-medium mb-2">用户信息</h4>
|
|
|
+ <div className="space-y-2 text-sm">
|
|
|
+ <div className="flex justify-between">
|
|
|
+ <span className="text-muted-foreground">用户名:</span>
|
|
|
+ <span>{selectedOrder.user?.username || '-'}</span>
|
|
|
+ </div>
|
|
|
+ <div className="flex justify-between">
|
|
|
+ <span className="text-muted-foreground">手机号:</span>
|
|
|
+ <span>{selectedOrder.userPhone || '-'}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div>
|
|
|
+ <h4 className="font-medium mb-2">收货信息</h4>
|
|
|
+ <div className="space-y-2 text-sm">
|
|
|
+ <div className="flex justify-between">
|
|
|
+ <span className="text-muted-foreground">收货人:</span>
|
|
|
+ <span>{selectedOrder.recevierName || '-'}</span>
|
|
|
+ </div>
|
|
|
+ <div className="flex justify-between">
|
|
|
+ <span className="text-muted-foreground">手机号:</span>
|
|
|
+ <span>{selectedOrder.receiverMobile || '-'}</span>
|
|
|
+ </div>
|
|
|
+ <div className="flex justify-between">
|
|
|
+ <span className="text-muted-foreground">地址:</span>
|
|
|
+ <span>{selectedOrder.address || '-'}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {selectedOrder.remark && (
|
|
|
+ <div>
|
|
|
+ <h4 className="font-medium mb-2">管理员备注</h4>
|
|
|
+ <p className="text-sm bg-muted p-3 rounded-md">{selectedOrder.remark}</p>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ </DialogContent>
|
|
|
+ </Dialog>
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+};
|