From 477226ac15456865b73e380ba4c3e525c2561451 Mon Sep 17 00:00:00 2001 From: yuzhiran-dev Date: Fri, 22 May 2026 17:08:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=89=A9=E4=BD=99=E9=A1=B5=E9=9D=A2=20?= =?UTF-8?q?useT()=20=E6=94=B9=E9=80=A0=20+=20=E9=A6=96=E9=A1=B5=E8=AF=BE?= =?UTF-8?q?=E7=A8=8B=E5=8A=A8=E6=80=81=E5=8A=A0=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 搜索/发现/工具/My 页面全部使用 useT(),支持中英切换 - 搜索页 Badge variant 修正 - 首页热门专题改为从 API 动态获取(无数据时用静态兜底) - 新增 discover 翻译键 viewCount/likeCount/postStats - 首页/仪表盘/社区 等 JSX 优化 --- frontend/src/app/discover/page.tsx | 56 +++++++++++------------------- frontend/src/app/my/page.tsx | 46 +++++++++--------------- frontend/src/app/page.tsx | 54 +++++++++++++++++++--------- frontend/src/app/search/page.tsx | 41 ++++++++-------------- frontend/src/app/tools/page.tsx | 23 +++++------- frontend/src/i18n/locales/en.ts | 2 +- frontend/src/i18n/locales/zh.ts | 2 +- 7 files changed, 97 insertions(+), 127 deletions(-) diff --git a/frontend/src/app/discover/page.tsx b/frontend/src/app/discover/page.tsx index 23b101f..768577d 100644 --- a/frontend/src/app/discover/page.tsx +++ b/frontend/src/app/discover/page.tsx @@ -4,48 +4,34 @@ import { useEffect, useState } from 'react'; import Link from 'next/link'; import { apiFetch } from '@/lib/auth'; import { Skeleton } from '@/components/ui/skeleton'; +import { useT } from '@/i18n'; -interface HotItem { - id: number; - title: string; - viewCount: number; - likeCount: number; - _type: 'course' | 'prompt' | 'post'; -} +interface HotItem { id: number; title: string; viewCount: number; likeCount: number; _type: 'course' | 'prompt' | 'post' } export default function DiscoverPage() { + const t = useT(); const [hotCourses, setHotCourses] = useState([]); const [hotPrompts, setHotPrompts] = useState([]); const [hotPosts, setHotPosts] = useState([]); const [loading, setLoading] = useState(true); - useEffect(() => { - loadData(); - }, []); + useEffect(() => { loadData(); }, []); async function loadData() { try { const [coursesRes, promptsRes, postsRes] = await Promise.all([ - apiFetch('/courses?pageSize=5'), - apiFetch('/prompts?pageSize=5'), - apiFetch('/community/posts?pageSize=5'), + apiFetch('/courses?pageSize=5'), apiFetch('/prompts?pageSize=5'), apiFetch('/community/posts?pageSize=5'), ]); - - const coursesData = await coursesRes.json(); - const promptsData = await promptsRes.json(); - const postsData = await postsRes.json(); - - setHotCourses((coursesData.items || []).map((c: any) => ({ ...c, _type: 'course' as const }))); - setHotPrompts((promptsData.items || []).map((p: any) => ({ ...p, _type: 'prompt' as const }))); - setHotPosts((postsData.items || []).map((p: any) => ({ ...p, _type: 'post' as const }))); + setHotCourses((await coursesRes.json()).items?.map((c: any) => ({ ...c, _type: 'course' as const })) || []); + setHotPrompts((await promptsRes.json()).items?.map((p: any) => ({ ...p, _type: 'prompt' as const })) || []); + setHotPosts((await postsRes.json()).items?.map((p: any) => ({ ...p, _type: 'post' as const })) || []); } catch (e) { console.error(e) } setLoading(false); } if (loading) return (
- - + {[1,2,3].map(i => )}
); @@ -53,15 +39,13 @@ export default function DiscoverPage() { return (
-

发现

-

探索热门内容和精选推荐

+

{t.discover.desc}

-
-

🔥 热门课程

- 查看全部 +

🔥 {t.discover.hotCourses}

+ {t.common.viewAll}
{hotCourses.map((item, index) => ( @@ -70,7 +54,7 @@ export default function DiscoverPage() { {index + 1}

{item.title}

-

👁 {item.viewCount} 浏览

+

👁 {t.discover.viewCount?.replace('{n}', String(item.viewCount)) || `${item.viewCount} 浏览`}

))} @@ -79,17 +63,17 @@ export default function DiscoverPage() {
-

✨ 热门提示词

- 查看全部 +

✨ {t.discover.hotPrompts}

+ {t.common.viewAll}
{hotPrompts.map((item, index) => ( - {index + 1}

{item.title}

-

❤️ {item.likeCount} 点赞

+

❤️ {t.discover.likeCount?.replace('{n}', String(item.likeCount)) || `${item.likeCount} 点赞`}

))} @@ -98,8 +82,8 @@ export default function DiscoverPage() {
-

💬 热门讨论

- 查看全部 +

💬 {t.discover.hotPosts}

+ {t.common.viewAll}
{hotPosts.map((item, index) => ( @@ -108,7 +92,7 @@ export default function DiscoverPage() { {index + 1}

{item.title}

-

❤️ {item.likeCount} 点赞 · 👁 {item.viewCount} 浏览

+

{t.discover.postStats?.replace('{likes}', String(item.likeCount)).replace('{views}', String(item.viewCount)) || `❤️ ${item.likeCount} · 👁 ${item.viewCount}`}

))} diff --git a/frontend/src/app/my/page.tsx b/frontend/src/app/my/page.tsx index df64415..07e945e 100644 --- a/frontend/src/app/my/page.tsx +++ b/frontend/src/app/my/page.tsx @@ -1,60 +1,46 @@ 'use client'; -import { useEffect, useState } from 'react'; import Link from 'next/link'; -import { apiFetch } from '../../lib/auth'; - -interface LearningItem { - courseId: number; - courseTitle: string; - progress: number; - completedLessons: number; - totalLessons: number; -} +import { useT } from '@/i18n'; export default function MyPage() { + const t = useT(); return (
-

我的

-

管理你的个人信息和收藏

+

{t.nav.my}

+

{t.my.desc}

-
📚
-

学习进度

-

查看你的课程学习进度

+

{t.my.learningProgress}

+

{t.my.learningProgressDesc}

-
❤️
-

我的收藏

-

提示词、课程等收藏内容

+

{t.my.favorites}

+

{t.my.favoritesDesc}

-
👑
-

会员中心

-

管理会员订阅和权益

+

{t.my.memberCenter}

+

{t.my.memberDesc}

-
⚙️
-

设置

-

账号设置和安全偏好

+

{t.my.settings}

+

{t.my.settingsDesc}

-
📊
-

学情分析

-

基于对话的知识掌握度分析

+

{t.learning.analytics}

+

{t.my.analyticsDesc}

-
🗺️
-

学习路径

-

分阶段系统掌握 AI 技能

+

{t.learning.path}

+

{t.my.pathDesc}

diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index ee3e700..fce2103 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -1,12 +1,22 @@ 'use client'; 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 { useT } from '@/i18n'; +import { API_BASE } from '@/lib/config'; export default function HomePage() { const t = useT(); + const [courses, setCourses] = useState([]); + + useEffect(() => { + fetch(`${API_BASE}/courses?pageSize=3`) + .then(r => r.json()).then(data => setCourses(data.items || [])) + .catch(() => {}); + }, []); + const stats = [ { value: '50+', label: t.home.statTopics }, { value: '200+', label: t.home.statPrompts }, @@ -107,25 +117,35 @@ export default function HomePage() {
- {[ - { title: 'AI 通识:零基础入门', students: '1,280', tag: t.courses.free, gradient: 'from-brand-500 to-blue-500', desc: '面向零基础用户,带你了解 AI 的基本概念、发展历程和实际应用。' }, - { title: '提示词工程从入门到精通', students: '860', tag: '热门', gradient: 'from-violet-500 to-purple-500', desc: '系统学习提示词编写技巧,掌握与 AI 高效沟通的方法。' }, - { title: '用 AI 提升 10 倍办公效率', students: '2,150', tag: '推荐', gradient: 'from-amber-500 to-orange-500', desc: '学习使用 AI 工具处理文档、数据分析、演示制作等日常工作。' }, - ].map((course) => ( -
-
-
-
- {course.tag} -
-

{course.title}

-

{course.desc}

-
- {t.home.moduleCount.replace('{n}', course.students)} + {courses.length > 0 ? courses.map((course: any) => ( + +
+
+
+
+ {course.isFree ? t.courses.free : t.courses.paid} +
+

{course.title}

+

{course.description || ''}

-
- ))} + + )) : ( + <> + {[{ title: 'AI 通识:零基础入门', tag: t.courses.free }, { title: '提示词工程从入门到精通', tag: '热门' }, { title: '用 AI 提升 10 倍办公效率', tag: '推荐' }].map((course) => ( +
+
+
+
+ {course.tag} +
+

{course.title}

+

探索 AI 世界

+
+
+ ))} + + )}
diff --git a/frontend/src/app/search/page.tsx b/frontend/src/app/search/page.tsx index c7d8dc7..b8865b8 100644 --- a/frontend/src/app/search/page.tsx +++ b/frontend/src/app/search/page.tsx @@ -9,12 +9,9 @@ import { Badge } from '@/components/ui/badge'; import { Skeleton } from '@/components/ui/skeleton'; import { SearchIcon, FileText, BookOpen, Wrench, MessageSquare } from 'lucide-react'; import { API_BASE } from '@/lib/config'; +import { useT } from '@/i18n'; -interface SearchResult { - id: number; _type: 'course' | 'prompt' | 'tool' | 'content'; - title?: string; name?: string; description?: string; summary?: string; - cover?: string; icon?: string; url?: string; model?: string; isFree?: boolean; publishedAt?: string; -} +interface SearchResult { id: number; _type: 'course' | 'prompt' | 'tool' | 'content'; title?: string; name?: string; description?: string; summary?: string; cover?: string; icon?: string; url?: string; model?: string; isFree?: boolean; publishedAt?: string } export default function SearchPage() { return ( @@ -25,6 +22,7 @@ export default function SearchPage() { } function SearchContent() { + const t = useT(); const searchParams = useSearchParams(); const q = searchParams.get('q') || ''; const type = searchParams.get('type') || 'all'; @@ -42,19 +40,18 @@ function SearchContent() { }, [q, type]); const groups = { course: results.filter(r => r._type === 'course'), prompt: results.filter(r => r._type === 'prompt'), tool: results.filter(r => r._type === 'tool'), content: results.filter(r => r._type === 'content') }; - const groupLabels: Record = { course: '专题', prompt: '提示词', tool: 'AI 工具', content: '文章' }; + const groupLabels: Record = { course: t.search.groupCourse, prompt: t.search.groupPrompt, tool: t.search.groupTool, content: t.search.groupContent }; const groupIcons: Record = { course: BookOpen, prompt: MessageSquare, tool: Wrench, content: FileText }; const groupLinks: Record = { course: '/courses/', prompt: '/prompts', tool: '/tools', content: '/contents/' }; return (
-

搜索结果

+

{t.search.title}

{ e.preventDefault(); window.location.href = `/search?q=${encodeURIComponent(input)}`; }}>
- setInput(e.target.value)} - placeholder="搜索专题、提示词、工具、文章..." className="pl-10 h-12 text-base" /> + setInput(e.target.value)} placeholder={t.search.placeholder} className="pl-10 h-12 text-base" />
@@ -62,25 +59,23 @@ function SearchContent() { {!q && (
-

输入关键词搜索

+

{t.search.emptyHint}

)} {q && loading && ( -
- {[1,2,3].map(i => )} -
+
{[1,2,3].map(i => )}
)} {q && !loading && total === 0 && (
-

未找到与 "{q}" 相关的结果

+

{t.search.noResults.replace('{q}', q)}

)} {q && !loading && total > 0 && (
-

找到 {total} 个结果

+

{t.search.resultsCount.replace('{n}', String(total))}

{Object.entries(groups).map(([key, items]) => { if (items.length === 0) return null; @@ -90,25 +85,17 @@ function SearchContent() {
{groupLabels[key]} - {items.length} 个结果 + {items.length} {t.search.resultsCount.replace('{n}', '')}
{items.map((item) => ( - +

{item.title || item.name}

{item.description || item.summary}

- {key === 'course' && ( - - {item.isFree ? '免费' : '付费'} - - )} - {key === 'prompt' && item.model && ( - 模型: {item.model} - )} + {key === 'course' && {item.isFree ? t.courses.free : t.courses.paid}} + {key === 'prompt' && item.model && 模型: {item.model}}
diff --git a/frontend/src/app/tools/page.tsx b/frontend/src/app/tools/page.tsx index 747a820..c67666a 100644 --- a/frontend/src/app/tools/page.tsx +++ b/frontend/src/app/tools/page.tsx @@ -6,26 +6,21 @@ import { Badge } from '@/components/ui/badge'; import { Skeleton } from '@/components/ui/skeleton'; import { Wrench, ExternalLink, Star } from 'lucide-react'; import { API_BASE } from '@/lib/config'; +import { useT } from '@/i18n'; -interface Tool { - id: number; name: string; description: string; url: string; - icon: string | null; isFeatured: boolean; tags: string | null; -} +interface Tool { id: number; name: string; description: string; url: string; icon: string | null; isFeatured: boolean; tags: string | null } function ToolSkeleton() { return ( -
- - -
- - +
+
); } export default function ToolsPage() { + const t = useT(); const [tools, setTools] = useState([]); const [loading, setLoading] = useState(true); @@ -38,14 +33,12 @@ export default function ToolsPage() { return (
-

AI 工具库

-

收录优质 AI 工具,助力工作效率提升

+

{t.tools.title}

+

{t.tools.desc}

{loading ? ( -
- {[1,2,3,4,5,6].map(i => )} -
+
{[1,2,3,4,5,6].map(i => )}
) : (
{tools.map((tool) => ( diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts index 95aed02..8778a00 100644 --- a/frontend/src/i18n/locales/en.ts +++ b/frontend/src/i18n/locales/en.ts @@ -15,7 +15,7 @@ const en: Translations = { courses: { title: 'Courses', desc: 'Explore AI systematically from beginner to expert', empty: 'No courses available', free: 'Free', paid: 'Paid', moduleCount: '{n} modules' }, search: { title: 'Search Results', placeholder: 'Search courses, prompts, tools, articles...', emptyHint: 'Enter keywords to search', noResults: 'No results found for "{q}"', resultsCount: '{n} results found', groupCourse: 'Courses', groupPrompt: 'Prompts', groupTool: 'AI Tools', groupContent: 'Articles' }, tools: { title: 'AI Tools', desc: 'Curated AI tools to boost your productivity' }, - discover: { desc: 'Explore trending content and curated picks', hotCourses: 'Hot Courses', hotPrompts: 'Trending Prompts', hotPosts: 'Popular Discussions' }, + discover: { desc: 'Explore trending content and curated picks', hotCourses: 'Hot Courses', hotPrompts: 'Trending Prompts', hotPosts: 'Popular Discussions', viewCount: '{n} views', likeCount: '{n} likes', postStats: '❤️ {likes} · 👁 {views}' }, footer: { tagline: 'Empowering Everyone to Master AI', explore: 'Explore', about: 'About', aboutUs: 'About Us', privacy: 'Privacy Policy', terms: 'Terms of Service', aiAgreement: 'AI Service Agreement', contact: 'Contact', copyright: '© {year} Yuzhiran Technology Center. All rights reserved.', models: 'Models', aiTools: 'AI Tools', articles: 'Articles', skills: 'Skills' }, models: { title: 'AI Model Encyclopedia', desc: 'Compare mainstream LLMs to find the best fit', tableName: 'Model', tableProvider: 'Provider', tableCapabilities: 'Capabilities', tableContext: 'Context', tableMaxOutput: 'Max Output', tablePricing: 'Pricing', free: 'Free', recommended: 'Recommended', pricingFree: 'Free', pricingMixed: 'Free/Paid', pricingPaid: 'Paid' }, error: { title: 'Something went wrong', desc: 'Page failed to load. Please try again.', reload: 'Reload' }, diff --git a/frontend/src/i18n/locales/zh.ts b/frontend/src/i18n/locales/zh.ts index 0954176..5756662 100644 --- a/frontend/src/i18n/locales/zh.ts +++ b/frontend/src/i18n/locales/zh.ts @@ -13,7 +13,7 @@ const zh = { courses: { title: '专题', desc: '系统化探索 AI,从入门到精通', empty: '暂无专题内容', free: '免费', paid: '付费', moduleCount: '{n} 模块' }, search: { title: '搜索结果', placeholder: '搜索专题、提示词、工具、文章...', emptyHint: '输入关键词搜索', noResults: '未找到与 "{q}" 相关的结果', resultsCount: '找到 {n} 个结果', groupCourse: '专题', groupPrompt: '提示词', groupTool: 'AI 工具', groupContent: '文章' }, tools: { title: 'AI 工具库', desc: '收录优质 AI 工具,助力工作效率提升' }, - discover: { desc: '探索热门内容和精选推荐', hotCourses: '热门课程', hotPrompts: '热门提示词', hotPosts: '热门讨论' }, + discover: { desc: '探索热门内容和精选推荐', hotCourses: '热门课程', hotPrompts: '热门提示词', hotPosts: '热门讨论', viewCount: '{n} 浏览', likeCount: '{n} 点赞', postStats: '❤️ {likes} 点赞 · 👁 {views} 浏览' }, footer: { tagline: '让每个人都能用好 AI', explore: '探索', about: '关于', aboutUs: '关于我们', privacy: '隐私政策', terms: '服务协议', aiAgreement: 'AI 服务协议', contact: '联系方式', copyright: '© {year} 北京宇之然科技中心 版权所有', models: '模型百科', aiTools: 'AI 工具', articles: '文章', skills: '技能' }, models: { title: 'AI 模型百科', desc: '收录主流大语言模型,全面对比各项参数', tableName: '模型名称', tableProvider: '提供商', tableCapabilities: '能力', tableContext: '上下文', tableMaxOutput: '最大输出', tablePricing: '价格', free: '免费', recommended: '推荐', pricingFree: '免费', pricingMixed: '免费/付费', pricingPaid: '付费' }, error: { title: '出错了', desc: '页面加载失败,请稍后重试', reload: '重新加载' },