This commit is contained in:
lnljyang
2026-01-06 10:06:01 +08:00
parent 907e68c68f
commit c2e7fc1f20
138 changed files with 118829 additions and 0 deletions

170
src/views/dishboard.vue Normal file
View File

@@ -0,0 +1,170 @@
<template>
<div class="dashboard">
<!-- 顶部标题 -->
<header class="header">
<h1>碳林</h1>
<span>{{ currentTime }}</span>
</header>
<!-- 主体区域 -->
<div class="main">
<!-- 左侧信息 -->
<div class="panel left-panel">
<div class="card" v-for="(item, index) in leftData" :key="index">
<p>{{ item.title }}</p>
<h2>{{ item.value }}</h2>
</div>
<div class="chart-box">
<v-chart class="chart" :option="carbonFootprintOption" />
</div>
</div>
<!-- 中心地图 -->
<div class="map-container">
<v-chart class="map-chart" :option="mapOption" />
<h2>今日碳减排总量: 8318 kg</h2>
</div>
<!-- 右侧图表 -->
<div class="panel right-panel">
<v-chart class="chart" :option="monthlySpecialLabelOption" />
<v-chart class="chart" :option="monthlyBoxCountOption" />
<v-chart class="chart" :option="boxWeightDistributionOption" />
</div>
</div>
<!-- 底部数据表 -->
<div class="footer">
<el-table :data="tradeData" border>
<el-table-column prop="exchange" label="交易所" />
<el-table-column prop="project" label="项目" />
<el-table-column prop="price" label="价格 (RMB)" />
<el-table-column prop="region" label="地区" />
</el-table>
</div>
</div>
</template>
<script>
import * as echarts from "echarts";
import "echarts/map/js/china";
import VChart from "vue-echarts";
export default {
components: { VChart },
data() {
return {
currentTime: new Date().toLocaleString(),
leftData: [
{ title: "在线车数", value: "340 / 569" },
{ title: "当日减碳", value: "334kg" },
{ title: "当日用氢量", value: "334kg" },
{ title: "当日里程", value: "3300km" },
],
tradeData: [
{ exchange: "北京碳交易所", project: "CCER", price: 100, region: "中国·北京" },
{ exchange: "上海环境能源交易所", project: "CCER", price: 98, region: "中国·上海" },
{ exchange: "深圳排放权交易所", project: "CCER", price: 97, region: "中国·深圳" },
{ exchange: "广东碳排放交易所", project: "CCER", price: 96, region: "中国·广东" },
{ exchange: "湖北碳排放交易所", project: "CCER", price: 95, region: "中国·湖北" },
],
// 碳足迹折线图
carbonFootprintOption: {
tooltip: { trigger: "axis" },
legend: { data: ["碳减排量", "行驶里程"] },
xAxis: { type: "category", data: ["1月", "2月", "3月", "4月", "5月", "6月"] },
yAxis: [{ type: "value" }, { type: "value" }],
series: [
{ name: "碳减排量", type: "bar", data: [10000, 20000, 15000, 30000, 25000, 35000] },
{ name: "行驶里程", type: "line", yAxisIndex: 1, data: [10, 20, 18, 25, 22, 28] },
],
},
// 中国地图
mapOption: {
tooltip: { trigger: "item" },
visualMap: { min: 0, max: 100, text: ["高", "低"], calculable: true },
series: [
{
type: "map",
map: "china",
data: [
{ name: "北京", value: 80 },
{ name: "上海", value: 50 },
{ name: "广东", value: 90 },
],
},
],
},
// 特殊标箱情况
monthlySpecialLabelOption: {
tooltip: { trigger: "axis" },
legend: { data: ["空箱", "危险品"] },
xAxis: { type: "category", data: ["1月", "2月", "3月", "4月", "5月"] },
yAxis: { type: "value" },
series: [
{ name: "空箱", type: "line", data: [10, 20, 30, 40, 50] },
{ name: "危险品", type: "line", data: [200, 250, 300, 350, 400] },
],
},
// 月度标箱数
monthlyBoxCountOption: {
tooltip: { trigger: "axis" },
xAxis: { type: "category", data: ["1月", "2月", "3月", "4月", "5月"] },
yAxis: { type: "value" },
series: [{ type: "bar", data: [30000, 40000, 35000, 45000, 38000] }],
},
// 标箱重量分布
boxWeightDistributionOption: {
tooltip: { trigger: "item" },
series: [
{
type: "pie",
radius: ["40%", "70%"],
data: [
{ value: 1234, name: "1~5T" },
{ value: 1234, name: "5~10T" },
{ value: 1234, name: "10~15T" },
],
},
],
},
};
},
mounted() {
this.updateTime();
},
methods: {
updateTime() {
setInterval(() => {
this.currentTime = new Date().toLocaleString();
}, 1000);
},
},
};
</script>
<style scoped>
.dashboard {
background: #0a1931;
color: white;
padding: 20px;
}
.header {
display: flex;
justify-content: space-between;
font-size: 24px;
}
.main {
display: flex;
justify-content: space-between;
margin-top: 20px;
}
.map-container {
width: 50%;
text-align: center;
}
.chart {
height: 200px;
}
</style>

332
src/views/home.scss Normal file
View File

