From 220e4fab27b7f419b3e89e2f2d28ae789aac09d7 Mon Sep 17 00:00:00 2001
From: wangzhibo <wangzhibo@shsening.com>
Date: 星期四, 08 十月 2026 16:29:55 +0800
Subject: [PATCH] 5种场景模式家长端ok

---
 xiaozhi-esp32-server/main/manager-mobile/src/pages/index/index.vue |  223 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 221 insertions(+), 2 deletions(-)

diff --git a/xiaozhi-esp32-server/main/manager-mobile/src/pages/index/index.vue b/xiaozhi-esp32-server/main/manager-mobile/src/pages/index/index.vue
index 4d73a15..55c5e70 100644
--- a/xiaozhi-esp32-server/main/manager-mobile/src/pages/index/index.vue
+++ b/xiaozhi-esp32-server/main/manager-mobile/src/pages/index/index.vue
@@ -11,12 +11,13 @@
 </route>
 
 <script lang="ts" setup>
-import type { Agent } from '@/api/agent/types'
+import type { Agent, AgentDevice } from '@/api/agent/types'
+import { onShow } from '@dcloudio/uni-app'
 import { computed, onMounted, ref } from 'vue'
-// 鍦ㄧ粍浠舵寕杞藉悗璁剧疆瀵艰埅鏍忔爣棰�
 import { useMessage } from 'wot-design-uni/components/wd-message-box'
 import useZPaging from 'z-paging/components/z-paging/js/hooks/useZPaging.js'
 import { createAgent, deleteAgent, getAgentList } from '@/api/agent/agent'
+import { getBindDevices } from '@/api/device'
 import { t } from '@/i18n'
 import { toast } from '@/utils/toast'
 
@@ -68,6 +69,7 @@
     console.log('z-paging鑾峰彇鏅鸿兘浣撳垪琛�')
 
     const response = await getAgentList()
+    await attachDevices(response)
 
     // 鏇存柊鏈湴鍒楄〃
     agentList.value = response
@@ -144,6 +146,73 @@
   finally {
     deleteAgentLoading.value = false
   }
+}
+
+async function attachDevices(agents: Agent[]) {
+  await Promise.all((agents || []).map(async (agent) => {
+    if (Array.isArray(agent.devices))
+      return
+    try {
+      const list = await getBindDevices(agent.id)
+      agent.devices = (list || []).map(device => ({
+        macAddress: device.macAddress,
+        alias: device.alias,
+        online: device.online,
+      }))
+      agent.onlineDeviceCount = (agent.devices || []).filter(item => item.online === true).length
+      agent.deviceCount = agent.devices?.length || 0
+    }
+    catch (error) {
+      console.error('load home device status failed', error)
+      agent.devices = []
+    }
+  }))
+}
+
+function agentPresence(agent: Agent): 'online' | 'offline' | 'none' | 'unknown' {
+  const devices = agent.devices
+  if (!Array.isArray(devices))
+    return 'unknown'
+  if (devices.length === 0)
+    return 'none'
+  if (devices.some(item => item.online === true))
+    return 'online'
+  if (devices.every(item => item.online === false))
+    return 'offline'
+  return 'unknown'
+}
+
+function agentPresenceTitle(agent: Agent) {
+  const state = agentPresence(agent)
+  if (state === 'online') {
+    const devices = agent.devices || []
+    const online = devices.filter(item => item.online === true).length
+    if (devices.length > 1)
+      return t('home.onlineCount', { online, total: devices.length })
+    return t('device.online')
+  }
+  if (state === 'offline')
+    return t('device.offline')
+  if (state === 'none')
+    return t('home.noBoundDevice')
+  return t('device.checkingOnline')
+}
+
+function devicePresence(device: AgentDevice): 'online' | 'offline' | 'unknown' {
+  if (device.online === true)
+    return 'online'
+  if (device.online === false)
+    return 'offline'
+  return 'unknown'
+}
+
+function devicePresenceText(device: AgentDevice) {
+  const state = devicePresence(device)
+  if (state === 'online')
+    return t('device.online')
+  if (state === 'offline')
+    return t('device.offline')
+  return t('device.checkingOnline')
 }
 
 // 杩涘叆缂栬緫椤甸潰
