Explorar o código

平台数据列表页调试

Ethanfly hai 15 horas
pai
achega
78f16c129c

+ 34 - 9
server/python/export_platform_statistics_xlsx.py

@@ -77,29 +77,54 @@ def _safe_str(v) -> str:
   return "".join(ch for ch in s if not (0xD800 <= ord(ch) <= 0xDFFF))
 
 
-def _format_date_only(value: str) -> str:
+def _format_update_time(value: str) -> str:
   """
-  将各种时间字符串格式化为 YYYY-MM-DD,仅保留日期部分
-  如果无法解析,则尽量取前 10 位作为日期返回
+  格式化更新时间为 "MM-DD HH:mm" 格式
+  如果已经是该格式,直接返回;否则尝试解析并转换
   """
   if not value:
     return ""
 
   s = str(value).strip()
+  
+  # 如果已经是 "MM-DD HH:mm" 格式,直接返回
+  if len(s) == 14 and s[2] == '-' and s[5] == ' ' and s[8] == ':':
+    return s
+  
+  # 尝试解析 ISO 格式或其他常见格式
   try:
+    # 处理 ISO 格式(如 "2026-01-28T12:22:00Z")
     if s.endswith("Z"):
       s_clean = s[:-1]
     else:
       s_clean = s
     s_clean = s_clean.replace(" ", "T")
     dt = datetime.fromisoformat(s_clean)
-    return dt.strftime("%Y-%m-%d")
+    return dt.strftime("%m-%d %H:%M")
   except Exception:
     pass
-
-  if len(s) >= 10:
-    return s[:10]
-
+  
+  # 如果无法解析,尝试提取日期和时间部分
+  # 格式可能是 "YYYY-MM-DD HH:mm:ss" 或类似
+  try:
+    # 尝试匹配 "YYYY-MM-DD HH:mm:ss" 格式
+    if len(s) >= 16:
+      parts = s.split(' ')
+      if len(parts) >= 2:
+        date_part = parts[0]  # "YYYY-MM-DD"
+        time_part = parts[1]  # "HH:mm:ss" 或 "HH:mm"
+        date_parts = date_part.split('-')
+        time_parts = time_part.split(':')
+        if len(date_parts) >= 3 and len(time_parts) >= 2:
+          month = date_parts[1]
+          day = date_parts[2]
+          hour = time_parts[0].zfill(2)
+          minute = time_parts[1].zfill(2)
+          return f"{month}-{day} {hour}:{minute}"
+  except Exception:
+    pass
+  
+  # 如果都失败了,返回原字符串
   return s
 
 
@@ -147,7 +172,7 @@ def build_xlsx(platforms):
       _safe_int(p.get("commentsCount")) or 0,
       _safe_int(p.get("likesCount")) or 0,
       _safe_int(p.get("fansIncrease")) or 0,
-      _safe_str(_format_date_only(p.get("updateTime"))),
+      _safe_str(_format_update_time(p.get("updateTime"))),
     ])
 
   int_cols = {"B", "C", "D", "E"}

BIN=BIN
server/python/platforms/__pycache__/__init__.cpython-311.pyc


BIN=BIN
server/python/platforms/__pycache__/weixin.cpython-311.pyc


BIN=BIN
server/python/platforms/__pycache__/xiaohongshu.cpython-311.pyc


+ 1 - 1
server/src/routes/workDayStatistics.ts

@@ -150,7 +150,7 @@ router.get(
         likesCount: p.likesCount,
         fansIncrease: p.fansIncrease,
         // 使用 endDate 作为“更新时间”展示(仅日期)
-        updateTime: endDate || new Date().toISOString(),
+        updateTime: p.updateTime || '',
       })),
     };
 

+ 43 - 10
server/src/services/WorkDayStatisticsService.ts

@@ -34,6 +34,7 @@ interface PlatformStatItem {
   likesCount: number;
   commentsCount: number;
   collectsCount: number;
+  updateTime?: string;
 }
 
 interface WorkStatisticsItem {
@@ -319,7 +320,7 @@ export class WorkDayStatisticsService {
       where: { userId },
     });
 
-    // 按平台聚合数据:Map<platform, { fansCount, fansIncrease, viewsCount, likesCount, commentsCount, collectsCount }>
+    // 按平台聚合数据:Map<platform, { fansCount, fansIncrease, viewsCount, likesCount, commentsCount, collectsCount, latestUpdateTime }>
     const platformMap = new Map<string, {
       fansCount: number;
       fansIncrease: number;
@@ -327,6 +328,7 @@ export class WorkDayStatisticsService {
       likesCount: number;
       commentsCount: number;
       collectsCount: number;
+      latestUpdateTime: Date | null;
     }>();
 
     // 遍历每个账号,计算该账号的数据,然后累加到对应平台
@@ -396,6 +398,7 @@ export class WorkDayStatisticsService {
           likesCount: 0,
           commentsCount: 0,
           collectsCount: 0,
+          latestUpdateTime: null,
         });
       }
 
@@ -406,18 +409,48 @@ export class WorkDayStatisticsService {
       platformStat.likesCount += accountLikesIncrease;
       platformStat.commentsCount += accountCommentsIncrease;
       platformStat.collectsCount += accountCollectsIncrease;
+
+      // 查询该账号在当前时间段内的最晚 updated_at
+      const latestUserStat = await this.userDayStatisticsRepository
+        .createQueryBuilder('uds')
+        .where('uds.account_id = :accountId', { accountId: account.id })
+        .andWhere('DATE(uds.record_date) >= :startDate', { startDate: startDateStr })
+        .andWhere('DATE(uds.record_date) <= :endDate', { endDate: endDateStr })
+        .orderBy('uds.updated_at', 'DESC')
+        .getOne();
+
+      if (latestUserStat && latestUserStat.updatedAt) {
+        // 更新平台的最晚更新时间
+        if (!platformStat.latestUpdateTime || latestUserStat.updatedAt > platformStat.latestUpdateTime) {
+          platformStat.latestUpdateTime = latestUserStat.updatedAt;
+        }
+      }
     }
 
     // 转换为数组格式,按粉丝数降序排序
-    const platformData: PlatformStatItem[] = Array.from(platformMap.entries()).map(([platform, stat]) => ({
-      platform,
-      fansCount: stat.fansCount,
-      fansIncrease: stat.fansIncrease,
-      viewsCount: stat.viewsCount,
-      likesCount: stat.likesCount,
-      commentsCount: stat.commentsCount,
-      collectsCount: stat.collectsCount,
-    }));
+    const platformData: PlatformStatItem[] = Array.from(platformMap.entries()).map(([platform, stat]) => {
+      // 格式化更新时间为 "MM-DD HH:mm" 格式
+      let updateTime: string | undefined;
+      if (stat.latestUpdateTime) {
+        const date = new Date(stat.latestUpdateTime);
+        const month = String(date.getMonth() + 1).padStart(2, '0');
+        const day = String(date.getDate()).padStart(2, '0');
+        const hours = String(date.getHours()).padStart(2, '0');
+        const minutes = String(date.getMinutes()).padStart(2, '0');
+        updateTime = `${month}-${day} ${hours}:${minutes}`;
+      }
+
+      return {
+        platform,
+        fansCount: stat.fansCount,
+        fansIncrease: stat.fansIncrease,
+        viewsCount: stat.viewsCount,
+        likesCount: stat.likesCount,
+        commentsCount: stat.commentsCount,
+        collectsCount: stat.collectsCount,
+        updateTime,
+      };
+    });
 
     platformData.sort((a, b) => b.fansCount - a.fansCount);