wenlele 10 months ago
parent
commit
da1e3c18d2
  1. 11
      web-screen/client/src/app.js
  2. 60
      web-screen/client/src/sections/advisoryNotice/actions/advisoryNotice.js
  3. 6
      web-screen/client/src/sections/advisoryNotice/actions/index.js
  4. 108
      web-screen/client/src/sections/advisoryNotice/components/addAdvisoryNoticeModal.js
  5. 216
      web-screen/client/src/sections/advisoryNotice/containers/advisoryNotice.js
  6. 5
      web-screen/client/src/sections/advisoryNotice/containers/index.js
  7. 0
      web-screen/client/src/sections/advisoryNotice/containers/style.less
  8. 15
      web-screen/client/src/sections/advisoryNotice/index.js
  9. 14
      web-screen/client/src/sections/advisoryNotice/nav-item.js
  10. 5
      web-screen/client/src/sections/advisoryNotice/reducers/index.js
  11. 12
      web-screen/client/src/sections/advisoryNotice/routes.js
  12. 3
      web-screen/client/src/sections/deviceManage/actions/index.js
  13. 50
      web-screen/client/src/sections/deviceManage/actions/network.js
  14. 103
      web-screen/client/src/sections/deviceManage/components/addNetworkModal.js
  15. 3
      web-screen/client/src/sections/deviceManage/containers/index.js
  16. 213
      web-screen/client/src/sections/deviceManage/containers/network.js
  17. 5
      web-screen/client/src/sections/deviceManage/nav-item.js
  18. 6
      web-screen/client/src/sections/deviceManage/routes.js
  19. 11
      web-screen/client/src/sections/issueHandle/actions/index.js
  20. 32
      web-screen/client/src/sections/issueHandle/actions/record.js
  21. 429
      web-screen/client/src/sections/issueHandle/components/isuue-handle-mdal.js
  22. 5
      web-screen/client/src/sections/issueHandle/containers/index.js
  23. 268
      web-screen/client/src/sections/issueHandle/containers/patrolRecord.js
  24. 15
      web-screen/client/src/sections/issueHandle/index.js
  25. 21
      web-screen/client/src/sections/issueHandle/nav-item.js
  26. 5
      web-screen/client/src/sections/issueHandle/reducers/index.js
  27. 32
      web-screen/client/src/sections/issueHandle/reducers/record.js
  28. 13
      web-screen/client/src/sections/issueHandle/routes.js
  29. 13
      web-screen/client/src/sections/issueHandle/style.less
  30. 51
      web-screen/client/src/sections/organization/actions/authority.js
  31. 11
      web-screen/client/src/sections/organization/actions/index.js
  32. 113
      web-screen/client/src/sections/organization/actions/user.js
  33. 88
      web-screen/client/src/sections/organization/components/deptModal.js
  34. 74
      web-screen/client/src/sections/organization/components/resetPwd.js
  35. 126
      web-screen/client/src/sections/organization/components/resource.js
  36. 237
      web-screen/client/src/sections/organization/components/userModal.js
  37. 158
      web-screen/client/src/sections/organization/containers/authority.js
  38. 49
      web-screen/client/src/sections/organization/containers/authority.less
  39. 6
      web-screen/client/src/sections/organization/containers/index.js
  40. 355
      web-screen/client/src/sections/organization/containers/user.js
  41. 42
      web-screen/client/src/sections/organization/containers/user.less
  42. 15
      web-screen/client/src/sections/organization/index.js
  43. 22
      web-screen/client/src/sections/organization/nav-item.js
  44. 5
      web-screen/client/src/sections/organization/reducers/index.js
  45. 26
      web-screen/client/src/sections/organization/routes.js
  46. 88
      web-screen/client/src/sections/patrolManage/actions/checkItems.js
  47. 18
      web-screen/client/src/sections/patrolManage/actions/index.js
  48. 81
      web-screen/client/src/sections/patrolManage/actions/plan.js
  49. 17
      web-screen/client/src/sections/patrolManage/actions/record.js
  50. 26
      web-screen/client/src/sections/patrolManage/actions/report.js
  51. 55
      web-screen/client/src/sections/patrolManage/actions/reportConf.js
  52. 48
      web-screen/client/src/sections/patrolManage/actions/template.js
  53. 24
      web-screen/client/src/sections/patrolManage/actions/yujingguanli.js
  54. 281
      web-screen/client/src/sections/patrolManage/components/addReportRulesModal.js
  55. 122
      web-screen/client/src/sections/patrolManage/components/checkItemsModal.js
  56. 263
      web-screen/client/src/sections/patrolManage/components/planModal.js
  57. 122
      web-screen/client/src/sections/patrolManage/components/planTemplateModal.js
  58. 89
      web-screen/client/src/sections/patrolManage/components/xiafagaojin.js
  59. 176
      web-screen/client/src/sections/patrolManage/containers/checkItems.js
  60. 10
      web-screen/client/src/sections/patrolManage/containers/index.js
  61. 192
      web-screen/client/src/sections/patrolManage/containers/patrolPlan.js
  62. 20
      web-screen/client/src/sections/patrolManage/containers/patrolPlan.less
  63. 387
      web-screen/client/src/sections/patrolManage/containers/patrolRecord.js
  64. 378
      web-screen/client/src/sections/patrolManage/containers/patrolReport.js
  65. 136
      web-screen/client/src/sections/patrolManage/containers/patrolTemplate.js
  66. 300
      web-screen/client/src/sections/patrolManage/containers/yujingguanli.js
  67. 15
      web-screen/client/src/sections/patrolManage/index.js
  68. 34
      web-screen/client/src/sections/patrolManage/nav-item.js
  69. 5
      web-screen/client/src/sections/patrolManage/reducers/index.js
  70. 32
      web-screen/client/src/sections/patrolManage/reducers/record.js
  71. 44
      web-screen/client/src/sections/patrolManage/routes.js
  72. 5
      web-screen/client/src/sections/patrolManage/style.less
  73. 6
      web-screen/client/src/sections/projectBinding/actions/index.js
  74. 59
      web-screen/client/src/sections/projectBinding/actions/projectBinding.js
  75. 88
      web-screen/client/src/sections/projectBinding/components/relationModal.js
  76. 5
      web-screen/client/src/sections/projectBinding/containers/index.js
  77. 304
      web-screen/client/src/sections/projectBinding/containers/projectBinding.js
  78. 0
      web-screen/client/src/sections/projectBinding/containers/style.less
  79. 15
      web-screen/client/src/sections/projectBinding/index.js
  80. 13
      web-screen/client/src/sections/projectBinding/nav-item.js
  81. 5
      web-screen/client/src/sections/projectBinding/reducers/index.js
  82. 13
      web-screen/client/src/sections/projectBinding/routes.js
  83. 83
      web-screen/client/src/sections/projectRegime/actions/graph.js
  84. 10
      web-screen/client/src/sections/projectRegime/actions/index.js
  85. 101
      web-screen/client/src/sections/projectRegime/actions/projectSituation.js
  86. 57
      web-screen/client/src/sections/projectRegime/components/pointDeploy/heatmap.js
  87. 114
      web-screen/client/src/sections/projectRegime/components/pointDeploy/station-spot.js
  88. 91
      web-screen/client/src/sections/projectRegime/components/pointDeploy/style.css
  89. 219
      web-screen/client/src/sections/projectRegime/components/pointModel.js
  90. 234
      web-screen/client/src/sections/projectRegime/components/projectAddModel.js
  91. 9
      web-screen/client/src/sections/projectRegime/containers/index.js
  92. 251
      web-screen/client/src/sections/projectRegime/containers/information.js
  93. 30
      web-screen/client/src/sections/projectRegime/containers/information.less
  94. 196
      web-screen/client/src/sections/projectRegime/containers/point.js
  95. 404
      web-screen/client/src/sections/projectRegime/containers/pointDeploy/default.js
  96. 137
      web-screen/client/src/sections/projectRegime/containers/pointDeploy/deploy-style.less
  97. 94
      web-screen/client/src/sections/projectRegime/containers/pointDeploy/upload-img-modal.js
  98. 173
      web-screen/client/src/sections/projectRegime/containers/qrCode.js
  99. 44
      web-screen/client/src/sections/projectRegime/containers/qrCode.less
  100. 15
      web-screen/client/src/sections/projectRegime/index.js

11
web-screen/client/src/app.js

@ -3,15 +3,8 @@
import React, { useEffect } from 'react';
import Layout from './layout';
import Auth from './sections/auth';
import Safetymanage from './sections/safetymanage';
import ProjectRegime from './sections/projectRegime';
import Organization from './sections/organization';
import PatrolManage from './sections/patrolManage';
import IssueHandle from './sections/issueHandle'
import Shouye from './sections/shouye';
import DeviceManage from './sections/deviceManage';
import ProjectBinding from './sections/projectBinding'
import AdvisoryNotice from './sections/advisoryNotice'
import { Func } from '$utils';
const App = props => {
const { projectName } = props
@ -23,7 +16,7 @@ const App = props => {
return (
<Layout
title={projectName}
sections={[Auth, Shouye, ProjectRegime, Safetymanage, Organization, PatrolManage, IssueHandle, DeviceManage,ProjectBinding,AdvisoryNotice]}
sections={[Auth, DeviceManage]}
/>
)

60
web-screen/client/src/sections/advisoryNotice/actions/advisoryNotice.js

@ -1,60 +0,0 @@
'use strict';
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
export function getAdvisoryNotices(query) {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
query,
actionType: 'GET_ADVISORY_NOTICES',
url: `${ApiTable.getAdvisoryNotices}`,
msg: { error: '获取资讯公告失败' },
reducer: { name: 'advisoryNotice'}
})
}
export function addOrUpdateAdvisoryNotice(data) {
return dispatch => basicAction({
type: 'post',
dispatch: dispatch,
data,
actionType: 'ADD_OR_UPDATE_ADVISORY_NOTICE',
url: `${ApiTable.addOrUpdateAdvisoryNotice}`,
msg: { option: data?.id?'编辑资讯公告':'新增资讯公告' },
})
}
export function delAdvisoryNotice(id) {
return dispatch => basicAction({
type: 'delete',
dispatch: dispatch,
actionType: 'DEL_ADVISORY_NOTICE',
url: ApiTable.delAdvisoryNotice.replace('{id}', id),
msg: { option: '删除资讯公告' },
})
}
export function updateAdvisoryNoticeState(id,data) {
return dispatch => basicAction({
type: 'post',
dispatch: dispatch,
data,
actionType: 'UPDATE_ADVISORY_NOTICE_STATE',
url: ApiTable.updateAdvisoryNoticeState.replace('{id}', id),
msg: { option: data?.msg?.includes('发布')?'发布资讯公告':'下架资讯公告' },
})
}
export default{
getAdvisoryNotices,
addOrUpdateAdvisoryNotice,
delAdvisoryNotice,
updateAdvisoryNoticeState
}

6
web-screen/client/src/sections/advisoryNotice/actions/index.js

@ -1,6 +0,0 @@
'use strict';
import advisoryNotice from './advisoryNotice'
export default {
...advisoryNotice
}

108
web-screen/client/src/sections/advisoryNotice/components/addAdvisoryNoticeModal.js

@ -1,108 +0,0 @@
import React, { useRef, useState, useEffect } from 'react'
import { Button, Form } from 'antd'
import { connect } from 'react-redux'
import { InfoCircleOutlined } from '@ant-design/icons'
import { ModalForm, ProFormSelect, ProFormText, ProFormDatePicker, ProFormTextArea,ProForm } from '@ant-design/pro-form'
import moment from 'moment'
import Uploads from '$components/Uploads'
function AddAdvisoryNoticeModal(props) {
const {
title,
triggerRender,
editData = null,
onFinish,
devices,
actions,
dispatch,
disabled,
} = props
const formItemLayout = { labelCol: { span: 6 }, wrapperCol: { span: 16 } }
const initialValues = editData ? { ...editData } : {}
const [form] = Form.useForm()
const formRef = useRef()
return (
<ModalForm
width={500}
formRef={formRef}
title={title || ''}
initialValues={initialValues}
trigger={triggerRender ? triggerRender : <Button type='primary'>{title || ''}</Button>}
layout='horizontal'
grid={true}
{...formItemLayout}
modalProps={{
destroyOnClose: true,
onCancel: () => {},
}}
onFinish={async values => {
let value = {
title: values?.title,
content: values?.content,
id: initialValues ? initialValues.id : null,
attachments:values?.attachments?.length?
values?.attachments[0]?.name ? values?.attachments.map(u => u.storageUrl) : editData?.attachments:[],
}
if(disabled){
return true
}
return onFinish && (await onFinish(value))
// return true;
}}>
<ProFormText
rules={[{ required: true, message: '资讯标题' }]}
placeholder='请输入资讯标题'
name='title'
label='资讯标题'
disabled={disabled ? true : false}
/>
<ProFormTextArea
rules={[{ required: true, message: '咨讯内容' }]}
placeholder='请输入咨讯内容'
name='content'
label='咨讯内容'
disabled={disabled ? true : false}
/>
<div className='ant-col ant-col-xs-24'>
<Form.Item
label='文件:'
name='attachments'
// rules={[{ required: true, message: '请添加附件!' }]}
disabled={disabled ? true : false}>
<Uploads
disabled={disabled ? true : false}
listType='picture-card'
uploadType='project'
maxFilesNum={10}
maxFileSize={10}
isQiniu={true}
// disabled={true}
fileTypes={['png', 'jpg']}
defaultValue={(() => {
let nextV = []
for (let s of editData?.attachments || []) {
if (s) {
nextV.push({
storageUrl: s,
})
}
}
return nextV
})()}
/>
</Form.Item>
</div>
</ModalForm>
)
}
function mapStateToProps(state) {
const { auth, global, device } = state
return {
loading: device.isRequesting,
clientHeight: global.clientHeight,
actions: global.actions,
}
}
export default connect(mapStateToProps)(AddAdvisoryNoticeModal)

216
web-screen/client/src/sections/advisoryNotice/containers/advisoryNotice.js

@ -1,216 +0,0 @@
import React, { useEffect, useState, useRef, useMemo } from 'react'
import { Spin, Popconfirm, message, Button, Input, Select } from 'antd'
import { connect } from 'react-redux'
import ProTable from '@ant-design/pro-table'
import moment from 'moment'
import AddAdvisoryNoticeModal from '../components/addAdvisoryNoticeModal'
function AdvisorNotice(props) {
const { loading, clientHeight, actions, dispatch } = props
const { advisorNotice } = actions
const tableRef = useRef()
const proTableFormRef = useRef()
const [tableParams, setTableParams] = useState({})
const [dataSource, setDataSource] = useState([])
const queryData = () => {
dispatch(advisorNotice.getAdvisoryNotices()).then(res => {
if (res.success) {
const list = res?.payload?.data?.rows
setDataSource(list)
}
})
}
//初始化
useEffect(() => {
queryData()
}, [])
//新增或编辑
const onFinish = async values => {
const dataToSave = { title: values?.title, content: values?.content,attachments:values?.attachments,id: values?.id }
return dispatch(advisorNotice.addOrUpdateAdvisoryNotice(dataToSave)).then(res => {
if (res.success) {
queryData()
// tableRef.current.reload()
return true
} else {
return false
}
})
}
//删除
const handleDelete = id => {
dispatch(advisorNotice.delAdvisoryNotice(id)).then(res => {
if (res.success) {
queryData()
}
})
}
//查询公告(搜索按钮)
const tableDatas = useMemo(() => {
const { title } = tableParams
let rslt = dataSource
rslt = rslt.filter(s => (title ? (s.title ? s.title.includes(title) : false) : true))
return rslt
})
//上架下架处理
const publishHandler=(record)=>{
const msg=record.state===2?'下架':'发布'
const publishTime=record.state===2?moment(record.publishTime).format('YYYY-MM-DD HH:mm:ss'):null
dispatch(advisorNotice.updateAdvisoryNoticeState(record.id,{msg,publishTime})).then(res => {
if (res.success) {
queryData()
}
})
}
const columns = [
{
title: '序号',
dataIndex: 'id',
width: '12%',
render: (text, record, index) => {
return index + 1
},
search: false,
},
{
title: '公告标题',
dataIndex: 'title',
ellipsis: true,
},
{
title: '发布时间',
dataIndex: 'publishTime',
ellipsis: true,
search: false,
render: (text, record, index) => {
return record?.publishTime?moment(record?.publishTime).format('YYYY-MM-DD HH:mm:ss'):'--'
},
},
{
title: '当前状态',
dataIndex: 'state',
ellipsis: true,
search: false,
render: (text, record, index) => {
return record?.state===1?'草稿':record?.state===2?'已发布':'已下架'
},
},
{
title: '操作',
width: 300,
key: 'option',
valueType: 'option',
render: (text, record) => {
const options = []
options.push(
<AddAdvisoryNoticeModal
triggerRender={<a>查看详情</a>}
editData={record}
disabled={true}
title='查看详情'
onFinish={onFinish}
key='lookModel'
/>
)
options.push(
<Popconfirm
key='del'
placement='top'
title={record?.state===2?'确定下架吗?':'确定发布吗?'}
onConfirm={() => publishHandler(record)}
okText='是'
cancelText='否'>
<a>{record?.state===2?'下架':'发布'}</a>
</Popconfirm>
)
record.state ===1||record.state ===3? options.push(
<AddAdvisoryNoticeModal
triggerRender={<a>编辑</a>}
editData={record}
title='编辑资讯'
onFinish={onFinish}
key='editModel'
/>
):''
record.state ===1||record.state ===3?options.push(
<Popconfirm
key='del'
placement='top'
title='是否确认删除资讯?'
onConfirm={() => handleDelete(record.id)}
okText='是'
cancelText='否'>
<a style={{color:'red'}}>删除</a>
</Popconfirm>
):''
return options
},
},
]
return (
<Spin spinning={loading}>
<div id='patrol-record' className='global-main'>
{/* <Spin spinning={loading}> */}
<div style={{ marginBottom: 19 }}>
<div className='top' style={{ marginBottom: 19 }}>
<div className='title'>
<span className='line'></span>
<span className='cn'>咨讯公告</span>
<span className='en'>&nbsp;ADVISORYNOTICE</span>
</div>
<div></div>
</div>
</div>
<AddAdvisoryNoticeModal
triggerRender={<Button type='primary'>新增</Button>}
title='新增资讯'
onFinish={onFinish}
key='addModel'
/>
<ProTable
formRef={proTableFormRef}
rowKey='id'
options={false}
request={async params => {
setTableParams(params)
return {
data: [],
success: true,
}
}}
actionRef={tableRef}
columns={columns}
pagination={{ pageSize: 10, size: 'default', className: 'global-pagination' }}
dataSource={tableDatas || []}
// search={{
// labelWidth: 100,
// }}
// search={{
// optionRender: ({searchText, resetText}, {form}, dom) => [
// <Button type="primary" onClick={searchHandler}>查询</Button>,
// ]
// }}
></ProTable>
{/* </Spin> */}
</div>
</Spin>
)
}
function mapStateToProps(state) {
const { auth, global, advisoryNotice } = state
return {
loading: advisoryNotice.isRequesting,
clientHeight: global.clientHeight,
actions: global.actions,
}
}
export default connect(mapStateToProps)(AdvisorNotice)

5
web-screen/client/src/sections/advisoryNotice/containers/index.js

@ -1,5 +0,0 @@
'use strict';
import AdvisoryNotice from './advisoryNotice'
export { AdvisoryNotice }

0
web-screen/client/src/sections/advisoryNotice/containers/style.less

15
web-screen/client/src/sections/advisoryNotice/index.js

@ -1,15 +0,0 @@
'use strict';
import reducers from './reducers';
import routes from './routes';
import actions from './actions';
import { getNavItem } from './nav-item';
export default {
key: 'advisorNotice',
name: '资讯广告',
reducers: reducers,
routes: routes,
actions: actions,
getNavItem: getNavItem
};

14
web-screen/client/src/sections/advisoryNotice/nav-item.js

@ -1,14 +0,0 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Menu } from 'antd';
import { HomeOutlined } from '@ant-design/icons';
import { Func } from '$utils';
const SubMenu = Menu.SubMenu;
export function getNavItem (user, dispatch) {
return <Menu.Item key="advisoryNotice" icon={<img src='/assets/images/menu/home.svg' style={{ width: 24, height: 24 }} />}>
<Link to="/advisoryNotice">咨讯公告</Link>
</Menu.Item>
}

5
web-screen/client/src/sections/advisoryNotice/reducers/index.js

@ -1,5 +0,0 @@
'use strict';
export default {
}

12
web-screen/client/src/sections/advisoryNotice/routes.js

@ -1,12 +0,0 @@
'use strict';
import { AdvisoryNotice } from './containers';
export default [{
type: 'inner',
route: {
path: '/advisoryNotice',
key: 'advisoryNotice',
breadcrumb: '咨询公告',
component: AdvisoryNotice,
}
}];

3
web-screen/client/src/sections/deviceManage/actions/index.js

@ -1,8 +1,7 @@
'use strict';
import * as device from './device'
import * as network from './network'
export default {
...device,...network
...device,
}

50
web-screen/client/src/sections/deviceManage/actions/network.js

@ -1,50 +0,0 @@
'use strict';
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
export function getNetworks(query) {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
query,
actionType: 'GET_NETWORKS',
url: `${ApiTable.getNetworks}`,
msg: { error: '获取宽带专网失败' },
reducer: { name: 'networks'}
})
}
export function addOrUpdateNetwork(data) {
return dispatch => basicAction({
type: 'post',
dispatch: dispatch,
data,
actionType: 'ADD_OR_UPDATE_NETWORK',
url: `${ApiTable.addOrUpdateNetwork}`,
msg: { option: data?.id?'编辑宽带专网':'新增宽带专网' },
})
}
export function delNetwork(id) {
return dispatch => basicAction({
type: 'delete',
dispatch: dispatch,
actionType: 'DEL_NETWORK',
url: ApiTable.delNetwork.replace('{id}', id),
msg: { option: '删除宽带专网' },
})
}
export default{
getNetworks,
addOrUpdateNetwork,
delNetwork,
}

103
web-screen/client/src/sections/deviceManage/components/addNetworkModal.js

@ -1,103 +0,0 @@
import React, { useRef, useState, useEffect } from 'react'
import { Button, Form } from 'antd'
import { connect } from 'react-redux'
import { InfoCircleOutlined } from '@ant-design/icons'
import { ModalForm, ProFormSelect, ProFormText, ProFormDatePicker, ProFormTextArea,ProForm, ProFormTimePicker } from '@ant-design/pro-form'
import moment from 'moment'
function addNetworkModal(props) {
const {
title,
structureListOpt,
triggerRender,
editData = null,
onFinish,
devices,
actions,
dispatch,
type
} = props
const formItemLayout = { labelCol: { span: 6 }, wrapperCol: { span: 16 } }
const initialValues = editData ? { ...editData } : {}
const [form] = Form.useForm()
const formRef = useRef()
return (
<ModalForm
width={500}
formRef={formRef}
title={title || ''}
initialValues={initialValues}
trigger={triggerRender ? triggerRender : <Button type='primary'>{title || ''}</Button>}
layout='horizontal'
grid={true}
{...formItemLayout}
modalProps={{
destroyOnClose: true,
onCancel: () => {},
}}
onFinish={async values => {
console.log('x111',values)
let value = {
name: values?.name,
type:values?.type,
account:values?.account,
indate: values?.indate,
id: initialValues ? initialValues.id : null,
projectId:values?.projectId
}
return onFinish && (await onFinish(value))
// return true;
}}>
<ProFormText
rules={[{ required: true, message: '请输入专网名称' }]}
placeholder='请输入专网名称'
name='name'
label='专网名称'
/>
<ProFormSelect
rules={[{ required: true, message: '请选择专网类型' }]}
placeholder='请选择专网类型'
options={type?.map(s => {
return { label: s.label, value: s.id }
})}
name='type'
label='专网类型'
/>
<ProFormText
rules={[{ required: true, message: '请输入账号' }]}
placeholder='请输入账号'
name='account'
label='账号'
/>
<ProFormDatePicker
rules={[{ required: true, message: '请输入有效期' }]}
placeholder='请输入有效期'
name='indate'
label='有效期'
/>
<ProFormSelect
showSearch
allowClear
rules={[{ required: true, message: '请选择结构物' }]}
placeholder='请选择结构物'
options={structureListOpt?.map(s => {
return { label: s.label, value: s.id }
})}
name='projectId'
label='关联结构物'
/>
</ModalForm>
)
}
function mapStateToProps(state) {
const { auth, global } = state
return {
clientHeight: global.clientHeight,
actions: global.actions,
}
}
export default connect(mapStateToProps)(addNetworkModal)

3
web-screen/client/src/sections/deviceManage/containers/index.js

@ -1,5 +1,4 @@
'use strict';
import DeviceManage from './deviceManage'
import Network from './network'
export { DeviceManage,Network};
export { DeviceManage};

213
web-screen/client/src/sections/deviceManage/containers/network.js

@ -1,213 +0,0 @@
import React, { useEffect, useState, useRef, useMemo } from 'react'
import { Spin, Popconfirm, message, Button, Input, Select } from 'antd'
import { connect } from 'react-redux'
import ProTable from '@ant-design/pro-table'
import moment from 'moment'
import AddNetworkModal from '../components/addNetworkModal';
const type=[{id:1,label:'外网'},{id:2,label:'内网'}]
function Network(props) {
const { loading, clientHeight, actions, dispatch, } = props
const { deviceManage,projectRegime} = actions
const tableRef = useRef()
const proTableFormRef = useRef()
const [tableParams, setTableParams] = useState({})
const [dataSource, setDataSource] = useState([])
const [structureListOpt, setStructureListOpt] = useState([])//巡检结构物
const queryData = () => {
dispatch(deviceManage.getNetworks()).then(res => {
if (res.success) {
const list = res?.payload?.data?.rows
setDataSource(list)
}
})
}
//初始化
useEffect(() => {
dispatch(projectRegime.getProjectList()).then(res => {
if (res.success) {
const dp = res.payload.data?.rows?.filter(i=>i.type==='管廊')?.map(item => {
return {
label: item?.name,
id: item?.id,
}
})
setStructureListOpt(dp)
}
})
queryData()
}, [])
//新增或编辑
const onFinish = async values => {
const dataToSave = {
name: values?.name,
type:values?.type,
account:values?.account,
indate: values?.indate,
id: values.id ,
projectId:values?.projectId
}
return dispatch(deviceManage.addOrUpdateNetwork(dataToSave)).then(res => {
if (res.success) {
queryData()
// tableRef.current.reload()
return true
} else {
return false
}
})
}
//删除
const handleDelete = id => {
dispatch(deviceManage.delNetwork(id)).then(res => {
if (res.success) {
queryData()
}
})
}
//查询宽带名字(搜索按钮)
const tableDatas = useMemo(() => {
const { name } = tableParams
let rslt = dataSource
rslt = rslt.filter(s => (name ? (s.name ? s.name.includes(name) : false) : true))
return rslt
})
const columns = [
{
title: '专网名称',
dataIndex: 'name',
ellipsis: true,
},
{
title: '专网类型',
dataIndex: 'type',
ellipsis: true,
search: false,
valueEnum: type.reduce((enumObj, { id, label }) => {
enumObj[id] = { text: label };
return enumObj;
}, {}),
},
{
title: '账号',
dataIndex: 'account',
ellipsis: true,
search: false,
},
{
title: '有效期',
dataIndex: 'indate',
ellipsis: true,
search: false,
render: (text, record, index) => {
return record?.indate?moment(record?.indate).format('YYYY-MM-DD'):'--'
},
},
{
title: '关联结构物',
dataIndex: 'projectId',
ellipsis: true,
search: false,
valueEnum: structureListOpt.reduce((enumObj, { id, label }) => {
enumObj[id] = { text: label };
return enumObj;
}, {}),
},
{
title: '操作',
width: 300,
key: 'option',
valueType: 'option',
render: (text, record) => {
const options = []
options
.push( <AddNetworkModal
type={type}
structureListOpt={structureListOpt}
triggerRender={<a>编辑</a>}
editData={record}
title='编辑宽带专网'
onFinish={onFinish}
key='editModel'
/>
)
options.push(
<Popconfirm
key='del'
placement='top'
title='是否确认删除宽带专网?'
onConfirm={() => handleDelete(record.id)}
okText='是'
cancelText='否'>
<a style={{ color: 'red' }}>删除</a>
</Popconfirm>
)
return options
},
},
]
return (
<Spin spinning={loading}>
<div id='patrol-record' className='global-main'>
{/* <Spin spinning={loading}> */}
<div style={{ marginBottom: 19 }}>
<div className='top' style={{ marginBottom: 19 }}>
<div className='title'>
<span className='line'></span>
<span className='cn'>宽带专网</span>
<span className='en'>&nbsp;NETWORK</span>
</div>
<div></div>
</div>
</div>
<AddNetworkModal
type={type}
structureListOpt={structureListOpt}
triggerRender={<Button type='primary'>新增</Button>}
title='新增宽带宽带'
onFinish={onFinish}
key='addModel'
/>
<ProTable
formRef={proTableFormRef}
rowKey='id'
options={false}
request={async params => {
setTableParams(params)
return {
data: [],
success: true,
}
}}
actionRef={tableRef}
columns={columns}
pagination={{ pageSize: 10, size: 'default', className: 'global-pagination' }}
dataSource={tableDatas || []}
></ProTable>
{/* </Spin> */}
</div>
</Spin>
)
}
function mapStateToProps(state) {
const { auth, global, networks } = state
return {
loading: networks.isRequesting,
clientHeight: global.clientHeight,
actions: global.actions,
}
}
export default connect(mapStateToProps)(Network)

5
web-screen/client/src/sections/deviceManage/nav-item.js

@ -12,11 +12,6 @@ export function getNavItem(user, dispatch) {
key="deviceCheck">
<Link to="/deviceManage/deviceCheck">设备查看</Link>
</Menu.Item>
<Menu.Item
// icon={<img src='/assets/images/menu/device.png' style={{ width: 24, height: 24 }} />}
key="network">
<Link to="/deviceManage/network">宽带专网</Link>
</Menu.Item>
</SubMenu>
);
}

6
web-screen/client/src/sections/deviceManage/routes.js

@ -12,12 +12,6 @@ export default [{
key: 'deviceCheck',
component: DeviceManage,
breadcrumb: '设备查看',
},
{
path: '/netWork',
key: 'netWork',
component: Network,
breadcrumb: '宽带专网',
}
]
}

11
web-screen/client/src/sections/issueHandle/actions/index.js

@ -1,11 +0,0 @@
'use strict';
import * as record from './record'
export default {
...record,
}

