optimize: UI update

This commit is contained in:
zhaoying
2025-12-16 11:26:41 +08:00
parent ea0a445d5b
commit 9b2f603454
10 changed files with 84 additions and 41 deletions

View File

@@ -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>
); );

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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>

View File

@@ -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={

View File

@@ -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>
) )

View File

@@ -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)]"

View File

@@ -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)]"

View File

@@ -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;

View File

@@ -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)
}
} }
} }
}} }}