From 87ca70588c3d678f8901f1f11daaebc5456c2b37 Mon Sep 17 00:00:00 2001 From: "peng.peng" Date: Fri, 18 Aug 2023 17:47:09 +0800 Subject: [PATCH] =?UTF-8?q?=EF=BC=88*=EF=BC=89=E6=B6=88=E9=98=B2=E5=91=8A?= =?UTF-8?q?=E8=AD=A6=E6=95=B0=E6=8D=AE=E6=8E=A5=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/app/lib/models/fire_alarm.js | 20 +- api/app/lib/routes/superScreen/fire.js | 2 +- super-screen/client/index.ejs | 2 +- super-screen/client/index.html | 2 +- .../src/sections/fire-control/actions/fire.js | 2 +- .../fire-control/components/alarm-add.js | 100 ++++-- .../components/location-select.js | 91 ++++++ .../sections/fire-control/constants/index.js | 26 ++ .../sections/fire-control/containers/gis.js | 303 +++++++++--------- .../sections/fire-control/containers/gis.less | 5 +- .../fire-control/containers/homePage.js | 4 +- .../client/src/sections/fire-control/index.js | 2 +- 12 files changed, 360 insertions(+), 199 deletions(-) create mode 100644 super-screen/client/src/sections/fire-control/components/location-select.js create mode 100644 super-screen/client/src/sections/fire-control/constants/index.js diff --git a/api/app/lib/models/fire_alarm.js b/api/app/lib/models/fire_alarm.js index 9bfdaad..ad64a01 100644 --- a/api/app/lib/models/fire_alarm.js +++ b/api/app/lib/models/fire_alarm.js @@ -64,7 +64,7 @@ module.exports = dc => { state: { type: DataTypes.INTEGER, allowNull: true, - defaultValue: null, + defaultValue: "1", comment: "事件状态:1 进行中 2已结束", primaryKey: false, field: "state", @@ -87,6 +87,24 @@ module.exports = dc => { primaryKey: false, field: "latitude", autoIncrement: false + }, + type: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: "警情类型", + primaryKey: false, + field: "type", + autoIncrement: false + }, + typeParam: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: "警情类型对应的不同属性 ", + primaryKey: false, + field: "type_param", + autoIncrement: false } }, { tableName: "fire_alarm", diff --git a/api/app/lib/routes/superScreen/fire.js b/api/app/lib/routes/superScreen/fire.js index 786d5d1..b134d95 100644 --- a/api/app/lib/routes/superScreen/fire.js +++ b/api/app/lib/routes/superScreen/fire.js @@ -6,7 +6,7 @@ module.exports = function (app, router, opts, AuthCode) { //查询消防告警 app.fs.api.logAttr['GET/fire/alarm'] = { content: '查询消防告警', visible: true }; - router.get('/fire/alarm', fire.addAlarm(opts)); + router.get('/fire/alarm', fire.getFireAlarmList(opts)); //新增消防告警 app.fs.api.logAttr['POST/fire/alarm'] = { content: '新增消防告警', visible: true }; diff --git a/super-screen/client/index.ejs b/super-screen/client/index.ejs index 2843462..1b2fc2c 100644 --- a/super-screen/client/index.ejs +++ b/super-screen/client/index.ejs @@ -27,7 +27,7 @@ }; + src="https://webapi.amap.com/maps?v=2.0&key=173f32a9ff6f3a8c6b15aceb3353c715&plugin=AMap.Adaptor,AMap.Scale,AMap.ToolBar,AMap.DistrictSearch,AMap.Geocoder,AMap.CustomLayer,Map3D,ElasticMarker,AMap.Autocomplete,AMap.PlaceSearch,AMap.MarkerCluster&plugin=AMap.Driving"> diff --git a/super-screen/client/index.html b/super-screen/client/index.html index 1995630..ad535f3 100644 --- a/super-screen/client/index.html +++ b/super-screen/client/index.html @@ -28,7 +28,7 @@ }; + src="https://webapi.amap.com/maps?v=2.0&key=173f32a9ff6f3a8c6b15aceb3353c715&plugin=AMap.Adaptor,AMap.Scale,AMap.ToolBar,AMap.DistrictSearch,AMap.Geocoder,AMap.CustomLayer,Map3D,ElasticMarker,AMap.Autocomplete,AMap.PlaceSearch,AMap.MarkerCluster&plugin=AMap.Driving"> diff --git a/super-screen/client/src/sections/fire-control/actions/fire.js b/super-screen/client/src/sections/fire-control/actions/fire.js index 1f17495..23dd394 100644 --- a/super-screen/client/src/sections/fire-control/actions/fire.js +++ b/super-screen/client/src/sections/fire-control/actions/fire.js @@ -11,7 +11,7 @@ export function getFireAlarmList(query) { actionType: 'GET_FIRE_ALARM', url: `${ApiTable.getFireAlarmList}`, msg: { error: '获取消防告警列表失败' }, - reducer: { name: 'riskReport' } + reducer: { name: 'alarms' } }); } diff --git a/super-screen/client/src/sections/fire-control/components/alarm-add.js b/super-screen/client/src/sections/fire-control/components/alarm-add.js index 96d8123..36f65b9 100644 --- a/super-screen/client/src/sections/fire-control/components/alarm-add.js +++ b/super-screen/client/src/sections/fire-control/components/alarm-add.js @@ -1,56 +1,71 @@ import React, { useEffect, useState } from 'react'; import { connect } from 'react-redux'; -import { Row, Col, Modal, Form, Input, Select, DatePicker } from 'antd'; -const { Opiton } = Select; +import { Modal, Form, Select, DatePicker, Tooltip } from 'antd'; +import moment from 'moment'; +import { typeParam_data } from '../constants/index' +const { Option } = Select; function FireAddForm(props) { - const { visible } = props; + const { visible, location } = props; + const [form] = Form.useForm(); const layout = { labelCol: { span: 8 }, wrapperCol: { span: 12 }, }; - const [form] = Form.useForm(); + useEffect(() => { + if (location?.location) form.setFieldValue('location', location) + }, [location]) + + const disabledDate = (current) => { + return current && current > moment(); + }; + + const eventType = Form.useWatch('type', form); const renderInfowindow = () => { - return
-
{ setVisible(false) }} /> + return
+
{ props.onCancel() }} />
{ + form.validateFields() + .then((values) => { + props.onFinish(values) + }) + .catch((errorInfo) => { + console.log(errorInfo) + }); + }} > - + { - setLocationVisible(true) + props.locationClick() }} - name="地点" label="地点" > - {/* */} + rules={[{ required: true, message: '请选择地点!' }]} + name="location" label="地点" >
{ setLocationVisible(true) }} - style={{ color: 'rgba(89, 153, 200, 1)', paddingLeft: 12 }}>请选择事件地点
-
- - + onClick={() => { props.locationClick() }} + style={{ color: 'rgba(89, 153, 200, 1)', paddingLeft: 12 }}>{location?.location ? + + + {location?.location?.length > 10 ? location?.location?.substring(0, 10) + '...' : location?.location} + + : '请选择事件地点'}
- - + + + + + - + -
+ {typeParam_data[eventType] && + + } + + {eventType == '火灾扑救' && + + + } + + +
{ props.onCancel() }}>取消
{ form?.submit() }} className='report_button'>上报
- +
} diff --git a/super-screen/client/src/sections/fire-control/components/location-select.js b/super-screen/client/src/sections/fire-control/components/location-select.js new file mode 100644 index 0000000..099cf6c --- /dev/null +++ b/super-screen/client/src/sections/fire-control/components/location-select.js @@ -0,0 +1,91 @@ +import React, { useEffect, useState } from 'react'; +import { Modal, Input, message } from 'antd'; + +let LOCATION_MAP_ID = 'LOCATION_MAP_ID'; +function LoacationSelect(props) { + const { locationVisible } = props; + const [lnglat, setLnglat] = useState() + const [location, setLocation] = useState() + + useEffect(() => { + setTimeout(() => { + if (locationVisible && document.getElementById(LOCATION_MAP_ID)) { + const locationMap = new AMap.Map(LOCATION_MAP_ID, { + // center: [116.054664, 28.538966], + zoomEnable: true, + dragEnable: true, + cursor: 'pointer', + }); + + locationMap.on('click', (e) => { + locationMap.clearMap(); + const marker = new AMap.Marker({ + icon: '/assets/images/homepage/fire/position.png', + position: e.lnglat, + offset: new AMap.Pixel(-5, -15) + }); + marker.setMap(locationMap); + setLnglat(e.lnglat.lng + ',' + e.lnglat.lat) + }) + } + }, 200); + }, [locationVisible]) + + const renderLocationInfowindow = () => { + return
+
{ props.onCancel() }} /> + +
+ 经纬度: + {lnglat} +
+
+ 坐标点位置: + { setLocation(e.target.value) }} /> +
+
+ +
+
{ + setLnglat(null) + setLocation(null) + }}> + 重置点位 +
+
{ + if (!lnglat) { + message.warning('请在地图上选择经纬度点位') + return; + } + if (!location) { + message.warning('请填写坐标点位置') + return; + } + props.locationSelect({ lnglat, location }) + }} + className='ok_btn'> + 确认选择 +
+
+
+ } + + + return + {renderLocationInfowindow()} + + +} + +export default LoacationSelect; \ No newline at end of file diff --git a/super-screen/client/src/sections/fire-control/constants/index.js b/super-screen/client/src/sections/fire-control/constants/index.js new file mode 100644 index 0000000..2ae5489 --- /dev/null +++ b/super-screen/client/src/sections/fire-control/constants/index.js @@ -0,0 +1,26 @@ +const typeParam_data = { + '火灾扑救': { + name: '着火物质', + options: ['固体物质', '液体或可熔物质', '气体', '带电物体和精密仪器等物质', '烹饪器具内的烹饪物',] + }, + '救援抢险': { + name: '事件类型', + options: ['危险化学品泄漏', '道路交通事故', '地震', '建筑坍塌', '重大安全生产事故', + '空难', '爆炸及恐怖事件', '群众遇险事件'] + }, + '自然灾害': { + name: '灾害类型', + options: ['水旱', '气象', '地质灾害', '等自然灾害', '森林、草原火灾'] + }, + '灾难事故': { + name: '事故类型', + options: ['矿山事故', '水上事故', '重大环境污染', '核与辐射事故', '突发公共卫生事件'] + }, +} + +const fireMaterial_data = ["民用建筑", "工业建筑", "森林", "地下建筑", "水上"] + + +export { + typeParam_data, fireMaterial_data +} \ No newline at end of file diff --git a/super-screen/client/src/sections/fire-control/containers/gis.js b/super-screen/client/src/sections/fire-control/containers/gis.js index 53b5e25..3f3d261 100644 --- a/super-screen/client/src/sections/fire-control/containers/gis.js +++ b/super-screen/client/src/sections/fire-control/containers/gis.js @@ -1,15 +1,12 @@ import React, { useEffect, useState } from 'react'; import { connect } from 'react-redux'; import { render } from 'react-dom'; -import { Row, Col, Modal, Form, Input, Select, Button } from 'antd'; +import { Row, Col, message } from 'antd'; import FireAddForm from '../components/alarm-add' +import LoacationSelect from '../components/location-select'; import './gis.less' const MAPDOMID = 'fs-amap-container-fire'; -const LOCATION_MAP_ID = 'location_map_id'; let map = null; -let heatmap = null; -let loca = null; -let interval = null; const tabs = [ { name: '应急机构', tab: 'yjjg', className: 'emergency_button' }, @@ -18,17 +15,32 @@ const tabs = [ { name: '医疗机构', tab: 'yljg', className: 'emergency_button' }, { name: '避难场所', tab: 'bncs', className: 'emergency_button' }, ] - -const { Option } = Select; - function Map(props) { + const { dispatch, actions } = props; const [delay, setDelay] = useState(true) const [tab, setTab] = useState('yjjg') const [visible, setVisible] = useState(false) const [level, setLevel] = useState('I') const [alarmData, setAlarmData] = useState() const [locationVisible, setLocationVisible] = useState(false) - const [lnglat, setLnglat] = useState() + const [location, setLocation] = useState({}) + const [alarmList, setAlarmList] = useState() + //查询告警列表数据 + const getData = () => { + dispatch(actions?.firecontrol?.getFireAlarmList()).then(res => { + if (res?.payload?.data) { + setAlarmList(res?.payload?.data) + } + }) + } + useEffect(() => { + if (!delay && alarmList?.length > 0) { + setTimeout(() => { + map && renderAlarms() + }, 1000); + } + }, [delay, alarmList]) + // 地图初始化 const loadMap = () => { // 图片图层 实现瓦片地图中国地图样式 bounds 第一个点为左下角 第二个点为右上角 @@ -59,14 +71,14 @@ function Map(props) { map.on('complete', () => { - map.setZoom(17.4) - map.setCenter([115.922069, 28.554867]) - map.setPitch(47.30) - map.setRotation(1.7000) + // map.setZoom(17.4) + // map.setCenter([115.922069, 28.554867]) + // map.setPitch(47.30) + // map.setRotation(1.7000) setTimeout(() => { setDelay(false) }, 1000); - map && renderAlarms() + }); map.on('click', (e) => { @@ -84,16 +96,12 @@ function Map(props) { console.log('Rotation' + Rotation) console.log('e.lnglat' + e.lnglat) }) - - loca = new Loca.Container({ map: map }) - }; - // 初始化GIS 组件销毁清空定时器 useEffect(() => { loadMap(); - + getData() }, []); useEffect(() => { @@ -101,54 +109,23 @@ function Map(props) { }, [level]) - useEffect(() => { - - setTimeout(() => { - if (locationVisible && document.getElementById(LOCATION_MAP_ID)) { - const locationMap = new AMap.Map(LOCATION_MAP_ID, { - // center: [116.054664, 28.538966], - zoomEnable: true, - dragEnable: true, - cursor: 'pointer', - }); - - locationMap.on('click', (e) => { - locationMap.clearMap(); - const marker = new AMap.Marker({ - icon: '/assets/images/homepage/fire/position.png', - position: e.lnglat, - offset: new AMap.Pixel(-5, -15) - }); - marker.setMap(locationMap); - setLnglat(e.lnglat.lng + ',' + e.lnglat.lat) - }) - } - }, 200); - - - }, [locationVisible]) - const renderAlarms = () => { - // map.clearMap(); - const alarms = [ - { lng: 115.92365, lat: 28.557404, type: 'device', name: '廉租房1', kind: 'markeralarm' }, - ] - alarms.map((x, index) => { + alarmList?.map((x, index) => { var marker = new AMap.Marker({ - position: new AMap.LngLat(x.lng, x.lat), + position: new AMap.LngLat(x.longitude, x.latitude), // 将一张图片的地址设置为 icon - icon: '/assets/images/homepage/communtity/' + x.kind + '.png', + icon: '/assets/images/homepage/communtity/markeralarm.png', // 设置了 icon 以后,设置 icon 的偏移量,以 icon 的 [center bottom] 为原点 offset: new AMap.Pixel(-13, -30), - zooms: [15, 19], + zooms: [3, 19], }); - marker.setTitle(x.name); + marker.setTitle(x.location); map.add(marker); var circle = new AMap.Circle({ - center: [x.lng, x.lat], - radius: 300, //半径 + center: [x.longitude, x.latitude], + radius: 5000, //半径 borderWeight: 3, strokeColor: "#AE0000", strokeOpacity: 1, @@ -167,24 +144,20 @@ function Map(props) { let infowindow = new AMap.InfoWindow({ isCustom: true, //使用自定义窗体 content: `
-
`, +
`, offset: new AMap.Pixel(233, 260) }); - let alarmOk = new AMap.InfoWindow({ - isCustom: true, //使用自定义窗体 - // content: `
- //
`, - offset: new AMap.Pixel(233, 440) - }); - marker.on('click', () => { let position = marker.getPosition ? marker.getPosition() : marker.getCenter(); infowindow.open(map, position); map.setCenter(position) + map.setZoom(17.4) + map.setPitch(47.30) + map.setRotation(1.7000) setAlarmData(x) setTimeout(() => { - if (document.getElementById(`alarmcontentid${x.name}`)) { + if (document.getElementById(`alarmcontentid${x.location}`)) { renderAlarmInfowindow(x) } }, 50) @@ -192,15 +165,84 @@ function Map(props) { }) } + //驾车路线规划 + const drawDrivings = (location1, location2) => { + var driving = new AMap.Driving({ + map: map, + }); + // 根据起终点经纬度规划驾车导航路线 + driving.search(new AMap.LngLat(location1[0], location1[1]), new AMap.LngLat(location2[0], location2[1]), function (status, result) { + // result 即是对应的驾车导航信息,相关数据结构文档请参考 https://lbs.amap.com/api/javascript-api/reference/route-search#m_DrivingResult + if (status === 'complete') { + if (result.routes && result.routes.length) { + // 绘制第一条路线,也可以按需求绘制其它几条路线 + drawRoute(result.routes[0]) + } + } else { + } + }); + // driving.clear() //清除路线 + } + + function drawRoute(route) { + var path = parseRouteToPath(route) + + // var startMarker = new AMap.Marker({ + // position: path[0], + // icon: 'https://webapi.amap.com/theme/v1.3/markers/n/start.png', + // map: map + // }) + + // var endMarker = new AMap.Marker({ + // position: path[path.length - 1], + // icon: 'https://webapi.amap.com/theme/v1.3/markers/n/end.png', + // map: map + // }) + + var routeLine = new AMap.Polyline({ + path: path, + isOutline: true, + outlineColor: '#ffeeee', + borderWeight: 2, + strokeWeight: 5, + strokeOpacity: 0.9, + strokeColor: '#0091ff', + lineJoin: 'round' + }) + + map.add(routeLine); + + // 调整视野达到最佳显示区域 + map.setFitView([startMarker, endMarker, routeLine]) + } + + // 解析DrivingRoute对象,构造成AMap.Polyline的path参数需要的格式 + // DrivingResult对象结构参考文档 https://lbs.amap.com/api/javascript-api/reference/route-search#m_DriveRoute + function parseRouteToPath(route) { + var path = [] + + for (var i = 0, l = route.steps.length; i < l; i++) { + var step = route.steps[i] + + for (var j = 0, n = step.path.length; j < n; j++) { + path.push(step.path[j]) + } + } + + return path + } const renderAlarmInfowindow = (x) => { return x && render(
{ - map.setCenter([115.922069, 28.554867]) + map.setCenter([116.054664, 28.538966]) + map.setZoom(10.3) + map.setPitch(22.9) + map.setRotation(0) map.clearInfoWindow(); }} /> -
+ {/*
地址信息: 南湖大道
@@ -211,12 +253,12 @@ function Map(props) {
告警内容 火情 -
+
*/} -
消除警情
+ {/*
消除警情
*/} -
请根据火灾态势,选择应急预案等级
- +
请根据火灾态势,选择应急预案等级
+ {['I', 'II', 'III', 'IV'].map(s => { return { setLevel(s) }} @@ -229,86 +271,35 @@ function Map(props) {
-
{ props.alarmOk() }}>是
+
{ + map.clearInfoWindow(); + drawDrivings([x.longitude, x.latitude], [115.895753, 28.553354]) + props.alarmOk() + }}>是
, - document.getElementById(`alarmcontentid${x.name}`)); + document.getElementById(`alarmcontentid${x.location}`)); } + const renderLeftTop = () => { return
{ setVisible(true) }} /> } - const layout = { - labelCol: { span: 8 }, - wrapperCol: { span: 12 }, - }; - - const [form] = Form.useForm(); - const renderInfowindow = () => { - return
-
{ setVisible(false) }} /> -
- - - - { - setLocationVisible(true) - }} - name="地点" label="地点" > - {/* */} -
{ setLocationVisible(true) }} - style={{ color: 'rgba(89, 153, 200, 1)', paddingLeft: 12 }}>请选择事件地点
-
- - - - - - - - - - -
-
{ setVisible(false) }}>取消
-
{ form?.submit() }} className='report_button'>上报
-
- -
- - -
- } - - const renderLocationInfowindow = () => { - return
-
{ setLocationVisible(false) }} /> - -
- 经纬度: - {lnglat} -
-
- 坐标点位置: - -
-
+ const onFinish = (values) => { -
-
- 重置点位 -
-
- 确认选择 -
-
-
+ dispatch(actions.firecontrol.addFireAlarm( + { + ...values, + state: 1, + location: location?.location, + longitude: location?.lnglat?.split(',')[0], + latitude: location?.lnglat?.split(',')[1], + } + )).then(res => { + //getData() + message.success('新增上报信息成功') + setVisible(false) + }) } return ( @@ -354,22 +345,20 @@ function Map(props) { setVisible(false)} + locationClick={() => setLocationVisible(true)} + location={location} + onFinish={onFinish} /> {/* 位置选点 */} - - {renderLocationInfowindow()} - + setLocationVisible(false)} + locationSelect={(location) => { + setLocation(location) + setLocationVisible(false) + }} + /> ); } diff --git a/super-screen/client/src/sections/fire-control/containers/gis.less b/super-screen/client/src/sections/fire-control/containers/gis.less index 4977ca7..a1f103c 100644 --- a/super-screen/client/src/sections/fire-control/containers/gis.less +++ b/super-screen/client/src/sections/fire-control/containers/gis.less @@ -482,11 +482,10 @@ } .ant-picker-suffix { - color: rgba(89, 153, 200, 1); + color: rgba(89, 153, 200, 1); } - - .ant-picker-input::input-placeholder { + .ant-picker-input input::placeholder { color: rgba(89, 153, 200, 1) !important; } } diff --git a/super-screen/client/src/sections/fire-control/containers/homePage.js b/super-screen/client/src/sections/fire-control/containers/homePage.js index 3e59a45..305032f 100644 --- a/super-screen/client/src/sections/fire-control/containers/homePage.js +++ b/super-screen/client/src/sections/fire-control/containers/homePage.js @@ -15,7 +15,7 @@ import Weather from '../../water-prevention/components/weather'; import { FullScreenContainer } from '$components' function homePage(props) { - const { dispatch } = props; + const { dispatch, actions } = props; const childStyle = { height: '32%', color: '#fff', marginBottom: 17 } const cardHeight = document.body.clientHeight * 0.896 * 0.32 const cardContentHeight = cardHeight - 42 - 13 @@ -58,6 +58,8 @@ function homePage(props) {
{ setTab('item') diff --git a/super-screen/client/src/sections/fire-control/index.js b/super-screen/client/src/sections/fire-control/index.js index 307bc46..2be1343 100644 --- a/super-screen/client/src/sections/fire-control/index.js +++ b/super-screen/client/src/sections/fire-control/index.js @@ -6,7 +6,7 @@ import actions from './actions'; import { getNavItem } from './nav-item'; export default { - key: 'communitysafty', + key: 'firecontrol', name: '首页', reducers: reducers, routes: routes,