32
web-screen/client/src/sections/issueHandle/actions/record.js

@ -1,32 +0,0 @@
'use strict';
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
export function addPatrolRecordIssueHandle(params) {
return (dispatch) => basicAction({
type: 'post',
data: params,
dispatch,
actionType: 'ADD_PatrolRecordIssueHandle_REPORT',
url: ApiTable.addPatrolRecordIssueHandle,
msg: {
option: '维修计划新增',
},
});
}
export function modifyPatrolRecordIssueHandle(id, params, msg) {
return (dispatch) => basicAction({
type: 'put',
data: params,
dispatch,
actionType: 'MODIFY_PatrolRecordIssueHandle_REPORT',
url: ApiTable.modifyPatrolRecordIssueHandle.replace('{id}', id),
msg: {
option: msg || '维修计划审批',
},
});
}

429
web-screen/client/src/sections/issueHandle/components/isuue-handle-mdal.js

@ -1,429 +0,0 @@
import React, { useState, useRef } from 'react';
import { Button, Form, Row, Col, Table, Popconfirm, Input, message } from 'antd';
import {
ModalForm,
ProFormText,
ProFormSelect,
ProFormTextArea,
ProFormDatePicker,
ProFormDateRangePicker,
ProFormDependency
} from '@ant-design/pro-form';
import Uploads from '$components/Uploads';
import moment from 'moment';
const FormItem = Form.Item;
//state: 1下发未上报 2已上报待审批 3整改完成 上报结果result: status 0 已上报未审批 1 审批通过 2 审批驳回
export default (props) => {
const { title, triggerRender, editData = null, onFinish, readOnly, structsUsers, user } = props;
const users = structsUsers?.find(s => s.id == editData?.points?.project?.id)?.users?.map(v => { return { value: v.id, label: v.name, ...v } })
const formItemLayout = { labelCol: { span: 7 }, wrapperCol: { span: 16 } };
const formRef = useRef();
const initialValues = editData ? {
...editData,
...editData?.patrolRecordIssueHandles[0],
approvePerson: editData?.patrolRecordIssueHandles[0]?.approvePerson?.name || '',
approveDate: editData?.patrolRecordIssueHandles[0]?.approveDate ? moment(editData?.patrolRecordIssueHandles[0]?.approveDate).format('YYYY-MM-DD HH:mm:ss') : "",
repairPerson: users?.find(s => s.value == editData?.patrolRecordIssueHandles[0]?.repairPerson?.id) ? editData?.patrolRecordIssueHandles[0]?.repairPerson?.id : null,
checkPerson: users?.find(s => s.value == editData?.patrolRecordIssueHandles[0]?.checkPerson?.id) ? editData?.patrolRecordIssueHandles[0]?.checkPerson?.id : null,
} : {};
if (editData?.patrolRecordIssueHandles?.length > 0) {
initialValues.dateRange = [editData?.patrolRecordIssueHandles[0]?.startTime, editData?.patrolRecordIssueHandles[0]?.endTime]
}
const [approve, setApprove] = useState('')
const approveHandle = async (values) => {
onFinish && await onFinish({
msg: approve ? '计划同意' : '计划驳回',
state: approve ? 4 : 3,
approveOpinion: values?.approveOpinion,
approvePerson: user,
approveDate: moment()
}, editData)
}
const renderPlanInfo = () => {
return <>
{/* <Card title={'巡检信息'}> */}
<div className="item-title">{"巡检信息"}</div>
<Form>
<Row>
<Col span={12}>
<Form.Item label="结构物名称:" {...formItemLayout}>
<Input value={editData?.points?.project?.name} readOnly />
</Form.Item>
<Form.Item label="巡检人:" {...formItemLayout}>
<Input value={editData?.points?.user?.name} readOnly />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label="巡检单位:" {...formItemLayout}>
<Input value={editData?.points?.user?.department?.name} readOnly title={222} />
</Form.Item>
<Form.Item label="巡检时间:" {...formItemLayout}>
<Input value={editData?.inspectionTime && moment(editData?.inspectionTime).format('YYYY-MM-DD HH:mm:ss')} readOnly />
</Form.Item>
</Col>
</Row>
</Form>
<div className="item-title">{"问题详情"}</div>
<Row>
<Col span={12}>
<Form.Item label="点位名称:" {...formItemLayout}>
<Input value={editData?.points?.itemData?.name} readOnly />
</Form.Item>
</Col>
</Row>
<Row>
<Col span={24}>
{
editData?.points?.inspectContent && Array.isArray(editData?.points?.inspectContent) &&
editData?.points?.inspectContent?.map(s => {
if (s?.alarm == true) {
return <>
{s?.deviceName && <Col span={12}>
<Form.Item label="设备名称:" {...formItemLayout}>
<Input value={s?.deviceName} readOnly />
</Form.Item>
</Col>}
{
s?.checkItems?.map(k => {
return <Row style={{ marginBottom: 15 }}>
<Col span={12}>
<Form.Item label="检查项:" {...formItemLayout}>
<Input value={k.name} readOnly />
</Form.Item>
<Form.Item label="异常等级:" {...formItemLayout}>
<Input value={k?.level} readOnly />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label="问题描述:" {...formItemLayout}>
<Input value={k?.msgInp} readOnly title={222} />
</Form.Item>
<Form.Item label="现场图片:" {...formItemLayout}>
<Uploads
listType='picture-card'
uploadType='project'
maxFilesNum={1}
maxFileSize={10}
isQiniu={true}
disabled={true}
fileTypes={["png", "jpg"]}
defaultValue={
(() => {
let nextV = []
for (let s of (k.imgs || [])) {
if (s) {
nextV.push({
storageUrl: s
})
}
}
return nextV
})()
}
/>
</Form.Item>
</Col>
</Row>
})
}
</>
}
})
}
</Col>
</Row></>
}
const renderRepairInfo = () => {
return <>
<div className="item-title">{"维修处理"}</div>
<ProFormTextArea
name="repairDesc"
label="维修情况描述:"
disabled={true}
/>
<Form.Item label="完工图片:">
<Uploads
listType='picture-card'
uploadType='project'
maxFilesNum={1}
maxFileSize={10}
isQiniu={true}
disabled={true}
fileTypes={["png", "jpg"]}
defaultValue={
(() => {
let nextV = []
for (let s of (editData?.patrolRecordIssueHandles[0]?.repairImage || [])) {
if (s) {
nextV.push({
storageUrl: s
})
}
}
return nextV
})()
}
/>
</Form.Item>
</>
}
const renderCheckInfo = () => {
return <>
<div className="item-title">{"质检验收"}</div>
<ProFormTextArea
name="checkPerson1"
label="验收人:"
disabled={true}
value={editData?.patrolRecordIssueHandles[0]?.checkPerson?.name}
/>
<ProFormText
name="checkPerson1"
label="成本(元):"
disabled={true}
value={editData?.patrolRecordIssueHandles[0]?.cost}
/>
<Form.Item label="完工图片:">
<Uploads
listType='picture-card'
uploadType='project'
maxFilesNum={1}
maxFileSize={10}
isQiniu={true}
disabled={true}
fileTypes={["png", "jpg"]}
defaultValue={
(() => {
let nextV = []
for (let s of (editData?.patrolRecordIssueHandles[0]?.checkImage || [])) {
if (s) {
nextV.push({
storageUrl: s
})
}
}
return nextV
})()
}
/>
</Form.Item>
<ProFormTextArea
name="checkOpinion"
label="验收意见:"
disabled={true}
/>
<ProFormTextArea
name="checkState"
label="验收结果:"
disabled={true}
value={editData?.patrolRecordIssueHandles[0]?.state == 6 ? '验收通过' : '验收不通过'}
/>
</>
}
return (
<ModalForm
formRef={formRef}
title={title || ''}
initialValues={initialValues}
trigger={
triggerRender ? triggerRender : <Button type="primary" >
{title || ''}
</Button>
}
width={1300}
layout="horizontal"
// grid={true}
{...formItemLayout}
modalProps={{
destroyOnClose: true,
// onCancel: () => { },
bodyStyle: { height: 620, overflowY: 'auto' }
}}
onFinish={async (values) => {
if (editData?.patrolRecordIssueHandles[0]?.state === 2 && title == '审核') {
approveHandle(values)
return true;
} else {
values.repairUnit = values?.repairUnits;
values.startTime = values?.dateRange[0];
values.endTime = values?.dateRange[1];
values.repairPerson = { id: users?.find(s => s.value == values.repairPerson)?.value, name: users?.find(s => s.id == values.repairPerson)?.label }
values.checkPerson = { id: users?.find(s => s.value == values.checkPerson)?.value, name: users?.find(s => s.id == values.checkPerson)?.label }
onFinish && await onFinish(values, editData)
//message.success('提交成功');
return true;
}
}}
submitter={editData?.patrolRecordIssueHandles[0]?.state === 2 && title != '修改计划' && title != '查看详情' ? {
render: (props, defaultDoms) => {
return [
<Button onClick={() => {
setApprove(1)
props.submit();
}} type='primary'>确定</Button>,
<Button onClick={() => {
setApprove(0)
props.submit();
}}>驳回</Button>
];
}
} : (!readOnly)}
>
<div>
{/*问题记录信息*/}
{renderPlanInfo()}
{/*问题处理计划表单*/}
{
((editData?.patrolRecordIssueHandles[0]?.state == 1 && title != '查看详情') || editData?.patrolRecordIssueHandles[0]?.state > 1) &&
<>
<div className="item-title">{"维修计划信息"}</div>
<Row>
<Col span={12}>
{!readOnly ? <ProFormSelect
rules={[{ required: true, message: '请选择维修人' }]}
options={users || []}
disabled={readOnly}
name="repairPerson"
label="维修人"
fieldProps={{
showSearch: true
}}
/> :
<ProFormText
name="repairPerson1"
label="维修人:"
disabled={true}
value={editData?.patrolRecordIssueHandles[0]?.repairPerson?.name}
/>
}
</Col>
<Col span={12}>
<ProFormDependency name={['repairPerson']}>
{({ repairPerson }) => {
const department = users?.find(s => s.id == repairPerson)?.department?.name
return (
<ProFormText
disabled={true}
name="repairUnits"
label="维修单位"
placeholder=""
fieldProps={{
showSearch: true
}}
colProps={{
span: 12,
}}
value={department}
/>
);
}}
</ProFormDependency>
</Col>
<Col span={12}>
<ProFormDateRangePicker
disabled={readOnly}
name="dateRange"
label="计划开始时间~结束时间:"
rules={[{ required: true, message: '请选择计划时间范围' }]}
/>
</Col>
<Col span={12}>
{!readOnly ? <ProFormSelect
rules={[{ required: true, message: '请选择质检人' }]}
options={users || []}
disabled={readOnly}
name="checkPerson"
label="质检人"
fieldProps={{
showSearch: true
}}
/> : <ProFormText
name="checkPerson1"
label="质检人:"
disabled={true}
value={editData?.patrolRecordIssueHandles[0]?.checkPerson?.name}
/>}
</Col>
<Col span={12}>
<ProFormTextArea
name="repairAsk"
label="维修要求:"
disabled={readOnly}
rules={[
{
max: 200, message: '维修要求长度不能大于200个字符'
},
{
whitespace: true, message: '请勿输入空格'
}]}
placeholder=""
/></Col>
{editData?.patrolRecordIssueHandles[0]?.state && editData?.patrolRecordIssueHandles[0]?.state > 3 && <Col span={12}>
<ProFormText
name="approvePerson"
label="制定人:"
disabled={true}
/>
<ProFormText
name="approveDate"
label="制定时间:"
disabled={true}
/>
</Col>}
</Row>
</>
}
{
((editData?.patrolRecordIssueHandles[0]?.state > 2) || title == '审核') &&
<>
<div className="item-title">{"维修计划审批"}</div>
<div>
<ProFormTextArea
name="approveOpinion"
label="审批意见:"
disabled={title != '审核'}
rules={[
{ required: true, message: '请输入审批意见' },
{
max: 200, message: '审批意见长度不能大于200个字符'
},
{
whitespace: true, message: '请勿输入空格'
}]}
placeholder="请输入审批意见"
/>
</div>
</>
}
{(editData?.patrolRecordIssueHandles[0]?.state && editData?.patrolRecordIssueHandles[0]?.state > 4) && renderRepairInfo()}
{(editData?.patrolRecordIssueHandles[0]?.state && editData?.patrolRecordIssueHandles[0]?.state > 5) && renderCheckInfo()}
</div>
</ ModalForm>
);
};

5
web-screen/client/src/sections/issueHandle/containers/index.js

@ -1,5 +0,0 @@
'use strict';
import PatrolReocrd from './patrolRecord';
export { PatrolReocrd };

268
web-screen/client/src/sections/issueHandle/containers/patrolRecord.js

@ -1,268 +0,0 @@
'use strict'
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { Form, Input, Select, Button, Table, Modal, DatePicker, Checkbox, Row, Col, Collapse } from 'antd';
import moment from "moment";
import Uploads from '$components/Uploads';
import IssueHandleModal from '../components/isuue-handle-mdal'
import '../style.less'
import { useFsRequest, ApiTable, Func } from '$utils';
const { Panel } = Collapse;
const ISSUEHANDLE_STATE = [1, 2, 3, 4, 5, 6, 7]
const STATE_TEXT = { 1: '待制定计划', 2: '待审核', 3: '计划驳回', 4: '待维修', 5: '待验收', 6: '验收通过', 7: '验收不通过', }
const PatrolRecord = (props) => {
const { dispatch, actions, user } = props
const { patrolManage, issueHandle } = actions
const [tableList, settableList] = useState([])
const [name, setName] = useState('');
const [curState, setCurState] = useState('全部');
const format = 'YYYY-MM-DD HH:mm:ss'
const times = [moment().subtract(70, 'years').format(format), moment().format(format)]
const [search, setSearch] = useState({ name: null, time: [times[0], times[1]], state: 'null' })
const { data: structsUsers = [] } = useFsRequest({ url: 'structures/users' });
useEffect(() => {
queryData()
}, [])
const queryData = () => {
dispatch(patrolManage.records(`patrolRecord/all/${times[0]}/${times[1]}/true/null`)).then(res => {
if (res.success) {
settableList(name != null ? res.payload.data
?.filter(v => (v.points.itemData.name.indexOf(name) != -1 || v.points.project.name.indexOf(name) != -1))
.filter(x => curState == '全部' || curState == renderOptionText(x?.patrolRecordIssueHandles[0]?.state))
.map(v => ({ ...v, key: v.id })) : res.payload.data?.map(v => ({ ...v, key: v.id })))
}
})
}
const onFinish = async (values, editData) => {
const dataToSave = { ...values };
if (editData?.patrolRecordIssueHandles?.length > 0) {
let msg = '';
if (editData?.patrolRecordIssueHandles[0]?.state == 3) {
dataToSave.state = 2;
msg = '维修计划修改';
}
if (editData?.patrolRecordIssueHandles[0]?.state == 1) {
dataToSave.state = 2;
dataToSave.creator = user;
dataToSave.createTime = moment();
msg = '计划制定';
}
return dispatch(
issueHandle.modifyPatrolRecordIssueHandle(editData?.patrolRecordIssueHandles[0]?.id, dataToSave,
values?.msg || msg),
).then(() => {
queryData();
});
}
let state = ISSUEHANDLE_STATE[1];
return dispatch(issueHandle.addPatrolRecordIssueHandle({
...dataToSave,
state,
patrolRecordId: editData?.id,
creator: user,
createTime: moment()
})).then(() => {
queryData();
});
};
const renderOptionText = (currentState) => {
let text = '待制定计划'
return STATE_TEXT[currentState] || text
}
const columns = [
{
title: '结构物名称',
dataIndex: 'name',
key: 'name',
width: '10%',
showInDetail: true,
render: (text, record, index) => {
return !record.points?.project ? '' : <div>{record.points.project.name}</div>
}
},
{
title: '上报人',
dataIndex: 'type',
key: 'type',
showInDetail: true,
width: '10%',
render: (text, record, index) => {
return !record.points?.user ? '' : <div>{record.points.user.name}</div>
}
},
{
title: '上报时间',
dataIndex: 'time',
key: 'time',
showInDetail: true,
render: (text, record, index) => moment(record.inspectionTime).format('YYYY-MM-DD HH:mm:ss') || '--'
}, {
title: '点位名称',
dataIndex: 'station',
key: 'station',
showInDetail: true,
render: (text, record, index) => record?.points?.itemData?.name
},
{
title: '问题来源',
dataIndex: 'source',
key: 'source',
showInDetail: true,
render: (text, record, index) => record?.patrolPlanId == -1 ? '主动上报' : '巡检上报' //暂定巡检上报 后续会增加平台录入
},
{
title: '严重等级',
dataIndex: 'level',
key: 'level',
showInDetail: true,
render: (text, record, index) => {
const LEVELS_ = ['严重', '中度', '轻微'];
const recordLevels = []
record?.points?.inspectContent ? Object.keys(record?.points?.inspectContent).map(key => {
recordLevels.push(record?.points?.inspectContent[key]?.level)
}) : ''
if (Array.isArray(record?.points?.inspectContent)) {
record?.points?.inspectContent?.map(x => {
x.checkItems?.map(v => {
recordLevels.push(v?.level)
})
})
}
const level = LEVELS_.find(s => recordLevels.find(x => x == s))
return level || '-';
}
},
{
title: '当前状态',
dataIndex: 'state',
key: 'name',
width: '10%',
showInDetail: true,
render: (text, record, index) => {
return !record?.patrolRecordIssueHandles || record?.patrolRecordIssueHandles?.length == 0 ? '待制定计划' :
renderOptionText(record?.patrolRecordIssueHandles[0]?.state)
}
},
{
title: '操作',
dataIndex: 'operation',
key: 'operation',
render: (text, record, index) => {
const options = [];
if (Func.isAuthorized('ZHIDINGJIHUA') && (!record?.patrolRecordIssueHandles || record?.patrolRecordIssueHandles?.length == 0 || record?.patrolRecordIssueHandles[0]?.state == 1)) {
options.push(<IssueHandleModal
structsUsers={structsUsers}
editData={record}
readOnly={false}
key="edit"
title="制定计划"
triggerRender={<a style={{ marginRight: 8 }}>制定计划</a>}
user={user}
onFinish={onFinish} />)
}
if (Func.isAuthorized('ZHIDINGJIHUA') && (record?.patrolRecordIssueHandles[0]?.state == 3 || record?.patrolRecordIssueHandles[0]?.state == 2)) {
options.push(<IssueHandleModal
structsUsers={structsUsers}
editData={record}
readOnly={false}
key="edit"
title="修改计划"
triggerRender={<a style={{ marginRight: 8 }}>修改计划</a>}
user={user}
onFinish={onFinish} />)
}
if (Func.isAuthorized('SHENHE') && record?.patrolRecordIssueHandles[0]?.state == 2) {
options.push(<IssueHandleModal
structsUsers={structsUsers}
editData={record}
readOnly={true}
key="edit"
title="审核"
triggerRender={<a style={{ marginRight: 8 }}>审核</a>}
user={user}
onFinish={onFinish} />)
}
Func.isAuthorized('CHAKANXIANGQING') && options.push(<IssueHandleModal
structsUsers={structsUsers}
editData={record}
readOnly={true}
key="edit"
title="查看详情"
triggerRender={<a>查看详情</a>}
user={user}
onFinish={onFinish} />)
return options;
}
}
]
return (
<div id='patrol-record' className='global-main'>
<div style={{ marginBottom: 20, display: 'flex', justifyContent: 'space-between' }}>
<div className='title'>
<span className='line'></span>
<span className='cn'>问题处理</span>
<span className='en'>&nbsp;PROBLEM HANDLING</span>
</div>
<div>
<Input style={{ width: 240, marginRight: 20 }}
value={name} onChange={e => { setName(e.target.value) }}
placeholder="请输入结构物名称或点位名称" allowClear />
<Select
value={curState}
onChange={e => { setCurState(e) }}
style={{ width: 140, marginRight: 20 }}
options={[
{ value: '全部', label: '全部' },
].concat(ISSUEHANDLE_STATE.map(s => {
return { value: renderOptionText(s), label: renderOptionText(s) }
}))} />
<Button type='primary' onClick={() => { queryData() }}>搜索</Button>
</div>
</div>
<Table
columns={columns}
dataSource={tableList}
pagination={{
showSizeChanger: true,
pageSizeOptions: [10, 20, 50],
className: 'global-pagination',
}}
rowClassName={(record, index) => {
let className = 'global-light-row';
if (index % 2 === 1) className = 'global-dark-row';
return className;
}}
/>
</div>
)
}
function mapStateToProps(state) {
const { auth, global } = state;
return {
user: auth.user,
actions: global.actions,
};
}
export default connect(mapStateToProps)(PatrolRecord);

15
web-screen/client/src/sections/issueHandle/index.js

@ -1,15 +0,0 @@
'use strict';
import reducers from './reducers';
import routes from './routes';
import actions from './actions';
import { getNavItem } from './nav-item';
export default {
key: 'issueHandle',
name: '',
reducers: reducers,
routes: routes,
actions: actions,
getNavItem: getNavItem
};

21
web-screen/client/src/sections/issueHandle/nav-item.js

@ -1,21 +0,0 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Menu } from 'antd';
import { CompressOutlined } from '@ant-design/icons';
import { Func } from '$utils';
const SubMenu = Menu.SubMenu;
export function getNavItem(user, dispatch) {
// if (!Func.isAuthorized("ORG_MANAGE")) {
// return null
// }
return (
(Func.isAuthorized("SHENHE")
|| Func.isAuthorized("ZHIDINGJIHUA")
|| Func.isAuthorized("CHAKANXIANGQING")) &&
<Menu.Item icon={<img src='/assets/images/menu/issue.svg' style={{ width: 24, height: 24 }} />} key="issueHandle">
<Link to="/issueHandle">问题处理</Link>
</Menu.Item>
);
}

5
web-screen/client/src/sections/issueHandle/reducers/index.js

@ -1,5 +0,0 @@
'use strict';
export default {
};

32
web-screen/client/src/sections/issueHandle/reducers/record.js

@ -1,32 +0,0 @@
'use strict';
import * as actionTypes from '../actions/record';
import Immutable from 'immutable';
const initState = {
data: {},
isRequesting: false,
error: null
};
function record(state = initState, action) {
const payload = action.payload;
switch (action.type){
case actionTypes.GET_PATROL_RECORD_LIST:
return Immutable.fromJS(state).set('data',
payload.data).toJS();
case actionTypes.GET_PATROL_RECORD_LIST_SUCCESS:
return Immutable.fromJS(state).merge({
isRequesting: false,
data: payload.data
}).toJS();
case actionTypes.GET_PATROL_RECORD_LIST_ERROR:
return Immutable.fromJS(state).merge({
isRequesting: false,
error: payload.error
}).toJS();
default:
return state;
}
}
export default record;

13
web-screen/client/src/sections/issueHandle/routes.js

@ -1,13 +0,0 @@
'use strict';
import { PatrolReocrd } from './containers';
export default [{
type: 'inner',
route: {
path: '/issueHandle',
key: 'issueHandle',
breadcrumb: '问题处理',
component: PatrolReocrd,
}
}];

13
web-screen/client/src/sections/issueHandle/style.less

@ -1,13 +0,0 @@
.patrol-record-detail-modal {
.ant-collapse>.ant-collapse-item>.ant-collapse-header {
padding: 0
}
}
.item-title {
background-color: #4A93DF;
padding: 10px;
color: #fff;
margin-bottom: 20px;
padding-left: 20px;
}

51
web-screen/client/src/sections/organization/actions/authority.js

@ -1,51 +0,0 @@
'use strict';
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
export function getAuthority(orgId) {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
actionType: 'GET_MEMBERS',
url: `${ApiTable.getEnterprisesMembers.replace('{enterpriseId}', orgId)}`,
msg: { error: '获取用户列表失败' },
reducer: { name: 'members' }
});
}
export function getResource(userId) {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
actionType: 'GET_RESOURCE',
url: `${ApiTable.getResource}`,
msg: { error: '获取权限失败' },
reducer: { name: 'resource' }
});
}
export function getUserResource(userId) {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
actionType: 'GET_USER_RESOURCE',
url: `${ApiTable.getUserResource}?userId=${userId}`,
msg: { error: '获取用户权限失败' },
reducer: { name: 'userResource' }
});
}
export function postUserRes(body) {
return dispatch => basicAction({
type: 'post',
dispatch: dispatch,
actionType: 'UPDATE_USER_RESOURCE',
url: `${ApiTable.postUserRes}`,
data: body,
msg: { success: '更新用户权限' }
});
}
export default {
getAuthority,
getResource,
getUserResource,
postUserRes
}

11
web-screen/client/src/sections/organization/actions/index.js

@ -1,11 +0,0 @@
'use strict';
import * as authority from './authority'
import { getDepMessage, getDepUser, createUser } from './user'
export default {
...authority,
getDepMessage,
getDepUser,
createUser,
}

113
web-screen/client/src/sections/organization/actions/user.js

@ -1,113 +0,0 @@
'use strict';
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
export function getDepMessage() {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
actionType: 'GET_DEPARTMENT_MESSAGE',
url: ApiTable.getDepMessage,
msg: { error: '获取部门信息失败' },
reducer: { name: 'depMessage' }
});
}
//新建部门
export function createDept(data) {
return dispatch => basicAction({
type: 'post',
data,
dispatch: dispatch,
actionType: 'CREATE_DEPT',
url: ApiTable.createDept,
msg: { option: '新建部门' },
});
}
//修改部门
export function updateDept(id, data) {
return dispatch => basicAction({
type: 'put',
data,
dispatch: dispatch,
actionType: 'UPDATE_DEPT',
url: ApiTable.updateDept.replace('{id}', id),
msg: { option: '修改部门' },
});
}
//删除部门
export function delDept(id) {
return dispatch => basicAction({
type: 'del',
dispatch: dispatch,
actionType: 'DEL_DEPT',
url: ApiTable.delDept.replace('{id}', id),
msg: { option: '删除部门' },
});
}
export function getDepUser(depId) {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
actionType: 'GET_DEPARTMENT_USER',
url: ApiTable.getDepUser.replace('{depId}', depId),
msg: { error: '获取部门下用户信息失败' },
reducer: { name: 'depUser' }
});
}
export function createUser(data) {
return dispatch => basicAction({
type: 'post',
data,
dispatch: dispatch,
actionType: 'CREATE_DEPARTMENT_USER',
url: ApiTable.createUser,
msg: { option: '新建用户' },
});
}
export function updateUser(id, data) {
return dispatch => basicAction({
type: 'put',
data,
dispatch: dispatch,
actionType: 'UPDATE_DEPARTMENT_USER',
url: ApiTable.updateUser.replace('{id}', id),
msg: { option: '修改用户' },
});
}
export function delUser(ids) {
return dispatch => basicAction({
type: 'del',
dispatch: dispatch,
actionType: 'DEL_DEPARTMENT_USER',
url: ApiTable.delUser.replace('{ids}', ids),
msg: { option: '删除用户' },
});
}
export function resetPwd(id, data) {
return dispatch => basicAction({
type: 'put',
data,
dispatch: dispatch,
actionType: 'CREATE_DEPARTMENT_USER',
url: ApiTable.resetPwd.replace('{id}', id),
msg: { option: '重置用户密码' },
});
}
export default {
getDepMessage,
getDepUser,
createUser,
updateUser,
delUser,
resetPwd
}

88
web-screen/client/src/sections/organization/components/deptModal.js

@ -1,88 +0,0 @@
import React from 'react';
import { connect } from 'react-redux';
import { ProFormText, ModalForm, ProFormSelect } from '@ant-design/pro-form';
const DeptModal = (props) => {
const { visible, modalType, onVisibleChange, onConfirm, editData, depts } = props
let deptOptions = [], sonArr = [];
depts.map(d => {
deptOptions.push({
value: d.id,
label: d.name
});
d.subordinate.map(ds => {
sonArr.push({
value: ds.id,
label: ds.name
})
})
})
const onFinish = (values) => {
if (onConfirm) {
if (modalType === 'edit') {
values.contract.parentDeptId = values.contract.parentDeptId || null
onConfirm(values)
} else {
onConfirm(values);
}
}
}
const checkName = (rule, value, callback) => {
const list = modalType == 'edit' ? deptOptions.concat(sonArr).filter(g => g.value != editData.id) : deptOptions.concat(sonArr)
if (list.filter(s => s.label == value).length) {
callback('该名称已存在');
} else {
callback();
}
}
return (
<ModalForm
width={400}
title={modalType == 'edit' ? '编辑部门' : '新建部门'}
visible={visible}
onVisibleChange={onVisibleChange}
onFinish={onFinish}
destroyOnClose
initialValues={
modalType == 'edit' ?
{
contract: editData
} :
{
contract: {
enable: true
}
}
}
>
<ProFormText
name={['contract', 'name']}
maxLength={24}
width="md"
label="部门名称"
required
placeholder="请输入部门名称"
rules={[{ required: true, message: '请输入部门名称' }, { validator: checkName }]}
/>
<ProFormSelect
name={['contract', 'dependence']}
label="上级部门"
request={async () => {
let t = modalType === 'edit' ? deptOptions.filter(i => i.value !== editData.id) : deptOptions
return t
}}
disabled={modalType === 'edit' ? editData.subordinate?.length === 0 ? false : true : false}
/>
</ModalForm>
)
}
function mapStateToProps(state) {
return {
};
}
export default connect(mapStateToProps)(DeptModal);

74
web-screen/client/src/sections/organization/components/resetPwd.js

@ -1,74 +0,0 @@
import React, { useRef, useState } from 'react';
import { connect } from 'react-redux';
import { Spin, Card, Modal, TreeSelect } from 'antd';
import ProForm, { ProFormText, ModalForm, ProFormSwitch, ProFormTreeSelect } from '@ant-design/pro-form';
const ResetPwd = (props) => {
const { visible, onVisibleChange, onConfirm } = props;
const formRef = useRef();
const onFinish = (values) => {
if (onConfirm) {
onConfirm(values);
}
}
return (
<Spin spinning={false}>
<ModalForm
title={'重置密码'}
visible={visible}
onVisibleChange={onVisibleChange}
onFinish={onFinish}
formRef={formRef}
destroyOnClose
>
<ProFormText.Password
name={['password']}
width="md"
label="新密码"
required
placeholder="请输入密码"
fieldProps={{
autocomplete: 'new-password'
}}
rules={[
{ required: true, message: '请填写密码' },
{ min: 6, message: '请填写至少6位密码' },
]}
/>
<ProFormText.Password
name={['checkPassword']}
width="md"
label="确认密码"
required
autocomplete='off'
placeholder="请输入密码"
rules={[
{ required: true, message: '请再次填写密码' },
{ min: 6, message: '请填写至少6位密码' },
{
validator: (rule, value, callback) => {
const pwd = formRef.current.getFieldValue('password');
if (!value) {
callback();
}
if (pwd == value) {
callback();
} else {
callback('两次输入的密码不一致');
}
}
}
]}
/>
</ModalForm>
</Spin>
)
}
function mapStateToProps(state) {
return {};
}
export default connect(mapStateToProps)(ResetPwd);

