application [cat-admin-web] view page [pages/cat-management] development
This commit is contained in:
233
apps/cat-admin-web/src/pages/cat-management.tsx
Normal file
233
apps/cat-admin-web/src/pages/cat-management.tsx
Normal file
@@ -0,0 +1,233 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { entities } from '@/lib/nvwa';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
|
||||
interface Cat {
|
||||
id: number;
|
||||
name: string;
|
||||
age: number;
|
||||
gender: string;
|
||||
grade: string;
|
||||
type: string;
|
||||
is_available: boolean;
|
||||
description?: string;
|
||||
image_ids: number[];
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export default function CatManagement() {
|
||||
const [searchParams] = useSearchParams();
|
||||
const editId = searchParams.get('id');
|
||||
const [cats, setCats] = useState<Cat[]>([]);
|
||||
const [editingCat, setEditingCat] = useState<Cat | null>(null);
|
||||
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
fetchCats();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (editId && cats.length > 0) {
|
||||
const cat = cats.find(c => c.id === parseInt(editId));
|
||||
if (cat) {
|
||||
setEditingCat(cat);
|
||||
setIsDialogOpen(true);
|
||||
}
|
||||
}
|
||||
}, [editId, cats]);
|
||||
|
||||
const fetchCats = async () => {
|
||||
const { data, error } = await entities.from('cat').select('*');
|
||||
if (error) {
|
||||
console.error(error);
|
||||
return;
|
||||
}
|
||||
setCats(data || []);
|
||||
};
|
||||
|
||||
const toggleAvailability = async (cat: Cat) => {
|
||||
const { error } = await entities.from('cat').update({ is_available: !cat.is_available }).eq('id', cat.id);
|
||||
if (error) {
|
||||
console.error(error);
|
||||
return;
|
||||
}
|
||||
setCats(cats.map(c => c.id === cat.id ? { ...c, is_available: !c.is_available } : c));
|
||||
};
|
||||
|
||||
const openEditDialog = (cat: Cat) => {
|
||||
setEditingCat(cat);
|
||||
setIsDialogOpen(true);
|
||||
};
|
||||
|
||||
const handleEdit = async () => {
|
||||
if (!editingCat) return;
|
||||
const { error } = await entities.from('cat').update({
|
||||
name: editingCat.name,
|
||||
age: editingCat.age,
|
||||
gender: editingCat.gender,
|
||||
grade: editingCat.grade,
|
||||
type: editingCat.type,
|
||||
description: editingCat.description,
|
||||
image_ids: editingCat.image_ids,
|
||||
}).eq('id', editingCat.id);
|
||||
if (error) {
|
||||
console.error(error);
|
||||
return;
|
||||
}
|
||||
setCats(cats.map(cat => cat.id === editingCat.id ? editingCat : cat));
|
||||
setIsDialogOpen(false);
|
||||
setEditingCat(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>猫咪管理</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>名称</TableHead>
|
||||
<TableHead>年龄</TableHead>
|
||||
<TableHead>性别</TableHead>
|
||||
<TableHead>等级</TableHead>
|
||||
<TableHead>类型</TableHead>
|
||||
<TableHead>可售卖</TableHead>
|
||||
<TableHead>操作</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{cats.map(cat => (
|
||||
<TableRow key={cat.id}>
|
||||
<TableCell>{cat.name}</TableCell>
|
||||
<TableCell>{cat.age} 月</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant={cat.gender === 'male' ? 'default' : 'secondary'}>
|
||||
{cat.gender === 'male' ? '雄' : '雌'}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant="outline">{cat.grade}</Badge>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant="outline">
|
||||
{cat.type === 'breeding_male' ? '种公' : cat.type === 'breeding_female' ? '种母' : '幼猫'}
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Switch
|
||||
checked={cat.is_available}
|
||||
onCheckedChange={() => toggleAvailability(cat)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Button onClick={() => openEditDialog(cat)}>编辑</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>编辑猫咪</DialogTitle>
|
||||
</DialogHeader>
|
||||
{editingCat && (
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<Label htmlFor="name">名称</Label>
|
||||
<Input
|
||||
id="name"
|
||||
value={editingCat.name}
|
||||
onChange={(e) => setEditingCat({ ...editingCat, name: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label htmlFor="age">年龄 (月)</Label>
|
||||
<Input
|
||||
id="age"
|
||||
type="number"
|
||||
value={editingCat.age}
|
||||
onChange={(e) => setEditingCat({ ...editingCat, age: parseInt(e.target.value) })}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label>性别</Label>
|
||||
<Select
|
||||
value={editingCat.gender}
|
||||
onValueChange={(value: string) => setEditingCat({ ...editingCat, gender: value })}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="male">雄</SelectItem>
|
||||
<SelectItem value="female">雌</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<Label>等级</Label>
|
||||
<Select
|
||||
value={editingCat.grade}
|
||||
onValueChange={(value: string) => setEditingCat({ ...editingCat, grade: value })}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="A">A</SelectItem>
|
||||
<SelectItem value="B">B</SelectItem>
|
||||
<SelectItem value="C">C</SelectItem>
|
||||
<SelectItem value="D">D</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<Label>类型</Label>
|
||||
<Select
|
||||
value={editingCat.type}
|
||||
onValueChange={(value: string) => setEditingCat({ ...editingCat, type: value })}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="breeding_male">种公</SelectItem>
|
||||
<SelectItem value="breeding_female">种母</SelectItem>
|
||||
<SelectItem value="kitten">幼猫</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<Label htmlFor="description">描述</Label>
|
||||
<Textarea
|
||||
id="description"
|
||||
value={editingCat.description || ''}
|
||||
onChange={(e) => setEditingCat({ ...editingCat, description: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
<Button onClick={handleEdit}>保存</Button>
|
||||
</div>
|
||||
)}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user