P8 平台轻量化改造 + SSG修复 + 编程导师 + 文档完善
- Prisma: Tool 模型加 affiliateLink;免费用户沙盒 10→5 次/日 - 后端: Tools API + /admin/tools CRUD 5 端点;Practices 完整模块 - 导航: 主菜单隐藏企业版/社区(URL 可访问) - 首页: 重定位为 AI 工具指南;新增精选工具区块;Feature 重写 - 工具页: affiliateLink 绿色推荐 Badge - SSG 修复: config.ts 构建时直连 localhost:4000,页面 108→127 - 沙盒: 新增编程导师场景(苏格拉底教学法) - 练习系统: Practices 多场景练习(含结构化评分) - 技能广场: 6 个付费 Skill(标题大师/回款助手等) - 管理后台: Models/Posts/Practices CRUD 页面 - 文档: README + progress.md 全面更新;AGENTS.md 同步定位 - 清理: .env.example 移除;tsbuildinfo gitignore
This commit is contained in:
+49
-24
@@ -3,25 +3,34 @@
|
||||
import Link from 'next/link';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { HomePageClient } from './home-client';
|
||||
import { ArrowRight, Sparkles, BookOpen, Bot, Compass, Zap } from 'lucide-react';
|
||||
import { ArrowRight, Sparkles, BookOpen, Bot, Compass, Zap, Wrench } from 'lucide-react';
|
||||
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<{ courses: number; prompts: number; tools: number; users: number } | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
fetch(`${API_BASE}/courses?pageSize=3`)
|
||||
.then(r => r.json()).then(data => setCourses(data.items || []))
|
||||
.catch(() => {});
|
||||
Promise.all([
|
||||
fetch(`${API_BASE}/courses?pageSize=3`).then(r => r.json()),
|
||||
fetch(`${API_BASE}/public/stats`).then(r => r.json()),
|
||||
fetch(`${API_BASE}/tools?isFeatured=true&pageSize=6`).then(r => r.json()),
|
||||
]).then(([courseData, statsData, toolsData]) => {
|
||||
setCourses(courseData.items || []);
|
||||
setFeaturedTools(toolsData.items || []);
|
||||
setStats(statsData);
|
||||
}).catch(() => {});
|
||||
}, []);
|
||||
|
||||
const stats = [
|
||||
{ value: '50+', label: t.home.statTopics },
|
||||
{ value: '200+', label: t.home.statPrompts },
|
||||
{ value: '30+', label: t.home.statTools },
|
||||
{ value: '10,000+', label: t.home.statExplorers },
|
||||
const statItems = [
|
||||
{ value: stats ? `${stats.courses}+` : '50+', label: t.home.statTopics },
|
||||
{ value: stats ? `${stats.prompts}+` : '200+', label: t.home.statPrompts },
|
||||
{ value: stats ? `${stats.tools}+` : '30+', label: t.home.statTools },
|
||||
{ value: stats ? `${stats.users / 1000 > 1 ? Math.round(stats.users / 100) * 100 + '+' : stats.users + '+'}` : '10,000+', label: t.home.statExplorers },
|
||||
];
|
||||
const features = [
|
||||
{ icon: Compass, title: t.home.featureGuide, desc: t.home.featureGuideDesc },
|
||||
@@ -71,7 +80,7 @@ export default function HomePage() {
|
||||
<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">
|
||||
{stats.map((s) => (
|
||||
{statItems.map((s) => (
|
||||
<div key={s.label} 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}
|
||||
@@ -83,6 +92,35 @@ export default function HomePage() {
|
||||
</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="text-center mb-10">
|
||||
<h2 className="text-3xl font-bold">{t.home.featuredToolsTitle}</h2>
|
||||
<p className="mt-2 text-muted-foreground">{t.home.featuredToolsDesc}</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{featuredTools.map((tool: any) => (
|
||||
<a key={tool.id} href={tool.url} target="_blank" rel="noopener noreferrer" className="block group">
|
||||
<Card className="p-4 hover:shadow-md hover:border-brand-200 dark:hover:border-brand-800 transition-all group">
|
||||
<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">{tool.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Features */}
|
||||
<section className="py-20">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
@@ -131,20 +169,7 @@ export default function HomePage() {
|
||||
</div>
|
||||
</Link>
|
||||
)) : (
|
||||
<>
|
||||
{[{ title: 'AI 通识:零基础入门', tag: t.courses.free }, { title: '提示词工程从入门到精通', tag: '热门' }, { title: '用 AI 提升 10 倍办公效率', tag: '推荐' }].map((course) => (
|
||||
<div key={course.title} 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.tag}</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">探索 AI 世界</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
<div className="col-span-3 text-center py-12 text-muted-foreground">{t.common.loading}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user