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