126
web-screen/client/src/sections/organization/components/resource.js

@ -1,126 +0,0 @@
import React, { useEffect } from 'react';
import { Checkbox, Table } from 'antd';
import { useState } from 'react';
const CheckboxGroup = Checkbox.Group;
const Resource = props => {
const { roleData, userRole, userSelected, setResCode, userType } = props;
const [indeterminate, setIndeterminate] = useState({});
const [roleCheck, setRoleCheck] = useState({});//一级权限码
const [parentRoleCheck, setParentRoleCheck] = useState({}); //二级权限码
const roleDatas = roleData.slice(0)
useEffect(() => {
const check = {}
const parentCheck = {}
const initInd = {}
roleData && roleData.map && roleData.map(r => {
let currentInd = false;
let sum = 0;
if (r.resources) {
check[r.code] = []
r.resources.map(child => {
if (userRole.find(code => code.resourceId == child.code)) {
currentInd = true;
sum++;
check[r.code].push(child.code);
}
})
}
parentCheck[r.code] = r.resources.length === sum
initInd[r.code] = parentCheck[r.code] ? false : currentInd
});
setParentRoleCheck(parentCheck)
setRoleCheck(check);
setIndeterminate(initInd);
}, [userRole]);
const setResData = (role) => {
let codes = [];
// Object.keys(partRole).map(r => {
// if (partRole[r]) codes.push(r)
// })
Object.keys(role).map(r => {
if (role[r].length) {
codes.push(r);
}
codes = codes.concat(role[r])
})
setResCode(codes)
}
return (
<Table
bordered
pagination={false}
dataSource={roleDatas}
rowClassName={(record, index) => {
let className = 'global-light-row';
if (index % 2 === 1) className = 'global-dark-row';
return className;
}}
columns={[{
title: '功能',
key: 'name',
dataIndex: 'name',
render: (text, record) => {
const parentCode = record.code
return <Checkbox
indeterminate={indeterminate[parentCode]}
onChange={(e) => {
const currentParCheck = JSON.parse(JSON.stringify(parentRoleCheck));
currentParCheck[parentCode] = e.target.checked;
const currentCode = JSON.parse(JSON.stringify(roleCheck));
currentCode[parentCode] = e.target.checked ? roleData.find(r => r.code == parentCode).resources.map(r => r.code) : []
const currentInd = JSON.parse(JSON.stringify(indeterminate));
currentInd[parentCode] = false;
setParentRoleCheck(currentParCheck);
setRoleCheck(currentCode);
setIndeterminate(currentInd);
setResData(currentCode)
}}
checked={parentRoleCheck[parentCode] || false}
disabled={userSelected === "SuperAdmin" || userType === 4}
options={''}
>
{text}
</Checkbox>
}
}, {
title: '列表',
key: 'resources',
dataIndex: 'resources',
render: (text, record) => {
let data = [];
console.log()
text.map(s => { s.name !== "整治汇总编辑" ? data.push({ label: s.name, value: s.code }) : '' })
let parentCode = record.code;
return <CheckboxGroup
disabled={userSelected === "SuperAdmin" || userType === 4}
options={data}
value={roleCheck[parentCode] || []}
onChange={value => {
const checkArr = JSON.parse(JSON.stringify(roleCheck));
const parentCheck = JSON.parse(JSON.stringify(parentRoleCheck));
const ind = JSON.parse(JSON.stringify(indeterminate));
const currentCode = roleData.find(r => r.code == parentCode) || {}
checkArr[parentCode] = value;
ind[parentCode] = !!value.length && value.length < currentCode.resources.length
parentCheck[parentCode] = value.length === currentCode.resources.length
setRoleCheck(checkArr);
setIndeterminate(ind);
setParentRoleCheck(parentCheck);
setResData(checkArr)
}}
/>
}
}]}
></Table >
)
}
export default Resource

237
web-screen/client/src/sections/organization/components/userModal.js

@ -1,237 +0,0 @@
import React from 'react';
import { connect } from 'react-redux';
import { Spin, Card, Modal, TreeSelect, message } from 'antd';
import ProForm, { ProFormText, ModalForm, ProFormSwitch, ProFormTreeSelect, ProFormSelect } from '@ant-design/pro-form';
const UserModal = (props) => {
const { visible, modalType, depData, onVisibleChange, onConfirm, editData, tableList } = props
const reg_tel = /^1([358][0-9]|4[579]|66|7[0135678]|9[89])[0-9]{8}$/;
const onFinish = (values) => {
if (onConfirm) {
onConfirm(values);
}
}
const mobile = (value) => {
if (reg_tel.test(value)) {
return
}
return message('请输入姓名')
}
return (
<Spin spinning={false}>
<ModalForm
modalProps={{
className: "global-modal-form",
}}
layout="horizontal"
grid={true}
width={800}
title={modalType == 'edit' ? '编辑用户' : '新建用户'}
visible={visible}
onVisibleChange={onVisibleChange}
onFinish={onFinish}
destroyOnClose
initialValues={
modalType == 'edit' ?
{
contract: editData
} :
{
contract: {
enable: true,
role: '巡检人员'
},
}
}
>
<ProForm.Group>
<ProFormText
name={['contract', 'name']}
colProps={{ md: 12, xl: 12 }}
maxLength={24}
label="姓名"
required
placeholder="请输入姓名"
rules={[{ required: true, message: '请输入姓名' }]}
bordered={false}
/>
<ProFormText
name={['contract', 'phone']}
colProps={{ md: 12, xl: 12 }}
label="用户名(手机号)"
required
fieldProps={{
maxLength: 11,
}}
getValueFromEvent={(event) => {
return event.target.value.replace(/\D/g, '')
}}
placeholder="请输入用户名(手机号)"
rules={[
{ required: true, valueType: Number, max: 11 }, { pattern: /^1(3|4|5|6|7|8|9)\d{9}$/, message: "请输入正确的手机号" }
]}
/>
</ProForm.Group>
<ProForm.Group>
<ProFormTreeSelect
name={['contract', 'departmentId']}
placeholder="请选择所属部门"
colProps={{ md: 12, xl: 12 }}
label="所属部门"
required
fieldNames={{
title: 'name',
key: 'id',
children: 'subordinate'
}}
onSelect={(selectedKeys, { selected, selectedNodes }) => {
if (selected) {
setDepSelectedKeys(selectedKeys)
setDepSelected(selectedNodes[0].name || "")
dispatch(getDepUser(selectedKeys[0]))
}
}}
fieldProps={{
fieldNames: {
label: 'title',
},
treeDefaultExpandAll: false,
}}
rules={[{ required: true, message: '请选择所属部门' }]}
request={async () => {
console.log(depData);
return depData
}}
expandedKeys={["title"]}
/>
< ProFormText
name={['contract', 'post']}
colProps={{ md: 12, xl: 12 }}
label="职位"
// required
placeholder="请输入职位"
/>
</ProForm.Group>
<ProForm.Group>
{/* <ProFormTreeSelect
name={['contract', 'structure']}
placeholder="请选择结构物"
width="md"
mode="multiple"
label="关注结构物"
required
// fieldNames={{
// title: 'name',
// key: 'id',
// children: 'subordinate'
// }}
onSelect={(selectedKeys, { selected, selectedNodes }) => {
}}
fieldProps={{
mode: 'multiple',
fieldNames: {
label: 'title',
},
treeDefaultExpandAll: false,
}}
rules={[{ required: true, message: '请选择结构物' }]}
request={async () => {
console.log(tableList);
const opts = tableList?.map(i=>({title:i.name,value:i.id}))
return opts
}}
expandedKeys={["title"]}
/> */}
<ProFormSelect
colProps={{ md: 12, xl: 12 }}
label="关注结构物"
name={['contract', 'structure']}
mode="multiple"
// fieldProps={{//这里使用了select的onChange方法,必须使用这样的写法来进行调用onChange方法
// onChange:(val) => handleChange(val),
// }}
request={async () => {
console.log(tableList);
const opts = tableList?.map(i => ({ label: i.name, value: i.id }))
return opts
}}
placeholder="请选择结构物"
rules={[{ required: true, message: '结构物不能为空' }]}
/>
<ProFormText
name={['contract', 'email']}
colProps={{ md: 12, xl: 12 }}
label="邮箱"
// required
placeholder="请输入邮箱"
rules={[
// { required: true, message: '请输入邮箱' },
{ type: 'email', message: '请输入正确格式的邮箱' },
]}
/>
</ProForm.Group>
<ProForm.Group>
{modalType == 'edit' ? null : <ProFormText.Password
name={['contract', 'password']}
colProps={{ md: 12, xl: 12 }}
label="密码"
required
placeholder="请输入密码"
fieldProps={{
autocomplete: 'new-password'
}}
rules={[
{ required: true, message: '请填写密码' },
{ min: 6, message: '请填写至少6位密码' },
]}
/>}
<ProFormSwitch
name={['contract', 'enable']}
colProps={{ md: 12, xl: 12 }}
label="是否启用"
placeholder="请选择"
// defaultChecked
valuePropName="checked"
/>
</ProForm.Group>
<ProFormSelect
name={['contract', 'role']}
colProps={{ md: 12, xl: 12 }}
label="角色"
placeholder="请选择角色"
options={[{ label: '巡检人员', value: '巡检人员' }, { label: '管理人员', value: '管理人员' }]}
rules={[
{ required: true, message: '请选择角色' },
]}
/>
</ModalForm>
</Spin>
)
}
function mapStateToProps(state) {
const { depMessage } = state;
const pakData = (dep) => {
// console.log(dep);
return dep.map((d) => {
return {
title: d.name,
value: d.id,
// key: d.id,
children: pakData(d.subordinate)
}
})
}
let depData = pakData(depMessage.data || [])
return {
loading: depMessage.isRequesting,
depData,
};
}
export default connect(mapStateToProps)(UserModal);

158
web-screen/client/src/sections/organization/containers/authority.js

@ -1,158 +0,0 @@
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { Spin, Row, Col, Card, Button, Tree, Empty, Divider } from 'antd';
import { getDepMessage, getDepUser } from '../actions/user';
import { getResource, getUserResource, postUserRes } from '../actions/authority';
import Resource from '../components/resource';
import './authority.less';
const Authority = (props) => {
const { dispatch, loading, depMessage, depUser, resource, userResource, clientHeight } = props
const [depSelectedKeys, setDepSelectedKeys] = useState([])
const [userSelectedKeys, setUserSelectedKeys] = useState([])
const [depSelected, setDepSelected] = useState()
const [userSelected, setUserSelected] = useState()
const [resCode, setResCode] = useState({})
const [useName, setUseName] = useState()// 选中名字
const [userType, setUserType] = useState()
useEffect(() => {
dispatch(getResource())
if (!(depMessage && depMessage.length)) {
dispatch(getDepMessage())
}
}, [])
useEffect(() => {
if (depMessage.length) {
setDepSelectedKeys([depMessage[0].id])
setDepSelected([depMessage[0].name])
dispatch(getDepUser(depMessage[0].id))
}
}, [depMessage])
useEffect(() => {
if (depUser.length) {
setUserSelectedKeys([depUser[0].id])
setUserSelected(depUser[0].username)
dispatch(getUserResource(depUser[0].id))
setUseName(depUser[0].name)
} else {
setUseName('')
}
}, [depUser])
const handleSave = () => {
dispatch(postUserRes({ userId: userSelectedKeys[0], resCode: resCode })).then(res => {
if (res.success) {
dispatch(getUserResource(userSelectedKeys[0]))
}
})
}
return (
<div className='main'>
<Spin spinning={loading}>
<div>
<div className='title'>
<span className='line'></span>
<span className='cn'>权限功能</span>
<span className='en'>&nbsp;PERMISSION FUNCTION</span>
</div>
<div className='tree-box'>
{
depMessage.length ?
<Tree
style={{ width: 272 }}
height={195}
defaultExpandedKeys={[depMessage[0].id]}
selectedKeys={depSelectedKeys}
onSelect={(selectedKeys, { selected, selectedNodes, node }) => {
setUserType(selectedNodes[0].type)
if (selected) {
setDepSelectedKeys(selectedKeys)
setDepSelected(selectedNodes[0].name || "")
dispatch(getDepUser(selectedKeys[0]))
}
}}
treeData={depMessage}
fieldNames={{
title: 'name',
key: 'id',
children: 'subordinate'
}}
/> : ''
}
<div className='user-list'>
<div className='list-title'>
{(depSelected ? `${depSelected}` : "") + '用户列表'}
</div>
{
depUser.length ?
<Tree
// style={{ width: 272 }}
height={168}
defaultSelectedKeys={[depUser[0].id]}
selectedKeys={userSelectedKeys}
onSelect={(selectedKeys, { selected, selectedNodes, node, event }) => {
const name = node.name
setUseName(name)
if (selected) {
setUserSelectedKeys(selectedKeys)
setUserSelected(selectedNodes[0].username || '')
dispatch(getUserResource(selectedKeys[0]))
}
}}
treeData={depUser}
fieldNames={{
title: 'name',
key: 'id'
}}
/> : <Empty />
}
</div>
</div>
</div>
<Divider />
<div className='list-title'>
{`${useName || ''}】 功能范围`}
</div>
{depUser.length ?
<Card bordered={false} bodyStyle={{ padding: 8, paddingTop: 24 }}>
<Resource
userSelected={userSelected}
roleData={resource}
userRole={userResource}
setResCode={setResCode}
userType={userType}
/>
<Row type="flex" justify="center" style={{ marginBottom: 16, marginTop: 16, textAlign: 'center' }}>
<Col span="24">
<Button
disabled={userSelected === "SuperAdmin" || userType === 4}
onClick={handleSave}
style={{ width: '60%' }}
type='primary'>保存修改</Button>
</Col></Row>
</Card>
: <Empty />
}
</Spin>
</div>
)
}
function mapStateToProps(state) {
const { userResource, resource, depMessage, depUser, global } = state;
return {
clientHeight: global.clientHeight,
loading: depMessage.isRequesting || depUser.isRequesting || resource.isRequesting,
userResource: userResource.data || [],
resource: resource.data || [],
depMessage: depMessage.data || [],
depUser: depUser.data || []
};
}
export default connect(mapStateToProps)(Authority);

49
web-screen/client/src/sections/organization/containers/authority.less

@ -1,49 +0,0 @@
.main {
width: 100%;
background: #fff;
padding: 10px 16px;
.title {
display: inline-block;
.line {
display: inline-block;
width: 3px;
height: 20px;
background: #006BE3;
}
.cn {
font-family: YouSheBiaoTiHei;
font-size: 24px;
color: #101531;
margin-left: 11px;
}
.en {
font-family: D-DINExp-Italic;
font-weight: Italic;
font-size: 12px;
color: #969799;
}
}
.tree-box {
display: flex;
width: 100%;
.user-list {
display: flex;
flex-direction: column;
margin-left: 100px;
}
}
.list-title {
font-family: PingFangSC-Medium;
font-weight: 600;
font-size: 16px;
color: #000000d9;
margin-left: 15px;
}
}

6
web-screen/client/src/sections/organization/containers/index.js

@ -1,6 +0,0 @@
'use strict';
import Authority from './authority';
import UserManage from './user';
export { Authority, UserManage };

355
web-screen/client/src/sections/organization/containers/user.js

@ -1,355 +0,0 @@
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { FormOutlined, DeleteOutlined } from '@ant-design/icons';
import { Spin, Tooltip, Button, Popconfirm, Row, Col, Tree, Card, Switch } from 'antd';
import ProTable from '@ant-design/pro-table';
import { getDepMessage, getDepUser, createUser, updateUser, delUser, resetPwd, createDept, updateDept, delDept } from '../actions/user';
import UserModal from '../components/userModal';
import ResetPwd from '../components/resetPwd';
import DeptModal from '../components/deptModal';
import './user.less';
const TreeNode = Tree.TreeNode;
const UserManage = (props) => {
const user = JSON.parse(sessionStorage.getItem('user'));
const [tableList, settableList] = useState([])
const { dispatch, loading, depMessage, depUser, clientHeight, actions } = props;
// 部门
const [deptModalVisible, setDeptModalVisible] = useState(false);
const [deptModalType, setDeptModalType] = useState();
const [deptModalRecord, setDeptModalRecord] = useState();
const { projectRegime } = actions
// 成员
const [modalVisible, setModalVisible] = useState(false);
const [modalType, setModalType] = useState();
const [modalRecord, setModalRecord] = useState();
const [pwdModalVisible, setPwdModalVisible] = useState(false);
const [depSelectedKeys, setDepSelectedKeys] = useState([])
const [rowSelected, setRowSelected] = useState([])
useEffect(() => {
dispatch(getDepMessage())
projectList()
}, [])
const projectList = (obj) => {
dispatch(projectRegime.getProjectList()).then(res => {
// console.log(res)
if (res.success) {
settableList(res.payload.data?.rows)
// setLimits(res.payload.data?.count)
}
})
}
useEffect(() => {
if (depMessage.length) {
setDepSelectedKeys([depMessage[0].id])
dispatch(getDepUser(depMessage[0].id))
}
}, [depMessage])
const columns = [
{
title: '姓名',
dataIndex: 'name',
}, {
title: '用户名(手机号)',
dataIndex: 'username',
},
{
title: '职位',
dataIndex: 'post',
}, {
title: '邮箱',
dataIndex: 'email',
}, {
title: '启用状态',
dataIndex: 'enable',
render: (_, r) => {
return <Switch checkedChildren="启用" unCheckedChildren="禁用" disabled defaultChecked={r.enable} />
}
}, {
title: '操作',
dataIndex: 'action',
render: (dom, record) => {
return record.username == 'SuperAdmin' ? '' : [
<Button type="link" onClick={() => { openModal('edit', record) }}>编辑</Button>,
<Popconfirm
title="确认删除?"
onConfirm={() => {
delUsers([record.id])
}}
>
<Button type="link">删除</Button>
</Popconfirm>,
<Button
type="link"
onClick={() => {
setModalRecord(record);
setPwdModalVisible(true);
}}
>重置密码</Button>
]
},
},
];
//弹窗确认
const onConfirm = (values) => {
if (modalType == 'edit') {
dispatch(updateUser(modalRecord.id, values.contract)).then(res => {
if (res.success) {
setModalVisible(false);
dispatch(getDepUser(depSelectedKeys[0]));
}
});
} else {
dispatch(createUser(values.contract)).then(res => {
if (res.success) {
setModalVisible(false);
dispatch(getDepUser(depSelectedKeys[0]));
}
});
}
}
//打开弹窗
const openModal = (type, record) => {
setModalVisible(true);
setModalType(type);
if (type == 'edit') {
setModalRecord(record);
} else {
setModalRecord(null);
}
}
//删除用户
const delUsers = (ids, type) => {
dispatch(delUser(ids)).then(res => {
dispatch(getDepUser(depSelectedKeys[0]));
if (type == 'batch') {
setRowSelected([]);
}
});
}
//重置密码
const onPwdConfirm = (values) => {
dispatch(resetPwd(modalRecord.id, { password: values.password })).then(res => {
if (res.success) {
setPwdModalVisible(false);
dispatch(getDepUser(depSelectedKeys[0]));
}
});
}
const openDeptModal = (type, record) => {
console.log(type, record, 'type, record')
setDeptModalVisible(true);
setDeptModalType(type);
if (type === 'edit') {
setDeptModalRecord(record);
} else {
setDeptModalRecord(null);
}
}
const onDeptConfirm = (values) => {
if (deptModalType === 'edit') {
dispatch(updateDept(deptModalRecord.id, values.contract)).then(res => {
if (res.success) {
setDeptModalVisible(false);
dispatch(getDepMessage())
}
});
} else {
dispatch(createDept(values.contract)).then(res => {
if (res.success) {
setDeptModalVisible(false);
dispatch(getDepMessage())
}
});
}
}
const delDepartment = (id) => {
dispatch(delDept(id)).then(res => {
if (res.success) {
dispatch(getDepMessage())
}
});
}
const renderTree = (item, id) => {
// let cannotDel = item.users.length || item.subordinate?.filter(is => is.users.length).length;//自己下面有成员 或者下级部门下有成员 不能删除
return <div style={{ display: 'flex', width: '10vw', justifyContent: 'space-between' }}>
<Tooltip title={item.name}>
<div style={{ width: '80%', textOverflow: 'ellipsis', whiteSpace: 'nowrap', overflow: 'hidden' }}>{item.name}</div>
</Tooltip>
<div style={{ width: '20%' }} >
{
depSelectedKeys == id && user.username === "SuperAdmin" ?
<>
<FormOutlined onClick={() => {
setDeptModalRecord(item)
setDeptModalVisible(true)
setDeptModalType('edit')
}} />
{
<Popconfirm title='是否确认删除?' onConfirm={() => { delDepartment(id) }}>
<DeleteOutlined style={{ marginLeft: 5 }} />
</Popconfirm>
}
</> : null
}
</div>
</div>
}
return (<>
<Spin spinning={loading} style={{ height: clientHeight }}>
<div className='dep-box'>
<div className='top'>
<div className='title'>
<span className='line'></span>
<span className='cn'>部门</span>
<span className='en'>&nbsp;DEPARTMENT</span>
</div>
{
user.username === "SuperAdmin" && <Button
type="primary"
key="primary"
onClick={() => openDeptModal('create')}
>新建部门</Button>
}
</div>
{
depMessage.length ?
<Tree
style={{ width: 272 }}
height={150}
defaultExpandedKeys={[depMessage[0].id]}
selectedKeys={depSelectedKeys}
onSelect={(selectedKeys, e) => {
if (e.selected) {
setDepSelectedKeys(selectedKeys)
dispatch(getDepUser(selectedKeys[0]))
}
}}
// treeData={depMessage}
// fieldNames={{
// title: 'name',
// key: 'id',
// children: 'subordinate'
// }}
>
{
depMessage.map((s, index) => {
return <TreeNode title={renderTree(s, s.id)} key={s.id} >
{
s.subordinate.map(k => {
return <TreeNode title={renderTree(k, k.id)} key={k.id} onMouseOver={() => { setIShowIcon(k.id) }} onMouseOut={() => { setIShowIcon(null) }}>
</TreeNode>
})
}
</TreeNode>
})
}
</Tree> : ''
}
</div>
<div className='user-box'>
<div className='top' style={{ marginBottom: 19 }}>
<div className='title'>
<span className='line'></span>
<span className='cn'>用户</span>
<span className='en'>&nbsp;USER</span>
</div>
<div>
<Button
type="primary"
key="primary"
style={{ marginRight: 10 }}
onClick={() => openModal('create')}
>新建用户</Button>
<Button style={{ marginRight: 10 }} onClick={() => { dispatch(getDepUser(depSelectedKeys[0])); }}>刷新</Button>
<Popconfirm title="确认删除?" onConfirm={() => { delUsers(rowSelected, 'batch') }}>
<Button>批量删除</Button>
</Popconfirm>
</div>
</div>
<ProTable
columns={columns}
dataSource={depUser}
style={{ width: "100% ", height: clientHeight - 371, overflow: "auto" }}
rowSelection={{
selectedRowKeys: rowSelected,
onChange: (selectedRowKeys) => {
setRowSelected(selectedRowKeys);
},
getCheckboxProps: (record) => {
return {
disabled: record.username === 'SuperAdmin',
}
},
}}
options={false}
search={false}
rowKey="id"
rowClassName={(record, index) => {
let className = 'global-light-row';
if (index % 2 === 1) className = 'global-dark-row';
return className;
}}
pagination={{ size: 'default', className: 'global-pagination' }}
/>
</div>
{
deptModalVisible ?
<DeptModal
visible={deptModalVisible}
onVisibleChange={setDeptModalVisible}
modalType={deptModalType}
onConfirm={onDeptConfirm}
editData={deptModalRecord}
depts={depMessage}
/>
: ''
}
{
depMessage.length && modalVisible ?
<UserModal
visible={modalVisible}
onVisibleChange={setModalVisible}
modalType={modalType}
onConfirm={onConfirm}
editData={{ ...modalRecord, structure: modalRecord?.structure || [] }}
tableList={tableList}
/>
: ''
}
{pwdModalVisible ? <ResetPwd visible={pwdModalVisible}
onVisibleChange={setPwdModalVisible}
onConfirm={onPwdConfirm} /> : ''}
</Spin>
</>)
}
function mapStateToProps(state) {
const { depMessage, depUser, global } = state;
return {
clientHeight: global.clientHeight,
loading: depMessage.isRequesting,
depMessage: depMessage.data || [],
depUser: depUser.data || [],
actions: global.actions
};
}
export default connect(mapStateToProps)(UserManage);

42
web-screen/client/src/sections/organization/containers/user.less

@ -1,42 +0,0 @@
.dep-box {
height: 213px;
background: #fff;
padding: 10px 16px;
margin-bottom: 20px;
}
.user-box {
background: #fff;
padding: 10px 16px;
}
.top {
display: flex;
justify-content: space-between;
.title {
background-color: #fff;
display: inline-block;
.line {
display: inline-block;
width: 3px;
height: 20px;
background: #006BE3;
}
.cn {
font-family: YouSheBiaoTiHei;
font-size: 24px;
color: #101531;
margin-left: 11px;
}
.en {
font-family: D-DINExp-Italic;
font-weight: Italic;
font-size: 12px;
color: #969799;
}
}
}

15
web-screen/client/src/sections/organization/index.js

@ -1,15 +0,0 @@
'use strict';
import reducers from './reducers';
import routes from './routes';
import actions from './actions';
import { getNavItem } from './nav-item';
export default {
key: 'organization',
name: '',
reducers: reducers,
routes: routes,
actions: actions,
getNavItem: getNavItem
};

22
web-screen/client/src/sections/organization/nav-item.js

@ -1,22 +0,0 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Menu } from 'antd';
import { FormatPainterOutlined } from '@ant-design/icons';
import { Func } from '$utils';
const SubMenu = Menu.SubMenu;
export function getNavItem(user, dispatch) {
// if (!Func.isAuthorized("ORG_MANAGE")) {
// return null
// }
return (
Func.isAuthorized('ORG_MANAGE') && <SubMenu key="organization" icon={<img src='/assets/images/menu/org.svg' style={{ width: 24, height: 24 }} />} title={'组织管理'}>
{Func.isAuthorized('USER_CONFIG') && <Menu.Item key="userManage">
<Link to="/organization/user">部门成员</Link>
</Menu.Item>}
{Func.isAuthorized('AUTH_CONFIG') && <Menu.Item key="authority">
<Link to="/organization/authority">权限配置</Link>
</Menu.Item>}
</SubMenu>
);
}

5
web-screen/client/src/sections/organization/reducers/index.js

@ -1,5 +0,0 @@
'use strict';
export default {
};

26
web-screen/client/src/sections/organization/routes.js

@ -1,26 +0,0 @@
'use strict';
import { UserManage, Authority } from './containers';
export default [{
type: 'inner',
route: {
path: '/organization',
key: 'organization',
breadcrumb: '组织管理',
menuSelectKeys: ['userManage'],
menuOpenKeys: ['organization'],
childRoutes: [{
path: '/user',
key: 'userManage',
menuSelectKeys: ['userManage'],
component: UserManage,
breadcrumb: '部门成员',
}, {
path: '/authority',
key: 'authority',
component: Authority,
menuSelectKeys: ['authority'],
breadcrumb: '权限配置',
}]
}
}];

88
web-screen/client/src/sections/patrolManage/actions/checkItems.js

@ -1,88 +0,0 @@
'use strict';
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
export function getCheckItemsGroup() {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
actionType: 'GET_CHECK_ITEMS_GROUP',
url: ApiTable.checkItemsGroup,
msg: { error: '获取检查项分组失败' },
reducer:{name:'checkItemsGroup'}
});
}
export function createCheckItemsGroup(data) {
return dispatch => basicAction({
type: 'post',
data,
dispatch: dispatch,
actionType: 'CREATE_CHECK_ITEMS_GROUP',
url: ApiTable.checkItemsGroup,
msg: { option: '创建检查项分组' },
});
}
export function delCheckItemsGroup(id) {
return dispatch => basicAction({
type: 'del',
dispatch: dispatch,
actionType: 'DEL_CHECK_ITEMS_GROUP',
url: ApiTable.delCheckItemsGroup.replace('{id}', id),
msg: { option: '删除检查项分组' },
});
}
export function getCheckItems(query) {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
query: query,
actionType: 'GET_CHECK_ITEMS',
url: ApiTable.checkItems,
msg: { error: '获取检查项失败' }
});
}
export function createCheckItems(data) {
return dispatch => basicAction({
type: 'post',
data,
dispatch: dispatch,
actionType: 'CREATE_CHECK_ITEMS',
url: ApiTable.checkItems,
msg: { option: '新建检查项' },
});
}
export function updateCheckItems(id, data) {
return dispatch => basicAction({
type: 'put',
data,
dispatch: dispatch,
actionType: 'UPDATE_CHECK_ITEMS',
url: ApiTable.updateCheckItems.replace('{id}', id),
msg: { option: '修改检查项' },
});
}
export function delCheckItems(ids) {
return dispatch => basicAction({
type: 'del',
dispatch: dispatch,
actionType: 'DEL_CHECK_ITEMS',
url: ApiTable.delCheckItems.replace('{ids}', ids),
msg: { option: '删除检查项' },
});
}
export default {
getCheckItemsGroup,
createCheckItemsGroup,
getCheckItems,
createCheckItems,
updateCheckItems,
delCheckItems,
}

18
web-screen/client/src/sections/patrolManage/actions/index.js

@ -1,18 +0,0 @@
'use strict';
import * as plan from './plan'
import * as record from './record'
import * as report from './report'
import * as template from './template'
import * as checkItems from './checkItems'
import * as yujingguanli from './yujingguanli'
import * as reportConf from './reportConf'
export default {
...plan,
...record,
...report,
...template,
...checkItems,
...yujingguanli,
...reportConf
}

81
web-screen/client/src/sections/patrolManage/actions/plan.js

