Files
smart_storage_app/pages/tabbar/components/topology/second.vue

878 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="warp">
<topoCanvas ref="topoCanvasRef" cId="secondcanvas" :width="'100%'" :height="'100%'" :canvas-data="canvasData" :noloading="noloading"/>
</view>
</template>
<script>
import topoCanvas from '@/components/new-canvas/index.vue'
export default {
components: {
topoCanvas
},
data() {
return {
canvasData: [],
partList: {},
noloading:false,
// 文字
textCanvasData: [
{
type: "text",
coord: [
[260, 65]
],
font: [{
text: this.$t("homePage.home.load"),
size: 12,
color: "#666666",
width: 50,
}]
},
{
type: "text",
coord: [
[10, 65]
],
font: [{
text: this.$t("homePage.home.grid"),
size: 12,
color: "#666666",
width: 50,
}]
},
{
type: "text",
coord: [
[30, 250]
],
font: [{
text: "1#" + this.$t("homePage.home.cabinet"),
size: 12,
color: "#666666",
width: 50,
}]
},
{
type: "text",
coord: [
[240, 250]
],
font: [{
text: "2#" + this.$t("homePage.home.cabinet"),
size: 12,
color: "#666666",
width: 50,
}]
},
],
// 图片
imageCanvasData: [
{
//负载
type: "image",
url: "/static/topology/load.png",
coord: [
[250, 10],
[40, 40],
],
},
{
//电网
type: "image",
url: "/static/topology/dianwang.png",
coord: [
[15, 10],
[40, 40],
],
},
{
//一体舱
type: "image",
url: "/static/topology/yiticang.png",
coord: [
[45, 195],
[30, 40],
],
},
{
//一体舱
type: "image",
url: "/static/topology/yiticang.png",
coord: [
[255, 195],
[30, 40],
],
},
{
//电表
type: "image",
url: "/static/topology/ammeter.png",
coord: [
[170, 35],
[30, 30],
],
},
{
//sts
type: "image",
url: "/static/topology/yitigui.png",
coord: [
[95, 85],
[30, 40],
],
},
],
// 线
lineCanvasData: [
{
type: "line",
coord: [
[60, 30],
[240, 30],
],
color: "#19875c",
width: 2,
dash: [10, 5],
},
{
type: "line",
coord: [
[110, 30],
[110, 85],
],
color: "#19875c",
width: 2,
dash: [10, 5],
},
{
type: "line",
coord: [
[110, 125],
[110, 150],
],
color: "#19875c",
width: 2,
dash: [10, 5],
},
{
type: "line",
coord: [
[60, 150],
[60, 190],
],
color: "#19875c",
width: 2,
dash: [10, 5],
},
{
type: "line",
coord: [
[60, 150],
[270, 150],
],
color: "#19875c",
width: 2,
dash: [10, 5],
},
{
type: "line",
coord: [
[270, 150],
[270, 190],
],
color: "#19875c",
width: 2,
dash: [10, 5],
},
{
type: "line",
coord: [
[110, 55],
[160, 55],
],
color: "#19875c",
width: 2,
dash: [10, 5],
}
],
// 点
circleCanvasData: [
{
type: "circle",
coord: [
[60, 30]
],
color: "#3AECA1",
isMove: false,
r: 3,
},
{
type: "circle",
coord: [
[110, 30]
],
color: "#3AECA1",
isMove: false,
r: 3,
},
{
type: "circle",
coord: [
[240, 30]
],
color: "#3AECA1",
isMove: false,
r: 3,
},
{
type: "circle",
coord: [
[60, 190]
],
color: "#3AECA1",
isMove: false,
r: 3,
},
{
type: "circle",
coord: [
[110, 150]
],
color: "#3AECA1",
isMove: false,
r: 3,
},
{
type: "circle",
coord: [
[270, 190]
],
color: "#3AECA1",
isMove: false,
r: 3,
},
{
type: "circle",
coord: [
[160, 55]
],
color: "#3AECA1",
isMove: false,
r: 3,
},
],
animationId: null, // requestAnimationFrame ID
movingPoints: [
// 点1左上角 → 向右移动
{
x: 60,
y: 30,
path: [{
x: 60,
y: 30
}, // 起点
{
x: 240,
y: 30
} // 终点
],
currentStep: 0, // 当前在路径的哪一步
isActive: false, // 标识动画是否激活
id: 'point-1'
},
// 点2左上角 → 向右 → 向下
{
x: 60,
y: 30,
path: [{
x: 60,
y: 30
},
{
x: 110,
y: 30
},
{
x: 110,
y: 85
}
],
currentStep: 0,
isActive: false, // 标识动画是否激活
id: 'point-2'
},
// 点3中间下 → 向下 → 向左 → 向下
{
x: 110,
y: 127,
path: [{
x: 110,
y: 127
},
{
x: 110,
y: 150
},
{
x: 60,
y: 150
},
{
x: 60,
y: 190
}
],
currentStep: 0,
isActive: false, // 标识动画是否激活
id: 'point-3'
},
// 点5中间下 → 向下 → 向右 → 向下
{
x: 110,
y: 127,
path: [{
x: 110,
y: 127
},
{
x: 110,
y: 150
},
{
x: 270,
y: 150
},
{
x: 270,
y: 190
}
],
currentStep: 0,
isActive: false, // 标识动画是否激活
id: 'point-5'
},
// 点6中间上 → 向上 → 向右
{
x: 110,
y: 85,
path: [{
x: 110,
y: 85
},
{
x: 110,
y: 30
},
{
x: 240,
y: 30
} // 终点
],
currentStep: 0,
isActive: false, // 标识动画是否激活
id: 'point-6'
},
// 点7左下角 → 向上 → 向右 → 向上
{
x: 60,
y: 190,
path: [{
x: 60,
y: 190
},
{
x: 60,
y: 150
},
{
x: 110,
y: 150
},
{
x: 110,
y: 127
}
],
currentStep: 0,
isActive: false, // 标识动画是否激活
id: 'point-7'
},
// 点9右下角 → 向上 → 向左 → 向上
{
x: 270,
y: 190,
path: [{
x: 270,
y: 190
},
{
x: 270,
y: 150
},
{
x: 110,
y: 150
},
{
x: 110,
y: 127
}
],
currentStep: 0,
isActive: false, // 标识动画是否激活
id: 'point-9'
}
],
pointSpeed: 1.5, // 移动速度(像素/帧)
kWValues: {
left: null, // 存储 getLeftPcs 的 kW 值
right: null // 存储 getRightPcs 的 kW 值
}
}
},
computed: {
currentStation() {
return this.vuex_currentStation;
},
},
beforeDestroy() {
// 强制取消动画帧
if (this.animationId) {
if (typeof requestAnimationFrame !== 'undefined') {
cancelAnimationFrame(this.animationId);
} else {
clearTimeout(this.animationId);
}
this.animationId = null; // 重置ID
}
// 重置所有动态点状态
this.movingPoints.forEach(point => {
point.isActive = false;
point.currentStep = 0;
point.x = point.path[0].x;
point.y = point.path[0].y;
});
// 清空canvasData
this.canvasData = [];
},
watch:{
stationId(newVal,oldVal){
if (newVal) {
this.getData(newVal);
}
}
},
methods: {
// 启动动画
startAnimation() {
const canvasRef = this.$refs.topoCanvasRef;
if (!canvasRef) return;
// 清除旧动画
if (this.animationId !== null) {
if (requestAnimationFrame && this.animationId) {
cancelAnimationFrame(this.animationId);
} else {
clearTimeout(this.animationId);
}
this.animationId = null;
}
// 直接启动新动画
this.animate();
},
animate() {
const canvasRef = this.$refs.topoCanvasRef;
if (!canvasRef) return;
const animateFrame = () => {
// 1. 更新移动点的位置
this.movingPoints.forEach(point => {
if (!point.isActive) return;
const currentIndex = point.currentStep;
const nextTarget = point.path[currentIndex + 1];
if (!nextTarget) {
point.x = point.path[0].x;
point.y = point.path[0].y;
point.currentStep = 0;
return;
}
const dx = nextTarget.x - point.x;
const dy = nextTarget.y - point.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < this.pointSpeed) {
point.x = nextTarget.x;
point.y = nextTarget.y;
point.currentStep++;
} else {
point.x += (dx / distance) * this.pointSpeed;
point.y += (dy / distance) * this.pointSpeed;
}
});
// 2. 更新 canvasData 中的动态点
this.updateMovingPoints();
// 3. 清除并重绘
canvasRef.clear();
canvasRef.draw(null);
// 4. 继续下一帧(✅ 安全判断)
if (typeof requestAnimationFrame !== 'undefined') {
this.animationId = requestAnimationFrame(animateFrame);
} else {
this.animationId = setTimeout(animateFrame, 16);
}
};
// 启动第一帧(✅ 安全判断)
if (typeof requestAnimationFrame !== 'undefined') {
requestAnimationFrame(animateFrame);
} else {
setTimeout(animateFrame, 16);
}
},
updateMovingPoints() {
this.movingPoints.forEach(point => {
const dataIndex = this.canvasData.findIndex(item => item.id === point.id);
if (dataIndex !== -1) {
this.canvasData[dataIndex].coord = [
[point.x, point.y]
];
}
});
},
changeEnglish(){
this.textCanvasData = [
{
type: "text",
coord: [
[260, 65]
],
font: [{
text: this.$t("homePage.home.load"),
size: 12,
color: "#666666",
width: 50,
}]
},
{
type: "text",
coord: [
[10, 65]
],
font: [{
text: this.$t("homePage.home.grid"),
size: 12,
color: "#666666",
width: 50,
}]
},
{
type: "text",
coord: [
[30, 250]
],
font: [{
text: "1#" + this.$t("homePage.home.cabinet"),
size: 12,
color: "#666666",
width: 50,
}]
},
{
type: "text",
coord: [
[240, 250]
],
font: [{
text: "2#" + this.$t("homePage.home.cabinet"),
size: 12,
color: "#666666",
width: 50,
}]
},
]
},
getData(val){
// 彻底重置画布数据
this.canvasData = [];
// 重置所有点状态
this.movingPoints.forEach(point => (point.isActive = false,point.isMove = false,point.currentStep = 0,point.x = point.path[0].x,point.y = point.path[0].y));
this.stationId = val
this.textCanvasData.splice(3)
const api = [this.getLeftPcs(),this.getRightPcs(),this.getAmmeter()]
Promise.all(api).finally((result) => {
// 获取三个 kW 值
const {
left,
right
} = this.kWValues;
const values = [left, right];
const allZero = values.every(v => v === 0);
const anyPositive = values.some(v => v > 0);
const anyNegative = values.some(v => v < 0);
// 重置所有点(确保干净)
this.movingPoints.forEach(p => (p.isActive = false));
// 条件3全部为0 → 只显示点1
if (allZero) {
this.movingPoints.find(p => p.id === 'point-1').isActive = true;
}
// 否则按原逻辑处理
else {
// 条件1任一大于0 → 点6运动
if (anyPositive) {
this.movingPoints.find(p => p.id === 'point-1').isActive = true;
this.movingPoints.find(p => p.id === 'point-2').isActive = true;
}
// 条件2任一小于0 → 点1和点2运动
if (anyNegative) {
this.movingPoints.find(p => p.id === 'point-6').isActive = true;
}
// 再设置点3~9的显示逻辑
this.updatePcsPoints();
}
this.canvasData = [...this.textCanvasData, ...this.imageCanvasData, ...this
.lineCanvasData, ...this.circleCanvasData
]
// 动态添加 movingPoints
this.movingPoints.forEach(point => {
this.canvasData.push({
type: "circle",
id: point.id,
coord: [
[point.x, point.y]
],
color: "#3AECA1",
r: 3,
isMove: true
});
});
this.noloading = true
this.$nextTick(() => {
this.startAnimation();
});
});
},
countChineseAndEnglishCharacters(str, x) {
var chineseCount = str.match(/[\u4e00-\u9fa5]/g) ? str.match(/[\u4e00-\u9fa5]/g).length : 0
var englishCount = str.match(/[a-zA-Z]/g) ? str.match(/[a-zA-Z]/g).length : 0
var otherCount = str.length - chineseCount - englishCount
const obj = { otherCount: otherCount, chineseCount: chineseCount, englishCount: englishCount }
return (obj.englishCount * 4) + (obj.chineseCount * 10 ) + (obj.otherCount * 8) + x
},
getAmmeter(){
let self = this;
return new Promise((resolve, reject) => {
self.$u.api.homePageData
.GetDynamicConfig({
stationId: this.stationId,
pageLocation:'second-ammeter'
})
.then((res) => {
if(res.data && res.data.length){
res.data.forEach((item,index) => {
this.textCanvasData.push(
{
type: "text",
coord: [
[120, 80 + index * 15]
],
font: [{
text: `${item.name}`,
size: 12,
color: "#666666",
width: 50,
}]
},
{
type: "text",
coord: [
[this.countChineseAndEnglishCharacters(item.name,130), 80 + index * 15]
],
font: [{
text: `${item.value}`,
size: 12,
color: "#666666",
width: 50,
}]
},
)
})
}
resolve()
})
})
},
getLeftPcs() {
let self = this;
return new Promise((resolve, reject) => {
self.$u.api.homePageData
.GetDynamicConfig({
stationId: this.stationId,
pageLocation:'second-pcs-left'
})
.then((res) => {
if(res.data && res.data.length){
res.data.forEach((item,index) => {
if (item.name.includes('kW')) { // 检查是否包含'kW'
const value = parseFloat(item.value);
this.kWValues.left = value; // 只记录
}
this.textCanvasData.push(
{
type: "text",
coord: [
[30, 265 + index * 15]
],
font: [{
text: `${item.name}`,
size: 12,
color: "#666666",
width: 50,
}]
},
{
type: "text",
coord: [
[this.countChineseAndEnglishCharacters(item.name,30), 265 + index * 15]
],
font: [{
text: `${item.value}`,
size: 12,
color: "#666666",
width: 50,
}]
},
)
})
} else {
this.kWValues.left = 0; // 没数据视为 0
}
resolve()
}).catch(() => {
this.kWValues.left = 0; // 出错也视为 0
resolve();
})
})
},
getRightPcs() {
let self = this;
return new Promise((resolve, reject) => {
self.$u.api.homePageData
.GetDynamicConfig({
stationId: this.stationId,
pageLocation:'second-pcs-right'
})
.then((res) => {
if(res.data && res.data.length){
res.data.forEach((item,index) => {
if (item.name.includes('kW')) { // 检查是否包含'kW'
const value = parseFloat(item.value);
this.kWValues.right = value;
}
this.textCanvasData.push(
{
type: "text",
coord: [
[200, 265 + index * 15]
],
font: [{
text: `${item.name}`,
size: 12,
color: "#666666",
width: 50,
}]
},
{
type: "text",
coord: [
[this.countChineseAndEnglishCharacters(item.name,200), 265 + index * 15]
],
font: [{
text: `${item.value}`,
size: 12,
color: "#666666",
width: 50,
}]
},
)
})
} else {
this.kWValues.right = 0;
}
resolve()
}).catch(() => {
this.kWValues.right = 0;
resolve();
})
})
},
updatePcsPoints() {
const { left, right } = this.kWValues;
// 处理左边点3 和 点7
const point3 = this.movingPoints.find(p => p.id === 'point-3');
const point7 = this.movingPoints.find(p => p.id === 'point-7');
if (left === 0) {
point3.isActive = false;
point7.isActive = false;
} else if (left > 0) {
point3.isActive = true;
point7.isActive = false;
} else if (left < 0) {
point3.isActive = false;
point7.isActive = true;
}
// 处理右边点5 和 点9
const point5 = this.movingPoints.find(p => p.id === 'point-5');
const point9 = this.movingPoints.find(p => p.id === 'point-9');
if (right === 0) {
point5.isActive = false;
point9.isActive = false;
} else if (right > 0) {
point5.isActive = true;
point9.isActive = false;
} else if (right < 0) {
point5.isActive = false;
point9.isActive = true;
}
}
}
}
</script>
<style lang="scss" scoped>
.warp {
width: 650rpx;
height: 650rpx;
position: relative;
}
</style>