@ -1,27 +1,51 @@
|
||||
import request from '@/utils/request' |
||||
import request from "@/utils/request"; |
||||
|
||||
// 查询设备参数列表
|
||||
export function cmpList(query) { |
||||
// 获取天气相关数据
|
||||
export function weatherData() { |
||||
return request({ |
||||
url: '/device/cmp/list', |
||||
method: 'get', |
||||
params: query |
||||
}) |
||||
url: "/device/cs/getWeatherData", |
||||
method: "get", |
||||
}); |
||||
} |
||||
|
||||
// 根据id查询设备参数信息
|
||||
export function getCMP(cmpId) { |
||||
// 获取运行时间
|
||||
export function runTime() { |
||||
return request({ |
||||
url: '/device/cmp/' + cmpId, |
||||
method: 'get' |
||||
}) |
||||
url: "/device/cs/runTime", |
||||
method: "get", |
||||
}); |
||||
} |
||||
|
||||
// 新增设备参数
|
||||
export function addCMP(data) { |
||||
// 获取系统性能数据
|
||||
export function sysPerformance() { |
||||
return request({ |
||||
url: '/device/cmp', |
||||
method: 'post', |
||||
data: data |
||||
}) |
||||
url: "/device/cs/sysPerformance", |
||||
method: "get", |
||||
}); |
||||
} |
||||
|
||||
// 系统监测列表
|
||||
export function monitorList(query) { |
||||
return request({ |
||||
url: "/device/cs/monitor/list", |
||||
method: "get", |
||||
params: query, |
||||
}); |
||||
} |
||||
// 查询系统控制列表
|
||||
export function operationList(query) { |
||||
return request({ |
||||
url: "/device/cs/operation/list", |
||||
method: "get", |
||||
params: query, |
||||
}); |
||||
} |
||||
|
||||
// 系统控制
|
||||
export function operationConrol(data) { |
||||
return request({ |
||||
url: "/device/operation", |
||||
method: "post", |
||||
data: data, |
||||
}); |
||||
} |
@ -0,0 +1,18 @@
|
||||
import request from "@/utils/request"; |
||||
|
||||
// 控制列表
|
||||
export function waterOperateList(query) { |
||||
return request({ |
||||
url: "/device/hotWater/operateList", |
||||
method: "get", |
||||
params: query, |
||||
}); |
||||
} |
||||
// 系统控制
|
||||
export function operationConrol(data) { |
||||
return request({ |
||||
url: "/device/operation", |
||||
method: "post", |
||||
data: data, |
||||
}); |
||||
} |
@ -0,0 +1,18 @@
|
||||
import request from "@/utils/request"; |
||||
|
||||
// 公共信息
|
||||
export function waterPublic(query) { |
||||
return request({ |
||||
url: "/device/hotWater/monitorPublic", |
||||
method: "get", |
||||
params: query, |
||||
}); |
||||
} |
||||
// 系统状态显示
|
||||
export function waterMonitorList(query) { |
||||
return request({ |
||||
url: "/device/hotWater/monitorList", |
||||
method: "get", |
||||
params: query, |
||||
}); |
||||
} |
@ -0,0 +1,47 @@
|
||||
import request from "@/utils/request"; |
||||
|
||||
// 获取项目简介数据
|
||||
export function introduction() { |
||||
return request({ |
||||
url: "/pro/overview/introduction", |
||||
method: "get", |
||||
}); |
||||
} |
||||
|
||||
// 项目logo上传
|
||||
export function changeLogo(data) { |
||||
const formData = new FormData(); |
||||
Object.keys(data).forEach((key) => { |
||||
formData.append(key, data[key]); |
||||
}); |
||||
return request({ |
||||
url: "/pro/overview/logo", |
||||
method: "post", |
||||
data: formData, |
||||
headers: { |
||||
"Content-Type": "multipart/form-data", |
||||
}, |
||||
// responseType: 'blob',
|
||||
}); |
||||
} |
||||
// 项目概况
|
||||
export function viewProfile() { |
||||
return request({ |
||||
url: "/pro/overview/profile", |
||||
method: "get", |
||||
}); |
||||
} |
||||
// 最近12月能耗
|
||||
export function viewYearEnergy() { |
||||
return request({ |
||||
url: "/pro/overview/energyAnalysis", |
||||
method: "get", |
||||
}); |
||||
} |
||||
// 各个系统主要参数值
|
||||
export function viewMainParams() { |
||||
return request({ |
||||
url: "/pro/overview/mainParams", |
||||
method: "get", |
||||
}); |
||||
} |
After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 12 MiB |
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 6.4 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 6.5 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 8.1 KiB |
@ -0,0 +1,528 @@
|
||||
<template> |
||||
<div class="app-container"> |
||||
<!-- 状态统计 --> |
||||
<div class="status-statistics"> |
||||
<div class="status-card"> |
||||
<div class="status-label">运行设备</div> |
||||
<div class="status-value-running"> |
||||
{{ statistics.running }}/{{ deviceList.length }} |
||||
</div> |
||||
</div> |
||||
<div class="status-card"> |
||||
<div class="status-label">手动模式</div> |
||||
<div class="status-value-auto"> |
||||
{{ statistics.manual }}/{{ deviceList.length }} |
||||
</div> |
||||
</div> |
||||
<div class="status-card"> |
||||
<div class="status-label">自动模式</div> |
||||
<div class="status-value-maintenance"> |
||||
{{ statistics.auto }}/{{ deviceList.length }} |
||||
</div> |
||||
</div> |
||||
<div class="status-card"> |
||||
<div class="status-label">故障设备</div> |
||||
<div class="status-value-error"> |
||||
{{ statistics.warn }}/{{ deviceList.length }} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<!-- 非蝶阀控制列表 --> |
||||
<div class="device-container"> |
||||
<div class="device-li"> |
||||
<div class="device-name">设备名称</div> |
||||
<div class="device-name">运行状态</div> |
||||
<div class="device-name">手动控制</div> |
||||
<div class="device-name">手自动切换</div> |
||||
<div class="device-name">故障报警</div> |
||||
<div class="device-name">频率调节</div> |
||||
<div class="device-name">频率反馈</div> |
||||
</div> |
||||
<div class="device-li" v-for="(item, index) in deviceList" :key="index"> |
||||
<div class="device-name">{{ item.name }}</div> |
||||
<div class="device-name"> |
||||
<div |
||||
class="run" |
||||
:class="item.runStatus === '运行' ? 'run' : 'no-run'" |
||||
> |
||||
{{ item.runStatus }} |
||||
</div> |
||||
</div> |
||||
<div class="device-name"> |
||||
<el-switch |
||||
style="display: block" |
||||
v-model="item.controlText" |
||||
active-color="#13ce66" |
||||
inactive-color="#ff4949" |
||||
active-text="开启" |
||||
inactive-text="停止" |
||||
@change="handleControlText(item)" |
||||
> |
||||
</el-switch> |
||||
</div> |
||||
<div class="device-name"> |
||||
<span |
||||
:class=" |
||||
item.automaticText === '手动' |
||||
? 'strong-electric' |
||||
: 'auto-electric' |
||||
" |
||||
>{{ item.automaticText }}</span |
||||
> |
||||
</div> |
||||
<div class="device-name"> |
||||
<div :class="item.warnText === '故障' ? 'bad-status' : 'good-status'"> |
||||
{{ item.warnText }} |
||||
</div> |
||||
</div> |
||||
<div class="device-name"> |
||||
<el-input |
||||
v-if="item.frequencySet !== null && item.frequencySet !== undefined" |
||||
v-model="item.frequencySet" |
||||
size="mini" |
||||
@keyup.enter.native="handleEnter(item)" |
||||
@input="handleInput(item)" |
||||
></el-input> |
||||
<div class="device-name" v-else></div> |
||||
</div> |
||||
<div class="device-name" v-if="item.frequency"> |
||||
{{ item.frequency }}Hz |
||||
</div> |
||||
<div class="device-name" v-else></div> |
||||
</div> |
||||
</div> |
||||
<!-- 蝶阀控制列表 --> |
||||
<div class="device-container second"> |
||||
<div class="device-li"> |
||||
<div class="device-name">设备名称</div> |
||||
<div class="device-name">手动阀关控制</div> |
||||
<div class="device-name">阀关反馈</div> |
||||
<div class="device-name">手动阀开控制</div> |
||||
<div class="device-name">阀开反馈</div> |
||||
</div> |
||||
<div class="device-li" v-for="(item, index) in valveList" :key="index"> |
||||
<div class="device-name">{{ item.name }}</div> |
||||
<div class="device-name"> |
||||
<el-switch |
||||
style="display: block" |
||||
v-model="item.openText" |
||||
active-color="#13ce66" |
||||
inactive-color="#ff4949" |
||||
active-text="开启" |
||||
inactive-text="停止" |
||||
@change="handleValveOpen(item)" |
||||
> |
||||
</el-switch> |
||||
</div> |
||||
<div class="device-name"> |
||||
<div |
||||
:class="item.openStauts === '关闭' ? 'bad-status' : 'good-status'" |
||||
> |
||||
{{ item.openStauts }} |
||||
</div> |
||||
</div> |
||||
<div class="device-name"> |
||||
<el-switch |
||||
style="display: block" |
||||
v-model="item.closeText" |
||||
active-color="#13ce66" |
||||
inactive-color="#ff4949" |
||||
active-text="开启" |
||||
inactive-text="停止" |
||||
@change="handleValveClose(item)" |
||||
> |
||||
</el-switch> |
||||
</div> |
||||
<div class="device-name"> |
||||
<div |
||||
:class="item.closeStatus === '关闭' ? 'bad-status' : 'good-status'" |
||||
> |
||||
{{ item.closeStatus }} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import { operationList, operationConrol } from "@/api/centerairC/sysMonitor"; |
||||
export default { |
||||
name: "sysMonitor", |
||||
data() { |
||||
return { |
||||
deviceList: [ |
||||
{ |
||||
name: "", |
||||
runStatus: "", |
||||
controlText: "", |
||||
automaticText: "", |
||||
warnText: "", |
||||
frequencySet: "", |
||||
frequency: "", |
||||
}, |
||||
], |
||||
valveList: [ |
||||
{ |
||||
name: "", |
||||
openText: "", |
||||
openStatus: "", |
||||
closeText: "", |
||||
closeStatus: "", |
||||
}, |
||||
], |
||||
}; |
||||
}, |
||||
computed: { |
||||
statistics() { |
||||
return { |
||||
running: this.deviceList.filter((d) => d.runStatus === "运行").length, |
||||
manual: this.deviceList.filter((d) => d.automaticText === "手动") |
||||
.length, |
||||
auto: this.deviceList.filter((d) => d.automaticText === "自动").length, |
||||
warn: this.deviceList.filter((d) => d.warnText === "故障").length, |
||||
}; |
||||
}, |
||||
}, |
||||
mounted() { |
||||
this.getOperationList(); |
||||
}, |
||||
methods: { |
||||
getOperationList() { |
||||
operationList({ systemType: 0 }).then((res) => { |
||||
console.log("列表返回res", res); |
||||
if (res.code == 200) { |
||||
let handleList = res.rows; |
||||
this.deviceList = []; |
||||
this.valveList = []; |
||||
handleList.forEach((element) => { |
||||
if (element.children && element.children.length > 0) { |
||||
// 初始化一个空对象来存储非蝶阀处理后的结果 |
||||
let deviceItem = { |
||||
name: element.name, |
||||
}; |
||||
// 初始化一个空对象来存储阀门处理后的结果 |
||||
let valveItem = { |
||||
name: element.name, |
||||
}; |
||||
|
||||
// 只处理前四个子元素 |
||||
const limitedChildren = element.children; |
||||
limitedChildren.forEach((child) => { |
||||
if (child.name) { |
||||
if (child.name.includes("运行状态")) { |
||||
deviceItem.runStatus = |
||||
child.value === "0.000" ? "不运行" : "运行"; |
||||
} else if (child.name.includes("启停控制")) { |
||||
deviceItem.controlText = |
||||
child.value === "0.000" ? false : true; |
||||
deviceItem.controlId = child.id; |
||||
} else if (child.name.includes("手自动状态")) { |
||||
deviceItem.automaticText = |
||||
child.value === "0.000" ? "自动" : "手动"; |
||||
} else if (child.name.includes("故障报警")) { |
||||
deviceItem.warnText = |
||||
child.value === "0.000" ? "未故障" : "故障"; |
||||
} else if (child.name.includes("频率调节")) { |
||||
deviceItem.frequencySet = |
||||
child.value === "0.000" ? "0" : child.value; |
||||
deviceItem.frequencyId = child.id; |
||||
} else if (child.name.includes("频率反馈")) { |
||||
deviceItem.frequency = child.value; |
||||
} else if (child.name.includes("阀开反馈")) { |
||||
valveItem.openStauts = |
||||
child.value === "0.000" ? "关闭" : "开启"; |
||||
} else if ( |
||||
child.name.includes("阀开") && |
||||
!child.name.includes("反馈") |
||||
) { |
||||
valveItem.openText = child.value === "0.000" ? false : true; |
||||
valveItem.openId = child.id; |
||||
} else if ( |
||||
child.name.includes("阀关") && |
||||
!child.name.includes("反馈") |
||||
) { |
||||
valveItem.colseText = |
||||
child.value === "0.000" ? false : true; |
||||
valveItem.closeId = child.id; |
||||
} else if (child.name.includes("阀关反馈")) { |
||||
valveItem.closeStatus = |
||||
child.value === "0.000" ? "关闭" : "开启"; |
||||
} |
||||
} |
||||
}); |
||||
// console.log("处理后的每个对象", deviceItem); |
||||
// 将处理后的对象添加到 deviceList 中 |
||||
if (Object.keys(deviceItem).length > 1) { |
||||
this.deviceList.push(deviceItem); |
||||
} |
||||
// 将处理后的对象添加到 valveList 中 |
||||
if (Object.keys(valveItem).length > 1) { |
||||
this.valveList.push(valveItem); |
||||
} |
||||
} |
||||
}); |
||||
console.log("处理过的this.deviceList", this.deviceList); |
||||
console.log("处理过的this.valveList", this.valveList); |
||||
} |
||||
}); |
||||
}, |
||||
// 处理输入事件,过滤非数字字符 |
||||
handleInput(item) { |
||||
console.log("校验"); |
||||
// 实时校验并过滤非数字字符 |
||||
item.frequencySet = String(item.frequencySet).replace(/[^\d]/g, ""); |
||||
}, |
||||
handleEnter(item) { |
||||
console.log("请求后端"); |
||||
this.$confirm( |
||||
`确定要修改"${item.name}"的频率为:${item.frequencySet} Hz吗?"`, |
||||
"提示", |
||||
{ |
||||
confirmButtonText: "确定", |
||||
cancelButtonText: "取消", |
||||
type: "warning", |
||||
} |
||||
) |
||||
.then(() => { |
||||
this.operationConrol(item.frequencyId, item.frequencySet); |
||||
}) |
||||
.catch(() => { |
||||
// 用户取消操作,需要更新原来的频率 |
||||
this.getOperationList(); |
||||
}); |
||||
}, |
||||
//启停控制 |
||||
handleControlText(item) { |
||||
this.$confirm( |
||||
`确定要切换设备"${item.name}"的状态为:${ |
||||
item.controlText ? "开启" : "停止 吗?" |
||||
}`, |
||||
"提示", |
||||
{ |
||||
confirmButtonText: "确定", |
||||
cancelButtonText: "取消", |
||||
type: "warning", |
||||
} |
||||
) |
||||
.then(() => { |
||||
// 这里调用请求函数,示例中只是简单打印信息 |
||||
console.log("请求后台", item.controlText); |
||||
let param = null; |
||||
if (item.controlText) { |
||||
param = 1; |
||||
} else { |
||||
param = 0; |
||||
} |
||||
this.operationConrol(item.controlId, param); |
||||
}) |
||||
.catch(() => { |
||||
// 用户取消操作,恢复开关状态 |
||||
item.controlText = !item.controlText; |
||||
console.log("不请求后台"); |
||||
}); |
||||
}, |
||||
//蝶阀关闭控制 |
||||
handleValveClose(item) { |
||||
this.$confirm( |
||||
`确定要切换设备"${item.name}"的状态为:${ |
||||
item.closeText ? "开启" : "停止 吗?" |
||||
}`, |
||||
"提示", |
||||
{ |
||||
confirmButtonText: "确定", |
||||
cancelButtonText: "取消", |
||||
type: "warning", |
||||
} |
||||
) |
||||
.then(() => { |
||||
let param = null; |
||||
if (item.closeText) { |
||||
param = 1; |
||||
} else { |
||||
param = 0; |
||||
} |
||||
this.operationConrol(item.closeId, param); |
||||
}) |
||||
.catch(() => { |
||||
// 用户取消操作,恢复开关状态 |
||||
item.closeText = !item.closeText; |
||||
console.log("不请求后台"); |
||||
}); |
||||
}, |
||||
//蝶阀开启控制 |
||||
handleValveOpen(item) { |
||||
this.$confirm( |
||||
`确定要切换设备"${item.name}"的状态为:${ |
||||
item.openText ? "开启" : "停止 吗?" |
||||
}`, |
||||
"提示", |
||||
{ |
||||
confirmButtonText: "确定", |
||||
cancelButtonText: "取消", |
||||
type: "warning", |
||||
} |
||||
) |
||||
.then(() => { |
||||
let param = null; |
||||
if (item.openText) { |
||||
param = 1; |
||||
} else { |
||||
param = 0; |
||||
} |
||||
this.operationConrol(item.openId, param); |
||||
}) |
||||
.catch(() => { |
||||
// 用户取消操作,恢复开关状态 |
||||
item.openText = !item.openText; |
||||
console.log("不请求后台"); |
||||
}); |
||||
}, |
||||
operationConrol(id, param) { |
||||
let data = { |
||||
id: id, |
||||
param: param, |
||||
}; |
||||
console.log("操作参数", data); |
||||
operationConrol([data]).then((res) => { |
||||
if (res.code == 200) { |
||||
this.$modal.msgSuccess("操作成功"); |
||||
// 更新所有设备状态; |
||||
this.getOperationList(); |
||||
} else { |
||||
this.$modal.msgError("操作失败"); |
||||
// 更新所有设备状态; |
||||
this.getOperationList(); |
||||
} |
||||
}); |
||||
}, |
||||
}, |
||||
}; |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
/* 设备控制列表样式 */ |
||||
.device-container { |
||||
display: flex; |
||||
flex-direction: column; |
||||
width: 100%; |
||||
background-color: #142c4e; |
||||
padding: 10px 10px 30px 10px; |
||||
border-radius: 10px; |
||||
.device-li { |
||||
flex: 1; |
||||
width: 100%; |
||||
display: flex; |
||||
flex-direction: row; |
||||
align-items: center; |
||||
padding: 12px 0; |
||||
color: #abcdfc; |
||||
border-bottom: 1px dashed #0349ac; |
||||
.device-name { |
||||
flex: 1; |
||||
white-space: nowrap; |
||||
.run { |
||||
display: flex; |
||||
flex-direction: row; |
||||
align-items: center; |
||||
display: block; |
||||
} |
||||
.run::before { |
||||
content: ""; |
||||
display: inline-block; |
||||
width: 10px; |
||||
height: 10px; |
||||
background-color: rgb(16, 231, 16); |
||||
border-radius: 50%; |
||||
margin-right: 5px; |
||||
} |
||||
.no-run { |
||||
display: flex; |
||||
flex-direction: row; |
||||
align-items: center; |
||||
display: block; |
||||
} |
||||
.no-run::before { |
||||
content: ""; |
||||
display: inline-block; |
||||
width: 10px; |
||||
height: 10px; |
||||
background-color: rgb(180, 180, 180); |
||||
border-radius: 50%; |
||||
margin-right: 5px; |
||||
} |
||||
.el-input { |
||||
width: 100px; |
||||
} |
||||
.strong-electric { |
||||
background-color: rgba(59, 130, 246, 0.2); |
||||
color: #60a5fa; |
||||
padding: 5px 20px; |
||||
border-radius: 10px; |
||||
} |
||||
.auto-electric { |
||||
background-color: rgba(231, 144, 45, 0.2); |
||||
color: #e47f21; |
||||
padding: 5px 20px; |
||||
border-radius: 10px; |
||||
} |
||||
.good-status { |
||||
color: #4ade80; |
||||
} |
||||
.bad-status { |
||||
color: #f05348; |
||||
} |
||||
} |
||||
} |
||||
.device-li:nth-child(1) { |
||||
color: #9ca3af; |
||||
} |
||||
} |
||||
.second { |
||||
margin-top: 20px; |
||||
} |
||||
|
||||
/* 状态统计样式 */ |
||||
.status-statistics { |
||||
margin-bottom: 25px; |
||||
display: flex; |
||||
flex-direction: row; |
||||
justify-content: space-between; |
||||
} |
||||
|
||||
.status-card { |
||||
background-color: #142c4e; |
||||
border-radius: 10px; |
||||
padding: 10px; |
||||
width: 24%; |
||||
} |
||||
|
||||
.status-label { |
||||
color: #9ca3af; |
||||
margin-bottom: 20px; |
||||
} |
||||
|
||||
.status-value-running { |
||||
font-size: 24px; |
||||
font-weight: bold; |
||||
color: #22c55e; |
||||
} |
||||
|
||||
.status-value-auto { |
||||
font-size: 24px; |
||||
font-weight: bold; |
||||
color: #60a5fa; |
||||
} |
||||
|
||||
.status-value-error { |
||||
font-size: 24px; |
||||
font-weight: bold; |
||||
color: #ef4444; |
||||
} |
||||
|
||||
.status-value-maintenance { |
||||
font-size: 24px; |
||||
font-weight: bold; |
||||
color: #f59e0b; |
||||
} |
||||
</style> |
@ -0,0 +1,120 @@
|
||||
<template> |
||||
<div class="line-container"> |
||||
<!-- 第一个圆点 --> |
||||
<div class="dot dot-start"></div> |
||||
<!-- 第一条直线 --> |
||||
<div |
||||
class="line line1" |
||||
:style="{ |
||||
transform: `rotate(${angle1}deg)`, |
||||
width: lineWidth1Rem + 'rem' |
||||
}" |
||||
></div> |
||||
<!-- 中间圆点 --> |
||||
<div |
||||
class="dot dot-mid" |
||||
:style="{ |
||||
top: (1 + Math.sin((angle1 * Math.PI) / 180) * lineWidth1Rem - 0.025) + 'rem', |
||||
left: (1 + Math.cos((angle1 * Math.PI) / 180) * lineWidth1Rem - 0.025) + 'rem' |
||||
}" |
||||
></div> |
||||
<!-- 第二条直线 --> |
||||
<div |
||||
class="line line2" |
||||
:style="{ |
||||
top: (1 + Math.sin((angle1 * Math.PI) / 180) * lineWidth1Rem) + 'rem', |
||||
left: (1 + Math.cos((angle1 * Math.PI) / 180) * lineWidth1Rem) + 'rem', |
||||
transform: `rotate(${angle2}deg)`, |
||||
width: lineWidth2Rem + 'rem' |
||||
}" |
||||
></div> |
||||
<!-- 最后一个圆点 --> |
||||
<div |
||||
class="dot dot-end" |
||||
:style="{ |
||||
top: endDotTop + 'rem', |
||||
left: endDotLeft + 'rem' |
||||
}" |
||||
></div> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
props: { |
||||
// 第一条直线的角度 |
||||
angle1: { |
||||
type: Number, |
||||
default: 0 |
||||
}, |
||||
// 第二条直线的角度 |
||||
angle2: { |
||||
type: Number, |
||||
default: 0 |
||||
}, |
||||
// 第一条直线的宽度(px) |
||||
lineWidth1: { |
||||
type: Number, |
||||
default: 100 |
||||
}, |
||||
// 第二条直线的宽度(px) |
||||
lineWidth2: { |
||||
type: Number, |
||||
default: 100 |
||||
} |
||||
}, |
||||
computed: { |
||||
lineWidth1Rem() { |
||||
return this.lineWidth1 / 100; |
||||
}, |
||||
lineWidth2Rem() { |
||||
return this.lineWidth2 / 100; |
||||
}, |
||||
endDotTop() { |
||||
// 第一条直线终点的 y 坐标 |
||||
const firstLineEndY = 1 + Math.sin((this.angle1 * Math.PI) / 180) * this.lineWidth1Rem; |
||||
// 第二条直线在第一条直线基础上终点的 y 坐标偏移量 |
||||
const secondLineYOffset = Math.sin((this.angle2 * Math.PI) / 180) * this.lineWidth2Rem; |
||||
return firstLineEndY + secondLineYOffset - 0.025; |
||||
}, |
||||
endDotLeft() { |
||||
// 第一条直线终点的 x 坐标 |
||||
const firstLineEndX = 1 + Math.cos((this.angle1 * Math.PI) / 180) * this.lineWidth1Rem; |
||||
// 第二条直线在第一条直线基础上终点的 x 坐标偏移量 |
||||
const secondLineXOffset = Math.cos((this.angle2 * Math.PI) / 180) * this.lineWidth2Rem; |
||||
return firstLineEndX + secondLineXOffset - 0.025; |
||||
} |
||||
} |
||||
}; |
||||
</script> |
||||
|
||||
<style scoped> |
||||
.line-container { |
||||
position: relative; |
||||
} |
||||
|
||||
.line { |
||||
position: absolute; |
||||
height: 1px; |
||||
background-color: rgba(0, 255, 255, 0.3); |
||||
transform-origin: left center; |
||||
} |
||||
|
||||
.line1 { |
||||
top: 1rem; |
||||
left: 1rem; |
||||
} |
||||
|
||||
.dot { |
||||
position: absolute; |
||||
width: 0.05rem; |
||||
height: 0.05rem; |
||||
background-color: aqua; |
||||
border-radius: 50%; |
||||
} |
||||
|
||||
.dot-start { |
||||
top: 0.97rem; |
||||
left: 0.97rem; |
||||
} |
||||
</style> |
@ -0,0 +1,578 @@
|
||||
<template> |
||||
<div class="energy_content"> |
||||
<div class="sys_charts" ref="sys_charts"></div> |
||||
<div class="eer">实时EER</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import * as echarts from "echarts"; |
||||
import { viewMainParams } from "@/api/index"; |
||||
export default { |
||||
data() { |
||||
return { |
||||
chartInstance: null, |
||||
option: {}, |
||||
isShowModule: false, |
||||
energyCostText: "eer数据", |
||||
dateType: "", |
||||
dateUse: "", |
||||
timeType: "", //时间类型 |
||||
startTime: "", |
||||
endTime: "", |
||||
backData: { |
||||
usedValue: "0", |
||||
maxValue: 100, //最大的刻度值 |
||||
momValueRate: "0%", |
||||
yoyValueRate: "0%", |
||||
usedMoney: "0", |
||||
maxMoney: 100, |
||||
momMoneyRate: "0%", |
||||
yoyMoneyRate: "0%", |
||||
}, |
||||
useForm: { |
||||
useData: 5, |
||||
maxData: 10, //最大的刻度值 |
||||
}, |
||||
}; |
||||
}, |
||||
mounted() { |
||||
this.initChart(); |
||||
this.screenAdapter(); |
||||
window.addEventListener("resize", this.screenAdapter); |
||||
this.getChartsData(); |
||||
}, |
||||
destroyed() { |
||||
//与mounted中的监听对应,在组件销毁的时候,需要将监听器取消掉 |
||||
window.removeEventListener("resize", this.screenAdapter); |
||||
}, |
||||
methods: { |
||||
// 计算颜色设置的函数 |
||||
getAxisLineColor(useData, maxData) { |
||||
// 计算阈值 |
||||
// 真实值大于最大值的0.75才使用颜色渐变 |
||||
const threshold = maxData * 0.75; |
||||
|
||||
// 判断实际值是否超过阈值 |
||||
if (useData > threshold) { |
||||
return [ |
||||
[ |
||||
useData / maxData, |
||||
new echarts.graphic.LinearGradient(0, 0, 1, 0, [ |
||||
{ offset: 0, color: "rgba(0,127,208,1)" }, |
||||
{ offset: 0.6, color: "rgba(0,127,208,1)" }, |
||||
{ offset: 1, color: "rgba(69, 235, 167,0.5)" }, |
||||
]), |
||||
], |
||||
[1, "rgba(28,128,245,.0)"], |
||||
]; |
||||
} else { |
||||
return [ |
||||
[ |
||||
useData / maxData, |
||||
new echarts.graphic.LinearGradient(0, 0, 1, 0, [ |
||||
{ offset: 0, color: "rgba(0,127,208,1)" }, |
||||
{ offset: 0.5, color: "rgba(0,127,208,1)" }, |
||||
{ offset: 1, color: "rgba(0,127,208,1)" }, |
||||
]), |
||||
], |
||||
[1, "rgba(28,128,245,.0)"], |
||||
]; |
||||
} |
||||
}, |
||||
//初始化chartInstance2对象 折线图 |
||||
initChart() { |
||||
// 使用配置函数 |
||||
const axisLineColor = this.getAxisLineColor( |
||||
this.useForm.useData, |
||||
this.useForm.maxData |
||||
); |
||||
this.chartInstance = echarts.init(this.$refs.sys_charts); |
||||
// var dataArr = 80; |
||||
this.option = { |
||||
backgroundColor: "transparent", |
||||
tooltip: { |
||||
formatter: "{a} <br/>{b} : {c}", |
||||
}, |
||||
series: [ |
||||
{ |
||||
name: "内部动态阴影", |
||||
type: "gauge", |
||||
center: ["50%", "100%"], |
||||
startAngle: 180, |
||||
endAngle: -0, |
||||
radius: "155%", |
||||
z: 1, |
||||
splitNumber: 10, |
||||
axisLine: { |
||||
lineStyle: { |
||||
color: axisLineColor, |
||||
// 相当于阴影部分的直径 |
||||
// width: 80, |
||||
}, |
||||
}, |
||||
axisLabel: { |
||||
show: false, |
||||
}, |
||||
axisTick: { |
||||
show: false, |
||||
}, |
||||
splitLine: { |
||||
show: false, |
||||
}, |
||||
itemStyle: { |
||||
show: false, |
||||
}, |
||||
textStyle: { |
||||
formatter: function (value) { |
||||
if (value !== 0) { |
||||
return parseInt(value); |
||||
} else { |
||||
return 0; |
||||
} |
||||
}, |
||||
offsetCenter: [0, 5], |
||||
detail: { |
||||
padding: [0, 0, 0, 0], |
||||
// fontSize: titleFontSize * 1.2, |
||||
color: "#EDFFFD", |
||||
}, |
||||
}, |
||||
title: { |
||||
//标题 |
||||
show: false, |
||||
}, |
||||
pointer: { |
||||
show: false, |
||||
}, |
||||
}, |
||||
{ |
||||
// 新增的蓝色背景 |
||||
name: "蓝色背景", |
||||
type: "gauge", |
||||
center: ["50%", "100%"], |
||||
// 自定义起始角度 |
||||
startAngle: 200, |
||||
// 自定义结束角度 |
||||
endAngle: -20, |
||||
radius: "155%", |
||||
z: 0, // 确保它在最底层 |
||||
splitNumber: 10, |
||||
axisLine: { |
||||
lineStyle: { |
||||
color: [ |
||||
[1, "#01366d"], // 设置背景颜色为蓝色 |
||||
], |
||||
}, |
||||
}, |
||||
axisLabel: { |
||||
show: false, |
||||
}, |
||||
axisTick: { |
||||
show: false, |
||||
}, |
||||
splitLine: { |
||||
show: false, |
||||
}, |
||||
itemStyle: { |
||||
show: false, |
||||
}, |
||||
textStyle: { |
||||
show: false, |
||||
}, |
||||
title: { |
||||
show: false, |
||||
}, |
||||
pointer: { |
||||
show: false, |
||||
}, |
||||
}, |
||||
{ |
||||
name: "内部大边框", |
||||
type: "gauge", |
||||
z: 2, |
||||
min: 0, |
||||
max: this.useForm.maxData, |
||||
splitNumber: 10, |
||||
radius: "180%", |
||||
center: ["50%", "100%"], |
||||
startAngle: 180, |
||||
endAngle: -0, |
||||
axisLine: { |
||||
lineStyle: { |
||||
color: [[1, "#023B80"]], |
||||
width: 3, |
||||
// 阴影 |
||||
shadowColor: "rgba(14,31,73)", |
||||
shadowBlur: 6, |
||||
shadowOffsetX: 0, |
||||
}, |
||||
}, |
||||
tooltip: { |
||||
show: false, |
||||
}, |
||||
axisLabel: { |
||||
show: false, |
||||
}, |
||||
axisTick: { |
||||
show: false, |
||||
}, |
||||
splitLine: { |
||||
show: false, |
||||
}, |
||||
itemStyle: { |
||||
show: false, |
||||
}, |
||||
detail: { |
||||
show: false, |
||||
}, |
||||
title: { |
||||
//标题 |
||||
show: false, |
||||
}, |
||||
pointer: { |
||||
show: false, |
||||
}, |
||||
}, |
||||
{ |
||||
name: "指针上的圆", |
||||
//指针上的圆 |
||||
type: "pie", |
||||
tooltip: { |
||||
show: false, |
||||
}, |
||||
emphasis: { |
||||
scale: false, // 新版的配置 |
||||
}, |
||||
legendHoverLink: false, |
||||
radius: ["0%", "70%"], |
||||
center: ["50%", "100%"], |
||||
startAngle: 120, |
||||
endAngle: -0, |
||||
labelLine: { |
||||
show: false, |
||||
}, |
||||
axisLine: { |
||||
lineStyle: { |
||||
color: [[1, "#F2BF59"]], |
||||
width: 3, |
||||
// 阴影 |
||||
shadowColor: "rgba(14,31,73)", |
||||
shadowBlur: 60, |
||||
shadowOffsetX: 0, |
||||
}, |
||||
}, |
||||
label: { |
||||
show: false, |
||||
}, |
||||
data: [ |
||||
{ |
||||
value: 120, |
||||
itemStyle: { |
||||
color: "#00223a", |
||||
}, |
||||
}, |
||||
], |
||||
z: 4, |
||||
}, |
||||
{ |
||||
name: "指针上的渐变圆", |
||||
//指针上的圆-渐变 |
||||
type: "pie", |
||||
tooltip: { |
||||
show: false, |
||||
}, |
||||
emphasis: { |
||||
scale: false, // 新版的配置 |
||||
}, |
||||
legendHoverLink: false, |
||||
radius: ["0%", "70%"], |
||||
center: ["50%", "100%"], |
||||
startAngle: 120, |
||||
endAngle: 0, |
||||
labelLine: { |
||||
show: false, |
||||
}, |
||||
axisLine: { |
||||
lineStyle: { |
||||
color: [[1, "#F2BF59"]], |
||||
width: 3, |
||||
// 阴影 |
||||
shadowColor: "rgba(14,31,73)", |
||||
shadowBlur: 60, |
||||
shadowOffsetX: 0, |
||||
}, |
||||
}, |
||||
z: 5, |
||||
}, |
||||
{ |
||||
// 指针 数据 |
||||
name: this.energyCostText, |
||||
type: "gauge", |
||||
radius: "175%", |
||||
center: ["50%", "100%"], |
||||
min: 0, //最小刻度 |
||||
max: this.useForm.maxData, //最大刻度 |
||||
splitNumber: 0, //刻度数量 |
||||
startAngle: 180, |
||||
endAngle: -0, |
||||
axisLine: { |
||||
show: false, |
||||
}, //仪表盘轴线 |
||||
axisLabel: { |
||||
show: true, |
||||
color: "rgba(4,112,212,1)", |
||||
// distance: 16, |
||||
// fontSize: 12, |
||||
formatter: (value) => { |
||||
// 仅显示 0 和最大值 |
||||
if (value === 0 || value == this.useForm.maxData) { |
||||
// 替换 100 为你的最大值 |
||||
return value; |
||||
} |
||||
return ""; |
||||
}, |
||||
}, //刻度标签-数字。 |
||||
axisTick: { |
||||
show: true, |
||||
// splitNumber: 5, |
||||
lineStyle: { |
||||
color: "rgba(4,112,212,1)", //用颜色渐变函数不起作用 |
||||
// width: 3, |
||||
}, |
||||
// length: 6, |
||||
}, //刻度样式 |
||||
splitLine: { |
||||
show: true, |
||||
// length: 6, |
||||
lineStyle: { |
||||
color: "rgba(106, 104, 228, 0.5)", //用颜色渐变函数不起作用 |
||||
}, |
||||
}, //分隔线样式 |
||||
itemStyle: { |
||||
show: false, |
||||
}, |
||||
detail: { |
||||
show: false, |
||||
}, |
||||
title: { |
||||
//标题 |
||||
show: false, |
||||
}, |
||||
data: [ |
||||
{ |
||||
name: this.dateUse, |
||||
value: this.useForm.useData, |
||||
}, |
||||
], |
||||
itemStyle: { |
||||
color: "#EDF85B", |
||||
}, |
||||
pointer: { |
||||
show: true, |
||||
length: "60%", |
||||
radius: "30%", |
||||
shape: "triangle", // 使用内置的箭头形状 |
||||
// width: 15, //指针粗细 |
||||
itemStyle: { |
||||
color: "rgb(3, 105, 206,0.5)", // 指针的颜色 |
||||
// shadowColor: "rgb(104, 194, 247, 1)", // 朦胧光的颜色 |
||||
shadowBlur: 20, // 朦胧光的模糊度 |
||||
}, |
||||
}, |
||||
animationDuration: 4000, |
||||
z: 2, |
||||
}, |
||||
], |
||||
}; |
||||
//把配置项给实例对象 |
||||
this.chartInstance.setOption(this.option, true); |
||||
}, |
||||
screenAdapter() { |
||||
const titleFontSize = this.$refs.sys_charts.offsetWidth / 18; |
||||
const adapterOption = { |
||||
series: [ |
||||
{ |
||||
name: "内部动态阴影", |
||||
type: "gauge", |
||||
axisLine: { |
||||
lineStyle: { |
||||
width: titleFontSize * 1, |
||||
}, |
||||
}, |
||||
}, |
||||
{ |
||||
name: "蓝色背景", |
||||
type: "gauge", |
||||
axisLine: { |
||||
lineStyle: { |
||||
width: titleFontSize * 1, |
||||
}, |
||||
}, |
||||
}, |
||||
{ |
||||
// 指针 数据 |
||||
name: this.energyCostText, |
||||
axisLabel: { |
||||
distance: titleFontSize, |
||||
fontSize: titleFontSize / 4, |
||||
}, |
||||
axisTick: { |
||||
distance: -(titleFontSize / 70), |
||||
lineStyle: { |
||||
width: titleFontSize / 20, |
||||
}, |
||||
length: titleFontSize / 5, |
||||
}, //刻度样式 |
||||
splitLine: { |
||||
distance: -(titleFontSize / 70), |
||||
lineStyle: { |
||||
width: titleFontSize / 20, |
||||
}, |
||||
length: titleFontSize / 3.6, |
||||
}, //分隔线样式 |
||||
pointer: { |
||||
width: titleFontSize / 2, //指针粗细 |
||||
}, |
||||
}, |
||||
], |
||||
}; |
||||
this.chartInstance.setOption(adapterOption); |
||||
this.chartInstance.resize(); |
||||
}, |
||||
// 请求的数据 |
||||
getChartsData() { |
||||
viewMainParams().then((res) => { |
||||
console.log("系统参数返回", res); |
||||
console.log("冷源监控返回",res.rows[0]); |
||||
if (res.code == 200) { |
||||
this.useForm.maxData = 10; |
||||
this.useForm.useData = res.rows[0].values[0].value; |
||||
let that = this; |
||||
// 使用配置函数 |
||||
const axisLineColor = this.getAxisLineColor( |
||||
this.useForm.useData, |
||||
this.useForm.maxData |
||||
); |
||||
const adapterOption = { |
||||
series: [ |
||||
{ |
||||
name: "内部动态阴影", |
||||
axisLine: { |
||||
lineStyle: { |
||||
color: axisLineColor, |
||||
// 相当于阴影部分的直径 |
||||
// width: 80, |
||||
}, |
||||
}, |
||||
}, |
||||
{ |
||||
name: "内部大边框", |
||||
min: 0, |
||||
max: this.useForm.maxData, |
||||
}, |
||||
{ |
||||
name: "指针上的圆", |
||||
data: [ |
||||
{ |
||||
value: 5, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
name: "指针上的渐变圆", |
||||
label: { |
||||
show: true, |
||||
position: "center", // 文字显示在中心位置 |
||||
offset: [0, -5], // 向上偏移 10 个单位 |
||||
formatter: function () { |
||||
// 返回 HTML 标签,使用 rich 里定义的样式 |
||||
return `{line|${that.useForm.useData}}`; |
||||
}, |
||||
rich: { |
||||
line: { |
||||
color: "#fff", // 第二行文字颜色 |
||||
fontSize: 20, // 第二行文字大小 |
||||
lineHeight: 0, // 行高,实现间距 |
||||
}, |
||||
}, |
||||
}, |
||||
data: [ |
||||
{ |
||||
value: 0, |
||||
itemStyle: { |
||||
// 设置渐变颜色 |
||||
color: { |
||||
type: "linear", |
||||
x: 0, |
||||
y: 0, |
||||
x2: 0, |
||||
y2: 1, |
||||
colorStops: [ |
||||
{ |
||||
offset: 0, |
||||
color: "rgb(4,112,212)", // 顶部颜色 |
||||
}, |
||||
{ |
||||
offset: 0.3, |
||||
color: "rgba(0, 46, 93)", // 底部透明 |
||||
}, |
||||
], |
||||
global: false, // 缺省为 false |
||||
}, |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
// 指针 数据 |
||||
name: this.energyCostText, |
||||
max: this.useForm.maxData, //最大刻度 |
||||
axisLabel: { |
||||
formatter: (value) => { |
||||
// 仅显示 0 和最大值 |
||||
if (value === 0 || value == this.useForm.maxData) { |
||||
// 替换 100 为你的最大值 |
||||
return value; |
||||
} |
||||
return ""; |
||||
}, |
||||
}, |
||||
data: [ |
||||
{ |
||||
name: this.dateUse, |
||||
value: this.useForm.useData, |
||||
}, |
||||
], |
||||
}, |
||||
], |
||||
}; |
||||
this.chartInstance.setOption(adapterOption); |
||||
//手动的调用图标对象的resize才能产生效果 |
||||
this.chartInstance.resize(); |
||||
} |
||||
}); |
||||
}, |
||||
}, |
||||
}; |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.energy_content { |
||||
display: flex; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
justify-content: center; |
||||
width: 100% !important; |
||||
height: 100%; |
||||
|
||||
.sys_charts { |
||||
width: 100%; |
||||
height: 1.6rem; |
||||
} |
||||
.eer { |
||||
font-size: 18px; |
||||
margin-top: 25px; |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,293 @@
|
||||
<template> |
||||
<div style="width: 100%; height: 100%"> |
||||
<div class="right-table"> |
||||
<div class="choice"> |
||||
<div |
||||
class="mr20" |
||||
v-for="(item, index) in energyTypes" |
||||
:key="index" |
||||
@click="handleEnter(index, item.name)" |
||||
:class="{ timeStyle: sharedIndex == index }" |
||||
> |
||||
{{ item.name }} |
||||
</div> |
||||
</div> |
||||
<div class="charts" ref="chart_ref"></div> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import * as echarts from "echarts"; |
||||
import { viewYearEnergy } from "@/api/index"; |
||||
export default { |
||||
data() { |
||||
return { |
||||
energyTypes: [], |
||||
sharedIndex: 0, |
||||
chartInstance: null, |
||||
option: {}, |
||||
colorList: [ |
||||
{ |
||||
color: "#00CED1", |
||||
offsetColor1: "rgba(0, 206, 209, 0.5)", |
||||
offsetColor2: "rgba(0, 206, 209, 0)", |
||||
}, |
||||
{ |
||||
color: "#ffe21e", |
||||
offsetColor1: "rgba(255,226,30, 0.5)", |
||||
offsetColor2: "rgba(255,226,30, 0)", |
||||
}, |
||||
{ |
||||
color: "#1a69f1", |
||||
offsetColor1: "rgba(26, 105, 241, 0.5)", |
||||
offsetColor2: "rgba(26, 105, 241, 0)", |
||||
}, |
||||
{ |
||||
color: "#2df499", |
||||
offsetColor1: "rgba(45,244,153, 0.5)", |
||||
offsetColor2: "rgba(45,244,153, 0)", |
||||
}, |
||||
{ |
||||
color: "#e87b4b", |
||||
offsetColor1: "rgba(232, 123, 75, 0.5)", |
||||
offsetColor2: "rgba(232, 123, 75, 0)", |
||||
}, |
||||
], |
||||
}; |
||||
}, |
||||
mounted() { |
||||
this.initChart(); |
||||
window.addEventListener("resize", this.screenAdapter); |
||||
this.screenAdapter(); |
||||
this.echartsData(); |
||||
}, |
||||
destroyed() { |
||||
//取消监听器 |
||||
window.removeEventListener("resize", this.screenAdapter); |
||||
}, |
||||
methods: { |
||||
// 选择日月年 |
||||
handleEnter(index, event) { |
||||
console.log("index", index); |
||||
console.log("event", event); |
||||
this.chartInstance.dispose(); |
||||
this.initChart(); |
||||
this.sharedIndex = index; |
||||
// 使用 find 方法查找符合条件的对象 |
||||
const chartsObj = this.energyTypes.find((item) => item.name === event); |
||||
const colorObj = this.colorList.find( |
||||
(_, currentIndex) => currentIndex === index |
||||
); |
||||
console.log("当前要渲染的数据对象", chartsObj); |
||||
console.log("当前要渲染的颜色对象", colorObj); |
||||
let adapterOption = {}; |
||||
// 添加折线的配置 |
||||
adapterOption = { |
||||
tooltip: { |
||||
trigger: "axis", |
||||
// 自定义 tooltip 内容 |
||||
formatter: function (params) { |
||||
var res = params[0].name + "<br/>"; |
||||
for (var i = 0, l = params.length; i < l; i++) { |
||||
var seriesName = params[i].seriesName; |
||||
var value = params[i].value; |
||||
var marker = |
||||
'<span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:' + |
||||
params[i].color + |
||||
'"></span>'; |
||||
// 根据不同德seriesName 返回不同的单位 |
||||
if (chartsObj.unit) { |
||||
res += |
||||
marker + |
||||
seriesName + |
||||
":" + |
||||
'<span style="color: #000000; font-weight: bold;margin-left:5px">' + |
||||
value + |
||||
chartsObj.unit + |
||||
"</span><br>"; |
||||
} else { |
||||
res += |
||||
marker + |
||||
seriesName + |
||||
":" + |
||||
'<span style="color: #000000; font-weight: bold;margin-left:5px">' + |
||||
value + |
||||
"</span><br>"; |
||||
} |
||||
} |
||||
return res; |
||||
}, |
||||
}, |
||||
xAxis: { |
||||
data: chartsObj.timeStr, |
||||
}, |
||||
yAxis: { |
||||
name: chartsObj.unit, |
||||
}, |
||||
series: [ |
||||
{ |
||||
data: chartsObj.data, |
||||
name: event, |
||||
//折线颜色 |
||||
itemStyle: { |
||||
color: colorObj.color, //折线的颜色 |
||||
}, |
||||
lineStyle: { |
||||
color: colorObj.color, //折线点的颜色 |
||||
}, |
||||
areaStyle: { |
||||
color: { |
||||
type: "linear", |
||||
x: 0, |
||||
y: 0, |
||||
x2: 0, |
||||
y2: 1, |
||||
colorStops: [ |
||||
{ |
||||
offset: 0, |
||||
color: colorObj.offsetColor1, // 渐变起始颜色 |
||||
}, |
||||
{ |
||||
offset: 1, |
||||
color: colorObj.offsetColor2, // 渐变结束颜色 |
||||
}, |
||||
], |
||||
global: false, // 缺省为 false |
||||
}, |
||||
}, |
||||
}, |
||||
], |
||||
}; |
||||
//记得重新给配置项给实例对象。只要实例对象.chartInstance不变,option就可以多次配置不同的条件。也可以配置一个dataoption只写需要从后台请求的数据相关 |
||||
this.chartInstance.setOption(adapterOption); |
||||
//手动的调用图标对象的resize才能产生效果 |
||||
this.chartInstance.resize(); |
||||
}, |
||||
// 折线图自适应+ 根据按钮切换图例仅限一条且不可点击+ 折线图数据 |
||||
screenAdapter() { |
||||
//自己定义的比较合适的适配大小,2.6 mes_ref是图表盒子 |
||||
const titleFontSize = this.$refs.chart_ref.offsetWidth / 130; |
||||
//因为option可以多次配置的,所以这里的option只需要写 需要配置大小的相关数据 |
||||
const adapterOption = {}; |
||||
//记得重新给配置项给实例对象。只要实例对象.chartInstance不变,option就可以多次配置不同的条件。也可以配置一个dataoption只写需要从后台请求的数据相关 |
||||
this.chartInstance.setOption(adapterOption); |
||||
//手动的调用图标对象的resize才能产生效果 |
||||
this.chartInstance.resize(); |
||||
}, |
||||
//初始化chartInstance对象 |
||||
initChart() { |
||||
this.chartInstance = echarts.init(this.$refs.chart_ref); |
||||
this.option = { |
||||
tooltip: { |
||||
trigger: "item", |
||||
}, |
||||
legend: { |
||||
show: false, |
||||
}, |
||||
grid: { |
||||
top: "10%", |
||||
left: "4%", |
||||
right: "6%", |
||||
bottom: "3%", |
||||
containLabel: true, |
||||
}, |
||||
xAxis: { |
||||
type: "category", |
||||
//设置为true代表离零刻度间隔一段距离 |
||||
boundaryGap: true, |
||||
// 修饰刻度标签的颜色即x坐标数据 |
||||
axisLabel: { |
||||
// interval: 0, //强制显示所有x轴数据 |
||||
// rotate: 30, //x轴坐标字体倾斜30度 |
||||
color: "rgba(255, 255, 255, 1)", |
||||
}, |
||||
axisTick: { |
||||
show: false, // 不显示坐标轴刻度线 |
||||
}, |
||||
// x坐标轴的颜色 |
||||
axisLine: { |
||||
show: true, |
||||
lineStyle: { |
||||
color: "#365576", |
||||
}, |
||||
}, |
||||
splitLine: { |
||||
lineStyle: { |
||||
color: "#e2e6f0", |
||||
}, |
||||
}, //x轴分割线 |
||||
}, |
||||
yAxis: { |
||||
min: 0, |
||||
// max:20, |
||||
// // // min:'dataMin', |
||||
// // // max:'dataMax', |
||||
// name: "kwh", // 第一个 y 轴的单位描述 |
||||
// 设置 name 的样式 |
||||
nameTextStyle: { |
||||
color: "rgba(255, 255, 255, 1)", |
||||
fontSize: 12, |
||||
}, |
||||
miniInterval: 5, |
||||
type: "value", |
||||
// 修饰刻度标签的颜色即y坐标数据 |
||||
axisLabel: { |
||||
color: "rgba(255, 255, 255, 1)", |
||||
}, |
||||
// 显示y坐标轴 |
||||
axisLine: { |
||||
show: true, |
||||
lineStyle: { |
||||
color: "#365576", // 设置 y 轴线的颜色 |
||||
}, |
||||
}, |
||||
//y轴分割线段数 |
||||
// splitNumber: 10, |
||||
// 修改y轴分割线的颜色 |
||||
splitLine: { |
||||
lineStyle: { |
||||
color: "#1a3d62", // 设置分割线的颜色 |
||||
type: "dashed", // 设置分割线为虚线 |
||||
}, |
||||
}, |
||||
}, |
||||
series: [ |
||||
{ |
||||
type: "line", |
||||
// 拐点大小 |
||||
symbolSize: 8, |
||||
}, |
||||
], |
||||
}; |
||||
//把配置项给实例对象 |
||||
this.chartInstance.setOption(this.option, true); |
||||
}, |
||||
echartsData() { |
||||
viewYearEnergy().then((res) => { |
||||
console.log("折线图返回值", res); |
||||
this.energyTypes = res.rows; |
||||
// 处理值 |
||||
// 在组件挂载完成后调用 handleEnter 方法 |
||||
if (this.energyTypes.length > 0) { |
||||
this.handleEnter(0, this.energyTypes[0].name); |
||||
} |
||||
}); |
||||
}, |
||||
}, |
||||
}; |
||||
</script> |
||||
<style lang="scss" scoped> |
||||
.right-table { |
||||
padding: 27px 15px 35px 15px; |
||||
} |
||||
.mr20 { |
||||
width: 92px; |
||||
padding: 2px; |
||||
} |
||||
.charts { |
||||
margin-top: 20px; |
||||
width: 100%; |
||||
height: 300px; |
||||
} |
||||
</style> |
@ -0,0 +1,330 @@
|
||||
<template> |
||||
<div class="app-container"> |
||||
<div class="left-tree"> |
||||
<!-- 为 el-tree 设置一个固定的高度和滚动条 --> |
||||
<div style="height: 550px; overflow-y: auto"> |
||||
<el-tree |
||||
ref="tree" |
||||
:data="treeData" |
||||
node-key="id" |
||||
:default-expand-all="false" |
||||
:default-expanded-keys="expandedKeys" |
||||
:auto-expand-parent="true" |
||||
icon-class="none" |
||||
@node-expand="handleNodeExpand" |
||||
@node-collapse="handleNodeCollapse" |
||||
:highlight-current="true" |
||||
@node-click="handleNodeClick" |
||||
> |
||||
<template #default="{ node }"> |
||||
<span class="custom-tree-node"> |
||||
<!-- 根据节点状态动态设置图标类名 --> |
||||
<div class="tree-left"> |
||||
<i :class="getIconClass(node)" class="custom-tree-icon"></i> |
||||
<span class="tree-label">{{ node.label }}</span> |
||||
</div> |
||||
</span> |
||||
</template> |
||||
</el-tree> |
||||
</div> |
||||
<div class="status"> |
||||
<div class="status-li"> |
||||
<div class="status1">正常</div> |
||||
<div>0个</div> |
||||
</div> |
||||
<div class="status-li"> |
||||
<div class="status2">报警</div> |
||||
<div>0个</div> |
||||
</div> |
||||
<div class="status-li"> |
||||
<div class="status3">异常</div> |
||||
<div>0个</div> |
||||
</div> |
||||
<div class="status-li"> |
||||
<div class="status4">离线</div> |
||||
<div>0个</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class="right-monitor"> |
||||
<div> |
||||
<div class="buildingDiv"> |
||||
<img |
||||
class="title-bg" |
||||
src="../../../assets/images/title-bg.png" |
||||
alt="" |
||||
/> |
||||
<div class="title-word">{{ buildingName }}</div> |
||||
</div> |
||||
<div class="monitor-context" v-loading="loading"></div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import { spaceTree } from "@/api/region"; |
||||
import { waterOperateList, operationConrol } from "@/api/hotWater/waterControl"; |
||||
export default { |
||||
data() { |
||||
return { |
||||
loading: false, |
||||
buildingName: "", |
||||
treeData: [], |
||||
defaultProps: { |
||||
children: "children", |
||||
label: "label", |
||||
}, |
||||
deviceList: [], |
||||
expandedKeys: [], |
||||
currentId: "", //当前选中高亮的id |
||||
currentName: "", //当前选中的名称 |
||||
currentLevel: "", //当前节点的层级 |
||||
currentParentId: "", //当前节点的上级的id |
||||
}; |
||||
}, |
||||
mounted() { |
||||
this.getSysBuild(); |
||||
}, |
||||
methods: { |
||||
getSysBuild() { |
||||
spaceTree().then((res) => { |
||||
console.log("楼栋返回值", res); |
||||
if (res.code == 200) { |
||||
// 只需要保留热水的系统 |
||||
console.log("楼栋返回值", res); |
||||
let newRes = { ...res }; |
||||
|
||||
if (newRes.data && newRes.data[0] && newRes.data[0].children) { |
||||
newRes.data[0].children = newRes.data[0].children.filter((item) => { |
||||
// 假设子项有一个 label属性,用于检查是否包含 "热水" |
||||
return item.label && item.label.includes("热水"); |
||||
}); |
||||
} |
||||
// 指定要保留的最大层级(从 1 开始计数),这里假设指定为第 2 级 |
||||
const targetLevel = 4; |
||||
// 从 data[0] 开始处理,当前层级为 1 |
||||
if (newRes.data[0]) { |
||||
this.removeChildrenAfterLevel(newRes.data[0], 1, targetLevel); |
||||
} |
||||
console.log("筛选后的新结果", newRes); |
||||
this.treeData = newRes.data; |
||||
this.$nextTick(() => { |
||||
this.$refs.tree.setCurrentKey(this.treeData[0].id); |
||||
}); |
||||
console.log("this.treeData[0].id", this.treeData[0].id); |
||||
console.log("this.treeData[0].label", this.treeData[0].label); |
||||
this.currentId = this.treeData[0].id; |
||||
this.currentLevel = this.treeData[0].nodeType; |
||||
this.currentName = this.treeData[0].label; |
||||
this.getExpandedKeys(this.treeData, 2); |
||||
} |
||||
}); |
||||
}, |
||||
// 递归函数,用于去除指定层级往后的 children 数据 |
||||
removeChildrenAfterLevel(obj, currentLevel, targetLevel) { |
||||
if (currentLevel >= targetLevel) { |
||||
// 当达到指定层级时,将 children 属性置为空数组 |
||||
obj.children = []; |
||||
return; |
||||
} |
||||
if (obj.children && obj.children.length > 0) { |
||||
// 若存在 children 数组,则递归处理每个子项 |
||||
for (let i = 0; i < obj.children.length; i++) { |
||||
this.removeChildrenAfterLevel( |
||||
obj.children[i], |
||||
currentLevel + 1, |
||||
targetLevel |
||||
); |
||||
} |
||||
} |
||||
}, |
||||
// 默认只展示一二级菜单 |
||||
getExpandedKeys(nodes, level) { |
||||
nodes.forEach((node) => { |
||||
if (level <= this.currentId + 4) { |
||||
this.expandedKeys.push(node.id); |
||||
} |
||||
if (node.children) { |
||||
this.getExpandedKeys(node.children, level + 1); |
||||
} |
||||
}); |
||||
}, |
||||
// 更换图标 |
||||
getIconClass(node) { |
||||
console.log("当前图标的节点内容", node); |
||||
if (node.level === 5) { |
||||
// 三级菜单时的图标 |
||||
if (node.expanded) { |
||||
return "el-icon-document-opened"; // 三级菜单展开时的图标类名 |
||||
} |
||||
return "el-icon-document"; // 三级菜单收缩时的图标类名 |
||||
} |
||||
if (node.expanded) { |
||||
return "el-icon-folder-opened"; // 非三级菜单展开时的图标类名 |
||||
} |
||||
return "el-icon-folder-add"; // 非三级菜单收缩时的图标类名 |
||||
}, |
||||
handleNodeExpand(node) { |
||||
// 节点展开时触发 |
||||
}, |
||||
handleNodeCollapse(node) { |
||||
// 节点收缩时触发 |
||||
}, |
||||
// 点击当前节点,保存节点内容 |
||||
handleNodeClick(node, data) { |
||||
console.log("点击的当前节点", node, data); |
||||
this.currentId = node.id; |
||||
this.currentLevel = node.nodeType; |
||||
this.currentName = node.label; |
||||
}, |
||||
}, |
||||
}; |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.app-container { |
||||
display: flex; |
||||
flex-direction: row; |
||||
justify-content: space-between; |
||||
align-items: stretch; |
||||
height: 100%; |
||||
.left-tree { |
||||
width: 216px; |
||||
padding: 15px 10px; |
||||
border: 1px solid #004b8c; |
||||
min-height: 800px; |
||||
.status { |
||||
display: flex; |
||||
flex-direction: row; |
||||
justify-content: space-between; |
||||
flex-wrap: wrap; |
||||
margin-top: 20px; |
||||
.status-li { |
||||
width: 50%; |
||||
display: flex; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
justify-content: center; |
||||
margin-bottom: 15px; |
||||
} |
||||
.status1, |
||||
.status2, |
||||
.status3, |
||||
.status4 { |
||||
display: flex; |
||||
flex-direction: row; |
||||
align-items: center; |
||||
margin-bottom: 5px; |
||||
} |
||||
.status1::before { |
||||
content: ""; |
||||
width: 10px; |
||||
height: 10px; |
||||
border-radius: 50%; |
||||
background-color: #00d2ff; |
||||
margin-right: 5px; |
||||
} |
||||
.status2::before { |
||||
content: ""; |
||||
width: 10px; |
||||
height: 10px; |
||||
border-radius: 50%; |
||||
background-color: #ff2f2f; |
||||
margin-right: 5px; |
||||
} |
||||
.status3::before { |
||||
content: ""; |
||||
width: 10px; |
||||
height: 10px; |
||||
border-radius: 50%; |
||||
background-color: #ff9908; |
||||
margin-right: 5px; |
||||
} |
||||
.status4::before { |
||||
content: ""; |
||||
width: 10px; |
||||
height: 10px; |
||||
border-radius: 50%; |
||||
background-color: #7398c7; |
||||
margin-right: 5px; |
||||
} |
||||
} |
||||
} |
||||
.right-monitor { |
||||
width: calc(100% - 240px); |
||||
display: flex; |
||||
flex-direction: column; |
||||
justify-content: space-between; |
||||
.buildingDiv { |
||||
padding-left: 54px; |
||||
display: flex; |
||||
flex-direction: row; |
||||
align-items: center; |
||||
margin-bottom: 20px; |
||||
position: relative; |
||||
.title-bg { |
||||
width: 208px; |
||||
height: 38px; |
||||
position: absolute; |
||||
left: 0; |
||||
z-index: 0; |
||||
} |
||||
.title-word { |
||||
z-index: 10; |
||||
font-family: YouSheBiaoTiHei; |
||||
font-size: 24px; |
||||
color: #ffffff; |
||||
white-space: nowrap; |
||||
} |
||||
} |
||||
.monitor-context { |
||||
height: 640px; |
||||
width: 100%; |
||||
overflow-y: auto; |
||||
display: flex; |
||||
flex-direction: row; |
||||
align-items: flex-start; |
||||
justify-content: flex-start; |
||||
flex-wrap: wrap; |
||||
align-content: flex-start; |
||||
} |
||||
} |
||||
} |
||||
.tree-container { |
||||
height: 300px; /* 设置固定高度 */ |
||||
overflow-y: auto; /* 启用垂直滚动条 */ |
||||
} |
||||
// 滚动条 |
||||
:-webkit-scrollbar { |
||||
width: 10px; /* 滚动条宽度 */ |
||||
} |
||||
|
||||
::-webkit-scrollbar-track { |
||||
background: transparent !important; /* 滚动条轨道背景色 */ |
||||
} |
||||
.custom-tree-node { |
||||
flex: 1; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
font-size: 14px; |
||||
padding-right: 8px; |
||||
.tree-left { |
||||
.custom-tree-icon { |
||||
margin-right: 5px; |
||||
} |
||||
} |
||||
} |
||||
</style> |
||||
<style scoped> |
||||
/* 自定义高亮颜色 */ |
||||
.left-tree |
||||
>>> .el-tree--highlight-current |
||||
.el-tree-node.is-current |
||||
> .el-tree-node__content { |
||||
background-color: #285b9e !important; |
||||
/* color: #f56c6c; */ |
||||
color: #25f1f8; |
||||
} |
||||
</style> |
@ -0,0 +1,18 @@
|
||||
<template> |
||||
<div>热水监测</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import { monitorList } from "@/api/centerairC/sysMonitor"; |
||||
export default { |
||||
data() { |
||||
return { |
||||
deviceList: [], |
||||
}; |
||||
}, |
||||
mounted() {}, |
||||
methods: {}, |
||||
}; |
||||
</script> |
||||
|
||||
<style></style> |