@ -1,81 +0,0 @@
'use strict';
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
export function getPatrolPlan(query) {
return dispatch => basicAction({
type: 'get',
query,
dispatch: dispatch,
actionType: 'GET_PATROL_PLAN',
url: ApiTable.patrolPlan,
msg: { error: '获取巡检计划失败' },
});
}
export function createPatrolPlan(data) {
return dispatch => basicAction({
type: 'post',
data,
dispatch: dispatch,
actionType: 'CREATE_PATROL_PLAN',
url: ApiTable.patrolPlan,
msg: { error: '新增巡检计划失败' },
});
}
export function delPatrolPlan(id) {
return dispatch => basicAction({
type: 'del',
dispatch: dispatch,
actionType: 'DEL_PATROL_PLAN',
url: ApiTable.delPatrolPlan.replace('{id}', id),
msg: { error: '删除巡检计划失败' },
});
}
export function updatePatrolPlan(data) {
return dispatch => basicAction({
type: 'put',
data,
dispatch: dispatch,
actionType: 'UPDATE_PATROL_PLAN',
url: ApiTable.patrolPlan,
msg: { error: '修改巡检计划失败' },
});
}
export function getUserList() {
return dispatch => basicAction({
type: 'get',
dispatch: dispatch,
actionType: 'GET_USER_LIST',
url: ApiTable.getDepUser.replace('{depId}', null),
msg: { error: '获取人员列表失败' },
reducer: { name: 'userList' }
});
}
export function getProjectList(query) {
return (dispatch) => basicAction({
type: 'get',
query,
dispatch,
actionType: 'GET_PROJEECT_LIST',
url: ApiTable.getProjectList,
msg: { error: '获取结构物列表失败', },
reducer: { name: 'structureList' }
});
}
export function positionList(query) {
return (dispatch) => basicAction({
type: 'get',
query,
dispatch,
actionType: 'POSITION_LIST',
url: ApiTable.position,
msg: { error: '获取点位列表失败', },
});
}

17
web-screen/client/src/sections/patrolManage/actions/record.js

@ -1,17 +0,0 @@
'use strict';
import { basicAction } from '@peace/utils'
export const GET_PATROL_RECORD_LIST = 'GET_PATROL_RECORD_LIST';
export const GET_PATROL_RECORD_LIST_SUCCESS = 'GET_PATROL_RECORD_LIST_SUCCESS';
export const GET_PATROL_RECORD_LIST_ERROR = 'GET_PATROL_RECORD_LIST_ERROR';
export function records(url) {
return (dispatch) => basicAction({
type: 'get',
dispatch,
actionType: GET_PATROL_RECORD_LIST,
url: url,
msg: { error: '获取巡检记录失败', },
reducer: { name: 'record' }
});
}

26
web-screen/client/src/sections/patrolManage/actions/report.js

@ -1,26 +0,0 @@
'use strict';
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
export function getPatrolReport (query) {
return dispatch => basicAction({
type: 'get',
query,
dispatch: dispatch,
actionType: 'GET_PATROL_REPORT',
url: ApiTable.patrolReport,
msg: { error: '获取巡检报告失败' },
});
}
export function delpatrolRecord (id) {
return dispatch => basicAction({
type: 'delete',
dispatch: dispatch,
actionType: 'DEL_PATROL_RECORD',
url: ApiTable.delpatrolRecord.replace('{id}', id),
msg: { error: '删除巡检报告失败' },
})
}

55
web-screen/client/src/sections/patrolManage/actions/reportConf.js

@ -1,55 +0,0 @@
'use strict';
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
export function getReportList (query) {
return dispatch => basicAction({
type: 'get',
query,
dispatch: dispatch,
actionType: 'GET_REPORT_LIST',
url: ApiTable.getReportList,
msg: { error: '获取报表配置列表失败' },
});
}
export function postReport (data = {}) {
return dispatch => basicAction({
type: 'post',
data,
dispatch: dispatch,
actionType: 'POST_REPORT',
url: `${ApiTable.postReport}`,
msg: { option: data?.id ? '编辑报表生成规则' : "新增报表生成规则" },
});
}
export function delReport (id) {//删除报表文件
return dispatch => basicAction({
type: 'del',
dispatch: dispatch,
actionType: 'DEL_REPORT',
url: `${ApiTable.delReport.replace('{id}', id)}`,
msg: { option: '删除报表规则' },
});
}
export function postGenerateReport (data = {}) { //生成报表
return dispatch => basicAction({
type: 'post',
data,
dispatch: dispatch,
actionType: 'POST_GENERATE_REPORT',
url: `${ApiTable.generateReport}`,
msg: { option: "生成报表" },
reducer: {
name: "generateReport",
params: { noClear: true }
}
});
}

48
web-screen/client/src/sections/patrolManage/actions/template.js

@ -1,48 +0,0 @@
'use strict';
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
export function getPatrolTemplate (query) {
return dispatch => basicAction({
type: 'get',
query,
dispatch: dispatch,
actionType: 'GET_PATROL_TEMPLATE',
url: ApiTable.patrolTemplate,
msg: { error: '获取巡检模板失败' },
reducer: { name: 'patrolTemplate' }
});
}
export function createPatrolTemplate (data) {
return dispatch => basicAction({
type: 'post',
data,
dispatch: dispatch,
actionType: 'CREATE_PATROL_TEMPLATE',
url: ApiTable.patrolTemplate,
msg: { option: '新增巡检模板' },
});
}
export function delPatrolTemplate (id) {
return dispatch => basicAction({
type: 'del',
dispatch: dispatch,
actionType: 'DEL_PATROL_TEMPLATE',
url: ApiTable.delPatrolTemplate.replace('{id}', id),
msg: { option: '删除巡检模板' },
});
}
export function updatePatrolTemplate (data) {
return dispatch => basicAction({
type: 'put',
data,
dispatch: dispatch,
actionType: 'UPDATE_PATROL_TEMPLATE',
url: ApiTable.patrolTemplate,
msg: { option: '修改巡检模板' },
});
}

24
web-screen/client/src/sections/patrolManage/actions/yujingguanli.js

@ -1,24 +0,0 @@
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
export function putxinxi (data) {
return dispatch => basicAction({
type: 'post',
data,
dispatch: dispatch,
actionType: 'PUT_XINXI',
url: ApiTable.yujingguanli,
msg: { option: '发送信息' },
});
}
export function modifyPatrolRecordIssueHandle(id, params, msg) {
return (dispatch) => basicAction({
type: 'put',
data: params,
dispatch,
actionType: 'MODIFY_PatrolRecordIssueHandle_REPORT',
url: ApiTable.modifyPatrolRecordIssueHandle.replace('{id}', id),
msg: '',
});
}

281
web-screen/client/src/sections/patrolManage/components/addReportRulesModal.js

@ -1,281 +0,0 @@
import { Button, Form, Input, Modal, Select, DatePicker,message } from 'antd'
import React, { useState, useEffect } from 'react'
import { connect } from 'react-redux'
import Uploads from '$components/Uploads'
const { RangePicker } = DatePicker
import moment from 'moment'
const AddReportRulesModal = props => {
const [form] = Form.useForm()
const { user, visible, cancelHandle, actions, dispatch, onOk, modalData,typeList,structAll} = props
const [systemList, setSystemList] = useState([{ value: 1, label: '动力系统' },{ value: 2, label: '网络系统' }])
const { patrolManage } = actions
const [type, setType] = useState(0)
const [system,setSystem]=useState(0)//system
const [isShow, setIsShow] = useState(false)
const [structlist, setStructlist] = useState([])//结构物列表(只包括id和name)
// const [startTime,setStartTime]=useState('')
// const [endTime,setEndTime]=useState('')
useEffect(()=>{
if(modalData){
setType(modalData.type)
}
},[modalData])
const typeChange = e => {
setType(e)
form.setFieldValue('system', '')
form.setFieldValue('structure', undefined)
}
useEffect(()=>{
if(type){
if(type==1){
const list = structAll.filter(v => v.type === '管廊')?.map(k => {
return {
value: k.id,
label: k.name
}
})
setStructlist(list)
}
}
},[type])
useEffect(()=>{
//过滤管廊类型的数据
const list = structAll.filter(v => v.type === '管廊')?.map(k => {
return {
value: k.id,
label: k.name
}
})
setStructlist(list)
},[])
useEffect(() => {
// setPic(modalData?.reportpic)
form.setFieldsValue({
structure: null,
pic: null,
name: null,
type: null,
timeRange: null,
})
form.setFieldsValue({
structure: modalData?.structure,
name: modalData?.name,
type: modalData?.type,
system:modalData?.system,
pic: modalData?.reportpic?.map(item=>{return {storageUrl:item}}),
timeRange: modalData?.startTime ? [moment(modalData?.startTime), moment(modalData?.endTime)] : [],
})
}, [visible])
const timeChane = e => {}
const okHandler = () => {
form
.validateFields()
.then(values => {
if(values.pic?.length<4){
message.warning(`最少选择4张图片`)
return
}
const params = {
id: modalData?.id,
name: values.name,
type: values.type,
system:values.system,
structure: Array.isArray(values.structure) ? [...values.structure] : [values.structure],
endTime: moment(values.timeRange[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss'),
startTime: moment(values.timeRange[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss'),
reportpic: values?.pic[0]?.name ? values?.pic.map(u => u.storageUrl) : modalData?.reportpic,
}
dispatch(patrolManage.postReport(params)).then(res => {
if (res.success) {
// form.resetFields()
cancelHandle()
onOk()
setType(null)
}
})
})
.catch(info => {
console.log('Validate Failed:', info)
})
}
//use
// const structChange=(e)=>{
// setStructObj(structAll.find(item=>item.id==e))
// }
// useEffect(()=>{
// if(strcutObj){
// if(strcutObj.subType.includes('供配电系统')||strcutObj.subType.includes('防雷')){
// setSystemList([{ value: 1, label: '动力系统' }])
// setIsShow(true)
// }else if(strcutObj.subType.includes('指挥中心')||strcutObj.subType.includes('安防'))
// setSystemList([{ value: 2, label: '网络系统' }])
// setIsShow(true)
// }
// },[strcutObj])
const systemChange=(e)=>{
setSystem(e)
// setType(null)
form.setFieldValue('structure', undefined)
if(e==1){
const list=structAll.filter(v => v.type === '管廊')?.filter(item=>item.subType.includes('供配电系统')||item.subType.includes('防雷'))
if(list&&list.length){
setStructlist( list?.map(item=>{
return {value: item.id,
label: item.name}
}))
}else{
setStructlist([])
}
}else if(e==2){
const list=structAll.filter(v => v.type === '管廊')?.filter(item=>item.subType.includes('指挥中心')||item.subType.includes('安防'))
if(list&&list.length){
setStructlist( list?.map(item=>{
return {value: item.id,
label: item.name}
}))
}else{
setStructlist([])
}
}
}
console.log('reportpic',modalData?.reportpic)
return (
<>
<Modal
destroyOnClose
title={modalData ? '编辑报表规则' : '新建报表规则'}
visible={visible}
onCancel={() => {
cancelHandle()
setIsShow(false)
setType(0)
form.setFieldsValue({
structure: null,
pic: null,
name: null,
type: null,
timeRange: null,
})
// form.resetFields()
}}
onOk={okHandler}>
<Form
form={form}
labelCol={{
span: 5,
}}
initialValues={
{
// structure:modalData?.structure,
// pic:modalData?.reportpic,
// name:modalData?.name,
// type:modalData?.type,
// timeRange:[moment(modalData?.startTime),moment(modalData?.endTime)]
}
}>
<Form.Item label='报表名称' name='name' rules={[{ required: true, message: '请输入报表名称' }]}>
<Input />
</Form.Item>
<Form.Item label='报表类型' name='type' rules={[{ required: true, message: '请选择报表类型' }]}>
<Select onChange={typeChange}>
{typeList?.map(g => {
return (
<Option key={g.value} value={g.value} label={g.label}>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
}}>
{g.label}
</div>
</Option>
)
})}
</Select>
</Form.Item>
{type===2?
<Form.Item label='系统' name='system' rules={[{ required: true, message: '请选择系统' }]}>
<Select onChange={systemChange} >
{systemList?.map(g => {
return (
<Option key={g.value} value={g.value} label={g.label}>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
}}>
{g.label}
</div>
</Option>
)
})}
</Select>
</Form.Item>:''}
<Form.Item label='关联结构物' name='structure' rules={[{ required: true, message: '请选择结构物' }]}>
<Select mode={type === 2 ? 'multiple' : undefined}>
{structlist?.map(g => {
return (
<Option key={g.value} value={g.value} label={g.label}>
<div
style={{
display: 'flex',
justifyContent: 'space-between',
}}>
{g.label}
</div>
</Option>
)
})}
</Select>
</Form.Item>
<Form.Item label='生成时间' name='timeRange' rules={[{ required: true, message: '请选择时间' }]}>
<RangePicker onChange={timeChane} />
</Form.Item>
<Form.Item label='发现问题上传:' name='pic' rules={[{ required: true, message: '请选择图片' }]}>
<Uploads
listType='picture-card'
uploadType='project'
maxFilesNum={15}
maxFileSize={10}
isQiniu={true}
// disabled={true}
fileTypes={['png', 'jpg']}
fileList={modalData?.reportpic}
defaultValue={(() => {
let nextV = []
for (let s of modalData?.reportpic || []) {
if (s) {
nextV.push({
url: s,
storageUrl: s,
})
}
}
return nextV
})()}
/>
</Form.Item>
</Form>
</Modal>
</>
)
}
function mapStateToProps(state) {
const { auth, global } = state
return {
user: auth.user,
actions: global.actions,
}
}
export default connect(mapStateToProps)(AddReportRulesModal)

122
web-screen/client/src/sections/patrolManage/components/checkItemsModal.js

@ -1,122 +0,0 @@
import { Button, Form, Input, Modal, Select } from 'antd';
import { DeleteOutlined } from '@ant-design/icons';
import React, { useState, useEffect } from 'react';
import { connect } from 'react-redux';
import { getCheckItemsGroup, delCheckItemsGroup } from '../actions/checkItems';
const { Option } = Select;
const CheckItemsModal = ({ visible, onOk, onCancel, curRecord, dispatch }) => {
const [group, setGroup] = useState([]);
const [isNewGroup, setIsNewGroup] = useState(false);
const [form] = Form.useForm();
useEffect(() => {
getGroup();
}, [])
function getGroup() {
dispatch(getCheckItemsGroup()).then(res => {
if (res.success) {
const opt = res.payload.data?.map(g => ({ value: g.id, label: g.name }));
setGroup(opt);
}
});
}
function delGroup(id, lastGroup) {
dispatch(delCheckItemsGroup(id)).then(res => {
if (res.success) {
form.setFieldValue('group', lastGroup === id ? null : lastGroup)
getGroup();
}
});
}
return (
<Modal
visible={visible}
title={curRecord ? "检查项修改" : "检查项添加"}
okText="确定"
cancelText="取消"
onCancel={() => {
form.resetFields();
onCancel();
}}
onOk={() => {
form
.validateFields()
.then((values) => {
form.resetFields();
const params = {
...values,
isNewGroup
}
onOk(params);
})
.catch((info) => {
console.log('Validate Failed:', info);
});
}}
>
<Form
form={form}
layout="vertical"
name="form_in_modal"
initialValues={{
...curRecord,
group: curRecord?.checkItemsGroup?.id
}}
>
<Form.Item
name="name"
label="检查项名称"
rules={[
{ required: true, message: '请输入检查项名称' },
]}
>
<Input />
</Form.Item>
<Form.Item
name="group"
label="分组名称"
rules={[
{ required: true, message: '请选择分组' },
]}
>
{
isNewGroup
? <Input />
: <Select loading={!group?.length} optionLabelProp="label">
{
group?.map((g) => {
return <Option key={g.value} value={g.value} label={g.label}>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
{g.label}
<DeleteOutlined onClick={() => { delGroup(g.value, form.getFieldValue('group')) }} />
</div>
</Option>
})
}
</Select>
}
</Form.Item>
</Form>
<Button type='link' onClick={() => {
if (!isNewGroup) {
form.setFieldsValue({ group: null })
} else {
form.setFieldsValue({ group: curRecord?.checkItemsGroup?.id })
}
setIsNewGroup(!isNewGroup);
}}>{isNewGroup ? '选择已有' : '创建分组'}</Button>
</Modal >
);
};
function mapStateToProps(state) {
const { auth } = state
return {
user: auth.user,
}
}
export default connect(mapStateToProps)(CheckItemsModal);

263
web-screen/client/src/sections/patrolManage/components/planModal.js

@ -1,263 +0,0 @@
import { Form, Input, Modal, Select, DatePicker } from 'antd';
import { DownOutlined } from '@ant-design/icons';
import React, { useState, useEffect } from 'react';
import { connect } from 'react-redux';
import { getUserList, getProjectList, positionList } from '../actions/plan';
import moment from 'moment';
const { RangePicker } = DatePicker;
const PlanModal = ({ visible, onCreate, onCancel, dispatch, userLoading, userList, structureList, struLoading, type, curRecord, templateLoading, patrolTemplate }) => {
const [userOpt, setUserOpt] = useState();
const [struOpt, setStruOpt] = useState();
const [pointOpt, setPointOpt] = useState();
const [points, setPoints] = useState();
const [unit, setUnit] = useState(curRecord?.frequency ? curRecord.frequency.substring(curRecord.frequency.length - 3, curRecord.frequency.length) : "次/天");
const [form] = Form.useForm();
useEffect(() => {
if (type === 'view') {
} else {
dispatch(getUserList())
dispatch(getProjectList())
}
if (type === 'edit' || type === 'view') {
dispatch(positionList({ projectId: curRecord?.project?.id })).then(res => {
if (res.success) {
setPoints(res.payload.data?.rows)
setPointOpt(res.payload.data?.rows[0]?.points?.map(p => ({ label: p.name, value: p.id })))
}
})
}
}, [])
useEffect(() => {
if (userList.length) {
setUserOpt(userList?.filter(f => f.structure?.includes(curRecord?.project?.id))?.map(u => ({ label: u.name, value: u.id })))
// 如果巡检人员用户被删除,筛掉被删除的用户
const userListIds = userList?.map(u => u.id);
const filterUsers = curRecord?.users?.filter(u => userListIds.includes(u.id));
const nextUserIds = filterUsers?.map(u => u.id);
form.setFieldsValue({
userIds: nextUserIds,
userDept: [...new Set(filterUsers?.map(u => u.department?.name))].join()
});
}
}, [userList])
useEffect(() => {
if (structureList?.rows?.length) {
setStruOpt(structureList?.rows?.map(s => ({ label: s.name, value: s.id })))
}
}, [structureList])
const selectAfter = (
<Select
defaultValue={curRecord?.frequency ? curRecord.frequency.substring(curRecord.frequency.length - 3, curRecord.frequency.length) : "次/天"}
onChange={value => setUnit(value)}
suffixIcon={<DownOutlined style={{ color: '#fff' }} />}
>
<Option value="次/天">/</Option>
<Option value="次/周">/</Option>
<Option value="次/月">/</Option>
</Select>
);
return (
<Modal
className="global-modal"
width={717}
visible={visible}
title={(type === 'view' ? '查看' : type === 'edit' ? '编辑' : '新增') + "巡检计划"}
okText="确定"
cancelText="取消"
onCancel={() => {
form.resetFields();
onCancel();
}}
onOk={() => {
if (type === 'view') {
form.resetFields();
onCancel();
return;
}
form
.validateFields()
.then((values) => {
form.resetFields();
const params = {
...values,
frequency: values.frequency + unit,
startTime: values.time[0],
endTime: values.time[1],
points: points[0]?.points?.filter(p => values?.points?.includes(p.id))
}
onCreate(params);
})
.catch((info) => {
console.log('Validate Failed:', info);
});
}}
>
<Form
form={form}
name="form_in_modal"
labelAlign='right'
labelCol={{ span: 4 }} wrapperCol={{ span: 18 }}
initialValues={{
...curRecord,
time: [moment(curRecord?.startTime), moment(curRecord?.endTime)],
points: curRecord?.points?.map(p => p.id),
userIds: curRecord?.users?.map(u => u.id),
userDept: [...new Set(curRecord?.users?.map(u => u.department?.name))].join(),
frequency: curRecord?.frequency?.split('次')[0]
}}
disabled={type === 'view'}
>
<div style={{ position: 'relative', display: 'flex', justifyContent: 'space-between' }}>
<Form.Item
name="structureId"
label="结构物名称"
labelCol={{ span: 9 }}
style={{ width: 330 }}
rules={[
{ required: true, message: '请选择结构物' },
]}
>
<Select disabled={type === 'view'} bordered={false} options={struOpt} loading={struLoading} onChange={(projectId) => {
dispatch(positionList({ projectId })).then(res => {
if (res.success) {
setPoints(res.payload.data?.rows)
setPointOpt(res.payload.data?.rows[0]?.points?.map(p => ({ label: p.name, value: p.id })))
}
})
form.setFieldsValue({ userIds: [], userDept: [] });
setUserOpt(userList?.filter(f => f.structure?.includes(projectId))?.map(u => ({ label: u.name, value: u.id })))
}} />
</Form.Item>
<Form.Item
name="name"
label="巡检任务名称"
labelCol={{ span: 9 }}
style={{ width: 330 }}
rules={[
{ required: true, message: '请输入巡检任务名称' },
]}
>
<Input disabled={type === 'view'} bordered={false} />
</Form.Item>
</div>
<div style={{ position: 'relative', display: 'flex', justifyContent: 'space-between' }}>
<Form.Item
name="way"
label="巡检方式"
labelCol={{ span: 8 }}
style={{ width: 330 }}
rules={[
{ required: true, message: '请选择巡检方式' },
]}
initialValue='周期巡检'
>
<Select bordered={false} options={[{
label: '周期巡检',
value: '周期巡检'
}]} disabled />
</Form.Item>
<Form.Item
name="frequency"
label="巡检频次"
labelCol={{ span: 8 }}
style={{ width: 330 }}
rules={[
{ required: true, message: '请选择巡检频次' },
]}
>
<Input addonAfter={selectAfter} disabled={type === 'view'} bordered={false} />
</Form.Item>
</div>
<div style={{ position: 'relative', display: 'flex', justifyContent: 'space-between' }}>
<Form.Item
name="templateId"
label="巡检模板"
labelCol={{ span: 8 }}
style={{ width: 330 }}
rules={[
{ required: true, message: '请选择巡检模板' },
]}
>
<Select
bordered={false}
disabled={type === 'view'}
options={patrolTemplate.map(t => {
return { label: t.name, value: t.id }
})}
loading={templateLoading}
/>
</Form.Item>
<Form.Item
name="time"
label="任务周期"
labelCol={{ span: 8 }}
style={{ width: 330 }}
rules={[
{ required: true, message: '请选择任务周期' },
]}
>
<RangePicker disabled={type === 'view'} bordered={false} />
</Form.Item>
</div>
<div style={{ position: 'relative', display: 'flex', justifyContent: 'space-between' }}>
<Form.Item
name="points"
label="巡检点"
labelCol={{ span: 8 }}
style={{ width: 330 }}
rules={[
{ required: true, message: '请选择巡检点' },
]}
>
<Select mode="multiple" options={pointOpt} disabled={!pointOpt || type === 'view'} bordered={false} showSearch
filterOption={(input, option) => (option?.label ?? '').toLowerCase().includes(input.toLowerCase())}
/>
</Form.Item>
<Form.Item
name="userIds"
label="巡检人员"
labelCol={{ span: 8 }}
style={{ width: 330 }}
rules={[
{ required: true, message: '请选择巡检人员' },
]}
>
<Select mode="multiple" disabled={type === 'view'} bordered={false} options={userOpt} loading={userLoading} onChange={(values) => {
const selectUser = userList?.filter(u => values?.includes(u.id))
form.setFieldsValue({
userDept: [...new Set(selectUser?.map(u => u.department.name))].join()
});
}} />
</Form.Item>
</div>
<Form.Item
name="userDept"
label="巡检单位"
>
<Input disabled bordered={false} />
</Form.Item>
</Form>
</Modal >
);
};
function mapStateToProps(state) {
const { auth, userList, structureList, patrolTemplate } = state
return {
user: auth.user,
userList: userList.data || [],
structureList: structureList.data || [],
patrolTemplate: (patrolTemplate.data || { rows: [] }).rows,
userLoading: userList.isRequesting,
struLoading: structureList.isRequesting,
templateLoading: patrolTemplate.isRequesting,
}
}
export default connect(mapStateToProps)(PlanModal);

122
web-screen/client/src/sections/patrolManage/components/planTemplateModal.js

@ -1,122 +0,0 @@
import { Button, Form, Input, Modal, Select, DatePicker } from 'antd';
import React, { useState, useEffect } from 'react';
import { connect } from 'react-redux';
import { createPatrolTemplate, delPatrolTemplate, updatePatrolTemplate, getPatrolTemplate } from '../actions/template';
import moment from 'moment';
const { RangePicker } = DatePicker;
const { TextArea } = Input;
const PlanModal = ({ visible, onCancel, dispatch, type, curRecord, tableRef, checkItemsGroup }) => {
const [form] = Form.useForm();
return (
<Modal
visible={visible}
title="新增巡检模板"
okText="确定"
cancelText="取消"
onCancel={() => {
form.resetFields();
onCancel();
}}
onOk={() => {
form
.validateFields()
.then((values) => {
const params = {
...values,
}
if (type === 'create') {
dispatch(createPatrolTemplate(params)).then(res => {
if (res.success) {
tableRef.current.reload();
form.resetFields();
onCancel();
}
})
} else {
dispatch(updatePatrolTemplate({
...params,
id: curRecord.id
})).then(res => {
if (res.success) {
tableRef.current.reload();
form.resetFields();
onCancel();
}
})
}
})
.catch((info) => {
console.log('Validate Failed:', info);
});
}}
>
<Form
form={form}
layout="vertical"
name="form_in_modal"
initialValues={{
...curRecord,
checkItems: curRecord?.checkItems?.map(c => c.id)
}}
>
<Form.Item
name="name"
label="模板名称"
rules={[
{ required: true, message: '请输入巡检模板名称' },
]}
>
<Input />
</Form.Item>
<Form.Item
name="describe"
label="描述"
rules={[]}
>
<TextArea rows={4} />
</Form.Item>
<Form.Item
name="checkItems"
label="检查项"
rules={[
{ required: true, message: '请选择检查项' },
]}
>
<Select
style={{
// width: 200,
}}
mode="multiple"
options={
checkItemsGroup.map(g => {
return {
label: g.name,
options: g.checkItems.map(c => {
return {
label: c.name,
value: c.id,
}
})
}
})
}
/>
</Form.Item>
</Form>
</Modal >
);
};
function mapStateToProps (state) {
const { auth, checkItemsGroup } = state
return {
user: auth.user,
checkItemsGroup: checkItemsGroup.data || []
}
}
export default connect(mapStateToProps)(PlanModal);

89
web-screen/client/src/sections/patrolManage/components/xiafagaojin.js

@ -1,89 +0,0 @@
import { Button, Form, Input, Modal, Select, DatePicker,Checkbox, message } from 'antd';
import React, { useState, useEffect } from 'react';
import { connect } from 'react-redux';
import {modifyPatrolRecordIssueHandle} from '../actions/yujingguanli'
import {putxinxi} from '../actions/yujingguanli'
import moment from 'moment';
const { RangePicker } = DatePicker;
const { TextArea } = Input;
const PlanModal = ({ visible, onCancel, dispatch, type, curRecord, tableRef, checkItemsGroup,userlist ,actions,onHandle}) => {
const [form] = Form.useForm();
const { issueHandle } = actions
const shigutypes = [{value:1,label: '短信告警'},
{value:2,label:'邮件告警'}]
console.log(userlist,'userlist')
return (
<Modal
visible={visible}
title="下发告警"
okText="确定"
cancelText="取消"
onCancel={() => {
form.resetFields();
onCancel();
}}
onOk={() => {
form
.validateFields()
.then((values) => {
const params = {
...values,
}
console.log('user,',userlist)
let usedata = userlist.filter(i=>i?.username===values.name)
console.log(usedata,'usedata')
dispatch(putxinxi({phone:[params.name],email:[usedata[0]?.email],type:params.type,struction:curRecord?.points?.project?.name
,point:curRecord?.points?.itemData?.name,number:curRecord?.patrolRecordIssueHandles[0]?.yanshoucishu})).then(res=>{
console.log(res,'res')
}).then(()=>{
dispatch(modifyPatrolRecordIssueHandle(curRecord?.patrolRecordIssueHandles[0]?.id,{
isgaojing:true,
yujingshijian:moment().format('YYYY-MM-DD HH:mm:ss')
})).then(()=>message.success('下发告警成功')),
onCancel();
onHandle()
})
console.log(curRecord,'curRecord')
console.log(params,'params')
})
.catch((info) => {
console.log('Validate Failed:', info);
});
}}
>
<Form
form={form}
// layout="vertical"
name="form_in_modal"
labelCol={{ span: 5 }} wrapperCol={{ span: 19 }}
>
<Form.Item
name="name"
label="告警接收人"
rules={[
{ required: true, message: '请输入用户账号' },
]}
>
<Select options={userlist?.map(i=>({value:i?.username,label:i?.name}))}></Select>
</Form.Item>
<Form.Item label="告警方式"
name="type">
<Checkbox.Group options={shigutypes}/>
</Form.Item>
</Form>
</Modal >
);
};
function mapStateToProps (state) {
const { auth, checkItemsGroup,global } = state
return {
user: auth.user,
checkItemsGroup: checkItemsGroup.data || [],
actions: global.actions,
}
}
export default connect(mapStateToProps)(PlanModal);

176
web-screen/client/src/sections/patrolManage/containers/checkItems.js

