Browse Source

插件

master
wenlele 2 years ago
parent
commit
bb3a4042ca
  1. 278
      code/web/client/src/sections/edition/actions/index.js
  2. 251
      code/web/client/src/sections/edition/components/plugInModel.jsx
  3. 3
      code/web/client/src/sections/edition/containers/index.js
  4. 283
      code/web/client/src/sections/edition/containers/plugIn.jsx
  5. 3
      code/web/client/src/sections/edition/nav-item.jsx
  6. 9
      code/web/client/src/sections/edition/routes.js
  7. 39
      code/web/client/src/utils/webapi.js
  8. 1
      code/web/config.js
  9. 2
      code/web/package.json

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

@ -3,155 +3,191 @@
import { basicAction } from '@peace/utils' import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils' import { ApiTable } from '$utils'
export function getGateways(query = {}) { export function getGateways (query = {}) {
return dispatch => basicAction({ return dispatch => basicAction({
type: 'get', type: 'get',
dispatch: dispatch, dispatch: dispatch,
query: query, query: query,
actionType: 'GET_GATEWAY_LIST', actionType: 'GET_GATEWAY_LIST',
url: ApiTable.getGateways, url: ApiTable.getGateways,
msg: { option: '查询网关列表' }, msg: { option: '查询网关列表' },
reducer: { name: 'getGateways' } reducer: { name: 'getGateways' }
}); });
} }
export function getGatewayStatus(id) { export function getGatewayStatus (id) {
return dispatch => basicAction({ return dispatch => basicAction({
type: 'get', type: 'get',
dispatch: dispatch, dispatch: dispatch,
actionType: 'GET_GATEWAY_STATUS', actionType: 'GET_GATEWAY_STATUS',
url: ApiTable.getGatewayStatus.replace('{id}', id), url: ApiTable.getGatewayStatus.replace('{id}', id),
msg: { option: '查询网关状态指标' }, msg: { option: '查询网关状态指标' },
reducer: { name: 'getGatewayStatus' } reducer: { name: 'getGatewayStatus' }
}); });
} }
export function ableGateway(id, data) { export function ableGateway (id, data) {
return dispatch => basicAction({ return dispatch => basicAction({
type: 'put', type: 'put',
data: data, data: data,
dispatch: dispatch, dispatch: dispatch,
actionType: 'ABLE_GATEWAY', actionType: 'ABLE_GATEWAY',
url: ApiTable.ableGateway.replace('{id}', id), url: ApiTable.ableGateway.replace('{id}', id),
msg: { option: '使能网关' }, msg: { option: '使能网关' },
}); });
} }
export function getVersions() { export function getVersions () {
return (dispatch) => return (dispatch) =>
basicAction({ basicAction({
type: "get", type: "get",
dispatch: dispatch, dispatch: dispatch,
actionType: "GET_VERSIONS", actionType: "GET_VERSIONS",
url: `${ApiTable.getVersions}`, url: `${ApiTable.getVersions}`,
msg: { option: "查询网关版本信息" }, msg: { option: "查询网关版本信息" },
reducer: { name: "", params: { noClear: true } }, reducer: { name: "", params: { noClear: true } },
}); });
} }
export function deleteVersion(id) { export function deleteVersion (id) {
return dispatch => basicAction({ return dispatch => basicAction({
type: 'delete', type: 'delete',
dispatch: dispatch, dispatch: dispatch,
actionType: 'DELETE_VERSION', actionType: 'DELETE_VERSION',
url: ApiTable.deleteVersion.replace('{versionId}', id), url: ApiTable.deleteVersion.replace('{versionId}', id),
msg: { option: '删除网关版本' }, msg: { option: '删除网关版本' },
reducer: { name: '' } reducer: { name: '' }
}); });
} }
export function postVersion(data) { export function postVersion (data) {
return (dispatch) => return (dispatch) =>
basicAction({ basicAction({
type: "post", type: "post",
dispatch: dispatch, dispatch: dispatch,
data, data,
actionType: "POST_VERSION", actionType: "POST_VERSION",
url: `${ApiTable.postVersion}`, url: `${ApiTable.postVersion}`,
msg: { option: "新增网关版本" }, msg: { option: "新增网关版本" },
}); });
} }
export function delGateway(id) { export function delGateway (id) {
return dispatch => basicAction({ return dispatch => basicAction({
type: 'delete', type: 'delete',
dispatch: dispatch, dispatch: dispatch,
actionType: 'DELETE_GATEWAY', actionType: 'DELETE_GATEWAY',
url: ApiTable.delGateway.replace('{id}', id), url: ApiTable.delGateway.replace('{id}', id),
msg: { option: '删除网关' }, msg: { option: '删除网关' },
reducer: { name: '' } reducer: { name: '' }
}); });
} }
export function gatewaySsh(id) { export function gatewaySsh (id) {
return dispatch => basicAction({ return dispatch => basicAction({
type: 'post', type: 'post',
data: null, data: null,
dispatch: dispatch, dispatch: dispatch,
actionType: 'GATEWAY_SSH', actionType: 'GATEWAY_SSH',
url: ApiTable.gatewaySsh.replace('{id}', id), url: ApiTable.gatewaySsh.replace('{id}', id),
msg: { option: '启动并获取远程SSH-web地址' }, msg: { option: '启动并获取远程SSH-web地址' },
}); });
} }
//重启网关reboot //重启网关reboot
export function rebootGateway(id) { export function rebootGateway (id) {
return dispatch => basicAction({ return dispatch => basicAction({
type: 'post', type: 'post',
data: null, data: null,
dispatch: dispatch, dispatch: dispatch,
actionType: 'REBOOT_GATEWAY', actionType: 'REBOOT_GATEWAY',
url: ApiTable.rebootGateway.replace('{id}', id), url: ApiTable.rebootGateway.replace('{id}', id),
msg: { option: '重启网关' }, msg: { option: '重启网关' },
}); });
} }
//重启网关服务restart //重启网关服务restart
export function restartGateway(id) { export function restartGateway (id) {
return dispatch => basicAction({ return dispatch => basicAction({
type: 'post', type: 'post',
data: null, data: null,
dispatch: dispatch, dispatch: dispatch,
actionType: 'RESTART_GATEWAY', actionType: 'RESTART_GATEWAY',
url: ApiTable.restartGateway.replace('{id}', id), url: ApiTable.restartGateway.replace('{id}', id),
msg: { option: '重启网关服务' }, msg: { option: '重启网关服务' },
}); });
} }
export function postedge(data) { export function postedge (data) {
return (dispatch) => return (dispatch) =>
basicAction({ basicAction({
type: "post", type: "post",
dispatch: dispatch, dispatch: dispatch,
data, data,
actionType: "POST_EDGE", actionType: "POST_EDGE",
url: `${ApiTable.postedge}`, url: `${ApiTable.postedge}`,
msg: { option: "新增网关" }, msg: { option: "新增网关" },
}); });
}
export function putedge (id, data) {
return dispatch => basicAction({
type: 'put',
data: data,
dispatch: dispatch,
actionType: 'PUT_EDGE',
url: ApiTable.putedge.replace('{edgeId}', id),
msg: { option: '修改网关' },
});
} }
export function putedge(id, data) { export function getPlugInList (id, query) {
return dispatch => basicAction({
type: 'get',
query,
dispatch: dispatch,
actionType: 'GET_PLUGINLIST',
url: ApiTable.getPlugInList.replace('{id}', id),
msg: { option: '获取网关插件列表' },
});
}
export function postAddPlugIn (id, query) {
return dispatch => basicAction({
type: 'post',
query,
dispatch: dispatch,
actionType: 'POST_ADD_PLUGIN',
url: ApiTable.postAddPlugIn.replace('{id}', id),
msg: { option: '获取网关插件列表' },
});
}
export function delPlugIn (edgeId,id) {
return dispatch => basicAction({ return dispatch => basicAction({
type: 'put', type: 'delete',
data: data, dispatch: dispatch,
dispatch: dispatch, actionType: 'DELETE_GATEWAY',
actionType: 'PUT_EDGE', url: ApiTable.delPlugIn.replace('{id}', id),
url: ApiTable.putedge.replace('{edgeId}', id), msg: { option: '删除网关' },
msg: { option: '修改网关' }, reducer: { name: '' }
}); });
} }
export default { export default {
getGateways, getGateways,
getGatewayStatus, getGatewayStatus,
ableGateway, ableGateway,
delGateway, delGateway,
gatewaySsh, gatewaySsh,
rebootGateway, rebootGateway,
restartGateway, restartGateway,
getVersions, getVersions,
deleteVersion, deleteVersion,
postVersion, postVersion,
postedge, postedge,
putedge, putedge,
getPlugInList,
postAddPlugIn,
}; };

