Переглянути джерело

fix(notice): add notice doc

lind 3 роки тому
батько
коміт
3626f6dae7

+ 38 - 0
src/components/ProTableCard/CardItems/noticeConfig.tsx

@@ -0,0 +1,38 @@
+import React from 'react';
+import { TableCard } from '@/components';
+import '@/style/common.less';
+import '../index.less';
+import { imgMap } from './noticeTemplate';
+
+export interface NoticeCardProps extends ConfigItem {
+  detail?: React.ReactNode;
+  actions?: React.ReactNode[];
+  avatarSize?: number;
+}
+
+export default (props: NoticeCardProps) => {
+  return (
+    <TableCard actions={props.actions} showStatus={false} showMask={false}>
+      <div className={'pro-table-card-item'}>
+        <div className={'card-item-avatar'}>
+          <img width={88} height={88} src={imgMap[props.type]} alt={props.type} />
+        </div>
+        <div className={'card-item-body'}>
+          <div className={'card-item-header'}>
+            <span className={'card-item-header-name ellipsis'}>{props.name}</span>
+          </div>
+          <div className={'card-item-content'}>
+            <div>
+              <label>通知方式</label>
+              <div className={'ellipsis'}>{props.name}</div>
+            </div>
+            <div>
+              <label>说明</label>
+              <div className={'ellipsis'}>{props.name}</div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </TableCard>
+  );
+};

+ 65 - 0
src/components/ProTableCard/CardItems/noticeTemplate.tsx

@@ -0,0 +1,65 @@
+import React from 'react';
+import { TableCard } from '@/components';
+import '@/style/common.less';
+import '../index.less';
+
+export interface NoticeCardProps extends TemplateItem {
+  detail?: React.ReactNode;
+  actions?: React.ReactNode[];
+  avatarSize?: number;
+}
+
+export const imgMap = {
+  dingTalk: require('/public/images/notice/dingtalk.png'),
+  weixin: require('/public/images/notice/wechat.png'),
+  email: require('/public/images/notice/email.png'),
+  voice: require('/public/images/notice/voice.png'),
+  sms: require('/public/images/notice/sms.png'),
+};
+
+export const typeList = {
+  weixin: {
+    corpMessage: '企业消息',
+    officialMessage: '服务号消息',
+  },
+  dingTalk: {
+    dingTalkMessage: '钉钉消息',
+    dingTalkRobotWebHook: '群机器人消息',
+  },
+  voice: {
+    aliyun: '阿里云语音',
+  },
+  sms: {
+    aliyunSms: '阿里云短信',
+  },
+  email: {
+    embedded: '默认',
+  },
+};
+
+export default (props: NoticeCardProps) => {
+  return (
+    <TableCard actions={props.actions} showStatus={false} showMask={false}>
+      <div className={'pro-table-card-item'}>
+        <div className={'card-item-avatar'}>
+          <img width={88} height={88} src={imgMap[props.type]} alt={props.type} />
+        </div>
+        <div className={'card-item-body'}>
+          <div className={'card-item-header'}>
+            <span className={'card-item-header-name ellipsis'}>{props.name}</span>
+          </div>
+          <div className={'card-item-content'}>
+            <div>
+              <label>通知方式</label>
+              <div className={'ellipsis'}>{typeList[props.type][props.provider] || '暂无'}</div>
+            </div>
+            <div>
+              <label>说明</label>
+              <div className={'ellipsis'}>{props.description}</div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </TableCard>
+  );
+};

+ 10 - 13
src/pages/notice/Config/Debug/index.tsx

@@ -4,7 +4,7 @@ import { createForm } from '@formily/core';
 import { createSchemaField, observer } from '@formily/react';
 import { Form, FormItem, Input, Select } from '@formily/antd';
 import { ISchema } from '@formily/json-schema';
-import { state } from '@/pages/notice/Template';
+import { service, state } from '@/pages/notice/Config';
 import { useLocation } from 'umi';
 import { useAsyncDataSource } from '@/utils/util';
 
