/**
* 好友列表弹窗组件
* 负责显示和管理好友列表的所有功能
*/
class FriendListModal {
constructor() {
this.isVisible = false;
this.element = null;
this.friends = [];
this.currentPage = 1;
this.pageSize = 10;
this.totalPages = 1;
this.isLoading = false;
this.searchKeyword = '';
this.init();
}
// 初始化组件
init() {
this.createStyles();
this.createElement();
this.bindEvents();
}
// 创建样式
createStyles() {
if (document.getElementById('friend-list-modal-styles')) return;
const style = document.createElement('style');
style.id = 'friend-list-modal-styles';
style.textContent = `
.friend-list-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(5px);
z-index: 10000;
opacity: 0;
visibility: hidden;
transition: all 0.3s ease;
display: flex;
justify-content: flex-end;
align-items: stretch;
}
.friend-list-modal.visible {
opacity: 1;
visibility: visible;
}
.friend-list-content {
background: white;
width: 400px;
max-width: 90vw;
height: 100%;
box-shadow: -8px 0 25px rgba(0, 0, 0, 0.15), -2px 0 10px rgba(0, 0, 0, 0.1);
transform: translateX(100%);
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
overflow: hidden;
display: flex;
flex-direction: column;
border-radius: 20px 0 0 20px;
border-left: 1px solid rgba(255, 255, 255, 0.1);
}
.friend-list-modal.visible .friend-list-content {
transform: translateX(0);
}
.friend-list-header {
padding: 20px;
border-bottom: 1px solid #eee;
display: flex;
justify-content: space-between;
align-items: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
flex-shrink: 0;
border-radius: 20px 0 0 0;
flex-direction: column;
gap: 10px;
}
.friend-list-header-top {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
.friend-list-title {
margin: 0;
font-size: 18px;
font-weight: 600;
}
.friend-list-user-info {
width: 100%;
display: flex;
align-items: center;
gap: 12px;
padding: 8px 0;
border-top: 1px solid rgba(255, 255, 255, 0.2);
min-height: 40px;
}
.friend-list-user-name {
color: white;
font-size: 14px;
font-weight: 500;
line-height: 1;
display: flex;
align-items: center;
height: 32px;
}
.friend-list-user-badge {
flex-shrink: 0;
display: flex;
align-items: center;
height: 32px;
}
.friend-list-user-badge .rank-badge {
vertical-align: middle !important;
margin: 0 !important;
margin-bottom: 0 !important;
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
}
.friend-list-close {
background: none;
border: none;
color: white;
font-size: 20px;
cursor: pointer;
padding: 0;
margin: 0;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
line-height: 1;
font-family: Arial, sans-serif;
font-weight: normal;
}
.friend-list-close:hover {
background: rgba(255, 255, 255, 0.2);
transform: scale(1.1);
backdrop-filter: blur(10px);
}
.friend-list-close:active {
transform: scale(0.95);
}
.friend-list-close svg {
display: block;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.friend-list-close:hover svg {
transform: rotate(90deg);
}
.friend-list-search {
padding: 15px 20px;
border-bottom: 1px solid #eee;
flex-shrink: 0;
}
.friend-search-input {
width: 100%;
padding: 10px 15px;
border: 2px solid #e0e0e0;
border-radius: 25px;
font-size: 14px;
outline: none;
transition: border-color 0.3s;
}
.friend-search-input:focus {
border-color: #667eea;
}
.friend-list-body {
padding: 20px;
flex: 1;
overflow-y: auto;
}
.friend-list-body::-webkit-scrollbar {
width: 6px;
}
.friend-list-body::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
.friend-list-body::-webkit-scrollbar-thumb {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 3px;
}
.friend-list-body::-webkit-scrollbar-thumb:hover {
background: linear-gradient(135deg, #5a67d8 0%, #6b46c1 100%);
}
/* 移动端优化 */
@media (max-width: 768px) {
.friend-list-content {
border-radius: 15px 0 0 15px;
}
.friend-list-header {
border-radius: 15px 0 0 0;
}
.friend-list-pagination {
border-radius: 0 0 0 15px;
}
}
.friend-item {
display: flex;
align-items: center;
padding: 12px 10px;
margin: 2px 0;
border-bottom: 1px solid #f5f5f5;
border-radius: 8px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
cursor: pointer;
gap: 12px;
}
.friend-item:hover {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
border-radius: 12px;
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
border-bottom: 1px solid transparent;
}
.friend-item:last-child {
border-bottom: none;
margin-bottom: 0;
}
.friend-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: 600;
font-size: 14px;
flex-shrink: 0;
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border: 2px solid rgba(255, 255, 255, 0.9);
}
.friend-item:hover .friend-avatar {
transform: scale(1.05);
box-shadow: 0 4px 16px rgba(102, 126, 234, 0.4);
}
.friend-info {
flex: 1;
min-width: 0;
display: flex;
align-items: center;
gap: 10px;
}
.friend-name {
font-weight: 600;
font-size: 14px;
color: #333;
transition: color 0.3s cubic-bezier(0.4, 0, 0.2, 1);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
flex-shrink: 1;
}
.friend-item:hover .friend-name {
color: #667eea;
}
.friend-rank {
display: flex;
align-items: center;
flex-shrink: 0;
}
.friend-rank-badge {
padding: 2px 8px;
border-radius: 12px;
font-size: 11px;
font-weight: 500;
background: #e3f2fd;
color: #1976d2;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
box-shadow: 0 1px 3px rgba(25, 118, 210, 0.2);
white-space: nowrap;
}
.friend-item:hover .friend-rank-badge {
transform: scale(1.02);
box-shadow: 0 2px 6px rgba(25, 118, 210, 0.3);
}
.friend-actions {
display: flex;
gap: 8px;
flex-shrink: 0;
}
.friend-action-btn {
padding: 6px 12px;
border: none;
border-radius: 20px;
font-size: 11px;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
font-weight: 500;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
opacity: 0.8;
transform: scale(0.95);
white-space: nowrap;
}
.friend-item:hover .friend-action-btn {
opacity: 1;
transform: scale(1);
}
.friend-remove-btn {
background: linear-gradient(135deg, #ffebee 0%, #fce4ec 100%);
color: #d32f2f;
border: 1px solid #ffcdd2;
}
.friend-remove-btn:hover {
background: linear-gradient(135deg, #d32f2f 0%, #c62828 100%);
color: white;
transform: scale(1.05);
box-shadow: 0 4px 12px rgba(211, 47, 47, 0.3);
}
.friend-list-pagination {
padding: 15px 20px;
border-top: 1px solid #eee;
display: flex !important;
justify-content: center;
align-items: center;
gap: 10px;
flex-shrink: 0;
background: #fafafa;
border-radius: 0 0 0 20px;
}
.pagination-btn {
padding: 8px 12px;
border: 1px solid #ddd;
background: white;
color: #333;
cursor: pointer;
border-radius: 6px;
font-size: 12px;
font-weight: 500;
transition: all 0.3s;
opacity: 1;
visibility: visible;
min-width: 60px;
}
.pagination-btn:hover:not(:disabled) {
background: #667eea;
color: white;
border-color: #667eea;
transform: translateY(-1px);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.pagination-btn:disabled {
opacity: 0.4;
cursor: not-allowed;
background: #f5f5f5;
color: #999;
}
/* 强制显示分页按钮 */
.friend-list-pagination .pagination-btn {
display: inline-block !important;
visibility: visible !important;
opacity: 1 !important;
}
.friend-list-pagination .pagination-btn:disabled {
opacity: 0.4 !important;
}
.pagination-info {
font-size: 12px;
color: #666;
font-weight: 500;
margin: 0 10px;
white-space: nowrap;
}
.friend-list-loading {
text-align: center;
padding: 40px;
color: #666;
}
.friend-list-empty {
text-align: center;
padding: 40px;
color: #999;
}
.friend-list-error {
text-align: center;
padding: 40px;
color: #d32f2f;
}
.loading-spinner {
display: inline-block;
width: 20px;
height: 20px;
border: 2px solid #f3f3f3;
border-top: 2px solid #667eea;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-right: 10px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.add-friend-section {
padding: 15px 20px;
border-bottom: 1px solid #eee;
background: #f8f9fa;
flex-shrink: 0;
}
.add-friend-tabs {
display: flex;
margin-bottom: 15px;
border-radius: 6px;
overflow: hidden;
border: 1px solid #ddd;
}
.add-friend-tab {
flex: 1;
padding: 8px 12px;
background: #fff;
border: none;
cursor: pointer;
font-size: 12px;
transition: all 0.3s;
color: #666;
}
.add-friend-tab.active {
background: #667eea;
color: white;
}
.add-friend-tab:hover:not(.active) {
background: #f0f0f0;
}
.add-friend-form {
display: flex;
gap: 8px;
align-items: center;
flex-wrap: nowrap;
}
.add-friend-input {
flex: 1;
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 13px;
outline: none;
min-width: 120px;
}
.add-friend-input:focus {
border-color: #667eea;
box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.1);
}
.add-friend-btn {
padding: 8px 16px;
background: #4caf50;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: background 0.3s;
}
.add-friend-btn:hover {
background: #45a049;
}
.add-friend-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
`;
document.head.appendChild(style);
}
// 创建DOM元素
createElement() {
this.element = document.createElement('div');
this.element.className = 'friend-list-modal';
this.element.innerHTML = `
`;
document.body.appendChild(this.element);
}
// 绑定事件
bindEvents() {
// 关闭弹窗
this.element.querySelector('.friend-list-close').addEventListener('click', () => {
this.hide();
});
// 点击背景关闭
this.element.addEventListener('click', (e) => {
if (e.target === this.element) {
this.hide();
}
});
// 搜索功能
const searchInput = this.element.querySelector('.friend-search-input');
let searchTimeout;
searchInput.addEventListener('input', (e) => {
clearTimeout(searchTimeout);
searchTimeout = setTimeout(() => {
this.searchKeyword = e.target.value.trim();
this.currentPage = 1;
this.loadFriends();
}, 300);
});
// 分页功能
this.element.querySelector('.friend-list-pagination').addEventListener('click', (e) => {
if (e.target.classList.contains('pagination-btn')) {
const action = e.target.dataset.action;
if (action === 'prev' && this.currentPage > 1) {
this.currentPage--;
this.loadFriends();
} else if (action === 'next' && this.currentPage < this.totalPages) {
this.currentPage++;
this.loadFriends();
}
}
});
// 添加好友选项卡切换
this.element.querySelector('.add-friend-tabs').addEventListener('click', (e) => {
if (e.target.classList.contains('add-friend-tab')) {
// 移除所有活动状态
this.element.querySelectorAll('.add-friend-tab').forEach(tab => {
tab.classList.remove('active');
});
// 设置当前选项卡为活动状态
e.target.classList.add('active');
// 更新输入框
const inputType = e.target.dataset.type;
const addFriendInput = this.element.querySelector('.add-friend-input');
addFriendInput.dataset.type = inputType;
if (inputType === 'id') {
addFriendInput.placeholder = '请输入用户ID(数字)';
addFriendInput.type = 'number';
} else {
addFriendInput.placeholder = '请输入用户名';
addFriendInput.type = 'text';
}
// 清空输入框
addFriendInput.value = '';
}
});
// 添加好友
const addFriendBtn = this.element.querySelector('.add-friend-btn');
const addFriendInput = this.element.querySelector('.add-friend-input');
addFriendBtn.addEventListener('click', () => {
this.addFriend();
});
addFriendInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
this.addFriend();
}
});
// 事件委托 - 处理好友列表中的按钮点击
this.element.querySelector('.friend-list-body').addEventListener('click', (e) => {
if (e.target.classList.contains('friend-remove-btn')) {
const userId = parseInt(e.target.dataset.userId);
this.removeFriend(userId);
}
});
}
// 显示弹窗
show() {
this.isVisible = true;
this.element.classList.add('visible');
this.loadUserInfo();
this.loadFriends();
}
// 隐藏弹窗
hide() {
this.isVisible = false;
this.element.classList.remove('visible');
}
// 切换显示状态
toggle() {
if (this.isVisible) {
this.hide();
} else {
this.show();
}
}
// 获取API配置
getApiConfig() {
const config = window.CONFIG || {};
const accessToken = localStorage.getItem('access_token') || sessionStorage.getItem('access_token');
return {
baseUrl: config.DataServerBaseUrl || '',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
}
};
}
// 等待徽章生成器加载
async waitForBadgeGenerator() {
return new Promise((resolve) => {
const checkInterval = setInterval(() => {
if (window.RankBadgeGenerator && typeof window.getBadgeOnly === 'function') {
clearInterval(checkInterval);
resolve(true);
}
}, 100);
// 5秒超时
setTimeout(() => {
clearInterval(checkInterval);
resolve(false);
}, 5000);
});
}
// 加载用户信息
async loadUserInfo() {
try {
const apiConfig = this.getApiConfig();
const username = localStorage.getItem('username') || '用户';
// 更新用户名
const userNameElement = this.element.querySelector('.friend-list-user-name');
userNameElement.textContent = username;
// 等待徽章生成器加载
await this.waitForBadgeGenerator();
// 获取用户称号信息
const response = await fetch(`${apiConfig.baseUrl}/api/get-user-rank/`, {
method: 'POST',
headers: apiConfig.headers,
body: JSON.stringify({})
});
if (response.ok) {
const result = await response.json();
if (result.success && result.data) {
const rankLevel = result.data.rank_level || 1;
const userBadgeElement = this.element.querySelector('.friend-list-user-badge');
const badge = this.generateUserRankBadge(rankLevel);
userBadgeElement.innerHTML = badge;
} else {
console.warn('获取用户称号信息失败:', result.message);
// 使用默认徽章
const userBadgeElement = this.element.querySelector('.friend-list-user-badge');
const badge = this.generateUserRankBadge(1);
userBadgeElement.innerHTML = badge;
}
}
} catch (error) {
console.error('加载用户信息失败:', error);
// 使用默认信息
const userNameElement = this.element.querySelector('.friend-list-user-name');
userNameElement.textContent = localStorage.getItem('username') || '用户';
// 使用默认徽章
const userBadgeElement = this.element.querySelector('.friend-list-user-badge');
const badge = this.generateUserRankBadge(1);
userBadgeElement.innerHTML = badge;
}
}
// 加载好友列表
async loadFriends() {
if (this.isLoading) return;
this.isLoading = true;
// 清空当前好友数据,防止累积
this.friends = [];
const bodyElement = this.element.querySelector('.friend-list-body');
// 显示加载状态
bodyElement.innerHTML = `
`;
try {
const apiConfig = this.getApiConfig();
const response = await fetch(`${apiConfig.baseUrl}/api/get-friends/`, {
method: 'POST',
headers: apiConfig.headers,
body: JSON.stringify({
page: this.currentPage,
page_size: this.pageSize,
search: this.searchKeyword
})
});
const result = await response.json();
if (result.success) {
// 添加调试信息
console.log('接口返回的好友数据:', result.data.friends);
console.log('好友数量:', result.data.friends.length);
// 数据去重处理(基于user_id)
const uniqueFriends = [];
const seenIds = new Set();
result.data.friends.forEach(friend => {
if (!seenIds.has(friend.user_id)) {
seenIds.add(friend.user_id);
uniqueFriends.push(friend);
} else {
console.warn('发现重复的好友数据:', friend);
}
});
console.log('去重后的好友数据:', uniqueFriends);
console.log('去重后的好友数量:', uniqueFriends.length);
this.friends = uniqueFriends;
this.updatePagination(result.data.pagination);
this.renderFriendList();
} else {
throw new Error(result.message);
}
} catch (error) {
console.error('加载好友列表失败:', error);
const errorMessage = error.message || '未知错误';
bodyElement.innerHTML = `
加载失败: ${errorMessage}
`;
} finally {
this.isLoading = false;
}
}
// 渲染好友列表
renderFriendList() {
const bodyElement = this.element.querySelector('.friend-list-body');
console.log('开始渲染好友列表,数量:', this.friends.length);
console.log('要渲染的好友:', this.friends);
// 调用调试方法检查重复
this.debugCheckDuplicates();
if (this.friends.length === 0) {
bodyElement.innerHTML = `
${this.searchKeyword ? '没有找到匹配的好友' : '还没有好友,快去添加一些吧!'}
`;
return;
}
const friendsHtml = this.friends.map(friend => {
const firstChar = friend.full_name ? friend.full_name.charAt(0) : friend.username.charAt(0);
const rankBadge = this.generateFriendRankBadge(friend.rank_level);
return `
${firstChar}
${friend.full_name || friend.username}
${rankBadge}
`;
}).join('');
bodyElement.innerHTML = friendsHtml;
console.log('渲染完成,DOM中的好友项数量:', bodyElement.querySelectorAll('.friend-item').length);
}
// 生成用户自己的段位徽章(原始大小)
generateUserRankBadge(rankLevel) {
console.log('生成用户徽章,rankLevel:', rankLevel);
console.log('window.getBadgeOnly存在:', typeof window.getBadgeOnly === 'function');
console.log('window.rankBadgeGenerator存在:', !!window.rankBadgeGenerator);
// 尝试使用全局的便捷方法
if (typeof window.getBadgeOnly === 'function') {
const badgeElement = window.getBadgeOnly(rankLevel);
console.log('getBadgeOnly返回的元素:', badgeElement);
if (badgeElement) {
// 确保徽章垂直对齐
badgeElement.style.display = 'inline-flex';
badgeElement.style.alignItems = 'center';
badgeElement.style.justifyContent = 'center';
badgeElement.style.margin = '0';
badgeElement.style.verticalAlign = 'middle';
return badgeElement.outerHTML;
}
}
// 尝试使用实例方法
if (window.rankBadgeGenerator && typeof window.rankBadgeGenerator.getBadgeOnly === 'function') {
const badgeElement = window.rankBadgeGenerator.getBadgeOnly(rankLevel);
console.log('rankBadgeGenerator.getBadgeOnly返回的元素:', badgeElement);
if (badgeElement) {
// 确保徽章垂直对齐
badgeElement.style.display = 'inline-flex';
badgeElement.style.alignItems = 'center';
badgeElement.style.justifyContent = 'center';
badgeElement.style.margin = '0';
badgeElement.style.verticalAlign = 'middle';
return badgeElement.outerHTML;
}
}
// 降级方案
console.log('使用降级方案生成用户徽章');
return this.getFallbackBadge(rankLevel, false);
}
// 生成好友的段位徽章(适合好友列表的小尺寸)
generateFriendRankBadge(rankLevel) {
console.log('生成好友徽章,rankLevel:', rankLevel);
// 尝试使用全局的便捷方法
if (typeof window.getBadgeOnly === 'function') {
const badgeElement = window.getBadgeOnly(rankLevel);
console.log('getBadgeOnly返回的好友徽章元素:', badgeElement);
if (badgeElement) {
// 调整样式以适应好友列表
badgeElement.style.width = '128px';
badgeElement.style.height = '32px';
badgeElement.style.fontSize = '9px';
badgeElement.style.marginBottom = '0';
return badgeElement.outerHTML;
}
}
// 尝试使用实例方法
if (window.rankBadgeGenerator && typeof window.rankBadgeGenerator.getBadgeOnly === 'function') {
const badgeElement = window.rankBadgeGenerator.getBadgeOnly(rankLevel);
console.log('rankBadgeGenerator.getBadgeOnly返回的好友徽章元素:', badgeElement);
if (badgeElement) {
// 调整样式以适应好友列表
badgeElement.style.width = '128px';
badgeElement.style.height = '32px';
badgeElement.style.fontSize = '9px';
badgeElement.style.marginBottom = '0';
return badgeElement.outerHTML;
}
}
// 降级方案
console.log('使用降级方案生成好友徽章');
return this.getFallbackBadge(rankLevel, true);
}
// 降级方案的徽章生成
getFallbackBadge(rankLevel, isSmall) {
const rankNames = {
1: '坚韧黑铁',
2: '英勇黄铜',
3: '不屈白银',
4: '荣耀黄金',
5: '华贵铂金',
6: '璀璨钻石',
7: '超凡大师',
8: '傲世宗师',
9: '最强王者'
};
const rankName = rankNames[rankLevel] || '无段位';
const colors = {
1: '#95a5a6',
2: '#f1c40f',
3: '#f8f9fa',
4: '#fff3cd',
5: '#d5dbdb',
6: '#3498db',
7: '#9b59b6',
8: '#e74c3c',
9: '#f39c12'
};
const color = colors[rankLevel] || '#666';
if (isSmall) {
return `${rankName}`;
} else {
return `${rankName}`;
}
}
// 更新分页信息
updatePagination(pagination) {
this.currentPage = pagination.current_page;
this.totalPages = pagination.total_pages;
const paginationElement = this.element.querySelector('.friend-list-pagination');
const prevBtn = paginationElement.querySelector('[data-action="prev"]');
const nextBtn = paginationElement.querySelector('[data-action="next"]');
const infoElement = paginationElement.querySelector('.pagination-info');
// 更新按钮状态
prevBtn.disabled = this.currentPage <= 1;
nextBtn.disabled = this.currentPage >= this.totalPages;
// 确保按钮可见
prevBtn.style.display = 'inline-block';
nextBtn.style.display = 'inline-block';
prevBtn.style.opacity = '1';
nextBtn.style.opacity = '1';
// 更新分页信息
infoElement.textContent = `第 ${this.currentPage} 页,共 ${this.totalPages} 页`;
// 只有多页时才显示分页区域
paginationElement.style.display = this.totalPages > 1 ? 'flex' : 'none';
// 强制显示分页区域用于测试(可以删除这行)
// paginationElement.style.display = 'flex';
console.log('分页更新:', {
currentPage: this.currentPage,
totalPages: this.totalPages,
prevDisabled: prevBtn.disabled,
nextDisabled: nextBtn.disabled
});
}
// 添加好友
async addFriend() {
const input = this.element.querySelector('.add-friend-input');
const btn = this.element.querySelector('.add-friend-btn');
const inputValue = input.value.trim();
const inputType = input.dataset.type;
if (!inputValue) {
const typeText = inputType === 'id' ? '用户ID' : '用户名';
alert(`请输入${typeText}`);
return;
}
// 验证输入格式
if (inputType === 'id') {
if (!/^\d+$/.test(inputValue)) {
alert('用户ID必须是数字');
return;
}
} else {
if (inputValue.length < 2) {
alert('用户名至少需要2个字符');
return;
}
}
btn.disabled = true;
btn.textContent = '添加中...';
try {
const apiConfig = this.getApiConfig();
// 根据选择的类型构建请求数据
const requestData = inputType === 'id' ?
{ user_to_id: parseInt(inputValue) } :
{ username: inputValue };
console.log('添加好友请求数据:', requestData);
const response = await fetch(`${apiConfig.baseUrl}/api/add-friend/`, {
method: 'POST',
headers: apiConfig.headers,
body: JSON.stringify(requestData)
});
const result = await response.json();
if (result.success) {
// 显示详细的成功信息
const friendInfo = result.data.user_to;
const friendName = friendInfo.full_name || friendInfo.username;
alert(`成功添加 ${friendName} (${friendInfo.username}) 为好友!`);
input.value = '';
this.currentPage = 1;
// 清空当前好友列表,避免重复
this.friends = [];
this.loadFriends(); // 重新加载好友列表
} else {
alert(`添加失败: ${result.message}`);
}
} catch (error) {
console.error('添加好友失败:', error);
alert(`添加失败: ${error.message}`);
} finally {
btn.disabled = false;
btn.textContent = '添加好友';
}
}
// 删除好友
async removeFriend(userId) {
// 找到对应的好友信息用于确认
const friend = this.friends.find(f => f.user_id === userId);
const friendName = friend ? (friend.full_name || friend.username) : '该好友';
if (!confirm(`确定要删除好友 "${friendName}" 吗?`)) {
return;
}
// 禁用所有删除按钮,防止重复点击
const removeButtons = this.element.querySelectorAll('.friend-remove-btn');
removeButtons.forEach(btn => {
btn.disabled = true;
btn.textContent = '删除中...';
});
try {
const apiConfig = this.getApiConfig();
const response = await fetch(`${apiConfig.baseUrl}/api/remove-friend/`, {
method: 'POST',
headers: apiConfig.headers,
body: JSON.stringify({
user_to_id: userId
})
});
const result = await response.json();
if (result.success) {
// 不使用alert,而是直接重新加载列表
// 清空当前好友列表,避免重复
this.friends = [];
this.loadFriends(); // 重新加载好友列表
} else {
alert(`删除失败: ${result.message}`);
// 恢复按钮状态
removeButtons.forEach(btn => {
btn.disabled = false;
btn.textContent = '删除';
});
}
} catch (error) {
console.error('删除好友失败:', error);
alert(`删除失败: ${error.message}`);
// 恢复按钮状态
removeButtons.forEach(btn => {
btn.disabled = false;
btn.textContent = '删除';
});
}
}
// 调试方法:检查重复数据
debugCheckDuplicates() {
console.group('🔍 重复数据检查');
console.log('当前好友数组:', this.friends);
const userIds = this.friends.map(f => f.user_id);
const uniqueIds = [...new Set(userIds)];
console.log('用户ID数组:', userIds);
console.log('去重后的ID数组:', uniqueIds);
console.log('是否有重复:', userIds.length !== uniqueIds.length);
if (userIds.length !== uniqueIds.length) {
console.warn('❌ 发现重复数据!');
const duplicates = userIds.filter((id, index) => userIds.indexOf(id) !== index);
console.log('重复的ID:', [...new Set(duplicates)]);
} else {
console.log('✅ 没有重复数据');
}
console.groupEnd();
}
// 销毁组件
destroy() {
if (this.element && this.element.parentNode) {
this.element.parentNode.removeChild(this.element);
}
const styles = document.getElementById('friend-list-modal-styles');
if (styles) {
styles.parentNode.removeChild(styles);
}
this.element = null;
}
}
// 暴露给全局使用
if (typeof window !== 'undefined') {
window.FriendListModal = FriendListModal;
// 暴露调试方法
window.debugFriendList = () => {
if (window.friendToggle && window.friendToggle.friendListModal) {
window.friendToggle.friendListModal.debugCheckDuplicates();
} else {
console.warn('好友组件未初始化');
}
};
}
// 支持模块导入
if (typeof module !== 'undefined' && module.exports) {
module.exports = FriendListModal;
}
// 支持 ES6 导入
export default FriendListModal;