diff --git a/RFID.md b/RFID.md index 563436a..027a4f4 100644 --- a/RFID.md +++ b/RFID.md @@ -236,6 +236,79 @@ C# 服务会通过 WebSocket 实时推送设备读取记录,格式示例: ### 原有接口(聚合 / 辅助) +1. `GET /rfid/dashboard/data` + - 前端方法:`getDashboardData(locationId?: number)` / `getDashboardStats(locationId?: number)`(兼容老名称)。 + - 参数:`locationId?: number`,位置 ID,可选。 + - 返回:`DashboardVO`(统计概览 + 设备状态列表 + 成功率趋势 + 告警统计)。 + +2. `GET /rfid/dashboard/overview` + - 前端方法:`getOverview()`。 + - 参数:无。 + - 返回:`StatisticsOverview`,字段含义同上。 + +3. `GET /rfid/dashboard/alarmStats` + - 前端方法:`getAlarmStats(limit?: number)`。 + - 参数:`limit?: number`,限制返回条数,默认 10。 + - 返回:`AlarmStatVO[]`,字段含义同实时统计中的 `alarmStats`. + +--- + +### 接口4:设备最新读取记录 + +> 请求方式:`GET /rfid/dashboard/deviceLatestRecords` +> 前端方法:`getDeviceLatestRecords()` +> 后端链路:`DashboardController#getDeviceLatestRecords` → `IDashboardService#getDeviceLatestRecords` + +**请求参数(Query)** + +- 无参数,直接调用即返回所有设备的最新读取记录。 + +**返回实体与字段** + +- 后端返回类型:`List` +- 前端 TS 类型:`DeviceLatestRecordVO[]` + +字段说明: + +1. `deviceId: number`:设备 ID。 +2. `deviceCode: string`:设备编号。 +3. `deviceName: string`:设备名称。 +4. `latestBarcode: string | null`:最新条码信息,可能为 `null`(无记录时)。 +5. `latestRecordTime: string | null`:最新记录时间(`yyyy-MM-dd HH:mm:ss` 格式),可能为 `null`。 +6. `readStatus: string | null`:读取状态(`1-成功;0-失败`),可能为 `null`。 +7. `alarmFlag: string | null`:是否告警(`0-否;1-是`),可能为 `null`。 +8. `alarmAction: string | null`:告警行为,可能为 `null`。 + +**后端处理要点** + +1. **近7天多表查询**:由于设备可能当天或最近几天没有数据,接口会查询近7天内(包含今天)所有实际存在的分表。 +2. **分表检测**:通过 `RfidReadRecordTableHelper.getExistingTableNames()` 获取近7天内**实际存在**的分表列表。 + - 先生成近7天的所有可能表名(如 `rfid_read_record_20251128` ~ `rfid_read_record_20251204`); + - 通过 `checkTableExists()` 查询 `information_schema` 过滤掉数据库中不存在的表; + - **分表不一定连续**:如某几天无数据则无对应分表,最终可能只返回 2-3 张表。 +3. **多表联合查询**:使用 `selectLatestRecordByDeviceMultiTable` 方法,通过 `UNION ALL` 合并多表数据,按 `device_id` 分组取每个设备 `record_time` 最大的记录。 +4. **异常处理**:当近7天内无可用分表或查询出错时,返回空列表,不影响接口可用性。 + +**SQL 逻辑说明** + +```sql +-- 合并近7天分表数据 +SELECT ... FROM ( + SELECT ... FROM rfid_read_record_20251128 + UNION ALL + SELECT ... FROM rfid_read_record_20251129 + ... +) t1 +INNER JOIN ( + -- 按设备分组取最新时间 + SELECT device_id, MAX(record_time) as max_time FROM (...) GROUP BY device_id +) latest ON t1.device_id = latest.device_id AND t1.record_time = latest.max_time +``` + +--- + +### 原有接口(聚合 / 辅助) + 1. `GET /rfid/dashboard/data` - 前端方法:`getDashboardData(locationId?: number)` / `getDashboardStats(locationId?: number)`(兼容老名称)。 - 参数:`locationId?: number`,位置 ID,可选。 diff --git a/ruoyi-modules/hw-rfid/src/main/java/org/dromara/rfid/controller/DashboardController.java b/ruoyi-modules/hw-rfid/src/main/java/org/dromara/rfid/controller/DashboardController.java index c6e1d06..fea259f 100644 --- a/ruoyi-modules/hw-rfid/src/main/java/org/dromara/rfid/controller/DashboardController.java +++ b/ruoyi-modules/hw-rfid/src/main/java/org/dromara/rfid/controller/DashboardController.java @@ -94,6 +94,19 @@ public class DashboardController extends BaseController { return R.ok(dashboardService.getSuccessRateTrends(type)); } + /** + * 【接口4】设备最新读取记录 + *

