Browse Source

(*)网关状态指标; 网关操作等; 解决冲突

master
wuqun 2 years ago
parent
commit
4921b85d0d
  1. BIN
      code/web/client/assets/images/background/logo.png
  2. BIN
      code/web/client/assets/videos/administer_banner.mp4
  3. BIN
      code/web/client/assets/videos/gateway_banner.mp4
  4. 2
      code/web/client/src/index.jsx
  5. 12
      code/web/client/src/layout/components/header/index.jsx
  6. 2
      code/web/client/src/layout/components/sider/index.jsx
  7. 4
      code/web/client/src/sections/auth/containers/login.jsx
  8. 40
      code/web/client/src/sections/edition/actions/index.js
  9. 278
      code/web/client/src/sections/edition/containers/administer.jsx
  10. 59
      code/web/client/src/sections/edition/containers/gateway.jsx
  11. 5
      code/web/client/src/utils/webapi.js

BIN
code/web/client/assets/images/background/logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

BIN
code/web/client/assets/videos/administer_banner.mp4

Binary file not shown.

BIN
code/web/client/assets/videos/gateway_banner.mp4

Binary file not shown.

2
code/web/client/src/index.jsx

@ -9,4 +9,4 @@ import microApp from '@micro-zoe/micro-app'
microApp.start() microApp.start()
render((<App projectName="飞尚物联" />), document.getElementById('IotAuthApp')); render((<App projectName="边缘网关" />), document.getElementById('IotAuthApp'));

12
code/web/client/src/layout/components/header/index.jsx

@ -16,7 +16,9 @@ const Header = (props) => {
// if (socket) { // if (socket) {
// socket.disconnect(); // socket.disconnect();
// } // }
history.push(`/signin`); history.push(`/signin`)
localStorage.setItem('fs_iot_auth_selected_sider', JSON.stringify(['gateway']))
localStorage.setItem('fs_iot_auth_open_sider', JSON.stringify(['edgeGateway']))
} }
}} }}
style={{ style={{
@ -60,10 +62,16 @@ const Header = (props) => {
left: -10, left: -10,
}} }}
/> />
<Avatar size="small" color="light-blue" style={{ margin: 4 }}> <Avatar size="small" color="light-blue" style={{ margin: 4 }}>
<img src="/assets/images/avatar/6.png" /> <img src="/assets/images/avatar/6.png" />
</Avatar> </Avatar>
<div style={{
display: "inline-block", position: "relative",
top: 4,
left: 4,
}}>
{user && user.userName}
</div>
</div> </div>
} }
> >

2
code/web/client/src/layout/components/sider/index.jsx

