Browse Source

交能切换

develop
gaoguangchao 3 weeks ago
parent
commit
48e7814398
  1. BIN
      ruoyi-ui/src/assets/images/carbon/active.png
  2. BIN
      ruoyi-ui/src/assets/images/carbon/btn_active.png
  3. BIN
      ruoyi-ui/src/assets/images/carbon/btn_normal.png
  4. BIN
      ruoyi-ui/src/assets/images/carbon/data_bg1.png
  5. BIN
      ruoyi-ui/src/assets/images/carbon/data_bg2.png
  6. BIN
      ruoyi-ui/src/assets/images/carbon/head_logo.png
  7. BIN
      ruoyi-ui/src/assets/images/carbon/head_out.png
  8. BIN
      ruoyi-ui/src/assets/images/carbon/head_setting.png
  9. BIN
      ruoyi-ui/src/assets/images/carbon/head_title.png
  10. BIN
      ruoyi-ui/src/assets/images/carbon/head_user.png
  11. BIN
      ruoyi-ui/src/assets/images/carbon/header_bg.png
  12. BIN
      ruoyi-ui/src/assets/images/carbon/icon_gf.png
  13. BIN
      ruoyi-ui/src/assets/images/carbon/item_title.png
  14. BIN
      ruoyi-ui/src/assets/images/carbon/tb_row_bg.png
  15. 76
      ruoyi-ui/src/views/JiHeExpressway/components/FormConfig/components/RadioGroup/RadioCustom1.vue
  16. 12
      ruoyi-ui/src/views/JiHeExpressway/components/FormConfig/components/RadioGroup/index.vue
  17. 2
      ruoyi-ui/src/views/JiHeExpressway/components/HeaderMenu/index.vue
  18. 589
      ruoyi-ui/src/views/JiHeExpressway/pages/Home/carbon.vue
  19. 67
      ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/carbon/btn/index.vue
  20. 83
      ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/carbon/contentItem/index.vue
  21. 346
      ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/carbon/echarts/RingChart.vue
  22. 271
      ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/carbon/echarts/SortBarChart.vue
  23. 192
      ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/carbon/echarts/SplitBarChart.vue
  24. 264
      ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/carbon/echarts/lineCharts.vue
  25. 56
      ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/carbon/echarts/mixins/resize.js
  26. 1954
      ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/carbon/echarts/realData.js
  27. 31
      ruoyi-ui/src/views/JiHeExpressway/pages/Home/index.vue

BIN
ruoyi-ui/src/assets/images/carbon/active.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
ruoyi-ui/src/assets/images/carbon/btn_active.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

BIN
ruoyi-ui/src/assets/images/carbon/btn_normal.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 617 B

BIN
ruoyi-ui/src/assets/images/carbon/data_bg1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

BIN
ruoyi-ui/src/assets/images/carbon/data_bg2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
ruoyi-ui/src/assets/images/carbon/head_logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
ruoyi-ui/src/assets/images/carbon/head_out.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

BIN
ruoyi-ui/src/assets/images/carbon/head_setting.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 B

BIN
ruoyi-ui/src/assets/images/carbon/head_title.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
ruoyi-ui/src/assets/images/carbon/head_user.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 437 B

BIN
ruoyi-ui/src/assets/images/carbon/header_bg.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
ruoyi-ui/src/assets/images/carbon/icon_gf.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
ruoyi-ui/src/assets/images/carbon/item_title.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
ruoyi-ui/src/assets/images/carbon/tb_row_bg.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

76
ruoyi-ui/src/views/JiHeExpressway/components/FormConfig/components/RadioGroup/RadioCustom1.vue

