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 { getTopicById } from '@renderer/hooks/useTopic'
import { useAppSelector } from '@renderer/store'
import { selectActiveAssistants } from '@renderer/store/assistants'
import { selectAllTopics } from '@renderer/store/topics'
import { Topic } from '@renderer/types'
import { Button, Divider, Empty } from 'antd'
@ -19,6 +20,7 @@ type Props = {
const TopicsHistory: React.FC<Props> = ({ keywords, onClick, onSearch, ...props }) => {
const topics = useAppSelector(selectAllTopics)
const assistants = useAppSelector(selectActiveAssistants)
const { t } = useTranslation()
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')
})
// 创建助手映射表
const assistantMap = assistants.reduce(
(map, assistant) => {
map[assistant.id] = assistant
return map
},
{} as Record<string, any>
)
if (isEmpty(filteredTopics)) {
return (
<ListContainer {...props}>
@ -52,17 +63,27 @@ const TopicsHistory: React.FC<Props> = ({ keywords, onClick, onSearch, ...props
<ListItem key={date}>
<Date>{date}</Date>
<Divider style={{ margin: '5px 0' }} />
{items.map((topic) => (
<TopicItem
key={topic.id}
onClick={async () => {
const _topic = await getTopicById(topic.id)
onClick(_topic)
}}>
<TopicName>{topic.name.substring(0, 50)}</TopicName>
<TopicDate>{dayjs(topic.updatedAt).format('HH:mm')}</TopicDate>
</TopicItem>
))}
{items.map((topic) => {
const assistant = assistantMap[topic.assistantId]
return (
<TopicItem
key={topic.id}
onClick={async () => {
const _topic = await getTopicById(topic.id)
onClick(_topic)
}}>
<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>
))}
{keywords.length >= 2 && (
@ -114,7 +135,15 @@ const TopicItem = styled.div`
flex-direction: row;
align-items: center;
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`
@ -122,10 +151,21 @@ const TopicName = styled.div`
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`
font-size: 14px;
color: var(--color-text-3);
margin-left: 10px;
flex-shrink: 0;
`
export default TopicsHistory

View File

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

View File

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