/** * UI 生成函数 */ import { getContext } from '../../../extensions.js'; import { extensionName, getSettings } from './config.js'; import { getCurrentTime, formatChatTime, escapeHtml } from './utils.js'; const GROUP_CHAT_MAX_AI_MEMBERS = 3; function getLastRenderableMessage(chatHistory) { const history = Array.isArray(chatHistory) ? chatHistory : []; for (let i = history.length - 1; i >= 0; i--) { const msg = history[i]; if (!msg) continue; if (msg.isVoiceCallMessage === true || msg.isVideoCallMessage === true) continue; if (msg.isMarker === true) continue; if (msg.isRecalled === true && (!msg.content || !msg.content.toString().trim())) continue; return msg; } return null; } // 获取用户头像HTML export function getUserAvatarHTML() { const settings = getSettings(); const context = getContext(); const userName = context?.name1 || 'User'; const firstChar = userName.charAt(0); if (settings.userAvatar) { return ``; } const userAvatar = context?.user_avatar; if (userAvatar) { const avatarPaths = [ `/User Avatars/${userAvatar}`, `/characters/${userAvatar}`, userAvatar ]; return ``; } const stPersona = getUserPersonaFromST(); if (stPersona?.avatar) { return ``; } return firstChar; } // 从酒馆获取用户设定 export function getUserPersonaFromST() { try { let name = ''; let description = ''; let avatar = ''; const context = getContext(); if (context) { name = context.name1 || ''; avatar = context.user_avatar || ''; } if (!name && typeof name1 !== 'undefined') { name = name1; } if (typeof power_user !== 'undefined') { if (power_user.persona_description) { description = power_user.persona_description; } if (power_user.personas && power_user.default_persona) { const currentPersona = power_user.default_persona; if (power_user.personas[currentPersona]) { description = power_user.personas[currentPersona]; if (!name) name = currentPersona; } } } if (!name && typeof user_avatar !== 'undefined') { name = user_avatar.replace(/\.[^/.]+$/, ''); } if (!description) { const personaDescEl = document.querySelector('#persona_description'); if (personaDescEl && personaDescEl.value) { description = personaDescEl.value; } } if (name || description) { return { name, description, avatar }; } } catch (err) { console.error('[可乐] 获取用户设定失败:', err); } return null; } // 生成聊天列表 HTML(包含单聊和群聊) export function generateChatList() { const settings = getSettings(); const contacts = settings.contacts || []; const groupChats = settings.groupChats || []; // 处理单聊 const contactsWithChat = contacts.map((contact, index) => { const chatHistory = contact.chatHistory || []; const lastMsg = getLastRenderableMessage(chatHistory); const lastMsgTime = lastMsg ? (lastMsg.timestamp || new Date(lastMsg.time).getTime() || 0) : 0; const contactId = contact.id || `idx_${index}`; return { type: 'contact', ...contact, id: contactId, originalIndex: index, lastMsg, lastMsgTime }; }).filter(c => c.lastMsg); // 处理群聊 const groupsWithChat = groupChats.map((group, index) => { const chatHistory = group.chatHistory || []; const lastMsg = getLastRenderableMessage(chatHistory); const lastMsgTime = lastMsg ? (lastMsg.timestamp || group.lastMessageTime || 0) : (group.lastMessageTime || 0); return { type: 'group', ...group, originalIndex: index, lastMsg, lastMsgTime: lastMsgTime || Date.now() }; }); // 合并并排序 const allChats = [...contactsWithChat, ...groupsWithChat].sort((a, b) => b.lastMsgTime - a.lastMsgTime); if (allChats.length === 0) { return `
暂无聊天记录
点击通讯录选择好友开始聊天
`; } return allChats.map(chat => { if (chat.type === 'group') { return generateGroupChatItem(chat, settings); } else { return generateContactChatItem(chat); } }).join(''); } // 生成单聊列表项 function generateContactChatItem(contact) { const lastMsg = contact.lastMsg; let preview = ''; if (lastMsg.type === 'voice' || lastMsg.isVoice) { preview = '[语音]'; } else if (lastMsg.type === 'image' || lastMsg.isImage) { preview = '[图片]'; } else if (lastMsg.type === 'sticker' || lastMsg.isSticker) { preview = '[表情]'; } else { preview = lastMsg.content || ''; // 处理内容中的特殊标签 if (preview.includes('')) { preview = '[表情]'; } else if (preview.includes('') || preview.includes('')) { preview = '[图片]'; } else if (/\[表情[::].+?\]/.test(preview)) { preview = '[表情]'; } else if (/\[语音[::].+?\]/.test(preview)) { preview = '[语音]'; } else if (/\[照片[::].+?\]/.test(preview)) { preview = '[图片]'; } else if (/\[图片[::].+?\]/.test(preview)) { preview = '[图片]'; } else { if (preview.length > 20) preview = preview.substring(0, 20) + '...'; } } const msgTime = contact.lastMsgTime ? formatChatTime(contact.lastMsgTime) : ''; const avatarContent = contact.avatar ? `${contact.name}` : `${contact.name?.charAt(0) || '?'}`; // 未读消息红点 const unreadCount = contact.unreadCount || 0; const badgeHtml = unreadCount > 0 ? `${unreadCount > 99 ? '99+' : unreadCount}` : ''; // 拉黑标识 const blockedBadge = contact.isBlocked === true ? '🚫' : ''; return `
${avatarContent}
${contact.name || '未知'}${blockedBadge}
${escapeHtml(preview)}
${badgeHtml} ${msgTime}
`; } // 生成群聊列表项 function generateGroupChatItem(group, settings) { const lastMsg = group.lastMsg; let preview = ''; if (lastMsg) { const sender = lastMsg.characterName ? `[${lastMsg.characterName}]: ` : ''; if (lastMsg.isVoice) { preview = `${sender}[语音]`; } else if (lastMsg.isImage) { preview = `${sender}[图片]`; } else if (lastMsg.isSticker) { preview = `${sender}[表情]`; } else { let content = lastMsg.content || ''; // 处理内容中的特殊标签 if (content.includes('')) { content = '[表情]'; } else if (content.includes('') || content.includes('')) { content = '[图片]'; } else if (/\[表情[::].+?\]/.test(content)) { content = '[表情]'; } else if (/\[语音[::].+?\]/.test(content)) { content = '[语音]'; } else if (/\[照片[::].+?\]/.test(content)) { content = '[图片]'; } else if (/\[图片[::].+?\]/.test(content)) { content = '[图片]'; } else { if (content.length > 15) content = content.substring(0, 15) + '...'; } preview = `${sender}${content}`; } } else { preview = '群聊已创建'; } const msgTime = group.lastMsgTime ? formatChatTime(group.lastMsgTime) : ''; // 生成群头像(九宫格) const memberIds = group.memberIds || []; const groupMemberCount = Math.min(memberIds.length, GROUP_CHAT_MAX_AI_MEMBERS) + 1; // +1:包含用户自己 const contactMembers = memberIds.map(id => settings.contacts?.find(c => c.id === id)).filter(Boolean); const members = [{ __isUser: true }, ...contactMembers].slice(0, 4); let avatarHtml = ''; if (members.length === 1 && members[0].__isUser) { avatarHtml = getUserAvatarHTML(); } else if (members.length === 0) { avatarHtml = `👥`; } else if (members.length === 1) { const m = members[0]; avatarHtml = m.avatar ? `` : `${m.name?.charAt(0) || '?'}`; } else { // 九宫格布局 const gridSize = members.length <= 4 ? 2 : 3; const itemSize = Math.floor(44 / gridSize) - 2; avatarHtml = `
`; members.forEach(m => { if (m.__isUser) { const userAvatar = getUserAvatarHTML(); const isImg = typeof userAvatar === 'string' && userAvatar.trim().startsWith('${userAvatar}
`; } else { avatarHtml += `
${escapeHtml((userAvatar || '我').toString().trim().charAt(0) || '我')}
`; } return; } if (m.avatar) { avatarHtml += `
`; } else { avatarHtml += `
${m.name?.charAt(0) || '?'}
`; } }); avatarHtml += ``; } return `
${avatarHtml}
群聊(${groupMemberCount})
${escapeHtml(preview)}
${msgTime}
`; } // 生成联系人列表 HTML export function generateContactsList() { const settings = getSettings(); const contacts = settings.contacts || []; const groupChats = settings.groupChats || []; if (contacts.length === 0 && groupChats.length === 0) { return `
暂无聊天
点击右上角 + 导入角色卡
`; } let html = '
'; // 生成群聊卡片 groupChats.forEach((group, index) => { const memberIds = group.memberIds || []; const groupMemberCount = Math.min(memberIds.length, GROUP_CHAT_MAX_AI_MEMBERS) + 1; // +1:包含用户自己 const contactMembers = memberIds.map(id => settings.contacts?.find(c => c.id === id)).filter(Boolean); const members = [{ __isUser: true }, ...contactMembers].slice(0, 4); let avatarHtml = ''; if (members.length === 1 && members[0].__isUser) { const userAvatar = getUserAvatarHTML(); const isImg = typeof userAvatar === 'string' && userAvatar.trim().startsWith('${escapeHtml((userAvatar || '我').toString().trim().charAt(0) || '我')}
`; } else if (members.length === 0) { avatarHtml = `
👥
`; } else if (members.length === 1) { const m = members[0]; avatarHtml = m.avatar ? `` : ''; avatarHtml += `
${m.name?.charAt(0) || '?'}
`; } else { // 九宫格头像 const gridSize = members.length <= 4 ? 2 : 3; const itemSize = Math.floor(50 / gridSize) - 2; avatarHtml = `
`; members.forEach(m => { if (m.__isUser) { const userAvatar = getUserAvatarHTML(); const isImg = typeof userAvatar === 'string' && userAvatar.trim().startsWith('${userAvatar}
`; } else { avatarHtml += `
${escapeHtml((userAvatar || '我').toString().trim().charAt(0) || '我')}
`; } return; } if (m.avatar) { avatarHtml += `
`; } else { avatarHtml += `
${m.name?.charAt(0) || '?'}
`; } }); avatarHtml += ``; } html += `
${avatarHtml}
群聊(${groupMemberCount})
删除
`; }); // 生成联系人卡片 contacts.forEach((contact, index) => { const firstChar = contact.name ? contact.name.charAt(0) : '?'; const avatarContent = contact.avatar ? `` : ''; html += `
${avatarContent}
${firstChar}
${contact.name}
删除
`; }); html += ''; return html; } // 刷新聊天列表 export function refreshChatList() { const chatListEl = document.getElementById('wechat-chat-list'); if (chatListEl) { chatListEl.innerHTML = generateChatList(); } // 更新底部导航栏红点 updateTabBadge(); } // 更新底部导航栏微信tab的红点 export function updateTabBadge() { const settings = getSettings(); const contacts = settings.contacts || []; // 计算总未读数 let totalUnread = 0; contacts.forEach(contact => { totalUnread += contact.unreadCount || 0; }); // 更新所有页面的微信tab badge const badges = document.querySelectorAll('.wechat-tab[data-tab="chat"] .wechat-tab-badge'); badges.forEach(badge => { if (totalUnread > 0) { badge.textContent = totalUnread > 99 ? '99+' : totalUnread; } else { badge.textContent = ''; } }); } // 导出到 window 供跨模块调用 window.wechatRefreshChatList = refreshChatList; window.wechatUpdateTabBadge = updateTabBadge; // 更新"我"页面用户信息 export function updateMePageInfo() { try { const context = getContext(); if (context) { const userName = context.name1 || 'User'; const nameEl = document.getElementById('wechat-me-name'); const avatarEl = document.getElementById('wechat-me-avatar'); if (nameEl) nameEl.textContent = userName; if (avatarEl) { avatarEl.innerHTML = getUserAvatarHTML(); } } } catch (err) { console.error('[可乐] 更新用户信息失败:', err); } } // 切换页面显示 export function showPage(pageId) { ['wechat-main-content', 'wechat-add-page', 'wechat-chat-page', 'wechat-settings-page', 'wechat-me-page', 'wechat-favorites-page', 'wechat-service-page', 'wechat-discover-page'].forEach(id => { const el = document.getElementById(id); if (el) { el.classList.toggle('hidden', id !== pageId); } }); if (pageId === 'wechat-me-page') { updateMePageInfo(); } if (pageId === 'wechat-favorites-page') { // refreshFavoritesList 会在 favorites.js 中导出 import('./favorites.js').then(m => m.refreshFavoritesList()); } if (pageId === 'wechat-service-page') { const settings = getSettings(); const amountEl = document.getElementById('wechat-wallet-amount'); if (amountEl) { const amount = settings.walletAmount || '5773.89'; amountEl.textContent = amount.startsWith('¥') ? amount : `¥${amount}`; } } }