Fix sqlite ambiguous status in subscription expiry top10 queries

This commit is contained in:
萝卜
2026-03-17 04:41:28 +08:00
parent 583854bd35
commit 313c6cfd5e
2 changed files with 43 additions and 14 deletions

View File

@@ -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);
}
});
});

View File

@@ -272,6 +272,8 @@
<option value="expiring_7d" @selected(($filters['expiry'] ?? '') === 'expiring_7d')>7天内到期</option>
<option value="expired" @selected(($filters['expiry'] ?? '') === 'expired')>已过期</option>
</select>
<input type="date" name="ends_from" data-role="sub-ends-from" placeholder="到期时间从" value="{{ $filters['ends_from'] ?? '' }}" class="w-180">
<input type="date" name="ends_to" data-role="sub-ends-to" placeholder="到期时间到" value="{{ $filters['ends_to'] ?? '' }}" class="w-180">
<select name="merchant_id">
<option value="">全部站点</option>
@foreach(($merchants ?? []) as $merchant)