251
code/web/client/src/sections/edition/components/plugInModel.jsx

@ -0,0 +1,251 @@
'use strict';
import React, { useEffect, useState, useRef } from 'react';
import { connect } from 'react-redux';
import { push } from 'react-router-redux';
import { Popconfirm, Button, Popover, Skeleton, Form, Tag, Modal, Collapse, Input } from '@douyinfe/semi-ui';
import { IconSearch, IconHelpCircle, IconAlertCircle, IconMinusCircle, IconPlusCircle, IconPlus, IconRefresh } from '@douyinfe/semi-icons';
import { SkeletonScreen } from "$components";
const AddModel = props => {
const { dispatch, user, error, actions, close, editionData, searchValue } = props
const { edition } = actions
const [query, setQuery] = useState({ limit: 10, page: 0 }); //
const [limits, setLimits] = useState()//
const [detailV, setDetailV] = useState(false)
const [property, setProperty] = useState([{ key: 'hb', value: 'ture' }])
const [attributeValue, setattributeValue] = useState({})
const [type, setType] = useState('groups') //
const [isEditor, setIsEditor] = useState(false)
const [appearType, setAppearType] = useState('mqtt')
const api = useRef()
useEffect(() => {
if(editionData){
}
}, [])
return (
<>
<Modal
title={editionData ? '编辑插件' : '新增插件'}
// okText={okText}
visible={true}
onOk={() => {
api.current.validate().then(r => {
console.log(r);
r.ctx_res = JSON.parse(r.ctx_res)
// delete r.type
if (dataToModal?.id) {
dispatch(edition.putedge(dataToModal?.id, r)).then(res => {
console.log(res)
if (res.success) {
close()
}
})
} else {
dispatch(edition.postAddPlugIn(searchValue, r)).then(res => {//
if (res.success) {
console.log(res);
}
})
}
})
}}
width={560}
onCancel={() => close()}
>
<Form
getFormApi={(formApi) => (api.current = formApi)}
layout="horizontal"
labelAlign="right"
labelWidth="104px"
allowEmpty={true}
style={{ display: 'flex', flexDirection: 'column' }}
onValueChange={(_, v) => {
console.log(v);
if (v?.type) {
setType(v.type)
}
if (v.ctx_type) {
setAppearType(v.ctx_type)
}
}}
>
<Form.Input
field='name'
label='名称:'
labelPosition="left"
placeholder='请输入名称'
style={{ width: 240, marginBottom: 12 }}
initValue={dataToModal?.name || ''}
rules={[{ required: true, message: "请输入设备名称" }]}
/>
<Form.Select
field="type"
label='类型:'
labelPosition="left"
placeholder='请选择类型'
style={{ width: 240, marginBottom: 12 }}
initValue={dataToModal?.softwareVer || type}
rules={[{ required: true, message: "请选择类型" }]}
>
{[{ name: '上报', value: 'groups' }, { name: '计算', value: 'antenna' }].map(v => <Form.Select.Option key={v.value} value={v.value}>{v.name}</Form.Select.Option>)}
</Form.Select>
<Form.TextArea
field='description'
label='描述:'
labelPosition="left"
placeholder=''
style={{ width: 300, marginBottom: 12 }}
initValue={dataToModal?.name || ''}
autosize
rows={1}
/>
<Form.Checkbox
field='enable'
label='是否启动:'
labelPosition="left"
style={{ marginBottom: 12 }}
initValue={dataToModal?.name || true}
/>
{type == 'groups' ?
<>
<Form.Select
field="ctx_type"
label='上报类型:'
labelPosition="left"
placeholder='请选择上报类型'
style={{ width: 240, marginBottom: 12 }}
initValue={'' || 'mqtt'}
rules={[{ required: true, message: "请选择上报类型" }]}
>
{[{ name: 'mqtt', value: 'mqtt' }, { name: 'http', value: 'http' }, { name: 'db', value: 'db' }].map(v => <Form.Select.Option key={v.value} value={v.value}>{v.name}</Form.Select.Option>)}
</Form.Select>
<Form.Select
field="ctx_res_lang"
label='脚本语言:'
labelPosition="left"
placeholder='请选择脚本语言'
style={{ width: 240, marginBottom: 12 }}
initValue={'' || 'Lua'}
rules={[{ required: true, message: "请选择脚本语言" }]}
>
{[{ name: 'Lua', value: 'Lua' },].map(v => <Form.Select.Option key={v.value} value={v.value}>{v.name}</Form.Select.Option>)}
</Form.Select>
<Form.Select
field="ctx_res_type"
label='脚本类型:'
labelPosition="left"
placeholder='请选择脚本类型'
style={{ width: 240, marginBottom: 12 }}
initValue={'' || 'INLINE'}
rules={[{ required: true, message: "请选择脚本类型" }]}
>
{[{ name: 'INLINE', value: 'INLINE' }].map(v => <Form.Select.Option key={v.value} value={v.value}>{v.name}</Form.Select.Option>)}
</Form.Select>
<div style={{ display: 'flex' }}>
<div style={{ width: 104, height: 44, padding: '6px 16px 6px 0', textIndent: 28, fontWeight: 600, color: 'var(--semi-color-text-0)', fontSize: 14 }}>参数:</div>
<div>
{appearType == 'mqtt' ?
<>
<Form.Input field='ctx_param_ur' label='URL(必填):' labelPosition="left"
placeholder='127.0.0.1:1883' style={{ width: 180, marginBottom: 12 }} initValue={dataToModal?.name || ''}
/>
<Form.Input field='ctx_param_clientid' label='ClientlD:' labelPosition="left" placeholder='请输入ClientlD'
style={{ width: 180, marginBottom: 12 }} initValue={dataToModal?.name || ''}
/>
<Form.Input field='ctx_param_username' label='用户名:' labelPosition="left" placeholder='请输入用户名'
style={{ width: 180, marginBottom: 12 }} initValue={dataToModal?.name || ''}
/>
<Form.Input field='ctx_param_password' label='密码:' labelPosition="left" placeholder='请输入密码'
style={{ width: 180, marginBottom: 12 }} initValue={dataToModal?.name || ''}
/>
<Form.Input field='ctx_param_topic' label='默认上报主题:' labelPosition="left" placeholder='请输入主题'
style={{ width: 180, marginBottom: 12 }} initValue={dataToModal?.name || ''}
/>
<Form.Input field='ctx_param_qos' label='默认上报QoS:' labelPosition="left" placeholder='0'
style={{ width: 180, marginBottom: 12 }} initValue={dataToModal?.name || ''}
/>
</>
: appearType == 'http' ?
<>
<Form.Input field='ctx_param_url' label='请求地址:' labelPosition="left"
style={{ width: 180, marginBottom: 12 }} initValue={dataToModal?.name || ''}
/>
<Form.Input field='ctx_param_method' label='请求方法:' labelPosition="left" placeholder='post'
style={{ width: 180, marginBottom: 12 }} initValue={dataToModal?.name || ''}
/>
<Form.Input field='ctx_param_headers' label='默认请求头:' labelPosition="left"
style={{ width: 180, marginBottom: 12 }} initValue={dataToModal?.name || JSON.stringify({})}
/>
</>
: <>
<Form.Input field='ctx_param_type' label='数据库类型:' labelPosition="left"
style={{ width: 180, marginBottom: 12 }} initValue={dataToModal?.name || JSON.stringify({})}
/>
<Form.Input field='ctx_param_conn' label='连接字符串:' labelPosition="left"
style={{ width: 180, marginBottom: 12 }} initValue={dataToModal?.name || JSON.stringify({})}
/>
</>
}
</div>
</div>
<Form.TextArea
field='ctx_res'
label={<>脚本<Button theme='borderless' type='secondary' style={{ width: 46, height: 32 }} onClick={() => setIsEditor(!isEditor)}>{isEditor ? '完成' : '编辑'}</Button></>}
labelPosition="left"
style={{ width: 300, marginBottom: 12 }}
initValue={dataToModal?.name || JSON.stringify([])}
autosize
disabled={!isEditor}
/>
<Form.Input
field='ctx_cron'
label='定时任务:'
labelPosition="left"
style={{ width: 180, marginBottom: 12 }}
initValue={dataToModal?.name || ''}
/>
</>
: <>
<Button style={{ width: 182, marginBottom: 10, marginLeft: 104, color: '#0000009c', border: '1px solid #00000040', }}>获取平台计算和分组配置</Button>
<Form.TextArea
field='ctx_group_content'
label='计算配置:'
labelPosition="left"
placeholder=''
style={{ width: 300, marginBottom: 12 }}
initValue={dataToModal?.name || JSON.stringify([])}
autosize
rules={[{ required: true, message: "请输入计算配置" }]}
/>
</>
}
</Form>
</Modal>
</>
);
}
function mapStateToProps (state) {
const { auth, global } = state;
return {
user: auth.user,
error: auth.error,
actions: global.actions,
apiRoot: global.apiRoot,
isRequesting: auth.isRequesting
}
}
export default connect(mapStateToProps)(AddModel);

