功能:字体颜色持久化、等级体系升级至99级、钓鱼小游戏、补充系统参数
- 字体颜色:s_color 改为 varchar,发消息时保存颜色,进入聊天室自动恢复 - 等级体系:maxlevel 15→99,superlevel 16→100,99级经验阶梯(幂次曲线) - 管理权限等级按比例调整:禁言50、踢人60、设公告60、封号80、封IP90 - 钓鱼小游戏:FishingController(抛竿扣金币+收竿随机结果+广播) - 补充6个缺失的 sysparam 参数 + 4个钓鱼参数 - 用户列表点击用户名后自动聚焦输入框 - Pint 格式化
This commit is contained in:
@@ -16,12 +16,15 @@ use App\Events\UserJoined;
|
||||
use App\Events\UserLeft;
|
||||
use App\Http\Requests\SendMessageRequest;
|
||||
use App\Jobs\SaveMessageJob;
|
||||
use App\Models\Autoact;
|
||||
use App\Models\Room;
|
||||
use App\Models\Sysparam;
|
||||
use App\Services\ChatStateService;
|
||||
use App\Services\MessageFilterService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class ChatController extends Controller
|
||||
@@ -42,6 +45,9 @@ class ChatController extends Controller
|
||||
$room = Room::findOrFail($id);
|
||||
$user = Auth::user();
|
||||
|
||||
// 房间人气 +1(每次访问递增,复刻原版人气计数)
|
||||
$room->increment('visit_num');
|
||||
|
||||
// 1. 将当前用户加入到 Redis 房间在线列表
|
||||
$this->chatState->userJoin($id, $user->username, [
|
||||
'level' => $user->user_level,
|
||||
@@ -76,6 +82,18 @@ class ChatController extends Controller
|
||||
$data = $request->validated();
|
||||
$user = Auth::user();
|
||||
|
||||
// 0. 检查用户是否被禁言(Redis TTL 自动过期)
|
||||
$muteKey = "mute:{$id}:{$user->username}";
|
||||
if (Redis::exists($muteKey)) {
|
||||
$ttl = Redis::ttl($muteKey);
|
||||
$minutes = ceil($ttl / 60);
|
||||
|
||||
return response()->json([
|
||||
'status' => 'error',
|
||||
'message' => "您正在禁言中,还需等待约 {$minutes} 分钟。",
|
||||
], 403);
|
||||
}
|
||||
|
||||
// 1. 过滤净化消息体
|
||||
$pureContent = $this->filter->filter($data['content'] ?? '');
|
||||
if (empty($pureContent)) {
|
||||
@@ -104,6 +122,13 @@ class ChatController extends Controller
|
||||
// 5. 丢进异步列队,慢慢持久化到 MySQL,保护数据库连接池
|
||||
SaveMessageJob::dispatch($messageData);
|
||||
|
||||
// 6. 如果用户更换了字体颜色,顺便保存到 s_color 字段,下次进入时恢复
|
||||
$chosenColor = $data['font_color'] ?? '';
|
||||
if ($chosenColor && $chosenColor !== ($user->s_color ?? '')) {
|
||||
$user->s_color = $chosenColor;
|
||||
$user->save();
|
||||
}
|
||||
|
||||
return response()->json(['status' => 'success']);
|
||||
}
|
||||
|
||||
@@ -120,19 +145,22 @@ class ChatController extends Controller
|
||||
return response()->json(['status' => 'error'], 401);
|
||||
}
|
||||
|
||||
// 1. 每次心跳 +1 点经验
|
||||
$user->exp_num += 1;
|
||||
|
||||
// 2. 检查等级计算:设定简单粗暴的平滑算式:需要经验=等级*等级*10
|
||||
// 例如:0级->0点;1级->10点;2级->40点;3级->90点;10级->1000点
|
||||
$currentLevel = $user->user_level;
|
||||
$requiredExpForNextLevel = ($currentLevel) * ($currentLevel) * 10;
|
||||
// 1. 每次心跳增加经验(可在 sysparam 后台配置)
|
||||
$expGain = (int) Sysparam::getValue('exp_per_heartbeat', '1');
|
||||
$user->exp_num += $expGain;
|
||||
|
||||
// 2. 使用 sysparam 表中可配置的等级-经验阈值计算等级
|
||||
// 管理员(superlevel 及以上)不参与自动升降级,等级由后台手动设置
|
||||
$superLevel = (int) Sysparam::getValue('superlevel', '100');
|
||||
$oldLevel = $user->user_level;
|
||||
$leveledUp = false;
|
||||
|
||||
if ($user->exp_num >= $requiredExpForNextLevel) {
|
||||
$user->user_level += 1;
|
||||
$leveledUp = true;
|
||||
if ($oldLevel < $superLevel) {
|
||||
$newLevel = Sysparam::calculateLevel($user->exp_num);
|
||||
if ($newLevel !== $oldLevel && $newLevel < $superLevel) {
|
||||
$user->user_level = $newLevel;
|
||||
$leveledUp = ($newLevel > $oldLevel);
|
||||
}
|
||||
}
|
||||
|
||||
$user->save(); // 存点入库
|
||||
@@ -167,12 +195,61 @@ class ChatController extends Controller
|
||||
SaveMessageJob::dispatch($sysMsg);
|
||||
}
|
||||
|
||||
// 5. 随机事件触发(复刻原版 autoact 系统,概率可在后台配置)
|
||||
$autoEvent = null;
|
||||
$eventChance = (int) Sysparam::getValue('auto_event_chance', '10');
|
||||
if ($eventChance > 0 && rand(1, 100) <= $eventChance) {
|
||||
$autoEvent = Autoact::randomEvent();
|
||||
if ($autoEvent) {
|
||||
// 应用经验/金币变化(不低于 0)
|
||||
if ($autoEvent->exp_change !== 0) {
|
||||
$user->exp_num = max(0, $user->exp_num + $autoEvent->exp_change);
|
||||
}
|
||||
if ($autoEvent->jjb_change !== 0) {
|
||||
$user->jjb = max(0, ($user->jjb ?? 0) + $autoEvent->jjb_change);
|
||||
}
|
||||
$user->save();
|
||||
|
||||
// 重新计算等级(经验可能因事件而变化,但管理员不参与自动升降级)
|
||||
if ($user->user_level < $superLevel) {
|
||||
$recalcLevel = Sysparam::calculateLevel($user->exp_num);
|
||||
if ($recalcLevel !== $user->user_level && $recalcLevel < $superLevel) {
|
||||
$user->user_level = $recalcLevel;
|
||||
$user->save();
|
||||
}
|
||||
}
|
||||
|
||||
// 广播随机事件消息到聊天室
|
||||
$eventMsg = [
|
||||
'id' => $this->chatState->nextMessageId($id),
|
||||
'room_id' => $id,
|
||||
'from_user' => '星海小博士',
|
||||
'to_user' => '大家',
|
||||
'content' => $autoEvent->renderText($user->username),
|
||||
'is_secret' => false,
|
||||
'font_color' => match ($autoEvent->event_type) {
|
||||
'good' => '#16a34a', // 绿色(好运)
|
||||
'bad' => '#dc2626', // 红色(坏运)
|
||||
default => '#7c3aed', // 紫色(中性)
|
||||
},
|
||||
'action' => '',
|
||||
'sent_at' => now()->toDateTimeString(),
|
||||
];
|
||||
|
||||
$this->chatState->pushMessage($id, $eventMsg);
|
||||
broadcast(new MessageSent($id, $eventMsg));
|
||||
SaveMessageJob::dispatch($eventMsg);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'status' => 'success',
|
||||
'data' => [
|
||||
'exp_num' => $user->exp_num,
|
||||
'user_level' => $user->user_level,
|
||||
'leveled_up' => $leveledUp,
|
||||
'is_max_level' => $user->user_level >= $superLevel,
|
||||
'auto_event' => $autoEvent ? $autoEvent->renderText($user->username) : null,
|
||||
],
|
||||
]);
|
||||
}
|
||||
@@ -197,4 +274,105 @@ class ChatController extends Controller
|
||||
|
||||
return response()->json(['status' => 'success']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可用头像列表(返回 JSON)
|
||||
* 扫描 /public/images/headface/ 目录,返回所有可用头像文件名
|
||||
*/
|
||||
public function headfaceList(): JsonResponse
|
||||
{
|
||||
$dir = public_path('images/headface');
|
||||
$files = [];
|
||||
|
||||
if (is_dir($dir)) {
|
||||
$all = scandir($dir);
|
||||
foreach ($all as $file) {
|
||||
// 只包含图片文件
|
||||
if (preg_match('/\.(gif|jpg|jpeg|png|bmp)$/i', $file)) {
|
||||
$files[] = $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 自然排序(1, 2, 3... 10, 11...)
|
||||
natsort($files);
|
||||
|
||||
return response()->json(['headfaces' => array_values($files)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改头像(原版 fw.asp 功能)
|
||||
* 用户选择一个头像文件名,更新到 usersf 字段
|
||||
*/
|
||||
public function changeAvatar(Request $request): JsonResponse
|
||||
{
|
||||
$user = auth()->user();
|
||||
$headface = $request->input('headface', '');
|
||||
|
||||
if (empty($headface)) {
|
||||
return response()->json(['status' => 'error', 'message' => '请选择一个头像'], 422);
|
||||
}
|
||||
|
||||
// 验证文件确实存在
|
||||
if (! file_exists(public_path('images/headface/'.$headface))) {
|
||||
return response()->json(['status' => 'error', 'message' => '头像文件不存在'], 422);
|
||||
}
|
||||
|
||||
// 更新用户头像
|
||||
$user->usersf = $headface;
|
||||
$user->save();
|
||||
|
||||
return response()->json([
|
||||
'status' => 'success',
|
||||
'message' => '头像修改成功!',
|
||||
'headface' => $headface,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置房间公告/祝福语(滚动显示在聊天室顶部)
|
||||
* 需要房间主人或等级达到 level_announcement 配置值
|
||||
*
|
||||
* @param int $id 房间ID
|
||||
*/
|
||||
public function setAnnouncement(Request $request, int $id): JsonResponse
|
||||
{
|
||||
$user = Auth::user();
|
||||
$room = Room::findOrFail($id);
|
||||
|
||||
// 权限检查:房间主人 或 等级 >= level_announcement
|
||||
$requiredLevel = (int) Sysparam::getValue('level_announcement', '10');
|
||||
if ($user->username !== $room->master && $user->user_level < $requiredLevel) {
|
||||
return response()->json(['status' => 'error', 'message' => '权限不足,无法修改公告'], 403);
|
||||
}
|
||||
|
||||
$request->validate([
|
||||
'announcement' => 'required|string|max:500',
|
||||
]);
|
||||
|
||||
$room->announcement = $request->input('announcement');
|
||||
$room->save();
|
||||
|
||||
// 广播公告更新到所有在线用户
|
||||
$sysMsg = [
|
||||
'id' => $this->chatState->nextMessageId($id),
|
||||
'room_id' => $id,
|
||||
'from_user' => '系统公告',
|
||||
'to_user' => '大家',
|
||||
'content' => "📢 {$user->username} 更新了房间公告:{$room->announcement}",
|
||||
'is_secret' => false,
|
||||
'font_color' => '#cc0000',
|
||||
'action' => '',
|
||||
'sent_at' => now()->toDateTimeString(),
|
||||
];
|
||||
|
||||
$this->chatState->pushMessage($id, $sysMsg);
|
||||
broadcast(new MessageSent($id, $sysMsg));
|
||||
|
||||
return response()->json([
|
||||
'status' => 'success',
|
||||
'message' => '公告已更新!',
|
||||
'announcement' => $room->announcement,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user