Files
cunkebao_v3/Cunkebao/app/workspace/group-push/page.tsx
2025-04-09 09:31:09 +08:00

256 lines
9.1 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.

"use client"
import { useState } from "react"
import Link from "next/link"
import { useRouter } from "next/navigation"
import { Button } from "@/components/ui/button"
import { Card } from "@/components/ui/card"
import { Switch } from "@/components/ui/switch"
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog"
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
import { PlusCircle, MoreVertical, Edit, Trash2, ArrowLeft, Clock, Search, Filter, RefreshCw } from "lucide-react"
import { Input } from "@/components/ui/input"
import { Badge } from "@/components/ui/badge"
// 模拟数据
const mockTasks = [
{
id: "1",
name: "社群推送测试",
pushTimeRange: "06:00 - 23:59",
dailyPushCount: 20,
pushOrder: "latest",
isLoopPush: false,
isEnabled: true,
groupCount: 3,
contentLibraryCount: 2,
createdAt: "2025-03-15 14:30",
lastPushTime: "2025-03-20 10:25",
totalPushCount: 245,
},
{
id: "2",
name: "产品更新推送",
pushTimeRange: "09:00 - 21:00",
dailyPushCount: 15,
pushOrder: "earliest",
isLoopPush: true,
isEnabled: false,
groupCount: 5,
contentLibraryCount: 1,
createdAt: "2025-03-10 10:15",
lastPushTime: "2025-03-19 16:45",
totalPushCount: 128,
},
{
id: "3",
name: "新客户欢迎",
pushTimeRange: "08:00 - 22:00",
dailyPushCount: 10,
pushOrder: "latest",
isLoopPush: true,
isEnabled: true,
groupCount: 2,
contentLibraryCount: 1,
createdAt: "2025-03-05 09:20",
lastPushTime: "2025-03-18 11:30",
totalPushCount: 87,
},
]
export default function GroupPushPage() {
const router = useRouter()
const [tasks, setTasks] = useState(mockTasks)
const [searchTerm, setSearchTerm] = useState("")
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false)
const [taskToDelete, setTaskToDelete] = useState<string | null>(null)
const handleDelete = (id: string) => {
setTaskToDelete(id)
setDeleteDialogOpen(true)
}
const confirmDelete = () => {
if (taskToDelete) {
setTasks(tasks.filter((task) => task.id !== taskToDelete))
setTaskToDelete(null)
}
setDeleteDialogOpen(false)
}
const handleToggleStatus = (id: string, isEnabled: boolean) => {
setTasks(tasks.map((task) => (task.id === id ? { ...task, isEnabled } : task)))
}
const filteredTasks = tasks.filter((task) => task.name.toLowerCase().includes(searchTerm.toLowerCase()))
return (
<div className="bg-gray-50 min-h-screen pb-16">
{/* 顶部导航栏 */}
<header className="sticky top-0 z-10 bg-white border-b">
<div className="flex items-center justify-between p-4">
<div className="flex items-center space-x-3">
<Button variant="ghost" size="icon" onClick={() => router.push("/workspace")}>
<ArrowLeft className="h-5 w-5" />
</Button>
<h1 className="text-lg font-medium"></h1>
</div>
<Link href="/workspace/group-push/new">
<Button>
<PlusCircle className="h-4 w-4 mr-2" />
</Button>
</Link>
</div>
</header>
{/* 搜索栏 */}
<div className="p-4">
<Card className="p-4 mb-4">
<div className="flex items-center space-x-2">
<div className="relative flex-1">
<Search className="absolute left-3 top-2.5 h-4 w-4 text-gray-400" />
<Input
placeholder="搜索任务名称"
className="pl-9"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
</div>
<Button variant="outline" size="icon">
<Filter className="h-4 w-4" />
</Button>
<Button variant="outline" size="icon">
<RefreshCw className="h-4 w-4" />
</Button>
</div>
</Card>
{/* 任务列表 */}
<div className="space-y-4">
{filteredTasks.map((task) => (
<Card key={task.id} className="p-4">
<div className="flex items-center justify-between mb-4">
<div className="flex items-center space-x-2">
<h3 className="font-medium">{task.name}</h3>
<Badge variant={task.isEnabled ? "success" : "secondary"}>
{task.isEnabled ? "进行中" : "已暂停"}
</Badge>
</div>
<div className="flex items-center space-x-2">
<Switch
checked={task.isEnabled}
onCheckedChange={(checked) => handleToggleStatus(task.id, checked)}
/>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="sm">
<MoreVertical className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<Link href={`/workspace/group-push/${task.id}`}>
<DropdownMenuItem>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="mr-2"
>
<path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z"></path>
<circle cx="12" cy="12" r="3"></circle>
</svg>
</DropdownMenuItem>
</Link>
<Link href={`/workspace/group-push/${task.id}/edit`}>
<DropdownMenuItem>
<Edit className="h-4 w-4 mr-2" />
</DropdownMenuItem>
</Link>
<DropdownMenuItem onClick={() => handleDelete(task.id)}>
<Trash2 className="h-4 w-4 mr-2" />
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
<div className="grid grid-cols-2 gap-4 mb-4">
<div className="text-sm text-gray-500">
<div>{task.groupCount} </div>
<div>{task.contentLibraryCount} </div>
<div>{task.pushTimeRange}</div>
</div>
<div className="text-sm text-gray-500">
<div>{task.dailyPushCount} </div>
<div>{task.totalPushCount} </div>
<div>{task.pushOrder === "latest" ? "按最新" : "按最早"}</div>
</div>
</div>
<div className="flex items-center justify-between text-xs text-gray-500 border-t pt-4">
<div className="flex items-center">
<Clock className="w-4 h-4 mr-1" />
{task.lastPushTime}
</div>
<div>{task.createdAt}</div>
</div>
</Card>
))}
</div>
{/* 空状态 */}
{filteredTasks.length === 0 && (
<div className="flex flex-col items-center justify-center py-12 text-center">
<div className="bg-gray-100 p-4 rounded-full mb-4">
<Clock className="h-10 w-10 text-gray-400" />
</div>
<h3 className="text-lg font-medium text-gray-900 mb-1"></h3>
<p className="text-gray-500 mb-4">"新建任务"</p>
<Link href="/workspace/group-push/new">
<Button>
<PlusCircle className="h-4 w-4 mr-2" />
</Button>
</Link>
</div>
)}
</div>
<Dialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
<DialogContent>
<DialogHeader>
<DialogTitle></DialogTitle>
<DialogDescription></DialogDescription>
</DialogHeader>
<DialogFooter>
<Button variant="outline" onClick={() => setDeleteDialogOpen(false)}>
</Button>
<Button variant="destructive" onClick={confirmDelete}>
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</div>
)
}