5 changed files with 758 additions and 125 deletions
@ -0,0 +1,180 @@ |
|||||||
|
<template> |
||||||
|
<div class="flex between v-center mb-10"> |
||||||
|
<span class="bar-title">{{ title }}</span> |
||||||
|
<span class="bar-sub-title">{{ subTitle }}</span> |
||||||
|
</div> |
||||||
|
<div> |
||||||
|
<div |
||||||
|
class="flex v-center bar-item wrap between " |
||||||
|
v-for="item in data" |
||||||
|
:size="size" |
||||||
|
:style="{ '--label-width': `${labelWidth}px` }" |
||||||
|
:position="labelPosition" |
||||||
|
style="height: 40px" |
||||||
|
> |
||||||
|
<span style="margin-left: 18px"> |
||||||
|
{{ item.sort }} |
||||||
|
</span> |
||||||
|
<div class="bar-item_content mr-8 " :long="!item.denominator" > |
||||||
|
<span>{{item.label}}</span> |
||||||
|
<div |
||||||
|
class="bar-item_content-bar" |
||||||
|
:style="{ |
||||||
|
width: `${(item.value / max) * 100}%`, |
||||||
|
background: getColor((item.value / max) * 100), |
||||||
|
}" |
||||||
|
></div> |
||||||
|
</div> |
||||||
|
<span >{{ item.value }}</span> |
||||||
|
<span |
||||||
|
class="bar-item_remark text-right ml-8" |
||||||
|
v-if="item.denominator" |
||||||
|
style="min-width: 40px" |
||||||
|
> |
||||||
|
<span class="text-success">{{ item.numerator }}</span> |
||||||
|
<span>/</span> |
||||||
|
<span>{{ item.denominator }}</span> |
||||||
|
</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<script setup> |
||||||
|
import { onMounted } from "vue"; |
||||||
|
|
||||||
|
const props = defineProps({ |
||||||
|
title: { |
||||||
|
type: String, |
||||||
|
default: "", |
||||||
|
}, |
||||||
|
subTitle: { |
||||||
|
type: String, |
||||||
|
default: "", |
||||||
|
}, |
||||||
|
data: { |
||||||
|
type: Array, |
||||||
|
default: [], |
||||||
|
}, |
||||||
|
size: { |
||||||
|
type: String, |
||||||
|
default: "", |
||||||
|
}, |
||||||
|
unit: { |
||||||
|
type: String, |
||||||
|
default: "", |
||||||
|
}, |
||||||
|
color: { |
||||||
|
type: Object, |
||||||
|
default: "linear-gradient(270deg, #63e700 0%, #19674c 100%)", |
||||||
|
}, |
||||||
|
labelWidth: { |
||||||
|
type: Number, |
||||||
|
default: 60, |
||||||
|
}, |
||||||
|
labelPosition: { |
||||||
|
type: String, |
||||||
|
default: "left", |
||||||
|
}, |
||||||
|
}); |
||||||
|
|
||||||
|
const max = ref(100); |
||||||
|
watch( |
||||||
|
() => props.data, |
||||||
|
() => { |
||||||
|
getMax(); |
||||||
|
} |
||||||
|
); |
||||||
|
|
||||||
|
function getMax() { |
||||||
|
if (props.unit !== "%") { |
||||||
|
max.value = Math.max(...props.data.map((item) => item.value)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
onMounted(() => { |
||||||
|
getMax(); |
||||||
|
}); |
||||||
|
|
||||||
|
function getColor(val) { |
||||||
|
if (props.color instanceof String) { |
||||||
|
return props.color; |
||||||
|
} |
||||||
|
if (props.color instanceof Array) { |
||||||
|
const colors = [...props.color]; |
||||||
|
colors.sort((a, b) => b.percentage - a.percentage); |
||||||
|
for (let i = 0; i < colors.length; i++) { |
||||||
|
if (val > colors[0].percentage) { |
||||||
|
return colors[0].color; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return "linear-gradient(270deg, #63e700 0%, #19674c 100%)"; |
||||||
|
// if (val >= 0.7) { |
||||||
|
// return "linear-gradient( 270deg, #FFB90E 0%, #71501D 100%)"; |
||||||
|
// } |
||||||
|
// return "linear-gradient( 270deg, #FB002D 0%, #822232 100%)"; |
||||||
|
} |
||||||
|
</script> |
||||||
|
<style lang="scss" scoped> |
||||||
|
.bar-title { |
||||||
|
font-size: 19px; |
||||||
|
} |
||||||
|
.bar-sub-title { |
||||||
|
color: #597ae9; |
||||||
|
font-size: 14px; |
||||||
|
} |
||||||
|
.bar-item { |
||||||
|
font-size: 17px; |
||||||
|
&[size="large"] { |
||||||
|
.bar-item_content { |
||||||
|
.bar-item_content-bar { |
||||||
|
height: 13px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
&[size="small"] { |
||||||
|
font-size: 12px; |
||||||
|
} |
||||||
|
.bar-item-label { |
||||||
|
text-align: right; |
||||||
|
width: var(--label-width); |
||||||
|
overflow: hidden; |
||||||
|
white-space: nowrap; |
||||||
|
text-overflow: ellipsis; |
||||||
|
} |
||||||
|
&[position="left"] { |
||||||
|
height: 32px; |
||||||
|
line-height: 32px; |
||||||
|
} |
||||||
|
&[position="top"] { |
||||||
|
margin-bottom: 4px; |
||||||
|
.bar-item-label { |
||||||
|
width: 100%; |
||||||
|
text-align: left; |
||||||
|
} |
||||||
|
.bar-item_content { |
||||||
|
width: calc(100% - 80px); |
||||||
|
} |
||||||
|
} |
||||||
|
.bar-item_content { |
||||||
|
width: calc(100% - var(--label-width) - 16px - 30px); |
||||||
|
&[long=false] { |
||||||
|
width: calc(100% - var(--label-width) - 36px - 58px); |
||||||
|
} |
||||||
|
.bar-item_content-bar { |
||||||
|
width: 0; |
||||||
|
height: 9px; |
||||||
|
background: linear-gradient(270deg, #63e700 0%, #19674c 100%); |
||||||
|
transition: width 0.3s; |
||||||
|
} |
||||||
|
} |
||||||
|
.bar-item_remark { |
||||||
|
font-size: 14px; |
||||||
|
.text-success { |
||||||
|
color: #09c700; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</style> |
||||||
@ -1,14 +1,343 @@ |
|||||||
<template> |
<template> |
||||||
<el-scrollbar height="100vh"> |
<el-scrollbar height="100vh"> |
||||||
<div class="wrapper"> |
<div class="wrapper"> |
||||||
<datav-header /> |
<datav-header/> |
||||||
<img src="/imgs/datav/jwpy.png" alt="" class="relative"> |
<main> |
||||||
</div> |
<el-row :gutter="16"> |
||||||
</el-scrollbar> |
<el-col :span="6"> |
||||||
|
<datav-card title="调查情况"> |
||||||
|
<el-row class="mb-32"> |
||||||
|
<el-col :span="4"> |
||||||
|
<div class="descriptions_cell text-center"> |
||||||
|
<div class="descriptions_content"> |
||||||
|
{{ overview.firstMail }} |
||||||
|
</div> |
||||||
|
<div class="descriptions_label"> |
||||||
|
调查总量 |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</el-col> |
||||||
|
<el-col :span="4"> |
||||||
|
<div class="descriptions_cell text-center"> |
||||||
|
<div class="descriptions_content"> |
||||||
|
{{ overview.firstMail }} |
||||||
|
</div> |
||||||
|
<div class="descriptions_label"> |
||||||
|
调查总量 |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</el-col> |
||||||
|
<el-col :span="4"> |
||||||
|
<div class="descriptions_cell text-center"> |
||||||
|
<div class="descriptions_content"> |
||||||
|
{{ overview.firstMail }} |
||||||
|
</div> |
||||||
|
<div class="descriptions_label"> |
||||||
|
有效回复 |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</el-col> |
||||||
|
<el-col :span="4"> |
||||||
|
<div class="descriptions_cell text-center"> |
||||||
|
<div class="descriptions_content"> |
||||||
|
{{ overview.firstMail }} |
||||||
|
</div> |
||||||
|
<div class="descriptions_label"> |
||||||
|
满意 |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</el-col> |
||||||
|
<el-col :span="4"> |
||||||
|
<div class="descriptions_cell text-center"> |
||||||
|
<div class="descriptions_content"> |
||||||
|
{{ overview.firstMail }} |
||||||
|
</div> |
||||||
|
<div class="descriptions_label"> |
||||||
|
基本满意 |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</el-col> |
||||||
|
<el-col :span="4"> |
||||||
|
<div class="descriptions_cell text-center"> |
||||||
|
<div class="descriptions_content"> |
||||||
|
{{ overview.firstMail }} |
||||||
|
</div> |
||||||
|
<div class="descriptions_label"> |
||||||
|
不满意数 |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</el-col> |
||||||
|
</el-row> |
||||||
|
</datav-card> |
||||||
|
<datav-card title="调查滿意度"></datav-card> |
||||||
|
<datav-card title="业务满意率"></datav-card> |
||||||
|
</el-col> |
||||||
|
|
||||||
|
<el-col :span="12"> |
||||||
|
<div class="datav-col"> |
||||||
|
<datav-date-picker v-model="time"/> |
||||||
|
</div> |
||||||
|
<v-charts |
||||||
|
style="height: 450px" |
||||||
|
:option="option" |
||||||
|
autoresize |
||||||
|
/> |
||||||
|
|
||||||
|
<datav-card title="综合滿意度排名"> |
||||||
|
|
||||||
|
</datav-card> |
||||||
|
|
||||||
|
</el-col> |
||||||
|
|
||||||
|
<el-col :span="6"> |
||||||
|
<datav-card title="不满意样本趋势"> |
||||||
|
|
||||||
|
</datav-card> |
||||||
|
<datav-card title="单项分析"></datav-card> |
||||||
|
<datav-card title="单项调查情况"></datav-card> |
||||||
|
</el-col> |
||||||
|
|
||||||
|
</el-row> |
||||||
|
</main> |
||||||
|
</div> |
||||||
|
</el-scrollbar> |
||||||
|
|
||||||
</template> |
</template> |
||||||
|
|
||||||
|
|
||||||
<script setup> |
<script setup> |
||||||
|
import vCharts from "vue-echarts"; |
||||||
|
import changshaMap from "@/assets/data/changsha.json"; |
||||||
|
import * as echarts from "echarts/core"; |
||||||
|
import {getMailVisitsData, getRecentlyMailTrend, getRecentlyMailTrend12337} from "@/api/datav"; |
||||||
|
import moment from "moment/moment.js"; |
||||||
|
|
||||||
|
echarts.registerMap("changsha", changshaMap); |
||||||
|
let mapDataList = reactive([ |
||||||
|
{name: '长沙县', value: 500}, |
||||||
|
{name: '浏阳市', value: 400}, |
||||||
|
{name: '开福区', value: 300}, |
||||||
|
{name: '浏阳市', value: 400}, |
||||||
|
{name: '望城区', value: 400}, |
||||||
|
{name: '芙蓉区', value: 400}, |
||||||
|
{name: '天心区', value: 400}, |
||||||
|
{name: '雨花区', value: 400}, |
||||||
|
{name: '岳麓区', value: 400}, |
||||||
|
{name: '宁乡市', value: 400}, |
||||||
|
]); |
||||||
|
const option = { |
||||||
|
geo: { |
||||||
|
// 是上面注册时的名字哦,registerMap('名字保持一致') |
||||||
|
map: "changsha", |
||||||
|
itemStyle: { |
||||||
|
normal: { |
||||||
|
areaColor: "#02215E", // 这里将地图区域的颜色修改为红色 |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
tooltip: { |
||||||
|
show: true, |
||||||
|
trigger: "item", |
||||||
|
position: "right", |
||||||
|
formatter: function (params) { |
||||||
|
if (typeof params.data === "undefined") { |
||||||
|
console.log(params); |
||||||
|
} else { |
||||||
|
console.log(params); |
||||||
|
return `<div class="tooltip"> |
||||||
|
<div class="tooltip-title">${params.name}</div> |
||||||
|
<div class="tooltip-content"> |
||||||
|
<ul class="tooltip-ul"> |
||||||
|
<li>信访总件数 <span>${params.data.todaysum}</span></li> |
||||||
|
<li>国家信访 <span>${params.data.allsum}</span> |
||||||
|
</li> |
||||||
|
<li>公安部信访 <span>${params.data.completed}</span> |
||||||
|
</li> |
||||||
|
<li>局长信箱 <span>${params.data.completedrate}</span></li> |
||||||
|
<li>12337信访 <span>${params.data.resolvedrate}</span></li> |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
</div>`; |
||||||
|
} |
||||||
|
}, |
||||||
|
backgroundColor: "#031577", // |
||||||
|
borderColor: "#0A2F86", |
||||||
|
borderWidth: 0, // 设置边框宽度为1像素 |
||||||
|
borderRadius: 3, // 设置边框半径为3像素 |
||||||
|
shadowBlur: 0, // 设置阴影模糊程度为8像素 |
||||||
|
shadowOffsetX: 0, // 设置水平阴影位移量为0像素 |
||||||
|
shadowOffsetY: 0, // 设置垂直阴影位移量为6像素 |
||||||
|
}, |
||||||
|
visualMap: { |
||||||
|
type: "piecewise", |
||||||
|
bottom: 10, |
||||||
|
pieces: [ |
||||||
|
{gte: 85, lte: 100, label: "信访总件数>300"}, |
||||||
|
{gte: 65, lte: 85, label: "信访总件数>200"}, |
||||||
|
{gte: 0, lte: 65, label: "信访总件数0-200"}, |
||||||
|
], |
||||||
|
right: 10, // 右边距 |
||||||
|
realtime: false, |
||||||
|
orient: "horizontal", // 水平显示 |
||||||
|
textStyle: { |
||||||
|
color: "#fff", // 文字颜色 |
||||||
|
}, |
||||||
|
calculable: true, |
||||||
|
inRange: { |
||||||
|
color: ["#D34343", "#F6A149", "#4987F6"], |
||||||
|
}, |
||||||
|
}, |
||||||
|
series: [ |
||||||
|
{ |
||||||
|
name: "长沙", |
||||||
|
type: "map", |
||||||
|
map: "changsha", |
||||||
|
hoverAnimation: true, |
||||||
|
label: { |
||||||
|
show: true, |
||||||
|
color: "white", |
||||||
|
}, |
||||||
|
data: mapDataList, |
||||||
|
}, |
||||||
|
|
||||||
|
], |
||||||
|
|
||||||
|
}; |
||||||
|
const option1 = ref({ |
||||||
|
xAxis: { |
||||||
|
type: "category", |
||||||
|
boundaryGap: false, |
||||||
|
data: [], |
||||||
|
}, |
||||||
|
yAxis: { |
||||||
|
type: "value", |
||||||
|
splitLine: { |
||||||
|
show: true, |
||||||
|
lineStyle: { |
||||||
|
color: "#193775", |
||||||
|
}, |
||||||
|
} |
||||||
|
}, |
||||||
|
tooltip: { |
||||||
|
trigger: 'axis', |
||||||
|
axisPointer: { |
||||||
|
type: 'line', |
||||||
|
label: { |
||||||
|
backgroundColor: '#6a7985' |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
series: [ |
||||||
|
{ |
||||||
|
type: "line", |
||||||
|
smooth: true, |
||||||
|
label: { |
||||||
|
show: false |
||||||
|
}, |
||||||
|
lineStyle: { |
||||||
|
color: "#28E6FF", |
||||||
|
width: 4, |
||||||
|
}, |
||||||
|
areaStyle: { |
||||||
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ |
||||||
|
{ |
||||||
|
offset: 0, |
||||||
|
color: "rgba(40,230,255,0.47)", // 渐变起始颜色 |
||||||
|
}, |
||||||
|
{ |
||||||
|
offset: 1, |
||||||
|
color: "rgba(40,230,255,0)", // 渐变结束颜色 |
||||||
|
}, |
||||||
|
]), |
||||||
|
}, |
||||||
|
data: [], |
||||||
|
}, |
||||||
|
], |
||||||
|
}); |
||||||
|
// region 调查满意度 |
||||||
|
const overview = ref({ |
||||||
|
total: 0, |
||||||
|
countryMail: 0, |
||||||
|
policeMail: 0, |
||||||
|
commissionerMail: 0, |
||||||
|
numMail: 0, |
||||||
|
}); |
||||||
|
|
||||||
|
const time = ref([ |
||||||
|
moment().startOf("year").format("YYYY-MM-DD"), |
||||||
|
moment().format("YYYY-MM-DD"), |
||||||
|
]); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 初始化 |
||||||
|
*/ |
||||||
|
let timer; |
||||||
|
const currentYear = new Date().getFullYear(); |
||||||
|
|
||||||
|
function initRecentlyMailTrend() { |
||||||
|
getRecentlyMailTrend({ |
||||||
|
sourcesCode: "1", |
||||||
|
year: currentYear, |
||||||
|
startTime: time.value[0], |
||||||
|
endTime: time.value[1] |
||||||
|
}).then((data) => { |
||||||
|
// 更新图表的 xAxis 和 series 数据 |
||||||
|
option1.value.xAxis.data = data.monthList; |
||||||
|
option1.value.series[0].data = data.totalList; |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
watch(time, () => { |
||||||
|
getData(); |
||||||
|
// initRecentlyMailTrend() |
||||||
|
}) |
||||||
|
onMounted(() => { |
||||||
|
getData(); |
||||||
|
initRecentlyMailTrend(); |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
function getData() { |
||||||
|
getMailVisitsData(time.value).then((data) => { |
||||||
|
overview.value = data.overview; |
||||||
|
|
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
const colors = [ |
||||||
|
{ |
||||||
|
color: "linear-gradient( 270deg, #FB002D 0%, #822232 100%)", |
||||||
|
percentage: 80, |
||||||
|
}, |
||||||
|
{ |
||||||
|
color: "linear-gradient( 270deg, #FFB90E 0%, #71501D 100%)", |
||||||
|
percentage: 60, |
||||||
|
}, |
||||||
|
{ |
||||||
|
color: "linear-gradient( 270deg, #63E700 0%, #19674C 100%)", |
||||||
|
percentage: 40, |
||||||
|
}, |
||||||
|
]; |
||||||
|
|
||||||
|
|
||||||
</script> |
</script> |
||||||
|
|
||||||
|
|
||||||
<style lang="scss" scoped> |
<style lang="scss" scoped> |
||||||
@import "@/style/datav.scss"; |
@import "@/style/datav.scss"; |
||||||
|
|
||||||
|
.dropdown-container { |
||||||
|
position: absolute; |
||||||
|
right: 30px; |
||||||
|
top: 65px; |
||||||
|
} |
||||||
|
|
||||||
|
.datav-tab-item { |
||||||
|
display: flex; |
||||||
|
justify-content: center; |
||||||
|
align-items: center; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
</style> |
</style> |
||||||
Loading…
Reference in new issue