Merge branch 'dev'
This commit is contained in:
@@ -4,9 +4,15 @@ tools/*
|
||||
docs/.vitepress/dist
|
||||
docs/.vitepress/cache
|
||||
temp/*
|
||||
docs/zh-cn/appendix-old-backup*/
|
||||
docs/zh-cn/appendix-dirs-backup*/
|
||||
CLAUDE.md
|
||||
MULTI_LANGUAGE_PLAN.md
|
||||
.trae
|
||||
scripts/collapse_code_blocks.py
|
||||
.gitignore
|
||||
scripts/verify.sh
|
||||
REFACTORING_PLAN.md
|
||||
.gitignore
|
||||
.gitignore
|
||||
REFACTORING_REPORT.md
|
||||
|
||||
@@ -209,7 +209,7 @@ Easy-Vibe 通过以下几个阶段,带你从 0 到 1:
|
||||
|
||||
| 章节 | 关键内容 | 状态 |
|
||||
| :------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------- | :--- |
|
||||
| [高级一:MCP 与 ClaudeCode Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claudecode-skills/) | 通过 MCP 与 Skills 扩展 IDE 能力,把外部服务接成工具 | 🚧 |
|
||||
| [高级一:MCP 与 Claude Code Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claude-code-skills/) | 通过 MCP 与 Skills 扩展 IDE 能力,把外部服务接成工具 | 🚧 |
|
||||
| [高级二:如何让 Coding Tools 长时间工作](docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) | 设计和配置长时间运行的任务,让 Coding Tools 更稳定可靠 | 🚧 |
|
||||
| [高级三:多平台开发:如何构建微信小程序](docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) | 了解微信小程序生态,从官方模板到上线完成一个前端小程序 | ✅ |
|
||||
| [高级四:多平台开发:如何构建微信小程序-包含后端](docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) | 在小程序中接入数据库与后端逻辑,打通完整业务闭环 | 🚧 |
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
|
||||
| الفصل | المحتوى الرئيسي | الحالة |
|
||||
| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------- | :----- |
|
||||
| [المتقدم 1: MCP ومهارات ClaudeCode](docs/stage-3/core-skills/3.1-mcp-claudecode-skills/) : توسيع قدرات IDE من خلال MCP والمهارات، توصيل الخدمات الخارجية كأدوات | 🚧 |
|
||||
| [المتقدم 1: MCP ومهارات ClaudeCode](docs/stage-3/core-skills/3.1-mcp-claude-code-skills/) : توسيع قدرات IDE من خلال MCP والمهارات، توصيل الخدمات الخارجية كأدوات | 🚧 |
|
||||
| [المتقدم 2: كيفية جعل Coding Tools تعمل لفترة طويلة](docs/stage-3/core-skills/3.2-long-running-tasks/) : تصميم وتكوين المهام طويلة التشغيل، جعل Coding Tools أكثر استقرارًا وموثوقية | 🚧 |
|
||||
| [المتقدم 3: التطوير متعدد المنصات: كيفية بناء برامج WeChat المصغرة](docs/stage-3/cross-platform/3.3-wechat-miniprogram/) : فهم نظام البرامج المصغرة WeChat، إكمال برنامج مصغر للواجهة الأمامية من القالب الرسمي إلى الإطلاق | ✅ |
|
||||
| [المتقدم 4: التطوير متعدد المنصات: كيفية بناء برامج WeChat المصغرة - بما في ذلك الخلفية](docs/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) : دمج قاعدة البيانات ومنطق الواجهة الخلفية في البرامج المصغرة، تحقيق دورة نشاط كاملة | 🚧 |
|
||||
|
||||
@@ -140,7 +140,7 @@ Wir glauben, dass durch die Beherrschung von Vibe Coding in Kombination mit syst
|
||||
|
||||
| Kapitel | Schlüsselinhalt | Status |
|
||||
| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------- | :----- |
|
||||
| [Fortgeschritten 1: MCP und ClaudeCode Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claudecode-skills/) : IDE-Fähigkeiten durch MCP und Skills erweitern, externe Dienste als Tools anschließen | 🚧 |
|
||||
| [Fortgeschritten 1: MCP und Claude Code Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claude-code-skills/) : IDE-Fähigkeiten durch MCP und Skills erweitern, externe Dienste als Tools anschließen | 🚧 |
|
||||
| [Fortgeschritten 2: Coding Tools lange laufen lassen](docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) : Lang laufende Aufgaben entwerfen und konfigurieren, Coding Tools stabiler und zuverlässiger machen | 🚧 |
|
||||
| [Fortgeschritten 3: Plattformübergreifende Entwicklung: WeChat-Miniprogramme erstellen](docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) : WeChat-Miniprogramm-Ökosystem verstehen, Frontend-Miniprogramm von offizieller Vorlage bis zum Start completed | ✅ |
|
||||
| [Fortgeschritten 4: Plattformübergreifende Entwicklung: WeChat-Miniprogramme erstellen - Mit Backend](docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) : Datenbank und Backend-Logik in Miniprogramme integrieren, vollständigen Geschäftskreislauf realisieren | 🚧 |
|
||||
|
||||
@@ -143,7 +143,7 @@ We believe that by mastering Vibe Coding combined with systematic training, one
|
||||
|
||||
| Chapter | Key Content | Status |
|
||||
| :-------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------- | :----- |
|
||||
| [Advanced 1: MCP and ClaudeCode Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claudecode-skills/) | Extend IDE capabilities through MCP and Skills, integrate external services as tools | 🚧 |
|
||||
| [Advanced 1: MCP and Claude Code Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claude-code-skills/) | Extend IDE capabilities through MCP and Skills, integrate external services as tools | 🚧 |
|
||||
| [Advanced 2: Making Coding Tools Work for Long Periods](docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) | Design and configure long-running tasks, make Coding Tools more stable and reliable | 🚧 |
|
||||
| [Advanced 3: Multi-Platform Development: Building WeChat Mini Programs](docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) | Understand WeChat mini program ecosystem, complete a frontend mini program from official template to launch | ✅ |
|
||||
| [Advanced 4: Multi-Platform Development: Building WeChat Mini Programs - With Backend](docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) | Integrate databases and backend logic in mini programs, complete business loops | 🚧 |
|
||||
|
||||
@@ -140,7 +140,7 @@ Creemos que al dominar Vibe Coding y combinarlo con entrenamiento sistemático,
|
||||
|
||||
| Capítulo | Contenido clave | Estado |
|
||||
| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------- | :----- |
|
||||
| [Avanzado 1: MCP y ClaudeCode Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claudecode-skills/) | Extender capacidades del IDE a través de MCP y Skills, conectar servicios externos como herramientas | 🚧 |
|
||||
| [Avanzado 1: MCP y Claude Code Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claude-code-skills/) | Extender capacidades del IDE a través de MCP y Skills, conectar servicios externos como herramientas | 🚧 |
|
||||
| [Avanzado 2: Cómo hacer que Coding Tools funcione durante mucho tiempo](docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) | Diseñar y configurar tareas de ejecución prolongada, hacer Coding Tools más estable y confiable | 🚧 |
|
||||
| [Avanzado 3: Desarrollo multiplataforma: Cómo construir mini programas de WeChat](docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) | Entender el ecosistema de mini programas de WeChat, completar un mini programa frontend desde plantilla oficial hasta lanzamiento | ✅ |
|
||||
| [Avanzado 4: Desarrollo multiplataforma: Cómo construir mini programas de WeChat - Incluyendo backend](docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) | Integrar base de datos y lógica backend en mini programas,实现 ciclo completo de negocio | 🚧 |
|
||||
|
||||
@@ -140,7 +140,7 @@ Nous croyons qu'en maîtrisant Vibe Coding et en le combinant avec un entraînem
|
||||
|
||||
| Chapitre | Contenu clé | Statut |
|
||||
| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :---------- | :----- |
|
||||
| [Avancé 1 : MCP et ClaudeCode Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claudecode-skills/) : Étendre les capacités de l'IDE via MCP et Skills, connecter des services externes comme outils | 🚧 |
|
||||
| [Avancé 1 : MCP et Claude Code Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claude-code-skills/) : Étendre les capacités de l'IDE via MCP et Skills, connecter des services externes comme outils | 🚧 |
|
||||
| [Avancé 2 : Comment faire fonctionner Coding Tools longtemps](docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) : Concevoir et configurer des tâches à longue exécution, rendre Coding Tools plus stable et fiable | 🚧 |
|
||||
| [Avancé 3 : Développement multiplateforme : Comment construire des mini-programmes WeChat](docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) : Comprendre l'écosystème des mini-programmes WeChat, compléter un mini-programme frontend du modèle officiel au lancement | ✅ |
|
||||
| [Avancé 4 : Développement multiplateforme : Comment construire des mini-programmes WeChat - Y compris backend](docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) : Intégrer une base de données et une logique backend dans les mini-programmes, réaliser un cycle d'activité complet | 🚧 |
|
||||
|
||||
@@ -140,7 +140,7 @@ AI でコードを書こうとしてエラーが続き、諦めかけたくな
|
||||
|
||||
| 章 | 主要内容 | 状態 |
|
||||
| :---------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------- | :--- |
|
||||
| [上級一:MCP と ClaudeCode Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claudecode-skills/) | MCP と Skills を通じて IDE 能力を拡張し、外部サービスをツールとして接続 | 🚧 |
|
||||
| [上級一:MCP と Claude Code Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claude-code-skills/) | MCP と Skills を通じて IDE 能力を拡張し、外部サービスをツールとして接続 | 🚧 |
|
||||
| [上級二:Coding Tools を長時間動作させる方法](docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) | 長時間動作するタスクを設計・設定し、Coding Tools をより安定して信頼性の高いものに | 🚧 |
|
||||
| [上級三:マルチプラットフォーム開発:WeChat ミニプログラムの構築方法](docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) | WeChat ミニプログラムのエコシステムを理解し、公式テンプレートからリリースまでフロントエンドミニプログラムを完成 | ✅ |
|
||||
| [上級四:マルチプラットフォーム開発:WeChat ミニプログラムの構築方法 - バックエンド含む](docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) | ミニプログラムにデータベースとバックエンドロジックを統合し、完全な業務クローズドループを実現 | 🚧 |
|
||||
|
||||
@@ -140,7 +140,7 @@ AI로 코드를 작성하려고 할 때 오류가 계속 발생하고, 포기하
|
||||
|
||||
| 장 | 주요 내용 | 상태 |
|
||||
| :--------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------- | :--- |
|
||||
| [고급 1: MCP와 ClaudeCode Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claudecode-skills/) | MCP와 Skills를 통해 IDE 능력 확장, 외부 서비스를 도구로 연결 | 🚧 |
|
||||
| [고급 1: MCP와 Claude Code Skills](docs/zh-cn/stage-3/core-skills/3.1-mcp-claude-code-skills/) | MCP와 Skills를 통해 IDE 능력 확장, 외부 서비스를 도구로 연결 | 🚧 |
|
||||
| [고급 2: Coding Tools를 장시간 작동시키는 방법](docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) | 장시간 실행되는 작업 설계 및 구성, Coding Tools를 더 안정적이고 신뢰할 수 있게 | 🚧 |
|
||||
| [고급 3: 멀티플랫폼 개발: 위챗 미니 프로그램 구축 방법](docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) | 위챗 미니 프로그램 생태계 이해, 공식 템플릿부터 출시까지 프론트엔드 미니 프로그램 완성 | ✅ |
|
||||
| [고급 4: 멀티플랫폼 개발: 위챗 미니 프로그램 구축 방법 - 백엔드 포함](docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) | 미니 프로그램에 데이터베이스와 백엔드 로직 통합, 완전한 비즈니스 폐루프 실현 | 🚧 |
|
||||
|
||||
@@ -140,7 +140,7 @@ Chúng tôi tin rằng thông qua việc làm chủ Vibe Coding kết hợp vớ
|
||||
|
||||
| Chương | Nội dung chính | Trạng thái |
|
||||
| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------- | :--------- |
|
||||
| [Cao cấp 1: MCP và ClaudeCode Skills](docs/stage-3/core-skills/3.1-mcp-claudecode-skills/) : Mở rộng khả năng IDE qua MCP và Skills, kết nối dịch vụ bên ngoài như công cụ | 🚧 |
|
||||
| [Cao cấp 1: MCP và Claude Code Skills](docs/stage-3/core-skills/3.1-mcp-claude-code-skills/) : Mở rộng khả năng IDE qua MCP và Skills, kết nối dịch vụ bên ngoài như công cụ | 🚧 |
|
||||
| [Cao cấp 2: Cách để Coding Tools hoạt động lâu](docs/stage-3/core-skills/3.2-long-running-tasks/) : Thiết kế và cấu hình nhiệm vụ chạy dài, làm Coding Tools ổn định và đáng tin cậy hơn | 🚧 |
|
||||
| [Cao cấp 3: Phát triển đa nền tảng: Cách xây dựng chương trình nhỏ WeChat](docs/stage-3/cross-platform/3.3-wechat-miniprogram/) : Hiểu hệ sinh thái chương trình nhỏ WeChat, hoàn thành chương trình nhỏ frontend từ mẫu chính thức đến phát hành | ✅ |
|
||||
| [Cao cấp 4: Phát triển đa nền tảng: Cách xây dựng chương trình nhỏ WeChat - Bao gồm backend](docs/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) : Tích hợp cơ sở dữ liệu và logic backend vào chương trình nhỏ, thực hiện vòng tuần hoàn hoạt động hoàn chỉnh | 🚧 |
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
|
||||
| 章节 | 關鍵內容 | 狀態 |
|
||||
| :---------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------- | :--- |
|
||||
| [高級一:MCP 與 ClaudeCode Skills](../docs/zh-cn/stage-3/core-skills/3.1-mcp-claudecode-skills/) | 通過 MCP 與 Skills 擴展 IDE 能力,把外部服務接成工具 | 🚧 |
|
||||
| [高級一:MCP 與 Claude Code Skills](../docs/zh-cn/stage-3/core-skills/3.1-mcp-claude-code-skills/) | 通過 MCP 與 Skills 擴展 IDE 能力,把外部服務接成工具 | 🚧 |
|
||||
| [高級二:如何讓 Coding Tools 長時間工作](../docs/zh-cn/stage-3/core-skills/3.2-long-running-tasks/) | 設計和配置長時間運行的任務,讓 Coding Tools 更穩定可靠 | 🚧 |
|
||||
| [高級三:多平台開發:如何建構微信小程式](../docs/zh-cn/stage-3/cross-platform/3.3-wechat-miniprogram/) | 了解微信小程式生態,從官方模板到上線完成一個前端小程式 | ✅ |
|
||||
| [高級四:多平台開發:如何建構微信小程式-包含後端](../docs/zh-cn/stage-3/cross-platform/3.4-wechat-miniprogram-backend/) | 在小程式中接入數據庫與後端邏輯,打通完整業務閉環 | 🚧 |
|
||||
|
||||
+131
-127
@@ -344,7 +344,7 @@ export default defineConfig({
|
||||
text: '高级开发',
|
||||
link: '/zh-cn/stage-3/intro'
|
||||
},
|
||||
{ text: '附录', link: '/zh-cn/appendix/intro' }
|
||||
{ text: '附录', link: '/zh-cn/appendix/index' }
|
||||
],
|
||||
sidebar: {
|
||||
'/zh-cn/stage-0/': productManagerSidebar,
|
||||
@@ -445,8 +445,8 @@ export default defineConfig({
|
||||
collapsed: false,
|
||||
items: [
|
||||
{
|
||||
text: '高级一:MCP 与 ClaudeCode Skills',
|
||||
link: '/zh-cn/stage-3/core-skills/3.1-mcp-claudecode-skills/'
|
||||
text: '高级一:MCP 与 Claude Code Skills',
|
||||
link: '/zh-cn/stage-3/core-skills/3.1-mcp-claude-code-skills/'
|
||||
},
|
||||
{
|
||||
text: '高级二:如何让 Coding Tools 长时间工作',
|
||||
@@ -570,152 +570,156 @@ export default defineConfig({
|
||||
],
|
||||
'/zh-cn/appendix/': [
|
||||
{
|
||||
text: '人工智能基础',
|
||||
text: '一、计算机是怎么回事',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{
|
||||
text: '提示词工程',
|
||||
link: '/zh-cn/appendix/prompt-engineering'
|
||||
},
|
||||
{
|
||||
text: '人工智能进化史',
|
||||
link: '/zh-cn/appendix/ai-evolution'
|
||||
},
|
||||
{ text: '大语言模型', link: '/zh-cn/appendix/llm-intro' },
|
||||
{ text: '多模态大模型', link: '/zh-cn/appendix/vlm-intro' },
|
||||
{
|
||||
text: 'AI 绘画原理',
|
||||
link: '/zh-cn/appendix/image-gen-intro'
|
||||
},
|
||||
{ text: 'AI 音频模型', link: '/zh-cn/appendix/audio-intro' },
|
||||
{
|
||||
text: '上下文工程',
|
||||
link: '/zh-cn/appendix/context-engineering'
|
||||
},
|
||||
{ text: 'Agent 智能体', link: '/zh-cn/appendix/agent-intro' },
|
||||
{
|
||||
text: 'AI 能力词典',
|
||||
link: '/zh-cn/appendix/ai-capability-dictionary'
|
||||
}
|
||||
{ text: '从晶体管到 CPU', link: '/zh-cn/appendix/1-computer-fundamentals/transistor-to-cpu' },
|
||||
{ text: '操作系统(进程 / 内存 / 文件系统)', link: '/zh-cn/appendix/1-computer-fundamentals/operating-systems' },
|
||||
{ text: '数据的编码、存储与传输', link: '/zh-cn/appendix/1-computer-fundamentals/data-encoding-storage' },
|
||||
{ text: '网络:两台电脑如何对话', link: '/zh-cn/appendix/1-computer-fundamentals/computer-networks' },
|
||||
{ text: '数据结构', link: '/zh-cn/appendix/1-computer-fundamentals/data-structures' },
|
||||
{ text: '算法思维入门', link: '/zh-cn/appendix/1-computer-fundamentals/algorithm-thinking' },
|
||||
{ text: '编程语言图谱', link: '/zh-cn/appendix/1-computer-fundamentals/programming-languages' },
|
||||
{ text: '类型系统与编译原理入门', link: '/zh-cn/appendix/1-computer-fundamentals/type-systems-compilers' }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: '前端开发',
|
||||
text: '二、开发环境与工具',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{
|
||||
text: 'HTML/CSS/JS 基础',
|
||||
link: '/zh-cn/appendix/web-basics'
|
||||
},
|
||||
{
|
||||
text: '前端进化史',
|
||||
link: '/zh-cn/appendix/frontend-evolution'
|
||||
},
|
||||
{
|
||||
text: '前端性能优化',
|
||||
link: '/zh-cn/appendix/frontend-performance'
|
||||
},
|
||||
{
|
||||
text: 'Canvas 2D 入门',
|
||||
link: '/zh-cn/appendix/canvas-intro'
|
||||
},
|
||||
{
|
||||
text: 'URL 到浏览器显示',
|
||||
link: '/zh-cn/appendix/url-to-browser'
|
||||
},
|
||||
{
|
||||
text: '浏览器调试器',
|
||||
link: '/zh-cn/appendix/browser-devtools'
|
||||
},
|
||||
{
|
||||
text: '浏览器渲染原理',
|
||||
link: '/zh-cn/appendix/browser-rendering-pipeline'
|
||||
},
|
||||
{
|
||||
text: '前端路由原理',
|
||||
link: '/zh-cn/appendix/frontend-routing'
|
||||
},
|
||||
{
|
||||
text: '组件状态管理',
|
||||
link: '/zh-cn/appendix/component-state-management'
|
||||
},
|
||||
{
|
||||
text: '前端工程化',
|
||||
link: '/zh-cn/appendix/frontend-engineering'
|
||||
}
|
||||
{ text: '集成开发环境 (IDE) 基础', link: '/zh-cn/appendix/2-development-tools/ide-basics' },
|
||||
{ text: '命令行与 Shell 脚本', link: '/zh-cn/appendix/2-development-tools/command-line-shell' },
|
||||
{ text: '编辑器与 AI 编程助手', link: '/zh-cn/appendix/2-development-tools/editors-and-ai' },
|
||||
{ text: 'Git:代码的时光机', link: '/zh-cn/appendix/2-development-tools/git-version-control' },
|
||||
{ text: '环境变量与 PATH', link: '/zh-cn/appendix/2-development-tools/environment-path' },
|
||||
{ text: '端口与 localhost', link: '/zh-cn/appendix/2-development-tools/ports-localhost' },
|
||||
{ text: 'SSH 与密钥认证', link: '/zh-cn/appendix/2-development-tools/ssh-authentication' },
|
||||
{ text: '包管理器(npm / pip / cargo)', link: '/zh-cn/appendix/2-development-tools/package-managers' },
|
||||
{ text: '调试的艺术', link: '/zh-cn/appendix/2-development-tools/debugging-art/' },
|
||||
{ text: '正则表达式', link: '/zh-cn/appendix/2-development-tools/regex' }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: '后端开发',
|
||||
text: '三、浏览器与前端',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{
|
||||
text: '后端进化史',
|
||||
link: '/zh-cn/appendix/backend-evolution'
|
||||
},
|
||||
{
|
||||
text: '后端分层架构',
|
||||
link: '/zh-cn/appendix/backend-layered-architecture'
|
||||
},
|
||||
{
|
||||
text: '后端编程语言',
|
||||
link: '/zh-cn/appendix/backend-languages'
|
||||
},
|
||||
{
|
||||
text: '并发编程模型',
|
||||
link: '/zh-cn/appendix/concurrency-models'
|
||||
},
|
||||
{
|
||||
text: '接口设计规范',
|
||||
link: '/zh-cn/appendix/api-design'
|
||||
},
|
||||
{ text: '数据库原理', link: '/zh-cn/appendix/database-intro' },
|
||||
{ text: '系统缓存设计', link: '/zh-cn/appendix/cache-design' },
|
||||
{ text: '消息队列设计', link: '/zh-cn/appendix/queue-design' },
|
||||
{ text: '鉴权原理与实战', link: '/zh-cn/appendix/auth-design' },
|
||||
{
|
||||
text: '网关与反向代理',
|
||||
link: '/zh-cn/appendix/gateway-proxy'
|
||||
},
|
||||
{
|
||||
text: '负载均衡策略',
|
||||
link: '/zh-cn/appendix/load-balancing'
|
||||
},
|
||||
{ text: '埋点设计', link: '/zh-cn/appendix/tracking-design' },
|
||||
{ text: '线上运维', link: '/zh-cn/appendix/operations' }
|
||||
{ text: 'JavaScript 语言深入', link: '/zh-cn/appendix/3-browser-and-frontend/javascript-deep-dive' },
|
||||
{ text: 'TypeScript:给 JS 加上类型系统', link: '/zh-cn/appendix/3-browser-and-frontend/typescript' },
|
||||
{ text: '前端框架对比(React / Vue / Svelte / Angular)', link: '/zh-cn/appendix/3-browser-and-frontend/frontend-frameworks' },
|
||||
{ text: '浏览器是一个操作系统', link: '/zh-cn/appendix/3-browser-and-frontend/browser-as-os' },
|
||||
{ text: '浏览器渲染管道', link: '/zh-cn/appendix/3-browser-and-frontend/browser-as-os-rendering' },
|
||||
{ text: 'HTML / CSS 布局体系', link: '/zh-cn/appendix/3-browser-and-frontend/html-css-layout' },
|
||||
{ text: 'JavaScript 运行时', link: '/zh-cn/appendix/3-browser-and-frontend/javascript-runtime' },
|
||||
{ text: '前端框架的本质', link: '/zh-cn/appendix/3-browser-and-frontend/frontend-framework-nature' },
|
||||
{ text: '状态管理哲学', link: '/zh-cn/appendix/3-browser-and-frontend/state-management' },
|
||||
{ text: '路由与导航', link: '/zh-cn/appendix/3-browser-and-frontend/routing-navigation' },
|
||||
{ text: '图形与动画(Canvas / SVG / WebGL)', link: '/zh-cn/appendix/3-browser-and-frontend/graphics-animation' },
|
||||
{ text: '实时通信(WebSocket / SSE)', link: '/zh-cn/appendix/3-browser-and-frontend/realtime-communication' },
|
||||
{ text: '网页性能的度量与优化', link: '/zh-cn/appendix/3-browser-and-frontend/web-performance' },
|
||||
{ text: '前端工程化全貌', link: '/zh-cn/appendix/3-browser-and-frontend/frontend-engineering' },
|
||||
{ text: '无障碍与国际化', link: '/zh-cn/appendix/3-browser-and-frontend/a11n-i18n' }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: '云计算与服务',
|
||||
text: '四、服务器与后端',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{
|
||||
text: '云服务基础',
|
||||
link: '/zh-cn/appendix/cloud-services'
|
||||
},
|
||||
{
|
||||
text: 'IAM 权限管理',
|
||||
link: '/zh-cn/appendix/cloud-iam'
|
||||
},
|
||||
{
|
||||
text: '对象存储与 CDN',
|
||||
link: '/zh-cn/appendix/cloud-storage-cdn'
|
||||
}
|
||||
{ text: '后端语言对比(Node.js / Go / Java / Rust)', link: '/zh-cn/appendix/4-server-and-backend/backend-languages' },
|
||||
{ text: '客户端语言对比(Swift / Kotlin / Dart)', link: '/zh-cn/appendix/4-server-and-backend/client-languages' },
|
||||
{ text: '跨平台方案对比(React Native / Flutter / Electron / Tauri)', link: '/zh-cn/appendix/4-server-and-backend/cross-platform' },
|
||||
{ text: 'HTTP 协议', link: '/zh-cn/appendix/4-server-and-backend/http-protocol' },
|
||||
{ text: '一个请求的完整旅程', link: '/zh-cn/appendix/4-server-and-backend/request-journey' },
|
||||
{ text: 'Web 框架的本质', link: '/zh-cn/appendix/4-server-and-backend/web-frameworks' },
|
||||
{ text: 'API 设计哲学(REST / GraphQL / gRPC)', link: '/zh-cn/appendix/4-server-and-backend/api-design' },
|
||||
{ text: 'API 入门', link: '/zh-cn/appendix/4-server-and-backend/api-intro' },
|
||||
{ text: '序列化与数据格式', link: '/zh-cn/appendix/4-server-and-backend/serialization' },
|
||||
{ text: '认证与授权体系', link: '/zh-cn/appendix/4-server-and-backend/auth-authorization' },
|
||||
{ text: '并发、异步与多线程', link: '/zh-cn/appendix/4-server-and-backend/concurrency-async' },
|
||||
{ text: '缓存的层次与策略', link: '/zh-cn/appendix/4-server-and-backend/caching' },
|
||||
{ text: '消息队列与事件驱动', link: '/zh-cn/appendix/4-server-and-backend/message-queues' },
|
||||
{ text: '异步任务队列与生产消费模型', link: '/zh-cn/appendix/4-server-and-backend/async-task-queues' },
|
||||
{ text: '限流与背压控制', link: '/zh-cn/appendix/4-server-and-backend/rate-limiting-backpressure' },
|
||||
{ text: '搜索引擎原理', link: '/zh-cn/appendix/4-server-and-backend/search-engines' },
|
||||
{ text: '文件存储与对象存储', link: '/zh-cn/appendix/4-server-and-backend/file-storage' },
|
||||
{ text: '后端分层架构', link: '/zh-cn/appendix/4-server-and-backend/backend-layered-architecture' }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: '通用技能',
|
||||
text: '五、数据',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: 'API 入门', link: '/zh-cn/appendix/api-intro' },
|
||||
{ text: 'IDE 原理', link: '/zh-cn/appendix/ide-intro' },
|
||||
{ text: '终端入门', link: '/zh-cn/appendix/terminal-intro' },
|
||||
{ text: 'Git 详细介绍', link: '/zh-cn/appendix/git-intro' },
|
||||
{
|
||||
text: '计算机网络',
|
||||
link: '/zh-cn/appendix/computer-networks'
|
||||
},
|
||||
{ text: '部署与上线', link: '/zh-cn/appendix/deployment' }
|
||||
{ text: 'SQL', link: '/zh-cn/appendix/5-data/sql' },
|
||||
{ text: '数据库原理(索引 / 事务 / 查询优化)', link: '/zh-cn/appendix/5-data/database-fundamentals' },
|
||||
{ text: '数据模型全景(文档 / 图 / 时序 / 向量)', link: '/zh-cn/appendix/5-data/data-models' },
|
||||
{ text: '数据埋点与用户行为采集', link: '/zh-cn/appendix/5-data/data-tracking' },
|
||||
{ text: '数据分析基础(统计 / 指标 / 漏斗)', link: '/zh-cn/appendix/5-data/data-analysis' },
|
||||
{ text: 'A/B 测试与实验驱动', link: '/zh-cn/appendix/5-data/ab-testing' },
|
||||
{ text: '数据可视化与仪表盘', link: '/zh-cn/appendix/5-data/data-visualization' },
|
||||
{ text: '数据治理与数据质量', link: '/zh-cn/appendix/5-data/data-governance' }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: '六、架构与系统设计',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: '从单体到微服务的演进', link: '/zh-cn/appendix/6-architecture-and-system-design/monolith-to-microservices' },
|
||||
{ text: '分布式系统的挑战', link: '/zh-cn/appendix/6-architecture-and-system-design/distributed-systems' },
|
||||
{ text: '高可用与容灾', link: '/zh-cn/appendix/6-architecture-and-system-design/high-availability' },
|
||||
{ text: '系统设计方法论', link: '/zh-cn/appendix/6-architecture-and-system-design/system-design-methodology' }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: '七、基础设施与运维',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: 'Linux 基础', link: '/zh-cn/appendix/7-infrastructure-and-operations/linux-basics' },
|
||||
{ text: 'Docker 容器化', link: '/zh-cn/appendix/7-infrastructure-and-operations/docker-containers' },
|
||||
{ text: 'Kubernetes 编排', link: '/zh-cn/appendix/7-infrastructure-and-operations/kubernetes' },
|
||||
{ text: 'CI / CD 自动化', link: '/zh-cn/appendix/7-infrastructure-and-operations/ci-cd' },
|
||||
{ text: '域名、DNS 与 HTTPS', link: '/zh-cn/appendix/7-infrastructure-and-operations/dns-https' },
|
||||
{ text: '负载均衡与网关', link: '/zh-cn/appendix/7-infrastructure-and-operations/load-balancing-gateway' },
|
||||
{ text: '网关与反向代理', link: '/zh-cn/appendix/7-infrastructure-and-operations/gateway-proxy' },
|
||||
{ text: '云平台实战', link: '/zh-cn/appendix/7-infrastructure-and-operations/cloud-platforms' },
|
||||
{ text: 'IAM 权限管理', link: '/zh-cn/appendix/7-infrastructure-and-operations/cloud-iam' },
|
||||
{ text: '对象存储与 CDN', link: '/zh-cn/appendix/7-infrastructure-and-operations/cloud-storage-cdn' },
|
||||
{ text: '基础设施即代码', link: '/zh-cn/appendix/7-infrastructure-and-operations/infrastructure-as-code' },
|
||||
{ text: '监控、日志与告警', link: '/zh-cn/appendix/7-infrastructure-and-operations/monitoring-logging' },
|
||||
{ text: '故障排查与应急响应', link: '/zh-cn/appendix/7-infrastructure-and-operations/incident-response' }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: '八、人工智能',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: 'AI 简史与核心概念', link: '/zh-cn/appendix/8-artificial-intelligence/ai-history' },
|
||||
{ text: '神经网络与深度学习', link: '/zh-cn/appendix/8-artificial-intelligence/neural-networks' },
|
||||
{ text: 'Transformer 与注意力机制', link: '/zh-cn/appendix/8-artificial-intelligence/transformer-attention' },
|
||||
{ text: '大语言模型的工作原理', link: '/zh-cn/appendix/8-artificial-intelligence/llm-principles' },
|
||||
{ text: '提示词工程', link: '/zh-cn/appendix/8-artificial-intelligence/prompt-engineering' },
|
||||
{ text: '上下文工程', link: '/zh-cn/appendix/8-artificial-intelligence/context-engineering' },
|
||||
{ text: '多模态模型(视觉 / 音频 / 视频)', link: '/zh-cn/appendix/8-artificial-intelligence/multimodal-models' },
|
||||
{ text: '图像生成原理', link: '/zh-cn/appendix/8-artificial-intelligence/image-generation' },
|
||||
{ text: '语音合成与识别', link: '/zh-cn/appendix/8-artificial-intelligence/speech-synthesis-recognition' },
|
||||
{ text: 'Embedding 与向量检索', link: '/zh-cn/appendix/8-artificial-intelligence/embedding-vector-retrieval' },
|
||||
{ text: 'RAG 架构', link: '/zh-cn/appendix/8-artificial-intelligence/rag' },
|
||||
{ text: 'AI Agent 与工具调用', link: '/zh-cn/appendix/8-artificial-intelligence/ai-agents' },
|
||||
{ text: 'AI 协议(MCP 等)', link: '/zh-cn/appendix/8-artificial-intelligence/ai-protocols' },
|
||||
{ text: '模型微调与部署', link: '/zh-cn/appendix/8-artificial-intelligence/model-finetuning-deployment' },
|
||||
{ text: 'AI 原生应用设计', link: '/zh-cn/appendix/8-artificial-intelligence/ai-native-app-design' },
|
||||
{ text: 'AI 能力词典', link: '/zh-cn/appendix/8-artificial-intelligence/ai-capability-dictionary' }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: '九、工程素养',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: '代码质量与重构', link: '/zh-cn/appendix/9-engineering-excellence/code-quality-refactoring' },
|
||||
{ text: '测试策略', link: '/zh-cn/appendix/9-engineering-excellence/testing-strategies' },
|
||||
{ text: '设计模式', link: '/zh-cn/appendix/9-engineering-excellence/design-patterns' },
|
||||
{ text: '安全思维与攻防基础', link: '/zh-cn/appendix/9-engineering-excellence/security-thinking' },
|
||||
{ text: '技术文档写作', link: '/zh-cn/appendix/9-engineering-excellence/technical-writing' },
|
||||
{ text: '开源协作', link: '/zh-cn/appendix/9-engineering-excellence/open-source-collaboration' },
|
||||
{ text: '技术选型方法论', link: '/zh-cn/appendix/9-engineering-excellence/technology-selection' }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -86,7 +86,6 @@ onMounted(() => {
|
||||
applyLineHeight(savedLineHeight)
|
||||
isHydrated.value = true
|
||||
|
||||
// 初始化 outline 自动滚动功能
|
||||
initOutlineAutoScroll()
|
||||
})
|
||||
|
||||
@@ -95,7 +94,34 @@ onMounted(() => {
|
||||
// 当页面滚动时,自动滚动 outline 让当前激活项保持在可视区域
|
||||
// ============================================
|
||||
function initOutlineAutoScroll() {
|
||||
// 使用 MutationObserver 监听 outline 的变化
|
||||
const outlineSelectors = [
|
||||
'.VPDocAsideOutline',
|
||||
'.VPTableOfContents',
|
||||
'.vitepress-doc-sidebar',
|
||||
'.sidebar-outline',
|
||||
'aside'
|
||||
]
|
||||
|
||||
const sidebarSelectors = [
|
||||
'.VPSidebar',
|
||||
'.VPDocSidebar',
|
||||
'.vitepress-doc-sidebar'
|
||||
]
|
||||
|
||||
let outlineContainer = null
|
||||
for (const selector of outlineSelectors) {
|
||||
outlineContainer = document.querySelector(selector)
|
||||
if (outlineContainer) break
|
||||
}
|
||||
|
||||
if (!outlineContainer) return
|
||||
|
||||
let sidebarContainer = null
|
||||
for (const selector of sidebarSelectors) {
|
||||
sidebarContainer = document.querySelector(selector)
|
||||
if (sidebarContainer) break
|
||||
}
|
||||
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
for (const mutation of mutations) {
|
||||
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
|
||||
@@ -107,7 +133,17 @@ function initOutlineAutoScroll() {
|
||||
}
|
||||
})
|
||||
|
||||
// 开始监听
|
||||
const sidebarObserver = new MutationObserver((mutations) => {
|
||||
for (const mutation of mutations) {
|
||||
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
|
||||
const target = mutation.target
|
||||
if (target.classList.contains('is-active')) {
|
||||
scrollSidebarToActiveItem(target)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const startObserving = () => {
|
||||
const outlineContainer = document.querySelector('.VPDocAsideOutline')
|
||||
if (outlineContainer) {
|
||||
@@ -116,32 +152,48 @@ function initOutlineAutoScroll() {
|
||||
subtree: true,
|
||||
attributeFilter: ['class']
|
||||
})
|
||||
|
||||
const existingActive = outlineContainer.querySelector('.active')
|
||||
if (existingActive) {
|
||||
scrollOutlineToActiveItem(existingActive)
|
||||
}
|
||||
}
|
||||
|
||||
if (sidebarContainer) {
|
||||
sidebarObserver.observe(sidebarContainer, {
|
||||
attributes: true,
|
||||
subtree: true,
|
||||
attributeFilter: ['class']
|
||||
})
|
||||
|
||||
const existingSidebarActive = sidebarContainer.querySelector('.is-active')
|
||||
if (existingSidebarActive) {
|
||||
scrollSidebarToActiveItem(existingSidebarActive)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载完成后开始监听
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', startObserving)
|
||||
} else {
|
||||
startObserving()
|
||||
}
|
||||
|
||||
// 同时监听路由变化(VitePress 是 SPA)
|
||||
const originalPushState = history.pushState
|
||||
const originalReplaceState = history.replaceState
|
||||
|
||||
history.pushState = function (...args) {
|
||||
originalPushState.apply(this, args)
|
||||
setTimeout(startObserving, 100)
|
||||
setTimeout(startObserving, 300)
|
||||
}
|
||||
|
||||
history.replaceState = function (...args) {
|
||||
originalReplaceState.apply(this, args)
|
||||
setTimeout(startObserving, 100)
|
||||
setTimeout(startObserving, 300)
|
||||
}
|
||||
|
||||
window.addEventListener('popstate', () => {
|
||||
setTimeout(startObserving, 100)
|
||||
setTimeout(startObserving, 300)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -172,6 +224,32 @@ function scrollOutlineToActiveItem(activeLink) {
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动侧边栏让当前激活项保持在可视区域中心
|
||||
function scrollSidebarToActiveItem(activeItem) {
|
||||
const sidebarContainer = document.querySelector('.VPSidebar') || document.querySelector('.VPDocSidebar')
|
||||
if (!sidebarContainer || !activeItem) return
|
||||
|
||||
const targetElement = activeItem.querySelector('.item') || activeItem.querySelector('a') || activeItem
|
||||
|
||||
const containerRect = sidebarContainer.getBoundingClientRect()
|
||||
const targetRect = targetElement.getBoundingClientRect()
|
||||
|
||||
const targetTop = targetRect.top - containerRect.top + sidebarContainer.scrollTop
|
||||
const targetHeight = targetRect.height
|
||||
const targetCenterY = targetTop + targetHeight / 2
|
||||
|
||||
const isInside = targetRect.top >= containerRect.top - 20 &&
|
||||
targetRect.bottom <= containerRect.bottom + 20
|
||||
|
||||
if (!isInside) {
|
||||
const targetScrollTop = targetCenterY - containerRect.height / 2
|
||||
sidebarContainer.scrollTo({
|
||||
top: targetScrollTop,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
watch(fontSize, (next) => {
|
||||
if (!isHydrated.value) return
|
||||
const normalized = clampFontSize(next)
|
||||
|
||||
@@ -156,7 +156,7 @@ const current = ref(modules[0])
|
||||
.icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
background: var(--vp-c-bg-soft);
|
||||
|
||||
@@ -261,7 +261,7 @@ const wait = (ms) => new Promise(r => setTimeout(r, ms))
|
||||
padding: 12px;
|
||||
min-height: 120px;
|
||||
max-height: 160px;
|
||||
overflow-y: auto;
|
||||
|
||||
}
|
||||
|
||||
.msg-row {
|
||||
@@ -421,7 +421,7 @@ const wait = (ms) => new Promise(r => setTimeout(r, ms))
|
||||
gap: 8px;
|
||||
padding: 10px 14px;
|
||||
background: #dcfce7;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 16px;
|
||||
font-size: 12px;
|
||||
color: #166534;
|
||||
@@ -433,7 +433,7 @@ const wait = (ms) => new Promise(r => setTimeout(r, ms))
|
||||
gap: 8px;
|
||||
padding: 10px 14px;
|
||||
background: var(--vp-c-brand-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
@@ -588,7 +588,7 @@ const truncate = (str, len) => str?.length > len ? str.slice(0, len) + '...' : s
|
||||
/* 对话区 */
|
||||
.chat-area {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 12px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
@@ -613,7 +613,7 @@ const truncate = (str, len) => str?.length > len ? str.slice(0, len) + '...' : s
|
||||
|
||||
.messages {
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
@@ -732,7 +732,7 @@ const truncate = (str, len) => str?.length > len ? str.slice(0, len) + '...' : s
|
||||
.memory-panel {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
@@ -778,7 +778,7 @@ const truncate = (str, len) => str?.length > len ? str.slice(0, len) + '...' : s
|
||||
padding: 10px;
|
||||
min-height: 80px;
|
||||
max-height: 120px;
|
||||
overflow-y: auto;
|
||||
|
||||
}
|
||||
|
||||
.empty {
|
||||
@@ -1060,7 +1060,7 @@ const truncate = (str, len) => str?.length > len ? str.slice(0, len) + '...' : s
|
||||
gap: 12px;
|
||||
padding: 12px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.practice-icon {
|
||||
|
||||
@@ -435,7 +435,7 @@ const truncate = (str, len) => str.length > len ? str.slice(0, len) + '...' : st
|
||||
.phase {
|
||||
margin-bottom: 12px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
opacity: 0.5;
|
||||
transition: all 0.3s;
|
||||
@@ -525,7 +525,7 @@ const truncate = (str, len) => str.length > len ? str.slice(0, len) + '...' : st
|
||||
gap: 12px;
|
||||
padding: 12px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
border: 2px solid transparent;
|
||||
transition: all 0.3s;
|
||||
position: relative;
|
||||
@@ -685,7 +685,7 @@ const truncate = (str, len) => str.length > len ? str.slice(0, len) + '...' : st
|
||||
.final-output {
|
||||
padding: 12px;
|
||||
background: #dcfce7;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.output-bubble {
|
||||
@@ -704,7 +704,7 @@ const truncate = (str, len) => str.length > len ? str.slice(0, len) + '...' : st
|
||||
|
||||
.control-btn {
|
||||
padding: 10px 24px;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
@@ -762,7 +762,7 @@ const truncate = (str, len) => str.length > len ? str.slice(0, len) + '...' : st
|
||||
.explanation-card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 14px;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -788,7 +788,7 @@ const truncate = (str, len) => str.length > len ? str.slice(0, len) + '...' : st
|
||||
.comparison-section {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 14px;
|
||||
}
|
||||
|
||||
|
||||
@@ -304,7 +304,7 @@ reset()
|
||||
.goal-bar {
|
||||
background: var(--vp-c-brand-soft);
|
||||
border-left: 3px solid var(--vp-c-brand);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 10px 14px;
|
||||
margin-bottom: 16px;
|
||||
font-size: 14px;
|
||||
@@ -403,7 +403,7 @@ reset()
|
||||
.log-box, .thought-box {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -431,7 +431,7 @@ reset()
|
||||
padding: 10px 12px;
|
||||
min-height: 100px;
|
||||
max-height: 140px;
|
||||
overflow-y: auto;
|
||||
|
||||
}
|
||||
|
||||
.empty {
|
||||
@@ -534,7 +534,7 @@ reset()
|
||||
gap: 8px;
|
||||
padding: 10px 14px;
|
||||
background: var(--vp-c-brand-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
@@ -476,7 +476,7 @@ const wait = (ms) => new Promise(r => setTimeout(r, ms))
|
||||
.thinking-section {
|
||||
margin-bottom: 10px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -516,7 +516,7 @@ const wait = (ms) => new Promise(r => setTimeout(r, ms))
|
||||
.tools-section {
|
||||
margin-bottom: 10px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -530,7 +530,7 @@ const wait = (ms) => new Promise(r => setTimeout(r, ms))
|
||||
gap: 10px;
|
||||
padding: 10px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 8px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
transition: all 0.3s;
|
||||
@@ -603,7 +603,7 @@ const wait = (ms) => new Promise(r => setTimeout(r, ms))
|
||||
padding: 12px;
|
||||
background: #dcfce7;
|
||||
border: 1px solid #86efac;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.response-header {
|
||||
@@ -628,7 +628,7 @@ const wait = (ms) => new Promise(r => setTimeout(r, ms))
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
@@ -651,7 +651,7 @@ const wait = (ms) => new Promise(r => setTimeout(r, ms))
|
||||
margin-top: 16px;
|
||||
padding: 12px 16px;
|
||||
background: var(--vp-c-brand-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
|
||||
@@ -163,7 +163,7 @@ const steps = [
|
||||
.n {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
background: var(--vp-c-bg-soft);
|
||||
|
||||
@@ -266,7 +266,7 @@ const reset = () => { currentStep.value = 0 }
|
||||
.user-input-bar {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 10px 14px;
|
||||
margin-bottom: 16px;
|
||||
font-size: 14px;
|
||||
@@ -460,7 +460,7 @@ const reset = () => { currentStep.value = 0 }
|
||||
.final-result {
|
||||
background: var(--vp-c-brand-soft);
|
||||
border-left: 3px solid var(--vp-c-brand);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 12px 14px;
|
||||
margin-bottom: 16px;
|
||||
font-size: 13px;
|
||||
@@ -513,7 +513,7 @@ const reset = () => { currentStep.value = 0 }
|
||||
gap: 8px;
|
||||
padding: 10px 14px;
|
||||
background: var(--vp-c-brand-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ const reset = () => {
|
||||
.icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
background: var(--vp-c-bg-soft);
|
||||
|
||||
@@ -140,7 +140,7 @@ const getInsight = (index) => {
|
||||
margin-bottom: 24px;
|
||||
padding: 16px;
|
||||
background-color: var(--vp-c-bg-alt);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.word-token {
|
||||
|
||||
@@ -234,7 +234,7 @@ onMounted(() => {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
background-color: var(--vp-c-bg-alt);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
|
||||
@@ -213,7 +213,7 @@ watch([featureCount, valuesPerFeature], () => {
|
||||
text-align: center;
|
||||
background-color: var(--vp-c-bg-alt);
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.formula-suffix {
|
||||
@@ -234,7 +234,7 @@ watch([featureCount, valuesPerFeature], () => {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 2px solid;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
+1
-1
@@ -208,7 +208,7 @@ const mode = ref('discriminative')
|
||||
gap: 10px;
|
||||
background-color: var(--vp-c-bg);
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.io-box {
|
||||
|
||||
@@ -149,7 +149,7 @@ const handleTabClick = (tab) => {
|
||||
}
|
||||
|
||||
.main-card {
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
|
||||
+1
-1
@@ -334,7 +334,7 @@ const isConnectionFocus = (c) => {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
background-color: var(--vp-c-bg-alt);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
|
||||
@@ -274,7 +274,7 @@ const train = () => {
|
||||
.result-box {
|
||||
background-color: var(--vp-c-bg-alt);
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -1,50 +1,496 @@
|
||||
<!--
|
||||
DocumentationDemo.vue - API 文档演示组件
|
||||
展示 API 文档的编写规范和最佳实践
|
||||
-->
|
||||
<template>
|
||||
<div class="demo-container">
|
||||
<div class="demo-header">
|
||||
<h4>{{ title }}</h4>
|
||||
<p class="hint">{{ description }}</p>
|
||||
<div class="demo">
|
||||
<div class="header">
|
||||
<span class="icon">📚</span>
|
||||
<span class="title">API 文档:最好的 API 文档就是代码本身</span>
|
||||
</div>
|
||||
<div class="demo-content">
|
||||
<el-alert type="info" :closable="false">
|
||||
文档演示组件占位符 - 待实现具体交互
|
||||
</el-alert>
|
||||
|
||||
<div class="content">
|
||||
<div class="tools-tabs">
|
||||
<button
|
||||
v-for="tool in tools"
|
||||
:key="tool.id"
|
||||
class="tool-btn"
|
||||
:class="{ active: selectedTool === tool.id }"
|
||||
@click="selectedTool = tool.id"
|
||||
>
|
||||
<span class="tool-icon">{{ tool.icon }}</span>
|
||||
<span class="tool-name">{{ tool.name }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="tool-detail" v-if="currentTool">
|
||||
<div class="tool-header">
|
||||
<div class="tool-title">{{ currentTool.name }}</div>
|
||||
<div class="tool-tags">
|
||||
<span class="tag" :class="tag.class" v-for="tag in currentTool.tags" :key="tag.text">
|
||||
{{ tag.text }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tool-description">
|
||||
<p>{{ currentTool.description }}</p>
|
||||
</div>
|
||||
|
||||
<div class="feature-section">
|
||||
<h4>核心特性</h4>
|
||||
<div class="feature-list">
|
||||
<div v-for="(feature, idx) in currentTool.features" :key="idx" class="feature-item">
|
||||
<span class="feature-icon">✓</span>
|
||||
<span class="feature-text">{{ feature }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="example-section">
|
||||
<h4>文档示例(OpenAPI 3.0)</h4>
|
||||
<div class="code-block">
|
||||
<pre><code>{{ currentTool.example }}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tools-section">
|
||||
<h4>🔧 推荐工具</h4>
|
||||
<div class="tools-grid">
|
||||
<div v-for="(rec, idx) in currentTool.recommendations" :key="idx" class="tool-card">
|
||||
<div class="rec-name">{{ rec.name }}</div>
|
||||
<div class="rec-desc">{{ rec.description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
const title = ref('API文档演示')
|
||||
const description = ref('展示RESTful API文档的编写规范和最佳实践,包括Swagger、OpenAPI等工具的使用')
|
||||
const tools = [
|
||||
{
|
||||
id: 'openapi',
|
||||
name: 'OpenAPI 规范',
|
||||
icon: '📋',
|
||||
tags: [
|
||||
{ text: '行业标准', class: 'primary' },
|
||||
{ text: '语言无关', class: 'secondary' }
|
||||
],
|
||||
description: 'OpenAPI Specification(原 Swagger)是描述 REST API 的标准格式,可以被工具解析生成交互式文档、客户端 SDK、服务器存根等。',
|
||||
features: [
|
||||
'标准化的 YAML/JSON 格式描述 API',
|
||||
'支持路径、参数、响应模型、认证等完整定义',
|
||||
'生态系统丰富,支持 100+ 工具',
|
||||
'可以生成交互式文档(Swagger UI)',
|
||||
'可以从代码注释自动生成',
|
||||
'支持 API 版本控制和演进'
|
||||
],
|
||||
example: `openapi: 3.0.0
|
||||
info:
|
||||
title: 用户服务 API
|
||||
version: 1.0.0
|
||||
description: 提供用户管理相关接口
|
||||
servers:
|
||||
- url: https://api.example.com/v1
|
||||
paths:
|
||||
/users:
|
||||
get:
|
||||
summary: 获取用户列表
|
||||
parameters:
|
||||
- name: page
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 1
|
||||
responses:
|
||||
'200':
|
||||
description: 成功
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
code:
|
||||
type: integer
|
||||
data:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/User'
|
||||
components:
|
||||
schemas:
|
||||
User:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
format: email`,
|
||||
recommendations: [
|
||||
{ name: 'Swagger UI', description: '最流行的交互式文档界面' },
|
||||
{ name: 'Redoc', description: '美观的现代文档生成器' },
|
||||
{ name: 'Stoplight', description: '可视化的 API 设计平台' }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'swagger',
|
||||
name: 'Swagger 工具链',
|
||||
icon: '🛠️',
|
||||
tags: [
|
||||
{ text: '工具集', class: 'success' },
|
||||
{ text: '自动化', class: 'info' }
|
||||
],
|
||||
description: 'Swagger 是一套围绕 OpenAPI 规范构建的工具,包括编辑器、UI、代码生成器等,帮助开发者快速构建和使用 API。',
|
||||
features: [
|
||||
'Swagger Editor:在线编写和验证 OpenAPI 文档',
|
||||
'Swagger UI:自动生成交互式文档',
|
||||
'Swagger Codegen:根据文档生成客户端 SDK',
|
||||
'支持主流编程语言和框架',
|
||||
'集成到 CI/CD 流程',
|
||||
'自动保持文档与代码同步'
|
||||
],
|
||||
example: `# Swagger Editor 示例配置
|
||||
swagger: '2.0'
|
||||
info:
|
||||
title: 示例 API
|
||||
version: '1.0.0'
|
||||
host: api.example.com
|
||||
basePath: /v1
|
||||
schemes:
|
||||
- https
|
||||
paths:
|
||||
/users:
|
||||
get:
|
||||
tags:
|
||||
- Users
|
||||
summary: 获取所有用户
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
200:
|
||||
description: 成功
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
code:
|
||||
type: integer
|
||||
data:
|
||||
type: array`,
|
||||
recommendations: [
|
||||
{ name: 'Swagger Editor', description: '在线编辑器,实时预览' },
|
||||
{ name: 'Swagger Codegen', description: '生成 40+ 种语言的客户端' },
|
||||
{ name: 'Postman', description: '导入 OpenAPI 进行测试' }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'best-practices',
|
||||
name: '文档最佳实践',
|
||||
icon: '⭐',
|
||||
tags: [
|
||||
{ text: '经验', class: 'warning' },
|
||||
{ text: '规范', class: 'secondary' }
|
||||
],
|
||||
description: '好的 API 文档应该像用户手册一样清晰,让开发者不问问题就能完成集成。',
|
||||
features: [
|
||||
'每个接口都有完整的请求示例',
|
||||
'提供多种语言的代码示例(curl、JavaScript、Python)',
|
||||
'错误码文档化,附带解决方案',
|
||||
'提供沙箱环境或测试工具',
|
||||
'包含认证流程和获取 Token 的方法',
|
||||
'实时更新,与代码保持一致',
|
||||
'版本变更日志和迁移指南'
|
||||
],
|
||||
example: `# 完整的接口文档示例
|
||||
|
||||
## 获取用户信息
|
||||
|
||||
**请求示例:**
|
||||
|
||||
\`\`\`bash
|
||||
curl -X GET \\
|
||||
https://api.example.com/v1/users/123 \\
|
||||
-H "Authorization: Bearer YOUR_TOKEN"
|
||||
\`\`\`
|
||||
|
||||
**成功响应:**
|
||||
|
||||
\`\`\`json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"id": 123,
|
||||
"name": "张三",
|
||||
"email": "zhangsan@example.com"
|
||||
}
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
**错误响应:**
|
||||
|
||||
| 错误码 | 说明 | 解决方案 |
|
||||
|--------|------|----------|
|
||||
| 10010 | 用户不存在 | 检查 user_id 是否正确 |
|
||||
| 10018 | Token 已过期 | 重新调用登录接口 |
|
||||
|
||||
**在线测试:**
|
||||
|
||||
[🚀 在 API Explorer 中测试](https://api.example.com/docs)`,
|
||||
recommendations: [
|
||||
{ name: 'API Blueprint', description: ' Markdown 风格的 API 文档' },
|
||||
{ name: 'Docusaurus', description: ' Facebook 开源的文档平台' },
|
||||
{ name: 'GitBook', description: '美观的文档托管平台' }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const selectedTool = ref('openapi')
|
||||
const currentTool = computed(() =>
|
||||
tools.find(t => t.id === selectedTool.value)
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.demo-container {
|
||||
.demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
margin: 24px 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
.header {
|
||||
padding: 16px 20px;
|
||||
background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.tools-tabs {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-bottom: 20px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.demo-header h4 {
|
||||
margin: 0 0 8px 0;
|
||||
.tool-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px 16px;
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.tool-btn:hover {
|
||||
border-color: rgba(var(--vp-c-brand-rgb), 0.5);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.tool-btn.active {
|
||||
border-color: var(--vp-c-brand);
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.tool-icon {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.tool-name {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.tool-detail {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tool-header {
|
||||
padding: 16px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tool-title {
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.hint {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
color: var(--vp-c-text-2);
|
||||
.tool-tags {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.demo-content {
|
||||
.tag {
|
||||
padding: 4px 10px;
|
||||
border-radius: 999px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.tag.primary {
|
||||
background: #dbeafe;
|
||||
color: #1d4ed8;
|
||||
}
|
||||
|
||||
.tag.secondary {
|
||||
background: #e0e7ff;
|
||||
color: #4338ca;
|
||||
}
|
||||
|
||||
.tag.success {
|
||||
background: #dcfce7;
|
||||
color: #16a34a;
|
||||
}
|
||||
|
||||
.tag.info {
|
||||
background: #ccfbf1;
|
||||
color: #0f766e;
|
||||
}
|
||||
|
||||
.tag.warning {
|
||||
background: #fef3c7;
|
||||
color: #d97706;
|
||||
}
|
||||
|
||||
.tool-description {
|
||||
padding: 16px;
|
||||
font-size: 14px;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.7;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.feature-section, .example-section, .tools-section {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.feature-section h4, .example-section h4, .tools-section h4 {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
|
||||
.feature-list {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.feature-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
align-items: flex-start;
|
||||
gap: 8px;
|
||||
padding: 8px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.feature-icon {
|
||||
color: #22c55e;
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.feature-text {
|
||||
font-size: 13px;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.code-block {
|
||||
background: var(--vp-c-bg-alt);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.code-block pre {
|
||||
margin: 0;
|
||||
padding: 16px;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.code-block code {
|
||||
font-family: monospace;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.tools-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.tool-card {
|
||||
padding: 12px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.rec-name {
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
color: var(--vp-c-text-1);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.rec-desc {
|
||||
font-size: 12px;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.tools-tabs {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.feature-list {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.tools-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,97 +1,379 @@
|
||||
<!--
|
||||
ErrorHandlingDemo.vue - 错误处理演示组件
|
||||
展示错误处理的正确和错误示例对比
|
||||
-->
|
||||
<template>
|
||||
<div class="demo-container">
|
||||
<div class="demo-header">
|
||||
<h4>错误处理演示</h4>
|
||||
<p class="hint">展示RESTful API中的错误处理机制</p>
|
||||
<div class="demo">
|
||||
<div class="header">
|
||||
<span class="icon">🚨</span>
|
||||
<span class="title">错误处理:优雅地"拒绝"</span>
|
||||
</div>
|
||||
<div class="demo-content">
|
||||
<div class="error-types">
|
||||
<div class="error-item">
|
||||
<span class="code">400</span>
|
||||
<span class="name">Bad Request</span>
|
||||
<span class="desc">请求参数错误</span>
|
||||
|
||||
<div class="content">
|
||||
<div class="comparison-tabs">
|
||||
<button
|
||||
class="tab-btn bad"
|
||||
:class="{ active: selectedTab === 'bad' }"
|
||||
@click="selectedTab = 'bad'"
|
||||
>
|
||||
❌ 错误示范
|
||||
</button>
|
||||
<button
|
||||
class="tab-btn good"
|
||||
:class="{ active: selectedTab === 'good' }"
|
||||
@click="selectedTab = 'good'"
|
||||
>
|
||||
✅ 正确示范
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 错误示范 -->
|
||||
<div v-if="selectedTab === 'bad'" class="comparison bad">
|
||||
<div class="response-preview">
|
||||
<div class="status-line bad">
|
||||
<span>HTTP/1.1</span>
|
||||
<span class="code">200 OK</span>
|
||||
</div>
|
||||
<div class="response-body">
|
||||
<pre><code>{
|
||||
"error": "出错了"
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="error-item">
|
||||
<span class="code">401</span>
|
||||
<span class="name">Unauthorized</span>
|
||||
<span class="desc">未授权访问</span>
|
||||
|
||||
<div class="problems">
|
||||
<h4>问题分析</h4>
|
||||
<ul>
|
||||
<li>
|
||||
<span class="icon">⚠️</span>
|
||||
HTTP 状态码说"成功",但业务说"出错" - 前后端状态不一致
|
||||
</li>
|
||||
<li>
|
||||
<span class="icon">⚠️</span>
|
||||
错误信息太笼统,无法定位问题
|
||||
</li>
|
||||
<li>
|
||||
<span class="icon">⚠️</span>
|
||||
没有错误代码,难以程序化判断
|
||||
</li>
|
||||
<li>
|
||||
<span class="icon">⚠️</span>
|
||||
浏览器和 CDN 会缓存这个"成功的"响应
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="error-item">
|
||||
<span class="code">404</span>
|
||||
<span class="name">Not Found</span>
|
||||
<span class="desc">资源不存在</span>
|
||||
</div>
|
||||
|
||||
<!-- 正确示范 -->
|
||||
<div v-if="selectedTab === 'good'" class="comparison good">
|
||||
<div class="response-preview">
|
||||
<div class="status-line">
|
||||
<span>HTTP/1.1</span>
|
||||
<span class="code">422 Unprocessable Entity</span>
|
||||
</div>
|
||||
<div class="response-body">
|
||||
<pre><code>{{ JSON.stringify(goodResponse, null, 2) }}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="error-item">
|
||||
<span class="code">500</span>
|
||||
<span class="name">Server Error</span>
|
||||
<span class="desc">服务器内部错误</span>
|
||||
|
||||
<div class="highlights">
|
||||
<h4>正确做法</h4>
|
||||
<ul>
|
||||
<li>
|
||||
<span class="icon">✅</span>
|
||||
<strong>正确的 HTTP 状态码</strong>: 422 表示语义错误
|
||||
</li>
|
||||
<li>
|
||||
<span class="icon">✅</span>
|
||||
<strong>业务错误码</strong>: `code: 20003` 可用于程序判断
|
||||
</li>
|
||||
<li>
|
||||
<span class="icon">✅</span>
|
||||
<strong>详细错误信息</strong>: `errors` 数组包含具体字段和原因
|
||||
</li>
|
||||
<li>
|
||||
<span class="icon">✅</span>
|
||||
<strong>可追踪性</strong>: `request_id` 用于日志查询
|
||||
</li>
|
||||
<li>
|
||||
<span class="icon">✅</span>
|
||||
<strong>帮助链接</strong>: `help_url` 引导用户查看文档
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="error-codes">
|
||||
<h4>错误码体系</h4>
|
||||
<div class="code-list">
|
||||
<div v-for="item in errorCodeItems" :key="item.code" class="code-item">
|
||||
<span class="code-badge">{{ item.code }}</span>
|
||||
<span class="code-desc">{{ item.desc }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const selectedTab = ref('bad')
|
||||
|
||||
const goodResponse = {
|
||||
code: 20003,
|
||||
message: '密码强度不足',
|
||||
errors: [
|
||||
{
|
||||
field: 'password',
|
||||
code: 'VALIDATION_ERROR',
|
||||
message: '密码必须包含至少 1 个大写字母、1 个小写字母、1 个数字,且长度至少 8 位'
|
||||
}
|
||||
],
|
||||
request_id: 'req-550e8400-e29b-41d4-a716-44665544000',
|
||||
timestamp: '2024-01-15T09:30:00.000Z',
|
||||
help_url: 'https://docs.example.com/errors/20003'
|
||||
}
|
||||
|
||||
const errorCodeItems = [
|
||||
{ code: '1XXYY', desc: '通用错误(第1位固定为1)' },
|
||||
{ code: '10001', desc: '参数错误' },
|
||||
{ code: '10010', desc: '用户不存在' },
|
||||
{ code: '10018', desc: 'Token 已过期' },
|
||||
{ code: '10021', desc: '权限不足' },
|
||||
{ code: '20003', desc: '密码强度不足' },
|
||||
{ code: '20014', desc: '余额不足' }
|
||||
]
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.demo-container {
|
||||
.demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
margin: 24px 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.demo-header h4 {
|
||||
margin: 0 0 8px 0;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.hint {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.demo-content {
|
||||
.header {
|
||||
padding: 16px 20px;
|
||||
background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
|
||||
color: white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.error-types {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.error-item {
|
||||
.icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.comparison-tabs {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.tab-btn {
|
||||
flex: 1;
|
||||
padding: 12px;
|
||||
border: 2px solid;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.tab-btn.bad {
|
||||
border-color: #ef4444;
|
||||
background: var(--vp-c-bg);
|
||||
color: #ef4444;
|
||||
}
|
||||
|
||||
.tab-btn.bad:hover {
|
||||
background: #fef2f2;
|
||||
}
|
||||
|
||||
.tab-btn.bad.active {
|
||||
background: #ef4444;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.tab-btn.good {
|
||||
border-color: #22c55e;
|
||||
background: var(--vp-c-bg);
|
||||
color: #22c55e;
|
||||
}
|
||||
|
||||
.tab-btn.good:hover {
|
||||
background: #f0fdf4;
|
||||
}
|
||||
|
||||
.tab-btn.good.active {
|
||||
background: #22c55e;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.comparison {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.response-preview {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.status-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
gap: 12px;
|
||||
padding: 12px 16px;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-left: 4px solid #f56c6c;
|
||||
}
|
||||
|
||||
.error-item .code {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
font-family: monospace;
|
||||
font-weight: 600;
|
||||
color: #f56c6c;
|
||||
font-size: 16px;
|
||||
min-width: 50px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.error-item .name {
|
||||
font-weight: 500;
|
||||
.status-line.bad .code {
|
||||
color: #ef4444;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.status-line:not(.bad) .code {
|
||||
color: #d97706;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.response-body {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.response-body pre {
|
||||
margin: 0;
|
||||
background: var(--vp-c-bg-alt);
|
||||
padding: 16px;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.response-body code {
|
||||
font-family: monospace;
|
||||
color: var(--vp-c-text-1);
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.error-item .desc {
|
||||
color: var(--vp-c-text-2);
|
||||
.problems, .highlights {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.problems h4, .highlights h4 {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
|
||||
.problems ul, .highlights ul {
|
||||
margin: 0;
|
||||
padding-left: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.problems li, .highlights li {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
padding: 10px;
|
||||
margin-bottom: 8px;
|
||||
border-radius: 6px;
|
||||
line-height: 1.6;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.problems li {
|
||||
background: #fef2f2;
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
.highlights li {
|
||||
background: #f0fdf4;
|
||||
color: #166534;
|
||||
}
|
||||
|
||||
.problems li .icon, .highlights li .icon {
|
||||
font-size: 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.problems li strong, .highlights li strong {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.error-codes {
|
||||
padding: 16px;
|
||||
border-top: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.error-codes h4 {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
|
||||
.code-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.code-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 10px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 6px;
|
||||
border-left: 3px solid var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.code-badge {
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
padding: 4px 8px;
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
min-width: 70px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.code-desc {
|
||||
font-size: 13px;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.comparison-tabs {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.status-line {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -268,7 +268,7 @@ const currentMethod = computed(() =>
|
||||
.method-detail {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
@@ -306,7 +306,7 @@ const currentMethod = computed(() =>
|
||||
align-items: center;
|
||||
padding: 12px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
opacity: 0.6;
|
||||
transition: all 0.2s ease;
|
||||
@@ -361,7 +361,7 @@ const currentMethod = computed(() =>
|
||||
.example-item {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<style scoped>
|
||||
.demo-container {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
}
|
||||
@@ -82,7 +82,7 @@
|
||||
|
||||
.section {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
border-left: 4px solid var(--vp-c-brand);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<style scoped>
|
||||
.demo-container {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
}
|
||||
@@ -77,7 +77,7 @@
|
||||
gap: 12px;
|
||||
padding: 12px;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
|
||||
@@ -1,50 +1,397 @@
|
||||
<!--
|
||||
ResponseStructureDemo.vue - HTTP 响应结构演示组件
|
||||
展示标准化 API 响应结构和分页响应
|
||||
-->
|
||||
<template>
|
||||
<div class="demo-container">
|
||||
<div class="demo-header">
|
||||
<h4>{{ title }}</h4>
|
||||
<p class="hint">{{ description }}</p>
|
||||
<div class="demo">
|
||||
<div class="header">
|
||||
<span class="icon">📦</span>
|
||||
<span class="title">HTTP 响应结构:标准化的数据契约</span>
|
||||
</div>
|
||||
<div class="demo-content">
|
||||
<el-alert type="info" :closable="false">
|
||||
响应结构演示组件占位符 - 待实现具体交互
|
||||
</el-alert>
|
||||
|
||||
<div class="content">
|
||||
<div class="response-tabs">
|
||||
<button
|
||||
v-for="tab in tabs"
|
||||
:key="tab.id"
|
||||
class="tab-btn"
|
||||
:class="{ active: selectedTab === tab.id }"
|
||||
@click="selectedTab = tab.id"
|
||||
>
|
||||
{{ tab.name }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="response-detail">
|
||||
<div class="response-header">
|
||||
<div class="status-line">
|
||||
<span class="http-version">HTTP/1.1</span>
|
||||
<span class="status-code" :class="getStatusClass(currentResponse.status)">{{ currentResponse.status }}</span>
|
||||
<span class="status-text">{{ currentResponse.statusText }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="response-headers">
|
||||
<div class="header-item">
|
||||
<span class="header-key">Content-Type:</span>
|
||||
<span class="header-value">application/json</span>
|
||||
</div>
|
||||
<div class="header-item">
|
||||
<span class="header-key">X-Request-ID:</span>
|
||||
<span class="header-value">req-550e8400-e29b-41d4</span>
|
||||
</div>
|
||||
<div class="header-item">
|
||||
<span class="header-key">X-Response-Time:</span>
|
||||
<span class="header-value">45ms</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="response-body">
|
||||
<pre><code>{{ JSON.stringify(currentResponse.body, null, 2) }}</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="field-descriptions">
|
||||
<h4>字段说明</h4>
|
||||
<div class="field-list">
|
||||
<div v-for="field in currentResponse.fields" :key="field.name" class="field-item">
|
||||
<div class="field-name">
|
||||
<code>{{ field.name }}</code>
|
||||
<span class="field-type">{{ field.type }}</span>
|
||||
</div>
|
||||
<div class="field-desc">{{ field.description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
const title = ref('HTTP响应结构演示')
|
||||
const description = ref('展示HTTP响应的结构,包括状态行、响应头和响应体')
|
||||
const tabs = [
|
||||
{ id: 'success', name: '成功响应' },
|
||||
{ id: 'pagination', name: '分页响应' },
|
||||
{ id: 'error', name: '错误响应' }
|
||||
]
|
||||
|
||||
const responses = {
|
||||
success: {
|
||||
status: 200,
|
||||
statusText: 'OK',
|
||||
body: {
|
||||
code: 0,
|
||||
message: 'success',
|
||||
data: {
|
||||
id: 123,
|
||||
name: '张三',
|
||||
email: 'zhangsan@example.com',
|
||||
phone: '13800138000',
|
||||
created_at: '2024-01-15T10:30:00.000Z'
|
||||
},
|
||||
request_id: 'req-550e8400-e29b-41d4-a716-446655440000',
|
||||
timestamp: '2024-01-15T10:30:00.000Z'
|
||||
},
|
||||
fields: [
|
||||
{ name: 'code', type: 'integer', description: '业务状态码,0 表示成功' },
|
||||
{ name: 'message', type: 'string', description: '状态描述,成功时为 "success"' },
|
||||
{ name: 'data', type: 'object', description: '业务数据,成功时返回具体数据' },
|
||||
{ name: 'request_id', type: 'string', description: '请求唯一标识,用于问题追踪' },
|
||||
{ name: 'timestamp', type: 'string', description: '响应时间戳,ISO 8601 格式' }
|
||||
]
|
||||
},
|
||||
pagination: {
|
||||
status: 200,
|
||||
statusText: 'OK',
|
||||
body: {
|
||||
code: 0,
|
||||
message: 'success',
|
||||
data: {
|
||||
list: [
|
||||
{ id: 1, name: '商品A', price: 100 },
|
||||
{ id: 2, name: '商品B', price: 200 }
|
||||
],
|
||||
pagination: {
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
total: 156,
|
||||
total_pages: 8,
|
||||
has_next: true,
|
||||
has_prev: false
|
||||
}
|
||||
},
|
||||
request_id: 'req-550e8400-e29b-41d4-a716-446655440000',
|
||||
timestamp: '2024-01-15T10:30:00.000Z'
|
||||
},
|
||||
fields: [
|
||||
{ name: 'list', type: 'array', description: '数据列表' },
|
||||
{ name: 'pagination', type: 'object', description: '分页信息对象' },
|
||||
{ name: 'page', type: 'integer', description: '当前页码' },
|
||||
{ name: 'page_size', type: 'integer', description: '每页数量' },
|
||||
{ name: 'total', type: 'integer', description: '总记录数' },
|
||||
{ name: 'total_pages', type: 'integer', description: '总页数' },
|
||||
{ name: 'has_next', type: 'boolean', description: '是否有下一页' },
|
||||
{ name: 'has_prev', type: 'boolean', description: '是否有上一页' }
|
||||
]
|
||||
},
|
||||
error: {
|
||||
status: 422,
|
||||
statusText: 'Unprocessable Entity',
|
||||
body: {
|
||||
code: 20003,
|
||||
message: '密码强度不足',
|
||||
errors: [
|
||||
{
|
||||
field: 'password',
|
||||
code: 'VALIDATION_ERROR',
|
||||
message: '密码必须包含至少 1 个大写字母、1 个小写字母、1 个数字,且长度至少 8 位'
|
||||
}
|
||||
],
|
||||
request_id: 'req-550e8400-e29b-41d4-a716-446655440000',
|
||||
timestamp: '2024-01-15T10:30:00.000Z',
|
||||
help_url: 'https://docs.example.com/errors/20003'
|
||||
},
|
||||
fields: [
|
||||
{ name: 'code', type: 'integer', description: '错误码,非 0 表示失败' },
|
||||
{ name: 'message', type: 'string', description: '错误描述,供用户阅读' },
|
||||
{ name: 'errors', type: 'array', description: '详细错误信息数组(可选)' },
|
||||
{ name: 'help_url', type: 'string', description: '错误文档链接(可选)' }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
const selectedTab = ref('success')
|
||||
const currentResponse = computed(() => responses[selectedTab.value])
|
||||
|
||||
function getStatusClass(status) {
|
||||
const prefix = Math.floor(status / 100)
|
||||
switch (prefix) {
|
||||
case 2: return 'success'
|
||||
case 3: return 'redirect'
|
||||
case 4: return 'client-error'
|
||||
case 5: return 'server-error'
|
||||
default: return ''
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.demo-container {
|
||||
.demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
margin: 24px 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
.header {
|
||||
padding: 16px 20px;
|
||||
background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%);
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.response-tabs {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.demo-header h4 {
|
||||
margin: 0 0 8px 0;
|
||||
color: var(--vp-c-text-1);
|
||||
.tab-btn {
|
||||
padding: 8px 16px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg);
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.hint {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
.tab-btn:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.tab-btn.active {
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
border-color: var(--vp-c-brand);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.response-detail {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.response-header {
|
||||
padding: 16px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.status-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.http-version {
|
||||
font-family: monospace;
|
||||
font-size: 13px;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.demo-content {
|
||||
.status-code {
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
font-weight: 700;
|
||||
font-size: 13px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.status-code.success {
|
||||
background: #dcfce7;
|
||||
color: #16a34a;
|
||||
}
|
||||
|
||||
.status-code.client-error {
|
||||
background: #fef3c7;
|
||||
color: #d97706;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 13px;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.response-headers {
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.header-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 6px 0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.header-key {
|
||||
font-family: monospace;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.header-value {
|
||||
font-family: monospace;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.response-body {
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.response-body pre {
|
||||
margin: 0;
|
||||
background: var(--vp-c-bg-alt);
|
||||
padding: 16px;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.response-body code {
|
||||
font-family: monospace;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.field-descriptions {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.field-descriptions h4 {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
|
||||
.field-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.field-item {
|
||||
padding: 12px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 6px;
|
||||
border-left: 3px solid var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.field-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.field-name code {
|
||||
font-family: monospace;
|
||||
font-size: 13px;
|
||||
color: var(--vp-c-brand);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.field-type {
|
||||
font-size: 11px;
|
||||
padding: 2px 6px;
|
||||
background: rgba(var(--vp-c-brand-rgb), 0.1);
|
||||
color: var(--vp-c-brand);
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.field-desc {
|
||||
font-size: 13px;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.response-tabs {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.status-line {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.header-item {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -194,9 +194,9 @@ const activePrinciple = computed(() =>
|
||||
.restful-design-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 1.5rem;
|
||||
margin: 1rem 0;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -225,8 +225,8 @@ const activePrinciple = computed(() =>
|
||||
.principle-card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
text-align: center;
|
||||
@@ -260,7 +260,7 @@ const activePrinciple = computed(() =>
|
||||
.detail-panel {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 1.25rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -417,7 +417,7 @@ function toggleExpand(number) {
|
||||
align-items: center;
|
||||
padding: 12px 20px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
@@ -465,7 +465,7 @@ function toggleExpand(number) {
|
||||
.status-card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
@@ -1,50 +1,413 @@
|
||||
<!--
|
||||
VersioningStrategyDemo.vue - API 版本控制策略演示
|
||||
展示 4 种版本控制策略的对比
|
||||
-->
|
||||
<template>
|
||||
<div class="demo-container">
|
||||
<div class="demo-header">
|
||||
<h4>{{ title }}</h4>
|
||||
<p class="hint">{{ description }}</p>
|
||||
<div class="demo">
|
||||
<div class="header">
|
||||
<span class="icon">🔢</span>
|
||||
<span class="title">API 版本控制:向后兼容的艺术</span>
|
||||
</div>
|
||||
<div class="demo-content">
|
||||
<el-alert type="info" :closable="false">
|
||||
版本策略演示组件占位符 - 待实现具体交互
|
||||
</el-alert>
|
||||
|
||||
<div class="content">
|
||||
<div class="strategies">
|
||||
<div
|
||||
v-for="strategy in strategies"
|
||||
:key="strategy.id"
|
||||
class="strategy-card"
|
||||
:class="{ active: selectedStrategy === strategy.id }"
|
||||
@click="selectedStrategy = strategy.id"
|
||||
>
|
||||
<div class="strategy-header">
|
||||
<div class="strategy-name">{{ strategy.name }}</div>
|
||||
<div class="strategy-stars">
|
||||
<span v-for="n in strategy.stars" :key="n" class="star">⭐</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="strategy-example">{{ strategy.example }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="strategy-detail" v-if="currentStrategy">
|
||||
<div class="detail-header">
|
||||
<div class="detail-title">{{ currentStrategy.name }}</div>
|
||||
<div class="detail-recommendation" :class="currentStrategy.level">
|
||||
{{ currentStrategy.level === 'high' ? '强烈推荐' : currentStrategy.level === 'medium' ? '可以使用' : '不推荐' }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-sections">
|
||||
<div class="detail-section">
|
||||
<h4>✅ 优点</h4>
|
||||
<ul>
|
||||
<li v-for="(pro, idx) in currentStrategy.pros" :key="idx">{{ pro }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="detail-section">
|
||||
<h4>❌ 缺点</h4>
|
||||
<ul>
|
||||
<li v-for="(con, idx) in currentStrategy.cons" :key="idx">{{ con }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-section example">
|
||||
<h4>💻 实现示例</h4>
|
||||
<div class="code-box">
|
||||
<div class="code-header">Request</div>
|
||||
<pre><code>{{ currentStrategy.codeExample.request }}</code></pre>
|
||||
<div class="code-header">Response Headers</div>
|
||||
<pre><code>{{ currentStrategy.codeExample.response }}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-section tips">
|
||||
<h4>💡 最佳实践</h4>
|
||||
<ul>
|
||||
<li v-for="(tip, idx) in currentStrategy.tips" :key="idx">{{ tip }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
const title = ref('版本策略演示')
|
||||
const description = ref('展示API版本控制的策略,包括URL版本、Header版本、内容协商等方式')
|
||||
const strategies = [
|
||||
{
|
||||
id: 'url-path',
|
||||
name: 'URL Path 版本',
|
||||
example: '/v1/users',
|
||||
stars: 4,
|
||||
level: 'high',
|
||||
pros: [
|
||||
'最直观,一目了然看到版本号',
|
||||
'易于缓存和控制权限',
|
||||
'文档清晰,社区主流做法',
|
||||
'支持不同版本的并行部署'
|
||||
],
|
||||
cons: [
|
||||
'URL 会变化,不符合 REST 资源唯一性',
|
||||
'需要配置路由规则'
|
||||
],
|
||||
codeExample: {
|
||||
request: `GET /v1/users HTTP/1.1
|
||||
Host: api.example.com`,
|
||||
response: `HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
X-API-Version: v1`
|
||||
},
|
||||
tips: [
|
||||
'版本号放在路径开头:`/v1/users`',
|
||||
'使用语义化版本号(Semantic Versioning)',
|
||||
'废弃版本返回 Sunset 头部',
|
||||
'客户端升级提示可通过响应头提示'
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'header',
|
||||
name: 'Header 版本',
|
||||
example: 'API-Version: v1',
|
||||
stars: 2,
|
||||
level: 'medium',
|
||||
pros: [
|
||||
'URL 保持简洁不变',
|
||||
'版本控制不影响路由'
|
||||
],
|
||||
cons: [
|
||||
'不直观,需要在工具里配置 Header',
|
||||
'缓存策略复杂',
|
||||
'文档不够清晰',
|
||||
'调试不便'
|
||||
],
|
||||
codeExample: {
|
||||
request: `GET /users HTTP/1.1
|
||||
Host: api.example.com
|
||||
API-Version: v1`,
|
||||
response: `HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
X-API-Version: v1`
|
||||
},
|
||||
tips: [
|
||||
'使用自定义 Header:`API-Version` 或 `Accept`',
|
||||
'需在 API Gateway 中统一处理',
|
||||
'适合内部系统或对 API 规范要求高的场景'
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'content-negotiation',
|
||||
name: '内容协商',
|
||||
example: 'Accept: application/vnd.api.v1+json',
|
||||
stars: 2,
|
||||
level: 'medium',
|
||||
pros: [
|
||||
'符合 HTTP 标准',
|
||||
'URL 完全不变'
|
||||
],
|
||||
cons: [
|
||||
'复杂,理解成本高',
|
||||
'开发者容易用错',
|
||||
'缓存和代理支持不佳'
|
||||
],
|
||||
codeExample: {
|
||||
request: `GET /users HTTP/1.1
|
||||
Host: api.example.com
|
||||
Accept: application/vnd.api.v1+json`,
|
||||
response: `HTTP/1.1 200 OK
|
||||
Content-Type: application/vnd.api.v1+json`
|
||||
},
|
||||
tips: [
|
||||
'使用 Vendor MIME 类型:`application/vnd.{company}.{resource}.v{version}+json`',
|
||||
'需要 API Gateway 或框架支持内容协商',
|
||||
'GitHub API 使用此策略'
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'query-param',
|
||||
name: 'Query 参数',
|
||||
example: '/users?version=v1',
|
||||
stars: 1,
|
||||
level: 'low',
|
||||
pros: [
|
||||
'实现简单'
|
||||
],
|
||||
cons: [
|
||||
'不专业,容易忽视',
|
||||
'缓存麻烦(不同参数视为不同资源)',
|
||||
'URL 混乱'
|
||||
],
|
||||
codeExample: {
|
||||
request: `GET /users?version=v1 HTTP/1.1
|
||||
Host: api.example.com`,
|
||||
response: `HTTP/1.1 200 OK
|
||||
Content-Type: application/json`
|
||||
},
|
||||
tips: [
|
||||
'仅用于快速原型或内部工具',
|
||||
'生产环境不推荐使用'
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const selectedStrategy = ref('url-path')
|
||||
const currentStrategy = computed(() =>
|
||||
strategies.find(s => s.id === selectedStrategy.value)
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.demo-container {
|
||||
.demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
margin: 24px 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
margin-bottom: 20px;
|
||||
.header {
|
||||
padding: 16px 20px;
|
||||
background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.demo-header h4 {
|
||||
margin: 0 0 8px 0;
|
||||
.icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.strategies {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.strategy-card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.strategy-card:hover {
|
||||
border-color: rgba(var(--vp-c-brand-rgb), 0.5);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.strategy-card.active {
|
||||
border-color: var(--vp-c-brand);
|
||||
box-shadow: 0 0 0 3px rgba(var(--vp-c-brand-rgb), 0.15);
|
||||
}
|
||||
|
||||
.strategy-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.strategy-name {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.hint {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
color: var(--vp-c-text-2);
|
||||
.strategy-stars {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.demo-content {
|
||||
.star {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.strategy-example {
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
color: var(--vp-c-text-2);
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 6px 10px;
|
||||
border-radius: 4px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.strategy-detail {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.detail-header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.detail-title {
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.detail-recommendation {
|
||||
padding: 4px 12px;
|
||||
border-radius: 999px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.detail-recommendation.high {
|
||||
background: #dcfce7;
|
||||
color: #16a34a;
|
||||
}
|
||||
|
||||
.detail-recommendation.medium {
|
||||
background: #fef3c7;
|
||||
color: #d97706;
|
||||
}
|
||||
|
||||
.detail-recommendation.low {
|
||||
background: #fee2e2;
|
||||
color: #dc2626;
|
||||
}
|
||||
|
||||
.detail-sections {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.detail-section {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.detail-section h4 {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
|
||||
.detail-section ul {
|
||||
margin: 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.detail-section li {
|
||||
font-size: 13px;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.6;
|
||||
margin: 6px 0;
|
||||
}
|
||||
|
||||
.detail-section.example {
|
||||
grid-column: 1 / -1;
|
||||
padding: 16px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
}
|
||||
|
||||
.code-box {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.code-header {
|
||||
padding: 8px 12px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.code-box pre {
|
||||
margin: 0;
|
||||
padding: 12px;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.code-box code {
|
||||
font-family: monospace;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.detail-section.tips {
|
||||
background: #eff6ff;
|
||||
border-left: 3px solid #3b82f6;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.strategies {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.detail-sections {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -250,7 +250,7 @@ function sendRequest() {
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.2s;
|
||||
@@ -303,7 +303,7 @@ function sendRequest() {
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
overflow-x: auto;
|
||||
overflow-y: auto;
|
||||
|
||||
max-height: 200px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ const isHuman = ref(false)
|
||||
|
||||
.api-doc {
|
||||
background: #1e293b;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
color: #e2e8f0;
|
||||
font-family: monospace;
|
||||
|
||||
@@ -237,7 +237,7 @@
|
||||
.method-examples {
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
@@ -249,7 +249,7 @@
|
||||
|
||||
.method-tip {
|
||||
padding: 10px 12px;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
@@ -339,7 +339,7 @@ tr:last-child td {
|
||||
.tips {
|
||||
background: var(--vp-c-bg);
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
color: var(--vp-c-text-2);
|
||||
|
||||
@@ -345,7 +345,7 @@ function sendRequest() {
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
margin-top: 8px;
|
||||
@@ -415,7 +415,7 @@ function sendRequest() {
|
||||
padding: 12px;
|
||||
margin-bottom: 12px;
|
||||
overflow-x: auto;
|
||||
overflow-y: auto;
|
||||
|
||||
max-height: 180px;
|
||||
}
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ function callApi() {
|
||||
.response-card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
animation: slideUp 0.3s ease-out;
|
||||
}
|
||||
|
||||
@@ -349,7 +349,7 @@ async function runDemo() {
|
||||
background: #1e293b;
|
||||
color: #e2e8f0;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-family: 'Monaco', 'Menlo', monospace;
|
||||
font-size: 12px;
|
||||
line-height: 1.6;
|
||||
@@ -371,7 +371,7 @@ async function runDemo() {
|
||||
.summary {
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
@@ -443,7 +443,7 @@ async function runDemo() {
|
||||
.result-body {
|
||||
background: #f0fdf4;
|
||||
border: 2px solid #86efac;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
|
||||
@@ -163,7 +163,7 @@ function send() {
|
||||
padding: 10px 20px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
@@ -183,7 +183,7 @@ function send() {
|
||||
|
||||
.result-box {
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
@@ -378,7 +378,7 @@ onMounted(() => {
|
||||
|
||||
.flow-section {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
@@ -418,7 +418,7 @@ onMounted(() => {
|
||||
padding: 16px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -458,14 +458,14 @@ onMounted(() => {
|
||||
padding: 12px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px dashed var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.audio-preview {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
@@ -479,7 +479,7 @@ onMounted(() => {
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
@@ -512,7 +512,7 @@ onMounted(() => {
|
||||
|
||||
.result-box {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
@@ -540,7 +540,7 @@ textarea {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
font-size: 14px;
|
||||
resize: vertical;
|
||||
@@ -654,7 +654,7 @@ textarea {
|
||||
|
||||
.comparison-section {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
@@ -673,7 +673,7 @@ textarea {
|
||||
|
||||
.comp-card {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -705,7 +705,7 @@ textarea {
|
||||
|
||||
.pipeline-comparison {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
@@ -724,7 +724,7 @@ textarea {
|
||||
|
||||
.pipeline {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
@@ -761,7 +761,7 @@ textarea {
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
background: var(--vp-c-bg-mute);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
@@ -462,7 +462,7 @@ onUnmounted(() => {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
resize: vertical;
|
||||
background: var(--vp-c-bg);
|
||||
@@ -504,7 +504,7 @@ onUnmounted(() => {
|
||||
.action-btn {
|
||||
padding: 12px 24px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-mute);
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
@@ -557,7 +557,7 @@ onUnmounted(() => {
|
||||
width: 100%;
|
||||
padding: 16px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.result-label {
|
||||
@@ -592,7 +592,7 @@ onUnmounted(() => {
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
opacity: 0.5;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
@@ -692,7 +692,7 @@ onUnmounted(() => {
|
||||
.embedding-viz {
|
||||
padding: 16px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.viz-title {
|
||||
@@ -720,7 +720,7 @@ onUnmounted(() => {
|
||||
.waveform-container {
|
||||
padding: 16px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.waveform-container canvas {
|
||||
@@ -777,7 +777,7 @@ onUnmounted(() => {
|
||||
gap: 8px;
|
||||
padding: 12px;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
|
||||
@@ -334,7 +334,7 @@ onMounted(() => {
|
||||
|
||||
<style scoped>
|
||||
.audio-tokenization-demo {
|
||||
margin: 1rem 0;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
@@ -352,7 +352,7 @@ onMounted(() => {
|
||||
|
||||
.codec-flow {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
@@ -385,7 +385,7 @@ onMounted(() => {
|
||||
|
||||
.step-visual {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 12px;
|
||||
margin-bottom: 8px;
|
||||
min-height: 80px;
|
||||
@@ -484,7 +484,7 @@ onMounted(() => {
|
||||
|
||||
.bitrate-comparison {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
@@ -502,7 +502,7 @@ onMounted(() => {
|
||||
|
||||
.bitrate-card {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
@@ -549,7 +549,7 @@ onMounted(() => {
|
||||
|
||||
.token-visualization {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
@@ -561,7 +561,7 @@ onMounted(() => {
|
||||
|
||||
.token-display {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
@@ -619,7 +619,7 @@ onMounted(() => {
|
||||
|
||||
.applications {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
@@ -637,7 +637,7 @@ onMounted(() => {
|
||||
|
||||
.app-card {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
<style scoped>
|
||||
.waveform-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
margin: 20px 0;
|
||||
|
||||
@@ -319,7 +319,7 @@ watch(selectedEmotion, drawEmotionEmbedding)
|
||||
|
||||
<style scoped>
|
||||
.emotion-control-demo {
|
||||
margin: 1rem 0;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
@@ -337,7 +337,7 @@ watch(selectedEmotion, drawEmotionEmbedding)
|
||||
|
||||
.emotion-selector {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ watch(selectedEmotion, drawEmotionEmbedding)
|
||||
|
||||
.emotion-card {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
@@ -389,7 +389,7 @@ watch(selectedEmotion, drawEmotionEmbedding)
|
||||
|
||||
.emotion-embedding {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
@@ -404,7 +404,7 @@ watch(selectedEmotion, drawEmotionEmbedding)
|
||||
height: auto;
|
||||
max-height: 200px;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.embedding-legend {
|
||||
@@ -430,7 +430,7 @@ watch(selectedEmotion, drawEmotionEmbedding)
|
||||
|
||||
.parameter-controls {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
@@ -447,7 +447,7 @@ watch(selectedEmotion, drawEmotionEmbedding)
|
||||
|
||||
.control-item {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
@@ -468,7 +468,7 @@ watch(selectedEmotion, drawEmotionEmbedding)
|
||||
|
||||
.preview-section {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
@@ -488,7 +488,7 @@ watch(selectedEmotion, drawEmotionEmbedding)
|
||||
|
||||
.tech-explanation {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
|
||||
@@ -342,7 +342,7 @@ watch([selectedType, fftSize, melBins], updateVisualization)
|
||||
margin-bottom: 24px;
|
||||
padding: 16px;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.audio-types {
|
||||
@@ -405,7 +405,7 @@ watch([selectedType, fftSize, melBins], updateVisualization)
|
||||
|
||||
.visualization {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
@@ -416,7 +416,7 @@ watch([selectedType, fftSize, melBins], updateVisualization)
|
||||
|
||||
.viz-section.highlight {
|
||||
border: 2px solid #67c23a;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
@@ -486,7 +486,7 @@ watch([selectedType, fftSize, melBins], updateVisualization)
|
||||
|
||||
.explanation {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
@@ -518,7 +518,7 @@ watch([selectedType, fftSize, melBins], updateVisualization)
|
||||
height: 80px;
|
||||
padding: 10px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.freq-bars .bar {
|
||||
@@ -545,7 +545,7 @@ watch([selectedType, fftSize, melBins], updateVisualization)
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
background: var(--vp-c-bg-mute);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
@@ -301,7 +301,7 @@ watch([selectedArch, activeStage], drawVisualization)
|
||||
.arch-btn {
|
||||
padding: 12px 20px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
@@ -344,7 +344,7 @@ watch([selectedArch, activeStage], drawVisualization)
|
||||
flex-wrap: wrap;
|
||||
padding: 20px;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
@@ -358,7 +358,7 @@ watch([selectedArch, activeStage], drawVisualization)
|
||||
.stage-content {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 12px 16px;
|
||||
text-align: center;
|
||||
transition: all 0.2s;
|
||||
@@ -406,7 +406,7 @@ watch([selectedArch, activeStage], drawVisualization)
|
||||
|
||||
.stage-detail {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
@@ -433,7 +433,7 @@ watch([selectedArch, activeStage], drawVisualization)
|
||||
|
||||
.detail-canvas {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
@@ -459,7 +459,7 @@ watch([selectedArch, activeStage], drawVisualization)
|
||||
|
||||
.comparison-table {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
@@ -475,7 +475,7 @@ watch([selectedArch, activeStage], drawVisualization)
|
||||
flex-direction: column;
|
||||
gap: 1px;
|
||||
background: var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -510,7 +510,7 @@ watch([selectedArch, activeStage], drawVisualization)
|
||||
|
||||
.models-section {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
@@ -529,7 +529,7 @@ watch([selectedArch, activeStage], drawVisualization)
|
||||
|
||||
.model-card {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
border: 2px solid transparent;
|
||||
@@ -567,7 +567,7 @@ watch([selectedArch, activeStage], drawVisualization)
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
background: var(--vp-c-bg-mute);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
@@ -369,7 +369,7 @@ onMounted(() => {
|
||||
|
||||
.demo-area {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
@@ -412,7 +412,7 @@ onMounted(() => {
|
||||
.audio-card {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
@@ -472,7 +472,7 @@ onMounted(() => {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: 2px dashed var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
cursor: pointer;
|
||||
color: var(--vp-c-text-2);
|
||||
@@ -499,7 +499,7 @@ onMounted(() => {
|
||||
gap: 8px;
|
||||
padding: 12px 16px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
opacity: 0.5;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
@@ -525,7 +525,7 @@ onMounted(() => {
|
||||
|
||||
.feature-viz {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -545,7 +545,7 @@ onMounted(() => {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
font-size: 14px;
|
||||
resize: vertical;
|
||||
@@ -558,7 +558,7 @@ onMounted(() => {
|
||||
background: linear-gradient(120deg, #409eff, #67c23a);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
@@ -595,7 +595,7 @@ onMounted(() => {
|
||||
margin-top: 16px;
|
||||
padding: 16px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
border: 2px solid #67c23a;
|
||||
}
|
||||
|
||||
@@ -653,7 +653,7 @@ onMounted(() => {
|
||||
|
||||
.tips-section {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
@@ -675,7 +675,7 @@ onMounted(() => {
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.tip-icon {
|
||||
@@ -699,7 +699,7 @@ onMounted(() => {
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
background: var(--vp-c-bg-mute);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
@@ -131,9 +131,9 @@ const active = computed(
|
||||
.auth-basics-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 1.5rem;
|
||||
margin: 1rem 0;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -197,8 +197,8 @@ const active = computed(
|
||||
.card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
@@ -233,7 +233,7 @@ const active = computed(
|
||||
.box {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-alt);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -127,9 +127,9 @@ const active = computed(
|
||||
.auth-evolution-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 1.5rem;
|
||||
margin: 1rem 0;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -151,13 +151,13 @@ const active = computed(
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 0.75rem;
|
||||
margin: 1rem 0;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.stage {
|
||||
text-align: left;
|
||||
padding: 0.75rem;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg);
|
||||
cursor: pointer;
|
||||
@@ -193,8 +193,8 @@ const active = computed(
|
||||
.card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
@@ -219,7 +219,7 @@ const active = computed(
|
||||
.box {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-alt);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -377,9 +377,9 @@ const resetDemo = () => {
|
||||
.auth-interactive-login {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 1.5rem;
|
||||
margin: 1rem 0;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -421,7 +421,7 @@ const resetDemo = () => {
|
||||
.mode-btn {
|
||||
padding: 0.6rem 1.2rem;
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg);
|
||||
cursor: pointer;
|
||||
font-size: 0.9rem;
|
||||
@@ -616,8 +616,8 @@ const resetDemo = () => {
|
||||
|
||||
.flow-stage {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
animation: slideIn 0.4s ease;
|
||||
}
|
||||
@@ -827,7 +827,7 @@ const resetDemo = () => {
|
||||
.reset-btn {
|
||||
padding: 0.75rem 2rem;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: #64748b;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
|
||||
@@ -149,9 +149,9 @@ const decisionLog = computed(() => {
|
||||
.authn-authz-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 1.5rem;
|
||||
margin: 1rem 0;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -179,8 +179,8 @@ const decisionLog = computed(() => {
|
||||
.card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
@@ -229,7 +229,7 @@ const decisionLog = computed(() => {
|
||||
.result {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-alt);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
@@ -153,9 +153,9 @@ const reset = () => {
|
||||
.csrf-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 1.5rem;
|
||||
margin: 1rem 0;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -218,8 +218,8 @@ const reset = () => {
|
||||
.card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
@@ -237,7 +237,7 @@ const reset = () => {
|
||||
margin-top: 0.75rem;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-alt);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
@@ -272,7 +272,7 @@ const reset = () => {
|
||||
margin-top: 0.75rem;
|
||||
border: 1px solid rgba(var(--vp-c-brand-rgb), 0.18);
|
||||
background: rgba(var(--vp-c-brand-rgb), 0.06);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -174,9 +174,9 @@ const copy = async (text) => {
|
||||
.jwt-workflow-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 1.5rem;
|
||||
margin: 1rem 0;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -239,8 +239,8 @@ const copy = async (text) => {
|
||||
.card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
@@ -277,7 +277,7 @@ const copy = async (text) => {
|
||||
min-width: 220px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-alt);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
opacity: 0.6;
|
||||
}
|
||||
@@ -308,7 +308,7 @@ const copy = async (text) => {
|
||||
margin-top: 0.75rem;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-alt);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
@@ -339,7 +339,7 @@ const copy = async (text) => {
|
||||
margin-top: 0.75rem;
|
||||
border: 1px solid rgba(var(--vp-c-brand-rgb), 0.18);
|
||||
background: rgba(var(--vp-c-brand-rgb), 0.06);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -200,9 +200,9 @@ const copy = async (text) => {
|
||||
.oauth2-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 1.5rem;
|
||||
margin: 1rem 0;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -265,8 +265,8 @@ const copy = async (text) => {
|
||||
.card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
@@ -300,7 +300,7 @@ const copy = async (text) => {
|
||||
margin-top: 0.75rem;
|
||||
border: 1px solid rgba(var(--vp-c-brand-rgb), 0.18);
|
||||
background: rgba(var(--vp-c-brand-rgb), 0.06);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -227,9 +227,9 @@ onMounted(() => {
|
||||
.password-hashing-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 1.5rem;
|
||||
margin: 1rem 0;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -258,8 +258,8 @@ onMounted(() => {
|
||||
.card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
@@ -345,7 +345,7 @@ onMounted(() => {
|
||||
.mono-box {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-alt);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
overflow-x: auto;
|
||||
}
|
||||
@@ -366,7 +366,7 @@ onMounted(() => {
|
||||
margin-top: 0.75rem;
|
||||
border: 1px solid rgba(var(--vp-c-brand-rgb), 0.18);
|
||||
background: rgba(var(--vp-c-brand-rgb), 0.06);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -193,9 +193,9 @@ Set-Cookie: session_id=; Max-Age=0`
|
||||
.session-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 1.5rem;
|
||||
margin: 1rem 0;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -258,8 +258,8 @@ Set-Cookie: session_id=; Max-Age=0`
|
||||
.card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
@@ -271,7 +271,7 @@ Set-Cookie: session_id=; Max-Age=0`
|
||||
.box {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-alt);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
@@ -339,7 +339,7 @@ Set-Cookie: session_id=; Max-Age=0`
|
||||
margin-top: 0.75rem;
|
||||
border: 1px solid rgba(var(--vp-c-brand-rgb), 0.18);
|
||||
background: rgba(var(--vp-c-brand-rgb), 0.06);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
|
||||
@@ -194,9 +194,9 @@ const recommendation = computed(() => {
|
||||
.session-vs-jwt-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 1.5rem;
|
||||
margin: 1rem 0;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -224,8 +224,8 @@ const recommendation = computed(() => {
|
||||
.card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
@@ -294,7 +294,7 @@ const recommendation = computed(() => {
|
||||
.box {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg-alt);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
||||
+85
-52
@@ -1,8 +1,9 @@
|
||||
<template>
|
||||
<div class="architecture-comparison-demo">
|
||||
<div class="demo-header">
|
||||
<h4>🏗️ 架构演进对比</h4>
|
||||
<p>四个时代的核心架构特征对比</p>
|
||||
<span class="icon">🏗️</span>
|
||||
<span class="title">架构演进对比</span>
|
||||
<span class="subtitle">四个时代的核心架构特征</span>
|
||||
</div>
|
||||
|
||||
<div class="comparison-grid">
|
||||
@@ -50,6 +51,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<span class="icon">💡</span>
|
||||
<strong>核心思想:</strong>架构演进是为了解决上一个时代的痛点,但也带来了新的复杂度。
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -106,40 +112,49 @@ const currentEra = computed(() => {
|
||||
<style scoped>
|
||||
.architecture-comparison-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1.5rem;
|
||||
margin: 1rem 0;
|
||||
padding: 0.75rem;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
margin-bottom: 1.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 0.5rem;
|
||||
padding-bottom: 0.4rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.demo-header h4 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
font-size: 1.1rem;
|
||||
.demo-header .icon {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.demo-header .title {
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.demo-header p {
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
.demo-header .subtitle {
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.75rem;
|
||||
margin-left: 0.4rem;
|
||||
}
|
||||
|
||||
.comparison-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1.5rem;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.era-card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 4px;
|
||||
padding: 0.5rem;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
@@ -147,96 +162,95 @@ const currentEra = computed(() => {
|
||||
|
||||
.era-card:hover {
|
||||
border-color: var(--vp-c-brand);
|
||||
transform: translateY(-2px);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.era-card.active {
|
||||
border-color: var(--vp-c-brand);
|
||||
background: rgba(102, 126, 234, 0.1);
|
||||
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.2);
|
||||
background: var(--vp-c-brand-soft);
|
||||
}
|
||||
|
||||
.era-icon {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 1rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.era-name {
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
font-size: 0.75rem;
|
||||
color: var(--vp-c-text-1);
|
||||
margin-bottom: 0.25rem;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.era-year {
|
||||
font-size: 0.75rem;
|
||||
font-size: 0.6rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-bottom: 0.5rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.era-tag {
|
||||
display: inline-block;
|
||||
padding: 0.15rem 0.5rem;
|
||||
padding: 0.1rem 0.3rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 10px;
|
||||
font-size: 0.7rem;
|
||||
border-radius: 6px;
|
||||
font-size: 0.55rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.detail-panel {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
border-radius: 4px;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.detail-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1.5rem;
|
||||
padding-bottom: 1rem;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 0.5rem;
|
||||
padding-bottom: 0.4rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.detail-icon {
|
||||
font-size: 1.5rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.detail-header h5 {
|
||||
margin: 0;
|
||||
font-size: 1.1rem;
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.detail-content {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 1.5rem;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.feature-section {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 6px;
|
||||
padding: 1rem;
|
||||
border-radius: 4px;
|
||||
padding: 0.4rem;
|
||||
}
|
||||
|
||||
.feature-section h6 {
|
||||
margin: 0 0 0.75rem 0;
|
||||
font-size: 0.85rem;
|
||||
margin: 0 0 0.3rem 0;
|
||||
font-size: 0.7rem;
|
||||
color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.feature-section ul {
|
||||
margin: 0;
|
||||
padding-left: 1.25rem;
|
||||
font-size: 0.85rem;
|
||||
padding-left: 0.75rem;
|
||||
font-size: 0.65rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.feature-section li {
|
||||
margin-bottom: 0.4rem;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 0.15rem;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.feature-section li:last-child {
|
||||
@@ -246,31 +260,50 @@ const currentEra = computed(() => {
|
||||
.tech-stack {
|
||||
grid-column: 1 / -1;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 6px;
|
||||
padding: 1rem;
|
||||
border-radius: 4px;
|
||||
padding: 0.4rem;
|
||||
}
|
||||
|
||||
.tech-stack h6 {
|
||||
margin: 0 0 0.75rem 0;
|
||||
font-size: 0.85rem;
|
||||
margin: 0 0 0.3rem 0;
|
||||
font-size: 0.7rem;
|
||||
color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.tech-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.tech-tag {
|
||||
padding: 0.25rem 0.75rem;
|
||||
padding: 0.15rem 0.4rem;
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 4px;
|
||||
font-size: 0.8rem;
|
||||
border-radius: 3px;
|
||||
font-size: 0.6rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.info-box {
|
||||
background: var(--vp-c-bg-alt);
|
||||
padding: 0.5rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-top: 0.5rem;
|
||||
display: flex;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
|
||||
.info-box .icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.info-box strong {
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.comparison-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
|
||||
+3
-3
@@ -433,8 +433,8 @@ const stages = [
|
||||
.server-box {
|
||||
background: #cbd5e1;
|
||||
border: 2px solid #94a3b8;
|
||||
padding: 1rem;
|
||||
border-radius: 8px;
|
||||
padding: 0.75rem;
|
||||
border-radius: 6px;
|
||||
text-align: center;
|
||||
}
|
||||
.file-system {
|
||||
@@ -464,7 +464,7 @@ const stages = [
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 4px;
|
||||
margin: 1rem 0;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
.module {
|
||||
background: #bfdbfe;
|
||||
|
||||
+1
-1
@@ -367,7 +367,7 @@ const currentStageData = computed(() => stageData[currentStage.value])
|
||||
gap: 10px;
|
||||
padding: 10px 12px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
|
||||
+83
-49
@@ -1,8 +1,9 @@
|
||||
<template>
|
||||
<div class="container-docker-demo">
|
||||
<div class="demo-header">
|
||||
<h4>🐳 Docker 容器化演示</h4>
|
||||
<p>理解容器如何让应用"一次打包,到处运行"</p>
|
||||
<span class="icon">🐳</span>
|
||||
<span class="title">Docker 容器化演示</span>
|
||||
<span class="subtitle">理解容器如何让应用"一次打包,到处运行"</span>
|
||||
</div>
|
||||
|
||||
<div class="docker-visualization">
|
||||
@@ -46,6 +47,11 @@
|
||||
<div class="benefit-desc">{{ benefit.desc }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<span class="icon">💡</span>
|
||||
<strong>核心思想:</strong>容器化让应用"一次构建,到处运行",解决了环境一致性和快速部署的问题。
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -67,41 +73,50 @@ const benefits = [
|
||||
<style scoped>
|
||||
.container-docker-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1.5rem;
|
||||
margin: 1rem 0;
|
||||
padding: 0.75rem;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
margin-bottom: 1.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 0.5rem;
|
||||
padding-bottom: 0.4rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.demo-header h4 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
font-size: 1.1rem;
|
||||
.demo-header .icon {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.demo-header .title {
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.demo-header p {
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
.demo-header .subtitle {
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.75rem;
|
||||
margin-left: 0.4rem;
|
||||
}
|
||||
|
||||
.docker-visualization {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.layer {
|
||||
flex: 1;
|
||||
background: var(--vp-c-bg);
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 4px;
|
||||
padding: 0.5rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
@@ -112,9 +127,9 @@ const benefits = [
|
||||
}
|
||||
|
||||
.layer h5 {
|
||||
margin: 0 0 1rem 0;
|
||||
margin: 0 0 0.5rem 0;
|
||||
text-align: center;
|
||||
font-size: 0.95rem;
|
||||
font-size: 0.75rem;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
@@ -122,14 +137,14 @@ const benefits = [
|
||||
.docker-stack {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.layer-item {
|
||||
padding: 0.6rem;
|
||||
border-radius: 4px;
|
||||
padding: 0.3rem;
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
font-size: 0.8rem;
|
||||
font-size: 0.65rem;
|
||||
}
|
||||
|
||||
.layer-item.app {
|
||||
@@ -164,47 +179,47 @@ const benefits = [
|
||||
.containers {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 0.5rem;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.container-box {
|
||||
background: rgba(102, 126, 234, 0.1);
|
||||
border: 1px solid rgba(102, 126, 234, 0.3);
|
||||
border-radius: 6px;
|
||||
padding: 0.5rem;
|
||||
border-radius: 4px;
|
||||
padding: 0.25rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.container-app {
|
||||
font-weight: 600;
|
||||
font-size: 0.8rem;
|
||||
font-size: 0.65rem;
|
||||
color: var(--vp-c-brand);
|
||||
margin-bottom: 0.2rem;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.container-deps {
|
||||
font-size: 0.7rem;
|
||||
font-size: 0.55rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.docker-engine {
|
||||
padding: 0.6rem;
|
||||
padding: 0.3rem;
|
||||
background: rgba(16, 185, 129, 0.1);
|
||||
border: 1px solid rgba(16, 185, 129, 0.3);
|
||||
border-radius: 4px;
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
font-size: 0.8rem;
|
||||
font-size: 0.65rem;
|
||||
font-weight: 600;
|
||||
color: #059669;
|
||||
}
|
||||
|
||||
.host-os,
|
||||
.hardware {
|
||||
padding: 0.6rem;
|
||||
padding: 0.3rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 4px;
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
font-size: 0.8rem;
|
||||
font-size: 0.65rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
@@ -213,45 +228,45 @@ const benefits = [
|
||||
align-items: center;
|
||||
font-weight: 700;
|
||||
color: var(--vp-c-text-3);
|
||||
font-size: 0.9rem;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.benefits-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 1rem;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.benefit-card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 4px;
|
||||
padding: 0.5rem;
|
||||
text-align: center;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.benefit-card:hover {
|
||||
border-color: var(--vp-c-brand);
|
||||
transform: translateY(-2px);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.benefit-icon {
|
||||
font-size: 2rem;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 1.25rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.benefit-title {
|
||||
font-weight: 600;
|
||||
font-size: 0.95rem;
|
||||
font-size: 0.75rem;
|
||||
color: var(--vp-c-text-1);
|
||||
margin-bottom: 0.25rem;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.benefit-desc {
|
||||
font-size: 0.8rem;
|
||||
font-size: 0.65rem;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.4;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
@@ -261,11 +276,30 @@ const benefits = [
|
||||
|
||||
.vs-divider {
|
||||
justify-content: center;
|
||||
padding: 0.5rem 0;
|
||||
padding: 0.25rem 0;
|
||||
}
|
||||
|
||||
.benefits-grid {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
.info-box {
|
||||
background: var(--vp-c-bg-alt);
|
||||
padding: 0.5rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-top: 0.5rem;
|
||||
display: flex;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
|
||||
.info-box .icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.info-box strong {
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -96,10 +96,10 @@ const steps = [
|
||||
<style scoped>
|
||||
.deployment-flow-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
padding: 0.75rem;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
@@ -185,7 +185,7 @@ const steps = [
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
padding: 1rem;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.step-detail h5 {
|
||||
|
||||
+103
-68
@@ -1,8 +1,9 @@
|
||||
<template>
|
||||
<div class="evolution-intro-demo">
|
||||
<div class="intro-header">
|
||||
<h3>后端架构进化之旅</h3>
|
||||
<p>用一个餐厅的成长历程,理解后端架构的 30 年变迁</p>
|
||||
<div class="demo-header">
|
||||
<span class="icon">🏗️</span>
|
||||
<span class="title">后端架构进化之旅</span>
|
||||
<span class="subtitle">用餐厅比喻理解 30 年架构演进</span>
|
||||
</div>
|
||||
|
||||
<div class="timeline-cards">
|
||||
@@ -20,7 +21,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stage-detail">
|
||||
<div class="stage-detail" v-if="currentStage !== null">
|
||||
<Transition name="fade" mode="out-in">
|
||||
<div :key="currentStage" class="detail-panel">
|
||||
<div class="detail-header">
|
||||
@@ -46,6 +47,11 @@
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<span class="icon">💡</span>
|
||||
<strong>核心思想:</strong>架构演进是为了解决上一个时代的痛点,但也带来了新的复杂度。没有最好的架构,只有最适合的架构。
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -116,148 +122,177 @@ const stages = [
|
||||
|
||||
<style scoped>
|
||||
.evolution-intro-demo {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border-radius: 16px;
|
||||
padding: 32px;
|
||||
color: #fff;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 0.75rem;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.intro-header {
|
||||
text-align: center;
|
||||
margin-bottom: 32px;
|
||||
.demo-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 0.5rem;
|
||||
padding-bottom: 0.4rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.intro-header h3 {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
margin: 0 0 8px 0;
|
||||
.demo-header .icon {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.intro-header p {
|
||||
font-size: 14px;
|
||||
opacity: 0.9;
|
||||
margin: 0;
|
||||
.demo-header .title {
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.demo-header .subtitle {
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.75rem;
|
||||
margin-left: 0.4rem;
|
||||
}
|
||||
|
||||
.timeline-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 12px;
|
||||
margin-bottom: 24px;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.stage-card {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: 2px solid transparent;
|
||||
border-radius: 12px;
|
||||
padding: 16px 12px;
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
padding: 0.75rem 0.5rem;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.stage-card:hover {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
transform: translateY(-2px);
|
||||
border-color: var(--vp-c-brand);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.stage-card.active {
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-color: rgba(255, 255, 255, 0.5);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
|
||||
border-color: var(--vp-c-brand);
|
||||
background: var(--vp-c-brand-soft);
|
||||
}
|
||||
|
||||
.stage-era {
|
||||
font-size: 11px;
|
||||
opacity: 0.7;
|
||||
margin-bottom: 4px;
|
||||
font-size: 0.6rem;
|
||||
color: var(--vp-c-text-3);
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.stage-icon {
|
||||
font-size: 32px;
|
||||
margin-bottom: 8px;
|
||||
font-size: 1rem;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
.stage-name {
|
||||
font-size: 14px;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 2px;
|
||||
color: var(--vp-c-text-1);
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.stage-arch {
|
||||
font-size: 11px;
|
||||
opacity: 0.7;
|
||||
font-size: 0.55rem;
|
||||
color: var(--vp-c-text-3);
|
||||
}
|
||||
|
||||
.stage-detail {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 4px;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.detail-panel {
|
||||
animation: fadeIn 0.4s ease;
|
||||
animation: fadeIn 0.3s ease;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(10px); }
|
||||
from { opacity: 0; transform: translateY(5px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
.detail-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 0.5rem;
|
||||
padding-bottom: 0.4rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.detail-icon {
|
||||
font-size: 32px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.detail-header h4 {
|
||||
font-size: 20px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.detail-content {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.detail-section h5 {
|
||||
font-size: 14px;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
margin: 0 0 8px 0;
|
||||
color: #ffd700;
|
||||
margin: 0 0 0.3rem 0;
|
||||
color: var(--vp-c-brand);
|
||||
}
|
||||
|
||||
.detail-section p {
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
opacity: 0.9;
|
||||
font-size: 0.65rem;
|
||||
line-height: 1.4;
|
||||
margin: 0 0 0.3rem 0;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.detail-section ul {
|
||||
margin: 0;
|
||||
padding-left: 18px;
|
||||
padding-left: 0.75rem;
|
||||
}
|
||||
|
||||
.detail-section li {
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
margin-bottom: 4px;
|
||||
opacity: 0.9;
|
||||
font-size: 0.6rem;
|
||||
line-height: 1.4;
|
||||
margin-bottom: 0.25rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.info-box {
|
||||
background: var(--vp-c-bg-alt);
|
||||
padding: 0.75rem;
|
||||
border-radius: 6px;
|
||||
font-size: 0.85rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-top: 1rem;
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.info-box .icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.info-box strong {
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: all 0.4s ease;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from {
|
||||
@@ -275,8 +310,8 @@ const stages = [
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.stage-detail {
|
||||
padding: 16px;
|
||||
.detail-content {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -240,10 +240,10 @@ const resetCluster = () => {
|
||||
<style scoped>
|
||||
.container-docker-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1.5rem;
|
||||
margin: 1rem 0;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
@@ -273,8 +273,8 @@ const resetCluster = () => {
|
||||
flex: 1;
|
||||
background: var(--vp-c-bg);
|
||||
border: 2px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
@@ -398,8 +398,8 @@ const resetCluster = () => {
|
||||
.benefit-card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
text-align: center;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
+2
-2
@@ -150,7 +150,7 @@ const insightIcon = computed(() => {
|
||||
.architecture {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 10px;
|
||||
padding: 1rem;
|
||||
padding: 0.75rem;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ const insightIcon = computed(() => {
|
||||
margin-top: 1.5rem;
|
||||
padding: 0.75rem 1rem;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
|
||||
@@ -134,10 +134,10 @@ const resetFlow = () => {
|
||||
<style scoped>
|
||||
.microservices-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1.5rem;
|
||||
margin: 1rem 0;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
@@ -166,8 +166,8 @@ const resetFlow = () => {
|
||||
.service-card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
@@ -249,8 +249,8 @@ const resetFlow = () => {
|
||||
.communication-flow {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.communication-flow h5 {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<template>
|
||||
<div class="monolith-demo">
|
||||
<div class="demo-header">
|
||||
<h4>🏢 单体架构演示</h4>
|
||||
<p>观察单体应用如何处理请求,以及模块间的依赖关系</p>
|
||||
<span class="icon">🏢</span>
|
||||
<span class="title">单体架构演示</span>
|
||||
<span class="subtitle">观察单体应用如何处理请求</span>
|
||||
</div>
|
||||
|
||||
<div class="monolith-diagram">
|
||||
@@ -47,13 +48,9 @@
|
||||
<button class="control-btn" @click="reset">重置</button>
|
||||
</div>
|
||||
|
||||
<div class="demo-explanation">
|
||||
<h5>💡 单体架构的特点</h5>
|
||||
<ul>
|
||||
<li><strong>共享进程空间</strong>:所有模块在同一个进程中运行,内存共享</li>
|
||||
<li><strong>数据库耦合</strong>:所有模块共享同一个数据库,Schema变更影响全局</li>
|
||||
<li><strong>级联故障</strong>:一个模块崩溃可能导致整个进程挂掉(雪崩效应)</li>
|
||||
</ul>
|
||||
<div class="info-box">
|
||||
<span class="icon">💡</span>
|
||||
<strong>核心思想:</strong>所有模块在同一个进程中运行,内存共享,但一个模块崩溃可能导致整个进程挂掉(雪崩效应)。
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -134,41 +131,50 @@ const reset = () => {
|
||||
<style scoped>
|
||||
.monolith-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1.5rem;
|
||||
margin: 1rem 0;
|
||||
padding: 0.75rem;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
margin-bottom: 1.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 0.5rem;
|
||||
padding-bottom: 0.4rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.demo-header h4 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
font-size: 1.1rem;
|
||||
.demo-header .icon {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.demo-header .title {
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.demo-header p {
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
.demo-header .subtitle {
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.75rem;
|
||||
margin-left: 0.4rem;
|
||||
}
|
||||
|
||||
.monolith-diagram {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
gap: 0.75rem;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 1.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.monolith-box {
|
||||
flex: 1;
|
||||
background: var(--vp-c-bg);
|
||||
border: 2px solid var(--vp-c-brand);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.5rem;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
@@ -181,23 +187,24 @@ const reset = () => {
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-brand);
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
padding-bottom: 0.25rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.modules-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1rem;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.module-box {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
border-radius: 4px;
|
||||
padding: 0.4rem;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
@@ -218,21 +225,21 @@ const reset = () => {
|
||||
}
|
||||
|
||||
.module-icon {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 0.25rem;
|
||||
font-size: 1rem;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.module-name {
|
||||
font-size: 0.8rem;
|
||||
font-size: 0.65rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
margin-bottom: 0.25rem;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.module-status {
|
||||
font-size: 0.7rem;
|
||||
padding: 0.1rem 0.4rem;
|
||||
border-radius: 10px;
|
||||
font-size: 0.55rem;
|
||||
padding: 0.05rem 0.25rem;
|
||||
border-radius: 6px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@@ -255,38 +262,38 @@ const reset = () => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.75rem;
|
||||
gap: 0.3rem;
|
||||
padding: 0.4rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 1px dashed var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.db-icon {
|
||||
font-size: 1.25rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.db-label {
|
||||
font-size: 0.8rem;
|
||||
font-size: 0.65rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.request-flow {
|
||||
width: 150px;
|
||||
width: 100px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.flow-request {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
gap: 0.25rem;
|
||||
padding: 0.3rem;
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 6px;
|
||||
font-size: 0.75rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
|
||||
.flow-request.active {
|
||||
@@ -309,19 +316,19 @@ const reset = () => {
|
||||
|
||||
.controls {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
gap: 0.4rem;
|
||||
justify-content: center;
|
||||
margin-bottom: 1.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.control-btn {
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.3rem 0.6rem;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
background: var(--vp-c-bg);
|
||||
color: var(--vp-c-text-1);
|
||||
font-size: 0.85rem;
|
||||
font-size: 0.75rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
@@ -339,34 +346,6 @@ const reset = () => {
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
}
|
||||
|
||||
.demo-explanation {
|
||||
padding-top: 1.5rem;
|
||||
border-top: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.demo-explanation h5 {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
margin: 0 0 0.75rem 0;
|
||||
}
|
||||
|
||||
.demo-explanation ul {
|
||||
margin: 0 0 1rem 0;
|
||||
padding-left: 1.25rem;
|
||||
}
|
||||
|
||||
.demo-explanation li {
|
||||
font-size: 0.9rem;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.6;
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
|
||||
.demo-explanation li strong {
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.monolith-diagram {
|
||||
flex-direction: column;
|
||||
@@ -378,4 +357,23 @@ const reset = () => {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
.info-box {
|
||||
background: var(--vp-c-bg-alt);
|
||||
padding: 0.5rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-top: 0.5rem;
|
||||
display: flex;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
|
||||
.info-box .icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.info-box strong {
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
</style>
|
||||
|
||||
+4
-4
@@ -159,7 +159,7 @@ const deployRelease = () => {
|
||||
|
||||
.module-btn {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg);
|
||||
padding: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
@@ -186,7 +186,7 @@ const deployRelease = () => {
|
||||
.risk-meter {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 10px;
|
||||
padding: 1rem;
|
||||
padding: 0.75rem;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ const deployRelease = () => {
|
||||
margin-top: 1rem;
|
||||
width: 100%;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 0.6rem;
|
||||
background: var(--vp-c-brand);
|
||||
color: #fff;
|
||||
@@ -229,7 +229,7 @@ const deployRelease = () => {
|
||||
margin-top: 0.75rem;
|
||||
font-size: 0.9rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px dashed var(--vp-c-divider);
|
||||
}
|
||||
|
||||
+6
-6
@@ -79,10 +79,10 @@ const reset = () => {
|
||||
<style scoped>
|
||||
.monolith-microservice-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1.5rem;
|
||||
margin: 1rem 0;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.controls {
|
||||
@@ -129,8 +129,8 @@ const reset = () => {
|
||||
.architecture-block {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@@ -146,8 +146,8 @@ const reset = () => {
|
||||
.server-container {
|
||||
border: 2px solid #3b82f6;
|
||||
background: #eff6ff;
|
||||
padding: 1rem;
|
||||
border-radius: 8px;
|
||||
padding: 0.75rem;
|
||||
border-radius: 6px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
transition: all 0.3s;
|
||||
|
||||
+92
-125
@@ -1,8 +1,9 @@
|
||||
<template>
|
||||
<div class="physical-server-demo">
|
||||
<div class="demo-header">
|
||||
<h4>🖥️ 物理服务器时代演示</h4>
|
||||
<p>点击"发送请求",观察早期 CGI 服务器的处理瓶颈</p>
|
||||
<span class="icon">🖥️</span>
|
||||
<span class="title">物理服务器时代演示</span>
|
||||
<span class="subtitle">观察早期 CGI 服务器的处理瓶颈</span>
|
||||
</div>
|
||||
|
||||
<div class="demo-stage">
|
||||
@@ -85,27 +86,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo-explanation">
|
||||
<h5>💡 早期的痛点在哪里?</h5>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>进程启动开销</strong>:每个请求都要启动新的 CGI
|
||||
进程,就像每来一个客人都要重新搭一个厨房
|
||||
</li>
|
||||
<li>
|
||||
<strong>资源无法复用</strong>:数据库连接每次都要重新建立,CPU
|
||||
频繁在进程间切换
|
||||
</li>
|
||||
<li>
|
||||
<strong>扩展困难</strong>:只能买更强的单机(垂直扩展),无法通过增加机器分担压力
|
||||
</li>
|
||||
</ul>
|
||||
<p class="demo-conclusion">
|
||||
这就是<strong>物理服务器 + CGI</strong>时代的核心问题:<span
|
||||
class="highlight"
|
||||
>进程级隔离带来了稳定性,但也带来了巨大的性能开销</span
|
||||
>。
|
||||
</p>
|
||||
<div class="info-box">
|
||||
<span class="icon">💡</span>
|
||||
<strong>核心思想:</strong>进程级隔离带来了稳定性,但也带来了巨大的性能开销。
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -190,77 +173,86 @@ const sendRequest = async () => {
|
||||
<style scoped>
|
||||
.physical-server-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1.5rem;
|
||||
margin: 1rem 0;
|
||||
padding: 0.75rem;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
margin-bottom: 1.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 0.5rem;
|
||||
padding-bottom: 0.4rem;
|
||||
border-bottom: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.demo-header h4 {
|
||||
margin: 0 0 0.5rem 0;
|
||||
font-size: 1.1rem;
|
||||
.demo-header .icon {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.demo-header .title {
|
||||
font-weight: bold;
|
||||
font-size: 0.9rem;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.demo-header p {
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
.demo-header .subtitle {
|
||||
color: var(--vp-c-text-2);
|
||||
font-size: 0.75rem;
|
||||
margin-left: 0.4rem;
|
||||
}
|
||||
|
||||
.demo-stage {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.client-zone,
|
||||
.server-zone {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.zone-title {
|
||||
font-size: 0.85rem;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-brand);
|
||||
margin-bottom: 0.75rem;
|
||||
margin-bottom: 0.4rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.request-queue {
|
||||
min-height: 60px;
|
||||
min-height: 40px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 6px;
|
||||
padding: 0.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
border-radius: 4px;
|
||||
padding: 0.3rem;
|
||||
margin-bottom: 0.4rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
gap: 0.15rem;
|
||||
}
|
||||
|
||||
.request-card {
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
padding: 0.4rem 0.5rem;
|
||||
border-radius: 3px;
|
||||
padding: 0.25rem 0.3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.75rem;
|
||||
gap: 0.3rem;
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
|
||||
.req-method {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
padding: 0.1rem 0.3rem;
|
||||
border-radius: 3px;
|
||||
padding: 0.05rem 0.2rem;
|
||||
border-radius: 2px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@@ -269,9 +261,9 @@ const sendRequest = async () => {
|
||||
background: var(--vp-c-brand);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
padding: 0.6rem;
|
||||
font-size: 0.85rem;
|
||||
border-radius: 4px;
|
||||
padding: 0.4rem;
|
||||
font-size: 0.75rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
@@ -290,12 +282,12 @@ const sendRequest = async () => {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 60px;
|
||||
min-width: 40px;
|
||||
}
|
||||
|
||||
.network-line {
|
||||
width: 3px;
|
||||
height: 120px;
|
||||
width: 2px;
|
||||
height: 80px;
|
||||
background: var(--vp-c-divider);
|
||||
border-radius: 2px;
|
||||
position: relative;
|
||||
@@ -309,29 +301,29 @@ const sendRequest = async () => {
|
||||
}
|
||||
|
||||
.latency-display {
|
||||
margin-top: 0.5rem;
|
||||
font-size: 0.75rem;
|
||||
margin-top: 0.3rem;
|
||||
font-size: 0.6rem;
|
||||
color: var(--vp-c-brand);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.server-status {
|
||||
margin-bottom: 0.75rem;
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
|
||||
.status-indicator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
gap: 0.3rem;
|
||||
padding: 0.3rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 6px;
|
||||
margin-bottom: 0.5rem;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: var(--vp-c-success);
|
||||
}
|
||||
@@ -347,59 +339,59 @@ const sendRequest = async () => {
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 0.8rem;
|
||||
font-size: 0.65rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.cpu-usage {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
|
||||
.cpu-bar {
|
||||
flex: 1;
|
||||
height: 6px;
|
||||
height: 4px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 3px;
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.cpu-fill {
|
||||
height: 100%;
|
||||
background: var(--vp-c-danger);
|
||||
border-radius: 3px;
|
||||
border-radius: 2px;
|
||||
transition: width 0.1s ease;
|
||||
}
|
||||
|
||||
.cpu-text {
|
||||
font-size: 0.7rem;
|
||||
font-size: 0.55rem;
|
||||
color: var(--vp-c-text-2);
|
||||
min-width: 60px;
|
||||
min-width: 50px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.process-queue {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.4rem;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.process-item {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 6px;
|
||||
padding: 0.5rem;
|
||||
border-radius: 4px;
|
||||
padding: 0.3rem;
|
||||
}
|
||||
|
||||
.proc-name {
|
||||
display: block;
|
||||
font-size: 0.7rem;
|
||||
font-size: 0.55rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 0.3rem;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
.proc-progress {
|
||||
height: 4px;
|
||||
height: 3px;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
@@ -412,64 +404,39 @@ const sendRequest = async () => {
|
||||
transition: width 0.1s linear;
|
||||
}
|
||||
|
||||
.demo-explanation {
|
||||
margin-top: 1.5rem;
|
||||
padding-top: 1.5rem;
|
||||
border-top: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
.demo-explanation h5 {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-1);
|
||||
margin: 0 0 0.75rem 0;
|
||||
}
|
||||
|
||||
.demo-explanation ul {
|
||||
margin: 0 0 1rem 0;
|
||||
padding-left: 1.25rem;
|
||||
}
|
||||
|
||||
.demo-explanation li {
|
||||
font-size: 0.9rem;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.6;
|
||||
margin-bottom: 0.4rem;
|
||||
}
|
||||
|
||||
.demo-explanation li strong {
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.demo-conclusion {
|
||||
font-size: 0.9rem;
|
||||
color: var(--vp-c-text-2);
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
padding: 0.75rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
color: var(--vp-c-brand);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.demo-stage {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1rem;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.connection-zone {
|
||||
flex-direction: row;
|
||||
height: 60px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.network-line {
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
height: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.info-box {
|
||||
background: var(--vp-c-bg-alt);
|
||||
padding: 0.5rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-top: 0.5rem;
|
||||
display: flex;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
|
||||
.info-box .icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.info-box strong {
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -62,10 +62,10 @@ const comparisonData = [
|
||||
<style scoped>
|
||||
.scaling-strategy-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
padding: 0.75rem;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
|
||||
+1
-1
@@ -142,7 +142,7 @@ const scaleHint = computed(() => {
|
||||
.card {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 12px;
|
||||
padding: 1rem;
|
||||
padding: 0.75rem;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
|
||||
@@ -161,10 +161,10 @@ onUnmounted(() => {
|
||||
<style scoped>
|
||||
.serverless-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1.5rem;
|
||||
margin: 1rem 0;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
@@ -199,8 +199,8 @@ onUnmounted(() => {
|
||||
.function-card {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
text-align: center;
|
||||
@@ -276,8 +276,8 @@ onUnmounted(() => {
|
||||
.auto-scaling-panel {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.scaling-title {
|
||||
@@ -335,8 +335,8 @@ onUnmounted(() => {
|
||||
.traffic-simulator {
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
|
||||
+63
-53
@@ -1,8 +1,9 @@
|
||||
<template>
|
||||
<div class="tech-stack-timeline-demo">
|
||||
<div class="demo-header">
|
||||
<h4>📚 技术栈演进时间线</h4>
|
||||
<p>每个时代的主流技术栈</p>
|
||||
<span class="icon">📚</span>
|
||||
<span class="title">技术栈演进时间线</span>
|
||||
<span class="subtitle">每个时代的主流技术栈</span>
|
||||
</div>
|
||||
|
||||
<div class="timeline">
|
||||
@@ -102,137 +103,127 @@ const eras = [
|
||||
<style scoped>
|
||||
.tech-stack-timeline-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
padding: 0.75rem;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
margin-bottom: 1rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.demo-header h4 {
|
||||
margin: 0 0 0.25rem 0;
|
||||
font-size: 1rem;
|
||||
margin: 0 0 0.15rem 0;
|
||||
font-size: 0.9rem;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.demo-header p {
|
||||
margin: 0;
|
||||
font-size: 0.85rem;
|
||||
font-size: 0.75rem;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
.timeline {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 0.4rem;
|
||||
}
|
||||
|
||||
.era-section {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
flex-direction: column;
|
||||
gap: 0.25rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 4px;
|
||||
padding: 0.4rem;
|
||||
}
|
||||
|
||||
.era-section:hover,
|
||||
.era-section.active {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-brand-soft);
|
||||
}
|
||||
|
||||
.era-marker {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 24px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.era-dot {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: var(--vp-c-divider);
|
||||
border: 2px solid var(--vp-c-bg);
|
||||
transition: all 0.2s;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.era-section.active .era-dot {
|
||||
background: var(--vp-c-brand);
|
||||
border-color: var(--vp-c-brand);
|
||||
box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.2);
|
||||
display: none;
|
||||
}
|
||||
|
||||
.era-line {
|
||||
flex: 1;
|
||||
width: 2px;
|
||||
background: var(--vp-c-divider);
|
||||
margin: 4px 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.era-content {
|
||||
flex: 1;
|
||||
padding: 0.5rem 0.5rem 0.5rem 0;
|
||||
}
|
||||
|
||||
.era-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
gap: 0.25rem;
|
||||
margin-bottom: 0.3rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.era-icon {
|
||||
font-size: 1.25rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.era-name {
|
||||
font-weight: 600;
|
||||
font-size: 0.95rem;
|
||||
font-size: 0.7rem;
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
|
||||
.era-period {
|
||||
font-size: 0.75rem;
|
||||
font-size: 0.6rem;
|
||||
color: var(--vp-c-text-3);
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 0.1rem 0.4rem;
|
||||
border-radius: 4px;
|
||||
padding: 0.05rem 0.25rem;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.tech-categories {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 0.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
|
||||
.category {
|
||||
background: var(--vp-c-bg-soft);
|
||||
border-radius: 4px;
|
||||
padding: 0.5rem;
|
||||
border-radius: 3px;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
|
||||
.category-name {
|
||||
font-size: 0.75rem;
|
||||
font-size: 0.6rem;
|
||||
font-weight: 600;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-bottom: 0.25rem;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.tech-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.25rem;
|
||||
gap: 0.15rem;
|
||||
}
|
||||
|
||||
.tech-tag {
|
||||
font-size: 0.7rem;
|
||||
padding: 0.1rem 0.35rem;
|
||||
font-size: 0.55rem;
|
||||
padding: 0.05rem 0.2rem;
|
||||
background: var(--vp-c-bg);
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 3px;
|
||||
border-radius: 2px;
|
||||
color: var(--vp-c-text-2);
|
||||
}
|
||||
|
||||
@@ -243,8 +234,27 @@ const eras = [
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.tech-categories {
|
||||
grid-template-columns: 1fr;
|
||||
.timeline {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
.info-box {
|
||||
background: var(--vp-c-bg-alt);
|
||||
padding: 0.5rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
color: var(--vp-c-text-2);
|
||||
margin-top: 0.5rem;
|
||||
display: flex;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
|
||||
.info-box .icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.info-box strong {
|
||||
color: var(--vp-c-text-1);
|
||||
}
|
||||
</style>
|
||||
|
||||
+9
-9
@@ -230,12 +230,12 @@ const getCurrentLang = () => {
|
||||
<style scoped>
|
||||
.backend-languages-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
padding: 0.75rem;
|
||||
margin: 0.5rem 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
@@ -286,10 +286,10 @@ const getCurrentLang = () => {
|
||||
}
|
||||
|
||||
.language-card {
|
||||
padding: 1rem;
|
||||
padding: 0.75rem;
|
||||
background: var(--vp-c-bg-soft);
|
||||
border: 2px solid transparent;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
text-align: center;
|
||||
@@ -338,8 +338,8 @@ const getCurrentLang = () => {
|
||||
|
||||
.lang-detail {
|
||||
background: var(--vp-c-bg);
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
padding: 0.75rem;
|
||||
margin-top: 0.75rem;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
}
|
||||
|
||||
+5
-5
@@ -149,12 +149,12 @@ const getModelInfo = () => {
|
||||
<style scoped>
|
||||
.concurrency-model-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
padding: 0.75rem;
|
||||
margin: 0.5rem 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
|
||||
+5
-5
@@ -93,12 +93,12 @@ const maxTime = computed(() => {
|
||||
<style scoped>
|
||||
.developer-efficiency-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
padding: 0.75rem;
|
||||
margin: 0.5rem 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
|
||||
+5
-5
@@ -174,12 +174,12 @@ const getBarClass = (score) => {
|
||||
<style scoped>
|
||||
.language-comparison-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
padding: 0.75rem;
|
||||
margin: 0.5rem 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
|
||||
+5
-5
@@ -89,12 +89,12 @@ const ecosystems = [
|
||||
<style scoped>
|
||||
.language-ecosystem-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
padding: 0.75rem;
|
||||
margin: 0.5rem 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
|
||||
+7
-7
@@ -165,12 +165,12 @@ const reset = () => {
|
||||
<style scoped>
|
||||
.language-selector-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
padding: 0.75rem;
|
||||
margin: 0.5rem 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
@@ -282,8 +282,8 @@ const reset = () => {
|
||||
|
||||
.recommendation-panel {
|
||||
background: var(--vp-c-bg);
|
||||
padding: 1rem;
|
||||
border-radius: 8px;
|
||||
padding: 0.75rem;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 1rem;
|
||||
border: 2px solid var(--vp-c-brand);
|
||||
}
|
||||
|
||||
+6
-6
@@ -64,12 +64,12 @@ const models = [
|
||||
<style scoped>
|
||||
.memory-management-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
padding: 0.75rem;
|
||||
margin: 0.5rem 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
@@ -118,7 +118,7 @@ const models = [
|
||||
|
||||
.model-card {
|
||||
background: var(--vp-c-bg);
|
||||
padding: 1rem;
|
||||
padding: 0.75rem;
|
||||
border-radius: 6px;
|
||||
text-align: center;
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
|
||||
+5
-5
@@ -157,12 +157,12 @@ runBenchmark()
|
||||
<style scoped>
|
||||
.performance-benchmark-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
padding: 0.75rem;
|
||||
margin: 0.5rem 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
|
||||
+6
-6
@@ -122,12 +122,12 @@ const getLineCount = (lang) => {
|
||||
<style scoped>
|
||||
.syntax-comparison-demo {
|
||||
border: 1px solid var(--vp-c-divider);
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--vp-c-bg-soft);
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
padding: 0.75rem;
|
||||
margin: 0.5rem 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
@@ -256,7 +256,7 @@ const getLineCount = (lang) => {
|
||||
|
||||
.code-content {
|
||||
margin: 0;
|
||||
padding: 1rem;
|
||||
padding: 0.75rem;
|
||||
background: #1e1e1e;
|
||||
color: #d4d4d4;
|
||||
font-family: 'Monaco', 'Menlo', monospace;
|
||||
|
||||
+7
-7
@@ -276,7 +276,7 @@ const tabs = [
|
||||
gap: 8px;
|
||||
padding: 20px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@ const tabs = [
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
text-align: center;
|
||||
border-left: 4px solid;
|
||||
}
|
||||
@@ -329,7 +329,7 @@ const tabs = [
|
||||
.arch-characteristics {
|
||||
padding: 16px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.arch-characteristics h5 {
|
||||
@@ -357,7 +357,7 @@ const tabs = [
|
||||
gap: 16px;
|
||||
padding: 20px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
@@ -369,7 +369,7 @@ const tabs = [
|
||||
|
||||
.clean-layer {
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
border-left: 4px solid;
|
||||
}
|
||||
|
||||
@@ -407,7 +407,7 @@ const tabs = [
|
||||
|
||||
.dependency-rule {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
border: 2px dashed #1890ff;
|
||||
@@ -485,7 +485,7 @@ const tabs = [
|
||||
|
||||
.rec-card {
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
+2
-2
@@ -250,7 +250,7 @@ const toggleDetails = (section) => {
|
||||
margin-top: 12px;
|
||||
padding: 16px;
|
||||
background: #f0f7ff;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
border-left: 4px solid #409eff;
|
||||
}
|
||||
|
||||
@@ -297,7 +297,7 @@ const toggleDetails = (section) => {
|
||||
text-align: center;
|
||||
padding: 16px 12px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -180,7 +180,7 @@
|
||||
.layer-box {
|
||||
padding: 16px 20px;
|
||||
background: #f5f7fa;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
text-align: center;
|
||||
|
||||
+2
-2
@@ -202,7 +202,7 @@ const viewMode = ref('conversion')
|
||||
|
||||
.flow-step {
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
border-left: 4px solid #409eff;
|
||||
}
|
||||
@@ -286,7 +286,7 @@ const viewMode = ref('conversion')
|
||||
|
||||
.table-header {
|
||||
background: #f5f7fa;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
font-size: 13px;
|
||||
|
||||
+1
-1
@@ -334,7 +334,7 @@ const layerInfo = computed(() => {
|
||||
margin-top: 16px;
|
||||
background: #f6ffed;
|
||||
border: 1px solid #b7eb8f;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
color: #389e0d;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
+7
-7
@@ -596,7 +596,7 @@ const principles = [
|
||||
margin-bottom: 20px;
|
||||
padding: 16px;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
@@ -670,7 +670,7 @@ const principles = [
|
||||
|
||||
.flow-step {
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
@@ -813,7 +813,7 @@ const principles = [
|
||||
padding: 10px 20px;
|
||||
border: 2px solid #dcdfe6;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
@@ -880,7 +880,7 @@ const principles = [
|
||||
|
||||
.code-block {
|
||||
background: #2d2d2d;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
padding: 16px;
|
||||
margin: 0;
|
||||
overflow-x: auto;
|
||||
@@ -897,7 +897,7 @@ const principles = [
|
||||
margin-top: 20px;
|
||||
padding: 16px;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.problems-list h5 {
|
||||
@@ -952,7 +952,7 @@ const principles = [
|
||||
|
||||
.table-header {
|
||||
background: #f5f7fa;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
font-size: 13px;
|
||||
@@ -1029,7 +1029,7 @@ const principles = [
|
||||
.table-row {
|
||||
padding: 16px;
|
||||
border: 1px solid #ebeef5;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -422,7 +422,7 @@ const principles = [
|
||||
margin-bottom: 20px;
|
||||
padding: 16px;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
@@ -496,7 +496,7 @@ const principles = [
|
||||
|
||||
.flow-step {
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
@@ -644,7 +644,7 @@ const principles = [
|
||||
.principle-card {
|
||||
padding: 14px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
border-left: 3px solid #e6a23c;
|
||||
}
|
||||
|
||||
|
||||
@@ -1523,7 +1523,7 @@ onUnmounted(() => {
|
||||
}
|
||||
.console-output {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
|
||||
font-family: Consolas, 'Lucida Console', monospace;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
+2
-2
@@ -400,7 +400,7 @@ const selectNode = (node) => {
|
||||
/* Virtual Page Preview */
|
||||
.virtual-page-container {
|
||||
border: 1px solid #d0d7de;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
background: #fff;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
@@ -471,7 +471,7 @@ const selectNode = (node) => {
|
||||
/* DevTools Simulator (Enhanced) */
|
||||
.browser-devtools-demo {
|
||||
border: 1px solid #d0d7de;
|
||||
border-radius: 8px;
|
||||
border-radius: 6px;
|
||||
background-color: #ffffff;
|
||||
color: #202124;
|
||||
font-family: 'Segoe UI', '.SFNSDisplay', 'Roboto', sans-serif;
|
||||
|
||||
@@ -152,7 +152,7 @@ const runShortcut = (cmd) => {
|
||||
|
||||
.console-body {
|
||||
height: 250px;
|
||||
overflow-y: auto;
|
||||
|
||||
background-color: #f5f7fa;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
|
||||
@@ -154,7 +154,7 @@ const updateStyle = (prop, value) => {
|
||||
|
||||
.dom-content, .style-content {
|
||||
padding: 10px;
|
||||
overflow-y: auto;
|
||||
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user