Files
sundynix-micro-admin/src/pages/plant/exchange/Config.tsx
T
2026-04-28 16:43:34 +08:00

142 lines
7.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useState } from 'react'
import { Plus, Search, Edit, Trash2, Gift, MoreHorizontal } from 'lucide-react'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
import { Badge } from '@/components/ui/badge'
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'
import { Label } from '@/components/ui/label'
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
import { Textarea } from '@/components/ui/textarea'
const mockItems = [
{ id: '1', name: '多肉植物盆栽', icon: '🪴', points: 500, stock: 50, sold: 23, category: '绿植', isActive: true, description: '精选多肉植物,含陶瓷花盆' },
{ id: '2', name: '园艺工具套装', icon: '🔧', points: 800, stock: 30, sold: 12, category: '工具', isActive: true, description: '包含铲子、剪刀、喷壶' },
{ id: '3', name: '植物生长灯', icon: '💡', points: 1200, stock: 20, sold: 8, category: '设备', isActive: true, description: 'LED全光谱补光灯' },
{ id: '4', name: '有机肥料包', icon: '🌿', points: 300, stock: 100, sold: 67, category: '肥料', isActive: true, description: '天然有机肥料 500g' },
{ id: '5', name: '花盆三件套', icon: '🏺', points: 600, stock: 0, sold: 45, category: '花盆', isActive: false, description: '陶瓷花盆 大中小三件套' },
{ id: '6', name: '种子礼盒', icon: '🌱', points: 200, stock: 200, sold: 156, category: '种子', isActive: true, description: '含向日葵、薄荷、薰衣草种子各一包' },
]
export default function ExchangeConfigPage() {
const [items] = useState(mockItems)
const [dialogOpen, setDialogOpen] = useState(false)
const [search, setSearch] = useState('')
const filtered = items.filter(i => !search || i.name.includes(search))
return (
<div className="space-y-6 animate-fadeIn">
<div>
<h1 className="text-2xl font-bold tracking-tight"></h1>
<p className="text-muted-foreground mt-1"></p>
</div>
<Card className="border-border/60 shadow-soft">
<CardHeader className="pb-3 border-b border-border/40">
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
<CardTitle className="text-lg flex items-center gap-2">
<Gift className="h-5 w-5 text-primary" />
<Badge variant="secondary" className="text-xs">{filtered.length}</Badge>
</CardTitle>
<div className="flex items-center gap-3">
<div className="relative">
<Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
<Input placeholder="搜索商品..." className="pl-9 w-48 h-9" value={search} onChange={e => setSearch(e.target.value)} />
</div>
<Button size="sm" onClick={() => setDialogOpen(true)} className="h-9 gap-1.5">
<Plus className="h-4 w-4" />
</Button>
</div>
</div>
</CardHeader>
<CardContent className="p-0">
<Table>
<TableHeader className="bg-muted/30">
<TableRow>
<TableHead className="pl-6 w-[60px]"></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead> / </TableHead>
<TableHead></TableHead>
<TableHead className="w-[60px]" />
</TableRow>
</TableHeader>
<TableBody>
{filtered.map(item => (
<TableRow key={item.id} className="group hover:bg-muted/20">
<TableCell className="pl-6 text-2xl">{item.icon}</TableCell>
<TableCell>
<div><span className="font-medium">{item.name}</span></div>
<div className="text-xs text-muted-foreground truncate max-w-[200px]">{item.description}</div>
</TableCell>
<TableCell><Badge variant="outline" className="bg-primary/5">{item.category}</Badge></TableCell>
<TableCell><span className="font-mono text-amber-600 font-semibold">{item.points}</span></TableCell>
<TableCell>
<span className={`font-mono text-sm ${item.stock === 0 ? 'text-red-500' : 'text-foreground'}`}>
{item.stock}
</span>
<span className="text-muted-foreground mx-1">/</span>
<span className="font-mono text-sm text-muted-foreground">{item.sold}</span>
</TableCell>
<TableCell>
{item.isActive
? <Badge className="bg-emerald-500/10 text-emerald-600 border-emerald-200 shadow-none"></Badge>
: <Badge variant="secondary" className="shadow-none"></Badge>}
</TableCell>
<TableCell>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="h-8 w-8 opacity-0 group-hover:opacity-100">
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem><Edit className="mr-2 h-4 w-4" /> </DropdownMenuItem>
<DropdownMenuItem className="text-red-500"><Trash2 className="mr-2 h-4 w-4" /> </DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle></DialogTitle>
<DialogDescription></DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label className="text-right"></Label>
<Input className="col-span-3" placeholder="如: 多肉植物盆栽" />
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label className="text-right"></Label>
<Input className="col-span-3" type="number" placeholder="500" />
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label className="text-right"></Label>
<Input className="col-span-3" type="number" placeholder="100" />
</div>
<div className="grid grid-cols-4 items-start gap-4">
<Label className="text-right pt-2"></Label>
<Textarea className="col-span-3" placeholder="商品描述..." rows={3} />
</div>
</div>
<DialogFooter>
<Button variant="outline" onClick={() => setDialogOpen(false)}></Button>
<Button onClick={() => setDialogOpen(false)}></Button>
</DialogFooter>
</DialogContent>
</Dialog>
</div>
)
}