LLM-test/test/code/4/glm-4.7.html

1370 lines
53 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>CYBER-OS | 赛博朋克未来都市操作系统</title>
<!-- 字体引入 -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;700;900&family=Roboto+Mono:wght@300;400;500&family=Share+Tech+Mono&display=swap" rel="stylesheet">
<!-- 图标库 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- 动画库 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>
<style>
/* =========================================
CSS 变量与基础重置
========================================= */
:root {
--neon-blue: #00f3ff;
--neon-pink: #ff00ff;
--neon-purple: #bc13fe;
--neon-green: #0aff0a;
--bg-dark: #050510;
--glass-bg: rgba(10, 15, 30, 0.65);
--glass-border: rgba(0, 243, 255, 0.3);
--text-main: #e0e0e0;
--font-head: 'Orbitron', sans-serif;
--font-code: 'Roboto Mono', monospace;
--font-ui: 'Share Tech Mono', monospace;
--shadow-glow: 0 0 10px rgba(0, 243, 255, 0.5), 0 0 20px rgba(0, 243, 255, 0.3);
--scanline-color: rgba(0, 0, 0, 0.5);
}
* {
box-sizing: border-box;
user-select: none; /* 防止文本被意外选中提升OS质感 */
scrollbar-width: thin;
scrollbar-color: var(--neon-blue) var(--bg-dark);
}
body, html {
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
overflow: hidden;
background-color: var(--bg-dark);
font-family: var(--font-ui);
color: var(--text-main);
cursor: crosshair; /* 赛博风格光标 */
}
/* 滚动条样式 */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: var(--bg-dark); }
::-webkit-scrollbar-thumb { background: var(--neon-blue); border-radius: 3px; }
/* 扫描线特效层 */
.scanlines {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(
to bottom,
rgba(255,255,255,0),
rgba(255,255,255,0) 50%,
rgba(0,0,0,0.2) 50%,
rgba(0,0,0,0.2)
);
background-size: 100% 4px;
pointer-events: none;
z-index: 9999;
opacity: 0.3;
}
/* =========================================
开机动画
========================================= */
#boot-screen {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #000;
z-index: 10000;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-family: var(--font-code);
color: var(--neon-green);
}
.boot-text {
font-size: 1.2rem;
margin-bottom: 10px;
text-shadow: 0 0 5px var(--neon-green);
}
.loader-bar {
width: 300px;
height: 4px;
background: #111;
margin-top: 20px;
position: relative;
}
.loader-progress {
width: 0%;
height: 100%;
background: var(--neon-green);
box-shadow: 0 0 10px var(--neon-green);
transition: width 0.1s linear;
}
/* =========================================
锁屏界面
========================================= */
#lock-screen {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(5, 5, 16, 0.9);
backdrop-filter: blur(15px);
z-index: 9000;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
transition: opacity 0.5s ease;
}
.lock-time {
font-family: var(--font-head);
font-size: 6rem;
color: #fff;
text-shadow: 0 0 20px var(--neon-purple);
letter-spacing: 4px;
}
.lock-date {
font-size: 1.5rem;
color: var(--neon-blue);
margin-bottom: 40px;
}
.lock-hint {
color: rgba(255,255,255,0.5);
font-size: 0.9rem;
animation: pulse 2s infinite;
}
@keyframes pulse { 0% { opacity: 0.3; } 50% { opacity: 1; } 100% { opacity: 0.3; } }
/* =========================================
桌面环境
========================================= */
#desktop {
position: relative;
width: 100%;
height: calc(100vh - 48px); /* 减去任务栏高度 */
background-image: url('https://picsum.photos/seed/cyberpunkcity/1920/1080');
background-size: cover;
background-position: center;
overflow: hidden;
}
/* 动态背景层 */
#bg-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0.4;
z-index: 0;
}
/* 桌面图标网格 */
#desktop-icons {
position: absolute;
top: 20px;
left: 20px;
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 90%;
width: 100px;
gap: 20px;
z-index: 10;
}
.desktop-icon {
width: 80px;
display: flex;
flex-direction: column;
align-items: center;
cursor: pointer;
padding: 10px;
border-radius: 8px;
transition: all 0.3s ease;
text-shadow: 0 0 5px #000;
}
.desktop-icon:hover {
background: rgba(255, 255, 255, 0.1);
box-shadow: inset 0 0 10px var(--neon-blue);
}
.desktop-icon i {
font-size: 2.5rem;
margin-bottom: 8px;
filter: drop-shadow(0 0 5px currentColor);
}
.desktop-icon span {
font-size: 0.8rem;
text-align: center;
color: #fff;
word-break: break-word;
}
/* 小部件区域 */
#widgets-area {
position: absolute;
top: 20px;
right: 20px;
width: 250px;
display: flex;
flex-direction: column;
gap: 15px;
z-index: 5;
}
.widget {
background: rgba(0, 0, 0, 0.5);
border: 1px solid var(--neon-purple);
padding: 15px;
border-radius: 4px;
backdrop-filter: blur(5px);
box-shadow: 0 0 15px rgba(188, 19, 254, 0.2);
}
.widget-clock {
text-align: center;
font-family: var(--font-head);
}
.widget-time { font-size: 2rem; color: var(--neon-blue); }
.widget-date { font-size: 0.9rem; color: #aaa; }
/* =========================================
窗口系统
========================================= */
.window {
position: absolute;
background: var(--glass-bg);
backdrop-filter: blur(12px);
border: 1px solid var(--glass-border);
box-shadow: 0 10px 30px rgba(0,0,0,0.5), 0 0 15px rgba(0, 243, 255, 0.2);
border-radius: 6px;
display: flex;
flex-direction: column;
min-width: 300px;
min-height: 200px;
overflow: hidden;
transition: transform 0.1s, opacity 0.2s;
animation: openWindow 0.3s cubic-bezier(0.18, 0.89, 0.32, 1.28);
}
@keyframes openWindow {
from { transform: scale(0.8); opacity: 0; }
to { transform: scale(1); opacity: 1; }
}
.window-header {
height: 36px;
background: rgba(0, 243, 255, 0.1);
border-bottom: 1px solid var(--glass-border);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 10px;
cursor: grab;
}
.window-header:active { cursor: grabbing; }
.window-title {
font-family: var(--font-head);
font-size: 0.9rem;
color: var(--neon-blue);
text-shadow: 0 0 5px var(--neon-blue);
pointer-events: none;
}
.window-controls {
display: flex;
gap: 8px;
}
.win-btn {
width: 12px;
height: 12px;
border-radius: 50%;
cursor: pointer;
border: none;
transition: all 0.2s;
}
.btn-min { background: #ffbd2e; box-shadow: 0 0 5px #ffbd2e; }
.btn-max { background: #27c93f; box-shadow: 0 0 5px #27c93f; }
.btn-close { background: #ff5f56; box-shadow: 0 0 5px #ff5f56; }
.btn-close:hover { background: #ff0000; transform: scale(1.1); }
.window-content {
flex: 1;
padding: 10px;
overflow: auto;
color: #ddd;
position: relative;
}
/* 调整大小的手柄 */
.resize-handle {
position: absolute;
bottom: 0;
right: 0;
width: 15px;
height: 15px;
cursor: se-resize;
background: linear-gradient(135deg, transparent 50%, var(--neon-blue) 50%);
opacity: 0.5;
}
/* =========================================
任务栏
========================================= */
#taskbar {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 48px;
background: rgba(5, 10, 20, 0.85);
backdrop-filter: blur(20px);
border-top: 1px solid var(--neon-blue);
display: flex;
align-items: center;
z-index: 5000;
padding: 0 10px;
}
.start-btn {
width: 36px;
height: 36px;
background: radial-gradient(circle, var(--neon-purple), transparent);
border: 1px solid var(--neon-purple);
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 15px;
cursor: pointer;
transition: all 0.3s;
}
.start-btn:hover {
box-shadow: 0 0 15px var(--neon-purple);
transform: scale(1.1);
}
.taskbar-apps {
flex: 1;
display: flex;
gap: 5px;
}
.task-item {
padding: 0 15px;
height: 36px;
background: rgba(255,255,255,0.05);
border-bottom: 2px solid transparent;
color: #aaa;
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
transition: all 0.2s;
font-size: 0.8rem;
max-width: 150px;
}
.task-item.active {
background: rgba(0, 243, 255, 0.1);
border-bottom: 2px solid var(--neon-blue);
color: #fff;
text-shadow: 0 0 8px var(--neon-blue);
}
.task-item:hover {
background: rgba(255,255,255,0.1);
}
.tray {
display: flex;
align-items: center;
gap: 15px;
font-size: 0.8rem;
color: var(--neon-blue);
margin-left: 10px;
}
/* =========================================
开始菜单
========================================= */
#start-menu {
position: fixed;
bottom: 55px;
left: 10px;
width: 320px;
background: rgba(10, 15, 30, 0.95);
border: 1px solid var(--neon-blue);
border-radius: 6px;
padding: 15px;
display: none; /* JS控制显示 */
flex-direction: column;
z-index: 5001;
box-shadow: 0 0 20px rgba(0,0,0,0.8);
transform-origin: bottom left;
animation: slideUp 0.2s ease-out;
}
@keyframes slideUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.menu-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
margin-top: 10px;
}
.menu-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 10px;
border-radius: 4px;
cursor: pointer;
transition: background 0.2s;
}
.menu-item:hover { background: rgba(255,255,255,0.1); }
.menu-item i { font-size: 1.5rem; margin-bottom: 5px; color: var(--neon-blue); }
.menu-footer {
margin-top: 15px;
padding-top: 10px;
border-top: 1px solid rgba(255,255,255,0.1);
display: flex;
justify-content: space-between;
align-items: center;
}
.user-info { display: flex; align-items: center; gap: 8px; }
.avatar { width: 30px; height: 30px; border-radius: 50%; border: 1px solid var(--neon-pink); }
.power-btn { color: var(--neon-pink); cursor: pointer; }
/* =========================================
右键菜单
========================================= */
#context-menu {
position: fixed;
width: 180px;
background: rgba(0,0,0,0.9);
border: 1px solid var(--neon-purple);
z-index: 9999;
display: none;
flex-direction: column;
box-shadow: 0 0 10px rgba(188, 19, 254, 0.4);
}
.ctx-item {
padding: 8px 15px;
cursor: pointer;
font-size: 0.85rem;
color: #ddd;
display: flex;
justify-content: space-between;
}
.ctx-item:hover { background: var(--neon-purple); color: #fff; }
.ctx-sep { height: 1px; background: #333; margin: 2px 0; }
/* =========================================
应用特定样式
========================================= */
/* 终端 */
.terminal-app {
background: #0d0d0d;
font-family: var(--font-code);
height: 100%;
padding: 10px;
overflow-y: auto;
color: #0f0;
font-size: 0.9rem;
}
.cmd-line { display: flex; margin-top: 5px; }
.prompt { color: var(--neon-blue); margin-right: 8px; }
.cmd-input {
background: transparent;
border: none;
color: #0f0;
flex: 1;
outline: none;
font-family: var(--font-code);
font-size: 0.9rem;
}
.terminal-output { white-space: pre-wrap; margin-bottom: 10px; }
/* 文件管理器 */
.file-manager { display: flex; height: 100%; }
.file-sidebar { width: 120px; background: rgba(255,255,255,0.05); padding: 10px; border-right: 1px solid #333; }
.file-content { flex: 1; padding: 10px; display: grid; grid-template-columns: repeat(auto-fill, minmax(80px, 1fr)); gap: 10px; align-content: start; }
.file-item { display: flex; flex-direction: column; align-items: center; cursor: pointer; padding: 5px; }
.file-item:hover { background: rgba(255,255,255,0.1); }
.file-icon { font-size: 2rem; color: var(--neon-pink); margin-bottom: 5px; }
/* 系统监控 */
.charts-container { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; height: 100%; }
.chart-box { position: relative; width: 100%; height: 100%; }
/* 音乐播放器 */
.music-player { display: flex; flex-direction: column; align-items: center; height: 100%; justify-content: center; }
.album-art { width: 150px; height: 150px; background: #333; margin-bottom: 20px; border: 2px solid var(--neon-pink); box-shadow: 0 0 20px var(--neon-pink); display: flex; align-items: center; justify-content: center; font-size: 3rem; color: #fff; position: relative; overflow: hidden; }
.track-info { text-align: center; margin-bottom: 15px; }
.track-name { font-size: 1.2rem; color: #fff; text-shadow: 0 0 5px var(--neon-blue); }
.artist { font-size: 0.9rem; color: #aaa; }
.controls { display: flex; gap: 20px; font-size: 1.5rem; margin-bottom: 15px; }
.progress-bar { width: 100%; height: 4px; background: #333; border-radius: 2px; overflow: hidden; margin-bottom: 10px; }
.progress-fill { height: 100%; width: 30%; background: var(--neon-blue); box-shadow: 0 0 10px var(--neon-blue); }
/* 设置中心 */
.settings-form { padding: 20px; }
.setting-row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; border-bottom: 1px solid #333; padding-bottom: 10px; }
.toggle-switch { position: relative; width: 40px; height: 20px; background: #333; border-radius: 10px; cursor: pointer; transition: 0.3s; }
.toggle-switch.active { background: var(--neon-green); }
.toggle-knob { position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; background: #fff; border-radius: 50%; transition: 0.3s; }
.toggle-switch.active .toggle-knob { left: 22px; }
/* 通知 */
#notification-area { position: fixed; top: 20px; right: 20px; display: flex; flex-direction: column; gap: 10px; z-index: 10000; }
.notification { width: 280px; background: rgba(0, 0, 0, 0.85); border-left: 4px solid var(--neon-blue); padding: 15px; backdrop-filter: blur(5px); box-shadow: 0 5px 15px rgba(0,0,0,0.5); transform: translateX(120%); transition: transform 0.3s ease-out; color: #fff; }
.notification.show { transform: translateX(0); }
.notif-title { font-weight: bold; color: var(--neon-blue); margin-bottom: 5px; font-family: var(--font-head); }
/* 移动端适配 */
@media (max-width: 768px) {
.window { width: 100% !important; height: calc(100% - 48px) !important; top: 0 !important; left: 0 !important; border-radius: 0; }
#desktop-icons { flex-direction: row; width: auto; height: auto; overflow-x: auto; top: auto; bottom: 60px; background: rgba(0,0,0,0.5); padding: 10px; border-radius: 15px; }
.widget { display: none; } /* 移动端隐藏桌面小部件 */
#taskbar { padding: 0 5px; }
.window-title { font-size: 0.7rem; }
}
</style>
</head>
<body>
<!-- 扫描线滤镜 -->
<div class="scanlines"></div>
<!-- 通知容器 -->
<div id="notification-area"></div>
<!-- 开机屏幕 -->
<div id="boot-screen">
<div class="boot-text" id="boot-log">INITIALIZING CORE...</div>
<div class="loader-bar"><div class="loader-progress" id="boot-progress"></div></div>
</div>
<!-- 锁屏界面 -->
<div id="lock-screen">
<div class="lock-time" id="lock-clock">00:00</div>
<div class="lock-date" id="lock-date">YYYY-MM-DD</div>
<div class="lock-hint">CLICK TO UNLOCK // 系统就绪</div>
</div>
<!-- 桌面环境 -->
<div id="desktop">
<!-- 背景 Canvas (用于矩阵或粒子效果) -->
<canvas id="bg-canvas"></canvas>
<!-- 桌面小部件 -->
<div id="widgets-area">
<div class="widget widget-clock">
<div class="widget-time" id="widget-time">12:00:00</div>
<div class="widget-date" id="widget-date">2077-10-23</div>
</div>
<div class="widget">
<div style="color: var(--neon-green); font-size: 0.8rem; margin-bottom: 5px;">CPU LOAD</div>
<div style="height: 4px; background: #333;"><div style="width: 45%; height: 100%; background: var(--neon-green);"></div></div>
</div>
</div>
<!-- 桌面图标 -->
<div id="desktop-icons">
<!-- 由 JS 生成 -->
</div>
<!-- 窗口容器 -->
<div id="window-container">
<!-- 动态生成窗口 -->
</div>
<!-- 开始菜单 -->
<div id="start-menu">
<div style="color: #fff; font-family: var(--font-head); padding-bottom: 10px; border-bottom: 1px solid #333;">CYBER-OS</div>
<div class="menu-grid" id="start-menu-grid">
<!-- JS 填充 -->
</div>
<div class="menu-footer">
<div class="user-info">
<img src="https://picsum.photos/seed/cyberuser/50/50" class="avatar" alt="User">
<span style="font-size: 0.8rem;">NetRunner_01</span>
</div>
<div class="power-btn" onclick="location.reload()"><i class="fas fa-power-off"></i></div>
</div>
</div>
</div>
<!-- 任务栏 -->
<div id="taskbar">
<div class="start-btn" id="start-btn">
<i class="fas fa-th-large" style="color: #fff;"></i>
</div>
<div class="taskbar-apps" id="taskbar-apps">
<!-- 任务栏项 -->
</div>
<div class="tray">
<i class="fas fa-wifi"></i>
<i class="fas fa-volume-up"></i>
<span id="tray-time">12:00</span>
</div>
</div>
<!-- 右键菜单 -->
<div id="context-menu">
<div class="ctx-item" onclick="appManager.openApp('terminal')">Terminal</div>
<div class="ctx-item" onclick="appManager.openApp('settings')">Settings</div>
<div class="ctx-sep"></div>
<div class="ctx-item" onclick="location.reload()">Reboot System</div>
<div class="ctx-item" onclick="document.getElementById('boot-screen').style.display='flex';location.reload()">Shutdown</div>
</div>
<!-- JavaScript 逻辑 -->
<script>
/**
* 赛博朋克 OS - 核心逻辑
* 包含:系统状态管理、窗口管理器、应用逻辑、特效渲染
*/
// ================= 系统配置与状态 =================
const SystemConfig = {
themes: ['neon-blue', 'neon-pink', 'matrix-green'],
fileSystem: {
'root': ['home', 'bin', 'etc', 'var'],
'home': ['documents', 'downloads', 'music', 'secret_plan.txt'],
'documents': ['project_omega.doc', 'budget.xls'],
'downloads': ['hack_tool_v2.zip', 'wallpaper.jpg']
},
currentPath: 'root'
};
let zIndexCounter = 100;
let activeWindowId = null;
const fileSystemData = { ...SystemConfig.fileSystem }; // 深拷贝以供操作
// ================= 工具函数 =================
function getEl(id) { return document.getElementById(id); }
function showNotification(title, msg) {
const area = getEl('notification-area');
const notif = document.createElement('div');
notif.className = 'notification';
notif.innerHTML = `<div class="notif-title">${title}</div><div>${msg}</div>`;
area.appendChild(notif);
// 动画
setTimeout(() => notif.classList.add('show'), 10);
setTimeout(() => {
notif.classList.remove('show');
setTimeout(() => notif.remove(), 300);
}, 4000);
}
// ================= 窗口管理器 =================
class WindowManager {
constructor() {
this.windows = {};
this.container = getEl('window-container');
this.taskbar = getEl('taskbar-apps');
}
createWindow(appId, title, contentHtml, width = 500, height = 400) {
const id = 'win_' + Date.now();
zIndexCounter++;
const winEl = document.createElement('div');
winEl.className = 'window';
winEl.id = id;
winEl.style.width = width + 'px';
winEl.style.height = height + 'px';
winEl.style.zIndex = zIndexCounter;
// 初始位置居中
winEl.style.top = (window.innerHeight / 2 - height / 2 - 24) + 'px';
winEl.style.left = (window.innerWidth / 2 - width / 2) + 'px';
winEl.innerHTML = `
<div class="window-header" onmousedown="windowManager.startDrag(event, '${id}')">
<div class="window-title"><i class="${appIcons[appId]}"></i> ${title}</div>
<div class="window-controls">
<button class="win-btn btn-min" onclick="windowManager.minimize('${id}')"></button>
<button class="win-btn btn-max" onclick="windowManager.toggleMaximize('${id}')"></button>
<button class="win-btn btn-close" onclick="windowManager.close('${id}')"></button>
</div>
</div>
<div class="window-content" onclick="windowManager.focus('${id}')">
${contentHtml}
</div>
<div class="resize-handle" onmousedown="windowManager.startResize(event, '${id}')"></div>
`;
this.container.appendChild(winEl);
this.windows[id] = { id, appId, minimized: false, maximized: false, prevRect: null };
this.addToTaskbar(id, appId, title);
this.focus(id);
// 初始化特定应用逻辑
if (appId === 'monitor') initMonitorApp();
if (appId === 'terminal') initTerminalApp(id);
if (appId === 'filemanager') renderFileManager(id);
}
close(id) {
const win = getEl(id);
if (win) {
win.style.opacity = '0';
win.style.transform = 'scale(0.9)';
setTimeout(() => win.remove(), 200);
}
delete this.windows[id];
getEl(id + '_task').remove();
}
focus(id) {
const win = getEl(id);
if (win) {
zIndexCounter++;
win.style.zIndex = zIndexCounter;
activeWindowId = id;
// Update taskbar active state
document.querySelectorAll('.task-item').forEach(t => t.classList.remove('active'));
const taskItem = getEl(id + '_task');
if (taskItem) taskItem.classList.add('active');
}
}
minimize(id) {
const win = getEl(id);
win.style.display = 'none';
this.windows[id].minimized = true;
getEl(id + '_task').classList.remove('active');
}
restore(id) {
const win = getEl(id);
win.style.display = 'flex';
this.windows[id].minimized = false;
this.focus(id);
}
toggleMaximize(id) {
const win = getEl(id);
const state = this.windows[id];
if (state.maximized) {
win.style.top = state.prevRect.top;
win.style.left = state.prevRect.left;
win.style.width = state.prevRect.width;
win.style.height = state.prevRect.height;
state.maximized = false;
} else {
state.prevRect = {
top: win.style.top,
left: win.style.left,
width: win.style.width,
height: win.style.height
};
win.style.top = '0';
win.style.left = '0';
win.style.width = '100%';
win.style.height = 'calc(100vh - 48px)'; // 减去任务栏
state.maximized = true;
}
}
addToTaskbar(id, appId, title) {
const item = document.createElement('div');
item.className = 'task-item active';
item.id = id + '_task';
item.innerHTML = `<i class="${appIcons[appId]}"></i> ${title}`;
item.onclick = () => {
const winState = this.windows[id];
if (winState.minimized) this.restore(id);
else if (activeWindowId === id) this.minimize(id);
else this.focus(id);
};
this.taskbar.appendChild(item);
}
// 拖拽逻辑
startDrag(e, id) {
if (e.target.closest('.window-controls')) return;
e.preventDefault();
const win = getEl(id);
this.focus(id);
let shiftX = e.clientX - win.getBoundingClientRect().left;
let shiftY = e.clientY - win.getBoundingClientRect().top;
const moveAt = (pageX, pageY) => {
// 边界限制
let newLeft = pageX - shiftX;
let newTop = pageY - shiftY;
// 简单限制不让标题栏完全跑出去
if (newTop < 0) newTop = 0;
if (newTop > window.innerHeight - 48) newTop = window.innerHeight - 48;
win.style.left = newLeft + 'px';
win.style.top = newTop + 'px';
};
const onMouseMove = (event) => moveAt(event.clientX, event.clientY);
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', () => {
document.removeEventListener('mousemove', onMouseMove);
}, {once: true});
}
// 调整大小逻辑
startResize(e, id) {
e.preventDefault();
e.stopPropagation();
const win = getEl(id);
const startX = e.clientX;
const startY = e.clientY;
const startWidth = parseInt(document.defaultView.getComputedStyle(win).width, 10);
const startHeight = parseInt(document.defaultView.getComputedStyle(win).height, 10);
const doDrag = (e) => {
win.style.width = (startWidth + e.clientX - startX) + 'px';
win.style.height = (startHeight + e.clientY - startY) + 'px';
}
const stopDrag = () => {
document.documentElement.removeEventListener('mousemove', doDrag, false);
document.documentElement.removeEventListener('mouseup', stopDrag, false);
}
document.documentElement.addEventListener('mousemove', doDrag, false);
document.documentElement.addEventListener('mouseup', stopDrag, false);
}
}
const windowManager = new WindowManager();
// ================= 应用管理器 =================
const appIcons = {
'terminal': 'fas fa-terminal',
'filemanager': 'fas fa-folder-open',
'browser': 'fas fa-globe',
'settings': 'fas fa-cogs',
'music': 'fas fa-music',
'notepad': 'fas fa-sticky-note',
'monitor': 'fas fa-chart-line'
};
const apps = {
'terminal': { title: 'Terminal', width: 600, height: 400 },
'filemanager': { title: 'File Explorer', width: 600, height: 450 },
'browser': { title: 'CyberBrowser', width: 800, height: 600 },
'settings': { title: 'System Settings', width: 400, height: 350 },
'music': { title: 'SynthWave Player', width: 350, height: 400 },
'notepad': { title: 'Data Note', width: 300, height: 400 },
'monitor': { title: 'System Monitor', width: 500, height: 350 }
};
const appManager = {
openApp: (appId) => {
const app = apps[appId];
let content = '';
// 根据应用ID生成内容
switch(appId) {
case 'terminal':
content = `<div class="terminal-app" id="term-${Date.now()}">
<div class="terminal-history">Welcome to Cyber-OS v2.4.0<br>Type 'help' for commands.</div>
<div class="cmd-line">
<span class="prompt">root@cyber:~$</span>
<input type="text" class="cmd-input" onkeydown="handleTerminalCommand(event, this)">
</div>
</div>`;
break;
case 'filemanager':
content = `<div class="file-manager">
<div class="file-sidebar">
<div class="ctx-item" onclick="renderFileManagerContent('${Date.now()}', 'root')">/ Root</div>
<div class="ctx-item">/ Home</div>
<div class="ctx-item">/ Bin</div>
</div>
<div class="file-content" id="fm-content-${Date.now()}">
<!-- JS Populate -->
</div>
</div>`;
break;
case 'browser':
content = `<div style="display:flex; flex-direction:column; height:100%;">
<div style="padding:5px; background:rgba(255,255,255,0.1); display:flex; gap:5px;">
<button>&lt;</button> <button>&gt;</button>
<input type="text" value="https://en.wikipedia.org/wiki/Cyberpunk" style="flex:1; background:#000; border:1px solid #333; color:#fff;">
</div>
<iframe src="https://en.m.wikipedia.org/wiki/Cyberpunk" style="flex:1; border:none; background:#fff;"></iframe>
</div>`;
break;
case 'settings':
content = `<div class="settings-form">
<div class="setting-row">
<span>Neon Glow</span>
<div class="toggle-switch active"><div class="toggle-knob"></div></div>
</div>
<div class="setting-row">
<span>Sound Effects</span>
<div class="toggle-switch active"><div class="toggle-knob"></div></div>
</div>
<div class="setting-row">
<span>Matrix Rain</span>
<div class="toggle-switch" onclick="toggleMatrixBg(this)"><div class="toggle-knob"></div></div>
</div>
<button style="width:100%; padding:10px; background:var(--neon-blue); border:none; font-family:var(--font-head); cursor:pointer;" onclick="showNotification('Settings', 'Configuration Saved')">SAVE CHANGES</button>
</div>`;
break;
case 'music':
content = `<div class="music-player">
<div class="album-art"><i class="fas fa-compact-disc fa-spin"></i></div>
<div class="track-info">
<div class="track-name">Nightcall</div>
<div class="artist">Kavinsky</div>
</div>
<div class="progress-bar"><div class="progress-fill"></div></div>
<div class="controls">
<i class="fas fa-step-backward"></i>
<i class="fas fa-play-circle" style="color:var(--neon-blue);"></i>
<i class="fas fa-step-forward"></i>
</div>
</div>`;
break;
case 'notepad':
const savedNote = localStorage.getItem('cyber_note') || '';
content = `<textarea style="width:100%; height:100%; background:rgba(0,0,0,0.5); border:none; color:#0f0; font-family:var(--font-code); padding:10px; resize:none;" placeholder="Enter data..." oninput="localStorage.setItem('cyber_note', this.value)">${savedNote}</textarea>`;
break;
case 'monitor':
content = `<div class="charts-container">
<div class="chart-box"><canvas id="chart-cpu"></canvas></div>
<div class="chart-box"><canvas id="chart-ram"></canvas></div>
</div>`;
break;
}
windowManager.createWindow(appId, app.title, content, app.width, app.height);
getEl('start-menu').style.display = 'none';
}
};
// ================= 应用逻辑实现 =================
// 1. 终端逻辑
function initTerminalApp(winId) {
// Auto focus
setTimeout(() => {
const input = getEl(winId).querySelector('input');
if(input) input.focus();
}, 100);
}
function handleTerminalCommand(e, input) {
if (e.key === 'Enter') {
const cmd = input.value.trim();
const history = input.parentElement.parentElement.querySelector('.terminal-history');
const output = executeCommand(cmd);
history.innerHTML += `<div><span style="color:var(--neon-blue)">root@cyber:~$</span> ${cmd}</div>${output}`;
history.scrollTop = history.scrollHeight;
input.value = '';
}
}
function executeCommand(cmd) {
const args = cmd.split(' ');
const command = args[0].toLowerCase();
let res = '';
switch(command) {
case 'help': res = `<div style="color:#fff">Available commands:<br>help, clear, date, whoami, ls, cat [file], echo [text], neofetch, matrix, theme [color], reboot</div>`; break;
case 'clear': return ''; // Special handling
case 'date': res = `<div>${new Date().toString()}</div>`; break;
case 'whoami': res = `<div>NetRunner_01 (Root User)</div>`; break;
case 'ls':
case 'dir': res = `<div style="color:var(--neon-pink)">documents downloads music secret_plan.txt</div>`; break;
case 'cat':
case 'type':
if(args[1]) res = `<div>Content of ${args[1]}: [ENCRYPTED DATA]... Access Denied.</div>`;
else res = `<div>Usage: cat [filename]</div>`;
break;
case 'echo': res = `<div>${args.slice(1).join(' ')}</div>`; break;
case 'neofetch':
res = `
<div style="color:var(--neon-blue)">
____ user@cyber-os
| _ \\ _ __ ___ __ __ ___ -------------
| |_) || '__|/ _ \\\\ \\ /\\ / // _ \\ OS: Cyber-OS v2.4
| _ < | | | (_) |\\ V V /| (_) | Kernel: NetKernel 9.0
|_| \\_\\|_| \\___/ \\_/\\_/ \\___/ Shell: CyberBash
Theme: Neon Blue
</div>`;
break;
case 'matrix':
showNotification('Terminal', 'Matrix Protocol Initiated');
toggleMatrixBg(null); // 修复:传递 null 让函数逻辑自动处理
res = `<div>Protocol engaged.</div>`;
break;
case 'theme':
if(args[1]) res = `<div>Theme switched to ${args[1]}</div>`;
else res = `<div>Usage: theme [blue/pink]</div>`;
break;
case 'reboot': location.reload(); break;
case '': break;
default: res = `<div>Command not found: ${command}</div>`;
}
return res;
}
// 2. 文件管理器逻辑
function renderFileManager(winId) {
setTimeout(() => renderFileManagerContent(winId, 'root'), 50);
}
function renderFileManagerContent(winId, path) {
const container = getEl(winId).querySelector('.file-content');
container.innerHTML = '';
// 模拟文件数据
const files = [
{ name: 'secret_plan.txt', icon: 'fa-file-alt' },
{ name: 'virus.exe', icon: 'fa-bug' },
{ name: 'image_data', icon: 'fa-folder' },
{ name: 'sys_config', icon: 'fa-cog' },
{ name: 'music_track.mp3', icon: 'fa-music' },
{ name: 'network_map', icon: 'fa-project-diagram' },
];
files.forEach(f => {
const el = document.createElement('div');
el.className = 'file-item';
el.innerHTML = `<i class="fas ${f.icon} file-icon"></i><span>${f.name}</span>`;
el.ondblclick = () => showNotification('System', `Opening ${f.name}...`);
container.appendChild(el);
});
}
// 3. 系统监控 (Chart.js)
function initMonitorApp() {
// 查找最新的monitor窗口
const cpuCtx = document.getElementById('chart-cpu')?.getContext('2d');
const ramCtx = document.getElementById('chart-ram')?.getContext('2d');
if(!cpuCtx || !ramCtx) return;
// 配置 Chart
Chart.defaults.color = '#888';
Chart.defaults.borderColor = '#333';
const commonOptions = {
responsive: true,
maintainAspectRatio: false,
animation: false,
plugins: { legend: { display: false } },
scales: { x: { display: false }, y: { min: 0, max: 100 } }
};
const createChart = (ctx, color) => new Chart(ctx, {
type: 'line',
data: {
labels: Array(20).fill(''),
datasets: [{
data: Array(20).fill(50),
borderColor: color,
borderWidth: 2,
backgroundColor: color.replace('1)', '0.1)'),
fill: true,
tension: 0.4,
pointRadius: 0
}]
},
options: commonOptions
});
const cpuChart = createChart(cpuCtx, '#00f3ff');
const ramChart = createChart(ramCtx, '#ff00ff');
// 模拟实时数据
setInterval(() => {
if(document.body.contains(cpuCtx.canvas)) {
updateData(cpuChart);
updateData(ramChart);
}
}, 1000);
function updateData(chart) {
const data = chart.data.datasets[0].data;
data.shift();
data.push(Math.floor(Math.random() * 60) + 20);
chart.update();
}
}
// ================= 全局交互与特效 =================
// 开机动画
window.onload = () => {
const progress = getEl('boot-progress');
const log = getEl('boot-log');
let width = 0;
const logs = ["Loading Kernel...", "Mounting Volumes...", "Starting Network...", "Decrypting User Data...", "Welcome to Night City"];
const interval = setInterval(() => {
width += 1;
progress.style.width = width + '%';
if (width % 20 === 0 && width/20 < logs.length) {
log.innerText = logs[width/20];
}
if (width >= 100) {
clearInterval(interval);
setTimeout(() => {
getEl('boot-screen').style.display = 'none';
updateClock();
setInterval(updateClock, 1000);
initBackground();
}, 500);
}
}, 30);
// 生成桌面图标
const iconContainer = getEl('desktop-icons');
const menuGrid = getEl('start-menu-grid');
Object.keys(apps).forEach(key => {
const app = apps[key];
// 桌面图标
const div = document.createElement('div');
div.className = 'desktop-icon';
div.innerHTML = `<i class="${appIcons[key]}" style="color: ${key === 'terminal' ? '#0f0' : (key === 'filemanager' ? 'var(--neon-pink)' : 'var(--neon-blue)')}"></i><span>${app.title}</span>`;
div.onclick = () => appManager.openApp(key);
iconContainer.appendChild(div);
// 开始菜单项
const menuItem = document.createElement('div');
menuItem.className = 'menu-item';
menuItem.innerHTML = `<i class="${appIcons[key]}"></i><span style="font-size:0.7rem">${app.title}</span>`;
menuItem.onclick = () => appManager.openApp(key);
menuGrid.appendChild(menuItem);
});
};
// 时钟更新
function updateClock() {
const now = new Date();
const timeStr = now.toLocaleTimeString('en-GB');
const dateStr = now.toLocaleDateString('zh-CN');
getEl('tray-time').innerText = timeStr;
getEl('widget-time').innerText = timeStr;
getEl('widget-date').innerText = dateStr;
getEl('lock-clock').innerText = timeStr;
getEl('lock-date').innerText = dateStr;
}
// 锁屏逻辑
getEl('lock-screen').addEventListener('click', () => {
getEl('lock-screen').style.opacity = '0';
setTimeout(() => getEl('lock-screen').style.display = 'none', 500);
showNotification('System', 'User Logged In Successfully');
});
// 任务栏开始按钮
getEl('start-btn').onclick = (e) => {
e.stopPropagation();
const menu = getEl('start-menu');
menu.style.display = menu.style.display === 'flex' ? 'none' : 'flex';
};
// 点击任意处关闭开始菜单
document.addEventListener('click', (e) => {
if (!e.target.closest('#start-menu') && !e.target.closest('#start-btn')) {
getEl('start-menu').style.display = 'none';
}
});
// 右键菜单
document.addEventListener('contextmenu', (e) => {
e.preventDefault();
const menu = getEl('context-menu');
menu.style.display = 'flex';
menu.style.left = e.clientX + 'px';
menu.style.top = e.clientY + 'px';
});
document.addEventListener('click', () => getEl('context-menu').style.display = 'none');
// ================= 背景特效 =================
let matrixMode = false;
// 修复后的 toggleMatrixBg 函数
function toggleMatrixBg(el) {
// 如果 el 为 null 或者不是有效的 DOM 元素(例如终端命令调用),则强制开启 Matrix 模式
if (!el || !el.classList || typeof el.classList.contains !== 'function') {
matrixMode = true;
return;
}
// 正常的 UI 点击逻辑
if (el.classList.contains('toggle-switch')) {
el.classList.toggle('active');
matrixMode = el.classList.contains('active');
}
}
function initBackground() {
const canvas = getEl('bg-canvas');
const ctx = canvas.getContext('2d');
let width, height;
function resize() {
width = canvas.width = window.innerWidth;
height = canvas.height = window.innerHeight;
}
window.addEventListener('resize', resize);
resize();
// 粒子系统
const particles = [];
const particleCount = 50;
for(let i=0; i<particleCount; i++) {
particles.push({
x: Math.random() * width,
y: Math.random() * height,
vx: (Math.random() - 0.5) * 0.5,
vy: (Math.random() - 0.5) * 0.5,
size: Math.random() * 2,
color: Math.random() > 0.5 ? '#00f3ff' : '#ff00ff'
});
}
// Matrix Rain 字符
const columns = Math.floor(width / 20);
const drops = Array(columns).fill(1);
const chars = "010101XYCYPUNK<>";
function animate() {
if (matrixMode) {
ctx.fillStyle = 'rgba(0, 0, 0, 0.05)';
ctx.fillRect(0, 0, width, height);
ctx.fillStyle = '#0f0';
ctx.font = '15px monospace';
for (let i = 0; i < drops.length; i++) {
const text = chars[Math.floor(Math.random() * chars.length)];
ctx.fillText(text, i * 20, drops[i] * 20);
if (drops[i] * 20 > height && Math.random() > 0.975) drops[i] = 0;
drops[i]++;
}
} else {
// 默认:赛博星空粒子
ctx.clearRect(0, 0, width, height);
// 绘制网格
ctx.strokeStyle = 'rgba(0, 243, 255, 0.05)';
ctx.lineWidth = 1;
const gridSize = 50;
// 移动网格效果
const time = Date.now() / 1000;
const offsetY = (time * 10) % gridSize;
ctx.beginPath();
for (let x = 0; x <= width; x += gridSize) {
ctx.moveTo(x, 0);
ctx.lineTo(x, height);
}
for (let y = offsetY; y <= height; y += gridSize) {
ctx.moveTo(0, y);
ctx.lineTo(width, y);
}
ctx.stroke();
// 绘制粒子
particles.forEach(p => {
p.x += p.vx;
p.y += p.vy;
if(p.x < 0) p.x = width;
if(p.x > width) p.x = 0;
if(p.y < 0) p.y = height;
if(p.y > height) p.y = 0;
ctx.beginPath();
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
ctx.fillStyle = p.color;
ctx.fill();
// 连线
particles.forEach(p2 => {
const dx = p.x - p2.x;
const dy = p.y - p2.y;
const dist = Math.sqrt(dx*dx + dy*dy);
if(dist < 100) {
ctx.beginPath();
ctx.strokeStyle = `rgba(0, 243, 255, ${0.1 - dist/1000})`;
ctx.moveTo(p.x, p.y);
ctx.lineTo(p2.x, p2.y);
ctx.stroke();
}
});
});
}
requestAnimationFrame(animate);
}
animate();
}
</script>
</body>
</html>