Browse Source

(*)社区功能提交

master
peng.peng 1 year ago
parent
commit
b3f1b88a8b
  1. 3
      super-screen/client/src/sections/community-safty/components/basic-info.js
  2. 235
      super-screen/client/src/sections/community-safty/components/charts/bar.js
  3. 124
      super-screen/client/src/sections/community-safty/components/charts/pie.js
  4. 15
      super-screen/client/src/sections/community-safty/components/charts/style.less
  5. 86
      super-screen/client/src/sections/community-safty/components/city-safty.js
  6. 17
      super-screen/client/src/sections/community-safty/components/infrastructure.js
  7. 26
      super-screen/client/src/sections/community-safty/components/population-dynamics.js
  8. 37
      super-screen/client/src/sections/community-safty/components/special-person.js
  9. 45
      super-screen/client/src/sections/community-safty/containers/gis.js
  10. 44
      super-screen/client/src/sections/community-safty/containers/homePage.js

3
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 <Box title={"基本信息"} >
<div className='_basic_info'>
<div className='_basic_row1'>

235
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 <>
<div className='bar_legend'><div className='_block' />家庭人口数</div>
<ReactEcharts
option={option}
notMerge
lazyUpdate
style={{ height: 231, width: 423 }}
/>
</>
}
export default ThreeDBarChart;

124
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) => (
<div key={s.name || index} className="type-leagle-item flex-row flex-item-center" style={{ background: "linear-gradient(90deg, #002C6C 0%, #1e293800 100%)", height: 24, marginBottom: 8, width: 180, }}>
<div className="flex-row flex-item-center">
<div className="type-leagle-dot" style={{ background: RING_COLORS[index]?.linearGradientFrom }} />
<div className="type-leagle-label">{s.name}</div>
</div>
<div className="type-leagle-value">{s.value} <div style={{ textAlign: 'right', display: 'inline-block', width: 40, fontSize: 14, color: RING_COLORS[index]?.linearGradientFrom }}>{Math.round(s.value / total * 100)}%</div></div>
</div>
));
return (
<div style={{ height: '100%' }} className="flex-row flex-item-center">
<div className="type-chart-wrapper">
<ReactEcharts
option={options}
notMerge
lazyUpdate
style={{ height: height || '174px', margin: '0', width: width || 'auto' }}
/>
</div>
<div className="type-leagle-wrapper flex-row flex-content-between" style={{ height: 185, paddingLeft: 10, paddingRight: 10 }}>
{renderList()}
</div>
</div>
);
}
export default RingChart;

15
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;
}
}

86
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 <div className='_city_safty'>
<div className='alarm_handle'>
<div className='handle_img' />
<div className='alarm_content'>
<div className='alarm_bg'>
<div className='alarm_title1'>2023-06-20 170000</div>
<div className='alarm_title2'>已处理</div>
</div>
<div className='alarm_text'>萌萌小区25栋305等等等等等发生等等火灾扥大哥大呢个</div>
</div>
</div>
<div className='alarm_unhandle'>
<div className='handle_img' />
<div className='alarm_content'>
<div className='alarm_bg'>
<div className='alarm_title1'>2023-06-20 170000</div>
<div className='alarm_title2' style={{ color: '#24DCF7' }}>处理中</div>
{fireAlarms.map(s => {
const handled = s?.state == 2
return <div className={handled ? 'alarm_handle' : 'alarm_unhandle'}>
<div className='handle_img' />
<div className='alarm_content'>
<div className='alarm_bg'>
<div className='alarm_title1'>{moment(s.createTime).format('YYYY-MM-DD HH:mm:ss')}</div>
<div className='alarm_title2' style={{ color: handled ? '#FFF' : '#24DCF7' }}>{handled ? '已处理' : '处理中'}</div>
</div>
<div className='alarm_text'>{s?.location}</div>
</div>
<div className='alarm_text'>萌萌小区25栋305等等等等等发生等等火灾扥大哥大呢个</div>
</div>
</div>
<div className='alarm_unhandle'>
})}
</div>
}
const renderList = () => <div className='_city_safty'>
{
waterLevelAlarms?.map(a => <div className={a.alarms[0]?.state >= 3 ? 'alarm_handle' : 'alarm_unhandle'}>
<div className='handle_img' />
<div className='alarm_content'>
<div className='alarm_bg'>
<div className='alarm_title1'>2023-06-20 170000</div>
<div className='alarm_title2' style={{ color: '#24DCF7' }}>处理中</div>
<Tooltip title={a.alarms[0]?.source?.name}>
<div className='alarm_title1'>{a.alarms[0]?.source?.name}</div>
</Tooltip>
<div className='alarm_title2' style={{ color: a.alarms[0]?.state >= 3 ? '#FFEA00' : '#FF2C2C' }}>{convertLevelToLabel(a.alarms[0]?.level)}</div>
</div>
<div className='alarm_text'>萌萌小区25栋305等等等等等发生等等火灾扥大哥大呢个</div>
<div className='alarm_text'>{a.alarms[0]?.content}</div>
</div>
</div>
</div>
}
</div>)
}
</div>
const dataSource = fireAlarms.concat(waterLevelAlarms || [])
return <Box title={"城市安全"} >
<AutoRollComponent canScroll={true} content={getContent()} divHeight={240} divId={`community-right-top`} />
{
dataSource?.length > 0 ? <AutoRollComponent
canScroll={true}
content={<>
{renderList()}
{getContent()}
</>}
divHeight={240}
divId={`community-right-top`} />
: <NoData height={240} />
}
</Box>
}
export default CitySafty;
function convertLevelToLabel(level) {
switch (level) {
case 1:
return '一级预警';
case 2:
return '二级预警';
case 3:
return '三级预警';
default:
return '';
}
}