@@ -0,0 +1,332 @@
.scale-wrap {
color: #d3d6dd;
width: 1920px;
height: 1080px;
overflow: hidden;
// &.pageisScale {
// position: absolute;
// top: 50%;
// left: 50%;
// transform: translate(-50%, -50%);
// transform-origin: left top;
// }
.bg {
width: 100%;
height: 100%;
padding: 16px 16px 10px 16px;
box-sizing: border-box;
background-image: url("../assets/img/u0.svg");
background-size: cover;
background-position: center center;
}
.host-body {
height: 100%;
.title_wrap {
height: 60px;
background-image: url("../assets/img/top.png");
background-size: cover;
background-position: center center;
position: relative;
margin-bottom: 4px;
// .guang {
// position: absolute;
// bottom: -26px;
// background-image: url("../assets/img/guang.png");
// background-position: 80px center;
// width: 100%;
// height: 56px;
// .imgs {
// width: 320px;
// height: 35px;
// margin-top: -1%;
// }
// }
.guang {
display: flex; /* 启用flex布局 */
align-items: center; /* 垂直居中 */
position: absolute;
background-image: url("../assets/img/guang.png");
bottom: 0px;
margin-left: 70px;
background: transparent;
background-position: 80px center;
width: 100%;
height: 56px;
border-radius: 0 0 8px 8px;
.imgs {
width: 40px;
height: 34px;
margin-left: 20px;
margin-right: -10px;
margin-top: 0px;
}
}
.zuojuxing,
.youjuxing {
position: absolute;
top: -2px;
width: 140px;
height: 6px;
background-image: url("../assets/img/headers/juxing1.png");
}
.zuojuxing {
left: 11%;
}
.youjuxing {
right: 11%;
transform: rotate(180deg);
}
.timers {
position: absolute;
right: 0;
top: 30px;
font-size: 18px;
display: flex;
align-items: center;
.blq-icon-shezhi02 {
cursor: pointer;
}
}
}
// 羚牛科技技术支持标识样式 - 简洁版本
.tech-support-badge {
position: absolute;
right: 0;
top: 15px;
padding: 4px 12px;
transition: all 0.3s ease;
opacity: 0.85;
&:hover {
opacity: 1;
transform: translateY(-1px);
}
.tech-text {
font-size: 14px;
color: #8c8c8c;
font-weight: 500;
letter-spacing: 0.8px;
white-space: nowrap;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
position: relative;
// 添加一个简洁的下划线装饰
&::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
width: 100%;
height: 1px;
background: linear-gradient(90deg, #8c8c8c 0%, transparent 100%);
opacity: 0.4;
transition: opacity 0.3s ease;
}
}
&:hover .tech-text::after {
opacity: 1;
}
}
.title {
position: relative;
// width: 500px;
text-align: center;
background-size: cover;
color: transparent;
height: 60px;
line-height: 46px;
.title-text {
font-size: 38px;
font-weight: 900;
letter-spacing: 6px;
width: 100%;
background: linear-gradient(92deg, #0072FF 0%, #00EAFF 48.8525390625%, #01AAFF 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
}
}
}
.scale-wrap {
.pagetab {
position: absolute;
top: -35px;
display: flex;
.item {
width: 130px;
height: 36px;
border-radius: 18px 0px 0px 18px;
color: #00FBF8;
text-indent: 26px;
line-height: 36px;
font-size: 16px;
margin-right: 20px;
background: linear-gradient(to right, rgba(76, 245, 255, .5), rgba(76, 245, 255, 0));
}
}
}
.setting {
position: fixed;
width: 100%;
height: 100%;
z-index: 999;
top: 0;
left: 0;
.left_shu {
color: #000;
font-weight: 900;
position: relative;
text-indent: 10px;
padding:16px 0 10px 0 ;
&::before {
display: block;
content: " ";
height: 16px;
width: 4px;
border-radius: 2px;
background: #0072FF;
position: absolute;
left: 0px;
}
}
.setting_dislog {
background-color: rgba($color: #000000, $alpha: .5);
position: absolute;
width: 100%;
height: 100%;
z-index: 0;
right: 0;
top: 0;
}
.setting_inner {
box-sizing: border-box;
background: #FFF;
width: 340px;
height: 100%;
position: absolute;
right: 0px;
top: 0;
z-index: 1;
color: #000000;
box-shadow: 0 8px 10px -5px rgba(0, 0, 0, .2), 0 16px 24px 2px rgba(0, 0, 0, .14), 0 6px 30px 5px rgba(0, 0, 0, .12);
.setting_header {
font-size: 20px;
color: rgb(0, 0, 0);
font-weight: 900;
text-align: center;
line-height: 40px;
}
.setting_body {
padding: 0px 16px;
box-sizing: border-box;
position: relative;
}
.setting_item {
font-size: 14px;
line-height: 1.5;
// display: flex;
.setting_label {
color: #555454;
}
.setting_label_tip{
font-size: 12px;
color: #838282;
}
}
}
.setting_inner {
animation: rtl-drawer-out .3s;
}
}
.settingShow {
.setting_inner {
animation: rtl-drawer-in .3s 1ms;
}
}
.yh-setting-fade-enter-active {
animation: yh-setting-fade-in .3s;
}
.yh-setting-fade-leave-active {
animation: yh-setting-fade-out .3s;
}
@keyframes yh-setting-fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes yh-setting-fade-out {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes rtl-drawer-in {
0% {
transform: translate(100%, 0)
}
100% {
-webkit-transform: translate(0, 0);
transform: translate(0, 0)
}
}
@keyframes rtl-drawer-out {
0% {
transform: translate(0, 0)
}
100% {
transform: translate(100%, 0)
}
}

128
src/views/home.vue Normal file
View File

@@ -0,0 +1,128 @@
<!--
* @Author: szy
* @Date: 2022-01-12 14:23:32
* @LastEditors: Please set LastEditors
* @LastEditTime: 2022-09-09 14:47:24
* @FilePath: \web-pc\src\pages\big-screen\view\home.vue
-->
<template>
<!-- <div id="index" ref="appRef" class="index_home" :class="{ pageisScale: isScale }"> -->
<ScaleScreen
:width="1920"
:height="1080"
class="scale-wrap"
:selfAdaption="$store.state.setting.isScale"
>
<div class="bg">
<dv-loading v-if="loading">Loading...</dv-loading>
<div v-else class="host-body">
<!-- 头部 s -->
<div class="d-flex jc-center title_wrap">
<div class="zuojuxing"></div>
<div class="youjuxing"></div>
<div class="guang">
<img src="@/assets/img/titles/gzjt_logo.png" alt="" class="imgs"/>
<p class="title-name">广州开发区交投氢能</p>
<!-- <img src="@/assets/img/logo.png" alt="" class="imgs"/> -->
</div>
<div class="d-flex jc-center">
<div class="title">
<!--箱箱碳林可视化平台-->
<!--嘉兴海港碳服务平台-->
<!--2025.4.1 szy -->
<span class="title-text">氢能碳数据看板</span>
</div>
</div>
<div class="timers">
{{ dateYear }} {{ dateWeek }} {{ dateDay }}
<!-- <button class="selectTime">选择日期</button> -->
<i
class="blq-icon-shezhi02"
style="margin-left: 10px"
@click="showSetting"
></i>
</div>
</div>
<!-- 羚牛科技技术支持标识 -->
<!-- <div class="tech-support-badge">
<span class="tech-text">© 2025 羚牛科技提供技术支持</span>
</div> -->
<!-- 头部 e-->
<!-- 内容 s-->
<router-view></router-view>
<!-- 内容 e -->
</div>
</div>
<Setting ref="setting" />
</ScaleScreen>
<!-- </div> -->
</template>
<script>
import { formatTime } from "../utils/index.js";
import Setting from "./setting.vue";
import ScaleScreen from "@/components/scale-screen/scale-screen.vue";
export default {
components: { Setting, ScaleScreen },
data() {
return {
timing: null,
loading: true,
dateDay: null,
dateYear: null,
dateWeek: null,
weekday: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
};
},
filters: {
numsFilter(msg) {
return msg || 0;
},
},
computed: {},
created() {},
mounted() {
this.timeFn();
this.cancelLoading();
},
beforeDestroy() {
clearInterval(this.timing);
},
methods: {
showSetting() {
this.$refs.setting.init();
},
timeFn() {
this.timing = setInterval(() => {
this.dateDay = formatTime(new Date(), "HH: mm: ss");
this.dateYear = formatTime(new Date(), "yyyy-MM-dd");
this.dateWeek = this.weekday[new Date().getDay()];
}, 1000);
},
cancelLoading() {
let timer = setTimeout(() => {
this.loading = false;
clearTimeout(timer);
}, 500);
},
},
};
</script>
<style lang="scss">
@import "./home.scss";
.selectTime {
color: #31abe3;
background: transparent;
border: none;
}
.title-name{
color: white;
font-size: 30px;
font-weight: 600;
margin-left: 20px;
font-family: "Microsoft YaHei", "微软雅黑", "SimHei", "PingFang SC", "Hiragino Sans GB", sans-serif;
}
</style>

View File

@@ -0,0 +1,155 @@
<!-- MapFlyLine.vue -->
<template>
<div class="flyline-container" ref="container">
<canvas ref="canvas" class="flyline-canvas"></canvas>
</div>
</template>
<script>
export default {
name: 'MapFlyLine',
props: {
// 地图实例(需要从父组件传递)
mapData: {
type: Object,
required: true
},
// 飞线数据
data: {
type: Array,
default: () => []
},
// 配置项
config: {
type: Object,
default: () => ({})
}
},
data() {
return {
ctx: null,
animationFrame: null,
defaultConfig: {
color: '#4f99d3',
lineWidth: 1,
animationSpeed: 0.02,
maxLength: 0.3,
curvature: 0.3
}
}
},
computed: {
mergedConfig() {
return { ...this.defaultConfig, ...this.config }
}
},
mounted() {
this.initCanvas()
this.startAnimation()
window.addEventListener('resize', this.handleResize)
},
beforeDestroy() {
window.removeEventListener('resize', this.handleResize)
cancelAnimationFrame(this.animationFrame)
},
watch: {
data: {
deep: true,
handler() {
this.drawLines()
}
}
},
methods: {
initCanvas() {
const canvas = this.$refs.canvas
const container = this.$refs.container
canvas.width = container.offsetWidth
canvas.height = container.offsetHeight
this.ctx = canvas.getContext('2d')
this.ctx.globalCompositeOperation = 'lighter'
},
handleResize() {
this.initCanvas()
this.drawLines()
},
startAnimation() {
const animate = () => {
this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height)
this.drawLines()
this.animationFrame = requestAnimationFrame(animate)
}
animate()
},
drawLines() {
if (!this.data.length) return
this.data.forEach(line => {
const from = this.mapInstance.convertToPixel(...line.from)
const to = this.mapInstance.convertToPixel(...line.to)
this.drawCurve(
from,
from,
to,
to,
line.color || this.mergedConfig.color
)
})
},
drawCurve(x1, y1, x2, y2, color) {
const ctx = this.ctx
const cp = this.calculateControlPoint(x1, y1, x2, y2)
// 飞线渐变效果
const gradient = ctx.createLinearGradient(x1, y1, x2, y2)
gradient.addColorStop(0, color)
gradient.addColorStop(1, color + '00')
ctx.beginPath()
ctx.moveTo(x1, y1)
ctx.quadraticCurveTo(cp.x, cp.y, x2, y2)
// 创建虚线动画效果
ctx.setLineDash([5, 3])
ctx.lineDashOffset = -performance.now() * this.mergedConfig.animationSpeed
ctx.strokeStyle = gradient
ctx.lineWidth = this.mergedConfig.lineWidth
ctx.stroke()
},
calculateControlPoint(x1, y1, x2, y2) {
// 计算曲线控制点(贝塞尔曲线)
const curvature = this.mergedConfig.curvature
const dx = x2 - x1
const dy = y2 - y1
return {
x: (x1 + x2) / 2 + dy * curvature,
y: (y1 + y2) / 2 - dx * curvature
}
}
}
}
</script>
<style scoped>
.flyline-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
.flyline-canvas {
width: 100%;
height: 100%;
}
</style>

View File

@@ -0,0 +1,130 @@
<template>
<div>
<div ref="chart" class="chart-container"></div>
</div>
</template>
<script>
import echarts from "echarts";
import { currentGET } from "api/modules";
export default {
data() {
return {
showPercentage: true, // 默认显示数量
chartData:[
[
{ modelName: '冷藏', total: 190 },
{ modelName: '普货', total: 40 }
// { name: '海格20%', value: 160 },
// { name: '宇通20%', value: 260 },
// { name: '其它10%', value: 260 }
]
],
colors: ["#00E5FF", "#FF5733"]
//colors: ["#00E5FF", "#FF5733", "#FFBF00", "#5CDB95"]
};
},
mounted() {
this.getData();
},
methods: {
getData() {
currentGET("big5").then((res) => {
if(res.code == 0){ // 确保接口返回的code正确
// 转换数据结构为饼图需要的格式
this.chartData = [res.data.map(item => ({
name: item.modelName,
value: item.total
}))];
this.initChart();
}
});
},
initChart() {
const myChart = echarts.init(this.$refs.chart); // 修复变量名不一致问题
let option = {
title: {
text: '',
left: 'center',
textStyle: {
color: '#DDDDDD', // 将原来的 #999 改为更亮的灰色
fontWeight: 'normal',
fontSize: 14
}
},
series: this.chartData.map(function (data, idx) {
var top = idx * 33.3;
return {
type: 'pie',
radius: [50, 90],
top: top + '%',
height: '33.33%',
left: 'center',
width: '600px',
itemStyle: {
borderColor: 'orange',
borderWidth: 1
},
label: {
alignTo: 'edge',
formatter: ({ name, value, percent }) =>
`{name|${name}}\n{value|${value}辆} {percent|${percent}%}`,
minMargin: 5,
edgeDistance: 10,
lineHeight: 20,
rich: {
name: { // 新增 name 样式
fontSize: 14,
color: 'yellow', // 使用亮白色
padding: [0, 0, 5, 0]
},
value: {
fontSize: 12,
color: 'orange',
padding: [0, 5, 0, 0]
},
percent: {
fontSize: 12,
color: '#FF5733' // 保留原有橙色
}
}
},
labelLine: {
length: 40,
length2: 15,
maxSurfaceAngle: 80
},
labelLayout: function (params) {
const isLeft = params.labelRect.x < myChart.getWidth() / 2;
const points = params.labelLinePoints;
// Update the end point.
points[2][0] = isLeft
? params.labelRect.x
: params.labelRect.x + params.labelRect.width;
return {
labelLinePoints: points
};
},
data: data
};
})
};
option && myChart.setOption(option);
this.chart = myChart;
},
toggleMode() {
this.showPercentage = !this.showPercentage;
this.initChart(); // 重新渲染图表
}
}
}
</script>
<style scoped>
.chart-container {
width: 100%;
height: 800px;
}
</style>

View File

@@ -0,0 +1,893 @@
<!--
* @Author: szy
* @Date: 2022-03-01 11:17:39
* @LastEditors: Please set LastEditors
* @LastEditTime: 2022-09-29 15:50:18
* @FilePath: \web-pc\src\pages\big-screen\view\indexs\center-map.vue
-->
<template>
<div class="centermap">
<div class="maptitle">
<div class="zuo"></div>
<span class="titletextBefore">今年碳减排总量<span class="titletext">{{ totalCarbon/1000 }}</span></span>
<div class="you"></div>
</div>
<div class="mileagetitle">
<div class="zuo"></div>
<span class="titletextBefore">总里程数<span class="titletext">{{ totalMileage }}</span>万km</span>
<div class="you"></div>
</div>
<div class="mapwrap">
<dv-border-box-13>
<div class="quanguo" @click="getData('china')" v-if="code !== 'china'">
中国
</div>
<div class="quanguo1" @click="goToPage()" v-if="showType === 1">
车辆实况
</div>
<div class="quanguo2" @click="changeShow1()" :style="{ backgroundColor: currentBgColor2 }">
<div >车辆信息</div>
</div>
<div class="quanguo3" @click="changeShow2()" :style="{ backgroundColor: currentBgColor3 }">
<div >加氢站</div>
</div>
<div class="quanguo4" v-if="code === 'china'">
<div >全国车辆范围</div>
</div>
<Echart id="CenterMap" :options="options" ref="CenterMap" />
<!-- <dv-flyline-chart :config="config" style="width:100%;height:100%;" /> -->
</dv-border-box-13>
</div>
</div>
</template>
<script>
import xzqCode from "../../utils/map/xzqCode";
import { currentGET } from "api/modules";
import * as echarts from "echarts";
import { GETNOBASE } from "api";
export default {
data() {
return {
totalCarbon: "0",
totalMileage: "0",
options: {},
code: "china", //china 代表中国 其他地市是行政编码
//code:"440000",
echartBindClick: false,
isSouthChinaSea: false, //是否要展示南海群岛 修改此值请刷新页面
currentMap : 'china', // 当前显示的地图层级
showType: 1, //显示内容类型: 1车辆信息2加氢站信息
currentBgColor2:'',
currentBgColor3:'',
};
},
created() {},
mounted() {
console.log(this.xzqCode);
this.getYearData();
this.showType = 1;
this.currentBgColor2 = '#158e8e';
//this.getData("china");
this.getData(this.code);
},
methods: {
changeShow1(){
this.showType = 1;
this.currentBgColor2 = '#158e8e';
this.currentBgColor3 = '';
this.getData(this.code);
},
changeShow2(){
this.currentBgColor2 = '';
this.currentBgColor3 = '#158e8e';
this.showType = 2;
this.getData(this.code);
},
goToPage() {
//window.open("http://localhost:9528/vehicle-management/vehicle-state?"+this.code, "_blank");
//window.open("http://47.100.49.118:8090/vehicle-situation?"+this.code, "_blank");
window.open("http://127.0.0.1:9528/vehicle-situation?"+this.code, "_blank");
//window.open("http://192.168.0.219:9528/vehicle-situation?"+this.code, "_blank");
},
parseAdcodeLevel(adcode) {
const codeStr = String(adcode);
if (codeStr.endsWith('0000')) return 'province'; // 省级(如 440000
if (codeStr.endsWith('00')) return 'city'; // 市级(如 440300
return 'district'; // 区县级(如 440305
},
getYearData() {
currentGET("big3").then((res) => {
console.log('年度碳排量');
console.log(res);
this.totalCarbon = res.data.yearCarbon || "0";
this.totalMileage = res.data.yearMileage || "0";
});
},
getData(code) {
console.log("code", code);
this.currentMap = this.parseAdcodeLevel(code);
//2025.9.10 szy 增加showType 分类处理1时处理车辆信息2时处理加氢站信息
if(this.showType === 1){
currentGET("big9", { regionCode: code, adcodeLevel: this.currentMap }).then((res) => {
console.log("map车辆分布", res);
//if (res.success)
if (res.status) {
this.getGeojson(res.data.regionCode, res.data.dataList);
this.mapclick();
} else {
this.$Message.warning(res.msg);
}
});
}else if(this.showType === 2){
//改为显示全国所有加氢站信息 停止使用big14 使用big15 2025.10.16 szy
currentGET("big15", { regionCode: code, adcodeLevel: this.currentMap }).then((res) => {
console.log("加氢站_map分布", res);
//if (res.success)
if (res.status) {
this.getGeojson2(res.data.regionCode, res.data.dataList);
this.mapclick();
} else {
this.$Message.warning(res.msg);
}
});
}
},
/**
* @description: 获取geojson
* @param {*} name china 表示中国 其他省份行政区编码
* @param {*} mydata 接口返回列表数据
* @return {*}
*/
async getGeojson(name, mydata) {
this.code = name;
this.currentMap = name;
console.log('当前地图层级');
console.log(this.currentMap);
//如果要展示南海群岛并且展示的是中国的话
let geoname=name
if (this.isSouthChinaSea && name == "china") {
geoname = "chinaNanhai";
}
//如果有注册地图的话就不用再注册 了
let mapjson = echarts.getMap(name);
console.log('已经是否已存在的地图数据');
if (mapjson) {
mapjson = mapjson.geoJson;
}
else
{
//console.log('当前未注册地图');
mapjson = await GETNOBASE(`./map-geojson/${geoname}.json`).then((res) => {
return res;
});
echarts.registerMap(name, mapjson);
}
console.log(mapjson);
let cityCenter = {};
let arr = mapjson.features;
//根据geojson获取省份中心点
arr.map((item) => {
cityCenter[item.properties.name] =
item.properties.centroid || item.properties.center;
});
let newData = [];
mydata.map((item) => {
if (cityCenter[item.name]) {
if(item.vehicleTotal===undefined || item.vehicleTotal===null ){
item.vehicleTotal = 0;
}
if(item.onLineCount===undefined || item.onLineCount===null){
item.onLineCount = 0;
}
if(item.dayMileage===undefined || item.dayMileage===null){
item.dayMileage = 0;
}
if(item.dayHydrogen===undefined || item.dayHydrogen===null){
item.dayHydrogen = 0;
}
if(item.dayCarbon===undefined || item.dayCarbon===null){
item.dayCarbon = 0;
}
newData.push({
name: item.name,
value: cityCenter[item.name].concat(item.vehicleTotal).concat(item.onLineCount).concat(item.dayMileage).concat(item.dayHydrogen).concat(item.dayCarbon),
});
}
});
console.log('开始初始化地图');
console.log(newData);
this.init(name, mydata, newData);
},
async getGeojson2(name, mydata) {
this.code = name;
this.currentMap = name;
console.log('加氢站_当前地图层级');
console.log(this.currentMap);
//如果要展示南海群岛并且展示的是中国的话
let geoname=name
if (this.isSouthChinaSea && name == "china") {
geoname = "chinaNanhai";
}
//如果有注册地图的话就不用再注册 了
let mapjson = echarts.getMap(name);
console.log('加氢站_已经是否已存在的地图数据');
if (mapjson) {
mapjson = mapjson.geoJson;
}
else
{
//console.log('当前未注册地图');
mapjson = await GETNOBASE(`./map-geojson/${geoname}.json`).then((res) => {
return res;
});
echarts.registerMap(name, mapjson);
}
console.log(mapjson);
let cityCenter = {};
let arr = mapjson.features;
//根据geojson获取省份中心点
arr.map((item) => {
cityCenter[item.properties.name] =
item.properties.centroid || item.properties.center;
});
let newData = [];
mydata.map((item) => {
if (cityCenter[item.name]) {
if(item.siteTotalCount===undefined || item.siteTotalCount===null ){
item.siteTotalCount = 0;
}
if(item.siteCount===undefined || item.siteCount===null){
item.siteCount = 0;
}
newData.push({
name: item.name,
value: cityCenter[item.name].concat(item.siteTotalCount).concat(item.siteCount),
});
}
});
console.log('加氢站_开始初始化地图');
console.log(newData);
this.init2(name, mydata, newData);
},
init(name, data, data2) {
console.log('init_data');
console.log(data);
console.log('init_data2');
console.log(data2);
let top = 45;
let zoom = 1.05;
let option = {
backgroundColor: "rgba(0,0,0,0)",
tooltip: {
show: false,
},
legend: {
show: false,
},
visualMap: {
left: 20,
bottom: 20,
pieces: [
// { gte: 1000, label: "1000辆以上" }, // 不指定 max表示 max 为无限大Infinity
// { gte: 600, lte: 999, label: "600-999辆" },
// { gte: 200, lte: 599, label: "200-599辆" },
// { gte: 50, lte: 199, label: "49-199辆" },
// { gte: 10, lte: 49, label: "10-49辆" },
// { lte: 9, label: "1-9辆" }, // 不指定 min表示 min 为无限大(-Infinity
{ gte: 500, label: "500辆以上" }, // 不指定 max表示 max 为无限大Infinity
{ gte: 100, lte: 500, label: "100-500辆" },
{ gte: 50, lte: 100, label: "50-100辆" },
{ lte: 50, label: "1-50辆" },// 不指定 min表示 min 为无限大(-Infinity
],
inRange: {
// 渐变颜色,从小到大
color: [
// "#c3d7df",
// "#5cb3cc",
// "#8abcd1",
// "#66a9c9",
// "#2f90b9",
// "#1781b5",
"#6EC3F7",
"#2196F3",
"#1565C0",
"#0D47A1",
],
},
textStyle: {
color: "#fff",
},
},
geo: {
map: name,
roam: false,
selectedMode: false, //是否允许选中多个区域
zoom: zoom,
top: top,
// aspectScale: 0.78,
show: false,
},
series: [
{
name: "MAP",
type: "map",
map: name,
// zlevel: 2,
// aspectScale: 0.78,
data: data,
//data: [1,100],
selectedMode: false, //是否允许选中多个区域
zoom: zoom,
geoIndex: 1,
top: top,
tooltip: {
show: true,
formatter: function (params) {
//console.log("series 1 formatter");
//console.log(params);
if (params.data) {
//return params.name + "" + params.data["value"][2];
//return params.name + "" + params.data.vehicleTotal + "辆";
return `${params.name}<br>车辆总数: ${params.data.vehicleTotal}<br>GPS在线数: ${params.data.onLineCount}<br>当日里程: ${params.data.dayMileage}km<br>当日用氢量: ${params.data.dayHydrogen}kg<br>当日减碳: ${params.data.dayCarbon}kg`;
} else {
return params.name;
}
},
backgroundColor: "rgba(0,0,0,.6)",
borderColor: "rgba(147, 235, 248, .8)",
textStyle: {
color: "#FFF",
},
},
label: {
show: false,
color: "#000",
// position: [-10, 0],
formatter: function (val) {
// console.log(val)
if (val.data !== undefined) {
return val.name.slice(0, 2);
} else {
return "";
}
},
rich: {},
},
emphasis: { //高亮时显示
label: {
show: false,
},
itemStyle: {
areaColor: "#389BB7",
borderWidth: 1,
},
},
itemStyle: {
borderColor: "rgba(147, 235, 248, .8)",
borderWidth: 1,
areaColor: {
type: "radial",
x: 0.5,
y: 0.5,
r: 0.8,
colorStops: [
{
offset: 0,
color: "rgba(147, 235, 248, 0)", // 0% 处的颜色
},
{
offset: 1,
color: "rgba(147, 235, 248, .2)", // 100% 处的颜色
},
],
globalCoord: false, // 缺为 false
},
shadowColor: "rgba(128, 217, 248, .3)",
shadowOffsetX: -2,
shadowOffsetY: 2,
shadowBlur: 10,
},
},
{
//data: data2,
//type: "effectScatter",
data: data2.filter(item => item.value && item.value.length > 2 && item.value[2] > 0),
type: "scatter",
coordinateSystem: "geo",
symbol: 'image://' + require('../../assets/img/cars.png'),
symbolSize: function (val) {
return 20;
//return 4;
},
legendHoverLink: true,
// showEffectOn: "render",
// rippleEffect: {
// // period: 4,
// scale: 6,
// color: "rgba(255,255,255, 1)",
// brushType: "fill",
// },
tooltip: {
show: true,
//trigger: "item",
formatter: function (params) {
//console.log("series 2 formatter");
//console.log(params);
if (params.data) {
console.log("params.data");
console.log(params.data);
console.log(params.data.name + "\n 车辆总数: "+params.data["value"][2] + "\n GPS在线数: " + params.data["value"][3]);
return params.data.name + "<br> 车辆总数: "+params.data["value"][2] + "<br> GPS在线数: " + params.data["value"][3] + "<br>当日里程: " + params.data["value"][4] + "km<br>当日用氢量: " + params.data["value"][5] + "kg<br>当日减碳: " + params.data["value"][6] + "kg";
//return '${params.name} <br />车辆总数:${params.data[value][2]} <br /> GPS在线总数${ params.data.[value][3]}';
}
},
backgroundColor: "rgba(0,0,0,.6)",
borderColor: "rgba(147, 235, 248, .8)",
textStyle: {
color: "#FFF",
},
},
label: {
formatter: (param) => {
//return param.name.slice(0, 2) + "\n 车辆总数:"+param.data["value"][2] + "\n GPS在线数"+param.data["value"][3]; //2025.03.28
//return param.name.slice(0, 2) ;
if (param.data && param.data.value && param.data.value.length > 2 && param.data.value[2] > 0) {
return param.data.value[2]; // 显示车辆总数
}
return '';
},
fontSize: 11,
offset: [0, 2],
position: "bottom",
textBorderColor: "#fff",
textShadowColor: "#000",
textShadowBlur: 10,
textBorderWidth: 0,
color: "#FFF",
show: true,
},
// colorBy: "data",
itemStyle: {
color: "rgba(255,255,255,1)",
borderColor: "rgba(2255,255,255,2)",
borderWidth: 4,
shadowColor: "#000",
shadowBlur: 10,
},
},
],
//动画效果
// animationDuration: 1000,
// animationEasing: 'linear',
// animationDurationUpdate: 1000
};
this.options = option;
},
//2025.9.11 szy add begin
init2(name, data, data2) {
console.log('init_data');
console.log(data);
console.log('init_data2');
console.log(data2);
let top = 45;
let zoom = 1.05;
let option = {
backgroundColor: "rgba(0,0,0,0)",
tooltip: {
show: false,
},
legend: {
show: false,
},
visualMap: {
left: 20,
bottom: 20,
pieces: [
{ gte: 100, label: "100 座以上" }, // 不指定 max表示 max 为无限大Infinity
{ gte: 30, lte: 100, label: "30-100 座" },
{ gte: 10, lte: 30, label: "10-30 座" },
{ lte: 10, label: "1-10 座" },// 不指定 min表示 min 为无限大(-Infinity
],
inRange: {
// 渐变颜色,从小到大
color: [
// "#66a9c9",
// "#2f90b9",
// "#1781b5",
"#6EC3F7",
"#2196F3",
"#1565C0",
"#0D47A1",
],
},
textStyle: {
color: "#fff",
},
},
geo: {
map: name,
roam: false,
selectedMode: false, //是否允许选中多个区域
zoom: zoom,
top: top,
// aspectScale: 0.78,
show: false,
},
series: [
{
name: "MAP",
type: "map",
map: name,
// zlevel: 2,
// aspectScale: 0.78,
data: data,
//data: [1,100],
selectedMode: false, //是否允许选中多个区域
zoom: zoom,
geoIndex: 1,
top: top,
tooltip: {
show: true,
formatter: function (params) {
//console.log("series 1 formatter");
//console.log(params);
if (params.data) {
//return params.name + "" + params.data["value"][2];
return `${params.name}<br>加氢站总数: ${params.data.siteTotalCount}<br>当前运营总数: ${params.data.siteCount}`;
} else {
return params.name;
}
},
backgroundColor: "rgba(0,0,0,.6)",
borderColor: "rgba(147, 235, 248, .8)",
textStyle: {
color: "#FFF",
},
},
label: {
show: false,
color: "#000",
// position: [-10, 0],
formatter: function (val) {
// console.log(val)
if (val.data !== undefined) {
return val.name.slice(0, 2);
} else {
return "";
}
},
rich: {},
},
emphasis: { //高亮时显示
label: {
show: false,
},
itemStyle: {
areaColor: "#389BB7",
borderWidth: 1,
},
},
itemStyle: {
borderColor: "rgba(147, 235, 248, .8)",
borderWidth: 1,
areaColor: {
type: "radial",
x: 0.5,
y: 0.5,
r: 0.8,
colorStops: [
{
offset: 0,
color: "rgba(147, 235, 248, 0)", // 0% 处的颜色
},
{
offset: 1,
color: "rgba(147, 235, 248, .2)", // 100% 处的颜色
},
],
globalCoord: false, // 缺为 false
},
shadowColor: "rgba(128, 217, 248, .3)",
shadowOffsetX: -2,
shadowOffsetY: 2,
shadowBlur: 10,
},
},
{
data: data2,
type: "effectScatter",
coordinateSystem: "geo",
symbolSize: function (val) {
return 4;
// return val[2] / 50;
},
legendHoverLink: true,
showEffectOn: "render",
rippleEffect: {
// period: 4,
scale: 6,
color: "rgba(255,255,255, 1)",
brushType: "fill",
},
tooltip: {
show: false,
//trigger: "item",
formatter: function (params) {
//console.log("series 2 formatter");
//console.log(params);
if (params.data) {
console.log("params.data");
console.log(params.data);
console.log(params.data.name + "\n 加氢站总数:"+params.data["value"][2] + "\n 当前运营总数:" + params.data["value"][3]);
return params.data.name + "<br> 加氢站总数:"+params.data["value"][2] + "<br> 当前运营总数: " + params.data["value"][3];
}
},
backgroundColor: "rgba(0,0,0,.6)",
borderColor: "rgba(147, 235, 248, .8)",
textStyle: {
color: "#FFF",
},
},
label: {
formatter: (param) => {
//return param.name.slice(0, 2) + "\n 车辆总数:"+param.data["value"][2] + "\n GPS在线数"+param.data["value"][3]; //2025.03.28
//return param.name.slice(0, 2) + "\n "+param.data["value"][2]; //2025.03.31
return param.name.slice(0, 2) ;
},
fontSize: 11,
offset: [0, 2],
position: "bottom",
textBorderColor: "#fff",
textShadowColor: "#000",
textShadowBlur: 10,
textBorderWidth: 0,
color: "#FFF",
show: true,
},
// colorBy: "data",
itemStyle: {
color: "rgba(255,255,255,1)",
borderColor: "rgba(2255,255,255,2)",
borderWidth: 4,
shadowColor: "#000",
shadowBlur: 10,
},
},
],
//动画效果
// animationDuration: 1000,
// animationEasing: 'linear',
// animationDurationUpdate: 1000
};
this.options = option;
},
//2025.9.11 szy add end
message(text) {
this.$Message({
text: text,
type: "warning",
});
},
mapclick() {
if (this.echartBindClick) return;
//单击切换到级地图当mapCode有值,说明可以切换到下级地图
this.$refs.CenterMap.chart.on("click", (params) => {
console.log(params);
let xzqData = xzqCode[params.name];
if (xzqData) {
this.getData(xzqData.adcode);
} else {
this.message("暂无下级地市!");
}
});
this.echartBindClick = true;
}
},
destroyed() {
// 销毁事件监听
this.$refs.CenterMap.chart.off("click");
if (this.charts) {
this.echarts.dispose();
}
},
};
</script>
<style lang="scss" scoped>
.mileagetitle {
height: 40px;
display: flex;
justify-content: center;
padding-top: 2px;
box-sizing: border-box;
.titletext {
font-size: 22px;
font-weight: 900;
letter-spacing: 4px;
background: linear-gradient(
92deg,
#0072ff 0%,
#00eaff 48.8525390625%,
#01aaff 100%
);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin: 0 8px;
}
.titletextBefore {
font-size: 18px;
font-weight: 900;
letter-spacing: 4px;
color: white;
margin: 0 8px;
}
.zuo,
.you {
background-size: 100% 100%;
width: 29px;
height: 20px;
margin-top: 8px;
}
.zuo {
background: url("../../assets/img/xiezuo.png") no-repeat;
}
.you {
background: url("../../assets/img/xieyou.png") no-repeat;
}
}
.centermap {
margin-bottom: 30px;
width: 720px;
.maptitle {
height: 60px;
display: flex;
justify-content: center;
padding-top: 10px;
box-sizing: border-box;
.titletext {
font-size: 32px;
font-weight: 900;
letter-spacing: 6px;
background: linear-gradient(
92deg,
#0072ff 0%,
#00eaff 48.8525390625%,
#01aaff 100%
);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin: 0 10px;
}
.titletextBefore {
font-size: 28px;
font-weight: 900;
letter-spacing: 6px;
color: white;
margin: 0 10px;
}
.zuo,
.you {
background-size: 100% 100%;
width: 29px;
height: 20px;
margin-top: 8px;
}
.zuo {
background: url("../../assets/img/xiezuo.png") no-repeat;
}
.you {
background: url("../../assets/img/xieyou.png") no-repeat;
}
}
.mapwrap {
top: -5px;
height: 548px;
width: 100%;
// padding: 0 0 10px 0;
box-sizing: border-box;
position: relative;
.quanguo {
position: absolute;
right: 20px;
top: -30px;
width: 60px;
height: 26px;
border: 1px solid #00eded;
border-radius: 10px;
color: #00f7f6;
text-align: center;
line-height: 24px;
letter-spacing: 6px;
cursor: pointer;
box-shadow: 0 2px 4px rgba(0, 237, 237, 0.5),
0 0 6px rgba(0, 237, 237, 0.4);
}
.quanguo1 {
position: absolute;
right: 20px;
top: 24px;
width: 100px;
height: 28px;
border: 1px solid #00eded;
border-radius: 10px;
color: white;
text-align: center;
line-height: 26px;
letter-spacing: 6px;
cursor: pointer;
box-shadow: 0 2px 4px rgba(0, 237, 237, 0.5), 0 0 6px rgba(0, 237, 237, 0.4);
font-family: "微软雅黑", sans-serif;
z-index: 9999;
}
.quanguo2 {
position: absolute;
left: 20px;
top: 24px;
width: 100px;
height: 28px;
border: 1px solid #00eded;
border-radius: 10px;
color: white;
text-align: center;
line-height: 26px;
letter-spacing: 6px;
cursor: pointer;
box-shadow: 0 2px 4px rgba(0, 237, 237, 0.5), 0 0 6px rgba(0, 237, 237, 0.4);
font-family: "微软雅黑", sans-serif;
z-index: 9999;
}
.quanguo3 {
position: absolute;
left: 20px;
top: 60px;
width: 100px;
height: 28px;
border: 1px solid #00eded;
border-radius: 10px;
color: white;
text-align: center;
line-height: 26px;
letter-spacing: 6px;
cursor: pointer;
box-shadow: 0 2px 4px rgba(0, 237, 237, 0.5), 0 0 6px rgba(0, 237, 237, 0.4);
font-family: "微软雅黑", sans-serif;
z-index: 9999;
}
.quanguo4{
position: absolute; /* 绝对定位 */
bottom: 0; /* 底部对齐 */
left: 50%; /* 左边缘对齐 */
transform: translateX(-50%); /* 向左移动自身宽度的50%以实现水平居中 */
bottom:10px;
color: white;
}
}
}
</style>

View File

@@ -0,0 +1,253 @@
<template>
<div class="chart-block">
<!-- 左侧 柱状+折线图 -->
<div class="chart-container">
<v-chart class="bar-line-chart" :options="barLineOption" style="width: 390px;height: 250px;"/>
</div>
<!-- 右侧 两个环形图 -->
<div class="chart-container-right">
<v-chart class="pie-chart" :options="pieOptionOne" style="width: 140px;height:100px;margin-left: -11%;margin-top: 5%;"/>
<v-chart class="pie-chart" :options="pieOptionTwo" style="width: 140px;height:100px;margin-left: -11%;margin-top: 5%;"/>
</div>
</div>
</template>
<script>
import VChart from 'vue-echarts'
import * as echarts from 'echarts'
import 'echarts/lib/chart/bar'
import 'echarts/lib/chart/line'
import 'echarts/lib/chart/pie'
import 'echarts/lib/component/legend'
import 'echarts/lib/component/tooltip'
import { currentGET } from 'api/modules'
export default {
name: 'ChartBlock',
components: { VChart },
data() {
return {
/* 柱状图 + 折线图 */
barLineOption: {
backgroundColor: 'transparent', // 让背景透明,方便在大屏布局中适配
tooltip: { trigger: 'axis',
formatter: (params) => {
console.log(params)
return `碳减排量:${params[0].value}kg<br/>行驶里程:${params[1].value}km`;
}
},
legend: {
data: ['碳减排量(kg)', '行驶里程(km)'],
textStyle: { color: '#fff' }
},
grid: {
left: '18%',
right: '18%',
top: '10%',
bottom: '10%'
},
xAxis: {
type: 'category',
data: ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'],
axisLine: { lineStyle: { color: '#fff' } },
axisLabel: { color: '#fff' }
},
yAxis: [
{
type: 'value',
// name: '碳减排量',
axisLine: { lineStyle: { color: '#fff' } },
axisLabel: { color: '#fff' },
splitLine: { show: false },
axisLabel: {
formatter: '{value}kg'
}
},
{
type: 'value',
// name: '行驶里程',
axisLine: { lineStyle: { color: '#fff' } },
axisLabel: { color: '#fff' },
splitLine: { show: false },
axisLabel: {
formatter: '{value}km'
}
}
],
series: [
{
name: '碳减排量(kg)',
type: 'bar',
data: [1000, 1500, 1800, 1200, 2000, 2500, 1800, 2200, 3000, 3500,2600, 3600],
itemStyle: { color: '#00BAFF' },
barWidth: 14
},
{
name: '行驶里程(km)',
type: 'line',
yAxisIndex: 1,
data: [3500, 400, 4200, 3800, 4500, 4800, 4200, 4600, 4900, 5200, 4700, 5500],
itemStyle: { color: '#FFC600' },
smooth: true,
lineStyle: { width: 2 },
symbol: 'circle',
symbolSize: 8
}
]
},
/* 环形图1 - 年度碳减排量 */
pieOptionOne: {
backgroundColor: 'transparent',
tooltip: { show: false },
title: {
text: '0吨',
//subtext: '年度碳减排量',
left: 'center',
top: '40%',
textStyle: { color: '#fff', fontSize: 18 },
subtextStyle: { color: '#fff', fontSize: 18}
},
graphic: [
{
type: 'text',
left: '0px', // 根据需要调整文字与图表的间距
top: 'center', // 垂直居中
style: {
text: '年\n度\n碳\n减\n排\n量', // 每个字符换行显示
fill: '#fff',
font: '16px sans-serif',
}
}
],
series: [
{
name: '年度碳减排量',
type: 'pie',
radius: ['70%', '90%'],
hoverAnimation: false,
label: { show: false },
labelLine: { show: false },
data: [
{ value: 5, name: '碳排放量', itemStyle: { color: '#7d70f9' } },
{ value: 95, name: 'other', itemStyle: { color: '#2f4c6e' } }
]
}
]
},
/* 环形图2 - 年度行驶里程 */
pieOptionTwo: {
backgroundColor: 'transparent',
tooltip: { show: false },
title: {
text: '0万',
//subtext: '年度行驶里程',
left: 'center',
top: '40%',
textStyle: { color: '#fff', fontSize: 18 },
subtextStyle: { color: '#fff', fontSize: 12 }
},
graphic: [
{
type: 'text',
left: '0px', // 根据需要调整文字与图表的间距
top: 'center', // 垂直居中
style: {
text: '年\n度\n行\n驶\n里\n程', // 每个字符换行显示
fill: '#fff',
font: '16px sans-serif',
}
}
],
series: [
{
name: '年度行驶里程',
type: 'pie',
radius: ['70%', '90%'],
hoverAnimation: false,
label: { show: false },
labelLine: { show: false },
data: [
{ value: 85, name: '行驶里程', itemStyle: { color: '#00BAFF' } },
{ value: 15, name: 'other', itemStyle: { color: '#2f4c6e' } }
]
}
]
},
monthItems:[],
monthCarbon:[],
monthMileage:[]
}
},
mounted() {
this.getMonthData();
this.getYearData();
},
methods: {
getMonthData() {
currentGET("big2").then((res) => {
console.log('月度碳足迹');
this.monthItems = res.data;
console.log(this.monthItems);
this.monthItems.forEach((item) => {
console.log(item.monthCarbon);
console.log(item.monthMileage);
this.monthCarbon.push(item.monthCarbon);
this.monthMileage.push(item.monthMileage);
});
console.log('碳减排:'+ this.monthCarbon);
console.log('里程数:'+ this.monthMileage);
this.barLineOption.series[0].data = this.monthCarbon;
this.barLineOption.series[1].data = this.monthMileage;
});
},
getYearData() {
currentGET("big3").then((res) => {
console.log('年度碳减排量');
console.log(res);
this.pieOptionOne.title.text = res.data.yearCarbonTon + '吨';
this.pieOptionTwo.title.text = res.data.yearMileage + '万km';
});
}
}
}
</script>
<style scoped>
.chart-block {
display: flex;
justify-content: space-around;
align-items: center;
/* 自行控制宽高,若嵌入大屏可由外层决定大小 */
width: 800px;
height: 300px;
/* 背景可保持透明,方便嵌入大屏的背景 */
background: transparent;
}
.chart-container {
margin-left: -30px;
width: 50%;
height: 100%;
}
.bar-line-chart {
width: 100%;
height: 100%;
}
/* 右侧两个环形图的布局 */
.chart-container-right {
width: 45%;
height: 100%;
margin-right: -20px;
}
.pie-chart {
width: 160px;
height: 160px;
}
</style>

232
src/views/indexs/index.vue Normal file
View File

@@ -0,0 +1,232 @@
<!--
* @Author: szy
* @Date: 2022-03-04 09:23:59
* @LastEditors: Please set LastEditors
* @LastEditTime: 2022-05-07 11:05:02
* @FilePath: \web-pc\src\pages\big-screen\view\indexs\index.vue
-->
<template>
<div class="contents">
<div class="contetn_left">
<div class="pagetab">
<!-- <div class="item">实时监测</div> -->
</div>
<ItemWrap class="contetn_left-top contetn_lr-item" title="当日实况">
<LeftTop/>
</ItemWrap>
<ItemWrap class="contetn_left-center contetn_lr-item" title="月度碳足迹">
<!-- <LeftCenter /> -->
<base-chart/>
</ItemWrap>
<ItemWrap class="contetn_left-bottom contetn_lr-item" title="月度用氢量统计"
style="padding: 0 10px 16px 10px">
<!-- <LeftBottom /> -->
<RightCenterNew />
</ItemWrap>
</div>
<div class="contetn_center">
<CenterMap class="contetn_center_top" />
<ItemWrap class="contetn_center-bottom" title="交易所信息">
<!-- <CenterBottom /> -->
<RightBottom />
</ItemWrap>
<div class="tech-support-bottom"><span class="tech-text">© 2025 羚牛科技提供技术支持</span></div>
</div>
<div class="contetn_right">
<!-- <ItemWrap
class="contetn_left-bottom contetn_lr-item"
title="月度违章情况"
>
<RightTop />
</ItemWrap> -->
<!-- <ItemWrap
class="contetn_left-bottom contetn_lr-item"
:title="currentTitle">
<RightTop @update-title="currentTitle = $event"/>
</ItemWrap> 暂时去掉折线面积图-->
<!-- 2025.8.13 szy 月度数据暂时不用 -->
<!-- <ItemWrap class="contetn_center-bottom" title="">
<RightTopMonth />
</ItemWrap> -->
<!-- 2025.8.13 szy 使用当天数据 -->
<ItemWrap class="contetn_right_day_top" title="">
<RightTopDay />
</ItemWrap>
<!-- <ItemWrap
class="contetn_left-bottom contetn_lr-item"
title="月度用氢量统计"
style="padding: 0 10px 16px 10px"
>
<RightCenterNew />
</ItemWrap> -->
<ItemWrap class="contetn_right-bottom" title="车型分类 "> <!--class="contetn_left-bottom contetn_lr-item" -->
<CenterBottom />
</ItemWrap>
</div>
</div>
</template>
<script>
import LeftTop from './left-top.vue'
import LeftCenter from "./left-center.vue";
import LeftBottom from "./left-bottom.vue";
import CenterMap from "./center-map.vue";
import CenterBottom from "./center-bottom.vue";
import RightTop from "./right-top.vue";
import RightCenter from "./right-center.vue";
import RightBottom from "./right-bottom.vue";
import BaseChart from "./chart/baseChart.vue";
import RightTopMonth from './right-top-new.vue';
import RightTopDay from './right-top-day.vue'
import RightCenterNew from "./right-center-new.vue";
export default {
components: {
LeftTop,
LeftCenter,
LeftBottom,
CenterMap,
RightTop,
RightCenter,
RightBottom,
CenterBottom,
BaseChart,
RightTopMonth,
RightTopDay,
RightCenterNew
},
data() {
return {
currentTitle:''
};
},
filters: {
numsFilter(msg) {
return msg || 0;
},
},
created() {
},
mounted() {},
methods: {
},
};
</script>
<style lang="scss" scoped>
// 内容
.contents {
.contetn_left,
.contetn_right {
width: 540px;
box-sizing: border-box;
// padding: 16px 0;
}
.contetn_center {
margin-top: -5px;
width: 700px;
}
//左右两侧 三个块
.contetn_lr-item {
height: 320px;
}
.contetn_center_top {
margin-top: 0px;
width: 712px;
}
//右上角,车辆信息
.contetn_right_day_top {
margin-top: 0px;
height: 640px;
}
// 中间
.contetn_center {
display: flex;
flex-direction: column;
justify-content: space-around;
}
//交易所
.contetn_center-bottom {
margin-top: -25px;
height: 320px;
width: 712px;
}
//车型分布
.contetn_right-bottom{
margin-bottom: -3px;
height: 320px;
}
//左边 右边 结构一样
.contetn_left,
.contetn_right {
display: flex;
flex-direction: column;
justify-content: space-around;
position: relative;
}
}
.tech-support-bottom {
display: flex;
justify-content: center; /* 水平居中 */
align-items: flex-start; /* 垂直居中 */
height: 12px;
margin-top: -4px;
&:hover {
opacity: 1;
transform: translateY(-1px);
}
.tech-text {
font-size: 14px;
color: #8c8c8c;
font-weight: 500;
letter-spacing: 0.8px;
white-space: nowrap;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
position: relative;
// 添加一个简洁的下划线装饰
&::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
width: 100%;
height: 1px;
background: linear-gradient(90deg, #8c8c8c 0%, transparent 100%);
opacity: 0.4;
transition: opacity 0.3s ease;
}
}
&:hover .tech-text::after {
opacity: 1;
}
}
@keyframes rotating {
0% {
-webkit-transform: rotate(0) scale(1);
transform: rotate(0) scale(1);
}
50% {
-webkit-transform: rotate(180deg) scale(1.1);
transform: rotate(180deg) scale(1.1);
}
100% {
-webkit-transform: rotate(360deg) scale(1);
transform: rotate(360deg) scale(1);
}
}
</style>

View File

@@ -0,0 +1,120 @@
<template>
<div ref="chart" class="chart-container"></div>
</template>
<script>
import echarts from 'echarts';
import { currentGET } from 'api/modules';
export default {
name: 'LeftBottomChart',
data() {
return {
monthItems:[],
monthHydrogen:[],
monthMileage:[],
monthCarbon:[],
seriesData:['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'],
}
},
mounted() {
this.getMonthData();
},
methods: {
getMonthData() {
currentGET("big2").then((res) => {
console.log('月度碳减排');
this.monthItems = res.data;
console.log(this.monthItems);
this.monthItems.forEach((item) => {
let month = parseInt(item.months.substring(5,7));
this.monthMileage[month-1] = item.monthMileage==null?0:item.monthMileage;
this.monthCarbon[month-1] = item.monthCarbon==null?0:item.monthCarbon;
// this.monthHydrogen.push(item.monthHydrogen);
// this.monthMileage.push(item.monthMileage);
// this.monthCarbon.push(item.monthCarbon);
});
//console.log('用氢量:'+ this.monthHydrogen);
//console.log('里程数:'+ this.monthMileage);
this.initChart();
});
},
initChart() {
let chart = echarts.init(this.$refs.chart);
let option = {
grid:{
left:'15%'
},
tooltip: {
trigger: 'axis',
formatter: (params) => {
console.log(params)
return `碳减排:${params[0].value}kg<br/>行驶里程:${params[1].value}km`;
}
},
legend: {
//data: ['用氢量', '用电量', '行驶里程'],
data: ['碳减排(kg)','行驶里程(km)'],
textStyle: { color: '#fff' }
},
xAxis: {
type: 'category',
boundaryGap: false,
data: this.seriesData,
axisLine: { lineStyle: { color: '#fff' } }
},
yAxis: {
type: 'value',
axisLine: { lineStyle: { color: '#fff' } },
splitLine: { lineStyle: { color: '#091a40' } },
axisLabel: {
formatter: '{value}kg'
}
},
series: [
// {
// name: '用氢量(kg)',
// type: 'line',
// //data: [5000, 7000, 10000, 8000, 6000, 11000, 9000, 7000, 5000, 7050, 10020, 8900],
// data: this.monthHydrogen,
// // data: [11865.86,11687.64,18874.66,11311.62, 0, 0, 0, 0, 0, 0, 0, 0],
// itemStyle: { color: '#3399FF' }
// },
// {
// name: '用电量',
// type: 'line',
// //data: [6000, 8000, 12000, 10000, 5000, 10000, 9500, 7200, 5000, 3000, 10000, 8500],
// data: this.monthCarbon,
// itemStyle: { color: '#3f89ff' }
// },
{
name: '碳减排(kg)',
type: 'line',
//data: [5000, 7000, 10000, 8000, 6000, 11000, 9000, 7000, 5000, 7050, 10020, 8900],
data: this.monthCarbon,
// data: [11865.86,11687.64,18874.66,11311.62, 0, 0, 0, 0, 0, 0, 0, 0],
itemStyle: { color: '#3399FF' }
},
{
name: '行驶里程(km)',
type: 'line',
data: [4000, 9000, 9500, 7000, 9000, 12000, 10000, 8000, 5000, 7000, 10000, 8000],
data: this.monthMileage,
//data: [20219.1,332767.1,1671592.3,330955, 0, 0, 0, 0, 0, 0, 0, 0],
itemStyle: { color: '#a060ff' }
}
]
};
chart.setOption(option);
}
}
};
</script>
<style scoped>
.chart-container {
width: 110%;
height: 300px;
}
</style>

View File

@@ -0,0 +1,231 @@
<!--
* @Author: szy
* @Date: 2022-02-28 16:16:42
* @LastEditors: Please set LastEditors
* @LastEditTime: 2022-10-25 09:18:22
* @FilePath: \web-pc\src\pages\big-screen\view\indexs\left-center.vue
-->
<template>
<Echart id="leftCenter" :options="options" class="left_center_inner" v-if="pageflag" ref="charts" />
<Reacquire v-else @onclick="getData" style="line-height:200px">
重新获取
</Reacquire>
</template>
<script>
import { currentGET } from 'api/modules'
export default {
data() {
return {
options: {},
countUserNumData: {
lockNum: 0,
onlineNum: 0,
offlineNum: 0,
totalNum: 0
},
pageflag: true,
timer: null
};
},
created() {
this.getData()
},
mounted() {
},
beforeDestroy() {
this.clearData()
},
methods: {
clearData() {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
},
getData() {
this.pageflag = true
// this.pageflag =false
currentGET('big1').then(res => {
//只打印一次
if (!this.timer) {
console.log("设备总览", res);
}
if (res.success) {
this.countUserNumData = res.data
this.$nextTick(() => {
this.init()
})
} else {
this.pageflag = false
this.$Message({
text: res.msg,
type: 'warning'
})
}
})
},
//轮询
switper() {
if (this.timer) {
return
}
let looper = (a) => {
this.getData()
};
this.timer = setInterval(looper, this.$store.state.setting.echartsAutoTime);
let myChart = this.$refs.charts.chart
myChart.on('mouseover', params => {
this.clearData()
});
myChart.on('mouseout', params => {
this.timer = setInterval(looper, this.$store.state.setting.echartsAutoTime);
});
},
init() {
let total = this.countUserNumData.totalNum;
let colors = ["#ECA444", "#33A1DB", "#56B557"];
let piedata = {
name: "用户总览",
type: "pie",
radius: ["42%", "65%"],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 4,
borderColor: "rgba(0,0,0,0)",
borderWidth: 2,
},
color: colors,
data: [
// {
// value: 0,
// name: "告警",
// label: {
// shadowColor: colors[0],
// },
// },
{
value: this.countUserNumData.lockNum,
name: "锁定",
label: {
shadowColor: colors[0],
},
},
{
value: this.countUserNumData.onlineNum,
name: "在线",
label: {
shadowColor: colors[2],
},
},
{
value: this.countUserNumData.offlineNum,
name: "离线",
label: {
shadowColor: colors[1],
},
},
],
};
this.options = {
title: {
// zlevel: 0,
text: ["{value|" + total + "}", "{name|总数}"].join("\n"),
top: "center",
left: "center",
textStyle: {
rich: {
value: {
color: "#ffffff",
fontSize: 24,
fontWeight: "bold",
lineHeight: 20,
},
name: {
color: "#ffffff",
lineHeight: 20,
},
},
},
},
tooltip: {
trigger: "item",
backgroundColor: "rgba(0,0,0,.6)",
borderColor: "rgba(147, 235, 248, .8)",
textStyle: {
color: "#FFF",
},
},
legend: {
show: false,
top: "5%",
left: "center",
},
series: [
//展示圆点
{
...piedata,
tooltip: { show: true },
label: {
formatter: " {b|{b}} \n {c|{c}个} {per|{d}%} ",
// position: "outside",
rich: {
b: {
color: "#fff",
fontSize: 12,
lineHeight: 26,
},
c: {
color: "#31ABE3",
fontSize: 14,
},
per: {
color: "#31ABE3",
fontSize: 14,
},
},
},
labelLine: {
length: 20, // 第一段线 长度
length2: 36, // 第二段线 长度
show: true,
},
emphasis: {
show: true,
},
},
{
...piedata,
tooltip: { show: true },
itemStyle: {},
label: {
backgroundColor: "inherit", //圆点颜色auto映射的系列色
height: 0,
width: 0,
lineHeight: 0,
borderRadius: 2.5,
shadowBlur: 8,
shadowColor: "auto",
padding: [2.5, -2.5, 2.5, -2.5],
},
labelLine: {
length: 20, // 第一段线 长度
length2: 36, // 第二段线 长度
show: false,
},
},
],
};
},
},
};
</script>
<style lang='scss' scoped>
</style>

View File

@@ -0,0 +1,331 @@
<template>
<div class="cards-container">
<!-- 四个卡片 -->
<div class="card">
<!-- 数值与文字 -->
<div class="card-info">
<!-- 主数值高亮 -->
<div class="value-line">
<span class="number">{{ cards[0].value }}</span>
<span class="unit">{{ cards[0].unit }}</span>
</div>
<!-- 标签说明 -->
<div class="label">{{ cards[0].label }}</div>
</div>
<!-- 图标及其闪动背景 -->
<div class="icon-wrapper">
<!-- 背后闪动的竖直矩形 -->
<div class="icon-bg icon-bg-0"></div>
<!-- 圆形平台 -->
<div class="platform-circle"></div>
<!-- 图标本身此处用Unicode或自定义图标 -->
<div class="icon">
<img src="@/assets/img/left/1.svg" class="images"/>
</div>
</div>
</div>
<div class="card">
<!-- 数值与文字 -->
<div class="card-info">
<!-- 主数值高亮 -->
<div class="value-line">
<span class="number">{{ cards[1].value }}</span>
<span class="unit">{{ cards[1].unit }}</span>
</div>
<!-- 标签说明 -->
<div class="label">{{ cards[1].label }}</div>
</div>
<!-- 图标及其闪动背景 -->
<div class="icon-wrapper">
<!-- 背后闪动的竖直矩形 -->
<div class="icon-bg icon-bg-1"></div>
<!-- 圆形平台 -->
<div class="platform-circle"></div>
<!-- 图标本身此处用Unicode或自定义图标 -->
<div class="icon">
<img src="@/assets/img/left/2.svg" class="images"/>
</div>
</div>
</div>
<div class="card">
<!-- 数值与文字 -->
<div class="card-info">
<!-- 主数值高亮 -->
<div class="value-line">
<span class="number">{{ cards[2].value }}</span>
<span class="unit">{{ cards[2].unit }}</span>
</div>
<!-- 标签说明 -->
<div class="label">{{ cards[2].label }}</div>
</div>
<!-- 图标及其闪动背景 -->
<div class="icon-wrapper">
<!-- 背后闪动的竖直矩形 -->
<div class="icon-bg icon-bg-2"></div>
<!-- 圆形平台 -->
<div class="platform-circle"></div>
<!-- 图标本身此处用Unicode或自定义图标 -->
<div class="icon">
<img src="@/assets/img/left/3.svg" class="images"/>
</div>
</div>
</div>
<div class="card">
<!-- 数值与文字 -->
<div class="card-info">
<!-- 主数值高亮 -->
<div class="value-line">
<span class="number">{{ cards[3].value }}</span>
<span class="unit">{{ cards[3].unit }}</span>
</div>
<!-- 标签说明 -->
<div class="label">{{ cards[3].label }}</div>
</div>
<!-- 图标及其闪动背景 -->
<div class="icon-wrapper">
<!-- 背后闪动的竖直矩形 -->
<div class="icon-bg icon-bg-3"></div>
<!-- 圆形平台 -->
<div class="platform-circle"></div>
<!-- 图标本身此处用Unicode或自定义图标 -->
<div class="icon">
<img src="@/assets/img/left/4.svg" class="images"/>
</div>
</div>
</div>
</div>
</template>
<script>
import { currentGET } from 'api/modules'
export default {
name: "BlinkingIcons",
data() {
return {
cards: [
{
id: 1,
value: "452/807",
unit: "辆",
label: "在线车数",
srcValue: "@/assets/img/left_top_lv.png",
},
{
id: 2,
value: "561",
unit: "kg",
label: "当日减碳",
srcValue: "@/assets/img/left/1.svg",
},
{
id: 3,
value: "534",
unit: "kg",
label: "当日用氢量",
srcValue: "@/assets/img/left/1.svg",
},
{
id:4,
value: "3300",
unit: "km",
label: "当日里程",
srcValue: "@/assets/img/left/1.svg",
},
],
};
},
mounted() {
this.getData();
},
methods: {
getData() {
currentGET("big1").then((res) => {
console.log('当日实况');
console.log(res);
let onLineCount = 0;
let vehicleCount = 0;
let dayCarbon = 0;
let dayHydrogen = 0;
let dayMileage = 0;
if(res !==null && res.data !==null )
{
if(res.data.onLineCount !== null)
onLineCount = res.data.onLineCount;
if(res.data.vehicleCount !== null)
vehicleCount = res.data.vehicleCount;
if(res.data.dayCarbon !== null)
dayCarbon = res.data.dayCarbon;
if(res.data.dayHydrogen !== null)
dayHydrogen = res.data.dayHydrogen;
if(res.data.dayMileage !== null)
dayMileage = res.data.dayMileage;
}
let change = this.cards[0];
change.value = onLineCount + "/" + vehicleCount;
this.$set(this.cards, 0, change);
change = this.cards[1];
change.value = dayCarbon;
this.$set(this.cards, 1, change);
change = this.cards[2];
change.value = dayHydrogen;
this.$set(this.cards, 2, change);
change = this.cards[3];
change.value = dayMileage;
this.$set(this.cards, 3, change);
});
},
}
};
</script>
<style scoped>
/* 整体背景 */
.cards-container {
display: flex;
justify-content: space-around;
align-items: flex-end;
padding-left: 0px;
padding-top: 30px;
padding-bottom: 30px;
background-image: url("../../assets/img/left/u665.svg");
background-repeat: no-repeat;
background-position: 0% 100%;
}
.images{
width: 65px;
height: 70px;
margin-left: 10px;
margin-top: -5px;
}
/* 单个卡片 */
.card {
position: relative;
width: 180px;
text-align: center;
color: #fff;
}
/* 卡片信息区域 */
.card-info {
margin-bottom: 120px; /* 给下方图标区域留出空间 */
margin-left:10px;
}
.value-line {
font-size: 20px;
margin-bottom: 8px;
width:120px;
}
.number {
color: #45f3ff; /* 高亮数字颜色 */
margin-right: 6px;
}
.unit {
font-size: 14px;
opacity: 0.8;
}
.label {
font-size: 16px;
color: #b9e4ff;
}
/* 图标容器 */
.icon-wrapper {
position: absolute;
bottom: 0;
left: 54%;
transform: translateX(-50%);
width: 100%;
height: 100px;
overflow: visible;
}
/* 背后闪动的竖直矩形 */
.icon-bg {
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 90px;
height: 100%;
border-radius: 6px;
background-image: url("../../assets/img/left/u676.svg");
background-repeat: no-repeat;
animation: blink 1s infinite alternate;
top: -15%;
}
.icon-bg-0 {
animation-delay: 0s;
}
.icon-bg-1 {
animation-delay: 0.2s;
}
.icon-bg-2 {
animation-delay: 0.4s;
}
.icon-bg-3 {
animation-delay: 0.6s;
}
/* 圆形平台 */
.platform-circle {
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 100px;
height: 20px;
background: radial-gradient(rgba(69, 243, 255, 0.4), transparent 70%);
border-radius: 50%;
box-shadow: 0 0 8px #0ad, 0 0 12px #0ad;
}
/* 图标 */
.icon {
position: absolute;
bottom: -5px;
left: 50%;
transform: translateX(-50%);
font-size: 28px;
color: #00e4ff;
}
/* 关键帧动画:闪动 */
@keyframes blink {
0% {
opacity: 0.5;
}
100% {
opacity: 1;
}
}
/* 图标模拟,可用 Font Awesome 等替换 */
.icon-phone::before {
content: "☎";
}
.icon-shield::before {
content: "⛨";
}
.icon-star::before {
content: "★";
}
.icon-protect::before {
content: "🛡";
}
</style>

View File

@@ -0,0 +1,232 @@
<!--
* @Author: szy
* @Date: 2022-02-28 16:16:42
* @LastEditors: Please set LastEditors
* @LastEditTime: 2022-07-20 17:57:11
* @FilePath: \web-pc\src\pages\big-screen\view\indexs\left-center.vue
-->
<template>
<ul class="user_Overview flex" v-if="pageflag">
<li class="user_Overview-item" style="color: #00fdfa">
<div class="user_Overview_nums allnum ">
<dv-digital-flop :config="config" style="width:100%;height:100%;" />
</div>
<p>总设备数</p>
</li>
<li class="user_Overview-item" style="color: #07f7a8">
<div class="user_Overview_nums online">
<dv-digital-flop :config="onlineconfig" style="width:100%;height:100%;" />
</div>
<p>在线数</p>
</li>
<li class="user_Overview-item" style="color: #e3b337">
<div class="user_Overview_nums offline">
<dv-digital-flop :config="offlineconfig" style="width:100%;height:100%;" />
</div>
<p>掉线数</p>
</li>
<li class="user_Overview-item" style="color: #f5023d">
<div class="user_Overview_nums laramnum">
<dv-digital-flop :config="laramnumconfig" style="width:100%;height:100%;" />
</div>
<p>告警次数</p>
</li>
</ul>
<Reacquire v-else @onclick="getData" line-height="200px">
重新获取
</Reacquire>
</template>
<script>
import { currentGET } from 'api/modules'
let style = {
fontSize: 24
}
export default {
data() {
return {
options: {},
userOverview: {
alarmNum: 0,
offlineNum: 0,
onlineNum: 0,
totalNum: 0,
},
pageflag: true,
timer: null,
config: {
number: [100],
content: '{nt}',
style: {
...style,
// stroke: "#00fdfa",
fill: "#00fdfa",
},
},
onlineconfig: {
number: [0],
content: '{nt}',
style: {
...style,
// stroke: "#07f7a8",
fill: "#07f7a8",
},
},
offlineconfig: {
number: [0],
content: '{nt}',
style: {
...style,
// stroke: "#e3b337",
fill: "#e3b337",
},
},
laramnumconfig: {
number: [0],
content: '{nt}',
style: {
...style,
// stroke: "#f5023d",
fill: "#f5023d",
},
}
};
},
filters: {
numsFilter(msg) {
return msg || 0;
},
},
created() {
this.getData()
},
mounted() {
},
beforeDestroy() {
this.clearData()
},
methods: {
clearData() {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
},
getData() {
this.pageflag = true;
currentGET("big2").then((res) => {
if (!this.timer) {
console.log("设备总览", res);
}
if (res.success) {
this.userOverview = res.data;
this.onlineconfig = {
...this.onlineconfig,
number: [res.data.onlineNum]
}
this.config = {
...this.config,
number: [res.data.totalNum]
}
this.offlineconfig = {
...this.offlineconfig,
number: [res.data.offlineNum]
}
this.laramnumconfig = {
...this.laramnumconfig,
number: [res.data.alarmNum]
}
this.switper()
} else {
this.pageflag = false;
this.$Message.warning(res.msg);
}
});
},
//轮询
switper() {
if (this.timer) {
return
}
let looper = (a) => {
this.getData()
};
this.timer = setInterval(looper, this.$store.state.setting.echartsAutoTime);
},
},
};
</script>
<style lang='scss' scoped>
.user_Overview {
li {
flex: 1;
p {
text-align: center;
height: 16px;
font-size: 16px;
}
.user_Overview_nums {
width: 100px;
height: 100px;
text-align: center;
line-height: 100px;
font-size: 22px;
margin: 50px auto 30px;
background-size: cover;
background-position: center center;
position: relative;
&::before {
content: '';
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
&.bgdonghua::before {
animation: rotating 14s linear infinite;
}
}
.allnum {
// background-image: url("../../assets/img/left_top_lan.png");
&::before {
background-image: url("../../assets/img/left/1.svg");
background-size: 100% 100%;
background-attachment: fixed;
background-repeat: no-repeat;
}
}
.online {
&::before {
background-image: url("../../assets/img/left_top_lv.png");
}
}
.offline {
&::before {
background-image: url("../../assets/img/left_top_huang.png");
}
}
.laramnum {
&::before {
background-image: url("../../assets/img/left_top_hong.png");
}
}
}
}
</style>

View File

@@ -0,0 +1,143 @@
<template>
<div class="table-container">
<table>
<thead>
<tr>
<th>交易所</th>
<th>项目</th>
<th>价格 (RMB)</th>
<th>地区</th>
</tr>
</thead>
</table>
<div class="scroll-wrapper">
<vue-seamless-scroll :data="tableData" :class-option="scrollOptions" class="scroll-container">
<table>
<tbody>
<tr v-for="(item, index) in tableData" :key="index">
<td :style="{ color: item.exchangeColor }">{{ item.name }}</td>
<td>{{ item.project }}</td>
<td :style="{ color: item.priceColor }">{{ item.price }}</td>
<td :style="{ color: item.regionColor }">{{ item.area }}</td>
</tr>
</tbody>
</table>
</vue-seamless-scroll>
</div>
</div>
</template>
<script>
import vueSeamlessScroll from "vue-seamless-scroll";
import { currentGET } from 'api/modules'
export default {
components: { vueSeamlessScroll },
data() {
return {
scrollOptions: {
step: 0.3, // 滚动速度
limitMoveNum: 2, // 限制单步滚动的条数
hoverStop: true, // 鼠标悬停是否暂停
direction: 1, // 方向1向上滚动
},
tableData: [
// { exchange: "湖北碳排放权交易中心", project: "CER", price: "90", region: "中国-湖北", exchangeColor: "#00ffcc", priceColor: "#ffffff", regionColor: "#ffffff" },
// { exchange: "欧洲碳排放权交易体系", project: "EUA", price: "90", region: "欧盟", exchangeColor: "#00ffcc", priceColor: "#00ffcc", regionColor: "#ffffff" },
// { exchange: "洲际交易所", project: "CERs", price: "89", region: "美国", exchangeColor: "#00ffcc", priceColor: "#00ffcc", regionColor: "#00ffcc" },
// { exchange: "加州碳市场", project: "CER", price: "88", region: "美国-加州", exchangeColor: "#ffcc00", priceColor: "#ffcc00", regionColor: "#ffcc00" },
// { exchange: "英国碳市场", project: "CER", price: "87", region: "英国", exchangeColor: "#ffcc00", priceColor: "#ffcc00", regionColor: "#ffffff" },
// { exchange: "热田碳排放交易所", project: "CER", price: "86", region: "韩国", exchangeColor: "#00ffcc", priceColor: "#ffffff", regionColor: "#ffffff" },
// { exchange: "湖北碳排放权交易中心", project: "CER", price: "90", region: "中国-湖北", exchangeColor: "#00ffcc", priceColor: "#ffffff", regionColor: "#ffffff" },
// { exchange: "欧洲碳排放权交易体系", project: "EUA", price: "90", region: "欧盟", exchangeColor: "#00ffcc", priceColor: "#00ffcc", regionColor: "#ffffff" },
// { exchange: "洲际交易所", project: "CERs", price: "89", region: "美国", exchangeColor: "#00ffcc", priceColor: "#00ffcc", regionColor: "#00ffcc" },
// { exchange: "加州碳市场", project: "CER", price: "88", region: "美国-加州", exchangeColor: "#ffcc00", priceColor: "#ffcc00", regionColor: "#ffcc00" },
// { exchange: "英国碳市场", project: "CER", price: "87", region: "英国", exchangeColor: "#ffcc00", priceColor: "#ffcc00", regionColor: "#ffffff" },
// { exchange: "热田碳排放交易所", project: "CER", price: "86", region: "韩国", exchangeColor: "#00ffcc", priceColor: "#ffffff", regionColor: "#ffffff" },
],
};
},
mounted() {
this.getExchangeData();
},
methods: {
getExchangeData() {
currentGET("big4").then(res => {
console.log("交易所数据:");
//console.log(this.tableData1);
console.log(res.data);
this.tableData = res.data;
this.tableData.forEach((item, index) => {
if(index % 2 !== 0)
{
item.exchangeColor = "#00ffcc";
item.priceColor = "#ffffff";
item.regionColor = "#ffffff";
this.$set(this.tableData, index, item);
}
else
{
//console.log("偶数index: " + index);
item.exchangeColor = "#ffcc00";
item.priceColor = "#ffcc00";
item.regionColor = "#ffcc00";
this.$set(this.tableData, index, item);
//this.$set(this.tableData, index, modifiedItem);
}
});
});
// console.log("转换后交易所数据:");
// console.log(this.tableData);
},
},
};
</script>
<style scoped>
.table-container {
width: 100%;
height: 310px;
border-radius: 5px;
overflow: hidden;
padding-top: 10px; /* 添加顶部内边距 */
}
table {
width: 100%;
border-collapse: collapse;
text-align: left;
}
th, td {
padding: 12px;
color: #fff;
font-size: 14px;
width: 25%;
}
thead {
background: #013f6a;
padding: 10%;
}
.scroll-wrapper {
height: 210px; /* 适配大屏,数据较多可增加高度 */
overflow: hidden;
}
.scroll-container table {
width: 100%;
}
tr {
border-bottom: 1px solid #0a2a4a;
}
tr:nth-child(even) {
background: rgba(255, 255, 255, 0.05);
}
</style>

View File

@@ -0,0 +1,201 @@
<template>
<div class="chart-container">
<div ref="chart" style="width: 520px; height: 300px;"></div>
</div>
</template>
<script>
import * as echarts from 'echarts';
import { currentGET } from "api/modules";
export default {
name: 'BarChart',
// 修改数据结构和series配置
data() {
return {
currentTab: 'month',
currentYear: new Date().getFullYear(),
chartData: {
month: {
xData: [], // 改为空数组,将从接口获取数据
seriesData: new Array(12).fill(0)
}
}
};
},
mounted() {
this.getData();
},
methods: {
getData() {
currentGET("big2").then((res) => {
console.log('big2',res);
if (res.code === 0) {
// 重置数组
this.chartData.month.seriesData = new Array(12).fill(0);
this.chartData.month.xData = []; // 重置x轴数据
//生成本年所有月份,填充数据的时候对已存在的月份再进行删除操作
this.generateMonths();
console.log('aa月度用氢量数据', this.chartData.month.seriesData);
// 按月份排序数据
const sortedData = res.data.sort((a, b) => {
const monthA = parseInt(a.months.substring(5, 7));
const monthB = parseInt(b.months.substring(5, 7));
return monthA - monthB;
});
console.log('sortedData: '+ sortedData);
// 填充数据
sortedData.forEach((item) => {
let monthStr = item.months; // 获取完整的月份字符串
console.log('月份:'+monthStr)
this.chartData.month.xData.pop(monthStr)
this.chartData.month.xData.push(monthStr); // 直接使用接口返回的月份字符串
let month = parseInt(monthStr.substring(5, 7));
if (month > 0 && month <= 12) {
this.chartData.month.seriesData[month-1] = item.monthHydrogen || 0;
}
});
console.log('月度用氢量数据:', this.chartData.month.seriesData);
console.log('月份数据:', this.chartData.month.xData);
this.$nextTick(() => {
this.initChart();
});
}
});
},
generateMonths() {
this.chartData.month.xData = Array.from({ length: 12 }, (_, i) => {
return `${this.currentYear}-${(i + 1).toString().padStart(2, '0')}`
})
},
switchTab(tab) {
this.currentTab = tab;
this.$nextTick(() => {
this.initChart();
});
},
initChart() {
if (this.chart) {
this.chart.dispose();
}
this.chart = echarts.init(this.$refs.chart);
const { xData, seriesData } = this.chartData[this.currentTab];
const option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: (params) => {
console.log(params)
return `用氢量:${params[0].value}kg`;
}
},
grid: {
left: '3%',
right: '4%',
top: '5%',
bottom: '15%',
containLabel: true
},
xAxis: {
type: 'category',
data: xData,
axisLabel: {
color: 'white',
interval: 0,
rotate: 45, // 保持倾斜以防文字重叠
fontSize: 12,
},
axisLine: {
lineStyle: {
color: 'white'
}
}
},
yAxis: {
type: 'value',
name: '用氢量',
axisLabel: {
color: 'white',
formatter: '{value}kg'
},
splitLine: {
lineStyle: {
color: 'rgba(51, 153, 255, 0.3)'
}
},
axisLine: {
lineStyle: {
color: 'white'
}
}
},
series: [{
name: '月度用氢量',
data: seriesData,
type: 'bar',
barWidth: 16,
barCategoryGap: '30%',
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: '#6a99f8'
}, {
offset: 1,
color: '#0b2149'
}])
},
label: {
show: true,
position: 'top',
color: '#fff',
formatter: (params) => {
return params.value === 0 ? '' : params.value+'kg';
}
}
}]
};
this.chart.setOption(option);
}
},
beforeDestroy() {
if (this.chart) {
this.chart.dispose();
this.chart = null;
}
}
};
</script>
<style scoped>
.chart-container {
position: relative;
}
.tabs {
position: absolute;
top: -10px;
left: 10px;
z-index: 10;
}
button {
background: rgba(25, 61, 112, 0.8);
border: 1px solid #2f6ed4;
color: #fff;
padding: 5px 15px;
margin-right: 10px;
cursor: pointer;
border-radius: 3px;
}
button.active {
background: #2f6ed4;
border-color: #4a8df8;
}
</style>

