import { Injectable, inject } from '@angular/core'; import { ApiClientService } from './api-client.service'; import type { Group } from '../../models'; import type { LifecyclePhase, HealthGrade } from '../../models'; export interface GroupChatDto { id: string; roomId: string; roomName: string; ownerId: string; ownerName: string; memberCount: number; avatarUrl: string; status: string; guid: string; storeId: string; storeName: string; communityId: string; communityName: string; activityLevel: string; healthScore: number; healthStatus: string; healthGrade: HealthGrade; opsActivityScore: number; customerActivityScore: number; lifecyclePhase: LifecyclePhase; hasDocument: boolean; documentPinned: boolean; documentInNotice: boolean; messageCountToday: number; messageCountTotal: number; memberChange24h: number; updatedAt: string; } export interface StoreDto { id: string; code: string; name: string; region: string; } export interface CommunityDto { id: string; name: string; address: string; deliveryDate: string; lifecyclePhase: LifecyclePhase; totalHouseholds: number; avgPrice: number; storeId: string; storeName: string; groupCount: number; status: string; } export interface LifecycleSummaryDto { phase: LifecyclePhase; label: string; count: number; communities: CommunityDto[]; } export interface GroupListFilters { storeId?: string; activityLevel?: string; healthStatus?: string; healthGrade?: string; lifecyclePhase?: string; hasDocument?: string; q?: string; } export interface SyncGroupsResult { sync: { created: number; updated: number; errors: string[] }; catalog?: { rooms: { created: number; updated: number; errors: string[] }; sessions: { created: number; updated: number; skipped: number }; fromMessages: number; }; database: { connected: boolean; counts?: { groupChat: number; groupMember: number; message: number }; }; } export interface MessageSyncResult { guid: string; startSeq: number; endSeq: number; pages: number; created: number; skipped: number; hasMore: boolean; groupsBackfilled?: number; errors: string[]; } export interface MessageDto { id: string; msgUniqueIdentifier: string; roomId: string | null; senderId: string; senderName: string; content: string; msgType: number; timestamp: string; guid: string; seq?: number; } export interface SyncMessagesResult { sync: MessageSyncResult; database: SyncGroupsResult['database']; } @Injectable({ providedIn: 'root' }) export class QiweApiService { private readonly api = inject(ApiClientService); listGroups(filters: GroupListFilters = {}) { const params = new URLSearchParams(); if (filters.storeId) params.set('storeId', filters.storeId); if (filters.activityLevel) params.set('activityLevel', filters.activityLevel); if (filters.healthStatus) params.set('healthStatus', filters.healthStatus); if (filters.healthGrade) params.set('healthGrade', filters.healthGrade); if (filters.lifecyclePhase) params.set('lifecyclePhase', filters.lifecyclePhase); if (filters.hasDocument) params.set('hasDocument', filters.hasDocument); if (filters.q) params.set('q', filters.q); const query = params.toString(); const path = query ? `/qiwe/groups?${query}` : '/qiwe/groups'; return this.api.getResult<{ groups: GroupChatDto[]; total: number; stores: StoreDto[] }>(path); } listCommunities(lifecyclePhase?: string) { const params = new URLSearchParams(); if (lifecyclePhase) params.set('lifecyclePhase', lifecyclePhase); const query = params.toString(); const path = query ? `/qiwe/communities?${query}` : '/qiwe/communities'; return this.api.getResult<{ communities: CommunityDto[]; grouped: LifecycleSummaryDto[]; total: number; }>(path); } listStores() { return this.api.getResult<{ stores: StoreDto[] }>('/qiwe/stores'); } syncOrg() { return this.api.postResult<{ departments: number; members: number; source: string; errors: string[] }>( '/qiwe/org/sync', {}, ); } getOrgTree() { return this.api.getResult<{ tree: unknown[] }>('/qiwe/org/tree'); } getGroup(roomId: string) { return this.api.getResult<{ group: GroupChatDto }>(`/qiwe/groups/${encodeURIComponent(roomId)}`); } syncGroups() { return this.api.postResult('/qiwe/sync-groups', {}); } syncMessages(options: { msgSeq?: number; limit?: number; maxPages?: number; resetCursor?: boolean } = {}) { return this.api.postResult('/qiwe/sync-messages', options); } listMessages(roomId: string, limit = 50, skip = 0, chatOnly = true) { const params = new URLSearchParams({ roomId, limit: String(limit), skip: String(skip), chatOnly: chatOnly ? 'true' : 'false', }); return this.api.getResult<{ messages: MessageDto[]; total: number; chatTotal: number }>( `/qiwe/messages?${params.toString()}`, ); } testWebhook(payload: unknown) { return this.api.postResult('/qiwe/webhook', payload); } mapToGroup(dto: GroupChatDto): Group { return { id: dto.roomId, name: dto.roomName, memberCount: dto.memberCount, communityId: dto.communityId, communityName: dto.communityName || '—', storeId: dto.storeId, storeName: dto.storeName || '—', ownerId: dto.ownerId, ownerName: dto.ownerName || '—', ownerRole: '—', createdAt: new Date(dto.updatedAt), healthScore: dto.healthScore, healthStatus: dto.healthStatus as Group['healthStatus'], healthGrade: dto.healthGrade || 'C', opsActivityScore: dto.opsActivityScore ?? 0, customerActivityScore: dto.customerActivityScore ?? 0, lifecyclePhase: dto.lifecyclePhase || 'pre_handover', hasDocument: dto.hasDocument, documentPinned: dto.documentPinned, documentInNotice: dto.documentInNotice, activityLevel: dto.activityLevel as Group['activityLevel'], messageCountToday: dto.messageCountToday, messageCountTotal: dto.messageCountTotal ?? 0, memberChange24h: dto.memberChange24h, tags: dto.status === 'active' ? ['企微同步'] : ['已解散'], }; } }