Loading...
\n

Hello World

\n\n', size: 107 } }} }}, 'Downloads': { type: 'dir', children: { 'image.png': { type: 'file', content: '[图片文件数据]', size: 204800 }, 'archive.zip': { type: 'file', content: '[压缩文件数据]', size: 5242880 } }}, 'Pictures': { type: 'dir', children: { 'wallpaper.jpg': { type: 'file', content: '[图片文件数据]', size: 3145728 }, 'screenshot.png': { type: 'file', content: '[截图文件数据]', size: 524288 } }}, 'Music': { type: 'dir', children: { 'song.mp3': { type: 'file', content: '[音频文件数据]', size: 8388608 } }}, '.bashrc': { type: 'file', content: '# Bash配置\nexport PATH="$PATH:/usr/local/bin"\nalias ll="ls -la"\nalias gs="git status"', size: 87 }, '.bash_history': { type: 'file', content: '', size: 0 } } }, '/': { type: 'dir', children: { 'home': { type: 'dir', children: {} }, 'usr': { type: 'dir', children: { 'bin': { type: 'dir', children: {} }, 'lib': { type: 'dir', children: {} } }}, 'etc': { type: 'dir', children: { 'passwd': { type: 'file', content: 'root:x:0:0:root:/root:/bin/bash\nguest:x:1000:1000:Guest User:/home/guest:/bin/bash', size: 98 }, 'hostname': { type: 'file', content: 'openskil', size: 8 } }}, 'var': { type: 'dir', children: { 'log': { type: 'dir', children: { 'syslog': { type: 'file', content: '[系统日志...]', size: 102400 } }} }}, 'tmp': { type: 'dir', children: {} } } } }; let currentDir = '~'; const homeDir = '~'; const rootDir = '/'; const commands = { help: { description: '显示所有可用命令', execute: function(args) { const output = []; output.push({ text: '\n 📚 命令帮助列表\n', class: 'openskil-output-info' }); output.push({ text: ' ═══════════════════════════════════════\n', class: 'openskil-output-muted' }); const cmdList = [ ['help', '显示帮助信息'], ['ls [路径]', '列出目录内容'], ['cd <目录>', '切换目录'], ['pwd', '显示当前目录'], ['cat <文件>', '查看文件内容'], ['echo <文本>', '输出文本'], ['mkdir <目录>', '创建目录'], ['touch <文件>', '创建空文件'], ['rm <目标>', '删除文件或目录'], ['cp <源> <目标>', '复制文件'], ['mv <源> <目标>', '移动/重命名'], ['clear', '清屏'], ['whoami', '显示当前用户'], ['date', '显示日期时间'], ['uname [-a]', '显示系统信息'], ['history', '显示命令历史'], ['neofetch', '显示系统信息'], ['cowsay <文本>', 'ASCII牛说话'], ['fortune', '随机名言'], ['matrix', '黑客帝国效果'], ['calc <表达式>', '简单计算器'], ['base64 -e <文本>', 'Base64编码'], ['base64 -d <文本>', 'Base64解码'], ['rev <文本>', '反转文本'], ['wc <文件>', '统计行数/字数'], ['tree [路径]', '显示目录树'] ]; cmdList.forEach(function(cmd) { output.push({ text: ` ${cmd[0].padEnd(20)} ${cmd[1]}`, class: 'openskil-help-grid' }); }); output.push({ text: '\n ═══════════════════════════════════════\n', class: 'openskil-output-muted' }); return output; } }, ls: { description: '列出目录内容', execute: function(args) { const targetPath = args[0] || currentDir; const resolved = resolvePath(targetPath); if (!resolved) { return [{ text: `ls: 无法访问 '${targetPath}': 目录不存在`, class: 'openskil-output-error' }]; } if (resolved.node.type !== 'dir') { return [{ text: `${getBasename(targetPath)}`, class: 'openskil-file-name' }]; } const children = Object.keys(resolved.node.children); if (children.length === 0) { return [{ text: '(空目录)', class: 'openskil-output-muted' }]; } const showAll = args.includes('-la') || args.includes('-l') || args.includes('-a'); const output = []; children.forEach(function(name) { const node = resolved.node.children[name]; const isDir = node.type === 'dir'; const displayName = isDir ? name + '/' : name; const className = isDir ? 'openskil-dir-name' : 'openskil-file-name'; if (showAll) { const size = node.size || 4096; const sizeStr = formatSize(size).padStart(10); output.push({ text: `drwxr-xr-x 2 guest guest ${sizeStr} ${new Date().toLocaleDateString('zh-CN')} ${displayName.padEnd(20)}`, class: className }); } else { output.push({ text: displayName.padEnd(15), class: className, inline: true }); } }); return output; } }, cd: { description: '切换目录', execute: function(args) { if (!args[0] || args[0] === '~') { currentDir = homeDir; updatePathDisplay(); return []; } if (args[0] === '..') { if (currentDir !== homeDir && currentDir !== '/') { const parts = currentDir.split('/').filter(Boolean); if (currentDir === '~') { currentDir = '~'; } else if (parts.length === 1) { currentDir = '/'; } else { parts.pop(); currentDir = '/' + parts.join('/'); } } updatePathDisplay(); return []; } const resolved = resolvePath(args[0]); if (!resolved) { return [{ text: `cd: ${args[0]}: 目录不存在`, class: 'openskil-output-error' }]; } if (resolved.node.type !== 'dir') { return [{ text: `cd: ${args[0]}: 不是目录`, class: 'openskil-output-error' }]; } currentDir = resolved.path; updatePathDisplay(); return []; } }, pwd: { description: '显示当前目录', execute: function() { const displayPath = currentDir === '~' ? '/home/guest' : (currentDir === '/' ? '/' : currentDir); return [{ text: displayPath, class: 'openskil-output-success' }]; } }, cat: { description: '查看文件内容', execute: function(args) { if (!args[0]) { return [{ text: 'cat: 缺少文件参数', class: 'openskil-output-error' }]; } const resolved = resolvePath(args[0]); if (!resolved) { return [{ text: `cat: ${args[0]}: 文件不存在`, class: 'openskil-output-error' }]; } if (resolved.node.type === 'dir') { return [{ text: `cat: ${args[0]}: 是一个目录`, class: 'openskil-output-error' }]; } return [{ text: resolved.node.content, class: 'openskil-output-success' }]; } }, echo: { description: '输出文本', execute: function(args) { const text = args.join(' '); const parsed = parseEcho(text); return [{ text: parsed, class: 'openskil-output-success' }]; } }, mkdir: { description: '创建目录', execute: function(args) { if (!args[0]) { return [{ text: 'mkdir: 缺少目录参数', class: 'openskil-output-error' }]; } const resolved = resolvePath(currentDir); const dirName = args[0]; if (resolved.node.children[dirName]) { return [{ text: `mkdir: 无法创建目录 '${dirName}': 文件已存在`, class: 'openskil-output-error' }]; } resolved.node.children[dirName] = { type: 'dir', children: {} }; return [{ text: `目录 '${dirName}' 已创建`, class: 'openskil-output-success' }]; } }, touch: { description: '创建空文件', execute: function(args) { if (!args[0]) { return [{ text: 'touch: 缺少文件参数', class: 'openskil-output-error' }]; } const resolved = resolvePath(currentDir); const fileName = args[0]; if (resolved.node.children[fileName]) { return [{ text: `文件 '${fileName}' 已存在`, class: 'openskil-output-muted' }]; } resolved.node.children[fileName] = { type: 'file', content: '', size: 0 }; return [{ text: `文件 '${fileName}' 已创建`, class: 'openskil-output-success' }]; } }, rm: { description: '删除文件或目录', execute: function(args) { if (!args[0]) { return [{ text: 'rm: 缺少目标参数', class: 'openskil-output-error' }]; } const resolved = resolvePath(args[0]); if (!resolved) { return [{ text: `rm: 无法删除 '${args[0]}': 文件不存在`, class: 'openskil-output-error' }]; } const parentResolved = resolvePath(resolved.parentPath); const name = resolved.name; delete parentResolved.node.children[name]; return [{ text: `已删除 '${name}'`, class: 'openskil-output-success' }]; } }, cp: { description: '复制文件', execute: function(args) { if (args.length < 2) { return [{ text: 'cp: 缺少参数 (用法: cp <源文件> <目标文件>)', class: 'openskil-output-error' }]; } const source = resolvePath(args[0]); if (!source) { return [{ text: `cp: 无法复制 '${args[0]}': 文件不存在`, class: 'openskil-output-error' }]; } if (source.node.type === 'dir') { return [{ text: 'cp: 不支持复制目录', class: 'openskil-output-error' }]; } const destResolved = resolvePath(currentDir); const destName = args[1]; destResolved.node.children[destName] = JSON.parse(JSON.stringify(source.node)); return [{ text: `已复制 '${args[0]}' 到 '${destName}'`, class: 'openskil-output-success' }]; } }, mv: { description: '移动/重命名文件', execute: function(args) { if (args.length < 2) { return [{ text: 'mv: 缺少参数 (用法: mv <源> <目标>)', class: 'openskil-output-error' }]; } const source = resolvePath(args[0]); if (!source) { return [{ text: `mv: 无法移动 '${args[0]}': 文件不存在`, class: 'openskil-output-error' }]; } const parentResolved = resolvePath(source.parentPath); const newName = args[1]; parentResolved.node.children[newName] = JSON.parse(JSON.stringify(source.node)); delete parentResolved.node.children[source.name]; return [{ text: `已将 '${args[0]}' 重命名为 '${newName}'`, class: 'openskil-output-success' }]; } }, clear: { description: '清屏', execute: function() { terminalBody.innerHTML = ''; return []; } }, whoami: { description: '显示当前用户', execute: function() { return [{ text: 'guest', class: 'openskil-output-success' }]; } }, date: { description: '显示日期时间', execute: function() { const now = new Date(); const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }; return [{ text: now.toLocaleString('zh-CN', options), class: 'openskil-output-success' }]; } }, uname: { description: '显示系统信息', execute: function(args) { if (args.includes('-a')) { return [{ text: 'Linux openskil 5.15.0-openskil #1 SMP PREEMPT x86_64 GNU/Linux', class: 'openskil-output-success' }]; } return [{ text: 'Linux', class: 'openskil-output-success' }]; } }, history: { description: '显示命令历史', execute: function() { const output = []; commandHistory.forEach(function(cmd, index) { output.push({ text: ` ${String(index + 1).padStart(4)} ${cmd}`, class: 'openskil-output-muted' }); }); if (output.length === 0) { return [{ text: '(无命令历史)', class: 'openskil-output-muted' }]; } return output; } }, neofetch: { description: '显示系统信息', execute: function() { const ascii = ` .--. guest@openskil |o_o | ────────────────────── |:_/ | OS: OpenSKIL Linux // \ \ Host: Web Browser (| | ) Kernel: JavaScript V8 /\_\\_ /_/\ Uptime: ${Math.floor((Date.now() - startTime) / 1000)} secs \___) \__/ Shell: openskil-sh Resolution: ${window.innerWidth}x${window.innerHeight} Terminal: Web Terminal Memory: ${Math.round(performance.memory ? performance.memory.usedJSHeapSize / 1048576 : 50)} MB / ${Math.round(performance.memory ? performance.memory.totalJSHeapSize / 1048576 : 100)} MB `; return [{ text: ascii, class: 'openskil-ascii-art' }]; } }, cowsay: { description: 'ASCII牛说话', execute: function(args) { const text = args.join(' ') || 'Moo!'; const border = '_'.repeat(text.length + 2); const output = ` ${border} < ${text} > ${'-'.repeat(text.length + 2)} \\ ^__^ \\ (oo)\\_______ (__)\\ )\\/\\ ||----w | || ||`; return [{ text: output, class: 'openskil-output-info' }]; } }, fortune: { description: '随机名言', execute: function() { const fortunes = [ '代码是写给人读的,顺便让机器执行。 — Harold Abelson', 'Talk is cheap. Show me the code. — Linus Torvalds', '程序员的三大谎言: 我明天就改,这个bug很简单,不可能发生。', '任何程序一旦部署就立即过时。 — Lehman\'s Law', '调试比编写代码困难一倍。 — Brian Kernighan', '世界上最慢的浏览器就是你刚刚下载的那个。', '一个优秀的程序员是在穿过地狱时不忘笑的人。', '删除代码的是金子,修改代码的是银子,写代码的是铜。', '没有愚蠢的问题,只有愚蠢的回答。', 'JavaScript: 世界上最被误解的编程语言。 — Brendan Eich' ]; return [{ text: fortunes[Math.floor(Math.random() * fortunes.length)], class: 'openskil-output-warning' }]; } }, matrix: { description: '黑客帝国效果', execute: function() { printWelcome(); return []; } }, calc: { description: '简单计算器', execute: function(args) { if (args.length === 0) { return [{ text: 'calc: 缺少表达式 (用法: calc <表达式>)', class: 'openskil-output-error' }]; } try { const expr = args.join(''); const result = Function('return ' + expr.replace(/[^0-9+\-*/().%]/g, ''))(); return [{ text: `${expr} = ${result}`, class: 'openskil-output-success' }]; } catch (e) { return [{ text: `calc: 表达式错误`, class: 'openskil-output-error' }]; } } }, 'base64': { description: 'Base64编码/解码', execute: function(args) { if (args[0] === '-e') { try { const encoded = btoa(args.slice(1).join(' ')); return [{ text: encoded, class: 'openskil-output-success' }]; } catch (e) { return [{ text: 'base64: 编码失败', class: 'openskil-output-error' }]; } } else if (args[0] === '-d') { try { const decoded = atob(args.slice(1).join(' ')); return [{ text: decoded, class: 'openskil-output-success' }]; } catch (e) { return [{ text: 'base64: 解码失败', class: 'openskil-output-error' }]; } } return [{ text: '用法: base64 [-e|-d] <文本>', class: 'openskil-output-error' }]; } }, rev: { description: '反转文本', execute: function(args) { return [{ text: args.join(' ').split('').reverse().join(''), class: 'openskil-output-success' }]; } }, wc: { description: '统计行数/字数', execute: function(args) { if (!args[0]) { return [{ text: 'wc: 缺少文件参数', class: 'openskil-output-error' }]; } const resolved = resolvePath(args[0]); if (!resolved || resolved.node.type !== 'file') { return [{ text: `wc: ${args[0]}: 文件不存在`, class: 'openskil-output-error' }]; } const lines = resolved.node.content.split('\n').length; const words = resolved.node.content.split(/\s+/).filter(Boolean).length; const chars = resolved.node.content.length; return [{ text: `${lines} ${words} ${chars} ${args[0]}`, class: 'openskil-output-muted' }]; } }, tree: { description: '显示目录树', execute: function(args) { const targetPath = args[0] || currentDir; const resolved = resolvePath(targetPath); if (!resolved || resolved.node.type !== 'dir') { return [{ text: `tree: ${args[0] || targetPath}: 目录不存在`, class: 'openskil-output-error' }]; } const output = []; output.push({ text: resolved.path === '~' ? 'home/guest' : resolved.path, class: 'openskil-output-info' }); printTree(resolved.node, '', output, true); return output; } } }; const startTime = Date.now(); function resolvePath(path) { let current = fileSystem['~']; let fullPath = ''; if (path === '~' || path === homeDir) { return { node: fileSystem['~'], path: '~', parentPath: '~', name: '~' }; } let parts; if (path.startsWith('~')) { parts = path.slice(1).split('/').filter(Boolean); current = fileSystem['~']; fullPath = '~'; } else if (path.startsWith('/')) { parts = path.split('/').filter(Boolean); current = fileSystem['/']; fullPath = '/'; } else { parts = currentDir.split('/').filter(Boolean); if (currentDir === '~') { parts = []; current = fileSystem['~']; fullPath = '~'; } else if (currentDir === '/') { parts = []; current = fileSystem['/']; fullPath = '/'; } else { current = fileSystem['~']; fullPath = '~'; currentDir.split('/').filter(Boolean).forEach(function(p) { if (current.children[p]) { current = current.children[p]; fullPath += '/' + p; } }); } parts = path.split('/').filter(Boolean); } for (let i = 0; i < parts.length; i++) { const part = parts[i]; if (part === '..') { const pathParts = fullPath.split('/').filter(Boolean); pathParts.pop(); fullPath = pathParts.length > 0 ? '/' + pathParts.join('/') : (fullPath.startsWith('~') ? '~' : '/'); current = getNodeByPath(fullPath); } else if (part !== '.') { if (current.children && current.children[part]) { current = current.children[part]; fullPath = fullPath === '~' ? '~/' + part : fullPath + '/' + part; fullPath = fullPath.replace(/\/\//g, '/'); } else { return null; } } } const parentParts = fullPath.split('/').filter(Boolean); const name = parentParts.pop() || (fullPath === '~' ? '~' : '/'); const parentPath = parentParts.length > 0 ? (fullPath.startsWith('~') ? '~/' + parentParts.join('/') : '/' + parentParts.join('/')) : (fullPath.startsWith('~') ? '~' : '/'); return { node: current, path: fullPath, parentPath: parentPath, name: name }; } function getNodeByPath(path) { if (path === '~') return fileSystem['~']; if (path === '/') return fileSystem['/']; const parts = path.replace(/^~\/|\/$/g, '').split('/').filter(Boolean); let current = path.startsWith('~') ? fileSystem['~'] : fileSystem['/']; for (const part of parts) { if (current.children && current.children[part]) { current = current.children[part]; } else { return null; } } return current; } function getBasename(path) { return path.split('/').pop() || path; } function formatSize(bytes) { if (bytes < 1024) return bytes + 'B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + 'K'; if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(1) + 'M'; return (bytes / (1024 * 1024 * 1024)).toFixed(1) + 'G'; } function parseEcho(text) { return text.replace(/\$(\w+)/g, function(match, varName) { const vars = { 'USER': 'guest', 'HOME': '/home/guest', 'PWD': currentDir === '~' ? '/home/guest' : currentDir, 'SHELL': '/bin/bash', 'HOSTNAME': 'openskil', 'DATE': new Date().toISOString().split('T')[0], 'TIME': new Date().toTimeString().split(' ')[0] }; return vars[varName] || match; }); } function printTree(node, prefix, output, isLast) { const entries = Object.entries(node.children || {}); entries.forEach(function(entry, index) { const name = entry[0]; const child = entry[1]; const isLastEntry = index === entries.length - 1; const connector = isLastEntry ? '└── ' : '├── '; const childPrefix = prefix + (isLast ? ' ' : '│ '); if (child.type === 'dir') { output.push({ text: prefix + connector + name + '/', class: 'openskil-dir-name', inline: true }); printTree(child, childPrefix, output, isLastEntry); } else { output.push({ text: prefix + connector + name, class: 'openskil-file-name', inline: true }); } }); } function updatePathDisplay() { const displayPath = currentDir === '~' ? '~' : currentDir; currentPathDisplay.textContent = displayPath; } function printWelcome() { const welcome = [ { text: '\n ██████╗ ██████╗ ███████╗███████╗███████╗███████╗', class: 'openskil-output-success' }, { text: ' ██╔══██╗██╔══██╗██╔════╝██╔════╝██╔════╝██╔════╝', class: 'openskil-output-success' }, { text: ' ██████╔╝██████╔╝███████╗█████╗ ███████╗███████╗', class: 'openskil-output-success' }, { text: ' ██╔═══╝ ██╔══██╗╚════██║██╔══╝ ╚════██║╚════██║', class: 'openskil-output-success' }, { text: ' ██║ ██║ ██║███████║███████╗███████║███████║', class: 'openskil-output-success' }, { text: ' ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝╚══════╝', class: 'openskil-output-success' }, { text: '\n 🦋 欢迎来到 OpenSKIL Matrix 世界 🦋\n', class: 'openskil-output-warning' }, { text: ' 记住:代码改变一切,跟随白兔...\n', class: 'openskil-output-muted' } ]; welcome.forEach(function(line) { addOutputLine(line.text, line.class); }); } function addOutputLine(text, className, inline) { const line = document.createElement('div'); line.className = 'openskil-output-line ' + (className || ''); line.textContent = text; if (inline) { line.style.display = 'inline'; } terminalBody.appendChild(line); terminalBody.scrollTop = terminalBody.scrollHeight; } function processCommand(input) { const trimmed = input.trim(); if (!trimmed) return; commandCount++; commandCountDisplay.textContent = commandCount; commandHistory.push(trimmed); historyIndex = commandHistory.length; const promptLine = document.createElement('div'); promptLine.className = 'openskil-output-line'; promptLine.innerHTML = `guest@openskil:${currentDir === '~' ? '~' : currentDir}$ ${escapeHtml(trimmed)}`; terminalBody.appendChild(promptLine); const parts = trimmed.split(/\s+/); const cmd = parts[0].toLowerCase(); const args = parts.slice(1); if (commands[cmd]) { const result = commands[cmd].execute(args); result.forEach(function(item) { if (item.inline) { const inlineLine = document.createElement('span'); inlineLine.className = item.class; inlineLine.textContent = item.text; terminalBody.appendChild(inlineLine); } else { addOutputLine(item.text, item.class); } }); } else if (cmd) { addOutputLine(`bash: ${cmd}: 未找到命令。请输入 'help' 查看所有可用命令。`, 'openskil-output-error'); } terminalBody.scrollTop = terminalBody.scrollHeight; } function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } function getAutocompleteSuggestions(input) { const parts = input.split(/\s+/); if (parts.length === 1) { const cmdPrefix = parts[0].toLowerCase(); return Object.keys(commands).filter(function(cmd) { return cmd.startsWith(cmdPrefix); }); } const cmd = parts[0].toLowerCase(); const lastPart = parts[parts.length - 1]; if (['ls', 'cd', 'cat', 'rm', 'tree', 'wc'].includes(cmd)) { const resolved = resolvePath(currentDir); if (resolved && resolved.node.children) { return Object.keys(resolved.node.children).filter(function(name) { return name.startsWith(lastPart); }); } } return []; } commandInput.addEventListener('keydown', function(e) { if (e.key === 'Enter') { processCommand(commandInput.value); commandInput.value = ''; } else if (e.key === 'ArrowUp') { e.preventDefault(); if (historyIndex > 0) { historyIndex--; commandInput.value = commandHistory[historyIndex]; } } else if (e.key === 'ArrowDown') { e.preventDefault(); if (historyIndex < commandHistory.length - 1) { historyIndex++; commandInput.value = commandHistory[historyIndex]; } else { historyIndex = commandHistory.length; commandInput.value = ''; } } else if (e.key === 'Tab') { e.preventDefault(); const suggestions = getAutocompleteSuggestions(commandInput.value); if (suggestions.length === 1) { const parts = commandInput.value.split(/\s+/); parts[parts.length - 1] = suggestions[0]; commandInput.value = parts.join(' '); } else if (suggestions.length > 1) { addOutputLine(suggestions.join(' '), 'openskil-output-muted'); } } else if (e.key === 'l' && e.ctrlKey) { e.preventDefault(); terminalBody.innerHTML = ''; } else if (e.key === 'c' && e.ctrlKey) { e.preventDefault(); const promptLine = document.createElement('div'); promptLine.className = 'openskil-output-line'; promptLine.innerHTML = `guest@openskil:${currentDir === '~' ? '~' : currentDir}$ ${escapeHtml(commandInput.value)}^C`; terminalBody.appendChild(promptLine); commandInput.value = ''; } }); document.addEventListener('click', function() { commandInput.focus(); }); commandInput.focus(); const initOutput = [ { text: '╔════════════════════════════════════════════════════════════╗', class: 'openskil-output-warning' }, { text: '║ ║', class: 'openskil-output-warning' }, { text: '║ 🖥️ 欢迎使用 OpenSKIL 控制台命令模拟器 🖥️ ║', class: 'openskil-output-warning' }, { text: '║ ║', class: 'openskil-output-warning' }, { text: '║ 这是一个在线终端模拟器,用于学习和练习命令行操作 ║', class: 'openskil-output-warning' }, { text: '║ ║', class: 'openskil-output-warning' }, { text: '╚════════════════════════════════════════════════════════════╝', class: 'openskil-output-warning' }, { text: '', class: '' }, { text: '提示: 输入 help 查看所有可用命令', class: 'openskil-output-muted' }, { text: '', class: '' } ]; initOutput.forEach(function(item) { addOutputLine(item.text, item.class); }); })();
操作面板
工具详情
  • 工具图片:
  • 工具名称: 控制台命令模拟器 - 在线终端
  • 创建时间: Sun Apr 12 2026 21:52:13 GMT+0800 (China Standard Time)
  • 收藏数量: 共0人
  • 点赞数量: 共0次
  • 分享次数: 共0次
  • 访问数量: 共0次
  • 工具版本: v1.0.0
会员评论

主标题

站点所有消息通知及提示Tips内容!