页面标题修改以及显卡左右移动的完善除连续左移以及闪烁换屏

This commit is contained in:
1 2025-07-25 09:33:40 +08:00
parent a59b923ed1
commit 830f16a9f5
10 changed files with 760 additions and 241 deletions

View File

@ -1,5 +1,5 @@
# 页面标题 # 页面标题
VUE_APP_TITLE = 信安智能 VUE_APP_TITLE = 浙江信安智能科技有限公司
# 开发环境配置 # 开发环境配置
ENV = 'development' ENV = 'development'

View File

@ -1,5 +1,5 @@
# 页面标题 # 页面标题
VUE_APP_TITLE = 信安智能 VUE_APP_TITLE = 浙江信安智能科技有限公司
# 生产环境配置 # 生产环境配置
ENV = 'production' ENV = 'production'

View File

@ -1,5 +1,5 @@
# 页面标题 # 页面标题
VUE_APP_TITLE = 信安智能 VUE_APP_TITLE = 浙江信安智能科技有限公司
NODE_ENV = production NODE_ENV = production

BIN
dist.zip

Binary file not shown.

View File

@ -1,7 +1,7 @@
{ {
"name": "fastbee", "name": "fastbee",
"version": "2.5.2", "version": "2.5.2",
"description": "信安智能", "description": "浙江信安智能科技有限公司",
"author": "kerwincui", "author": "kerwincui",
"license": "AGPL3.0", "license": "AGPL3.0",
"scripts": { "scripts": {

View File

@ -9,13 +9,18 @@
<el-card class="mode-card" shadow="hover"> <el-card class="mode-card" shadow="hover">
<div class="mode-header"> <div class="mode-header">
<i class="el-icon-menu" style="font-size: 30px;color: #409EFF;"></i> <i class="el-icon-menu" style="font-size: 30px;color: #409EFF;"></i>
<span class="mode-title">{{ $t('device.running-status.866086-0') }}</span> <span class="mode-title">
<template v-if="boardOnline">{{ $t('device.running-status.866086-0') }}</template>
<template v-else>设备离线</template>
</span>
</div> </div>
<div class="mode-content"> <div class="mode-content">
<span class="title" :style="{ color: statusColor.background }">{{ title }}</span> <template v-if="boardOnline">
<!-- <el-button type="text" @click="printThingsModels" style="margin-left: 10px"> <span class="title" :style="{ color: statusColor.background }">{{ title }}</span>
<i class="el-icon-printer"></i> 打印物模型 </template>
</el-button> --> <template v-else>
<span class="title offline">设备离线</span>
</template>
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
@ -585,7 +590,7 @@ export default {
this.$nextTick(function () { this.$nextTick(function () {
this.MonitorChart(); this.MonitorChart();
}); });
console.log("物模型", JSON.stringify(this.deviceInfo.thingsModels)); // console.log("", JSON.stringify(this.deviceInfo.thingsModels));
if (this.deviceInfo.thingsModels && this.deviceInfo.thingsModels.length > 0) { if (this.deviceInfo.thingsModels && this.deviceInfo.thingsModels.length > 0) {
this.deviceInfo.thingsModels = this.device.thingsModels.sort((a, b) => b.order - a.order); this.deviceInfo.thingsModels = this.device.thingsModels.sort((a, b) => b.order - a.order);
@ -813,6 +818,7 @@ export default {
programList: [], programList: [],
// 使 // 使
programEnableList: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], // programEnableList: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], //
boardOnline: false,
}; };
}, },
mounted() { mounted() {
@ -1010,7 +1016,7 @@ export default {
fillProgramForm(programData) { fillProgramForm(programData) {
if (!programData) return; if (!programData) return;
console.log('填充节目表单数据:', JSON.stringify(programData)); // console.log(':', JSON.stringify(programData));
// //
this.addProgramForm = { this.addProgramForm = {
@ -1022,7 +1028,7 @@ export default {
// //
if (programData.aLst && programData.aLst.length > 0) { if (programData.aLst && programData.aLst.length > 0) {
console.log('解析分区数据:', JSON.stringify(programData.aLst)); // console.log(':', JSON.stringify(programData.aLst));
this.addProgramForm.zones = programData.aLst.map(area => { this.addProgramForm.zones = programData.aLst.map(area => {
let x = area.size ? area.size.x : 0; let x = area.size ? area.size.x : 0;
let y = area.size ? area.size.y : 0; let y = area.size ? area.size.y : 0;
@ -1067,14 +1073,15 @@ export default {
zone.font = item.txt.fCn ? item.txt.fCn - 1 : 0; // zone.font = item.txt.fCn ? item.txt.fCn - 1 : 0; //
zone.fontEn = item.txt.fEn ? item.txt.fEn - 1 : 0; // zone.fontEn = item.txt.fEn ? item.txt.fEn - 1 : 0; //
zone.fontSize = item.txt.fS ? this.getFontSizeIndex(item.txt.fS) : 0; // zone.fontSize = item.txt.fS ? this.getFontSizeIndex(item.txt.fS) : 0; //
zone.fontColor = item.txt.col || 0; // zone.fontColor = item.txt.col - 1 || 0; //
zone.fontBold = item.txt.fW || 0; // zone.fontBold = item.txt.fW || 0; //
zone.fontStretch = item.txt.stch || 0; // zone.fontStretch = item.txt.stch || 0; //
// //
console.log('编辑节目item.txt.hPos:', item.txt.hPos, 'item.txt.vPos:', item.txt.vPos); // console.log('item.txt.hPos:', item.txt.hPos, 'item.txt.vPos:', item.txt.vPos);
zone.hAlign = typeof item.txt.hPos === 'number' ? (item.txt.hPos + 1) : 0; // 123 // hPos/vPos1/2/3UI0/1/2
zone.vAlign = typeof item.txt.vPos === 'number' ? (item.txt.vPos + 1) : 0; // 123 zone.hAlign = typeof item.txt.hPos === 'number' ? (item.txt.hPos - 1) : 0; // 123
console.log('zone.hAlign:', zone.hAlign, 'zone.vAlign:', zone.vAlign); zone.vAlign = typeof item.txt.vPos === 'number' ? (item.txt.vPos - 1) : 0; // 123
// console.log('zone.hAlign:', zone.hAlign, 'zone.vAlign:', zone.vAlign);
} else if (item.typ === 1 && item.img) { } else if (item.typ === 1 && item.img) {
// //
zone.playType = 1; zone.playType = 1;
@ -1230,7 +1237,7 @@ export default {
// //
async refreshBuildInfo() { async refreshBuildInfo() {
console.log('programList', JSON.stringify(this.programList)) // console.log('programList', JSON.stringify(this.programList))
try { try {
// 102#model1 // 102#model1
const model = this.deviceInfo.thingsModels.find(m => m.id === '102#model'); const model = this.deviceInfo.thingsModels.find(m => m.id === '102#model');
@ -1371,7 +1378,10 @@ export default {
// //
updateBasicSettings() { updateBasicSettings() {
if (!this.deviceInfo.thingsModels) return; if (!this.deviceInfo.thingsModels) return;
this.updateBoardOnlineStatus();
// //
const screenEnModel = this.deviceInfo.thingsModels.find(model => model.id === '102#screenEn'); const screenEnModel = this.deviceInfo.thingsModels.find(model => model.id === '102#screenEn');
@ -1431,7 +1441,7 @@ export default {
// 102#progList // 102#progList
const progListModel = this.deviceInfo.thingsModels.find(model => model.id === '102#progList'); const progListModel = this.deviceInfo.thingsModels.find(model => model.id === '102#progList');
console.log("progListModel", JSON.stringify(progListModel)) // console.log("progListModel", JSON.stringify(progListModel))
if (progListModel && progListModel.shadow) { if (progListModel && progListModel.shadow) {
try { try {
const jsonStr = progListModel.shadow.replace('JSON=', ''); const jsonStr = progListModel.shadow.replace('JSON=', '');
@ -1451,7 +1461,7 @@ export default {
raw: program raw: program
}; };
}); });
console.log('解析后的节目列表:', this.programList); // console.log(':', this.programList);
} else { } else {
this.programList = []; this.programList = [];
} }
@ -1480,16 +1490,14 @@ export default {
this.programList.forEach((program, index) => { this.programList.forEach((program, index) => {
program.enabled = this.programEnableList[index] || 0; program.enabled = this.programEnableList[index] || 0;
}); });
console.log('节目使能状态:', this.programEnableList); // console.log('使:', this.programEnableList);
} }
} catch (error) { } catch (error) {
console.error('解析节目使能状态失败:', error); console.error('解析节目使能状态失败:', error);
// 100 // 100
this.programEnableList = new Array(10).fill(0); this.programEnableList = new Array(10).fill(0);
} }
} else { //线线
// 100
this.programEnableList = new Array(10).fill(0);
} }
}, },
@ -2237,8 +2245,16 @@ export default {
}, },
onAddProgramModeChange(val) { onAddProgramModeChange(val) {
// //
const isSwap = this.screenParams.angle === 90 || this.screenParams.angle === 270;
let actualMode = val;
//
if (isSwap) {
if (val === 1) actualMode = 2; //
else if (val === 2) actualMode = 1; //
else if (val === 3) actualMode = 2; //
}
const zoneCounts = [1, 2, 2, 3, 1, 1]; const zoneCounts = [1, 2, 2, 3, 1, 1];
const count = zoneCounts[val] || 1; const count = zoneCounts[actualMode] || 1;
// 使 // 使
const screenW = this.screenParams.width || 32; const screenW = this.screenParams.width || 32;
const screenH = this.screenParams.height || 64; const screenH = this.screenParams.height || 64;
@ -2268,7 +2284,7 @@ export default {
width: screenW, width: screenW,
height: screenH height: screenH
}; };
switch (val) { switch (actualMode) {
case 1: // case 1: //
templateZone.height = Math.floor(screenH / count); templateZone.height = Math.floor(screenH / count);
templateZone.y = i * templateZone.height; templateZone.y = i * templateZone.height;
@ -2332,10 +2348,10 @@ export default {
aLst: this.addProgramForm.zones.map(zone => { aLst: this.addProgramForm.zones.map(zone => {
// //
let x = zone.x, y = zone.y, w = zone.width, h = zone.height; let x = zone.x, y = zone.y, w = zone.width, h = zone.height;
if (this.screenParams.angle === 90 || this.screenParams.angle === 270) { // if (this.screenParams.angle === 90 || this.screenParams.angle === 270) {
[x, y] = [y, x]; // [x, y] = [y, x];
[w, h] = [h, w]; // [w, h] = [h, w];
} // }
const area = { const area = {
size: { size: {
x: x, // X x: x, // X
@ -2597,7 +2613,12 @@ export default {
// //
const imageData = tempCtx.getImageData(0, 0, newWidth, newHeight); const imageData = tempCtx.getImageData(0, 0, newWidth, newHeight);
const data = imageData.data; const data = imageData.data;
const colors = [[0, 0, 0], [255, 0, 0], [0, 255, 0], [255, 255, 0]]; // Black, Red, Green, Yellow // 0=, 1=绿, 2=
const colors = [
[255, 0, 0], //
[0, 255, 0], // 绿
[255, 255, 0] //
];
const selectedColor = colors[zone.imageColor]; const selectedColor = colors[zone.imageColor];
if (selectedColor) { if (selectedColor) {
for (let i = 0; i < data.length; i += 4) { for (let i = 0; i < data.length; i += 4) {
@ -2664,9 +2685,10 @@ export default {
this.addProgramPreviewAssets = this.addProgramForm.zones.map(zone => { this.addProgramPreviewAssets = this.addProgramForm.zones.map(zone => {
if (zone.playType === 1 && zone.image) { if (zone.playType === 1 && zone.image) {
console.log('加载图片', zone.image);
// //
const img = new window.Image(); const img = new window.Image();
img.crossOrigin = 'Anonymous'; // img.crossOrigin = 'Anonymous';
const asset = { img, isImage: true, loaded: false }; const asset = { img, isImage: true, loaded: false };
img.onload = () => { img.onload = () => {
asset.loaded = true; asset.loaded = true;
@ -2747,13 +2769,20 @@ export default {
if (pages.length === 0) pages.push([]); if (pages.length === 0) pages.push([]);
//
const totalWidth = Math.max(...lines.map(line => measureCtx.measureText(line).width), 0);
const totalHeight = lines.length * lineHeight;
return { return {
pages, pages,
isText: true, isText: true,
scaledFontSize, scaledFontSize,
fontFamily: fontFamily2, fontFamily: fontFamily2,
fontWeight, fontWeight,
lineHeight lineHeight,
totalWidth,
totalHeight,
zoneRenderWidth: zoneRenderWidth * scale,
zoneRenderHeight: zoneRenderHeight * scale
}; };
}); });
}, },
@ -2855,66 +2884,286 @@ export default {
// //
const renderWidth = 640; const renderWidth = 640;
const renderHeight = 240; const renderHeight = 240;
const scale = Math.min(renderWidth / 32, renderHeight / 64); // const scale = Math.min(renderWidth / 32, renderHeight / 64);
// 使 prepareAddProgramPreviewAssets scale
let screenW = this.screenParams.width || 32;
let screenH = this.screenParams.height || 64;
const angle = this.screenParams.angle;
const swapWH = angle === 90 || angle === 270;
if (swapWH) {
[screenW, screenH] = [screenH, screenW];
}
const scale = Math.min(renderWidth / screenW, renderHeight / screenH);
this.addProgramForm.zones.forEach((zone, idx) => { this.addProgramForm.zones.forEach((zone, idx) => {
const asset = this.addProgramPreviewAssets[idx]; const asset = this.addProgramPreviewAssets[idx];
const state = this.addProgramPreviewAnimState[idx]; const state = this.addProgramPreviewAnimState[idx];
if (!asset || !state || !asset.isText) return; if (!asset || !state || !asset.isText) return;
const effect = zone.effect; const effect = zone.effect;
const page = this.addProgramPreviewPage[idx] || 0; const page = this.addProgramPreviewPage[idx] || 0;
const pageLines = asset.pages[page] || []; const pageLines = asset.pages[page] || [];
const lineHeight = asset.scaledFontSize * 1.2; const lineHeight = asset.lineHeight;
const totalHeight = pageLines.length * lineHeight; // const totalHeight = pageLines.length * lineHeight; //
const totalWidth = Math.max(...pageLines.map(line => this.measureTextWidth(line, asset))); // const totalWidth = Math.max(...pageLines.map(line => measureCtx.measureText(line).width), 0); //
// 使 prepareAddProgramPreviewAssets
const totalHeight = asset.totalHeight;
const totalWidth = asset.totalWidth;
// //
const speedMap = [1, 2, 3, 4, 5]; const speedMap = [1, 2, 3, 4, 5];
const animSpeed = (speedMap[zone.speed] || 3) * scale * 0.5; const animSpeed = (speedMap[zone.speed] || 3) * scale * 0.5; // /
//
const zoneWidth = zone.width * scale; // (使)
const zoneHeight = zone.height * scale; const zoneWidth = asset.zoneRenderWidth;
// const zoneHeight = asset.zoneRenderHeight;
// ()
const pauseMs = this.getPauseTime(zone.stayTime);
//
if (typeof state.isPausing !== 'boolean') state.isPausing = false;
if (typeof state.pauseStart !== 'number') state.pauseStart = 0;
if (typeof state.pausePhase !== 'string') state.pausePhase = 'start'; // 'start' | 'move'
switch (effect) { switch (effect) {
case 1: // case 1: //
if (state.currentX > -totalWidth) { // state.currentX
state.currentX -= animSpeed; if (typeof state.currentX !== 'number') state.currentX = 0;
} else { // pausePhase
state.currentX = zoneWidth; if (!state.pausePhase) state.pausePhase = 'start'; // 'start' | 'move'
//
if (!state.isPausing && state.pausePhase === 'start') {
state.isPausing = true;
state.pauseStart = Date.now();
} }
//
if (state.isPausing && state.pausePhase === 'start') {
if (Date.now() - state.pauseStart >= pauseMs) {
state.isPausing = false;
state.pausePhase = 'move';
}
//
} else if (!state.isPausing && state.pausePhase === 'move') {
// --- ---
// !!! !!!
// : if (state.currentX + totalWidth > 0)
// : (0) (-state.currentX)
// ""
const pixelsMoved = -state.currentX; // X=0
const distanceToTriggerReset = zoneWidth + 100; // <--- +
// 32 + 100 = 132
// 100
if (pixelsMoved < distanceToTriggerReset) {
//
state.currentX -= animSpeed;
} else {
//
// console.log(`Zone ${idx} - Left Move: Forcefully reset after moving ${pixelsMoved.toFixed(2)} pixels.`); //
state.currentX = 0; //
state.pausePhase = 'start'; //
}
// --- ---
}
// Y
state.currentY = 0;
break; break;
case 2: // case 2: //
if (state.currentX < zoneWidth) { // state.currentX
state.currentX += animSpeed; if (typeof state.currentX !== 'number') state.currentX = 0; //
} else { // pausePhase
state.currentX = -totalWidth; if (!state.pausePhase) state.pausePhase = 'start'; // 'start' | 'move'
//
if (!state.isPausing && state.pausePhase === 'start') {
state.isPausing = true;
state.pauseStart = Date.now();
} }
//
if (state.isPausing && state.pausePhase === 'start') {
if (Date.now() - state.pauseStart >= pauseMs) {
state.isPausing = false;
state.pausePhase = 'move';
}
//
} else if (!state.isPausing && state.pausePhase === 'move') {
// --- ---
//
// (currentX < zoneWidth)
if (state.currentX < zoneWidth) {
state.currentX += animSpeed;
//
// if (state.currentX > zoneWidth) {
// state.currentX = zoneWidth; //
// }
} else {
//
// 'end'
state.currentX = 0; //
state.pausePhase = 'start'; //
}
// --- ---
}
// Y
state.currentY = 0;
break; break;
case 3: // case 3: //
if (state.currentY > -totalHeight) { // state.currentY
state.currentY -= animSpeed; if (typeof state.currentY !== 'number') state.currentY = 0;
} else { // pausePhase
state.currentY = zoneHeight; if (!state.pausePhase) state.pausePhase = 'start'; // 'start' | 'move'
//
if (!state.isPausing && state.pausePhase === 'start') {
state.isPausing = true;
state.pauseStart = Date.now();
} }
//
if (state.isPausing && state.pausePhase === 'start') {
if (Date.now() - state.pauseStart >= pauseMs) {
state.isPausing = false;
state.pausePhase = 'move';
}
//
} else if (!state.isPausing && state.pausePhase === 'move') {
// --- ---
//
// (currentY + totalHeight > 0)
if (state.currentY + totalHeight > 0) {
state.currentY -= animSpeed;
//
// if (state.currentY + totalHeight < 0) {
// state.currentY = -totalHeight;
// }
} else {
//
// 'end'
state.currentY = 0; //
state.pausePhase = 'start'; //
}
// --- ---
}
// X
state.currentX = 0;
break; break;
case 4: // case 4: //
if (state.currentY < zoneHeight) { // state.currentY
state.currentY += animSpeed; if (typeof state.currentY !== 'number') state.currentY = 0; //
} else { // pausePhase
state.currentY = -totalHeight; if (!state.pausePhase) state.pausePhase = 'start'; // 'start' | 'move'
//
if (!state.isPausing && state.pausePhase === 'start') {
state.isPausing = true;
state.pauseStart = Date.now();
} }
break;
case 5: // //
if (state.currentX > -totalWidth) { if (state.isPausing && state.pausePhase === 'start') {
state.currentX -= animSpeed; if (Date.now() - state.pauseStart >= pauseMs) {
} else { state.isPausing = false;
state.currentX = 0; state.pausePhase = 'move';
}
//
} else if (!state.isPausing && state.pausePhase === 'move') {
// --- ---
//
// (currentY < zoneHeight)
if (state.currentY < zoneHeight) {
state.currentY += animSpeed;
//
// if (state.currentY > zoneHeight) {
// state.currentY = zoneHeight;
// }
} else {
//
// 'end'
state.currentY = 0; //
state.pausePhase = 'start'; //
}
// --- ---
} }
// X
state.currentX = 0;
break; break;
case 5: // ( -> -> -> ...)
// state.currentX
if (typeof state.currentX !== 'number') state.currentX = 0;
// pausePhase
if (!state.pausePhase) state.pausePhase = 'start'; // 'start' | 'move'
// ()
if (!state.isPausing && state.pausePhase === 'start') {
// pauseMs
state.isPausing = true;
state.pauseStart = Date.now();
}
//
if (state.isPausing && state.pausePhase === 'start') {
if (Date.now() - state.pauseStart >= pauseMs) {
state.isPausing = false;
state.pausePhase = 'move'; //
}
// ()
} else if (!state.isPausing && state.pausePhase === 'move') {
// --- () ---
//
if (state.currentX > -totalWidth) {
state.currentX -= animSpeed;
//
// if (state.currentX < -totalWidth) {
// state.currentX = -totalWidth;
// }
} else {
//
// pauseMs
state.isPausing = true;
state.pauseStart = Date.now();
state.currentX = 0; //
state.pausePhase = 'start'; // 'start'
}
// --- ---
}
state.currentY = 0; // Y
break;
case 6: // case 6: //
// //
break;
default:
state.currentX = 0; state.currentX = 0;
state.currentY = 0; state.currentY = 0;
break;
default: // (effect === 0)
state.currentX = 0;
state.currentY = 0;
//
// if (!state.isPausing && state.pausePhase === 'start') {
// state.isPausing = true;
// state.pauseStart = Date.now();
// }
// if (state.isPausing && state.pausePhase === 'start') {
// if (Date.now() - state.pauseStart >= pauseMs) {
// state.isPausing = false;
// state.pausePhase = 'end'; // 'start'
// }
// }
// state.pausePhase = 'start'; // 便
break;
} }
}); });
}, },
@ -3016,36 +3265,47 @@ export default {
zoneDisplay(zIdx) { zoneDisplay(zIdx) {
const zone = this.addProgramForm.zones[zIdx]; const zone = this.addProgramForm.zones[zIdx];
if (!zone) return { x: 0, y: 0, width: 0, height: 0 }; if (!zone) return { x: 0, y: 0, width: 0, height: 0 };
if (this.screenParams.angle === 90 || this.screenParams.angle === 270) { // 90270xy/UI
return { return {
x: zone.y, x: zone.x,
y: zone.x, y: zone.y,
width: zone.height, width: zone.width,
height: zone.width height: zone.height
}; };
} else {
return {
x: zone.x,
y: zone.y,
width: zone.width,
height: zone.height
};
}
}, },
// UI // UI
setZoneDisplay(zIdx, key, value) { setZoneDisplay(zIdx, key, value) {
const zone = this.addProgramForm.zones[zIdx]; const zone = this.addProgramForm.zones[zIdx];
if (!zone) return; if (!zone) return;
if (this.screenParams.angle === 90 || this.screenParams.angle === 270) { // 90270xy/UI
// zone[key] = value;
if (key === 'x') zone.y = value;
else if (key === 'y') zone.x = value;
else if (key === 'width') zone.height = value;
else if (key === 'height') zone.width = value;
} else {
zone[key] = value;
}
}, },
updateBoardOnlineStatus() {
if (!this.deviceInfo || !this.deviceInfo.thingsModels) {
this.boardOnline = false;
return;
}
const onlineModel = this.deviceInfo.thingsModels.find(m => m.id === '1#onlineBoard');
if (!onlineModel || !(onlineModel.shadow || onlineModel.value)) { // shadow
this.boardOnline = false;
return;
}
try {
const valueStr = onlineModel.shadow || onlineModel.value; // 使 shadow
const jsonStr = valueStr.replace(/^JSON=/, '');
const data = JSON.parse(jsonStr);
const onlineArr = data.online || [];
this.boardOnline = onlineArr.includes(102); //
} catch (e) {
this.boardOnline = false;
}
// console.log("", JSON.stringify(this.boardOnline));
// console.log("", onlineModel.shadow ? "shadow" : "value");
}
},
computed: {
// ...computed
}, },
}; };
</script> </script>
@ -3479,4 +3739,25 @@ export default {
border-radius: 16px; border-radius: 16px;
margin-bottom: 20px; margin-bottom: 20px;
} }
.board-status-single {
margin-top: 6px;
font-size: 15px;
span {
font-weight: 600;
&.online {
color: #67C23A;
}
&.offline {
color: #bbb;
}
}
}
.title.offline {
color: #bbb;
}
</style> </style>

View File

@ -8,10 +8,23 @@
<div class="icon-wrapper bg-blue"> <div class="icon-wrapper bg-blue">
<i class="el-icon-menu"></i> <i class="el-icon-menu"></i>
</div> </div>
<span class="mode-title">设备模式</span> <span class="mode-title">
<template v-if="boardOnline">设备模式</template>
<template v-else>设备离线</template>
</span>
</div> </div>
<div class="mode-content"> <div class="mode-content">
<span class="title gradient-text">{{ title }}</span> <template v-if="boardOnline">
<span class="title gradient-text">{{ title }}</span>
</template>
<template v-else>
<span class="title offline">设备离线</span>
</template>
<!-- <div class="board-status-single">
<span :class="isBoardOnline ? 'online' : 'offline'">
{{ isBoardOnline ? '网关在线' : '网关离线' }}
</span>
</div> -->
<!-- <el-button type="text" class="print-btn" @click="printThingsModels"> <!-- <el-button type="text" class="print-btn" @click="printThingsModels">
<i class="el-icon-printer"></i> 打印物模型 <i class="el-icon-printer"></i> 打印物模型
</el-button> --> </el-button> -->
@ -205,6 +218,42 @@
<script> <script>
export default { export default {
props: {
device: {
type: Object,
default: null,
},
},
watch: {
device: {
handler(newVal) {
if (newVal && newVal.deviceId != 0) {
this.deviceInfo = newVal;
this.updateDeviceStatus(this.deviceInfo);
this.$nextTick(function () {
this.MonitorChart();
});
console.log("物模型", JSON.stringify(this.deviceInfo.thingsModels));
if (this.deviceInfo.thingsModels && this.deviceInfo.thingsModels.length > 0) {
this.deviceInfo.thingsModels = this.device.thingsModels.sort((a, b) => b.order - a.order);
}
if (this.deviceInfo.chartList && this.deviceInfo.chartList.length > 0) {
this.deviceInfo.chartList = this.deviceInfo.chartList.sort((a, b) => b.order - a.order);
}
}
},
},
},
mounted() {
console.log("device",JSON.stringify(this.device),"deviceInfo",JSON.stringify(this.deviceInfo))
if (this.device && this.device.deviceId) {
this.handleDeviceChange(this.device);
this.initDataStatus();
this.initData();
}
},
name: 'gateway-setting', name: 'gateway-setting',
data() { data() {
return { return {
@ -212,6 +261,21 @@ export default {
firmwareVersion: '1.0.0', firmwareVersion: '1.0.0',
mac: '00:11:22:33:44:55', mac: '00:11:22:33:44:55',
}, },
deviceInfo: {
deviceId: 0,
serialNumber: '',
productId: '',
productName: '',
status: 0,
isShadow: 0,
rssi: 0,
firmwareVersion: '',
wirelessVersion: '',
firmwareType: 1,
protocolCode: '',
thingsModels: [],
chartList: [],
},
form: { form: {
networkId: '', networkId: '',
band: '', band: '',
@ -303,6 +367,16 @@ export default {
],
monitorChart: [
{
chart: {},
data: {
id: '',
name: '',
value: '',
},
},
], ],
pinOptions: [ pinOptions: [
{ label: '引脚1', value: 'pin1' }, { label: '引脚1', value: 'pin1' },
@ -315,9 +389,49 @@ export default {
{ label: '引脚8', value: 'pin8' }, { label: '引脚8', value: 'pin8' },
{ label: '引脚9', value: 'pin9' }, { label: '引脚9', value: 'pin9' },
], ],
boardOnline: false,
}; };
},
computed: {
}, },
methods: { methods: {
initDataStatus() {
this.$busEvent.$on('updateStatus', (status) => {
this.updateStatus(status);
});
},
initData() {
this.$busEvent.$on('updateData', (params) => {
this.updateParam(params);
});
},
//
handleDeviceChange(device) {
console.log("inpout")
if (device && device.deviceId != 0) {
const { firmwareVersion, wirelessVersion, firmwareType, ...res } = device;
const data = {
version: firmwareType === 1 ? firmwareVersion : wirelessVersion,
firmwareType,
...res,
};
this.deviceInfo = data;
this.updateDeviceStatus(this.deviceInfo);
this.$nextTick(() => {
this.MonitorChart();
});
if (this.deviceInfo.thingsModels && this.deviceInfo.thingsModels.length > 0) {
this.deviceInfo.thingsModels = this.deviceInfo.thingsModels.sort((a, b) => b.order - a.order);
this.updateBasicSettings(); //
// this.printThingsModels();
}
if (this.deviceInfo.chartList && this.deviceInfo.chartList.length > 0) {
this.deviceInfo.chartList = this.deviceInfo.chartList.sort((a, b) => b.order - a.order);
}
}
},
onSubmit() { onSubmit() {
this.$refs.formRef.validate((valid) => { this.$refs.formRef.validate((valid) => {
if (valid) { if (valid) {
@ -326,6 +440,83 @@ export default {
} }
}); });
}, },
MonitorChart() {
for (let i = 0; i < this.deviceInfo.chartList.length; i++) {
this.monitorChart[i] = {
chart: this.$echarts.init(this.$refs.map[i]),
data: {
id: this.deviceInfo.chartList[i].id,
name: this.deviceInfo.chartList[i].name,
value: this.deviceInfo.chartList[i].shadow ? this.deviceInfo.chartList[i].shadow : this.deviceInfo.chartList[i].datatype.min,
},
};
var option;
option = {
tooltip: {
formatter: ' {b} <br/> {c}' + this.deviceInfo.chartList[i].datatype.unit,
},
series: [
{
name: this.deviceInfo.chartList[i].datatype.type,
type: 'gauge',
min: this.deviceInfo.chartList[i].datatype.min,
max: this.deviceInfo.chartList[i].datatype.max,
colorBy: 'data',
splitNumber: 10,
radius: '100%',
splitLine: {
distance: 4,
},
axisLabel: {
fontSize: 10,
distance: 10,
},
axisTick: {
distance: 4,
},
axisLine: {
lineStyle: {
width: 8,
color: [
[0.2, '#409EFF'],
[0.8, '#12d09f'],
[1, '#F56C6C'],
],
opacity: 0.3,
},
},
pointer: {
icon: 'triangle',
length: '60%',
width: 7,
},
progress: {
show: true,
width: 8,
},
detail: {
valueAnimation: true,
formatter: '{value}' + ' ' + this.deviceInfo.chartList[i].datatype.unit,
offsetCenter: [0, '80%'],
fontSize: 20,
},
data: [
{
value: this.deviceInfo.chartList[i].shadow ? this.deviceInfo.chartList[i].shadow : this.deviceInfo.chartList[i].datatype.min,
name: this.deviceInfo.chartList[i].name,
},
],
title: {
offsetCenter: [0, '115%'],
fontSize: 16,
},
},
],
};
option && this.monitorChart[i].chart.setOption(option);
}
},
printThingsModels() { printThingsModels() {
this.$message.info('打印物模型功能保留'); this.$message.info('打印物模型功能保留');
}, },
@ -336,6 +527,24 @@ export default {
this.$message.success('雷达设置已保存'); this.$message.success('雷达设置已保存');
// TODO: // TODO:
}, },
updateDeviceStatus(device) {
if (device.status == 3) {
this.statusColor.background = '#12d09f';
this.title = this.$t('device.running-status.866086-26');
this.shadowUnEnable = false;
} else {
if (device.isShadow == 1) {
this.statusColor.background = '#486FF2';
this.title = this.$t('device.running-status.866086-27');
this.shadowUnEnable = false;
} else {
this.statusColor.background = '#909399';
this.title = this.$t('device.running-status.866086-28');
this.shadowUnEnable = true;
}
}
this.$emit('statusEvent', this.deviceInfo.status);
},
handleAddEvent() { handleAddEvent() {
this.$refs.eventFormRef.validate((valid) => { this.$refs.eventFormRef.validate((valid) => {
if (valid) { if (valid) {
@ -352,6 +561,31 @@ export default {
} }
}); });
}, },
updateBoardOnlineStatus() {
if (!this.deviceInfo || !this.deviceInfo.thingsModels) {
this.boardOnline = false;
return;
}
const onlineModel = this.deviceInfo.thingsModels.find(m => m.id === '1#onlineBoard');
if (!onlineModel || !(onlineModel.value || onlineModel.shadow)) {
this.boardOnline = false;
return;
}
try {
const valueStr = onlineModel.value || onlineModel.shadow;
const jsonStr = valueStr.replace(/^JSON=/, '');
const data = JSON.parse(jsonStr);
const onlineArr = data.online || [];
this.boardOnline = onlineArr.includes(1); //
} catch (e) {
this.boardOnline = false;
}
console.log("测试网关是否受到消息", JSON.stringify(this.boardOnline));
console.log("数据来源:", onlineModel.shadow ? "shadow" : "value");
},
updateBasicSettings() {
this.updateBoardOnlineStatus();
},
}, },
}; };
</script> </script>
@ -654,4 +888,25 @@ export default {
} }
} }
} }
.board-status-single {
margin-top: 6px;
font-size: 15px;
span {
font-weight: 600;
&.online {
color: #67C23A;
}
&.offline {
color: #bbb;
}
}
}
.title.offline {
color: #bbb;
}
</style> </style>

View File

@ -67,6 +67,15 @@
<i class="el-icon-connection"></i> <i class="el-icon-connection"></i>
<span>子设备管理</span> <span>子设备管理</span>
</div> </div>
<!-- 板卡在线状态显示 -->
<!-- <div class="board-status">
<span
:class="{ 'online': boardOnlineStatus.gateway, 'offline': !boardOnlineStatus.gateway }">网关</span>
<span :class="{ 'online': boardOnlineStatus.display, 'offline': !boardOnlineStatus.display }"
style="margin-left: 16px;">显卡</span>
<span :class="{ 'online': boardOnlineStatus.sound, 'offline': !boardOnlineStatus.sound }"
style="margin-left: 16px;">声卡</span>
</div> -->
</el-col> </el-col>
</el-row> </el-row>
@ -257,6 +266,24 @@ export default {
// deviceInfo.product undefined/null // deviceInfo.product undefined/null
const arr = (this.deviceInfo.product || []).slice(1); // const arr = (this.deviceInfo.product || []).slice(1); //
return arr.map(type => PRODUCT_TYPE_MAP[type]).filter(Boolean); return arr.map(type => PRODUCT_TYPE_MAP[type]).filter(Boolean);
},
// 线
boardOnlineStatus() {
const model = this.deviceInfo.thingsModels?.find(m => m.id === '1#onlineBoard');
if (!model || !(model.value || model.shadow)) return {};
try {
const valueStr = model.value || model.shadow;
const jsonStr = valueStr.replace(/^JSON=/, '');
const data = JSON.parse(jsonStr);
const onlineArr = data.online || [];
return {
gateway: onlineArr.includes(1),
display: onlineArr.includes(102),
sound: onlineArr.includes(103)
};
} catch (e) {
return {};
}
} }
}, },
watch: { watch: {
@ -1031,4 +1058,23 @@ export default {
} }
} }
} }
.board-status {
margin-top: 8px;
font-size: 15px;
span {
display: inline-block;
min-width: 40px;
font-weight: 600;
&.online {
color: #67C23A;
}
&.offline {
color: #bbb;
}
}
}
</style> </style>

View File

@ -9,13 +9,18 @@
<el-card class="mode-card" shadow="hover"> <el-card class="mode-card" shadow="hover">
<div class="mode-header"> <div class="mode-header">
<i class="el-icon-menu"></i> <i class="el-icon-menu"></i>
<span class="mode-title">{{ $t('device.running-status.866086-0') }}</span> <span class="mode-title">
<template v-if="boardOnline">{{ $t('device.running-status.866086-0') }}</template>
<template v-else>设备离线</template>
</span>
</div> </div>
<div class="mode-content"> <div class="mode-content">
<span class="title" :style="{ color: statusColor.background }">{{ title }}</span> <template v-if="boardOnline">
<el-button type="text" @click="printThingsModels" style="margin-left: 10px"> <span class="title" :style="{ color: statusColor.background }">{{ title }}</span>
<i class="el-icon-printer"></i> 打印物模型 </template>
</el-button> <template v-else>
<span class="title offline">设备离线</span>
</template>
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
@ -49,10 +54,12 @@
</el-form-item> </el-form-item>
<el-form-item label="音量设置"> <el-form-item label="音量设置">
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<el-slider v-model="basicSettings.volume" :min="0" :max="100" :format-tooltip="formatVolume" <el-slider v-model="basicSettings.volume" :min="0" :max="100"
@change="handleVolumeChange" style="width: 80%; flex: 1;" :disabled="!basicSettings.audioEnabled"> :format-tooltip="formatVolume" @change="handleVolumeChange"
style="width: 80%; flex: 1;" :disabled="!basicSettings.audioEnabled">
</el-slider> </el-slider>
<span style="margin-left: 16px; min-width: 32px; text-align: right;">{{ basicSettings.volume }}</span> <span style="margin-left: 16px; min-width: 32px; text-align: right;">{{
basicSettings.volume }}</span>
</div> </div>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -294,19 +301,22 @@
</el-form-item> </el-form-item>
<el-form-item label="合成语速" prop="spd"> <el-form-item label="合成语速" prop="spd">
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<el-slider v-model="newAudio.spd" :min="0" :max="15" :step="1" :format-tooltip="formatSpeed" style="flex: 1;"></el-slider> <el-slider v-model="newAudio.spd" :min="0" :max="15" :step="1" :format-tooltip="formatSpeed"
style="flex: 1;"></el-slider>
<span style="margin-left: 16px; min-width: 32px; text-align: right;">{{ newAudio.spd }}</span> <span style="margin-left: 16px; min-width: 32px; text-align: right;">{{ newAudio.spd }}</span>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="合成音调" prop="pit"> <el-form-item label="合成音调" prop="pit">
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<el-slider v-model="newAudio.pit" :min="0" :max="15" :step="1" :format-tooltip="formatPitch" style="flex: 1;"></el-slider> <el-slider v-model="newAudio.pit" :min="0" :max="15" :step="1" :format-tooltip="formatPitch"
style="flex: 1;"></el-slider>
<span style="margin-left: 16px; min-width: 32px; text-align: right;">{{ newAudio.pit }}</span> <span style="margin-left: 16px; min-width: 32px; text-align: right;">{{ newAudio.pit }}</span>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="合成音量" prop="vol"> <el-form-item label="合成音量" prop="vol">
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<el-slider v-model="newAudio.vol" :min="0" :max="15" :step="1" :format-tooltip="formatVolume" style="flex: 1;"></el-slider> <el-slider v-model="newAudio.vol" :min="0" :max="15" :step="1" :format-tooltip="formatVolume"
style="flex: 1;"></el-slider>
<span style="margin-left: 16px; min-width: 32px; text-align: right;">{{ newAudio.vol }}</span> <span style="margin-left: 16px; min-width: 32px; text-align: right;">{{ newAudio.vol }}</span>
</div> </div>
</el-form-item> </el-form-item>
@ -444,6 +454,7 @@ export default {
}, },
firmware: {}, firmware: {},
openFirmware: false, openFirmware: false,
boardOnline: false,
loading: true, loading: true,
deviceInfo: { deviceInfo: {
deviceId: 0, deviceId: 0,
@ -706,7 +717,7 @@ export default {
if (this.deviceInfo.thingsModels && this.deviceInfo.thingsModels.length > 0) { if (this.deviceInfo.thingsModels && this.deviceInfo.thingsModels.length > 0) {
this.deviceInfo.thingsModels = this.deviceInfo.thingsModels.sort((a, b) => b.order - a.order); this.deviceInfo.thingsModels = this.deviceInfo.thingsModels.sort((a, b) => b.order - a.order);
this.updateBasicSettings(); // this.updateBasicSettings(); //
this.printThingsModels(); // this.printThingsModels();
} }
if (this.deviceInfo.chartList && this.deviceInfo.chartList.length > 0) { if (this.deviceInfo.chartList && this.deviceInfo.chartList.length > 0) {
this.deviceInfo.chartList = this.deviceInfo.chartList.sort((a, b) => b.order - a.order); this.deviceInfo.chartList = this.deviceInfo.chartList.sort((a, b) => b.order - a.order);
@ -716,8 +727,9 @@ export default {
// //
updateBasicSettings() { updateBasicSettings() {
// this.isBoardOnline();
if (!this.deviceInfo.thingsModels) return; if (!this.deviceInfo.thingsModels) return;
this.updateBoardOnlineStatus();
// //
const playEnModel = this.deviceInfo.thingsModels.find(model => model.id === '103#playEn'); const playEnModel = this.deviceInfo.thingsModels.find(model => model.id === '103#playEn');
if (playEnModel) { if (playEnModel) {
@ -791,6 +803,7 @@ export default {
console.error('解析播放列表失败:', error); console.error('解析播放列表失败:', error);
} }
} }
}, },
printThingsModels() { printThingsModels() {
@ -800,7 +813,30 @@ export default {
type: 'success' type: 'success'
}); });
}, },
//online or offline
updateBoardOnlineStatus() {
if (!this.deviceInfo || !this.deviceInfo.thingsModels) {
this.boardOnline = false;
return;
}
const onlineModel = this.deviceInfo.thingsModels.find(m => m.id === '1#onlineBoard');
if (!onlineModel || !(onlineModel.shadow || onlineModel.value)) { // shadow
this.boardOnline = false;
return;
}
try {
const valueStr = onlineModel.shadow || onlineModel.value; // 使 shadow
const jsonStr = valueStr.replace(/^JSON=/, '');
const data = JSON.parse(jsonStr);
const onlineArr = data.online || [];
this.boardOnline = onlineArr.includes(103); //
} catch (e) {
this.boardOnline = false;
}
// console.log("", JSON.stringify(this.boardOnline));
// console.log("", onlineModel.shadow ? "shadow" : "value");
},
// //
formatVolume(val) { formatVolume(val) {
return val + '%'; return val + '%';
@ -841,130 +877,10 @@ export default {
// }, // },
// initData() {
updateParam(params) { this.$busEvent.$on('updateData', (params) => {
let { serialNumber, productId, data } = params; this.updateParam(params);
let isComplete = false; });
data = data.message;
if (data) {
for (let j = 0; j < data.length; j++) {
for (let k = 0; k < this.deviceInfo.thingsModels.length && !isComplete; k++) {
if (this.deviceInfo.thingsModels[k].id == data[j].id) {
const variable = this.deviceInfo.thingsModels[k];
// (////)
if (this.deviceInfo.thingsModels[k].datatype.type == 'decimal' || this.deviceInfo.thingsModels[k].datatype.type == 'integer') {
variable.shadow = Number(data[j].value);
} else {
variable.shadow = data[j].value;
}
}
if (this.deviceInfo.thingsModels[k].datatype.type == 'object') {
//
for (let n = 0; n < this.deviceInfo.thingsModels[k].datatype.params.length; n++) {
if (this.deviceInfo.thingsModels[k].datatype.params[n].id == data[j].id) {
this.deviceInfo.thingsModels[k].datatype.params[n].shadow = data[j].value;
isComplete = true;
break;
}
}
} else if (this.deviceInfo.thingsModels[k].datatype.type == 'array') {
//
if (this.deviceInfo.thingsModels[k].datatype.arrayType == 'object') {
// 1.,id,array_01_gateway_temperature
if (String(data[j].id).indexOf('array_') == 0) {
for (let n = 0; n < this.deviceInfo.thingsModels[k].datatype.arrayParams.length; n++) {
for (let m = 0; m < this.deviceInfo.thingsModels[k].datatype.arrayParams[n].length; m++) {
if (this.deviceInfo.thingsModels[k].datatype.arrayParams[n][m].id == data[j].id) {
this.deviceInfo.thingsModels[k].datatype.arrayParams[n][m].shadow = data[j].value;
isComplete = true;
break;
}
}
if (isComplete) {
break;
}
}
} else {
// 2.gateway_temperature,ID
for (let n = 0; n < this.deviceInfo.thingsModels[k].datatype.arrayParams.length; n++) {
for (let m = 0; m < this.deviceInfo.thingsModels[k].datatype.arrayParams[n].length; m++) {
let index = n > 9 ? String(n) : '0' + k;
let prefix = 'array_' + index + '_';
if (this.deviceInfo.thingsModels[k].datatype.arrayParams[n][m].id == prefix + data[j].id) {
this.deviceInfo.thingsModels[k].datatype.arrayParams[n][m].shadow = data[j].value;
}
}
}
}
} else {
//
for (let n = 0; n < this.deviceInfo.thingsModels[k].datatype.arrayModel.length; n++) {
if (this.deviceInfo.thingsModels[k].datatype.arrayModel[n].id == data[j].id) {
this.deviceInfo.thingsModels[k].datatype.arrayModel[n].shadow = data[j].value;
break;
}
}
}
}
}
//
for (let k = 0; k < this.deviceInfo.chartList.length; k++) {
if (this.deviceInfo.chartList[k].id.indexOf('array_') == 0) {
// ,array_00_gateway_temperature
if (this.deviceInfo.chartList[k].id == data[j].id) {
this.deviceInfo.chartList[k].shadow = data[j].value;
//
for (let m = 0; m < this.monitorChart.length; m++) {
if (data[j].id == this.monitorChart[m].data.id) {
let data = [
{
value: this.deviceInfo.chartList[k].shadow,
name: this.monitorChart[m].data.name,
},
];
this.monitorChart[m].chart.setOption({
series: [
{
data: data,
},
],
});
break;
}
}
}
} else {
//
if (this.deviceInfo.chartList[k].id == data[j].id) {
this.deviceInfo.chartList[k].shadow = data[j].value;
//
for (let m = 0; m < this.monitorChart.length; m++) {
if (data[j].id == this.monitorChart[m].data.id) {
let data = [
{
value: this.deviceInfo.chartList[k].shadow,
name: this.monitorChart[m].data.name,
},
];
this.monitorChart[m].chart.setOption({
series: [
{
data: data,
},
],
});
break;
}
}
}
}
if (isComplete) {
break;
}
}
}
}
this.updateBasicSettings();
}, },
@ -1830,6 +1746,10 @@ export default {
this.editingPlaylistIndex = null; this.editingPlaylistIndex = null;
}, },
}, },
computed: {
// ...computed
},
}; };
</script> </script>
@ -2209,4 +2129,25 @@ export default {
background: #a8a8a8; background: #a8a8a8;
} }
} }
.board-status-single {
margin-top: 6px;
font-size: 15px;
span {
font-weight: 600;
&.online {
color: #67C23A;
}
&.offline {
color: #bbb;
}
}
}
.title.offline {
color: #bbb;
}
</style> </style>

View File

@ -263,14 +263,10 @@
</el-button> </el-button>
</div> </div>
<!-- <div class="copyright-wrap"> <div class="copyright-wrap">
<span>
Copyright © 2021-2025 <a target="_blank" href="https://beian.miit.gov.cn/">浙ICP备16005910号-1</a>
<a target="_blank" href="http://fastbee.cn">FastBee</a> </div>
All Rights Reserved.
</span>
<a target="_blank" href="https://beian.miit.gov.cn/">滇ICP备2023000466号-6</a>
</div> -->
</div> </div>
</div> </div>
</template> </template>