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> |
||||
<el-scrollbar height="100vh"> |
||||
<div class="wrapper"> |
||||
<datav-header /> |
||||
<img src="/imgs/datav/jwpy.png" alt="" class="relative"> |
||||
</div> |
||||
</el-scrollbar> |
||||
<el-scrollbar height="100vh"> |
||||
<div class="wrapper"> |
||||
<datav-header/> |
||||
<main> |
||||
<el-row :gutter="16"> |
||||
<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> |
||||
|
||||
|
||||
<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> |
||||
|
||||
|
||||
<style lang="scss" scoped> |
||||
@import "@/style/datav.scss"; |
||||
|
||||
.dropdown-container { |
||||
position: absolute; |
||||
right: 30px; |
||||
top: 65px; |
||||
} |
||||
|
||||
.datav-tab-item { |
||||
display: flex; |
||||
justify-content: center; |
||||
align-items: center; |
||||
} |
||||
|
||||
|
||||
</style> |
||||
Loading…
Reference in new issue