|
@@ -9,6 +9,7 @@ import { WorkService } from './WorkService.js';
|
|
|
import { AccountService } from './AccountService.js';
|
|
import { AccountService } from './AccountService.js';
|
|
|
import { PublishService } from './PublishService.js';
|
|
import { PublishService } from './PublishService.js';
|
|
|
import { XiaohongshuWorkNoteStatisticsImportService } from './XiaohongshuWorkNoteStatisticsImportService.js';
|
|
import { XiaohongshuWorkNoteStatisticsImportService } from './XiaohongshuWorkNoteStatisticsImportService.js';
|
|
|
|
|
+import { DouyinWorkStatisticsImportService } from './DouyinWorkStatisticsImportService.js';
|
|
|
import { AppDataSource, PlatformAccount } from '../models/index.js';
|
|
import { AppDataSource, PlatformAccount } from '../models/index.js';
|
|
|
import { logger } from '../utils/logger.js';
|
|
import { logger } from '../utils/logger.js';
|
|
|
|
|
|
|
@@ -18,6 +19,7 @@ const workService = new WorkService();
|
|
|
const accountService = new AccountService();
|
|
const accountService = new AccountService();
|
|
|
const publishService = new PublishService();
|
|
const publishService = new PublishService();
|
|
|
const xhsWorkStatsService = new XiaohongshuWorkNoteStatisticsImportService();
|
|
const xhsWorkStatsService = new XiaohongshuWorkNoteStatisticsImportService();
|
|
|
|
|
+const dyWorkStatsService = new DouyinWorkStatisticsImportService();
|
|
|
|
|
|
|
|
type ProgressUpdater = (update: Partial<TaskProgressUpdate>) => void;
|
|
type ProgressUpdater = (update: Partial<TaskProgressUpdate>) => void;
|
|
|
|
|
|
|
@@ -262,6 +264,54 @@ async function xhsWorkStatsBackfillExecutor(task: Task, updateProgress: Progress
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
|
|
+ * 抖音作品日统计/快照补数(不阻塞同步作品)
|
|
|
|
|
+ * 任务 data: { workIds: number[] }
|
|
|
|
|
+ */
|
|
|
|
|
+async function dyWorkStatsBackfillExecutor(task: Task, updateProgress: ProgressUpdater): Promise<TaskResult> {
|
|
|
|
|
+ updateProgress({ progress: 5, currentStep: '准备抖音作品补数任务...' });
|
|
|
|
|
+
|
|
|
|
|
+ const userId = (task as Task & { userId?: number }).userId;
|
|
|
|
|
+ if (!userId) throw new Error('缺少用户ID');
|
|
|
|
|
+ if (!task.accountId) throw new Error('缺少账号ID');
|
|
|
|
|
+
|
|
|
|
|
+ const workIdsRaw = (task as Task & { workIds?: unknown }).workIds;
|
|
|
|
|
+ const workIds = Array.isArray(workIdsRaw)
|
|
|
|
|
+ ? workIdsRaw.map((x) => Number(x)).filter((n) => Number.isFinite(n) && n > 0)
|
|
|
|
|
+ : [];
|
|
|
|
|
+ if (!workIds.length) throw new Error('缺少 workIds');
|
|
|
|
|
+
|
|
|
|
|
+ // 仅允许当前用户自己的抖音账号
|
|
|
|
|
+ const account = await AppDataSource.getRepository(PlatformAccount).findOne({
|
|
|
|
|
+ where: { id: task.accountId, userId, platform: 'douyin' as any },
|
|
|
|
|
+ });
|
|
|
|
|
+ if (!account) throw new Error('未找到抖音账号或无权限');
|
|
|
|
|
+
|
|
|
|
|
+ const total = workIds.length;
|
|
|
|
|
+ updateProgress({ progress: 15, currentStep: `开始抖音作品补数(作品数:${total})...`, totalSteps: total });
|
|
|
|
|
+
|
|
|
|
|
+ await dyWorkStatsService.importAccountWorksStatistics(account, false, {
|
|
|
|
|
+ workIdFilter: workIds,
|
|
|
|
|
+ onProgress: ({ index, total, work }) => {
|
|
|
|
|
+ const pct = Math.min(99, Math.max(15, Math.round(15 + (index / Math.max(1, total)) * 84)));
|
|
|
|
|
+ updateProgress({
|
|
|
|
|
+ progress: pct,
|
|
|
|
|
+ currentStepIndex: index,
|
|
|
|
|
+ totalSteps: total,
|
|
|
|
|
+ currentStep: `第 ${index}/${total} 个作品:${(work.title || '').trim() || `workId=${work.id}`}`,
|
|
|
|
|
+ });
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ updateProgress({ progress: 100, currentStep: '抖音作品补数完成' });
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ success: true,
|
|
|
|
|
+ message: `抖音作品补数完成,作品数:${workIds.length}`,
|
|
|
|
|
+ data: { workIdsCount: workIds.length },
|
|
|
|
|
+ };
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
* 注册所有任务执行器
|
|
* 注册所有任务执行器
|
|
|
*/
|
|
*/
|
|
|
export function registerTaskExecutors(): void {
|
|
export function registerTaskExecutors(): void {
|
|
@@ -271,6 +321,7 @@ export function registerTaskExecutors(): void {
|
|
|
taskQueueService.registerExecutor('publish_video', publishVideoExecutor);
|
|
taskQueueService.registerExecutor('publish_video', publishVideoExecutor);
|
|
|
taskQueueService.registerExecutor('delete_work', deleteWorkExecutor);
|
|
taskQueueService.registerExecutor('delete_work', deleteWorkExecutor);
|
|
|
taskQueueService.registerExecutor('xhs_work_stats_backfill', xhsWorkStatsBackfillExecutor);
|
|
taskQueueService.registerExecutor('xhs_work_stats_backfill', xhsWorkStatsBackfillExecutor);
|
|
|
|
|
+ taskQueueService.registerExecutor('dy_work_stats_backfill', dyWorkStatsBackfillExecutor);
|
|
|
|
|
|
|
|
logger.info('All task executors registered');
|
|
logger.info('All task executors registered');
|
|
|
}
|
|
}
|