272 lines
6.0 KiB
PHP
272 lines
6.0 KiB
PHP
{{--
|
||
文件功能:好友列表浮窗面板
|
||
|
||
提供全局 JS API:
|
||
window.openFriendPanel() 打开好友面板(自动刷新列表)
|
||
window.closeFriendPanel() 关闭好友面板
|
||
|
||
面板分为两个区域:
|
||
1. 📋 我关注的好友 —— 我已添加的人,显示互相状态、添加时间、删除按钮
|
||
2. 💌 对方已加我 —— 别人加了我但我未回加,显示对方添加时间、回加按钮
|
||
|
||
搜索栏支持输入用户名后按 Enter 或点击「➕ 添加好友」直接添加。
|
||
|
||
所有添加/删除操作调用与双击用户卡片完全相同的后端接口:
|
||
POST /friend/{username}/add
|
||
DELETE /friend/{username}/remove
|
||
|
||
依赖:
|
||
- window.chatContext.roomId 当前房间 ID(由 frame.blade.php 注入)
|
||
- meta[name="csrf-token"] CSRF 令牌
|
||
|
||
@author ChatRoom Laravel
|
||
@version 1.0.0
|
||
--}}
|
||
|
||
{{-- ════ 样式 ════ --}}
|
||
<style>
|
||
#friend-panel {
|
||
display: none;
|
||
position: fixed;
|
||
inset: 0;
|
||
background: rgba(0, 0, 0, .5);
|
||
z-index: 9999;
|
||
justify-content: center;
|
||
align-items: center;
|
||
}
|
||
|
||
#friend-panel-inner {
|
||
background: #fff;
|
||
border-radius: 8px;
|
||
width: 480px;
|
||
max-width: 96vw;
|
||
max-height: 86vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
box-shadow: 0 8px 32px rgba(0, 0, 0, .3);
|
||
overflow: hidden;
|
||
}
|
||
|
||
#friend-panel-header {
|
||
background: linear-gradient(135deg, #336699, #5a8fc0);
|
||
color: #fff;
|
||
padding: 10px 16px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
#friend-panel-title {
|
||
font-size: 14px;
|
||
font-weight: bold;
|
||
flex: 1;
|
||
}
|
||
|
||
#friend-panel-close {
|
||
cursor: pointer;
|
||
font-size: 18px;
|
||
opacity: .8;
|
||
line-height: 1;
|
||
transition: opacity .15s;
|
||
}
|
||
|
||
#friend-panel-close:hover {
|
||
opacity: 1;
|
||
}
|
||
|
||
#friend-add-bar {
|
||
padding: 8px 12px;
|
||
border-bottom: 1px solid #e8eef5;
|
||
display: flex;
|
||
gap: 6px;
|
||
background: #f6faff;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
#friend-search-input {
|
||
flex: 1;
|
||
padding: 5px 10px;
|
||
border: 1px solid #aac;
|
||
border-radius: 4px;
|
||
font-size: 12px;
|
||
outline: none;
|
||
}
|
||
|
||
#friend-search-input:focus {
|
||
border-color: #336699;
|
||
}
|
||
|
||
#friend-search-btn {
|
||
padding: 5px 14px;
|
||
background: #336699;
|
||
color: #fff;
|
||
border: none;
|
||
border-radius: 4px;
|
||
font-size: 12px;
|
||
font-weight: bold;
|
||
cursor: pointer;
|
||
}
|
||
|
||
#friend-search-btn:hover {
|
||
background: #2a5580;
|
||
}
|
||
|
||
#friend-panel-body {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding: 10px 12px;
|
||
background: #f6faff;
|
||
}
|
||
|
||
.fp-section-title {
|
||
font-size: 11px;
|
||
font-weight: bold;
|
||
color: #336699;
|
||
padding: 4px 0 6px;
|
||
border-bottom: 1px solid #cde;
|
||
margin-bottom: 6px;
|
||
}
|
||
|
||
.fp-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 6px 8px;
|
||
border-radius: 5px;
|
||
background: #fff;
|
||
margin-bottom: 5px;
|
||
border: 1px solid #e0eaf5;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.fp-row:hover {
|
||
background: #eef5ff;
|
||
}
|
||
|
||
.fp-avatar {
|
||
width: 28px;
|
||
height: 28px;
|
||
border-radius: 3px;
|
||
border: 1px solid #aac;
|
||
flex-shrink: 0;
|
||
object-fit: cover;
|
||
}
|
||
|
||
.fp-name {
|
||
font-weight: bold;
|
||
color: #224466;
|
||
flex: 1;
|
||
}
|
||
|
||
.fp-badge {
|
||
font-size: 10px;
|
||
padding: 1px 6px;
|
||
border-radius: 10px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.fp-badge-mutual {
|
||
background: #e8fde8;
|
||
color: #16a34a;
|
||
}
|
||
|
||
.fp-badge-onesided {
|
||
background: #fff3e0;
|
||
color: #b45309;
|
||
}
|
||
|
||
.fp-date {
|
||
font-size: 10px;
|
||
color: #999;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.fp-action-btn {
|
||
padding: 3px 10px;
|
||
border: none;
|
||
border-radius: 3px;
|
||
font-size: 11px;
|
||
font-weight: bold;
|
||
cursor: pointer;
|
||
transition: opacity .15s;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.fp-action-btn:hover {
|
||
opacity: .8;
|
||
}
|
||
|
||
.fp-btn-add {
|
||
background: #16a34a;
|
||
color: #fff;
|
||
}
|
||
|
||
.fp-btn-remove {
|
||
background: #dc2626;
|
||
color: #fff;
|
||
}
|
||
|
||
#fp-notice {
|
||
font-size: 11px;
|
||
color: #888;
|
||
text-align: center;
|
||
padding: 4px 0 2px;
|
||
min-height: 18px;
|
||
}
|
||
|
||
.fp-empty {
|
||
text-align: center;
|
||
color: #aaa;
|
||
font-size: 12px;
|
||
padding: 16px 0;
|
||
}
|
||
|
||
/* 在线状态小圆点 */
|
||
.fp-status {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 3px;
|
||
font-size: 10px;
|
||
font-weight: bold;
|
||
padding: 1px 6px;
|
||
border-radius: 10px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.fp-status-online {
|
||
background: #dcfce7;
|
||
color: #15803d;
|
||
}
|
||
|
||
.fp-status-offline {
|
||
background: #f1f5f9;
|
||
color: #94a3b8;
|
||
}
|
||
</style>
|
||
|
||
{{-- ════ HTML ════ --}}
|
||
<div id="friend-panel">
|
||
<div id="friend-panel-inner">
|
||
{{-- 标题栏 --}}
|
||
<div id="friend-panel-header">
|
||
<span id="friend-panel-title">👥 我的好友</span>
|
||
<span id="friend-panel-close" data-friend-panel-close>✕</span>
|
||
</div>
|
||
|
||
{{-- 搜索/添加新好友 --}}
|
||
<div id="friend-add-bar">
|
||
<input id="friend-search-input" type="text" maxlength="20" placeholder="输入用户名搜索并添加好友…">
|
||
<button id="friend-search-btn" data-friend-search>➕ 添加好友</button>
|
||
</div>
|
||
|
||
{{-- 操作结果提示 --}}
|
||
<div id="fp-notice"></div>
|
||
|
||
{{-- 列表主体(由 JS 动态填充) --}}
|
||
<div id="friend-panel-body">
|
||
<div class="fp-empty">加载中…</div>
|
||
</div>
|
||
</div>
|
||
</div>
|