357 lines
8.5 KiB
TypeScript
357 lines
8.5 KiB
TypeScript
import { useChartHooks } from '@/views/knowledge/hooks/chart.ts'
|
||
import { computed, ref } from 'vue'
|
||
import { router } from "@/router/index.ts";
|
||
import { createData } from './mockData'
|
||
|
||
|
||
// 存储已生成的颜色,确保不重复
|
||
const usedColors = new Set<string>()
|
||
|
||
/**
|
||
* 生成随机且不重复的颜色
|
||
* @returns 十六进制颜色值
|
||
*/
|
||
const generateRandomColor = (): string => {
|
||
// 生成随机颜色
|
||
const generateColor = (): string => {
|
||
// 生成更亮的颜色,避免太暗
|
||
const r = Math.floor(Math.random() * 155) + 100
|
||
const g = Math.floor(Math.random() * 155) + 100
|
||
const b = Math.floor(Math.random() * 155) + 100
|
||
return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`
|
||
}
|
||
|
||
let color: string
|
||
let attempts = 0
|
||
|
||
// 尝试生成不重复的颜色,最多尝试100次
|
||
do {
|
||
color = generateColor()
|
||
attempts++
|
||
} while (usedColors.has(color) && attempts < 100)
|
||
|
||
// 如果尝试次数过多,清空已使用的颜色重新开始
|
||
if (attempts >= 100) {
|
||
usedColors.clear()
|
||
color = generateColor()
|
||
}
|
||
|
||
usedColors.add(color)
|
||
return color
|
||
}
|
||
|
||
/**
|
||
* 为关系类型生成颜色映射
|
||
*/
|
||
const relationColors = ref<Map<string, string>>(new Map())
|
||
|
||
/**
|
||
* 获取关系类型对应的颜色
|
||
*/
|
||
const getRelationColor = (type: string): string => {
|
||
if (!relationColors.value.has(type)) {
|
||
relationColors.value.set(type, generateRandomColor())
|
||
}
|
||
return relationColors.value.get(type) || '#000000'
|
||
}
|
||
|
||
/**
|
||
* 为节点类型生成颜色映射
|
||
*/
|
||
const nodeColors = ref<Map<string, string>>(new Map())
|
||
|
||
/**
|
||
* 获取节点类型对应的颜色
|
||
*/
|
||
const getNodeColor = (type: string): string => {
|
||
if (!nodeColors.value.has(type)) {
|
||
nodeColors.value.set(type, generateRandomColor())
|
||
}
|
||
return nodeColors.value.get(type) || '#000000'
|
||
}
|
||
|
||
|
||
export const useChartServices = () => {
|
||
|
||
const { option, createPointData, createLink} = useChartHooks()
|
||
|
||
// 图表原始数据
|
||
const chatData = ref({})
|
||
|
||
// 类型字典集合
|
||
const typesMap = ref<string[]>([])
|
||
|
||
// 节点集合
|
||
const nodes = ref<Record<string, any>[]>([])
|
||
|
||
// 节点字典集合
|
||
const nodesMap = computed(() => {
|
||
const dataMap = new Map()
|
||
nodes.value.forEach((node) => {
|
||
if (!dataMap.has(node.id)) {
|
||
dataMap.set(node.id, node)
|
||
}
|
||
})
|
||
return dataMap
|
||
})
|
||
|
||
// 关系字典集合
|
||
const relationMap = computed(() => {
|
||
const dataMap = new Map()
|
||
console.log('relationMap', relations.value)
|
||
relations.value.forEach((relation) => {
|
||
if (!dataMap.has(relation.id)) {
|
||
dataMap.set(relation.raw.id, relation)
|
||
}
|
||
})
|
||
return dataMap
|
||
})
|
||
|
||
// 关系节点集合
|
||
const relations = ref<Record<string, any>[]>([])
|
||
|
||
// 数据规整
|
||
const chartConfig = {
|
||
chatData,
|
||
relationMap: relationMap,
|
||
typesMap,
|
||
nodes,
|
||
relations
|
||
}
|
||
|
||
// 选中的类型
|
||
const selectTypes = ref<string[]>([])
|
||
|
||
// 选中的关系
|
||
const selectRelations = ref<string[]>([])
|
||
|
||
// 切换选中类型
|
||
const toggleSelectType = (type: string) => {
|
||
const i = selectTypes.value.indexOf(type)
|
||
if (i > -1) {
|
||
selectTypes.value.splice(i, 1)
|
||
} else {
|
||
selectTypes.value.push(type)
|
||
}
|
||
}
|
||
|
||
// 切换选中关系
|
||
const toggleRelation = (relation: string) => {
|
||
const i = selectRelations.value.indexOf(relation)
|
||
if (i > -1) {
|
||
selectRelations.value.splice(i, 1)
|
||
} else {
|
||
selectRelations.value.push(relation)
|
||
}
|
||
}
|
||
|
||
// 重置数据
|
||
const resetData = () => {
|
||
chatData.value = {}
|
||
relations.value = []
|
||
typesMap.value = []
|
||
nodes.value = []
|
||
// 重置颜色映射,以便下次生成新的颜色
|
||
relationColors.value.clear()
|
||
nodeColors.value.clear()
|
||
}
|
||
|
||
// 新增类型,已存在则跳过
|
||
const addTypeMap = (data: Record<string, any>) => {
|
||
if (typesMap.value.includes(data.labels)) return
|
||
typesMap.value.push(data.labels)
|
||
}
|
||
|
||
// 处理数据
|
||
const handleData = (data: Record<string, any>) => {
|
||
const { nodes: rawNodes, relationships } = data
|
||
rawNodes.forEach((node: Record<string, any>) => {
|
||
addTypeMap(node)
|
||
// 获取节点类型对应的颜色
|
||
const nodeColor = getNodeColor(node.labels)
|
||
const nodeInfo = createPointData({
|
||
...node,
|
||
type: node.labels,
|
||
name: node.id,
|
||
itemStyle: {
|
||
color: nodeColor
|
||
},
|
||
// name: node.properties.name
|
||
})
|
||
nodes.value.push(nodeInfo)
|
||
})
|
||
relationships.forEach((relation: Record<string, any>) => {
|
||
// addRelationMap(relation)
|
||
// 获取关系类型对应的颜色
|
||
const relationColor = getRelationColor(relation.type)
|
||
const link = createLink({
|
||
...relation,
|
||
parentIndex: getNodeIndex(relation.start_node_id),
|
||
index: getNodeIndex(relation.end_node_id),
|
||
type: relation.type,
|
||
lineStyle: {
|
||
color: relationColor,
|
||
width: 2 // 关系线条宽度
|
||
},
|
||
itemStyle: {
|
||
color: relationColor
|
||
}
|
||
})
|
||
relations.value.push(link)
|
||
})
|
||
}
|
||
|
||
// 获取节点索引
|
||
const getNodeIndex = (id: string, source?: Record<string, any>) => {
|
||
return (source || nodes.value).findIndex((item:Record<string, any>) => item.id === id)
|
||
}
|
||
|
||
// 显示用的数据
|
||
const showData = computed(() => {
|
||
// 生成带有颜色的分类配置
|
||
// const categoriesWithColor = relationsMap.value.map(item => ({
|
||
// name: item,
|
||
// itemStyle: {
|
||
// normal: {
|
||
// color: getRelationColor(item)
|
||
// }
|
||
// }
|
||
// }))
|
||
|
||
// 为每个节点添加category索引,使其与对应关系类型关联
|
||
const nodesWithCategory = nodes.value.map(node => ({
|
||
...node,
|
||
// category: relationsMap.value.indexOf(node.type) !== -1 ?
|
||
// relationsMap.value.indexOf(node.type) : 0
|
||
}))
|
||
|
||
const useData = {
|
||
...option.value,
|
||
series: [
|
||
{
|
||
...option.value.series[0],
|
||
// categories: categoriesWithColor,
|
||
data: nodesWithCategory,
|
||
links: relations.value,
|
||
}
|
||
]
|
||
}
|
||
|
||
console.log('useData', useData)
|
||
return useData
|
||
})
|
||
|
||
|
||
const getDataPath = () => {
|
||
const { id } = router.currentRoute.value.query;
|
||
const jsonMap: Record<string, any> = {
|
||
'1': 'http://222.190.139.186:10001/public/demo/knowledge-chat/neo4j_export2.json',
|
||
'2': 'http://222.190.139.186:10001/public/demo/knowledge-chat/neo4j_export.json'
|
||
}
|
||
return jsonMap[id as string] || jsonMap[2]
|
||
}
|
||
|
||
const getMockData = () => {
|
||
const data = createData()
|
||
return data
|
||
|
||
}
|
||
|
||
|
||
const getData = async () => {
|
||
// const path = getDataPath()
|
||
// const res = await fetch(path)
|
||
// const mockData = await res.json()
|
||
const mockData = getMockData()
|
||
console.log('mockData', mockData)
|
||
chatData.value = mockData
|
||
handleData(chatData.value)
|
||
return mockData
|
||
}
|
||
|
||
// 获取节点关系
|
||
const getNodeRelationById = (id: string) => {
|
||
console.log('relations', relationMap.value)
|
||
const relationNode = []
|
||
|
||
relations.value.forEach((item: Record<string, any>) => {
|
||
if (item.raw.end_node_id == id || item.raw.start_node_id == id) {
|
||
let targetNodeId = null
|
||
// 如果是起始点, 相关点是终点
|
||
if (item.raw.start_node_id === id) {
|
||
targetNodeId = item.raw.end_node_id
|
||
} else {
|
||
// 如果是终点, 相关点是起始点
|
||
targetNodeId = item.raw.start_node_id
|
||
}
|
||
const nodeInfo = getNodeById(targetNodeId)
|
||
if (!nodeInfo) return
|
||
const params = {
|
||
type: item.raw.type,
|
||
node: nodeInfo.raw,
|
||
relation: item.raw
|
||
}
|
||
relationNode.push(params)
|
||
}
|
||
|
||
// 如果是起始点
|
||
// 如果是终点
|
||
// if (item.start_node_id === id) {
|
||
// targets.push(item)
|
||
// } else if (item.end_node_id === id) {
|
||
// ends.push(item)
|
||
// }
|
||
})
|
||
return relationNode
|
||
|
||
}
|
||
|
||
// 获取节点信息
|
||
const getNodeById = (id: string) => {
|
||
if (!id) return
|
||
return nodesMap.value.get(id)
|
||
}
|
||
|
||
|
||
|
||
|
||
const searchValue = ref('')
|
||
|
||
// 显示节点
|
||
const onShowNodeEven = () => {
|
||
|
||
}
|
||
// 隐藏节点
|
||
const onHideNodeEven = () => {}
|
||
|
||
|
||
|
||
const state = {
|
||
option,
|
||
showData,
|
||
chartConfig,
|
||
relationColors,
|
||
nodeColors,
|
||
searchValue
|
||
}
|
||
|
||
const api = {
|
||
getData,
|
||
handleData,
|
||
// addRelationMap,
|
||
addTypeMap,
|
||
resetData,
|
||
toggleSelectType,
|
||
toggleRelation,
|
||
getNodeById,
|
||
getNodeRelationById,
|
||
onShowNodeEven,
|
||
onHideNodeEven
|
||
}
|
||
|
||
return {
|
||
state,
|
||
api
|
||
}
|
||
}
|