SettingsGeneral.js 6.0 KB

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