CMVR-IOT-UI/src/views/resource/terminal/index.vue

76 lines
6.8 KiB
Vue
Raw Normal View History

<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>