1006 lines
43 KiB
TypeScript
1006 lines
43 KiB
TypeScript
"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>
|
||
)
|
||
}
|