routes_monitor_data.ts 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. import { Hono } from "hono";
  2. import debug from "debug";
  3. import type {
  4. DeviceMonitorData,
  5. } from "../client/share/monitorTypes.ts";
  6. import {
  7. DeleteStatus,
  8. } from "../client/share/types.ts";
  9. import type { Variables, WithAuth } from "./middlewares.ts";
  10. import { checkAndTriggerAlert, parseTemperatureHumidity } from "./utils/monitor.ts";
  11. const log = {
  12. api: debug("api:monitor"),
  13. };
  14. // 创建设备监控数据路由
  15. export function createMonitorDataRoutes(withAuth: WithAuth) {
  16. const monitorDataRoutes = new Hono<{ Variables: Variables }>();
  17. // 获取设备监控数据列表
  18. monitorDataRoutes.get("/", withAuth, async (c) => {
  19. try {
  20. const apiClient = c.get('apiClient');
  21. // 获取分页参数
  22. const page = Number(c.req.query("page")) || 1;
  23. const pageSize = Number(c.req.query("pageSize")) || 10;
  24. const offset = (page - 1) * pageSize;
  25. // 获取筛选参数
  26. const deviceId = c.req.query("device_id")
  27. ? Number(c.req.query("device_id"))
  28. : null;
  29. const deviceName = c.req.query("device_name");
  30. const protocol = c.req.query("protocol");
  31. const address = c.req.query("address");
  32. const metricType = c.req.query("metric_type");
  33. const status = c.req.query("status") ? Number(c.req.query("status")) : null;
  34. // 构建查询
  35. let query = apiClient.database
  36. .table("device_monitor_data as dmd")
  37. .leftJoin("device_instances as di", "dmd.device_id", "di.id")
  38. .leftJoin("zichan_info as zi", "di.id", "zi.id")
  39. .select(
  40. "dmd.*",
  41. "di.protocol",
  42. "di.address",
  43. "zi.asset_name as device_name"
  44. )
  45. .where("dmd.is_deleted", DeleteStatus.NOT_DELETED)
  46. .orderBy("dmd.collect_time", "desc");
  47. // 应用筛选条件
  48. if (deviceId) {
  49. query = query.where("dmd.device_id", deviceId);
  50. }
  51. if (deviceName) {
  52. query = query.where("zi.asset_name", "like", `%${deviceName}%`);
  53. }
  54. if (protocol) {
  55. query = query.where("di.protocol", protocol);
  56. }
  57. if (address) {
  58. query = query.where("di.address", "like", `%${address}%`);
  59. }
  60. if (metricType) {
  61. query = query.where("dmd.metric_type", metricType);
  62. }
  63. if (status !== null && status !== undefined) {
  64. query = query.where("dmd.status", status);
  65. }
  66. // 获取总记录数
  67. const total = await query.clone().count();
  68. // 获取分页数据
  69. const data = await query.limit(pageSize).offset(offset);
  70. return c.json({
  71. data,
  72. total: Number(total),
  73. page,
  74. pageSize,
  75. });
  76. } catch (error) {
  77. log.api("获取设备监控数据失败:", error);
  78. return c.json({ error: "获取设备监控数据失败" }, 500);
  79. }
  80. });
  81. // 添加监控数据
  82. monitorDataRoutes.post("/", withAuth, async (c) => {
  83. try {
  84. const data = (await c.req.json()) as Partial<DeviceMonitorData>;
  85. // 验证必填字段
  86. if (!data.device_id) {
  87. return c.json({ error: "设备ID不能为空" }, 400);
  88. }
  89. if (!data.metric_type) {
  90. return c.json({ error: "监控指标类型不能为空" }, 400);
  91. }
  92. if (data.metric_value === undefined || data.metric_value === null) {
  93. return c.json({ error: "监控值不能为空" }, 400);
  94. }
  95. const apiClient = c.get('apiClient');
  96. // 检查设备是否存在
  97. const device = await apiClient.database
  98. .table("zichan_info")
  99. .where("id", data.device_id)
  100. .where("is_deleted", DeleteStatus.NOT_DELETED)
  101. .first();
  102. if (!device) {
  103. return c.json({ error: "设备不存在" }, 404);
  104. }
  105. // 插入监控数据
  106. const [id] = await apiClient.database.table("device_monitor_data").insert({
  107. ...data,
  108. collect_time: data.collect_time || apiClient.database.fn.now(),
  109. created_at: apiClient.database.fn.now(),
  110. updated_at: apiClient.database.fn.now(),
  111. });
  112. // 获取插入的数据
  113. const [insertedData] = await apiClient.database
  114. .table("device_monitor_data")
  115. .where("id", id);
  116. // 检查并触发告警
  117. await checkAndTriggerAlert(apiClient, insertedData);
  118. return c.json({
  119. message: "监控数据添加成功",
  120. data: insertedData,
  121. });
  122. } catch (error) {
  123. log.api("添加监控数据失败:", error);
  124. return c.json({ error: "添加监控数据失败" }, 500);
  125. }
  126. });
  127. // 添加原始温湿度数据接口
  128. monitorDataRoutes.post("/raw", withAuth, async (c) => {
  129. try {
  130. const { device_id, raw_data } = await c.req.json();
  131. // 验证必填字段
  132. if (!device_id) {
  133. return c.json({ error: "设备ID不能为空" }, 400);
  134. }
  135. if (!raw_data) {
  136. return c.json({ error: "原始数据不能为空" }, 400);
  137. }
  138. const apiClient = c.get('apiClient');
  139. // 检查设备是否存在
  140. const device = await apiClient.database
  141. .table("zichan_info")
  142. .where("id", device_id)
  143. .where("is_deleted", DeleteStatus.NOT_DELETED)
  144. .first();
  145. if (!device) {
  146. return c.json({ error: "设备不存在" }, 404);
  147. }
  148. // 解析温湿度数据
  149. const { temperature, humidity, error } = parseTemperatureHumidity(raw_data);
  150. if (error) {
  151. return c.json({ error }, 400);
  152. }
  153. // 插入温度数据
  154. await apiClient.database.table("device_monitor_data").insert({
  155. device_id,
  156. metric_type: "temperature",
  157. metric_value: temperature.value,
  158. unit: temperature.unit,
  159. status: 1, // 正常状态
  160. collect_time: apiClient.database.fn.now(),
  161. created_at: apiClient.database.fn.now(),
  162. updated_at: apiClient.database.fn.now(),
  163. });
  164. // 插入湿度数据
  165. await apiClient.database.table("device_monitor_data").insert({
  166. device_id,
  167. metric_type: "humidity",
  168. metric_value: humidity.value,
  169. unit: humidity.unit,
  170. status: 1, // 正常状态
  171. collect_time: apiClient.database.fn.now(),
  172. created_at: apiClient.database.fn.now(),
  173. updated_at: apiClient.database.fn.now(),
  174. });
  175. return c.json({
  176. message: "温湿度数据添加成功",
  177. data: { temperature, humidity }
  178. });
  179. } catch (error) {
  180. log.api("添加原始温湿度数据失败:", error);
  181. return c.json({ error: "添加原始温湿度数据失败" }, 500);
  182. }
  183. });
  184. return monitorDataRoutes;
  185. }