Skip to content

Commit b8bfc97

Browse files
committed
feat: 更新知识图谱组件,优化统计信息显示和图表加载逻辑
1 parent f0275aa commit b8bfc97

File tree

5 files changed

+75
-224
lines changed

5 files changed

+75
-224
lines changed

web/src/components/FileTable.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,7 @@ import { parseToShanghai } from '@/utils/time';
372372
<style scoped>
373373
.file-table-container {
374374
display: flex;
375+
flex-grow: 1;
375376
flex-direction: column;
376377
max-height: 100%;
377378
overflow: hidden;

web/src/components/KnowledgeGraphSection.vue

Lines changed: 26 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,11 @@
22
<div class="graph-section" v-if="isGraphSupported">
33
<div class="graph-toolbar">
44
<div class="toolbar-left">
5-
<div v-if="graphStats.displayed_nodes > 0 || graphStats.displayed_edges > 0" class="graph-stats">
6-
<a-tag color="blue" size="small">节点: {{ graphStats.displayed_nodes }}</a-tag>
7-
<a-tag color="green" size="small">: {{ graphStats.displayed_edges }}</a-tag>
5+
<div class="graph-stats">
6+
<a-tag color="blue" size="small">总节点: {{ graphStats.total_nodes || 0 }}</a-tag>
7+
<a-tag color="green" size="small">总边: {{ graphStats.total_edges || 0 }}</a-tag>
88
</div>
99
</div>
10-
<div class="toolbar-right">
11-
<a-button
12-
type="primary"
13-
size="small"
14-
@click="loadGraph"
15-
:disabled="!isGraphSupported"
16-
:icon='h(ReloadOutlined)'
17-
>
18-
加载图谱
19-
</a-button>
20-
<a-button
21-
type="text"
22-
size="small"
23-
:icon="h(ExpandOutlined)"
24-
title="最大化"
25-
@click="toggleGraphMaximize"
26-
:disabled="!isGraphSupported"
27-
>
28-
最大化
29-
</a-button>
30-
</div>
3110
</div>
3211
<div class="graph-container-compact">
3312
<div v-if="!isGraphSupported" class="graph-disabled">
@@ -41,12 +20,10 @@
4120
v-else
4221
:initial-database-id="databaseId"
4322
:hide-db-selector="true"
44-
:hide-stats="true"
45-
:hide-controls="!store.state.isGraphMaximized"
4623
:initial-limit="graphLimit"
4724
:initial-depth="graphDepth"
48-
@update:stats="handleStatsUpdate"
4925
ref="graphViewerRef"
26+
@update:stats="handleViewerStats"
5027
/>
5128
</div>
5229

@@ -115,7 +92,7 @@
11592
<script setup>
11693
import { ref, computed, watch, nextTick, onUnmounted } from 'vue';
11794
import { useDatabaseStore } from '@/stores/database';
118-
import { ReloadOutlined, ExpandOutlined } from '@ant-design/icons-vue';
95+
import { ReloadOutlined } from '@ant-design/icons-vue';
11996
import KnowledgeGraphViewer from '@/components/KnowledgeGraphViewer.vue';
12097
import { h } from 'vue';
12198
import { getKbTypeLabel } from '@/utils/kb_utils';
@@ -139,7 +116,7 @@ const graphStats = computed({
139116
140117
const graphViewerRef = ref(null);
141118
const showSettings = ref(false);
142-
const graphLimit = ref(200);
119+
const graphLimit = ref(50);
143120
const graphDepth = ref(2);
144121
145122
const showExportModal = ref(false);
@@ -168,14 +145,6 @@ const clearGraph = () => {
168145
}
169146
};
170147
171-
const toggleGraphMaximize = () => {
172-
store.state.isGraphMaximized = !store.state.isGraphMaximized;
173-
};
174-
175-
const handleStatsUpdate = (stats) => {
176-
graphStats.value = stats;
177-
};
178-
179148
const applySettings = () => {
180149
showSettings.value = false;
181150
// 设置已通过props传递给子组件,不需要额外操作
@@ -241,6 +210,20 @@ const scheduleGraphLoad = (delay = 200) => {
241210
}, delay);
242211
};
243212
213+
// 处理子组件(Viewer)上报的统计信息,将其写入 database store 的 graphStats
214+
const handleViewerStats = (stats) => {
215+
if (!stats) return;
216+
217+
// 合并现有 store.graphStats,优先使用来自 viewer 的值
218+
store.graphStats = {
219+
total_nodes: stats.total_nodes ?? store.graphStats.total_nodes ?? 0,
220+
total_edges: stats.total_edges ?? store.graphStats.total_edges ?? 0,
221+
displayed_nodes: stats.displayed_nodes ?? store.graphStats.displayed_nodes ?? 0,
222+
displayed_edges: stats.displayed_edges ?? store.graphStats.displayed_edges ?? 0,
223+
is_truncated: stats.is_truncated ?? store.graphStats.is_truncated ?? false,
224+
}
225+
}
226+
244227
watch(
245228
() => props.active,
246229
(active) => {
@@ -252,13 +235,17 @@ watch(
252235
);
253236
254237
watch(databaseId, () => {
238+
store.graphStats = defaultGraphStats();
255239
scheduleGraphLoad(300);
256240
});
257241
258242
watch(isGraphSupported, (supported) => {
259-
if (supported) {
260-
scheduleGraphLoad(200);
243+
if (!supported) {
244+
store.graphStats = defaultGraphStats();
245+
clearGraph();
246+
return;
261247
}
248+
scheduleGraphLoad(200);
262249
});
263250
264251
onUnmounted(() => {

web/src/components/KnowledgeGraphViewer.vue

Lines changed: 25 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -71,24 +71,8 @@
7171
>
7272
<SearchOutlined v-if="!loading" /> 加载图谱
7373
</a-button>
74-
<a-button
75-
type="default"
76-
size="small"
77-
:loading="loading"
78-
@click="loadTestData"
79-
:disabled="!selectedDatabase"
80-
style="margin-left: 6px"
81-
title="加载测试数据(用于演示图谱功能)"
82-
>
83-
<ReloadOutlined v-if="!loading" /> 测试数据
84-
</a-button>
8574
</div>
8675

87-
<div v-if="!props.hideStats" class="stats-section">
88-
<a-tag color="blue" size="small">节点: {{ stats.displayed_nodes || 0 }}</a-tag>
89-
<a-tag color="green" size="small">边: {{ stats.displayed_edges || 0 }}</a-tag>
90-
<!-- <a-tag v-if="stats.is_truncated" color="red" size="small">已截断</a-tag> -->
91-
</div>
9276
</div>
9377

9478
<!-- Sigma.js图可视化容器 -->
@@ -98,6 +82,11 @@
9882
:class="{ 'loading': loading }"
9983
></div>
10084

85+
<div v-if="!props.hideStats" class="graph-overlay-stats">
86+
<a-tag color="blue" size="small">节点: {{ stats.displayed_nodes || 0 }}</a-tag>
87+
<a-tag color="green" size="small">边: {{ stats.displayed_edges || 0 }}</a-tag>
88+
</div>
89+
10190
<!-- 节点详情面板 -->
10291
<div
10392
v-if="selectedNodeData"
@@ -234,7 +223,6 @@ import { ref, reactive, onMounted, onUnmounted, computed, watch, nextTick } from
234223
import { message } from 'ant-design-vue'
235224
import {
236225
SearchOutlined,
237-
ReloadOutlined,
238226
ClearOutlined,
239227
CloseOutlined,
240228
PlusOutlined,
@@ -248,6 +236,7 @@ import { EdgeArrowProgram } from 'sigma/rendering'
248236
249237
import { lightragApi } from '@/apis/graph_api'
250238
import { useGraphStore } from '@/stores/graphStore'
239+
import { useDatabaseStore } from '@/stores/database'
251240
import '@/assets/css/sigma.css'
252241
253242
// 定义 props
@@ -283,6 +272,7 @@ const emit = defineEmits(['update:stats', 'refresh-graph', 'clear-graph'])
283272
284273
// 状态管理
285274
const graphStore = useGraphStore()
275+
const databaseStore = useDatabaseStore()
286276
287277
// 响应式引用
288278
const loading = ref(false)
@@ -714,9 +704,13 @@ const loadGraphData = async () => {
714704
715705
// 设置图数据
716706
graphStore.setRawGraph(rawGraph)
707+
// 更新 displayed 计数(当前视图)以及来自后端的 total 计数(整个库)
717708
graphStore.stats = {
718709
displayed_nodes: graphResponse.data.nodes.length,
719710
displayed_edges: graphResponse.data.edges.length,
711+
// 从 statsResponse 填充整个知识库的统计信息(后端返回 total_nodes/total_edges)
712+
total_nodes: statsResponse.data.total_nodes ?? graphStore.stats.total_nodes ?? 0,
713+
total_edges: statsResponse.data.total_edges ?? graphStore.stats.total_edges ?? 0,
720714
is_truncated: graphResponse.data.is_truncated
721715
}
722716
@@ -755,82 +749,6 @@ const loadGraphData = async () => {
755749
}
756750
}
757751
758-
// 加载测试数据
759-
const loadTestData = async () => {
760-
if (!selectedDatabase.value) {
761-
message.warning('请先选择数据库')
762-
return
763-
}
764-
765-
loading.value = true
766-
loadingMessage.value = '加载测试数据中...'
767-
768-
try {
769-
const response = await fetch(`/api/graph/lightrag/test-data?db_id=${selectedDatabase.value}`, {
770-
headers: {
771-
'Authorization': `Bearer ${localStorage.getItem('access_token')}`,
772-
'Content-Type': 'application/json'
773-
}
774-
})
775-
776-
if (!response.ok) {
777-
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
778-
}
779-
780-
const testData = await response.json()
781-
782-
if (testData.success) {
783-
// 创建图数据
784-
const rawGraph = graphStore.createGraphFromApiData(
785-
testData.data.nodes,
786-
testData.data.edges
787-
)
788-
789-
// 设置图数据
790-
graphStore.setRawGraph(rawGraph)
791-
graphStore.stats = {
792-
displayed_nodes: testData.data.nodes.length,
793-
displayed_edges: testData.data.edges.length,
794-
is_truncated: testData.data.is_truncated
795-
}
796-
797-
console.log('Test graph created:', {
798-
nodes: rawGraph.nodes.length,
799-
edges: rawGraph.edges.length,
800-
sampleNode: rawGraph.nodes[0],
801-
sampleEdge: rawGraph.edges[0]
802-
})
803-
804-
// 创建Sigma图
805-
const sigmaGraph = graphStore.createSigmaGraph(rawGraph)
806-
graphStore.setSigmaGraph(sigmaGraph)
807-
808-
// 应用布局
809-
await applyLayout(sigmaGraph)
810-
811-
// 更新Sigma实例
812-
if (sigmaInstance) {
813-
sigmaInstance.setGraph(sigmaGraph)
814-
sigmaInstance.refresh()
815-
} else {
816-
await nextTick()
817-
await initSigma()
818-
}
819-
820-
message.success(`测试数据加载成功:${rawGraph.nodes.length} 个节点,${rawGraph.edges.length} 条边`)
821-
} else {
822-
throw new Error('Failed to load test data')
823-
}
824-
825-
} catch (error) {
826-
console.error('加载测试数据失败:', error)
827-
message.error('加载测试数据失败: ' + error.message)
828-
} finally {
829-
loading.value = false
830-
loadingMessage.value = '加载图数据中...'
831-
}
832-
}
833-
834752
// 加载完整图数据
835753
const loadFullGraph = async () => {
836754
selectedLabel.value = '*'
@@ -1277,7 +1195,7 @@ defineExpose({
12771195
12781196
.control-panel {
12791197
background: white;
1280-
padding: 8px 0; /* Reduced from 16px */
1198+
padding: 6px 16px; /* Reduced from 16px */
12811199
border-bottom: none;
12821200
display: flex;
12831201
gap: 12px; /* Reduced from 16px */
@@ -1301,9 +1219,9 @@ defineExpose({
13011219
13021220
.sigma-container {
13031221
flex: 1;
1304-
background: white;
1222+
// background: white;
13051223
position: relative; /* 确保子元素可以相对于此容器定位 */
1306-
border: 1px solid var(--main-20);
1224+
// border: 1px solid var(--main-20);
13071225
border-radius: 8px;
13081226
overflow: hidden;
13091227
@@ -1312,6 +1230,16 @@ defineExpose({
13121230
}
13131231
}
13141232
1233+
.graph-overlay-stats {
1234+
position: absolute;
1235+
left: 16px;
1236+
bottom: 16px;
1237+
display: flex;
1238+
gap: 8px;
1239+
pointer-events: none;
1240+
z-index: 1100;
1241+
}
1242+
13151243
.detail-panel {
13161244
position: absolute;
13171245
width: 240px; /* Reduced from 300px */
@@ -1546,4 +1474,4 @@ defineExpose({
15461474
font-size: 12px; /* Added smaller font size */
15471475
}
15481476
}
1549-
</style>
1477+
</style>

web/src/stores/database.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ export const useDatabaseStore = defineStore('database', () => {
1818
const queryParams = ref([]);
1919
const meta = reactive({});
2020
const graphStats = ref({
21+
total_nodes: 0,
22+
total_edges: 0,
2123
displayed_nodes: 0,
2224
displayed_edges: 0,
2325
is_truncated: false,
@@ -35,7 +37,6 @@ export const useDatabaseStore = defineStore('database', () => {
3537
chunkLoading: false,
3638
autoRefresh: false,
3739
queryParamsLoading: false,
38-
isGraphMaximized: false,
3940
rightPanelVisible: true,
4041
});
4142

0 commit comments

Comments
 (0)