8f13604e0e
- 课程详情页下架付费购买与扫码支付弹窗 - 首页/能力导览文案 购买→免费使用 - 付费面(会员/技能广场/用量包/课程)均已免费化,原 orders/payment 模块保留后端备用
305 lines
19 KiB
TypeScript
Executable File
305 lines
19 KiB
TypeScript
Executable File
'use client';
|
||
|
||
import Link from 'next/link';
|
||
import { useState, useEffect } from 'react';
|
||
import { HomePageClient } from './home-client';
|
||
import { ArrowRight, Sparkles, BookOpen, Bot, Wrench, GraduationCap, FileText, Puzzle, MessageSquare, Code, BarChart3 } from 'lucide-react';
|
||
import { Badge } from '@/components/ui/badge';
|
||
import { Card } from '@/components/ui/card';
|
||
import { useT } from '@/i18n';
|
||
import { API_BASE } from '@/lib/config';
|
||
|
||
export default function HomePage() {
|
||
const t = useT();
|
||
const [courses, setCourses] = useState<any[]>([]);
|
||
const [featuredTools, setFeaturedTools] = useState<any[]>([]);
|
||
const [stats, setStats] = useState<{ tools: number; courses: number; prompts: number; practices: number } | null>(null);
|
||
|
||
useEffect(() => {
|
||
Promise.all([
|
||
fetch(`${API_BASE}/tools?isFeatured=true&pageSize=6&categoryId=7`).then(r => r.json()),
|
||
fetch(`${API_BASE}/courses?pageSize=3`).then(r => r.json()),
|
||
fetch(`${API_BASE}/tools?pageSize=1`).then(r => r.json()),
|
||
fetch(`${API_BASE}/prompts?pageSize=1`).then(r => r.json()),
|
||
fetch(`${API_BASE}/practices?pageSize=1`).then(r => r.json()),
|
||
]).then(([toolsData, coursesData, toolsAll, promptsData, practicesData]) => {
|
||
setFeaturedTools(toolsData.items || []);
|
||
setCourses(coursesData.items || []);
|
||
setStats({
|
||
tools: toolsAll.total || toolsAll.items?.length || 0,
|
||
courses: coursesData.total || coursesData.items?.length || 0,
|
||
prompts: promptsData.total || promptsData.items?.length || 0,
|
||
practices: practicesData.total || practicesData.items?.length || 0,
|
||
});
|
||
}).catch(() => {
|
||
setStats({ tools: 0, courses: 0, prompts: 0, practices: 0 });
|
||
});
|
||
}, []);
|
||
|
||
const statItems = [
|
||
{ value: stats ? `${stats.tools}+` : '--', label: '收录工具', href: '/tools', icon: Wrench },
|
||
{ value: stats ? `${stats.courses}+` : '--', label: '课程资源', href: '/courses', icon: BookOpen },
|
||
{ value: stats ? `${stats.prompts}+` : '--', label: '提示词库', href: '/prompts', icon: FileText },
|
||
{ value: stats ? `${stats.practices}+` : '--', label: '练习场景', href: '/practices', icon: Puzzle },
|
||
];
|
||
|
||
return (
|
||
<HomePageClient>
|
||
{/* Hero */}
|
||
<section className="relative overflow-hidden">
|
||
<div className="absolute inset-0 bg-gradient-to-br from-brand-50 via-white to-blue-50 dark:from-brand-950/30 dark:via-background dark:to-blue-950/20" />
|
||
<div className="absolute inset-0 bg-[url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjAiIGhlaWdodD0iNjAiIHZpZXdCb3g9IjAgMCA2MCA2MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxnIGZpbGw9IiM2NjdlZWEiIGZpbGwtb3BhY2l0eT0iMC4wNCI+PHBhdGggZD0iTTM2IDM0djItSDI0di0xaDEyek0zNiAyNHYySDI0di0yaDEyeiIvPjwvZz48L2c+PC9zdmc+')] opacity-50 dark:opacity-20" />
|
||
<div className="absolute top-20 right-0 w-96 h-96 bg-brand-400/10 dark:bg-brand-400/5 rounded-full blur-3xl" />
|
||
<div className="absolute bottom-0 left-20 w-72 h-72 bg-blue-400/10 dark:bg-blue-400/5 rounded-full blur-3xl" />
|
||
|
||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-20 md:py-28 relative">
|
||
<div className="text-center max-w-3xl mx-auto animate-fade-in-up">
|
||
<span className="inline-flex items-center gap-1.5 px-4 py-1.5 text-sm font-medium text-brand-700 dark:text-brand-300 bg-brand-100 dark:bg-brand-900/50 rounded-full mb-8 border border-brand-200 dark:border-brand-800">
|
||
<Sparkles className="w-3.5 h-3.5" />
|
||
精选AI工具 · 真实评测
|
||
</span>
|
||
<h1 className="text-4xl md:text-6xl font-bold tracking-tight leading-tight">
|
||
<span className="bg-gradient-to-r from-brand-600 via-brand-500 to-blue-500 bg-clip-text text-transparent">
|
||
找AI工具?先看真实评测
|
||
</span>
|
||
</h1>
|
||
<p className="mt-6 text-lg md:text-xl text-muted-foreground leading-relaxed max-w-2xl mx-auto">
|
||
汇集优质AI工具,提供真实使用评测、详细参数对比和专业教程。帮你快速找到合适工具,系统化提升AI应用能力。
|
||
</p>
|
||
<div className="mt-10 flex flex-col sm:flex-row gap-4 justify-center">
|
||
<Link href="/tools" className="inline-flex items-center justify-center gap-2 px-8 py-3 text-base font-medium text-white bg-brand-600 rounded-xl hover:bg-brand-700 transition-all shadow-lg shadow-brand-200/50 dark:shadow-brand-900/30 hover:shadow-xl hover:-translate-y-0.5 active:scale-[0.98]">
|
||
<Wrench className="w-5 h-5" />
|
||
浏览工具库
|
||
<ArrowRight className="w-4 h-4" />
|
||
</Link>
|
||
<Link href="/sandbox" className="inline-flex items-center justify-center gap-2 px-8 py-3 text-base font-medium text-foreground bg-card border border-border rounded-xl hover:bg-accent transition-all hover:-translate-y-0.5 active:scale-[0.98] shadow-sm">
|
||
<Bot className="w-5 h-5" />
|
||
沙盒体验
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Stats */}
|
||
<section className="py-12 md:py-16 border-y border-border">
|
||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||
<div className="grid grid-cols-2 md:grid-cols-4 gap-8">
|
||
{statItems.map((s) => (
|
||
<Link key={s.label} href={s.href} className="text-center group">
|
||
<div className="text-3xl md:text-4xl font-bold bg-gradient-to-b from-brand-600 to-brand-400 bg-clip-text text-transparent group-hover:scale-110 transition-transform">
|
||
{s.value}
|
||
</div>
|
||
<div className="mt-1.5 flex items-center justify-center gap-1.5 text-sm text-muted-foreground group-hover:text-brand-600 transition-colors">
|
||
<s.icon className="w-3.5 h-3.5" />
|
||
{s.label}
|
||
<ArrowRight className="w-3 h-3 opacity-0 group-hover:opacity-100 transition-opacity" />
|
||
</div>
|
||
</Link>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Featured Tools */}
|
||
{featuredTools.length > 0 && (
|
||
<section className="py-16 bg-muted/30">
|
||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||
<div className="flex items-center justify-between mb-10">
|
||
<div>
|
||
<h2 className="text-3xl font-bold">精选AI工具推荐</h2>
|
||
<p className="mt-2 text-muted-foreground">每个工具都经过实际测试,附带详细评测,助你快速决策</p>
|
||
</div>
|
||
<Link href="/tools" className="hidden sm:inline-flex items-center gap-1 text-brand-600 hover:text-brand-700 font-medium text-sm group">
|
||
查看全部 <ArrowRight className="w-4 h-4 group-hover:translate-x-0.5 transition-transform" />
|
||
</Link>
|
||
</div>
|
||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||
{featuredTools.map((tool: any) => {
|
||
const highlightMatch = tool.description?.match(/【推荐理由】\s*(.+?)(?:\n|$)/);
|
||
const baseDesc = tool.description?.split('\n\n')[0] || '';
|
||
return (
|
||
<Link key={tool.id} href={`/tools/${tool.slug}`} className="block group">
|
||
<Card className="p-4 hover:shadow-md hover:border-brand-200 dark:hover:border-brand-800 transition-all group h-full">
|
||
<div className="flex items-center gap-3">
|
||
<div className="w-10 h-10 bg-brand-100 dark:bg-brand-900/30 rounded-xl flex items-center justify-center shrink-0 group-hover:scale-110 transition-transform">
|
||
<Wrench className="w-5 h-5 text-brand-600 dark:text-brand-400" />
|
||
</div>
|
||
<div className="flex-1 min-w-0">
|
||
<h3 className="font-semibold group-hover:text-brand-600 transition-colors truncate">{tool.name}</h3>
|
||
<p className="text-xs text-muted-foreground line-clamp-1">{baseDesc}</p>
|
||
</div>
|
||
<ArrowRight className="w-4 h-4 text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity shrink-0" />
|
||
</div>
|
||
{highlightMatch && (
|
||
<div className="mt-2 px-2 py-1 bg-brand-50 dark:bg-brand-950/40 rounded-md">
|
||
<p className="text-xs text-brand-600 dark:text-brand-400 font-medium">💡 {highlightMatch[1].trim().slice(0, 35)}</p>
|
||
</div>
|
||
)}
|
||
{tool.tags && (
|
||
<div className="flex gap-1.5 mt-2 flex-wrap">
|
||
{tool.tags.split(',').slice(0, 3).map((tag: string) => (
|
||
<span key={tag} className="text-xs px-2 py-0.5 bg-muted rounded-full text-muted-foreground">{tag.trim()}</span>
|
||
))}
|
||
</div>
|
||
)}
|
||
</Card>
|
||
</Link>
|
||
);
|
||
})}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
)}
|
||
|
||
{/* Marketplace Skills Section */}
|
||
<section className="py-16">
|
||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||
<div className="flex items-center justify-between mb-10">
|
||
<div>
|
||
<h2 className="text-3xl font-bold">💼 AI 技能广场</h2>
|
||
<p className="mt-2 text-muted-foreground">即用即走的 AI 工作流技能,解决具体业务问题,¥9.9 起</p>
|
||
</div>
|
||
<Link href="/marketplace" className="hidden sm:inline-flex items-center gap-1 text-brand-600 hover:text-brand-700 font-medium text-sm group">
|
||
查看全部技能 <ArrowRight className="w-4 h-4 group-hover:translate-x-0.5 transition-transform" />
|
||
</Link>
|
||
</div>
|
||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||
<Link href="/marketplace" className="group">
|
||
<Card className="p-5 hover:shadow-md hover:border-brand-200 dark:hover:border-brand-800 transition-all h-full cursor-pointer">
|
||
<div className="flex items-center gap-3 mb-3">
|
||
<div className="w-10 h-10 rounded-xl bg-emerald-100 dark:bg-emerald-900/30 flex items-center justify-center shrink-0">
|
||
<span className="text-xl">⚡</span>
|
||
</div>
|
||
<div>
|
||
<h3 className="font-semibold text-foreground">标题大师</h3>
|
||
<p className="text-xs text-muted-foreground">AI 生成高点击标题</p>
|
||
</div>
|
||
</div>
|
||
<div className="flex items-center justify-between">
|
||
<Badge variant="secondary" className="bg-emerald-50 dark:bg-emerald-950/40 text-emerald-700 dark:text-emerald-400">¥9.9</Badge>
|
||
<span className="text-xs text-muted-foreground">已售1000+</span>
|
||
</div>
|
||
</Card>
|
||
</Link>
|
||
<Link href="/marketplace" className="group">
|
||
<Card className="p-5 hover:shadow-md hover:border-brand-200 dark:hover:border-brand-800 transition-all h-full cursor-pointer">
|
||
<div className="flex items-center gap-3 mb-3">
|
||
<div className="w-10 h-10 rounded-xl bg-blue-100 dark:bg-blue-900/30 flex items-center justify-center shrink-0">
|
||
<span className="text-xl">📋</span>
|
||
</div>
|
||
<div>
|
||
<h3 className="font-semibold text-foreground">提案智造</h3>
|
||
<p className="text-xs text-muted-foreground">5个问题生成专业商业提案</p>
|
||
</div>
|
||
</div>
|
||
<div className="flex items-center justify-between">
|
||
<Badge variant="secondary" className="bg-blue-50 dark:bg-blue-950/40 text-blue-700 dark:text-blue-400">¥19.9</Badge>
|
||
<span className="text-xs text-muted-foreground">6个技能可选</span>
|
||
</div>
|
||
</Card>
|
||
</Link>
|
||
<Link href="/marketplace" className="group">
|
||
<Card className="p-5 hover:shadow-md hover:border-brand-200 dark:hover:border-brand-800 transition-all h-full cursor-pointer">
|
||
<div className="flex items-center gap-3 mb-3">
|
||
<div className="w-10 h-10 rounded-xl bg-purple-100 dark:bg-purple-900/30 flex items-center justify-center shrink-0">
|
||
<span className="text-xl">⚖️</span>
|
||
</div>
|
||
<div>
|
||
<h3 className="font-semibold text-foreground">合同审查助手</h3>
|
||
<p className="text-xs text-muted-foreground">AI 标记风险条款并给出修改建议</p>
|
||
</div>
|
||
</div>
|
||
<div className="flex items-center justify-between">
|
||
<Badge variant="secondary" className="bg-purple-50 dark:bg-purple-950/40 text-purple-700 dark:text-purple-400">¥29.9</Badge>
|
||
<span className="text-xs text-muted-foreground">专业级</span>
|
||
</div>
|
||
</Card>
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* AI 能力导览 */}
|
||
<section className="py-20">
|
||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||
<div className="text-center mb-16">
|
||
<h2 className="text-3xl font-bold">AI 能力导览</h2>
|
||
<p className="mt-4 text-lg text-muted-foreground">探索 AI 能为你做什么,从对话写作到编程实战,找到适合你的场景</p>
|
||
</div>
|
||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||
{[
|
||
{ icon: MessageSquare, title: '对话写作', desc: '与 AI 进行自然对话,获取灵感、润色文案、翻译语言', href: '/sandbox', cta: '打开沙盒' },
|
||
{ icon: Code, title: '编程辅助', desc: '生成代码、调试错误、解释算法,你的随身编程搭档', href: '/sandbox', cta: '打开沙盒' },
|
||
{ icon: BarChart3, title: '数据分析', desc: '分析数据、生成图表、洞察趋势,让数据说话', href: '/sandbox', cta: '打开沙盒' },
|
||
{ icon: FileText, title: '提示词工程', desc: '学习编写高效提示词,掌握与 AI 沟通的最佳实践', href: '/prompts', cta: '浏览提示词库' },
|
||
{ icon: GraduationCap, title: '技能实战', desc: '在真实场景中练习 AI 技能,获得即时评分反馈', href: '/practices', cta: '开始练习' },
|
||
{ icon: Puzzle, title: '工作流技能', desc: '免费使用的 AI 工作流技能,解决具体业务问题', href: '/marketplace', cta: '前往技能广场' },
|
||
].map((item) => {
|
||
const Icon = item.icon;
|
||
return (
|
||
<Link key={item.title} href={item.href} className="group bg-card rounded-xl border border-border p-6 hover:border-brand-200 hover:shadow-sm transition-all">
|
||
<div className="w-10 h-10 rounded-lg bg-brand-50 dark:bg-brand-950 flex items-center justify-center mb-4 group-hover:bg-brand-100 dark:group-hover:bg-brand-900 transition-colors">
|
||
<Icon className="h-5 w-5 text-brand-600 dark:text-brand-400" />
|
||
</div>
|
||
<h3 className="text-lg font-semibold text-foreground mb-2">{item.title}</h3>
|
||
<p className="text-sm text-muted-foreground mb-4 leading-relaxed">{item.desc}</p>
|
||
<span className="text-sm font-medium text-brand-600 dark:text-brand-400 group-hover:underline">
|
||
{item.cta} →
|
||
</span>
|
||
</Link>
|
||
);
|
||
})}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* Popular Courses */}
|
||
<section className="py-20 bg-muted/30">
|
||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||
<div className="flex items-center justify-between mb-10">
|
||
<div>
|
||
<h2 className="text-3xl font-bold">{t.home.popularTopics}</h2>
|
||
<p className="mt-2 text-muted-foreground">{t.home.popularDesc}</p>
|
||
</div>
|
||
<Link href="/courses" className="hidden sm:inline-flex items-center gap-1 text-brand-600 hover:text-brand-700 font-medium text-sm group">
|
||
{t.common.viewAll} <ArrowRight className="w-4 h-4 group-hover:translate-x-0.5 transition-transform" />
|
||
</Link>
|
||
</div>
|
||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||
{courses.length > 0 ? courses.map((course: any) => (
|
||
<Link key={course.id} href={`/courses/${course.id}`} className="block group">
|
||
<div className="group bg-card rounded-xl border border-border overflow-hidden hover:shadow-xl transition-all hover:-translate-y-1">
|
||
<div className="h-2 bg-gradient-to-r from-brand-500 to-blue-500" />
|
||
<div className="p-6">
|
||
<div className="flex items-center justify-between mb-3">
|
||
<span className="text-xs font-medium text-brand-700 dark:text-brand-300 bg-brand-50 dark:bg-brand-900/30 px-2 py-1 rounded-full">{course.isFree ? t.courses.free : t.courses.paid}</span>
|
||
</div>
|
||
<h3 className="text-lg font-semibold mb-2 group-hover:text-brand-600 transition-colors">{course.title}</h3>
|
||
<p className="text-sm text-muted-foreground mb-4 line-clamp-2">{course.description || ''}</p>
|
||
</div>
|
||
</div>
|
||
</Link>
|
||
)) : (
|
||
<div className="col-span-3 text-center py-12 text-muted-foreground">{t.common.loading}</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{/* CTA */}
|
||
<section className="py-20 bg-gradient-to-r from-brand-600 to-brand-800 dark:from-brand-900 dark:to-brand-950 relative overflow-hidden">
|
||
<div className="absolute inset-0 bg-[url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHZpZXdCb3g9IjAgMCA0MCA0MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMjAgMjB2MTBoLTEwVjIwaDEwek0yMCAwaDEwdjEwSDIwVjB6IiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9IjAuMDMiLz48L3N2Zz4=')] opacity-50" />
|
||
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center relative">
|
||
<h2 className="text-3xl font-bold text-white mb-4">{t.home.ctaTitle}</h2>
|
||
<p className="text-brand-100/80 dark:text-brand-200/80 mb-8 text-lg">{t.home.ctaDesc}</p>
|
||
<Link href="/auth?tab=register" className="inline-flex items-center gap-2 px-8 py-3 text-base font-medium text-brand-600 bg-white rounded-xl hover:bg-brand-50 transition-all hover:-translate-y-0.5 active:scale-[0.98] shadow-xl">
|
||
{t.home.freeRegister}
|
||
<ArrowRight className="w-4 h-4" />
|
||
</Link>
|
||
</div>
|
||
</section>
|
||
</HomePageClient>
|
||
);
|
||
}
|