@ -14,7 +14,6 @@ const Sider = props => {
useEffect(() => { useEffect(() => {
const { sections, dispatch, user } = props; const { sections, dispatch, user } = props;
let nextItems = [] let nextItems = []
console.log(sections);
for (let c of sections) { for (let c of sections) {
if (typeof c.getNavItem == 'function') { if (typeof c.getNavItem == 'function') {
let item = c.getNavItem(user, dispatch); let item = c.getNavItem(user, dispatch);
@ -23,7 +22,6 @@ const Sider = props => {
} }
} }
} }
console.log(nextItems);
setItems(nextItems) setItems(nextItems)
const lastSelectedKeys = localStorage.getItem('fs_iot_auth_selected_sider') const lastSelectedKeys = localStorage.getItem('fs_iot_auth_selected_sider')

4
code/web/client/src/sections/auth/containers/login.jsx

@ -21,8 +21,8 @@ const Login = props => {
useEffect(() => { useEffect(() => {
if (user && user.authorized) { if (user && user.authorized) {
dispatch(push('/edgeGateway/gateway')); dispatch(push('/edgeGateway/gateway'));
// localStorage.setItem('fs_iot_auth_selected_sider', JSON.stringify([])) localStorage.setItem('fs_iot_auth_selected_sider', JSON.stringify(['gateway']))
// localStorage.setItem('fs_iot_auth_open_sider', JSON.stringify([])) localStorage.setItem('fs_iot_auth_open_sider', JSON.stringify(['edgeGateway']))
} }
}, [user]) }, [user])

40
code/web/client/src/sections/edition/actions/index.js

@ -36,6 +36,41 @@ export function ableGateway(id, data) {
}); });
} }
export function getVersions() {
return (dispatch) =>
basicAction({
type: "get",
dispatch: dispatch,
actionType: "GET_VERSIONS",
url: `${ApiTable.getVersions}`,
msg: { option: "查询网关版本信息" },
reducer: { name: "", params: { noClear: true } },
});
}
export function deleteVersion(id) {
return dispatch => basicAction({
type: 'delete',
dispatch: dispatch,
actionType: 'DELETE_VERSION',
url: ApiTable.deleteVersion.replace('{versionId}', id),
msg: { option: '删除网关版本' },
reducer: { name: '' }
});
}
export function postVersion(data) {
return (dispatch) =>
basicAction({
type: "post",
dispatch: dispatch,
data,
actionType: "POST_VERSION",
url: `${ApiTable.postVersion}`,
msg: { option: "新增网关版本" },
});
}
export function gatewaySsh(id) { export function gatewaySsh(id) {
return dispatch => basicAction({ return dispatch => basicAction({
type: 'post', type: 'post',
@ -76,5 +111,8 @@ export default {
ableGateway, ableGateway,
gatewaySsh, gatewaySsh,
rebootGateway, rebootGateway,
restartGateway restartGateway,
getVersions,
deleteVersion,
postVersion,
}; };

278
code/web/client/src/sections/edition/containers/administer.jsx

@ -2,24 +2,290 @@
import React, { useEffect, useRef } from 'react'; import React, { useEffect, useRef } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { push } from 'react-router-redux'; import { push } from 'react-router-redux';
import { Form, Button, Toast } from '@douyinfe/semi-ui'; import { Form, Button, Table, Pagination, Modal } from '@douyinfe/semi-ui';
import { IconLock, IconUser } from '@douyinfe/semi-icons'; import { IconLock, IconUser } from '@douyinfe/semi-icons';
import { useState } from 'react';
import moment from "moment";
const EditionManage = props => { const EditionManage = props => {
const { dispatch, user, error, actions, apiRoot, isRequesting } = props const { dispatch, user, error, actions, apiRoot, isRequesting } = props
const { edition } = actions
const [versionList, setVersionList] = useState([])
const [addVersion, setaddVersion] = useState(false)
const api = useRef()
useEffect(() => { useEffect(() => {
requestData()
}, [])
const requestData = () => {
dispatch(edition.getVersions()).then(res => {
console.log(res);
if (res.success) {
setVersionList(res.payload.data)
}
})
}
const columns = [
{
}, []) title: "序列号",
render: (_, record, index) => {
return index + 1;
},
}, {
title: "主版本号",
dataIndex: "major",
key: "major",
}, {
title: "次版本号",
dataIndex: "minor",
key: "minor",
}, {
title: "补丁版本号",
dataIndex: "patch",
key: "patch",
}, {
title: "构建号",
dataIndex: "build",
key: "build",
}, {
title: "类型",
dataIndex: "type",
key: "type",
}, {
title: "描述",
dataIndex: "desc",
key: "desc",
}, {
title: "基础镜像地址",
dataIndex: "imageBase",
key: "imageBase",
}, {
title: "镜像版本",
dataIndex: "imageVersion",
key: "imageVersion",
render: (_, r, index) => {
return <div style={{ width: 80 }}>{r.imageVersion}</div>
},
}, {
title: "创建时间",
dataIndex: "createdAt",
key: "createdAt",
render: (_, r, index) => {
return <div style={{ width: 130 }}>{r.createdAt}</div>
},
}, {
title: "操作",
dataIndex: "operation",
render: (_, r, index) => {
return <Button onClick={() => {
dispatch(edition.deleteVersion(r.id)).then(res => {
if (res.success) {
requestData()
}
})
}}>删除</Button>
},
},
]
return ( return (
<div style={{}}> <>
<div style={{ position: "" }}>
<video
id="cameraBanner"
autoPlay
loop
muted
style={{ width: "100%", objectFit: "cover", height: 171 }}
src="/assets/videos/administer_banner.mp4"
type="video/mp4"
/>
<div style={{ position: "absolute", top: 12 }}>
<div
style={{
fontSize: 22,
paddingTop: 15,
marginLeft: 21,
}}
>
版本管理 版本管理
</div> </div>
<div
style={{
fontSize: 14,
paddingTop: 18,
marginLeft: 20,
}}
>
对网关版本添加删除的管理页面
</div>
<div
style={{
fontSize: 14,
marginTop: 28,
marginLeft: 21,
width: 89,
height: 32,
lineHeight: 32 + "px",
textAlign: "center",
backgroundColor: "#D9EAFF",
color: "#1859C1",
cursor: "pointer",
}}
onClick={() => {
setaddVersion(true)
}}
>
添加版本
</div>
</div>
</div>
<div style={{
width: "100%",
background: "#FFFFFF",
borderRadius: 3,
padding: "8px 20px",
marginTop: 20,
}}>
<Table
columns={columns}
dataSource={versionList}
bordered={false}
empty="暂无数据"
style={{
padding: "0px 20px",
}}
pagination={false}
/>
{versionList.length > 0 ? <div
style={{
display: "flex",
justifyContent: "flex-end",
padding: "20px 20px",
}}
>
<span style={{ lineHeight: "30px" }}>
{versionList.length}个设备
</span>
<Pagination
total={versionList.length}
showSizeChanger
currentPage={1}
pageSizeOpts={[10, 20, 30, 40]}
onChange={(currentPage, pageSize) => {
// setQuery({ limit: pageSize, page: currentPage - 1 });
// page.current = currentPage - 1
}}
/>
</div> : ""}
</div>
<Modal
title='新增网关版本'
// okText={okText}
visible={addVersion}
onOk={() => {
api.current.validate().then(r => {
console.log(r);
for (let key in r) {
if (['major', 'minor', 'patch', 'build'].includes(key)) {
r[key] = Number(r[key])
}
}
dispatch(edition.postVersion({ ...r, createdAt: moment().format("YYYY-MM-DD HH:MM:SS") })).then(res => {
if (res.success) {
requestData()
setaddVersion(false)
}
})
})
}}
width={610}
onCancel={() => setaddVersion(false)}
>
<Form
getFormApi={(formApi) => (api.current = formApi)}
layout="horizontal"
labelAlign="right"
labelWidth="114px"
style={{ display: 'flex', flexDirection: 'column' }}
>
<Form.Input
field='major'
label='主版本号:'
labelPosition="left"
hideButtons={true}
placeholder='请输入主版本号'
style={{ width: 200, marginBottom: 10 }}
rules={[{ required: true, message: "请输入主版本号" }, { pattern: "^[0-9]+$", message: "只能输入数字" },]}
/>
<Form.Input
field='minor'
label='次版本号:'
labelPosition="left"
hideButtons={true}
placeholder='请输入次版本号'
style={{ width: 200, marginBottom: 10 }}
rules={[{ required: true, message: "请输入次版本号" }, { pattern: "^[0-9]+$", message: "只能输入数字" },]}
/>
<Form.Input
field='patch'
label='补丁版本号:'
labelPosition="left"
hideButtons={true}
placeholder='请输入补丁版本号'
style={{ width: 200, marginBottom: 10 }}
rules={[{ required: true, message: "请输入补丁版本号" }, { pattern: "^[0-9]+$", message: "只能输入数字" },]}
/>
<Form.Input
field='build' label='构建号:'
labelPosition="left"
hideButtons={true}
placeholder='请输入构建号'
style={{ width: 200, marginBottom: 10 }}
rules={[{ required: true, message: "请输入构建号" }, { pattern: "^[0-9]+$", message: "只能输入数字" },]}
/>
<Form.Select
field="type"
label='Type:'
labelPosition="left"
placeholder='请选择类型'
style={{ width: 200, marginBottom: 10 }}
rules={[{ required: true, message: "请选择类型" }]}
>
<Form.Select.Option value="beta">beta</Form.Select.Option>
<Form.Select.Option value="alpha">alpha</Form.Select.Option>
<Form.Select.Option value="release">release</Form.Select.Option>
<Form.Select.Option value="LTS">LTS</Form.Select.Option>
</Form.Select>
<Form.Input
field='imageBase'
label='基础镜像地址:'
labelPosition="left"
placeholder='请输入基础镜像地址'
style={{ width: 440, marginBottom: 10 }}
rules={[{ required: true, message: "请输入基础镜像地址" }]}
/>
<Form.Input
field='imageVersion'
label='镜像版本:'
labelPosition="left"
placeholder='请输入镜像版本'
style={{ width: 200, marginBottom: 10 }}
rules={[{ required: true, message: "请输入镜像版本" }]}
/>
<Form.TextArea
field='desc'
label='描述:'
labelPosition="left"
placeholder='请输入描述'
style={{ width: 440 }}
/>
</Form>
</Modal>
</>
); );
} }

59
code/web/client/src/sections/edition/containers/gateway.jsx

@ -158,7 +158,62 @@ const GatewayManage = props => {
} }
return ( return (
<div style={{}}> <>
<div>
<video
id="gatewayBanner"
autoPlay
loop
muted
style={{ width: "100%", objectFit: "cover", height: 171 }}
src="/assets/videos/gateway_banner.mp4"
type="video/mp4"
/>
<div style={{ position: "absolute", top: 12 }}>
<div
style={{
fontSize: 22,
paddingTop: 15,
marginLeft: 21,
}}
>
设备管理
</div>
<div
style={{
fontSize: 14,
paddingTop: 18,
marginLeft: 20,
}}
>
对NVR网络硬盘录像机设备节点的管理
</div>
<div
style={{
fontSize: 14,
marginTop: 28,
marginLeft: 21,
width: 89,
height: 32,
lineHeight: "32px",
textAlign: "center",
backgroundColor: "#D9EAFF",
color: "#1859C1",
cursor: "pointer",
}}
onClick={() => {
}}
>
新增设备
</div>
</div>
</div>
<div style={{ width: "100%",
background: "#FFFFFF",
borderRadius: 3,
padding: "8px 20px",
marginTop: 20,}}>
<Skeleton <Skeleton
loading={false} loading={false}
active={true} active={true}
@ -198,6 +253,8 @@ const GatewayManage = props => {
dataToModal={dataToModal} /> : '' dataToModal={dataToModal} /> : ''
} }
</div> </div>
</>
); );
} }

5
code/web/client/src/utils/webapi.js

@ -8,10 +8,13 @@ export const ApiTable = {
getGateways: 'v1/edges', getGateways: 'v1/edges',
ableGateway: 'v1/edge/{id}/enable', ableGateway: 'v1/edge/{id}/enable',
getGatewayStatus: 'v1/edge/{id}/metrics', getGatewayStatus: 'v1/edge/{id}/metrics',
gatewaySsh: 'v1/edge/{id}/ssh', gatewaySsh: 'v1/edge/{id}/ssh',
rebootGateway: 'v1/edge/{id}/reboot', rebootGateway: 'v1/edge/{id}/reboot',
restartGateway: 'v1/edge/{id}/restart', restartGateway: 'v1/edge/{id}/restart',
getVersions: 'v1/versions', //查询网关版本信息
deleteVersion: 'v1/version/{versionId}', //删除网关版本
postVersion: 'v1/version', //新增网关版本
}; };
export const RouteTable = { export const RouteTable = {

Loading…
Cancel
Save