@mindbase/express-knowledge 1.0.4 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.ts +35 -0
- package/module/KnowledgeModule.ts +18 -0
- package/orm/Knowledge.schema.ts +123 -0
- package/orm/Tag.schema.ts +51 -0
- package/package.json +12 -9
- package/routes/knowledge/tags.route.ts +192 -0
- package/routes/knowledge.route.ts +378 -0
- package/service/KnowledgeService.ts +515 -0
- package/service/TagService.ts +271 -0
- package/tsconfig.json +7 -0
- package/types/index.ts +85 -0
- package/utils/path-builder.ts +47 -0
- package/utils/tree-builder.ts +57 -0
- package/zod/knowledge.schema.ts +13 -0
- package/zod/tag.schema.ts +7 -0
- package/dist/Knowledge.schema-BHFPDLIO.mjs +0 -27
- package/dist/Knowledge.schema-BHFPDLIO.mjs.map +0 -1
- package/dist/KnowledgeService-JDG23Q4Z.mjs +0 -303
- package/dist/KnowledgeService-JDG23Q4Z.mjs.map +0 -1
- package/dist/TagService-YZAGBPG7.mjs +0 -163
- package/dist/TagService-YZAGBPG7.mjs.map +0 -1
- package/dist/chunk-2G44ILZL.mjs +0 -93
- package/dist/chunk-2G44ILZL.mjs.map +0 -1
- package/dist/chunk-GWIBTASJ.mjs +0 -40
- package/dist/chunk-GWIBTASJ.mjs.map +0 -1
- package/dist/chunk-SG44KRK4.mjs +0 -40
- package/dist/chunk-SG44KRK4.mjs.map +0 -1
- package/dist/chunk-VHBDNZOQ.mjs +0 -10
- package/dist/chunk-VHBDNZOQ.mjs.map +0 -1
- package/dist/index.d.mts +0 -7682
- package/dist/index.mjs +0 -55
- package/dist/index.mjs.map +0 -1
- package/dist/tree-builder-LIYCLUJS.mjs +0 -35
- package/dist/tree-builder-LIYCLUJS.mjs.map +0 -1
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
import { Router, type Request, type Response, type NextFunction } from "express";
|
|
2
|
+
import { logger, validate } from "@mindbase/express-common";
|
|
3
|
+
import * as KnowledgeService from "../service/KnowledgeService";
|
|
4
|
+
import * as schemas from "../zod/knowledge.schema";
|
|
5
|
+
|
|
6
|
+
const router = Router();
|
|
7
|
+
|
|
8
|
+
// ==================== 知识库内容路由 ====================
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 获取目录树
|
|
12
|
+
* @apiParam {number} [parentId] 父节点ID(可选,不传则获取根节点)
|
|
13
|
+
* @apiSuccess {number} code 状态码
|
|
14
|
+
* @apiSuccess {string} message 消息
|
|
15
|
+
* @apiSuccess {Object[]} data 目录树结构
|
|
16
|
+
* @apiSuccess {number} data[].id 节点ID
|
|
17
|
+
* @apiSuccess {string} data[].name 名称
|
|
18
|
+
* @apiSuccess {number} data[].type 类型(0:文件夹, 1:笔记, 2:书籍)
|
|
19
|
+
* @apiSuccess {number} data[].level 层级
|
|
20
|
+
* @apiSuccess {Object} data[].children 子节点
|
|
21
|
+
*/
|
|
22
|
+
router.get("/tree", async (req: Request, res: Response, next: NextFunction) => {
|
|
23
|
+
const userId = res.locals.user?.id;
|
|
24
|
+
const permissions = res.locals.permissions || [];
|
|
25
|
+
const isAdmin = permissions.includes('admin') || permissions.includes('*:*:*');
|
|
26
|
+
const { parentId } = req.query;
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const tree = await KnowledgeService.getKnowledgeTree({
|
|
30
|
+
parentId: parentId ? Number(parentId) : null,
|
|
31
|
+
userId,
|
|
32
|
+
isAdmin,
|
|
33
|
+
});
|
|
34
|
+
res.json({ code: 200, message: "获取成功", data: tree });
|
|
35
|
+
} catch (error) {
|
|
36
|
+
logger.error("[KnowledgeRoute] 获取目录树失败:", error);
|
|
37
|
+
next(error);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 获取内容列表(分页)
|
|
43
|
+
* @apiParam {number} [pageIndex] 页码(可选,默认1)
|
|
44
|
+
* @apiParam {number} [pageSize] 每页数量(可选,默认10)
|
|
45
|
+
* @apiParam {number} [level] 层级筛选(可选)
|
|
46
|
+
* @apiParam {number} [type] 类型筛选(可选,0:文件夹, 1:笔记, 2:书籍)
|
|
47
|
+
* @apiParam {number[]} [safe] 安全等级筛选(可选)
|
|
48
|
+
* @apiSuccess {number} code 状态码
|
|
49
|
+
* @apiSuccess {string} message 消息
|
|
50
|
+
* @apiSuccess {Object} data 内容列表
|
|
51
|
+
* @apiSuccess {Object[]} data.list 内容数组
|
|
52
|
+
* @apiSuccess {number} data.total 总数
|
|
53
|
+
* @apiSuccess {number} data.pageIndex 当前页
|
|
54
|
+
* @apiSuccess {number} data.pageSize 每页数量
|
|
55
|
+
*/
|
|
56
|
+
router.get("/list", validate(schemas.listKnowledgeSchema, "query"), async (req: Request, res: Response, next: NextFunction) => {
|
|
57
|
+
const userId = res.locals.user?.id;
|
|
58
|
+
const permissions = res.locals.permissions || [];
|
|
59
|
+
const isAdmin = permissions.includes('admin') || permissions.includes('*:*:*');
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const result = await KnowledgeService.listKnowledge({
|
|
63
|
+
...req.query as any,
|
|
64
|
+
userId,
|
|
65
|
+
isAdmin,
|
|
66
|
+
});
|
|
67
|
+
res.json({ code: 200, message: "获取成功", data: result });
|
|
68
|
+
} catch (error) {
|
|
69
|
+
logger.error("[KnowledgeRoute] 获取内容列表失败:", error);
|
|
70
|
+
next(error);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 搜索内容
|
|
76
|
+
* @apiParam {string} keyword 搜索关键词(必填)
|
|
77
|
+
* @apiParam {number} [pageIndex] 页码(可选,默认1)
|
|
78
|
+
* @apiParam {number} [pageSize] 每页数量(可选,默认10)
|
|
79
|
+
* @apiSuccess {number} code 状态码
|
|
80
|
+
* @apiSuccess {string} message 消息
|
|
81
|
+
* @apiSuccess {Object} data 搜索结果
|
|
82
|
+
* @apiSuccess {Object[]} data.list 结果数组
|
|
83
|
+
* @apiSuccess {number} data.total 总数
|
|
84
|
+
*/
|
|
85
|
+
router.get("/search", validate(schemas.searchKnowledgeSchema, "query"), async (req: Request, res: Response, next: NextFunction) => {
|
|
86
|
+
const userId = res.locals.user?.id;
|
|
87
|
+
const permissions = res.locals.permissions || [];
|
|
88
|
+
const isAdmin = permissions.includes('admin') || permissions.includes('*:*:*');
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
const result = await KnowledgeService.searchKnowledge({
|
|
92
|
+
...req.query as any,
|
|
93
|
+
userId,
|
|
94
|
+
isAdmin,
|
|
95
|
+
});
|
|
96
|
+
res.json({ code: 200, message: "搜索成功", data: result });
|
|
97
|
+
} catch (error) {
|
|
98
|
+
logger.error("[KnowledgeRoute] 搜索失败:", error);
|
|
99
|
+
next(error);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* 获取内容详情
|
|
105
|
+
* @apiParam {number} id 内容ID(路径参数,必填)
|
|
106
|
+
* @apiSuccess {number} code 状态码
|
|
107
|
+
* @apiSuccess {string} message 消息
|
|
108
|
+
* @apiSuccess {Object} data 内容详情
|
|
109
|
+
* @apiSuccess {number} data.id ID
|
|
110
|
+
* @apiSuccess {string} data.name 名称
|
|
111
|
+
* @apiSuccess {string} data.content 内容
|
|
112
|
+
* @apiSuccess {string} data.description 描述
|
|
113
|
+
* @apiSuccess {number} data.type 类型
|
|
114
|
+
* @apiSuccess {number} data.safe 安全等级
|
|
115
|
+
* @apiSuccess {boolean} data.isTop 是否置顶
|
|
116
|
+
*/
|
|
117
|
+
router.get("/:id", async (req: Request, res: Response, next: NextFunction) => {
|
|
118
|
+
const { id } = req.params;
|
|
119
|
+
const userId = res.locals.user?.id;
|
|
120
|
+
const permissions = res.locals.permissions || [];
|
|
121
|
+
const isAdmin = permissions.includes('admin') || permissions.includes('*:*:*');
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
const knowledge = await KnowledgeService.getKnowledgeById(Number(id));
|
|
125
|
+
|
|
126
|
+
if (!knowledge) {
|
|
127
|
+
return res.status(404).json({ code: 404, message: "内容不存在", data: null });
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// 权限检查
|
|
131
|
+
if (knowledge.safe === 2 && knowledge.userId !== userId && !isAdmin) {
|
|
132
|
+
return res.status(403).json({ code: 403, message: "无权访问", data: null });
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
res.json({ code: 200, message: "获取成功", data: knowledge });
|
|
136
|
+
} catch (error) {
|
|
137
|
+
logger.error("[KnowledgeRoute] 获取详情失败:", error);
|
|
138
|
+
next(error);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* 获取子节点
|
|
144
|
+
* @apiParam {number} id 父节点ID(路径参数,必填)
|
|
145
|
+
* @apiSuccess {number} code 状态码
|
|
146
|
+
* @apiSuccess {string} message 消息
|
|
147
|
+
* @apiSuccess {Object[]} data 子节点列表
|
|
148
|
+
*/
|
|
149
|
+
router.get("/:id/children", async (req: Request, res: Response, next: NextFunction) => {
|
|
150
|
+
const { id } = req.params;
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
const children = await KnowledgeService.getChildren(Number(id));
|
|
154
|
+
res.json({ code: 200, message: "获取成功", data: children });
|
|
155
|
+
} catch (error) {
|
|
156
|
+
logger.error("[KnowledgeRoute] 获取子节点失败:", error);
|
|
157
|
+
next(error);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* 创建内容
|
|
163
|
+
* @apiParam {string} name 名称(必填)
|
|
164
|
+
* @apiParam {number} type 类型(必填,0:文件夹, 1:笔记, 2:书籍)
|
|
165
|
+
* @apiParam {number} [safe] 安全等级(可选,默认0)
|
|
166
|
+
* @apiParam {string} [description] 描述(可选)
|
|
167
|
+
* @apiParam {string} [content] 内容(可选)
|
|
168
|
+
* @apiParam {string} [contentText] 文本内容(可选)
|
|
169
|
+
* @apiParam {string} [coverImage] 封面图片(可选)
|
|
170
|
+
* @apiParam {string} [author] 作者(可选)
|
|
171
|
+
* @apiParam {string} [isbn] ISBN(可选)
|
|
172
|
+
* @apiParam {number} [parentId] 父节点ID(可选)
|
|
173
|
+
* @apiSuccess {number} code 状态码
|
|
174
|
+
* @apiSuccess {string} message 消息
|
|
175
|
+
* @apiSuccess {Object} data 创建的内容信息
|
|
176
|
+
*/
|
|
177
|
+
router.post("/", validate(schemas.createKnowledgeSchema), async (req: Request, res: Response, next: NextFunction) => {
|
|
178
|
+
const userId = res.locals.user?.id;
|
|
179
|
+
const { parentId, ...data } = req.body;
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
const result = await KnowledgeService.createKnowledge({
|
|
183
|
+
...data,
|
|
184
|
+
userId,
|
|
185
|
+
parentId,
|
|
186
|
+
});
|
|
187
|
+
res.json({ code: 200, message: "创建成功", data: result });
|
|
188
|
+
} catch (error) {
|
|
189
|
+
logger.error("[KnowledgeRoute] 创建失败:", error);
|
|
190
|
+
next(error);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* 批量创建
|
|
196
|
+
* @apiParam {number} [parentId] 父节点ID(可选)
|
|
197
|
+
* @apiParam {Object[]} items 批量项目(必填)
|
|
198
|
+
* @apiParam {string} items[].name 名称(必填)
|
|
199
|
+
* @apiParam {number} items[].type 类型(必填,0:文件夹, 1:笔记, 2:书籍)
|
|
200
|
+
* @apiSuccess {number} code 状态码
|
|
201
|
+
* @apiSuccess {string} message 消息
|
|
202
|
+
* @apiSuccess {Object[]} data 批量创建结果
|
|
203
|
+
*/
|
|
204
|
+
router.post("/batch", validate(schemas.batchCreateKnowledgeSchema), async (req: Request, res: Response, next: NextFunction) => {
|
|
205
|
+
const userId = res.locals.user?.id;
|
|
206
|
+
const { parentId, items } = req.body;
|
|
207
|
+
|
|
208
|
+
try {
|
|
209
|
+
const results = await KnowledgeService.createKnowledgeBatch(items, userId, parentId);
|
|
210
|
+
res.json({ code: 200, message: "批量创建完成", data: results });
|
|
211
|
+
} catch (error) {
|
|
212
|
+
logger.error("[KnowledgeRoute] 批量创建失败:", error);
|
|
213
|
+
next(error);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* 批量获取详情
|
|
219
|
+
* @apiParam {number[]} ids 内容ID数组(必填)
|
|
220
|
+
* @apiSuccess {number} code 状态码
|
|
221
|
+
* @apiSuccess {string} message 消息
|
|
222
|
+
* @apiSuccess {Object[]} data 内容详情数组
|
|
223
|
+
*/
|
|
224
|
+
router.post("/batch-detail", validate(schemas.batchDetailKnowledgeSchema), async (req: Request, res: Response, next: NextFunction) => {
|
|
225
|
+
const { ids } = req.body;
|
|
226
|
+
|
|
227
|
+
try {
|
|
228
|
+
const result = await KnowledgeService.getKnowledgeByIds(ids);
|
|
229
|
+
res.json({ code: 200, message: "获取成功", data: result });
|
|
230
|
+
} catch (error) {
|
|
231
|
+
logger.error("[KnowledgeRoute] 批量获取详情失败:", error);
|
|
232
|
+
next(error);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* 更新内容
|
|
238
|
+
* @apiParam {number} id 内容ID(路径参数,必填)
|
|
239
|
+
* @apiParam {string} [name] 名称(可选)
|
|
240
|
+
* @apiParam {number} [type] 类型(可选)
|
|
241
|
+
* @apiParam {number} [safe] 安全等级(可选)
|
|
242
|
+
* @apiParam {string} [description] 描述(可选)
|
|
243
|
+
* @apiParam {string} [content] 内容(可选)
|
|
244
|
+
* @apiParam {string} [contentText] 文本内容(可选)
|
|
245
|
+
* @apiParam {string} [coverImage] 封面图片(可选)
|
|
246
|
+
* @apiParam {string} [author] 作者(可选)
|
|
247
|
+
* @apiParam {string} [isbn] ISBN(可选)
|
|
248
|
+
* @apiSuccess {number} code 状态码
|
|
249
|
+
* @apiSuccess {string} message 消息
|
|
250
|
+
* @apiSuccess {Object} data 更新后的内容信息
|
|
251
|
+
*/
|
|
252
|
+
router.post("/:id", validate(schemas.updateKnowledgeSchema), async (req: Request, res: Response, next: NextFunction) => {
|
|
253
|
+
const { id } = req.params;
|
|
254
|
+
const userId = res.locals.user?.id;
|
|
255
|
+
const data = req.body;
|
|
256
|
+
|
|
257
|
+
try {
|
|
258
|
+
await KnowledgeService.updateKnowledge(Number(id), data, userId);
|
|
259
|
+
const result = await KnowledgeService.getKnowledgeById(Number(id));
|
|
260
|
+
res.json({ code: 200, message: "更新成功", data: result });
|
|
261
|
+
} catch (error) {
|
|
262
|
+
logger.error("[KnowledgeRoute] 更新失败:", error);
|
|
263
|
+
next(error);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* 移动节点
|
|
269
|
+
* @apiParam {number} id 内容ID(路径参数,必填)
|
|
270
|
+
* @apiParam {number} newParentId 新父节点ID(必填)
|
|
271
|
+
* @apiSuccess {number} code 状态码
|
|
272
|
+
* @apiSuccess {string} message 消息
|
|
273
|
+
* @apiSuccess {Object} data 移动结果
|
|
274
|
+
*/
|
|
275
|
+
router.post("/:id/move", validate(schemas.moveKnowledgeSchema), async (req: Request, res: Response, next: NextFunction) => {
|
|
276
|
+
const { id } = req.params;
|
|
277
|
+
const userId = res.locals.user?.id;
|
|
278
|
+
const { newParentId } = req.body;
|
|
279
|
+
|
|
280
|
+
try {
|
|
281
|
+
const result = await KnowledgeService.moveKnowledge(Number(id), newParentId, userId);
|
|
282
|
+
res.json({ code: 200, message: "移动成功", data: result });
|
|
283
|
+
} catch (error) {
|
|
284
|
+
logger.error("[KnowledgeRoute] 移动失败:", error);
|
|
285
|
+
next(error);
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* 更新置顶状态
|
|
291
|
+
* @apiParam {number} id 内容ID(路径参数,必填)
|
|
292
|
+
* @apiParam {number} isTop 是否置顶(必填,0:否, 1:是)
|
|
293
|
+
* @apiSuccess {number} code 状态码
|
|
294
|
+
* @apiSuccess {string} message 消息
|
|
295
|
+
* @apiSuccess {Object} data 更新结果
|
|
296
|
+
*/
|
|
297
|
+
router.post("/:id/isTop", validate(schemas.updateIsTopSchema), async (req: Request, res: Response, next: NextFunction) => {
|
|
298
|
+
const { id } = req.params;
|
|
299
|
+
const userId = res.locals.user?.id;
|
|
300
|
+
const { isTop } = req.body;
|
|
301
|
+
|
|
302
|
+
try {
|
|
303
|
+
const result = await KnowledgeService.updateIsTop(Number(id), isTop, userId);
|
|
304
|
+
res.json({ code: 200, message: "更新成功", data: result });
|
|
305
|
+
} catch (error) {
|
|
306
|
+
logger.error("[KnowledgeRoute] 更新置顶状态失败:", error);
|
|
307
|
+
next(error);
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* 更新安全等级
|
|
313
|
+
* @apiParam {number} id 内容ID(路径参数,必填)
|
|
314
|
+
* @apiParam {number} safe 安全等级(必填,0:公开, 1:私有, 2:加密)
|
|
315
|
+
* @apiSuccess {number} code 状态码
|
|
316
|
+
* @apiSuccess {string} message 消息
|
|
317
|
+
* @apiSuccess {Object} data 更新结果
|
|
318
|
+
*/
|
|
319
|
+
router.post("/:id/safe", validate(schemas.updateSafeSchema), async (req: Request, res: Response, next: NextFunction) => {
|
|
320
|
+
const { id } = req.params;
|
|
321
|
+
const userId = res.locals.user?.id;
|
|
322
|
+
const { safe } = req.body;
|
|
323
|
+
|
|
324
|
+
try {
|
|
325
|
+
const result = await KnowledgeService.updateSafe(Number(id), safe, userId);
|
|
326
|
+
res.json({ code: 200, message: "更新成功", data: result });
|
|
327
|
+
} catch (error) {
|
|
328
|
+
logger.error("[KnowledgeRoute] 更新安全等级失败:", error);
|
|
329
|
+
next(error);
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* 逻辑删除
|
|
335
|
+
* @apiParam {number} id 内容ID(路径参数,必填)
|
|
336
|
+
* @apiSuccess {number} code 状态码
|
|
337
|
+
* @apiSuccess {string} message 消息
|
|
338
|
+
* @apiSuccess {null} data 返回空
|
|
339
|
+
*/
|
|
340
|
+
router.delete("/:id", async (req: Request, res: Response, next: NextFunction) => {
|
|
341
|
+
const { id } = req.params;
|
|
342
|
+
const userId = res.locals.user?.id;
|
|
343
|
+
|
|
344
|
+
try {
|
|
345
|
+
await KnowledgeService.deleteKnowledge(Number(id), userId);
|
|
346
|
+
res.json({ code: 200, message: "删除成功", data: null });
|
|
347
|
+
} catch (error) {
|
|
348
|
+
logger.error("[KnowledgeRoute] 删除失败:", error);
|
|
349
|
+
next(error);
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* 真实删除(管理员)
|
|
355
|
+
* @apiParam {number} id 内容ID(路径参数,必填)
|
|
356
|
+
* @apiSuccess {number} code 状态码
|
|
357
|
+
* @apiSuccess {string} message 消息
|
|
358
|
+
* @apiSuccess {null} data 返回空
|
|
359
|
+
*/
|
|
360
|
+
router.delete("/:id/real", async (req: Request, res: Response, next: NextFunction) => {
|
|
361
|
+
const { id } = req.params;
|
|
362
|
+
const permissions = res.locals.permissions || [];
|
|
363
|
+
const isAdmin = permissions.includes('admin') || permissions.includes('*:*:*');
|
|
364
|
+
|
|
365
|
+
if (!isAdmin) {
|
|
366
|
+
return res.status(403).json({ code: 403, message: "需要管理员权限", data: null });
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
try {
|
|
370
|
+
await KnowledgeService.deleteKnowledgeReal(Number(id));
|
|
371
|
+
res.json({ code: 200, message: "删除成功", data: null });
|
|
372
|
+
} catch (error) {
|
|
373
|
+
logger.error("[KnowledgeRoute] 真实删除失败:", error);
|
|
374
|
+
next(error);
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
export default router;
|