chore: init saasshop repo + sql migrations runner + gitee go
This commit is contained in:
196
app/Http/Controllers/Admin/SiteSubscriptionController.php
Normal file
196
app/Http/Controllers/Admin/SiteSubscriptionController.php
Normal file
@@ -0,0 +1,196 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Concerns\ResolvesPlatformAdminContext;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\SiteSubscription;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
|
||||
class SiteSubscriptionController extends Controller
|
||||
{
|
||||
use ResolvesPlatformAdminContext;
|
||||
|
||||
public function export(Request $request): StreamedResponse
|
||||
{
|
||||
$this->ensurePlatformAdmin($request);
|
||||
|
||||
$filters = [
|
||||
'status' => trim((string) $request->query('status', '')),
|
||||
'keyword' => trim((string) $request->query('keyword', '')),
|
||||
'merchant_id' => trim((string) $request->query('merchant_id', '')),
|
||||
'plan_id' => trim((string) $request->query('plan_id', '')),
|
||||
'expiry' => trim((string) $request->query('expiry', '')),
|
||||
];
|
||||
|
||||
$query = $this->applyFilters(
|
||||
SiteSubscription::query()->with(['merchant', 'plan']),
|
||||
$filters
|
||||
)->orderBy('id');
|
||||
|
||||
$filename = 'site_subscriptions_' . now()->format('Ymd_His') . '.csv';
|
||||
|
||||
return response()->streamDownload(function () use ($query) {
|
||||
$out = fopen('php://output', 'w');
|
||||
|
||||
// UTF-8 BOM,避免 Excel 打开中文乱码
|
||||
fwrite($out, "\xEF\xBB\xBF");
|
||||
|
||||
fputcsv($out, [
|
||||
'ID',
|
||||
'订阅号',
|
||||
'站点',
|
||||
'套餐',
|
||||
'状态',
|
||||
'计费周期',
|
||||
'周期(月)',
|
||||
'金额',
|
||||
'开始时间',
|
||||
'到期时间',
|
||||
'到期状态',
|
||||
'试用到期',
|
||||
'生效时间',
|
||||
'取消时间',
|
||||
]);
|
||||
|
||||
$statusLabels = $this->statusLabels();
|
||||
|
||||
$query->chunkById(500, function ($subs) use ($out, $statusLabels) {
|
||||
foreach ($subs as $sub) {
|
||||
$endsAt = $sub->ends_at;
|
||||
$expiryLabel = '无到期';
|
||||
if ($endsAt) {
|
||||
if ($endsAt->lt(now())) {
|
||||
$expiryLabel = '已过期';
|
||||
} elseif ($endsAt->lt(now()->addDays(7))) {
|
||||
$expiryLabel = '7天内到期';
|
||||
} else {
|
||||
$expiryLabel = '未到期';
|
||||
}
|
||||
}
|
||||
|
||||
$status = (string) ($sub->status ?? '');
|
||||
$statusText = ($statusLabels[$status] ?? $status);
|
||||
$statusText = $statusText . ' (' . $status . ')';
|
||||
|
||||
fputcsv($out, [
|
||||
$sub->id,
|
||||
$sub->subscription_no,
|
||||
$sub->merchant?->name ?? '',
|
||||
$sub->plan_name ?: ($sub->plan?->name ?? ''),
|
||||
$statusText,
|
||||
$sub->billing_cycle ?: '',
|
||||
(int) $sub->period_months,
|
||||
(float) $sub->amount,
|
||||
optional($sub->starts_at)->format('Y-m-d H:i:s') ?: '',
|
||||
optional($sub->ends_at)->format('Y-m-d H:i:s') ?: '',
|
||||
$expiryLabel,
|
||||
optional($sub->trial_ends_at)->format('Y-m-d H:i:s') ?: '',
|
||||
optional($sub->activated_at)->format('Y-m-d H:i:s') ?: '',
|
||||
optional($sub->cancelled_at)->format('Y-m-d H:i:s') ?: '',
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
fclose($out);
|
||||
}, $filename, [
|
||||
'Content-Type' => 'text/csv; charset=UTF-8',
|
||||
]);
|
||||
}
|
||||
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$this->ensurePlatformAdmin($request);
|
||||
|
||||
$filters = [
|
||||
'status' => trim((string) $request->query('status', '')),
|
||||
'keyword' => trim((string) $request->query('keyword', '')),
|
||||
'merchant_id' => trim((string) $request->query('merchant_id', '')),
|
||||
'plan_id' => trim((string) $request->query('plan_id', '')),
|
||||
// 到期辅助筛选(不改变 status 字段,仅按 ends_at 计算)
|
||||
// - expired:已过期(ends_at < now)
|
||||
// - expiring_7d:7 天内到期(now <= ends_at < now+7d)
|
||||
'expiry' => trim((string) $request->query('expiry', '')),
|
||||
];
|
||||
|
||||
$query = $this->applyFilters(
|
||||
SiteSubscription::query()->with(['merchant', 'plan']),
|
||||
$filters
|
||||
);
|
||||
|
||||
$subscriptions = (clone $query)
|
||||
->latest('id')
|
||||
->paginate(10)
|
||||
->withQueryString();
|
||||
|
||||
$baseQuery = $this->applyFilters(SiteSubscription::query(), $filters);
|
||||
|
||||
return view('admin.site_subscriptions.index', [
|
||||
'subscriptions' => $subscriptions,
|
||||
'filters' => $filters,
|
||||
'statusLabels' => $this->statusLabels(),
|
||||
'filterOptions' => [
|
||||
'statuses' => $this->statusLabels(),
|
||||
],
|
||||
'merchants' => SiteSubscription::query()->with('merchant')->select('merchant_id')->distinct()->get()->pluck('merchant')->filter()->unique('id')->values(),
|
||||
'plans' => SiteSubscription::query()->with('plan')->select('plan_id')->whereNotNull('plan_id')->distinct()->get()->pluck('plan')->filter()->unique('id')->values(),
|
||||
'summaryStats' => [
|
||||
'total_subscriptions' => (clone $baseQuery)->count(),
|
||||
'activated_subscriptions' => (clone $baseQuery)->where('status', 'activated')->count(),
|
||||
'pending_subscriptions' => (clone $baseQuery)->where('status', 'pending')->count(),
|
||||
'cancelled_subscriptions' => (clone $baseQuery)->where('status', 'cancelled')->count(),
|
||||
// 可治理辅助指标:按 ends_at 计算
|
||||
'expired_subscriptions' => (clone $baseQuery)
|
||||
->whereNotNull('ends_at')
|
||||
->where('ends_at', '<', now())
|
||||
->count(),
|
||||
'expiring_7d_subscriptions' => (clone $baseQuery)
|
||||
->whereNotNull('ends_at')
|
||||
->where('ends_at', '>=', now())
|
||||
->where('ends_at', '<', now()->addDays(7))
|
||||
->count(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
protected function statusLabels(): array
|
||||
{
|
||||
return [
|
||||
'pending' => '待生效',
|
||||
'activated' => '已生效',
|
||||
'cancelled' => '已取消',
|
||||
'expired' => '已过期',
|
||||
];
|
||||
}
|
||||
|
||||
protected function applyFilters(Builder $query, array $filters): Builder
|
||||
{
|
||||
return $query
|
||||
->when($filters['status'] !== '', fn (Builder $builder) => $builder->where('status', $filters['status']))
|
||||
->when(($filters['merchant_id'] ?? '') !== '', fn (Builder $builder) => $builder->where('merchant_id', (int) $filters['merchant_id']))
|
||||
->when(($filters['plan_id'] ?? '') !== '', fn (Builder $builder) => $builder->where('plan_id', (int) $filters['plan_id']))
|
||||
->when(($filters['expiry'] ?? '') !== '', function (Builder $builder) use ($filters) {
|
||||
$expiry = (string) ($filters['expiry'] ?? '');
|
||||
if ($expiry === 'expired') {
|
||||
$builder->whereNotNull('ends_at')->where('ends_at', '<', now());
|
||||
} elseif ($expiry === 'expiring_7d') {
|
||||
$builder->whereNotNull('ends_at')
|
||||
->where('ends_at', '>=', now())
|
||||
->where('ends_at', '<', now()->addDays(7));
|
||||
}
|
||||
})
|
||||
->when($filters['keyword'] !== '', function (Builder $builder) use ($filters) {
|
||||
$keyword = $filters['keyword'];
|
||||
|
||||
$builder->where(function (Builder $subQuery) use ($keyword) {
|
||||
$subQuery->where('subscription_no', 'like', '%' . $keyword . '%')
|
||||
->orWhere('plan_name', 'like', '%' . $keyword . '%')
|
||||
->orWhere('billing_cycle', 'like', '%' . $keyword . '%');
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user