@ -1,176 +0,0 @@
import React, { useState, useRef } from 'react';
import { connect } from 'react-redux';
import { Button, Popconfirm } from 'antd';
import ProTable from '@ant-design/pro-table';
import CheckItemsModal from '../components/checkItemsModal';
import { getCheckItems, createCheckItems, updateCheckItems, delCheckItems, createCheckItemsGroup } from '../actions/checkItems';
function CheckItems(props) {
const { dispatch } = props;
const tableRef = useRef();
const [dataSource, setDataSource] = useState([{}]);
const [visible, setVisible] = useState(false);
const [curRecord, setCurRecord] = useState(null); // 新增 or 修改
const [select, setSelect] = useState([]);
const onOk = async (values) => {
let groupId = null;
if (values.isNewGroup) {
await dispatch(createCheckItemsGroup({ name: values.group })).then(res => {
if (res.success) {
groupId = res.payload.data?.groupId
}
})
}
if (!curRecord) {
dispatch(createCheckItems({
name: values.name,
groupId: groupId ? groupId : values.group
})).then(res => {
if (res.success) {
tableRef.current.reload();
}
})
} else {
dispatch(updateCheckItems(curRecord.id, {
name: values.name,
groupId: groupId ? groupId : values.group
})).then(res => {
if (res.success) {
tableRef.current.reload();
}
})
}
setVisible(false);
};
function delItems(ids) {
dispatch(delCheckItems(ids)).then(res => {
if (res.success) {
tableRef.current.reload();
setSelect([]);
}
})
}
const columns = [{
title: '检查项',
dataIndex: 'name',
key: 'name',
ellipsis: true,
width: 150,
}, {
title: '分组名称',
dataIndex: 'groupName',
key: 'groupName',
ellipsis: true,
search: false,
width: 150,
render: (_, record) => {
return <div>{record?.checkItemsGroup?.name}</div>
}
}, {
title: '操作',
dataIndex: 'action',
key: 'action',
search: false,
width: 200,
render: (_, record) => {
return <>
<Button type="link" onClick={() => {
setCurRecord(record)
setVisible(true)
}}>修改</Button>
<Popconfirm
title="确认删除?"
onConfirm={() => { delItems(record.id) }}
disabled={record && record.patrolTemplates && record.patrolTemplates.length}
>
<Button type="link" danger disabled={record && record.patrolTemplates && record.patrolTemplates.length}>删除</Button>
</Popconfirm>
</>
},
}];
return (
<>
<ProTable
columns={columns}
actionRef={tableRef}
options={false}
dataSource={dataSource || []}
rowKey='id'
pagination={{ pageSize: 10, size: 'default', className: 'global-pagination' }}
request={async (params = {}) => {
const res = await dispatch(getCheckItems({
limit: params.pageSize,
page: params.current - 1,
name: params?.name
}));
setDataSource(res?.payload.data?.rows);
return {
...res,
total: res.payload.data.count ? res.payload.data.count : 0,
};
}}
onReset={() => { }}
search={{
defaultCollapsed: false,
optionRender: (searchConfig, formProps, dom) => [
...dom.reverse(),
<Button
key="add"
type='primary'
onClick={() => {
setCurRecord(null)
setVisible(true)
}}
>新增</Button>,
<Button
key="del"
type='primary'
disabled={!select?.length}
onClick={() => {
const ids = select?.map(s => s.id).join();
delItems(ids);
}}
>批量删除</Button>,
],
}}
rowSelection={{
selectedRowKeys: select?.map(v => v.id) || [],
onChange: (_, selectedRows) => {
setSelect(selectedRows)
},
getCheckboxProps: (record) => ({
disabled: record && record.patrolTemplates && record.patrolTemplates.length,
}),
}}
rowClassName={(record, index) => {
let className = 'global-light-row';
if (index % 2 === 1) className = 'global-dark-row';
return className;
}}
/>
{
visible ?
<CheckItemsModal
visible={visible}
onOk={onOk}
curRecord={curRecord}
onCancel={() => {
setVisible(false);
}}
/> : null
}
</>
)
}
function mapStateToProps(state) {
const { auth } = state
return {
user: auth.user
}
}
export default connect(mapStateToProps)(CheckItems);

10
web-screen/client/src/sections/patrolManage/containers/index.js

@ -1,10 +0,0 @@
'use strict';
import PatrolPlan from './patrolPlan';
import PatrolReocrd from './patrolRecord';
import PatrolReport from './patrolReport';
import CheckItems from './checkItems';
import PlanTemplate from './patrolTemplate';
import YujingGuanli from './yujingguanli';
export { PatrolPlan, PatrolReocrd, PatrolReport, CheckItems, PlanTemplate,YujingGuanli };

192
web-screen/client/src/sections/patrolManage/containers/patrolPlan.js

@ -1,192 +0,0 @@
import React, { useState, useRef, useEffect } from 'react';
import { connect } from 'react-redux';
import { Button, Popconfirm } from 'antd';
import ProTable from '@ant-design/pro-table';
import PlanModal from '../components/planModal';
import { createPatrolPlan, delPatrolPlan, updatePatrolPlan, getPatrolPlan } from '../actions/plan';
import { getPatrolTemplate } from '../actions/template';
import moment from 'moment';
import './patrolPlan.less'
function PatrolPlan(props) {
const { dispatch, user } = props;
const tableRef = useRef();
const [dataSource, setDataSource] = useState([{}]);
const [visible, setVisible] = useState(false);
const [type, setType] = useState();
const [curRecord, setCurRecord] = useState();
useEffect(() => {
dispatch(getPatrolTemplate({}))
}, [])
const onCreate = (values) => {
if (type === 'create') {
dispatch(createPatrolPlan(values)).then(res => {
if (res.success) {
tableRef.current.reload();
}
})
} else {
dispatch(updatePatrolPlan({ ...values, id: curRecord.id })).then(res => {
if (res.success) {
tableRef.current.reload();
}
})
}
setVisible(false);
setCurRecord(null);
};
const columns = [{
title: '结构物名称',
dataIndex: 'projectName',
key: 'projectName',
ellipsis: true,
render: (_, record) => {
return <div>{record?.project?.name}</div>
}
}, {
title: '巡检任务名称',
dataIndex: 'name',
key: 'name',
ellipsis: true
}, {
title: '开始时间',
dataIndex: 'startTime',
key: 'startTime',
ellipsis: true,
search: false,
render: (_, record) => moment(record.startTime).format('YYYY-MM-DD')
}, {
title: '结束时间',
dataIndex: 'endTime',
key: 'endTime',
ellipsis: true,
search: false,
render: (_, record) => moment(record.endTime).format('YYYY-MM-DD')
}, {
title: '巡检频次',
dataIndex: 'frequency',
key: 'frequency',
ellipsis: true,
search: false,
}, {
title: '巡检点位',
dataIndex: 'patrolPoints',
key: 'patrolPoints',
ellipsis: true,
search: false,
render: (_, record) => record?.points?.length ? record?.points?.map(p => p.name).join() : '-'
}, {
title: '巡检人',
dataIndex: 'patrolPerson',
key: 'patrolPerson',
ellipsis: true,
search: false,
render: (_, record) => record?.users?.map(u => u.name).join() || '-'
}, {
title: '巡检次数统计',
dataIndex: 'patrolCount',
key: 'patrolCount',
ellipsis: true,
search: false,
}, {
title: '操作',
dataIndex: 'action',
key: 'action',
search: false,
width: 200,
render: (_, record) => {
return <>
<Button type="link" onClick={() => {
setType('edit')
setCurRecord(record)
setVisible(true)
}}>修改</Button>
<Button type="link" onClick={() => {
setType('view')
setCurRecord(record)
setVisible(true)
}}>查看</Button>
<Popconfirm
title="确认删除?"
onConfirm={() => {
dispatch(delPatrolPlan(record.id)).then(res => {
if (res.success) {
tableRef.current.reload();
}
})
}}>
<Button type="link" danger>删除</Button>
</Popconfirm>
</>
},
}];
return (
<div className='plan-main'>
<div className='title'>
<span className='line'></span>
<span className='cn'>巡检计划制定</span>
<span className='en'>&nbsp;Inspection plan making</span>
</div>
<ProTable
columns={columns}
actionRef={tableRef}
options={false}
dataSource={dataSource || []}
rowKey='id'
pagination={{ pageSize: 10, size: 'default', className: 'global-pagination' }}
search={{
className: 'search-form',
defaultCollapsed: false,
labelWidth: 'auto',
optionRender: (searchConfig, formProps, dom) => [
...dom.reverse(),
<Button
type="primary"
key="primary"
onClick={() => {
setType('create')
setVisible(true)
}}
>新增巡检计划</Button>,
],
}}
request={async (params = {}) => {
const res = await dispatch(getPatrolPlan(params));
setDataSource(res?.payload.data?.rows);
return { ...res };
}}
onReset={() => { }}
rowClassName={(record, index) => {
let className = 'global-light-row';
if (index % 2 === 1) className = 'global-dark-row';
return className;
}}
/>
{
visible ?
<PlanModal
visible={visible}
onCreate={onCreate}
type={type}
curRecord={curRecord}
onCancel={() => {
setVisible(false);
setCurRecord(null)
}}
/> : null
}
</div>
)
}
function mapStateToProps(state) {
const { auth } = state
return {
user: auth.user
}
}
export default connect(mapStateToProps)(PatrolPlan);

20
web-screen/client/src/sections/patrolManage/containers/patrolPlan.less

@ -1,20 +0,0 @@
.plan-main {
background: #fff;
.search-form {
.ant-row-start {
justify-content: flex-end;
.ant-col-offset-6 {
margin-left: 0;
}
}
}
.title {
position: absolute;
top: 50px;
left: 50px;
z-index: 1;
}
}

387
web-screen/client/src/sections/patrolManage/containers/patrolRecord.js

@ -1,387 +0,0 @@
'use strict'
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { Form, Input, Select, Button, Table, Modal, DatePicker, message, Row, Col, Collapse, Popconfirm } from 'antd';
import moment from "moment";
import XLSX from 'xlsx';
import Uploads from '$components/Uploads';
import '../style.less'
const { Panel } = Collapse;
const PatrolRecord = (props) => {
const { dispatch, actions, } = props
const { patrolManage } = actions
const [tableList, settableList] = useState([])
const [showDetailModal, setShowDetail] = useState(false)
const [modelData, setModelData] = useState({})
const [query, setQuery] = useState({ limit: 10, page: 0 })
const [limits, setLimits] = useState()
const format = 'YYYY-MM-DD HH:mm:ss'
const [search, setSearch] = useState({ name: null, time: [moment().add(-7, 'd').format(format), moment().format(format)], state: 'null' })
const [exportLoading, setExportLoading] = useState(false)
const aboutDisaster={handleObj:'排查及处理对象',installLocation:'安装位置',handleGoal:'排查及处理目的',rtuNo:'RTU编号'}
useEffect(() => {
record(search)
}, [])
const record = (params) => {
dispatch(patrolManage.records(`patrolRecord/all/${params.time[0]}/${params.time[1]}/${params.state}/null`)).then(res => {
if (res.success) {
settableList(params.name != null ? res.payload.data?.filter(v =>
(v.points.user.name.indexOf(params.name) != -1 || v.points.project.name.indexOf(params.name) != -1))
.map(v => ({ ...v, key: v.id })) : res.payload.data?.map(v => ({ ...v, key: v.id })))
setLimits(res.payload.data?.length)
}
})
}
const exportRecord = () => {
if (tableList.length === 0) {
message.warning('没有数据可以导出')
return
}
setExportLoading(true)
const workbook = XLSX.utils.book_new(); // 新建工作簿
let data = [['结构物名称', '巡检计划', '巡检点位', '巡检人', '巡检单位', '巡检频次', '上次巡检日期', '本次巡检日期', '巡检结果']];
for (const item of tableList) {
data.push([
item.points?.project?.name || '--',
item.patrolPlan?.name || '--',
item.points?.itemData?.name || '--',
item.points?.user?.name || '--',
item.points?.user?.department?.name || '--',
item.points?.frequency || '--',
item.lastInspectionTime ? moment(item.lastInspectionTime).format('YYYY-MM-DD HH:mm:ss') : '--',
moment(item.inspectionTime).format('YYYY-MM-DD HH:mm:ss'),
!item.alarm ? '正常' : '异常',
])
}
const worksheet = XLSX.utils.aoa_to_sheet(data); // 从二维数组新建工作表
XLSX.utils.book_append_sheet(workbook, worksheet, "sheet1"); // 将工作表添加到工作簿
XLSX.writeFile(workbook, '巡检记录.xlsx'); // 将工作簿数据建立为./xlsx文件(浏览器环境下会直接下载)
message.success('导出成功')
setExportLoading(false)
}
const columns = [{
title: '结构物名称',
dataIndex: 'name',
key: 'name',
width: '10%',
showInDetail: true,
render: (text, record, index) => {
return !record.points?.project ? '--' : <div>{record.points.project.name}</div>
}
}, {
title: '巡检计划',
dataIndex: 'name',
key: 'name',
width: '10%',
showInDetail: true,
render: (text, record, index) => {
return !record.patrolPlan ? '--' : <div>{record?.patrolPlan?.name || '-'}</div>
}
}, {
title: '巡检点位',
dataIndex: 'type',
key: 'type',
showInDetail: true,
width: '10%',
render: (text, record, index) => {
return !record.points?.user ? '--' : <div>{record.points.itemData.name}</div>
}
}, {
title: '巡检人',
dataIndex: 'type',
key: 'type',
showInDetail: true,
width: '10%',
render: (text, record, index) => {
return !record.points?.user ? '--' : <div>{record.points.user.name}</div>
}
}, {
title: '巡检单位',
dataIndex: 'type',
showInDetail: true,
key: 'type',
width: '10%',
render: (text, record, index) => {
return !record.points?.user ? '--' : <div>{record.points.user.department.name}</div>
}
}, {
title: '巡检频次',
dataIndex: 'describe',
key: 'describe',
showInDetail: true,
width: '10%',
render: (text, record, index) => {
return !record.points ? '--' : <div>{record.points.frequency || '-'}</div>
}
}, {
title: '上次巡检日期',
dataIndex: 'describe',
showInDetail: true,
key: 'describe',
render: (text, record, index) => record.lastInspectionTime ? moment(record.lastInspectionTime).format('YYYY-MM-DD HH:mm:ss') : '--'
}, {
title: '本次巡检日期',
dataIndex: 'describe',
key: 'describe',
showInDetail: true,
render: (text, record, index) => moment(record.inspectionTime).format('YYYY-MM-DD HH:mm:ss') || '--'
}, {
title: '巡检结果',
dataIndex: 'describe',
key: 'describe',
render: (text, record, index) => !record.alarm ? '正常' : '异常'
}, {
title: '操作',
dataIndex: 'operation',
key: 'operation',
render: (text, record, index) => {
return (
<div style={{ width: 190 }}>
<Button type="link" onClick={() => {
setShowDetail(true)
setModelData(record)
}}>
查看详情</Button>
</div>
)
}
}
]
return (
<div id='patrol-record' className='global-main'>
<div style={{ display: 'flex', justifyContent: 'space-between', padding: '0 10px' }}>
<Form
style={{ display: 'flex', }}
onFinish={r => {
record({
name: r.name,
time: [moment(r.time[0]).format(format), moment(r.time[1]).format(format)],
state: r.state
})
}}
>
<Form.Item
name="name"
style={{ marginRight: 16, minWidth: 250 }}
>
<Input placeholder="请输入结构物名称或巡检人" allowClear />
</Form.Item>
<Form.Item
name="time"
style={{ marginRight: 16, }}
initialValue={[moment(search.time[0], format), moment(search.time[1], format)]}
>
<DatePicker.RangePicker showTime style={{ marginRight: 16, }} />
</Form.Item>
<Form.Item
name="state"
style={{ marginRight: 16, }}
initialValue={'null'}
>
<Select allowClear
options={[
{ value: 'null', label: '全部' },
{ value: false, label: '正常' },
{ value: true, label: '异常' }]} />
</Form.Item>
<Form.Item wrapperCol={{}}>
<Button type="primary" htmlType="submit" style={{ marginRight: 16 }}>搜索</Button>
<Button type="primary" onClick={exportRecord} loading={exportLoading}>导出</Button>
</Form.Item>
</Form>
</div>
<Table
columns={columns}
dataSource={tableList}
pagination={{
className: 'global-pagination',
showTotal: (total, range) => `${range[0]}-${range[1]} 条/总共 ${total}`
}}
rowClassName={(record, index) => {
let className = 'global-light-row';
if (index % 2 === 1) className = 'global-dark-row';
return className;
}}
/>
<Modal
title='巡检记录详情'
open={showDetailModal}
onCancel={() => setShowDetail(false)}
footer={[<Button onClick={() => setShowDetail(false)}>关闭</Button>]}
className='patrol-record-detail-modal'
width={666}
>
{(() => {
let dataArr = []
columns.forEach(c => {
if (c.showInDetail) {
dataArr.push(
<>
<Row>
<Col span={5} style={{
// textAlign: 'justify', textAlignLast: 'justify'
}}>{c.title} </Col>
<Col span={19}>{c.render('', modelData)}</Col>
</Row>
</>
)
}
})
if (modelData && modelData.points && modelData.points.inspectContent) {
//地灾相关详情数据渲染
if(modelData.points.aboutDisaster){
for (let v in modelData.points.aboutDisaster) {
dataArr.push( <>
<Row>
<Col span={5} style={{
// textAlign: 'justify', textAlignLast: 'justify'
}}>{aboutDisaster[v]} </Col>
<Col span={19}>{modelData.points.aboutDisaster[v]}</Col>
</Row>
</>)
}
}
if (modelData?.points?.itemData?.pointDevices?.length > 0) {
let inspectContent = modelData.points.inspectContent
inspectContent?.map(s => {
dataArr.push(
<>
<Row>
<Col span={5} style={{}}>{s?.deviceName} </Col>
<Col span={19}>
{
!s.alarm ? '正常' :
<Collapse ghost style={{ padding: 0 }}>
<Panel header="异常" key="1" style={{ padding: 0 }}>
{s?.checkItems?.map(k => {
return <>
<Row style={{ fontWeight: 'bold' }}>{k.name}:</Row>
<Row style={{ marginBottom: 20 }}>
<Col span={4} style={{}}>巡查详情 </Col>
<Col span={20}>{k.msgInp}</Col>
<Col span={4} style={{}}>严重等级 </Col>
<Col span={20}>{k.level}</Col>
<Col span={4} style={{}}>现场照片 </Col>
<Col span={20}>
<Uploads
listType='picture-card'
uploadType='project'
maxFilesNum={1}
maxFileSize={10}
isQiniu={true}
disabled={true}
fileTypes={["png", "jpg"]}
defaultValue={
(() => {
let nextV = []
for (let s of (k.imgs || [])) {
if (s) {
nextV.push({
storageUrl: s
})
}
}
return nextV
})()
}
/>
</Col>
</Row>
</>
})}
</Panel>
</Collapse>
}
</Col>
</Row>
</>
)
})
} else {
let inspectContent = modelData.points.inspectContent
for (let v in inspectContent) {
inspectContent[v]?.checkItems?.map(k => {
dataArr.push(
<>
<Row>
<Col span={5} style={{}}>{k?.name} </Col>
<Col span={19}>
{
!k.level ? '正常' :
<Collapse ghost style={{ padding: 0 }}>
<Panel header="异常" key="1" style={{ padding: 0 }}>
<Row>
<Col span={4} style={{}}>巡查详情 </Col>
<Col span={20}>{k.msgInp}</Col>
<Col span={4} style={{}}>严重等级 </Col>
<Col span={20}>{k.level}</Col>
<Col span={4} style={{}}>现场照片 </Col>
<Col span={20}>
<Uploads
listType='picture-card'
uploadType='project'
maxFilesNum={1}
maxFileSize={10}
isQiniu={true}
disabled={true}
fileTypes={["png", "jpg"]}
defaultValue={
(() => {
let nextV = []
for (let s of (k.imgs || [])) {
if (s) {
nextV.push({
storageUrl: s
})
}
}
return nextV
})()
}
/>
</Col>
</Row>
</Panel>
</Collapse>
}
</Col>
</Row>
</>
)
})
}
}
}
return dataArr
})()}
</Modal>
</div>
)
}
function mapStateToProps(state) {
const { auth, global } = state;
return {
user: auth.user,
actions: global.actions,
};
}
export default connect(mapStateToProps)(PatrolRecord);

378
web-screen/client/src/sections/patrolManage/containers/patrolReport.js

@ -1,378 +0,0 @@
import React, { useState, useRef, useEffect } from 'react';
import { connect } from 'react-redux';
import { Button, Tabs, Popconfirm, Tooltip, Spin } from 'antd';
import ProTable from '@ant-design/pro-table';
import { getPatrolReport } from '../actions/report';
import { getProjectList } from '../actions/plan';
import moment from 'moment';
import AddReportRulesModal from '../components/addReportRulesModal';
function patrolReport(props) {
const { dispatch, actions } = props;
const { projectRegime, patrolManage } = actions
const tableRef = useRef();
const tableRef2 = useRef();
const [selectOpts, setSelectOpts] = useState([]);
const [date, setDate] = useState([moment().subtract(1, 'days'), moment()]);
const [dataSource, setDataSource] = useState([]);
const [modalVis, setModalVis] = useState(false)
const [structAll, setStructAll] = useState([])//完整的结构物列表(包括subType)
const [reportList, setReportList] = useState([])//报表
const qnDomain = localStorage.getItem('qnDomain');
const [query, setQuery] = useState({ limit: 10, page: 0 })
const [typeList, setTypeList] = useState([{ value: 1, label: '周报表' }, { value: 2, label: '月报表' }])
const [modalData, setModalData] = useState(null)
const [loading, setLoading] = useState(false)
//报表配置
// const getReportConfig = (query) => {
// const { limit, page, name } = query
// dispatch(patrolManage.getReportList({ limit, page, name })).then(res => {
// if (res.success) {
// //过滤管廊类型的数据
// const list = res.payload.data?.rows
// setReportList(list)
// }
// })
// }
//结构物
const projectList = () => {
dispatch(projectRegime.getProjectList()).then(res => {
if (res.success) {
const nextSelectOpts = res.payload?.data?.rows.map(d => {
return { label: d.name, value: d.id }
})
setStructAll(res.payload?.data?.rows)
setSelectOpts(nextSelectOpts)
// setStructlist(list)
}
})
}
useEffect(() => {
// dispatch(getProjectList()).then(res => {
// if (res.success) {
// }
// });
projectList()
// getReportConfig(query)
}, [])
const edithandler = (e) => {
setModalData(e)
setModalVis(true)
}
const onOk = () => {
tableRef2.current.reload();
}
const confirmHandler = (id) => {
dispatch(patrolManage.delReport(id)).then(res => {
if (res.success) {
// getReportConfig(query)
tableRef2.current.reload();
}
})
}
const generateReport = (record) => {
setLoading(true)
let data = {
reportName: record?.name,
startTime: moment(record?.startTime).format('YYYY-MM-DD HH:mm:ss'),
endTime: moment(record?.endTime).format('YYYY-MM-DD HH:mm:ss'),
structIds: record?.structure,
structNames: structAll?.filter(item => record?.structure.some(q => q == item.id))?.map(o => o.name) || [],
reportType: record?.type,
system: record?.system,
images: record?.reportpic.map(item => qnDomain + '/' + item) || []
}
dispatch(patrolManage.postGenerateReport(data)).then(res => {
if (res.success) {
setLoading(false)
tableRef.current.reload();
}
})
}
//删除巡检记录
const delReport = (id) => {
}
const columns = [{
title: '结构物名称',
dataIndex: 'projectName',
key: 'projectName',
valueType: 'select',
fieldProps: {
showSearch: true,
defaultValue: '',
options: [{ label: '全部', value: '' }, ...selectOpts],
},
ellipsis: true,
width: 150,
render: (_, record) => {
const rslt = structAll?.filter(p => record.structure?.some(q => q == p.id))
return <>
<div>{record?.project ? record?.project?.name : record.structure?.length > 1 ? <Tooltip title={rslt?.map(item => item.name)?.join(',')}>
<span>{rslt && rslt.length ? rslt[0].name + '...' : ''}</span>
</Tooltip> : rslt?.map(item => item.name)?.join(',')
}</div>
</>
}
}, {
title: '巡检报告名称',
dataIndex: 'groupName',
key: 'groupName',
ellipsis: true,
search: false,
width: 250,
render: (_, record) => {
const fileName = record?.excelPath?.substring(record?.excelPath?.lastIndexOf('/') + 1);
return <div>{fileName}</div>
}
}, {
title: '生成日期',
dataIndex: 'date',
key: 'date',
valueType: 'dateRange',
fieldProps: {
value: date,
onChange: e => { setDate(e) }
},
ellipsis: true,
width: 150,
render: (_, record) => {
return <div>{moment(record?.inspectTm).format('YYYY-MM-DD')}</div>
}
}, {
title: '操作',
dataIndex: 'action',
key: 'action',
search: false,
width: 200,
render: (_, record) => {
return <>
<Button type="link" onClick={() => {
window.open(`https://view.officeapps.live.com/op/view.aspx?src=${qnDomain}/${record?.excelPath}`)
}}>预览</Button>
{/* onClick={() => { window.open() }} */}
<a href={'/_file-server' + '/' + record?.excelPath}>下载</a>
<Popconfirm
placement='left'
title={`确定删除?`}
onConfirm={() => {
dispatch(patrolManage.delpatrolRecord(record?.id)).then(res=>{
if(res.success){
tableRef.current.reload();
}
})
}}
>
<Button type="link">删除</Button>
</Popconfirm>
</>
},
}];
const column2 = [
{
title: '报表名称',
dataIndex: 'name',
key: 'name',
ellipsis: true,
width: 250,
fieldProps: {
showSearch: true,
defaultValue: '',
},
},
{
title: '报表类型',
dataIndex: 'type',
key: 'type',
ellipsis: true,
search: false,
width: 250,
render: (_, record) => {
return <>
{typeList.find(item => record.type == item.value)?.label}
</>
}
},
{
title: '关联结构物',
dataIndex: 'structure',
key: 'structure',
ellipsis: true,
search: false,
width: 250,
render: (_, record) => {
const rslt = structAll?.filter(p => record.structure?.some(q => q == p.id))
return <>
{record.structure.length > 1 ? <Tooltip title={rslt?.map(item => item.name)?.join(',')}>
<span>{rslt && rslt.length ? rslt[0].name + '...' : ''}</span>
</Tooltip> : rslt?.map(item => item.name)?.join(',')}
</>
}
},
{
title: '生成时间范围',
key: 'timeRange',
// ellipsis: true,
search: false,
width: 250,
render: (_, record) => {
return <>
{moment(record.startTime).format('YYYY-MM-DD')} ~ {moment(record.endTime).format('YYYY-MM-DD')}
</>
}
},
{
title: '系统',
key: 'system',
// ellipsis: true,
search: false,
width: 250,
render: (_, record) => {
return <>
{record.system ? record.system === 1 ? '动力系统' : record.system === 2 ? '网络系统' : '--' : '--'}
</>
}
},
{
title: '操作',
key: 'option',
// ellipsis: true,
search: false,
width: 250,
render: (_, record) => {
return <>
<Button type="primary" style={{ marginRight: 10 }} onClick={() => { edithandler(record) }}>编辑</Button>
<Popconfirm title="确定删除报表吗"
description="确定删除报表吗?"
onConfirm={() => { confirmHandler(record?.id) }}
><Button type="primary" style={{ marginRight: 10 }} danger>删除</Button></Popconfirm>
<Button type="primary" onClick={() => { generateReport(record) }}>立即生成</Button>
</>
}
}
]
const onChange = (key) => {
};
const cancelHandle = () => {
setModalVis(false)
setModalData(null)
}
return (
<>
<Tabs
defaultActiveKey="1"
onChange={onChange}
items={[
{
label: `报表列表`,
key: '1',
children: <ProTable
columns={columns}
actionRef={tableRef}
options={false}
dataSource={dataSource || []}
rowKey='id'
pagination={{ pageSize: 10, size: 'default', className: 'global-pagination' }}
request={async (params = {}) => {
const res = await dispatch(getPatrolReport({
limit: params?.pageSize,
page: params?.current - 1,
projectId: params?.projectName,
startTime: date ? date[0].format('YYYY-MM-DD') + ' 00:00:00' : '',
endTime: date ? date[1].format('YYYY-MM-DD') + ' 23:59:59' : '',
}));
setDataSource(res?.payload.data?.rows);
return {
...res,
total: res.payload.data.count ? res.payload.data.count : 0,
};
}}
onReset={() => { setDate([moment().subtract(1, 'days'), moment()]) }}
rowClassName={(record, index) => {
let className = 'global-light-row';
if (index % 2 === 1) className = 'global-dark-row';
return className;
}}
/>,
},
{
label: `报表配置`,
key: '2',
children: <>
<Spin spinning={loading}>
<ProTable
actionRef={tableRef2}
options={false}
columns={column2}
dataSource={reportList || []}
pagination={{ pageSize: 10, size: 'default', className: 'global-pagination' }}
request={async (query) => {
const { limit, page, name } = query
const res = await dispatch(patrolManage.getReportList({ limit, page, name }))
const list = res?.payload?.data?.rows
setReportList(list)
return {
...res,
total: res.payload.data.count ? res.payload.data.count : 0,
};
}}
// cardProps={{ title: '新建报表规则', bordered: true }}
headerTitle={
<Button
key="primary"
type="primary"
onClick={() => {
setModalVis(true)
}}
>
新建报表规则
</Button>
}
rowKey="key"
search={true}
/>
</Spin>
<AddReportRulesModal structAll={structAll} typeList={typeList} modalData={modalData} onOk={onOk} visible={modalVis} cancelHandle={cancelHandle}>
</AddReportRulesModal>
</>
,
},
]}
/>
</>
)
}
function mapStateToProps(state) {
const { auth, structureList, global } = state
return {
user: auth.user,
struList: structureList.data || [],
struLoading: structureList.isRequesting,
actions: global.actions,
}
}
export default connect(mapStateToProps)(patrolReport);

136
web-screen/client/src/sections/patrolManage/containers/patrolTemplate.js

@ -1,136 +0,0 @@
import React, { useState, useRef, useEffect } from 'react';
import { connect } from 'react-redux';
import { Button, Popconfirm, Tag } from 'antd';
import ProTable from '@ant-design/pro-table';
import PlanTemplateModal from '../components/planTemplateModal';
import { createPatrolTemplate, delPatrolTemplate, updatePatrolTemplate, getPatrolTemplate } from '../actions/template';
import { getCheckItemsGroup } from '../actions/checkItems';
function PatrolTemplate(props) {
const { dispatch, user } = props;
const tableRef = useRef();
const [dataSource, setDataSource] = useState([{}]);
const [visible, setVisible] = useState(false);
const [type, setType] = useState();
const [curRecord, setCurRecord] = useState();
useEffect(() => {
dispatch(getCheckItemsGroup())
}, [])
const columns = [{
title: '模板名称',
dataIndex: 'name',
key: 'name',
ellipsis: true,
}, {
title: '模板描述',
dataIndex: 'describe',
key: 'describe',
ellipsis: true,
search: false,
}, {
title: '操作人',
dataIndex: 'user.name',
key: 'user.name',
ellipsis: true,
search: false,
render: (t, r, i) => {
return r.user ? r.user.name : '-'
}
}, {
title: '检查项',
dataIndex: 'checkItems',
key: 'checkItems',
ellipsis: true,
search: false,
render: (_, r) => {
return r?.checkItems ? r?.checkItems.map(c => <Tag>{c.name}</Tag>) : '-'
}
}, {
title: '操作',
dataIndex: 'action',
key: 'action',
search: false,
width: 200,
render: (_, record) => {
return <>
<Button type="link" onClick={() => {
setType('edit')
setCurRecord(record)
setVisible(true)
}}>修改</Button>
<Popconfirm
title="确认删除?"
onConfirm={() => {
dispatch(delPatrolTemplate(record.id)).then(res => {
if (res.success) {
tableRef.current.reload();
}
})
}}>
<Button type="link" danger disabled={record && record.patrolPlans && record.patrolPlans.length}>删除</Button>
</Popconfirm>
</>
},
}];
return (
<>
<ProTable
columns={columns}
actionRef={tableRef}
options={false}
dataSource={dataSource || []}
rowKey='id'
pagination={{ pageSize: 10, size: 'default', className: 'global-pagination' }}
search={{
defaultCollapsed: false,
optionRender: (searchConfig, formProps, dom) => [
...dom.reverse(),
<Button
type="primary"
key="primary"
onClick={() => {
setType('create')
setVisible(true)
}}
>新增巡检模板</Button>,
],
}}
request={async (params = {}) => {
const res = await dispatch(getPatrolTemplate(params));
setDataSource(res?.payload.data?.rows);
return { ...res };
}}
onReset={() => { }}
rowClassName={(record, index) => {
let className = 'global-light-row';
if (index % 2 === 1) className = 'global-dark-row';
return className;
}}
/>
{
visible ?
<PlanTemplateModal
visible={visible}
type={type}
curRecord={curRecord}
onCancel={() => {
setVisible(false);
setCurRecord({})
}}
tableRef={tableRef}
/> : null
}
</>
)
}
function mapStateToProps(state) {
const { auth } = state
return {
user: auth.user
}
}
export default connect(mapStateToProps)(PatrolTemplate);