3
code/web/client/src/sections/edition/containers/index.js

@ -1,5 +1,6 @@
'use strict'; 'use strict';
import EditionManage from './administer'; import EditionManage from './administer';
import GatewayManage from './gateway'; import GatewayManage from './gateway';
import PlugIn from './plugIn.jsx';
export { EditionManage, GatewayManage }; export { EditionManage, GatewayManage,PlugIn };

283
code/web/client/src/sections/edition/containers/plugIn.jsx

@ -0,0 +1,283 @@
'use strict';
import React, { useEffect, useState, useRef } from 'react';
import { connect } from 'react-redux';
import { push } from 'react-router-redux';
import { Popconfirm, Button, Popover, Skeleton, Table, Tag, Input, Pagination, Select } from '@douyinfe/semi-ui';
import { IconSearch } from '@douyinfe/semi-icons';
import { SkeletonScreen } from "$components";
import GatewayStatusModal from './gatewayStatusModal'
import PlugInModel from '../components/plugInModel'
import { UnControlled as CodeMirror } from 'react-codemirror2'
import moment from 'moment'
const PlugIn = 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(0)//
const [detailV, setDetailV] = useState(false)
const [dataToModal, setDataToModal] = useState(null)
const [addModel, setAddModel] = useState(false)
const [editionData, setEditionData] = useState()
const [searchValue, setSearchValue] = useState('') //
const [selectData, setSelectData] = useState([]) //
const [instance, setInstance] = useState(null);
const [codeData, setCodeData] = useState('');
useEffect(() => {
dispatch(edition.getGateways({})).then(res => {//
if (res.success) {
let data = res.payload.data?.data?.map(r => ({ name: r.serialNo, value: r.id }))
setSelectData(data)
setSearchValue(data[0]?.value)
getTableData({ id: data[0]?.value, limit: 10, page: 0 })
}
})
}, [])
const getTableData = (obj) => {
let { id, limit, page } = obj
dispatch(edition.getPlugInList(id, { limit, offset: limit * page })).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: "插件ID",
dataIndex: "ID",
key: "ID",
}, {
title: "类型",
dataIndex: "Type",
key: "Type",
render: (text, r) => {
let type = { group: '分组计算', antenna: '上报' }
return r.Type ? type[r.Type] : ""
}
}, {
title: " 插件名称",
dataIndex: "Name",
key: "Name",
}, {
title: "插件描述",
dataIndex: "Desctription",
key: "Desctription",
render: (text, r) => {
return r.Desctription || '--'
}
}, {
title: "是否启用",
dataIndex: "Enable",
key: "Enable",
render: (text, r) => {
return r.Enable == true ? '启用' : '禁用'
}
}, {
title: "操作",
dataIndex: "action",
key: "action",
render: (text, r) => {
return <div style={{ width: 90 }}>
<a style={{ ...aStyle, marginLeft: 15, marginRight: 15 }} onClick={() => {
setAddModel(true)
setEditionData(r.ID)
}}>编辑</a>
<Popconfirm
title="提示"
position='leftBottom'
content={<div style={{ width: 150 }}>确认删除该网关插件吗</div>}
onConfirm={() => {
dispatch(edition.getPlugInList(id, { limit, offset: limit * page })).then(res => {
if (res.success) {
setTableData(res.payload.data.data);
setLimits(res.payload.data.total);
}
})
}}>
<a style={aStyle}>删除</a>
</Popconfirm>
</div>
}
}
];
return (
<>
<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,
}}
>
对单个网关设备进行插件管理根据所选序列号展示对应网关的插件
</div>
<div
style={{
fontSize: 14,
marginTop: 28,
marginLeft: 21,
width: 89,
height: 32,
lineHeight: "32px",
textAlign: "center",
backgroundColor: "#D9EAFF",
color: "#1859C1",
cursor: "pointer",
}}
onClick={() => {
setAddModel(true)
}}
>
新增插件
</div>
</div>
</div>
<div style={{
width: "100%",
background: "#FFFFFF",
borderRadius: 3,
padding: "8px 20px",
marginTop: 20,
}}>
<div style={{ display: 'flex', alignItems: 'center', marginBottom: 16 }}>
序列号
<Select
maxHeight={240}
// filter={true}
// defaultValue={selectData[0]?.value}
value={searchValue}
placeholder="请选择网关序列号"
dropdownMatchSelectWidth={true}
style={{ width: 186 }}
onSelect={(value, option) => {
console.log(value, option);
setSearchValue(value)
getTableData({ id: value, limit: 1, page: 0 })
}}
>
{selectData?.map(r => <Select.Option value={r.value} key={r.value}>{r.name}</Select.Option>)}
</Select>
<Button
style={{ marginLeft: 20, width: 60, height: 32, borderRadius: 3, backgroundColor: '#0b57dcb3' }}
theme="solid"
type="primary"
onClick={() => {
getTableData({ limit: 10, page: 0, name: searchValue })
setQuery({ limit: 10, page: 0 })
}}>查询</Button>
</div>
<Table
columns={columns}
dataSource={tableData}
bordered={false}
empty="暂无插件"
style={{
padding: "0px 20px",
}}
pagination={false}
/>
{limits > 0 ? <div
style={{
display: "flex",
justifyContent: "flex-end",
padding: "20px 20px",
}}
>
<span style={{ lineHeight: "30px" }}>
{limits}个设备
</span>
<Pagination
total={limits}
showSizeChanger
currentPage={query.page + 1}
pageSizeOpts={[10, 20, 30, 40]}
onChange={(page, pageSize) => {
setQuery({ limit: pageSize, page: page - 1 })
getTableData({ limit: pageSize, page: page - 1, name: searchValue })
}}
/>
</div> : ""}
</div>
{
addModel ?
<PlugInModel
editionData={editionData}
searchValue={searchValue}
close={() => {
setAddModel(false);
setEditionData('')
getTableData({ limit: 10, page: 0, id: searchValue });
setQuery({ limit: 10, page: 0 })
}}
/>
: ""
}
</>
);
}
function mapStateToProps (state) {
const { auth, global } = state;
return {
user: auth.user,
error: auth.error,
actions: global.actions,
apiRoot: global.apiRoot,
isRequesting: auth.isRequesting
}
}
export default connect(mapStateToProps)(PlugIn);