View File

@@ -0,0 +1,167 @@
<template>
<div class="chart-container">
<div class="tabs">
<button
:class="{ active: currentTab === 'month' }"
@click="switchTab('month')"></button>
<button
:class="{ active: currentTab === 'quarter' }"
@click="switchTab('quarter')"></button>
<button
:class="{ active: currentTab === 'year' }"
@click="switchTab('year')"></button>
</div>
<div ref="chart" style="width: 520px; height: 300px;"></div>
</div>
</template>
<script>
import * as echarts from 'echarts';
import { currentGET } from "api/modules";
export default {
name: 'BarChart',
// 修改数据结构和series配置
data() {
return {
currentTab: 'month',
chartData: {
month: {
xData: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
seriesData:[],
},
quarter: {
xData: ['一季度', '二季度', '三季度', '四季度'],
seriesData: [
]
},
year: {
xData: ['2022', '2023', '2024', '2025', '2026'],
seriesData: [
]
}
}
};
},
mounted() {
this.getData();
},
methods: {
getData() {
currentGET("big11").then((res) => {
console.log(res);
if (res.code === 0) {
// this.chartData.month.seriesData = res.data.monthList
res.data.monthList.forEach((item, index) => {
let month = parseInt(item.months);
this.chartData.month.seriesData[month-1] = item;
})
// this.chartData.quarter.seriesData = res.data.quarterList;
res.data.quarterList.forEach((item, index) => {
let quarter = parseInt(item.quarters);
this.chartData.quarter.seriesData[quarter-1] = item;
})
// this.chartData.year.seriesData = res.data.yearList;
res.data.yearList.forEach((item, index) => {
let year = parseInt(item.years);
this.chartData.year.seriesData[year-2022] = item;
})
console.log('==========',this.chartData.year.seriesData);
this.$nextTick(() => {
this.initChart();
});
}
});
},
switchTab(tab) {
this.currentTab = tab;
this.$nextTick(() => {
this.initChart();
});
},
initChart() {
const myChart = echarts.init(this.$refs.chart);
const { xData, seriesData } = this.chartData[this.currentTab];
// 在option配置中添加tooltip格式化
const option = {
tooltip: {
trigger: 'item',
formatter: (params) => {
const dataItem = seriesData[params.dataIndex];
let tip = `${params.name}<br>总数: ${params.value}`;
for (const [code, count] of Object.entries(dataItem.faultCodes)) {
tip += `<br>${code}: ${count}`;
}
return tip;
}
},
grid: {
left: '0%',
right: '4%',
top: '20%',
bottom: '15%',
containLabel: true
},
xAxis: {
type: 'category',
data: xData,
axisLabel: { color: 'white' }
},
yAxis: {
type: 'value',
axisLabel: {
color: 'white'
},
splitLine: {
lineStyle: {
color: '#3399FF'
}
}
},
series: [{
data: seriesData.map(item => item.total), // 保持数值部分
type: 'bar',
barWidth: this.currentTab === 'month' ? 16 : 28, // 微调月份柱宽到16px
barCategoryGap: '-5%', // 间距从15%减少到10%
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0, color: '#6a99f8'
}, {
offset: 1, color: '#0b2149'
}])
}
}]
};
myChart.setOption(option);
}
}
};
</script>
<style scoped>
.chart-container {
position: relative;
}
.tabs {
position: absolute;
top: -10px;
left: 10px;
z-index: 10;
}
button {
background: rgba(25, 61, 112, 0.8);
border: 1px solid #2f6ed4;
color: #fff;
padding: 5px 15px;
margin-right: 10px;
cursor: pointer;
border-radius: 3px;
}
button.active {
background: #2f6ed4;
border-color: #4a8df8;
}
</style>

