antd/lib/table#SorterResult TypeScript Examples

The following examples show how to use antd/lib/table#SorterResult. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: ProTable.tsx    From jetlinks-ui-antd with MIT License 5 votes vote down vote up
ProTable = (props: Props) => {
    const { loading, dataSource, columns, rowKey, onSearch, paginationConfig,title } = props;

    const onTableChange = (
        pagination: PaginationConfig,
        filters: any,
        sorter: SorterResult<any>,
    ) => {
        onSearch({
            pageIndex: Number(pagination.current) - 1,
            pageSize: pagination.pageSize,
            sorts: sorter,
            terms: converFilter(filters, '$IN'),
        })
    };

    return (
        <Table
            {...props}
            size={props.size}
            // loading={loading}
            // dataSource={dataSource}
            // columns={columns}
            // rowKey={rowKey}
            onChange={onTableChange}
            pagination={typeof paginationConfig === "boolean" ? paginationConfig : {
                current: paginationConfig?.pageIndex + 1 || 0,
                total: paginationConfig?.total || 0,
                pageSize: paginationConfig?.pageSize || 0,
                showQuickJumper: true,
                showSizeChanger: true,
                pageSizeOptions: ['10', '20', '50', '100'],
                showTotal: (total: number) =>
                    `共 ${total} 条记录 第  ${paginationConfig?.pageIndex + 1}/${Math.ceil(
                        paginationConfig?.total / paginationConfig?.pageSize,
                    )}页`,
            }}
        />
    )
}
Example #2
Source File: ChoiceDevice.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
ChoiceDevice: React.FC<Props> = props => {
  const initState: State = {
    searchParam: {pageSize: 10, terms: {
      "id$dev-group$not": props.parentId
    }},
    deviceData: {},
    deviceList: []
  };

  const [searchParam, setSearchParam] = useState(initState.searchParam);
  const [deviceData, setDeviceData] = useState(initState.deviceData);
  const [deviceList, setDeviceList] = useState(initState.deviceList);
  const [spinning, setSpinning] = useState(true);

  const handleSearch = (params?: any) => {
    setSearchParam(params);
    apis.deviceInstance
      .list(encodeQueryParam(params))
      .then(response => {
        if (response.status === 200) {
          setDeviceData(response.result);
        }
        setSpinning(false);
      })
      .catch(() => {
      });
  };

  useEffect(() => {
    handleSearch(searchParam);
  }, []);

  const onTableChange = (
    pagination: PaginationConfig,
    filters: any,
    sorter: SorterResult<DeviceInstance>,
  ) => {
    handleSearch({
      pageIndex: Number(pagination.current) - 1,
      pageSize: pagination.pageSize,
      terms: searchParam.terms,
      sorts: sorter,
    });
  };

  const rowSelection = {
    onChange: (selectedRowKeys: any) => {
      setDeviceList(selectedRowKeys);
      props.save(selectedRowKeys);
    },
  };

  const statusMap = new Map();
  statusMap.set('在线', 'success');
  statusMap.set('离线', 'error');
  statusMap.set('未激活', 'processing');

  const columns: ColumnProps<DeviceInstance>[] = [
    {
      title: 'ID',
      dataIndex: 'id',
      ellipsis: true,
    },
    {
      title: '设备名称',
      dataIndex: 'name',
      ellipsis: true,
    },
    {
      title: '产品名称',
      dataIndex: 'productName',
      ellipsis: true,
    },
    {
      title: '注册时间',
      dataIndex: 'registryTime',
      width: '200px',
      render: (text: any) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
      sorter: true,
      defaultSortOrder: 'descend',
      ellipsis: true,
    },
    {
      title: '状态',
      dataIndex: 'state',
      width: '80px',
      render: record =>
        record ? <Badge status={statusMap.get(record.text)} text={record.text}/> : '',
    },
  ];

  return (
    <Spin spinning={spinning}>
      <div className={styles.tableList}>
        <div className={styles.tableListForm}>
          <Search
            search={(params: any) => {
              setSearchParam({...searchParam, ...params});
              handleSearch({terms: {...searchParam.terms, ...params}, sorter: searchParam.sorter, pageSize: 10});
            }}
          />
        </div>
        <div className={styles.StandardTable}>
          <Table
            columns={columns}
            dataSource={deviceData.data}
            rowKey="id"
            onChange={onTableChange}
            rowSelection={{
              type: 'checkbox',
              ...rowSelection,
              selectedRowKeys: deviceList
            }}
            size='middle'
            pagination={{
              current: deviceData.pageIndex + 1,
              total: deviceData.total,
              pageSize: deviceData.pageSize,
              showQuickJumper: true,
              showSizeChanger: true,
              pageSizeOptions: ['10', '20', '50', '100'],
              showTotal: (total: number) =>
                `共 ${total} 条记录 第  ${deviceData.pageIndex + 1}/${Math.ceil(
                  deviceData.total / deviceData.pageSize,
                )}页`,
            }}
          />
        </div>
      </div>
    </Spin>
  );
}
Example #3
Source File: bind.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
DeviceGatewayBind: React.FC<Props> = props => {
  const initState: State = {
    searchParam: {pageSize: 10},
    deviceData: {},
    deviceId: [],
  };

  const [searchParam, setSearchParam] = useState(initState.searchParam);
  const [deviceData, setDeviceData] = useState(initState.deviceData);
  const [deviceId, setDeviceId] = useState(initState.deviceId);

  const submitData = () => {
    props.save(deviceId);
  };

  const handleSearch = (params?: any) => {
    setSearchParam(params);
    apis.deviceInstance
      .list(encodeQueryParam(params))
      .then(response => {
        if (response.status === 200) {
          setDeviceData(response.result);
        }
      })
      .catch(() => {
      });
  };

  useEffect(() => {
    if (props.selectionType === 'checkbox') {
      searchParam.terms = {parentId$isnull: 1};
    }
    handleSearch(searchParam);
  }, []);

  const onTableChange = (pagination: PaginationConfig, filters: any, sorter: SorterResult<any>) => {
    apis.deviceInstance
      .list(
        encodeQueryParam({
          pageIndex: Number(pagination.current) - 1,
          pageSize: pagination.pageSize,
          sorts: sorter,
        }),
      )
      .then(response => {
        if (response.status === 200) {
          setDeviceData(response.result);
        }
      })
      .catch(() => {
      });
  };

  const rowSelection = {
    onChange: (selectedRowKeys: any) => {
      setDeviceId(selectedRowKeys);
    },
  };

  const statusMap = new Map();
  statusMap.set('在线', 'success');
  statusMap.set('离线', 'error');
  statusMap.set('未激活', 'processing');

  const columns: ColumnProps<DeviceInstance>[] = [
    {
      title: 'ID',
      dataIndex: 'id',
      ellipsis: true,
    },
    {
      title: '设备名称',
      dataIndex: 'name',
      ellipsis: true,
    },
    {
      title: '产品名称',
      dataIndex: 'productName',
      ellipsis: true,
    },
    {
      title: '注册时间',
      dataIndex: 'registryTime',
      width: '200px',
      ellipsis: true,
      render: (text: any) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
      sorter: true,
      defaultSortOrder: 'descend',
    },
    {
      title: '状态',
      dataIndex: 'state',
      width: '120px',
      render: record =>
        record ? <Badge status={statusMap.get(record.text)} text={record.text}/> : '',
    }
  ];

  return (
    <Modal
      title="绑定子设备"
      visible
      okText="确定"
      cancelText="取消"
      onOk={() => {
        submitData();
      }}
      width="60%"
      style={{marginTop: -30}}
      onCancel={() => props.close()}
    >
      <div className={styles.tableList} style={{maxHeight: 600, overflowY: 'auto', overflowX: 'hidden'}}>
        <div className={styles.tableListForm}>
          <Search
            search={(params: any) => {
              setSearchParam(params);
              if (props.selectionType === 'checkbox') {
                params['parentId$isnull'] = 1;
              }
              handleSearch({terms: params, sorter: searchParam.sorter, pageSize: 10});
            }}
          />
        </div>

        <div className={styles.StandardTable}>
          <Table
            columns={columns}
            dataSource={deviceData.data}
            rowKey="id"
            onChange={onTableChange}
            rowSelection={{
              type: props.selectionType,
              ...rowSelection,
            }}
            pagination={{
              current: deviceData.pageIndex + 1,
              total: deviceData.total,
              pageSize: deviceData.pageSize,
              showQuickJumper: true,
              showSizeChanger: true,
              pageSizeOptions: ['10', '20', '50', '100'],
              showTotal: (total: number) =>
                `共 ${total} 条记录 第  ${deviceData.pageIndex + 1}/${Math.ceil(
                  deviceData.total / deviceData.pageSize,
                )}页`,
            }}
          />
        </div>
      </div>
    </Modal>
  );
}
Example #4
Source File: bind-device.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
BindDevice: React.FC<Props> = props => {

    const [deviceData, setDeviceData] = useState<any>({});
    const [clusterList, setClusterList] = useState<any[]>([]);
    const [cluster, setCluster] = useState<string>("");
    const [current, setCurrent] = useState(0);
    const [deviceIds, setDeviceIds] = useState<any[]>([]);
    const [searchParam, setSearchParam] = useState({ pageSize: 10, terms: {} });

    const handleSearch = (params: any) => {
        params.terms = {
            ...params.terms,
            'productId$dev-protocol': 'opc-ua'
        }
        setSearchParam(params);
        apis.deviceInstance.list(encodeQueryParam(params))
            .then(response => {
                if (response.status === 200) {
                    setDeviceData(response.result);
                }
            })
            .catch(() => {
            });
    }

    const queryClusterList = () => {
        apis.opcUa.clusterList().then(res => {
            if (res.status === 200) {
                setClusterList(res.result);
            }
        })
    };

    const statusMap = new Map();
    statusMap.set('在线', 'success');
    statusMap.set('离线', 'error');
    statusMap.set('未激活', 'processing');

    const steps = [
        {
            title: '选择集群'
        },
        {
            title: '绑定设备'
        }
    ];

    const columns = [
        {
            title: 'ID',
            dataIndex: 'id',
            ellipsis: true,
        },
        {
            title: '设备名称',
            dataIndex: 'name',
            ellipsis: true,
        },
        {
            title: '产品名称',
            dataIndex: 'productName',
            ellipsis: true,
        },
        {
            title: '注册时间',
            dataIndex: 'registryTime',
            width: '200px',
            ellipsis: true,
            render: (text: any) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
            sorter: true,
            defaultSortOrder: 'descend',
        },
        {
            title: '状态',
            dataIndex: 'state',
            width: '120px',
            render: (record: any) =>
                record ? <Badge status={statusMap.get(record.text)} text={record.text} /> : '',
        }
    ];

    const onTableChange = (pagination: PaginationConfig, filters: any, sorter: SorterResult<any>) => {
        handleSearch({
            pageIndex: Number(pagination.current) - 1,
            pageSize: pagination.pageSize,
            terms: searchParam.terms
        })
    };

    const renderFooter = () => (
        <div>
            {current > 0 && (<Button onClick={() => { setCurrent(current - 1) }}>上一步</Button>)}
            {current < steps.length - 1 && (<Button onClick={() => {
                if (cluster !== '') {
                    setCurrent(current + 1);
                } else {
                    message.error('请选择集群');
                }
            }}>下一步</Button>)}
            {current === steps.length - 1 && (
                <Button type="primary" onClick={() => { props.close() }}>确认</Button>
            )}
        </div>
    )

    const getBindedDevice = () => {
        //获取已绑定数据
        apis.opcUa.getDeviceBindListNoPaging(encodeQueryParam({
            terms: {
                opcUaId: props.opcId
            }
        })).then(resp => {
            let children: any[] = [];
            resp.result.map((item: any) => {
                children.push(item.deviceId);
            })
            setDeviceIds(children);
        })
    }

    const unbindSelection = {
        onChange: (selectedRowKeys: any) => {
            setDeviceIds(selectedRowKeys);
        },
        onSelect: (record: any, selected: any) => {
            let list: string[] = [record.id];
            if (selected) {
                _bind(list);
            } else {
                _unbind(list);
            }
        },
        onSelectAll: (selected: any, selectedRows: any, changeRows: any) => {
            let list: string[] = [];
            changeRows.map((item: any) => {
                list.push(item.id);
            });
            if (selected) {
                _bind(list);
            } else {
                _unbind(list);
            }
        },
    };

    const _bind = (deviceIds: string[]) => {
        let data: any[] = deviceData.data || [];
        let params: any[] = [];
        deviceIds.map((item: any) => {
            let device = data.filter(i => {
                return i.id === item
            })
            params.push({
                deviceId: item,
                opcUaId: props.opcId,
                serverId: cluster,
                productId: device[0].productId,
                deviceName: device[0].name,
                productName: device[0].productName
            })
        })
        apis.opcUa.bindManyDevice(params).then(res => {
            if (res.status === 200) {
                message.success('绑定成功!');
            }else{
                message.error('绑定失败')
            }
        })
    };

    const _unbind = (deviceIds: string[]) => {
        apis.opcUa.removeManyBind(props.opcId, deviceIds).then(res => {
            if (res.status === 200) {
                message.success('解绑成功!');
            }else{
                message.success('解绑失败!');
            }
        })
    };

    useEffect(() => {
        queryClusterList();
        handleSearch(searchParam);
        getBindedDevice();
    }, []);

    return (
        <Modal
            title='绑定设备'
            visible
            width={1000}
            footer={renderFooter()}
            onCancel={() => {
                props.close();
            }}
        >
            <div style={{ padding: '10px' }}>
                <div>
                    {current === 0 ?
                        <Form labelCol={{ span: 2 }} wrapperCol={{ span: 22 }}>
                            <Form.Item key="clusterId" label="集群">
                                <Select placeholder="请选择" value={cluster}
                                    onChange={(value: string) => {
                                        setCluster(value);
                                    }}>
                                    {(clusterList || []).map(item => (
                                        <Select.Option
                                            key={item.id}
                                            value={item.id}
                                        >
                                            {item.id}
                                        </Select.Option>
                                    ))}
                                </Select>
                            </Form.Item>
                        </Form> :
                        <div className={styles.tableList}>
                            <div className={styles.tableListForm}>
                                <Search
                                    search={(params: any) => {
                                        setSearchParam(params);
                                        handleSearch({ terms: params, sorter: searchParam.sorter, pageSize: 10 });
                                    }}
                                />
                            </div>

                            <div className={styles.StandardTable}>
                                <Table
                                    scroll={{
                                        y: '450px'
                                    }}
                                    columns={columns}
                                    dataSource={deviceData.data}
                                    rowKey="id"
                                    onChange={onTableChange}
                                    rowSelection={{
                                        type: 'checkbox',
                                        selectedRowKeys: deviceIds,
                                        ...unbindSelection
                                    }}
                                    pagination={{
                                        current: deviceData.pageIndex + 1,
                                        total: deviceData.total,
                                        pageSize: deviceData.pageSize
                                    }}
                                />
                            </div>
                        </div>
                    }
                </div>
            </div>
        </Modal>
    );
}
Example #5
Source File: index.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
MediaDevice: React.FC<Props> = props => {
  const {location: {pathname},} = props;
  const service = new Service('media/channel');
  const [loading, setLoading] = useState<boolean>(false);
  const [deviceId, setDeviceId] = useState<string>("");
  const [result, setResult] = useState<any>({});
  const [deviceInfo, setDeviceInfo] = useState<any>({});
  const [channel, setChannel] = useState<boolean>(false);
  const [channelInfo, setChannelInfo] = useState<any>({});
  const [playing, setPlaying] = useState<boolean>(false);
  const [playback, setPalyback] = useState<boolean>(false)
  const [data, setData] = useState<any>({});

  const [searchParam, setSearchParam] = useState(initState.searchParam);
  const statusMap = new Map();
  statusMap.set('online', 'success');
  statusMap.set('offline', 'error');
  statusMap.set('notActive', 'processing');

  const ptzType = new Map();
  ptzType.set(0, '未知');
  ptzType.set(1, '球体');
  ptzType.set(2, '半球体');
  ptzType.set(3, '固定枪机');
  ptzType.set(4, '遥控枪机');

  const deviceDetail = (deviceId: string) => {
    service.mediaDevice(deviceId).subscribe((data) => {
        setDeviceInfo(data);
      },
      () => {
      },
      () => {
      })
  };

  const handleSearch = (params?: any) => {
    setSearchParam(params);
    setLoading(true);
    service.query(encodeQueryParam(params)).subscribe(
      data => setResult(data),
      () => {
      },
      () => setLoading(false));
  };


  const columns: ColumnProps<any>[] = [
    {
      title: '通道国标编号',
      dataIndex: 'channelId',
      ellipsis: true,
    },
    {
      title: '通道名称',
      dataIndex: 'name',
      ellipsis: true,
    },
    {
      title: '厂商',
      dataIndex: 'manufacturer',
      width: 100,
      ellipsis: true,
    },
    {
      title: '安装地址',
      dataIndex: 'address',
      width: '10%',
      ellipsis: true,
    },
    {
      title: '云台类型',
      dataIndex: 'ptzType',
      width: 100,
      render: record => ptzType.get(record?.value || 0),
      ellipsis: true,
    },
    {
      title: '在线状态',
      dataIndex: 'status',
      width: 110,
      render: record => record ? <Badge status={statusMap.get(record.value)} text={record.text}/> : '',
      filters: [
        {
          text: '离线',
          value: 'offline',
        },
        {
          text: '在线',
          value: 'online',
        },
      ],
      filterMultiple: false,
    },
    {
      title: '经纬度',
      width: 200,
      ellipsis: true,
      render: (record: any) => (
        <span>{record.longitude ? `${record.longitude ? record.longitude : ''},${record.latitude ? record.latitude : ''}` : ''}</span>
      )
    },
    {
      title: '子通道数',
      dataIndex: 'subCount',
      width: 100,
    },
    {
      title: '描述',
      dataIndex: 'description',
      width: '10%',
      ellipsis: true
    },
    {
      title: '操作',
      align: 'center',
      // fixed: 'right',
      render: (record: any) => (
        <Fragment>
          <a
            onClick={() => {
              setChannel(true);
              setChannelInfo(record);
            }}
          >
            编辑
          </a>
          <Divider type="vertical"/>
          {record.status.value === 'online' ? (
            <>
              <a
                onClick={() => {
                  setPlaying(true);
                  setData(record)
                }}
              >
                播放
              </a>
              <Divider type="vertical"/>
              <a
                onClick={() => {
                  setPalyback(true);
                  setData(record)
                }}
              >
                回放
              </a>
            </>
          ) : (
            <Popconfirm
              placement="topRight"
              title="确定删除此通道吗?"
              onConfirm={() => {
                setLoading(true);
                service.remove(record.id).subscribe(
                  () => {
                    message.success('通道删除成功');
                  },
                  () => {
                    message.error('通道删除失败');
                  },
                  () => {
                    handleSearch(searchParam);
                    setLoading(false);
                  },
                );
              }}
            >
              <a>删除</a>
            </Popconfirm>
          )}
        </Fragment>
      )
    },
  ];

  useEffect(() => {
    if (pathname.indexOf('channel') > 0) {
      const list = pathname.split('/');
      deviceDetail(list[list.length - 1]);
      setDeviceId(list[list.length - 1]);
      searchParam.terms = {deviceId: list[list.length - 1]};
      handleSearch(searchParam);
    }
  }, [window.location.hash]);


  const onTableChange = (
    pagination: PaginationConfig,
    filters: any,
    sorter: SorterResult<DeviceInstance>,
  ) => {
    const {terms} = searchParam;

    handleSearch({
      pageIndex: Number(pagination.current) - 1,
      pageSize: pagination.pageSize,
      terms: {...terms, ...filters},
      sorts: sorter,
    })
  };

  const content = (
    <div style={{marginTop: 30}}>
      <Descriptions column={4}>
        <Descriptions.Item label="设备名称">
          <div>
            {deviceInfo.name}
          </div>
        </Descriptions.Item>
      </Descriptions>
    </div>
  );

  const titleInfo = (
    <Row>
      <div>
        <span style={{paddingRight: 20}}>
          通道列表:{deviceId}
        </span>
        <Badge status={statusMap.get(deviceInfo.state?.value)} text={deviceInfo.state?.text}/>
      </div>
    </Row>
  );

  return (
    <PageHeaderWrapper title={titleInfo} content={content}>
      <Card style={{height: 92, marginBottom: 16}}>
        <div className={styles.tableList} style={{marginTop: -22}}>
          <div>
            <SearchForm
              search={(params: any) => {
                setSearchParam(params);
                params ? params.deviceId = deviceId : params = {deviceId: deviceId};
                handleSearch({pageSize: 10, terms: {...params}, sorts: {field: 'id', order: 'desc'}});
              }}
              formItems={[
                {
                  label: '名称',
                  key: 'name$LIKE',
                  type: 'string',
                },
              ]}
            />
          </div>
        </div>
      </Card>
      <Card>
        <div className={styles.StandardTable}>
          <Table
            loading={loading}
            columns={columns}
            dataSource={(result || {}).data}
            rowKey="id"
            onChange={onTableChange}
            pagination={{
              current: result?.pageIndex + 1,
              total: result?.total,
              pageSize: result?.pageSize,
              showQuickJumper: true,
              showSizeChanger: true,
              pageSizeOptions: ['10', '20', '50', '100'],
              showTotal: (total: number) =>
                `共 ${total} 条记录 第  ${result?.pageIndex + 1}/${Math.ceil(
                  result?.total / result?.pageSize,
                )}页`,
            }}
          />
        </div>
      </Card>
      {playing && <Play data={data} close={() => {
        setPlaying(false)
      }} ok={() => {
        setPlaying(false)
      }}/>}

      {channel && <ChannelEdit data={channelInfo} close={() => {
        setChannel(false);
        handleSearch(searchParam);
      }}/>
      }
      {playback && <Playback data={data} close={() => {
        setPalyback(false)
      }} ok={() => {
        setPalyback(false)
      }} />}
    </PageHeaderWrapper>
  )
}
Example #6
Source File: bind.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
DeviceGatewayBind: React.FC<Props> = props => {

  const service = new Service('device-network');
  const initState: State = {
    searchParam: { pageSize: 10 },
    deviceData: {},
    deviceId: [],
  };

  const [searchParam, setSearchParam] = useState(initState.searchParam);
  const [deviceData, setDeviceData] = useState(initState.deviceData);
  const [deviceId, setDeviceId] = useState(initState.deviceId);

  const submitData = () => {
    props.save(deviceId);
  };

  const handleSearch = (params?: any) => {
    setSearchParam(params);
    service.getDeviceList(props.deviceId, params).subscribe(
      (res) => {
        setDeviceData(res)
      })
    // apis.deviceInstance
    //   .list(encodeQueryParam(params))
    //   .then(response => {
    //     if (response.status === 200) {
    //       setDeviceData(response.result);
    //     }
    //   })
    //   .catch(() => {
    //   });
  };

  useEffect(() => {
    if (props.selectionType === 'checkbox') {
      searchParam.terms = { parentId$isnull: 1 };
    }
    handleSearch(searchParam);
  }, []);

  const onTableChange = (pagination: PaginationConfig, filters: any, sorter: SorterResult<any>) => {
    service.getDeviceList(props.deviceId, encodeQueryParam({
      pageIndex: Number(pagination.current) - 1,
      pageSize: pagination.pageSize,
      sorts: sorter,
    })).subscribe(
      (res) => {
        setDeviceData(res)
      })
  };

  const rowSelection = {
    onChange: (selectedRowKeys: any) => {
      setDeviceId(selectedRowKeys);
    },
  };

  const statusMap = new Map();
  statusMap.set('在线', 'success');
  statusMap.set('离线', 'error');
  statusMap.set('未激活', 'processing');

  const columns = [
    {
      title: 'ID',
      dataIndex: 'id',
      ellipsis: true,
    },
    {
      title: '设备名称',
      dataIndex: 'name',
      ellipsis: true,
    },
    {
      title: '产品名称',
      dataIndex: 'productName',
      ellipsis: true,
    },
    {
      title: '注册时间',
      dataIndex: 'registryTime',
      width: '200px',
      ellipsis: true,
      render: (text: any) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
      sorter: true,
      defaultSortOrder: 'descend',
    },
    {
      title: '状态',
      dataIndex: 'state',
      width: '120px',
      render: record =>
        record ? <Badge status={statusMap.get(record.text)} text={record.text} /> : '',
    }
  ];

  return (
    <Modal
      title="绑定子设备"
      visible
      okText="确定"
      cancelText="取消"
      onOk={() => {
        submitData();
      }}
      width="60%"
      style={{ marginTop: -30 }}
      onCancel={() => props.close()}
    >
      <div className={styles.tableList} style={{ maxHeight: 600, overflowY: 'auto', overflowX: 'hidden' }}>
        <div className={styles.tableListForm}>
          <SearchForm
            formItems={[
              {
                label: '名称',
                key: 'name',
                type: 'string',
              }
            ]}
            search={(params: any) => {
              if (params?.name) {
                setSearchParam({
                  where: `name like '%${params?.name}%'`,
                  pageSize: 10
                })
                handleSearch({
                  where: `name like '%${params?.name}%'`,
                  pageSize: 10
                });
              } else {
                setSearchParam({ pageSize: 10 })
                handleSearch({ pageSize: 10 });
              }
            }}
          />
        </div>

        <div className={styles.StandardTable}>
          <Table
            columns={columns}
            dataSource={deviceData.data}
            rowKey="id"
            onChange={onTableChange}
            rowSelection={{
              type: props.selectionType,
              ...rowSelection,
            }}
            pagination={{
              current: deviceData.pageIndex + 1,
              total: deviceData.total,
              pageSize: deviceData.pageSize,
              showQuickJumper: true,
              showSizeChanger: true,
              pageSizeOptions: ['10', '20', '50', '100'],
              showTotal: (total: number) =>
                `共 ${total} 条记录 第  ${deviceData.pageIndex + 1}/${Math.ceil(
                  deviceData.total / deviceData.pageSize,
                )}页`,
            }}
          />
        </div>
      </div>
    </Modal>
  );
}
Example #7
Source File: index.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
DeviceInstancePage: React.FC<Props> = props => {
  const { result } = props.deviceInstance;
  const { dispatch, location } = props;

  const map = new Map();
  map.set('id', 'id$like');
  map.set('name', 'name$like');
  map.set('orgId', 'orgId$in');
  map.set('devTag', 'id$dev-tag');
  map.set('devBind', 'id$dev-bind$any');
  map.set('devProd', 'productId$dev-prod-cat');
  map.set('productId', 'productId');

  const initState: State = {
    data: result,
    searchParam: {
      pageSize: 10,
      terms: location?.query?.terms,
      sorts: {
        order: 'desc',
        field: 'id',
      },
    },
    addVisible: false,
    currentItem: {},
    processVisible: false,
    importLoading: false,
    action: '',
    deviceCount: {
      notActiveCount: 0,
      offlineCount: 0,
      onlineCount: 0,
      deviceTotal: 0,
      loading: true,
    },
    productList: [],
    deviceIdList: [],
  };

  const [searchParam, setSearchParam] = useState(initState.searchParam);
  const [addVisible, setAddVisible] = useState(initState.addVisible);
  const [currentItem, setCurrentItem] = useState(initState.currentItem);
  const [importLoading, setImportLoading] = useState(initState.importLoading);
  const [action, setAction] = useState(initState.action);
  const [productList, setProductList] = useState(initState.productList);
  const [product, setProduct] = useState<string>();
  const [deviceCount, setDeviceCount] = useState(initState.deviceCount);
  const [deviceImport, setDeviceImport] = useState(false);
  const [deviceExport, setDeviceExport] = useState(false);
  const [deviceIdList, setDeviceIdLIst] = useState(initState.deviceIdList);

  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 handleSearch = (params?: any) => {
    setSearchParam(params);
    dispatch({
      type: 'deviceInstance/query',
      payload: encodeQueryParam(params),
    });
  };

  const delelteInstance = (record: any) => {
    apis.deviceInstance
      .remove(record.id)
      .then(response => {
        if (response.status === 200) {
          message.success('操作成功');
          deviceIdList.splice(0, deviceIdList.length);
          handleSearch(searchParam);
        }
      })
      .catch(() => {});
  };

  const changeDeploy = (record: any) => {
    apis.deviceInstance
      .changeDeploy(record.id)
      .then(response => {
        if (response.status === 200) {
          message.success('操作成功');
          deviceIdList.splice(0, deviceIdList.length);
          handleSearch(searchParam);
        }
      })
      .catch(() => {});
  };

  const unDeploy = (record: any) => {
    apis.deviceInstance
      .unDeploy(record.id)
      .then(response => {
        if (response.status === 200) {
          message.success('操作成功');
          deviceIdList.splice(0, deviceIdList.length);
          handleSearch(searchParam);
        }
      })
      .catch(() => {});
  };
  const columns: ColumnProps<DeviceInstance>[] = [
    {
      title: 'ID',
      dataIndex: 'id',
    },
    {
      title: '设备名称',
      dataIndex: 'name',
      ellipsis: true,
    },
    {
      title: '产品名称',
      dataIndex: 'productName',
      ellipsis: true,
    },
    {
      title: '注册时间',
      dataIndex: 'registryTime',
      width: '200px',
      render: (text: any) => (text ? moment(text).format('YYYY-MM-DD HH:mm:ss') : '/'),
      sorter: true,
    },
    {
      title: '状态',
      dataIndex: 'state',
      width: '90px',
      render: record =>
        record ? <Badge status={statusMap.get(record.value)} text={record.text} /> : '',
      filters: [
        {
          text: '未启用',
          value: 'notActive',
        },
        {
          text: '离线',
          value: 'offline',
        },
        {
          text: '在线',
          value: 'online',
        },
      ],
      filterMultiple: false,
    },
    {
      title: '说明',
      dataIndex: 'describe',
      width: '15%',
      ellipsis: true,
    },
    {
      title: '操作',
      width: '200px',
      align: 'center',
      render: (record: any) => (
        <Fragment>
          <a
            onClick={() => {
              router.push(`/device/instance/save/${record.id}`);
            }}
          >
            查看
          </a>
          <Divider type="vertical" />
          <a
            onClick={() => {
              setCurrentItem(record);
              setAddVisible(true);
            }}
          >
            编辑
          </a>
          <Divider type="vertical" />
          {record.state?.value === 'notActive' ? (
            <span>
              <Popconfirm
                title="确认启用?"
                onConfirm={() => {
                  changeDeploy(record);
                }}
              >
                <a>启用</a>
              </Popconfirm>
              <Divider type="vertical" />
              <Popconfirm
                title="确认删除?"
                onConfirm={() => {
                  delelteInstance(record);
                }}
              >
                <a>删除</a>
              </Popconfirm>
            </span>
          ) : (
            <Popconfirm
              title="确认禁用设备?"
              onConfirm={() => {
                unDeploy(record);
              }}
            >
              <a>禁用</a>
            </Popconfirm>
          )}
        </Fragment>
      ),
    },
  ];

  const stateCount = (productId: string) => {
    const map = {
      notActiveCount: 0,
      offlineCount: 0,
      onlineCount: 0,
      deviceTotal: 0,
      loading: true,
    };

    apis.deviceInstance
      .count(
        encodeQueryParam({
          terms: {
            state: 'notActive',
            productId,
            ...location?.query?.terms,
            ...(location?.query.iop && JSON.parse(location?.query.iop)?.terms),
          },
        }),
      )
      .then(res => {
        if (res.status === 200) {
          map.notActiveCount = res.result;
          setDeviceCount({ ...map });
        }
      })
      .catch();
    apis.deviceInstance
      .count(
        encodeQueryParam({
          terms: {
            state: 'offline',
            productId,
            ...location?.query?.terms,
            ...(location?.query.iop && JSON.parse(location?.query.iop)?.terms),
          },
        }),
      )
      .then(res => {
        if (res.status === 200) {
          map.offlineCount = res.result;
          setDeviceCount({ ...map });
        }
      })
      .catch();
    apis.deviceInstance
      .count(
        encodeQueryParam({
          terms: {
            state: 'online',
            productId,
            ...location?.query?.terms,
            ...(location?.query.iop && JSON.parse(location?.query.iop)?.terms),
          },
        }),
      )
      .then(res => {
        if (res.status === 200) {
          map.onlineCount = res.result;
          setDeviceCount({ ...map });
        }
      })
      .catch();
    apis.deviceInstance
      .count(
        encodeQueryParam({
          terms: {
            productId,
            ...location?.query?.terms,
            ...(location?.query.iop && JSON.parse(location?.query.iop)?.terms),
          },
        }),
      )
      .then(res => {
        if (res.status === 200) {
          map.deviceTotal = res.result;
          map.loading = false;
          setDeviceCount({ ...map });
        }
      })
      .catch();
  };

  useEffect(() => {
    // 获取下拉框数据
    apis.deviceProdcut
      .queryNoPagin(
        encodeQueryParam({
          paging: false,
        }),
      )
      .then(e => {
        setProductList(e.result);
      })
      .catch(() => {});

    const query: any = getPageQuery();
    if (query.hasOwnProperty('productId')) {
      const { productId } = query;
      setProduct(productId);
      handleSearch({
        terms: {
          productId: query.productId,
        },
        pageSize: 10,
      });
      stateCount(productId);
    } else if (location?.query) {
      let key = Object.keys(location?.query)[0];
      let params = {};
      params[map.get(key)] = location?.query[key];
      handleSearch({
        terms: { ...params, ...(location?.query.iop && JSON.parse(location?.query.iop)?.terms) },
        pageSize: 10,
        sorts: searchParam.sorts,
      });
      stateCount('');
    } else {
      handleSearch(searchParam);
      stateCount('');
    }
  }, []);

  const onTableChange = (
    pagination: PaginationConfig,
    filters: any,
    sorter: SorterResult<DeviceInstance>,
  ) => {
    let { terms } = searchParam;
    if (filters.state) {
      if (terms) {
        terms.state = filters.state[0];
      } else {
        terms = {
          state: filters.state[0],
        };
      }
    }
    handleSearch({
      pageIndex: Number(pagination.current) - 1,
      pageSize: pagination.pageSize,
      terms,
      sorts: sorter,
    });
  };

  const [processVisible, setProcessVisible] = useState(false);

  const [api, setAPI] = useState<string>('');

  const getSearchParam = () => {
    const data = encodeQueryParam(searchParam);
    let temp = '';
    Object.keys(data).forEach((i: string) => {
      if (data[i] && i !== 'pageSize' && i !== 'pageIndex') {
        temp += `${i}=${data[i]}&`;
      }
    });
    return encodeURI(temp.replace(/%/g, '%'));
  };
  // 激活全部设备
  const startImport = () => {
    setProcessVisible(true);
    const activeAPI = `/jetlinks/device-instance/deploy?${getSearchParam()}:X_Access_Token=${getAccessToken()} `;
    setAPI(activeAPI);
    setAction('active');
  };

  const startSync = () => {
    setProcessVisible(true);
    const syncAPI = `/jetlinks/device-instance/state/_sync/?${getSearchParam()}:X_Access_Token=${getAccessToken()}`;
    setAPI(syncAPI);
    setAction('sync');
  };

  const activeDevice = () => {
    Modal.confirm({
      title: `确认激活全部设备`,
      okText: '确定',
      okType: 'primary',
      cancelText: '取消',
      onOk() {
        startImport();
      },
    });
  };

  const syncDevice = () => {
    Modal.confirm({
      title: '确定同步设备真实状态?',
      okText: '确定',
      okType: 'primary',
      cancelText: '取消',
      onOk() {
        // 同步设备
        startSync();
      },
    });
  };

  const onDeviceProduct = (value: string) => {
    let { terms } = searchParam;
    if (terms) {
      terms.productId = value;
    } else {
      terms = {
        productId: value,
      };
    }

    handleSearch({
      pageIndex: searchParam.pageIndex,
      pageSize: searchParam.pageSize,
      terms,
      sorts: searchParam.sorter,
    });
    stateCount(value);
  };

  const rowSelection = {
    onChange: (selectedRowKeys: any) => {
      setDeviceIdLIst(selectedRowKeys);
    },
  };

  const _delete = (deviceId: any[]) => {
    Modal.confirm({
      title: `确认删除选中设备`,
      okText: '确定',
      okType: 'primary',
      cancelText: '取消',
      onOk() {
        apis.deviceInstance
          ._delete(deviceId)
          .then(response => {
            if (response.status === 200) {
              message.success('成功删除选中设备');
              deviceIdList.splice(0, deviceIdList.length);
              handleSearch(searchParam);
            }
          })
          .catch(() => {});
      },
    });
  };

  const _unDeploy = (deviceId: any[]) => {
    Modal.confirm({
      title: `确认注销选中设备`,
      okText: '确定',
      okType: 'primary',
      cancelText: '取消',
      onOk() {
        apis.deviceInstance
          ._unDeploy(deviceId)
          .then(response => {
            if (response.status === 200) {
              message.success('成功注销选中设备');
              deviceIdList.splice(0, deviceIdList.length);
              handleSearch(searchParam);
            }
          })
          .catch(() => {});
      },
    });
  };

  const _deploy = (deviceId: any[]) => {
    Modal.confirm({
      title: `确认激活选中设备`,
      okText: '确定',
      okType: 'primary',
      cancelText: '取消',
      onOk() {
        apis.deviceInstance
          ._deploy(deviceId)
          .then(response => {
            if (response.status === 200) {
              message.success('成功激活选中设备');
              deviceIdList.splice(0, deviceIdList.length);
              handleSearch(searchParam);
            }
          })
          .catch(() => {});
      },
    });
  };

  const Info: FC<{
    title: React.ReactNode;
    value: React.ReactNode;
  }> = ({ title, value }) => (
    <div>
      <span>{title}</span>
      <p style={{ fontSize: '26px' }}>{value}</p>
    </div>
  );

  const menu = (
    <Menu>
      <Menu.Item key="1">
        <Button
          icon="download"
          type="default"
          onClick={() => {
            setDeviceExport(true);
          }}
        >
          批量导出设备
        </Button>
      </Menu.Item>
      <Menu.Item key="2">
        <Button
          icon="upload"
          onClick={() => {
            setDeviceImport(true);
          }}
        >
          批量导入设备
        </Button>
      </Menu.Item>
      {deviceIdList.length > 0 && (
        <Menu.Item key="3">
          <Button
            icon="delete"
            onClick={() => {
              _delete(deviceIdList);
            }}
          >
            删除选中设备
          </Button>
        </Menu.Item>
      )}
      {deviceIdList.length > 0 && (
        <Menu.Item key="6">
          <Button
            icon="stop"
            onClick={() => {
              _unDeploy(deviceIdList);
            }}
          >
            注销选中设备
          </Button>
        </Menu.Item>
      )}

      {deviceIdList.length > 0 ? (
        <Menu.Item key="4">
          <Button icon="check-circle" type="danger" onClick={() => _deploy(deviceIdList)}>
            激活选中设备
          </Button>
        </Menu.Item>
      ) : (
        <Menu.Item key="4">
          <Button icon="check-circle" type="danger" onClick={() => activeDevice()}>
            激活全部设备
          </Button>
        </Menu.Item>
      )}

      <Menu.Item key="5">
        <Button icon="sync" type="danger" onClick={() => syncDevice()}>
          同步设备状态
        </Button>
      </Menu.Item>
    </Menu>
  );

  return (
    <PageHeaderWrapper title="设备管理">
      <div className={styles.standardList}>
        <Card bordered={false} style={{ height: 95 }}>
          <Spin spinning={deviceCount.loading}>
            <Row>
              <Col sm={7} xs={24}>
                <Select
                  placeholder="选择产品"
                  showSearch
                  optionFilterProp='label'
                  allowClear
                  style={{ width: '70%', marginTop: 7 }}
                  value={product}
                  onChange={(value: string) => {
                    let key = Object.keys(location?.query)[0];
                    let params = {};
                    if (location?.query) {
                      params[key] = location?.query[key];
                    }
                    params['productId'] = value;
                    router.push({ pathname: `/device/instance`, query: params });
                    setProduct(() => value);
                    setDeviceCount({ loading: true });
                    onDeviceProduct(value);
                  }}
                >
                  {productList?.map(item => (
                    <Select.Option key={item.id} label={item.name}>{item.name}</Select.Option>
                  ))}
                </Select>
              </Col>
              <Col sm={4} xs={24}>
                <Info title="全部设备" value={numeral(deviceCount.deviceTotal).format('0,0')} />
              </Col>
              <Col sm={4} xs={24}>
                <Info
                  title={<Badge status={statusMap.get('online')} text="在线" />}
                  value={numeral(deviceCount.onlineCount).format('0,0')}
                />
              </Col>
              <Col sm={4} xs={24}>
                <Info
                  title={<Badge status={statusMap.get('offline')} text="离线" />}
                  value={numeral(deviceCount.offlineCount).format('0,0')}
                />
              </Col>
              <Col sm={4} xs={24}>
                <Info
                  title={<Badge status={statusMap.get('notActive')} text="未启用" />}
                  value={numeral(deviceCount.notActiveCount).format('0,0')}
                />
              </Col>
              <Col sm={1} xs={24}>
                <Tooltip title="刷新">
                  <Icon
                    type="sync"
                    style={{ fontSize: 20 }}
                    onClick={() => {
                      setDeviceCount({ loading: true });
                      stateCount(product);
                    }}
                  />
                </Tooltip>
              </Col>
            </Row>
          </Spin>
        </Card>
        <br />
        <Card bordered={false}>
          <div className={styles.tableList}>
            <div className={styles.tableListForm}>
              <Search
                type={'device-instance'}
                search={(params: any) => {
                  if (Object.keys(params).length === 0) {
                    deviceIdList.splice(0, deviceIdList.length);
                  }
                  if (product) {
                    params.productId = product;
                  }
                  params.state = searchParam.terms?.state;
                  handleSearch({ terms: params, pageSize: 10, sorts: searchParam.sorts });
                }}
              />
            </div>
            <div className={styles.tableListOperator}>
              <Button
                icon="plus"
                type="primary"
                onClick={() => {
                  setCurrentItem({});
                  setAddVisible(true);
                }}
              >
                添加设备
              </Button>
              <Divider type="vertical" />
              <Dropdown overlay={menu}>
                <Button icon="menu">
                  其他批量操作
                  <Icon type="down" />
                </Button>
              </Dropdown>
            </div>
            <div className={styles.StandardTable}>
              <Table
                loading={props.loading}
                columns={columns}
                dataSource={(result || {}).data}
                rowKey="id"
                onChange={onTableChange}
                rowSelection={{
                  type: 'checkbox',
                  ...rowSelection,
                }}
                pagination={{
                  current: result.pageIndex + 1,
                  total: result.total,
                  pageSize: result.pageSize,
                  showQuickJumper: true,
                  showSizeChanger: true,
                  pageSizeOptions: ['10', '20', '50', '100'],
                  showTotal: (total: number) =>
                    `共 ${total} 条记录 第  ${result.pageIndex + 1}/${Math.ceil(
                      result.total / result.pageSize,
                    )}页`,
                }}
              />
            </div>
          </div>
        </Card>
        {addVisible && (
          <Save
            data={currentItem}
            close={() => {
              setAddVisible(false);
              setCurrentItem({});
            }}
          />
        )}
        {(processVisible || importLoading) && (
          <Process
            api={api}
            action={action}
            closeVisible={() => {
              setProcessVisible(false);
              setImportLoading(false);
              handleSearch(searchParam);
            }}
          />
        )}
        {deviceImport && (
          <Import
            productId={product}
            close={() => {
              setDeviceImport(false);
              handleSearch(searchParam);
            }}
          />
        )}
        {deviceExport && (
          <Export
            productId={product}
            searchParam={searchParam}
            close={() => {
              setDeviceExport(false);
              handleSearch(searchParam);
            }}
          />
        )}
      </div>
    </PageHeaderWrapper>
  );
}
Example #8
Source File: index-backups.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
DeviceInstancePage: React.FC<Props> = props => {
  const { result } = props.deviceInstance;
  const initState: State = {
    data: result,
    searchParam: { pageSize: 10 },
    addVisible: false,
    currentItem: {},
    processVisible: false,
    importLoading: false,
    action: '',
  };

  const [searchParam, setSearchParam] = useState(initState.searchParam);
  const [addVisible, setAddvisible] = useState(initState.addVisible);
  const [currentItem, setCurrentItem] = useState(initState.currentItem);
  const [importLoading, setImportLoading] = useState(initState.importLoading);
  const [action, setAction] = useState(initState.action);
  const { dispatch } = props;

  const statusMap = new Map();
  statusMap.set('在线', 'success');
  statusMap.set('离线', 'error');
  statusMap.set('未激活', 'processing');

  const handleSearch = (params?: any) => {
    setSearchParam(params);
    dispatch({
      type: 'deviceInstance/query',
      payload: encodeQueryParam(params),
    });
  };

  const delelteInstance = (record: any) => {
    apis.deviceInstance
      .remove(record.id)
      .then(response => {
        if (response.status === 200) {
          message.success('操作成功');
          handleSearch(searchParam);
        }
      })
      .catch(() => {});
  };

  const changeDeploy = (record: any) => {
    apis.deviceInstance
      .changeDeploy(record.id)
      .then(response => {
        if (response.status === 200) {
          message.success('操作成功');
          handleSearch(searchParam);
        }
      })
      .catch(() => {});
  };

  const unDeploy = (record: any) => {
    apis.deviceInstance
      .unDeploy(record.id)
      .then(response => {
        if (response.status === 200) {
          message.success('操作成功');
          handleSearch(searchParam);
        }
      })
      .catch(() => {});
  };
  const columns: ColumnProps<DeviceInstance>[] = [
    {
      title: 'ID',
      dataIndex: 'id',
    },
    {
      title: '设备名称',
      dataIndex: 'name',
    },
    {
      title: '产品名称',
      dataIndex: 'productName',
    },
    {
      title: '注册时间',
      dataIndex: 'registryTime',
      width: '200px',
      render: (text: any) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
      sorter: true,
      defaultSortOrder: 'descend',
    },
    {
      title: '状态',
      dataIndex: 'state',
      render: record =>
        record ? <Badge status={statusMap.get(record.text)} text={record.text} /> : '',
    },
    {
      title: '描述',
      dataIndex: 'describe',
    },
    {
      title: '操作',
      width: '200px',
      align: 'center',
      render: (record: any) => (
        <Fragment>
          <a
            onClick={() => {
              router.push(`/device/instance/save/${record.id}`);
            }}
          >
            查看
          </a>
          <Divider type="vertical" />
          <a
            onClick={() => {
              setCurrentItem(record);
              setAddvisible(true);
            }}
          >
            编辑
          </a>
          <Divider type="vertical" />
          {record.state?.value === 'notActive' ? (
            <span>
              <Popconfirm
                title="确认激活?"
                onConfirm={() => {
                  changeDeploy(record);
                }}
              >
                <a>激活</a>
              </Popconfirm>
              <Divider type="vertical" />
              <Popconfirm
                title="确认删除?"
                onConfirm={() => {
                  delelteInstance(record);
                }}
              >
                <a>删除</a>
              </Popconfirm>
            </span>
          ) : (
            <Popconfirm
              title="确认注销设备?"
              onConfirm={() => {
                unDeploy(record);
              }}
            >
              <a>注销</a>
            </Popconfirm>
          )}
        </Fragment>
      ),
    },
  ];

  useEffect(() => {
    handleSearch(searchParam);
  }, []);

  const saveDeviceInstance = (item: any) => {
    dispatch({
      type: 'deviceInstance/update',
      payload: encodeQueryParam(item),
      callback: (response:any) => {
        if (response.status === 200) {
          message.success('保存成功');
          setAddvisible(false);
          router.push(`/device/instance/save/${item.id}`);
        }
      },
    });
  };

  const onTableChange = (
    pagination: PaginationConfig,
    filters: any,
    sorter: SorterResult<DeviceInstance>,
  ) => {
    handleSearch({
      pageIndex: Number(pagination.current) - 1,
      pageSize: pagination.pageSize,
      terms: searchParam.terms,
      sorts: sorter,
    });
  };

  const [processVisible, setProcessVisible] = useState(false);

  const [api, setAPI] = useState<string>('');

  const getSearchParam = () => {
    const data = encodeQueryParam(searchParam);
    let temp = '';
    Object.keys(data).forEach((i: string) => {
      if (data[i] && i !== 'pageSize' && i !== 'pageIndex') {
        temp += `${i}=${data[i]}&`;
      }
    });
    return encodeURI(temp.replace(/%/g, '%'));
  };
  // 激活全部设备
  const startImport = () => {
    // let dt = 0;
    setProcessVisible(true);
    const activeAPI = `/jetlinks/device-instance/deploy?${getSearchParam()}:X_Access_Token=${getAccessToken()} `;
    setAPI(activeAPI);
    setAction('active');
  };

  const startSync = () => {
    setProcessVisible(true);
    const syncAPI = `/jetlinks/device-instance/state/_sync/?${getSearchParam()}:X_Access_Token=${getAccessToken()}`;
    setAPI(syncAPI);
    setAction('sync');
  };

  const activeDevice = () => {
    Modal.confirm({
      title: `确认激活全部设备`,
      okText: '确定',
      okType: 'primary',
      cancelText: '取消',
      onOk() {
        startImport();
      },
    });
  };

  const syncDevice = () => {
    Modal.confirm({
      title: '确定同步设备真实状态?',
      okText: '确定',
      okType: 'primary',
      cancelText: '取消',
      onOk() {
        // 同步设备
        startSync();
      },
    });
  };

  const [uploading, setUploading] = useState(false);
  const exportDevice = () => {
    const formElement = document.createElement('form');
    formElement.style.display = 'display:none;';
    formElement.method = 'post';
    formElement.action = `/jetlinks/device-instance/export?:X_Access_Token=${getAccessToken()}`;
    const params = encodeQueryParam(searchParam);
    Object.keys(params).forEach((key: string) => {
      const inputElement = document.createElement('input');
      inputElement.type = 'hidden';
      inputElement.name = key;
      inputElement.value = params[key];
      formElement.appendChild(inputElement);
    });
    document.body.appendChild(formElement);
    formElement.submit();
    document.body.removeChild(formElement);
  };

  const uploadProps: UploadProps = {
    accept: '.xlsx, .xls',
    action: '/jetlinks/file/static',
    headers: {
      'X-Access-Token': getAccessToken(),
    },
    showUploadList: false,
    onChange(info) {
      if (info.file.status === 'done') {
        setUploading(false);
        const fileUrl = info.file.response.result;
        const url = `/jetlinks/device-instance/import?fileUrl=${fileUrl}&:X_Access_Token=${getAccessToken()}`;
        setAPI(url);
        setAction('import');
        setImportLoading(true);
      }
      if (info.file.status === 'uploading') {
        setUploading(true);
      }
    },
  };

  return (
    <PageHeaderWrapper title="设备管理">
      <Spin spinning={uploading} tip="上传中...">
        <Card bordered={false}>
          <div className={styles.tableList}>
            <div className={styles.tableListForm}>
              <Search
                search={(params: any) => {
                  setSearchParam(params);
                  handleSearch({ terms: params, pageSize: 10 });
                }}
              />
            </div>
            <div className={styles.tableListOperator}>
              <Button
                icon="plus"
                type="primary"
                onClick={() => {
                  setCurrentItem({});
                  setAddvisible(true);
                }}
              >
                新建
              </Button>

              <Divider type="vertical" />

              <Button href={template} download="设备模版" icon="download">
                下载模版
              </Button>
              <Divider type="vertical" />
              <Button icon="download" type="default" onClick={() => exportDevice()}>
                导出设备
              </Button>
              <Divider type="vertical" />
              <Upload {...uploadProps}>
                <Button icon="upload">导入设备</Button>
              </Upload>
              <Divider type="vertical" />
              <Button icon="check-circle" type="danger" onClick={() => activeDevice()}>
                激活全部设备
              </Button>
              <Divider type="vertical" />
              <Button icon="sync" type="danger" onClick={() => syncDevice()}>
                同步设备状态
              </Button>
            </div>
            <div className={styles.StandardTable}>
              <Table
                loading={props.loading}
                columns={columns}
                dataSource={(result || {}).data}
                rowKey="id"
                onChange={onTableChange}
                pagination={{
                  current: result.pageIndex + 1,
                  total: result.total,
                  pageSize: result.pageSize,
                  showQuickJumper: true,
                  showSizeChanger: true,
                  pageSizeOptions: ['10', '20', '50', '100'],
                  showTotal: (total: number) =>
                    `共 ${total} 条记录 第  ${result.pageIndex + 1}/${Math.ceil(
                      result.total / result.pageSize,
                    )}页`,
                }}
              />
            </div>
          </div>
        </Card>
        {addVisible && (
          <Save
            data={currentItem}
            close={() => {
              setAddvisible(false);
              setCurrentItem({});
            }}
            save={(item: any) => {
              saveDeviceInstance(item);
            }}
          />
        )}
        {(processVisible || importLoading) && (
          <Process
            api={api}
            action={action}
            closeVisible={() => {
              setProcessVisible(false);
              setImportLoading(false);
              handleSearch(searchParam);
            }}
          />
        )}
      </Spin>
    </PageHeaderWrapper>
  );
}
Example #9
Source File: gateway.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
Gateway: React.FC<Props> = (props) => {

  const initState: State = {
    data: {},
    searchParam: { pageSize: 10 },
    currentItem: {},
    spinning: false,
    bindVisible: false,
    addVisible: false,
  };

  const [searchParam, setSearchParam] = useState(initState.searchParam);
  const [data, setData] = useState(initState.data);
  const [spinning, setSpinning] = useState(initState.spinning);
  const [currentItem, setCurrentItem] = useState(initState.currentItem);
  const [addVisible, setAddVisible] = useState(initState.addVisible);
  const [bindVisible, setBindVisible] = useState(initState.bindVisible);

  const handleSearch = (params?: any) => {
    setSearchParam(params);
    apis.deviceInstance.list(encodeQueryParam(params))
      .then((response: any) => {
          if (response.status === 200) {
            setData(response.result);
          }
          setSpinning(false);
        },
      ).catch(() => {
    });

  };

  useEffect(() => {
    setSpinning(true);
    handleSearch({
      pageSize: 10,
      terms: {
        parentId: props.deviceId,
      },
    });
  }, []);

  const changeDeploy = (record: any) => {
    setSpinning(true);
    apis.deviceInstance
      .changeDeploy(record.id)
      .then(response => {
        if (response.status === 200) {
          message.success('操作成功');
          handleSearch(searchParam);
        } else {
          setSpinning(false);
        }
      })
      .catch(() => {
      });
  };

  const unDeploy = (record: any) => {
    setSpinning(true);
    apis.deviceInstance
      .unDeploy(record.id)
      .then(response => {
        if (response.status === 200) {
          message.success('操作成功');
          handleSearch(searchParam);
        } else {
          setSpinning(false);
        }
      })
      .catch(() => {
      });
  };

  const unBindGateway = (id: string, deviceId: string) => {
    setSpinning(true);
    apis.deviceGateway.unBind(id, deviceId)
      .then(response => {
        if (response.status === 200) {
          message.success('解绑成功');
          handleSearch(searchParam);
        } else {
          setSpinning(false);
        }
      }).catch(() => {
    });
  };

  const statusMap = new Map();
  statusMap.set('online', 'success');
  statusMap.set('offline', 'error');
  statusMap.set('notActive', 'processing');

  const columns: ColumnProps<DeviceInstance>[] = [
    {
      title: 'ID',
      dataIndex: 'id',
    },
    {
      title: '设备名称',
      dataIndex: 'name',
    },
    {
      title: '产品名称',
      dataIndex: 'productName',
    },
    {
      title: '注册时间',
      dataIndex: 'registryTime',
      width: '200px',
      render: (text: any) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
      sorter: true,
      defaultSortOrder: 'descend',
    },
    {
      title: '状态',
      dataIndex: 'state',
      render: record =>
        record ? <Badge status={statusMap.get(record.value)} text={record.text}/> : '',
    },
    {
      title: '操作',
      width: '200px',
      align: 'center',
      render: (record: any) => (
        <Fragment>
          <a
            onClick={() => {
              router.push(`/device/instance/save/${record.id}`);
            }}
          >
            查看
          </a>
          <Divider type="vertical"/>
          <a
            onClick={() => {
              setCurrentItem(record);
              setAddVisible(true);
            }}
          >
            编辑
          </a>
          <Divider type="vertical"/>
          {record.state?.value === 'notActive' ? (
            <Popconfirm
              title="确认激活?"
              onConfirm={() => {
                changeDeploy(record);
              }}
            >
              <a>激活</a>
            </Popconfirm>
          ) : (
            <Popconfirm
              title="确认注销设备?"
              onConfirm={() => {
                unDeploy(record);
              }}
            >
              <a>注销</a>
            </Popconfirm>
          )}

          <Divider type="vertical"/>
          <Popconfirm
            title="确认解绑?"
            onConfirm={() => {
              unBindGateway(props.deviceId, record.id);
            }}
          >
            <a>解绑</a>
          </Popconfirm>
        </Fragment>
      ),
    },
  ];

  const onTableChange = (
    pagination: PaginationConfig,
    filters: any,
    sorter: SorterResult<DeviceInstance>,
  ) => {
    handleSearch({
      pageIndex: Number(pagination.current) - 1,
      pageSize: pagination.pageSize,
      terms: searchParam.terms,
      sorts: sorter,
    });
  };

  const saveDeviceInstance = (item: any) => {
    setSpinning(true);
    apis.deviceInstance.saveOrUpdate(item)
      .then((response: any) => {
        if (response.status === 200) {
          message.success('保存成功');
          handleSearch(searchParam);
        } else {
          setSpinning(false);
        }
      }).catch(() => {
    });
  };

  const insert = (deviceData: any) => {
    setSpinning(true);
    apis.deviceGateway.bind(props.deviceId, deviceData).then(response => {
      if (response.status === 200) {
        message.success('保存成功');
        handleSearch(searchParam);
      } else {
        setSpinning(false);
      }
    }).catch(() => {
    });
  };

  const action = (
    <Button type="primary" icon="plus" onClick={() => setBindVisible(true)}>
      绑定子设备
    </Button>
  );

  return (
    <div>
      <Spin spinning={spinning}>
        <Card style={{ marginBottom: 20 }} title="子设备列表" extra={action}>
          <div className={styles.tableListForm}>
            <Search
              search={(params: any) => {
                setSearchParam(params);
                params.parentId = props.deviceId;
                handleSearch({ terms: params, pageSize: 10 });
              }}
            />
          </div>
          <Table
            loading={props.loading}
            columns={columns}
            dataSource={data?.data}
            rowKey="id"
            onChange={onTableChange}
            pagination={{
              current: data.pageIndex + 1,
              total: data.total,
              pageSize: data.pageSize,
              showQuickJumper: true,
              showSizeChanger: true,
              pageSizeOptions: ['10', '20', '50', '100'],
              showTotal: (total: number) =>
                `共 ${total} 条记录 第  ${data.pageIndex + 1}/${Math.ceil(
                  data.total / data.pageSize,
                )}页`,
            }}
          />
        </Card>
        {addVisible && (
          <Save
            data={currentItem}
            close={() => {
              setAddVisible(false);
              setCurrentItem({});
            }}
            save={(item: any) => {
              setAddVisible(false);
              saveDeviceInstance(item);
            }}
          />
        )}

        {bindVisible && (
          <Bind selectionType='checkbox'
                close={() => {
                  setBindVisible(false);
                }}
                save={(item: any) => {
                  setBindVisible(false);
                  insert(item);
                }}
          />
        )}
      </Spin>
    </div>
  );
}
Example #10
Source File: EventLog.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
EventLog: React.FC<Props> = props => {
  const initState: State = {
    eventColumns: props.item.valueType.type === "object" ? props.item.valueType.properties?.map((item: any) => {
      return {
        title: item.name,
        dataIndex: `${item.id}_format`,
        ellipsis: true,
        render: (text: any) => typeof text === 'object' ?
          JSON.stringify(text) : text
      };
    }) : [{
      title: "数据",
      dataIndex: `value`,
      ellipsis: true,
      render:(text)=>JSON.stringify(text)
    }],
    logData: {},
  };
  initState.eventColumns.push({
    title: '事件时间',
    dataIndex: 'timestamp',
    width: '200px',
    render: (text: any) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
    sorter: true,
    defaultSortOrder: 'descend',
  });

  initState.eventColumns.push({
    title: '操作',
    render: (record: any) => (
      <>
        <a onClick={() => {
          for (let i in record) {
            if (i.indexOf('_format') != -1) {
              delete record[i];
            }
          }
          Modal.info({
            title: '详情',
            width: 850,
            content: (
              <Form.Item wrapperCol={{ span: 20 }} labelCol={{ span: 4 }} label={props.item.name}>
                <AceEditor
                  readOnly
                  value={JSON.stringify(record, null, 2)}
                  mode='json'
                  theme="eclipse"
                  name="app_code_editor"
                  key='deviceShadow'
                  fontSize={14}
                  showPrintMargin
                  showGutter
                  wrapEnabled
                  highlightActiveLine  //突出活动线
                  enableSnippets  //启用代码段
                  style={{ width: '100%', height: '50vh' }}
                  setOptions={{
                    enableBasicAutocompletion: true,   //启用基本自动完成功能
                    enableLiveAutocompletion: true,   //启用实时自动完成功能 (比如:智能代码提示)
                    enableSnippets: true,  //启用代码段
                    showLineNumbers: true,
                    tabSize: 2,
                  }}
                />
              </Form.Item>
            ),
            okText: '关闭',
            onOk() {
            },
          });
        }}>详情</a>
      </>
    )
  });

  const [logData, setLogData] = useState(initState.logData);

  useEffect(() => {
    apis.deviceInstance.eventData(
      props.deviceId,
      props.item.id,
      encodeQueryParam({
        pageIndex: 0,
        pageSize: 10,
      }),
    ).then(response => {
      setLogData(response.result);
    }).catch(() => {

    });
  }, []);

  const onTableChange = (pagination: PaginationConfig, filters: any, sorter: SorterResult<any>) => {
    apis.deviceInstance.eventData(
      props.deviceId,
      props.item.id,
      encodeQueryParam({
        pageIndex: Number(pagination.current) - 1,
        pageSize: pagination.pageSize,
        sorts: sorter,
      }),
    ).then(response => {
      setLogData(response.result);
    }).catch(() => {

    });
  };

  return (
    <Modal
      title="事件详情"
      visible
      onCancel={() => props.close()}
      onOk={() => props.close()}
      width="70%"
    >
      <Table
        rowKey='id'
        dataSource={logData.data}
        size="small"
        onChange={onTableChange}
        pagination={{
          current: logData.pageIndex + 1,
          total: logData.total,
          pageSize: logData.pageSize,
          showQuickJumper: true,
          showSizeChanger: true,
          pageSizeOptions: ['10', '20', '50', '100'],
          showTotal: (total: number) => `共 ${total} 条记录 第  ${logData.pageIndex + 1}/${Math.ceil(logData.total / logData.pageSize)}页`,
        }}
        columns={initState.eventColumns}
      />
    </Modal>
  );
}
Example #11
Source File: index.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
DeviceList = (props: Props) => {
  const [searchParam, setSearchParam] = useState({
    pageSize: 10,
    terms: { productId: props.productId },
  });
  const [deviceData, setDeviceData] = useState<any>({});
  const [deviceId, setDeviceId] = useState(props.data);

  const submitData = () => {
    props.save(deviceId);
  };

  const handleSearch = (params?: any) => {
    setSearchParam(params);
    apis.deviceInstance
      .list(encodeQueryParam(params))
      .then(response => {
        if (response.status === 200) {
          setDeviceData(response.result);
        }
      })
      .catch(() => {});
  };

  useEffect(() => {
    handleSearch(searchParam);
  }, []);

  const onTableChange = (pagination: PaginationConfig, filters: any, sorter: SorterResult<any>) => {
    apis.deviceInstance
      .list(
        encodeQueryParam({
          pageIndex: Number(pagination.current) - 1,
          pageSize: pagination.pageSize,
          sorts: sorter,
          terms: { productId: props.productId },
        }),
      )
      .then(response => {
        if (response.status === 200) {
          setDeviceData(response.result);
        }
      })
      .catch(() => {});
  };

  const rowSelection = {
    onChange: (selectedRowKeys: any) => {
      setDeviceId(selectedRowKeys);
    },
  };

  const statusMap = new Map();
  statusMap.set('在线', 'success');
  statusMap.set('离线', 'error');
  statusMap.set('未激活', 'processing');

  const columns: ColumnProps<any>[] = [
    {
      title: 'ID',
      dataIndex: 'id',
      ellipsis: true,
    },
    {
      title: '设备名称',
      dataIndex: 'name',
      ellipsis: true,
    },
    {
      title: '产品名称',
      dataIndex: 'productName',
      ellipsis: true,
    },
    {
      title: '注册时间',
      dataIndex: 'registryTime',
      width: '200px',
      ellipsis: true,
      render: (text: any) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
      sorter: true,
      defaultSortOrder: 'descend',
    },
    {
      title: '状态',
      dataIndex: 'state',
      width: '120px',
      render: record =>
        record ? <Badge status={statusMap.get(record.text)} text={record.text} /> : '',
    },
  ];

  return (
    <Modal
      title="选择设备"
      visible
      okText="确定"
      cancelText="取消"
      onOk={() => {
        submitData();
      }}
      width="60%"
      style={{ marginTop: -30 }}
      onCancel={() => props.close()}
    >
      <div
        className={styles.tableList}
        style={{ maxHeight: 600, overflowY: 'auto', overflowX: 'hidden' }}
      >
        <div className={styles.tableListForm}>
          <SearchForm
            search={(params: any) => {
              handleSearch({ terms: { ...searchParam.terms, ...params }, pageSize: 10 });
            }}
            formItems={[
              {
                label: '设备名称',
                key: 'name$LIKE',
                type: 'string',
              },
              {
                label: '设备ID',
                key: 'deviceId$IN',
                type: 'string',
              },
            ]}
          />
        </div>

        <div className={styles.StandardTable}>
          <Table
            columns={columns}
            dataSource={deviceData.data}
            rowKey="id"
            onChange={onTableChange}
            rowSelection={{
              selectedRowKeys: deviceId,
              type: 'checkbox',
              ...rowSelection,
            }}
            pagination={{
              current: deviceData.pageIndex + 1,
              total: deviceData.total,
              pageSize: deviceData.pageSize,
              showQuickJumper: true,
              showSizeChanger: true,
              pageSizeOptions: ['10', '20', '50', '100'],
              showTotal: (total: number) =>
                `共 ${total} 条记录 第  ${deviceData.pageIndex + 1}/${Math.ceil(
                  deviceData.total / deviceData.pageSize,
                )}页`,
            }}
          />
        </div>
      </div>
    </Modal>
  );
}
Example #12
Source File: index.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
DeviceGatewayBind: React.FC<Props> = props => {
  const initState: State = {
    searchParam: { pageSize: 10, terms: { 'parentId$not@or': props.gatewayId } },
    deviceData: {},
    deviceId: [],
  };

  const [searchParam, setSearchParam] = useState(initState.searchParam);
  const [deviceData, setDeviceData] = useState(initState.deviceData);
  const [deviceId, setDeviceId] = useState(initState.deviceId);

  const submitData = () => {
    props.save(deviceId);
  };

  const handleSearch = (params?: any) => {
    setSearchParam(params);
    apis.deviceInstance
      .list(encodeQueryParam(params))
      .then(response => {
        if (response.status === 200) {
          setDeviceData(response.result);
        }
      })
      .catch(() => {});
  };

  useEffect(() => {
    if (props.selectionType === 'checkbox') {
      searchParam.terms = { parentId$isnull: 1, 'parentId$not@or': props.gatewayId };
    }
    handleSearch(searchParam);
  }, []);

  const onTableChange = (pagination: PaginationConfig, filters: any, sorter: SorterResult<any>) => {
    apis.deviceInstance
      .list(
        encodeQueryParam({
          terms: searchParam.terms,
          pageIndex: Number(pagination.current) - 1,
          pageSize: pagination.pageSize,
          sorts: sorter,
        }),
      )
      .then(response => {
        if (response.status === 200) {
          setDeviceData(response.result);
        }
      })
      .catch(() => {});
  };

  const rowSelection = {
    onChange: (selectedRowKeys: any) => {
      setDeviceId(selectedRowKeys);
    },
  };

  const statusMap = new Map();
  statusMap.set('online', 'success');
  statusMap.set('offline', 'error');
  statusMap.set('notActive', 'processing');

  const columns: ColumnProps<DeviceInstance>[] = [
    {
      title: 'ID',
      dataIndex: 'id',
      ellipsis: true,
    },
    {
      title: '设备名称',
      dataIndex: 'name',
      ellipsis: true,
    },
    {
      title: '产品名称',
      dataIndex: 'productName',
      ellipsis: true,
    },
    {
      title: '注册时间',
      dataIndex: 'registryTime',
      width: '200px',
      ellipsis: true,
      render: (text: any) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
      sorter: true,
      defaultSortOrder: 'descend',
    },
    {
      title: '状态',
      dataIndex: 'state',
      width: '120px',
      render: record =>
        record ? <Badge status={statusMap.get(record.value)} text={record.text} /> : '',
    },
  ];

  return (
    <Modal
      title="绑定子设备"
      visible
      okText="确定"
      cancelText="取消"
      onOk={() => {
        submitData();
      }}
      width="60%"
      style={{ marginTop: -30 }}
      onCancel={() => props.close()}
    >
      <div
        className={styles.tableList}
        style={{ maxHeight: 600, overflowY: 'auto', overflowX: 'hidden' }}
      >
        <div className={styles.tableListForm}>
          <Search
            search={(params: any) => {
              setSearchParam(params);
              if (props.selectionType === 'checkbox') {
                // params['parentId$isnull'] = 1;
                handleSearch({
                  sorter: searchParam.sorter, 
                  pageSize: 10,
                  terms:{
                    ...params,
                    parentId$isnull:1,
                    'parentId$not@or':props.gatewayId
                  },
                })
              }else{
                handleSearch({
                  sorter: searchParam.sorter, 
                  pageSize: 10,
                  terms:{
                    ...params,
                    // parentId$isnull:1,
                    'parentId$not@or':props.gatewayId
                  },
                })
              }
              // params['parentId$not@or'] = props.gatewayId;
              // handleSearch({ terms: params, sorter: searchParam.sorter, pageSize: 10 });
            }}
          />
        </div>

        <div className={styles.StandardTable}>
          <Table
            columns={columns}
            dataSource={deviceData.data}
            rowKey="id"
            onChange={onTableChange}
            rowSelection={{
              type: props.selectionType,
              ...rowSelection,
            }}
            pagination={{
              current: deviceData.pageIndex + 1,
              total: deviceData.total,
              pageSize: deviceData.pageSize,
              showQuickJumper: true,
              showSizeChanger: true,
              pageSizeOptions: ['10', '20', '50', '100'],
              showTotal: (total: number) =>
                `共 ${total} 条记录 第  ${deviceData.pageIndex + 1}/${Math.ceil(
                  deviceData.total / deviceData.pageSize,
                )}页`,
            }}
          />
        </div>
      </div>
    </Modal>
  );
}
Example #13
Source File: upgrade-task.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
UpgradeTask: React.FC<Props> = (props) => {

  const initState: State = {
    data: {},
    saveUpgradeTaskData: {},
    searchParam: { pageSize: 10 },
    spinning: false,
  };

  const [searchParam, setSearchParam] = useState(initState.searchParam);
  const [data, setData] = useState(initState.data);
  const [spinning, setSpinning] = useState(initState.spinning);

  const handleSearch = (params?: any) => {
    setSearchParam(params);
    apis.firmware.upgradeTask(encodeQueryParam(params))
      .then((response: any) => {
          if (response.status === 200) {
            setData(response.result);
          }
          setSpinning(false);
        },
      ).catch(() => {
    });
  };

  useEffect(() => {
    setSpinning(true);
    handleSearch({
      pageSize: 10,
      terms: {
        firmwareId: props.firmwareId,
      },
    });
  }, []);

  const columns: ColumnProps<UpgradeTaskData>[] = [
    {
      title: 'ID',
      dataIndex: 'id',
    },
    {
      title: '任务名称',
      dataIndex: 'name',
    },
    {
      title: '升级方式',
      dataIndex: 'mode.text',
    },
    {
      title: '超时时间',
      dataIndex: 'timeoutSeconds',
      render: (text: any) => text + ' 秒',
    },
    {
      title: '创建时间',
      dataIndex: 'createTime',
      width: '200px',
      render: (text: any) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
      sorter: true,
      defaultSortOrder: 'descend',
    },
    {
      title: '操作',
      width: '120px',
      align: 'center',
      render: (record: any) => (
        <Fragment>
          <a onClick={() => {
            props.jumpPedal(record);
          }}
          >
            查看
          </a>
          <Divider type="vertical"/>
          <Popconfirm title="确定删除此任务吗?请谨慎操作" onConfirm={() => removeUpgrade(record)}>
            <a>
              删除
            </a>
          </Popconfirm>
        </Fragment>
      ),
    },
  ];

  const onTableChange = (
    pagination: PaginationConfig,
    filters: any,
    sorter: SorterResult<UpgradeTaskData>,
  ) => {
    handleSearch({
      pageIndex: Number(pagination.current) - 1,
      pageSize: pagination.pageSize,
      terms: searchParam.terms,
      sorts: sorter,
    });
  };

  const removeUpgrade = (item: any) => {
    setSpinning(true);
    apis.firmware.removeUpgrade(item.id)
      .then((response: any) => {
        if (response.status === 200) {
          message.success('删除成功');
          handleSearch(searchParam);
        }
      }).catch(() => {
    });
  };

  return (
    <div>
      <Spin spinning={spinning}>
        <Card style={{ marginBottom: 20 }}>
          <div className={styles.tableListOperator} style={{ paddingBottom: 20 }}>
            <Button icon="plus" type="primary" onClick={() => {
              props.jumpPedal({});
            }}>
              新建
            </Button>
          </div>
          <div className={styles.StandardTable}>
            <Table
              columns={columns}
              dataSource={data?.data}
              rowKey="id"
              onChange={onTableChange}
              pagination={{
                current: data.pageIndex + 1,
                total: data.total,
                pageSize: data.pageSize,
                showQuickJumper: true,
                showSizeChanger: true,
                pageSizeOptions: ['10', '20', '50', '100'],
                showTotal: (total: number) =>
                  `共 ${total} 条记录 第  ${data.pageIndex + 1}/${Math.ceil(
                    data.total / data.pageSize,
                  )}页`,
              }}
            />
          </div>
        </Card>
      </Spin>
    </div>
  );
}
Example #14
Source File: ChoiceDevice.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
ChoiceDevice: React.FC<Props> = props => {
  const initState: State = {
    searchParam: { pageSize: 10 },
    deviceData: {},
  };

  const [searchParam, setSearchParam] = useState(initState.searchParam);
  const [deviceData, setDeviceData] = useState(initState.deviceData);

  const handleSearch = (params?: any) => {
    setSearchParam(params);
    apis.deviceInstance
      .list(encodeQueryParam(params))
      .then(response => {
        if (response.status === 200) {
          setDeviceData(response.result);
        }
      })
      .catch(() => {
      });
  };

  useEffect(() => {
    searchParam.terms = { productId: props.productId };
    handleSearch(searchParam);
  }, []);

  const onTableChange = (
    pagination: PaginationConfig,
    filters: any,
    sorter: SorterResult<DeviceInstance>,
  ) => {
    handleSearch({
      pageIndex: Number(pagination.current) - 1,
      pageSize: pagination.pageSize,
      terms: searchParam.terms,
      sorts: sorter,
    });
  };

  const rowSelection = {
    onChange: (selectedRowKeys: any) => {
      props.save(selectedRowKeys);
    },
  };

  const statusMap = new Map();
  statusMap.set('在线', 'success');
  statusMap.set('离线', 'error');
  statusMap.set('未激活', 'processing');

  const columns: ColumnProps<DeviceInstance>[] = [
    {
      title: 'ID',
      dataIndex: 'id',
    },
    {
      title: '设备名称',
      dataIndex: 'name',
    },
    {
      title: '产品名称',
      dataIndex: 'productName',
    },
    {
      title: '注册时间',
      dataIndex: 'registryTime',
      width: '200px',
      render: (text: any) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
      sorter: true,
      defaultSortOrder: 'descend',
    },
    {
      title: '状态',
      dataIndex: 'state',
      render: record =>
        record ? <Badge status={statusMap.get(record.text)} text={record.text}/> : '',
    },
  ];

  return (
    <div className={styles.tableList}>
      <div className={styles.tableListForm}>
        <Search
          search={(params: any) => {
            setSearchParam(params);
            searchParam.terms = { productId: props.productId };
            handleSearch({ terms: params, sorter: searchParam.sorter, pageSize: 10 });
          }}
        />
      </div>
      <div className={styles.StandardTable}>
        <Table
          columns={columns}
          dataSource={deviceData.data}
          rowKey="id"
          onChange={onTableChange}
          rowSelection={{
            type: 'checkbox',
            ...rowSelection,
          }}
          size='middle'
          pagination={{
            current: deviceData.pageIndex + 1,
            total: deviceData.total,
            pageSize: deviceData.pageSize,
            showQuickJumper: true,
            showSizeChanger: true,
            pageSizeOptions: ['10', '20', '50', '100'],
            showTotal: (total: number) =>
              `共 ${total} 条记录 第  ${deviceData.pageIndex + 1}/${Math.ceil(
                deviceData.total / deviceData.pageSize,
              )}页`,
          }}
        />
      </div>
    </div>
  );
}
Example #15
Source File: History.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
UpgradeHistory: React.FC<Props> = (props) => {

  const initState: State = {
    data: {},
    searchParam: { pageSize: 10 },
    spinning: false,
  };

  const [searchParam, setSearchParam] = useState(initState.searchParam);
  const [data, setData] = useState(initState.data);
  const [spinning, setSpinning] = useState(initState.spinning);

  const upgradeStatus = new Map();
  upgradeStatus.set('waiting', 'warning');
  upgradeStatus.set('processing', 'processing');
  upgradeStatus.set('success', 'success');
  upgradeStatus.set('failed', 'error');
  upgradeStatus.set('canceled', 'default');

  const handleSearch = (params?: any) => {
    setSearchParam(params);
    apis.firmware.upgradeHistory(encodeQueryParam(params))
      .then((response: any) => {
          if (response.status === 200) {
            setData(response.result);
          }
          setSpinning(false);
        },
      ).catch(() => {
    });
  };

  useEffect(() => {
    setSpinning(true);
    let terms = {
      firmwareId: props.firmwareId,
    };
    if (props.taskId !== '' && props.taskId) {
      terms['taskId'] = props.taskId;
    }
    if (props.historyState !== '' && props.historyState) {
      terms['state'] = props.historyState;
    }
    handleSearch({
      pageSize: 10,
      terms: terms,
    });
  }, []);

  const columns: ColumnProps<UpgradeHistoryData>[] = [
    {
      title: '设备名称',
      dataIndex: 'deviceName',
    },
    {
      title: '任务名称',
      dataIndex: 'taskName',
    },
    {
      title: '版本',
      dataIndex: 'version',
    },
    {
      title: '状态',
      dataIndex: 'state',
      render: record => <Badge status={upgradeStatus.get(record.value)} text={record.text}/>,
    },
    {
      title: '进度',
      dataIndex: 'progress',
      render: (text: any) => text + ' %',
    },
    {
      title: '创建时间',
      dataIndex: 'createTime',
      width: '200px',
      render: (text: any) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
      sorter: true,
      defaultSortOrder: 'descend',
    },
  ];

  const onTableChange = (
    pagination: PaginationConfig,
    filters: any,
    sorter: SorterResult<UpgradeHistoryData>,
  ) => {
    handleSearch({
      pageIndex: Number(pagination.current) - 1,
      pageSize: pagination.pageSize,
      terms: searchParam.terms,
      sorts: sorter,
    });
  };

  return (
    <div>
      <Spin spinning={spinning}>
        <Card style={{ marginBottom: 20 }}>
          <div>
            <SearchForm
              search={(params: any) => {
                let terms = {
                  firmwareId: props.firmwareId,
                  taskName$LIKE:params['taskName$LIKE'],
                };
                if (props.taskId !== '' && props.taskId) {
                  terms['taskId'] = props.taskId;
                }
                if (props.historyState !== '' && props.historyState) {
                  terms['state'] = props.historyState;
                }

                handleSearch({
                  terms: { ...terms },
                  pageSize: 10,
                  sorts: searchParam.sorts,
                });
              }}
              formItems={[{
                label: '任务名称',
                key: 'taskName$LIKE',
                type: 'string',
              }]}
            />
          </div>
          <div className={styles.StandardTable}>
            <Table
              columns={columns}
              dataSource={data?.data}
              rowKey="id"
              onChange={onTableChange}
              pagination={{
                current: data.pageIndex + 1,
                total: data.total,
                pageSize: data.pageSize,
                showQuickJumper: true,
                showSizeChanger: true,
                pageSizeOptions: ['10', '20', '50', '100'],
                showTotal: (total: number) =>
                  `共 ${total} 条记录 第  ${data.pageIndex + 1}/${Math.ceil(
                    data.total / data.pageSize,
                  )}页`,
              }}
            />
          </div>
        </Card>
      </Spin>
    </div>
  );
}
Example #16
Source File: index.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
productBind: React.FC<Props> = (props) => {

    const [spinning, setSpinning] = useState(true);
    const [productIdList, setProductIdList] = useState([]);
    const [productData, setProductData] = useState<any>({});
    const [searchParam, setSearchParam] = useState<any>({
        pageSize: 10,
        terms: {},
        sorts: {
            order: 'descend',
            field: 'id',
        },
    });
    const [productBind, setProductBind] = useState<boolean>(false);

    const columns: ColumnProps<any>[] = [
        {
            title: '产品ID',
            align: 'left',
            width: 150,
            dataIndex: 'id',
            ellipsis: true,
        },
        {
            title: '产品名称',
            align: 'left',
            width: 150,
            dataIndex: 'name',
        },
        {
            title: '说明',
            dataIndex: 'description',
            width: 300,
            align: 'center',
            ellipsis: true,
            render: (description: string) => (description ? description : '--'),
        },
        {
            title: '操作',
            width: '200px',
            align: 'center',
            render: (record: any) => (
                <Fragment>
                    <Popconfirm
                        title="确认解绑?"
                        onConfirm={() => {
                            setSpinning(true);
                            unBindClassify([record.id])
                        }}
                    >
                        <a>解绑</a>
                    </Popconfirm>
                </Fragment>
            ),
        },
    ];

    const handleSearch = (params: any) => {
        setSearchParam(params);
        params.terms = {
            ...params.terms,
            "id#dim-assets": `{"assetType":"product","targets":[{"type":"${props.targetType}","id":"${props.targetId}"}]}`
        };
        api.deviceProdcut
            .query(encodeParam(params))
            .then(res => {
                setSpinning(false);
                if (res.status === 200) {
                    setProductData(res.result);
                }
            });
    };

    const unBindClassify = (value: any[]) => {
        const data = [{
            "targetType": props.targetType,
            "targetId": props.targetId,
            "assetType": "product",
            "assetIdList": value
        }];

        api.assets.UnBindAssets("product", data)
            .then((result: any) => {
                if (result.status === 200) {
                    message.success("资产解绑成功");
                    productIdList.splice(0, productIdList.length);
                    handleSearch(searchParam);
                } else {
                    message.error("资产解绑失败");
                    handleSearch(searchParam);
                }
            }).catch(() => {
        })
    };

    const rowSelection = {
        onChange: (selectedRowKeys: any) => {
            setProductIdList(selectedRowKeys);
        },
    };

    useEffect(() => {
        if (props.targetId != null || props.targetId != "") {
            handleSearch(searchParam);
        }
    }, [props.targetId]);

    const onTableChange = (
        pagination: PaginationConfig,
        filters: any,
        sorter: SorterResult<DeviceInstance>,
    ) => {
        let {terms} = searchParam;
        handleSearch({
            pageIndex: Number(pagination.current) - 1,
            pageSize: pagination.pageSize,
            terms,
            sorts: sorter,
        })
    };

    return (
        <div>
            <Spin spinning={spinning}>
                <Card>
                    <SearchForm
                        search={(params: any) => {
                            handleSearch({
                                terms: {...params},
                                pageSize: 10,
                                sorts: searchParam.sorts,
                            });
                        }}
                        formItems={[
                            {
                                label: '产品名称',
                                key: 'name$LIKE',
                                type: 'string',
                            },
                            {
                                label: '产品类型',
                                key: 'deviceType$IN',
                                type: 'list',
                                props: {
                                    data: [
                                        {id: 'device', name: '直连设备'},
                                        {id: 'childrenDevice', name: '网关子设备'},
                                        {id: 'gateway', name: '网关设备'},
                                    ],
                                    mode: 'tags',
                                },
                            },
                        ]}
                    />
                    <Button
                        icon="plus"
                        type="primary"
                        style={{marginBottom: '20px'}}
                        onClick={() => {
                            setProductBind(true);
                        }}
                    >
                        分配资产
                    </Button>
                    {productIdList.length > 0 && (
                        <Popconfirm
                            title="确认批量解绑?"
                            onConfirm={() => {
                                setSpinning(true);
                                unBindClassify(productIdList);
                            }}
                        >
                            <Button
                                icon="delete"
                                type="primary"
                                style={{marginBottom: '20px', marginLeft: "20px"}}
                            >
                                批量解绑
                            </Button>
                        </Popconfirm>
                    )}
                    <Table
                        columns={columns}
                        dataSource={(productData || {}).data}
                        rowKey="id"
                        onChange={onTableChange}
                        rowSelection={{
                            type: 'checkbox',
                            ...rowSelection,
                        }}
                        pagination={{
                            current: productData.pageIndex + 1,
                            total: productData.total,
                            pageSize: productData.pageSize,
                            showQuickJumper: true,
                            showSizeChanger: true,
                            pageSizeOptions: ['10', '20', '50', '100'],
                            showTotal: (total: number) =>
                                `共 ${total} 条记录 第  ${productData.pageIndex + 1}/${Math.ceil(
                                    productData.total / productData.pageSize,
                                )}页`,
                        }}
                    />
                </Card>
            </Spin>
            {productBind && <BindProduct targetId={props.targetId} targetType={props.targetType} close={() => {
                setProductBind(false);

                handleSearch(searchParam);
            }}/>
            }
        </div>
    );
}
Example #17
Source File: bindProduct.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
BindProduct: React.FC<Props> = props => {

    const [spinning, setSpinning] = useState(true);
    const [authority, setAuthority] = useState(false);
    const [productData, setProductData] = useState<any>({});
    const [productIdList, setProductIdList] = useState<any[]>([]);
    const [searchParam, setSearchParam] = useState<any>({
        pageSize: 10,
        terms: {},
        sorts: {
            order: 'descend',
            field: 'id',
        },
    });

    const handleSearch = (parmes: any) => {
        setSearchParam(parmes);
        parmes.terms = {
            ...parmes.terms,
            "id#dim-assets$not": `{"assetType":"product","targets":[{"type":"${props.targetType}","id":"${props.targetId}"}]}`
        };
        api.deviceProdcut
            .query(encodeParam(parmes))
            .then(res => {
                setSpinning(false);
                if (res.status === 200) {
                    setProductData(res.result);
                }
            });
    };

    useEffect(() => {
        handleSearch(searchParam);
    }, []);

    const bindProduct = (value: any) => {
        const data = [{
            "targetType": props.targetType,
            "targetId": props.targetId,
            "assetType": "product",
            "assetIdList": productIdList,
            "permission": value.permission
        }];

        api.assets.BindAssets("product",data)
            .then((result: any) => {
                if (result.status === 200) {
                    message.success("资产分配成功");
                    props.close();
                } else {
                    message.error("资产分配失败");
                }
            }).catch(() => {
        })
    };

    const columns: ColumnProps<any>[] = [
        {
            title: '分类ID',
            align: 'left',
            width: 150,
            dataIndex: 'id',
            ellipsis: true,
        },
        {
            title: '标识',
            align: 'left',
            dataIndex: 'key',
        },
        {
            title: '分类名称',
            dataIndex: 'name',
            align: 'center',
        }
    ];

    const onTableChange = (
        pagination: PaginationConfig,
        filters: any,
        sorter: SorterResult<DeviceInstance>,
    ) => {
        let {terms} = searchParam;
        handleSearch({
            pageIndex: Number(pagination.current) - 1,
            pageSize: pagination.pageSize,
            terms,
            sorts: sorter,
        })
    };

    const rowSelection = {
        onChange: (selectedRowKeys: any) => {
            setProductIdList(selectedRowKeys);
        },
    };

    return (
        <Drawer
            visible
            title='分配产品资产'
            width='50%'
            onClose={() => props.close()}
            closable
        >
            <Spin spinning={spinning}>
                <SearchForm
                    search={(params: any) => {
                        handleSearch({
                            terms: {...params},
                            pageSize: 10,
                            sorts: searchParam.sorts,
                        });
                    }}
                    formItems={[
                        {
                            label: '产品名称',
                            key: 'name$LIKE',
                            type: 'string',
                        },
                        {
                            label: '产品类型',
                            key: 'deviceType$IN',
                            type: 'list',
                            props: {
                                data: [
                                    {id: 'device', name: '直连设备'},
                                    {id: 'childrenDevice', name: '网关子设备'},
                                    {id: 'gateway', name: '网关设备'},
                                ],
                                mode: 'tags',
                            },
                        },
                    ]}
                />
                <Table
                    columns={columns}
                    dataSource={(productData || {}).data}
                    rowKey="id"
                    onChange={onTableChange}
                    rowSelection={{
                        type: 'checkbox',
                        ...rowSelection,
                    }}
                    pagination={{
                        current: productData.pageIndex + 1,
                        total: productData.total,
                        pageSize: productData.pageSize,
                        showQuickJumper: true,
                        showSizeChanger: true,
                        pageSizeOptions: ['10', '20', '50', '100'],
                        showTotal: (total: number) =>
                            `共 ${total} 条记录 第  ${productData.pageIndex + 1}/${Math.ceil(
                                productData.total / productData.pageSize,
                            )}页`,
                    }}
                />
            </Spin>
            <div
                style={{
                    position: 'absolute',
                    right: 0,
                    bottom: 0,
                    width: '100%',
                    borderTop: '1px solid #e9e9e9',
                    padding: '10px 16px',
                    background: '#fff',
                    textAlign: 'right',
                }}
            >
                <Button
                    onClick={() => {
                        props.close();
                    }}
                    style={{marginRight: 8}}
                >
                    关闭
                </Button>
                {productIdList.length > 0 && <Button
                    onClick={() => {
                        setAuthority(true);
                    }}
                    type="primary"
                >
                    绑定
                </Button>}
            </div>
            {authority && <Authority close={(data: any) => {
                setAuthority(false);
                if (data) {
                    bindProduct(data);
                }
            }}/>}
        </Drawer>
    );
}
Example #18
Source File: index.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
deviceBind: React.FC<Props> = (props) => {

    const [searchParam, setSearchParam] = useState({
        pageSize: 10,
        terms: {},
        sorts: {
            order: 'descend',
            field: 'id',
        },
    });
    const [spinning, setSpinning] = useState<boolean>(false);

    const [deviceIdList, setDeviceIdLIst] = useState<any[]>([]);
    const [deviceData, setDeviceData] = useState<any>({});
    const [deviceBind, setDeviceBind] = useState<any>();

    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 handleSearch = (params: any) => {
        setSearchParam(params);
        params.terms = {
            ...params.terms,
            "id#dim-assets": `{"assetType":"device","targets":[{"type":"${props.targetType}","id":"${props.targetId}"}]}`
        };
        api.deviceInstance
            .list(encodeParam(params))
            .then(res => {
                setSpinning(false);
                if (res.status === 200) {
                    setDeviceData(res.result);
                }
            });
    };

    const unBindClassify = (value: any[]) => {
        const data = [{
            "targetType": props.targetType,
            "targetId": props.targetId,
            "assetType": "device",
            "assetIdList": value
        }];

        api.assets.UnBindAssets("device", data)
            .then((result: any) => {
                if (result.status === 200) {
                    message.success("资产解绑成功");
                    deviceIdList.splice(0, deviceIdList.length);
                    handleSearch(searchParam);
                } else {
                    message.error("资产解绑失败");
                    handleSearch(searchParam);
                }
            }).catch(() => {
        })
    };

    const columns: ColumnProps<DeviceInstance>[] = [
        {
            title: 'ID',
            dataIndex: 'id',
            ellipsis: true,
        },
        {
            title: '设备名称',
            dataIndex: 'name',
            ellipsis: true,
        },
        {
            title: '产品名称',
            dataIndex: 'productName',
            ellipsis: true,
        },
        {
            title: '注册时间',
            dataIndex: 'registryTime',
            width: '200px',
            render: (text: any) => (text ? moment(text).format('YYYY-MM-DD HH:mm:ss') : '/'),
            sorter: true,
        },
        {
            title: '状态',
            dataIndex: 'state',
            width: '90px',
            render: record =>
                record ? <Badge status={statusMap.get(record.value)} text={record.text}/> : '',
            filterMultiple: false,
        },
        {
            title: '操作',
            width: '200px',
            align: 'center',
            render: (record: any) => (
                <Fragment>
                    <Popconfirm
                        title="确认解绑?"
                        onConfirm={() => {
                            setSpinning(true);
                            unBindClassify([record.id])
                        }}
                    >
                        <a>解绑</a>
                    </Popconfirm>
                </Fragment>
            ),
        },
    ];

    useEffect(() => {
        if (props.targetId != null || props.targetId != "") {
            handleSearch(searchParam);
        }
    }, [props.targetId]);

    const onTableChange = (
        pagination: PaginationConfig,
        filters: any,
        sorter: SorterResult<DeviceInstance>,
    ) => {
        let {terms} = searchParam;
        handleSearch({
            pageIndex: Number(pagination.current) - 1,
            pageSize: pagination.pageSize,
            terms,
            sorts: sorter,
        });
    };

    const rowSelection = {
        onChange: (selectedRowKeys: any) => {
            setDeviceIdLIst(selectedRowKeys);
        },
    };

    return (
        <div>
            <Spin spinning={spinning}>
                <Card>
                    <SearchForm
                        search={(params: any) => {
                            handleSearch({
                                terms: {...params},
                                pageSize: 10,
                                sorts: searchParam.sorts,
                            });
                        }}
                        formItems={[
                            {
                                label: '设备ID',
                                key: 'id$like',
                                type: 'string',
                            },
                            {
                                label: '设备名称',
                                key: 'name$LIKE',
                                type: 'string',
                            }
                        ]}
                    />
                    <Button
                        icon="plus"
                        type="primary"
                        style={{marginBottom: '20px'}}
                        onClick={() => {
                            setDeviceBind(true);
                        }}
                    >
                        分配资产
                    </Button>
                    {deviceIdList.length > 0 && (
                        <Popconfirm
                            title="确认批量解绑?"
                            onConfirm={() => {
                                setSpinning(true);
                                unBindClassify(deviceIdList);
                            }}
                        >
                            <Button
                                icon="delete"
                                type="primary"
                                style={{marginBottom: '20px', marginLeft: "20px"}}
                            >
                                批量解绑
                            </Button>
                        </Popconfirm>
                    )}
                    <Table
                        columns={columns}
                        dataSource={(deviceData || {}).data}
                        rowKey="id"
                        onChange={onTableChange}
                        rowSelection={{
                            type: 'checkbox',
                            ...rowSelection,
                        }}
                        pagination={{
                            current: deviceData.pageIndex + 1,
                            total: deviceData.total,
                            pageSize: deviceData.pageSize,
                            showQuickJumper: true,
                            showSizeChanger: true,
                            pageSizeOptions: ['10', '20', '50', '100'],
                            showTotal: (total: number) =>
                                `共 ${total} 条记录 第  ${deviceData.pageIndex + 1}/${Math.ceil(
                                    deviceData.total / deviceData.pageSize,
                                )}页`,
                        }}
                    />
                </Card>
                {deviceBind && <BindDecide targetId={props.targetId} targetType={props.targetType} close={() => {
                    setDeviceBind(false);
                    handleSearch(searchParam);
                }}/>}
            </Spin>
        </div>
    );
}
Example #19
Source File: bindDevice.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
BindDecide: React.FC<Props> = props => {

    const [spinning, setSpinning] = useState(true);
    const [authority, setAuthority] = useState(false);
    const [deviceData, setDeviceData] = useState<any>({});
    const [deviceIdList, setDeviceIdList] = useState<any[]>([]);
    const [searchParam, setSearchParam] = useState<any>({
        pageSize: 10,
        terms: {},
        sorts: {
            order: 'descend',
            field: 'id',
        },
    });

    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 handleSearch = (parmes: any) => {
        setSearchParam(parmes);
        parmes.terms = {
            ...parmes.terms,
            "id#dim-assets$not": `{"assetType":"device","targets":[{"type":"${props.targetType}","id":"${props.targetId}"}]}`
        };
        api.deviceInstance
            .list(encodeParam(parmes))
            .then(res => {
                setSpinning(false);
                if (res.status === 200) {
                    setDeviceData(res.result);
                }
            });
    };

    useEffect(() => {
        handleSearch(searchParam);
    }, []);

    const bindProduct = (value: any) => {
        const data = [{
            "targetType": props.targetType,
            "targetId": props.targetId,
            "assetType": "device",
            "assetIdList": deviceIdList,
            "permission": value.permission
        }];

        api.assets.BindAssets("device", data)
            .then((result: any) => {
                if (result.status === 200) {
                    message.success("资产分配成功");
                    props.close();
                } else {
                    message.error("资产分配失败");
                }
            }).catch(() => {
        })
    };

    const columns: ColumnProps<DeviceInstance>[] = [
        {
            title: 'ID',
            dataIndex: 'id',
            ellipsis: true,
        },
        {
            title: '设备名称',
            dataIndex: 'name',
            ellipsis: true,
        },
        {
            title: '产品名称',
            dataIndex: 'productName',
            ellipsis: true,
        },
        {
            title: '注册时间',
            dataIndex: 'registryTime',
            width: '200px',
            render: (text: any) => (text ? moment(text).format('YYYY-MM-DD HH:mm:ss') : '/'),
            sorter: true,
        },
        {
            title: '状态',
            dataIndex: 'state',
            width: '90px',
            render: record =>
                record ? <Badge status={statusMap.get(record.value)} text={record.text}/> : '',
            filterMultiple: false,
        }
    ];

    const onTableChange = (
        pagination: PaginationConfig,
        filters: any,
        sorter: SorterResult<DeviceInstance>,
    ) => {
        let {terms} = searchParam;
        handleSearch({
            pageIndex: Number(pagination.current) - 1,
            pageSize: pagination.pageSize,
            terms,
            sorts: sorter,
        })
    };

    const rowSelection = {
        onChange: (selectedRowKeys: any) => {
            setDeviceIdList(selectedRowKeys);
        },
    };

    return (
        <Drawer
            visible
            title='分配设备资产'
            width='50%'
            onClose={() => props.close()}
            closable
        >
            <Spin spinning={spinning}>
                <SearchForm
                    search={(params: any) => {
                        handleSearch({
                            terms: {...params},
                            pageSize: 10,
                            sorts: searchParam.sorts,
                        });
                    }}
                    formItems={[
                        {
                            label: '设备ID',
                            key: 'id$like',// id
                            type: 'string',
                        },
                        {
                            label: '设备名称',
                            key: 'name$LIKE',
                            type: 'string',
                        }
                    ]}
                />
                <Table
                    columns={columns}
                    dataSource={(deviceData || {}).data}
                    rowKey="id"
                    onChange={onTableChange}
                    rowSelection={{
                        type: 'checkbox',
                        ...rowSelection,
                    }}
                    pagination={{
                        current: deviceData.pageIndex + 1,
                        total: deviceData.total,
                        pageSize: deviceData.pageSize,
                        showQuickJumper: true,
                        showSizeChanger: true,
                        pageSizeOptions: ['10', '20', '50', '100'],
                        showTotal: (total: number) =>
                            `共 ${total} 条记录 第  ${deviceData.pageIndex + 1}/${Math.ceil(
                                deviceData.total / deviceData.pageSize,
                            )}页`,
                    }}
                />
            </Spin>
            <div
                style={{
                    position: 'absolute',
                    right: 0,
                    bottom: 0,
                    width: '100%',
                    borderTop: '1px solid #e9e9e9',
                    padding: '10px 16px',
                    background: '#fff',
                    textAlign: 'right',
                }}
            >
                <Button
                    onClick={() => {
                        props.close();
                    }}
                    style={{marginRight: 8}}
                >
                    关闭
                </Button>
                {deviceIdList.length > 0 && <Button
                    onClick={() => {
                        setAuthority(true);
                    }}
                    type="primary"
                >
                    绑定
                </Button>}
            </div>
            {authority && <Authority close={(data: any) => {
                setAuthority(false);
                if (data) {
                    bindProduct(data);
                }
            }}/>}
        </Drawer>
    );
}
Example #20
Source File: index.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
TenantDevice: React.FC<Props> = (props) => {
  const initState: State = {
    searchParam: {
      pageSize: 10, sorts: {
        order: "descend",
        field: "createTime"
      }
    },
    productList: [],
    deviceData: {},
  };

  const [searchParam, setSearchParam] = useState(initState.searchParam);
  const [deviceData, setDeviceData] = useState(initState.deviceData);
  const [spinning, setSpinning] = useState(true);

  const statusMap = new Map();
  statusMap.set('online', <Tag color="#87d068">在线</Tag>);
  statusMap.set('offline', <Tag color="#f50">离线</Tag>);
  statusMap.set('notActive', <Tag color="#1890ff">未激活</Tag>);

  const handleSearch = (params?: any) => {
    setSearchParam(params);
    apis.deviceInstance.list(encodeQueryParam(params))
      .then((response: any) => {
        if (response.status === 200) {
          setDeviceData(response.result);
        }
        setSpinning(false);
      })
      .catch(() => {
      })
  };

  const columns: ColumnProps<DeviceInstance>[] = [
    {
      title: 'ID',
      dataIndex: 'id',
    },
    {
      title: '设备名称',
      dataIndex: 'name',
    },
    {
      title: '产品名称',
      dataIndex: 'productName',
    },
    {
      title: '状态',
      dataIndex: 'state',
      width: '90px',
      render: record => record ? statusMap.get(record.value) : '',
      filters: [
        {
          text: '未激活',
          value: 'notActive',
        },
        {
          text: '离线',
          value: 'offline',
        },
        {
          text: '在线',
          value: 'online',
        },
      ],
      filterMultiple: false,
    },
  ];

  useEffect(() => {
    handleSearch(searchParam);
  }, []);


  const onTableChange = (
    pagination: PaginationConfig,
    filters: any,
    sorter: SorterResult<DeviceInstance>,) => {
    setSpinning(true);
    let { terms } = searchParam;
    if (filters.state) {
      if (terms) {
        terms.state = filters.state[0];
      } else {
        terms = {
          state: filters.state[0],
        };
      }
    }
    handleSearch({
      pageIndex: Number(pagination.current) - 1,
      pageSize: pagination.pageSize,
      terms,
      sorts: sorter,
    });
  };


  const service = new Service('');
  const [data, setData] = useState<any[]>([]);

  const user = JSON.parse(localStorage.getItem('user-detail') || '{}');
  const tenantId = (user.tenants || []).filter((i: any) => i.mainTenant)[0]?.tenantId;
  const tenantAdmin = (user.tenants || []).filter((i: any) => i.mainTenant)[0]?.adminMember;

  const getProduct = (userId: string) =>
    service.assets.productNopaging(encodeQueryParam({
      terms: {
        id$assets: JSON.stringify({
          tenantId: tenantId,
          assetType: 'product',
          memberId: userId,
        }),
      }
    }));

  const getDeviceState = (product: any, userId: string) =>
    service.assets.instanceNopaging(encodeQueryParam({
      terms: {
        productId: product.id,
        // id$assets: JSON.stringify({
        //   tenantId: tenantId,
        //   assetType: 'device',
        //   memberId: userId,
        // }),
      }
    })).pipe(
      groupBy((instance: any) => instance.state.value),
      mergeMap(group$ => group$.pipe(
        count(),
        map(count => {
          let v: any = {};
          v[group$.key] = count;
          return v;
        }),
      )),
      map(state => ({ productName: product.name, online: state.online || 0, offline: state.offline || 0 })),
      defaultIfEmpty({ productName: product.name, 'online': 0, 'offline': 0 }),
    );

  const getAlarmCount = (productId: string, userId: string) => service.alarm.count(encodeQueryParam({
    terms: {
      // deviceId$assets: JSON.stringify({
      //   tenantId: tenantId,
      //   assetType: 'device',
      //   memberId: userId,
      // }),
      productId: productId,
    }
  }));

  useEffect(() => {
    // todo 查询租户
    if (tenantId) {
      service.member.queryNoPaging({})
        .pipe(
          flatMap((i: any) => getProduct(i.userId)
            .pipe(
              flatMap((product: any) =>
                zip(getDeviceState(product, i.userId), getAlarmCount(product.id, i.userId))),
              map(tp2 => ({ userId: i.userId, name: i.name, key: `${i.userId}-${randomString(7)}`, ...tp2[0], alarmCount: tp2[1] })),
              defaultIfEmpty({ userId: i.userId, name: i.name, key: `${i.userId}` })
            )),
          toArray(),
          map(list => list.sort((a, b) => a.userId - b.userId)),
        ).subscribe((result) => {
          setData(result);
        });
    }
  }, [tenantId]);

  const test: string[] = [];

  const columns2 = [
    {
      title: '成员',
      dataIndex: 'name',
      render: (text, row, index) => {
        test.push(text);
        return {
          children: text,
          props: {
            rowSpan: test.filter(i => i === text).length > 1 ? 0 : data.filter(i => i.name === text).length,
          },
        };
      },
    },
    {
      title: '产品',
      dataIndex: 'productName',
      // render: renderContent,
    },
    {
      title: '设备在线',
      // colSpan: 2,
      dataIndex: 'online',
      render: (text: any) => text || 0,
      // render: (value, row, index) => {
      //     const obj = {
      //         children: value,
      //         props: {
      //             // rowSpan: 0,
      //         },
      //     };
      //     if (index === 2) {
      //         obj.props.rowSpan = 2;
      //     }
      //     // These two are merged into above cell
      //     if (index === 3) {
      //         obj.props.rowSpan = 0;
      //     }
      //     if (index === 4) {
      //         obj.props.colSpan = 0;
      //     }
      //     return obj;
      // },
    },
    {
      title: '设备离线',
      // colSpan: 0,
      dataIndex: 'offline',
      render: (text: any) => text || 0,
    },
    {
      dataIndex: 'alarmCount',
      title: '告警记录',
      render: (text: any) => text || 0,
    },
  ];


  return (
    <Spin spinning={spinning}>
      <Card bordered={false}>
        <div className={styles.tableList}>
          <div className={styles.tableListForm}>
            {/* <Search
              search={(params: any) => {
                setSpinning(true);
                params.state = searchParam.terms?.state;
                handleSearch({ terms: params, pageSize: 10, sorts: searchParam.sorts });
              }}
            /> */}
          </div>
          <div className={styles.StandardTable} style={{ marginTop: 10 }}>
            {/* <Table
              size='middle'
              columns={columns}
              dataSource={(deviceData || {}).data}
              rowKey="id"
              onChange={onTableChange}
              pagination={{
                current: deviceData.pageIndex + 1,
                total: deviceData.total,
                pageSize: deviceData.pageSize,
              }}
            /> */}
            <Table
              size="small"
              pagination={false}
              columns={tenantAdmin ? columns2 : columns2.filter(i => i.dataIndex !== 'name')}
              dataSource={data}
              bordered />
          </div>
        </div>
      </Card>
    </Spin>
  );
}