数据修复工具:完善设备检索
This commit is contained in:
parent
4599221606
commit
4cc487c00f
@ -159,7 +159,7 @@ public class DeviceController extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* 查询树形设备列表(用于报表生成等场景,网关设备可展开显示子设备)
|
* 查询树形设备列表(用于报表生成等场景,网关设备可展开显示子设备)
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@ss.hasAnyPermi('iot:device:list,iot:report:generate')")
|
@PreAuthorize("@ss.hasAnyPermi('iot:device:list,iot:report:generate,dataCenter:repair:list')")
|
||||||
@GetMapping("/treeList")
|
@GetMapping("/treeList")
|
||||||
@ApiOperation("查询树形设备列表(网关可展开子设备)")
|
@ApiOperation("查询树形设备列表(网关可展开子设备)")
|
||||||
public AjaxResult treeList(Device device) {
|
public AjaxResult treeList(Device device) {
|
||||||
|
|||||||
@ -47,16 +47,34 @@
|
|||||||
<el-form-item label="设备">
|
<el-form-item label="设备">
|
||||||
<el-select
|
<el-select
|
||||||
v-model="queryParams.deviceId"
|
v-model="queryParams.deviceId"
|
||||||
placeholder="请选择设备"
|
placeholder="请选择设备(可输入名称/编号检索)"
|
||||||
filterable
|
filterable
|
||||||
clearable
|
clearable
|
||||||
@change="handleDeviceChange"
|
@change="handleDeviceChange"
|
||||||
style="width: 220px"
|
style="width: 280px"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in deviceList"
|
v-for="item in deviceList"
|
||||||
:key="item.deviceId"
|
:key="item.deviceId"
|
||||||
:label="`${item.deviceName} (${item.serialNumber})`"
|
:label="item.label"
|
||||||
|
:value="item.deviceId"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<!-- 选中网关且其下挂有子设备时动态出现;不选则修复网关本体的物模型 -->
|
||||||
|
<el-form-item v-if="gatewayChildren.length > 0" label="子设备">
|
||||||
|
<el-select
|
||||||
|
v-model="queryParams.subDeviceId"
|
||||||
|
placeholder="不选则修复网关本体"
|
||||||
|
filterable
|
||||||
|
clearable
|
||||||
|
@change="handleSubDeviceChange"
|
||||||
|
style="width: 240px"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in gatewayChildren"
|
||||||
|
:key="item.deviceId"
|
||||||
|
:label="item.label"
|
||||||
:value="item.deviceId"
|
:value="item.deviceId"
|
||||||
></el-option>
|
></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
@ -124,7 +142,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 自动校准配置弹窗 -->
|
<!-- 自动校准配置弹窗 -->
|
||||||
<el-dialog title="自动校准配置" :visible.sync="calibrationConfigVisible" width="600px" append-to-body v-dialogDrag>
|
<el-dialog title="自动校准配置" :visible.sync="calibrationConfigVisible" width="720px" append-to-body v-dialogDrag>
|
||||||
<el-alert
|
<el-alert
|
||||||
type="info"
|
type="info"
|
||||||
:closable="false"
|
:closable="false"
|
||||||
@ -170,7 +188,24 @@
|
|||||||
<el-option
|
<el-option
|
||||||
v-for="item in deviceList"
|
v-for="item in deviceList"
|
||||||
:key="item.deviceId"
|
:key="item.deviceId"
|
||||||
:label="`${item.deviceName} (${item.serialNumber})`"
|
:label="item.label"
|
||||||
|
:value="item.deviceId"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="configGatewayChildren.length > 0" label="子设备">
|
||||||
|
<el-select
|
||||||
|
v-model="newConfig.subDeviceId"
|
||||||
|
placeholder="不选则配置网关本体"
|
||||||
|
filterable
|
||||||
|
clearable
|
||||||
|
@change="handleConfigSubDeviceChange"
|
||||||
|
style="width: 200px"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in configGatewayChildren"
|
||||||
|
:key="item.deviceId"
|
||||||
|
:label="item.label"
|
||||||
:value="item.deviceId"
|
:value="item.deviceId"
|
||||||
></el-option>
|
></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
@ -337,7 +372,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { listDeviceShort, listThingsModel } from '@/api/iot/device.js';
|
import { listDeviceTree, listThingsModel } from '@/api/iot/device.js';
|
||||||
import {
|
import {
|
||||||
getRepairDataList,
|
getRepairDataList,
|
||||||
addDeviceLog,
|
addDeviceLog,
|
||||||
@ -367,13 +402,16 @@ export default {
|
|||||||
calibrationConfigList: [],
|
calibrationConfigList: [],
|
||||||
newConfig: {
|
newConfig: {
|
||||||
deviceId: null,
|
deviceId: null,
|
||||||
|
subDeviceId: null,
|
||||||
identifier: null
|
identifier: null
|
||||||
},
|
},
|
||||||
|
configGatewayChildren: [],
|
||||||
configIdentifierList: [],
|
configIdentifierList: [],
|
||||||
|
|
||||||
// 查询参数
|
// 查询参数
|
||||||
queryParams: {
|
queryParams: {
|
||||||
deviceId: null,
|
deviceId: null,
|
||||||
|
subDeviceId: null,
|
||||||
identifier: null,
|
identifier: null,
|
||||||
dateRange: [
|
dateRange: [
|
||||||
moment().subtract(24, 'hours').format('YYYY-MM-DD HH:mm:ss'),
|
moment().subtract(24, 'hours').format('YYYY-MM-DD HH:mm:ss'),
|
||||||
@ -384,7 +422,10 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 数据
|
// 数据
|
||||||
|
// 设备栏只放顶层设备(网关 + 直连设备);网关的子设备走按需出现的「子设备」栏
|
||||||
deviceList: [],
|
deviceList: [],
|
||||||
|
deviceMap: {},
|
||||||
|
gatewayChildren: [],
|
||||||
identifierList: [],
|
identifierList: [],
|
||||||
tableData: [],
|
tableData: [],
|
||||||
total: 0,
|
total: 0,
|
||||||
@ -450,17 +491,22 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
// 主设备(网关或直连设备)
|
||||||
|
mainDevice() {
|
||||||
|
return this.deviceMap[this.queryParams.deviceId];
|
||||||
|
},
|
||||||
|
// 有效设备:选了子设备就是子设备,否则是主设备(网关本体)
|
||||||
|
currentDevice() {
|
||||||
|
return this.deviceMap[this.queryParams.subDeviceId] || this.mainDevice;
|
||||||
|
},
|
||||||
currentDeviceName() {
|
currentDeviceName() {
|
||||||
const device = this.deviceList.find(d => d.deviceId === this.queryParams.deviceId);
|
const device = this.currentDevice;
|
||||||
return device ? `${device.deviceName} (${device.serialNumber})` : '';
|
return device ? `${device.deviceName} (${device.serialNumber})` : '';
|
||||||
},
|
},
|
||||||
currentModelName() {
|
currentModelName() {
|
||||||
const model = this.identifierList.find(m => m.identifier === this.queryParams.identifier);
|
const model = this.identifierList.find(m => m.identifier === this.queryParams.identifier);
|
||||||
return model ? model.modelName : '';
|
return model ? model.modelName : '';
|
||||||
},
|
},
|
||||||
currentDevice() {
|
|
||||||
return this.deviceList.find(d => d.deviceId === this.queryParams.deviceId);
|
|
||||||
},
|
|
||||||
currentModel() {
|
currentModel() {
|
||||||
return this.identifierList.find(m => m.identifier === this.queryParams.identifier);
|
return this.identifierList.find(m => m.identifier === this.queryParams.identifier);
|
||||||
}
|
}
|
||||||
@ -506,19 +552,27 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 配置设备变化
|
// 配置:主设备变化 → 重置子设备与物模型,并按需挂出该网关的子设备
|
||||||
async handleConfigDeviceChange(deviceId) {
|
async handleConfigDeviceChange(deviceId) {
|
||||||
|
this.newConfig.subDeviceId = null;
|
||||||
this.newConfig.identifier = null;
|
this.newConfig.identifier = null;
|
||||||
|
this.configGatewayChildren = [];
|
||||||
this.configIdentifierList = [];
|
this.configIdentifierList = [];
|
||||||
if (!deviceId) return;
|
if (!deviceId) return;
|
||||||
try {
|
const device = this.deviceMap[deviceId];
|
||||||
const res = await listThingsModel({ deviceId, pageNum: 1, pageSize: 9999 });
|
if (device && device.children.length) {
|
||||||
if (res.code === 200) {
|
this.configGatewayChildren = device.children;
|
||||||
this.configIdentifierList = res.rows || [];
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error('加载物模型失败', e);
|
|
||||||
}
|
}
|
||||||
|
this.configIdentifierList = await this.fetchIdentifierList(device);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 配置:子设备变化(清空则回到网关本体)
|
||||||
|
async handleConfigSubDeviceChange(subDeviceId) {
|
||||||
|
this.newConfig.identifier = null;
|
||||||
|
this.configIdentifierList = [];
|
||||||
|
const deviceId = subDeviceId || this.newConfig.deviceId;
|
||||||
|
if (!deviceId) return;
|
||||||
|
this.configIdentifierList = await this.fetchIdentifierList(this.deviceMap[deviceId]);
|
||||||
},
|
},
|
||||||
|
|
||||||
// 添加自动校准配置
|
// 添加自动校准配置
|
||||||
@ -526,7 +580,7 @@ export default {
|
|||||||
if (!this.newConfig.deviceId || !this.newConfig.identifier) {
|
if (!this.newConfig.deviceId || !this.newConfig.identifier) {
|
||||||
return this.$message.warning('请选择设备和物模型');
|
return this.$message.warning('请选择设备和物模型');
|
||||||
}
|
}
|
||||||
const device = this.deviceList.find(d => d.deviceId === this.newConfig.deviceId);
|
const device = this.deviceMap[this.newConfig.subDeviceId || this.newConfig.deviceId];
|
||||||
const model = this.configIdentifierList.find(m => m.identifier === this.newConfig.identifier);
|
const model = this.configIdentifierList.find(m => m.identifier === this.newConfig.identifier);
|
||||||
if (!device || !model) {
|
if (!device || !model) {
|
||||||
return this.$message.error('设备或物模型不存在');
|
return this.$message.error('设备或物模型不存在');
|
||||||
@ -581,35 +635,81 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 加载设备列表
|
// 加载设备树:主栏只取顶层设备(网关 + 直连设备),子设备递归挂在所属网关的 children 上
|
||||||
async loadDeviceList() {
|
async loadDeviceList() {
|
||||||
try {
|
try {
|
||||||
const res = await listDeviceShort({ showChild: true, pageNum: 1, pageSize: 9999 });
|
const res = await listDeviceTree({ showChild: true });
|
||||||
if (res.code === 200) {
|
if (res.code !== 200) return;
|
||||||
this.deviceList = res.rows || [];
|
const deviceMap = {};
|
||||||
}
|
// 节点 → 下拉项;label 带编号(filterable 可按名称或编号检索),并同步写进 deviceId 索引
|
||||||
|
const convert = (node) => {
|
||||||
|
const option = {
|
||||||
|
deviceId: node.deviceId,
|
||||||
|
deviceName: node.deviceName,
|
||||||
|
serialNumber: node.serialNumber,
|
||||||
|
productId: node.productId,
|
||||||
|
productName: node.productName,
|
||||||
|
deviceType: node.deviceType,
|
||||||
|
children: [],
|
||||||
|
label: `${node.deviceType === 2 ? '🌐 ' : ''}${node.deviceName || node.serialNumber} (${node.serialNumber})`
|
||||||
|
};
|
||||||
|
deviceMap[node.deviceId] = option;
|
||||||
|
option.children = (node.children || []).map(convert);
|
||||||
|
return option;
|
||||||
|
};
|
||||||
|
const roots = (res.data || []).map(convert);
|
||||||
|
// 整体替换而非逐键写入,保证 deviceMap 的响应式失效
|
||||||
|
this.deviceMap = deviceMap;
|
||||||
|
this.deviceList = roots;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('加载设备列表失败', e);
|
console.error('加载设备树失败', e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// 设备变化
|
// 设备变化:清空子设备栏与物模型;是网关则挂出子设备,并默认按网关本体加载物模型
|
||||||
async handleDeviceChange(deviceId) {
|
async handleDeviceChange(deviceId) {
|
||||||
|
this.queryParams.subDeviceId = null;
|
||||||
this.queryParams.identifier = null;
|
this.queryParams.identifier = null;
|
||||||
|
this.gatewayChildren = [];
|
||||||
this.identifierList = [];
|
this.identifierList = [];
|
||||||
this.tableData = [];
|
this.tableData = [];
|
||||||
this.total = 0;
|
this.total = 0;
|
||||||
|
|
||||||
if (!deviceId) return;
|
if (!deviceId) return;
|
||||||
|
|
||||||
try {
|
const device = this.deviceMap[deviceId];
|
||||||
const res = await listThingsModel({ deviceId, pageNum: 1, pageSize: 9999 });
|
if (device && device.children.length) {
|
||||||
if (res.code === 200) {
|
this.gatewayChildren = device.children;
|
||||||
// 显示所有物模型(属性type=1、功能type=2、事件type=3)
|
|
||||||
this.identifierList = res.rows || [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 网关本体没有物模型时,物模型栏就空着,由用户去「子设备」里选
|
||||||
|
this.identifierList = await this.fetchIdentifierList(device);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 子设备变化:选中则修复该子设备,清空则回到网关本体
|
||||||
|
async handleSubDeviceChange(subDeviceId) {
|
||||||
|
this.queryParams.identifier = null;
|
||||||
|
this.identifierList = [];
|
||||||
|
this.tableData = [];
|
||||||
|
this.total = 0;
|
||||||
|
|
||||||
|
const deviceId = subDeviceId || this.queryParams.deviceId;
|
||||||
|
if (!deviceId) return;
|
||||||
|
this.identifierList = await this.fetchIdentifierList(this.deviceMap[deviceId]);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 查设备「自己」的物模型(属性type=1、功能type=2、事件type=3)
|
||||||
|
// ⚠️ /iot/device/listThingsModel 会把网关下所有子设备的物模型也合并返回(带 parentSerialNumber),
|
||||||
|
// 修复页只认选中设备自身的物模型,否则子设备的标识符会被当成网关的物模型去查询/新增
|
||||||
|
async fetchIdentifierList(device) {
|
||||||
|
if (!device) return [];
|
||||||
|
try {
|
||||||
|
const res = await listThingsModel({ deviceId: device.deviceId, pageNum: 1, pageSize: 9999 });
|
||||||
|
const rows = res.code === 200 ? (res.rows || []) : [];
|
||||||
|
return rows.filter(model => model.serialNumber === device.serialNumber);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('加载物模型失败', e);
|
console.error('加载物模型失败', e);
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -632,6 +732,7 @@ export default {
|
|||||||
handleReset() {
|
handleReset() {
|
||||||
this.queryParams = {
|
this.queryParams = {
|
||||||
deviceId: null,
|
deviceId: null,
|
||||||
|
subDeviceId: null,
|
||||||
identifier: null,
|
identifier: null,
|
||||||
dateRange: [
|
dateRange: [
|
||||||
moment().subtract(24, 'hours').format('YYYY-MM-DD HH:mm:ss'),
|
moment().subtract(24, 'hours').format('YYYY-MM-DD HH:mm:ss'),
|
||||||
@ -640,6 +741,7 @@ export default {
|
|||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 50
|
pageSize: 50
|
||||||
};
|
};
|
||||||
|
this.gatewayChildren = [];
|
||||||
this.identifierList = [];
|
this.identifierList = [];
|
||||||
this.tableData = [];
|
this.tableData = [];
|
||||||
this.total = 0;
|
this.total = 0;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user