Ver código fonte

Merge remote-tracking branch 'origin/fix/bug-6151-6146-6145-6143'

ethanfly 4 dias atrás
pai
commit
9ae0bd3388

+ 25 - 17
client/src/views/Analytics/Platform/index.vue

@@ -316,23 +316,31 @@ function handleDetail(row: PlatformData) {
   console.log('[Platform] platform:', row.platform);
   console.log('[Platform] startDate:', startDate.value, 'endDate:', endDate.value);
 
-  // 直接按完整路径跳转,避免动态路由参数解析问题
-  const path = `/analytics/platform-detail/${row.platform}`;
-  router.push({
-    path,
-    query: {
-      startDate: startDate.value,
-      endDate: endDate.value,
-    },
-  }).then(() => {
-    console.log('[Platform] 路由跳转成功, path:', path);
-  }).catch((error) => {
-    // 仅在真正的错误时提示,重复导航等忽略
-    console.error('[Platform] 路由跳转失败:', error);
-    if (error && error.name !== 'NavigationDuplicated') {
-      ElMessage.error('跳转失败: ' + (error?.message || '未知错误'));
-    }
-  });
+  if (!row.platform) {
+    ElMessage.error('缺少平台参数,无法查看详情');
+    return;
+  }
+
+  try {
+    // 直接按完整路径跳转,避免动态路由参数解析问题
+    const path = `/analytics/platform-detail/${row.platform}`;
+    router.push({
+      path,
+      query: {
+        startDate: startDate.value,
+        endDate: endDate.value,
+      },
+    }).catch((error) => {
+      // 仅在真正的错误时提示,重复导航等忽略
+      console.error('[Platform] 路由跳转失败:', error);
+      if (error && error.name !== 'NavigationDuplicated') {
+        ElMessage.error('跳转详情页失败: ' + (error?.message || '未知错误'));
+      }
+    });
+  } catch (error: any) {
+    console.error('[Platform] handleDetail 异常:', error);
+    ElMessage.error('查看详情失败: ' + (error?.message || '未知错误'));
+  }
 }
 
 // 加载平台详情

+ 7 - 2
client/src/views/Publish/index.vue

@@ -37,7 +37,7 @@
           </template>
         </el-table-column>
         
-        <el-table-column label="目标账号" min-width="220">
+        <el-table-column label="目标账号" min-width="160">
           <template #default="{ row }">
             <span>{{ row.targetAccounts?.length || 0 }} 个</span>
             <template v-if="row.successCount !== undefined || row.failCount !== undefined">
@@ -48,11 +48,16 @@
                 ✗ {{ row.failCount }}
               </el-tag>
             </template>
+          </template>
+        </el-table-column>
+
+        <el-table-column label="平台" min-width="140">
+          <template #default="{ row }">
             <el-tag
               v-for="platform in getTaskPlatforms(row)"
               :key="platform"
               size="small"
-              style="margin-left: 4px"
+              style="margin-right: 4px"
             >
               {{ getPlatformName(platform) }}
             </el-tag>

+ 32 - 0
server/src/routes/publish.ts

@@ -74,6 +74,38 @@ router.post(
   })
 );
 
+// 修改并重新发布(更新现有任务)
+router.put(
+  '/:id',
+  [
+    param('id').isInt().withMessage('任务ID无效'),
+    body('targetAccounts').isArray({ min: 1 }).withMessage('至少选择一个目标账号'),
+    body('publishProxy').optional({ nullable: true }).isObject().withMessage('发布代理配置无效'),
+    validateRequest,
+  ],
+  asyncHandler(async (req, res) => {
+    const userId = req.user!.userId;
+    const taskId = Number(req.params.id);
+
+    // 修复 Bug #6145:更新现有任务而非创建新任务
+    const task = await publishService.updateTask(userId, taskId, req.body);
+
+    // 如果不是定时任务且状态允许,加入任务队列重新执行
+    if (!req.body.scheduledAt && task.status !== 'cancelled') {
+      taskQueueService.createTask(userId, {
+        type: 'publish_video',
+        title: `重新发布: ${task.title}`,
+        description: `发布到 ${task.targetAccounts.length} 个账号`,
+        data: {
+          publishTaskId: task.id,
+        },
+      });
+    }
+
+    res.json({ success: true, data: task });
+  })
+);
+
 // 取消任务
 router.post(
   '/:id/cancel',

+ 12 - 0
server/src/services/PublishService.ts

@@ -615,6 +615,18 @@ export class PublishService {
     });
   }
 
+  /**
+   * 将发布任务状态更新为 failed(用于任务执行器异常时调用)
+   * 修复 Bug #6143:避免 publish_task 表状态停留在 'processing'
+   */
+  async updateTaskStatusToFailed(taskId: number, userId: number): Promise<void> {
+    await this.taskRepository.update(taskId, { status: 'failed' });
+    wsManager.sendToUser(userId, WS_EVENTS.TASK_STATUS_CHANGED, {
+      taskId,
+      status: 'failed',
+    });
+  }
+
   async retryTask(userId: number, taskId: number): Promise<PublishTaskType> {
     const task = await this.taskRepository.findOne({
       where: { id: taskId, userId },

+ 15 - 8
server/src/services/taskExecutors.ts

@@ -142,14 +142,21 @@ async function publishVideoExecutor(task: Task, updateProgress: ProgressUpdater)
     throw new Error('缺少发布任务ID');
   }
 
-  // 执行发布任务
-  await publishService.executePublishTaskWithProgress(
-    taskData.publishTaskId, 
-    userId,
-    (progress, message) => {
-      updateProgress({ progress, currentStep: message });
-    }
-  );
+  try {
+    // 执行发布任务
+    await publishService.executePublishTaskWithProgress(
+      taskData.publishTaskId,
+      userId,
+      (progress, message) => {
+        updateProgress({ progress, currentStep: message });
+      }
+    );
+  } catch (error) {
+    // 修复 Bug #6143:执行器抛出异常时(如缺少发布任务ID),显式更新数据库状态为 failed
+    // 避免 publish_task 表状态停留在 'processing',导致前端显示"等待中"
+    await publishService.updateTaskStatusToFailed(taskData.publishTaskId, userId);
+    throw error;
+  }
 
   updateProgress({ progress: 100, currentStep: '发布完成' });