功能:字体颜色持久化、等级体系升级至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:
@@ -1,13 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
{{--
|
||||
文件功能:聊天大厅 - 房间列表页
|
||||
展示所有公开聊天房间,支持创建、编辑、转让、删除房间
|
||||
以及修改个人资料和密码
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>聊天大厅 - 飘落流星</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<!-- 引入 Alpine.js 用于简单的无代码弹窗切换 -->
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||
@extends layouts.app
|
||||
--}}
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', '聊天大厅 - 飘落流星')
|
||||
|
||||
@section('nav-icon', '🌟')
|
||||
@section('nav-title', '星光大厅')
|
||||
|
||||
@section('head')
|
||||
<style>
|
||||
.custom-scrollbar::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
@@ -22,102 +27,65 @@
|
||||
background-color: transparent;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
@endsection
|
||||
|
||||
<body class="bg-gray-100 min-h-screen text-gray-800" x-data="{
|
||||
@section('nav-right')
|
||||
{{-- admin 后台直达 --}}
|
||||
@if (Auth::user()->user_level >= 15)
|
||||
<a href="{{ route('admin.dashboard') }}" class="text-indigo-200 hover:text-white font-bold hidden sm:block">⚙️ 后台</a>
|
||||
@endif
|
||||
{{-- 个人资料 --}}
|
||||
<button @click="showProfileModal = true" class="font-medium text-sm hover:text-indigo-200 transition flex items-center">
|
||||
欢迎您,{{ Auth::user()->username }}
|
||||
</button>
|
||||
{{-- 新建房间 --}}
|
||||
@if (Auth::user()->user_level >= 10)
|
||||
<button @click="showCreateModal = true"
|
||||
class="bg-emerald-500 hover:bg-emerald-400 px-4 py-2 rounded-md font-bold text-sm transition shadow-sm">
|
||||
+ 新建房间
|
||||
</button>
|
||||
@endif
|
||||
{{-- 退出登录 --}}
|
||||
<form action="{{ route('logout') }}" method="POST" class="inline">
|
||||
@csrf
|
||||
<button type="submit"
|
||||
class="text-sm border border-white/30 hover:bg-white/10 px-4 py-2 rounded-md transition font-medium">退出登录</button>
|
||||
</form>
|
||||
@endsection
|
||||
|
||||
@section('body-data',
|
||||
"x-data=\"{
|
||||
showCreateModal: false,
|
||||
showEditModal: false,
|
||||
showTransferModal: false,
|
||||
showProfileModal: false,
|
||||
showPasswordModal: false,
|
||||
currentRoom: null
|
||||
}">
|
||||
}\"")
|
||||
|
||||
<!-- 顶部导航条 -->
|
||||
<nav class="bg-indigo-600 px-6 py-4 shadow-md sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto flex justify-between items-center text-white">
|
||||
<div class="flex items-center space-x-4">
|
||||
<span class="text-xl">🌟</span>
|
||||
<h1 class="text-xl font-extrabold tracking-wider">星光大厅</h1>
|
||||
</div>
|
||||
|
||||
<!-- 右侧操作区 -->
|
||||
<div class="flex items-center space-x-3 text-sm">
|
||||
|
||||
<!-- 留言板入口 -->
|
||||
<a href="{{ route('guestbook.index') }}"
|
||||
class="text-indigo-100 hover:text-white font-bold flex items-center bg-indigo-800/40 px-3 py-1.5 rounded-full transition shadow-inner">
|
||||
<span class="mr-1">✉️</span> 留言板
|
||||
</a>
|
||||
|
||||
<!-- 风云排行榜入口 -->
|
||||
<a href="{{ route('leaderboard.index') }}"
|
||||
class="mr-4 text-yellow-400 hover:text-yellow-300 font-bold flex items-center bg-indigo-800/50 px-3 py-1.5 rounded-full transition shadow-inner">
|
||||
<span class="mr-1">🏆</span> 风云榜
|
||||
</a>
|
||||
|
||||
<!-- admin 后台直达 -->
|
||||
@if (Auth::user()->user_level >= 15)
|
||||
<a href="{{ route('admin.dashboard') }}"
|
||||
class="mr-4 text-indigo-200 hover:text-white font-bold hidden sm:block">⚙️ 后台管理</a>
|
||||
@endif
|
||||
<!-- 点击直接在本页弹出资料卡修改 -->
|
||||
<button @click="showProfileModal = true"
|
||||
class="font-medium text-sm hover:text-indigo-200 transition flex items-center">
|
||||
欢迎您,{{ Auth::user()->username }}
|
||||
<span
|
||||
class="bg-white/20 px-2 py-0.5 rounded-full text-xs ml-2 border border-white/10 shadow-sm">LV.{{ Auth::user()->user_level }}</span>
|
||||
</button>
|
||||
|
||||
{{-- 权限按钮区 --}}
|
||||
@if (Auth::user()->user_level >= 10)
|
||||
<button @click="showCreateModal = true"
|
||||
class="bg-emerald-500 hover:bg-emerald-400 px-4 py-2 rounded-md font-bold text-sm transition shadow-sm">
|
||||
+ 新建房间
|
||||
</button>
|
||||
@endif
|
||||
|
||||
<form action="{{ route('logout') }}" method="POST" class="inline">
|
||||
@csrf
|
||||
<button type="submit"
|
||||
class="text-sm border border-white/30 hover:bg-white/10 px-4 py-2 rounded-md transition font-medium">退出登录</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- 主展示区 -->
|
||||
<main class="max-w-7xl mx-auto py-10 px-6">
|
||||
|
||||
<!-- 全局提示消息 -->
|
||||
@if (session('success'))
|
||||
<div class="bg-green-100 border-l-4 border-green-500 text-green-700 p-4 mb-8 rounded shadow-sm">
|
||||
<p class="font-bold">操作成功</p>
|
||||
<p>{{ session('success') }}</p>
|
||||
</div>
|
||||
@endif
|
||||
@if (session('error'))
|
||||
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 mb-8 rounded shadow-sm">
|
||||
<p class="font-bold">发生错误</p>
|
||||
<p>{{ session('error') }}</p>
|
||||
</div>
|
||||
@endif
|
||||
@if ($errors->any())
|
||||
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 mb-8 rounded shadow-sm">
|
||||
@section('content')
|
||||
{{-- 验证错误信息 --}}
|
||||
@if ($errors->any())
|
||||
<div class="max-w-7xl mx-auto px-6 mt-4">
|
||||
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 rounded shadow-sm">
|
||||
<ul class="list-disc list-inside text-sm">
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- 主展示区 --}}
|
||||
<main class="max-w-7xl mx-auto py-10 px-6">
|
||||
|
||||
<div class="mb-6 flex justify-between items-end border-b pb-4">
|
||||
<h2 class="text-xl font-bold text-gray-700">公开频段 (<span
|
||||
class="text-indigo-600">{{ $rooms->count() }}</span>)</h2>
|
||||
<h2 class="text-xl font-bold text-gray-700">公开频段 (<span class="text-indigo-600">{{ $rooms->count() }}</span>)
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<!-- 房间瀑布流网格 -->
|
||||
{{-- 房间瀑布流网格 --}}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
|
||||
@forelse($rooms as $room)
|
||||
<div
|
||||
@@ -145,7 +113,6 @@
|
||||
{{-- 管理按钮组(仅房主或超管可见) --}}
|
||||
<div class="flex space-x-2">
|
||||
@if ($room->master == Auth::user()->username || Auth::user()->user_level >= 15)
|
||||
<!-- 修改 -->
|
||||
<button
|
||||
@click="currentRoom = {id: {{ $room->id }}, name: '{{ addslashes($room->name) }}', description: '{{ addslashes($room->description) }}'}; showEditModal = true"
|
||||
class="text-xs text-blue-600 hover:text-blue-800 font-semibold px-2 py-1 rounded hover:bg-blue-50 transition">
|
||||
@@ -153,15 +120,12 @@
|
||||
</button>
|
||||
|
||||
@if (!$room->is_system)
|
||||
<!-- 转让 -->
|
||||
<button
|
||||
@click="currentRoom = {id: {{ $room->id }}, name: '{{ addslashes($room->name) }}'}; showTransferModal = true"
|
||||
class="text-xs text-amber-600 hover:text-amber-800 font-semibold px-2 py-1 rounded hover:bg-amber-50 transition">
|
||||
转让
|
||||
</button>
|
||||
<!-- 删除 -->
|
||||
<form action="{{ route('rooms.destroy', $room->id) }}" method="POST"
|
||||
class="inline"
|
||||
<form action="{{ route('rooms.destroy', $room->id) }}" method="POST" class="inline"
|
||||
onsubmit="return confirm('警告:确实要彻底解散「{{ $room->name }}」吗?此操作不可逆!');">
|
||||
@csrf @method('delete')
|
||||
<button type="submit"
|
||||
@@ -172,7 +136,8 @@
|
||||
</div>
|
||||
|
||||
{{-- 进入按钮 --}}
|
||||
<a href="{{ route('chat.room', $room->id) }}"
|
||||
<a href="#"
|
||||
onclick="openChatRoom('{{ route('chat.room', $room->id) }}', '{{ $room->name }}'); return false;"
|
||||
class="bg-indigo-600 text-white hover:bg-indigo-700 px-4 py-2 rounded-t-xl rounded-br-xl text-sm font-bold shadow-md hover:shadow-lg transition-all transform group-hover:-translate-y-0.5">
|
||||
立刻进入 →
|
||||
</a>
|
||||
@@ -187,7 +152,7 @@
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- 新建房间 Modal (通过 Alpine.js 开关) -->
|
||||
{{-- ═══════════ 新建房间 Modal ═══════════ --}}
|
||||
<div x-show="showCreateModal" style="display: none;"
|
||||
class="fixed inset-0 z-[100] bg-black/60 backdrop-blur-sm flex items-center justify-center p-4">
|
||||
<div @click.away="showCreateModal = false"
|
||||
@@ -221,7 +186,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 修改管理 Modal -->
|
||||
{{-- ═══════════ 修改管理 Modal ═══════════ --}}
|
||||
<div x-show="showEditModal" style="display: none;"
|
||||
class="fixed inset-0 z-[100] bg-black/60 backdrop-blur-sm flex items-center justify-center p-4">
|
||||
<div @click.away="showEditModal = false"
|
||||
@@ -232,7 +197,6 @@
|
||||
<button @click="showEditModal = false"
|
||||
class="text-blue-400 hover:text-blue-600 font-bold text-xl">×</button>
|
||||
</div>
|
||||
<!-- 注意这里通过 Alpine 动态拼接 action 路径 -->
|
||||
<form :action="'{{ url('rooms') }}/' + currentRoom?.id" method="POST" class="p-6">
|
||||
@csrf @method('PUT')
|
||||
<div class="mb-4">
|
||||
@@ -256,7 +220,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 转让房主 Modal -->
|
||||
{{-- ═══════════ 转让房主 Modal ═══════════ --}}
|
||||
<div x-show="showTransferModal" style="display: none;"
|
||||
class="fixed inset-0 z-[100] bg-black/60 backdrop-blur-sm flex items-center justify-center p-4">
|
||||
<div @click.away="showTransferModal = false"
|
||||
@@ -288,7 +252,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 个人资料设置 Modal -->
|
||||
{{-- ═══════════ 个人资料设置 Modal ═══════════ --}}
|
||||
<div x-show="showProfileModal" style="display: none;"
|
||||
class="fixed inset-0 z-[100] bg-black/60 backdrop-blur-sm flex items-center justify-center p-4">
|
||||
<div @click.away="showProfileModal = false"
|
||||
@@ -310,16 +274,28 @@
|
||||
isSaving: false,
|
||||
|
||||
async saveProfile() {
|
||||
this.isSaving = true;
|
||||
try {
|
||||
const res = await fetch('{{ route('user.update_profile') }}', {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'), 'Content-Type'
|
||||
: 'application/json' , 'Accept' : 'application/json' }, body: JSON.stringify(this.profileData) }); const
|
||||
data=await res.json(); if (res.ok && data.status === 'success') { alert(data.message);
|
||||
window.location.reload(); } else { alert('保存失败: ' + (data.message || ' 输入有误')); } } catch (e) {
|
||||
alert('网络异常'); } finally { this.isSaving=false; } } }">
|
||||
this.isSaving = true;
|
||||
try {
|
||||
const res = await fetch('{{ route('user.update_profile') }}', {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(this.profileData)
|
||||
});
|
||||
const
|
||||
data = await res.json();
|
||||
if (res.ok && data.status === 'success') {
|
||||
alert(data.message);
|
||||
window.location.reload();
|
||||
} else { alert('保存失败: ' + (data.message || ' 输入有误')); }
|
||||
} catch (e) {
|
||||
alert('网络异常');
|
||||
} finally { this.isSaving = false; }
|
||||
}
|
||||
}">
|
||||
<form @submit.prevent="saveProfile">
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-bold text-gray-700 mb-2">性别</label>
|
||||
@@ -330,7 +306,6 @@
|
||||
<option value="保密">保密</option>
|
||||
</select>
|
||||
</div>
|
||||
<!-- 头像选择 (暂时写死输入框,后续可优化为网格选择) -->
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-bold text-gray-700 mb-2">头像选择 (01.gif - 50.gif)</label>
|
||||
<div class="flex items-center space-x-3">
|
||||
@@ -363,7 +338,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 修改密码 Modal -->
|
||||
{{-- ═══════════ 修改密码 Modal ═══════════ --}}
|
||||
<div x-show="showPasswordModal" style="display: none;"
|
||||
class="fixed inset-0 z-[110] bg-black/60 backdrop-blur-sm flex items-center justify-center p-4">
|
||||
<div @click.away="showPasswordModal = false"
|
||||
@@ -384,25 +359,38 @@
|
||||
isSaving: false,
|
||||
|
||||
async savePassword() {
|
||||
if (this.pwdData.new_password !== this.pwdData.new_password_confirmation) {
|
||||
alert('两次输入的新密码不一致!');
|
||||
return;
|
||||
if (this.pwdData.new_password !== this.pwdData.new_password_confirmation) {
|
||||
alert('两次输入的新密码不一致!');
|
||||
return;
|
||||
}
|
||||
if (this.pwdData.new_password.length < 6) {
|
||||
alert('新密码最少 6 位!');
|
||||
return;
|
||||
}
|
||||
this.isSaving = true;
|
||||
try {
|
||||
const res = await fetch('{{ route('user.update_password') }}', {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(this.pwdData)
|
||||
});
|
||||
const
|
||||
data = await res.json();
|
||||
if (res.ok && data.status === 'success') {
|
||||
alert(data.message);
|
||||
window.location.href = '{{ route('home') }}';
|
||||
} else {
|
||||
alert('密码修改失败: ' + (data.message || ' 请输入正确的旧密码'));
|
||||
}
|
||||
if (this.pwdData.new_password.length < 6) {
|
||||
alert('新密码最少 6 位!');
|
||||
return;
|
||||
}
|
||||
this.isSaving = true;
|
||||
try {
|
||||
const res = await fetch('{{ route('user.update_password') }}', {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content'), 'Content-Type'
|
||||
: 'application/json' , 'Accept' : 'application/json' }, body: JSON.stringify(this.pwdData) }); const
|
||||
data=await res.json(); if (res.ok && data.status === 'success') { alert(data.message);
|
||||
window.location.href = '{{ route('home') }}'; // 改密成功重新登录 } else {
|
||||
alert('密码修改失败: ' + (data.message || ' 请输入正确的旧密码')); } } catch (e) { alert('网络异常'); } finally {
|
||||
this.isSaving=false; } } }">
|
||||
} catch (e) { alert('网络异常'); } finally {
|
||||
this.isSaving = false;
|
||||
}
|
||||
}
|
||||
}">
|
||||
<form @submit.prevent="savePassword">
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-bold text-gray-700 mb-2">当前旧密码</label>
|
||||
@@ -429,7 +417,25 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@section('scripts')
|
||||
{{-- 原版风格:弹出独立聊天窗口 --}}
|
||||
<script>
|
||||
/**
|
||||
* 打开聊天室弹出窗口(复刻原版 DEFAULT.asp 的 launchchat 函数)
|
||||
*/
|
||||
function openChatRoom(url, roomName) {
|
||||
var chatWin = window.open(
|
||||
url,
|
||||
'chatroom_' + roomName,
|
||||
'toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes'
|
||||
);
|
||||
if (chatWin) {
|
||||
chatWin.moveTo(0, 0);
|
||||
chatWin.resizeTo(screen.availWidth, screen.availHeight);
|
||||
chatWin.focus();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@endsection
|
||||
|
||||
Reference in New Issue
Block a user