@@ -31,18 +31,14 @@ const Debug = observer(() => {
 
   console.log(id, 'testt');
 
-  const getTemplate = () => {};
-  // const getConfig = () =>
-  //   configService
-  //     .queryNoPagingPost({
-  //       terms: [{column: 'type$IN', value: id}],
-  //     })
-  //     .then((resp: any) => {
-  //       return resp.result?.map((item) => ({
-  //         label: item.name,
-  //         value: item.id,
-  //       }));
-  //     });
+  const getTemplate = () => {
+    return service.getTemplate(id).then((resp) => {
+      return resp.result?.map((item: any) => ({
+        label: item.name,
+        value: item.id,
+      }));
+    });
+  };
 
   const schema: ISchema = {
     type: 'object',
@@ -64,6 +60,7 @@ const Debug = observer(() => {
   };
   return (
     <Modal
+      title="调试"
       width="40vw"
       visible={state.debug}
       onCancel={() => (state.debug = false)}

+ 35 - 0
src/pages/notice/Config/Detail/doc/AliyunSms.tsx

@@ -0,0 +1,35 @@
+const AliyunSms = () => {
+  return (
+    <div>
+      <div
+        style={{
+          backgroundColor: '#e9eaeb',
+          height: '30px',
+          display: 'flex',
+          alignItems: 'center',
+        }}
+      >
+        阿里云管理控制台:
+        <a href="https://home.console.aliyun.com">https://home.console.aliyun.com</a>
+      </div>
+      <b>1. 概述</b>
+      <div>
+        通知配置可以结合通知配置为告警消息通知提供支撑。也可以用于系统中其他自定义模块的调用。
+      </div>
+      <b>2.通知配置说明</b>
+      <div>
+        <div>1. RegionID</div>
+        <div>阿里云内部给每台机器设置的唯一编号。请根据购买的阿里云服务器地址进行填写。</div>
+        <div>
+          阿里云地域和可用区对照表地址:https://help.aliyun.com/document_detail/40654.html?spm=a2c6h.13066369.0.0.54a174710O7rWH
+        </div>
+      </div>
+      <b>2、AccesskeyID/Secret</b>
+      <div>
+        <div>用于程序通知方式调用云服务费API的用户标识和秘钥</div>
+        <div>获取路径:“阿里云管理控制台”--“用户头像”--“”--“AccessKey管理”--“查看”</div>
+      </div>
+    </div>
+  );
+};
+export default AliyunSms;

+ 34 - 0
src/pages/notice/Config/Detail/doc/AliyunVoice.tsx

@@ -0,0 +1,34 @@
+const AliyunVoice = () => {
+  return (
+    <div>
+      <div
+        style={{
+          backgroundColor: '#e9eaeb',
+          height: '30px',
+          display: 'flex',
+          alignItems: 'center',
+        }}
+      >
+        阿里云管理控制台:
+        <a href="https://home.console.aliyun.com">https://home.console.aliyun.com</a>
+      </div>
+      <b>1. 概述</b>
+      <div>
+        通知配置可以结合通知配置为告警消息通知提供支撑。也可以用于系统中其他自定义模块的调用。
+      </div>
+      <b>2.通知配置说明</b>
+      <div>
+        <div>1. RegionID</div>
+        <div>
+          阿里云内部给每台机器设置的唯一编号。请根据购买的阿里云服务器阿里云地域和可用区对照表地址:https://help.aliyun.com/document_detail/40654.html?spm=a2c6h.13066369.0.0.54a174710O7rWH获取路径:“微信公众平台”管理后台--“设置与开发”--“基本配置”
+        </div>
+      </div>
+      <b>2、AccesskeyID/Secret</b>
+      <div>
+        <div>用于程序通知方式调用云服务费API的用户标识和秘钥公众号开发者身份的密码</div>
+        <div>获取路径:“阿里云管理控制台”--“用户头像”--“”--“AccessKey管理”--“查看”</div>
+      </div>
+    </div>
+  );
+};
+export default AliyunVoice;

+ 34 - 0
src/pages/notice/Config/Detail/doc/DingTalk.tsx

@@ -0,0 +1,34 @@
+const DingTalk = () => {
+  return (
+    <div>
+      <div
+        style={{
+          backgroundColor: '#e9eaeb',
+          height: '30px',
+          display: 'flex',
+          alignItems: 'center',
+        }}
+      >
+        钉钉管理后台:<a href="https://open-dev.dingtalk.com">https://open-dev.dingtalk.com</a>
+      </div>
+      <b>1. 概述</b>
+      <div>
+        通知配置可以结合通知配置为告警消息通知提供支撑。也可以用于系统中其他自定义模块的调用。
+      </div>
+      <b>2.通知配置说明</b>
+      <div>
+        <div>1. AppKey</div>
+        <div>
+          企业内部应用的唯一身份标识。在钉钉开发者后台创建企业内部应用后,系统会自动生成一对AppKey和AppSecret。
+        </div>
+        <div>获取路径:“钉钉开放平台”--“应用开发”--“应用信息”</div>
+      </div>
+      <b>2. AppSecret</b>
+      <div>
+        <div>钉钉应用对应的调用密钥</div>
+        <div>获取路径:“钉钉开放平台”--“应用开发”--“应用信息”</div>
+      </div>
+    </div>
+  );
+};
+export default DingTalk;

+ 19 - 0
src/pages/notice/Config/Detail/doc/DingTalkRebot.tsx

@@ -0,0 +1,19 @@
+const DingTalkRebot = () => {
+  return (
+    <div>
+      <b>1. 概述</b>
+      <div>
+        通知配置可以结合通知配置为告警消息通知提供支撑。也可以用于系统中其他自定义模块的调用。
+      </div>
+      <b>2.通知配置说明</b>
+      <div>
+        <div> 1. WebHook</div>
+        <div>在钉钉群内每创建一个钉钉群自定义机器人都会产生唯一的WebHook地址。</div>
+        <div>获取路径:“钉钉桌面客户端”--“群设置”--“智能群助手”--“机器人信息”</div>
+        <div>1、登录钉钉桌面客户端,进入群设置</div>
+        <div>2、点击智能群助手,查看机器人信息</div>
+      </div>
+    </div>
+  );
+};
+export default DingTalkRebot;

+ 23 - 0
src/pages/notice/Config/Detail/doc/Email.tsx

@@ -0,0 +1,23 @@
+const Email = () => {
+  return (
+    <div>
+      <b>1. 概述</b>
+      <div>
+        通知配置可以结合通知配置为告警消息通知提供支撑。也可以用于系统中其他自定义模块的调用。
+      </div>
+      <b>2.通知配置说明</b>
+      <div>1. 服务器地址</div>
+      <div>下拉可选择国内常用的邮箱服务配置,也支持手动输入其他地址。</div>
+      <div>
+        系统POP协议。POP允许电子邮件客户端下载服务器上的邮件,但是您在电子邮件客户端的操作(如:移动邮件、标记已读等),这是不会反馈到服务器上。
+      </div>
+      <div>2、发件人</div>
+      <div>用于发送邮件时“发件人“信息的显示</div>
+      <div>3、用户名</div>
+      <div>用该账号进行发送邮件。</div>
+      <div>4、密码</div>
+      <div>用与账号身份认证,认证通过后可通过该账号进行发送邮件。</div>
+    </div>
+  );
+};
+export default Email;

+ 32 - 0
src/pages/notice/Config/Detail/doc/WeixinApp.tsx

@@ -0,0 +1,32 @@
+const WeixinApp = () => {
+  return (
+    <div>
+      <div
+        style={{
+          backgroundColor: '#e9eaeb',
+          height: '30px',
+          display: 'flex',
+          alignItems: 'center',
+        }}
+      >
+        微信公众平台:<a href="https://mp.weixin.qq.com/">https://mp.weixin.qq.com/</a>
+      </div>
+      <b>1. 概述</b>
+      <div>
+        通知配置可以结合通知配置为告警消息通知提供支撑。也可以用于系统中其他自定义模块的调用。
+      </div>
+      <b>2.通知配置说明</b>
+      <div>
+        <div>1. AppID</div>
+        <div>微信服务号的唯一专属编号。</div>
+        <div>获取路径:“微信公众平台”管理后台--“设置与开发”--“基本配置”</div>
+      </div>
+      <b>2. AppSecret</b>
+      <div>
+        <div>公众号开发者身份的密码</div>
+        <div>获取路径:“微信公众平台”管理后台--“设置与开发”--“基本配置”</div>
+      </div>
+    </div>
+  );
+};
+export default WeixinApp;

+ 33 - 0
src/pages/notice/Config/Detail/doc/WeixinCorp.tsx

@@ -0,0 +1,33 @@
+const WeixinCorp = () => {
+  return (
+    <div>
+      <div
+        style={{
+          backgroundColor: '#e9eaeb',
+          height: '30px',
+          display: 'flex',
+          alignItems: 'center',
+        }}
+      >
+        企业微信管理后台:<a href="https://work.weixin.qq.com">https://work.weixin.qq.com</a>
+      </div>
+      <b>1. 概述</b>
+      <div>
+        通知配置可以结合通知配置为告警消息通知提供支撑。也可以用于系统中其他自定义模块的调用。
+      </div>
+      <b>2.通知配置说明</b>
+      <div>
+        <div>1. corpId</div>
+        <div>企业号的唯一专属编号。</div>
+        <div>获取路径:“企业微信”管理后台--“我的企业”--“企业ID”</div>
+      </div>
+
+      <b>2. corpSecret</b>
+      <div>
+        <div>应用的唯一secret,一个企业微信中可以有多个corpSecret</div>
+        <div>获取路径:“企业微信”--“应用与小程序”--“自建应用”中获取</div>
+      </div>
+    </div>
+  );
+};
+export default WeixinCorp;

+ 42 - 16
src/pages/notice/Config/Detail/index.tsx

@@ -2,34 +2,61 @@ import { PageContainer } from '@ant-design/pro-layout';
 import { createForm, onFieldValueChange } from '@formily/core';
 import { Card, Col, Input, message, Row } from 'antd';
 import { ISchema } from '@formily/json-schema';
-import { useEffect, useMemo } from 'react';
+import { useEffect, useMemo, useState } from 'react';
 import { createSchemaField, observer } from '@formily/react';
 import {
+  ArrayTable,
+  Checkbox,
+  Editable,
+  Form,
   FormButtonGroup,
   FormItem,
+  NumberPicker,
+  PreviewText,
+  Radio,
   Select,
+  Space,
   Submit,
   Switch,
-  Form,
-  Radio,
-  ArrayTable,
-  Editable,
-  PreviewText,
-  Space,
-  NumberPicker,
-  Checkbox,
 } from '@formily/antd';
 import styles from './index.less';
-import { service } from '@/pages/notice/Config';
+import { service, state } from '@/pages/notice/Config';
 import { useAsyncDataSource } from '@/utils/util';
 import { useParams } from 'umi';
 import { typeList } from '@/pages/notice';
 import FUpload from '@/components/Upload';
-import { state } from '@/pages/notice/Config';
+import WeixinCorp from '@/pages/notice/Config/Detail/doc/WeixinCorp';
+import WeixinApp from '@/pages/notice/Config/Detail/doc/WeixinApp';
+import DingTalk from '@/pages/notice/Config/Detail/doc/DingTalk';
+import DingTalkRebot from '@/pages/notice/Config/Detail/doc/DingTalkRebot';
+import AliyunSms from '@/pages/notice/Config/Detail/doc/AliyunSms';
+import AliyunVoice from '@/pages/notice/Config/Detail/doc/AliyunVoice';
+import Email from '@/pages/notice/Config/Detail/doc/Email';
+
+export const docMap = {
+  weixin: {
+    corpMessage: <WeixinCorp />,
+    officialMessage: <WeixinApp />,
+  },
+  dingTalk: {
+    dingTalkMessage: <DingTalk />,
+    dingTalkRobotWebHook: <DingTalkRebot />,
+  },
+  voice: {
+    aliyun: <AliyunVoice />,
+  },
+  sms: {
+    aliyunSms: <AliyunSms />,
+  },
+  email: {
+    embedded: <Email />,
+  },
+};
 
 const Detail = observer(() => {
   const { id } = useParams<{ id: string }>();
 
+  const [provider, setProvider] = useState<string>();
   const form = useMemo(
     () =>
       createForm({
@@ -45,10 +72,8 @@ const Detail = observer(() => {
               //   ?.providerInfos.map((i) => ({ label: i.name, value: i.id }));
             });
           });
-          onFieldValueChange('provider', async () => {
-            // eslint-disable-next-line @typescript-eslint/no-use-before-define
-            // currentType = field.value;
-            // await createSchema();
+          onFieldValueChange('provider', async (field) => {
+            setProvider(field.value);
           });
         },
       }),
@@ -316,6 +341,7 @@ const Detail = observer(() => {
       history.back();
     }
   };
+
   return (
     <PageContainer>
       <Card>
@@ -331,7 +357,7 @@ const Detail = observer(() => {
             </Form>
           </Col>
           <Col span={12} push={2}>
-            结果
+            {docMap[id][provider]}
           </Col>
         </Row>
       </Card>

+ 71 - 50
src/pages/notice/Config/index.tsx

@@ -7,21 +7,23 @@ import {
   DeleteOutlined,
   EditOutlined,
   PlusOutlined,
+  UnorderedListOutlined,
 } from '@ant-design/icons';
 import { Button, message, Popconfirm, Tooltip } from 'antd';
-import { useMemo, useRef, useState } from 'react';
+import { useRef, useState } from 'react';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import { downloadObject } from '@/utils/util';
-import { CurdModel } from '@/components/BaseCrud/model';
 import Service from '@/pages/notice/Config/service';
-import { createForm, onFieldValueChange } from '@formily/core';
 import { observer } from '@formily/react';
 import SearchComponent from '@/components/SearchComponent';
-import ProTable from '@jetlinks/pro-table';
 import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
 import { history, useLocation } from 'umi';
 import { model } from '@formily/reactive';
 import moment from 'moment';
+import { ProTableCard } from '@/components';
+import NoticeConfig from '@/components/ProTableCard/CardItems/noticeConfig';
+import Debug from '@/pages/notice/Config/Debug';
+import Log from '@/pages/notice/Config/Log';
 
 export const service = new Service('notifier/config');
 
@@ -36,55 +38,10 @@ export const state = model<{
 const Config = observer(() => {
   const intl = useIntl();
   const actionRef = useRef<ActionType>();
-  const providerRef = useRef<NetworkType[]>([]);
-  const oldTypeRef = useRef();
   const location = useLocation<{ id: string }>();
 
   const id = (location as any).query?.id;
 
-  // const [configSchema, setConfigSchema] = useState<ISchema>({});
-  // const [loading, setLoading] = useState<boolean>(false);
-  const createSchema = async () => {
-    // eslint-disable-next-line @typescript-eslint/no-use-before-define
-    const DForm = form;
-    if (!DForm?.values) return;
-    DForm.setValuesIn('provider', DForm.values.provider);
-  };
-
-  const formEvent = () => {
-    onFieldValueChange('type', async (field, f) => {
-      const type = field.value;
-      if (!type) return;
-      f.setFieldState('provider', (state1) => {
-        state1.value = undefined;
-        state1.dataSource = providerRef.current
-          .find((item) => type === item.id)
-          ?.providerInfos.map((i) => ({ label: i.name, value: i.id }));
-      });
-    });
-    onFieldValueChange('provider', async (field) => {
-      // eslint-disable-next-line @typescript-eslint/no-use-before-define
-      currentType = field.value;
-      await createSchema();
-    });
-  };
-
-  const form = useMemo(
-    () =>
-      createForm({
-        effects: formEvent,
-        initialValues: CurdModel.current,
-      }),
-    [],
-  );
-
-  let currentType = form.values.provider;
-
-  if (oldTypeRef.current !== currentType) {
-    form.clearFormGraph('configuration.*'); // 回收字段模型
-    form.deleteValuesIn('configuration.*');
-  }
-
   const columns: ProColumns<ConfigItem>[] = [
     {
       dataIndex: 'index',
@@ -233,7 +190,7 @@ const Config = observer(() => {
           setParam(data);
         }}
       />
-      <ProTable<ConfigItem>
+      <ProTableCard<ConfigItem>
         search={false}
         params={param}
         columns={columns}
@@ -254,8 +211,72 @@ const Config = observer(() => {
             })}
           </Button>,
         ]}
+        gridColumn={3}
         request={async (params) => service.query(params)}
+        cardRender={(record) => (
+          <NoticeConfig
+            {...record}
+            type={id}
+            actions={[
+              <Button
+                key="edit"
+                onClick={async () => {
+                  // setLoading(true);
+                  state.current = record;
+                  history.push(getMenuPathByParams(MENUS_CODE['notice/Config/Detail'], id));
+                }}
+              >
+                <EditOutlined />
+                编辑
+              </Button>,
+              <Button
+                key="debug"
+                onClick={() => {
+                  state.debug = true;
+                }}
+              >
+                <BugOutlined />
+                调试
+              </Button>,
+              <Button
+                key="export"
+                onClick={() =>
+                  downloadObject(
+                    record,
+                    `通知配置${record.name}-${moment(new Date()).format('YYYY/MM/DD HH:mm:ss')}`,
+                  )
+                }
+              >
+                <ArrowDownOutlined />
+                导出
+              </Button>,
+              <Button
+                key="log"
+                onClick={() => {
+                  state.log = true;
+                }}
+              >
+                <UnorderedListOutlined />
+                通知记录
+              </Button>,
+              <Popconfirm
+                key="delete"
+                title="确认删除?"
+                onConfirm={async () => {
+                  await service.remove(record.id);
+                  actionRef.current?.reset?.();
+                }}
+              >
+                <Button key="delete">
+                  <DeleteOutlined />
+                </Button>
+              </Popconfirm>,
+            ]}
+          />
+        )}
       />
+      <Debug />
+      <Log />
     </PageContainer>
   );
 });

+ 40 - 0
src/pages/notice/Template/Detail/doc/AliyunSms.tsx

@@ -0,0 +1,40 @@
+const AliyunSms = () => {
+  return (
+    <div>
+      <div
+        style={{
+          backgroundColor: '#e9eaeb',
+          height: '30px',
+          display: 'flex',
+          alignItems: 'center',
+        }}
+      >
+        阿里云短信服务平台:
+        <a href="https://dysms.console.aliyun.com">https://dysms.console.aliyun.com</a>
+      </div>
+      <b>1. 概述</b>
+      <div>
+        通知模板结合通知配置为告警消息通知提供支撑。通知模板只能调用同一类型的通知配置服务。
+        使用阿里云短信时需先在阿里云短信服务平台创建短信模板。
+      </div>
+      <b>2.模板配置说明</b>
+
+      <div>
+        <div> 1、绑定配置</div>
+        <div> 绑定通知配置</div>
+        <div> 2、模板ID</div>
+        <div> 阿里云短信对每一条短信模板分配的唯一ID标识</div>
+        <div> 3、收信人</div>
+        <div> 当前仅支持国内手机号,此处若不填,则在模板调试和配置告警通知时手动填写</div>
+        <div> 4、签名</div>
+        <div> 用于短信内容签名信息显示,需在阿里云短信进行配置。</div>
+        <div> 5、变量属性</div>
+        <div>
+          {' '}
+          阿里云短信模板可支持变量,当前阿里云的接口可获取模板内容,但不能自动提取其中的变量,所以需要在当前页面手动设置与阿里云短信模板中一样的变量,否则会导致发送异常。
+        </div>
+      </div>
+    </div>
+  );
+};
+export default AliyunSms;

+ 41 - 0
src/pages/notice/Template/Detail/doc/AliyunVoice.tsx

@@ -0,0 +1,41 @@
+const AliyunVoice = () => {
+  return (
+    <div>
+      <div
+        style={{
+          backgroundColor: '#e9eaeb',
+          height: '30px',
+          display: 'flex',
+          alignItems: 'center',
+        }}
+      >
+        阿里云语音服务平台:
+        <a href="https://account.console.aliyun.com">https://account.console.aliyun.com</a>
+      </div>
+      <b>1. 概述</b>
+      <div>
+        通知模板结合通知配置为告警消息通知提供支撑。通知模板只能调用同一类型的通知配置服务。
+        使用阿里云语音时需先在阿里云语音服务平台创建语音模板。
+      </div>
+      <b>2.模板配置说明</b>
+      <div>
+        <div>1、绑定配置</div>
+        <div> 绑定通知配置</div>
+        <div> 2、模板ID</div>
+        <div> 阿里云语音对每一条语音通知分配的唯一ID标识</div>
+        <div> 3、被叫号码</div>
+        <div> 当前仅支持国内手机号,此处若不填,则在模板调试和配置告警通知时手动填写</div>
+        <div> 4、被叫显号</div>
+        <div> 用户呼叫号码显示,必须是在阿里云购买的号码。</div>
+        <div> 5、播放次数</div>
+        <div> 最多可播放3次</div>
+        <div> 6、变量属性</div>
+        <div>
+          {' '}
+          阿里云语音模板可支持变量,但当前阿里云未提供相关语音模板内容接口,所以需要在当前页面手动设置与阿里云模板中一样的变量,否则会导致发送异常。
+        </div>
+      </div>
+    </div>
+  );
+};
+export default AliyunVoice;

+ 41 - 0
src/pages/notice/Template/Detail/doc/DingTalk.tsx

@@ -0,0 +1,41 @@
+const DingTalk = () => {
+  return (
+    <div>
+      <div
+        style={{
+          backgroundColor: '#e9eaeb',
+          height: '30px',
+          display: 'flex',
+          alignItems: 'center',
+        }}
+      >
+        钉钉开放平台:<a href="https://open-dev.dingtalk.com">https://open-dev.dingtalk.com</a>
+        钉钉管理后台:<a href="https://www.dingtalk.com">https://www.dingtalk.com</a>
+      </div>
+      <b>1. 概述</b>
+      <div>
+        通知模板结合通知配置为告警消息通知提供支撑。通知模板只能调用同一类型的通知配置服务。
+      </div>
+      <b> 2.模板配置说明</b>
+      <div> 1、绑定配置</div>
+      <div> 绑定通知配置</div>
+      <div> 2. Agentid</div>
+      <div> 应用唯一标识</div>
+      <div> 获取路径:“钉钉开发平台”--“应用开发”--“查看应用”</div>
+      <div> 3. 收信人ID、收信部门ID</div>
+      <div>
+        {' '}
+        接收通知的2种方式,2个字段若在此页面都没有填写,则在模板调试和配置告警通知时需要手动填写
+      </div>
+      <div> 收信人ID获取路径:“钉钉管理后台”--“通讯录”--“查看用户”</div>
+      <div> 收信部门ID获取路径:“钉钉管理后台”--“通讯录”--“编辑部门”</div>
+      <div> 4. 模板内容</div>
+      <div>
+        {' '}
+        支持填写带变量的动态模板。变量填写规范示例:${name}
+        。填写动态参数后,可对变量的名称、类型、格式进行配置,以便告警通知时填写。
+      </div>
+    </div>
+  );
+};
+export default DingTalk;

+ 34 - 0
src/pages/notice/Template/Detail/doc/DingTalkRebot.tsx

@@ -0,0 +1,34 @@
+const DingTalkRebot = () => {
+  return (
+    <div>
+      <div
+        style={{
+          backgroundColor: '#e9eaeb',
+          height: '30px',
+          display: 'flex',
+          alignItems: 'center',
+        }}
+      >
+        钉钉管理后台:<a href="https://www.dingtalk.com">https://www.dingtalk.com</a>
+      </div>
+      <b>1. 概述</b>
+      <div>
+        通知模板结合通知配置为告警消息通知提供支撑。通知模板只能调用同一类型的通知配置服务。
+      </div>
+      <b>2.模板配置说明</b>
+      <div>
+        <div> 1、绑定配置</div>
+        <div> 绑定通知配置</div>
+        <div> 2、消息类型</div>
+        <div> 目前支持text、markdown、link3种,对应的发送效果示例,如下图:</div>
+        <div> 3. 模板内容</div>
+        <div>
+          {' '}
+          支持填写带变量的动态模板。变量填写规范示例:${name}
+          。填写动态参数后,可对变量的名称、类型、格式进行配置,以便告警通知时填写。
+        </div>
+      </div>
+    </div>
+  );
+};
+export default DingTalkRebot;

+ 30 - 0
src/pages/notice/Template/Detail/doc/Email.tsx

@@ -0,0 +1,30 @@
+const Email = () => {
+  return (
+    <div>
+      <b>1. 概述</b>
+      <div>
+        通知模板结合通知配置为告警消息通知提供支撑。通知模板只能调用同一类型的通知配置服务。
+        服务器地址支持自定义输入。
+      </div>
+      <b>2.模板配置说明</b>
+      <div>
+        <div> 1. 服务器地址</div>
+        <div>服务器地址支持自定义输入</div>
+        <div> 2. 标题</div>
+        {
+          // @ts-ignore
+          <div>支持输入变量,变量格式${标题}</div>
+        }
+        <div> 2. 收件人</div>
+        <div> 支持录入多个邮箱地址,可填写变量参数。</div>
+        <div> 3. 模板内容</div>
+        <div>
+          {' '}
+          支持填写带变量的动态模板。变量填写规范示例:${name}
+          。填写动态参数后,可对变量的名称、类型、格式进行配置,以便告警通知时填写。
+        </div>
+      </div>
+    </div>
+  );
+};
+export default Email;

+ 32 - 0
src/pages/notice/Template/Detail/doc/WeixinApp.tsx

@@ -0,0 +1,32 @@
+const WeixinApp = () => {
+  return (
+    <div>
+      <div
+        style={{
+          backgroundColor: '#e9eaeb',
+          height: '30px',
+          display: 'flex',
+          alignItems: 'center',
+        }}
+      >
+        微信公众平台:<a href="https://mp.weixin.qq.com/">https://mp.weixin.qq.com/</a>
+      </div>
+      <b>1. 概述</b>
+      <div>
+        通知配置可以结合通知配置为告警消息通知提供支撑。也可以用于系统中其他自定义模块的调用。
+      </div>
+      <b>2.通知配置说明</b>
+      <div>
+        <div>1. AppID</div>
+        <div>微信服务号的唯一专属编号。</div>
+        <div>获取路径:“微信公众平台”管理后台--“设置与开发”--“基本配置”</div>
+      </div>
+      <b>2. AppSecret</b>
+      <div>
+        <div>公众号开发者身份的密码</div>
+        <div>获取路径:“微信公众平台”管理后台--“设置与开发”--“基本配置”</div>
+      </div>
+    </div>
+  );
+};
+export default WeixinApp;

+ 36 - 0
src/pages/notice/Template/Detail/doc/WeixinCorp.tsx

@@ -0,0 +1,36 @@
+const WeixinCorp = () => {
+  return (
+    <div>
+      <div
+        style={{
+          backgroundColor: '#e9eaeb',
+          height: '30px',
+          display: 'flex',
+          alignItems: 'center',
+        }}
+      >
+        企业微信管理后台:<a href="https://work.weixin.qq.com">https://work.weixin.qq.com</a>
+      </div>
+      <b>1. 概述</b>
+      <div>
+        通知模板结合通知配置为告警消息通知提供支撑。通知模板只能调用同一类型的通知配置服务。
+      </div>
+      <b>2.模版配置说明</b>
+      <div>
+        <div> 1、绑定配置</div>
+        <div> 绑定通知配置</div>
+        <div> 2. Agentid</div>
+        <div> 应用唯一标识</div>
+        <div> 获取路径:“企业微信”管理后台--“应用管理”--“应用”--“查看应用”</div>
+        <div> 3. 收信人ID、收信部门ID、标签推送</div>
+        <div>
+          {' '}
+          接收通知的3种方式,3个字段若在此页面都没有填写,则在模板调试和配置告警通知时需要手动填写
+        </div>
+        <div> 收信人ID获取路径:【通讯录】-{'>'}【成员信息】查看成员账号</div>
+        <div> 收信部门ID获取路径:【通讯录】-{'>'}【部门信息】查看部门ID</div>
+      </div>
+    </div>
+  );
+};
+export default WeixinCorp;

+ 41 - 9
src/pages/notice/Template/Detail/index.tsx

@@ -20,7 +20,7 @@ import { createForm, onFieldInit, onFieldValueChange } from '@formily/core';
 import { createSchemaField, observer } from '@formily/react';
 import type { ISchema } from '@formily/json-schema';
 import styles from './index.less';
-import { useEffect, useMemo } from 'react';
+import { useEffect, useMemo, useState } from 'react';
 import FUpload from '@/components/Upload';
 import { useParams } from 'umi';
 import { PageContainer } from '@ant-design/pro-layout';
@@ -29,6 +29,33 @@ import { typeList } from '@/pages/notice';
 import { configService, service, state } from '@/pages/notice/Template';
 import FBraftEditor from '@/components/FBraftEditor';
 import { useAsyncDataSource } from '@/utils/util';
+import WeixinCorp from '@/pages/notice/Template/Detail/doc/WeixinCorp';
+import WeixinApp from '@/pages/notice/Template/Detail/doc/WeixinApp';
+import DingTalk from '@/pages/notice/Template/Detail/doc/DingTalk';
+import DingTalkRebot from '@/pages/notice/Template/Detail/doc/DingTalkRebot';
+import AliyunVoice from '@/pages/notice/Template/Detail/doc/AliyunVoice';
+import AliyunSms from '@/pages/notice/Template/Detail/doc/AliyunSms';
+import Email from '@/pages/notice/Template/Detail/doc/Email';
+
+export const docMap = {
+  weixin: {
+    corpMessage: <WeixinCorp />,
+    officialMessage: <WeixinApp />,
+  },
+  dingTalk: {
+    dingTalkMessage: <DingTalk />,
+    dingTalkRobotWebHook: <DingTalkRebot />,
+  },
+  voice: {
+    aliyun: <AliyunVoice />,
+  },
+  sms: {
+    aliyunSms: <AliyunSms />,
+  },
+  email: {
+    embedded: <Email />,
+  },
+};
 
 const Detail = observer(() => {
   const { id } = useParams<{ id: string }>();
@@ -57,6 +84,7 @@ const Detail = observer(() => {
   const getAliyunSigns = (configId: string) => service.aliyun.getSigns(configId);
   const getAliyunTemplates = (configId: string) => service.aliyun.getTemplates(configId);
 
+  const [provider, setProvider] = useState<string>();
   // 正则提取${}里面的值
   const pattern = /(?<=\$\{).*?(?=\})/g;
   const form = useMemo(
@@ -72,6 +100,10 @@ const Detail = observer(() => {
             console.log(form1);
             ///给FBraftEditor 设置初始值
           });
+          onFieldValueChange('provider', (field) => {
+            const value = field.value;
+            setProvider(value);
+          });
           onFieldValueChange('template.message', (field, form1) => {
             let value = (field as Field).value;
             if (id === 'email' && form1.modified) {
@@ -123,11 +155,6 @@ const Detail = observer(() => {
                 break;
             }
           });
-          // onFieldValueChange('configId', (field, form1) => {
-          //   const value = (field as Field).value;
-          //
-          //
-          // })
         },
       }),
     [id],
@@ -190,7 +217,12 @@ const Detail = observer(() => {
       data.template.message = data.template.message.toHTML();
     }
 
-    const response: any = await service.save(data);
+    let response;
+    if (data.id) {
+      response = await service.update(data);
+    } else {
+      response = await service.save(data);
+    }
 
     if (response?.status === 200) {
       message.success('保存成功');
@@ -754,7 +786,7 @@ const Detail = observer(() => {
                 format: {
                   type: 'string',
                   'x-decorator': 'FormItem',
-                  'x-component': 'PreviewText.Input',
+                  'x-component': 'Input',
                 },
               },
             },
@@ -800,7 +832,7 @@ const Detail = observer(() => {
             </Form>
           </Col>
           <Col span={12} push={2}>
-            这里是放描述信息的
+            {docMap[id][provider]}
           </Col>
         </Row>
       </Card>

+ 66 - 6
src/pages/notice/Template/index.tsx

@@ -1,9 +1,6 @@
 import { PageContainer } from '@ant-design/pro-layout';
 import { useRef, useState } from 'react';
 import type { ActionType, ProColumns } from '@jetlinks/pro-table';
-// import type { Field } from '@formily/core';
-// import { onFieldValueChange } from '@formily/core';
-import ProTable from '@jetlinks/pro-table';
 import {
   ArrowDownOutlined,
   BugOutlined,
@@ -14,11 +11,9 @@ import {
 } from '@ant-design/icons';
 import { Button, Popconfirm, Tooltip } from 'antd';
 import { useIntl } from '@@/plugin-locale/localeExports';
-// import type { ISchema } from '@formily/json-schema';
 import Service from '@/pages/notice/Template/service';
 import ConfigService from '@/pages/notice/Config/service';
 import SearchComponent from '@/components/SearchComponent';
-// import Detail from '@/pages/notice/Template/Detail';
 import { history, useLocation } from 'umi';
 import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
 import { model } from '@formily/reactive';
@@ -26,6 +21,8 @@ import Debug from './Debug';
 import Log from '@/pages/notice/Template/Log';
 import { downloadObject } from '@/utils/util';
 import moment from 'moment';
+import { ProTableCard } from '@/components';
+import NoticeCard from '@/components/ProTableCard/CardItems/noticeTemplate';
 
 export const service = new Service('notifier/template');
 
@@ -166,7 +163,8 @@ const Template = () => {
           setParam(data);
         }}
       />
-      <ProTable<TemplateItem>
+      <ProTableCard<TemplateItem>
+        actionRef={actionRef}
         rowKey="id"
         search={false}
         params={param}
@@ -191,6 +189,68 @@ const Template = () => {
             })}
           </Button>,
         ]}
+        gridColumn={3}
+        cardRender={(record) => (
+          <NoticeCard
+            {...record}
+            type={id}
+            actions={[
+              <Button
+                key="edit"
+                onClick={() => {
+                  state.current = record;
+                  history.push(getMenuPathByParams(MENUS_CODE['notice/Template/Detail'], id));
+                }}
+              >
+                <EditOutlined />
+                编辑
+              </Button>,
+              <Button
+                key="debug"
+                onClick={() => {
+                  state.debug = true;
+                  state.current = record;
+                }}
+              >
+                <BugOutlined />
+                调试
+              </Button>,
+              <Button
+                key="export"
+                onClick={() => {
+                  downloadObject(
+                    record,
+                    `${record.name}-${moment(new Date()).format('YYYY/MM/DD HH:mm:ss')}`,
+                  );
+                }}
+              >
+                <ArrowDownOutlined />
+                导出
+              </Button>,
+              <Button
+                key="log"
+                onClick={() => {
+                  state.log = true;
+                }}
+              >
+                <UnorderedListOutlined />
+                通知记录
+              </Button>,
+              <Popconfirm
+                key="delete"
+                title="确认删除?"
+                onConfirm={async () => {
+                  await service.remove(record.id);
+                  actionRef.current?.reset?.();
+                }}
+              >
+                <Button key="delete">
+                  <DeleteOutlined />
+                </Button>
+              </Popconfirm>,
+            ]}
+          />
+        )}
         request={async (params) => service.query(params)}
       />
       <Debug />

+ 5 - 0
src/pages/notice/Template/service.ts

@@ -13,6 +13,11 @@ class Service extends BaseService<TemplateItem> {
       method: 'GET',
     });
 
+  public batchInsert = () =>
+    request(`${this.uri}/_batch`, {
+      method: 'POST',
+    });
+
   public getConfigs = (data: any) =>
     request(`${SystemConst.API_BASE}/notifier/config/_query`, {
       method: 'POST',

+ 1 - 0
src/pages/notice/Template/typings.d.ts

@@ -7,6 +7,7 @@ type TemplateItem = {
   creatorId: string;
   createTime: number;
   variableDefinitions: any;
+  description: string;
 };
 
 type LogItem = {

+ 172 - 73
yarn.lock

@@ -2778,86 +2778,86 @@
   resolved "https://registry.yarnpkg.com/@formatjs/intl-utils/-/intl-utils-2.3.0.tgz#2dc8c57044de0340eb53a7ba602e59abf80dc799"
   integrity sha512-KWk80UPIzPmUg+P0rKh6TqspRw0G6eux1PuJr+zz47ftMaZ9QDwbGzHZbtzWkl5hgayM/qrKRutllRC7D/vVXQ==
 
-"@formily/antd@2.0.18":
-  version "2.0.18"
-  resolved "https://registry.yarnpkg.com/@formily/antd/-/antd-2.0.18.tgz#b266ae84aede957168b84878696c57171fc5fe4b"
-  integrity sha512-VAj59sB0U5wA7ZUfxVAtMlU08agv6wkdnDkP/ImdRTUCHVcJGrbBUgM3VqKcHAmvlauZxzj0kK+Vl18SpYh4mQ==
+"@formily/antd@2.0.0-rc.17":
+  version "2.0.0-rc.17"
+  resolved "https://registry.yarnpkg.com/@formily/antd/-/antd-2.0.0-rc.17.tgz#fe41ded1c387a2018c292cd37c17e13350ee1dfe"
+  integrity sha512-FLUnq56b43+va3NiH2bhLPSO2BhmAMMxRWvdMX2qfV7s6SG4TQ35hEQkxDPu3YUUKKDv/75kFdgAJIaIZwHcNA==
   dependencies:
     "@ant-design/icons" "^4.0.0"
-    "@formily/core" "2.0.18"
-    "@formily/grid" "2.0.18"
-    "@formily/json-schema" "2.0.18"
-    "@formily/react" "2.0.18"
-    "@formily/reactive" "2.0.18"
-    "@formily/reactive-react" "2.0.18"
-    "@formily/shared" "2.0.18"
+    "@formily/core" "2.0.0-rc.17"
+    "@formily/grid" "2.0.0-rc.17"
+    "@formily/json-schema" "2.0.0-rc.17"
+    "@formily/react" "2.0.0-rc.17"
+    "@formily/reactive" "2.0.0-rc.17"
+    "@formily/reactive-react" "2.0.0-rc.17"
+    "@formily/shared" "2.0.0-rc.17"
+    "@juggle/resize-observer" "^3.3.1"
     classnames "^2.2.6"
     react-sortable-hoc "^1.11.0"
     react-sticky-box "^0.9.3"
 
-"@formily/core@2.0.18":
-  version "2.0.18"
-  resolved "https://registry.yarnpkg.com/@formily/core/-/core-2.0.18.tgz#1fa21a5a3e92fc2b94cf4e49adafb57102fa400b"
-  integrity sha512-ZjTih1T7MXWNIYRawVCo5nJ2ZdFqUwxWiezBFbZX2VajFrkb/5St26h6bYcRLgCAmiuwxu3H8hNmOO3iVOIB5w==
-  dependencies:
-    "@formily/reactive" "2.0.18"
-    "@formily/shared" "2.0.18"
-    "@formily/validator" "2.0.18"
-
-"@formily/grid@2.0.18":
-  version "2.0.18"
-  resolved "https://registry.yarnpkg.com/@formily/grid/-/grid-2.0.18.tgz#65f628001a0ece52f407341d1f2abb45e0f96150"
-  integrity sha512-41X1ovt7cLXPvDy9gBS6EcB8j9ddLNtPHM0Qrs9ylW2XNKz0lkH5raGzzRPZ5Chr9enR5U5yby+bAMkjQb3dsA==
-  dependencies:
-    "@formily/reactive" "2.0.18"
-    "@juggle/resize-observer" "^3.3.1"
-
-"@formily/json-schema@2.0.18":
-  version "2.0.18"
-  resolved "https://registry.yarnpkg.com/@formily/json-schema/-/json-schema-2.0.18.tgz#93561f14a58bf4243a59ba03f0ec74c5e2576597"
-  integrity sha512-ZU7W8Hi670fpCdBJNxx03EjarV8JzvB/AXCMFT2umZkyaCLx0YqxUVDC+/UOigeUVv19H/pA2yLL/rJuoab4+A==
-  dependencies:
-    "@formily/core" "2.0.18"
-    "@formily/reactive" "2.0.18"
-    "@formily/shared" "2.0.18"
-
-"@formily/path@2.0.18":
-  version "2.0.18"
-  resolved "https://registry.yarnpkg.com/@formily/path/-/path-2.0.18.tgz#09e6570a001ca996e86858fddd35e4ea598c728d"
-  integrity sha512-8KkJq9BQPMY6tleQ25BvxMTk0bBdasNwnZWj93w6BXlKMShRkOO3YBCbGxeI3gXQQxws0Q0xX34/fTeccWZVRw==
-
-"@formily/react@2.0.18":
-  version "2.0.18"
-  resolved "https://registry.yarnpkg.com/@formily/react/-/react-2.0.18.tgz#1c81134ed17b2fb841d054fd46eec349e0c65903"
-  integrity sha512-Y1g48icjQcApd+KIdK4sb1d49RGsItyvV9JzQAANTgULkMi2qYJrB6vTkAkT2yipyIe1GAO9tsgYaEvXDyZCtw==
-  dependencies:
-    "@formily/core" "2.0.18"
-    "@formily/json-schema" "2.0.18"
-    "@formily/reactive" "2.0.18"
-    "@formily/reactive-react" "2.0.18"
-    "@formily/shared" "2.0.18"
-    "@formily/validator" "2.0.18"
+"@formily/core@2.0.0-rc.17":
+  version "2.0.0-rc.17"
+  resolved "https://registry.yarnpkg.com/@formily/core/-/core-2.0.0-rc.17.tgz#06880aa6be6f6f822050998662654748bce1627b"
+  integrity sha512-O+iahZipqv1iwqQW9KDLTSo0USVwFrwjUs3v6ToHWgaJHbOFY3rHtUjUBB00QN4cQsc7tANErx8+MawoV/fH8Q==
+  dependencies:
+    "@formily/reactive" "2.0.0-rc.17"
+    "@formily/shared" "2.0.0-rc.17"
+    "@formily/validator" "2.0.0-rc.17"
+
+"@formily/grid@2.0.0-rc.17":
+  version "2.0.0-rc.17"
+  resolved "https://registry.yarnpkg.com/@formily/grid/-/grid-2.0.0-rc.17.tgz#46603919f435cbf71b65f039a4f7a4c98db8cf77"
+  integrity sha512-1boauZbcyKFC+0Pom3xeOzbH5DvCBXs2u9xHklDoaQrxZZLPggtZLlo7Qxyx7zXfyKQRn910WkbzlWFIt2VaDg==
+  dependencies:
+    "@formily/reactive" "2.0.0-rc.17"
+
+"@formily/json-schema@2.0.0-rc.17":
+  version "2.0.0-rc.17"
+  resolved "https://registry.yarnpkg.com/@formily/json-schema/-/json-schema-2.0.0-rc.17.tgz#5638ad56c7c44da89ae33b60b8b1f78f548ed9e4"
+  integrity sha512-x7kqGGdXXS40a3xf7LvbjPvMsCEhUZCshoEfHbQaxKOq4Y+mtUCpFYwJMBr3xsJG6+Yid3IDqflL0yBHn9/SDA==
+  dependencies:
+    "@formily/core" "2.0.0-rc.17"
+    "@formily/reactive" "2.0.0-rc.17"
+    "@formily/shared" "2.0.0-rc.17"
+
+"@formily/path@2.0.0-rc.17":
+  version "2.0.0-rc.17"
+  resolved "https://registry.yarnpkg.com/@formily/path/-/path-2.0.0-rc.17.tgz#40ea317fc8f46fa9908c4407720d8bcfd7e5fae6"
+  integrity sha512-BOFI38udFlYC/q9DYHehwu9FfKOdW1KgIjXp0t/wFlwfiVGQ+B/KyKVSkFPzEocdK5Q3fkujs8kyGLoyJLfSHQ==
+
+"@formily/react@2.0.0-rc.17":
+  version "2.0.0-rc.17"
+  resolved "https://registry.yarnpkg.com/@formily/react/-/react-2.0.0-rc.17.tgz#a88d9fa4b30d08a5ac19fda7ae09841fab64d493"
+  integrity sha512-PLBZYzKHNAb8PSGJrIFBEHA8kB3+j3WN0ls6weo89RXqbcnmkLCmjs6Xa7Cx0KYFLSLkmUZySmrI+Y51w0ASJA==
+  dependencies:
+    "@formily/core" "2.0.0-rc.17"
+    "@formily/json-schema" "2.0.0-rc.17"
+    "@formily/reactive" "2.0.0-rc.17"
+    "@formily/reactive-react" "2.0.0-rc.17"
+    "@formily/shared" "2.0.0-rc.17"
+    "@formily/validator" "2.0.0-rc.17"
     hoist-non-react-statics "^3.3.2"
 
-"@formily/reactive-react@2.0.18":
-  version "2.0.18"
-  resolved "https://registry.yarnpkg.com/@formily/reactive-react/-/reactive-react-2.0.18.tgz#c7c4e60b16a27581c67692dc8ac0973b5d0f150b"
-  integrity sha512-pbnInraFXMy1+CB+W4SEbjlYQ6cQ43GxMuFmNJD5zbXh6NI2lSgflb/R/1XiXuvwqTfAS0qE+u2xI2C4bTCRrg==
+"@formily/reactive-react@2.0.0-rc.17":
+  version "2.0.0-rc.17"
+  resolved "https://registry.yarnpkg.com/@formily/reactive-react/-/reactive-react-2.0.0-rc.17.tgz#fa7d86c83170f183c8180bc6a798797609e8839b"
+  integrity sha512-7rHZ1Az0cpqjLccmrwASJ68b6QxPzJ2mpTLYKf5jbmIINPB5mG0zziFPJLymY15ljAQ6jIyX15viOkDBSkedJA==
   dependencies:
-    "@formily/reactive" "2.0.18"
+    "@formily/reactive" "2.0.0-rc.17"
     hoist-non-react-statics "^3.3.2"
 
-"@formily/reactive@2.0.18":
-  version "2.0.18"
-  resolved "https://registry.yarnpkg.com/@formily/reactive/-/reactive-2.0.18.tgz#3d6fc59f813b05c5f0f56c83ad944df6e110141d"
-  integrity sha512-Xy0RZ+Srnnr1q6ApU6SOReOyhOUMWiL00qpUQUO1XclIgWxcxCQVOzPsBQA9S+MPg2B4Ja30ii7/QcEd554CLg==
+"@formily/reactive@2.0.0-rc.17":
+  version "2.0.0-rc.17"
+  resolved "https://registry.yarnpkg.com/@formily/reactive/-/reactive-2.0.0-rc.17.tgz#fcf752d2c6c14459580d08305efc0d56d9741278"
+  integrity sha512-xFLOFnd+O5t1TRmunlFJHpTTKObSjh7rxJW7IvO42OkrV1o2dUJ7TdDcsaZIHsHg9H/3tMFHzAtfGcprpIcYAA==
 
-"@formily/shared@2.0.18":
-  version "2.0.18"
-  resolved "https://registry.yarnpkg.com/@formily/shared/-/shared-2.0.18.tgz#ebc0b3468dbf7fe6daf168214c238a26f61e2e04"
-  integrity sha512-v+rhavjzSXnMPZX6LpEtpecUBRhw08MrS1peKSNCLX6Kdof8sQq0j13SGNZ2oKuE7F98kDV9j9fllZ6EUGRaKQ==
+"@formily/shared@2.0.0-rc.17":
+  version "2.0.0-rc.17"
+  resolved "https://registry.yarnpkg.com/@formily/shared/-/shared-2.0.0-rc.17.tgz#c6e88df5652f376783130be908e428d3533093b5"
+  integrity sha512-+09L5mOP0MwOk5AOOiphNlZ1PPNYxPI/7pMthulyF3BIDSAJF9Odx3IGvGz+YthzD0fYpi3QX7ly2OuwAA3FhA==
   dependencies:
-    "@formily/path" "2.0.18"
+    "@formily/path" "2.0.0-rc.17"
     camel-case "^4.1.1"
     lower-case "^2.0.1"
     no-case "^3.0.4"
@@ -2865,12 +2865,12 @@
     pascal-case "^3.1.1"
     upper-case "^2.0.1"
 
-"@formily/validator@2.0.18":
-  version "2.0.18"
-  resolved "https://registry.yarnpkg.com/@formily/validator/-/validator-2.0.18.tgz#8fd15547152546b500080d4d1653e0b00ee11980"
-  integrity sha512-G8+w22T8yaojc4Kk9LaIr2sr5YRzm5s9W3rlQYVq/0yIJDmkj1oTCkuGiknnR22Y28REasBVdp93qWQa8o9YHw==
+"@formily/validator@2.0.0-rc.17":
+  version "2.0.0-rc.17"
+  resolved "https://registry.yarnpkg.com/@formily/validator/-/validator-2.0.0-rc.17.tgz#e11bf27a5f5b14bed92dcdc8e5dbf2430965018d"
+  integrity sha512-srjQrfY8ubKaFjldb75lcHhBVgXKNY6Q1R6BvFr2Xogslbkriv2ct752Bix0YC+cFZ4elFwWyiOknSaupnzZRg==
   dependencies:
-    "@formily/shared" "2.0.18"
+    "@formily/shared" "2.0.0-rc.17"
 
 "@hapi/address@^2.1.2":
   version "2.1.4"
@@ -5683,7 +5683,7 @@ antd-mobile@^2.3.1:
     rmc-tabs "~1.2.0"
     rmc-tooltip "~1.0.0"
 
-antd@^4.1.2, antd@^4.1.3, antd@^4.19.5:
+antd@^4.1.2, antd@^4.1.3, antd@^4.18.8:
   version "4.19.5"
   resolved "https://registry.yarnpkg.com/antd/-/antd-4.19.5.tgz#38d08f3e1391a7a69c2ca76f50968bb12ec2ac93"
   integrity sha512-C4H/VJqlVO5iMvHZyiV27R8SbPs4jsOKCGPhDXIHUry/RnUCbMmVeQaPRfUIxSI1NbqDflsuQfevPtz1svyIlg==
@@ -6237,6 +6237,11 @@ balanced-match@^2.0.0:
   resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-2.0.0.tgz#dc70f920d78db8b858535795867bf48f820633d9"
   integrity sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==
 
+base16@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/base16/-/base16-1.0.0.tgz#e297f60d7ec1014a7a971a39ebc8a98c0b681e70"
+  integrity sha1-4pf2DX7BAUp6lxo568ipjAtoHnA=
+
 base64-js@^1.0.2, base64-js@^1.3.1, base64-js@^1.5.1:
   version "1.5.1"
   resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
@@ -9492,6 +9497,18 @@ fb-watchman@^2.0.0:
   dependencies:
     bser "2.1.1"
 
+fbemitter@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/fbemitter/-/fbemitter-3.0.0.tgz#00b2a1af5411254aab416cd75f9e6289bee4bff3"
+  integrity sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==
+  dependencies:
+    fbjs "^3.0.0"
+
+fbjs-css-vars@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8"
+  integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==
+
 fbjs@^0.8.15, fbjs@^0.8.3:
   version "0.8.18"
   resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.18.tgz#9835e0addb9aca2eff53295cd79ca1cfc7c9662a"
@@ -9505,6 +9522,19 @@ fbjs@^0.8.15, fbjs@^0.8.3:
     setimmediate "^1.0.5"
     ua-parser-js "^0.7.30"
 
+fbjs@^3.0.0, fbjs@^3.0.1:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.4.tgz#e1871c6bd3083bac71ff2da868ad5067d37716c6"
+  integrity sha512-ucV0tDODnGV3JCnnkmoszb5lf4bNpzjv80K41wd4k798Etq+UYD0y0TIfalLjZoKgjive6/adkRnszwapiDgBQ==
+  dependencies:
+    cross-fetch "^3.1.5"
+    fbjs-css-vars "^1.0.0"
+    loose-envify "^1.0.0"
+    object-assign "^4.1.0"
+    promise "^7.1.1"
+    setimmediate "^1.0.5"
+    ua-parser-js "^0.7.30"
+
 fd-slicer@~1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e"
@@ -9670,6 +9700,14 @@ flatten@^1.0.2:
   resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.3.tgz#c1283ac9f27b368abc1e36d1ff7b04501a30356b"
   integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==
 
+flux@^4.0.1:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/flux/-/flux-4.0.3.tgz#573b504a24982c4768fdfb59d8d2ea5637d72ee7"
+  integrity sha512-yKAbrp7JhZhj6uiT1FTuVMlIAT1J4jqEyBpFApi1kxpGZCvacMVc/t1pMQyotqHhAgvoE3bNvAykhCo2CLjnYw==
+  dependencies:
+    fbemitter "^3.0.0"
+    fbjs "^3.0.1"
+
 fmin@^0.0.2:
   version "0.0.2"
   resolved "https://registry.yarnpkg.com/fmin/-/fmin-0.0.2.tgz#59bbb40d43ffdc1c94cd00a568c41f95f1973017"
@@ -12552,6 +12590,11 @@ lodash-es@^4.17.15, lodash-es@^4.17.21, lodash-es@^4.2.1:
   resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
   integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
 
+lodash.curry@^4.0.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/lodash.curry/-/lodash.curry-4.1.1.tgz#248e36072ede906501d75966200a86dab8b23170"
+  integrity sha1-JI42By7ekGUB11lmIAqG2riyMXA=
+
 lodash.debounce@^4, lodash.debounce@^4.0.8:
   version "4.0.8"
   resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
@@ -12567,6 +12610,11 @@ lodash.flattendeep@^4.4.0:
   resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2"
   integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=
 
+lodash.flow@^3.3.0:
+  version "3.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.flow/-/lodash.flow-3.5.0.tgz#87bf40292b8cf83e4e8ce1a3ae4209e20071675a"
+  integrity sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=
+
 lodash.get@^4.4.2:
   version "4.4.2"
   resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
@@ -15750,6 +15798,11 @@ puppeteer-core@~1.12.0:
     rimraf "^2.6.1"
     ws "^6.1.0"
 
+pure-color@^1.2.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/pure-color/-/pure-color-1.3.0.tgz#1fe064fb0ac851f0de61320a8bf796836422f33e"
+  integrity sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4=
+
 q@^1.1.2:
   version "1.5.1"
   resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
@@ -16422,6 +16475,16 @@ react-attr-converter@^0.3.1:
   resolved "https://registry.yarnpkg.com/react-attr-converter/-/react-attr-converter-0.3.1.tgz#4a2abf6d907b7ddae4d862dfec80e489ce41ad6e"
   integrity sha512-dSxo2Mn6Zx4HajeCeQNLefwEO4kNtV/0E682R1+ZTyFRPqxDa5zYb5qM/ocqw9Bxr/kFQO0IUiqdV7wdHw+Cdg==
 
+react-base16-styling@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/react-base16-styling/-/react-base16-styling-0.6.0.tgz#ef2156d66cf4139695c8a167886cb69ea660792c"
+  integrity sha1-7yFW1mz0E5aVyKFniGy2nqZgeSw=
+  dependencies:
+    base16 "^1.0.0"
+    lodash.curry "^4.0.1"
+    lodash.flow "^3.3.0"
+    pure-color "^1.2.0"
+
 react-color@2.17.1:
   version "2.17.1"
   resolved "https://registry.yarnpkg.com/react-color/-/react-color-2.17.1.tgz#f114811c83f5d80a1bd1b80466c2f7ddcc58da9d"
@@ -16633,6 +16696,16 @@ react-is@^18.0.0:
   resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.0.0.tgz#026f6c4a27dbe33bf4a35655b9e1327c4e55e3f5"
   integrity sha512-yUcBYdBBbo3QiPsgYDcfQcIkGZHfxOaoE6HLSnr1sPzMhdyxusbfKOSUbSd/ocGi32dxcj366PsTj+5oggeKKw==
 
+react-json-view@^1.21.3:
+  version "1.21.3"
+  resolved "https://registry.yarnpkg.com/react-json-view/-/react-json-view-1.21.3.tgz#f184209ee8f1bf374fb0c41b0813cff54549c475"
+  integrity sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw==
+  dependencies:
+    flux "^4.0.1"
+    react-base16-styling "^0.6.0"
+    react-lifecycles-compat "^3.0.4"
+    react-textarea-autosize "^8.3.2"
+
 react-lifecycles-compat@^3.0.4:
   version "3.0.4"
   resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
@@ -16829,6 +16902,15 @@ react-syntax-highlighter@^15.4.4, react-syntax-highlighter@^15.4.5:
     prismjs "^1.27.0"
     refractor "^3.6.0"
 
+react-textarea-autosize@^8.3.2:
+  version "8.3.3"
+  resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.3.3.tgz#f70913945369da453fd554c168f6baacd1fa04d8"
+  integrity sha512-2XlHXK2TDxS6vbQaoPbMOfQ8GK7+irc2fVK6QFIcC8GOnH3zI/v481n+j1L0WaPVvKxwesnY93fEfH++sus2rQ==
+  dependencies:
+    "@babel/runtime" "^7.10.2"
+    use-composed-ref "^1.0.0"
+    use-latest "^1.0.0"
+
 react-tween-state@^0.1.5:
   version "0.1.5"
   resolved "https://registry.yarnpkg.com/react-tween-state/-/react-tween-state-0.1.5.tgz#e98b066551efb93cb92dd1be14995c2e3deae339"
@@ -20099,11 +20181,28 @@ url@^0.11.0, url@~0.11.0:
     punycode "1.3.2"
     querystring "0.2.0"
 
+use-composed-ref@^1.0.0:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.2.1.tgz#9bdcb5ccd894289105da2325e1210079f56bf849"
+  integrity sha512-6+X1FLlIcjvFMAeAD/hcxDT8tmyrWnbSPMU0EnxQuDLIxokuFzWliXBiYZuGIx+mrAMLBw0WFfCkaPw8ebzAhw==
+
+use-isomorphic-layout-effect@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb"
+  integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==
+
 use-json-comparison@^1.0.3, use-json-comparison@^1.0.5:
   version "1.0.6"
   resolved "https://registry.yarnpkg.com/use-json-comparison/-/use-json-comparison-1.0.6.tgz#a012bbc258ce745db1f56745dc653f575226cb21"
   integrity sha512-xPadt5yMRbEmVfOSGFSMqjjICrq7nLbfSH3rYIXsrtcuFX7PmbYDN/ku8ObBn3v8o/yZelO1OxUS5+5TI3+fUw==
 
+use-latest@^1.0.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/use-latest/-/use-latest-1.2.0.tgz#a44f6572b8288e0972ec411bdd0840ada366f232"
+  integrity sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw==
+  dependencies:
+    use-isomorphic-layout-effect "^1.0.0"
+
 use-media-antd-query@1.0.6:
   version "1.0.6"
   resolved "https://registry.yarnpkg.com/use-media-antd-query/-/use-media-antd-query-1.0.6.tgz#2395fc52a9bc810fa7360bff43eb84609eee1b2f"