300
web-screen/client/src/sections/patrolManage/containers/yujingguanli.js

@ -1,300 +0,0 @@
import React, { useState, useRef, useEffect } from 'react';
import { connect } from 'react-redux';
import { Button, Popconfirm, Tag,Tabs } from 'antd';
import ProTable from '@ant-design/pro-table';
import Xiafagaojin from '../components/xiafagaojin';
import {getDepUser} from '../../organization/actions/user'
import { createPatrolTemplate, delPatrolTemplate, updatePatrolTemplate, getPatrolTemplate } from '../actions/template';
import { getCheckItemsGroup } from '../actions/checkItems';
import moment from 'moment';
function YujingGuanli (props) {
const { dispatch, user,actions,depUser} = props;
const tableRef = useRef();
const format = 'YYYY-MM-DD HH:mm:ss'
const { patrolManage } = actions
const [dataSource, setDataSource] = useState([{}]);
const [dataSource2, setDataSource2] = useState([{}]);
const [visible, setVisible] = useState(false);
const [type, setType] = useState();
const [curRecord, setCurRecord] = useState();
const [tabs,settabs] = useState(1)
const [data,setdata]= useState([])
const [tableList, settableList] = useState([])
const [name, setName] = useState('');
const [curState, setCurState] = useState('全部');
const times = [moment().subtract(70, 'years').format(format), moment().format(format)]
const [search, setSearch] = useState({ name: null, time: [times[0], times[1]], state: 'null' })
const STATE_TEXT = { 1: '待制定计划', 2: '待审核', 3: '计划驳回', 4: '待维修', 5: '待验收', 6: '验收通过', 7: '验收不通过', }
const onChange = (key) => {
settabs(key)
};
const renderOptionText = (currentState) => {
let text = '待制定计划'
return STATE_TEXT[currentState] || text
}
const queryData = () => {
dispatch(patrolManage.records(`patrolRecord/all/${times[0]}/${times[1]}/true/null`)).then(res => {
if (res.success) {
console.log(res,'水平')
// res?.payload?.data?.map(i=>{
// if(obj[i?.points?.project?.id]){
// // if(obj[i?.points?.project?.id.toString()][i.pointId.toString()]){
// // obj[i?.points?.project?.id.toString()][i.pointId.toString()].ponintname=i.points?.itemData?.name
// // obj[i?.points?.project?.id.toString()][i.pointId.toString()].num=obj[i?.points?.project?.id.toString()][i.pointId.toString()].num+i?.patrolRecordIssueHandles[0]?.state==6?1:0
// // }else{
// // obj[i?.points?.project?.id.toString()][i.pointId.toString()].ponintname=i.points?.itemData?.name
// // obj[i?.points?.project?.id.toString()][i.pointId.toString()].num=i?.patrolRecordIssueHandles[0]?.state==6?1:0
// // }
// obj[i?.points?.project?.id]?.push({pointId:i.pointId,pointname:i.points.itemData.name})
// // i?patrolRecordIssueHandles[0]?.state==6
// obj[i?.points?.project?.id].num= obj[i?.points?.project?.id].num + i?.patrolRecordIssueHandles[0]?.state==6 ?1:0
// }else{
// obj[i?.points?.project?.id]={name:i?.points?.project?.name,num:i?.patrolRecordIssueHandles[0]?.state==6 ?1:0 }
// }
// console.log(obj,'obj')
// })
}
})
}
console.log(depUser,'depUser')
useEffect(() => {
dispatch(getDepUser())
queryData()
// dispatch(getCheckItemsGroup())
}, [])
// console.log(tableList,'tablist')
const columns = [{
title: '结构物名称',
dataIndex: 'name',
key: 'name',
// search: false,
ellipsis: true,
render: (t, r, i) => {
// console.log(r,'测试')
return r?.points?.project?.name
}
}, {
title: '点位名称',
dataIndex: 'pointname',
key: 'pointname',
search: false,
ellipsis: true,
render: (t, r, i) => {
// console.log(r,'测试')
return r?.points?.itemData?.name
}
}, {
title: '异常次数',
dataIndex: 'yanshoucishu',
key: 'yanshoucishu',
ellipsis: true,
search: false,
render: (t, r, i) => {
return r?.patrolRecordIssueHandles && r?.patrolRecordIssueHandles[0]?.yanshoucishu
}
}, {
title: '产生时间',
dataIndex: 'yujingshijian',
key: 'yujingshijia',
ellipsis: true,
search: false,
render: (_, r) => {
return r?.patrolRecordIssueHandles && moment(r?.patrolRecordIssueHandles[0]?.yujingshijian).format('YYYY-MM-DD HH:mm:ss')
}
}, {
title: '更新时间',
dataIndex: 'updatatime',
key: 'updatatime',
search: false,
ellipsis: true,
render: (_, r) => {
return r?.patrolRecordIssueHandles && moment(r?.patrolRecordIssueHandles[0]?.yanshoushijian).format('YYYY-MM-DD HH:mm:ss')
}
}, {
title: '操作',
dataIndex: 'action',
key: 'action',
search: false,
width: 200,
render: (_, record) => {
return <>
<Button type="link" onClick={() => {
setType('edit')
setCurRecord(record)
setVisible(true)
}}>下发告警</Button>
</>
},
}];
const columns1 = [{
title: '结构物名称',
dataIndex: 'name',
key: 'name',
// search: false,
ellipsis: true,
render: (t, r, i) => {
// console.log(r,'测试')
return r?.points?.project?.name
}
}, {
title: '点位名称',
dataIndex: 'pointname',
key: 'pointname',
search: false,
ellipsis: true,
render: (t, r, i) => {
// console.log(r,'测试')
return r?.points?.itemData?.name
}
}, {
title: '异常次数',
dataIndex: 'yanshoucishu',
key: 'yanshoucishu',
ellipsis: true,
search: false,
render: (t, r, i) => {
// console.log(r,'r')
return r?.patrolRecordIssueHandles && r?.patrolRecordIssueHandles[0]?.yanshoucishu
}
}, {
title: '下发时间',
dataIndex: 'yujingshijian',
key: 'yujingshijia',
ellipsis: true,
search: false,
render: (_, r) => {
return r?.patrolRecordIssueHandles && moment(r?.patrolRecordIssueHandles[0]?.yujingshijian).format('YYYY-MM-DD HH:mm:ss')
}
}];
return (
<>
<Tabs
activeKey={tabs}
onChange={onChange}
style={{marginLeft:'20px',marginRight:'20px'}}
items={[
{
label: `未告警`,
key: 1,
children: <ProTable
columns={columns}
actionRef={tableRef}
options={false}
dataSource={dataSource || []}
rowKey='id'
pagination={{ pageSize: 10 }}
// search={false}
request={async (params = {}) => {
// dispatch(patrolManage.records(`patrolRecord/all/${times[0]}/${times[1]}/true/null`)).then(res => {
// if (res.success) {
// console.log(res,'水平')
// const t1 = res?.payload?.data?.filter(i=>i.patrolRecordIssueHandles[0]?.isgaojing!==true&& i.patrolRecordIssueHandles[0]?.yanshoucishu>=3)
// }
// })
const res = await dispatch(patrolManage.records(`patrolRecord/all/${times[0]}/${times[1]}/true/null`));
const data = res?.payload?.data?.filter(i=>{
return i?.patrolRecordIssueHandles[0]?.yanshoucishu>2&&i?.patrolRecordIssueHandles[0]?.isgaojing!==true
&&res?.payload?.data?.filter(j=>j?.pointId===i?.pointId&&j?.points?.project?.id===i?.points?.project?.id
&&j?.patrolRecordIssueHandles[0]?.yujingshijian
&&i?.patrolRecordIssueHandles[0]?.yujingshijian
&&moment(i?.patrolRecordIssueHandles[0].yanshoushijian).valueOf()<moment(j?.patrolRecordIssueHandles[0]?.yanshoushijian).valueOf()
).length===0
})
// console.log(res,'res')
// console.log(data,'data')
// setDataSource(res?.payload?.data.filter(i=>i?.points?.project?.name.match(params.name)));
setDataSource(data.filter(i=>i?.points?.project?.name.match(params.name)));
}}
/>,
},
{
label: `已告警`,
key: 2,
children: <ProTable
columns={columns1}
actionRef={tableRef}
options={false}
dataSource={dataSource2 || []}
rowKey='id'
pagination={{ pageSize: 10 }}
// search={false}
request={async (params = {}) => {
const res = await dispatch(patrolManage.records(`patrolRecord/all/${times[0]}/${times[1]}/true/null`));
const data = res?.payload?.data?.filter(i=>{
return i?.patrolRecordIssueHandles[0]?.isgaojing===true&&i?.patrolRecordIssueHandles[0]?.yujingafchishu===null
// &&res?.payload?.data?.filter(j=>
// {
// return j?.pointId===i?.pointId
// &&j?.points?.project?.id===i?.points?.project?.id&&i?.patrolRecordIssueHandles[0]?.yujingshijian&&
// parseInt(moment(i?.patrolRecordIssueHandles[0].yujingshijian).format('YYYYMMDDHHMMSS'))<parseInt(moment(j?.patrolRecordIssueHandles[0]?.yujingshijian).format('YYYYMMDDHHMMSS'))
// }).length===0
})
console.log(data,'data')
setDataSource2(data.filter(i=>i?.points?.project?.name.match(params.name)).sort((a, b) => moment(b.patrolRecordIssueHandles[0].yanshoushijian).valueOf() - moment(a.patrolRecordIssueHandles[0].yanshoushijian).valueOf()));
}}
/>,
}
]}
/>
{
visible &&depUser.filter(i=>i.username&&i.email).length!==0 ?
<Xiafagaojin
visible={visible}
type={type}
curRecord={curRecord}
userlist={depUser.filter(i=>i.username&&i.email)}
onCancel={() => {
setVisible(false);
setCurRecord({})
}}
onHandle={async ()=>{
const res = await dispatch(patrolManage.records(`patrolRecord/all/${times[0]}/${times[1]}/true/null`));
const data2 = res?.payload?.data?.filter(i=>{
return i?.patrolRecordIssueHandles[0]?.isgaojing===true&&i?.patrolRecordIssueHandles[0]?.yujingafchishu===null
// &&res?.payload?.data?.filter(j=>
// {
// return j?.pointId===i?.pointId
// &&j?.points?.project?.id===i?.points?.project?.id&&i?.patrolRecordIssueHandles[0]?.yujingshijian&&
// parseInt(moment(i?.patrolRecordIssueHandles[0].yujingshijian).format('YYYYMMDDHHMMSS'))<parseInt(moment(j?.patrolRecordIssueHandles[0]?.yujingshijian).format('YYYYMMDDHHMMSS'))
// }).length===0
})
// console.log(data,'data')
const data = res?.payload?.data?.filter(i=>{
return i?.patrolRecordIssueHandles[0]?.yanshoucishu>2&&i?.patrolRecordIssueHandles[0]?.isgaojing!==true
&&res?.payload?.data?.filter(j=>j?.pointId===i?.pointId
&&j?.points?.project?.id===i?.points?.project?.id
&&moment(i?.patrolRecordIssueHandles[0].yanshoushijian).valueOf()<moment(j?.patrolRecordIssueHandles[0]?.yanshoushijian).valueOf()
).length===0
})
console.log(res,'res')
// setDataSource(res?.payload?.data.filter(i=>i?.points?.project?.name.match(params.name)));
setDataSource(data);
setDataSource2(data2.sort((a, b) => moment(b.patrolRecordIssueHandles[0].yanshoushijian).valueOf() - moment(a.patrolRecordIssueHandles[0].yanshoushijian).valueOf()));
settabs(2)
}}
tableRef={tableRef}
/> : null
}
</>
)
}
function mapStateToProps (state) {
const { auth, global ,depUser} = state
return {
user: auth.user,
actions: global.actions,
depUser: depUser.data || [],
}
}
export default connect(mapStateToProps)(YujingGuanli);

15
web-screen/client/src/sections/patrolManage/index.js

@ -1,15 +0,0 @@
'use strict';
import reducers from './reducers';
import routes from './routes';
import actions from './actions';
import { getNavItem } from './nav-item';
export default {
key: 'patrolManage',
name: '',
reducers: reducers,
routes: routes,
actions: actions,
getNavItem: getNavItem
};

34
web-screen/client/src/sections/patrolManage/nav-item.js

@ -1,34 +0,0 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Menu } from 'antd';
import { GatewayOutlined } from '@ant-design/icons';
import { Func } from '$utils';
const SubMenu = Menu.SubMenu;
export function getNavItem (user, dispatch) {
// if (!Func.isAuthorized("ORG_MANAGE")) {
// return null
// }
return (
Func.isAuthorized('PATROL_MANAGE') && <SubMenu key="patrolManage" icon={<img src='/assets/images/menu/xun.svg' style={{ width: 24, height: 24 }} />} title={'巡检管理'}>
{Func.isAuthorized('PATROL_PLAN_CONFIG') && <Menu.Item key="patrolPlan">
<Link to="/patrolManage/patrolPlan">巡检计划制定</Link>
</Menu.Item>}
{Func.isAuthorized('PATROL_RECORD_VIEW') && <Menu.Item key="patrolRecord">
<Link to="/patrolManage/patrolRecord">巡检记录</Link>
</Menu.Item>}
{Func.isAuthorized('CHECKREPORT') && <Menu.Item key="patrolReport">
<Link to="/patrolManage/patrolReport">巡检报告</Link>
</Menu.Item>}
{Func.isAuthorized('CHECKITEMSET') && <Menu.Item key="checkItems">
<Link to="/patrolManage/checkItems">检查项设定</Link>
</Menu.Item>}
{Func.isAuthorized('CHECKMOULD') && <Menu.Item key="patrolTemplate">
<Link to="/patrolManage/patrolTemplate">巡检模板</Link>
</Menu.Item>}
{ <Menu.Item key="yujingguanli">
<Link to="/patrolManage/yujingguanli">预警管理</Link>
</Menu.Item>}
</SubMenu>
);
}

5
web-screen/client/src/sections/patrolManage/reducers/index.js

@ -1,5 +0,0 @@
'use strict';
export default {
};

32
web-screen/client/src/sections/patrolManage/reducers/record.js

@ -1,32 +0,0 @@
'use strict';
import * as actionTypes from '../actions/record';
import Immutable from 'immutable';
const initState = {
data: {},
isRequesting: false,
error: null
};
function record(state = initState, action) {
const payload = action.payload;
switch (action.type){
case actionTypes.GET_PATROL_RECORD_LIST:
return Immutable.fromJS(state).set('data',
payload.data).toJS();
case actionTypes.GET_PATROL_RECORD_LIST_SUCCESS:
return Immutable.fromJS(state).merge({
isRequesting: false,
data: payload.data
}).toJS();
case actionTypes.GET_PATROL_RECORD_LIST_ERROR:
return Immutable.fromJS(state).merge({
isRequesting: false,
error: payload.error
}).toJS();
default:
return state;
}
}
export default record;

44
web-screen/client/src/sections/patrolManage/routes.js

@ -1,44 +0,0 @@
'use strict';
import { PatrolPlan, PatrolReocrd, PatrolReport, CheckItems, PlanTemplate ,YujingGuanli} from './containers';
export default [{
type: 'inner',
route: {
path: '/patrolManage',
key: 'patrolManage',
breadcrumb: '巡检管理',
childRoutes: [{
path: '/patrolPlan',
key: 'patrolPlan',
component: PatrolPlan,
breadcrumb: '巡检计划制定',
}, {
path: '/patrolRecord',
key: 'patrolRecord',
component: PatrolReocrd,
breadcrumb: '巡检记录',
}, {
path: '/patrolReport',
key: 'patrolReport',
component: PatrolReport,
breadcrumb: '巡检报告',
}, {
path: '/checkItems',
key: 'checkItems',
component: CheckItems,
breadcrumb: '检查项设定',
}, {
path: '/patrolTemplate',
key: 'patrolTemplate',
component: PlanTemplate,
breadcrumb: '巡检模板',
},
{
path: '/yujingguanli',
key: 'yujingguanli',
component: YujingGuanli,
breadcrumb: '预警管理',
}
]
}
}];

5
web-screen/client/src/sections/patrolManage/style.less

@ -1,5 +0,0 @@
.patrol-record-detail-modal {
.ant-collapse>.ant-collapse-item>.ant-collapse-header {
padding: 0
}
}

6
web-screen/client/src/sections/projectBinding/actions/index.js

@ -1,6 +0,0 @@
'use strict';
import projectBinding from './projectBinding'
export default {
...projectBinding
}

59
web-screen/client/src/sections/projectBinding/actions/projectBinding.js

@ -1,59 +0,0 @@
'use strict';
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
export function getanxinyunProject(data) {
return dispatch => basicAction({
type: 'post',
dispatch: dispatch,
data,
actionType: 'GET_ANXINYUN_PROJECT',
url: `${ApiTable.getanxinyunProject}`,
msg: { error: '获取安心云结构物失败' },
reducer: { name: 'anxinyunProject'}
});
}
export function addorEditRelation(data) {
return dispatch => basicAction({
type: 'post',
dispatch: dispatch,
data,
actionType: 'ADD_OR_EDIT_RELATION',
url: `${ApiTable.addorEditRelation}`,
msg: { option:data?.id? '编辑绑定关系':'新增绑定关系' },
// reducer: { name: 'anxinyunProject'}
});
}
export function getRelation(query) {
return dispatch => basicAction({
type: 'get',
query,
dispatch: dispatch,
actionType: 'GET_RELATION',
url: `${ApiTable.getRelation}`,
msg: { error:'查询项目映射关系失败' },
reducer: { name: 'relation'}
});
}
export function delRelation(id) {
return dispatch => basicAction({
type: 'delete',
dispatch: dispatch,
actionType: 'DEL_RELATION',
url: ApiTable.delRelation.replace('{id}', id),
msg: { option:'删除项目映射关系' },
// reducer: { name: 'anxinyunProject'}
});
}
export default{
getanxinyunProject,
getRelation,
addorEditRelation,
delRelation
}

88
web-screen/client/src/sections/projectBinding/components/relationModal.js

@ -1,88 +0,0 @@
import React, { useRef,useState,useEffect } from 'react'
import { Button, Form } from 'antd'
import { connect } from 'react-redux';
import { InfoCircleOutlined } from '@ant-design/icons'
import { ModalForm, ProFormSelect, ProFormText, ProFormDatePicker } from '@ant-design/pro-form'
import moment from 'moment'
function RelationModal(props) {
const { title, triggerRender, editData = null, onFinish, devices,actions,dispatch,proejctListOpt,structureListOpt } = props
const{projectBinding}=actions
const formItemLayout = { labelCol: { span: 6 }, wrapperCol: { span: 16 } }
const initialValues = editData? { ...editData,} : {}
const [form] = Form.useForm()
const formRef = useRef()
return (
<ModalForm
formRef={formRef}
title={title || ''}
initialValues={initialValues}
trigger={triggerRender ? triggerRender : <Button type='primary'>{title || ''}</Button>}
layout='horizontal'
grid={true}
{...formItemLayout}
modalProps={{
destroyOnClose: true,
onCancel: () => {},
}}
onFinish={async values => {
// console.log('values1',editData)
let value={
anxinyunProject:values?.anxinyunProject,
structName:values?.structName,
id:initialValues?initialValues.key:null
}
return onFinish && (await onFinish(value))
// return true;
}}
width={500}>
<ProFormSelect
rules={[{ required: true, message: '安心云结构物' }]}
showSearch
options={proejctListOpt?.map(s => {
return { label: s.label, value: s.value }
})}
name='anxinyunProject'
label='安心云结构物'
/>
<ProFormSelect
rules={[{ required: true, message: '关联结构物' }]}
showSearch
options={structureListOpt?.map(s => {
return { label: s.label, value: s.value }
})}
name='structName'
label='关联结构物'
/>
</ModalForm>
)
}
function mapStateToProps(state) {
const {auth, global, device } = state;
return {
loading: device.isRequesting,
clientHeight: global.clientHeight,
actions: global.actions,
};
}
export const DEVICE_TYPES = [
'安防系统',
'厨房系统',
'电梯',
'供电系统',
'空调',
'排水系统',
'水系统',
'通道门禁',
'通风系统',
'通信系统',
'显示视频',
'消防系统',
'照明系统',
]
export default connect(mapStateToProps)(RelationModal)

5
web-screen/client/src/sections/projectBinding/containers/index.js

@ -1,5 +0,0 @@
'use strict';
import ProjectBinding from './projectBinding'
export { ProjectBinding };

304
web-screen/client/src/sections/projectBinding/containers/projectBinding.js

@ -1,304 +0,0 @@
import React, { useEffect, useState, useRef, useMemo } from 'react'
import { Spin, Popconfirm, message, Button, Input, Select } from 'antd'
import { connect } from 'react-redux'
import ProTable from '@ant-design/pro-table'
import moment from 'moment'
import RelationModal from '../components/relationModal'
function ProjectBinding(props) {
const {loading, clientHeight, actions, dispatch, devices,anxinyunProjectLoading,relationLoading } = props
const { projectBinding, projectRegime } = actions
const tableRef = useRef()
const proTableFormRef = useRef()
const [proejctListOpt, setProjectListOpt] = useState([])//安心云结构物
const [structureListOpt, setStructureListOpt] = useState([])//巡检结构物
const [dataSource, setDataSource] = useState([])
// const [dataCopy,setDataCopy]=useState([])
const [tableParams, setTableParams] = useState({})
// const fetchData = async () => {
// let data={
// url:"users/{orgId}/projects",
// type:"get"
// }
// dispatch(projectBinding.getanxinyunProject(data)).then(async res=>{
// if(res.success){
// const d=res.payload.data?.map(item=>{
// return {
// label:item?.projects[0]?.name,
// value:item?.projects[0]?.id
// }
// })
// setProjectListOpt(d)
// const r2= await dispatch(projectRegime.getProjectList())
// const dp=r2.pauseStatemap(item=>{
// return {
// label:item?.name,
// value:item?.id
// }
// })
// setStructureListOpt(dp)
// const r= await dispatch(projectBinding.getRelation())
// const list = r?.payload?.data?.rows?.map(item=>{
// return {
// key: item.id,
// anxinyunProject:d?.find(q=>q.value===item.axyProjectId)?.label,
// structName:dp?.find(q=>q.value===item.structureId)?.label
// }
// })
// setDataSource(list)
// }
// })
// }
//初始化
useEffect(() => {
let data = {
url:'organizations/{orgId}/structures',
// url: 'users/{orgId}/projects',
type: 'get',
}
dispatch(projectBinding.getanxinyunProject(data)).then(res => {
if (res.success) {
const d = res.payload.data?.map(item => {
return {
label: item?.name,
value: item?.iotaThingId,
}
})
setProjectListOpt(d)
}
})
dispatch(projectRegime.getProjectList()).then(res => {
if (res.success) {
const dp = res.payload.data?.rows?.map(item => {
return {
label: item?.name,
value: item?.id,
}
})
setStructureListOpt(dp)
}
})
}, [])
const queryData = () => {
dispatch(projectBinding.getRelation()).then(res => {
if (res.success) {
const list = res?.payload?.data?.rows?.map(item => {
return {
key: item.id,
anxinyunProject: proejctListOpt?.find(q => q.value === item.axyProjectId)?.value,
structName: structureListOpt?.find(q => q.value === item.structureId)?.value,
}
})
setDataSource(list)
// setDataCopy(list)
}
})
}
useEffect(() => {
if (proejctListOpt && structureListOpt && proejctListOpt.length && structureListOpt.length) {
queryData()
}
}, [proejctListOpt, structureListOpt])
const onFinish = async values => {
const dataToSave = { axyProjectId: values?.anxinyunProject, structrueId: values?.structName, id: values?.id }
return dispatch(projectBinding.addorEditRelation(dataToSave)).then(res => {
if (res.success) {
queryData()
// tableRef.current.reload()
return true
} else {
return false
}
})
}
//删除按钮
const handleDelete = id => {
dispatch(projectBinding.delRelation(id)).then(res => {
if (res.success) {
queryData()
}
})
}
const filterOption = (input, option) => (option?.label ?? '').toLowerCase().includes(input.toLowerCase())
const columns = [
{
title: '安心云结构物',
dataIndex: 'anxinyunProject',
ellipsis: true,
valueType: 'select',
fieldProps: {
options: proejctListOpt,
},
renderFormItem: () => (
<Select
showSearch
// style={{paddingLeft:10}}
allowClear
placeholder='请选择'
options={proejctListOpt?.map(item => ({ label: item.label, value: item.value }))}
filterOption={filterOption}
optionFilterProp='children'></Select>
),
// fieldProps: {
// showSearch: true,
// defaultValue: '',
// },
// onFilter: (value, record) => record.name.includes(value),
// search:false
},
{
title: '结构物名称',
dataIndex: 'structName',
ellipsis: true,
valueType: 'select',
fieldProps: {
options: structureListOpt,
},
renderFormItem: () => (
<Select
showSearch
// style={{paddingLeft:10}}
allowClear
placeholder='请选择'
options={structureListOpt?.map(item => ({ label: item.label, value: item.value }))}
filterOption={filterOption}
optionFilterProp='children'></Select>
),
// fieldProps: {
// showSearch: true,
// defaultValue: '',
// },
// search:false
valueType: 'select',
fieldProps: {
options: structureListOpt,
},
},
{
title: '操作',
width: 160,
key: 'option',
valueType: 'option',
render: (text, record) => {
const options = []
options.push(
<RelationModal
proejctListOpt={proejctListOpt}
triggerRender={<a>修改映射关系</a>}
editData={record}
structureListOpt={structureListOpt}
title='修改映射关系'
onFinish={onFinish}
key='editModel'
/>
)
options.push(
<Popconfirm
key='del'
placement='top'
title='是否确认删除映射关系?'
onConfirm={() => handleDelete(record.key)}
okText='是'
cancelText='否'>
<a>删除</a>
</Popconfirm>
)
return options
},
},
]
// useMemo(()=>{
// })
const tableDatas = useMemo(() => {
const { anxinyunProject, structName } = tableParams
let rslt = dataSource
rslt = rslt
.filter(s => (anxinyunProject ? (s.anxinyunProject ? s.anxinyunProject === anxinyunProject : false) : true))
?.filter(s => (structName ? (s.structName ? s.structName === structName : false) : true))
return rslt
})
// const searchHandler=()=>{
// const anxinyunProject=proTableFormRef.current.getFieldsValue()?.anxinyunProject
// const structName=proTableFormRef.current.getFieldsValue()?.structName
// setDataSource(
// dataCopy.filter(f =>
// (!anxinyunProject || f.anxinyunProject?.includes(anxinyunProject)) &&
// (!structName || f?.structName === structName)
// )
// )
// }
return (
<Spin spinning={anxinyunProjectLoading||relationLoading}>
<div id='patrol-record' className='global-main'>
{/* <Spin spinning={loading}> */}
<div style={{ marginBottom: 19 }}>
<div className='top' style={{ marginBottom: 19 }}>
<div className='title'>
<span className='line'></span>
<span className='cn'>项目绑定</span>
<span className='en'>&nbsp;PROJECT</span>
</div>
<div></div>
</div>
</div>
<RelationModal
structureListOpt={structureListOpt}
proejctListOpt={proejctListOpt}
triggerRender={<Button type='primary'>新增</Button>}
title='新增映射关系'
onFinish={onFinish}
key='addModel'
/>
<ProTable
formRef={proTableFormRef}
rowKey='id'
options={false}
request={async params => {
setTableParams(params)
return {
data: [],
success: true,
}
}}
actionRef={tableRef}
columns={columns}
pagination={{ pageSize: 10, size: 'default', className: 'global-pagination' }}
dataSource={tableDatas || []}
search={{
labelWidth: 100,
}}
// search={{
// optionRender: ({searchText, resetText}, {form}, dom) => [
// <Button type="primary" onClick={searchHandler}>查询</Button>,
// ]
// }}
></ProTable>
{/* </Spin> */}
</div>
</Spin>
)
}
function mapStateToProps(state) {
const { auth, global, device,anxinyunProject, relation} = state
return {
loading: device.isRequesting,
clientHeight: global.clientHeight,
actions: global.actions,
relationLoading:relation.isRequesting,
anxinyunProjectLoading:anxinyunProject.isRequesting,
}
}
export default connect(mapStateToProps)(ProjectBinding)

0
web-screen/client/src/sections/projectBinding/containers/style.less

15
web-screen/client/src/sections/projectBinding/index.js

@ -1,15 +0,0 @@
'use strict';
import reducers from './reducers';
import routes from './routes';
import actions from './actions';
import { getNavItem } from './nav-item';
export default {
key: 'projectBinding',
name: '项目绑定',
reducers: reducers,
routes: routes,
actions: actions,
getNavItem: getNavItem
};

13
web-screen/client/src/sections/projectBinding/nav-item.js

@ -1,13 +0,0 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Menu } from 'antd';
import { Func } from '$utils';
export function getNavItem(user, dispatch) {
return (
<Menu.Item icon={<img src='/assets/images/menu/device.png' style={{ width: 24, height: 24 }} />}
key="projectBinding">
<Link to="/projectBinding">项目绑定</Link>
</Menu.Item>
);
}

