专项优化设备绑定页面查询

This commit is contained in:
zhugongping 2026-09-16 19:28:16 +08:00
parent f30ffda889
commit 20a148a04e
8 changed files with 84 additions and 19 deletions

View File

@ -75,6 +75,13 @@ public class PlatformDeviceMappingController extends BaseController {
// ==================== 子映射管理 ====================
@PreAuthorize("@ss.hasAnyPermi('platform:deviceMapping:query,platform:deviceMapping:list')")
@GetMapping("/sub-mappings/batch")
@ApiOperation("批量查询多个设备绑定的子设备映射(列表页展开行一次拉取,避免 N 次请求)")
public AjaxResult listSubMappingsBatch(@RequestParam List<Long> parentIds) {
return success(subMappingService.selectByParentIds(parentIds));
}
@PreAuthorize("@ss.hasAnyPermi('platform:deviceMapping:query,platform:deviceMapping:list')")
@GetMapping("/{id}/sub-mappings")
@ApiOperation("查询子设备映射列表")

View File

@ -10,6 +10,9 @@ public interface PlatformDeviceSubMappingMapper extends BaseMapperX<PlatformDevi
List<PlatformDeviceSubMapping> selectByParentId(@Param("parentMappingId") Long parentMappingId);
/** 批量查询多个父映射下的所有子映射(IN 查询,列表页展开行使用) */
List<PlatformDeviceSubMapping> selectByParentIds(@Param("parentIds") List<Long> parentIds);
PlatformDeviceSubMapping selectByParentAndSerial(@Param("parentMappingId") Long parentMappingId,
@Param("subSerialNumber") String subSerialNumber);

View File

@ -4,12 +4,16 @@ import com.baomidou.mybatisplus.extension.service.IService;
import com.fastbee.iot.platform.domain.PlatformDeviceSubMapping;
import java.util.List;
import java.util.Map;
public interface IPlatformDeviceSubMappingService extends IService<PlatformDeviceSubMapping> {
/** 查询父映射下的所有子映射 */
List<PlatformDeviceSubMapping> selectByParentId(Long parentMappingId);
/** 批量查询多个父映射下的子映射,按 parentMappingId 分组返回(列表页展开行一次拉取,避免 N 次请求) */
Map<Long, List<PlatformDeviceSubMapping>> selectByParentIds(List<Long> parentIds);
/** 根据子设备序列号查找子映射(推送时使用) */
List<PlatformDeviceSubMapping> selectBySubSerialNumber(String subSerialNumber);

View File

@ -3,6 +3,8 @@ package com.fastbee.iot.platform.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fastbee.iot.domain.Device;
import com.fastbee.iot.mapper.DeviceMapper;
import com.fastbee.iot.platform.domain.*;
import com.fastbee.iot.platform.flow.FlowContext;
import com.fastbee.iot.platform.flow.PlatformFlowExecutor;
@ -21,6 +23,7 @@ import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@ -41,6 +44,8 @@ public class PlatformDeviceMappingServiceImpl extends ServiceImpl<PlatformDevice
private IPlatformDeviceSubMappingService subMappingService;
@Autowired
private PlatformUserAuthMapper platformUserAuthMapper;
@Autowired
private DeviceMapper deviceMapper;
@Override
public List<PlatformDeviceMapping> selectList(PlatformDeviceMapping query) {
@ -58,7 +63,25 @@ public class PlatformDeviceMappingServiceImpl extends ServiceImpl<PlatformDevice
.eq(query.getNetStatus() != null, PlatformDeviceMapping::getNetStatus, query.getNetStatus())
.eq(StringUtils.hasText(query.getEnable()), PlatformDeviceMapping::getEnable, query.getEnable())
.orderByDesc(PlatformDeviceMapping::getCreateTime);
return this.list(wrapper);
List<PlatformDeviceMapping> rows = this.list(wrapper);
// 批量补全设备名称:device_name 为冗余字段,旧数据可能为空,按 deviceId 一次 IN 查询回填,避免前端逐个查询
List<Long> deviceIds = rows.stream()
.filter(m -> m.getDeviceId() != null && !StringUtils.hasText(m.getDeviceName()))
.map(PlatformDeviceMapping::getDeviceId)
.distinct()
.collect(Collectors.toList());
if (!deviceIds.isEmpty()) {
List<Device> devices = deviceMapper.selectList(Wrappers.<Device>lambdaQuery()
.in(Device::getDeviceId, deviceIds));
Map<Long, String> nameMap = devices.stream()
.collect(Collectors.toMap(Device::getDeviceId, Device::getDeviceName, (a, b) -> a));
rows.forEach(m -> {
if (m.getDeviceId() != null && !StringUtils.hasText(m.getDeviceName())) {
m.setDeviceName(nameMap.get(m.getDeviceId()));
}
});
}
return rows;
}
@Override

View File

@ -8,7 +8,11 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@ -24,6 +28,25 @@ public class PlatformDeviceSubMappingServiceImpl extends ServiceImpl<PlatformDev
return subMappingMapper.selectByParentId(parentMappingId);
}
@Override
public Map<Long, List<PlatformDeviceSubMapping>> selectByParentIds(List<Long> parentIds) {
if (parentIds == null || parentIds.isEmpty()) {
return Collections.emptyMap();
}
List<PlatformDeviceSubMapping> all = subMappingMapper.selectByParentIds(parentIds);
Map<Long, List<PlatformDeviceSubMapping>> grouped = new HashMap<>();
for (PlatformDeviceSubMapping sub : all) {
Long pid = sub.getParentMappingId();
if (pid == null) continue;
grouped.computeIfAbsent(pid, k -> new ArrayList<>()).add(sub);
}
// 保证请求的每个 parentId 都有 key,即便没有子映射也返回空列表,避免前端取到 undefined
for (Long pid : parentIds) {
grouped.putIfAbsent(pid, new ArrayList<>());
}
return grouped;
}
@Override
public List<PlatformDeviceSubMapping> selectBySubSerialNumber(String subSerialNumber) {
return subMappingMapper.selectBySubSerialNumber(subSerialNumber);

View File

@ -20,4 +20,14 @@
WHERE sub_serial_number = #{subSerialNumber}
</select>
<!-- 批量查询多个父映射下的子映射,按 parent_mapping_id 分组,前端列表展开行一次拉取 -->
<select id="selectByParentIds" resultType="com.fastbee.iot.platform.domain.PlatformDeviceSubMapping">
SELECT * FROM platform_device_sub_mapping
WHERE parent_mapping_id IN
<foreach collection="parentIds" item="pid" open="(" separator="," close=")">
#{pid}
</foreach>
ORDER BY parent_mapping_id ASC, id ASC
</select>
</mapper>

View File

@ -28,6 +28,11 @@ export function listSubMappings(parentId) {
return request({ url: `/platform/device-mapping/${parentId}/sub-mappings`, method: 'get' })
}
// 批量查询多个设备绑定的子设备映射,列表页展开行一次拉取,避免 N 次请求
export function listSubMappingsBatch(parentIds) {
return request({ url: '/platform/device-mapping/sub-mappings/batch', method: 'get', params: { parentIds: parentIds.join(',') } })
}
export function syncSubMappings(parentId, data) {
return request({ url: `/platform/device-mapping/${parentId}/sub-mappings`, method: 'post', data })
}

View File

@ -335,7 +335,7 @@
</template>
<script>
import { listPlatformDeviceMapping, addPlatformDeviceMapping, updatePlatformDeviceMapping, delPlatformDeviceMapping, onboardDevice, listSubMappings, syncSubMappings } from '@/api/platform/deviceMapping'
import { listPlatformDeviceMapping, addPlatformDeviceMapping, updatePlatformDeviceMapping, delPlatformDeviceMapping, onboardDevice, listSubMappings, listSubMappingsBatch, syncSubMappings } from '@/api/platform/deviceMapping'
import { listPlatformInstance } from '@/api/platform/instance'
import { getInitializedUsers, getProjectsByUserAuthId } from '@/api/platform/userAuth'
import { listPlatformInterface } from '@/api/platform/interface'
@ -425,25 +425,15 @@ export default {
this.loading = true
listPlatformDeviceMapping(this.queryParams).then(res => {
this.list = res.rows; this.total = res.total; this.loading = false
// 加载设备名称映射
const ids = [...new Set(res.rows.map(r => r.deviceId).filter(Boolean))]
if (ids.length) {
Promise.all(ids.map(id => getDevice(id).catch(() => null))).then(results => {
const map = {}
results.forEach(res => {
const d = res && (res.data || res)
if (d && d.deviceId) map[d.deviceId] = d.deviceName
})
this.deviceMap = map
// deviceName 由后端列表查询批量补全,前端无需再逐个 getDevice(N→0)
// 预加载网关设备的子映射(批量一次拉取,避免 N 次请求)
this.subMappingCache = {}
const gatewayIds = res.rows.filter(r => r.deviceType === 1).map(r => r.id).filter(Boolean)
if (gatewayIds.length) {
listSubMappingsBatch(gatewayIds).then(subRes => {
this.subMappingCache = subRes.data || {}
})
}
// 预加载网关设备的子映射
this.subMappingCache = {}
res.rows.filter(r => r.deviceType === 1).forEach(row => {
listSubMappings(row.id).then(subRes => {
this.$set(this.subMappingCache, row.id, subRes.data || [])
})
})
})
},
platformName(id) { const p = this.platformList.find(x => x.id === id); return p ? p.name : id },