<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TENG YUAN - 智能终端系统</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&family=Inter:wght@300;400;500;600;700&display=swap">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
<style>
:root {
/* 基础变量 */
--transition-fast: 0.2s ease;
--transition-normal: 0.3s ease;
--transition-slow: 0.5s ease;
--border-radius: 20px;
--border-radius-lg: 25px;
--font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
--font-mono: 'JetBrains Mono', 'Consolas', 'Monaco', monospace;
/* 暗色主题变量 */
--bg-primary: #0f172a;
--bg-secondary: #1e293b;
--bg-tertiary: #334155;
--text-primary: #f8fafc;
--text-secondary: #cbd5e1;
--text-tertiary: #94a3b8;
--accent-primary: #6366f1;
--accent-secondary: #8b5cf6;
--accent-hover: #7c3aed;
--border-color: rgba(255, 255, 255, 0.1);
--glass-bg: rgba(15, 23, 42, 0.8);
--glass-border: rgba(255, 255, 255, 0.1);
--shadow-sm: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
--shadow-md: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
/* 起始页变量 */
--startup-bg: #0a0a0a;
--startup-card-bg: rgba(255, 255, 255, 0.04);
--startup-card-hover: rgba(255, 255, 255, 0.08);
--startup-card-border: rgba(255, 255, 255, 0.08);
--startup-search-bg: rgba(255, 255, 255, 0.06);
--startup-search-focus: rgba(255, 255, 255, 0.1);
--startup-icon-bg: rgba(255, 255, 255, 0.08);
--startup-icon-hover: rgba(99, 102, 241, 0.2);
/* 终端变量 */
--editor-bg: #1e1e1e;
--editor-secondary-bg: #252526;
--line-color: #858585;
--text-color: #d4d4d4;
--keyword-color: #569cd6;
--string-color: #ce9178;
--comment-color: #6a9955;
--number-color: #b5cea8;
--function-color: #dcdcaa;
--header-bg: #2d2d2d;
--window-btn-close: #ff5f56;
--window-btn-min: #ffbd2e;
--window-btn-max: #27c93f;
--ai-output-color: #4ec9b0;
--user-input-color: #d7ba7d;
--video-bg: #000000;
--box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
--calendar-today-bg: rgba(10, 132, 255, 0.3);
--calendar-selected-bg: var(--accent-primary);
--weather-temp-high: #ff7e67;
--weather-temp-low: #70c1ff;
--birthday-color: #ff4081;
--birthday-bg: rgba(255, 64, 129, 0.15);
}
/* 亮色主题变量 */
.light-mode {
--bg-primary: #ffffff;
--bg-secondary: #f8fafc;
--bg-tertiary: #e2e8f0;
--text-primary: #1e293b;
--text-secondary: #475569;
--text-tertiary: #64748b;
--accent-primary: #3b82f6;
--accent-secondary: #6366f1;
--accent-hover: #2563eb;
--border-color: rgba(0, 0, 0, 0.1);
--glass-bg: rgba(255, 255, 255, 0.8);
--glass-border: rgba(0, 0, 0, 0.1);
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
/* 起始页变量 */
--startup-bg: #fafbfc;
--startup-card-bg: rgba(255, 255, 255, 0.8);
--startup-card-hover: rgba(255, 255, 255, 0.95);
--startup-card-border: rgba(0, 0, 0, 0.06);
--startup-search-bg: rgba(255, 255, 255, 0.9);
--startup-search-focus: rgba(255, 255, 255, 1);
--startup-icon-bg: rgba(0, 0, 0, 0.04);
--startup-icon-hover: rgba(59, 130, 246, 0.1);
/* 终端变量 */
--editor-bg: #f5f5f5;
--editor-secondary-bg: #ebebeb;
--text-color: #333333;
--keyword-color: #0000ff;
--string-color: #a31515;
--comment-color: #008000;
--number-color: #098658;
--function-color: #795e26;
--header-bg: #e5e5e5;
--ai-output-color: #098658;
--user-input-color: #0000ff;
--video-bg: #f0f0f0;
--box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
--calendar-today-bg: rgba(10, 132, 255, 0.2);
--weather-temp-high: #ff5a3d;
--weather-temp-low: #4a9eff;
--birthday-bg: rgba(255, 64, 129, 0.1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: var(--font-family);
background: linear-gradient(135deg, var(--bg-primary) 0%, var(--bg-secondary) 100%);
color: var(--text-primary);
min-height: 100vh;
transition: all var(--transition-normal);
overflow: hidden;
background-image:
radial-gradient(circle at 10% 20%, rgba(100, 100, 255, 0.03) 0%, transparent 20%),
radial-gradient(circle at 90% 80%, rgba(100, 255, 100, 0.03) 0%, transparent 20%);
background-attachment: fixed;
}
/* ==================== 顶部导航栏样式 ==================== */
.top-nav {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 80px;
background: var(--glass-bg);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-bottom: 1px solid var(--glass-border);
border-radius: 0 0 var(--border-radius) var(--border-radius);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 1.5rem;
z-index: 1000;
box-shadow: var(--shadow-sm);
transition: all var(--transition-normal);
}
/* 左侧Logo */
.nav-logo {
display: flex;
align-items: center;
gap: 0.75rem;
font-size: 1.5rem;
font-weight: 700;
background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
-webkit-background-clip: text;
background-clip: text;
color: transparent;
letter-spacing: -0.02em;
position: relative;
padding: 0.5rem 1rem;
border-radius: var(--border-radius);
transition: all var(--transition-normal);
}
.nav-logo::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: var(--startup-card-bg);
border-radius: var(--border-radius);
z-index: -1;
opacity: 0;
transition: opacity var(--transition-normal);
}
.nav-logo:hover::before {
opacity: 1;
}
.nav-logo i {
color: var(--accent-primary);
background: none;
-webkit-background-clip: unset;
background-clip: unset;
filter: drop-shadow(0 0 5px rgba(99, 102, 241, 0.5));
}
/* 中间导航按钮 */
.nav-tabs {
display: flex;
gap: 0.5rem;
background: var(--startup-card-bg);
border: 1px solid var(--startup-card-border);
border-radius: var(--border-radius-lg);
padding: 0.5rem;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
position: relative;
z-index: 1;
transition: all var(--transition-normal);
}
.nav-tabs::before {
content: '';
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
border-radius: calc(var(--border-radius-lg) + 2px);
z-index: -1;
opacity: 0.3;
filter: blur(5px);
transition: opacity var(--transition-normal);
}
.nav-tabs:hover::before {
opacity: 0.5;
}
.nav-tab {
position: relative;
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1.5rem;
border-radius: calc(var(--border-radius-lg) - 0.25rem);
border: none;
background: transparent;
color: var(--text-secondary);
font-family: inherit;
font-size: 0.9rem;
font-weight: 500;
cursor: pointer;
transition: all var(--transition-normal);
overflow: hidden;
min-width: 120px;
justify-content: center;
}
.nav-tab::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
opacity: 0;
transition: opacity var(--transition-normal);
z-index: -1;
}
.nav-tab:hover {
color: var(--text-primary);
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}
.nav-tab:hover::before {
opacity: 0.1;
}
.nav-tab.active {
color: white;
background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
box-shadow:
var(--shadow-md),
0 0 20px rgba(99, 102, 241, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.2);
transform: translateY(-1px);
}
.nav-tab.active::before {
opacity: 0;
}
.nav-tab i {
font-size: 1rem;
transition: transform var(--transition-normal);
}
.nav-tab:hover i {
transform: scale(1.1);
}
.nav-tab.active i {
filter: drop-shadow(0 0 8px rgba(255, 255, 255, 0.5));
}
/* 右侧控制区域 - 天气和主题切换结合 */
.right-controls {
display: flex;
align-items: center;
gap: 1rem;
}
.weather-theme-widget {
display: flex;
align-items: center;
background: var(--startup-card-bg);
border: 1px solid var(--startup-card-border);
border-radius: var(--border-radius-lg);
padding: 0.5rem;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
transition: all var(--transition-normal);
gap: 0.75rem;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
position: relative;
overflow: hidden;
}
.weather-theme-widget::before {
content: '';
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
border-radius: calc(var(--border-radius-lg) + 2px);
z-index: -1;
opacity: 0.2;
filter: blur(5px);
transition: opacity var(--transition-normal);
}
.weather-theme-widget:hover {
background: var(--startup-card-hover);
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}
.weather-theme-widget:hover::before {
opacity: 0.4;
}
/* 天气信息部分 */
.weather-section {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.25rem 0.75rem;
border-radius: calc(var(--border-radius-lg) - 0.25rem);
cursor: pointer;
transition: all var(--transition-normal);
position: relative;
overflow: hidden;
}
.weather-section::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
transition: left 0.6s ease;
}
.weather-section:hover::before {
left: 100%;
}
.weather-section:hover {
background: var(--startup-icon-hover);
}
.weather-icon {
font-size: 1.25rem;
color: var(--accent-primary);
min-width: 20px;
filter: drop-shadow(0 0 5px rgba(99, 102, 241, 0.5));
}
.weather-info {
display: flex;
flex-direction: column;
line-height: 1.2;
}
.weather-temp {
font-weight: 600;
font-size: 0.85rem;
color: var(--text-primary);
}
.weather-location {
font-size: 0.7rem;
color: var(--text-tertiary);
}
/* 主题切换部分 */
.theme-toggle-container {
position: relative;
width: 60px;
height: 30px;
}
.theme-toggle-input {
display: none;
}
.theme-toggle-label {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--startup-icon-bg);
border: 1px solid var(--startup-card-border);
border-radius: 50px;
cursor: pointer;
transition: all var(--transition-normal);
overflow: hidden;
}
.theme-toggle-label:hover {
transform: scale(1.05);
box-shadow: 0 0 10px rgba(99, 102, 241, 0.3);
}
.theme-toggle-button {
position: absolute;
top: 2px;
left: 2px;
width: 26px;
height: 26px;
background: linear-gradient(145deg, #d1d1d1, #f1f1f1);
border-radius: 50%;
box-shadow: 0 2px 8px rgba(209, 209, 209, 0.4);
transition: all var(--transition-normal);
display: flex;
justify-content: center;
align-items: center;
}
.light-mode .theme-toggle-button {
left: 32px;
background: linear-gradient(145deg, #ffdf6b, #ffb347);
box-shadow: 0 2px 8px rgba(255, 179, 71, 0.4);
}
.sun, .moon {
position: absolute;
width: 14px;
height: 14px;
transition: all var(--transition-normal);
}
.moon {
border-radius: 50%;
background: #f1f1f1;
box-shadow: inset -3px -1px 0 0 #d1d1d1;
opacity: 1;
transform: scale(1);
}
.light-mode .moon {
opacity: 0;
transform: scale(0.5) rotate(90deg);
}
.sun {
border-radius: 50%;
background: #ffdf6b;
box-shadow: 0 0 6px #ffdf6b;
opacity: 0;
transform: scale(0.5);
}
.light-mode .sun {
opacity: 1;
transform: scale(1);
}
/* ==================== 天气详情弹窗 ==================== */
.weather-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
display: none;
justify-content: center;
align-items: center;
z-index: 2000;
opacity: 0;
transition: opacity var(--transition-normal);
}
.weather-modal.show {
display: flex;
opacity: 1;
}
.weather-modal-content {
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: var(--border-radius-lg);
padding: 2rem;
max-width: 500px;
width: 90%;
max-height: 80vh;
overflow-y: auto;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: var(--shadow-lg);
transform: scale(0.9);
transition: transform var(--transition-normal);
position: relative;
}
.weather-modal-content::before {
content: '';
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
border-radius: calc(var(--border-radius-lg) + 2px);
z-index: -1;
opacity: 0.3;
filter: blur(5px);
}
.weather-modal.show .weather-modal-content {
transform: scale(1);
}
.weather-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
border-bottom: 1px solid var(--glass-border);
padding-bottom: 1rem;
}
.weather-modal-title {
font-size: 1.5rem;
font-weight: 600;
color: var(--text-primary);
background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.weather-modal-close {
background: none;
border: none;
font-size: 1.5rem;
color: var(--text-secondary);
cursor: pointer;
padding: 0.5rem;
border-radius: 50%;
transition: all var(--transition-fast);
display: flex;
align-items: center;
justify-content: center;
}
.weather-modal-close:hover {
background: var(--startup-card-hover);
color: var(--text-primary);
transform: rotate(90deg);
}
.weather-current {
text-align: center;
margin-bottom: 2rem;
padding: 1.5rem;
background: var(--startup-card-bg);
border-radius: var(--border-radius);
border: 1px solid var(--startup-card-border);
position: relative;
overflow: hidden;
}
.weather-current::before {
content: '';
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
border-radius: calc(var(--border-radius) + 2px);
z-index: -1;
opacity: 0.2;
filter: blur(5px);
}
.weather-current-temp {
font-size: 3rem;
font-weight: 700;
color: var(--accent-primary);
margin-bottom: 0.5rem;
text-shadow: 0 0 10px rgba(99, 102, 241, 0.3);
}
.weather-current-desc {
font-size: 1.1rem;
color: var(--text-secondary);
margin-bottom: 1rem;
}
.weather-current-location {
font-size: 0.9rem;
color: var(--text-tertiary);
}
.weather-details {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 1rem;
margin-bottom: 1.5rem;
}
.weather-detail-item {
background: var(--startup-card-bg);
border: 1px solid var(--startup-card-border);
border-radius: var(--border-radius);
padding: 1rem;
text-align: center;
transition: all var(--transition-normal);
position: relative;
overflow: hidden;
}
.weather-detail-item::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
transition: left 0.6s ease;
}
.weather-detail-item:hover::before {
left: 100%;
}
.weather-detail-item:hover {
background: var(--startup-card-hover);
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.weather-detail-icon {
font-size: 1.5rem;
color: var(--accent-primary);
margin-bottom: 0.5rem;
filter: drop-shadow(0 0 5px rgba(99, 102, 241, 0.3));
}
.weather-detail-label {
font-size: 0.8rem;
color: var(--text-tertiary);
margin-bottom: 0.25rem;
}
.weather-detail-value {
font-size: 1rem;
font-weight: 600;
color: var(--text-primary);
}
/* ==================== 主内容区域 ==================== */
.main-container {
margin-top: 80px;
height: calc(100vh - 160px);
position: relative;
overflow: hidden;
padding: 1rem;
}
.content-view {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
visibility: hidden;
transition: all var(--transition-normal);
border-radius: var(--border-radius);
overflow: hidden;
}
.content-view.active {
opacity: 1;
visibility: visible;
}
/* ==================== 浏览器起始页样式 ==================== */
.browser-start-page {
background: var(--startup-bg);
background-image:
radial-gradient(circle at 20% 50%, rgba(120, 119, 198, 0.1) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(255, 119, 198, 0.08) 0%, transparent 50%),
radial-gradient(circle at 40% 80%, rgba(120, 219, 255, 0.06) 0%, transparent 50%);
height: 100%;
overflow-y: auto;
padding: 1.5rem;
border-radius: var(--border-radius);
}
.startup-container {
max-width: 1200px;
margin: 0 auto;
display: flex;
flex-direction: column;
align-items: center;
min-height: 100%;
}
.startup-header {
text-align: center;
padding: 1.5rem 0 2.5rem;
}
.startup-logo {
font-size: 2.5rem;
font-weight: 700;
margin-bottom: 0.75rem;
background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
-webkit-background-clip: text;
background-clip: text;
color: transparent;
letter-spacing: -0.02em;
text-shadow: 0 5px 15px rgba(99, 102, 241, 0.3);
}
.startup-subtitle {
font-size: 1rem;
color: var(--text-secondary);
margin-bottom: 0.75rem;
}
.startup-time {
display: inline-block;
padding: 0.4rem 0.8rem;
background: var(--startup-card-bg);
border: 1px solid var(--startup-card-border);
border-radius: var(--border-radius);
font-size: 0.8rem;
color: var(--text-tertiary);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
position: relative;
overflow: hidden;
}
.startup-time::before {
content: '';
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
border-radius: calc(var(--border-radius) + 2px);
z-index: -1;
opacity: 0.2;
filter: blur(5px);
}
/* 搜索区域 */
.search-section {
width: 100%;
max-width: 600px;
margin-bottom: 3rem;
}
.search-container {
position: relative;
}
.search-input {
width: 100%;
height: 50px;
padding: 0 20px 0 50px;
font-size: 0.95rem;
border: 1px solid var(--startup-card-border);
border-radius: 25px;
background: var(--startup-search-bg);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
color: var(--text-primary);
transition: all var(--transition-normal);
font-family: inherit;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.search-input::placeholder {
color: var(--text-tertiary);
}
.search-input:focus {
outline: none;
background: var(--startup-search-focus);
border-color: var(--accent-primary);
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1), 0 5px 15px rgba(0, 0, 0, 0.1);
}
.search-icon {
position: absolute;
left: 18px;
top: 50%;
transform: translateY(-50%);
color: var(--text-tertiary);
pointer-events: none;
}
.search-engine {
position: absolute;
right: 6px;
top: 6px;
height: 38px;
display: flex;
align-items: center;
padding: 0 14px;
background: var(--startup-icon-bg);
border: 1px solid var(--startup-card-border);
border-radius: 19px;
cursor: pointer;
transition: all var(--transition-normal);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
.search-engine:hover {
background: var(--startup-icon-hover);
transform: scale(1.02);
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
}
.search-engine img {
width: 16px;
height: 16px;
margin-right: 6px;
border-radius: 50%;
}
.search-engine span {
font-size: 0.8rem;
color: var(--text-secondary);
font-weight: 500;
margin-right: 4px;
}
/* 快捷链接 */
.quick-links {
width: 100%;
margin-bottom: 2rem;
}
.section-title {
font-size: 1.1rem;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 1.25rem;
text-align: center;
position: relative;
display: inline-block;
padding: 0 1rem;
}
.section-title::before, .section-title::after {
content: '';
position: absolute;
top: 50%;
width: 30px;
height: 1px;
background: var(--accent-primary);
}
.section-title::before {
left: -30px;
}
.section-title::after {
right: -30px;
}
.links-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1.25rem;
}
.link-card {
background: var(--startup-card-bg);
border: 1px solid var(--startup-card-border);
border-radius: var(--border-radius);
padding: 1.25rem;
transition: all var(--transition-normal);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
position: relative;
overflow: hidden;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.link-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary));
opacity: 0;
transition: opacity var(--transition-normal);
}
.link-card:hover {
background: var(--startup-card-hover);
transform: translateY(-3px);
box-shadow: var(--shadow-lg);
}
.link-card:hover::before {
opacity: 1;
}
.card-header {
display: flex;
align-items: center;
margin-bottom: 1rem;
}
.card-icon {
width: 20px;
height: 20px;
margin-right: 10px;
color: var(--accent-primary);
filter: drop-shadow(0 0 5px rgba(99, 102, 241, 0.3));
}
.card-title {
font-size: 0.95rem;
font-weight: 600;
color: var(--text-primary);
}
.card-links {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
gap: 0.6rem;
}
.quick-link {
display: flex;
flex-direction: column;
align-items: center;
padding: 0.8rem 0.6rem;
background: var(--startup-icon-bg);
border: 1px solid var(--startup-card-border);
border-radius: var(--border-radius);
text-decoration: none;
color: var(--text-secondary);
transition: all var(--transition-normal);
position: relative;
overflow: hidden;
}
.quick-link::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
transition: left 0.6s ease;
}
.quick-link:hover::before {
left: 100%;
}
.quick-link:hover {
background: var(--startup-icon-hover);
color: var(--text-primary);
transform: translateY(-2px) scale(1.02);
box-shadow: var(--shadow-md);
}
.link-icon {
width: 36px;
height: 36px;
margin-bottom: 0.6rem;
display: flex;
align-items: center;
justify-content: center;
background: var(--startup-card-bg);
border: 1px solid var(--startup-card-border);
border-radius: 8px;
transition: all var(--transition-normal);
}
.quick-link:hover .link-icon {
background: var(--accent-primary);
border-color: var(--accent-primary);
box-shadow: 0 0 15px rgba(99, 102, 241, 0.3);
}
.link-icon img {
width: 18px;
height: 18px;
object-fit: contain;
}
.link-name {
font-size: 0.8rem;
font-weight: 500;
text-align: center;
line-height: 1.2;
}
/* ==================== 终端样式 ==================== */
.terminal-container {
height: 100%;
display: flex;
flex-direction: column;
background: var(--editor-bg);
border-radius: var(--border-radius);
overflow: hidden;
box-shadow: var(--shadow-lg);
border: 1px solid var(--border-color);
position: relative;
}
.terminal-header {
background: var(--header-bg);
padding: 0.75rem 1rem;
display: flex;
align-items: center;
gap: 0.5rem;
border-bottom: 1px solid var(--border-color);
border-radius: var(--border-radius) var(--border-radius) 0 0;
}
.window-btn {
width: 12px;
height: 12px;
border-radius: 50%;
transition: all var(--transition-fast);
cursor: pointer;
position: relative;
}
.window-btn:hover::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 6px;
height: 6px;
background: rgba(0, 0, 0, 0.3);
border-radius: 50%;
}
.window-btn.close { background: var(--window-btn-close); }
.window-btn.minimize { background: var(--window-btn-min); }
.window-btn.maximize { background: var(--window-btn-max); }
.terminal-title {
margin-left: 1rem;
color: var(--text-secondary);
font-size: 0.9rem;
}
.terminal-content {
flex: 1;
padding: 1rem;
overflow-y: auto;
font-family: var(--font-mono);
font-size: 14px;
line-height: 1.6;
background: var(--editor-bg);
color: var(--text-color);
counter-reset: line;
scrollbar-width: thin;
scrollbar-color: var(--line-color) transparent;
}
.terminal-content::-webkit-scrollbar {
width: 8px;
height: 8px;
}
.terminal-content::-webkit-scrollbar-track {
background: transparent;
}
.terminal-content::-webkit-scrollbar-thumb {
background-color: var(--line-color);
border-radius: 4px;
}
.line {
display: flex;
padding: 2px 0;
position: relative;
min-height: 1.6em;
}
.line::before {
counter-increment: line;
content: counter(line);
color: var(--line-color);
width: 2em;
text-align: right;
padding-right: 1em;
position: absolute;
transition: color var(--transition-normal);
opacity: 0.7;
}
.line-content {
padding-left: 3em;
width: 100%;
}
.indent { margin-left: 2em; }
.indent-2 { margin-left: 4em; }
.keyword { color: var(--keyword-color); }
.string { color: var(--string-color); }
.comment { color: var(--comment-color); }
.number { color: var(--number-color); }
.function { color: var(--function-color); }
.ai-output { color: var(--ai-output-color); }
.user-input { color: var(--user-input-color); }
.terminal-input-line {
display: flex;
align-items: center;
background: var(--editor-secondary-bg);
padding: 0.75rem 1rem;
border-top: 1px solid var(--border-color);
}
.terminal-prompt {
color: var(--accent-primary);
margin-right: 0.5rem;
font-weight: bold;
}
.terminal-input {
flex: 1;
background: transparent;
border: none;
color: var(--text-color);
font-family: var(--font-mono);
font-size: 14px;
outline: none;
}
/* 思考动画 */
.thinking-animation {
display: inline-block;
position: relative;
width: 60px;
height: 16px;
}
.thinking-animation span {
position: absolute;
width: 6px;
height: 6px;
background: var(--ai-output-color);
border-radius: 50%;
animation: thinking 1.4s infinite ease-in-out;
}
.thinking-animation span:nth-child(1) {
left: 0;
animation-delay: 0s;
}
.thinking-animation span:nth-child(2) {
left: 12px;
animation-delay: 0.2s;
}
.thinking-animation span:nth-child(3) {
left: 24px;
animation-delay: 0.4s;
}
@keyframes thinking {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-8px);
}
}
/* 视频容器 */
.video-container {
margin-top: 15px;
width: 100%;
background: var(--video-bg);
border-radius: var(--border-radius);
overflow: hidden;
transition: all var(--transition-normal);
box-shadow: var(--box-shadow);
border: 1px solid var(--border-color);
}
.video-container iframe {
width: 100%;
height: 300px;
border: none;
}
.video-info {
padding: 12px;
font-size: 0.85em;
color: var(--text-color);
background: var(--editor-secondary-bg);
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.video-command {
background: var(--header-bg);
padding: 6px 12px;
border-radius: 15px;
cursor: pointer;
font-size: 0.8em;
transition: all var(--transition-fast);
border: 1px solid rgba(255, 255, 255, 0.1);
user-select: none;
margin-top: 8px;
display: inline-block;
}
.video-command:hover {
background: var(--accent-primary);
color: white;
transform: translateY(-1px);
box-shadow: 0 3px 10px rgba(99, 102, 241, 0.3);
}
/* 图片转换器 */
.image-converter {
margin-top: 15px;
width: 100%;
background: var(--editor-secondary-bg);
border-radius: var(--border-radius);
padding: 15px;
transition: all var(--transition-normal);
box-shadow: var(--box-shadow);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.image-btn {
background: var(--accent-primary);
color: white;
border: none;
padding: 8px 16px;
border-radius: 15px;
cursor: pointer;
font-family: var(--font-mono);
font-weight: bold;
transition: all var(--transition-fast);
min-width: 100px;
text-align: center;
font-size: 0.85rem;
}
.image-btn:hover {
background: var(--accent-hover);
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);
}
/* 命令历史记录 */
.command-history {
margin-top: 20px;
background: var(--editor-secondary-bg);
border-radius: var(--border-radius);
padding: 15px;
display: none;
border: 1px solid var(--border-color);
}
.history-title {
font-size: 0.9em;
margin-bottom: 10px;
color: var(--accent-primary);
font-weight: bold;
}
.history-list {
max-height: 200px;
overflow-y: auto;
}
.history-item {
padding: 5px 0;
cursor: pointer;
display: flex;
align-items: center;
transition: color var(--transition-fast);
}
.history-item:hover {
color: var(--accent-primary);
}
.history-item::before {
content: ">";
margin-right: 10px;
color: var(--line-color);
}
/* 命令面板 */
.command-palette {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 90%;
max-width: 600px;
background: var(--editor-bg);
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
z-index: 1000;
display: none;
border: 1px solid rgba(255, 255, 255, 0.1);
max-height: 70vh;
overflow: hidden;
}
.command-palette-content {
padding: 15px;
max-height: calc(70vh - 50px);
overflow-y: auto;
}
.command-search {
width: 100%;
background: var(--editor-secondary-bg);
border: 1px solid var(--line-color);
color: var(--text-color);
padding: 8px 12px;
border-radius: 4px;
font-family: var(--font-family);
margin-bottom: 15px;
}
.command-list {
max-height: 50vh;
overflow-y: auto;
}
.command-item {
padding: 8px 12px;
cursor: pointer;
border-radius: 4px;
display: flex;
align-items: center;
gap: 10px;
margin: 5px 0;
transition: all var(--transition-fast);
}
.command-item:hover {
background: var(--editor-secondary-bg);
}
.command-item.selected {
background: var(--accent-primary);
color: white;
}
.command-icon {
width: 16px;
height: 16px;
}
.command-shortcut {
margin-left: auto;
color: var(--line-color);
font-size: 0.8em;
background: var(--editor-secondary-bg);
padding: 2px 6px;
border-radius: 4px;
}
.command-category {
font-size: 0.8em;
color: var(--line-color);
padding: 5px 12px;
margin-top: 10px;
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.command-category:first-child {
border-top: none;
margin-top: 0;
}
/* ==================== 底部版权信息 ==================== */
.footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 80px;
background: var(--glass-bg);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-top: 1px solid var(--glass-border);
border-radius: var(--border-radius) var(--border-radius) 0 0;
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
box-shadow: 0 -4px 6px -1px rgba(0, 0, 0, 0.1);
transition: all var(--transition-normal);
}
.footer::before {
content: '';
position: absolute;
top: -2px;
left: 0;
right: 0;
height: 2px;
background: linear-gradient(90deg, var(--accent-primary), var(--accent-secondary), var(--accent-primary));
opacity: 0.5;
filter: blur(1px);
}
.footer-content {
text-align: center;
color: var(--text-secondary);
font-size: 0.8rem;
line-height: 1.4;
position: relative;
padding: 0.5rem 1rem;
border-radius: var(--border-radius);
transition: all var(--transition-normal);
}
.footer-content::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: var(--startup-card-bg);
border-radius: var(--border-radius);
z-index: -1;
opacity: 0;
transition: opacity var(--transition-normal);
}
.footer-content:hover::before {
opacity: 1;
}
.footer-content .copyright {
font-weight: 500;
margin-bottom: 0.2rem;
}
.footer-content .links {
display: flex;
gap: 0.75rem;
justify-content: center;
align-items: center;
}
.footer-content a {
color: var(--accent-primary);
text-decoration: none;
transition: color var(--transition-fast);
position: relative;
}
.footer-content a:hover {
color: var(--accent-hover);
}
.footer-content a::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
width: 0;
height: 1px;
background: var(--accent-hover);
transition: width var(--transition-normal);
}
.footer-content a:hover::after {
width: 100%;
}
/* ==================== 移动端优化 ==================== */
@media (max-width: 768px) {
.top-nav {
padding: 0 1rem;
height: 70px;
}
.main-container {
margin-top: 70px;
height: calc(100vh - 140px);
padding: 0.75rem;
}
.footer {
height: 70px;
}
.nav-logo {
font-size: 1.2rem;
}
.nav-logo span {
display: none;
}
.nav-tabs {
gap: 0.25rem;
padding: 0.25rem;
}
.nav-tab {
padding: 0.6rem 1rem;
min-width: 90px;
font-size: 0.8rem;
}
.nav-tab span {
display: none;
}
.weather-theme-widget {
gap: 0.5rem;
padding: 0.4rem;
}
.weather-section {
padding: 0.2rem 0.5rem;
}
.weather-info {
display: none;
}
.weather-icon {
font-size: 1.1rem;
}
.theme-toggle-container {
width: 50px;
height: 26px;
}
.theme-toggle-button {
width: 22px;
height: 22px;
top: 2px;
left: 2px;
}
.light-mode .theme-toggle-button {
left: 26px;
}
.sun, .moon {
width: 12px;
height: 12px;
}
.weather-modal-content {
padding: 1.5rem;
margin: 1rem;
}
.weather-details {
grid-template-columns: repeat(2, 1fr);
}
}
/* ==================== 滚动条样式 ==================== */
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: var(--text-tertiary);
border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--accent-primary);
}
/* ==================== 动画效果 ==================== */
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(15px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.startup-container > * {
animation: fadeIn 0.5s ease-out forwards;
}
.startup-header {
animation-delay: 0.1s;
}
.search-section {
animation-delay: 0.2s;
}
.quick-links {
animation-delay: 0.3s;
}
/* 光标效果 */
.cursor {
display: inline-block;
width: 2px;
height: 1.2em;
background: var(--text-color);
margin-left: 2px;
animation: blink 1s step-end infinite;
vertical-align: middle;
transition: background var(--transition-normal);
}
@keyframes blink {
50% { opacity: 0; }
}
</style>
</head>
<body class="dark-mode">
<!-- 天气详情弹窗 -->
<div class="weather-modal" id="weather-modal">
<div class="weather-modal-content">
<div class="weather-modal-header">
<h2 class="weather-modal-title">天气详情</h2>
<button class="weather-modal-close" id="weather-modal-close">
<i class="fas fa-times"></i>
</button>
</div>
<div class="weather-current">
<div class="weather-current-temp" id="modal-temp">--°C</div>
<div class="weather-current-desc" id="modal-desc">加载中...</div>
<div class="weather-current-location" id="modal-location">未知位置</div>
</div>
<div class="weather-details">
<div class="weather-detail-item">
<div class="weather-detail-icon">
<i class="fas fa-eye"></i>
</div>
<div class="weather-detail-label">能见度</div>
<div class="weather-detail-value" id="modal-visibility">--</div>
</div>
<div class="weather-detail-item">
<div class="weather-detail-icon">
<i class="fas fa-tint"></i>
</div>
<div class="weather-detail-label">湿度</div>
<div class="weather-detail-value" id="modal-humidity">--%</div>
</div>
<div class="weather-detail-item">
<div class="weather-detail-icon">
<i class="fas fa-wind"></i>
</div>
<div class="weather-detail-label">风速</div>
<div class="weather-detail-value" id="modal-wind">-- m/s</div>
</div>
<div class="weather-detail-item">
<div class="weather-detail-icon">
<i class="fas fa-thermometer-half"></i>
</div>
<div class="weather-detail-label">体感温度</div>
<div class="weather-detail-value" id="modal-feels-like">--°C</div>
</div>
<div class="weather-detail-item">
<div class="weather-detail-icon">
<i class="fas fa-compress-arrows-alt"></i>
</div>
<div class="weather-detail-label">气压</div>
<div class="weather-detail-value" id="modal-pressure">-- hPa</div>
</div>
<div class="weather-detail-item">
<div class="weather-detail-icon">
<i class="fas fa-cloud"></i>
</div>
<div class="weather-detail-label">云量</div>
<div class="weather-detail-value" id="modal-clouds">--%</div>
</div>
</div>
</div>
</div>
<!-- 顶部导航栏 -->
<nav class="top-nav">
<div class="nav-logo">
<i class="fas fa-cube"></i>
<span>TENG YUAN</span>
</div>
<div class="nav-tabs">
<button class="nav-tab active" data-view="browser">
<i class="fas fa-globe"></i>
<span>浏览器</span>
</button>
<button class="nav-tab" data-view="terminal">
<i class="fas fa-terminal"></i>
<span>终端</span>
</button>
</div>
<!-- 右侧天气和主题切换结合 -->
<div class="right-controls">
<div class="weather-theme-widget">
<!-- 天气信息部分 -->
<div class="weather-section" id="weather-section">
<div class="weather-icon">
<i class="fas fa-cloud-sun"></i>
</div>
<div class="weather-info">
<span class="weather-temp">--°C</span>
<span class="weather-location">加载中...</span>
</div>
</div>
<!-- 主题切换部分 -->
<div class="theme-toggle-container">
<input type="checkbox" id="theme-toggle" class="theme-toggle-input">
<label for="theme-toggle" class="theme-toggle-label">
<div class="theme-toggle-button">
<div class="sun"></div>
<div class="moon"></div>
</div>
</label>
</div>
</div>
</div>
</nav>
<!-- 主内容区域 -->
<main class="main-container">
<!-- 浏览器起始页 -->
<div class="content-view active" id="browser-view">
<div class="browser-start-page">
<div class="startup-container">
<header class="startup-header">
<h1 class="startup-logo">Teng Yuan</h1>
<p class="startup-subtitle">智能终端 · 高效工作 · 极致体验</p>
<div class="startup-time" id="current-time"></div>
</header>
<section class="search-section">
<div class="search-container">
<i class="fas fa-search search-icon"></i>
<form id="search-form" action="https://www.google.com/search" method="get" target="_blank">
<input
type="text"
name="q"
class="search-input"
placeholder="搜索互联网,发现无限可能..."
autofocus
>
<div class="search-engine" id="search-engine">
<img src="https://www.google.com/favicon.ico" alt="Google">
<span>Google</span>
<i class="fas fa-chevron-down"></i>
</div>
</form>
</div>
</section>
<section class="quick-links">
<h2 class="section-title">常用网站</h2>
<div class="links-grid">
<!-- 娱乐媒体 -->
<div class="link-card">
<div class="card-header">
<i class="fas fa-play-circle card-icon"></i>
<h3 class="card-title">娱乐媒体</h3>
</div>
<div class="card-links">
<a href="https://www.youtube.com" class="quick-link" target="_blank">
<div class="link-icon">
<img src="https://www.youtube.com/favicon.ico" alt="YouTube">
</div>
<div class="link-name">YouTube</div>
</a>
<a href="https://www.bilibili.com" class="quick-link" target="_blank">
<div class="link-icon">
<img src="https://www.bilibili.com/favicon.ico" alt="Bilibili">
</div>
<div class="link-name">Bilibili</div>
</a>
<a href="https://music.163.com" class="quick-link" target="_blank">
<div class="link-icon">
<img src="https://music.163.com/favicon.ico" alt="网易云音乐">
</div>
<div class="link-name">网易云音乐</div>
</a>
<a href="https://www.netflix.com" class="quick-link" target="_blank">
<div class="link-icon">
<img src="https://www.netflix.com/favicon.ico" alt="Netflix">
</div>
<div class="link-name">Netflix</div>
</a>
</div>
</div>
<!-- 开发工具 -->
<div class="link-card">
<div class="card-header">
<i class="fas fa-code card-icon"></i>
<h3 class="card-title">开发工具</h3>
</div>
<div class="card-links">
<a href="https://github.com" class="quick-link" target="_blank">
<div class="link-icon">
<img src="https://github.com/favicon.ico" alt="GitHub">
</div>
<div class="link-name">GitHub</div>
</a>
<a href="https://stackoverflow.com" class="quick-link" target="_blank">
<div class="link-icon">
<img src="https://stackoverflow.com/favicon.ico" alt="Stack Overflow">
</div>
<div class="link-name">Stack Overflow</div>
</a>
<a href="https://developer.mozilla.org" class="quick-link" target="_blank">
<div class="link-icon">
<img src="https://developer.mozilla.org/favicon.ico" alt="MDN">
</div>
<div class="link-name">MDN</div>
</a>
<a href="https://v0.dev" class="quick-link" target="_blank">
<div class="link-icon">
<img src="https://v0.dev/favicon.ico" alt="v0.dev">
</div>
<div class="link-name">v0.dev</div>
</a>
</div>
</div>
<!-- AI工具 -->
<div class="link-card">
<div class="card-header">
<i class="fas fa-robot card-icon"></i>
<h3 class="card-title">AI工具</h3>
</div>
<div class="card-links">
<a href="https://chat.openai.com" class="quick-link" target="_blank">
<div class="link-icon">
<img src="https://chat.openai.com/favicon.ico" alt="ChatGPT">
</div>
<div class="link-name">ChatGPT</div>
</a>
<a href="https://claude.ai" class="quick-link" target="_blank">
<div class="link-icon">
<img src="https://claude.ai/favicon.ico" alt="Claude">
</div>
<div class="link-name">Claude</div>
</a>
<a href="https://www.midjourney.com" class="quick-link" target="_blank">
<div class="link-icon">
<img src="https://www.midjourney.com/favicon.ico" alt="Midjourney">
</div>
<div class="link-name">Midjourney</div>
</a>
<a href="https://copilot.microsoft.com" class="quick-link" target="_blank">
<div class="link-icon">
<img src="https://copilot.microsoft.com/favicon.ico" alt="Copilot">
</div>
<div class="link-name">Copilot</div>
</a>
</div>
</div>
<!-- 实用工具 -->
<div class="link-card">
<div class="card-header">
<i class="fas fa-tools card-icon"></i>
<h3 class="card-title">实用工具</h3>
</div>
<div class="card-links">
<a href="https://www.google.com" class="quick-link" target="_blank">
<div class="link-icon">
<img src="https://www.google.com/favicon.ico" alt="Google">
</div>
<div class="link-name">Google</div>
</a>
<a href="https://translate.google.com" class="quick-link" target="_blank">
<div class="link-icon">
<img src="https://translate.google.com/favicon.ico" alt="Google 翻译">
</div>
<div class="link-name">Google 翻译</div>
</a>
<a href="https://www.notion.so" class="quick-link" target="_blank">
<div class="link-icon">
<img src="https://www.notion.so/favicon.ico" alt="Notion">
</div>
<div class="link-name">Notion</div>
</a>
<a href="https://www.figma.com" class="quick-link" target="_blank">
<div class="link-icon">
<img src="https://www.figma.com/favicon.ico" alt="Figma">
</div>
<div class="link-name">Figma</div>
</a>
</div>
</div>
</div>
</section>
</div>
</div>
</div>
<!-- 终端界面 -->
<div class="content-view" id="terminal-view">
<div class="terminal-container">
<div class="terminal-header">
<span class="window-btn close"></span>
<span class="window-btn minimize"></span>
<span class="window-btn maximize"></span>
<span class="terminal-title">terminal.js - 藤原的个人终端</span>
</div>
<div class="terminal-content" id="terminal-content">
<div class="line"><div class="line-content"><span class="comment">// 个人信息配置</span></div></div>
<div class="line"><div class="line-content"><span class="keyword">const</span> <span class="function">profile</span> = {</div></div>
<div class="line"><div class="line-content indent"><span class="keyword">name</span>: <span class="string">"藤原"</span>,</div></div>
<div class="line"><div class="line-content indent"><span class="keyword">title</span>: <span class="string">"职场牛马!!!"</span>,</div></div>
<div class="line"><div class="line-content indent"><span class="keyword">contact</span>: {</div></div>
<div class="line"><div class="line-content indent-2"><span class="keyword">email</span>: <span class="string"><a href="mailto:2083737075@qq.com">"2083737075@qq.com"</a></span>,</div></div>
<div class="line"><div class="line-content indent-2"><span class="keyword">website</span>: <span class="string"><a href="http://tengyuan.icu" target="_blank">"TengYuan.icu"</a></span>,</div></div>
<div class="line"><div class="line-content indent-2"><span class="keyword">FileCodeBox</span>: <span class="string"><a href="http://wp.tengyuan.icu/" target="_blank">"wp.tengyuan.icu"</a></span>,</div></div>
<div class="line"><div class="line-content indent">},</div></div>
<div class="line"><div class="line-content indent"><span class="keyword">links</span>: {</div></div>
<div class="line"><div class="line-content indent-2"><span class="keyword">travel blog</span>: <span class="string"><a href="http://blog.tengyuan.icu/" target="_blank">"blog.tengyuan.icu"</a></span>,</div></div>
<div class="line"><div class="line-content indent-2"><span class="keyword">birthday</span>: <span class="string"><a href="http://sr.0814.cn" target="_blank">"2001/11/01"</a></span>,</div></div>
<div class="line"><div class="line-content indent">},</div></div>
<div class="line"><div class="line-content indent"><span class="comment">// 座右铭</span></div></div>
<div class="line"><div class="line-content indent"><span class="keyword">motto</span>: <span class="string">"以清简代码,筑玖维数字宇宙。"</span>,</div></div>
<div class="line"><div class="line-content indent"><span class="keyword">copyright</span>: <span class="string">"2017-<span id="year"></span> 藤原"</span>,</div></div>
<div class="line"><div class="line-content">};</div></div>
<div class="line"><div class="line-content"><span class="comment">// 终端交互</span></div></div>
<div class="line"><div class="line-content"><span class="function">console</span>.<span class="function">log</span>(<span class="string">"欢迎访问藤原的个人终端"</span>);</div></div>
<div class="line"><div class="line-content"><span class="function">console</span>.<span class="function">log</span>(<span class="string">"输入 'help' 获取可用命令"</span>);</div></div>
<!-- 命令历史记录 -->
<div class="command-history" id="commandHistory">
<div class="history-title">命令历史记录</div>
<div class="history-list" id="historyList"></div>
</div>
</div>
<form class="terminal-input-line" id="terminal-form">
<span class="terminal-prompt">></span>
<input type="text" class="terminal-input" id="terminal-input" autocomplete="off" autofocus>
</form>
</div>
</div>
</main>
<!-- 底部版权信息 -->
<footer class="footer">
<div class="footer-content">
<div class="copyright">© 2017-<span id="footer-year"></span> 藤原 | TENG YUAN 智能终端系统</div>
<div class="links">
<a href="mailto:2083737075@qq.com">联系邮箱</a>
<span>|</span>
<a href="http://tengyuan.icu" target="_blank">官方网站</a>
<span>|</span>
<a href="http://blog.tengyuan.icu/" target="_blank">旅行博客</a>
<span>|</span>
<a href="http://wp.tengyuan.icu/" target="_blank">文件传输</a>
</div>
</div>
</footer>
<!-- 命令面板 -->
<div class="command-palette" id="commandPalette">
<div class="terminal-header">
<span class="window-btn close" id="closeCommandPaletteBtn"></span>
<span class="terminal-title">command-palette.js - 命令面板</span>
</div>
<div class="command-palette-content">
<input type="text" class="command-search" id="commandSearch" placeholder="搜索命令...">
<div class="command-list" id="commandList">
<!-- 命令将通过JS动态添加 -->
</div>
</div>
</div>
<!-- 隐藏的文件输入元素 -->
<input type="file" id="fileInput" accept="image/*" style="display: none;">
<script>
// ==================== 全局变量 ====================
let currentTheme = 'dark';
let currentView = 'browser';
let commandHistory = [];
let historyIndex = -1;
let weatherData = null;
// ==================== 主题管理 ====================
const themeManager = {
init() {
const savedTheme = localStorage.getItem('theme') || 'dark';
this.setTheme(savedTheme);
// 绑定主题切换事件
const themeToggle = document.getElementById('theme-toggle');
if (themeToggle) {
themeToggle.addEventListener('change', () => {
this.toggleTheme();
});
}
},
setTheme(theme) {
currentTheme = theme;
document.body.className = theme === 'light' ? 'light-mode' : 'dark-mode';
const themeToggle = document.getElementById('theme-toggle');
if (themeToggle) {
themeToggle.checked = theme === 'light';
}
localStorage.setItem('theme', theme);
},
toggleTheme() {
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
this.setTheme(newTheme);
}
};
// ==================== 导航管理 ====================
const navigationManager = {
init() {
const navTabs = document.querySelectorAll('.nav-tab');
navTabs.forEach(tab => {
tab.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
const view = tab.dataset.view;
if (view) {
this.switchView(view);
}
});
});
},
switchView(view) {
// 更新导航按钮状态
document.querySelectorAll('.nav-tab').forEach(tab => {
tab.classList.remove('active');
});
const activeTab = document.querySelector(`[data-view="${view}"]`);
if (activeTab) {
activeTab.classList.add('active');
}
// 切换内容视图
document.querySelectorAll('.content-view').forEach(contentView => {
contentView.classList.remove('active');
});
const activeView = document.getElementById(`${view}-view`);
if (activeView) {
activeView.classList.add('active');
}
currentView = view;
// 如果切换到终端,聚焦输入框
if (view === 'terminal') {
setTimeout(() => {
const terminalInput = document.getElementById('terminal-input');
if (terminalInput) {
terminalInput.focus();
}
}, 300);
}
}
};
// ==================== 时间管理 ====================
const timeManager = {
init() {
this.updateTime();
setInterval(() => this.updateTime(), 1000);
},
updateTime() {
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
};
const timeString = now.toLocaleDateString('zh-CN', options);
const timeElement = document.getElementById('current-time');
if (timeElement) {
timeElement.textContent = timeString;
}
// 更新年份
const currentYear = now.getFullYear();
const yearElement = document.getElementById('year');
const footerYearElement = document.getElementById('footer-year');
if (yearElement) {
yearElement.textContent = currentYear;
}
if (footerYearElement) {
footerYearElement.textContent = currentYear;
}
}
};
// ==================== 搜索引擎管理 ====================
const searchManager = {
engines: {
google: {
name: 'Google',
url: 'https://www.google.com/search',
param: 'q',
icon: 'https://www.google.com/favicon.ico'
},
baidu: {
name: '百度',
url: 'https://www.baidu.com/s',
param: 'wd',
icon: 'https://www.baidu.com/favicon.ico'
},
bing: {
name: 'Bing',
url: 'https://www.bing.com/search',
param: 'q',
icon: 'https://www.bing.com/favicon.ico'
}
},
currentEngine: 'google',
init() {
this.updateSearchEngine();
// 搜索引擎切换
const searchEngine = document.getElementById('search-engine');
if (searchEngine) {
searchEngine.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
const engines = Object.keys(this.engines);
const currentIndex = engines.indexOf(this.currentEngine);
const nextIndex = (currentIndex + 1) % engines.length;
this.currentEngine = engines[nextIndex];
this.updateSearchEngine();
});
}
},
updateSearchEngine() {
const engine = this.engines[this.currentEngine];
const form = document.getElementById('search-form');
const input = form ? form.querySelector('input[name]') : null;
const engineElement = document.getElementById('search-engine');
if (form && engine) {
form.action = engine.url;
}
if (input && engine) {
input.name = engine.param;
}
if (engineElement && engine) {
const img = engineElement.querySelector('img');
const span = engineElement.querySelector('span');
if (img) img.src = engine.icon;
if (span) span.textContent = engine.name;
}
}
};
// ==================== 天气管理 ====================
const weatherManager = {
apiKey: '4d8fb5b93d4af21d66a2948710284366', // OpenWeatherMap免费API密钥
init() {
this.getWeather();
// 点击天气组件显示详情弹窗
const weatherSection = document.getElementById('weather-section');
if (weatherSection) {
weatherSection.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
this.showWeatherModal();
});
}
// 关闭弹窗
const weatherModalClose = document.getElementById('weather-modal-close');
const weatherModal = document.getElementById('weather-modal');
if (weatherModalClose && weatherModal) {
weatherModalClose.addEventListener('click', () => {
weatherModal.classList.remove('show');
});
weatherModal.addEventListener('click', (e) => {
if (e.target === weatherModal) {
weatherModal.classList.remove('show');
}
});
}
// 每30分钟更新一次天气
setInterval(() => this.getWeather(), 30 * 60 * 1000);
},
async getWeather() {
try {
// 先尝试获取用户位置
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
async (position) => {
const { latitude, longitude } = position.coords;
await this.fetchWeatherByCoords(latitude, longitude);
},
async (error) => {
console.log('无法获取位置,使用IP定位:', error);
await this.fetchWeatherByIP();
}
);
} else {
await this.fetchWeatherByIP();
}
} catch (error) {
console.error('获取天气失败:', error);
this.updateWeatherUI('--°C', '未知位置', 'fa-cloud');
}
},
async fetchWeatherByCoords(lat, lon) {
try {
const response = await fetch(`https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&units=metric&lang=zh_cn&appid=${this.apiKey}`);
const data = await response.json();
this.processWeatherData(data);
} catch (error) {
console.error('通过坐标获取天气失败:', error);
this.updateWeatherUI('--°C', '未知位置', 'fa-cloud');
}
},
async fetchWeatherByIP() {
try {
// 先获取IP位置
const ipResponse = await fetch('https://ipapi.co/json/');
const ipData = await ipResponse.json();
// 然后获取天气
const response = await fetch(`https://api.openweathermap.org/data/2.5/weather?q=${ipData.city}&units=metric&lang=zh_cn&appid=${this.apiKey}`);
const data = await response.json();
this.processWeatherData(data);
} catch (error) {
console.error('通过IP获取天气失败:', error);
this.updateWeatherUI('--°C', '未知位置', 'fa-cloud');
}
},
processWeatherData(data) {
if (!data || data.cod === '404') {
this.updateWeatherUI('--°C', '未知位置', 'fa-cloud');
return;
}
weatherData = data;
const temp = Math.round(data.main.temp);
const location = data.name;
const weatherIcon = this.getWeatherIcon(data.weather[0].id);
this.updateWeatherUI(`${temp}°C`, location, weatherIcon);
this.updateWeatherModal(data);
},
updateWeatherUI(temp, location, iconClass) {
const weatherSection = document.getElementById('weather-section');
if (!weatherSection) return;
const weatherIcon = weatherSection.querySelector('.weather-icon i');
const weatherTemp = weatherSection.querySelector('.weather-temp');
const weatherLocation = weatherSection.querySelector('.weather-location');
if (weatherIcon) {
weatherIcon.className = '';
weatherIcon.classList.add('fas', iconClass);
}
if (weatherTemp) {
weatherTemp.textContent = temp;
}
if (weatherLocation) {
weatherLocation.textContent = location;
}
},
updateWeatherModal(data) {
if (!data) return;
// 更新弹窗内容
const modalTemp = document.getElementById('modal-temp');
const modalDesc = document.getElementById('modal-desc');
const modalLocation = document.getElementById('modal-location');
const modalVisibility = document.getElementById('modal-visibility');
const modalHumidity = document.getElementById('modal-humidity');
const modalWind = document.getElementById('modal-wind');
const modalFeelsLike = document.getElementById('modal-feels-like');
const modalPressure = document.getElementById('modal-pressure');
const modalClouds = document.getElementById('modal-clouds');
if (modalTemp) modalTemp.textContent = `${Math.round(data.main.temp)}°C`;
if (modalDesc) modalDesc.textContent = data.weather[0].description;
if (modalLocation) modalLocation.textContent = data.name;
if (modalVisibility) modalVisibility.textContent = data.visibility ? `${(data.visibility / 1000).toFixed(1)} km` : '--';
if (modalHumidity) modalHumidity.textContent = `${data.main.humidity}%`;
if (modalWind) modalWind.textContent = `${data.wind.speed} m/s`;
if (modalFeelsLike) modalFeelsLike.textContent = `${Math.round(data.main.feels_like)}°C`;
if (modalPressure) modalPressure.textContent = `${data.main.pressure} hPa`;
if (modalClouds) modalClouds.textContent = `${data.clouds.all}%`;
},
showWeatherModal() {
const weatherModal = document.getElementById('weather-modal');
if (weatherModal) {
weatherModal.classList.add('show');
}
},
getWeatherIcon(weatherId) {
// 根据OpenWeatherMap的天气代码返回对应的Font Awesome图标
if (weatherId >= 200 && weatherId < 300) return 'fa-bolt'; // 雷暴
if (weatherId >= 300 && weatherId < 400) return 'fa-cloud-rain'; // 小雨
if (weatherId >= 500 && weatherId < 600) return 'fa-cloud-showers-heavy'; // 大雨
if (weatherId >= 600 && weatherId < 700) return 'fa-snowflake'; // 雪
if (weatherId >= 700 && weatherId < 800) return 'fa-smog'; // 雾
if (weatherId === 800) return 'fa-sun'; // 晴天
if (weatherId > 800) return 'fa-cloud-sun'; // 多云
return 'fa-cloud'; // 默认
}
};
// ==================== 终端管理 ====================
const terminalManager = {
init() {
const form = document.getElementById('terminal-form');
const input = document.getElementById('terminal-input');
if (form && input) {
form.addEventListener('submit', (e) => {
e.preventDefault();
const command = input.value.trim();
if (command) {
this.executeCommand(command);
input.value = '';
historyIndex = -1;
}
});
// 命令历史导航
input.addEventListener('keydown', (e) => {
if (e.key === 'ArrowUp') {
e.preventDefault();
if (commandHistory.length > 0 && historyIndex < commandHistory.length - 1) {
historyIndex++;
input.value = commandHistory[commandHistory.length - 1 - historyIndex];
}
} else if (e.key === 'ArrowDown') {
e.preventDefault();
if (historyIndex > -1) {
historyIndex--;
input.value = historyIndex === -1 ? '' : commandHistory[commandHistory.length - 1 - historyIndex];
}
}
});
}
// 初始化欢迎消息
setTimeout(() => {
this.addToTerminal('欢迎来到藤原的个人终端!输入 "help" 获取可用命令。', 'output');
}, 500);
},
executeCommand(command) {
// 添加到历史记录
commandHistory.push(command);
if (commandHistory.length > 50) {
commandHistory.shift();
}
// 显示命令
this.addToTerminal(`> ${command}`, 'command');
// 处理命令
const output = this.processCommand(command);
if (output && output.message) {
this.addToTerminal(output.message, output.isError ? 'error' : 'output');
}
},
processCommand(command) {
const cmd = command.toLowerCase().trim();
if (cmd === 'help') {
return {
message: `可用命令:
基础命令:
- help: 显示帮助信息
- clear: 清空终端
- history: 显示命令历史记录
- theme: 切换深色/浅色主题
工具命令:
- video [url]: 解析并播放视频
- ai [message]: 与AI助手对话
- base64 [encode/decode] [text]: 进行Base64编码/解码
- image [format]: 转换图片格式
- todo [add/list/done/remove]: 管理待办事项
- weather: 显示详细天气信息
快捷键:
- 上/下箭头: 浏览命令历史`,
isError: false
};
}
if (cmd === 'clear') {
const terminalContent = document.getElementById('terminal-content');
if (terminalContent) {
terminalContent.innerHTML = `
<div class="line"><div class="line-content"><span class="comment">// 个人信息配置</span></div></div>
<div class="line"><div class="line-content"><span class="keyword">const</span> <span class="function">profile</span> = {</div></div>
<div class="line"><div class="line-content indent"><span class="keyword">name</span>: <span class="string">"藤原"</span>,</div></div>
<div class="line"><div class="line-content indent"><span class="keyword">title</span>: <span class="string">"职场牛马!!!"</span>,</div></div>
<div class="line"><div class="line-content indent"><span class="keyword">contact</span>: {</div></div>
<div class="line"><div class="line-content indent-2"><span class="keyword">email</span>: <span class="string"><a href="mailto:2083737075@qq.com">"2083737075@qq.com"</a></span>,</div></div>
<div class="line"><div class="line-content indent-2"><span class="keyword">website</span>: <span class="string"><a href="http://tengyuan.icu" target="_blank">"TengYuan.icu"</a></span>,</div></div>
<div class="line"><div class="line-content indent-2"><span class="keyword">FileCodeBox</span>: <span class="string"><a href="http://wp.tengyuan.icu/" target="_blank">"wp.tengyuan.icu"</a></span>,</div></div>
<div class="line"><div class="line-content indent">},</div></div>
<div class="line"><div class="line-content indent"><span class="keyword">links</span>: {</div></div>
<div class="line"><div class="line-content indent-2"><span class="keyword">travel blog</span>: <span class="string"><a href="http://blog.tengyuan.icu/" target="_blank">"blog.tengyuan.icu"</a></span>,</div></div>
<div class="line"><div class="line-content indent-2"><span class="keyword">birthday</span>: <span class="string"><a href="http://sr.0814.cn" target="_blank">"2001/11/01"</a></span>,</div></div>
<div class="line"><div class="line-content indent">},</div></div>
<div class="line"><div class="line-content indent"><span class="comment">// 座右铭</span></div></div>
<div class="line"><div class="line-content indent"><span class="keyword">motto</span>: <span class="string">"以清简代码,筑玖维数字宇宙。"</span>,</div></div>
<div class="line"><div class="line-content indent"><span class="keyword">copyright</span>: <span class="string">"2017-<span id="year"></span> 藤原"</span>,</div></div>
<div class="line"><div class="line-content">};</div></div>
<div class="line"><div class="line-content"><span class="comment">// 终端交互</span></div></div>
<div class="line"><div class="line-content"><span class="function">console</span>.<span class="function">log</span>(<span class="string">"欢迎访问藤原的个人终端"</span>);</div></div>
<div class="line"><div class="line-content"><span class="function">console</span>.<span class="function">log</span>(<span class="string">"输入 'help' 获取可用命令"</span>);</div></div>
`;
}
return { message: '', isError: false };
}
if (cmd === 'history') {
if (commandHistory.length === 0) {
return { message: '没有命令历史记录', isError: false };
}
return {
message: commandHistory.map((cmd, i) => `${i + 1}: ${cmd}`).join('\n'),
isError: false
};
}
if (cmd === 'theme') {
themeManager.toggleTheme();
return { message: `已切换到${currentTheme === 'dark' ? '亮色' : '暗色'}主题`, isError: false };
}
if (cmd === 'weather') {
weatherManager.showWeatherModal();
return { message: '已打开天气详情窗口', isError: false };
}
if (cmd.startsWith('base64')) {
const parts = command.split(' ');
const action = parts[1]?.toLowerCase();
const text = parts.slice(2).join(' ');
if (!action || !text) {
return { message: '使用方法: base64 [encode/decode] [text]', isError: true };
}
if (action === 'encode') {
try {
const encoded = btoa(
encodeURIComponent(text).replace(/%([0-9A-F]{2})/g, (_, p1) => {
return String.fromCharCode(Number.parseInt(p1, 16));
})
);
return { message: encoded, isError: false };
} catch (e) {
return { message: '编码失败: ' + e.message, isError: true };
}
} else if (action === 'decode') {
try {
const decoded = decodeURIComponent(
Array.from(atob(text), (c) => {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join('')
);
return { message: decoded, isError: false };
} catch (e) {
return { message: '解码失败: ' + e.message, isError: true };
}
} else {
return { message: '无效的操作,请使用 encode 或 decode', isError: true };
}
}
if (cmd.startsWith('video')) {
const url = command.split(' ')[1];
if (!url) {
return { message: '请提供视频URL', isError: true };
}
if (!url.startsWith('http')) {
return { message: '请提供有效的URL地址', isError: true };
}
this.createVideoPlayer(url);
return {
message: `正在解析视频: ${url}`,
isError: false
};
}
if (cmd.startsWith('ai')) {
const message = command.substring(2).trim();
if (!message) {
return { message: '请输入您想对AI说的话', isError: true };
}
this.sendAIMessage(message);
return { message: '', isError: false };
}
if (cmd.startsWith('image')) {
const format = command.split(' ')[1];
if (!format) {
return { message: '请指定目标图片格式,例如: image png', isError: true };
}
const validFormats = ['jpg', 'jpeg', 'png', 'webp', 'bmp'];
if (!validFormats.includes(format.toLowerCase())) {
return { message: `不支持的格式: ${format}。支持格式: ${validFormats.join(', ')}`, isError: true };
}
this.createImageConverter(format.toLowerCase());
return { message: `图片转换器已启动,目标格式: ${format.toUpperCase()}`, isError: false };
}
if (cmd.startsWith('todo')) {
const parts = command.split(' ');
const action = parts[1];
const text = parts.slice(2).join(' ');
return this.manageTodo(action, text);
}
return { message: `未知命令: ${command}。输入 "help" 获取可用命令。`, isError: true };
},
addToTerminal(text, type) {
const content = document.getElementById('terminal-content');
if (!content) return;
const div = document.createElement('div');
if (type === 'command') {
div.innerHTML = `<div class="line"><div class="line-content"><span class="terminal-prompt">></span> <span class="user-input">${text.substring(2)}</span></div></div>`;
} else {
const lines = text.split('\n');
const lineElements = lines.map(line =>
`<div class="line"><div class="line-content ${type === 'error' ? 'ai-output' : 'ai-output'}">${type === 'error' ? '错误: ' : '藤原: '}${line}</div></div>`
).join('');
div.innerHTML = lineElements;
}
content.appendChild(div);
content.scrollTop = content.scrollHeight;
},
createVideoPlayer(url) {
const content = document.getElementById('terminal-content');
if (!content) return;
const videoContainer = document.createElement('div');
videoContainer.className = 'video-container';
const iframe = document.createElement('iframe');
iframe.src = `https://www.yemu.xyz/?url=${encodeURIComponent(url)}`;
iframe.style.width = '100%';
iframe.style.height = '300px';
iframe.style.border = 'none';
const videoInfo = document.createElement('div');
videoInfo.className = 'video-info';
videoInfo.textContent = '视频播放器 - 点击关闭按钮可关闭播放器';
const closeBtn = document.createElement('div');
closeBtn.className = 'video-command';
closeBtn.textContent = '关闭视频';
closeBtn.addEventListener('click', () => {
videoContainer.remove();
});
videoContainer.appendChild(iframe);
videoContainer.appendChild(videoInfo);
videoContainer.appendChild(closeBtn);
content.appendChild(videoContainer);
content.scrollTop = content.scrollHeight;
},
createImageConverter(format) {
const content = document.getElementById('terminal-content');
if (!content) return;
const converter = document.createElement('div');
converter.className = 'image-converter';
const title = document.createElement('div');
title.style.marginBottom = '15px';
title.style.color = 'var(--ai-output-color)';
title.textContent = `图片转换器 - 目标格式: ${format.toUpperCase()}`;
const selectBtn = document.createElement('button');
selectBtn.className = 'image-btn';
selectBtn.textContent = '选择图片文件';
selectBtn.addEventListener('click', () => {
const fileInput = document.getElementById('fileInput');
if (fileInput) fileInput.click();
});
const preview = document.createElement('div');
preview.id = 'imagePreview';
preview.style.marginTop = '15px';
preview.style.textAlign = 'center';
converter.appendChild(title);
converter.appendChild(selectBtn);
converter.appendChild(preview);
content.appendChild(converter);
content.scrollTop = content.scrollHeight;
// 文件选择处理
const fileInput = document.getElementById('fileInput');
if (fileInput) {
fileInput.onchange = (e) => {
const file = e.target.files[0];
if (!file || !file.type.match('image.*')) {
this.addToTerminal('请选择有效的图片文件', 'error');
return;
}
const reader = new FileReader();
reader.onload = (event) => {
preview.innerHTML = `
<img src="${event.target.result}" style="max-width: 100%; max-height: 200px; border-radius: var(--border-radius); margin: 10px 0;">
<br>
<button class="image-btn" onclick="terminalManager.convertImage('${event.target.result}', '${format}')">转换为 ${format.toUpperCase()}</button>
`;
};
reader.readAsDataURL(file);
};
}
},
convertImage(dataUrl, format) {
const img = new Image();
img.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
const mimeType = format === 'jpg' || format === 'jpeg' ? 'image/jpeg' : `image/${format}`;
canvas.toBlob((blob) => {
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = `converted-image.${format}`;
link.click();
this.addToTerminal(`图片已转换为 ${format.toUpperCase()} 格式并开始下载`, 'output');
}, mimeType, 0.8);
};
img.src = dataUrl;
},
manageTodo(action, text) {
const todos = JSON.parse(localStorage.getItem('todos') || '[]');
switch(action) {
case 'add':
if (!text) {
return { message: '请提供待办事项内容', isError: true };
}
todos.push({
id: Date.now(),
text: text,
completed: false,
date: new Date().toISOString()
});
localStorage.setItem('todos', JSON.stringify(todos));
return { message: `已添加待办事项: ${text}`, isError: false };
case 'list':
if (todos.length === 0) {
return { message: '没有待办事项', isError: false };
}
let todoList = '待办事项列表:\n';
todos.forEach((todo, index) => {
todoList += `${index + 1}. [${todo.completed ? '✓' : ' '}] ${todo.text}\n`;
});
return { message: todoList, isError: false };
case 'done':
const index = parseInt(text) - 1;
if (isNaN(index) || index < 0 || index >= todos.length) {
return { message: '无效的待办事项编号', isError: true };
}
todos[index].completed = true;
localStorage.setItem('todos', JSON.stringify(todos));
return { message: `已完成待办事项: ${todos[index].text}`, isError: false };
case 'remove':
const removeIndex = parseInt(text) - 1;
if (isNaN(removeIndex) || removeIndex < 0 || removeIndex >= todos.length) {
return { message: '无效的待办事项编号', isError: true };
}
const removedTodo = todos.splice(removeIndex, 1)[0];
localStorage.setItem('todos', JSON.stringify(todos));
return { message: `已删除待办事项: ${removedTodo.text}`, isError: false };
default:
return { message: '使用方法: todo [add/list/done/remove] [内容/编号]', isError: false };
}
},
async sendAIMessage(message) {
const content = document.getElementById('terminal-content');
if (!content) return;
// 显示思考动画
const thinkingDiv = document.createElement('div');
thinkingDiv.innerHTML = `
<div class="line">
<div class="line-content ai-output">
藤原: 正在思考中
<div class="thinking-animation">
<span></span>
<span></span>
<span></span>
</div>
</div>
</div>
`;
content.appendChild(thinkingDiv);
content.scrollTop = content.scrollHeight;
try {
const response = await fetch('https://api.deepseek.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer sk-a676938665e04742b75ce9e77e5e6d44'
},
body: JSON.stringify({
model: "deepseek-chat",
messages: [
{
role: "system",
content: "你是藤原的个人AI助手,请用简洁、友好的语气回答问题。回答要准确、有用,并且符合中文表达习惯。"
},
{
role: "user",
content: message
}
],
temperature: 0.7,
max_tokens: 2000,
stream: false
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
// 移除思考动画
thinkingDiv.remove();
if (data.choices && data.choices[0].message) {
this.addToTerminal(data.choices[0].message.content, 'output');
} else {
this.addToTerminal('无法获取AI回复,请稍后再试', 'error');
}
} catch (error) {
// 移除思考动画
thinkingDiv.remove();
console.error('AI请求详细错误:', error);
// 更详细的错误处理
let errorMessage = 'AI请求失败: ';
if (error.name === 'TypeError' && error.message.includes('fetch')) {
errorMessage += '网络连接失败,请检查网络连接';
} else if (error.message.includes('401')) {
errorMessage += 'API密钥无效或已过期';
} else if (error.message.includes('429')) {
errorMessage += 'API请求频率过高,请稍后再试';
} else if (error.message.includes('500')) {
errorMessage += 'AI服务暂时不可用,请稍后再试';
} else {
errorMessage += error.message;
}
this.addToTerminal(errorMessage, 'error');
}
}
};
// ==================== 初始化 ====================
document.addEventListener('DOMContentLoaded', () => {
// 初始化各个管理器
try {
themeManager.init();
navigationManager.init();
timeManager.init();
searchManager.init();
terminalManager.init();
weatherManager.init();
} catch (error) {
console.error('初始化失败:', error);
}
// 图片加载错误处理
document.addEventListener('error', (e) => {
if (e.target.tagName === 'IMG') {
e.target.src = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJjdXJyZW50Q29sb3IiPjxwYXRoIGQ9Ik0xMiAyQzYuNDggMiAyIDYuNDggMiAxMnM0LjQ4IDEwIDEwIDEwIDEwLTQuNDggMTAtMTBTMTcuNTIgMiAxMiAyem0tMiAxNWwtNS01aDN2LThoMnY4aDNsLTMgNXoiLz48L3N2Zz4=';
}
}, true);
console.log('TENG YUAN 系统已初始化完成!');
});
</script>
</body>
</html>
index.html
style.css
index.js