Просмотр исходного кода

fix(metadata): delete、refresh...

Lind 3 лет назад
Родитель
Сommit
7e08f028bf

+ 1 - 9
src/pages/device/Instance/Detail/ChildDevice/BindChildDevice/index.tsx

@@ -4,7 +4,7 @@ import SearchComponent from '@/components/SearchComponent';
 import type { ActionType, ProColumns } from '@jetlinks/pro-table';
 import ProTable from '@jetlinks/pro-table';
 import { useRef, useState } from 'react';
-import { InstanceModel, service } from '@/pages/device/Instance';
+import { InstanceModel, service, statusMap } from '@/pages/device/Instance';
 import { useIntl } from 'umi';
 import moment from 'moment';
 
@@ -17,14 +17,6 @@ interface Props {
 const BindChildDevice = (props: Props) => {
   const { visible } = props;
   const intl = useIntl();
-  const statusMap = new Map();
-
-  statusMap.set('在线', 'success');
-  statusMap.set('离线', 'error');
-  statusMap.set('未激活', 'processing');
-  statusMap.set('online', 'success');
-  statusMap.set('offline', 'error');
-  statusMap.set('notActive', 'processing');
 
   const actionRef = useRef<ActionType>();
   const [searchParams, setSearchParams] = useState<any>({});

+ 1 - 8
src/pages/device/Instance/Detail/ChildDevice/index.tsx

@@ -4,7 +4,7 @@ import type { LogItem } from '@/pages/device/Instance/Detail/Log/typings';
 import { Badge, Button, Card, message, Popconfirm, Tooltip } from 'antd';
 import { DisconnectOutlined, SearchOutlined } from '@ant-design/icons';
 import { useIntl } from '@@/plugin-locale/localeExports';
-import { InstanceModel, service } from '@/pages/device/Instance';
+import { InstanceModel, service, statusMap } from '@/pages/device/Instance';
 import { useRef, useState } from 'react';
 import SearchComponent from '@/components/SearchComponent';
 import BindChildDevice from './BindChildDevice';
@@ -14,13 +14,6 @@ import { Link } from 'umi';
 const ChildDevice = () => {
   const intl = useIntl();
   const [visible, setVisible] = useState<boolean>(false);
-  const statusMap = new Map();
-  statusMap.set('在线', 'success');
-  statusMap.set('离线', 'error');
-  statusMap.set('未激活', 'processing');
-  statusMap.set('online', 'success');
-  statusMap.set('offline', 'error');
-  statusMap.set('notActive', 'processing');
 
   const actionRef = useRef<ActionType>();
   const [searchParams, setSearchParams] = useState<any>({});

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

@@ -13,7 +13,7 @@ const Running = () => {
         <Tabs.TabPane tab="属性" key="1">
           <Property data={metadata?.properties || {}} />
         </Tabs.TabPane>
-        {metadata.events.map((item) => (
+        {metadata.events?.map((item) => (
           <Tabs.TabPane tab={item.name} key={item.id}>
             <Event data={item} />
           </Tabs.TabPane>

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

@@ -16,6 +16,8 @@ import { useIntl } from '@@/plugin-locale/localeExports';
 import Metadata from '../../components/Metadata';
 import type { DeviceMetadata } from '@/pages/device/Product/typings';
 import MetadataAction from '@/pages/device/components/Metadata/DataBaseAction';
+import { Store } from 'jetlinks-store';
+import SystemConst from '@/utils/const';
 
 export const deviceStatus = new Map();
 deviceStatus.set('online', <Badge status="success" text={'在线'} />);
@@ -34,11 +36,23 @@ const InstanceDetail = observer(() => {
   };
   const params = useParams<{ id: string }>();
 
+  useEffect(() => {
+    Store.subscribe(SystemConst.REFRESH_DEVICE, () => {
+      MetadataAction.clean();
+      setTimeout(() => {
+        getDetail(params.id);
+      }, 200);
+    });
+    // return subscription.unsubscribe();
+  }, []);
   const resetMetadata = async () => {
     const resp = await service.deleteMetadata(params.id);
     if (resp.status === 200) {
       message.success('操作成功');
-      getDetail(params.id);
+      Store.set(SystemConst.REFRESH_DEVICE, true);
+      setTimeout(() => {
+        Store.set(SystemConst.REFRESH_METADATA_TABLE, true);
+      }, 400);
     }
   };
   const list = [

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

@@ -10,9 +10,9 @@ import {
   CheckCircleOutlined,
   DeleteOutlined,
   ExportOutlined,
+  EyeOutlined,
   ImportOutlined,
   PlusOutlined,
-  SearchOutlined,
   StopOutlined,
   SyncOutlined,
 } from '@ant-design/icons';
@@ -29,7 +29,7 @@ import SearchComponent from '@/components/SearchComponent';
 import SystemConst from '@/utils/const';
 import Token from '@/utils/token';
 
-const statusMap = new Map();
+export const statusMap = new Map();
 statusMap.set('在线', 'success');
 statusMap.set('离线', 'error');
 statusMap.set('未激活', 'processing');
@@ -167,7 +167,7 @@ const Instance = () => {
             })}
             key={'detail'}
           >
-            <SearchOutlined />
+            <EyeOutlined />
           </Tooltip>
         </Link>,
         // <a key="editable" onClick={() => {

+ 29 - 6
src/pages/device/Product/Detail/PropertyImport/index.tsx

@@ -11,11 +11,17 @@ import { useParams } from 'umi';
 import { productModel, service } from '../..';
 import { downloadFile } from '@/utils/util';
 import type { DeviceMetadata, ProductItem } from '@/pages/device/Product/typings';
-import { updateMetadata } from '@/utils/metadata';
+import { Store } from 'jetlinks-store';
+import { asyncUpdateMedata, updateMetadata } from '@/pages/device/components/Metadata/metadata';
+import { InstanceModel } from '@/pages/device/Instance';
 
 const NormalUpload = (props: any) => {
   const param = useParams<{ id: string }>();
-  console.log(props?.fileType);
+
+  const typeMap = new Map<string, any>();
+
+  typeMap.set('product', productModel.current);
+  typeMap.set('device', InstanceModel.detail);
 
   const mergeMetadata = async (url: string) => {
     if (!url) return;
@@ -23,14 +29,26 @@ const NormalUpload = (props: any) => {
     const r = await service.importProductProperty(param.id, url);
     const _metadata = JSON.parse(r.result || '{}') as DeviceMetadata;
 
-    const product = productModel.current;
+    const target = typeMap.get(props.type);
 
-    const _product = updateMetadata('properties', _metadata.properties, product!) as ProductItem;
-    const resp = await service.update(_product);
+    const _data = updateMetadata('properties', _metadata.properties, target) as ProductItem;
+    // const resp = await service.update(_product);
+    const resp = await asyncUpdateMedata(props.type, _data);
     console.log(resp);
     if (resp.status === 200) {
       message.success('操作成功');
+      // 刷新物模型
+
+      if (props.type === 'product') {
+        Store.set(SystemConst.GET_METADATA, true);
+      } else if (props.type === 'device') {
+        Store.set(SystemConst.REFRESH_DEVICE, true);
+      }
+      setTimeout(() => {
+        Store.set(SystemConst.REFRESH_METADATA_TABLE, true);
+      }, 300);
     }
+    MetadataModel.importMetadata = false;
   };
 
   return (
@@ -87,7 +105,11 @@ const NormalUpload = (props: any) => {
   );
 };
 
-const PropertyImport = () => {
+interface Props {
+  type: 'product' | 'device';
+}
+
+const PropertyImport = (props: Props) => {
   const SchemaField = createSchemaField({
     components: {
       Radio,
@@ -103,6 +125,7 @@ const PropertyImport = () => {
         form.setFieldState('*(upload)', (state) => {
           state.componentProps = {
             fileType: field.value,
+            type: props.type,
           };
         });
       });

+ 19 - 7
src/pages/device/Product/Detail/index.tsx

@@ -25,6 +25,7 @@ import MetadataAction from '@/pages/device/components/Metadata/DataBaseAction';
 import { QuestionCircleOutlined } from '@ant-design/icons';
 import { getMenuPathByCode, MENUS_CODE } from '@/utils/menu';
 import encodeQuery from '@/utils/encodeQuery';
+import SystemConst from '@/utils/const';
 
 const ProductDetail = observer(() => {
   const intl = useIntl();
@@ -61,25 +62,36 @@ const ProductDetail = observer(() => {
   };
   const param = useParams<{ id: string }>();
 
+  const initMetadata = () => {
+    service.getProductDetail(param?.id).subscribe((data) => {
+      if (data.metadata) {
+        const metadata: DeviceMetadata = JSON.parse(data.metadata);
+        productModel.current = data;
+        MetadataAction.insert(metadata);
+      }
+    });
+  };
   useEffect(() => {
+    const subscription = Store.subscribe(SystemConst.GET_METADATA, () => {
+      MetadataAction.clean();
+      setTimeout(() => {
+        initMetadata();
+        Store.set(SystemConst.REFRESH_METADATA_TABLE, true);
+      }, 300);
+    });
     if (!productModel.current) {
       history.goBack();
     } else {
-      service.getProductDetail(param?.id).subscribe((data) => {
-        if (data.metadata) {
-          const metadata: DeviceMetadata = JSON.parse(data.metadata);
-          MetadataAction.insert(metadata);
-        }
-      });
+      initMetadata();
       service.instanceCount(encodeQuery({ terms: { productId: param?.id } })).then((res: any) => {
         if (res.status === 200) {
           productModel.current!.count = res.result;
         }
       });
     }
-
     return () => {
       MetadataAction.clean();
+      subscription.unsubscribe();
     };
   }, [param.id]);
 

+ 4 - 4
src/pages/device/Product/index.tsx

@@ -177,7 +177,7 @@ const Product = observer(() => {
           key={'state'}
           title={intl.formatMessage({
             id: `pages.data.option.${record.state ? 'disabled' : 'enabled'}.tips`,
-            defaultMessage: '是否删除该菜单',
+            defaultMessage: '是否删除?',
           })}
           onConfirm={() => {
             changeDeploy(record.id, record.state ? 'undeploy' : 'deploy');
@@ -196,10 +196,10 @@ const Product = observer(() => {
           key="unBindUser"
           title={intl.formatMessage({
             id: 'page.system.menu.table.delete',
-            defaultMessage: '是否删除该菜单',
+            defaultMessage: '是否删除?',
           })}
-          onConfirm={() => {
-            deleteItem(record.id);
+          onConfirm={async () => {
+            await deleteItem(record.id);
           }}
         >
           <Tooltip

+ 17 - 15
src/pages/device/components/Metadata/Base/Edit/index.tsx

@@ -39,11 +39,10 @@ import { lastValueFrom } from 'rxjs';
 import SystemConst from '@/utils/const';
 import DB from '@/db';
 import _ from 'lodash';
-import { useParams } from 'umi';
 import { InstanceModel } from '@/pages/device/Instance';
 import FRuleEditor from '@/components/FRuleEditor';
 import { action } from '@formily/reactive';
-import { updateMetadata } from '@/utils/metadata';
+import { asyncUpdateMedata, updateMetadata } from '../../metadata';
 
 interface Props {
   type: 'product' | 'device';
@@ -692,12 +691,12 @@ const Edit = observer((props: Props) => {
     );
   };
 
-  const param = useParams<{ id: string }>();
+  // const param = useParams<{ id: string }>();
   const typeMap = new Map<string, any>();
 
   typeMap.set('product', productModel.current);
   typeMap.set('device', InstanceModel.detail);
-  const saveMap = new Map<string, Promise<any>>();
+  // const saveMap = new Map<string, Promise<any>>();
   const { type } = MetadataModel;
 
   const saveMetadata = async (deploy?: boolean) => {
@@ -727,18 +726,21 @@ const Edit = observer((props: Props) => {
       }
     };
 
+    console.log(typeMap.get(props.type), 'log');
     const _data = updateMetadata(type, [params], typeMap.get(props.type), updateDB);
-    if (props.type === 'product') {
-      // const product = typeMap.get('product');
-      // @ts-ignore
-      // metadata[type] = config;
-      // product.metadata = JSON.stringify(metadata);
-      saveMap.set('product', service.saveProductMetadata(_data));
-    } else {
-      saveMap.set('device', service.saveDeviceMetadata(param.id, { metadata: _data.metadata }));
-    }
-
-    const result = await saveMap.get(props.type);
+    // console.log(params, JSON.parse(_data.metadata));
+    // if (props.type === 'product') {
+    //   // const product = typeMap.get('product');
+    //   // @ts-ignore
+    //   // metadata[type] = config;
+    //   // product.metadata = JSON.stringify(metadata);
+    //   saveMap.set('product', service.saveProductMetadata(_data));
+    // } else {
+    //   saveMap.set('device', service.saveDeviceMetadata(param.id, { metadata: _data.metadata }));
+    // }
+    //
+    // const result = await saveMap.get(props.type);
+    const result = await asyncUpdateMedata(props.type, _data);
     if (result.status === 200) {
       message.success('操作成功!');
       Store.set(SystemConst.REFRESH_METADATA_TABLE, true);

+ 37 - 7
src/pages/device/components/Metadata/Base/index.tsx

@@ -5,7 +5,7 @@ import { useParams } from 'umi';
 import DB from '@/db';
 import type { MetadataItem, MetadataType } from '@/pages/device/Product/typings';
 import MetadataMapping from './columns';
-import { Button, Popconfirm, Tooltip } from 'antd';
+import { Button, message, Popconfirm, Tooltip } from 'antd';
 import { DeleteOutlined, EditOutlined, ImportOutlined, PlusOutlined } from '@ant-design/icons';
 import Edit from './Edit';
 import { observer } from '@formily/react';
@@ -14,6 +14,9 @@ import { Store } from 'jetlinks-store';
 import SystemConst from '@/utils/const';
 import { useIntl } from '@@/plugin-locale/localeExports';
 import PropertyImport from '@/pages/device/Product/Detail/PropertyImport';
+import { productModel } from '@/pages/device/Product';
+import { InstanceModel } from '@/pages/device/Instance';
+import { asyncUpdateMedata, removeMetadata } from '../metadata';
 
 interface Props {
   type: MetadataType;
@@ -27,6 +30,26 @@ const BaseMetadata = observer((props: Props) => {
 
   const [loading, setLoading] = useState<boolean>(true);
   const [data, setData] = useState<MetadataItem[]>([]);
+  const typeMap = new Map<string, any>();
+
+  typeMap.set('product', productModel.current);
+  typeMap.set('device', InstanceModel.detail);
+
+  const removeItem = async (record: MetadataItem) => {
+    const removeDB = () => {
+      return DB.getDB().table(`${type}`).delete(record.id!);
+    };
+    const _currentData = removeMetadata(type, [record], typeMap.get(target), removeDB);
+    const result = await asyncUpdateMedata(target, _currentData);
+    if (result.status === 200) {
+      message.success('操作成功!');
+      Store.set(SystemConst.REFRESH_METADATA_TABLE, true);
+      MetadataModel.edit = false;
+      MetadataModel.item = {};
+    } else {
+      message.error('操作失败!');
+    }
+  };
 
   const actions: ProColumns<MetadataItem>[] = [
     {
@@ -49,7 +72,12 @@ const BaseMetadata = observer((props: Props) => {
           </Tooltip>
         </a>,
         <a key="delete">
-          <Popconfirm title="确认删除?" onConfirm={async () => {}}>
+          <Popconfirm
+            title="确认删除?"
+            onConfirm={async () => {
+              await removeItem(record);
+            }}
+          >
             <Tooltip title="删除">
               <DeleteOutlined />
             </Tooltip>
@@ -69,10 +97,12 @@ const BaseMetadata = observer((props: Props) => {
   }, [initData]);
 
   useEffect(() => {
-    const subscription = Store.subscribe(SystemConst.REFRESH_METADATA_TABLE, async (flag) => {
-      if (flag) {
-        await initData();
-      }
+    const subscription = Store.subscribe(SystemConst.REFRESH_METADATA_TABLE, (flag) => {
+      setTimeout(async () => {
+        if (flag) {
+          await initData();
+        }
+      }, 300);
     });
     return () => subscription.unsubscribe();
   }, []);
@@ -142,7 +172,7 @@ const BaseMetadata = observer((props: Props) => {
           </Button>,
         ]}
       />
-      {MetadataModel.importMetadata && <PropertyImport />}
+      {MetadataModel.importMetadata && <PropertyImport type={target} />}
       {MetadataModel.edit && <Edit type={target} />}
     </>
   );

+ 4 - 0
src/pages/device/components/Metadata/Import/index.tsx

@@ -8,6 +8,8 @@ import FMonacoEditor from '@/components/FMonacoEditor';
 import FUpload from '@/components/Upload';
 import { service } from '@/pages/device/Product';
 import { useParams } from 'umi';
+import { Store } from 'jetlinks-store';
+import SystemConst from '@/utils/const';
 
 interface Props {
   visible: boolean;
@@ -180,7 +182,9 @@ const Import = (props: Props) => {
     } else {
       await service.modify(param.id, { metadata: data[data.type] });
     }
+    Store.set(SystemConst.GET_METADATA, true);
     message.success('导入成功');
+    props.close();
   };
   return (
     <Modal

+ 86 - 0
src/pages/device/components/Metadata/metadata.ts

@@ -0,0 +1,86 @@
+import type {
+  DeviceMetadata,
+  MetadataItem,
+  MetadataType,
+  ProductItem,
+} from '@/pages/device/Product/typings';
+import type { DeviceInstance } from '@/pages/device/Instance/typings';
+import { service } from '@/pages/device/components/Metadata/index';
+
+/**
+ * 更新物模型
+ * @param type 物模型类型 events
+ * @param item 物模型数据 【{a},{b},{c}】
+ // * @param target product、device
+ * @param data product 、device [{event:[1,2,3]]
+ * @param onEvent 数据更新回调:更新数据库、发送事件等操作
+ *
+ */
+export const updateMetadata = (
+  type: MetadataType,
+  item: MetadataItem[],
+  // target: 'product' | 'device',
+  data: ProductItem | DeviceInstance,
+  onEvent?: (type: 'update' | 'add', item: MetadataItem) => void,
+): ProductItem | DeviceInstance => {
+  if (!data) return data;
+  const metadata = JSON.parse(data.metadata || '{}') as DeviceMetadata;
+  const config = (metadata[type] || []) as MetadataItem[];
+  if (item.length > 0) {
+    item.forEach((i) => {
+      const index = config.findIndex((c) => c.id === i.id);
+      if (index > -1) {
+        config[index] = i;
+        onEvent?.('update', i);
+      } else {
+        config.push(i);
+        onEvent?.('add', i);
+      }
+    });
+  } else {
+    console.warn('未触发物模型修改');
+  }
+  // @ts-ignore
+  metadata[type] = config;
+  data.metadata = JSON.stringify(metadata);
+  return data;
+};
+
+/**
+ * 删除物模型数据
+ * @param type 物模型类型
+ * @param item 删除的数据
+ * @param data 设备/产品数据
+ * @param onEvent 回调
+ */
+export const removeMetadata = (
+  type: MetadataType,
+  item: MetadataItem[],
+  data: ProductItem | DeviceInstance,
+  onEvent?: (type: 'remove', item: MetadataItem) => void,
+): ProductItem | DeviceInstance => {
+  const metadata = JSON.parse(data.metadata || '{}') as DeviceMetadata;
+  const config = (metadata[type] || []) as MetadataItem[];
+  // @ts-ignore
+  metadata[type] = config.filter((i) => !item.map((r) => r.id).includes(i.id));
+  onEvent?.('remove', item);
+  data.metadata = JSON.stringify(metadata);
+  return data;
+};
+
+/**
+ * 保存物模型数据到服务器
+ * @param type 类型
+ * @param data 数据
+ */
+export const asyncUpdateMedata = (
+  type: 'product' | 'device',
+  data: ProductItem | DeviceInstance,
+): Promise<any> => {
+  switch (type) {
+    case 'product':
+      return service.saveProductMetadata(data);
+    case 'device':
+      return service.saveDeviceMetadata(data.id, JSON.parse(data.metadata || '{}'));
+  }
+};

+ 4 - 0
src/utils/const.ts

@@ -22,6 +22,10 @@ class SystemConst {
   static REFRESH_METADATA = 'refresh_metadata';
 
   static REFRESH_METADATA_TABLE = 'refresh_metadata_table';
+
+  static GET_METADATA = 'get_metadata';
+
+  static REFRESH_DEVICE = 'refresh_device';
 }
 
 export default SystemConst;

+ 0 - 43
src/utils/metadata.ts

@@ -1,43 +0,0 @@
-import type {
-  DeviceMetadata,
-  MetadataItem,
-  MetadataType,
-  ProductItem,
-} from '@/pages/device/Product/typings';
-import type { DeviceInstance } from '@/pages/device/Instance/typings';
-
-/**
- *
- * @param type 物模型类型 events
- * @param item 物模型数据 【{a},{b},{c}】
- // * @param target product、device
- * @param data product 、device [{event:[1,2,3]]
- * @param onEvent 数据更新回调:更新数据库、发送事件等操作
- *
- */
-export const updateMetadata = (
-  type: MetadataType,
-  item: MetadataItem[],
-  // target: 'product' | 'device',
-  data: ProductItem | DeviceInstance,
-  onEvent?: (type: 'update' | 'add', item: MetadataItem) => void,
-): ProductItem | DeviceInstance => {
-  const metadata = JSON.parse(data.metadata || '{}') as DeviceMetadata;
-  const config = (metadata[type] || []) as MetadataItem[];
-  if (item.length > 1) {
-    item.forEach((i) => {
-      const index = config.findIndex((c) => c.id === i.id);
-      if (index > -1) {
-        config[index] = i;
-        onEvent?.('update', i);
-      } else {
-        config.push(i);
-        onEvent?.('add', i);
-      }
-    });
-  }
-  // @ts-ignore
-  metadata[type] = config;
-  data.metadata = JSON.stringify(metadata);
-  return data;
-};