diff --git a/code/web/client/assets/color.less b/code/web/client/assets/color.less index 0047c87..96c2350 100644 --- a/code/web/client/assets/color.less +++ b/code/web/client/assets/color.less @@ -174,7 +174,7 @@ button::-moz-focus-inner, [type='submit']::-moz-focus-inner {border-style: none;} fieldset {border: 0;} legend {color: inherit;} -mark {background-color: color(~`colorPalette("@{table-header-sort-active-bg}", 2)`);} +mark {background-color: #feffe6;} ::selection {color: #fff;background: @primary-color;} .anticon {color: inherit;} .ant-fade-enter, .ant-fade-appear {animation-fill-mode: both;} @@ -1147,10 +1147,10 @@ tr > .ant-picker-cell-in-view.ant-picker-cell-range-hover-start:last-child::afte .ant-mentions-dropdown-menu-item-active {background-color: @item-hover-bg;} .ant-menu-item-danger.ant-menu-item {color: #ff4d4f;} .ant-menu-item-danger.ant-menu-item:hover, .ant-menu-item-danger.ant-menu-item-active {color: #ff4d4f;} -.ant-menu-item-danger.ant-menu-item:active {background: color(~`colorPalette("@{alert-info-border-color}", 4)`);} +.ant-menu-item-danger.ant-menu-item:active {background: color(~`colorPalette("@{skeleton-color}", 1)`);} .ant-menu-item-danger.ant-menu-item-selected {color: #ff4d4f;} .ant-menu-item-danger.ant-menu-item-selected > a, .ant-menu-item-danger.ant-menu-item-selected > a:hover {color: #ff4d4f;} -.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-danger.ant-menu-item-selected {background-color: color(~`colorPalette("@{alert-info-border-color}", 4)`);} +.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-danger.ant-menu-item-selected {background-color: color(~`colorPalette("@{skeleton-color}", 1)`);} .ant-menu-inline .ant-menu-item-danger.ant-menu-item::after {border-right-color: #ff4d4f;} .ant-menu-dark .ant-menu-item-danger.ant-menu-item, .ant-menu-dark .ant-menu-item-danger.ant-menu-item:hover, .ant-menu-dark .ant-menu-item-danger.ant-menu-item > a {color: #ff4d4f;} .ant-menu-dark.ant-menu-dark:not(.ant-menu-horizontal) .ant-menu-item-danger.ant-menu-item-selected {color: #fff;background-color: #ff4d4f;} @@ -1727,17 +1727,17 @@ tr.ant-table-expanded-row:hover > td {background: @table-expanded-row-bg;} .ant-tag-checkable:active, .ant-tag-checkable-checked {color: #fff;} .ant-tag-checkable-checked {background-color: @primary-color;} .ant-tag-checkable:active {background-color: color(~`colorPalette("@{primary-color}", 7)`);} -.ant-tag-pink {color: #c41d7f;background: #fff0f6;border-color: #ffadd2;} +.ant-tag-pink {color: #c41d7f;background: color(~`colorPalette("@{shadow-color}", 1)`);border-color: #ffadd2;} .ant-tag-pink-inverse {color: #fff;background: #eb2f96;border-color: #eb2f96;} -.ant-tag-magenta {color: #c41d7f;background: #fff0f6;border-color: #ffadd2;} +.ant-tag-magenta {color: #c41d7f;background: color(~`colorPalette("@{shadow-color}", 1)`);border-color: #ffadd2;} .ant-tag-magenta-inverse {color: #fff;background: #eb2f96;border-color: #eb2f96;} -.ant-tag-red {color: #cf1322;background: color(~`colorPalette("@{alert-info-border-color}", 4)`);border-color: #ffa39e;} +.ant-tag-red {color: #cf1322;background: color(~`colorPalette("@{skeleton-color}", 1)`);border-color: #ffa39e;} .ant-tag-red-inverse {color: #fff;background: #f5222d;border-color: #f5222d;} .ant-tag-volcano {color: #d4380d;background: #fff2e8;border-color: #ffbb96;} .ant-tag-volcano-inverse {color: #fff;background: #fa541c;border-color: #fa541c;} -.ant-tag-orange {color: #d46b08;background: #fff7e6;border-color: #ffd591;} +.ant-tag-orange {color: #d46b08;background: color(~`colorPalette("@{switch-bg}", 1)`);border-color: #ffd591;} .ant-tag-orange-inverse {color: #fff;background: #fa8c16;border-color: #fa8c16;} -.ant-tag-yellow {color: #d4b106;background: color(~`colorPalette("@{table-header-sort-active-bg}", 2)`);border-color: #fffb8f;} +.ant-tag-yellow {color: #d4b106;background: #feffe6;border-color: #fffb8f;} .ant-tag-yellow-inverse {color: #fff;background: #fadb14;border-color: #fadb14;} .ant-tag-gold {color: #d48806;background: #fffbe6;border-color: #ffe58f;} .ant-tag-gold-inverse {color: #fff;background: #faad14;border-color: #faad14;} @@ -1749,9 +1749,9 @@ tr.ant-table-expanded-row:hover > td {background: @table-expanded-row-bg;} .ant-tag-green-inverse {color: #fff;background: #52c41a;border-color: #52c41a;} .ant-tag-blue {color: #096dd9;background: #e6f7ff;border-color: #91d5ff;} .ant-tag-blue-inverse {color: #fff;background: #1890ff;border-color: #1890ff;} -.ant-tag-geekblue {color: #1d39c4;background: color(~`colorPalette("@{slider-rail-background-color-hover}", 1)`);border-color: #adc6ff;} +.ant-tag-geekblue {color: #1d39c4;background: color(~`colorPalette("@{disabled-color}", 1)`);border-color: #adc6ff;} .ant-tag-geekblue-inverse {color: #fff;background: #2f54eb;border-color: #2f54eb;} -.ant-tag-purple {color: #531dab;background: color(~`colorPalette("@{shadow-color-inverse}", 1)`);border-color: #d3adf7;} +.ant-tag-purple {color: #531dab;background: #f9f0ff;border-color: #d3adf7;} .ant-tag-purple-inverse {color: #fff;background: #722ed1;border-color: #722ed1;} .ant-tag-success {color: #52c41a;background: @success-color-deprecated-bg;border-color: @success-color-deprecated-border;} .ant-tag-processing {color: @primary-color;background: @info-color-deprecated-bg;border-color: @info-color-deprecated-border;} diff --git a/code/web/client/src/app.js b/code/web/client/src/app.js index 844a85a..dde044d 100644 --- a/code/web/client/src/app.js +++ b/code/web/client/src/app.js @@ -5,6 +5,7 @@ import Layout from './layout'; import Auth from './sections/auth'; import Gateway from './sections/gateway'; import Search from './sections/search'; +import Factor from './sections/factor'; const App = props => { const { projectName } = props @@ -16,7 +17,7 @@ const App = props => { return ( ) } diff --git a/code/web/client/src/layout/components/header/index.js b/code/web/client/src/layout/components/header/index.js index 13856ff..7701c74 100644 --- a/code/web/client/src/layout/components/header/index.js +++ b/code/web/client/src/layout/components/header/index.js @@ -76,6 +76,9 @@ const Header = props => { } > 网关配置 + } > + 监测因素 + 主题切换} > diff --git a/code/web/client/src/sections/factor/actions/factors.js b/code/web/client/src/sections/factor/actions/factors.js new file mode 100644 index 0000000..792cd96 --- /dev/null +++ b/code/web/client/src/sections/factor/actions/factors.js @@ -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' } + }) +} \ No newline at end of file diff --git a/code/web/client/src/sections/factor/actions/index.js b/code/web/client/src/sections/factor/actions/index.js new file mode 100644 index 0000000..335a5b6 --- /dev/null +++ b/code/web/client/src/sections/factor/actions/index.js @@ -0,0 +1,7 @@ +'use strict'; + +import * as factor from './factors' + +export default { + ...factor +} \ No newline at end of file diff --git a/code/web/client/src/sections/factor/containers/ConfigModal.js b/code/web/client/src/sections/factor/containers/ConfigModal.js new file mode 100644 index 0000000..91cc7c3 --- /dev/null +++ b/code/web/client/src/sections/factor/containers/ConfigModal.js @@ -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 { + 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() + }} + > + + + + + + + + + + + + )} + > + {protocols.map(item => ( + + ))} + + + + + + +} + +function mapStateToProps(state) { + const { auth, global } = state; + return { + user: auth.user, + actions: global.actions, + }; +} + +export default connect(mapStateToProps)(ConfigModal); diff --git a/code/web/client/src/sections/factor/containers/FactorProfile.js b/code/web/client/src/sections/factor/containers/FactorProfile.js new file mode 100644 index 0000000..4b57163 --- /dev/null +++ b/code/web/client/src/sections/factor/containers/FactorProfile.js @@ -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) => ( + + {record.Factor_proto_item.map(({ Name }) => ( + + {Name} + + ))} + + ), + }, { + title: '操作', + valueType: 'option', + key: 'option', + render: (txt, row, _, action) => [ + + ], + } + ] + + 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
+ } + } + const [activeExpRow, setActiveExpRow] = React.useState(); + + return ( +
+ {/* */} + [ + , + ]} + 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); + } + } + > + + + { + configModalVis ? + { + setConfigModalVis(false) + setEditData(null) + }} + editData={editData} + /> : '' + } + {/* */} +
+ ) +} + +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); diff --git a/code/web/client/src/sections/factor/containers/index.js b/code/web/client/src/sections/factor/containers/index.js new file mode 100644 index 0000000..a3e33d1 --- /dev/null +++ b/code/web/client/src/sections/factor/containers/index.js @@ -0,0 +1,5 @@ +'use strict'; + +import FactorProfile from './FactorProfile'; + +export { FactorProfile }; \ No newline at end of file diff --git a/code/web/client/src/sections/factor/containers/models.js b/code/web/client/src/sections/factor/containers/models.js new file mode 100644 index 0000000..e479d43 --- /dev/null +++ b/code/web/client/src/sections/factor/containers/models.js @@ -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"] \ No newline at end of file diff --git a/code/web/client/src/sections/factor/index.js b/code/web/client/src/sections/factor/index.js new file mode 100644 index 0000000..3f4f724 --- /dev/null +++ b/code/web/client/src/sections/factor/index.js @@ -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 +}; \ No newline at end of file diff --git a/code/web/client/src/sections/factor/nav-item.js b/code/web/client/src/sections/factor/nav-item.js new file mode 100644 index 0000000..8eb5fa8 --- /dev/null +++ b/code/web/client/src/sections/factor/nav-item.js @@ -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 ( + } title={'监测因素'}> + + 监测因素列表 + + + ); +} \ No newline at end of file diff --git a/code/web/client/src/sections/factor/reducers/index.js b/code/web/client/src/sections/factor/reducers/index.js new file mode 100644 index 0000000..7ed1088 --- /dev/null +++ b/code/web/client/src/sections/factor/reducers/index.js @@ -0,0 +1,5 @@ +'use strict'; + +export default { + +} \ No newline at end of file diff --git a/code/web/client/src/sections/factor/routes.js b/code/web/client/src/sections/factor/routes.js new file mode 100644 index 0000000..393f9ee --- /dev/null +++ b/code/web/client/src/sections/factor/routes.js @@ -0,0 +1,12 @@ +'use strict'; +import { FactorProfile} from './containers'; + +export default [{ + type: 'inner', + route: { + path: '/factor_profile', + key: 'factor', + breadcrumb: '监测因素管理', + component: FactorProfile + } +}]; \ No newline at end of file diff --git a/code/web/client/src/sections/factor/style.less b/code/web/client/src/sections/factor/style.less new file mode 100644 index 0000000..3323452 --- /dev/null +++ b/code/web/client/src/sections/factor/style.less @@ -0,0 +1,3 @@ +#example:hover { + font-size: larger; +} \ 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 9b10f25..d9093ee 100644 --- a/code/web/client/src/utils/webapi.js +++ b/code/web/client/src/utils/webapi.js @@ -17,6 +17,9 @@ export const ApiTable = { delGatewayConfig: 'gateway/{gatewayId}', getGatewayProtocols: 'v1/deviceProxy/protocols', + // 监测因素 + getFactors: 'v1/searchFactor', + getEnterprisesMembers: 'enterprises/{enterpriseId}/members', };