@ -0,0 +1,76 @@
<template>
<el-radio-button v-bind="getBind" v-on="$listeners" :style="{ '--active-color': activeColor }" class="custom1">
<slot />
</el-radio-button>
</template>
<script>
export default {
name: 'RadioCustom1',
props: {
activeColor: {
type: String,
default: "linear-gradient(180deg, #FF6969 0%, #FFB904 100%)"
}
},
computed: {
getBind() {
return {
border: true,
...this.$attrs
}
}
}
}
</script>
<style lang='scss' scoped>
label.custom1.el-radio-button {
margin: 0;
height: 27px;
&:first-child {
::v-deep {
span.el-radio-button__inner {
border-radius: 0;
border-left: 1px solid #00B3CC;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}
}
}
&.is-active {
::v-deep {
span.el-radio-button__inner {
background: var(--active-color);
}
}
}
&:last-child {
::v-deep {
span.el-radio-button__inner {
border-radius: 0;
border-right: 1px solid #00B3CC;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
}
}
::v-deep {
span.el-radio-button__inner {
border: 0;
border-radius: 0;
border-top: 1px solid #00B3CC;
border-bottom: 1px solid #00B3CC;
font-size: 14px;
font-family: PingFang SC, PingFang SC;
font-weight: 400;
color: #FFFFFF;
}
}
}
</style>

12
ruoyi-ui/src/views/JiHeExpressway/components/FormConfig/components/RadioGroup/index.vue

@ -1,6 +1,7 @@
<template> <template>
<ElRadioGroup class='RadioGroup' v-bind="$attrs" v-on="$listeners"> <ElRadioGroup class='RadioGroup' v-bind="$attrs" v-on="$listeners">
<component :activeColor="activeColor" :is="getComponents()" v-for="item in options" :key="item.key" :label="item.key"> <component :activeColor="activeColor" :is="getComponents()" v-for="item in options" :key="item.key"
:label="item.key">
{{ item.label }} {{ item.label }}
</component> </component>
</ElRadioGroup> </ElRadioGroup>
@ -10,13 +11,15 @@
import Radio from "./Radio.vue" import Radio from "./Radio.vue"
import RadioButton from "./RadioButton.vue" import RadioButton from "./RadioButton.vue"
import RadioCircle from "./RadioCircle.vue" import RadioCircle from "./RadioCircle.vue"
import RadioCustom1 from "./RadioCustom1.vue"
export default { export default {
name: 'RadioGroup', name: 'RadioGroup',
components: { components: {
Radio, Radio,
RadioButton, RadioButton,
RadioCircle RadioCircle,
RadioCustom1
}, },
props: { props: {
type: { type: {
@ -45,6 +48,8 @@ export default {
return 'RadioButton'; return 'RadioButton';
case "circle": case "circle":
return 'RadioCircle'; return 'RadioCircle';
case "custom1":
return 'RadioCustom1';
default: default:
return 'Radio' return 'Radio'
} }
@ -54,5 +59,6 @@ export default {
</script> </script>
<style lang='scss' scoped> <style lang='scss' scoped>
.RadioGroup {} .RadioGroup {
}
</style> </style>

2
ruoyi-ui/src/views/JiHeExpressway/components/HeaderMenu/index.vue

@ -106,7 +106,7 @@ export default {
} }
} }
if(index < 4){ if(index < 4){
_menuLeft.push(menuItem) _menuLeft.push(menuItem)
} else { } else {
_menuRight.push(menuItem) _menuRight.push(menuItem)
} }

589
ruoyi-ui/src/views/JiHeExpressway/pages/Home/carbon.vue

@ -0,0 +1,589 @@
<template>
<div class="screen-content">
<div class="content-left">
<content-item name="资产概览" class="custom-height">
<el-row class="zcgl-box">
<el-col v-for="(item,index) in zcglData" class="zcgl-item">
<span>
<span class="zcgl-num" :style="{'color':item.color}">{{item.num}}</span>
<span class="zcgl-unit">{{item.unit}}</span>
</span>
<div class="zcgl-name">{{item.name}}</div>
</el-col>
</el-row>
</content-item>
<content-item name="能量分布">
<div class="zdtp-top">
<div class="zdtp-tj">
<span class="name">已检测到排放源类别</span>
<span class="num">76</span>
</div>
<span class="unit">单位tCO</span>
</div>
<ring-chart></ring-chart>
</content-item>
<content-item name="清洁能源发电" >
<div class="scope-box">
<span class="unit">单位tCO</span>
<div class="scope">
<div class="scope-label">
<span class="name" >直接碳排放</span>
<span class="pf-num">{{ scope.zjpf }}</span>
</div>
<div class="pf" :style="{width:scope.zjpf/(scope.zjpf+scope.zjjp)*100 +'%'}"></div>
<div class="jp" :style="{width:scope.zjjp/(scope.zjpf+scope.zjjp)*100 +'%'}"></div>
<div class="scope-label">
<span class="name">直接碳减排</span>
<span class="jp-num">{{ scope.zjjp }}</span>
</div>
</div>
<div class="tzh">
<span class="zh-text">碳中和</span>
<div class="zh-line"></div>
</div>
<div class="scope">
<div class="scope-label">
<span class="name" >间接碳排放</span>
<span class="pf-num">{{ scope.jjpf }}</span>
</div>
<div class="pf" :style="{width:scope.jjpf/(scope.jjpf+scope.jjjp)*100 +'%'}"></div>
<div class="jp" :style="{width:scope.jjjp/(scope.jjpf+scope.jjjp)*100 +'%'}"></div>
<div class="scope-label">
<span class="name">间接碳减排</span>
<span class="jp-num">{{scope.jjjp}}</span>
</div>
</div>
</div>
</content-item>
<content-item name="能耗排名">
<div class="btn-box">
<btn name="日报" @click.native="btnClick('day')" :active="active==='day'"></btn>
<btn name="月报" @click.native="btnClick('month')" :active="active==='month'"></btn>
<btn name="年报" @click.native="btnClick('year')" :active="active==='year'"></btn>
</div>
<sort-bar-chart></sort-bar-chart>
</content-item>
</div>
<div class="content-right">
<content-item name="社会贡献">
<div class="shgx-box">
<el-row class="row">
<el-col class="col" :span="12">
<img src="../../../../assets/images/carbon/icon_gf.png" alt=""/>
<div class="tj">
<span class="num">3452</span>
<span class="unit ml5">万吨</span>
<div class="name">累计节约标准煤</div>
</div>
</el-col>
<el-col class="col" :span="12">
<img src="../../../../assets/images/carbon/icon_gf.png" alt=""/>
<div class="tj">
<span class="num">3452</span>
<span class="unit ml5">万吨</span>
<div class="name">累计减排CO2</div>
</div>
</el-col>
</el-row>
<el-row class="row">
<el-col class="col" :span="12">
<img src="../../../../assets/images/carbon/icon_gf.png" alt=""/>
<div class="tj">
<span class="num">3452</span>
<span class="unit ml5">万吨</span>
<div class="name">累计减排SO2</div>
</div>
</el-col>
<el-col class="col" :span="12">
<img src="../../../../assets/images/carbon/icon_gf.png" alt=""/>
<div class="tj">
<span class="num">3452</span>
<span class="unit ml5">万吨</span>
<div class="name">累计减排NO2</div>
</div>
</el-col>
</el-row>
<el-row class="row">
<el-col class="col" :span="12">
<img src="../../../../assets/images/carbon/icon_gf.png" alt=""/>
<div class="tj">
<span class="num">3452</span>
<span class="unit ml5">万吨</span>
<div class="name">累计减排烟尘</div>
</div>
</el-col>
<el-col class="col" :span="12">
<img src="../../../../assets/images/carbon/icon_gf.png" alt=""/>
<div class="tj">
<span class="num">3452</span>
<span class="unit ml5">万棵</span>
<div class="name">等效植树量</div>
</div>
</el-col>
</el-row>
</div>
</content-item>
<content-item name="全域碳排放">
<div class="btn-box">
<btn name="日报" @click.native="btnClick('day')" :active="active==='day'"></btn>
<btn name="月报" @click.native="btnClick('month')" :active="active==='month'"></btn>
<btn name="年报" @click.native="btnClick('year')" :active="active==='year'"></btn>
</div>
<split-bar-chart :chart-data="tpfChartData"></split-bar-chart>
</content-item>
<content-item name="碳中和分析">
<div class="btn-box">
<btn name="日报" @click.native="btnClick('day')" :active="active==='day'"></btn>
<btn name="月报" @click.native="btnClick('month')" :active="active==='month'"></btn>
<btn name="年报" @click.native="btnClick('year')" :active="active==='year'"></btn>
</div>
<line-charts></line-charts>
</content-item>
<content-item name="碳排放强度排名">
<div class="btn-box">
<btn name="日报" @click.native="btnClick('day')" :active="active==='day'"></btn>
<btn name="月报" @click.native="btnClick('month')" :active="active==='month'"></btn>
<btn name="年报" @click.native="btnClick('year')" :active="active==='year'"></btn>
</div>
<sort-bar-chart></sort-bar-chart>
</content-item>
</div>
</div>
</template>
<script>
import ContentItem from './components/carbon/contentItem/index'
import lineCharts from "./components/carbon/echarts/lineCharts";
import SplitBarChart from "./components/carbon/echarts/SplitBarChart";
import btn from './components/carbon/btn/index'
import scroll from "vue-seamless-scroll";
import SortBarChart from "./components/carbon/echarts/SortBarChart";
import RingChart from "./components/carbon/echarts/RingChart";
export default {
name: "carbon",
components: {
ContentItem,
RingChart, lineCharts, btn, SplitBarChart, scroll, SortBarChart
},
data() {
return {
active:'day',
tpfChartData:{
xData:['1日','2日','3日','4日','5日','6日','7日','8日','9日','10日','11日'],
yData:{
name:'',
unit:'单位: tCO₂',
data:[54,55,465,465,584,321,365,51,321,32,31]
}
},
tableData:[
{
siteName:'大学城收费站',
happenTime:'2024-10-01 10:00:00',
warningContent:'碳排放异常',
dealStatus:0
},
{
siteName:'大学城收费站',
happenTime:'2024-10-01 10:00:00',
warningContent:'碳排放异常',
dealStatus:0
},
{
siteName:'大学城收费站',
happenTime:'2024-10-01 10:00:00',
warningContent:'碳排放异常',
dealStatus:1
},
{
siteName:'长清城收费站',
happenTime:'2024-10-01 10:00:00',
warningContent:'碳排放异常',
dealStatus:0
},
{
siteName:'长清收费站',
happenTime:'2024-10-01 10:00:00',
warningContent:'碳排放异常',
dealStatus:0
},
{
siteName:'长清收费站',
happenTime:'2024-10-01 10:00:00',
warningContent:'碳排放异常',
dealStatus:0
},
{
siteName:'长清收费站',
happenTime:'2024-10-01 10:00:00',
warningContent:'碳排放异常',
dealStatus:0
},
{
siteName:'孝里收费站',
happenTime:'2024-10-01 10:00:00',
warningContent:'碳排放异常',
dealStatus:0
},
],
zcglData:[
{
num:'3452',
unit:'MW',
name:'光伏装机容量',
color:'#00D1FF'
},
{
num:'3452',
unit:'MW',
name:'风电装机容量',
color:'#00D1FF'
},
{
num:'3452',
unit:'MWh',
name:'储能总容量',
color:'#00EBC1'
},
{
num:'3452',
unit:'台',
name:'充电桩数量',
color:'#FFDB82'
},
],
scope:{
zjpf:546,
zjjp:3698,
jjpf:2547,
jjjp:2354
}
}
},
computed: {
defaultOption() {
return {
step: 0.1, //
limitMoveNum: 5, // this.dataList.length
hoverStop: true, // stop
direction: 1, // 0 1 2 3
openWatch: true, // dom
singleHeight: 0, // (0) direction => 0/1
singleWidth: 0, // (0) direction => 2/3
waitTime: 3000, // (1000ms)
};
},
},
methods:{
btnClick(val) {
if (val) {
this.active = val
this.getEnergyAnalysisBySiteCode()
}
},
}
}
</script>
<style lang="scss" scoped>
.screen-content{
/*height: calc(100vh - 68px);
width: 100%;
padding-top: 15px;
position: relative;*/
height: 100%;
width: 100%;
display: flex;
//flex-direction: column;
justify-content: space-between;
}
.content-left,.content-right{
// position: absolute;
//top: 0;
z-index: 1;
width: 500px;
height: calc(100% - 4px);
display: flex;
flex-direction: column;
justify-content: space-around;
}
.content-left{
left: 0;
padding: 5px 0 0 20px;
background: linear-gradient(to right, rgba(20, 26, 41, 0.7), rgba(20, 26, 41, 0.5), rgba(20, 26, 41, 0));
align-items: start;
}
.content-right{
right: 0;
padding: 5px 20px 0 0;
background: linear-gradient(to left, rgba(20, 26, 41, 0.7), rgba(20, 26, 41, 0.5), rgba(20, 26, 41, 0));
float: right;
align-items: end;
}
.btn-box{
position: absolute;
display: flex;
z-index: 2;
}
.my-table{
margin-top: 9px;
height: 91%;
overflow: hidden;
width: 100%;
.table-header{
width: 100%;
height: 22px;
display: flex;
margin-bottom: 4px;
background:#006E91;
justify-content: space-between;
line-height: 22px;
color: #e3e3e3;
font-size: 12px;
}
.table-row{
display: flex;
justify-content: space-between;
color: #e3e3e3;
height: 24px;
line-height: 24px;
margin-bottom: 4px;
cursor: pointer;
font-size: 12px;
}
.table-row-db{
background-image: url("../../../../assets/images/carbon/tb_row_bg.png");
background-size: 100% 100%;
}
.table-row:hover{
background: linear-gradient(to right,#45B9D2, rgba(1, 71, 129, 0));
color: #FFD234;
}
.table-column{
text-align: start;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
padding: 0 5px;
align-items: center;
}
.w1{
width: 70px;
}
.w2{
width: 85px;
}
.w3{
width: 130px;
}
.w4{
width: 70px;
}
.scrollStyle {
height: 330px;
overflow: auto;
}
::v-deep *::-webkit-scrollbar {
width: 0px;
height: 16px;
background-color: transparent;
}
}
.shgx-box{
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
padding: 8px;
.row{
width: 100%;
height: 30%;
//margin-bottom: 8px;
.col{
height: 100%;
background-image: url("../../../../assets/images/carbon/data_bg2.png");
background-size: 100% 100%;
display: flex;
justify-content: center;
align-items: center;
img{
height: 36px;
margin: 0 15px;
}
span{
background: linear-gradient(to bottom, #E8F7FF , #01D1FF);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent; /* 这行代码很重要,它确保了文本本身是透明的,从而显示出背景 */
text-align: left;
font-weight: 600;
line-height: 15px;
letter-spacing: 1px;
font-style: normal;
text-transform: none;
}
.num{
font-size: 18px;
}
.unit{
font-size: 10px;
}
.name{
font-size: 12px;
color: #FFFFFF;
}
.tj{
width: calc(100% - 66px);
}
}
}
}
.zcgl-box{
height:100%;
padding: 15px 20px;
text-align: center;
.zcgl-item {
height: calc(50% - 12px);
width: calc(50% - 12px);
margin: 6px;
background: url('../../../../assets/images/carbon/data_bg1.png') no-repeat;
background-size: 100% 60%;
background-position: center bottom;
display: flex;
flex-direction: column;
justify-content: end;
.zcgl-num {
color: #00afff;
font-size: 20px;
font-weight: 600;
margin-right: 5px;
}
.zcgl-unit {
color: #FFFFFF;
font-size: 12px
}
.zcgl-name{
color: #FFFFFF;
display: block;
margin: 10px 0 7px 0;
font-size: 14px;
}
}
}
.zdtp-top{
height: 30px;
.zdtp-tj{
display: inline-block;
width: 274px;
height: 21px;
background-image: url("../../../../assets/images/carbon/data_bg1.png");
background-size: 100% 100%;
text-align: center;
margin: 9px 20px 0 20px;
.name{
font-size: 12px;
color: #FFFFFF;
margin-right: 10px;
}
.num{
font-size: 14px;
color: #F4B149;
line-height: 14px;
text-shadow: 0 1px 4px #F29600;
}
}
.unit{
color: #FFFFFF;
font-size: 12px;
}
}
.scope-box{
height: 100%;
//padding: 25px;
width: 100%;
position: relative;
.unit{
color: #fff;
font-size: 12px;
height: 30px;
line-height: 30px;
float: right;
margin-right: 15px
}
.scope{
display: flex;
align-items: center;
height: calc(50% - 30px);
width: calc(100% - 30px);
margin: 0 15px 15px 15px;
background-image: url("../../../../assets/images/carbon/data_bg2.png");
background-size: 100% 100%;
.pf{
width: 50%;
height: 30%;
background: linear-gradient(to right, rgba(255, 214, 0, 0), rgba(255, 214, 0, 0.84));
border-radius: 0 50px 50px 0;
border-right: 3px solid #FFD600;
color: #fff;
}
.pf:hover {
border: 1px solid #FFD600;
}
.jp{
width: 50%;
height: 30%;
background: linear-gradient(to left, rgba(0, 233, 149, 0), rgba(0, 233, 149, 0.76));
border-radius: 50px 0 0 50px;
border-left: 3px solid #00E995;
color: #fff;
}
.scope-label{
width: 100px;
text-align: center;
.name{
font-size: 12px;
color: #fff;
}
.pf-num{
font-size: 18px;
color: #FFCD1D;
}
.jp-num{
font-size: 18px;
color: #00E995;
}
span{
display: block;
}
}
}
.tzh{
height: 100%;
position: absolute;
left: 45.3%;
display: flex;
flex-direction: column;
align-items: center;
top: 0;
.zh-text{
height: 30px;
color: #fff;
line-height: 30px;
}
.zh-line{
border-left: 1px dashed orange;
width: 1px;
height: calc(100% - 35px);
}
}
}
.custom-height{
height: 190px !important;
}
</style>

67
ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/carbon/btn/index.vue

@ -0,0 +1,67 @@
<template>
<div :class="{'btn':true,'big':size==='big','normal':size==='normal','small':size==='small','mini':size==='mini','selected':active}" >{{ name }}</div>
</template>
<script>
export default {
name: "index",
props: {
name: {
type: String,
default: '',
required:true
},
active: {
type: Boolean,
default: false
},
size:{
type:String,
default:'normal'
}
},
watch:{
size(val){
console.log(val)
}
}
}
</script>
<style lang="scss" scoped>
.btn {
text-align: center;
line-height: 20px;
color: #FFFFFF;
cursor: pointer;
border-radius: 1px;
background-image: url("../../../../../../../assets/images/carbon/btn_normal.png");
background-size: 100% 100%;
}
.normal{
font-size: 10px;
width: 56px;
height: 20px;
line-height: 20px;
margin: 9px 5px 9px 0;
}
.small{
font-size: 10px;
width: 45px;
height: 18px;
line-height: 18px;
margin: 0;
}
.big{
font-size: 12px;
width: 76px;
height: 24px;
line-height: 24px;
margin: 7px 10px 7px 0;
}
.mini{}
.selected {
background-image: url("../../../../../../../assets/images/carbon/btn_active.png");
}
</style>

83
ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/carbon/contentItem/index.vue

@ -0,0 +1,83 @@
<template>
<!-- <div class="content-item" @mouseenter="transitionAnimation">-->
<div class="content-item" :style="{height: height}">
<transition name="el-zoom-in-center">
<div class="item-title-bg" v-show="show">
<div class="text" :data-text="name">{{ name }}</div>
</div>
</transition>
<transition name="el-zoom-in-center">
<div class="item-content" v-show="show">
<slot></slot>
</div>
</transition>
</div>
</template>
<script>
export default {
name: "index",
props: ['name', 'transition','height'],
data() {
return {
show: true,
};
},
mounted() {
this.transitionAnimation()
},
methods: {
transitionAnimation() {
this.show = false;
setTimeout(() => {
this.show = true;
}, 500);
}
}
}
</script>
<style lang="scss" scoped>
.content-item {
height: calc(25% - 5px);
width: 400px;
margin-bottom: 5px;
background-color: rgba(18, 232, 232, 0);
.item-title-bg {
display: flex;
align-items: center;
height: 30px;
width: 100%;
background-image: url("../../../../../../../assets/images/carbon/item_title.png");
background-size: 100% 100%;
.text {
background: linear-gradient(to bottom, #fff, #4DD4FF);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent; /* 这行代码很重要,它确保了文本本身是透明的,从而显示出背景 */
font-size: 18px; /* 你可以根据需要调整字体大小 */
text-align: left;
font-weight: 600;
line-height: 23px;
margin-left: 16px;
letter-spacing: 1px;
font-style: normal;
text-transform: none;
//text-shadow: 0 4px 0 rgba(0, 0, 0, 0.25); /* */
}
}
.item-content {
height: calc(100% - 30px);
background-color: rgba(21, 46, 60, 0.64);
border-width: 2px;
/* 使用 border-image 属性 */
border-image: linear-gradient(to bottom, rgba(40, 144, 167, 0), rgba(40, 144, 167, 0.7)) 1;
/* 确保边框是连续的,而不是间隔的 */
border-style: solid;
}
}
</style>

346
ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/carbon/echarts/RingChart.vue

@ -0,0 +1,346 @@
<template>
<div :class="className" :style="{height:height,width:width}"/>
</template>
<script>
import * as echarts from 'echarts'
import resize from './mixins/resize'
export default {
mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: 'calc(100% - 30px)'
}
},
data() {
return {
chart: null,
}
},
mounted() {
this.$nextTick(() => {
this.initChart()
})
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(this.$el)
this.setOption()
},
setOption() {
this.chart.setOption(
{
grid: {
top: '100%',
left: '3%',
right: '4%',
bottom: '5%',
containLabel: true,
},
legend: {
orient: 'vertical',
show: true,
right: '8%',
y: 'center',
itemWidth: 5,
itemHeight: 5,
itemGap: 10,
textStyle: {
color: '#e1e1e1',
fontSize: 14,
lineHeight: 20,
rich: {
percent: {
color: '#37E7FF',
fontSize: 14,
},
},
},
formatter: name => {
switch (name) {
case '办公用电':
return (
'办公用电\r{percent|30%}'
);
case '空调用电':
return (
'空调用电\r{percent|30%}'
);
case '路域用电':
return (
'路域用电\r{percent|40%}'
);
case '收费岛用电':
return (
'收费岛用电\r{percent|40%}'
);
default:
break;
}
},
},
graphic: {
type: 'text',
left: '26%', //
top: '45%', //
style: {
text: '60%',
textAlign: 'center',
fill: '#fff', //
fontSize: 16 //
},
z: 100 //
},
tooltip: {
show: true,
},
series: [
{
type: 'pie',
radius: ['43%', '70%'],
center: ['30%', '50%'],
z:1,
//hoverAnimation: false,
avoidLabelOverlap: false,
padAngle: 5,
itemStyle: {
borderRadius: 3
},
/* label: {
position: 'center',
formatter: () => {
return '作业总数\r\n{total|100} 个';
},
rich: {
total: {
fontSize: 30,
color: '#fff',
},
},
color: '#7a8c9f',
fontSize: 16,
lineHeight: 30,
},*/
data: [
{
value: 30,
name: '办公用电',
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
{
offset: 0,
color: '#FFF1A2'
},
{
offset: 1,
color: '#FFB905'
}
]),
},
},
{
value: 30,
name: '空调用电',
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
{
offset: 0,
color: '#61D8FF'
},
{
offset: 1,
color: '#0BA7DA'
}
]),
},
},
{
value: 40,
name: '路域用电',
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
{
offset: 0,
color: '#8EBBFF'
},
{
offset: 1,
color: '#5973FF'
}
]),
},
},
{
value: 40,
name: '收费岛用电',
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
{
offset: 0,
color: '#6AF4DA'
},
{
offset: 1,
color: '#0FE9A7'
}
]),
},
}
],
labelLine: {
show: false,
},
label: {
show: false,
}
},
{
type: 'pie',
radius: [0, '38%'],
center: ['30%', '50%'],
hoverAnimation: false,
tooltip:{
show:false,
},
label: {
show:false,
},
labelLine: {
show: false
},
itemStyle: {
color: '#02a6ff',
opacity: 0.4,
},
data: [
{ value: 0 }
]
},
{
type: 'pie',
hoverAnimation: false,
z:2,
radius: [0, '60%'],
center: ['30%', '50%'],
tooltip:{
show:false,
},
label: {
show:false,
},
labelLine: {
show: false
},
itemStyle: {
color: '#163A45',
opacity: 0.9,
},
data: [
{ value: 0 }
]
},
{
type: 'pie',
z: 4,
silent: true,
radius: ['51%', '52%'],
center: ['30%', '50%'],
label: {
show: false
},
labelLine: {
show: false
},
data: _pie3()
},
/*{
type: 'pie',
radius: ['45%', '75%'],
center: ['20%', '50%'],
//hoverAnimation: false,
padAngle: 5,
itemStyle: {
borderRadius: 5,
color: '#0286ff',
opacity: 0.4,
},
label: {
show: false,
},
data: [
{
value: 30,
name: '运行中'
},
{
value: 30,
name: '已停止'
},
{
value: 40,
name: '未上线'
},
],
labelLine: {
show: false,
},
}*/
],
}
)
function _pie3() {
let dataArr = [];
for (var i = 0; i < 100; i++) {
if (i % 2 === 0) {
dataArr.push({
//name: (i + 1).toString(),
value: 25,
itemStyle: {
normal: {
color: "#1ABAF0",
borderWidth: 0,
borderColor: "rgba(0,0,0,0)"
}
}
})
} else {
dataArr.push({
//name: (i + 1).toString(),
value: 20,
itemStyle: {
normal: {
color: "rgba(0,0,0,0)",
borderWidth: 0,
borderColor: "rgba(0,0,0,0)"
}
}
})
}
}
return dataArr
}
}
}
}
</script>
<style scoped>
</style>