View File

@@ -0,0 +1,242 @@
<template>
<!-- <transition name="yh-setting-fade"> -->
<div class="table-container">
<table @click="tableClick">
<thead>
<tr>
<th style="width:24%">车牌号</th>
<th style="width:19%">当前总里程</th>
<th style="width:19%">当日里程</th>
<th style="width:19%">当日用氢量</th>
<th style="width:19%">当日碳减排</th>
</tr>
</thead>
</table>
<div class="scroll-wrapper">
<vue-seamless-scroll :data="tableData" :class-option="scrollOptions" class="scroll-container">
<table @click="tableClick">
<tbody>
<tr v-for="(item, index) in tableData" :key="index">
<td style="width:24%">{{ item.plateNumber }}</td>
<td style="width:19%">{{ item.totalMileage }}km</td>
<td style="width:19%">{{ item.dayMileage }}km</td>
<td style="width:19%">{{ item.dayHydrogen }}kg</td>
<td style="width:19%">{{ item.dayCarbon }}kg</td>
</tr>
</tbody>
</table>
</vue-seamless-scroll>
</div>
<div class="dialog-container" >
<!-- :body-style="{ maxHeight: 'calc(100vh - 510px)', overflow: 'auto' }" -->
<el-dialog title="车辆当日信息" :visible.sync="setVehicleDialog" class="dialog_el" height="400px" width="803px" center
:lock-scroll="false"
:append-to-body="true"
:modal-append-to-body="true"
>
<!-- width="100%" class="dialog-table" -->
<div class="dialog-body-wrapper">
<el-table :data="tableData" border class="vehicleTable" height="600px" width="800px" :default-sort="{prop: 'totalMileage', order: 'descending'}">
<el-table-column type="index" prop="tableIndex" label="序号" width="80px"></el-table-column>
<el-table-column prop="plateNumber" label="车牌号" width="120px" sortable></el-table-column>
<el-table-column prop="totalMileage" label="当前总里程" width="140px" :formatter="formatMileageKm" sortable></el-table-column>
<el-table-column prop="dayMileage" label="当日里程" width="130px" :formatter="formatMileageKm" sortable></el-table-column>
<el-table-column prop="dayHydrogen" label="当日用氢量" width="140px" :formatter="formatHydrogenKg" sortable></el-table-column>
<el-table-column prop="dayCarbon" label="当日碳减排" width="140px" :formatter="formatHydrogenKg" sortable></el-table-column>
</el-table>
</div>
<span slot="footer" class="dialog-footer">
<el-button class="closeButton" type="primary" size="small" @click="closeDialog">关闭</el-button>
</span>
</el-dialog>
</div>
</div>
<!-- </transition> -->
</template>
<script>
import Vue from 'vue'
import vueSeamlessScroll from "vue-seamless-scroll";
import { currentGET } from 'api/modules'
import { Dialog,Table, TableColumn } from 'element-ui'
import 'element-ui/lib/theme-chalk/table.css'
import 'element-ui/lib/theme-chalk/table-column.css'
Vue.component('el-dialog', Dialog)
Vue.use(Table)
Vue.use(TableColumn)
export default {
components: { vueSeamlessScroll },
data() {
return {
scrollOptions: {
step: 0.3, // 滚动速度
limitMoveNum: 3, // 限制单步滚动的条数
hoverStop: true, // 鼠标悬停是否暂停
direction: 1, // 方向1向上滚动
singleHeight: 50, // 单行高度,用于精确控制滚动
waitTime: 2000, // 等待时间,滚动间隔
},
tableData: [],
setVehicleDialog:false,
};
},
mounted() {
this.getExchangeData();
},
methods: {
tableClick(){
console.log('tableClick')
this.setVehicleDialog = true;
},
closeDialog(){
this.setVehicleDialog = false;
},
getExchangeData() {
currentGET("big13").then(res => {
console.log("当日汇总数据:");
console.log(res.data);
this.tableData = res.data;
// 限制最多显示20条数据
//this.tableData = res.data.slice(0, 20);
});
},
formatMileageKm(row, column, cellValue, index){
if(row.nodeName === null)
return '0km';
else
return cellValue + 'km';
},
formatHydrogenKg(row, column, cellValue, index) {
if(row.nodeName === null)
return '0kg';
else
return cellValue + 'kg';
},
},
};
</script>
<style scoped>
.table-container {
width: 100%;
border-radius: 5px;
overflow: hidden;
padding-top: 10px; /* 添加顶部内边距 */
}
table {
width: 100%;
border-collapse: collapse;
text-align: center; /* 修改为居中对齐 */
}
th {
padding: 10px 12px;
color:white;
font-size: 14px;
width: 20%;
text-align: center; /* 确保单元格内容居中 */
height: 50px; /* 固定行高,与数据行保持一致 */
box-sizing: border-box;
}
td {
padding: 10px 12px;
color:rgb(0, 255, 204);
font-size: 14px;
width: 20%;
text-align: center; /* 确保单元格内容居中 */
}
thead {
background: #013f6a;
padding: 10%;
}
.dialog_el >>> .el-dialog__body {
/* //border-top: 1px solid #dcdfe6;
//border-bottom: 1px solid #dcdfe6; */
max-height: 60vh !important;
min-height: 100px;
overflow-y: hidden;
/* background: #013f6a; */
}
.vehicleTable{
/* width: 100%; */
text-align: center; /* 确保单元格内容居中 */
}
.vehicleTable >>> th {
padding: 12px;
font-size: 14px;
/* width: 20%; */
text-align: center; /* 确保单元格内容居中 */
}
.vehicleTable >>> td{
text-align: center; /* 确保单元格内容居中 */
}
.closeButton{
color: gray;
background-color: #013f6a;
}
/* 内容容器滚动设置 */
.dialog-body-wrapper {
padding: 1px 1px;
height: 100%;
overflow-y: auto;
/* width: 100%; */
}
.dialog-container {
width: 300px;
height: 0px; /* 适配大屏,数据较多可增加高度 */
overflow: hidden;
background-color: #031a47;
border-radius: 8px;
}
.dialog_el .el-table {
background-color: transparent !important;
/* width: 100%; */
/* back */
}
/* .dialog-table{
background-color: #031a47;
} */
/* .dialog-table {
// background: linear-gradient(135deg, #031a47 0%, #e4e8ed 100%);
background-color: #013f6a;
// text-align: center;
} */
/* .dialog-table th {
background-color: #011946 !important;
color: white;
}
.dialog-table td {
background-color: rgba(255,255,255,0.8);
} */
.scroll-wrapper {
height: 550px; /*适配大屏,数据较多可增加高度 */
overflow: hidden;
}
.scroll-container table {
width: 100%;
}
tr {
border-bottom: 1px solid #0a2a4a;
}
tr:nth-child(even) {
background: rgba(255, 255, 255, 0.05);
}
</style>

