const API_BASE = process.env.QIWE_API_BASE || 'https://manager.qiweapi.com/qiwe'; const TOKEN = process.env.QIWE_TOKEN || ''; const GUID = process.env.QIWE_GUID || ''; interface QiWeResponse { code: number; msg: string; data: T; } interface RoomInfo { roomId: string; roomName: string; roomOwnerId: string; roomMemberCount: number; roomAvatarUrl: string; roomCreateTime: string; roomUpdateTime: string; roomFlag: number; ticket: string; } interface SessionInfo { sessionId: string; sessionType: number; } export interface InternalContactRef { userId: string; partyId: string; } export interface ContactDetail { userId: string; name: string; mobile: string; position: string; } async function callApi(method: string, params: Record = {}): Promise> { const resp = await fetch(`${API_BASE}/api/qw/doApi`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-QIWEI-TOKEN': TOKEN, }, body: JSON.stringify({ tokenId: TOKEN, method, params }), }); if (!resp.ok) { throw new Error(`QiWe API HTTP ${resp.status}: ${resp.statusText}`); } const json = await resp.json(); if (json.code !== 0) { throw new Error(`QiWe API error code=${json.code}: ${json.msg}`); } return json; } /** 获取创建的群列表(含群名称、群主、人数等完整信息) */ export async function getRoomList(page = 1, pageSize = 50): Promise<{ rooms: RoomInfo[]; hasMore: boolean; total: number; }> { const resp = await callApi<{ hasMore: boolean; nextStartIndex: number; roomCount: number; roomList: RoomInfo[]; }>('/room/getRoomList', { guid: GUID, page, pageSize }); return { rooms: resp.data.roomList || [], hasMore: resp.data.hasMore || false, total: resp.data.roomCount || 0, }; } /** 获取所有群(遍历分页) */ export async function getAllRooms(): Promise { const all: RoomInfo[] = []; let page = 1; while (true) { const { rooms, hasMore } = await getRoomList(page, 50); all.push(...rooms); if (!hasMore) break; page++; } return all; } /** 获取会话列表(含群会话和个人会话) */ export async function getSessionList(sessionType?: number): Promise { const resp = await callApi<{ collectList: SessionInfo[]; shieldList: SessionInfo[]; topList: SessionInfo[]; }>('/session/getSessionList', { guid: GUID }); const all = [ ...(resp.data.collectList || []), ...(resp.data.shieldList || []), ...(resp.data.topList || []), ]; if (sessionType !== undefined) { return all.filter((s) => s.sessionType === sessionType); } return all; } /** 内部联系人分页(企微组织成员) */ export async function getInternalContactList(limit = 100): Promise { if (!TOKEN || !GUID) return []; const resp = await callApi<{ contactList: InternalContactRef[]; hasMore: boolean; currentVersion?: string; }>('/contact/getWxWorkContactList', { guid: GUID, limit, }); return resp.data.contactList || []; } /** 联系人详情批量(API-18 /contact/batchGetUserinfo) */ export async function getContactDetailsBatch(userIds: string[]): Promise { if (!TOKEN || !GUID || userIds.length === 0) return []; try { const resp = await callApi<{ contactList: Array<{ userId: string; nickname?: string; name?: string; mobile?: string; position?: string; }>; }>('/contact/batchGetUserinfo', { guid: GUID, userIdList: userIds }); return (resp.data.contactList || []).map((c) => ({ userId: c.userId, name: c.nickname || c.name || c.userId, mobile: c.mobile || '', position: c.position || '', })); } catch { return userIds.map((userId) => ({ userId, name: userId, mobile: '', position: '' })); } } export interface SyncMsgListItem { fromRoomId?: number | string; senderId?: number | string; receiverId?: number | string; senderName?: string; msgType?: number; timestamp?: number; seq?: number; msgServerId?: number; msgUniqueIdentifier?: string; msgData?: Record; } /** 同步历史消息分页(API-06 /msg/syncMsg) */ export async function syncMsgPage( guid: string, msgSeq: number, limit = 50, ): Promise<{ hasMore: number | boolean; travelSyncKey: number; syncMsgList: SyncMsgListItem[]; }> { const resp = await callApi<{ hasMore: number | boolean; travelSyncKey: number; syncMsgList: SyncMsgListItem[]; }>('/msg/syncMsg', { guid, msgSeq, limit }); return { hasMore: resp.data.hasMore ?? 0, travelSyncKey: resp.data.travelSyncKey ?? msgSeq, syncMsgList: resp.data.syncMsgList || [], }; } export interface RoomMemberRef { userId: string; nickname: string; } export interface RoomDetailDto { roomId: string; roomName: string; memberCount: number; ownerId: string; members: RoomMemberRef[]; } function parseRoomMember(raw: unknown): RoomMemberRef | null { if (!raw || typeof raw !== 'object') return null; const o = raw as Record; const userId = String(o.userId ?? o.memberId ?? ''); if (!userId) return null; const nickname = String(o.nickname ?? o.name ?? o.memberName ?? o.displayName ?? ''); return { userId, nickname }; } /** 批量获取群详情(API-08) */ export async function batchGetRoomDetails( guid: string, roomIdList: string[], ): Promise { const ids = roomIdList.map((id) => String(id).trim()).filter(Boolean); if (!TOKEN || !guid || ids.length === 0) return []; const resp = await callApi<{ roomList: Array<{ roomId: string; roomName: string; roomOwnerId?: string; memberList?: unknown[]; }>; }>('/room/batchGetRoomDetail', { guid, roomIdList: ids }); return (resp.data.roomList || []).map((r) => { const members = (r.memberList || []) .map(parseRoomMember) .filter((m): m is RoomMemberRef => m !== null); return { roomId: String(r.roomId), roomName: r.roomName || '', memberCount: members.length, ownerId: r.roomOwnerId ? String(r.roomOwnerId) : '', members, }; }); } /** 获取 Token 和 Guid 的可用性 */ export function getQiWeConfig() { return { apiBase: API_BASE, token: TOKEN, guid: GUID }; }