Browse Source

搜索

master
wenlele 2 years ago
parent
commit
6a6b83884d
  1. 27
      code/web/client/src/sections/edition/actions/index.js
  2. 187
      code/web/client/src/sections/edition/components/addModel.jsx
  3. 15
      code/web/client/src/sections/edition/containers/administer.jsx
  4. 589
      code/web/client/src/sections/edition/containers/gateway.jsx
  5. 130
      code/web/client/src/sections/edition/containers/gatewayModal.jsx
  6. 2
      code/web/client/src/utils/webapi.js

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

@ -116,6 +116,31 @@ export function restartGateway(id) {
msg: { option: '重启网关服务' }, msg: { option: '重启网关服务' },
}); });
} }
export function postedge(data) {
return (dispatch) =>
basicAction({
type: "post",
dispatch: dispatch,
data,
actionType: "POST_EDGE",
url: `${ApiTable.postedge}`,
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 default { export default {
getGateways, getGateways,
getGatewayStatus, getGatewayStatus,
@ -127,4 +152,6 @@ export default {
getVersions, getVersions,
deleteVersion, deleteVersion,
postVersion, postVersion,
postedge,
putedge,
}; };

187
code/web/client/src/sections/edition/components/addModel.jsx

@ -0,0 +1,187 @@
'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, dataToModal, editionData } = 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 api = useRef()
useEffect(() => {
if (dataToModal?.properties) {
let data = []
for (let k in dataToModal?.properties) {
data.push({ key: k, value: dataToModal?.properties[k] })
}
setProperty(data)
}
}, [])
useEffect(() => {
let data = {}
property?.map(v => {
if (v.key) {
data[v.key] = v.value
}
})
setattributeValue(data)
}, [property])
return (
<>
<Modal
title={dataToModal?.id ? '修改网关' : '新增网关'}
// okText={okText}
visible={true}
onOk={() => {
api.current.validate().then(r => {
// console.log(r);
r.properties = JSON.stringify(attributeValue)
if (dataToModal?.id) {
dispatch(edition.putedge(dataToModal?.id, r)).then(res => {
console.log(res)
if (res.success) {
close()
}
})
} else {
dispatch(edition.postedge(r)).then(res => {
// console.log(res);
if (res.success) {
close()
}
})
}
})
}}
width={500}
onCancel={() => close()}
>
<Form
getFormApi={(formApi) => (api.current = formApi)}
layout="horizontal"
labelAlign="right"
labelWidth="114px"
style={{ display: 'flex', flexDirection: 'column' }}
>
<Form.Input
field='serialNo'
label='设备序列号:'
labelPosition="left"
hideButtons={true}
placeholder='请输入设备序列号'
style={{ width: 240, marginBottom: 12 }}
initValue={dataToModal?.serialNo || ''}
disabled={dataToModal?.id ? true : false}
rules={[{ required: true, message: "请输入设备序列号" }, { pattern: "^[a-zA-Z0-9]{4,20}$", message: "必须4~20位数字或字母" },]}
/>
<Form.Input
field='name'
label='设备名称:'
labelPosition="left"
hideButtons={true}
placeholder='请输入设备名称'
style={{ width: 240, marginBottom: 12 }}
initValue={dataToModal?.name || ''}
rules={[{ required: true, message: "请输入设备名称" }]}
/>
{/* <Form.Input
field='properties'
label='设备属性:'
labelPosition="left"
hideButtons={true}
placeholder='请输入设备属性'
style={{ width: 240, marginBottom: 12 }}
initValue={JSON.stringify(dataToModal?.properties) || ''}
// rules={[{ required: true, message: "" }, { pattern: "^[0-9]+$", message: "" },]}
/> */}
<Form.Input
field='hardwareName' label='硬件信息:'
labelPosition="left"
hideButtons={true}
placeholder='请输入硬件信息'
style={{ width: 240, marginBottom: 12 }}
initValue={dataToModal?.hardwareName || ''}
// rules={[{ required: true, message: "" }, { pattern: "^[0-9]+$", message: "" },]}
/>
<Form.Select
field="softwareVer"
label='软件信息:'
labelPosition="left"
placeholder='请选择软件版本'
style={{ width: 240, marginBottom: 12 }}
initValue={dataToModal?.softwareVer || ''}
// rules={[{ required: true, message: "" }]}
>
{editionData?.map((v, i) => <Form.Select.Option key={'softwareVer' + i} value={v}>{v}</Form.Select.Option>)}
</Form.Select>
<div style={{ display: 'flex', marginBottom: 12 }}>
<div style={{ width: 114, height: 44, padding: '6px 16px 6px 0', textIndent: 38, fontWeight: 600, color: 'var(--semi-color-text-0)', fontSize: 14 }}>设备属性:</div>
<Collapse style={{ width: 270, background: 'var(--semi-color-fill-0)' }}>
<Collapse.Panel header={<div style={{ width: 260, whiteSpace: 'nowrap', textOverflow: 'ellipsis', overflow: 'hidden' }}>{JSON.stringify(attributeValue)}</div>} itemKey="1">
<div style={{ background: 'white', paddingBottom: 10, position: 'relative' }}>
<div style={{ display: 'flex', marginBottom: 10 }}>
<div style={{ width: 104, fontWeight: 600, marginLeft: 6 }}>key:</div>
<div style={{ width: 94, fontWeight: 600, }}>value:</div>
</div>
{property?.map((v, i) =>
<div key={'properties' + i} style={{ marginBottom: 10 }}>
<Input value={v.key} style={{ width: 90, marginLeft: 6 }}
onChange={e => {
console.log(e);
property?.splice(i, 1, { key: e, value: v.value })
setProperty([...property])
}}
/> --
<Input value={v.value} style={{ width: 90 }}
onChange={e => {
property?.splice(i, 1, { key: v.key, value: e })
setProperty([...property])
}}
/>
{property?.length > 1 ? <IconMinusCircle onClick={() => {
console.log(i);
console.log(property);
property?.splice(i, 1)
setProperty([...property])
}} /> : ""}
</div>)}
<IconPlusCircle style={{ position: 'absolute', bottom: 0, right: 0 }}
onClick={() => {
setProperty([...property, { key: '', value: '' }])
}}
/>
</div>
</Collapse.Panel>
</Collapse>
</div>
</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);

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

@ -12,6 +12,7 @@ const EditionManage = props => {
const { edition } = actions const { edition } = actions
const [versionList, setVersionList] = useState([]) const [versionList, setVersionList] = useState([])
const [addVersion, setaddVersion] = useState(false) const [addVersion, setaddVersion] = useState(false)
const [query, setQuery] = useState({ page: 1, pageSize: 10 })
const api = useRef() const api = useRef()
useEffect(() => { useEffect(() => {
@ -20,7 +21,6 @@ const EditionManage = props => {
const requestData = () => { const requestData = () => {
dispatch(edition.getVersions()).then(res => { dispatch(edition.getVersions()).then(res => {
console.log(res);
if (res.success) { if (res.success) {
setVersionList(res.payload.data) setVersionList(res.payload.data)
} }
@ -80,9 +80,14 @@ const EditionManage = props => {
dataIndex: "operation", dataIndex: "operation",
render: (_, r, index) => { render: (_, r, index) => {
return <Button onClick={() => { return <Button onClick={() => {
let volume = versionList?.slice((query?.page - 1) * query?.pageSize, query?.page * query?.pageSize) || []
dispatch(edition.deleteVersion(r.id)).then(res => { dispatch(edition.deleteVersion(r.id)).then(res => {
if (res.success) { if (res.success) {
requestData() requestData()
if (versionList?.length < (query?.limit + 1) || tableData?.length > 1) {
} else {
setQuery({ ...query, page: query?.page - 1 })
}
} }
}) })
}}>删除</Button> }}>删除</Button>
@ -151,7 +156,7 @@ const EditionManage = props => {
}}> }}>
<Table <Table
columns={columns} columns={columns}
dataSource={versionList} dataSource={versionList?.slice((query?.page - 1) * query?.pageSize, query?.page * query?.pageSize) || []}
bordered={false} bordered={false}
empty="暂无数据" empty="暂无数据"
style={{ style={{
@ -172,11 +177,10 @@ const EditionManage = props => {
<Pagination <Pagination
total={versionList.length} total={versionList.length}
showSizeChanger showSizeChanger
currentPage={1} currentPage={query?.page}
pageSizeOpts={[10, 20, 30, 40]} pageSizeOpts={[10, 20, 30, 40]}
onChange={(currentPage, pageSize) => { onChange={(currentPage, pageSize) => {
// setQuery({ limit: pageSize, page: currentPage - 1 }); setQuery({ pageSize: pageSize, page: currentPage });
// page.current = currentPage - 1
}} }}
/> />
</div> : ""} </div> : ""}
@ -196,6 +200,7 @@ const EditionManage = props => {
dispatch(edition.postVersion({ ...r, createdAt: moment().format("YYYY-MM-DD HH:MM:SS") })).then(res => { dispatch(edition.postVersion({ ...r, createdAt: moment().format("YYYY-MM-DD HH:MM:SS") })).then(res => {
if (res.success) { if (res.success) {
requestData() requestData()
setQuery({ limit: 10, page: 1 })
setaddVersion(false) setaddVersion(false)
} }
}) })

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

@ -2,286 +2,357 @@
import React, { useEffect, useState, useRef } from 'react'; import React, { useEffect, useState, 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 { Popconfirm, Button, Popover, Skeleton, Table, Tag } from '@douyinfe/semi-ui'; import { Popconfirm, Button, Popover, Skeleton, Table, Tag, Input, Pagination } from '@douyinfe/semi-ui';
import { IconSearch } from '@douyinfe/semi-icons';
import { SkeletonScreen } from "$components"; import { SkeletonScreen } from "$components";
import GatewayStatusModal from './gatewayStatusModal' import GatewayStatusModal from './gatewayStatusModal'
import GatewayModal from './gatewayModal' import AddModel from '../components/addModel'
const GatewayManage = props => { const GatewayManage = props => {
const { dispatch, user, error, actions } = props const { dispatch, user, error, actions } = props
const { edition } = actions; const { edition } = actions;
const [query, setQuery] = useState({ limit: 10, page: 0 }); // const [query, setQuery] = useState({ limit: 10, page: 0 }); //
const [tableData, setTableData] = useState([]); const [tableData, setTableData] = useState([]);
const [limits, setLimits] = useState()// const [limits, setLimits] = useState(0)//
const [detailV, setDetailV] = useState(false) const [detailV, setDetailV] = useState(false)
const [dataToModal, setDataToModal] = useState(null) const [dataToModal, setDataToModal] = useState(null)
const [deviceModalV, setDeviceModalV] = useState(false) const [addModel, setAddModel] = useState(false)
const [editionData, setEditionData] = useState([])
const [searchValue, setSearchValue] = useState('')
useEffect(() => {
getTableData(query)
}, [])
const getTableData = (obj) => { useEffect(() => {
let { limit, page } = obj getTableData(query)
let queryObj = { limit, offset: limit * page } dispatch(edition.getVersions()).then(res => {
dispatch(edition.getGateways(queryObj)).then(res => {// if (res.success) {
if (res.success) { let data = res.payload.data?.map(r => r.imageVersion)
setTableData(res.payload.data.data); setEditionData(data)
setLimits(res.payload.data.total); }
} })
}) }, [])
}
const ableDevice = (id, v) => { const getTableData = (obj) => {
let ableObj = { "enabled": v } let { limit, page, name } = obj
dispatch(edition.ableGateway(id, ableObj)).then(r => { let queryObj = { limit, offset: limit * page, name }
if (r.success) { dispatch(edition.getGateways(queryObj)).then(res => {//
getTableData(query) if (res.success) {
} setTableData(res.payload.data.data);
}) setLimits(res.payload.data.total);
} }
})
}
const aStyle = { color: '#40a9ff', cursor: 'pointer' } const ableDevice = (id, v) => {
const columns = [ let ableObj = { "enabled": v }
{ dispatch(edition.ableGateway(id, ableObj)).then(r => {
title: "序列号", if (r.success) {
dataIndex: "serialNo", getTableData(query)
key: "serialNo", }
}, { })
title: "名称", }
dataIndex: "name",
key: "name",
}, {
title: "在线状态",
dataIndex: "state",
key: "state",
render: (text, record) => {
return text ? <Tag color='green'>在线</Tag> : <Tag color='grey'>离线</Tag>
}
}, {
title: "固件信息",
dataIndex: "hardwareName",
key: "hardwareName",
}, {
title: "软件信息",
dataIndex: "softwareVer",
key: "softwareVer",
render: (text, record) => <span>{text || '-'}</span>
}, {
title: "绑定结构物数",
dataIndex: "thingIds",
key: "thingIds",
render: (text, record) => <span>{text.length}</span>
}, {
title: "是否启用",
dataIndex: "enabled",
key: "enabled",
render: (text, record) => <span>{text ? '是' : '否'}</span>
}, {
title: "状态指标",
dataIndex: "detail",
key: "detail",
render: (text, record) => <a style={aStyle} onClick={() => {
setDetailV(true)
setDataToModal(record)
}}>查看</a>
}, {
title: "操作",
dataIndex: "action",
key: "action",
render: (text, record) => {
return <div>
<Popconfirm
title="提示"
content={`确认${record.enabled ? '禁用' : '启用'}该网关?`}
onConfirm={() => {
ableDevice(record.id, !record.enabled)
}}>
<a style={aStyle}>{record.enabled ? '禁用' : '启用'}</a>
</Popconfirm>
<a style={{ ...aStyle, marginLeft: 15 }} onClick={() => { const aStyle = { color: '#40a9ff', cursor: 'pointer' }
setDeviceModalV(true) const columns = [
setDataToModal(record) {
}}>编辑</a> title: "序列号",
dataIndex: "serialNo",
key: "serialNo",
}, {
title: "名称",
dataIndex: "name",
key: "name",
}, {
title: "在线状态",
dataIndex: "state",
key: "state",
render: (text, record) => {
return text ? <Tag color='green'>在线</Tag> : <Tag color='grey'>离线</Tag>
}
}, {
title: "固件信息",
dataIndex: "hardwareName",
key: "hardwareName",
}, {
title: "软件信息",
dataIndex: "softwareVer",
key: "softwareVer",
render: (text, record) => <span>{text || '-'}</span>
}, {
title: "绑定结构物数",
dataIndex: "thingIds",
key: "thingIds",
render: (text, record) => <span>{text.length}</span>
}, {
title: "是否启用",
dataIndex: "enabled",
key: "enabled",
render: (text, record) => <span>{text ? '是' : '否'}</span>
}, {
title: "状态指标",
dataIndex: "detail",
key: "detail",
render: (text, record) => <a style={aStyle} onClick={() => {
setDetailV(true)
setDataToModal(record)
}}>查看</a>
}, {
title: "操作",
dataIndex: "action",
key: "action",
render: (text, record) => {
return <div style={{ width: 168 }}>
<Popconfirm
title="提示"
position='leftBottom'
content={<div style={{ width: 150 }}>确认{record.enabled ? '禁用' : '启用'}该网关</div>}
onConfirm={() => {
ableDevice(record.id, !record.enabled)
}}>
<a style={aStyle}>{record.enabled ? '禁用' : '启用'}</a>
</Popconfirm>
<Popconfirm <a style={{ ...aStyle, marginLeft: 15 }} onClick={() => {
title="提示" setAddModel(true)
content={`确认删除该网关?`} setDataToModal(record || {})
onConfirm={() => { }}>编辑</a>
dispatch(edition.delGateway(record.id)).then(r => {
if (r.success) {
getTableData(query)
}
})
}}>
<a style={{ ...aStyle, marginLeft: 15 }}>删除</a>
</Popconfirm>
<Popover key={Math.random()} content={renderPopover(record)} trigger='click' position='right'> <Popconfirm
<a style={{ ...aStyle, marginLeft: 15 }}>更多...</a> title="提示"
</Popover> position='leftBottom'
</div> content={<div style={{ width: 150 }}>确认删除该网关</div>}
} onConfirm={() => {
} dispatch(edition.delGateway(record.id)).then(r => {
]; if (r.success) {
if (limits < (query?.limit + 1) || tableData?.length > 1) {
getTableData({ ...query, name: searchValue })
} else {
getTableData({ ...query, page: query?.page - 1 })
setQuery({ ...query, page: query?.page - 1, name: searchValue })
}
}
})
}}>
<a style={{ ...aStyle, marginLeft: 15 }}>删除</a>
</Popconfirm>
const renderPopover = (record) => { <Popover key={Math.random()} content={renderPopover(record)} trigger='click' position='right'>
return (<div style={{ padding: 12 }}> <a style={{ ...aStyle, marginLeft: 15 }}>更多...</a>
<div style={{ ...aStyle, marginBottom: 10 }} onClick={() => { </Popover>
dispatch(edition.gatewaySsh(record.id)).then(r => { </div>
if (r.success) { }
let url = r.payload.data.redirectUrl }
window.open(url, '_blank') ];
}
})
}}>远程控制</div>
<div style={{ ...aStyle, marginBottom: 10 }} onClick={() => { const renderPopover = (record) => {
let url = `http://${record.serialNo}.edge.yinweiwen.cn` return (<div style={{ padding: 12 }}>
window.open(url, '_blank') <div style={{ ...aStyle, marginBottom: 10 }} onClick={() => {
}}>远程主机</div> dispatch(edition.gatewaySsh(record.id)).then(r => {
if (r.success) {
let url = r.payload.data.redirectUrl
window.open(url, '_blank')
}
})
}}>远程控制</div>
<Popconfirm <div style={{ ...aStyle, marginBottom: 10 }} onClick={() => {
title="提示" let url = `http://${record.serialNo}.edge.yinweiwen.cn`
content={`确认重启网关系统?`} window.open(url, '_blank')
onConfirm={() => { }}>远程主机</div>
dispatch(edition.rebootGateway(record.id)).then(r => {
if (r.success) {
getTableData(query)
}
})
}}>
<div style={{ ...aStyle, marginBottom: 10 }}>重启系统</div>
</Popconfirm>
<Popconfirm <Popconfirm
title="提示" title="提示"
content={`确认重启网关服务?`} content={`确认重启网关系统?`}
onConfirm={() => { onConfirm={() => {
dispatch(edition.restartGateway(record.id)).then(r => { dispatch(edition.rebootGateway(record.id)).then(r => {
if (r.success) { if (r.success) {
getTableData(query) getTableData({ ...query, name: searchValue })
} }
}) })
}}> }}>
<div style={{ ...aStyle }}>重启应用</div> <div style={{ ...aStyle, marginBottom: 10 }}>重启系统</div>
</Popconfirm> </Popconfirm>
</div>)
}
return ( <Popconfirm
<> title="提示"
<div> content={`确认重启网关服务?`}
<video onConfirm={() => {
id="gatewayBanner" dispatch(edition.restartGateway(record.id)).then(r => {
autoPlay if (r.success) {
loop getTableData({ ...query, name: searchValue })
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={() => {
setDeviceModalV(true)
}}
>
新增网关
</div>
</div>
</div>
<div style={{
width: "100%",
background: "#FFFFFF",
borderRadius: 3,
padding: "8px 20px",
marginTop: 20,
}}> }}>
<Skeleton <div style={{ ...aStyle }}>重启应用</div>
loading={false} </Popconfirm>
active={true} </div>)
placeholder={SkeletonScreen()} }
>
<Table return (
columns={columns} <>
dataSource={tableData} <div>
bordered={false} <video
empty="暂无数据" id="gatewayBanner"
style={{ autoPlay
padding: "0px 20px", loop
}} muted
pagination={{ style={{ width: "100%", objectFit: "cover", height: 171 }}
current: query.page + 1, src="/assets/videos/gateway_banner.mp4"
total: limits, type="video/mp4"
showSizeChanger: true, />
showQuickJumper: true, <div style={{ position: "absolute", top: 12 }}>
showTotal: (total) => { <div
return <span style={{ fontSize: 15 }}>{`${Math.ceil(total / limits)}页,${total}`}</span> style={{
}, fontSize: 22,
onChange: (page, pageSize) => { paddingTop: 15,
setQuery({ limit: pageSize, page: page - 1 }); marginLeft: 21,
getTableData({ limit: pageSize, page: page - 1 }); }}
} >
}} 设备列表
/> </div>
</Skeleton> <div
{ style={{
detailV ? <GatewayStatusModal fontSize: 14,
onCancel={() => setDetailV(false)} paddingTop: 18,
dataToModal={dataToModal} /> : '' marginLeft: 20,
} }}
{ >
deviceModalV ? <GatewayModal 对网关设备添加编辑删除以及远程控制等的管理页面
onCancel={() => setDeviceModalV(false)} </div>
dataToModal={dataToModal} /> : '' <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>
<div style={{
width: "100%",
background: "#FFFFFF",
borderRadius: 3,
padding: "8px 20px",
marginTop: 20,
}}>
<div style={{ display: 'flex', alignItems: 'center', marginBottom: 16 }}>
名称
<Input
style={{ width: 200 }}
placeholder='请输入名称关键字'
onEnterPress={(e) => {
console.log(e.target.value)
getTableData({ limit: 10, page: 0, name: e.target.value })
setQuery({ limit: 10, page: 0 })
}}
onChange={e => {
setSearchValue(e)
}}
showClear>
</Input>
<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>
<Skeleton
loading={false}
active={true}
placeholder={SkeletonScreen()}
>
<Table
columns={columns}
dataSource={tableData}
bordered={false}
empty="暂无数据"
style={{
padding: "0px 20px",
}}
pagination={false}
// pagination={{
// current: query.page + 1,
// total: limits,
// showSizeChanger: true,
// showQuickJumper: true,
// showTotal: (total) => {
// return <span style={{ fontSize: 15 }}>{`${Math.ceil(total / limits)}${total}`}</span>
// },
// onChange: (page, pageSize) => {
// setQuery({ limit: pageSize, page: page - 1 })
// getTableData({ limit: pageSize, page: page - 1 })
// }
// }}
/>
</Skeleton>
{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> : ""}
{
detailV ? <GatewayStatusModal
onCancel={() => setDetailV(false)}
dataToModal={dataToModal} /> : ''
}
</div>
{addModel ?
<AddModel
dataToModal={dataToModal}
editionData={editionData}
close={() => {
setAddModel(false);
setDataToModal({})
getTableData({ limit: 10, page: 0, name: searchValue });
setQuery({ limit: 10, page: 0 })
}}
/>
: ""
}
</>
); );
} }
function mapStateToProps(state) { function mapStateToProps (state) {
const { auth, global } = state; const { auth, global } = state;
return { return {
user: auth.user, user: auth.user,
error: auth.error, error: auth.error,
actions: global.actions, actions: global.actions,
apiRoot: global.apiRoot, apiRoot: global.apiRoot,
isRequesting: auth.isRequesting isRequesting: auth.isRequesting
} }
} }
export default connect(mapStateToProps)(GatewayManage); export default connect(mapStateToProps)(GatewayManage);

130
code/web/client/src/sections/edition/containers/gatewayModal.jsx

@ -1,130 +0,0 @@
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 GatewayModal = (props) => {
const { dispatch, actions, user, onCancel, dataToModal } = props;
const { edition } = actions;
const api = useRef()
//
useEffect(() => {
}, []);
return (
<Modal
title={`${dataToModal ? '修改' : '新增'}网关`}
destroyOnClose visible={true}
onOk={() => {
api.current.validate().then(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={() => onCancel(0)}
>
{/* <Form
getFormApi={(formApi) => (api.current = formApi)}
layout="horizontal"
labelAlign="right"
labelWidth="114px"
style={{ display: 'flex', flexDirection: 'column' }}
>
<Form.Input
field='serialNo'
label='序列号'
labelPosition="left"
hideButtons={true}
placeholder='请输入序列号'
style={{ width: 200, marginBottom: 10 }}
rules={[{ required: true, message: "请输入序列号" }]}
/>
<Form.Input
field='name'
label='名称'
labelPosition="left"
hideButtons={true}
placeholder='请输入名称'
style={{ width: 200, marginBottom: 10 }}
rules={[{ required: true, message: "请输入名称" }]}
/>
<Form.Input
field='patch'
label='属性'
labelPosition="left"
hideButtons={true}
placeholder='请输入网关属性'
style={{ width: 200, marginBottom: 10 }}
rules={[{ required: true, 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>
)
}
function mapStateToProps(state) {
const { auth, global } = state;
return {
user: auth.user,
error: auth.error,
actions: global.actions,
};
}
export default connect(mapStateToProps)(GatewayModal);

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

@ -13,6 +13,8 @@ export const ApiTable = {
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', //新增网关
putedge:"v1/edge/{edgeId}", //修改网关
getVersions: 'v1/versions', //查询网关版本信息 getVersions: 'v1/versions', //查询网关版本信息
deleteVersion: 'v1/version/{versionId}', //删除网关版本 deleteVersion: 'v1/version/{versionId}', //删除网关版本

Loading…
Cancel
Save