Files
chatroom/DEVELOPMENT.md
T
lkddi 0c5e218aa8 功能:新增用户积分流水系统
- 新建 user_currency_logs 流水表 (Migration)
- App\Enums\CurrencySource 来源枚举(可扩展)
- App\Models\UserCurrencyLog 流水模型
- App\Services\UserCurrencyService 统一积分变更服务
- FishingController:抛竿/收竿接入流水记录
- AutoSaveExp:自动存点接入流水记录
- Admin/UserManagerController:管理员调整接入流水记录
- LeaderboardController:新增今日三榜(经验/金币/魅力)+ 个人流水日志页
- Admin/CurrencyStatsController:后台活动统计页
- views:新增个人日志页、后台统计页;排行榜新增今日榜数据传递
- routes:新增个人日志路由 /my/currency-logs、后台路由 /admin/currency-stats
2026-02-28 12:49:26 +08:00

548 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ChatRoom 开发计划与注意事项
> **技术栈**Laravel 12 · PHP 8.4 · Laravel Reverb (WebSocket) · Redis · MySQL 8.0 · Laravel Horizon
> **原项目**`/Users/pllx/Web/chat/hp0709`VBScript ASP + MS Access 聊天室)
> **目标域名**`http://chatroom.test`Herd 自动配置)| `https://chat.ay.lc`(生产环境)
---
## 一、环境版本要求
| 组件 | 版本 |
| --------------------- | -------------------------- |
| **PHP** | 8.4.5+ |
| **Laravel Framework** | v12.x |
| **Laravel Reverb** | latestWebSocket 服务器) |
| **Laravel Horizon** | v5Redis 队列可视化管理) |
| **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
<?php
/**
* 文件功能:[本文件的业务职责描述]
*
* 对应原 ASP 文件:[原文件名.asp]
*
* @package App\[命名空间]
* @author ChatRoom Laravel
* @version 1.0.0
*/
namespace App\Services;
class ChatStateService
{
/**
* 用户进入聊天房间,将其信息写入 Redis。
*
* 替代原 ASP 的 Application("_user_list") 字符串拼接操作。
*
* @param int $roomId 房间 ID
* @param string $username 用户名
* @param array $userInfo 用户信息(等级、头像、性别等)
*/
public function userJoin(int $roomId, string $username, array $userInfo): void
{
// 将用户信息序列化后存入 Redis HashKey 为 "room:{房间ID}:users"
$this->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` | 用户名黑名单 |
---
## 五、推荐目录结构
```
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 # 商店购买 + 道具激活逻辑
├── 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 厂商配置管理
│ │ └── 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
│ └── System/
│ └── PlatformSmtpAccount.php
└── 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(烟花/下雨/闪电/彩带,支持单次卡/周卡)
---
### 🔲 待完善事项
- [ ] **用户名黑名单管理**(后台 CRUD`UsernameBlacklist` 模型已建,路由/界面待完成)
- [ ] **滚动公告管理**(后台 CRUD`ScrollAd` 模型已建,界面待完成)
- [ ] **好友系统**`FriendCall` / `FriendRequest` 模型已建,Controller 待完成)
- [ ] **婚姻系统**`Marriage` 模型已建,界面待完成)
- [ ] **历史数据迁移**(从 Access 导入旧用户数据:GBK→UTF-8 转换)
- [ ] **密码兼容过渡**(旧 MD5 用户登录时自动升级为 bcrypt)
- [ ] **单元测试**(核心 Service 层测试覆盖率)
- [ ] **Flash 游戏替代**`game/``pig/` 等 .swf 文件,考虑 HTML5/Canvas 重写)
---
## 七、注意事项
### 7.1 密码兼容策略
- 导入旧数据时,`password` 字段存原始 MD5 值(32位字符串)
- 登录时双模式验证:`md5($input) === $storedPass` 成功后升级为 `bcrypt`
- 新注册用户直接用 `bcrypt``Hash::make()`
### 7.2 字符编码
- 原 Access 数据库为 **GBK 编码**
- 所有 MySQL 表必须 `utf8mb4_unicode_ci`
- 导入历史数据前转换:
```bash
iconv -f GBK -t UTF-8 原文件.csv > 目标文件_utf8.csv
```
### 7.3 REFRESH.ASP 已废弃
原系统的 6 秒 `<meta http-equiv=refresh>` **完全由 Reverb WebSocket 实时推送取代**,无需任何轮询逻辑。
### 7.4 Application 对象替代
| 原 ASP | Laravel 替代 |
| ------------------------------- | --------------------------------------------- |
| `Application("_user_list")` | `Redis::hgetall("room:{id}:users")` |
| `Application("_says")` 环形缓冲 | `Redis::lrange("room:{id}:messages", 0, 199)` |
| `Application("_room_list")` | `Redis::get("room:{id}:info")` + `rooms` 表 |
| `Application.Lock/Unlock` | `Cache::lock("key", 10)->block(5, fn)` |
### 7.5 Flash 游戏(暂不处理)
`game/`、`pig/`、`Gupiao/` 等目录内的 `.swf` Flash 文件现代浏览器已不支持,**本期不做转换**。
### 7.6 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.7 商店商品类型说明
| type | slug 示例 | 说明 |
| ---------- | ---------------- | ---------------------- |
| `instant` | `once_fireworks` | 单次特效卡(即时生效) |
| `duration` | `week_fireworks` | 周卡(7天内持续生效) |
| `rename` | `rename` | 改名卡(改变显示名称) |
---
## 八、常用命令速查
```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
```
---
> 原 ASP 源码参考路径:`/Users/pllx/Web/chat/hp0709/`
> 数据库 SQL 参考:`/Users/pllx/Web/chat/hp0709_php/database.sql`