feat(web): user memory & detail ui upgrade

This commit is contained in:
zhaoying
2026-03-07 14:59:58 +08:00
parent 6d53d9178c
commit d68bbab419
10 changed files with 359 additions and 422 deletions

View File

@@ -1,8 +1,8 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-03 17:57:26
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-03 17:57:26
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-09 14:28:34
*/
/**
* Neo4j User Memory Detail View
@@ -10,12 +10,12 @@
* Shows profile, interests, node statistics, relationships, and insights
*/
import { type FC, useRef, useState } from 'react'
import { useParams } from 'react-router-dom'
import { Row, Col, Space, Button } from 'antd'
import { type FC, useRef, useState, type MouseEvent } from 'react'
import clsx from 'clsx'
import { useParams, useNavigate } from 'react-router-dom'
import { Flex, Popover } from 'antd'
import { useTranslation } from 'react-i18next';
import PageHeader from './components/PageHeader'
import EndUserProfile from './components/EndUserProfile'
import AboutMe from './components/AboutMe'
import InterestDistribution from './components/InterestDistribution'
@@ -28,21 +28,29 @@ import {
} from '@/api/memory'
const Neo4j: FC = () => {
const { t } = useTranslation();
const { id } = useParams()
const { t } = useTranslation();
const navigate = useNavigate();
const [loading, setLoading] = useState(false)
const [name, setName] = useState('')
const ref = useRef<EndUserProfileRef>(null)
const memoryInsightRef = useRef<MemoryInsightRef>(null)
const aboutMeRef = useRef<AboutMeRef>(null)
const [selectedKey, setSelectedKey] = useState<string | null>(null)
/** Update displayed name */
const handleNameUpdate = (data: { other_name?: string; id: string }) => {
setName(data.other_name && data.other_name !== '' ? data.other_name : data.id)
}
/** Navigate back */
const goBack = () => {
navigate('/user-memory', { replace: true })
}
/** Refresh analytics data */
const handleRefresh = () => {
if (loading) return;
setLoading(true)
analyticsRefresh(id as string)
.then(res => {
@@ -59,43 +67,104 @@ const Neo4j: FC = () => {
})
}
const onOpenChange = (e: MouseEvent, type: string) => {
e.preventDefault();
e.stopPropagation();
setSelectedKey(type)
}
return (
<div className="rb:h-full rb:w-full">
<PageHeader
name={name}
operation={(
<Button
loading={loading}
className="rb:group rb:h-7! rb:bg-transparent! rb:border-[#5B6167] rb:text-[#5B6167] rb:ml-3"
onClick={handleRefresh}
>
{!loading && <div
className="rb:size-4 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/refresh.svg')] rb:group-hover:bg-[url('@/assets/images/refresh_hover.svg')]"
></div>}
{t('common.refresh')}
</Button>
)}
/>
<div className="rb:h-[calc(100vh-64px)] rb:overflow-y-auto rb:py-3 rb:px-4">
<Row gutter={16}>
<Col span={8}>
<Space size={16} direction="vertical" className="rb:w-full">
<EndUserProfile ref={ref} onDataLoaded={handleNameUpdate} />
<AboutMe ref={aboutMeRef} />
<InterestDistribution />
</Space>
</Col>
<Col span={16}>
<Space size={16} direction="vertical" className="rb:w-full">
<NodeStatistics />
<RelationshipNetwork />
<MemoryInsight ref={memoryInsightRef} />
</Space>
</Col>
</Row>
</div>
<div className="rb:h-screen rb:w-screen rb:p-3 rb:relative" onClick={() => setSelectedKey(null)}>
<Flex className="rb:h-[calc(100vh-24px)]" gap={12}>
<Flex gap={15} vertical justify="space-between" align="center" className="rb:h-full! rb:px-4! rb:pt-6! rb:pb-5! rb:bg-white rb:w-20 rb:rounded-xl">
<Flex gap={15} vertical>
<Popover
content={t('userMemory.memoryWindow', { name: name })}
placement="right"
arrow={false}
trigger="hover"
>
<div className="rb:mb-4.25! rb:size-12 rb:rounded-xl rb:bg-cover rb:bg-[url('@/assets/images/userMemory/logo.png')]"></div>
</Popover>
<Flex
align="center"
justify="center"
className={clsx("rb:cursor-pointer rb:size-12 rb:rounded-xl rb:group", {
'rb:bg-[#155EEF]': selectedKey === 'userProfile',
'rb:hover:bg-[#F0F3F8]': selectedKey !== 'userProfile',
})}
onClick={(e) => onOpenChange(e, 'userProfile')}
>
<div className={clsx("rb:size-6 rb:bg-cover", {
"rb:bg-[url('@/assets/images/userMemory/userProfile.svg')]": selectedKey !== 'userProfile',
"rb:bg-[url('@/assets/images/userMemory/userProfile_active.svg')]": selectedKey === 'userProfile'
})}></div>
</Flex>
<Flex
align="center"
justify="center"
className={clsx("rb:cursor-pointer rb:size-12 rb:rounded-xl rb:group", {
'rb:bg-[#155EEF]': selectedKey === 'aboutMe',
'rb:hover:bg-[#F0F3F8]': selectedKey !== 'aboutMe',
})}
onClick={(e) => onOpenChange(e, 'aboutMe')}
>
<div className={clsx("rb:size-6 rb:bg-cover", {
"rb:bg-[url('@/assets/images/userMemory/aboutMe.svg')]": selectedKey !== 'aboutMe',
"rb:bg-[url('@/assets/images/userMemory/aboutMe_active.svg')]": selectedKey === 'aboutMe'
})}></div>
</Flex>
<Flex
align="center"
justify="center"
className={clsx("rb:cursor-pointer rb:size-12 rb:rounded-xl rb:group", {
'rb:bg-[#155EEF]': selectedKey === 'interestDistribution',
'rb:hover:bg-[#F0F3F8]': selectedKey !== 'interestDistribution',
})}
onClick={(e) => onOpenChange(e, 'interestDistribution')}
>
<div className={clsx("rb:size-6 rb:bg-cover", {
"rb:bg-[url('@/assets/images/userMemory/interestDistribution.svg')]": selectedKey !== 'interestDistribution',
"rb:bg-[url('@/assets/images/userMemory/interestDistribution_active.svg')]": selectedKey === 'interestDistribution'
})}></div>
</Flex>
<Flex
align="center"
justify="center"
className={clsx("rb:cursor-pointer rb:size-12 rb:rounded-xl rb:group", {
'rb:bg-[#155EEF]': selectedKey === 'memoryInsight',
'rb:hover:bg-[#F0F3F8]': selectedKey !== 'memoryInsight',
})}
onClick={(e) => onOpenChange(e, 'memoryInsight')}
>
<div className={clsx("rb:size-6 rb:bg-cover", {
"rb:bg-[url('@/assets/images/userMemory/memoryInsight.svg')]": selectedKey !== 'memoryInsight',
"rb:bg-[url('@/assets/images/userMemory/memoryInsight_active.svg')]": selectedKey === 'memoryInsight'
})}></div>
</Flex>
</Flex>
<Flex vertical gap={24}>
<div className={clsx("rb:cursor-pointer rb:size-6 rb:bg-cover rb:bg-[url('@/assets/images/userMemory/refresh.svg')]", {
"rb:animate-spin": loading
})} onClick={handleRefresh}></div>
<div className="rb:cursor-pointer rb:size-6 rb:bg-cover rb:bg-[url('@/assets/images/userMemory/logout.svg')]" onClick={goBack}></div>
</Flex>
</Flex>
<Flex vertical className="rb:flex-1">
<NodeStatistics />
<RelationshipNetwork />
</Flex>
</Flex>
<EndUserProfile ref={ref} onDataLoaded={handleNameUpdate} className={selectedKey === 'userProfile' ? 'rb:block!' : 'rb:hidden!'} />
<AboutMe ref={aboutMeRef} className={selectedKey === 'aboutMe' ? 'rb:block!' : 'rb:hidden!'} />
<InterestDistribution className={selectedKey === 'interestDistribution' ? 'rb:block!' : 'rb:hidden!'} />
<MemoryInsight ref={memoryInsightRef} className={selectedKey === 'memoryInsight' ? 'rb:block!' : 'rb:hidden!'} />
</div>
)
}