Selaa lähdekoodia

fix(duerOs): duerOS

lind 4 vuotta sitten
vanhempi
commit
4857981d71

BIN
public/images/cloud/dueros.png


+ 55 - 0
src/components/ProTableCard/CardItems/duerOs.tsx

@@ -0,0 +1,55 @@
+import React from 'react';
+import { TableCard } from '@/components';
+import '@/style/common.less';
+import '../index.less';
+import { Tooltip } from 'antd';
+import { DuerOSItem } from '@/pages/cloud/DuerOS/typings';
+
+export interface DuerOSProps extends DuerOSItem {
+  detail?: React.ReactNode;
+  action?: React.ReactNode[];
+  avatarSize?: number;
+}
+
+export const duerOS = require('/public/images/cloud/dueros.png');
+
+export default (props: DuerOSProps) => {
+  return (
+    <TableCard
+      actions={props.action}
+      detail={props.detail}
+      // status={props.state?.value}
+      // statusText={props.state?.text}
+      // statusNames={{
+      //   enabled: StatusColorEnum.success,
+      //   disabled: StatusColorEnum.error,
+      // }}
+      // showMask={false}
+    >
+      <div className={'pro-table-card-item'}>
+        <div className={'card-item-avatar'}>
+          <img width={88} height={88} src={duerOS} alt={''} />
+        </div>
+        <div className={'card-item-body'}>
+          <div className={'card-item-header'}>
+            <span className={'card-item-header-name ellipsis'}>{props?.name}</span>
+          </div>
+          <div className={'card-item-content'}>
+            <div>
+              <label>产品</label>
+              <div className={'ellipsis'}>
+                <Tooltip title={props?.name || ''}>{props?.name || ''}</Tooltip>
+              </div>
+            </div>
+            <div>
+              <label>设备类型</label>
+              <div className={'ellipsis'}>
+                <Tooltip title={props.applianceType}>{props.applianceType}</Tooltip>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </TableCard>
+  );
+};

+ 356 - 0
src/pages/Northbound/DuerOS/Detail/index.tsx

