| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- import React from 'react';
- import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
- import { Button } from '@/client/components/ui/button';
- import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/client/components/ui/card';
- import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/client/components/ui/table';
- import { DataTablePagination } from '../components/DataTablePagination';
- import { Plus, Edit, Trash2, Calendar } from 'lucide-react';
- import { useState } from 'react';
- import { activityClient } from '@/client/api';
- import type { InferResponseType } from 'hono/client';
- // 类型提取规范
- type ActivityResponse = InferResponseType<typeof activityClient.$get, 200>['data'][0];
- // 统一操作处理函数
- const handleOperation = async (operation: () => Promise<any>) => {
- try {
- await operation();
- // toast.success('操作成功');
- console.log('操作成功');
- } catch (error) {
- console.error('操作失败:', error);
- // toast.error('操作失败,请重试');
- throw error;
- }
- };
- export const ActivitiesPage: React.FC = () => {
- const queryClient = useQueryClient();
- const [page, setPage] = useState(1);
- const [pageSize, setPageSize] = useState(20);
- // 获取活动列表 - 使用RPC客户端
- const { data, isLoading, error } = useQuery({
- queryKey: ['activities', page, pageSize],
- queryFn: async () => {
- const res = await activityClient.$get({
- query: {
- page,
- pageSize
- }
- });
- if (res.status !== 200) throw new Error('获取活动列表失败');
- return await res.json();
- },
- staleTime: 5 * 60 * 1000, // 5分钟缓存
- });
- // 删除活动 - 使用RPC客户端
- const deleteMutation = useMutation({
- mutationFn: async (id: number) => {
- await handleOperation(async () => {
- const res = await activityClient[':id'].$delete({
- param: { id }
- });
- if (res.status !== 204) throw new Error('删除活动失败');
- });
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['activities'] });
- },
- });
- if (error) {
- return (
- <div className="p-6">
- <Card>
- <CardContent className="pt-6">
- <div className="text-center text-red-500">
- 加载活动数据失败: {error.message}
- </div>
- </CardContent>
- </Card>
- </div>
- );
- }
- return (
- <div className="p-6">
- <div className="flex items-center justify-between mb-6">
- <div>
- <h1 className="text-3xl font-bold tracking-tight">活动管理</h1>
- <p className="text-muted-foreground">
- 管理旅行活动,包括去程和返程活动
- </p>
- </div>
- <Button>
- <Plus className="h-4 w-4 mr-2" />
- 新建活动
- </Button>
- </div>
- <Card>
- <CardHeader>
- <CardTitle>活动列表</CardTitle>
- <CardDescription>
- 当前共有 {data?.pagination.total || 0} 个活动
- </CardDescription>
- </CardHeader>
- <CardContent>
- <div className="rounded-md border">
- <Table>
- <TableHeader>
- <TableRow>
- <TableHead>活动名称</TableHead>
- <TableHead>类型</TableHead>
- <TableHead>开始时间</TableHead>
- <TableHead>结束时间</TableHead>
- <TableHead>状态</TableHead>
- <TableHead className="text-right">操作</TableHead>
- </TableRow>
- </TableHeader>
- <TableBody>
- {isLoading ? (
- <TableRow>
- <TableCell colSpan={6} className="text-center py-4">
- 加载中...
- </TableCell>
- </TableRow>
- ) : data?.data && data.data.length > 0 ? (
- data.data.map((activity: ActivityResponse) => (
- <TableRow key={activity.id}>
- <TableCell>
- <div className="flex items-center gap-2">
- <Calendar className="h-4 w-4 text-blue-500" />
- <span>{activity.name}</span>
- </div>
- </TableCell>
- <TableCell>
- <span className={`px-2 py-1 rounded-full text-xs ${
- activity.type === 'departure'
- ? 'bg-blue-100 text-blue-800'
- : 'bg-green-100 text-green-800'
- }`}>
- {activity.type === 'departure' ? '去程' : '返程'}
- </span>
- </TableCell>
- <TableCell>
- {new Date(activity.startDate).toLocaleString('zh-CN')}
- </TableCell>
- <TableCell>
- {new Date(activity.endDate).toLocaleString('zh-CN')}
- </TableCell>
- <TableCell>
- <span className={`px-2 py-1 rounded-full text-xs ${
- activity.isDisabled === 0
- ? 'bg-green-100 text-green-800'
- : 'bg-red-100 text-red-800'
- }`}>
- {activity.isDisabled === 0 ? '启用' : '禁用'}
- </span>
- </TableCell>
- <TableCell className="text-right">
- <div className="flex justify-end gap-2">
- <Button
- variant="outline"
- size="sm"
- onClick={() => {
- // TODO: 编辑活动
- console.log('编辑活动:', activity.id);
- }}
- >
- <Edit className="h-4 w-4" />
- </Button>
- <Button
- variant="destructive"
- size="sm"
- onClick={() => {
- if (confirm('确定要删除这个活动吗?')) {
- deleteMutation.mutate(activity.id);
- }
- }}
- >
- <Trash2 className="h-4 w-4" />
- </Button>
- </div>
- </TableCell>
- </TableRow>
- ))
- ) : (
- <TableRow>
- <TableCell colSpan={6} className="text-center py-4">
- 暂无活动数据
- </TableCell>
- </TableRow>
- )}
- </TableBody>
- </Table>
- </div>
- {data && (
- <DataTablePagination
- currentPage={data.pagination.current}
- totalCount={data.pagination.total}
- pageSize={data.pagination.pageSize}
- onPageChange={(page, pageSize) => {
- setPage(page);
- setPageSize(pageSize);
- }}
- />
- )}
- </CardContent>
- </Card>
- </div>
- );
- };
|