3
code/web/client/src/sections/edition/nav-item.jsx

@ -8,7 +8,8 @@ export function getNavItem(user, dispatch) {
itemKey: 'edgeGateway', text: '网关管理', to: '/edgeGateway/gateway', icon: <IconCheckList />, itemKey: 'edgeGateway', text: '网关管理', to: '/edgeGateway/gateway', icon: <IconCheckList />,
items: [ items: [
{ itemKey: 'gateway', to: '/edgeGateway/gateway', text: '设备列表' }, { itemKey: 'gateway', to: '/edgeGateway/gateway', text: '设备列表' },
{ itemKey: 'edition', to: '/edgeGateway/edition', text: '版本管理' } { itemKey: 'edition', to: '/edgeGateway/edition', text: '版本管理' },
{ itemKey: 'plugIn', to: '/edgeGateway/plugIn', text: '插件管理' }
], ],
}, },
] ]

9
code/web/client/src/sections/edition/routes.js

@ -1,6 +1,6 @@
'use strict'; 'use strict';
import { EditionManage, GatewayManage } from './containers'; import { EditionManage, GatewayManage,PlugIn } from './containers';
export default [ export default [
{ {
@ -18,7 +18,12 @@ export default [
key: 'gateway', key: 'gateway',
breadcrumb: '网关管理', breadcrumb: '网关管理',
component: GatewayManage component: GatewayManage
}] }, {
path: '/plugIn',
key: 'plugIn',
breadcrumb: '插件管理',
component: PlugIn
}]
} }
} }
]; ];

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

