edit.tsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. import React, { useEffect, useState } from 'react';
  2. import type { UploadProps } from 'antd';
  3. import { Cascader } from 'antd';
  4. import { Checkbox, Col, Form, Input, message, Modal, Row, Select, Upload } from 'antd';
  5. import { createUser, editUser, queryTreeList, queryUserList } from '@/services/setting';
  6. import { LoadingOutlined, PlusOutlined } from '@ant-design/icons';
  7. import md5 from 'js-md5';
  8. import { queryRole } from '@/services/role';
  9. interface userEditPros {
  10. visible: boolean;
  11. editCallback: () => void;
  12. detailData: any;
  13. }
  14. /**
  15. * 用户管理编辑
  16. * @param props
  17. * @constructor
  18. */
  19. const Edit: React.FC<userEditPros> = (props) => {
  20. const { visible, editCallback, detailData } = props;
  21. const [form] = Form.useForm();
  22. const uploadHeaders = { Authorization: `${localStorage.getItem('token')}` };
  23. const [fileUrl, setFileUrl]: any = useState(
  24. detailData && detailData.photo ? detailData.photo : '',
  25. );
  26. const [loading, setLoading] = useState(false);
  27. const [roleList, setRoleList] = useState([]);
  28. const [selectList, setSelectList] = useState([]);
  29. const [areaList, setAreaList] = useState([]);
  30. const getBase64 = (img: any) => {
  31. const reader = new FileReader();
  32. reader.readAsDataURL(img);
  33. reader.onloadend = () => {
  34. const url = reader.result;
  35. setFileUrl(url);
  36. };
  37. };
  38. useEffect(() => {
  39. // 编辑时
  40. if (detailData) {
  41. const data = [...detailData?.user_role].sort((a: any, b: any) => b.level - a.level);
  42. if (data && data.length) {
  43. const param = {
  44. q: 'list',
  45. role_id: data[0].role_parent_id,
  46. };
  47. // 根据角色id请求用户列表接口 保证所属名称字段编辑时回显
  48. queryUserList(param).then((res) => {
  49. if (res.code === 0) {
  50. setSelectList(res?.data || []);
  51. }
  52. });
  53. }
  54. }
  55. // 角色列表
  56. queryRole({ q: 'list' }).then((res) => {
  57. if (res.code === 0) {
  58. // 去掉超级管理员的角色
  59. const arr = res.data.list.filter(
  60. (item: { record_id: string }) => item.record_id !== '1t7svi01izqcoog3mtdyxdq1008mws8u',
  61. );
  62. setRoleList(arr);
  63. }
  64. });
  65. // 地区列表
  66. queryTreeList({ q: 'tree' }).then((res) => {
  67. if (res && res.code === 0) {
  68. setAreaList(res.data.list || []);
  69. }
  70. });
  71. }, []);
  72. const handleLevel = (values: any) => {
  73. const data: any = roleList.filter((option: { record_id: string }) =>
  74. values.includes(option.record_id),
  75. );
  76. return [...data].sort((a: any, b: any) => b.level - a.level);
  77. };
  78. // 角色选择
  79. const onRoleChange = (selectedValues: any) => {
  80. // 切换角色时,所属名称要清空重新选择
  81. form.setFieldsValue({ parent_id: '' });
  82. const sortedData = handleLevel(selectedValues);
  83. if (sortedData && sortedData.length > 0) {
  84. const maxLevelObject = sortedData[0];
  85. const param = {
  86. q: 'list',
  87. role_id: maxLevelObject.parent_id,
  88. };
  89. queryUserList(param).then((res) => {
  90. if (res.code === 0) {
  91. setSelectList(res?.data || []);
  92. }
  93. });
  94. } else {
  95. setSelectList([]);
  96. }
  97. };
  98. const filesProps: UploadProps = {
  99. maxCount: 1,
  100. action: '/web/v1/files',
  101. headers: uploadHeaders,
  102. listType: 'picture-card',
  103. showUploadList: false,
  104. onChange(info) {
  105. if (info.file.status === 'uploading') {
  106. setLoading(true);
  107. return;
  108. }
  109. if (info.file.status === 'done') {
  110. setLoading(false);
  111. getBase64(info.file.originFileObj);
  112. } else if (info.file.status === 'error') {
  113. setLoading(false);
  114. message.error('文件上传失败');
  115. }
  116. },
  117. };
  118. /**
  119. * 确定
  120. */
  121. const onOk = () => {
  122. form.validateFields().then((values) => {
  123. if (values) {
  124. const data = { ...values };
  125. if (values?.photo) {
  126. data.photo = values?.photo?.file?.response?.data?.url;
  127. }
  128. if (values?.password) {
  129. data.password = md5(values.password);
  130. }
  131. if (values?.role_id) {
  132. const user_role: { role_id: any }[] = [];
  133. values?.role_id.forEach((el: any) => {
  134. user_role.push({ role_id: el });
  135. });
  136. data.user_role = user_role;
  137. delete data.role_id;
  138. }
  139. if (values?.area) {
  140. data.province = values.area[0];
  141. data.city = values.area[1];
  142. data.district = values.area[2];
  143. delete data.area;
  144. }
  145. if (values?.parent_id) {
  146. data.parent_id = values?.parent_id;
  147. }
  148. if (detailData) {
  149. data.record_id = detailData.record_id;
  150. // 编辑
  151. editUser(data)
  152. .then((res) => {
  153. if (res.code === 0) {
  154. message.success('编辑成功');
  155. editCallback();
  156. } else {
  157. message.error(res?.message);
  158. editCallback();
  159. }
  160. })
  161. .catch((e) => {
  162. message.error(e?.message);
  163. editCallback();
  164. });
  165. } else {
  166. // 新增
  167. createUser(data)
  168. .then((res) => {
  169. if (res.code === 0) {
  170. message.success('保存成功');
  171. editCallback();
  172. } else {
  173. message.error(res?.message);
  174. editCallback();
  175. }
  176. })
  177. .catch((e) => {
  178. message.error(e?.message);
  179. editCallback();
  180. });
  181. }
  182. }
  183. });
  184. };
  185. /**
  186. * 取消
  187. */
  188. const onCancel = () => {
  189. editCallback();
  190. };
  191. const formItemLayout = {
  192. labelCol: {
  193. span: 6,
  194. },
  195. wrapperCol: {
  196. span: 16,
  197. },
  198. };
  199. const formItemLayoutTwo = {
  200. labelCol: {
  201. span: 3,
  202. },
  203. wrapperCol: {
  204. span: 21,
  205. },
  206. };
  207. const uploadButton = (
  208. <div>
  209. {loading ? <LoadingOutlined /> : <PlusOutlined />}
  210. <div className="ant-upload-text">上传</div>
  211. </div>
  212. );
  213. return (
  214. <Modal
  215. title={`${detailData ? '编辑' : '新增'}`}
  216. open={visible}
  217. onOk={onOk}
  218. onCancel={onCancel}
  219. width={800}
  220. >
  221. <Form form={form}>
  222. <Row>
  223. <Col span={12}>
  224. <Form.Item
  225. {...formItemLayout}
  226. name="user_name"
  227. label="用户姓名"
  228. rules={[{ required: true, message: '请输入用户姓名' }]}
  229. initialValue={detailData?.user_name || ''}
  230. >
  231. <Input placeholder="请输入用户姓名" />
  232. </Form.Item>
  233. </Col>
  234. <Col span={12}>
  235. <Form.Item {...formItemLayout} name="password" label="密码">
  236. <Input type="password" placeholder="请输入密码" />
  237. </Form.Item>
  238. </Col>
  239. <Col span={12}>
  240. <Form.Item
  241. {...formItemLayout}
  242. name="phone"
  243. label="手机号"
  244. rules={[
  245. { required: true, message: '请输入手机号' },
  246. {
  247. pattern:
  248. /^1((34[0-8])|(8\d{2})|(([35][0-35-9]|4[579]|66|7[35678]|9[1389])\d{1}))\d{7}$/,
  249. message: '请输入正确的手机号',
  250. },
  251. ]}
  252. initialValue={detailData?.phone || ''}
  253. >
  254. <Input placeholder="请输入手机号" />
  255. </Form.Item>
  256. </Col>
  257. <Col span={12}>
  258. <Form.Item
  259. {...formItemLayout}
  260. name="company"
  261. label="公司名称"
  262. initialValue={detailData?.company || ''}
  263. >
  264. <Input placeholder="请输入公司名称" />
  265. </Form.Item>
  266. </Col>
  267. <Col span={24}>
  268. <Form.Item
  269. {...formItemLayoutTwo}
  270. name="role_id"
  271. label="角色名称"
  272. rules={[{ required: true, message: '请选择角色名称' }]}
  273. initialValue={
  274. detailData && detailData?.user_role && detailData?.user_role.length
  275. ? detailData?.user_role?.map((item: any) => item.role_id)
  276. : []
  277. }
  278. >
  279. <Checkbox.Group
  280. options={roleList.map((option: { record_id: string; name: string }) => ({
  281. label: option.name,
  282. value: option.record_id,
  283. record_id: option.record_id,
  284. }))}
  285. onChange={onRoleChange}
  286. />
  287. </Form.Item>
  288. </Col>
  289. <Col span={24}>
  290. <Form.Item
  291. {...formItemLayoutTwo}
  292. name="parent_id"
  293. label="所属名称"
  294. rules={[{ required: true, message: '请选择所属名称' }]}
  295. initialValue={detailData?.parent_id || ''}
  296. >
  297. <Select placeholder="请选择所属名称">
  298. {selectList && selectList.length
  299. ? selectList.map(
  300. (res: { user_name: string; record_id: string; parent_id: string }) => {
  301. return (
  302. <Select.Option key={res.record_id} value={res.record_id}>
  303. {res?.user_name}
  304. </Select.Option>
  305. );
  306. },
  307. )
  308. : null}
  309. </Select>
  310. </Form.Item>
  311. </Col>
  312. <Col span={24}>
  313. <Form.Item
  314. {...formItemLayoutTwo}
  315. name="area"
  316. label="所属地区"
  317. initialValue={
  318. detailData?.province
  319. ? `${detailData?.province}/${detailData?.city}/${detailData?.district}`
  320. : ''
  321. }
  322. >
  323. <Cascader
  324. options={areaList}
  325. placeholder="请选择所属地区"
  326. fieldNames={{ label: 'name', value: 'name', children: 'children' }}
  327. />
  328. </Form.Item>
  329. </Col>
  330. <Col span={12}>
  331. <Form.Item {...formItemLayout} name="photo" label="头像" initialValue={[]}>
  332. <Upload {...filesProps}>
  333. {fileUrl === '' ? (
  334. uploadButton
  335. ) : (
  336. <img src={fileUrl} alt="data" style={{ width: '100%' }} />
  337. )}
  338. </Upload>
  339. </Form.Item>
  340. </Col>
  341. </Row>
  342. </Form>
  343. </Modal>
  344. );
  345. };
  346. export default Edit;