index.tsx 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  1. import {
  2. ArrayTable,
  3. Editable,
  4. Form,
  5. FormButtonGroup,
  6. FormItem,
  7. Input,
  8. NumberPicker,
  9. PreviewText,
  10. Radio,
  11. Select,
  12. Space,
  13. Submit,
  14. Switch,
  15. } from '@formily/antd';
  16. import type { Field } from '@formily/core';
  17. import { createForm, onFieldInit, onFieldValueChange } from '@formily/core';
  18. import { createSchemaField, observer } from '@formily/react';
  19. import type { ISchema } from '@formily/json-schema';
  20. import styles from './index.less';
  21. import { useEffect, useMemo } from 'react';
  22. import FUpload from '@/components/Upload';
  23. import { useParams } from 'umi';
  24. import { PageContainer } from '@ant-design/pro-layout';
  25. import { Card, Col, message, Row } from 'antd';
  26. import { typeList } from '@/pages/notice';
  27. import { configService, service, state } from '@/pages/notice/Template';
  28. import FBraftEditor from '@/components/FBraftEditor';
  29. import { useAsyncDataSource } from '@/utils/util';
  30. const Detail = observer(() => {
  31. const { id } = useParams<{ id: string }>();
  32. const getConfig = () =>
  33. configService
  34. .queryNoPagingPost({
  35. terms: [{ column: 'type$IN', value: id }],
  36. })
  37. .then((resp) => {
  38. return resp.result?.map((item) => ({
  39. label: item.name,
  40. value: item.id,
  41. }));
  42. });
  43. // 正则提取${}里面的值
  44. const pattern = /(?<=\$\{).*?(?=\})/g;
  45. const form = useMemo(
  46. () =>
  47. createForm({
  48. validateFirst: true,
  49. effects() {
  50. onFieldInit('template.message', (field, form1) => {
  51. if (id === 'email') {
  52. field.setComponent(FBraftEditor);
  53. }
  54. console.log(form1);
  55. ///给FBraftEditor 设置初始值
  56. });
  57. onFieldValueChange('template.message', (field, form1) => {
  58. let value = (field as Field).value;
  59. if (id === 'email' && form1.modified) {
  60. value = value?.toHTML();
  61. }
  62. console.log(value, 'test');
  63. const idList = value
  64. .match(pattern)
  65. ?.filter((i: string) => i)
  66. .map((item: string) => ({ id: item, type: 'string', format: '--' }));
  67. if (form1.modified) {
  68. form1.setValuesIn('variableDefinitions', idList);
  69. }
  70. });
  71. onFieldValueChange('variableDefinitions.*.type', (field) => {
  72. const value = (field as Field).value;
  73. const format = field.query('.format').take();
  74. switch (value) {
  75. case 'date':
  76. format.setComponent(Select);
  77. format.setDataSource([
  78. { label: 'String类型的UTC时间戳 (毫秒)', value: 'string' },
  79. { label: 'yyyy-MM-dd', value: 'yyyy-MM-dd' },
  80. { label: 'yyyy-MM-dd HH:mm:ss', value: 'yyyy-MM-dd HH:mm:ss' },
  81. { label: 'yyyy-MM-dd HH:mm:ss EE', value: 'yyyy-MM-dd HH:mm:ss EE' },
  82. { label: 'yyyy-MM-dd HH:mm:ss zzz', value: 'yyyy-MM-dd HH:mm:ss zzz' },
  83. ]);
  84. format.setValue('string');
  85. break;
  86. case 'string':
  87. format.setComponent(PreviewText.Input);
  88. format.setValue('--');
  89. break;
  90. case 'number':
  91. format.setComponent(Input);
  92. format.setValue('%.xf');
  93. break;
  94. case 'file':
  95. format.setComponent(Select);
  96. format.setDataSource([
  97. { label: '视频', value: 'video' },
  98. { label: '图片', value: 'img' },
  99. { label: '全部', value: 'any' },
  100. ]);
  101. format.setValue('any');
  102. break;
  103. case 'other':
  104. format.setComponent(PreviewText.Input);
  105. format.setValue('--');
  106. break;
  107. }
  108. });
  109. },
  110. }),
  111. [id],
  112. );
  113. useEffect(() => {
  114. if (state.current) {
  115. form.setValues(state.current);
  116. }
  117. }, []);
  118. const SchemaField = createSchemaField({
  119. components: {
  120. FormItem,
  121. Input,
  122. Select,
  123. Switch,
  124. Radio,
  125. ArrayTable,
  126. Editable,
  127. PreviewText,
  128. Space,
  129. FUpload,
  130. NumberPicker,
  131. FBraftEditor,
  132. },
  133. });
  134. const handleSave = async () => {
  135. const data: TemplateItem = await form.submit();
  136. // dingTalkRobotWebHook
  137. // 提交的时候处理内容
  138. // 钉钉机器人-->dingTalkRobotWebHook
  139. // r如果是text 的话。template.message=>template.text.content
  140. // 如果是markdown 的话。 template.message=>template.markdown.text
  141. // 如果是link的话。 template.message =>template.markdown.text
  142. if (data.provider === 'dingTalkRobotWebHook') {
  143. const type = data.template.messageType;
  144. // emplate.messageType
  145. switch (type) {
  146. case 'text':
  147. data.template.text = {
  148. content: data.template.message,
  149. };
  150. // data.template.text.content = data.template.message;
  151. break;
  152. case 'markdown':
  153. data.template.markdown.text = data.template.message;
  154. break;
  155. case 'link':
  156. data.template.link.text = data.template.message;
  157. }
  158. }
  159. if (id === 'email') {
  160. data.provider = 'embedded';
  161. data.template.message = data.template.message.toHTML();
  162. }
  163. const response: any = await service.save(data);
  164. if (response?.status === 200) {
  165. message.success('保存成功');
  166. history.back();
  167. }
  168. };
  169. const schema: ISchema = {
  170. type: 'object',
  171. properties: {
  172. name: {
  173. title: '名称',
  174. type: 'string',
  175. 'x-decorator': 'FormItem',
  176. 'x-component': 'Input',
  177. name: 'name',
  178. 'x-validator': [
  179. {
  180. max: 64,
  181. message: '最多可输入64个字符',
  182. },
  183. {
  184. required: true,
  185. message: '请输入名称',
  186. },
  187. ],
  188. },
  189. type: {
  190. title: '类型',
  191. 'x-value': id,
  192. 'x-hidden': true,
  193. },
  194. provider: {
  195. title: '类型',
  196. type: 'string',
  197. 'x-decorator': 'FormItem',
  198. 'x-component': 'Radio.Group',
  199. 'x-component-props': {
  200. optionType: 'button',
  201. },
  202. required: true,
  203. 'x-visible': typeList[id]?.length > 0,
  204. 'x-hidden': id === 'email',
  205. enum: typeList[id] || [],
  206. },
  207. configId: {
  208. title: '绑定配置',
  209. type: 'string',
  210. 'x-decorator': 'FormItem',
  211. 'x-component': 'Select',
  212. // enum: [
  213. // {label: '测试配置1', value: 'test1'},
  214. // {label: '测试配置2', value: 'test2'},
  215. // {label: '测试配置3', value: 'test3'},
  216. // ],
  217. 'x-reactions': '{{useAsyncDataSource(getConfig)}}',
  218. 'x-visible': id !== 'email',
  219. },
  220. template: {
  221. type: 'object',
  222. properties: {
  223. weixin: {
  224. type: 'void',
  225. 'x-visible': id === 'weixin',
  226. properties: {
  227. agentId: {
  228. title: 'AgentId',
  229. 'x-component': 'Input',
  230. 'x-decorator': 'FormItem',
  231. 'x-decorator-props': {
  232. tooltip: '请输入AgentID',
  233. },
  234. 'x-component-props': {
  235. placeholder: '请输入AgentID',
  236. },
  237. },
  238. toUser: {
  239. title: '收信人ID',
  240. 'x-component': 'Input',
  241. 'x-decorator': 'FormItem',
  242. 'x-decorator-props': {
  243. tooltip: '请输入收信人ID',
  244. },
  245. 'x-component-props': {
  246. placeholder: '请输入收信人ID',
  247. },
  248. },
  249. toParty: {
  250. title: '收信部门ID',
  251. 'x-component': 'Input',
  252. 'x-decorator': 'FormItem',
  253. 'x-decorator-props': {
  254. tooltip: '请输入收信部门ID',
  255. },
  256. 'x-component-props': {
  257. placeholder: '请输入收信部门ID',
  258. },
  259. },
  260. toTag: {
  261. title: '标签推送',
  262. 'x-component': 'Input',
  263. 'x-decorator': 'FormItem',
  264. 'x-decorator-props': {
  265. tooltip: '标签推送',
  266. },
  267. 'x-component-props': {
  268. placeholder: '请输入标签推送,多个标签用,号分隔',
  269. },
  270. },
  271. },
  272. },
  273. dingTalk: {
  274. type: 'void',
  275. 'x-visible': id === 'dingTalk',
  276. properties: {
  277. dingTalkMessage: {
  278. type: 'void',
  279. properties: {
  280. agentId: {
  281. title: 'AgentID',
  282. 'x-component': 'Input',
  283. 'x-decorator': 'FormItem',
  284. 'x-decorator-props': {
  285. tooltip: '请输入AgentID',
  286. },
  287. 'x-component-props': {
  288. placeholder: '请输入AgentID',
  289. },
  290. },
  291. toAllUser: {
  292. title: '通知全部用户',
  293. type: 'boolean',
  294. 'x-component': 'Radio.Group',
  295. 'x-decorator': 'FormItem',
  296. enum: [
  297. { label: '是', value: true },
  298. { label: '否', value: false },
  299. ],
  300. },
  301. userIdList: {
  302. title: '收信人ID',
  303. 'x-component': 'Input',
  304. 'x-decorator': 'FormItem',
  305. 'x-decorator-props': {
  306. tooltip: '请输入收信人ID',
  307. },
  308. 'x-component-props': {
  309. placeholder: '请输入收信人ID',
  310. },
  311. },
  312. departmentIdList: {
  313. title: '收信部门ID',
  314. 'x-component': 'Input',
  315. 'x-decorator': 'FormItem',
  316. 'x-decorator-props': {
  317. tooltip: '请输入收信部门ID',
  318. },
  319. 'x-component-props': {
  320. placeholder: '请输入AgentID',
  321. },
  322. },
  323. },
  324. 'x-reactions': {
  325. dependencies: ['provider'],
  326. fulfill: {
  327. state: {
  328. visible: '{{$deps[0]==="dingTalkMessage"}}',
  329. },
  330. },
  331. },
  332. },
  333. dingTalkRobotWebHook: {
  334. type: 'void',
  335. properties: {
  336. messageType: {
  337. title: '消息类型',
  338. 'x-component': 'Select',
  339. 'x-decorator': 'FormItem',
  340. enum: [
  341. { label: 'markdown', value: 'markdown' },
  342. { label: 'text', value: 'text' },
  343. { label: 'link', value: 'link' },
  344. ],
  345. },
  346. markdown: {
  347. type: 'object',
  348. properties: {
  349. title: {
  350. title: '标题',
  351. 'x-component': 'Input',
  352. 'x-decorator': 'FormItem',
  353. },
  354. },
  355. 'x-reactions': {
  356. dependencies: ['.messageType'],
  357. fulfill: {
  358. state: {
  359. visible: '{{$deps[0]==="markdown"}}',
  360. },
  361. },
  362. },
  363. },
  364. link: {
  365. type: 'object',
  366. properties: {
  367. title: {
  368. title: '标题',
  369. 'x-component': 'Input',
  370. 'x-decorator': 'FormItem',
  371. },
  372. '{url:picUrl}': {
  373. title: '图片链接',
  374. 'x-component': 'FUpload',
  375. 'x-decorator': 'FormItem',
  376. 'x-component-props': {
  377. type: 'file',
  378. },
  379. },
  380. messageUrl: {
  381. title: '内容链接',
  382. 'x-component': 'Input',
  383. 'x-decorator': 'FormItem',
  384. },
  385. },
  386. 'x-reactions': {
  387. dependencies: ['.messageType'],
  388. fulfill: {
  389. state: {
  390. visible: '{{$deps[0]==="link"}}',
  391. },
  392. },
  393. },
  394. },
  395. },
  396. 'x-reactions': {
  397. dependencies: ['provider'],
  398. fulfill: {
  399. state: {
  400. visible: '{{$deps[0]==="dingTalkRobotWebHook"}}',
  401. },
  402. },
  403. },
  404. },
  405. },
  406. // 钉钉群机器人配置参数名 类型 说明
  407. // messageType String 钉钉-消息类型 markdown、text、link
  408. // ${messageType} String 钉钉-内容
  409. },
  410. aliyun: {
  411. type: 'void',
  412. properties: {
  413. voice: {
  414. 'x-visible': id === 'voice',
  415. type: 'void',
  416. properties: {
  417. // ttsCode String 语音-模版ID
  418. // calledShowNumbers String 语音-被叫显号
  419. // CalledNumber String 语音-被叫号码
  420. // PlayTimes String 语音-播放次数
  421. ttsCode: {
  422. title: '模版ID',
  423. 'x-component': 'Input',
  424. 'x-decorator': 'FormItem',
  425. 'x-decorator-props': {
  426. tooltip: '请输入模版ID',
  427. },
  428. 'x-component-props': {
  429. placeholder: '请输入模版ID',
  430. },
  431. },
  432. calledShowNumbers: {
  433. title: '被叫号码',
  434. 'x-component': 'Input',
  435. 'x-decorator': 'FormItem',
  436. 'x-decorator-props': {
  437. tooltip: '请输入calledShowNumbers',
  438. },
  439. 'x-component-props': {
  440. placeholder: '请输入calledShowNumbers',
  441. },
  442. },
  443. calledNumber: {
  444. title: '被叫显号',
  445. 'x-component': 'Input',
  446. 'x-decorator': 'FormItem',
  447. 'x-decorator-props': {
  448. tooltip: '请输入CalledNumber',
  449. },
  450. 'x-component-props': {
  451. placeholder: '请输入CalledNumber',
  452. },
  453. },
  454. PlayTimes: {
  455. title: '播放次数',
  456. 'x-component': 'Input',
  457. 'x-decorator': 'FormItem',
  458. 'x-decorator-props': {
  459. tooltip: '请输入PlayTimes',
  460. },
  461. 'x-component-props': {
  462. placeholder: '请输入PlayTimes',
  463. },
  464. },
  465. },
  466. },
  467. sms: {
  468. 'x-visible': id === 'sms',
  469. type: 'void',
  470. properties: {
  471. code: {
  472. title: '模版ID',
  473. 'x-component': 'Input',
  474. 'x-decorator': 'FormItem',
  475. 'x-decorator-props': {
  476. tooltip: '请输入模版ID',
  477. },
  478. 'x-component-props': {
  479. placeholder: '请输入模版ID',
  480. },
  481. },
  482. phoneNumber: {
  483. title: '收信人',
  484. 'x-component': 'Input',
  485. 'x-decorator': 'FormItem',
  486. 'x-decorator-props': {
  487. tooltip: '请输入收信人',
  488. },
  489. 'x-component-props': {
  490. placeholder: '请输入收信人',
  491. },
  492. },
  493. signName: {
  494. title: '签名',
  495. 'x-component': 'Input',
  496. 'x-decorator': 'FormItem',
  497. 'x-decorator-props': {
  498. tooltip: '请输入签名',
  499. },
  500. 'x-component-props': {
  501. placeholder: '请输入签名',
  502. },
  503. },
  504. // code String 短信-模板ID
  505. // signName String 短信-签名
  506. // phoneNumber String 短信-收信人
  507. },
  508. },
  509. },
  510. // ttsCode String 语音-模版ID
  511. // calledShowNumbers String 语音-被叫显号
  512. // CalledNumber String 语音-被叫号码
  513. // PlayTimes String 语音-播放次数
  514. },
  515. email: {
  516. type: 'void',
  517. 'x-visible': id === 'email',
  518. properties: {
  519. // subject String 邮件-模板ID
  520. // sendTo Array 邮件-收件人
  521. // sendTo String 邮件-内容
  522. // attachments String 邮件-附件信息
  523. sendTo: {
  524. 'x-component': 'Input.TextArea',
  525. 'x-decorator': 'FormItem',
  526. title: '收件人',
  527. 'x-decorator-props': {
  528. tip: '请输入收件人邮箱,多个收件人用换行分隔',
  529. },
  530. },
  531. // message: {
  532. // "x-component": 'FBraftEditor',
  533. // "x-decorator": 'FormItem',
  534. // title: '模版内容',
  535. // "x-decorator-props": {
  536. // tip: '请输入收件人邮箱,多个收件人用换行分隔'
  537. // },
  538. // },
  539. attachments: {
  540. 'x-component': 'FUpload',
  541. 'x-decorator': 'FormItem',
  542. title: '附件',
  543. 'x-component-props': {
  544. type: 'file',
  545. placeholder: '请上传文件',
  546. },
  547. },
  548. // subject: {
  549. // title: '模版ID',
  550. // 'x-decorator': 'FormItem',
  551. // 'x-component': 'Input',
  552. // },
  553. },
  554. },
  555. },
  556. },
  557. 'template.message': {
  558. title: '模版内容',
  559. 'x-component': 'Input.TextArea',
  560. 'x-decorator': 'FormItem',
  561. 'x-decorator-props': {
  562. tooltip: '请输入模版内容',
  563. },
  564. 'x-component-props': {
  565. rows: 5,
  566. placeholder: '变量格式:${name};\n 示例:尊敬的${name},${time}有设备触发告警,请注意处理',
  567. },
  568. },
  569. variableDefinitions: {
  570. type: 'array',
  571. title: '变量列表',
  572. 'x-decorator': 'FormItem',
  573. 'x-component': 'ArrayTable',
  574. 'x-component-props': {
  575. pagination: { pageSize: 9999 },
  576. scroll: { x: '100%' },
  577. },
  578. items: {
  579. type: 'object',
  580. properties: {
  581. column1: {
  582. type: 'void',
  583. 'x-component': 'ArrayTable.Column',
  584. 'x-component-props': { title: '变量', width: '120px' },
  585. properties: {
  586. id: {
  587. type: 'string',
  588. 'x-decorator': 'FormItem',
  589. 'x-component': 'PreviewText.Input',
  590. 'x-disabled': true,
  591. },
  592. },
  593. },
  594. column2: {
  595. type: 'void',
  596. 'x-component': 'ArrayTable.Column',
  597. 'x-component-props': { title: '名称' },
  598. properties: {
  599. name: {
  600. type: 'string',
  601. 'x-decorator': 'FormItem',
  602. required: true,
  603. 'x-component': 'Input',
  604. },
  605. },
  606. },
  607. column3: {
  608. type: 'void',
  609. 'x-component': 'ArrayTable.Column',
  610. 'x-component-props': { title: '类型', width: '120px' },
  611. properties: {
  612. type: {
  613. type: 'string',
  614. 'x-decorator': 'FormItem',
  615. 'x-component': 'Select',
  616. required: true,
  617. enum: [
  618. { label: '字符串', value: 'string' },
  619. { label: '时间', value: 'date' },
  620. { label: '数字', value: 'number' },
  621. { label: '文件', value: 'file' },
  622. { label: '其他', value: 'other' },
  623. ],
  624. },
  625. },
  626. },
  627. column4: {
  628. type: 'void',
  629. 'x-component': 'ArrayTable.Column',
  630. 'x-component-props': { title: '格式', width: '150px' },
  631. required: true,
  632. properties: {
  633. format: {
  634. type: 'string',
  635. 'x-decorator': 'FormItem',
  636. 'x-component': 'PreviewText.Input',
  637. },
  638. },
  639. },
  640. },
  641. },
  642. },
  643. description: {
  644. title: '说明',
  645. 'x-decorator': 'FormItem',
  646. 'x-component': 'Input.TextArea',
  647. 'x-component-props': {
  648. rows: 4,
  649. },
  650. },
  651. },
  652. };
  653. return (
  654. <PageContainer>
  655. <Card>
  656. <Row>
  657. <Col span={10}>
  658. <Form className={styles.form} form={form} layout={'vertical'}>
  659. <SchemaField schema={schema} scope={{ getConfig, useAsyncDataSource }} />
  660. <FormButtonGroup.Sticky>
  661. <FormButtonGroup.FormItem>
  662. <Submit onSubmit={handleSave}>保存</Submit>
  663. </FormButtonGroup.FormItem>
  664. </FormButtonGroup.Sticky>
  665. </Form>
  666. </Col>
  667. <Col span={12} push={2}>
  668. 这里是放描述信息的
  669. </Col>
  670. </Row>
  671. </Card>
  672. </PageContainer>
  673. );
  674. });
  675. export default Detail;