@ -1,28 +1,31 @@
'use strict'; 'use strict';
export const ApiTable = { export const ApiTable = {
login: 'v1/login', login: 'v1/login',
logout: 'v1/logout', logout: 'v1/logout',
crossCheck: 'cross_token/check', crossCheck: 'cross_token/check',
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',
delGateway: 'v1/edge/{id}', delGateway: 'v1/edge/{id}',
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',
postedge:'v1/edge', //新增网关 postedge: 'v1/edge', //新增网关
putedge:"v1/edge/{edgeId}", //修改网关 putedge: "v1/edge/{edgeId}", //修改网关
getVersions: 'v1/versions', //查询网关版本信息
deleteVersion: 'v1/version/{versionId}', //删除网关版本
postVersion: 'v1/version', //新增网关版本
getPlugInList: 'v1/edge/{id}/plugins', //插件列表
postAddPlugIn:'v1/edge/{id}/plugin/new'
getVersions: 'v1/versions', //查询网关版本信息
deleteVersion: 'v1/version/{versionId}', //删除网关版本
postVersion: 'v1/version', //新增网关版本
}; };
export const RouteTable = { export const RouteTable = {
apiRoot: '/api/root', apiRoot: '/api/root',
fileUpload: '/_upload/new', fileUpload: '/_upload/new',
cleanUpUploadTrash: '/_upload/cleanup', cleanUpUploadTrash: '/_upload/cleanup',
}; };

