2026-03-17 13:17:02 +08:00

1006 lines
43 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 { DashboardShell } from "@/components/dashboard-shell"
import { DashboardHeader } from "@/components/dashboard-header"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Slider } from "@/components/ui/slider"
import { Switch } from "@/components/ui/switch"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import { Badge } from "@/components/ui/badge"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Heart, Save, RefreshCw, Clock, Gift, BarChart3, Edit } from "lucide-react"
import { AffinityRuleDialog, type AffinityRule } from "@/components/affinity/affinity-rule-dialog"
import { AffinityLevelDialog, type AffinityLevel } from "@/components/affinity/affinity-level-dialog"
// 初始互动规则数据
const initialRules: AffinityRule[] = [
{
id: "rule-1",
name: "使用卡片",
type: "card",
description: "用户使用洛天依卡片",
minChange: 1,
maxChange: 3,
singleCap: 3,
dailyCap: 10,
isNegative: false,
isEnabled: true,
},
{
id: "rule-2",
name: "对话",
type: "chat",
description: "与洛天依进行对话",
minChange: 1,
maxChange: 5,
singleCap: 5,
dailyCap: 15,
isNegative: false,
isEnabled: true,
},
{
id: "rule-3",
name: "喂食",
type: "feed",
description: "给洛天依喂食",
minChange: 2,
maxChange: 8,
singleCap: 8,
dailyCap: 16,
isNegative: false,
isEnabled: true,
},
{
id: "rule-4",
name: "抚摸",
type: "touch",
description: "抚摸洛天依",
minChange: 1,
maxChange: 3,
singleCap: 3,
dailyCap: 9,
isNegative: false,
isEnabled: true,
},
{
id: "rule-5",
name: "换装",
type: "dress",
description: "为洛天依更换服装",
minChange: 2,
maxChange: 6,
singleCap: 6,
dailyCap: 12,
isNegative: false,
isEnabled: true,
},
{
id: "rule-6",
name: "使用道具",
type: "prop",
description: "使用互动道具",
minChange: 1,
maxChange: 4,
singleCap: 4,
dailyCap: 12,
isNegative: false,
isEnabled: true,
},
{
id: "rule-7",
name: "送礼物",
type: "gift",
description: "赠送礼物给洛天依",
minChange: 5,
maxChange: 15,
singleCap: 15,
dailyCap: 20,
isNegative: false,
isEnabled: true,
},
{
id: "rule-8",
name: "无互动衰减",
type: "decay",
description: "长时间不互动导致好感度下降",
minChange: -3,
maxChange: -1,
singleCap: 3,
dailyCap: 5,
isNegative: true,
isEnabled: true,
},
]
// 初始好感度等级数据
const initialLevels: AffinityLevel[] = [
{
id: "level-1",
level: 1,
name: "初识",
minAffinity: 0,
maxAffinity: 20,
unlockContent: "基础对话功能",
rewardType: "unlock",
isEnabled: true,
},
{
id: "level-2",
level: 2,
name: "相识",
minAffinity: 21,
maxAffinity: 40,
unlockContent: "基础服装、道具使用",
rewardType: "unlock",
isEnabled: true,
},
{
id: "level-3",
level: 3,
name: "熟悉",
minAffinity: 41,
maxAffinity: 60,
unlockContent: "更多服装、特殊对话",
rewardType: "unlock",
isEnabled: true,
},
{
id: "level-4",
level: 4,
name: "亲密",
minAffinity: 61,
maxAffinity: 80,
unlockContent: "限定服装、特殊互动",
rewardType: "unlock",
isEnabled: true,
},
{
id: "level-5",
level: 5,
name: "挚友",
minAffinity: 81,
maxAffinity: 100,
unlockContent: "专属内容、特殊剧情",
rewardType: "unlock",
isEnabled: true,
},
]
export default function AffinityPage() {
// 状态管理
const [rules, setRules] = useState<AffinityRule[]>(initialRules)
const [levels, setLevels] = useState<AffinityLevel[]>(initialLevels)
// 处理规则保存
const handleSaveRule = (updatedRule: AffinityRule) => {
setRules((prevRules) => {
const index = prevRules.findIndex((rule) => rule.id === updatedRule.id)
if (index >= 0) {
// 更新现有规则
const newRules = [...prevRules]
newRules[index] = updatedRule
return newRules
} else {
// 添加新规则
return [...prevRules, updatedRule]
}
})
}
// 处理等级保存
const handleSaveLevel = (updatedLevel: AffinityLevel) => {
setLevels((prevLevels) => {
const index = prevLevels.findIndex((level) => level.id === updatedLevel.id)
if (index >= 0) {
// 更新现有等级
const newLevels = [...prevLevels]
newLevels[index] = updatedLevel
return newLevels
} else {
// 添加新等级
return [...prevLevels.sort((a, b) => a.level - b.level), updatedLevel].sort((a, b) => a.level - b.level)
}
})
}
// 处理设置保存
const handleSaveSettings = () => {
alert("设置已保存!")
}
return (
<DashboardShell>
<DashboardHeader heading="好感度系统" text="管理洛天依与用户之间的好感度机制">
<Button
className="bg-gradient-to-r from-pink-500 to-purple-600 hover:from-pink-600 hover:to-purple-700 transition-all duration-300 shadow-md hover:shadow-lg"
onClick={handleSaveSettings}
>
<Save className="mr-2 h-4 w-4" />
</Button>
</DashboardHeader>
<Tabs defaultValue="overview" className="space-y-4">
<TabsList className="bg-white p-1 shadow-md rounded-lg border">
<TabsTrigger
value="overview"
className="data-[state=active]:bg-gradient-to-r data-[state=active]:from-pink-500 data-[state=active]:to-purple-600 data-[state=active]:text-white rounded-md transition-all duration-300"
>
</TabsTrigger>
<TabsTrigger
value="rules"
className="data-[state=active]:bg-gradient-to-r data-[state=active]:from-pink-500 data-[state=active]:to-purple-600 data-[state=active]:text-white rounded-md transition-all duration-300"
>
</TabsTrigger>
<TabsTrigger
value="levels"
className="data-[state=active]:bg-gradient-to-r data-[state=active]:from-pink-500 data-[state=active]:to-purple-600 data-[state=active]:text-white rounded-md transition-all duration-300"
>
</TabsTrigger>
<TabsTrigger
value="statistics"
className="data-[state=active]:bg-gradient-to-r data-[state=active]:from-pink-500 data-[state=active]:to-purple-600 data-[state=active]:text-white rounded-md transition-all duration-300"
>
</TabsTrigger>
</TabsList>
{/* 系统概览标签页 */}
<TabsContent value="overview" className="space-y-4">
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
<Card className="border-none shadow-lg hover:shadow-xl transition-all duration-300 overflow-hidden relative group">
<div className="absolute inset-0 bg-gradient-to-r from-pink-500/5 to-purple-500/5 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium"></CardTitle>
<div className="p-1.5 rounded-full bg-pink-100">
<Heart className="h-5 w-5 text-pink-600" />
</div>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">78.5</div>
<p className="text-xs text-muted-foreground flex items-center">
<span className="inline-block h-1.5 w-1.5 rounded-full bg-green-500 mr-1.5"></span>
5.2%
</p>
</CardContent>
</Card>
<Card className="border-none shadow-lg hover:shadow-xl transition-all duration-300 overflow-hidden relative group">
<div className="absolute inset-0 bg-gradient-to-r from-purple-500/5 to-blue-500/5 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium"></CardTitle>
<div className="p-1.5 rounded-full bg-purple-100">
<Heart className="h-5 w-5 text-purple-600" />
</div>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">100</div>
<p className="text-xs text-muted-foreground flex items-center">
<span className="inline-block h-1.5 w-1.5 rounded-full bg-purple-500 mr-1.5"></span>
156
</p>
</CardContent>
</Card>
<Card className="border-none shadow-lg hover:shadow-xl transition-all duration-300 overflow-hidden relative group">
<div className="absolute inset-0 bg-gradient-to-r from-blue-500/5 to-teal-500/5 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">/</CardTitle>
<div className="p-1.5 rounded-full bg-blue-100">
<Gift className="h-5 w-5 text-blue-600" />
</div>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">12,543</div>
<p className="text-xs text-muted-foreground flex items-center">
<span className="inline-block h-1.5 w-1.5 rounded-full bg-green-500 mr-1.5"></span>
8.7%
</p>
</CardContent>
</Card>
<Card className="border-none shadow-lg hover:shadow-xl transition-all duration-300 overflow-hidden relative group">
<div className="absolute inset-0 bg-gradient-to-r from-teal-500/5 to-green-500/5 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium"></CardTitle>
<div className="p-1.5 rounded-full bg-teal-100">
<BarChart3 className="h-5 w-5 text-teal-600" />
</div>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">86.4%</div>
<p className="text-xs text-muted-foreground flex items-center">
<span className="inline-block h-1.5 w-1.5 rounded-full bg-green-500 mr-1.5"></span>
3.2%
</p>
</CardContent>
</Card>
</div>
<Card className="border-none shadow-lg bg-gradient-to-br from-white to-purple-50">
<CardHeader>
<CardTitle className="text-xl font-bold flex items-center">
<span className="bg-clip-text text-transparent bg-gradient-to-r from-purple-600 to-pink-600">
</span>
<div className="ml-2 h-1 w-10 bg-gradient-to-r from-purple-600 to-pink-600 rounded-full"></div>
</CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="base-affinity"></Label>
<div className="flex items-center space-x-2">
<Input
id="base-affinity"
type="number"
defaultValue="10"
min="0"
max="100"
className="border-gray-300 focus-visible:ring-pink-500"
/>
<span className="text-sm text-gray-500">/ 100</span>
</div>
<p className="text-xs text-gray-500"></p>
</div>
<div className="space-y-2">
<Label htmlFor="max-affinity"></Label>
<div className="flex items-center space-x-2">
<Input
id="max-affinity"
type="number"
defaultValue="100"
min="0"
max="999"
className="border-gray-300 focus-visible:ring-pink-500"
/>
<span className="text-sm text-gray-500"></span>
</div>
<p className="text-xs text-gray-500"></p>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="daily-cap"></Label>
<div className="flex items-center space-x-2">
<Input
id="daily-cap"
type="number"
defaultValue="20"
min="0"
max="100"
className="border-gray-300 focus-visible:ring-pink-500"
/>
<span className="text-sm text-gray-500"> / </span>
</div>
<p className="text-xs text-gray-500"></p>
</div>
<div className="space-y-2">
<Label htmlFor="decay-rate"></Label>
<div className="flex items-center space-x-2">
<Input
id="decay-rate"
type="number"
defaultValue="2"
min="0"
max="10"
step="0.1"
className="border-gray-300 focus-visible:ring-pink-500"
/>
<span className="text-sm text-gray-500"> / </span>
</div>
<p className="text-xs text-gray-500"></p>
</div>
</div>
<div className="space-y-2">
<Label htmlFor="decay-threshold"></Label>
<div className="pt-2">
<Slider id="decay-threshold" defaultValue={[3]} max={14} min={1} step={1} className="w-full" />
</div>
<div className="flex justify-between text-xs text-gray-500">
<span>1</span>
<span>3</span>
<span>7</span>
<span>14</span>
</div>
<p className="text-xs text-gray-500"></p>
</div>
<div className="flex items-center space-x-2 pt-2">
<Switch id="enable-notifications" defaultChecked />
<Label htmlFor="enable-notifications" className="cursor-pointer">
</Label>
</div>
<div className="flex items-center space-x-2 pt-2">
<Switch id="enable-rewards" defaultChecked />
<Label htmlFor="enable-rewards" className="cursor-pointer">
</Label>
</div>
</CardContent>
<CardFooter className="flex justify-between">
<Button variant="outline" className="hover:bg-pink-50 hover:text-pink-700 transition-all duration-200">
<RefreshCw className="mr-2 h-4 w-4" />
</Button>
<Button
className="bg-gradient-to-r from-pink-500 to-purple-600 hover:from-pink-600 hover:to-purple-700 transition-all duration-300 shadow-md hover:shadow-lg"
onClick={handleSaveSettings}
>
<Save className="mr-2 h-4 w-4" />
</Button>
</CardFooter>
</Card>
</TabsContent>
{/* 互动规则标签页 */}
<TabsContent value="rules" className="space-y-4">
<Card className="border-none shadow-lg bg-gradient-to-br from-white to-purple-50">
<CardHeader className="flex flex-row items-center justify-between">
<div>
<CardTitle className="text-xl font-bold flex items-center">
<span className="bg-clip-text text-transparent bg-gradient-to-r from-purple-600 to-pink-600">
</span>
<div className="ml-2 h-1 w-10 bg-gradient-to-r from-purple-600 to-pink-600 rounded-full"></div>
</CardTitle>
<CardDescription></CardDescription>
</div>
<AffinityRuleDialog onSave={handleSaveRule} />
</CardHeader>
<CardContent>
<Table>
<TableHeader className="bg-gray-50">
<TableRow>
<TableHead className="w-[200px]"></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead className="text-right"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{rules.map((rule) => (
<TableRow key={rule.id} className="hover:bg-gray-50 transition-colors">
<TableCell className="font-medium">{rule.name}</TableCell>
<TableCell>{rule.description}</TableCell>
<TableCell>
{rule.isNegative ? "" : "+"}
{rule.minChange}~{rule.maxChange}
</TableCell>
<TableCell>{rule.singleCap}</TableCell>
<TableCell>{rule.dailyCap}</TableCell>
<TableCell>
<Badge
className={
rule.isEnabled ? "bg-green-500 hover:bg-green-600" : "bg-gray-500 hover:bg-gray-600"
}
>
{rule.isEnabled ? "已启用" : "已禁用"}
</Badge>
</TableCell>
<TableCell className="text-right">
<AffinityRuleDialog
mode="edit"
rule={rule}
onSave={handleSaveRule}
trigger={
<Button variant="ghost" size="icon" className="hover:bg-pink-50 hover:text-pink-600">
<Edit className="h-4 w-4" />
</Button>
}
/>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
<Card className="border-none shadow-lg bg-gradient-to-br from-white to-blue-50">
<CardHeader>
<CardTitle className="text-xl font-bold flex items-center">
<span className="bg-clip-text text-transparent bg-gradient-to-r from-blue-600 to-teal-600">
</span>
<div className="ml-2 h-1 w-10 bg-gradient-to-r from-blue-600 to-teal-600 rounded-full"></div>
</CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="decay-start"></Label>
<Select defaultValue="3">
<SelectTrigger className="border-gray-300 focus:ring-blue-500">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="1">1</SelectItem>
<SelectItem value="2">2</SelectItem>
<SelectItem value="3">3</SelectItem>
<SelectItem value="5">5</SelectItem>
<SelectItem value="7">7</SelectItem>
<SelectItem value="14">14</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label htmlFor="decay-rate"></Label>
<div className="flex items-center space-x-2">
<Input
id="decay-rate"
type="number"
defaultValue="2"
min="0"
max="10"
step="0.1"
className="border-gray-300 focus-visible:ring-blue-500"
/>
<span className="text-sm text-gray-500"> / </span>
</div>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="min-decay"></Label>
<div className="flex items-center space-x-2">
<Input
id="min-decay"
type="number"
defaultValue="1"
min="0"
max="10"
className="border-gray-300 focus-visible:ring-blue-500"
/>
<span className="text-sm text-gray-500"> / </span>
</div>
</div>
<div className="space-y-2">
<Label htmlFor="max-decay"></Label>
<div className="flex items-center space-x-2">
<Input
id="max-decay"
type="number"
defaultValue="3"
min="0"
max="20"
className="border-gray-300 focus-visible:ring-blue-500"
/>
<span className="text-sm text-gray-500"> / </span>
</div>
</div>
</div>
<div className="space-y-2">
<Label htmlFor="decay-cap"></Label>
<div className="flex items-center space-x-2">
<Input
id="decay-cap"
type="number"
defaultValue="5"
min="0"
max="20"
className="border-gray-300 focus-visible:ring-blue-500"
/>
<span className="text-sm text-gray-500"> / </span>
</div>
</div>
<div className="space-y-2">
<Label htmlFor="min-affinity"></Label>
<div className="flex items-center space-x-2">
<Input
id="min-affinity"
type="number"
defaultValue="0"
min="0"
max="50"
className="border-gray-300 focus-visible:ring-blue-500"
/>
<span className="text-sm text-gray-500"></span>
</div>
<p className="text-xs text-gray-500"></p>
</div>
<div className="flex items-center space-x-2 pt-2">
<Switch id="notify-decay" defaultChecked />
<Label htmlFor="notify-decay" className="cursor-pointer">
</Label>
</div>
</CardContent>
<CardFooter className="flex justify-between">
<Button variant="outline" className="hover:bg-blue-50 hover:text-blue-700 transition-all duration-200">
<RefreshCw className="mr-2 h-4 w-4" />
</Button>
<Button
className="bg-gradient-to-r from-blue-500 to-teal-600 hover:from-blue-600 hover:to-teal-700 transition-all duration-300 shadow-md hover:shadow-lg"
onClick={handleSaveSettings}
>
<Clock className="mr-2 h-4 w-4" />
</Button>
</CardFooter>
</Card>
</TabsContent>
{/* 等级奖励标签页 */}
<TabsContent value="levels" className="space-y-4">
<Card className="border-none shadow-lg bg-gradient-to-br from-white to-purple-50">
<CardHeader className="flex flex-row items-center justify-between">
<div>
<CardTitle className="text-xl font-bold flex items-center">
<span className="bg-clip-text text-transparent bg-gradient-to-r from-purple-600 to-pink-600">
</span>
<div className="ml-2 h-1 w-10 bg-gradient-to-r from-purple-600 to-pink-600 rounded-full"></div>
</CardTitle>
<CardDescription></CardDescription>
</div>
<AffinityLevelDialog onSave={handleSaveLevel} />
</CardHeader>
<CardContent>
<Table>
<TableHeader className="bg-gray-50">
<TableRow>
<TableHead className="w-[100px]"></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead className="text-right"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{levels.map((level) => (
<TableRow key={level.id} className="hover:bg-gray-50 transition-colors">
<TableCell className="font-medium">{level.level}</TableCell>
<TableCell>{level.name}</TableCell>
<TableCell>
{level.minAffinity}-{level.maxAffinity}
</TableCell>
<TableCell>{level.unlockContent}</TableCell>
<TableCell>
<Badge
className={
level.isEnabled ? "bg-green-500 hover:bg-green-600" : "bg-gray-500 hover:bg-gray-600"
}
>
{level.isEnabled ? "已启用" : "已禁用"}
</Badge>
</TableCell>
<TableCell className="text-right">
<AffinityLevelDialog
mode="edit"
level={level}
onSave={handleSaveLevel}
trigger={
<Button variant="ghost" size="icon" className="hover:bg-pink-50 hover:text-pink-600">
<Edit className="h-4 w-4" />
</Button>
}
/>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
<Card className="border-none shadow-lg bg-gradient-to-br from-white to-blue-50">
<CardHeader>
<CardTitle className="text-xl font-bold flex items-center">
<span className="bg-clip-text text-transparent bg-gradient-to-r from-blue-600 to-teal-600">
</span>
<div className="ml-2 h-1 w-10 bg-gradient-to-r from-blue-600 to-teal-600 rounded-full"></div>
</CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="reward-type"></Label>
<Select defaultValue="unlock">
<SelectTrigger className="border-gray-300 focus:ring-blue-500">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="unlock"></SelectItem>
<SelectItem value="item"></SelectItem>
<SelectItem value="currency"></SelectItem>
<SelectItem value="mixed"></SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label htmlFor="notification-type"></Label>
<Select defaultValue="popup">
<SelectTrigger className="border-gray-300 focus:ring-blue-500">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="popup"></SelectItem>
<SelectItem value="message"></SelectItem>
<SelectItem value="animation"></SelectItem>
<SelectItem value="all"></SelectItem>
</SelectContent>
</Select>
</div>
</div>
<div className="flex items-center space-x-2 pt-2">
<Switch id="level-up-notification" defaultChecked />
<Label htmlFor="level-up-notification" className="cursor-pointer">
</Label>
</div>
<div className="flex items-center space-x-2 pt-2">
<Switch id="special-animation" defaultChecked />
<Label htmlFor="special-animation" className="cursor-pointer">
</Label>
</div>
<div className="flex items-center space-x-2 pt-2">
<Switch id="milestone-rewards" defaultChecked />
<Label htmlFor="milestone-rewards" className="cursor-pointer">
</Label>
</div>
</CardContent>
<CardFooter className="flex justify-between">
<Button variant="outline" className="hover:bg-blue-50 hover:text-blue-700 transition-all duration-200">
<RefreshCw className="mr-2 h-4 w-4" />
</Button>
<Button
className="bg-gradient-to-r from-blue-500 to-teal-600 hover:from-blue-600 hover:to-teal-700 transition-all duration-300 shadow-md hover:shadow-lg"
onClick={handleSaveSettings}
>
<Gift className="mr-2 h-4 w-4" />
</Button>
</CardFooter>
</Card>
</TabsContent>
{/* 数据统计标签页 */}
<TabsContent value="statistics" className="space-y-4">
<Card className="border-none shadow-lg bg-gradient-to-br from-white to-purple-50">
<CardHeader>
<CardTitle className="text-xl font-bold flex items-center">
<span className="bg-clip-text text-transparent bg-gradient-to-r from-purple-600 to-pink-600">
</span>
<div className="ml-2 h-1 w-10 bg-gradient-to-r from-purple-600 to-pink-600 rounded-full"></div>
</CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
<Card className="border shadow-sm">
<CardHeader className="pb-2">
<CardTitle className="text-sm"></CardTitle>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">78.5</div>
<p className="text-xs text-green-600"> 5.2%</p>
</CardContent>
</Card>
<Card className="border shadow-sm">
<CardHeader className="pb-2">
<CardTitle className="text-sm"></CardTitle>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold"></div>
<p className="text-xs text-blue-600">60-80</p>
</CardContent>
</Card>
<Card className="border shadow-sm">
<CardHeader className="pb-2">
<CardTitle className="text-sm"></CardTitle>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold"></div>
<p className="text-xs text-purple-600">42%</p>
</CardContent>
</Card>
<Card className="border shadow-sm">
<CardHeader className="pb-2">
<CardTitle className="text-sm"></CardTitle>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">86.4%</div>
<p className="text-xs text-green-600"> 3.2%</p>
</CardContent>
</Card>
</div>
<div className="mt-6 p-4 bg-gray-50 rounded-lg">
<h3 className="text-sm font-medium mb-4"></h3>
<div className="space-y-4">
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span>5 (81-100)</span>
<span className="font-medium">15%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2.5">
<div className="bg-pink-600 h-2.5 rounded-full" style={{ width: "15%" }}></div>
</div>
</div>
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span>4 (61-80)</span>
<span className="font-medium">32%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2.5">
<div className="bg-purple-600 h-2.5 rounded-full" style={{ width: "32%" }}></div>
</div>
</div>
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span>3 (41-60)</span>
<span className="font-medium">28%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2.5">
<div className="bg-blue-600 h-2.5 rounded-full" style={{ width: "28%" }}></div>
</div>
</div>
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span>2 (21-40)</span>
<span className="font-medium">18%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2.5">
<div className="bg-teal-600 h-2.5 rounded-full" style={{ width: "18%" }}></div>
</div>
</div>
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span>1 (0-20)</span>
<span className="font-medium">7%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2.5">
<div className="bg-green-600 h-2.5 rounded-full" style={{ width: "7%" }}></div>
</div>
</div>
</div>
</div>
</CardContent>
</Card>
<Card className="border-none shadow-lg bg-gradient-to-br from-white to-blue-50">
<CardHeader>
<CardTitle className="text-xl font-bold flex items-center">
<span className="bg-clip-text text-transparent bg-gradient-to-r from-blue-600 to-teal-600">
</span>
<div className="ml-2 h-1 w-10 bg-gradient-to-r from-blue-600 to-teal-600 rounded-full"></div>
</CardTitle>
<CardDescription></CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="p-4 bg-gray-50 rounded-lg">
<h3 className="text-sm font-medium mb-4"></h3>
<div className="space-y-4">
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span></span>
<span className="font-medium">42%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2.5">
<div className="bg-pink-600 h-2.5 rounded-full" style={{ width: "42%" }}></div>
</div>
</div>
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span></span>
<span className="font-medium">18%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2.5">
<div className="bg-purple-600 h-2.5 rounded-full" style={{ width: "18%" }}></div>
</div>
</div>
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span>使</span>
<span className="font-medium">15%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2.5">
<div className="bg-blue-600 h-2.5 rounded-full" style={{ width: "15%" }}></div>
</div>
</div>
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span></span>
<span className="font-medium">12%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2.5">
<div className="bg-teal-600 h-2.5 rounded-full" style={{ width: "12%" }}></div>
</div>
</div>
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span></span>
<span className="font-medium">8%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2.5">
<div className="bg-green-600 h-2.5 rounded-full" style={{ width: "8%" }}></div>
</div>
</div>
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span></span>
<span className="font-medium">5%</span>
</div>
<div className="w-full bg-gray-200 rounded-full h-2.5">
<div className="bg-gray-600 h-2.5 rounded-full" style={{ width: "5%" }}></div>
</div>
</div>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label></Label>
<div className="p-3 bg-white rounded-lg border shadow-sm">
<p className="text-xl font-bold">24.7</p>
<p className="text-xs text-green-600"> 8.3%</p>
</div>
</div>
<div className="space-y-2">
<Label></Label>
<div className="p-3 bg-white rounded-lg border shadow-sm">
<p className="text-xl font-bold">38</p>
<p className="text-xs text-green-600"> 12.5%</p>
</div>
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label></Label>
<div className="p-3 bg-white rounded-lg border shadow-sm">
<p className="text-xl font-bold">20:00-22:00</p>
<p className="text-xs text-blue-600">32%</p>
</div>
</div>
<div className="space-y-2">
<Label></Label>
<div className="p-3 bg-white rounded-lg border shadow-sm">
<p className="text-xl font-bold">+</p>
<p className="text-xs text-purple-600"></p>
</div>
</div>
</div>
</CardContent>
</Card>
</TabsContent>
</Tabs>
</DashboardShell>
)
}