17
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 <Box title={"基础设施"} >
{/* <NoData /> */}

26
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 <Box title={"人口动态"} >
<div className='_person_trends'>
<div className='_person_tends_item1' />
<div className='_person_tends_item2'>
{
data.map(s => {
return <div className='_person_text'>
<div className='_person_title'>{s.title}</div>
<div className='_person_number'>{s.number}</div>
<span>万人</span>
</div>
})
}
</div>
</div>
return <Box title={"租户家庭人口统计"} >
<ThreeDBarChart />
</Box>
}

37
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 <Box title={"特殊人群统计"}>
<div className='_special'>
{
data.map((s, index) => {
return <div className={`_special_item _special_bg${index % 2 == 0 ? 1 : 2}`}>
<span>{s.name}</span>
<span><span className='_number'>{s.number}</span></span>
</div>
})
}
</div>
return <Box title={"租户年龄分布"}>
<RingChart
data={data}
width={220}
height={220}
image={
{
url: '/assets/images/ring_bg.png',
width: 106,
height: 106,
}
}
/>
</Box>
}

45
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' ?
<div className='device_home_right'>
{[
{ name: '烟感设备', icon: 'gissmoke', type: 3 },
{ name: '配电箱', icon: 'giselectricity', type: 4 },
{ name: '消火栓', icon: 'gishydrant', type: 1 },
{ name: '水箱', icon: 'giswatertank', type: 2 }
].map(s => <div className='flex-row flex-item-center' style={{ marginBottom: 8 }}>
<div onClick={() => { setType(s.type) }} className={`checkbox`} >{s.type == type ? '✓' : ''}</div>
<img src={`/assets/images/homepage/communtity/${s.icon}.png`} />
<span>{s.name}</span>
</div>)}
</div> :
<div className='home_right'>
<div className='_lz'>
<div className='_icon' />
<span>廉租房</span>
</div>
<div className='_hq'>
<div className='_icon' />
<span>回迁房</span>
</div>
<div className='_cz'>
<div className='_icon' />
<span>城中村</span>
</div>
</div>
return <div className='device_home_right'>
{[
{ name: '烟感设备', icon: 'gissmoke', type: 3 },
{ name: '配电箱', icon: 'giselectricity', type: 4 },
{ name: '消火栓', icon: 'gishydrant', type: 1 },
{ name: '水箱', icon: 'giswatertank', type: 2 }
].map(s => <div className='flex-row flex-item-center' style={{ marginBottom: 8 }}>
<div onClick={() => { setType(s.type) }} className={`checkbox`} >{s.type == type ? '✓' : ''}</div>
<img src={`/assets/images/homepage/communtity/${s.icon}.png`} />
<span>{s.name}</span>
</div>)}
</div>
}
@ -394,8 +379,8 @@ function Map(props) {
}
{/* 左上角图例 */}
{renderLeftTop()}
{renderRightBottom()}
{tab == 'home' && renderLeftTop()}
{tab == 'device' && renderRightBottom()}
{/* 四周遮罩 */}
<div className='gis-left'></div>
<div className='gis-right'></div>

44
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 <>
<FullScreenContainer>
<div className='homepage'>
@ -59,7 +97,7 @@ function homePage(props) {
<RightMiddle cardContentHeight={cardContentHeight} />
</div>
<div className='child-right' style={childStyle}>
<RightBottom />
<RightBottom waterLevelAlarms={waterLevelAlarms} />
</div>
</div>
</div>

Loading…
Cancel
Save