You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

163 lines
5.0 KiB

  1. /*
  2. Copyright (C) 2025 QuantumNous
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <https://www.gnu.org/licenses/>.
  13. For commercial licensing, please contact support@quantumnous.com
  14. */
  15. import React, { useContext, useEffect, useState } from 'react';
  16. import { useTranslation } from 'react-i18next';
  17. import { marked } from 'marked';
  18. import { StatusContext } from '../../context/Status';
  19. import { useActualTheme } from '../../context/Theme';
  20. import { API, showError } from '../../helpers';
  21. import NoticeModal from '../../components/layout/NoticeModal';
  22. import { useIsMobile } from '../../hooks/common/useIsMobile';
  23. // 首页组件
  24. import HeroSection from './components/HeroSection';
  25. import ValueSection from './components/ValueSection';
  26. import WorkflowSection from './components/WorkflowSection';
  27. import ToolsSection from './components/ToolsSection';
  28. import PartnersSection from './components/PartnersSection';
  29. import CTASection from './components/CTASection';
  30. import HomePageFooter from './components/HomePageFooter';
  31. // 模型广场
  32. import HomePricingFilters from './HomePricingFilters';
  33. const Home = () => {
  34. const { i18n } = useTranslation();
  35. const [statusState] = useContext(StatusContext);
  36. const actualTheme = useActualTheme();
  37. const [homePageContentLoaded, setHomePageContentLoaded] = useState(false);
  38. const [homePageContent, setHomePageContent] = useState('');
  39. const [noticeVisible, setNoticeVisible] = useState(false);
  40. const isMobile = useIsMobile();
  41. const displayHomePageContent = async () => {
  42. setHomePageContent(localStorage.getItem('home_page_content') || '');
  43. const res = await API.get('/api/home_page_content');
  44. const { success, message, data } = res.data;
  45. if (success) {
  46. let content = data;
  47. if (!data.startsWith('https://')) {
  48. content = marked.parse(data);
  49. }
  50. setHomePageContent(content);
  51. localStorage.setItem('home_page_content', content);
  52. // 如果内容是 URL,则发送主题模式
  53. if (data.startsWith('https://')) {
  54. const iframe = document.querySelector('iframe');
  55. if (iframe) {
  56. iframe.onload = () => {
  57. iframe.contentWindow.postMessage({ themeMode: actualTheme }, '*');
  58. iframe.contentWindow.postMessage({ lang: i18n.language }, '*');
  59. };
  60. }
  61. }
  62. } else {
  63. showError(message);
  64. setHomePageContent('加载首页内容失败...');
  65. }
  66. setHomePageContentLoaded(true);
  67. };
  68. useEffect(() => {
  69. const checkNoticeAndShow = async () => {
  70. const lastCloseDate = localStorage.getItem('notice_close_date');
  71. const today = new Date().toDateString();
  72. if (lastCloseDate !== today) {
  73. try {
  74. const res = await API.get('/api/notice');
  75. const { success, data } = res.data;
  76. if (success && data && data.trim() !== '') {
  77. setNoticeVisible(true);
  78. }
  79. } catch (error) {
  80. console.error('获取公告失败:', error);
  81. }
  82. }
  83. };
  84. checkNoticeAndShow();
  85. }, []);
  86. useEffect(() => {
  87. displayHomePageContent().then();
  88. }, []);
  89. // 如果有自定义首页内容,显示自定义内容
  90. if (homePageContentLoaded && homePageContent !== '') {
  91. return (
  92. <div className="w-full overflow-x-hidden">
  93. {homePageContent.startsWith('https://') ? (
  94. <iframe
  95. src={homePageContent}
  96. className="h-screen w-full border-none"
  97. />
  98. ) : (
  99. <div
  100. className="mt-[60px]"
  101. dangerouslySetInnerHTML={{ __html: homePageContent }}
  102. />
  103. )}
  104. </div>
  105. );
  106. }
  107. // 默认首页布局
  108. return (
  109. <div className="home-snap-container">
  110. <NoticeModal
  111. visible={noticeVisible}
  112. onClose={() => setNoticeVisible(false)}
  113. isMobile={isMobile}
  114. />
  115. {/* Hero Section */}
  116. <HeroSection />
  117. {/* 工具链 Section */}
  118. <ToolsSection />
  119. {/* 核心价值 Section */}
  120. <ValueSection />
  121. {/* 工作流 Section */}
  122. <WorkflowSection />
  123. {/* 生态伙伴 Section */}
  124. <PartnersSection />
  125. {/* 模型广场 Section */}
  126. <section className="home-snap-section home-snap-section-pricing bg-[var(--semi-color-bg-0)]">
  127. <div className="mx-auto w-full max-w-6xl px-5 py-16 md:px-6 lg:px-8">
  128. <HomePricingFilters t={(key) => key} />
  129. </div>
  130. </section>
  131. {/* CTA Section */}
  132. <CTASection />
  133. {/* Footer */}
  134. <HomePageFooter />
  135. </div>
  136. );
  137. };
  138. export default Home;