EditUser.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. import React, { useEffect, useState } from 'react';
  2. import { useParams, useNavigate } from 'react-router-dom';
  3. import { API, isMobile, showError, showSuccess } from '../../helpers';
  4. import { renderQuota, renderQuotaWithPrompt } from '../../helpers/render';
  5. import Title from "@douyinfe/semi-ui/lib/es/typography/title";
  6. import { SideSheet, Space, Button, Spin, Input, Typography, Select, Divider } from "@douyinfe/semi-ui";
  7. const EditUser = (props) => {
  8. const userId = props.editingUser.id;
  9. const [loading, setLoading] = useState(true);
  10. const [inputs, setInputs] = useState({
  11. username: '',
  12. display_name: '',
  13. password: '',
  14. github_id: '',
  15. wechat_id: '',
  16. email: '',
  17. quota: 0,
  18. group: 'default'
  19. });
  20. const [groupOptions, setGroupOptions] = useState([]);
  21. const { username, display_name, password, github_id, wechat_id, telegram_id, email, quota, group } =
  22. inputs;
  23. const handleInputChange = (name, value) => {
  24. setInputs((inputs) => ({ ...inputs, [name]: value }));
  25. };
  26. const fetchGroups = async () => {
  27. try {
  28. let res = await API.get(`/api/group/`);
  29. setGroupOptions(res.data.data.map((group) => ({
  30. label: group,
  31. value: group,
  32. })));
  33. } catch (error) {
  34. showError(error.message);
  35. }
  36. };
  37. const navigate = useNavigate();
  38. const handleCancel = () => {
  39. props.handleClose();
  40. }
  41. const loadUser = async () => {
  42. setLoading(true);
  43. let res = undefined;
  44. if (userId) {
  45. res = await API.get(`/api/user/${userId}`);
  46. } else {
  47. res = await API.get(`/api/user/self`);
  48. }
  49. const { success, message, data } = res.data;
  50. if (success) {
  51. data.password = '';
  52. setInputs(data);
  53. } else {
  54. showError(message);
  55. }
  56. setLoading(false);
  57. };
  58. useEffect(() => {
  59. loadUser().then();
  60. if (userId) {
  61. fetchGroups().then();
  62. }
  63. }, [props.editingUser.id]);
  64. const submit = async () => {
  65. setLoading(true);
  66. let res = undefined;
  67. if (userId) {
  68. let data = { ...inputs, id: parseInt(userId) };
  69. if (typeof data.quota === 'string') {
  70. data.quota = parseInt(data.quota);
  71. }
  72. res = await API.put(`/api/user/`, data);
  73. } else {
  74. res = await API.put(`/api/user/self`, inputs);
  75. }
  76. const { success, message } = res.data;
  77. if (success) {
  78. showSuccess('用户信息更新成功!');
  79. props.refresh();
  80. props.handleClose();
  81. } else {
  82. showError(message);
  83. }
  84. setLoading(false);
  85. };
  86. return (
  87. <>
  88. <SideSheet
  89. placement={'right'}
  90. title={<Title level={3}>{'编辑用户'}</Title>}
  91. headerStyle={{ borderBottom: '1px solid var(--semi-color-border)' }}
  92. bodyStyle={{ borderBottom: '1px solid var(--semi-color-border)' }}
  93. visible={props.visible}
  94. footer={
  95. <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
  96. <Space>
  97. <Button theme='solid' size={'large'} onClick={submit}>提交</Button>
  98. <Button theme='solid' size={'large'} type={'tertiary'} onClick={handleCancel}>取消</Button>
  99. </Space>
  100. </div>
  101. }
  102. closeIcon={null}
  103. onCancel={() => handleCancel()}
  104. width={isMobile() ? '100%' : 600}
  105. >
  106. <Spin spinning={loading}>
  107. <div style={{ marginTop: 20 }}>
  108. <Typography.Text>用户名</Typography.Text>
  109. </div>
  110. <Input
  111. label='用户名'
  112. name='username'
  113. placeholder={'请输入新的用户名'}
  114. onChange={value => handleInputChange('username', value)}
  115. value={username}
  116. autoComplete='new-password'
  117. />
  118. <div style={{ marginTop: 20 }}>
  119. <Typography.Text>密码</Typography.Text>
  120. </div>
  121. <Input
  122. label='密码'
  123. name='password'
  124. type={'password'}
  125. placeholder={'请输入新的密码,最短 8 位'}
  126. onChange={value => handleInputChange('password', value)}
  127. value={password}
  128. autoComplete='new-password'
  129. />
  130. <div style={{ marginTop: 20 }}>
  131. <Typography.Text>显示名称</Typography.Text>
  132. </div>
  133. <Input
  134. label='显示名称'
  135. name='display_name'
  136. placeholder={'请输入新的显示名称'}
  137. onChange={value => handleInputChange('display_name', value)}
  138. value={display_name}
  139. autoComplete='new-password'
  140. />
  141. {
  142. userId && <>
  143. <div style={{ marginTop: 20 }}>
  144. <Typography.Text>分组</Typography.Text>
  145. </div>
  146. <Select
  147. placeholder={'请选择分组'}
  148. name='group'
  149. fluid
  150. search
  151. selection
  152. allowAdditions
  153. additionLabel={'请在系统设置页面编辑分组倍率以添加新的分组:'}
  154. onChange={value => handleInputChange('group', value)}
  155. value={inputs.group}
  156. autoComplete='new-password'
  157. optionList={groupOptions}
  158. />
  159. <div style={{ marginTop: 20 }}>
  160. <Typography.Text>{`剩余额度${renderQuotaWithPrompt(quota)}`}</Typography.Text>
  161. </div>
  162. <Input
  163. name='quota'
  164. placeholder={'请输入新的剩余额度'}
  165. onChange={value => handleInputChange('quota', value)}
  166. value={quota}
  167. type={'number'}
  168. autoComplete='new-password'
  169. />
  170. </>
  171. }
  172. <Divider style={{ marginTop: 20 }}>以下信息不可修改</Divider>
  173. <div style={{ marginTop: 20 }}>
  174. <Typography.Text>已绑定的 GitHub 账户</Typography.Text>
  175. </div>
  176. <Input
  177. name='github_id'
  178. value={github_id}
  179. autoComplete='new-password'
  180. placeholder='此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改'
  181. readonly
  182. />
  183. <div style={{ marginTop: 20 }}>
  184. <Typography.Text>已绑定的微信账户</Typography.Text>
  185. </div>
  186. <Input
  187. name='wechat_id'
  188. value={wechat_id}
  189. autoComplete='new-password'
  190. placeholder='此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改'
  191. readonly
  192. />
  193. <Input
  194. name='telegram_id'
  195. value={telegram_id}
  196. autoComplete='new-password'
  197. placeholder='此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改'
  198. readonly
  199. />
  200. <div style={{ marginTop: 20 }}>
  201. <Typography.Text>已绑定的邮箱账户</Typography.Text>
  202. </div>
  203. <Input
  204. name='email'
  205. value={email}
  206. autoComplete='new-password'
  207. placeholder='此项只读,需要用户通过个人设置页面的相关绑定按钮进行绑定,不可直接修改'
  208. readonly
  209. />
  210. </Spin>
  211. </SideSheet>
  212. </>
  213. );
  214. };
  215. export default EditUser;