@@ -26,7 +29,9 @@
-
@@ -64,7 +68,9 @@
-
🦍 Monolithic App (Tomcat/Django)
+
+ 🦍 Monolithic App (Tomcat/Django)
+
User
Order
@@ -110,7 +116,6 @@
BaaS (Auth0, Supabase, Stripe)
-
@@ -122,7 +127,9 @@
{{ stages[currentStage].opsIcon }}
-
{{ stages[currentStage].opsTitle }}
+
+ {{ stages[currentStage].opsTitle }}
+
{{ stages[currentStage].opsDesc }}
@@ -152,7 +159,8 @@ const stages = [
desc: 'In the beginning, servers were physical machines. We uploaded files via FTP. Backend logic was often simple Perl/CGI scripts executing one by one.',
opsIcon: '🐌',
opsTitle: 'Manual FTP Upload',
- opsDesc: 'Development was slow. "It works on my machine" was the common nightmare. Scaling meant buying a bigger physical computer.'
+ opsDesc:
+ 'Development was slow. "It works on my machine" was the common nightmare. Scaling meant buying a bigger physical computer.'
},
{
year: '2000s',
@@ -161,7 +169,8 @@ const stages = [
desc: 'Frameworks like Java Spring, Rails, Django appeared. All logic (User, Order, Pay) was packed into ONE giant process. Simple to develop, hard to scale.',
opsIcon: '🐳',
opsTitle: 'Virtual Machines (VM)',
- opsDesc: 'We started using VMs (AWS EC2). Scaling meant copying the entire giant application to multiple servers behind a Load Balancer.'
+ opsDesc:
+ 'We started using VMs (AWS EC2). Scaling meant copying the entire giant application to multiple servers behind a Load Balancer.'
},
{
year: '2014+',
@@ -170,7 +179,8 @@ const stages = [
desc: 'Breaking the monolith! Each function (User, Order) became a separate tiny server. Docker changed the game by packaging dependencies together.',
opsIcon: '☸️',
opsTitle: 'Kubernetes (K8s)',
- opsDesc: 'Orchestrating thousands of containers. Complexity exploded, but teams could work independently and scale specific parts (e.g., just the Payment service).'
+ opsDesc:
+ 'Orchestrating thousands of containers. Complexity exploded, but teams could work independently and scale specific parts (e.g., just the Payment service).'
},
{
year: '2020s+',
@@ -179,7 +189,8 @@ const stages = [
desc: 'No more managing servers. You just write a function (e.g., "resize image") and upload it. The cloud provider runs it only when needed (Pay-per-use).',
opsIcon: '⚡',
opsTitle: 'GitOps & Edge',
- opsDesc: 'Push to Git -> Auto Deploy to global Edge nodes (Vercel, Cloudflare). Backend becomes "Functions + Managed Services (BaaS)".'
+ opsDesc:
+ 'Push to Git -> Auto Deploy to global Edge nodes (Vercel, Cloudflare). Backend becomes "Functions + Managed Services (BaaS)".'
}
]
@@ -188,11 +199,13 @@ const stages = [
.backend-evolution-demo {
border-radius: 16px;
background: var(--vp-c-bg);
- box-shadow: 0 8px 30px rgba(0,0,0,0.05);
+ box-shadow: 0 8px 30px rgba(0, 0, 0, 0.05);
border: 1px solid var(--vp-c-divider);
overflow: hidden;
margin: 2rem 0;
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
+ font-family:
+ -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial,
+ sans-serif;
}
/* Timeline (Reused) */
@@ -230,8 +243,13 @@ const stages = [
opacity: 0.6;
}
-.timeline-node:hover { opacity: 0.9; }
-.timeline-node.active, .timeline-node.passed { opacity: 1; }
+.timeline-node:hover {
+ opacity: 0.9;
+}
+.timeline-node.active,
+.timeline-node.passed {
+ opacity: 1;
+}
.node-dot {
width: 16px;
@@ -259,8 +277,14 @@ const stages = [
transform: scale(1.3);
box-shadow: 0 0 0 4px var(--vp-c-bg-soft);
}
-.timeline-node.active .inner-dot { width: 8px; height: 8px; }
-.timeline-node.passed .node-dot { border-color: var(--vp-c-brand); background: var(--vp-c-brand); }
+.timeline-node.active .inner-dot {
+ width: 8px;
+ height: 8px;
+}
+.timeline-node.passed .node-dot {
+ border-color: var(--vp-c-brand);
+ background: var(--vp-c-brand);
+}
.node-content {
text-align: center;
@@ -286,7 +310,10 @@ const stages = [
}
/* Content */
-.content-wrapper { padding: 2rem; min-height: 400px; }
+.content-wrapper {
+ padding: 2rem;
+ min-height: 400px;
+}
.header-section {
text-align: center;
@@ -298,13 +325,26 @@ const stages = [
.header-section h3 {
font-size: 1.5rem;
margin-bottom: 0.5rem;
- background: linear-gradient(120deg, #f59e0b, #ea580c); /* Orange/Amber for Backend */
+ background: linear-gradient(
+ 120deg,
+ #f59e0b,
+ #ea580c
+ ); /* Orange/Amber for Backend */
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
-.stage-index { color: var(--vp-c-text-3); -webkit-text-fill-color: var(--vp-c-text-3); margin-right: 0.5rem; font-weight: normal; }
-.header-section p { font-size: 1rem; color: var(--vp-c-text-2); line-height: 1.6; }
+.stage-index {
+ color: var(--vp-c-text-3);
+ -webkit-text-fill-color: var(--vp-c-text-3);
+ margin-right: 0.5rem;
+ font-weight: normal;
+}
+.header-section p {
+ font-size: 1rem;
+ color: var(--vp-c-text-2);
+ line-height: 1.6;
+}
/* Visualizations */
.visualization-grid {
@@ -314,37 +354,60 @@ const stages = [
align-items: stretch;
}
-@media (max-width: 768px) { .visualization-grid { grid-template-columns: 1fr; } }
+@media (max-width: 768px) {
+ .visualization-grid {
+ grid-template-columns: 1fr;
+ }
+}
.mac-window {
border-radius: 12px;
- border: 1px solid rgba(0,0,0,0.1);
- box-shadow: 0 10px 30px rgba(0,0,0,0.05);
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05);
overflow: hidden;
display: flex;
flex-direction: column;
background: white;
transition: transform 0.3s;
}
-.mac-window:hover { transform: translateY(-5px); }
+.mac-window:hover {
+ transform: translateY(-5px);
+}
-.arch-window { background: #f1f5f9; }
-.ops-window { background: white; }
+.arch-window {
+ background: #f1f5f9;
+}
+.ops-window {
+ background: white;
+}
.window-bar {
padding: 0.8rem 1rem;
background: white;
- border-bottom: 1px solid rgba(0,0,0,0.05);
+ border-bottom: 1px solid rgba(0, 0, 0, 0.05);
display: flex;
align-items: center;
position: relative;
}
-.traffic-lights { display: flex; gap: 6px; }
-.light { width: 10px; height: 10px; border-radius: 50%; }
-.light.red { background: #ff5f56; }
-.light.yellow { background: #ffbd2e; }
-.light.green { background: #27c93f; }
+.traffic-lights {
+ display: flex;
+ gap: 6px;
+}
+.light {
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+}
+.light.red {
+ background: #ff5f56;
+}
+.light.yellow {
+ background: #ffbd2e;
+}
+.light.green {
+ background: #27c93f;
+}
.window-title {
position: absolute;
@@ -356,7 +419,8 @@ const stages = [
font-weight: 600;
}
-.arch-canvas, .ops-canvas {
+.arch-canvas,
+.ops-canvas {
padding: 2rem;
flex: 1;
display: flex;
@@ -373,32 +437,140 @@ const stages = [
border-radius: 8px;
text-align: center;
}
-.file-system { margin-top: 1rem; background: white; padding: 0.5rem; border-radius: 4px; font-family: monospace; font-size: 0.8rem; }
-.request-arrow { margin-top: 1rem; display: flex; flex-direction: column; align-items: center; font-size: 0.8rem; color: #64748b; }
+.file-system {
+ margin-top: 1rem;
+ background: white;
+ padding: 0.5rem;
+ border-radius: 4px;
+ font-family: monospace;
+ font-size: 0.8rem;
+}
+.request-arrow {
+ margin-top: 1rem;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ font-size: 0.8rem;
+ color: #64748b;
+}
-.server-box.big { background: #dbeafe; border-color: #3b82f6; width: 100%; max-width: 250px; }
-.modules-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; margin: 1rem 0; }
-.module { background: #bfdbfe; padding: 4px; border-radius: 4px; font-size: 0.8rem; color: #1e40af; }
-.db-connection { font-size: 0.8rem; display: flex; flex-direction: column; align-items: center; }
+.server-box.big {
+ background: #dbeafe;
+ border-color: #3b82f6;
+ width: 100%;
+ max-width: 250px;
+}
+.modules-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 4px;
+ margin: 1rem 0;
+}
+.module {
+ background: #bfdbfe;
+ padding: 4px;
+ border-radius: 4px;
+ font-size: 0.8rem;
+ color: #1e40af;
+}
+.db-connection {
+ font-size: 0.8rem;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
-.cloud-bg { width: 100%; }
-.service-mesh { display: flex; gap: 1rem; justify-content: center; }
-.service { background: white; border: 1px solid #e2e8f0; padding: 0.8rem; border-radius: 6px; text-align: center; box-shadow: 0 4px 6px rgba(0,0,0,0.05); display: flex; flex-direction: column; }
-.service small { color: #64748b; font-size: 0.7rem; margin-top: 4px; }
-.comm-lines { margin-top: 1rem; font-size: 0.8rem; color: #94a3b8; text-align: center; border-top: 1px dashed #cbd5e1; width: 80%; padding-top: 4px; }
+.cloud-bg {
+ width: 100%;
+}
+.service-mesh {
+ display: flex;
+ gap: 1rem;
+ justify-content: center;
+}
+.service {
+ background: white;
+ border: 1px solid #e2e8f0;
+ padding: 0.8rem;
+ border-radius: 6px;
+ text-align: center;
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
+ display: flex;
+ flex-direction: column;
+}
+.service small {
+ color: #64748b;
+ font-size: 0.7rem;
+ margin-top: 4px;
+}
+.comm-lines {
+ margin-top: 1rem;
+ font-size: 0.8rem;
+ color: #94a3b8;
+ text-align: center;
+ border-top: 1px dashed #cbd5e1;
+ width: 80%;
+ padding-top: 4px;
+}
-.function-cloud { display: flex; flex-wrap: wrap; gap: 1rem; justify-content: center; margin-bottom: 1.5rem; }
-.func-node { background: #fef3c7; border: 1px solid #f59e0b; color: #b45309; padding: 6px 12px; border-radius: 20px; font-family: monospace; font-size: 0.8rem; }
-.baas-layer { width: 100%; background: #e0e7ff; padding: 0.5rem; text-align: center; border-radius: 6px; font-size: 0.8rem; color: #4338ca; font-weight: bold; }
+.function-cloud {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 1rem;
+ justify-content: center;
+ margin-bottom: 1.5rem;
+}
+.func-node {
+ background: #fef3c7;
+ border: 1px solid #f59e0b;
+ color: #b45309;
+ padding: 6px 12px;
+ border-radius: 20px;
+ font-family: monospace;
+ font-size: 0.8rem;
+}
+.baas-layer {
+ width: 100%;
+ background: #e0e7ff;
+ padding: 0.5rem;
+ text-align: center;
+ border-radius: 6px;
+ font-size: 0.8rem;
+ color: #4338ca;
+ font-weight: bold;
+}
/* Ops Card */
-.ops-card { text-align: center; }
-.ops-icon { font-size: 4rem; margin-bottom: 1rem; }
-.ops-title { font-size: 1.2rem; font-weight: bold; margin-bottom: 0.5rem; color: var(--vp-c-text-1); }
-.ops-desc { font-size: 0.9rem; color: var(--vp-c-text-2); line-height: 1.5; }
+.ops-card {
+ text-align: center;
+}
+.ops-icon {
+ font-size: 4rem;
+ margin-bottom: 1rem;
+}
+.ops-title {
+ font-size: 1.2rem;
+ font-weight: bold;
+ margin-bottom: 0.5rem;
+ color: var(--vp-c-text-1);
+}
+.ops-desc {
+ font-size: 0.9rem;
+ color: var(--vp-c-text-2);
+ line-height: 1.5;
+}
/* Transitions */
-.fade-slide-enter-active, .fade-slide-leave-active { transition: all 0.4s ease; }
-.fade-slide-enter-from { opacity: 0; transform: translateY(20px); }
-.fade-slide-leave-to { opacity: 0; transform: translateY(-20px); }
-
\ No newline at end of file
+.fade-slide-enter-active,
+.fade-slide-leave-active {
+ transition: all 0.4s ease;
+}
+.fade-slide-enter-from {
+ opacity: 0;
+ transform: translateY(20px);
+}
+.fade-slide-leave-to {
+ opacity: 0;
+ transform: translateY(-20px);
+}
+
diff --git a/docs/.vitepress/theme/components/appendix/backend-evolution/CacheHitRatioDemo.vue b/docs/.vitepress/theme/components/appendix/backend-evolution/CacheHitRatioDemo.vue
new file mode 100644
index 0000000..bd4cef2
--- /dev/null
+++ b/docs/.vitepress/theme/components/appendix/backend-evolution/CacheHitRatioDemo.vue
@@ -0,0 +1,177 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
平均延迟
+
{{ avgLatency }} ms
+
+
+
+
数据库请求比例
+
{{ dbRate }}%
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/.vitepress/theme/components/appendix/backend-evolution/CgiQueueDemo.vue b/docs/.vitepress/theme/components/appendix/backend-evolution/CgiQueueDemo.vue
new file mode 100644
index 0000000..ca3db91
--- /dev/null
+++ b/docs/.vitepress/theme/components/appendix/backend-evolution/CgiQueueDemo.vue
@@ -0,0 +1,232 @@
+
+
+
+
+
+
+
+
+
+
+
平均响应时间
+
{{ avgResponse }} ms
+
+
+
+
排队请求数
+
{{ queueLength }}
+
+
+
+
+
+
+ {{ statusText }}
+
+
+
+
+
+
+
+
diff --git a/docs/.vitepress/theme/components/appendix/backend-evolution/MicroserviceLatencyDemo.vue b/docs/.vitepress/theme/components/appendix/backend-evolution/MicroserviceLatencyDemo.vue
new file mode 100644
index 0000000..4f17e1f
--- /dev/null
+++ b/docs/.vitepress/theme/components/appendix/backend-evolution/MicroserviceLatencyDemo.vue
@@ -0,0 +1,264 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
单体架构
+
+
+
User
+
Order
+
Payment
+
+
+
+
{{ monolithLatency }} ms
+
内存调用(~0ms)
+
+
+
+
+
微服务架构
+
+
+
User Svc
+
+ ⇄ {{ networkLatency }}ms
+
+
Order Svc
+
+ ⇄ {{ networkLatency }}ms
+
+
Payment Svc
+
+
+
+
{{ microLatency }} ms
+
网络调用累积
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/.vitepress/theme/components/appendix/backend-evolution/MonolithReleaseRiskDemo.vue b/docs/.vitepress/theme/components/appendix/backend-evolution/MonolithReleaseRiskDemo.vue
new file mode 100644
index 0000000..cb8f4a2
--- /dev/null
+++ b/docs/.vitepress/theme/components/appendix/backend-evolution/MonolithReleaseRiskDemo.vue
@@ -0,0 +1,263 @@
+
+
+
+
+
+
+
+
本次改动涉及
+
+
+
+
+
+
+
+
+
+
+
+
+
故障概率
+
{{ riskPercent }}%
+
+
+
+
+
+ {{ deployStatus }}
+
+
+
+
最近 3 次发布
+
+ -
+ {{ item }}
+
+ - 暂无记录
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/.vitepress/theme/components/appendix/backend-evolution/MonolithVsMicroserviceDemo.vue b/docs/.vitepress/theme/components/appendix/backend-evolution/MonolithVsMicroserviceDemo.vue
index d3bf54f..d8cd060 100644
--- a/docs/.vitepress/theme/components/appendix/backend-evolution/MonolithVsMicroserviceDemo.vue
+++ b/docs/.vitepress/theme/components/appendix/backend-evolution/MonolithVsMicroserviceDemo.vue
@@ -1,7 +1,9 @@
-
+
@@ -12,15 +14,19 @@
User
-
Order
+
+ Order
+
Payment
- Status: {{ monolithCrashed ? 'SYSTEM DOWN (Critical Failure)' : 'Healthy' }}
+ Status:
+ {{ monolithCrashed ? 'SYSTEM DOWN (Critical Failure)' : 'Healthy' }}
- One process. If "Order" module has a memory leak or fatal error, the entire server crashes. Everyone is affected.
+ One process. If "Order" module has a memory leak or fatal error,
+ the entire server crashes. Everyone is affected.
@@ -45,7 +51,8 @@
Status: {{ microCrashed ? 'Partial Outage (Order Down)' : 'Healthy' }}
- Isolated processes. If "Order" crashes, User and Payment services keep running. The system degrades gracefully.
+ Isolated processes. If "Order" crashes, User and Payment services
+ keep running. The system degrades gracefully.
@@ -98,7 +105,9 @@ const reset = () => {
background: #ef4444;
color: white;
}
-.crash-btn:hover { background: #dc2626; }
+.crash-btn:hover {
+ background: #dc2626;
+}
.reset-btn {
background: var(--vp-c-brand);
@@ -112,7 +121,9 @@ const reset = () => {
}
@media (max-width: 640px) {
- .comparison-view { grid-template-columns: 1fr; }
+ .comparison-view {
+ grid-template-columns: 1fr;
+ }
}
.architecture-block {
@@ -185,7 +196,7 @@ const reset = () => {
display: flex;
justify-content: space-between;
align-items: center;
- box-shadow: 0 2px 4px rgba(0,0,0,0.05);
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.service-box.crashed {
@@ -198,8 +209,14 @@ const reset = () => {
height: 10px;
border-radius: 50%;
}
-.dot.green { background: #22c55e; box-shadow: 0 0 4px #22c55e; }
-.dot.red { background: #ef4444; box-shadow: 0 0 4px #ef4444; }
+.dot.green {
+ background: #22c55e;
+ box-shadow: 0 0 4px #22c55e;
+}
+.dot.red {
+ background: #ef4444;
+ box-shadow: 0 0 4px #ef4444;
+}
.status-indicator {
margin-top: 1rem;
@@ -217,16 +234,38 @@ const reset = () => {
}
@keyframes shake {
- 0% { transform: translate(1px, 1px) rotate(0deg); }
- 10% { transform: translate(-1px, -2px) rotate(-1deg); }
- 20% { transform: translate(-3px, 0px) rotate(1deg); }
- 30% { transform: translate(3px, 2px) rotate(0deg); }
- 40% { transform: translate(1px, -1px) rotate(1deg); }
- 50% { transform: translate(-1px, 2px) rotate(-1deg); }
- 60% { transform: translate(-3px, 1px) rotate(0deg); }
- 70% { transform: translate(3px, 1px) rotate(-1deg); }
- 80% { transform: translate(-1px, -1px) rotate(1deg); }
- 90% { transform: translate(1px, 2px) rotate(0deg); }
- 100% { transform: translate(1px, -2px) rotate(-1deg); }
+ 0% {
+ transform: translate(1px, 1px) rotate(0deg);
+ }
+ 10% {
+ transform: translate(-1px, -2px) rotate(-1deg);
+ }
+ 20% {
+ transform: translate(-3px, 0px) rotate(1deg);
+ }
+ 30% {
+ transform: translate(3px, 2px) rotate(0deg);
+ }
+ 40% {
+ transform: translate(1px, -1px) rotate(1deg);
+ }
+ 50% {
+ transform: translate(-1px, 2px) rotate(-1deg);
+ }
+ 60% {
+ transform: translate(-3px, 1px) rotate(0deg);
+ }
+ 70% {
+ transform: translate(3px, 1px) rotate(-1deg);
+ }
+ 80% {
+ transform: translate(-1px, -1px) rotate(1deg);
+ }
+ 90% {
+ transform: translate(1px, 2px) rotate(0deg);
+ }
+ 100% {
+ transform: translate(1px, -2px) rotate(-1deg);
+ }
}
-
\ No newline at end of file
+
diff --git a/docs/.vitepress/theme/components/appendix/backend-evolution/ServerlessCostAutoScaleDemo.vue b/docs/.vitepress/theme/components/appendix/backend-evolution/ServerlessCostAutoScaleDemo.vue
new file mode 100644
index 0000000..5e700ad
--- /dev/null
+++ b/docs/.vitepress/theme/components/appendix/backend-evolution/ServerlessCostAutoScaleDemo.vue
@@ -0,0 +1,193 @@
+
+
+
+
+
+
+
+
+
+
Serverless 估算
+
${{ serverlessCost }}
+
按量计费(示意)
+
+
+
固定服务器
+
${{ serverCost }}
+
需预留 {{ requiredServers }} 台服务器
+
+
+
+
+
扩缩容状态
+
+
+ {{ scaleHint }}
+
+
+
+
+
+
+
+
diff --git a/docs/.vitepress/theme/components/appendix/backend-languages/BackendLanguagesDemo.vue b/docs/.vitepress/theme/components/appendix/backend-languages/BackendLanguagesDemo.vue
new file mode 100644
index 0000000..ca1db0c
--- /dev/null
+++ b/docs/.vitepress/theme/components/appendix/backend-languages/BackendLanguagesDemo.vue
@@ -0,0 +1,688 @@
+
+
+
+
+
+
+
+ {{ tag.label }}
+
+
+
{{ lang.description }}
+
+
+
+
+
+
+
{{ getLangDetail(selectedLang).title }}
+
+
+
+
+
+
+
+
+
diff --git a/docs/.vitepress/theme/components/appendix/backend-languages/ConcurrencyModelDemo.vue b/docs/.vitepress/theme/components/appendix/backend-languages/ConcurrencyModelDemo.vue
new file mode 100644
index 0000000..d059292
--- /dev/null
+++ b/docs/.vitepress/theme/components/appendix/backend-languages/ConcurrencyModelDemo.vue
@@ -0,0 +1,769 @@
+
+
+
+
+
+
+
{{ model.icon }}
+
{{ model.name }}
+
{{ model.tag }}
+
{{ model.description }}
+
+
+
+
+
+
+
+
+
代码示例
+
{{ getModelDetail(selectedModel).code }}
+
+
+
+
并发可视化
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/.vitepress/theme/components/appendix/backend-languages/DeveloperEfficiencyDemo.vue b/docs/.vitepress/theme/components/appendix/backend-languages/DeveloperEfficiencyDemo.vue
new file mode 100644
index 0000000..d908979
--- /dev/null
+++ b/docs/.vitepress/theme/components/appendix/backend-languages/DeveloperEfficiencyDemo.vue
@@ -0,0 +1,523 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 💡 分析:
+ {{ getTaskDetail(selectedTask).linesInsight }}
+
+
+
+
+
+
+
+
+
+ 💡 分析:
+ {{ getTaskDetail(selectedTask).timeInsight }}
+
+
+
+
+
+
+
+
+
{{ lang.name }}
+
+
+ {{ lang.debug }}h
+
+
+
+
+
+
+ 💡 分析:
+ {{ getTaskDetail(selectedTask).debugInsight }}
+
+
+
+
+
+
+
综合效率雷达图
+
+
+
+
+ 左上:代码少,开发快
+
+
+
+ 右上:调试快,类型安全
+
+
+
+ 左下:生态好,库丰富
+
+
+
+ 右下:学习简单,上手快
+
+
+
+
+
+
+
+
+
diff --git a/docs/.vitepress/theme/components/appendix/backend-languages/LanguageComparisonDemo.vue b/docs/.vitepress/theme/components/appendix/backend-languages/LanguageComparisonDemo.vue
new file mode 100644
index 0000000..077d1c9
--- /dev/null
+++ b/docs/.vitepress/theme/components/appendix/backend-languages/LanguageComparisonDemo.vue
@@ -0,0 +1,290 @@
+
+
+
+
+
+
+ | 维度 |
+
+ {{ lang.name }}
+ |
+
+
+
+
+ | {{ dimension.label }} |
+
+
+
+ {{
+ getScore(lang.name, dimension.key)
+ }}
+
+
+ |
+
+
+
+
+
+
+
💡 洞察分析
+
+
+ 性能王者:
+ C++ 和 Rust 在性能方面遥遥领先,但学习曲线极其陡峭。
+
+
+ 开发效率:
+ Python 和 Ruby 在快速开发方面无与伦比,适合原型和初创公司。
+
+
+ 生态成熟度:
+ Java、Python、Node.js 拥有最成熟的生态系统,库和框架丰富。
+
+
+ 学习曲线:
+ Python、Ruby、Go 最容易上手,Rust 和 C++ 需要较长时间学习。
+
+
+
+
+
+
+
+
+
diff --git a/docs/.vitepress/theme/components/appendix/backend-languages/LanguageEcosystemDemo.vue b/docs/.vitepress/theme/components/appendix/backend-languages/LanguageEcosystemDemo.vue
new file mode 100644
index 0000000..5cd5e54
--- /dev/null
+++ b/docs/.vitepress/theme/components/appendix/backend-languages/LanguageEcosystemDemo.vue
@@ -0,0 +1,980 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 包数量
+ {{ formatNumber(pkg.count) }}
+
+
+ 周下载量
+ {{ formatDownloads(pkg.downloads) }}
+
+
+
+ {{ pkg.command }}
+
+
+
+
+
+
+
+
+
+
+
+
+ | 框架 |
+ 语言 |
+ 性能 |
+ 学习曲线 |
+ 特点 |
+ 适用场景 |
+
+
+
+
+ |
+ {{ fw.icon }}
+ {{ fw.name }}
+ |
+ {{ fw.language }} |
+
+
+ |
+
+
+ |
+
+
+
+ {{ tag.label }}
+
+
+ |
+ {{ fw.useCase }} |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
在线课程
+
+
+ {{ course }}
+
+
+
+
+
学习曲线
+
+
{{ resource.curveLabel }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/.vitepress/theme/components/appendix/backend-languages/LanguageSelectorDemo.vue b/docs/.vitepress/theme/components/appendix/backend-languages/LanguageSelectorDemo.vue
new file mode 100644
index 0000000..fc5896a
--- /dev/null
+++ b/docs/.vitepress/theme/components/appendix/backend-languages/LanguageSelectorDemo.vue
@@ -0,0 +1,575 @@
+
+
+
+
+
+
+
+
1
+
项目类型
+
+
+
+
+
+
+
+
2
+
性能要求
+
+
+
+
+
+
+
+
3
+
团队背景
+
+
+
+
+
+
+
+
4
+
上市时间
+
+
+
+
+
+
+
+
+
+
🎉 推荐语言
+
+
+ {{ recommendation.icon }}
+ {{ recommendation.language }}
+
+
+
选择理由
+
{{ recommendation.reason }}
+
+
+
备选方案
+
+
+ {{ alt }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/.vitepress/theme/components/appendix/backend-languages/PerformanceBenchmarkDemo.vue b/docs/.vitepress/theme/components/appendix/backend-languages/PerformanceBenchmarkDemo.vue
new file mode 100644
index 0000000..da3c16b
--- /dev/null
+++ b/docs/.vitepress/theme/components/appendix/backend-languages/PerformanceBenchmarkDemo.vue
@@ -0,0 +1,386 @@
+
+
+
+
+
+
+
diff --git a/docs/.vitepress/theme/components/appendix/backend-languages/SyntaxComparisonDemo.vue b/docs/.vitepress/theme/components/appendix/backend-languages/SyntaxComparisonDemo.vue
new file mode 100644
index 0000000..a0cb80c
--- /dev/null
+++ b/docs/.vitepress/theme/components/appendix/backend-languages/SyntaxComparisonDemo.vue
@@ -0,0 +1,471 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ getCode(selectedLang) }}
+
+
+
+ 代码行数:
+ {{ getLineCount(selectedLang) }} 行
+
+
+ 字符数:
+ {{ getCharCount(selectedLang) }} 字符
+
+
+ 复杂度:
+ {{ getComplexity(selectedLang) }}
+
+
+
+
+
+
+
💡 语法分析
+
+
{{ getAnalysis(selectedLang) }}
+
+
+
+
+
代码复杂度对比
+
+
+
{{ lang.name }}
+
+
{{ getLineCount(lang.name) }} 行
+
+
+
+
+
+
+
+
+
diff --git a/docs/.vitepress/theme/components/appendix/browser-devtools/BrowserDevToolsDemo.vue b/docs/.vitepress/theme/components/appendix/browser-devtools/BrowserDevToolsDemo.vue
index ffacaae..f10f55c 100644
--- a/docs/.vitepress/theme/components/appendix/browser-devtools/BrowserDevToolsDemo.vue
+++ b/docs/.vitepress/theme/components/appendix/browser-devtools/BrowserDevToolsDemo.vue
@@ -25,13 +25,33 @@ const tourOptions = [
const selectedTour = ref('')
const tabs = [
- { id: 'elements', label: '元素', desc: '查看和修改页面 HTML 结构与 CSS 样式' },
- { id: 'console', label: '控制台', desc: '查看日志、错误信息,执行 JavaScript 代码' },
- { id: 'sources', label: '源代码/来源', desc: '查看源代码,设置断点调试 JavaScript' },
- { id: 'network', label: '网络', desc: '监控网络请求,查看接口数据和加载性能' },
+ {
+ id: 'elements',
+ label: '元素',
+ desc: '查看和修改页面 HTML 结构与 CSS 样式'
+ },
+ {
+ id: 'console',
+ label: '控制台',
+ desc: '查看日志、错误信息,执行 JavaScript 代码'
+ },
+ {
+ id: 'sources',
+ label: '源代码/来源',
+ desc: '查看源代码,设置断点调试 JavaScript'
+ },
+ {
+ id: 'network',
+ label: '网络',
+ desc: '监控网络请求,查看接口数据和加载性能'
+ },
{ id: 'performance', label: '性能', desc: '分析页面运行性能' },
{ id: 'memory', label: '内存', desc: '检测内存泄漏' },
- { id: 'application', label: '应用', desc: '查看本地存储(Storage)、Cookies、缓存等' },
+ {
+ id: 'application',
+ label: '应用',
+ desc: '查看本地存储(Storage)、Cookies、缓存等'
+ },
{ id: 'security', label: '隐私与安全', desc: '查看证书和安全问题' },
{ id: 'lighthouse', label: 'Lighthouse', desc: '页面质量审计' },
{ id: 'recorder', label: '记录器', desc: '录制用户操作' }
@@ -49,62 +69,112 @@ const consoleSidebarItems = [
const consoleLogs = ref([
{ type: 'log', msg: '[vite] connecting...', source: 'client:733' },
{ type: 'log', msg: '[vite] connected.', source: 'client:827' },
- { type: 'log', msg: 'Config Layers for 404.md:\n========================\n1. locale config (root)\n2. .vitepress/config (root)', source: 'shared.js:194' },
- { type: 'log', msg: 'Config Layers for zh-cn/appendix/browser-devtools/index.md:\n=======================================================\n1. locale config (zh-cn)\n2. .vitepress/config (root)', source: 'shared.js:194' },
- { type: 'log', msg: '[vite] hot updated: .vitepress/theme/components/appendix/browser-devtools/BrowserDevToolsDemo.vue', source: 'client:810' },
- { type: 'log', msg: '[vite] hot updated: .vitepress/theme/components/appendix/browser-devtools/BrowserDevToolsDemo.vue?vue&type=style&index=0&scoped=d906459f&lang.css', source: 'client:810' }
+ {
+ type: 'log',
+ msg: 'Config Layers for 404.md:\n========================\n1. locale config (root)\n2. .vitepress/config (root)',
+ source: 'shared.js:194'
+ },
+ {
+ type: 'log',
+ msg: 'Config Layers for zh-cn/appendix/browser-devtools/index.md:\n=======================================================\n1. locale config (zh-cn)\n2. .vitepress/config (root)',
+ source: 'shared.js:194'
+ },
+ {
+ type: 'log',
+ msg: '[vite] hot updated: .vitepress/theme/components/appendix/browser-devtools/BrowserDevToolsDemo.vue',
+ source: 'client:810'
+ },
+ {
+ type: 'log',
+ msg: '[vite] hot updated: .vitepress/theme/components/appendix/browser-devtools/BrowserDevToolsDemo.vue?vue&type=style&index=0&scoped=d906459f&lang.css',
+ source: 'client:810'
+ }
])
const consoleInput = ref('')
// --- Elements Data (Aligned with screenshot) ---
const domTree = ref([
- {
- tag: 'html',
+ {
+ tag: 'html',
attrs: { class: 'mac', lang: 'zh-CN', dir: 'ltr' },
expanded: true,
children: [
- {
- tag: 'head',
+ {
+ tag: 'head',
expanded: false,
- children: [
- { tag: 'title', text: 'DevTools Demo' }
- ]
+ children: [{ tag: 'title', text: 'DevTools Demo' }]
},
- {
- tag: 'body',
+ {
+ tag: 'body',
expanded: true,
children: [
- {
- tag: 'div',
- attrs: { id: 'app', 'data-v-app': '' },
+ {
+ tag: 'div',
+ attrs: { id: 'app', 'data-v-app': '' },
expanded: true,
children: [
- { tag: 'div', text: '' },
- { tag: 'script', attrs: { type: 'module', src: '/easy-vibe/node_modules/vitepress/dist/client/app/index.js' } },
- { tag: 'div', attrs: { id: 'el-popper-container-3083' }, text: '' }
+ { tag: 'div', text: '' },
+ {
+ tag: 'script',
+ attrs: {
+ type: 'module',
+ src: '/easy-vibe/node_modules/vitepress/dist/client/app/index.js'
+ }
+ },
+ {
+ tag: 'div',
+ attrs: { id: 'el-popper-container-3083' },
+ text: ''
+ }
]
},
- { tag: 'div', attrs: { style: 'all: initial' }, expanded: false, children: [] },
- { tag: 'div', attrs: { id: 'immersive-translate-browser-popup', style: 'all: initial' }, expanded: false, children: [] }
+ {
+ tag: 'div',
+ attrs: { style: 'all: initial' },
+ expanded: false,
+ children: []
+ },
+ {
+ tag: 'div',
+ attrs: {
+ id: 'immersive-translate-browser-popup',
+ style: 'all: initial'
+ },
+ expanded: false,
+ children: []
+ }
]
}
]
}
])
const cssRules = ref([
- { selector: 'body', styles: { 'background-color': 'rgb(255, 255, 255)', 'color': '#24292f', 'margin': '0', 'font-family': '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto' } },
- { selector: '#app', styles: { 'padding': '20px' } },
+ {
+ selector: 'body',
+ styles: {
+ 'background-color': 'rgb(255, 255, 255)',
+ color: '#24292f',
+ margin: '0',
+ 'font-family': '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto'
+ }
+ },
+ { selector: '#app', styles: { padding: '20px' } },
{ selector: '.mac', styles: { 'font-synthesis': 'none' } }
])
// --- Sources Data ---
const fileSystem = ref([
{ name: 'index.html', type: 'file' },
- { name: 'src', type: 'folder', expanded: true, children: [
+ {
+ name: 'src',
+ type: 'folder',
+ expanded: true,
+ children: [
{ name: 'main.js', type: 'file' },
{ name: 'App.vue', type: 'file' },
{ name: 'utils.js', type: 'file' }
- ]}
+ ]
+ }
])
const activeFile = ref('main.js')
const fileContent = ref(`import { createApp } from 'vue'
@@ -117,34 +187,87 @@ app.mount('#app')`)
// --- Network Data ---
const networkRequests = ref([
- {
- id: 1, name: 'index.html', status: 200, type: 'document', size: '2.4kB', time: '120ms', waterfall: 10,
- headers: { 'Content-Type': 'text/html; charset=utf-8', 'Server': 'Vite' },
- requestHeaders: { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)', 'Accept': 'text/html' },
- preview: '\n\n...\n...\n'
+ {
+ id: 1,
+ name: 'index.html',
+ status: 200,
+ type: 'document',
+ size: '2.4kB',
+ time: '120ms',
+ waterfall: 10,
+ headers: { 'Content-Type': 'text/html; charset=utf-8', Server: 'Vite' },
+ requestHeaders: {
+ 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)',
+ Accept: 'text/html'
+ },
+ preview:
+ '\n\n...\n...\n'
},
- {
- id: 2, name: 'main.js', status: 200, type: 'script', size: '15.2kB', time: '80ms', waterfall: 40,
- headers: { 'Content-Type': 'application/javascript', 'Cache-Control': 'no-cache' },
- requestHeaders: { 'User-Agent': 'Mozilla/5.0 ...', 'Referer': 'http://localhost:3000/' },
- preview: 'import { createApp } from "vue";\nimport App from "./App.vue";\ncreateApp(App).mount("#app");'
+ {
+ id: 2,
+ name: 'main.js',
+ status: 200,
+ type: 'script',
+ size: '15.2kB',
+ time: '80ms',
+ waterfall: 40,
+ headers: {
+ 'Content-Type': 'application/javascript',
+ 'Cache-Control': 'no-cache'
+ },
+ requestHeaders: {
+ 'User-Agent': 'Mozilla/5.0 ...',
+ Referer: 'http://localhost:3000/'
+ },
+ preview:
+ 'import { createApp } from "vue";\nimport App from "./App.vue";\ncreateApp(App).mount("#app");'
},
- {
- id: 3, name: 'style.css', status: 200, type: 'stylesheet', size: '4.1kB', time: '45ms', waterfall: 50,
+ {
+ id: 3,
+ name: 'style.css',
+ status: 200,
+ type: 'stylesheet',
+ size: '4.1kB',
+ time: '45ms',
+ waterfall: 50,
headers: { 'Content-Type': 'text/css' },
- requestHeaders: { 'User-Agent': 'Mozilla/5.0 ...', 'Referer': 'http://localhost:3000/' },
- preview: 'body { margin: 0; font-family: sans-serif; }\n#app { padding: 20px; }'
+ requestHeaders: {
+ 'User-Agent': 'Mozilla/5.0 ...',
+ Referer: 'http://localhost:3000/'
+ },
+ preview:
+ 'body { margin: 0; font-family: sans-serif; }\n#app { padding: 20px; }'
},
- {
- id: 4, name: 'api/user', status: 200, type: 'fetch', size: '500B', time: '200ms', waterfall: 120,
+ {
+ id: 4,
+ name: 'api/user',
+ status: 200,
+ type: 'fetch',
+ size: '500B',
+ time: '200ms',
+ waterfall: 120,
headers: { 'Content-Type': 'application/json' },
- requestHeaders: { 'Authorization': 'Bearer eyJhbGci...', 'Accept': 'application/json', 'Content-Type': 'application/json' },
- preview: '{\n "id": 1001,\n "username": "developer",\n "role": "admin",\n "permissions": ["read", "write"]\n}'
+ requestHeaders: {
+ Authorization: 'Bearer eyJhbGci...',
+ Accept: 'application/json',
+ 'Content-Type': 'application/json'
+ },
+ preview:
+ '{\n "id": 1001,\n "username": "developer",\n "role": "admin",\n "permissions": ["read", "write"]\n}'
},
- {
- id: 5, name: 'logo.png', status: 304, type: 'png', size: '12kB', time: '20ms', waterfall: 60,
+ {
+ id: 5,
+ name: 'logo.png',
+ status: 304,
+ type: 'png',
+ size: '12kB',
+ time: '20ms',
+ waterfall: 60,
headers: { 'Content-Type': 'image/png' },
- requestHeaders: { 'User-Agent': 'Mozilla/5.0 ...', 'Accept': 'image/webp,image/apng' },
+ requestHeaders: {
+ 'User-Agent': 'Mozilla/5.0 ...',
+ Accept: 'image/webp,image/apng'
+ },
preview: '[Binary Data - Image]'
}
])
@@ -160,7 +283,6 @@ const selectRequest = (req) => {
}
}
-
// --- Application Data ---
const localStorageData = ref([
{ key: 'theme', value: 'light' },
@@ -186,8 +308,13 @@ const runConsoleCommand = () => {
try {
const val = consoleInput.value
if (val === '1+1') consoleLogs.value.push({ type: 'result', msg: '2' })
- else if (val.includes('alert')) consoleLogs.value.push({ type: 'result', msg: 'undefined' })
- else consoleLogs.value.push({ type: 'error', msg: 'ReferenceError: Command not found in mock' })
+ else if (val.includes('alert'))
+ consoleLogs.value.push({ type: 'result', msg: 'undefined' })
+ else
+ consoleLogs.value.push({
+ type: 'error',
+ msg: 'ReferenceError: Command not found in mock'
+ })
} catch (e) {
consoleLogs.value.push({ type: 'error', msg: e.message })
}
@@ -203,16 +330,16 @@ const runConsoleCommand = () => {
const handleTourSelect = async () => {
if (!selectedTour.value) return
const target = selectedTour.value
-
+
// 如果已经在播放,先停止
if (isAutoPlaying.value) {
stopTour()
- await new Promise(r => setTimeout(r, 100))
+ await new Promise((r) => setTimeout(r, 100))
}
-
+
// 切换到目标 Tab
activeTab.value = target
-
+
// 启动导览
startTour(target)
}
@@ -227,29 +354,29 @@ const moveCursorTo = (selector, infoText, waitTime = 2000) => {
if (el) {
const containerRect = container.getBoundingClientRect()
const rect = el.getBoundingClientRect()
-
+
// Calculate center
const targetX = rect.left - containerRect.left + rect.width / 2
const targetY = rect.top - containerRect.top + rect.height / 2
-
+
// Move cursor
cursorX.value = targetX
cursorY.value = targetY
cursorVisible.value = true
-
+
// Show highlight after a slight delay to simulate travel time
setTimeout(() => {
if (!isAutoPlaying.value) return resolve()
-
+
highlightStyle.value = {
- top: (rect.top - containerRect.top) + 'px',
- left: (rect.left - containerRect.left) + 'px',
+ top: rect.top - containerRect.top + 'px',
+ left: rect.left - containerRect.left + 'px',
width: rect.width + 'px',
height: rect.height + 'px'
}
highlightVisible.value = true
hoverInfo.value = infoText
-
+
// Wait and then clear
tourTimeout = setTimeout(() => {
highlightVisible.value = false
@@ -277,7 +404,7 @@ const startTour = async (targetTab) => {
isAutoPlaying.value = true
cursorVisible.value = true
hoverInfo.value = ''
-
+
try {
// Dispatch based on target tab
if (targetTab === 'console') await runConsoleTour()
@@ -285,7 +412,7 @@ const startTour = async (targetTab) => {
else if (targetTab === 'sources') await runSourcesTour()
else if (targetTab === 'network') await runNetworkTour()
else if (targetTab === 'application') await runApplicationTour()
-
+
stopTour()
} catch (e) {
console.error(e)
@@ -294,98 +421,173 @@ const startTour = async (targetTab) => {
}
const runConsoleTour = async () => {
- await moveCursorTo('.tab[data-id="console"]', '控制台 (Console):查看日志、交互式运行代码')
+ await moveCursorTo(
+ '.tab[data-id="console"]',
+ '控制台 (Console):查看日志、交互式运行代码'
+ )
if (!isAutoPlaying.value) return
- await moveCursorTo('.console-toolbar', '工具栏:可清空日志、设置 Log 级别、过滤内容')
+ await moveCursorTo(
+ '.console-toolbar',
+ '工具栏:可清空日志、设置 Log 级别、过滤内容'
+ )
if (!isAutoPlaying.value) return
- await moveCursorTo('.console-sidebar', '侧边栏:按类型聚合消息 (Errors, Warnings)')
+ await moveCursorTo(
+ '.console-sidebar',
+ '侧边栏:按类型聚合消息 (Errors, Warnings)'
+ )
if (!isAutoPlaying.value) return
- await moveCursorTo('.log-line:nth-child(1)', '日志流:显示代码输出,点击右侧链接可跳转源码')
+ await moveCursorTo(
+ '.log-line:nth-child(1)',
+ '日志流:显示代码输出,点击右侧链接可跳转源码'
+ )
if (!isAutoPlaying.value) return
- await moveCursorTo('.bottom-drawer-header', '抽屉 (Drawer):查看搜索结果、Issues 等辅助信息')
+ await moveCursorTo(
+ '.bottom-drawer-header',
+ '抽屉 (Drawer):查看搜索结果、Issues 等辅助信息'
+ )
if (!isAutoPlaying.value) return
- await moveCursorTo('.console-input-area', '即时执行:在这里输入 JS 表达式并回车运行')
+ await moveCursorTo(
+ '.console-input-area',
+ '即时执行:在这里输入 JS 表达式并回车运行'
+ )
}
const runElementsTour = async () => {
- await moveCursorTo('.tab[data-id="elements"]', '元素面板 (Elements):实时查看和修改 DOM/CSS')
+ await moveCursorTo(
+ '.tab[data-id="elements"]',
+ '元素面板 (Elements):实时查看和修改 DOM/CSS'
+ )
if (!isAutoPlaying.value) return
- await moveCursorTo('.dom-tree-panel', 'DOM 树:页面的 HTML 结构,可折叠/展开/拖拽')
+ await moveCursorTo(
+ '.dom-tree-panel',
+ 'DOM 树:页面的 HTML 结构,可折叠/展开/拖拽'
+ )
if (!isAutoPlaying.value) return
- await moveCursorTo('.dom-node[data-tag="div"]', '选中元素:点击元素以在右侧查看其样式')
+ await moveCursorTo(
+ '.dom-node[data-tag="div"]',
+ '选中元素:点击元素以在右侧查看其样式'
+ )
if (!isAutoPlaying.value) return
- await moveCursorTo('.styles-panel', '样式面板 (Styles):查看计算后的样式和 CSS 规则')
+ await moveCursorTo(
+ '.styles-panel',
+ '样式面板 (Styles):查看计算后的样式和 CSS 规则'
+ )
if (!isAutoPlaying.value) return
- await moveCursorTo('.style-rule:first-child', 'CSS 规则:可直接修改属性值,实时预览效果')
+ await moveCursorTo(
+ '.style-rule:first-child',
+ 'CSS 规则:可直接修改属性值,实时预览效果'
+ )
}
const runSourcesTour = async () => {
- await moveCursorTo('.tab[data-id="sources"]', '源代码 (Sources):文件浏览与断点调试')
+ await moveCursorTo(
+ '.tab[data-id="sources"]',
+ '源代码 (Sources):文件浏览与断点调试'
+ )
if (!isAutoPlaying.value) return
await moveCursorTo('.file-navigator', '文件系统:查看加载的所有资源文件')
if (!isAutoPlaying.value) return
await moveCursorTo('.code-editor', '编辑器:查看源码,点击行号设置断点')
if (!isAutoPlaying.value) return
- await moveCursorTo('.debugger-sidebar', '调试器:查看变量 (Watch)、调用栈 (Call Stack)')
+ await moveCursorTo(
+ '.debugger-sidebar',
+ '调试器:查看变量 (Watch)、调用栈 (Call Stack)'
+ )
}
const runNetworkTour = async () => {
await moveCursorTo('.tab[data-id="network"]', '网络 (Network):抓包分析')
if (!isAutoPlaying.value) return
- await moveCursorTo('.network-toolbar', '过滤器:按类型筛选请求 (XHR/Fetch, CSS, JS)')
+ await moveCursorTo(
+ '.network-toolbar',
+ '过滤器:按类型筛选请求 (XHR/Fetch, CSS, JS)'
+ )
if (!isAutoPlaying.value) return
- await moveCursorTo('.network-grid-header', '请求列表:查看状态码、类型、大小、耗时')
+ await moveCursorTo(
+ '.network-grid-header',
+ '请求列表:查看状态码、类型、大小、耗时'
+ )
if (!isAutoPlaying.value) return
-
+
// Simulate clicking the API request
await moveCursorTo('.network-row:nth-child(4)', '点击请求行查看详情')
if (!isAutoPlaying.value) return
-
+
// Trigger selection
selectedRequest.value = networkRequests.value[3] // api/user
-
- await moveCursorTo('.detail-header', '详情面板:查看 Headers, Preview, Response')
- if (!isAutoPlaying.value) return
-
- // 1. Headers Tab
- activeDetailTab.value = 'headers'
- await moveCursorTo('.detail-title:nth-child(1)', 'Headers: 查看请求/响应头信息')
- if (!isAutoPlaying.value) return
- await moveCursorTo('.detail-section:nth-child(1)', 'General:查看 URL、Method (GET/POST) 和状态码 (200)')
- if (!isAutoPlaying.value) return
+ await moveCursorTo(
+ '.detail-header',
+ '详情面板:查看 Headers, Preview, Response'
+ )
+ if (!isAutoPlaying.value) return
- await moveCursorTo('.detail-section:nth-child(2)', 'Response Headers:服务器返回的头信息 (Content-Type)')
- if (!isAutoPlaying.value) return
+ // 1. Headers Tab
+ activeDetailTab.value = 'headers'
+ await moveCursorTo(
+ '.detail-title:nth-child(1)',
+ 'Headers: 查看请求/响应头信息'
+ )
+ if (!isAutoPlaying.value) return
- await moveCursorTo('.detail-section:nth-child(3)', 'Request Headers:浏览器发送的头信息 (User-Agent, Cookies)')
- if (!isAutoPlaying.value) return
-
- // 2. Preview Tab
- await moveCursorTo('.detail-title:nth-child(2)', 'Preview: 格式化预览接口返回的数据')
- if (!isAutoPlaying.value) return
- activeDetailTab.value = 'preview'
-
- await moveCursorTo('.preview-content', 'Preview Content: 查看 JSON 结构')
- if (!isAutoPlaying.value) return
+ await moveCursorTo(
+ '.detail-section:nth-child(1)',
+ 'General:查看 URL、Method (GET/POST) 和状态码 (200)'
+ )
+ if (!isAutoPlaying.value) return
- // 3. Response Tab
- await moveCursorTo('.detail-title:nth-child(3)', 'Response: 查看原始响应数据')
- if (!isAutoPlaying.value) return
- activeDetailTab.value = 'response'
+ await moveCursorTo(
+ '.detail-section:nth-child(2)',
+ 'Response Headers:服务器返回的头信息 (Content-Type)'
+ )
+ if (!isAutoPlaying.value) return
- await moveCursorTo('.preview-content', 'Response Body: 原始文本内容')
- if (!isAutoPlaying.value) return
+ await moveCursorTo(
+ '.detail-section:nth-child(3)',
+ 'Request Headers:浏览器发送的头信息 (User-Agent, Cookies)'
+ )
+ if (!isAutoPlaying.value) return
- await moveCursorTo('.waterfall-cell', '瀑布流 (Waterfall):请求生命周期耗时分析')
+ // 2. Preview Tab
+ await moveCursorTo(
+ '.detail-title:nth-child(2)',
+ 'Preview: 格式化预览接口返回的数据'
+ )
+ if (!isAutoPlaying.value) return
+ activeDetailTab.value = 'preview'
+
+ await moveCursorTo('.preview-content', 'Preview Content: 查看 JSON 结构')
+ if (!isAutoPlaying.value) return
+
+ // 3. Response Tab
+ await moveCursorTo('.detail-title:nth-child(3)', 'Response: 查看原始响应数据')
+ if (!isAutoPlaying.value) return
+ activeDetailTab.value = 'response'
+
+ await moveCursorTo('.preview-content', 'Response Body: 原始文本内容')
+ if (!isAutoPlaying.value) return
+
+ await moveCursorTo(
+ '.waterfall-cell',
+ '瀑布流 (Waterfall):请求生命周期耗时分析'
+ )
}
const runApplicationTour = async () => {
- await moveCursorTo('.tab[data-id="application"]', '应用 (Application):存储与缓存管理')
+ await moveCursorTo(
+ '.tab[data-id="application"]',
+ '应用 (Application):存储与缓存管理'
+ )
if (!isAutoPlaying.value) return
- await moveCursorTo('.storage-sidebar', '存储类型:Local Storage, Cookies, IndexedDB')
+ await moveCursorTo(
+ '.storage-sidebar',
+ '存储类型:Local Storage, Cookies, IndexedDB'
+ )
if (!isAutoPlaying.value) return
- await moveCursorTo('.storage-content', '数据视图:查看 Key-Value 数据,支持增删改查')
+ await moveCursorTo(
+ '.storage-content',
+ '数据视图:查看 Key-Value 数据,支持增删改查'
+ )
}
onUnmounted(() => {
@@ -394,42 +596,97 @@ onUnmounted(() => {
-