(taskId)
| 2695 | } |
| 2696 | |
| 2697 | async function markBindCardTaskUserAction(taskId) { |
| 2698 | const lockKey = `mark:${taskId}`; |
| 2699 | if (bindTaskActionRunning.has(lockKey)) { |
| 2700 | toast.info(`任务 #${taskId} 正在验证中,请稍候...`, 2500); |
| 2701 | return; |
| 2702 | } |
| 2703 | bindTaskActionRunning.add(lockKey); |
| 2704 | try { |
| 2705 | toast.info(`任务 #${taskId} 已进入后台验证,最多等待 180 秒...`, 3000); |
| 2706 | const opTask = await api.post(`/payment/bind-card/tasks/${taskId}/mark-user-action/async`, { |
| 2707 | timeout_seconds: 180, |
| 2708 | interval_seconds: 10, |
| 2709 | }, { |
| 2710 | timeoutMs: 20000, |
| 2711 | retry: 0, |
| 2712 | }); |
| 2713 | |
| 2714 | const opTaskId = String(opTask?.id || "").trim(); |
| 2715 | if (!opTaskId) { |
| 2716 | throw new Error("任务创建失败:未返回任务 ID"); |
| 2717 | } |
| 2718 | |
| 2719 | const finalTask = await watchPaymentOpTask(opTaskId); |
| 2720 | const finalStatus = String(finalTask?.status || "").toLowerCase(); |
| 2721 | const data = finalTask?.result || {}; |
| 2722 | |
| 2723 | if (finalStatus === "failed") { |
| 2724 | throw new Error(finalTask?.error || finalTask?.message || "验证任务失败"); |
| 2725 | } |
| 2726 | |
| 2727 | if (finalStatus === "cancelled" || data?.cancelled) { |
| 2728 | toast.warning(`任务 #${taskId} 验证已取消`, 5000); |
| 2729 | } else if (data?.verified) { |
| 2730 | toast.success(`任务 #${taskId} 验证成功: ${String(data.subscription_type || "").toUpperCase()}`); |
| 2731 | } else { |
| 2732 | const sub = String(data?.subscription_type || "free").toUpperCase(); |
| 2733 | const source = String(data?.detail?.source || "unknown"); |
| 2734 | const confidence = String(data?.detail?.confidence || "unknown"); |
| 2735 | const note = String(data?.detail?.note || ""); |
| 2736 | const suffix = note ? `, note=${note}` : ""; |
| 2737 | toast.warning( |
| 2738 | `任务 #${taskId} 暂未检测到订阅(当前 ${sub}, source=${source}, confidence=${confidence}${suffix}),已切回待用户完成`, |
| 2739 | 7000 |
| 2740 | ); |
| 2741 | } |
| 2742 | await loadBindCardTasks(); |
| 2743 | } catch (e) { |
| 2744 | // 兼容旧后端:如果 mark-user-action/async 尚未部署,自动降级到旧同步接口。 |
| 2745 | const detail = String(e?.data?.detail || "").toLowerCase(); |
| 2746 | const isRouteNotFound = e?.response?.status === 404 && detail === "not found"; |
| 2747 | if (isRouteNotFound) { |
| 2748 | try { |
| 2749 | const fallbackMark = await api.post(`/payment/bind-card/tasks/${taskId}/mark-user-action`, { |
| 2750 | timeout_seconds: 180, |
| 2751 | interval_seconds: 10, |
| 2752 | }, { |
| 2753 | timeoutMs: 210000, |
| 2754 | retry: 0, |
nothing calls this directly
no test coverage detected