feat(iot): 支持按区域和设备类型查询配置
新增 getConfigByAreaIdAndRelationType 方法,用于跨设备获取配置场景。 例如:工牌设备需要获取该区域的信标配置。 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
package com.viewsh.module.ops.environment.service.dispatch;
|
||||
|
||||
import com.viewsh.module.ops.api.badge.BadgeDeviceStatusDTO;
|
||||
import com.viewsh.module.ops.core.dispatch.DispatchEngine;
|
||||
import com.viewsh.module.ops.core.dispatch.model.OrderDispatchContext;
|
||||
import com.viewsh.module.ops.enums.PriorityEnum;
|
||||
import com.viewsh.module.ops.environment.service.badge.BadgeDeviceStatusService;
|
||||
import com.viewsh.module.ops.environment.service.cleanorder.CleanOrderService;
|
||||
import com.viewsh.module.ops.environment.test.BadgeDispatchTestConfig;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* 工牌设备调度流程集成测试
|
||||
*
|
||||
* @author lzh
|
||||
*/
|
||||
@Slf4j
|
||||
@SpringJUnitConfig(classes = BadgeDispatchTestConfig.class)
|
||||
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class})
|
||||
public class BadgeDeviceDispatchTest {
|
||||
|
||||
@Resource
|
||||
private BadgeDeviceStatusService badgeDeviceStatusService;
|
||||
|
||||
@Resource
|
||||
private CleanOrderService cleanOrderService;
|
||||
|
||||
@Resource
|
||||
private DispatchEngine dispatchEngine;
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
/**
|
||||
* 测试区域ID - A座2楼男卫
|
||||
*/
|
||||
private static final Long TEST_AREA_ID = 1301L;
|
||||
|
||||
/**
|
||||
* 测试设备ID
|
||||
*/
|
||||
private static final Long TEST_DEVICE_ID = 31L;
|
||||
private static final String TEST_DEVICE_CODE = "09207455611";
|
||||
|
||||
/**
|
||||
* 第二个设备
|
||||
*/
|
||||
private static final Long TEST_DEVICE_2 = 34L;
|
||||
private static final String TEST_DEVICE_2_CODE = "09207457042";
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
log.info("========================================");
|
||||
log.info("开始准备测试数据...");
|
||||
log.info("========================================");
|
||||
|
||||
// 清理之前的测试数据
|
||||
try {
|
||||
badgeDeviceStatusService.deleteBadgeStatus(TEST_DEVICE_ID);
|
||||
badgeDeviceStatusService.deleteBadgeStatus(TEST_DEVICE_2);
|
||||
} catch (Exception e) {
|
||||
log.warn("清理测试数据失败(可能首次运行): {}", e.getMessage());
|
||||
}
|
||||
|
||||
// 初始化区域设备索引
|
||||
try {
|
||||
badgeDeviceStatusService.addToAreaIndex(TEST_DEVICE_ID, TEST_AREA_ID);
|
||||
badgeDeviceStatusService.addToAreaIndex(TEST_DEVICE_2, TEST_AREA_ID);
|
||||
} catch (Exception e) {
|
||||
log.warn("初始化区域索引失败: {}", e.getMessage());
|
||||
}
|
||||
|
||||
log.info("测试数据准备完成: areaId={}, deviceId={}", TEST_AREA_ID, TEST_DEVICE_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* 简单测试 - 只测试心跳和状态
|
||||
*/
|
||||
@Test
|
||||
void testHeartbeatAndStatus() {
|
||||
log.info("========================================");
|
||||
log.info("测试:心跳和状态");
|
||||
log.info("========================================");
|
||||
|
||||
try {
|
||||
// 模拟心跳
|
||||
badgeDeviceStatusService.handleHeartbeatWithArea(
|
||||
TEST_DEVICE_ID,
|
||||
TEST_DEVICE_CODE,
|
||||
75,
|
||||
TEST_AREA_ID,
|
||||
"A座2楼男卫"
|
||||
);
|
||||
|
||||
// 查询状态
|
||||
BadgeDeviceStatusDTO status = badgeDeviceStatusService.getBadgeStatus(TEST_DEVICE_ID);
|
||||
|
||||
log.info("========================================");
|
||||
log.info("心跳和状态测试完成");
|
||||
log.info("设备状态: status={}, battery={}%, area={}",
|
||||
status.getStatus(), status.getBatteryLevel(), status.getCurrentAreaName());
|
||||
log.info("========================================");
|
||||
|
||||
assertNotNull(status, "设备状态不应为空");
|
||||
assertEquals("idle", status.getStatus().getCode());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("心跳测试失败", e);
|
||||
fail("测试失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.viewsh.module.ops.environment.test;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.viewsh.module.ops.api.queue.OrderQueueDTO;
|
||||
import com.viewsh.module.ops.api.queue.OrderQueueService;
|
||||
import com.viewsh.module.ops.core.dispatch.DispatchEngine;
|
||||
import com.viewsh.module.ops.environment.service.badge.BadgeDeviceStatusService;
|
||||
import com.viewsh.module.ops.environment.service.badge.BadgeDeviceStatusServiceImpl;
|
||||
import com.viewsh.module.ops.environment.service.dispatch.BadgeDeviceAreaAssignStrategy;
|
||||
import com.viewsh.module.ops.environment.service.dispatch.BadgeDeviceScheduleStrategy;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* 测试配置类
|
||||
* 使用 Mock 避免外部依赖(Redis、数据库等)
|
||||
*
|
||||
* @author lzh
|
||||
*/
|
||||
@Configuration
|
||||
public class BadgeDispatchTestConfig {
|
||||
|
||||
@Bean
|
||||
public RedisTemplate<String, Object> redisTemplate() {
|
||||
RedisTemplate<String, Object> template = mock(RedisTemplate.class);
|
||||
when(template.opsForHash()).thenReturn(mock(org.springframework.data.redis.core.HashOperations.class));
|
||||
when(template.opsForSet()).thenReturn(mock(org.springframework.data.redis.core.SetOperations.class));
|
||||
when(template.keys(anyString())).thenReturn(new HashSet<>());
|
||||
when(template.expire(anyString(), anyLong(), any())).thenReturn(true);
|
||||
when(template.delete(anyString())).thenReturn(true);
|
||||
return template;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ObjectMapper objectMapper() {
|
||||
return new ObjectMapper();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BadgeDeviceStatusServiceImpl badgeDeviceStatusServiceImpl(
|
||||
RedisTemplate<String, Object> redisTemplate,
|
||||
ObjectMapper objectMapper) {
|
||||
BadgeDeviceStatusServiceImpl service = new BadgeDeviceStatusServiceImpl();
|
||||
setField(service, "redisTemplate", redisTemplate);
|
||||
setField(service, "objectMapper", objectMapper);
|
||||
try {
|
||||
service.afterPropertiesSet();
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BadgeDeviceStatusService badgeDeviceStatusService(BadgeDeviceStatusServiceImpl impl) {
|
||||
return impl;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public OrderQueueService orderQueueService() {
|
||||
OrderQueueService mockService = mock(OrderQueueService.class);
|
||||
when(mockService.getWaitingTasksByUserId(anyLong())).thenReturn(Collections.emptyList());
|
||||
return mockService;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DispatchEngine dispatchEngine() {
|
||||
return new DispatchEngine();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BadgeDeviceAreaAssignStrategy badgeDeviceAreaAssignStrategy(
|
||||
BadgeDeviceStatusService badgeDeviceStatusService,
|
||||
OrderQueueService orderQueueService,
|
||||
DispatchEngine dispatchEngine) {
|
||||
BadgeDeviceAreaAssignStrategy strategy = new BadgeDeviceAreaAssignStrategy();
|
||||
setField(strategy, "badgeDeviceStatusService", badgeDeviceStatusService);
|
||||
setField(strategy, "orderQueueService", orderQueueService);
|
||||
setField(strategy, "dispatchEngine", dispatchEngine);
|
||||
strategy.init();
|
||||
return strategy;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BadgeDeviceScheduleStrategy badgeDeviceScheduleStrategy(
|
||||
BadgeDeviceStatusService badgeDeviceStatusService,
|
||||
OrderQueueService orderQueueService,
|
||||
DispatchEngine dispatchEngine) {
|
||||
BadgeDeviceScheduleStrategy strategy = new BadgeDeviceScheduleStrategy();
|
||||
setField(strategy, "badgeDeviceStatusService", badgeDeviceStatusService);
|
||||
setField(strategy, "orderQueueService", orderQueueService);
|
||||
setField(strategy, "dispatchEngine", dispatchEngine);
|
||||
strategy.init();
|
||||
return strategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过反射设置私有字段
|
||||
*/
|
||||
private void setField(Object target, String fieldName, Object value) {
|
||||
try {
|
||||
java.lang.reflect.Field field = target.getClass().getDeclaredField(fieldName);
|
||||
field.setAccessible(true);
|
||||
field.set(target, value);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to set field: " + fieldName, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.viewsh.module.ops.environment.test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
|
||||
/**
|
||||
* 测试用 Spring Boot 应用配置
|
||||
* 排除数据源自动配置,避免数据库连接问题
|
||||
*
|
||||
* @author lzh
|
||||
*/
|
||||
@SpringBootApplication(
|
||||
scanBasePackages = {
|
||||
"com.viewsh.module.ops.environment",
|
||||
"com.viewsh.module.ops.core"
|
||||
},
|
||||
exclude = {
|
||||
DataSourceAutoConfiguration.class,
|
||||
RedisAutoConfiguration.class
|
||||
}
|
||||
)
|
||||
public class TestApplication {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
-- ============================================
|
||||
-- 区域设备关联完整配置(三个设备各司其职)
|
||||
-- ============================================
|
||||
-- 设备类型说明:
|
||||
-- BADGE → buttonEvent(按键映射配置)
|
||||
-- BEACON → beaconPresence(信标MAC + 窗口配置)
|
||||
-- TRAFFIC_COUNTER → trafficThreshold(触发阈值配置)
|
||||
--
|
||||
-- 已知设备信息:
|
||||
-- 工牌:31(09207455611), 34(09207457042) | 产品: 19 / AOQwO9pJWKgfFTk4
|
||||
-- 客流:32 | 产品: 21 / 82Zr08RUnstRHRO2
|
||||
-- 信标:需要补充设备ID
|
||||
-- ============================================
|
||||
|
||||
-- ============================================
|
||||
-- 清理旧数据(可选)
|
||||
-- ============================================
|
||||
-- DELETE FROM `ops_area_device_relation` WHERE `id` BETWEEN 10000 AND 10999;
|
||||
|
||||
-- ============================================
|
||||
-- 1. A座2楼男卫 (area_id = 1301)
|
||||
-- ============================================
|
||||
|
||||
-- 1.1 工牌设备 - 按键映射配置
|
||||
INSERT INTO `ops_area_device_relation` (
|
||||
`id`, `area_id`, `device_id`, `device_key`, `product_id`, `product_key`,
|
||||
`relation_type`, `config_data`, `enabled`, `creator`, `create_time`,
|
||||
`updater`, `update_time`, `deleted`, `tenant_id`
|
||||
) VALUES (
|
||||
10101, -- id
|
||||
1301, -- area_id (A座2楼男卫)
|
||||
31, -- device_id (工牌)
|
||||
'09207455611', -- device_key
|
||||
19, -- product_id
|
||||
'AOQwO9pJWKgfFTk4', -- product_key
|
||||
'BADGE', -- relation_type
|
||||
'{
|
||||
"buttonEvent": {
|
||||
"enabled": true,
|
||||
"confirmKeyId": 1,
|
||||
"queryKeyId": 2
|
||||
}
|
||||
}',
|
||||
1, -- enabled
|
||||
'system',
|
||||
'2026-01-23 09:56:22',
|
||||
'system',
|
||||
'2026-01-23 09:56:22',
|
||||
b'0',
|
||||
1
|
||||
);
|
||||
|
||||
-- 1.2 信标设备 - MAC地址 + 窗口配置
|
||||
-- 注意:device_id 需要替换为实际的信标设备ID
|
||||
INSERT INTO `ops_area_device_relation` (
|
||||
`id`, `area_id`, `device_id`, `device_key`, `product_id`, `product_key`,
|
||||
`relation_type`, `config_data`, `enabled`, `creator`, `create_time`,
|
||||
`updater`, `update_time`, `deleted`, `tenant_id`
|
||||
) VALUES (
|
||||
10102, -- id
|
||||
1301, -- area_id (A座2楼男卫)
|
||||
37, -- device_id (信标,需替换为实际ID)
|
||||
'BEACON_MALE_001', -- device_key
|
||||
21, -- product_id (假设与客流同产品,需确认)
|
||||
'82Zr08RUnstRHRO2', -- product_key
|
||||
'BEACON', -- relation_type
|
||||
'{
|
||||
"beaconPresence": {
|
||||
"enabled": true,
|
||||
"beaconMac": "F0:C8:60:1D:10:BB",
|
||||
"window": {
|
||||
"sampleTtlSeconds": 120,
|
||||
"missingValue": -999
|
||||
},
|
||||
"enter": {
|
||||
"rssiThreshold": -70,
|
||||
"windowSize": 3,
|
||||
"hitCount": 2,
|
||||
"autoArrival": true
|
||||
},
|
||||
"exit": {
|
||||
"weakRssiThreshold": -85,
|
||||
"windowSize": 5,
|
||||
"hitCount": 4,
|
||||
"warningDelayMinutes": 0,
|
||||
"lossTimeoutMinutes": 10,
|
||||
"minValidWorkMinutes": 3,
|
||||
"autoComplete": true
|
||||
}
|
||||
}
|
||||
}',
|
||||
1, -- enabled
|
||||
'system',
|
||||
'2026-01-23 09:56:22',
|
||||
'system',
|
||||
'2026-01-23 09:56:22',
|
||||
b'0',
|
||||
1
|
||||
);
|
||||
|
||||
-- 1.3 客流计数器 - 触发阈值配置
|
||||
INSERT INTO `ops_area_device_relation` (
|
||||
`id`, `area_id`, `device_id`, `device_key`, `product_id`, `product_key`,
|
||||
`relation_type`, `config_data`, `enabled`, `creator`, `create_time`,
|
||||
`updater`, `update_time`, `deleted`, `tenant_id`
|
||||
) VALUES (
|
||||
10103, -- id
|
||||
1301, -- area_id (A座2楼男卫)
|
||||
32, -- device_id (客流计数器)
|
||||
'11225420037', -- device_key
|
||||
21, -- product_id
|
||||
'82Zr08RUnstRHRO2', -- product_key
|
||||
'TRAFFIC_COUNTER', -- relation_type
|
||||
'{
|
||||
"trafficThreshold": {
|
||||
"threshold": 100,
|
||||
"timeWindowSeconds": 3600,
|
||||
"autoCreateOrder": true,
|
||||
"orderPriority": "P1"
|
||||
}
|
||||
}',
|
||||
1, -- enabled
|
||||
'system',
|
||||
'2026-01-23 09:56:22',
|
||||
'system',
|
||||
'2026-01-23 09:56:22',
|
||||
b'0',
|
||||
1
|
||||
);
|
||||
|
||||
-- ============================================
|
||||
-- 2. A座2楼女卫 (area_id = 1302)
|
||||
-- ============================================
|
||||
|
||||
-- 2.1 工牌设备 - 按键映射配置
|
||||
INSERT INTO `ops_area_device_relation` (
|
||||
`id`, `area_id`, `device_id`, `device_key`, `product_id`, `product_key`,
|
||||
`relation_type`, `config_data`, `enabled`, `creator`, `create_time`,
|
||||
`updater`, `update_time`, `deleted`, `tenant_id`
|
||||
) VALUES (
|
||||
10201, -- id
|
||||
1302, -- area_id (A座2楼女卫)
|
||||
34, -- device_id (工牌)
|
||||
'09207457042', -- device_key
|
||||
19, -- product_id
|
||||
'AOQwO9pJWKgfFTk4', -- product_key
|
||||
'BADGE', -- relation_type
|
||||
'{
|
||||
"buttonEvent": {
|
||||
"enabled": true,
|
||||
"confirmKeyId": 1,
|
||||
"queryKeyId": 2
|
||||
}
|
||||
}',
|
||||
1, -- enabled
|
||||
'system',
|
||||
'2026-01-23 09:56:22',
|
||||
'system',
|
||||
'2026-01-23 09:56:22',
|
||||
b'0',
|
||||
1
|
||||
);
|
||||
|
||||
-- 2.2 信标设备 - MAC地址 + 窗口配置
|
||||
-- 注意:device_id 需要替换为实际的信标设备ID
|
||||
INSERT INTO `ops_area_device_relation` (
|
||||
`id`, `area_id`, `device_id`, `device_key`, `product_id`, `product_key`,
|
||||
`relation_type`, `config_data`, `enabled`, `creator`, `create_time`,
|
||||
`updater`, `update_time`, `deleted`, `tenant_id`
|
||||
) VALUES (
|
||||
10202, -- id
|
||||
1302, -- area_id (A座2楼女卫)
|
||||
38, -- device_id (信标,需替换为实际ID)
|
||||
'BEACON_FEMALE_001', -- device_key
|
||||
21, -- product_id
|
||||
'82Zr08RUnstRHRO2', -- product_key
|
||||
'BEACON', -- relation_type
|
||||
'{
|
||||
"beaconPresence": {
|
||||
"enabled": true,
|
||||
"beaconMac": "F0:C8:60:1D:10:BC",
|
||||
"window": {
|
||||
"sampleTtlSeconds": 120,
|
||||
"missingValue": -999
|
||||
},
|
||||
"enter": {
|
||||
"rssiThreshold": -70,
|
||||
"windowSize": 3,
|
||||
"hitCount": 2,
|
||||
"autoArrival": true
|
||||
},
|
||||
"exit": {
|
||||
"weakRssiThreshold": -85,
|
||||
"windowSize": 5,
|
||||
"hitCount": 4,
|
||||
"warningDelayMinutes": 0,
|
||||
"lossTimeoutMinutes": 10,
|
||||
"minValidWorkMinutes": 3,
|
||||
"autoComplete": true
|
||||
}
|
||||
}
|
||||
}',
|
||||
1, -- enabled
|
||||
'system',
|
||||
'2026-01-23 09:56:22',
|
||||
'system',
|
||||
'2026-01-23 09:56:22',
|
||||
b'0',
|
||||
1
|
||||
);
|
||||
|
||||
-- 2.3 客流计数器 - 触发阈值配置
|
||||
INSERT INTO `ops_area_device_relation` (
|
||||
`id`, `area_id`, `device_id`, `device_key`, `product_id`, `product_key`,
|
||||
`relation_type`, `config_data`, `enabled`, `creator`, `create_time`,
|
||||
`updater`, `update_time`, `deleted`, `tenant_id`
|
||||
) VALUES (
|
||||
10203, -- id
|
||||
1302, -- area_id (A座2楼女卫)
|
||||
33, -- device_id (同一客流计数器)
|
||||
'11225420051', -- device_key
|
||||
21, -- product_id
|
||||
'82Zr08RUnstRHRO2', -- product_key
|
||||
'TRAFFIC_COUNTER', -- relation_type
|
||||
'{
|
||||
"trafficThreshold": {
|
||||
"threshold": 80, -- 女卫阈值设低一些
|
||||
"timeWindowSeconds": 3600,
|
||||
"autoCreateOrder": true,
|
||||
"orderPriority": "P1"
|
||||
}
|
||||
}',
|
||||
1, -- enabled
|
||||
'system',
|
||||
'2026-01-23 09:56:22',
|
||||
'system',
|
||||
'2026-01-23 09:56:22',
|
||||
b'0',
|
||||
1
|
||||
);
|
||||
|
||||
-- ============================================
|
||||
-- 3. 验证查询
|
||||
-- ============================================
|
||||
|
||||
-- 查看所有关联(按区域、类型分组)
|
||||
SELECT
|
||||
r.id,
|
||||
r.area_id,
|
||||
a.area_name,
|
||||
r.relation_type,
|
||||
r.device_id,
|
||||
r.device_key,
|
||||
r.enabled,
|
||||
JSON_EXTRACT(r.config_data, '$.buttonEvent') AS button_event,
|
||||
JSON_EXTRACT(r.config_data, '$.beaconPresence.beaconMac') AS beacon_mac,
|
||||
JSON_EXTRACT(r.config_data, '$.trafficThreshold.threshold') AS traffic_threshold
|
||||
FROM `ops_area_device_relation` r
|
||||
LEFT JOIN `ops_bus_area` a ON r.area_id = a.id
|
||||
WHERE r.id BETWEEN 10101 AND 10203
|
||||
ORDER BY r.area_id, FIELD(r.relation_type, 'BADGE', 'BEACON', 'TRAFFIC_COUNTER');
|
||||
|
||||
-- 查看某个区域的所有设备
|
||||
SELECT
|
||||
r.relation_type,
|
||||
r.device_id,
|
||||
r.device_key,
|
||||
r.config_data
|
||||
FROM `ops_area_device_relation` r
|
||||
WHERE r.area_id = 1301 -- 1301=男卫, 1302=女卫
|
||||
AND r.enabled = 1
|
||||
AND r.deleted = 0;
|
||||
|
||||
-- ============================================
|
||||
-- 4. 查询你的设备信息(确认信标设备ID)
|
||||
-- ============================================
|
||||
|
||||
-- 查看所有工牌和客流设备
|
||||
SELECT id, device_name, nickname, serial_number, product_id, product_key, device_type, state
|
||||
FROM iot_device
|
||||
WHERE id IN (31, 32, 34)
|
||||
ORDER BY id;
|
||||
|
||||
-- 查找信标类设备(根据产品或类型)
|
||||
SELECT id, device_name, nickname, serial_number, product_id, product_key, device_type, state
|
||||
FROM iot_device
|
||||
WHERE device_type LIKE '%BEACON%'
|
||||
OR product_key LIKE '%BEACON%'
|
||||
OR device_name LIKE '%信标%'
|
||||
ORDER BY id;
|
||||
@@ -0,0 +1,303 @@
|
||||
-- ============================================
|
||||
-- 工牌设备调度流程测试数据
|
||||
-- ============================================
|
||||
-- 说明:
|
||||
-- 1. 先执行此 SQL 插入测试数据
|
||||
-- 2. 运行 BadgeDeviceDispatchTest 测试类
|
||||
-- 3. device_id 需要在 iot_device 表中存在,如不存在需先创建设备
|
||||
-- ============================================
|
||||
|
||||
-- ============================================
|
||||
-- 1. 区域测试数据 (ops_bus_area)
|
||||
-- ============================================
|
||||
|
||||
-- 清理旧测试数据
|
||||
DELETE FROM ops_bus_area WHERE id BETWEEN 1000 AND 1999;
|
||||
|
||||
-- 插入测试区域
|
||||
INSERT INTO `ops_bus_area` (`id`, `parent_id`, `parent_path`, `area_name`, `area_code`, `area_type`, `function_type`, `floor_no`, `cleaning_frequency`, `standard_duration`, `area_level`, `is_active`, `sort`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES
|
||||
-- 园区级别
|
||||
(1000, NULL, '/1000', '测试科技园', 'TEST_PARK', 'PARK', NULL, NULL, 1, 30, 'MEDIUM', 1, 1, 'system', NOW(), 'system', NOW(), 0, 1),
|
||||
|
||||
-- 楼栋级别
|
||||
(1100, 1000, '/1000/1100', 'A座写字楼', 'BLDG_A', 'BUILDING', NULL, NULL, 1, 30, 'MEDIUM', 1, 1, 'system', NOW(), 'system', NOW(), 0, 1),
|
||||
(1101, 1000, '/1000/1101', 'B座写字楼', 'BLDG_B', 'BUILDING', NULL, NULL, 1, 30, 'MEDIUM', 1, 2, 'system', NOW(), 'system', NOW(), 0, 1),
|
||||
|
||||
-- 楼层级别 - A座
|
||||
(1200, 1100, '/1000/1100/1200', 'A座1楼', 'A_F1', 'FLOOR', NULL, 1, 2, 30, 'MEDIUM', 1, 1, 'system', NOW(), 'system', NOW(), 0, 1),
|
||||
(1201, 1100, '/1000/1100/1201', 'A座2楼', 'A_F2', 'FLOOR', NULL, 2, 2, 30, 'MEDIUM', 1, 2, 'system', NOW(), 'system', NOW(), 0, 1),
|
||||
(1202, 1100, '/1000/1100/1202', 'A座3楼', 'A_F3', 'FLOOR', NULL, 3, 1, 20, 'LOW', 1, 3, 'system', NOW(), 'system', NOW(), 0, 1),
|
||||
|
||||
-- 楼层级别 - B座
|
||||
(1203, 1101, '/1000/1101/1203', 'B座1楼', 'B_F1', 'FLOOR', NULL, 1, 2, 30, 'HIGH', 1, 1, 'system', NOW(), 'system', NOW(), 0, 1),
|
||||
(1204, 1101, '/1000/1101/1204', 'B座2楼', 'B_F2', 'FLOOR', NULL, 2, 2, 30, 'MEDIUM', 1, 2, 'system', NOW(), 'system', NOW(), 0, 1),
|
||||
|
||||
-- 功能区域 - A座2楼(主要测试区域)
|
||||
(1300, 1201, '/1000/1100/1201/1300', 'A座2楼电梯厅', 'A_F2_ELEVATOR', 'FUNCTION', 'ELEVATOR', 2, 4, 15, 'HIGH', 1, 1, 'system', NOW(), 'system', NOW(), 0, 1),
|
||||
(1301, 1201, '/1000/1100/1201/1301', 'A座2楼男卫', 'A_F2_MALE_TOILET', 'FUNCTION', 'MALE_TOILET', 2, 4, 20, 'HIGH', 1, 2, 'system', NOW(), 'system', NOW(), 0, 1),
|
||||
(1302, 1201, '/1000/1100/1201/1302', 'A座2楼女卫', 'A_F2_FEMALE_TOILET', 'FUNCTION', 'FEMALE_TOILET', 2, 4, 20, 'HIGH', 1, 3, 'system', NOW(), 'system', NOW(), 0, 1),
|
||||
(1303, 1201, '/1000/1100/1201/1303', 'A座2楼走廊', 'A_F2_CORRIDOR', 'FUNCTION', 'PUBLIC', 2, 2, 30, 'MEDIUM', 1, 4, 'system', NOW(), 'system', NOW(), 0, 1),
|
||||
(1304, 1201, '/1000/1100/1201/1304', 'A座2楼会议室', 'A_F2_MEETING', 'FUNCTION', 'PUBLIC', 2, 1, 15, 'LOW', 1, 5, 'system', NOW(), 'system', NOW(), 0, 1),
|
||||
|
||||
-- 功能区域 - B座1楼
|
||||
(1305, 1203, '/1000/1101/1203/1305', 'B座1楼大堂', 'B_F1_LOBBY', 'FUNCTION', 'PUBLIC', 1, 6, 45, 'HIGH', 1, 1, 'system', NOW(), 'system', NOW(), 0, 1),
|
||||
(1306, 1203, '/1000/1101/1203/1306', 'B座1楼电梯厅', 'B_F1_ELEVATOR', 'FUNCTION', 'ELEVATOR', 1, 4, 15, 'HIGH', 1, 2, 'system', NOW(), 'system', NOW(), 0, 1);
|
||||
|
||||
-- ============================================
|
||||
-- 2. 区域设备关联测试数据 (ops_area_device_relation)
|
||||
-- ============================================
|
||||
-- config_data 按照 CleanOrderIntegrationConfig 文档配置
|
||||
|
||||
-- 清理旧测试数据
|
||||
DELETE FROM ops_area_device_relation WHERE id BETWEEN 10000 AND 10999;
|
||||
DELETE FROM ops_area_device_relation WHERE device_id IN (2011, 2012, 2013, 2014, 2015, 2021, 2022);
|
||||
|
||||
-- 假设产品ID(根据实际情况调整,或使用现有产品ID)
|
||||
SET @TEST_PRODUCT_ID = 1;
|
||||
|
||||
-- 插入测试设备关联
|
||||
-- BADGE 类型设备配置:buttonEvent(按键事件)+ beaconPresence(信标检测)
|
||||
INSERT INTO `ops_area_device_relation` (`id`, `area_id`, `device_id`, `device_key`, `product_id`, `product_key`, `relation_type`, `config_data`, `enabled`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES
|
||||
-- A座2楼电梯厅设备(主要测试区域 - area_id=1300)
|
||||
(10000, 1300, 2011, 'BADGE_A2_E1', @TEST_PRODUCT_ID, 'BADGE_PRODUCT', 'BADGE',
|
||||
'{
|
||||
"buttonEvent": {
|
||||
"enabled": true,
|
||||
"confirmKeyId": 1,
|
||||
"queryKeyId": 2
|
||||
},
|
||||
"beaconPresence": {
|
||||
"enabled": true,
|
||||
"beaconMac": "F0:C8:60:1D:10:BB",
|
||||
"window": {
|
||||
"sampleTtlSeconds": 300,
|
||||
"missingValue": -999
|
||||
},
|
||||
"enter": {
|
||||
"rssiThreshold": -70,
|
||||
"windowSize": 3,
|
||||
"hitCount": 2,
|
||||
"autoArrival": true
|
||||
},
|
||||
"exit": {
|
||||
"weakRssiThreshold": -85,
|
||||
"windowSize": 5,
|
||||
"hitCount": 4,
|
||||
"warningDelayMinutes": 0,
|
||||
"lossTimeoutMinutes": 5,
|
||||
"minValidWorkMinutes": 2,
|
||||
"autoComplete": true
|
||||
}
|
||||
}
|
||||
}', 1, 'system', NOW(), 'system', NOW(), 0, 1),
|
||||
|
||||
(10001, 1300, 2012, 'BADGE_A2_E2', @TEST_PRODUCT_ID, 'BADGE_PRODUCT', 'BADGE',
|
||||
'{
|
||||
"buttonEvent": {
|
||||
"enabled": true,
|
||||
"confirmKeyId": 1,
|
||||
"queryKeyId": 2
|
||||
},
|
||||
"beaconPresence": {
|
||||
"enabled": true,
|
||||
"beaconMac": "F0:C8:60:1D:10:BC",
|
||||
"window": {
|
||||
"sampleTtlSeconds": 300,
|
||||
"missingValue": -999
|
||||
},
|
||||
"enter": {
|
||||
"rssiThreshold": -70,
|
||||
"windowSize": 3,
|
||||
"hitCount": 2,
|
||||
"autoArrival": true
|
||||
},
|
||||
"exit": {
|
||||
"weakRssiThreshold": -85,
|
||||
"windowSize": 5,
|
||||
"hitCount": 4,
|
||||
"warningDelayMinutes": 0,
|
||||
"lossTimeoutMinutes": 5,
|
||||
"minValidWorkMinutes": 2,
|
||||
"autoComplete": true
|
||||
}
|
||||
}
|
||||
}', 1, 'system', NOW(), 'system', NOW(), 0, 1),
|
||||
|
||||
(10002, 1300, 2013, 'BADGE_A2_E3', @TEST_PRODUCT_ID, 'BADGE_PRODUCT', 'BADGE',
|
||||
'{
|
||||
"buttonEvent": {
|
||||
"enabled": true,
|
||||
"confirmKeyId": 1,
|
||||
"queryKeyId": 2
|
||||
},
|
||||
"beaconPresence": {
|
||||
"enabled": false,
|
||||
"beaconMac": null,
|
||||
"window": null,
|
||||
"enter": null,
|
||||
"exit": null
|
||||
}
|
||||
}', 1, 'system', NOW(), 'system', NOW(), 0, 1),
|
||||
|
||||
-- A座2楼其他功能区域设备
|
||||
(10003, 1301, 2014, 'BADGE_A2_M1', @TEST_PRODUCT_ID, 'BADGE_PRODUCT', 'BADGE',
|
||||
'{
|
||||
"buttonEvent": {
|
||||
"enabled": true,
|
||||
"confirmKeyId": 1,
|
||||
"queryKeyId": 2
|
||||
},
|
||||
"beaconPresence": {
|
||||
"enabled": true,
|
||||
"beaconMac": "F0:C8:60:1D:10:BD",
|
||||
"window": {
|
||||
"sampleTtlSeconds": 300,
|
||||
"missingValue": -999
|
||||
},
|
||||
"enter": {
|
||||
"rssiThreshold": -70,
|
||||
"windowSize": 3,
|
||||
"hitCount": 2,
|
||||
"autoArrival": true
|
||||
},
|
||||
"exit": {
|
||||
"weakRssiThreshold": -85,
|
||||
"windowSize": 5,
|
||||
"hitCount": 4,
|
||||
"warningDelayMinutes": 0,
|
||||
"lossTimeoutMinutes": 5,
|
||||
"minValidWorkMinutes": 2,
|
||||
"autoComplete": true
|
||||
}
|
||||
}
|
||||
}', 1, 'system', NOW(), 'system', NOW(), 0, 1),
|
||||
|
||||
(10004, 1302, 2015, 'BADGE_A2_F1', @TEST_PRODUCT_ID, 'BADGE_PRODUCT', 'BADGE',
|
||||
'{
|
||||
"buttonEvent": {
|
||||
"enabled": true,
|
||||
"confirmKeyId": 1,
|
||||
"queryKeyId": 2
|
||||
},
|
||||
"beaconPresence": {
|
||||
"enabled": true,
|
||||
"beaconMac": "F0:C8:60:1D:10:BE",
|
||||
"window": {
|
||||
"sampleTtlSeconds": 300,
|
||||
"missingValue": -999
|
||||
},
|
||||
"enter": {
|
||||
"rssiThreshold": -70,
|
||||
"windowSize": 3,
|
||||
"hitCount": 2,
|
||||
"autoArrival": true
|
||||
},
|
||||
"exit": {
|
||||
"weakRssiThreshold": -85,
|
||||
"windowSize": 5,
|
||||
"hitCount": 4,
|
||||
"warningDelayMinutes": 0,
|
||||
"lossTimeoutMinutes": 5,
|
||||
"minValidWorkMinutes": 2,
|
||||
"autoComplete": true
|
||||
}
|
||||
}
|
||||
}', 1, 'system', NOW(), 'system', NOW(), 0, 1),
|
||||
|
||||
-- B座1楼设备(用于跨区域测试)
|
||||
(10010, 1305, 2021, 'BADGE_B1_L1', @TEST_PRODUCT_ID, 'BADGE_PRODUCT', 'BADGE',
|
||||
'{
|
||||
"buttonEvent": {
|
||||
"enabled": true,
|
||||
"confirmKeyId": 1,
|
||||
"queryKeyId": 2
|
||||
},
|
||||
"beaconPresence": {
|
||||
"enabled": false,
|
||||
"beaconMac": null,
|
||||
"window": null,
|
||||
"enter": null,
|
||||
"exit": null
|
||||
}
|
||||
}', 1, 'system', NOW(), 'system', NOW(), 0, 1),
|
||||
|
||||
(10011, 1306, 2022, 'BADGE_B1_E1', @TEST_PRODUCT_ID, 'BADGE_PRODUCT', 'BADGE',
|
||||
'{
|
||||
"buttonEvent": {
|
||||
"enabled": true,
|
||||
"confirmKeyId": 1,
|
||||
"queryKeyId": 2
|
||||
},
|
||||
"beaconPresence": {
|
||||
"enabled": true,
|
||||
"beaconMac": "F0:C8:60:1D:10:BF",
|
||||
"window": {
|
||||
"sampleTtlSeconds": 300,
|
||||
"missingValue": -999
|
||||
},
|
||||
"enter": {
|
||||
"rssiThreshold": -70,
|
||||
"windowSize": 3,
|
||||
"hitCount": 2,
|
||||
"autoArrival": true
|
||||
},
|
||||
"exit": {
|
||||
"weakRssiThreshold": -85,
|
||||
"windowSize": 5,
|
||||
"hitCount": 4,
|
||||
"warningDelayMinutes": 0,
|
||||
"lossTimeoutMinutes": 5,
|
||||
"minValidWorkMinutes": 2,
|
||||
"autoComplete": true
|
||||
}
|
||||
}
|
||||
}', 1, 'system', NOW(), 'system', NOW(), 0, 1);
|
||||
|
||||
-- ============================================
|
||||
-- 3. IoT设备测试数据 (iot_device)
|
||||
-- ============================================
|
||||
|
||||
-- 清理旧测试设备
|
||||
DELETE FROM iot_device WHERE id BETWEEN 2011 AND 2030;
|
||||
|
||||
-- 创建测试工牌设备
|
||||
INSERT INTO `iot_device` (`id`, `device_name`, `nickname`, `serial_number`, `product_id`, `product_key`, `device_type`, `state`, `active_time`, `tenant_id`) VALUES
|
||||
(2011, '测试工牌_A2_E1', 'A座2楼工牌1', 'SN2011001', @TEST_PRODUCT_ID, 'BADGE_PRODUCT', 10, 3, NOW(), 1),
|
||||
(2012, '测试工牌_A2_E2', 'A座2楼工牌2', 'SN2011002', @TEST_PRODUCT_ID, 'BADGE_PRODUCT', 10, 3, NOW(), 1),
|
||||
(2013, '测试工牌_A2_E3', 'A座2楼工牌3', 'SN2011003', @TEST_PRODUCT_ID, 'BADGE_PRODUCT', 10, 3, NOW(), 1),
|
||||
(2014, '测试工牌_A2_M1', 'A座2楼男卫工牌', 'SN2011004', @TEST_PRODUCT_ID, 'BADGE_PRODUCT', 10, 3, NOW(), 1),
|
||||
(2015, '测试工牌_A2_F1', 'A座2楼女卫工牌', 'SN2011005', @TEST_PRODUCT_ID, 'BADGE_PRODUCT', 10, 3, NOW(), 1),
|
||||
(2021, '测试工牌_B1_L1', 'B座1楼大堂工牌', 'SN2011006', @TEST_PRODUCT_ID, 'BADGE_PRODUCT', 10, 3, NOW(), 1),
|
||||
(2022, '测试工牌_B1_E1', 'B座1楼电梯工牌', 'SN2011007', @TEST_PRODUCT_ID, 'BADGE_PRODUCT', 10, 3, NOW(), 1);
|
||||
|
||||
-- ============================================
|
||||
-- 4. 验证查询
|
||||
-- ============================================
|
||||
|
||||
-- 查看插入的区域
|
||||
SELECT id, parent_id, parent_path, area_name, area_code, area_type, function_type, floor_no
|
||||
FROM ops_bus_area
|
||||
WHERE id BETWEEN 1000 AND 1999
|
||||
ORDER BY parent_path, id;
|
||||
|
||||
-- 查看插入的设备关联(含配置)
|
||||
SELECT r.id, r.area_id, a.area_name, r.device_id, r.device_key, r.relation_type, r.config_data
|
||||
FROM ops_area_device_relation r
|
||||
LEFT JOIN ops_bus_area a ON r.area_id = a.id
|
||||
WHERE r.id BETWEEN 10000 AND 10999
|
||||
ORDER BY r.area_id, r.id;
|
||||
|
||||
-- 查看插入的IoT设备
|
||||
SELECT id, device_name, nickname, serial_number, state
|
||||
FROM iot_device
|
||||
WHERE id BETWEEN 2011 AND 2030
|
||||
ORDER BY id;
|
||||
|
||||
-- 查看某区域下的所有工牌设备(含配置)
|
||||
SELECT r.device_id, r.device_key, d.device_name, r.config_data
|
||||
FROM ops_area_device_relation r
|
||||
LEFT JOIN iot_device d ON r.device_id = d.id
|
||||
WHERE r.area_id = 1300 -- A座2楼电梯厅
|
||||
AND r.relation_type = 'BADGE'
|
||||
AND r.enabled = 1
|
||||
AND r.deleted = 0;
|
||||
Reference in New Issue
Block a user