You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

234 lines
6.7 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!DOCTYPE html>
<head>
<title>无痕聊天室</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<!-- ================= 原有样式,未做任何删改 ================= -->
<style>
html, body {
margin: 0;
padding: 0;
height: 100%;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
background: linear-gradient(135deg, #eceff4, #f5f7fa);
}
body.dark { background: #1e1e1e; color: #ccc; }
#chat-container {
display: flex;
flex-direction: column;
height: 100vh;
max-width: 800px;
margin: 0 auto;
background: #ffffffcc;
backdrop-filter: blur(8px);
border-radius: 12px;
overflow: hidden;
position: relative;
}
body.dark #chat-container { background: #2c2c2ccc; }
#chatLog {
flex: 1;
padding: 16px;
overflow-y: auto;
background: #f9f9fb;
display: flex;
flex-direction: column;
gap: 8px;
}
body.dark #chatLog { background: #2a2a2a; }
.message {
max-width: 75%;
padding: 10px 14px;
border-radius: 16px;
font-size: 14px;
line-height: 1.5;
word-wrap: break-word;
white-space: pre-wrap;
}
.self {
align-self: flex-end;
background: linear-gradient(135deg, #409eff, #66b1ff);
color: #fff;
border-bottom-right-radius: 4px;
}
.other {
align-self: flex-start;
background: #e5e5ea;
color: #333;
border-bottom-left-radius: 4px;
}
.system {
align-self: center;
background: transparent;
color: #999;
font-size: 13px;
}
#input-container {
padding: 12px;
background-color: #f4f6f8;
display: flex;
gap: 8px;
border-top: 1px solid #e0e0e0;
align-items: flex-end;
}
#messageInput {
flex: 1;
padding: 10px 14px;
border: 1px solid #ccc;
border-radius: 10px;
resize: none;
min-height: 42px;
}
#sendButton, #uploadButton {
padding: 10px 14px;
border: none;
border-radius: 8px;
cursor: pointer;
background: #409eff;
color: #fff;
}
#onlineCount, #toggleDark, #status {
position: absolute;
font-size: 12px;
padding: 4px 8px;
background: #eef;
border-radius: 12px;
}
#onlineCount { top: 8px; right: 12px; }
#toggleDark { top: 8px; left: 12px; cursor: pointer; }
#status { top: 40px; left: 12px; }
</style>
</head>
<body>
<div id="chat-container">
<div id="toggleDark" onclick="toggleDarkMode()">🌙 夜间</div>
<div id="onlineCount">在线人数0</div>
<div id="status">🟢 已连接</div>
<div id="chatLog"></div>
<div id="input-container">
<textarea id="messageInput" placeholder="来说点什么吧..."></textarea>
<input type="file" id="fileInput" style="display:none">
<button id="uploadButton">📎</button>
<button id="sendButton">发送</button>
</div>
</div>
<script>
/* ================= 用户名 ================= */
let username = localStorage.getItem("chat_username");
if (!username) {
username = prompt("请输入你的昵称:") || "匿名用户";
localStorage.setItem("chat_username", username);
}
/* ================= WebSocket ================= */
let ws;
function connectWS() {
const scheme = location.protocol === "https:" ? "wss" : "ws";
ws = new WebSocket(`${scheme}://${location.host}/ws`);
ws.onopen = () => {
ws.send(username);
setStatus("🟢 已连接");
};
ws.onmessage = e => renderMessage(e.data);
ws.onclose = () => {
setStatus("🔴 断开,重连中...");
setTimeout(connectWS, 2000);
};
}
connectWS();
/* ================= 渲染消息 ================= */
function renderMessage(msg) {
const log = document.getElementById("chatLog");
const div = document.createElement("div");
if (msg.startsWith("COUNT::")) {
document.getElementById("onlineCount").textContent =
"在线人数:" + msg.replace("COUNT::", "");
return;
}
if (msg.startsWith("SYSTEM::")) {
div.className = "message system";
div.textContent = msg.replace("SYSTEM::", "");
}
else if (msg.startsWith("IMG::")) {
div.className = "message other";
const img = document.createElement("img");
img.src = msg.replace("IMG::", "");
img.style.maxWidth = "240px";
img.style.borderRadius = "8px";
div.appendChild(img);
}
else if (msg.startsWith("VIDEO::")) {
div.className = "message other";
const v = document.createElement("video");
v.src = msg.replace("VIDEO::", "");
v.controls = true;
v.style.maxWidth = "260px";
div.appendChild(v);
}
else if (msg.startsWith("TEXT::")) {
const [, sender, text] = msg.split("::", 3);
div.className = "message " + (sender === username ? "self" : "other");
div.textContent = `${sender}${text}`;
}
log.appendChild(div);
log.scrollTop = log.scrollHeight;
}
/* ================= 发送文本 ================= */
document.getElementById("sendButton").onclick = () => {
const input = document.getElementById("messageInput");
if (input.value.trim()) {
ws.send(input.value.trim());
input.value = "";
}
};
/* ================= 上传附件 ================= */
document.getElementById("uploadButton").onclick = () =>
document.getElementById("fileInput").click();
document.getElementById("fileInput").onchange = async () => {
const file = fileInput.files[0];
if (!file) return;
setStatus("📤 上传中...");
const form = new FormData();
form.append("file", file);
const res = await fetch("/upload", { method: "POST", body: form });
const data = await res.json();
if (data.error) alert(data.error);
setStatus("🟢 已连接");
fileInput.value = "";
};
/* ================= UI ================= */
function toggleDarkMode() {
document.body.classList.toggle("dark");
}
function setStatus(t) {
document.getElementById("status").textContent = t;
}
</script>
</body>
</html>