diff --git a/app/Http/Controllers/Admin/SiteSubscriptionController.php b/app/Http/Controllers/Admin/SiteSubscriptionController.php index 810ca4a..6a8c422 100644 --- a/app/Http/Controllers/Admin/SiteSubscriptionController.php +++ b/app/Http/Controllers/Admin/SiteSubscriptionController.php @@ -9,11 +9,44 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Http\Request; use Illuminate\View\View; use Symfony\Component\HttpFoundation\StreamedResponse; +use App\Models\PlatformOrder; class SiteSubscriptionController extends Controller { use ResolvesPlatformAdminContext; + public function show(Request $request, SiteSubscription $subscription): View + { + $this->ensurePlatformAdmin($request); + + $subscription->loadMissing(['merchant', 'plan']); + + $platformOrders = PlatformOrder::query() + ->where('site_subscription_id', $subscription->id) + ->latest('id') + ->paginate(10) + ->withQueryString(); + + $endsAt = $subscription->ends_at; + $expiryLabel = '无到期'; + if ($endsAt) { + if ($endsAt->lt(now())) { + $expiryLabel = '已过期'; + } elseif ($endsAt->lt(now()->addDays(7))) { + $expiryLabel = '7天内到期'; + } else { + $expiryLabel = '未到期'; + } + } + + return view('admin.site_subscriptions.show', [ + 'subscription' => $subscription, + 'platformOrders' => $platformOrders, + 'statusLabels' => $this->statusLabels(), + 'expiryLabel' => $expiryLabel, + ]); + } + public function export(Request $request): StreamedResponse { $this->ensurePlatformAdmin($request); diff --git a/resources/views/admin/site_subscriptions/index.blade.php b/resources/views/admin/site_subscriptions/index.blade.php index 532de2f..6918383 100644 --- a/resources/views/admin/site_subscriptions/index.blade.php +++ b/resources/views/admin/site_subscriptions/index.blade.php @@ -106,7 +106,7 @@ {{ $subscription->id }} - {{ $subscription->subscription_no }} + {{ $subscription->subscription_no }} @if($subscription->merchant) diff --git a/resources/views/admin/site_subscriptions/show.blade.php b/resources/views/admin/site_subscriptions/show.blade.php new file mode 100644 index 0000000..e13ea13 --- /dev/null +++ b/resources/views/admin/site_subscriptions/show.blade.php @@ -0,0 +1,135 @@ +@extends('admin.layouts.app') + +@section('title', '订阅详情') +@section('page_title', '订阅详情') + +@section('content') +
+

+ 这里是总台视角的订阅详情页,用于运营排查“订阅状态/到期/关联平台订单/同步记录”。 +

+ +
+
+
订阅号
+
{{ $subscription->subscription_no }}
+
+
+
状态
+
{{ ($statusLabels[$subscription->status] ?? $subscription->status) }} ({{ $subscription->status }})
+
+
+
站点
+
{{ $subscription->merchant?->name ?? '未关联站点' }}
+
+
+
套餐
+
{{ $subscription->plan_name ?: ($subscription->plan?->name ?? '未设置') }}
+
+
+ +
+
+
计费周期 / 周期(月)
+
{{ $subscription->billing_cycle ?: '-' }} / {{ (int) $subscription->period_months }}
+
+
+
金额
+
¥{{ number_format((float) $subscription->amount, 2) }}
+
+
+
开始时间
+
{{ optional($subscription->starts_at)->format('Y-m-d H:i:s') ?: '-' }}
+
+
+
到期时间
+
{{ optional($subscription->ends_at)->format('Y-m-d H:i:s') ?: '-' }}
+
+
+ +
+
+
到期状态(按到期时间)
+
{{ $expiryLabel }}
+
+
+
试用到期
+
{{ optional($subscription->trial_ends_at)->format('Y-m-d H:i:s') ?: '-' }}
+
+
+
生效时间
+
{{ optional($subscription->activated_at)->format('Y-m-d H:i:s') ?: '-' }}
+
+
+
取消时间
+
{{ optional($subscription->cancelled_at)->format('Y-m-d H:i:s') ?: '-' }}
+
+
+ +
+ ← 返回订阅列表 + @if($subscription->subscription_no) + + 按订阅号查看平台订单 + @endif +
+
+ +
+

关联平台订单({{ $platformOrders->total() }})

+ + + + + + + + + + + + + + + + @forelse($platformOrders as $order) + @php + $syncedId = (int) data_get($order->meta, 'subscription_activation.subscription_id', 0); + $syncErr = (string) (data_get($order->meta, 'subscription_activation_error.message') ?? ''); + if ($syncedId > 0) { + $syncStatus = '已同步'; + } elseif ($syncErr !== '') { + $syncStatus = '同步失败'; + } else { + $syncStatus = '未同步'; + } + @endphp + + + + + + + + + + + + @empty + + + + @endforelse + +
ID订单号订单状态支付状态应付/已付下单时间生效时间同步状态操作
{{ $order->id }}{{ $order->order_no }}{{ $order->status }}{{ $order->payment_status }}¥{{ number_format((float) $order->payable_amount, 2) }} / ¥{{ number_format((float) $order->paid_amount, 2) }}{{ optional($order->placed_at)->format('Y-m-d H:i:s') ?: '-' }}{{ optional($order->activated_at)->format('Y-m-d H:i:s') ?: '-' }} + {{ $syncStatus }} + @if($syncStatus === '同步失败') + ({{ mb_substr($syncErr, 0, 30) }}) + @endif + + 详情 +
暂无关联平台订单。
+ +
{{ $platformOrders->links() }}
+
+@endsection diff --git a/routes/web.php b/routes/web.php index ff54025..a5379b1 100644 --- a/routes/web.php +++ b/routes/web.php @@ -109,6 +109,7 @@ Route::prefix('admin')->group(function () { Route::get('/site-subscriptions', [SiteSubscriptionController::class, 'index']); Route::get('/site-subscriptions/export', [SiteSubscriptionController::class, 'export']); + Route::get('/site-subscriptions/{subscription}', [SiteSubscriptionController::class, 'show']); Route::get('/plans', [PlanController::class, 'index']); Route::get('/plans/export', [PlanController::class, 'export']); diff --git a/tests/Feature/AdminSiteSubscriptionShowTest.php b/tests/Feature/AdminSiteSubscriptionShowTest.php new file mode 100644 index 0000000..3ed3136 --- /dev/null +++ b/tests/Feature/AdminSiteSubscriptionShowTest.php @@ -0,0 +1,119 @@ +seed(); + + $this->post('/admin/login', [ + 'email' => 'platform.admin@demo.local', + 'password' => 'Platform@123456', + ])->assertRedirect('/admin'); + } + + public function test_platform_admin_can_open_site_subscription_show_page(): void + { + $this->loginAsPlatformAdmin(); + + $merchant = Merchant::query()->firstOrFail(); + $plan = Plan::query()->create([ + 'code' => 'sub_show_test', + 'name' => '订阅详情测试套餐', + 'billing_cycle' => 'monthly', + 'price' => 88, + 'list_price' => 88, + 'status' => 'active', + 'sort' => 10, + 'published_at' => now(), + ]); + + $sub = SiteSubscription::query()->create([ + 'merchant_id' => $merchant->id, + 'plan_id' => $plan->id, + 'status' => 'activated', + 'source' => 'manual', + 'subscription_no' => 'SUB_SHOW_0001', + 'plan_name' => $plan->name, + 'billing_cycle' => 'monthly', + 'period_months' => 1, + 'amount' => 88, + 'starts_at' => now()->subDays(2), + 'ends_at' => now()->addDays(20), + 'activated_at' => now()->subDays(2), + ]); + + PlatformOrder::query()->create([ + 'merchant_id' => $merchant->id, + 'plan_id' => $plan->id, + 'site_subscription_id' => $sub->id, + 'created_by_admin_id' => 1, + 'order_no' => 'PO_SUB_SHOW_0001', + 'order_type' => 'subscription', + 'status' => 'activated', + 'payment_status' => 'paid', + 'plan_name' => $plan->name, + 'billing_cycle' => 'monthly', + 'period_months' => 1, + 'quantity' => 1, + 'list_amount' => 88, + 'discount_amount' => 0, + 'payable_amount' => 88, + 'paid_amount' => 88, + 'placed_at' => now()->subDay(), + 'paid_at' => now()->subDay(), + 'activated_at' => now()->subDay(), + 'meta' => [ + 'subscription_activation' => [ + 'subscription_id' => $sub->id, + 'synced_at' => now()->subDay()->toDateTimeString(), + 'admin_id' => 1, + ], + ], + ]); + + $this->get('/admin/site-subscriptions/' . $sub->id) + ->assertOk() + ->assertSee('订阅详情') + ->assertSee('SUB_SHOW_0001') + ->assertSee('关联平台订单') + ->assertSee('PO_SUB_SHOW_0001'); + } + + public function test_guest_cannot_open_site_subscription_show_page(): void + { + $merchant = Merchant::query()->create([ + 'name' => '访客测试站点', + 'slug' => 'guest-test', + 'status' => 'active', + ]); + + $sub = SiteSubscription::query()->create([ + 'merchant_id' => $merchant->id, + 'status' => 'activated', + 'source' => 'manual', + 'subscription_no' => 'SUB_GUEST_0001', + 'plan_name' => '访客测试套餐', + 'billing_cycle' => 'monthly', + 'period_months' => 1, + 'amount' => 88, + 'starts_at' => now()->subDay(), + 'ends_at' => now()->addDays(29), + 'activated_at' => now()->subDay(), + ]); + + $this->get('/admin/site-subscriptions/' . $sub->id) + ->assertRedirect('/admin/login'); + } +}