CMVR-IOT-UI/src/views/resource/terminal/index.vue
lixiaolong 3909a1f217 refactor(api): 调整API导入路径并更新设备注册相关功能
- 将inspection/robot API导入路径更改为resource/robot
- 更新getRobotDevicesByRobotId等函数的导入路径
- 修改流程序列组件中的API引用路径
- 更新设备注册页面的相关API调用
- 移除AppMain.vue中的过渡动画
- 添加新的resource/device API模块
- 更新语音合成组件的API导入路径
- 修改Node-RED转换工具的API引用
- 调整手动接管方向控制的API导入
- 更新流执行工具的API调用
- 优化流资源角色处理逻辑
- 移除已废弃的设备控制台和配置页面
- 更新相机和灵巧手组件的数据获取方式
- 调整麦克风组件的API引用路径
- 更新VueFlow组件的API导入
- 修改开发环境配置的URL地址和端口设置
2026-08-24 16:50:24 +08:00

76 lines
6.8 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="app-container">
<el-form :inline="true" :model="query">
<el-form-item label="终端"><el-input v-model="query.terminalName" clearable @keyup.enter="search" /></el-form-item>
<el-form-item label="连接状态"><el-select v-model="query.connectStatus" clearable style="width: 120px"><el-option label="在线" value="1" /><el-option label="离线" value="0" /></el-select></el-form-item>
<el-form-item><el-button type="primary" icon="Search" @click="search">查询</el-button><el-button icon="Refresh" @click="reset">重置</el-button></el-form-item>
</el-form>
<el-row class="mb8"><el-button type="primary" icon="Plus" @click="openAdd">登记终端</el-button></el-row>
<el-table v-loading="loading" :data="rows" row-key="id">
<el-table-column label="终端" min-width="210"><template #default="{ row }"><strong>{{ row.terminalName || row.terminalCode }}</strong><div class="secondary">{{ row.terminalCode }}</div></template></el-table-column>
<el-table-column label="当前地址" min-width="180"><template #default="{ row }">{{ endpoint(row) }}</template></el-table-column>
<el-table-column label="连接" width="95"><template #default="{ row }"><el-tag :type="row.connectStatus === '1' ? 'success' : 'info'">{{ row.connectStatus === '1' ? '在线' : '离线' }}</el-tag></template></el-table-column>
<el-table-column label="软件版本" prop="softwareVersion" min-width="130" />
<el-table-column label="绑定机器人" min-width="220"><template #default="{ row }"><span v-if="row.robotCount">{{ row.robotIdsCsv }}</span><span v-else class="secondary">未绑定</span></template></el-table-column>
<el-table-column label="最后心跳" prop="lastHeartbeatTime" width="180" />
<el-table-column label="操作" width="190" fixed="right"><template #default="{ row }"><el-button link type="primary" icon="Link" @click="openBindings(row)">绑定</el-button><el-button link type="primary" icon="Edit" @click="openEdit(row)">编辑</el-button><el-button link type="danger" icon="Delete" :disabled="row.connectStatus === '1'" @click="remove(row)">删除</el-button></template></el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="query.pageNum" v-model:limit="query.pageSize" @pagination="load" />
<el-dialog v-model="formOpen" :title="form.id ? '编辑边缘终端' : '登记边缘终端'" width="540px">
<el-alert v-if="!form.id" title="终端编码应与QUIC节点ID一致;连接地址和在线状态由终端自动上报。" type="info" :closable="false" show-icon />
<el-form :model="form" label-width="95px" class="terminal-form">
<el-form-item label="终端编码" required><el-input v-model="form.terminalCode" :disabled="Boolean(form.id)" /></el-form-item>
<el-form-item label="终端名称" required><el-input v-model="form.terminalName" /></el-form-item>
<el-form-item label="启用状态"><el-switch v-model="form.status" active-value="0" inactive-value="1" /></el-form-item>
<el-form-item label="备注"><el-input v-model="form.remark" type="textarea" /></el-form-item>
</el-form>
<template #footer><el-button @click="formOpen = false">取消</el-button><el-button type="primary" :loading="saving" @click="save">保存</el-button></template>
</el-dialog>
<el-dialog v-model="bindingOpen" title="绑定机器人" width="620px">
<el-alert title="一台机器人同一时间只归属一个在线边缘终端;重新绑定会自动解除旧终端关系。" type="info" :closable="false" show-icon />
<el-select v-model="selectedRobotIds" multiple filterable collapse-tags collapse-tags-tooltip placeholder="选择机器人" class="binding-select">
<el-option v-for="robot in robots" :key="robot.robotId" :label="`${robot.robotName || robot.robotId} (${robot.robotId})`" :value="robot.robotId" />
</el-select>
<template #footer><el-button @click="bindingOpen = false">取消</el-button><el-button type="primary" :loading="saving" @click="saveBindings">保存绑定</el-button></template>
</el-dialog>
</div>
</template>
<script setup name="ResourceTerminal">
import { onActivated, onMounted, reactive, ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { listResourceTerminals, addResourceTerminal, updateResourceTerminal, deleteResourceTerminals, listTerminalRobots, updateTerminalRobots } from '@/api/resource/terminal'
import { listResourceRobots } from '@/api/resource/robot'
const loading = ref(false), saving = ref(false), rows = ref([]), total = ref(0), formOpen = ref(false), bindingOpen = ref(false), robots = ref([]), selectedRobotIds = ref([]), activeTerminal = ref(null)
const query = reactive({ pageNum: 1, pageSize: 20, terminalName: '', connectStatus: '' })
const empty = () => ({ id: '', terminalCode: '', terminalName: '', status: '0', remark: '' })
const form = reactive(empty())
const endpoint = row => row.ipAddress ? `${row.ipAddress}${row.port ? `:${row.port}` : ''}` : '-'
async function load() { loading.value = true; try { const res = await listResourceTerminals(query); rows.value = res.rows || []; total.value = res.total || 0 } finally { loading.value = false } }
function search() { query.pageNum = 1; load() }
function reset() { Object.assign(query, { pageNum: 1, terminalName: '', connectStatus: '' }); load() }
function openAdd() { Object.assign(form, empty()); formOpen.value = true }
function openEdit(row) { Object.assign(form, empty(), row); formOpen.value = true }
async function save() { if (!form.terminalCode.trim() || !form.terminalName.trim()) return ElMessage.warning('请输入终端编码和名称'); saving.value = true; try { if (form.id) await updateResourceTerminal(form); else await addResourceTerminal(form); ElMessage.success('终端已保存'); formOpen.value = false; load() } finally { saving.value = false } }
async function remove(row) { await ElMessageBox.confirm(`确定删除终端“${row.terminalName || row.terminalCode}”吗?`, '提示', { type: 'warning' }); await deleteResourceTerminals(row.id); ElMessage.success('已删除'); load() }
async function openBindings(row) {
activeTerminal.value = row
const [robotRes, bindingRes] = await Promise.all([listResourceRobots({ pageNum: 1, pageSize: 10000 }), listTerminalRobots(row.id)])
robots.value = robotRes.rows || []
selectedRobotIds.value = bindingRes.data || []
bindingOpen.value = true
}
async function saveBindings() { saving.value = true; try { await updateTerminalRobots(activeTerminal.value.id, selectedRobotIds.value); ElMessage.success('机器人绑定已保存'); bindingOpen.value = false; load() } finally { saving.value = false } }
onMounted(load)
onActivated(load)
</script>
<style scoped>
.secondary { color: var(--el-text-color-secondary); font-size: 12px; margin-top: 3px; }
.terminal-form { margin-top: 20px; }
.binding-select { width: 100%; margin-top: 20px; }
</style>