OtherSetting.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. import React, { useEffect, useRef, useState } from 'react';
  2. import { Col, Row , Form, Button, Banner } from '@douyinfe/semi-ui';
  3. import { API, showError, showSuccess } from '../helpers';
  4. import { marked } from 'marked';
  5. const OtherSetting = () => {
  6. let [inputs, setInputs] = useState({
  7. Notice: '',
  8. SystemName: '',
  9. Logo: '',
  10. Footer: '',
  11. About: '',
  12. HomePageContent: ''
  13. });
  14. let [loading, setLoading] = useState(false);
  15. const [showUpdateModal, setShowUpdateModal] = useState(false);
  16. const [updateData, setUpdateData] = useState({
  17. tag_name: '',
  18. content: ''
  19. });
  20. const updateOption = async (key, value) => {
  21. setLoading(true);
  22. const res = await API.put('/api/option/', {
  23. key,
  24. value
  25. });
  26. const { success, message } = res.data;
  27. if (success) {
  28. setInputs((inputs) => ({ ...inputs, [key]: value }));
  29. } else {
  30. showError(message);
  31. }
  32. setLoading(false);
  33. };
  34. const [loadingInput, setLoadingInput] = useState({
  35. Notice: false,
  36. SystemName: false,
  37. Logo: false,
  38. HomePageContent: false,
  39. About: false,
  40. Footer: false
  41. });
  42. const handleInputChange = async (value, e) => {
  43. const name = e.target.id;
  44. setInputs((inputs) => ({ ...inputs, [name]: value }));
  45. };
  46. // 通用设置
  47. const formAPISettingGeneral = useRef();
  48. // 通用设置 - Notice
  49. const submitNotice = async () => {
  50. try {
  51. setLoadingInput((loadingInput) => ({ ...loadingInput, Notice: true }));
  52. await updateOption('Notice', inputs.Notice);
  53. showSuccess('公告已更新');
  54. } catch (error) {
  55. console.error("公告更新失败", error);
  56. showError("公告更新失败")
  57. } finally {
  58. setLoadingInput((loadingInput) => ({ ...loadingInput, Notice: false }));
  59. }
  60. };
  61. // 个性化设置
  62. const formAPIPersonalization = useRef();
  63. // 个性化设置 - SystemName
  64. const submitSystemName = async () => {
  65. try {
  66. setLoadingInput((loadingInput) => ({ ...loadingInput, SystemName: true }));
  67. await updateOption('SystemName', inputs.SystemName);
  68. showSuccess('系统名称已更新');
  69. } catch (error) {
  70. console.error("系统名称更新失败", error);
  71. showError("系统名称更新失败")
  72. } finally {
  73. setLoadingInput((loadingInput) => ({ ...loadingInput, SystemName: false }));
  74. }
  75. };
  76. // 个性化设置 - Logo
  77. const submitLogo = async () => {
  78. try {
  79. setLoadingInput((loadingInput) => ({ ...loadingInput, Logo: true }));
  80. await updateOption('Logo', inputs.Logo);
  81. showSuccess('Logo 已更新');
  82. } catch (error) {
  83. console.error("Logo 更新失败", error);
  84. showError("Logo 更新失败")
  85. } finally {
  86. setLoadingInput((loadingInput) => ({ ...loadingInput, Logo: false }));
  87. }
  88. };
  89. // 个性化设置 - 首页内容
  90. const submitOption = async (key) => {
  91. try {
  92. setLoadingInput((loadingInput) => ({ ...loadingInput, HomePageContent: true }));
  93. await updateOption(key, inputs[key]);
  94. showSuccess('首页内容已更新');
  95. } catch (error) {
  96. console.error("首页内容更新失败", error);
  97. showError("首页内容更新失败")
  98. } finally {
  99. setLoadingInput((loadingInput) => ({ ...loadingInput, HomePageContent: false }));
  100. }
  101. };
  102. // 个性化设置 - 关于
  103. const submitAbout = async () => {
  104. try {
  105. setLoadingInput((loadingInput) => ({ ...loadingInput, About: true }));
  106. await updateOption('About', inputs.About);
  107. showSuccess('关于内容已更新');
  108. } catch (error) {
  109. console.error("关于内容更新失败", error);
  110. showError("关于内容更新失败");
  111. } finally {
  112. setLoadingInput((loadingInput) => ({ ...loadingInput, About: false }));
  113. }
  114. };
  115. // 个性化设置 - 页脚
  116. const submitFooter = async () => {
  117. try {
  118. setLoadingInput((loadingInput) => ({ ...loadingInput, Footer: true }));
  119. await updateOption('Footer', inputs.Footer);
  120. showSuccess('页脚内容已更新');
  121. } catch (error) {
  122. console.error("页脚内容更新失败", error);
  123. showError("页脚内容更新失败");
  124. } finally {
  125. setLoadingInput((loadingInput) => ({ ...loadingInput, Footer: false }));
  126. }
  127. };
  128. const openGitHubRelease = () => {
  129. window.location =
  130. 'https://github.com/songquanpeng/one-api/releases/latest';
  131. };
  132. const checkUpdate = async () => {
  133. const res = await API.get(
  134. 'https://api.github.com/repos/songquanpeng/one-api/releases/latest'
  135. );
  136. const { tag_name, body } = res.data;
  137. if (tag_name === process.env.REACT_APP_VERSION) {
  138. showSuccess(`已是最新版本:${tag_name}`);
  139. } else {
  140. setUpdateData({
  141. tag_name: tag_name,
  142. content: marked.parse(body)
  143. });
  144. setShowUpdateModal(true);
  145. }
  146. };
  147. const getOptions = async () => {
  148. const res = await API.get('/api/option/');
  149. const { success, message, data } = res.data;
  150. if (success) {
  151. let newInputs = {};
  152. data.forEach((item) => {
  153. if (item.key in inputs) {
  154. newInputs[item.key] = item.value;
  155. }
  156. });
  157. setInputs(newInputs);
  158. formAPISettingGeneral.current.setValues(newInputs);
  159. formAPIPersonalization.current.setValues(newInputs);
  160. } else {
  161. showError(message);
  162. }
  163. };
  164. useEffect( () => {
  165. getOptions();
  166. }, []);
  167. return (
  168. <Row >
  169. <Col span={24}>
  170. {/* 通用设置 */}
  171. <Form values={inputs} getFormApi={formAPI => formAPISettingGeneral.current = formAPI} style={{marginBottom: 15}}>
  172. <Form.Section text={'通用设置'}>
  173. <Form.TextArea
  174. label={'公告'}
  175. placeholder={'在此输入新的公告内容,支持 Markdown & HTML 代码'}
  176. field={'Notice'}
  177. onChange={handleInputChange}
  178. style={{ fontFamily: 'JetBrains Mono, Consolas' }}
  179. autosize={{ minRows: 6, maxRows: 12 }}
  180. />
  181. <Button onClick={submitNotice} loading={loadingInput['Notice']}>设置公告</Button>
  182. </Form.Section>
  183. </Form>
  184. {/* 个性化设置 */}
  185. <Form values={inputs} getFormApi={formAPI => formAPIPersonalization.current = formAPI} style={{marginBottom: 15}}>
  186. <Form.Section text={'个性化设置'}>
  187. <Form.Input
  188. label={'系统名称'}
  189. placeholder={'在此输入系统名称'}
  190. field={'SystemName'}
  191. onChange={handleInputChange}
  192. />
  193. <Button onClick={submitSystemName} loading={loadingInput['SystemName']}>设置系统名称</Button>
  194. <Form.Input
  195. label={'Logo 图片地址'}
  196. placeholder={'在此输入 Logo 图片地址'}
  197. field={'Logo'}
  198. onChange={handleInputChange}
  199. />
  200. <Button onClick={submitLogo} loading={loadingInput['Logo']}>设置 Logo</Button>
  201. <Form.TextArea
  202. label={'首页内容'}
  203. placeholder={'在此输入首页内容,支持 Markdown & HTML 代码,设置后首页的状态信息将不再显示。如果输入的是一个链接,则会使用该链接作为 iframe 的 src 属性,这允许你设置任意网页作为首页。'}
  204. field={'HomePageContent'}
  205. onChange={handleInputChange}
  206. style={{ fontFamily: 'JetBrains Mono, Consolas' }}
  207. autosize={{ minRows: 6, maxRows: 12 }}
  208. />
  209. <Button onClick={() => submitOption('HomePageContent')} loading={loadingInput['HomePageContent']}>设置首页内容</Button>
  210. <Form.TextArea
  211. label={'关于'}
  212. placeholder={'在此输入新的关于内容,支持 Markdown & HTML 代码。如果输入的是一个链接,则会使用该链接作为 iframe 的 src 属性,这允许你设置任意网页作为关于页面。'}
  213. field={'About'}
  214. onChange={handleInputChange}
  215. style={{ fontFamily: 'JetBrains Mono, Consolas' }}
  216. autosize={{ minRows: 6, maxRows: 12 }}
  217. />
  218. <Button onClick={submitAbout} loading={loadingInput['About']}>设置关于</Button>
  219. {/* */}
  220. <Banner
  221. fullMode={false}
  222. type="info"
  223. description="移除 One API 的版权标识必须首先获得授权,项目维护需要花费大量精力,如果本项目对你有意义,请主动支持本项目。"
  224. closeIcon={null}
  225. style={{ marginTop: 15 }}
  226. />
  227. <Form.Input
  228. label={'页脚'}
  229. placeholder={'在此输入新的页脚,留空则使用默认页脚,支持 HTML 代码'}
  230. field={'Footer'}
  231. onChange={handleInputChange}
  232. />
  233. <Button onClick={submitFooter} loading={loadingInput['Footer']}>设置页脚</Button>
  234. </Form.Section>
  235. </Form>
  236. </Col>
  237. {/*<Modal*/}
  238. {/* onClose={() => setShowUpdateModal(false)}*/}
  239. {/* onOpen={() => setShowUpdateModal(true)}*/}
  240. {/* open={showUpdateModal}*/}
  241. {/*>*/}
  242. {/* <Modal.Header>新版本:{updateData.tag_name}</Modal.Header>*/}
  243. {/* <Modal.Content>*/}
  244. {/* <Modal.Description>*/}
  245. {/* <div dangerouslySetInnerHTML={{ __html: updateData.content }}></div>*/}
  246. {/* </Modal.Description>*/}
  247. {/* </Modal.Content>*/}
  248. {/* <Modal.Actions>*/}
  249. {/* <Button onClick={() => setShowUpdateModal(false)}>关闭</Button>*/}
  250. {/* <Button*/}
  251. {/* content='详情'*/}
  252. {/* onClick={() => {*/}
  253. {/* setShowUpdateModal(false);*/}
  254. {/* openGitHubRelease();*/}
  255. {/* }}*/}
  256. {/* />*/}
  257. {/* </Modal.Actions>*/}
  258. {/*</Modal>*/}
  259. </Row>
  260. );
  261. };
  262. export default OtherSetting;