Files
chatroom/resources/views/chat/partials/layout/toolbar.blade.php
T
2026-04-28 14:32:39 +08:00

1164 lines
53 KiB
PHP
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.
{{--
文件功能:聊天室竖向工具条(中间导航栏)+ 关联弹窗
包含:
1. 工具条按钮(管理、商店、存点、头像、设置等)
2. 头像选择弹窗
3. 个人设置弹窗(密码、资料、密保)
4. 商店弹窗(从工具栏点击打开的全屏模态)
5. 对应的 JS 操作函数
依赖变量:$user, $superLevel, $room
@author ChatRoom Laravel
@version 1.0.0
--}}
{{-- ═══════════ 竖向工具条按钮 ═══════════ --}}
<div class="chat-toolbar" id="toolbar-strip">
<div class="tool-btn" data-toolbar-action="shop" title="购买道具">商店</div>
<div class="tool-btn" data-toolbar-action="vip" title="会员中心">会员</div>
<div class="tool-btn" data-toolbar-action="save-exp" title="手动存经验点">存点</div>
<div class="tool-btn" data-toolbar-action="game" title="娱乐游戏大厅">娱乐</div>
{{-- <div class="tool-btn" data-toolbar-action="earn" title="看视频赚金币">赚钱</div> --}}
<div class="tool-btn" data-toolbar-action="bank" title="银行存取金币">银行</div>
<div class="tool-btn" data-toolbar-action="marriage" title="婚姻状态">婚姻</div>
<div class="tool-btn" data-toolbar-action="friend" title="好友列表">好友</div>
<div class="tool-btn" data-toolbar-action="avatar" title="修改头像">头像</div>
<div class="tool-btn" data-toolbar-action="settings" title="个人设置">设置
</div>
<div class="tool-btn" data-toolbar-action="feedback" title="反馈">反馈</div>
<div class="tool-btn" data-toolbar-action="guestbook" title="留言板/私信">留言</div>
<div class="tool-btn" data-toolbar-url="{{ route('guide') }}" title="规则/帮助">规则</div>
@if ($user->id === 1 || $user->activePosition()->exists())
<div class="tool-btn" style="color: #ffcc00;" data-toolbar-url="/admin" title="管理后台">管理</div>
<div class="tool-btn" data-toolbar-url="{{ route('leaderboard.index') }}" title="排行榜">排行
</div>
@else
<div class="tool-btn" data-toolbar-url="{{ route('leaderboard.index') }}" title="排行榜">排行
</div>
@endif
<div class="tool-btn" style="color: #ffaaaa;" data-toolbar-action="leave" title="离开聊天室">
离开
</div>
</div>
{{-- ═══════════ 头像选择弹窗 ═══════════ --}}
<div id="avatar-picker-modal" data-avatar-picker-overlay
style="display:none; position:fixed; top:0; left:0; right:0; bottom:0;
background:rgba(0,0,0,0.5); z-index:9999; justify-content:center; align-items:center;">
<div data-avatar-picker-panel
style="background:#fff; width:600px; max-height:80vh; border-radius:6px; overflow:hidden;
box-shadow:0 4px 20px rgba(0,0,0,0.3); display:flex; flex-direction:column;">
{{-- 标题栏 --}}
<div
style="background:#336699; color:#fff; padding:10px 16px; font-size:14px; font-weight:bold;
display:flex; justify-content:space-between; align-items:center;">
<span>🖼 修改头像(原版风格)</span>
<span style="cursor:pointer; font-size:18px;" data-avatar-picker-close></span>
</div>
{{-- 预览区 --}}
<div
style="padding:10px 16px; background:#f0f6ff; border-bottom:1px solid #ddd; display:flex; align-items:center; gap:12px; flex-wrap:wrap;">
<span style="font-size:12px; color:#666;">当前选中:</span>
<img id="avatar-preview" src="{{ str_starts_with($user->usersf, 'storage/') ? '/' . $user->usersf : '/images/headface/' . ($user->usersf ?: '1.gif') }}"
style="width:40px; height:40px; border:2px solid #336699; border-radius:4px; object-fit: cover;">
<span id="avatar-selected-name" style="font-size:12px; color:#333;">{{ $user->usersf ?: '未设置' }}</span>
<button id="avatar-save-btn" disabled data-avatar-save
style="margin-left:auto; padding:5px 16px; background:#336699; color:#fff; border:none;
border-radius:3px; font-size:12px; cursor:pointer;">确定更换系统头像</button>
<div style="width:100%; height:1px; background:#ddd; margin: 4px 0;"></div>
<div style="display:flex; align-items:center; gap:8px; width:100%;">
<span style="font-size:12px; color:#666; font-weight:bold;">自定义头像上传(112x112)</span>
<input type="file" id="avatar-upload-input" accept="image/jpeg,image/png,image/gif,image/webp" style="display:none;" data-avatar-upload-input>
<button id="avatar-upload-btn" data-avatar-upload-trigger
style="padding:5px 16px; background:#16a34a; color:#fff; border:none;
border-radius:3px; font-size:12px; cursor:pointer;">选择本地图片上传</button>
</div>
</div>
{{-- 头像网格 --}}
<div id="avatar-grid"
style="flex:1; overflow-y:auto; padding:10px; display:flex; flex-wrap:wrap;
gap:4px; align-content:flex-start;">
</div>
</div>
</div>
{{-- ═══════════ 个人设置弹窗 ═══════════ --}}
<div id="settings-modal" data-settings-modal-overlay
style="display:none; position:fixed; top:0; left:0; right:0; bottom:0;
background:rgba(0,0,0,0.5); z-index:10000; justify-content:center; align-items:center;">
<div data-settings-modal-panel
style="background:#fff; border-radius:8px; width:380px; max-height:90vh;
box-shadow:0 8px 32px rgba(0,0,0,0.3); display:flex; flex-direction:column;">
{{-- --}}
<div
style="background:linear-gradient(135deg,#336699,#5a8fc0); color:#fff;
padding:12px 16px; border-radius:8px 8px 0 0; display:flex; justify-content:space-between; align-items:center; flex-shrink:0;">
<span style="font-size:14px; font-weight:bold;">⚙️ 个人设置</span>
<span data-settings-modal-close
style="cursor:pointer; font-size:18px; opacity:0.8;">&times;</span>
</div>
{{-- 内容滚动区:把 overflow-y:auto 放到内层,避免外层 overflow 创建堆叠上下文论clip全局弹窗 --}}
<div style="padding:16px; overflow-y:auto; flex:1;">
{{-- 修改密码 --}}
<div style="margin-bottom:16px; border:1px solid #e0e0e0; border-radius:6px; padding:12px;">
<div style="font-size:12px; font-weight:bold; color:#336699; margin-bottom:8px;">🔒 修改密码</div>
<div style="display:flex; flex-direction:column; gap:6px;">
<input id="set-old-pwd" type="password" placeholder="当前旧密码"
style="padding:6px 8px; border:1px solid #ccc; border-radius:4px; font-size:12px;">
<input id="set-new-pwd" type="password" placeholder="新密码(至少6位)"
style="padding:6px 8px; border:1px solid #ccc; border-radius:4px; font-size:12px;">
<input id="set-new-pwd2" type="password" placeholder="确认新密码"
style="padding:6px 8px; border:1px solid #ccc; border-radius:4px; font-size:12px;">
<div id="pwd-inline-msg"
style="display:none; border-radius:10px; padding:10px 14px;
text-align:center; margin-top:8px; font-size:12px; font-weight:bold;">
</div>
<button data-settings-save-password
style="padding:6px; background:#336699; color:#fff; border:none; border-radius:4px;
font-size:12px; cursor:pointer;">确定修改密码</button>
</div>
</div>
{{-- 个人资料 --}}
<div style="margin-bottom:16px; border:1px solid #e0e0e0; border-radius:6px; padding:12px;">
<div style="font-size:12px; font-weight:bold; color:#336699; margin-bottom:8px;">👤 个人资料</div>
<div style="display:flex; flex-direction:column; gap:6px;">
<div style="display:flex; align-items:center; gap:8px;">
<label style="font-size:12px; width:50px; text-align:right;">性别:</label>
<select id="set-sex"
style="flex:1; padding:5px; border:1px solid #ccc; border-radius:4px; font-size:12px;">
<option value="1" {{ Auth::user()->sex == 1 ? 'selected' : '' }}></option>
<option value="2" {{ Auth::user()->sex == 2 ? 'selected' : '' }}></option>
<option value="0" {{ Auth::user()->sex == 0 ? 'selected' : '' }}>保密</option>
</select>
</div>
<div style="display:flex; align-items:center; gap:8px;">
<label style="font-size:12px; width:50px; text-align:right;">邮箱:</label>
<input id="set-email" type="email" value="{{ Auth::user()->email ?? '' }}"
placeholder="用来找回密码(必填)"
style="flex:1; padding:5px; border:1px solid #ccc; border-radius:4px; font-size:12px;">
</div>
@if (\App\Models\SysParam::where('alias', 'smtp_enabled')->value('body') === '1')
<div style="display:flex; align-items:center; gap:8px; margin-top:6px;">
<label style="font-size:12px; width:50px; text-align:right;">验证码:</label>
<input id="set-email-code" type="text" placeholder="修改邮箱时必填" maxlength="6"
style="flex:1; padding:5px; border:1px solid #ccc; border-radius:4px; font-size:12px; max-width:100px;">
<button id="btn-send-code" type="button" data-settings-send-email-code
style="padding:5px 10px; border:1px solid #336699; background:#eef5ff; color:#336699; border-radius:4px; font-size:12px; cursor:pointer;">
获取验证码
</button>
</div>
@endif
</div>
</div>
{{-- 密保设置 --}}
<div style="margin-bottom:16px; border:1px solid #e0e0e0; border-radius:6px; padding:12px;">
<div style="font-size:12px; font-weight:bold; color:#336699; margin-bottom:8px;">🛡️ 密码保护</div>
<div style="display:flex; flex-direction:column; gap:6px;">
<input id="set-question" type="text" value="{{ Auth::user()->question ?? '' }}"
placeholder="密保问题(如:我的小学名字?)"
style="padding:6px 8px; border:1px solid #ccc; border-radius:4px; font-size:12px;">
<input id="set-answer" type="text" value="{{ Auth::user()->answer ?? '' }}"
placeholder="密保答案"
style="padding:6px 8px; border:1px solid #ccc; border-radius:4px; font-size:12px;">
</div>
</div>
{{-- 微信绑定 --}}
<div style="margin-bottom:16px; border:1px solid #e0e0e0; border-radius:6px; padding:12px;">
<div style="font-size:12px; font-weight:bold; color:#336699; margin-bottom:8px;">💬 微信绑定</div>
<div style="display:flex; flex-direction:column; gap:6px;" id="wechat-bind-container">
@if (empty(Auth::user()->wxid))
@php
$botConfigBody = \App\Models\SysParam::where('alias', 'wechat_bot_config')->value('body');
$botConfig = $botConfigBody ? json_decode($botConfigBody, true) : [];
$botWxid = $botConfig['kafka']['bot_wxid'] ?? '暂未配置';
$qrcodeImage = $botConfig['api']['qrcode_image'] ?? null;
@endphp
<div style="font-size:12px; color:#666;">
您尚未绑定微信。<br>
@if($qrcodeImage)
扫码添加机器人微信:<br>
<img src="{{ \Illuminate\Support\Facades\Storage::url($qrcodeImage) }}" alt="机器人二维码" style="max-height:100px; display:block; margin: 6px 0; border: 1px solid #ddd; border-radius: 4px;">
@else
请添加机器人微信:<strong style="color:#d97706">{{ $botWxid }}</strong><br>
@endif
并发送以下绑定代码完成绑定:
</div>
<div style="display:flex; align-items:center; gap:8px;">
<input id="wechat-bind-code" type="text" readonly value="点击生成"
style="flex:1; padding:6px 8px; border:1px dashed #336699; background:#f9fafb; border-radius:4px; font-size:13px; font-weight:bold; color:#336699; text-align:center; cursor:text;">
<button type="button" id="btn-copy-bind-code" data-settings-copy-wechat-code
style="display:none; padding:5px 10px; border:1px solid #10b981; background:#ecfdf5; color:#10b981; border-radius:4px; font-size:12px; cursor:pointer; white-space:nowrap;">
复制
</button>
<button type="button" id="btn-generate-bind-code" data-settings-generate-wechat-code
style="padding:5px 10px; border:1px solid #336699; background:#eef5ff; color:#336699; border-radius:4px; font-size:12px; cursor:pointer; white-space:nowrap;">
生成代码
</button>
</div>
<div id="bind-code-tip" style="font-size:11px; color:#888; display:none; text-align:center;">有效时间 5 分钟,绑定成功后请刷新页面。</div>
@else
<div style="font-size:12px; color:#16a34a; font-weight:bold; display:flex; justify-content:space-between; align-items:center;">
<span>已绑定微信,可接收提醒通知。</span>
<button type="button" data-settings-unbind-wechat style="padding:4px 8px; background:#fee2e2; color:#dc2626; border:1px solid #fecaca; border-radius:4px; font-size:11px; cursor:pointer;">解除绑定</button>
</div>
@endif
</div>
</div>
{{-- 内联操作结果提示(仿百家乐已押注卡片风格) --}}
<div id="settings-inline-msg"
style="display:none; border-radius:10px; padding:10px 14px;
text-align:center; margin-bottom:10px; font-size:13px; font-weight:bold;">
</div>
{{-- 保存按钮 --}}
<button data-settings-save-profile
style="width:100%; padding:8px; background:linear-gradient(135deg,#336699,#5a8fc0);
color:#fff; border:none; border-radius:4px; font-size:13px; font-weight:bold; cursor:pointer;">
💾 保存资料设置
</button>
</div>
</div>
</div>
{{-- ═══════════ 好友面板(独立文件)═══════════ --}}
@include('chat.partials.friend-panel')
{{-- ═══════════ 娱乐游戏大厅弹窗(games/ 子目录)═══════════ --}}
@include('chat.partials.games.game-hall')
{{-- 头像选择和个人设置脚本已迁移到 resources/js/chat-room/profile-controls.js --}}
{{-- ═══════════ 商店弹窗 ═══════════ --}}
<style>
/* 商店弹窗遮罩 */
#shop-modal {
display: none;
position: fixed;
inset: 0;
background: rgba(0, 0, 0, .5);
z-index: 9999;
justify-content: center;
align-items: center;
}
/* 弹窗主体 — 与设置弹窗同风格 */
#shop-modal-inner {
background: #fff;
border-radius: 8px;
width: 800px;
max-width: 95vw;
max-height: 84vh;
display: flex;
flex-direction: column;
box-shadow: 0 8px 32px rgba(0, 0, 0, .3);
overflow: hidden;
position: relative;
}
/* 标题栏 — 与设置/头像弹窗一致 */
#shop-modal-header {
background: linear-gradient(135deg, #336699, #5a8fc0);
color: #fff;
padding: 10px 16px;
display: flex;
align-items: center;
gap: 10px;
flex-shrink: 0;
}
#shop-modal-title {
font-size: 14px;
font-weight: bold;
flex: 1;
}
#shop-modal-jjb {
font-size: 12px;
color: #d0e8ff;
display: flex;
align-items: center;
gap: 3px;
background: rgba(0, 0, 0, .2);
padding: 2px 8px;
border-radius: 10px;
}
#shop-modal-jjb strong {
color: #ffe082;
font-size: 13px;
}
#shop-week-badge {
display: none;
font-size: 10px;
background: rgba(255, 255, 255, .2);
padding: 2px 7px;
border-radius: 10px;
color: #fff;
}
#shop-modal-close {
cursor: pointer;
font-size: 18px;
opacity: .8;
transition: opacity .15s;
line-height: 1;
}
#shop-modal-close:hover {
opacity: 1;
}
/* Toast */
#shop-toast {
display: none;
margin: 6px 12px 0;
padding: 5px 10px;
border-radius: 4px;
font-size: 12px;
font-weight: bold;
flex-shrink: 0;
}
/* 商品列表区 */
#shop-items-list {
flex: 1;
overflow-y: auto;
padding: 10px 12px;
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 8px;
align-content: start;
background: #f6faff;
}
/* 装扮列表区 — 与商品列表同风格 */
#shop-decorations-list {
flex: 1;
overflow-y: auto;
padding: 10px 12px;
display: none;
grid-template-columns: repeat(4, 1fr);
gap: 8px;
align-content: start;
background: #f6faff;
}
/* Tab 导航 */
#shop-tabs {
display: flex;
border-bottom: 1px solid #cde;
flex-shrink: 0;
background: #eef4fb;
}
.shop-tab {
flex: 1;
padding: 8px 6px;
background: transparent;
border: none;
color: #6b7280;
font-size: 12px;
cursor: pointer;
border-bottom: 2px solid transparent;
font-weight: bold;
transition: all .2s;
}
.shop-tab.active { color: #336699 !important; border-bottom-color: #336699 !important; }
.shop-tab:hover { color: #5a8fc0; }
/* 分组标题 — 独占一整行 */
.shop-group-header {
grid-column: 1 / -1;
font-size: 11px;
font-weight: bold;
color: #336699;
padding: 6px 4px 4px;
border-bottom: 1px solid #cde;
display: flex;
align-items: baseline;
gap: 6px;
}
.shop-group-header span {
font-size: 10px;
color: #888;
font-weight: normal;
}
/* 商品卡 */
.shop-card {
background: #fff;
border: 1px solid #d0e4f5;
border-radius: 6px;
padding: 10px;
display: flex;
flex-direction: column;
gap: 5px;
transition: border-color .2s, box-shadow .2s;
cursor: default;
}
.shop-card:hover {
border-color: #5a8fc0;
box-shadow: 0 2px 8px rgba(51, 102, 153, .18);
}
.shop-card-top {
display: flex;
align-items: center;
gap: 6px;
}
.shop-card-icon {
font-size: 20px;
flex-shrink: 0;
}
.shop-card-name {
font-size: 12px;
font-weight: bold;
color: #225588;
flex: 1;
line-height: 1.3;
}
.shop-card-desc {
font-size: 10px;
color: #888;
line-height: 1.4;
flex: 1;
}
.shop-validity {
margin-top: 2px;
font-size: 10px;
line-height: 1.4;
color: #6b7280;
font-weight: normal;
}
/* 装扮Tab购买说明 */
.decoration-note {
font-size: 11px;
color: #b45309;
background: #fef3c7;
border: 1px solid #fde68a;
border-radius: 6px;
padding: 6px 10px;
margin-bottom: 10px;
grid-column: 1 / -1;
}
/* 装扮卡片状态行(独立一行,显示在商品名下方) */
.decoration-status-line {
margin-top: 4px;
}
/* 装扮卡片状态标签 */
.decoration-status {
font-size: 9px;
padding: 1px 6px;
border-radius: 8px;
}
.decoration-status.active { background: #065f46; color: #6ee7b7; }
.decoration-expiry { font-size: 10px; color: #9ca3af; margin-top: 2px; }
.shop-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 3px;
background: linear-gradient(135deg, #336699, #5a8fc0);
color: #fff;
border: none;
border-radius: 4px;
padding: 5px 8px;
cursor: pointer;
font-size: 11px;
font-weight: bold;
width: 100%;
margin-top: auto;
transition: opacity .15s;
}
.shop-btn:hover {
opacity: .85;
}
.shop-btn-use {
background: linear-gradient(135deg, #7c3aed, #9f67e8);
}
/* 改名内嵌遮罩 */
#shop-rename-overlay {
display: none;
position: absolute;
inset: 0;
background: rgba(0, 0, 0, .5);
z-index: 10001;
justify-content: center;
align-items: center;
border-radius: 8px;
}
#shop-rename-box {
background: #fff;
border: 1px solid #5a8fc0;
border-radius: 8px;
padding: 16px 14px;
width: 230px;
box-shadow: 0 4px 20px rgba(0, 0, 0, .25);
}
#shop-rename-box h4 {
font-size: 13px;
font-weight: bold;
color: #336699;
margin: 0 0 10px;
}
#rename-input {
width: 100%;
border: 1px solid #aac;
border-radius: 4px;
padding: 6px 8px;
color: #333;
font-size: 12px;
box-sizing: border-box;
margin-bottom: 8px;
outline: none;
}
#rename-input:focus {
border-color: #336699;
}
.rename-btn-row {
display: flex;
gap: 6px;
}
#rename-confirm {
flex: 1;
background: #336699;
color: #fff;
border: none;
border-radius: 4px;
padding: 6px;
cursor: pointer;
font-size: 12px;
font-weight: bold;
}
#rename-cancel {
flex: 1;
background: #eee;
color: #555;
border: 1px solid #ccc;
border-radius: 4px;
padding: 6px;
cursor: pointer;
font-size: 12px;
}
#rename-err {
color: #c00;
font-size: 10px;
margin-top: 5px;
min-height: 14px;
}
/* 送礼对话框 */
#gift-dialog {
display: none;
position: absolute;
inset: 0;
background: rgba(0, 0, 0, .55);
z-index: 10001;
justify-content: center;
align-items: center;
border-radius: 8px;
}
#gift-dialog-box {
background: #fff;
border: 1px solid #5a8fc0;
border-radius: 8px;
padding: 16px 14px;
width: 250px;
box-shadow: 0 4px 20px rgba(0, 0, 0, .25);
}
#gift-dialog-box h4 {
font-size: 12px;
font-weight: bold;
color: #336699;
margin: 0 0 3px;
}
#gift-item-name {
font-size: 11px;
color: #555;
display: block;
border-bottom: 1px dashed #cde;
padding-bottom: 6px;
margin-bottom: 10px;
}
.gift-label {
font-size: 11px;
color: #555;
margin-bottom: 3px;
display: block;
}
.gift-input {
width: 100%;
border: 1px solid #aac;
border-radius: 4px;
padding: 5px 8px;
font-size: 12px;
box-sizing: border-box;
margin-bottom: 8px;
outline: none;
}
.gift-input:focus {
border-color: #336699;
}
.gift-hint {
font-size: 10px;
color: #999;
margin: -4px 0 8px;
display: block;
}
#gift-err {
color: #c00;
font-size: 10px;
margin-top: 4px;
min-height: 14px;
}
</style>
<div id="shop-modal" data-shop-items-url="{{ route('shop.items') }}" data-shop-buy-url="{{ route('shop.buy') }}"
data-shop-rename-url="{{ route('shop.rename') }}">
<div id="shop-modal-inner" style="position:relative;">
{{-- 标题栏 --}}
<div id="shop-modal-header">
<div id="shop-modal-title">🛍 道具商店</div>
<div id="shop-modal-jjb">💰 <strong id="shop-jjb">--</strong> 金币</div>
<span id="shop-week-badge"></span>
<span id="shop-modal-close" data-shop-modal-close></span>
</div>
{{-- Toast --}}
<div id="shop-toast"></div>
{{-- Tab 导航 --}}
<div id="shop-tabs">
<button class="shop-tab active" data-shop-tab="items">特效道具</button>
<button class="shop-tab" data-shop-tab="decorations">个人装扮</button>
</div>
{{-- 商品网格 --}}
<div id="shop-items-list">
<div style="grid-column:1/-1; text-align:center; color:#6366f1; padding:30px 0; font-size:13px;">加载中…</div>
</div>
{{-- 装扮网格 --}}
<div id="shop-decorations-list">
<div style="grid-column:1/-1; text-align:center; color:#6366f1; padding:30px 0; font-size:13px;">加载中…</div>
</div>
{{-- 改名内嵌遮罩 --}}
<div id="shop-rename-overlay">
<div id="shop-rename-box">
<h4>🎭 使用改名卡</h4>
<input id="rename-input" type="text" maxlength="10" placeholder="输入新昵称(1-10字)">
<div class="rename-btn-row">
<button id="rename-confirm" data-shop-rename-confirm>确认改名</button>
<button id="rename-cancel" data-shop-rename-cancel>取消</button>
</div>
<div id="rename-err"></div>
</div>
</div>
{{-- 送礼对话框:填写接收人 + 赠言 --}}
<div id="gift-dialog">
<div id="gift-dialog-box">
<h4>🎁 赠出单次特效卡</h4>
<span id="gift-item-name"></span>
<label class="gift-label">送给谁?</label>
<input id="gift-recipient" class="gift-input" type="text" maxlength="20"
placeholder="用户名(留空 = 全场可见)">
<span class="gift-hint">💡 留空表示所有人;购买者必定可见</span>
<label class="gift-label">说一句话(公屏发送)</label>
<input id="gift-message" class="gift-input" type="text" maxlength="50" placeholder="可不填,百字以内">
<div id="gift-err"></div>
<div class="rename-btn-row" style="margin-top:8px;">
<button data-shop-gift-confirm
style="flex:1;background:#336699;color:#fff;border:none;border-radius:4px;padding:7px;cursor:pointer;font-size:12px;font-weight:bold;">确认赠出</button>
<button data-shop-gift-cancel
style="flex:1;background:#eee;color:#555;border:1px solid #ccc;border-radius:4px;padding:7px;cursor:pointer;font-size:12px;">取消</button>
</div>
</div>
</div>
</div>
</div>
{{-- 商店弹窗业务脚本已迁移到 resources/js/chat-room/shop-controls.js --}}
{{-- ═══════════ 会员中心弹窗 ═══════════ --}}
<style>
#vip-modal { display:none; position:fixed; inset:0; background:rgba(0,0,0,.6); z-index:9999; justify-content:center; align-items:center; }
#vip-modal-inner { width:760px; max-width:96vw; max-height:90vh; background:#fff; border-radius:12px; overflow:hidden; display:flex; flex-direction:column; box-shadow:0 12px 40px rgba(0,0,0,.4); font-family:'Microsoft YaHei',SimSun,sans-serif; }
#vip-modal-header { background:linear-gradient(135deg,#1e293b,#334155); color:#fff; padding:12px 18px; display:flex; align-items:center; flex-shrink:0; }
.vip-tab-btn { background:rgba(255,255,255,.1); border:none; color:#cbd5e1; border-radius:8px; padding:6px 16px; font-size:13px; cursor:pointer; font-weight:bold; transition:all .2s; }
.vip-tab-btn.active { background:#f59e0b; color:#fff; box-shadow:0 2px 4px rgba(0,0,0,.1); }
.vip-view-pane { display:none; flex-direction:column; flex:1; overflow-y:auto; background:#f8fafc; padding:20px; }
.vip-view-pane.active { display:flex; }
/* 会员卡片 */
.vip-level-card { background:#fff; border:1px solid #e2e8f0; border-radius:12px; padding:18px; display:flex; flex-direction:column; gap:10px; transition:all .2s; position:relative; overflow:hidden; }
.vip-level-card.current { border-color:#f59e0b; background:#fffdf5; box-shadow:0 0 0 1px #f59e0b; }
.vip-level-badge { position:absolute; top:10px; right:10px; background:#f59e0b; color:#fff; font-size:10px; font-weight:bold; padding:2px 8px; border-radius:10px; }
/* 设置表单 */
.vip-setting-group { margin-bottom:15px; }
.vip-setting-label { display:block; font-size:13px; font-weight:bold; color:#475569; margin-bottom:6px; }
.vip-setting-input { width:100%; border:1px solid #cbd5e1; border-radius:8px; padding:10px 12px; font-size:13px; outline:none; transition:border-color .2s; background:#fff; }
.vip-setting-input:focus { border-color:#f59e0b; }
.vip-setting-textarea { min-height:80px; resize:vertical; }
.vip-btn-save { background:#1e293b; color:#fff; border:none; border-radius:8px; padding:10px 20px; font-size:13px; font-weight:bold; cursor:pointer; transition:opacity .2s; }
.vip-btn-save:hover { opacity:.9; }
/* 会员特权图标 */
.vip-feature-item { display:flex; align-items:center; gap:8px; font-size:12px; color:#64748b; }
.vip-feature-icon { color:#10b981; font-weight:bold; }
.vip-modal-close { cursor:pointer; font-size:24px; opacity:.7; transition:opacity .15s; }
.vip-modal-close:hover { opacity:1; }
</style>
<div id="vip-modal">
<div id="vip-modal-inner">
<div id="vip-modal-header">
<div style="font-size:16px; font-weight:bold; margin-right:24px;">👑 会员中心</div>
<div style="display:flex; gap:10px; flex:1;">
<button id="vip-tabbtn-center" class="vip-tab-btn active" data-vip-tab="center">会员中心</button>
<button id="vip-tabbtn-settings" class="vip-tab-btn" data-vip-tab="settings" style="display:none;">会员相关设置</button>
<button id="vip-tabbtn-logs" class="vip-tab-btn" data-vip-tab="logs">购买记录</button>
</div>
<span class="vip-modal-close" data-vip-modal-close>&times;</span>
</div>
{{-- 会员中心面板 --}}
<div id="vip-view-center" class="vip-view-pane active">
<div id="vip-status-bar" style="background:#fff; border:1px solid #fef3c7; border-radius:12px; padding:16px; margin-bottom:20px; display:flex; justify-content:space-between; align-items:center;">
<div>
<div style="font-size:12px; font-weight:bold; color:#b45309;">我的会员状态</div>
<div id="vip-current-name" style="font-size:18px; font-weight:900; color:#1e293b; margin-top:4px;">加载中...</div>
<div id="vip-expire-time" style="font-size:12px; color:#64748b; margin-top:4px;"></div>
</div>
<div style="text-align:right;">
<div style="font-size:12px; font-weight:bold; color:#059669;">累计已支付</div>
<div id="vip-total-amount" style="font-size:18px; font-weight:900; color:#064e3b; margin-top:4px;">¥0.00</div>
</div>
</div>
<div style="font-size:14px; font-weight:bold; color:#1e293b; margin-bottom:12px;">会员等级列表</div>
<div id="vip-levels-grid" style="display:grid; grid-template-columns:repeat(auto-fill, minmax(220px, 1fr)); gap:15px;">
<!-- 动态渲染会员等级 -->
</div>
</div>
{{-- 会员相关设置面板 --}}
<div id="vip-view-settings" class="vip-view-pane">
<div style="display:grid; grid-template-columns:1.2fr 0.8fr; gap:20px;">
<div>
<div style="background:#fff; border:1px solid #e2e8f0; border-radius:12px; padding:18px; margin-bottom:15px;">
<div style="display:flex; align-items:center; gap:10px; margin-bottom:15px;">
<div id="vip-theme-icon" style="width:40px; height:40px; background:#1e293b; border-radius:10px; display:flex; align-items:center; justify-content:center; font-size:20px; color:#fff;"></div>
<div>
<div style="font-size:12px; color:#64748b;">当前主题预览</div>
<div id="vip-theme-name" style="font-size:15px; font-weight:bold; color:#1e293b;">普通用户</div>
</div>
</div>
<div style="display:grid; grid-template-columns:1fr 1fr; gap:12px;">
<div style="background:#f8fafc; border:1px solid #e2e8f0; border-radius:10px; padding:12px;">
<div style="font-size:10px; font-weight:bold; color:#94a3b8; text-transform:uppercase;">入场特效</div>
<div id="vip-join-effect" style="font-size:14px; font-weight:bold; color:#1e293b; margin-top:4px;"></div>
<div id="vip-join-banner" style="font-size:11px; color:#64748b; margin-top:4px;"></div>
</div>
<div style="background:#f8fafc; border:1px solid #e2e8f0; border-radius:10px; padding:12px;">
<div style="font-size:10px; font-weight:bold; color:#94a3b8; text-transform:uppercase;">离场特效</div>
<div id="vip-leave-effect" style="font-size:14px; font-weight:bold; color:#1e293b; margin-top:4px;"></div>
<div id="vip-leave-banner" style="font-size:11px; color:#64748b; margin-top:4px;"></div>
</div>
</div>
</div>
<div style="background:#fffdf5; border:1px solid #fef3c7; border-radius:12px; padding:18px;">
<div style="font-size:13px; font-weight:bold; color:#b45309; margin-bottom:12px;">等级默认语句</div>
<div style="display:grid; gap:10px;">
<div style="background:#fff; border:1px solid #fef3c7; border-radius:10px; padding:12px;">
<div style="font-size:11px; font-weight:bold; color:#f59e0b;">默认欢迎语</div>
<div id="vip-default-join" style="font-size:12px; color:#475569; margin-top:6px; line-height:1.6;"></div>
</div>
<div style="background:#fff; border:1px solid #fef3c7; border-radius:10px; padding:12px;">
<div style="font-size:11px; font-weight:bold; color:#f59e0b;">默认离开语</div>
<div id="vip-default-leave" style="font-size:12px; color:#475569; margin-top:6px; line-height:1.6;"></div>
</div>
</div>
</div>
</div>
<div style="background:#fff; border:1px solid #e2e8f0; border-radius:12px; padding:18px;">
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:15px;">
<div style="font-size:15px; font-weight:bold; color:#1e293b;">我的个性化设置</div>
<span id="vip-customize-badge" style="font-size:10px; font-weight:bold; padding:2px 8px; border-radius:10px;"></span>
</div>
<div id="vip-customize-form" style="display:none;">
<div class="vip-setting-group">
<label class="vip-setting-label">入场特效选择</label>
<select id="vip-custom-join-effect" class="vip-setting-input">
<!-- 动态渲染 -->
</select>
</div>
<div class="vip-setting-group">
<label class="vip-setting-label">离场特效选择</label>
<select id="vip-custom-leave-effect" class="vip-setting-input">
<!-- 动态渲染 -->
</select>
</div>
<div class="vip-setting-group">
<label class="vip-setting-label">我的欢迎语</label>
<textarea id="vip-custom-join" class="vip-setting-input vip-setting-textarea" placeholder="例:{username} 闪耀登场..."></textarea>
<p style="font-size:10px; color:#94a3b8; margin-top:6px;">支持使用 {username} 占位符</p>
</div>
<div class="vip-setting-group">
<label class="vip-setting-label">我的离开语</label>
<textarea id="vip-custom-leave" class="vip-setting-input vip-setting-textarea" placeholder="例:{username} 优雅离场..."></textarea>
</div>
<button data-vip-save-presence class="vip-btn-save" style="width:100%;">保存我的专属设置</button>
</div>
<div id="vip-customize-notice" style="display:none; padding:15px; background:#f8fafc; border:1px dashed #cbd5e1; border-radius:10px; font-size:12px; color:#64748b; line-height:1.8;">
<!-- 动态提示 -->
</div>
</div>
</div>
</div>
{{-- 购买记录面板 --}}
<div id="vip-view-logs" class="vip-view-pane">
<div style="overflow-x:auto;">
<table style="width:100%; border-collapse:collapse; font-size:12px;">
<thead>
<tr style="background:#f1f5f9; color:#475569; text-align:left;">
<th style="padding:10px; border-bottom:1px solid #e2e8f0;">订单号</th>
<th style="padding:10px; border-bottom:1px solid #e2e8f0;">等级</th>
<th style="padding:10px; border-bottom:1px solid #e2e8f0;">金额</th>
<th style="padding:10px; border-bottom:1px solid #e2e8f0;">状态</th>
<th style="padding:10px; border-bottom:1px solid #e2e8f0;">开通时间</th>
</tr>
</thead>
<tbody id="vip-logs-body">
<!-- 动态渲染购买记录 -->
</tbody>
</table>
</div>
</div>
</div>
</div>
{{-- VIP 中心业务脚本已迁移到 resources/js/chat-room/vip-controls.js --}}
{{-- ═══════════ 婚姻状态弹窗 ═══════════ --}}
<style>
/* 婚姻弹窗选项卡按钮 */
.marriage-tab-btn {
background: rgba(255, 255, 255, .15);
border: none;
color: #fce7f3;
border-radius: 12px;
padding: 3px 12px;
font-size: 11px;
cursor: pointer;
font-weight: bold;
transition: all .2s;
}
.marriage-tab-btn.active {
background: #fff;
color: #be185d;
box-shadow: 0 2px 4px rgba(0, 0, 0, .1);
}
/* 已婚列表项样式 */
.married-list-item {
background: #fff;
border: 1px solid #fce7f3;
border-radius: 8px;
padding: 10px;
margin-bottom: 8px;
display: flex;
flex-direction: column;
gap: 8px;
transition: all .2s;
}
.married-list-item:hover {
border-color: #f43f5e;
box-shadow: 0 2px 8px rgba(190, 24, 93, .1);
}
.married-couple-info {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
}
.married-user-box {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
width: 80px;
}
.married-user-avatar {
width: 36px;
height: 36px;
border-radius: 50%;
border: 2px solid #fff;
box-shadow: 0 0 0 1px #fce7f3;
object-fit: cover;
}
.married-user-name {
font-size: 11px;
font-weight: bold;
color: #333;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
}
.married-heart {
font-size: 20px;
color: #f43f5e;
animation: heartBeat 1.5s ease-in-out infinite;
}
@keyframes heartBeat {
0% { transform: scale(1); }
15% { transform: scale(1.2); }
30% { transform: scale(1); }
45% { transform: scale(1.1); }
100% { transform: scale(1); }
}
.married-meta-info {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 10px;
color: #999;
padding-top: 6px;
border-top: 1px dashed #fce7f3;
}
.married-intimacy {
color: #be185d;
font-weight: bold;
}
</style>
<div id="marriage-status-modal"
style="display:none; position:fixed; inset:0; background:rgba(0,0,0,.5);
z-index:9999; justify-content:center; align-items:center;">
<div
style="background:#fff; border-radius:10px; width:380px; max-width:94vw;
box-shadow:0 12px 40px rgba(0,0,0,.3); overflow:hidden;
animation:gdSlideIn .18s ease; display:flex; flex-direction:column; max-height: 85vh;">
{{-- 标题栏 --}}
<div
style="background:linear-gradient(135deg,#be185d,#f43f5e,#ec4899);
color:#fff; padding:10px 16px;
display:flex; align-items:center; justify-content:space-between;">
<div style="display:flex; align-items:center; gap:12px;">
<span style="font-size:14px; font-weight:bold;">💍 婚姻系统</span>
<div style="display:flex; gap:6px;">
<button id="marriage-tabbtn-mine" class="marriage-tab-btn active" data-marriage-tab="mine">我的婚姻</button>
<button id="marriage-tabbtn-list" class="marriage-tab-btn" data-marriage-tab="list">已婚列表</button>
</div>
</div>
<span data-marriage-modal-close
style="cursor:pointer; font-size:18px; opacity:.8; line-height:1;"></span>
</div>
{{-- 我的婚姻 面板 --}}
<div id="marriage-view-mine" style="display:flex; flex-direction:column; flex:1; overflow:hidden;">
<div id="marriage-status-body" style="padding:16px; min-height:120px;">
<div style="text-align:center; color:#aaa; padding:30px 0; font-size:12px;">加载中…</div>
</div>
<div id="marriage-status-footer" style="padding:0 16px 16px; display:flex; gap:8px;"></div>
</div>
{{-- 已婚列表 面板 --}}
<div id="marriage-view-list" style="display:none; flex-direction:column; flex:1; overflow:hidden; background: #fffafb;">
<div id="married-list-container" style="padding:12px; flex:1; overflow-y:auto;">
<div style="text-align:center; color:#aaa; padding:30px 0; font-size:12px;">加载中…</div>
</div>
<div id="married-list-pagination" style="padding:10px 16px; border-top:1px solid #fce7f3; display:flex; justify-content:space-between; align-items:center; font-size:11px;">
<button data-marriage-page-delta="-1" id="married-prev-btn" style="border:1px solid #fbcfe8; background:#fff; color:#be185d; padding:2px 8px; border-radius:4px; cursor:pointer;">上一页</button>
<span id="married-page-info" style="color:#be185d; font-weight:bold;">1 / 1</span>
<button data-marriage-page-delta="1" id="married-next-btn" style="border:1px solid #fbcfe8; background:#fff; color:#be185d; padding:2px 8px; border-radius:4px; cursor:pointer;">下一页</button>
</div>
</div>
</div>
</div>
{{-- 婚姻状态弹窗业务脚本已迁移到 resources/js/chat-room/marriage-status.js --}}
{{-- ═══════════ 银行弹窗 ═══════════ --}}
<style>
/* 银行弹窗遮罩 */
#bank-modal { display:none; position:fixed; inset:0; background:rgba(0,0,0,.55); z-index:9999; justify-content:center; align-items:center; }
/* 弹窗主体 */
#bank-modal-inner { width:520px; max-width:96vw; max-height:88vh; background:#fff; border-radius:8px; overflow:hidden; display:flex; flex-direction:column; box-shadow:0 8px 32px rgba(0,0,0,.3); font-family:'Microsoft YaHei',SimSun,sans-serif; }
/* 头部 */
#bank-modal-header { background:linear-gradient(135deg,#336699,#5a8fc0); color:#fff; padding:10px 16px; display:flex; align-items:center; flex-shrink:0; }
/* Tabs */
.bank-tab-btn { background:rgba(255,255,255,.15); border:none; color:#d0e8ff; border-radius:15px; padding:4px 14px; font-size:12px; cursor:pointer; font-weight:bold; transition:all .2s; }
.bank-tab-btn.active { background:#fff; color:#336699; box-shadow:0 2px 4px rgba(0,0,0,.1); }
/* 包含容器 */
.bank-view-pane { display:flex; flex-direction:column; flex:1; overflow:hidden; background:#f6faff; }
/* 余额卡片 */
.bank-balance-card { flex:1; background:#fff; border:1px solid #d0e4f5; border-radius:6px; padding:12px 14px; text-align:center; transition:box-shadow .2s; }
.bank-balance-card:hover { box-shadow:0 2px 8px rgba(51,102,153,.1); }
.bank-bcard-title { font-size:12px; margin-bottom:6px; }
.bank-bcard-val { font-size:20px; font-weight:bold; }
/* 操作区 */
.bank-op-row { display:flex; gap:10px; align-items:center; margin-bottom:10px; }
.bank-op-label { font-size:12px; font-weight:bold; width:44px; }
.bank-op-input { flex:1; height:34px; padding:0 10px; border:1px solid #b0d0ee; border-radius:4px; font-size:13px; outline:none; transition:border-color .2s; }
.bank-op-input:focus { border-color:#336699; }
.bank-op-btn { height:34px; padding:0 20px; color:#fff; border:none; border-radius:4px; cursor:pointer; font-size:13px; font-weight:bold; transition:opacity .2s; }
.bank-op-btn:hover { opacity:.85; }
.bank-op-btn:disabled { opacity:.5; cursor:not-allowed; }
/* 流水列表 */
.bank-log-item { display:flex; justify-content:space-between; align-items:center; padding:8px 0; border-bottom:1px dashed #d0e4f5; font-size:12px; }
.bank-log-item:last-child { border-bottom:none; }
.bank-log-deposit { color:#16a34a; font-weight:bold; }
.bank-log-withdraw { color:#0891b2; font-weight:bold; }
/* 排行榜单项 */
.bank-rank-item { background:#fff; border:1px solid #d0e4f5; border-radius:6px; padding:10px 14px; display:flex; align-items:center; gap:12px; font-size:13px; margin-bottom:8px; transition:border-color .2s; }
.bank-rank-item:hover { border-color:#336699; box-shadow:0 2px 8px rgba(51,102,153,.1); }
.bank-rank-num { font-size:18px; font-weight:bold; font-style:italic; width:30px; text-align:center; color:#9db3d4; }
.bank-rank-top1 { color:#fbbf24; }
.bank-rank-top2 { color:#9ca3af; }
.bank-rank-top3 { color:#b45309; }
.bank-rank-val { margin-left:auto; font-weight:bold; color:#0891b2; display:flex; align-items:center; gap:4px; }
.bank-modal-close { cursor:pointer; font-size:20px; opacity:.8; transition:opacity .15s; }
.bank-modal-close:hover { opacity:1; }
</style>
<div id="bank-modal">
<div id="bank-modal-inner">
{{-- 标题栏 --}}
<div id="bank-modal-header">
<div style="font-size:15px; font-weight:bold; margin-right:20px;">🏦 金币银行</div>
{{-- Tabs --}}
<div style="display:flex; gap:10px; flex:1;">
<button id="bank-tabbtn-account" class="bank-tab-btn active" data-bank-tab="account">我的账户</button>
<button id="bank-tabbtn-ranking" class="bank-tab-btn" data-bank-tab="ranking">存款排行</button>
</div>
<span class="bank-modal-close" data-bank-modal-close>&times;</span>
</div>
{{-- 我的账户 面板 --}}
<div id="bank-view-account" class="bank-view-pane" style="display:flex;">
{{-- 余额展示 --}}
<div style="display:flex; gap:12px; padding:14px 16px; border-bottom:1px solid #d0e4f5; background:#fff;">
<div class="bank-balance-card" style="border-left:4px solid #3b82f6;">
<div class="bank-bcard-title" style="color:#3b82f6;">💰 流通金币</div>
<div class="bank-bcard-val" style="color:#1d4ed8;" id="bank-jjb-display"></div>
</div>
<div class="bank-balance-card" style="border-left:4px solid #0891b2;">
<div class="bank-bcard-title" style="color:#0891b2;">🏦 银行存款</div>
<div class="bank-bcard-val" style="color:#164e63;" id="bank-bank-display"></div>
</div>
</div>
{{-- 操作区 --}}
<div style="padding:14px 16px; border-bottom:1px solid #d0e4f5; background:#fff;">
<div class="bank-op-row">
<span class="bank-op-label" style="color:#3b82f6;"> </span>
<input type="number" id="bank-deposit-input" class="bank-op-input" min="1" placeholder="输入你想存入银行的金币数量...">
<button id="bank-deposit-btn" class="bank-op-btn" style="background:linear-gradient(135deg,#3b82f6,#60a5fa);" data-bank-action="deposit">确认存入</button>
</div>
<div class="bank-op-row" style="margin-bottom:0;">
<span class="bank-op-label" style="color:#0891b2;"> </span>
<input type="number" id="bank-withdraw-input" class="bank-op-input" min="1" placeholder="输入你想从银行取回的金币数量...">
<button id="bank-withdraw-btn" class="bank-op-btn" style="background:linear-gradient(135deg,#0891b2,#22d3ee);" data-bank-action="withdraw">确认取出</button>
</div>
<div id="bank-op-msg" style="display:none; text-align:center; font-size:12px; font-weight:bold; padding:8px 10px; border-radius:6px; margin-top:12px;"></div>
</div>
{{-- 流水记录 --}}
<div style="padding:8px 16px; font-size:12px; font-weight:bold; color:#336699; background:#fff; border-bottom:1px solid #e0ecf8;">
📝 最近资金流水
</div>
<div id="bank-logs-list" style="flex:1; overflow-y:auto; padding:10px 16px;">
<div style="text-align:center; color:#9db3d4; font-size:12px; padding:30px 0;">加载中...</div>
</div>
</div>
{{-- 存款排行 面板 --}}
<div id="bank-view-ranking" class="bank-view-pane" style="display:none;">
<div style="padding:10px 16px; border-bottom:1px solid #d0e4f5; display:flex; justify-content:space-between; align-items:center; background:#fff;">
<div style="font-size:13px; color:#336699; font-weight:bold;">🏆 全站存款排行榜</div>
<button data-bank-rank-sort id="bank-rank-sort-btn" style="background:#f0f6ff; border:1px solid #b0d0ee; color:#336699; padding:4px 12px; border-radius:15px; font-size:12px; cursor:pointer; font-weight:bold; transition:background .2s;">
降序
</button>
</div>
<div id="bank-ranking-list" style="flex:1; overflow-y:auto; padding:12px 16px;">
<div style="text-align:center; color:#9db3d4; font-size:12px; padding:30px 0;">加载中...</div>
</div>
{{-- 分页控件 --}}
<div style="padding:10px 16px; border-top:1px solid #d0e4f5; background:#fff; display:flex; justify-content:space-between; align-items:center;">
<button class="bank-tab-btn" id="bank-rank-prev" data-bank-rank-page-delta="-1" style="color:#336699; border:1px solid #b0d0ee; background:#fff; font-weight:normal;">上一页</button>
<div id="bank-rank-page-info" style="font-size:12px; color:#666; font-weight:bold;">1 / 1</div>
<button class="bank-tab-btn" id="bank-rank-next" data-bank-rank-page-delta="1" style="color:#336699; border:1px solid #b0d0ee; background:#fff; font-weight:normal;">下一页</button>
</div>
</div>
</div>
</div>