Browse Source

大屏统计考核得分情况

dev
巴林闲侠 2 years ago
parent
commit
8c45b9326a
  1. 38
      api/app/lib/controllers/data/assess.js
  2. 3
      api/app/lib/routes/data/index.js
  3. 11
      web/client/src/sections/quanju/actions/example.js
  4. 87
      web/client/src/sections/quanju/containers/footer/conserve/left/left-center.js
  5. 106
      web/client/src/sections/quanju/containers/footer/conserve/right/right-center.js
  6. 128
      web/client/src/sections/quanju/containers/footer/conserve/right/right-top.js
  7. 2
      web/client/src/sections/quanju/containers/footer/leadership/left/left-center.js
  8. 1
      web/client/src/utils/webapi.js
  9. 16
      web/package-lock.json
  10. 1
      web/package.json

38
api/app/lib/controllers/data/assess.js

@ -102,6 +102,42 @@ async function assessDel (ctx) {
} }
} }
async function nearestSourceData (ctx) {
try {
const { models } = ctx.fs.dc;
const { monthRange } = ctx.query
// 查最近的有数据的月份的数据
const nearestRes = await models.Assess.findOne({
order: [['month', 'DESC']],
})
let rslt = []
if (nearestRes) {
rslt = await models.Assess.findAll({
attributes: ['totalPoints', 'unit', 'month'],
where: {
month: {
$between: [
moment(nearestRes.month).subtract(monthRange || 0, 'month').startOf('month').format(), moment(nearestRes.month).endOf('month').format()
]
}
},
order: [['month', 'DESC']],
})
}
ctx.status = 200;
ctx.body = rslt
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: error`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
module.exports = { module.exports = {
assessGet, assessEdit, assessDel, assessGet, assessEdit, assessDel, nearestSourceData,
}; };

3
api/app/lib/routes/data/index.js

@ -192,5 +192,8 @@ module.exports = function (app, router, opts) {
app.fs.api.logAttr['DEL/assess/:assessId'] = { content: '删除评分考核数据', visible: false }; app.fs.api.logAttr['DEL/assess/:assessId'] = { content: '删除评分考核数据', visible: false };
router.del('/assess/:assessId', assess.assessDel); router.del('/assess/:assessId', assess.assessDel);
app.fs.api.logAttr['GET/assess/nearest'] = { content: '获取评分考核最近的月份的所有考核单位的数据', visible: true };
router.get('/assess/nearest', assess.nearestSourceData);
// 评分考核 END // 评分考核 END
}; };

11
web/client/src/sections/quanju/actions/example.js

@ -157,3 +157,14 @@ export function getCustodyunit() {
// reducer: { name: 'roadMaintenances' } // reducer: { name: 'roadMaintenances' }
}); });
} }
export function getNearestAssessData (query = {}) {
return dispatch => basicAction({
type: 'get',
query,
dispatch: dispatch,
actionType: 'GET_NEAREST_ASSESS_DATA',
url: ApiTable.nearestAssessData,
msg: { error: '获取各乡镇考核得分情况失败' },
});
}

87
web/client/src/sections/quanju/containers/footer/conserve/left/left-center.js

@ -6,18 +6,59 @@ import * as echarts from 'echarts';
import ZheXian from "./zhexin" import ZheXian from "./zhexin"
import PieChart from "./shituzujian" import PieChart from "./shituzujian"
import Lunbo from './lunbo'; import Lunbo from './lunbo';
import { connect } from 'react-redux'
import ReactECharts from 'echarts-for-react';
import { getNearestAssessData } from "../../../../actions/example"
import moment from 'moment'
const LeftCenter = (props) => { const LeftCenter = (props) => {
const { data, shuju } = props const { data, shuju, dispatch } = props
const style = { height: "31%", marginTop: "3%" } const style = { height: "31%", marginTop: "3%" }
// const chartRef = useState(); // const chartRef = useState();
// const { roadData } = props // const { roadData } = props
const [flag, setFlag] = useState(true) const [flag, setFlag] = useState(true)
// const [colorFlage, setColorFlage] = useState(true) // const [colorFlage, setColorFlage] = useState(true)
const [chartData, setChartData] = useState({
series: [],
xAxis: []
})
useEffect(() => {
dispatch(getNearestAssessData({ monthRange: 6 })).then(res => {
if (res.success) {
let nextChartSeries = []
let nextXAxis = new Set()
let data = res.payload.data
data.reverse()
for (let d of data) {
let corUnitSeries = nextChartSeries.find(item => item.name == d.unit)
let month = moment(d.month).format('YYYY-MM')
nextXAxis.add(month)
if (corUnitSeries) {
corUnitSeries.data.push(d.totalPoints)
} else {
nextChartSeries.push({
type: 'line',
smooth: true,
data: [d.totalPoints],
name: d.unit,
})
}
}
setChartData({
series: nextChartSeries,
xAxis: [...nextXAxis]
})
}
})
}, [])
return ( return (
<> <>
<Module style={style} title={"各乡镇养护里程及费用"}> <Module style={style} title={"各乡镇养护得分趋势"}>
{
false ?
<>
<div onClick={() => { <div onClick={() => {
setFlag(false) setFlag(false)
}} style={{ position: "absolute", top: "38.5%", left: "80%", width: "50px", height: "20px", background: "linear-gradient(270deg, rgba(15,74,159,0) 0%, rgba(17,75,160,0.95) 100%)", float: "right", textAlign: "center", zIndex: 100, marginRight: "4%", borderLeft: "solid 2px #6E7A83" }} > }} style={{ position: "absolute", top: "38.5%", left: "80%", width: "50px", height: "20px", background: "linear-gradient(270deg, rgba(15,74,159,0) 0%, rgba(17,75,160,0.95) 100%)", float: "right", textAlign: "center", zIndex: 100, marginRight: "4%", borderLeft: "solid 2px #6E7A83" }} >
@ -31,8 +72,48 @@ const LeftCenter = (props) => {
{ {
flag ? <Lunbo data={data} /> : <ZheXian shuju={shuju} /> flag ? <Lunbo data={data} /> : <ZheXian shuju={shuju} />
} }
</> : ''
}
<ReactECharts
notMerge={true}
lazyUpdate={true}
option={{
xAxis: {
type: 'category',
data: chartData.xAxis,
boundaryGap: false,
axisTick: {
show: false
}
},
yAxis: {
type: 'value',
splitLine: {
show: false
}
},
tooltip: {
trigger: "axis"
},
series: chartData.series,
grid: {
left: '3%',
right: '12%',
bottom: '21%',
top: '4%',
containLabel: true
},
}}
/>
</Module> </Module>
</> </>
) )
} }
export default LeftCenter function mapStateToProps (state) {
return {
}
}
export default connect(mapStateToProps)(LeftCenter)

106
web/client/src/sections/quanju/containers/footer/conserve/right/right-center.js

@ -1,6 +1,10 @@
import React from 'react' import React from 'react'
import Module from '../../../public/module' import Module from '../../../public/module'
import { Col, Row } from 'antd' import { Col, Row } from 'antd'
import { useEffect, useState } from 'react'
import { connect } from 'react-redux'
import ReactECharts from 'echarts-for-react';
import { getNearestAssessData } from "../../../../actions/example"
// const unit =['个','个',] // const unit =['个','个',]
const icon = [ const icon = [
@ -10,33 +14,47 @@ const icon = [
'assets/images/quanju/zerenpai.png' 'assets/images/quanju/zerenpai.png'
] ]
const RightCenter = (props) => { const RightCenter = (props) => {
const { highwaysData } = props const { highwaysData, dispatch } = props
const [data, setData] = useState([])
const style = { height: "31%", marginTop: "3%" } const style = { height: "31%", marginTop: "3%" }
const textStyle = { fontSize: 14, color: '#E9F7FF' } // const textStyle = { fontSize: 14, color: '#E9F7FF' }
const numStyle = { color: '#fff', fontSize: 21, fontFamily: 'YouSheBiaoTiHei', textShadow: '0px 0px 8px #1C60FE', marginTop: 8 } // const numStyle = { color: '#fff', fontSize: 21, fontFamily: 'YouSheBiaoTiHei', textShadow: '0px 0px 8px #1C60FE', marginTop: 8 }
let list = highwaysData?.sort((a, b) => a.id - b.id) // let list = highwaysData?.sort((a, b) => a.id - b.id)
list = highwaysData?.slice(4, 8).map((h,index)=>{ // list = highwaysData?.slice(4, 8).map((h, index) => {
return { // return {
id:h.id, // id: h.id,
name:h.name, // name: h.name,
count:h.count, // count: h.count,
// unit:unit[index], // // unit:unit[index],
icon:icon[index] // icon: icon[index]
// }
// })
// const arrayChunk = (array, size) => {
// let data = []
// for (let i = 0; i < array.length; i += size) {
// data.push(array.slice(i, i + size))
// }
// return data
// }
// let lists = list ? arrayChunk(list, 2) : []
useEffect(() => {
dispatch(getNearestAssessData()).then(res => {
if (res.success) {
setData(res.payload.data)
} }
}) })
const arrayChunk = (array, size) => { }, [])
let data = []
for (let i = 0; i < array.length; i += size) {
data.push(array.slice(i, i + size))
}
return data
}
let lists = list ? arrayChunk(list, 2) : []
return ( return (
<> <>
<Module style={style} title={"各类附属设施数量统计"}> <Module style={style} title={"各乡镇考核得分情况"}>
<div style={{ paddingLeft: '8%' }}> <div style={{ paddingLeft: '8%' }}>
{ {/* {
lists?.map((item, index) => { lists?.map((item, index) => {
return <div style={{ display: 'flex', marginTop: "5%", justifyContent: 'space-around' }} key={index}> return <div style={{ display: 'flex', marginTop: "5%", justifyContent: 'space-around' }} key={index}>
{ {
@ -52,10 +70,54 @@ const RightCenter = (props) => {
} }
</div> </div>
}) })
} */}
<ReactECharts
notMerge={true}
lazyUpdate={true}
option={{
xAxis: {
type: 'category',
data: data.map(d => d.unit),
axisTick: {
show: false
}
},
yAxis: {
type: 'value',
splitLine: {
show: false
}
},
tooltip: {
trigger: "axis"
},
series: [
{
data: data.map(d => d.totalPoints),
type: 'bar',
showBackground: true,
backgroundStyle: {
color: 'rgba(180, 180, 180, 0.2)'
}
} }
],
grid: {
left: '3%',
right: '4%',
bottom: '21%',
top: '4%',
containLabel: true
},
}}
/>
</div> </div>
</Module> </Module>
</> </>
) )
} }
export default RightCenter function mapStateToProps (state) {
return {
}
}
export default connect(mapStateToProps)(RightCenter)

128
web/client/src/sections/quanju/containers/footer/conserve/right/right-top.js

@ -1,7 +1,11 @@
import { Col, Row } from 'antd' import { Col, Row } from 'antd'
import React, { useState, useEffect } from 'react' import React, { useState, useEffect } from 'react'
import Module from '../../../public/module' import Module from '../../../public/module'
import { connect } from 'react-redux'
import Lun from "../../leadership/right/lunbo"
import { getRoadmaintain } from "../../../../actions/example"
import Hua from "../../leadership/right/hudong"
import moment from 'moment'
const iconSrc = [ const iconSrc = [
'assets/images/quanju/biaoxian.png', 'assets/images/quanju/biaoxian.png',
@ -12,35 +16,99 @@ const iconSrc = [
const unit = ['km', '处', '个', 'km'] const unit = ['km', '处', '个', 'km']
const RightTop = (props) => { const RightTop = (props) => {
const { highwaysData } = props const { highwaysData, dispatch } = props
const [roadmaintainList, setRoadmaintainList] = useState([])
const [beijing, setBeijing] = useState()
const [num, setNum] = useState()
const style = { height: "31%", marginTop: "3%" } const style = { height: "31%", marginTop: "3%" }
const textStyle = { fontSize: 14, color: '#E9F7FF' } // const textStyle = { fontSize: 14, color: '#E9F7FF' }
const numStyle = { color: '#fff', fontSize: 21, fontFamily: 'YouSheBiaoTiHei', textShadow: '0px 0px 8px #1C60FE', marginTop: 8 } // const numStyle = { color: '#fff', fontSize: 21, fontFamily: 'YouSheBiaoTiHei', textShadow: '0px 0px 8px #1C60FE', marginTop: 8 }
let list = highwaysData?.sort((a, b) => a.id - b.id) // let list = highwaysData?.sort((a, b) => a.id - b.id)
list = highwaysData?.slice(0, 4).map((h, index) => { // list = highwaysData?.slice(0, 4).map((h, index) => {
return { // return {
id: h.id, // id: h.id,
name: h.name, // name: h.name,
count: h.count, // count: h.count,
unit: unit[index], // unit: unit[index],
icon: iconSrc[index] // icon: iconSrc[index]
} // }
// })
// const arrayChunk = (array, size) => {
// let data = []
// for (let i = 0; i < array.length; i += size) {
// data.push(array.slice(i, i + size))
// }
// return data
// }
// let lists = list ? arrayChunk(list, 2) : []
useEffect(() => {
dispatch(getRoadmaintain()).then((res) => {
setRoadmaintainList(res.payload.data.reportList.filter((item, index) => {
return item.projectType == "road"
}))
}) })
}, [])
const arrayChunk = (array, size) => { const renderBody = () => {
let data = [] return (
for (let i = 0; i < array.length; i += size) { <div style={{ width: "100%", height: "100%" }}>
data.push(array.slice(i, i + size)) {
roadmaintainList.map((item, index) => {
return (
<li className={index} style={{
height: "20px", position: "relative", width: "100%", color: "#FFFFFF", marginTop: index == 0 ? "4px" : "5px", listStyle: "none", fontSize: "14px"
}} onMouseEnter={() => {
setBeijing(index)
setNum(index)
}} onMouseLeave={() => {
setBeijing()
setNum()
}}>
{beijing == index ? <img src='/assets/images/leadership/shezhi.png' style={{ width: "2%", height: "80%", position: "absolute", top: "12%", left: "1%" }} /> : ""}
{beijing == index ? <img src='/assets/images/leadership/lan.png' style={{ width: "100%", height: "120%", position: "absolute", right: "5%" }} /> : ""}
<p style={{ textAlign: "center", width: "40%", position: "absolute", right: "28.5%", color: beijing == index ? "#ffffff" : "rgba(216,240,255,0.8)" }} >{item?.user?.name || '--'}</p>
<p style={{ textAlign: "left", width: "30%", position: "absolute", left: "5%", color: beijing == index ? "#ffffff" : "rgba(216,240,255,0.8)" }} >{item.road ? item.road : "--"}</p>
<p style={{ textAlign: "right", width: "30%", position: "absolute", right: "3%", color: beijing == index ? "#ffffff" : "rgba(216,240,255,0.8)" }}>
{
item.time ?
moment(item.time).format("YYYY-MM-DD")
: "--"
}
</p>
{
num == index ?
<div style={{ position: "fixed", width: "400px", height: "200px", zIndex: 100, right: "24%", marginTop: "0", top: "25%" }}>
<img src='/assets/images/leadership/beijinglan.png' style={{ width: "100%", height: "100%" }} />
<div style={{ width: "50%", height: "100%", position: "absolute", top: "0", }}>
<Hua shuzu={[{ "imgs": item.conserveAfterPic ? item.conserveAfterPic[0] : "" }, { "imgs": item.conserveBeforePic ? item.conserveBeforePic[0] : "" }, { "imgs": item.conserveUnderwayPic ? item.conserveUnderwayPic[0] : "" }]} />
</div>
<div style={{ position: "absolute", top: "0", width: "50%", left: "50%", paddingRight: "10px" }}>
<p style={{ marginTop: "20px", color: "#FFFFFF", fontSize: "16px", fontFamily: "YouSheBiaoTiHei" }}>
{item.roadSectionStart ? item.roadSectionStart : ""}{item.roadSectionStart && item.roadSectionEnd ? "——" : ""}{item.roadSectionEnd ? item.roadSectionEnd : ""}{item.roadSectionStart || item.roadSectionEnd ? "" : "--"}
</p>
<p style={{ color: "rgba(216,240,255,0.8)", fontSize: "14px", fontFamily: "PingFangSC-Regular, PingFang SC" }}>养护类型<span style={{ color: "#EEF4FF", marginLeft: "30px", fontFamily: " PingFangSC-Medium, PingFang SC" }}>日常养护</span></p>
<p style={{ color: "rgba(216,240,255,0.8)", fontSize: "14px", fontFamily: "PingFangSC-Regular, PingFang SC" }}>负责人<span style={{ color: "#EEF4FF", marginLeft: "45px", fontFamily: " PingFangSC-Medium, PingFang SC" }}>{item.user?.name ? item.user.name : "--"}</span></p>
<p style={{ color: "rgba(216,240,255,0.8)", fontSize: "14px", fontFamily: "PingFangSC-Regular, PingFang SC" }}>日期<span style={{ color: "#EEF4FF", marginLeft: "60px", fontFamily: " PingFangSC-Medium, PingFang SC" }}>{moment(item.time).format("YYYY-MM-DD") ? moment(item.time).format("YYYY-MM-DD") : "--"}</span></p>
</div>
</div> : ""
} }
return data </li>
)
})
} }
let lists = list ? arrayChunk(list, 2) : [] </div>
)
}
return ( return (
<> <>
<Module style={style} title={"道路设施数量统计"}> <Module style={style} title={"养护详情"}>
<div style={{ paddingLeft: '8%' }}> <div style={{ paddingLeft: '8%', height: '100%' }}>
{ {/* {
lists?.map((item, index) => { lists?.map((item, index) => {
return <div style={{ display: 'flex', marginTop: "5%", justifyContent: 'space-around' }} key={index}> return <div style={{ display: 'flex', marginTop: "5%", justifyContent: 'space-around' }} key={index}>
{ {
@ -56,10 +124,22 @@ const RightTop = (props) => {
} }
</div> </div>
}) })
} } */}
<Lun
// canScroll={true}
content={renderBody()}
containerStyle={{ height: "100%", width: "90%" }}
divHeight={"100%"}
divId={"screen"}
/>
</div> </div>
</Module> </Module>
</> </>
) )
} }
export default RightTop function mapStateToProps (state) {
return {
}
}
export default connect(mapStateToProps)(RightTop)

2
web/client/src/sections/quanju/containers/footer/leadership/left/left-center.js

@ -59,7 +59,7 @@ const Leftcenter = () => {
<div style={{ width: "100%", height: "40px"/* , backgroundColor: "#fff" */, position: "relative" }}> <div style={{ width: "100%", height: "40px"/* , backgroundColor: "#fff" */, position: "relative" }}>
{/* <p>{title || []}</p> */} {/* <p>{title || []}</p> */}
<img src='/assets/images/quanju/icon.png' style={{ width: "24px", position: "absolute", left: "20px", top: "20%" }} /> <img src='/assets/images/quanju/icon.png' style={{ width: "24px", position: "absolute", left: "20px", top: "20%" }} />
<span style={{ position: "absolute", color: "#FFFFFF", fontSize: "24px", fontFamily: "YouSheBiaoTiHei", left: "50px" }}>主要路段拥堵情况分析</span> <span style={{ position: "absolute", color: "#FFFFFF", fontSize: "24px", fontFamily: "YouSheBiaoTiHei", left: "50px" }}>主要路段拥堵情况</span>
<img src='/assets/images/leadership/zibiaoti.png' style={{ width: "93%", height: "35px", position: "absolute", top: "8px", left: "35px" }} /> <img src='/assets/images/leadership/zibiaoti.png' style={{ width: "93%", height: "35px", position: "absolute", top: "8px", left: "35px" }} />
</div> </div>
<div style={{ width: "100%", height: "100%", marginTop: "3%" }}> <div style={{ width: "100%", height: "100%", marginTop: "3%" }}>

1
web/client/src/utils/webapi.js

@ -170,6 +170,7 @@ export const ApiTable = {
getAssess: 'assess', getAssess: 'assess',
editAssess: 'assess', editAssess: 'assess',
delAssess: 'assess/{assessId}', delAssess: 'assess/{assessId}',
nearestAssessData:'assess/nearest',
//工程数据 //工程数据
getProject: 'project', getProject: 'project',

16
web/package-lock.json

@ -4446,7 +4446,7 @@
}, },
"cross-env": { "cross-env": {
"version": "7.0.3", "version": "7.0.3",
"resolved": "http://10.8.30.22:7000/cross-env/-/cross-env-7.0.3.tgz", "resolved": "http://npm.anxinyun.cn/cross-env/-/cross-env-7.0.3.tgz",
"integrity": "sha1-hlJkspZ33AFbqEGJGJZd0jL8VM8=", "integrity": "sha1-hlJkspZ33AFbqEGJGJZd0jL8VM8=",
"requires": { "requires": {
"cross-spawn": "^7.0.1" "cross-spawn": "^7.0.1"
@ -4964,6 +4964,15 @@
} }
} }
}, },
"echarts-for-react": {
"version": "3.0.2",
"resolved": "http://10.8.30.22:7000/echarts-for-react/-/echarts-for-react-3.0.2.tgz",
"integrity": "sha512-DRwIiTzx8JfwPOVgGttDytBqdp5VzCSyMRIxubgU/g2n9y3VLUmF2FK7Icmg/sNVkv4+rktmrLN9w22U2yy3fA==",
"requires": {
"fast-deep-equal": "^3.1.3",
"size-sensor": "^1.0.1"
}
},
"ee-first": { "ee-first": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "http://npm.anxinyun.cn/ee-first/-/ee-first-1.1.1.tgz", "resolved": "http://npm.anxinyun.cn/ee-first/-/ee-first-1.1.1.tgz",
@ -10299,6 +10308,11 @@
"totalist": "^1.0.0" "totalist": "^1.0.0"
} }
}, },
"size-sensor": {
"version": "1.0.1",
"resolved": "http://10.8.30.22:7000/size-sensor/-/size-sensor-1.0.1.tgz",
"integrity": "sha1-+E5GIG0+JZ+v8dVI5LO+ypMhnbs="
},
"smart-buffer": { "smart-buffer": {
"version": "4.2.0", "version": "4.2.0",
"resolved": "http://npm.anxinyun.cn/smart-buffer/-/smart-buffer-4.2.0.tgz", "resolved": "http://npm.anxinyun.cn/smart-buffer/-/smart-buffer-4.2.0.tgz",

1
web/package.json

@ -77,6 +77,7 @@
"co-busboy": "^1.4.1", "co-busboy": "^1.4.1",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"echarts": "^5.3.2", "echarts": "^5.3.2",
"echarts-for-react": "^3.0.2",
"fs-web-server-scaffold": "^1.0.6", "fs-web-server-scaffold": "^1.0.6",
"koa-better-http-proxy": "^0.2.5", "koa-better-http-proxy": "^0.2.5",
"koa-convert": "^2.0.0", "koa-convert": "^2.0.0",

Loading…
Cancel
Save