import { Hono } from "hono"; import debug from "debug"; import type { RackServer } from "../client/share/monitorTypes.ts"; import { DeleteStatus } from "../client/share/types.ts"; import type { Variables , WithAuth } from "./middlewares.ts"; const log = { api: debug("d8d:rack:api"), }; // 创建机柜服务器管理 API 的工厂函数 export function createRackServerRoutes(withAuth: WithAuth) { const rackServerRoutes = new Hono<{ Variables: Variables }>(); // 获取机柜服务器列表 rackServerRoutes.get("/", withAuth, async (c) => { try { const apiClient = c.get('apiClient'); // 获取分页参数 const page = Number(c.req.query("page")) || 1; const limit = Number(c.req.query("limit")) || 10; const offset = (page - 1) * limit; // 获取筛选参数 const rackId = c.req.query("rack_id") ? Number(c.req.query("rack_id")) : null; const assetId = c.req.query("asset_id") ? Number(c.req.query("asset_id")) : null; const serverType = c.req.query("server_type") || ""; // 构建查询 let query = apiClient.database .table("rack_server as rs") .where("rs.is_deleted", DeleteStatus.NOT_DELETED) .leftJoin("rack_info as ri", "rs.rack_id", "ri.id") .leftJoin("zichan_info as zi", "rs.asset_id", "zi.id") .select("rs.*", "ri.rack_name", "ri.rack_code", "zi.asset_name"); // 应用筛选条件 if (rackId) { query = query.where("rs.rack_id", rackId); } if (assetId) { query = query.where("rs.asset_id", assetId); } if (serverType) { query = query.where("rs.server_type", serverType); } // 获取总记录数 const total = await query.clone().count(); // 获取分页数据 const servers = await query .limit(limit) .offset(offset) .orderBy("rs.created_at", "desc"); // 返回结果 return c.json({ data: servers, pagination: { total, current: page, pageSize: limit, }, }); } catch (error: any) { log.api("获取机柜服务器列表失败:", error); return c.json({ error: "获取机柜服务器列表失败" }, 500); } }); // 获取机柜服务器详情 rackServerRoutes.get("/:id", withAuth, async (c) => { try { const id = Number(c.req.param("id")); if (!id || isNaN(id)) { return c.json({ error: "无效的机柜服务器ID" }, 400); } const apiClient = c.get('apiClient'); // 查询机柜服务器 const server = await apiClient.database .table("rack_server as rs") .where("rs.id", id) .where("rs.is_deleted", DeleteStatus.NOT_DELETED) .leftJoin("rack_info as ri", "rs.rack_id", "ri.id") .leftJoin("zichan_info as zi", "rs.asset_id", "zi.id") .select("rs.*", "ri.rack_name", "ri.rack_code", "zi.asset_name") .first(); if (!server) { return c.json({ error: "机柜服务器不存在" }, 404); } return c.json(server); } catch (error) { log.api("获取机柜服务器详情失败:", error); return c.json({ error: "获取机柜服务器详情失败" }, 500); } }); // 创建机柜服务器 rackServerRoutes.post("/", withAuth, async (c) => { try { const serverData = (await c.req.json()) as Partial; // 验证必填字段 if (!serverData.rack_id) { return c.json({ error: "机柜ID不能为空" }, 400); } if (!serverData.asset_id) { return c.json({ error: "资产ID不能为空" }, 400); } if (!serverData.start_position) { return c.json({ error: "起始位置不能为空" }, 400); } const apiClient = c.get('apiClient'); // 检查机柜是否存在 const rack = await apiClient.database .table("rack_info") .where("id", serverData.rack_id) .where("is_deleted", DeleteStatus.NOT_DELETED) .first(); if (!rack) { return c.json({ error: "所选机柜不存在" }, 400); } // 检查资产是否存在 const asset = await apiClient.database .table("zichan_info") .where("id", serverData.asset_id) .where("is_deleted", DeleteStatus.NOT_DELETED) .first(); if (!asset) { return c.json({ error: "所选资产不存在" }, 400); } // 检查资产是否已分配到其他机柜 const existingServer = await apiClient.database .table("rack_server") .where("asset_id", serverData.asset_id) .where("is_deleted", DeleteStatus.NOT_DELETED) .first(); if (existingServer) { return c.json({ error: "该资产已分配到其他机柜" }, 400); } // 检查U位是否冲突 const size = serverData.size || 1; const startPosition = serverData.start_position; // 检查开始位置和大小是否超出机柜容量 if ( !startPosition || startPosition <= 0 || startPosition + size - 1 > rack.capacity ) { return c.json( { error: `设备位置超出机柜容量范围 (1-${rack.capacity}U)` }, 400 ); } const conflictServers = await apiClient.database .table("rack_server") .where("rack_id", serverData.rack_id) .where("is_deleted", DeleteStatus.NOT_DELETED) .select("*"); const newPositions = Array.from( { length: size }, (_, i) => startPosition + i ); for (const server of conflictServers) { const serverPositions = Array.from( { length: server.size }, (_, i) => server.start_position + i ); const hasConflict = newPositions.some((pos) => serverPositions.includes(pos) ); if (hasConflict) { return c.json( { error: `U位 ${startPosition} 与现有设备位置冲突` }, 400 ); } } // 插入机柜服务器 const [id] = await apiClient.database.table("rack_server").insert({ ...serverData, created_at: apiClient.database.fn.now(), updated_at: apiClient.database.fn.now(), }); return c.json({ message: "创建机柜服务器成功", id, }); } catch (error) { log.api("创建机柜服务器失败:", error); return c.json({ error: "创建机柜服务器失败" }, 500); } }); // 更新机柜服务器 rackServerRoutes.put("/:id", withAuth, async (c) => { try { const id = Number(c.req.param("id")); if (!id || isNaN(id)) { return c.json({ error: "无效的机柜服务器ID" }, 400); } const serverData = (await c.req.json()) as Partial; const apiClient = c.get('apiClient'); // 检查机柜服务器是否存在 const existingServer = await apiClient.database .table("rack_server") .where("id", id) .where("is_deleted", DeleteStatus.NOT_DELETED) .first(); if (!existingServer) { return c.json({ error: "机柜服务器不存在" }, 404); } // 检查机柜是否存在 const rack = await apiClient.database .table("rack_info") .where("id", serverData.rack_id || 0) .where("is_deleted", DeleteStatus.NOT_DELETED) .first(); if (!rack) { return c.json({ error: "所选机柜不存在" }, 400); } // 检查资产是否存在 const asset = await apiClient.database .table("zichan_info") .where("id", serverData.asset_id || 0) .where("is_deleted", DeleteStatus.NOT_DELETED) .first(); if (!asset) { return c.json({ error: "所选资产不存在" }, 400); } // 如果资产ID更改,检查资产是否存在 if (serverData.asset_id !== existingServer.asset_id) { const [existingAsset] = await apiClient.database .table("zichan_info") .where({ id: serverData.asset_id, is_deleted: DeleteStatus.NOT_DELETED, }); if (!existingAsset) { return c.json({ error: "所选资产不存在" }, 400); } } // 检查U位是否冲突 const size = serverData.size || existingServer.size; const startPosition = serverData.start_position; // 检查开始位置和大小是否超出机柜容量 if ( !startPosition || startPosition <= 0 || startPosition + size - 1 > rack.capacity ) { return c.json( { error: `设备位置超出机柜容量范围 (1-${rack.capacity}U)` }, 400 ); } // 只有当位置相关信息改变时才检查冲突 if ( serverData.rack_id !== existingServer.rack_id || serverData.start_position !== existingServer.start_position || size !== existingServer.size ) { const conflictServers = await apiClient.database .table("rack_server") .where("rack_id", serverData.rack_id || 0) .where("id", "!=", id) .where("is_deleted", DeleteStatus.NOT_DELETED) .select("*"); const newPositions = Array.from( { length: size }, (_, i) => startPosition + i ); for (const server of conflictServers) { const serverPositions = Array.from( { length: server.size }, (_, i) => server.start_position + i ); const hasConflict = newPositions.some((pos) => serverPositions.includes(pos) ); if (hasConflict) { return c.json( { error: `U位 ${startPosition} 与现有设备位置冲突` }, 400 ); } } } // 更新机柜服务器 await apiClient.database .table("rack_server") .where("id", id) .update({ ...serverData, updated_at: apiClient.database.fn.now(), }); return c.json({ message: "更新机柜服务器成功", id, }); } catch (error) { log.api("更新机柜服务器失败:", error); return c.json({ error: "更新机柜服务器失败" }, 500); } }); // 删除机柜服务器 rackServerRoutes.delete("/:id", withAuth, async (c) => { try { const id = Number(c.req.param("id")); if (!id || isNaN(id)) { return c.json({ error: "无效的机柜服务器ID" }, 400); } const apiClient = c.get('apiClient'); // 检查机柜服务器是否存在 const existingServer = await apiClient.database .table("rack_server") .where("id", id) .where("is_deleted", DeleteStatus.NOT_DELETED) .first(); if (!existingServer) { return c.json({ error: "机柜服务器不存在" }, 404); } // 软删除机柜服务器 await apiClient.database.table("rack_server").where("id", id).update({ is_deleted: DeleteStatus.DELETED, updated_at: apiClient.database.fn.now(), }); return c.json({ message: "删除机柜服务器成功", id, }); } catch (error) { log.api("删除机柜服务器失败:", error); return c.json({ error: "删除机柜服务器失败" }, 500); } }); return rackServerRoutes; }