271
ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/carbon/echarts/SortBarChart.vue

@ -0,0 +1,271 @@
<template>
<div :class="className" :style="{height:height,width:width}"/>
</template>
<script>
import * as echarts from 'echarts'
import resize from './mixins/resize'
export default {
mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '17.63vh'
}
},
data() {
return {
chart: null,
chartData:[
{
value: 239,
name: "大学城收费站"
},
{
"value": 181,
"name": "长清收费站"
},
{
"value": 154,
"name": "孝里收费站"
},
{
"value": 144,
"name": "平阴北收费站"
},
{
"value": 135,
"name": "平阴收费站"
},
{
"value": 117,
"name": "平阴南收费站"
},
{
"value": 74,
"name": "梁山东收费站"
},
{
"value": 52,
"name": "嘉祥西收费站"
}
],
}
},
mounted() {
this.$nextTick(() => {
this.initChart()
})
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(this.$el)
this.setOption()
},
setOption() {
let that = this
this.chart.setOption(
{
tooltip: {
show: false,
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
legend: {
show: false
},
grid: {
left: '42%',
right: '14%',
bottom: '2%',
top: '26%',
//containLabel: true
},
xAxis: {
show: false,
type: 'value'
},
yAxis: [
{
type: 'category',
inverse: true,
axisLine: {
show: false
},
axisTick: {
show: false
},
axisPointer: {
label: {
show: false,
margin: 30
}
},
data: that.chartData.map(item => item.name),
axisLabel: {
margin: 150,
fontSize: 14,
align: 'left',
color: '#ffffff',
rich: {
a1: {
color: '#fff',
backgroundColor: new echarts.graphic.LinearGradient(0, 1, 0, 0, [
{
offset: 0,
color: '#FFB904'
},
{
offset: 1,
color: '#FF6969'
}
]),
width: 45,
height: 18,
align: 'center',
borderRadius: 5
},
b: {
color: '#fff',
backgroundColor: new echarts.graphic.LinearGradient(0, 1, 0, 0, [
{
offset: 0,
color: '#61D8FF'
},
{
offset: 1,
color: '#0BA7DA'
}
]),
width: 45,
height: 18,
align: 'center',
borderRadius: 5
}
},
formatter: function (params) {
let index = that.chartData.map(item => item.name).indexOf(params);
index = index + 1;
if (index - 1 < 1) {
return [
'{a1|TOP' + index + '}' + ' ' + params
].join('\n')
} else {
return [
'{b|TOP' + index + '}' + ' ' + params
].join('\n')
}
}
}
},
{
type: 'category',
inverse: true,
axisTick: 'none',
axisLine: 'none',
show: true,
data: that.chartData.map(item => item.value),
axisLabel: {
show: true,
fontSize: 14,
color: '#ffffff',
formatter: '{value}'
}
}],
series: [
{
z: 2,
name: 'value',
type: 'bar',
barWidth: 8,
zlevel: 1,
data: that.chartData.map((item, i) => {
let itemStyle = {
barBorderRadius: 30,
color: i > 0
? new echarts.graphic.LinearGradient(0, 0, 1, 0, [
{
offset: 0,
color: '#61D8FF'
},
{
offset: 1,
color: '#0BA7DA'
}
])
: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
{
offset: 0,
color: '#FFB904'
},
{
offset: 1,
color: '#FF6969'
}
]),
}
return {
value: item.value,
itemStyle: itemStyle
};
}),
label: {//
show: false,
position: 'right',
color: '#e70a0a',
fontSize: 14,
offset: [10, 0]
}
}
],
dataZoom: [
{
yAxisIndex: [0, 1], //X0
show: false, //使
type: "slider", // dataZoom slider dataZoom
startValue: 0, //
endValue: 3, //
},
{
//
//
type: "inside",
// y
yAxisIndex: [0, 1],
//
zoomOnMouseWheel: false,
//
moveOnMouseMove: true,
//
moveOnMouseWheel: true,
}
],
}
)
}
},
}
</script>
<style scoped>
</style>

