From dd17bad4c41ae3b291ce267b9143919a89706ddf Mon Sep 17 00:00:00 2001 From: NVWA Code Agent Date: Thu, 11 Dec 2025 16:46:18 +0000 Subject: [PATCH] application [cat-admin-web] view page [pages/queue-management] development --- .../src/pages/queue-management.tsx | 277 ++++++++++++++++++ 1 file changed, 277 insertions(+) create mode 100644 apps/cat-admin-web/src/pages/queue-management.tsx diff --git a/apps/cat-admin-web/src/pages/queue-management.tsx b/apps/cat-admin-web/src/pages/queue-management.tsx new file mode 100644 index 0000000..cda6f3b --- /dev/null +++ b/apps/cat-admin-web/src/pages/queue-management.tsx @@ -0,0 +1,277 @@ +import React, { useState, useEffect } from 'react'; +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 { Input } from '@/components/ui/input'; +import { Label } from '@/components/ui/label'; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; + +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; +} + +interface Reservation { + id: number; + user_id: string; + cat_id?: number; + deposit: string; + status: string; + queue_order?: number; + created_at: string; + updated_at: string; + user: { name: string }; + cat?: { name: string }; +} + +interface QueueRules { + maxQueueLength: number; + defaultDeposit: number; + ruleType: 'fifo' | 'priority'; +} + +export default function QueueManagement() { + const [cats, setCats] = useState([]); + const [reservations, setReservations] = useState([]); + const [rules, setRules] = useState({ + maxQueueLength: 10, + defaultDeposit: 100, + ruleType: 'fifo' + }); + + useEffect(() => { + fetchCats(); + fetchReservations(); + }, []); + + const fetchCats = async () => { + const { data, error } = await entities.from('cat').select('*'); + if (error) { + console.error(error); + return; + } + setCats(data || []); + }; + + const fetchReservations = async () => { + const { data, error } = await entities + .from('reservation') + .select('*, user!inner(name), cat(name)') + .eq('status', 'queuing') + .order('queue_order'); + if (error) { + console.error(error); + return; + } + setReservations(data || []); + }; + + const toggleQueuing = async (cat: Cat) => { + // Assuming enabling queuing sets is_available to true + 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 updateRules = (key: keyof QueueRules, value: any) => { + setRules(prev => ({ ...prev, [key]: value })); + }; + + const moveQueue = async (reservation: Reservation, direction: 'up' | 'down') => { + const currentIndex = reservations.findIndex(r => r.id === reservation.id); + if (direction === 'up' && currentIndex > 0) { + const prev = reservations[currentIndex - 1]; + await swapOrder(reservation, prev); + } else if (direction === 'down' && currentIndex < reservations.length - 1) { + const next = reservations[currentIndex + 1]; + await swapOrder(reservation, next); + } + fetchReservations(); + }; + + const swapOrder = async (res1: Reservation, res2: Reservation) => { + const { error: error1 } = await entities.from('reservation').update({ queue_order: res2.queue_order }).eq('id', res1.id); + const { error: error2 } = await entities.from('reservation').update({ queue_order: res1.queue_order }).eq('id', res2.id); + if (error1 || error2) { + console.error(error1 || error2); + } + }; + + const changeStatus = async (reservation: Reservation, newStatus: string) => { + const { error } = await entities.from('reservation').update({ status: newStatus }).eq('id', reservation.id); + if (error) { + console.error(error); + return; + } + fetchReservations(); + }; + + return ( +
+

排队管理

+ + + 开启排队 + 设置规则 + 管理队列 + + + + + 开启猫咪排队功能 + + + + + + 名称 + 年龄 + 性别 + 等级 + 类型 + 排队开启 + + + + {cats.map(cat => ( + + {cat.name} + {cat.age} 月 + + + {cat.gender === 'male' ? '雄' : '雌'} + + + + {cat.grade} + + + + {cat.type === 'breeding_male' ? '种公' : cat.type === 'breeding_female' ? '种母' : '幼猫'} + + + + toggleQueuing(cat)} + /> + + + ))} + +
+
+
+
+ + + + 设置排队规则 + + +
+ + updateRules('maxQueueLength', parseInt(e.target.value))} + /> +
+
+ + updateRules('defaultDeposit', parseFloat(e.target.value))} + /> +
+
+ + +
+
+
+
+ + + + 管理排队队列 + + + + + + 队列顺序 + 用户 + 猫咪 + 定金 + 状态 + 操作 + + + + {reservations.map((res, index) => ( + + {res.queue_order} + {res.user.name} + {res.cat?.name || 'N/A'} + {res.deposit} + + {res.status} + + +
+ + + + +
+
+
+ ))} +
+
+
+
+
+
+
+ ); +} \ No newline at end of file