View File

@@ -0,0 +1,114 @@
<template>
<div class="table-container">
<table>
<thead>
<tr>
<th>车牌号</th>
<th>当前总里程</th>
<th>当月用氢量</th>
<th>当月行驶里程</th>
<th>当月碳排放</th>
</tr>
</thead>
</table>
<div class="scroll-wrapper">
<vue-seamless-scroll :data="tableData" :class-option="scrollOptions" class="scroll-container">
<table>
<tbody>
<tr v-for="(item, index) in tableData" :key="index">
<td>{{ item.plateNumber }}</td>
<td>{{ item.totalMileage }}km</td>
<td>{{ item.dayHydrogen }}kg</td>
<td>{{ item.dayMileage }}km</td>
<td>{{ item.dayCarbon }}kg</td>
</tr>
</tbody>
</table>
</vue-seamless-scroll>
</div>
</div>
</template>
<script>
import vueSeamlessScroll from "vue-seamless-scroll";
import { currentGET } from 'api/modules'
export default {
components: { vueSeamlessScroll },
data() {
return {
scrollOptions: {
step: 0.3, // 滚动速度
limitMoveNum: 5, // 限制单步滚动的条数
hoverStop: true, // 鼠标悬停是否暂停
direction: 1, // 方向1向上滚动
},
tableData: [],
};
},
mounted() {
this.getExchangeData();
},
methods: {
getExchangeData() {
currentGET("big12").then(res => {
console.log("当月汇总数据:");
console.log(res.data);
this.tableData = res.data;
});
},
},
};
</script>
<style scoped>
.table-container {
width: 100%;
border-radius: 5px;
overflow: hidden;
padding-top: 10px; /* 添加顶部内边距 */
}
table {
width: 100%;
border-collapse: collapse;
text-align: center; /* 修改为居中对齐 */
}
th {
padding: 12px;
color:white;
font-size: 14px;
width: 20%;
text-align: center; /* 确保单元格内容居中 */
}
td {
padding: 12px;
color:rgb(0, 255, 204);
font-size: 14px;
width: 20%;
text-align: center; /* 确保单元格内容居中 */
}
thead {
background: #013f6a;
padding: 10%;
}
.scroll-wrapper {
height: 250px; /* 适配大屏,数据较多可增加高度 */
overflow: hidden;
}
.scroll-container table {
width: 100%;
}
tr {
border-bottom: 1px solid #0a2a4a;
}
tr:nth-child(even) {
background: rgba(255, 255, 255, 0.05);
}
</style>

