|
@@ -1,7 +1,6 @@
|
|
|
import Parse from '../../../../shared/db/parse-client.js';
|
|
import Parse from '../../../../shared/db/parse-client.js';
|
|
|
import { ensureGroupChatForRoom } from './groups.service.js';
|
|
import { ensureGroupChatForRoom } from './groups.service.js';
|
|
|
-import { getContactDetailsBatch, batchGetRoomDetails, getQiWeConfig } from './qiwe-api.service.js';
|
|
|
|
|
-import { resolveOwnerName } from './organization.service.js';
|
|
|
|
|
|
|
+import { getContactDetailsBatch } from './qiwe-api.service.js';
|
|
|
|
|
|
|
|
const MSG_TYPE_LABELS: Record<number, string> = {
|
|
const MSG_TYPE_LABELS: Record<number, string> = {
|
|
|
0: '文本消息',
|
|
0: '文本消息',
|
|
@@ -103,9 +102,8 @@ function formatSenderDisplay(senderId: string, senderName: string): string {
|
|
|
return senderId;
|
|
return senderId;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-async function loadRoomMemberNameMap(roomId: string, guid: string): Promise<Map<string, string>> {
|
|
|
|
|
|
|
+async function loadRoomMemberNameMapFromDb(roomId: string): Promise<Map<string, string>> {
|
|
|
const map = new Map<string, string>();
|
|
const map = new Map<string, string>();
|
|
|
-
|
|
|
|
|
const dbQuery = new Parse.Query('GroupMember');
|
|
const dbQuery = new Parse.Query('GroupMember');
|
|
|
dbQuery.equalTo('roomId', roomId);
|
|
dbQuery.equalTo('roomId', roomId);
|
|
|
dbQuery.limit(500);
|
|
dbQuery.limit(500);
|
|
@@ -115,49 +113,40 @@ async function loadRoomMemberNameMap(roomId: string, guid: string): Promise<Map<
|
|
|
const nick = m.get('nickname');
|
|
const nick = m.get('nickname');
|
|
|
if (uid && nick) map.set(String(uid), String(nick));
|
|
if (uid && nick) map.set(String(uid), String(nick));
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- try {
|
|
|
|
|
- const rooms = await batchGetRoomDetails(guid, [roomId]);
|
|
|
|
|
- for (const room of rooms) {
|
|
|
|
|
- for (const mem of room.members) {
|
|
|
|
|
- if (mem.nickname) map.set(mem.userId, mem.nickname);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- } catch {
|
|
|
|
|
- /* 群详情不可用时跳过 */
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
return map;
|
|
return map;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+function needsSenderLookup(m: MessageDto): boolean {
|
|
|
|
|
+ return !m.senderName || m.senderName === m.senderId;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
async function enrichMessagesForDisplay(
|
|
async function enrichMessagesForDisplay(
|
|
|
messages: MessageDto[],
|
|
messages: MessageDto[],
|
|
|
roomId: string,
|
|
roomId: string,
|
|
|
|
|
+ resolveNames = false,
|
|
|
): Promise<MessageDto[]> {
|
|
): Promise<MessageDto[]> {
|
|
|
- const guid = getQiWeConfig().guid;
|
|
|
|
|
- const memberMap = guid ? await loadRoomMemberNameMap(roomId, guid) : new Map<string, string>();
|
|
|
|
|
|
|
+ if (messages.length === 0) return [];
|
|
|
|
|
|
|
|
- const needIds = [...new Set(
|
|
|
|
|
- messages
|
|
|
|
|
- .filter((m) => !memberMap.has(m.senderId) && (!m.senderName || m.senderName === m.senderId))
|
|
|
|
|
- .map((m) => m.senderId)
|
|
|
|
|
- .filter(Boolean),
|
|
|
|
|
- )];
|
|
|
|
|
|
|
+ const needsLookup = messages.some(needsSenderLookup);
|
|
|
|
|
+ const memberMap = needsLookup ? await loadRoomMemberNameMapFromDb(roomId) : new Map<string, string>();
|
|
|
|
|
|
|
|
const contactMap = new Map<string, string>();
|
|
const contactMap = new Map<string, string>();
|
|
|
- if (needIds.length > 0) {
|
|
|
|
|
- try {
|
|
|
|
|
- const contacts = await getContactDetailsBatch(needIds.slice(0, 50));
|
|
|
|
|
- for (const c of contacts) {
|
|
|
|
|
- if (c.name && c.name !== c.userId) contactMap.set(c.userId, c.name);
|
|
|
|
|
|
|
+ if (resolveNames && needsLookup) {
|
|
|
|
|
+ const needIds = [...new Set(
|
|
|
|
|
+ messages
|
|
|
|
|
+ .filter((m) => needsSenderLookup(m) && !memberMap.has(m.senderId))
|
|
|
|
|
+ .map((m) => m.senderId)
|
|
|
|
|
+ .filter(Boolean),
|
|
|
|
|
+ )];
|
|
|
|
|
+ if (needIds.length > 0) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const contacts = await getContactDetailsBatch(needIds.slice(0, 50));
|
|
|
|
|
+ for (const c of contacts) {
|
|
|
|
|
+ if (c.name && c.name !== c.userId) contactMap.set(c.userId, c.name);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ /* 联系人接口不可用时跳过 */
|
|
|
}
|
|
}
|
|
|
- } catch {
|
|
|
|
|
- /* 联系人接口不可用时跳过 */
|
|
|
|
|
- }
|
|
|
|
|
- for (const id of needIds.slice(0, 20)) {
|
|
|
|
|
- if (contactMap.has(id) || memberMap.has(id)) continue;
|
|
|
|
|
- const orgName = await resolveOwnerName(id);
|
|
|
|
|
- if (orgName && orgName !== id) contactMap.set(id, orgName);
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -310,35 +299,35 @@ export function toMessageDto(obj: Parse.Object): MessageDto {
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+function messageQueryForRoom(roomId: string): Parse.Query {
|
|
|
|
|
+ const query = new Parse.Query('Message');
|
|
|
|
|
+ query.equalTo('roomId', roomId);
|
|
|
|
|
+ return query;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
export async function listMessagesByRoom(
|
|
export async function listMessagesByRoom(
|
|
|
roomId: string,
|
|
roomId: string,
|
|
|
limit = 50,
|
|
limit = 50,
|
|
|
skip = 0,
|
|
skip = 0,
|
|
|
chatOnly = true,
|
|
chatOnly = true,
|
|
|
|
|
+ resolveNames = false,
|
|
|
): Promise<{ messages: MessageDto[]; total: number; chatTotal: number }> {
|
|
): Promise<{ messages: MessageDto[]; total: number; chatTotal: number }> {
|
|
|
- const query = new Parse.Query('Message');
|
|
|
|
|
- query.equalTo('roomId', roomId);
|
|
|
|
|
- query.descending('timestamp');
|
|
|
|
|
|
|
+ const listQuery = messageQueryForRoom(roomId);
|
|
|
|
|
+ listQuery.descending('timestamp');
|
|
|
|
|
+ if (chatOnly) listQuery.containedIn('msgType', [...CHAT_MSG_TYPES]);
|
|
|
|
|
+ listQuery.skip(skip).limit(limit);
|
|
|
|
|
|
|
|
- const countQuery = new Parse.Query('Message');
|
|
|
|
|
- countQuery.equalTo('roomId', roomId);
|
|
|
|
|
|
|
+ const countQuery = messageQueryForRoom(roomId);
|
|
|
|
|
+ const chatTotalQuery = messageQueryForRoom(roomId);
|
|
|
|
|
+ chatTotalQuery.containedIn('msgType', [...CHAT_MSG_TYPES]);
|
|
|
|
|
|
|
|
- const [rows, total] = await Promise.all([
|
|
|
|
|
- query.skip(skip).limit(Math.min(limit * 3, 300)).find({ useMasterKey: true }),
|
|
|
|
|
|
|
+ const [rows, total, chatTotal] = await Promise.all([
|
|
|
|
|
+ listQuery.find({ useMasterKey: true }),
|
|
|
countQuery.count({ useMasterKey: true }),
|
|
countQuery.count({ useMasterKey: true }),
|
|
|
|
|
+ chatTotalQuery.count({ useMasterKey: true }),
|
|
|
]);
|
|
]);
|
|
|
|
|
|
|
|
- let dtos = rows.map(toMessageDto);
|
|
|
|
|
- if (chatOnly) {
|
|
|
|
|
- dtos = dtos.filter((m) => isChatMessageType(m.msgType));
|
|
|
|
|
- }
|
|
|
|
|
- dtos = dtos.slice(0, limit);
|
|
|
|
|
-
|
|
|
|
|
- const chatTotalQuery = new Parse.Query('Message');
|
|
|
|
|
- chatTotalQuery.equalTo('roomId', roomId);
|
|
|
|
|
- chatTotalQuery.containedIn('msgType', [...CHAT_MSG_TYPES]);
|
|
|
|
|
- const chatTotal = await chatTotalQuery.count({ useMasterKey: true });
|
|
|
|
|
-
|
|
|
|
|
- const messages = await enrichMessagesForDisplay(dtos, roomId);
|
|
|
|
|
|
|
+ const dtos = rows.map(toMessageDto);
|
|
|
|
|
+ const messages = await enrichMessagesForDisplay(dtos, roomId, resolveNames);
|
|
|
return { messages, total, chatTotal };
|
|
return { messages, total, chatTotal };
|
|
|
}
|
|
}
|