feat(TopicsHistory): integrate assistant information into topic display

- Added functionality to map and display assistant details alongside topics in the TopicsHistory component.
- Introduced a new AssistantTag styled component for better visual representation of assistants.
- Updated the layout of TopicItem to accommodate assistant information.
This commit is contained in:
suyao 2025-06-19 14:20:20 +08:00
parent 7ae10be387
commit 7c3752a8e6
No known key found for this signature in database
3 changed files with 58 additions and 14 deletions

View File

@ -3,6 +3,7 @@ import { VStack } from '@renderer/components/Layout'
import useScrollPosition from '@renderer/hooks/useScrollPosition' import useScrollPosition from '@renderer/hooks/useScrollPosition'
import { getTopicById } from '@renderer/hooks/useTopic' import { getTopicById } from '@renderer/hooks/useTopic'
import { useAppSelector } from '@renderer/store' import { useAppSelector } from '@renderer/store'
import { selectActiveAssistants } from '@renderer/store/assistants'
import { selectAllTopics } from '@renderer/store/topics' import { selectAllTopics } from '@renderer/store/topics'
import { Topic } from '@renderer/types' import { Topic } from '@renderer/types'
import { Button, Divider, Empty } from 'antd' import { Button, Divider, Empty } from 'antd'
@ -19,6 +20,7 @@ type Props = {
const TopicsHistory: React.FC<Props> = ({ keywords, onClick, onSearch, ...props }) => { const TopicsHistory: React.FC<Props> = ({ keywords, onClick, onSearch, ...props }) => {
const topics = useAppSelector(selectAllTopics) const topics = useAppSelector(selectAllTopics)
const assistants = useAppSelector(selectActiveAssistants)
const { t } = useTranslation() const { t } = useTranslation()
const { handleScroll, containerRef } = useScrollPosition('TopicsHistory') const { handleScroll, containerRef } = useScrollPosition('TopicsHistory')
@ -32,6 +34,15 @@ const TopicsHistory: React.FC<Props> = ({ keywords, onClick, onSearch, ...props
return dayjs(topic.createdAt).format('MM/DD') return dayjs(topic.createdAt).format('MM/DD')
}) })
// 创建助手映射表
const assistantMap = assistants.reduce(
(map, assistant) => {
map[assistant.id] = assistant
return map
},
{} as Record<string, any>
)
if (isEmpty(filteredTopics)) { if (isEmpty(filteredTopics)) {
return ( return (
<ListContainer {...props}> <ListContainer {...props}>
@ -52,17 +63,27 @@ const TopicsHistory: React.FC<Props> = ({ keywords, onClick, onSearch, ...props
<ListItem key={date}> <ListItem key={date}>
<Date>{date}</Date> <Date>{date}</Date>
<Divider style={{ margin: '5px 0' }} /> <Divider style={{ margin: '5px 0' }} />
{items.map((topic) => ( {items.map((topic) => {
<TopicItem const assistant = assistantMap[topic.assistantId]
key={topic.id} return (
onClick={async () => { <TopicItem
const _topic = await getTopicById(topic.id) key={topic.id}
onClick(_topic) onClick={async () => {
}}> const _topic = await getTopicById(topic.id)
<TopicName>{topic.name.substring(0, 50)}</TopicName> onClick(_topic)
<TopicDate>{dayjs(topic.updatedAt).format('HH:mm')}</TopicDate> }}>
</TopicItem> <TopicContent>
))} <TopicName>{topic.name.substring(0, 50)}</TopicName>
{assistant && (
<AssistantTag>
{assistant.emoji} {assistant.name}
</AssistantTag>
)}
</TopicContent>
<TopicDate>{dayjs(topic.updatedAt).format('HH:mm')}</TopicDate>
</TopicItem>
)
})}
</ListItem> </ListItem>
))} ))}
{keywords.length >= 2 && ( {keywords.length >= 2 && (
@ -114,7 +135,15 @@ const TopicItem = styled.div`
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
height: 30px; min-height: 30px;
padding: 4px 0;
`
const TopicContent = styled.div`
display: flex;
flex-direction: column;
gap: 4px;
flex: 1;
` `
const TopicName = styled.div` const TopicName = styled.div`
@ -122,10 +151,21 @@ const TopicName = styled.div`
color: var(--color-text); color: var(--color-text);
` `
const AssistantTag = styled.div`
font-size: 12px;
color: var(--color-text-3);
background: var(--color-fill-quaternary);
padding: 2px 6px;
border-radius: 4px;
display: inline-block;
width: fit-content;
`
const TopicDate = styled.div` const TopicDate = styled.div`
font-size: 14px; font-size: 14px;
color: var(--color-text-3); color: var(--color-text-3);
margin-left: 10px; margin-left: 10px;
flex-shrink: 0;
` `
export default TopicsHistory export default TopicsHistory

View File

@ -5,7 +5,7 @@ export interface Tab {
path: string path: string
} }
interface TabsState { export interface TabsState {
tabs: Tab[] tabs: Tab[]
activeTabId: string activeTabId: string
} }

View File

@ -129,8 +129,12 @@ const topicsSlice = createSlice({
// Remove topics from redux // Remove topics from redux
topicsAdapter.removeMany(state, topicIds) topicsAdapter.removeMany(state, topicIds)
state.topicIdsByAssistant[assistantId] = []
// Create default topic // Create default topic
topicsActions.addDefaultTopic({ assistantId }) const defaultTopic = getDefaultTopic(assistantId)
topicsAdapter.addOne(state, defaultTopic)
state.topicIdsByAssistant[assistantId] = [defaultTopic.id]
}, },
moveTopic(state, action: PayloadAction<MoveTopicPayload>) { moveTopic(state, action: PayloadAction<MoveTopicPayload>) {
const { fromAssistantId, toAssistantId, topicId } = action.payload const { fromAssistantId, toAssistantId, topicId } = action.payload