新增:聊天室留言板模态弹窗(仿商店样式)
点击工具栏「留言」按钮弹出留言板弹窗,不再跳转新页面。 新建文件: - guestbook-modal.blade.php — 蓝白渐变标题栏、三Tab切换、留言卡片列表、内嵌写留言表单 - guestbook.js — 完整的AJAX加载/提交/删除逻辑,绑定所有事件 修改文件: - toolbar.blade.php — 留言按钮 data-toolbar-url → data-toolbar-action - toolbar.js — 添加 guestbook 动作 - chat-room.js — 静态导入 guestbook 模块 - frame.blade.php — 引入留言弹窗 - routes/web.php — 新增 guestbook.data JSON 路由 - GuestbookController.php — 新增 data() 方法
This commit is contained in:
@@ -223,6 +223,8 @@
|
||||
{{-- 节日福利弹窗 --}}
|
||||
@include('chat.partials.holiday-modal')
|
||||
@include('chat.partials.daily-sign-in-modal')
|
||||
{{-- 留言板弹窗 --}}
|
||||
@include('chat.partials.guestbook-modal')
|
||||
|
||||
{{-- ═══════════ 游戏面板(partials/games/ 子目录,各自独立,包含 CSS + HTML + JS) ═══════════ --}}
|
||||
{{-- deferChatGameBootstrap 已迁移到 resources/js/chat-room/game-bootstrap.js --}}
|
||||
|
||||
@@ -0,0 +1,438 @@
|
||||
{{--
|
||||
文件功能:星光留言板模态弹窗(仿商店弹窗样式)
|
||||
供聊天室工具栏"留言"按钮使用,替代跳转留言板页面。
|
||||
|
||||
依赖 CSS:与商店弹窗一致的蓝白风格
|
||||
依赖 JS:resources/js/chat-room/guestbook.js
|
||||
--}}
|
||||
|
||||
<style>
|
||||
/* 留言板弹窗遮罩 */
|
||||
#guestbook-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, .5);
|
||||
z-index: 9999;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 弹窗主体 */
|
||||
#guestbook-modal-inner {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
width: 720px;
|
||||
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;
|
||||
}
|
||||
|
||||
/* 标题栏 */
|
||||
#guestbook-modal-header {
|
||||
background: linear-gradient(135deg, #336699, #5a8fc0);
|
||||
color: #fff;
|
||||
padding: 10px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#guestbook-modal-title {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
#guestbook-modal-close {
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
opacity: .8;
|
||||
transition: opacity .15s;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
#guestbook-modal-close:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Toast */
|
||||
#guestbook-toast {
|
||||
display: none;
|
||||
margin: 6px 12px 0;
|
||||
padding: 5px 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Tab 导航 */
|
||||
#guestbook-tabs {
|
||||
display: flex;
|
||||
border-bottom: 1px solid #cde;
|
||||
flex-shrink: 0;
|
||||
background: #eef4fb;
|
||||
}
|
||||
.guestbook-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;
|
||||
}
|
||||
.guestbook-tab.active { color: #336699 !important; border-bottom-color: #336699 !important; }
|
||||
.guestbook-tab:hover { color: #5a8fc0; }
|
||||
|
||||
/* 留言列表容器 */
|
||||
#guestbook-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 10px 12px;
|
||||
background: #f6faff;
|
||||
}
|
||||
|
||||
/* 留言卡片 */
|
||||
.gb-card {
|
||||
background: #fff;
|
||||
border: 1px solid #d0e4f5;
|
||||
border-radius: 6px;
|
||||
padding: 10px 12px;
|
||||
margin-bottom: 8px;
|
||||
transition: border-color .2s, box-shadow .2s;
|
||||
}
|
||||
.gb-card:hover {
|
||||
border-color: #5a8fc0;
|
||||
box-shadow: 0 2px 8px rgba(51, 102, 153, .18);
|
||||
}
|
||||
.gb-card.gb-secret {
|
||||
border-color: #f9c7d3;
|
||||
background: #fff5f7;
|
||||
}
|
||||
.gb-card.gb-secret:hover {
|
||||
border-color: #e91e63;
|
||||
box-shadow: 0 2px 8px rgba(233, 30, 99, .12);
|
||||
}
|
||||
|
||||
.gb-card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 6px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.gb-card-author {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
.gb-avatar {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
background: #dbeafe;
|
||||
color: #336699;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.gb-avatar.secret {
|
||||
background: #fce4ec;
|
||||
color: #c62828;
|
||||
}
|
||||
.gb-who {
|
||||
font-weight: bold;
|
||||
color: #225588;
|
||||
}
|
||||
.gb-arrow {
|
||||
color: #9ca3af;
|
||||
font-size: 11px;
|
||||
}
|
||||
.gb-towho {
|
||||
font-weight: 600;
|
||||
color: #336699;
|
||||
}
|
||||
.gb-towho.public {
|
||||
color: #9ca3af;
|
||||
font-style: italic;
|
||||
}
|
||||
.gb-secret-badge {
|
||||
background: #fce4ec;
|
||||
color: #c62828;
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
padding: 1px 6px;
|
||||
border-radius: 8px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
.gb-time {
|
||||
color: #9ca3af;
|
||||
font-size: 11px;
|
||||
}
|
||||
.gb-body {
|
||||
font-size: 13px;
|
||||
color: #374151;
|
||||
line-height: 1.6;
|
||||
word-break: break-word;
|
||||
padding: 2px 0 4px;
|
||||
}
|
||||
.gb-card-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.gb-btn {
|
||||
font-size: 11px;
|
||||
padding: 3px 10px;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
transition: opacity .15s;
|
||||
}
|
||||
.gb-btn:hover { opacity: .8; }
|
||||
.gb-btn-reply {
|
||||
background: #eef4fb;
|
||||
color: #336699;
|
||||
border: 1px solid #cde;
|
||||
}
|
||||
.gb-btn-reply:hover { background: #dbeafe; }
|
||||
.gb-btn-delete {
|
||||
background: #fee2e2;
|
||||
color: #dc2626;
|
||||
border: 1px solid #fecaca;
|
||||
}
|
||||
.gb-btn-delete:hover { background: #fecaca; }
|
||||
|
||||
/* 写留言按钮 */
|
||||
#guestbook-write-btn-wrap {
|
||||
flex-shrink: 0;
|
||||
padding: 8px 12px;
|
||||
background: #eef4fb;
|
||||
border-top: 1px solid #cde;
|
||||
text-align: center;
|
||||
}
|
||||
#guestbook-write-btn {
|
||||
background: linear-gradient(135deg, #336699, #5a8fc0);
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 7px 20px;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: opacity .15s;
|
||||
width: 100%;
|
||||
}
|
||||
#guestbook-write-btn:hover { opacity: .85; }
|
||||
|
||||
/* 写留言表单(内嵌) */
|
||||
#guestbook-write-form {
|
||||
display: none;
|
||||
flex-shrink: 0;
|
||||
padding: 10px 12px;
|
||||
background: #fff;
|
||||
border-top: 1px solid #cde;
|
||||
}
|
||||
#guestbook-write-form.active { display: block; }
|
||||
|
||||
.gb-form-row {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.gb-form-row label {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
color: #336699;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.gb-form-row select,
|
||||
.gb-form-row textarea {
|
||||
width: 100%;
|
||||
padding: 6px 8px;
|
||||
border: 1px solid #cde;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
outline: none;
|
||||
transition: border-color .2s;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.gb-form-row select:focus,
|
||||
.gb-form-row textarea:focus {
|
||||
border-color: #336699;
|
||||
}
|
||||
.gb-form-row textarea {
|
||||
resize: vertical;
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
.gb-form-checkbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 12px;
|
||||
color: #555;
|
||||
}
|
||||
.gb-form-checkbox input[type="checkbox"] {
|
||||
accent-color: #336699;
|
||||
}
|
||||
|
||||
.gb-form-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.gb-form-actions button {
|
||||
padding: 5px 14px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
transition: opacity .15s;
|
||||
}
|
||||
.gb-form-actions button:hover { opacity: .85; }
|
||||
.gb-form-submit {
|
||||
background: linear-gradient(135deg, #336699, #5a8fc0);
|
||||
color: #fff;
|
||||
}
|
||||
.gb-form-cancel {
|
||||
background: #e5e7eb;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.gb-empty {
|
||||
text-align: center;
|
||||
color: #9ca3af;
|
||||
padding: 40px 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
.gb-empty-icon {
|
||||
font-size: 36px;
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
/* 加载中 */
|
||||
.gb-loading {
|
||||
text-align: center;
|
||||
color: #6366f1;
|
||||
padding: 30px 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* 分页 */
|
||||
#guestbook-pager {
|
||||
flex-shrink: 0;
|
||||
padding: 8px 12px;
|
||||
background: #eef4fb;
|
||||
border-top: 1px solid #cde;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
#guestbook-pager button {
|
||||
padding: 3px 10px;
|
||||
border: 1px solid #cde;
|
||||
border-radius: 4px;
|
||||
background: #fff;
|
||||
color: #336699;
|
||||
cursor: pointer;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
transition: all .15s;
|
||||
}
|
||||
#guestbook-pager button:hover {
|
||||
background: #dbeafe;
|
||||
}
|
||||
#guestbook-pager button:disabled {
|
||||
opacity: .4;
|
||||
cursor: default;
|
||||
}
|
||||
#guestbook-pager span {
|
||||
color: #6b7280;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="guestbook-modal"
|
||||
data-guestbook-data-url="{{ route('guestbook.data') }}"
|
||||
data-guestbook-store-url="{{ route('guestbook.store') }}"
|
||||
data-guestbook-destroy-url-template="{{ route('guestbook.destroy', '__ID__') }}">
|
||||
<div id="guestbook-modal-inner">
|
||||
{{-- 标题栏 --}}
|
||||
<div id="guestbook-modal-header">
|
||||
<div id="guestbook-modal-title">✉️ 星光留言板</div>
|
||||
<span id="guestbook-modal-close" data-guestbook-modal-close>✕</span>
|
||||
</div>
|
||||
|
||||
{{-- Toast --}}
|
||||
<div id="guestbook-toast"></div>
|
||||
|
||||
{{-- Tab 导航 --}}
|
||||
<div id="guestbook-tabs">
|
||||
<button class="guestbook-tab active" data-guestbook-tab="public">🌍 公共留言墙</button>
|
||||
<button class="guestbook-tab" data-guestbook-tab="inbox">📥 我收件的</button>
|
||||
<button class="guestbook-tab" data-guestbook-tab="outbox">📤 我发出的</button>
|
||||
</div>
|
||||
|
||||
{{-- 留言列表 --}}
|
||||
<div id="guestbook-list">
|
||||
<div class="gb-loading">加载中…</div>
|
||||
</div>
|
||||
|
||||
{{-- 写留言表单(内嵌) --}}
|
||||
<div id="guestbook-write-form">
|
||||
<form id="guestbook-form" method="POST">
|
||||
@csrf
|
||||
<div class="gb-form-row">
|
||||
<label>📬 收件人 <span style="font-weight:normal;color:#9ca3af;">(留空则为公共留言)</span></label>
|
||||
<select name="towho" id="gb-towho">
|
||||
<option value="">🌍 公共留言(所有人可见)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="gb-form-row">
|
||||
<label class="gb-form-checkbox">
|
||||
<input type="checkbox" name="secret" value="1"> 🔒 悄悄话(仅双方可见)
|
||||
</label>
|
||||
</div>
|
||||
<div class="gb-form-row">
|
||||
<label>📝 留言内容 <span style="color:#dc2626;">*</span></label>
|
||||
<textarea name="text_body" id="gb-text-body" rows="3" required placeholder="相逢何必曾相识,留下您的足迹吧..."></textarea>
|
||||
</div>
|
||||
<div class="gb-form-actions">
|
||||
<button type="button" class="gb-form-cancel" data-gb-form-cancel>取消</button>
|
||||
<button type="submit" class="gb-form-submit">✈️ 发送飞鸽</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{{-- 写留言按钮 --}}
|
||||
<div id="guestbook-write-btn-wrap">
|
||||
<button id="guestbook-write-btn" data-guestbook-write-btn>✏️ 写新留言</button>
|
||||
</div>
|
||||
|
||||
{{-- 分页 --}}
|
||||
<div id="guestbook-pager" style="display:none;">
|
||||
<button id="gb-page-prev" data-gb-page="prev">‹ 上一页</button>
|
||||
<span id="gb-page-info"></span>
|
||||
<button id="gb-page-next" data-gb-page="next">下一页 ›</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -27,7 +27,7 @@
|
||||
<div class="tool-btn" data-toolbar-action="settings" title="个人设置">设置
|
||||
</div>
|
||||
<div class="tool-btn" data-toolbar-url="{{ route('feedback.index') }}" title="反馈">反馈</div>
|
||||
<div class="tool-btn" data-toolbar-url="{{ route('guestbook.index') }}" 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())
|
||||
|
||||
Reference in New Issue
Block a user