qiwe-api.service.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. import { Injectable, inject } from '@angular/core';
  2. import { ApiClientService } from './api-client.service';
  3. import type { Group } from '../../models';
  4. import type { LifecyclePhase, HealthGrade } from '../../models';
  5. export interface GroupChatDto {
  6. id: string;
  7. roomId: string;
  8. roomName: string;
  9. ownerId: string;
  10. ownerName: string;
  11. memberCount: number;
  12. avatarUrl: string;
  13. status: string;
  14. guid: string;
  15. storeId: string;
  16. storeName: string;
  17. communityId: string;
  18. communityName: string;
  19. activityLevel: string;
  20. healthScore: number;
  21. healthStatus: string;
  22. healthGrade: HealthGrade;
  23. opsActivityScore: number;
  24. customerActivityScore: number;
  25. lifecyclePhase: LifecyclePhase;
  26. hasDocument: boolean;
  27. documentPinned: boolean;
  28. documentInNotice: boolean;
  29. messageCountToday: number;
  30. messageCountTotal: number;
  31. memberChange24h: number;
  32. updatedAt: string;
  33. }
  34. export interface StoreDto {
  35. id: string;
  36. code: string;
  37. name: string;
  38. region: string;
  39. }
  40. export interface CommunityDto {
  41. id: string;
  42. name: string;
  43. address: string;
  44. deliveryDate: string;
  45. lifecyclePhase: LifecyclePhase;
  46. totalHouseholds: number;
  47. avgPrice: number;
  48. storeId: string;
  49. storeName: string;
  50. groupCount: number;
  51. status: string;
  52. }
  53. export interface LifecycleSummaryDto {
  54. phase: LifecyclePhase;
  55. label: string;
  56. count: number;
  57. communities: CommunityDto[];
  58. }
  59. export interface GroupListFilters {
  60. storeId?: string;
  61. activityLevel?: string;
  62. healthStatus?: string;
  63. healthGrade?: string;
  64. lifecyclePhase?: string;
  65. hasDocument?: string;
  66. q?: string;
  67. }
  68. export interface SyncGroupsResult {
  69. sync: { created: number; updated: number; errors: string[] };
  70. catalog?: {
  71. rooms: { created: number; updated: number; errors: string[] };
  72. sessions: { created: number; updated: number; skipped: number };
  73. fromMessages: number;
  74. };
  75. database: {
  76. connected: boolean;
  77. counts?: { groupChat: number; groupMember: number; message: number };
  78. };
  79. }
  80. export interface MessageSyncResult {
  81. guid: string;
  82. startSeq: number;
  83. endSeq: number;
  84. pages: number;
  85. created: number;
  86. skipped: number;
  87. hasMore: boolean;
  88. groupsBackfilled?: number;
  89. errors: string[];
  90. }
  91. export interface MessageDto {
  92. id: string;
  93. msgUniqueIdentifier: string;
  94. roomId: string | null;
  95. senderId: string;
  96. senderName: string;
  97. content: string;
  98. msgType: number;
  99. timestamp: string;
  100. guid: string;
  101. seq?: number;
  102. }
  103. export interface SyncMessagesResult {
  104. sync: MessageSyncResult;
  105. database: SyncGroupsResult['database'];
  106. }
  107. @Injectable({ providedIn: 'root' })
  108. export class QiweApiService {
  109. private readonly api = inject(ApiClientService);
  110. listGroups(filters: GroupListFilters = {}) {
  111. const params = new URLSearchParams();
  112. if (filters.storeId) params.set('storeId', filters.storeId);
  113. if (filters.activityLevel) params.set('activityLevel', filters.activityLevel);
  114. if (filters.healthStatus) params.set('healthStatus', filters.healthStatus);
  115. if (filters.healthGrade) params.set('healthGrade', filters.healthGrade);
  116. if (filters.lifecyclePhase) params.set('lifecyclePhase', filters.lifecyclePhase);
  117. if (filters.hasDocument) params.set('hasDocument', filters.hasDocument);
  118. if (filters.q) params.set('q', filters.q);
  119. const query = params.toString();
  120. const path = query ? `/qiwe/groups?${query}` : '/qiwe/groups';
  121. return this.api.getResult<{ groups: GroupChatDto[]; total: number; stores: StoreDto[] }>(path);
  122. }
  123. listCommunities(lifecyclePhase?: string) {
  124. const params = new URLSearchParams();
  125. if (lifecyclePhase) params.set('lifecyclePhase', lifecyclePhase);
  126. const query = params.toString();
  127. const path = query ? `/qiwe/communities?${query}` : '/qiwe/communities';
  128. return this.api.getResult<{
  129. communities: CommunityDto[];
  130. grouped: LifecycleSummaryDto[];
  131. total: number;
  132. }>(path);
  133. }
  134. listStores() {
  135. return this.api.getResult<{ stores: StoreDto[] }>('/qiwe/stores');
  136. }
  137. syncOrg() {
  138. return this.api.postResult<{ departments: number; members: number; source: string; errors: string[] }>(
  139. '/qiwe/org/sync',
  140. {},
  141. );
  142. }
  143. getOrgTree() {
  144. return this.api.getResult<{ tree: unknown[] }>('/qiwe/org/tree');
  145. }
  146. getGroup(roomId: string) {
  147. return this.api.getResult<{ group: GroupChatDto }>(`/qiwe/groups/${encodeURIComponent(roomId)}`);
  148. }
  149. syncGroups() {
  150. return this.api.postResult<SyncGroupsResult>('/qiwe/sync-groups', {});
  151. }
  152. syncMessages(options: { msgSeq?: number; limit?: number; maxPages?: number; resetCursor?: boolean } = {}) {
  153. return this.api.postResult<SyncMessagesResult>('/qiwe/sync-messages', options);
  154. }
  155. listMessages(roomId: string, limit = 50, skip = 0, chatOnly = true) {
  156. const params = new URLSearchParams({
  157. roomId,
  158. limit: String(limit),
  159. skip: String(skip),
  160. chatOnly: chatOnly ? 'true' : 'false',
  161. });
  162. return this.api.getResult<{ messages: MessageDto[]; total: number; chatTotal: number }>(
  163. `/qiwe/messages?${params.toString()}`,
  164. );
  165. }
  166. testWebhook(payload: unknown) {
  167. return this.api.postResult<null>('/qiwe/webhook', payload);
  168. }
  169. mapToGroup(dto: GroupChatDto): Group {
  170. return {
  171. id: dto.roomId,
  172. name: dto.roomName,
  173. memberCount: dto.memberCount,
  174. communityId: dto.communityId,
  175. communityName: dto.communityName || '—',
  176. storeId: dto.storeId,
  177. storeName: dto.storeName || '—',
  178. ownerId: dto.ownerId,
  179. ownerName: dto.ownerName || '—',
  180. ownerRole: '—',
  181. createdAt: new Date(dto.updatedAt),
  182. healthScore: dto.healthScore,
  183. healthStatus: dto.healthStatus as Group['healthStatus'],
  184. healthGrade: dto.healthGrade || 'C',
  185. opsActivityScore: dto.opsActivityScore ?? 0,
  186. customerActivityScore: dto.customerActivityScore ?? 0,
  187. lifecyclePhase: dto.lifecyclePhase || 'pre_handover',
  188. hasDocument: dto.hasDocument,
  189. documentPinned: dto.documentPinned,
  190. documentInNotice: dto.documentInNotice,
  191. activityLevel: dto.activityLevel as Group['activityLevel'],
  192. messageCountToday: dto.messageCountToday,
  193. messageCountTotal: dto.messageCountTotal ?? 0,
  194. memberChange24h: dto.memberChange24h,
  195. tags: dto.status === 'active' ? ['企微同步'] : ['已解散'],
  196. };
  197. }
  198. }