From 243e06915efcda0ae58351f73c4746e18fa21690 Mon Sep 17 00:00:00 2001 From: pllx Date: Tue, 28 Apr 2026 13:00:21 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=B2=A1=E5=BF=85=E8=A6=81?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DEVELOPMENT.md | 1004 ------------------------------------------------ GAMES_TODO.md | 98 ----- 2 files changed, 1102 deletions(-) delete mode 100644 DEVELOPMENT.md delete mode 100644 GAMES_TODO.md diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md deleted file mode 100644 index e0d7bbe..0000000 --- a/DEVELOPMENT.md +++ /dev/null @@ -1,1004 +0,0 @@ -# ChatRoom 开发计划与注意事项 - -> **技术栈**:Laravel 12 · PHP 8.4 · Laravel Reverb (WebSocket) · Redis · MySQL 8.0 · Laravel Horizon -> **参照原项目**:`/Users/pllx/Web/chat/hp0709`(VBScript ASP 聊天室,仅作功能参考,不做数据迁移) -> **目标域名**:`http://chatroom.test`(Herd 自动配置)| `https://chat.ay.lc`(生产环境) - ---- - -## 一、环境版本要求 - -| 组件 | 版本 | -| --------------------- | -------------------------- | -| **PHP** | 8.4.5+ | -| **Laravel Framework** | v12.x | -| **Laravel Reverb** | latest(WebSocket 服务器) | -| **Laravel Horizon** | v5(Redis 队列可视化管理) | -| **PHPUnit** | v11(测试框架) | -| **Node.js** | 20.x LTS | -| **MySQL** | 8.0+ | -| **Redis** | 7.x | - ---- - -## 二、代码规范(强制执行) - -### 2.1 Laravel Pint 格式化 - -```bash -# 提交代码前必须运行,修复格式问题 -vendor/bin/pint --dirty - -# 检查格式问题(不修复) -vendor/bin/pint --test - -# 格式化整个项目 -vendor/bin/pint -``` - -### 2.2 PHP 8.4 类型系统(必须遵守) - -```php -// ✅ 正确:构造函数属性提升 (Constructor Property Promotion) -class ChatController extends Controller -{ - public function __construct( - private readonly ChatStateService $chatState, - private readonly MessageFilterService $filter, - ) {} -} - -// ❌ 错误:不允许无参空构造函数 -class SomeClass -{ - public function __construct() {} // 禁止! -} - -// ✅ 正确:显式返回类型 + 参数类型提示 -public function send(SendMessageRequest $request): JsonResponse -{ - // ... -} - -// ✅ 正确:使用 PHP 8.4 新特性 -// 联合类型 -public function findUser(int|string $id): User|null {} - -// readonly 属性 -class MessageDto -{ - public function __construct( - public readonly string $content, - public readonly string $fromUser, - public readonly int $roomId, - ) {} -} -``` - -### 2.3 Laravel 12 中间件配置(重要) - -> [!IMPORTANT] -> Laravel 12 已废弃 `Kernel.php`,中间件在 `bootstrap/app.php` 中配置。 - -```php -// bootstrap/app.php -return Application::configure(basePath: dirname(__DIR__)) - ->withRouting( - web: __DIR__.'/../routes/web.php', - api: __DIR__.'/../routes/api.php', // API 路由 - channels: __DIR__.'/../routes/channels.php', // WebSocket 频道 - commands: __DIR__.'/../routes/console.php', - health: '/up', - ) - ->withMiddleware(function (Middleware $middleware): void { - // 注册聊天室登录验证中间件 - $middleware->alias([ - 'chat.auth' => \App\Http\Middleware\ChatAuthenticate::class, - 'chat.level' => \App\Http\Middleware\LevelRequired::class, - 'chat.site_owner' => \App\Http\Middleware\SiteOwnerOnly::class, - ]); - }) - ->withExceptions(function (Exceptions $exceptions): void { - // - })->create(); -``` - -### 2.4 中文注释规范(每个文件必须) - -```php -redis->hset("room:{$roomId}:users", $username, json_encode($userInfo)); - } -} -``` - ---- - -## 三、首次启动(必须先执行) - -```bash -cd /Users/pllx/Web/Herd/chatroom - -# 安装 PHP 依赖(已完成) -composer install - -# 创建数据库(已完成) -mysql -u root -proot -e "CREATE DATABASE IF NOT EXISTS chatroom CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" - -# 运行数据库迁移 + 基础数据填充 -php artisan migrate --seed - -# 安装前端依赖并构建(已完成) -npm install -npm run build -``` - -**开发时运行的服务**: - -```bash -php artisan reverb:start --debug # WebSocket 服务器 :8080 -php artisan horizon # 队列 Worker(含 Web 监控 /horizon) -npm run dev # Vite 热更新(开发阶段) -# HTTP 由 Herd 自动提供 chatroom.test -``` - ---- - -## 四、数据库迁移对照表 - -**原 Access 表** → **Laravel Migration** 对应关系: - -| 原 ASP 表 | Laravel 迁移文件 | Model 类 | 说明 | -| ----------- | ---------------------------------- | ------------------- | ---------------------------------- | -| `user` | `create_users_table` | `User` | 主用户表(含 jjb 金币 / exp 经验) | -| `room` | `create_rooms_table` | `Room` | 聊天房间 | -| _(内存)_ | `create_messages_table` | `Message` | 消息归档(实时用 Redis) | -| `sysparam` | `create_sys_params_table` | `Sysparam` | 系统参数(alias/guidetxt/body) | -| `ip_lock` | `create_ip_locks_table` | `IpLock` | IP 封锁 | -| `record` | `create_audit_logs_table` | `AuditLog` | 管理操作日志 | -| `guestbook` | `create_guestbooks_table` | `Guestbook` | 留言板 | -| `calls` | `create_friend_calls_table` | `FriendCall` | 好友呼叫 | -| `friendrq` | `create_friend_requests_table` | `FriendRequest` | 好友申请 | -| `action` | `create_actions_table` | `Action` | 表情/动作定义 | -| `admincz` | `create_admin_logs_table` | `AdminLog` | 管理员操作统计 | -| `gg` | `create_user_items_table` | `UserItem` | 道具(封口令等) | -| `scrollad` | `create_scroll_ads_table` | `ScrollAd` | 滚动公告 | -| `hy` / `lh` | `create_marriages_table` | `Marriage` | 婚姻关系 | -| `ip` | `create_ip_logs_table` | `IpLog` | IP 登录日志 | -| `room_des` | `create_room_descriptions_table` | `RoomDescription` | 房间描述模板 | -| `autoact` | `create_autoacts_table` | `Autoact` | 机器人随机事件 | -| _(新增)_ | `create_gifts_table` | `Gift` | 礼物/鲜花定义(名称/图标/金币) | -| _(新增)_ | `create_shop_items_table` | `ShopItem` | 商店商品(特效卡/改名卡等) | -| _(新增)_ | `create_user_purchases_table` | `UserPurchase` | 用户购买记录 | -| _(新增)_ | `create_vip_levels_table` | `VipLevel` | VIP 会员等级(倍率/进入模板) | -| _(新增)_ | `create_ai_provider_configs_table` | `AiProviderConfig` | AI 服务商配置(多厂商支持) | -| _(新增)_ | `create_ai_usage_logs_table` | `AiUsageLog` | AI 使用日志(Token 用量记录) | -| _(新增)_ | `create_username_blacklist_table` | `UsernameBlacklist` | 用户名黑名单 | -| _(新增)_ | `create_user_currency_logs_table` | `UserCurrencyLog` | 积分流水(经验/金币/魅力变动记录) | - ---- - -## 五、推荐目录结构 - -``` -app/ -├── Events/ # WebSocket 广播事件(ShouldBroadcast) -│ ├── MessageSent.php # 消息发送(替代 NEWSAY.ASP) -│ ├── UserJoined.php # 用户进房(替代 INIT.ASP) -│ ├── UserLeft.php # 用户离开(替代 LEAVE.ASP) -│ ├── UserKicked.php # 踢人 -│ ├── UserMuted.php # 封口 -│ ├── UserLevelUp.php # 用户升级通知 -│ ├── RoomTitleUpdated.php # 房间标题更新 -│ ├── ScreenCleared.php # 管理员清屏 -│ └── EffectBroadcast.php # 特效广播(烟花/下雨等) -│ -├── Services/ # 业务逻辑服务层(纯 PHP,不含 HTTP 逻辑) -│ ├── ChatStateService.php # Redis 全局状态(替代 Application 对象) -│ ├── MessageFilterService.php # 敏感词/HTML 过滤 -│ ├── UserLevelService.php # 等级权限判断(替代 getLevel()) -│ ├── AiChatService.php # AI 聊天服务(多厂商适配:OpenAI/DeepSeek 等) -│ ├── VipService.php # VIP 开通/到期检查 -│ ├── ShopService.php # 商店购买 + 道具激活逻辑 -│ └── UserCurrencyService.php # ⭐ 积分统一操作服务(所有经验/金币/魅力变更必须经此) -│ -├── Http/ -│ ├── Controllers/ -│ │ ├── AuthController.php # DEFAULT.asp + CHECK.asp + CLOSE.ASP -│ │ ├── ChatController.php # NEWSAY.ASP + INIT.ASP + LEAVE.ASP + 心跳 -│ │ ├── RoomController.php # ROOM*.ASP 系列(大厅/创建/编辑/删除/转让) -│ │ ├── UserController.php # USERSET + DOUSER + KILLUSER + 封禁/解封 -│ │ ├── GuestbookController.php # GUEST.ASP(留言板) -│ │ ├── LeaderboardController.php # TOP10.ASP(排行榜) -│ │ ├── ShopController.php # 商店购买 + 改名 -│ │ ├── ChatBotController.php # AI 聊天机器人接口 -│ │ ├── FishingController.php # 钓鱼小游戏(复刻原版 diaoyu/ 功能) -│ │ ├── AdminCommandController.php # 聊天室内管理员快捷命令 -│ │ └── Admin/ -│ │ ├── DashboardController.php # 后台首页总览 -│ │ ├── SystemController.php # VIEWSYS.ASP 系统参数配置 -│ │ ├── UserManagerController.php # 用户大盘管理 -│ │ ├── RoomManagerController.php # 房间大盘管理 -│ │ ├── AutoactController.php # 随机事件管理 -│ │ ├── VipController.php # VIP 等级 CRUD -│ │ ├── AiProviderController.php # AI 厂商配置管理(含启用/禁用/设为默认) -│ │ ├── CurrencyStatsController.php # ⭐ 积分流水活动统计(每日来源产出分析) -│ │ └── SmtpController.php # 邮件发信配置 -│ │ -│ ├── Middleware/ -│ │ ├── ChatAuthenticate.php # 聊天室登录验证(检查 Session) -│ │ ├── LevelRequired.php # 等级权限中间件(chat.level:super) -│ │ └── SiteOwnerOnly.php # 超级站长专属(chat.site_owner) -│ │ -│ └── Requests/ # Form Request 验证 -│ ├── LoginRequest.php -│ ├── SendMessageRequest.php -│ └── CreateRoomRequest.php -│ -├── Models/ -│ ├── User.php ├── Room.php ├── Message.php -│ ├── Sysparam.php ├── IpLock.php ├── IpLog.php -│ ├── AuditLog.php ├── AdminLog.php ├── Guestbook.php -│ ├── FriendCall.php ├── FriendRequest.php ├── Marriage.php -│ ├── Action.php ├── Autoact.php ├── ScrollAd.php -│ ├── RoomDescription.php ├── UserItem.php ├── Gift.php -│ ├── ShopItem.php ├── UserPurchase.php ├── VipLevel.php -│ ├── AiProviderConfig.php ├── AiUsageLog.php ├── UsernameBlacklist.php -│ ├── UserCurrencyLog.php # ⭐ 积分流水记录 -│ └── System/ -│ └── PlatformSmtpAccount.php -│ -├── Enums/ -│ └── CurrencySource.php # ⭐ 积分来源枚举(auto_save/fishing_gain/admin_adjust 等) -│ -└── Jobs/ - └── SaveMessageJob.php # 异步将消息持久化到 MySQL - -bootstrap/ -└── app.php # ⚠ Laravel 12:中间件/路由在此配置(无 Kernel.php) - -routes/ -├── web.php # 所有 HTTP 路由 -├── api.php # API 路由(验证码等) -└── channels.php # WebSocket Presence Channel 鉴权 -``` - ---- - -## 六、具体开发任务计划 - -> **图例**:`[x]` 已完成 · `[/]` 进行中 · `[ ]` 待开发 - ---- - -### ✅ 第一阶段:数据库层 - -- [x] 修改默认 `users` 迁移(username/jjb/exp/sex/headface/user_level/email 等) -- [x] 创建 `rooms` 迁移(room_name/owner/auto/des/title/permit_level/door_open) -- [x] 创建 `messages` 迁移(room_id/from_user/to_user/content/is_secret/font_color/action/sent_at) -- [x] 创建 `sys_params` 迁移(alias/guidetxt/body) -- [x] 创建 `ip_locks` 迁移 -- [x] 创建 `audit_logs` 迁移 -- [x] 创建 `guestbooks` 迁移 -- [x] 创建 `friend_calls` 迁移 -- [x] 创建 `friend_requests` 迁移 -- [x] 创建 `actions` 迁移 -- [x] 创建 `admin_logs` 迁移 -- [x] 创建 `user_items` 迁移(封口令道具) -- [x] 创建 `scroll_ads` 迁移 -- [x] 创建 `marriages` 迁移 -- [x] 创建 `ip_logs` 迁移 -- [x] 创建 `room_descriptions` 迁移 -- [x] 创建 `autoacts` 迁移(随机事件/机器人自动发言) -- [x] 创建 `gifts` 迁移(礼物定义:emoji/cost/charm) -- [x] 创建 `shop_items` 迁移(商店商品:特效卡/改名卡) -- [x] 创建 `user_purchases` 迁移(购买记录) -- [x] 创建 `vip_levels` 迁移(VIP 等级:倍率/进入模板/价格) -- [x] 创建 `ai_provider_configs` 迁移(AI 服务商配置) -- [x] 创建 `ai_usage_logs` 迁移(AI 用量日志) -- [x] 创建 `username_blacklist` 迁移(用户名黑名单) -- [x] 创建所有 Model 文件(含 `$fillable`、`$casts`、关联关系、中文 DocBlock) -- [x] 创建 `DatabaseSeeder`(默认房间「公共大厅」、系统参数) -- [x] 运行 `php artisan migrate --seed` 验证建表成功 - ---- - -### ✅ 第二阶段:Auth 认证 - -- [x] `AuthController::login()` — 登录(含 IP 封锁检查 + 密码 bcrypt) -- [x] `AuthController::logout()` — 退出并清理 Redis 用户状态 -- [x] `ChatAuthenticate` 中间件 — 检查 Session 是否有效 -- [x] `LevelRequired` 中间件 — 权限等级检查(`chat.level:super`) -- [x] `SiteOwnerOnly` 中间件 — 超级站长专属(最高权限区块) -- [x] 登录 Blade 视图 `resources/views/index.blade.php` -- [x] 测试:登录 → 退出完整流程 - ---- - -### ✅ 第三阶段:Redis 状态层 - -- [x] `ChatStateService` — 完整实现(userJoin/userLeave/getRoomUsers/pushMessage/nextMsgId/withLock/getSysParam) -- [x] `MessageFilterService` — 敏感词替换 + HTML 过滤 -- [x] `UserLevelService` — 等级权限判断 - ---- - -### ✅ 第四阶段:WebSocket 广播 - -- [x] `MessageSent` Event(广播到 `room.{id}` Presence Channel) -- [x] `UserJoined` Event — 用户进入广播 -- [x] `UserLeft` Event — 用户离开广播 -- [x] `UserKicked` Event — 踢人广播(私有频道) -- [x] `UserMuted` Event — 封口广播 -- [x] `UserLevelUp` Event — 升级通知广播 -- [x] `RoomTitleUpdated` Event — 标题更新广播 -- [x] `ScreenCleared` Event — 管理员清屏广播 -- [x] `EffectBroadcast` Event — 特效广播(烟花/下雨/闪电/彩带) -- [x] `routes/channels.php` — Presence Channel 鉴权 -- [x] `resources/js/chat.js` — Laravel Echo 接入 -- [x] Reverb 连通性测试通过 - ---- - -### ✅ 第五阶段:聊天核心 - -- [x] `ChatController::init()` — 进入房间(历史消息 + 在线用户) -- [x] `ChatController::send()` — 发言(过滤 → Redis → SaveMessageJob → 广播) -- [x] `ChatController::heartbeat()` — 挂机心跳(限流:每分钟6次) -- [x] `ChatController::leave()` — 离开房间 -- [x] `ChatController::headfaceList()` — 头像列表 -- [x] `ChatController::changeAvatar()` — 修改头像 -- [x] `ChatController::setAnnouncement()` — 设置房间公告 -- [x] `ChatController::sendFlower()` — 送花/礼物(扣金币 + 增魅力) -- [x] `SaveMessageJob` — 异步消息持久化到 MySQL -- [x] 聊天主界面 Blade 视图 `resources/views/chat/frame.blade.php` -- [x] 测试:进房 → 发言 → 实时收到消息 - ---- - -### ✅ 第六阶段:房间管理 - -- [x] `RoomController::index()` — 大厅房间列表 -- [x] `RoomController::store()` — 创建房间 -- [x] `RoomController::update()` — 修改设置 -- [x] `RoomController::destroy()` — 删除/解散房间 -- [x] `RoomController::transfer()` — 转让房主 -- [x] 对应 Blade 视图(大厅列表、引导页) - ---- - -### ✅ 第七阶段:用户管理 - -- [x] `UserController::show()` — 用户名片/资料页 -- [x] `UserController::updateProfile()` — 修改个人资料 -- [x] `UserController::changePassword()` — 改密码 -- [x] `UserController::kick()` — 踢人 -- [x] `UserController::mute()` — 封口 -- [x] `UserController::ban()` — 封号 -- [x] `UserController::banIp()` — 封 IP -- [x] 邮箱验证码发送(`Api\VerificationController`) - ---- - -### ✅ 第八阶段:管理后台 - -- [x] `Admin\DashboardController` — 后台首页总览 -- [x] `Admin\SystemController` — 系统参数配置 -- [x] `Admin\SmtpController` — 邮件发信配置 -- [x] `Admin\UserManagerController` — 用户大盘管理(编辑/删除) -- [x] `Admin\RoomManagerController` — 房间大盘管理 -- [x] `Admin\AutoactController` — 随机事件 CRUD 管理 -- [x] `Admin\VipController` — VIP 等级 CRUD 管理 -- [x] `Admin\AiProviderController` — AI 厂商配置管理(含启用/禁用/设为默认) -- [x] Horizon 面板 `/horizon`(队列监控) -- [x] 对应 Blade 视图 - ---- - -### ✅ 第九阶段:外围功能 - -- [x] `LeaderboardController` — 风云排行榜(经验/金币/魅力榜) -- [x] `GuestbookController` — 留言板(发表/删除) - ---- - -### ✅ 第十阶段:扩展玩法 - -- [x] **钓鱼小游戏** `FishingController` — 复刻原版 `diaoyu/` 功能(投竿/收竿/随机收益) -- [x] **AI 聊天机器人** `ChatBotController` + `AiChatService`(多厂商:OpenAI/DeepSeek/Gemini 等) -- [x] **礼物/送花系统** — `Gift` 模型 + `ChatController::sendFlower()`(金币消耗 + 魅力增量) -- [x] **商店系统** `ShopController` + `ShopService`(购买特效卡/改名卡,`ShopItem` + `UserPurchase`) -- [x] **VIP 会员系统** `VipService` + `VipLevel`(进入/离开专属模板、倍率加成) -- [x] **管理员快捷命令** `AdminCommandController`(警告/踢人/封口/冻结/清屏/全服广播/特效) -- [x] **特效系统** `EffectBroadcast` Event(烟花/下雨/闪电/彩带,支持单次卡/周卡) - ---- - -### ✅ 第十一阶段:积分流水审计系统 - -- [x] `App\Enums\CurrencySource` — 所有来源枚举(可扩展) -- [x] `App\Models\UserCurrencyLog` — 流水 Model(含查询 Scope) -- [x] `App\Services\UserCurrencyService` — 统一积分变更服务(**所有经验/金币/魅力修改必须走此服务**) -- [x] 接入 `AutoSaveExp`(auto_save 来源) -- [x] 接入 `FishingController`(fishing_cost / fishing_gain 来源) -- [x] 接入 `ChatController::init()` 新人礼包(newbie_bonus 来源) -- [x] 接入 `Admin\UserManagerController`(admin_adjust 来源) -- [x] `LeaderboardController::todayIndex()` — 今日风云榜独立页(`/leaderboard/today`) -- [x] `LeaderboardController::myLogs()` — 用户个人流水日志(`/my/currency-logs`) -- [x] `Admin\CurrencyStatsController` — 后台积分活动统计(`/admin/currency-stats`) -- [x] 导航栏新增「📅 今日榜」按钮,后台侧边栏新增「📈 积分流水统计」入口 - ---- - -### 🔲 待完善事项 - -- [x] **用户名禁词管理**(已完成) - - `username_blacklist` 表新增 `type`(`temp`/`permanent`)和 `reason` 字段 - - `temp` = 改名后旧名30天保留;`permanent` = 管理员永久禁用词 - - `UsernameBlacklist::isBlocked()` 精确匹配两种类型,`isReserved()` 保留兼容 - - 注册(`AuthController`)和改名(`ShopService::useRenameCard`)均经过检测 - - 后台「🚫 禁用用户名」页面(站长专用): - - 单个添加 / 批量添加(多行/逗号/空格分隔,自动去重) - - 关键词搜索 + 分页列表 - - 行内编辑原因备注、删除 - - 已预置:系统保留词、国家领导人名称、侮辱性词汇 -- [ ] **滚动公告管理**(后台 CRUD,`ScrollAd` 模型已建,界面待完成) -- [x] **好友系统**(已完成) - - 好友面板独立 partial:`resources/views/chat/partials/friend-panel.blade.php` - - 工具栏「好友」按钮,点击弹出浮窗 - - 「我关注的好友」列表:显示互相状态(💚互相/👤单向)、添加时间、删除按钮 - - 「对方已加我」列表:显示对方添加时间、➕ 回加按钮 - - 搜索栏:输入用户名 Enter/点击直接添加好友 - - 所有操作调用与双击用户卡片相同的后端接口 - - `FriendController::index()` 返回 `friends`(含 `sub_time`)和 `pending` 两个列表 -- [ ] **婚姻系统**(`Marriage` 模型已建,界面待完成) -- [ ] **单元测试**(核心 Service 层测试覆盖率) -- [ ] **Flash 游戏替代**(`game/`、`pig/` 等 .swf 文件,考虑 HTML5/Canvas 重写) - ---- - -## 七、注意事项 - -### 7.1 密码策略 - -- 所有用户密码使用 `bcrypt`(`Hash::make()`) -- 登录时使用 `Hash::check()` 验证 - -### 7.2 实时推送机制 - -**聊天室所有状态变更均通过 Reverb WebSocket 广播**,无需轮询刷新。 - -> [!NOTE] -> 历史上基于 `` 的 6秒刷新方案已被完全取代,任何涉及聊天室状态更新的功能都应通过 Event → Broadcasting 实现,**禁止在实现中引入轮询逻辑**。 - -### 7.3 Redis 状态层设计 - -| 数据 | Redis Key 格式 | 说明 | -| ------------ | ------------------------- | -------------------------- | -| 在线用户列表 | `room:{id}:users` Hash | 值为用户信息 JSON | -| 消息环形缓冲 | `room:{id}:messages` List | 最多保留 200 条 | -| 房间基本信息 | `room:{id}:info` String | JSON 快照 | -| 并发锁 | `Cache::lock("key", 10)` | 使用 `->block(5, fn)` 实现 | - -### 7.4 Flash 游戏(暂不处理) - -`game/`、`pig/`、`Gupiao/` 等目录内的 `.swf` Flash 文件现代浏览器已不支持,**本期不做转换**。 - -### 7.5 AI 机器人多厂商支持 - -`AiChatService` 支持以下 Provider,通过 `ai_provider_configs` 后台配置切换: - -| Provider | 推荐模型 | 说明 | -| ---------- | ------------------ | ---------------------------- | -| `openai` | `gpt-4o-mini` | OpenAI 官方 API | -| `deepseek` | `deepseek-chat` | 国产低成本,兼容 OpenAI 接口 | -| `gemini` | `gemini-1.5-flash` | Google Gemini | - -### 7.6 商店商品类型说明 - -| type | slug 示例 | 说明 | -| ---------- | ---------------- | ---------------------- | -| `instant` | `once_fireworks` | 单次特效卡(即时生效) | -| `duration` | `week_fireworks` | 周卡(7天内持续生效) | -| `rename` | `rename` | 改名卡(改变显示名称) | - ---- - -### 7.7 积分流水系统 — 开发者使用指南 ⭐ - -> [!IMPORTANT] -> **铁律**:所有涉及修改用户 `exp_num`(经验)、`jjb`(金币)、`meili`(魅力)的操作, -> **必须通过 `UserCurrencyService::change()` 执行**,禁止直接操作 `$user->increment()` 或 `User::update()`。 - -#### 8.1 注入服务 - -```php -use App\Enums\CurrencySource; -use App\Services\UserCurrencyService; - -public function __construct( - private readonly UserCurrencyService $currencyService, -) {} -``` - -#### 8.2 单次变更 - -```php -// 给用户增加经验(正数=增加,负数=扣除) -$this->currencyService->change( - user: $user, - currency: 'exp', // 'exp' | 'gold' | 'charm' - amount: 10, // 正数=增加,负数=消耗(不会低于0) - source: CurrencySource::AUTO_SAVE, // 来源(必须用 Enum,不得写裸字符串) - remark: '挂机获得经验', // 可选备注 - roomId: 1, // 可选房间ID -); - -// 扣金币(钓鱼消耗) -$this->currencyService->change($user, 'gold', -5, CurrencySource::FISHING_COST, '抛竿消耗'); -``` - -#### 8.3 批量变更(自动存点场景) - -```php -// 对多个用户批量发放,内部逐条原子执行 -$this->currencyService->batchChange( - users: $onlineUsers, // Collection - currency: 'exp', - amount: 1, - source: CurrencySource::AUTO_SAVE, - remark: '定时存点', -); -``` - -#### 8.4 添加新的积分来源(扩展 Enum) - -在 `App\Enums\CurrencySource` 枚举中新增一个常量即可,**无需修改数据库**: - -```php -// app/Enums/CurrencySource.php -enum CurrencySource: string -{ - case AUTO_SAVE = 'auto_save'; - case FISHING_COST = 'fishing_cost'; - case FISHING_GAIN = 'fishing_gain'; - case NEWBIE_BONUS = 'newbie_bonus'; - case ADMIN_ADJUST = 'admin_adjust'; - // ↓ 新增活动时在此追加一行即可 - case DAILY_SIGN_IN = 'daily_sign_in'; // 示例:每日签到 - - /** 返回可读名称(用于后台统计展示) */ - public function label(): string - { - return match($this) { - self::AUTO_SAVE => '⏰ 自动存点', - self::FISHING_COST => '🎣 钓鱼消耗', - self::FISHING_GAIN => '🐟 钓鱼收获', - self::NEWBIE_BONUS => '🎁 新人礼包', - self::ADMIN_ADJUST => '🛠️ 管理员调整', - self::DAILY_SIGN_IN => '📅 每日签到', // 对应新增 - }; - } -} -``` - -#### 8.5 流水查询 Scope - -```php -use App\Models\UserCurrencyLog; - -// 查询某用户最近7天的经验记录 -$logs = UserCurrencyLog::where('user_id', $user->id) - ->currency('exp') - ->whereDate('created_at', '>=', now()->subDays(7)) - ->orderByDesc('created_at') - ->get(); - -// 今日金币排行(今日获得量前20名) -$ranking = UserCurrencyLog::whereDate('created_at', today()) - ->where('currency', 'gold') - ->where('amount', '>', 0) // 只算增加,不算消耗 - ->selectRaw('user_id, username, SUM(amount) as total') - ->groupBy('user_id', 'username') - ->orderByDesc('total') - ->limit(20) - ->get(); -``` - -#### 8.6 相关页面路由速查 - -| 页面 | 路由名 | URI | -| ------------ | ---------------------------- | --------------------------------------- | -| 个人积分日志 | `currency.my-logs` | `/my/currency-logs?currency=exp&days=7` | -| 今日风云榜 | `leaderboard.today` | `/leaderboard/today` | -| 累计风云榜 | `leaderboard.index` | `/leaderboard` | -| 后台积分统计 | `admin.currency-stats.index` | `/admin/currency-stats?date=2026-02-28` | - ---- - -### 7.8 全局弹窗系统 `window.chatDialog` ⭐ - -> [!IMPORTANT] -> 聊天室内**禁止使用**浏览器原生的 `alert()` / `confirm()` / `prompt()`。 -> 原因:原生弹窗在 Chrome 中会与 `beforeunload` / `pagehide` 事件产生冲突,导致弹窗闪烁消失。 -> **所有需要提示或确认的场景,必须使用 `window.chatDialog`。** - -#### 文件位置 - -``` -resources/views/chat/partials/global-dialog.blade.php ← 弹窗 HTML + JS -resources/views/chat/frame.blade.php ← 已 @include,全页面可用 -``` - -#### API 说明 - -| 方法 | 模式 | 返回值 | 说明 | -| ----------------------------------------- | ----------------- | ------------------ | ---------------- | -| `chatDialog.alert(msg, title?, color?)` | 仅「确定」按钮 | `Promise` | 替代 `alert()` | -| `chatDialog.confirm(msg, title?, color?)` | 「取消」+「确定」 | `Promise` | 替代 `confirm()` | - -参数说明: - -- `msg`:弹窗正文内容(字符串) -- `title`:标题栏文字,默认 `'提示'` / `'请确认'` -- `color`:标题栏背景色(CSS 颜色值),默认蓝色 `#336699` / 红色 `#cc4444` - -#### 使用示例 - -```javascript -// ① alert 模式(提示成功 — 绿色) -await window.chatDialog.alert("操作成功!", "提示", "#16a34a"); - -// ② alert 模式(提示失败 — 红色) -await window.chatDialog.alert("网络异常,请稍后重试", "错误", "#cc4444"); - -// ③ confirm 模式(执行危险操作前确认) -const yes = await window.chatDialog.confirm( - "确定要撤销该用户的职务吗?撤销后将不再拥有相关权限。", - "撤销职务", // 标题默认红色 -); -if (yes) { - // 用户点了「确定」 -} - -// ④ confirm 模式 — 自定义颜色 -const leave = await window.chatDialog.confirm( - "确定要离开聊天室吗?", - "离开聊天室", - "#cc4444", -); -if (leave) { - leaveRoom(); -} -``` - -#### 在 Alpine.js 组件内使用 - -`userCardComponent` 组件已通过代理方法封装: - -```javascript -// 在 Alpine.js 组件方法中,可以直接用 this.$alert / this.$confirm -await this.$alert("任命成功!", "任命成功 ✨", "#16a34a"); - -const ok = await this.$confirm("确定撤销职务?", "撤销确认"); -if (ok) { - /* ... */ -} -``` - -这两个方法内部等价于 `window.chatDialog.alert()` / `window.chatDialog.confirm()`。 - -#### 颜色速查 - -| 场景 | 推荐颜色 | -| --------------- | ----------------------- | -| 成功 / 正向操作 | `#16a34a`(绿色) | -| 错误 / 警告 | `#cc4444`(红色) | -| 一般提示 | `#336699`(蓝色,默认) | -| 撤销 / 中性操作 | `#6b7280`(灰色) | -| 管理 / 特权操作 | `#7c3aed`(紫色) | - ---- - -### 7.9 全局右下角 Toast 通知卡片 `window.chatToast` ⭐ - -> [!NOTE] -> `chatToast` 是固定在**右下角**的轻量通知卡片,适用于实时事件通知(奖励到账、好友动态等)。 -> 与 `chatDialog` 不同,它不阻断操作流程,自动消失,可堆叠多条。 - -#### 文件位置 - -``` -resources/views/chat/partials/toast-notification.blade.php ← Toast 组件 HTML + JS -resources/views/chat/frame.blade.php ← 已 @include,全页面可用 -``` - -#### API 说明 - -```javascript -window.chatToast.show({ - title: "标题文字", // 必填 - message: "正文内容", // 必填,支持 HTML - icon: "🪙", // 可选,左侧 Emoji,默认 💬 - color: "#f59e0b", // 可选,强调色,默认 #336699 - duration: 6000, // 可选,自动消失毫秒,0 = 不自动消失,默认 6000 - action: { - // 可选,操作按钮 - label: "操作文字", - onClick: () => { - /* ... */ - }, - }, -}); -``` - -#### 通过消息字段自动触发(后端控制) - -后端 broadcast 的消息中包含 `toast_notification` 字段,且接收方是当前用户时,前端脚本会自动弹出 Toast: - -```php -// AdminCommandController::reward() 示例 -$msg['toast_notification'] = [ - 'title' => '🪙 奖励金币到账', - 'message' => "{$admin->username} 向你发放了 {$amount} 枚金币!", - 'icon' => '🪙', - 'color' => '#f59e0b', - 'duration' => 8000, -]; -``` - -#### 使用场景 - -| 场景 | 颜色 | 图标 | -| ---------------- | --------------- | ---- | -| 奖励金币到账 | `#f59e0b`(橙) | 🪙 | -| 好友动态通知 | `#6b7280`(灰) | 👥 | -| 礼物收到 | `#e11d48`(玫) | 🎁 | -| 系统提示(普通) | `#336699`(蓝) | 💬 | -| 等级晋升 | `#7c3aed`(紫) | 🌟 | - -#### 原 `showFriendToast` 迁移说明 - -旧函数 `showFriendToast()` 已被 `window.chatToast.show()` 替代,好友删除通知已改用新 API。 -新增功能只需调用 `window.chatToast.show()`,**勿新增** `showFriendToast` 调用。 - ---- - -### 7.10 全局大卡片通知 `window.chatBanner` ⭐ - -> [!NOTE] -> `chatBanner` 是居中弹出的沉浸式大卡片通知组件,适用于好友通知、任命公告、系统广播等重要事件。与 `chatDialog` 不同,它**不阻断操作流程**,支持自动消失和自定义按钮。 - -#### 文件位置 - -``` -resources/views/chat/partials/scripts.blade.php ← chatBanner 定义(window.chatBanner) -app/Events/BannerNotification.php ← 广播事件(后端推送) -app/Http/Controllers/Admin/BannerBroadcastController.php ← 管理员推送接口 -``` - -#### 前端 API - -```javascript -window.chatBanner.show(options); // 显示大卡片 -window.chatBanner.close(id); // 关闭指定 banner -``` - -#### `show(options)` 参数说明 - -| 参数 | 类型 | 说明 | 默认值 | -| ------------ | ---------- | ------------------------------------------- | --------------------------------- | -| `id` | `string` | 可选,banner DOM ID,同 ID 自动覆盖防重叠 | `'chat-banner-default'` | -| `icon` | `string` | 顶部 Emoji 图标 | 无 | -| `title` | `string` | 小标题(显示为 `══ 标题 ══`) | 无 | -| `name` | `string` | 大名字/主角行(自动 HTML 转义) | 无 | -| `body` | `string` | 主内容,支持有限 HTML(`
` 等) | 无 | -| `sub` | `string` | 副说明(小字,支持有限 HTML) | 无 | -| `gradient` | `string[]` | 渐变色数组,如 `['#4f46e5', '#db2777']` | `['#4f46e5','#7c3aed','#db2777']` | -| `titleColor` | `string` | 小标题字体颜色 | `'#fde68a'` | -| `autoClose` | `number` | 自动关闭时间(ms),`0` = 不自动关闭 | `5000` | -| `buttons` | `Button[]` | 按钮列表(见下) | 无(无按钮时不可点击) | - -`buttons` 数组元素: - -```typescript -{ - label: string, // 按钮文字 - color: string, // 背景色(CSS 颜色值) - onClick: (btn: HTMLElement, close: () => void) => void, // 点击回调 -} -``` - -#### 使用示例 - -```javascript -// ① 简单通知(5秒自动消失) -window.chatBanner.show({ - icon: "🎉💚🎉", - title: "好友通知", - name: "lkddi1", - body: "将你加为好友了!", - sub: '你们现在互为好友 🎊', - gradient: ["#065f46", "#059669", "#10b981"], - titleColor: "#a7f3d0", - autoClose: 5000, -}); - -// ② 带操作按钮(不自动关闭) -window.chatBanner.show({ - id: "friend-add-banner", - icon: "💚📩", - title: "好友申请", - name: "lkddi1", - body: "将你加为好友了!", - sub: "但你还没有回加对方为好友", - gradient: ["#1e3a5f", "#1d4ed8", "#0891b2"], - titleColor: "#bae6fd", - autoClose: 0, // 不自动关闭,等待用户操作 - buttons: [ - { - label: "➕ 回加好友", - color: "#10b981", - onClick: (btn, close) => { - btn.textContent = "处理中…"; - // ... 调用 API ... - close(); // 完成后手动关闭 - }, - }, - { - label: "稍后再说", - color: "rgba(255,255,255,0.15)", - onClick: (btn, close) => close(), - }, - ], -}); - -// ③ 手动关闭指定 banner -window.chatBanner.close("friend-add-banner"); -``` - -#### 后端推送(管理员) - -通过 `BannerNotification` 事件向**单个用户**或**整个房间**广播大卡片: - -```php -use App\Events\BannerNotification; - -// 推给单个用户(私有频道 user.{username}) -broadcast(new BannerNotification( - target: 'user', - targetId: 'lkddi', - options: [ - 'icon' => '📢', - 'title' => '系统通知', - 'body' => '你有一条新消息', - 'gradient' => ['#4f46e5', '#7c3aed'], - 'autoClose' => 6000, - ] -)); - -// 推给整个房间(Presence 频道 room.{id}) -broadcast(new BannerNotification( - target: 'room', - targetId: 1, - options: [ - 'icon' => '🎊', - 'title' => '活动公告', - 'body' => '双倍积分活动已开始!', - 'gradient' => ['#065f46', '#059669'], - 'autoClose' => 8000, - ] -)); -``` - -也可通过管理员 HTTP 接口(仅超级管理员): - -``` -POST /admin/banner/broadcast -Content-Type: application/json - -{ - "target": "room", - "target_id": 1, - "options": { - "icon": "📢", - "title": "公告", - "body": "服务器将于 10 分钟后重启", - "gradient": ["#374151", "#4b5563"], - "autoClose": 10000 - } -} -``` - -#### 渐变配色速查 - -| 场景 | 渐变数组 | -| ----------- | --------------------------------------------- | -| 好友 / 成功 | `['#065f46', '#059669', '#10b981']`(绿色) | -| 申请 / 信息 | `['#1e3a5f', '#1d4ed8', '#0891b2']`(蓝色) | -| 任命 / 荣耀 | `['#4f46e5', '#7c3aed', '#db2777']`(紫粉) | -| 撤销 / 中性 | `['#374151', '#4b5563', '#6b7280']`(灰色) | -| 警告 / 紧急 | `['#7f1d1d', '#991b1b', '#dc2626']`(红色) | -| 系统 / 特权 | `['#1e1b4b', '#312e81', '#4338ca']`(深蓝紫) | - -#### 安全说明 - -> [!IMPORTANT] -> -> - **前端控制台调用** `window.chatBanner.show()` 只影响**用户自己的浏览器**,无法推送给他人。 -> - **HTTP 推送接口** `POST /admin/banner/broadcast` 受三层中间件保护(`chat.auth` + `chat.has_position` + `chat.level:super`),普通用户调用返回 403。 -> - **内容净化**:`body`、`sub`、`title` 字段经过 `strip_tags` 白名单处理(允许 `
`),防止 XSS。 -> - **按钮 action 白名单**:仅允许 `close | add_friend | remove_friend | link`,禁止任意 JS 注入。 - ---- - -## 八、常用命令速查 - -```bash -# 创建 Model + Migration(-m 同时生成迁移) -php artisan make:model Room -m - -# 创建 Controller(-r 生成 RESTful 方法) -php artisan make:controller ChatController - -# 创建广播 Event -php artisan make:event MessageSent - -# 创建队列 Job -php artisan make:job SaveMessageJob - -# 创建 Middleware -php artisan make:middleware ChatAuthenticate - -# 创建 Form Request -php artisan make:request SendMessageRequest - -# 重置迁移(开发阶段) -php artisan migrate:fresh --seed - -# 查看路由列表 -php artisan route:list --columns=method,uri,name,action - -# 代码格式化(提交前必须运行) -vendor/bin/pint --dirty - -# Horizon 队列监控(生产环境) -php artisan horizon - -# 重启 Horizon(更新代码后) -php artisan horizon:terminate - -# 清理所有缓存 -php artisan optimize:clear -``` - ---- - -> **参照原项目**:`/Users/pllx/Web/chat/hp0709/`(VBScript ASP 源码,仅作功能参考和备查,不做数据迁移) diff --git a/GAMES_TODO.md b/GAMES_TODO.md deleted file mode 100644 index c11b7e1..0000000 --- a/GAMES_TODO.md +++ /dev/null @@ -1,98 +0,0 @@ -# 🎮 聊天室游戏开发进度 - -> 更新时间:2026-03-04 - ---- - -## ✅ 已完成 - -### 🎲 百家乐(Baccarat) - -- **类型**:定时自动开局(调度器每分钟检查,间隔可配置) -- **数据库**:`baccarat_rounds` + `baccarat_bets` -- **模型**:`BaccaratRound` / `BaccaratBet` -- **队列 Job**:`OpenBaccaratRoundJob` (开局) + `CloseBaccaratRoundJob` (摇骰结算) -- **事件**:`BaccaratRoundOpened` / `BaccaratRoundSettled`(PresenceChannel 广播) -- **控制器**:`BaccaratController`(`/baccarat/current` / `/baccarat/bet` / `/baccarat/history`) -- **前端**:`chat/partials/baccarat-panel.blade.php`(倒计时/押注/骰子动画/趋势) -- **货币来源**:`CurrencySource::BACCARAT_BET` / `BACCARAT_WIN` -- **后台配置**:`game_configs` 表,管理员可配置开关/间隔/赔率/押注范围 - -### 🎰 老虎机(Slot Machine) - -- **类型**:玩家随时主动触发(即时游戏) -- **数据库**:`slot_machine_logs` -- **模型**:`SlotMachineLog`(8种带权重图案、判奖逻辑) -- **控制器**:`SlotMachineController`(`/slot/info` / `/slot/spin` / `/slot/history`) -- **赔率**:三7×100(全服广播)/ 三钻×50 / 三同×10 / 两同×2 / 三骷髅诅咒(扣双倍) -- **聊天通知**:中奖发私信通知;三7全服公屏广播 -- **前端**:`chat/partials/slot-machine.blade.php`(三列滚轮动画/逐列停止/可拖动FAB) -- **货币来源**:`CurrencySource::SLOT_SPIN` / `SLOT_WIN` / `SLOT_CURSE` -- **后台配置**:`game_configs` 表,可配置每次消耗/每日次数上限/各赔率 - -### 📦 神秘箱子(Mystery Box) - -- **类型**:系统定时自动投放 + 管理员手动投放(即时广播暗号,先到先得) -- **数据库**:`mystery_boxes`(箱子记录)+ `mystery_box_claims`(领取日志) -- **模型**:`MysteryBox` / `MysteryBoxClaim` -- **队列 Job**:`DropMysteryBoxJob`(投放 + 公屏广播暗号 + 派发 ExpireJob)/ `ExpireMysteryBoxJob`(到期处理) -- **控制器**:`MysteryBoxController`(`/mystery-box/status` 状态查询 / `/mystery-box/claim` 领取) -- **前端**:`chat/partials/mystery-box.blade.php`(5秒轮询检测 + 可拖动FAB + 快捷输入面板) -- **领取方式**:① 聊天框直接输入暗号发送(前端拦截,不发普通消息)② 点击悬浮FAB打开面板输入 -- **箱子类型**:普通箱(500\~2000金)/ 稀有箱(5000\~20000金)/ 黑化箱(陷阱,倒扣200\~1000金) -- **货币来源**:`CurrencySource::MYSTERY_BOX` / `MYSTERY_BOX_TRAP`(含 `room_id` 流水记录) -- **后台配置**:`game_configs` 表,可配置开关/自动投放间隔/各奖励范围/陷阱概率;支持手动投放三种类型 - -### 🐎 赛马竞猜(Horse Racing) - -- **类型**:定时自动开局(调度器每分钟检查,间隔可配置) -- **数据库**:`horse_races` + `horse_bets` -- **模型**:`HorseRace` / `HorseBet` -- **队列 Job**:`OpenHorseRaceJob`(开赛广播)+ `RunHorseRaceJob`(每秒播报马匹进度 + 确定胜者)+ `CloseHorseRaceJob`(结算) -- **事件**:`HorseRaceOpened` / `HorseRaceProgress` / `HorseRaceSettled`(PresenceChannel 广播) -- **控制器**:`HorseRaceController`(`/horse-race/current` / `/horse-race/bet` / `/horse-race/history`) -- **广播**:`horse.opened` / `horse.progress` / `horse.settled` -- **前端**:`chat/partials/horse-race-panel.blade.php`(倒计时/赛马道动画/实时赔率/可拖动FAB) -- **货币来源**:`CurrencySource::HORSE_BET` / `HORSE_WIN` -- **后台配置**:`game_configs` 表,马匹数量/押注窗口/跨马时长/庄家抓水比例均可配置 - -### 🔮 神秘占卜(Fortune Telling) - -- **类型**:玩家主动使用(每日免费 N 次,额外次数消耗金币) -- **数据库**:`fortune_logs` -- **模型**:`FortuneLog`(55+ 条签文内嵌在模型中) -- **控制器**:`FortuneTellingController`(`/fortune/today` 查今日 / `/fortune/tell` 占卜 / `/fortune/history` 历史) -- **前端**:`chat/partials/fortune-panel.blade.php`(卦象摇动动画/签文卡片/当日加成状态/可拖动FAB) -- **每日限制**:免费 N 次(可配置),额外次数消耗金币 -- **广播**:暂无实时广播(占卜结果仅展示给本人) -- **货币来源**:`CurrencySource::FORTUNE_COST` -- **后台配置**:`game_configs` 表,免费次数/额外消耗/各签概率均可配置 - ---- - -## 🕐 待开发 - ---- - -## 📌 通用待办(所有游戏共用) - -- [x] 后台游戏管理页面(`/admin/game-configs`)显示各游戏实时统计数据(点击"加载实时统计"异步加载各游戏汇总卡片) -- [x] 各游戏历史记录在后台可查(管理员视角,新增 `/admin/game-history/` 路由组,支持百家乐/老虎机/赛马/神秘箱子/占卜各自的历史记录列表及详情页,含筛选分页) -- [x] 生产环境部署:`php artisan db:seed --class=GameConfigSeeder`(初始化游戏配置) 已经完成了 -- [ ] 百家乐/老虎机 全面测试(多用户并发下注) - ---- - -## 🔧 已修复的 Bug - -1. **百家乐广播频道**:`Channel` → `PresenceChannel`,解决前端收不到 WebSocket 事件 -2. **百家乐余额检查**:`$user->gold` → `$user->jjb`(字段名错误) -3. **老虎机积分日志**:普通中奖/诅咒发私信通知;三7全服广播 -4. **老虎机FAB**:支持拖动 + localStorage 位置持久化 -5. **星海小博士随机事件**:改走 `UserCurrencyService.change()`,补写流水日志 -6. **百家乐结算UI**:骰子改数字方块(跨平台);中奖/未中奖卡片重设计 -7. **全部 FAB 拖动统一**:百家乐 FAB 改为 Alpine.js `baccaratFab()` 组件,与老虎机 `slotFab()` 完全一致,位置持久化存 localStorage -8. **Alpine.js 初始化顺序**:`frame.blade.php` 中 Alpine CDN 补加 `defer`,解决所有组件 `is not defined` 错误 -9. **神秘箱子暗号领取**:改为主动尝试模式(不依赖5秒轮询),聊天框输入暗号即可触发领取;`claim()` 暗号统一转大写 -10. **神秘箱子流水记录**:`change()` 调用补上 `room_id` 参数,确保积分统计页面可按房间筛选 -11. **后台弹窗**:游戏管理页所有 `alert/confirm` 替换为全局 `window.adminDialog`(毛玻璃弹窗)