feat: 好友系统全实现
后端:
- FriendController:add/remove/status/index 四个接口
- FriendAdded / FriendRemoved 广播事件(私有频道)
- channels.php 注册 user.{username} 私有频道鉴权
- routes/web.php 注册好友路由
- ChatController::init() 修复 DutyLog 在 return 后执行的 bug
- ChatController::notifyFriendsOnline() 上线时悄悄话通知好友
前端:
- user-actions:写私信 → 加好友/删好友按钮(动态状态)
- toggleFriend() 方法 + fetchUser 后加载好友状态
- scripts:监听私有频道 FriendAdded/FriendRemoved
- showFriendToast() 右下角浮窗通知(5秒自动消失)
- global-dialog 加 fdSlideIn 动画
This commit is contained in:
@@ -86,6 +86,8 @@
|
||||
whisperList: [],
|
||||
showAnnounce: false,
|
||||
announceText: '',
|
||||
is_friend: false, // 当前用户是否已将对方加为好友
|
||||
friendLoading: false, // 好友操作加载状态
|
||||
gifts: window.__gifts || [],
|
||||
selectedGiftId: window.__defaultGiftId || 0,
|
||||
giftCount: 1,
|
||||
@@ -107,6 +109,51 @@
|
||||
$alert: (...args) => window.chatDialog.alert(...args),
|
||||
$confirm: (...args) => window.chatDialog.confirm(...args),
|
||||
|
||||
/** 切换好友关系(加好友 / 删好友) */
|
||||
async toggleFriend() {
|
||||
if (this.friendLoading) return;
|
||||
this.friendLoading = true;
|
||||
const username = this.userInfo.username;
|
||||
const roomId = window.chatContext.roomId;
|
||||
const removing = this.is_friend;
|
||||
|
||||
try {
|
||||
let res;
|
||||
if (removing) {
|
||||
// 删除好友
|
||||
res = await fetch(`/friend/${encodeURIComponent(username)}/remove`, {
|
||||
method: 'DELETE',
|
||||
headers: this._headers(),
|
||||
body: JSON.stringify({
|
||||
room_id: roomId
|
||||
}),
|
||||
});
|
||||
} else {
|
||||
// 添加好友
|
||||
res = await fetch(`/friend/${encodeURIComponent(username)}/add`, {
|
||||
method: 'POST',
|
||||
headers: this._headers(),
|
||||
body: JSON.stringify({
|
||||
room_id: roomId
|
||||
}),
|
||||
});
|
||||
}
|
||||
const data = await res.json();
|
||||
const ok = data.status === 'success';
|
||||
this.$alert(
|
||||
data.message,
|
||||
ok ? (removing ? '已删除好友' : '添加成功 🎉') : '操作失败',
|
||||
ok ? (removing ? '#6b7280' : '#16a34a') : '#cc4444'
|
||||
);
|
||||
if (ok) {
|
||||
this.is_friend = !this.is_friend;
|
||||
}
|
||||
} catch (e) {
|
||||
this.$alert('网络异常', '错误', '#cc4444');
|
||||
}
|
||||
this.friendLoading = false;
|
||||
},
|
||||
|
||||
/** 获取用户资料 */
|
||||
async fetchUser(username) {
|
||||
try {
|
||||
@@ -126,6 +173,19 @@
|
||||
const data = await res.json();
|
||||
if (data.status === 'success') {
|
||||
this.userInfo = data.data;
|
||||
this.showPositionHistory = false;
|
||||
|
||||
// 加载好友状态(仅对非自己的用户查询)
|
||||
if (data.data.username !== window.chatContext.username) {
|
||||
fetch(`/friend/${encodeURIComponent(data.data.username)}/status`, {
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
}
|
||||
}).then(r => r.json()).then(s => {
|
||||
this.is_friend = s.is_friend ?? false;
|
||||
});
|
||||
}
|
||||
this.showUserModal = true;
|
||||
this.isMuting = false;
|
||||
this.showWhispers = false;
|
||||
@@ -554,13 +614,15 @@
|
||||
<div x-data="{ showGiftPanel: false }" x-show="userInfo.username !== window.chatContext.username">
|
||||
|
||||
<div class="modal-actions" style="margin-bottom: 0;">
|
||||
{{-- 写私信 --}}
|
||||
<a class="btn-mail"
|
||||
:href="'{{ route('guestbook.index', ['tab' => 'outbox']) }}&to=' + encodeURIComponent(userInfo
|
||||
.username)"
|
||||
target="_blank">
|
||||
写私信
|
||||
</a>
|
||||
{{-- 加好友 / 删好友(替代写私信) --}}
|
||||
<button x-on:click="toggleFriend()" :disabled="friendLoading"
|
||||
:style="is_friend
|
||||
?
|
||||
'background: #f1f5f9; color: #6b7280; border: 1px solid #d1d5db;' :
|
||||
'background: linear-gradient(135deg,#16a34a,#22c55e); color:#fff; border:none;'"
|
||||
style="padding: 7px 14px; border-radius: 5px; font-size: 12px;
|
||||
cursor: pointer; font-weight: bold; transition: opacity .15s;"
|
||||
x-text="friendLoading ? '处理中…' : (is_friend ? '✅ 已是好友 (点击删除)' : '➕ 加好友')"></button>
|
||||
{{-- 送花按鈕(与写私信并列) --}}
|
||||
<button class="btn-whisper" x-on:click="showGiftPanel = !showGiftPanel">
|
||||
🎁 送礼物
|
||||
|
||||
Reference in New Issue
Block a user