diff --git a/web/package.json b/web/package.json index d91cb630..9a6aa18b 100644 --- a/web/package.json +++ b/web/package.json @@ -6,6 +6,7 @@ "dependencies": { "@douyinfe/semi-icons": "^2.63.1", "@douyinfe/semi-ui": "^2.69.1", + "@lobehub/icons": "^2.0.0", "@visactor/react-vchart": "~1.8.8", "@visactor/vchart": "~1.8.8", "@visactor/vchart-semi-theme": "~1.8.8", diff --git a/web/src/components/Footer.js b/web/src/components/Footer.js index de8ab977..086b48c3 100644 --- a/web/src/components/Footer.js +++ b/web/src/components/Footer.js @@ -1,10 +1,16 @@ -import React, { useEffect, useState, useMemo } from 'react'; +import React, { useEffect, useState, useMemo, useContext } from 'react'; import { useTranslation } from 'react-i18next'; -import { getFooterHTML } from '../helpers'; +import { Typography } from '@douyinfe/semi-ui'; +import { getFooterHTML, getLogo, getSystemName } from '../helpers'; +import { StatusContext } from '../context/Status'; const FooterBar = () => { const { t } = useTranslation(); const [footer, setFooter] = useState(getFooterHTML()); + const systemName = getSystemName(); + const logo = getLogo(); + const [statusState] = useContext(StatusContext); + const isDemoSiteMode = statusState?.status?.demo_site_enabled || false; const loadFooter = () => { let footer_html = localStorage.getItem('footer_html'); @@ -13,48 +19,93 @@ const FooterBar = () => { } }; - const defaultFooter = useMemo(() => ( -
- - New API {import.meta.env.VITE_REACT_APP_VERSION}{' '} - - {t('由')}{' '} - - Calcium-Ion - {' '} - {t('开发,基于')}{' '} - - One API - -
- ), [t]); + const currentYear = new Date().getFullYear(); + + const customFooter = useMemo(() => ( + + ), [logo, systemName, t, currentYear, isDemoSiteMode]); useEffect(() => { loadFooter(); }, []); return ( -
+
{footer ? (
) : ( - defaultFooter + customFooter )}
); diff --git a/web/src/components/HeaderBar.js b/web/src/components/HeaderBar.js index 1e45e7e4..f8d2db4f 100644 --- a/web/src/components/HeaderBar.js +++ b/web/src/components/HeaderBar.js @@ -356,7 +356,7 @@ const HeaderBar = () => { {isLoading ? ( ) : ( - logo + logo )}
@@ -374,6 +374,7 @@ const HeaderBar = () => { color={isSelfUseMode ? 'purple' : 'blue'} className="text-xs px-1.5 py-0.5 rounded whitespace-nowrap shadow-sm" size="small" + shape='circle' > {isSelfUseMode ? t('自用模式') : t('演示站点')} @@ -387,6 +388,7 @@ const HeaderBar = () => { color={isSelfUseMode ? 'purple' : 'blue'} className="ml-2 text-xs px-1 py-0.5 rounded whitespace-nowrap shadow-sm" size="small" + shape='circle' > {isSelfUseMode ? t('自用模式') : t('演示站点')} diff --git a/web/src/components/Loading.js b/web/src/components/Loading.js index 14242e44..5432b837 100644 --- a/web/src/components/Loading.js +++ b/web/src/components/Loading.js @@ -1,11 +1,20 @@ import React from 'react'; import { Spin } from '@douyinfe/semi-ui'; -const Loading = ({ prompt: name = 'page' }) => { +const Loading = ({ prompt: name = '', size = 'large' }) => { return ( - - 加载{name}中... - +
+
+ + + {name ? `加载${name}中...` : '加载中...'} + +
+
); }; diff --git a/web/src/i18n/locales/en.json b/web/src/i18n/locales/en.json index 6d1d6ae1..445cd07a 100644 --- a/web/src/i18n/locales/en.json +++ b/web/src/i18n/locales/en.json @@ -1373,5 +1373,19 @@ "不需要设置模型价格,系统将弱化用量计算,您可专注于使用模型。": "No need to set the model price, the system will weaken the usage calculation, you can focus on using the model.", "适用于展示系统功能的场景。": "Suitable for scenarios where the system functions are displayed.", "可在初始化后修改": "Can be modified after initialization", - "初始化系统": "Initialize system" + "初始化系统": "Initialize system", + "支持众多的大模型供应商": "Supporting various LLM providers", + "新一代大模型网关与AI资产管理系统,一键接入主流大模型,轻松管理您的AI资产": "Next-generation LLM gateway and AI asset management system, one-click integration with mainstream models, easily manage your AI assets", + "开始使用": "Get Started", + "关于我们": "About Us", + "关于项目": "About Project", + "联系我们": "Contact Us", + "功能特性": "Features", + "快速开始": "Quick Start", + "安装指南": "Installation Guide", + "API 文档": "API Documentation", + "相关项目": "Related Projects", + "基于New API的项目": "Projects Based on New API", + "版权所有": "All rights reserved", + "设计与开发由": "Designed & Developed with love by" } \ No newline at end of file diff --git a/web/src/images/example.png b/web/src/images/example.png new file mode 100644 index 00000000..257a3dd9 Binary files /dev/null and b/web/src/images/example.png differ diff --git a/web/src/pages/Home/index.js b/web/src/pages/Home/index.js index 599c7930..7c151467 100644 --- a/web/src/pages/Home/index.js +++ b/web/src/pages/Home/index.js @@ -1,17 +1,23 @@ import React, { useContext, useEffect, useState } from 'react'; -import { Card, Col, Row } from '@douyinfe/semi-ui'; -import { API, showError, showNotice, timestamp2string } from '../../helpers'; +import { Button, Typography, Tag } from '@douyinfe/semi-ui'; +import { API, showError, showNotice } from '../../helpers'; import { StatusContext } from '../../context/Status'; import { marked } from 'marked'; -import { StyleContext } from '../../context/Style/index.js'; import { useTranslation } from 'react-i18next'; +import { IconGithubLogo } from '@douyinfe/semi-icons'; +import exampleImage from '../../images/example.png'; +import { Link } from 'react-router-dom'; +import { Moonshot, OpenAI, XAI, Zhipu, Volcengine, Cohere, Claude, Gemini, Suno, Minimax, Wenxin, Spark, Qingyan, DeepSeek, Qwen, Midjourney, Grok, AzureAI, Hunyuan, Xinference } from '@lobehub/icons'; + +const { Text } = Typography; const Home = () => { const { t, i18n } = useTranslation(); const [statusState] = useContext(StatusContext); const [homePageContentLoaded, setHomePageContentLoaded] = useState(false); const [homePageContent, setHomePageContent] = useState(''); - const [styleState, styleDispatch] = useContext(StyleContext); + + const isDemoSiteMode = statusState?.status?.demo_site_enabled || false; const displayNotice = async () => { const res = await API.get('/api/notice'); @@ -45,8 +51,6 @@ const Home = () => { const iframe = document.querySelector('iframe'); if (iframe) { const theme = localStorage.getItem('theme-mode') || 'light'; - // 测试是否正确传递theme-mode给iframe - // console.log('Sending theme-mode to iframe:', theme); iframe.onload = () => { iframe.contentWindow.postMessage({ themeMode: theme }, '*'); iframe.contentWindow.postMessage({ lang: i18n.language }, '*'); @@ -60,153 +64,161 @@ const Home = () => { setHomePageContentLoaded(true); }; - const getStartTimeString = () => { - const timestamp = statusState?.status?.start_time; - return statusState.status ? timestamp2string(timestamp) : ''; - }; - useEffect(() => { displayNotice().then(); displayHomePageContent().then(); }, []); return ( - <> +
{homePageContentLoaded && homePageContent === '' ? ( - <> - - - - + {/* Banner 部分 */} +
+
+ {/* 左侧内容区 */} +
+
+

+ {statusState?.status?.system_name} +

+ {statusState?.status?.version && ( + + {statusState.status.version} + + )} +
+

+ {t('新一代大模型网关与AI资产管理系统,一键接入主流大模型,轻松管理您的AI资产')} +

+ + {/* 操作按钮 */} +
+ + + + {isDemoSiteMode && ( + + )} +
+ + {/* 框架兼容性图标 */} +
+
+ + {t('支持众多的大模型供应商')} + +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ 30+ +
+
+
+
+ + {/* 右侧图片区域 - 在小屏幕上隐藏或调整位置 */} +
+
+
+
+
+ + application demo +
+
+
+
) : ( - <> +
{homePageContent.startsWith('https://') ? (