5
web-screen/client/src/sections/projectBinding/reducers/index.js

@ -1,5 +0,0 @@
'use strict';
export default {
}

13
web-screen/client/src/sections/projectBinding/routes.js

@ -1,13 +0,0 @@
'use strict';
import { ProjectBinding } from './containers';
export default [{
type: 'inner',
route: {
path: '/projectBinding',
key: 'projectBinding',
breadcrumb: '项目绑定',
component: ProjectBinding,
}
}];

83
web-screen/client/src/sections/projectRegime/actions/graph.js

@ -1,83 +0,0 @@
'use strict';
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
export function getProjectGraph(projectId) {
return (dispatch) => basicAction({
type: 'get',
dispatch,
actionType: 'GET_PROJECT_PLANAR_GRAPH',
url: ApiTable.getProjectGraph.replace('{projectId}', projectId),
msg: { option: '获取结构物平面图' },
reducer: { name: 'projectGraph' }
});
}
export function createGraph(data) {
return (dispatch) => basicAction({
type: 'post',
data,
dispatch,
actionType: 'ADD_PROJECT_PLANAR_GRAPH',
url: ApiTable.createGraph,
msg: { option: '新增结构物平面图' },
});
}
export function updateGraph(id, data) {
return (dispatch) => basicAction({
type: 'post',
data,
dispatch,
actionType: 'UPDATE_PROJECT_PLANAR_GRAPH',
url: ApiTable.updateGraph.replace('{id}', id),
msg: { option: '修改结构物平面图' },
});
}
export function deleteGraph(id) {
return (dispatch) => basicAction({
type: 'del',
dispatch,
actionType: 'DELETE_PROJECT_GRAPH',
url: ApiTable.deleteGraph.replace('{id}', id),
msg: {
option: '删除结构物布设图',
},
});
}
export function getProjectPoints(projectId) {
return (dispatch) => basicAction({
type: 'get',
dispatch,
actionType: 'GET_PROJECT_ALL_POINTS',
url: ApiTable.getProjectPoints.replace('{projectId}', projectId),
msg: { option: '获取结构物所有点位' },
reducer: { name: 'projectAllPoints' }
});
}
export function getDeployPoints(pictureId) {
return (dispatch) => basicAction({
type: 'get',
dispatch,
actionType: 'GET_PROJECT_DEPLOY_POINTS',
url: ApiTable.getDeployPoints.replace('{pictureId}', pictureId),
msg: { option: '获取结构物平面图测点分布' },
reducer: { name: 'projectDeployPoints' }
});
}
export function setDeployPoints(pictureId, data) {
return (dispatch) => basicAction({
type: 'post',
data,
dispatch,
actionType: 'SET_PROJECT_DEPLOY_POINTS',
url: ApiTable.setDeployPoints.replace('{pictureId}', pictureId),
msg: { option: '结构物平面图点位布设' },
});
}

10
web-screen/client/src/sections/projectRegime/actions/index.js

@ -1,10 +0,0 @@
'use strict';
import * as projectSituation from './projectSituation'
import * as projectGraph from './graph'
export default {
...projectSituation,
...projectGraph
}

101
web-screen/client/src/sections/projectRegime/actions/projectSituation.js

@ -1,101 +0,0 @@
'use strict';
import { basicAction } from '@peace/utils'
import { ApiTable } from '$utils'
export function getProjectList (query) {
return (dispatch) => basicAction({
type: 'get',
query,
dispatch,
actionType: 'GET_PROJEECT_LIST',
url: ApiTable.getProjectList,
msg: { error: '获取结构物列表失败', },
});
}
export function postAddProject (data) {
return (dispatch) => basicAction({
type: 'post',
data,
dispatch,
actionType: 'POST_ADD_PROJECT',
url: ApiTable.postAddProject,
msg: { option: data?.id ? '编辑结构物' : '新增结构物', },
});
}
export function delProject (id) {
return (dispatch) => basicAction({
type: 'del',
dispatch,
actionType: 'DEL_PROJECT',
url: ApiTable.delProject.replace('{id}', id),
msg: {
option: '删除结构物',
},
});
}
export function addPosition (data, point) {
return (dispatch) => basicAction({
type: 'post',
data,
dispatch,
actionType: 'ADD_POSITION',
url: ApiTable.position,
msg: { option: point ? '二维码生成' : data?.id ? '编辑点位' : '新增点位', },
});
}
export function positionList (query) {
return (dispatch) => basicAction({
type: 'get',
query,
dispatch,
actionType: 'POSITION_LIST',
url: ApiTable.position,
msg: { error: '获取点位列表失败', },
reducer: { name: 'projectPoints' }
});
}
export function delPosition (id) {
return (dispatch) => basicAction({
type: 'del',
dispatch,
actionType: 'DEL_POSITION',
url: ApiTable.delPosition.replace('{id}', id),
msg: {
option: '删除点位',
},
});
}
export function qrCodeShow (query) {
return (dispatch) => basicAction({
type: 'get',
query,
dispatch,
actionType: 'GET_QR_CODE',
url: ApiTable.qrCodeShow,
msg: { error: '获取二维码列表失败', },
});
}
export function q () {
return (dispatch) => basicAction({
type: 'get',
dispatch,
actionType: 'GET_CODE',
url: ApiTable.q,
msg: { error: '获取二维码列表失败', },
});
}

57
web-screen/client/src/sections/projectRegime/components/pointDeploy/heatmap.js

@ -1,57 +0,0 @@
'use strict'
import React, { Component, PropTypes } from 'react';
import { DropTarget } from 'react-dnd';
import StationSpot from './station-spot';
const heatmapTarget = {
drop(props, monitor) {
//get item from station-spot.js
//item:{deployed, rect, spotInlist, info}
const item = monitor.getItem();
const move = monitor.getDifferenceFromInitialOffset();
props.onDeploySpot({ ...item, move });
}
};
function collect(connect, monitor) {
return {
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver()
};
}
class Heatmap extends React.Component {
componentDidMount() {
}
renderSpots() {
const { width, height, spots, onRemoveSpot } = this.props;
return spots.map(s => <StationSpot key={s.sensorId} info={s}
size={{ "width": width, "height": height }}
onRemoveSpot={onRemoveSpot} />);
}
render() {
const { connectDropTarget, height, width, image } = this.props;
let targetStyle = {
position: 'relative',
width: width,
// overflow:'hidden',
height: height,
background: `url("/_file-server/${image}") no-repeat`,
backgroundSize: '100% 100%',
};
return connectDropTarget(
<div id="dragTarget" style={targetStyle}>
{this.renderSpots()}
</div>
)
}
}
export default DropTarget('stationSpot', heatmapTarget, collect)(Heatmap);

114
web-screen/client/src/sections/projectRegime/components/pointDeploy/station-spot.js

@ -1,114 +0,0 @@
/**
* Created by yuanfenghua on 2018/6/18.
*/
'use strict'
import React, { Component } from 'react';
import { findDOMNode } from 'react-dom';
import { connect } from 'react-redux';
import { DragSource } from 'react-dnd';
import { Tooltip } from 'antd';
import { MinusOutlined } from '@ant-design/icons';
import Style from './style.css';
const stationSource = {
beginDrag(props, monitor, component) {
const dom = findDOMNode(component);
const rect = {
x: dom.offsetLeft - dom.offsetParent.scrollLeft,
y: dom.offsetTop - dom.offsetParent.scrollTop
};
const spotInlist = {
x: dom.getBoundingClientRect().left,
y: dom.getBoundingClientRect().top
};
return {
info: props.info,
rect: rect,
spotInlist: spotInlist,
deployed: props.info.deployed
};
},
endDrag(props, monitor) {
if (!monitor.didDrop() && props.onRemoveSpot) {
props.onRemoveSpot(monitor.getItem().info);
}
},
canDrag(props) {
if (props.size) {
//热点图上的热点可拖拽
return true;
} else {
//测点树未布设的叶结点可拖拽
return !props.children && props.info.deployed == false
}
},
};
function collect(connect, monitor) {
return {
connectDragSource: connect.dragSource(),
isDragging: monitor.isDragging()
}
}
class StationSpot extends React.Component {
constructor(props) {
super(props);
}
renderTreeTitle = () => {
const { isDragging, info } = this.props;
const { spotId, location, deployed } = info;
const opacity = isDragging ? 0.4 : 1;
return (
<span style={{ lineHeight: '15px', opacity }} className={Style['icon']}>
<span key={spotId}>
<Tooltip title={location}>
<span className={deployed == false ? Style['station-tree-node-normal'] : null}>{location.length >= 12 ? location.substring(0, 12) + "..." : location}</span>
</Tooltip>
{deployed ? <MinusOutlined type="minus-circle-o" className={Style['tip']} onClick={this.onRemoveSpot} /> : null}
</span>
</span>
);
};
onRemoveSpot = () => {
const { onRemoveSpot, info } = this.props;
if (onRemoveSpot) {
onRemoveSpot(info);
}
};
renderHotspot = () => {
const { info, size } = this.props;
const { key, location, x, y, screenWidth, screenHeight } = info;
const { width, height } = size;
let style = {
position: 'absolute',
left: width * x / screenWidth,
top: height * y / screenHeight,
cursor: 'move'
};
return <span style={style}>
<Tooltip title={location}>
<div style={{ height: 24, width: 24, borderRadius: '100%', backgroundColor: 'rgba(16,142,233,0.2)', padding: '5px' }}>
<div style={{ height: 14, width: 14, borderRadius: '100%', backgroundColor: '#108ee9', boxShadow: '0 0 10px #108ee9' }}></div>
</div>
</Tooltip>
</span>
};
render() {
const { connectDragSource, size } = this.props;
return connectDragSource(
size ? this.renderHotspot() : this.renderTreeTitle()
);
}
}
export default connect()(DragSource('stationSpot', stationSource, collect)(StationSpot));

91
web-screen/client/src/sections/projectRegime/components/pointDeploy/style.css

@ -1,91 +0,0 @@
.station-tree-node-normal{
margin-right: 6px;
padding: 0 4px;
height: 15px;
line-height: 15px;
background: #108ee9;
color: #fff;
font-size: 12px;
text-align: center;
}
.icon .tip{
margin-left:10px;
-webkit-transition:opacity 0.1s 0.2s;
opacity:0;
pointer-events:none;
}
.icon:hover .tip{
-webkit-transition:opacity 0.2s;
opacity:1;
pointer-events:auto;
}
.icon .tip:hover{
-webkit-transition:none;
}
:global(.no-card-border>.ant-card-head){
border: none;
}
.cardCoverBox{
position: absolute;
top: 50px;
left: 0;
right: 0;
bottom: 0;
}
.cardCover{
display: flex;
flex-direction: column;
justify-content: center;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
background-color: rgba(240 , 240, 240, 0.9);
z-index: 2;
}
.cardCover .btnCell{
text-align: center;
margin: 25px;
}
.cardFootCover{
display: flex;
justify-content: space-around;
align-items: center;
position: absolute;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.9);
z-index: 1;
opacity: 0;
}
.cardFootCover:hover{
opacity: 1;
}
.deleteBox{
margin: 0 40px;
}
.deleteBox h3{
text-align: center;
margin-bottom: 5px;
}
.deleteBox .btnRow{
display: flex;
justify-content: space-around;
margin-top: 10px;
width: 100%;
}
.loadingBox{
width: 100%;
margin-bottom: 50px;
text-align: center;
padding: 50px 0;
}

219
web-screen/client/src/sections/projectRegime/components/pointModel.js

@ -1,219 +0,0 @@
import React, { useState } from 'react';
import { Button, Form, Input, Modal, Select, DatePicker } from 'antd';
import { EnvironmentTwoTone } from '@ant-design/icons';
const { TextArea } = Input;
import { connect } from 'react-redux';
import Uploads from '$components/Uploads';
import { useEffect } from 'react';
import moment from 'moment';
const ProjectAddModel = ({ dispatch, actions, user, modelData, close, success, qrCodeId, devices }) => {
const { projectRegime } = actions
const [showBaiduMap, setShowBaiduMap] = useState(false)
const [form] = Form.useForm();
useEffect(() => {
if (modelData?.longitude && modelData?.latitude) {
form.setFieldValue('longitude', modelData?.longitude)
form.setFieldValue('latitude', modelData?.latitude)
}
var map = new AMap.Map('container', {
resizeEnable: true, //是否监控地图容器尺寸变化
zoom: 11, //初始化地图层级
center: [116.397428, 39.90923] //初始化地图中心点
});
var autoOptions = {
input: "tipinput"
};
AMap.plugin(['AMap.PlaceSearch', 'AMap.AutoComplete', 'AMap.Geocoder'], () => {
var auto = new AMap.AutoComplete(autoOptions);
var placeSearch = new AMap.PlaceSearch({
map: map
}); //构造地点查询类
function select(e) {
if (e) {
placeSearch.setCity(e.poi.adcode);
placeSearch.search(e.poi.name, function (status, result) {
form.setFieldValue('longitude', result.poiList.pois[0].location.lat)
form.setFieldValue('latitude', result.poiList.pois[0].location.lng)
}) //关键字查询查询
}
}
auto.on("select", select);//注册监听,当选中某条记录时会触发
map.on('click', function (e) { //点击地图获取经纬度
form.setFieldValue('longitude', e.lnglat.lat)
form.setFieldValue('latitude', e.lnglat.lng)
});
});
}, [])
return (
<Modal
title={modelData.id ? '编辑点位' : '新增点位'}
width={570}
open={true}
onOk={() => {
form.validateFields().then(r => {
dispatch(projectRegime.addPosition({
...r,
id: modelData?.id,
projectId: qrCodeId,
latitude: r?.latitude ? r?.latitude : null,
longitude: r?.longitude ? r?.longitude : null,
img: r.img ? r.img.map(u => u.storageUrl) : [],
})).then(res => {
if (res.success) {
success()
}
})
})
}}
onCancel={() => {
close()
}}
>
<Form
style={{}}
form={form}
labelAlign='right'
labelCol={{ span: 6 }} wrapperCol={{ span: 18 }}
onFinish={r => {
}}
initialValues={{
img: (modelData.img || []).map(s => {
return {
storageUrl: s
}
}),
}}
>
<Form.Item label='点位名称' name="name" style={{}}
initialValue={modelData?.name}
rules={[{ required: true, message: '必填,名称不能包含 \\ / : * ? " < > | #', pattern: new RegExp('^[^\\\\/|:*?\"<>#]+$') },]}
>
<Input placeholder="请输入点位名称" allowClear />
</Form.Item>
<div style={{ position: 'relative' }}>
{/* /^\d+$|^\d*\.\d+$/g */}
<Form.Item label="所在地区:" labelCol={{ span: 11 }} labelAlign='right' name="longitude" style={{ display: 'inline-block', width: 'calc(60% - 30px)', }}
rules={[{ required: false, message: '', }, {
validator: (rule, value, callback) => {
const sjh = /^\d+$|^\d*\.\d+$/g;
if (value) {
let valid = sjh.test(value);
if (!valid) {
return callback([new Error("横坐标填写错误")]);
}
callback();
}
// return callback([new Error("请输入横坐标")]);
return Promise.resolve();
}
}]}
>
<Input placeholder="经度支持数字" />
</Form.Item>
~
<Form.Item name="latitude" style={{ display: 'inline-block', width: 'calc(40% + 15px)', }}
rules={[{ required: false, message: '', }, {
validator: (rule, value, callback) => {
const sjh = /^\d+$|^\d*\.\d+$/g;
if (value) {
let valid = sjh.test(value);
if (!valid) {
return callback([new Error("纵坐标填写错误")]);
}
callback();
}
// return callback([new Error("请输入纵坐标")]);
return Promise.resolve();
}
}]}
>
<Input placeholder="维度支持数字" />
</Form.Item>
<EnvironmentTwoTone style={{ position: 'absolute', top: 5, right: 27, fontSize: 22 }} onClick={() => {
setShowBaiduMap(!showBaiduMap)
}} />
</div>
<Form.Item
label={"地址"}
name='location'
style={showBaiduMap ? { display: 'block' } : { display: 'none' }}
>
<Input id="tipinput" />
</Form.Item>
<Form.Item
label="地图"
name='map'
style={showBaiduMap ? { display: 'block' } : { display: 'none' }}
>
<div id="container" style={{ width: '100%', height: '425px', marginBottom: '15px' }}></div>
</Form.Item>
<Form.Item name='describe' label="描述"
initialValue={modelData?.describe}
rules={[{ required: true, message: '请输入描述内容', },]}>
<TextArea />
</Form.Item>
<Form.Item label='设备编号' name="equipmentNo" style={{}}
initialValue={modelData?.equipmentNo}>
<Input placeholder="请输入设备编号" allowClear />
</Form.Item>
<Form.Item label='设备型号' name="equipmentModel" style={{}}
initialValue={modelData?.equipmentModel}>
<Input placeholder="请输入设备型号" allowClear />
</Form.Item>
<Form.Item label='设备绑定' name="devices" style={{}}
initialValue={modelData?.pointDevices?.map(s => s?.deviceId) || []}>
<Select mode="multiple" showSearch filterOption={(input, option) => (option?.children ?? '').toLowerCase().includes(input.toLowerCase())}>
{
devices?.map(s => <Select.Option
disabled={s?.pointDevices?.length > 0 && !s?.pointDevices?.find(x => x.pointId == modelData?.id)}
value={s.id} >{s?.name}</Select.Option>)
}
</Select>
</Form.Item>
<Form.Item
label="点位图片"
name='img'
help={<div style={{ fontSize: 12 }}>说明请上传pngjpg格式图片图片大小不超过10M</div>}
>
<Uploads
listType='picture-card'
uploadType='project'
maxFilesNum={1}
maxFileSize={10}
isQiniu={true}
fileTypes={["png", "jpg"]}
defaultValue={(modelData.img || []).map(s => {
return {
storageUrl: s
}
})}
/>
</Form.Item>
</Form>
</Modal>
);
};
function mapStateToProps(state) {
const { auth, global } = state;
return {
user: auth.user,
actions: global.actions,
};
}
export default connect(mapStateToProps)(ProjectAddModel);

234
web-screen/client/src/sections/projectRegime/components/projectAddModel.js

@ -1,234 +0,0 @@
import React, { useState } from 'react';
import { Form, Input, Modal, Select, Row, Col } from 'antd';
// import { EnvironmentTwoTone } from '@ant-design/icons';
const { TextArea } = Input;
import { connect } from 'react-redux';
import Uploads from '$components/Uploads';
import { useEffect } from 'react';
// import moment from 'moment';
const type_options = [
{ value: '桥梁', label: '桥梁' },
{ value: '隧道', label: '隧道' },
{ value: '管廊', label: '管廊' },
{ value: '地灾', label: '地灾' },
]
const ProjectAddModel = ({ dispatch, actions, user, modelData, close, success, firmList }) => {
const { projectRegime } = actions
const [showBaiduMap, setShowBaiduMap] = useState(false)
const [type, setType] = useState(modelData?.type || type_options[0])
const [form] = Form.useForm();
useEffect(() => {
if (modelData?.longitude && modelData?.latitude) {
form.setFieldValue('longitude', modelData?.longitude)
form.setFieldValue('latitude', modelData?.latitude)
}
var map = new AMap.Map('container', {
resizeEnable: true, //是否监控地图容器尺寸变化
zoom: 11, //初始化地图层级
center: [116.397428, 39.90923] //初始化地图中心点
});
var autoOptions = {
input: "tipinput"
};
AMap.plugin(['AMap.PlaceSearch', 'AMap.AutoComplete', 'AMap.Geocoder'], () => {
var auto = new AMap.AutoComplete(autoOptions);
var placeSearch = new AMap.PlaceSearch({
map: map
}); //构造地点查询类
function select(e) {
if (e) {
placeSearch.setCity(e.poi.adcode);
placeSearch.search(e.poi.name, function (status, result) {
form.setFieldValue('longitude', result.poiList.pois[0].location.lng)
form.setFieldValue('latitude', result.poiList.pois[0].location.lat)
}) //关键字查询查询
}
}
auto.on("select", select);//注册监听,当选中某条记录时会触发
map.on('click', function (e) { //点击地图获取经纬度
form.setFieldValue('longitude', e.lnglat.lng)
form.setFieldValue('latitude', e.lnglat.lat)
});
});
}, [])
return (
<Modal
className="global-modal"
title={modelData?.id ? '编辑项目' : '新建项目'}
width={717}
open={true}
onOk={() => {
form.validateFields().then(v => {
dispatch(projectRegime.postAddProject({
...v,
img: v.img ? v.img.map(u => u.storageUrl) : [],
id: modelData?.id
})).then(res => {
if (res.success) {
success()
}
})
})
}}
onCancel={() => close()}
>
<Form
style={{}}
form={form}
labelAlign='right'
labelCol={{ span: 4 }} wrapperCol={{ span: 18 }}
onFinish={r => {
}}
initialValues={{
img: (modelData.img || []).map(s => {
return {
storageUrl: s
}
}),
describe: modelData?.describe,
}}
>
<div style={{ position: 'relative', display: 'flex' }}>
<Form.Item label='结构物名称' labelCol={{ span: 9 }} name="name" style={{ width: 369 }}
initialValue={modelData?.name}
rules={[{ required: true, message: '请输入结构物名称' },]}
>
<Input placeholder="请输入结构物名称" allowClear bordered={false} />
</Form.Item>
<Form.Item label='结构物类型' labelCol={{ span: 9 }} name="type" style={{ width: 254 }}
initialValue={modelData?.type || '桥梁'}
// rules={[{ required: true, message: '请选择结构物类型' },]}
>
<Select
onChange={value => { setType(value) }}
bordered={false}
allowClear
options={type_options}
/>
</Form.Item>
</div>
{type == '管廊' && <Form.Item label='子系统' name="subType"
initialValue={modelData?.subType || '指挥中心'}
rules={[{ required: true, message: '请选择子系统' }]}
>
<Select
bordered={false}
options={[
{ value: '指挥中心', label: '指挥中心' },
{ value: '管廊本体', label: '管廊本体' },
{ value: '电梯系统', label: '电梯系统' },
{ value: '供配电系统', label: '供配电系统' },
{ value: '防雷与接地系统', label: '防雷与接地系统' },
{ value: '燃气仓', label: '燃气仓' },
{ value: '给水仓', label: '给水仓' },
{ value: '电气仓', label: '电气仓' },
{ value: '安防系统', label: '安防系统' },
{ value: '高压电力仓', label: '高压电力仓' },
]}
/>
</Form.Item>}
<div style={{ position: 'relative' }}>
<Form.Item label="所在地区:" labelCol={{ span: 9 }} labelAlign='right' name="longitude" style={{ display: 'inline-block', width: 'calc(60% - 50px)', }}
rules={[{ required: true, message: '', }, {
validator: (rule, value, callback) => {
const sjh = /^\d+$|^\d*\.\d+$/g;
if (value) {
let valid = sjh.test(value);
if (!valid) {
return callback([new Error("横坐标填写错误")]);
}
callback();
}
return callback([new Error("请输入横坐标")]);
}
}]}
>
<Input placeholder="经度支持数字" bordered={false} />
</Form.Item>
&nbsp;&nbsp;
<Form.Item name="latitude" style={{ display: 'inline-block', width: 'calc(40% + 15px)', }}
rules={[{ required: true, message: '', }, {
validator: (rule, value, callback) => {
const sjh = /^\d+$|^\d*\.\d+$/g;
if (value) {
let valid = sjh.test(value);
if (!valid) {
return callback([new Error("纵坐标填写错误")]);
}
callback();
}
return callback([new Error("请输入纵坐标")]);
}
}]}
>
<Input placeholder="维度支持数字" bordered={false} />
</Form.Item>
<img src='/assets/images/show_map.svg' style={{ position: 'absolute', width: 28, top: 2, right: 47, cursor: 'pointer' }} onClick={() => {
setShowBaiduMap(!showBaiduMap)
}} />
</div>
<Form.Item
label={"地址"}
name='location'
style={showBaiduMap ? { display: 'block' } : { display: 'none' }}
>
<Input id="tipinput" bordered={false} />
</Form.Item>
<Form.Item
label="地图"
name='map'
style={showBaiduMap ? { display: 'block' } : { display: 'none' }}
>
<div id="container" style={{ width: '100%', height: '425px', marginBottom: '15px' }}></div>
</Form.Item>
<Form.Item name='describe' label="描述">
<TextArea bordered={false} />
</Form.Item>
<Form.Item
label="结构物图片"
name='img'
help={<div style={{ fontSize: 12 }}>说明请上传pngjpg格式图片图片大小不超过5M建议图片宽高比16:9</div>}
// rules={[{ required: true, message: '请上传图片', },]}
>
<Uploads
// className='upload'
listType='picture-card'
uploadType='project'
maxFilesNum={1}
maxFileSize={5}
isQiniu={true}
// onChange={vsjunct}
fileTypes={["png", "jpg"]}
// value={editUrl}
defaultValue={(modelData.img || []).map(s => {
return {
storageUrl: s
}
})}
/>
</Form.Item>
</Form>
</Modal>
);
};
function mapStateToProps(state) {
const { auth, global } = state;
return {
user: auth.user,
actions: global.actions,
};
}
export default connect(mapStateToProps)(ProjectAddModel);

9
web-screen/client/src/sections/projectRegime/containers/index.js

@ -1,9 +0,0 @@
'use strict';
import QrCode from './qrCode'
import Information from './information'
import Point from './point'
import PointDeploy from './pointDeploy/default'
export { QrCode, Information, Point, PointDeploy };

251
web-screen/client/src/sections/projectRegime/containers/information.js

@ -1,251 +0,0 @@
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { Form, Input, Button, Table, Modal, Popconfirm, Tooltip } from 'antd';
import '../style.less';
import { push } from 'react-router-redux';
import ProjectAddModel from '../components/projectAddModel'
import './information.less';
const Information = (props) => {
const { dispatch, actions, user, loading } = props
const { projectRegime } = actions
const [firmList, setFirmList] = useState([])
const [tableList, settableList] = useState([])
const [addModel, setAddModel] = useState(false)
const [modelData, setModelData] = useState({})
const [query, setQuery] = useState({ limit: 10, page: 0 })
const [limits, setLimits] = useState()
const [search, setSearch] = useState({})
const [isPicture, setIsPicture] = useState(false)
const [pictureUrl, setPictureUrl] = useState()
const [companyID, setCompanyId] = useState('')
const [select, setSelect] = useState([])
// var QRCode = require('qrcode')
useEffect(() => {
projectList(query)
}, [])
const projectList = (obj) => {
const { limit, page, name } = obj
dispatch(projectRegime.getProjectList({ limit, page, name, })).then(res => {
// console.log(res)
if (res.success) {
settableList(res.payload.data?.rows?.map(v => ({ ...v, key: v.id })))
setLimits(res.payload.data?.count)
}
})
}
// const createQrCode = (name) => {
// let url = ''
// QRCode.toDataURL(name, {
// errorCorrectionLevel: 'low',
// type: 'image/png',
// quality: 0.3,
// margin: 2,
// maskPattern: 9,
// width: 400,
// color: {
// dark: "#000000ff",
// light: "#ffffffff"
// }
// }, function (err, v) {
// url = v
// })
// return url
// }
const columns = [
{
title: '序号',
dataIndex: 'index',
key: 'index',
render: (text, record, index) => index + 1
}, {
title: '结构物名称',
dataIndex: 'name',
key: 'name',
}, {
title: '所在地区',
dataIndex: 'type',
key: 'type',
render: (text, record, index) => {
return record.longitude && record.latitude ? <div style={{ width: 100 }}>{record.longitude},{record.latitude}</div> : "--"
}
}, {
title: '结构物类型',
dataIndex: 'type',
key: 'type',
render: (text, record, index) => record.type || '--'
}, {
title: '描述',
dataIndex: 'describe',
key: 'describe',
render: (text, record, index) => record.describe?.length>10?<Tooltip title={record.describe}><span>
{record?.describe.substring(0,10)}...
</span>
</Tooltip>: record.describe || '--'
}, {
title: '操作',
dataIndex: 'operation',
key: 'operation',
render: (text, record, index) => {
return (
<div>
<Button type="link" onClick={() => {
setAddModel(true)
setModelData(record)
}}
>编辑</Button>
<Popconfirm
title={<div style={{ width: 180 }}>删除此结构物后与结构物对应的点位巡检计划巡检记录也会删除是否确认删除</div>}
position='topLeft'
onConfirm={() => {
dispatch(projectRegime.delProject(record.id)).then(res => {
if (res.success) {
if ((limits > 11 && tableList.length > 1) || limits < 11) {
projectList({ ...query, ...search })
} else {
projectList({ limit: query?.limit, page: query?.page - 1, ...search })
setQuery({ limit: query?.limit, page: query?.page - 1 });
}
}
})
}}
>
<Button type="link" danger >删除</Button>
</Popconfirm>
{/* <Button type="link" danger >二维码生成</Button> */}
<Button type="link" onClick={() => {
dispatch(push(`/projectRegime/information/${record.id}/point`));
}} >点位</Button>
<Button type="link" onClick={() => {
dispatch(push(`/projectRegime/information/${record.id}/deploy`));
}} >布设</Button>
</div>
)
}
}
]
return (
<div className='global-main'>
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<div className='title'>
<span className='line'></span>
<span className='cn'>结构物</span>
<span className='en'>&nbsp;Structure</span>
</div>
<div className='flex-end'>
<Form
style={{ display: 'flex' }}
onFinish={r => {
projectList({ limit: 10, page: 0, ...r, companyId: companyID || r?.companyId })
setQuery({ limit: 10, page: 0 });
setSearch(r)
}}
>
<Form.Item
label='结构物名称'
name="name"
style={{ marginRight: 16, minWidth: 180 }}
>
<Input placeholder="请输入结构物名称" allowClear suffix={<img src='/assets/images/search.svg' style={{ width: 16 }} />} />
</Form.Item>
<Form.Item wrapperCol={{}}>
<Button htmlType="submit">
搜索
</Button>
</Form.Item>
</Form>
<div style={{ display: 'flex', marginLeft: 20 }}>
<Button type="primary" onClick={() => {
setAddModel(true)
}}>新建结构物</Button>
{/* <Button type="primary" style={{ marginLeft: 20 }} onClick={() => {
console.log(45513);
setAddModel(true)
}}>一键生成二维码</Button> */}
</div>
</div>
</div>
<Table
columns={columns}
dataSource={tableList}
pagination={{
className: 'global-pagination',
current: query.page + 1,
total: limits,
showSizeChanger: true,
showQuickJumper: true,
pageSizeOptions: [10, 20, 50],
showTotal: (total) => {
return <span style={{ fontSize: 15 }}>{`${Math.ceil(total / query?.limit)}页,${total}`}</span>
},
onChange: (page, pageSize) => {
setQuery({ limit: pageSize, page: page - 1 });
projectList({ limit: pageSize, page: page - 1, ...search, companyId: companyID || search?.companyId })
}
}}
rowSelection={{
selectedRowKeys: select || [],
onChange: (selectedRowKeys, selectedRows) => {
setSelect(selectedRowKeys)
console.log(selectedRowKeys, selectedRows);
}
}}
rowClassName={(record, index) => {
let className = 'global-light-row';
if (index % 2 === 1) className = 'global-dark-row';
return className;
}}
// scroll={{ y: 590 }}
/>
{
<Modal
// title={ }
width={570}
open={isPicture}
onOk={() => { }}
footer={null}
onCancel={() => {
setIsPicture(false)
setPictureUrl('')
}}
>
{pictureUrl && pictureUrl[0] ? <img src={`/_file-server/${pictureUrl}`} width={500} /> : "暂无图片"}
</Modal>
}
{
addModel ?
<ProjectAddModel
firmList={firmList}
modelData={modelData}
close={() => {
setAddModel(false)
setModelData({})
}}
success={() => {
setAddModel(false)
setModelData({})
setQuery({ limit: 10, page: 0 });
projectList({ limit: 10, page: 0, ...search, companyId: companyID || search?.companyId })
}}
/> : ""
}
</div>
)
}
function mapStateToProps(state) {
const { auth, global } = state;
return {
user: auth.user,
actions: global.actions,
};
}
export default connect(mapStateToProps)(Information);