192
ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/carbon/echarts/SplitBarChart.vue

@ -0,0 +1,192 @@
<template>
<div ref="echarts" :class="className" :style="{width: width, height: height}"></div>
</template>
<script>
import * as echarts from 'echarts'
import resize from './mixins/resize'
export default {
mixins: [resize],
components: {},
name: 'SplitBarChart',
data() {
return {
chart: null,
}
},
props: {
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '100%'
},
autoResize: {
type: Boolean,
default: true
},
chartData: {
type: Object,
required: true
}
},
watch: {
chartData: {
deep: true,
handler(val) {
this.setOptions(val)
}
}
},
mounted() {
this.$nextTick(() => {
//this.getData()
this.initChart()
})
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(this.$refs.echarts)
this.setOptions(this.chartData)
},
setOptions({xData, yData} = {}) {
let series = [], unit = ''
if (yData.unit) unit = yData.unit
let seriesBarDefault = {
type: 'pictorialBar',
name: yData.name?yData.name:'',
itemStyle: {
color:yData.color?yData.color:'#20E6FE'
/*normal: {
// color: 'rgba(70,179,250,1)'
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: '#20E6FE'
},
{
offset: 1,
color: '#007EAE'
}
])
}*/
},
yAxisIndex: 0,
symbolRepeat: 'fixed',
barWidth:'60%',
barGap: 0.01, //
symbolMargin: 1,
symbol: 'rect',
symbolClip: true,
symbolSize: [8, 4],
symbolOffset: [0, 0],
data:yData.data?yData.data:[]
}
series.push(seriesBarDefault)
let options = {
title:{
show:true,
text:unit,
textStyle:{
color:'#e3e3e3',
fontSize: 12,
fontWeight:500
},
right:'0%',
top: '4%',
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
},
legend: {
show: true,
icon: 'circle',
top: '4%',
right: '15%',
itemHeight: 10,
itemWidth: 10,
//data: legend,
textStyle: {
//
color: '#e3e3e3',
fontSize: 1
}
},
grid: {
left: '2%',
right: '1%',
bottom: '5%',
top: '30%',
containLabel: true
},
xAxis: {
type: 'category',
axisTick: {
show: false
},
axisLine: {
show: false,
lineStyle: {
color: '#F1F1F1'
}
},
axisLabel: {
color: '#e3e3e3'
},
data: xData,
},
yAxis: [
{
//name: unit,
type: 'value',
splitLine: {
show: true,
lineStyle:{
type:5,
width:1,
color: '#104266' , //x线
}
},
axisLabel: {
color: '#e3e3e3'
}
}
],
series: series,
dataZoom: [
{
xAxisIndex: 0, //X0
show: false, //使
type: "inside", // dataZoom slider dataZoom
startValue: 0, //
endValue: 10, //
}
],
animation:false,
//animationDuration: 0,//
//animationEasing: 'cubicInOut'//
}
this.chart.setOption(options,true)
}
}
}
</script>
<style scoped>
/* @import url(); 引入css类 */
</style>