@@ -0,0 +1,356 @@
+import { PageContainer } from '@ant-design/pro-layout';
+import { createSchemaField } from '@formily/react';
+import { ISchema } from '@formily/json-schema';
+import { Card, Col, Row } from 'antd';
+import {
+  ArrayCollapse,
+  Form,
+  FormButtonGroup,
+  FormGrid,
+  FormItem,
+  Input,
+  Select,
+} from '@formily/antd';
+import { PermissionButton } from '@/components';
+import { useMemo } from 'react';
+import { createForm, Field, onFieldInit } from '@formily/core';
+import { useAsyncDataSource } from '@/utils/util';
+import { service } from '..';
+import { Store } from 'jetlinks-store';
+
+const Save = () => {
+  const SchemaField = createSchemaField({
+    components: {
+      FormGrid,
+      FormItem,
+      Input,
+      Select,
+      ArrayCollapse,
+    },
+  });
+
+  const getProduct = () => service.getProduct().then((resp) => resp.result);
+
+  const getTypes = () =>
+    service.getTypes().then((resp) => {
+      Store.set('product-types', resp.result);
+      return resp.result;
+    });
+
+  const schema: ISchema = {
+    type: 'object',
+    properties: {
+      name: {
+        title: '名称',
+        type: 'string',
+        'x-decorator': 'FormItem',
+        'x-component': 'Input',
+        'x-decorator-props': {
+          gridSpan: 1,
+        },
+        required: true,
+        'x-component-props': {
+          placeholder: '请输入名称',
+        },
+        name: 'name',
+      },
+      layout: {
+        type: 'void',
+        'x-decorator': 'FormGrid',
+        'x-decorator-props': {
+          maxColumns: 2,
+          minColumns: 2,
+          columnGap: 24,
+        },
+        properties: {
+          product: {
+            title: '产品',
+            'x-decorator-props': {
+              gridSpan: 1,
+            },
+            type: 'string',
+            'x-decorator': 'FormItem',
+            'x-component': 'Select',
+            'x-component-props': {
+              placeholder: '请选择产品',
+              fieldNames: {
+                label: 'name',
+                value: 'id',
+              },
+            },
+            'x-reactions': '{{useAsyncDataSource(getProduct)}}',
+            required: true,
+          },
+          deviceType: {
+            title: '设备类型',
+            'x-decorator-props': {
+              gridSpan: 1,
+            },
+            type: 'string',
+            'x-decorator': 'FormItem',
+            'x-component': 'Select',
+            'x-component-props': {
+              placeholder: '请选择产品',
+              fieldNames: {
+                label: 'name',
+                value: 'id',
+              },
+            },
+            'x-reactions': '{{useAsyncDataSource(getTypes)}}',
+            required: true,
+          },
+        },
+      },
+      actionMappings: {
+        type: 'array',
+        title: '动作映射',
+        'x-component': 'ArrayCollapse',
+        'x-decorator': 'FormItem',
+        items: {
+          type: 'object',
+          'x-component': 'ArrayCollapse.CollapsePanel',
+          'x-component-props': {
+            header: '动作',
+          },
+          properties: {
+            index: {
+              type: 'void',
+              'x-component': 'ArrayCollapse.Index',
+            },
+            layout: {
+              type: 'void',
+              'x-decorator': 'FormGrid',
+              'x-decorator-props': {
+                maxColumns: 2,
+                minColumns: 2,
+                columnGap: 24,
+              },
+              properties: {
+                action: {
+                  title: '动作',
+                  'x-component': 'Select',
+                  'x-decorator': 'FormItem',
+                  'x-decorator-props': {
+                    layout: 'vertical',
+                    labelAlign: 'left',
+                  },
+                  required: true,
+                  'x-component-props': {
+                    fieldNames: {
+                      label: 'name',
+                      value: 'id',
+                    },
+                  },
+                },
+                actionType: {
+                  title: '操作',
+                  'x-component': 'Select',
+                  'x-decorator': 'FormItem',
+                  'x-decorator-props': {
+                    layout: 'vertical',
+                    labelAlign: 'left',
+                  },
+                  enum: [
+                    { label: '下发指令', value: 'command' },
+                    { label: '获取历史数据', value: 'latestData' },
+                  ],
+                },
+                command: {
+                  type: 'object',
+                  properties: {
+                    messageType: {
+                      type: 'string',
+                      title: '指令类型',
+                      'x-decorator-props': {
+                        layout: 'vertical',
+                        labelAlign: 'left',
+                        gridSpan: 2,
+                      },
+                      'x-component': 'Select',
+                      'x-decorator': 'FormItem',
+                      enum: [
+                        { label: '读取属性', value: 'READ_PROPERTY' },
+                        { label: '修改属性', value: 'WRITE_PROPERTY' },
+                        { label: '调用功能', value: 'INVOKE_FUNCTION' },
+                      ],
+                      'x-reactions': {
+                        dependencies: ['..actionType'],
+                        fulfill: {
+                          state: {
+                            visible: '{{$deps[0]==="command"}}',
+                          },
+                        },
+                      },
+                    },
+                    message: {
+                      type: 'object',
+                      properties: {
+                        properties: {
+                          title: '属性',
+                          'x-component': 'Select',
+                          'x-decorator': 'FormItem',
+                          'x-decorator-props': {
+                            layout: 'vertical',
+                            labelAlign: 'left',
+                          },
+                          'x-reactions': [
+                            {
+                              dependencies: ['..messageType'],
+                              fulfill: {
+                                state: {
+                                  visible:
+                                    '{{["READ_PROPERTY","WRITE_PROPERTY"].includes($deps[0])}}',
+                                },
+                              },
+                            },
+                            {
+                              dependencies: ['..messageType'],
+                              fulfill: {
+                                state: {
+                                  decoratorProps: {
+                                    gridSpan: '{{$deps[0]==="READ_PROPERTY"?2:1}}',
+                                  },
+                                },
+                              },
+                            },
+                          ],
+                        },
+                        value: {
+                          title: '值',
+                          'x-component': 'Input',
+                          'x-decorator': 'FormItem',
+                          'x-decorator-props': {
+                            layout: 'vertical',
+                            labelAlign: 'left',
+                          },
+                          'x-reactions': {
+                            dependencies: ['..messageType'],
+                            fulfill: {
+                              state: {
+                                visible: '{{["WRITE_PROPERTY"].includes($deps[0])}}',
+                              },
+                            },
+                          },
+                        },
+                        function: {
+                          title: '参数列表',
+                          'x-component': 'Input',
+                          'x-decorator': 'FormItem',
+                          'x-decorator-props': {
+                            layout: 'vertical',
+                            labelAlign: 'left',
+                          },
+                          'x-reactions': {
+                            dependencies: ['..messageType'],
+                            fulfill: {
+                              state: {
+                                visible: '{{["INVOKE_FUNCTION"].includes($deps[0])}}',
+                              },
+                            },
+                          },
+                        },
+                      },
+                    },
+                  },
+                },
+              },
+            },
+            remove: {
+              type: 'void',
+              'x-component': 'ArrayCollapse.Remove',
+            },
+          },
+        },
+        properties: {
+          addition: {
+            type: 'void',
+            title: '新增动作',
+            'x-component': 'ArrayCollapse.Addition',
+          },
+        },
+      },
+      propertyMappings: {
+        title: '属性映射',
+        type: 'array',
+        'x-component': 'ArrayCollapse',
+        'x-decorator': 'FormItem',
+        items: {
+          type: 'void',
+          'x-component': 'ArrayCollapse.CollapsePanel',
+          'x-component-props': {
+            header: '动作',
+          },
+          properties: {
+            index: {
+              type: 'void',
+              'x-component': 'ArrayCollapse.Index',
+            },
+            source: {
+              title: 'DuerOS属性',
+              'x-component': 'Select',
+              'x-decorator': 'FormItem',
+            },
+            target: {
+              title: '平台属性',
+              'x-component': 'Select',
+              'x-decorator': 'FormItem',
+            },
+            remove: {
+              type: 'void',
+              'x-component': 'ArrayCollapse.Remove',
+            },
+          },
+        },
+        properties: {
+          addition: {
+            type: 'void',
+            title: '新增属性',
+            'x-component': 'ArrayCollapse.Addition',
+          },
+        },
+      },
+    },
+  };
+
+  const handleSave = () => {};
+
+  const form = useMemo(
+    () =>
+      createForm({
+        validateFirst: true,
+        effects() {
+          onFieldInit('actionMappings.*.layout.action', (field) => {
+            const productType = field.query('deviceType').value();
+            if (!productType) return;
+            const _productTypes = Store.get('product-types');
+            const _type = _productTypes.find((item: any) => item.id === productType);
+            (field as Field).setDataSource(_type.actions);
+          });
+        },
+      }),
+    [],
+  );
+  return (
+    <PageContainer>
+      <Card>
+        <Row>
+          <Col span={10}>
+            <Form layout="vertical" form={form}>
+              <SchemaField schema={schema} scope={{ useAsyncDataSource, getTypes, getProduct }} />
+              <FormButtonGroup.Sticky>
+                <FormButtonGroup.FormItem>
+                  <PermissionButton type="primary" onClick={handleSave}>
+                    保存
+                  </PermissionButton>
+                </FormButtonGroup.FormItem>
+              </FormButtonGroup.Sticky>
+            </Form>
+          </Col>
+          <Col span={12} push={2}></Col>
+        </Row>
+      </Card>
+    </PageContainer>
+  );
+};
+
+export default Save;

