feat(web): end user list support page
This commit is contained in:
@@ -2,51 +2,36 @@
|
||||
* @Author: ZhaoYing
|
||||
* @Date: 2026-02-03 17:53:44
|
||||
* @Last Modified by: ZhaoYing
|
||||
* @Last Modified time: 2026-03-26 14:58:48
|
||||
* @Last Modified time: 2026-03-31 12:15:59
|
||||
*/
|
||||
/**
|
||||
* User Memory Page
|
||||
* Displays list of end users with their memory statistics and configuration
|
||||
*/
|
||||
|
||||
import { useEffect, useState, useMemo } from 'react';
|
||||
import { useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { Row, Col, Form, Flex, Tooltip } from 'antd';
|
||||
|
||||
import type { Data } from './types'
|
||||
import { getUserMemoryList } from '@/api/memory';
|
||||
import { userMemoryListUrl } from '@/api/memory';
|
||||
import { useUser } from '@/store/user'
|
||||
import RbCard from '@/components/RbCard/Card'
|
||||
import SearchInput from '@/components/SearchInput';
|
||||
import RbStatistic from '@/components/RbStatistic';
|
||||
import BodyWrapper from '@/components/Empty/BodyWrapper'
|
||||
import PageScrollList, { type PageScrollListRef } from '@/components/PageScrollList'
|
||||
|
||||
export default function UserMemory() {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate()
|
||||
const { storageType } = useUser()
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [data, setData] = useState<Data[]>([]);
|
||||
|
||||
const [form] = Form.useForm()
|
||||
const search = Form.useWatch(['search'], form)
|
||||
const keyword = Form.useWatch(['keyword'], form)
|
||||
|
||||
/** Fetch user memory list */
|
||||
useEffect(() => {
|
||||
getData()
|
||||
}, []);
|
||||
const scrollListRef = useRef<PageScrollListRef>(null)
|
||||
|
||||
/** Get data from API */
|
||||
const getData = () => {
|
||||
setLoading(true)
|
||||
getUserMemoryList().then((res) => {
|
||||
setData(res as Data[] || [])
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false)
|
||||
})
|
||||
}
|
||||
/** Navigate to user memory detail */
|
||||
const handleViewDetail = (id: string | number) => {
|
||||
switch (storageType) {
|
||||
@@ -64,25 +49,12 @@ export default function UserMemory() {
|
||||
navigate(`/memory`)
|
||||
}
|
||||
|
||||
/** Filter data by search term */
|
||||
const filterData = useMemo(() => {
|
||||
if (search && search.trim() !== '') {
|
||||
return data.filter((item) => {
|
||||
const { end_user } = item as Data;
|
||||
const name = end_user?.other_name && end_user?.other_name !== '' ? end_user?.other_name : end_user?.id
|
||||
return name?.includes(search)
|
||||
})
|
||||
}
|
||||
|
||||
return data
|
||||
}, [search, data])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Form form={form}>
|
||||
<Row gutter={16} className="rb:mb-4">
|
||||
<Col span={8}>
|
||||
<Form.Item name="search" noStyle>
|
||||
<Form.Item name="keyword" noStyle>
|
||||
<SearchInput
|
||||
placeholder={t('userMemory.searchPlaceholder')}
|
||||
className="rb:w-full!"
|
||||
@@ -91,52 +63,52 @@ export default function UserMemory() {
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
<BodyWrapper loading={loading} empty={data.length === 0}>
|
||||
<Row
|
||||
gutter={[12, 12]}
|
||||
className="rb:max-h-[calc(100%-48px)] rb:overflow-y-auto"
|
||||
>
|
||||
{filterData.map((item, index) => {
|
||||
const { end_user, memory_num, memory_config } = item as Data;
|
||||
const name = end_user?.other_name && end_user?.other_name !== '' ? end_user?.other_name : end_user?.id
|
||||
return (
|
||||
<Col key={index} span={8}>
|
||||
<RbCard
|
||||
title={<Flex gap={4}>
|
||||
<div className="rb:size-6 rb:text-center rb:font-semibold rb:leading-6 rb:rounded-md rb:text-white rb:bg-[#155EEF]">{name[0]}</div>
|
||||
|
||||
<Tooltip title={name || '-'}><div className={`rb:flex-1 rb:text-ellipsis rb:overflow-hidden rb:whitespace-nowrap`}>{name || '-'}</div></Tooltip>
|
||||
</Flex>}
|
||||
headerType="border"
|
||||
headerClassName="rb:h-[48px]! rb:mx-4!"
|
||||
bodyClassName="rb:py-3! rb:px-4!"
|
||||
className="rb:cursor-pointer"
|
||||
onClick={() => handleViewDetail(end_user.id)}
|
||||
>
|
||||
<Row>
|
||||
<Col span={12}>
|
||||
<RbStatistic title={t('userMemory.capacity')} value={memory_num?.total || 0} suffix={t('userMemory.memoryNum')} />
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<RbStatistic title={t('userMemory.type')} value={t(`userMemory.${item.type || 'person'}`)} />
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<PageScrollList<Data, { keyword: string; }>
|
||||
ref={scrollListRef}
|
||||
url={userMemoryListUrl}
|
||||
query={{ keyword }}
|
||||
column={3}
|
||||
renderItem={(item) => {
|
||||
const { end_user, memory_num, memory_config } = item as Data;
|
||||
const name = end_user?.other_name && end_user?.other_name !== '' ? end_user?.other_name : end_user?.id
|
||||
return (
|
||||
<RbCard
|
||||
key={item.end_user.id}
|
||||
title={<Flex gap={4}>
|
||||
<div className="rb:size-6 rb:text-center rb:font-semibold rb:leading-6 rb:rounded-md rb:text-white rb:bg-[#155EEF]">{name[0]}</div>
|
||||
|
||||
<div className="rb:relative rb:z-2 rb:mt-3 rb:bg-[#F6F6F6] rb:rounded-lg rb:py-2 rb:px-3 rb:leading-5" onClick={handleViewMemoryConfig}>
|
||||
<Flex align="center" justify="space-between" className="rb:text-[#5B6167]">
|
||||
{t('userMemory.memory_config_name')}
|
||||
<div
|
||||
className="rb:size-5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/userMemory/arrow_right_dark.svg')]"
|
||||
></div>
|
||||
</Flex>
|
||||
<div className="rb:font-medium rb:text-[#212332] rb:mt-1">{memory_config?.memory_config_name || '-'}</div>
|
||||
</div>
|
||||
</RbCard>
|
||||
</Col>
|
||||
)
|
||||
})}
|
||||
</Row>
|
||||
</BodyWrapper>
|
||||
<Tooltip title={name || '-'}><div className={`rb:flex-1 rb:text-ellipsis rb:overflow-hidden rb:whitespace-nowrap`}>{name || '-'}</div></Tooltip>
|
||||
</Flex>}
|
||||
headerType="border"
|
||||
headerClassName="rb:h-[48px]! rb:mx-4!"
|
||||
bodyClassName="rb:py-3! rb:px-4!"
|
||||
className="rb:cursor-pointer"
|
||||
onClick={() => handleViewDetail(end_user.id)}
|
||||
>
|
||||
<Row>
|
||||
<Col span={12}>
|
||||
<RbStatistic title={t('userMemory.capacity')} value={memory_num?.total || 0} suffix={t('userMemory.memoryNum')} />
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<RbStatistic title={t('userMemory.type')} value={t(`userMemory.${item.type || 'person'}`)} />
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<div className="rb:relative rb:z-2 rb:mt-3 rb:bg-[#F6F6F6] rb:rounded-lg rb:py-2 rb:px-3 rb:leading-5" onClick={handleViewMemoryConfig}>
|
||||
<Flex align="center" justify="space-between" className="rb:text-[#5B6167]">
|
||||
{t('userMemory.memory_config_name')}
|
||||
<div
|
||||
className="rb:size-5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/userMemory/arrow_right_dark.svg')]"
|
||||
></div>
|
||||
</Flex>
|
||||
<div className="rb:font-medium rb:text-[#212332] rb:mt-1">{memory_config?.memory_config_name || '-'}</div>
|
||||
</div>
|
||||
</RbCard>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user