yinweiwen
2 years ago
15 changed files with 442 additions and 11 deletions
@ -0,0 +1,16 @@ |
|||
'use strict'; |
|||
|
|||
import { basicAction } from '@peace/utils' |
|||
import { ApiTable } from '$utils' |
|||
|
|||
export function list(query) { |
|||
return dispatch => basicAction({ |
|||
type: 'get', |
|||
dispatch: dispatch, |
|||
query: query, |
|||
actionType: 'GET_FACTOR_LIST', |
|||
url: ApiTable.getFactors, |
|||
msg: { error: '获取监测原型列表失败' }, |
|||
reducer: { name: 'factors' } |
|||
}) |
|||
} |
@ -0,0 +1,7 @@ |
|||
'use strict'; |
|||
|
|||
import * as factor from './factors' |
|||
|
|||
export default { |
|||
...factor |
|||
} |
@ -0,0 +1,145 @@ |
|||
import React, { useEffect, useRef } from 'react'; |
|||
import { connect } from 'react-redux'; |
|||
import { Spin, Select, Divider, Space, Button, Modal, Input, Form, Switch, AutoComplete } from 'antd'; |
|||
import ProForm, { ProFormText, ProFormSelect, ProFormTextArea } from '@ant-design/pro-form'; |
|||
import { useState } from 'react'; |
|||
import { InMode, OutMode, ProtocolTypes } from './models'; |
|||
import { PlusOutlined } from '@ant-design/icons'; |
|||
const { Option } = Select; |
|||
|
|||
const ConfigModal = (props) => { |
|||
const { dispatch, actions, visible, close, editData } = props |
|||
const formRef = useRef() |
|||
const inputRef = useRef() |
|||
const { gateway } = actions |
|||
const [protocols, setProtocols] = useState([]) |
|||
const [newProtocol, setNewProtocol] = useState('') |
|||
|
|||
useEffect(() => { |
|||
setProtocols([]); |
|||
dispatch(gateway.getProtocols()).then(res => { |
|||
if (res.success) { |
|||
setProtocols(res.payload.data.sort()) |
|||
} |
|||
}) |
|||
}, []) |
|||
|
|||
const onNewProtocolChange = (e) => { |
|||
setNewProtocol(e.target.value) |
|||
} |
|||
|
|||
const addNewProtocol = (e) => { |
|||
e.preventDefault(); |
|||
setProtocols([...protocols, newProtocol]) |
|||
setNewProtocol(''); |
|||
setTimeout(()=>{ |
|||
inputRef.current?.focus(); |
|||
}) |
|||
} |
|||
|
|||
const batchAdd=(v)=>{ |
|||
|
|||
} |
|||
|
|||
return <Modal |
|||
title={`${editData ? '编辑' : '新增'}配置`} |
|||
visible={visible} |
|||
onOk={() => { |
|||
formRef.current.validateFields() |
|||
.then(v => { |
|||
v.id = editData?.id; |
|||
if (!v.in_config) { |
|||
v.in_config = '{}' |
|||
} |
|||
if (!v.out_config) { |
|||
v.out_config = '{}' |
|||
} |
|||
dispatch(editData ? gateway.edit([v]) : gateway.add([v])) |
|||
.then(res => { |
|||
if (res.success) { |
|||
dispatch(gateway.list()) |
|||
close() |
|||
} |
|||
}) |
|||
}) |
|||
}} |
|||
onCancel={() => { |
|||
close() |
|||
}} |
|||
> |
|||
<ProForm |
|||
formRef={formRef} |
|||
autoFocusFirstInput |
|||
Layout={'vertical'} |
|||
initialValues={ |
|||
editData ? |
|||
editData : |
|||
{ |
|||
in_mode: InMode[0], |
|||
out_mode: OutMode[0], |
|||
protocol: ProtocolTypes[0], |
|||
} |
|||
} |
|||
submitter={false} |
|||
formKey='config-form' |
|||
grid={true} |
|||
> |
|||
<ProFormText name="name" label="名称" tooltip="最长为 24 位" placeholder="请输入名称" rules={[{ required: true, message: '请输入名称' }]} /> |
|||
<ProFormSelect |
|||
colProps={{ span: 12 }} |
|||
label="输入模式" |
|||
name="in_mode" |
|||
valueEnum={InMode} |
|||
/> |
|||
<ProFormSelect |
|||
colProps={{ span: 12 }} |
|||
label="输出模式" |
|||
name="out_mode" |
|||
valueEnum={OutMode} |
|||
/> |
|||
<ProFormTextArea colProps={{ span: 24 }} name="in_config" label="输入配置" /> |
|||
<ProFormTextArea colProps={{ span: 24 }} name="out_config" label="输出配置" /> |
|||
<Form.Item name="protocol" label="协议" rules={[{ required: true }]}> |
|||
<Select |
|||
style={{ width: 300 }} |
|||
placeholder="选择协议" |
|||
dropdownRender={menu => ( |
|||
<> |
|||
{menu} |
|||
<Divider style={{ margin: '8px 0' }} /> |
|||
<Space style={{ padding: '0 8px 4px' }}> |
|||
<Input |
|||
placeholder="输入新增协议名" |
|||
ref={inputRef} |
|||
value={newProtocol} |
|||
onChange={onNewProtocolChange} |
|||
/> |
|||
<Button type="text" icon={<PlusOutlined />} onClick={addNewProtocol}> |
|||
添加项 |
|||
</Button> |
|||
</Space> |
|||
</> |
|||
)} |
|||
> |
|||
{protocols.map(item => ( |
|||
<Option key={item}>{item}</Option> |
|||
))} |
|||
</Select> |
|||
|
|||
</Form.Item> |
|||
<ProFormTextArea colProps={{ span: 24 }} |
|||
name="protocol_info" label="协议信息" |
|||
/> |
|||
</ProForm> |
|||
</Modal> |
|||
} |
|||
|
|||
function mapStateToProps(state) { |
|||
const { auth, global } = state; |
|||
return { |
|||
user: auth.user, |
|||
actions: global.actions, |
|||
}; |
|||
} |
|||
|
|||
export default connect(mapStateToProps)(ConfigModal); |
@ -0,0 +1,196 @@ |
|||
import React, { useState, useEffect, useRef } from 'react'; |
|||
import { connect } from 'react-redux'; |
|||
import { Spin, Button, Card, Input, Space, Tag, Table } from 'antd'; |
|||
import '../style.less'; |
|||
import { push } from 'react-router-redux' |
|||
import ProTable, { TableDropdown } from '@ant-design/pro-table'; |
|||
import { InMode, OutMode, ProtocolTypes } from './models'; |
|||
import ConfigModal from './ConfigModal'; |
|||
import { request } from 'superagent'; |
|||
|
|||
const FactorProfile = (props) => { |
|||
const { dispatch, actions, user, loading, factors, total } = props |
|||
|
|||
const { factor } = actions; |
|||
const [configModalVis, setConfigModalVis] = useState(false) |
|||
const [editData, setEditData] = useState(null) |
|||
const [fdata, setFdata] = useState([]) |
|||
|
|||
const pageSize = 10 |
|||
|
|||
useEffect(() => { |
|||
// dispatch(factor.list())
|
|||
}, []) |
|||
|
|||
const actionRef = useRef(); |
|||
const columns = [ |
|||
{ |
|||
dataIndex: 'id', |
|||
valueType: 'indexBorder', |
|||
width: 48, |
|||
}, { |
|||
title: '名称', |
|||
dataIndex: 'Name', |
|||
ellipsis: true |
|||
}, |
|||
{ |
|||
title: '编码', |
|||
dataIndex: 'Proto', |
|||
}, |
|||
{ |
|||
title: '监测项', |
|||
dataIndex: 'Factor_proto_item', |
|||
ellipsis: true, |
|||
render: (_, record) => ( |
|||
<Space> |
|||
{record.Factor_proto_item.map(({ Name }) => ( |
|||
<Tag key={Name}> |
|||
{Name} |
|||
</Tag> |
|||
))} |
|||
</Space> |
|||
), |
|||
}, { |
|||
title: '操作', |
|||
valueType: 'option', |
|||
key: 'option', |
|||
render: (txt, row, _, action) => [ |
|||
<Button type="primary" |
|||
onClick={() => { |
|||
setConfigModalVis(true) |
|||
setEditData({ ...row }) |
|||
}} |
|||
>详情</Button> |
|||
], |
|||
} |
|||
] |
|||
|
|||
const requestList = async (params) => { |
|||
const ret = await dispatch(factor.list()); |
|||
console.log(ret) |
|||
let tmp = [] |
|||
tmp = ret.payload.data.data; |
|||
if (!!params.Name) { |
|||
tmp = tmp.filter(a => a.Name.includes(params.Name)) |
|||
} |
|||
if (!!params.Proto) { |
|||
tmp = tmp.filter(a => a.Proto.includes(params.Proto)) |
|||
} |
|||
if(!!params.Factor_proto_item){ |
|||
tmp = tmp.filter(a => a.Factor_proto_item.some(d=>{ |
|||
return d.Name.includes(params.Factor_proto_item) || |
|||
d.Field_name.includes(params.Factor_proto_item) || |
|||
d.Item_unit.includes(params.Factor_proto_item) |
|||
})) |
|||
} |
|||
let data = tmp.slice(params.pageSize * (params.current - 1), params.pageSize * params.current); |
|||
data = data.map(d => ({ |
|||
...d, |
|||
key: d.Proto + d.Name |
|||
})) |
|||
setFdata(data) |
|||
return { |
|||
total: tmp.length, |
|||
data: data |
|||
} |
|||
const query = { |
|||
limit: params.pageSize, |
|||
offset: params.pageSize * (params.current - 1) |
|||
} |
|||
const res = await dispatch(factor.list(query)); |
|||
return { |
|||
...res, |
|||
total: res.payload.data ? res.payload.data.total : 0 |
|||
} |
|||
} |
|||
|
|||
const expandRow = (record, index, indent, expanded) => { |
|||
let cols = [] |
|||
if (expanded) { |
|||
cols = [{ |
|||
title: '名称', |
|||
dataIndex: 'Name', |
|||
ellipsis: true |
|||
}, { |
|||
title: '字段', |
|||
dataIndex: 'Field_name', |
|||
ellipsis: true |
|||
}, { |
|||
title: '单位', |
|||
dataIndex: 'Item_unit', |
|||
ellipsis: true |
|||
}, |
|||
] |
|||
return <Table columns={cols} dataSource={record.Factor_proto_item} pagination={false}></Table> |
|||
} |
|||
} |
|||
const [activeExpRow, setActiveExpRow] = React.useState(); |
|||
|
|||
return ( |
|||
<div> |
|||
{/* <Spin tip="biubiubiu~" spinning={loading}> */} |
|||
<ProTable |
|||
columns={columns} |
|||
actionRef={actionRef} |
|||
toolbar={{ |
|||
settings: [] |
|||
}} |
|||
search={{ |
|||
labelWidth: 'auto', |
|||
}} |
|||
dataSource={fdata} |
|||
request={requestList} |
|||
manualRequest={false} |
|||
options={false} |
|||
toolBarRender={() => [ |
|||
<Button type="primary" key="primary" onClick={() => { setConfigModalVis(true) }}> |
|||
添加配置 |
|||
</Button>, |
|||
]} |
|||
pagination={{ |
|||
pageSize: pageSize, |
|||
onChange: (page) => console.log(page), |
|||
}} |
|||
expandedRowKeys={activeExpRow} |
|||
rowExpandable={(record) => { return true; }} |
|||
expandedRowRender={expandRow} |
|||
onExpand={ |
|||
(expanded, record) => { |
|||
const keys = []; |
|||
if (expanded) { |
|||
keys.push(record.Proto + record.Name); |
|||
} |
|||
console.log(keys); |
|||
setActiveExpRow(keys); |
|||
} |
|||
} |
|||
> |
|||
</ProTable> |
|||
|
|||
{ |
|||
configModalVis ? |
|||
<ConfigModal |
|||
visible={true} |
|||
close={() => { |
|||
setConfigModalVis(false) |
|||
setEditData(null) |
|||
}} |
|||
editData={editData} |
|||
/> : '' |
|||
} |
|||
{/* </Spin> */} |
|||
</div> |
|||
) |
|||
} |
|||
|
|||
function mapStateToProps(state) { |
|||
const { auth, global, factors } = state; |
|||
return { |
|||
user: auth.user, |
|||
actions: global.actions, |
|||
loading: factors.isRequesting, |
|||
factors: factors.data?.data ?? [], |
|||
}; |
|||
} |
|||
|
|||
export default connect(mapStateToProps)(FactorProfile); |
@ -0,0 +1,5 @@ |
|||
'use strict'; |
|||
|
|||
import FactorProfile from './FactorProfile'; |
|||
|
|||
export { FactorProfile }; |
@ -0,0 +1,4 @@ |
|||
const GatewayMode = ["tcp", "udp", "mqtt", "http", "dtu"] |
|||
export const InMode = GatewayMode |
|||
export const OutMode = GatewayMode |
|||
export const ProtocolTypes = ["DeviceA", "DeviceB", "DeviceC", "DeviceD"] |
@ -0,0 +1,15 @@ |
|||
'use strict'; |
|||
|
|||
import reducers from './reducers'; |
|||
import routes from './routes'; |
|||
import actions from './actions'; |
|||
import { getNavItem } from './nav-item'; |
|||
|
|||
export default { |
|||
key: 'factor', |
|||
name: '监测因素', |
|||
reducers: reducers, |
|||
routes: routes, |
|||
actions: actions, |
|||
getNavItem: getNavItem |
|||
}; |
@ -0,0 +1,16 @@ |
|||
import React from 'react'; |
|||
import { Link } from 'react-router-dom'; |
|||
import { Menu } from 'antd'; |
|||
import { SettingOutlined } from '@ant-design/icons'; |
|||
|
|||
const SubMenu = Menu.SubMenu; |
|||
|
|||
export function getNavItem(user, dispatch) { |
|||
return ( |
|||
<SubMenu key="factor" icon={<SettingOutlined />} title={'监测因素'}> |
|||
<Menu.Item key="factor_profile"> |
|||
<Link to="/factor_profile/list">监测因素列表</Link> |
|||
</Menu.Item> |
|||
</SubMenu> |
|||
); |
|||
} |
@ -0,0 +1,5 @@ |
|||
'use strict'; |
|||
|
|||
export default { |
|||
|
|||
} |
@ -0,0 +1,12 @@ |
|||
'use strict'; |
|||
import { FactorProfile} from './containers'; |
|||
|
|||
export default [{ |
|||
type: 'inner', |
|||
route: { |
|||
path: '/factor_profile', |
|||
key: 'factor', |
|||
breadcrumb: '监测因素管理', |
|||
component: FactorProfile |
|||
} |
|||
}]; |
@ -0,0 +1,3 @@ |
|||
#example:hover { |
|||
font-size: larger; |
|||
} |
Loading…
Reference in new issue