@@ -260,6 +329,28 @@
                   <text class="agent-name">
                     {{ agent.agentName }}
                   </text>
+                  <view class="presence-chip" :class="agentPresence(agent)">
+                    <view class="presence-chip-dot" :class="agentPresence(agent)" />
+                    <text class="presence-chip-text" :class="agentPresence(agent)">
+                      {{ agentPresenceTitle(agent) }}
+                    </text>
+                  </view>
+                </view>
+
+                <view v-if="agent.devices && agent.devices.length" class="device-presence-list">
+                  <view
+                    v-for="device in agent.devices"
+                    :key="device.macAddress"
+                    class="device-presence-row"
+                  >
+                    <view class="device-presence-dot" :class="devicePresence(device)" />
+                    <text class="device-presence-name">
+                      {{ device.macAddress }}
+                    </text>
+                    <text class="device-presence-state" :class="devicePresence(device)">
+                      {{ devicePresenceText(device) }}
+                    </text>
+                  </view>
                 </view>
 
                 <view class="model-info">
@@ -557,15 +648,143 @@
     display: flex;
     align-items: center;
     justify-content: space-between;
+    gap: 12rpx;
     margin-bottom: 12rpx;
 
     .agent-name {
+      flex: 1;
+      min-width: 0;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
       font-size: 32rpx;
       font-weight: 600;
       color: #1a1a1a;
     }
   }
 
+  .presence-chip {
+    display: flex;
+    align-items: center;
+    gap: 8rpx;
+    flex-shrink: 0;
+    padding: 6rpx 14rpx;
+    border-radius: 24rpx;
+
+    &.online {
+      background: #e8f8ef;
+    }
+
+    &.offline {
+      background: #fff1f0;
+    }
+
+    &.none,
+    &.unknown {
+      background: #f5f7fb;
+    }
+  }
+
+  .presence-chip-dot {
+    width: 12rpx;
+    height: 12rpx;
+    flex-shrink: 0;
+    border-radius: 50%;
+
+    &.online {
+      background: #1aa34a;
+    }
+
+    &.offline {
+      background: #d4380d;
+    }
+
+    &.none,
+    &.unknown {
+      background: #c0c4cc;
+    }
+  }
+
+  .presence-chip-text {
+    font-size: 22rpx;
+    font-weight: 600;
+    line-height: 1.4;
+
+    &.online {
+      color: #146c36;
+    }
+
+    &.offline {
+      color: #d4380d;
+    }
+
+    &.none,
+    &.unknown {
+      color: #65686f;
+    }
+  }
+
+  .device-presence-list {
+    display: flex;
+    flex-direction: column;
+    gap: 8rpx;
+    margin-bottom: 16rpx;
+  }
+
+  .device-presence-row {
+    display: flex;
+    align-items: center;
+    gap: 10rpx;
+    padding: 8rpx 4rpx;
+  }
+
+  .device-presence-dot {
+    width: 12rpx;
+    height: 12rpx;
+    flex-shrink: 0;
+    border-radius: 50%;
+
+    &.online {
+      background: #1aa34a;
+    }
+
+    &.offline {
+      background: #d4380d;
+    }
+
+    &.unknown {
+      background: #c0c4cc;
+    }
+  }
+
+  .device-presence-name {
+    flex: 1;
+    min-width: 0;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    font-size: 24rpx;
+    color: #232338;
+  }
+
+  .device-presence-state {
+    flex-shrink: 0;
+    font-size: 22rpx;
+    font-weight: 600;
+
+    &.online {
+      color: #146c36;
+    }
+
+    &.offline {
+      color: #d4380d;
+    }
+
+    &.unknown {
+      color: #65686f;
+    }
+  }
+
   .model-info {
     margin-bottom: 16rpx;
 

--
Gitblit v1.9.1