Bläddra i källkod

fix: 修改物模型导入

sun-chaochao 3 år sedan
förälder
incheckning
2a1a5e468e

+ 4 - 1
src/pages/device/Instance/Detail/Diagnose/index.tsx

@@ -47,8 +47,11 @@ const Diagnose = observer(() => {
     return () => {
       DiagnoseStatusModel.list = [];
       DiagnoseStatusModel.count = 0;
+      DiagnoseStatusModel.percent = 0;
+      DiagnoseStatusModel.status = 'loading';
+      DiagnoseStatusModel.state = 'loading';
     };
-  }, []);
+  }, [InstanceModel.active]);
 
   const activeStyle = {
     background: '#FFFFFF',

+ 3 - 0
src/pages/device/Instance/Detail/Info/index.tsx

@@ -65,6 +65,9 @@ const Info = observer(() => {
               </div>
             </Tooltip>
           </Descriptions.Item>
+          <Descriptions.Item label={'产品分类'}>
+            {InstanceModel.detail?.classifiedName}
+          </Descriptions.Item>
           <Descriptions.Item
             label={intl.formatMessage({
               id: 'pages.device.instanceDetail.deviceType',

+ 5 - 2
src/pages/device/Instance/Detail/index.tsx

@@ -1,7 +1,7 @@
 import { PageContainer } from '@ant-design/pro-layout';
 import { InstanceModel } from '@/pages/device/Instance';
 import { history, useParams } from 'umi';
-import { Badge, Card, Descriptions, Divider, Space, Tooltip } from 'antd';
+import { Badge, Card, Descriptions, Divider, message, Space, Tooltip } from 'antd';
 import type { ReactNode } from 'react';
 import { useEffect, useState } from 'react';
 import { observer } from '@formily/react';
@@ -421,7 +421,10 @@ const InstanceDetail = observer(() => {
           onClick={() => {
             getDetail(params.id);
             service.getConfigMetadata(params.id).then((config) => {
-              InstanceModel.config = config?.result || [];
+              if (config.status === 200) {
+                InstanceModel.config = config?.result || [];
+                message.success('操作成功!');
+              }
             });
           }}
           style={{ fontSize: 20, marginRight: 20 }}

+ 1 - 0
src/pages/device/Instance/typings.d.ts

@@ -44,6 +44,7 @@ export type DeviceInstance = {
   accessId?: string;
   features?: any[];
   parentId?: string;
+  classifiedName?: string;
 };
 
 type Unit = {

+ 32 - 15
src/pages/device/Product/Detail/Access/AccessConfig/index.tsx

@@ -12,6 +12,8 @@ import { getMenuPathByCode } from '@/utils/menu';
 import PermissionButton from '@/components/PermissionButton';
 import { onlyMessage } from '@/utils/util';
 import Empty from '@/components/Empty';
+import _ from 'lodash';
+import MetadataAction from '@/pages/device/components/Metadata/DataBaseAction';
 
 interface Props {
   close: () => void;
@@ -128,6 +130,15 @@ const AccessConfig = (props: Props) => {
     handleSearch(param);
   }, []);
 
+  const modifyArray = (oldData: any[], newData: any[]) => {
+    newData.map((item) => {
+      if (!_.map(oldData, 'id').includes(item.id)) {
+        oldData.push(item);
+      }
+    });
+    return oldData;
+  };
+
   return (
     <Modal
       onCancel={() => {
@@ -138,7 +149,7 @@ const AccessConfig = (props: Props) => {
       title={'设备接入配置'}
       onOk={async () => {
         if (!!currrent) {
-          const resp: any = await service1.update({
+          const obj: any = {
             ...productModel.current,
             transportProtocol: currrent.transport,
             protocolName: currrent.protocolDetail.name,
@@ -146,7 +157,26 @@ const AccessConfig = (props: Props) => {
             accessName: currrent.name,
             accessProvider: currrent.provider,
             messageProtocol: currrent.protocol,
-          });
+          };
+          const metatdata = JSON.parse(productModel.current?.metadata || '{}');
+          if (obj.accessProvider === 'gb28181-2016') {
+            const response = await service.getConfigView(
+              obj?.messageProtocol || '',
+              obj?.transportProtocol || '',
+            );
+            if (response.status === 200) {
+              const ndata = JSON.parse(response.result?.metadata || '{}');
+              const mdata = {
+                events: modifyArray(metatdata?.events || [], ndata?.events || []),
+                properties: modifyArray(metatdata?.properties || [], ndata?.properties || []),
+                functions: modifyArray(metatdata?.functions || [], ndata?.functions || []),
+                tags: modifyArray(metatdata?.tags || [], ndata?.tags || []),
+              };
+              MetadataAction.insert(mdata);
+              obj.metadata = JSON.stringify(mdata);
+            }
+          }
+          const resp: any = await service1.update(obj);
           if (resp.status === 200) {
             service1.detail(productModel.current?.id || '').then((res) => {
               if (res.status === 200) {
@@ -155,19 +185,6 @@ const AccessConfig = (props: Props) => {
               }
               close();
             });
-            // service1
-            //   .changeDeploy(productModel.current?.id || '', 'deploy')
-            //   .subscribe((response) => {
-            //     if (response) {
-            //       service1.detail(productModel.current?.id || '').then((res) => {
-            //         if (res.status === 200) {
-            //           productModel.current = { ...res.result };
-            //           message.success('操作成功!');
-            //         }
-            //         close();
-            //       });
-            //     }
-            //   });
           }
         } else {
           onlyMessage('请选择接入方式', 'error');

+ 8 - 8
src/pages/device/Product/Detail/Access/index.less

@@ -33,11 +33,11 @@
 
 .driver {
   .driver-next-btn {
-    background-color: #2F54EB !important;
     color: #fff !important;
-    text-shadow: 0 0 black !important;
     font-size: 14px !important;
     line-height: 22px !important;
+    text-shadow: 0 0 black !important;
+    background-color: #2f54eb !important;
   }
 
   .driver-prev-btn {
@@ -45,16 +45,16 @@
     line-height: 22px !important;
     background-color: #fff !important;
   }
-  .driver-prev-btn.driver-disabled{
+  .driver-prev-btn.driver-disabled {
     display: none !important;
   }
 
   .driver-close-btn {
-    background-color: #fff !important;
-    border: none !important;
+    padding: 5px 0 0 0 !important;
     color: #828282 !important;
     font-size: 14px !important;
-    padding: 5px 0 0 0 !important;
+    background-color: #fff !important;
+    border: none !important;
   }
 
   .driver-popover-description {
@@ -67,7 +67,7 @@
 
     #guide {
       margin-top: 3px;
-      font-size: 14px
+      font-size: 14px;
     }
   }
-}
+}

+ 145 - 113
src/pages/device/Product/Detail/Access/index.tsx

@@ -40,7 +40,7 @@ const Access = () => {
   const [access, setAccess] = useState<any>();
   const { permission } = usePermissions('device/Product');
   const [dataSource, setDataSource] = useState<any[]>([]);
-
+  const [storageList, setStorageList] = useState<any[]>([]);
 
   const MetworkTypeMapping = new Map();
   MetworkTypeMapping.set('websocket-server', 'WEB_SOCKET_SERVER');
@@ -65,8 +65,7 @@ const Access = () => {
         title: `<div id='title'>配置物模型</div><div id='guide'>1/3</div>`,
         description: `配置产品物模型,实现设备在云端的功能描述。`,
         position: 'bottom',
-
-      }
+      },
     },
     {
       element: '.ant-switch',
@@ -74,8 +73,8 @@ const Access = () => {
         className: 'driver',
         title: `<div id='title'>启用产品</div><div id='guide'>2/3</div>`,
         description: '启用产品后,可在产品下新增设备。',
-        position: 'bottom'
-      }
+        position: 'bottom',
+      },
     },
     {
       element: '.ant-descriptions-item-label',
@@ -83,10 +82,10 @@ const Access = () => {
         className: 'driver',
         title: `<div id='title'>添加设备</div><div id='guide'>3/3</div>`,
         description: '添加设备,并连接到平台。',
-        position: 'bottom'
-      }
-    }
-  ]
+        position: 'bottom',
+      },
+    },
+  ];
   const steps1 = [
     {
       element: '#driver-config',
@@ -95,8 +94,7 @@ const Access = () => {
         title: `<div id='title'>填写配置</div><div id='guide'>1/4</div>`,
         description: `填写设备接入所需的配置参数。`,
         position: 'right',
-
-      }
+      },
     },
     {
       element: '#metadata-driver',
@@ -105,8 +103,7 @@ const Access = () => {
         title: `<div id='title'>配置物模型</div><div id='guide'>2/4</div>`,
         description: `配置产品物模型,实现设备在云端的功能描述。`,
         position: 'bottom',
-
-      }
+      },
     },
     {
       element: '.ant-switch',
@@ -114,8 +111,8 @@ const Access = () => {
         className: 'driver',
         title: `<div id='title'>启用产品</div><div id='guide'>3/4</div>`,
         description: '启用产品后,可在产品下新增设备。',
-        position: 'bottom'
-      }
+        position: 'bottom',
+      },
     },
     {
       element: '.ant-descriptions-item-label',
@@ -123,10 +120,10 @@ const Access = () => {
         className: 'driver',
         title: `<div id='title'>添加设备</div><div id='guide'>4/4</div>`,
         description: '添加设备,并连接到平台。',
-        position: 'bottom'
-      }
-    }
-  ]
+        position: 'bottom',
+      },
+    },
+  ];
 
   const queryAccessDetail = (id: string) => {
     service
@@ -286,19 +283,18 @@ const Access = () => {
       // onDeselected:(e)=>{
       //   console.log(e)
       // },
-      onNext:()=>{
-        console.log('下一步')
+      onNext: () => {
+        console.log('下一步');
       },
-      onPrevious:()=>{
-        console.log('上一步')
+      onPrevious: () => {
+        console.log('上一步');
       },
-      onReset:()=>{
-        console.log('关闭')
+      onReset: () => {
+        console.log('关闭');
       },
       // onDeselected:()=>{
       //   console.log('oncolse')
       // }
-    
     });
     setVisible(!!productModel.current?.accessId);
     if (productModel.current?.accessId) {
@@ -308,10 +304,10 @@ const Access = () => {
           .then((resp: { result: SetStateAction<ConfigMetadata[]> }) => {
             setMetadata(resp.result);
             if (resp.result && resp.result.length > 0) {
-              driver.defineSteps(steps1)
+              driver.defineSteps(steps1);
               driver.start();
             } else {
-              driver.defineSteps(steps)
+              driver.defineSteps(steps);
               driver.start();
             }
           });
@@ -335,6 +331,16 @@ const Access = () => {
           });
       }
     }
+    productService.getStoragList().then((resp) => {
+      if (resp.status === 200) {
+        setStorageList(
+          resp.result.map((i: any) => ({
+            label: i.name,
+            value: i.id,
+          })),
+        );
+      }
+    });
   }, [productModel.current]);
 
   // useEffect(() => {
@@ -357,7 +363,10 @@ const Access = () => {
 
   const form = createForm({
     validateFirst: true,
-    initialValues: productModel.current?.configuration,
+    initialValues: {
+      ...productModel.current?.configuration,
+      storePolicy: productModel.current?.storePolicy,
+    },
   });
 
   const SchemaField = createSchemaField({
@@ -372,13 +381,16 @@ const Access = () => {
   });
 
   const configToSchema = (data: ConfigProperty[]) => {
-    const obj = {};
+    const obj: any = {};
     data.forEach((item) => {
       obj[item?.property] = {
         type: 'string',
         title: item.name,
         'x-decorator': 'FormItem',
         'x-component': componentMap[item.type.type],
+        'x-component-props': {
+          placeholder: item.type.type === 'enum' ? '请选择' : '请输入',
+        },
         'x-decorator-props': {
           tooltip: item.description,
           gridSpan: 1,
@@ -388,14 +400,15 @@ const Access = () => {
         enum:
           item?.type?.type === 'enum' && item?.type?.elements
             ? (item?.type?.elements || []).map((t: { value: string; text: string }) => {
-              return {
-                label: t.text,
-                value: t.value,
-              };
-            })
+                return {
+                  label: t.text,
+                  value: t.value,
+                };
+              })
             : [],
       };
     });
+
     return obj;
   };
 
@@ -411,84 +424,101 @@ const Access = () => {
   };
 
   const renderConfigCard = () => {
-    return (
-      metadata &&
-      metadata.length > 0 &&
-      metadata?.map((item: any) => {
-        const itemSchema: ISchema = {
-          type: 'object',
-          properties: {
-            grid: {
-              type: 'void',
-              'x-component': 'FormGrid',
-              'x-component-props': {
-                maxColumns: 1,
-                minColumns: 1,
-                columnGap: 48,
-              },
-              title: (
-                <TitleComponent
-                  data={
-                    <div className='config'>
-                      {item.name}
-                      <Tooltip title="此配置来自于该产品接入方式所选择的协议">
-                        <QuestionCircleOutlined />
-                      </Tooltip>
-                    </div>
-                  }
-                />
-              ),
-              'x-decorator': 'FormItem',
-              'x-decorator-props': {
-                gridSpan: 1,
-                labelAlign: 'left',
-                layout: 'vertical',
-              },
-              properties: configToSchema(item.properties),
+    const itemSchema: any = (metadata || []).map((item: any) => {
+      return {
+        type: 'object',
+        properties: {
+          grid: {
+            type: 'void',
+            'x-component': 'FormGrid',
+            'x-component-props': {
+              maxColumns: 1,
+              minColumns: 1,
+              columnGap: 48,
+            },
+            title: (
+              <TitleComponent
+                data={
+                  <div className="config">
+                    {item.name}
+                    <Tooltip title="此配置来自于该产品接入方式所选择的协议">
+                      <QuestionCircleOutlined />
+                    </Tooltip>
+                  </div>
+                }
+              />
+            ),
+            'x-decorator': 'FormItem',
+            'x-decorator-props': {
+              gridSpan: 1,
+              labelAlign: 'left',
+              layout: 'vertical',
             },
+            properties: configToSchema(item.properties),
           },
-        };
-
-        return (
-          <PreviewText.Placeholder value="-" key={'config'}>
-            <Form form={form} layout="vertical">
-              <FormLayout>
-                <SchemaField schema={itemSchema} />
-              </FormLayout>
-              <Button
-                type="primary"
-                onClick={async () => {
-                  const values = (await form.submit()) as any;
-                  const resp = await productService.modify(id || '', {
-                    id,
-                    configuration: { ...values },
-                  });
-                  if (resp.status === 200) {
-                    onlyMessage('操作成功!');
-                    if ((window as any).onTabSaveSuccess) {
-                      if (resp.result) {
-                        (window as any).onTabSaveSuccess(resp);
-                        setTimeout(() => window.close(), 300);
-                      }
-                    } else {
-                      getDetailInfo();
-                    }
+        },
+      };
+    });
+    const schema: ISchema = {
+      type: 'object',
+      properties: {
+        ...itemSchema,
+        storePolicy: {
+          type: 'string',
+          title: <TitleComponent data={'存储策略'} />,
+          'x-decorator': 'FormItem',
+          'x-component': 'Select',
+          'x-component-props': {
+            placeholder: '请选择存储策略',
+          },
+          // required: true,
+          default: 'default-column',
+          'x-decorator-props': {
+            // tooltip: '使用指定的存储策略来存储设备数据',
+            gridSpan: 1,
+            labelAlign: 'left',
+            layout: 'vertical',
+          },
+          enum: storageList,
+        },
+      },
+    };
+    return (
+      <PreviewText.Placeholder value="-" key={'config'}>
+        <Form form={form} layout="vertical">
+          <FormLayout>
+            <SchemaField schema={schema} />
+          </FormLayout>
+          <Button
+            type="primary"
+            onClick={async () => {
+              const values = (await form.submit()) as any;
+              const { storePolicy, ...extra } = values;
+              const resp = await productService.modify(id || '', {
+                id,
+                configuration: { ...extra },
+                storePolicy: storePolicy,
+              });
+              if (resp.status === 200) {
+                onlyMessage('操作成功!');
+                if ((window as any).onTabSaveSuccess) {
+                  if (resp.result) {
+                    (window as any).onTabSaveSuccess(resp);
+                    setTimeout(() => window.close(), 300);
                   }
-                }}
-              >
-                保存
-              </Button>
-            </Form>
-          </PreviewText.Placeholder>
-        );
-      })
+                } else {
+                  getDetailInfo();
+                }
+              }
+            }}
+          >
+            保存
+          </Button>
+        </Form>
+      </PreviewText.Placeholder>
     );
   };
 
-  // useEffect(() => {
-
-  // }, [])
-
   return (
     <div>
       {!visible ? (
@@ -582,14 +612,16 @@ const Access = () => {
                 <TitleComponent data={'连接信息'} />
                 {(access?.channelInfo?.addresses || []).length > 0
                   ? (access?.channelInfo?.addresses || []).map((item: any) => (
-                    <div key={item.address}>
-                      <Badge color={item.health === -1 ? 'red' : 'green'} text={item.address} />
-                    </div>
-                  ))
+                      <div key={item.address}>
+                        <Badge color={item.health === -1 ? 'red' : 'green'} text={item.address} />
+                      </div>
+                    ))
                   : '暂无连接信息'}
               </div>
 
-              <div className={styles.item} id='driver-config'>{renderConfigCard()}</div>
+              <div className={styles.item} id="driver-config">
+                {renderConfigCard()}
+              </div>
             </div>
           </Col>
           {config?.routes && config?.routes?.length > 0 && (
@@ -598,7 +630,7 @@ const Access = () => {
                 <div>
                   <div style={{ fontWeight: '600', marginBottom: 10 }}>
                     {access?.provider === 'mqtt-server-gateway' ||
-                      access?.provider === 'mqtt-client-gateway'
+                    access?.provider === 'mqtt-client-gateway'
                       ? 'topic'
                       : 'URL信息'}
                   </div>

+ 1 - 1
src/pages/device/Product/Detail/index.tsx

@@ -54,7 +54,7 @@ const ProductDetail = observer(() => {
     {
       key: 'metadata',
       tab: (
-        <div id='metadata-driver'>
+        <div id="metadata-driver">
           {intl.formatMessage({
             id: 'pages.device.instanceDetail.metadata',
             defaultMessage: '物模型',

+ 5 - 0
src/pages/device/Product/service.ts

@@ -164,6 +164,11 @@ class Service extends BaseService<ProductItem> {
     request(`/${SystemConst.API_BASE}/protocol/${id}/detail`, {
       method: 'POST',
     });
+  // 存储策略
+  public getStoragList = () =>
+    request(`/${SystemConst.API_BASE}/device/product/storage/policies`, {
+      method: 'GET',
+    });
 }
 
 export default Service;

+ 1 - 0
src/pages/device/Product/typings.d.ts

@@ -27,6 +27,7 @@ export type ProductItem = {
   accessId?: string;
   accessName?: string;
   photoUrl?: string;
+  storePolicy?: string;
   accessProvider?: string;
 };
 

+ 20 - 2
src/pages/device/components/Metadata/Import/index.tsx

@@ -12,6 +12,9 @@ import { Store } from 'jetlinks-store';
 import SystemConst from '@/utils/const';
 import { onlyMessage } from '@/utils/util';
 import { ExclamationCircleOutlined } from '@ant-design/icons';
+import { InstanceModel } from '@/pages/device/Instance';
+import _ from 'lodash';
+import { DeviceMetadata } from '@/pages/device/Product/typings';
 
 interface Props {
   visible: boolean;
@@ -181,6 +184,19 @@ const Import = (props: Props) => {
     },
   };
 
+  const operateLimits = (mdata: DeviceMetadata) => {
+    const obj: DeviceMetadata = { ...mdata };
+    const old = JSON.parse(InstanceModel.detail?.metadata || '{}');
+    const fid = _.map(InstanceModel.detail?.features || [], 'id');
+    if (fid.includes('eventNotModifiable')) {
+      obj.events = old?.event || [];
+    }
+    if (fid.includes('propertyNotModifiable')) {
+      obj.properties = old?.properties || {};
+    }
+    return obj;
+  };
+
   const handleImport = async () => {
     const data = (await form.submit()) as any;
 
@@ -188,14 +204,16 @@ const Import = (props: Props) => {
       service.convertMetadata('from', 'alink', data.import).subscribe({
         next: async (meta) => {
           onlyMessage('导入成功');
-          await service.modify(param.id, { metadata: JSON.stringify(meta) });
+          await service.modify(param.id, { metadata: JSON.stringify(operateLimits(meta)) });
         },
         error: () => {
           onlyMessage('发生错误!', 'error');
         },
       });
     } else {
-      const resp = await service.modify(param.id, { metadata: data[data.type] });
+      const resp = await service.modify(param.id, {
+        metadata: JSON.stringify(operateLimits(JSON.parse(data[data?.type] || '{}'))),
+      });
       if (resp.status === '200') {
         onlyMessage('导入成功');
       }

+ 5 - 4
src/pages/home/components/Steps.tsx

@@ -7,13 +7,13 @@ interface StepItemProps {
   content: string | React.ReactNode;
   onClick: () => void;
   url?: string;
-  after?: any
+  after?: any;
 }
 
 interface StepsProps {
   title: string | React.ReactNode;
   data: StepItemProps[];
-  style?: any
+  style?: any;
 }
 
 const ItemDefaultImg = require('/public/images/home/bottom-1.png');
@@ -40,10 +40,11 @@ const Steps = (props: StepsProps) => {
         style={{
           gridTemplateColumns: `repeat(${props.data ? props.data.length : 1}, 1fr)`,
           minHeight: props.style?.height,
-          gridColumnGap:props?.style?.gridColumnGap
+          gridColumnGap: props?.style?.gridColumnGap,
         }}
       >
-        {props.data && props.data.map((item) => <StepsItem {...item} after={props.style ? true : false} />)}
+        {props.data &&
+          props.data.map((item) => <StepsItem {...item} after={props.style ? true : false} />)}
       </div>
     </div>
   );

+ 1 - 1
src/pages/home/comprehensive/index.tsx

@@ -171,7 +171,7 @@ const Comprehensive = () => {
                 {
                   name: '产品数量',
                   value: productCount,
-                  children:require('/public/images/home/top-2.png'),
+                  children: require('/public/images/home/top-2.png'),
                 },
                 {
                   name: '设备数量',

+ 3 - 3
src/pages/home/device/index.tsx

@@ -82,8 +82,8 @@ const Device = () => {
       <Col span={18}>
         <Steps
           style={{
-            height:275,
-            gridColumnGap:20
+            height: 275,
+            gridColumnGap: 20,
           }}
           title={
             <span>
@@ -198,7 +198,7 @@ const Device = () => {
           }
         />
       </Col>
-      <Col span={24} style={{marginTop:24}}>
+      <Col span={24} style={{ marginTop: 24 }}>
         <Body title={'平台架构图'} english={'PLATFORM ARCHITECTURE DIAGRAM'} />
       </Col>
 

+ 94 - 0
src/pages/link/AccessConfig/Detail/Media/SipSelectComponent/index.tsx

@@ -0,0 +1,94 @@
+import { Select } from 'antd';
+import { useEffect, useState } from 'react';
+
+interface SipSelectComponentProps {
+  onChange?: (data: any) => void;
+  value?: {
+    host?: string;
+    port?: number;
+  };
+  type?: boolean;
+  data: any[];
+}
+
+const SipSelectComponent = (props: SipSelectComponentProps) => {
+  const { value, onChange } = props;
+  const [data, setData] = useState<{ host?: string; port?: number } | undefined>(value);
+  const [list, setList] = useState<any[]>([]);
+
+  useEffect(() => {
+    setData(value);
+  }, [value]);
+
+  useEffect(() => {
+    if (!props.type) {
+      setData(value || { host: '0.0.0.0' });
+      if (!value) {
+        const dt: any = props.data.find((i) => i.host === '0.0.0.0');
+        setList(dt?.portList || []);
+      } else {
+        const dt: any = props.data.find((i) => i.host === value.host);
+        setList(dt?.portList || []);
+      }
+    }
+  }, [props.type]);
+
+  return (
+    <div style={{ display: 'flex', alignItems: 'center' }}>
+      <Select
+        showSearch
+        value={data?.host}
+        style={{ marginRight: 10 }}
+        placeholder="请选择IP地址"
+        disabled={!props.type}
+        onChange={(e) => {
+          if (onChange) {
+            const item = {
+              port: undefined,
+              host: e,
+            };
+            onChange(item);
+            const dt: any = props.data.find((i) => i.host === e);
+            setList(dt?.portList || []);
+          }
+        }}
+        filterOption={(input: string, option: any) =>
+          String(option?.children)?.toLowerCase()?.indexOf(String(input).toLowerCase()) >= 0
+        }
+      >
+        {(props.data || []).map((item: any) => (
+          <Select.Option key={item.host} value={item.host}>
+            {item.host}
+          </Select.Option>
+        ))}
+      </Select>
+      <Select
+        showSearch
+        style={{ minWidth: 100 }}
+        value={data?.port}
+        placeholder="请选择端口"
+        optionFilterProp="children"
+        onChange={(e: number) => {
+          if (onChange) {
+            const item = {
+              ...data,
+              port: e,
+            };
+            onChange(item);
+          }
+        }}
+        filterOption={(input: string, option: any) =>
+          String(option?.children)?.toLowerCase()?.indexOf(String(input).toLowerCase()) >= 0
+        }
+      >
+        {list.map((item) => (
+          <Select.Option key={item?.port} value={item?.port}>
+            {(item?.transports || []).join('/')}({item?.port})
+          </Select.Option>
+        ))}
+      </Select>
+    </div>
+  );
+};
+
+export default SipSelectComponent;

+ 25 - 3
src/pages/link/AccessConfig/Detail/Media/index.tsx

@@ -22,6 +22,7 @@ import TitleComponent from '@/components/TitleComponent';
 import { InfoCircleOutlined } from '@ant-design/icons';
 import { onlyMessage, testIP } from '@/utils/util';
 import { getButtonPermission } from '@/utils/menu';
+import SipSelectComponent from './SipSelectComponent';
 
 type LocationType = {
   id?: string;
@@ -38,6 +39,7 @@ const Media = (props: Props) => {
   const [form] = Form.useForm();
   const [configuration, setConfiguration] = useState<any>({});
   const [clusters, setClusters] = useState<any[]>([]);
+  const [alist, setAList] = useState<any[]>([]);
 
   const location = useLocation<LocationType>();
 
@@ -88,6 +90,16 @@ const Media = (props: Props) => {
     }
   };
 
+  useEffect(() => {
+    if (props.provider?.id === 'gb28181-2016') {
+      service.getResourcesCurrent().then((resp) => {
+        if (resp.status === 200) {
+          setAList(resp.result);
+        }
+      });
+    }
+  }, [props.provider]);
+
   const BasicRender = () => {
     const SchemaField = createSchemaField({
       components: {
@@ -96,6 +108,7 @@ const Media = (props: Props) => {
         Select,
         Radio,
         SipComponent,
+        SipSelectComponent,
         FormGrid,
         FormCollapse,
         ArrayCollapse,
@@ -146,6 +159,7 @@ const Media = (props: Props) => {
       },
       properties: {
         clusterNodeId: {
+          type: 'string',
           title: '节点名称',
           'x-component': 'Select',
           'x-decorator': 'FormItem',
@@ -159,13 +173,17 @@ const Media = (props: Props) => {
         sip: {
           title: 'SIP 地址',
           'x-decorator': 'FormItem',
-          'x-component': 'SipComponent',
+          'x-component': 'SipSelectComponent',
           'x-decorator-props': {
             gridSpan: 1,
             labelAlign: 'left',
             layout: 'vertical',
             tooltip: '绑定到服务器上的网卡地址,绑定到所有网卡:0.0.0.0',
           },
+          'x-component-props': {
+            data: alist,
+            type: true,
+          },
           'x-validator': [
             {
               required: true,
@@ -185,7 +203,6 @@ const Media = (props: Props) => {
             layout: 'vertical',
           },
           required: true,
-          type: 'number',
           'x-decorator': 'FormItem',
           'x-component': 'SipComponent',
           'x-validator': [
@@ -297,9 +314,13 @@ const Media = (props: Props) => {
                   properties: {
                     sip: {
                       title: 'SIP 地址',
-                      'x-component': 'SipComponent',
+                      'x-component': 'SipSelectComponent',
                       'x-decorator': 'FormItem',
                       required: true,
+                      'x-component-props': {
+                        data: alist,
+                        type: false,
+                      },
                       'x-decorator-props': {
                         gridSpan: 1,
                         labelAlign: 'left',
@@ -405,6 +426,7 @@ const Media = (props: Props) => {
               <Button
                 onClick={async () => {
                   const value = await aform.submit<any>();
+                  console.log(value);
                   let param: any = {};
                   if (value.configuration.shareCluster) {
                     const hostPort = { ...value.configuration.hostPort };

+ 4 - 0
src/pages/link/AccessConfig/service.ts

@@ -51,6 +51,10 @@ class Service extends BaseService<AccessItem> {
     request(`/${SystemConst.API_BASE}/network/resources/clusters`, {
       method: 'GET',
     });
+  public getResourcesCurrent = () =>
+    request(`${SystemConst.API_BASE}/network/resources/alive/_current`, {
+      method: 'GET',
+    });
 }
 
 export default Service;

+ 22 - 22
src/pages/link/Protocol/save/index.tsx

@@ -20,30 +20,30 @@ interface Props {
 const Save = (props: Props) => {
   const [data, setData] = useState<ProtocolItem | undefined>(props.data);
   const { permission } = PermissionButton.usePermission('link/Protocol');
-  const [count, setCount] = useState<number>(0);
+  // const [count, setCount] = useState<number>(0);
 
   useEffect(() => {
     setData(props.data);
-    if (props.data?.id) {
-      service
-        .productCount({
-          terms: [
-            {
-              terms: [
-                {
-                  column: 'message_protocol',
-                  value: props.data.id,
-                },
-              ],
-            },
-          ],
-        })
-        .then((resp) => {
-          if (resp.status === 200) {
-            setCount(resp.result);
-          }
-        });
-    }
+    // if (props.data?.id) {
+    //   service
+    //     .productCount({
+    //       terms: [
+    //         {
+    //           terms: [
+    //             {
+    //               column: 'message_protocol',
+    //               value: props.data.id,
+    //             },
+    //           ],
+    //         },
+    //       ],
+    //     })
+    //     .then((resp) => {
+    //       if (resp.status === 200) {
+    //         setCount(resp.result);
+    //       }
+    //     });
+    // }
   }, [props.data]);
 
   const form = createForm({
@@ -200,7 +200,7 @@ const Save = (props: Props) => {
                 'x-decorator-props': {
                   gridSpan: 2,
                 },
-                'x-disabled': !!count,
+                // 'x-disabled': !!count,
                 'x-validator': [
                   {
                     required: true,

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

@@ -147,7 +147,7 @@ const EditTable = (props: Props) => {
               'x-component': 'ArrayTable.Column',
               'x-component-props': { title: '精度' },
               properties: {
-                scale: {
+                precision: {
                   type: 'number',
                   'x-decorator': 'FormItem',
                   'x-component': 'NumberPicker',

+ 5 - 0
yarn.lock

@@ -8639,6 +8639,11 @@ draftjs-utils@^0.9.4:
   resolved "https://registry.yarnpkg.com/draftjs-utils/-/draftjs-utils-0.9.4.tgz#976c61aa133dbbbfedd65ae1dd6627d7b98c6f08"
   integrity sha512-KYjABSbGpJrwrwmxVj5UhfV37MF/p0QRxKIyL+/+QOaJ8J9z1FBKxkblThbpR0nJi9lxPQWGg+gh+v0dAsSCCg==
 
+driver.js@^0.9.8:
+  version "0.9.8"
+  resolved "https://registry.npmmirror.com/driver.js/-/driver.js-0.9.8.tgz#4b327f4537b1c9b9fb19419de86174be821ae32a"
+  integrity sha512-bczjyKdX6XmFyCDkwtRmlaORDwfBk1xXmRO0CAe5VwNQTM98aWaG2LAIiIdTe53iV/B7W5lXlIy2xYtf0JRb7Q==
+
 dumi-assets-types@1.0.0, dumi-assets-types@^1.0.0-beta.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/dumi-assets-types/-/dumi-assets-types-1.0.0.tgz#d5368cb11045b203bf1ef1080e553b2287a2ec81"