调整传感器页面

This commit is contained in:
zx
2026-04-23 16:01:13 +08:00
parent 63d1a62a06
commit 6904f960b7
2 changed files with 128 additions and 69 deletions

View File

@@ -25,9 +25,6 @@
</view>
<view class="report"> 最近上报:{{ latestReportTime || '--' }} </view>
</view>
</view>
<view class="sensor-grid">
@@ -40,30 +37,38 @@
<view v-for="item in sensorCards" :key="item.cardKey" :class="['sensor-card', item.statusClass]">
<view class="sensor-content">
<view class="sensor-main">
<view class="sensor-top">
<view class="sensor-top flex">
<view :class="['sensor-icon', item.type]">
<text>{{ item.icon }}</text>
</view>
<view class="sensor-state">
<view v-if="isSocketControlType(item.type)" class="socket-actions">
<uv-switch v-model="controlLoadingMap[item.cardKey]" active-color="#165D46"
@change="(e) => handleSocketControl(e, item)" />
</view>
<!-- <view class="sensor-state">
<text class="dot"></text>
{{ item.onlineText }}
</view>
</view> -->
</view>
<view class="sensor-body">
<text class="location">{{ item.locationName }}</text>
<view class="type-name">{{ item.typeName }}</view>
<text class="summary">{{ item.summary }}</text>
<view class="flex justify-between align-center">
<view class="type-name mb-4">{{ item.typeName }} </view>
</view>
<view>
<text class="mr-4"> {{ item.summary }}</text>|
<text :class="['sensor-state', item.statusClass, 'ml-4']"> {{ item.onlineText }}</text>
</view>
<view v-if="isSocketControlType(item.type)" class="socket-actions">
<button class="control-btn on" :disabled="!!controlLoadingMap[item.cardKey]"
<!-- <text class="control-btn on" :disabled="!!controlLoadingMap[item.cardKey]"
@tap="handleSocketControl(item, 'on')">
{{ getSocketActionText(item.type, 'on', !!controlLoadingMap[item.cardKey]) }}
</button>
<button class="control-btn off" :disabled="!!controlLoadingMap[item.cardKey]"
</text>
<text class="control-btn off" :disabled="!!controlLoadingMap[item.cardKey]"
@tap="handleSocketControl(item, 'off')">
{{ getSocketActionText(item.type, 'off', !!controlLoadingMap[item.cardKey]) }}
</button>
</text> -->
</view>
<view v-else-if="item.type === 'switch'" class="switch-actions">
@@ -84,7 +89,7 @@
</view>
</view>
<view class="metric-panel">
<!-- <view class="metric-panel">
<text class="panel-title">实时指标</text>
<view class="metric-list">
<view v-for="metric in item.metrics" :key="metric.label" class="metric-item">
@@ -96,15 +101,18 @@
<text class="value">等待数据</text>
</view>
</view>
</view>
</view> -->
</view>
<view class="sensor-footer">
<!-- <view class="sensor-footer">
<text>DevEUI{{ item.devEui || '--' }}</text>
<text>{{ item.reportTime || '暂无上报' }}</text>
</view>
</view> -->
</view>
</view>
</view>
</template>
@@ -228,21 +236,31 @@ function patchRealtimeState(prev, next) {
return res
}
async function handleSocketControl(item, action) {
const deviceId = item.id || item.deviceId
const devEui = item.devEui || item.devEUI || item.dev_eui
if (!devEui) return uni.showToast({ title: '未找到设备', icon: 'none' })
const k = item.cardKey || String(deviceId)
if (controlLoadingMap[k]) return
controlLoadingMap[k] = true
try {
const status = action === 'on' ? 1 : 0
await controlSocket({ devEui, deviceId, status })
syncSocketLocalState(item, status)
uni.showToast({ title: '指令已发送', icon: 'success' })
} finally {
controlLoadingMap[k] = false
async function handleSocketControl(e, item) {
console.log(e, item, '111');
const action = e ? 'on' : 'off'
console.log(action, '111');
if (action) {
const deviceId = item.id || item.deviceId
const devEui = item.devEui || item.devEUI || item.dev_eui
console.log('devEui', devEui);
if (!devEui) return uni.showToast({ title: '未找到设备', icon: 'none' })
const k = item.cardKey || String(deviceId)
if (controlLoadingMap[k]) return
controlLoadingMap[k] = true
try {
const status = action === 'on' ? 1 : 0
console.log(status, action, 'status');
await controlSocket({ devEui, deviceId, status })
syncSocketLocalState(item, status)
uni.showToast({ title: '指令已发送', icon: 'success' })
} finally {
controlLoadingMap[k] = false
}
}
}
async function handleLightSwitchControl(item, ch, action) {
@@ -574,24 +592,52 @@ onBeforeUnmount(() => {
color: #999;
}
/* 父容器:网格布局 → 2个一行 */
.sensor-grid {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
/* 两个卡片之间的间距 */
padding: 10rpx;
}
/* loading / 空状态 占满整行 */
.loading-view,
.empty-state {
width: 100%;
text-align: center;
padding: 40rpx 0;
font-size: 28rpx;
color: #666;
}
.sensor-card {
// background: #fff;
// border-radius: 24rpx;
// padding: 24rpx;
// margin-bottom: 20rpx;
// position: relative;
// overflow: hidden;
width: calc(50% - 10rpx);
box-sizing: border-box;
border-radius: 16rpx;
background: #fff;
border-radius: 24rpx;
padding: 24rpx;
margin-bottom: 20rpx;
position: relative;
overflow: hidden;
}
.sensor-card::before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 8rpx;
background: #08a089;
}
// .sensor-card::before {
// content: '';
// position: absolute;
// left: 0;
// top: 0;
// bottom: 0;
// width: 8rpx;
// background: #08a089;
// }
.sensor-card.offline {
opacity: 0.6;
@@ -601,11 +647,11 @@ onBeforeUnmount(() => {
.sensor-content {
display: flex;
flex-direction: column;
gap: 20rpx;
gap: 8px;
}
.sensor-main {
background: #f9f9f9;
background: #fff;
border-radius: 20rpx;
padding: 20rpx;
}
@@ -629,14 +675,24 @@ onBeforeUnmount(() => {
color: #088a77;
}
.sensor-state {
font-size: 24rpx;
padding: 8rpx 16rpx;
background: #e6f7f5;
.sensor-state.offline {
opacity: 0.6;
color: grey;
filter: grayscale(0.5);
}
.sensor-state.online {
color: #088a77;
border-radius: 100rpx;
display: flex;
align-items: center;
}
.sensor-state {
font-size: 14px;
// padding: 8rpx 16rpx;
// background: #e6f7f5;
// color: #088a77;
// border-radius: 100rpx;
// display: flex;
// align-items: center;
}
.dot {
@@ -649,21 +705,22 @@ onBeforeUnmount(() => {
.sensor-body {
margin-top: 20rpx;
}
.location {
font-size: 24rpx;
font-size: 16px;
color: #666;
}
.type-name {
font-size: 32rpx;
font-weight: bold;
margin: 8rpx 0;
font-size: 16px;
font-weight: 600;
// margin: 8rpx 0;
}
.summary {
font-size: 26rpx;
font-size: 14px;
background: #f0f0f0;
padding: 8rpx 16rpx;
border-radius: 100rpx;
@@ -673,8 +730,9 @@ onBeforeUnmount(() => {
.socket-actions {
display: flex;
justify-content: space-between;
gap: 16rpx;
margin-top: 20rpx;
margin-top: 10px;
}
.switch-actions {
@@ -690,13 +748,13 @@ onBeforeUnmount(() => {
.ch-label {
width: 80rpx;
font-size: 24rpx;
font-size: 12px;
}
.control-btn {
padding: 12rpx 24rpx;
border-radius: 100rpx;
font-size: 24rpx;
font-size: 12px;
font-weight: bold;
border: none;
}
@@ -714,11 +772,11 @@ onBeforeUnmount(() => {
.metric-panel {
background: #f9f9f9;
border-radius: 20rpx;
padding: 20rpx;
padding: 10rpx;
}
.panel-title {
font-size: 26rpx;
font-size: 14px;
color: #666;
margin-bottom: 16rpx;
display: block;
@@ -739,13 +797,13 @@ onBeforeUnmount(() => {
}
.label {
font-size: 22rpx;
font-size: 14px;
color: #666;
display: block;
}
.value {
font-size: 28rpx;
font-size: 14px;
font-weight: bold;
color: #088a77;
margin-top: 4rpx;