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

1370 lines
53 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>