+ 69 - 6
src/pages/Northbound/DuerOS/index.tsx

@@ -3,14 +3,26 @@ import SearchComponent from '@/components/SearchComponent';
 import { useRef, useState } from 'react';
 import type { ActionType, ProColumns } from '@jetlinks/pro-table';
 import { PermissionButton, ProTableCard } from '@/components';
-import { DeleteOutlined, EditOutlined, PlayCircleOutlined, StopOutlined } from '@ant-design/icons';
+import {
+  DeleteOutlined,
+  EditOutlined,
+  PlayCircleOutlined,
+  PlusOutlined,
+  StopOutlined,
+} from '@ant-design/icons';
 import { useIntl } from '@@/plugin-locale/localeExports';
+import { Space } from 'antd';
+import { DuerOSItem } from '@/pages/Northbound/DuerOS/types';
+import DuerOSCard from '@/components/ProTableCard/CardItems/duerOs';
+import { history } from '@@/core/history';
+import { getMenuPathByParams, MENUS_CODE } from '@/utils/menu';
+import Service from './service';
 
+export const service = new Service('dueros/product');
 export default () => {
   const actionRef = useRef<ActionType>();
   const intl = useIntl();
   const [searchParams, setSearchParams] = useState<any>({});
-
   const { permission } = PermissionButton.usePermission('Northbound/DuerOS');
 
   const Tools = (record: any, type: 'card' | 'table') => {
@@ -94,12 +106,37 @@ export default () => {
     ];
   };
 
-  const columns: ProColumns<DuerOSType>[] = [
+  const columns: ProColumns<DuerOSItem>[] = [
     {
+      title: intl.formatMessage({
+        id: 'pages.table.name',
+        defaultMessage: '名称',
+      }),
       dataIndex: 'name',
     },
     {
       title: intl.formatMessage({
+        id: 'pages.cloud.duerOS.applianceType',
+        defaultMessage: '设备类型',
+      }),
+      dataIndex: 'applianceType',
+    },
+    {
+      title: intl.formatMessage({
+        id: 'pages.cloud.duerOS.manufacturerName',
+        defaultMessage: '厂家名称',
+      }),
+      dataIndex: 'manufacturerName',
+    },
+    {
+      title: intl.formatMessage({
+        id: 'pages.cloud.duerOS.version',
+        defaultMessage: '动作数量',
+      }),
+      dataIndex: 'version',
+    },
+    {
+      title: intl.formatMessage({
         id: 'pages.data.option',
         defaultMessage: '操作',
       }),
@@ -112,22 +149,48 @@ export default () => {
 
   return (
     <PageContainer>
-      <SearchComponent<DuerOSType>
+      <SearchComponent<DuerOSItem>
         field={columns}
-        target="device-instance"
+        target="northbound-dueros"
         onSearch={(data) => {
           actionRef.current?.reset?.();
           setSearchParams(data);
         }}
       />
-      <ProTableCard<DuerOSType>
+      <ProTableCard<DuerOSItem>
         rowKey="id"
         search={false}
         columns={columns}
         actionRef={actionRef}
         params={searchParams}
         options={{ fullScreen: true }}
+        request={(params) =>
+          service.query({ ...params, sorts: [{ name: 'createTime', order: 'desc' }] })
+        }
+        cardRender={(record) => <DuerOSCard {...record} action={Tools(record, 'card')} />}
+        headerTitle={
+          <Space>
+            <PermissionButton
+              isPermission={true}
+              onClick={() => {
+                // setCurrent(undefined);
+                // setVisible(true);
+                // state.current = record;
+                history.push(getMenuPathByParams(MENUS_CODE['Northbound/DuerOS/Detail']));
+              }}
+              key="button"
+              icon={<PlusOutlined />}
+              type="primary"
+            >
+              {intl.formatMessage({
+                id: 'pages.data.option.add',
+                defaultMessage: '新增',
+              })}
+            </PermissionButton>
+          </Space>
+        }
       />
+      {/*<Save/>*/}
     </PageContainer>
   );
 };

+ 21 - 0
src/pages/Northbound/DuerOS/service.ts

@@ -0,0 +1,21 @@
+import BaseService from '@/utils/BaseService';
+import { request } from 'umi';
+import SystemConst from '@/utils/const';
+import { DuerOSItem } from '@/pages/Northbound/DuerOS/types';
+
+class Service extends BaseService<DuerOSItem> {
+  public getTypes = () =>
+    request(`${this.uri}/types`, {
+      method: 'GET',
+    });
+
+  public getProduct = () =>
+    request(`/${SystemConst.API_BASE}/device-product/_query/no-paging`, {
+      method: 'POST',
+      data: {
+        paging: false,
+      },
+    });
+}
+
+export default Service;

+ 22 - 3
src/pages/Northbound/DuerOS/types.d.ts

@@ -1,4 +1,23 @@
-type DuerOSType = {
-  id: string;
-  name: string;
+import { BaseItem } from '@/utils/typings';
+
+type PropertyMapping = {
+  source: string;
+  target: string[];
 };
+
+type ActionMapping = {
+  action: string;
+  actionType: string;
+  command: {
+    message: Record<string, any>;
+    messageType: string;
+  };
+};
+type DuerOSItem = {
+  version: number;
+  manufacturerName: string;
+  autoReportProperty: boolean;
+  applianceType: string;
+  actionMappings: ActionMapping[];
+  propertyMappings: PropertyMapping[];
+} & BaseItem;

+ 11 - 0
src/pages/cloud/DuerOS/Save/index.tsx

@@ -0,0 +1,11 @@
+import { Modal } from 'antd';
+
+const Save = () => {
+  return (
+    <Modal title="新增" visible>
+      。。。
+    </Modal>
+  );
+};
+
+export default Save;

+ 69 - 14
src/pages/cloud/DuerOS/index.tsx

@@ -1,12 +1,14 @@
 import BaseService from '@/utils/BaseService';
-import type { ProColumns, ActionType } from '@jetlinks/pro-table';
+import type { ActionType, ProColumns } from '@jetlinks/pro-table';
 import { PageContainer } from '@ant-design/pro-layout';
-import BaseCrud from '@/components/BaseCrud';
-import { useRef } from 'react';
-import { Tooltip } from 'antd';
-import { EditOutlined, MinusOutlined } from '@ant-design/icons';
+import { useRef, useState } from 'react';
+import { Space, Tooltip } from 'antd';
+import { DeleteOutlined, EditOutlined, MinusOutlined, PlusOutlined } from '@ant-design/icons';
 import type { DuerOSItem } from '@/pages/cloud/DuerOS/typings';
 import { useIntl } from '@@/plugin-locale/localeExports';
+import SearchComponent from '@/components/SearchComponent';
+import { PermissionButton, ProTableCard } from '@/components';
+import DuerOSCard from '@/components/ProTableCard/CardItems/duerOs';
 
 export const service = new BaseService<DuerOSItem>('dueros/product');
 const DuerOS = () => {
@@ -82,19 +84,72 @@ const DuerOS = () => {
       ],
     },
   ];
-  const schema = {};
+  // const schema = {};
 
+  const [param, setParam] = useState({});
   return (
     <PageContainer>
-      <BaseCrud<DuerOSItem>
-        columns={columns}
-        service={service}
-        title={intl.formatMessage({
-          id: 'pages.cloud.duerOS',
-          defaultMessage: 'DuerOS',
-        })}
-        schema={schema}
+      <SearchComponent
+        field={columns}
+        onSearch={(data) => {
+          actionRef.current?.reset?.();
+          setParam(data);
+        }}
+      />
+      <ProTableCard<any>
         actionRef={actionRef}
+        rowKey="id"
+        search={false}
+        params={param}
+        columns={columns}
+        request={(params) =>
+          service.query({ ...params, sorts: [{ name: 'createTime', order: 'desc' }] })
+        }
+        cardRender={(record) => (
+          <DuerOSCard
+            {...record}
+            action={[
+              <PermissionButton>
+                <EditOutlined />
+                编辑
+              </PermissionButton>,
+              <PermissionButton
+                type="link"
+                popConfirm={{
+                  disabled: record.state?.value !== 'disabled',
+                  title: '确认删除?',
+                  onConfirm: async () => {
+                    await service.remove(record.id);
+                    actionRef.current?.reset?.();
+                  },
+                }}
+                isPermission={true}
+                key="delete"
+              >
+                <DeleteOutlined />
+              </PermissionButton>,
+            ]}
+          />
+        )}
+        headerTitle={
+          <Space>
+            <PermissionButton
+              isPermission={true}
+              onClick={() => {
+                // setCurrent(undefined);
+                // setVisible(true);
+              }}
+              key="button"
+              icon={<PlusOutlined />}
+              type="primary"
+            >
+              {intl.formatMessage({
+                id: 'pages.data.option.add',
+                defaultMessage: '新增',
+              })}
+            </PermissionButton>
+          </Space>
+        }
       />
     </PageContainer>
   );

+ 30 - 8
src/pages/cloud/DuerOS/typings.d.ts

@@ -1,15 +1,37 @@
 import type { BaseItem } from '@/utils/typings';
 
-type Action = {
-  arg: unknown[];
-} & BaseItem;
+// type Action = {
+//   arg: unknown[];
+// } & BaseItem;
+//
+// type Mode = BaseItem;
+//
+// type Property = BaseItem;
 
-type Mode = BaseItem;
+// type DuerOSItem = {
+//   actions?: Action[];
+//   modes?: Mode[];
+//   properties?: Property[];
+// } & BaseItem;
 
-type Property = BaseItem;
+type PropertyMapping = {
+  source: string;
+  target: string[];
+};
 
+type ActionMapping = {
+  action: string;
+  actionType: string;
+  command: {
+    message: Record<string, any>;
+    messageType: string;
+  };
+};
 type DuerOSItem = {
-  actions: Action[];
-  modes: Mode[];
-  properties: Property[];
+  version: number;
+  manufacturerName: string;
+  autoReportProperty: boolean;
+  applianceType: string;
+  actionMappings: ActionMapping[];
+  propertyMappings: PropertyMapping[];
 } & BaseItem;

+ 1 - 0
src/utils/menu/router.ts

@@ -110,6 +110,7 @@ export enum MENUS_CODE {
   'system/Department/Detail' = 'system/Department/Detail',
   'link/Type/Detail' = 'link/Type/Detail',
   'Northbound/DuerOS' = 'Northbound/DuerOS',
+  'Northbound/DuerOS/Detail' = 'Northbound/DuerOS/Detail',
   'Northbound/AliCloud' = 'Northbound/AliCloud',
 }