SettingsGeneral.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. import React, { useEffect, useState, useRef } from 'react';
  2. import { Banner, Button, Col, Form, Row, Spin } from '@douyinfe/semi-ui';
  3. import {
  4. compareObjects,
  5. API,
  6. showError,
  7. showSuccess,
  8. showWarning,
  9. } from '../../../helpers';
  10. import { useTranslation } from 'react-i18next';
  11. export default function GeneralSettings(props) {
  12. const { t } = useTranslation();
  13. const [loading, setLoading] = useState(false);
  14. const [inputs, setInputs] = useState({
  15. TopUpLink: '',
  16. ChatLink: '',
  17. ChatLink2: '',
  18. QuotaPerUnit: '',
  19. RetryTimes: '',
  20. DisplayInCurrencyEnabled: false,
  21. DisplayTokenStatEnabled: false,
  22. DefaultCollapseSidebar: false,
  23. DemoSiteEnabled: false,
  24. });
  25. const refForm = useRef();
  26. const [inputsRow, setInputsRow] = useState(inputs);
  27. function onChange(value, e) {
  28. const name = e.target.id;
  29. setInputs((inputs) => ({ ...inputs, [name]: value }));
  30. }
  31. function onSubmit() {
  32. const updateArray = compareObjects(inputs, inputsRow);
  33. if (!updateArray.length) return showWarning(t('你似乎并没有修改什么'));
  34. const requestQueue = updateArray.map((item) => {
  35. let value = '';
  36. if (typeof inputs[item.key] === 'boolean') {
  37. value = String(inputs[item.key]);
  38. } else {
  39. value = inputs[item.key];
  40. }
  41. return API.put('/api/option/', {
  42. key: item.key,
  43. value,
  44. });
  45. });
  46. setLoading(true);
  47. Promise.all(requestQueue)
  48. .then((res) => {
  49. if (requestQueue.length === 1) {
  50. if (res.includes(undefined)) return;
  51. } else if (requestQueue.length > 1) {
  52. if (res.includes(undefined)) return showError(t('部分保存失败,请重试'));
  53. }
  54. showSuccess(t('保存成功'));
  55. props.refresh();
  56. })
  57. .catch(() => {
  58. showError(t('保存失败,请重试'));
  59. })
  60. .finally(() => {
  61. setLoading(false);
  62. });
  63. }
  64. useEffect(() => {
  65. const currentInputs = {};
  66. for (let key in props.options) {
  67. if (Object.keys(inputs).includes(key)) {
  68. currentInputs[key] = props.options[key];
  69. }
  70. }
  71. setInputs(currentInputs);
  72. setInputsRow(structuredClone(currentInputs));
  73. refForm.current.setValues(currentInputs);
  74. }, [props.options]);
  75. return (
  76. <>
  77. <Spin spinning={loading}>
  78. <Banner
  79. type='warning'
  80. description={t('聊天链接功能已经弃用,请使用下方聊天设置功能')}
  81. />
  82. <Form
  83. values={inputs}
  84. getFormApi={(formAPI) => (refForm.current = formAPI)}
  85. style={{ marginBottom: 15 }}
  86. >
  87. <Form.Section text={t('通用设置')}>
  88. <Row gutter={16}>
  89. <Col span={8}>
  90. <Form.Input
  91. field={'TopUpLink'}
  92. label={t('充值链接')}
  93. initValue={''}
  94. placeholder={t('例如发卡网站的购买链接')}
  95. onChange={onChange}
  96. showClear
  97. />
  98. </Col>
  99. <Col span={8}>
  100. <Form.Input
  101. field={'ChatLink'}
  102. label={t('默认聊天页面链接')}
  103. initValue={''}
  104. placeholder={t('例如 ChatGPT Next Web 的部署地址')}
  105. onChange={onChange}
  106. showClear
  107. />
  108. </Col>
  109. <Col span={8}>
  110. <Form.Input
  111. field={'ChatLink2'}
  112. label={t('聊天页面 2 链接')}
  113. initValue={''}
  114. placeholder={t('例如 ChatGPT Next Web 的部署地址')}
  115. onChange={onChange}
  116. showClear
  117. />
  118. </Col>
  119. <Col span={8}>
  120. <Form.Input
  121. field={'QuotaPerUnit'}
  122. label={t('单位美元额度')}
  123. initValue={''}
  124. placeholder={t('一单位货币能兑换的额度')}
  125. onChange={onChange}
  126. showClear
  127. />
  128. </Col>
  129. <Col span={8}>
  130. <Form.Input
  131. field={'RetryTimes'}
  132. label={t('失败重试次数')}
  133. initValue={''}
  134. placeholder={t('失败重试次数')}
  135. onChange={onChange}
  136. showClear
  137. />
  138. </Col>
  139. </Row>
  140. <Row gutter={16}>
  141. <Col span={8}>
  142. <Form.Switch
  143. field={'DisplayInCurrencyEnabled'}
  144. label={t('以货币形式显示额度')}
  145. size='default'
  146. checkedText='|'
  147. uncheckedText='〇'
  148. onChange={(value) => {
  149. setInputs({
  150. ...inputs,
  151. DisplayInCurrencyEnabled: value,
  152. });
  153. }}
  154. />
  155. </Col>
  156. <Col span={8}>
  157. <Form.Switch
  158. field={'DisplayTokenStatEnabled'}
  159. label={t('额度查询接口返回令牌额度而非用户额度')}
  160. size='default'
  161. checkedText='|'
  162. uncheckedText='〇'
  163. onChange={(value) =>
  164. setInputs({
  165. ...inputs,
  166. DisplayTokenStatEnabled: value,
  167. })
  168. }
  169. />
  170. </Col>
  171. <Col span={8}>
  172. <Form.Switch
  173. field={'DefaultCollapseSidebar'}
  174. label={t('默认折叠侧边栏')}
  175. size='default'
  176. checkedText='|'
  177. uncheckedText='〇'
  178. onChange={(value) =>
  179. setInputs({
  180. ...inputs,
  181. DefaultCollapseSidebar: value,
  182. })
  183. }
  184. />
  185. </Col>
  186. </Row>
  187. <Row>
  188. <Col span={8}>
  189. <Form.Switch
  190. field={'DemoSiteEnabled'}
  191. label={t('演示站点模式')}
  192. size='default'
  193. checkedText='|'
  194. uncheckedText='〇'
  195. onChange={(value) =>
  196. setInputs({
  197. ...inputs,
  198. DemoSiteEnabled: value
  199. })
  200. }
  201. />
  202. </Col>
  203. </Row>
  204. <Row>
  205. <Button size='default' onClick={onSubmit}>
  206. {t('保存通用设置')}
  207. </Button>
  208. </Row>
  209. </Form.Section>
  210. </Form>
  211. </Spin>
  212. </>
  213. );
  214. }