From b3f1b88a8be9389bc72e66599faeff4dc1b6d96a Mon Sep 17 00:00:00 2001 From: "peng.peng" Date: Wed, 23 Aug 2023 16:01:37 +0800 Subject: [PATCH] =?UTF-8?q?(*)=E7=A4=BE=E5=8C=BA=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../community-safty/components/basic-info.js | 3 + .../community-safty/components/charts/bar.js | 235 ++++++++++++++++++ .../community-safty/components/charts/pie.js | 124 +++++++++ .../components/charts/style.less | 15 ++ .../community-safty/components/city-safty.js | 86 +++++-- .../components/infrastructure.js | 17 +- .../components/population-dynamics.js | 26 +- .../components/special-person.js | 37 +-- .../community-safty/containers/gis.js | 45 ++-- .../community-safty/containers/homePage.js | 44 +++- 10 files changed, 528 insertions(+), 104 deletions(-) create mode 100644 super-screen/client/src/sections/community-safty/components/charts/bar.js create mode 100644 super-screen/client/src/sections/community-safty/components/charts/pie.js create mode 100644 super-screen/client/src/sections/community-safty/components/charts/style.less diff --git a/super-screen/client/src/sections/community-safty/components/basic-info.js b/super-screen/client/src/sections/community-safty/components/basic-info.js index d185e56..6262568 100644 --- a/super-screen/client/src/sections/community-safty/components/basic-info.js +++ b/super-screen/client/src/sections/community-safty/components/basic-info.js @@ -1,8 +1,11 @@ import React from 'react' import { Box } from '$components'; + function BasicInfo() { + + return
diff --git a/super-screen/client/src/sections/community-safty/components/charts/bar.js b/super-screen/client/src/sections/community-safty/components/charts/bar.js new file mode 100644 index 0000000..55c9f9b --- /dev/null +++ b/super-screen/client/src/sections/community-safty/components/charts/bar.js @@ -0,0 +1,235 @@ + + +import React from 'react' +import { Box } from '$components'; +import ReactEcharts from 'echarts-for-react'; +import * as echarts from 'echarts'; +import './style.less'; + +function ThreeDBarChart() { + const offsetX = 12; //bar宽 + const offsetY = 6; //倾斜角度 + // 绘制左侧面 + const CubeLeft = echarts.graphic.extendShape({ + shape: { + x: 0, + y: 0, + }, + buildPath: function (ctx, shape) { + // 会canvas的应该都能看得懂,shape是从custom传入的 + const xAxisPoint = shape.xAxisPoint; + // console.log(shape); + const c0 = [shape.x, shape.y]; + const c1 = [shape.x - offsetX, shape.y - offsetY]; + const c2 = [xAxisPoint[0] - offsetX, xAxisPoint[1] - offsetY]; + const c3 = [xAxisPoint[0], xAxisPoint[1]]; + ctx.moveTo(c0[0], c0[1]).lineTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).closePath(); + }, + }); + // 绘制右侧面 + const CubeRight = echarts.graphic.extendShape({ + shape: { + x: 0, + y: 0, + }, + buildPath: function (ctx, shape) { + const xAxisPoint = shape.xAxisPoint; + const c1 = [shape.x, shape.y]; + const c2 = [xAxisPoint[0], xAxisPoint[1]]; + const c3 = [xAxisPoint[0] + offsetX, xAxisPoint[1] - offsetY]; + const c4 = [shape.x + offsetX, shape.y - offsetY]; + ctx.moveTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).lineTo(c4[0], c4[1]).closePath(); + }, + }); + // 绘制顶面 + const CubeTop = echarts.graphic.extendShape({ + shape: { + x: 0, + y: 0, + }, + buildPath: function (ctx, shape) { + const c1 = [shape.x, shape.y]; + const c2 = [shape.x + offsetX, shape.y - offsetY]; //右点 + // const c3 = [shape.x, shape.y - offsetX]; + const c3 = [shape.x, shape.y - offsetY * 2]; + const c4 = [shape.x - offsetX, shape.y - offsetY]; + ctx.moveTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).lineTo(c4[0], c4[1]).closePath(); + }, + }); + // 注册三个面图形 + echarts.graphic.registerShape('CubeLeft', CubeLeft); + echarts.graphic.registerShape('CubeRight', CubeRight); + echarts.graphic.registerShape('CubeTop', CubeTop); + let xAxisData = ["1人", "2人", "3人", "4人", "5人及以上"] + let seriesData = [100, 200, 300, 400, 300] + let colorArr = [["#42D5F8"], ["#2086B0", "rgba(13,8,16,0)"], ["#3394D7", "rgba(14,185,151,0)"]] + const option = { + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'shadow', + }, + // formatter: function (params, ticket, callback) { + // const item = params[1]; + // return item.name + ' : ' + item.value; + // }, + }, + grid: { + left: '5%', + right: '5%', + top: '20%', + bottom: '3%', + containLabel: true, + }, + xAxis: { + type: 'category', + data: xAxisData, + axisLine: { + show: false, + lineStyle: { + width: 2, + color: '#E6EFFF', + }, + }, + axisTick: { + show: false, + }, + axisLabel: { + fontSize: 13, + interval: 0, + color: "#E6EFFF", + }, + }, + yAxis: { + type: 'value', + name: "单位:户", + // nameGap: 30, + nameTextStyle: { + color: "rgba(195, 230, 255, 1)", + fontWeight: 400, + fontSize: 14, + padding: [-20, 20, 0, 0] + }, + axisLine: { + // show: false, + lineStyle: { + width: 2, + color: '#2B7BD6', + }, + }, + splitLine: { + // show: false, + lineStyle: { + color: '#153D7D', + }, + }, + axisTick: { + // show: false, + }, + axisLabel: { + // show: false, + fontSize: 14, + color: 'E6EFFF' + }, + // boundaryGap: ['20%', '20%'], + }, + series: [ + { + type: 'custom', + renderItem: (params, api) => { + const location = api.coord([api.value(0), api.value(1)]); + return { + type: 'group', + children: [ + { + type: 'CubeLeft', + shape: { + api, + xValue: api.value(0), + yValue: api.value(1), + x: location[0], + y: location[1], + xAxisPoint: api.coord([api.value(0), 0]), + }, + style: { + fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { + offset: 0, + color: colorArr[1][0], + }, + { + offset: 1, + color: colorArr[1][1], + }, + ]), + }, + }, + { + type: 'CubeRight', + shape: { + api, + xValue: api.value(0), + yValue: api.value(1), + x: location[0], + y: location[1], + xAxisPoint: api.coord([api.value(0), 0]), + }, + style: { + fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { + offset: 0, + color: colorArr[2][0], + }, + { + offset: 1, + color: colorArr[2][1], + }, + ]), + }, + }, + { + type: 'CubeTop', + shape: { + api, + xValue: api.value(0), + yValue: api.value(1), + x: location[0], + y: location[1], + xAxisPoint: api.coord([api.value(0), 0]), + }, + style: { + fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { + offset: 0, + color: colorArr[0][0], + }, + { + offset: 1, + color: colorArr[0][0], + }, + ]), + }, + }, + ], + }; + }, + data: seriesData, + }, + ], + }; + + + return <> +
家庭人口数
+ + +} + +export default ThreeDBarChart; + + diff --git a/super-screen/client/src/sections/community-safty/components/charts/pie.js b/super-screen/client/src/sections/community-safty/components/charts/pie.js new file mode 100644 index 0000000..1a63f0d --- /dev/null +++ b/super-screen/client/src/sections/community-safty/components/charts/pie.js @@ -0,0 +1,124 @@ +import React from 'react'; +import ReactEcharts from 'echarts-for-react'; +import * as echarts from 'echarts'; +import { RING_COLORS, tooltip } from '../../../water-prevention/components/charts/constants'; +/** + * props + * height: 图表高度 + */ + +function RingChart(props) { + const { data, image = {} } = props; + // eslint-disable-next-line react/destructuring-assignment + const colors = props.colors || RING_COLORS; + const max = data.reduce((pre, cur) => pre + cur.value, 0); + const getOption = () => { + const option = { + graphic: { + type: 'image', + style: { + image: image.url, + width: image.width, + height: image.height, + }, + left: 'center', + top: 'center', + }, + title: { + text: max, + subtext: '总人数', + textStyle: { + color: '#E2F8FF', + fontSize: 25, + align: 'center', + fontFamily: 'DINMediumItalic', + fontWeight: 'Italic', + letterSpacing: '2.08px', + }, + subtextStyle: { + fontSize: 14, + fontWeight: 400, + color: ['#E6EFFF'], + }, + x: 'center', + y: 'center', + top: '35%', + }, + tooltip: { + ...tooltip, + trigger: 'item', + formatter: '{b} : {c}个 ({d}%)', + position: ['10%', '40%'], + }, + // 渐变色 + color: colors.map((s) => { + const cs = new echarts.graphic.LinearGradient(1, 1, 0, 0, [ + { offset: 0, color: s.linearGradientFrom }, + { offset: 0.9, color: s.linearGradientTo }, + ]); + return cs; + }), + + series: [ + { + type: 'pie', + radius: ['66%', '80%'], + avoidLabelOverlap: false, + itemStyle: { + // 环图间隙 + borderColor: '#0A1024', + borderWidth: 3, + }, + label: { + show: false, + position: 'center', + }, + emphasis: { + label: { + show: false, + fontSize: '40', + fontWeight: 'bold', + }, + }, + labelLine: { + show: false, + }, + data, + }, + ], + }; + + return option; + }; + const { height, width } = props; + const options = getOption(); + const percent_colors = ['#24DDFA', '#267FD3', '#F8C86B',] + const total = data?.reduce((p, c) => p + c.value, 0) + const renderList = () => data.map((s, index) => ( +
+
+
+
{s.name}
+
+
{s.value}个
{Math.round(s.value / total * 100)}%
+
+ )); + + return ( +
+
+ +
+
+ {renderList()} +
+
+ ); +} + +export default RingChart; diff --git a/super-screen/client/src/sections/community-safty/components/charts/style.less b/super-screen/client/src/sections/community-safty/components/charts/style.less new file mode 100644 index 0000000..8cbdd43 --- /dev/null +++ b/super-screen/client/src/sections/community-safty/components/charts/style.less @@ -0,0 +1,15 @@ +.bar_legend { + color: #E6EFFF; + display: flex; + position: absolute; + top: 17%; + right: 5%; + align-items: center; + + ._block { + width: 10px; + height: 10px; + background: #3ED5F7; + margin-right: 6px; + } +} \ No newline at end of file diff --git a/super-screen/client/src/sections/community-safty/components/city-safty.js b/super-screen/client/src/sections/community-safty/components/city-safty.js index 82a3a49..3d78ad8 100644 --- a/super-screen/client/src/sections/community-safty/components/city-safty.js +++ b/super-screen/client/src/sections/community-safty/components/city-safty.js @@ -1,48 +1,80 @@ import React, { useEffect, useState } from 'react' -import { Box, AutoRollComponent } from '$components'; +import { Box, AutoRollComponent, NoData } from '$components'; +import { useFsRequest, ApiTable } from '$utils'; +import moment from 'moment'; +import { Tooltip } from 'antd'; import './style.less'; function CitySafty(props) { + const { waterLevelAlarms } = props; + + const { data: fireAlarms = [] } = useFsRequest({ url: ApiTable.getFireAlarmList }); const getContent = () => { return
-
-
-
-
-
2023-06-20 17:00:00
-
已处理
-
-
萌萌小区25栋305等等等等等发生等等火灾扥大哥大呢个
-
-
-
-
-
-
-
2023-06-20 17:00:00
-
处理中
+ {fireAlarms.map(s => { + const handled = s?.state == 2 + return
+
+
+
+
{moment(s.createTime).format('YYYY-MM-DD HH:mm:ss')}
+
{handled ? '已处理' : '处理中'}
+
+
{s?.location}
-
萌萌小区25栋305等等等等等发生等等火灾扥大哥大呢个
-
-
+ })} + +
+ } + + const renderList = () =>
+ { + waterLevelAlarms?.map(a =>
= 3 ? 'alarm_handle' : 'alarm_unhandle'}>
-
2023-06-20 17:00:00
-
处理中
+ +
{a.alarms[0]?.source?.name}
+
+
= 3 ? '#FFEA00' : '#FF2C2C' }}>{convertLevelToLabel(a.alarms[0]?.level)}
-
萌萌小区25栋305等等等等等发生等等火灾扥大哥大呢个
+
{a.alarms[0]?.content}
-
-
- } +
) + } +
+ + const dataSource = fireAlarms.concat(waterLevelAlarms || []) + return - + { + dataSource?.length > 0 ? + {renderList()} + {getContent()} + } + divHeight={240} + divId={`community-right-top`} /> + : + } } export default CitySafty; +function convertLevelToLabel(level) { + switch (level) { + case 1: + return '一级预警'; + case 2: + return '二级预警'; + case 3: + return '三级预警'; + default: + return ''; + } +} diff --git a/super-screen/client/src/sections/community-safty/components/infrastructure.js b/super-screen/client/src/sections/community-safty/components/infrastructure.js index 005fa43..366e469 100644 --- a/super-screen/client/src/sections/community-safty/components/infrastructure.js +++ b/super-screen/client/src/sections/community-safty/components/infrastructure.js @@ -1,13 +1,22 @@ import React from 'react' import { Box, NoData } from '$components'; +import { useMockRequest, ApiTable } from '$utils'; function Infrastructure(props) { + const { data: devices = [] } = useMockRequest({ + url: 'https://superchangnan.anxinyun.cn/api/xiaofang/devices', + method: 'mockGet', + }); + const datas = devices?.map(s => { + s.data = JSON.parse(s.data) + return s; + }) const data = [ - { name: '烟感设备', number: 32 }, - { name: '温度设备', number: 32 }, - { name: '摄像头设备', number: 32 }, - { name: '电梯设备', number: 32 }, + { name: '烟感设备', number: datas?.find(s => s.type == 3)?.data?.length || 0 }, + { name: '消火栓', number: datas?.find(s => s.type == 1)?.data?.length || 0 }, + { name: '配电箱', number: datas?.find(s => s.type == 4)?.data?.length || 0 }, + { name: '水箱', number: datas?.find(s => s.type == 2)?.data?.length || 0 }, ] return {/* */} diff --git a/super-screen/client/src/sections/community-safty/components/population-dynamics.js b/super-screen/client/src/sections/community-safty/components/population-dynamics.js index ac17319..f62754c 100644 --- a/super-screen/client/src/sections/community-safty/components/population-dynamics.js +++ b/super-screen/client/src/sections/community-safty/components/population-dynamics.js @@ -1,32 +1,12 @@ import React from 'react' import { Box } from '$components'; +import ThreeDBarChart from './charts/bar'; function PopulationDynamics() { - const data = [ - { title: '常驻人口', number: 447 }, - { title: '流动人口', number: 447 }, - { title: '境外人口', number: 447 }, - { title: '未落户人口', number: 447 }, - { title: '贫困人口', number: 447 }, - { title: '老龄人口', number: 447 }, - ] - return -
-
-
- { - data.map(s => { - return
-
{s.title}
-
{s.number}
- 万人 -
- }) - } -
-
+ return + } diff --git a/super-screen/client/src/sections/community-safty/components/special-person.js b/super-screen/client/src/sections/community-safty/components/special-person.js index bcdf793..392754d 100644 --- a/super-screen/client/src/sections/community-safty/components/special-person.js +++ b/super-screen/client/src/sections/community-safty/components/special-person.js @@ -1,28 +1,31 @@ import React, { useEffect, useState } from 'react' import { Box } from '$components'; import './style.less'; +import RingChart from './charts/pie'; function SpecialPerson(props) { - const data = [ - { name: '刑满释放', number: 447 }, - { name: '社区矫正', number: 447 }, - { name: '吸毒人员', number: 447 }, - { name: '重点青少年', number: 447 }, - { name: '艾滋病人', number: 447 }, + { name: '17岁以下', value: 2312 }, + { name: '18-28岁', value: 123 }, + { name: '29-40岁', value: 432 }, + { name: '41-65岁', value: 42 }, + { name: '66-85岁', value: 41}, + { name: '85岁以上', value: 43 } ] - return -
- { - data.map((s, index) => { - return
- {s.name} - {s.number} -
- }) - } -
+ return + } diff --git a/super-screen/client/src/sections/community-safty/containers/gis.js b/super-screen/client/src/sections/community-safty/containers/gis.js index 08b26a5..9591251 100644 --- a/super-screen/client/src/sections/community-safty/containers/gis.js +++ b/super-screen/client/src/sections/community-safty/containers/gis.js @@ -333,34 +333,19 @@ function Map(props) { } const renderRightBottom = () => { - // | type | 设备类型 | 1-获取消防栓 2-水箱 3-烟感 4-配电箱 - return tab == 'device' ? -
- {[ - { name: '烟感设备', icon: 'gissmoke', type: 3 }, - { name: '配电箱', icon: 'giselectricity', type: 4 }, - { name: '消火栓', icon: 'gishydrant', type: 1 }, - { name: '水箱', icon: 'giswatertank', type: 2 } - ].map(s =>
-
{ setType(s.type) }} className={`checkbox`} >{s.type == type ? '✓' : ''}
- - {s.name} -
)} -
: -
-
-
- 廉租房 -
-
-
- 回迁房 -
-
-
- 城中村 -
-
+ return
+ {[ + { name: '烟感设备', icon: 'gissmoke', type: 3 }, + { name: '配电箱', icon: 'giselectricity', type: 4 }, + { name: '消火栓', icon: 'gishydrant', type: 1 }, + { name: '水箱', icon: 'giswatertank', type: 2 } + ].map(s =>
+
{ setType(s.type) }} className={`checkbox`} >{s.type == type ? '✓' : ''}
+ + {s.name} +
)} +
+ } @@ -394,8 +379,8 @@ function Map(props) { } {/* 左上角图例 */} - {renderLeftTop()} - {renderRightBottom()} + {tab == 'home' && renderLeftTop()} + {tab == 'device' && renderRightBottom()} {/* 四周遮罩 */}
diff --git a/super-screen/client/src/sections/community-safty/containers/homePage.js b/super-screen/client/src/sections/community-safty/containers/homePage.js index 25bb03f..4142f6a 100644 --- a/super-screen/client/src/sections/community-safty/containers/homePage.js +++ b/super-screen/client/src/sections/community-safty/containers/homePage.js @@ -4,7 +4,7 @@ import { push } from 'react-router-redux'; import LeftTop from '../components/basic-info' import LeftMiddle from '../components/population-dynamics' import RightTop from '../components/infrastructure' -import RightBottom from '../components/city-safty' +import RightBottom from '../components/city-safty' import RightMiddle from '../components/special-person' import LeftBottom from '../components/traffic-ranking' import Gis from './gis'; @@ -13,10 +13,48 @@ import { FullScreenContainer } from '$components' import './style.less' function homePage(props) { - const { dispatch } = props; + const { dispatch, actions } = props; + const { waterLogin, getWaterStructures, getWaterAlarms } = actions.waterprevention; const childStyle = { height: '32%', color: '#fff', marginBottom: 17 } const cardHeight = document.body.clientHeight * 0.896 * 0.32 const cardContentHeight = cardHeight - 42 - 13 + const [waterLevelAlarms, setWaterLevelAlarms] = useState([]); + useEffect(() => { + getData(); + }, []) + + const getData = () => { + // 水务 + dispatch(waterLogin({ username: "123456", password: "123456", pcode: 'fce4afe2-5b6a-408a-ab18-a2afa7fa027c' })).then(loginRes => { + if (loginRes.success) { + const { token } = loginRes.payload.data; + sessionStorage.setItem('waterUser', JSON.stringify(loginRes.payload.data)); + // 结构物 + dispatch(getWaterStructures({ token })).then(structRes => { + if (structRes.success) { + // 告警 + dispatch(getWaterAlarms({ token })).then(alarmRes => { + if (alarmRes.success) { + let levelAlarms = []; + alarmRes.payload.data.alarms.forEach(a => { + let alarm = { ...a } + for (const struct of structRes.payload.data) { + if (struct.id === a.structureId && struct.type.name === '河流') { + alarm.lng = struct.longitude; + alarm.lat = struct.latitude; + levelAlarms.push(alarm); + } + }; + }) + setWaterLevelAlarms(levelAlarms); + } + }) + } + }) + } + }) + } + return <>
@@ -59,7 +97,7 @@ function homePage(props) {
- +