249 lines
27 KiB
HTML
249 lines
27 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="filename" content="audio-to-text-tool.html">
|
||
<title>录音文件转文字工具</title>
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&family=Noto+Sans+SC:wght@400;500;700&display=swap" rel="stylesheet">
|
||
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
|
||
<!-- 使用页面内样式,避免旧样式冲突 -->
|
||
<style>
|
||
/* 省略:保留你提供的全部样式,未改动 */
|
||
:root { --primary: #4361ee; --primary-light: #5a9cff; --primary-dark: #3a0ca3; --success: #41d6a4; --warning: #ffb020; --error: #ff4d4f; --bg-light: #f9fafc; --bg-dark: #101827; --text-light: #111827; --text-dark: #e2e8f0; --card-bg-light: #ffffff; --card-bg-dark: #1e293b; --border-light: #e2e8f0; --border-dark: #334155; --gray-100: #f1f5f9; --gray-200: #e2e8f0; --gray-300: #cbd5e1; --gray-700: #334155; --font-main: 'Poppins', 'Noto Sans SC', system-ui, sans-serif; --font-secondary: 'SF Pro', 'Helvetica Neue', sans-serif; --radius: 16px; --shadow: 0 10px 20px rgba(0, 0, 0, 0.08); --shadow-dark: 0 10px 20px rgba(0, 0, 0, 0.2); --transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); }
|
||
* { margin:0; padding:0; box-sizing:border-box; }
|
||
body { background: linear-gradient(135deg, #f0f4ff 0%, #e6f0ff 100%); color: var(--text-light); font-family: var(--font-main); margin: 0; padding: 0; display: flex; justify-content: center; min-height: 100vh; transition: var(--transition); }
|
||
body.dark-mode { background: linear-gradient(135deg, #0c142a 0%, #101e3c 100%); color: var(--text-dark); }
|
||
::-webkit-scrollbar { width:8px; } ::-webkit-scrollbar-track { background: var(--gray-100); border-radius:4px; } body.dark-mode ::-webkit-scrollbar-track { background: var(--gray-700);} ::-webkit-scrollbar-thumb { background: var(--primary); border-radius:4px; }
|
||
.app-container { width:100%; max-width:1400px; margin:2rem; }
|
||
.navbar { display:flex; justify-content:space-between; align-items:center; margin-bottom:2.5rem; padding:0.5rem 1rem; background: var(--card-bg-light); border-radius: var(--radius); box-shadow: var(--shadow); transition: var(--transition); }
|
||
body.dark-mode .navbar { background: var(--card-bg-dark); box-shadow: var(--shadow-dark); }
|
||
.brand { display:flex; align-items:center; gap:16px; }
|
||
.logo-svg { height:44px; width:44px; background: linear-gradient(135deg, var(--primary), var(--primary-dark)); border-radius:12px; display:flex; align-items:center; justify-content:center; }
|
||
.logo-svg svg { width:24px; height:24px; fill:white; }
|
||
.brand-info h1 { font-size:1.8rem; font-weight:700; margin-bottom:4px; color: var(--primary); letter-spacing:-0.5px; }
|
||
.brand-info p { font-size:0.9rem; color: var(--gray-700); }
|
||
body.dark-mode .brand-info p { color: var(--gray-300);}
|
||
.navbar-controls { display:flex; align-items:center; gap:1.5rem; }
|
||
.language-select { padding:0.8rem 1.4rem; background: var(--card-bg-light); border:1px solid var(--border-light); border-radius:12px; cursor:pointer; display:flex; align-items:center; gap:12px; transition: var(--transition); font-weight:500; }
|
||
body.dark-mode .language-select { background: var(--card-bg-dark); border-color: var(--border-dark);}
|
||
.language-select:hover { border-color: var(--primary);}
|
||
.theme-toggle { background: var(--card-bg-light); border:1px solid var(--border-light); height:50px; width:50px; border-radius:50%; display:flex; align-items:center; justify-content:center; cursor:pointer; transition: var(--transition);}
|
||
body.dark-mode .theme-toggle { background: var(--card-bg-dark); border-color: var(--border-dark);}
|
||
.theme-toggle:hover { background: var(--gray-100); transform: rotate(20deg);} body.dark-mode .theme-toggle:hover { background: rgba(255,255,255,0.1);}
|
||
.content-grid { display:grid; grid-template-columns: 1fr 1fr 1fr; gap:2rem; margin-bottom:2rem; }
|
||
@media (max-width:1200px){ .content-grid { grid-template-columns: 1fr 1fr; } } @media (max-width:768px){ .content-grid { grid-template-columns: 1fr; } }
|
||
.card { border-radius: var(--radius); overflow:hidden; box-shadow: var(--shadow); background: var(--card-bg-light); transition: var(--transition); position:relative; margin-bottom:2rem; }
|
||
body.dark-mode .card { background: var(--card-bg-dark); box-shadow: var(--shadow-dark);}
|
||
.card:hover { transform: translateY(-5px); box-shadow: 0 15px 30px rgba(0,0,0,0.15);} body.dark-mode .card:hover { box-shadow: 0 15px 30px rgba(0,0,0,0.3);}
|
||
.card-header { padding:1.8rem 1.8rem 1.2rem; display:flex; align-items:center; font-weight:600; gap:0.75rem; border-bottom:1px solid var(--border-light); font-size:1.2rem; color: var(--primary);} body.dark-mode .card-header { border-bottom:1px solid var(--border-dark);}
|
||
.card-body { padding:2rem; }
|
||
.upload-area { display:flex; flex-direction:column; align-items:center; justify-content:center; text-align:center; padding:4rem 2rem; border:2px dashed var(--border-light); border-radius: var(--radius); cursor:pointer; transition: var(--transition); position:relative; background: rgba(67,97,238,0.03);} body.dark-mode .upload-area { border-color: var(--border-dark); background: rgba(33,66,164,0.05);} .upload-area:hover { border-color: var(--primary); background: rgba(67,97,238,0.08);} .upload-area.active { background: rgba(67,97,238,0.1); border-color: var(--primary); border-style: solid; }
|
||
.upload-icon { font-size:4.5rem; color: var(--primary); margin-bottom:1.5rem; display:flex; align-items:center; justify-content:center; }
|
||
.upload-text { font-size:1.4rem; margin-bottom:1.2rem; font-weight:500; color: var(--text-light);} body.dark-mode .upload-text { color: var(--text-dark);}
|
||
.upload-info { color: var(--gray-700); font-size:1rem; margin-bottom:1.5rem; max-width:90%; } body.dark-mode .upload-info { color: var(--gray-300);}
|
||
.file-input { opacity:0; position:absolute; top:0; left:0; width:100%; height:100%; cursor:pointer; z-index:2; }
|
||
.btn { padding:1.1rem 3rem; border-radius: var(--radius); border:none; cursor:pointer; font-weight:600; transition: var(--transition); display:inline-flex; align-items:center; justify-content:center; gap:12px; font-size:1.1rem; position:relative; overflow:hidden; z-index:1; }
|
||
.btn::after { content:''; position:absolute; width:100%; height:0; top:50%; left:50%; background: rgba(255,255,255,0.2); opacity:0; transform: translateX(-50%) translateY(-50%) rotate(0deg); transition: all .5s; z-index:-1; } .btn:hover::after { height:350%; opacity:1;} .btn:active::after { height:500%; opacity:0; }
|
||
.btn-primary { background: linear-gradient(90deg, var(--primary), var(--primary-light)); color:white; box-shadow: 0 8px 20px rgba(67,97,238,0.3);} .btn-primary:hover { background: linear-gradient(90deg, var(--primary-dark), var(--primary)); box-shadow: 0 12px 25px rgba(58,12,163,0.4);}
|
||
.btn-secondary { background: var(--gray-100); color: var(--text-light);} body.dark-mode .btn-secondary { background: var(--gray-700); color: var(--text-dark);}
|
||
.btn-success { background: var(--success); color:white; box-shadow: 0 8px 20px rgba(65,214,164,0.3);} .btn-success:hover { background:#2a9d7d; box-shadow: 0 12px 25px rgba(42,157,125,0.4);}
|
||
.status-grid { display:grid; grid-template-columns: 1fr 1fr; gap:2rem; margin-bottom:2rem; }
|
||
.progress-container { width:100%; display:flex; flex-direction:column; justify-content:center; }
|
||
.progress-header { display:flex; justify-content:space-between; margin-bottom:1.5rem; }
|
||
.progress-label { font-size:1.25rem; font-weight:500; color: var(--text-light);} body.dark-mode .progress-label { color: var(--text-dark);}
|
||
.progress-percent { font-weight:700; color: var(--primary); font-size:1.4rem; }
|
||
.progress-bar { height:16px; background-color: var(--gray-200); border-radius:8px; overflow:hidden; } body.dark-mode .progress-bar { background-color: var(--gray-700);}
|
||
.progress-fill { height:100%; background: linear-gradient(90deg, var(--primary), var(--primary-light)); border-radius:8px; width:0%; transition: width 0.4s ease; box-shadow: 2px 0 10px rgba(67,97,238,0.4);}
|
||
.progress-info { display:flex; justify-content:space-between; margin-top:1rem; font-size:1rem; color: var(--gray-700);} body.dark-mode .progress-info { color: var(--gray-300);}
|
||
.status-animation { display:flex; align-items:center; justify-content:center; height:160px;} .sound-wave { display:flex; align-items:center; height:130px; gap:12px;} .sound-bar { width:10px; background-color: var(--primary); border-radius:5px; animation: sound-wave 1.2s ease-in-out infinite; box-shadow: 0 0 10px rgba(67,97,238,0.3);} @keyframes sound-wave { 0%,100%{ transform: scaleY(0.7) translateY(10px); background-color: var(--primary-light);} 50%{ transform: scaleY(1.5) translateY(0); background-color: var(--primary);} } .sound-bar:nth-child(1){ height:30px; animation-delay:0s;} .sound-bar:nth-child(2){ height:50px; animation-delay:0.1s;} .sound-bar:nth-child(3){ height:70px; animation-delay:0.2s;} .sound-bar:nth-child(4){ height:100px; animation-delay:0.3s;} .sound-bar:nth-child(5){ height:70px; animation-delay:0.4s;} .sound-bar:nth-child(6){ height:50px; animation-delay:0.5s;} .sound-bar:nth-child(7){ height:30px; animation-delay:0.6s;}
|
||
.status-detail { text-align:center; margin-top:2rem;} .status-detail p { font-size:1.2rem; margin-bottom:0.5rem; line-height:1.7;} .highlight-text { color: var(--primary); font-weight:700; display:inline-block; }
|
||
.result-container { display:grid; grid-template-columns: 1fr 1fr; gap:2rem; } @media (max-width:1200px){ .result-container { grid-template-columns: 1fr; } }
|
||
.audio-player-section { display:flex; flex-direction:column; gap:2rem; }
|
||
.audio-cover { width:100%; height:280px; border-radius: var(--radius); background-color: var(--gray-200); background-image: url('https://images.unsplash.com/photo-1505740420928-5e560c06d30e?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1000&q=80'); background-size: cover; background-position:center; position:relative; overflow:hidden; box-shadow: inset 0 -60px 40px -20px rgba(0,0,0,0.7);}
|
||
.audio-info { position:absolute; bottom:0; left:0; right:0; padding:2rem; color:white; } .audio-info h3 { font-size:1.8rem; margin-bottom:0.7rem; font-weight:700; text-shadow: 0 2px 4px rgba(0,0,0,0.5);} .audio-info p { opacity:0.9; font-size:1.1rem; text-shadow: 0 1px 2px rgba(0,0,0,0.5);}
|
||
.audio-controls { background: var(--card-bg-light); border-radius: var(--radius); padding:2rem; display:flex; flex-direction:column; gap:1.5rem; box-shadow: var(--shadow);} body.dark-mode .audio-controls { background: var(--card-bg-dark); box-shadow: var(--shadow-dark);}
|
||
.control-bar { display:flex; align-items:center; gap:1.8rem; } .play-btn { width:60px; height:60px; border-radius:50%; background: linear-gradient(135deg, var(--primary), var(--primary-dark)); color:white; display:flex; align-items:center; justify-content:center; border:none; cursor:pointer; transition: var(--transition); box-shadow: 0 6px 15px rgba(58,12,163,0.5);} .play-btn:hover { transform: scale(1.08); box-shadow: 0 8px 20px rgba(58,12,163,0.7);}
|
||
.progress-audio { flex:1; position:relative; } .progress-seek { width:100%; height:8px; background: var(--gray-200); border-radius:4px; cursor:pointer; position:relative;} body.dark-mode .progress-seek { background: var(--gray-700);} .progress-current { height:100%; background: linear-gradient(90deg, var(--primary), var(--primary-light)); border-radius:4px; position:absolute; top:0; left:0; width:0%; transition: width 0.2s ease;}
|
||
.time-indicators { display:flex; justify-content:space-between; margin-top:0.8rem; font-size:1rem; font-weight:500; color: var(--gray-700);} body.dark-mode .time-indicators { color: var(--gray-300);}
|
||
.secondary-controls { display:flex; justify-content:space-between; align-items:center;} .control-group { display:flex; align-items:center; gap:1.5rem;} .control-btn { background: rgba(67,97,238,0.1); border:none; width:42px; height:42px; border-radius:12px; display:flex; align-items:center; justify-content:center; cursor:pointer; color: var(--primary); transition: var(--transition);} body.dark-mode .control-btn { background: rgba(67,97,238,0.15);} .control-btn:hover { background: rgba(67,97,238,0.2); transform: translateY(-3px);} body.dark-mode .control-btn:hover { background: rgba(67,97,238,0.3);}
|
||
.dropdown { background: var(--card-bg-light); border:1px solid var(--border-light); border-radius:12px; padding:0.6rem 1.2rem; font-weight:500; font-size:1rem;} body.dark-mode .dropdown { background: var(--card-bg-dark); border:1px solid var(--border-dark);}
|
||
.transcript-area { display:flex; flex-direction:column; height:100%; gap:1.5rem;}
|
||
.transcript-content { flex:1; background: var(--card-bg-light); border-radius: var(--radius); padding:2.2rem; overflow-y:auto; box-shadow: var(--shadow);} body.dark-mode .transcript-content { background: var(--card-bg-dark); box-shadow: var(--shadow-dark);}
|
||
.transcript-header { display:flex; justify-content:space-between; align-items:center; margin-bottom:1.8rem; padding-bottom:1.2rem; border-bottom:1px solid var(--border-light);} body.dark-mode .transcript-header { border-bottom-color: var(--border-dark);}
|
||
.speaker-tags { display:flex; gap:1rem; flex-wrap:wrap; }
|
||
.speaker-tag { background: var(--primary); color:white; padding:0.45rem 1.3rem; border-radius:24px; font-size:1rem; font-weight:600; box-shadow: 0 4px 8px rgba(0,0,0,0.1);}
|
||
.tag-1 { background: linear-gradient(90deg, #4361ee, #4895ef);} .tag-2 { background: linear-gradient(90deg, #41d6a4, #2e9d7d);} .tag-3 { background: linear-gradient(90deg, #f15bb5, #ae3f85);}
|
||
.tool-btn { background: rgba(67,97,238,0.1); border:none; padding:0.7rem 1.2rem; border-radius:8px; cursor:pointer; color: var(--primary); font-weight:500; transition: var(--transition);} .tool-btn:hover { background: rgba(67,97,238,0.2);}
|
||
.transcript-lines { display:flex; flex-direction:column; gap:1.5rem; }
|
||
.transcript-line { padding:1.5rem; border-radius:14px; transition: var(--transition); position:relative; cursor:pointer; }
|
||
body.dark-mode .transcript-line { background: rgba(255,255,255,0.03);} .transcript-line:not(.active):hover { background: rgba(67,97,238,0.05);} .transcript-line.active { background: rgba(67,97,238,0.1); border-left:5px solid var(--primary); box-shadow: 0 4px 12px rgba(67,97,238,0.1);}
|
||
.timestamp { font-size:0.9rem; font-weight:600; color: var(--primary); margin-bottom:0.5rem; display:block; background: rgba(67,97,238,0.1); padding:0.3rem 0.8rem; border-radius:20px; display:inline-block; transition: var(--transition);} body.dark-mode .timestamp { color: var(--primary-light);} .timestamp:hover { background: rgba(67,97,238,0.2);}
|
||
.speaker { font-weight:700; font-size:1.1rem; margin-right:0.5rem; display:inline-block; padding:0.3rem 1rem; border-radius:18px; color:white; }
|
||
.text-content { line-height:1.75; margin-top:0.8rem; font-size:1.05rem; }
|
||
.action-bar { display:flex; justify-content:flex-end; gap:1.5rem; padding:1.5rem 0 0; }
|
||
.action-btn { padding:1.1rem 2.2rem; border-radius: var(--radius); border:none; cursor:pointer; font-weight:600; transition: var(--transition); display:inline-flex; align-items:center; gap:10px; font-size:1.1rem; }
|
||
.action-success { background: var(--success); color:white; box-shadow: 0 8px 20px rgba(65,214,164,0.3);} .action-secondary { background: var(--gray-100); color: var(--text-light);} body.dark-mode .action-secondary { background: var(--gray-700); color: var(--text-dark);} .action-secondary:hover { background: var(--gray-200);} body.dark-mode .action-secondary:hover { background: var(--gray-600);}
|
||
.footer { text-align:center; padding:2rem; color: var(--gray-700); font-size:0.95rem; margin-top:2rem; border-top:1px solid var(--border-light);} body.dark-mode .footer { color: var(--gray-300); border-top-color: var(--border-dark);}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="app-container">
|
||
<div class="navbar">
|
||
<div class="brand">
|
||
<div class="logo-svg">
|
||
<svg viewBox="0 0 24 24"><path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/></svg>
|
||
</div>
|
||
<div class="brand-info">
|
||
<h1>AudioToText Pro</h1>
|
||
<p>智能语音识别与转换解决方案</p>
|
||
</div>
|
||
</div>
|
||
<div class="navbar-controls">
|
||
<div class="language-select">
|
||
<i class="fas fa-globe"></i>
|
||
<span>自动检测语言</span>
|
||
<i class="fas fa-chevron-down"></i>
|
||
</div>
|
||
<button class="theme-toggle" id="themeToggle"><i class="fas fa-moon"></i></button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="content-grid">
|
||
<div class="card">
|
||
<div class="card-header"><i class="fas fa-file-upload"></i><span>上传录音文件</span></div>
|
||
<div class="card-body">
|
||
<div class="upload-area" id="uploadArea">
|
||
<div class="upload-icon"><i class="fas fa-cloud-upload-alt"></i></div>
|
||
<p class="upload-text">拖拽录音文件到这里或点击上传</p>
|
||
<p class="upload-info">支持 MP3, WAV, FLAC, AAC, M4A 等格式,最大500MB</p>
|
||
<button class="btn btn-primary" onclick="document.getElementById('fileInput').click()"><i class="fas fa-upload"></i> 选择文件</button>
|
||
<input type="file" class="file-input" id="fileInput" accept="audio/*">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-header"><i class="fas fa-arrow-up"></i><span>上传状态</span></div>
|
||
<div class="card-body">
|
||
<div class="progress-container">
|
||
<div class="progress-header"><span class="progress-label">文件上传进度</span><span class="progress-percent" id="uploadPercent">0%</span></div>
|
||
<div class="progress-bar"><div class="progress-fill" id="uploadFill"></div></div>
|
||
<div class="progress-info"><span id="uploadFileName">未选择文件</span><span id="uploadEta">准备就绪</span></div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card" id="analysisCard">
|
||
<div class="card-header"><i class="fas fa-cogs"></i><span>转写分析</span></div>
|
||
<div class="card-body">
|
||
<div class="status-animation"><div class="sound-wave"><div class="sound-bar"></div><div class="sound-bar"></div><div class="sound-bar"></div><div class="sound-bar"></div><div class="sound-bar"></div><div class="sound-bar"></div><div class="sound-bar"></div></div></div>
|
||
<div class="status-detail">
|
||
<p>AI正在分析音频内容,识别不同发言者</p>
|
||
<p>转写用时 <span class="highlight-text" id="analysisProgress">00:00</span></p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-body">
|
||
<div class="result-container">
|
||
<div class="audio-player-section">
|
||
<div class="audio-cover"><div class="audio-info"><h3 id="audioTitle">录音文件</h3><p id="audioMeta">—</p></div></div>
|
||
<div class="audio-controls">
|
||
<div class="control-bar">
|
||
<button class="play-btn" id="playBtn"><i class="fas fa-play"></i></button>
|
||
<div class="progress-audio">
|
||
<div class="progress-seek"><div class="progress-current" id="audioProgress"></div></div>
|
||
<div class="time-indicators"><span id="currentTime">0:00</span><span id="totalTime">—</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="secondary-controls">
|
||
<div class="control-group">
|
||
<button class="control-btn" id="stepBack"><i class="fas fa-step-backward"></i></button>
|
||
<button class="control-btn" id="stepForward"><i class="fas fa-step-forward"></i></button>
|
||
<button class="control-btn" id="redoBtn"><i class="fas fa-redo"></i></button>
|
||
</div>
|
||
<div class="control-group">
|
||
<button class="control-btn"><i class="fas fa-volume-up"></i></button>
|
||
<div class="dropdown"><select id="speedSelect"><option>1.0x</option><option>0.75x</option><option>1.25x</option><option>1.5x</option><option>2.0x</option></select></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="transcript-area">
|
||
<div class="transcript-header">
|
||
<div class="speaker-tags" id="speakerTags"></div>
|
||
<button class="tool-btn" id="editToggle"><i class="fas fa-edit"></i> 编辑</button>
|
||
<button class="tool-btn" id="saveSpkBtn" style="display:none"><i class="fas fa-save"></i> 保存</button>
|
||
</div>
|
||
<div class="transcript-content">
|
||
<div class="transcript-lines" id="transcriptLines"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="action-bar">
|
||
<button class="action-secondary action-btn" id="convertBtn"><i class="fas fa-redo"></i> 重新转换</button>
|
||
<button class="action-secondary action-btn" id="copyAllBtn"><i class="fas fa-copy"></i> 复制全文</button>
|
||
<button class="action-success action-btn" id="exportBtn"><i class="fas fa-download"></i> 导出文件</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 调试日志卡片(置底) -->
|
||
<div class="card">
|
||
<div class="card-header"><i class="fas fa-terminal"></i><span>调试日志</span></div>
|
||
<div class="card-body">
|
||
<div class="action-bar" style="justify-content: flex-end; padding: 0; margin-bottom: 1rem;">
|
||
<button class="tool-btn" id="copyDebugBtn"><i class="fas fa-copy"></i> 复制日志全文</button>
|
||
</div>
|
||
<div class="transcript-content" style="max-height: 40vh;">
|
||
<pre id="debugLog">等待提交…</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="footer"><p>AudioToText Pro © 2025 | 高精度语音识别解决方案</p></div>
|
||
</div>
|
||
|
||
<!-- 主题与上传交互保留;识别、渲染由 main.js 接管 -->
|
||
<script>
|
||
const themeToggle = document.getElementById('themeToggle');
|
||
const body = document.body;
|
||
const savedTheme = localStorage.getItem('theme');
|
||
if (savedTheme === 'dark') { body.classList.add('dark-mode'); themeToggle.innerHTML = '<i class="fas fa-sun"></i>'; }
|
||
themeToggle.addEventListener('click', () => {
|
||
body.classList.toggle('dark-mode');
|
||
if (body.classList.contains('dark-mode')) { themeToggle.innerHTML = '<i class="fas fa-sun"></i>'; localStorage.setItem('theme', 'dark'); }
|
||
else { themeToggle.innerHTML = '<i class="fas fa-moon"></i>'; localStorage.setItem('theme', 'light'); }
|
||
});
|
||
const uploadArea = document.getElementById('uploadArea');
|
||
const fileInput = document.getElementById('fileInput');
|
||
uploadArea.addEventListener('dragover', (e) => { e.preventDefault(); uploadArea.classList.add('active'); });
|
||
uploadArea.addEventListener('dragleave', () => { uploadArea.classList.remove('active'); });
|
||
function startAnalysisTimer(){ const el=document.getElementById('analysisProgress'); const started=Date.now(); if (!startAnalysisTimer._timer){ startAnalysisTimer._timer=setInterval(()=>{ const ms=Date.now()-started; const mm=Math.floor(ms/60000).toString().padStart(2,'0'); const ss=Math.floor((ms%60000)/1000).toString().padStart(2,'0'); el.textContent=`${mm}:${ss}`; },1000);} }
|
||
uploadArea.addEventListener('drop', (e) => { e.preventDefault(); uploadArea.classList.remove('active'); if (e.dataTransfer.files.length) { fileInput.files = e.dataTransfer.files; const f=e.dataTransfer.files[0]; document.getElementById('uploadFileName').textContent=f.name; document.getElementById('uploadPercent').textContent='100%'; document.getElementById('uploadFill').style.width='100%'; startAnalysisTimer(); } });
|
||
fileInput.addEventListener('change', () => { if (fileInput.files.length){ const f=fileInput.files[0]; document.getElementById('uploadFileName').textContent=f.name; document.getElementById('uploadPercent').textContent='100%'; document.getElementById('uploadFill').style.width='100%'; startAnalysisTimer(); } });
|
||
const copyDebugBtn = document.getElementById('copyDebugBtn');
|
||
copyDebugBtn?.addEventListener('click', async () => { try { const txt = document.getElementById('debugLog')?.textContent || ''; await navigator.clipboard.writeText(txt); } catch(e){} });
|
||
const playBtn = document.getElementById('playBtn');
|
||
playBtn.addEventListener('click', () => { const icon=playBtn.querySelector('i'); icon.classList.toggle('fa-play'); icon.classList.toggle('fa-pause'); });
|
||
</script>
|
||
<script>
|
||
(function(){
|
||
function wlog(msg){
|
||
try{var el=document.getElementById('debugLog'); if(el){ var ts=new Date().toISOString(); el.textContent = (el.textContent&&el.textContent!=='等待提交…'? (el.textContent+'\n'): '') + '['+ts+'] '+msg; }}catch(e){}
|
||
}
|
||
window.addEventListener('error', function(e){ wlog('全局错误: '+ (e.message||e.error||e.filename||'unknown')); });
|
||
window.addEventListener('unhandledrejection', function(e){ wlog('未捕获的Promise拒绝: '+ (e.reason&&e.reason.message?e.reason.message:JSON.stringify(e.reason||{}))); });
|
||
wlog('调试桥已安装');
|
||
})();
|
||
</script>
|
||
<script src="main.js?v=3"></script>
|
||
</body>
|
||
</html>
|