+ * 返回每个设备的最新一条读取记录,包括设备ID、编号、最新条码和时间。 + *

+ * + * @return 设备最新读取记录列表 + */ + @GetMapping("/deviceLatestRecords") + public R> getDeviceLatestRecords() { + return R.ok(dashboardService.getDeviceLatestRecords()); + } + // ==================== 以下为原有接口(保留) ==================== /** diff --git a/ruoyi-modules/hw-rfid/src/main/java/org/dromara/rfid/domain/vo/DashboardVO.java b/ruoyi-modules/hw-rfid/src/main/java/org/dromara/rfid/domain/vo/DashboardVO.java index cf6ccf9..7928ecb 100644 --- a/ruoyi-modules/hw-rfid/src/main/java/org/dromara/rfid/domain/vo/DashboardVO.java +++ b/ruoyi-modules/hw-rfid/src/main/java/org/dromara/rfid/domain/vo/DashboardVO.java @@ -268,4 +268,58 @@ public class DashboardVO implements Serializable { private String alarmAction; } + + /** + * 设备最新读取记录 + *

+ * 用于返回每个设备的最新一条读取记录信息 + *

+ */ + @Data + public static class DeviceLatestRecordVO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 设备ID + */ + private Long deviceId; + + /** + * 设备编号 + */ + private String deviceCode; + + /** + * 设备名称 + */ + private String deviceName; + + /** + * 最新条码信息 + */ + private String latestBarcode; + + /** + * 最新记录时间 + */ + private String latestRecordTime; + + /** + * 读取状态 (1-成功; 0-失败) + */ + private String readStatus; + + /** + * 是否告警 (0-否; 1-是) + */ + private String alarmFlag; + + /** + * 告警行为 + */ + private String alarmAction; + + } } diff --git a/ruoyi-modules/hw-rfid/src/main/java/org/dromara/rfid/mapper/RfidReadRecordMapper.java b/ruoyi-modules/hw-rfid/src/main/java/org/dromara/rfid/mapper/RfidReadRecordMapper.java index 8fd4b80..b13d283 100644 --- a/ruoyi-modules/hw-rfid/src/main/java/org/dromara/rfid/mapper/RfidReadRecordMapper.java +++ b/ruoyi-modules/hw-rfid/src/main/java/org/dromara/rfid/mapper/RfidReadRecordMapper.java @@ -205,7 +205,7 @@ public interface RfidReadRecordMapper extends BaseMapperPlus deviceIds); + /** + * 查询每个设备的最新一条读取记录(多表,跨日期范围) + *

+ * 用于查询近N天内每个设备的最新记录 + *

+ * + * @param tableNames 表名列表 + * @param deviceIds 设备ID列表(可选) + * @return 最新读取记录列表 + */ + List selectLatestRecordByDeviceMultiTable( + @Param("tableNames") List tableNames, + @Param("deviceIds") List deviceIds); + /** * 按小时统计成功率 * diff --git a/ruoyi-modules/hw-rfid/src/main/java/org/dromara/rfid/service/IDashboardService.java b/ruoyi-modules/hw-rfid/src/main/java/org/dromara/rfid/service/IDashboardService.java index 2e74d6a..eba0c8d 100644 --- a/ruoyi-modules/hw-rfid/src/main/java/org/dromara/rfid/service/IDashboardService.java +++ b/ruoyi-modules/hw-rfid/src/main/java/org/dromara/rfid/service/IDashboardService.java @@ -78,4 +78,14 @@ public interface IDashboardService { * @return 完整看板数据 */ DashboardVO getDashboardData(Long locationId); + + /** + * 获取所有设备的最新读取记录 + *

+ * 返回每个已标识设备的最新一条读取记录信息,包括设备ID、编号、最新条码和时间 + *

+ * + * @return 设备最新读取记录列表 + */ + List getDeviceLatestRecords(); } diff --git a/ruoyi-modules/hw-rfid/src/main/java/org/dromara/rfid/service/impl/DashboardServiceImpl.java b/ruoyi-modules/hw-rfid/src/main/java/org/dromara/rfid/service/impl/DashboardServiceImpl.java index cc10617..f6b1794 100644 --- a/ruoyi-modules/hw-rfid/src/main/java/org/dromara/rfid/service/impl/DashboardServiceImpl.java +++ b/ruoyi-modules/hw-rfid/src/main/java/org/dromara/rfid/service/impl/DashboardServiceImpl.java @@ -20,7 +20,7 @@ import org.dromara.rfid.service.IDashboardService; import org.springframework.stereotype.Service; import java.time.LocalDate; -import java.time.LocalDateTime; +import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; @@ -284,4 +284,54 @@ public class DashboardServiceImpl implements IDashboardService { dashboard.setAlarmStats(getAlarmStats(null)); return dashboard; } + + /** + * 获取所有设备的最新读取记录 + *

+ * 查询近7天分表中每个设备的最新一条读取记录。 + * 由于设备可能当天或最近几天没有数据,需要跨多表查询。 + *

+ */ + @Override + public List getDeviceLatestRecords() { + // 计算近7天的日期范围 + LocalDate today = LocalDate.now(); + LocalDate startDate = today.minusDays(6); + + // 获取近7天内实际存在的分表列表(使用 DateUtil 转换避免 java.sql.Date 不支持 toInstant) + Date beginDate = DateUtil.date(startDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); + Date endDate = DateUtil.date(today.atStartOfDay(ZoneId.systemDefault()).toInstant()); + List existingTables = RfidReadRecordTableHelper.getExistingTableNames(beginDate, endDate); + + if (CollUtil.isEmpty(existingTables)) { + log.warn("近7天内没有可用的读取记录分表"); + return Collections.emptyList(); + } + + log.debug("查询设备最新记录,涉及分表: {}", existingTables); + + List latestRecords; + try { + // 多表查询所有设备的最新记录 + latestRecords = readRecordMapper.selectLatestRecordByDeviceMultiTable(existingTables, null); + } catch (Exception e) { + log.warn("查询设备最新读取记录失败: {}", e.getMessage()); + latestRecords = Collections.emptyList(); + } + + return latestRecords.stream().map(record -> { + DashboardVO.DeviceLatestRecordVO vo = new DashboardVO.DeviceLatestRecordVO(); + vo.setDeviceId(record.getDeviceId()); + vo.setDeviceCode(record.getDeviceCode()); + vo.setDeviceName(record.getDeviceName()); + vo.setLatestBarcode(record.getBarcode()); + vo.setLatestRecordTime(record.getRecordTime() != null + ? DateUtil.format(record.getRecordTime(), "yyyy-MM-dd HH:mm:ss") + : null); + vo.setReadStatus(record.getReadStatus()); + vo.setAlarmFlag(record.getAlarmFlag()); + vo.setAlarmAction(record.getAlarmAction()); + return vo; + }).collect(Collectors.toList()); + } } diff --git a/ruoyi-modules/hw-rfid/src/main/resources/mapper/rfid/RfidReadRecordMapper.xml b/ruoyi-modules/hw-rfid/src/main/resources/mapper/rfid/RfidReadRecordMapper.xml index debb4ef..fc91473 100644 --- a/ruoyi-modules/hw-rfid/src/main/resources/mapper/rfid/RfidReadRecordMapper.xml +++ b/ruoyi-modules/hw-rfid/src/main/resources/mapper/rfid/RfidReadRecordMapper.xml @@ -379,6 +379,60 @@ order by t.device_id + + +