diff --git a/code/web/client/src/components/index.js b/code/web/client/src/components/index.js index 2d3a832..2fd185a 100644 --- a/code/web/client/src/components/index.js +++ b/code/web/client/src/components/index.js @@ -1,6 +1,8 @@ 'use strict'; import Coming from './coming' +import { SkeletonScreen } from './skeletonScreen' export { - Coming + Coming, + SkeletonScreen }; diff --git a/code/web/client/src/components/skeletonScreen.jsx b/code/web/client/src/components/skeletonScreen.jsx new file mode 100644 index 0000000..dc6c2e9 --- /dev/null +++ b/code/web/client/src/components/skeletonScreen.jsx @@ -0,0 +1,18 @@ +import React, { useState, useEffect } from "react"; +import { Skeleton } from "@douyinfe/semi-ui"; + + +export function SkeletonScreen () { + return <> + + + + + + + + + + + +} diff --git a/code/web/client/src/sections/edition/actions/index.js b/code/web/client/src/sections/edition/actions/index.js index a71e70b..8fef2cf 100644 --- a/code/web/client/src/sections/edition/actions/index.js +++ b/code/web/client/src/sections/edition/actions/index.js @@ -1,19 +1,56 @@ 'use strict'; -import { ApiTable,basicAction } from "$utils"; +import { basicAction } from '@peace/utils' +import { ApiTable } from '$utils' -export function getVersions() { +export function getGateways (query = {}) { + return dispatch => basicAction({ + type: 'get', + dispatch: dispatch, + query: query, + actionType: 'GET_GATEWAY_LIST', + url: ApiTable.getGateways, + msg: { option: '查询网关列表' }, + reducer: { name: 'getGateways' } + }); +} + +export function getGatewayStatus (id) { + return dispatch => basicAction({ + type: 'get', + dispatch: dispatch, + actionType: 'GET_GATEWAY_STATUS', + url: ApiTable.getGatewayStatus.replace('{id}', id), + msg: { option: '查询网关状态指标' }, + reducer: { name: 'getGatewayStatus' } + }); +} +export function ableGateway (id, data) { + return dispatch => basicAction({ + type: 'put', + data: data, + dispatch: dispatch, + actionType: 'ABLE_GATEWAY', + url: ApiTable.ableGateway.replace('{id}', id), + msg: { option: '使能网关' }, + }); +} + +export function getVersions () { return (dispatch) => - basicAction({ - type: "get", - dispatch: dispatch, - actionType: "GET_CAMREA", - url: `${ApiTable.getVersions}`, - msg: { option: "查询网关版本信息" }, - reducer: { name: "", params: { noClear: true } }, - }); - } + basicAction({ + type: "get", + dispatch: dispatch, + actionType: "GET_CAMREA", + url: `${ApiTable.getVersions}`, + msg: { option: "查询网关版本信息" }, + reducer: { name: "", params: { noClear: true } }, + }); +} export default { getVersions, + getGateways, + getGatewayStatus, + ableGateway }; \ No newline at end of file diff --git a/code/web/client/src/sections/edition/containers/gateway.jsx b/code/web/client/src/sections/edition/containers/gateway.jsx index fc27e03..634152b 100644 --- a/code/web/client/src/sections/edition/containers/gateway.jsx +++ b/code/web/client/src/sections/edition/containers/gateway.jsx @@ -1,24 +1,159 @@ 'use strict'; -import React, { useEffect, useRef } from 'react'; +import React, { useEffect, useState, useRef } from 'react'; import { connect } from 'react-redux'; import { push } from 'react-router-redux'; -import { Form, Button, Toast, Table } from '@douyinfe/semi-ui'; -import { IconLock, IconUser } from '@douyinfe/semi-icons'; +import { Popconfirm, Button, Toast, Skeleton, Table, Tag } from '@douyinfe/semi-ui'; +import { IconChevronDown } from '@douyinfe/semi-icons'; +import { SkeletonScreen } from "$components"; +import GatewayStatusModal from './gatewayStatusModal' +import GatewayEditModal from './gatewayEditModal' const GatewayManage = props => { - const { dispatch, user, error, actions, apiRoot, isRequesting } = props - - + const { dispatch, user, error, actions } = props + const { edition } = actions; + const [query, setQuery] = useState({ limit: 10, page: 0 }); //页码信息 + const [tableData, setTableData] = useState([]); + const [limits, setLimits] = useState()//每页实际条数 + const [detailV, setDetailV] = useState(false) + const [editV, setEditV] = useState(false) + const [dataToModal, setDataToModal] = useState(null) useEffect(() => { + getTableData(query) + }, []) + const getTableData = (obj) => { + let { limit, page } = obj + let queryObj = { limit, offset: limit * page } + dispatch(edition.getGateways(queryObj)).then(res => {//查询网关列表 + if (res.success) { + setTableData(res.payload.data.data); + setLimits(res.payload.data.total); + } + }) + } + const ableDevice = (id, v) => { + let ableObj = { "enabled": v } + dispatch(edition.ableGateway(id, ableObj)).then(r => { + if (r.success) { + getTableData(query) + } + }) + } + const aStyle = { color: '#40a9ff', cursor: 'pointer' } + const columns = [ + { + title: "序列号", + dataIndex: "serialNo", + key: "serialNo", + }, { + title: "名称", + dataIndex: "name", + key: "name", + }, { + title: "在线状态", + dataIndex: "state", + key: "state", + render: (text, record) => { + return text ? 在线 : 离线 + } + }, { + title: "固件信息", + dataIndex: "hardwareName", + key: "hardwareName", + }, { + title: "软件信息", + dataIndex: "softwareVer", + key: "softwareVer", + render: (text, record) => {text || '-'} + }, { + title: "绑定结构物数", + dataIndex: "thingIds", + key: "thingIds", + render: (text, record) => {text.length} + }, { + title: "是否启用", + dataIndex: "enabled", + key: "enabled", + render: (text, record) => {text ? '是' : '否'} + }, { + title: "状态详情", + dataIndex: "detail", + key: "detail", + render: (text, record) => { + setDetailV(true) + setDataToModal(record) + }}>查看 + }, { + title: "操作", + dataIndex: "action", + key: "action", + render: (text, record) => { + return
+ { + ableDevice(record.id, !record.enabled) + }}> + {record.enabled ? '禁用' : '启用'} + - }, []) + { + setEditV(true) + setDataToModal(record) + }}>编辑 + { + + }}>删除 + { + }}>更多 +
+ } + } + ]; return (
- 网关设备列表 + + { + return {`共${Math.ceil(total / limits)}页,${total}项`} + }, + onChange: (page, pageSize) => { + setQuery({ limit: pageSize, page: page - 1 }); + getTableData({ limit: pageSize, page: page - 1 }); + } + }} + /> + + { + detailV ? setDetailV(false)} + dataToModal={dataToModal} /> : '' + } + { + editV ? setEditV(false)} + dataToModal={dataToModal} /> : '' + } ); } diff --git a/code/web/client/src/sections/edition/containers/gatewayEditModal.jsx b/code/web/client/src/sections/edition/containers/gatewayEditModal.jsx new file mode 100644 index 0000000..6bd0051 --- /dev/null +++ b/code/web/client/src/sections/edition/containers/gatewayEditModal.jsx @@ -0,0 +1,33 @@ +import React, { useEffect, useRef, useState } from 'react'; +import moment from 'moment'; +import { connect } from "react-redux"; +import { Select, Modal, Form, Button } from "@douyinfe/semi-ui"; + +const GatewayEditModal = (props) => { + const { dispatch, actions, user, onCancel, dataToModal } = props; + const { edition } = actions; + + //初始化 + useEffect(() => { + + }, []); + + return ( + 关闭]}> +
+
+ ) +} + +function mapStateToProps(state) { + const { auth, global } = state; + return { + user: auth.user, + error: auth.error, + actions: global.actions, + }; +} + +export default connect(mapStateToProps)(GatewayEditModal); \ No newline at end of file diff --git a/code/web/client/src/sections/edition/containers/gatewayStatusModal.jsx b/code/web/client/src/sections/edition/containers/gatewayStatusModal.jsx new file mode 100644 index 0000000..092ca95 --- /dev/null +++ b/code/web/client/src/sections/edition/containers/gatewayStatusModal.jsx @@ -0,0 +1,53 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { connect } from "react-redux"; +import { Select, Modal, Form, Button } from "@douyinfe/semi-ui"; + +const GatewayStatusModal = (props) => { + const { dispatch, actions, user, onCancel, dataToModal } = props; + const { edition } = actions; + const [listData, setListData] = useState(null); + //初始化 + useEffect(() => { + dispatch(edition.getGatewayStatus(dataToModal.id)).then(res => {//查询网关状态指标 + if (res.success) { + setListData(res.payload.data) + } + }) + }, []); + + const statusKeys = { + status: '状态', + streamIn: '流入', + streamOut: '流出', + memUsedPercent: '内存使用', + diskPercent: '磁盘使用', + timeDiff: '时间偏差(最新心跳 服务器时间-设备时间)', + uptime: '本次在线时常',//??? + sysVersion: '系统', + status: '软件信息',//??? + status: '配置版本',//??? + acqConfVersion: '采集参数版本',//??? + pluginVersion: '插件版本', + load1: 'Load1', + load5: 'Load5', + load15: 'Load15', + } + return ( + 关闭]}> +
+
+ ) +} + +function mapStateToProps(state) { + const { auth, global } = state; + return { + user: auth.user, + error: auth.error, + actions: global.actions, + }; +} + +export default connect(mapStateToProps)(GatewayStatusModal); \ No newline at end of file diff --git a/code/web/client/src/utils/webapi.js b/code/web/client/src/utils/webapi.js index 6fe1f64..bd72aa1 100644 --- a/code/web/client/src/utils/webapi.js +++ b/code/web/client/src/utils/webapi.js @@ -4,9 +4,12 @@ export const ApiTable = { login: 'v1/login', logout: 'v1/logout', - crossCheck: 'cross_token/check', + crossCheck: 'cross_token/check', + getGateways: 'v1/edges', + ableGateway: 'v1/edge/{id}/enable', + getGatewayStatus: 'v1/edge/{id}/metrics', - getVersions: 'v1/versions', //查询网关版本信息 + getVersions: 'v1/versions', //查询网关版本信息 }; export const RouteTable = {