application [cat-admin-web] view page [pages/cat-management] development

This commit is contained in:
NVWA Code Agent
2025-12-11 16:45:37 +00:00
parent 68f291d76c
commit ae09db28cb

View 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>
);
}