peng.peng
1 year ago
10 changed files with 528 additions and 104 deletions
@ -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; |
|||
|
|||
|
@ -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; |
@ -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; |
|||
} |
|||
} |
@ -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 17:00:00</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 17:00:00</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 17:00:00</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 ''; |
|||
} |
|||
} |
|||
|
Loading…
Reference in new issue