Files
ckb-SuperAdmin/Cunkebao/app/workspace/traffic-distribution/components/keyword-selector.tsx
2025-04-09 09:31:09 +08:00

181 lines
5.4 KiB
TypeScript

"use client"
import { useState } from "react"
import { Search, Plus, X } from "lucide-react"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"
import { Card } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { ScrollArea } from "@/components/ui/scroll-area"
interface KeywordSelectorProps {
onSelect: (keywords: string[]) => void
initialSelected?: string[]
}
export default function KeywordSelector({ onSelect, initialSelected = [] }: KeywordSelectorProps) {
const [searchQuery, setSearchQuery] = useState("")
const [selectedKeywords, setSelectedKeywords] = useState<string[]>(initialSelected)
const [activeCategory, setActiveCategory] = useState("popular")
// 模拟关键词数据
const keywordCategories = {
popular: [
"电商运营",
"社交媒体",
"短视频",
"直播带货",
"私域流量",
"用户增长",
"品牌营销",
"内容创作",
"数据分析",
"SEO优化",
"付费推广",
"用户留存",
"转化率",
"客户服务",
"产品推荐",
],
industry: [
"美妆护肤",
"服装穿搭",
"数码科技",
"家居生活",
"母婴育儿",
"食品饮料",
"健康养生",
"教育培训",
"金融理财",
"旅游出行",
],
scenario: [
"节日促销",
"新品上市",
"会员活动",
"限时折扣",
"满减优惠",
"秒杀活动",
"拼团活动",
"签到奖励",
"复购激励",
"用户调研",
],
custom: ["我的标签1", "我的标签2", "我的标签3", "自定义标签", "个性化标签"],
}
const filteredKeywords = searchQuery
? Object.values(keywordCategories)
.flat()
.filter((kw) => kw.includes(searchQuery))
: keywordCategories[activeCategory as keyof typeof keywordCategories]
const handleKeywordToggle = (keyword: string) => {
let newSelected
if (selectedKeywords.includes(keyword)) {
newSelected = selectedKeywords.filter((k) => k !== keyword)
} else {
newSelected = [...selectedKeywords, keyword]
}
setSelectedKeywords(newSelected)
onSelect(newSelected)
}
const handleRemoveKeyword = (keyword: string) => {
const newSelected = selectedKeywords.filter((k) => k !== keyword)
setSelectedKeywords(newSelected)
onSelect(newSelected)
}
return (
<div className="space-y-4">
{/* 已选关键词展示 */}
{selectedKeywords.length > 0 && (
<div className="space-y-2">
<div className="text-sm font-medium"></div>
<div className="flex flex-wrap gap-2">
{selectedKeywords.map((keyword) => (
<Badge key={keyword} variant="secondary" className="flex items-center gap-1 py-1">
{keyword}
<button
onClick={() => handleRemoveKeyword(keyword)}
className="ml-1 rounded-full hover:bg-gray-200 p-0.5"
>
<X className="h-3 w-3" />
</button>
</Badge>
))}
</div>
</div>
)}
{/* 搜索框 */}
<div className="relative">
<Search className="absolute left-3 top-2.5 h-4 w-4 text-gray-400" />
<Input
placeholder="搜索关键词"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="pl-9"
/>
</div>
{/* 分类标签页 */}
<Tabs
defaultValue="popular"
value={activeCategory}
onValueChange={(value) => {
setActiveCategory(value)
setSearchQuery("")
}}
>
<TabsList className="grid w-full grid-cols-4">
<TabsTrigger value="popular"></TabsTrigger>
<TabsTrigger value="industry"></TabsTrigger>
<TabsTrigger value="scenario"></TabsTrigger>
<TabsTrigger value="custom"></TabsTrigger>
</TabsList>
</Tabs>
{/* 关键词列表 */}
<ScrollArea className="h-[300px]">
<div className="grid grid-cols-2 gap-2">
{filteredKeywords.map((keyword) => (
<Card
key={keyword}
className={`p-3 cursor-pointer hover:shadow-sm transition-shadow ${
selectedKeywords.includes(keyword) ? "bg-blue-50 border-blue-200" : ""
}`}
onClick={() => handleKeywordToggle(keyword)}
>
<div className="flex items-center justify-between">
<span className="text-sm">{keyword}</span>
{selectedKeywords.includes(keyword) && <div className="h-2 w-2 rounded-full bg-blue-500"></div>}
</div>
</Card>
))}
</div>
</ScrollArea>
{/* 添加自定义关键词 */}
<Button
variant="outline"
className="w-full"
onClick={() => {
if (searchQuery && !selectedKeywords.includes(searchQuery)) {
const newSelected = [...selectedKeywords, searchQuery]
setSelectedKeywords(newSelected)
onSelect(newSelected)
setSearchQuery("")
}
}}
>
<Plus className="h-4 w-4 mr-2" />
</Button>
</div>
)
}