Files
IOT_WEB/src/components/thing/PointSendForm.vue
T
dengboling 240ede9769 feat: 网关管理页面 + 设备表单网关下拉联动
- 新增 src/api/gateway.js(网关 CRUD + 测试连接 + options API + 枚举映射)
- 新增 src/views/config/gateway/Index.vue(网关管理页面:列表/新增/编辑/测试连接/详情抽屉+下挂设备)
- 修改 src/views/config/device/Index.vue(GatewayCode 文本输入改为 GatewayId 下拉选择,列表列显示 GatewayName)
- 新增 src/api/product.js、src/api/thingPoint.js(产品/物模型点 API)
- 新增 src/components/thing/(PointSendForm、ThingPointTable、ThingAlarmPanel 共享组件)
2026-09-04 17:43:36 +08:00

155 lines
5.2 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="point-send-form">
<div class="ps-toolbar">
<span class="ps-count">
{{ points.length }} 个点可下发 {{ writablePoints.length }}
<span v-if="points.length" class="ps-tip">只读点不支持下发Int32/Float 从地址起连写 2 个寄存器</span>
</span>
<el-button link type="primary" size="small" :loading="loading" @click="fetchPoints">刷新</el-button>
</div>
<el-table :data="points" v-loading="loading" size="small" border stripe>
<el-table-column prop="Code" label="编码" width="120" />
<el-table-column prop="Name" label="名称" min-width="110" show-overflow-tooltip />
<el-table-column label="寄存器" width="90">
<template #default="{ row }">{{ registerLabel(row.RegisterType) }}</template>
</el-table-column>
<el-table-column label="地址" width="70" align="center">
<template #default="{ row }">0x{{ dec2hex(row.Address) }}</template>
</el-table-column>
<el-table-column label="读写" width="60" align="center">
<template #default="{ row }">{{ rwLabel(row.Rw) }}</template>
</el-table-column>
<el-table-column label="状态" width="84" align="center">
<template #default="{ row }">
<el-tag v-if="row.Rw === 1" size="small" type="info">只读</el-tag>
<el-tag v-else size="small" type="success">可下发</el-tag>
</template>
</el-table-column>
<el-table-column label="下发值" width="150">
<template #default="{ row }">
<el-switch
v-if="row.DataType === 1"
:model-value="row._sendValue === 1"
active-text=""
@change="row._sendValue = $event ? 1 : 0"
/>
<el-input-number
v-else
v-model="row._sendValue"
:precision="row.DataType === 5 ? 1 : 0"
:step="1"
:controls="false"
size="small"
style="width: 100%"
/>
</template>
</el-table-column>
<el-table-column label="单位" width="60" align="center">
<template #default="{ row }">{{ row.Unit || '-' }}</template>
</el-table-column>
<el-table-column label="操作" width="70" fixed="right" align="center">
<template #default="{ row }">
<el-button
link type="primary"
:disabled="row.Rw === 1"
@click="onSend(row)"
>下发</el-button>
</template>
</el-table-column>
</el-table>
<!-- 空状态区分无点 / 点均不可下发 -->
<el-empty
v-if="!loading && points.length === 0"
description="该设备暂无物模型点,请先在「物模型点」标签页为该设备添加数据点"
:image-size="60"
/>
<el-alert
v-else-if="!loading && writablePoints.length === 0"
title="已添加的点均为只读,暂无可下发点(可将点读写属性改为「只写/读写」)"
type="info"
:closable="false"
class="ps-feedback"
/>
<!-- 下发反馈 -->
<el-alert v-if="feedback.text" :title="feedback.text" :type="feedback.type" :closable="false" class="ps-feedback" />
</div>
</template>
<script setup>
import { ref, computed, watch, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { getThingPoints, registerLabel, rwLabel } from '@/api/thingPoint'
import { sendDeviceCommand } from '@/api/device'
const props = defineProps({
deviceId: { type: String, required: true }
})
const loading = ref(false)
const points = ref([])
const feedback = ref({ text: '', type: 'success' })
// 只读(1)的点不能下发;只写/读写都可以(Int32/Float 走 FC16 连写 2 个寄存器,已支持)
const writablePoints = computed(() => points.value.filter(p => p.Rw !== 1))
function dec2hex(n) {
return (Number(n) || 0).toString(16).toUpperCase().padStart(4, '0')
}
async function fetchPoints() {
loading.value = true
try {
const pts = (await getThingPoints(2, props.deviceId)) || []
// 显示设备全部点(含只读),便于与「物模型点」标签页对照
points.value = pts.map(p => ({ ...p, _sendValue: p.DataType === 1 ? 1 : 0 }))
} catch (e) {
points.value = []
} finally {
loading.value = false
}
}
async function onSend(row) {
try {
await sendDeviceCommand(props.deviceId, {
Id: props.deviceId,
PointId: row.Id,
Value: row._sendValue ?? 0,
IsSimulated: false
})
// res 为后端返回的 Data(无数据时返回 undefined),消息提示走统一处理
feedback.value = { text: `已下发至「${row.Name || row.Code}」`, type: 'success' }
ElMessage.success(`指令已下发:${row.Name || row.Code}`)
} catch (e) {
feedback.value = { text: e?.message || '下发失败', type: 'error' }
}
}
watch(() => props.deviceId, (val) => { if (val) fetchPoints() })
onMounted(() => { if (props.deviceId) fetchPoints() })
defineExpose({ refresh: fetchPoints })
</script>
<style scoped>
.ps-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.ps-count {
font-size: 12px;
color: #909399;
}
.ps-tip {
color: #c0c4cc;
}
.ps-feedback {
margin-top: 12px;
}
</style>