diff --git a/app/Http/Controllers/Admin/PlatformOrderController.php b/app/Http/Controllers/Admin/PlatformOrderController.php index 3e8eaef..d959c9a 100644 --- a/app/Http/Controllers/Admin/PlatformOrderController.php +++ b/app/Http/Controllers/Admin/PlatformOrderController.php @@ -1605,9 +1605,21 @@ class PlatformOrderController extends Controller // 注意:当前阶段仍由 Job 内逐条写 meta 与错误原因;后续可再升级为分片 Job + 结果聚合。 $orderIds = $orders->pluck('id')->map(fn ($id) => (int) $id)->values()->all(); + // run_id:用于把一次批量执行关联起来,便于后续追溯/筛选/可观测。 + // 说明:run_id 在投递阶段就生成,这样运营在页面成功提示里即可复制 run_id 并进入批次复盘页。 + $runId = 'BAS' . now()->format('YmdHis') . str_pad((string) random_int(1, 9999), 4, '0', STR_PAD_LEFT); + // 幂等/防抖(最小实现):避免运营短时间内重复点击导致重复投递同一批次。 // 说明:这里做“短 TTL 的一次性锁”,不引入新表;后续可演进为批次表 + 幂等 key。 // key 口径:scope + filters + ids + limit(同一集合的重复点击会被拦截)。 + $lockKey = \App\Support\BatchDispatchLock::makeKey( + 'admin:bas:dispatch', + $scope, + (string) $filterSummary, + $orderIds, + (int) $limit, + ); + if (! \App\Support\BatchDispatchLock::acquire( 'admin:bas:dispatch', $scope, @@ -1615,14 +1627,22 @@ class PlatformOrderController extends Controller $orderIds, (int) $limit, 60, - '1', + (string) $runId, )) { - return redirect()->back()->with('warning', '检测到刚刚已提交过同一批次的 BAS 任务(1 分钟内)。为避免重复投递,本次未再次提交。'); - } + $existing = (string) (\App\Support\BatchDispatchLock::getExistingValue($lockKey) ?? ''); + $existing = trim($existing); - // run_id:用于把一次批量执行关联起来,便于后续追溯/筛选/可观测。 - // 说明:run_id 在投递阶段就生成,这样运营在页面成功提示里即可复制 run_id 并进入批次复盘页。 - $runId = 'BAS' . now()->format('YmdHis') . str_pad((string) random_int(1, 9999), 4, '0', STR_PAD_LEFT); + $res = redirect()->back()->with('warning', '检测到刚刚已提交过同一批次的 BAS 任务(1 分钟内)。为避免重复投递,本次未再次提交。'); + + // 若锁内已有 run_id(作为 value 存储),则给运营一个直达复盘入口。 + if ($existing !== '' && str_starts_with($existing, 'BAS')) { + $res = $res + ->with('warning_link_href', '/admin/platform-batches/show?type=bas&run_id=' . urlencode($existing)) + ->with('warning_link_label', '进入上次批次复盘'); + } + + return $res; + } \App\Jobs\BatchActivateSubscriptionsJob::dispatch( $orderIds, @@ -1744,6 +1764,14 @@ class PlatformOrderController extends Controller // 幂等/防抖(最小实现):避免运营短时间内重复点击导致重复投递同一批次。 // 说明:这里做“短 TTL 的一次性锁”,不引入新表;后续可演进为批次表 + 幂等 key。 // key 口径:scope + filters + ids + limit(同一集合的重复点击会被拦截)。 + $lockKey = \App\Support\BatchDispatchLock::makeKey( + 'admin:bmpa:dispatch', + $scope, + (string) $filterSummary, + $orderIds, + (int) $limit, + ); + if (! \App\Support\BatchDispatchLock::acquire( 'admin:bmpa:dispatch', $scope, @@ -1753,7 +1781,18 @@ class PlatformOrderController extends Controller 60, (string) $runId, )) { - return redirect()->back()->with('warning', '检测到刚刚已提交过同一批次的 BMPA 任务(1 分钟内)。为避免重复投递,本次未再次提交。'); + $existing = (string) (\App\Support\BatchDispatchLock::getExistingValue($lockKey) ?? ''); + $existing = trim($existing); + + $res = redirect()->back()->with('warning', '检测到刚刚已提交过同一批次的 BMPA 任务(1 分钟内)。为避免重复投递,本次未再次提交。'); + + if ($existing !== '' && str_starts_with($existing, 'BMPA')) { + $res = $res + ->with('warning_link_href', '/admin/platform-batches/show?type=bmpa&run_id=' . urlencode($existing)) + ->with('warning_link_label', '进入上次批次复盘'); + } + + return $res; } \App\Jobs\BatchMarkPaidAndActivateJob::dispatch( diff --git a/resources/views/admin/layouts/app.blade.php b/resources/views/admin/layouts/app.blade.php index 57f3889..52be026 100644 --- a/resources/views/admin/layouts/app.blade.php +++ b/resources/views/admin/layouts/app.blade.php @@ -91,7 +91,18 @@ @endif @if(session('warning')) -