改为独立座驾模块

This commit is contained in:
pllx
2026-04-30 09:55:20 +08:00
parent 3c95478097
commit 181cc6a0b0
22 changed files with 886 additions and 216 deletions
+26 -35
View File
@@ -8,9 +8,9 @@
namespace App\Services;
use App\Models\ShopItem;
use App\Models\Ride;
use App\Models\User;
use App\Models\UserPurchase;
use App\Models\UserRidePurchase;
use App\Support\ChatContentSanitizer;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Carbon;
@@ -18,23 +18,18 @@ use Illuminate\Support\Facades\DB;
/**
* 聊天室座驾服务
* 负责复用商店商品和用户购买记录完成座驾购买、续期、替换与进房展示。
* 负责通过 rides user_ride_purchases 完成座驾购买、续期、替换与进房展示。
*/
class RideService
{
/**
* 获取全部上架座驾商品。
*
* @return Collection<int, ShopItem>
* @return Collection<int, Ride>
*/
public function activeItems(): Collection
{
return ShopItem::query()
->where('type', ShopItem::TYPE_RIDE)
->where('is_active', true)
->orderBy('sort_order')
->orderBy('id')
->get();
return Ride::active();
}
/**
@@ -42,7 +37,7 @@ class RideService
*
* @return array<string, mixed>
*/
public function formatItem(ShopItem $item): array
public function formatItem(Ride $item): array
{
return [
'id' => $item->id,
@@ -60,13 +55,12 @@ class RideService
/**
* 获取用户当前有效座驾,若已过期则自动标记为 expired。
*/
public function currentRide(User $user): ?UserPurchase
public function currentRide(User $user): ?UserRidePurchase
{
$purchase = UserPurchase::query()
->with('shopItem')
$purchase = UserRidePurchase::query()
->with('ride')
->where('user_id', $user->id)
->where('status', 'active')
->whereHas('shopItem', fn ($query) => $query->where('type', ShopItem::TYPE_RIDE))
->orderByDesc('expires_at')
->first();
@@ -92,7 +86,7 @@ class RideService
public function formatCurrentRide(User $user): ?array
{
$purchase = $this->currentRide($user);
if (! $purchase || ! $purchase->shopItem) {
if (! $purchase || ! $purchase->ride) {
return null;
}
@@ -106,14 +100,13 @@ class RideService
*/
public function purchaseRecords(User $user, int $limit = 20): array
{
return UserPurchase::query()
->with('shopItem')
return UserRidePurchase::query()
->with('ride')
->where('user_id', $user->id)
->whereHas('shopItem', fn ($query) => $query->where('type', ShopItem::TYPE_RIDE))
->latest()
->limit($limit)
->get()
->map(fn (UserPurchase $purchase) => $this->formatPurchase($purchase))
->map(fn (UserRidePurchase $purchase) => $this->formatPurchase($purchase))
->values()
->all();
}
@@ -123,9 +116,9 @@ class RideService
*
* @return array{ok:bool, message:string, current_ride?:array<string, mixed>}
*/
public function buy(User $user, ShopItem $item): array
public function buy(User $user, Ride $item): array
{
if (! $item->isRide() || ! $item->is_active) {
if (! $item->is_active) {
return ['ok' => false, 'message' => '该座驾暂未上架。'];
}
@@ -142,35 +135,33 @@ class RideService
$now = Carbon::now();
// 先清理已过期的 active 座驾,避免旧状态影响替换判断。
UserPurchase::query()
UserRidePurchase::query()
->where('user_id', $user->id)
->where('status', 'active')
->whereNotNull('expires_at')
->where('expires_at', '<=', $now)
->whereHas('shopItem', fn ($query) => $query->where('type', ShopItem::TYPE_RIDE))
->update(['status' => 'expired']);
$activeRide = UserPurchase::query()
->with('shopItem')
$activeRide = UserRidePurchase::query()
->with('ride')
->where('user_id', $user->id)
->where('status', 'active')
->whereHas('shopItem', fn ($query) => $query->where('type', ShopItem::TYPE_RIDE))
->orderByDesc('expires_at')
->first();
// 座驾购买必须先扣金币,后续续期或替换都在同一个事务内完成。
$user->decrement('jjb', $item->price);
if ($activeRide && (int) $activeRide->shop_item_id === (int) $item->id) {
if ($activeRide && (int) $activeRide->ride_id === (int) $item->id) {
$baseTime = $activeRide->expires_at && $activeRide->expires_at->greaterThan($now)
? $activeRide->expires_at
: $now;
// 同款续购先取消旧 active,再创建新 active,既保留购买记录,又保持当前座驾唯一。
$activeRide->update(['status' => 'cancelled']);
UserPurchase::create([
UserRidePurchase::create([
'user_id' => $user->id,
'shop_item_id' => $item->id,
'ride_id' => $item->id,
'status' => 'active',
'price_paid' => $item->price,
'expires_at' => $baseTime->copy()->addDays($days),
@@ -184,9 +175,9 @@ class RideService
$activeRide->update(['status' => 'cancelled']);
}
UserPurchase::create([
UserRidePurchase::create([
'user_id' => $user->id,
'shop_item_id' => $item->id,
'ride_id' => $item->id,
'status' => 'active',
'price_paid' => $item->price,
'expires_at' => $now->copy()->addDays($days),
@@ -208,7 +199,7 @@ class RideService
public function buildPresencePayload(User $user): ?array
{
$purchase = $this->currentRide($user);
$item = $purchase?->shopItem;
$item = $purchase?->ride;
$rideKey = $item?->rideKey();
if (! $purchase || ! $item || ! $rideKey) {
@@ -234,9 +225,9 @@ class RideService
*
* @return array<string, mixed>
*/
private function formatPurchase(UserPurchase $purchase): array
private function formatPurchase(UserRidePurchase $purchase): array
{
$item = $purchase->shopItem;
$item = $purchase->ride;
return [
'id' => $purchase->id,