feat: 简化知识库导入——只输入NodeToken,自动获取标题和SpaceID

- admin_knowledge.py: /knowledge/import 改为单条导入,自动获取 title+space_id
- feishu_service.py: 新增 get_node_info() 公开方法
- App.vue: 简化 UI,只保留 NodeToken 输入框和导入按钮
- api.ts: 更新类型定义
This commit is contained in:
2026-07-09 10:13:09 +08:00
parent 76da6dd65a
commit 67048a14e8
4 changed files with 54 additions and 47 deletions

View File

@@ -28,46 +28,38 @@ def import_knowledge_from_space(
db: Session = Depends(get_db),
current_admin: Admin = Depends(get_current_admin),
) -> dict:
parent_node_token = payload.get("parent_node_token", "").strip()
if not parent_node_token:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="父节点 NodeToken 不能为空")
node_token = payload.get("node_token", "").strip()
if not node_token:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="NodeToken 不能为空")
nodes = FeishuKnowledgeService.import_nodes_from_parent(parent_node_token, db)
if not nodes:
return api_success({"imported": 0, "skipped": 0, "nodes": []})
# 获取已存在的 node_id避免重复导入
existing_nodes = {
row.feishu_node_id for row in db.scalars(select(Knowledge)).all() if row.feishu_node_id
}
imported = 0
skipped = 0
results = []
for node in nodes:
node_token = node["node_token"]
if node_token in existing_nodes:
skipped += 1
results.append({"name": node["name"], "nodeToken": node_token, "status": "skipped"})
continue
knowledge = Knowledge(
name=node["name"],
feishu_space_id=space_id,
feishu_node_id=node_token,
status=1,
remark=f"obj_type={node.get('obj_type', '')}",
)
db.add(knowledge)
db.flush()
imported += 1
results.append({"name": node["name"], "nodeToken": node_token, "status": "imported", "id": knowledge.id})
OperationLogService.write(
db, admin_id=current_admin.id, module="knowledge", action="import", target_id=knowledge.id
info = FeishuKnowledgeService.get_node_info(node_token, db)
space_id = info.get("space_id", "")
if not space_id:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"无法获取节点 {node_token} 的 SpaceID",
)
# 检查是否已存在
existing = db.scalar(select(Knowledge).where(Knowledge.feishu_node_id == node_token))
if existing is not None:
return api_success({"imported": 0, "skipped": 1, "id": existing.id, "name": existing.name})
knowledge = Knowledge(
name=info.get("title", node_token),
feishu_space_id=space_id,
feishu_node_id=node_token,
status=1,
remark=f"obj_type={info.get('obj_type', '')}",
)
db.add(knowledge)
db.flush()
OperationLogService.write(
db, admin_id=current_admin.id, module="knowledge", action="import", target_id=knowledge.id
)
db.commit()
return api_success({"imported": imported, "skipped": skipped, "nodes": results})
db.refresh(knowledge)
return api_success({"imported": 1, "skipped": 0, "id": knowledge.id, "name": knowledge.name})
@router.post("/knowledge")

View File

@@ -330,6 +330,17 @@ class FeishuKnowledgeService:
cls._content_cache.clear()
return count
@classmethod
def get_node_info(cls, node_token: str, db: Session | None = None) -> dict:
"""获取 Wiki 节点基本信息space_id、标题、obj_type 等)"""
config = _feishu_retrieval_config(db)
if not config.app_id or not config.app_secret:
raise ExternalServiceError(
"未配置飞书应用凭证,无法读取飞书知识库。",
provider="feishu",
)
return _get_wiki_node_info(node_token, config)
@classmethod
def import_nodes_from_parent(
cls,