optimize: UI update
This commit is contained in:
@@ -34,12 +34,12 @@ const ButtonCheckbox: FC<ButtonCheckboxProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx("rb:flex rb:items-center rb:border rb:rounded-[8px] rb:px-[8px] rb:text-[12px] rb:h-[24px] rb:cursor-pointer rb:hover:bg-[#F0F3F8]", {
|
<div className={clsx("rb:flex rb:items-center rb:border rb:rounded-lg rb:px-2 rb:text-[12px] rb:h-6 rb:cursor-pointer rb:hover:bg-[#F0F3F8]", {
|
||||||
"rb:bg-[rgba(21,94,239,0.06)] rb:border-[#155EEF] rb:text-[#155EEF]": checked,
|
"rb:bg-[rgba(21,94,239,0.06)] rb:border-[#155EEF] rb:text-[#155EEF]": checked,
|
||||||
"rb:border-[#DFE4ED] rb:text-[#212332]": !checked,
|
"rb:border-[#DFE4ED] rb:text-[#212332]": !checked,
|
||||||
})} onClick={handleChange}>
|
})} onClick={handleChange}>
|
||||||
{icon && !checked && <img src={icon} className="rb:w-[16px] rb:h-[16px] rb:mr-[4px]" />}
|
{icon && !checked && <img src={icon} className="rb:w-4 rb:h-4 rb:mr-1" />}
|
||||||
{checkedIcon && checked && <img src={checkedIcon} className="rb:w-[16px] rb:h-[16px] rb:mr-[4px]" />}
|
{checkedIcon && checked && <img src={checkedIcon} className="rb:w-4 rb:h-4 rb:mr-1" />}
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ interface ApiResponse<T> {
|
|||||||
items?: T[];
|
items?: T[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CustomSelectProps {
|
interface CustomSelectProps extends Omit<SelectProps, 'filterOption'> {
|
||||||
url: string;
|
url: string;
|
||||||
params?: Record<string, unknown>;
|
params?: Record<string, unknown>;
|
||||||
valueKey?: string;
|
valueKey?: string;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ interface PageScrollListProps {
|
|||||||
|
|
||||||
const PageScrollList = forwardRef<PageScrollListRef, PageScrollListProps>(({
|
const PageScrollList = forwardRef<PageScrollListRef, PageScrollListProps>(({
|
||||||
renderItem,
|
renderItem,
|
||||||
query = {},
|
query,
|
||||||
url,
|
url,
|
||||||
column = 4,
|
column = 4,
|
||||||
className = '',
|
className = '',
|
||||||
@@ -51,11 +51,11 @@ const PageScrollList = forwardRef<PageScrollListRef, PageScrollListProps>(({
|
|||||||
request.get(url, {
|
request.get(url, {
|
||||||
page: page,
|
page: page,
|
||||||
pagesize: PAGE_SIZE,
|
pagesize: PAGE_SIZE,
|
||||||
...query,
|
...(query||{}),
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
const response = res as ApiResponse;
|
const response = res as ApiResponse;
|
||||||
const results = Array.isArray(response.items) ? response.items : Array.isArray(response.hosts) ? response.hosts : Array.isArray(response) ? response : [];
|
const results = Array.isArray(response.items) ? response.items : Array.isArray(response) ? response : [];
|
||||||
if (flag) {
|
if (flag) {
|
||||||
setData(results);
|
setData(results);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const colors = {
|
|||||||
|
|
||||||
const RbAlert: FC<RbAlertProps> = ({ color = 'blue', icon, className, children }) => {
|
const RbAlert: FC<RbAlertProps> = ({ color = 'blue', icon, className, children }) => {
|
||||||
return (
|
return (
|
||||||
<div className={`${colors[color]} ${className} rb:p-[6px_9px] rb:flex rb:items-center rb:text-[12px] rb:font-regular rb:leading-[16px] rb:border-[1px] rb:rounded-[6px]`}>
|
<div className={`${colors[color]} ${className} rb:p-[6px_9px] rb:flex rb:items-center rb:text-[12px] rb:font-regular rb:leading-4 rb:border rb:rounded-md`}>
|
||||||
{icon && <span className="rb:text-[16px] rb:mr-[9px]">{icon}</span>}
|
{icon && <span className="rb:text-[16px] rb:mr-[9px]">{icon}</span>}
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ const RbCard: FC<RbCardProps> = ({
|
|||||||
title={typeof title === 'function' ? title() : title ?
|
title={typeof title === 'function' ? title() : title ?
|
||||||
<div className="rb:flex rb:items-center">
|
<div className="rb:flex rb:items-center">
|
||||||
{avatarUrl
|
{avatarUrl
|
||||||
? <img src={avatarUrl} className="rb:mr-[13px] rb:w-[48px] rb:h-[48px] rb:rounded-[8px]" />
|
? <img src={avatarUrl} className="rb:mr-3.25 rb:w-12 rb:h-12 rb:rounded-lg" />
|
||||||
: avatar ? avatar : null
|
: avatar ? avatar : null
|
||||||
}
|
}
|
||||||
<div className={
|
<div className={
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { type FC, type ReactNode } from 'react'
|
import { type FC, type ReactNode } from 'react'
|
||||||
|
|
||||||
interface TagProps {
|
export interface TagProps {
|
||||||
color?: 'processing' | 'error' | 'success' | 'warning' | 'default',
|
color?: 'processing' | 'error' | 'success' | 'warning' | 'default',
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
@@ -16,7 +16,7 @@ const colors = {
|
|||||||
|
|
||||||
const Tag: FC<TagProps> = ({ color = 'processing', children, className }) => {
|
const Tag: FC<TagProps> = ({ color = 'processing', children, className }) => {
|
||||||
return (
|
return (
|
||||||
<span className={`rb:inline-block rb:px-[4px] rb:py-[2px] rb:rounded-[4px] rb:text-[12px] rb:font-regular! rb:leading-[16px] rb:border-[1px] ${colors[color]} ${className || ''}`}>
|
<span className={`rb:inline-block rb:px-1 rb:py-0.5 rb:rounded-sm rb:text-[12px] rb:font-regular! rb:leading-4 rb:border ${colors[color]} ${className || ''}`}>
|
||||||
{children}
|
{children}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ const NoPermission = () => {
|
|||||||
return (
|
return (
|
||||||
<Empty
|
<Empty
|
||||||
url={noPermission}
|
url={noPermission}
|
||||||
|
size={[240, 240]}
|
||||||
title={t('empty.noPermission')}
|
title={t('empty.noPermission')}
|
||||||
subTitle={t('empty.noPermissionDesc')}
|
subTitle={t('empty.noPermissionDesc')}
|
||||||
className="rb:h-[calc(100vh-84px)]"
|
className="rb:h-[calc(100vh-84px)]"
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ const NotFound = () => {
|
|||||||
return (
|
return (
|
||||||
<Empty
|
<Empty
|
||||||
url={notFoundImg}
|
url={notFoundImg}
|
||||||
|
size={[328, 146]}
|
||||||
title={t('empty.notFound')}
|
title={t('empty.notFound')}
|
||||||
subTitle={t('empty.notFoundDesc')}
|
subTitle={t('empty.notFoundDesc')}
|
||||||
className="rb:h-[calc(100vh-84px)]"
|
className="rb:h-[calc(100vh-84px)]"
|
||||||
|
|||||||
@@ -7,16 +7,17 @@ export interface Data {
|
|||||||
other_address: string;
|
other_address: string;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
updated_at: string;
|
updated_at: string;
|
||||||
},
|
},
|
||||||
memory_num: {
|
memory_num: {
|
||||||
total: number;
|
total: number;
|
||||||
counts: {
|
counts: {
|
||||||
dialogue: number;
|
dialogue: number;
|
||||||
chunk: number;
|
chunk: number;
|
||||||
statement: number;
|
statement: number;
|
||||||
entity: number;
|
entity: number;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
name?: string;
|
||||||
}
|
}
|
||||||
export interface ConfigModalData {
|
export interface ConfigModalData {
|
||||||
llm: string;
|
llm: string;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { type FC, useEffect, useState, useRef } from 'react'
|
import React, { type FC, useEffect, useState, useRef, useCallback } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useParams } from 'react-router-dom'
|
import { useParams } from 'react-router-dom'
|
||||||
import { Col } from 'antd'
|
import { Col } from 'antd'
|
||||||
@@ -29,13 +29,9 @@ const RelationshipNetwork:FC = () => {
|
|||||||
const [categories, setCategories] = useState<{ name: string }[]>([])
|
const [categories, setCategories] = useState<{ name: string }[]>([])
|
||||||
const [selectedNode, setSelectedNode] = useState<Node | null>(null)
|
const [selectedNode, setSelectedNode] = useState<Node | null>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!id) return
|
|
||||||
getEdgeData()
|
|
||||||
}, [id])
|
|
||||||
|
|
||||||
// 关系网络
|
// 关系网络
|
||||||
const getEdgeData = () => {
|
const getEdgeData = useCallback(() => {
|
||||||
if (!id) return
|
if (!id) return
|
||||||
setSelectedNode(null)
|
setSelectedNode(null)
|
||||||
getMemorySearchEdges(id).then((res) => {
|
getMemorySearchEdges(id).then((res) => {
|
||||||
@@ -45,20 +41,20 @@ const RelationshipNetwork:FC = () => {
|
|||||||
const categories: { name: string }[] = []
|
const categories: { name: string }[] = []
|
||||||
|
|
||||||
list.forEach(item => {
|
list.forEach(item => {
|
||||||
if (item.edge) {
|
if (item.edge && item.edge.target_id && item.edge.source_id) {
|
||||||
links.push({
|
links.push({
|
||||||
...item.edge,
|
...item.edge,
|
||||||
target: item.edge?.target_id,
|
target: item.edge.target_id,
|
||||||
source: item.edge?.source_id,
|
source: item.edge.source_id,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (item.sourceNode) {
|
if (item.sourceNode) {
|
||||||
nodes.push(item.sourceNode)
|
nodes.push(item.sourceNode)
|
||||||
categories.push({name: item.sourceNode.entity_type})
|
categories.push({name: item.sourceNode.entity_type || 'Unknown'})
|
||||||
}
|
}
|
||||||
if (item.targetNode) {
|
if (item.targetNode) {
|
||||||
nodes.push(item.targetNode)
|
nodes.push(item.targetNode)
|
||||||
categories.push({name: item.targetNode.entity_type})
|
categories.push({name: item.targetNode.entity_type || 'Unknown'})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -76,14 +72,58 @@ const RelationshipNetwork:FC = () => {
|
|||||||
setLinks(uniqueLinks)
|
setLinks(uniqueLinks)
|
||||||
setCategories(uniqueCategories)
|
setCategories(uniqueCategories)
|
||||||
|
|
||||||
|
// Calculate node frequency based on appearance in links
|
||||||
|
const nodeFrequency = new Map<string, number>()
|
||||||
|
|
||||||
|
// Count each node's appearance in links (both as source and target)
|
||||||
|
uniqueLinks.forEach(link => {
|
||||||
|
// Increment source node frequency (only if source exists and is a string)
|
||||||
|
if (typeof link.source === 'string') {
|
||||||
|
nodeFrequency.set(link.source, (nodeFrequency.get(link.source) || 0) + 1)
|
||||||
|
}
|
||||||
|
// Increment target node frequency (only if target exists and is a string)
|
||||||
|
if (typeof link.target === 'string') {
|
||||||
|
nodeFrequency.set(link.target, (nodeFrequency.get(link.target) || 0) + 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Set minimum frequency to 1 for nodes not in any links
|
||||||
|
uniqueNodes.forEach(node => {
|
||||||
|
if (node.id && typeof node.id === 'string') {
|
||||||
|
if (!nodeFrequency.has(node.id)) {
|
||||||
|
nodeFrequency.set(node.id, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
uniqueNodes.map(item => {
|
uniqueNodes.map(item => {
|
||||||
const index = uniqueCategories.findIndex((n) => n.name === item.entity_type)
|
const index = uniqueCategories.findIndex((n) => n.name === (item.entity_type || 'Unknown'))
|
||||||
item.category = index
|
item.category = index
|
||||||
item.symbolSize = index < 10 ? 5 : index <100 ? 8 : 10
|
|
||||||
|
// Get frequency for the node, ensuring id is a string
|
||||||
|
const frequency = (item.id && typeof item.id === 'string') ? (nodeFrequency.get(item.id) || 1) : 1
|
||||||
|
|
||||||
|
// Set symbolSize based on frequency
|
||||||
|
// Adjust these thresholds based on expected frequency ranges
|
||||||
|
if (frequency <= 1) {
|
||||||
|
item.symbolSize = 5
|
||||||
|
} else if (frequency <= 10) {
|
||||||
|
item.symbolSize = 10
|
||||||
|
} else if (frequency <= 15) {
|
||||||
|
item.symbolSize = 15
|
||||||
|
} else if (frequency <= 20) {
|
||||||
|
item.symbolSize = 25
|
||||||
|
} else {
|
||||||
|
item.symbolSize = 35
|
||||||
|
}
|
||||||
})
|
})
|
||||||
setNodes(uniqueNodes)
|
setNodes(uniqueNodes)
|
||||||
})
|
})
|
||||||
}
|
}, [id])
|
||||||
|
useEffect(() => {
|
||||||
|
if (!id) return
|
||||||
|
getEdgeData()
|
||||||
|
}, [id])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleResize = () => {
|
const handleResize = () => {
|
||||||
@@ -95,7 +135,7 @@ const RelationshipNetwork:FC = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const resizeObserver = new ResizeObserver(handleResize)
|
const resizeObserver = new ResizeObserver(handleResize)
|
||||||
const chartElement = chartRef.current?.getEchartsInstance().getDom().parentElement
|
const chartElement = chartRef.current?.getEchartsInstance().getDom().parentElement
|
||||||
if (chartElement) {
|
if (chartElement) {
|
||||||
@@ -106,6 +146,8 @@ const RelationshipNetwork:FC = () => {
|
|||||||
resizeObserver.disconnect()
|
resizeObserver.disconnect()
|
||||||
}
|
}
|
||||||
}, [nodes])
|
}, [nodes])
|
||||||
|
|
||||||
|
console.log('nodes', nodes)
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* 关系网络 */}
|
{/* 关系网络 */}
|
||||||
@@ -175,12 +217,10 @@ const RelationshipNetwork:FC = () => {
|
|||||||
if (params.dataType === 'node') {
|
if (params.dataType === 'node') {
|
||||||
// 处理节点点击事件
|
// 处理节点点击事件
|
||||||
console.log('Node clicked:', params.data);
|
console.log('Node clicked:', params.data);
|
||||||
setSelectedNode(params.data)
|
// 使用函数式更新避免状态依赖问题
|
||||||
if (selectedNode?.id === params.data.id) {
|
setSelectedNode(prevSelected =>
|
||||||
setSelectedNode(null)
|
prevSelected?.id === params.data.id ? null : params.data
|
||||||
} else {
|
)
|
||||||
setSelectedNode(params.data)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|||||||
Reference in New Issue
Block a user