View File

@@ -0,0 +1,245 @@
<template>
<div class="chart-container">
<div ref="chart" style="width: 520px; height: 280px;margin-top: 0%;"></div>
</div>
</template>
<script>
import * as echarts from 'echarts';
import { currentGET } from "api/modules";
export default {
name: 'DoubleAxisChart',
mounted() {
this.getData();
// 初始化时设置标题
this.$emit('update-title', '月度用氢量');
},
beforeDestroy() {
if (this.intervalId) {
clearInterval(this.intervalId);
}
// Cleanup chart instance
if (this.chart) {
this.chart.dispose();
this.chart = null;
}
},
data() {
return {
dailyHydrogen: [],
dailyCarbon: [],
dailyMileage: [],
XAxisData: [],
seriesData: [],
currentChartIndex: 0,
intervalId: null,
currentMonth: new Date().getMonth() + 1,
currentYear: new Date().getFullYear(),
chart: null
};
},
methods: {
updateParentTitle(title) {
this.$emit('update-title', title)
},
getDaysInMonth(year, month) {
return new Date(year, month, 0).getDate();
},
generateDaysArray() {
const daysInMonth = this.getDaysInMonth(this.currentYear, this.currentMonth);
return Array.from({length: daysInMonth}, (_, i) => `${this.currentMonth}${i+1}`);
},
getData() {
this.XAxisData = this.generateDaysArray();
const daysInMonth = this.getDaysInMonth(this.currentYear, this.currentMonth);
this.dailyHydrogen = new Array(daysInMonth).fill(0);
this.dailyCarbon = new Array(daysInMonth).fill(0);
this.dailyMileage = new Array(daysInMonth).fill(0);
const formattedMonth = `${this.currentYear}-${String(this.currentMonth).padStart(2, '0')}`;
currentGET("big12").then((res) => {
console.log('每日数据');
this.monthItems = res.data;
console.log(this.monthItems);
this.monthItems.forEach((item) => {
const day = parseInt(item.dates.substring(8, 10));
if (day > 0 && day <= daysInMonth) {
this.dailyHydrogen[day - 1] = item.dayHydrogen;
this.dailyCarbon[day - 1] = item.dayCarbon;
this.dailyMileage[day - 1] = item.dayMileage || 0;
}
});
console.log('用氢量:', this.dailyHydrogen);
console.log('碳排放:', this.dailyCarbon);
console.log('行驶里程:', this.dailyMileage);
this.initChart();
this.intervalId = setInterval(this.switchChart, 5000);
});
},
switchChart() {
this.currentChartIndex = (this.currentChartIndex + 1) % 3;
const titles = ['日用氢量', '日碳排放量', '日行驶里程'];
this.$emit('update-title', titles[this.currentChartIndex]);
console.log('切换图表', titles[this.currentChartIndex]);
this.initChart();
},
initChart() {
const chartDom = this.$refs.chart;
if (this.chart) {
this.chart.dispose();
}
this.chart = echarts.init(chartDom);
let legendData = [];
let seriesName = '';
let seriesColor = '';
let areaColor = '';
if (this.currentChartIndex === 0) {
legendData = ['用氢量'];
this.seriesData = this.dailyHydrogen;
seriesName = '用氢量';
seriesColor = 'orange';
areaColor = 'orange';
} else if (this.currentChartIndex === 1) {
legendData = ['碳排放'];
this.seriesData = this.dailyCarbon;
seriesName = '碳排放';
seriesColor = 'green';
areaColor = 'green';
} else {
legendData = ['行驶里程'];
this.seriesData = this.dailyMileage;
seriesName = '行驶里程';
seriesColor = '#1890ff';
areaColor = '#1890ff';
}
const option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
legend: {
data: legendData,
left: 'right',
icon: 'line',
itemWidth: 30,
itemHeight: .0,
itemGap: 10,
textStyle: {
color: 'white',
fontSize: 16,
fontWeight: 'normal',
fontFamily: 'Arial, sans-serif'
}
},
grid: {
left: '3%',
right: '4%',
top: '10%',
bottom: '10%',
containLabel: true
},
xAxis: [
{
type: 'category',
boundaryGap: false,
data: this.XAxisData,
axisLine: {
lineStyle: {
color: 'white',
width: 1
}
},
axisTick: {
show: true,
alignWithLabel: true,
lineStyle: {
color: 'white'
}
},
axisLabel: {
color: 'white',
fontSize: 12,
interval: 1,
rotate: 45
}
}
],
yAxis: [
{
type: 'value',
name: '',
offset: 10,
axisLine: {
lineStyle: {
color: 'white'
}
},
splitLine: { lineStyle: { color: '#081b42' } },
axisLabel: {
formatter: '{value}',
align: 'right',
padding: [0, 5, 0, 0]
}
},
{
type: 'value',
name: '',
axisLine: {
lineStyle: {
color: 'white'
}
},
splitLine: { lineStyle: { color: '#081b42' } },
axisLabel: {
formatter: '{value}'
}
}
],
series: [
{
name: seriesName,
type: 'line',
stack: '总量',
areaStyle: {color: areaColor},
emphasis: {
focus: 'series'
},
data: this.seriesData,
lineStyle: {
color: seriesColor,
width: 2,
},
label: {
show: true,
position: 'top',
color: '#fff',
fontSize: 12,
formatter: (params) => {
return params.value === 0 ? '' : params.value;
},
textShadowBlur: 10,
textShadowColor: 'rgba(0,0,0,0.5)'
}
}
]
};
this.chart.setOption(option);
}
}
};
</script>
<style scoped>
.chart-container {
position: relative;
border: 1px solid red; /* 添加边框用于调试 */
}
</style>

