Spaces:
Running
Running
| <html lang="zh-CN"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>WeChat Web</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| /* 自定义滚动条 */ | |
| .custom-scrollbar::-webkit-scrollbar { | |
| width: 6px; | |
| } | |
| .custom-scrollbar::-webkit-scrollbar-track { | |
| background: #f1f1f1; | |
| } | |
| .custom-scrollbar::-webkit-scrollbar-thumb { | |
| background: #c1c1c1; | |
| border-radius: 3px; | |
| } | |
| .custom-scrollbar::-webkit-scrollbar-thumb:hover { | |
| background: #a8a8a8; | |
| } | |
| /* 聊天气泡 */ | |
| .message-bubble { | |
| max-width: 70%; | |
| word-wrap: break-word; | |
| } | |
| .message-bubble.sent { | |
| background-color: #95ec69; | |
| border-radius: 8px 0 8px 8px; | |
| } | |
| .message-bubble.received { | |
| background-color: white; | |
| border-radius: 0 8px 8px 8px; | |
| } | |
| /* 动画效果 */ | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .fade-in { | |
| animation: fadeIn 0.3s ease-out forwards; | |
| } | |
| /* 输入框占位符样式 */ | |
| .input-placeholder::placeholder { | |
| color: #999; | |
| font-size: 14px; | |
| } | |
| /* 未读消息小红点 */ | |
| .unread-badge { | |
| position: absolute; | |
| top: -5px; | |
| right: -5px; | |
| width: 16px; | |
| height: 16px; | |
| background-color: #f56c6c; | |
| border-radius: 50%; | |
| color: white; | |
| font-size: 10px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-100 h-screen flex items-center justify-center"> | |
| <div class="container mx-auto shadow-2xl rounded-lg overflow-hidden" style="width: 900px; height: 650px;"> | |
| <div class="flex h-full"> | |
| <!-- 左侧联系人列表 --> | |
| <div class="w-1/3 bg-white border-r border-gray-200 flex flex-col"> | |
| <!-- 顶部搜索栏 --> | |
| <div class="p-3 bg-gray-50 border-b border-gray-200"> | |
| <div class="relative"> | |
| <input type="text" placeholder="搜索" class="w-full py-2 pl-10 pr-4 bg-white rounded-full text-sm focus:outline-none border border-gray-200 input-placeholder"> | |
| <i class="fas fa-search absolute left-3 top-2.5 text-gray-400"></i> | |
| </div> | |
| </div> | |
| <!-- 联系人列表 --> | |
| <div class="flex-1 overflow-y-auto custom-scrollbar" id="contactList"> | |
| <!-- 联系人项将通过JavaScript动态生成 --> | |
| </div> | |
| <!-- 底部导航 --> | |
| <div class="flex justify-around items-center p-2 bg-gray-50 border-t border-gray-200"> | |
| <button class="p-2 text-gray-600 hover:text-green-500 transition-colors"> | |
| <i class="fas fa-comment-alt text-xl"></i> | |
| </button> | |
| <button class="p-2 text-gray-600 hover:text-green-500 transition-colors"> | |
| <i class="fas fa-address-book text-xl"></i> | |
| </button> | |
| <button class="p-2 text-gray-600 hover:text-green-500 transition-colors"> | |
| <i class="fas fa-compass text-xl"></i> | |
| </button> | |
| <button class="p-2 text-gray-600 hover:text-green-500 transition-colors"> | |
| <i class="fas fa-user-circle text-xl"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <!-- 右侧聊天区域 --> | |
| <div class="w-2/3 flex flex-col bg-gray-100"> | |
| <!-- 聊天顶部信息栏 --> | |
| <div class="p-3 bg-gray-50 border-b border-gray-200 flex items-center justify-between"> | |
| <div class="flex items-center"> | |
| <div class="relative"> | |
| <img src="https://randomuser.me/api/portraits/women/12.jpg" alt="头像" class="w-10 h-10 rounded-full"> | |
| <span class="absolute bottom-0 right-0 w-3 h-3 bg-green-500 rounded-full border-2 border-white"></span> | |
| </div> | |
| <div class="ml-3"> | |
| <div class="font-semibold" id="chatTitle">李小红</div> | |
| <div class="text-xs text-gray-500">在线</div> | |
| </div> | |
| </div> | |
| <div class="flex items-center space-x-4"> | |
| <button class="text-gray-600 hover:text-green-500"> | |
| <i class="fas fa-phone-alt"></i> | |
| </button> | |
| <button class="text-gray-600 hover:text-green-500"> | |
| <i class="fas fa-video"></i> | |
| </button> | |
| <button class="text-gray-600 hover:text-green-500"> | |
| <i class="fas fa-search"></i> | |
| </button> | |
| <button class="text-gray-600 hover:text-green-500"> | |
| <i class="fas fa-ellipsis-v"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <!-- 聊天消息区域 --> | |
| <div class="flex-1 p-4 overflow-y-auto custom-scrollbar bg-gray-50" id="messageArea"> | |
| <!-- 时间分隔线 --> | |
| <div class="flex items-center justify-center my-4"> | |
| <div class="h-px bg-gray-300 flex-1"></div> | |
| <span class="px-2 text-xs text-gray-500 bg-gray-50 rounded-full">今天</span> | |
| <div class="h-px bg-gray-300 flex-1"></div> | |
| </div> | |
| <!-- 消息将通过JavaScript动态生成 --> | |
| </div> | |
| <!-- 底部输入区域 --> | |
| <div class="p-3 bg-white border-t border-gray-200"> | |
| <!-- 工具栏 --> | |
| <div class="flex items-center justify-between mb-2"> | |
| <div class="flex space-x-3"> | |
| <button class="text-gray-500 hover:text-green-500"> | |
| <i class="far fa-smile"></i> | |
| </button> | |
| <button class="text-gray-500 hover:text-green-500"> | |
| <i class="fas fa-paperclip"></i> | |
| </button> | |
| <button class="text-gray-500 hover:text-green-500"> | |
| <i class="fas fa-image"></i> | |
| </button> | |
| <button class="text-gray-500 hover:text-green-500"> | |
| <i class="fas fa-camera"></i> | |
| </button> | |
| </div> | |
| <button class="text-gray-500 hover:text-green-500"> | |
| <i class="fas fa-ellipsis-h"></i> | |
| </button> | |
| </div> | |
| <!-- 输入框 --> | |
| <div class="relative"> | |
| <textarea id="messageInput" placeholder="输入消息" class="w-full p-3 border border-gray-200 rounded-lg focus:outline-none focus:border-green-400 resize-none input-placeholder" rows="2" style="min-height: 40px;"></textarea> | |
| <button id="sendButton" class="absolute right-3 bottom-3 text-gray-400 hover:text-green-500"> | |
| <i class="fas fa-paper-plane"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // 模拟联系人数据 | |
| const contacts = [ | |
| { | |
| id: 1, | |
| name: '李小红', | |
| avatar: 'https://randomuser.me/api/portraits/women/12.jpg', | |
| lastMessage: '好的,明天见!', | |
| time: '12:30', | |
| unread: 3, | |
| online: true | |
| }, | |
| { | |
| id: 2, | |
| name: '张小明', | |
| avatar: 'https://randomuser.me/api/portraits/men/32.jpg', | |
| lastMessage: '项目文档我已经发给你了', | |
| time: '昨天', | |
| unread: 0, | |
| online: false | |
| }, | |
| { | |
| id: 3, | |
| name: '王丽丽', | |
| avatar: 'https://randomuser.me/api/portraits/women/44.jpg', | |
| lastMessage: '周末一起去爬山吗?', | |
| time: '昨天', | |
| unread: 1, | |
| online: true | |
| }, | |
| { | |
| id: 4, | |
| name: '技术交流群', | |
| avatar: 'https://randomuser.me/api/portraits/lego/3.jpg', | |
| lastMessage: '张三: 这个问题可以这样解决...', | |
| time: '周一', | |
| unread: 5, | |
| online: false | |
| }, | |
| { | |
| id: 5, | |
| name: '赵老师', | |
| avatar: 'https://randomuser.me/api/portraits/men/22.jpg', | |
| lastMessage: '作业记得按时提交', | |
| time: '周日', | |
| unread: 0, | |
| online: false | |
| }, | |
| { | |
| id: 6, | |
| name: '刘阿姨', | |
| avatar: 'https://randomuser.me/api/portraits/women/65.jpg', | |
| lastMessage: '谢谢你的帮助!', | |
| time: '上周', | |
| unread: 0, | |
| online: false | |
| } | |
| ]; | |
| // 模拟消息数据 | |
| const messages = { | |
| 1: [ | |
| { | |
| id: 1, | |
| sender: 'other', | |
| content: '嗨,最近怎么样?', | |
| time: '12:20' | |
| }, | |
| { | |
| id: 2, | |
| sender: 'me', | |
| content: '还不错,你呢?', | |
| time: '12:22' | |
| }, | |
| { | |
| id: 3, | |
| sender: 'other', | |
| content: '我也挺好的,明天有空一起吃饭吗?', | |
| time: '12:25' | |
| }, | |
| { | |
| id: 4, | |
| sender: 'me', | |
| content: '好啊,几点?在哪里?', | |
| time: '12:27' | |
| }, | |
| { | |
| id: 5, | |
| sender: 'other', | |
| content: '晚上6点,老地方见吧', | |
| time: '12:28' | |
| }, | |
| { | |
| id: 6, | |
| sender: 'me', | |
| content: '没问题,明天见!', | |
| time: '12:29' | |
| }, | |
| { | |
| id: 7, | |
| sender: 'other', | |
| content: '好的,明天见!', | |
| time: '12:30' | |
| } | |
| ], | |
| 2: [ | |
| { | |
| id: 1, | |
| sender: 'other', | |
| content: '项目文档我已经发给你了', | |
| time: '昨天 15:30' | |
| }, | |
| { | |
| id: 2, | |
| sender: 'me', | |
| content: '收到了,我看看', | |
| time: '昨天 15:35' | |
| }, | |
| { | |
| id: 3, | |
| sender: 'other', | |
| content: '有什么问题随时问我', | |
| time: '昨天 15:36' | |
| } | |
| ], | |
| 3: [ | |
| { | |
| id: 1, | |
| sender: 'other', | |
| content: '周末一起去爬山吗?', | |
| time: '昨天 10:20' | |
| } | |
| ] | |
| }; | |
| // 当前选中的联系人ID | |
| let currentContactId = 1; | |
| // 渲染联系人列表 | |
| function renderContacts() { | |
| const contactList = document.getElementById('contactList'); | |
| contactList.innerHTML = ''; | |
| contacts.forEach(contact => { | |
| const contactItem = document.createElement('div'); | |
| contactItem.className = `flex items-center p-3 border-b border-gray-100 cursor-pointer hover:bg-gray-50 ${contact.id === currentContactId ? 'bg-gray-100' : ''}`; | |
| contactItem.dataset.id = contact.id; | |
| contactItem.innerHTML = ` | |
| <div class="relative"> | |
| <img src="${contact.avatar}" alt="头像" class="w-12 h-12 rounded-full"> | |
| ${contact.online ? '<span class="absolute bottom-0 right-0 w-3 h-3 bg-green-500 rounded-full border-2 border-white"></span>' : ''} | |
| </div> | |
| <div class="ml-3 flex-1"> | |
| <div class="flex justify-between items-center"> | |
| <div class="font-semibold">${contact.name}</div> | |
| <div class="text-xs text-gray-500">${contact.time}</div> | |
| </div> | |
| <div class="text-sm text-gray-500 truncate">${contact.lastMessage}</div> | |
| </div> | |
| ${contact.unread > 0 ? `<div class="unread-badge">${contact.unread}</div>` : ''} | |
| `; | |
| contactItem.addEventListener('click', () => { | |
| currentContactId = contact.id; | |
| renderContacts(); | |
| renderMessages(); | |
| document.getElementById('chatTitle').textContent = contact.name; | |
| // 清除未读消息 | |
| if (contact.unread > 0) { | |
| contact.unread = 0; | |
| renderContacts(); | |
| } | |
| }); | |
| contactList.appendChild(contactItem); | |
| }); | |
| } | |
| // 渲染消息列表 | |
| function renderMessages() { | |
| const messageArea = document.getElementById('messageArea'); | |
| const currentMessages = messages[currentContactId] || []; | |
| // 清空消息区域 | |
| messageArea.innerHTML = ''; | |
| // 添加时间分隔线 | |
| const timeDivider = document.createElement('div'); | |
| timeDivider.className = 'flex items-center justify-center my-4'; | |
| timeDivider.innerHTML = ` | |
| <div class="h-px bg-gray-300 flex-1"></div> | |
| <span class="px-2 text-xs text-gray-500 bg-gray-50 rounded-full">今天</span> | |
| <div class="h-px bg-gray-300 flex-1"></div> | |
| `; | |
| messageArea.appendChild(timeDivider); | |
| // 添加消息 | |
| currentMessages.forEach(message => { | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = `fade-in mb-3 flex ${message.sender === 'me' ? 'justify-end' : 'justify-start'}`; | |
| if (message.sender === 'me') { | |
| messageDiv.innerHTML = ` | |
| <div class="message-bubble sent px-4 py-2 text-sm"> | |
| ${message.content} | |
| <div class="text-right mt-1 text-xs text-gray-600">${message.time}</div> | |
| </div> | |
| `; | |
| } else { | |
| const contact = contacts.find(c => c.id === currentContactId); | |
| messageDiv.innerHTML = ` | |
| <img src="${contact.avatar}" alt="头像" class="w-8 h-8 rounded-full mr-2 self-end"> | |
| <div class="message-bubble received px-4 py-2 text-sm"> | |
| ${message.content} | |
| <div class="text-right mt-1 text-xs text-gray-600">${message.time}</div> | |
| </div> | |
| `; | |
| } | |
| messageArea.appendChild(messageDiv); | |
| }); | |
| // 滚动到底部 | |
| messageArea.scrollTop = messageArea.scrollHeight; | |
| } | |
| // 发送消息 | |
| function sendMessage() { | |
| const input = document.getElementById('messageInput'); | |
| const content = input.value.trim(); | |
| if (content) { | |
| // 获取当前时间 | |
| const now = new Date(); | |
| const hours = now.getHours().toString().padStart(2, '0'); | |
| const minutes = now.getMinutes().toString().padStart(2, '0'); | |
| const timeStr = `${hours}:${minutes}`; | |
| // 创建新消息 | |
| const newMessage = { | |
| id: Date.now(), | |
| sender: 'me', | |
| content: content, | |
| time: timeStr | |
| }; | |
| // 添加到消息列表 | |
| if (!messages[currentContactId]) { | |
| messages[currentContactId] = []; | |
| } | |
| messages[currentContactId].push(newMessage); | |
| // 清空输入框 | |
| input.value = ''; | |
| // 重新渲染消息 | |
| renderMessages(); | |
| // 模拟回复 | |
| setTimeout(() => { | |
| const contact = contacts.find(c => c.id === currentContactId); | |
| const replyMessage = { | |
| id: Date.now(), | |
| sender: 'other', | |
| content: getRandomReply(), | |
| time: `${hours}:${(now.getMinutes() + 1).toString().padStart(2, '0')}` | |
| }; | |
| messages[currentContactId].push(replyMessage); | |
| renderMessages(); | |
| // 更新联系人列表的最后消息 | |
| contact.lastMessage = replyMessage.content; | |
| contact.time = timeStr; | |
| renderContacts(); | |
| }, 1000 + Math.random() * 2000); | |
| } | |
| } | |
| // 随机回复 | |
| function getRandomReply() { | |
| const replies = [ | |
| '好的', | |
| '明白了', | |
| '谢谢', | |
| '我知道了', | |
| '没问题', | |
| '稍等', | |
| '正在处理', | |
| '一会回复你', | |
| '这个主意不错', | |
| '可以', | |
| '不行', | |
| '让我想想', | |
| '明天再说吧', | |
| '周末有空吗?', | |
| '最近怎么样?' | |
| ]; | |
| return replies[Math.floor(Math.random() * replies.length)]; | |
| } | |
| // 初始化 | |
| renderContacts(); | |
| renderMessages(); | |
| // 事件监听 | |
| document.getElementById('sendButton').addEventListener('click', sendMessage); | |
| document.getElementById('messageInput').addEventListener('keypress', function(e) { | |
| if (e.key === 'Enter' && !e.shiftKey) { | |
| e.preventDefault(); | |
| sendMessage(); | |
| } | |
| }); | |
| // 输入框自动调整高度 | |
| document.getElementById('messageInput').addEventListener('input', function() { | |
| this.style.height = 'auto'; | |
| this.style.height = (this.scrollHeight) + 'px'; | |
| }); | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=cogobim591/mm" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |