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:
+359
-179
@@ -597,19 +597,21 @@ onUnmounted(() => {
|
||||
|
||||
<template>
|
||||
<div
|
||||
ref="demoRef"
|
||||
class="browser-devtools-demo"
|
||||
:class="{ 'dark-mode': isDark }"
|
||||
ref="demoRef"
|
||||
>
|
||||
<!-- Top Controls (Custom for Demo) -->
|
||||
<div class="demo-controls">
|
||||
<div class="control-label">Chrome DevTools 模拟器</div>
|
||||
<div class="control-label">
|
||||
Chrome DevTools 模拟器
|
||||
</div>
|
||||
<div class="control-actions">
|
||||
<select
|
||||
v-model="selectedTour"
|
||||
@change="handleTourSelect"
|
||||
class="tour-select"
|
||||
:disabled="isAutoPlaying"
|
||||
@change="handleTourSelect"
|
||||
>
|
||||
<option
|
||||
v-for="opt in tourOptions"
|
||||
@@ -620,7 +622,11 @@ onUnmounted(() => {
|
||||
{{ opt.label }}
|
||||
</option>
|
||||
</select>
|
||||
<button v-if="isAutoPlaying" class="stop-btn" @click="stopTour">
|
||||
<button
|
||||
v-if="isAutoPlaying"
|
||||
class="stop-btn"
|
||||
@click="stopTour"
|
||||
>
|
||||
停止演示
|
||||
</button>
|
||||
</div>
|
||||
@@ -628,8 +634,8 @@ onUnmounted(() => {
|
||||
|
||||
<!-- Virtual Cursor & Highlight -->
|
||||
<div
|
||||
class="virtual-cursor"
|
||||
v-if="cursorVisible"
|
||||
class="virtual-cursor"
|
||||
:style="{ transform: `translate(${cursorX}px, ${cursorY}px)` }"
|
||||
>
|
||||
<svg
|
||||
@@ -648,10 +654,10 @@ onUnmounted(() => {
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="highlight-box"
|
||||
v-if="highlightVisible"
|
||||
class="highlight-box"
|
||||
:style="highlightStyle"
|
||||
></div>
|
||||
/>
|
||||
|
||||
<!-- Main UI Container -->
|
||||
<div class="devtools-container">
|
||||
@@ -662,20 +668,33 @@ onUnmounted(() => {
|
||||
class="icon-btn element-picker"
|
||||
title="选择页面中的元素以进行检查"
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="#6e6e6e">
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="#6e6e6e"
|
||||
>
|
||||
<path
|
||||
d="M4 4h9v2H4V4zm0 4h5v2H4V8zm0 4h5v2H4v-2zm12-5l-4 4h3v4h2v-4h3l-4-4z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="icon-btn device-toggle" title="切换设备工具栏">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="#6e6e6e">
|
||||
<div
|
||||
class="icon-btn device-toggle"
|
||||
title="切换设备工具栏"
|
||||
>
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="#6e6e6e"
|
||||
>
|
||||
<path
|
||||
d="M17 1.01L7 1c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM17 19H7V5h10v14z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="separator"></div>
|
||||
<div class="separator" />
|
||||
<div class="tabs">
|
||||
<div
|
||||
v-for="tab in tabs"
|
||||
@@ -692,24 +711,54 @@ onUnmounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="icon-btn settings" title="设置">⚙️</div>
|
||||
<div class="icon-btn close" title="关闭">×</div>
|
||||
<div
|
||||
class="icon-btn settings"
|
||||
title="设置"
|
||||
>
|
||||
⚙️
|
||||
</div>
|
||||
<div
|
||||
class="icon-btn close"
|
||||
title="关闭"
|
||||
>
|
||||
×
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Body Area -->
|
||||
<div class="devtools-body">
|
||||
<!-- 1. Console Panel -->
|
||||
<div v-if="activeTab === 'console'" class="panel console-panel-layout">
|
||||
<div class="console-toolbar" @mouseenter="showInfo('控制台工具栏')">
|
||||
<div class="icon-btn clear" title="清除控制台">🚫</div>
|
||||
<div class="separator"></div>
|
||||
<div class="dropdown-trigger">top ▼</div>
|
||||
<div class="icon-btn eye" title="创建实时表达式">👁️</div>
|
||||
<div class="filter-box">
|
||||
<span class="filter-icon">🔍</span><input placeholder="过滤" />
|
||||
<div
|
||||
v-if="activeTab === 'console'"
|
||||
class="panel console-panel-layout"
|
||||
>
|
||||
<div
|
||||
class="console-toolbar"
|
||||
@mouseenter="showInfo('控制台工具栏')"
|
||||
>
|
||||
<div
|
||||
class="icon-btn clear"
|
||||
title="清除控制台"
|
||||
>
|
||||
🚫
|
||||
</div>
|
||||
<div class="separator" />
|
||||
<div class="dropdown-trigger">
|
||||
top ▼
|
||||
</div>
|
||||
<div
|
||||
class="icon-btn eye"
|
||||
title="创建实时表达式"
|
||||
>
|
||||
👁️
|
||||
</div>
|
||||
<div class="filter-box">
|
||||
<span class="filter-icon">🔍</span><input placeholder="过滤">
|
||||
</div>
|
||||
<div class="dropdown-trigger">
|
||||
默认级别 ▼
|
||||
</div>
|
||||
<div class="dropdown-trigger">默认级别 ▼</div>
|
||||
</div>
|
||||
<div class="console-main-area">
|
||||
<div class="console-sidebar">
|
||||
@@ -744,16 +793,22 @@ onUnmounted(() => {
|
||||
:class="log.type"
|
||||
>
|
||||
<div class="log-gutter">
|
||||
<span class="icon error" v-if="log.type === 'error'"
|
||||
>❌</span
|
||||
>
|
||||
<span class="icon warn" v-else-if="log.type === 'warn'"
|
||||
>⚠️</span
|
||||
>
|
||||
<span class="icon" v-else-if="log.type === 'command'"
|
||||
>></span
|
||||
>
|
||||
<span class="icon" v-else><</span>
|
||||
<span
|
||||
v-if="log.type === 'error'"
|
||||
class="icon error"
|
||||
>❌</span>
|
||||
<span
|
||||
v-else-if="log.type === 'warn'"
|
||||
class="icon warn"
|
||||
>⚠️</span>
|
||||
<span
|
||||
v-else-if="log.type === 'command'"
|
||||
class="icon"
|
||||
>></span>
|
||||
<span
|
||||
v-else
|
||||
class="icon"
|
||||
><</span>
|
||||
</div>
|
||||
<div class="log-content">
|
||||
<pre>{{ log.msg }}</pre>
|
||||
@@ -767,10 +822,10 @@ onUnmounted(() => {
|
||||
<span class="prompt">></span>
|
||||
<input
|
||||
v-model="consoleInput"
|
||||
@keyup.enter="runConsoleCommand"
|
||||
class="input-field"
|
||||
placeholder=""
|
||||
/>
|
||||
@keyup.enter="runConsoleCommand"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -784,10 +839,18 @@ onUnmounted(() => {
|
||||
>
|
||||
⋮
|
||||
</div>
|
||||
<div class="drawer-tab">控制台</div>
|
||||
<div class="drawer-tab">AI 辅助</div>
|
||||
<div class="drawer-tab">新变化</div>
|
||||
<div class="drawer-tab">问题</div>
|
||||
<div class="drawer-tab">
|
||||
控制台
|
||||
</div>
|
||||
<div class="drawer-tab">
|
||||
AI 辅助
|
||||
</div>
|
||||
<div class="drawer-tab">
|
||||
新变化
|
||||
</div>
|
||||
<div class="drawer-tab">
|
||||
问题
|
||||
</div>
|
||||
<div class="drawer-tab active">
|
||||
搜索 <span class="close-icon">×</span>
|
||||
</div>
|
||||
@@ -799,12 +862,16 @@ onUnmounted(() => {
|
||||
<input
|
||||
placeholder="A terminal is just a grid of same-sized cells..."
|
||||
class="search-input"
|
||||
/>
|
||||
<div class="search-actions">Aa ab .*</div>
|
||||
>
|
||||
<div class="search-actions">
|
||||
Aa ab .*
|
||||
</div>
|
||||
</div>
|
||||
<div class="search-results">
|
||||
<div class="no-results">
|
||||
<div class="no-results-title">未找到匹配项</div>
|
||||
<div class="no-results-title">
|
||||
未找到匹配项
|
||||
</div>
|
||||
<div class="no-results-desc">
|
||||
没有与您的搜索查询相符的结果
|
||||
</div>
|
||||
@@ -816,84 +883,80 @@ onUnmounted(() => {
|
||||
</div>
|
||||
|
||||
<!-- 2. Elements Panel -->
|
||||
<div v-else-if="activeTab === 'elements'" class="panel elements-panel">
|
||||
<div
|
||||
v-else-if="activeTab === 'elements'"
|
||||
class="panel elements-panel"
|
||||
>
|
||||
<div class="dom-tree-panel">
|
||||
<div class="dom-tree-content">
|
||||
<div class="dom-node" data-tag="html">
|
||||
<div
|
||||
class="dom-node"
|
||||
data-tag="html"
|
||||
>
|
||||
<div class="line-content">
|
||||
<span class="arrow expanded">▼</span>
|
||||
<span class="tag-name">html</span>
|
||||
<span class="attr-name">class</span>=<span class="attr-val"
|
||||
>"mac"</span
|
||||
>
|
||||
<span class="attr-name">lang</span>=<span class="attr-val"
|
||||
>"zh-CN"</span
|
||||
>
|
||||
<span class="attr-name">dir</span>=<span class="attr-val"
|
||||
>"ltr"</span
|
||||
>
|
||||
<span class="attr-name">style</span>=<span class="attr-val"
|
||||
>"--ev-doc-font-size: 14px..."</span
|
||||
>
|
||||
<span class="attr-name">class</span>=<span class="attr-val">"mac"</span>
|
||||
<span class="attr-name">lang</span>=<span class="attr-val">"zh-CN"</span>
|
||||
<span class="attr-name">dir</span>=<span class="attr-val">"ltr"</span>
|
||||
<span class="attr-name">style</span>=<span class="attr-val">"--ev-doc-font-size: 14px..."</span>
|
||||
</div>
|
||||
<div class="children">
|
||||
<div class="dom-node" data-tag="head">
|
||||
<div
|
||||
class="dom-node"
|
||||
data-tag="head"
|
||||
>
|
||||
<div class="line-content">
|
||||
<span class="arrow">▶</span>
|
||||
<span class="tag-name">head</span>
|
||||
<span class="dots">...</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dom-node" data-tag="body">
|
||||
<div
|
||||
class="dom-node"
|
||||
data-tag="body"
|
||||
>
|
||||
<div class="line-content">
|
||||
<span class="arrow expanded">▼</span>
|
||||
<span class="tag-name">body</span>
|
||||
<span class="node-trail">== $0</span>
|
||||
</div>
|
||||
<div class="children">
|
||||
<div class="dom-node selected" data-tag="div">
|
||||
<div
|
||||
class="dom-node selected"
|
||||
data-tag="div"
|
||||
>
|
||||
<div class="line-content">
|
||||
<span class="arrow expanded">▼</span>
|
||||
<span class="tag-name">div</span>
|
||||
<span class="attr-name">id</span>=<span
|
||||
class="attr-val"
|
||||
>"app"</span
|
||||
>
|
||||
>"app"</span>
|
||||
<span class="attr-name">data-v-app</span>
|
||||
</div>
|
||||
<div class="children">
|
||||
<div class="dom-node">
|
||||
<div class="line-content">
|
||||
<span class="indent"></span
|
||||
><span class="tag-name">div</span
|
||||
><span class="dots">...</span
|
||||
><span class="tag-name">/div</span>
|
||||
<span class="indent" /><span class="tag-name">div</span><span class="dots">...</span><span class="tag-name">/div</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dom-node">
|
||||
<div class="line-content">
|
||||
<span class="indent"></span
|
||||
><span class="tag-name">script</span>
|
||||
<span class="indent" /><span class="tag-name">script</span>
|
||||
<span class="attr-name">type</span>=<span
|
||||
class="attr-val"
|
||||
>"module"</span
|
||||
>
|
||||
>"module"</span>
|
||||
<span class="attr-name">src</span>=<span
|
||||
class="attr-val"
|
||||
>"/easy-vibe/..."</span
|
||||
><span class="tag-name">/script</span>
|
||||
>"/easy-vibe/..."</span><span class="tag-name">/script</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dom-node">
|
||||
<div class="line-content">
|
||||
<span class="indent"></span
|
||||
><span class="tag-name">div</span>
|
||||
<span class="indent" /><span class="tag-name">div</span>
|
||||
<span class="attr-name">id</span>=<span
|
||||
class="attr-val"
|
||||
>"el-popper-container-3083"</span
|
||||
><span class="tag-name">></span
|
||||
><span class="dots">...</span
|
||||
><span class="tag-name">/div</span>
|
||||
>"el-popper-container-3083"</span><span class="tag-name">></span><span class="dots">...</span><span class="tag-name">/div</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -907,10 +970,7 @@ onUnmounted(() => {
|
||||
<span class="tag-name">div</span>
|
||||
<span class="attr-name">style</span>=<span
|
||||
class="attr-val"
|
||||
>"all: initial;"</span
|
||||
><span class="tag-name">></span
|
||||
><span class="dots">...</span
|
||||
><span class="tag-name">/div</span>
|
||||
>"all: initial;"</span><span class="tag-name">></span><span class="dots">...</span><span class="tag-name">/div</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dom-node">
|
||||
@@ -919,14 +979,10 @@ onUnmounted(() => {
|
||||
<span class="tag-name">div</span>
|
||||
<span class="attr-name">id</span>=<span
|
||||
class="attr-val"
|
||||
>"immersive-translate-browser-popup"</span
|
||||
>
|
||||
>"immersive-translate-browser-popup"</span>
|
||||
<span class="attr-name">style</span>=<span
|
||||
class="attr-val"
|
||||
>"all: initial;"</span
|
||||
><span class="tag-name">></span
|
||||
><span class="dots">...</span
|
||||
><span class="tag-name">/div</span>
|
||||
>"all: initial;"</span><span class="tag-name">></span><span class="dots">...</span><span class="tag-name">/div</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -940,9 +996,14 @@ onUnmounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="breadcrumbs">html.mac > body > div#app</div>
|
||||
<div class="breadcrumbs">
|
||||
html.mac > body > div#app
|
||||
</div>
|
||||
<!-- Bottom Drawer (Shared) -->
|
||||
<div class="bottom-drawer" style="border-top: 1px solid #ccc">
|
||||
<div
|
||||
class="bottom-drawer"
|
||||
style="border-top: 1px solid #ccc"
|
||||
>
|
||||
<div class="bottom-drawer-header">
|
||||
<div
|
||||
class="icon-btn more"
|
||||
@@ -950,10 +1011,18 @@ onUnmounted(() => {
|
||||
>
|
||||
⋮
|
||||
</div>
|
||||
<div class="drawer-tab">控制台</div>
|
||||
<div class="drawer-tab">AI 辅助</div>
|
||||
<div class="drawer-tab">新变化</div>
|
||||
<div class="drawer-tab">问题</div>
|
||||
<div class="drawer-tab">
|
||||
控制台
|
||||
</div>
|
||||
<div class="drawer-tab">
|
||||
AI 辅助
|
||||
</div>
|
||||
<div class="drawer-tab">
|
||||
新变化
|
||||
</div>
|
||||
<div class="drawer-tab">
|
||||
问题
|
||||
</div>
|
||||
<div class="drawer-tab active">
|
||||
搜索 <span class="close-icon">×</span>
|
||||
</div>
|
||||
@@ -965,12 +1034,16 @@ onUnmounted(() => {
|
||||
<input
|
||||
placeholder="A terminal is just a grid of same-sized cells..."
|
||||
class="search-input"
|
||||
/>
|
||||
<div class="search-actions">Aa ab .*</div>
|
||||
>
|
||||
<div class="search-actions">
|
||||
Aa ab .*
|
||||
</div>
|
||||
</div>
|
||||
<div class="search-results">
|
||||
<div class="no-results">
|
||||
<div class="no-results-title">未找到匹配项</div>
|
||||
<div class="no-results-title">
|
||||
未找到匹配项
|
||||
</div>
|
||||
<div class="no-results-desc">
|
||||
没有与您的搜索查询相符的结果
|
||||
</div>
|
||||
@@ -982,35 +1055,77 @@ onUnmounted(() => {
|
||||
</div>
|
||||
<div class="styles-panel">
|
||||
<div class="styles-tabs">
|
||||
<div class="style-tab active">样式</div>
|
||||
<div class="style-tab">计算样式</div>
|
||||
<div class="style-tab">布局</div>
|
||||
<div class="style-tab">事件监听器</div>
|
||||
<div class="style-tab">»</div>
|
||||
<div class="style-tab active">
|
||||
样式
|
||||
</div>
|
||||
<div class="style-tab">
|
||||
计算样式
|
||||
</div>
|
||||
<div class="style-tab">
|
||||
布局
|
||||
</div>
|
||||
<div class="style-tab">
|
||||
事件监听器
|
||||
</div>
|
||||
<div class="style-tab">
|
||||
»
|
||||
</div>
|
||||
</div>
|
||||
<div class="styles-content">
|
||||
<!-- Box Model Mock -->
|
||||
<div class="box-model-container">
|
||||
<div class="box-margin">
|
||||
<div class="label">margin</div>
|
||||
<div class="val-top">-</div>
|
||||
<div class="val-left">-</div>
|
||||
<div class="val-right">-</div>
|
||||
<div class="val-bottom">-</div>
|
||||
<div class="label">
|
||||
margin
|
||||
</div>
|
||||
<div class="val-top">
|
||||
-
|
||||
</div>
|
||||
<div class="val-left">
|
||||
-
|
||||
</div>
|
||||
<div class="val-right">
|
||||
-
|
||||
</div>
|
||||
<div class="val-bottom">
|
||||
-
|
||||
</div>
|
||||
<div class="box-border">
|
||||
<div class="label">border</div>
|
||||
<div class="val-top">-</div>
|
||||
<div class="val-left">-</div>
|
||||
<div class="val-right">-</div>
|
||||
<div class="val-bottom">-</div>
|
||||
<div class="label">
|
||||
border
|
||||
</div>
|
||||
<div class="val-top">
|
||||
-
|
||||
</div>
|
||||
<div class="val-left">
|
||||
-
|
||||
</div>
|
||||
<div class="val-right">
|
||||
-
|
||||
</div>
|
||||
<div class="val-bottom">
|
||||
-
|
||||
</div>
|
||||
<div class="box-padding">
|
||||
<div class="label">padding</div>
|
||||
<div class="val-top">-</div>
|
||||
<div class="val-left">-</div>
|
||||
<div class="val-right">-</div>
|
||||
<div class="val-bottom">-</div>
|
||||
<div class="label">
|
||||
padding
|
||||
</div>
|
||||
<div class="val-top">
|
||||
-
|
||||
</div>
|
||||
<div class="val-left">
|
||||
-
|
||||
</div>
|
||||
<div class="val-right">
|
||||
-
|
||||
</div>
|
||||
<div class="val-bottom">
|
||||
-
|
||||
</div>
|
||||
<div class="box-content">
|
||||
<div class="val-content">1600 x 3461</div>
|
||||
<div class="val-content">
|
||||
1600 x 3461
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1018,35 +1133,40 @@ onUnmounted(() => {
|
||||
</div>
|
||||
|
||||
<div class="filter-bar">
|
||||
<input placeholder="过滤" />
|
||||
<input placeholder="过滤">
|
||||
<span class="filter-opt">:hov</span>
|
||||
<span class="filter-opt">.cls</span>
|
||||
<span class="filter-opt">+</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="style-rule"
|
||||
v-for="(rule, idx) in cssRules"
|
||||
:key="idx"
|
||||
class="style-rule"
|
||||
>
|
||||
<div class="selector">{{ rule.selector }} {</div>
|
||||
<div class="selector">
|
||||
{{ rule.selector }} {
|
||||
</div>
|
||||
<div
|
||||
class="property"
|
||||
v-for="(val, key) in rule.styles"
|
||||
:key="key"
|
||||
class="property"
|
||||
>
|
||||
<span class="prop-name">{{ key }}</span
|
||||
>: <span class="prop-val">{{ val }}</span
|
||||
>;
|
||||
<span class="prop-name">{{ key }}</span>: <span class="prop-val">{{ val }}</span>;
|
||||
</div>
|
||||
<div class="selector">
|
||||
}
|
||||
</div>
|
||||
<div class="selector">}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 3. Sources Panel -->
|
||||
<div v-else-if="activeTab === 'sources'" class="panel sources-panel">
|
||||
<div
|
||||
v-else-if="activeTab === 'sources'"
|
||||
class="panel sources-panel"
|
||||
>
|
||||
<div class="file-navigator">
|
||||
<div class="nav-header">
|
||||
<span class="nav-tab active">Page</span>
|
||||
@@ -1079,7 +1199,7 @@ onUnmounted(() => {
|
||||
</div>
|
||||
<div class="editor-content">
|
||||
<div class="line-numbers">
|
||||
1<br />2<br />3<br />4<br />5<br />6
|
||||
1<br>2<br>3<br>4<br>5<br>6
|
||||
</div>
|
||||
<div class="code-text">
|
||||
<pre>{{ fileContent }}</pre>
|
||||
@@ -1091,14 +1211,19 @@ onUnmounted(() => {
|
||||
<div class="section-title">
|
||||
<span class="arrow">▼</span> Watch
|
||||
</div>
|
||||
<div class="section-content empty">No watch expressions</div>
|
||||
<div class="section-content empty">
|
||||
No watch expressions
|
||||
</div>
|
||||
</div>
|
||||
<div class="debug-section">
|
||||
<div class="section-title">
|
||||
<span class="arrow">▼</span> Breakpoints
|
||||
</div>
|
||||
<div class="section-content">
|
||||
<label><input type="checkbox" checked /> main.js:12</label>
|
||||
<label><input
|
||||
type="checkbox"
|
||||
checked
|
||||
> main.js:12</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="debug-section">
|
||||
@@ -1110,10 +1235,15 @@ onUnmounted(() => {
|
||||
</div>
|
||||
|
||||
<!-- 4. Network Panel -->
|
||||
<div v-else-if="activeTab === 'network'" class="panel network-panel">
|
||||
<div
|
||||
v-else-if="activeTab === 'network'"
|
||||
class="panel network-panel"
|
||||
>
|
||||
<div class="network-toolbar">
|
||||
<div class="record-icon">🔴</div>
|
||||
<div class="separator"></div>
|
||||
<div class="record-icon">
|
||||
🔴
|
||||
</div>
|
||||
<div class="separator" />
|
||||
<span class="filter-btn active">All</span>
|
||||
<span class="filter-btn">Fetch/XHR</span>
|
||||
<span class="filter-btn">JS</span>
|
||||
@@ -1123,28 +1253,50 @@ onUnmounted(() => {
|
||||
<div class="network-split-view">
|
||||
<div class="network-grid">
|
||||
<div class="network-grid-header">
|
||||
<div class="col name">Name</div>
|
||||
<div class="col status">Status</div>
|
||||
<div class="col type">Type</div>
|
||||
<div class="col size">Size</div>
|
||||
<div class="col time">Time</div>
|
||||
<div class="col waterfall">Waterfall</div>
|
||||
<div class="col name">
|
||||
Name
|
||||
</div>
|
||||
<div class="col status">
|
||||
Status
|
||||
</div>
|
||||
<div class="col type">
|
||||
Type
|
||||
</div>
|
||||
<div class="col size">
|
||||
Size
|
||||
</div>
|
||||
<div class="col time">
|
||||
Time
|
||||
</div>
|
||||
<div class="col waterfall">
|
||||
Waterfall
|
||||
</div>
|
||||
</div>
|
||||
<div class="network-rows">
|
||||
<div
|
||||
class="network-row"
|
||||
v-for="(req, idx) in networkRequests"
|
||||
:key="idx"
|
||||
class="network-row"
|
||||
:class="{
|
||||
selected: selectedRequest && selectedRequest.id === req.id
|
||||
}"
|
||||
@click="selectRequest(req)"
|
||||
>
|
||||
<div class="col name">{{ req.name }}</div>
|
||||
<div class="col status">{{ req.status }}</div>
|
||||
<div class="col type">{{ req.type }}</div>
|
||||
<div class="col size">{{ req.size }}</div>
|
||||
<div class="col time">{{ req.time }}</div>
|
||||
<div class="col name">
|
||||
{{ req.name }}
|
||||
</div>
|
||||
<div class="col status">
|
||||
{{ req.status }}
|
||||
</div>
|
||||
<div class="col type">
|
||||
{{ req.type }}
|
||||
</div>
|
||||
<div class="col size">
|
||||
{{ req.size }}
|
||||
</div>
|
||||
<div class="col time">
|
||||
{{ req.time }}
|
||||
</div>
|
||||
<div class="col waterfall">
|
||||
<div
|
||||
class="waterfall-bar"
|
||||
@@ -1152,45 +1304,46 @@ onUnmounted(() => {
|
||||
width: req.waterfall + 'px',
|
||||
left: idx * 10 + 'px'
|
||||
}"
|
||||
></div>
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Network Detail Panel (Right Side) -->
|
||||
<div class="network-detail" v-if="selectedRequest">
|
||||
<div
|
||||
v-if="selectedRequest"
|
||||
class="network-detail"
|
||||
>
|
||||
<div class="detail-header">
|
||||
<span
|
||||
class="detail-title"
|
||||
:class="{ active: activeDetailTab === 'headers' }"
|
||||
@click="activeDetailTab = 'headers'"
|
||||
>Headers</span
|
||||
>
|
||||
>Headers</span>
|
||||
<span
|
||||
class="detail-title"
|
||||
:class="{ active: activeDetailTab === 'preview' }"
|
||||
@click="activeDetailTab = 'preview'"
|
||||
>Preview</span
|
||||
>
|
||||
>Preview</span>
|
||||
<span
|
||||
class="detail-title"
|
||||
:class="{ active: activeDetailTab === 'response' }"
|
||||
@click="activeDetailTab = 'response'"
|
||||
>Response</span
|
||||
>
|
||||
<span class="close-detail" @click="selectedRequest = null"
|
||||
>×</span
|
||||
>
|
||||
>Response</span>
|
||||
<span
|
||||
class="close-detail"
|
||||
@click="selectedRequest = null"
|
||||
>×</span>
|
||||
</div>
|
||||
<div class="detail-content">
|
||||
<div v-if="activeDetailTab === 'headers'">
|
||||
<div class="detail-section">
|
||||
<div class="section-label">General</div>
|
||||
<div class="section-label">
|
||||
General
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="key">Request URL:</span>
|
||||
<span class="val"
|
||||
>http://localhost:3000/{{ selectedRequest.name }}</span
|
||||
>
|
||||
<span class="val">http://localhost:3000/{{ selectedRequest.name }}</span>
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="key">Request Method:</span>
|
||||
@@ -1198,31 +1351,33 @@ onUnmounted(() => {
|
||||
</div>
|
||||
<div class="detail-row">
|
||||
<span class="key">Status Code:</span>
|
||||
<span class="val status-code"
|
||||
>{{ selectedRequest.status }} OK</span
|
||||
>
|
||||
<span class="val status-code">{{ selectedRequest.status }} OK</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="detail-section">
|
||||
<div class="section-label">Response Headers</div>
|
||||
<div class="section-label">
|
||||
Response Headers
|
||||
</div>
|
||||
<div
|
||||
class="detail-row"
|
||||
v-for="(val, key) in selectedRequest.headers"
|
||||
:key="key"
|
||||
class="detail-row"
|
||||
>
|
||||
<span class="key">{{ key }}:</span>
|
||||
<span class="val">{{ val }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="detail-section"
|
||||
v-if="selectedRequest.requestHeaders"
|
||||
class="detail-section"
|
||||
>
|
||||
<div class="section-label">Request Headers</div>
|
||||
<div class="section-label">
|
||||
Request Headers
|
||||
</div>
|
||||
<div
|
||||
class="detail-row"
|
||||
v-for="(val, key) in selectedRequest.requestHeaders"
|
||||
:key="key"
|
||||
class="detail-row"
|
||||
>
|
||||
<span class="key">{{ key }}:</span>
|
||||
<span class="val">{{ val }}</span>
|
||||
@@ -1232,7 +1387,9 @@ onUnmounted(() => {
|
||||
|
||||
<div v-if="activeDetailTab === 'preview'">
|
||||
<div class="detail-section">
|
||||
<div class="section-label">Preview</div>
|
||||
<div class="section-label">
|
||||
Preview
|
||||
</div>
|
||||
<div class="preview-content">
|
||||
{{ selectedRequest.preview }}
|
||||
</div>
|
||||
@@ -1241,7 +1398,9 @@ onUnmounted(() => {
|
||||
|
||||
<div v-if="activeDetailTab === 'response'">
|
||||
<div class="detail-section">
|
||||
<div class="section-label">Response</div>
|
||||
<div class="section-label">
|
||||
Response
|
||||
</div>
|
||||
<div class="preview-content">
|
||||
{{ selectedRequest.preview }}
|
||||
</div>
|
||||
@@ -1259,16 +1418,26 @@ onUnmounted(() => {
|
||||
>
|
||||
<div class="storage-sidebar">
|
||||
<div class="sidebar-section">
|
||||
<div class="section-title">Application</div>
|
||||
<div class="section-item">Manifest</div>
|
||||
<div class="section-item">Service Workers</div>
|
||||
<div class="section-title">
|
||||
Application
|
||||
</div>
|
||||
<div class="section-item">
|
||||
Manifest
|
||||
</div>
|
||||
<div class="section-item">
|
||||
Service Workers
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-section">
|
||||
<div class="section-title">Storage</div>
|
||||
<div class="section-title">
|
||||
Storage
|
||||
</div>
|
||||
<div class="section-item active">
|
||||
<span class="arrow">▼</span> Local Storage
|
||||
</div>
|
||||
<div class="section-item indent">http://localhost</div>
|
||||
<div class="section-item indent">
|
||||
http://localhost
|
||||
</div>
|
||||
<div class="section-item">
|
||||
<span class="arrow">▶</span> Session Storage
|
||||
</div>
|
||||
@@ -1280,16 +1449,24 @@ onUnmounted(() => {
|
||||
<div class="storage-content">
|
||||
<div class="storage-table">
|
||||
<div class="table-header">
|
||||
<div class="col key">Key</div>
|
||||
<div class="col value">Value</div>
|
||||
<div class="col key">
|
||||
Key
|
||||
</div>
|
||||
<div class="col value">
|
||||
Value
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="table-row"
|
||||
v-for="(item, idx) in localStorageData"
|
||||
:key="idx"
|
||||
class="table-row"
|
||||
>
|
||||
<div class="col key">{{ item.key }}</div>
|
||||
<div class="col value">{{ item.value }}</div>
|
||||
<div class="col key">
|
||||
{{ item.key }}
|
||||
</div>
|
||||
<div class="col value">
|
||||
{{ item.value }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1297,7 +1474,10 @@ onUnmounted(() => {
|
||||
</div>
|
||||
|
||||
<!-- Info Bar Overlay -->
|
||||
<div class="info-bar" v-if="hoverInfo">
|
||||
<div
|
||||
v-if="hoverInfo"
|
||||
class="info-bar"
|
||||
>
|
||||
<span class="info-icon">💡</span> {{ hoverInfo }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+101
-52
@@ -182,21 +182,29 @@ const selectNode = (node) => {
|
||||
<div class="virtual-page-container">
|
||||
<div class="virtual-browser-bar">
|
||||
<div class="dots">
|
||||
<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="address-bar">
|
||||
http://localhost:3000/demo
|
||||
</div>
|
||||
<div class="address-bar">http://localhost:3000/demo</div>
|
||||
</div>
|
||||
<div
|
||||
class="virtual-page-content"
|
||||
:style="liveStyles.container"
|
||||
@click.self="selectNode('container')"
|
||||
>
|
||||
<h1 :style="liveStyles.h1" @click.stop="selectNode('h1')">
|
||||
<h1
|
||||
:style="liveStyles.h1"
|
||||
@click.stop="selectNode('h1')"
|
||||
>
|
||||
{{ liveContent.h1 }}
|
||||
</h1>
|
||||
<button :style="liveStyles.button" @click.stop="selectNode('button')">
|
||||
<button
|
||||
:style="liveStyles.button"
|
||||
@click.stop="selectNode('button')"
|
||||
>
|
||||
{{ liveContent.button }}
|
||||
</button>
|
||||
</div>
|
||||
@@ -214,20 +222,33 @@ const selectNode = (node) => {
|
||||
class="icon-btn element-picker"
|
||||
title="选择页面中的元素以进行检查"
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="#6e6e6e">
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="#6e6e6e"
|
||||
>
|
||||
<path
|
||||
d="M4 4h9v2H4V4zm0 4h5v2H4V8zm0 4h5v2H4v-2zm12-5l-4 4h3v4h2v-4h3l-4-4z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="icon-btn device-toggle" title="切换设备工具栏">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="#6e6e6e">
|
||||
<div
|
||||
class="icon-btn device-toggle"
|
||||
title="切换设备工具栏"
|
||||
>
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="#6e6e6e"
|
||||
>
|
||||
<path
|
||||
d="M17 1.01L7 1c-1.1 0-2 .9-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2V3c0-1.1-.9-1.99-2-1.99zM17 19H7V5h10v14z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="separator"></div>
|
||||
<div class="separator" />
|
||||
<div class="tabs">
|
||||
<div
|
||||
v-for="tab in tabs"
|
||||
@@ -241,81 +262,87 @@ const selectNode = (node) => {
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="icon-btn settings">⚙️</div>
|
||||
<div class="icon-btn close">×</div>
|
||||
<div class="icon-btn settings">
|
||||
⚙️
|
||||
</div>
|
||||
<div class="icon-btn close">
|
||||
×
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Body -->
|
||||
<div class="devtools-body">
|
||||
<!-- Elements Panel -->
|
||||
<div v-if="activeTab === 'elements'" class="panel elements-panel">
|
||||
<div
|
||||
v-if="activeTab === 'elements'"
|
||||
class="panel elements-panel"
|
||||
>
|
||||
<div class="dom-tree-panel">
|
||||
<div class="dom-tree-content">
|
||||
<div
|
||||
class="dom-node"
|
||||
@click="selectNode('container')"
|
||||
:class="{ selected: selectedNode === 'container' }"
|
||||
@click="selectNode('container')"
|
||||
>
|
||||
<div class="line-content">
|
||||
<span class="arrow expanded">▼</span>
|
||||
<span class="tag-name">div</span>
|
||||
<span class="attr-name">class</span>=<span class="attr-val"
|
||||
>"virtual-page-content"</span
|
||||
>
|
||||
<span class="node-trail" v-if="selectedNode === 'container'"
|
||||
>== $0</span
|
||||
>
|
||||
<span class="attr-name">class</span>=<span class="attr-val">"virtual-page-content"</span>
|
||||
<span
|
||||
v-if="selectedNode === 'container'"
|
||||
class="node-trail"
|
||||
>== $0</span>
|
||||
</div>
|
||||
<div class="children">
|
||||
<div
|
||||
class="dom-node"
|
||||
@click.stop="selectNode('h1')"
|
||||
:class="{ selected: selectedNode === 'h1' }"
|
||||
@click.stop="selectNode('h1')"
|
||||
>
|
||||
<div class="line-content">
|
||||
<span class="indent"></span>
|
||||
<span class="indent" />
|
||||
<span class="tag-name">h1</span>
|
||||
<span class="node-trail" v-if="selectedNode === 'h1'"
|
||||
>== $0</span
|
||||
>
|
||||
<span
|
||||
v-if="selectedNode === 'h1'"
|
||||
class="node-trail"
|
||||
>== $0</span>
|
||||
</div>
|
||||
<div class="line-content">
|
||||
<span class="indent"></span>
|
||||
<span class="indent" />
|
||||
<input
|
||||
v-model="liveContent.h1"
|
||||
class="dom-text-input"
|
||||
@click.stop="selectNode('h1')"
|
||||
/>
|
||||
>
|
||||
</div>
|
||||
<div class="line-content">
|
||||
<span class="indent"></span
|
||||
><span class="tag-name">/h1</span>
|
||||
<span class="indent" /><span class="tag-name">/h1</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="dom-node"
|
||||
@click.stop="selectNode('button')"
|
||||
:class="{ selected: selectedNode === 'button' }"
|
||||
@click.stop="selectNode('button')"
|
||||
>
|
||||
<div class="line-content">
|
||||
<span class="indent"></span>
|
||||
<span class="indent" />
|
||||
<span class="tag-name">button</span>
|
||||
<span class="node-trail" v-if="selectedNode === 'button'"
|
||||
>== $0</span
|
||||
>
|
||||
<span
|
||||
v-if="selectedNode === 'button'"
|
||||
class="node-trail"
|
||||
>== $0</span>
|
||||
</div>
|
||||
<div class="line-content">
|
||||
<span class="indent"></span>
|
||||
<span class="indent" />
|
||||
<input
|
||||
v-model="liveContent.button"
|
||||
class="dom-text-input"
|
||||
@click.stop="selectNode('button')"
|
||||
/>
|
||||
>
|
||||
</div>
|
||||
<div class="line-content">
|
||||
<span class="indent"></span
|
||||
><span class="tag-name">/button</span>
|
||||
<span class="indent" /><span class="tag-name">/button</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -333,15 +360,31 @@ const selectNode = (node) => {
|
||||
<!-- Interactive Styles Panel -->
|
||||
<div class="styles-panel">
|
||||
<div class="styles-tabs">
|
||||
<div class="style-tab active">样式 (Styles)</div>
|
||||
<div class="style-tab">计算 (Computed)</div>
|
||||
<div class="style-tab active">
|
||||
样式 (Styles)
|
||||
</div>
|
||||
<div class="style-tab">
|
||||
计算 (Computed)
|
||||
</div>
|
||||
</div>
|
||||
<div class="styles-content">
|
||||
<!-- Preset Selector -->
|
||||
<div class="style-section" v-if="availablePresets.length > 0">
|
||||
<div class="style-section-title">✨ 快速预设 (Presets)</div>
|
||||
<select class="preset-select" @change="applyPreset">
|
||||
<option value="" disabled selected>
|
||||
<div
|
||||
v-if="availablePresets.length > 0"
|
||||
class="style-section"
|
||||
>
|
||||
<div class="style-section-title">
|
||||
✨ 快速预设 (Presets)
|
||||
</div>
|
||||
<select
|
||||
class="preset-select"
|
||||
@change="applyPreset"
|
||||
>
|
||||
<option
|
||||
value=""
|
||||
disabled
|
||||
selected
|
||||
>
|
||||
选择一种风格 (Select Preset)...
|
||||
</option>
|
||||
<option
|
||||
@@ -356,29 +399,35 @@ const selectNode = (node) => {
|
||||
|
||||
<!-- CSS Properties -->
|
||||
<div class="style-rule">
|
||||
<div class="selector">element.style {</div>
|
||||
<div class="selector">
|
||||
element.style {
|
||||
</div>
|
||||
<div
|
||||
class="property"
|
||||
v-for="(val, key) in currentStyles"
|
||||
:key="key"
|
||||
class="property"
|
||||
>
|
||||
<span class="prop-name">{{ key }}</span
|
||||
>:
|
||||
<span class="prop-name">{{ key }}</span>:
|
||||
<input
|
||||
v-model="liveStyles[selectedNode][key]"
|
||||
class="style-input"
|
||||
/>
|
||||
>
|
||||
;
|
||||
</div>
|
||||
<div class="selector">}</div>
|
||||
<div class="selector">
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div class="style-add-hint"></div>
|
||||
<div class="style-add-hint" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Other Panels (Simplified placeholders) -->
|
||||
<div v-else class="panel placeholder-panel">
|
||||
<div
|
||||
v-else
|
||||
class="panel placeholder-panel"
|
||||
>
|
||||
<div class="placeholder-text">
|
||||
此演示主要展示 Elements 面板的实时编辑功能。请切换回 "元素" 面板。
|
||||
</div>
|
||||
|
||||
+73
-26
@@ -59,11 +59,21 @@ const clearAll = () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-card class="app-demo" shadow="hover">
|
||||
<el-card
|
||||
class="app-demo"
|
||||
shadow="hover"
|
||||
>
|
||||
<template #header>
|
||||
<div class="header">
|
||||
<span class="title">Application (应用面板)</span>
|
||||
<el-button type="danger" size="small" icon="Delete" @click="clearAll">Clear All</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
icon="Delete"
|
||||
@click="clearAll"
|
||||
>
|
||||
Clear All
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -94,26 +104,54 @@ const clearAll = () => {
|
||||
|
||||
<div class="content">
|
||||
<div class="toolbar">
|
||||
<el-input
|
||||
v-model="newEntry.key"
|
||||
placeholder="Key"
|
||||
size="small"
|
||||
style="width: 120px"
|
||||
/>
|
||||
<el-input
|
||||
v-model="newEntry.value"
|
||||
placeholder="Value"
|
||||
size="small"
|
||||
style="width: 120px"
|
||||
/>
|
||||
<el-button type="primary" size="small" @click="addEntry">Add</el-button>
|
||||
<el-input
|
||||
v-model="newEntry.key"
|
||||
placeholder="Key"
|
||||
size="small"
|
||||
style="width: 120px"
|
||||
/>
|
||||
<el-input
|
||||
v-model="newEntry.value"
|
||||
placeholder="Value"
|
||||
size="small"
|
||||
style="width: 120px"
|
||||
/>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="addEntry"
|
||||
>
|
||||
Add
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-table :data="storageData[activeTab]" style="width: 100%" height="250" border>
|
||||
<el-table-column prop="key" label="Key" width="120" />
|
||||
<el-table-column prop="value" label="Value" min-width="150" />
|
||||
<el-table-column v-if="activeTab === 'cookies'" prop="domain" label="Domain" width="110" />
|
||||
<el-table-column label="Action" width="70" align="center">
|
||||
<el-table
|
||||
:data="storageData[activeTab]"
|
||||
style="width: 100%"
|
||||
height="250"
|
||||
border
|
||||
>
|
||||
<el-table-column
|
||||
prop="key"
|
||||
label="Key"
|
||||
width="120"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="value"
|
||||
label="Value"
|
||||
min-width="150"
|
||||
/>
|
||||
<el-table-column
|
||||
v-if="activeTab === 'cookies'"
|
||||
prop="domain"
|
||||
label="Domain"
|
||||
width="110"
|
||||
/>
|
||||
<el-table-column
|
||||
label="Action"
|
||||
width="70"
|
||||
align="center"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="danger"
|
||||
@@ -126,14 +164,23 @@ const clearAll = () => {
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="info-bar" v-if="activeTab === 'local'">
|
||||
持久化存储:即便关闭浏览器,数据也会保留。
|
||||
<div
|
||||
v-if="activeTab === 'local'"
|
||||
class="info-bar"
|
||||
>
|
||||
持久化存储:即便关闭浏览器,数据也会保留。
|
||||
</div>
|
||||
<div class="info-bar" v-else-if="activeTab === 'session'">
|
||||
临时存储:关闭标签页后,数据会被清空。
|
||||
<div
|
||||
v-else-if="activeTab === 'session'"
|
||||
class="info-bar"
|
||||
>
|
||||
临时存储:关闭标签页后,数据会被清空。
|
||||
</div>
|
||||
<div class="info-bar" v-else>
|
||||
Cookies:通常用于身份验证,会随请求发送给服务器。
|
||||
<div
|
||||
v-else
|
||||
class="info-bar"
|
||||
>
|
||||
Cookies:通常用于身份验证,会随请求发送给服务器。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -90,20 +90,49 @@ const runShortcut = (cmd) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-card class="console-demo" shadow="hover">
|
||||
<el-card
|
||||
class="console-demo"
|
||||
shadow="hover"
|
||||
>
|
||||
<template #header>
|
||||
<div class="header">
|
||||
<span class="title">Console (控制台)</span>
|
||||
<el-button size="small" @click="clearConsole" icon="Delete" circle title="Clear console" />
|
||||
<el-button
|
||||
size="small"
|
||||
icon="Delete"
|
||||
circle
|
||||
title="Clear console"
|
||||
@click="clearConsole"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="console-body" ref="consoleRef">
|
||||
<div v-for="(log, index) in logs" :key="index" class="log-item" :class="log.type">
|
||||
<span class="icon" v-if="log.type === 'error'">❌</span>
|
||||
<span class="icon" v-else-if="log.type === 'warn'">⚠️</span>
|
||||
<span class="icon" v-else-if="log.type === 'info'">ℹ️</span>
|
||||
<span class="icon" v-else-if="log.type === 'result'">⬅️</span>
|
||||
<div
|
||||
ref="consoleRef"
|
||||
class="console-body"
|
||||
>
|
||||
<div
|
||||
v-for="(log, index) in logs"
|
||||
:key="index"
|
||||
class="log-item"
|
||||
:class="log.type"
|
||||
>
|
||||
<span
|
||||
v-if="log.type === 'error'"
|
||||
class="icon"
|
||||
>❌</span>
|
||||
<span
|
||||
v-else-if="log.type === 'warn'"
|
||||
class="icon"
|
||||
>⚠️</span>
|
||||
<span
|
||||
v-else-if="log.type === 'info'"
|
||||
class="icon"
|
||||
>ℹ️</span>
|
||||
<span
|
||||
v-else-if="log.type === 'result'"
|
||||
class="icon"
|
||||
>⬅️</span>
|
||||
<span class="content">{{ log.message }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -114,7 +143,9 @@ const runShortcut = (cmd) => {
|
||||
placeholder="输入 JS 代码,按回车执行..."
|
||||
@keyup.enter="executeCommand"
|
||||
>
|
||||
<template #prepend>></template>
|
||||
<template #prepend>
|
||||
>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
|
||||
|
||||
+24
-11
@@ -35,7 +35,10 @@ const updateStyle = (prop, value) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-card class="elements-demo" shadow="hover">
|
||||
<el-card
|
||||
class="elements-demo"
|
||||
shadow="hover"
|
||||
>
|
||||
<template #header>
|
||||
<div class="header">
|
||||
<span class="title">Elements (元素面板)</span>
|
||||
@@ -45,7 +48,9 @@ const updateStyle = (prop, value) => {
|
||||
<div class="devtools-layout">
|
||||
<!-- Left: DOM Tree -->
|
||||
<div class="panel dom-panel">
|
||||
<div class="panel-header">DOM Tree</div>
|
||||
<div class="panel-header">
|
||||
DOM Tree
|
||||
</div>
|
||||
<div class="dom-content">
|
||||
<div class="dom-line">
|
||||
<span class="tag"><div</span> <span class="attr">id</span>="app" <span class="attr">class</span>="container"<span class="tag">></span>
|
||||
@@ -79,18 +84,24 @@ const updateStyle = (prop, value) => {
|
||||
|
||||
<!-- Right: Styles -->
|
||||
<div class="panel style-panel">
|
||||
<div class="panel-header">Styles ({{ selectedElement === 'box' ? '.box' : '.text' }})</div>
|
||||
<div class="panel-header">
|
||||
Styles ({{ selectedElement === 'box' ? '.box' : '.text' }})
|
||||
</div>
|
||||
<div class="style-content">
|
||||
<div class="css-rule">
|
||||
<span class="selector">{{ selectedElement === 'box' ? '.box' : '.text' }}</span> {
|
||||
<div v-for="(value, prop) in styles[selectedElement]" :key="prop" class="css-prop">
|
||||
<div
|
||||
v-for="(value, prop) in styles[selectedElement]"
|
||||
:key="prop"
|
||||
class="css-prop"
|
||||
>
|
||||
<span class="prop-name">{{ prop }}</span>:
|
||||
<span class="prop-value">
|
||||
<!-- Simple editable input simulation -->
|
||||
<input
|
||||
v-model="styles[selectedElement][prop]"
|
||||
class="style-input"
|
||||
/>
|
||||
<!-- Simple editable input simulation -->
|
||||
<input
|
||||
v-model="styles[selectedElement][prop]"
|
||||
class="style-input"
|
||||
>
|
||||
</span>;
|
||||
</div>
|
||||
}
|
||||
@@ -101,7 +112,9 @@ const updateStyle = (prop, value) => {
|
||||
|
||||
<!-- Preview Area -->
|
||||
<div class="preview-area">
|
||||
<div class="preview-label">页面预览 (Page Preview)</div>
|
||||
<div class="preview-label">
|
||||
页面预览 (Page Preview)
|
||||
</div>
|
||||
<div class="preview-content">
|
||||
<div :style="styles.box">
|
||||
<span :style="styles.text">Hello DevTools</span>
|
||||
@@ -110,7 +123,7 @@ const updateStyle = (prop, value) => {
|
||||
</div>
|
||||
|
||||
<div class="footer-tip">
|
||||
点击左侧 DOM 树中的元素,在右侧 Styles 面板修改样式,下方预览会实时更新。
|
||||
点击左侧 DOM 树中的元素,在右侧 Styles 面板修改样式,下方预览会实时更新。
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
+83
-33
@@ -60,13 +60,30 @@ const addFailedRequest = () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-card class="network-demo" shadow="hover">
|
||||
<el-card
|
||||
class="network-demo"
|
||||
shadow="hover"
|
||||
>
|
||||
<template #header>
|
||||
<div class="header">
|
||||
<span class="title">Network (网络面板)</span>
|
||||
<div class="actions">
|
||||
<el-button type="primary" size="small" icon="Refresh" @click="refresh">刷新页面</el-button>
|
||||
<el-button type="danger" size="small" icon="Warning" @click="addFailedRequest">模拟请求失败</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
icon="Refresh"
|
||||
@click="refresh"
|
||||
>
|
||||
刷新页面
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
icon="Warning"
|
||||
@click="addFailedRequest"
|
||||
>
|
||||
模拟请求失败
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -75,37 +92,68 @@ const addFailedRequest = () => {
|
||||
:data="requests"
|
||||
style="width: 100%"
|
||||
height="300"
|
||||
@row-click="showDetails"
|
||||
class="network-table"
|
||||
@row-click="showDetails"
|
||||
>
|
||||
<el-table-column prop="name" label="Name" min-width="120">
|
||||
<template #default="scope">
|
||||
<span :class="{ error: scope.row.status >= 400 }">{{ scope.row.name }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="Status" width="80">
|
||||
<el-table-column
|
||||
prop="name"
|
||||
label="Name"
|
||||
min-width="120"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.status >= 400 ? 'danger' : 'success'" size="small">
|
||||
<span :class="{ error: scope.row.status >= 400 }">{{ scope.row.name }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="status"
|
||||
label="Status"
|
||||
width="80"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-tag
|
||||
:type="scope.row.status >= 400 ? 'danger' : 'success'"
|
||||
size="small"
|
||||
>
|
||||
{{ scope.row.status }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="type" label="Type" width="90" />
|
||||
<el-table-column prop="size" label="Size" width="80" />
|
||||
<el-table-column prop="time" label="Time" width="80">
|
||||
<template #default="scope">{{ scope.row.time }}ms</template>
|
||||
<el-table-column
|
||||
prop="type"
|
||||
label="Type"
|
||||
width="90"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="size"
|
||||
label="Size"
|
||||
width="80"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="time"
|
||||
label="Time"
|
||||
width="80"
|
||||
>
|
||||
<template #default="scope">
|
||||
{{ scope.row.time }}ms
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="Waterfall" min-width="150">
|
||||
<el-table-column
|
||||
label="Waterfall"
|
||||
min-width="150"
|
||||
>
|
||||
<template #default="scope">
|
||||
<div class="timeline-container">
|
||||
<div class="timeline-bar" :style="getTimelineStyle(scope.row)"></div>
|
||||
<div
|
||||
class="timeline-bar"
|
||||
:style="getTimelineStyle(scope.row)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="footer-tip">
|
||||
💡 点击某一行可以查看请求详情
|
||||
💡 点击某一行可以查看请求详情
|
||||
</div>
|
||||
|
||||
<!-- Detail Drawer -->
|
||||
@@ -127,30 +175,32 @@ const addFailedRequest = () => {
|
||||
<p><strong>Status Code:</strong> {{ selectedRequest.status }}</p>
|
||||
</div>
|
||||
<div class="detail-section">
|
||||
<h4>Response Headers</h4>
|
||||
<p><strong>Content-Type:</strong> {{ selectedRequest.type === 'document' ? 'text/html' : selectedRequest.type === 'fetch' ? 'application/json' : 'text/plain' }}</p>
|
||||
<p><strong>Cache-Control:</strong> max-age=3600</p>
|
||||
<h4>Response Headers</h4>
|
||||
<p><strong>Content-Type:</strong> {{ selectedRequest.type === 'document' ? 'text/html' : selectedRequest.type === 'fetch' ? 'application/json' : 'text/plain' }}</p>
|
||||
<p><strong>Cache-Control:</strong> max-age=3600</p>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="Preview">
|
||||
<div class="preview-box">
|
||||
<div v-if="selectedRequest.status >= 400">
|
||||
⚠️ Failed to load response data
|
||||
</div>
|
||||
<div v-else-if="selectedRequest.type === 'fetch' || selectedRequest.type === 'xhr'">
|
||||
<pre>{ "id": 123, "data": "Sample API response" }</pre>
|
||||
</div>
|
||||
<div v-else-if="selectedRequest.type === 'png' || selectedRequest.type === 'jpeg'">
|
||||
<div class="fake-image">Image Preview</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<pre><html>...</html></pre>
|
||||
<div v-if="selectedRequest.status >= 400">
|
||||
⚠️ Failed to load response data
|
||||
</div>
|
||||
<div v-else-if="selectedRequest.type === 'fetch' || selectedRequest.type === 'xhr'">
|
||||
<pre>{ "id": 123, "data": "Sample API response" }</pre>
|
||||
</div>
|
||||
<div v-else-if="selectedRequest.type === 'png' || selectedRequest.type === 'jpeg'">
|
||||
<div class="fake-image">
|
||||
Image Preview
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<pre><html>...</html></pre>
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="Response">
|
||||
<div class="response-raw">
|
||||
(Raw response data would appear here)
|
||||
(Raw response data would appear here)
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
+62
-24
@@ -235,16 +235,42 @@ const flatNext = () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-card class="sources-demo" shadow="hover">
|
||||
<el-card
|
||||
class="sources-demo"
|
||||
shadow="hover"
|
||||
>
|
||||
<template #header>
|
||||
<div class="header">
|
||||
<span class="title">Sources (源代码调试)</span>
|
||||
<div class="controls">
|
||||
<el-button-group>
|
||||
<el-button type="success" size="small" icon="VideoPlay" @click="flatRun" :disabled="isRunning && demoState.line !== -1 && !breakpoints.includes(demoState.line)">Run</el-button>
|
||||
<el-button type="primary" size="small" icon="VideoPause" @click="flatResume" :disabled="!breakpoints.includes(demoState.line)">Resume</el-button>
|
||||
<el-button type="info" size="small" icon="ArrowRight" @click="flatNext">Step</el-button>
|
||||
</el-button-group>
|
||||
<el-button-group>
|
||||
<el-button
|
||||
type="success"
|
||||
size="small"
|
||||
icon="VideoPlay"
|
||||
:disabled="isRunning && demoState.line !== -1 && !breakpoints.includes(demoState.line)"
|
||||
@click="flatRun"
|
||||
>
|
||||
Run
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
icon="VideoPause"
|
||||
:disabled="!breakpoints.includes(demoState.line)"
|
||||
@click="flatResume"
|
||||
>
|
||||
Resume
|
||||
</el-button>
|
||||
<el-button
|
||||
type="info"
|
||||
size="small"
|
||||
icon="ArrowRight"
|
||||
@click="flatNext"
|
||||
>
|
||||
Step
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -261,38 +287,50 @@ const flatNext = () => {
|
||||
}"
|
||||
@click="toggleBreakpoint(index)"
|
||||
>
|
||||
<div class="line-num">{{ index + 1 }}</div>
|
||||
<div class="code-text">{{ line }}</div>
|
||||
<div class="line-num">
|
||||
{{ index + 1 }}
|
||||
</div>
|
||||
<div class="code-text">
|
||||
{{ line }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sidebar">
|
||||
<div class="section">
|
||||
<div class="section-title">Scope (Variables)</div>
|
||||
<div class="var-list">
|
||||
<div class="var-item">
|
||||
<span class="name">count:</span>
|
||||
<span class="value">{{ demoState.vars.count !== undefined ? demoState.vars.count : 'undefined' }}</span>
|
||||
</div>
|
||||
<div class="var-item">
|
||||
<span class="name">max:</span>
|
||||
<span class="value">{{ demoState.vars.max !== undefined ? demoState.vars.max : 'undefined' }}</span>
|
||||
</div>
|
||||
<div class="section-title">
|
||||
Scope (Variables)
|
||||
</div>
|
||||
<div class="var-list">
|
||||
<div class="var-item">
|
||||
<span class="name">count:</span>
|
||||
<span class="value">{{ demoState.vars.count !== undefined ? demoState.vars.count : 'undefined' }}</span>
|
||||
</div>
|
||||
<div class="var-item">
|
||||
<span class="name">max:</span>
|
||||
<span class="value">{{ demoState.vars.max !== undefined ? demoState.vars.max : 'undefined' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="section-title">Console Output</div>
|
||||
<div class="output-list">
|
||||
<div v-for="(log, i) in demoState.output" :key="i" class="log-line">
|
||||
{{ log }}
|
||||
</div>
|
||||
<div class="section-title">
|
||||
Console Output
|
||||
</div>
|
||||
<div class="output-list">
|
||||
<div
|
||||
v-for="(log, i) in demoState.output"
|
||||
:key="i"
|
||||
class="log-line"
|
||||
>
|
||||
{{ log }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer-tip">
|
||||
点击行号设置断点。点击 Run 开始执行,代码将在断点处暂停。
|
||||
点击行号设置断点。点击 Run 开始执行,代码将在断点处暂停。
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user