diff --git a/client/shared/model/user.ts b/client/shared/model/user.ts index 9a1565d7..25624b54 100644 --- a/client/shared/model/user.ts +++ b/client/shared/model/user.ts @@ -335,6 +335,22 @@ export async function appendUserDMConverse( return data; } +/** + * 移除会话列表 + */ +export async function removeUserDMConverse( + converseId: string +): Promise { + const { data } = await request.post( + '/api/user/dmlist/removeConverse', + { + converseId, + } + ); + + return data; +} + /** * 修改用户属性 * @param fieldName 要修改的属性名 diff --git a/client/shared/redux/slices/chat.ts b/client/shared/redux/slices/chat.ts index d2123e99..ca2b3e7a 100644 --- a/client/shared/redux/slices/chat.ts +++ b/client/shared/redux/slices/chat.ts @@ -210,6 +210,16 @@ const chatSlice = createSlice({ state.converses[converseId].hasFetchedHistory = true; }, + removeConverse(state, action: PayloadAction<{ converseId: string }>) { + const { converseId } = action.payload; + + if (!state.converses[converseId]) { + return; + } + + delete state.converses[converseId]; + }, + /** * 清理所有会话信息 */ diff --git a/client/web/src/routes/Main/Content/Personal/SidebarDMItem.tsx b/client/web/src/routes/Main/Content/Personal/SidebarDMItem.tsx index 29babc81..d84c7364 100644 --- a/client/web/src/routes/Main/Content/Personal/SidebarDMItem.tsx +++ b/client/web/src/routes/Main/Content/Personal/SidebarDMItem.tsx @@ -1,14 +1,18 @@ import { + chatActions, ChatConverseState, getCachedUserInfo, + model, + useAppDispatch, useAsync, + useAsyncRequest, useDMConverseName, useUnread, useUserId, } from 'tailchat-shared'; import React from 'react'; import { SidebarItem } from '../SidebarItem'; -import { CombinedAvatar } from 'tailchat-design'; +import { CombinedAvatar, Icon } from 'tailchat-design'; import _without from 'lodash/without'; interface SidebarDMItemProps { @@ -17,9 +21,11 @@ interface SidebarDMItemProps { export const SidebarDMItem: React.FC = React.memo( (props) => { const converse = props.converse; + const converseId = converse._id; const name = useDMConverseName(converse); const userId = useUserId(); - const [hasUnread] = useUnread([converse._id]); + const [hasUnread] = useUnread([converseId]); + const dispatch = useAppDispatch(); const { value: icon } = useAsync(async () => { if (!userId) { @@ -42,13 +48,27 @@ export const SidebarDMItem: React.FC = React.memo( ); }, [converse.members, userId]); + const [, handleRemove] = useAsyncRequest(async () => { + dispatch(chatActions.removeConverse({ converseId })); + await model.user.removeUserDMConverse(converseId); + }, [converseId]); + return ( } // TODO + action={ + { + e.stopPropagation(); + e.preventDefault(); + handleRemove(); + }} + /> + } icon={icon} - to={`/main/personal/converse/${converse._id}`} + to={`/main/personal/converse/${converseId}`} badge={hasUnread} /> ); diff --git a/server/packages/sdk/src/services/lib/call.ts b/server/packages/sdk/src/services/lib/call.ts index 3c362847..bd788403 100644 --- a/server/packages/sdk/src/services/lib/call.ts +++ b/server/packages/sdk/src/services/lib/call.ts @@ -27,6 +27,13 @@ export function call(ctx: TcPureContext) { userId, }); }, + + /** + * 检查用户是否在线 + */ + async isUserOnline(userIds: string[]): Promise { + return await ctx.call('gateway.checkUserOnline', { userIds }); + }, /** * 发送系统消息 * 如果为群组消息则需要增加groupId diff --git a/server/services/core/chat/message.service.ts b/server/services/core/chat/message.service.ts index 281d7b25..66120bd3 100644 --- a/server/services/core/chat/message.service.ts +++ b/server/services/core/chat/message.service.ts @@ -18,6 +18,7 @@ import { } from 'tailchat-server-sdk'; import type { Group } from '../../../models/group/group'; import { isValidStr } from '../../../lib/utils'; +import _ from 'lodash'; interface MessageService extends TcService, @@ -180,12 +181,13 @@ class MessageService extends TcService { const { converseId, groupId, content, plain, meta } = ctx.params; const userId = ctx.meta.userId; const t = ctx.meta.t; + const isGroupMessage = isValidStr(groupId); /** * 鉴权 */ await this.checkConversePermission(ctx, converseId, groupId); // 鉴权是否能获取到会话内容 - if (isValidStr(groupId)) { + if (isGroupMessage) { // 是群组消息, 鉴权是否禁言 const groupInfo = await call(ctx).getGroupInfo(groupId); const member = groupInfo.members.find((m) => String(m.userId) === userId); @@ -208,7 +210,40 @@ class MessageService extends TcService { const json = await this.transformDocuments(ctx, {}, message); - this.roomcastNotify(ctx, converseId, 'add', json); + if (isGroupMessage) { + this.roomcastNotify(ctx, converseId, 'add', json); + } else { + // 如果是私信的话需要基于用户去推送 + // 因为用户可能不订阅消息(删除了dmlist) + const converseInfo = await call(ctx).getConverseInfo(converseId); + if (converseInfo) { + const converseMemberIds = converseInfo.members.map((m) => String(m)); + + call(ctx) + .isUserOnline(converseMemberIds) + .then((onlineList) => { + _.zip(converseMemberIds, onlineList).forEach( + ([memberId, isOnline]) => { + if (isOnline) { + // 用户在线,则直接推送,通过客户端来创建会话 + this.unicastNotify(ctx, memberId, 'add', json); + } else { + // 用户离线,确保追加到会话中 + ctx.call( + 'user.dmlist.addConverse', + { converseId }, + { + meta: { + userId: memberId, + }, + } + ); + } + } + ); + }); + } + } ctx.emit('chat.message.updateMessage', { type: 'add', diff --git a/server/services/core/user/dmlist.service.ts b/server/services/core/user/dmlist.service.ts index 10160d03..6b23c74b 100644 --- a/server/services/core/user/dmlist.service.ts +++ b/server/services/core/user/dmlist.service.ts @@ -61,13 +61,13 @@ class UserDMListService extends TcService { }, { $pull: { - converseIds: new db.Types.ObjectId(converseId), + converseIds: converseId, }, } ) .exec(); - return modifiedCount; + return { modifiedCount }; } /**