30
web-screen/client/src/sections/projectRegime/containers/information.less

@ -1,30 +0,0 @@
.title {
background-color: #fff;
display: inline-block;
.line {
display: inline-block;
width: 3px;
height: 20px;
background: #006BE3;
}
.cn {
font-family: YouSheBiaoTiHei;
font-size: 24px;
color: #101531;
margin-left: 11px;
}
.en {
font-family: D-DINExp-Italic;
font-weight: Italic;
font-size: 12px;
color: #969799;
}
}
.flex-end {
display: flex;
justify-content: flex-end;
}

196
web-screen/client/src/sections/projectRegime/containers/point.js

@ -1,196 +0,0 @@
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { Button, Table, Popconfirm, Input } from 'antd';
import '../style.less';
import PointModel from '../components/pointModel'
const Information = (props) => {
const { dispatch, actions, devices } = props
const { projectRegime } = actions
const [tableList, settableList] = useState([])
const [addModel, setAddModel] = useState(false)
const [modelData, setModelData] = useState({})
const [query, setQuery] = useState({ limit: 10, page: 0 })
const [limits, setLimits] = useState()
const [search, setSearch] = useState({})
const [companyID, setCompanyId] = useState('')
const [select, setSelect] = useState([])
const [selec, setSelec] = useState()
const [qrCodeingIds, setQrCodeingIds] = useState(null)
const [searchTableList, setSearchTableList] = useState([])
const [name, setName] = useState('')
const qrCodeId = props?.match?.params?.id
useEffect(() => {
projectList(query)
}, [])
const projectList = (obj) => {
const { limit, page } = obj
dispatch(actions.deviceManage.getDeviceList());
dispatch(projectRegime.positionList({ limit, page: 0, projectId: qrCodeId })).then(res => {
if (res.success) {
let data = []
res.payload.data?.rows?.map(v => {
v.points?.map(r => {
data?.push(r)
})
})
settableList(data?.map(v => ({ ...v, key: v.id })))
setSearchTableList(data?.map(v => ({ ...v, key: v.id })))
setLimits(res.payload.data?.count)
}
})
}
const columns = [
{
title: '序号',
dataIndex: 'index',
key: 'index',
render: (text, record, index) => index + 1
}, {
title: '点位名称',
dataIndex: 'name',
key: 'name',
}, {
title: '所在地区',
dataIndex: 'position',
key: 'position',
render: (text, record, index) => {
return record.longitude && record.latitude ? <div style={{ width: 100 }}>{record.longitude},{record.latitude}</div> : "--"
}
}, {
title: '描述',
dataIndex: 'describe',
key: 'describe',
render: (text, record, index) => record.describe || '--'
}, {
title: '操作',
dataIndex: 'operation',
key: 'operation',
render: (text, record, index) => {
return (
<>
<Button type="link" onClick={() => {
setAddModel(true)
setModelData(record)
}}>编辑</Button>
<Popconfirm
title={<div style={{ width: 184 }}>删除该点位后与巡检计划关联的点位删除对应的巡检记录删除是否确认删除</div>}
position='topLeft'
onConfirm={() => {
dispatch(projectRegime.delPosition(record.id)).then(res => {
if (res.success) {
if ((limits > 11 && tableList.length > 1) || limits < 11) {
projectList({ ...query, ...search })
} else {
projectList({ limit: query?.limit, page: query?.page - 1, ...search })
setQuery({ limit: query?.limit, page: query?.page - 1 });
}
}
})
}}
>
<Button type="link" danger >删除</Button>
</Popconfirm>
<Button type="link" onClick={() => {
setQrCodeingIds([record.id])
dispatch(projectRegime.addPosition({
qrCode: true,
id: record.id,
}, true)).then(() => {
setQrCodeingIds(null)
})
}} loading={qrCodeingIds?.includes(record.id)}>二维码生成</Button>
</>
)
}
}
]
return (
<>
<img src={selec} />
<div style={{ display: 'flex', marginBottom: 10 }}>
<Button type="primary" onClick={() => {
setAddModel(true)
}}>新建点位</Button>
<Button type="primary" style={{ marginLeft: 20 }} onClick={() => {
if (select.length) {
setQrCodeingIds(select.map(s => s.id));
select?.map((v, i) => {
dispatch(projectRegime.addPosition({
qrCode: true,
id: v.id,
}, true)).then(() => {
if (i === select.length - 1) {
setQrCodeingIds(null);
}
})
})
}
}} disabled={qrCodeingIds?.length}>一键生成二维码</Button>
<Input style={{ width: 300, margin: '0px 20px' }} placeholder="请输入点位名称" onChange={(e) => { setName(e.target.value) }} />
<Button type="primary" onClick={() => {
setSearchTableList(tableList?.filter(l => l.name?.includes(name)))
}}>搜索</Button>
</div>
<Table
columns={columns}
dataSource={searchTableList}
pagination={{
// current: query.page + 1,
// total: limits,
showSizeChanger: true,
showQuickJumper: true,
pageSizeOptions: [10, 20, 50],
showTotal: (total) => {
return <span style={{ fontSize: 15 }}>{`${Math.ceil(total / query?.limit)}页,${total}`}</span>
},
onChange: (page, pageSize) => {
setQuery({ limit: pageSize, page: page - 1 });
projectList({ limit: pageSize, page: page - 1, ...search, companyId: companyID || search?.companyId })
}
}}
rowSelection={{
selectedRowKeys: select?.map(v => v.id) || [],
onChange: (selectedRowKeys, selectedRows) => {
setSelect(selectedRows)
}
}}
/>
{
addModel ?
<PointModel
modelData={modelData}
qrCodeId={qrCodeId}
devices={devices}
close={() => {
setAddModel(false)
setModelData({})
}}
success={() => {
setAddModel(false)
setModelData({})
setQuery({ limit: 10, page: 0 });
projectList({ limit: 10, page: 0 })
}}
/> : ""
}
</>
)
}
function mapStateToProps(state) {
const { auth, global, device } = state;
return {
user: auth.user,
actions: global.actions,
devices: device?.data?.rows || []
};
}
export default connect(mapStateToProps)(Information);

404
web-screen/client/src/sections/projectRegime/containers/pointDeploy/default.js

@ -1,404 +0,0 @@
'use strict'
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { findDOMNode } from 'react-dom';
import Heatmap from '../../components/pointDeploy/heatmap';
import { DragDropContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import { Layout, Tree, Button, Input, Popconfirm, message, Spin } from 'antd'
const { Content, Sider } = Layout;
const Search = Input.Search;
const TreeNode = Tree.TreeNode;
import StationSpot from '../../components/pointDeploy/station-spot';
import './deploy-style.less';
import { getProjectGraph, deleteGraph, getProjectPoints, getDeployPoints, setDeployPoints } from '../../actions/graph';
import UploadImgModal from './upload-img-modal';
import PerfectScrollbar from 'perfect-scrollbar';
class ConfigPlanarGraph extends Component {
constructor(props) {
super(props);
this.ps = null;
this.state = {
uploadImgModal: '',
searchValue: '',
deployState: -1, //0未布,1已布,-1全部
filteredSpots: [],
spots: [],
dataHasChanged: false,
}
this.projectId = props?.match?.params?.id
}
componentDidUpdate() {
let ele = document.getElementById('security-spots-scroller');
if (ele) {
this.ps = new PerfectScrollbar(ele);
}
}
componentDidMount() {
this.props.dispatch(getProjectPoints(this.projectId));//获取所有点位列表
this.getData();
}
getData = () => {
this.props.dispatch(getProjectGraph(this.projectId)).then(_ => {
if (_.success) {
let graph = _.payload.data;
if (graph) {//有图片
this.props.dispatch(getDeployPoints(graph.id));//获取平面图点位分布
}
}
});
}
componentWillReceiveProps(nextProps) {
const { allPoints, projectDeployPoints } = nextProps;
if (projectDeployPoints && projectDeployPoints != this.props.projectDeployPoints) {
this.setSpotsState(allPoints, projectDeployPoints);
}
}
setSpotsState = (allPoints, projectDeployPoints) => {
const { searchValue } = this.state;
let deployedSpotsMap = new Map();
projectDeployPoints?.forEach(s => {
deployedSpotsMap.set(s.pointId, s);
});
let tempData = [];
allPoints?.map(m => {
let x = null, y = null, screenH = null, screenW = null;
let deployed = false;
let station = deployedSpotsMap.get(m.id);
if (station) {
let p = JSON.parse(station.position);
x = p.x;
y = p.y;
screenH = p.screenHeight;
screenW = p.screenWidth;
deployed = true;
}
tempData.push({
groupId: 1,
groupName: '全部',
pointId: m.id,
location: m.name,
x: x,
y: y,
screenHeight: screenH,
screenWidth: screenW,
deployed: deployed,
})
});
let searchSpots = tempData;
if (searchValue.trim().length > 0) {
searchSpots = tempData.filter(s => s.location.indexOf(searchValue) >= 0);
}
this.setState({
spots: tempData,
filteredSpots: searchSpots,
});
}
onAddImgClick = () => {
this.openPcrModal(null)
};
editHandler = (heatmap) => {
this.openPcrModal(heatmap)
};
openPcrModal = (heatmap) => {
const { dispatch } = this.props;
this.setState({
uploadImgModal: <UploadImgModal
dispatch={dispatch}
projectId={this.projectId}
pictureInfo={heatmap}
onCancel={this.closeUploadPointsImgModal}
getData={this.getData}
/>,
})
}
closeUploadPointsImgModal = () => {
this.setState({ uploadImgModal: '' })
};
onDeploySpot = (spot) => {
const { pictureInfo, clientHeight, clientWidth } = this.props;
const { spots, deployState, searchValue, partsSpots } = this.state;
const that = this;
let h = clientHeight / 1.3;
let w = clientWidth / 1.4;
function dealPosition(spot, item) {
if (spot.deployed) {
item.x = spot.rect.x + spot.move.x;
item.y = spot.rect.y + spot.move.y;
item.screenHeight = h;
item.screenWidth = w;
} else {
const boundingClientRect = findDOMNode(that.refs.heatmapComponent).getBoundingClientRect();
item.x = spot.spotInlist.x + spot.move.x - boundingClientRect.left;
item.y = spot.spotInlist.y + spot.move.y - boundingClientRect.top;
item.screenHeight = h;
item.screenWidth = w;
item.deployed = true;
}
}
if (pictureInfo) {
let tempSpots = Object.assign([], spots);
if (spot.info.pointId) {
tempSpots.forEach(item => {
if (item.pointId == spot.info.pointId) {
dealPosition(spot, item)
}
});
}
this.setState({ spots: tempSpots });
this.filterSpots(deployState, searchValue);
this.setState({ changedTreeNodeKey: spot.info.key, dataHasChanged: true });
}
};
filterSpots = (deployState, searchValue) => {
let deploySpots = this.state.spots;
if (deployState != -1) {
deploySpots = this.state.spots.filter(s => s.deployed == (deployState == 1 ? true : false));
}
let searchSpots = deploySpots;
if (searchValue.trim().length > 0) {
searchSpots = deploySpots.filter(s => s.location.indexOf(searchValue) >= 0);
}
this.setState({
searchValue,
deployState,
filteredSpots: searchSpots
});
};
onSearch = (searchValue) => {
this.filterSpots(this.state.deployState, searchValue);
};
handleStateChange = (deployState) => {
this.filterSpots(deployState, this.state.searchValue);
};
onRemoveSpot = (spot) => {
const { pictureInfo } = this.props;
const { spots, deployState, searchValue, partsSpots } = this.state;
if (pictureInfo) {
let tempSpots;
if (spot.pointId) {
tempSpots = Object.assign([], spots);
tempSpots.forEach(item => {
if (item.pointId == spot.pointId) {
item.x = null;
item.y = null;
item.screenWidth = null;
item.screenHeight = null;
item.deployed = false;
}
});
tempSpots = tempSpots.concat(partsSpots)
} else {
tempSpots = Object.assign([], partsSpots);
tempSpots.forEach(item => {
if (item.partId == spot.partId) {
item.x = null;
item.y = null;
item.screenWidth = null;
item.screenHeight = null;
item.deployed = false;
}
});
tempSpots = tempSpots.concat(spots)
}
this.filterSpots(deployState, searchValue);
this.setState({ changedTreeNodeKey: spot.key, dataHasChanged: true });
}
};
loop = (data) => {
if (!data || data.length == 0) return;
const treeNodes = [];
data.forEach((item) => {
let title = <StationSpot info={item} children={item.children} />;
if (item.children) {
treeNodes.push(
<TreeNode key={item.key} title={title}>
{this.loop(item.children)}
</TreeNode>
);
} else {
let titleProps = {
info: item,
children: item.children,
onRemoveSpot: this.onRemoveSpot,
};
//性能优化,减少组件渲染
if (this.state.changedTreeNodeKey == item.key) titleProps.key = Math.random();
let nodeTitle = <StationSpot {...titleProps} />;
treeNodes.push(<TreeNode key={item.key} title={nodeTitle} />);
}
});
return treeNodes;
};
formatTreeSource = (data) => {
if (!data || data.length == 0) return;
let tempGroups = new Map();
data.map(item => {
if (tempGroups.has(item.groupId)) {
let groupChildren = tempGroups.get(item.groupId).children;
item.key = `0-${item.groupId}-${item.pointId}`;
groupChildren.set(item.pointId, item);
} else {
tempGroups.set(item.groupId, {
'key': `0-${item.groupId}`,
'location': item.groupName,
'groupId': item.groupId,
'children': new Map(),
});
let groupChildren = tempGroups.get(item.groupId).children;
item.key = `0-${item.groupId}-${item.pointId}`;
groupChildren.set(item.pointId, item);
}
});
return tempGroups;
};
onSaveClick = () => {
this.saveHotspots(this.state.spots);
};
saveHotspots = (data) => {
const { pictureInfo } = this.props;
let postData = data.filter(s => s.x != null && s.y != null).map(item => {
const { x, y, screenWidth, screenHeight } = item;
let relativeX = parseFloat((x / screenWidth).toFixed(4));
let relativeY = parseFloat((y / screenHeight).toFixed(4));
if (item.pointId) {
return ({
pointId: item.pointId,
position: { x, y, screenWidth, screenHeight, relativeX, relativeY }
})
}
});
this.props.dispatch(setDeployPoints(pictureInfo.id, { "spots": postData })).then(res => {
this.setState({ dataHasChanged: false, deployState: -1 }, () => {
this.props.dispatch(getDeployPoints(pictureInfo.id));//获取平面图点位分布
});
});
};
render() {
const { pictureInfo, clientHeight, clientWidth, allPoints } = this.props;
const { deployState, spots, filteredSpots, dataHasChanged } = this.state;
const treeDataSource = this.formatTreeSource(filteredSpots);
let h = clientHeight / 1.3;
let w = clientWidth / 1.4;
return (<div className='patrolLayout'>
<header className='title' style={{ marginBottom: 10 }}>
<span className='line'></span>
<span className='cn'>布设信息</span>
<span className='en'>&nbsp;DEPLOYMENT INFORMATION</span>
</header>
<Layout>
<Sider width={'23%'} style={{ background: 'transparent' }}>
<div style={{ display: 'flex' }}>
<div style={{ display: 'flex', flexDirection: 'column' }}>
<Button className={deployState == -1 ? 'btn-spots-filter' : 'btn-default'} style={{ borderRadius: 0, margin: '0 20px 7px 0' }} onClick={() => this.handleStateChange(-1)}>全部</Button>
<Button className={deployState == 1 ? 'btn-spots-filter' : 'btn-default'} style={{ borderRadius: 0, margin: '0 20px 7px 0' }} onClick={() => this.handleStateChange(1)}>已布</Button>
<Button className={deployState == 0 ? 'btn-spots-filter' : 'btn-default'} style={{ borderRadius: 0, margin: '0 20px 7px 0' }} onClick={() => this.handleStateChange(0)}>未布</Button>
</div>
<div className='PingFangSC-Regular'>点位</div>
<div>
<div className='search-panel'>
<div style={{ marginTop: -1 }}>
<Search
placeholder={"请输入名称关键字搜索"}
style={{ borderRadius: 0 }}
onChange={e => this.onSearch(e.target.value)}
/>
</div>
</div>
{
treeDataSource ?
<div id='security-spots-scroller' style={{ position: 'relative', height: h - 63 }}>
<Tree className='equip-tree' showLine defaultExpandAll={true}>
{this.loop(treeDataSource)}
</Tree> </div> : <div style={{ textAlign: 'center' }}></div>
}
</div>
</div>
</Sider>
<Layout>
<Content className='spots-opr-content' style={{ width: w }}>
{spots && pictureInfo?.graph ?
<Heatmap key={Math.random()}
ref="heatmapComponent"
height={h}
width={w}
image={pictureInfo?.graph}
spots={spots.filter(s => s.deployed == true)}
onRemoveSpot={this.onRemoveSpot}
onDeploySpot={this.onDeploySpot}
/>
: <div style={{ border: '1px dashed #999', width: w, height: h, paddingTop: h * 0.3, textAlign: 'center' }}>
<img className='no-deploy-img' src='/assets/images/no_deploy.svg'></img>
<div className='PingFangSC-Regular'>暂无热点图</div>
</div>
}
<div className='opr-tip-row'>
<div className='PingFangSC-Regular'>说明拖拽点位进行布设拖出画布移除点位</div>
{
pictureInfo ?
<div className='opr-button'>
<Popconfirm
title='确认删除该结构物布设图?(已布点位将同步删除)'
position='top'
onConfirm={() => {
this.props.dispatch(deleteGraph(pictureInfo.id)).then(_ => {
this.getData();
this.setSpotsState(allPoints, [])
})
}}>
<Button className='graph-cfg-btn'>删除图片</Button>
</Popconfirm>
<Button className='graph-cfg-btn' onClick={() => this.editHandler(pictureInfo)} style={{ marginLeft: 15 }}>修改图片</Button>
<Button className='graph-cfg-btn' type='primary' onClick={this.onSaveClick} disabled={!dataHasChanged} style={{ marginLeft: 15 }}>完成</Button>
</div>
:
<div className='opr-button'>
<Button className='graph-cfg-btn' type='primary' onClick={this.onAddImgClick}>添加布设图</Button>
</div>
}
</div>
</Content>
</Layout>
</Layout>
{this.state.uploadImgModal}
</div>)
}
}
function mapStateToProps(state) {
const { global, projectGraph, projectDeployPoints, projectAllPoints } = state;
return {
pictureInfo: projectGraph.data,
projectDeployPoints: projectDeployPoints?.data || [],
clientHeight: global.clientHeight,
clientWidth: global.clientWidth,
allPoints: projectAllPoints?.data || []
};
}
export default connect(mapStateToProps)(DragDropContext(HTML5Backend)(ConfigPlanarGraph));

137
web-screen/client/src/sections/projectRegime/containers/pointDeploy/deploy-style.less

@ -1,137 +0,0 @@
.spots-opr-content {
padding: 0;
margin: 0;
position: relative;
}
.opr-tip-row {
display: flex;
margin-top: 10px;
justify-content: space-between;
}
.opr-button {
.ant-btn-disabled,
.ant-btn.disabled,
.ant-btn[disabled] {
//按钮 禁用
background-color: #3198F7;
}
}
.graph-cfg-btn {
color: #fff;
background-color: #3198F7;
border-color: #3198F7;
}
//蓝色按钮 鼠标悬浮
.graph-cfg-btn:hover,
.graph-cfg-btn:focus {
//color: #fff;
background-color: #3198F7;
border-color: #3198F7;
}
.patrolLayout {
margin-top: 20px;
background-color: #fff;
padding: 10px 16px;
.ant-layout {
background-color: transparent;
}
.ant-input:hover,
.ant-input:focus {
border-color: #fff;
}
.search-panel {
text-align: center;
margin-bottom: 7px;
.btn-spots-filter {
//选中的
background-color: #3198F7;
border-color: #3198F7;
color: #fff;
}
}
.search-panel input {
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
}
}
.equip-tree {
//测点 树结构
.ant-tree.ant-tree-show-line li span.ant-tree-switcher {
//展开, 关闭按钮
color: #fff;
}
.ant-tree li .ant-tree-node-content-wrapper {
//文字白色
color: #fff;
}
.ant-tree.ant-tree-show-line li:not(:last-child)::before {
//不显示竖线
width: 0px;
border: 0px;
}
.ant-tree li .ant-tree-node-content-wrapper.ant-tree-node-selected {
background-color: #98e5f381;
}
.ant-tree-node-content-wrapper:hover,
.ant-tree-node-content-wrapper:focus {
//文字鼠标悬浮 背景色 蓝色
background-color: #3198F7 !important;
}
}
//查询按钮
.ant-input-group-addon {
background-color: transparent;
.ant-btn {
background-color: transparent !important;
}
.ant-btn-primary {
float: right;
width: 90px;
height: 45px;
margin: 5px 0px 0px 10px;
background-color: #3198f7;
border-color: #3198f7;
}
.ant-btn-primary:hover {
border-color: #3198f7;
}
.ant-btn-primary:focus {
border-color: #3198f7;
}
}
.PingFangSC-Regular {
font-family: PingFangSC-Regular;
font-weight: 400;
font-size: 14px;
color: #4A4A4A;
line-height: 30px;
}
.no-deploy-img {
width: 289px;
height: 216px;
}

94
web-screen/client/src/sections/projectRegime/containers/pointDeploy/upload-img-modal.js

@ -1,94 +0,0 @@
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import Uploads from '$components/Uploads';
import { Input, Modal, Form, Button, message, Select } from 'antd';
import { getProjectGraph, createGraph, updateGraph } from '../../actions/graph';
const DisclosureModal = (props) => {
const { dispatch, onCancel, projectId, pictureInfo, getData } = props;
let files = pictureInfo ? [{ storageUrl: pictureInfo.graph }] : []
const [form] = Form.useForm();
const [editUrl, setEditUrl] = useState(files);
//初始化表单数据
const getinitialValues = () => {
if (pictureInfo) {
return { files: 1 };
}
return {}
};
useEffect(() => {
}, []);
const handleOk = () => {
form.validateFields().then(values => {
let data = {
projectId: projectId,
graph: editUrl[0]?.storageUrl,
}
if (pictureInfo) {//更新
dispatch(updateGraph(pictureInfo.id, data)).then(_ => {
getData()
});
} else {//新增
dispatch(createGraph(data)).then(_ => {
getData();
});
}
onCancel()
})
}
const vsjunct = (params) => {
if (params.length) {
let appendix = []
for (let p of params) {
appendix.push({
fName: p.name,
size: p.size,
fileSize: p.size,
storageUrl: p.storageUrl,//必须有storageUrl
})
}
setEditUrl(appendix)
} else {
setEditUrl([])
}
}
return (
<Modal title='添加布设图' visible={true} destroyOnClose
onCancel={onCancel} onOk={handleOk}>
<Form form={form} labelCol={{ span: 6 }} wrapperCol={{ span: 17 }} initialValues={getinitialValues()}>
<Form.Item label="布设图" name='files'
rules={[{ required: true, message: '请上传布设图' }]}>
<Uploads
className='upload'
listType='card'
uploadType='project'
maxFilesNum={1}
maxFileSize={10}
isQiniu={true}
onChange={vsjunct}
fileTypes={["png", "jpeg", "jpg"]}
value={editUrl}
defaultValue={editUrl}
/>
</Form.Item>
<Form.Item style={{ paddingLeft: '17%' }}>
<div style={{ color: '#999', width: 460 }}>说明附件格式为pngjpegjpg大小不超过10MB</div>
</Form.Item>
</Form>
</Modal>
)
}
function mapStateToProps(state) {
const { auth, global } = state;
return {
user: auth.user,
actions: global.actions,
}
}
export default connect(mapStateToProps)(DisclosureModal);

173
web-screen/client/src/sections/projectRegime/containers/qrCode.js

@ -1,173 +0,0 @@
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { Form, Input, Select, Button, message } from 'antd';
import JSZip from 'jszip';
import './qrCode.less';
const QrCode = (props) => {
const { dispatch, actions } = props
const { projectRegime } = actions
const [firmList, setFirmList] = useState([])
const [tableList, settableList] = useState([])
const [downloading, setDownloading] = useState(false)
useEffect(() => {
dispatch(projectRegime.getProjectList({ justStructure: true })).then(res => {
if (res.success) {
setFirmList(res.payload.data?.rows?.map(v => ({ value: v.id, label: v.name })))
}
})
projectList({})
}, [])
const projectList = (obj) => {
const { projectId, name } = obj
dispatch(projectRegime.qrCodeShow({ projectId, name })).then(res => {
if (res.success) {
settableList(res.payload.data?.rows)
}
})
}
const imgError = (e) => {
const img = e.currentTarget;
img.src = '/assets/images/no_qcoder.png';
img.onerror = null;
}
const batchDownload = () => {
if (tableList.length === 0) {
message.warning('没有数据可以导出')
return
}
setDownloading(true)
let promiseArr = [], nameArr = []
tableList.forEach(l => {
promiseArr.push(
window.fetch(`/_file-server/${l.qrCode}`, {
method: 'get',
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"X-Requested-With": "XMLHttpRequest",
},
})
)
nameArr.push(l.name + '.jpeg')
})
try {
Promise.all(promiseArr).then(async resArr => {
const zip = new JSZip()
for (let i = 0; i < resArr.length; i++) {
const response = resArr[i]
const blob = await response.blob()
zip.file(nameArr[i], blob)
}
zip.generateAsync({ type: "blob" }).then(blob => {
const url = window.URL.createObjectURL(blob)
downloadFile(url, "点位二维码.zip")
setDownloading(false)
message.success('下载成功')
});
})
} catch (error) {
console.log(error)
setDownloading(false)
message.error('下载失败')
}
}
return (
<div className='global-main'>
<div className='top'>
<div className='title'>
<span className='line'></span>
<span className='cn'>二维码</span>
<span className='en'>&nbsp;QRCode</span>
</div>
<Form
style={{ display: 'flex', }}
onFinish={r => {
projectList(r)
}}
>
<Form.Item
label='结构物名称'
name="projectId"
style={{ marginRight: 16, width: 240 }}
// initialValue={firmList[0]?.name}
>
<Select allowClear placeholder="请选择结构物名称" options={firmList} />
</Form.Item>
<Form.Item
label='点位名称'
name="name"
style={{ marginRight: 16, width: 260 }}
>
<Input placeholder="请输入点位名称" allowClear />
</Form.Item>
<Form.Item wrapperCol={{}}>
<Button htmlType="submit" style={{ marginRight: 16 }}>搜索</Button>
<Button type="primary" onClick={batchDownload} loading={downloading}>导出</Button>
</Form.Item>
</Form>
</div>
<div>
{
tableList?.map(v => {
return <div key={v.name + v.id}
style={{
display: 'inline-block',
margin: '0 20px 20px 0',
border: '1px solid #3c383824',
borderRadius: '3px'
}}
>
<img src={`/_file-server/${v.qrCode}`} style={{ display: 'inline-block', width: 234 }} onError={imgError} />
<div style={{
display: 'flex', flexDirection: 'column', padding: '6px 0',
width: 220, alignItems: 'center'
}}>
<span className='stru-name'>{firmList?.filter(u => u.value == v.projectId)[0]?.label}</span>
<span className='point-name'>点位名称{v.name}</span>
</div>
<div style={{
width: 234, height: 60, display: 'flex',
justifyContent: 'center', alignItems: 'center',
}}>
<Button type="primary" onClick={() => {
const tempArr = v.qrCode.split('/')
const filename = tempArr[tempArr.length - 1]
downloadFile(`/_file-server/${v.qrCode}`, filename)
}}>下载二维码</Button>
</div>
</div>
}
)
}
</div>
</div>
)
}
function mapStateToProps(state) {
const { auth, global } = state;
return {
user: auth.user,
actions: global.actions,
};
}
export default connect(mapStateToProps)(QrCode);
function downloadFile(url, fileName) {
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = fileName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}

44
web-screen/client/src/sections/projectRegime/containers/qrCode.less

@ -1,44 +0,0 @@
.top {
display: flex;
justify-content: space-between;
.title {
background-color: #fff;
display: inline-block;
.line {
display: inline-block;
width: 3px;
height: 20px;
background: #006BE3;
}
.cn {
font-family: YouSheBiaoTiHei;
font-size: 24px;
color: #101531;
margin-left: 11px;
}
.en {
font-family: D-DINExp-Italic;
font-weight: Italic;
font-size: 12px;
color: #969799;
}
}
}
.stru-name {
font-family: PingFangSC-Medium;
font-weight: 500;
font-size: 16px;
color: #323233;
}
.point-name {
font-family: PingFangSC-Regular;
font-weight: 400;
font-size: 14px;
color: #646566;
line-height: 18px;
}

15
web-screen/client/src/sections/projectRegime/index.js

@ -1,15 +0,0 @@
'use strict';
import reducers from './reducers';
import routes from './routes';
import actions from './actions';
import { getNavItem } from './nav-item';
export default {
key: 'projectRegime',
name: '结构物管理',
reducers: reducers,
routes: routes,
actions: actions,
getNavItem: getNavItem
};

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save