@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
package/index.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export { default } from "./module/KnowledgeModule";
|
|
2
|
+
|
|
3
|
+
// 导出类型
|
|
4
|
+
export {
|
|
5
|
+
type KnowledgeSafe,
|
|
6
|
+
type KnowledgeType,
|
|
7
|
+
type Knowledge,
|
|
8
|
+
type KnowledgeTreeNode,
|
|
9
|
+
type KnowledgeTag,
|
|
10
|
+
type KnowledgeTagRelation,
|
|
11
|
+
type InsertKnowledge,
|
|
12
|
+
type InsertTag,
|
|
13
|
+
} from './types';
|
|
14
|
+
|
|
15
|
+
// 导出 Schema
|
|
16
|
+
export {
|
|
17
|
+
knowledge,
|
|
18
|
+
createKnowledgeSchema,
|
|
19
|
+
batchCreateKnowledgeSchema,
|
|
20
|
+
batchDetailKnowledgeSchema,
|
|
21
|
+
updateKnowledgeSchema,
|
|
22
|
+
listKnowledgeSchema,
|
|
23
|
+
searchKnowledgeSchema,
|
|
24
|
+
moveKnowledgeSchema,
|
|
25
|
+
updateIsTopSchema,
|
|
26
|
+
updateSafeSchema,
|
|
27
|
+
} from './orm/Knowledge.schema';
|
|
28
|
+
|
|
29
|
+
export {
|
|
30
|
+
knowledgeTag,
|
|
31
|
+
knowledgeTagRelation,
|
|
32
|
+
createTagSchema,
|
|
33
|
+
updateTagSchema,
|
|
34
|
+
addTagRelationSchema,
|
|
35
|
+
} from './orm/Tag.schema';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createModule } from "@mindbase/express-common";
|
|
2
|
+
import { logger } from "@mindbase/express-common";
|
|
3
|
+
|
|
4
|
+
export default createModule(async (app) => {
|
|
5
|
+
const db = app.getDB();
|
|
6
|
+
|
|
7
|
+
logger.info("[KnowledgeModule] 初始化 knowledge 模块");
|
|
8
|
+
|
|
9
|
+
// 初始化 Service
|
|
10
|
+
const { initKnowledgeService } = await import("../service/KnowledgeService");
|
|
11
|
+
const { initTagService } = await import("../service/TagService");
|
|
12
|
+
initKnowledgeService(db);
|
|
13
|
+
initTagService(db);
|
|
14
|
+
|
|
15
|
+
// 路由将通过自动扫描 routes/*.route.ts 和 routes/**/*.route.ts 注册
|
|
16
|
+
|
|
17
|
+
logger.info("[KnowledgeModule] 模块加载完成");
|
|
18
|
+
}, __filename);
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
|
|
2
|
+
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 知识库主表
|
|
7
|
+
*/
|
|
8
|
+
export const knowledge = sqliteTable("knowledge", {
|
|
9
|
+
id: integer("id").primaryKey({ autoIncrement: true }),
|
|
10
|
+
parentId: integer("parent_id").notNull(),
|
|
11
|
+
name: text("name").notNull(),
|
|
12
|
+
path: text("path").notNull(),
|
|
13
|
+
level: integer("level").notNull().default(0),
|
|
14
|
+
type: integer("type").notNull(), // 0:文件夹 1:笔记 2:书籍
|
|
15
|
+
safe: integer("safe").notNull().default(0),
|
|
16
|
+
userId: integer("user_id").notNull(),
|
|
17
|
+
// 书籍特有字段
|
|
18
|
+
coverImage: text("cover_image"),
|
|
19
|
+
author: text("author"),
|
|
20
|
+
isbn: text("isbn"),
|
|
21
|
+
description: text("description"),
|
|
22
|
+
created: integer("created", { mode: "timestamp" }),
|
|
23
|
+
updated: integer("updated", { mode: "timestamp" }),
|
|
24
|
+
isDelete: integer("is_delete").notNull().default(0),
|
|
25
|
+
isTop: integer("is_top").notNull().default(0),
|
|
26
|
+
content: text("content"),
|
|
27
|
+
contentText: text("content_text"),
|
|
28
|
+
viewType: integer("view_type").default(0),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// ==================== Zod Schemas ====================
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 创建知识库内容验证
|
|
35
|
+
*/
|
|
36
|
+
export const createKnowledgeSchema = createInsertSchema(knowledge as any, {
|
|
37
|
+
name: z.string().min(1, "名称不能为空").max(255, "名称不能超过255字符") as any,
|
|
38
|
+
type: z.coerce.number().int().min(0).max(2) as any,
|
|
39
|
+
safe: z.coerce.number().int().min(0).max(2).optional() as any,
|
|
40
|
+
}).pick({
|
|
41
|
+
name: true,
|
|
42
|
+
type: true,
|
|
43
|
+
safe: true,
|
|
44
|
+
description: true,
|
|
45
|
+
content: true,
|
|
46
|
+
contentText: true,
|
|
47
|
+
viewType: true,
|
|
48
|
+
coverImage: true,
|
|
49
|
+
author: true,
|
|
50
|
+
isbn: true,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 批量创建验证
|
|
55
|
+
*/
|
|
56
|
+
export const batchCreateKnowledgeSchema = z.object({
|
|
57
|
+
parentId: z.number().optional(),
|
|
58
|
+
items: z
|
|
59
|
+
.array(
|
|
60
|
+
z.object({
|
|
61
|
+
name: z.string().min(1, "名称不能为空").max(255),
|
|
62
|
+
type: z.coerce.number().int().min(0).max(2),
|
|
63
|
+
})
|
|
64
|
+
)
|
|
65
|
+
.min(1, "至少需要一个项目"),
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 批量获取详情验证
|
|
70
|
+
*/
|
|
71
|
+
export const batchDetailKnowledgeSchema = z.object({
|
|
72
|
+
ids: z.array(z.number().int().positive()).min(1, "至少需要一个ID"),
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 更新知识库内容验证
|
|
77
|
+
*/
|
|
78
|
+
export const updateKnowledgeSchema = createInsertSchema(knowledge as any)
|
|
79
|
+
.partial()
|
|
80
|
+
.extend({
|
|
81
|
+
id: z.number({ required_error: "ID不能为空" }),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 列表查询验证
|
|
86
|
+
*/
|
|
87
|
+
export const listKnowledgeSchema = z.object({
|
|
88
|
+
pageIndex: z.coerce.number().int().positive().optional().default(1),
|
|
89
|
+
pageSize: z.coerce.number().int().positive().optional().default(10),
|
|
90
|
+
level: z.coerce.number().int().min(0).optional(),
|
|
91
|
+
type: z.coerce.number().int().min(0).max(2).optional(),
|
|
92
|
+
safe: z.array(z.coerce.number().int().min(0).max(2)).optional(),
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 搜索验证
|
|
97
|
+
*/
|
|
98
|
+
export const searchKnowledgeSchema = z.object({
|
|
99
|
+
keyword: z.string().min(1, "关键词不能为空"),
|
|
100
|
+
pageIndex: z.coerce.number().int().positive().optional().default(1),
|
|
101
|
+
pageSize: z.coerce.number().int().positive().optional().default(10),
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* 移动节点验证
|
|
106
|
+
*/
|
|
107
|
+
export const moveKnowledgeSchema = z.object({
|
|
108
|
+
newParentId: z.number({ required_error: "新父节点ID不能为空" }),
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* 更新置顶状态验证
|
|
113
|
+
*/
|
|
114
|
+
export const updateIsTopSchema = z.object({
|
|
115
|
+
isTop: z.coerce.number().int().min(0).max(1),
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* 更新安全等级验证
|
|
120
|
+
*/
|
|
121
|
+
export const updateSafeSchema = z.object({
|
|
122
|
+
safe: z.coerce.number().int().min(0).max(2),
|
|
123
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
|
|
2
|
+
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 标签表
|
|
7
|
+
*/
|
|
8
|
+
export const knowledgeTag = sqliteTable("knowledge_tag", {
|
|
9
|
+
id: integer("id").primaryKey({ autoIncrement: true }),
|
|
10
|
+
name: text("name").notNull().unique(),
|
|
11
|
+
color: text("color"),
|
|
12
|
+
userId: integer("user_id"),
|
|
13
|
+
created: integer("created", { mode: "timestamp" }),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 标签关联表(多对多)
|
|
18
|
+
*/
|
|
19
|
+
export const knowledgeTagRelation = sqliteTable("knowledge_tag_relation", {
|
|
20
|
+
knowledgeId: integer("knowledge_id").notNull(),
|
|
21
|
+
tagId: integer("tag_id").notNull(),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// ==================== Zod Schemas ====================
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 创建标签验证
|
|
28
|
+
*/
|
|
29
|
+
export const createTagSchema = createInsertSchema(knowledgeTag as any, {
|
|
30
|
+
name: z.string().min(1, "标签名不能为空").max(50, "标签名不能超过50字符") as any,
|
|
31
|
+
color: z.string().regex(/^#[0-9A-Fa-f]{6}$/, "颜色必须是十六进制格式").optional() as any,
|
|
32
|
+
}).pick({
|
|
33
|
+
name: true,
|
|
34
|
+
color: true,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 更新标签验证
|
|
39
|
+
*/
|
|
40
|
+
export const updateTagSchema = createInsertSchema(knowledgeTag as any)
|
|
41
|
+
.partial()
|
|
42
|
+
.extend({
|
|
43
|
+
id: z.number({ required_error: "标签ID不能为空" }),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 添加标签关联验证
|
|
48
|
+
*/
|
|
49
|
+
export const addTagRelationSchema = z.object({
|
|
50
|
+
tagId: z.number({ required_error: "标签ID不能为空" }),
|
|
51
|
+
});
|
package/package.json
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mindbase/express-knowledge",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"exports": {
|
|
5
|
-
".":
|
|
6
|
-
"development": "./index.ts",
|
|
7
|
-
"types": "./dist/index.d.ts",
|
|
8
|
-
"import": "./dist/index.mjs"
|
|
9
|
-
}
|
|
5
|
+
".": "./index.ts"
|
|
10
6
|
},
|
|
11
7
|
"files": [
|
|
12
|
-
"
|
|
8
|
+
"routes",
|
|
9
|
+
"zod",
|
|
10
|
+
"orm",
|
|
11
|
+
"module",
|
|
12
|
+
"service",
|
|
13
|
+
"utils",
|
|
14
|
+
"types",
|
|
15
|
+
"index.ts",
|
|
16
|
+
"tsconfig.json"
|
|
13
17
|
],
|
|
14
18
|
"engines": {
|
|
15
19
|
"node": ">=20.0.0"
|
|
@@ -21,11 +25,10 @@
|
|
|
21
25
|
"zod": "^3.24.0"
|
|
22
26
|
},
|
|
23
27
|
"devDependencies": {
|
|
24
|
-
"tsup": "^8.0.0",
|
|
25
28
|
"typescript": "^5.1.3"
|
|
26
29
|
},
|
|
27
30
|
"scripts": {
|
|
28
|
-
"
|
|
31
|
+
"prepare": "tsc --noEmit"
|
|
29
32
|
},
|
|
30
33
|
"publishConfig": {
|
|
31
34
|
"access": "public"
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { Router, type Request, type Response, type NextFunction } from "express";
|
|
2
|
+
import { logger, validate } from "@mindbase/express-common";
|
|
3
|
+
import * as TagService from "../../service/TagService";
|
|
4
|
+
import * as schemas from "../../zod/tag.schema";
|
|
5
|
+
|
|
6
|
+
const router = Router();
|
|
7
|
+
|
|
8
|
+
// ==================== 标签路由 ====================
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 获取标签列表
|
|
12
|
+
* @apiSuccess {number} code 状态码
|
|
13
|
+
* @apiSuccess {string} message 消息
|
|
14
|
+
* @apiSuccess {Object[]} data 标签列表
|
|
15
|
+
*/
|
|
16
|
+
router.get("/", async (req: Request, res: Response, next: NextFunction) => {
|
|
17
|
+
const userId = res.locals.user?.id;
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const tags = await TagService.listTags(userId);
|
|
21
|
+
res.json({ code: 200, message: "获取成功", data: tags });
|
|
22
|
+
} catch (error) {
|
|
23
|
+
logger.error("[TagRoute] 获取标签列表失败:", error);
|
|
24
|
+
next(error);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 创建标签
|
|
30
|
+
* @apiParam {string} name 标签名称(必填)
|
|
31
|
+
* @apiParam {string} [color] 颜色(可选)
|
|
32
|
+
* @apiParam {string} [description] 描述(可选)
|
|
33
|
+
* @apiSuccess {number} code 状态码
|
|
34
|
+
* @apiSuccess {string} message 消息
|
|
35
|
+
* @apiSuccess {Object} data 创建的标签信息
|
|
36
|
+
*/
|
|
37
|
+
router.post("/", validate(schemas.createTagSchema), async (req: Request, res: Response, next: NextFunction) => {
|
|
38
|
+
const userId = res.locals.user?.id;
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
const result = await TagService.createTag({
|
|
42
|
+
...req.body,
|
|
43
|
+
userId,
|
|
44
|
+
});
|
|
45
|
+
res.json({ code: 200, message: "创建成功", data: result });
|
|
46
|
+
} catch (error) {
|
|
47
|
+
logger.error("[TagRoute] 创建标签失败:", error);
|
|
48
|
+
next(error);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 更新标签
|
|
54
|
+
* @apiParam {number} id 标签ID(路径参数,必填)
|
|
55
|
+
* @apiParam {string} [name] 标签名称(可选)
|
|
56
|
+
* @apiParam {string} [color] 颜色(可选)
|
|
57
|
+
* @apiParam {string} [description] 描述(可选)
|
|
58
|
+
* @apiSuccess {number} code 状态码
|
|
59
|
+
* @apiSuccess {string} message 消息
|
|
60
|
+
* @apiSuccess {Object} data 更新后的标签信息
|
|
61
|
+
*/
|
|
62
|
+
router.post("/:id", validate(schemas.updateTagSchema), async (req: Request, res: Response, next: NextFunction) => {
|
|
63
|
+
const { id } = req.params;
|
|
64
|
+
const userId = res.locals.user?.id;
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const result = await TagService.updateTag(Number(id), req.body, userId);
|
|
68
|
+
res.json({ code: 200, message: "更新成功", data: result });
|
|
69
|
+
} catch (error) {
|
|
70
|
+
logger.error("[TagRoute] 更新标签失败:", error);
|
|
71
|
+
next(error);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 删除标签
|
|
77
|
+
* @apiParam {number} id 标签ID(路径参数,必填)
|
|
78
|
+
* @apiSuccess {number} code 状态码
|
|
79
|
+
* @apiSuccess {string} message 消息
|
|
80
|
+
* @apiSuccess {null} data 返回空
|
|
81
|
+
*/
|
|
82
|
+
router.delete("/:id", async (req: Request, res: Response, next: NextFunction) => {
|
|
83
|
+
const { id } = req.params;
|
|
84
|
+
const userId = res.locals.user?.id;
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
await TagService.deleteTag(Number(id), userId);
|
|
88
|
+
res.json({ code: 200, message: "删除成功", data: null });
|
|
89
|
+
} catch (error) {
|
|
90
|
+
logger.error("[TagRoute] 删除标签失败:", error);
|
|
91
|
+
next(error);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 为知识库内容添加标签
|
|
97
|
+
* @apiParam {number} id 内容ID(路径参数,必填)
|
|
98
|
+
* @apiParam {number} tagId 标签ID(必填)
|
|
99
|
+
* @apiSuccess {number} code 状态码
|
|
100
|
+
* @apiSuccess {string} message 消息
|
|
101
|
+
* @apiSuccess {Object} data 添加结果
|
|
102
|
+
*/
|
|
103
|
+
router.post(
|
|
104
|
+
"/:id/tags",
|
|
105
|
+
validate(schemas.addTagRelationSchema),
|
|
106
|
+
async (req: Request, res: Response, next: NextFunction) => {
|
|
107
|
+
const { id } = req.params;
|
|
108
|
+
const { tagId } = req.body;
|
|
109
|
+
const userId = res.locals.user?.id;
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
const result = await TagService.addTagToKnowledge(Number(id), tagId, userId);
|
|
113
|
+
res.json({ code: 200, message: "添加成功", data: result });
|
|
114
|
+
} catch (error) {
|
|
115
|
+
logger.error("[TagRoute] 添加标签失败:", error);
|
|
116
|
+
next(error);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 移除知识库内容的标签
|
|
123
|
+
* @apiParam {number} id 内容ID(路径参数,必填)
|
|
124
|
+
* @apiParam {number} tagId 标签ID(路径参数,必填)
|
|
125
|
+
* @apiSuccess {number} code 状态码
|
|
126
|
+
* @apiSuccess {string} message 消息
|
|
127
|
+
* @apiSuccess {null} data 返回空
|
|
128
|
+
*/
|
|
129
|
+
router.delete("/:id/tags/:tagId", async (req: Request, res: Response, next: NextFunction) => {
|
|
130
|
+
const { id, tagId } = req.params;
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
await TagService.removeTagFromKnowledge(Number(id), Number(tagId));
|
|
134
|
+
res.json({ code: 200, message: "移除成功", data: null });
|
|
135
|
+
} catch (error) {
|
|
136
|
+
logger.error("[TagRoute] 移除标签失败:", error);
|
|
137
|
+
next(error);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* 获取知识库内容的标签列表
|
|
143
|
+
* @apiParam {number} id 内容ID(路径参数,必填)
|
|
144
|
+
* @apiSuccess {number} code 状态码
|
|
145
|
+
* @apiSuccess {string} message 消息
|
|
146
|
+
* @apiSuccess {Object[]} data 标签列表
|
|
147
|
+
*/
|
|
148
|
+
router.get("/:id/tags", async (req: Request, res: Response, next: NextFunction) => {
|
|
149
|
+
const { id } = req.params;
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const tags = await TagService.getKnowledgeTags(Number(id));
|
|
153
|
+
res.json({ code: 200, message: "获取成功", data: tags });
|
|
154
|
+
} catch (error) {
|
|
155
|
+
logger.error("[TagRoute] 获取内容标签失败:", error);
|
|
156
|
+
next(error);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* 按标签查询知识库内容
|
|
162
|
+
* @apiParam {number} tagId 标签ID(路径参数,必填)
|
|
163
|
+
* @apiParam {number} [pageIndex] 页码(可选,默认1)
|
|
164
|
+
* @apiParam {number} [pageSize] 每页数量(可选,默认10)
|
|
165
|
+
* @apiSuccess {number} code 状态码
|
|
166
|
+
* @apiSuccess {string} message 消息
|
|
167
|
+
* @apiSuccess {Object} data 查询结果
|
|
168
|
+
* @apiSuccess {Object[]} data.list 内容列表
|
|
169
|
+
* @apiSuccess {number} data.total 总数
|
|
170
|
+
*/
|
|
171
|
+
router.get("/by-tag/:tagId", async (req: Request, res: Response, next: NextFunction) => {
|
|
172
|
+
const { tagId } = req.params;
|
|
173
|
+
const userId = res.locals.user?.id;
|
|
174
|
+
const permissions = res.locals.permissions || [];
|
|
175
|
+
const isAdmin = permissions.includes("admin") || permissions.includes("*:*:*");
|
|
176
|
+
const { pageIndex, pageSize } = req.query;
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
const result = await TagService.getKnowledgeByTag(Number(tagId), {
|
|
180
|
+
pageIndex: pageIndex ? Number(pageIndex) : 1,
|
|
181
|
+
pageSize: pageSize ? Number(pageSize) : 10,
|
|
182
|
+
userId,
|
|
183
|
+
isAdmin,
|
|
184
|
+
});
|
|
185
|
+
res.json({ code: 200, message: "获取成功", data: result });
|
|
186
|
+
} catch (error) {
|
|
187
|
+
logger.error("[TagRoute] 按标签查询失败:", error);
|
|
188
|
+
next(error);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
export default router;
|