264
ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/carbon/echarts/lineCharts.vue

@ -0,0 +1,264 @@
<template>
<div :class="className" :style="{height:height,width:width}" />
</template>
<script>
import * as echarts from 'echarts'
import {duoyuan} from './realData'
import {parseTime} from '@/utils/ruoyi'
import resize from './mixins/resize'
export default {
mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '17.63vh'
}
},
watch: {
data: {
deep: true,
handler: function (newV, oldV) {
this.setOption()
}
}
},
data() {
return {
chart: null,
timer: null,
value: 18,
yuan:duoyuan,
xData:[],
pvData:[],
loadData:[],
electricData:[]
}
},
mounted() {
this.$nextTick(() => {
this.initChart()
})
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
created() {
this.$nextTick(()=>{
//
var now = new Date();
let nowTime = parseInt(now.getTime());
let dateStr = parseTime(now,'{y}-{m}-{d}')
if(this.yuan){
this.yuan.forEach(e=>{
e.time = e.time.replace(e.time.substr(0,10),dateStr);
let cTime = this.dateStrChangeTimeTamp(e.time)
if(cTime<nowTime){
this.xData.push(e.time)
this.pvData.push(e.photovoltaicMeter)
this.loadData.push(e.loadMeter)
this.electricData.push(e.electricMeter)
}
})
}
})
},
methods: {
//
//var date = '2015-03-05 17:59:00.0';
dateStrChangeTimeTamp(dateStr){
dateStr = dateStr.substring(0,19);
dateStr = dateStr.replace(/-/g,'/');
return new Date(dateStr).getTime();
},
initChart() {
this.chart = echarts.init(this.$el)
this.setOption()
},
setOption() {
this.chart.setOption({
backgroundColor: 'rgba(255,255,255,0)',
// dataZoom: [
// {
// moveOnMouseMove: true,
// type: 'slider',
// show: false,
// xAxisIndex: [0],
// start: 0,
// end: 30, //
// minValueSpan: 7,
// maxValueSpan: 7
// },
// {
// type: 'inside',
// xAxisIndex: 0,
// zoomOnMouseWheel: false, //
// moveOnMouseMove: true, //
// moveOnMouseWheel: true
// }
// ],
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(1, 29, 63, .8)', //
textStyle: {
color: '#fff',
fontSize: 12
},
borderColor: 'rgba(1, 29, 63,.8)',
axisPointer: {
type: 'shadow',
shadowStyle: {
fontSize: 12,
color: 'rgba(0, 11, 34, 0)'
}
}
},
title: {
text: '单位(tCO₂)',
textStyle: {
fontSize: 11,
fontWeight: 'normal',
color: '#FFFFFF' //
},
top: '3%',
right: '2%'
},
legend: {
icon: 'circle',
itemWidth: 7,
itemHeight: 7,
data: ['碳排放', '碳减排'],
right: '25%',
top: '3%',
textStyle: {
fontSize: 11,
color: '#FFFFFF'
}
},
grid: {
top: '32%',
left: '4%',
right: '2%',
bottom: '2%',
containLabel: true
},
xAxis: {
type: 'category',
axisLine: {
lineStyle: {
color: 'rgba(143, 169, 192, 0.60)'
}
},
axisLabel: {
color: '#FFFFFF'
},
axisTick: {
show: false
},
data: this.xData
},
yAxis: {
type: 'value',
// interval: 100,
axisLine: {
lineStyle: {
color: 'rgba(143,169,192,0.7)'
}
},
axisLabel: {
margin: 18,
fontSize: 10,
color: '#FFFFFF'
},
splitLine: {
lineStyle: {
//type: 'dashed',
color: 'rgba(143,169,192,0.25)'
}
}
},
series: [
{
name: '碳排放',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 5,
showSymbol: false,
zlevel: 1,
z: 1,
lineStyle: {
width: 1.5
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: '#E2BA74'
},
{
offset: 0.9,
color: 'rgba(226,186,116,0.1)'
}
], false),
shadowBlur: 10
},
itemStyle: {
color: '#E2BA74',
borderWidth: 30
},
data: this.pvData
},
{
name: '碳减排',
type: 'line',
smooth: true,
symbol: 'circle',
zlevel: 1,
z: 1,
symbolSize: 5,
showSymbol: false,
lineStyle: {
width: 1.5
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: 'rgba(50,187,138,0.7)'
},
{
offset: 0.9,
color: 'rgba(50,187,138,0.1)'
}
], false),
shadowBlur: 10
},
itemStyle: {
color: '#32BB8A',
borderWidth: 30
},
data: this.electricData
}
]
})
}
}
}
</script>
<style scoped>
</style>

