774 lines
18 KiB
Vue
Raw Normal View History

2023-05-12 10:04:12 +08:00
<template>
<div class="leftBorder">
<div class="title">
<div class="text">工程数</div>
</div>
<div class="projectNum">
<div v-for="(item, index) in projectNum.newNum" :key="index">
2023-05-12 10:04:12 +08:00
<div class="numItem">{{ item }}</div>
</div>
</div>
<div class="title">
<div class="text">在建工程分类</div>
</div>
2023-05-13 18:44:53 +08:00
<div id="mainCenter"></div>
2023-05-12 10:04:12 +08:00
<div v-for="(item, index) in percentList" :key="index" class="allPercent">
<div :class="item.css">{{ item.number }}</div>
</div>
<div class="title">
<div class="text">扬尘今日预警</div>
</div>
<div class="pieBg">
<div class="imgbg">
<img src="@/assets/images/screenImg/blueCircleBig.gif" alt="" />
</div>
2023-05-13 18:44:53 +08:00
<div id="mainBottom"></div>
2023-05-12 10:04:12 +08:00
</div>
</div>
</template>
<script lang="ts" setup>
import { nextTick, ref, reactive, onMounted } from "vue";
import { getEngineeringAll, getProjectAll, getFugitiveDustAll } from "@/api/modules/largeSreen";
2023-05-12 10:04:12 +08:00
import * as echarts from "echarts";
import "echarts-gl";
import { result } from "lodash";
import { ResponseSame, ScreenResponse } from "@/api/types/common";
onMounted(() => {
projectNumber();
ProjectAll();
FugitiveDustAll();
});
2023-05-12 10:04:12 +08:00
//工程数
const projectNum = reactive({
num: "000000",
newNum: ["0", "0", "0", "0", "0", "0"]
});
const projectNumber = async () => {
const { result } = await getEngineeringAll();
const stringNum = String(result.total / 1000000);
const newNum = stringNum.split(".");
if (newNum[1].length < 6) {
const a = 6 - newNum[1].length;
for (let i = 0; i <= a; i++) {
projectNum.num = newNum[1] + "0";
}
} else {
projectNum.num = newNum[1];
}
projectNum.newNum = projectNum.num.split("");
};
2023-05-12 10:04:12 +08:00
//在建工程分类
const percentList = ref([
{ number: "0", css: "greenPercent", name: "市政公用" },
{ number: "0", css: "bluePercent", name: "房屋建筑" },
{ number: "0", css: "yellowPercent", name: "其他" }
2023-05-12 10:04:12 +08:00
]);
const ProjectAll = async () => {
const { result } = await getProjectAll();
result.forEach((item: { dict_value: string; ratio: string }, index: number) => {
percentList.value.forEach((item2, index: number) => {
if (item.dict_value == item2.name) {
item2.number = item.ratio + "%";
}
});
});
threeDOption(result);
};
const threeDOption = (val: any[] | ResponseSame<ScreenResponse.ProjectAllResponse> | undefined) => {
2023-05-12 10:04:12 +08:00
const chartDom = document.getElementById("mainCenter") as HTMLElement;
const myChart = echarts.init(chartDom);
2023-05-13 18:44:53 +08:00
window.addEventListener("resize", function () {
myChart.resize();
});
//当前视口宽度
let nowClientWidth = document.documentElement.clientWidth;
// 换算方法
function nowSize(val: number, initWidth = 1920) {
return val * (nowClientWidth / initWidth);
}
let allNumber = 0;
2023-05-12 10:04:12 +08:00
const data = [
{
name: "房屋建筑",
value: 0,
2023-05-12 10:04:12 +08:00
itemStyle: {
color: "#3c6fb6"
}
},
{
name: "市政公用",
value: 0,
2023-05-12 10:04:12 +08:00
itemStyle: {
color: "#53d5a3"
}
},
{
name: "其他",
value: 0,
2023-05-12 10:04:12 +08:00
itemStyle: {
color: "#f6bc05"
}
}
];
let temp = 0;
val.forEach((item2: { dict_value: string; num: number }, index: number) => {
temp += Number(item2.num);
data.forEach((item, index) => {
if (item.name == item2.dict_value) {
item.value = Number(item2.num);
}
});
});
allNumber = temp;
console.log(allNumber, data);
2023-05-12 10:04:12 +08:00
function array2obj(array: [], key: string) {
let resObj = {};
for (let i = 0; i < array.length; i++) {
resObj[array[i][key]] = array[i];
}
return resObj;
}
const objData = array2obj(data, "name");
// 生成扇形的曲面参数方程,用于 series-surface.parametricEquation
function getParametricEquation(
startRatio: number,
endRatio: number,
isSelected: boolean,
isHovered: boolean,
k: number,
h: number
) {
// 计算
let midRatio = (startRatio + endRatio) / 2;
let startRadian = startRatio * Math.PI * 2;
let endRadian = endRatio * Math.PI * 2;
let midRadian = midRatio * Math.PI * 2;
// 如果只有一个扇形,则不实现选中效果。
if (startRatio === 0 && endRatio === 1) {
isSelected = false;
}
// 通过扇形内径/外径的值,换算出辅助参数 k默认值 1/3
k = typeof k !== "undefined" ? k : 1 / 3;
// 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0
let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
// 计算高亮效果的放大比例(未高亮,则比例为 1
let hoverRate = isHovered ? 1.05 : 1;
// 返回曲面参数方程
return {
u: {
min: -Math.PI,
max: Math.PI * 3,
step: Math.PI / 32
},
v: {
min: 0,
max: Math.PI * 2,
step: Math.PI / 20
},
x: function (u: number, v: number) {
if (u < startRadian) {
return offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
}
if (u > endRadian) {
return offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
}
return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
},
y: function (u: number, v: number) {
if (u < startRadian) {
return offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
}
if (u > endRadian) {
return offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
}
return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
},
z: function (u: number, v: number) {
if (u < -Math.PI * 0.5) {
return Math.sin(u);
}
if (u > Math.PI * 2.5) {
return Math.sin(u) * h * 0.1;
}
return Math.sin(v) > 0 ? 1 * h * 0.1 : -1;
}
};
}
// 生成模拟 3D 饼图的配置项
function getPie3D(pieData: string | any[], internalDiameterRatio: number) {
let series = [];
let sumValue = 0;
let startValue = 0;
let endValue = 0;
let legendData = [];
let k = typeof internalDiameterRatio !== "undefined" ? (1 - internalDiameterRatio) / (1 + internalDiameterRatio) : 1 / 3;
// 为每一个饼图数据,生成一个 series-surface 配置
for (let i = 0; i < pieData.length; i++) {
sumValue += pieData[i].value;
let seriesItem = {
name: typeof pieData[i].name === "undefined" ? `series${i}` : `${pieData[i].name}`,
type: "surface",
parametric: true,
wireframe: {
show: false
},
pieData: pieData[i],
pieStatus: {
selected: false,
hovered: false,
k: k
}
};
if (typeof pieData[i].itemStyle != "undefined") {
let itemStyle = {};
typeof pieData[i].itemStyle.color != "undefined" ? (itemStyle.color = pieData[i].itemStyle.color) : null;
typeof pieData[i].itemStyle.opacity != "undefined" ? (itemStyle.opacity = pieData[i].itemStyle.opacity) : null;
seriesItem.itemStyle = itemStyle;
}
series.push(seriesItem);
}
// 使用上一次遍历时,计算出的数据和 sumValue调用 getParametricEquation 函数,
// 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation也就是实现每一个扇形。
for (let i = 0; i < series.length; i++) {
endValue = startValue + series[i].pieData.value;
series[i].pieData.startRatio = startValue / sumValue;
series[i].pieData.endRatio = endValue / sumValue;
series[i].parametricEquation = getParametricEquation(
series[i].pieData.startRatio,
series[i].pieData.endRatio,
false,
false,
k,
series[i].pieData.value
);
startValue = endValue;
legendData.push(series[i].name);
}
// 补充一个透明的圆环,用于支撑高亮功能的近似实现。
series.push({
// name: "mouseoutSeries",
type: "surface",
parametric: true,
wireframe: {
show: false
},
itemStyle: {
opacity: 0
},
parametricEquation: {
u: {
min: 0,
max: Math.PI * 2,
step: Math.PI / 20
},
v: {
min: 0,
max: Math.PI,
step: Math.PI / 20
},
x: function (u: number, v: number) {
return Math.sin(v) * Math.sin(u) + Math.sin(u);
},
y: function (u: number, v: number) {
return Math.sin(v) * Math.cos(u) + Math.cos(u);
},
z: function (u: any, v: number) {
return Math.cos(v) > 0 ? 0.1 : -0.1;
}
}
});
// 准备待返回的配置项,把准备好的 legendData、series 传入。
let option = {
//animation: false,
legend: {
// orient 设置布局方式,默认水平布局,可选值:'horizontal'(水平) | 'vertical'(垂直)
orient: "horizontal",
x: "center",
y: "left",
itemWidth: nowSize(18),
itemHeight: nowSize(18),
2023-05-12 10:04:12 +08:00
// itemGap设置各个item之间的间隔单位px默认为10横向布局时为水平间隔纵向布局时为纵向间隔
itemGap: nowSize(30),
2023-05-12 10:04:12 +08:00
formatter: function (name: string) {
return "{title|" + name + "}{value| " + `${objData[name].value}` + "}";
2023-05-12 10:04:12 +08:00
},
textStyle: {
rich: {
title: {
fontSize: nowSize(13),
lineHeight: nowSize(15),
2023-05-12 10:04:12 +08:00
color: "white",
fontFamily: "DigitalRegular"
},
value: {
fontSize: nowSize(19),
lineHeight: nowSize(20),
2023-05-12 10:04:12 +08:00
color: "white",
fontFamily: "YouSheBiaoTiHei"
}
}
}
},
tooltip: {
formatter: (params: { seriesName: string; color: any; seriesIndex: string | number }) => {
if (params.seriesName !== "mouseoutSeries") {
return `${
params.seriesName
}<br/><span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${
params.color
};"></span>${((option.series[params.seriesIndex].pieData.value / allNumber) * 100).toFixed(1)}%`;
2023-05-12 10:04:12 +08:00
}
}
},
xAxis3D: {
min: -1,
max: 1
},
yAxis3D: {
min: -1,
max: 1
},
zAxis3D: {
min: -1,
max: 1
},
grid3D: {
show: false,
boxHeight: 10,
viewControl: {
//3d效果可以放大、旋转等请自己去查看官方配置
alpha: 40,
// beta: 40,
rotateSensitivity: 0,
zoomSensitivity: 0,
panSensitivity: 0,
autoRotate: false
},
//后处理特效可以为画面添加高光、景深、环境光遮蔽SSAO、调色等效果。可以让整个画面更富有质感。
postEffect: {
//配置这项会出现锯齿,请自己去查看官方配置有办法解决
enable: true,
bloom: {
enable: true,
bloomIntensity: 0.1
},
SSAO: {
enable: true,
quality: "medium",
radius: 2
}
}
},
series: series
};
return option;
}
// 传入数据生成 option
let option = getPie3D(data, 0.65);
option && myChart.setOption(option);
};
//扬尘今日预警
const FugitiveDustAll = async () => {
const { result } = await getFugitiveDustAll();
pieOption(result);
};
const pieOption = (val: ResponseSame<ScreenResponse.FugitiveDustAllResponse> | undefined) => {
2023-05-12 10:04:12 +08:00
const chartDomPie = document.getElementById("mainBottom") as HTMLElement;
const myChartPie = echarts.init(chartDomPie);
2023-05-13 18:44:53 +08:00
window.addEventListener("resize", function () {
myChartPie.resize();
});
//当前视口宽度
let nowClientWidth = document.documentElement.clientWidth;
//换算方法
function nowSize(val: number, initWidth = 1920) {
return val * (nowClientWidth / initWidth);
}
2023-05-12 10:04:12 +08:00
let scale = 1;
let echartData = [
{
value: 0,
2023-05-12 10:04:12 +08:00
name: "PM10",
itemStyle: {
normal: {
//颜色渐变
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "#1d2f31" },
{ offset: 1, color: "#30ab7b" }
])
}
},
labelLine: {
lineStyle: {
color: "#2fa678"
}
},
label: {
normal: {
rich: {
b: {
height: 5,
width: 5,
lineHeight: 15,
marginBottom: 10,
padding: [0, -2.5],
borderRadius: 5,
backgroundColor: "#2fa678" // 圆点颜色
}
}
}
}
},
{
value: 0,
name: "噪音",
2023-05-12 10:04:12 +08:00
itemStyle: {
normal: {
//颜色渐变
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "#2c2e29" },
{ offset: 1, color: "#f9bd02" }
])
}
},
labelLine: {
lineStyle: {
color: "#e2ad06"
}
},
label: {
normal: {
rich: {
b: {
height: 5,
width: 5,
lineHeight: 15,
marginBottom: 10,
padding: [0, -2.5],
borderRadius: 5,
backgroundColor: "#e2ad06" // 圆点颜色
}
}
}
}
},
{
value: 0,
name: "TSP",
2023-05-12 10:04:12 +08:00
itemStyle: {
normal: {
//颜色渐变
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "#f04b17" },
{ offset: 1, color: "#2b242b" }
])
}
},
labelLine: {
lineStyle: {
color: "#e94a18"
}
},
label: {
normal: {
rich: {
b: {
height: 5,
width: 5,
lineHeight: 15,
marginBottom: 10,
padding: [0, -2.5],
borderRadius: 5,
backgroundColor: "#e94a18" // 圆点颜色
}
}
}
}
},
{
value: 0,
2023-05-12 10:04:12 +08:00
name: "PM2.5",
itemStyle: {
normal: {
//颜色渐变
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "#5488d8" },
{ offset: 1, color: "#222c3a" }
])
}
},
labelLine: {
lineStyle: {
color: "#5183cf"
}
},
label: {
normal: {
rich: {
b: {
height: 5,
width: 5,
lineHeight: 15,
marginBottom: 10,
padding: [0, -2.5],
borderRadius: 5,
backgroundColor: "#5183cf" // 圆点颜色
}
}
}
}
}
];
let total_datas = 0;
let temp = 0;
val.forEach((item2: { total: any; type: string; num: any }, index: number) => {
temp += Number(item2.num);
echartData.forEach((item, index) => {
if (item.name == item2.type) {
item.value = Number(item2.num);
}
});
});
total_datas = temp;
console.log(total_datas, echartData);
2023-05-12 10:04:12 +08:00
let rich = {
top: {
color: "white",
fontSize: nowSize(13),
left: nowSize(20),
padding: [nowSize(-20), nowSize(-50), nowSize(-20), nowSize(-50)],
2023-05-12 10:04:12 +08:00
fontFamily: "SourceHanSansCNH"
},
total: {
color: "#ffc72b",
fontSize: nowSize(40) * scale,
2023-05-12 10:04:12 +08:00
align: "center"
},
bottom: {
color: "white",
fontSize: nowSize(14),
height: nowSize(5),
width: nowSize(5),
lineHeight: nowSize(5),
marginBottom: nowSize(10),
padding: [nowSize(0), nowSize(-80), nowSize(-15), nowSize(-75)],
borderRadius: nowSize(5),
2023-05-12 10:04:12 +08:00
fontFamily: "OPPOSansB"
},
hr: {
borderColor: "#0b5263",
width: "100%",
borderWidth: nowSize(1),
height: nowSize(0)
2023-05-12 10:04:12 +08:00
}
},
optionPie = {
title: {
text: total_datas,
subtext: "今日报警次数",
itemGap: 5,
top: "top",
padding: [nowSize(108), nowSize(100)],
2023-05-12 10:04:12 +08:00
textStyle: {
color: "#f2f2f2",
fontSize: nowSize(48),
2023-05-12 10:04:12 +08:00
fontFamily: "DigitalRegular"
},
subtextStyle: {
fontSize: nowSize(14),
2023-05-12 10:04:12 +08:00
color: ["#f2f2f2"],
fontFamily: "SourceHanSansCNR"
},
x: "center",
y: "center"
},
series: [
{
name: "违纪总次数",
type: "pie",
radius: ["38%", "50%"],
hoverAnimation: false,
label: {
normal: {
formatter: function (params: { value: number; name: string }) {
let total = 0; //考生总数量
echartData.forEach(function (value) {
total += value.value;
});
let percent = ((params.value / total) * 100).toFixed(0);
if (percent == "NaN") {
return "{top|" + params.name + "}\n{b| }\n{bottom|" + params.value + "次 / " + 0 + "%}";
} else {
return "{top|" + params.name + "}\n{b| }\n{bottom|" + params.value + "次 / " + percent + "%}";
}
2023-05-12 10:04:12 +08:00
},
rich: rich
}
},
labelLine: {
normal: {
length: nowSize(20),
length2: nowSize(100),
2023-05-12 10:04:12 +08:00
align: "right",
lineStyle: {
width: nowSize(1)
2023-05-12 10:04:12 +08:00
},
emphasis: {
show: true
}
}
},
data: echartData
}
]
};
optionPie && myChartPie.setOption(optionPie);
};
// nextTick(() => {
// });
2023-05-12 10:04:12 +08:00
</script>
<style lang="scss" scoped>
.leftBorder {
position: fixed;
top: 15%;
right: 0;
width: 27%;
height: 100%;
background: url("@/assets/images/screenImg/rightBorder.png") no-repeat right center;
2023-05-13 18:44:53 +08:00
background-size: 100% 100%;
2023-05-12 10:04:12 +08:00
.title {
width: 100%;
height: 50px;
font-family: YouSheBiaoTiHei;
color: white;
background: url("@/assets/images/screenImg/littleTitle.png") no-repeat left center;
background-size: 75%;
.text {
padding: 0 0 0 50px;
font-size: 18px;
}
}
.projectNum {
display: flex;
width: 90%;
height: 100px;
margin-left: 22px;
.numItem {
width: 56px;
height: 62px;
margin-right: 10px;
font-family: DigitalRegular;
font-size: 48px;
line-height: 62px;
color: white;
text-align: center;
background: url("@/assets/images/screenImg/frame.png") no-repeat;
background-size: 100%;
}
}
}
/* stylelint-disable-next-line selector-id-pattern */
#mainCenter {
width: 100%;
height: 290px;
}
.pieBg {
position: relative;
width: 90%;
height: 250px;
.imgbg {
width: 245px;
height: 245px;
margin: 0 auto;
background: url("@/assets/images/screenImg/blueCircleBigbg.png") no-repeat center center;
background-size: 100%;
img {
position: absolute;
top: 14.5%;
left: 31.5%;
width: 174px;
height: 174px;
}
}
/* stylelint-disable-next-line selector-id-pattern */
#mainBottom {
position: absolute;
top: -8.5%;
left: 0;
width: 100%;
height: 290px;
}
}
.allPercent {
// position: relative;
.greenPercent {
position: absolute;
top: 350px;
left: 70px;
2023-05-12 10:04:12 +08:00
width: 76px;
height: 30px;
font-family: OPPOSansH;
2023-05-13 18:44:53 +08:00
font-size: 17px;
2023-05-12 10:04:12 +08:00
color: rgb(48 172 124);
text-align: center;
border-bottom: 5px solid #dddddd;
border-image: linear-gradient(to right, rgb(48 172 124 / 0%), rgb(48 172 124 / 100%)) 30 30;
}
.bluePercent {
position: absolute;
top: 265px;
left: 350px;
2023-05-12 10:04:12 +08:00
width: 76px;
height: 30px;
font-family: OPPOSansH;
2023-05-13 18:44:53 +08:00
font-size: 17px;
2023-05-12 10:04:12 +08:00
color: rgb(49 123 196);
text-align: center;
border-bottom: 5px solid #dddddd;
border-image: linear-gradient(to right, rgb(49 123 196 / 20%), rgb(49 123 196 / 80%)) 30 30;
}
.yellowPercent {
position: absolute;
top: 430px;
left: 320px;
2023-05-12 10:04:12 +08:00
width: 76px;
height: 30px;
font-family: OPPOSansH;
2023-05-13 18:44:53 +08:00
font-size: 17px;
2023-05-12 10:04:12 +08:00
color: rgb(252 191 2);
text-align: center;
border-bottom: 5px solid #dddddd;
border-image: linear-gradient(to right, rgb(252 191 2 / 0%), rgb(252 191 2 / 100%)) 30 30;
}
}
</style>