From 5de9a7f522307c1aa592bc9e414a99cdcf3a1d46 Mon Sep 17 00:00:00 2001 From: lion <120344285@qq.com> Date: Tue, 26 May 2026 14:49:15 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=92=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/Api/H5ContentController.php | 38 +++++++++++++------ app/Models/Activity.php | 21 +++++++++- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/app/Http/Controllers/Api/H5ContentController.php b/app/Http/Controllers/Api/H5ContentController.php index 1bff2b4..75d26d9 100644 --- a/app/Http/Controllers/Api/H5ContentController.php +++ b/app/Http/Controllers/Api/H5ContentController.php @@ -40,7 +40,7 @@ class H5ContentController extends Controller $q->whereComputedScheduleStatus($st); } }) - ->orderByHotThenScheduleStatusPriority() + ->orderByHotThenH5ActivityListRecentEnded() ->paginate($size); $rows->getCollection()->transform(function ($a) { @@ -421,7 +421,7 @@ class H5ContentController extends Controller $payload['activities'] = Activity::query() ->where('venue_id', $v->id) ->visibleOnH5() - ->orderByHotThenScheduleStatusPriority() + ->orderByHotThenH5ActivityListRecentEnded() ->with('activityDays') ->with('venue:id,cover_image') ->limit(50) @@ -788,17 +788,33 @@ class H5ContentController extends Controller if ($sx !== $sy) { return $sx <=> $sy; } - $aStart = $x['start_at'] ?? ''; - $bStart = $y['start_at'] ?? ''; - if ($aStart !== $bStart) { - if ($aStart === '' || $aStart === null) { - return 1; - } - if ($bStart === '' || $bStart === null) { - return -1; + /** 已结束:按结束日期由近到远(字符串比较兼容 ISO8601 / YYYY-MM-DD) */ + if ($sx === 2) { + $ae = (string) ($x['end_at'] ?? ''); + $be = (string) ($y['end_at'] ?? ''); + if ($ae !== $be) { + if ($ae === '') { + return 1; + } + if ($be === '') { + return -1; + } + + return $be <=> $ae; } + } else { + $aStart = $x['start_at'] ?? ''; + $bStart = $y['start_at'] ?? ''; + if ($aStart !== $bStart) { + if ($aStart === '' || $aStart === null) { + return 1; + } + if ($bStart === '' || $bStart === null) { + return -1; + } - return $aStart <=> $bStart; + return $aStart <=> $bStart; + } } $tx = $this->mixedListActivityTicketPaidRank($x); diff --git a/app/Models/Activity.php b/app/Models/Activity.php index 82b3478..b988703 100644 --- a/app/Models/Activity.php +++ b/app/Models/Activity.php @@ -268,7 +268,9 @@ class Activity extends Model } /** - * 热门优先,其次进行中 → 未开始 → 已结束;组内按开始时间、id。 + * 后台/通用:热门优先,其次进行中 → 未开始 → 已结束;未结束组内按开始时间升序。 + * + * H5 前台列表若要「已结束按结束日期由近到远」请用 {@see scopeOrderByHotThenH5ActivityListRecentEnded}。 */ public function scopeOrderByHotThenScheduleStatusPriority(Builder $query): Builder { @@ -283,6 +285,23 @@ class Activity extends Model ->orderByDesc('id'); } + /** + * H5 活动列表专用:热门 → 进行中 → 未开始 → 已结束;已结束组内按 {@see activities}.end_at 降序(最近结束靠前),其余组内仍按开始日升序。 + */ + public function scopeOrderByHotThenH5ActivityListRecentEnded(Builder $query): Builder + { + [$rankSql, $rankBindings] = static::scheduleStatusPriorityRankSql(); + + return $query + ->orderByDesc('is_hot') + ->orderByRaw($rankSql.' ASC', $rankBindings) + ->orderByRaw('(CASE WHEN ('.$rankSql.') = 2 THEN activities.end_at END) DESC', $rankBindings) + ->orderByRaw('(CASE WHEN ('.$rankSql.') IN (0, 1) THEN activities.start_at IS NULL END) ASC', $rankBindings) + ->orderByRaw('(CASE WHEN ('.$rankSql.') IN (0, 1) THEN activities.start_at END) ASC', $rankBindings) + ->orderByTicketNoteFreeBeforePaid() + ->orderByDesc('activities.id'); + } + /** * 门票说明:免费等非 paid 在前,收费(paid)在后。 */