128
src/views/setting.vue Normal file
View File

@@ -0,0 +1,128 @@
<template>
<transition name="yh-setting-fade">
<div class="setting" :class="{ settingShow: settingShow }" v-show="settingShow">
<div class="setting_dislog" @click="settingShow = false">
</div>
<div class="setting_inner">
<div class="setting_header">
设置
</div>
<div class="setting_body">
<!-- <div class="left_shu"> 实时监测</div> -->
<div class="left_shu"> 全局设置</div>
<div class="setting_item">
<span class="setting_label">
是否进行自动适配<span class="setting_label_tip">(默认分辨率1920*1080)</span>:
</span>
<div class="setting_content">
<el-radio-group v-model="isScaleradio" @change="(val) => radiochange(val, 'isScale')">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
</div>
</div>
<div class="left_shu"> 全屏设置</div>
<div class="setting_item">
<!-- <span class="setting_label">全屏显示:</span> -->
<div class="setting_content">
<!-- <el-button type="primary" round size="mini" @click="toggleFullScreen">全屏</el-button> -->
<el-radio-group v-model="sbtxradio" @change="(val) => radiochange(val, 'isFullScreen')">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
</div>
</div>
<!-- <div class="left_shu"> 实时监测</div>
<div class="setting_item">
<span class="setting_label">
设备提醒自动轮询: <span class="setting_label_tip"></span>
</span>
<div class="setting_content">
<el-radio-group v-model="sbtxradio" @change="(val) => radiochange(val, 'sbtxSwiper')">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
</div>
</div>
<div class="setting_item">
<span class="setting_label">
实时预警轮播:
</span>
<div class="setting_content">
<el-radio-group v-model="ssyjradio" @change="(val) => radiochange(val, 'ssyjSwiper')">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
</div>
</div> -->
<div class="flex justify-center">
<!-- <el-button type="primary" round size="mini">确定</el-button> -->
</div>
</div>
</div>
</div>
</transition>
</template>
<script>
export default {
components: {},
data() {
return {
settingShow: false,
sbtxradio:true,
ssyjradio: true,
isScaleradio:true,
isFullScreen: false,
};
},
computed: {},
methods: {
init() {
this.settingShow = true
},
radiochange(val, type) {
this.$store.commit('setting/updateSwiper', { val, type })
if(type==='isFullScreen'){
this.toggleFullScreen()
}
},
toggleFullScreen() {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen().catch(err => {
console.error(`Error attempting to enable full-screen mode: ${err.message} (${err.name})`);
});
this.isFullScreen = true;
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
}
this.isFullScreen = false;
}
},
},
created() {
this.$store.commit('setting/initSwipers')
this.sbtxradio = this.$store.state.setting.sbtxSwiper,
this.ssyjradio = this.$store.state.setting.ssyjSwiper,
this.isScaleradio = this.$store.state.setting.isScale;
},
mounted() {
document.body.appendChild(this.$el);
},
beforeDestroy() {
},
destroyed() {
if (this.$el && this.$el.parentNode) {
this.$el.parentNode.removeChild(this.$el);
}
}
}
</script>
<style lang='scss' scoped>
</style>

