diff --git a/app/Http/Controllers/Admin/SiteSubscriptionController.php b/app/Http/Controllers/Admin/SiteSubscriptionController.php index a8d6baf..2d15a06 100644 --- a/app/Http/Controllers/Admin/SiteSubscriptionController.php +++ b/app/Http/Controllers/Admin/SiteSubscriptionController.php @@ -226,6 +226,8 @@ class SiteSubscriptionController extends Controller 'merchant_id' => trim((string) $request->query('merchant_id', '')), 'plan_id' => trim((string) $request->query('plan_id', '')), 'expiry' => trim((string) $request->query('expiry', '')), + 'ends_from' => trim((string) $request->query('ends_from', '')), + 'ends_to' => trim((string) $request->query('ends_to', '')), ]; $query = $this->applyFilters( @@ -474,31 +476,56 @@ class SiteSubscriptionController extends Controller protected function applyFilters(Builder $query, array $filters): Builder { + // 说明:该方法既会用于普通列表查询(无 join),也会用于「到期提醒 Top10」统计(有 join merchants/plans)。 + // 为避免在 SQLite 下出现 "ambiguous column name",这里统一对 site_subscriptions 的字段加上表前缀。 + $t = 'site_subscriptions'; + 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) { + ->when($filters['status'] !== '', fn (Builder $builder) => $builder->where($t . '.status', $filters['status'])) + ->when(($filters['merchant_id'] ?? '') !== '', fn (Builder $builder) => $builder->where($t . '.merchant_id', (int) $filters['merchant_id'])) + ->when(($filters['plan_id'] ?? '') !== '', fn (Builder $builder) => $builder->where($t . '.plan_id', (int) $filters['plan_id'])) + ->when(($filters['expiry'] ?? '') !== '', function (Builder $builder) use ($filters, $t) { $expiry = (string) ($filters['expiry'] ?? ''); if ($expiry === 'expired') { - $builder->whereNotNull('ends_at')->where('ends_at', '<', now()); + $builder->whereNotNull($t . '.ends_at')->where($t . '.ends_at', '<', now()); } elseif ($expiry === 'expiring_7d') { - $builder->whereNotNull('ends_at') - ->where('ends_at', '>=', now()) - ->where('ends_at', '<', now()->addDays(7)); + $builder->whereNotNull($t . '.ends_at') + ->where($t . '.ends_at', '>=', now()) + ->where($t . '.ends_at', '<', now()->addDays(7)); } }) - ->when($filters['keyword'] !== '', function (Builder $builder) use ($filters) { + ->when(($filters['ends_from'] ?? '') !== '' || ($filters['ends_to'] ?? '') !== '', function (Builder $builder) use ($filters, $t) { + // 到期时间范围筛选:用于运营按 ends_at 精确定位 + // 容错:仅接受 YYYY-MM-DD + $from = trim((string) ($filters['ends_from'] ?? '')); + $to = trim((string) ($filters['ends_to'] ?? '')); + + if ($from !== '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $from)) { + $from = ''; + } + if ($to !== '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $to)) { + $to = ''; + } + + if ($from !== '' && $to !== '') { + $builder->whereBetween($t . '.ends_at', [$from . ' 00:00:00', $to . ' 23:59:59']); + } elseif ($from !== '') { + $builder->where($t . '.ends_at', '>=', $from . ' 00:00:00'); + } elseif ($to !== '') { + $builder->where($t . '.ends_at', '<=', $to . ' 23:59:59'); + } + }) + ->when($filters['keyword'] !== '', function (Builder $builder) use ($filters, $t) { // 关键词搜索:订阅号 / 站点 / 套餐 / 计费周期 $keyword = trim((string) ($filters['keyword'] ?? '')); if ($keyword === '') { return; } - $builder->where(function (Builder $q) use ($keyword) { - $q->where('subscription_no', 'like', '%' . $keyword . '%') - ->orWhere('plan_name', 'like', '%' . $keyword . '%') - ->orWhere('billing_cycle', 'like', '%' . $keyword . '%') + $builder->where(function (Builder $q) use ($keyword, $t) { + $q->where($t . '.subscription_no', 'like', '%' . $keyword . '%') + ->orWhere($t . '.plan_name', 'like', '%' . $keyword . '%') + ->orWhere($t . '.billing_cycle', 'like', '%' . $keyword . '%') ->orWhereHas('merchant', function (Builder $mq) use ($keyword) { $mq->where('name', 'like', '%' . $keyword . '%') ->orWhere('slug', 'like', '%' . $keyword . '%'); @@ -509,7 +536,7 @@ class SiteSubscriptionController extends Controller }); if (ctype_digit($keyword)) { - $q->orWhere('id', (int) $keyword); + $q->orWhere($t . '.id', (int) $keyword); } }); }); diff --git a/resources/views/admin/site_subscriptions/index.blade.php b/resources/views/admin/site_subscriptions/index.blade.php index ef10718..c991cec 100644 --- a/resources/views/admin/site_subscriptions/index.blade.php +++ b/resources/views/admin/site_subscriptions/index.blade.php @@ -272,6 +272,8 @@ + +