Browse Source

feat: 新增设备数据查询接口及相关文档

实现了通过设备ID和时间范围查询设备数据的功能,包括:
1. 新增查询参数DTO和返回值VO
2. 在CommonService中添加接口定义并实现查询逻辑
3. 在CommonController中添加对外接口路由
4. 补充完整的技能文档和OpenAPI接口文档
zhc
zhczyx@163.com 1 month ago
parent
commit
add2093e90
  1. BIN
      .DS_Store
  2. 9
      data-center-business-controller/src/main/java/com/techsor/datacenter/business/controller/CommonController.java
  3. 19
      data-center-business-model/src/main/java/com/techsor/datacenter/business/dto/data/QueryDeviceDataParams.java
  4. 41
      data-center-business-model/src/main/java/com/techsor/datacenter/business/vo/data/DeviceDataVO.java
  5. 3
      data-center-business-service/src/main/java/com/techsor/datacenter/business/service/CommonService.java
  6. 122
      data-center-business-service/src/main/java/com/techsor/datacenter/business/service/impl/CommonServiceImpl.java
  7. BIN
      document/.DS_Store
  8. 236
      document/openapis/query-device-data-openapi.json
  9. BIN
      document/skills/.DS_Store
  10. BIN
      document/skills/eaon_query-device-data.zip
  11. 239
      document/skills/query-device-data/SKILL.md

BIN
.DS_Store

Binary file not shown.

9
data-center-business-controller/src/main/java/com/techsor/datacenter/business/controller/CommonController.java

