robot_bigScreen/src/components/dialog/RobotListModal.vue
2025-06-05 18:21:18 +08:00

446 lines
9.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="robot-list-modal" v-if="visible">
<div class="modal-content">
<!-- 标题 -->
<div class="modal-header">
<span class="title">机器人总数</span>
<img src="../../assets/img/close.png" class="close-icon" @click="handleClose" />
</div>
<!-- 内容区域 -->
<div class="modal-body">
<!-- 筛选栏 -->
<div class="filter-bar">
<div class="filter-tabs">
<div
v-for="tab in tabs"
:key="tab.type"
class="tab-item"
:class="{ active: currentTab === tab.type }"
@click="handleTabClick(tab.type)"
>
{{ tab.label }} ({{ getTabCount(tab.type) }})
</div>
</div>
<div class="type-select">
<span class="select-label">类型</span>
<span class="select-divider">|</span>
<div class="select-wrapper" @click="toggleSelect" @blur="closeSelect" tabindex="0">
<span class="select-text">{{ selectedType }}</span>
<img
v-if="!selectOpen"
src="../../assets/img/arraw_bottom.png"
alt="下箭头"
class="arrow-icon"
/>
<img
v-else
src="../../assets/img/arraw_top.png"
alt="上箭头"
class="arrow-icon"
/>
<ul v-if="selectOpen" class="select-dropdown">
<li v-for="type in robotTypes" :key="type" @click.stop="selectType(type)">{{ type }}</li>
</ul>
</div>
</div>
</div>
<!-- 表格 -->
<div class="table-container">
<table class="robot-table">
<thead>
<tr>
<th>机器人编号</th>
<th>类型</th>
<th>状态</th>
<th>电量</th>
</tr>
</thead>
<tbody>
<tr v-for="robot in filteredRobots" :key="robot.id">
<td>{{ robot.id }}</td>
<td>{{ robot.name }}</td>
<td :class="robot.status">{{ robot.status }}</td>
<td>
<BatteryIndicator :battery="robot.battery" />
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted, watch } from 'vue';
import BatteryIndicator from '../common/BatteryIndicator.vue';
import { homeApi } from '../../api/index';
const props = defineProps({
visible: {
type: Boolean,
default: false
}
});
const emit = defineEmits(['update:visible']);
const handleClose = () => {
emit('update:visible', false);
};
// Tab相关
const tabs = [
{ type: 'all', label: '全部' },
{ type: 'online', label: '在线' },
{ type: 'offline', label: '离线' },
{ type: 'fault', label: '故障' }
];
const currentTab = ref('all');
const handleTabClick = (type) => {
currentTab.value = type;
};
// 类型选择相关
const robotTypes = ref(['全部类型']);
const selectedType = ref('全部类型');
const selectOpen = ref(false);
const toggleSelect = () => {
selectOpen.value = !selectOpen.value;
};
const closeSelect = () => {
selectOpen.value = false;
};
const selectType = (type) => {
selectedType.value = type;
selectOpen.value = false;
};
// 机器人列表数据
const robotList = ref([]);
const loading = ref(false);
const error = ref(null);
// 获取机器人列表
const fetchRobotList = async () => {
loading.value = true;
error.value = null;
try {
const res = await homeApi.getRobotList({
tenantInfoId: '4fff5d4bcc4b4239941ff077a0da8958', // 租户id
number: null, // 机器人名
status: null, // 是否故障
onlineStatus: null // 在线状态
});
if (res.code === 200) {
// 处理返回的数据
const allRobots = [];
const groupTypes = new Set(['全部类型']);
// 遍历分组数据
Object.entries(res.data).forEach(([groupName, robots]) => {
robots.forEach(robot => {
// 添加分组名称
const robotData = {
id: robot.number,
name: groupName,
groupId: robot.groupingId,
robotId: robot.robotId,
status: getStatusText(robot.onlineStatus, robot.status),
battery: robot.robotInfo?.power || 0,
position: robot.robotInfo?.positon || '',
temperature: robot.robotInfo?.temperature || '',
humidity: robot.robotInfo?.humidity || '',
updateTime: robot.robotInfo?.updateTime || ''
};
allRobots.push(robotData);
groupTypes.add(groupName);
});
});
robotList.value = allRobots;
robotTypes.value = ['全部类型', ...Array.from(groupTypes).filter(type => type !== '全部类型')];
console.log('获取机器人列表成功:', robotList.value);
} else {
error.value = res.msg || '获取机器人列表失败';
console.error('获取机器人列表失败:', res);
}
} catch (err) {
error.value = '获取机器人列表失败';
console.error('获取机器人列表错误:', err);
} finally {
loading.value = false;
}
};
// 根据状态码获取状态文本
const getStatusText = (onlineStatus, status) => {
if (onlineStatus === '0') return '离线';
// 在线状态下根据status判断
const statusMap = {
'0': '充电中',
'1': '待机中',
'2': '运行中',
'3': '故障'
};
return statusMap[status] || '未知';
};
// 过滤逻辑
const filteredRobots = computed(() => {
let result = robotList.value;
// 状态过滤
if (currentTab.value !== 'all') {
const statusMap = {
online: ['运行中', '待机中'],
offline: ['离线'],
fault: ['故障']
};
const statusList = statusMap[currentTab.value] || [];
result = result.filter(robot => statusList.includes(robot.status));
}
// 类型过滤
if (selectedType.value !== '全部类型') {
result = result.filter(robot => robot.name === selectedType.value);
}
return result;
});
// 获取各状态数量
const getTabCount = (type) => {
if (type === 'all') return robotList.value.length;
const statusMap = {
online: ['运行中', '待机中'],
offline: ['离线'],
fault: ['故障']
};
const statusList = statusMap[type] || [];
return robotList.value.filter(robot => statusList.includes(robot.status)).length;
};
// 监听弹窗显示状态,显示时获取数据
watch(() => props.visible, (newVal) => {
if (newVal) {
fetchRobotList();
}
});
// 组件挂载时获取数据
onMounted(() => {
if (props.visible) {
fetchRobotList();
}
});
</script>
<style scoped>
.robot-list-modal {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal-content {
width: 900px;
height: 600px;
background: url("../../assets/img/alert.png") no-repeat;
background-size: 100% 100%;
border-radius: 4px;
padding: 20px;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.title {
color: #B9E8FF;
font-size: 28px;
letter-spacing: 4px;
padding-left: 20px;
}
.close-icon {
width: 20px;
height: 20px;
cursor: pointer;
}
.modal-body {
padding: 0 10px;
}
.filter-bar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.filter-tabs {
display: flex;
gap: 0;
background: rgba(0, 21, 31, 0.3);
border: 1px solid rgba(0, 206, 234, 0.7);
border-radius: 2px;
overflow: hidden;
}
.tab-item {
color: #B9E8FF;
font-size: 14px;
cursor: pointer;
padding: 8px 20px;
border-right: 1px solid rgba(0, 206, 234, 0.7);
}
.tab-item:last-child {
border-right: none;
}
.tab-item.active {
background: rgba(0, 206, 234, 0.2);
}
.type-select {
display: flex;
align-items: center;
font-size: 14px;
color: #B9E8FF;
background: rgba(0, 21, 31, 0.3);
border: 1px solid rgba(0, 206, 234, 0.7);
border-radius: 2px;
padding: 5px 10px;
}
.select-label {
color: #B9E8FF;
}
.select-divider {
color: #00ffff;
margin: 0 10px;
}
.select-wrapper {
position: relative;
cursor: pointer;
min-width: 120px;
outline: none;
}
.select-text {
color: #B9E8FF;
margin-right: 25px;
}
.arrow-icon {
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
width: 16px;
height: 16px;
}
.select-dropdown {
position: absolute;
top: 100%;
right: 0;
background: #00273A;
border: 1px solid rgba(0, 206, 234, 0.7);
border-radius: 2px;
margin-top: 5px;
padding: 5px 0;
min-width: 120px;
z-index: 10;
}
.select-dropdown li {
padding: 8px 15px;
color: #B9E8FF;
cursor: pointer;
}
.select-dropdown li:hover {
background: rgba(0, 206, 234, 0.2);
}
.table-container {
border: 1px solid rgba(0, 206, 234, 0.7);
border-radius: 4px;
overflow: hidden;
}
.robot-table {
width: 100%;
border-collapse: collapse;
color: #B9E8FF;
}
.robot-table th {
background: rgba(0, 21, 31, 0.3);
padding: 12px;
text-align: center;
font-weight: normal;
border-bottom: 1px solid #244C60;
}
.robot-table td {
padding: 12px;
text-align: center;
}
.robot-table td:last-child {
display: flex;
justify-content: center;
align-items: center;
}
.robot-table td.运行中 {
color: #00FF84;
}
.robot-table td.离线 {
color: #F33F3F;
}
.robot-table td.充电中 {
color: #FFB800;
}
.battery-wrapper,
.battery-box,
.battery-level,
.battery-text {
/* 这些样式将被删除 */
}
</style>