Pārlūkot izejas kodu

fix: 修改阿里云文档

sun-chaochao 3 gadi atpakaļ
vecāks
revīzija
b6647a2add

BIN
public/images/northbound/doc1.png


BIN
public/images/northbound/doc2.png


BIN
public/images/northbound/doc3.png


+ 37 - 0
src/pages/link/AccessConfig/Detail/Access/data.ts

@@ -0,0 +1,37 @@
+const MetworkTypeMapping = new Map();
+MetworkTypeMapping.set('websocket-server', 'WEB_SOCKET_SERVER');
+MetworkTypeMapping.set('http-server-gateway', 'HTTP_SERVER');
+MetworkTypeMapping.set('udp-device-gateway', 'UDP');
+MetworkTypeMapping.set('coap-server-gateway', 'COAP_SERVER');
+MetworkTypeMapping.set('mqtt-client-gateway', 'MQTT_CLIENT');
+MetworkTypeMapping.set('mqtt-server-gateway', 'MQTT_SERVER');
+MetworkTypeMapping.set('tcp-server-gateway', 'TCP_SERVER');
+
+const ProcotoleMapping = new Map();
+ProcotoleMapping.set('websocket-server', 'WebSocket');
+ProcotoleMapping.set('http-server-gateway', 'HTTP');
+ProcotoleMapping.set('udp-device-gateway', 'UDP');
+ProcotoleMapping.set('coap-server-gateway', 'COAP');
+ProcotoleMapping.set('mqtt-client-gateway', 'MQTT');
+ProcotoleMapping.set('mqtt-server-gateway', 'MQTT');
+ProcotoleMapping.set('tcp-server-gateway', 'TCP');
+ProcotoleMapping.set('child-device', '');
+
+const descriptionList = {
+  'udp-device-gateway':
+    'UDP可以让设备无需建立连接就可以与平台传输数据。在允许一定程度丢包的情况下,提供轻量化且简单的连接。',
+  'tcp-server-gateway':
+    'TCP服务是一种面向连接的、可靠的、基于字节流的传输层通信协议。设备可通过TCP服务与平台进行长链接,实时更新状态并发送消息。可自定义多种粘拆包规则,处理传输过程中可能发生的粘拆包问题。',
+  'websocket-server':
+    'WebSocket是一种在单个TCP连接上进行全双工通信的协议,允许服务端主动向客户端推送数据。设备通过WebSocket服务与平台进行长链接,实时更新状态并发送消息,且可以发布订阅消息',
+  'mqtt-client-gateway':
+    'MQTT是ISO 标准下基于发布/订阅范式的消息协议,具有轻量、简单、开放和易于实现的特点。平台使用指定的ID接入其他远程平台,订阅消息。也可添加用户名和密码校验。可设置最大消息长度。可统一设置共享的订阅前缀。',
+  'http-server-gateway':
+    'HTTP服务是一个简单的请求-响应的基于TCP的无状态协议。设备通过HTTP服务与平台进行灵活的短链接通信,仅支持设备和平台之间单对单的请求-响应模式',
+  'mqtt-server-gateway':
+    'MQTT是ISO 标准下基于发布/订阅范式的消息协议,具有轻量、简单、开放和易于实现的特点。提供MQTT的服务端,以供设备以长链接的方式接入平台。设备使用唯一的ID,也可添加用户名和密码校验。可设置最大消息长度。',
+  'coap-server-gateway':
+    'CoAP是针对只有少量的内存空间和有限的计算能力提供的一种基于UDP的协议。便于低功耗或网络受限的设备与平台通信,仅支持设备和平台之间单对单的请求-响应模式。',
+};
+
+export { MetworkTypeMapping, ProcotoleMapping, descriptionList };

+ 27 - 30
src/pages/link/AccessConfig/Detail/Access/index.tsx

@@ -23,6 +23,7 @@ import { ExclamationCircleFilled } from '@ant-design/icons';
 import TitleComponent from '@/components/TitleComponent';
 import { PermissionButton } from '@/components';
 import { useDomFullHeight } from '@/hooks';
