Stop/cancel/resume a task from the dashboard.
(task_id, action, reason)
| 198 | |
| 199 | |
| 200 | def handle_task_action(task_id, action, reason): |
| 201 | """Stop/cancel/resume a task from the dashboard.""" |
| 202 | tasks = load_tasks() |
| 203 | task = next((t for t in tasks if t.get('id') == task_id), None) |
| 204 | if not task: |
| 205 | return {'ok': False, 'error': f'任务 {task_id} 不存在'} |
| 206 | |
| 207 | old_state = task.get('state', '') |
| 208 | _ensure_scheduler(task) |
| 209 | _scheduler_snapshot(task, f'task-action-before-{action}') |
| 210 | |
| 211 | if action == 'stop': |
| 212 | task['state'] = 'Blocked' |
| 213 | task['block'] = reason or '皇上叫停' |
| 214 | task['now'] = f'⏸️ 已暂停:{reason}' |
| 215 | elif action == 'cancel': |
| 216 | task['state'] = 'Cancelled' |
| 217 | task['block'] = reason or '皇上取消' |
| 218 | task['now'] = f'🚫 已取消:{reason}' |
| 219 | elif action == 'resume': |
| 220 | # Resume to previous active state or Doing |
| 221 | task['state'] = task.get('_prev_state', 'Doing') |
| 222 | task['block'] = '无' |
| 223 | task['now'] = f'▶️ 已恢复执行' |
| 224 | |
| 225 | if action in ('stop', 'cancel'): |
| 226 | task['_prev_state'] = old_state # Save for resume |
| 227 | |
| 228 | task.setdefault('flow_log', []).append({ |
| 229 | 'at': now_iso(), |
| 230 | 'from': '皇上', |
| 231 | 'to': task.get('org', ''), |
| 232 | 'remark': f'{"⏸️ 叫停" if action == "stop" else "🚫 取消" if action == "cancel" else "▶️ 恢复"}:{reason}' |
| 233 | }) |
| 234 | |
| 235 | if action == 'resume': |
| 236 | _scheduler_mark_progress(task, f'恢复到 {task.get("state", "Doing")}') |
| 237 | else: |
| 238 | _scheduler_add_flow(task, f'皇上{action}:{reason or "无"}') |
| 239 | |
| 240 | task['updatedAt'] = now_iso() |
| 241 | |
| 242 | save_tasks(tasks) |
| 243 | if action == 'resume' and task.get('state') not in _TERMINAL_STATES: |
| 244 | dispatch_for_state(task_id, task, task.get('state'), trigger='resume') |
| 245 | label = {'stop': '已叫停', 'cancel': '已取消', 'resume': '已恢复'}[action] |
| 246 | return {'ok': True, 'message': f'{task_id} {label}'} |
| 247 | |
| 248 | |
| 249 | def handle_archive_task(task_id, archived, archive_all_done=False): |
no test coverage detected