Ethanfly 15 часов назад
Родитель
Сommit
e9061e895c
1 измененных файлов с 45 добавлено и 11 удалено
  1. 45 11
      server/src/services/WeixinVideoWorkStatisticsImportService.ts

+ 45 - 11
server/src/services/WeixinVideoWorkStatisticsImportService.ts

@@ -178,8 +178,12 @@ const NEAR_30_DAYS_SELECTORS = [
   'label:has-text("近30天")',
 ];
 const VIEW_BTN_SELECTORS = (objectId: string) => [
-  `div.ant-table-fixed-right tr[data-row-key="${objectId}"] a.detail-wrap`,
+  // 与当前后台 DOM 一致:table.ant-table-fixed 下 tr[data-row-key] 内 a.detail-wrap
+  `table.ant-table-fixed tr[data-row-key="${objectId}"] a.detail-wrap`,
+  `div.ant-table-fixed tr[data-row-key="${objectId}"] a.detail-wrap`,
+  `tr[data-row-key="${objectId}"] div.slot-wrap a.detail-wrap`,
   `tr[data-row-key="${objectId}"] a.detail-wrap`,
+  `div.ant-table-fixed-right tr[data-row-key="${objectId}"] a.detail-wrap`,
   `tr[data-row-key="${objectId}"] a:has-text("查看")`,
   `tr[data-row-key="${objectId}"] a`,
 ];
@@ -530,17 +534,48 @@ export class WeixinVideoWorkStatisticsImportService {
           continue;
         }
 
+        // 先挂好监听再点击「查看」,避免响应在 waitForResponse 之前就返回导致漏接
+        const FEED_AGGREAGATE_PAGE_URL = 'https://channels.weixin.qq.com/micro/statistic/postDetail';
+        const getReqPageUrl = (req: { url: () => string; postData: () => string | undefined }): string => {
+          try {
+            let pageUrl = new URL(req.url()).searchParams.get('_pageUrl') ?? '';
+            if (pageUrl) return decodeURIComponent(pageUrl);
+            const postData = req.postData();
+            if (typeof postData === 'string') {
+              const p = JSON.parse(postData);
+              const raw = (p?._pageUrl ?? p?._page_url ?? '') as string;
+              return raw ? decodeURIComponent(raw) : '';
+            }
+          } catch {
+            // ignore
+          }
+          return '';
+        };
+        const responsePromise = page.waitForResponse(
+          (r) => {
+            if (!r.url().includes('feed_aggreagate_data_by_tab_type')) return false;
+            const pageUrl = getReqPageUrl(r.request());
+            if (pageUrl !== FEED_AGGREAGATE_PAGE_URL) {
+              logger.info(`[WX WorkStats] feed_aggreagate 忽略 _pageUrl=${pageUrl}`);
+              return false;
+            }
+            return true;
+          },
+          { timeout: 15_000 }
+        );
+
         let viewClicked = false;
         for (const sel of VIEW_BTN_SELECTORS(oid)) {
           const viewBtn = page.locator(sel);
           if ((await viewBtn.count()) > 0) {
             try {
               await viewBtn.nth(0).waitFor({ state: 'visible', timeout: 3000 });
+              logger.info(`[WX WorkStats] accountId=${account.id} 点击「查看」oid=${oid} selector=${sel}`);
               await viewBtn.nth(0).click();
               viewClicked = true;
               break;
-            } catch {
-              // next selector
+            } catch (e) {
+              logger.warn(`[WX WorkStats] 点击「查看」失败 oid=${oid} selector=${sel}`, e);
             }
           }
         }
@@ -548,18 +583,17 @@ export class WeixinVideoWorkStatisticsImportService {
           totalSkipped += 1;
           continue;
         }
-        await page.waitForTimeout(2000);
 
         let body: { data?: { dataByFanstype?: Array<{ dataByTabtype?: Array<{ tabTypeName?: string; tabType?: number; data?: any }> }>; feedData?: Array<{ totalData?: any }> } } | null = null;
         try {
-          const res = await page.waitForResponse(
-            (r) => r.url().includes('feed_aggreagate_data_by_tab_type'),
-            { timeout: 12_000 }
-          );
+          const res = await responsePromise;
           const json = await res.json().catch(() => null);
-          if (json?.errCode === 0 && json?.data) body = json;
-        } catch {
-          // timeout or no response
+          if (json?.errCode === 0 && json?.data) {
+            body = json;
+            logger.info(`[WX WorkStats] accountId=${account.id} 收到 feed_aggreagate 详情数据 oid=${oid}`);
+          }
+        } catch (e) {
+          logger.warn(`[WX WorkStats] accountId=${account.id} 等待 feed_aggreagate(postDetail) 超时或失败 oid=${oid}`, e);
         }
 
         if (!body?.data) {