新增座驾购买公屏通知
This commit is contained in:
@@ -8,9 +8,12 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Events\MessageSent;
|
||||||
use App\Http\Requests\BuyRideRequest;
|
use App\Http\Requests\BuyRideRequest;
|
||||||
|
use App\Jobs\SaveMessageJob;
|
||||||
use App\Models\Ride;
|
use App\Models\Ride;
|
||||||
use App\Models\Room;
|
use App\Models\Room;
|
||||||
|
use App\Models\User;
|
||||||
use App\Services\ChatStateService;
|
use App\Services\ChatStateService;
|
||||||
use App\Services\RideService;
|
use App\Services\RideService;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
@@ -67,6 +70,8 @@ class RideController extends Controller
|
|||||||
return response()->json(['status' => 'error', 'message' => $result['message']], 400);
|
return response()->json(['status' => 'error', 'message' => $result['message']], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->pushRidePurchaseNotice($user, $item, $roomId);
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'status' => 'success',
|
'status' => 'success',
|
||||||
'message' => $result['message'],
|
'message' => $result['message'],
|
||||||
@@ -75,4 +80,36 @@ class RideController extends Controller
|
|||||||
'jjb' => $user->fresh()->jjb,
|
'jjb' => $user->fresh()->jjb,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向当前房间广播座驾购买成功通知,方便其他用户快速打开座驾页面。
|
||||||
|
*/
|
||||||
|
private function pushRidePurchaseNotice(User $user, Ride $item, int $roomId): void
|
||||||
|
{
|
||||||
|
$button = '<button onclick="openRideModal()">购买座驾</button>';
|
||||||
|
$content = sprintf(
|
||||||
|
'🚀 【座驾】 <b>%s</b> 购买了 <b>%s</b>,有效期 <b>%d 天</b>,排面已安排!%s',
|
||||||
|
e($user->username),
|
||||||
|
e($item->name),
|
||||||
|
(int) $item->duration_days,
|
||||||
|
$button,
|
||||||
|
);
|
||||||
|
|
||||||
|
$message = [
|
||||||
|
'id' => $this->chatState->nextMessageId($roomId),
|
||||||
|
'room_id' => $roomId,
|
||||||
|
'from_user' => '系统传音',
|
||||||
|
'to_user' => '大家',
|
||||||
|
'content' => $content,
|
||||||
|
'is_secret' => false,
|
||||||
|
'font_color' => '#0f766e',
|
||||||
|
'action' => 'ride_purchase',
|
||||||
|
'sent_at' => now()->toDateTimeString(),
|
||||||
|
];
|
||||||
|
|
||||||
|
// 购买通知需要写入房间消息缓存、实时广播并落库,刷新后仍可追溯。
|
||||||
|
$this->chatState->pushMessage($roomId, $message);
|
||||||
|
broadcast(new MessageSent($roomId, $message));
|
||||||
|
SaveMessageJob::dispatch($message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,11 @@ description: "开发 /Users/pllx/Web/Herd/chatroom 的聊天室座驾。适用
|
|||||||
- 第一行用户身份信息显示 `用户 <用户名> · 部门 <部门> · 职务 <图标 职务> · 会员 <图标 会员>`。
|
- 第一行用户身份信息显示 `用户 <用户名> · 部门 <部门> · 职务 <图标 职务> · 会员 <图标 会员>`。
|
||||||
- 第二行标题只显示 `乘坐【<座驾名称>】闪亮登场`,不要重复用户名。
|
- 第二行标题只显示 `乘坐【<座驾名称>】闪亮登场`,不要重复用户名。
|
||||||
- `effect_user_info` 供动画 HUD 第一行使用,`effect_title` 供动画 HUD 第二行使用,`identity_text` 只供文字播报使用。
|
- `effect_user_info` 供动画 HUD 第一行使用,`effect_title` 供动画 HUD 第二行使用,`identity_text` 只供文字播报使用。
|
||||||
|
- 座驾购买成功必须向当前房间广播文字通知:
|
||||||
|
- 通知使用 `系统传音`,`action = ride_purchase`。
|
||||||
|
- 文案包含 `【座驾】`,前端会按百家乐同款紧凑卡片样式渲染。
|
||||||
|
- 通知末尾必须带 `购买座驾` 按钮,点击调用 `openRideModal()`,方便其他人快速购买。
|
||||||
|
- 购买通知必须写入 `ChatStateService`、广播 `MessageSent`,并通过 `SaveMessageJob` 落库。
|
||||||
- 前端改动后如果浏览器仍显示旧动画标题,必须运行 `npm run build` 或确认 Vite dev server 已刷新,避免加载旧的 `public/build` 资源。
|
- 前端改动后如果浏览器仍显示旧动画标题,必须运行 `npm run build` 或确认 Vite dev server 已刷新,避免加载旧的 `public/build` 资源。
|
||||||
|
|
||||||
## 新增座驾步骤
|
## 新增座驾步骤
|
||||||
|
|||||||
@@ -201,6 +201,18 @@ function resolveGameNotificationCardMeta(msg) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (normalizedContent.includes("【座驾】")) {
|
||||||
|
return {
|
||||||
|
label: "座驾",
|
||||||
|
icon: "🚀",
|
||||||
|
accent: "#0f766e",
|
||||||
|
background: "linear-gradient(135deg,#ecfeff,#f0fdfa)",
|
||||||
|
border: "rgba(15,118,110,.16)",
|
||||||
|
text: "#115e59",
|
||||||
|
chipBg: "#ccfbf1",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
normalizedContent.includes("【赛马】")
|
normalizedContent.includes("【赛马】")
|
||||||
|| normalizedContent.startsWith("🐎 开赛:")
|
|| normalizedContent.startsWith("🐎 开赛:")
|
||||||
@@ -336,6 +348,14 @@ function extractSystemGameCardSummary(content, meta) {
|
|||||||
.trim();
|
.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (meta.label === "座驾") {
|
||||||
|
return normalizedContent
|
||||||
|
.replace(/^[🚀]+\s*/u, "")
|
||||||
|
.replace(/^【座驾】/u, "")
|
||||||
|
.replace(/\s+/gu, " ")
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
if (meta.label === "赛马") {
|
if (meta.label === "赛马") {
|
||||||
return normalizedContent
|
return normalizedContent
|
||||||
.replace(/^[🐎🏇🏆]+\s*/u, "")
|
.replace(/^[🐎🏇🏆]+\s*/u, "")
|
||||||
|
|||||||
@@ -122,6 +122,17 @@ class RideControllerTest extends TestCase
|
|||||||
'remark' => '购买聊天室座驾:测试座驾',
|
'remark' => '购买聊天室座驾:测试座驾',
|
||||||
'room_id' => $room->id,
|
'room_id' => $room->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$messages = app(\App\Services\ChatStateService::class)->getNewMessages($room->id, 0);
|
||||||
|
$purchaseNotice = collect($messages)->first(fn (array $message): bool => ($message['action'] ?? '') === 'ride_purchase');
|
||||||
|
|
||||||
|
$this->assertNotNull($purchaseNotice);
|
||||||
|
$this->assertSame('系统传音', $purchaseNotice['from_user']);
|
||||||
|
$this->assertStringContainsString('【座驾】', $purchaseNotice['content']);
|
||||||
|
$this->assertStringContainsString($user->username, $purchaseNotice['content']);
|
||||||
|
$this->assertStringContainsString('测试座驾', $purchaseNotice['content']);
|
||||||
|
$this->assertStringContainsString('openRideModal()', $purchaseNotice['content']);
|
||||||
|
$this->assertStringContainsString('购买座驾', $purchaseNotice['content']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user