+import { MetworkTypeMapping, ProcotoleMapping, descriptionList } from './data';
 
 interface Props {
   change: () => void;
@@ -45,25 +46,6 @@ const Access = (props: Props) => {
   const protocolPermission = PermissionButton.usePermission('link/Protocol').permission;
   const [steps, setSteps] = useState<string[]>(['网络组件', '消息协议', '完成']);
 
-  const MetworkTypeMapping = new Map();
-  MetworkTypeMapping.set('websocket-server', 'WEB_SOCKET_SERVER');
-  MetworkTypeMapping.set('http-server-gateway', 'HTTP_SERVER');
-  MetworkTypeMapping.set('udp-device-gateway', 'UDP');
-  MetworkTypeMapping.set('coap-server-gateway', 'COAP_SERVER');
-  MetworkTypeMapping.set('mqtt-client-gateway', 'MQTT_CLIENT');
-  MetworkTypeMapping.set('mqtt-server-gateway', 'MQTT_SERVER');
-  MetworkTypeMapping.set('tcp-server-gateway', 'TCP_SERVER');
-
-  const ProcotoleMapping = new Map();
-  ProcotoleMapping.set('websocket-server', 'WebSocket');
-  ProcotoleMapping.set('http-server-gateway', 'HTTP');
-  ProcotoleMapping.set('udp-device-gateway', 'UDP');
-  ProcotoleMapping.set('coap-server-gateway', 'COAP');
-  ProcotoleMapping.set('mqtt-client-gateway', 'MQTT');
-  ProcotoleMapping.set('mqtt-server-gateway', 'MQTT');
-  ProcotoleMapping.set('tcp-server-gateway', 'TCP');
-  ProcotoleMapping.set('child-device', '');
-
   const queryNetworkList = (id: string, params?: any) => {
     service.getNetworkList(MetworkTypeMapping.get(id), params).then((resp) => {
       if (resp.status === 200) {
@@ -331,7 +313,11 @@ const Access = (props: Props) => {
                         setNetworkCurrent(item.id);
                       }}
                     >
-                      <div className={styles.title}>{item.name || '--'}</div>
+                      <div className={styles.title}>
+                        <Tooltip placement="topLeft" title={item.name}>
+                          {item.name}
+                        </Tooltip>
+                      </div>
                       <div className={styles.cardContent}>
                         <div
                           style={{
@@ -349,7 +335,14 @@ const Access = (props: Props) => {
                             </div>
                           ))}
                         </div>
-                        <div className={styles.desc}>{item?.description || '--'}</div>
+                        <div className={styles.desc}>
+                          <Tooltip
+                            placement="topLeft"
+                            title={item?.description || descriptionList[props.provider?.id]}
+                          >
+                            {item?.description || descriptionList[props.provider?.id]}
+                          </Tooltip>
+                        </div>
                       </div>
                     </Card>
                   </Col>
@@ -444,8 +437,14 @@ const Access = (props: Props) => {
                       }}
                     >
                       <div style={{ height: '45px' }}>
-                        <div className={styles.title}>{item.name || '--'}</div>
-                        <div className={styles.desc}>{item.description || '--'}</div>
+                        <div className={styles.title}>
+                          <Tooltip title={item.name}>{item.name}</Tooltip>
+                        </div>
+                        <div className={styles.desc}>
+                          <Tooltip placement="topLeft" title={item.description}>
+                            {item.description}
+                          </Tooltip>
+                        </div>
                       </div>
                     </Card>
                   </Col>
@@ -467,7 +466,6 @@ const Access = (props: Props) => {
                           const tab: any = window.open(`${origin}/#${url}?save=true`);
                           tab!.onTabSaveSuccess = (resp: any) => {
                             if (resp.status === 200) {
-                              console.log(props.provider);
                               queryProcotolList(props.provider?.id);
                             }
                           };
@@ -574,17 +572,17 @@ const Access = (props: Props) => {
               <div className={styles.config}>
                 <div className={styles.item}>
                   <div className={styles.title}>接入方式</div>
-                  <div className={styles.context}>{props.provider?.name || '--'}</div>
-                  <div className={styles.context}>{props.provider?.description || '--'}</div>
+                  <div className={styles.context}>{props.provider?.name}</div>
+                  <div className={styles.context}>{props.provider?.description}</div>
                 </div>
                 <div className={styles.item}>
                   <div className={styles.title}>消息协议</div>
                   <div className={styles.context}>
-                    {procotolList.find((i) => i.id === procotolCurrent)?.name || '--'}
+                    {procotolList.find((i) => i.id === procotolCurrent)?.name}
                   </div>
                   {config?.document && (
                     <div className={styles.context}>
-                      {<ReactMarkdown>{config?.document}</ReactMarkdown> || '--'}
+                      {<ReactMarkdown>{config?.document}</ReactMarkdown>}
                     </div>
                   )}
                 </div>
@@ -597,12 +595,11 @@ const Access = (props: Props) => {
                             <Badge
                               color={item.health === -1 ? 'red' : 'green'}
                               text={item.address}
-                              style={{ marginLeft: '20px' }}
                             />
                           </div>
                         ),
                       )
-                    : '--'}
+                    : ''}
                 </div>
                 {config?.routes && config?.routes?.length > 0 && (
                   <div className={styles.item}>

+ 35 - 0
src/pages/media/Cascade/Save/index.less

@@ -0,0 +1,35 @@
+.doc {
+  height: 1050px;
+  padding: 24px;
+  overflow-y: auto;
+  color: rgba(#000, 0.8);
+  font-size: 14px;
+  background-color: #fafafa;
+
+  .url {
+    padding: 8px 16px;
+    color: #2f54eb;
+    background-color: rgba(#a7bdf7, 0.2);
+  }
+
+  h1 {
+    margin: 16px 0;
+    color: rgba(#000, 0.85);
+    font-weight: bold;
+    font-size: 14px;
+
+    &:first-child {
+      margin-top: 0;
+    }
+  }
+
+  h2 {
+    margin: 6px 0;
+    color: rgba(0, 0, 0, 0.8);
+    font-size: 14px;
+  }
+
+  .image {
+    margin: 16px 0;
+  }
+}

+ 322 - 252
src/pages/media/Cascade/Save/index.tsx

@@ -1,5 +1,5 @@
 import TitleComponent from '@/components/TitleComponent';
-import { QuestionCircleOutlined } from '@ant-design/icons';
+import { InfoCircleFilled, QuestionCircleOutlined } from '@ant-design/icons';
 import { PageContainer } from '@ant-design/pro-layout';
 import {
   Button,
@@ -13,6 +13,8 @@ import {
   Row,
   Select,
   Tooltip,
+  Image,
+  Alert,
 } from 'antd';
 import SipComponent from '@/components/SipComponent';
 import SipSelectComponent from '@/components/SipSelectComponent';
@@ -20,6 +22,7 @@ import { testIP } from '@/utils/util';
 import { useEffect, useState } from 'react';
 import { service } from '../index';
 import { useLocation } from 'umi';
+import styles from './index.less';
 
 const Save = () => {
   const location: any = useLocation();
@@ -99,262 +102,329 @@ const Save = () => {
     return Promise.reject(new Error('请输入1~10000之间的数字'));
   };
 
+  const img1 = require('/public/images/northbound/doc1.png');
+  const img2 = require('/public/images/northbound/doc2.png');
+  const img3 = require('/public/images/northbound/doc3.png');
+
   return (
     <PageContainer>
       <Card>
-        <Form
-          name="cascade"
-          layout="vertical"
-          form={form}
-          initialValues={{
-            proxyStream: false,
-            sipConfigs: {
-              transport: 'UDP',
-              keepaliveInterval: 60,
-              registerInterval: 3000,
-            },
-          }}
-          onFinish={async (values: any) => {
-            const sipConfigs = {
-              ...values.sipConfigs,
-              remoteAddress: values.sipConfigs.public.host,
-              remotePort: values.sipConfigs.public.port,
-              host: values.sipConfigs.local.host,
-              port: values.sipConfigs.local.port,
-              publicHost: values.sipConfigs.remotePublic.host,
-              publicPort: values.sipConfigs.remotePublic.port,
-            };
-            delete values.sipConfigs;
-            delete sipConfigs.public;
-            delete sipConfigs.local;
-            const param = { ...values, sipConfigs: [sipConfigs] };
-            let resp = undefined;
-            if (id) {
-              resp = await service.update({ ...param, id });
-            } else {
-              resp = await service.save(param);
-            }
-            if (resp && resp.status === 200) {
-              message.success('操作成功!');
-              history.back();
-            }
-          }}
-        >
-          <Row gutter={24}>
-            <TitleComponent data={'基本信息'} />
-            <Col span={12}>
-              <Form.Item
-                label="名称"
-                name="name"
-                rules={[{ required: true, message: '请输入名称' }]}
-              >
-                <Input placeholder="请输入名称" />
-              </Form.Item>
-            </Col>
-            <Col span={12}>
-              <Form.Item
-                label={<span>代理视频流</span>}
-                name="proxyStream"
-                rules={[{ required: true, message: '请选择代理视频流' }]}
-              >
-                <Radio.Group optionType="button" buttonStyle="solid">
-                  <Radio.Button value={true}>启用</Radio.Button>
-                  <Radio.Button value={false}>禁用</Radio.Button>
-                </Radio.Group>
-              </Form.Item>
-            </Col>
-            <TitleComponent data={'信令服务配置'} />
-            <Col span={12}>
-              <Form.Item
-                label={
-                  <span>
-                    集群节点
-                    <Tooltip title="使用此集群节点级联到上级平台">
-                      <QuestionCircleOutlined />
-                    </Tooltip>
-                  </span>
+        <Row gutter={24}>
+          <Col span={12}>
+            <Form
+              name="cascade"
+              layout="vertical"
+              form={form}
+              initialValues={{
+                proxyStream: false,
+                sipConfigs: {
+                  transport: 'UDP',
+                  keepaliveInterval: 60,
+                  registerInterval: 3000,
+                },
+              }}
+              onFinish={async (values: any) => {
+                const sipConfigs = {
+                  ...values.sipConfigs,
+                  remoteAddress: values.sipConfigs.public.host,
+                  remotePort: values.sipConfigs.public.port,
+                  host: values.sipConfigs.local.host,
+                  port: values.sipConfigs.local.port,
+                  publicHost: values.sipConfigs.remotePublic.host,
+                  publicPort: values.sipConfigs.remotePublic.port,
+                };
+                delete values.sipConfigs;
+                delete sipConfigs.public;
+                delete sipConfigs.local;
+                const param = { ...values, sipConfigs: [sipConfigs] };
+                let resp = undefined;
+                if (id) {
+                  resp = await service.update({ ...param, id });
+                } else {
+                  resp = await service.save(param);
                 }
-                name={['sipConfigs', 'clusterNodeId']}
-                rules={[{ required: true, message: '请选择集群节点' }]}
-              >
-                <Select placeholder="请选择集群节点">
-                  {clusters.map((item) => (
-                    <Select.Option key={item.id} value={item.id}>
-                      {item.name}
-                    </Select.Option>
-                  ))}
-                </Select>
-              </Form.Item>
-            </Col>
-            <Col span={12}>
-              <Form.Item
-                label="信令名称"
-                name={['sipConfigs', 'name']}
-                rules={[{ required: true, message: '请输入信令名称' }]}
-              >
-                <Input placeholder="请输入信令名称" />
-              </Form.Item>
-            </Col>
-            <Col span={24}>
-              <Form.Item
-                label="上级SIP ID"
-                name={['sipConfigs', 'sipId']}
-                rules={[{ required: true, message: '请输入上级SIP ID' }]}
-              >
-                <Input placeholder="请输入上级SIP ID" />
-              </Form.Item>
-            </Col>
-            <Col span={12}>
-              <Form.Item
-                label="上级SIP域"
-                name={['sipConfigs', 'domain']}
-                rules={[{ required: true, message: '请输入上级平台SIP域' }]}
-              >
-                <Input placeholder="请输入上级平台SIP域" />
-              </Form.Item>
-            </Col>
-            <Col span={12}>
-              <Form.Item
-                label="上级SIP 地址"
-                name={['sipConfigs', 'public']}
-                rules={[{ required: true, message: '请输入上级SIP 地址' }, { validator: checkSIP }]}
-              >
-                <SipComponent />
-              </Form.Item>
-            </Col>
-            <Col span={24}>
-              <Form.Item
-                label="本地SIP ID"
-                name={['sipConfigs', 'localSipId']}
-                rules={[{ required: true, message: '请输入网关侧的SIP ID' }]}
-              >
-                <Input placeholder="网关侧的SIP ID" />
-              </Form.Item>
-            </Col>
-            <Col span={12}>
-              <Form.Item
-                label={
-                  <span>
-                    SIP本地地址
-                    <Tooltip title="使用指定的网卡和端口进行请求">
-                      <QuestionCircleOutlined />
-                    </Tooltip>
-                  </span>
+                if (resp && resp.status === 200) {
+                  message.success('操作成功!');
+                  history.back();
                 }
-                name={['sipConfigs', 'local']}
-                rules={[
-                  { required: true, message: '请输入SIP本地地址' },
-                  { validator: checkLocalSIP },
-                ]}
-              >
-                <SipSelectComponent data={list} transport={transport} />
-              </Form.Item>
-            </Col>
-            <Col span={12}>
-              <Form.Item
-                label="SIP远程地址"
-                name={['sipConfigs', 'remotePublic']}
-                rules={[{ required: true, message: '请输入SIP远程地址' }, { validator: checkSIP }]}
-              >
-                <SipComponent />
-              </Form.Item>
-            </Col>
-            <Col span={24}>
-              <Form.Item
-                label="传输协议"
-                name={['sipConfigs', 'transport']}
-                rules={[{ required: true, message: '请选择传输协议' }]}
-              >
-                <Radio.Group
-                  optionType="button"
-                  buttonStyle="solid"
-                  onChange={(e) => {
-                    setTransport(e.target.value);
-                  }}
-                >
-                  <Radio.Button value="UDP">UDP</Radio.Button>
-                  <Radio.Button value="TCP">TCP</Radio.Button>
-                </Radio.Group>
-              </Form.Item>
-            </Col>
-            <Col span={12}>
-              <Form.Item
-                label="用户"
-                name={['sipConfigs', 'user']}
-                rules={[{ required: true, message: '请输入用户' }]}
-              >
-                <Input placeholder="请输入用户" />
-              </Form.Item>
-            </Col>
-            <Col span={12}>
-              <Form.Item
-                label="接入密码"
-                name={['sipConfigs', 'password']}
-                rules={[{ required: true, message: '请输入接入密码' }]}
-              >
-                <Input.Password placeholder="请输入接入密码" />
-              </Form.Item>
-            </Col>
-            <Col span={12}>
-              <Form.Item
-                label="厂商"
-                name={['sipConfigs', 'manufacturer']}
-                rules={[{ required: true, message: '请输入厂商' }]}
-              >
-                <Input placeholder="请输入厂商" />
-              </Form.Item>
-            </Col>
-            <Col span={12}>
-              <Form.Item
-                label="型号"
-                name={['sipConfigs', 'model']}
-                rules={[{ required: true, message: '请输入型号' }]}
-              >
-                <Input placeholder="请输入型号" />
-              </Form.Item>
-            </Col>
-            <Col span={12}>
-              <Form.Item
-                label="版本号"
-                name={['sipConfigs', 'firmware']}
-                rules={[{ required: true, message: '请输入版本号' }]}
-              >
-                <Input placeholder="请输入版本号" />
-              </Form.Item>
-            </Col>
-            <Col span={12}>
-              <Form.Item
-                label="心跳周期(秒)"
-                name={['sipConfigs', 'keepaliveInterval']}
-                rules={[
-                  { required: true, message: '请输入心跳周期' },
-                  { validator: keepValidator },
-                ]}
-              >
-                <InputNumber placeholder="请输入心跳周期" style={{ width: '100%' }} />
-              </Form.Item>
-            </Col>
-            <Col span={12}>
-              <Form.Item
-                label="注册间隔(秒)"
-                name={['sipConfigs', 'registerInterval']}
-                rules={[
-                  { required: true, message: '请输入注册间隔' },
-                  { validator: keepValidator },
-                ]}
-              >
-                <InputNumber placeholder="请输入注册间隔" style={{ width: '100%' }} />
-              </Form.Item>
-            </Col>
-            <Col span={24}>
-              <Form.Item>
-                <Button type="primary" htmlType="submit">
-                  保存
-                </Button>
-              </Form.Item>
-            </Col>
-          </Row>
-        </Form>
+              }}
+            >
+              <Row gutter={24}>
+                <TitleComponent data={'基本信息'} />
+                <Col span={12}>
+                  <Form.Item
+                    label="名称"
+                    name="name"
+                    rules={[{ required: true, message: '请输入名称' }]}
+                  >
+                    <Input placeholder="请输入名称" />
+                  </Form.Item>
+                </Col>
+                <Col span={12}>
+                  <Form.Item
+                    label={<span>代理视频流</span>}
+                    name="proxyStream"
+                    rules={[{ required: true, message: '请选择代理视频流' }]}
+                  >
+                    <Radio.Group optionType="button" buttonStyle="solid">
+                      <Radio.Button value={true}>启用</Radio.Button>
+                      <Radio.Button value={false}>禁用</Radio.Button>
+                    </Radio.Group>
+                  </Form.Item>
+                </Col>
+                <TitleComponent data={'信令服务配置'} />
+                <Col span={12}>
+                  <Form.Item
+                    label={
+                      <span>
+                        集群节点
+                        <Tooltip title="使用此集群节点级联到上级平台">
+                          <QuestionCircleOutlined />
+                        </Tooltip>
+                      </span>
+                    }
+                    name={['sipConfigs', 'clusterNodeId']}
+                    rules={[{ required: true, message: '请选择集群节点' }]}
+                  >
+                    <Select placeholder="请选择集群节点">
+                      {clusters.map((item) => (
+                        <Select.Option key={item.id} value={item.id}>
+                          {item.name}
+                        </Select.Option>
+                      ))}
+                    </Select>
+                  </Form.Item>
+                </Col>
+                <Col span={12}>
+                  <Form.Item
+                    label="信令名称"
+                    name={['sipConfigs', 'name']}
+                    rules={[{ required: true, message: '请输入信令名称' }]}
+                  >
+                    <Input placeholder="请输入信令名称" />
+                  </Form.Item>
+                </Col>
+                <Col span={24}>
+                  <Form.Item
+                    label="上级SIP ID"
+                    name={['sipConfigs', 'sipId']}
+                    rules={[{ required: true, message: '请输入上级SIP ID' }]}
+                  >
+                    <Input placeholder="请输入上级SIP ID" />
+                  </Form.Item>
+                </Col>
+                <Col span={12}>
+                  <Form.Item
+                    label="上级SIP域"
+                    name={['sipConfigs', 'domain']}
+                    rules={[{ required: true, message: '请输入上级平台SIP域' }]}
+                  >
+                    <Input placeholder="请输入上级平台SIP域" />
+                  </Form.Item>
+                </Col>
+                <Col span={12}>
+                  <Form.Item
+                    label="上级SIP 地址"
+                    name={['sipConfigs', 'public']}
+                    rules={[
+                      { required: true, message: '请输入上级SIP 地址' },
+                      { validator: checkSIP },
+                    ]}
+                  >
+                    <SipComponent />
+                  </Form.Item>
+                </Col>
+                <Col span={24}>
+                  <Form.Item
+                    label="本地SIP ID"
+                    name={['sipConfigs', 'localSipId']}
+                    rules={[{ required: true, message: '请输入网关侧的SIP ID' }]}
+                  >
+                    <Input placeholder="网关侧的SIP ID" />
+                  </Form.Item>
+                </Col>
+                <Col span={12}>
+                  <Form.Item
+                    label={
+                      <span>
+                        SIP本地地址
+                        <Tooltip title="使用指定的网卡和端口进行请求">
+                          <QuestionCircleOutlined />
+                        </Tooltip>
+                      </span>
+                    }
+                    name={['sipConfigs', 'local']}
+                    rules={[
+                      { required: true, message: '请输入SIP本地地址' },
+                      { validator: checkLocalSIP },
+                    ]}
+                  >
+                    <SipSelectComponent data={list} transport={transport} />
+                  </Form.Item>
+                </Col>
+                <Col span={12}>
+                  <Form.Item
+                    label="SIP远程地址"
+                    name={['sipConfigs', 'remotePublic']}
+                    rules={[
+                      { required: true, message: '请输入SIP远程地址' },
+                      { validator: checkSIP },
+                    ]}
+                  >
+                    <SipComponent />
+                  </Form.Item>
+                </Col>
+                <Col span={24}>
+                  <Form.Item
+                    label="传输协议"
+                    name={['sipConfigs', 'transport']}
+                    rules={[{ required: true, message: '请选择传输协议' }]}
+                  >
+                    <Radio.Group
+                      optionType="button"
+                      buttonStyle="solid"
+                      onChange={(e) => {
+                        setTransport(e.target.value);
+                      }}
+                    >
+                      <Radio.Button value="UDP">UDP</Radio.Button>
+                      <Radio.Button value="TCP">TCP</Radio.Button>
+                    </Radio.Group>
+                  </Form.Item>
+                </Col>
+                <Col span={12}>
+                  <Form.Item
+                    label="用户"
+                    name={['sipConfigs', 'user']}
+                    rules={[{ required: true, message: '请输入用户' }]}
+                  >
+                    <Input placeholder="请输入用户" />
+                  </Form.Item>
+                </Col>
+                <Col span={12}>
+                  <Form.Item
+                    label="接入密码"
+                    name={['sipConfigs', 'password']}
+                    rules={[{ required: true, message: '请输入接入密码' }]}
+                  >
+                    <Input.Password placeholder="请输入接入密码" />
+                  </Form.Item>
+                </Col>
+                <Col span={12}>
+                  <Form.Item
+                    label="厂商"
+                    name={['sipConfigs', 'manufacturer']}
+                    rules={[{ required: true, message: '请输入厂商' }]}
+                  >
+                    <Input placeholder="请输入厂商" />
+                  </Form.Item>
+                </Col>
+                <Col span={12}>
+                  <Form.Item
+                    label="型号"
+                    name={['sipConfigs', 'model']}
+                    rules={[{ required: true, message: '请输入型号' }]}
+                  >
+                    <Input placeholder="请输入型号" />
+                  </Form.Item>
+                </Col>
+                <Col span={12}>
+                  <Form.Item
+                    label="版本号"
+                    name={['sipConfigs', 'firmware']}
+                    rules={[{ required: true, message: '请输入版本号' }]}
+                  >
+                    <Input placeholder="请输入版本号" />
+                  </Form.Item>
+                </Col>
+                <Col span={12}>
+                  <Form.Item
+                    label="心跳周期(秒)"
+                    name={['sipConfigs', 'keepaliveInterval']}
+                    rules={[
+                      { required: true, message: '请输入心跳周期' },
+                      { validator: keepValidator },
+                    ]}
+                  >
+                    <InputNumber placeholder="请输入心跳周期" style={{ width: '100%' }} />
+                  </Form.Item>
+                </Col>
+                <Col span={12}>
+                  <Form.Item
+                    label="注册间隔(秒)"
+                    name={['sipConfigs', 'registerInterval']}
+                    rules={[
+                      { required: true, message: '请输入注册间隔' },
+                      { validator: keepValidator },
+                    ]}
+                  >
+                    <InputNumber placeholder="请输入注册间隔" style={{ width: '100%' }} />
+                  </Form.Item>
+                </Col>
+                <Col span={24}>
+                  <Form.Item>
+                    <Button type="primary" htmlType="submit">
+                      保存
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+            </Form>
+          </Col>
+          <Col span={12}>
+            <div className={styles.doc}>
+              <h1>1.概述</h1>
+              <div>配置国标级联,平台可以将已经接入到自身的摄像头共享给第三方调用播放。</div>
+              <div>
+                <Alert
+                  icon={<InfoCircleFilled style={{ fontSize: 16, marginTop: 5 }} />}
+                  description="注:该配置只用于将本平台向上级联至第三方平台,如需第三方平台向上级联至本平台,请在“视频设备”页面新增设备时选择“GB/T28181”接入方式。"
+                  showIcon
+                />
+              </div>
+              <h1>2.配置说明</h1>
+              <div>以下配置说明以将本平台数据级联到LiveGBS平台为例。</div>
+              <h2>1、上级SIP ID</h2>
+              <div>请填写第三方平台中配置的SIP ID。</div>
+              <div className={styles.image}>
+                <Image width="100%" src={img2} />
+              </div>
+              <h2>2、上级SIP 域</h2>
+              <div>请填写第三方平台中配置的SIP ID域。</div>
+              <div className={styles.image}>
+                <Image width="100%" src={img1} />
+              </div>
+              <h2>3、上级SIP 地址</h2>
+              <div>请填写第三方平台中配置的SIP ID地址。</div>
+              <div className={styles.image}>
+                <Image width="100%" src={img3} />
+              </div>
+              <h2>4、本地SIP ID</h2>
+              <div>
+                请填写本地的SIP ID地址。
+                地址由由中心编码(8位)、行业编码(2位)、类型编码(3位)和序号(7位)四个码段共20位十
+                进制数字字符构成。详细规则请参见《GB/T28181-2016》中附录D部分。
+              </div>
+              <h2>5、SIP本地地址</h2>
+              <div>请选择指定的网卡和端口,如有疑问请联系系统运维人员。</div>
+              <h2>6、用户</h2>
+              <div>部分平台有基于用于和接入密码的特殊认证。通常情况下,请填写本地SIP ID值。</div>
+              <h2>7、接入密码</h2>
+              <div>需与上级平台设置的接入密码一致,用于身份认证。</div>
+              <h2>8、厂商/型号/版本号</h2>
+              <div>
+                本平台将以“设备”的身份级联到上级平台,请设置本平台在上级平台中显示的厂商、型号、版本号。
+              </div>
+              <h2>9、心跳周期</h2>
+              <div>需与上级平台设置的心跳周期保持一致,通常默认60秒。</div>
+              <h2>10、注册间隔</h2>
+              <div>
+                若SIP代理通过注册方式校时,其注册过期时间宜设置为小于 SIP代理与 SIP服务器出现1s误
+                差所经过的运行时间。
+              </div>
+            </div>
+          </Col>
+        </Row>
       </Card>
     </PageContainer>
   );

+ 1 - 1
src/pages/media/Stream/Detail/index.tsx

@@ -145,7 +145,7 @@ const Detail = () => {
         setProviders(resp.result);
       }
     });
-    if (params.id) {
+    if (params.id && params.id != ':id') {
       service.detail(params.id).then((resp) => {
         if (resp.status === 200) {
           StreamModel.current = resp.result;

+ 1 - 1
src/pages/system/DataSource/Management/EditTable.tsx

@@ -193,7 +193,7 @@ const EditTable = (props: Props) => {
               'x-component': 'ArrayTable.Column',
               'x-component-props': { title: '说明' },
               properties: {
-                description: {
+                comment: {
                   'x-component': 'Input',
                   'x-decorator': 'FormItem',
                   'x-component-props': {

+ 20 - 14
src/pages/system/DataSource/Management/RemoveData.tsx

@@ -4,6 +4,7 @@ import { Popconfirm } from 'antd';
 import { service } from '@/pages/system/DataSource';
 import _ from 'lodash';
 import { useField } from '@formily/react';
+import { Store } from 'jetlinks-store';
 
 interface Props {
   type: any;
@@ -25,21 +26,26 @@ const RemoveData = (props: Props) => {
         title={'确认删除'}
         onConfirm={() => {
           if (self?.disabled) return;
-          service.rdbTables(type.id, type.table).then((resp) => {
-            if (resp.status === 200) {
-              if ([..._.map(resp.result.columns, 'name')].includes(row?.name)) {
-                service.delRdbTablesColumn(type.id, type.table, [row?.name]).then((response) => {
-                  if (response.status === 200) {
-                    array.field?.remove?.(index);
-                    array.props?.onRemove?.(index);
-                  }
-                });
-              } else {
-                array.field?.remove?.(index);
-                array.props?.onRemove?.(index);
+          if (_.map(Store.get('datasource-detail-list'), 'name').includes(type.table)) {
+            service.rdbTables(type.id, type.table).then((resp) => {
+              if (resp.status === 200) {
+                if ([..._.map(resp.result.columns, 'name')].includes(row?.name)) {
+                  service.delRdbTablesColumn(type.id, type.table, [row?.name]).then((response) => {
+                    if (response.status === 200) {
+                      array.field?.remove?.(index);
+                      array.props?.onRemove?.(index);
+                    }
+                  });
+                } else {
+                  array.field?.remove?.(index);
+                  array.props?.onRemove?.(index);
+                }
               }
-            }
-          });
+            });
+          } else {
+            array.field?.remove?.(index);
+            array.props?.onRemove?.(index);
+          }
         }}
       >
         <DeleteOutlined />

+ 0 - 292
src/pages/system/DataSource/Management/index copy.tsx

@@ -1,292 +0,0 @@
-import { PageContainer } from '@ant-design/pro-layout';
-import { Card, Input, message, Popconfirm, Space, Tooltip, Tree } from 'antd';
-import { useEffect, useRef, useState } from 'react';
-import { service } from '@/pages/system/DataSource';
-import { useIntl, useLocation } from 'umi';
-import type { ActionType, ProColumns } from '@jetlinks/pro-table';
-import ProTable from '@jetlinks/pro-table';
-import PermissionButton from '@/components/PermissionButton';
-import { DeleteOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons';
-import usePermissions from '@/hooks/permission';
-import SearchComponent from '@/components/SearchComponent';
-import DataTable from './DataTable';
-import styles from './index.less';
-import DataRow from './DataRow';
-
-const Management = () => {
-  const location = useLocation<{ id: string }>();
-  const id = (location as any).query?.id;
-  const intl = useIntl();
-  const actionRef = useRef<ActionType>();
-  const [param, setParam] = useState({});
-  const { permission: userPermission } = usePermissions('system/User');
-
-  const [rdbList, setRdbList] = useState<any[]>([]);
-  const [defaultSelectedKeys, setDefaultSelectedKeys] = useState<any[]>([]);
-  const [visible, setVisible] = useState<boolean>(false);
-  const [current, setCurrent] = useState<any>({});
-  const [rowVisible, setRowVisible] = useState<boolean>(false);
-  const [rowCurrent, setRowCurrent] = useState<any>({});
-
-  useEffect(() => {
-    service.rdbTree(id).then((resp) => {
-      if (resp.status === 200) {
-        setRdbList(resp.result);
-        setDefaultSelectedKeys([resp.result[0]?.name]);
-      }
-    });
-  }, []);
-
-  useEffect(() => {
-    actionRef.current?.reload();
-  }, [defaultSelectedKeys]);
-
-  const columns: ProColumns<DataSourceType>[] = [
-    {
-      title: '列名',
-      dataIndex: 'name',
-      ellipsis: true,
-    },
-    {
-      title: '类型',
-      dataIndex: 'type',
-      ellipsis: true,
-    },
-    {
-      title: '长度',
-      dataIndex: 'length',
-      ellipsis: true,
-    },
-    {
-      title: '精度',
-      dataIndex: 'scale',
-      ellipsis: true,
-    },
-    {
-      title: '不能为空',
-      dataIndex: 'notnull',
-      ellipsis: true,
-      render: (text, record) => {
-        console.log(record.notnull);
-        return <span>{text ? '是' : '否'}</span>;
-      },
-      valueType: 'select',
-      valueEnum: {
-        true: {
-          text: '是',
-          status: true,
-        },
-        false: {
-          text: '否',
-          status: false,
-        },
-      },
-    },
-    {
-      dataIndex: 'description',
-      title: '说明',
-      ellipsis: true,
-    },
-    {
-      title: intl.formatMessage({
-        id: 'pages.data.option',
-        defaultMessage: '操作',
-      }),
-      valueType: 'option',
-      render: (_, record) => [
-        <a key="edit">
-          <EditOutlined
-            onClick={() => {
-              setRowCurrent(record);
-              setRowVisible(true);
-            }}
-          />
-        </a>,
-        <PermissionButton
-          type="link"
-          key="delete"
-          style={{ padding: 0 }}
-          isPermission={userPermission.delete}
-          tooltip={{ title: '删除' }}
-        >
-          <Popconfirm
-            onConfirm={async () => {
-              // await service.remove(record.id);
-              // actionRef.current?.reload();
-            }}
-            title="确认删除?"
-          >
-            <DeleteOutlined />
-          </Popconfirm>
-        </PermissionButton>,
-      ],
-    },
-  ];
-
-  return (
-    <PageContainer>
-      <Card>
-        <div className={styles.datasourceBox}>
-          <div className={styles.left}>
-            <Input.Search
-              placeholder="请输入"
-              onSearch={() => {}}
-              style={{ width: '100%', marginBottom: 20 }}
-            />
-            <div className={styles.tables}>
-              <Tree
-                showLine
-                showIcon
-                defaultExpandAll
-                height={500}
-                selectedKeys={[...defaultSelectedKeys]}
-                onSelect={(selectedKeys) => {
-                  if (!selectedKeys.includes('tables')) {
-                    setDefaultSelectedKeys([...selectedKeys]);
-                  }
-                }}
-              >
-                <Tree.TreeNode
-                  title={() => {
-                    return (
-                      <div style={{ display: 'flex', justifyContent: 'space-between', width: 230 }}>
-                        <div>数据源名称</div>
-                        <div>
-                          <a>
-                            <PlusOutlined
-                              onClick={() => {
-                                setCurrent({});
-                                setVisible(true);
-                              }}
-                            />
-                          </a>
-                        </div>
-                      </div>
-                    );
-                  }}
-                  key={'tables'}
-                >
-                  {rdbList.map((item) => (
-                    <Tree.TreeNode
-                      key={item.name}
-                      title={() => {
-                        return (
-                          <div className={styles.treeTitle}>
-                            <div className={styles.title}>
-                              <span
-                                className={
-                                  defaultSelectedKeys[0] === item?.name ? styles.active : ''
-                                }
-                              >
-                                <Tooltip title={item.name}>{item.name}</Tooltip>
-                              </span>
-                            </div>
-                            <div className={styles.options}>
-                              <Space>
-                                <a>
-                                  <EditOutlined
-                                    onClick={() => {
-                                      setCurrent(item);
-                                      setVisible(true);
-                                    }}
-                                  />
-                                </a>
-                                <a>
-                                  <Popconfirm title="确认删除!" onConfirm={() => {}}>
-                                    <DeleteOutlined />
-                                  </Popconfirm>
-                                </a>
-                              </Space>
-                            </div>
-                          </div>
-                        );
-                      }}
-                    />
-                  ))}
-                </Tree.TreeNode>
-              </Tree>
-            </div>
-          </div>
-          <div className={styles.right}>
-            <SearchComponent<DataSourceType>
-              field={columns}
-              target="datasource-manage"
-              onSearch={(data) => {
-                // 重置分页数据
-                actionRef.current?.reset?.();
-                setParam(data);
-              }}
-            />
-            <ProTable<DataSourceType>
-              actionRef={actionRef}
-              params={param}
-              columns={columns}
-              search={false}
-              rowKey="name"
-              headerTitle={
-                <PermissionButton
-                  onClick={() => {
-                    setRowCurrent({});
-                    setRowVisible(true);
-                  }}
-                  isPermission={userPermission.add}
-                  key="add"
-                  icon={<PlusOutlined />}
-                  type="primary"
-                >
-                  新增列
-                </PermissionButton>
-              }
-              request={async (params) => {
-                if (defaultSelectedKeys.length > 0) {
-                  const response = await service.rdbTables(id, defaultSelectedKeys[0], {
-                    ...params,
-                    sorts: [{ name: 'createTime', order: 'desc' }],
-                  });
-                  return {
-                    result: { data: response.result?.columns || [] },
-                    success: true,
-                    status: 200,
-                  } as any;
-                } else {
-                  return {
-                    result: { data: [] },
-                    success: true,
-                    status: 200,
-                  } as any;
-                }
-              }}
-            />
-          </div>
-        </div>
-      </Card>
-      {visible && (
-        <DataTable
-          data={current}
-          save={(data) => {
-            rdbList.push(data);
-            setRdbList([...rdbList]);
-            message.success('操作成功!');
-            setVisible(false);
-          }}
-          close={() => {
-            setVisible(false);
-          }}
-        />
-      )}
-      {rowVisible && (
-        <DataRow
-          data={rowCurrent}
-          reload={() => {
-            // setRowVisible(false);
-          }}
-          close={() => {
-            setRowVisible(false);
-          }}
-        />
-      )}
-    </PageContainer>
-  );
-};
-
-export default Management;

+ 10 - 10
src/pages/system/DataSource/Management/index.less

@@ -8,11 +8,11 @@
     width: 280px;
 
     .tables {
-      :global {
-        .ant-tree-treenode .ant-tree-node-selected {
-          background-color: white;
-        }
-      }
+      // :global {
+      //   .ant-tree-treenode .ant-tree-node-selected {
+      //     background-color: white;
+      //   }
+      // }
 
       .treeTitle {
         display: flex;
@@ -31,11 +31,11 @@
         }
       }
 
-      .treeTitle:hover {
-        .options {
-          display: block;
-        }
-      }
+      // .treeTitle:hover {
+      //   .options {
+      //     display: block;
+      //   }
+      // }
 
       .active {
         background-color: #c3d3f7;

+ 120 - 135
src/pages/system/DataSource/Management/index.tsx

@@ -1,54 +1,65 @@
 import { PageContainer } from '@ant-design/pro-layout';
-import { Card, Input, message, Popconfirm, Space, Tooltip, Tree } from 'antd';
+import { Card, Input, message, Spin, Tooltip, Tree, Empty } from 'antd';
 import { useEffect, useState } from 'react';
 import { service } from '@/pages/system/DataSource';
 import { useLocation } from 'umi';
-import { DeleteOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons';
-// import usePermissions from '@/hooks/permission';
+import { PlusOutlined } from '@ant-design/icons';
 import DataTable from './DataTable';
 import styles from './index.less';
 import EditTable from './EditTable';
 import _ from 'lodash';
 import { useDomFullHeight } from '@/hooks';
+import { Store } from 'jetlinks-store';
 
 const Management = () => {
   const location = useLocation<{ id: string }>();
   const id = (location as any).query?.id;
 
+  const [info, setInfo] = useState<Partial<DataSourceItem>>({});
   const [rdbList, setRdbList] = useState<any[]>([]);
   const [allList, setAllList] = useState<any[]>([]);
   const [defaultSelectedKeys, setDefaultSelectedKeys] = useState<any[]>([]);
   const [visible, setVisible] = useState<boolean>(false);
-  const [current, setCurrent] = useState<any>({});
-  const [model, setModel] = useState<'edit' | 'add' | 'list'>('list');
   const [tableList, setTableList] = useState<any[]>([]);
   const [param, setParam] = useState<string | undefined>(undefined);
+  const [loading, setLoading] = useState<boolean>(true);
   const { minHeight } = useDomFullHeight(`.management`);
 
-  const handleSearch = () => {
+  const queryTables = (key: string) => {
+    setLoading(true);
+    service.rdbTables(id, key).then((resp) => {
+      if (resp.status === 200) {
+        setTableList(resp.result?.columns || []);
+      }
+      setLoading(false);
+    });
+  };
+
+  const handleSearch = (refresh: boolean) => {
     service.rdbTree(id).then((resp) => {
       if (resp.status === 200) {
+        Store.set('datasource-detail-list', resp.result);
         setAllList(resp.result);
-        setDefaultSelectedKeys([resp.result[0]?.name]);
+        if (refresh) {
+          setDefaultSelectedKeys([resp.result[0]?.name]);
+          queryTables(resp.result[0]?.name);
+        } else {
+          queryTables(defaultSelectedKeys[0]);
+        }
       }
     });
   };
 
   useEffect(() => {
-    handleSearch();
-  }, []);
-
-  useEffect(() => {
-    if (defaultSelectedKeys.length > 0) {
-      service.rdbTables(id, defaultSelectedKeys[0]).then((resp) => {
+    if (id) {
+      service.detail(id).then((resp) => {
         if (resp.status === 200) {
-          setTableList(resp.result?.columns || []);
+          setInfo(resp.result);
         }
       });
-    } else {
-      setTableList([]);
+      handleSearch(true);
     }
-  }, [defaultSelectedKeys]);
+  }, [id]);
 
   useEffect(() => {
     if (!!param) {
@@ -58,141 +69,115 @@ const Management = () => {
       setRdbList([...list]);
       if (!_.map(list, 'name').includes(defaultSelectedKeys[0])) {
         setDefaultSelectedKeys([list[0]?.name]);
+        queryTables(list[0]?.name);
       }
     } else {
       setRdbList([...allList]);
     }
   }, [allList, param]);
 
+  const saveTables = async (name: string, data: any) => {
+    const resp = await service.saveRdbTables(id, {
+      name: name,
+      columns: [...data.array],
+    });
+    if (resp.status === 200) {
+      message.success('保存成功');
+      handleSearch(false);
+    }
+  };
+
   return (
     <PageContainer>
-      <Card className="management" style={{ minHeight }}>
-        <div className={styles.datasourceBox}>
-          <div className={styles.left}>
-            <Input.Search
-              placeholder="请输入"
-              onSearch={(val: string) => {
-                setParam(val);
-              }}
-              allowClear
-              style={{ width: '100%', marginBottom: 20 }}
-            />
-            <div className={styles.tables}>
-              <Tree showLine showIcon defaultExpandAll height={500}>
-                <Tree.TreeNode
-                  title={() => {
-                    return (
-                      <div style={{ display: 'flex', justifyContent: 'space-between', width: 230 }}>
-                        <div>数据源名称</div>
-                        <div>
-                          <a>
-                            <PlusOutlined
-                              onClick={() => {
-                                setCurrent({});
-                                setModel('add');
-                                setVisible(true);
-                              }}
-                            />
-                          </a>
-                        </div>
-                      </div>
-                    );
+      <Spin spinning={loading}>
+        <Card className="management" style={{ minHeight }}>
+          <div className={styles.datasourceBox}>
+            <div className={styles.left}>
+              <Input.Search
+                placeholder="请输入"
+                onSearch={(val: string) => {
+                  setParam(val);
+                }}
+                allowClear
+                style={{ width: '100%', marginBottom: 20 }}
+              />
+              <div className={styles.tables}>
+                <Tree
+                  showLine
+                  showIcon
+                  selectedKeys={defaultSelectedKeys}
+                  defaultExpandAll
+                  height={500}
+                  onSelect={(value: any) => {
+                    setDefaultSelectedKeys(value);
+                    queryTables(value[0]);
                   }}
-                  key={'tables'}
                 >
-                  {rdbList.map((item, index) => (
-                    <Tree.TreeNode
-                      key={item.name}
-                      title={() => {
-                        return (
-                          <div className={styles.treeTitle}>
-                            <div
-                              className={styles.title}
-                              onClick={() => {
-                                setDefaultSelectedKeys([item.name]);
-                              }}
-                            >
-                              <span
-                                className={
-                                  defaultSelectedKeys[0] === item?.name ? styles.active : ''
-                                }
-                              >
+                  <Tree.TreeNode
+                    selectable={false}
+                    title={() => {
+                      return (
+                        <div
+                          style={{ display: 'flex', justifyContent: 'space-between', width: 230 }}
+                        >
+                          <div>{info?.shareConfig?.schema || '数据源名称'}</div>
+                          <div>
+                            <a>
+                              <PlusOutlined
+                                onClick={() => {
+                                  setVisible(true);
+                                }}
+                              />
+                            </a>
+                          </div>
+                        </div>
+                      );
+                    }}
+                    key={'tables'}
+                  >
+                    {rdbList.map((item) => (
+                      <Tree.TreeNode
+                        key={item.name}
+                        title={() => {
+                          return (
+                            <div className={styles.treeTitle}>
+                              <div className={styles.title}>
                                 <Tooltip title={item.name}>{item.name}</Tooltip>
-                              </span>
+                              </div>
                             </div>
-                            <div className={styles.options}>
-                              <Space>
-                                <a>
-                                  <EditOutlined
-                                    onClick={() => {
-                                      setCurrent(item);
-                                      setVisible(true);
-                                      setModel('edit');
-                                    }}
-                                  />
-                                </a>
-                                <a>
-                                  <Popconfirm
-                                    title="确认删除!"
-                                    onConfirm={() => {
-                                      const list = [...rdbList];
-                                      list.splice(index, 1);
-                                      setAllList([...list]);
-                                      if (item.name === defaultSelectedKeys[0]) {
-                                        setDefaultSelectedKeys([list[0]?.name]);
-                                      }
-                                    }}
-                                  >
-                                    <DeleteOutlined />
-                                  </Popconfirm>
-                                </a>
-                              </Space>
-                            </div>
-                          </div>
-                        );
-                      }}
-                    />
-                  ))}
-                </Tree.TreeNode>
-              </Tree>
+                          );
+                        }}
+                      />
+                    ))}
+                  </Tree.TreeNode>
+                </Tree>
+              </div>
+            </div>
+            <div className={styles.right}>
+              {defaultSelectedKeys.length > 0 ? (
+                <EditTable
+                  table={{ id, table: defaultSelectedKeys[0] }}
+                  data={tableList}
+                  onChange={(data: any) => {
+                    saveTables(defaultSelectedKeys[0], data);
+                  }}
+                />
+              ) : (
+                <Empty />
+              )}
             </div>
           </div>
-          <div className={styles.right}>
-            <EditTable
-              table={{ id, table: defaultSelectedKeys[0] }}
-              data={tableList}
-              onChange={async (data: any) => {
-                const resp = await service.saveRdbTables(id, {
-                  name: defaultSelectedKeys[0],
-                  columns: [...data.array],
-                });
-                if (resp.status === 200) {
-                  message.success('保存成功');
-                  handleSearch();
-                }
-              }}
-            />
-          </div>
-        </div>
-      </Card>
+        </Card>
+      </Spin>
       {visible && (
         <DataTable
-          data={current}
+          data={{}}
           save={(data) => {
-            if (model === 'edit') {
-              const list = [...rdbList].map((item) => {
-                return {
-                  name: item?.name === current?.name ? data.name : item.name,
-                };
-              });
-              setAllList(list);
-            } else {
-              const list = [...rdbList];
-              list.unshift(data);
-              setAllList([...list]);
-            }
-            setModel('list');
-            message.success('操作成功!');
+            const list = [...rdbList];
+            list.unshift(data);
+            setAllList([...list]);
+            setDefaultSelectedKeys([data.name]);
+            setTableList([]);
             setVisible(false);
           }}
           close={() => {

+ 2 - 1
src/pages/system/DataSource/index.tsx

@@ -138,12 +138,13 @@ const DataSource = observer(() => {
           type="link"
           isPermission={userPermission.action}
           key="manage"
+          disabled={record.state?.value !== 'enabled'}
           onClick={() => {
             const url = getMenuPathByCode(MENUS_CODE[`system/DataSource/Management`]);
             history.push(`${url}?id=${record.id}`);
           }}
           tooltip={{
-            title: '管理',
+            title: record.state?.value !== 'enabled' ? '请先启用数据源' : '管理',
           }}
         >
           <DatabaseOutlined />