56
ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/carbon/echarts/mixins/resize.js

@ -0,0 +1,56 @@
import { debounce } from '@/utils'
export default {
data() {
return {
$_sidebarElm: null,
$_resizeHandler: null
}
},
mounted() {
this.initListener()
},
activated() {
if (!this.$_resizeHandler) {
// avoid duplication init
this.initListener()
}
// when keep-alive chart activated, auto resize
this.resize()
},
beforeDestroy() {
this.destroyListener()
},
deactivated() {
this.destroyListener()
},
methods: {
// use $_ for mixins properties
// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
$_sidebarResizeHandler(e) {
if (e.propertyName === 'width') {
this.$_resizeHandler()
}
},
initListener() {
this.$_resizeHandler = debounce(() => {
this.resize()
}, 100)
window.addEventListener('resize', this.$_resizeHandler)
this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
},
destroyListener() {
window.removeEventListener('resize', this.$_resizeHandler)
this.$_resizeHandler = null
this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
},
resize() {
const { chart } = this
chart && chart.resize()
}
}
}

1954
ruoyi-ui/src/views/JiHeExpressway/pages/Home/components/carbon/echarts/realData.js

File diff suppressed because it is too large

31
ruoyi-ui/src/views/JiHeExpressway/pages/Home/index.vue

