Skip to content

Commit 0bbe41e

Browse files
authored
✨ feat: 支持会话置顶 (#32)
1 parent 885895a commit 0bbe41e

5 files changed

Lines changed: 75 additions & 16 deletions

File tree

src/pages/chat/SessionList/List/SessionItem.tsx

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,9 @@ interface SessionItemProps {
1919
active?: boolean;
2020
id: string;
2121
loading?: boolean;
22-
pin?: boolean;
2322
}
2423

25-
const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading, pin }) => {
24+
const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading }) => {
2625
const ref = useRef(null);
2726
const isHovering = useHover(ref);
2827

@@ -33,6 +32,7 @@ const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading, pi
3332
const [defaultModel] = useSettings((s) => [s.settings.model], shallow);
3433

3534
const [
35+
pin,
3636
title,
3737
description,
3838
systemRole,
@@ -42,11 +42,13 @@ const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading, pi
4242
model,
4343
chatLength,
4444
removeSession,
45+
pinSession,
4546
] = useSessionStore((s) => {
4647
const session = sessionSelectors.getSessionById(id)(s);
4748
const meta = session.meta;
4849
const systemRole = session.config.systemRole;
4950
return [
51+
session.pinned,
5052
agentSelectors.getTitle(meta),
5153
meta.description,
5254
systemRole,
@@ -56,6 +58,7 @@ const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading, pi
5658
session.config.model,
5759
chatSelectors.currentChats(s).length,
5860
s.removeSession,
61+
s.pinSession,
5962
];
6063
}, shallow);
6164

@@ -66,8 +69,9 @@ const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading, pi
6669
icon: <Icon icon={pin ? PinOff : Pin} />,
6770
key: 'pin',
6871
label: t(pin ? 'pinOff' : 'pin'),
69-
// TODO: 动作绑定
70-
onClick: () => {},
72+
onClick: () => {
73+
pinSession(id, !pin);
74+
},
7175
},
7276
{
7377
children: [
@@ -154,7 +158,16 @@ const SessionItem: FC<SessionItemProps> = memo(({ id, active = true, loading, pi
154158
style={{ color: theme.colorText }}
155159
title={title}
156160
/>
157-
<Dropdown arrow={false} menu={{ items }} trigger={['click']}>
161+
<Dropdown
162+
arrow={false}
163+
menu={{
164+
items,
165+
onClick: ({ domEvent }) => {
166+
domEvent.stopPropagation();
167+
},
168+
}}
169+
trigger={['click']}
170+
>
158171
<ActionIcon
159172
className="session-remove"
160173
icon={MoreVertical}

src/store/session/slices/session/action.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ export interface SessionAction {
3131
*/
3232
importSessions: (sessions: LobeSessions) => void;
3333

34+
/**
35+
* 置顶会话
36+
* @param sessionId
37+
*/
38+
pinSession: (sessionId: string, pinned?: boolean) => void;
3439
/**
3540
* 生成压缩后的消息
3641
* @returns 压缩后的消息
@@ -42,12 +47,13 @@ export interface SessionAction {
4247
* @returns void
4348
*/
4449
removeSession: (sessionId: string) => void;
50+
4551
/**
4652
* @title 切换会话
4753
* @param sessionId - 会话索引
4854
* @returns void
4955
*/
50-
switchSession: (sessionId?: string | 'new') => Promise<void>;
56+
switchSession: (sessionId?: string) => Promise<void>;
5157
}
5258

5359
export const createSessionSlice: StateCreator<
@@ -104,6 +110,19 @@ export const createSessionSlice: StateCreator<
104110
}),
105111
});
106112
},
113+
// genShareUrl: () => {
114+
// const session = sessionSelectors.currentSession(get());
115+
// if (!session) return '';
116+
//
117+
// const agent = session.config;
118+
// return genShareMessagesUrl(session.chats, agent.systemRole);
119+
// },
120+
pinSession: (sessionId, pinned) => {
121+
const nextValue = typeof pinned === 'boolean' ? pinned : !get().sessions[sessionId].pinned;
122+
123+
get().dispatchSession({ id: sessionId, pinned: nextValue, type: 'toggleSessionPinned' });
124+
},
125+
107126
removeSession: (sessionId) => {
108127
get().dispatchSession({ id: sessionId, type: 'removeSession' });
109128

@@ -122,11 +141,4 @@ export const createSessionSlice: StateCreator<
122141
// 新会话
123142
await Router.push(`/chat/${sessionId}`);
124143
},
125-
// genShareUrl: () => {
126-
// const session = sessionSelectors.currentSession(get());
127-
// if (!session) return '';
128-
//
129-
// const agent = session.config;
130-
// return genShareMessagesUrl(session.chats, agent.systemRole);
131-
// },
132144
});

src/store/session/slices/session/reducers/session.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,20 @@ interface UpdateSessionAgentConfig {
6363
id: string;
6464
type: 'updateSessionConfig';
6565
}
66+
interface ToggleSessionPinned {
67+
id: string;
68+
pinned: boolean;
69+
type: 'toggleSessionPinned';
70+
}
6671

6772
export type SessionDispatch =
6873
| AddSession
6974
| UpdateSessionChat
7075
| RemoveSession
7176
| UpdateSessionMeta
7277
| UpdateSessionAgentConfig
73-
| UpdateSessionTopic;
78+
| UpdateSessionTopic
79+
| ToggleSessionPinned;
7480

7581
export const sessionsReducer = (state: LobeSessions, payload: SessionDispatch): LobeSessions => {
7682
switch (payload.type) {
@@ -89,6 +95,16 @@ export const sessionsReducer = (state: LobeSessions, payload: SessionDispatch):
8995
});
9096
}
9197

98+
case 'toggleSessionPinned': {
99+
return produce(state, (draft) => {
100+
const { pinned, id } = payload;
101+
const session = draft[id];
102+
if (!session) return;
103+
104+
session.pinned = pinned;
105+
});
106+
}
107+
92108
case 'updateSessionMeta': {
93109
return produce(state, (draft) => {
94110
const chat = draft[payload.id];

src/store/session/slices/session/selectors/list.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,19 @@ export const sessionList = (s: SessionStore) => {
2121
.map((c) => c.content)
2222
.join(''),
2323
]);
24-
25-
return Object.values(filterChats).sort((a, b) => (b.updateAt || 0) - (a.updateAt || 0));
24+
// 先按照 `pinned` 字段进行排序,置顶的会排在前面。然后,根据 `updateAt` 字段进行倒序排序。
25+
return Object.values(filterChats).sort((a, b) => {
26+
if (a.pinned && !b.pinned) {
27+
return -1;
28+
}
29+
if (!a.pinned && b.pinned) {
30+
return 1;
31+
}
32+
if (a.updateAt && b.updateAt) {
33+
return b.updateAt - a.updateAt;
34+
}
35+
return 0;
36+
});
2637
};
2738

2839
export const getSessionById =

src/types/session.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ interface LobeSessionBase extends BaseDataModel {
1919
* 聊天记录
2020
*/
2121
chats: ChatMessageMap;
22+
/**
23+
* 置顶
24+
*/
25+
pinned?: boolean;
26+
/**
27+
* 主题
28+
*/
2229
topics?: ChatTopicMap;
2330
/**
2431
* 每个会话的类别

0 commit comments

Comments
 (0)