@ -31,6 +31,7 @@ import com.techsor.datacenter.business.dto.common.DatacenterV1QueryParams;
import com.techsor.datacenter.business.dto.common.GetFileTemporaryParams;
import com.techsor.datacenter.business.dto.common.QueryBuilding;
import com.techsor.datacenter.business.dto.common.QueryDataFor2D3D;
import com.techsor.datacenter.business.dto.data.QueryDeviceDataParams;
import com.techsor.datacenter.business.dto.device.ApiAlarmDeviceSearchParams;
import com.techsor.datacenter.business.dto.device.ApiRiliDeviceSearchParams;
import com.techsor.datacenter.business.dto.device.DeviceSearchParams;
@ -185,6 +186,14 @@ public class CommonController{
return commonService.queryDeviceInfo(Apikey, deviceSearchParams);
}
@Operation(summary = "Query device data by device IDs and time range")
@RequestMapping(value = "/queryDeviceData", method = RequestMethod.POST)
public SimpleDataResponse queryDeviceData(
@RequestBody QueryDeviceDataParams queryDeviceDataParams,
@Parameter(name = "Apikey", description = "API key", required = false, schema = @Schema(defaultValue = "RjV5ZTZBeFArekMxM2hlekFjWnlmZz09")) @RequestHeader(required = true) String Apikey) {
return commonService.queryDeviceData(Apikey, queryDeviceDataParams);
}
/**
* Query asset information by class.
*

19
data-center-business-model/src/main/java/com/techsor/datacenter/business/dto/data/QueryDeviceDataParams.java

@ -0,0 +1,19 @@
package com.techsor.datacenter.business.dto.data;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Data
public class QueryDeviceDataParams {
@Schema(description = "Device ID list", example = "[\"FFFF0001\",\"FFFF0002\"]", required = true)
private List<String> deviceIds;
@Schema(description = "Start time, Unix milliseconds timestamp", example = "1709870240425", required = true)
private Long startTime;
@Schema(description = "End time, Unix milliseconds timestamp", example = "1709889240425", required = true)
private Long endTime;
}

41
data-center-business-model/src/main/java/com/techsor/datacenter/business/vo/data/DeviceDataVO.java

@ -0,0 +1,41 @@
package com.techsor.datacenter.business.vo.data;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class DeviceDataVO {
@Schema(description = "Device ID", example = "FFFF0001")
private String deviceId;
@Schema(description = "Device name", example = "温度传感器")
private String deviceName;
@Schema(description = "Raw data JSON", example = "{\"temp\":25.5}")
private String rawData;
@Schema(description = "Device data values, comma-separated", example = "25.5")
private String dataValue;
@Schema(description = "Receive timestamp (milliseconds)", example = "1709870240425")
private Long receiveTs;
@Schema(description = "Status", example = "UP")
private String status;
@Schema(description = "Alert level", example = "1")
private String alertLevel;
@Schema(description = "Alert content", example = "温度异常")
private String alertContent;
@Schema(description = "Building info", example = "东京建物日本桥ビル")
private String buildingInfo;
@Schema(description = "Floor info", example = "3F")
private String floorInfo;
@Schema(description = "Space info", example = "会議室A")
private String spaceInfo;
}

3
data-center-business-service/src/main/java/com/techsor/datacenter/business/service/CommonService.java

@ -16,6 +16,7 @@ import com.techsor.datacenter.business.dto.common.DatacenterV1QueryParams;
import com.techsor.datacenter.business.dto.common.GetFileTemporaryParams;
import com.techsor.datacenter.business.dto.common.QueryBuilding;
import com.techsor.datacenter.business.dto.common.QueryDataFor2D3D;
import com.techsor.datacenter.business.dto.data.QueryDeviceDataParams;
import com.techsor.datacenter.business.dto.device.ApiAlarmDeviceSearchParams;
import com.techsor.datacenter.business.dto.device.ApiRiliDeviceSearchParams;
import com.techsor.datacenter.business.dto.device.DeviceSearchParams;
@ -88,4 +89,6 @@ public interface CommonService {
SimpleDataResponse querySpaceInfoList(String authorization, ApiSpaceSearchParams searchParams);
SimpleDataResponse queryDeviceData(String apikey, QueryDeviceDataParams params);
}

122
data-center-business-service/src/main/java/com/techsor/datacenter/business/service/impl/CommonServiceImpl.java

@ -7,6 +7,7 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.MessageFormat;
import java.time.ZoneId;
import java.time.Duration;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
@ -78,6 +79,7 @@ import com.techsor.datacenter.business.dto.common.DatacenterV1QueryParams;
import com.techsor.datacenter.business.dto.common.GetFileTemporaryParams;
import com.techsor.datacenter.business.dto.common.QueryBuilding;
import com.techsor.datacenter.business.dto.common.QueryDataFor2D3D;
import com.techsor.datacenter.business.dto.data.QueryDeviceDataParams;
import com.techsor.datacenter.business.dto.device.ApiAlarmDeviceSearchParams;
import com.techsor.datacenter.business.dto.device.ApiRiliDeviceSearchParams;
import com.techsor.datacenter.business.dto.device.DeviceSearchParams;
@ -103,6 +105,7 @@ import com.techsor.datacenter.business.vo.device.ApiAlarmDeviceInfoVO;
import com.techsor.datacenter.business.vo.device.ApiCancelAlarmDeviceInfoVO;
import com.techsor.datacenter.business.vo.device.ApiRiliDeviceInfoVO;
import com.techsor.datacenter.business.vo.device.DeviceVO;
import com.techsor.datacenter.business.vo.data.DeviceDataVO;
import com.techsor.datacenter.business.vo.space.ApiSpaceWithAssetVO;
import com.techsor.datacenter.business.vo.version.VersionVO;
@ -1977,4 +1980,123 @@ public class CommonServiceImpl implements CommonService {
return SimpleDataResponse.success(deviceInfoVOs);
}
@Override
public SimpleDataResponse queryDeviceData(String apikey, QueryDeviceDataParams params) {
try {
if (CollectionUtils.isEmpty(params.getDeviceIds())) {
return SimpleDataResponse.fail(ResponseCode.MSG_ERROR, "[deviceIds] is required");
}
if (null == params.getStartTime()) {
return SimpleDataResponse.fail(ResponseCode.MSG_ERROR, "[startTime] is required");
}
if (null == params.getEndTime()) {
return SimpleDataResponse.fail(ResponseCode.MSG_ERROR, "[endTime] is required");
}
long startTime = params.getStartTime();
long endTime = params.getEndTime();
if (startTime < 10000000000L) {
startTime = startTime * 1000;
}
if (endTime < 10000000000L) {
endTime = endTime * 1000;
}
if (startTime > endTime) {
return SimpleDataResponse.fail(ResponseCode.MSG_ERROR, "startTime must be before endTime");
}
if (endTime - startTime > 7 * 24 * 60 * 60 * 1000L) {
return SimpleDataResponse.fail(ResponseCode.MSG_ERROR, "Time range must not exceed 7 days");
}
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("apikey", apikey);
ApikeyInfo2 apikeyInfo = commonOpt.getAuroraInfoByApikey(paramMap);
if (null == apikeyInfo) {
return SimpleDataResponse.fail(ResponseCode.MSG_ERROR, "Apikey is invalid");
}
apikeyInfo.setAuroraPassword(DESUtil.decrypt(apikeyInfo.getAuroraPassword(), Constants.DES_SALT));
apikeyInfo.setAuroraUsername(DESUtil.decrypt(apikeyInfo.getAuroraUsername(), Constants.DES_SALT));
List<String> dateList = DateUtils.getDatesBetween(startTime, endTime, ZoneId.of("Asia/Tokyo"), "yyyy_MM_dd");
List<DeviceDataVO> resultList = new ArrayList<>();
Class.forName("com.mysql.cj.jdbc.Driver");
try (Connection conn = DriverManager.getConnection(
MessageFormat.format(Constants.AURORA_URL_FORMAT, apikeyInfo.getAuroraUrl()),
apikeyInfo.getAuroraUsername(), apikeyInfo.getAuroraPassword())) {
StringBuilder inClause = new StringBuilder();
for (int i = 0; i < params.getDeviceIds().size(); i++) {
inClause.append("?");
if (i < params.getDeviceIds().size() - 1) {
inClause.append(",");
}
}
for (String dateStr : dateList) {
String table = "rawData_" + dateStr;
String sql = "select * from " + table
+ " where deviceId in (" + inClause + ") and ? <= receive_ts and receive_ts <= ?"
+ " order by receive_ts desc, hashId desc";
logger.info("queryDeviceData sql:{}", sql);
try (PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
int idx = 1;
for (String deviceId : params.getDeviceIds()) {
preparedStatement.setString(idx++, deviceId);
}
preparedStatement.setLong(idx++, startTime);
preparedStatement.setLong(idx, endTime);
ResultSet result = preparedStatement.executeQuery();
while (result.next()) {
DeviceDataVO vo = new DeviceDataVO();
vo.setDeviceId(result.getString("deviceId"));
vo.setDeviceName(result.getString("deviceTypeName"));
vo.setRawData(result.getString("rawData"));
String rawDataStr = result.getString("rawData");
if (StringUtils.isNotBlank(rawDataStr)) {
try {
JSONObject rawDataObj = JSON.parseObject(rawDataStr);
List<Object> valueList = new ArrayList<>();
for (String key : rawDataObj.keySet()) {
valueList.add(rawDataObj.get(key));
}
vo.setDataValue(StringUtils.join(valueList, ","));
} catch (Exception ignored) {
}
}
vo.setReceiveTs(result.getLong("receive_ts"));
vo.setStatus(result.getString("status"));
vo.setAlertLevel(result.getString("alertLevel"));
vo.setAlertContent(result.getString("alertContent"));
vo.setBuildingInfo(result.getString("buildingInfo"));
vo.setFloorInfo(result.getString("floorInfo"));
vo.setSpaceInfo(result.getString("spaceInfo"));
resultList.add(vo);
}
}
}
}
return SimpleDataResponse.success(resultList);
} catch (Exception e) {
logger.error("queryDeviceData error", e);
return SimpleDataResponse.fail(ResponseCode.SERVER_ERROR, ResponseCode.SERVER_ERROR_MSG);
}
}
}

BIN
document/.DS_Store

Binary file not shown.

236
document/openapis/query-device-data-openapi.json

@ -0,0 +1,236 @@
{
"openapi": "3.0.0",
"info": {
"title": "Device Data Query API",
"description": "通过设备ID列表和时间范围查询设备数据的接口文档",
"version": "1.0.0"
},
"servers": [
{
"url": "https://api.example.com",
"description": "Production Server"
}
],
"paths": {
"/common/queryDeviceData": {
"post": {
"summary": "Query device data by device IDs and time range",
"description": "根据设备ID列表和时间范围查询Aurora中的设备原始数据,支持跨天查询但时间跨度不能超过7天",
"tags": ["CommonController"],
"parameters": [
{
"name": "Apikey",
"in": "header",
"required": true,
"schema": {
"type": "string"
},
"description": "API key for authentication, provided by user"
},
{
"name": "Referer",
"in": "header",
"required": true,
"schema": {
"type": "string"
},
"description": "Request source domain, must match server's accessControlAllowOrigin config (e.g. https://bilplartform-stg.ifmservice.jp)"
}
],
"requestBody": {
"description": "Query parameters including device IDs and time range",
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/QueryDeviceDataParams"
}
}
}
},
"responses": {
"200": {
"description": "Successful operation",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SimpleDataResponse_List_DeviceDataVO"
}
}
}
},
"400": {
"description": "Bad request - validation error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SimpleDataResponse"
}
}
}
},
"401": {
"description": "Unauthorized - invalid API key",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SimpleDataResponse"
}
}
}
},
"500": {
"description": "Internal server error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SimpleDataResponse"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"QueryDeviceDataParams": {
"type": "object",
"required": ["deviceIds", "startTime", "endTime"],
"properties": {
"deviceIds": {
"type": "array",
"items": {
"type": "string"
},
"description": "Device ID list",
"example": ["FFFF0001", "FFFF0002"]
},
"startTime": {
"type": "integer",
"format": "int64",
"description": "Start time, Unix milliseconds timestamp",
"example": 1709870240425
},
"endTime": {
"type": "integer",
"format": "int64",
"description": "End time, Unix milliseconds timestamp (must not exceed 7 days from startTime)",
"example": 1709889240425
}
}
},
"DeviceDataVO": {
"type": "object",
"properties": {
"deviceId": {
"type": "string",
"description": "Device ID",
"example": "FFFF0001"
},
"deviceName": {
"type": "string",
"description": "Device name",
"example": "温度传感器"
},
"rawData": {
"type": "string",
"description": "Raw data JSON",
"example": "{\"temp\":25.5}"
},
"dataValue": {
"type": "string",
"description": "Device data values, comma-separated",
"example": "25.5"
},
"receiveTs": {
"type": "integer",
"format": "int64",
"description": "Receive timestamp (milliseconds)",
"example": 1709870240425
},
"status": {
"type": "string",
"description": "Status",
"example": "UP"
},
"alertLevel": {
"type": "string",
"description": "Alert level",
"example": "1"
},
"alertContent": {
"type": "string",
"description": "Alert content",
"example": "温度异常"
},
"buildingInfo": {
"type": "string",
"description": "Building info",
"example": "东京建物日本桥ビル"
},
"floorInfo": {
"type": "string",
"description": "Floor info",
"example": "3F"
},
"spaceInfo": {
"type": "string",
"description": "Space info",
"example": "会議室A"
}
}
},
"SimpleDataResponse": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"description": "Status code, 0 or 200 indicates success",
"example": 0
},
"msg": {
"type": "string",
"description": "Response message",
"example": "success"
},
"data": {
"description": "Response data (null on error)"
},
"errorMap": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "Detailed error information",
"example": {
"deviceIds": "Device ID list is required"
}
}
}
},
"SimpleDataResponse_List_DeviceDataVO": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"description": "Status code, 0 or 200 indicates success",
"example": 0
},
"msg": {
"type": "string",
"description": "Response message",
"example": "success"
},
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/DeviceDataVO"
}
}
}
}
}
}
}

BIN
document/skills/.DS_Store

Binary file not shown.

BIN
document/skills/eaon_query-device-data.zip

Binary file not shown.

239
document/skills/query-device-data/SKILL.md

@ -0,0 +1,239 @@
---
name: "query-device-data"
description: "Queries device raw data from Aurora by device IDs and time range via /common/queryDeviceData API. Invoke when user needs to retrieve device telemetry/historical data with device ID list and time range."
---
# Query Device Data
通过设备ID列表和时间范围查询 Aurora 中的设备原始数据。
## 触发条件
当用户需要按设备ID列表和时间范围查询设备原始数据时调用此 skill。
用户可能用自然语言表达,例如:
- "查询设备A和设备B昨天的数据"
- "查一下FT0001最近3天的数据"
- "看看FFFF0001今天的数据"
- "获取设备A和C在2024年1月1日到1月5日的数据"
## API 信息
| 项目 | 内容 |
|------|------|
| 接口路径 | `POST /common/queryDeviceData` |
| 认证方式 | Header 传入 `Apikey` |
| Referer 校验 | Header 需传入 `Referer`(值为服务端域名),否则被过滤器拦截返回 403 |
| 时间范围限制 | 最多7天 |
| 数据源 | Aurora 数据库 `rawData_yyyy_MM_dd` 分表 |
## 自然语言转 API 参数
### 1. 时间范围解析
用户可能会用各种方式描述时间,需要根据当前时间(`Today's date`)计算出对应的毫秒时间戳。
| 自然语言表达 | 转换为 API 参数 |
|:-------------|:----------------|
| "最近 X 天 / 近 X 天 / 过去 X 天" | `startTime` = 当前日期往前推 X 天 的 00:00:00(时区 Asia/Tokyo),`endTime` = 当前时间的 23:59:59 |
| "昨天" | `startTime` = 昨天 00:00:00,`endTime` = 昨天 23:59:59 |
| "今天" | `startTime` = 今天 00:00:00,`endTime` = 当前时间 |
| "今天 x 点到 y 点" | `startTime` = 今天 x:00:00,`endTime` = 今天 y:59:59 |
| "2024年1月1日到2024年1月5日" | `startTime` = 2024-01-01 00:00:00,`endTime` = 2024-01-05 23:59:59 |
| "X月Y日到X月Y日" | 根据当前年份推算,`startTime` = X月Y日 00:00:00,`endTime` = X月Y日 23:59:59 |
| "上个月" | `startTime` = 上个月1号 00:00:00,`endTime` = 上个月最后一天 23:59:59 |
| "最近X小时" | `startTime` = 当前时间往前推X小时,`endTime` = 当前时间 |
**注意**:
- 所有时间戳需要转换为 **毫秒**(13位数字)
- 时区统一使用 `Asia/Tokyo`
- `startTime``endTime` 之间的跨度不能超过 **7 天**
### 2. 设备ID解析
请求参数要求传入 `deviceIds`(设备ID列表),用户可能会用不同方式描述设备:
| 自然语言表达 | 转换方式 |
|:-------------|:---------|
| "设备A"、"设备B" | 如果用户提及设备名/编号,先根据上下文尝试确定是否为已知设备ID |
| "FFFF0001"、"FT0001" | 直接作为设备ID使用 |
| "所有设备"、"全部设备" | **不支持**,需要用户提供具体的设备ID列表 |
| "传感器A"、"温度计1" | 如果已知设备ID和名称的映射关系,转换为对应设备ID |
如果用户只说了设备名称但没有提供具体ID,需要向用户确认具体的设备ID。
### 3. 请求头解析
- `Apikey` 由用户提供,**不设置默认值**
- 如果用户没有提供 Apikey,需要向用户询问具体的 Apikey 值
## 自然语言处理流程
当收到自然语言请求时,按以下步骤执行:
```
1. 提取时间描述 → 计算 startTime/endTime(毫秒时间戳)
2. 提取设备描述 → 构建设备ID列表 deviceIds
3. 检查参数完整性:如有缺漏,向用户询问补齐
4. 检查 Apikey:如用户未提供,向用户询问
5. 检查 Referer:如用户未提供,向用户询问
6. 构建请求体 JSON 并设置请求头(Apikey、Referer)
7. 调用 POST /common/queryDeviceData
8. 返回结果给用户
```
### 参数不完整时的处理
**所有参数不设默认值**,缺失时需向用户询问。
| 缺失参数 | 询问示例 |
|:---------|:---------|
| 未提供 `deviceIds` | "请问要查询哪些设备的ID?请提供设备ID列表。" |
| 未提供时间范围 | "请问要查询什么时间范围的数据?例如:最近3天、昨天、或指定日期区间。" |
| 仅提供开始/结束时间之一 | 补齐另一个时间点,例如:用户只说"从2024年1月1日开始",则询问"请问结束时间是什么时候?" |
| 未提供 `Apikey` | "请提供用于认证的 Apikey。" |
| 未提供 `Referer` | "请提供请求来源域名(Referer),例如服务的域名地址。" |
### 处理后响应模板
调用接口后将结果以自然语言呈现给用户:
- 查询到数据时:告知用户共查询到多少条数据,以及设备的主要信息摘要
- 未查询到数据时:告知用户在指定时间范围内没有找到对应设备的数据
- 接口报错时:将错误信息展示给用户
## 请求参数
### Header
| 参数名 | 必填 | 说明 |
|--------|:----:|------|
| `Apikey` | 是 | API key,用于认证,由用户提供 |
| `Referer` | 是 | 请求来源域名,需与服务端配置的 `accessControlAllowOrigin` 匹配(例如 `https://bilplartform-stg.ifmservice.jp`),否则返回 403 |
### Request Body (JSON)
| 字段 | 类型 | 必填 | 说明 |
|------|:----:|:----:|------|
| `deviceIds` | `List<String>` | 是 | 设备ID列表,由用户提供 |
| `startTime` | `Long` | 是 | 开始时间戳(毫秒,也支持秒级自动转换),由用户提供或根据用户描述计算 |
| `endTime` | `Long` | 是 | 结束时间戳(毫秒,也支持秒级自动转换),与 startTime 跨度不能超过7天,由用户提供或根据用户描述计算 |
## 返回数据
返回 `SimpleDataResponse<List<DeviceDataVO>>`,其中 `data` 为设备数据列表:
| 字段 | 类型 | 说明 |
|------|:----:|------|
| `deviceId` | String | 设备ID |
| `deviceName` | String | 设备名称 |
| `rawData` | String | 原始数据 JSON |
| `dataValue` | String | 从 rawData 解析出的数值,逗号拼接 |
| `receiveTs` | Long | 接收时间戳(毫秒) |
| `status` | String | 状态 |
| `alertLevel` | String | 告警级别 |
| `alertContent` | String | 告警内容 |
| `buildingInfo` | String | 楼宇信息 |
| `floorInfo` | String | 楼层信息 |
| `spaceInfo` | String | 空间信息 |
## 调用示例
### 请求
```
POST /common/queryDeviceData
Apikey: <用户提供的Apikey>
Referer: <服务端域名例如 https://bilplartform-stg.ifmservice.jp>
```
```json
{
"deviceIds": ["FFFF0001", "FFFF0002"],
"startTime": 1709870240425,
"endTime": 1709889240425
}
```
### 成功响应
```json
{
"code": 0,
"msg": "success",
"data": [
{
"deviceId": "FFFF0001",
"deviceName": "温度传感器",
"rawData": "{\"temp\":25.5}",
"dataValue": "25.5",
"receiveTs": 1709870240425,
"status": "UP",
"alertLevel": null,
"alertContent": null,
"buildingInfo": "东京建物日本桥ビル",
"floorInfo": "3F",
"spaceInfo": "会議室A"
}
]
}
```
### 错误响应示例
```json
{
"code": 20001,
"msg": "[deviceIds] is required",
"data": null
}
```
## 自然语言用例映射
### 用例1:查询某设备最近N天的数据
> 用户说:**"查一下设备FFFF0001最近3天的数据"**
```
步骤:
1. 假设 Today's date = 2026-06-01
2. 计算 startTime = 2026-05-30 00:00:00 JST → 毫秒时间戳
3. 计算 endTime = 2026-06-01 23:59:59 JST → 毫秒时间戳
4. deviceIds = ["FFFF0001"]
5. 调用接口
```
### 用例2:查询多个设备特定日期的数据
> 用户说:**"查询FFFF0001和FT0002在2024年1月1日的数据"**
```
步骤:
1. 计算 startTime = 2024-01-01 00:00:00 JST → 毫秒时间戳
2. 计算 endTime = 2024-01-01 23:59:59 JST → 毫秒时间戳
3. deviceIds = ["FFFF0001", "FT0002"]
4. 调用接口
```
### 用例3:查询设备今天的数据
> 用户说:**"看看FT0001今天的监测数据"**
```
步骤:
1. 假设 Today's date = 2026-06-01
2. 计算 startTime = 2026-06-01 00:00:00 JST → 毫秒时间戳
3. 计算 endTime = 当前时间 JST → 毫秒时间戳
4. deviceIds = ["FT0001"]
5. 调用接口
```
## 注意事项
1. `startTime``endTime` 支持毫秒和秒级时间戳(< 10000000000L 时自动按秒处理
2. 时间跨度不能超过 **7 天**,否则接口会返回错误
3. 跨天查询时自动查询多张 `rawData_yyyy_MM_dd` 分表并合并结果
4. 使用 Apikey 认证,与 `/common/queryDeviceInfo` 相同的方式
5. 所有时间计算都基于 `Asia/Tokyo` 时区
6. Apikey 和所有请求参数均**不设置默认值**,缺失时需向用户询问补齐
7. **Referer 头必传**:请求必须携带 `Referer` 头,否则被 `CrosXssFilter` 过滤器拦截返回 403。Referer 值需与服务端配置的 `accessControlAllowOrigin` 匹配(通常为服务域名本身,如 `https://bilplartform-stg.ifmservice.jp`
Loading…
Cancel
Save