@ -1,7 +1,7 @@
<template> <template>
<div style="width: 100%;height: 100%;"> <div style="width: 100%;height: 100%;position: relative">
<component :is="mapContainer" ref="MapContainerRef" @update:isGisCompleted="(data) => { this.isGisCompleted = data; }" /> <component :is="mapContainer" ref="MapContainerRef" @update:isGisCompleted="(data) => { this.isGisCompleted = data; }" />
<div class="Home"> <div class="Home" v-show="jnValue==='1'">
<section class="content"> <section class="content">
<!-- 左侧 --> <!-- 左侧 -->
<div class="content-l"> <div class="content-l">
@ -37,6 +37,13 @@
</div> </div>
</footer> </footer>
</div> </div>
<carbon v-if="jnValue==='2'"/>
<!-- 交能切换 -->
<radio-group :options="[
{ key: '1', label: '交' },
{ key: '2', label: '能' },
]" class="jn-radio" type="custom1" v-model="jnValue" size="mini" />
</div> </div>
</template> </template>
@ -60,7 +67,8 @@ import RoadAndEvents from "./components/RoadAndEvents/index.vue";
import Button from "@screen/components/Buttons/Button.vue"; import Button from "@screen/components/Buttons/Button.vue";
import Vue from "vue"; import Vue from "vue";
import BMapContainer from "./components/BMapContainer/index.vue"; import BMapContainer from "./components/BMapContainer/index.vue";
import RadioGroup from "@screen/components/FormConfig/components/RadioGroup/index.vue";
import Carbon from "./carbon";
export default { export default {
name: "Home", name: "Home",
components: { components: {
@ -79,13 +87,16 @@ export default {
HomeWord, HomeWord,
HomeWeather, HomeWeather,
HomeWeatherLayer, HomeWeatherLayer,
HomeTraffic HomeTraffic,
RadioGroup,
Carbon
}, },
data() { data() {
return { return {
selectedDevice: null, selectedDevice: null,
isGisCompleted: false, isGisCompleted: false,
mapContainer:'BMapContainer' mapContainer:'BMapContainer',
jnValue:'1'
}; };
}, },
provide() { provide() {
@ -121,7 +132,7 @@ export default {
translateXElement.style.transform = `translateY(0)`; translateXElement.style.transform = `translateY(0)`;
translateXElement.style.position = `relative`; translateXElement.style.position = `relative`;
} }
}, }
}, },
}; };
</script> </script>
@ -248,4 +259,10 @@ export default {
} }
} }
} }
.jn-radio{
position: absolute;
top: 16px;
left: 22.6%;
z-index: 2;
}
</style> </style>

Loading…
Cancel
Save