index.tsx 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275
  1. import {
  2. ArrayItems,
  3. ArrayTable,
  4. Editable,
  5. Form,
  6. FormButtonGroup,
  7. FormGrid,
  8. FormItem,
  9. Input,
  10. NumberPicker,
  11. PreviewText,
  12. Radio,
  13. Select,
  14. Space,
  15. Submit,
  16. Switch,
  17. } from '@formily/antd';
  18. import type { Field } from '@formily/core';
  19. import {
  20. createForm,
  21. FormPath,
  22. onFieldInit,
  23. onFieldReact,
  24. onFieldValueChange,
  25. registerValidateRules,
  26. } from '@formily/core';
  27. import { createSchemaField, observer } from '@formily/react';
  28. import type { ISchema } from '@formily/json-schema';
  29. import styles from './index.less';
  30. import { useEffect, useMemo, useRef, useState } from 'react';
  31. import FUpload from '@/components/Upload';
  32. import { useParams } from 'umi';
  33. import { PageContainer } from '@ant-design/pro-layout';
  34. import { Card, Col, message, Row } from 'antd';
  35. import { typeList } from '@/pages/notice';
  36. import { configService, service, state } from '@/pages/notice/Template';
  37. import FBraftEditor from '@/components/FBraftEditor';
  38. import { useAsyncDataSource } from '@/utils/util';
  39. import WeixinCorp from '@/pages/notice/Template/Detail/doc/WeixinCorp';
  40. import WeixinApp from '@/pages/notice/Template/Detail/doc/WeixinApp';
  41. import DingTalk from '@/pages/notice/Template/Detail/doc/DingTalk';
  42. import DingTalkRebot from '@/pages/notice/Template/Detail/doc/DingTalkRebot';
  43. import AliyunVoice from '@/pages/notice/Template/Detail/doc/AliyunVoice';
  44. import AliyunSms from '@/pages/notice/Template/Detail/doc/AliyunSms';
  45. import Email from '@/pages/notice/Template/Detail/doc/Email';
  46. import { Store } from 'jetlinks-store';
  47. import FAutoComplete from '@/components/FAutoComplete';
  48. export const docMap = {
  49. weixin: {
  50. corpMessage: <WeixinCorp />,
  51. officialMessage: <WeixinApp />,
  52. },
  53. dingTalk: {
  54. dingTalkMessage: <DingTalk />,
  55. dingTalkRobotWebHook: <DingTalkRebot />,
  56. },
  57. voice: {
  58. aliyun: <AliyunVoice />,
  59. },
  60. sms: {
  61. aliyunSms: <AliyunSms />,
  62. },
  63. email: {
  64. embedded: <Email />,
  65. },
  66. };
  67. const Detail = observer(() => {
  68. const { id } = useParams<{ id: string }>();
  69. const [provider, setProvider] = useState<string>('embedded');
  70. // 正则提取${}里面的值
  71. const pattern = /(?<=\$\{).*?(?=\})/g;
  72. const getConfig = (provider1: string) =>
  73. configService
  74. .queryNoPagingPost({
  75. terms: [
  76. { column: 'type$IN', value: id },
  77. { column: 'provider', value: provider1 },
  78. ],
  79. })
  80. .then((resp: any) => {
  81. return resp.result?.map((item: any) => ({
  82. label: item.name,
  83. value: item.id,
  84. }));
  85. });
  86. //需要复杂联动才可以完成
  87. const getWeixinDept = (configId: string) => service.weixin.getDepartments(configId);
  88. const getWeixinTags = (configId: string) => service.weixin.getTags(configId);
  89. const getWeixinUser = (configId: string) => service.weixin.getUser(configId);
  90. const getDingTalkDept = (configId: string) => service.dingTalk.getDepartments(configId);
  91. const getDingTalkDeptTree = (configId: string) => service.dingTalk.getDepartmentsTree(configId);
  92. const getDingTalkUser = (configId: string) => service.dingTalk.getUser(configId);
  93. const getWeixinOfficialTags = (configId: string) => service.weixin.getOfficialTags(configId);
  94. const getWeixinOfficialTemplates = (configId: string) =>
  95. service.weixin.getOfficialTemplates(configId);
  96. const getAliyunSigns = (configId: string) => service.aliyun.getSigns(configId);
  97. const getAliyunTemplates = (configId: string) => service.aliyun.getTemplates(configId);
  98. const variableDefinitionsRef =
  99. useRef<{ id: string; name: string; type: string; format: string }[]>();
  100. const form = useMemo(
  101. () =>
  102. createForm({
  103. validateFirst: true,
  104. effects() {
  105. onFieldInit('template.message', (field) => {
  106. if (id === 'email') {
  107. field.setComponent(FBraftEditor, {
  108. placeholder:
  109. '变量格式:${name};\n 示例:尊敬的${name},${time}有设备触发告警,请注意处理',
  110. height: '100px',
  111. });
  112. }
  113. });
  114. onFieldValueChange('provider', (field, form1) => {
  115. const value = field.value;
  116. setProvider(value);
  117. if (field.modified) {
  118. form1.setValuesIn('configId', null);
  119. form1.setValuesIn('template', null);
  120. }
  121. // 设置绑定配置的数据
  122. form1.setFieldState('configId', async (state1) => {
  123. state1.dataSource = await getConfig(value);
  124. });
  125. if (value === 'officialMessage') {
  126. form1.setFieldState('template.message', (state5) => {
  127. state5.decoratorProps = {
  128. tooltip: '服务号模版消息内容',
  129. };
  130. });
  131. }
  132. });
  133. onFieldValueChange('configId', (field, form1) => {
  134. const value = field.value;
  135. // 判断provider
  136. if (!value) return;
  137. switch (form1.values.provider) {
  138. case 'corpMessage':
  139. form1.setFieldState('template.toUser', async (state8) => {
  140. state8.dataSource = await getWeixinUser(value);
  141. });
  142. form1.setFieldState('template.toParty', async (state9) => {
  143. state9.dataSource = await getWeixinDept(value);
  144. });
  145. form1.setFieldState('template.toTag', async (state10) => {
  146. state10.dataSource = await getWeixinTags(value);
  147. });
  148. break;
  149. case 'officialMessage':
  150. form1.setFieldState('template.tagid', async (state1) => {
  151. state1.dataSource = await getWeixinOfficialTags(value);
  152. });
  153. form1.setFieldState('template.wxTemplateId', async (state2) => {
  154. const list = await getWeixinOfficialTemplates(value);
  155. Store.set('wxTemplate', list);
  156. state2.dataSource = list;
  157. });
  158. break;
  159. case 'dingTalkMessage':
  160. form1.setFieldState('template.userIdList', async (state3) => {
  161. state3.dataSource = await getDingTalkUser(value);
  162. });
  163. form1.setFieldState('template.departmentIdList', async (state4) => {
  164. const list = await getDingTalkDept(value);
  165. Store.set('wxTemplate', list);
  166. state4.dataSource = list;
  167. });
  168. break;
  169. case 'aliyun':
  170. // 阿里云语音
  171. form1.setFieldState('template.ttsCode', async (state5) => {
  172. const list = await getAliyunTemplates(value);
  173. Store.set('AliyunTemplate', list);
  174. state5.dataSource = list;
  175. });
  176. break;
  177. case 'aliyunSms':
  178. // 阿里云短信
  179. form1.setFieldState('template.code', async (state6) => {
  180. const list = await getAliyunTemplates(value);
  181. Store.set('AliyunTemplate', list);
  182. state6.dataSource = list;
  183. });
  184. form1.setFieldState('template.signName', async (state7) => {
  185. // const list =
  186. // Store.set('AliyunTemplate', list);
  187. state7.dataSource = await getAliyunSigns(value);
  188. });
  189. break;
  190. default:
  191. break;
  192. }
  193. });
  194. onFieldValueChange('template.wxTemplateId', (field, form1) => {
  195. const value = field.value;
  196. // 处理消息模版。
  197. const template = Store.get('wxTemplate');
  198. const data = template?.find((i: { id: any }) => i.id === value);
  199. if (data) {
  200. form1.setFieldState('template.title', (state1) => {
  201. state1.value = data.title;
  202. state1.disabled = true;
  203. });
  204. form1.setFieldState('template.message', (state1) => {
  205. state1.value = data.content;
  206. state1.disabled = true;
  207. });
  208. }
  209. });
  210. onFieldValueChange('template.code', (field, form1) => {
  211. const value = field.value;
  212. const template = Store.get('AliyunTemplate');
  213. const data = template?.find((i: { templateCode: any }) => i.templateCode === value);
  214. if (data) {
  215. form1.setFieldState('template.message', (state1) => {
  216. state1.value = data.templateContent;
  217. state1.disabled = true;
  218. });
  219. }
  220. });
  221. onFieldValueChange('template.*(subject,markdown.title)', (field, form1) => {
  222. const value = (field as Field).value;
  223. const _message = field.query('template.message').value();
  224. const titleList =
  225. (typeof value === 'string' &&
  226. (value + _message)?.match(pattern)?.filter((i: string) => i)) ||
  227. // .map((item: string) => ({id: item, type: 'string', format: '--'}))) ||
  228. [];
  229. // 拼接message的内容
  230. form1.setFieldState('variableDefinitions', (state1) => {
  231. state1.visible = !!titleList && titleList.length > 0;
  232. });
  233. if (form1.modified) {
  234. const oldKey = variableDefinitionsRef.current?.map((i) => i.id);
  235. const newKey = [...new Set(titleList)];
  236. const _result = newKey.map((item) =>
  237. oldKey?.includes(item)
  238. ? variableDefinitionsRef.current?.find((i) => i.id === item)
  239. : {
  240. id: item,
  241. type: 'string',
  242. format: '--',
  243. },
  244. );
  245. form1.setValuesIn('variableDefinitions', _result);
  246. }
  247. });
  248. onFieldValueChange('template.message', (field, form1) => {
  249. const value = (field as Field).value;
  250. const idList =
  251. (typeof value === 'string' && value?.match(pattern)?.filter((i: string) => i)) || [];
  252. if (id === 'email') {
  253. const subject = field.query('template.subject');
  254. const title = subject.value();
  255. const titleList = title?.match(pattern)?.filter((i: string) => i);
  256. // .map((item: string) => ({id: item, type: 'string', format: '--'}));
  257. if (idList && titleList?.length > 0) {
  258. idList.unshift(...titleList);
  259. }
  260. }
  261. const _provider = field.query('provider').value();
  262. if (_provider === 'dingTalkRobotWebHook') {
  263. const title = field.query('template.markdown.title').value();
  264. const titleList = title?.match(pattern)?.filter((i: string) => i);
  265. // .map((item: string) => ({id: item, type: 'string', format: '--'}));
  266. if (idList && titleList?.length > 0) {
  267. idList.unshift(...titleList);
  268. }
  269. }
  270. form1.setFieldState('variableDefinitions', (state1) => {
  271. state1.visible = !!idList && idList.length > 0;
  272. });
  273. if (form1.modified) {
  274. // 获取缓存的KEY;
  275. const oldKey = variableDefinitionsRef.current?.map((i) => i.id);
  276. const newKey = [...new Set(idList)];
  277. const _result = newKey.map((item) =>
  278. oldKey?.includes(item)
  279. ? variableDefinitionsRef.current?.find((i) => i.id === item)
  280. : {
  281. id: item,
  282. type: 'string',
  283. format: '--',
  284. },
  285. );
  286. form1.setValuesIn('variableDefinitions', _result);
  287. }
  288. });
  289. onFieldValueChange('variableDefinitions.*.*', (field) => {
  290. // 缓存编辑后的数据
  291. variableDefinitionsRef.current = field.query('variableDefinitions').value();
  292. });
  293. onFieldReact('variableDefinitions.*.type', (field) => {
  294. const value = (field as Field).value;
  295. const formatPath = FormPath.transform(
  296. field.path,
  297. /\d+/,
  298. (index) => `variableDefinitions.${parseInt(index)}.format`,
  299. );
  300. const format = field.query(formatPath).take() as any;
  301. const fieldModified = field && (field as Field).modified;
  302. if (!format) return;
  303. if (fieldModified) {
  304. format.setValue(undefined);
  305. }
  306. switch (value) {
  307. case 'date':
  308. format.setComponent(FAutoComplete);
  309. format.setDataSource([
  310. { label: 'timestamp', value: 'timestamp' },
  311. { label: 'yyyy-MM-dd', value: 'yyyy-MM-dd' },
  312. { label: 'yyyy-MM-dd HH:mm:ss', value: 'yyyy-MM-dd HH:mm:ss' },
  313. { label: 'yyyy-MM-dd HH:mm:ss EE', value: 'yyyy-MM-dd HH:mm:ss EE' },
  314. { label: 'yyyy-MM-dd HH:mm:ss zzz', value: 'yyyy-MM-dd HH:mm:ss zzz' },
  315. ]);
  316. if (fieldModified) {
  317. format.setValue('timestamp');
  318. }
  319. break;
  320. case 'string':
  321. format.setComponent(PreviewText.Input);
  322. if (fieldModified) {
  323. format.setValue('s%');
  324. }
  325. break;
  326. case 'number':
  327. format.setComponent(Input);
  328. if (fieldModified) {
  329. format.setValue('%.xf');
  330. }
  331. break;
  332. // case 'file':
  333. // format.setComponent(Select);
  334. // format.setDataSource([
  335. // {label: '视频', value: 'video'},
  336. // {label: '图片', value: 'img'},
  337. // {label: '全部', value: 'any'},
  338. // ]);
  339. // format.setValue('any');
  340. // break;
  341. // case 'other':
  342. // format.setComponent(PreviewText.Input);
  343. // format.setValue('--');
  344. // break;
  345. }
  346. });
  347. },
  348. }),
  349. [id],
  350. );
  351. useEffect(() => {
  352. if (state.current) {
  353. form.setValues(state.current);
  354. }
  355. }, []);
  356. const SchemaField = createSchemaField({
  357. components: {
  358. FormItem,
  359. Input,
  360. Select,
  361. Switch,
  362. Radio,
  363. Editable,
  364. PreviewText,
  365. Space,
  366. FUpload,
  367. NumberPicker,
  368. FBraftEditor,
  369. ArrayItems,
  370. FormGrid,
  371. ArrayTable,
  372. FAutoComplete,
  373. },
  374. });
  375. const handleSave = async () => {
  376. const data: TemplateItem = await form.submit();
  377. // dingTalkRobotWebHook
  378. // 提交的时候处理内容
  379. // 钉钉机器人-->dingTalkRobotWebHook
  380. // r如果是text 的话。template.message=>template.text.content
  381. // 如果是markdown 的话。 template.message=>template.markdown.text
  382. // 如果是link的话。 template.message =>template.markdown.text
  383. // 微信服务号: template.message =>template.content
  384. if (data.provider === 'dingTalkRobotWebHook') {
  385. const type = data.template.messageType;
  386. // emplate.messageType
  387. switch (type) {
  388. case 'text':
  389. data.template.text = {
  390. content: data.template.message,
  391. };
  392. // data.template.text.content = data.template.message;
  393. break;
  394. case 'markdown':
  395. data.template.markdown.text = data.template.message;
  396. break;
  397. case 'link':
  398. data.template.link.text = data.template.message;
  399. }
  400. }
  401. if (id === 'email') {
  402. data.provider = 'embedded';
  403. data.template.text = data.template.message;
  404. }
  405. let response;
  406. if (data.id) {
  407. response = await service.update(data);
  408. } else {
  409. response = await service.save(data);
  410. }
  411. if (response?.status === 200) {
  412. message.success('保存成功');
  413. history.back();
  414. }
  415. };
  416. registerValidateRules({
  417. batchCheckEmail(value) {
  418. const regEmail = /^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/;
  419. let error;
  420. value.some((item: string) => {
  421. if (!regEmail.test(item)) {
  422. error = item;
  423. return true;
  424. }
  425. return false;
  426. });
  427. return error ? `${error}邮件格式错误` : '';
  428. },
  429. });
  430. const schema: ISchema = {
  431. type: 'object',
  432. properties: {
  433. name: {
  434. title: '名称',
  435. type: 'string',
  436. 'x-decorator': 'FormItem',
  437. 'x-component': 'Input',
  438. 'x-component-props': {
  439. placeholder: '请输入名称',
  440. },
  441. name: 'name',
  442. 'x-validator': [
  443. {
  444. max: 64,
  445. message: '最多可输入64个字符',
  446. },
  447. {
  448. required: true,
  449. message: '请输入名称',
  450. },
  451. ],
  452. },
  453. type: {
  454. title: '类型',
  455. 'x-value': id,
  456. 'x-hidden': true,
  457. },
  458. provider: {
  459. title: '类型',
  460. type: 'string',
  461. 'x-decorator': 'FormItem',
  462. 'x-component': 'Radio.Group',
  463. 'x-component-props': {
  464. optionType: 'button',
  465. placeholder: '请选择类型',
  466. },
  467. required: true,
  468. 'x-visible': typeList[id]?.length > 0,
  469. 'x-hidden': id === 'email',
  470. 'x-value': typeList[id][0]?.value,
  471. enum: typeList[id] || [],
  472. },
  473. configId: {
  474. title: '绑定配置',
  475. type: 'string',
  476. 'x-decorator': 'FormItem',
  477. 'x-component': 'Select',
  478. 'x-component-props': {
  479. placeholder: '请选择绑定配置',
  480. },
  481. required: true,
  482. 'x-decorator-props': {
  483. tooltip: '使用固定的通知配置来发送此通知模版',
  484. },
  485. 'x-visible': id !== 'email',
  486. },
  487. template: {
  488. type: 'object',
  489. properties: {
  490. weixin: {
  491. type: 'void',
  492. 'x-visible': id === 'weixin',
  493. properties: {
  494. corpMessage: {
  495. type: 'void',
  496. properties: {
  497. agentId: {
  498. title: 'AgentId',
  499. 'x-component': 'Input',
  500. 'x-decorator': 'FormItem',
  501. 'x-decorator-props': {
  502. tooltip: '应用唯一标识',
  503. },
  504. required: true,
  505. 'x-component-props': {
  506. placeholder: '请输入AgentID',
  507. },
  508. },
  509. layout: {
  510. type: 'void',
  511. 'x-decorator': 'FormGrid',
  512. 'x-decorator-props': {
  513. maxColumns: 2,
  514. minColumns: 2,
  515. },
  516. properties: {
  517. toUser: {
  518. title: '收信人',
  519. 'x-component': 'Select',
  520. 'x-decorator': 'FormItem',
  521. 'x-decorator-props': {
  522. tooltip: '如果不填写该字段,将在使用此模版发送通知时进行指定。',
  523. gridSpan: 1,
  524. },
  525. 'x-component-props': {
  526. placeholder: '请选择收信人',
  527. },
  528. },
  529. toParty: {
  530. title: '收信部门',
  531. 'x-component': 'Select',
  532. 'x-decorator': 'FormItem',
  533. 'x-decorator-props': {
  534. tooltip: '如果不填写该字段,将在使用此模版发送通知时进行指定。',
  535. gridSpan: 1,
  536. },
  537. 'x-component-props': {
  538. placeholder: '请选择收信部门',
  539. },
  540. },
  541. },
  542. },
  543. toTag: {
  544. title: '标签推送',
  545. 'x-component': 'Select',
  546. 'x-decorator': 'FormItem',
  547. 'x-decorator-props': {
  548. tooltip:
  549. '本企业微信的标签ID列表,最多支持100个,如果不填写该字段,将在使用此模版发送通知时进行指定',
  550. },
  551. 'x-component-props': {
  552. placeholder: '请输入标签推送,多个标签用,号分隔',
  553. },
  554. },
  555. },
  556. 'x-reactions': {
  557. dependencies: ['provider'],
  558. fulfill: {
  559. state: {
  560. visible: '{{$deps[0]==="corpMessage"}}',
  561. },
  562. },
  563. },
  564. },
  565. officialMessage: {
  566. type: 'void',
  567. properties: {
  568. tagid: {
  569. title: '用户标签',
  570. type: 'string',
  571. 'x-decorator': 'FormItem',
  572. 'x-component': 'Select',
  573. 'x-component-props': {
  574. placeholder: '请选择用户标签',
  575. },
  576. 'x-decorator-props': {
  577. tooltip: '如果不填写该字段,将在使用此模板发送通知时进行指定',
  578. },
  579. },
  580. layout: {
  581. type: 'void',
  582. 'x-decorator': 'FormGrid',
  583. 'x-decorator-props': {
  584. maxColumns: 2,
  585. minColumns: 2,
  586. },
  587. properties: {
  588. wxTemplateId: {
  589. title: '消息模版',
  590. type: 'string',
  591. 'x-decorator': 'FormItem',
  592. 'x-component': 'Select',
  593. 'x-component-props': {
  594. placeholder: '请选择消息模版',
  595. },
  596. 'x-decorator-props': {
  597. gridSpan: 1,
  598. tooltip: '微信公众号中配置的消息模版',
  599. },
  600. },
  601. url: {
  602. title: '模版跳转链接',
  603. type: 'string',
  604. 'x-decorator': 'FormItem',
  605. 'x-component': 'Input',
  606. 'x-component-props': {
  607. placeholder: '请输入模版跳转链接',
  608. },
  609. 'x-decorator-props': {
  610. gridSpan: 1,
  611. tooltip: '用于点击消息后进行页面跳转',
  612. },
  613. },
  614. },
  615. },
  616. toMiniProgram: {
  617. title: '跳转小程序',
  618. type: 'string',
  619. 'x-decorator': 'FormItem',
  620. 'x-component': 'Radio.Group',
  621. 'x-component-props': {
  622. // optionType: 'button'
  623. },
  624. 'x-decorator-props': {
  625. tooltip: '配置后点击通知消息将跳转到对应小程序',
  626. },
  627. default: false,
  628. enum: [
  629. { label: '是', value: true },
  630. { label: '否', value: false },
  631. ],
  632. },
  633. miniProgram: {
  634. type: 'void',
  635. properties: {
  636. layout: {
  637. type: 'void',
  638. 'x-decorator': 'FormGrid',
  639. 'x-decorator-props': {
  640. maxColumns: 2,
  641. minColumns: 2,
  642. },
  643. properties: {
  644. miniProgramId: {
  645. title: '跳转小程序AppId',
  646. type: 'string',
  647. 'x-decorator': 'FormItem',
  648. 'x-component': 'Input',
  649. 'x-component-props': {
  650. placeholder: '请输入跳转小程序AppId',
  651. },
  652. 'x-decorator-props': {
  653. gridSpan: 1,
  654. tooltip: '小程序唯一性id',
  655. },
  656. },
  657. miniProgramPath: {
  658. title: '跳转小程序具体路径',
  659. type: 'string',
  660. 'x-decorator': 'FormItem',
  661. 'x-component': 'Input',
  662. 'x-component-props': {
  663. placeholder: '请输入跳转小程序具体路径',
  664. },
  665. 'x-decorator-props': {
  666. gridSpan: 1,
  667. tooltip: '用于点击消息之后跳转到小程序的具体页面',
  668. },
  669. },
  670. },
  671. },
  672. },
  673. 'x-reactions': {
  674. dependencies: ['.toMiniProgram'],
  675. fulfill: {
  676. state: {
  677. visible: '{{$deps[0]===true}}',
  678. },
  679. },
  680. },
  681. },
  682. title: {
  683. title: '模版标题',
  684. type: 'string',
  685. 'x-decorator': 'FormItem',
  686. 'x-component': 'Input',
  687. 'x-component-props': {
  688. placeholder: '这里是回显内容',
  689. },
  690. 'x-decorator-props': {
  691. tooltip: '服务号消息模版标题',
  692. },
  693. },
  694. },
  695. 'x-reactions': {
  696. dependencies: ['provider'],
  697. fulfill: {
  698. state: {
  699. visible: '{{$deps[0]==="officialMessage"}}',
  700. },
  701. },
  702. },
  703. },
  704. },
  705. },
  706. dingTalk: {
  707. type: 'void',
  708. 'x-visible': id === 'dingTalk',
  709. properties: {
  710. dingTalkMessage: {
  711. type: 'void',
  712. properties: {
  713. agentId: {
  714. title: 'AgentID',
  715. required: true,
  716. 'x-component': 'Input',
  717. 'x-decorator': 'FormItem',
  718. 'x-decorator-props': {
  719. tooltip: '应用唯一标识',
  720. },
  721. 'x-component-props': {
  722. placeholder: '请输入AgentID',
  723. },
  724. },
  725. layout: {
  726. type: 'void',
  727. 'x-decorator': 'FormGrid',
  728. 'x-decorator-props': {
  729. maxColumns: 2,
  730. minColumns: 2,
  731. },
  732. properties: {
  733. userIdList: {
  734. title: '收信人',
  735. 'x-component': 'Select',
  736. 'x-decorator': 'FormItem',
  737. 'x-decorator-props': {
  738. tooltip: '如果不填写该字段,将在使用此模板发送通知时进行指定',
  739. gridSpan: 1,
  740. },
  741. 'x-component-props': {
  742. placeholder: '请选择收信人',
  743. },
  744. 'x-reactions': {
  745. dependencies: ['configId'],
  746. fulfill: {
  747. run: '{{useAsyncDataSource(getDingTalkUser($deps[0]))}}',
  748. },
  749. },
  750. },
  751. departmentIdList: {
  752. title: '收信部门',
  753. 'x-component': 'Select',
  754. 'x-decorator': 'FormItem',
  755. 'x-decorator-props': {
  756. tooltip: '如果不填写该字段,将在使用此模板发送通知时进行指定',
  757. gridSpan: 1,
  758. },
  759. 'x-component-props': {
  760. placeholder: '请选择收信部门',
  761. },
  762. 'x-reactions': {
  763. dependencies: ['configId'],
  764. fulfill: {
  765. run: '{{useAsyncDataSource(getDingTalkDept($deps[0]))}}',
  766. },
  767. },
  768. },
  769. },
  770. },
  771. },
  772. 'x-reactions': {
  773. dependencies: ['provider'],
  774. fulfill: {
  775. state: {
  776. visible: '{{$deps[0]==="dingTalkMessage"}}',
  777. },
  778. },
  779. },
  780. },
  781. dingTalkRobotWebHook: {
  782. type: 'void',
  783. properties: {
  784. messageType: {
  785. title: '消息类型',
  786. 'x-component': 'Select',
  787. 'x-decorator': 'FormItem',
  788. required: true,
  789. 'x-component-props': {
  790. placeholder: '请选择消息类型',
  791. },
  792. enum: [
  793. { label: 'markdown', value: 'markdown' },
  794. { label: 'text', value: 'text' },
  795. { label: 'link', value: 'link' },
  796. ],
  797. },
  798. markdown: {
  799. type: 'object',
  800. properties: {
  801. title: {
  802. required: true,
  803. title: '标题',
  804. 'x-component': 'Input',
  805. 'x-decorator': 'FormItem',
  806. 'x-component-props': {
  807. placeholder: '请输入标题',
  808. },
  809. },
  810. },
  811. 'x-reactions': {
  812. dependencies: ['.messageType'],
  813. fulfill: {
  814. state: {
  815. visible: '{{$deps[0]==="markdown"}}',
  816. },
  817. },
  818. },
  819. },
  820. link: {
  821. type: 'object',
  822. properties: {
  823. title: {
  824. required: true,
  825. title: '标题',
  826. 'x-component': 'Input',
  827. 'x-decorator': 'FormItem',
  828. 'x-component-props': {
  829. placeholder: '请输入标题',
  830. },
  831. },
  832. '{url:picUrl}': {
  833. title: '图片链接',
  834. 'x-component': 'FUpload',
  835. 'x-decorator': 'FormItem',
  836. 'x-component-props': {
  837. type: 'file',
  838. placeholder: '请输入图片链接',
  839. },
  840. },
  841. messageUrl: {
  842. title: '内容链接',
  843. 'x-component': 'Input',
  844. 'x-decorator': 'FormItem',
  845. 'x-component-props': {
  846. placeholder: '请输入内容链接',
  847. },
  848. },
  849. },
  850. 'x-reactions': {
  851. dependencies: ['.messageType'],
  852. fulfill: {
  853. state: {
  854. visible: '{{$deps[0]==="link"}}',
  855. },
  856. },
  857. },
  858. },
  859. },
  860. 'x-reactions': {
  861. dependencies: ['provider'],
  862. fulfill: {
  863. state: {
  864. visible: '{{$deps[0]==="dingTalkRobotWebHook"}}',
  865. },
  866. },
  867. },
  868. },
  869. },
  870. // 钉钉群机器人配置参数名 类型 说明
  871. // messageType String 钉钉-消息类型 markdown、text、link
  872. // ${messageType} String 钉钉-内容
  873. },
  874. aliyun: {
  875. type: 'void',
  876. properties: {
  877. voice: {
  878. 'x-visible': id === 'voice',
  879. type: 'void',
  880. properties: {
  881. layout: {
  882. type: 'void',
  883. 'x-decorator': 'FormGrid',
  884. 'x-decorator-props': {
  885. maxColumns: 2,
  886. minColumns: 2,
  887. },
  888. properties: {
  889. ttsCode: {
  890. title: '模版ID',
  891. 'x-component': 'Select',
  892. 'x-decorator': 'FormItem',
  893. 'x-decorator-props': {
  894. tooltip: '阿里云内部分配的唯一ID标识',
  895. gridSpan: 1,
  896. },
  897. required: true,
  898. 'x-component-props': {
  899. placeholder: '请输入模版ID',
  900. },
  901. },
  902. calledShowNumbers: {
  903. title: '被叫号码',
  904. 'x-component': 'Input',
  905. 'x-decorator': 'FormItem',
  906. 'x-decorator-props': {
  907. tooltip: '仅支持中国大陆号码',
  908. gridSpan: 1,
  909. },
  910. 'x-component-props': {
  911. placeholder: '请输入被叫号码',
  912. },
  913. },
  914. },
  915. },
  916. calledNumber: {
  917. title: '被叫显号',
  918. 'x-component': 'Input',
  919. 'x-decorator': 'FormItem',
  920. 'x-decorator-props': {
  921. tooltip: '必须是已购买的号码,用于呼叫号码显示',
  922. },
  923. 'x-component-props': {
  924. placeholder: '请输入被叫显号',
  925. },
  926. },
  927. PlayTimes: {
  928. title: '播放次数',
  929. 'x-component': 'NumberPicker',
  930. 'x-decorator': 'FormItem',
  931. 'x-decorator-props': {
  932. tooltip: '语音文件的播放次数',
  933. },
  934. default: 1,
  935. 'x-validator': [
  936. {
  937. min: 1,
  938. max: 3,
  939. message: '仅支持1~3次',
  940. },
  941. ],
  942. 'x-component-props': {
  943. placeholder: '请输入播放次数',
  944. },
  945. },
  946. },
  947. },
  948. sms: {
  949. 'x-visible': id === 'sms',
  950. type: 'void',
  951. properties: {
  952. layout: {
  953. type: 'void',
  954. 'x-decorator': 'FormGrid',
  955. 'x-decorator-props': {
  956. maxColumns: 2,
  957. minColumns: 2,
  958. },
  959. properties: {
  960. code: {
  961. title: '模版',
  962. 'x-component': 'Select',
  963. 'x-decorator': 'FormItem',
  964. 'x-decorator-props': {
  965. tooltip: '阿里云短信平台自定义的模版名称',
  966. gridSpan: 1,
  967. },
  968. 'x-component-props': {
  969. placeholder: '请选择模版',
  970. },
  971. 'x-reactions': {
  972. dependencies: ['configId'],
  973. fulfill: {
  974. run: '{{useAsyncDataSource(getAliyunTemplates($deps[0]))}}',
  975. },
  976. },
  977. },
  978. phoneNumber: {
  979. title: '收信人',
  980. 'x-component': 'Input',
  981. 'x-decorator': 'FormItem',
  982. 'x-decorator-props': {
  983. tooltip: '仅支持中国大陆号码',
  984. gridSpan: 1,
  985. },
  986. 'x-validator': ['phone'],
  987. 'x-component-props': {
  988. placeholder: '请输入收信人',
  989. },
  990. },
  991. },
  992. },
  993. signName: {
  994. title: '签名',
  995. 'x-component': 'Select',
  996. 'x-decorator': 'FormItem',
  997. 'x-decorator-props': {
  998. tooltip: '用于短信内容签名信息显示',
  999. },
  1000. 'x-component-props': {
  1001. placeholder: '请输入签名',
  1002. },
  1003. 'x-reactions': {
  1004. dependencies: ['configId'],
  1005. fulfill: {
  1006. run: '{{useAsyncDataSource(getAliyunSigns($deps[0]))}}',
  1007. },
  1008. },
  1009. },
  1010. },
  1011. },
  1012. },
  1013. },
  1014. email: {
  1015. type: 'void',
  1016. 'x-visible': id === 'email',
  1017. properties: {
  1018. subject: {
  1019. 'x-component': 'Input',
  1020. 'x-decorator': 'FormItem',
  1021. title: '标题',
  1022. 'x-decorator-props': {
  1023. tooltip: '邮件标题',
  1024. },
  1025. required: true,
  1026. 'x-component-props': {
  1027. placeholder: '请输入标题',
  1028. },
  1029. },
  1030. sendTo: {
  1031. 'x-component': 'Select',
  1032. 'x-decorator': 'FormItem',
  1033. title: '收件人',
  1034. 'x-decorator-props': {
  1035. tooltip: '多个收件人用换行分隔 \n最大支持1000个号码',
  1036. },
  1037. 'x-component-props': {
  1038. mode: 'tags',
  1039. placeholder: '请输入收件人邮箱,多个收件人用换行分隔',
  1040. },
  1041. 'x-validator': {
  1042. batchCheckEmail: true,
  1043. },
  1044. },
  1045. attachments: {
  1046. type: 'array',
  1047. title: '附件信息',
  1048. 'x-decorator': 'FormItem',
  1049. 'x-component': 'ArrayItems',
  1050. 'x-decorator-props': {
  1051. style: {
  1052. width: '100%',
  1053. },
  1054. tooltip: '附件只输入文件名称将在发送邮件时进行文件上传',
  1055. },
  1056. items: {
  1057. type: 'object',
  1058. 'x-decorator': 'FormGrid',
  1059. 'x-decorator-props': {
  1060. maxColumns: 24,
  1061. minColumns: 24,
  1062. },
  1063. properties: {
  1064. '{url:location,name:name}': {
  1065. 'x-component': 'FUpload',
  1066. 'x-decorator': 'FormItem',
  1067. 'x-decorator-props': {
  1068. style: {
  1069. width: '100%',
  1070. },
  1071. gridSpan: 23,
  1072. },
  1073. 'x-component-props': {
  1074. type: 'file',
  1075. display: 'name',
  1076. placeholder: '请上传文件或输入文件名称',
  1077. },
  1078. },
  1079. remove: {
  1080. type: 'void',
  1081. 'x-decorator': 'FormItem',
  1082. 'x-component': 'ArrayItems.Remove',
  1083. 'x-decorator-props': {
  1084. gridSpan: 1,
  1085. },
  1086. },
  1087. },
  1088. },
  1089. properties: {
  1090. add: {
  1091. type: 'void',
  1092. 'x-component': 'ArrayItems.Addition',
  1093. title: '添加附件',
  1094. },
  1095. },
  1096. },
  1097. },
  1098. },
  1099. },
  1100. },
  1101. 'template.message': {
  1102. title: '模版内容',
  1103. 'x-component': 'Input.TextArea',
  1104. 'x-decorator': 'FormItem',
  1105. 'x-decorator-props': {
  1106. tooltip: '发送的内容,支持录入变量',
  1107. },
  1108. required: true,
  1109. 'x-reactions': {
  1110. dependencies: ['provider'],
  1111. fulfill: {
  1112. state: {
  1113. hidden: '{{$deps[0]==="aliyun"}}',
  1114. disabled: '{{["aliyunSms","aliyun"].includes($deps[0])}}',
  1115. },
  1116. },
  1117. },
  1118. 'x-component-props': {
  1119. rows: 5,
  1120. placeholder: '变量格式:${name};\n 示例:尊敬的${name},${time}有设备触发告警,请注意处理',
  1121. },
  1122. },
  1123. variableDefinitions: {
  1124. type: 'array',
  1125. title: '变量列表',
  1126. 'x-decorator': 'FormItem',
  1127. 'x-component': 'ArrayTable',
  1128. 'x-component-props': {
  1129. pagination: { pageSize: 9999 },
  1130. scroll: { x: '100%' },
  1131. },
  1132. 'x-decorator-props': {
  1133. style: {
  1134. zIndex: 999,
  1135. },
  1136. },
  1137. 'x-visible': false,
  1138. items: {
  1139. type: 'object',
  1140. properties: {
  1141. column1: {
  1142. type: 'void',
  1143. 'x-component': 'ArrayTable.Column',
  1144. 'x-component-props': { title: '变量', width: '120px' },
  1145. properties: {
  1146. id: {
  1147. type: 'string',
  1148. 'x-decorator': 'FormItem',
  1149. 'x-component': 'PreviewText.Input',
  1150. 'x-disabled': true,
  1151. },
  1152. },
  1153. },
  1154. column2: {
  1155. type: 'void',
  1156. 'x-component': 'ArrayTable.Column',
  1157. 'x-component-props': { title: '名称' },
  1158. properties: {
  1159. name: {
  1160. type: 'string',
  1161. 'x-decorator': 'FormItem',
  1162. required: true,
  1163. 'x-component': 'Input',
  1164. },
  1165. },
  1166. },
  1167. column3: {
  1168. type: 'void',
  1169. 'x-component': 'ArrayTable.Column',
  1170. 'x-component-props': { title: '类型', width: '120px' },
  1171. properties: {
  1172. type: {
  1173. type: 'string',
  1174. 'x-decorator': 'FormItem',
  1175. 'x-component': 'Select',
  1176. required: true,
  1177. enum: [
  1178. { label: '字符串', value: 'string' },
  1179. { label: '时间', value: 'date' },
  1180. { label: '数字', value: 'number' },
  1181. ],
  1182. },
  1183. },
  1184. },
  1185. column4: {
  1186. type: 'void',
  1187. 'x-component': 'ArrayTable.Column',
  1188. 'x-component-props': { title: '格式', width: '300px' },
  1189. required: true,
  1190. properties: {
  1191. format: {
  1192. type: 'string',
  1193. 'x-decorator': 'FormItem',
  1194. 'x-component': 'Input',
  1195. },
  1196. },
  1197. },
  1198. },
  1199. },
  1200. },
  1201. description: {
  1202. title: '说明',
  1203. 'x-decorator': 'FormItem',
  1204. 'x-component': 'Input.TextArea',
  1205. 'x-component-props': {
  1206. rows: 4,
  1207. },
  1208. },
  1209. },
  1210. };
  1211. return (
  1212. <PageContainer>
  1213. <Card>
  1214. <Row>
  1215. <Col span={10}>
  1216. <Form className={styles.form} form={form} layout={'vertical'}>
  1217. <SchemaField
  1218. schema={schema}
  1219. scope={{
  1220. getConfig,
  1221. getDingTalkDept,
  1222. getDingTalkDeptTree,
  1223. getDingTalkUser,
  1224. getWeixinDept,
  1225. getWeixinTags,
  1226. getWeixinUser,
  1227. getAliyunSigns,
  1228. getAliyunTemplates,
  1229. useAsyncDataSource,
  1230. getWeixinOfficialTags,
  1231. getWeixinOfficialTemplates,
  1232. }}
  1233. />
  1234. <FormButtonGroup.Sticky>
  1235. <FormButtonGroup.FormItem>
  1236. <Submit onSubmit={handleSave}>保存</Submit>
  1237. </FormButtonGroup.FormItem>
  1238. </FormButtonGroup.Sticky>
  1239. </Form>
  1240. </Col>
  1241. <Col span={12} push={2}>
  1242. {docMap[id][provider]}
  1243. </Col>
  1244. </Row>
  1245. </Card>
  1246. </PageContainer>
  1247. );
  1248. });
  1249. export default Detail;