| | |
| | | </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' |
| | | |
| | |
| | | console.log('z-paging获取智能体列表') |
| | | |
| | | const response = await getAgentList() |
| | | await attachDevices(response) |
| | | |
| | | // 更新本地列表 |
| | | agentList.value = response |
| | |
| | | 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') |
| | | } |
| | | |
| | | // 进入编辑页面 |
| | |
| | | <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"> |
| | |
| | | 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; |
| | | |