|
|
@@ -1,4 +1,4 @@
|
|
|
-import { AppDataSource, PlatformAccount, AccountGroup } from '../models/index.js';
|
|
|
+import { AppDataSource, PlatformAccount, AccountGroup } from '../models/index.js';
|
|
|
import { AppError } from '../middleware/error.js';
|
|
|
import { ERROR_CODES, HTTP_STATUS } from '@media-manager/shared';
|
|
|
import type {
|
|
|
@@ -245,6 +245,8 @@ export class AccountService {
|
|
|
|
|
|
if (existing) {
|
|
|
// 更新已存在的账号
|
|
|
+ const wasExpired = existing.status === 'expired';
|
|
|
+
|
|
|
await this.accountRepository.update(existing.id, {
|
|
|
cookieData: cookieData, // 存储原始数据(可能是加密的)
|
|
|
accountName: accountInfo.accountName,
|
|
|
@@ -264,6 +266,16 @@ export class AccountService {
|
|
|
logger.warn(`[addAccount] Background refresh failed for existing account ${existing.id}:`, err);
|
|
|
});
|
|
|
|
|
|
+ // 账号从 expired 恢复为 active:异步补齐最近 30 天用户每日数据
|
|
|
+ if (wasExpired && updated && updated.status === 'active') {
|
|
|
+ this.backfillDailyStatisticsForReactivatedAccountAsync(updated).catch(err => {
|
|
|
+ logger.warn(
|
|
|
+ `[addAccount] Daily statistics backfill failed for reactivated account ${updated.id}:`,
|
|
|
+ err
|
|
|
+ );
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
return this.formatAccount(updated!);
|
|
|
}
|
|
|
|
|
|
@@ -363,6 +375,46 @@ export class AccountService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 账号从失效(expired)恢复为 active 时,为该账号补齐最近 30 天的用户每日数据(user_day_statistics)
|
|
|
+ * 注意:仅在状态从 expired → active 的切换时触发,且按平台调用对应的单账号导入入口
|
|
|
+ */
|
|
|
+ private async backfillDailyStatisticsForReactivatedAccountAsync(
|
|
|
+ account: PlatformAccount
|
|
|
+ ): Promise<void> {
|
|
|
+ const platform = account.platform as PlatformType;
|
|
|
+
|
|
|
+ // 延迟几秒,避免与前端后续操作/其他浏览器任务抢占资源
|
|
|
+ await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
|
+
|
|
|
+ try {
|
|
|
+ if (platform === 'xiaohongshu') {
|
|
|
+ await XiaohongshuAccountOverviewImportService.runDailyImportForAccount(account.id);
|
|
|
+ } else if (platform === 'douyin') {
|
|
|
+ await DouyinAccountOverviewImportService.runDailyImportForAccount(account.id);
|
|
|
+ } else if (platform === 'baijiahao') {
|
|
|
+ await BaijiahaoContentOverviewImportService.runDailyImportForAccount(account.id);
|
|
|
+ } else if (platform === 'weixin_video') {
|
|
|
+ await WeixinVideoDataCenterImportService.runDailyImportForAccount(account.id);
|
|
|
+ } else {
|
|
|
+ logger.info(
|
|
|
+ `[AccountService] Skip daily statistics backfill for unsupported platform ${platform} (accountId=${account.id})`
|
|
|
+ );
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ logger.info(
|
|
|
+ `[AccountService] Completed daily statistics backfill for reactivated account ${account.id} (${platform})`
|
|
|
+ );
|
|
|
+ } catch (error) {
|
|
|
+ logger.warn(
|
|
|
+ `[AccountService] Daily statistics backfill failed for reactivated account ${account.id} (${platform}):`,
|
|
|
+ error
|
|
|
+ );
|
|
|
+ // 出错不影响账号激活本身
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
async updateAccount(
|
|
|
userId: number,
|
|
|
accountId: number,
|
|
|
@@ -411,6 +463,7 @@ export class AccountService {
|
|
|
}
|
|
|
|
|
|
const platform = account.platform as PlatformType;
|
|
|
+ const wasExpired = account.status === 'expired';
|
|
|
const updateData: Partial<PlatformAccount> = {
|
|
|
updatedAt: new Date(),
|
|
|
};
|
|
|
@@ -597,6 +650,17 @@ export class AccountService {
|
|
|
|
|
|
const updated = await this.accountRepository.findOne({ where: { id: accountId } });
|
|
|
|
|
|
+ // 账号从 expired 恢复为 active:异步补齐最近 30 天用户每日数据
|
|
|
+ const newStatus = updated?.status ?? account.status;
|
|
|
+ if (wasExpired && newStatus === 'active' && updated) {
|
|
|
+ this.backfillDailyStatisticsForReactivatedAccountAsync(updated).catch((error) => {
|
|
|
+ logger.warn(
|
|
|
+ `[AccountService] Daily statistics backfill failed after refresh for reactivated account ${updated.id}:`,
|
|
|
+ error
|
|
|
+ );
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
// 刷新账号时不再写入 user_day_statistics,仅保留:每天定时任务 + 添加账号时的 initStatisticsForNewAccountAsync
|
|
|
// if (updated) {
|
|
|
// try {
|