171
src/views/test/testMap.vue Normal file
View File

@@ -0,0 +1,171 @@
<template>
<div class="map" id="map"></div>
</template>
<script>
import * as echarts from "echarts";
import jilin from "./json/jilin.json";
export default {
data() {
return {
weatherMap: {
// "qing": require('@/assets/tq__1.jpg'),
// "qingZhuanDuoyun": require('@/assets/tq__2.jpg'),
// "zhongyu": require('@/assets/tq__3.jpg'),
// "qingZhuanZhongyu": require('@/assets/tq__4.jpg'),
// "zhongxue": require('@/assets/tq__5.jpg'),
// "leidian": require('@/assets/tq__6.jpg'),
// "yin": require('@/assets/tq__7.jpg'),
// "daxue": require('@/assets/tq__8.jpg'),
// "qingZhuanYin": require('@/assets/tq__9.jpg'),
},
testData: [
{
name: '长春市',
value: 'qing',
min: '10',
max: '20',
weather: '晴'
},
{
name: '吉林市',
value: 'qingZhuanDuoyun',
min: '11',
max: '15',
weather: '晴转多云'
},
{
name: '通化市',
value: 'zhongyu',
min: '8',
max: '12',
weather: '中雨'
},
{
name: '四平市',
value: 'qingZhuanZhongyu',
min: '9',
max: '19',
weather: '晴转中雨'
},
{
name: '白山市',
value: 'zhongxue',
min: '-15',
max: '-5',
weather: '中雪'
},
{
name: '辽源市',
value: 'leidian',
min: '13',
max: '17',
weather: '雷电'
},
{
name: '白城市',
value: 'yin',
min: '4',
max: '7',
weather: '阴'
},
{
name: '延边朝鲜族自治州',
value: 'daxue',
min: '-22',
max: '-12',
weather: '大雪'
},
{
name: '松原市',
value: 'qingZhuanYin',
min: '10',
max: '20',
weather: '晴转多云'
}
]
};
},
created() {
},
mounted() {
this.drawMap()
},
methods: {
drawMap() {
// 判断地图是否渲染
let myChart = echarts.getInstanceByDom(document.getElementById("map"))
// 如果渲染则清空地图
if (myChart != null) {
myChart.dispose()
}
// 初始化地图
myChart = echarts.init(document.getElementById("map"));
echarts.registerMap("jilin", jilin)
let rich = {
max: {
color: '#fff',
backgroundColor: '#E6A23C',
width: 44,
height: 26,
},
min: {
color: '#fff',
backgroundColor: '#67C23A',
width: 44,
height: 26,
},
name: {
color: '#F56C6C',
height: 32
},
}
const weatherMap = this.weatherMap
let tempData = this.testData
tempData.forEach(item => {
item.weatherImg = weatherMap[item.value]
rich[item.value] = {
height: 26,
width: 26,
backgroundColor: {
image: weatherMap[item.value]
}
}
})
var option = {
series: [
{
type: 'map',
zoom: 1.2,
map: 'jilin',
label: {
show: true,
formatter: function (params) {
return `{${params.data.value}|} {min|${params.data.min}℃} {max|${params.data.max}℃}\n{name|${params.name}}`
},
rich: rich
},
data: tempData
},
]
}
myChart.setOption(option)
},
},
}
</script>
<style scoped>
.map {
width: 800px;
height: 600px;
position: relative;
}
</style>

37
src/views/tjfx/tjfx.vue Normal file
View File

@@ -0,0 +1,37 @@
<!--
* @Author: szy
* @Date: 2022-03-04 09:52:25
* @LastEditors: szy
* @LastEditTime: 2022-03-04 11:03:40
* @FilePath: \web-pc\src\pages\big-screen\view\tjfx\tjfx.vue
-->
<template>
<div>
</div>
</template>
<script>
export default {
data() {
return {
}
},
created(){
},
mounted() {
},
methods: {
},
}
</script>
<style lang='scss' scoped>
</style>