325 lines
7.3 KiB
Vue

<template>
<view class="gateway-container">
<!-- 设备状态卡片 -->
<view class="card">
<view class="status-titletop">{{ title }}</view>
<view style="padding:20rpx;">
<u--form labelPosition="left" labelWidth="100"
:labelStyle="{ marginRight: '16px', lineHeight: '32px', width: '50px', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', color: '#000000' }">
<view class="version-wrap">
<u-form-item :label="$tt('status.deviceVersion')">
<u-row>
<u-col span="8">
<u--text :text="'Version ' + device.firmwareVersion"></u--text>
</u-col>
</u-row>
</u-form-item>
</view>
</u--form>
</view>
</view>
<!-- 网关信息卡片 -->
<view class="card gateway-info">
<view class="section-title">网关信息</view>
<view class="info-content">
<view class="info-grid">
<view class="info-item">
<text class="info-label">设备名称</text>
<text class="info-value">{{ device.deviceName || '未命名' }}</text>
</view>
<view class="info-item">
<text class="info-label">设备ID</text>
<text class="info-value">{{ device.deviceId || '未知' }}</text>
</view>
<view class="info-item">
<text class="info-label">序列号</text>
<text class="info-value">{{ device.serialNumber || '未知' }}</text>
</view>
<view class="info-item">
<text class="info-label">产品ID</text>
<text class="info-value">{{ device.productId || '未知' }}</text>
</view>
</view>
</view>
</view>
<!-- 子设备分段控制器 -->
<view class="subsection-container">
<view class="subsection-header">
<text class="subsection-title">子设备管理</text>
<view class="subdevice-status">
<view class="status-item">
<view class="status-dot online"></view>
<text>声卡在线</text>
</view>
<view class="status-item">
<view class="status-dot online"></view>
<text>显卡在线</text>
</view>
</view>
</view>
<u-subsection :list="subsectionList" :current="currentSubsection" @change="onSubsectionChange"
activeColor="#2979ff" inactiveColor="#666" :fontSize="14" :height="80" :bold="true" mode="subsection" :animation="true"
></u-subsection>
</view>
<!-- 子设备内容区域 -->
<view class="subdevice-content">
<!-- 声卡子设备 -->
<view v-if="currentSubsection === 0" class="subdevice-panel">
<voice-control :device="device"></voice-control>
</view>
<!-- 显卡子设备 -->
<view v-if="currentSubsection === 1" class="subdevice-panel">
<display-control :device="device"></display-control>
</view>
<view v-if="currentSubsection === 2" class="subdevice-panel">
<gatewayset :device="device"></gatewayset>
</view>
</view>
</view>
</template>
<script>
import VoiceControl from './voice.vue';
import DisplayControl from './display.vue';
import gatewayset from './gatewayset.vue';
export default {
name: 'GatewayControl',
components: {
VoiceControl,
DisplayControl,
gatewayset
},
props: {
device: {
type: Object,
required: true
}
},
data() {
return {
title: '设备离线',
currentSubsection: 0,
subsectionList: [
{
name: '声卡',
icon: 'volume',
description: '音频控制'
},
{
name: '显卡',
icon: 'eye',
description: '显示控制'
},
{
name: '网关',
icon: 'eye',
description: '网关控制'
}
],
deviceInfo: {
chartList: [],
}
};
},
watch: {
device: function (newVal, oldVal) {
if (newVal.deviceName !== '') {
this.deviceInfo = newVal;
this.updateDeviceStatus(this.deviceInfo);
}
}
},
created() {
if (this.device !== null && Object.keys(this.device).length !== 0) {
this.deviceInfo = this.device;
this.updateDeviceStatus(this.deviceInfo);
};
this.mqttCallback();
},
methods: {
onSubsectionChange(index) {
this.currentSubsection = index;
console.log('切换到子设备:', this.subsectionList[index].text);
},
mqttCallback() {
this.$mqttTool.client.on('message', (topic, message, buffer) => {
let topics = topic.split('/');
let productId = topics[1];
let deviceNum = topics[2];
message = JSON.parse(message.toString());
if (topics[3] == 'status') {
if (this.deviceInfo.serialNumber == deviceNum) {
this.deviceInfo.status = message.status;
this.deviceInfo.isShadow = message.isShadow;
this.deviceInfo.rssi = message.rssi;
this.updateDeviceStatus(this.deviceInfo);
}
}
});
},
updateDeviceStatus(device) {
if (device.status === 3) {
this.title = this.$tt('status.online');
} else {
this.title = device.isShadow === 1 ? this.$tt('status.shadow') : this.$tt('status.deviceOffline');
}
}
}
};
</script>
<style lang="scss" scoped>
.gateway-container {
padding: 24rpx;
background-color: #f5f7fa;
min-height: 100vh;
font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
.card {
background-color: #fff;
border-radius: 16rpx;
margin-bottom: 24rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
overflow: hidden;
transition: all 0.3s ease;
&:hover {
box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.1);
}
}
.status-titletop {
font-weight: bold;
font-size: 15px;
color: #333333;
line-height: 42rpx;
text-align: left;
padding: 15rpx 28rpx;
background-color: #eef6ff;
border-bottom: 1rpx solid #dceaff;
}
.version-wrap {
background-color: #F7F7F7;
border-radius: 10rpx;
padding: 0 42rpx;
font-size: 24rpx;
color: #000000;
line-height: 42rpx;
}
.subsection-container {
background-color: #fff;
border-radius: 16rpx;
margin-bottom: 24rpx;
padding: 20rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
.subsection-header {
margin-bottom: 20rpx;
display: flex;
justify-content: space-between;
align-items: center;
.subsection-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
}
.subdevice-status {
display: flex;
gap: 20rpx;
.status-item {
display: flex;
align-items: center;
gap: 8rpx;
.status-dot {
width: 12rpx;
height: 12rpx;
border-radius: 50%;
&.online {
background-color: #52c41a;
box-shadow: 0 0 8rpx rgba(82, 196, 26, 0.4);
}
&.offline {
background-color: #ff4d4f;
box-shadow: 0 0 8rpx rgba(255, 77, 79, 0.4);
}
}
text {
font-size: 24rpx;
color: #666;
}
}
}
}
}
.subdevice-content {
.subdevice-panel {
background-color: #fff;
border-radius: 16rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
overflow: hidden;
}
}
.gateway-info {
background-color: #fff;
border-radius: 16rpx;
margin-bottom: 24rpx;
padding: 20rpx;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
.section-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
padding: 24rpx 24rpx 16rpx;
border-bottom: 1rpx solid #f0f2f5;
}
.info-content {
padding: 24rpx;
.info-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20rpx;
.info-item {
display: flex;
flex-direction: column;
gap: 8rpx;
.info-label {
font-size: 26rpx;
color: #666;
font-weight: 500;
}
.info-value {
font-size: 28rpx;
color: #333;
font-weight: 600;
}
}
}
}
}
}
</style>