2
0

routes_know_info.ts 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. import { Hono } from "hono";
  2. import debug from "debug";
  3. import type {
  4. KnowInfo,
  5. } from "../client/share/types.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("api:sys"),
  13. };
  14. // 创建知识库管理路由
  15. export function createKnowInfoRoutes(withAuth: WithAuth) {
  16. const knowInfoRoutes = new Hono<{ Variables: Variables }>();
  17. // 获取知识库文章列表
  18. knowInfoRoutes.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 title = c.req.query("title");
  27. const category = c.req.query("category");
  28. const tags = c.req.query("tags");
  29. // 构建查询
  30. let query = apiClient.database
  31. .table("know_info")
  32. .where("is_deleted", 0)
  33. .orderBy("id", "desc");
  34. // 应用筛选条件
  35. if (title) {
  36. query = query.where("title", "like", `%${title}%`);
  37. }
  38. if (category) {
  39. query = query.where("category", category);
  40. }
  41. if (tags) {
  42. query = query.where("tags", "like", `%${tags}%`);
  43. }
  44. // 克隆查询以获取总数
  45. const countQuery = query.clone();
  46. // 执行分页查询
  47. const articles = await query.limit(limit).offset(offset);
  48. // 获取总数
  49. const count = await countQuery.count();
  50. return c.json({
  51. data: articles,
  52. pagination: {
  53. total: Number(count),
  54. current: page,
  55. pageSize: limit,
  56. totalPages: Math.ceil(Number(count) / limit),
  57. },
  58. });
  59. } catch (error) {
  60. log.api("获取知识库文章列表失败:", error);
  61. return c.json({ error: "获取知识库文章列表失败" }, 500);
  62. }
  63. });
  64. // 获取单个知识库文章
  65. knowInfoRoutes.get("/:id", withAuth, async (c) => {
  66. try {
  67. const id = Number(c.req.param("id"));
  68. if (!id || isNaN(id)) {
  69. return c.json({ error: "无效的文章ID" }, 400);
  70. }
  71. const apiClient = c.get('apiClient');
  72. const [article] = await apiClient.database
  73. .table("know_info")
  74. .where({ id, is_deleted: 0 });
  75. if (!article) {
  76. return c.json({ error: "文章不存在" }, 404);
  77. }
  78. return c.json({message: '获取知识库文章详情成功', data: article});
  79. } catch (error) {
  80. log.api("获取知识库文章详情失败:", error);
  81. return c.json({ error: "获取知识库文章详情失败" }, 500);
  82. }
  83. });
  84. // 创建知识库文章
  85. knowInfoRoutes.post("/", withAuth, async (c) => {
  86. try {
  87. const articleData = (await c.req.json()) as Partial<KnowInfo>;
  88. // 验证必填字段
  89. if (!articleData.title) {
  90. return c.json({ error: "文章标题不能为空" }, 400);
  91. }
  92. // 如果作者为空,则使用当前用户的用户名
  93. if (!articleData.author) {
  94. const user = c.get("user");
  95. articleData.author = user ? user.username : "unknown";
  96. }
  97. const apiClient = c.get('apiClient');
  98. const [id] = await apiClient.database
  99. .table("know_info")
  100. .insert(articleData);
  101. // 获取创建的文章
  102. const [createdArticle] = await apiClient.database
  103. .table("know_info")
  104. .where("id", id);
  105. return c.json({
  106. message: "知识库文章创建成功",
  107. data: createdArticle,
  108. });
  109. } catch (error) {
  110. log.api("创建知识库文章失败:", error);
  111. return c.json({ error: "创建知识库文章失败" }, 500);
  112. }
  113. });
  114. // 更新知识库文章
  115. knowInfoRoutes.put("/:id", withAuth, async (c) => {
  116. try {
  117. const id = Number(c.req.param("id"));
  118. if (!id || isNaN(id)) {
  119. return c.json({ error: "无效的文章ID" }, 400);
  120. }
  121. const articleData = (await c.req.json()) as Partial<KnowInfo>;
  122. // 验证必填字段
  123. if (!articleData.title) {
  124. return c.json({ error: "文章标题不能为空" }, 400);
  125. }
  126. const apiClient = c.get('apiClient');
  127. // 检查文章是否存在
  128. const [existingArticle] = await apiClient.database
  129. .table("know_info")
  130. .where({ id, is_deleted: 0 });
  131. if (!existingArticle) {
  132. return c.json({ error: "文章不存在" }, 404);
  133. }
  134. // 更新文章
  135. await apiClient.database
  136. .table("know_info")
  137. .where("id", id)
  138. .update({
  139. ...articleData,
  140. updated_at: apiClient.database.fn.now(),
  141. });
  142. // 获取更新后的文章
  143. const [updatedArticle] = await apiClient.database
  144. .table("know_info")
  145. .where("id", id);
  146. return c.json({
  147. message: "知识库文章更新成功",
  148. data: updatedArticle,
  149. });
  150. } catch (error) {
  151. log.api("更新知识库文章失败:", error);
  152. return c.json({ error: "更新知识库文章失败" }, 500);
  153. }
  154. });
  155. // 删除知识库文章(软删除)
  156. knowInfoRoutes.delete("/:id", withAuth, async (c) => {
  157. try {
  158. const id = Number(c.req.param("id"));
  159. if (!id || isNaN(id)) {
  160. return c.json({ error: "无效的文章ID" }, 400);
  161. }
  162. const apiClient = c.get('apiClient');
  163. // 检查文章是否存在
  164. const [existingArticle] = await apiClient.database
  165. .table("know_info")
  166. .where({ id, is_deleted: 0 });
  167. if (!existingArticle) {
  168. return c.json({ error: "文章不存在" }, 404);
  169. }
  170. // 软删除文章
  171. await apiClient.database.table("know_info").where("id", id).update({
  172. is_deleted: 1,
  173. updated_at: apiClient.database.fn.now(),
  174. });
  175. return c.json({
  176. message: "知识库文章删除成功",
  177. });
  178. } catch (error) {
  179. log.api("删除知识库文章失败:", error);
  180. return c.json({ error: "删除知识库文章失败" }, 500);
  181. }
  182. });
  183. return knowInfoRoutes;
  184. }