antd/lib/table#PaginationConfig TypeScript Examples

The following examples show how to use antd/lib/table#PaginationConfig. 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: index.tsx    From jetlinks-ui-antd with MIT License 5 votes vote down vote up
Event: React.FC<Props> = props => {
  const initState: State = {
    list: {},
    searchParam: { pageIndex: 0, pageSize: 10 },
  };

  const [list, setList] = useState(initState.list);
  const [searchParam, setSearchParam] = useState(initState.searchParam);

  const handleSearch = (params?: any) => {
    apis.ruleInstance.event(props.data.id, encodeQueryParam(params)).then(response => {
      if (response.status === 200) {
        setList(response.result);
      }
    });
    setSearchParam(params);
  };

  useEffect(() => {
    handleSearch({
      pageIndex: 0,
      pageSize: 10,
    });
  }, []);

  const onTableChange = (pagination: PaginationConfig) => {
    handleSearch({
      pageIndex: Number(pagination.current) - 1,
      pageSize: pagination.pageSize,
      sorts: {
        field: 'createTime',
        order: 'desc',
      },
      terms: searchParam.terms,
    });
  };

  return (
    <div>
      <Search
        search={(params: any) => {
          handleSearch({ terms: params, pageSize: 10 });
        }}
      />
      <Table
        rowKey="id"
        onChange={onTableChange}
        pagination={{
          current: list.pageIndex + 1,
          total: list.total,
          pageSize: list.pageSize,
          showQuickJumper: true,
          showSizeChanger: true,
          pageSizeOptions: ['10', '20', '50', '100'],
          showTotal: (total: number) =>
            `共 ${total} 条记录 第  ${list.pageIndex + 1}/${Math.ceil(
              list.total / list.pageSize,
            )}页`,
        }}
        columns={[
          {
            dataIndex: 'createTime',
            title: '时间',
            defaultSortOrder: 'descend',
            render: text => moment(text).format('YYYY-MM-DD HH:mm:ss'),
          },
          {
            dataIndex: 'event',
            title: '事件',
          },
          {
            dataIndex: 'ruleData',
            title: '数据',
          },
        ]}
        dataSource={list.data}
      />
    </div>
  );
}
Example #3
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 #4
Source File: propertiesInfo.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
PropertiesInfo: React.FC<Props> = props => {

  const {
    form: { getFieldDecorator },
    form,
  } = props;
  const initState: State = {
    eventColumns: [
      {
        title: '时间',
        dataIndex: 'timestamp',
        render: text => moment(text).format('YYYY-MM-DD HH:mm:ss'),
      },
      {
        title: `${props.item.name}(点击可复制)`,
        dataIndex: 'formatValue',
        ellipsis: true,
        render: text => (
          <CopyToClipboard text={text} onCopy={() => message.success('已复制')}>
            <span>{typeof (text) === 'object' ? JSON.stringify(text) : text}<Icon type="copy" /></span>
          </CopyToClipboard>
        )
      },
      {
        title: '操作',
        dataIndex: 'value',
        render: (text) => (
          <>
            <a onClick={() => {
              Modal.info({
                title: '详情',
                width: 850,
                content: (
                  <Form.Item wrapperCol={{ span: 20 }} labelCol={{ span: 4 }} label={props.item.name}>
                    <AceEditor
                      value={JSON.stringify((text), 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() {
                  console.log('OK');
                },
              });
            }}>详情</a>
          </>
        )
      }
    ],
    propertiesInfo: {},
    marksCreated: {},
    gatewayDataList: [],
    lineArr: [],
    labelMarkerList: [],
    labelsDataList: [],
    mapCenter: [106.57, 29.52],
    markerPosition: [],
    mapCreated: {},
    tabsType: '1',
  };


  const [marksCreated, setMarksCreated] = useState(initState.marksCreated);
  const [mapCenter, setMapCenter] = useState(initState.mapCenter);
  const [propertiesInfo, setPropertiesInfo] = useState<any>({});
  const [gatewayData, setGatewayData] = useState(initState.gatewayDataList);
  const [lineArr, setLineArr] = useState(initState.lineArr);
  const [spinning, setSpinning] = useState(true);
  const [statistics, setStatistics] = useState(false);
  const [mapCreated, setMapCreated] = useState(initState.mapCreated);
  const [labelMarkerList] = useState(initState.labelMarkerList);
  const [labelsDataList, setLabelsDataList] = useState(initState.labelMarkerList);
  const [markerPosition, setMarkerPosition] = useState(initState.markerPosition);
  const [tabsType, setTabsType] = useState(initState.tabsType);
  const [labelsLayer, setLabelsLayer] = useState<any>();
  const [drawPolyline, setDrawPolyline] = useState<any>();
  const [passedPolyline, setPassedPolyline] = useState<any>();

  const handleSearch = (params?: any) => {
    apis.deviceInstance.propertieInfo(props.deviceId, encodeQueryParam({
      terms: {
        ...params.terms,
        property: props.item.id
      },
      sorts: {
        field: 'timestamp',
        order: 'desc',
      },
      pageIndex: params.pageIndex || 0,
      pageSize: params.pageSize || 10
    }))
      .then((response: any) => {
        if (response.status === 200) {
          setPropertiesInfo(response.result);
        }
        setSpinning(false);
      })
      .catch(() => {
      });
  };

  const statisticsChart = (params?: any) => {
    apis.deviceInstance.propertieInfo(props.deviceId, encodeQueryParam(params))
      .then((response: any) => {
        if (response.status === 200) {
          const dataList: any[] = [];
          response.result.data.forEach((item: any) => {
            dataList.push({
              year: moment(item.timestamp).format('YYYY-MM-DD HH:mm:ss'),
              value: Number(item.value),
              type: props.item.name
            });
          });
          setGatewayData(dataList);
        }
        setSpinning(false);
      })
      .catch(() => {
      });
  };

  const trajectory = (params?: any) => {
    apis.deviceInstance.propertieInfo(props.deviceId, encodeQueryParam(params))
      .then((response: any) => {
        if (response.status === 200) {
          let list: any[] = [];
          let labelsData: any[] = [];
          let position: any[] = [];
          response.result.data?.map((item: any, index: number) => {
            if (index === 0) {
              setMapCenter([item.geoValue.lon, item.geoValue.lat]);
              setMarkerPosition([item.geoValue.lon, item.geoValue.lat]);
              position = [item.geoValue.lon, item.geoValue.lat];
            }
            list.push([item.geoValue.lon, item.geoValue.lat]);
            labelsData.push({
              name: item.timestamp, // 时间
              position: [item.geoValue.lon, item.geoValue.lat], //经纬度
              zooms: [3, 20],
              opacity: 1,
              rank: index, //index
              icon: {
                type: 'image',
                image: mark_b,
                size: [19, 22],
                anchor: 'bottom-center',
              },
              text: {
                content: moment(item.timestamp).format('YYYY-MM-DD HH:mm:ss'), //时间
                direction: 'top',
                offset: [0, -2],
                lnglat: [item.geoValue.lon, item.geoValue.lat], //经纬度
                style: {
                  fontSize: 12,
                  fontWeight: 'normal',
                  fillColor: '#FFFFFF',
                  padding: '6 10 6 10',
                  backgroundColor: '#5C5C5C',
                },
              },
            });
          });

          setLineArr([...list]);
          setLabelsDataList([...labelsData]);
          if (Object.keys(mapCreated).length != 0) {
            mapElement(mapCreated, position, list, labelsData);
          }
        }
        setSpinning(false);
      })
      .catch(() => {
      });
  };

  useEffect(() => {
    if (props.item.valueType.type === 'int' || props.item.valueType.type === 'float'
      || props.item.valueType.type === 'double' || props.item.valueType.type === 'long') {
      setStatistics(true);
    }
    handleSearch({
      pageIndex: 0,
      pageSize: 10,
      sorts: {
        field: 'timestamp',
        order: 'desc',
      },
      terms: { property: props.item.id },
    });

    if (props.item.valueType.type === 'geoPoint') {
      trajectory({
        pageIndex: 0,
        pageSize: 1000,
        sorts: {
          field: 'timestamp',
          order: 'asc',
        },
        terms: { property: props.item.id },
      }
      );
    }
  }, []);

  const onTableChange = (pagination: PaginationConfig) => {
    const params = queryParams();
    handleSearch({
      pageIndex: Number(pagination.current) - 1,
      pageSize: pagination.pageSize,
      sorts: {
        field: 'timestamp',
        order: 'desc',
      },
      terms: { ...params, property: props.item.id },
    });
  };

  const queryParams = () => {
    let params = form.getFieldsValue();
    if (params.timestamp$BTW) {
      let formatDate = params.timestamp$BTW.map((e: Moment) =>
        moment(e).format('YYYY-MM-DD HH:mm:ss'),
      );
      params.timestamp$BTW = formatDate.join(',');
    }
    return params;
  };

  const unSearch = () => {
    if (tabsType === '1') {
      if (Object.keys(mapCreated).length != 0) {
        mapCreated.remove(labelsLayer);
        labelsLayer.clear();
      }

      handleSearch({
        pageIndex: 0,
        pageSize: 10,
        sorts: {
          field: 'timestamp',
          order: 'desc',
        },
        terms: { property: props.item.id },
      });
      if (props.item.valueType.type === 'geoPoint') {
        geoPoint();
      }
    } else if (tabsType === '2') {
      statisticsChart(
        {
          pageIndex: 0,
          pageSize: 60,
          sorts: {
            field: 'timestamp',
            order: 'desc',
          },
          terms: { property: props.item.id },
        }
      );
    } else {
      geoPoint();
    }
  };

  const geoPoint = (params?: any) => {
    if (Object.keys(mapCreated).length != 0) {
      mapCreated.remove([marksCreated, labelsLayer, passedPolyline, drawPolyline]);
      labelsLayer.clear();
    }
    setLineArr([]);
    setLabelsDataList([]);
    setMarkerPosition([]);
    trajectory({
      pageIndex: 0,
      pageSize: 1000,
      sorts: {
        field: 'timestamp',
        order: 'asc',
      },
      terms: { ...params, property: props.item.id },
    }
    );
  };

  const tabs = (params: any) => {
    if (Object.keys(mapCreated).length != 0) {
      mapCreated.remove(labelsLayer);
      labelsLayer.clear();
    }
    setSpinning(true);
    handleSearch({
      pageIndex: 0,
      pageSize: 10,
      sorts: {
        field: 'timestamp',
        order: 'desc',
      },
      terms: { ...params, property: props.item.id },
    });
    if (props.item.valueType.type === 'geoPoint') {
      geoPoint(params);
    }
  };

  const onSearch = () => {
    setSpinning(true);
    let params = queryParams();

    if (tabsType === '1') {
      tabs(params);
    } else if (tabsType === '2') {
      statisticsChart(
        {
          pageIndex: 0,
          pageSize: 60,
          sorts: {
            field: 'timestamp',
            order: 'desc',
          },
          terms: { ...params, property: props.item.id },
        }
      );
    } else {
      geoPoint(params);
    }
  };

  const mapElement = (ins: any, position: any, line: any, labelsData: any) => {

    let marker = new window.AMap.Marker({
      map: ins,
      position: position,
      icon: img26,
      offset: new window.AMap.Pixel(-13, -13),
      autoRotation: true,
      angle: -90,
    });
    setMarksCreated(marker);

    // 绘制轨迹
    let draw = new window.AMap.Polyline({
      map: ins,
      path: line,
      showDir: true,
      strokeColor: "#f5222d",  //线颜色
      // strokeOpacity: 1,     //线透明度
      strokeWeight: 6,      //线宽
      // strokeStyle: "solid"  //线样式
    });
    setDrawPolyline(draw);
    // 运动轨迹
    let passed = new window.AMap.Polyline({
      map: ins,
      // path: lineArr,
      strokeColor: "#AF5",  //线颜色
      // strokeOpacity: 1,     //线透明度
      strokeWeight: 6,      //线宽
      // strokeStyle: "solid"  //线样式
    });
    setPassedPolyline(passed);
    marker.on('moving', function (e: any) {
      passed.setPath(e.passedPath);
    });

    // 创建轨迹上的点位
    let layer = new window.AMap.LabelsLayer({
      zooms: [3, 20],
      visible: true,
      collision: false,
    });

    layer.remove(labelMarkerList);
    setLabelsLayer(layer);
    ins.add(layer);

    labelMarkerList.splice(0, labelMarkerList.length);
    let labelMarker = {};
    labelsData.map((item: any) => {
      labelMarker = new window.AMap.LabelMarker(item);

      labelMarkerList.push(labelMarker);
      layer.add(labelMarker);
    });
  };

  // map事件列表
  const mapEvents = {
    created: (ins: any) => {
      setMapCreated(ins);
      mapElement(ins, markerPosition, lineArr, labelsDataList);
    },
  };

  return (
    <Modal
      title="属性详情"
      visible
      onCancel={() => props.close()}
      onOk={() => props.close()}
      width="70%"
    >
      <Spin spinning={spinning}>
        <Form labelCol={{ span: 0 }} wrapperCol={{ span: 18 }}>
          <Row gutter={{ md: 8, lg: 4, xl: 48 }}>
            <Col md={10} sm={24}>
              <Form.Item>
                {getFieldDecorator('timestamp$BTW')(
                  <DatePicker.RangePicker
                    showTime={{ format: 'HH:mm:ss' }}
                    format="YYYY-MM-DD HH:mm:ss"
                    placeholder={['开始时间', '结束时间']}
                    onChange={(value: any[]) => {
                      if (value.length === 0) {
                        unSearch();
                      }
                    }}
                    onOk={onSearch}
                  />,
                )}
              </Form.Item>
            </Col>
          </Row>
        </Form>
        <Tabs defaultActiveKey="1" tabPosition="top" type="card"
          onTabClick={(value: string) => {
            setTabsType(value);

            let params = queryParams();
            if (value === '1') {
              tabs(params);
            } else if (value === '2') {
              setSpinning(true);
              statisticsChart(
                {
                  pageIndex: 0,
                  pageSize: 60,
                  sorts: {
                    field: 'timestamp',
                    order: 'desc',
                  },
                  terms: { ...params, property: props.item.id },
                }
              );
            }
          }}
        >
          <Tabs.TabPane tab="列表" key="1">
            <Table
                loading={spinning}
                columns={initState.eventColumns}
                dataSource={(propertiesInfo || {}).data}
                rowKey="id"
                size="small"
                onChange={onTableChange}
                pagination={{
                  current: propertiesInfo.pageIndex + 1,
                  total: propertiesInfo.total,
                  pageSize: propertiesInfo.pageSize,
                  showQuickJumper: true,
                  showSizeChanger: true,
                  pageSizeOptions: ['10', '20', '50', '100'],
                  showTotal: (total: number) =>
                      `共 ${total} 条记录 第  ${propertiesInfo.pageIndex + 1}/${Math.ceil(
                          propertiesInfo.total / propertiesInfo.pageSize,
                      )}页`,
                }}
            />
          </Tabs.TabPane>

          {statistics && (
            <Tabs.TabPane tab="图表" key="2">
              <Chart
                height={400}
                data={gatewayData}
                scale={{
                  value: { min: 0 },
                  year: {
                    range: [0, 0.96],
                    type: 'timeCat'
                  },
                }}
                forceFit
              >
                <Axis name="year" />
                <Axis name="value" label={{
                  formatter: val => parseFloat(val).toLocaleString()
                }} />
                <Legend />
                <Tooltip crosshairs={{ type: 'y' }} />
                <Geom type="line" position="year*value" size={2} tooltip={[
                  "year*value*type",
                  (year, value, type) => ({
                    title: moment(year).format('YYYY-MM-DD HH:mm:ss'),
                    name: type,
                    value: value
                  })
                ]} />
                <Geom type="area" position="year*value" shape={'circle'} tooltip={[
                  "year*value*type",
                  (year, value, type) => ({
                    title: moment(year).format('YYYY-MM-DD HH:mm:ss'),
                    name: type,
                    value: value
                  })
                ]}
                />
              </Chart>
            </Tabs.TabPane>
          )}

          {props.item.valueType.type === 'geoPoint' && (
            <Tabs.TabPane tab={
              <span>
                轨迹
                <AntdTooltip title='默认启动循环执行动画,运动速度为:200km/h'>
                  <Icon type="question-circle-o" style={{ paddingLeft: 10 }} />
                </AntdTooltip>
              </span>
            } key="3">
              <div style={{ width: '100%', height: '60vh' }}>
                <Map version="1.4.15" resizeEnable events={mapEvents} center={mapCenter} />
              </div>
              <div style={{ marginTop: '-6.4%', paddingRight: 2, textAlign: 'right', float: 'right' }}>
                <Card style={{ width: 240 }}>
                  <Button type="primary"
                    onClick={() => {
                      marksCreated.moveAlong(
                        lineArr, // 路径坐标串
                        200, // 指定速度,单位:千米/小时,不可为0
                        function (k: any) { // 回调函数f为变化曲线函数,缺省为function(k){return k}
                          return k
                        },
                        true // true表明是否循环执行动画,默认为false
                      );
                    }}
                  >
                    开始动画
                  </Button>
                  <Button style={{ marginLeft: 10 }} type="primary"
                    onClick={() => {
                      marksCreated.stopMove();
                    }}
                  >
                    停止动画
                  </Button>
                </Card>
              </div>
            </Tabs.TabPane>
          )}
        </Tabs>
      </Spin>
    </Modal>
  );
}
Example #5
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 #6
Source File: index-backups.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
DeviceModel: React.FC<Props> = props => {
  const { result } = props.deviceProduct;
  const initState: State = {
    data: result,
    searchParam: { pageSize: 10 },
    saveVisible: false,
  };

  const [searchParam, setSearchParam] = useState(initState.searchParam);
  const [saveVisible, setSaveVisible] = useState(initState.saveVisible);
  const [filterData, setFilterData] = useState({});
  const { dispatch } = props;

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

  const deploy = (record: any) => {
    dispatch({
      type: 'deviceProduct/deploy',
      payload: record.id,
      callback: response => {
        if (response.status === 200) {
          message.success('操作成功');
          handleSearch(searchParam);
        }
      },
    });
  };
  const unDeploy = (record: any) => {
    dispatch({
      type: 'deviceProduct/unDeploy',
      payload: record.id,
      callback: response => {
        if (response.status === 200) {
          message.success('操作成功');
          handleSearch(searchParam);
        }
      },
    });
  };

  const handleDelete = (params: any) => {
    dispatch({
      type: 'deviceProduct/remove',
      payload: params.id,
      callback: response => {
        if (response.status === 200) {
          message.success('删除成功');
          handleSearch(searchParam);
        }
      },
    });
  };

  const columns: ColumnProps<DeviceProduct>[] = [
    {
      title: 'ID',
      dataIndex: 'id',
      width: '250px',
    },
    {
      title: '产品名称',
      dataIndex: 'name',
    },
    {
      title: '类型',
      dataIndex: 'deviceType',
      width: '150px',
      align: 'center',
      render: (text: any) => (text || {}).text,
      sorter: true,
    },
    {
      title: '创建时间',
      dataIndex: 'createTime',
      width: '200px',
      align: 'center',
      render: (text: any) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
      sorter: true,
      defaultSortOrder: 'descend',
    },
    {
      title: '发布状态',
      dataIndex: 'state',
      align: 'center',
      filters: [{
        value: '0',
        text: '未发布'
      }, {
        value: '1',
        text: '已发布'
      }],
      render: (text: any) => {
        const color = text === 0 ? 'red' : 'green';
        const status = text === 0 ? '未发布' : '已发布';
        return <Badge color={color} text={status} />;
      },
    },
    {
      title: '操作',
      width: '300px',
      align: 'center',
      render: (record: DeviceProduct) => (
        <Fragment>
          <a
            onClick={() => {
              router.push(`/device/product/save/${record.id}`);
            }}
          >
            查看
          </a>
          <Divider type="vertical" />
          {record.state === 0 ? (
            <span>
              <Popconfirm
                title="确认发布?"
                onConfirm={() => {
                  deploy(record);
                }}
              >
                <a>发布</a>
              </Popconfirm>
              <Divider type="vertical" />
              <Popconfirm title="确定删除?" onConfirm={() => handleDelete(record)}>
                <a>删除</a>
              </Popconfirm>
            </span>
          ) : (
              <Popconfirm
                title="确认停用"
                onConfirm={() => {
                  unDeploy(record);
                }}
              >
                <a>停用</a>
              </Popconfirm>
            )}
          <Divider type="vertical" />
          <a
            onClick={() => {
              downloadObject(record, '产品');
            }}
          >
            下载配置
          </a>
          <Divider type="vertical" />
          <a
            onClick={() => {
              router.push(`/device/instance?productId=${record.id}`);
            }}
          >
            查看设备
          </a>
        </Fragment>
      ),
    },
  ];

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

  const handeSave = (record: any) => {
    dispatch({
      type: 'deviceProduct/insert',
      payload: record,
      callback: response => {
        if (response.status === 200) {
          setSaveVisible(false);
          message.success('保存成功');
          router.push(`/device/product/save/${record.id}`);
        }
      },
    });
  };



  const onTableChange = (
    pagination: PaginationConfig,
    filters: any,
    sorter: SorterResult<DeviceProduct>
  ) => {
    const tempFilter = converObjectKey(filters, { state: 'state$IN' });
    setFilterData(tempFilter);
    handleSearch({
      pageIndex: Number(pagination.current) - 1,
      pageSize: pagination.pageSize,
      terms: { ...searchParam, ...tempFilter },
      sorts: sorter,
    });
  };
  const uploadProps: UploadProps = {
    accept: '.json',
    action: '/jetlinks/file/static',
    headers: {
      'X-Access-Token': getAccessToken(),
    },
    showUploadList: false,
    onChange(info) {
      if (info.file.status === 'done') {
        const fileUrl = info.file.response.result;
        request(fileUrl, { method: 'GET' }).then(e => {
          if (e || e !== null) {
            dispatch({
              type: 'deviceProduct/insert',
              payload: e,
              callback: (response: any) => {
                if (response.status === 200) {
                  message.success('导入成功');
                  handleSearch(searchParam);
                }
              },
            });
          }
        }).catch(() => {
          message.error('导入配置失败');
        });
      }
    },
  };


  // 消息协议
  const [protocolSupports, setProtocolSupports] = useState([]);

  useEffect(() => {
    apis.deviceProdcut
      .protocolSupport()
      .then(response => {
        if (response.status === 200) {
          setProtocolSupports(response.result.map((i: any) => ({ id: i.id, name: i.name })));
        }
      })
      .catch(() => { });
  }, []);

  return (
    <PageHeaderWrapper title="产品管理">
      <Card bordered={false}>
        <div className={styles.tableList}>
          <div>
            <SearchForm
              search={(params: any) => {
                handleSearch({
                  terms: { ...params, ...filterData },
                  pageSize: 10,
                  sorts: searchParam.sorts
                });
              }}
              formItems={[{
                label: '产品名称',
                key: 'name$LIKE',
                type: 'string',
              },
              {
                label: '设备类型',
                key: 'deviceType',
                type: 'list',
                props: {
                  data: [
                    { id: 'gateway', name: '网关' },
                    { id: 'device', name: '设备' }
                  ]
                }
              },
              {
                label: '消息协议',
                key: 'messageProtocol',
                type: 'list',
                props: {
                  data: protocolSupports
                }
              },]}
            />
          </div>
          <div className={styles.tableListOperator}>
            <Button icon="plus" type="primary" onClick={() => setSaveVisible(true)}>
              新建
            </Button>
            <Divider type="vertical" />
            <Upload {...uploadProps}>
              <Button>
                <Icon type="upload" /> 导入配置
              </Button>
            </Upload>
          </div>
          <div className={styles.StandardTable}>
            <Table
              loading={props.loading}
              dataSource={(result || {}).data}
              columns={columns}
              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>
      {saveVisible && <Save close={() => setSaveVisible(false)} save={item => handeSave(item)} />}
    </PageHeaderWrapper>
  );
}
Example #7
Source File: Properties.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
Properties: React.FC<Props> = (props: Props) => {
  const tenantContextData = useContext(TenantContext);
  const productContext = useContext(ProductContext);

  const initState: State = {
    data: props.data || [],
    current: {},
    visible: false,
    importVisible: false,
    product: {}
  };

  const [visible, setVisible] = useState(initState.visible);
  const [importVisible, setImportVisible] = useState(initState.importVisible);
  const [data, setData] = useState(initState.data);
  const [product, setProduct] = useState(initState.product);
  const [current, setCurrent] = useState(initState.current);
  const [searchParam, setSearchParam] = useState<any>({});
  const [dataList, setDataList] = useState(initState.data);
  const sourceList = new Map();
  sourceList.set('device', '设备');
  sourceList.set('manual', '手动');
  sourceList.set('rule', '规则');

  useEffect(() => {
    setData(tenantContextData.properties || [])
  }, [tenantContextData]);

  useEffect(() => {
    setProduct(productContext || {});
  }, [productContext])

  const editItem = (item: any) => {
    setVisible(true);
    setCurrent(item);
  };

  const deleteItem = (item: any) => {
    const temp = data.filter(e => e.id !== item.id);
    setData([...temp]);
    props.save(temp, true);
  };

  const columns: ColumnProps<PropertiesMeta>[] = [
    {
      title: '属性标识',
      dataIndex: 'id',
      align: 'center',
    },
    {
      title: '属性名称',
      dataIndex: 'name',
      align: 'center',
    },
    {
      title: '数据类型',
      dataIndex: 'valueType.type',
      align: 'center',
      render: text => text,
      filters: [
        {
          value: 'int',
          text: '整数型',
        },
        {
          value: 'long',
          text: '长整数型',
        },
        {
          value: 'float',
          text: '单精度浮点型',
        },
        {
          value: 'double',
          text: '双精度浮点数',
        },
        {
          value: 'string',
          text: '字符串',
        },
        {
          value: 'boolean',
          text: '布尔型',
        },
        {
          value: 'date',
          text: '时间型',
        },
        {
          value: 'enum',
          text: '枚举',
        },
        {
          value: 'array',
          text: '数组',
        },
        {
          value: 'object',
          text: '结构体',
        },
        {
          value: 'file',
          text: '文件',
        },
        {
          value: 'password',
          text: '密码',
        },
        {
          value: 'geoPoint',
          text: '地理位置',
        },
      ],
      filterMultiple: false,
    },
    {
      title: '属性值来源',
      dataIndex: 'expands.source',
      align: 'center',
      render: text => sourceList.get(text),
      filters: [
        {
          value: 'device',
          text: '设备',
        },
        {
          value: 'manual',
          text: '手动',
        },
        {
          value: 'rule',
          text: '规则',
        }
      ],
      filterMultiple: false,
    },
    {
      title: '是否只读',
      dataIndex: 'expands.readOnly',
      align: 'center',
      render: text => ((text === 'true' || text === true) ? '是' : '否'),
    },
    {
      title: '说明',
      dataIndex: 'description',
      align: 'center',
      ellipsis: true
    },
    {
      title: '操作',
      render: (text, record) => (
        <Fragment>
          <a onClick={() => editItem(record)}>编辑</a>
          <Divider type="vertical" />
          <a onClick={() => deleteItem(record)}>删除</a>
        </Fragment>
      ),
    },
  ];

  const savePropertiesData = (item: PropertiesMeta, onlySave: boolean) => {
    const i = data.findIndex((j: any) => j.id === item.id);
    if (i > -1) {
      data[i] = item;
    } else {
      data.push(item);
    }
    setData([...data]);
    props.save(data, onlySave);
    setVisible(false);
  };

  const onTableChange = (
    pagination: PaginationConfig,
    filters: any) => {
    let params = { ...searchParam }
    Object.keys(filters || {}).forEach((i: string) => {
      params[i] = filters[i][0]
    })
    handleSearch(params);
  }

  const handleSearch = (params?: any) => {
    setSearchParam(params);
    let items = [...data]
    Object.keys(params || {}).forEach((item) => {
      if (!!params[item]) {
        items = items.filter((i) => {
          return !!_.at(i, item)[0] && _.at(i, item)[0].indexOf(params[item]) !== -1
        })
      }
    })
    setDataList([...items]);
  }

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


  return (
    <div>
      <Card
        title="属性定义"
        style={{ marginBottom: 20 }}
        extra={
          <>
            <Button style={{ marginRight: '10px' }} onClick={() => {
              setImportVisible(true);
            }}>导入属性</Button>
            <Button type="primary" onClick={() => {
              setCurrent({});
              setVisible(true);
            }}>
              添加
            </Button>
          </>
        }
      >
        <div style={{ margin: '10px 0px 20px', display: 'flex', alignItems: 'center' }}>
          <Input.Search allowClear style={{ width: 300 }} placeholder="请输入属性名称" onSearch={(value) => {
            handleSearch({
              ...searchParam,
              name: value
            })
          }} />
        </div>
        <Table rowKey="id" columns={columns} dataSource={dataList} onChange={onTableChange} />
      </Card>
      {visible && (
        <PropertiesDefin
          dataList={data}
          data={current}
          unitsData={props.unitsData}
          save={(item: PropertiesMeta, onlySave: boolean) => {
            savePropertiesData(item, onlySave);
          }}
          close={() => {
            setVisible(false);
            setCurrent({});
          }}
        />
      )}
      {importVisible && <Import data={{
        productId: product?.id
      }} close={() => {
        setImportVisible(false);
      }}
        save={(params: any) => {
          setImportVisible(false);
          let dataParams = JSON.parse(params) || {};
          let list = dataParams?.properties || [];
          props.update(list);
          setData(list);
        }}
      />}
    </div>
  );
}
Example #8
Source File: index.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
Alarm: React.FC<Props> = props => {
  const service = new Service('rule-engine-alarm');
  const {
    form: { getFieldDecorator },
    form,
  } = props;

  const initState: State = {
    data: {},
    saveAlarmData: {},
    searchParam: {
      pageSize: 10,
      // sorts:[{name:"alarmTime",order: 'desc' }]
      sorts: {
        order: "desc",
        field: "alarmTime"
      }
    },
    searchAlarmParam: {
      pageSize: 10
    },
    alarmLogData: {},
    alarmDataList: [],
  };

  const [data, setData] = useState(initState.data);
  const [spinning, setSpinning] = useState(true);
  const [saveVisible, setSaveVisible] = useState(false);
  const [solveVisible, setSolveVisible] = useState(false);
  const [saveAlarmData, setSaveAlarmData] = useState(initState.saveAlarmData);
  const [alarmActiveKey, setAlarmActiveKey] = useState('');
  const [alarmLogId, setAlarmLogId] = useState<string>("");
  const [solveAlarmLog, setSolveAlarmLog] = useState<any>({});
  const [searchParam, setSearchParam] = useState(initState.searchParam);
  const [searchAlarmParam, setSearchAlarmParam] = useState(initState.searchAlarmParam);
  const [alarmLogData, setAlarmLogData] = useState(initState.alarmLogData);
  const [alarmDataList, setAlarmDataList] = useState(initState.alarmDataList);

  const statusMap = new Map();
  statusMap.set('运行中', 'success');
  statusMap.set('已停止', 'error');

  const getProductAlarms = () => {
    alarmDataList.splice(0, alarmDataList.length);
    setSpinning(false)
    service.getAlarmsList(props.device.id, {
      paging: false
    }).subscribe(
      (res) => {
        res.data.map((item: any) => {
          alarmDataList.push(item);
        });
        setAlarmDataList([...alarmDataList]);
      },
      () => setSpinning(false)
    )
  };
  const getData = (params?: any) => {
    setSearchAlarmParam(params)
    service.getAlarmsList(props.device.id, params).subscribe(
      (res) => {
        setData(res);
      },
      () => setSpinning(false)
    )
  }

  useEffect(() => {
    setAlarmActiveKey('info');
    getProductAlarms();
    getData(searchAlarmParam);
    handleSearch(searchParam);
  }, []);

  const submitData = (data: any) => {
    service.saveAlarms(props.device.id, data).subscribe(
      res => {
        message.success('保存成功');
        setSaveVisible(false);
        getProductAlarms();
        getData(searchAlarmParam);
      },
      () => setSpinning(false)
    )
  };

  const _start = (item: alarm) => {
    service._start(props.device.id, { id: item.id }).subscribe(
      () => {
        message.success('启动成功');
        getProductAlarms();
        getData(searchAlarmParam);
        setSpinning(false)
      },
      () => { },
      () => setSpinning(false)
    )
  };

  const _stop = (item: any) => {
    service._stop(props.device.id, { id: item.id }).subscribe(
      () => {
        message.success('停止成功');
        getProductAlarms();
        getData(searchAlarmParam);
        setSpinning(false)
      },
      () => { },
      () => setSpinning(false)
    )
  };

  const deleteAlarm = (id: string) => {
    service._remove(props.device.id, { id: id }).subscribe(
      () => {
        message.success('删除成功');
        getProductAlarms();
        getData(searchAlarmParam);
        setSpinning(false)
      },
      () => { },
      () => setSpinning(false)
    )
  };

  const columns: ColumnProps<alarm>[] = [
    {
      title: '告警名称',
      dataIndex: 'name',
    },
    {
      title: '创建时间',
      dataIndex: 'createTime',
      render: (text: any) => text ? moment(text).format('YYYY-MM-DD HH:mm:ss') : '/',
    },
    {
      title: '运行状态',
      dataIndex: 'state',
      render: record => record ? <Badge status={statusMap.get(record.text)} text={record.text} /> : '',
    },
    {
      title: '操作',
      width: '250px',
      align: 'center',
      render: (record: any) => (
        <Fragment>
          <a onClick={() => {
            setSaveAlarmData(record);
            setSaveVisible(true);
          }}>编辑</a>
          <Divider type="vertical" />
          <a onClick={() => {
            setAlarmLogId(record.id);
            onAlarmProduct(record.id);
            setAlarmActiveKey('logList');
          }}>告警日志</a>
          <Divider type="vertical" />
          {record.state?.value === 'stopped' ? (
            <span>
              <Popconfirm
                title="确认启动此告警?"
                onConfirm={() => {
                  setSpinning(true);
                  _start(record);
                }}
              >
                <a>启动</a>
              </Popconfirm>
              <Divider type="vertical" />
              <Popconfirm
                title="确认删除此告警?"
                onConfirm={() => {
                  setSpinning(true);
                  deleteAlarm(record.id);
                }}
              >
                <a>删除</a>
              </Popconfirm>
            </span>
          ) : (
            <Popconfirm
              title="确认停止此告警?"
              onConfirm={() => {
                setSpinning(true);
                _stop(record);
              }}
            >
              <a>停止</a>
            </Popconfirm>
          )}
        </Fragment>
      ),
    },
  ];

  const alarmLogColumns: ColumnProps<AlarmLog>[] = [
    {
      title: '设备ID',
      dataIndex: 'deviceId',
    },
    {
      title: '设备名称',
      dataIndex: 'deviceName',
    },
    {
      title: '告警名称',
      dataIndex: 'alarmName',
    },
    {
      title: '告警时间',
      dataIndex: 'alarmTime',
      width: '300px',
      render: (text: any) => text ? moment(text).format('YYYY-MM-DD HH:mm:ss') : '/',
      sorter: true,
      defaultSortOrder: 'descend'
    },
    {
      title: '处理状态',
      dataIndex: 'state',
      align: 'center',
      width: '100px',
      render: text => text === 'solve' ? <Tag color="#87d068">已处理</Tag> : <Tag color="#f50">未处理</Tag>,
    },
    {
      title: '操作',
      width: '120px',
      align: 'center',
      render: (record: any) => (
        <Fragment>
          <a onClick={() => {
            let content: string;
            try {
              content = JSON.stringify(record.alarmData, null, 2);
            } catch (error) {
              content = record.alarmData;
            }
            Modal.confirm({
              width: '40VW',
              title: '告警数据',
              content: <pre>{content}
                {record.state === 'solve' && (
                  <>
                    <br /><br />
                    <span style={{ fontSize: 16 }}>处理结果:</span>
                    <br />
                    <p>{record.description}</p>
                  </>
                )}
              </pre>,
              okText: '确定',
              cancelText: '关闭',
            })
          }}>详情</a>
          {

            record.state !== 'solve' && (
              <>
                <Divider type="vertical" />
                <a onClick={() => {
                  setSolveAlarmLog(record);
                  setSolveVisible(true);
                }}>处理</a>
              </>
            )
          }
        </Fragment>
      )
    },
  ];

  const alarmSolve = () => {
    form.validateFields((err, fileValue) => {
      if (err) return;
      let params = {
        descriptionMono: fileValue.description,
        id: solveAlarmLog.id,
        state: 'solve'
      }
      service.updataAlarmLog(props.device.id, params).subscribe(res => {
        setSolveVisible(false);
        handleSearch(searchParam);
        message.success('操作成功!');
      })
    });
  };

  const handleSearch = (params?: any) => {
    setSearchParam(params);
    service.getAlarmLogList(props.device.id, params).subscribe(
      res => {
        setAlarmLogData(res);
      }
    )
  };

  const onAlarmProduct = (value?: string) => {
    handleSearch({
      pageSize: 10,
      where: `alarmId=${value}`
    });
  };

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

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

  const onTableAlarmChange = (
    pagination: PaginationConfig,
  ) => {
    getData({
      pageIndex: Number(pagination.current) - 1,
      pageSize: pagination.pageSize,
      terms: searchParam.terms,
    })
  };

  return (
    <Spin tip="加载中..." spinning={spinning}>
      <Card>
        <Tabs tabPosition="top" type="card" activeKey={alarmActiveKey} onTabClick={(key: any) => {
          setAlarmActiveKey(key);
          // if (key = 'logList') {
          //   setAlarmLogId("");
          //   handleSearch(searchParam);
          // }
        }}>
          <Tabs.TabPane tab="告警设置" key="info">
            <Card title={
              <Button
                icon="plus"
                type="primary"
                onClick={() => {
                  setSaveAlarmData({});
                  setSaveVisible(true);
                }}
              >
                新增告警
              </Button>
            } bordered={false}>
              <Table rowKey="id" columns={columns} dataSource={data.data}
                onChange={onTableAlarmChange}
                pagination={{
                  current: data.pageIndex + 1,
                  total: data.total,
                  pageSize: data.pageSize,
                  showQuickJumper: true,
                  showSizeChanger: true,
                  hideOnSinglePage: true,
                  pageSizeOptions: ['10', '20', '50', '100'],
                  style: { marginTop: -20 },
                  showTotal: (total: number) =>
                    `共 ${total} 条记录 第  ${data.pageIndex + 1}/${Math.ceil(
                      data.total / data.pageSize,
                    )}页`,
                }} />
            </Card>
          </Tabs.TabPane>
          <Tabs.TabPane tab="告警记录" key="logList">
            <div style={{ display: 'flex', justifyContent: 'space-between' }}>
              <Select placeholder="选择告警设置" allowClear style={{ width: 300 }} value={alarmLogId}
                onChange={(value: string) => {
                  setAlarmLogId(value);
                  if (value !== '' && value !== undefined) {
                    onAlarmProduct(value);
                  } else {
                    handleSearch({
                      pageIndex: searchParam.pageIndex,
                      pageSize: searchParam.pageSize
                    });
                  }
                }}
              >
                {alarmDataList.length > 0 && alarmDataList.map(item => (
                  <Select.Option key={item.id}>{item.name}</Select.Option>
                ))}
              </Select>
              <div>
                <Button type="primary" onClick={() => {
                  handleSearch(searchParam);
                }}>刷新</Button>
              </div>
            </div>
            <div className={styles.StandardTable} style={{ marginTop: 10 }}>
              <Table
                dataSource={alarmLogData.data}
                columns={alarmLogColumns}
                rowKey='id'
                onChange={onTableChange}
                pagination={{
                  current: alarmLogData.pageIndex + 1,
                  total: alarmLogData.total,
                  pageSize: alarmLogData.pageSize
                }}
              />
            </div>
          </Tabs.TabPane>
        </Tabs>
      </Card>

      {saveVisible && <AlarmSave
        close={() => {
          setSaveAlarmData({});
          setSaveVisible(false);
          getProductAlarms();
        }}
        save={(data: any) => {
          setSpinning(true);
          submitData(data);
        }}
        data={saveAlarmData}
        deviceId={props.device.id}
      />}

      {solveVisible && (
        <Modal
          title='告警处理结果'
          visible
          okText="确定"
          cancelText="取消"
          width='700px'
          onOk={() => {
            alarmSolve();
          }}
          onCancel={() => {
            setSolveVisible(false);
            setSolveAlarmLog({});
          }}
        >
          <Form labelCol={{ span: 3 }} wrapperCol={{ span: 21 }} key="solve_form">
            <Form.Item key="description" label="处理结果">
              {getFieldDecorator('description', {
                rules: [
                  { required: true, message: '请输入处理结果' },
                  { max: 2000, message: '处理结果不超过2000个字符' }
                ],
              })(
                <Input.TextArea rows={8} placeholder="请输入处理结果" />,
              )}
            </Form.Item>
          </Form>
        </Modal>
      )}
    </Spin>
  );
}
Example #9
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 #10
Source File: index.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
Add: React.FC<Props> = props => {
  const [spin, setSpin] = useState(false);
  const [addVisible, setAddVisible] = useState(false);
  const [channelVisible, setChannelVisible] = useState(false);
  const [playVisible, setPlaylVisible] = useState(false);
  const [leftData, setLeftData] = useState<any>({});
  const [deviceLength, setDeviceLength] = useState(0);
  const [rightData, setRightData] = useState<any>({});
  const [deviceParams, setDeviceParams] = useState({
    pageSize: 8,
  });
  const [channelParams, setChannelParams] = useState({
    pageSize: 8,
  });
  const [device, setDevice] = useState({});
  const [deviceId, setDeviceId] = useState('');
  const [channel, setChannel] = useState({});

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

  const columnsLeft = [
    {
      title: '序号',
      align: 'center',
      width: 60,
      render: (text: string, record: any, index: number) => `${index + 1}`,
    },
    {
      title: '视频设备',
      key: 'device',
      align: 'center',
      render: (text: string, record: any) => (
        <div style={{ width: '100%', textAlign: 'center' }}>
          <div style={{ width: '100%', fontWeight: 600, textAlign: 'center' }}>{record.name}</div>
          <div
            style={{
              width: '100%',
              display: 'flex',
              justifyContent: 'center',
              color: 'rgba(0, 0, 0, 0.4)',
            }}
          >
            <div style={{ fontSize: '10px', marginRight: '5px' }}>IP: {record.host}</div>
            <div style={{ fontSize: '10px' }}>通道:{record.channelNumber || 0}个</div>
          </div>
        </div>
      ),
    },
    {
      title: '状态',
      dataIndex: 'state',
      key: 'state',
      align: 'center',
      render: (record: any) =>
        record ? <Badge status={statusMap.get(record.text)} text={record.text} /> : '',
    },
    {
      title: '协议',
      dataIndex: 'provider',
      key: 'provider',
      align: 'center',
      with: 180,
    },
    {
      title: '操作',
      key: 'action',
      align: 'center',
      width: 100,
      fixed: 'right',
      render: (text: string, record: any) => (
        <>
          <a
            onClick={() => {
              setAddVisible(true);
              setDevice(record);
            }}
          >
            编辑
          </a>
          <Divider type="vertical" />
          <Popconfirm
            title="确认删除吗?"
            onConfirm={() => {
              setSpin(true);
              apis.edgeDevice.delDevice(props.device.id, { deviceId: record.id }).then(res => {
                if (res.status === 200) {
                  message.success('删除成功!');
                  setSpin(false);
                  getDevice(props.device.id, deviceParams);
                }
              });
            }}
          >
            <a>删除</a>
          </Popconfirm>
        </>
      ),
    },
  ];
  const columnsRight = [
    {
      title: '序号',
      align: 'center',
      width: 60,
      render: (text: string, record: any, index: number) => `${index + 1}`,
    },
    {
      title: '通道名称',
      dataIndex: 'name',
      key: 'name',
      align: 'center',
      width: 140,
      ellipsis: true,
      render: (name: string) => {
        return (
          <Tooltip arrowPointAtCenter title={name}>
            {name}
          </Tooltip>
        );
      },
    },
    {
      title: '状态',
      dataIndex: 'status',
      key: 'status',
      align: 'center',
      width: 100,
      render: (record: any) =>
        record ? <Badge status={statusMap.get(record.text)} text={record.text} /> : '',
    },
    {
      title: '通道ID',
      dataIndex: 'channelId',
      key: 'channelId',
      width: 120,
      align: 'center',
      ellipsis: true,
      render: (channelId: string) => {
        return (
          <Tooltip arrowPointAtCenter title={channelId}>
            {channelId}
          </Tooltip>
        );
      },
    },
    {
      title: '协议',
      dataIndex: 'provider',
      key: 'provider',
      width: 100,
      align: 'center',
    },
    {
      title: '操作',
      key: 'action',
      width: 150,
      fixed: 'right',
      align: 'center',
      render: (text: string, record: any) => (
        <>
          <a
            onClick={() => {
              setChannel(record);
              setChannelVisible(true);
            }}
          >
            编辑
          </a>
          {props.edgeTag && (
            <>
              <Divider type="vertical" />
              <a
                onClick={() => {
                  setChannel(record);
                  setPlaylVisible(true);
                }}
              >
                播放
              </a>
            </>
          )}
          <Divider type="vertical" />
          <Popconfirm
            title="确认删除吗?"
            onConfirm={() => {
              apis.edgeDevice
                .delChannel(props.device.id, { channelDataId: record.id })
                .then(res => {
                  if (res.status === 200) {
                    message.success('删除成功!');
                    getChannel(props.device.id, channelParams);
                  }
                });
            }}
          >
            <a>删除</a>
          </Popconfirm>
        </>
      ),
    },
  ];

  const getDevice = (id: string, params: any) => {
    setSpin(true);
    setDeviceParams(params);
    apis.edgeDevice.getDeviceList(id, params).then(res => {
      if (res.status === 200) {
        setLeftData(res.result[0]);
        setSpin(false);
        setDeviceLength(res.result[0].total);
      }
    });
  };

  const getChannel = (id: string, params: any) => {
    setChannelParams(params);
    apis.edgeDevice.getChannelList(id, params).then(res => {
      if (res.status === 200) {
        setRightData(res.result[0]);
      }
    });
  };

  const backgroundStyle = (record: any) => {
    return record.id === deviceId ? styles.clickRowStyl : '';
  };

  const saveOnvif = (fileValue: any) => {
    if (!!fileValue.id) {
      apis.edgeDevice.addOnvif(props.device.id, fileValue).then(response => {
        if (response.status === 200) {
          message.success('保存成功!');
        }
        setSpin(false);
        getDevice(props.device.id, deviceParams);
      });
    } else {
      let param = {
        url: fileValue.url,
        username: fileValue.username,
        password: fileValue.password,
      };
      apis.edgeDevice.getOnvif(props.device.id, param).then(res => {
        if (res.status === 200) {
          if (res.result.length > 0) {
            let data = res.result[0];
            let mediaProfiles = (res.result[0]?.mediaProfiles || []).map(
              (item: any, index: number) => {
                let ra = Math.round(Math.random() * 10000000000);
                return {
                  name: item.name,
                  token: item.token,
                  id: `channel${index}${ra}`,
                };
              },
            );
            let params = {
              id: `device${Math.round(Math.random() * 10000000000)}`,
              firmwareVersion: data.firmwareVersion,
              hardwareId: data.hardwareId,
              description: fileValue.description,
              manufacturer: data.manufacturer,
              mediaProfiles: mediaProfiles,
              model: data.model,
              name: fileValue.name || data.name,
              password: data.password,
              serialNumber: data.serialNumber,
              url: data.url,
              username: data.username,
            };
            apis.edgeDevice.addOnvif(props.device.id, params).then(response => {
              if (response.status === 200) {
                message.success('保存成功!');
              }
              setSpin(false);
              getDevice(props.device.id, deviceParams);
            });
          }
        } else {
          setSpin(false);
        }
      });
    }
  };

  const onTableChange = (pagination: PaginationConfig) => {
    getDevice(props.device.id, {
      pageIndex: Number(pagination.current) - 1,
      pageSize: pagination.pageSize,
    });
  };

  const onRightTableChange = (pagination: PaginationConfig) => {
    getChannel(props.device.id, {
      pageIndex: Number(pagination.current) - 1,
      pageSize: pagination.pageSize,
    });
  };

  useEffect(() => {
    getDevice(props.device.id, deviceParams);
    getChannel(props.device.id, channelParams);
  }, []);

  return (
    <Spin spinning={spin}>
      <div className={styles.box}>
        <div className={styles.left}>
          <Card
            title="视频设备"
            bordered={false}
            extra={
              <div className={styles.leftTop}>
                <div>
                  <span>已接入设备: {deviceLength}</span>
                </div>
                <div>
                  <Button
                    type="primary"
                    onClick={() => {
                      setAddVisible(true);
                      setDevice({});
                    }}
                  >
                    添加设备
                  </Button>
                </div>
                <div>
                  <Button
                    type="primary"
                    onClick={() => {
                      getDevice(props.device.id, deviceParams);
                      setDeviceId('');
                      getChannel(props.device.id, {
                        pageSize: 8,
                      });
                    }}
                  >
                    刷新
                  </Button>
                </div>
              </div>
            }
          >
            <div className={styles.leftTable}>
              <Table
                size="small"
                rowKey="id"
                scroll={{ x: 600 }}
                rowClassName={backgroundStyle}
                onRow={record => {
                  return {
                    onClick: () => {
                      setDeviceId(record.id);
                      let params = {
                        where: `deviceId = ${record.id}`,
                        pageSize: 8,
                      };
                      getChannel(props.device.id, params);
                    },
                  };
                }}
                onChange={onTableChange}
                columns={columnsLeft}
                dataSource={leftData?.data || []}
                pagination={{
                  current: leftData.pageIndex + 1,
                  total: leftData.total,
                  pageSize: leftData.pageSize,
                }}
              />
            </div>
          </Card>
        </div>
        <div className={styles.right}>
          <Card
            title="视频通道"
            bordered={false}
            extra={
              <Button
                type="primary"
                onClick={() => {
                  if (deviceId === '') {
                    getChannel(props.device.id, channelParams);
                  } else {
                    getChannel(props.device.id, {
                      where: `deviceId = ${deviceId}`,
                      pageSize: 8,
                    });
                  }
                }}
              >
                刷新
              </Button>
            }
          >
            <div className={styles.rightTable}>
              <Table
                rowKey="id"
                scroll={{ x: 600 }}
                onChange={onRightTableChange}
                columns={columnsRight}
                dataSource={rightData?.data || []}
                pagination={{
                  current: rightData.pageIndex + 1,
                  total: rightData.total,
                  pageSize: rightData.pageSize,
                }}
              />
            </div>
          </Card>
        </div>
        {addVisible && (
          <AddDevice
            deviceId={props.device.id}
            close={() => {
              setAddVisible(false);
            }}
            data={{ ...device }}
            save={(data: any) => {
              setSpin(true);
              saveOnvif(data);
              setAddVisible(false);
            }}
          />
        )}
        {channelVisible && (
          <ChannelEdit
            id={props.device.id}
            close={() => {
              setChannelVisible(false);
            }}
            data={{ ...channel }}
            save={() => {
              setChannelVisible(false);
              getChannel(props.device.id, channelParams);
            }}
          />
        )}
        {playVisible && (
          <Play
            close={() => {
              setPlaylVisible(false);
            }}
            data={{ ...channel }}
            deviceId={props.device.id}
            save={() => {
              setPlaylVisible(false);
            }}
          />
        )}
      </div>
    </Spin>
  );
}
Example #11
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 #12
Source File: index.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
ChoiceDevice = (props: Props) => {
    const { masterId } = props
    const initState: State = {
        searchParam: {
            pageSize: 10,
            pageIndex: 0,
            terms: []
        },
        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);
        const data = {
            pageSize: params.pageSize || 10,
            pageIndex: params.pageIndex || 0,
            "terms": [
                {
                    "terms": [
                        {
                            "column": "id$modbus-master$not",
                            "value": masterId
                        },
                        ...params?.terms
                    ]
                }
            ]
        }
        apis.modbus.getDeviceList(data).then(response => {
            if (response.status === 200) {
                setDeviceData(response.result);
            }
            setSpinning(false);
        })
    };

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

    const onTableChange = (
        pagination: PaginationConfig
    ) => {
        handleSearch({
            pageIndex: Number(pagination.current) - 1,
            pageSize: pagination.pageSize,
            terms: searchParam?.terms || []
        });
    };

    const rowSelection = {
        onChange: (selectedRowKeys: any) => {
            setDeviceList(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'),
            ellipsis: true,
        },
        {
            title: '状态',
            dataIndex: 'state',
            width: '80px',
            render: record =>
                record ? <Badge status={statusMap.get(record.text)} text={record.text} /> : '',
        },
    ];

    return (
        <Modal
            title="绑定设备"
            visible
            width="80vw"
            onCancel={() => {
                props.save([]);
            }}
            onOk={() => {
                props.save(deviceList)
            }}
        >
            <Spin spinning={spinning}>
                <div className={styles.tableList}>
                    <div className={styles.tableListForm}>
                        <SearchForm
                            search={(params: any) => {
                                const data: any[] = []
                                if (params) {
                                    Object.keys(params).forEach(key => {
                                        if (params[key]) {
                                            data.push({
                                                "column": key,
                                                "value": `%${params[key]}%`,
                                                "termType": "like",
                                                "type": "and"
                                            })
                                        }
                                    })
                                }
                                handleSearch({
                                    pageSize: 10,
                                    terms: [...data]
                                })
                            }}
                            formItems={[
                                {
                                    label: '设备ID',
                                    key: 'id',
                                    type: 'string',
                                },
                                {
                                    label: '设备名称',
                                    key: 'name',
                                    type: 'string',
                                }
                            ]}
                        />
                    </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>
        </Modal>
    );
}
Example #13
Source File: index.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
Config: React.FC<Props> = props => {
  const { noticeConfig, loading, dispatch } = props;

  const initState: State = {
    typeList: [],
    // activeType: '',
    saveVisible: false,
    currentItem: {},
    searchParam: {},
    filterType: [],
    filterName: '',
    debugVisible: false,
  };
  const [typeList, setTypeList] = useState(initState.typeList);
  // const [activeType, setActiveType] = useState(initState.activeType);
  const [saveVisible, setSaveVisible] = useState(initState.saveVisible);
  const [currentItem, setCurrentItem] = useState(initState.currentItem);
  const [searchParam, setSearchParam] = useState(initState.searchParam);
  const [filterType, setFilterType] = useState(initState.filterType);
  const [filterName, setFilterName] = useState(initState.filterName);
  const [debugVisible, setDebugVisible] = useState(initState.debugVisible);
  const [logVisible, setLogVisible] = useState(false);
  const handlerSearch = (params?: any) => {
    dispatch({
      type: 'noticeConfig/query',
      payload: encodeQueryParam(params),
    });
    setSearchParam(params);
  };

  const onSearch = (type?: string[], name?: string) => {
    const tempType = type || filterType;
    const tempName = name || filterName;
    const param = {
      paging: false,
      sorts: {
        field: 'id',
        order: 'desc',
      },
      terms: {
        type$IN: tempType,
        name$LIKE: tempName,
      },
    };
    setSearchParam(param);
    dispatch({
      type: 'noticeConfig/query',
      payload: encodeQueryParam(param),
    });
  };

  useEffect(() => {
    apis.notifier.configType().then((res: any) => {
      if (res) {
        setTypeList(res.result);
      }
    });
    handlerSearch({
      pageIndex: 0,
      pageSize: 10,
    });
  }, []);

  const remove = (record: any) => {
    dispatch({
      type: 'noticeConfig/remove',
      payload: record.id,
      callback: () => {
        message.success('删除成功');
        handlerSearch(searchParam);
      },
    });
  };

  const saveData = (item: any) => {
    dispatch({
      type: 'noticeConfig/insert',
      payload: item,
      callback: () => {
        message.success('保存成功');
        setSaveVisible(false);
        handlerSearch(searchParam);
      },
    });
  };

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

  const uploadProps = (item: any) => {
    dispatch({
      type: 'noticeConfig/insert',
      payload: item,
      callback: (data) => {
        if(data.status===200){
          message.success('导入成功');
        }
        handlerSearch(searchParam);
      },
    });
  };

  /*const uploadProps: UploadProps = {
    accept: '.json',
    action: '/jetlinks/file/static',
    headers: {
      'X-Access-Token': getAccessToken(),
    },
    showUploadList: false,
    onChange(info) {

      if (info.file.status === 'done') {
        const fileUrl = info.file.response.result;
        request(fileUrl, { method: 'GET' }).then(e => {
          dispatch({
            type: 'noticeConfig/insert',
            payload: e,
            callback: () => {
              message.success('导入成功');
              handlerSearch(searchParam);
            },
          });
        });
      }
      if (info.file.status === 'error') {
        message.error(`${info.file.name} 导入失败.`);
      }
    },
  };*/

  return (
    <PageHeaderWrapper title="通知配置">
      <div className={styles.filterCardList}>
        <Card bordered={false}>
          <Form layout="inline">
            <StandardFormRow title="组件类型" block style={{ paddingBottom: 11 }}>
              <Form.Item>
                <TagSelect
                  // expandable
                  onChange={(value: any[]) => {
                    setFilterType(value);
                    onSearch(value, undefined);
                  }}
                >
                  {(typeList || []).map(item => (
                    <TagSelect.Option key={item.id} value={item.id}>
                      {item.name}
                    </TagSelect.Option>
                  ))}
                </TagSelect>
              </Form.Item>
            </StandardFormRow>
            <StandardFormRow title="其它选项" grid last>
              <Row gutter={16}>
                <Col lg={8} md={10} sm={10} xs={24}>
                  <Form.Item {...formItemLayout} label="配置名称">
                    <Input
                      onChange={e => {
                        setFilterName(e.target.value);
                        onSearch(undefined, e.target.value);
                      }}
                    />
                  </Form.Item>
                </Col>
              </Row>
            </StandardFormRow>
          </Form>
        </Card>
        <br />
        <Card>
          <Button
            onClick={() => {
              setCurrentItem({});
              setSaveVisible(true);
            }}
            type="primary"
            style={{ marginBottom: 16 }}
          >
            新建
          </Button>
          <Divider type="vertical" />
          <Button
            onClick={() => {
              downloadObject(noticeConfig.result?.data, '通知配置');
            }}
            style={{ marginBottom: 16 }}
          >
            导出配置
          </Button>
          <Divider type="vertical" />
          {/*<Upload {...uploadProps}>
            <Button type="primary" style={{ marginBottom: 16 }}>
              导入配置
            </Button>
          </Upload>*/}
          <Upload
          action="/jetlinks/file/static"
          headers={{
            'X-Access-Token': getAccessToken(),
          }}
            showUploadList={false} accept='.json'
            beforeUpload={(file) => {
              const reader = new FileReader();
              reader.readAsText(file);
              reader.onload = (result) => {
                try {
                  uploadProps(JSON.parse(result.target.result));
                } catch (error) {
                  message.error('文件格式错误');
                }
              }
            }}
          >
            <Button>
              <Icon type="upload" />导入配置
            </Button>
          </Upload>
          <Table
            rowKey="id"
            loading={loading}
            onChange={onTableChange}
            columns={[
              {
                dataIndex: 'id',
                title: 'ID',
                defaultSortOrder: 'descend',
              },
              {
                dataIndex: 'name',
                title: '配置名称',
              },
              {
                dataIndex: 'type',
                title: '通知类型',
              },
              {
                dataIndex: 'provider',
                title: '服务商',
              },
              {
                dataIndex: 'option',
                title: '操作',
                render: (text, record: any) => (
                  <Fragment>
                    <a
                      onClick={() => {
                        setCurrentItem(record);
                        setSaveVisible(true);
                      }}
                    >
                      编辑
                    </a>
                    <Divider type="vertical" />
                    <Popconfirm
                      title="确认删除?"
                      onConfirm={() => {
                        remove(record);
                      }}
                    >
                      <a>删除</a>
                    </Popconfirm>
                    <Divider type="vertical" />
                    <a onClick={() => downloadObject(record, '通知配置')}>下载配置</a>
                    <Divider type="vertical" />
                    <a
                      onClick={() => {
                        setCurrentItem(record);
                        setDebugVisible(true);
                      }}
                    >
                      调试
                    </a>
                    <Divider type="vertical" />
                    <a
                      onClick={() => {
                        setCurrentItem(record);
                        setLogVisible(true);
                      }}
                    >
                      通知记录
                    </a>
                  </Fragment>
                ),
              },
            ]}
            dataSource={noticeConfig.result?.data}
            pagination={{
              current: noticeConfig.result?.pageIndex + 1,
              total: noticeConfig.result?.total,
              pageSize: noticeConfig.result?.pageSize,
              showQuickJumper: true,
              showSizeChanger: true,
              pageSizeOptions: ['10', '20', '50', '100'],
              showTotal: (total: number) =>
                `共 ${total} 条记录 第  ${noticeConfig.result?.pageIndex + 1}/${Math.ceil(
                  noticeConfig.result?.total / noticeConfig.result?.pageSize,
                )}页`,
            }}
          />
        </Card>
      </div>

      {saveVisible && (
        <Save
          data={currentItem}
          close={() => setSaveVisible(false)}
          save={(item: any) => saveData(item)}
        />
      )}
      {debugVisible && <Debug data={currentItem} close={() => setDebugVisible(false)} />}
      {logVisible && <Logger close={() => setLogVisible(false)} data={currentItem} />}
    </PageHeaderWrapper>
  );
}
Example #14
Source File: index.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
Template: React.FC<Props> = props => {
  const { noticeTemplate, loading, dispatch } = props;

  const initState: State = {
    typeList: [],
    activeType: '',
    saveVisible: false,
    currentItem: {},
    searchParam: {},
    filterType: [],
    filterName: '',
    debugVisible: false,
  };
  const [typeList, setTypeList] = useState(initState.typeList);
  // const [activeType, setActiveType] = useState(initState.activeType);
  const [saveVisible, setSaveVisible] = useState(initState.saveVisible);
  const [currentItem, setCurrentItem] = useState(initState.currentItem);
  const [searchParam, setSearchParam] = useState(initState.searchParam);
  const [filterType, setFilterType] = useState(initState.filterType);
  const [filterName, setFilterName] = useState(initState.filterName);
  const [debugVisible, setDebugVisible] = useState(initState.debugVisible);

  const handlerSearch = (params?: any) => {
    const temp = params;
    temp.sorts = {
      field: 'id',
      order: 'desc',
    };
    dispatch({
      type: 'noticeTemplate/query',
      payload: encodeQueryParam(temp),
    });
    setSearchParam(temp);
  };

  const onSearch = (type?: string[], name?: string) => {
    const tempType = type || filterType;
    const tempName = name || filterName;

    dispatch({
      type: 'noticeTemplate/query',
      payload: encodeQueryParam({
        paging: false,
        sorts: {
          field: 'id',
          order: 'desc',
        },
        terms: {
          type$IN: tempType,
          name$LIKE: name === '' ? undefined : tempName,
        },
      }),
    });
  };

  useEffect(() => {
    apis.notifier.configType().then((res: any) => {
      if (res) {
        setTypeList(res.result);
      }
    });
    handlerSearch({
      pageIndex: 0,
      pageSize: 10,
    });
  }, []);

  const remove = (record: any) => {
    dispatch({
      type: 'noticeTemplate/remove',
      payload: record.id,
      callback: (res) => {
        if (res.status === 200) {
          message.success('删除成功');
          handlerSearch(searchParam);
        }
      },
    });
  };

  const saveData = (item: any) => {
    dispatch({
      type: 'noticeTemplate/insert',
      payload: item,
      callback: (res) => {
        if (res.status === 200) {
          message.success('保存成功');
          setSaveVisible(false);
          handlerSearch(searchParam);
        }
      },
    });
  };

  const onTableChange = (
    pagination: PaginationConfig,
    filters: any,
    sorter: any,
    // extra: any,
  ) => {
    handlerSearch({
      pageIndex: Number(pagination.current) - 1,
      pageSize: pagination.pageSize,
      terms: searchParam,
      sorts: sorter,
    });
  };

  const uploadProps = (item: any) => {
    dispatch({
      type: 'noticeTemplate/insert',
      payload: item,
      callback: (res) => {
        if (res.status === 200) {
          message.success('导入成功');
          handlerSearch(searchParam);
        }
      },
    });
  };

  /*const uploadProps: UploadProps = {
    accept: '.json',
    action: '/jetlinks/file/static',
    headers: {
      'X-Access-Token': getAccessToken(),
    },
    showUploadList: false,
    onChange(info) {
      if (info.file.status !== 'uploading') {
        // console.log(info.file, info.fileList);
      }
      if (info.file.status === 'done') {
        const fileUrl = info.file.response.result;
        request(fileUrl, { method: 'GET' }).then(e => {
          dispatch({
            type: 'noticeTemplate/insert',
            payload: e,
            callback: () => {
              message.success('导入成功');
              handlerSearch(searchParam);
            },
          });
        });
      }
      if (info.file.status === 'error') {
        message.error(`${info.file.name} 导入失败.`);
      }
    },
  };*/

  return (
    <PageHeaderWrapper title="通知模版">
      <div className={styles.filterCardList}>
        <Card bordered={false}>
          <Form layout="inline">
            <StandardFormRow title="组件类型" block style={{ paddingBottom: 11 }}>
              <Form.Item>
                <TagSelect
                  // expandable
                  onChange={(value: any[]) => {
                    setFilterType(value);
                    onSearch(value, undefined);
                  }}
                >
                  {typeList?.map(item => (
                    <TagSelect.Option key={item.id} value={item.id}>
                      {item.name}
                    </TagSelect.Option>
                  ))}
                </TagSelect>
              </Form.Item>
            </StandardFormRow>
            <StandardFormRow title="其它选项" grid last>
              <Row gutter={16}>
                <Col lg={8} md={10} sm={10} xs={24}>
                  <Form.Item {...formItemLayout} label="配置名称">
                    <Input
                      onChange={e => {
                        const tempValue = e.target.value;
                        setFilterName(tempValue);
                        onSearch(undefined, tempValue === '' ? undefined : tempValue);
                      }}
                    />
                  </Form.Item>
                </Col>
              </Row>
            </StandardFormRow>
          </Form>
        </Card>
        <br />
        <Card>
          <Button
            onClick={() => {
              setCurrentItem({});
              setSaveVisible(true);
            }}
            type="primary"
            style={{ marginBottom: 16 }}
          >
            新建
          </Button>
          <Divider type="vertical" />
          <Button
            onClick={() => {
              downloadObject(noticeTemplate.result?.data, '通知模板');
            }}
            style={{ marginBottom: 16 }}
          >
            导出配置
          </Button>
          <Divider type="vertical" />
          {/*<Upload {...uploadProps}>
            <Button type="primary" style={{ marginBottom: 16 }}>
              导入配置
            </Button>
          </Upload>*/}
          <Upload
          action="/jetlinks/file/static"
          headers={{
            'X-Access-Token': getAccessToken(),
          }}
            showUploadList={false} accept='.json'
            beforeUpload={(file) => {
              const reader = new FileReader();
              reader.readAsText(file);
              reader.onload = (result) => {
                try {
                  uploadProps(JSON.parse(result.target.result));
                } catch (error) {
                  message.error('文件格式错误');
                }
              }
            }}
          >
            <Button>
              <Icon type="upload" />导入配置
            </Button>
          </Upload>

          <Table
            rowKey="id"
            onChange={onTableChange}
            loading={loading}
            columns={[
              {
                dataIndex: 'id',
                title: 'ID',

                defaultSortOrder: 'descend',
              },
              {
                dataIndex: 'name',
                title: '模版名称',
              },
              {
                dataIndex: 'type',
                title: '通知类型',
              },
              {
                dataIndex: 'provider',
                title: '服务商',
              },
              {
                dataIndex: 'option',
                title: '操作',
                render: (text, record: any) => (
                  <Fragment>
                    <a
                      onClick={() => {
                        setCurrentItem(record);
                        setSaveVisible(true);
                      }}
                    >
                      编辑
                    </a>
                    <Divider type="vertical" />
                    <Popconfirm
                      title="确认删除?"
                      onConfirm={() => {
                        remove(record);
                      }}
                    >
                      <a>删除</a>
                    </Popconfirm>
                    <Divider type="vertical" />
                    <a onClick={() => downloadObject(record, '通知模版')}>下载配置</a>
                    <Divider type="vertical" />
                    <a
                      onClick={() => {
                        setCurrentItem(record);
                        setDebugVisible(true);
                      }}
                    >
                      调试
                    </a>
                  </Fragment>
                ),
              },
            ]}
            dataSource={noticeTemplate.result?.data}
            pagination={{
              current: noticeTemplate.result?.pageIndex + 1,
              total: noticeTemplate.result?.total,
              pageSize: noticeTemplate.result?.pageSize,
              showQuickJumper: true,
              showSizeChanger: true,
              pageSizeOptions: ['10', '20', '50', '100'],
              showTotal: (total: number) =>
                `共 ${total} 条记录 第  ${noticeTemplate.result?.pageIndex + 1}/${Math.ceil(
                  noticeTemplate.result?.total / noticeTemplate.result?.pageSize,
                )}页`,
            }}
          />
        </Card>
      </div>

      {saveVisible && (
        <Save
          data={currentItem}
          close={() => setSaveVisible(false)}
          save={(item: any) => saveData(item)}
        />
      )}
      {debugVisible && <Debug data={currentItem} close={() => setDebugVisible(false)} />}
    </PageHeaderWrapper>
  );
}
Example #15
Source File: index.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
Log: React.FC<Props> = props => {
  const initState: State = {
    list: {},
    searchParam: { pageIndex: 0, pageSize: 10 },
  };

  const [list, setList] = useState(initState.list);
  const [searchParam, setSearchParam] = useState(initState.searchParam);

  const handleSearch = (params?: any) => {
    apis.ruleInstance.log(props.data.id, encodeQueryParam(params)).then(response => {
      if (response.status === 200) {
        setList(response.result);
      }
    });
    setSearchParam(params);
  };

  useEffect(() => {
    handleSearch({
      pageIndex: 0,
      pageSize: 10,
    });
  }, []);

  const onTableChange = (pagination: PaginationConfig) => {
    handleSearch({
      pageIndex: Number(pagination.current) - 1,
      pageSize: pagination.pageSize,
      sorts: {
        field: 'createTime',
        order: 'desc',
      },
      terms: searchParam.terms,
    });
  };

  return (
    <div>
      <Search
        search={(params: any) => {
          handleSearch({ terms: params, pageSize: 10 });
        }}
      />
      <Table
        rowKey="id"
        onChange={onTableChange}
        pagination={{
          current: list.pageIndex + 1,
          total: list.total,
          pageSize: list.pageSize,
          showQuickJumper: true,
          showSizeChanger: true,
          pageSizeOptions: ['10', '20', '50', '100'],
          showTotal: (total: number) =>
            `共 ${total} 条记录 第  ${list.pageIndex + 1}/${Math.ceil(
              list.total / list.pageSize,
            )}页`,
        }}
        columns={[
          {
            dataIndex: 'createTime',
            title: '时间',
            defaultSortOrder: 'descend',
            render: text => moment(text).format('YYYY-MM-DD HH:mm:ss'),
          },
          {
            dataIndex: 'level',
            title: 'LEVEL',
            render: text => <Tag color="#f50">{text}</Tag>,
          },
          {
            dataIndex: 'message',
            title: '消息',
          },
        ]}
        dataSource={list.data}
      />
    </div>
  );
}
Example #16
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 #17
Source File: index.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
OrgList: React.FC<Props> = props => {
  const {
    dispatch,
    org: { result },
  } = props;

  const initState: State = {
    data: result,
    searchParam: { pageSize: 10 },
    saveVisible: false,
    currentItem: {},
    parentId: null,
    autzVisible: false,
    userVisible: false,
  };

  const [searchParam, setSearchParam] = useState(initState.searchParam);
  const [saveVisible, setSaveVisible] = useState(initState.saveVisible);
  const [currentItem, setCurrentItem] = useState(initState.currentItem);
  const [parentId, setParentId] = useState(initState.parentId);
  const [autzVisible, setAutzVisible] = useState(initState.autzVisible);
  const [userVisible, setUserVisible] = useState(initState.userVisible);

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

  useEffect(() => {
    handleSearch({
      terms: {
        typeId: 'org',
      },
      paging: false,
    });
  }, []);

  const saveOrUpdate = (item: OrgItem) => {
    if (currentItem.id) {
      dispatch({
        //编辑
        type: 'org/insert',
        payload: encodeQueryParam(item),
        callback: (response: any) => {
          if (response.status === 200) {
            message.success('保存成功');
          }
          setSaveVisible(false);
          handleSearch(searchParam);
        },
      });
    } else {
      apis.org.add(item).then(res => {
        if (res.status === 200) {
          message.success('保存成功');
        }
        setSaveVisible(false);
        handleSearch(searchParam);
      });
    }
  };
  const handleDelete = (item: any) => {
    dispatch({
      type: 'org/remove',
      payload: item.id,
      callback: (response: any) => {
        if (response) {
          message.success('删除成功');
          handleSearch(searchParam);
        }
      },
    });
  };

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

  const columns: ColumnProps<OrgItem>[] = [
    {
      title: '机构标识',
      dataIndex: 'id',
      width: '45%',
    },
    {
      title: '机构名称',
      dataIndex: 'name',
      width: '15%',
    },
    {
      title: '描述',
      dataIndex: 'describe',
      width: '10%',
    },
    {
      title: '操作',
      width: '20%',
      render: (text, record) => (
        <Fragment>
          <a
            onClick={() => {
              setCurrentItem(record);
              setParentId(null);
              setSaveVisible(true);
            }}
          >
            编辑
          </a>
          <Divider type="vertical" />
          <a
            onClick={() => {
              setCurrentItem({});
              setSaveVisible(true);
              setParentId(record.id);
            }}
          >
            添加子机构
          </a>
          <Divider type="vertical" />
          <a
            onClick={() => {
              setCurrentItem(record);
              setAutzVisible(true);
            }}
          >
            权限分配
          </a>
          <Divider type="vertical" />
          <a
            onClick={() => {
              setCurrentItem(record);
              setUserVisible(true);
            }}
          >
            绑定用户
          </a>
          <Divider type="vertical" />
          <Popconfirm
            title="确认删除此机构吗?"
            onConfirm={() => {
              handleDelete(record);
            }}
          >
            <a>删除</a>
          </Popconfirm>
        </Fragment>
      ),
    },
  ];
  return (
    <PageHeaderWrapper title="机构管理">
      <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={() => {
                setParentId(null);
                setCurrentItem({});
                setSaveVisible(true);
              }}
            >
              新建
            </Button>
          </div>
          <div className={styles.StandardTable}>
            <Table
              loading={props.loading}
              dataSource={result}
              columns={columns}
              rowKey="id"
              onChange={onTableChange}
              pagination={false}
              // 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>
      {saveVisible && (
        <Save
          parentId={parentId}
          save={(item: any) => saveOrUpdate(item)}
          data={currentItem}
          close={() => {
            setSaveVisible(false);
            setCurrentItem({});
          }}
        />
      )}
      {autzVisible && (
        <Authorization
          close={() => {
            setAutzVisible(false);
            setCurrentItem({});
          }}
          target={currentItem}
          targetType="org"
        />
      )}
      {userVisible && (
        <BindUser
          data={currentItem}
          close={() => {
            setUserVisible(false);
          }}
        />
      )}
    </PageHeaderWrapper>
  );
}
Example #18
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 #19
Source File: index.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
TenantAlarm: React.FC<Props> = (props) => {

  const initState: State = {
    data: [],
    saveAlarmData: {},
    searchParam: {
      pageSize: 10, sorts: {
        order: "descend",
        field: "alarmTime"
      }
    },
    alarmLogData: {},
    alarmDataList: [],
  };

  const [spinning, setSpinning] = useState(true);

  const [searchParam, setSearchParam] = useState(initState.searchParam);
  const [alarmLogData, setAlarmLogData] = useState(initState.alarmLogData);

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

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

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

  const alarmLogColumns: ColumnProps<AlarmLog>[] = [
    {
      title: '设备ID',
      dataIndex: 'deviceId',
    },
    {
      title: '设备名称',
      dataIndex: 'deviceName',
    },
    {
      title: '告警名称',
      dataIndex: 'alarmName',
    },
    {
      title: '告警时间',
      dataIndex: 'alarmTime',
      width: '180px',
      render: (text: any) => text ? moment(text).format('YYYY-MM-DD HH:mm:ss') : '/',
      sorter: true,
      defaultSortOrder: 'descend'
    },
    {
      title: '处理状态',
      dataIndex: 'state',
      align: 'center',
      width: '100px',
      render: text => text === 'solve' ? <Tag color="#87d068">已处理</Tag> : <Tag color="#f50">未处理</Tag>,
    },
  ];

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

  return (
    <Spin spinning={spinning}>
      <Card bordered={false}>
        <div className={styles.tableList}>
          <div className={styles.tableListForm}>
            <Search
              search={(params: any) => {
                setSpinning(true);
                handleSearch({terms: params, pageSize: 10, sorts: searchParam.sorts});
              }}
            />
          </div>
          <div className={styles.StandardTable} style={{marginTop: 10}}>
            <Table
              size='middle'
              dataSource={(alarmLogData || {}).data}
              columns={alarmLogColumns}
              rowKey='id'
              onChange={onTableChange}
              pagination={{
                current: alarmLogData.pageIndex + 1,
                total: alarmLogData.total,
                pageSize: alarmLogData.pageSize,
              }}
            />
          </div>
        </div>
      </Card>
    </Spin>
  );
}
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>
  );
}
Example #21
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 #22
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 #23
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 #24
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 #25
Source File: index.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
Alarm: React.FC<Props> = props => {
  const {
    form: { getFieldDecorator },
    form,
  } = props;

  const initState: State = {
    data: [],
    saveAlarmData: {},
    searchParam: {
      pageSize: 10,
      sorts: {
        order: 'descend',
        field: 'alarmTime',
      },
    },
    alarmLogData: {},
    alarmDataList: [],
  };

  const [data, setData] = useState(initState.data);
  const [spinning, setSpinning] = useState(true);
  const [saveVisible, setSaveVisible] = useState(false);
  const [solveVisible, setSolveVisible] = useState(false);
  const [saveAlarmData, setSaveAlarmData] = useState(initState.saveAlarmData);
  const [alarmActiveKey, setAlarmActiveKey] = useState('');
  const [alarmLogId, setAlarmLogId] = useState<any>(null);
  const [solveAlarmLogId, setSolveAlarmLogId] = useState();
  const [searchParam, setSearchParam] = useState(initState.searchParam);
  const [alarmLogData, setAlarmLogData] = useState(initState.alarmLogData);
  const [alarmDataList, setAlarmDataList] = useState(initState.alarmDataList);

  const statusMap = new Map();
  statusMap.set('运行中', 'success');
  statusMap.set('已停止', 'error');

  const getProductAlarms = () => {
    alarmDataList.splice(0, alarmDataList.length);
    apis.deviceAlarm
      .getProductAlarms(props.target, props.targetId)
      .then((response: any) => {
        if (response.status === 200) {
          setData(response.result);
          response.result.map((item: any) => {
            alarmDataList.push(item);
          });
          setAlarmDataList([...alarmDataList]);
        }
        setSpinning(false);
      })
      .catch(() => {});

    if (props.target === 'device') {
      apis.deviceAlarm
        .getProductAlarms('product', props.productId)
        .then((response: any) => {
          if (response.status === 200) {
            response.result.map((item: any) => {
              alarmDataList.push(item);
            });
            setAlarmDataList([...alarmDataList]);
          }
        })
        .catch(() => {});
    }
  };

  useEffect(() => {
    setAlarmActiveKey('info');
    getProductAlarms();
  }, []);

  const submitData = (data: any) => {
    apis.deviceAlarm
      .saveProductAlarms(props.target, props.targetId, data)
      .then((response: any) => {
        if (response.status === 200) {
          message.success('保存成功');
          setSaveVisible(false);
          getProductAlarms();
        }
        setSpinning(false);
      })
      .catch(() => {});
  };

  const _start = (item: alarm) => {
    apis.deviceAlarm
      ._start(item.id)
      .then((response: any) => {
        if (response.status === 200) {
          message.success('启动成功');
          getProductAlarms();
        } else {
          setSpinning(false);
        }
      })
      .catch();
  };

  const _stop = (item: any) => {
    apis.deviceAlarm
      ._stop(item.id)
      .then((response: any) => {
        if (response.status === 200) {
          message.success('停止成功');
          getProductAlarms();
        } else {
          setSpinning(false);
        }
      })
      .catch();
  };

  const deleteAlarm = (id: string) => {
    apis.deviceAlarm
      .remove(id)
      .then((response: any) => {
        if (response.status === 200) {
          getProductAlarms();
        } else {
          setSpinning(false);
        }
      })
      .catch(() => {});
  };

  const columns: ColumnProps<alarm>[] = [
    {
      title: '告警名称',
      dataIndex: 'name',
    },
    {
      title: '创建时间',
      dataIndex: 'createTime',
      render: (text: any) => (text ? moment(text).format('YYYY-MM-DD HH:mm:ss') : '/'),
    },
    {
      title: '运行状态',
      dataIndex: 'state',
      render: record =>
        record ? <Badge status={statusMap.get(record.text)} text={record.text} /> : '',
    },
    {
      title: '操作',
      width: '250px',
      align: 'center',
      render: (record: any) => (
        <Fragment>
          <a
            onClick={() => {
              setSaveAlarmData(record);
              setSaveVisible(true);
            }}
          >
            编辑
          </a>
          <Divider type="vertical" />
          <a
            onClick={() => {
              setAlarmLogId(record.id);
              setAlarmActiveKey('logList');
            }}
          >
            告警日志
          </a>
          <Divider type="vertical" />
          {record.state?.value === 'stopped' ? (
            <span>
              <Popconfirm
                title="确认启动此告警?"
                onConfirm={() => {
                  setSpinning(true);
                  _start(record);
                }}
              >
                <a>启动</a>
              </Popconfirm>
              <Divider type="vertical" />
              <Popconfirm
                title="确认删除此告警?"
                onConfirm={() => {
                  setSpinning(true);
                  deleteAlarm(record.id);
                }}
              >
                <a>删除</a>
              </Popconfirm>
            </span>
          ) : (
            <Popconfirm
              title="确认停止此告警?"
              onConfirm={() => {
                setSpinning(true);
                _stop(record);
              }}
            >
              <a>停止</a>
            </Popconfirm>
          )}
        </Fragment>
      ),
    },
  ];

  const alarmLogColumns: ColumnProps<AlarmLog>[] = [
    {
      title: '设备ID',
      dataIndex: 'deviceId',
    },
    {
      title: '设备名称',
      dataIndex: 'deviceName',
    },
    {
      title: '告警名称',
      dataIndex: 'alarmName',
    },
    {
      title: '告警时间',
      dataIndex: 'alarmTime',
      width: '300px',
      render: (text: any) => (text ? moment(text).format('YYYY-MM-DD HH:mm:ss') : '/'),
      sorter: true,
      defaultSortOrder: 'descend',
    },
    {
      title: '处理状态',
      dataIndex: 'state',
      align: 'center',
      width: '100px',
      render: text =>
        text === 'solve' ? <Tag color="#87d068">已处理</Tag> : <Tag color="#f50">未处理</Tag>,
    },
    {
      title: '操作',
      width: '120px',
      align: 'center',
      render: (record: any) => (
        <Fragment>
          <a
            onClick={() => {
              let content: string;
              try {
                content = JSON.stringify(record.alarmData, null, 2);
              } catch (error) {
                content = record.alarmData;
              }
              Modal.confirm({
                width: '40VW',
                title: '告警数据',
                content: (
                  <pre>
                    {content}
                    {record.state === 'solve' && (
                      <>
                        <br />
                        <br />
                        <span style={{ fontSize: 16 }}>处理结果:</span>
                        <br />
                        <p>{record.description}</p>
                      </>
                    )}
                  </pre>
                ),
                okText: '确定',
                cancelText: '关闭',
              });
            }}
          >
            详情
          </a>
          <Divider type="vertical" />
          {record.state !== 'solve' && (
            <a
              onClick={() => {
                setSolveAlarmLogId(record.id);
                setSolveVisible(true);
              }}
            >
              处理
            </a>
          )}
        </Fragment>
      ),
    },
  ];

  const alarmSolve = () => {
    form.validateFields((err, fileValue) => {
      if (err) return;

      apis.deviceAlarm
        .alarmLogSolve(solveAlarmLogId || '', fileValue.description)
        .then((response: any) => {
          if (response.status === 200) {
            message.success('保存成功');
            setSolveAlarmLogId(undefined);
            setSolveVisible(false);
            handleSearch(searchParam);
          }
        })
        .catch(() => {});
    });
  };

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

  const onAlarmProduct = (value: string) => {
    let { terms } = searchParam;
    if (terms) {
      terms.alarmId = value;
    } else {
      terms = {
        alarmId: value,
      };
    }
    handleSearch({
      pageIndex: searchParam.pageIndex,
      pageSize: searchParam.pageSize,
      terms,
      sorts: searchParam.sorter || {
        order: 'descend',
        field: 'alarmTime',
      },
    });
  };

  useEffect(() => {
    if (alarmActiveKey === 'logList') {
      if (props.target === 'device') {
        searchParam.terms = {
          deviceId: props.targetId,
        };
        if (alarmLogId != '' && alarmLogId != null && alarmLogId) {
          searchParam.terms.alarmId = alarmLogId;
        }
      } else {
        searchParam.terms = {
          productId: props.targetId,
        };
        if (alarmLogId != '' && alarmLogId != null && alarmLogId) {
          searchParam.terms.alarmId = alarmLogId;
        }
      }
      handleSearch(searchParam);
    }
  }, [alarmActiveKey]);

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

  return (
    <Spin tip="加载中..." spinning={spinning}>
      <Card>
        <Tabs
          activeKey={alarmActiveKey}
          onTabClick={(key: any) => {
            setAlarmLogId(undefined);
            setAlarmActiveKey(key);
          }}
        >
          <Tabs.TabPane tab="告警设置" key="info">
            <Card
              title={
                <Button
                  icon="plus"
                  type="primary"
                  onClick={() => {
                    setSaveAlarmData({});
                    setSaveVisible(true);
                  }}
                >
                  新增告警
                </Button>
              }
              bordered={false}
            >
              <Table rowKey="id" columns={columns} dataSource={data} pagination={false} />
            </Card>
          </Tabs.TabPane>
          <Tabs.TabPane tab="告警记录" key="logList">
            <div>
              <Select
                placeholder="选择告警设置"
                allowClear
                style={{ width: 300 }}
                value={alarmLogId}
                onChange={(value: string) => {
                  onAlarmProduct(value);
                  setAlarmLogId(value);
                }}
              >
                {alarmDataList.length > 0 &&
                  alarmDataList.map(item => (
                    <Select.Option key={item.id}>{item.name}</Select.Option>
                  ))}
              </Select>
            </div>
            <div className={styles.StandardTable} style={{ marginTop: 10 }}>
              <Table
                dataSource={alarmLogData.data}
                columns={alarmLogColumns}
                rowKey="id"
                onChange={onTableChange}
                pagination={{
                  current: alarmLogData.pageIndex + 1,
                  total: alarmLogData.total,
                  pageSize: alarmLogData.pageSize,
                  showQuickJumper: true,
                  showSizeChanger: true,
                  pageSizeOptions: ['10', '20', '50', '100'],
                  showTotal: (total: number) =>
                    `共 ${total} 条记录 第  ${alarmLogData.pageIndex + 1}/${Math.ceil(
                      alarmLogData.total / alarmLogData.pageSize,
                    )}页`,
                }}
              />
            </div>
          </Tabs.TabPane>
        </Tabs>
      </Card>

      {saveVisible && (
        <Save
          close={() => {
            setSaveAlarmData({});
            setSaveVisible(false);
            getProductAlarms();
          }}
          save={(data: any) => {
            setSpinning(true);
            submitData(data);
          }}
          data={saveAlarmData}
          targetId={props.targetId}
          target={props.target}
          metaData={props.metaData}
          name={props.name}
          productName={props.productName}
          productId={props.productId}
        />
      )}

      {solveVisible && (
        <Modal
          title="告警处理结果"
          visible
          okText="确定"
          cancelText="取消"
          width="700px"
          onOk={() => {
            alarmSolve();
          }}
          onCancel={() => {
            setSolveVisible(false);
            setSolveAlarmLogId(undefined);
          }}
        >
          <Form labelCol={{ span: 3 }} wrapperCol={{ span: 21 }} key="solve_form">
            <Form.Item key="description" label="处理结果">
              {getFieldDecorator('description', {
                rules: [
                  { required: true, message: '请输入处理结果' },
                  { max: 2000, message: '处理结果不超过2000个字符' },
                ],
              })(<Input.TextArea rows={8} placeholder="请输入处理结果" />)}
            </Form.Item>
          </Form>
        </Modal>
      )}
    </Spin>
  );
}
Example #26
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 #27
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 #28
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 #29
Source File: index.tsx    From jetlinks-ui-antd with MIT License 4 votes vote down vote up
Firmware: React.FC<Props> = props => {
  const initState: State = {
    searchParam: {
      pageSize: 10,
      sorts: {
        order: 'descend',
        field: 'id',
      },
    },
    saveVisible: false,
    firmwareData: {},
    saveFirmwareData: {},
  };

  const [productList, setProductList] = useState([]);
  const [searchParam, setSearchParam] = useState(initState.searchParam);
  const [saveVisible, setSaveVisible] = useState(initState.saveVisible);
  const [firmwareData, setFirmwareData] = useState(initState.firmwareData);
  const [saveFirmwareData, setSaveFirmwareData] = useState(initState.saveFirmwareData);
  const [spinning, setSpinning] = useState(true);

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

  useEffect(() => {
    apis.deviceProdcut
      .queryNoPagin({
        paging: false
      })
      .then(response => {
        setProductList(response.result);
      })
      .catch(() => {});
    handleSearch(searchParam);
  }, []);

  const handleDelete = (params: FirmwareData) => {
    apis.firmware
      .remove(params.id)
      .then((response: any) => {
        if (response.status === 200) {
          message.success('删除成功');
          handleSearch(searchParam);
        }
      })
      .catch(() => {});
  };

  const handleSave = (item: any) => {
    apis.firmware
      .saveOrUpdate(item)
      .then((response: any) => {
        if (response.status === 200) {
          message.success('保存成功');
          handleSearch(searchParam);
        }
      })
      .catch(() => {});
  };

  const columns: ColumnProps<FirmwareData>[] = [
    {
      title: '固件名称',
      dataIndex: 'name',
    },
    {
      title: '固件版本',
      dataIndex: 'version',
    },
    {
      title: '所属产品',
      dataIndex: 'productName',
    },
    {
      title: '签名方式',
      dataIndex: 'signMethod',
    },
    {
      title: '创建时间',
      dataIndex: 'createTime',
      width: '200px',
      align: 'center',
      render: (text: any) => moment(text).format('YYYY-MM-DD HH:mm:ss'),
      sorter: true,
      defaultSortOrder: 'descend',
    },
    {
      title: '操作',
      width: '300px',
      align: 'center',
      render: (record: FirmwareData) => (
        <Fragment>
          <a
            onClick={() => {
              router.push(`/device/firmware/save/${record.id}`);
            }}
          >
            查看
          </a>
          <Divider type="vertical" />
          <a
            onClick={() => {
              setSaveFirmwareData(record);
              setSaveVisible(true);
            }}
          >
            编辑
          </a>
          <Divider type="vertical" />
          <Popconfirm
            title="确定删除?"
            onConfirm={() => {
              handleDelete(record);
            }}
          >
            <a>删除</a>
          </Popconfirm>
        </Fragment>
      ),
    },
  ];

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

  return (
    <PageHeaderWrapper title="固件升级">
      <Spin spinning={spinning}>
        <Card bordered={false}>
          <div className={styles.tableList}>
            <div>
              <SearchForm
                search={(params: any) => {
                  setSpinning(true);
                  handleSearch({
                    terms: params,
                    pageSize: 10,
                    sorts: searchParam.sorts,
                  });
                }}
                formItems={[
                  {
                    label: '固件名称',
                    key: 'name$LIKE',
                    type: 'string',
                  },
                  {
                    label: '所属产品',
                    key: 'productId',
                    type: 'list',
                    props: {
                      data: productList,
                      mode: 'tags',
                    },
                  },
                ]}
              />
            </div>
            <div className={styles.tableListOperator}>
              <Button
                icon="plus"
                type="primary"
                onClick={() => {
                  setSaveFirmwareData({});
                  setSaveVisible(true);
                }}
              >
                新建
              </Button>
            </div>
            <div className={styles.StandardTable}>
              <Table
                loading={props.loading}
                dataSource={(firmwareData || {}).data}
                columns={columns}
                rowKey="id"
                onChange={onTableChange}
                pagination={{
                  current: firmwareData?.pageIndex + 1,
                  total: firmwareData?.total,
                  pageSize: firmwareData?.pageSize,
                  showQuickJumper: true,
                  showSizeChanger: true,
                  pageSizeOptions: ['10', '20', '50', '100'],
                  showTotal: (total: number) =>
                    `共 ${total} 条记录 第  ${firmwareData?.pageIndex + 1}/${Math.ceil(
                      firmwareData?.total / firmwareData?.pageSize,
                    )}页`,
                }}
              />
            </div>
          </div>
        </Card>
      </Spin>
      {saveVisible && (
        <Save
          data={saveFirmwareData}
          close={() => {
            setSaveVisible(false);
            setSpinning(true);
            handleSearch(searchParam);
          }}
          save={(item: any) => {
            setSaveVisible(false);
            setSpinning(true);
            handleSave(item);
          }}
        />
      )}
    </PageHeaderWrapper>
  );
}