index.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import React, { useContext, useEffect, useState } from 'react';
  2. import { Card, Col, Row } from '@douyinfe/semi-ui';
  3. import { API, showError, showNotice, timestamp2string } from '../../helpers';
  4. import { StatusContext } from '../../context/Status';
  5. import { marked } from 'marked';
  6. import { StyleContext } from '../../context/Style/index.js';
  7. import { useTranslation } from 'react-i18next';
  8. const Home = () => {
  9. const { t, i18n } = useTranslation();
  10. const [statusState] = useContext(StatusContext);
  11. const [homePageContentLoaded, setHomePageContentLoaded] = useState(false);
  12. const [homePageContent, setHomePageContent] = useState('');
  13. const [styleState, styleDispatch] = useContext(StyleContext);
  14. const displayNotice = async () => {
  15. const res = await API.get('/api/notice');
  16. const { success, message, data } = res.data;
  17. if (success) {
  18. let oldNotice = localStorage.getItem('notice');
  19. if (data !== oldNotice && data !== '') {
  20. const htmlNotice = marked(data);
  21. showNotice(htmlNotice, true);
  22. localStorage.setItem('notice', data);
  23. }
  24. } else {
  25. showError(message);
  26. }
  27. };
  28. const displayHomePageContent = async () => {
  29. setHomePageContent(localStorage.getItem('home_page_content') || '');
  30. const res = await API.get('/api/home_page_content');
  31. const { success, message, data } = res.data;
  32. if (success) {
  33. let content = data;
  34. if (!data.startsWith('https://')) {
  35. content = marked.parse(data);
  36. }
  37. setHomePageContent(content);
  38. localStorage.setItem('home_page_content', content);
  39. // 如果内容是 URL,则发送主题模式
  40. if (data.startsWith('https://')) {
  41. const iframe = document.querySelector('iframe');
  42. if (iframe) {
  43. const theme = localStorage.getItem('theme-mode') || 'light';
  44. // 测试是否正确传递theme-mode给iframe
  45. // console.log('Sending theme-mode to iframe:', theme);
  46. iframe.onload = () => {
  47. iframe.contentWindow.postMessage({ themeMode: theme }, '*');
  48. iframe.contentWindow.postMessage({ lang: i18n.language }, '*');
  49. };
  50. }
  51. }
  52. } else {
  53. showError(message);
  54. setHomePageContent('加载首页内容失败...');
  55. }
  56. setHomePageContentLoaded(true);
  57. };
  58. const getStartTimeString = () => {
  59. const timestamp = statusState?.status?.start_time;
  60. return statusState.status ? timestamp2string(timestamp) : '';
  61. };
  62. useEffect(() => {
  63. displayNotice().then();
  64. displayHomePageContent().then();
  65. }, []);
  66. return (
  67. <>
  68. {homePageContentLoaded && homePageContent === '' ? (
  69. <>
  70. <Card
  71. bordered={false}
  72. headerLine={false}
  73. title={t('系统状况')}
  74. bodyStyle={{ padding: '10px 20px' }}
  75. >
  76. <Row gutter={16}>
  77. <Col span={12}>
  78. <Card
  79. title={t('系统信息')}
  80. headerExtraContent={
  81. <span
  82. style={{
  83. fontSize: '12px',
  84. color: 'var(--semi-color-text-1)',
  85. }}
  86. >
  87. {t('系统信息总览')}
  88. </span>
  89. }
  90. >
  91. <p>
  92. {t('名称')}:{statusState?.status?.system_name}
  93. </p>
  94. <p>
  95. {t('版本')}:
  96. {statusState?.status?.version
  97. ? statusState?.status?.version
  98. : 'unknown'}
  99. </p>
  100. <p>
  101. {t('源码')}:
  102. <a
  103. href='https://github.com/Calcium-Ion/new-api'
  104. target='_blank'
  105. rel='noreferrer'
  106. >
  107. https://github.com/Calcium-Ion/new-api
  108. </a>
  109. </p>
  110. <p>
  111. {t('协议')}:
  112. <a
  113. href='https://www.apache.org/licenses/LICENSE-2.0'
  114. target='_blank'
  115. rel='noreferrer'
  116. >
  117. Apache-2.0 License
  118. </a>
  119. </p>
  120. <p>
  121. {t('启动时间')}:{getStartTimeString()}
  122. </p>
  123. </Card>
  124. </Col>
  125. <Col span={12}>
  126. <Card
  127. title={t('系统配置')}
  128. headerExtraContent={
  129. <span
  130. style={{
  131. fontSize: '12px',
  132. color: 'var(--semi-color-text-1)',
  133. }}
  134. >
  135. {t('系统配置总览')}
  136. </span>
  137. }
  138. >
  139. <p>
  140. {t('邮箱验证')}:
  141. {statusState?.status?.email_verification === true
  142. ? t('已启用')
  143. : t('未启用')}
  144. </p>
  145. <p>
  146. {t('GitHub 身份验证')}:
  147. {statusState?.status?.github_oauth === true
  148. ? t('已启用')
  149. : t('未启用')}
  150. </p>
  151. <p>
  152. {t('OIDC 身份验证')}:
  153. {statusState?.status?.oidc_enabled === true
  154. ? t('已启用')
  155. : t('未启用')}
  156. </p>
  157. <p>
  158. {t('微信身份验证')}:
  159. {statusState?.status?.wechat_login === true
  160. ? t('已启用')
  161. : t('未启用')}
  162. </p>
  163. <p>
  164. {t('Turnstile 用户校验')}:
  165. {statusState?.status?.turnstile_check === true
  166. ? t('已启用')
  167. : t('未启用')}
  168. </p>
  169. <p>
  170. {t('Telegram 身份验证')}:
  171. {statusState?.status?.telegram_oauth === true
  172. ? t('已启用')
  173. : t('未启用')}
  174. </p>
  175. <p>
  176. {t('Linux DO 身份验证')}:
  177. {statusState?.status?.linuxdo_oauth === true
  178. ? t('已启用')
  179. : t('未启用')}
  180. </p>
  181. </Card>
  182. </Col>
  183. </Row>
  184. </Card>
  185. </>
  186. ) : (
  187. <>
  188. {homePageContent.startsWith('https://') ? (
  189. <iframe
  190. src={homePageContent}
  191. style={{ width: '100%', height: '100vh', border: 'none' }}
  192. />
  193. ) : (
  194. <div
  195. style={{ fontSize: 'larger' }}
  196. dangerouslySetInnerHTML={{ __html: homePageContent }}
  197. ></div>
  198. )}
  199. </>
  200. )}
  201. </>
  202. );
  203. };
  204. export default Home;