@mindbase/express-knowledge 1.0.0 → 1.0.4
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/dist/{Knowledge.schema-7KD5X7KG.mjs → Knowledge.schema-BHFPDLIO.mjs} +2 -2
- package/dist/{KnowledgeService-YZHS7UHY.mjs → KnowledgeService-JDG23Q4Z.mjs} +3 -3
- package/dist/KnowledgeService-JDG23Q4Z.mjs.map +1 -0
- package/dist/{TagService-VX6SB3S6.mjs → TagService-YZAGBPG7.mjs} +3 -3
- package/dist/TagService-YZAGBPG7.mjs.map +1 -0
- package/dist/{chunk-Y47QRG3M.mjs → chunk-2G44ILZL.mjs} +1 -1
- package/dist/chunk-2G44ILZL.mjs.map +1 -0
- package/dist/{chunk-S3ZXTYZ2.mjs → chunk-SG44KRK4.mjs} +1 -1
- package/dist/chunk-SG44KRK4.mjs.map +1 -0
- package/dist/index.d.mts +47 -33
- package/dist/index.mjs +4 -4
- package/dist/{tree-builder-XZ4OA2TD.mjs → tree-builder-LIYCLUJS.mjs} +1 -1
- package/dist/tree-builder-LIYCLUJS.mjs.map +1 -0
- package/package.json +7 -11
- package/dist/KnowledgeService-YZHS7UHY.mjs.map +0 -1
- package/dist/TagService-VX6SB3S6.mjs.map +0 -1
- package/dist/chunk-S3ZXTYZ2.mjs.map +0 -1
- package/dist/chunk-Y47QRG3M.mjs.map +0 -1
- package/dist/tree-builder-XZ4OA2TD.mjs.map +0 -1
- /package/dist/{Knowledge.schema-7KD5X7KG.mjs.map → Knowledge.schema-BHFPDLIO.mjs.map} +0 -0
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
updateIsTopSchema,
|
|
10
10
|
updateKnowledgeSchema,
|
|
11
11
|
updateSafeSchema
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-2G44ILZL.mjs";
|
|
13
13
|
import "./chunk-GWIBTASJ.mjs";
|
|
14
14
|
import "./chunk-VHBDNZOQ.mjs";
|
|
15
15
|
export {
|
|
@@ -24,4 +24,4 @@ export {
|
|
|
24
24
|
updateKnowledgeSchema,
|
|
25
25
|
updateSafeSchema
|
|
26
26
|
};
|
|
27
|
-
//# sourceMappingURL=Knowledge.schema-
|
|
27
|
+
//# sourceMappingURL=Knowledge.schema-BHFPDLIO.mjs.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
knowledge
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2G44ILZL.mjs";
|
|
4
4
|
import "./chunk-GWIBTASJ.mjs";
|
|
5
5
|
import "./chunk-VHBDNZOQ.mjs";
|
|
6
6
|
|
|
@@ -161,7 +161,7 @@ async function getKnowledgeTree(options) {
|
|
|
161
161
|
conditions.push(like(knowledge.path, `${parent.path}%`));
|
|
162
162
|
}
|
|
163
163
|
const allNodes = await db.select().from(knowledge).where(and(...conditions)).orderBy(desc(knowledge.isTop), knowledge.name).execute();
|
|
164
|
-
const { buildTree } = await import("./tree-builder-
|
|
164
|
+
const { buildTree } = await import("./tree-builder-LIYCLUJS.mjs");
|
|
165
165
|
return buildTree(allNodes, parentId);
|
|
166
166
|
}
|
|
167
167
|
async function getChildren(parentId) {
|
|
@@ -300,4 +300,4 @@ export {
|
|
|
300
300
|
updateKnowledge,
|
|
301
301
|
updateSafe
|
|
302
302
|
};
|
|
303
|
-
//# sourceMappingURL=KnowledgeService-
|
|
303
|
+
//# sourceMappingURL=KnowledgeService-JDG23Q4Z.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../service/KnowledgeService.ts","../utils/path-builder.ts"],"sourcesContent":["import { knowledge } from \"../orm/Knowledge.schema\";\nimport { eq, and, or, like, sql, desc, inArray } from \"drizzle-orm\";\nimport { buildPath, getLevel, validatePath, isDescendant } from \"../utils/path-builder\";\nimport type { Knowledge, KnowledgeSafe, InsertKnowledge } from \"../types\";\n\nlet _db: any;\n\n/**\n * 初始化 Service 的数据库实例\n */\nexport function initKnowledgeService(db: any) {\n _db = db;\n}\n\nfunction getDB() {\n if (!_db) throw new Error(\"KnowledgeService not initialized with DB\");\n return _db;\n}\n\n// ==================== CRUD 操作 ====================\n\n/**\n * 创建知识库内容\n */\nexport async function createKnowledge(data: InsertKnowledge & { userId: number }) {\n const db = getDB();\n const now = new Date();\n\n // 如果有父节点,获取父节点信息\n let parentPath = \"/\";\n let level = 0;\n\n if (data.parentId) {\n const [parent] = await db\n .select()\n .from(knowledge)\n .where(and(eq(knowledge.id, data.parentId), eq(knowledge.isDelete, 0)))\n .limit(1);\n\n if (!parent) {\n throw new Error(\"父节点不存在\");\n }\n\n parentPath = parent.path;\n level = parent.level + 1;\n }\n\n // 先插入基础数据(不含 path 和 level)\n const result = await db\n .insert(knowledge)\n .values({\n name: data.name,\n type: data.type ?? 0,\n safe: data.safe ?? 0,\n userId: data.userId,\n description: data.description,\n content: data.content,\n contentText: data.contentText,\n viewType: data.viewType,\n coverImage: data.coverImage,\n author: data.author,\n isbn: data.isbn,\n created: now,\n updated: now,\n isDelete: 0,\n isTop: 0,\n path: \"/\", // 临时值\n level: 0, // 临时值\n })\n .execute();\n\n // 获取插入的 ID\n const lastId = result.lastInsertRowid as number;\n\n // 更新 path 和 level\n const finalPath = buildPath(parentPath, lastId);\n await db\n .update(knowledge)\n .set({ path: finalPath, level })\n .where(eq(knowledge.id, lastId))\n .execute();\n\n return getKnowledgeById(lastId);\n}\n\n/**\n * 批量创建知识库内容\n */\nexport async function createKnowledgeBatch(items: Array<{ name: string; type: number }>, userId: number, parentId?: number) {\n const results = [];\n\n for (const item of items) {\n try {\n const result = await createKnowledge({ ...item, userId, parentId });\n results.push({ success: true, data: result });\n } catch (error) {\n results.push({ success: false, error: error instanceof Error ? error.message : String(error) });\n }\n }\n\n return results;\n}\n\n/**\n * 分页获取知识库列表\n */\nexport async function listKnowledge(options: {\n pageIndex: number;\n pageSize: number;\n level?: number;\n type?: number;\n safe?: number[];\n userId?: number;\n isAdmin?: boolean;\n}) {\n const db = getDB();\n const { pageIndex, pageSize, level, type, safe = [0], userId, isAdmin } = options;\n\n let conditions = [eq(knowledge.isDelete, 0)];\n\n // 层级筛选\n if (level !== undefined) {\n conditions.push(eq(knowledge.level, level));\n }\n\n // 类型筛选\n if (type !== undefined) {\n conditions.push(eq(knowledge.type, type));\n }\n\n // 权限筛选\n const safeConditions = [];\n for (const s of safe) {\n switch (s) {\n case 0: // 公开\n safeConditions.push(eq(knowledge.safe, s));\n break;\n case 1: // 登录共享\n if (userId) {\n safeConditions.push(eq(knowledge.safe, s));\n }\n break;\n case 2: // 个人私密\n if (userId) {\n safeConditions.push(\n and(eq(knowledge.safe, s), isAdmin ? sql`1=1` : eq(knowledge.userId, userId))\n );\n }\n break;\n }\n }\n\n if (safeConditions.length > 0) {\n conditions.push(or(...safeConditions));\n }\n\n const offset = (pageIndex - 1) * pageSize;\n\n const list = await db\n .select()\n .from(knowledge)\n .where(and(...conditions))\n .limit(pageSize)\n .offset(offset)\n .orderBy(desc(knowledge.isTop), desc(knowledge.created))\n .execute();\n\n const [totalResult] = await db\n .select({ count: sql<number>`count(*)` })\n .from(knowledge)\n .where(and(...conditions))\n .execute();\n\n return {\n list,\n total: totalResult.count,\n pageIndex,\n pageSize,\n };\n}\n\n/**\n * 获取知识库详情\n */\nexport async function getKnowledgeById(id: number): Promise<Knowledge | null> {\n const db = getDB();\n const [item] = await db\n .select()\n .from(knowledge)\n .where(and(eq(knowledge.id, id), eq(knowledge.isDelete, 0)))\n .limit(1);\n\n return item || null;\n}\n\n/**\n * 批量获取知识库详情\n */\nexport async function getKnowledgeByIds(ids: number[]): Promise<Knowledge[]> {\n const db = getDB();\n if (ids.length === 0) return [];\n\n return await db\n .select()\n .from(knowledge)\n .where(and(inArray(knowledge.id, ids), eq(knowledge.isDelete, 0)))\n .execute();\n}\n\n/**\n * 获取知识库目录树\n */\nexport async function getKnowledgeTree(options: {\n parentId?: number | null;\n safe?: number[];\n userId?: number;\n isAdmin?: boolean;\n}) {\n const db = getDB();\n const { parentId = null, safe = [0], userId, isAdmin } = options;\n\n let conditions = [eq(knowledge.isDelete, 0)];\n\n // 权限筛选\n const safeConditions = [];\n for (const s of safe) {\n switch (s) {\n case 0: // 公开\n safeConditions.push(eq(knowledge.safe, s));\n break;\n case 1: // 登录共享\n if (userId) {\n safeConditions.push(eq(knowledge.safe, s));\n }\n break;\n case 2: // 个人私密\n if (userId) {\n safeConditions.push(\n and(eq(knowledge.safe, s), isAdmin ? sql`1=1` : eq(knowledge.userId, userId))\n );\n }\n break;\n }\n }\n\n if (safeConditions.length > 0) {\n conditions.push(or(...safeConditions));\n }\n\n // 如果指定了 parentId,只获取该节点下的子树\n if (parentId !== null) {\n const [parent] = await db\n .select()\n .from(knowledge)\n .where(and(eq(knowledge.id, parentId), eq(knowledge.isDelete, 0)))\n .limit(1);\n\n if (!parent) return [];\n\n conditions.push(like(knowledge.path, `${parent.path}%`));\n }\n\n const allNodes = await db\n .select()\n .from(knowledge)\n .where(and(...conditions))\n .orderBy(desc(knowledge.isTop), knowledge.name)\n .execute();\n\n // 使用 tree-builder 构建树形结构\n const { buildTree } = await import(\"../utils/tree-builder\");\n return buildTree(allNodes, parentId);\n}\n\n/**\n * 获取子节点列表\n */\nexport async function getChildren(parentId: number) {\n const db = getDB();\n\n const [parent] = await db\n .select()\n .from(knowledge)\n .where(and(eq(knowledge.id, parentId), eq(knowledge.isDelete, 0)))\n .limit(1);\n\n if (!parent) {\n throw new Error(\"父节点不存在\");\n }\n\n return await db\n .select()\n .from(knowledge)\n .where(\n and(\n eq(knowledge.isDelete, 0),\n like(knowledge.path, `${parent.path}%`),\n eq(knowledge.level, parent.level + 1)\n )\n )\n .orderBy(desc(knowledge.isTop), knowledge.name)\n .execute();\n}\n\n/**\n * 更新知识库内容\n */\nexport async function updateKnowledge(id: number, data: Partial<InsertKnowledge>, userId: number) {\n const db = getDB();\n const now = new Date();\n\n const result = await db\n .update(knowledge)\n .set({\n ...(data.name !== undefined && { name: data.name }),\n ...(data.description !== undefined && { description: data.description }),\n ...(data.content !== undefined && { content: data.content }),\n ...(data.contentText !== undefined && { contentText: data.contentText }),\n ...(data.viewType !== undefined && { viewType: data.viewType }),\n ...(data.coverImage !== undefined && { coverImage: data.coverImage }),\n ...(data.author !== undefined && { author: data.author }),\n ...(data.isbn !== undefined && { isbn: data.isbn }),\n updated: now,\n })\n .where(and(eq(knowledge.id, id), eq(knowledge.userId, userId)))\n .execute();\n\n return result;\n}\n\n/**\n * 移动节点(更新整个子树的 path 和 level)\n */\nexport async function moveKnowledge(nodeId: number, newParentId: number, userId: number) {\n const db = getDB();\n\n // 1. 获取节点和新父节点信息\n const [node] = await db\n .select()\n .from(knowledge)\n .where(and(eq(knowledge.id, nodeId), eq(knowledge.isDelete, 0)))\n .limit(1);\n\n const [newParent] = await db\n .select()\n .from(knowledge)\n .where(and(eq(knowledge.id, newParentId), eq(knowledge.isDelete, 0)))\n .limit(1);\n\n if (!node || !newParent) {\n throw new Error(\"节点不存在\");\n }\n\n // 权限检查\n if (node.userId !== userId) {\n throw new Error(\"无权操作此节点\");\n }\n\n // 2. 防止循环:不能移动到自己的后代节点\n if (isDescendant(node.path, newParent.path)) {\n throw new Error(\"不能移动到自己的后代节点\");\n }\n\n const oldPath = node.path;\n const newPath = buildPath(newParent.path, nodeId);\n const levelDiff = newParent.level + 1 - node.level;\n\n // 3. 批量更新整个子树\n await db\n .update(knowledge)\n .set({\n path: sql`REPLACE(${knowledge.path}, ${oldPath}, ${newPath})`,\n level: sql`${knowledge.level} + ${levelDiff}`,\n })\n .where(or(like(knowledge.path, `${oldPath}%`), eq(knowledge.path, oldPath)))\n .execute();\n\n return getKnowledgeById(nodeId);\n}\n\n/**\n * 更新置顶状态\n */\nexport async function updateIsTop(id: number, isTop: number, userId: number) {\n const db = getDB();\n const now = new Date();\n\n await db\n .update(knowledge)\n .set({ isTop, updated: now })\n .where(and(eq(knowledge.id, id), eq(knowledge.userId, userId)))\n .execute();\n\n return getKnowledgeById(id);\n}\n\n/**\n * 更新安全等级\n */\nexport async function updateSafe(id: number, safe: KnowledgeSafe, userId: number) {\n const db = getDB();\n const now = new Date();\n\n await db\n .update(knowledge)\n .set({ safe, updated: now })\n .where(and(eq(knowledge.id, id), eq(knowledge.userId, userId)))\n .execute();\n\n return getKnowledgeById(id);\n}\n\n/**\n * 逻辑删除\n */\nexport async function deleteKnowledge(id: number, userId: number) {\n const db = getDB();\n const now = new Date();\n\n await db\n .update(knowledge)\n .set({ isDelete: 1, updated: now })\n .where(and(eq(knowledge.id, id), eq(knowledge.userId, userId)))\n .execute();\n\n return { success: true };\n}\n\n/**\n * 真实删除(管理员)\n */\nexport async function deleteKnowledgeReal(id: number) {\n const db = getDB();\n\n await db\n .delete(knowledge)\n .where(eq(knowledge.id, id))\n .execute();\n\n return { success: true };\n}\n\n/**\n * 搜索知识库内容\n */\nexport async function searchKnowledge(options: {\n keyword: string;\n pageIndex?: number;\n pageSize?: number;\n safe?: number[];\n userId?: number;\n isAdmin?: boolean;\n}) {\n const db = getDB();\n const { keyword, pageIndex = 1, pageSize = 10, safe = [0], userId, isAdmin } = options;\n\n let conditions = [\n eq(knowledge.isDelete, 0),\n or(\n like(knowledge.name, `%${keyword}%`),\n like(knowledge.description, `%${keyword}%`),\n like(knowledge.contentText, `%${keyword}%`)\n ),\n ];\n\n // 权限筛选\n const safeConditions = [];\n for (const s of safe) {\n switch (s) {\n case 0: // 公开\n safeConditions.push(eq(knowledge.safe, s));\n break;\n case 1: // 登录共享\n if (userId) {\n safeConditions.push(eq(knowledge.safe, s));\n }\n break;\n case 2: // 个人私密\n if (userId) {\n safeConditions.push(\n and(eq(knowledge.safe, s), isAdmin ? sql`1=1` : eq(knowledge.userId, userId))\n );\n }\n break;\n }\n }\n\n if (safeConditions.length > 0) {\n conditions.push(or(...safeConditions));\n }\n\n const offset = (pageIndex - 1) * pageSize;\n\n const list = await db\n .select()\n .from(knowledge)\n .where(and(...conditions))\n .limit(pageSize)\n .offset(offset)\n .orderBy(desc(knowledge.created))\n .execute();\n\n const [totalResult] = await db\n .select({ count: sql<number>`count(*)` })\n .from(knowledge)\n .where(and(...conditions))\n .execute();\n\n return {\n list,\n total: totalResult.count,\n pageIndex,\n pageSize,\n };\n}\n","/**\n * 物化路径工具函数\n */\n\n/**\n * 构建新节点路径\n * @param parentPath 父节点路径\n * @param id 新节点ID\n * @returns 新节点路径\n */\nexport function buildPath(parentPath: string, id: number): string {\n return `${parentPath}${id}/`;\n}\n\n/**\n * 从路径计算层级\n * @param path 节点路径\n * @returns 层级深度(根节点为0)\n */\nexport function getLevel(path: string): number {\n // path 格式: \"/1/3/7/\" -> 分割后 ['', '1', '3', '7', '']\n // 减2是因为前后各有一个空字符串\n const parts = path.split(\"/\").filter(Boolean);\n return parts.length - 1;\n}\n\n/**\n * 验证路径是否有效(防止循环引用)\n * @param newPath 新路径\n * @param oldPath 旧路径\n * @returns 是否有效\n */\nexport function validatePath(newPath: string, oldPath: string): boolean {\n // 不能将节点移动到自己的后代节点下\n // 如果新父节点的 path 以旧节点的 path 开头,说明是后代\n return !newPath.startsWith(oldPath);\n}\n\n/**\n * 检查是否为后代节点\n * @param ancestorPath 祖先节点路径\n * @param descendantPath 后代节点路径\n * @returns 是否为后代\n */\nexport function isDescendant(ancestorPath: string, descendantPath: string): boolean {\n return descendantPath.startsWith(ancestorPath) && ancestorPath !== descendantPath;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
knowledgeTag,
|
|
3
3
|
knowledgeTagRelation
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-SG44KRK4.mjs";
|
|
5
5
|
import "./chunk-GWIBTASJ.mjs";
|
|
6
6
|
import "./chunk-VHBDNZOQ.mjs";
|
|
7
7
|
|
|
@@ -109,7 +109,7 @@ async function getKnowledgeByTag(tagId, options) {
|
|
|
109
109
|
return { list: [], total: 0, pageIndex, pageSize };
|
|
110
110
|
}
|
|
111
111
|
const knowledgeIds = relations.map((r) => r.knowledgeId);
|
|
112
|
-
const { knowledge } = await import("./Knowledge.schema-
|
|
112
|
+
const { knowledge } = await import("./Knowledge.schema-BHFPDLIO.mjs");
|
|
113
113
|
const { eq: eq2, and: and2, or, sql, desc } = await import("drizzle-orm");
|
|
114
114
|
let conditions = [
|
|
115
115
|
eq2(knowledge.isDelete, 0),
|
|
@@ -160,4 +160,4 @@ export {
|
|
|
160
160
|
removeTagFromKnowledge,
|
|
161
161
|
updateTag
|
|
162
162
|
};
|
|
163
|
-
//# sourceMappingURL=TagService-
|
|
163
|
+
//# sourceMappingURL=TagService-YZAGBPG7.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../service/TagService.ts"],"sourcesContent":["import { knowledgeTag, knowledgeTagRelation } from \"../orm/Tag.schema\";\nimport { eq, and, inArray } from \"drizzle-orm\";\nimport type { InsertTag } from \"../types\";\n\nlet _db: any;\n\n/**\n * 初始化 Service 的数据库实例\n */\nexport function initTagService(db: any) {\n _db = db;\n}\n\nfunction getDB() {\n if (!_db) throw new Error(\"TagService not initialized with DB\");\n return _db;\n}\n\n// ==================== 标签管理 ====================\n\n/**\n * 创建标签\n */\nexport async function createTag(data: InsertTag & { userId?: number }) {\n const db = getDB();\n const now = new Date();\n\n const result = await db\n .insert(knowledgeTag)\n .values({\n name: data.name,\n color: data.color,\n userId: data.userId,\n created: now,\n })\n .execute();\n\n const lastId = result.lastInsertRowid as number;\n return getTagById(lastId);\n}\n\n/**\n * 获取标签详情\n */\nexport async function getTagById(id: number) {\n const db = getDB();\n const [tag] = await db\n .select()\n .from(knowledgeTag)\n .where(eq(knowledgeTag.id, id))\n .limit(1);\n\n return tag || null;\n}\n\n/**\n * 获取标签列表\n */\nexport async function listTags(userId?: number) {\n const db = getDB();\n\n let conditions = [];\n if (userId !== undefined) {\n conditions.push(eq(knowledgeTag.userId, userId));\n }\n\n return await db\n .select()\n .from(knowledgeTag)\n .where(conditions.length > 0 ? and(...conditions) : undefined)\n .orderBy(knowledgeTag.name)\n .execute();\n}\n\n/**\n * 更新标签\n */\nexport async function updateTag(id: number, data: Partial<InsertTag>, userId: number) {\n const db = getDB();\n\n // 检查权限\n const [tag] = await db\n .select()\n .from(knowledgeTag)\n .where(and(eq(knowledgeTag.id, id), eq(knowledgeTag.userId, userId)))\n .limit(1);\n\n if (!tag) {\n throw new Error(\"标签不存在或无权操作\");\n }\n\n await db\n .update(knowledgeTag)\n .set({\n ...(data.name !== undefined && { name: data.name }),\n ...(data.color !== undefined && { color: data.color }),\n })\n .where(eq(knowledgeTag.id, id))\n .execute();\n\n return getTagById(id);\n}\n\n/**\n * 删除标签\n */\nexport async function deleteTag(id: number, userId: number) {\n const db = getDB();\n\n // 检查权限\n const [tag] = await db\n .select()\n .from(knowledgeTag)\n .where(and(eq(knowledgeTag.id, id), eq(knowledgeTag.userId, userId)))\n .limit(1);\n\n if (!tag) {\n throw new Error(\"标签不存在或无权操作\");\n }\n\n // 删除标签关联\n await db\n .delete(knowledgeTagRelation)\n .where(eq(knowledgeTagRelation.tagId, id))\n .execute();\n\n // 删除标签\n await db\n .delete(knowledgeTag)\n .where(eq(knowledgeTag.id, id))\n .execute();\n\n return { success: true };\n}\n\n// ==================== 标签关联 ====================\n\n/**\n * 为知识库内容添加标签\n */\nexport async function addTagToKnowledge(knowledgeId: number, tagId: number, userId: number) {\n const db = getDB();\n\n // 检查标签是否存在\n const [tag] = await db\n .select()\n .from(knowledgeTag)\n .where(eq(knowledgeTag.id, tagId))\n .limit(1);\n\n if (!tag) {\n throw new Error(\"标签不存在\");\n }\n\n // 检查是否已存在关联\n const [existing] = await db\n .select()\n .from(knowledgeTagRelation)\n .where(\n and(\n eq(knowledgeTagRelation.knowledgeId, knowledgeId),\n eq(knowledgeTagRelation.tagId, tagId)\n )\n )\n .limit(1);\n\n if (existing) {\n return { success: true, message: \"标签已存在\" };\n }\n\n // 创建关联\n await db\n .insert(knowledgeTagRelation)\n .values({\n knowledgeId,\n tagId,\n })\n .execute();\n\n return { success: true };\n}\n\n/**\n * 移除知识库内容的标签\n */\nexport async function removeTagFromKnowledge(knowledgeId: number, tagId: number) {\n const db = getDB();\n\n await db\n .delete(knowledgeTagRelation)\n .where(\n and(\n eq(knowledgeTagRelation.knowledgeId, knowledgeId),\n eq(knowledgeTagRelation.tagId, tagId)\n )\n )\n .execute();\n\n return { success: true };\n}\n\n/**\n * 获取知识库内容的标签列表\n */\nexport async function getKnowledgeTags(knowledgeId: number) {\n const db = getDB();\n\n return await db\n .select({\n id: knowledgeTag.id,\n name: knowledgeTag.name,\n color: knowledgeTag.color,\n })\n .from(knowledgeTagRelation)\n .innerJoin(knowledgeTag, eq(knowledgeTagRelation.tagId, knowledgeTag.id))\n .where(eq(knowledgeTagRelation.knowledgeId, knowledgeId))\n .execute();\n}\n\n/**\n * 按标签查询知识库内容\n */\nexport async function getKnowledgeByTag(tagId: number, options: {\n pageIndex?: number;\n pageSize?: number;\n safe?: number[];\n userId?: number;\n isAdmin?: boolean;\n}) {\n const db = getDB();\n const { pageIndex = 1, pageSize = 10, safe = [0], userId, isAdmin } = options;\n\n // 获取带有该标签的知识库 ID 列表\n const relations = await db\n .select()\n .from(knowledgeTagRelation)\n .where(eq(knowledgeTagRelation.tagId, tagId))\n .execute();\n\n if (relations.length === 0) {\n return { list: [], total: 0, pageIndex, pageSize };\n }\n\n const knowledgeIds = relations.map(r => r.knowledgeId);\n\n // 导入 knowledge 表\n const { knowledge } = await import(\"../orm/Knowledge.schema\");\n const { eq, and, or, sql, desc } = await import(\"drizzle-orm\");\n\n let conditions = [\n eq(knowledge.isDelete, 0),\n inArray(knowledge.id, knowledgeIds),\n ];\n\n // 权限筛选\n const safeConditions = [];\n for (const s of safe) {\n switch (s) {\n case 0: // 公开\n safeConditions.push(eq(knowledge.safe, s));\n break;\n case 1: // 登录共享\n if (userId) {\n safeConditions.push(eq(knowledge.safe, s));\n }\n break;\n case 2: // 个人私密\n if (userId) {\n safeConditions.push(\n and(eq(knowledge.safe, s), isAdmin ? sql`1=1` : eq(knowledge.userId, userId))\n );\n }\n break;\n }\n }\n\n if (safeConditions.length > 0) {\n conditions.push(or(...safeConditions));\n }\n\n const offset = (pageIndex - 1) * pageSize;\n\n const list = await db\n .select()\n .from(knowledge)\n .where(and(...conditions))\n .limit(pageSize)\n .offset(offset)\n .orderBy(desc(knowledge.created))\n .execute();\n\n const [totalResult] = await db\n .select({ count: sql<number>`count(*)` })\n .from(knowledge)\n .where(and(...conditions))\n .execute();\n\n return {\n list,\n total: totalResult.count,\n pageIndex,\n pageSize,\n };\n}\n"],"mappings":"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","names":["eq","and"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../orm/Knowledge.schema.ts"],"sourcesContent":["import { sqliteTable, text, integer } from \"drizzle-orm/sqlite-core\";\nimport { createInsertSchema, createSelectSchema } from \"drizzle-zod\";\nimport { z } from \"zod\";\n\n/**\n * 知识库主表\n */\nexport const knowledge = sqliteTable(\"knowledge\", {\n id: integer(\"id\").primaryKey({ autoIncrement: true }),\n name: text(\"name\").notNull(),\n path: text(\"path\").notNull(),\n level: integer(\"level\").notNull().default(0),\n type: integer(\"type\").notNull(), // 0:文件夹 1:笔记 2:书籍\n safe: integer(\"safe\").notNull().default(0),\n userId: integer(\"user_id\").notNull(),\n // 书籍特有字段\n coverImage: text(\"cover_image\"),\n author: text(\"author\"),\n isbn: text(\"isbn\"),\n description: text(\"description\"),\n created: integer(\"created\", { mode: \"timestamp\" }),\n updated: integer(\"updated\", { mode: \"timestamp\" }),\n isDelete: integer(\"is_delete\").notNull().default(0),\n isTop: integer(\"is_top\").notNull().default(0),\n content: text(\"content\"),\n contentText: text(\"content_text\"),\n viewType: integer(\"view_type\").default(0),\n});\n\n// ==================== Zod Schemas ====================\n\n/**\n * 创建知识库内容验证\n */\nexport const createKnowledgeSchema = createInsertSchema(knowledge as any, {\n name: z.string().min(1, \"名称不能为空\").max(255, \"名称不能超过255字符\") as any,\n type: z.coerce.number().int().min(0).max(2) as any,\n safe: z.coerce.number().int().min(0).max(2).optional() as any,\n}).pick({\n name: true,\n type: true,\n safe: true,\n description: true,\n content: true,\n contentText: true,\n viewType: true,\n coverImage: true,\n author: true,\n isbn: true,\n});\n\n/**\n * 批量创建验证\n */\nexport const batchCreateKnowledgeSchema = z.object({\n parentId: z.number().optional(),\n items: z.array(z.object({\n name: z.string().min(1, \"名称不能为空\").max(255),\n type: z.coerce.number().int().min(0).max(2),\n })).min(1, \"至少需要一个项目\"),\n});\n\n/**\n * 批量获取详情验证\n */\nexport const batchDetailKnowledgeSchema = z.object({\n ids: z.array(z.number().int().positive()).min(1, \"至少需要一个ID\"),\n});\n\n/**\n * 更新知识库内容验证\n */\nexport const updateKnowledgeSchema = createInsertSchema(knowledge as any)\n .partial()\n .extend({\n id: z.number({ required_error: \"ID不能为空\" }),\n });\n\n/**\n * 列表查询验证\n */\nexport const listKnowledgeSchema = z.object({\n pageIndex: z.coerce.number().int().positive().optional().default(1),\n pageSize: z.coerce.number().int().positive().optional().default(10),\n level: z.coerce.number().int().min(0).optional(),\n type: z.coerce.number().int().min(0).max(2).optional(),\n safe: z.array(z.coerce.number().int().min(0).max(2)).optional(),\n});\n\n/**\n * 搜索验证\n */\nexport const searchKnowledgeSchema = z.object({\n keyword: z.string().min(1, \"关键词不能为空\"),\n pageIndex: z.coerce.number().int().positive().optional().default(1),\n pageSize: z.coerce.number().int().positive().optional().default(10),\n});\n\n/**\n * 移动节点验证\n */\nexport const moveKnowledgeSchema = z.object({\n newParentId: z.number({ required_error: \"新父节点ID不能为空\" }),\n});\n\n/**\n * 更新置顶状态验证\n */\nexport const updateIsTopSchema = z.object({\n isTop: z.coerce.number().int().min(0).max(1),\n});\n\n/**\n * 更新安全等级验证\n */\nexport const updateSafeSchema = z.object({\n safe: z.coerce.number().int().min(0).max(2),\n});\n"],"mappings":";;;;;AAAA,SAAS,aAAa,MAAM,eAAe;AAE3C,SAAS,SAAS;AAKX,IAAM,YAAY,YAAY,aAAa;AAAA,EAChD,IAAI,QAAQ,IAAI,EAAE,WAAW,EAAE,eAAe,KAAK,CAAC;AAAA,EACpD,MAAM,KAAK,MAAM,EAAE,QAAQ;AAAA,EAC3B,MAAM,KAAK,MAAM,EAAE,QAAQ;AAAA,EAC3B,OAAO,QAAQ,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC;AAAA,EAC3C,MAAM,QAAQ,MAAM,EAAE,QAAQ;AAAA;AAAA,EAC9B,MAAM,QAAQ,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC;AAAA,EACzC,QAAQ,QAAQ,SAAS,EAAE,QAAQ;AAAA;AAAA,EAEnC,YAAY,KAAK,aAAa;AAAA,EAC9B,QAAQ,KAAK,QAAQ;AAAA,EACrB,MAAM,KAAK,MAAM;AAAA,EACjB,aAAa,KAAK,aAAa;AAAA,EAC/B,SAAS,QAAQ,WAAW,EAAE,MAAM,YAAY,CAAC;AAAA,EACjD,SAAS,QAAQ,WAAW,EAAE,MAAM,YAAY,CAAC;AAAA,EACjD,UAAU,QAAQ,WAAW,EAAE,QAAQ,EAAE,QAAQ,CAAC;AAAA,EAClD,OAAO,QAAQ,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC;AAAA,EAC5C,SAAS,KAAK,SAAS;AAAA,EACvB,aAAa,KAAK,cAAc;AAAA,EAChC,UAAU,QAAQ,WAAW,EAAE,QAAQ,CAAC;AAC1C,CAAC;AAOM,IAAM,wBAAwB,EAAmB,WAAkB;AAAA,EACxE,MAAM,EAAE,OAAO,EAAE,IAAI,GAAG,sCAAQ,EAAE,IAAI,KAAK,qDAAa;AAAA,EACxD,MAAM,EAAE,OAAO,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC;AAAA,EAC1C,MAAM,EAAE,OAAO,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AACvD,CAAC,EAAE,KAAK;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,aAAa;AAAA,EACb,SAAS;AAAA,EACT,aAAa;AAAA,EACb,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,MAAM;AACR,CAAC;AAKM,IAAM,6BAA6B,EAAE,OAAO;AAAA,EACjD,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,OAAO,EAAE,MAAM,EAAE,OAAO;AAAA,IACtB,MAAM,EAAE,OAAO,EAAE,IAAI,GAAG,sCAAQ,EAAE,IAAI,GAAG;AAAA,IACzC,MAAM,EAAE,OAAO,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC;AAAA,EAC5C,CAAC,CAAC,EAAE,IAAI,GAAG,kDAAU;AACvB,CAAC;AAKM,IAAM,6BAA6B,EAAE,OAAO;AAAA,EACjD,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,IAAI,GAAG,wCAAU;AAC7D,CAAC;AAKM,IAAM,wBAAwB,EAAmB,SAAgB,EACrE,QAAQ,EACR,OAAO;AAAA,EACN,IAAI,EAAE,OAAO,EAAE,gBAAgB,6BAAS,CAAC;AAC3C,CAAC;AAKI,IAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,WAAW,EAAE,OAAO,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC;AAAA,EAClE,UAAU,EAAE,OAAO,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE;AAAA,EAClE,OAAO,EAAE,OAAO,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EAC/C,MAAM,EAAE,OAAO,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EACrD,MAAM,EAAE,MAAM,EAAE,OAAO,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,SAAS;AAChE,CAAC;AAKM,IAAM,wBAAwB,EAAE,OAAO;AAAA,EAC5C,SAAS,EAAE,OAAO,EAAE,IAAI,GAAG,4CAAS;AAAA,EACpC,WAAW,EAAE,OAAO,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,CAAC;AAAA,EAClE,UAAU,EAAE,OAAO,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE;AACpE,CAAC;AAKM,IAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,aAAa,EAAE,OAAO,EAAE,gBAAgB,qDAAa,CAAC;AACxD,CAAC;AAKM,IAAM,oBAAoB,EAAE,OAAO;AAAA,EACxC,OAAO,EAAE,OAAO,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC;AAC7C,CAAC;AAKM,IAAM,mBAAmB,EAAE,OAAO;AAAA,EACvC,MAAM,EAAE,OAAO,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC;AAC5C,CAAC;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../orm/Tag.schema.ts"],"sourcesContent":["import { sqliteTable, text, integer } from \"drizzle-orm/sqlite-core\";\nimport { createInsertSchema, createSelectSchema } from \"drizzle-zod\";\nimport { z } from \"zod\";\n\n/**\n * 标签表\n */\nexport const knowledgeTag = sqliteTable(\"knowledge_tag\", {\n id: integer(\"id\").primaryKey({ autoIncrement: true }),\n name: text(\"name\").notNull().unique(),\n color: text(\"color\"),\n userId: integer(\"user_id\"),\n created: integer(\"created\", { mode: \"timestamp\" }),\n});\n\n/**\n * 标签关联表(多对多)\n */\nexport const knowledgeTagRelation = sqliteTable(\"knowledge_tag_relation\", {\n knowledgeId: integer(\"knowledge_id\").notNull(),\n tagId: integer(\"tag_id\").notNull(),\n});\n\n// ==================== Zod Schemas ====================\n\n/**\n * 创建标签验证\n */\nexport const createTagSchema = createInsertSchema(knowledgeTag as any, {\n name: z.string().min(1, \"标签名不能为空\").max(50, \"标签名不能超过50字符\") as any,\n color: z.string().regex(/^#[0-9A-Fa-f]{6}$/, \"颜色必须是十六进制格式\").optional() as any,\n}).pick({\n name: true,\n color: true,\n});\n\n/**\n * 更新标签验证\n */\nexport const updateTagSchema = createInsertSchema(knowledgeTag as any)\n .partial()\n .extend({\n id: z.number({ required_error: \"标签ID不能为空\" }),\n });\n\n/**\n * 添加标签关联验证\n */\nexport const addTagRelationSchema = z.object({\n tagId: z.number({ required_error: \"标签ID不能为空\" }),\n});\n"],"mappings":";;;;;AAAA,SAAS,aAAa,MAAM,eAAe;AAE3C,SAAS,SAAS;AAKX,IAAM,eAAe,YAAY,iBAAiB;AAAA,EACvD,IAAI,QAAQ,IAAI,EAAE,WAAW,EAAE,eAAe,KAAK,CAAC;AAAA,EACpD,MAAM,KAAK,MAAM,EAAE,QAAQ,EAAE,OAAO;AAAA,EACpC,OAAO,KAAK,OAAO;AAAA,EACnB,QAAQ,QAAQ,SAAS;AAAA,EACzB,SAAS,QAAQ,WAAW,EAAE,MAAM,YAAY,CAAC;AACnD,CAAC;AAKM,IAAM,uBAAuB,YAAY,0BAA0B;AAAA,EACxE,aAAa,QAAQ,cAAc,EAAE,QAAQ;AAAA,EAC7C,OAAO,QAAQ,QAAQ,EAAE,QAAQ;AACnC,CAAC;AAOM,IAAM,kBAAkB,EAAmB,cAAqB;AAAA,EACrE,MAAM,EAAE,OAAO,EAAE,IAAI,GAAG,4CAAS,EAAE,IAAI,IAAI,0DAAa;AAAA,EACxD,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,oEAAa,EAAE,SAAS;AACvE,CAAC,EAAE,KAAK;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACT,CAAC;AAKM,IAAM,kBAAkB,EAAmB,YAAmB,EAClE,QAAQ,EACR,OAAO;AAAA,EACN,IAAI,EAAE,OAAO,EAAE,gBAAgB,yCAAW,CAAC;AAC7C,CAAC;AAKI,IAAM,uBAAuB,EAAE,OAAO;AAAA,EAC3C,OAAO,EAAE,OAAO,EAAE,gBAAgB,yCAAW,CAAC;AAChD,CAAC;","names":[]}
|
package/dist/index.d.mts
CHANGED
|
@@ -3,14 +3,8 @@ import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
|
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
|
|
5
5
|
interface MindBaseAppOptions {
|
|
6
|
-
/**
|
|
7
|
-
|
|
8
|
-
* - normal: 正常启动服务
|
|
9
|
-
* - sync: 同步数据库 Schema(仅收集)
|
|
10
|
-
* - migrate: 执行数据库迁移
|
|
11
|
-
* @default "normal"
|
|
12
|
-
*/
|
|
13
|
-
mode?: "normal" | "sync" | "migrate";
|
|
6
|
+
/** 服务监听主机名 @default 127.0.0.1 */
|
|
7
|
+
host?: string;
|
|
14
8
|
/** 服务监听端口 @default 3000 */
|
|
15
9
|
port?: number;
|
|
16
10
|
/** 是否启用请求日志 @default true */
|
|
@@ -92,7 +86,7 @@ declare const knowledge: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
92
86
|
baseColumn: never;
|
|
93
87
|
identity: undefined;
|
|
94
88
|
generated: undefined;
|
|
95
|
-
},
|
|
89
|
+
}, {}, {}>;
|
|
96
90
|
name: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
97
91
|
name: "name";
|
|
98
92
|
tableName: "knowledge";
|
|
@@ -109,7 +103,9 @@ declare const knowledge: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
109
103
|
baseColumn: never;
|
|
110
104
|
identity: undefined;
|
|
111
105
|
generated: undefined;
|
|
112
|
-
},
|
|
106
|
+
}, {}, {
|
|
107
|
+
length: number;
|
|
108
|
+
}>;
|
|
113
109
|
path: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
114
110
|
name: "path";
|
|
115
111
|
tableName: "knowledge";
|
|
@@ -126,7 +122,9 @@ declare const knowledge: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
126
122
|
baseColumn: never;
|
|
127
123
|
identity: undefined;
|
|
128
124
|
generated: undefined;
|
|
129
|
-
},
|
|
125
|
+
}, {}, {
|
|
126
|
+
length: number;
|
|
127
|
+
}>;
|
|
130
128
|
level: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
131
129
|
name: "level";
|
|
132
130
|
tableName: "knowledge";
|
|
@@ -143,7 +141,7 @@ declare const knowledge: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
143
141
|
baseColumn: never;
|
|
144
142
|
identity: undefined;
|
|
145
143
|
generated: undefined;
|
|
146
|
-
},
|
|
144
|
+
}, {}, {}>;
|
|
147
145
|
type: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
148
146
|
name: "type";
|
|
149
147
|
tableName: "knowledge";
|
|
@@ -160,7 +158,7 @@ declare const knowledge: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
160
158
|
baseColumn: never;
|
|
161
159
|
identity: undefined;
|
|
162
160
|
generated: undefined;
|
|
163
|
-
},
|
|
161
|
+
}, {}, {}>;
|
|
164
162
|
safe: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
165
163
|
name: "safe";
|
|
166
164
|
tableName: "knowledge";
|
|
@@ -177,7 +175,7 @@ declare const knowledge: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
177
175
|
baseColumn: never;
|
|
178
176
|
identity: undefined;
|
|
179
177
|
generated: undefined;
|
|
180
|
-
},
|
|
178
|
+
}, {}, {}>;
|
|
181
179
|
userId: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
182
180
|
name: "user_id";
|
|
183
181
|
tableName: "knowledge";
|
|
@@ -194,7 +192,7 @@ declare const knowledge: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
194
192
|
baseColumn: never;
|
|
195
193
|
identity: undefined;
|
|
196
194
|
generated: undefined;
|
|
197
|
-
},
|
|
195
|
+
}, {}, {}>;
|
|
198
196
|
coverImage: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
199
197
|
name: "cover_image";
|
|
200
198
|
tableName: "knowledge";
|
|
@@ -211,7 +209,9 @@ declare const knowledge: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
211
209
|
baseColumn: never;
|
|
212
210
|
identity: undefined;
|
|
213
211
|
generated: undefined;
|
|
214
|
-
},
|
|
212
|
+
}, {}, {
|
|
213
|
+
length: number;
|
|
214
|
+
}>;
|
|
215
215
|
author: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
216
216
|
name: "author";
|
|
217
217
|
tableName: "knowledge";
|
|
@@ -228,7 +228,9 @@ declare const knowledge: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
228
228
|
baseColumn: never;
|
|
229
229
|
identity: undefined;
|
|
230
230
|
generated: undefined;
|
|
231
|
-
},
|
|
231
|
+
}, {}, {
|
|
232
|
+
length: number;
|
|
233
|
+
}>;
|
|
232
234
|
isbn: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
233
235
|
name: "isbn";
|
|
234
236
|
tableName: "knowledge";
|
|
@@ -245,7 +247,9 @@ declare const knowledge: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
245
247
|
baseColumn: never;
|
|
246
248
|
identity: undefined;
|
|
247
249
|
generated: undefined;
|
|
248
|
-
},
|
|
250
|
+
}, {}, {
|
|
251
|
+
length: number;
|
|
252
|
+
}>;
|
|
249
253
|
description: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
250
254
|
name: "description";
|
|
251
255
|
tableName: "knowledge";
|
|
@@ -262,7 +266,9 @@ declare const knowledge: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
262
266
|
baseColumn: never;
|
|
263
267
|
identity: undefined;
|
|
264
268
|
generated: undefined;
|
|
265
|
-
},
|
|
269
|
+
}, {}, {
|
|
270
|
+
length: number;
|
|
271
|
+
}>;
|
|
266
272
|
created: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
267
273
|
name: "created";
|
|
268
274
|
tableName: "knowledge";
|
|
@@ -279,7 +285,7 @@ declare const knowledge: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
279
285
|
baseColumn: never;
|
|
280
286
|
identity: undefined;
|
|
281
287
|
generated: undefined;
|
|
282
|
-
},
|
|
288
|
+
}, {}, {}>;
|
|
283
289
|
updated: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
284
290
|
name: "updated";
|
|
285
291
|
tableName: "knowledge";
|
|
@@ -296,7 +302,7 @@ declare const knowledge: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
296
302
|
baseColumn: never;
|
|
297
303
|
identity: undefined;
|
|
298
304
|
generated: undefined;
|
|
299
|
-
},
|
|
305
|
+
}, {}, {}>;
|
|
300
306
|
isDelete: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
301
307
|
name: "is_delete";
|
|
302
308
|
tableName: "knowledge";
|
|
@@ -313,7 +319,7 @@ declare const knowledge: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
313
319
|
baseColumn: never;
|
|
314
320
|
identity: undefined;
|
|
315
321
|
generated: undefined;
|
|
316
|
-
},
|
|
322
|
+
}, {}, {}>;
|
|
317
323
|
isTop: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
318
324
|
name: "is_top";
|
|
319
325
|
tableName: "knowledge";
|
|
@@ -330,7 +336,7 @@ declare const knowledge: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
330
336
|
baseColumn: never;
|
|
331
337
|
identity: undefined;
|
|
332
338
|
generated: undefined;
|
|
333
|
-
},
|
|
339
|
+
}, {}, {}>;
|
|
334
340
|
content: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
335
341
|
name: "content";
|
|
336
342
|
tableName: "knowledge";
|
|
@@ -347,7 +353,9 @@ declare const knowledge: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
347
353
|
baseColumn: never;
|
|
348
354
|
identity: undefined;
|
|
349
355
|
generated: undefined;
|
|
350
|
-
},
|
|
356
|
+
}, {}, {
|
|
357
|
+
length: number;
|
|
358
|
+
}>;
|
|
351
359
|
contentText: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
352
360
|
name: "content_text";
|
|
353
361
|
tableName: "knowledge";
|
|
@@ -364,7 +372,9 @@ declare const knowledge: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
364
372
|
baseColumn: never;
|
|
365
373
|
identity: undefined;
|
|
366
374
|
generated: undefined;
|
|
367
|
-
},
|
|
375
|
+
}, {}, {
|
|
376
|
+
length: number;
|
|
377
|
+
}>;
|
|
368
378
|
viewType: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
369
379
|
name: "view_type";
|
|
370
380
|
tableName: "knowledge";
|
|
@@ -381,7 +391,7 @@ declare const knowledge: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
381
391
|
baseColumn: never;
|
|
382
392
|
identity: undefined;
|
|
383
393
|
generated: undefined;
|
|
384
|
-
},
|
|
394
|
+
}, {}, {}>;
|
|
385
395
|
};
|
|
386
396
|
dialect: "sqlite";
|
|
387
397
|
}>;
|
|
@@ -3991,7 +4001,7 @@ declare const knowledgeTag: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
3991
4001
|
baseColumn: never;
|
|
3992
4002
|
identity: undefined;
|
|
3993
4003
|
generated: undefined;
|
|
3994
|
-
},
|
|
4004
|
+
}, {}, {}>;
|
|
3995
4005
|
name: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
3996
4006
|
name: "name";
|
|
3997
4007
|
tableName: "knowledge_tag";
|
|
@@ -4008,7 +4018,9 @@ declare const knowledgeTag: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
4008
4018
|
baseColumn: never;
|
|
4009
4019
|
identity: undefined;
|
|
4010
4020
|
generated: undefined;
|
|
4011
|
-
},
|
|
4021
|
+
}, {}, {
|
|
4022
|
+
length: number;
|
|
4023
|
+
}>;
|
|
4012
4024
|
color: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
4013
4025
|
name: "color";
|
|
4014
4026
|
tableName: "knowledge_tag";
|
|
@@ -4025,7 +4037,9 @@ declare const knowledgeTag: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
4025
4037
|
baseColumn: never;
|
|
4026
4038
|
identity: undefined;
|
|
4027
4039
|
generated: undefined;
|
|
4028
|
-
},
|
|
4040
|
+
}, {}, {
|
|
4041
|
+
length: number;
|
|
4042
|
+
}>;
|
|
4029
4043
|
userId: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
4030
4044
|
name: "user_id";
|
|
4031
4045
|
tableName: "knowledge_tag";
|
|
@@ -4042,7 +4056,7 @@ declare const knowledgeTag: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
4042
4056
|
baseColumn: never;
|
|
4043
4057
|
identity: undefined;
|
|
4044
4058
|
generated: undefined;
|
|
4045
|
-
},
|
|
4059
|
+
}, {}, {}>;
|
|
4046
4060
|
created: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
4047
4061
|
name: "created";
|
|
4048
4062
|
tableName: "knowledge_tag";
|
|
@@ -4059,7 +4073,7 @@ declare const knowledgeTag: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
4059
4073
|
baseColumn: never;
|
|
4060
4074
|
identity: undefined;
|
|
4061
4075
|
generated: undefined;
|
|
4062
|
-
},
|
|
4076
|
+
}, {}, {}>;
|
|
4063
4077
|
};
|
|
4064
4078
|
dialect: "sqlite";
|
|
4065
4079
|
}>;
|
|
@@ -4086,7 +4100,7 @@ declare const knowledgeTagRelation: drizzle_orm_sqlite_core.SQLiteTableWithColum
|
|
|
4086
4100
|
baseColumn: never;
|
|
4087
4101
|
identity: undefined;
|
|
4088
4102
|
generated: undefined;
|
|
4089
|
-
},
|
|
4103
|
+
}, {}, {}>;
|
|
4090
4104
|
tagId: drizzle_orm_sqlite_core.SQLiteColumn<{
|
|
4091
4105
|
name: "tag_id";
|
|
4092
4106
|
tableName: "knowledge_tag_relation";
|
|
@@ -4103,7 +4117,7 @@ declare const knowledgeTagRelation: drizzle_orm_sqlite_core.SQLiteTableWithColum
|
|
|
4103
4117
|
baseColumn: never;
|
|
4104
4118
|
identity: undefined;
|
|
4105
4119
|
generated: undefined;
|
|
4106
|
-
},
|
|
4120
|
+
}, {}, {}>;
|
|
4107
4121
|
};
|
|
4108
4122
|
dialect: "sqlite";
|
|
4109
4123
|
}>;
|
package/dist/index.mjs
CHANGED
|
@@ -9,14 +9,14 @@ import {
|
|
|
9
9
|
updateIsTopSchema,
|
|
10
10
|
updateKnowledgeSchema,
|
|
11
11
|
updateSafeSchema
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-2G44ILZL.mjs";
|
|
13
13
|
import {
|
|
14
14
|
addTagRelationSchema,
|
|
15
15
|
createTagSchema,
|
|
16
16
|
knowledgeTag,
|
|
17
17
|
knowledgeTagRelation,
|
|
18
18
|
updateTagSchema
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-SG44KRK4.mjs";
|
|
20
20
|
import "./chunk-GWIBTASJ.mjs";
|
|
21
21
|
import {
|
|
22
22
|
__filename
|
|
@@ -28,8 +28,8 @@ import { logger } from "@mindbase/express-common";
|
|
|
28
28
|
var KnowledgeModule_default = createModule(async (app) => {
|
|
29
29
|
const db = app.getDB();
|
|
30
30
|
logger.info("[KnowledgeModule] \u521D\u59CB\u5316 knowledge \u6A21\u5757");
|
|
31
|
-
const { initKnowledgeService } = await import("./KnowledgeService-
|
|
32
|
-
const { initTagService } = await import("./TagService-
|
|
31
|
+
const { initKnowledgeService } = await import("./KnowledgeService-JDG23Q4Z.mjs");
|
|
32
|
+
const { initTagService } = await import("./TagService-YZAGBPG7.mjs");
|
|
33
33
|
initKnowledgeService(db);
|
|
34
34
|
initTagService(db);
|
|
35
35
|
logger.info("[KnowledgeModule] \u6A21\u5757\u52A0\u8F7D\u5B8C\u6210");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../utils/tree-builder.ts"],"sourcesContent":["import type { KnowledgeTreeNode, Knowledge } from \"../types\";\n\n/**\n * 将扁平数组转换为树形结构\n * @param nodes 扁平节点数组\n * @param parentId 父节点ID(可选,用于构建子树)\n * @returns 树形结构\n */\nexport function buildTree(\n nodes: Knowledge[],\n parentId: number | null = null\n): KnowledgeTreeNode[] {\n // 按 isTop 降序、created 降序排序\n const sortedNodes = [...nodes].sort((a, b) => {\n if (a.isTop !== b.isTop) {\n return b.isTop - a.isTop;\n }\n return b.created.getTime() - a.created.getTime();\n });\n\n // 如果指定了 parentId,先找到该节点\n if (parentId !== null) {\n const parent = sortedNodes.find(n => n.id === parentId);\n if (!parent) return [];\n\n // 查找该节点的直接子节点\n const children = sortedNodes.filter(n =>\n n.path.startsWith(parent.path) &&\n n.level === parent.level + 1\n );\n\n return children.map(child => buildNodeTree(child, sortedNodes));\n }\n\n // 否则返回根节点(level=0)的树\n const rootNodes = sortedNodes.filter(n => n.level === 0);\n return rootNodes.map(node => buildNodeTree(node, sortedNodes));\n}\n\n/**\n * 递归构建节点树\n */\nfunction buildNodeTree(node: Knowledge, allNodes: Knowledge[]): KnowledgeTreeNode {\n const treeNode: KnowledgeTreeNode = { ...node };\n\n // 查找直接子节点\n const children = allNodes.filter(n =>\n n.path.startsWith(node.path) &&\n n.level === node.level + 1\n );\n\n if (children.length > 0) {\n treeNode.children = children.map(child => buildNodeTree(child, allNodes));\n }\n\n return treeNode;\n}\n"],"mappings":";;;AAQO,SAAS,UACd,OACA,WAA0B,MACL;AAErB,QAAM,cAAc,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM;AAC5C,QAAI,EAAE,UAAU,EAAE,OAAO;AACvB,aAAO,EAAE,QAAQ,EAAE;AAAA,IACrB;AACA,WAAO,EAAE,QAAQ,QAAQ,IAAI,EAAE,QAAQ,QAAQ;AAAA,EACjD,CAAC;AAGD,MAAI,aAAa,MAAM;AACrB,UAAM,SAAS,YAAY,KAAK,OAAK,EAAE,OAAO,QAAQ;AACtD,QAAI,CAAC,OAAQ,QAAO,CAAC;AAGrB,UAAM,WAAW,YAAY;AAAA,MAAO,OAClC,EAAE,KAAK,WAAW,OAAO,IAAI,KAC7B,EAAE,UAAU,OAAO,QAAQ;AAAA,IAC7B;AAEA,WAAO,SAAS,IAAI,WAAS,cAAc,OAAO,WAAW,CAAC;AAAA,EAChE;AAGA,QAAM,YAAY,YAAY,OAAO,OAAK,EAAE,UAAU,CAAC;AACvD,SAAO,UAAU,IAAI,UAAQ,cAAc,MAAM,WAAW,CAAC;AAC/D;AAKA,SAAS,cAAc,MAAiB,UAA0C;AAChF,QAAM,WAA8B,EAAE,GAAG,KAAK;AAG9C,QAAM,WAAW,SAAS;AAAA,IAAO,OAC/B,EAAE,KAAK,WAAW,KAAK,IAAI,KAC3B,EAAE,UAAU,KAAK,QAAQ;AAAA,EAC3B;AAEA,MAAI,SAAS,SAAS,GAAG;AACvB,aAAS,WAAW,SAAS,IAAI,WAAS,cAAc,OAAO,QAAQ,CAAC;AAAA,EAC1E;AAEA,SAAO;AACT;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mindbase/express-knowledge",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"main": "./dist/index.js",
|
|
5
|
-
"types": "./dist/index.d.ts",
|
|
3
|
+
"version": "1.0.4",
|
|
6
4
|
"exports": {
|
|
7
5
|
".": {
|
|
8
6
|
"development": "./index.ts",
|
|
9
|
-
"
|
|
10
|
-
"
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"import": "./dist/index.mjs"
|
|
11
9
|
}
|
|
12
10
|
},
|
|
13
11
|
"files": [
|
|
@@ -17,11 +15,9 @@
|
|
|
17
15
|
"node": ">=20.0.0"
|
|
18
16
|
},
|
|
19
17
|
"peerDependencies": {
|
|
20
|
-
"@mindbase/express-auth": "
|
|
21
|
-
"@mindbase/express-common": "
|
|
22
|
-
|
|
23
|
-
"dependencies": {
|
|
24
|
-
"drizzle-orm": "^0.36.0",
|
|
18
|
+
"@mindbase/express-auth": "^1.0.0",
|
|
19
|
+
"@mindbase/express-common": "^1.0.0",
|
|
20
|
+
"drizzle-orm": "^0.44.7",
|
|
25
21
|
"zod": "^3.24.0"
|
|
26
22
|
},
|
|
27
23
|
"devDependencies": {
|
|
@@ -34,4 +30,4 @@
|
|
|
34
30
|
"publishConfig": {
|
|
35
31
|
"access": "public"
|
|
36
32
|
}
|
|
37
|
-
}
|
|
33
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../service/KnowledgeService.ts","../utils/path-builder.ts"],"sourcesContent":["import { knowledge } from \"../orm/Knowledge.schema\";\r\nimport { eq, and, or, like, sql, desc, inArray } from \"drizzle-orm\";\r\nimport { buildPath, getLevel, validatePath, isDescendant } from \"../utils/path-builder\";\r\nimport type { Knowledge, KnowledgeSafe, InsertKnowledge } from \"../types\";\r\n\r\nlet _db: any;\r\n\r\n/**\r\n * 初始化 Service 的数据库实例\r\n */\r\nexport function initKnowledgeService(db: any) {\r\n _db = db;\r\n}\r\n\r\nfunction getDB() {\r\n if (!_db) throw new Error(\"KnowledgeService not initialized with DB\");\r\n return _db;\r\n}\r\n\r\n// ==================== CRUD 操作 ====================\r\n\r\n/**\r\n * 创建知识库内容\r\n */\r\nexport async function createKnowledge(data: InsertKnowledge & { userId: number }) {\r\n const db = getDB();\r\n const now = new Date();\r\n\r\n // 如果有父节点,获取父节点信息\r\n let parentPath = \"/\";\r\n let level = 0;\r\n\r\n if (data.parentId) {\r\n const [parent] = await db\r\n .select()\r\n .from(knowledge)\r\n .where(and(eq(knowledge.id, data.parentId), eq(knowledge.isDelete, 0)))\r\n .limit(1);\r\n\r\n if (!parent) {\r\n throw new Error(\"父节点不存在\");\r\n }\r\n\r\n parentPath = parent.path;\r\n level = parent.level + 1;\r\n }\r\n\r\n // 先插入基础数据(不含 path 和 level)\r\n const result = await db\r\n .insert(knowledge)\r\n .values({\r\n name: data.name,\r\n type: data.type ?? 0,\r\n safe: data.safe ?? 0,\r\n userId: data.userId,\r\n description: data.description,\r\n content: data.content,\r\n contentText: data.contentText,\r\n viewType: data.viewType,\r\n coverImage: data.coverImage,\r\n author: data.author,\r\n isbn: data.isbn,\r\n created: now,\r\n updated: now,\r\n isDelete: 0,\r\n isTop: 0,\r\n path: \"/\", // 临时值\r\n level: 0, // 临时值\r\n })\r\n .execute();\r\n\r\n // 获取插入的 ID\r\n const lastId = result.lastInsertRowid as number;\r\n\r\n // 更新 path 和 level\r\n const finalPath = buildPath(parentPath, lastId);\r\n await db\r\n .update(knowledge)\r\n .set({ path: finalPath, level })\r\n .where(eq(knowledge.id, lastId))\r\n .execute();\r\n\r\n return getKnowledgeById(lastId);\r\n}\r\n\r\n/**\r\n * 批量创建知识库内容\r\n */\r\nexport async function createKnowledgeBatch(items: Array<{ name: string; type: number }>, userId: number, parentId?: number) {\r\n const results = [];\r\n\r\n for (const item of items) {\r\n try {\r\n const result = await createKnowledge({ ...item, userId, parentId });\r\n results.push({ success: true, data: result });\r\n } catch (error) {\r\n results.push({ success: false, error: error instanceof Error ? error.message : String(error) });\r\n }\r\n }\r\n\r\n return results;\r\n}\r\n\r\n/**\r\n * 分页获取知识库列表\r\n */\r\nexport async function listKnowledge(options: {\r\n pageIndex: number;\r\n pageSize: number;\r\n level?: number;\r\n type?: number;\r\n safe?: number[];\r\n userId?: number;\r\n isAdmin?: boolean;\r\n}) {\r\n const db = getDB();\r\n const { pageIndex, pageSize, level, type, safe = [0], userId, isAdmin } = options;\r\n\r\n let conditions = [eq(knowledge.isDelete, 0)];\r\n\r\n // 层级筛选\r\n if (level !== undefined) {\r\n conditions.push(eq(knowledge.level, level));\r\n }\r\n\r\n // 类型筛选\r\n if (type !== undefined) {\r\n conditions.push(eq(knowledge.type, type));\r\n }\r\n\r\n // 权限筛选\r\n const safeConditions = [];\r\n for (const s of safe) {\r\n switch (s) {\r\n case 0: // 公开\r\n safeConditions.push(eq(knowledge.safe, s));\r\n break;\r\n case 1: // 登录共享\r\n if (userId) {\r\n safeConditions.push(eq(knowledge.safe, s));\r\n }\r\n break;\r\n case 2: // 个人私密\r\n if (userId) {\r\n safeConditions.push(\r\n and(eq(knowledge.safe, s), isAdmin ? sql`1=1` : eq(knowledge.userId, userId))\r\n );\r\n }\r\n break;\r\n }\r\n }\r\n\r\n if (safeConditions.length > 0) {\r\n conditions.push(or(...safeConditions));\r\n }\r\n\r\n const offset = (pageIndex - 1) * pageSize;\r\n\r\n const list = await db\r\n .select()\r\n .from(knowledge)\r\n .where(and(...conditions))\r\n .limit(pageSize)\r\n .offset(offset)\r\n .orderBy(desc(knowledge.isTop), desc(knowledge.created))\r\n .execute();\r\n\r\n const [totalResult] = await db\r\n .select({ count: sql<number>`count(*)` })\r\n .from(knowledge)\r\n .where(and(...conditions))\r\n .execute();\r\n\r\n return {\r\n list,\r\n total: totalResult.count,\r\n pageIndex,\r\n pageSize,\r\n };\r\n}\r\n\r\n/**\r\n * 获取知识库详情\r\n */\r\nexport async function getKnowledgeById(id: number): Promise<Knowledge | null> {\r\n const db = getDB();\r\n const [item] = await db\r\n .select()\r\n .from(knowledge)\r\n .where(and(eq(knowledge.id, id), eq(knowledge.isDelete, 0)))\r\n .limit(1);\r\n\r\n return item || null;\r\n}\r\n\r\n/**\r\n * 批量获取知识库详情\r\n */\r\nexport async function getKnowledgeByIds(ids: number[]): Promise<Knowledge[]> {\r\n const db = getDB();\r\n if (ids.length === 0) return [];\r\n\r\n return await db\r\n .select()\r\n .from(knowledge)\r\n .where(and(inArray(knowledge.id, ids), eq(knowledge.isDelete, 0)))\r\n .execute();\r\n}\r\n\r\n/**\r\n * 获取知识库目录树\r\n */\r\nexport async function getKnowledgeTree(options: {\r\n parentId?: number | null;\r\n safe?: number[];\r\n userId?: number;\r\n isAdmin?: boolean;\r\n}) {\r\n const db = getDB();\r\n const { parentId = null, safe = [0], userId, isAdmin } = options;\r\n\r\n let conditions = [eq(knowledge.isDelete, 0)];\r\n\r\n // 权限筛选\r\n const safeConditions = [];\r\n for (const s of safe) {\r\n switch (s) {\r\n case 0: // 公开\r\n safeConditions.push(eq(knowledge.safe, s));\r\n break;\r\n case 1: // 登录共享\r\n if (userId) {\r\n safeConditions.push(eq(knowledge.safe, s));\r\n }\r\n break;\r\n case 2: // 个人私密\r\n if (userId) {\r\n safeConditions.push(\r\n and(eq(knowledge.safe, s), isAdmin ? sql`1=1` : eq(knowledge.userId, userId))\r\n );\r\n }\r\n break;\r\n }\r\n }\r\n\r\n if (safeConditions.length > 0) {\r\n conditions.push(or(...safeConditions));\r\n }\r\n\r\n // 如果指定了 parentId,只获取该节点下的子树\r\n if (parentId !== null) {\r\n const [parent] = await db\r\n .select()\r\n .from(knowledge)\r\n .where(and(eq(knowledge.id, parentId), eq(knowledge.isDelete, 0)))\r\n .limit(1);\r\n\r\n if (!parent) return [];\r\n\r\n conditions.push(like(knowledge.path, `${parent.path}%`));\r\n }\r\n\r\n const allNodes = await db\r\n .select()\r\n .from(knowledge)\r\n .where(and(...conditions))\r\n .orderBy(desc(knowledge.isTop), knowledge.name)\r\n .execute();\r\n\r\n // 使用 tree-builder 构建树形结构\r\n const { buildTree } = await import(\"../utils/tree-builder\");\r\n return buildTree(allNodes, parentId);\r\n}\r\n\r\n/**\r\n * 获取子节点列表\r\n */\r\nexport async function getChildren(parentId: number) {\r\n const db = getDB();\r\n\r\n const [parent] = await db\r\n .select()\r\n .from(knowledge)\r\n .where(and(eq(knowledge.id, parentId), eq(knowledge.isDelete, 0)))\r\n .limit(1);\r\n\r\n if (!parent) {\r\n throw new Error(\"父节点不存在\");\r\n }\r\n\r\n return await db\r\n .select()\r\n .from(knowledge)\r\n .where(\r\n and(\r\n eq(knowledge.isDelete, 0),\r\n like(knowledge.path, `${parent.path}%`),\r\n eq(knowledge.level, parent.level + 1)\r\n )\r\n )\r\n .orderBy(desc(knowledge.isTop), knowledge.name)\r\n .execute();\r\n}\r\n\r\n/**\r\n * 更新知识库内容\r\n */\r\nexport async function updateKnowledge(id: number, data: Partial<InsertKnowledge>, userId: number) {\r\n const db = getDB();\r\n const now = new Date();\r\n\r\n const result = await db\r\n .update(knowledge)\r\n .set({\r\n ...(data.name !== undefined && { name: data.name }),\r\n ...(data.description !== undefined && { description: data.description }),\r\n ...(data.content !== undefined && { content: data.content }),\r\n ...(data.contentText !== undefined && { contentText: data.contentText }),\r\n ...(data.viewType !== undefined && { viewType: data.viewType }),\r\n ...(data.coverImage !== undefined && { coverImage: data.coverImage }),\r\n ...(data.author !== undefined && { author: data.author }),\r\n ...(data.isbn !== undefined && { isbn: data.isbn }),\r\n updated: now,\r\n })\r\n .where(and(eq(knowledge.id, id), eq(knowledge.userId, userId)))\r\n .execute();\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * 移动节点(更新整个子树的 path 和 level)\r\n */\r\nexport async function moveKnowledge(nodeId: number, newParentId: number, userId: number) {\r\n const db = getDB();\r\n\r\n // 1. 获取节点和新父节点信息\r\n const [node] = await db\r\n .select()\r\n .from(knowledge)\r\n .where(and(eq(knowledge.id, nodeId), eq(knowledge.isDelete, 0)))\r\n .limit(1);\r\n\r\n const [newParent] = await db\r\n .select()\r\n .from(knowledge)\r\n .where(and(eq(knowledge.id, newParentId), eq(knowledge.isDelete, 0)))\r\n .limit(1);\r\n\r\n if (!node || !newParent) {\r\n throw new Error(\"节点不存在\");\r\n }\r\n\r\n // 权限检查\r\n if (node.userId !== userId) {\r\n throw new Error(\"无权操作此节点\");\r\n }\r\n\r\n // 2. 防止循环:不能移动到自己的后代节点\r\n if (isDescendant(node.path, newParent.path)) {\r\n throw new Error(\"不能移动到自己的后代节点\");\r\n }\r\n\r\n const oldPath = node.path;\r\n const newPath = buildPath(newParent.path, nodeId);\r\n const levelDiff = newParent.level + 1 - node.level;\r\n\r\n // 3. 批量更新整个子树\r\n await db\r\n .update(knowledge)\r\n .set({\r\n path: sql`REPLACE(${knowledge.path}, ${oldPath}, ${newPath})`,\r\n level: sql`${knowledge.level} + ${levelDiff}`,\r\n })\r\n .where(or(like(knowledge.path, `${oldPath}%`), eq(knowledge.path, oldPath)))\r\n .execute();\r\n\r\n return getKnowledgeById(nodeId);\r\n}\r\n\r\n/**\r\n * 更新置顶状态\r\n */\r\nexport async function updateIsTop(id: number, isTop: number, userId: number) {\r\n const db = getDB();\r\n const now = new Date();\r\n\r\n await db\r\n .update(knowledge)\r\n .set({ isTop, updated: now })\r\n .where(and(eq(knowledge.id, id), eq(knowledge.userId, userId)))\r\n .execute();\r\n\r\n return getKnowledgeById(id);\r\n}\r\n\r\n/**\r\n * 更新安全等级\r\n */\r\nexport async function updateSafe(id: number, safe: KnowledgeSafe, userId: number) {\r\n const db = getDB();\r\n const now = new Date();\r\n\r\n await db\r\n .update(knowledge)\r\n .set({ safe, updated: now })\r\n .where(and(eq(knowledge.id, id), eq(knowledge.userId, userId)))\r\n .execute();\r\n\r\n return getKnowledgeById(id);\r\n}\r\n\r\n/**\r\n * 逻辑删除\r\n */\r\nexport async function deleteKnowledge(id: number, userId: number) {\r\n const db = getDB();\r\n const now = new Date();\r\n\r\n await db\r\n .update(knowledge)\r\n .set({ isDelete: 1, updated: now })\r\n .where(and(eq(knowledge.id, id), eq(knowledge.userId, userId)))\r\n .execute();\r\n\r\n return { success: true };\r\n}\r\n\r\n/**\r\n * 真实删除(管理员)\r\n */\r\nexport async function deleteKnowledgeReal(id: number) {\r\n const db = getDB();\r\n\r\n await db\r\n .delete(knowledge)\r\n .where(eq(knowledge.id, id))\r\n .execute();\r\n\r\n return { success: true };\r\n}\r\n\r\n/**\r\n * 搜索知识库内容\r\n */\r\nexport async function searchKnowledge(options: {\r\n keyword: string;\r\n pageIndex?: number;\r\n pageSize?: number;\r\n safe?: number[];\r\n userId?: number;\r\n isAdmin?: boolean;\r\n}) {\r\n const db = getDB();\r\n const { keyword, pageIndex = 1, pageSize = 10, safe = [0], userId, isAdmin } = options;\r\n\r\n let conditions = [\r\n eq(knowledge.isDelete, 0),\r\n or(\r\n like(knowledge.name, `%${keyword}%`),\r\n like(knowledge.description, `%${keyword}%`),\r\n like(knowledge.contentText, `%${keyword}%`)\r\n ),\r\n ];\r\n\r\n // 权限筛选\r\n const safeConditions = [];\r\n for (const s of safe) {\r\n switch (s) {\r\n case 0: // 公开\r\n safeConditions.push(eq(knowledge.safe, s));\r\n break;\r\n case 1: // 登录共享\r\n if (userId) {\r\n safeConditions.push(eq(knowledge.safe, s));\r\n }\r\n break;\r\n case 2: // 个人私密\r\n if (userId) {\r\n safeConditions.push(\r\n and(eq(knowledge.safe, s), isAdmin ? sql`1=1` : eq(knowledge.userId, userId))\r\n );\r\n }\r\n break;\r\n }\r\n }\r\n\r\n if (safeConditions.length > 0) {\r\n conditions.push(or(...safeConditions));\r\n }\r\n\r\n const offset = (pageIndex - 1) * pageSize;\r\n\r\n const list = await db\r\n .select()\r\n .from(knowledge)\r\n .where(and(...conditions))\r\n .limit(pageSize)\r\n .offset(offset)\r\n .orderBy(desc(knowledge.created))\r\n .execute();\r\n\r\n const [totalResult] = await db\r\n .select({ count: sql<number>`count(*)` })\r\n .from(knowledge)\r\n .where(and(...conditions))\r\n .execute();\r\n\r\n return {\r\n list,\r\n total: totalResult.count,\r\n pageIndex,\r\n pageSize,\r\n };\r\n}\r\n","/**\r\n * 物化路径工具函数\r\n */\r\n\r\n/**\r\n * 构建新节点路径\r\n * @param parentPath 父节点路径\r\n * @param id 新节点ID\r\n * @returns 新节点路径\r\n */\r\nexport function buildPath(parentPath: string, id: number): string {\r\n return `${parentPath}${id}/`;\r\n}\r\n\r\n/**\r\n * 从路径计算层级\r\n * @param path 节点路径\r\n * @returns 层级深度(根节点为0)\r\n */\r\nexport function getLevel(path: string): number {\r\n // path 格式: \"/1/3/7/\" -> 分割后 ['', '1', '3', '7', '']\r\n // 减2是因为前后各有一个空字符串\r\n const parts = path.split(\"/\").filter(Boolean);\r\n return parts.length - 1;\r\n}\r\n\r\n/**\r\n * 验证路径是否有效(防止循环引用)\r\n * @param newPath 新路径\r\n * @param oldPath 旧路径\r\n * @returns 是否有效\r\n */\r\nexport function validatePath(newPath: string, oldPath: string): boolean {\r\n // 不能将节点移动到自己的后代节点下\r\n // 如果新父节点的 path 以旧节点的 path 开头,说明是后代\r\n return !newPath.startsWith(oldPath);\r\n}\r\n\r\n/**\r\n * 检查是否为后代节点\r\n * @param ancestorPath 祖先节点路径\r\n * @param descendantPath 后代节点路径\r\n * @returns 是否为后代\r\n */\r\nexport function isDescendant(ancestorPath: string, descendantPath: string): boolean {\r\n return descendantPath.startsWith(ancestorPath) && ancestorPath !== descendantPath;\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../service/TagService.ts"],"sourcesContent":["import { knowledgeTag, knowledgeTagRelation } from \"../orm/Tag.schema\";\r\nimport { eq, and, inArray } from \"drizzle-orm\";\r\nimport type { InsertTag } from \"../types\";\r\n\r\nlet _db: any;\r\n\r\n/**\r\n * 初始化 Service 的数据库实例\r\n */\r\nexport function initTagService(db: any) {\r\n _db = db;\r\n}\r\n\r\nfunction getDB() {\r\n if (!_db) throw new Error(\"TagService not initialized with DB\");\r\n return _db;\r\n}\r\n\r\n// ==================== 标签管理 ====================\r\n\r\n/**\r\n * 创建标签\r\n */\r\nexport async function createTag(data: InsertTag & { userId?: number }) {\r\n const db = getDB();\r\n const now = new Date();\r\n\r\n const result = await db\r\n .insert(knowledgeTag)\r\n .values({\r\n name: data.name,\r\n color: data.color,\r\n userId: data.userId,\r\n created: now,\r\n })\r\n .execute();\r\n\r\n const lastId = result.lastInsertRowid as number;\r\n return getTagById(lastId);\r\n}\r\n\r\n/**\r\n * 获取标签详情\r\n */\r\nexport async function getTagById(id: number) {\r\n const db = getDB();\r\n const [tag] = await db\r\n .select()\r\n .from(knowledgeTag)\r\n .where(eq(knowledgeTag.id, id))\r\n .limit(1);\r\n\r\n return tag || null;\r\n}\r\n\r\n/**\r\n * 获取标签列表\r\n */\r\nexport async function listTags(userId?: number) {\r\n const db = getDB();\r\n\r\n let conditions = [];\r\n if (userId !== undefined) {\r\n conditions.push(eq(knowledgeTag.userId, userId));\r\n }\r\n\r\n return await db\r\n .select()\r\n .from(knowledgeTag)\r\n .where(conditions.length > 0 ? and(...conditions) : undefined)\r\n .orderBy(knowledgeTag.name)\r\n .execute();\r\n}\r\n\r\n/**\r\n * 更新标签\r\n */\r\nexport async function updateTag(id: number, data: Partial<InsertTag>, userId: number) {\r\n const db = getDB();\r\n\r\n // 检查权限\r\n const [tag] = await db\r\n .select()\r\n .from(knowledgeTag)\r\n .where(and(eq(knowledgeTag.id, id), eq(knowledgeTag.userId, userId)))\r\n .limit(1);\r\n\r\n if (!tag) {\r\n throw new Error(\"标签不存在或无权操作\");\r\n }\r\n\r\n await db\r\n .update(knowledgeTag)\r\n .set({\r\n ...(data.name !== undefined && { name: data.name }),\r\n ...(data.color !== undefined && { color: data.color }),\r\n })\r\n .where(eq(knowledgeTag.id, id))\r\n .execute();\r\n\r\n return getTagById(id);\r\n}\r\n\r\n/**\r\n * 删除标签\r\n */\r\nexport async function deleteTag(id: number, userId: number) {\r\n const db = getDB();\r\n\r\n // 检查权限\r\n const [tag] = await db\r\n .select()\r\n .from(knowledgeTag)\r\n .where(and(eq(knowledgeTag.id, id), eq(knowledgeTag.userId, userId)))\r\n .limit(1);\r\n\r\n if (!tag) {\r\n throw new Error(\"标签不存在或无权操作\");\r\n }\r\n\r\n // 删除标签关联\r\n await db\r\n .delete(knowledgeTagRelation)\r\n .where(eq(knowledgeTagRelation.tagId, id))\r\n .execute();\r\n\r\n // 删除标签\r\n await db\r\n .delete(knowledgeTag)\r\n .where(eq(knowledgeTag.id, id))\r\n .execute();\r\n\r\n return { success: true };\r\n}\r\n\r\n// ==================== 标签关联 ====================\r\n\r\n/**\r\n * 为知识库内容添加标签\r\n */\r\nexport async function addTagToKnowledge(knowledgeId: number, tagId: number, userId: number) {\r\n const db = getDB();\r\n\r\n // 检查标签是否存在\r\n const [tag] = await db\r\n .select()\r\n .from(knowledgeTag)\r\n .where(eq(knowledgeTag.id, tagId))\r\n .limit(1);\r\n\r\n if (!tag) {\r\n throw new Error(\"标签不存在\");\r\n }\r\n\r\n // 检查是否已存在关联\r\n const [existing] = await db\r\n .select()\r\n .from(knowledgeTagRelation)\r\n .where(\r\n and(\r\n eq(knowledgeTagRelation.knowledgeId, knowledgeId),\r\n eq(knowledgeTagRelation.tagId, tagId)\r\n )\r\n )\r\n .limit(1);\r\n\r\n if (existing) {\r\n return { success: true, message: \"标签已存在\" };\r\n }\r\n\r\n // 创建关联\r\n await db\r\n .insert(knowledgeTagRelation)\r\n .values({\r\n knowledgeId,\r\n tagId,\r\n })\r\n .execute();\r\n\r\n return { success: true };\r\n}\r\n\r\n/**\r\n * 移除知识库内容的标签\r\n */\r\nexport async function removeTagFromKnowledge(knowledgeId: number, tagId: number) {\r\n const db = getDB();\r\n\r\n await db\r\n .delete(knowledgeTagRelation)\r\n .where(\r\n and(\r\n eq(knowledgeTagRelation.knowledgeId, knowledgeId),\r\n eq(knowledgeTagRelation.tagId, tagId)\r\n )\r\n )\r\n .execute();\r\n\r\n return { success: true };\r\n}\r\n\r\n/**\r\n * 获取知识库内容的标签列表\r\n */\r\nexport async function getKnowledgeTags(knowledgeId: number) {\r\n const db = getDB();\r\n\r\n return await db\r\n .select({\r\n id: knowledgeTag.id,\r\n name: knowledgeTag.name,\r\n color: knowledgeTag.color,\r\n })\r\n .from(knowledgeTagRelation)\r\n .innerJoin(knowledgeTag, eq(knowledgeTagRelation.tagId, knowledgeTag.id))\r\n .where(eq(knowledgeTagRelation.knowledgeId, knowledgeId))\r\n .execute();\r\n}\r\n\r\n/**\r\n * 按标签查询知识库内容\r\n */\r\nexport async function getKnowledgeByTag(tagId: number, options: {\r\n pageIndex?: number;\r\n pageSize?: number;\r\n safe?: number[];\r\n userId?: number;\r\n isAdmin?: boolean;\r\n}) {\r\n const db = getDB();\r\n const { pageIndex = 1, pageSize = 10, safe = [0], userId, isAdmin } = options;\r\n\r\n // 获取带有该标签的知识库 ID 列表\r\n const relations = await db\r\n .select()\r\n .from(knowledgeTagRelation)\r\n .where(eq(knowledgeTagRelation.tagId, tagId))\r\n .execute();\r\n\r\n if (relations.length === 0) {\r\n return { list: [], total: 0, pageIndex, pageSize };\r\n }\r\n\r\n const knowledgeIds = relations.map(r => r.knowledgeId);\r\n\r\n // 导入 knowledge 表\r\n const { knowledge } = await import(\"../orm/Knowledge.schema\");\r\n const { eq, and, or, sql, desc } = await import(\"drizzle-orm\");\r\n\r\n let conditions = [\r\n eq(knowledge.isDelete, 0),\r\n inArray(knowledge.id, knowledgeIds),\r\n ];\r\n\r\n // 权限筛选\r\n const safeConditions = [];\r\n for (const s of safe) {\r\n switch (s) {\r\n case 0: // 公开\r\n safeConditions.push(eq(knowledge.safe, s));\r\n break;\r\n case 1: // 登录共享\r\n if (userId) {\r\n safeConditions.push(eq(knowledge.safe, s));\r\n }\r\n break;\r\n case 2: // 个人私密\r\n if (userId) {\r\n safeConditions.push(\r\n and(eq(knowledge.safe, s), isAdmin ? sql`1=1` : eq(knowledge.userId, userId))\r\n );\r\n }\r\n break;\r\n }\r\n }\r\n\r\n if (safeConditions.length > 0) {\r\n conditions.push(or(...safeConditions));\r\n }\r\n\r\n const offset = (pageIndex - 1) * pageSize;\r\n\r\n const list = await db\r\n .select()\r\n .from(knowledge)\r\n .where(and(...conditions))\r\n .limit(pageSize)\r\n .offset(offset)\r\n .orderBy(desc(knowledge.created))\r\n .execute();\r\n\r\n const [totalResult] = await db\r\n .select({ count: sql<number>`count(*)` })\r\n .from(knowledge)\r\n .where(and(...conditions))\r\n .execute();\r\n\r\n return {\r\n list,\r\n total: totalResult.count,\r\n pageIndex,\r\n pageSize,\r\n };\r\n}\r\n"],"mappings":"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","names":["eq","and"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../orm/Tag.schema.ts"],"sourcesContent":["import { sqliteTable, text, integer } from \"drizzle-orm/sqlite-core\";\r\nimport { createInsertSchema, createSelectSchema } from \"drizzle-zod\";\r\nimport { z } from \"zod\";\r\n\r\n/**\r\n * 标签表\r\n */\r\nexport const knowledgeTag = sqliteTable(\"knowledge_tag\", {\r\n id: integer(\"id\").primaryKey({ autoIncrement: true }),\r\n name: text(\"name\").notNull().unique(),\r\n color: text(\"color\"),\r\n userId: integer(\"user_id\"),\r\n created: integer(\"created\", { mode: \"timestamp\" }),\r\n});\r\n\r\n/**\r\n * 标签关联表(多对多)\r\n */\r\nexport const knowledgeTagRelation = sqliteTable(\"knowledge_tag_relation\", {\r\n knowledgeId: integer(\"knowledge_id\").notNull(),\r\n tagId: integer(\"tag_id\").notNull(),\r\n});\r\n\r\n// ==================== Zod Schemas ====================\r\n\r\n/**\r\n * 创建标签验证\r\n */\r\nexport const createTagSchema = createInsertSchema(knowledgeTag as any, {\r\n name: z.string().min(1, \"标签名不能为空\").max(50, \"标签名不能超过50字符\") as any,\r\n color: z.string().regex(/^#[0-9A-Fa-f]{6}$/, \"颜色必须是十六进制格式\").optional() as any,\r\n}).pick({\r\n name: true,\r\n color: true,\r\n});\r\n\r\n/**\r\n * 更新标签验证\r\n */\r\nexport const updateTagSchema = createInsertSchema(knowledgeTag as any)\r\n .partial()\r\n .extend({\r\n id: z.number({ required_error: \"标签ID不能为空\" }),\r\n });\r\n\r\n/**\r\n * 添加标签关联验证\r\n */\r\nexport const addTagRelationSchema = z.object({\r\n tagId: z.number({ required_error: \"标签ID不能为空\" }),\r\n});\r\n"],"mappings":";;;;;AAAA,SAAS,aAAa,MAAM,eAAe;AAE3C,SAAS,SAAS;AAKX,IAAM,eAAe,YAAY,iBAAiB;AAAA,EACvD,IAAI,QAAQ,IAAI,EAAE,WAAW,EAAE,eAAe,KAAK,CAAC;AAAA,EACpD,MAAM,KAAK,MAAM,EAAE,QAAQ,EAAE,OAAO;AAAA,EACpC,OAAO,KAAK,OAAO;AAAA,EACnB,QAAQ,QAAQ,SAAS;AAAA,EACzB,SAAS,QAAQ,WAAW,EAAE,MAAM,YAAY,CAAC;AACnD,CAAC;AAKM,IAAM,uBAAuB,YAAY,0BAA0B;AAAA,EACxE,aAAa,QAAQ,cAAc,EAAE,QAAQ;AAAA,EAC7C,OAAO,QAAQ,QAAQ,EAAE,QAAQ;AACnC,CAAC;AAOM,IAAM,kBAAkB,EAAmB,cAAqB;AAAA,EACrE,MAAM,EAAE,OAAO,EAAE,IAAI,GAAG,4CAAS,EAAE,IAAI,IAAI,0DAAa;AAAA,EACxD,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,oEAAa,EAAE,SAAS;AACvE,CAAC,EAAE,KAAK;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACT,CAAC;AAKM,IAAM,kBAAkB,EAAmB,YAAmB,EAClE,QAAQ,EACR,OAAO;AAAA,EACN,IAAI,EAAE,OAAO,EAAE,gBAAgB,yCAAW,CAAC;AAC7C,CAAC;AAKI,IAAM,uBAAuB,EAAE,OAAO;AAAA,EAC3C,OAAO,EAAE,OAAO,EAAE,gBAAgB,yCAAW,CAAC;AAChD,CAAC;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../orm/Knowledge.schema.ts"],"sourcesContent":["import { sqliteTable, text, integer } from \"drizzle-orm/sqlite-core\";\r\nimport { createInsertSchema, createSelectSchema } from \"drizzle-zod\";\r\nimport { z } from \"zod\";\r\n\r\n/**\r\n * 知识库主表\r\n */\r\nexport const knowledge = sqliteTable(\"knowledge\", {\r\n id: integer(\"id\").primaryKey({ autoIncrement: true }),\r\n name: text(\"name\").notNull(),\r\n path: text(\"path\").notNull(),\r\n level: integer(\"level\").notNull().default(0),\r\n type: integer(\"type\").notNull(), // 0:文件夹 1:笔记 2:书籍\r\n safe: integer(\"safe\").notNull().default(0),\r\n userId: integer(\"user_id\").notNull(),\r\n // 书籍特有字段\r\n coverImage: text(\"cover_image\"),\r\n author: text(\"author\"),\r\n isbn: text(\"isbn\"),\r\n description: text(\"description\"),\r\n created: integer(\"created\", { mode: \"timestamp\" }),\r\n updated: integer(\"updated\", { mode: \"timestamp\" }),\r\n isDelete: integer(\"is_delete\").notNull().default(0),\r\n isTop: integer(\"is_top\").notNull().default(0),\r\n content: text(\"content\"),\r\n contentText: text(\"content_text\"),\r\n viewType: integer(\"view_type\").default(0),\r\n});\r\n\r\n// ==================== Zod Schemas ====================\r\n\r\n/**\r\n * 创建知识库内容验证\r\n */\r\nexport const createKnowledgeSchema = createInsertSchema(knowledge as any, {\r\n name: z.string().min(1, \"名称不能为空\").max(255, \"名称不能超过255字符\") as any,\r\n type: z.coerce.number().int().min(0).max(2) as any,\r\n safe: z.coerce.number().int().min(0).max(2).optional() as any,\r\n}).pick({\r\n name: true,\r\n type: true,\r\n safe: true,\r\n description: true,\r\n content: true,\r\n contentText: true,\r\n viewType: true,\r\n coverImage: true,\r\n author: true,\r\n isbn: true,\r\n});\r\n\r\n/**\r\n * 批量创建验证\r\n */\r\nexport const batchCreateKnowledgeSchema = z.object({\r\n parentId: z.number().optional(),\r\n items: z.array(z.object({\r\n name: z.string().min(1, \"名称不能为空\").max(255),\r\n type: z.coerce.number().int().min(0).max(2),\r\n })).min(1, \"至少需要一个项目\"),\r\n});\r\n\r\n/**\r\n * 批量获取详情验证\r\n */\r\nexport const batchDetailKnowledgeSchema = z.object({\r\n ids: z.array(z.number().int().positive()).min(1, \"至少需要一个ID\"),\r\n});\r\n\r\n/**\r\n * 更新知识库内容验证\r\n */\r\nexport const updateKnowledgeSchema = createInsertSchema(knowledge as any)\r\n .partial()\r\n .extend({\r\n id: z.number({ required_error: \"ID不能为空\" }),\r\n });\r\n\r\n/**\r\n * 列表查询验证\r\n */\r\nexport const listKnowledgeSchema = z.object({\r\n pageIndex: z.coerce.number().int().positive().optional().default(1),\r\n pageSize: z.coerce.number().int().positive().optional().default(10),\r\n level: z.coerce.number().int().min(0).optional(),\r\n type: z.coerce.number().int().min(0).max(2).optional(),\r\n safe: z.array(z.coerce.number().int().min(0).max(2)).optional(),\r\n});\r\n\r\n/**\r\n * 搜索验证\r\n */\r\nexport const searchKnowledgeSchema = z.object({\r\n keyword: z.string().min(1, \"关键词不能为空\"),\r\n pageIndex: z.coerce.number().int().positive().optional().default(1),\r\n pageSize: z.coerce.number().int().positive().optional().default(10),\r\n});\r\n\r\n/**\r\n * 移动节点验证\r\n */\r\nexport const moveKnowledgeSchema = z.object({\r\n newParentId: z.number({ required_error: \"新父节点ID不能为空\" }),\r\n});\r\n\r\n/**\r\n * 更新置顶状态验证\r\n */\r\nexport const updateIsTopSchema = z.object({\r\n isTop: z.coerce.number().int().min(0).max(1),\r\n});\r\n\r\n/**\r\n * 更新安全等级验证\r\n */\r\nexport const updateSafeSchema = z.object({\r\n safe: z.coerce.number().int().min(0).max(2),\r\n});\r\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../utils/tree-builder.ts"],"sourcesContent":["import type { KnowledgeTreeNode, Knowledge } from \"../types\";\r\n\r\n/**\r\n * 将扁平数组转换为树形结构\r\n * @param nodes 扁平节点数组\r\n * @param parentId 父节点ID(可选,用于构建子树)\r\n * @returns 树形结构\r\n */\r\nexport function buildTree(\r\n nodes: Knowledge[],\r\n parentId: number | null = null\r\n): KnowledgeTreeNode[] {\r\n // 按 isTop 降序、created 降序排序\r\n const sortedNodes = [...nodes].sort((a, b) => {\r\n if (a.isTop !== b.isTop) {\r\n return b.isTop - a.isTop;\r\n }\r\n return b.created.getTime() - a.created.getTime();\r\n });\r\n\r\n // 如果指定了 parentId,先找到该节点\r\n if (parentId !== null) {\r\n const parent = sortedNodes.find(n => n.id === parentId);\r\n if (!parent) return [];\r\n\r\n // 查找该节点的直接子节点\r\n const children = sortedNodes.filter(n =>\r\n n.path.startsWith(parent.path) &&\r\n n.level === parent.level + 1\r\n );\r\n\r\n return children.map(child => buildNodeTree(child, sortedNodes));\r\n }\r\n\r\n // 否则返回根节点(level=0)的树\r\n const rootNodes = sortedNodes.filter(n => n.level === 0);\r\n return rootNodes.map(node => buildNodeTree(node, sortedNodes));\r\n}\r\n\r\n/**\r\n * 递归构建节点树\r\n */\r\nfunction buildNodeTree(node: Knowledge, allNodes: Knowledge[]): KnowledgeTreeNode {\r\n const treeNode: KnowledgeTreeNode = { ...node };\r\n\r\n // 查找直接子节点\r\n const children = allNodes.filter(n =>\r\n n.path.startsWith(node.path) &&\r\n n.level === node.level + 1\r\n );\r\n\r\n if (children.length > 0) {\r\n treeNode.children = children.map(child => buildNodeTree(child, allNodes));\r\n }\r\n\r\n return treeNode;\r\n}\r\n"],"mappings":";;;AAQO,SAAS,UACd,OACA,WAA0B,MACL;AAErB,QAAM,cAAc,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM;AAC5C,QAAI,EAAE,UAAU,EAAE,OAAO;AACvB,aAAO,EAAE,QAAQ,EAAE;AAAA,IACrB;AACA,WAAO,EAAE,QAAQ,QAAQ,IAAI,EAAE,QAAQ,QAAQ;AAAA,EACjD,CAAC;AAGD,MAAI,aAAa,MAAM;AACrB,UAAM,SAAS,YAAY,KAAK,OAAK,EAAE,OAAO,QAAQ;AACtD,QAAI,CAAC,OAAQ,QAAO,CAAC;AAGrB,UAAM,WAAW,YAAY;AAAA,MAAO,OAClC,EAAE,KAAK,WAAW,OAAO,IAAI,KAC7B,EAAE,UAAU,OAAO,QAAQ;AAAA,IAC7B;AAEA,WAAO,SAAS,IAAI,WAAS,cAAc,OAAO,WAAW,CAAC;AAAA,EAChE;AAGA,QAAM,YAAY,YAAY,OAAO,OAAK,EAAE,UAAU,CAAC;AACvD,SAAO,UAAU,IAAI,UAAQ,cAAc,MAAM,WAAW,CAAC;AAC/D;AAKA,SAAS,cAAc,MAAiB,UAA0C;AAChF,QAAM,WAA8B,EAAE,GAAG,KAAK;AAG9C,QAAM,WAAW,SAAS;AAAA,IAAO,OAC/B,EAAE,KAAK,WAAW,KAAK,IAAI,KAC3B,EAAE,UAAU,KAAK,QAAQ;AAAA,EAC3B;AAEA,MAAI,SAAS,SAAS,GAAG;AACvB,aAAS,WAAW,SAAS,IAAI,WAAS,cAAc,OAAO,QAAQ,CAAC;AAAA,EAC1E;AAEA,SAAO;AACT;","names":[]}
|
|
File without changes
|