index.tsx 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. import { PageContainer } from '@ant-design/pro-layout';
  2. import { createForm, onFieldValueChange, onFormInit } from '@formily/core';
  3. import { Card, Col, Input, Row } from 'antd';
  4. import { ISchema } from '@formily/json-schema';
  5. import { useEffect, useMemo, useState } from 'react';
  6. import { createSchemaField, observer } from '@formily/react';
  7. import {
  8. ArrayTable,
  9. Checkbox,
  10. Editable,
  11. Form,
  12. FormButtonGroup,
  13. FormItem,
  14. NumberPicker,
  15. PreviewText,
  16. Radio,
  17. Select,
  18. Space,
  19. Switch,
  20. } from '@formily/antd';
  21. import styles from './index.less';
  22. import { service } from '@/pages/notice/Config';
  23. import { onlyMessage, useAsyncDataSource } from '@/utils/util';
  24. import { useParams } from 'umi';
  25. import { typeList } from '@/pages/notice';
  26. import FUpload from '@/components/Upload';
  27. import WeixinCorp from '@/pages/notice/Config/Detail/doc/WeixinCorp';
  28. import WeixinApp from '@/pages/notice/Config/Detail/doc/WeixinApp';
  29. import DingTalk from '@/pages/notice/Config/Detail/doc/DingTalk';
  30. import DingTalkRebot from '@/pages/notice/Config/Detail/doc/DingTalkRebot';
  31. import AliyunSms from '@/pages/notice/Config/Detail/doc/AliyunSms';
  32. import AliyunVoice from '@/pages/notice/Config/Detail/doc/AliyunVoice';
  33. import Email from '@/pages/notice/Config/Detail/doc/Email';
  34. import { PermissionButton } from '@/components';
  35. import usePermissions from '@/hooks/permission';
  36. import FAutoComplete from '@/components/FAutoComplete';
  37. import Webhook from './doc/Webhook';
  38. import { useModel } from '@@/plugin-model/useModel';
  39. import { typeArray } from '@/components/ProTableCard/CardItems/noticeTemplate';
  40. import RegionIdList from './regionId';
  41. export const docMap = {
  42. weixin: {
  43. corpMessage: <WeixinCorp />,
  44. officialMessage: <WeixinApp />,
  45. },
  46. dingTalk: {
  47. dingTalkMessage: <DingTalk />,
  48. dingTalkRobotWebHook: <DingTalkRebot />,
  49. },
  50. voice: {
  51. aliyun: <AliyunVoice />,
  52. },
  53. sms: {
  54. aliyunSms: <AliyunSms />,
  55. },
  56. email: {
  57. embedded: <Email />,
  58. },
  59. webhook: {
  60. http: <Webhook />,
  61. },
  62. };
  63. const Detail = observer(() => {
  64. const { id } = useParams<{ id: string }>();
  65. const { initialState } = useModel('@@initialState');
  66. const [typeItem, setTypeItem] = useState<string>('email');
  67. const [providerItem, setProviderItem] = useState<string>('embedded');
  68. const [loading, setLoading] = useState<boolean>(false);
  69. const form = useMemo(
  70. () =>
  71. createForm({
  72. validateFirst: true,
  73. effects() {
  74. onFormInit(async (form1) => {
  75. if (id === ':id' || !id) {
  76. form1.setValues({
  77. type: 'email',
  78. provider: 'embedded',
  79. });
  80. } else {
  81. const resp = await service.detail(id);
  82. if (resp.status === 200) {
  83. setTypeItem(resp.result.type);
  84. setProviderItem(resp.result.provider);
  85. form1.setValues(resp.result);
  86. }
  87. }
  88. });
  89. onFieldValueChange('type', async (field, f) => {
  90. const value = field.value;
  91. setTypeItem(value);
  92. if (!value) return;
  93. f.setFieldState('provider', (state1) => {
  94. if (id === ':id' || !id) {
  95. state1.value = typeList[value][0].value;
  96. }
  97. state1.dataSource = typeList[value];
  98. });
  99. });
  100. onFieldValueChange('provider', async (field) => {
  101. const _type = field.query('.type').get('value');
  102. if (_type === 'email') {
  103. setProviderItem('embedded');
  104. } else {
  105. setProviderItem(field.value);
  106. }
  107. });
  108. },
  109. }),
  110. [],
  111. );
  112. useEffect(() => {
  113. setTimeout(() => {
  114. if (initialState?.settings?.title) {
  115. document.title = `通知配置 - ${initialState?.settings?.title}`;
  116. } else {
  117. document.title = '通知配置';
  118. }
  119. }, 0);
  120. }, []);
  121. const SchemaField = createSchemaField({
  122. components: {
  123. FormItem,
  124. Input,
  125. Select,
  126. Switch,
  127. Radio,
  128. ArrayTable,
  129. Editable,
  130. PreviewText,
  131. Space,
  132. FUpload,
  133. Checkbox,
  134. NumberPicker,
  135. FAutoComplete,
  136. },
  137. });
  138. const getTypes = async () =>
  139. service.getTypes().then((resp) => {
  140. return resp.result.map((item: NetworkType) => ({
  141. label: item.name,
  142. value: item.id,
  143. }));
  144. });
  145. const schema: ISchema = {
  146. type: 'object',
  147. properties: {
  148. type: {
  149. title: '通知方式',
  150. 'x-component': 'Select',
  151. 'x-decorator': 'FormItem',
  152. 'x-component-props': {
  153. placeholder: '请选择通知方式',
  154. },
  155. 'x-disabled': !!id && id !== ':id',
  156. 'x-validator': [
  157. {
  158. required: true,
  159. message: '请选择通知方式',
  160. },
  161. ],
  162. enum: typeArray.map((item) => {
  163. return { label: item.text, value: item.status };
  164. }),
  165. },
  166. name: {
  167. title: '名称',
  168. required: true,
  169. 'x-component': 'Input',
  170. 'x-decorator': 'FormItem',
  171. 'x-component-props': {
  172. placeholder: '请输入名称',
  173. },
  174. 'x-validator': [
  175. {
  176. required: true,
  177. message: '请输入名称',
  178. },
  179. {
  180. max: 64,
  181. message: '最多可输入64个字符',
  182. },
  183. ],
  184. },
  185. provider: {
  186. title: '类型',
  187. type: 'string',
  188. 'x-decorator': 'FormItem',
  189. 'x-component': 'Radio.Group',
  190. 'x-component-props': {
  191. optionType: 'button',
  192. },
  193. 'x-reactions': {
  194. dependencies: ['type'],
  195. fulfill: {
  196. state: {
  197. visible: '{{!!$deps[0] && $deps[0] !== "email"}}',
  198. },
  199. },
  200. },
  201. 'x-validator': [
  202. {
  203. required: true,
  204. message: '请选择类型',
  205. },
  206. ],
  207. },
  208. configuration: {
  209. type: 'object',
  210. properties: {
  211. weixin: {
  212. type: 'void',
  213. 'x-reactions': {
  214. dependencies: ['type'],
  215. fulfill: {
  216. state: {
  217. visible: '{{$deps[0]==="weixin"}}',
  218. },
  219. },
  220. },
  221. properties: {
  222. corpId: {
  223. title: 'corpId',
  224. 'x-component': 'Input',
  225. 'x-decorator': 'FormItem',
  226. required: true,
  227. // 企业消息
  228. 'x-reactions': {
  229. dependencies: ['provider'],
  230. fulfill: {
  231. state: {
  232. visible: '{{$deps[0]==="corpMessage"}}',
  233. },
  234. },
  235. },
  236. 'x-component-props': {
  237. placeholder: '请输入corpId',
  238. },
  239. 'x-validator': [
  240. {
  241. max: 64,
  242. message: '最多可输入64个字符',
  243. },
  244. ],
  245. },
  246. corpSecret: {
  247. title: 'corpSecret',
  248. 'x-component': 'Input',
  249. 'x-decorator': 'FormItem',
  250. required: true,
  251. 'x-component-props': {
  252. placeholder: '请输入corpSecret',
  253. },
  254. 'x-reactions': {
  255. dependencies: ['provider'],
  256. fulfill: {
  257. state: {
  258. visible: '{{$deps[0]==="corpMessage"}}',
  259. },
  260. },
  261. },
  262. 'x-validator': [
  263. {
  264. max: 64,
  265. message: '最多可输入64个字符',
  266. },
  267. ],
  268. },
  269. appId: {
  270. title: 'appID',
  271. 'x-component': 'Input',
  272. required: true,
  273. 'x-decorator': 'FormItem',
  274. 'x-component-props': {
  275. placeholder: '请输入appId',
  276. },
  277. 'x-reactions': {
  278. dependencies: ['provider'],
  279. fulfill: {
  280. state: {
  281. visible: '{{$deps[0]==="officialMessage"}}',
  282. },
  283. },
  284. },
  285. },
  286. secret: {
  287. title: 'AppSecret',
  288. 'x-component': 'Input',
  289. required: true,
  290. 'x-decorator': 'FormItem',
  291. 'x-component-props': {
  292. placeholder: '请输入secret',
  293. },
  294. 'x-reactions': {
  295. dependencies: ['provider'],
  296. fulfill: {
  297. state: {
  298. visible: '{{$deps[0]==="officialMessage"}}',
  299. },
  300. },
  301. },
  302. },
  303. },
  304. },
  305. dingTalk: {
  306. type: 'void',
  307. // 'x-visible': id === 'dingTalk',
  308. 'x-reactions': {
  309. dependencies: ['type'],
  310. fulfill: {
  311. state: {
  312. visible: '{{$deps[0]==="dingTalk"}}',
  313. },
  314. },
  315. },
  316. properties: {
  317. appKey: {
  318. title: 'AppKey',
  319. 'x-component': 'Input',
  320. 'x-decorator': 'FormItem',
  321. required: true,
  322. 'x-component-props': {
  323. placeholder: '请输入AppKey',
  324. },
  325. 'x-reactions': {
  326. dependencies: ['provider'],
  327. fulfill: {
  328. state: {
  329. visible: '{{$deps[0]==="dingTalkMessage"}}',
  330. },
  331. },
  332. },
  333. 'x-validator': [
  334. {
  335. max: 64,
  336. message: '最多可输入64个字符',
  337. },
  338. ],
  339. },
  340. appSecret: {
  341. title: 'AppSecret',
  342. 'x-component': 'Input',
  343. 'x-decorator': 'FormItem',
  344. required: true,
  345. 'x-component-props': {
  346. placeholder: '请输入AppSecret',
  347. },
  348. 'x-validator': [
  349. {
  350. max: 64,
  351. message: '最多可输入64个字符',
  352. },
  353. ],
  354. 'x-reactions': {
  355. dependencies: ['provider'],
  356. fulfill: {
  357. state: {
  358. visible: '{{$deps[0]==="dingTalkMessage"}}',
  359. },
  360. },
  361. },
  362. },
  363. url: {
  364. title: 'webHook',
  365. 'x-component': 'Input',
  366. 'x-decorator': 'FormItem',
  367. required: true,
  368. 'x-component-props': {
  369. placeholder: '请输入webhook',
  370. },
  371. 'x-reactions': {
  372. dependencies: ['provider'],
  373. fulfill: {
  374. state: {
  375. visible: '{{$deps[0]==="dingTalkRobotWebHook"}}',
  376. },
  377. },
  378. },
  379. },
  380. },
  381. },
  382. // 阿里云语音/短信
  383. voiceOrSms: {
  384. type: 'void',
  385. // 'x-visible': id === 'voice' || id === 'sms',
  386. 'x-reactions': {
  387. dependencies: ['type'],
  388. fulfill: {
  389. state: {
  390. visible: '{{$deps[0]==="voice" || $deps[0]==="sms"}}',
  391. },
  392. },
  393. },
  394. properties: {
  395. regionId: {
  396. title: 'RegionId',
  397. required: true,
  398. 'x-component-props': {
  399. placeholder: '请选择regionId',
  400. },
  401. 'x-component': 'Select',
  402. 'x-decorator': 'FormItem',
  403. enum: RegionIdList,
  404. },
  405. accessKeyId: {
  406. title: 'AccessKeyId',
  407. required: true,
  408. 'x-component-props': {
  409. placeholder: '请输入accessKeyId',
  410. },
  411. 'x-component': 'Input',
  412. 'x-decorator': 'FormItem',
  413. 'x-validator': [
  414. {
  415. max: 64,
  416. message: '最多可输入64个字符',
  417. },
  418. ],
  419. },
  420. secret: {
  421. title: 'Secret',
  422. required: true,
  423. 'x-component-props': {
  424. placeholder: '请输入secret',
  425. },
  426. 'x-component': 'Input',
  427. 'x-decorator': 'FormItem',
  428. 'x-validator': [
  429. {
  430. max: 64,
  431. message: '最多可输入64个字符',
  432. },
  433. ],
  434. },
  435. },
  436. },
  437. email: {
  438. type: 'void',
  439. // 'x-visible': id === 'email',
  440. 'x-reactions': {
  441. dependencies: ['type'],
  442. fulfill: {
  443. state: {
  444. visible: '{{$deps[0]==="email"}}',
  445. },
  446. },
  447. },
  448. properties: {
  449. space: {
  450. title: '服务器地址',
  451. type: 'void',
  452. 'x-component': 'Space',
  453. 'x-decorator': 'FormItem',
  454. 'x-decorator-props': {
  455. asterisk: true,
  456. feedbackLayout: 'none',
  457. },
  458. properties: {
  459. host: {
  460. // title: '服务器地址',
  461. required: true,
  462. 'x-component-props': {
  463. placeholder: '请输入服务器地址',
  464. style: {
  465. width: '180px',
  466. },
  467. },
  468. 'x-component': 'FAutoComplete',
  469. 'x-decorator': 'FormItem',
  470. enum: [
  471. { label: 'smtp.163.com', value: 'smtp.163.com' },
  472. { label: 'pop.163.com', value: 'pop.163.com' },
  473. { label: 'smtp.exmail.qq.com', value: 'smtp.exmail.qq.com' },
  474. { label: 'pop.exmail.qq.com', value: 'pop.exmail.qq.com' },
  475. { label: 'smtp.qq.com', value: 'smtp.qq.com' },
  476. { label: 'pop.qq.com', value: 'pop.qq.com' },
  477. { label: 'smtpdm.aliyun.com', value: 'smtpdm.aliyun.com' },
  478. { label: 'smtp.126.com', value: 'smtp.126.com' },
  479. { label: 'pop.126.com', value: 'pop.126.com' },
  480. ],
  481. },
  482. port: {
  483. // title: '端口',
  484. required: true,
  485. 'x-component-props': {
  486. placeholder: '请输入端口',
  487. },
  488. default: 25,
  489. 'x-validator': [
  490. {
  491. min: 1,
  492. max: 65535,
  493. message: '请输入1~65535之间的正整数',
  494. },
  495. ],
  496. 'x-component': 'NumberPicker',
  497. 'x-decorator': 'FormItem',
  498. 'x-reactions': {
  499. dependencies: ['.ssl'],
  500. when: '{{$deps[0]}}',
  501. fulfill: {
  502. state: {
  503. value: 465,
  504. },
  505. },
  506. // otherwise: {
  507. // state: {
  508. // value: 25,
  509. // },
  510. // },
  511. },
  512. },
  513. ssl: {
  514. // title: '开启SSL',
  515. type: 'boolean',
  516. 'x-component': 'Checkbox',
  517. 'x-decorator': 'FormItem',
  518. 'x-component-props': {
  519. children: '开启SSL',
  520. style: {
  521. width: '100px',
  522. },
  523. },
  524. // enum: [{label: '开启SSL', value: true}],
  525. },
  526. },
  527. },
  528. sender: {
  529. title: '发件人',
  530. required: true,
  531. 'x-component': 'Input',
  532. 'x-decorator': 'FormItem',
  533. 'x-component-props': {
  534. placeholder: '请输入发件人',
  535. },
  536. 'x-validator': [
  537. {
  538. max: 64,
  539. message: '最多可输入64个字符',
  540. },
  541. ],
  542. },
  543. username: {
  544. title: '用户名',
  545. required: true,
  546. 'x-component': 'Input',
  547. 'x-component-props': {
  548. placeholder: '请输入用户名',
  549. },
  550. 'x-decorator': 'FormItem',
  551. 'x-validator': [
  552. {
  553. max: 64,
  554. message: '最多可输入64个字符',
  555. },
  556. ],
  557. },
  558. password: {
  559. title: '密码',
  560. required: true,
  561. 'x-component-props': {
  562. placeholder: '请输入密码',
  563. },
  564. 'x-component': 'Input',
  565. 'x-decorator': 'FormItem',
  566. 'x-validator': [
  567. {
  568. max: 64,
  569. message: '最多可输入64个字符',
  570. },
  571. ],
  572. },
  573. },
  574. },
  575. webhook: {
  576. // 'x-visible': id === 'webhook',
  577. 'x-reactions': {
  578. dependencies: ['type'],
  579. fulfill: {
  580. state: {
  581. visible: '{{$deps[0]==="webhook"}}',
  582. },
  583. },
  584. },
  585. type: 'void',
  586. properties: {
  587. url: {
  588. title: 'Webhook',
  589. required: true,
  590. 'x-component-props': {
  591. placeholder: '请输入Webhook',
  592. },
  593. 'x-component': 'Input',
  594. 'x-decorator': 'FormItem',
  595. },
  596. headers: {
  597. title: '请求头',
  598. type: 'array',
  599. 'x-decorator': 'FormItem',
  600. 'x-component': 'ArrayTable',
  601. 'x-component-props': {
  602. pagination: { pageSize: 9999 },
  603. // scroll: {x: '100%'},
  604. },
  605. items: {
  606. type: 'object',
  607. properties: {
  608. column1: {
  609. type: 'void',
  610. 'x-component': 'ArrayTable.Column',
  611. 'x-component-props': { width: 200, title: 'KEY' },
  612. properties: {
  613. key: {
  614. type: 'string',
  615. 'x-decorator': 'FormItem',
  616. 'x-component': 'Input',
  617. required: true,
  618. 'x-validator': [
  619. {
  620. max: 64,
  621. message: '最多可输入64个字符',
  622. },
  623. ],
  624. },
  625. },
  626. },
  627. column2: {
  628. type: 'void',
  629. 'x-component': 'ArrayTable.Column',
  630. 'x-component-props': { width: 200, title: 'VALUE' },
  631. properties: {
  632. value: {
  633. type: 'string',
  634. 'x-decorator': 'FormItem',
  635. 'x-component': 'Input',
  636. required: true,
  637. 'x-validator': [
  638. {
  639. max: 64,
  640. message: '最多可输入64个字符',
  641. },
  642. ],
  643. },
  644. },
  645. },
  646. column3: {
  647. type: 'void',
  648. 'x-component': 'ArrayTable.Column',
  649. 'x-component-props': {
  650. title: '操作',
  651. dataIndex: 'operations',
  652. width: 50,
  653. fixed: 'right',
  654. },
  655. properties: {
  656. item: {
  657. type: 'void',
  658. 'x-component': 'FormItem',
  659. properties: {
  660. remove: {
  661. type: 'void',
  662. 'x-component': 'ArrayTable.Remove',
  663. },
  664. },
  665. },
  666. },
  667. },
  668. },
  669. },
  670. properties: {
  671. add: {
  672. type: 'void',
  673. 'x-component': 'ArrayTable.Addition',
  674. title: '添加',
  675. },
  676. },
  677. },
  678. },
  679. },
  680. },
  681. },
  682. description: {
  683. title: '说明',
  684. 'x-decorator': 'FormItem',
  685. 'x-component': 'Input.TextArea',
  686. 'x-component-props': {
  687. rows: 5,
  688. placeholder: '请输入说明',
  689. showCount: true,
  690. maxLength: 200,
  691. },
  692. 'x-validator': [
  693. {
  694. max: 200,
  695. message: '最多可输入200个字符',
  696. },
  697. ],
  698. },
  699. },
  700. };
  701. const handleSave = async () => {
  702. const data: ConfigItem = await form.submit();
  703. setLoading(true);
  704. let response;
  705. if (data.id) {
  706. response = await service.update(data);
  707. } else {
  708. response = await service.save(data);
  709. }
  710. setLoading(false);
  711. if (response?.status === 200) {
  712. onlyMessage('保存成功');
  713. history.back();
  714. }
  715. };
  716. const { getOtherPermission } = usePermissions('notice');
  717. return (
  718. <PageContainer>
  719. <Card>
  720. <Row>
  721. <Col span={10}>
  722. <Form className={styles.form} form={form} layout={'vertical'}>
  723. <SchemaField scope={{ useAsyncDataSource, getTypes }} schema={schema} />
  724. <FormButtonGroup.Sticky>
  725. <FormButtonGroup.FormItem>
  726. <PermissionButton
  727. type="primary"
  728. onClick={handleSave}
  729. loading={loading}
  730. isPermission={getOtherPermission(['add', 'update'])}
  731. >
  732. 保存
  733. </PermissionButton>
  734. </FormButtonGroup.FormItem>
  735. </FormButtonGroup.Sticky>
  736. </Form>
  737. </Col>
  738. <Col span={12} push={2}>
  739. {docMap?.[typeItem]?.[providerItem]}
  740. </Col>
  741. </Row>
  742. </Card>
  743. </PageContainer>
  744. );
  745. });
  746. export default Detail;