1
code/web/config.js

@ -16,6 +16,7 @@ args.option(['u', 'api-url'], 'webapi的URL');
const flags = args.parse(process.argv); const flags = args.parse(process.argv);
const API_URL = process.env.API_URL || 'http://10.8.30.183:4100'; const API_URL = process.env.API_URL || 'http://10.8.30.183:4100';
// const API_URL = process.env.API_URL || 'http://10.8.30.191:4100';
if (!API_URL) { if (!API_URL) {
console.log('缺少启动参数,异常退出'); console.log('缺少启动参数,异常退出');

2
code/web/package.json

@ -56,6 +56,7 @@
"@vitejs/plugin-react-refresh": "^1.3.6", "@vitejs/plugin-react-refresh": "^1.3.6",
"args": "^5.0.1", "args": "^5.0.1",
"babel-polyfill": "^6.26.0", "babel-polyfill": "^6.26.0",
"codemirror": "^6.0.1",
"copy-to-clipboard": "^3.3.1", "copy-to-clipboard": "^3.3.1",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"fs-web-server-scaffold": "^1.0.6", "fs-web-server-scaffold": "^1.0.6",
@ -65,6 +66,7 @@
"moment": "^2.29.3", "moment": "^2.29.3",
"npm": "^7.20.6", "npm": "^7.20.6",
"perfect-scrollbar": "^1.5.5", "perfect-scrollbar": "^1.5.5",
"react-codemirror2": "^7.2.1",
"socket.io-client": "^4.5.0", "socket.io-client": "^4.5.0",
"socket.io-parser": "^4.2.0", "socket.io-parser": "^4.2.0",
"superagent": "^6.1.0", "superagent": "^6.1.0",

Loading…
Cancel
Save