routes_device_instances.ts 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. import { Hono } from "hono";
  2. import debug from "debug";
  3. import type {
  4. DeviceInstance
  5. } from "../client/share/monitorTypes.ts";
  6. import {
  7. EnableStatus,
  8. DeleteStatus,
  9. } from "../client/share/types.ts";
  10. import type { Variables, WithAuth } from "./middlewares.ts";
  11. const log = {
  12. api: debug("d8d:device:api"),
  13. };
  14. // 创建设备实例路由
  15. export function createDeviceInstancesRoutes(withAuth: WithAuth) {
  16. const deviceInstancesRoutes = new Hono<{ Variables: Variables }>();
  17. // 获取设备列表
  18. deviceInstancesRoutes.get("/", withAuth, async (c) => {
  19. try {
  20. const apiClient = c.get('apiClient');
  21. // 获取分页参数
  22. const page = Number(c.req.query("page")) || 1;
  23. const limit = Number(c.req.query("limit")) || 10;
  24. const offset = (page - 1) * limit;
  25. // 获取筛选参数
  26. const typeId = c.req.query("type_id");
  27. const protocol = c.req.query("protocol");
  28. const status = c.req.query("status");
  29. // 构建查询
  30. let query = apiClient.database
  31. .table("device_instances as di")
  32. .leftJoin("zichan_info as zi", "di.id", "zi.id")
  33. .select(
  34. "di.*",
  35. "zi.asset_name",
  36. "zi.device_category",
  37. "zi.area",
  38. "zi.supplier",
  39. "zi.device_status"
  40. )
  41. .where("di.is_deleted", DeleteStatus.NOT_DELETED)
  42. .orderBy("di.id", "desc");
  43. // 应用筛选条件
  44. if (typeId) {
  45. const typeIdNum = Number(typeId);
  46. if (!isNaN(typeIdNum)) {
  47. query = query.where("di.type_id", typeIdNum);
  48. }
  49. }
  50. if (protocol) {
  51. query = query.where("di.protocol", "like", `%${protocol}%`);
  52. }
  53. if (status) {
  54. const statusNum = Number(status);
  55. if (!isNaN(statusNum)) {
  56. query = query.where("di.is_enabled", statusNum);
  57. }
  58. }
  59. // 克隆查询以获取总数
  60. const countQuery = query.clone();
  61. // 执行分页查询
  62. const devices = await query.limit(limit).offset(offset);
  63. // 获取总数
  64. const count = await countQuery.count();
  65. return c.json({
  66. data: devices,
  67. pagination: {
  68. total: Number(count),
  69. current: page,
  70. pageSize: limit,
  71. totalPages: Math.ceil(Number(count) / limit),
  72. },
  73. });
  74. } catch (error) {
  75. log.api("获取设备列表失败:", error);
  76. return c.json({ error: "获取设备列表失败" }, 500);
  77. }
  78. });
  79. // 获取单个设备
  80. deviceInstancesRoutes.get("/:id", withAuth, async (c) => {
  81. try {
  82. const id = Number(c.req.param("id"));
  83. if (!id || isNaN(id)) {
  84. return c.json({ error: "无效的设备ID" }, 400);
  85. }
  86. const apiClient = c.get('apiClient');
  87. const [device] = await apiClient.database
  88. .table("device_instances")
  89. .where({ id, is_deleted: DeleteStatus.NOT_DELETED });
  90. if (!device) {
  91. return c.json({ error: "设备不存在" }, 404);
  92. }
  93. // 获取关联的资产信息
  94. const [asset] = await apiClient.database
  95. .table("zichan_info")
  96. .where("id", id);
  97. // 获取关联的设备类型信息
  98. const [deviceType] = await apiClient.database
  99. .table("device_types")
  100. .where("id", device.type_id);
  101. return c.json({
  102. ...device,
  103. asset_info: asset,
  104. type_info: deviceType,
  105. });
  106. } catch (error) {
  107. log.api("获取设备详情失败:", error);
  108. return c.json({ error: "获取设备详情失败" }, 500);
  109. }
  110. });
  111. // 创建设备
  112. deviceInstancesRoutes.post("/", withAuth, async (c) => {
  113. try {
  114. const apiClient = c.get('apiClient');
  115. const data = (await c.req.json()) as Partial<DeviceInstance>;
  116. // 验证必填字段
  117. if (!data.id || !data.type_id || !data.protocol || !data.address) {
  118. return c.json(
  119. { error: "关联资产、设备类型、通信协议和通信地址不能为空" },
  120. 400
  121. );
  122. }
  123. // 检查关联的资产是否存在
  124. const [asset] = await apiClient.database
  125. .table("zichan_info")
  126. .where({ id: data.id, is_deleted: DeleteStatus.NOT_DELETED });
  127. if (!asset) {
  128. return c.json({ error: "关联的资产不存在" }, 404);
  129. }
  130. // 检查设备类型是否存在
  131. const [deviceType] = await apiClient.database
  132. .table("device_types")
  133. .where({ id: data.type_id, is_deleted: DeleteStatus.NOT_DELETED });
  134. if (!deviceType) {
  135. return c.json({ error: "设备类型不存在" }, 404);
  136. }
  137. // 检查该资产是否已经关联了设备
  138. const [existingDevice] = await apiClient.database
  139. .table("device_instances")
  140. .where({ id: data.id, is_deleted: DeleteStatus.NOT_DELETED });
  141. if (existingDevice) {
  142. return c.json({ error: "该资产已关联了设备" }, 400);
  143. }
  144. // 创建设备
  145. await apiClient.database.table("device_instances").insert({
  146. id: data.id,
  147. type_id: data.type_id,
  148. protocol: data.protocol,
  149. address: data.address,
  150. collect_interval: data.collect_interval || 60,
  151. remark: data.remark,
  152. is_enabled: data.is_enabled ?? EnableStatus.ENABLED,
  153. is_deleted: DeleteStatus.NOT_DELETED,
  154. });
  155. // 获取创建的设备
  156. const [createdDevice] = await apiClient.database
  157. .table("device_instances")
  158. .where("id", data.id);
  159. return c.json({
  160. message: "设备创建成功",
  161. data: createdDevice,
  162. });
  163. } catch (error) {
  164. log.api("创建设备失败:", error);
  165. return c.json({ error: "创建设备失败" }, 500);
  166. }
  167. });
  168. // 更新设备
  169. deviceInstancesRoutes.put("/:id", withAuth, async (c) => {
  170. try {
  171. const id = Number(c.req.param("id"));
  172. if (!id || isNaN(id)) {
  173. return c.json({ error: "无效的设备ID" }, 400);
  174. }
  175. const apiClient = c.get('apiClient');
  176. const data = (await c.req.json()) as Partial<DeviceInstance>;
  177. // 检查设备是否存在
  178. const [existingDevice] = await apiClient.database
  179. .table("device_instances")
  180. .where({ id, is_deleted: DeleteStatus.NOT_DELETED });
  181. if (!existingDevice) {
  182. return c.json({ error: "设备不存在" }, 404);
  183. }
  184. // 如果更新设备类型,检查该类型是否存在
  185. if (data.type_id) {
  186. const [deviceType] = await apiClient.database
  187. .table("device_types")
  188. .where({ id: data.type_id, is_deleted: DeleteStatus.NOT_DELETED });
  189. if (!deviceType) {
  190. return c.json({ error: "设备类型不存在" }, 404);
  191. }
  192. }
  193. // 更新设备
  194. await apiClient.database
  195. .table("device_instances")
  196. .where("id", id)
  197. .update({
  198. ...data,
  199. updated_at: apiClient.database.fn.now(),
  200. });
  201. // 获取更新后的设备
  202. const [updatedDevice] = await apiClient.database
  203. .table("device_instances")
  204. .where("id", id);
  205. return c.json({
  206. message: "设备更新成功",
  207. data: updatedDevice,
  208. });
  209. } catch (error) {
  210. log.api("更新设备失败:", error);
  211. return c.json({ error: "更新设备失败" }, 500);
  212. }
  213. });
  214. // 删除设备(软删除)
  215. deviceInstancesRoutes.delete("/:id", withAuth, async (c) => {
  216. try {
  217. const id = Number(c.req.param("id"));
  218. if (!id || isNaN(id)) {
  219. return c.json({ error: "无效的设备ID" }, 400);
  220. }
  221. const apiClient = c.get('apiClient');
  222. // 检查设备是否存在
  223. const [existingDevice] = await apiClient.database
  224. .table("device_instances")
  225. .where({ id, is_deleted: DeleteStatus.NOT_DELETED });
  226. if (!existingDevice) {
  227. return c.json({ error: "设备不存在" }, 404);
  228. }
  229. // 软删除设备
  230. await apiClient.database.table("device_instances").where("id", id).update({
  231. is_deleted: DeleteStatus.DELETED,
  232. updated_at: apiClient.database.fn.now(),
  233. });
  234. return c.json({
  235. message: "设备删除成功",
  236. id,
  237. });
  238. } catch (error) {
  239. log.api("删除设备失败:", error);
  240. return c.json({ error: "删除设备失败" }, 500);
  241. }
  242. });
  243. return deviceInstancesRoutes;
  244. }