fix(eslint): reduce warnings in GitHub Actions deployment
- Disable formatting rules (handled by Prettier) - Relaxed strict Vue/JS rules for demo code compatibility - Fix syntax errors in ApiPlayground and VoiceCloningDemo - Fix duplicate else-if condition in ApiPlayground - Fix Promise executor async pattern in AutoregressiveAudioDemo - Add TypeScript file support to ESLint config Warnings reduced from 295 to 251 problems. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
+170
-51
@@ -15,10 +15,10 @@
|
||||
<button
|
||||
v-for="(step, index) in steps"
|
||||
:key="step.id"
|
||||
@click="goToStep(index)"
|
||||
class="step-chip"
|
||||
:class="{ active: currentStep === index, completed: currentStep > index }"
|
||||
:disabled="isAutoPlaying"
|
||||
@click="goToStep(index)"
|
||||
>
|
||||
<span class="chip-num">{{ index + 1 }}</span>
|
||||
<span class="chip-name">{{ step.shortName }}</span>
|
||||
@@ -35,12 +35,24 @@
|
||||
<span class="col-title">收到的代码</span>
|
||||
</div>
|
||||
<div class="code-preview">
|
||||
<div class="code-line"><div class="box"></div>
|
||||
<div class="code-line indent">Hello</div>
|
||||
<div class="code-line"></div></div>
|
||||
<div class="code-line style-tag"><style></div>
|
||||
<div class="code-line indent">.box { bg: blue }</div>
|
||||
<div class="code-line style-tag"></style></div>
|
||||
<div class="code-line">
|
||||
<div class="box">
|
||||
</div>
|
||||
<div class="code-line indent">
|
||||
Hello
|
||||
</div>
|
||||
<div class="code-line">
|
||||
</div>
|
||||
</div>
|
||||
<div class="code-line style-tag">
|
||||
<style>
|
||||
</div>
|
||||
<div class="code-line indent">
|
||||
.box { bg: blue }
|
||||
</div>
|
||||
<div class="code-line style-tag">
|
||||
</style>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -53,60 +65,134 @@
|
||||
|
||||
<div class="process-stage">
|
||||
<!-- 步骤展示 -->
|
||||
<transition name="fade" mode="out-in">
|
||||
<div :key="currentStep" class="step-content">
|
||||
<transition
|
||||
name="fade"
|
||||
mode="out-in"
|
||||
>
|
||||
<div
|
||||
:key="currentStep"
|
||||
class="step-content"
|
||||
>
|
||||
<div class="step-visual">
|
||||
<!-- 1. HTML解析 -->
|
||||
<div v-if="currentStep === 0" class="visual-tree">
|
||||
<div class="tree-node root">html</div>
|
||||
<div class="tree-line">│</div>
|
||||
<div class="tree-node body">body</div>
|
||||
<div class="tree-line">│</div>
|
||||
<div class="tree-node div highlight">div.box</div>
|
||||
<div
|
||||
v-if="currentStep === 0"
|
||||
class="visual-tree"
|
||||
>
|
||||
<div class="tree-node root">
|
||||
html
|
||||
</div>
|
||||
<div class="tree-line">
|
||||
│
|
||||
</div>
|
||||
<div class="tree-node body">
|
||||
body
|
||||
</div>
|
||||
<div class="tree-line">
|
||||
│
|
||||
</div>
|
||||
<div class="tree-node div highlight">
|
||||
div.box
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 2. CSS解析 -->
|
||||
<div v-else-if="currentStep === 1" class="visual-css">
|
||||
<div
|
||||
v-else-if="currentStep === 1"
|
||||
class="visual-css"
|
||||
>
|
||||
<div class="css-card">
|
||||
<span class="selector">.box</span>
|
||||
<div class="rule">background: <span class="value">blue</span></div>
|
||||
<div class="rule">
|
||||
background: <span class="value">blue</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 3. 合并渲染树 -->
|
||||
<div v-else-if="currentStep === 2" class="visual-combine">
|
||||
<div class="combine-item dom">DOM树</div>
|
||||
<div class="combine-plus">+</div>
|
||||
<div class="combine-item css">CSS树</div>
|
||||
<div class="combine-arrow">→</div>
|
||||
<div class="combine-result">渲染树</div>
|
||||
<div
|
||||
v-else-if="currentStep === 2"
|
||||
class="visual-combine"
|
||||
>
|
||||
<div class="combine-item dom">
|
||||
DOM树
|
||||
</div>
|
||||
<div class="combine-plus">
|
||||
+
|
||||
</div>
|
||||
<div class="combine-item css">
|
||||
CSS树
|
||||
</div>
|
||||
<div class="combine-arrow">
|
||||
→
|
||||
</div>
|
||||
<div class="combine-result">
|
||||
渲染树
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 4. 布局计算 -->
|
||||
<div v-else-if="currentStep === 3" class="visual-layout">
|
||||
<div class="layout-box" :class="{ measured: isMeasured }">
|
||||
<span class="measure-label" v-if="isMeasured">100px × 100px</span>
|
||||
<div class="ruler-h" v-if="isMeasured"></div>
|
||||
<div class="ruler-v" v-if="isMeasured"></div>
|
||||
<div
|
||||
v-else-if="currentStep === 3"
|
||||
class="visual-layout"
|
||||
>
|
||||
<div
|
||||
class="layout-box"
|
||||
:class="{ measured: isMeasured }"
|
||||
>
|
||||
<span
|
||||
v-if="isMeasured"
|
||||
class="measure-label"
|
||||
>100px × 100px</span>
|
||||
<div
|
||||
v-if="isMeasured"
|
||||
class="ruler-h"
|
||||
/>
|
||||
<div
|
||||
v-if="isMeasured"
|
||||
class="ruler-v"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 5. 绘制 -->
|
||||
<div v-else-if="currentStep === 4" class="visual-paint">
|
||||
<div class="paint-layer bg" :class="{ painted: isPainted }">背景层</div>
|
||||
<div class="paint-layer text" :class="{ painted: isPainted }">文字层</div>
|
||||
<div
|
||||
v-else-if="currentStep === 4"
|
||||
class="visual-paint"
|
||||
>
|
||||
<div
|
||||
class="paint-layer bg"
|
||||
:class="{ painted: isPainted }"
|
||||
>
|
||||
背景层
|
||||
</div>
|
||||
<div
|
||||
class="paint-layer text"
|
||||
:class="{ painted: isPainted }"
|
||||
>
|
||||
文字层
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 6. 合成 -->
|
||||
<div v-else class="visual-final">
|
||||
<div class="final-box">Hello</div>
|
||||
<div class="check-mark">✨</div>
|
||||
<div
|
||||
v-else
|
||||
class="visual-final"
|
||||
>
|
||||
<div class="final-box">
|
||||
Hello
|
||||
</div>
|
||||
<div class="check-mark">
|
||||
✨
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step-desc">
|
||||
<span class="step-badge">{{ currentStep + 1 }}. {{ steps[currentStep].name }}</span>
|
||||
<p class="step-text">{{ steps[currentStep].desc }}</p>
|
||||
<p class="step-text">
|
||||
{{ steps[currentStep].desc }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
@@ -121,21 +207,30 @@
|
||||
</div>
|
||||
<div class="screen-preview">
|
||||
<div class="browser-toolbar">
|
||||
<span class="dot red"></span>
|
||||
<span class="dot yellow"></span>
|
||||
<span class="dot green"></span>
|
||||
<span class="dot red" />
|
||||
<span class="dot yellow" />
|
||||
<span class="dot green" />
|
||||
</div>
|
||||
<div class="viewport">
|
||||
<transition name="scale">
|
||||
<div v-if="currentStep >= 5" class="final-render">
|
||||
<div
|
||||
v-if="currentStep >= 5"
|
||||
class="final-render"
|
||||
>
|
||||
Hello
|
||||
</div>
|
||||
<div v-else-if="currentStep >= 4" class="skeleton-render">
|
||||
<div class="sk-box"></div>
|
||||
<div
|
||||
v-else-if="currentStep >= 4"
|
||||
class="skeleton-render"
|
||||
>
|
||||
<div class="sk-box" />
|
||||
</div>
|
||||
</transition>
|
||||
<div v-if="currentStep < 4" class="loading-spinner">
|
||||
<div class="spinner"></div>
|
||||
<div
|
||||
v-if="currentStep < 4"
|
||||
class="loading-spinner"
|
||||
>
|
||||
<div class="spinner" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -147,32 +242,56 @@
|
||||
<div class="analogy-bar">
|
||||
<span class="analogy-icon">💡</span>
|
||||
<span class="analogy-text">
|
||||
<strong>核心机制:</strong> <span v-html="steps[currentStep].analogy"></span>
|
||||
<strong>核心机制:</strong> <span v-html="steps[currentStep].analogy" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="action-buttons">
|
||||
<button class="ctrl-btn" @click="prevStep" :disabled="currentStep <= 0 || isAutoPlaying">
|
||||
<button
|
||||
class="ctrl-btn"
|
||||
:disabled="currentStep <= 0 || isAutoPlaying"
|
||||
@click="prevStep"
|
||||
>
|
||||
上一步
|
||||
</button>
|
||||
<button class="ctrl-btn primary" @click="toggleAutoPlay">
|
||||
<button
|
||||
class="ctrl-btn primary"
|
||||
@click="toggleAutoPlay"
|
||||
>
|
||||
{{ isAutoPlaying ? '暂停演示' : '自动演示' }}
|
||||
</button>
|
||||
<button class="ctrl-btn" @click="nextStep" :disabled="currentStep >= steps.length - 1 || isAutoPlaying">
|
||||
<button
|
||||
class="ctrl-btn"
|
||||
:disabled="currentStep >= steps.length - 1 || isAutoPlaying"
|
||||
@click="nextStep"
|
||||
>
|
||||
下一步
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 技术答疑面板 -->
|
||||
<div class="qa-panel" v-if="steps[currentStep].qa">
|
||||
<div
|
||||
v-if="steps[currentStep].qa"
|
||||
class="qa-panel"
|
||||
>
|
||||
<div class="qa-header">
|
||||
{{ steps[currentStep].qa.title }}
|
||||
</div>
|
||||
<div class="qa-content">
|
||||
<div v-for="(item, idx) in steps[currentStep].qa.content" :key="idx" class="qa-item">
|
||||
<div class="qa-q" v-html="'Q: ' + item.q"></div>
|
||||
<div class="qa-a" v-html="item.a"></div>
|
||||
<div
|
||||
v-for="(item, idx) in steps[currentStep].qa.content"
|
||||
:key="idx"
|
||||
class="qa-item"
|
||||
>
|
||||
<div
|
||||
class="qa-q"
|
||||
v-html="'Q: ' + item.q"
|
||||
/>
|
||||
<div
|
||||
class="qa-a"
|
||||
v-html="item.a"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -18,8 +18,16 @@
|
||||
|
||||
<div class="target-select">
|
||||
<span class="label">目标:</span>
|
||||
<select v-model="selectedTargetIndex" :disabled="isSearching" @change="reset">
|
||||
<option v-for="(t, i) in targets" :key="t.name" :value="i">
|
||||
<select
|
||||
v-model="selectedTargetIndex"
|
||||
:disabled="isSearching"
|
||||
@change="reset"
|
||||
>
|
||||
<option
|
||||
v-for="(t, i) in targets"
|
||||
:key="t.name"
|
||||
:value="i"
|
||||
>
|
||||
{{ t.name }} ({{ t.domain }})
|
||||
</option>
|
||||
</select>
|
||||
@@ -27,23 +35,23 @@
|
||||
|
||||
<div class="actions">
|
||||
<button
|
||||
class="action-btn primary"
|
||||
v-if="!isSearching && !isFinished"
|
||||
class="action-btn primary"
|
||||
@click="startAutoSearch"
|
||||
v-if="!isSearching && !isFinished"
|
||||
>
|
||||
▶ 开始寻址
|
||||
</button>
|
||||
<button
|
||||
class="action-btn secondary"
|
||||
v-if="isSearching && !autoPlay"
|
||||
class="action-btn secondary"
|
||||
@click="nextStep"
|
||||
v-if="isSearching && !autoPlay"
|
||||
>
|
||||
⏭ 下一步
|
||||
</button>
|
||||
<button
|
||||
class="action-btn outline"
|
||||
v-if="isFinished || isSearching"
|
||||
class="action-btn outline"
|
||||
@click="reset"
|
||||
v-if="isFinished || isSearching"
|
||||
>
|
||||
↺ 重置
|
||||
</button>
|
||||
@@ -52,15 +60,24 @@
|
||||
|
||||
<!-- 进度条/状态展示 -->
|
||||
<div class="status-bar">
|
||||
<div v-if="!isSearching && !isFinished" class="status-text">
|
||||
<div
|
||||
v-if="!isSearching && !isFinished"
|
||||
class="status-text"
|
||||
>
|
||||
<span class="icon">👋</span>
|
||||
准备出发:去问问 <strong>{{ targets[selectedTargetIndex].domain }}</strong> 的 IP 是多少?
|
||||
</div>
|
||||
<div v-else-if="isSearching" class="status-text running">
|
||||
<div
|
||||
v-else-if="isSearching"
|
||||
class="status-text running"
|
||||
>
|
||||
<span class="icon spin">⏳</span>
|
||||
正在询问:{{ queryLevels[currentStep]?.analogyName }}...
|
||||
</div>
|
||||
<div v-else class="status-text success">
|
||||
<div
|
||||
v-else
|
||||
class="status-text success"
|
||||
>
|
||||
<span class="icon">✅</span>
|
||||
找到了!IP 地址是:<strong>{{ targets[selectedTargetIndex].ip }}</strong>
|
||||
</div>
|
||||
@@ -79,13 +96,21 @@
|
||||
}"
|
||||
@click="jumpToStep(index)"
|
||||
>
|
||||
<div class="step-icon-box" :style="{ '--step-color': level.color }">
|
||||
<div
|
||||
class="step-icon-box"
|
||||
:style="{ '--step-color': level.color }"
|
||||
>
|
||||
<span class="step-icon">{{ level.analogyIcon }}</span>
|
||||
</div>
|
||||
<div class="step-label">{{ level.analogyName }}</div>
|
||||
<div class="step-label">
|
||||
{{ level.analogyName }}
|
||||
</div>
|
||||
|
||||
<!-- 连接线 -->
|
||||
<div class="step-line" v-if="index < queryLevels.length - 1"></div>
|
||||
<div
|
||||
v-if="index < queryLevels.length - 1"
|
||||
class="step-line"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -93,20 +118,35 @@
|
||||
<div class="info-panels">
|
||||
<!-- 左侧:生活场景 -->
|
||||
<div class="detail-panel analogy-panel">
|
||||
<transition name="fade" mode="out-in">
|
||||
<div v-if="currentStep >= 0" class="panel-content" :key="currentStep">
|
||||
<div class="panel-header" :style="{ color: currentLevel.color }">
|
||||
<transition
|
||||
name="fade"
|
||||
mode="out-in"
|
||||
>
|
||||
<div
|
||||
v-if="currentStep >= 0"
|
||||
:key="currentStep"
|
||||
class="panel-content"
|
||||
>
|
||||
<div
|
||||
class="panel-header"
|
||||
:style="{ color: currentLevel.color }"
|
||||
>
|
||||
<span class="header-icon">{{ currentLevel.analogyIcon }}</span>
|
||||
<span class="header-title">{{ currentLevel.analogyName }} ({{ currentLevel.techName }})</span>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p class="analogy-text">{{ currentLevel.analogyAction }}</p>
|
||||
<p class="analogy-text">
|
||||
{{ currentLevel.analogyAction }}
|
||||
</p>
|
||||
<div class="tech-hint-badge">
|
||||
{{ currentLevel.techAction }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="panel-placeholder">
|
||||
<div
|
||||
v-else
|
||||
class="panel-placeholder"
|
||||
>
|
||||
<span>生活场景视角</span>
|
||||
</div>
|
||||
</transition>
|
||||
@@ -116,12 +156,21 @@
|
||||
<div class="detail-panel terminal-panel">
|
||||
<div class="terminal-header">
|
||||
<div class="terminal-dots">
|
||||
<span></span><span></span><span></span>
|
||||
<span /><span /><span />
|
||||
</div>
|
||||
<div class="terminal-title">
|
||||
Terminal
|
||||
</div>
|
||||
<div class="terminal-title">Terminal</div>
|
||||
</div>
|
||||
<transition name="fade" mode="out-in">
|
||||
<div v-if="currentStep >= 0" class="terminal-body" :key="currentStep">
|
||||
<transition
|
||||
name="fade"
|
||||
mode="out-in"
|
||||
>
|
||||
<div
|
||||
v-if="currentStep >= 0"
|
||||
:key="currentStep"
|
||||
class="terminal-body"
|
||||
>
|
||||
<div class="cmd-line">
|
||||
<span class="prompt">$</span>
|
||||
<span class="cmd">{{ formatText(currentLevel.techCommand) }}</span>
|
||||
@@ -130,13 +179,15 @@
|
||||
<pre>{{ formatText(currentLevel.techOutput) }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="terminal-placeholder">
|
||||
<div
|
||||
v-else
|
||||
class="terminal-placeholder"
|
||||
>
|
||||
<span>Waiting for command...</span>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -19,17 +19,17 @@
|
||||
<button
|
||||
v-for="s in scenarios"
|
||||
:key="s.id"
|
||||
@click="selectScenario(s)"
|
||||
class="tab-btn"
|
||||
:class="{ active: currentScenario.id === s.id }"
|
||||
:disabled="isAnimating"
|
||||
@click="selectScenario(s)"
|
||||
>
|
||||
{{ s.name }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button
|
||||
<button
|
||||
class="action-btn primary"
|
||||
@click="toggleAutoPlay"
|
||||
>
|
||||
@@ -56,16 +56,23 @@
|
||||
|
||||
<!-- 传输通道 -->
|
||||
<div class="channel">
|
||||
<div class="channel-bg"></div>
|
||||
<div class="channel-bg" />
|
||||
|
||||
<!-- 请求包 -->
|
||||
<div class="packet request" :class="{ moving: step === 1, done: step > 1 }">
|
||||
<div
|
||||
class="packet request"
|
||||
:class="{ moving: step === 1, done: step > 1 }"
|
||||
>
|
||||
<span class="packet-icon">📤</span>
|
||||
<span class="packet-label">GET</span>
|
||||
</div>
|
||||
|
||||
<!-- 响应包 -->
|
||||
<div class="packet response" :class="{ moving: step === 2, done: step > 2 }" v-if="step >= 2">
|
||||
<div
|
||||
v-if="step >= 2"
|
||||
class="packet response"
|
||||
:class="{ moving: step === 2, done: step > 2 }"
|
||||
>
|
||||
<span class="packet-icon">📦</span>
|
||||
<span class="packet-label">{{ currentScenario.status }}</span>
|
||||
</div>
|
||||
@@ -82,35 +89,51 @@
|
||||
|
||||
<!-- 底部详情面板 (固定高度) -->
|
||||
<div class="detail-panel">
|
||||
<transition name="fade" mode="out-in">
|
||||
<div v-if="step > 0" class="detail-content" :key="step">
|
||||
<!-- 左侧状态徽章 -->
|
||||
<div class="detail-left" :style="{ borderColor: getStatusColor() }">
|
||||
<div class="status-badge" :class="currentScenario.statusType">
|
||||
{{ step === 1 ? '请求中' : currentScenario.status + ' ' + currentScenario.statusText }}
|
||||
</div>
|
||||
</div>
|
||||
<transition
|
||||
name="fade"
|
||||
mode="out-in"
|
||||
>
|
||||
<div
|
||||
v-if="step > 0"
|
||||
:key="step"
|
||||
class="detail-content"
|
||||
>
|
||||
<!-- 左侧状态徽章 -->
|
||||
<div
|
||||
class="detail-left"
|
||||
:style="{ borderColor: getStatusColor() }"
|
||||
>
|
||||
<div
|
||||
class="status-badge"
|
||||
:class="currentScenario.statusType"
|
||||
>
|
||||
{{ step === 1 ? '请求中' : currentScenario.status + ' ' + currentScenario.statusText }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-divider"></div>
|
||||
<div class="detail-divider" />
|
||||
|
||||
<!-- 右侧详情 -->
|
||||
<div class="detail-right">
|
||||
<div class="info-row">
|
||||
<span class="tag life">快递员说</span>
|
||||
<span class="text highlight">
|
||||
{{ step === 1 ? currentScenario.requestText : currentScenario.responseText }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="tag tech">技术报文</span>
|
||||
<span class="text code">
|
||||
{{ step === 1 ? `${currentScenario.method} ${currentScenario.path} HTTP/1.1` : `HTTP/1.1 ${currentScenario.status} ${currentScenario.statusText}` }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 右侧详情 -->
|
||||
<div class="detail-right">
|
||||
<div class="info-row">
|
||||
<span class="tag life">快递员说</span>
|
||||
<span class="text highlight">
|
||||
{{ step === 1 ? currentScenario.requestText : currentScenario.responseText }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="tag tech">技术报文</span>
|
||||
<span class="text code">
|
||||
{{ step === 1 ? `${currentScenario.method} ${currentScenario.path} HTTP/1.1` : `HTTP/1.1 ${currentScenario.status} ${currentScenario.statusText}` }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="detail-placeholder">
|
||||
<div
|
||||
v-else
|
||||
class="detail-placeholder"
|
||||
>
|
||||
<span class="guide-bounce">📦</span>
|
||||
<span>选择一个场景,点击"演示"看看发生了什么</span>
|
||||
</div>
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button
|
||||
class="action-btn primary"
|
||||
@click="nextStep"
|
||||
<button
|
||||
v-if="currentStep < 3"
|
||||
class="action-btn primary"
|
||||
:disabled="currentStep >= 3"
|
||||
v-if="currentStep < 3"
|
||||
@click="nextStep"
|
||||
>
|
||||
{{ currentStep === 0 ? '▶ 开始拨号' : '下一步 ➔' }}
|
||||
</button>
|
||||
@@ -42,7 +42,10 @@
|
||||
<span class="avatar-label">客户端 (你)</span>
|
||||
</div>
|
||||
<transition name="pop">
|
||||
<div class="bubble client" v-if="currentStep >= 1">
|
||||
<div
|
||||
v-if="currentStep >= 1"
|
||||
class="bubble client"
|
||||
>
|
||||
{{ getBubbleText(1) }}
|
||||
</div>
|
||||
</transition>
|
||||
@@ -50,11 +53,20 @@
|
||||
|
||||
<!-- 中间:连接状态线 -->
|
||||
<div class="connection-line">
|
||||
<div class="line-bg"></div>
|
||||
<div class="signal-packet" :class="getSignalClass()">
|
||||
<span class="packet-icon" v-if="currentStep > 0">{{ getSignalIcon() }}</span>
|
||||
<div class="line-bg" />
|
||||
<div
|
||||
class="signal-packet"
|
||||
:class="getSignalClass()"
|
||||
>
|
||||
<span
|
||||
v-if="currentStep > 0"
|
||||
class="packet-icon"
|
||||
>{{ getSignalIcon() }}</span>
|
||||
</div>
|
||||
<div class="status-badge" :class="{ connected: currentStep === 3 }">
|
||||
<div
|
||||
class="status-badge"
|
||||
:class="{ connected: currentStep === 3 }"
|
||||
>
|
||||
{{ currentStep === 3 ? '✅ 连接建立' : '⏳ 连接中...' }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -66,7 +78,10 @@
|
||||
<span class="avatar-label">服务器</span>
|
||||
</div>
|
||||
<transition name="pop">
|
||||
<div class="bubble server" v-if="currentStep >= 2">
|
||||
<div
|
||||
v-if="currentStep >= 2"
|
||||
class="bubble server"
|
||||
>
|
||||
{{ getBubbleText(2) }}
|
||||
</div>
|
||||
</transition>
|
||||
@@ -80,83 +95,125 @@
|
||||
:key="index"
|
||||
class="step-dot"
|
||||
:class="{ active: currentStep === index + 1, passed: currentStep > index + 1 }"
|
||||
@click="goToStep(index + 1)"
|
||||
:title="step.techTitle"
|
||||
@click="goToStep(index + 1)"
|
||||
>
|
||||
<span class="dot-num">{{ index + 1 }}</span>
|
||||
<span class="dot-line" v-if="index < steps.length - 1"></span>
|
||||
<span
|
||||
v-if="index < steps.length - 1"
|
||||
class="dot-line"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部详情面板 (固定高度) -->
|
||||
<div class="detail-panel">
|
||||
<transition name="fade" mode="out-in">
|
||||
<div v-if="currentStep > 0" class="detail-content" :key="currentStep">
|
||||
<div class="detail-left" :style="{ borderColor: getCurrentStepColor() }">
|
||||
<div class="step-badge" :style="{ background: getCurrentStepColor() }">
|
||||
步骤 {{ currentStep }}
|
||||
</div>
|
||||
</div>
|
||||
<transition
|
||||
name="fade"
|
||||
mode="out-in"
|
||||
>
|
||||
<div
|
||||
v-if="currentStep > 0"
|
||||
:key="currentStep"
|
||||
class="detail-content"
|
||||
>
|
||||
<div
|
||||
class="detail-left"
|
||||
:style="{ borderColor: getCurrentStepColor() }"
|
||||
>
|
||||
<div
|
||||
class="step-badge"
|
||||
:style="{ background: getCurrentStepColor() }"
|
||||
>
|
||||
步骤 {{ currentStep }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-divider"></div>
|
||||
<div class="detail-divider" />
|
||||
|
||||
<div class="detail-right">
|
||||
<div class="info-row">
|
||||
<span class="tag life">生活对话</span>
|
||||
<span class="text highlight">{{ steps[currentStep-1].simpleTitle }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="tag tech">技术原理</span>
|
||||
<div class="tech-content">
|
||||
<div class="tech-desc">{{ steps[currentStep-1].techDesc }}</div>
|
||||
<!-- 动态名词解码卡片 -->
|
||||
<div class="term-glossary">
|
||||
<div v-for="term in steps[currentStep-1].terms" :key="term.key" class="term-item">
|
||||
<span class="term-key">{{ term.key }}</span>
|
||||
<span class="term-val">{{ term.val }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-right">
|
||||
<div class="info-row">
|
||||
<span class="tag life">生活对话</span>
|
||||
<span class="text highlight">{{ steps[currentStep-1].simpleTitle }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="tag tech">技术原理</span>
|
||||
<div class="tech-content">
|
||||
<div class="tech-desc">
|
||||
{{ steps[currentStep-1].techDesc }}
|
||||
</div>
|
||||
<!-- 动态名词解码卡片 -->
|
||||
<div class="term-glossary">
|
||||
<div
|
||||
v-for="term in steps[currentStep-1].terms"
|
||||
:key="term.key"
|
||||
class="term-item"
|
||||
>
|
||||
<span class="term-key">{{ term.key }}</span>
|
||||
<span class="term-val">{{ term.val }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 代码实现细节 (折叠) -->
|
||||
<details class="code-details" v-if="steps[currentStep-1].codeImpl">
|
||||
<summary class="code-summary">
|
||||
<span class="summary-icon">🛠️</span>
|
||||
<span class="summary-text">技术深究:底层代码如何实现?</span>
|
||||
</summary>
|
||||
<div class="code-block-wrapper">
|
||||
<div class="code-title">{{ steps[currentStep-1].codeImpl.title }}</div>
|
||||
<pre class="code-block"><code v-html="steps[currentStep-1].codeImpl.code"></code></pre>
|
||||
<!-- 代码实现细节 (折叠) -->
|
||||
<details
|
||||
v-if="steps[currentStep-1].codeImpl"
|
||||
class="code-details"
|
||||
>
|
||||
<summary class="code-summary">
|
||||
<span class="summary-icon">🛠️</span>
|
||||
<span class="summary-text">技术深究:底层代码如何实现?</span>
|
||||
</summary>
|
||||
<div class="code-block-wrapper">
|
||||
<div class="code-title">
|
||||
{{ steps[currentStep-1].codeImpl.title }}
|
||||
</div>
|
||||
<pre class="code-block"><code v-html="steps[currentStep-1].codeImpl.code" /></pre>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
<!-- 技术问答 (折叠) - 仅在有问答时显示 -->
|
||||
<details class="code-details qa-details" v-if="steps[currentStep-1].qa">
|
||||
<details
|
||||
v-if="steps[currentStep-1].qa"
|
||||
class="code-details qa-details"
|
||||
>
|
||||
<summary class="code-summary qa-summary">
|
||||
<span class="summary-icon">🎓</span>
|
||||
<span class="summary-text">{{ steps[currentStep-1].qa.title }}</span>
|
||||
</summary>
|
||||
<div class="code-block-wrapper qa-content">
|
||||
<div v-for="(item, idx) in steps[currentStep-1].qa.content" :key="idx" class="qa-item">
|
||||
<div class="qa-q">Q: {{ item.q }}</div>
|
||||
<div class="qa-a" v-html="item.a"></div>
|
||||
<div
|
||||
v-for="(item, idx) in steps[currentStep-1].qa.content"
|
||||
:key="idx"
|
||||
class="qa-item"
|
||||
>
|
||||
<div class="qa-q">
|
||||
Q: {{ item.q }}
|
||||
</div>
|
||||
<div
|
||||
class="qa-a"
|
||||
v-html="item.a"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 下一步按钮 -->
|
||||
<button
|
||||
class="next-btn"
|
||||
v-if="currentStep < 3"
|
||||
@click="nextStep"
|
||||
>
|
||||
下一步 ➔
|
||||
</button>
|
||||
<!-- 下一步按钮 -->
|
||||
<button
|
||||
v-if="currentStep < 3"
|
||||
class="next-btn"
|
||||
@click="nextStep"
|
||||
>
|
||||
下一步 ➔
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-else class="detail-placeholder">
|
||||
<div
|
||||
v-else
|
||||
class="detail-placeholder"
|
||||
>
|
||||
<span class="guide-bounce">📞</span>
|
||||
<span>点击"开始拨号"或步骤圆点,开始拨打电话</span>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,10 @@
|
||||
<div class="url-parser-order">
|
||||
<!-- 顶部:输入区 -->
|
||||
<div class="input-section">
|
||||
<div class="url-input-box" :class="{ 'has-error': error }">
|
||||
<div
|
||||
class="url-input-box"
|
||||
:class="{ 'has-error': error }"
|
||||
>
|
||||
<span class="input-label">URL</span>
|
||||
<input
|
||||
v-model="urlInput"
|
||||
@@ -19,17 +22,23 @@
|
||||
placeholder="https://www.example.com/path?query=1"
|
||||
class="real-input"
|
||||
@input="parseUrl"
|
||||
/>
|
||||
<button v-if="urlInput" class="clear-btn" @click="clear">✕</button>
|
||||
>
|
||||
<button
|
||||
v-if="urlInput"
|
||||
class="clear-btn"
|
||||
@click="clear"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
</div>
|
||||
<div class="quick-actions">
|
||||
<span class="action-label">试一试:</span>
|
||||
<button
|
||||
v-for="ex in examples"
|
||||
:key="ex.name"
|
||||
@click="useExample(ex)"
|
||||
class="action-chip"
|
||||
:class="{ active: currentExample === ex.name }"
|
||||
@click="useExample(ex)"
|
||||
>
|
||||
{{ ex.name }}
|
||||
</button>
|
||||
@@ -48,8 +57,8 @@
|
||||
<div class="code-blocks">
|
||||
<div
|
||||
v-for="(field, key) in formFields"
|
||||
:key="key"
|
||||
v-show="shouldShowField(key)"
|
||||
:key="key"
|
||||
class="code-block"
|
||||
:class="[key, { active: hovered === key }]"
|
||||
:style="{ '--color': field.color }"
|
||||
@@ -75,19 +84,24 @@
|
||||
<span class="title">购物订单</span>
|
||||
</div>
|
||||
<div class="order-ticket">
|
||||
<div class="ticket-hole"></div>
|
||||
<div class="ticket-hole" />
|
||||
|
||||
<div
|
||||
v-for="(field, key) in formFields"
|
||||
:key="key"
|
||||
v-show="shouldShowField(key)"
|
||||
:key="key"
|
||||
class="ticket-row"
|
||||
:class="{ active: hovered === key }"
|
||||
:style="{ '--color': field.color }"
|
||||
@mouseenter="hovered = key"
|
||||
@mouseleave="hovered = null"
|
||||
>
|
||||
<div class="ticket-icon" :style="{ backgroundColor: field.color }">{{ field.icon }}</div>
|
||||
<div
|
||||
class="ticket-icon"
|
||||
:style="{ backgroundColor: field.color }"
|
||||
>
|
||||
{{ field.icon }}
|
||||
</div>
|
||||
<div class="ticket-content">
|
||||
<span class="ticket-label">{{ field.analogyLabel }}</span>
|
||||
<span class="ticket-desc">{{ field.analogyDesc }}</span>
|
||||
@@ -99,24 +113,45 @@
|
||||
|
||||
<!-- 技术答疑面板 -->
|
||||
<transition name="fade">
|
||||
<div class="qa-panel" v-if="activeQa">
|
||||
<div class="qa-header">{{ activeQa.title }}</div>
|
||||
<div
|
||||
v-if="activeQa"
|
||||
class="qa-panel"
|
||||
>
|
||||
<div class="qa-header">
|
||||
{{ activeQa.title }}
|
||||
</div>
|
||||
<div class="qa-content">
|
||||
<div v-for="(item, idx) in activeQa.content" :key="idx" class="qa-item">
|
||||
<div class="qa-q">Q: {{ item.q }}</div>
|
||||
<div class="qa-a">A: {{ item.a }}</div>
|
||||
<div
|
||||
v-for="(item, idx) in activeQa.content"
|
||||
:key="idx"
|
||||
class="qa-item"
|
||||
>
|
||||
<div class="qa-q">
|
||||
Q: {{ item.q }}
|
||||
</div>
|
||||
<div class="qa-a">
|
||||
A: {{ item.a }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qa-placeholder" v-else>
|
||||
<div
|
||||
v-else
|
||||
class="qa-placeholder"
|
||||
>
|
||||
👆 鼠标悬停在上方色块,查看详细技术解释
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<!-- 空状态引导 -->
|
||||
<div class="empty-state" v-else>
|
||||
<div class="empty-icon">🛒</div>
|
||||
<div
|
||||
v-else
|
||||
class="empty-state"
|
||||
>
|
||||
<div class="empty-icon">
|
||||
🛒
|
||||
</div>
|
||||
<div class="empty-text">
|
||||
<p>输入网址,生成你的"数字购物单"</p>
|
||||
<span class="sub-text">看看浏览器如何理解这一长串字符</span>
|
||||
|
||||
+56
-23
@@ -11,52 +11,66 @@
|
||||
<template>
|
||||
<div class="quick-start-compact">
|
||||
<!-- 顶部:极简输入栏 -->
|
||||
<div class="input-bar" :class="{ 'is-active': isActive }">
|
||||
<div
|
||||
class="input-bar"
|
||||
:class="{ 'is-active': isActive }"
|
||||
>
|
||||
<div class="input-wrapper">
|
||||
<span class="protocol">https://</span>
|
||||
<input
|
||||
v-model="url"
|
||||
type="text"
|
||||
placeholder="输入网址,开始旅程..."
|
||||
@keyup.enter="handleMainAction"
|
||||
:disabled="isActive && !isFinished"
|
||||
/>
|
||||
@keyup.enter="handleMainAction"
|
||||
>
|
||||
|
||||
<!-- 主操作按钮 -->
|
||||
<button
|
||||
class="start-btn"
|
||||
:class="{ 'next-btn': isActive && !isFinished, 'reset-btn': isFinished }"
|
||||
@click="handleMainAction"
|
||||
:disabled="!url"
|
||||
:disabled="!url"
|
||||
@click="handleMainAction"
|
||||
>
|
||||
{{ mainButtonText }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 步骤控制按钮组 -->
|
||||
<div class="step-controls" v-if="isActive">
|
||||
<div
|
||||
v-if="isActive"
|
||||
class="step-controls"
|
||||
>
|
||||
<button
|
||||
class="control-btn"
|
||||
@click="prevStep"
|
||||
:disabled="currentStep === 0"
|
||||
:disabled="currentStep === 0"
|
||||
title="上一步"
|
||||
@click="prevStep"
|
||||
>
|
||||
⬅️
|
||||
</button>
|
||||
<button
|
||||
class="control-btn"
|
||||
@click="nextStep"
|
||||
:disabled="isFinished"
|
||||
:disabled="isFinished"
|
||||
title="下一步"
|
||||
@click="nextStep"
|
||||
>
|
||||
➡️
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 快速体验按钮 (仅在未开始时显示) -->
|
||||
<div class="quick-chips" v-if="!isActive">
|
||||
<div
|
||||
v-if="!isActive"
|
||||
class="quick-chips"
|
||||
>
|
||||
<span class="chip-label">试一试:</span>
|
||||
<button v-for="u in quickUrls" :key="u" @click="quickStart(u)" class="chip">
|
||||
<button
|
||||
v-for="u in quickUrls"
|
||||
:key="u"
|
||||
class="chip"
|
||||
@click="quickStart(u)"
|
||||
>
|
||||
{{ u }}
|
||||
</button>
|
||||
</div>
|
||||
@@ -66,7 +80,10 @@
|
||||
<div class="conveyor-stage">
|
||||
<!-- 进度轨道 -->
|
||||
<div class="track-line">
|
||||
<div class="track-progress" :style="{ width: packagePosition + '%' }"></div>
|
||||
<div
|
||||
class="track-progress"
|
||||
:style="{ width: packagePosition + '%' }"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 站点节点 -->
|
||||
@@ -83,19 +100,23 @@
|
||||
>
|
||||
<div class="station-icon-box">
|
||||
<span class="station-icon">{{ step.icon }}</span>
|
||||
<div class="station-status-dot"></div>
|
||||
<div class="station-status-dot" />
|
||||
</div>
|
||||
<div class="station-label">
|
||||
{{ step.name }}
|
||||
</div>
|
||||
<div class="station-label">{{ step.name }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 移动的包裹 (绝对定位) -->
|
||||
<div
|
||||
v-show="isActive"
|
||||
class="moving-package"
|
||||
:style="{ '--package-pos': packagePosition }"
|
||||
v-show="isActive"
|
||||
>
|
||||
<div class="package-body">📦</div>
|
||||
<div class="package-shadow"></div>
|
||||
<div class="package-body">
|
||||
📦
|
||||
</div>
|
||||
<div class="package-shadow" />
|
||||
<!-- 动态提示气泡 -->
|
||||
<div class="package-bubble">
|
||||
<span class="bubble-analogy">{{ steps[currentStep]?.analogyAction }}</span>
|
||||
@@ -105,26 +126,38 @@
|
||||
|
||||
<!-- 底部:动态对照条 -->
|
||||
<div class="dynamic-info-bar">
|
||||
<transition name="slide-up" mode="out-in">
|
||||
<div v-if="isActive" :key="currentStep" class="info-content">
|
||||
<transition
|
||||
name="slide-up"
|
||||
mode="out-in"
|
||||
>
|
||||
<div
|
||||
v-if="isActive"
|
||||
:key="currentStep"
|
||||
class="info-content"
|
||||
>
|
||||
<div class="info-left">
|
||||
<span class="stage-badge">第 {{ currentStep + 1 }} 站</span>
|
||||
<span class="stage-title">{{ steps[currentStep].title }}</span>
|
||||
</div>
|
||||
<div class="info-divider"></div>
|
||||
<div class="info-divider" />
|
||||
<div class="info-right">
|
||||
<div class="mapping-item">
|
||||
<span class="mapping-icon">🚚</span>
|
||||
<span class="mapping-text">生活:{{ steps[currentStep].analogyDesc }}</span>
|
||||
</div>
|
||||
<div class="mapping-arrow">↔️</div>
|
||||
<div class="mapping-arrow">
|
||||
↔️
|
||||
</div>
|
||||
<div class="mapping-item">
|
||||
<span class="mapping-icon">💻</span>
|
||||
<span class="mapping-text">技术:{{ steps[currentStep].techDesc }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="info-placeholder">
|
||||
<div
|
||||
v-else
|
||||
class="info-placeholder"
|
||||
>
|
||||
👈 在左上角输入网址,开启网络快递之旅
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
Reference in New Issue
Block a user