graph.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import { defineStore } from 'pinia'
  2. import { ref, computed } from 'vue'
  3. // eslint-disable-next-line no-undef
  4. const graphDataRaw = __GRAPH_DATA__ // 由 vite.config.js 注入
  5. // eslint-disable-next-line no-undef
  6. const postGraphListRaw = __POST_GRAPH_LIST__ || [] // 帖子图谱列表
  7. console.log('人设图谱 loaded:', !!graphDataRaw)
  8. console.log('人设节点数:', Object.keys(graphDataRaw?.nodes || {}).length)
  9. console.log('帖子图谱数:', postGraphListRaw.length)
  10. export const useGraphStore = defineStore('graph', () => {
  11. // ==================== 人设图谱数据 ====================
  12. const graphData = ref(graphDataRaw || { nodes: {}, edges: {}, index: {}, tree: {} })
  13. // ==================== 帖子图谱数据 ====================
  14. const postGraphList = ref(postGraphListRaw)
  15. const selectedPostIndex = ref(postGraphListRaw.length > 0 ? 0 : -1)
  16. // 当前选中的帖子图谱
  17. const currentPostGraph = computed(() => {
  18. if (selectedPostIndex.value < 0 || selectedPostIndex.value >= postGraphList.value.length) {
  19. return null
  20. }
  21. return postGraphList.value[selectedPostIndex.value]
  22. })
  23. // 帖子列表(用于下拉选择)
  24. const postList = computed(() => {
  25. return postGraphList.value.map((post, index) => ({
  26. index,
  27. postId: post.meta?.postId,
  28. postTitle: post.meta?.postTitle || post.meta?.postId,
  29. createTime: post.meta?.postDetail?.create_time
  30. }))
  31. })
  32. // 选择帖子
  33. function selectPost(index) {
  34. selectedPostIndex.value = index
  35. // 清除帖子相关的选中状态
  36. selectedPostNodeId.value = null
  37. highlightedPostNodeIds.value = new Set()
  38. }
  39. // ==================== 帖子树选中状态 ====================
  40. const selectedPostNodeId = ref(null)
  41. const highlightedPostNodeIds = ref(new Set())
  42. // 获取帖子节点
  43. function getPostNode(nodeId) {
  44. return currentPostGraph.value?.nodes?.[nodeId]
  45. }
  46. // 选中帖子节点
  47. function selectPostNode(nodeId) {
  48. selectedPostNodeId.value = nodeId
  49. highlightedPostNodeIds.value = new Set([nodeId])
  50. }
  51. // 清除帖子选中
  52. function clearPostSelection() {
  53. selectedPostNodeId.value = null
  54. highlightedPostNodeIds.value = new Set()
  55. }
  56. // 当前选中的节点
  57. const selectedNodeId = ref(null)
  58. // 高亮的节点ID集合
  59. const highlightedNodeIds = ref(new Set())
  60. // 获取节点
  61. function getNode(nodeId) {
  62. return graphData.value.nodes[nodeId]
  63. }
  64. // 获取邻居节点
  65. function getNeighbors(nodeId, direction = 'both') {
  66. const neighbors = []
  67. const seen = new Set()
  68. const index = graphData.value.index
  69. if (direction === 'out' || direction === 'both') {
  70. const outEdges = index.outEdges?.[nodeId] || {}
  71. for (const [edgeType, targets] of Object.entries(outEdges)) {
  72. for (const t of targets) {
  73. if (!seen.has(t.target)) {
  74. seen.add(t.target)
  75. neighbors.push({
  76. nodeId: t.target,
  77. edgeType,
  78. direction: 'out',
  79. score: t.score
  80. })
  81. }
  82. }
  83. }
  84. }
  85. if (direction === 'in' || direction === 'both') {
  86. const inEdges = index.inEdges?.[nodeId] || {}
  87. for (const [edgeType, sources] of Object.entries(inEdges)) {
  88. for (const s of sources) {
  89. if (!seen.has(s.source)) {
  90. seen.add(s.source)
  91. neighbors.push({
  92. nodeId: s.source,
  93. edgeType,
  94. direction: 'in',
  95. score: s.score
  96. })
  97. }
  98. }
  99. }
  100. }
  101. return neighbors
  102. }
  103. // 选中节点
  104. function selectNode(nodeId) {
  105. selectedNodeId.value = nodeId
  106. // 更新高亮节点(邻居)
  107. const neighbors = getNeighbors(nodeId)
  108. highlightedNodeIds.value = new Set(neighbors.map(n => n.nodeId))
  109. }
  110. // 清除选中
  111. function clearSelection() {
  112. selectedNodeId.value = null
  113. highlightedNodeIds.value = new Set()
  114. }
  115. // 计算属性:当前选中节点的数据
  116. const selectedNode = computed(() => {
  117. return selectedNodeId.value ? getNode(selectedNodeId.value) : null
  118. })
  119. // 计算属性:树数据
  120. const treeData = computed(() => graphData.value.tree)
  121. // 帖子树数据
  122. const postTreeData = computed(() => currentPostGraph.value?.tree)
  123. return {
  124. // 人设图谱
  125. graphData,
  126. selectedNodeId,
  127. highlightedNodeIds,
  128. selectedNode,
  129. treeData,
  130. getNode,
  131. getNeighbors,
  132. selectNode,
  133. clearSelection,
  134. // 帖子图谱
  135. postGraphList,
  136. postList,
  137. selectedPostIndex,
  138. currentPostGraph,
  139. postTreeData,
  140. selectPost,
  141. selectedPostNodeId,
  142. highlightedPostNodeIds,
  143. getPostNode,
  144. selectPostNode,
  145. clearPostSelection
  146. }
  147. })