feat: 知识库树形视图(按来源分组),左侧树导航+右侧列表联动
This commit is contained in:
@@ -239,4 +239,88 @@ class KnowledgeService:
|
||||
|
||||
def get_embedding_count(self) -> int:
|
||||
with Session(engine) as session:
|
||||
return len(session.exec(select(KnowledgeEmbedding)).all())
|
||||
return len(session.exec(select(KnowledgeEmbedding)).all())
|
||||
|
||||
def get_grouped_items(self) -> list[dict]:
|
||||
"""
|
||||
按 source_type → source_detail 两层聚合,返回树形结构数据。
|
||||
|
||||
返回格式:
|
||||
[
|
||||
{
|
||||
"key": "全部",
|
||||
"label": "全部(N条)",
|
||||
"count": 总条目数,
|
||||
"children": [
|
||||
{
|
||||
"key": "manuscript",
|
||||
"label": "节目文稿(n条)",
|
||||
"count": n,
|
||||
"children": [ # source_detail 为 null 时直接为空数组,不造空节点
|
||||
{"key": "...", "label": "具体出处", "count": n}
|
||||
]
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
注意:source_detail 为 null 的条目(如节目文稿、报题单),
|
||||
归入对应 source_type 大类下,但不单独成子节点(大类的 children 直接为其条目列表,
|
||||
但前端 Tree 组件渲染时,若 children 为空则不展示二级节点,大类直接可点击)。
|
||||
"""
|
||||
SOURCE_TYPE_LABEL = {
|
||||
"military_report": "杂志文章",
|
||||
"manuscript": "节目文稿",
|
||||
"baoti": "报题单",
|
||||
"manual": "其他",
|
||||
}
|
||||
|
||||
with Session(engine) as session:
|
||||
items = session.exec(select(KnowledgeItem)).all()
|
||||
|
||||
total_count = len(items)
|
||||
|
||||
# 按 source_type 分组
|
||||
type_groups: dict = {}
|
||||
for item in items:
|
||||
st = item.source_type or "manual"
|
||||
if st not in type_groups:
|
||||
type_groups[st] = []
|
||||
type_groups[st].append(item)
|
||||
|
||||
children = []
|
||||
for st, st_items in type_groups.items():
|
||||
# 按 source_detail 细分
|
||||
detail_groups: dict = {}
|
||||
for item in st_items:
|
||||
tags = item.tags or {}
|
||||
sd = tags.get("source_detail") if isinstance(tags, dict) else None
|
||||
if sd not in detail_groups:
|
||||
detail_groups[sd] = []
|
||||
detail_groups[sd].append(item)
|
||||
|
||||
# 构建二级节点:仅 source_detail 非 null 的才建子节点
|
||||
grandchildren = []
|
||||
for sd, sd_items in detail_groups.items():
|
||||
if sd is not None:
|
||||
grandchildren.append({
|
||||
"key": f"{st}|{sd}",
|
||||
"label": f"{sd}({len(sd_items)}条)",
|
||||
"count": len(sd_items),
|
||||
})
|
||||
|
||||
label = SOURCE_TYPE_LABEL.get(st, st)
|
||||
children.append({
|
||||
"key": st,
|
||||
"label": f"{label}({len(st_items)}条)",
|
||||
"count": len(st_items),
|
||||
"children": grandchildren,
|
||||
})
|
||||
|
||||
return [{
|
||||
"key": "all",
|
||||
"label": f"全部({total_count}条)",
|
||||
"count": total_count,
|
||||
"children": children,
|
||||
}]
|
||||
|
||||
Reference in New Issue
Block a user