Ver Fonte

fix: prevent fansCount from resetting to 0 on fetch error

1. Update AccountInfo interface to allow optional fansCount.
2. Initialize fansCount to undefined in HeadlessBrowserService for all platforms.
3. In AccountService.refreshAccount, only update fansCount if it is defined.
4. Add safeguard to ignore 0 fansCount if account previously had fans (prevent accidental reset).
Ethanfly há 22 horas atrás
pai
commit
a2b842c159

+ 26 - 16
server/src/services/AccountService.ts

@@ -510,7 +510,18 @@ export class AccountService {
                 if (isValidProfile) {
                   updateData.accountName = profile.accountName;
                   updateData.avatarUrl = profile.avatarUrl;
-                  updateData.fansCount = profile.fansCount;
+                  
+                  // 仅在粉丝数有效时更新(避免因获取失败导致的归零)
+                  if (profile.fansCount !== undefined) {
+                    // 如果新粉丝数为 0,但原粉丝数 > 0,可能是获取失败,记录警告并跳过更新
+                    // 除非 worksCount 也为 0(可能是新号或被封号)
+                    if (profile.fansCount === 0 && (account.fansCount || 0) > 0 && profile.worksCount > 0) {
+                      logger.warn(`[refreshAccount] Fans count dropped to 0 for ${accountId} (was ${account.fansCount}). Ignoring potential fetch error.`);
+                    } else {
+                      updateData.fansCount = profile.fansCount;
+                    }
+                  }
+                  
                   updateData.worksCount = profile.worksCount;
                   
                   // 如果获取到了有效的 accountId(如抖音号),也更新它
@@ -555,21 +566,20 @@ export class AccountService {
 
     // 保存账号每日统计数据(粉丝数、作品数)
     // 无论是否更新了粉丝数/作品数,都要保存当前值到统计表,确保每天都有记录
-    // TODO: 暂时注释掉,待后续需要时再启用
-    // if (updated) {
-    //   try {
-    //     const userDayStatisticsService = new UserDayStatisticsService();
-    //     await userDayStatisticsService.saveStatistics({
-    //       accountId,
-    //       fansCount: updated.fansCount || 0,
-    //       worksCount: updated.worksCount || 0,
-    //     });
-    //     logger.debug(`[AccountService] Saved account day statistics for account ${accountId} (fans: ${updated.fansCount || 0}, works: ${updated.worksCount || 0})`);
-    //   } catch (error) {
-    //     logger.error(`[AccountService] Failed to save account day statistics for account ${accountId}:`, error);
-    //     // 不抛出错误,不影响主流程
-    //   }
-    // }
+    if (updated) {
+      try {
+        const userDayStatisticsService = new UserDayStatisticsService();
+        await userDayStatisticsService.saveStatistics({
+          accountId,
+          fansCount: updated.fansCount || 0,
+          worksCount: updated.worksCount || 0,
+        });
+        logger.debug(`[AccountService] Saved account day statistics for account ${accountId} (fans: ${updated.fansCount || 0}, works: ${updated.worksCount || 0})`);
+      } catch (error) {
+        logger.error(`[AccountService] Failed to save account day statistics for account ${accountId}:`, error);
+        // 不抛出错误,不影响主流程
+      }
+    }
 
     // 通知其他客户端
     wsManager.sendToUser(userId, WS_EVENTS.ACCOUNT_UPDATED, { account: this.formatAccount(updated!) });

+ 9 - 8
server/src/services/HeadlessBrowserService.ts

@@ -76,7 +76,7 @@ export interface AccountInfo {
   accountId: string;
   accountName: string;
   avatarUrl: string;
-  fansCount: number;
+  fansCount?: number;
   worksCount: number;
   worksList?: WorkItem[];
 }
@@ -744,7 +744,7 @@ class HeadlessBrowserService {
     let accountId = `douyin_${Date.now()}`;
     let accountName = '抖音账号';
     let avatarUrl = '';
-    let fansCount = 0;
+    let fansCount: number | undefined;
     let worksCount = 0;
     let worksList: WorkItem[] = [];
     let isLoggedIn = false;
@@ -1143,7 +1143,7 @@ class HeadlessBrowserService {
     let accountId = `bilibili_${Date.now()}`;
     let accountName = 'B站账号';
     let avatarUrl = '';
-    let fansCount = 0;
+    let fansCount: number | undefined;
     let worksCount = 0;
 
     try {
@@ -1194,7 +1194,7 @@ class HeadlessBrowserService {
     let accountId = `kuaishou_${Date.now()}`;
     let accountName = '快手账号';
     let avatarUrl = '';
-    let fansCount = 0;
+    let fansCount: number | undefined;
     let worksCount = 0;
 
     try {
@@ -1245,7 +1245,7 @@ class HeadlessBrowserService {
     let accountId = `weixin_video_${Date.now()}`;
     let accountName = '视频号账号';
     let avatarUrl = '';
-    let fansCount = 0;
+    let fansCount: number | undefined;
     let worksCount = 0;
     let finderId = '';
 
@@ -1564,7 +1564,7 @@ class HeadlessBrowserService {
     let accountId = `xiaohongshu_${Date.now()}`;
     let accountName = '小红书账号';
     let avatarUrl = '';
-    let fansCount = 0;
+    let fansCount: number | undefined;
     let worksCount = 0;
 
     // 用于存储捕获的数据
@@ -1652,7 +1652,8 @@ class HeadlessBrowserService {
       const currentUrl = page.url();
       if (currentUrl.includes('login') || currentUrl.includes('passport')) {
         logger.warn('[Xiaohongshu] Cookie expired, needs login');
-        return this.getDefaultAccountInfo('xiaohongshu');
+        // 返回空信息,fansCount 为 undefined,避免重置为 0
+        return { accountId, accountName, avatarUrl, fansCount: undefined, worksCount: 0 };
       }
 
       // 等待 API 响应
@@ -2546,7 +2547,7 @@ class HeadlessBrowserService {
       accountId: `${platform}_${Date.now()}`,
       accountName: `${name}账号`,
       avatarUrl: '',
-      fansCount: 0,
+      fansCount: undefined,
       worksCount: 0,
     };
   }