index.tsx 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. import { Col, Form, Input, Modal, Row, Select } from 'antd';
  2. import { service } from '@/pages/device/Instance';
  3. import type { DeviceInstance } from '../typings';
  4. import { useEffect, useState } from 'react';
  5. import { useIntl } from '@@/plugin-locale/localeExports';
  6. import { UploadImage } from '@/components';
  7. import { debounce } from 'lodash';
  8. import encodeQuery from '@/utils/encodeQuery';
  9. import { onlyMessage } from '@/utils/util';
  10. interface Props {
  11. visible: boolean;
  12. close: (data: DeviceInstance | undefined) => void;
  13. reload?: () => void;
  14. model?: 'add' | 'edit';
  15. data?: Partial<DeviceInstance>;
  16. }
  17. const Save = (props: Props) => {
  18. const { visible, close, data } = props;
  19. const [productList, setProductList] = useState<any[]>([]);
  20. const [loading, setLoading] = useState(false);
  21. const [form] = Form.useForm();
  22. useEffect(() => {
  23. if (visible && data) {
  24. form.setFieldsValue({
  25. ...data,
  26. });
  27. }
  28. }, [visible]);
  29. const intl = useIntl();
  30. useEffect(() => {
  31. service
  32. .getProductList(
  33. encodeQuery({
  34. paging: false,
  35. sorts: {
  36. createTime: 'desc',
  37. },
  38. terms: {
  39. state: 1,
  40. },
  41. }),
  42. )
  43. .then((resp: any) => {
  44. if (resp.status === 200) {
  45. const list = resp.result.map((item: { name: any; id: any }) => ({
  46. label: item.name,
  47. value: item.id,
  48. }));
  49. setProductList(list);
  50. }
  51. });
  52. }, []);
  53. const intlFormat = (
  54. id: string,
  55. defaultMessage: string,
  56. paramsID?: string,
  57. paramsMessage?: string,
  58. ) => {
  59. const paramsObj: Record<string, string> = {};
  60. if (paramsID) {
  61. const paramsMsg = intl.formatMessage({
  62. id: paramsID,
  63. defaultMessage: paramsMessage,
  64. });
  65. paramsObj.name = paramsMsg;
  66. }
  67. return intl.formatMessage(
  68. {
  69. id,
  70. defaultMessage,
  71. },
  72. paramsObj,
  73. );
  74. };
  75. const handleSave = async () => {
  76. const values = await form.validateFields();
  77. if (values) {
  78. if (values.id === '') {
  79. delete values.id;
  80. }
  81. setLoading(true);
  82. const resp = (await service.update(values)) as any;
  83. setLoading(false);
  84. if (resp.status === 200) {
  85. onlyMessage('保存成功');
  86. if (props.reload) {
  87. props.reload();
  88. }
  89. props.close(values);
  90. form.resetFields();
  91. }
  92. }
  93. };
  94. const vailId = (_: any, value: any, callback: Function) => {
  95. if (props.model === 'add' && value) {
  96. service.isExists(value).then((resp: any) => {
  97. if (resp.status === 200 && resp.result) {
  98. callback(
  99. intl.formatMessage({
  100. id: 'pages.form.tip.existsID',
  101. defaultMessage: 'ID重复',
  102. }),
  103. );
  104. } else {
  105. callback();
  106. }
  107. });
  108. } else {
  109. callback();
  110. }
  111. };
  112. return (
  113. <Modal
  114. maskClosable={false}
  115. visible={visible}
  116. onCancel={() => {
  117. form.resetFields();
  118. close(undefined);
  119. }}
  120. width="580px"
  121. title={intl.formatMessage({
  122. id: `pages.data.option.${props.model || 'add'}`,
  123. defaultMessage: '新增',
  124. })}
  125. confirmLoading={loading}
  126. onOk={handleSave}
  127. >
  128. <Form
  129. form={form}
  130. layout={'vertical'}
  131. labelAlign={'right'}
  132. labelCol={{
  133. style: { width: 100 },
  134. }}
  135. >
  136. <Row>
  137. <Col span={8}>
  138. <Form.Item name={'photoUrl'}>
  139. <UploadImage />
  140. </Form.Item>
  141. </Col>
  142. <Col span={16}>
  143. <Form.Item
  144. label={'ID'}
  145. name={'id'}
  146. tooltip={intlFormat('pages.form.tooltip.id', '若不填写,系统将自动生成唯一ID')}
  147. rules={[
  148. {
  149. pattern: /^[a-zA-Z0-9_\-]+$/,
  150. message: intlFormat('pages.form.tip.id', '请输入英文或者数字或者-或者_'),
  151. },
  152. {
  153. max: 64,
  154. message: intlFormat('pages.form.tip.max64', '最多输入64个字符'),
  155. },
  156. {
  157. validator: debounce(vailId, 300),
  158. },
  159. ]}
  160. >
  161. <Input
  162. disabled={props.model === 'edit'}
  163. placeholder={`${intlFormat('pages.form.tip.input', '请输入')}ID`}
  164. />
  165. </Form.Item>
  166. <Form.Item
  167. label={intlFormat('pages.table.name', '名称')}
  168. name={'name'}
  169. rules={[
  170. {
  171. required: true,
  172. message: intlFormat(
  173. 'pages.form.tip.input.props',
  174. '请输入名称',
  175. 'pages.table.name',
  176. '名称',
  177. ),
  178. },
  179. {
  180. max: 64,
  181. message: intl.formatMessage({
  182. id: 'pages.form.tip.max64',
  183. defaultMessage: '最多输入64个字符',
  184. }),
  185. },
  186. ]}
  187. required
  188. >
  189. <Input
  190. placeholder={
  191. intlFormat('pages.form.tip.input', '请输入') +
  192. intlFormat('pages.table.name', '名称')
  193. }
  194. />
  195. </Form.Item>
  196. </Col>
  197. </Row>
  198. <Row>
  199. <Col span={24}>
  200. <Form.Item
  201. label={'所属产品'}
  202. name={'productId'}
  203. rules={[
  204. {
  205. required: true,
  206. message: '请选择所属产品',
  207. },
  208. ]}
  209. tooltip={'只能选择“正常”状态的产品'}
  210. required
  211. >
  212. <Select
  213. showSearch
  214. allowClear
  215. options={productList}
  216. disabled={props.model === 'edit'}
  217. onSelect={(_: any, node: any) => {
  218. form.setFieldsValue({
  219. productName: node.label,
  220. });
  221. }}
  222. placeholder={'请选择状态为“正常”的产品'}
  223. filterOption={(input, option) => option.label.includes(input)}
  224. />
  225. </Form.Item>
  226. <Form.Item hidden={true} name={'productName'}>
  227. <Input />
  228. </Form.Item>
  229. </Col>
  230. </Row>
  231. <Row>
  232. <Col span={24}>
  233. <Form.Item label={intlFormat('pages.table.description', '说明')} name={'description'}>
  234. <Input.TextArea
  235. placeholder={
  236. intlFormat('pages.form.tip.input', '请输入') +
  237. intlFormat('pages.table.description', '说明')
  238. }
  239. rows={4}
  240. style={{ width: '100%' }}
  241. maxLength={200}
  242. showCount={true}
  243. />
  244. </Form.Item>
  245. </Col>
  246. </Row>
  247. </Form>
  248. </Modal>
  249. );
  250. };
  251. export default Save;