Compare commits
523 Commits
6d3dc23f12
...
455e0a54d3
| Author | SHA1 | Date | |
|---|---|---|---|
| 455e0a54d3 | |||
| 6445d968fe | |||
| 0325d50661 | |||
| 812a37da1c | |||
| 5c4c8b1f49 | |||
| 8352260871 | |||
| 9ac0f56427 | |||
| a5be85040e | |||
| 461ea357ab | |||
| df24d8f6de | |||
| b8ebbf4348 | |||
| 3aa1eb059c | |||
| 9cbc549cae | |||
| 5ac27e907e | |||
| 93256540f5 | |||
| d962359412 | |||
| fea9ccd383 | |||
| 64d79e6775 | |||
| 89035bd4c8 | |||
| 19611a73ad | |||
| 5d39307d57 | |||
| d2f6bd7504 | |||
| cc11ea6ae0 | |||
| 339b24fd95 | |||
| 668c3accdc | |||
| fa940c15f8 | |||
| 3f169f543d | |||
| 59de919932 | |||
| d15ea09261 | |||
| 21047a2b60 | |||
| d2c9baf23c | |||
| 72bdfc1044 | |||
| e2c9e0f06d | |||
| 8cd4151e2b | |||
| 6517eeb1a2 | |||
| debd5889c8 | |||
| 2cef901b13 | |||
| dc6a93c930 | |||
| 60b55eb372 | |||
| 9a98bb5d0f | |||
| a7849acc17 | |||
| 9513946ee4 | |||
| c3bcb7a288 | |||
| a1fa14b459 | |||
| d085979077 | |||
| a6933aabf4 | |||
| 7cb4f92659 | |||
| 89d5965f25 | |||
| 03e0435d0c | |||
| f8d6abff7a | |||
| 5af23a4383 | |||
| c08e10d00c | |||
| 80609bf277 | |||
| c74849757e | |||
| 2bc38c6b2d | |||
| 59db08e6d2 | |||
| 3caa1f88bc | |||
| b67b7afe7a | |||
| a4c75a3a34 | |||
| d03d5dae59 | |||
| 90842adccf | |||
| 02ce40433a | |||
| 261426e7b9 | |||
| df42f5811d | |||
| d417a34686 | |||
| 2390f29dda | |||
| d5986ce658 | |||
| 5b22ade43c | |||
| a11639024e | |||
| a49d0483a3 | |||
| 384638d128 | |||
| 8149539bf1 | |||
| 445b8f07b4 | |||
| e191fa7ddb | |||
| b3ca518409 | |||
| 7392d8a805 | |||
| f42a633226 | |||
| 4438edf4d5 | |||
| 547cf834ec | |||
| 493313bdb9 | |||
| de9e22b85e | |||
| 42e0c20775 | |||
| d44da01024 | |||
| 23a08b1c32 | |||
| 7dafbd7f04 | |||
| 56cba7fb44 | |||
| e064f933b6 | |||
| 04e0dbf0a0 | |||
| a177fd9e1f | |||
| 7d6c2cbf9c | |||
| f6454b0342 | |||
| 51d0738a62 | |||
| 0ac5d0a934 | |||
| fa0378b079 | |||
| 9df2cec104 | |||
| 7de2695d87 | |||
| 28b27fc4a0 | |||
| 4512c010bd | |||
| fba9d76ddd | |||
| 98ff6bd56e | |||
| f86668d458 | |||
| ee4b8f18e3 | |||
| f72fb10d90 | |||
| 706a86853e | |||
| d61084d427 | |||
| 679dc7ea90 | |||
| e2796ea75d | |||
| c50b4377fe | |||
| 96a00195fa | |||
| dd5c098301 | |||
| 2aac9d218e | |||
| 7ce6f4fd40 | |||
| fc096759fb | |||
| b68eaa0364 | |||
| 215c45099a | |||
| abf60f7149 | |||
| 596213244a | |||
| 6b9e0fbf1d | |||
| c8b68e5139 | |||
| 39e75df8c7 | |||
| 244861ee8d | |||
| c99264cb02 | |||
| ec95e132f4 | |||
| 74c2f4ab26 | |||
| 8cb13c70e3 | |||
| 57c662aa2f | |||
| 600dc0fd5b | |||
| 20ba9d7965 | |||
| 04fa929af8 | |||
| 780293c57e | |||
| c0d8e6b2a3 | |||
| 507fe47f2c | |||
| a76c588a0e | |||
| 6a0deeef6f | |||
| b68e5f4ff4 | |||
| cc0e7fcc36 | |||
| 448ec3f697 | |||
| b010e9c8c1 | |||
| 7f33a020bd | |||
| 508d7aa012 | |||
| 41b185344e | |||
| 83d5dfa8a7 | |||
| be8ccf6a8c | |||
| aa080c2097 | |||
| 5e37fc1109 | |||
| c231d8278c | |||
| 2d5980b525 | |||
| ed51bc3687 | |||
| bfb72742fd | |||
| 9014f4f337 | |||
| 8327eea2d5 | |||
| 689bac2178 | |||
| 707801c265 | |||
| ae1c98818e | |||
| d08509f2d9 | |||
| bb2b4af00f | |||
| 144137d4fd | |||
| f0259bf8f9 | |||
| 7bdf37c0bc | |||
| 5cd8b992e6 | |||
| 9d125b072a | |||
| c927f03018 | |||
| 7d40376a77 | |||
| 87b150a3e7 | |||
| 5728ae16b3 | |||
| 0ca1a53306 | |||
| 0cde334b1d | |||
| 521892b787 | |||
| 35c9b1d60d | |||
| 90b7949bd9 | |||
| a0db05b09c | |||
| 7908836b9f | |||
| b215b13303 | |||
| 098fc3aab7 | |||
| 46507052eb | |||
| e958ffe0ca | |||
| 6db9ef4d7c | |||
| 02694d8cb4 | |||
| 7c1abbb407 | |||
| 6ed901a1e0 | |||
| 25909511df | |||
| 9a4e1544c3 | |||
| ec2a746be5 | |||
| cd682b0969 | |||
| ded4ff235c | |||
| b99d4af698 | |||
| c8613de3ca | |||
| 8af6b43caf | |||
| c6c0c3950d | |||
| a46332adda | |||
| 346c83a49e | |||
| e89657174e | |||
| 128c5a7df1 | |||
| a2c46646f1 | |||
| dc8b5773f1 | |||
| d8eb93663d | |||
| 5360b34531 | |||
| 5323285868 | |||
| c38ef42b43 | |||
| 76a328ceba | |||
| ed0f1820e2 | |||
| f29dbc65b9 | |||
| c87e4fc66f | |||
| e84b8d8ae0 | |||
| 09cbd870e5 | |||
| 3d932c1e0a | |||
| 7dd0768f94 | |||
| c228758896 | |||
| 46fc124afa | |||
| f50fc95e81 | |||
| 6334a29a63 | |||
| ea33e07a7b | |||
| 56390ed575 | |||
| d248c0d17f | |||
| a9aa68639f | |||
| e7b3fa8001 | |||
| 8bac413237 | |||
| b2e3ffa1fd | |||
| 7cd26c59d8 | |||
| de86489421 | |||
| d2809706e5 | |||
| a40adac683 | |||
| 311546a2fc | |||
| ef70b1d8e1 | |||
| e293d165ce | |||
| df51f84ab5 | |||
| f44c842fe7 | |||
| 3af119a598 | |||
| b5a55811cc | |||
| f35cddeb8b | |||
| baba96e7ed | |||
| 951541d5c5 | |||
| 7538228113 | |||
| 260d17ee8b | |||
| 94f9db0834 | |||
| d45df3cda5 | |||
| 6e13832d97 | |||
| 1062e2e16f | |||
| 2a0fdd3392 | |||
| 780be69b99 | |||
| 5b622800b8 | |||
| e5a5b9df5b | |||
| 4b83a4c23e | |||
| 8e558ac943 | |||
| b5baf54431 | |||
| fd5ea92722 | |||
| 6b1a9cf056 | |||
| 6098908eee | |||
| 399913d3ff | |||
| da9e54f0cd | |||
| ec9d52033f | |||
| 0e8618f902 | |||
| c49ccf47eb | |||
| c4c494cbac | |||
| 00702fbd10 | |||
| 648ac343f6 | |||
| 0868fd85fb | |||
| 4aca9df44e | |||
| 46cbb7b6d0 | |||
| 66b2ba6e45 | |||
| 0a187579d5 | |||
| 8078ee201c | |||
| 94d06ce4ae | |||
| b1948225f4 | |||
| da2d8db031 | |||
| cca9185b2b | |||
| cc9911fed3 | |||
| 0b8f17fbb0 | |||
| 12c5fcd690 | |||
| f1d1b95a8f | |||
| 0eba9e87e9 | |||
| a313f57fbf | |||
| 8b01686e68 | |||
| c7ee45646e | |||
| 6768339e35 | |||
| d0afb042b8 | |||
| 47377646df | |||
| 35972e43d7 | |||
| d1ace4f65a | |||
| 8e9093209e | |||
| 990adeaffa | |||
| 9ee3312569 | |||
| 60b023f26d | |||
| 9c1a395962 | |||
| e822721dec | |||
| 4732d48777 | |||
| 07d82d046b | |||
| 004496f1d5 | |||
| 73269958b2 | |||
| d7d79114a6 | |||
| d35211071a | |||
| 81e4284b87 | |||
| 01d9bea81b | |||
| ebe2bf6109 | |||
| 20aec454e4 | |||
| 80821b7571 | |||
| cd2ce9e661 | |||
| f9ade6f924 | |||
| f9c4ae9320 | |||
| d174ceea32 | |||
| 599052b2e0 | |||
| 0d12dacf8c | |||
| 36d7919da6 | |||
| b7224ca218 | |||
| 9e735fd8f2 | |||
| 68cd389545 | |||
| d84532e567 | |||
| c089f75fc1 | |||
| 3f97843ed5 | |||
| d1ee24e8b8 | |||
| 6b61d8ee3e | |||
| c0bd277190 | |||
| 66ec2ffa9a | |||
| 6dc3281333 | |||
| d1be7ebfa9 | |||
| 825bbfbb88 | |||
| 99d608d2a0 | |||
| a1198630be | |||
| 5c26af2790 | |||
| 8a7eda8014 | |||
| d166dc5b12 | |||
| 6bfd61355a | |||
| 167e3e60c8 | |||
| 12102a2bac | |||
| 1755489aaa | |||
| 7d0e798672 | |||
| a5d3bf2124 | |||
| d19b0eaca9 | |||
| 5f4236a23d | |||
| a21f0c5376 | |||
| fd685f3034 | |||
| 30ad0e353f | |||
| e15bac802d | |||
| 399bd0186b | |||
| 959d7a938b | |||
| 2fef9d052b | |||
| be0ac668be | |||
| d87b19d257 | |||
| 06fe6797f2 | |||
| e003547544 | |||
| 74ad9bce88 | |||
| 36d77998a0 | |||
| c3fc76a32f | |||
| 03c63c7015 | |||
| 8e4e0d7c71 | |||
| bee3b7f9e7 | |||
| f388bb6969 | |||
| fe76383a29 | |||
| f41e95b7a1 | |||
| 7c70c37072 | |||
| e8bba6f7c0 | |||
| 3c4a5c0e0b | |||
| 084ebed417 | |||
| e5b1c6cc88 | |||
| ad95658a11 | |||
| a9a5c5c8a7 | |||
| 119304a0a4 | |||
| b0879e7c60 | |||
| 84af03e736 | |||
| e9b153d897 | |||
| d83bb56fa1 | |||
| 9311586cea | |||
| 12f08e5c1a | |||
| 91e67fa89a | |||
| 2e68d86491 | |||
| 9b42da3c72 | |||
| 0aad243ce2 | |||
| 303bfc7843 | |||
| 57884c4a5c | |||
| 11605edb3f | |||
| 761aa7d68b | |||
| 10f1109512 | |||
| f5adedf77b | |||
| 6f78114865 | |||
| af4913a799 | |||
| 2f6b49d660 | |||
| 2f715c59e8 | |||
| ff80f91f85 | |||
| 84b1e83f4e | |||
| 4bb9333b37 | |||
| f6195ee17a | |||
| 389c9126a1 | |||
| 6806f05deb | |||
| 08da622964 | |||
| 91ab13ee46 | |||
| c3cae94db0 | |||
| ad8e63964f | |||
| cccc1d5cd4 | |||
| 7d86ba9504 | |||
| bb28f010e3 | |||
| e41063a1cd | |||
| 26ed39e1eb | |||
| 82be39a9ac | |||
| 047118a7f0 | |||
| 1b6b88fe35 | |||
| 73f4788d7e | |||
| c8567ce23f | |||
| c9e7ece75d | |||
| e1a5eb5586 | |||
| 590e036c65 | |||
| 6ec7161884 | |||
| 0e0556f902 | |||
| 50d44f7721 | |||
| c238f07e0d | |||
| a9f4071308 | |||
| 69073e2eae | |||
| 646811282a | |||
| 6eeae7cffa | |||
| b0f1ccf500 | |||
| b61e839f69 | |||
| 176caa08bd | |||
| 6b95b42eb7 | |||
| 06b154a607 | |||
| f75289c3ea | |||
| f3df90e728 | |||
| 26abc96b2f | |||
| 61dea9888f | |||
| 3ffdae8c1b | |||
| 4c25317b86 | |||
| 93914f54b0 | |||
| 7e26e9533d | |||
| 27d14a4bcc | |||
| 0e0de6382f | |||
| bfa503162c | |||
| c532b04f29 | |||
| e61706520d | |||
| edaef68c1e | |||
| 0b1473bcc3 | |||
| 0a0a22add3 | |||
| 1d25eb9b9b | |||
| 7c546e62f8 | |||
| bc0644aa4b | |||
| ecb8abd5e7 | |||
| c2152498a4 | |||
| 07fad27e81 | |||
| 50086ae71d | |||
| 6ed6ae796d | |||
| 6dca0016eb | |||
| 1d2893925a | |||
| 5e345fe3e7 | |||
| 65cef1f11e | |||
| f11093a711 | |||
| a58b21d49d | |||
| 2a521ac92f | |||
| 404f887e00 | |||
| 7d853d06ad | |||
| dd4d08431a | |||
| 70c127d5ad | |||
| eaac9b5452 | |||
| 49a92f466a | |||
| 99c1fb9ba8 | |||
| 2b762868df | |||
| 3d9101c247 | |||
| eace31ff07 | |||
| e7b6fd9245 | |||
| d35cfb3402 | |||
| 0347f96547 | |||
| 26a612e40d | |||
| 630090d9de | |||
| 1b5a899937 | |||
| d33d85734d | |||
| ab90283e1b | |||
| 201806f662 | |||
| bc71ebd1bc | |||
| 18f958500e | |||
| 1f23432439 | |||
| 5e8adc790c | |||
| ce2fbc6679 | |||
| 4f1c052d28 | |||
| 0d2f3c5c10 | |||
| 8ef37053a8 | |||
| 50e252c3b4 | |||
| a4b583b13f | |||
| 307a37cdb9 | |||
| ec37e13b90 | |||
| 7af6686c81 | |||
| 95f8f1a3ec | |||
| 628c2027a8 | |||
| 93a54bdcf6 | |||
| b7e08a0083 | |||
| 32f010ca7b | |||
| 2f0f96829e | |||
| c038ba066d | |||
| 84491a31f7 | |||
| 5984cc8fa2 | |||
| 364457e3ea | |||
| e53b7c0832 | |||
| 2d858d79e2 | |||
| 4a67933ffc | |||
| a46c94a082 | |||
| 7d1281b368 | |||
| 98cbf457f6 | |||
| 175c726ed0 | |||
| 4f36ae6dc6 | |||
| 58ad9c11e2 | |||
| f07ed6ad07 | |||
| a2aa8b1227 | |||
| d9b059c22e | |||
| 6e12112783 | |||
| 8ef4a47065 | |||
| 3f95b14010 | |||
| 3114f00e65 | |||
| bed8778159 | |||
| 6bbef0cea0 | |||
| 48e54ae819 | |||
| 2e5ca07c8c | |||
| fb6d6c189a | |||
| 47251ea747 | |||
| 506585c15c | |||
| 783282922f | |||
| e146d0876f | |||
| 39ee38443c | |||
| 7cebba0d87 | |||
| 229f8a6e92 | |||
| 41ae6c181b | |||
| 28cff90513 | |||
| edb68ebb31 | |||
| 1eafa872fd | |||
| a16edc2e0e | |||
| 1c9d388c74 | |||
| 60b04d595d | |||
| f0dc148d63 | |||
| 1ea94465dd |
@@ -0,0 +1,13 @@
|
|||||||
|
# Easy-Vibe 魔搭创空间部署:排除不需要打入镜像的文件和目录
|
||||||
|
node_modules
|
||||||
|
.git
|
||||||
|
.github
|
||||||
|
.husky
|
||||||
|
.trae
|
||||||
|
.vscode
|
||||||
|
docs/.vitepress/dist
|
||||||
|
docs/.vitepress/cache
|
||||||
|
temp
|
||||||
|
assets
|
||||||
|
.claude
|
||||||
|
docs-readme
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
# Sample workflow for building and deploying a VitePress site to GitHub Pages
|
||||||
|
name: Deploy VitePress site to Pages
|
||||||
|
|
||||||
|
on:
|
||||||
|
# Runs on pushes to main branch only
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
# Allows you to run this workflow manually from the Actions tab
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
|
||||||
|
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
|
||||||
|
concurrency:
|
||||||
|
group: pages
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# Build job
|
||||||
|
build:
|
||||||
|
if: github.repository_owner == 'datawhalechina'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Not needed if lastUpdated is not enabled
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
cache: npm
|
||||||
|
- name: Setup Pages
|
||||||
|
uses: actions/configure-pages@v4
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
- name: Build with VitePress
|
||||||
|
run: |
|
||||||
|
npm run build
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-pages-artifact@v3
|
||||||
|
with:
|
||||||
|
path: docs/.vitepress/dist
|
||||||
|
|
||||||
|
# Deployment job
|
||||||
|
deploy:
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Deploy
|
||||||
|
steps:
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
id: deployment
|
||||||
|
uses: actions/deploy-pages@v4
|
||||||
@@ -1,72 +1,25 @@
|
|||||||
# ==========================================
|
|
||||||
# 🎮 Unity (критично для кроссплатформы)
|
|
||||||
# ==========================================
|
|
||||||
Library/
|
|
||||||
Temp/
|
|
||||||
obj/
|
|
||||||
bin/
|
|
||||||
Build/
|
|
||||||
.vs/
|
|
||||||
*.pidb
|
|
||||||
*.pdb.meta
|
|
||||||
!*.meta # ← : meta-файлы Unity ЯТЬЫ для версии!
|
|
||||||
ProjectSettings/
|
|
||||||
Packages/
|
|
||||||
|
|
||||||
# ==========================================
|
|
||||||
# 💻 IDE / едакторы (Rider, VS Code, Android Studio)
|
|
||||||
# ==========================================
|
|
||||||
.idea/
|
|
||||||
*.suo
|
|
||||||
*.user
|
|
||||||
*.userosscache
|
|
||||||
*.sln.docstates
|
|
||||||
Rider/
|
|
||||||
.vscode/
|
|
||||||
.reSharper/
|
|
||||||
|
|
||||||
# ==========================================
|
|
||||||
# 📱 латформенные артефакты (PC / Android / iOS)
|
|
||||||
# ==========================================
|
|
||||||
# Android
|
|
||||||
gradle/
|
|
||||||
.gradle/
|
|
||||||
local.properties
|
|
||||||
Assets/Plugins/Android/*.aab
|
|
||||||
Assets/Plugins/Android/*.apk
|
|
||||||
Assets/Plugins/Android/*.so
|
|
||||||
|
|
||||||
# iOS
|
|
||||||
ios/
|
|
||||||
macos/
|
|
||||||
Assets/Plugins/iOS/*.xcodeproj
|
|
||||||
Assets/Plugins/iOS/*.xcworkspace
|
|
||||||
|
|
||||||
# Windows / PC билды
|
|
||||||
*.exe
|
|
||||||
*.dll
|
|
||||||
*.pdb
|
|
||||||
*.appref-ms
|
|
||||||
*.crash
|
|
||||||
|
|
||||||
# ==========================================
|
|
||||||
# 🖥️ перационные системы (Windows/macOS/Linux)
|
|
||||||
# ==========================================
|
|
||||||
Thumbs.db
|
|
||||||
ehthumbs.db
|
|
||||||
Desktop.ini
|
|
||||||
.BIN/
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.Trashes
|
node_modules
|
||||||
*.lnk
|
tools/*
|
||||||
|
docs/.vitepress/dist
|
||||||
# ==========================================
|
docs/.vitepress/cache
|
||||||
# 📦 оги, кэш, временные файлы
|
temp/*
|
||||||
# ==========================================
|
docs/zh-cn/appendix-old-backup*/
|
||||||
*.log
|
docs/zh-cn/appendix-dirs-backup*/
|
||||||
*.tmp
|
CLAUDE.md
|
||||||
*.temp
|
MULTI_LANGUAGE_PLAN.md
|
||||||
.cache/
|
.trae
|
||||||
dist/
|
scripts/collapse_code_blocks.py
|
||||||
out/
|
.gitignore
|
||||||
node_modules/ # если используете npm для билдов или UPM-кэш
|
scripts/verify.sh
|
||||||
|
REFACTORING_PLAN.md
|
||||||
|
.gitignore
|
||||||
|
.gitignore
|
||||||
|
REFACTORING_REPORT.md
|
||||||
|
docs/.vitepress/.temp/*
|
||||||
|
.temp/*
|
||||||
|
.vitepress/cache/*
|
||||||
|
.vitepress/cache/*
|
||||||
|
docs/archived-components.md
|
||||||
|
.claude/skills/*
|
||||||
|
temp/*
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
echo "🔍 Pre-commit checks started..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 0. 检查是否有 Vue 文件变动,没有则跳过检查直接提交
|
||||||
|
VUE_FILES=$(git diff --cached --name-only --diff-filter=ACMR | grep '\.vue$' || true)
|
||||||
|
if [ -z "$VUE_FILES" ]; then
|
||||||
|
echo "✅ No Vue files in this commit, skipping checks."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo "🔍 Vue files detected, running checks..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 1. ESLint 检查(只检查 errors,忽略 warnings)
|
||||||
|
echo "1️⃣ Running ESLint check..."
|
||||||
|
LINT_OUTPUT=$(npm run lint 2>&1)
|
||||||
|
LINT_EXIT_CODE=$?
|
||||||
|
|
||||||
|
# 检查是否有真正的 errors(不包括 warnings)
|
||||||
|
if echo "$LINT_OUTPUT" | grep -q "✖.*[1-9] error"; then
|
||||||
|
echo ""
|
||||||
|
echo "❌ ESLint errors found! Please fix before committing."
|
||||||
|
echo ""
|
||||||
|
echo "$LINT_OUTPUT"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "✅ ESLint: No errors (warnings ignored)"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 2. Build 检查(确保代码能成功构建)
|
||||||
|
echo "2️⃣ Running build check..."
|
||||||
|
if ! npm run build > /dev/null 2>&1; then
|
||||||
|
echo ""
|
||||||
|
echo "❌ Build failed! Please fix build errors before committing."
|
||||||
|
echo ""
|
||||||
|
echo "💡 Run 'npm run build' to see detailed errors"
|
||||||
|
echo "💡 To skip pre-commit checks: git commit --no-verify"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "✅ Build: Success"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "✅ All pre-commit checks passed!"
|
||||||
|
echo "📦 Build output verified, committing..."
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
echo "🚀 Pre-push checks started..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "1️⃣ Running forced build..."
|
||||||
|
if ! SITEMAP_NO_WRITE=1 npm run build:force > /dev/null 2>&1; then
|
||||||
|
echo ""
|
||||||
|
echo "❌ Forced build failed! Please fix build errors before pushing."
|
||||||
|
echo ""
|
||||||
|
echo "💡 Run 'npm run build:force' to see detailed errors"
|
||||||
|
echo "💡 To skip pre-push checks: git push --no-verify"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "✅ Forced build: Success"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "✅ Pre-push checks passed!"
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
**/*.md
|
||||||
|
**/*.vue
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": "*.vue",
|
||||||
|
"options": {
|
||||||
|
"parser": "vue",
|
||||||
|
"htmlWhitespaceSensitivity": "ignore",
|
||||||
|
"vueIndentScriptAndStyle": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
我将严格参照 `llm-intro.md` 的结构(**引言 -> 基础单元 -> 核心机制 -> 架构演进 -> 训练目标 -> 总结**)来撰写这三个新章节,确保风格统一且深入浅出。
|
||||||
|
|
||||||
|
### 1. 创建 `docs/zh-cn/appendix/vlm-intro.md` (多模态大模型:给 AI 装上眼睛)
|
||||||
|
|
||||||
|
- **0. 引言**: 从“读万卷书”到“行万里路”。VLM 的核心任务:把图像信号翻译成大模型能懂的语言信号。
|
||||||
|
|
||||||
|
- **1. 第一步:视觉翻译 (Visual Tokenization)**:
|
||||||
|
- **ViT (Vision Transformer)**: 计算机怎么“看”图?将图片切成 16x16 的小方块 (Patches),就像把句子切成词 (Tokens)。
|
||||||
|
- **Qwen-VL 的创新**: 提到 **Naive Dynamic Resolution**(动态分辨率),不强制压缩图片,而是根据图片比例动态切分 Patch,像人眼一样看清细节(分辨率自适应),解决了传统模型“看不清长图”的问题。
|
||||||
|
|
||||||
|
- **2. 核心难题:跨界沟通 (Projection)**:
|
||||||
|
- 视觉向量 vs 语言向量。我们需要一个“适配器” (Projector),把视觉特征映射到文本空间。
|
||||||
|
- **架构对比**:
|
||||||
|
- **Linear (LLaVA)**: 简单粗暴的线性投影,训练快,保留信息多。
|
||||||
|
- **Q-Former (BLIP-2)**: 使用查询向量 (Query) 提取关键视觉信息,更轻量。
|
||||||
|
- **C-Abstractor (Qwen-VL)**: 结合注意力机制,更高效地压缩视觉信息。
|
||||||
|
|
||||||
|
- **3. 进化之路:ViT + LLM**:
|
||||||
|
- Vision Transformer (ViT) 负责“看”,LLM 负责“想”和“说”。
|
||||||
|
- **M-LLM**: 像 GPT-4V 或 Qwen2-VL,已经不仅是“拼接”,而是深度的多模态融合,甚至能处理视频(视为连续的图片帧)。
|
||||||
|
|
||||||
|
- **4. 训练揭秘:从对齐到对话**:
|
||||||
|
- **阶段一 (Pre-training)**: 像 CLIP 一样,在大规模图文对上预训练,学会“这张图是猫”。
|
||||||
|
- **阶段二 (Instruction Tuning)**: 学会“看图说话”,使用 `<image>` 标签和对话数据,让模型能回答“这只猫在干什么?”。
|
||||||
|
|
||||||
|
- **5. 总结**: 视觉与语言的统一。
|
||||||
|
|
||||||
|
### 2. 创建 `docs/zh-cn/appendix/image-gen-intro.md` (AI 绘画:从噪声中重构世界)
|
||||||
|
|
||||||
|
- **0. 引言**: 生成式 AI 的魔法——从混沌 (Noise) 到秩序 (Data)。
|
||||||
|
|
||||||
|
- **1. 第一步:降维打击 (VAE & Latent Space)**:
|
||||||
|
- 直接画像素太累了(1024x1024 有百万像素)。我们先用 **VAE (变分自编码器)** 把图片压缩成“潜变量” (Latent),在小黑屋里作画(效率提升)。
|
||||||
|
|
||||||
|
- **2. 核心机制:扩散 (Diffusion)**:
|
||||||
|
- **破坏 (Forward)**: 像滴入墨水一样,一步步把图片变成纯高斯噪声。
|
||||||
|
- **重构 (Reverse)**: 训练神经网络预测噪声 $\epsilon$,一步步把墨水“吸”出来。
|
||||||
|
- **SDE 视角**: 理解为在概率分布上进行随机游走。
|
||||||
|
|
||||||
|
- **3. 进化之路:流匹配 (Flow Matching)**:
|
||||||
|
- **为什么 Diffusion 慢?**: 它的去噪路径是弯弯曲曲的随机路径。
|
||||||
|
- **Flow Matching (Flux/SD3)**: 寻找从噪声分布到图像分布的 **“直线”路径 (Optimal Transport)**。
|
||||||
|
- **向量场 (Vector Field)**: 训练模型预测“速度”而非“噪声”,采样时直接沿着直线飞奔,几步就能画出好图。
|
||||||
|
|
||||||
|
- **4. 操控:文本如何指挥绘画**:
|
||||||
|
- **CLIP / T5 Encoder**: 充当“甲方”,把 Prompt 变成向量。
|
||||||
|
- **DiT (Diffusion Transformer)**: 像 Sora 和 SD3 一样,用 Transformer 替换掉老的 U-Net,处理能力更强,画质上限更高。
|
||||||
|
|
||||||
|
- **5. 总结**: 概率分布的搬运工。
|
||||||
|
|
||||||
|
### 3. 创建 `docs/zh-cn/appendix/audio-intro.md` (AI 音频:声音的数字化身)
|
||||||
|
|
||||||
|
- **0. 引言**: 听与说的艺术。声音本质上是空气的振动,计算机如何处理?
|
||||||
|
|
||||||
|
- **1. 第一步:声音的“文字” (Audio Tokenization)**:
|
||||||
|
- 声音是连续的波形,语言是离散的 Token。
|
||||||
|
- **Neural Codec (VQ-VAE / EnCodec)**: 把连续波形切碎,通过 **量化 (Quantization)** 变成一个个数字 Token (Codebook)。
|
||||||
|
- **RVQ (Residual VQ)**: 像洋葱一样一层层剥开声音细节,保证高保真音质。
|
||||||
|
|
||||||
|
- **2. 核心表示:梅尔频谱 (Mel-Spectrogram)**:
|
||||||
|
- 把“听觉问题”转化成“视觉问题”。在频域上处理声音往往比时域更高效。
|
||||||
|
|
||||||
|
- **3. 架构演进:从 GPT 到 Flow**:
|
||||||
|
- **AudioLM / VALL-E**: 把声音 Token 当作文字,用 GPT **自回归 (Autoregressive)** 地狂猜下一个音。优点是能学到很好的韵律,缺点是容易“胡言乱语”或无限循环。
|
||||||
|
- **F5-TTS / CosyVoice**: 使用 **Flow Matching** 直接生成频谱。不需要复杂的 Token 预测,而是从噪声中“流”出声音频谱,速度更快,控制更稳,支持零样本克隆。
|
||||||
|
|
||||||
|
- **4. 总结**: 统一多模态的未来。
|
||||||
|
|
||||||
|
### 4. 更新配置
|
||||||
|
|
||||||
|
- 修改 `docs/.vitepress/config.mjs`,在 `zh-cn` 侧边栏添加这三个章节。
|
||||||
@@ -0,0 +1,227 @@
|
|||||||
|
---
|
||||||
|
name: 教程美化方案
|
||||||
|
description: 使用 VitePress 和 Element Plus 组件美化教程,提升可读性和交互性
|
||||||
|
---
|
||||||
|
|
||||||
|
# 教程美化最佳实践
|
||||||
|
|
||||||
|
你是一个专注于美化 VitePress 教程文档的专家。你的任务是根据用户的需求,使用 VitePress 原生功能和 Element Plus 组件来增强教程的视觉效果和交互性。
|
||||||
|
|
||||||
|
## 可用组件和样式
|
||||||
|
|
||||||
|
### 1. 醒目的提示块
|
||||||
|
|
||||||
|
**VitePress 原生样式** (简单场景)
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
::: tip 💡 提示
|
||||||
|
这是一个提示块,适合放补充信息。
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: warning ⚠️ 注意
|
||||||
|
这是一个警告块,提醒用户注意潜在问题。
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: danger 🚫 危险
|
||||||
|
这是一个危险块,用于警告严重错误。
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: info ℹ️ 信息
|
||||||
|
这是一个信息块,用于一般性说明。
|
||||||
|
:::
|
||||||
|
```
|
||||||
|
|
||||||
|
**Element Plus 样式** (更现代化)
|
||||||
|
|
||||||
|
```html
|
||||||
|
<el-alert title="成功提示的文案" type="success" show-icon />
|
||||||
|
<el-alert title="消息提示的文案" type="info" show-icon />
|
||||||
|
<el-alert title="警告提示的文案" type="warning" show-icon />
|
||||||
|
<el-alert title="错误提示的文案" type="error" show-icon />
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 步骤条
|
||||||
|
|
||||||
|
**⚠️ 重要:必须使用 `<ClientOnly>` 包裹 `<StepBar>` 组件**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<ClientOnly>
|
||||||
|
<StepBar
|
||||||
|
:active="1"
|
||||||
|
:items="[
|
||||||
|
{ title: '环境准备', description: '安装 Node.js 和编辑器' },
|
||||||
|
{ title: '代码编写', description: '跟着 AI 写第一行代码' },
|
||||||
|
{ title: '部署上线', description: '发布你的作品' },
|
||||||
|
{ title: '完成', description: '享受成果' }
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</ClientOnly>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 折叠内容
|
||||||
|
|
||||||
|
**VitePress 原生**
|
||||||
|
|
||||||
|
````markdown
|
||||||
|
::: details 点击查看详细代码
|
||||||
|
|
||||||
|
```js
|
||||||
|
console.log('Hello World')
|
||||||
|
```
|
||||||
|
````
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
````
|
||||||
|
|
||||||
|
**Element Plus 手风琴**
|
||||||
|
```html
|
||||||
|
<el-collapse accordion>
|
||||||
|
<el-collapse-item title="为什么选择 Easy-Vibe?" name="1">
|
||||||
|
<div>因为它可以让你在 AI 时代零基础学会编程。</div>
|
||||||
|
</el-collapse-item>
|
||||||
|
<el-collapse-item title="我需要什么基础?" name="2">
|
||||||
|
<div>只需要会打字,会说话即可。</div>
|
||||||
|
</el-collapse-item>
|
||||||
|
</el-collapse>
|
||||||
|
````
|
||||||
|
|
||||||
|
### 4. 代码分组
|
||||||
|
|
||||||
|
````markdown
|
||||||
|
::: code-group
|
||||||
|
|
||||||
|
```bash [npm]
|
||||||
|
npm install easy-vibe
|
||||||
|
```
|
||||||
|
````
|
||||||
|
|
||||||
|
```bash [yarn]
|
||||||
|
yarn add easy-vibe
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash [pnpm]
|
||||||
|
pnpm add easy-vibe
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
````
|
||||||
|
|
||||||
|
### 5. 交互式标签页
|
||||||
|
```html
|
||||||
|
<el-tabs type="border-card">
|
||||||
|
<el-tab-pane label="场景 A">
|
||||||
|
这里是场景 A 的详细说明...
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="场景 B">
|
||||||
|
这里是场景 B 的详细说明...
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="场景 C">
|
||||||
|
这里是场景 C 的详细说明...
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
````
|
||||||
|
|
||||||
|
### 6. 徽章与标签
|
||||||
|
|
||||||
|
```html
|
||||||
|
这是一段普通文本,但是包含 <el-tag>核心概念</el-tag> 和
|
||||||
|
<el-tag type="danger">重要提醒</el-tag>。
|
||||||
|
|
||||||
|
<el-badge :value="12" class="item">
|
||||||
|
<el-button>评论</el-button>
|
||||||
|
</el-badge>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. 进度条
|
||||||
|
|
||||||
|
```html
|
||||||
|
<el-progress
|
||||||
|
:percentage="50"
|
||||||
|
:stroke-width="15"
|
||||||
|
status="exception"
|
||||||
|
striped
|
||||||
|
striped-flow
|
||||||
|
/>
|
||||||
|
<el-progress
|
||||||
|
:percentage="100"
|
||||||
|
:stroke-width="15"
|
||||||
|
status="success"
|
||||||
|
striped
|
||||||
|
striped-flow
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8. 数据可视化卡片
|
||||||
|
|
||||||
|
```html
|
||||||
|
<el-card shadow="hover" style="margin: 20px 0; border-radius: 12px;">
|
||||||
|
<template #header>
|
||||||
|
<div style="display: flex; align-items: center; gap: 8px;">
|
||||||
|
<span style="font-size: 20px;">🚀</span>
|
||||||
|
<span style="font-weight: bold; font-size: 16px;">效率的飞跃</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-row :gutter="20" style="margin-bottom: 24px;">
|
||||||
|
<el-col :span="6" :xs="12">
|
||||||
|
<div style="text-align: center; padding: 10px;">
|
||||||
|
<div style="color: #409EFF; font-size: 24px; font-weight: bold;">
|
||||||
|
55%
|
||||||
|
</div>
|
||||||
|
<div style="color: #909399; font-size: 12px; margin-top: 4px;">
|
||||||
|
提升率
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6" :xs="12">
|
||||||
|
<div style="text-align: center; padding: 10px;">
|
||||||
|
<div style="color: #67C23A; font-size: 24px; font-weight: bold;">
|
||||||
|
2.4 <span style="font-size: 14px;">天</span>
|
||||||
|
</div>
|
||||||
|
<div style="color: #909399; font-size: 12px; margin-top: 4px;">
|
||||||
|
耗时
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<div style="line-height: 1.8; color: #606266;">
|
||||||
|
这里是详细的文字描述,可以配合 <b>加粗</b> 强调关键信息。
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9. 核心理念卡片
|
||||||
|
|
||||||
|
```html
|
||||||
|
<el-card
|
||||||
|
shadow="hover"
|
||||||
|
style="border-radius: 16px; border: 2px dashed #FFB6C1; background-color: #FFF0F5; margin: 20px 0;"
|
||||||
|
>
|
||||||
|
<div style="text-align: center;">
|
||||||
|
<div style="font-size: 24px; font-weight: 600; color: #595959;">
|
||||||
|
✨ 完成比完美更重要 🐣
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用指南
|
||||||
|
|
||||||
|
根据用户的教程内容需求,选择合适的组件:
|
||||||
|
|
||||||
|
- **内容强调**:使用 `::: tip` 或 `el-alert`,或核心理念卡片
|
||||||
|
- **流程引导**:使用 `<StepBar>`(必须包裹在 `<ClientOnly>` 中)
|
||||||
|
- **信息分层**:使用 `::: details` 或 `el-tabs`
|
||||||
|
- **数据展示**:使用数据可视化卡片
|
||||||
|
- **视觉点缀**:使用 `el-tag` 和 Icons
|
||||||
|
|
||||||
|
## 执行步骤
|
||||||
|
|
||||||
|
1. 理解用户想要美化的教程内容
|
||||||
|
2. 分析内容结构,确定需要哪些组件
|
||||||
|
3. 根据上述组件库,选择最合适的组件
|
||||||
|
4. 将组件代码插入到合适的位置
|
||||||
|
5. 确保所有自定义组件(如 StepBar)都包裹在 `<ClientOnly>` 中
|
||||||
@@ -0,0 +1,832 @@
|
|||||||
|
---
|
||||||
|
name: 编写交互式教程指南
|
||||||
|
description: 基于 llm-intro.md 的编写模式,总结如何创建高质量的交互式技术教程。涵盖内容展开的循序渐进原则、文章结构规范、交互式组件开发规范、最佳实践及完整开发工作流。
|
||||||
|
---
|
||||||
|
|
||||||
|
# 编写交互式教程指南 (Interactive Tutorial Guide)
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
本指南基于 `docs/zh-cn/appendix/llm-intro.md` 的编写模式,总结如何创建高质量的交互式技术教程。
|
||||||
|
|
||||||
|
## 一、内容展开的循序渐进原则
|
||||||
|
|
||||||
|
### 1.1 核心叙事模式
|
||||||
|
|
||||||
|
`llm-intro.md` 采用的是 **"螺旋上升"** 的叙事结构,每个知识点都遵循以下认知路径:
|
||||||
|
|
||||||
|
```
|
||||||
|
具体体验 → 抽象概念 → 历史对比 → 本质揭示 → 前沿拓展
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 原则 1:从具体体验到抽象原理
|
||||||
|
|
||||||
|
**不要一上来就讲定义**,先让读者看到效果。
|
||||||
|
|
||||||
|
**示例(llm-intro.md 第 0 章)**:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# 大语言模型入门
|
||||||
|
|
||||||
|
> 💡 **学习指南**:本章节无需编程基础,通过交互式演示带你深入了解大语言模型...
|
||||||
|
|
||||||
|
<LlmQuickStartDemo /> <!-- 先让读者玩起来 -->
|
||||||
|
|
||||||
|
## 0. 引言:从人类语言到机器计算
|
||||||
|
|
||||||
|
人类用语言交流,计算机用数字计算。
|
||||||
|
**大语言模型 (LLM)** 的本质,就是一座连接这两个世界的桥梁。
|
||||||
|
```
|
||||||
|
|
||||||
|
**要点**:
|
||||||
|
|
||||||
|
- ✅ 第一屏就是交互式演示
|
||||||
|
- ✅ 读者"玩过"后再讲原理
|
||||||
|
- ❌ 避免开篇就是"LLM 是基于 Transformer 的..."
|
||||||
|
|
||||||
|
#### 原则 2:从简单到复杂(知识依赖链)
|
||||||
|
|
||||||
|
**每个新概念都建立在前一个概念基础上**,形成知识链条。
|
||||||
|
|
||||||
|
**示例(llm-intro.md 第 1-3 章)**:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 1. 第一步:翻译(Tokenization)
|
||||||
|
|
||||||
|
核心任务:把文字变成数字 ID
|
||||||
|
<TokenizationDemo />
|
||||||
|
|
||||||
|
## 2. 核心难题:如何让计算机"计算"语言?
|
||||||
|
|
||||||
|
问题:只用 ID 太浪费、没内涵
|
||||||
|
方案:Embedding(稠密向量)
|
||||||
|
<EmbeddingDemo />
|
||||||
|
|
||||||
|
## 3. 从 单词 到 矩阵
|
||||||
|
|
||||||
|
回顾:Embedding 把每个词变成向量 → 把向量拼成矩阵 → GPU 高效计算
|
||||||
|
<TokenizerToMatrix />
|
||||||
|
```
|
||||||
|
|
||||||
|
**依赖关系**:
|
||||||
|
|
||||||
|
```
|
||||||
|
Tokenization(基础)
|
||||||
|
↓
|
||||||
|
Embedding(优化 Tokenization)
|
||||||
|
↓
|
||||||
|
矩阵化(优化 Embedding 的计算)
|
||||||
|
↓
|
||||||
|
Transformer(利用矩阵并行)
|
||||||
|
```
|
||||||
|
|
||||||
|
**要点**:
|
||||||
|
|
||||||
|
- 每章开头"回顾"上一章内容
|
||||||
|
- 明确说明"为什么要学这个"
|
||||||
|
- 用"因为...所以..."连接知识点
|
||||||
|
|
||||||
|
#### 原则 3:从问题到方案(对比式讲解)
|
||||||
|
|
||||||
|
**先提出"直白方案"的缺陷,再引出"聪明方案"**。
|
||||||
|
|
||||||
|
**示例(llm-intro.md 第 2.1-2.2 章)**:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
### 2.1 为什么不用简单的 ID?
|
||||||
|
|
||||||
|
如果只用 ID,计算机会认为"10"和"20"只是两个毫无关系的数字。
|
||||||
|
|
||||||
|
- **缺点1**:太浪费(稀疏,One-Hot 数组太大)。
|
||||||
|
- **缺点2**:没内涵(无法表示"苹果"和"香蕉"都是水果)。
|
||||||
|
|
||||||
|
### 2.2 解决方案:Embedding(稠密向量)
|
||||||
|
|
||||||
|
为了**高效**且**有内涵**地表达一个词,我们发明了 **Embedding**。
|
||||||
|
它不再用一个长长的 0/1 数组,而是用一个短一点的、填满小数的数组...
|
||||||
|
```
|
||||||
|
|
||||||
|
**模板**:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
### N.1 为什么不用 [朴素方案]?
|
||||||
|
|
||||||
|
[说明朴素方案的问题]
|
||||||
|
|
||||||
|
- **缺点1**:[具体问题]
|
||||||
|
- **缺点2**:[具体问题]
|
||||||
|
|
||||||
|
### N.2 解决方案:[优化方案]
|
||||||
|
|
||||||
|
为了解决上述问题,我们引入了 [优化方案]。
|
||||||
|
[说明优化方案的核心思想]
|
||||||
|
```
|
||||||
|
|
||||||
|
**要点**:
|
||||||
|
|
||||||
|
- 用"为什么不用..."作为章节标题
|
||||||
|
- 用列表清晰列出缺陷
|
||||||
|
- 用"为了...我们引入..."过渡到新方案
|
||||||
|
|
||||||
|
#### 原则 4:从历史到现代(进化式讲解)
|
||||||
|
|
||||||
|
**通过对比"旧技术"和"新技术",说明技术演进的动机**。
|
||||||
|
|
||||||
|
**示例(llm-intro.md 第 4 章)**:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
### 4.1 为什么要淘汰 RNN?
|
||||||
|
|
||||||
|
以前的模型(RNN)像人读书一样,**从左到右**一个字一个字读。
|
||||||
|
|
||||||
|
- **缺点1**:慢。必须读完第1个字才能读第2个,没法并行。
|
||||||
|
- **缺点2**:忘。读到文章最后,可能已经忘了开头讲什么了。
|
||||||
|
|
||||||
|
### 4.2 Transformer 强在哪?
|
||||||
|
|
||||||
|
现在的 LLM 都基于 Transformer 架构,它完美契合了矩阵并行的特性:
|
||||||
|
|
||||||
|
1. **并行阅读**:它可以**一眼看完**整句话...
|
||||||
|
2. **注意力机制**:让每个词都**直接关注**到其他所有词...
|
||||||
|
```
|
||||||
|
|
||||||
|
**对比表格化**:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
| 特性 | RNN | Transformer |
|
||||||
|
| :------------- | :----------------- | :--------------------- |
|
||||||
|
| **阅读方式** | 从左到右,逐字处理 | 并行处理,一眼看完整句 |
|
||||||
|
| **计算效率** | 慢(无法并行) | 快(GPU 矩阵运算) |
|
||||||
|
| **长距离记忆** | 容易遗忘 | 注意力机制保持连接 |
|
||||||
|
```
|
||||||
|
|
||||||
|
**要点**:
|
||||||
|
|
||||||
|
- 明确说明"为什么要淘汰"
|
||||||
|
- 用具体场景对比(如"读书方式")
|
||||||
|
- 配合 `<RNNvsTransformer />` 可视化
|
||||||
|
|
||||||
|
#### 原则 5:从现象到本质(揭秘式讲解)
|
||||||
|
|
||||||
|
**先描述用户能观察到的现象,再揭示背后的本质机制**。
|
||||||
|
|
||||||
|
**示例(llm-intro.md 第 5 章)**:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 5. 揭秘:从"续写"到"对话"
|
||||||
|
|
||||||
|
很多人会误以为 ChatGPT 真的懂我们在说什么,但其实它的本能只有一个:**猜下一个词**。
|
||||||
|
|
||||||
|
### 5.1 本能:疯狂续写
|
||||||
|
|
||||||
|
如果你给基础模型输入:"今天天气不错",它可能会续写:"去公园玩吧。"
|
||||||
|
但如果你输入:"美国的首都是哪里?",它可能会续写:"中国首都是哪里?..."
|
||||||
|
|
||||||
|
### 5.2 技巧:用"剧本"来对话
|
||||||
|
|
||||||
|
为了让它变成对话助手,工程师们想出了一个绝妙的办法:**角色扮演**。
|
||||||
|
我们在输入给模型的内容里,悄悄加了一些特殊的**标签**...
|
||||||
|
```
|
||||||
|
|
||||||
|
**叙事结构**:
|
||||||
|
|
||||||
|
```
|
||||||
|
现象(ChatGPT 会对话)
|
||||||
|
↓
|
||||||
|
打破误解(它只是在续写)
|
||||||
|
↓
|
||||||
|
揭示本质(Next Token Prediction)
|
||||||
|
↓
|
||||||
|
技巧揭秘(Template 角色扮演)
|
||||||
|
↓
|
||||||
|
深度交互(TrainingInferenceDemo)
|
||||||
|
```
|
||||||
|
|
||||||
|
**要点**:
|
||||||
|
|
||||||
|
- 用"揭秘"作为章节标题
|
||||||
|
- 用"很多人会误以为..."制造悬念
|
||||||
|
- 用"但其实..."转折到真相
|
||||||
|
- 用"本质只有一个"强调核心
|
||||||
|
|
||||||
|
#### 原则 6:从基础到前沿(拓展式讲解)
|
||||||
|
|
||||||
|
**在讲完核心原理后,介绍最新进展,保持内容的先进性**。
|
||||||
|
|
||||||
|
**示例(llm-intro.md 第 7 章)**:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 7. 前沿探索:会思考的模型、MoE 架构与线性注意力机制
|
||||||
|
|
||||||
|
随着技术的发展,我们发现仅仅靠"预测下一个词"有时候会犯蠢...
|
||||||
|
于是,新一代的 **Thinking Models**(如 OpenAI o1, DeepSeek-R1)诞生了。
|
||||||
|
|
||||||
|
### 7.1 什么是"思考"?
|
||||||
|
|
||||||
|
- **快思考 (System 1)**:凭直觉,脱口而出。容易犯错。
|
||||||
|
- **慢思考 (System 2)**:通过产生"思维链",一步步推理。
|
||||||
|
|
||||||
|
### 7.5 架构进化:从"全能"到"专家团"(Dense vs MoE)
|
||||||
|
|
||||||
|
- **Dense(稠密模型)**:比喻为一个**全能天才**...
|
||||||
|
- **MoE(混合专家模型)**:比喻为一个**专家团队**...
|
||||||
|
```
|
||||||
|
|
||||||
|
**拓展维度**:
|
||||||
|
|
||||||
|
1. **算法演进**:传统 → 现代
|
||||||
|
2. **架构优化**:Dense → MoE
|
||||||
|
3. **效率提升**:标准 Attention → Linear Attention
|
||||||
|
|
||||||
|
**要点**:
|
||||||
|
|
||||||
|
- 用"前沿探索"作为章节标题
|
||||||
|
- 说明"为什么需要新东西"
|
||||||
|
- 用比喻降低理解难度(如"专家团队")
|
||||||
|
- 提供实战指南(Prompt 风格变化)
|
||||||
|
|
||||||
|
### 1.2 章节编排的六个层次
|
||||||
|
|
||||||
|
一个完整的交互式教程应该包含以下层次(从浅到深):
|
||||||
|
|
||||||
|
```
|
||||||
|
层次 0:引子 (类比 + 核心挑战)
|
||||||
|
层次 1:基础概念 (是什么 + 怎么做)
|
||||||
|
层次 2:设计动机 (为什么不用朴素方案)
|
||||||
|
层次 3:核心机制 (本质原理 + 可视化)
|
||||||
|
层次 4:实践应用 (数据格式 + 使用场景)
|
||||||
|
层次 5:前沿拓展 (最新技术 + 未来趋势)
|
||||||
|
```
|
||||||
|
|
||||||
|
**对照检查**:
|
||||||
|
|
||||||
|
- ✅ 每个层次是否有对应章节?
|
||||||
|
- ✅ 层次之间是否有逻辑连接?
|
||||||
|
- ✅ 是否提供了交互式演示?
|
||||||
|
|
||||||
|
### 1.3 段落内的微观展开
|
||||||
|
|
||||||
|
每个段落内部也遵循 **"提出问题 → 分析问题 → 解决问题"** 的三段式结构:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
[提出问题]
|
||||||
|
计算机看不懂"汉堡"这两个字,它只认识数字。
|
||||||
|
所以,我们的第一个任务是:**把文本切分成计算机能理解的最小单位**。
|
||||||
|
|
||||||
|
[分析问题]
|
||||||
|
|
||||||
|
- **英文**:自带空格,天然容易分词(如 `I love AI`)。
|
||||||
|
- **中文**:没有空格,需要算法来切分(如 `我爱人工智能`)。
|
||||||
|
|
||||||
|
[解决问题]
|
||||||
|
现代 LLM(如 GPT-4)通常使用 **Subword Tokenization(子词分词)** 技术(如 BPE 算法)。
|
||||||
|
它的聪明之处在于:
|
||||||
|
|
||||||
|
- **常用词**(如 "apple")保持完整,作为一个 Token。
|
||||||
|
- **生僻词**(如 "applepie")拆分成常见片段("apple" + "pie")。
|
||||||
|
```
|
||||||
|
|
||||||
|
**要点**:
|
||||||
|
|
||||||
|
- 第一段:提出问题(用粗体强调任务)
|
||||||
|
- 第二段:分析问题(用列表对比)
|
||||||
|
- 第三段:解决问题(说明方案和优势)
|
||||||
|
|
||||||
|
## 二、文章结构规范
|
||||||
|
|
||||||
|
### 2.1 标题与学习指南
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# 主题名称 (English Title)
|
||||||
|
|
||||||
|
> 💡 **学习指南**:本章节[前置要求],通过[教学方式]带你深入了解[核心主题]。我们将从[起点]开始,一直到[终点]。
|
||||||
|
```
|
||||||
|
|
||||||
|
**要点**:
|
||||||
|
|
||||||
|
- 标题使用中英双语,括号标注
|
||||||
|
- 学习指南块说明:前置要求、教学方式、学习路径
|
||||||
|
- 降低读者焦虑,强调"无需XX基础"
|
||||||
|
|
||||||
|
### 2.2 引子:从问题到动机
|
||||||
|
|
||||||
|
**结构**:
|
||||||
|
|
||||||
|
1. **类比/比喻**:用日常生活中的例子引入
|
||||||
|
2. **核心挑战**:列出 3 个左右要解决的问题
|
||||||
|
3. **路线图**:预告章节结构
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## 0. 引言:从[熟悉概念]到[新概念]
|
||||||
|
|
||||||
|
[用类比连接两个概念]
|
||||||
|
|
||||||
|
它的核心任务只有一个:**[一句话总结核心目标]**。
|
||||||
|
|
||||||
|
为了实现这个目标,我们需要解决三个核心挑战:
|
||||||
|
|
||||||
|
1. **[挑战1]**:[为什么需要]
|
||||||
|
2. **[挑战2]**:[为什么需要]
|
||||||
|
3. **[挑战3]**:[为什么需要]
|
||||||
|
|
||||||
|
本教程将带你从零开始,一步步拆解[核心主题]的构建过程。
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.3 主体章节结构
|
||||||
|
|
||||||
|
每个知识点遵循 **"问题 → 方案 → 对比 → 演示"** 的结构:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## N. [章节标题]
|
||||||
|
|
||||||
|
[段落1:提出问题/当前困境]
|
||||||
|
|
||||||
|
### N.1 [子问题标题]
|
||||||
|
|
||||||
|
[解释问题产生的背景/原因]
|
||||||
|
|
||||||
|
### N.2 [解决方案标题]
|
||||||
|
|
||||||
|
[提出解决方案,解释其核心思想]
|
||||||
|
|
||||||
|
**关键点**:[一句话总结核心概念]
|
||||||
|
|
||||||
|
<[InteractiveDemo />
|
||||||
|
```
|
||||||
|
|
||||||
|
**要点**:
|
||||||
|
|
||||||
|
- 用问答式标题("什么是XX?" "为什么不用XX?")
|
||||||
|
- 用列表和粗体强调重点
|
||||||
|
- 每个关键概念后紧跟交互式演示
|
||||||
|
|
||||||
|
### 2.4 对比分析表格
|
||||||
|
|
||||||
|
当需要对比多个选项时,使用表格:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
| 特性 | [选项A] | [选项B] |
|
||||||
|
| :----------- | :----------------- | :----------------- |
|
||||||
|
| **核心逻辑** | **[描述]** | **[描述]** |
|
||||||
|
| **优点** | [优点1]<br>[优点2] | [优点1]<br>[优点2] |
|
||||||
|
| **缺点** | [缺点1]<br>[缺点2] | [缺点1]<br>[缺点2] |
|
||||||
|
| **适用场景** | [场景1] | [场景2] |
|
||||||
|
|
||||||
|
> ⚠️ **注意**:[使用建议或注意事项]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.5 数据示例
|
||||||
|
|
||||||
|
当涉及数据格式时,提供 JSON 示例:
|
||||||
|
|
||||||
|
````markdown
|
||||||
|
- **数据示例 (JSON 格式)**:
|
||||||
|
```json
|
||||||
|
// [注释说明这是什么数据]
|
||||||
|
{
|
||||||
|
"field1": "值1",
|
||||||
|
"field2": "值2"
|
||||||
|
}
|
||||||
|
// 模型学会了:[解释这个数据的作用]
|
||||||
|
```
|
||||||
|
````
|
||||||
|
|
||||||
|
### 2.6 名词速查表
|
||||||
|
|
||||||
|
文章末尾提供 Glossary:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## N. 名词速查表 (Glossary)
|
||||||
|
|
||||||
|
| 名词 | 全称 | 解释 |
|
||||||
|
| :-------- | :---------- | :------------------------------------- |
|
||||||
|
| **TERM1** | Full Name 1 | **简短中文说明**。详细解释为什么重要。 |
|
||||||
|
| **TERM2** | Full Name 2 | **简短中文说明**。详细解释。 |
|
||||||
|
```
|
||||||
|
|
||||||
|
## 三、交互式组件规范
|
||||||
|
|
||||||
|
### 3.1 组件文件组织
|
||||||
|
|
||||||
|
**目录结构**:
|
||||||
|
|
||||||
|
```
|
||||||
|
docs/.vitepress/theme/components/appendix/{topic-name}/
|
||||||
|
├── {Concept}Demo.vue # 主演示组件
|
||||||
|
├── {Concept}Demo.vue # 其他相关组件
|
||||||
|
└── ...
|
||||||
|
```
|
||||||
|
|
||||||
|
**命名规范**:
|
||||||
|
|
||||||
|
- 使用 PascalCase
|
||||||
|
- 描述性强,如 `TokenizationDemo.vue`、`EmbeddingDemo.vue`
|
||||||
|
- 与 Markdown 中引用的组件名一致
|
||||||
|
|
||||||
|
### 3.2 组件开发规范
|
||||||
|
|
||||||
|
#### 3.2.1 文件头注释
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<!--
|
||||||
|
ComponentName.vue
|
||||||
|
组件用途简述
|
||||||
|
|
||||||
|
用途:
|
||||||
|
[详细说明这个组件要展示什么概念,解决什么教学问题]
|
||||||
|
|
||||||
|
交互功能:
|
||||||
|
- [功能1]:[说明]
|
||||||
|
- [功能2]:[说明]
|
||||||
|
- [功能3]:[说明]
|
||||||
|
-->
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.2.2 模板结构
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<div class="[component-name]">
|
||||||
|
<!-- 控制面板(如果有) -->
|
||||||
|
<div class="control-panel">[输入控件、模式切换等]</div>
|
||||||
|
|
||||||
|
<!-- 可视化区域 -->
|
||||||
|
<div class="visualization-area">[核心可视化内容]</div>
|
||||||
|
|
||||||
|
<!-- 说明文字 -->
|
||||||
|
<div class="info-box">
|
||||||
|
<p>
|
||||||
|
<span class="icon">💡</span>
|
||||||
|
<strong>Note:</strong>
|
||||||
|
[教育性说明文字]
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
**层级结构**:
|
||||||
|
|
||||||
|
- `.control-panel`:控制区(输入、切换按钮)
|
||||||
|
- `.visualization-area`:核心可视化区
|
||||||
|
- `.info-box`:说明提示框
|
||||||
|
|
||||||
|
#### 3.2.3 脚本编写
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
|
||||||
|
// 响应式状态
|
||||||
|
const [stateName] = ref([initialValue])
|
||||||
|
|
||||||
|
// 计算属性
|
||||||
|
const [computedName] = computed(() => {
|
||||||
|
// 逻辑处理
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
|
||||||
|
// 方法
|
||||||
|
const [methodName] = ([params]) => {
|
||||||
|
// 方法实现
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
**要点**:
|
||||||
|
|
||||||
|
- 使用 Vue 3 Composition API (`<script setup>`)
|
||||||
|
- 优先使用 `ref` 和 `computed`
|
||||||
|
- 保持逻辑简洁,复杂计算应有注释
|
||||||
|
|
||||||
|
#### 3.2.4 样式规范
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<style scoped>
|
||||||
|
.[component-name] {
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: var(--vp-c-bg-soft);
|
||||||
|
padding: 1.5rem;
|
||||||
|
margin: 1rem 0;
|
||||||
|
font-family: var(--vp-font-family-mono);
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-panel {
|
||||||
|
/* 控制面板样式 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.visualization-area {
|
||||||
|
/* 可视化区域样式 */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
```
|
||||||
|
|
||||||
|
**CSS 变量使用**:
|
||||||
|
|
||||||
|
- `var(--vp-c-bg)`:主背景色
|
||||||
|
- `var(--vp-c-bg-soft)`:次背景色
|
||||||
|
- `var(--vp-c-bg-alt)`:交替背景色
|
||||||
|
- `var(--vp-c-divider)`:分隔线颜色
|
||||||
|
- `var(--vp-c-brand)`:主题色
|
||||||
|
- `var(--vp-c-text-1/2/3)`:文本颜色(1最深,3最浅)
|
||||||
|
|
||||||
|
**布局工具**:
|
||||||
|
|
||||||
|
- 使用 Flexbox:`display: flex; gap: 1rem;`
|
||||||
|
- 响应式:`@media (max-width: 640px) { ... }`
|
||||||
|
- 圆角:`border-radius: 6px/8px/12px`
|
||||||
|
- 过渡:`transition: all 0.2s`
|
||||||
|
|
||||||
|
### 3.3 交互设计原则
|
||||||
|
|
||||||
|
#### 3.3.1 即时反馈
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 用户操作立即触发视觉反馈
|
||||||
|
const handleInput = (value) => {
|
||||||
|
result.value = processInput(value)
|
||||||
|
// 不需要点击"提交"按钮
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.3.2 颜色编码
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 使用颜色区分不同状态/类型
|
||||||
|
const colorClasses = [
|
||||||
|
'color-0', // rgba(255, 99, 132, 0.2) - 红色
|
||||||
|
'color-1', // rgba(54, 162, 235, 0.2) - 蓝色
|
||||||
|
'color-2', // rgba(255, 206, 86, 0.2) - 黄色
|
||||||
|
'color-3', // rgba(75, 192, 192, 0.2) - 青色
|
||||||
|
'color-4' // rgba(153, 102, 255, 0.2) - 紫色
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.3.3 多模式支持
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 提供不同视角/模式
|
||||||
|
const modes = [
|
||||||
|
{ id: 'mode1', label: '模式1', desc: '说明' },
|
||||||
|
{ id: 'mode2', label: '模式2', desc: '说明' }
|
||||||
|
]
|
||||||
|
|
||||||
|
const currentMode = ref('mode1')
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.3.4 动画效果
|
||||||
|
|
||||||
|
```css
|
||||||
|
/* 淡入动画 */
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(5px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 脉冲动画 */
|
||||||
|
@keyframes pulse {
|
||||||
|
0% {
|
||||||
|
opacity: 0.4;
|
||||||
|
transform: scale(0.8);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0.4;
|
||||||
|
transform: scale(0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 弹性过渡 */
|
||||||
|
transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.4 常见组件模式
|
||||||
|
|
||||||
|
#### 3.4.1 输入演示型
|
||||||
|
|
||||||
|
**示例**:`TokenizationDemo.vue`
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<div class="demo">
|
||||||
|
<div class="input-group">
|
||||||
|
<label>Input</label>
|
||||||
|
<textarea v-model="inputText"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="output">
|
||||||
|
<div v-for="item in processedItems" :key="item.id">
|
||||||
|
{{ item }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const inputText = ref('默认示例文本')
|
||||||
|
|
||||||
|
const processedItems = computed(() => {
|
||||||
|
return process(inputText.value)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.4.2 模式切换型
|
||||||
|
|
||||||
|
**示例**:`EmbeddingDemo.vue`
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<div class="demo">
|
||||||
|
<div class="mode-selector">
|
||||||
|
<button
|
||||||
|
v-for="mode in modes"
|
||||||
|
:key="mode.id"
|
||||||
|
:class="{ active: currentMode === mode.id }"
|
||||||
|
@click="currentMode = mode.id"
|
||||||
|
>
|
||||||
|
{{ mode.label }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
{{ modes.find((m) => m.id === currentMode)?.content }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.4.3 步骤引导型
|
||||||
|
|
||||||
|
**示例**:`TrainingInferenceDemo.vue`(假设)
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<div class="demo">
|
||||||
|
<div class="steps">
|
||||||
|
<button
|
||||||
|
v-for="(step, index) in steps"
|
||||||
|
:key="index"
|
||||||
|
:class="{ active: currentStep === index }"
|
||||||
|
@click="currentStep = index"
|
||||||
|
>
|
||||||
|
{{ step.title }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="step-content">
|
||||||
|
{{ steps[currentStep].content }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 四、Markdown 使用技巧
|
||||||
|
|
||||||
|
### 4.1 组件引用
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
<ConceptDemo />
|
||||||
|
|
||||||
|
<!-- 带间距 -->
|
||||||
|
<ConceptDemo />
|
||||||
|
|
||||||
|
<!-- 多个组件 -->
|
||||||
|
<Demo1 />
|
||||||
|
<Demo2 />
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 代码块
|
||||||
|
|
||||||
|
````markdown
|
||||||
|
```javascript
|
||||||
|
// 代码示例
|
||||||
|
const example = 'highlighted'
|
||||||
|
```
|
||||||
|
````
|
||||||
|
|
||||||
|
### 4.3 强调与标注
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
**粗体强调**
|
||||||
|
_斜体_
|
||||||
|
`代码片段`
|
||||||
|
|
||||||
|
> 引用块
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.4 分隔线
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- 使用分隔线区分不同主题 -->
|
||||||
|
```
|
||||||
|
|
||||||
|
## 五、最佳实践
|
||||||
|
|
||||||
|
### 5.1 内容层面
|
||||||
|
|
||||||
|
1. **从具体到抽象**:先展示效果,再解释原理
|
||||||
|
2. **用类比降低认知负担**:如"Tokenizer 就像翻译官"
|
||||||
|
3. **多问"为什么"**:解释设计动机,不只讲是什么
|
||||||
|
4. **保持简洁**:每个知识点控制在 200-300 字
|
||||||
|
|
||||||
|
### 5.2 交互层面
|
||||||
|
|
||||||
|
1. **提供默认值**:让用户打开即见效果
|
||||||
|
2. **即时反馈**:不需要点击"提交"才看结果
|
||||||
|
3. **容错性**:输入验证,友好提示错误
|
||||||
|
4. **移动端适配**:使用 `@media` 查询
|
||||||
|
|
||||||
|
### 5.3 可视化层面
|
||||||
|
|
||||||
|
1. **颜色有意义**:不仅美观,更要传递信息
|
||||||
|
2. **动画适度**:增强理解,不干扰阅读
|
||||||
|
3. **层次清晰**:用阴影、边框、间距区分层级
|
||||||
|
4. **统一风格**:项目内组件使用相似的设计语言
|
||||||
|
|
||||||
|
### 5.4 性能优化
|
||||||
|
|
||||||
|
1. **计算属性缓存**:使用 `computed` 而非方法
|
||||||
|
2. **避免不必要的响应式**:静态数据用 `const`
|
||||||
|
3. **懒加载**:复杂组件考虑按需加载
|
||||||
|
|
||||||
|
## 六、开发工作流
|
||||||
|
|
||||||
|
### 6.1 创建新教程步骤
|
||||||
|
|
||||||
|
1. **规划内容**:
|
||||||
|
- 列出要讲解的核心概念
|
||||||
|
- 为每个概念设计交互演示
|
||||||
|
- 画出组件草图
|
||||||
|
|
||||||
|
2. **创建组件**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p docs/.vitepress/theme/components/appendix/{topic-name}
|
||||||
|
touch docs/.vitepress/theme/components/appendix/{topic-name}/{Concept}Demo.vue
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **编写组件**:
|
||||||
|
- 添加文件头注释
|
||||||
|
- 实现 `<template>`、`<script setup>`、`<style scoped>`
|
||||||
|
- 本地测试交互效果
|
||||||
|
|
||||||
|
4. **编写文档**:
|
||||||
|
- 创建 Markdown 文件
|
||||||
|
- 按照文章结构规范编写
|
||||||
|
- 在适当位置嵌入组件
|
||||||
|
|
||||||
|
5. **测试发布**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev # 本地预览
|
||||||
|
npm run build # 构建检查
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 调试技巧
|
||||||
|
|
||||||
|
1. **Vue DevTools**:检查组件状态
|
||||||
|
2. **Console.log**:输出中间结果
|
||||||
|
3. **简化测试**:先用静态数据测试布局
|
||||||
|
|
||||||
|
## 七、示例对照
|
||||||
|
|
||||||
|
参考以下文件学习完整实现:
|
||||||
|
|
||||||
|
| 文件 | 说明 |
|
||||||
|
| --------------------------------------------------------------------------- | -------------- |
|
||||||
|
| `docs/zh-cn/appendix/llm-intro.md` | 完整的文章结构 |
|
||||||
|
| `docs/.vitepress/theme/components/appendix/llm-intro/LlmQuickStartDemo.vue` | 聊天交互型组件 |
|
||||||
|
| `docs/.vitepress/theme/components/appendix/llm-intro/TokenizationDemo.vue` | 输入处理型组件 |
|
||||||
|
| `docs/.vitepress/theme/components/appendix/llm-intro/EmbeddingDemo.vue` | 模式切换型组件 |
|
||||||
|
|
||||||
|
## 八、检查清单
|
||||||
|
|
||||||
|
发布前确认:
|
||||||
|
|
||||||
|
- [ ] 文章结构完整(标题、引言、主体、总结)
|
||||||
|
- [ ] 每个核心概念都有交互演示
|
||||||
|
- [ ] 组件有文件头注释
|
||||||
|
- [ ] 使用 VitePress CSS 变量
|
||||||
|
- [ ] 响应式设计(移动端测试)
|
||||||
|
- [ ] 默认值示例让组件"打开即用"
|
||||||
|
- [ ] 动画流畅不卡顿
|
||||||
|
- [ ] 文字无错别字
|
||||||
|
- [ ] 代码示例可运行
|
||||||
|
- [ ] `npm run build` 成功
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**总结**:优秀的交互式教程 = 清晰的逻辑 + 即时的反馈 + 精致的可视化。遵循本规范,可以创建出让读者"秒懂"复杂概念的高质量内容。
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"cSpell.words": [],
|
||||||
|
"pasteImage.path": "${currentFileDir}/images",
|
||||||
|
"pasteImage.defaultName": "${currentFileNameWithoutExt}-YYYY-MM-DD-HH-mm-ss",
|
||||||
|
"pasteImage.prefix": "images/",
|
||||||
|
"pasteImage.insertPattern": "",
|
||||||
|
"pasteImage.basePath": "${currentFileDir}/images",
|
||||||
|
"markdown.copyFiles.destination": {
|
||||||
|
"*.md": "images/${fileName}"
|
||||||
|
},
|
||||||
|
"markdown.editor.drop.enabled": false,
|
||||||
|
"markdown.editor.pasteUrlAsFormattedLink.enabled": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# Repository Guidelines
|
||||||
|
|
||||||
|
## Project Structure & Module Organization
|
||||||
|
|
||||||
|
- `docs/`: VitePress site source (Markdown content, sidebar/nav, assets referenced by docs).
|
||||||
|
- `docs/.vitepress/theme/`: custom theme, global component registration in `index.js`, shared styles in `style.css`, layout in `Layout.vue`.
|
||||||
|
- `docs/.vitepress/theme/components/appendix/*/`: interactive Vue demos used inside appendix pages (e.g. `web-basics/`, `deployment/`).
|
||||||
|
- `assets/`: repo-level images/media (if referenced, prefer linking/copying into `docs/public/` or a doc-local folder when appropriate).
|
||||||
|
- `scripts/`, `tools/`, `update_readmes.cjs`: utility scripts for maintaining docs.
|
||||||
|
|
||||||
|
## Build, Test, and Development Commands
|
||||||
|
|
||||||
|
This repo is a VitePress (Vue 3) documentation project. Requires Node.js **>= 18**.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
npm run dev # start local docs server (hot reload)
|
||||||
|
npm run build # production build (use as CI-style check)
|
||||||
|
npm run preview # preview the built site locally
|
||||||
|
npm run format # run Prettier on the whole repo
|
||||||
|
```
|
||||||
|
|
||||||
|
## Coding Style & Naming Conventions
|
||||||
|
|
||||||
|
- Formatting: Prettier (`npm run format`). Keep diffs small and avoid reformatting unrelated files.
|
||||||
|
- Vue components: Vue 3 SFCs with `<script setup>`, PascalCase filenames (e.g. `SemanticTagsDemo.vue`).
|
||||||
|
- CSS: prefer VitePress theme variables (`var(--vp-c-*)`) and keep components responsive (`@media (max-width: 720px)` when needed).
|
||||||
|
- Docs: use clear headings and short paragraphs; components are referenced in Markdown as `<ComponentName />`.
|
||||||
|
|
||||||
|
## Testing Guidelines
|
||||||
|
|
||||||
|
There is no dedicated test framework in this repo. Use `npm run build` as the primary correctness check, and manually verify interactive components in `npm run dev`.
|
||||||
|
|
||||||
|
## Commit & Pull Request Guidelines
|
||||||
|
|
||||||
|
- Commits follow a Conventional Commits style seen in history: `feat: ...`, `fix: ...`, `docs: ...` (optionally scoped like `feat(docs): ...`).
|
||||||
|
- PRs should include: a short description, screenshots/GIFs for UI or component changes, and any relevant paths touched (e.g. `docs/zh-cn/appendix/...`, `docs/.vitepress/theme/...`).
|
||||||
|
|
||||||
|
## Configuration & Deployment Notes
|
||||||
|
|
||||||
|
- `vercel.json` is present; keep builds reproducible and avoid relying on local-only assets.
|
||||||
@@ -0,0 +1,312 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
**Easy-Vibe** is an educational curriculum for learning AI Vibe Coding from zero to advanced levels. It's a documentation-based project using **VitePress** to serve educational content about AI-assisted software development.
|
||||||
|
|
||||||
|
The curriculum follows a progressive four-stage structure:
|
||||||
|
|
||||||
|
- **Stage 0 (幼儿园)**: Introduction to AI programming through games
|
||||||
|
- **Stage 1 (AI 产品经理)**: Building AI-powered web application prototypes
|
||||||
|
- **Stage 2 (初中级开发工程师)**: Full-stack development with databases and deployment
|
||||||
|
- **Stage 3 (高级开发工程师)**: Cross-platform development (WeChat mini-programs, Android apps, MCP)
|
||||||
|
|
||||||
|
## Development Commands
|
||||||
|
|
||||||
|
### Start Local Documentation Server
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install # Install dependencies (first time only)
|
||||||
|
npm run dev # Start VitePress dev server
|
||||||
|
```
|
||||||
|
|
||||||
|
The documentation will be available at `http://localhost:5173` (VitePress default port)
|
||||||
|
|
||||||
|
### Build/Run Commands
|
||||||
|
|
||||||
|
- `npm run dev` - Start VitePress development server with hot reload
|
||||||
|
- `npm run build` - Build static site for production (outputs to `docs/.vitepress/dist`)
|
||||||
|
- `npm run preview` - Preview production build locally
|
||||||
|
- `npm run format` - Format code using Prettier
|
||||||
|
|
||||||
|
### Node Version Requirement
|
||||||
|
|
||||||
|
- Node.js >= 18.0.0 required (specified in package.json `engines`)
|
||||||
|
|
||||||
|
## Project Architecture
|
||||||
|
|
||||||
|
### VitePress Base Path Configuration
|
||||||
|
|
||||||
|
The site automatically configures its base path based on the deployment environment:
|
||||||
|
|
||||||
|
- **Vercel**: Uses `/` as base (detected via `VERCEL` environment variable)
|
||||||
|
- **GitHub Pages / Local**: Uses `/easy-vibe/` as base
|
||||||
|
|
||||||
|
This logic is in `docs/.vitepress/config.mjs:3-5`. When linking assets or configuring paths, the `${base}` variable is used to ensure compatibility across environments.
|
||||||
|
|
||||||
|
### Directory Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
easy-vibe/
|
||||||
|
├── docs/ # Main documentation content (served by VitePress)
|
||||||
|
│ ├── .vitepress/ # VitePress configuration and theme
|
||||||
|
│ │ ├── config.mjs # Site configuration (nav, sidebar, plugins)
|
||||||
|
│ │ ├── theme/ # Custom theme extensions
|
||||||
|
│ │ │ ├── Layout.vue # Override default layout with typewriter effect
|
||||||
|
│ │ │ ├── index.js # Theme setup (Viewer.js, TypeIt, image optimization)
|
||||||
|
│ │ │ └── style.css # Custom CSS overrides
|
||||||
|
│ │ ├── dist/ # Production build output (generated)
|
||||||
|
│ │ └── cache/ # VitePress cache (generated)
|
||||||
|
│ ├── index.md # Homepage
|
||||||
|
│ ├── public/ # Static assets (logo.png, etc.)
|
||||||
|
│ ├── assets/ # Symlink to ../assets
|
||||||
|
│ ├── stage-1/ # Stage 1 content (AI 产品经理)
|
||||||
|
│ ├── stage-2/ # Stage 2 content (初中级开发工程师)
|
||||||
|
│ ├── stage-3/ # Stage 3 content (高级开发工程师)
|
||||||
|
│ ├── appendix/ # Reference materials (AI capability dictionary)
|
||||||
|
│ ├── examples/ # Practical examples and tutorials (legacy)
|
||||||
|
│ ├── extra/ # Additional knowledge (Git, API, RAG, etc.)
|
||||||
|
│ ├── guide/ # Course guide
|
||||||
|
│ └── project/ # Legacy project documentation
|
||||||
|
├── assets/ # Images and static assets
|
||||||
|
├── package.json # Project dependencies and scripts
|
||||||
|
├── vercel.json # Vercel deployment configuration
|
||||||
|
└── README.md # Project overview and contribution guide
|
||||||
|
```
|
||||||
|
|
||||||
|
### Content Organization
|
||||||
|
|
||||||
|
Each stage follows a numbered chapter structure:
|
||||||
|
|
||||||
|
```
|
||||||
|
stage-{N}/
|
||||||
|
└── {category or chapter-dir}/
|
||||||
|
└── index.md # Main content file (or .md file directly)
|
||||||
|
```
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
- `stage-1/introduction-to-ai-ide/index.md`
|
||||||
|
- `stage-2/backend/what-is-api/extra2/extra2-what-is-api.md`
|
||||||
|
|
||||||
|
**Note**: Content files may use either `index.md` or direct `.md` files depending on the chapter structure.
|
||||||
|
|
||||||
|
### Documentation System (VitePress)
|
||||||
|
|
||||||
|
The project uses **VitePress 2.0.0-alpha.15** with these key features:
|
||||||
|
|
||||||
|
**Configuration** (`docs/.vitepress/config.mjs`):
|
||||||
|
|
||||||
|
- **Single Sidebar**: Route-based sidebars configured per path prefix (`/stage-1/`, etc.)
|
||||||
|
- **Navigation**: Top nav with links to each stage and appendix
|
||||||
|
- **Search**: Local search via `minisearch` (no external API required)
|
||||||
|
- **Dark Mode**: Built-in VitePress theme with toggle
|
||||||
|
|
||||||
|
**Custom Theme** (`docs/.vitepress/theme/`):
|
||||||
|
|
||||||
|
- **Image Viewer**: Viewer.js integration for zoom/rotate/flip on all images
|
||||||
|
- **Typewriter Effect**: TypeIt.js for homepage hero tagline animation
|
||||||
|
- **Image Optimization**: Automatic image height classes based on aspect ratio
|
||||||
|
- **Custom Layout**: Extends default theme with `Layout.vue` override
|
||||||
|
- **Reading Settings**: Element Plus popover panel for adjusting font size (12-18px) and line height (1.25-1.8) with localStorage persistence
|
||||||
|
|
||||||
|
**Key Theme Behaviors**:
|
||||||
|
|
||||||
|
- Images with aspect ratio > 1.2 get height-limited classes (tall/very-tall/ultra-tall)
|
||||||
|
- Viewer.js initialized on `.vp-doc` container on each route change
|
||||||
|
- Typewriter effect only activates on homepage when `frontmatter.hero.tagline` is an array
|
||||||
|
- Font size/line height adjustments use CSS custom properties `--ev-doc-font-size` and `--ev-doc-line-height`
|
||||||
|
- Reading settings panel appears in nav bar after the search/home buttons (gear icon)
|
||||||
|
|
||||||
|
### Sidebar Management
|
||||||
|
|
||||||
|
The sidebar is defined in `docs/.vitepress/config.mjs`. When adding new chapters:
|
||||||
|
|
||||||
|
1. Locate the appropriate route prefix section (`/stage-1/`, etc.)
|
||||||
|
2. Add a new object with `text` (display name) and `link` (relative path)
|
||||||
|
3. For nested items, use `items` array with `collapsed: true|false`
|
||||||
|
4. **Links should not include `.md` extension** - VitePress handles this
|
||||||
|
5. Links should not include `index` - use directory path with trailing slash
|
||||||
|
|
||||||
|
Example pattern:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
text: 'Chapter Title',
|
||||||
|
link: '/stage-1/chapter-directory/' // Note: trailing slash, no .md
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Asset Management
|
||||||
|
|
||||||
|
- Root-level static assets are in `/assets/` at project root
|
||||||
|
- Public files (favicon, logo) go in `docs/public/`
|
||||||
|
- Images are referenced with relative paths from markdown file location
|
||||||
|
- VitePress serves `docs/assets` as symlink to `../assets`
|
||||||
|
- Image optimization is automatic via theme (height-limited classes based on aspect ratio)
|
||||||
|
|
||||||
|
### Deployment
|
||||||
|
|
||||||
|
**Vercel** (vercel.json):
|
||||||
|
|
||||||
|
- Build command: `npm run build`
|
||||||
|
- Output directory: `docs/.vitepress/dist`
|
||||||
|
- Framework: vitepress
|
||||||
|
|
||||||
|
**Preview Production Build**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build
|
||||||
|
npm run preview # Preview built site locally
|
||||||
|
```
|
||||||
|
|
||||||
|
### Legacy Content Structure
|
||||||
|
|
||||||
|
The project maintains three legacy sections for backward compatibility:
|
||||||
|
|
||||||
|
1. **Project 文档** (`project/`): Older chapter-based tutorials (migrated to Stage 2)
|
||||||
|
2. **Extra 扩展知识** (`extra/`): Supplementary topics - Git, APIs, RAG, deployment (migrated to Stage 2/3)
|
||||||
|
3. **Examples 实战案例** (`examples/`): Practical tutorials (migrated to Stage 0/3)
|
||||||
|
|
||||||
|
When updating content, prefer integrating into the stage structure over adding to legacy sections.
|
||||||
|
|
||||||
|
## Content Guidelines
|
||||||
|
|
||||||
|
### Writing New Chapters
|
||||||
|
|
||||||
|
1. Create directory: `docs/stage-{N}/{chapter-directory}/`
|
||||||
|
2. Create `index.md` or direct `.md` file with chapter content
|
||||||
|
3. Update `docs/.vitepress/config.mjs` sidebar with the new entry
|
||||||
|
4. Follow Chinese language conventions (this is a Chinese curriculum)
|
||||||
|
|
||||||
|
### Content Status Markers
|
||||||
|
|
||||||
|
In README.md, use these status indicators:
|
||||||
|
|
||||||
|
- ✅ Completed
|
||||||
|
- 🚧 In progress/Under construction
|
||||||
|
|
||||||
|
### File Naming Conventions
|
||||||
|
|
||||||
|
- Use kebab-case for directories: `1.1-introduction-to-ai-ide`, `frontend`, `backend`
|
||||||
|
- Content can be either `index.md` in a directory or a direct `.md` file
|
||||||
|
- Images use descriptive names; can be in chapter subdirectories or root `/assets/`
|
||||||
|
|
||||||
|
### Code Formatting
|
||||||
|
|
||||||
|
Prettier configuration (`.prettierrc`):
|
||||||
|
|
||||||
|
- No semicolons (`semi: false`)
|
||||||
|
- Single quotes (`singleQuote: true`)
|
||||||
|
- No trailing commas (`trailingComma: "none"`)
|
||||||
|
|
||||||
|
Run `npm run format` before committing code changes.
|
||||||
|
|
||||||
|
## Interactive Vue Components
|
||||||
|
|
||||||
|
### Component Registration
|
||||||
|
|
||||||
|
All interactive Vue components for the documentation are registered in `docs/.vitepress/theme/index.js`. To add a new component:
|
||||||
|
|
||||||
|
1. Create the `.vue` file in the appropriate subdirectory of `docs/.vitepress/theme/components/`
|
||||||
|
2. Import the component in `docs/.vitepress/theme/index.js`
|
||||||
|
3. Register the component using `app.component('ComponentName', ComponentName)` in the `enhanceApp` function
|
||||||
|
|
||||||
|
### Component Categories
|
||||||
|
|
||||||
|
Components are organized by topic:
|
||||||
|
|
||||||
|
- `appendix/llm-intro/` - Large Language Model interactive demos
|
||||||
|
- `appendix/vlm-intro/` - Vision Language Model interactive demos
|
||||||
|
- `appendix/git-intro/` - Git workflow visualizations
|
||||||
|
- `appendix/terminal-intro/` - Terminal/CLI interactive demos
|
||||||
|
- `appendix/web-basics/` - HTML/CSS/JavaScript fundamentals
|
||||||
|
- `appendix/auth-design/` - Authentication/authorization demos
|
||||||
|
- `appendix/cache-design/` - Caching strategy visualizations
|
||||||
|
- `appendix/database-intro/` - Database fundamentals
|
||||||
|
- `appendix/queue-design/` - Message queue demos
|
||||||
|
- `appendix/operations/` - DevOps/monitoring demos
|
||||||
|
- `appendix/deployment/` - Deployment architecture demos
|
||||||
|
- `appendix/frontend-performance/` - Frontend performance demos
|
||||||
|
- `appendix/frontend-evolution/` - Frontend history/evolution demos
|
||||||
|
- `appendix/backend-evolution/` - Backend architecture evolution
|
||||||
|
- `appendix/backend-languages/` - Backend language comparisons
|
||||||
|
|
||||||
|
### Using Components in Markdown
|
||||||
|
|
||||||
|
Components can be used directly in markdown files:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## LLM Basics
|
||||||
|
|
||||||
|
<LLMQuickStartDemo />
|
||||||
|
|
||||||
|
### Tokenization
|
||||||
|
|
||||||
|
<TokenizationDemo />
|
||||||
|
```
|
||||||
|
|
||||||
|
### Component Development Best Practices
|
||||||
|
|
||||||
|
1. **Props**: Use props for configurable demo parameters
|
||||||
|
2. **Styling**: Use scoped CSS or Tailwind-like utility classes
|
||||||
|
3. **Responsiveness**: Ensure components work on mobile and desktop
|
||||||
|
4. **Accessibility**: Include aria labels where appropriate
|
||||||
|
5. **i18n**: Keep text content minimal or use props for text
|
||||||
|
|
||||||
|
## Multi-language Support
|
||||||
|
|
||||||
|
### Supported Locales
|
||||||
|
|
||||||
|
The project supports 13 languages:
|
||||||
|
|
||||||
|
- `zh-cn` - Simplified Chinese (primary)
|
||||||
|
- `zh-tw` - Traditional Chinese
|
||||||
|
- `en-us` - English (US)
|
||||||
|
- `ja-jp` - Japanese
|
||||||
|
- `ko-kr` - Korean
|
||||||
|
- `es-es` - Spanish
|
||||||
|
- `fr-fr` - French
|
||||||
|
- `de-de` - German
|
||||||
|
- `ar-sa` - Arabic
|
||||||
|
- `vi-vn` - Vietnamese
|
||||||
|
|
||||||
|
### Adding Multi-language Content
|
||||||
|
|
||||||
|
1. Create content in `docs/{locale}/` following the same structure as `docs/zh-cn/`
|
||||||
|
2. Add locale configuration in `docs/.vitepress/config.mjs` under `locales`
|
||||||
|
3. Copy the sidebar structure from `zh-cn` and translate the text values
|
||||||
|
|
||||||
|
### Content Translation Priority
|
||||||
|
|
||||||
|
1. **Primary**: `zh-cn` (Simplified Chinese) - always complete this first
|
||||||
|
2. **Secondary**: `en-us` (English) - for international reach
|
||||||
|
3. **Tertiary**: Other languages based on contributor availability
|
||||||
|
|
||||||
|
## Permissions
|
||||||
|
|
||||||
|
The project has configured bash permissions in `.claude/settings.local.json`:
|
||||||
|
|
||||||
|
- File operations: `which`, `find`, `mv`, `tree`, `cat`, `curl`, `lsof`, `mkdir`, `cp`, `ls`
|
||||||
|
- Process management: `xargs ps`, `kill`
|
||||||
|
- Development: `npm run dev`, `npm run build`, `npm run preview`, `npm run format`
|
||||||
|
|
||||||
|
## Key Context for Development
|
||||||
|
|
||||||
|
- **Educational Focus**: This is curriculum content, not application code
|
||||||
|
- **Target Audience**: Beginners to advanced developers learning AI-assisted programming
|
||||||
|
- **Language**: Primary content is in Chinese
|
||||||
|
- **Build Pipeline**: VitePress requires build step for production (`npm run build`)
|
||||||
|
- **Git Workflow**: Content changes should preserve formatting and structure
|
||||||
|
- **Asset Paths**: Always use relative paths from markdown file location
|
||||||
|
|
||||||
|
When making changes:
|
||||||
|
|
||||||
|
- Preserve the VitePress configuration in `docs/.vitepress/config.mjs`
|
||||||
|
- Maintain sidebar structure consistency in config.mjs
|
||||||
|
- Test locally with `npm run dev` before committing
|
||||||
|
- Check that image links work correctly
|
||||||
|
- Ensure theme customizations in `.vitepress/theme/` are not broken
|
||||||
|
- Run `npm run format` before committing code changes (uses Prettier: no semicolons, single quotes)
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# ============================================================
|
||||||
|
# Easy-Vibe 魔搭创空间 (ModelScope Studio) 部署镜像
|
||||||
|
# 使用多阶段构建:先编译 VitePress 静态站点,再用 Nginx 提供服务
|
||||||
|
# 魔搭要求服务端口为 7860,通过 nginx.conf 配置监听
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
# ---- 构建阶段:Node.js 编译 VitePress 文档站 ----
|
||||||
|
FROM node:20-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# ---- 运行阶段:Nginx 提供静态文件服务 ----
|
||||||
|
FROM nginx:alpine
|
||||||
|
|
||||||
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
COPY --from=builder /app/docs/.vitepress/dist /usr/share/nginx/html
|
||||||
|
|
||||||
|
EXPOSE 7860
|
||||||
|
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 681 KiB |
|
After Width: | Height: | Size: 285 KiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 270 KiB |
|
After Width: | Height: | Size: 291 KiB |
|
After Width: | Height: | Size: 441 KiB |
|
After Width: | Height: | Size: 291 KiB |
|
After Width: | Height: | Size: 615 KiB |
|
After Width: | Height: | Size: 374 KiB |
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 348 KiB |
|
After Width: | Height: | Size: 460 KiB |
|
After Width: | Height: | Size: 162 KiB |
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"autoglm-browser-agent": {
|
||||||
|
"command": "/Users/sanbu/.agents/skills/autoglm-browser-agent/dist/mcp_server --start_url https://www.bing.com --window_width 1456 --window_height 819 --resize_width 1456 --resize_height 819 --max_steps 100 --log_dir /Users/sanbu/.agents/skills/autoglm-browser-agent/mcp_output --if_subagent"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"imports": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,448 @@
|
|||||||
|
<!-- trigger vercel build -->
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
<img src="../../assets/easy-vibe-logo-hd.svg" alt="شعار Easy-Vibe" width="300">
|
||||||
|
|
||||||
|
<img src="../../assets/banner.png" alt="بانر Easy-Vibe" width="100%">
|
||||||
|
|
||||||
|
<p align="center" style="font-size: 1.2em; color: #666; margin: 20px 0;">
|
||||||
|
ابدأ مباشرة وادخل معنا في الـ vibe. إذا كنت تستطيع التحدث، يمكنك بناء التطبيقات.<br>
|
||||||
|
<span style="font-size: 0.9em; color: #888;">直接上手,一起 vibe!会说话就会做应用。</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a href="https://trendshift.io/repositories/22079" target="_blank"><img src="https://trendshift.io/api/badge/repositories/22079" alt="datawhalechina/easy-vibe | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||||
|
|
||||||
|
<p align="center" style="font-size: 1.05em; color: #666; margin: 16px 0;">
|
||||||
|
你好 · Hello · 哈囉 · こんにちは · 안녕하세요 · Hola · Bonjour · Hallo · مرحبا · Xin chào<br>
|
||||||
|
أصبح الجزء الأول من دليلنا متاحا الآن بـ 10 لغات. نرحب بالأصدقاء من كل أنحاء العالم لنبدأ coding معا!<br>
|
||||||
|
<span style="font-size: 0.9em; color: #888;">我们的教程(第一部分)已经支持 10 种语言,欢迎世界各地的朋友一起 coding!</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
🚀 <a href="https://datawhalechina.github.io/easy-vibe/welcome.html">ابدأ الآن</a> · ✨ <a href="https://datawhalechina.github.io/easy-vibe/en/appendix/">دليل تفاعلي</a> · 🦞 <a href="https://github.com/datawhalechina/hello-claw">تعلّم OpenClaw</a> · 📖 <a href="#table-of-contents">جدول المحتويات</a><br>
|
||||||
|
<span style="font-size: 0.85em; color: #888;">🚀 <a href="https://datawhalechina.github.io/easy-vibe/welcome.html">开始体验</a> · ✨ <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/">交互式教程</a> · 🦞 <a href="https://github.com/datawhalechina/hello-claw">学习 OpenClaw</a> · 📖 <a href="#table-of-contents">查看目录</a></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://datawhalechina.github.io/easy-vibe/welcome.html">اقرأ عبر الإنترنت</a> ·
|
||||||
|
<a href="#-content-navigation">خريطة التعلّم</a><br>
|
||||||
|
<span style="font-size: 0.85em; color: #888;">
|
||||||
|
<a href="https://datawhalechina.github.io/easy-vibe/welcome.html">开始阅读</a> ·
|
||||||
|
<a href="#-content-navigation">学习地图</a>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/stargazers" target="_blank">
|
||||||
|
<img src="https://img.shields.io/github/stars/datawhalechina/easy-vibe?color=660874&style=for-the-badge&logo=star&logoColor=white&labelColor=1a1a2e" alt="Stars"></a>
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/network/members" target="_blank">
|
||||||
|
<img src="https://img.shields.io/github/forks/datawhalechina/easy-vibe?color=660874&style=for-the-badge&logo=git-fork&logoColor=white&labelColor=1a1a2e" alt="Forks"></a>
|
||||||
|
<a href="../../LICENSE" target="_blank">
|
||||||
|
<img src="https://img.shields.io/badge/License-CC_BY_NC_SA_4.0-4ecdc4?style=for-the-badge&logo=creative-commons&logoColor=white&labelColor=1a1a2e" alt="License"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="../zh-CN/README.md"><img alt="简体中文" src="https://img.shields.io/badge/简体中文-d9d9d9"></a>
|
||||||
|
<a href="../zh-TW/README.md"><img alt="繁體中文" src="https://img.shields.io/badge/繁體中文-d9d9d9"></a>
|
||||||
|
<a href="../en-US/README.md"><img alt="English" src="https://img.shields.io/badge/English-d9d9d9"></a>
|
||||||
|
<a href="../ja-JP/README.md"><img alt="日本語" src="https://img.shields.io/badge/日本語-d9d9d9"></a>
|
||||||
|
<a href="../es-ES/README.md"><img alt="Español" src="https://img.shields.io/badge/Español-d9d9d9"></a>
|
||||||
|
<a href="../fr-FR/README.md"><img alt="Français" src="https://img.shields.io/badge/Français-d9d9d9"></a>
|
||||||
|
<a href="../ko-KR/README.md"><img alt="한국어" src="https://img.shields.io/badge/한국어-d9d9d9"></a>
|
||||||
|
<a href="../ar-SA/README.md"><img alt="العربية" src="https://img.shields.io/badge/العربية-d9d9d9"></a>
|
||||||
|
<a href="../vi-VN/README.md"><img alt="Tiếng_Việt" src="https://img.shields.io/badge/Tiếng_Việt-d9d9d9"></a>
|
||||||
|
<a href="../de-DE/README.md"><img alt="Deutsch" src="https://img.shields.io/badge/Deutsch-d9d9d9"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<table align="center">
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-header.png" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>خريطة تعلّم للمبتدئين</strong>
|
||||||
|
<br>
|
||||||
|
<sub>إرشاد واضح من الصفر، لتنسى مشكلة "تعلّم ونسي"</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-tutorial.png" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>دروس مرئية خطوة بخطوة</strong>
|
||||||
|
<br>
|
||||||
|
<sub>شروحات مفصّلة كأنك تتعلم مع معلّم خاص</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-ide.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>برمجة محاكاة غامرة</strong>
|
||||||
|
<br>
|
||||||
|
<sub>فأر افتراضي يرشدك لتعلّم سير عمل IDE بسرعة</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-diffusion.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>مبادئ الذكاء الاصطناعي المرئية</strong>
|
||||||
|
<br>
|
||||||
|
<sub>شروحات متحركة تسهّل رؤية كيف تولّد الذكاء الاصطناعي الصور</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-rag.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>تعلّم RAG كأنك تلعب لعبة</strong>
|
||||||
|
<br>
|
||||||
|
<sub>مكونات تفاعلية تتيح لك النقر عبر تدفق بيانات RAG الكامل</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/git-terminal.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>مفاهيم الطرفية المرئية</strong>
|
||||||
|
<br>
|
||||||
|
<sub>سلوك سطر الأوامر يصبح حدسيًا عند تصور المنطق الأساسي</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div align="center">
|
||||||
|
<h3>⭐ <a href="https://github.com/datawhalechina/easy-vibe" style="color: #d0cd16ff;">ضع نجمة للمستودع هنا</a> للمساعدة في تسريع التحديثات ❤️</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align="center" style="margin: 30px 0;">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/issues/new?template=story_submission.md">
|
||||||
|
<img src="https://raw.githubusercontent.com/datawhalechina/easy-vibe/main/assets/stories_image.png" alt="شارك قصة Vibe الخاصة بك" width="80%" style="border-radius: 10px; box-shadow: 0 4px 12px rgba(0,0,0,0.15);">
|
||||||
|
</a>
|
||||||
|
<p style="margin-top: 15px; font-size: 1.1em; color: #666;">
|
||||||
|
📝 <strong>هل لديك قصة vibe coding خاصة بك؟</strong>
|
||||||
|
أرسلها هنا وألهم الآخرين!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## جدول المحتويات
|
||||||
|
|
||||||
|
- [لماذا Easy-Vibe](#لماذا-easy-vibe)
|
||||||
|
- [أخبار](#-news)
|
||||||
|
- [لمن هذا المشروع](#لمن-هذا-المشروع)
|
||||||
|
- [مسارات التعلّم الخاصة بك](#مسارات-التعلّم-الخاصة-بك)
|
||||||
|
- [نصائح الدراسة](#نصائح-الدراسة)
|
||||||
|
- [أولاً: دخول المبتدئين](#أولاً-دخول-المبتدئين)
|
||||||
|
- [ثانياً: المطورون المبتدئون والمتوسطون](#ثانياً-المطورون-المبتدئون-والمتوسطون)
|
||||||
|
- [ثالثاً: المطورون المتقدمون](#ثالثاً-المطورون-المتقدمون)
|
||||||
|
- [قاعدة المعرفة في الملحق](#-قاعدة-المعرفة-في-الملحق)
|
||||||
|
- [كيف تتعلم](#️-كيف-تتعلم)
|
||||||
|
- [التشغيل محلياً](#-التشغيل-محلياً)
|
||||||
|
- [دورات أخرى](#دورات-أخرى)
|
||||||
|
- [المساهمة والمساهمون](#-المساهمة-والمساهمون)
|
||||||
|
- [الترخيص](#-الترخيص)
|
||||||
|
|
||||||
|
## لماذا Easy-Vibe
|
||||||
|
|
||||||
|
تريد تطبيقا لتتبع الدخل والمصروفات؟ فقط قل ذلك.
|
||||||
|
|
||||||
|
تحتاج نظام حجز مع تسجيل دخول عبر WeChat؟ فقط قل ذلك.
|
||||||
|
|
||||||
|
تريد مدونة مع تعليقات؟ فقط قل ذلك.
|
||||||
|
|
||||||
|
في عصر الذكاء الاصطناعي، تبدأ البرمجة بوصف ما تريده.
|
||||||
|
|
||||||
|
Easy-Vibe يعلمك كيف تحول ذلك إلى منتج حقيقي.
|
||||||
|
|
||||||
|
|
||||||
|
## 🔥 News
|
||||||
|
|
||||||
|
- **[2026-05-20]** 🌍 **اكتمال تغطية المرحلة 1 متعددة اللغات**: اصبحت المرحلة 1 متاحة بالكامل بجميع اللغات المدعومة (zh-cn, en, zh-tw, ja-jp, ko-kr, es-es, fr-fr, de-de, ar-sa, vi-vn)، وتم التحقق من التنقل/البناء لتجنب 404.
|
||||||
|
- **[2026-03-29]** ✨ **إطلاق قسم قصص المستخدمين وتحديثه بأربع قصص حقيقية**: أضفنا في الصفحة الرئيسية شريط قصص تفاعليًا وصفحات مستقلة للقصص، ثم استبدلنا المحتوى المؤقت بأربع قصص حقيقية لمدرسة ريفية وطالبة جامعية ومعلم تقنية معلومات في الثانوية وسائق شاحنة بنوا منتجات حقيقية باستخدام الذكاء الاصطناعي. [👉 View the stories](https://datawhalechina.github.io/easy-vibe/zh-cn/vibe-stories/story-1.html)
|
||||||
|
- **[2026-03-26]** 🚀 **تحديث كبير لممارسة المرحلة 2**: اكتمل مشروع SaaS النهائي "[أول تطبيق SaaS full-stack: موقع مولد النصوص](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/fullstack-app/)" وتم توسيع قسم "[كيفية دمج Stripe وأنظمة الدفع](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/stripe-payment/)" بشكل كبير.
|
||||||
|
- **[2026-03-25]** 📚 **ملحق جديد: بحث المستخدم والتحقق من المتطلبات**: تمت إضافة أربع مقالات جديدة تغطي مصادر الأفكار، نموذج Double Diamond، Jobs to Be Done و The Mom Test لمساعدة المبتدئين على اكتشاف أفكار المنتجات والتحقق منها. [👉 قراءة الملحق](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
- **[2026-03-25]** 📚 **الوثائق الإنجليزية محدثة بالكامل**: المرحلة 2 (تطوير full-stack) والمرحلة 3 (تطوير متقدم) متاحتان الآن بالكامل باللغة الإنجليزية. [👉 ابدأ التعلم](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
<details>
|
||||||
|
<summary>أخبار سابقة</summary>
|
||||||
|
|
||||||
|
- **[2026-03-02]** 🦞 **دعم ودي لـ OpenClaw و AI Agent**: تمت إضافة `llms.txt` بحيث يمكن لـ OpenClaw و Claude و Cursor و Trae ووكلاء AI الآخرين فهم بنية المستودع بسرعة والعثور على محتوى البرنامج التعليمي المناسب.
|
||||||
|
- **[2026-03-01]** تمت ترقية قسم [التطوير المتقدم](https://datawhalechina.github.io/easy-vibe/en/stage-3/) بشكل شامل مع أدلة عميقة لـ Claude Code، بما في ذلك MCP و Skills و Agent Teams والمزيد، بالإضافة إلى ثمانية دروس تعليمية لمشاريع متعددة المنصات.
|
||||||
|
- **[2026-02-25]** تم تحديث [قاعدة معارف الملحق](https://datawhalechina.github.io/easy-vibe/en/appendix/)، وتغطي الآن 9 مجالات معرفية وأكثر من 80 موضوعًا تفاعليًا.
|
||||||
|
- **[2026-01-27]** تمت إضافة دروس تعليمية لتطوير تطبيقات Android و iOS.
|
||||||
|
- **[2026-01-19]** تم إصدار عروض تفاعلية لـ Prompt Engineering وتاريخ AI وتصميم المصادقة ومبادئ Git والمزيد.
|
||||||
|
- **[2026-01-16]** إعادة تنظيم هيكل المشروع وإنشاء رسمي لقسم "مدخل للمبتدئين".
|
||||||
|
- **[2026-01-14]** إكمال تحديث كبير لمستندات نماذج المنتجات الأولية للمرحلة 1.
|
||||||
|
- **[2026-01-13]** إعادة بناء بنية الوثائق وتمكين كامل للدعم متعدد اللغات (i18n).
|
||||||
|
- **[2026-01-01]** إصدار خريطة التعلم الأساسية للمشروع.
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## لمن هذا المشروع
|
||||||
|
|
||||||
|
- **المبتدئون تماماً**: ابنِ مشروعك الأول أولاً، ثم افهم كيف يعمل
|
||||||
|
- **مديرو المنتجات / المؤسسون**: تحقق من أفكارك بسرعة وابنِ MVPs بتكلفة منخفضة
|
||||||
|
- **الطلاب**: طوّر مهارات عملية لعصر الذكاء الاصطناعي
|
||||||
|
- **المطورون المبتدئون**: تعلّم المسار الكامل من الفكرة إلى الإطلاق
|
||||||
|
- **المطورون المتوسطون والكبار**: حسّن سير عمل التعاون مع الذكاء الاصطناعي للمشاريع المعقدة
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## مسارات التعلّم الخاصة بك
|
||||||
|
|
||||||
|
### 🎮 أريد نجاحاً سريعاً أولاً
|
||||||
|
**الأفضل ل**: الجميع
|
||||||
|
**ما ستتعلمه**: ما يشبه البرمجة بالذكاء الاصطناعي من خلال مثال عملي بسيط ومحدد
|
||||||
|
**ما ستحصل عليه**: انطباع أول واضح عن vibe coding وكيفية العمل مع الذكاء الاصطناعي عبر المحادثة
|
||||||
|
|
||||||
|
[ابدأ من هنا](https://datawhalechina.github.io/easy-vibe/en/stage-1/ai-capabilities-through-games/)
|
||||||
|
|
||||||
|
### 💡 أريد تحويل فكرة إلى نموذج أولي للمنتج
|
||||||
|
**الأفضل ل**: المبتدئين / مديري المنتجات / المؤسسين
|
||||||
|
**ما ستتعلمه**: خارطة طريق التعلم، أدوات AI IDE، التحقق من الأفكار، النماذج الأولية، تكامل قدرات الذكاء الاصطناعي وتكرار العروض الكاملة
|
||||||
|
**ما ستحصل عليه**: نموذج أولي لمنتج بالذكاء الاصطناعي يمكنك عرضه فعلياً للمستخدمين أو زملائك
|
||||||
|
|
||||||
|
[ابدأ التعلّم](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/)
|
||||||
|
|
||||||
|
### 🚀 أريد بناء منتجات full-stack من البداية للنهاية
|
||||||
|
**الأفضل ل**: المطورين المبتدئين / صانعي التطبيقات المستقلين / المتعلمين المتقدمين
|
||||||
|
**ما ستتعلمه**: سير العمل الأمامي، التصميم إلى الكود، قواعد البيانات، واجهات backend APIs، النشر، الفوترة والمشاريع الكبرى
|
||||||
|
**ما ستحصل عليه**: القدرة على إطلاق تطبيقات ويب حديثة بالذكاء الاصطناعي بشكل مستقل
|
||||||
|
|
||||||
|
[ابدأ التعلّم](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
|
||||||
|
### AI-Native: أريد سير عمل متقدم مع Claude Code والوكلاء
|
||||||
|
**الأفضل ل**: المطورين المهتمين بالهندسة الأصلية للذكاء الاصطناعي
|
||||||
|
**ما ستتعلمه**: Claude Code، MCP، Skills، Agent Teams، المهام طويلة الأمد، Spec Coding وتسليم التطبيقات متعددة المنصات
|
||||||
|
**ما ستحصل عليه**: سير عمل أقوى للتطوير المعقد بمساعدة الذكاء الاصطناعي والأتمتة
|
||||||
|
|
||||||
|
[اذهب إلى التطوير المتقدم](https://datawhalechina.github.io/easy-vibe/en/stage-3/)
|
||||||
|
|
||||||
|
### 📚 أريد مواد مرجعية وأساسيات
|
||||||
|
**الأفضل ل**: الجميع
|
||||||
|
**ما ستتعلمه**: أساسيات الحوسبة، أساسيات frontend/backend، البنية التحتية، مبادئ الذكاء الاصطناعي وممارسات الهندسة
|
||||||
|
**ما ستحصل عليه**: قاعدة معرفة مرجعية طويلة الأمد تغطي 9 مجالات معرفية رئيسية
|
||||||
|
|
||||||
|
[تصفّح قاعدة المعرفة](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
## نصائح الدراسة
|
||||||
|
|
||||||
|
- إذا كنت مبتدئاً أو مدير منتج أو مؤسساً، ابدأ بـ [المرحلة 1](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/)
|
||||||
|
- إذا كنت تريد الانتقال من النماذج الأولية إلى التسليم الكامل، ابدأ بـ [المرحلة 2](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
- إذا كنت تريد سير عمل متقدم مع Claude Code أو مشاريع متعددة المنصات، اذهب إلى [المرحلة 3](https://datawhalechina.github.io/easy-vibe/en/stage-3/)
|
||||||
|
- إذا أعاقتك المفاهيم أو نقص المعرفة الأساسية، استخدم [قاعدة معرفة الملحق](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
### 📖 التنقل في المحتوى
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<img src="../../assets/readme-image1.png" alt="خريطة التعلّم" width="70%" style="border-radius: 10px; box-shadow: 0 8px 20px rgba(45,55,72,0.3); margin: 15px 0;"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
### أولاً: دخول المبتدئين
|
||||||
|
|
||||||
|
| القسم | المحتوى الرئيسي |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [خريطة التعلّم](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/) | نظرة عامة موجزة لرحلة التعلم الكاملة |
|
||||||
|
| [عصر الذكاء الاصطناعي: إذا كنت تستطيع التحدث، يمكنك البرمجة](https://datawhalechina.github.io/easy-vibe/en/stage-1/ai-capabilities-through-games/) | احصل على أول تجربة للبرمجة بالذكاء الاصطناعي عبر أمثلة مثل لعبة Snake |
|
||||||
|
| [أتقن أدوات البرمجة بالذكاء الاصطناعي](https://datawhalechina.github.io/easy-vibe/en/stage-1/introduction-to-ai-ide/) | تعلّم كيف تعمل أدوات AI IDE وابنِ مشاريع محلية بسيطة بها |
|
||||||
|
| [اعثر على أفكار رائعة](https://datawhalechina.github.io/easy-vibe/en/stage-1/finding-great-idea/) | تعلّم كيف تكتشف وتتحقق من أفكار المنتجات التي تستحق البناء |
|
||||||
|
| [ابنِ نماذج أولية للمنتج](https://datawhalechina.github.io/easy-vibe/en/stage-1/building-prototype/) | انتقل من المتطلبات إلى نماذج أولية للمنتج بصفحة واحدة أو متعددة الصفحات |
|
||||||
|
| [تكامل قدرات الذكاء الاصطناعي](https://datawhalechina.github.io/easy-vibe/en/stage-1/integrating-ai-capabilities/) | تكامل ميزات الذكاء الاصطناعي للنصوص والصور والفيديو |
|
||||||
|
| [ممارسة مشروع كامل](https://datawhalechina.github.io/easy-vibe/en/stage-1/complete-project-practice/) | محاكاة سيناريوهات حقيقية، وجمع تعليقات المستخدمين والتكرار على مشروع كامل |
|
||||||
|
|
||||||
|
#### الملحق: التفكير في المنتج والأعمال
|
||||||
|
|
||||||
|
| القسم | المحتوى الرئيسي |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [التفكير في المنتج وتصميم الحلول](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-a-product-thinking/) | أطر أساسية للانتقال من الصفر إلى الواحد مع منتج |
|
||||||
|
| [سيناريوهات تطبيق الذكاء الاصطناعي في الصناعة (B2B)](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-industry-scenarios/) | فهم كيف يُطبَّق الذكاء الاصطناعي عبر مختلف الصناعات |
|
||||||
|
| [إلهام سيناريوهات الذكاء الاصطناعي الاستهلاكية (B2C)](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-c-consumer-scenarios/) | استكشف فرص المنتجات في الذكاء الاصطناعي الاستهلاكي |
|
||||||
|
|
||||||
|
#### الملحق: بحث المستخدم والتحقق من المتطلبات
|
||||||
|
|
||||||
|
| القسم | المحتوى الرئيسي |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [أين تجد الأفكار: 3 مصادر مرجعية تعمل بشكل أفضل للمبتدئين](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-idea-sources/) | ابنِ تدفقاً موثوقاً لإيجاد فرص منتجات ملموسة |
|
||||||
|
| [Double Diamond: افعل الشيء الصحيح أولاً، ثم افعله بشكل صحيح](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-double-diamond/) | استخدم عملية منظمة للانتقال من الإلهام المشتت إلى اتجاه عملي |
|
||||||
|
| [استخدم Jobs to Be Done لاكتشاف ما يريده المستخدمون حقاً](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-jobs-to-be-done/) | حلل أهداف المستخدمين من خلال مهام حقيقية بدلاً من طلبات الميزات السطحية |
|
||||||
|
| [The Mom Test: طريقة مقابلة المستخدمين للتحقق من الطلب](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-mom-test/) | تعلّم كيف تطرح أسئلة أفضل وتتجنب التعليقات الإيجابية الكاذبة |
|
||||||
|
|
||||||
|
#### الملحق: الحلول التقنية
|
||||||
|
|
||||||
|
| القسم | المحتوى الرئيسي |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [ماذا تفعل إذا واجهت أخطاء](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-b-common-errors/) | مشاكل vibe coding الشائعة وكيفية حلها |
|
||||||
|
| [مقارنة بين سبع أدوات برمجة بالذكاء الاصطناعي](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-articles/example0-1/vibe-coding-tools-snake-game-tutorial) | قارن منصات البرمجة بالذكاء الاصطناعي الرئيسية عبر اختبارات عملية |
|
||||||
|
| [صمّم مواقع ويب مع وكلاء](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-articles/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents) | تعلّم التعاون متعدد الوكلاء في الممارسة |
|
||||||
|
|
||||||
|
### ثانياً: المطورون المبتدئون والمتوسطون
|
||||||
|
|
||||||
|
#### الواجهة الأمامية (Frontend)
|
||||||
|
|
||||||
|
| القسم | المحتوى الرئيسي |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Frontend 0: ابنِ وكيل إنتاج الأصول الخاص بك مع Lovart](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/lovart-assets/) | استخدم Nanobanana و Lovart لتوليد أصول بصرية دفعة واحدة وابنِ وكيل رسم مع التعرف على النية |
|
||||||
|
| [Frontend 1: أساسيات Figma و MasterGo](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/figma-mastergo/) | تعلّم سير العمل من مسودات التصميم إلى التفكير في واجهة المستخدم الجاهزة للتنفيذ |
|
||||||
|
| [Frontend 2: ابنِ تطبيقك الحديث الأول - تصميم UI](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/ui-design/) | تعلّم أساسيات تصميم UI خلف واجهات التطبيقات الحديثة |
|
||||||
|
| [Frontend 3: إرشادات UI وتصميم متعدد المنتجات](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/multi-product-ui/) | حسّن الاتساق والجمالية عبر منتجات متعددة بقواعد UI مشتركة |
|
||||||
|
| [Frontend 4: اجعل الواجهات جميلة مع LLMs و Skills](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/llm-skills-beautiful/) | استخدم الأوامر والإضافات لجعل الذكاء الاصطناعي ينتج واجهات أكثر تنقية وتميزاً |
|
||||||
|
| [Frontend 4: لنبني لوحات هوجورتس معاً](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/hogwarts-portraits/) | ابنِ مشروع واجهة أمامية تفاعلي لصور الذكاء الاصطناعي من الصفر |
|
||||||
|
| [Frontend 6: من نموذج التصميم إلى كود المشروع](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/design-to-code/) | حوّل نماذج التصميم إلى كود واجهة أمامية يعمل فعلياً في المتصفح |
|
||||||
|
| [Frontend 7: حدّث واجهتك بمكتبات مكونات حديثة](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/modern-component-library/) | استخدم مكتبات المكونات لبناء واجهات احترافية بشكل أسرع |
|
||||||
|
|
||||||
|
#### الواجهة الخلفية (Backend)
|
||||||
|
|
||||||
|
| القسم | المحتوى الرئيسي |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Backend 1: تعلّم Git و GitHub](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/git-workflow/) | أتقن عمليات التحكم في الإصدار وسير العمل التعاوني مع Git |
|
||||||
|
| [Backend 2: من قاعدة البيانات إلى Supabase](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/database-supabase/) | تعلّم أساسيات قواعد البيانات العلائقية واستخدم Supabase كمنصة BaaS حديثة |
|
||||||
|
| [Backend 3: تصميم وتطوير واجهات backend APIs](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/ai-interface-code/) | استخدم الذكاء الاصطناعي للمساعدة في تصميم APIs وتوليد كود backend وتوثيق APIs |
|
||||||
|
| [Backend 4: انشر نموذج منتجك الأولي](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/zeabur-deployment/) | انشر تطبيقات full-stack بسرعة على السحابة مع Zeabur |
|
||||||
|
| [Backend 5: من IDEs إلى أدوات البرمجة بالذكاء الاصطناعي عبر CLI](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/modern-cli/) | استكشف سير عمل البرمجة بالذكاء الاصطناعي من الطرفية للتطوير الحديث |
|
||||||
|
| [Backend 6: تكامل Stripe وأنظمة الفوترة الأخرى](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/stripe-payment/) | أضف تحقيق الدخل مع قدرات الدفع والفوترة |
|
||||||
|
|
||||||
|
#### المشاريع الكبرى
|
||||||
|
|
||||||
|
| القسم | المحتوى الرئيسي |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [المشروع الكبير 1: أول تطبيق SaaS full-stack خاص بك - موقع كتابة محتوى بالذكاء الاصطناعي](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/fullstack-app/) | ابنِ مساحة عمل تسويقية بالذكاء الاصطناعي مع تسجيل الدخول والتوليد والفوترة وإدارة المسؤول |
|
||||||
|
| [المشروع الكبير 2: نظام اختبارات وإدارة عبر الإنترنت](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/modern-frontend-trae/) | ابنِ نظام اختبارات عبر الإنترنت مع توليد الأسئلة وتدفقات الامتحان وأدوات الإدارة |
|
||||||
|
|
||||||
|
#### ملحق قدرات الذكاء الاصطناعي
|
||||||
|
|
||||||
|
| القسم | المحتوى الرئيسي |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [الذكاء الاصطناعي 1: أساسيات Dify وتكامل قاعدة المعرفة](https://datawhalechina.github.io/easy-vibe/en/stage-2/ai-capabilities/dify-knowledge-base/) | تعلّم بناء تطبيقات الذكاء الاصطناعي مع Dify وتكامل قواعد المعرفة الخاصة |
|
||||||
|
|
||||||
|
### ثالثاً: المطورون المتقدمون
|
||||||
|
|
||||||
|
#### المهارات الأساسية لـ Claude Code
|
||||||
|
|
||||||
|
| القسم | المحتوى الرئيسي |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [البدء مع Claude Code](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/basics/) | التثبيت والإعداد والأساسيات والأوامر المفيدة |
|
||||||
|
| [دليل Claude Code MCP](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/mcp/) | ربط Claude Code بـ GitHub وقواعد البيانات و APIs وخدمات أخرى عبر MCP |
|
||||||
|
| [دليل Claude Code Skills](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/skills/) | حوّل خبرتك إلى مهارات قابلة لإعادة الاستخدام مراراً وتكراراً |
|
||||||
|
| [كيف تجعل Claude Code يعمل لفترات طويلة](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/long-running-tasks/) | صمّم مهام طويلة الأمد لكي تستمر أدوات الترميز في العمل حتى الانتهاء |
|
||||||
|
| [دليل Claude Agent Teams](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/agent-teams/) | نسّق عدة حالات ذكاء اصطناعي كفريق تطوير حقيقي |
|
||||||
|
| [قوى Claude Code الخارقة للتطوير بمستوى الهندسة](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/superpowers/) | ساعد الذكاء الاصطناعي في إنتاج كود بمستوى الهندسة مع TDD وأفضل الممارسات |
|
||||||
|
| [أفضل ممارسات سير عمل Claude Code](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/workflow/) | أفضل الممارسات لإعادة الهيكلة ومراجعة الكود والتطوير اليومي |
|
||||||
|
| [التطوير عن بُعد مع Claude Code على الجوال](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/mobile-development/) | استخدم Claude Code خارج سطح المكتب وابنِ سير عمل عن بُعد منتج على الأجهزة المحمولة |
|
||||||
|
| [الدليل الشامل لـ SDK Claude Agent](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/claude-agent-sdk/) | ابنِ سير عمل وكلاء مخصص وادمج Claude في أدواتك الخاصة مع SDK |
|
||||||
|
| [من vibe coding إلى spec coding](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/spec-coding/) | انتقل من الأوامر العفوية إلى سير عمل تطوير بالذكاء الاصطناعي أكثر هيكلة وقائماً على المواصفات |
|
||||||
|
|
||||||
|
#### التطوير متعدد المنصات
|
||||||
|
|
||||||
|
| القسم | المحتوى الرئيسي |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [كيف تختار المنصة المناسبة لتطبيقك](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/choose-platform/) | قارن أشكال التطبيقات واختر المنصة المناسبة بناءً على المستخدمين والسيناريوهات وأهداف التسليم |
|
||||||
|
| [ابنِ برنامج WeChat Mini](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/wechat-miniprogram/) | افهم النظام البيئي وانشر برنامج Mini أمامي من القالب إلى الإطلاق |
|
||||||
|
| [ابنِ برنامج WeChat Mini مع backend](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/wechat-miniprogram-backend/) | أضف منطق backend وقواعد البيانات لإكمال حلقة الأعمال الكاملة |
|
||||||
|
| [ابنِ تطبيق Android](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/android-app/) | تعلّم تطوير تطبيقات Android بسير عمل أصلي حديث |
|
||||||
|
| [ابنِ تطبيق iOS](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/ios-app/) | تعلّم تطوير تطبيقات iOS واصطلاحات نظام Apple البيئي |
|
||||||
|
| [ابنِ تطبيق PWA محلي](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/pwa-local-app/) | حوّل موقع ويب إلى تطبيق حقيقي مع دعم عدم الاتصال والإشعارات والتثبيت |
|
||||||
|
| [ابنِ إضافة مساعد ذكاء اصطناعي للمتصفح](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/browser-ai-extension/) | أنشئ إضافة Chrome تلخّص أي صفحة إما بـ APIs سحابية أو ذكاء اصطناعي مدمج |
|
||||||
|
| [ابنِ تطبيق سطح مكتب Electron](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/electron-voice-to-text/) | ابنِ تطبيق سطح مكتب لتحويل الصوت إلى نص مع Electron لثلاث منصات |
|
||||||
|
| [ابنِ واصنع NFT بسرعة](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/nft-minting/) | اكتب عقداً ذكياً من الصفر، انشره واصنع NFT الخاص بك |
|
||||||
|
| [ابنِ إضافة VS Code](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/vscode-extension/) | ابنِ مساعد مشروع بالذكاء الاصطناعي مع قوالب ودردشة كود وأسئلة وأجوبة متعددة الملفات |
|
||||||
|
| [ابنِ تطبيق سطح مكتب Qt بمستوى صناعي](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/qt-industrial-hmi/) | أنشئ نظام HMI Qt في الوقت الفعلي مع الاتجاهات والتنبيهات والمراقبة |
|
||||||
|
|
||||||
|
#### ملحق قدرات الذكاء الاصطناعي
|
||||||
|
|
||||||
|
| القسم | المحتوى الرئيسي |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [ما هو RAG وكيف يعمل](https://datawhalechina.github.io/easy-vibe/en/stage-3/ai-advanced/rag-introduction/) | ابنِ فهماً منظماً لمبادئ RAG والبنيات الشائعة |
|
||||||
|
| [سير عمل RAG المتوسط والمتقدم مع LangGraph](https://datawhalechina.github.io/easy-vibe/en/stage-3/ai-advanced/langgraph-advanced-rag/) | صمّم سير عمل متعدد الخطوات وأنظمة RAG أكثر تقدماً |
|
||||||
|
|
||||||
|
### 📚 قاعدة المعرفة في الملحق
|
||||||
|
|
||||||
|
> تغطي **9 مجالات معرفية رئيسية** و**أكثر من 80 موضوعاً تفاعلياً**، يستخدم هذا الملحق الرسوم المتحركة والمكونات المرئية لمساعدتك على فهم المفاهيم الأساسية بشكل حدسي من أساسيات الحوسبة إلى حدود الذكاء الاصطناعي.
|
||||||
|
>
|
||||||
|
> 👉 [عرض الملحق الكامل](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
### 🎓 دورات أخرى
|
||||||
|
|
||||||
|
- [Hands-on Modern RL](#دورات-أخرى)
|
||||||
|
- [Learn Harness Engineering](#دورات-أخرى)
|
||||||
|
|
||||||
|
## 🛠️ كيف تتعلم
|
||||||
|
|
||||||
|
- اقرأ وتدرّب على الأقسام التي تناسب مستواك الحالي. إذا واجهتك مشكلة، لا تتردد في فتح issue.
|
||||||
|
|
||||||
|
## 💻 التشغيل محلياً
|
||||||
|
|
||||||
|
### الطريقة الحديثة
|
||||||
|
|
||||||
|
في نافذة محادثة AI IDE مثل VS Code أو Cursor أو Trae، يمكنك ببساطة أن تقول:
|
||||||
|
|
||||||
|
```text
|
||||||
|
ساعدني في تشغيل هذا المشروع محلياً.
|
||||||
|
```
|
||||||
|
|
||||||
|
### الطريقة التقليدية
|
||||||
|
|
||||||
|
1. `npm install`
|
||||||
|
2. `npm run dev`
|
||||||
|
3. افتح `http://localhost:3000` في متصفحك.
|
||||||
|
|
||||||
|
## دورات أخرى
|
||||||
|
|
||||||
|
فريقنا أنشأ أيضاً دورات أخرى! اطلع عليها:
|
||||||
|
|
||||||
|
[](https://github.com/walkinglabs/hands-on-modern-rl)
|
||||||
|
|
||||||
|
**Hands-on Modern RL**: منهاج عملي ومفتوح المصدر يسد الفجوة من مفاهيم RL الأساسية إلى محاذاة LLMs و RLVR وأنظمة Agentic المتقدمة.
|
||||||
|
|
||||||
|
[](https://github.com/walkinglabs/learn-harness-engineering/tree/main)
|
||||||
|
|
||||||
|
**Learn Harness Engineering**: دليل شامل لهندسة الهارنيس.
|
||||||
|
|
||||||
|
## 🤝 المساهمة والمساهمون
|
||||||
|
|
||||||
|
- إذا وجدت مشكلة أو رأيت شيئاً يمكن تحسينه، لا تتردد في فتح issue. إذا لم يرد أحد، يمكنك أيضاً التواصل مع [فريق دعم Datawhale](https://github.com/datawhalechina/DOPMC/blob/main/OP.md).
|
||||||
|
- إذا كنت تريد المساهمة، افتح pull request. إذا لم يرد أحد، يمكنك أيضاً التواصل مع [فريق دعم Datawhale](https://github.com/datawhalechina/DOPMC/blob/main/OP.md).
|
||||||
|
- إذا كنت تريد بدء مشروع Datawhale مفتوح المصدر جديد، يرجى اتباع [دليل مشاريع Datawhale المفتوحة المصدر](https://github.com/datawhalechina/DOPMC/blob/main/GUIDE.md).
|
||||||
|
|
||||||
|
### 🙏 المساهمون
|
||||||
|
|
||||||
|
- [Sanbu - قائد المشروع](https://github.com/sanbuphy) (عضو في Datawhale)
|
||||||
|
- Fang Ke - المرشد (عضو في Datawhale، جامعة Tsinghua)
|
||||||
|
- [Yerim Kang](https://github.com/yerim25) (المشاريع العملية، جامعة Tsinghua)
|
||||||
|
- [Zhilin Zhao](https://github.com/ChileenZ) (المشاريع العملية، جامعة Tsinghua)
|
||||||
|
- [Yixuan Li](https://yixuan20.github.io/) (التصميم البصري، جامعة Tsinghua)
|
||||||
|
- Siyi Liu (المشاريع العملية، جامعة Tsinghua)
|
||||||
|
- [Lixin Liu](https://github.com/liulx25xx) (المشاريع العملية، جامعة Tsinghua)
|
||||||
|
- كل من في مجموعة الاختبار الداخلي لـ AI Vibe Coding 101 الذين شاركوا اقتراحاتهم وملاحظاتهم
|
||||||
|
|
||||||
|
### شكر خاص
|
||||||
|
|
||||||
|
- شكراً لـ [@Sm1les](https://github.com/Sm1les) على المساعدة والدعم في هذا المشروع
|
||||||
|
- شكراً لكل مساهم وكل من دعم المشروع بملاحظاته ونجومه ❤️
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a href="https://www.star-history.com/#datawhalechina/easy-vibe&type=timeline&legend=top-left">
|
||||||
|
<picture>
|
||||||
|
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=datawhalechina/easy-vibe&type=timeline&theme=dark&legend=top-left" />
|
||||||
|
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=datawhalechina/easy-vibe&type=timeline&legend=top-left" />
|
||||||
|
</picture>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align=center style="margin-top: 30px;">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=datawhalechina/easy-vibe" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 📄 الترخيص
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
|
||||||
|
<img
|
||||||
|
alt="رخصة المشاع الإبداعي"
|
||||||
|
style="border-width:0"
|
||||||
|
src="https://img.shields.io/badge/license-CC%20BY--NC--SA%204.0-lightgrey"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<br />
|
||||||
|
هذا العمل مرخص بموجب
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
|
||||||
|
رخصة المشاع الإبداعي Attribution-NonCommercial-ShareAlike 4.0 الدولية
|
||||||
|
</a>.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Star History
|
||||||
|
|
||||||
|
[](https://www.star-history.com/#datawhalechina/easy-vibe&type=date&legend=top-left)
|
||||||
@@ -0,0 +1,448 @@
|
|||||||
|
<!-- trigger vercel build -->
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
<img src="../../assets/easy-vibe-logo-hd.svg" alt="Easy-Vibe Logo" width="300">
|
||||||
|
|
||||||
|
<img src="../../assets/banner.png" alt="Easy-Vibe Banner" width="100%">
|
||||||
|
|
||||||
|
<p align="center" style="font-size: 1.2em; color: #666; margin: 20px 0;">
|
||||||
|
Leg direkt los und vibe mit uns. Wenn du sprechen kannst, kannst du Apps bauen.<br>
|
||||||
|
<span style="font-size: 0.9em; color: #888;">直接上手,一起 vibe!会说话就会做应用。</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a href="https://trendshift.io/repositories/22079" target="_blank"><img src="https://trendshift.io/api/badge/repositories/22079" alt="datawhalechina/easy-vibe | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||||
|
|
||||||
|
<p align="center" style="font-size: 1.05em; color: #666; margin: 16px 0;">
|
||||||
|
你好 · Hello · 哈囉 · こんにちは · 안녕하세요 · Hola · Bonjour · Hallo · مرحبا · Xin chào<br>
|
||||||
|
Teil 1 unseres Tutorials ist jetzt in 10 Sprachen verfügbar. Freunde aus aller Welt, lasst uns gemeinsam coding starten!<br>
|
||||||
|
<span style="font-size: 0.9em; color: #888;">我们的教程(第一部分)已经支持 10 种语言,欢迎世界各地的朋友一起 coding!</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
🚀 <a href="https://datawhalechina.github.io/easy-vibe/welcome.html">Jetzt entdecken</a> · ✨ <a href="https://datawhalechina.github.io/easy-vibe/en/appendix/">Interaktives Tutorial</a> · 🦞 <a href="https://github.com/datawhalechina/hello-claw">OpenClaw lernen</a> · 📖 <a href="#table-of-contents">Inhaltsverzeichnis</a><br>
|
||||||
|
<span style="font-size: 0.85em; color: #888;">🚀 <a href="https://datawhalechina.github.io/easy-vibe/welcome.html">开始体验</a> · ✨ <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/">交互式教程</a> · 🦞 <a href="https://github.com/datawhalechina/hello-claw">学习 OpenClaw</a> · 📖 <a href="#table-of-contents">查看目录</a></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://datawhalechina.github.io/easy-vibe/welcome.html">Online lesen</a> ·
|
||||||
|
<a href="#-content-navigation">Lernpfad</a><br>
|
||||||
|
<span style="font-size: 0.85em; color: #888;">
|
||||||
|
<a href="https://datawhalechina.github.io/easy-vibe/welcome.html">开始阅读</a> ·
|
||||||
|
<a href="#-content-navigation">学习地图</a>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/stargazers" target="_blank">
|
||||||
|
<img src="https://img.shields.io/github/stars/datawhalechina/easy-vibe?color=660874&style=for-the-badge&logo=star&logoColor=white&labelColor=1a1a2e" alt="Stars"></a>
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/network/members" target="_blank">
|
||||||
|
<img src="https://img.shields.io/github/forks/datawhalechina/easy-vibe?color=660874&style=for-the-badge&logo=git-fork&logoColor=white&labelColor=1a1a2e" alt="Forks"></a>
|
||||||
|
<a href="../../LICENSE" target="_blank">
|
||||||
|
<img src="https://img.shields.io/badge/License-CC_BY_NC_SA_4.0-4ecdc4?style=for-the-badge&logo=creative-commons&logoColor=white&labelColor=1a1a2e" alt="License"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="../../README.md"><img alt="English" src="https://img.shields.io/badge/English-d9d9d9"></a>
|
||||||
|
<a href="../zh-CN/README.md"><img alt="简体中文" src="https://img.shields.io/badge/简体中文-d9d9d9"></a>
|
||||||
|
<a href="../zh-TW/README.md"><img alt="繁體中文" src="https://img.shields.io/badge/繁體中文-d9d9d9"></a>
|
||||||
|
<a href="../ja-JP/README.md"><img alt="日本語" src="https://img.shields.io/badge/日本語-d9d9d9"></a>
|
||||||
|
<a href="../es-ES/README.md"><img alt="Español" src="https://img.shields.io/badge/Español-d9d9d9"></a>
|
||||||
|
<a href="../fr-FR/README.md"><img alt="Français" src="https://img.shields.io/badge/Français-d9d9d9"></a>
|
||||||
|
<a href="../ko-KR/README.md"><img alt="한국어" src="https://img.shields.io/badge/한국어-d9d9d9"></a>
|
||||||
|
<a href="../ar-SA/README.md"><img alt="العربية" src="https://img.shields.io/badge/العربية-d9d9d9"></a>
|
||||||
|
<a href="../vi-VN/README.md"><img alt="Tiếng_Việt" src="https://img.shields.io/badge/Tiếng_Việt-d9d9d9"></a>
|
||||||
|
<a href="../de-DE/README.md"><img alt="Deutsch" src="https://img.shields.io/badge/Deutsch-d9d9d9"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<table align="center">
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-header.png" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Eine anfaengerfreundliche Lernkarte</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Klare Orientierung von Null an, damit du aufhoerst zu "lernen und vergessen"</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-tutorial.png" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Schritt-fuer-Schritt visuelle Tutorials</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Ausfuehrliche Anleitungen, die sich anfuehlen wie Lernen mit einem Privatlehrer</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-ide.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Immersives simuliertes Codieren</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Virtuelle Mausfuehrung hilft dir, den Kern-IDE-Workflow schnell zu lernen</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-diffusion.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Sichtbare KI-Prinzipien</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Animierte Erklaerungen machen es leicht zu sehen, wie KI Bilder erzeugt</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-rag.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>RAG lernen wie ein Spiel</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Interaktive Komponenten lassen dich den gesamten RAG-Datenfluss durchklicken</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/git-terminal.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Visuelle Terminal-Konzepte</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Kommandozeilenverhalten wird intuitiv, wenn die zugrundeliegende Logik visualisiert wird</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div align="center">
|
||||||
|
<h3>⭐ <a href="https://github.com/datawhalechina/easy-vibe" style="color: #d0cd16ff;">Sterne hier vergeben</a>, um Aktualisierungen zu beschleunigen ❤️</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align="center" style="margin: 30px 0;">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/issues/new?template=story_submission.md">
|
||||||
|
<img src="https://raw.githubusercontent.com/datawhalechina/easy-vibe/main/assets/stories_image.png" alt="Teile deine Vibe-Story" width="80%" style="border-radius: 10px; box-shadow: 0 4px 12px rgba(0,0,0,0.15);">
|
||||||
|
</a>
|
||||||
|
<p style="margin-top: 15px; font-size: 1.1em; color: #666;">
|
||||||
|
📝 <strong>Hast du deine eigene Vibe-Coding-Story?</strong>
|
||||||
|
Reiche sie hier ein und inspiriere andere!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Inhaltsverzeichnis
|
||||||
|
|
||||||
|
- [Warum Easy-Vibe](#warum-easy-vibe)
|
||||||
|
- [Neuigkeiten](#-neuigkeiten)
|
||||||
|
- [Fuer wen ist das](#fuer-wen-ist-das)
|
||||||
|
- [Deine Lernpfade](#deine-lernpfade)
|
||||||
|
- [Lernempfehlungen](#lernempfehlungen)
|
||||||
|
- [I. Einsteiger-Einstieg](#i-einsteiger-einstieg)
|
||||||
|
- [II. Junior- und Mid-Level-Entwickler](#ii-junior-und-mid-level-entwickler)
|
||||||
|
- [III. Fortgeschrittene Entwickler](#iii-fortgeschrittene-entwickler)
|
||||||
|
- [Anhang Wissensdatenbank](#-anhang-wissensdatenbank)
|
||||||
|
- [Wie man lernt](#️-wie-man-lernt)
|
||||||
|
- [Lokal ausfuehren](#-lokal-ausfuehren)
|
||||||
|
- [Weitere Kurse](#weitere-kurse)
|
||||||
|
- [Mitmachen & Mitwirkende](#mitmachen--mitwirkende)
|
||||||
|
- [Lizenz](#-lizenz)
|
||||||
|
|
||||||
|
## Warum Easy-Vibe
|
||||||
|
|
||||||
|
Du willst eine Ausgabenverfolgung? Sag es einfach.
|
||||||
|
|
||||||
|
Du brauchst ein Buchungssystem mit WeChat-Login? Sag es einfach.
|
||||||
|
|
||||||
|
Du willst einen Blog mit Kommentaren? Sag es einfach.
|
||||||
|
|
||||||
|
Im KI-Zeitalter beginnt Programmieren damit, zu beschreiben, was du willst.
|
||||||
|
|
||||||
|
Easy-Vibe zeigt dir, wie du daraus ein echtes Produkt machst.
|
||||||
|
|
||||||
|
|
||||||
|
## 🔥 Neuigkeiten
|
||||||
|
|
||||||
|
- **[2026-05-20]** 🌍 **Mehrsprachige Abdeckung von Stage 1 ist vollstaendig**: Stage 1 ist jetzt in allen unterstuetzten Sprachen verfuegbar (zh-cn, en, zh-tw, ja-jp, ko-kr, es-es, fr-fr, de-de, ar-sa, vi-vn). Navigation/Build wurden geprueft, um 404 zu vermeiden.
|
||||||
|
- **[2026-03-29]** ✨ **Vibe Stories gestartet und mit echten Nutzerreisen aktualisiert**: Eine neue Vibe-Stories-Sektion mit interaktivem Karussell und dedizierten Story-Seiten wurde auf der Startseite hinzugefuegt. Platzhalter wurden durch vier echte Nutzergeschichten ersetzt: eine Grundschullehrerin vom Land, einen Studenten, einen IT-Lehrer an einer weiterfuehrenden Schule und einen Lkw-Fahrer, die alle echte Produkte mit KI gebaut haben. [👉 Geschichten ansehen](https://datawhalechina.github.io/easy-vibe/zh-cn/vibe-stories/story-1.html)
|
||||||
|
- **[2026-03-26]** 🚀 **Grosses Phase-2-Praxis-Update**: Das SaaS-Abschlussprojekt "[Deine erste SaaS-Full-Stack-App: Copywriting-Generator-Website](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/fullstack-app/)" wurde abgeschlossen und der Abschnitt "[Stripe- und Zahlungssysteme integrieren](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/stripe-payment/)" deutlich erweitert, plus wichtige Inhalte zu Multi-Produkt-UI und WeChat-Mini-Programm-Backend-Workflows.
|
||||||
|
- **[2026-03-25]** 📚 **Neuer Anhang: Nutzerforschung und Anforderungsvalidierung**: Vier neue Artikel hinzugefuegt, die Ideenfindung, das Double-Diamond-Modell, Jobs to Be Done und The Mom Test abdecken, um Anfaengern zu helfen, Produktideen zu entdecken und zu validieren. [👉 Anhang lesen](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
- **[2026-03-25]** 📚 **Englische Dokumentation vollstaendig aktualisiert**: Phase 2 (Full-Stack-Entwicklung) und Phase 3 (Fortgeschrittene Entwicklung) sind jetzt vollstaendig auf Englisch verfuegbar. [👉 Lernen beginnen](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
<details>
|
||||||
|
<summary>Vergangene Neuigkeiten</summary>
|
||||||
|
|
||||||
|
- **[2026-03-02]** 🦞 **OpenClaw- und KI-Agent-freundliche Unterstuetzung**: `llms.txt` hinzugefuegt, damit OpenClaw, Claude, Cursor, Trae und andere KI-Agenten die Repository-Struktur schnell verstehen und die richtigen Tutorial-Inhalte finden koennen.
|
||||||
|
- **[2026-03-01]** Der Abschnitt [Fortgeschrittene Entwicklung](https://datawhalechina.github.io/easy-vibe/en/stage-3/) wurde umfassend mit tiefen Anleitungen fuer Claude Code aktualisiert, einschliesslich MCP, Skills, Agent Teams und mehr, zusammen mit acht plattformuebergreifenden Projekttutorials.
|
||||||
|
- **[2026-02-25]** Die [Anhang-Wissensdatenbank](https://datawhalechina.github.io/easy-vibe/en/appendix/) wurde aktualisiert und deckt jetzt 9 Wissensbereiche und ueber 80 interaktive Themen ab.
|
||||||
|
- **[2026-01-27]** Tutorials fuer Android- und iOS-App-Entwicklung hinzugefuegt.
|
||||||
|
- **[2026-01-19]** Interaktive Demos fuer Prompt Engineering, KI-Geschichte, Authentifizierungsdesign, Git-Prinzipien und mehr veroeffentlicht.
|
||||||
|
- **[2026-01-16]** Projektstruktur reorganisiert und einen Einsteiger-Einstiegspfad offiziell etabliert.
|
||||||
|
- **[2026-01-14]** Grosses Update der Phase-1-Produktprototyp-Dokumentation abgeschlossen.
|
||||||
|
- **[2026-01-13]** Dokumentenarchitektur umgestaltet und Mehrsprachigkeitsunterstuetzung vollstaendig aktiviert.
|
||||||
|
- **[2026-01-01]** Die Kern-Lernkarte des Projekts wurde veroeffentlicht.
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## Fuer wen ist das
|
||||||
|
|
||||||
|
- **Komplette Anfaenger**: Baue zuerst dein erstes Projekt, dann verstehe, wie es funktioniert
|
||||||
|
- **Produktmanager / Gruender**: Ideen schnell validieren und MVPs mit niedrigen Kosten erstellen
|
||||||
|
- **Studierende**: Praktische Faehigkeiten fuer das KI-Zeitalter entwickeln
|
||||||
|
- **Junior-Entwickler**: Den vollstaendigen Weg von der Idee zum Launch lernen
|
||||||
|
- **Mid-Level- und Senior-Entwickler**: Deine KI-Zusammenarbeitsworkflow fuer komplexe Projekte aufwerten
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Deine Lernpfade
|
||||||
|
|
||||||
|
### 🎮 Ich moechte einen schnellen ersten Erfolg
|
||||||
|
**Am besten fuer**: Alle
|
||||||
|
**Was du lernen wirst**: Wie sich KI-Coding wirklich anfuehlt, an einem einfachen, konkreten praktischen Beispiel
|
||||||
|
**Was du bekommst**: Ein klarer erster Eindruck von Vibe-Coding und wie man mit KI durch Konversation arbeitet
|
||||||
|
|
||||||
|
[Hier starten](https://datawhalechina.github.io/easy-vibe/en/stage-1/ai-capabilities-through-games/)
|
||||||
|
|
||||||
|
### 💡 Ich moechte eine Idee in einen Produktprototyp umwandeln
|
||||||
|
**Am besten fuer**: Anfaenger / Produktmanager / Gruender
|
||||||
|
**Was du lernen wirst**: Lernkarte, KI-IDE-Tools, Ideenvalidierung, Prototyping, KI-Faehigkeitsintegration und vollstaendige Demo-Iteration
|
||||||
|
**Was du bekommst**: Ein demo-basierter KI-Produktprototyp, den du tatsaechlich Nutzern oder Teammitgliedern zeigen kannst
|
||||||
|
|
||||||
|
[Lernen beginnen](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/)
|
||||||
|
|
||||||
|
### 🚀 Ich moechte Full-Stack-Produkte Ende zu Ende erstellen
|
||||||
|
**Am besten fuer**: Junior-Entwickler / Indie-Hacker / Fortgeschrittene Lernende
|
||||||
|
**Was du lernen wirst**: Frontend-Workflows, Design-to-Code, Datenbanken, Backend-APIs, Bereitstellung, Abrechnung und grosse Projekte
|
||||||
|
**Was du bekommst**: Die Faehigkeit, unabhaengig moderne KI-gestuetzte Webanwendungen bereitzustellen
|
||||||
|
|
||||||
|
[Lernen beginnen](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
|
||||||
|
### KI-Nativ: Ich moechte fortgeschrittene Claude-Code- und Agenten-Workflows
|
||||||
|
**Am besten fuer**: Entwickler, die sich fuer KI-native Entwicklung interessieren
|
||||||
|
**Was du lernen wirst**: Claude Code, MCP, Skills, Agent Teams, langlaufende Aufgaben, Spec Coding und plattformuebergreifende App-Bereitstellung
|
||||||
|
**Was du bekommst**: Ein staerkerer Workflow fuer komplexe KI-gestuetzte Entwicklung und Automatisierung
|
||||||
|
|
||||||
|
[Zur fortgeschrittenen Entwicklung](https://datawhalechina.github.io/easy-vibe/en/stage-3/)
|
||||||
|
|
||||||
|
### 📚 Ich moechte Referenzmaterial und Grundlagen
|
||||||
|
**Am besten fuer**: Alle
|
||||||
|
**Was du lernen wirst**: Informatik-Grundlagen, Frontend-/Backend-Basics, Infrastruktur, KI-Prinzipien und Engineering-Praktiken
|
||||||
|
**Was du bekommst**: Eine langfristige Referenz-Wissensdatenbank, die 9 grosse Wissensbereiche abdeckt
|
||||||
|
|
||||||
|
[Wissensdatenbank durchsuchen](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
## Lernempfehlungen
|
||||||
|
|
||||||
|
- Wenn du Anfaenger, Produktmanager oder Gruender bist, beginne mit [Phase 1](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/)
|
||||||
|
- Wenn du von Prototypen zur Full-Stack-Bereitstellung wechseln moechtest, beginne mit [Phase 2](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
- Wenn du fortgeschrittene Claude-Code-Workflows oder plattformuebergreifende Projekte moechtest, gehe zu [Phase 3](https://datawhalechina.github.io/easy-vibe/en/stage-3/)
|
||||||
|
- Wenn du durch Konzepte oder fehlendes Hintergrundwissen blockiert wirst, nutze die [Anhang-Wissensdatenbank](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
### 📖 Inhaltliche Navigation
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<img src="../../assets/readme-image1.png" alt="Lernkarte" width="70%" style="border-radius: 10px; box-shadow: 0 8px 20px rgba(45,55,72,0.3); margin: 15px 0;"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
### I. Einsteiger-Einstieg
|
||||||
|
|
||||||
|
| Abschnitt | Wichtiger Inhalt |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Lernkarte](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/) | Eine gefuehrte Uebersicht der gesamten Lernreise |
|
||||||
|
| [KI-Aera: Wenn du sprechen kannst, kannst du coden](https://datawhalechina.github.io/easy-vibe/en/stage-1/ai-capabilities-through-games/) | Ersten Eindruck von KI-Coding durch Beispiele wie Snake bekommen |
|
||||||
|
| [KI-Programmierwerkzeuge meistern](https://datawhalechina.github.io/easy-vibe/en/stage-1/introduction-to-ai-ide/) | Lernen, wie KI-IDE-Tools funktionieren und einfache lokale Projekte damit erstellen |
|
||||||
|
| [Grossartige Ideen finden](https://datawhalechina.github.io/easy-vibe/en/stage-1/finding-great-idea/) | Lernen, wie man Produktideen entdeckt und validiert, die es wert sind, umgesetzt zu werden |
|
||||||
|
| [Produktprototypen erstellen](https://datawhalechina.github.io/easy-vibe/en/stage-1/building-prototype/) | Von Anforderungen zu Einzelseiten- und Mehrseiten-Produktprototypen |
|
||||||
|
| [KI-Faehigkeiten integrieren](https://datawhalechina.github.io/easy-vibe/en/stage-1/integrating-ai-capabilities/) | Text-, Bild- und Video-KI-Funktionen integrieren |
|
||||||
|
| [Vollstaendiges Projektpraktikum](https://datawhalechina.github.io/easy-vibe/en/stage-1/complete-project-practice/) | Reale Szenarien simulieren, Nutzerfeedback sammeln und ein vollstaendiges Projekt iterieren |
|
||||||
|
|
||||||
|
#### Anhang: Produkt- und Geschaeftsdenken
|
||||||
|
|
||||||
|
| Abschnitt | Wichtiger Inhalt |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Produktdenken und Loungsdesign](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-a-product-thinking/) | Kern-Frameworks fuer den Weg von Null zu Eins mit einem Produkt |
|
||||||
|
| [KI-Branchen-Anwendungsszenarien (B2B)](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-industry-scenarios/) | Verstehen, wie KI ueber Branchen hinweg angewendet wird |
|
||||||
|
| [KI-Konsumentenszenarien-Inspiration (B2C)](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-c-consumer-scenarios/) | Produktmoeglichkeiten in der Konsum-KI erkunden |
|
||||||
|
|
||||||
|
#### Anhang: Nutzerforschung und Anforderungsvalidierung
|
||||||
|
|
||||||
|
| Abschnitt | Wichtiger Inhalt |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Wo man Ideen findet: 3 Referenzquellen, die fuer Anfaenger am besten funktionieren](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-idea-sources/) | Eine zuverlaessige Pipeline fuer konkrete Produktmoeglichkeiten aufbauen |
|
||||||
|
| [Double Diamond: Erst das Richtige tun, dann es richtig machen](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-double-diamond/) | Einen strukturierten Prozess nutzen, um von verstreuter Inspiration zu einer machbaren Richtung zu kommen |
|
||||||
|
| [Jobs to Be Done nutzen, um herauszufinden, was Nutzer wirklich wollen](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-jobs-to-be-done/) | Nutzerziele durch echte Aufgaben analysieren statt durch oberflaechliche Feature-Anfragen |
|
||||||
|
| [The Mom Test: Eine Nutzerinterview-Methode zur Validierung von Bedarf](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-mom-test/) | Lernen, bessere Fragen zu stellen und falsch-positive Rueckmeldungen zu vermeiden |
|
||||||
|
|
||||||
|
#### Anhang: Technische Loesungen
|
||||||
|
|
||||||
|
| Abschnitt | Wichtiger Inhalt |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Was tun bei Fehlern](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-b-common-errors/) | Haeufige Vibe-Coding-Probleme und wie man sie behebt |
|
||||||
|
| [Vergleich von sieben KI-Programmierwerkzeugen](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-articles/example0-1/vibe-coding-tools-snake-game-tutorial) | Wichtige KI-Coding-Plattformen durch praktisches Testen vergleichen |
|
||||||
|
| [Websites mit Agenten entwerfen](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-articles/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents) | Multi-Agent-Zusammenarbeit in der Praxis lernen |
|
||||||
|
|
||||||
|
### II. Junior- und Mid-Level-Entwickler
|
||||||
|
|
||||||
|
#### Frontend
|
||||||
|
|
||||||
|
| Abschnitt | Wichtiger Inhalt |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Frontend 0: Erstelle deinen eigenen Asset-Produktions-Agenten mit Lovart](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/lovart-assets/) | Nanobanana und Lovart verwenden, um visuelle Assets in Mengen zu generieren und einen Zeichen-Agenten mit Intent-Erkennung zu erstellen |
|
||||||
|
| [Frontend 1: Figma & MasterGo Grundlagen](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/figma-mastergo/) | Den Workflow von Designentwuerfen zu implementierungsbereitem UI-Denken lernen |
|
||||||
|
| [Frontend 2: Erste moderne App erstellen - UI-Design](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/ui-design/) | Die UI-Design-Grundlagen hinter modernen Anwendungsoberflaechen lernen |
|
||||||
|
| [Frontend 3: UI-Richtlinien und Multi-Produkt-Design](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/multi-product-ui/) | Konsistenz und Aesthetik ueber mehrere Produkte hinweg mit gemeinsamen UI-Regeln verbessern |
|
||||||
|
| [Frontend 4: Schnittstellen mit LLMs und Skills verschoenern](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/llm-skills-beautiful/) | Prompts und Plugins verwenden, damit KI ausgefeiltere, einzigartige Schnittstellen generiert |
|
||||||
|
| [Frontend 4: Lasst uns Hogwarts-Portraets erstellen](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/hogwarts-portraits/) | Ein interaktives KI-Bild-Frontend-Projekt von Grund auf neu erstellen |
|
||||||
|
| [Frontend 6: Vom Designprototyp zum Projektcode](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/design-to-code/) | Designprototypen in Frontend-Code umwandeln, der tatsaechlich im Browser laeuft |
|
||||||
|
| [Frontend 7: UI mit modernen Komponentenbibliotheken aufwerten](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/modern-component-library/) | Komponentenbibliotheken verwenden, um schneller professionelle Schnittstellen zu erstellen |
|
||||||
|
|
||||||
|
#### Backend
|
||||||
|
|
||||||
|
| Abschnitt | Wichtiger Inhalt |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Backend 1: Git und GitHub lernen](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/git-workflow/) | Kern-Versionskontrolloperationen und Zusammenarbeitsworkflows mit Git meistern |
|
||||||
|
| [Backend 2: Von Datenbanken zu Supabase](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/database-supabase/) | Relationale Datenbankgrundlagen lernen und Supabase als moderne BaaS-Plattform verwenden |
|
||||||
|
| [Backend 3: Backend-API-Design und Entwicklung](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/ai-interface-code/) | KI zur Unterstuetzung von API-Design, Backend-Code-Generierung und API-Dokumentation verwenden |
|
||||||
|
| [Backend 4: Produktprototyp bereitstellen](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/zeabur-deployment/) | Full-Stack-Anwendungen schnell mit Zeabur in der Cloud bereitstellen |
|
||||||
|
| [Backend 5: Von IDEs zu CLI-KI-Coding-Tools](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/modern-cli/) | Terminal-first-KI-Coding-Workflows fuer moderne Entwicklung erkunden |
|
||||||
|
| [Backend 6: Stripe und andere Abrechnungssysteme integrieren](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/stripe-payment/) | Monetarisierung mit Zahlungs- und Abrechnungsfaehigkeiten hinzufuegen |
|
||||||
|
|
||||||
|
#### Große Projekte
|
||||||
|
|
||||||
|
| Abschnitt | Wichtiger Inhalt |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Grosses Projekt 1: Deine erste SaaS-Full-Stack-App - KI-Copywriting-Website](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/fullstack-app/) | Einen KI-Marketing-Copy-Workspace mit Login, Generierung, Abrechnung und Admin-Verwaltung erstellen |
|
||||||
|
| [Grosses Projekt 2: Online-Pruefungs- und Managementsystem](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/modern-frontend-trae/) | Ein Online-Pruefungssystem mit Fragengenerierung, Pruefungsablaeufen und Admin-Tools erstellen |
|
||||||
|
|
||||||
|
#### KI-Faehigkeiten Anhang
|
||||||
|
|
||||||
|
| Abschnitt | Wichtiger Inhalt |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [KI 1: Dify-Grundlagen & Wissensdatenbank-Integration](https://datawhalechina.github.io/easy-vibe/en/stage-2/ai-capabilities/dify-knowledge-base/) | Lernen, KI-Anwendungen mit Dify zu erstellen und private Wissensdatenbanken zu integrieren |
|
||||||
|
|
||||||
|
### III. Fortgeschrittene Entwickler
|
||||||
|
|
||||||
|
#### Claude Code Kernkompetenzen
|
||||||
|
|
||||||
|
| Abschnitt | Wichtiger Inhalt |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Erste Schritte mit Claude Code](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/basics/) | Installation, Einrichtung, Grundlagen und nuetzliche Befehle |
|
||||||
|
| [Claude Code MCP-Leitfaden](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/mcp/) | Claude Code ueber MCP mit GitHub, Datenbanken, APIs und anderen Diensten verbinden |
|
||||||
|
| [Claude Code Skills-Leitfaden](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/skills/) | Expertise in wiederverwendbare Skills verpacken, die du immer wieder nutzen kannst |
|
||||||
|
| [Claude Code fuer langlaufende Aufgaben am Arbeiten halten](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/long-running-tasks/) | Langlaufende Aufgaben so gestalten, dass Coding-Tools weiterarbeiten, bis der Job erledigt ist |
|
||||||
|
| [Claude Agent Teams-Leitfaden](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/agent-teams/) | Mehrere KI-Instanzen wie ein echtes Entwicklungsteam koordinieren |
|
||||||
|
| [Claude Code Superpowers fuer engineering-grade Entwicklung](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/superpowers/) | KI helfen, engineering-grade Code mit TDD und Best Practices zu produzieren |
|
||||||
|
| [Claude Code Workflow Best Practices](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/workflow/) | Best Practices fuer Refactoring, Code Review und taegliche Entwicklung |
|
||||||
|
| [Claude Code Remote-Entwicklung auf Mobilgeraeten](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/mobile-development/) | Claude Code ueber den Desktop hinaus nutzen und einen produktiven Remote-Workflow auf Mobilgeraeten aufbauen |
|
||||||
|
| [Claude Agent SDK vollstaendiger Leitfaden](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/claude-agent-sdk/) | Benutzerdefinierte Agenten-Workflows erstellen und Claude mit dem SDK in deine eigenen Tools integrieren |
|
||||||
|
| [Vom Vibe-Coding zum Spec-Coding](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/spec-coding/) | Vom ad-hoc-Prompting zu einem strukturierteren, spezifikationsgesteuerten KI-Entwicklungsworkflow wechseln |
|
||||||
|
|
||||||
|
#### Plattformuebergreifende Entwicklung
|
||||||
|
|
||||||
|
| Abschnitt | Wichtiger Inhalt |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Die richtige Plattform fuer deine App waehlen](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/choose-platform/) | App-Formen vergleichen und die richtige Plattform basierend auf Nutzern, Szenarien und Bereitstellungszielen waehlen |
|
||||||
|
| [WeChat-Mini-Programm erstellen](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/wechat-miniprogram/) | Das Oekosystem verstehen und ein Frontend-Mini-Programm von der Vorlage bis zum Launch bereitstellen |
|
||||||
|
| [WeChat-Mini-Programm mit Backend erstellen](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/wechat-miniprogram-backend/) | Backend-Logik und Datenbanken hinzufuegen, um die vollstaendige Geschaeftsschleife abzuschliessen |
|
||||||
|
| [Android-App erstellen](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/android-app/) | Android-App-Entwicklung mit einem modernen nativen Workflow lernen |
|
||||||
|
| [iOS-App erstellen](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/ios-app/) | iOS-App-Entwicklung und die Konventionen des Apple-Oekosystems lernen |
|
||||||
|
| [Lokale PWA-App erstellen](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/pwa-local-app/) | Eine Website in eine echte App mit Offline-Unterstuetzung, Push und Installation umwandeln |
|
||||||
|
| [Browser-KI-Assistenten-Erweiterung erstellen](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/browser-ai-extension/) | Eine Chrome-Erweiterung erstellen, die jede Seite mit Cloud-APIs oder eingebauter KI zusammenfasst |
|
||||||
|
| [Electron-Desktop-App erstellen](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/electron-voice-to-text/) | Eine Sprache-zu-Text-Desktop-App mit Electron fuer drei Plattformen erstellen |
|
||||||
|
| [Schnell ein NFT erstellen und praegen](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/nft-minting/) | Einen Smart Contract von Grund auf schreiben, bereitstellen und dein eigenes NFT praegen |
|
||||||
|
| [VS-Code-Erweiterung erstellen](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/vscode-extension/) | Einen KI-Projektassistenten mit Vorlagen, Code-Chat und Multi-File-Q&A erstellen |
|
||||||
|
| [Industrie-grade Qt-Desktop-App erstellen](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/qt-industrial-hmi/) | Ein Echtzeit-Qt-HMI-System mit Trends, Alarmen und Ueberwachung erstellen |
|
||||||
|
|
||||||
|
#### KI-Faehigkeiten Anhang
|
||||||
|
|
||||||
|
| Abschnitt | Wichtiger Inhalt |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Was ist RAG und wie funktioniert es](https://datawhalechina.github.io/easy-vibe/en/stage-3/ai-advanced/rag-introduction/) | Ein systematisches Verstaendnis von RAG-Prinzipien und haeufigen Architekturen aufbauen |
|
||||||
|
| [Fortgeschrittene RAG-Workflows mit LangGraph](https://datawhalechina.github.io/easy-vibe/en/stage-3/ai-advanced/langgraph-advanced-rag/) | Multi-Step-Workflows und fortgeschrittenere RAG-Systeme entwerfen |
|
||||||
|
|
||||||
|
### 📚 Anhang Wissensdatenbank
|
||||||
|
|
||||||
|
> Mit **9 grossen Wissensbereichen** und **ueber 80 interaktiven Themen** hilft dieser Anhang durch Animation und visuelle Komponenten, Kernkonzepte von Informatik-Grundlagen bis zur KI-Frontier intuitiv zu verstehen.
|
||||||
|
>
|
||||||
|
> 👉 [Vollstaendigen Anhang ansehen](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
### 🎓 Weitere Kurse
|
||||||
|
|
||||||
|
- [Hands-on Modern RL](#weitere-kurse)
|
||||||
|
- [Learn Harness Engineering](#weitere-kurse)
|
||||||
|
|
||||||
|
## 🛠️ Wie man lernt
|
||||||
|
|
||||||
|
- Lies und praktiziere die Abschnitte, die deinem aktuellen Level entsprechen. Wenn du nicht weiterkommst, oeffne gerne ein Issue.
|
||||||
|
|
||||||
|
## 💻 Lokal ausfuehren
|
||||||
|
|
||||||
|
### Moderner Ansatz
|
||||||
|
|
||||||
|
In einem KI-IDE-Chatfenster wie VS Code, Cursor oder Trae kannst du einfach sagen:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Bitte hilf mir, dieses Projekt lokal auszufuehren.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Klassischer Ansatz
|
||||||
|
|
||||||
|
1. `npm install`
|
||||||
|
2. `npm run dev`
|
||||||
|
3. Oeffne `http://localhost:3000` in deinem Browser.
|
||||||
|
|
||||||
|
## Weitere Kurse
|
||||||
|
|
||||||
|
Unser Team hat auch weitere Kurse erstellt! Schau dir an:
|
||||||
|
|
||||||
|
[](https://github.com/walkinglabs/hands-on-modern-rl)
|
||||||
|
|
||||||
|
**Hands-on Modern RL**: Ein Open-Source-Hands-on-Lehrplan, der die Luecke von grundlegenden RL-Konzepten zu LLM-Alignment, RLVR und fortgeschrittenen Agenten-Systemen schliesst.
|
||||||
|
|
||||||
|
[](https://github.com/walkinglabs/learn-harness-engineering/tree/main)
|
||||||
|
|
||||||
|
**Learn Harness Engineering**: Ein umfassender Leitfaden fuer Harness Engineering.
|
||||||
|
|
||||||
|
## 🤝 Mitmachen & Mitwirkende
|
||||||
|
|
||||||
|
- Wenn du ein Problem findest oder etwas siehst, das verbessert werden kann, oeffne gerne ein Issue. Wenn niemand antwortet, kannst du auch das [Datawhale-Supportteam](https://github.com/datawhalechina/DOPMC/blob/main/OP.md) kontaktieren.
|
||||||
|
- Wenn du einen Beitrag leisten moechtest, oeffne einen Pull Request. Wenn niemand antwortet, kannst du auch das [Datawhale-Supportteam](https://github.com/datawhalechina/DOPMC/blob/main/OP.md) kontaktieren.
|
||||||
|
- Wenn du ein neues Datawhale-Open-Source-Projekt starten moechtest, folge dem [Datawhale Open-Source-Projekt-Leitfaden](https://github.com/datawhalechina/DOPMC/blob/main/GUIDE.md).
|
||||||
|
|
||||||
|
### 🙏 Mitwirkende
|
||||||
|
|
||||||
|
- [Sanbu - Projektleitung](https://github.com/sanbuphy) (Datawhale-Mitglied)
|
||||||
|
- Fang Ke - Mentor (Datawhale-Mitglied, Tsinghua-Universitaet)
|
||||||
|
- [Yerim Kang](https://github.com/yerim25) (Praxisprojekte, Tsinghua-Universitaet)
|
||||||
|
- [Zhilin Zhao](https://github.com/ChileenZ) (Praxisprojekte, Tsinghua-Universitaet)
|
||||||
|
- [Yixuan Li](https://yixuan20.github.io/) (Visuelles Design, Tsinghua-Universitaet)
|
||||||
|
- Siyi Liu (Praxisprojekte, Tsinghua-Universitaet)
|
||||||
|
- [Lixin Liu](https://github.com/liulx25xx) (Praxisprojekte, Tsinghua-Universitaet)
|
||||||
|
- Alle in der internen Testgruppe AI Vibe Coding 101, die Vorschlaege und Feedback geteilt haben
|
||||||
|
|
||||||
|
### Besonderer Dank
|
||||||
|
|
||||||
|
- Danke an [@Sm1les](https://github.com/Sm1les) fuer die Hilfe und Unterstuetzung bei diesem Projekt
|
||||||
|
- Danke an alle Mitwirkenden und alle, die das Projekt mit Feedback und Sternen unterstuetzt haben ❤️
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a href="https://www.star-history.com/#datawhalechina/easy-vibe&type=timeline&legend=top-left">
|
||||||
|
<picture>
|
||||||
|
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=datawhalechina/easy-vibe&type=timeline&theme=dark&legend=top-left" />
|
||||||
|
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=datawhalechina/easy-vibe&type=timeline&legend=top-left" />
|
||||||
|
</picture>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align=center style="margin-top: 30px;">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=datawhalechina/easy-vibe" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 📄 Lizenz
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
|
||||||
|
<img
|
||||||
|
alt="Creative Commons License"
|
||||||
|
style="border-width:0"
|
||||||
|
src="https://img.shields.io/badge/license-CC%20BY--NC--SA%204.0-lightgrey"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<br />
|
||||||
|
Dieses Werk ist lizenziert unter der
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
|
||||||
|
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
|
||||||
|
</a>.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Stern-Historie
|
||||||
|
|
||||||
|
[](https://www.star-history.com/#datawhalechina/easy-vibe&type=date&legend=top-left)
|
||||||
@@ -0,0 +1,448 @@
|
|||||||
|
<!-- trigger vercel build -->
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
<img src="../../assets/easy-vibe-logo-hd.svg" alt="Easy-Vibe Logo" width="300">
|
||||||
|
|
||||||
|
<img src="../../assets/banner.png" alt="Easy-Vibe Banner" width="100%">
|
||||||
|
|
||||||
|
<p align="center" style="font-size: 1.2em; color: #666; margin: 20px 0;">
|
||||||
|
Jump right in and vibe together — if you can talk, you can build apps.<br>
|
||||||
|
<span style="font-size: 0.9em; color: #888;">直接上手,一起 vibe!会说话就会做应用。</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a href="https://trendshift.io/repositories/22079" target="_blank"><img src="https://trendshift.io/api/badge/repositories/22079" alt="datawhalechina/easy-vibe | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||||
|
|
||||||
|
<p align="center" style="font-size: 1.05em; color: #666; margin: 16px 0;">
|
||||||
|
你好 · Hello · 哈囉 · こんにちは · 안녕하세요 · Hola · Bonjour · Hallo · مرحبا · Xin chào<br>
|
||||||
|
Stage 1 of our tutorial is now available in 10 languages. Friends around the world, let's start coding together!<br>
|
||||||
|
<span style="font-size: 0.9em; color: #888;">我们的教程(第一部分)已经支持 10 种语言,欢迎世界各地的朋友一起 coding!</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
🚀 <a href="https://datawhalechina.github.io/easy-vibe/welcome.html">Start Exploring</a> · ✨ <a href="https://datawhalechina.github.io/easy-vibe/en/appendix/">Interactive Tutorial</a> · 🦞 <a href="https://github.com/datawhalechina/hello-claw">Learn OpenClaw</a> · 📖 <a href="#table-of-contents">Table of Contents</a><br>
|
||||||
|
<span style="font-size: 0.85em; color: #888;">🚀 <a href="https://datawhalechina.github.io/easy-vibe/welcome.html">开始体验</a> · ✨ <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/">交互式教程</a> · 🦞 <a href="https://github.com/datawhalechina/hello-claw">学习 OpenClaw</a> · 📖 <a href="#table-of-contents">查看目录</a></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://datawhalechina.github.io/easy-vibe/welcome.html">Read Online</a> ·
|
||||||
|
<a href="#-content-navigation">Learning Map</a><br>
|
||||||
|
<span style="font-size: 0.85em; color: #888;">
|
||||||
|
<a href="https://datawhalechina.github.io/easy-vibe/welcome.html">开始阅读</a> ·
|
||||||
|
<a href="#-content-navigation">学习地图</a>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/stargazers" target="_blank">
|
||||||
|
<img src="https://img.shields.io/github/stars/datawhalechina/easy-vibe?color=660874&style=for-the-badge&logo=star&logoColor=white&labelColor=1a1a2e" alt="Stars"></a>
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/network/members" target="_blank">
|
||||||
|
<img src="https://img.shields.io/github/forks/datawhalechina/easy-vibe?color=660874&style=for-the-badge&logo=git-fork&logoColor=white&labelColor=1a1a2e" alt="Forks"></a>
|
||||||
|
<a href="../../LICENSE" target="_blank">
|
||||||
|
<img src="https://img.shields.io/badge/License-CC_BY_NC_SA_4.0-4ecdc4?style=for-the-badge&logo=creative-commons&logoColor=white&labelColor=1a1a2e" alt="License"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="../en-US/README.md"><img alt="English" src="https://img.shields.io/badge/English-d9d9d9"></a>
|
||||||
|
<a href="../zh-CN/README.md"><img alt="简体中文" src="https://img.shields.io/badge/简体中文-d9d9d9"></a>
|
||||||
|
<a href="../zh-TW/README.md"><img alt="繁體中文" src="https://img.shields.io/badge/繁體中文-d9d9d9"></a>
|
||||||
|
<a href="../ja-JP/README.md"><img alt="日本語" src="https://img.shields.io/badge/日本語-d9d9d9"></a>
|
||||||
|
<a href="../es-ES/README.md"><img alt="Español" src="https://img.shields.io/badge/Español-d9d9d9"></a>
|
||||||
|
<a href="../fr-FR/README.md"><img alt="Français" src="https://img.shields.io/badge/Français-d9d9d9"></a>
|
||||||
|
<a href="../ko-KR/README.md"><img alt="한국어" src="https://img.shields.io/badge/한국어-d9d9d9"></a>
|
||||||
|
<a href="../ar-SA/README.md"><img alt="العربية" src="https://img.shields.io/badge/العربية-d9d9d9"></a>
|
||||||
|
<a href="../vi-VN/README.md"><img alt="Tiếng_Việt" src="https://img.shields.io/badge/Tiếng_Việt-d9d9d9"></a>
|
||||||
|
<a href="../de-DE/README.md"><img alt="Deutsch" src="https://img.shields.io/badge/Deutsch-d9d9d9"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<table align="center">
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-header.png" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>A beginner-friendly learning map</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Clear guidance from zero, so you can stop "learning and forgetting"</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-tutorial.png" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Step-by-step visual tutorials</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Detailed walkthroughs that feel like learning with a private tutor</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-ide.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Immersive simulated coding</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Virtual mouse guidance helps you quickly learn the core IDE workflow</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-diffusion.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Visible AI principles</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Animated explanations make it easy to see how AI generates images</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-rag.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Learn RAG like a game</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Interactive components let you click through the full RAG data flow</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/git-terminal.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Visual terminal concepts</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Command-line behavior becomes intuitive when the underlying logic is visualized</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div align="center">
|
||||||
|
<h3>⭐ <a href="https://github.com/datawhalechina/easy-vibe" style="color: #d0cd16ff;">Star the repo here</a> to help accelerate updates ❤️</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align="center" style="margin: 30px 0;">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/issues/new?template=story_submission.md">
|
||||||
|
<img src="https://raw.githubusercontent.com/datawhalechina/easy-vibe/main/assets/stories_image.png" alt="Share Your Vibe Story" width="80%" style="border-radius: 10px; box-shadow: 0 4px 12px rgba(0,0,0,0.15);">
|
||||||
|
</a>
|
||||||
|
<p style="margin-top: 15px; font-size: 1.1em; color: #666;">
|
||||||
|
📝 <strong>Have your own vibe coding story?</strong>
|
||||||
|
Submit it here and inspire others!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Why Easy-Vibe](#why-easy-vibe)
|
||||||
|
- [News](#-news)
|
||||||
|
- [Who This Is For](#who-this-is-for)
|
||||||
|
- [Your Learning Paths](#your-learning-paths)
|
||||||
|
- [Study Suggestions](#study-suggestions)
|
||||||
|
- [I. Beginner Entry](#i-beginner-entry)
|
||||||
|
- [II. Junior and Mid-Level Developers](#ii-junior-and-mid-level-developers)
|
||||||
|
- [III. Advanced Developers](#iii-advanced-developers)
|
||||||
|
- [Appendix Knowledge Base](#-appendix-knowledge-base)
|
||||||
|
- [How To Learn](#️-how-to-learn)
|
||||||
|
- [Run Locally](#-run-locally)
|
||||||
|
- [Other Courses](#other-courses)
|
||||||
|
- [Contributing & Contributors](#-contributing--contributors)
|
||||||
|
- [LICENSE](#-license)
|
||||||
|
|
||||||
|
## Why Easy-Vibe
|
||||||
|
|
||||||
|
Want an expense tracker? Say it.
|
||||||
|
|
||||||
|
Need a booking system with WeChat login? Say it.
|
||||||
|
|
||||||
|
Want a blog with comments? Say it.
|
||||||
|
|
||||||
|
In the AI era, programming starts by describing what you want.
|
||||||
|
|
||||||
|
Easy-Vibe teaches you how to turn that into a real product.
|
||||||
|
|
||||||
|
|
||||||
|
## 🔥 News
|
||||||
|
|
||||||
|
- **[2026-05-20]** 🌍 **Stage 1 multilingual coverage is now complete**: Stage 1 is fully available across all supported locales (zh-cn, en, zh-tw, ja-jp, ko-kr, es-es, fr-fr, de-de, ar-sa, vi-vn). Navigation/build checks have been verified to avoid 404s.
|
||||||
|
- **[2026-03-29]** ✨ **Vibe Stories launched and upgraded with real user journeys**: Added a new homepage Vibe Stories section with an interactive carousel and dedicated story pages, then replaced placeholder content with four real user stories featuring a rural primary school teacher, a college student, a high school IT teacher, and a truck driver who built real products with AI. [👉 View the stories](https://datawhalechina.github.io/easy-vibe/zh-cn/vibe-stories/story-1.html)
|
||||||
|
- **[2026-03-26]** 🚀 **Major Stage 2 practice update**: Completed the SaaS capstone project "[Your First SaaS Full-Stack App: Copywriting Generator Website](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/fullstack-app/)" and substantially expanded the "[How to integrate Stripe and payment systems](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/stripe-payment/)" section, plus key content around multi-product UI and WeChat Mini Program backend workflows.
|
||||||
|
- **[2026-03-25]** 📚 **New appendix: User Research and Requirement Validation**: Added four new articles covering idea sourcing, the Double Diamond model, Jobs to Be Done, and The Mom Test to help beginners discover and validate product ideas. [👉 Read the appendix](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
- **[2026-03-25]** 📚 **English documentation fully updated**: Stage 2 (Full-stack Development) and Stage 3 (Advanced Development) are now fully available in English. [👉 Start learning](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
<details>
|
||||||
|
<summary>Past News</summary>
|
||||||
|
|
||||||
|
- **[2026-03-02]** 🦞 **OpenClaw and AI Agent friendly support**: Added `llms.txt` so OpenClaw, Claude, Cursor, Trae, and other AI agents can quickly understand the repository structure and find the right tutorial content.
|
||||||
|
- **[2026-03-01]** The [Advanced Development section](https://datawhalechina.github.io/easy-vibe/en/stage-3/) has been comprehensively upgraded with deep guides for Claude Code, including MCP, Skills, Agent Teams, and more, along with eight cross-platform project tutorials.
|
||||||
|
- **[2026-02-25]** Updated the [Appendix Knowledge Base](https://datawhalechina.github.io/easy-vibe/en/appendix/), now covering 9 knowledge areas and 80+ interactive topics.
|
||||||
|
- **[2026-01-27]** Added Android and iOS app development tutorials.
|
||||||
|
- **[2026-01-19]** Released interactive demos for Prompt Engineering, AI history, authentication design, Git principles, and more.
|
||||||
|
- **[2026-01-16]** Reorganized the project structure and formally established a beginner entry path.
|
||||||
|
- **[2026-01-14]** Completed a large update to the Stage 1 product prototyping docs.
|
||||||
|
- **[2026-01-13]** Refactored the documentation architecture and fully enabled multi-language support.
|
||||||
|
- **[2026-01-01]** Released the core learning map for the project.
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## Who This Is For
|
||||||
|
|
||||||
|
- **Complete beginners**: Build your first project first, then understand how it works
|
||||||
|
- **Product managers / founders**: Validate ideas fast and build MVPs at low cost
|
||||||
|
- **Students**: Develop practical skills for the AI era
|
||||||
|
- **Junior developers**: Learn the full path from idea to launch
|
||||||
|
- **Mid-level and senior developers**: Upgrade your AI collaboration workflow for complex projects
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Your Learning Paths
|
||||||
|
|
||||||
|
### 🎮 I want a fast first win
|
||||||
|
**Best for**: Everyone
|
||||||
|
**What you will learn**: What AI coding actually feels like through a simple, concrete hands-on example
|
||||||
|
**What you will get**: A clear first impression of vibe coding and how to work with AI by conversation
|
||||||
|
|
||||||
|
[Start here](https://datawhalechina.github.io/easy-vibe/en/stage-1/ai-capabilities-through-games/)
|
||||||
|
|
||||||
|
### 💡 I want to turn an idea into a product prototype
|
||||||
|
**Best for**: Beginners / product managers / founders
|
||||||
|
**What you will learn**: Learning roadmap, AI IDE tools, idea validation, prototyping, AI capability integration, and full demo iteration
|
||||||
|
**What you will get**: A demoable AI product prototype you can actually show to users or teammates
|
||||||
|
|
||||||
|
[Start learning](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/)
|
||||||
|
|
||||||
|
### 🚀 I want to build full-stack products end to end
|
||||||
|
**Best for**: Junior developers / indie hackers / advanced learners
|
||||||
|
**What you will learn**: Frontend workflows, design-to-code, databases, backend APIs, deployment, billing, and major projects
|
||||||
|
**What you will get**: The ability to independently ship modern AI-enabled web applications
|
||||||
|
|
||||||
|
[Start learning](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
|
||||||
|
### AI-Native: I want advanced Claude Code and agent workflows
|
||||||
|
**Best for**: Developers interested in AI-native engineering
|
||||||
|
**What you will learn**: Claude Code, MCP, Skills, Agent Teams, long-running tasks, Spec Coding, and cross-platform app delivery
|
||||||
|
**What you will get**: A stronger workflow for complex AI-assisted development and automation
|
||||||
|
|
||||||
|
[Go to advanced development](https://datawhalechina.github.io/easy-vibe/en/stage-3/)
|
||||||
|
|
||||||
|
### 📚 I want reference material and fundamentals
|
||||||
|
**Best for**: Everyone
|
||||||
|
**What you will learn**: Computer fundamentals, frontend/backend basics, infrastructure, AI principles, and engineering practices
|
||||||
|
**What you will get**: A long-term reference knowledge base covering 9 major knowledge areas
|
||||||
|
|
||||||
|
[Browse the knowledge base](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
## Study Suggestions
|
||||||
|
|
||||||
|
- If you are a beginner, product manager, or founder, start with [Stage 1](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/)
|
||||||
|
- If you want to move from prototypes to full-stack delivery, start with [Stage 2](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
- If you want advanced Claude Code workflows or cross-platform projects, go to [Stage 3](https://datawhalechina.github.io/easy-vibe/en/stage-3/)
|
||||||
|
- If you get blocked by concepts or missing background knowledge, use the [Appendix Knowledge Base](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
### 📖 Content Navigation
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<img src="../../assets/readme-image1.png" alt="Learning Map" width="70%" style="border-radius: 10px; box-shadow: 0 8px 20px rgba(45,55,72,0.3); margin: 15px 0;"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
### I. Beginner Entry
|
||||||
|
|
||||||
|
| Section | Key Content |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Learning Map](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/) | A guided overview of the full learning journey |
|
||||||
|
| [AI Era: If You Can Speak, You Can Code](https://datawhalechina.github.io/easy-vibe/en/stage-1/ai-capabilities-through-games/) | Get your first feel for AI coding through examples like Snake |
|
||||||
|
| [Master AI Programming Tools](https://datawhalechina.github.io/easy-vibe/en/stage-1/introduction-to-ai-ide/) | Learn how AI IDE tools work and build simple local projects with them |
|
||||||
|
| [Find Great Ideas](https://datawhalechina.github.io/easy-vibe/en/stage-1/finding-great-idea/) | Learn how to discover and validate product ideas worth building |
|
||||||
|
| [Build Product Prototypes](https://datawhalechina.github.io/easy-vibe/en/stage-1/building-prototype/) | Move from requirements to single-page and multi-page product prototypes |
|
||||||
|
| [Integrate AI Capabilities](https://datawhalechina.github.io/easy-vibe/en/stage-1/integrating-ai-capabilities/) | Integrate text, image, and video AI features |
|
||||||
|
| [Complete project practice](https://datawhalechina.github.io/easy-vibe/en/stage-1/complete-project-practice/) | Simulate real scenarios, collect user feedback, and iterate on a full project |
|
||||||
|
|
||||||
|
#### Appendix: Product and Business Thinking
|
||||||
|
|
||||||
|
| Section | Key Content |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Product Thinking and Solution Design](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-a-product-thinking/) | Core frameworks for going from zero to one with a product |
|
||||||
|
| [AI Industry Application Scenarios (B-end)](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-industry-scenarios/) | Understand how AI is applied across industries |
|
||||||
|
| [AI Consumer Scenarios Inspiration (C-end)](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-c-consumer-scenarios/) | Explore product opportunities in consumer AI |
|
||||||
|
|
||||||
|
#### Appendix: User Research and Requirement Validation
|
||||||
|
|
||||||
|
| Section | Key Content |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Where to find ideas: 3 reference sources that work best for beginners](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-idea-sources/) | Build a reliable pipeline for finding concrete product opportunities |
|
||||||
|
| [Double Diamond: first do the right thing, then do it right](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-double-diamond/) | Use a structured process to move from scattered inspiration to a workable direction |
|
||||||
|
| [Use Jobs to Be Done to find what users really want done](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-jobs-to-be-done/) | Analyze user goals through real tasks instead of surface-level feature requests |
|
||||||
|
| [The Mom Test: a user interview method for validating demand](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-mom-test/) | Learn how to ask better questions and avoid false-positive feedback |
|
||||||
|
|
||||||
|
#### Appendix: Technical Solutions
|
||||||
|
|
||||||
|
| Section | Key Content |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [What to do if you encounter errors](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-b-common-errors/) | Common vibe coding issues and how to troubleshoot them |
|
||||||
|
| [Comparison of Seven AI Programming Tools](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-articles/example0-1/vibe-coding-tools-snake-game-tutorial) | Compare major AI coding platforms through hands-on testing |
|
||||||
|
| [Design Websites with Agents](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-articles/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents) | Learn multi-agent collaboration in practice |
|
||||||
|
|
||||||
|
### II. Junior and Mid-Level Developers
|
||||||
|
|
||||||
|
#### Frontend
|
||||||
|
|
||||||
|
| Section | Key Content |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Frontend 0: Build Your Own Asset-Production Agent with Lovart](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/lovart-assets/) | Use Nanobanana and Lovart to batch-generate visual assets and build a drawing agent with intent recognition |
|
||||||
|
| [Frontend 1: Figma & MasterGo Basics](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/figma-mastergo/) | Learn the workflow from design drafts to implementation-ready UI thinking |
|
||||||
|
| [Frontend 2: Build Your First Modern App - UI Design](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/ui-design/) | Learn the UI design foundations behind modern application interfaces |
|
||||||
|
| [Frontend 3: UI Guidelines and Multi-Product Design](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/multi-product-ui/) | Improve consistency and aesthetics across multiple products with shared UI rules |
|
||||||
|
| [Frontend 4: Make Interfaces Beautiful with LLMs and Skills](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/llm-skills-beautiful/) | Use prompts and plugins to make AI generate more polished, distinctive interfaces |
|
||||||
|
| [Frontend 4: Let's Build Hogwarts Portraits](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/hogwarts-portraits/) | Build an interactive AI-image frontend project from scratch |
|
||||||
|
| [Frontend 6: From Design Prototype to Project Code](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/design-to-code/) | Turn design prototypes into frontend code that can really run in the browser |
|
||||||
|
| [Frontend 7: Upgrade Your UI with Modern Component Libraries](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/modern-component-library/) | Use component libraries to build professional interfaces faster |
|
||||||
|
|
||||||
|
#### Backend
|
||||||
|
|
||||||
|
| Section | Key Content |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Backend 1: Learn Git and GitHub](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/git-workflow/) | Master core version control operations and collaboration workflows with Git |
|
||||||
|
| [Backend 2: From Database to Supabase](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/database-supabase/) | Learn relational database basics and use Supabase as a modern BaaS platform |
|
||||||
|
| [Backend 3: Backend API Design and Development](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/ai-interface-code/) | Use AI to assist API design, backend code generation, and API documentation |
|
||||||
|
| [Backend 4: Ship Your Product Prototype](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/zeabur-deployment/) | Quickly deploy full-stack applications to the cloud with Zeabur |
|
||||||
|
| [Backend 5: From IDEs to CLI AI Coding Tools](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/modern-cli/) | Explore terminal-first AI coding workflows for modern development |
|
||||||
|
| [Backend 6: Integrate Stripe and Other Billing Systems](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/stripe-payment/) | Add monetization with payment and billing capabilities |
|
||||||
|
|
||||||
|
#### Major Projects
|
||||||
|
|
||||||
|
| Section | Key Content |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Major Project 1: Your First SaaS Full-Stack App - AI Copywriting Website](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/fullstack-app/) | Build an AI marketing copy workspace with login, generation, billing, and admin management |
|
||||||
|
| [Major Project 2: Online Exam and Management System](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/modern-frontend-trae/) | Build an online exam system with question generation, test-taking flows, and admin tools |
|
||||||
|
|
||||||
|
#### AI Capabilities Appendix
|
||||||
|
|
||||||
|
| Section | Key Content |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [AI 1: Dify Basics & Knowledge Base Integration](https://datawhalechina.github.io/easy-vibe/en/stage-2/ai-capabilities/dify-knowledge-base/) | Learn to build AI applications with Dify and integrate private knowledge bases |
|
||||||
|
|
||||||
|
### III. Advanced Developers
|
||||||
|
|
||||||
|
#### Claude Code Core Skills
|
||||||
|
|
||||||
|
| Section | Key Content |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Getting started with Claude Code](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/basics/) | Installation, setup, fundamentals, and useful commands |
|
||||||
|
| [Claude Code MCP guide](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/mcp/) | Connect Claude Code to GitHub, databases, APIs, and other services through MCP |
|
||||||
|
| [Claude Code Skills guide](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/skills/) | Package expertise into reusable skills you can use again and again |
|
||||||
|
| [How to keep Claude Code working for long-running tasks](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/long-running-tasks/) | Design long-running tasks so coding tools can keep working until the job is done |
|
||||||
|
| [Claude Agent Teams guide](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/agent-teams/) | Coordinate multiple AI instances like a real development team |
|
||||||
|
| [Claude Code Superpowers for engineering-grade development](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/superpowers/) | Help AI produce engineering-grade code with TDD and best practices |
|
||||||
|
| [Claude Code workflow best practices](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/workflow/) | Best practices for refactoring, code review, and daily development |
|
||||||
|
| [Claude Code remote development on mobile](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/mobile-development/) | Use Claude Code beyond the desktop and build a productive remote workflow on mobile devices |
|
||||||
|
| [Claude Agent SDK complete guide](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/claude-agent-sdk/) | Build custom agent workflows and integrate Claude into your own tools with the SDK |
|
||||||
|
| [From vibe coding to spec coding](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/spec-coding/) | Move from ad-hoc prompting to a more structured, specification-driven AI development workflow |
|
||||||
|
|
||||||
|
#### Cross-Platform Development
|
||||||
|
|
||||||
|
| Section | Key Content |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [How to choose the right platform for your app](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/choose-platform/) | Compare app forms and choose the right platform based on users, scenarios, and delivery goals |
|
||||||
|
| [Build a WeChat Mini Program](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/wechat-miniprogram/) | Understand the ecosystem and ship a frontend mini program from template to launch |
|
||||||
|
| [Build a WeChat Mini Program with backend](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/wechat-miniprogram-backend/) | Add backend logic and databases to complete the full business loop |
|
||||||
|
| [Build an Android app](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/android-app/) | Learn Android app development with a modern native workflow |
|
||||||
|
| [Build an iOS app](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/ios-app/) | Learn iOS app development and the conventions of the Apple ecosystem |
|
||||||
|
| [Build a local PWA app](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/pwa-local-app/) | Turn a website into a real app with offline support, push, and installation |
|
||||||
|
| [Build a browser AI assistant extension](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/browser-ai-extension/) | Create a Chrome extension that summarizes any page with either cloud APIs or built-in AI |
|
||||||
|
| [Build an Electron desktop app](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/electron-voice-to-text/) | Build a voice-to-text desktop app with Electron for three platforms |
|
||||||
|
| [Rapidly build and mint an NFT](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/nft-minting/) | Write a smart contract from scratch, deploy it, and mint your own NFT |
|
||||||
|
| [Build a VS Code extension](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/vscode-extension/) | Build an AI project assistant with templates, code chat, and multi-file Q&A |
|
||||||
|
| [Build an industrial-grade Qt desktop app](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/qt-industrial-hmi/) | Create a real-time Qt HMI system with trends, alerts, and monitoring |
|
||||||
|
|
||||||
|
#### AI Capabilities Appendix
|
||||||
|
|
||||||
|
| Section | Key Content |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [What is RAG and how does it work](https://datawhalechina.github.io/easy-vibe/en/stage-3/ai-advanced/rag-introduction/) | Build a systematic understanding of RAG principles and common architectures |
|
||||||
|
| [Intermediate and advanced RAG workflows with LangGraph](https://datawhalechina.github.io/easy-vibe/en/stage-3/ai-advanced/langgraph-advanced-rag/) | Design multi-step workflows and more advanced RAG systems |
|
||||||
|
|
||||||
|
### 📚 Appendix Knowledge Base
|
||||||
|
|
||||||
|
> Covering **9 major knowledge areas** and **80+ interactive topics**, this appendix uses animation and visual components to help you intuitively understand core concepts from computer fundamentals to the AI frontier.
|
||||||
|
>
|
||||||
|
> 👉 [View the full appendix](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
### 🎓 Other Courses
|
||||||
|
|
||||||
|
- [Hands-on Modern RL](#other-courses)
|
||||||
|
- [Learn Harness Engineering](#other-courses)
|
||||||
|
|
||||||
|
## 🛠️ How To Learn
|
||||||
|
|
||||||
|
- Read and practice the sections that match your current level. If you get stuck, feel free to open an issue.
|
||||||
|
|
||||||
|
## 💻 Run Locally
|
||||||
|
|
||||||
|
### Modern approach
|
||||||
|
|
||||||
|
In an AI IDE chat window such as VS Code, Cursor, or Trae, you can simply say:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Please help me run this project locally.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Traditional approach
|
||||||
|
|
||||||
|
1. `npm install`
|
||||||
|
2. `npm run dev`
|
||||||
|
3. Open `http://localhost:3000` in your browser.
|
||||||
|
|
||||||
|
## Other Courses
|
||||||
|
|
||||||
|
Our team has also created other courses! Check them out:
|
||||||
|
|
||||||
|
[](https://github.com/walkinglabs/hands-on-modern-rl)
|
||||||
|
|
||||||
|
**Hands-on Modern RL**: An open-source, hands-on curriculum bridging the gap from basic RL concepts to LLM alignment, RLVR, and advanced Agentic systems.
|
||||||
|
|
||||||
|
[](https://github.com/walkinglabs/learn-harness-engineering/tree/main)
|
||||||
|
|
||||||
|
**Learn Harness Engineering**: A comprehensive guide to harness engineering.
|
||||||
|
|
||||||
|
## 🤝 Contributing & Contributors
|
||||||
|
|
||||||
|
- If you find an issue or see something that can be improved, feel free to open an issue. If nobody replies, you can also contact the [Datawhale support team](https://github.com/datawhalechina/DOPMC/blob/main/OP.md).
|
||||||
|
- If you want to contribute, open a pull request. If nobody replies, you can also contact the [Datawhale support team](https://github.com/datawhalechina/DOPMC/blob/main/OP.md).
|
||||||
|
- If you want to start a new Datawhale open-source project, please follow the [Datawhale Open Source Project Guide](https://github.com/datawhalechina/DOPMC/blob/main/GUIDE.md).
|
||||||
|
|
||||||
|
### 🙏 Contributors
|
||||||
|
|
||||||
|
- [Sanbu - Project Lead](https://github.com/sanbuphy) (Datawhale member)
|
||||||
|
- Fang Ke - Mentor (Datawhale member, Tsinghua University)
|
||||||
|
- [Yerim Kang](https://github.com/yerim25) (Practice projects, Tsinghua University)
|
||||||
|
- [Zhilin Zhao](https://github.com/ChileenZ) (Practice projects, Tsinghua University)
|
||||||
|
- [Yixuan Li](https://yixuan20.github.io/) (Visual design, Tsinghua University)
|
||||||
|
- Siyi Liu (Practice projects, Tsinghua University)
|
||||||
|
- [Lixin Liu](https://github.com/liulx25xx) (Practice projects, Tsinghua University)
|
||||||
|
- Everyone in the AI Vibe Coding 101 internal testing group who shared suggestions and feedback
|
||||||
|
|
||||||
|
### Special Thanks
|
||||||
|
|
||||||
|
- Thanks to [@Sm1les](https://github.com/Sm1les) for the help and support on this project
|
||||||
|
- Thanks to every contributor and everyone who supported the project with feedback and stars ❤️
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a href="https://www.star-history.com/#datawhalechina/easy-vibe&type=timeline&legend=top-left">
|
||||||
|
<picture>
|
||||||
|
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=datawhalechina/easy-vibe&type=timeline&theme=dark&legend=top-left" />
|
||||||
|
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=datawhalechina/easy-vibe&type=timeline&legend=top-left" />
|
||||||
|
</picture>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align=center style="margin-top: 30px;">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=datawhalechina/easy-vibe" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 📄 LICENSE
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
|
||||||
|
<img
|
||||||
|
alt="Creative Commons License"
|
||||||
|
style="border-width:0"
|
||||||
|
src="https://img.shields.io/badge/license-CC%20BY--NC--SA%204.0-lightgrey"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<br />
|
||||||
|
This work is licensed under the
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
|
||||||
|
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
|
||||||
|
</a>.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Star History
|
||||||
|
|
||||||
|
[](https://www.star-history.com/#datawhalechina/easy-vibe&type=date&legend=top-left)
|
||||||
@@ -0,0 +1,448 @@
|
|||||||
|
<!-- trigger vercel build -->
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
<img src="../../assets/easy-vibe-logo-hd.svg" alt="Easy-Vibe Logo" width="300">
|
||||||
|
|
||||||
|
<img src="../../assets/banner.png" alt="Banner de Easy-Vibe" width="100%">
|
||||||
|
|
||||||
|
<p align="center" style="font-size: 1.2em; color: #666; margin: 20px 0;">
|
||||||
|
Empieza ya y vibrea con nosotros. Si puedes hablar, puedes crear apps.<br>
|
||||||
|
<span style="font-size: 0.9em; color: #888;">直接上手,一起 vibe!会说话就会做应用。</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a href="https://trendshift.io/repositories/22079" target="_blank"><img src="https://trendshift.io/api/badge/repositories/22079" alt="datawhalechina/easy-vibe | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||||
|
|
||||||
|
<p align="center" style="font-size: 1.05em; color: #666; margin: 16px 0;">
|
||||||
|
你好 · Hello · 哈囉 · こんにちは · 안녕하세요 · Hola · Bonjour · Hallo · مرحبا · Xin chào<br>
|
||||||
|
La primera parte de nuestro tutorial ya está disponible en 10 idiomas. Amigos de todo el mundo, empecemos a coding juntos!<br>
|
||||||
|
<span style="font-size: 0.9em; color: #888;">我们的教程(第一部分)已经支持 10 种语言,欢迎世界各地的朋友一起 coding!</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
🚀 <a href="https://datawhalechina.github.io/easy-vibe/welcome.html">Empezar ahora</a> · ✨ <a href="https://datawhalechina.github.io/easy-vibe/en/appendix/">Tutorial interactivo</a> · 🦞 <a href="https://github.com/datawhalechina/hello-claw">Aprender OpenClaw</a> · 📖 <a href="#table-of-contents">Tabla de contenidos</a><br>
|
||||||
|
<span style="font-size: 0.85em; color: #888;">🚀 <a href="https://datawhalechina.github.io/easy-vibe/welcome.html">开始体验</a> · ✨ <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/">交互式教程</a> · 🦞 <a href="https://github.com/datawhalechina/hello-claw">学习 OpenClaw</a> · 📖 <a href="#table-of-contents">查看目录</a></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://datawhalechina.github.io/easy-vibe/welcome.html">Leer en línea</a> ·
|
||||||
|
<a href="#-content-navigation">Mapa de aprendizaje</a><br>
|
||||||
|
<span style="font-size: 0.85em; color: #888;">
|
||||||
|
<a href="https://datawhalechina.github.io/easy-vibe/welcome.html">开始阅读</a> ·
|
||||||
|
<a href="#-content-navigation">学习地图</a>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/stargazers" target="_blank">
|
||||||
|
<img src="https://img.shields.io/github/stars/datawhalechina/easy-vibe?color=660874&style=for-the-badge&logo=star&logoColor=white&labelColor=1a1a2e" alt="Stars"></a>
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/network/members" target="_blank">
|
||||||
|
<img src="https://img.shields.io/github/forks/datawhalechina/easy-vibe?color=660874&style=for-the-badge&logo=git-fork&logoColor=white&labelColor=1a1a2e" alt="Forks"></a>
|
||||||
|
<a href="../../LICENSE" target="_blank">
|
||||||
|
<img src="https://img.shields.io/badge/License-CC_BY_NC_SA_4.0-4ecdc4?style=for-the-badge&logo=creative-commons&logoColor=white&labelColor=1a1a2e" alt="License"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="../zh-CN/README.md"><img alt="简体中文" src="https://img.shields.io/badge/简体中文-d9d9d9"></a>
|
||||||
|
<a href="../zh-TW/README.md"><img alt="繁體中文" src="https://img.shields.io/badge/繁體中文-d9d9d9"></a>
|
||||||
|
<a href="../en-US/README.md"><img alt="English" src="https://img.shields.io/badge/English-d9d9d9"></a>
|
||||||
|
<a href="../ja-JP/README.md"><img alt="日本語" src="https://img.shields.io/badge/日本語-d9d9d9"></a>
|
||||||
|
<a href="../es-ES/README.md"><img alt="Español" src="https://img.shields.io/badge/Español-d9d9d9"></a>
|
||||||
|
<a href="../fr-FR/README.md"><img alt="Français" src="https://img.shields.io/badge/Français-d9d9d9"></a>
|
||||||
|
<a href="../ko-KR/README.md"><img alt="한국어" src="https://img.shields.io/badge/한국어-d9d9d9"></a>
|
||||||
|
<a href="../ar-SA/README.md"><img alt="العربية" src="https://img.shields.io/badge/العربية-d9d9d9"></a>
|
||||||
|
<a href="../vi-VN/README.md"><img alt="Tiếng_Việt" src="https://img.shields.io/badge/Tiếng_Việt-d9d9d9"></a>
|
||||||
|
<a href="../de-DE/README.md"><img alt="Deutsch" src="https://img.shields.io/badge/Deutsch-d9d9d9"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<table align="center">
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-header.png" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Un mapa de aprendizaje para principiantes</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Guía clara desde cero, para que dejes de "aprender y olvidar"</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-tutorial.png" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Tutoriales visuales paso a paso</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Explicaciones detalladas que parecen aprender con un tutor privado</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-ide.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Programación simulada inmersiva</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Un ratón virtual te guía para aprender rápidamente el flujo de trabajo del IDE</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-diffusion.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Principios de IA visibles</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Explicaciones animadas que facilitan ver cómo la IA genera imágenes</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-rag.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Aprende RAG como en un juego</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Componentes interactivos que te permiten hacer clic en el flujo completo de datos RAG</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/git-terminal.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Conceptos de terminal visuales</strong>
|
||||||
|
<br>
|
||||||
|
<sub>El comportamiento de la línea de comandos se vuelve intuitivo al visualizar la lógica subyacente</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div align="center">
|
||||||
|
<h3>⭐ <a href="https://github.com/datawhalechina/easy-vibe" style="color: #d0cd16ff;">Marca con una estrella el repositorio aquí</a> para ayudar a acelerar las actualizaciones ❤️</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align="center" style="margin: 30px 0;">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/issues/new?template=story_submission.md">
|
||||||
|
<img src="https://raw.githubusercontent.com/datawhalechina/easy-vibe/main/assets/stories_image.png" alt="Comparte tu historia Vibe" width="80%" style="border-radius: 10px; box-shadow: 0 4px 12px rgba(0,0,0,0.15);">
|
||||||
|
</a>
|
||||||
|
<p style="margin-top: 15px; font-size: 1.1em; color: #666;">
|
||||||
|
📝 <strong>¿Tienes tu propia historia de vibe coding?</strong>
|
||||||
|
¡Envíala aquí e inspira a otros!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Tabla de contenidos
|
||||||
|
|
||||||
|
- [Por qué Easy-Vibe](#por-qué-easy-vibe)
|
||||||
|
- [Noticias](#-news)
|
||||||
|
- [Para quién es esto](#para-quién-es-esto)
|
||||||
|
- [Tus rutas de aprendizaje](#tus-rutas-de-aprendizaje)
|
||||||
|
- [Sugerencias de estudio](#sugerencias-de-estudio)
|
||||||
|
- [I. Entrada para principiantes](#i-entrada-para-principiantes)
|
||||||
|
- [II. Desarrolladores junior e intermedios](#ii-desarrolladores-junior-e-intermedios)
|
||||||
|
- [III. Desarrolladores avanzados](#iii-desarrolladores-avanzados)
|
||||||
|
- [Base de conocimiento del apéndice](#-base-de-conocimiento-del-apéndice)
|
||||||
|
- [Cómo aprender](#️-cómo-aprender)
|
||||||
|
- [Ejecutar localmente](#-ejecutar-localmente)
|
||||||
|
- [Otros cursos](#otros-cursos)
|
||||||
|
- [Contribuir y colaboradores](#-contribuir-y-colaboradores)
|
||||||
|
- [LICENCIA](#-licencia)
|
||||||
|
|
||||||
|
## Por qué Easy-Vibe
|
||||||
|
|
||||||
|
¿Quieres una aplicación para controlar ingresos y gastos? Solo dilo.
|
||||||
|
|
||||||
|
¿Necesitas un sistema de reservas con inicio de sesión por WeChat? Solo dilo.
|
||||||
|
|
||||||
|
¿Quieres un blog con comentarios? Solo dilo.
|
||||||
|
|
||||||
|
En la era de la IA, programar empieza por describir lo que quieres.
|
||||||
|
|
||||||
|
Easy-Vibe te enseña a convertir eso en un producto real.
|
||||||
|
|
||||||
|
|
||||||
|
## 🔥 News
|
||||||
|
|
||||||
|
- **[2026-05-20]** 🌍 **Cobertura multilingue completa de la Etapa 1**: La Etapa 1 ya esta disponible en todos los idiomas soportados (zh-cn, en, zh-tw, ja-jp, ko-kr, es-es, fr-fr, de-de, ar-sa, vi-vn). Se verifico la navegacion/compilacion para evitar 404.
|
||||||
|
- **[2026-03-29]** ✨ **Lanzamos la sección de historias de usuarios y la actualizamos con casos reales**: Añadimos un carrusel interactivo y páginas dedicadas en la portada, y sustituimos el contenido provisional por cuatro historias reales de una maestra rural, una estudiante universitaria, un profesor de informática de secundaria y un camionero que construyeron productos reales con IA. [👉 View the stories](https://datawhalechina.github.io/easy-vibe/zh-cn/vibe-stories/story-1.html)
|
||||||
|
- **[2026-03-26]** 🚀 **Actualización masiva de contenido práctico de la Etapa 2**: Se completó el proyecto final SaaS "[Tu primera aplicación full-stack SaaS: Generador de copywriting](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/fullstack-app/)" y se amplió sustancialmente la sección "[Cómo integrar Stripe y sistemas de pago](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/stripe-payment/)".
|
||||||
|
- **[2026-03-25]** 📚 **Nuevo apéndice: Investigación de usuarios y validación de requisitos**: Se agregaron cuatro nuevos artículos que cubren la búsqueda de ideas, el modelo Double Diamond, Jobs to Be Done y The Mom Test para ayudar a los principiantes a descubrir y validar ideas de productos. [👉 Leer el apéndice](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
- **[2026-03-25]** 📚 **Documentación en inglés completamente actualizada**: La Etapa 2 (Desarrollo full-stack) y la Etapa 3 (Desarrollo avanzado) ya están disponibles completamente en inglés. [👉 Empezar a aprender](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
<details>
|
||||||
|
<summary>Noticias Pasadas</summary>
|
||||||
|
|
||||||
|
- **[2026-03-02]** 🦞 **Soporte amigable para OpenClaw y AI Agent**: Se agregó `llms.txt` para que OpenClaw, Claude, Cursor, Trae y otros agentes de IA puedan comprender rápidamente la estructura del repositorio y encontrar el contenido tutorial adecuado.
|
||||||
|
- **[2026-03-01]** La sección de [Desarrollo Avanzado](https://datawhalechina.github.io/easy-vibe/en/stage-3/) ha sido actualizada con guías detalladas para Claude Code, incluyendo MCP, Skills, Agent Teams y más, junto con ocho tutoriales de proyectos multiplataforma.
|
||||||
|
- **[2026-02-25]** Actualizada la [Base de Conocimientos del Apéndice](https://datawhalechina.github.io/easy-vibe/en/appendix/), ahora cubre 9 áreas de conocimiento y más de 80 temas interactivos.
|
||||||
|
- **[2026-01-27]** Agregados tutoriales de desarrollo de aplicaciones para Android e iOS.
|
||||||
|
- **[2026-01-19]** Lanzadas demos interactivas para Prompt Engineering, historia de la IA, diseño de autenticación, principios de Git y más.
|
||||||
|
- **[2026-01-16]** Reorganizada la estructura del proyecto y establecido formalmente el capítulo de entrada para principiantes.
|
||||||
|
- **[2026-01-14]** Completada una gran actualización de los documentos de prototipado de productos de la Etapa 1.
|
||||||
|
- **[2026-01-13]** Refactorizada la arquitectura de documentación y habilitado completamente el soporte multilenguaje (i18n).
|
||||||
|
- **[2026-01-01]** Lanzado el mapa de aprendizaje principal del proyecto.
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## Para quién es esto
|
||||||
|
|
||||||
|
- **Principiantes sin experiencia**: Construye tu primer proyecto primero, luego entiende cómo funciona
|
||||||
|
- **Product managers / emprendedores**: Valida ideas rápidamente y construye MVPs a bajo costo
|
||||||
|
- **Estudiantes**: Desarrolla habilidades prácticas para la era de la IA
|
||||||
|
- **Desarrolladores junior**: Aprende el camino completo desde la idea hasta el lanzamiento
|
||||||
|
- **Desarrolladores de nivel medio y senior**: Mejora tu flujo de trabajo de colaboración con IA para proyectos complejos
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Tus rutas de aprendizaje
|
||||||
|
|
||||||
|
### 🎮 Quiero un primer logro rápido
|
||||||
|
**Ideal para**: Todos
|
||||||
|
**Qué aprenderás**: Qué se siente realmente al programar con IA a través de un ejemplo práctico, simple y concreto
|
||||||
|
**Qué obtendrás**: Una primera impresión clara del vibe coding y cómo trabajar con IA mediante conversación
|
||||||
|
|
||||||
|
[Empieza aquí](https://datawhalechina.github.io/easy-vibe/en/stage-1/ai-capabilities-through-games/)
|
||||||
|
|
||||||
|
### 💡 Quiero convertir una idea en un prototipo de producto
|
||||||
|
**Ideal para**: Principiantes / product managers / emprendedores
|
||||||
|
**Qué aprenderás**: Hoja de ruta de aprendizaje, herramientas AI IDE, validación de ideas, prototipado, integración de capacidades de IA e iteración de demos completas
|
||||||
|
**Qué obtendrás**: Un prototipo de producto con IA que puedes mostrar realmente a usuarios o compañeros de equipo
|
||||||
|
|
||||||
|
[Empezar a aprender](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/)
|
||||||
|
|
||||||
|
### 🚀 Quiero construir productos full-stack de principio a fin
|
||||||
|
**Ideal para**: Desarrolladores junior / indie hackers / aprendiz avanzados
|
||||||
|
**Qué aprenderás**: Flujos de trabajo frontend, diseño a código, bases de datos, APIs backend, despliegue, facturación y proyectos principales
|
||||||
|
**Qué obtendrás**: La capacidad de lanzar de forma independiente aplicaciones web modernas con IA
|
||||||
|
|
||||||
|
[Empezar a aprender](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
|
||||||
|
### AI-Native: Quiero flujos de trabajo avanzados con Claude Code y agentes
|
||||||
|
**Ideal para**: Desarrolladores interesados en ingeniería AI-Native
|
||||||
|
**Qué aprenderás**: Claude Code, MCP, Skills, Agent Teams, tareas de larga duración, Spec Coding y entrega de aplicaciones multiplataforma
|
||||||
|
**Qué obtendrás**: Un flujo de trabajo más robusto para desarrollo asistido por IA complejo y automatización
|
||||||
|
|
||||||
|
[Ir a desarrollo avanzado](https://datawhalechina.github.io/easy-vibe/en/stage-3/)
|
||||||
|
|
||||||
|
### 📚 Quiero material de referencia y fundamentos
|
||||||
|
**Ideal para**: Todos
|
||||||
|
**Qué aprenderás**: Fundamentos de computación, conceptos básicos frontend/backend, infraestructura, principios de IA y prácticas de ingeniería
|
||||||
|
**Qué obtendrás**: Una base de conocimiento de referencia a largo plazo que cubre 9 áreas de conocimiento principales
|
||||||
|
|
||||||
|
[Explorar la base de conocimiento](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
## Sugerencias de estudio
|
||||||
|
|
||||||
|
- Si eres principiante, product manager o emprendedor, empieza con la [Etapa 1](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/)
|
||||||
|
- Si quieres pasar de prototipos a entrega full-stack, empieza con la [Etapa 2](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
- Si quieres flujos de trabajo avanzados con Claude Code o proyectos multiplataforma, ve a la [Etapa 3](https://datawhalechina.github.io/easy-vibe/en/stage-3/)
|
||||||
|
- Si te bloquean conceptos o te falta conocimiento previo, usa la [Base de Conocimiento del Apéndice](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
### 📖 Navegación de contenidos
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<img src="../../assets/readme-image1.png" alt="Mapa de aprendizaje" width="70%" style="border-radius: 10px; box-shadow: 0 8px 20px rgba(45,55,72,0.3); margin: 15px 0;"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
### I. Entrada para principiantes
|
||||||
|
|
||||||
|
| Sección | Contenido clave |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Mapa de aprendizaje](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/) | Una visión general guiada de todo el recorrido de aprendizaje |
|
||||||
|
| [La era de la IA: Si puedes hablar, puedes programar](https://datawhalechina.github.io/easy-vibe/en/stage-1/ai-capabilities-through-games/) | Ten tu primer contacto con la programación con IA a través de ejemplos como Snake |
|
||||||
|
| [Domina las herramientas de programación con IA](https://datawhalechina.github.io/easy-vibe/en/stage-1/introduction-to-ai-ide/) | Aprende cómo funcionan las herramientas AI IDE y construye proyectos locales simples con ellas |
|
||||||
|
| [Encuentra grandes ideas](https://datawhalechina.github.io/easy-vibe/en/stage-1/finding-great-idea/) | Aprende a descubrir y validar ideas de productos que valgan la pena construir |
|
||||||
|
| [Construye prototipos de producto](https://datawhalechina.github.io/easy-vibe/en/stage-1/building-prototype/) | Avanza desde los requisitos hasta prototipos de producto de una o múltiples páginas |
|
||||||
|
| [Integra capacidades de IA](https://datawhalechina.github.io/easy-vibe/en/stage-1/integrating-ai-capabilities/) | Integra funciones de IA de texto, imagen y video |
|
||||||
|
| [Práctica de proyecto completo](https://datawhalechina.github.io/easy-vibe/en/stage-1/complete-project-practice/) | Simula escenarios reales, recopila comentarios de usuarios e itera en un proyecto completo |
|
||||||
|
|
||||||
|
#### Apéndice: Pensamiento de producto y negocio
|
||||||
|
|
||||||
|
| Sección | Contenido clave |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Pensamiento de producto y diseño de soluciones](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-a-product-thinking/) | Marcos fundamentales para ir de cero a uno con un producto |
|
||||||
|
| [Escenarios de aplicación de IA en la industria (B2B)](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-industry-scenarios/) | Comprende cómo se aplica la IA en diferentes industrias |
|
||||||
|
| [Inspiración de escenarios de IA para consumidores (B2C)](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-c-consumer-scenarios/) | Explora oportunidades de productos en IA de consumo |
|
||||||
|
|
||||||
|
#### Apéndice: Investigación de usuarios y validación de requisitos
|
||||||
|
|
||||||
|
| Sección | Contenido clave |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Dónde encontrar ideas: 3 fuentes de referencia que funcionan mejor para principiantes](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-idea-sources/) | Construye un flujo confiable para encontrar oportunidades de productos concretas |
|
||||||
|
| [Double Diamond: primero haz lo correcto, luego hazlo bien](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-double-diamond/) | Usa un proceso estructurado para pasar de la inspiración dispersa a una dirección viable |
|
||||||
|
| [Usa Jobs to Be Done para descubrir lo que los usuarios realmente quieren](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-jobs-to-be-done/) | Analiza los objetivos de los usuarios a través de tareas reales en lugar de solicitudes de funciones superficiales |
|
||||||
|
| [The Mom Test: un método de entrevista a usuarios para validar la demanda](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-mom-test/) | Aprende a hacer mejores preguntas y evitar comentarios falsos positivos |
|
||||||
|
|
||||||
|
#### Apéndice: Soluciones técnicas
|
||||||
|
|
||||||
|
| Sección | Contenido clave |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Qué hacer si encuentras errores](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-b-common-errors/) | Problemas comunes de vibe coding y cómo solucionarlos |
|
||||||
|
| [Comparación de siete herramientas de programación con IA](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-articles/example0-1/vibe-coding-tools-snake-game-tutorial) | Compara las principales plataformas de programación con IA mediante pruebas prácticas |
|
||||||
|
| [Diseña sitios web con agentes](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-articles/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents) | Aprende la colaboración multi-agente en la práctica |
|
||||||
|
|
||||||
|
### II. Desarrolladores junior e intermedios
|
||||||
|
|
||||||
|
#### Frontend
|
||||||
|
|
||||||
|
| Sección | Contenido clave |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Frontend 0: Construye tu propio agente de producción de recursos con Lovart](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/lovart-assets/) | Usa Nanobanana y Lovart para generar recursos visuales por lotes y construir un agente de dibujo con reconocimiento de intenciones |
|
||||||
|
| [Frontend 1: Conceptos básicos de Figma y MasterGo](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/figma-mastergo/) | Aprende el flujo de trabajo desde borradores de diseño hasta un pensamiento UI listo para implementar |
|
||||||
|
| [Frontend 2: Construye tu primera aplicación moderna - Diseño UI](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/ui-design/) | Aprende los fundamentos de diseño UI detrás de las interfaces de aplicaciones modernas |
|
||||||
|
| [Frontend 3: Guías de UI y diseño multi-producto](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/multi-product-ui/) | Mejora la consistencia y estética de múltiples productos con reglas UI compartidas |
|
||||||
|
| [Frontend 4: Haz interfaces hermosas con LLMs y Skills](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/llm-skills-beautiful/) | Usa prompts y plugins para que la IA genere interfaces más pulidas y distintivas |
|
||||||
|
| [Frontend 4: Construyamos retratos de Hogwarts](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/hogwarts-portraits/) | Construye un proyecto frontend interactivo de imágenes con IA desde cero |
|
||||||
|
| [Frontend 6: De prototipo de diseño a código de proyecto](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/design-to-code/) | Convierte prototipos de diseño en código frontend que realmente funciona en el navegador |
|
||||||
|
| [Frontend 7: Actualiza tu UI con bibliotecas de componentes modernas](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/modern-component-library/) | Usa bibliotecas de componentes para construir interfaces profesionales más rápido |
|
||||||
|
|
||||||
|
#### Backend
|
||||||
|
|
||||||
|
| Sección | Contenido clave |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Backend 1: Aprende Git y GitHub](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/git-workflow/) | Domina las operaciones de control de versiones y los flujos de colaboración con Git |
|
||||||
|
| [Backend 2: De base de datos a Supabase](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/database-supabase/) | Aprende los fundamentos de bases de datos relacionales y usa Supabase como plataforma BaaS moderna |
|
||||||
|
| [Backend 3: Diseño y desarrollo de APIs backend](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/ai-interface-code/) | Usa IA para asistir en el diseño de APIs, generación de código backend y documentación de APIs |
|
||||||
|
| [Backend 4: Lanza tu prototipo de producto](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/zeabur-deployment/) | Despliega rápidamente aplicaciones full-stack en la nube con Zeabur |
|
||||||
|
| [Backend 5: De IDEs a herramientas de programación con IA por CLI](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/modern-cli/) | Explora flujos de trabajo de programación con IA desde la terminal para desarrollo moderno |
|
||||||
|
| [Backend 6: Integra Stripe y otros sistemas de facturación](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/stripe-payment/) | Agrega monetización con capacidades de pago y facturación |
|
||||||
|
|
||||||
|
#### Proyectos principales
|
||||||
|
|
||||||
|
| Sección | Contenido clave |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Proyecto principal 1: Tu primera aplicación SaaS full-stack - Sitio web de copywriting con IA](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/fullstack-app/) | Construye un espacio de trabajo de marketing con IA con inicio de sesión, generación, facturación y gestión de administración |
|
||||||
|
| [Proyecto principal 2: Sistema de exámenes y gestión en línea](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/modern-frontend-trae/) | Construye un sistema de exámenes en línea con generación de preguntas, flujos de examen y herramientas de administración |
|
||||||
|
|
||||||
|
#### Apéndice de capacidades de IA
|
||||||
|
|
||||||
|
| Sección | Contenido clave |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [IA 1: Conceptos básicos de Dify e integración de base de conocimiento](https://datawhalechina.github.io/easy-vibe/en/stage-2/ai-capabilities/dify-knowledge-base/) | Aprende a construir aplicaciones de IA con Dify e integrar bases de conocimiento privadas |
|
||||||
|
|
||||||
|
### III. Desarrolladores avanzados
|
||||||
|
|
||||||
|
#### Habilidades centrales de Claude Code
|
||||||
|
|
||||||
|
| Sección | Contenido clave |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Comenzando con Claude Code](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/basics/) | Instalación, configuración, fundamentos y comandos útiles |
|
||||||
|
| [Guía de Claude Code MCP](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/mcp/) | Conecta Claude Code a GitHub, bases de datos, APIs y otros servicios a través de MCP |
|
||||||
|
| [Guía de Claude Code Skills](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/skills/) | Empaqueta experiencia en habilidades reutilizables que puedes usar una y otra vez |
|
||||||
|
| [Cómo mantener a Claude Code trabajando en tareas de larga duración](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/long-running-tasks/) | Diseña tareas de larga duración para que las herramientas de codificación sigan trabajando hasta terminar |
|
||||||
|
| [Guía de Claude Agent Teams](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/agent-teams/) | Coordina múltiples instancias de IA como un equipo de desarrollo real |
|
||||||
|
| [Superpoderes de Claude Code para desarrollo de grado empresarial](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/superpowers/) | Ayuda a la IA a producir código de grado empresarial con TDD y mejores prácticas |
|
||||||
|
| [Mejores prácticas de flujo de trabajo de Claude Code](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/workflow/) | Mejores prácticas para refactorización, revisión de código y desarrollo diario |
|
||||||
|
| [Desarrollo remoto con Claude Code en móvil](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/mobile-development/) | Usa Claude Code más allá del escritorio y construye un flujo de trabajo remoto productivo en dispositivos móviles |
|
||||||
|
| [Guía completa del SDK de Claude Agent](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/claude-agent-sdk/) | Construye flujos de trabajo de agentes personalizados e integra Claude en tus propias herramientas con el SDK |
|
||||||
|
| [De vibe coding a spec coding](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/spec-coding/) | Pasa de prompts ad-hoc a un flujo de desarrollo con IA más estructurado y basado en especificaciones |
|
||||||
|
|
||||||
|
#### Desarrollo multiplataforma
|
||||||
|
|
||||||
|
| Sección | Contenido clave |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Cómo elegir la plataforma adecuada para tu aplicación](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/choose-platform/) | Compara formatos de aplicaciones y elige la plataforma adecuada según usuarios, escenarios y objetivos de entrega |
|
||||||
|
| [Construye un Mini Programa de WeChat](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/wechat-miniprogram/) | Comprende el ecosistema y lanza un mini programa frontend desde plantilla hasta producción |
|
||||||
|
| [Construye un Mini Programa de WeChat con backend](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/wechat-miniprogram-backend/) | Agrega lógica backend y bases de datos para completar el ciclo de negocio completo |
|
||||||
|
| [Construye una aplicación Android](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/android-app/) | Aprende desarrollo de aplicaciones Android con un flujo de trabajo nativo moderno |
|
||||||
|
| [Construye una aplicación iOS](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/ios-app/) | Aprende desarrollo de aplicaciones iOS y las convenciones del ecosistema Apple |
|
||||||
|
| [Construye una aplicación PWA local](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/pwa-local-app/) | Convierte un sitio web en una aplicación real con soporte offline, push e instalación |
|
||||||
|
| [Construye una extensión de asistente de IA para navegador](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/browser-ai-extension/) | Crea una extensión de Chrome que resume cualquier página con APIs en la nube o IA integrada |
|
||||||
|
| [Construye una aplicación de escritorio con Electron](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/electron-voice-to-text/) | Construye una aplicación de escritorio de voz a texto con Electron para tres plataformas |
|
||||||
|
| [Construye y acuña un NFT rápidamente](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/nft-minting/) | Escribe un contrato inteligente desde cero, despliégalo y acuña tu propio NFT |
|
||||||
|
| [Construye una extensión para VS Code](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/vscode-extension/) | Construye un asistente de proyecto de IA con plantillas, chat de código y preguntas/respuestas multi-archivo |
|
||||||
|
| [Construye una aplicación de escritorio Qt de grado industrial](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/qt-industrial-hmi/) | Crea un sistema HMI Qt en tiempo real con tendencias, alertas y monitoreo |
|
||||||
|
|
||||||
|
#### Apéndice de capacidades de IA
|
||||||
|
|
||||||
|
| Sección | Contenido clave |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Qué es RAG y cómo funciona](https://datawhalechina.github.io/easy-vibe/en/stage-3/ai-advanced/rag-introduction/) | Construye una comprensión sistemática de los principios de RAG y arquitecturas comunes |
|
||||||
|
| [Flujos de trabajo RAG intermedios y avanzados con LangGraph](https://datawhalechina.github.io/easy-vibe/en/stage-3/ai-advanced/langgraph-advanced-rag/) | Diseña flujos de trabajo de múltiples pasos y sistemas RAG más avanzados |
|
||||||
|
|
||||||
|
### 📚 Base de conocimiento del apéndice
|
||||||
|
|
||||||
|
> Cubriendo **9 áreas de conocimiento principales** y ** más de 80 temas interactivos**, este apéndice usa animación y componentes visuales para ayudarte a comprender intuitivamente conceptos fundamentales desde los fundamentos de computación hasta la frontera de la IA.
|
||||||
|
>
|
||||||
|
> 👉 [Ver el apéndice completo](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
### 🎓 Otros cursos
|
||||||
|
|
||||||
|
- [Hands-on Modern RL](#otros-cursos)
|
||||||
|
- [Learn Harness Engineering](#otros-cursos)
|
||||||
|
|
||||||
|
## 🛠️ Cómo aprender
|
||||||
|
|
||||||
|
- Lee y practica las secciones que coincidan con tu nivel actual. Si te quedas atascado, no dudes en abrir un issue.
|
||||||
|
|
||||||
|
## 💻 Ejecutar localmente
|
||||||
|
|
||||||
|
### Enfoque moderno
|
||||||
|
|
||||||
|
En una ventana de chat de un AI IDE como VS Code, Cursor o Trae, simplemente puedes decir:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Por favor, ayúdame a ejecutar este proyecto localmente.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Enfoque tradicional
|
||||||
|
|
||||||
|
1. `npm install`
|
||||||
|
2. `npm run dev`
|
||||||
|
3. Abre `http://localhost:3000` en tu navegador.
|
||||||
|
|
||||||
|
## Otros cursos
|
||||||
|
|
||||||
|
¡Nuestro equipo también ha creado otros cursos! Échales un vistazo:
|
||||||
|
|
||||||
|
[](https://github.com/walkinglabs/hands-on-modern-rl)
|
||||||
|
|
||||||
|
**Hands-on Modern RL**: Un plan de estudios práctico y de código abierto que cierra la brecha desde conceptos básicos de RL hasta la alineación de LLMs, RLVR y sistemas Agentic avanzados.
|
||||||
|
|
||||||
|
[](https://github.com/walkinglabs/learn-harness-engineering/tree/main)
|
||||||
|
|
||||||
|
**Learn Harness Engineering**: Una guía completa sobre ingeniería de arneses.
|
||||||
|
|
||||||
|
## 🤝 Contribuir y colaboradores
|
||||||
|
|
||||||
|
- Si encuentras un problema o ves algo que se puede mejorar, no dudes en abrir un issue. Si nadie responde, también puedes contactar al [equipo de soporte de Datawhale](https://github.com/datawhalechina/DOPMC/blob/main/OP.md).
|
||||||
|
- Si quieres contribuir, abre un pull request. Si nadie responde, también puedes contactar al [equipo de soporte de Datawhale](https://github.com/datawhalechina/DOPMC/blob/main/OP.md).
|
||||||
|
- Si quieres iniciar un nuevo proyecto de código abierto de Datawhale, por favor sigue la [Guía de Proyectos de Código Abierto de Datawhale](https://github.com/datawhalechina/DOPMC/blob/main/GUIDE.md).
|
||||||
|
|
||||||
|
### 🙏 Colaboradores
|
||||||
|
|
||||||
|
- [Sanbu - Líder del proyecto](https://github.com/sanbuphy) (Miembro de Datawhale)
|
||||||
|
- Fang Ke - Mentor (Miembro de Datawhale, Universidad de Tsinghua)
|
||||||
|
- [Yerim Kang](https://github.com/yerim25) (Proyectos prácticos, Universidad de Tsinghua)
|
||||||
|
- [Zhilin Zhao](https://github.com/ChileenZ) (Proyectos prácticos, Universidad de Tsinghua)
|
||||||
|
- [Yixuan Li](https://yixuan20.github.io/) (Diseño visual, Universidad de Tsinghua)
|
||||||
|
- Siyi Liu (Proyectos prácticos, Universidad de Tsinghua)
|
||||||
|
- [Lixin Liu](https://github.com/liulx25xx) (Proyectos prácticos, Universidad de Tsinghua)
|
||||||
|
- Todos en el grupo de prueba interna de AI Vibe Coding 101 que compartieron sugerencias y comentarios
|
||||||
|
|
||||||
|
### Agradecimientos especiales
|
||||||
|
|
||||||
|
- Gracias a [@Sm1les](https://github.com/Sm1les) por la ayuda y el apoyo en este proyecto
|
||||||
|
- Gracias a cada colaborador y a todos los que apoyaron el proyecto con comentarios y estrellas ❤️
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a href="https://www.star-history.com/#datawhalechina/easy-vibe&type=timeline&legend=top-left">
|
||||||
|
<picture>
|
||||||
|
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=datawhalechina/easy-vibe&type=timeline&theme=dark&legend=top-left" />
|
||||||
|
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=datawhalechina/easy-vibe&type=timeline&legend=top-left" />
|
||||||
|
</picture>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align=center style="margin-top: 30px;">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=datawhalechina/easy-vibe" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 📄 LICENCIA
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
|
||||||
|
<img
|
||||||
|
alt="Licencia Creative Commons"
|
||||||
|
style="border-width:0"
|
||||||
|
src="https://img.shields.io/badge/license-CC%20BY--NC--SA%204.0-lightgrey"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<br />
|
||||||
|
Esta obra está licenciada bajo la
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
|
||||||
|
Licencia Internacional Creative Commons Attribution-NonCommercial-ShareAlike 4.0
|
||||||
|
</a>.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Star History
|
||||||
|
|
||||||
|
[](https://www.star-history.com/#datawhalechina/easy-vibe&type=date&legend=top-left)
|
||||||
@@ -0,0 +1,448 @@
|
|||||||
|
<!-- trigger vercel build -->
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
<img src="../../assets/easy-vibe-logo-hd.svg" alt="Logo Easy-Vibe" width="300">
|
||||||
|
|
||||||
|
<img src="../../assets/banner.png" alt="Bannière Easy-Vibe" width="100%">
|
||||||
|
|
||||||
|
<p align="center" style="font-size: 1.2em; color: #666; margin: 20px 0;">
|
||||||
|
Lancez-vous tout de suite et vibez avec nous. Si vous pouvez parler, vous pouvez creer des applis.<br>
|
||||||
|
<span style="font-size: 0.9em; color: #888;">直接上手,一起 vibe!会说话就会做应用。</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a href="https://trendshift.io/repositories/22079" target="_blank"><img src="https://trendshift.io/api/badge/repositories/22079" alt="datawhalechina/easy-vibe | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||||
|
|
||||||
|
<p align="center" style="font-size: 1.05em; color: #666; margin: 16px 0;">
|
||||||
|
你好 · Hello · 哈囉 · こんにちは · 안녕하세요 · Hola · Bonjour · Hallo · مرحبا · Xin chào<br>
|
||||||
|
La première partie de notre tutoriel est maintenant disponible en 10 langues. Amis du monde entier, commençons à coding ensemble !<br>
|
||||||
|
<span style="font-size: 0.9em; color: #888;">我们的教程(第一部分)已经支持 10 种语言,欢迎世界各地的朋友一起 coding!</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
🚀 <a href="https://datawhalechina.github.io/easy-vibe/welcome.html">Commencer</a> · ✨ <a href="https://datawhalechina.github.io/easy-vibe/en/appendix/">Tutoriel interactif</a> · 🦞 <a href="https://github.com/datawhalechina/hello-claw">Apprendre OpenClaw</a> · 📖 <a href="#table-of-contents">Table des matières</a><br>
|
||||||
|
<span style="font-size: 0.85em; color: #888;">🚀 <a href="https://datawhalechina.github.io/easy-vibe/welcome.html">开始体验</a> · ✨ <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/">交互式教程</a> · 🦞 <a href="https://github.com/datawhalechina/hello-claw">学习 OpenClaw</a> · 📖 <a href="#table-of-contents">查看目录</a></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://datawhalechina.github.io/easy-vibe/welcome.html">Lire en ligne</a> ·
|
||||||
|
<a href="#-content-navigation">Carte d'apprentissage</a><br>
|
||||||
|
<span style="font-size: 0.85em; color: #888;">
|
||||||
|
<a href="https://datawhalechina.github.io/easy-vibe/welcome.html">开始阅读</a> ·
|
||||||
|
<a href="#-content-navigation">学习地图</a>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/stargazers" target="_blank">
|
||||||
|
<img src="https://img.shields.io/github/stars/datawhalechina/easy-vibe?color=660874&style=for-the-badge&logo=star&logoColor=white&labelColor=1a1a2e" alt="Stars"></a>
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/network/members" target="_blank">
|
||||||
|
<img src="https://img.shields.io/github/forks/datawhalechina/easy-vibe?color=660874&style=for-the-badge&logo=git-fork&logoColor=white&labelColor=1a1a2e" alt="Forks"></a>
|
||||||
|
<a href="../../LICENSE" target="_blank">
|
||||||
|
<img src="https://img.shields.io/badge/License-CC_BY_NC_SA_4.0-4ecdc4?style=for-the-badge&logo=creative-commons&logoColor=white&labelColor=1a1a2e" alt="License"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="../zh-CN/README.md"><img alt="简体中文" src="https://img.shields.io/badge/简体中文-d9d9d9"></a>
|
||||||
|
<a href="../zh-TW/README.md"><img alt="繁體中文" src="https://img.shields.io/badge/繁體中文-d9d9d9"></a>
|
||||||
|
<a href="../en-US/README.md"><img alt="English" src="https://img.shields.io/badge/English-d9d9d9"></a>
|
||||||
|
<a href="../ja-JP/README.md"><img alt="日本語" src="https://img.shields.io/badge/日本語-d9d9d9"></a>
|
||||||
|
<a href="../es-ES/README.md"><img alt="Español" src="https://img.shields.io/badge/Español-d9d9d9"></a>
|
||||||
|
<a href="../fr-FR/README.md"><img alt="Français" src="https://img.shields.io/badge/Français-d9d9d9"></a>
|
||||||
|
<a href="../ko-KR/README.md"><img alt="한국어" src="https://img.shields.io/badge/한국어-d9d9d9"></a>
|
||||||
|
<a href="../ar-SA/README.md"><img alt="العربية" src="https://img.shields.io/badge/العربية-d9d9d9"></a>
|
||||||
|
<a href="../vi-VN/README.md"><img alt="Tiếng_Việt" src="https://img.shields.io/badge/Tiếng_Việt-d9d9d9"></a>
|
||||||
|
<a href="../de-DE/README.md"><img alt="Deutsch" src="https://img.shields.io/badge/Deutsch-d9d9d9"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<table align="center">
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-header.png" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Une carte d'apprentissage pour les debutants</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Des orientations claires depuis zero, pour ne plus "apprendre et oublier"</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-tutorial.png" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Tutoriels visuels etape par etape</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Des explications detaillees comme avec un tuteur prive</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-ide.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Programmation simulee immersive</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Une souris virtuelle vous guide pour apprendre rapidement le flux de travail de l'IDE</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-diffusion.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Principes de IA visibles</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Des explications animees pour voir facilement comment l'IA genere des images</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-rag.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Apprenez RAG comme un jeu</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Des composants interactifs pour cliquer a travers le flux complet de donnees RAG</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/git-terminal.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Concepts de terminal visuels</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Le comportement en ligne de commande devient intuitif quand la logique sous-jacente est visualisee</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div align="center">
|
||||||
|
<h3>⭐ <a href="https://github.com/datawhalechina/easy-vibe" style="color: #d0cd16ff;">Mettez une etoile au depot ici</a> pour accelerer les mises a jour ❤️</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align="center" style="margin: 30px 0;">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/issues/new?template=story_submission.md">
|
||||||
|
<img src="https://raw.githubusercontent.com/datawhalechina/easy-vibe/main/assets/stories_image.png" alt="Partagez votre histoire Vibe" width="80%" style="border-radius: 10px; box-shadow: 0 4px 12px rgba(0,0,0,0.15);">
|
||||||
|
</a>
|
||||||
|
<p style="margin-top: 15px; font-size: 1.1em; color: #666;">
|
||||||
|
📝 <strong>Vous avez votre propre histoire de vibe coding ?</strong>
|
||||||
|
Soumettez-la ici et inspirez les autres !
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Table des matières
|
||||||
|
|
||||||
|
- [Pourquoi Easy-Vibe](#pourquoi-easy-vibe)
|
||||||
|
- [Actualités](#-news)
|
||||||
|
- [Pour qui est-ce](#pour-qui-est-ce)
|
||||||
|
- [Vos parcours d'apprentissage](#vos-parcours-dapprentissage)
|
||||||
|
- [Suggestions d'étude](#suggestions-détude)
|
||||||
|
- [I. Entrée debutant](#i-entrée-débutant)
|
||||||
|
- [II. Developpeurs junior et intermédiaires](#ii-développeurs-junior-et-intermédiaires)
|
||||||
|
- [III. Developpeurs avancés](#iii-développeurs-avancés)
|
||||||
|
- [Base de connaissances de l'annexe](#-base-de-connaissances-de-lannexe)
|
||||||
|
- [Comment apprendre](#️-comment-apprendre)
|
||||||
|
- [Executer localement](#-exécuter-localement)
|
||||||
|
- [Autres cours](#autres-cours)
|
||||||
|
- [Contribuer et contributeurs](#-contribuer-et-contributeurs)
|
||||||
|
- [LICENCE](#-licence)
|
||||||
|
|
||||||
|
## Pourquoi Easy-Vibe
|
||||||
|
|
||||||
|
Vous voulez une appli de suivi des depenses ? Dites-le.
|
||||||
|
|
||||||
|
Besoin d'un systeme de reservation avec connexion WeChat ? Dites-le.
|
||||||
|
|
||||||
|
Vous voulez un blog avec commentaires ? Dites-le.
|
||||||
|
|
||||||
|
A l'ere de l'IA, programmer commence par decrire ce que vous voulez.
|
||||||
|
|
||||||
|
Easy-Vibe vous apprend a transformer cela en un vrai produit.
|
||||||
|
|
||||||
|
|
||||||
|
## 🔥 News
|
||||||
|
|
||||||
|
- **[2026-05-20]** 🌍 **Couverture multilingue complete du Stage 1**: Le Stage 1 est maintenant disponible dans toutes les langues supportees (zh-cn, en, zh-tw, ja-jp, ko-kr, es-es, fr-fr, de-de, ar-sa, vi-vn). La navigation/le build ont ete verifies pour eviter les 404.
|
||||||
|
- **[2026-03-29]** ✨ **La section Histoires d'utilisateurs est en ligne avec 4 cas réels** : Nous avons ajouté un carrousel interactif et des pages dédiées sur la page d'accueil, puis remplacé le contenu provisoire par quatre récits réels mettant en scène un instituteur rural, une étudiante, un professeur d'informatique au lycée et un chauffeur routier ayant créé de vrais produits avec l'IA. [👉 View the stories](https://datawhalechina.github.io/easy-vibe/zh-cn/vibe-stories/story-1.html)
|
||||||
|
- **[2026-03-26]** 🚀 **Mise à jour majeure de la pratique de l'Étape 2**: Projet final SaaS "[Votre première application full-stack SaaS : Générateur de copywriting](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/fullstack-app/)" complété et section "[Comment intégrer Stripe et les systèmes de paiement](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/stripe-payment/)" substantiellement élargie.
|
||||||
|
- **[2026-03-25]** 📚 **Nouvel appendice : Recherche utilisateur et validation des besoins**: Ajout de quatre nouveaux articles couvrant la recherche d'idées, le modèle Double Diamond, Jobs to Be Done et The Mom Test pour aider les débutants à découvrir et valider des idées de produits. [👉 Lire l'appendice](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
- **[2026-03-25]** 📚 **Documentation anglaise entièrement mise à jour**: L'Étape 2 (Développement full-stack) et l'Étape 3 (Développement avancé) sont maintenant entièrement disponibles en anglais. [👉 Commencer à apprendre](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
<details>
|
||||||
|
<summary>Actualités Passées</summary>
|
||||||
|
|
||||||
|
- **[2026-03-02]** 🦞 **Support amical pour OpenClaw et AI Agent**: Ajout de `llms.txt` pour qu'OpenClaw, Claude, Cursor, Trae et autres agents IA puissent rapidement comprendre la structure du dépôt et trouver le bon contenu tutoriel.
|
||||||
|
- **[2026-03-01]** La section [Développement Avancé](https://datawhalechina.github.io/easy-vibe/en/stage-3/) a été complètement mise à niveau avec des guides approfondis pour Claude Code, incluant MCP, Skills, Agent Teams et plus, ainsi que huit tutoriels de projets multiplateformes.
|
||||||
|
- **[2026-02-25]** Mise à jour de la [Base de Connaissances de l'Appendice](https://datawhalechina.github.io/easy-vibe/en/appendix/), couvrant maintenant 9 domaines de connaissances et plus de 80 sujets interactifs.
|
||||||
|
- **[2026-01-27]** Ajout de tutoriels de développement d'applications pour Android et iOS.
|
||||||
|
- **[2026-01-19]** Lancement de démos interactives pour Prompt Engineering, histoire de l'IA, conception d'authentification, principes Git et plus.
|
||||||
|
- **[2026-01-16]** Restructuration du projet et établissement formel du chapitre d'entrée pour débutants.
|
||||||
|
- **[2026-01-14]** Mise à jour majeure des documents de prototypage de produits de l'Étape 1.
|
||||||
|
- **[2026-01-13]** Refonte de l'architecture documentaire et activation complète du support multilingue (i18n).
|
||||||
|
- **[2026-01-01]** Lancement de la carte d'apprentissage principale du projet.
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## Pour qui est-ce
|
||||||
|
|
||||||
|
- **Debutants complets**: Construisez d'abord votre premier projet, puis comprenez comment il fonctionne
|
||||||
|
- **Chefs de produit / fondateurs**: Validez rapidement vos idées et construisez des MVPs a faible cout
|
||||||
|
- **Etudiants**: Developpez des competences pratiques pour l'ere de l'IA
|
||||||
|
- **Developpeurs juniors**: Apprenez le chemin complet de l'idee au lancement
|
||||||
|
- **Developpeurs de niveau intermediaire et senior**: Ameliorez votre flux de collaboration avec l'IA pour des projets complexes
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Vos parcours d'apprentissage
|
||||||
|
|
||||||
|
### 🎮 Je veux une premiere reussite rapide
|
||||||
|
**Ideal pour**: Tout le monde
|
||||||
|
**Ce que vous apprendrez**: Ce que ca fait vraiment de coder avec l'IA a travers un exemple pratique, simple et concret
|
||||||
|
**Ce que vous obtiendrez**: Une premiere impression claire du vibe coding et comment travailler avec l'IA par la conversation
|
||||||
|
|
||||||
|
[Commencez ici](https://datawhalechina.github.io/easy-vibe/en/stage-1/ai-capabilities-through-games/)
|
||||||
|
|
||||||
|
### 💡 Je veux transformer une idee en prototype de produit
|
||||||
|
**Ideal pour**: Debutants / chefs de produit / fondateurs
|
||||||
|
**Ce que vous apprendrez**: Feuille de route d'apprentissage, outils AI IDE, validation d'idees, prototypage, integration de capacites IA et iteration de demos completes
|
||||||
|
**Ce que vous obtiendrez**: Un prototype de produit IA que vous pouvez reellement montrer a des utilisateurs ou des collegues
|
||||||
|
|
||||||
|
[Commencer a apprendre](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/)
|
||||||
|
|
||||||
|
### 🚀 Je veux construire des produits full-stack de bout en bout
|
||||||
|
**Ideal pour**: Developpeurs juniors / indie hackers / apprenants avances
|
||||||
|
**Ce que vous apprendrez**: Flux de travail frontend, design-to-code, bases de donnees, APIs backend, deploiement, facturation et projets majeurs
|
||||||
|
**Ce que vous obtiendrez**: La capacite de livrer independamment des applications web modernes avec IA
|
||||||
|
|
||||||
|
[Commencer a apprendre](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
|
||||||
|
### AI-Native: Je veux des flux de travail avances avec Claude Code et agents
|
||||||
|
**Ideal pour**: Developpeurs interesses par l'ingenierie AI-Native
|
||||||
|
**Ce que vous apprendrez**: Claude Code, MCP, Skills, Agent Teams, taches de longue duree, Spec Coding et livraison d'applications multiplateformes
|
||||||
|
**Ce que vous obtiendrez**: Un flux de travail plus robuste pour le developpement assiste par IA complexe et l'automatisation
|
||||||
|
|
||||||
|
[Aller au developpement avance](https://datawhalechina.github.io/easy-vibe/en/stage-3/)
|
||||||
|
|
||||||
|
### 📚 Je veux du materiel de reference et des fondamentaux
|
||||||
|
**Ideal pour**: Tout le monde
|
||||||
|
**Ce que vous apprendrez**: Fondamentaux informatiques, bases frontend/backend, infrastructure, principes IA et pratiques d'ingenierie
|
||||||
|
**Ce que vous obtiendrez**: Une base de connaissances de reference a long terme couvrant 9 domaines de connaissances majeurs
|
||||||
|
|
||||||
|
[Parcourir la base de connaissances](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
## Suggestions d'étude
|
||||||
|
|
||||||
|
- Si vous etes debutant, chef de produit ou fondateur, commencez par l'[Etape 1](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/)
|
||||||
|
- Si vous voulez passer des prototypes a la livraison full-stack, commencez par l'[Etape 2](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
- Si vous voulez des flux de travail avances avec Claude Code ou des projets multiplateformes, allez a l'[Etape 3](https://datawhalechina.github.io/easy-vibe/en/stage-3/)
|
||||||
|
- Si vous etes bloque par des concepts ou des lacunes, utilisez la [Base de Connaissances de l'Appendice](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
### 📖 Navigation du contenu
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<img src="../../assets/readme-image1.png" alt="Carte d'apprentissage" width="70%" style="border-radius: 10px; box-shadow: 0 8px 20px rgba(45,55,72,0.3); margin: 15px 0;"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
### I. Entrée debutant
|
||||||
|
|
||||||
|
| Section | Contenu cle |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Carte d'apprentissage](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/) | Un apercu guide du parcours d'apprentissage complet |
|
||||||
|
| [L'ere de l'IA : Si vous savez parler, vous savez coder](https://datawhalechina.github.io/easy-vibe/en/stage-1/ai-capabilities-through-games/) | Decouvrez la programmation avec l'IA a travers des exemples comme Snake |
|
||||||
|
| [Maitrisez les outils de programmation IA](https://datawhalechina.github.io/easy-vibe/en/stage-1/introduction-to-ai-ide/) | Apprenez comment fonctionnent les outils AI IDE et construisez des projets locaux simples |
|
||||||
|
| [Trouvez de bonnes idees](https://datawhalechina.github.io/easy-vibe/en/stage-1/finding-great-idea/) | Apprenez a decouvrir et valider des idees de produits qui valent la peine d'etre construites |
|
||||||
|
| [Construisez des prototypes de produit](https://datawhalechina.github.io/easy-vibe/en/stage-1/building-prototype/) | Passez des exigences aux prototypes de produit mono et multi-pages |
|
||||||
|
| [Integrez les capacites IA](https://datawhalechina.github.io/easy-vibe/en/stage-1/integrating-ai-capabilities/) | Integrez des fonctionnalites IA de texte, image et video |
|
||||||
|
| [Pratique de projet complet](https://datawhalechina.github.io/easy-vibe/en/stage-1/complete-project-practice/) | Simulez des scenarios reels, collectez les retours utilisateurs et iterez sur un projet complet |
|
||||||
|
|
||||||
|
#### Annexe : Pensee produit et business
|
||||||
|
|
||||||
|
| Section | Contenu cle |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Pensee produit et conception de solutions](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-a-product-thinking/) | Cadres fondamentaux pour passer de zero a un avec un produit |
|
||||||
|
| [Scenarios d'application de l'IA dans l'industrie (B2B)](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-industry-scenarios/) | Comprenez comment l'IA est appliquee dans differentes industries |
|
||||||
|
| [Inspiration de scenarios IA grand public (B2C)](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-c-consumer-scenarios/) | Explorez les opportunites de produits dans l'IA grand public |
|
||||||
|
|
||||||
|
#### Annexe : Recherche utilisateur et validation des besoins
|
||||||
|
|
||||||
|
| Section | Contenu cle |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Ou trouver des idees : 3 sources de reference qui fonctionnent le mieux pour les debutants](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-idea-sources/) | Construisez un flux fiable pour trouver des opportunites de produits concretes |
|
||||||
|
| [Double Diamond : faites d'abord la bonne chose, puis faites-la bien](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-double-diamond/) | Utilisez un processus structure pour passer de l'inspiration disperse a une direction viable |
|
||||||
|
| [Utilisez Jobs to Be Done pour decouvrir ce que les utilisateurs veulent vraiment](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-jobs-to-be-done/) | Analysez les objectifs des utilisateurs a travers de vraies taches plutot que des demandes de fonctionnalites superficielles |
|
||||||
|
| [The Mom Test : une methode d'entretien utilisateur pour valider la demande](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-mom-test/) | Apprenez a poser de meilleures questions et a eviter les retours faux positifs |
|
||||||
|
|
||||||
|
#### Annexe : Solutions techniques
|
||||||
|
|
||||||
|
| Section | Contenu cle |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Que faire si vous rencontrez des erreurs](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-b-common-errors/) | Problemes courants de vibe coding et comment les resoudre |
|
||||||
|
| [Comparaison de sept outils de programmation IA](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-articles/example0-1/vibe-coding-tools-snake-game-tutorial) | Comparez les principales plateformes de programmation IA par des tests pratiques |
|
||||||
|
| [Concevez des sites web avec des agents](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-articles/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents) | Apprenez la collaboration multi-agent en pratique |
|
||||||
|
|
||||||
|
### II. Developpeurs junior et intermédiaires
|
||||||
|
|
||||||
|
#### Frontend
|
||||||
|
|
||||||
|
| Section | Contenu cle |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Frontend 0 : Construisez votre propre agent de production de ressources avec Lovart](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/lovart-assets/) | Utilisez Nanobanana et Lovart pour generer des ressources visuelles en lot et construire un agent de dessin avec reconnaissance d'intentions |
|
||||||
|
| [Frontend 1 : Bases de Figma et MasterGo](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/figma-mastergo/) | Apprenez le flux de travail des maquettes de design a la pensee UI prete a l'implementation |
|
||||||
|
| [Frontend 2 : Construisez votre premiere application moderne - Design UI](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/ui-design/) | Apprenez les fondamentaux du design UI derriere les interfaces d'applications modernes |
|
||||||
|
| [Frontend 3 : Directives UI et design multi-produit](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/multi-product-ui/) | Ameliorez la coherence et l'esthetique de plusieurs produits avec des regles UI partagees |
|
||||||
|
| [Frontend 4 : Rendez les interfaces belles avec les LLMs et Skills](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/llm-skills-beautiful/) | Utilisez des prompts et plugins pour que l'IA genere des interfaces plus polies et distinctives |
|
||||||
|
| [Frontend 4 : Construisons des portraits de Poudlard](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/hogwarts-portraits/) | Construisez un projet frontend interactif d'images IA depuis zero |
|
||||||
|
| [Frontend 6 : Du prototype de design au code de projet](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/design-to-code/) | Transformez les prototypes de design en code frontend qui fonctionne reellement dans le navigateur |
|
||||||
|
| [Frontend 7 : Mettez a jour votre UI avec des bibliotheques de composants modernes](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/modern-component-library/) | Utilisez des bibliotheques de composants pour construire des interfaces professionnelles plus rapidement |
|
||||||
|
|
||||||
|
#### Backend
|
||||||
|
|
||||||
|
| Section | Contenu cle |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Backend 1 : Apprenez Git et GitHub](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/git-workflow/) | Maitrisez les operations de controle de version et les flux de collaboration avec Git |
|
||||||
|
| [Backend 2 : De la base de donnees a Supabase](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/database-supabase/) | Apprenez les fondamentaux des bases de donnees relationnelles et utilisez Supabase comme plateforme BaaS moderne |
|
||||||
|
| [Backend 3 : Conception et developpement d'APIs backend](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/ai-interface-code/) | Utilisez l'IA pour assister la conception d'APIs, la generation de code backend et la documentation d'APIs |
|
||||||
|
| [Backend 4 : Livrez votre prototype de produit](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/zeabur-deployment/) | Deploiez rapidement des applications full-stack dans le cloud avec Zeabur |
|
||||||
|
| [Backend 5 : Des IDEs aux outils de programmation IA par CLI](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/modern-cli/) | Explorez les flux de travail de programmation IA depuis le terminal pour le developpement moderne |
|
||||||
|
| [Backend 6 : Integrez Stripe et d'autres systemes de facturation](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/stripe-payment/) | Ajoutez la monetisation avec des capacites de paiement et de facturation |
|
||||||
|
|
||||||
|
#### Projets majeurs
|
||||||
|
|
||||||
|
| Section | Contenu cle |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Projet majeur 1 : Votre premiere application SaaS full-stack - Site de copywriting IA](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/fullstack-app/) | Construisez un espace de travail de marketing IA avec connexion, generation, facturation et gestion admin |
|
||||||
|
| [Projet majeur 2 : Systeme d'examens et de gestion en ligne](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/modern-frontend-trae/) | Construisez un systeme d'examens en ligne avec generation de questions, flux d'examen et outils d'administration |
|
||||||
|
|
||||||
|
#### Annexe des capacites IA
|
||||||
|
|
||||||
|
| Section | Contenu cle |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [IA 1 : Bases de Dify et integration de base de connaissances](https://datawhalechina.github.io/easy-vibe/en/stage-2/ai-capabilities/dify-knowledge-base/) | Apprenez a construire des applications IA avec Dify et integrer des bases de connaissances privees |
|
||||||
|
|
||||||
|
### III. Developpeurs avancés
|
||||||
|
|
||||||
|
#### Competences cles de Claude Code
|
||||||
|
|
||||||
|
| Section | Contenu cle |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Demarrer avec Claude Code](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/basics/) | Installation, configuration, fondamentaux et commandes utiles |
|
||||||
|
| [Guide Claude Code MCP](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/mcp/) | Connectez Claude Code a GitHub, bases de donnees, APIs et autres services via MCP |
|
||||||
|
| [Guide Claude Code Skills](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/skills/) | Emballez l'expertise en competences reutilisables que vous pouvez utiliser encore et encore |
|
||||||
|
| [Comment garder Claude Code au travail pour les taches de longue duree](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/long-running-tasks/) | Concevez des taches de longue duree pour que les outils de codage continuent a travailler jusqu'a la fin |
|
||||||
|
| [Guide Claude Agent Teams](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/agent-teams/) | Coordonnez plusieurs instances d'IA comme une vraie equipe de developpement |
|
||||||
|
| [Superpouvoirs Claude Code pour le developpement de qualite industrielle](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/superpowers/) | Aidez l'IA a produire du code de qualite industrielle avec TDD et meilleures pratiques |
|
||||||
|
| [Meilleures pratiques de flux de travail Claude Code](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/workflow/) | Meilleures pratiques pour le refactoring, la revue de code et le developpement quotidien |
|
||||||
|
| [Developpement a distance avec Claude Code sur mobile](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/mobile-development/) | Utilisez Claude Code au-dela du bureau et construisez un flux de travail a distance productif sur appareils mobiles |
|
||||||
|
| [Guide complet du SDK Claude Agent](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/claude-agent-sdk/) | Construisez des flux de travail d'agents personnalises et integrez Claude dans vos propres outils avec le SDK |
|
||||||
|
| [Du vibe coding au spec coding](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/spec-coding/) | Passez des prompts ad-hoc a un flux de developpement IA plus structure et base sur des specifications |
|
||||||
|
|
||||||
|
#### Developpement multiplateformes
|
||||||
|
|
||||||
|
| Section | Contenu cle |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Comment choisir la bonne plateforme pour votre application](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/choose-platform/) | Comparez les formats d'applications et choisissez la bonne plateforme selon les utilisateurs, scenarios et objectifs de livraison |
|
||||||
|
| [Construisez un Mini Programme WeChat](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/wechat-miniprogram/) | Comprenez l'ecosysteme et livrez un mini programme frontend du template au lancement |
|
||||||
|
| [Construisez un Mini Programme WeChat avec backend](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/wechat-miniprogram-backend/) | Ajoutez une logique backend et des bases de donnees pour completer la boucle metier complete |
|
||||||
|
| [Construisez une application Android](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/android-app/) | Apprenez le developpement d'applications Android avec un flux de travail natif moderne |
|
||||||
|
| [Construisez une application iOS](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/ios-app/) | Apprenez le developpement d'applications iOS et les conventions de l'ecosysteme Apple |
|
||||||
|
| [Construisez une application PWA locale](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/pwa-local-app/) | Transformez un site web en vraie application avec support hors ligne, push et installation |
|
||||||
|
| [Construisez une extension d'assistant IA pour navigateur](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/browser-ai-extension/) | Creez une extension Chrome qui resumera n'importe quelle page avec des APIs cloud ou l'IA integree |
|
||||||
|
| [Construisez une application de bureau avec Electron](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/electron-voice-to-text/) | Construisez une application de bureau voix-vers-texte avec Electron pour trois plateformes |
|
||||||
|
| [Construisez et frappez rapidement un NFT](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/nft-minting/) | Ecrivez un contrat intelligent depuis zero, deployez-le et frappez votre propre NFT |
|
||||||
|
| [Construisez une extension VS Code](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/vscode-extension/) | Construisez un assistant de projet IA avec templates, chat de code et Q&A multi-fichiers |
|
||||||
|
| [Construisez une application de bureau Qt de qualite industrielle](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/qt-industrial-hmi/) | Creez un systeme HMI Qt en temps reel avec tendances, alertes et surveillance |
|
||||||
|
|
||||||
|
#### Annexe des capacites IA
|
||||||
|
|
||||||
|
| Section | Contenu cle |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Qu'est-ce que RAG et comment ca fonctionne](https://datawhalechina.github.io/easy-vibe/en/stage-3/ai-advanced/rag-introduction/) | Construisez une comprehension systematique des principes RAG et des architectures courantes |
|
||||||
|
| [Flux de travail RAG intermediaires et avances avec LangGraph](https://datawhalechina.github.io/easy-vibe/en/stage-3/ai-advanced/langgraph-advanced-rag/) | Concevez des flux de travail multi-etapes et des systemes RAG plus avances |
|
||||||
|
|
||||||
|
### 📚 Base de connaissances de l'annexe
|
||||||
|
|
||||||
|
> Couvrant **9 domaines de connaissances majeurs** et **plus de 80 sujets interactifs**, cette annexe utilise l'animation et des composants visuels pour vous aider a comprendre intuitivement les concepts cles, des fondamentaux informatiques a la frontiere de l'IA.
|
||||||
|
>
|
||||||
|
> 👉 [Voir l'appendice complet](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
### 🎓 Autres cours
|
||||||
|
|
||||||
|
- [Hands-on Modern RL](#autres-cours)
|
||||||
|
- [Learn Harness Engineering](#autres-cours)
|
||||||
|
|
||||||
|
## 🛠️ Comment apprendre
|
||||||
|
|
||||||
|
- Lisez et pratiquez les sections qui correspondent a votre niveau actuel. Si vous etes bloque, n'hesitez pas a ouvrir un issue.
|
||||||
|
|
||||||
|
## 💻 Executer localement
|
||||||
|
|
||||||
|
### Approche moderne
|
||||||
|
|
||||||
|
Dans une fenetre de chat d'un AI IDE comme VS Code, Cursor ou Trae, vous pouvez simplement dire :
|
||||||
|
|
||||||
|
```text
|
||||||
|
Aidez-moi a executer ce projet localement.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Approche traditionnelle
|
||||||
|
|
||||||
|
1. `npm install`
|
||||||
|
2. `npm run dev`
|
||||||
|
3. Ouvrez `http://localhost:3000` dans votre navigateur.
|
||||||
|
|
||||||
|
## Autres cours
|
||||||
|
|
||||||
|
Notre equipe a aussi cree d'autres cours ! Decouvrez-les :
|
||||||
|
|
||||||
|
[](https://github.com/walkinglabs/hands-on-modern-rl)
|
||||||
|
|
||||||
|
**Hands-on Modern RL**: Un programme pratique et open source qui comble le fosse entre les concepts de base du RL et l'alignement des LLMs, RLVR et les systemes Agentic avances.
|
||||||
|
|
||||||
|
[](https://github.com/walkinglabs/learn-harness-engineering/tree/main)
|
||||||
|
|
||||||
|
**Learn Harness Engineering**: Un guide complet sur l'ingenierie des harnais.
|
||||||
|
|
||||||
|
## 🤝 Contribuer et contributeurs
|
||||||
|
|
||||||
|
- Si vous trouvez un probleme ou voyez quelque chose qui peut etre ameliore, n'hesitez pas a ouvrir un issue. Si personne ne repond, vous pouvez aussi contacter l'[equipe de support Datawhale](https://github.com/datawhalechina/DOPMC/blob/main/OP.md).
|
||||||
|
- Si vous voulez contribuer, ouvrez un pull request. Si personne ne repond, vous pouvez aussi contacter l'[equipe de support Datawhale](https://github.com/datawhalechina/DOPMC/blob/main/OP.md).
|
||||||
|
- Si vous voulez lancer un nouveau projet open source Datawhale, veuillez suivre le [Guide des Projets Open Source Datawhale](https://github.com/datawhalechina/DOPMC/blob/main/GUIDE.md).
|
||||||
|
|
||||||
|
### 🙏 Contributeurs
|
||||||
|
|
||||||
|
- [Sanbu - Chef de projet](https://github.com/sanbuphy) (Membre Datawhale)
|
||||||
|
- Fang Ke - Mentor (Membre Datawhale, Universite Tsinghua)
|
||||||
|
- [Yerim Kang](https://github.com/yerim25) (Projets pratiques, Universite Tsinghua)
|
||||||
|
- [Zhilin Zhao](https://github.com/ChileenZ) (Projets pratiques, Universite Tsinghua)
|
||||||
|
- [Yixuan Li](https://yixuan20.github.io/) (Design visuel, Universite Tsinghua)
|
||||||
|
- Siyi Liu (Projets pratiques, Universite Tsinghua)
|
||||||
|
- [Lixin Liu](https://github.com/liulx25xx) (Projets pratiques, Universite Tsinghua)
|
||||||
|
- Tous les membres du groupe de test interne AI Vibe Coding 101 qui ont partage des suggestions et des commentaires
|
||||||
|
|
||||||
|
### Remerciements speciaux
|
||||||
|
|
||||||
|
- Merci a [@Sm1les](https://github.com/Sm1les) pour l'aide et le soutien sur ce projet
|
||||||
|
- Merci a chaque contributeur et a tous ceux qui ont soutenu le projet avec des commentaires et des etoiles ❤️
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a href="https://www.star-history.com/#datawhalechina/easy-vibe&type=timeline&legend=top-left">
|
||||||
|
<picture>
|
||||||
|
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=datawhalechina/easy-vibe&type=timeline&theme=dark&legend=top-left" />
|
||||||
|
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=datawhalechina/easy-vibe&type=timeline&legend=top-left" />
|
||||||
|
</picture>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align=center style="margin-top: 30px;">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=datawhalechina/easy-vibe" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 📄 LICENCE
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
|
||||||
|
<img
|
||||||
|
alt="Licence Creative Commons"
|
||||||
|
style="border-width:0"
|
||||||
|
src="https://img.shields.io/badge/license-CC%20BY--NC--SA%204.0-lightgrey"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<br />
|
||||||
|
Cette oeuvre est licenciee sous la
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
|
||||||
|
Licence Internationale Creative Commons Attribution-NonCommercial-ShareAlike 4.0
|
||||||
|
</a>.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Star History
|
||||||
|
|
||||||
|
[](https://www.star-history.com/#datawhalechina/easy-vibe&type=date&legend=top-left)
|
||||||
@@ -0,0 +1,449 @@
|
|||||||
|
<!-- trigger vercel build -->
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
<img src="../../assets/easy-vibe-logo-hd.svg" alt="Easy-Vibe Logo" width="300">
|
||||||
|
|
||||||
|
<img src="../../assets/banner.png" alt="Easy-Vibe Banner" width="100%">
|
||||||
|
|
||||||
|
<p align="center" style="font-size: 1.2em; color: #666; margin: 20px 0;">
|
||||||
|
さっそく始めて、一緒に vibe しよう。話せればアプリは作れます。<br>
|
||||||
|
<span style="font-size: 0.9em; color: #888;">直接上手,一起 vibe!会说话就会做应用。</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a href="https://trendshift.io/repositories/22079" target="_blank"><img src="https://trendshift.io/api/badge/repositories/22079" alt="datawhalechina/easy-vibe | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||||
|
|
||||||
|
<p align="center" style="font-size: 1.05em; color: #666; margin: 16px 0;">
|
||||||
|
你好 · Hello · 哈囉 · こんにちは · 안녕하세요 · Hola · Bonjour · Hallo · مرحبا · Xin chào<br>
|
||||||
|
チュートリアルの第1部は10言語に対応しました。世界中の仲間たち、一緒に coding を始めましょう!<br>
|
||||||
|
<span style="font-size: 0.9em; color: #888;">我们的教程(第一部分)已经支持 10 种语言,欢迎世界各地的朋友一起 coding!</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
🚀 <a href="https://datawhalechina.github.io/easy-vibe/welcome.html">探索を始める</a> · ✨ <a href="https://datawhalechina.github.io/easy-vibe/en/appendix/">インタラクティブ教材</a> · 🦞 <a href="https://github.com/datawhalechina/hello-claw">OpenClaw を学ぶ</a> · 📖 <a href="#table-of-contents">目次</a><br>
|
||||||
|
<span style="font-size: 0.85em; color: #888;">🚀 <a href="https://datawhalechina.github.io/easy-vibe/welcome.html">开始体验</a> · ✨ <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/">交互式教程</a> · 🦞 <a href="https://github.com/datawhalechina/hello-claw">学习 OpenClaw</a> · 📖 <a href="#table-of-contents">查看目录</a></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://datawhalechina.github.io/easy-vibe/welcome.html">オンラインで読む</a> ·
|
||||||
|
<a href="#-content-navigation">学習マップ</a><br>
|
||||||
|
<span style="font-size: 0.85em; color: #888;">
|
||||||
|
<a href="https://datawhalechina.github.io/easy-vibe/welcome.html">开始阅读</a> ·
|
||||||
|
<a href="#-content-navigation">学习地图</a>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/stargazers" target="_blank">
|
||||||
|
<img src="https://img.shields.io/github/stars/datawhalechina/easy-vibe?color=660874&style=for-the-badge&logo=star&logoColor=white&labelColor=1a1a2e" alt="Stars"></a>
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/network/members" target="_blank">
|
||||||
|
<img src="https://img.shields.io/github/forks/datawhalechina/easy-vibe?color=660874&style=for-the-badge&logo=git-fork&logoColor=white&labelColor=1a1a2e" alt="Forks"></a>
|
||||||
|
<a href="../../LICENSE" target="_blank">
|
||||||
|
<img src="https://img.shields.io/badge/License-CC_BY_NC_SA_4.0-4ecdc4?style=for-the-badge&logo=creative-commons&logoColor=white&labelColor=1a1a2e" alt="License"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="../zh-CN/README.md"><img alt="简体中文" src="https://img.shields.io/badge/简体中文-d9d9d9"></a>
|
||||||
|
<a href="../zh-TW/README.md"><img alt="繁體中文" src="https://img.shields.io/badge/繁體中文-d9d9d9"></a>
|
||||||
|
<a href="../en-US/README.md"><img alt="English" src="https://img.shields.io/badge/English-d9d9d9"></a>
|
||||||
|
<a href="../ja-JP/README.md"><img alt="日本語" src="https://img.shields.io/badge/日本語-d9d9d9"></a>
|
||||||
|
<a href="../es-ES/README.md"><img alt="Español" src="https://img.shields.io/badge/Español-d9d9d9"></a>
|
||||||
|
<a href="../fr-FR/README.md"><img alt="Français" src="https://img.shields.io/badge/Français-d9d9d9"></a>
|
||||||
|
<a href="../ko-KR/README.md"><img alt="한국어" src="https://img.shields.io/badge/한국어-d9d9d9"></a>
|
||||||
|
<a href="../ar-SA/README.md"><img alt="العربية" src="https://img.shields.io/badge/العربية-d9d9d9"></a>
|
||||||
|
<a href="../vi-VN/README.md"><img alt="Tiếng_Việt" src="https://img.shields.io/badge/Tiếng_Việt-d9d9d9"></a>
|
||||||
|
<a href="../de-DE/README.md"><img alt="Deutsch" src="https://img.shields.io/badge/Deutsch-d9d9d9"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<table align="center">
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-header.png" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>初心者向け学習マップ</strong>
|
||||||
|
<br>
|
||||||
|
<sub>ゼロから迷わず進める明確なガイダンス、「学んでは忘れる」から脱却</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-tutorial.png" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>手取り足取りの図解チュートリアル</strong>
|
||||||
|
<br>
|
||||||
|
<sub>専属講師がそばにいるかのように、詳しい手順を一つずつ解説</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-ide.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>没入型シミュレーションコーディング</strong>
|
||||||
|
<br>
|
||||||
|
<sub>仮想マウスガイドで IDE の核心的なワークフローを素早く習得</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-diffusion.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>目で見える AI の原理</strong>
|
||||||
|
<br>
|
||||||
|
<sub>アニメーション解説で AI が画像を生成する仕組みを直感的に理解</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-rag.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>ゲーム感覚で学ぶ RAG</strong>
|
||||||
|
<br>
|
||||||
|
<sub>インタラクティブコンポーネントで RAG のデータフロー全体をクリック操作で理解</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/git-terminal.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>可視化されたターミナルの概念</strong>
|
||||||
|
<br>
|
||||||
|
<sub>裏側のロジックを可視化することで、コマンドラインの動作が直感的に理解できる</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div align="center">
|
||||||
|
<h3>⭐ <a href="https://github.com/datawhalechina/easy-vibe" style="color: #d0cd16ff;">こちらで Star を付けると</a> 更新が加速します ❤️</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align="center" style="margin: 30px 0;">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/issues/new?template=story_submission.md">
|
||||||
|
<img src="https://raw.githubusercontent.com/datawhalechina/easy-vibe/main/assets/stories_image.png" alt="あなたの Vibe ストーリーをシェア" width="80%" style="border-radius: 10px; box-shadow: 0 4px 12px rgba(0,0,0,0.15);">
|
||||||
|
</a>
|
||||||
|
<p style="margin-top: 15px; font-size: 1.1em; color: #666;">
|
||||||
|
📝 <strong>あなたの vibe coding ストーリーがありますか?</strong>
|
||||||
|
こちらから投稿して、他の人にインスピレーションを与えましょう!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 目次
|
||||||
|
|
||||||
|
- [なぜ Easy-Vibe なのか](#なぜ-easy-vibe-なのか)
|
||||||
|
- [ニュース](#-news)
|
||||||
|
- [こんな人におすすめ](#こんな人におすすめ)
|
||||||
|
- [あなたの学習パス](#あなたの学習パス)
|
||||||
|
- [学習のヒント](#学習のヒント)
|
||||||
|
- [I. 初心者入門](#i-初心者入門)
|
||||||
|
- [II. ジュニア・ミッドレベル開発者](#ii-ジュニアミッドレベル開発者)
|
||||||
|
- [III. 上級開発者](#iii-上級開発者)
|
||||||
|
- [附録 ナレッジベース](#-附录ナレッジベース)
|
||||||
|
- [学び方](#️-学び方)
|
||||||
|
- [ローカルで実行](#-ローカルで実行)
|
||||||
|
- [その他のコース](#その他のコース)
|
||||||
|
- [貢献と貢献者](#-貢献と貢献者)
|
||||||
|
- [ライセンス](#-ライセンス)
|
||||||
|
|
||||||
|
## なぜ Easy-Vibe なのか
|
||||||
|
|
||||||
|
家計簿アプリを作りたい?言葉にするだけでいい。
|
||||||
|
|
||||||
|
WeChat ログイン付きの予約システムが必要?言葉にするだけでいい。
|
||||||
|
|
||||||
|
コメント機能付きのブログを作りたい?言葉にするだけでいい。
|
||||||
|
|
||||||
|
AI 時代のプログラミングは、欲しいものを言葉で伝えることから始まります。
|
||||||
|
|
||||||
|
Easy-Vibe は、それを本物のプロダクトにする方法を教えます。
|
||||||
|
|
||||||
|
|
||||||
|
## 🔥 ニュース
|
||||||
|
|
||||||
|
- **[2026-05-20]** 🌍 **Stage 1 の多言語カバーが完了**:Stage 1 はサポート対象の全言語(zh-cn, en, zh-tw, ja-jp, ko-kr, es-es, fr-fr, de-de, ar-sa, vi-vn)で利用可能になりました。ナビゲーション/ビルドの確認を行い、404 を避けています。
|
||||||
|
- **[2026-03-29]** ✨ **Vibe ストーリーズを公開し、実ユーザーの体験談にアップグレード**:ホームページにインタラクティブなカルーセルと専用ストーリーページを追加し、仮の内容を農村の小学校教師、大学生、高校の情報技術教師、トラック運転手による 4 つの実話に差し替えました。[👉 ストーリーを見る](https://datawhalechina.github.io/easy-vibe/zh-cn/vibe-stories/story-1.html)
|
||||||
|
- **[2026-03-26]** 🚀 **ステージ 2 実践コンテンツの大幅更新**:SaaS キャップストーンプロジェクト「[最初の SaaS フルスタックアプリ:コピー生成サイト](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/fullstack-app/)」を完成し、「[Stripe などの決済システムの統合方法](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/stripe-payment/)」セクションを大幅に拡充し、マルチプロダクト UI や WeChat ミニプログラムのバックエンドワークフローに関する重要コンテンツも追加。
|
||||||
|
- **[2026-03-25]** 📚 **新規附録:ユーザー調査と要件検証**:アイデアの探し方、ダブルダイヤモンドモデル、Jobs to Be Done、The Mom Test の 4 つの新記事を追加し、初心者が製品アイデアを発見・検証できるよう支援。[👉 附録を読む](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
- **[2026-03-25]** 📚 **英語ドキュメント全面更新**:ステージ 2(フルスタック開発)とステージ 3(高度開発)が完全に英語で利用可能になりました。[👉 学習を始める](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
<details>
|
||||||
|
<summary>過去のニュース</summary>
|
||||||
|
|
||||||
|
- **[2026-03-02]** 🦞 **OpenClaw & AI Agent フレンドリーサポート**:`llms.txt` を追加し、OpenClaw、Claude、Cursor、Trae などの AI Agent がリポジトリ構造を迅速に理解し、適切なチュートリアルコンテンツを見つけられるようにしました。
|
||||||
|
- **[2026-03-01]** [高度開発セクション](https://datawhalechina.github.io/easy-vibe/en/stage-3/)を全面アップグレード:Claude Code の詳細ガイド(MCP、Skills、Agent Teams など)と 8 つのクロスプラットフォームプロジェクトチュートリアルを追加。
|
||||||
|
- **[2026-02-25]** [附録ナレッジベース](https://datawhalechina.github.io/easy-vibe/en/appendix/)を更新し、9 つの主要ナレッジ領域と 80 以上のインタラクティブトピックをカバー。
|
||||||
|
- **[2026-01-27]** Android と iOS アプリ開発チュートリアルを追加。
|
||||||
|
- **[2026-01-19]** Prompt Engineering、AI 歴史、認証設計、Git 原理などのインタラクティブデモをリリース。
|
||||||
|
- **[2026-01-16]** プロジェクト構造を再構築し、初心者向け入門パスを正式に確立。
|
||||||
|
- **[2026-01-14]** ステージ 1 のプロダクトプロトタイピングドキュメントの大規模更新を完了。
|
||||||
|
- **[2026-01-13]** ドキュメントアーキテクチャを再構築し、多言語サポートを完全に有効化。
|
||||||
|
- **[2026-01-01]** プロジェクトのコア学習マップをリリース。
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## こんな人におすすめ
|
||||||
|
|
||||||
|
- **完全な初心者**:まずは最初のプロジェクトを作り、仕組みは後から理解する
|
||||||
|
- **プロダクトマネージャー / 起業家**:アイデアを素早く検証し、低コストで MVP を構築
|
||||||
|
- **学生**:AI 時代の実践的スキルを身につける
|
||||||
|
- **ジュニア開発者**:アイデアからリリースまでの全工程を学ぶ
|
||||||
|
- **ミッドレベル・シニア開発者**:複雑なプロジェクトでの AI 協働ワークフローをアップグレード
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## あなたの学習パス
|
||||||
|
|
||||||
|
### 🎮 まずはサクッと体験したい
|
||||||
|
**対象**:すべての人
|
||||||
|
**学ぶこと**:シンプルで具体的なハンズオンを通じて、AI コーディングがどのようなものか体験する
|
||||||
|
**得られるもの**:vibe coding の明確な第一印象と、AI との対話による開発手法
|
||||||
|
|
||||||
|
[ここから始める](https://datawhalechina.github.io/easy-vibe/en/stage-1/ai-capabilities-through-games/)
|
||||||
|
|
||||||
|
### 💡 アイデアをプロダクトプロトタイプにしたい
|
||||||
|
**対象**:初心者 / プロダクトマネージャー / 起業家
|
||||||
|
**学ぶこと**:学習マップ、AI IDE ツール、アイデア検証、プロトタイピング、AI 機能統合、フルデモの反復開発
|
||||||
|
**得られるもの**:ユーザーやチームメンバーに見せられる、実動する AI プロダクトプロトタイプ
|
||||||
|
|
||||||
|
[学習を始める](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/)
|
||||||
|
|
||||||
|
### 🚀 エンドツーエンドでフルスタックプロダクトを構築したい
|
||||||
|
**対象**:ジュニア開発者 / インディーハッカー / 上級学習者
|
||||||
|
**学ぶこと**:フロントエンドワークフロー、デザイン to コード、データベース、バックエンド API、デプロイメント、決済、大型プロジェクト
|
||||||
|
**得られるもの**:モダンな AI 対応 Web アプリケーションを独自にリリースする力
|
||||||
|
|
||||||
|
[学習を始める](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
|
||||||
|
### AI ネイティブ:高度な Claude Code とエージェントワークフローを学びたい
|
||||||
|
**対象**:AI ネイティブエンジニアリングに興味のある開発者
|
||||||
|
**学ぶこと**:Claude Code、MCP、Skills、Agent Teams、長時間タスク、Spec Coding、クロスプラットフォームアプリ開発
|
||||||
|
**得られるもの**:複雑な AI 支援開発と自動化のための強力なワークフロー
|
||||||
|
|
||||||
|
[高度開発へ進む](https://datawhalechina.github.io/easy-vibe/en/stage-3/)
|
||||||
|
|
||||||
|
### 📚 参考資料と基礎知識を身につけたい
|
||||||
|
**対象**:すべての人
|
||||||
|
**学ぶこと**:コンピュータの基礎、フロントエンド / バックエンドの基本、インフラ、AI の原理、エンジニアリングの実践
|
||||||
|
**得られるもの**:9 つの主要ナレッジ領域をカバーする長期参照用ナレッジベース
|
||||||
|
|
||||||
|
[ナレッジベースを見る](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
## 学習のヒント
|
||||||
|
|
||||||
|
- 初心者、プロダクトマネージャー、起業家は [ステージ 1](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/) から始めましょう
|
||||||
|
- プロトタイプからフルスタック開発へ進みたい場合は [ステージ 2](https://datawhalechina.github.io/easy-vibe/en/stage-2/) から始めましょう
|
||||||
|
- 高度な Claude Code ワークフローやクロスプラットフォームプロジェクトを学びたい場合は [ステージ 3](https://datawhalechina.github.io/easy-vibe/en/stage-3/) へ進みましょう
|
||||||
|
- 概念や背景知識で行き詰まった場合は [附録ナレッジベース](https://datawhalechina.github.io/easy-vibe/en/appendix/) を活用しましょう
|
||||||
|
|
||||||
|
### 📖 コンテンツナビゲーション
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<img src="../../assets/readme-image1.png" alt="学習マップ" width="70%" style="border-radius: 10px; box-shadow: 0 8px 20px rgba(45,55,72,0.3); margin: 15px 0;"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
### I. 初心者入門
|
||||||
|
|
||||||
|
| セクション | 主要コンテンツ |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [学習マップ](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/) | 学習全体のガイド付き概覧 |
|
||||||
|
| [AI 時代:話せればプログラミングできる](https://datawhalechina.github.io/easy-vibe/en/stage-1/ai-capabilities-through-games/) | スネークゲームなどの例で AI コーディングを初体験 |
|
||||||
|
| [AI プログラミングツールをマスターする](https://datawhalechina.github.io/easy-vibe/en/stage-1/introduction-to-ai-ide/) | AI IDE ツールの使い方を学び、シンプルなローカルプロジェクトを構築 |
|
||||||
|
| [良いアイデアを見つける](https://datawhalechina.github.io/easy-vibe/en/stage-1/finding-great-idea/) | 作る価値のあるプロダクトアイデアを見つけ検証する方法を学ぶ |
|
||||||
|
| [プロダクトプロトタイプを構築する](https://datawhalechina.github.io/easy-vibe/en/stage-1/building-prototype/) | 要件から単一ページ・複数ページのプロダクトプロトタイプへ |
|
||||||
|
| [AI 機能を統合する](https://datawhalechina.github.io/easy-vibe/en/stage-1/integrating-ai-capabilities/) | テキスト、画像、動画の AI 機能を統合 |
|
||||||
|
| [完全プロジェクト実践](https://datawhalechina.github.io/easy-vibe/en/stage-1/complete-project-practice/) | 実際のシナリオをシミュレーションし、ユーザーフィードバックを集めてプロジェクトを反復開発 |
|
||||||
|
|
||||||
|
#### 附録:プロダクトとビジネス思考
|
||||||
|
|
||||||
|
| セクション | 主要コンテンツ |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [プロダクト思考とソリューション設計](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-a-product-thinking/) | ゼロからイチのプロダクトを作るための核心フレームワーク |
|
||||||
|
| [AI 業界アプリケーションシナリオ(BtoB)](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-industry-scenarios/) | 業界横断的な AI の活用方法を理解する |
|
||||||
|
| [AI コンシューマーシナリオのインスピレーション(BtoC)](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-c-consumer-scenarios/) | コンシューマー AI におけるプロダクト機会を探る |
|
||||||
|
|
||||||
|
#### 附録:ユーザー調査と要件検証
|
||||||
|
|
||||||
|
| セクション | 主要コンテンツ |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [アイデアの探し方:初心者に最適な 3 つの参考ソース](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-idea-sources/) | 具体的なプロダクト機会を見つけるための信頼できるパイプラインを構築 |
|
||||||
|
| [ダブルダイヤモンド:まず正しいことをして、それから正しくやる](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-double-diamond/) | 構造化されたプロセスで散在するインスピレーションから実行可能な方向へ |
|
||||||
|
| [Jobs to Be Done でユーザーが本当に望むことを見つける](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-jobs-to-be-done/) | 表面的な機能要望ではなく、実際のタスクを通じてユーザーの目標を分析 |
|
||||||
|
| [The Mom Test:需要を検証するためのユーザーインタビュー法](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-mom-test/) | より良い質問の仕方を学び、誤検出フィードバックを回避する |
|
||||||
|
|
||||||
|
#### 附録:技術ソリューション
|
||||||
|
|
||||||
|
| セクション | 主要コンテンツ |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [エラーに遭遇したらどうするか](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-b-common-errors/) | vibe coding でのよくある問題とトラブルシューティング方法 |
|
||||||
|
| [7 つの AI プログラミングツールの比較](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-articles/example0-1/vibe-coding-tools-snake-game-tutorial) | 実際のテストを通じて主要 AI コーディングプラットフォームを比較 |
|
||||||
|
| [エージェントでウェブサイトをデザインする](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-articles/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents) | 実践的なマルチエージェントコラボレーションを学ぶ |
|
||||||
|
|
||||||
|
### II. ジュニア・ミッドレベル開発者
|
||||||
|
|
||||||
|
#### フロントエンド
|
||||||
|
|
||||||
|
| セクション | 主要コンテンツ |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [フロントエンド 0:Lovart で自分専用の素材制作エージェントを構築](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/lovart-assets/) | Nanobanana と Lovart を使ってビジュアル素材を一括生成し、意図認識付きの描画エージェントを構築 |
|
||||||
|
| [フロントエンド 1:Figma と MasterGo の基礎](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/figma-mastergo/) | デザインカンプから実装可能な UI 設計思考までのワークフローを学ぶ |
|
||||||
|
| [フロントエンド 2:最初のモダンアプリを構築 - UI デザイン](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/ui-design/) | モダンアプリケーションインターフェースの背後にある UI デザインの基礎を学ぶ |
|
||||||
|
| [フロントエンド 3:UI ガイドラインとマルチプロダクトデザイン](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/multi-product-ui/) | 共通の UI ルールで複数プロダクト間の一貫性と美しさを向上 |
|
||||||
|
| [フロントエンド 4:LLM と Skills でインターフェースを美しく](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/llm-skills-beautiful/) | プロンプトとプラグインを使って AI により洗練された独自のインターフェースを生成 |
|
||||||
|
| [フロントエンド 4:ホグワーツの肖像画を作ろう](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/hogwarts-portraits/) | ゼロからインタラクティブな AI 画像フロントエンドプロジェクトを構築 |
|
||||||
|
| [フロントエンド 6:デザインプロトタイプからプロジェクトコードへ](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/design-to-code/) | デザインプロトタイプをブラウザで実際に動くフロントエンドコードに変換 |
|
||||||
|
| [フロントエンド 7:モダンコンポーネントライブラリで UI をアップグレード](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/modern-component-library/) | コンポーネントライブラリでプロフェッショナルなインターフェースを素早く構築 |
|
||||||
|
|
||||||
|
#### バックエンド
|
||||||
|
|
||||||
|
| セクション | 主要コンテンツ |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [バックエンド 1:Git と GitHub を学ぶ](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/git-workflow/) | Git のコアバージョン管理操作とコラボレーションワークフローをマスター |
|
||||||
|
| [バックエンド 2:データベースから Supabase まで](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/database-supabase/) | リレーショナルデータベースの基礎を学び、Supabase をモダン BaaS プラットフォームとして活用 |
|
||||||
|
| [バックエンド 3:バックエンド API 設計と開発](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/ai-interface-code/) | AI を活用した API 設計、バックエンドコード生成、API ドキュメント |
|
||||||
|
| [バックエンド 4:プロダクトプロトタイプをリリースする](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/zeabur-deployment/) | フルスタックアプリケーションを Zeabur で素早くクラウドにデプロイ |
|
||||||
|
| [バックエンド 5:IDE から CLI AI コーディングツールへ](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/modern-cli/) | ターミナルファーストの AI コーディングワークフローを探索 |
|
||||||
|
| [バックエンド 6:Stripe やその他の決済システムを統合する](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/stripe-payment/) | 支払いと決済機能でマネタイズを追加 |
|
||||||
|
|
||||||
|
#### 大型プロジェクト
|
||||||
|
|
||||||
|
| セクション | 主要コンテンツ |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [大型プロジェクト 1:最初の SaaS フルスタックアプリ - AI コピー生成サイト](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/fullstack-app/) | ログイン、生成、決済、管理機能付きの AI マーケティングコピー作成ワークスペースを構築 |
|
||||||
|
| [大型プロジェクト 2:オンライン試験・管理システム](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/modern-frontend-trae/) | 問題生成、受験フロー、管理ツール付きのオンライン試験システムを構築 |
|
||||||
|
|
||||||
|
#### AI 機能 附録
|
||||||
|
|
||||||
|
| セクション | 主要コンテンツ |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [AI 1:Dify 基礎とナレッジベース統合](https://datawhalechina.github.io/easy-vibe/en/stage-2/ai-capabilities/dify-knowledge-base/) | Dify で AI アプリケーションを構築し、プライベートナレッジベースを統合する方法を学ぶ |
|
||||||
|
|
||||||
|
### III. 上級開発者
|
||||||
|
|
||||||
|
#### Claude Code コアスキル
|
||||||
|
|
||||||
|
| セクション | 主要コンテンツ |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Claude Code 入門](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/basics/) | インストール、セットアップ、基礎、便利なコマンド |
|
||||||
|
| [Claude Code MCP ガイド](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/mcp/) | MCP を通じて Claude Code を GitHub、データベース、API などのサービスに接続 |
|
||||||
|
| [Claude Code Skills ガイド](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/skills/) | 専門知識を再利用可能なスキルとしてパッケージ化 |
|
||||||
|
| [長時間タスクで Claude Code を働かせ続ける方法](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/long-running-tasks/) | コーディングツールが完了まで働き続けられるよう長時間タスクを設計 |
|
||||||
|
| [Claude Agent Teams ガイド](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/agent-teams/) | 複数の AI インスタンスを本当の開発チームのように連携 |
|
||||||
|
| [エンジニアリング級開発のための Claude Code Superpowers](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/superpowers/) | TDD とベストプラクティスで AI にエンジニアリング級のコードを書かせる |
|
||||||
|
| [Claude Code ワークフローベストプラクティス](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/workflow/) | リファクタリング、コードレビュー、日常開発のベストプラクティス |
|
||||||
|
| [モバイルでの Claude Code リモート開発](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/mobile-development/) | デスクトップを超えて Claude Code を活用し、モバイルデバイスで生産的なリモートワークフローを構築 |
|
||||||
|
| [Claude Agent SDK 完全ガイド](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/claude-agent-sdk/) | カスタムエージェントワークフローを構築し、SDK で Claude を独自のツールに統合 |
|
||||||
|
| [vibe coding から spec coding へ](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/spec-coding/) | アドホックなプロンプトから、より構造化された仕様駆動の AI 開発ワークフローへ移行 |
|
||||||
|
|
||||||
|
#### クロスプラットフォーム開発
|
||||||
|
|
||||||
|
| セクション | 主要コンテンツ |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [アプリに適したプラットフォームの選び方](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/choose-platform/) | アプリ形態を比較し、ユーザー、シナリオ、配信目標に基づいて適切なプラットフォームを選択 |
|
||||||
|
| [WeChat ミニプログラムを構築する](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/wechat-miniprogram/) | エコシステムを理解し、テンプレートからリリースまでフロントエンドミニプログラムを完成 |
|
||||||
|
| [バックエンド付き WeChat ミニプログラムを構築する](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/wechat-miniprogram-backend/) | バックエンドロジックとデータベースを追加して完全なビジネスループを完成 |
|
||||||
|
| [Android アプリを構築する](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/android-app/) | モダンなネイティブワークフローで Android アプリ開発を学ぶ |
|
||||||
|
| [iOS アプリを構築する](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/ios-app/) | iOS アプリ開発と Apple エコシステムの規約を学ぶ |
|
||||||
|
| [ローカル PWA アプリを構築する](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/pwa-local-app/) | オフラインサポート、プッシュ通知、インストール機能でウェブサイトを本当のアプリに変換 |
|
||||||
|
| [ブラウザ AI アシスタント拡張機能を構築する](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/browser-ai-extension/) | クラウド API または内蔵 AI で任意のページを要約する Chrome 拡張機能を作成 |
|
||||||
|
| [Electron デスクトップアプリを構築する](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/electron-voice-to-text/) | Electron で 3 プラットフォーム対応の音声テキスト変換デスクトップアプリを構築 |
|
||||||
|
| [NFT を迅速に構築してミントする](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/nft-minting/) | スマートコントラクトをゼロから作成し、デプロイして自分の NFT をミント |
|
||||||
|
| [VS Code 拡張機能を構築する](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/vscode-extension/) | テンプレート、コードチャット、複数ファイル Q&A を備えた AI プロジェクトアシスタントを構築 |
|
||||||
|
| [産業グレードの Qt デスクトップアプリを構築する](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/qt-industrial-hmi/) | トレンド、アラート、監視機能を備えたリアルタイム Qt HMI システムを作成 |
|
||||||
|
|
||||||
|
#### AI 機能 附録
|
||||||
|
|
||||||
|
| セクション | 主要コンテンツ |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [RAG とは何か、どのように機能するのか](https://datawhalechina.github.io/easy-vibe/en/stage-3/ai-advanced/rag-introduction/) | RAG の原理と一般的なアーキテクチャの体系的な理解を構築 |
|
||||||
|
| [LangGraph による中級・上級 RAG ワークフロー](https://datawhalechina.github.io/easy-vibe/en/stage-3/ai-advanced/langgraph-advanced-rag/) | マルチステップのワークフローとより高度な RAG システムを設計 |
|
||||||
|
|
||||||
|
### 📚 附録 ナレッジベース
|
||||||
|
|
||||||
|
> **9 つの主要ナレッジ領域**と **80 以上のインタラクティブトピック**をカバー。アニメーションとビジュアルコンポーネントで、コンピュータの基礎から AI の最前線までの核心概念を直感的に理解できます。
|
||||||
|
>
|
||||||
|
> 👉 [附録の全容を見る](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
### 🎓 その他のコース
|
||||||
|
|
||||||
|
- [Hands-on Modern RL](#その他のコース)
|
||||||
|
- [Learn Harness Engineering](#その他のコース)
|
||||||
|
|
||||||
|
## 🛠️ 学び方
|
||||||
|
|
||||||
|
- 自分のレベルに合ったセクションを読んで実践しましょう。行き詰まった場合は、お気軽に Issue を立ててください。
|
||||||
|
|
||||||
|
## 💻 ローカルで実行
|
||||||
|
|
||||||
|
### モダンなアプローチ
|
||||||
|
|
||||||
|
VS Code、Cursor、Trae などの AI IDE のチャットウィンドウで、次のように入力するだけ:
|
||||||
|
|
||||||
|
```text
|
||||||
|
このプロジェクトをローカルで実行するのを手伝ってください。
|
||||||
|
```
|
||||||
|
|
||||||
|
### 従来のアプローチ
|
||||||
|
|
||||||
|
1. `npm install`
|
||||||
|
2. `npm run dev`
|
||||||
|
3. ブラウザで `http://localhost:3000` を開く
|
||||||
|
|
||||||
|
## その他のコース
|
||||||
|
|
||||||
|
私たちのチームは他のコースも作成しています。ぜひチェックしてください:
|
||||||
|
|
||||||
|
[](https://github.com/walkinglabs/hands-on-modern-rl)
|
||||||
|
|
||||||
|
**Hands-on Modern RL**:基礎的な強化学習の概念から LLM アライメント、RLVR、高度なエージェントシステムまでをつなぐ、オープンソースのハンズオンカリキュラム。
|
||||||
|
|
||||||
|
[](https://github.com/walkinglabs/learn-harness-engineering/tree/main)
|
||||||
|
|
||||||
|
**Learn Harness Engineering**:ハーネスエンジニアリングの包括的なガイド。
|
||||||
|
|
||||||
|
## 🤝 貢献と貢献者
|
||||||
|
|
||||||
|
- 問題を発見したり、改善できる点があれば、お気軽に Issue を立ててください。返答がない場合は [Datawhale サポートチーム](https://github.com/datawhalechina/DOPMC/blob/main/OP.md)にご連絡ください。
|
||||||
|
- 貢献したい場合は、Pull Request を送ってください。返答がない場合は [Datawhale サポートチーム](https://github.com/datawhalechina/DOPMC/blob/main/OP.md)にご連絡ください。
|
||||||
|
- 新しい Datawhale オープンソースプロジェクトを始めたい場合は、[Datawhale オープンソースプロジェクトガイド](https://github.com/datawhalechina/DOPMC/blob/main/GUIDE.md)に従ってください。
|
||||||
|
|
||||||
|
### 🙏 貢献者
|
||||||
|
|
||||||
|
- [Sanbu - プロジェクトリーダー](https://github.com/sanbuphy)(Datawhale メンバー)
|
||||||
|
- Fang Ke - メンター(Datawhale メンバー、清華大学)
|
||||||
|
- [Yerim Kang](https://github.com/yerim25)(実践プロジェクト、清華大学)
|
||||||
|
- [Zhilin Zhao](https://github.com/ChileenZ)(実践プロジェクト、清華大学)
|
||||||
|
- [Yixuan Li](https://yixuan20.github.io/)(ビジュアルデザイン、清華大学)
|
||||||
|
- Siyi Liu(実践プロジェクト、清華大学)
|
||||||
|
- [Lixin Liu](https://github.com/liulx25xx)(実践プロジェクト、清華大学)
|
||||||
|
- AI Vibe Coding 101 内部テストグループのフィードバックを共有してくださった皆さん
|
||||||
|
|
||||||
|
### 特別な感謝
|
||||||
|
|
||||||
|
- [@Sm1les](https://github.com/Sm1les) さんのこのプロジェクトへの支援とサポートに感謝します
|
||||||
|
- フィードバックと Star でこのプロジェクトをサポートしてくださるすべての貢献者の皆さんに感謝します ❤️
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a href="https://www.star-history.com/#datawhalechina/easy-vibe&type=timeline&legend=top-left">
|
||||||
|
<picture>
|
||||||
|
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=datawhalechina/easy-vibe&type=timeline&theme=dark&legend=top-left" />
|
||||||
|
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=datawhalechina/easy-vibe&type=timeline&legend=top-left" />
|
||||||
|
</picture>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align=center style="margin-top: 30px;">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=datawhalechina/easy-vibe" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 📄 ライセンス
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
|
||||||
|
<img
|
||||||
|
alt="クリエイティブ・コモンズ・ライセンス"
|
||||||
|
style="border-width:0"
|
||||||
|
src="https://img.shields.io/badge/license-CC%20BY--NC--SA%204.0-lightgrey"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<br />
|
||||||
|
この作品は
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
|
||||||
|
クリエイティブ・コモンズ 表示 - 非営利 - 継承 4.0 国際ライセンス
|
||||||
|
</a>
|
||||||
|
の下に提供されています。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Star History
|
||||||
|
|
||||||
|
[](https://www.star-history.com/#datawhalechina/easy-vibe&type=date&legend=top-left)
|
||||||
@@ -0,0 +1,448 @@
|
|||||||
|
<!-- trigger vercel build -->
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
<img src="../../assets/easy-vibe-logo-hd.svg" alt="Easy-Vibe Logo" width="300">
|
||||||
|
|
||||||
|
<img src="../../assets/banner.png" alt="Easy-Vibe Banner" width="100%">
|
||||||
|
|
||||||
|
<p align="center" style="font-size: 1.2em; color: #666; margin: 20px 0;">
|
||||||
|
바로 시작해서 함께 vibe 해봐요. 말할 수 있으면 앱도 만들 수 있어요.<br>
|
||||||
|
<span style="font-size: 0.9em; color: #888;">直接上手,一起 vibe!会说话就会做应用。</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a href="https://trendshift.io/repositories/22079" target="_blank"><img src="https://trendshift.io/api/badge/repositories/22079" alt="datawhalechina/easy-vibe | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||||
|
|
||||||
|
<p align="center" style="font-size: 1.05em; color: #666; margin: 16px 0;">
|
||||||
|
你好 · Hello · 哈囉 · こんにちは · 안녕하세요 · Hola · Bonjour · Hallo · مرحبا · Xin chào<br>
|
||||||
|
튜토리얼 1부가 이제 10개 언어를 지원합니다. 전 세계의 친구들과 함께 coding을 시작해요!<br>
|
||||||
|
<span style="font-size: 0.9em; color: #888;">我们的教程(第一部分)已经支持 10 种语言,欢迎世界各地的朋友一起 coding!</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
🚀 <a href="https://datawhalechina.github.io/easy-vibe/welcome.html">둘러보기 시작</a> · ✨ <a href="https://datawhalechina.github.io/easy-vibe/en/appendix/">인터랙티브 튜토리얼</a> · 🦞 <a href="https://github.com/datawhalechina/hello-claw">OpenClaw 배우기</a> · 📖 <a href="#table-of-contents">목차</a><br>
|
||||||
|
<span style="font-size: 0.85em; color: #888;">🚀 <a href="https://datawhalechina.github.io/easy-vibe/welcome.html">开始体验</a> · ✨ <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/">交互式教程</a> · 🦞 <a href="https://github.com/datawhalechina/hello-claw">学习 OpenClaw</a> · 📖 <a href="#table-of-contents">查看目录</a></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://datawhalechina.github.io/easy-vibe/welcome.html">온라인으로 읽기</a> ·
|
||||||
|
<a href="#-content-navigation">학습 지도</a><br>
|
||||||
|
<span style="font-size: 0.85em; color: #888;">
|
||||||
|
<a href="https://datawhalechina.github.io/easy-vibe/welcome.html">开始阅读</a> ·
|
||||||
|
<a href="#-content-navigation">学习地图</a>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/stargazers" target="_blank">
|
||||||
|
<img src="https://img.shields.io/github/stars/datawhalechina/easy-vibe?color=660874&style=for-the-badge&logo=star&logoColor=white&labelColor=1a1a2e" alt="Stars"></a>
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/network/members" target="_blank">
|
||||||
|
<img src="https://img.shields.io/github/forks/datawhalechina/easy-vibe?color=660874&style=for-the-badge&logo=git-fork&logoColor=white&labelColor=1a1a2e" alt="Forks"></a>
|
||||||
|
<a href="../../LICENSE" target="_blank">
|
||||||
|
<img src="https://img.shields.io/badge/License-CC_BY_NC_SA_4.0-4ecdc4?style=for-the-badge&logo=creative-commons&logoColor=white&labelColor=1a1a2e" alt="License"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="../../README.md"><img alt="English" src="https://img.shields.io/badge/English-d9d9d9"></a>
|
||||||
|
<a href="../zh-CN/README.md"><img alt="简体中文" src="https://img.shields.io/badge/简体中文-d9d9d9"></a>
|
||||||
|
<a href="../zh-TW/README.md"><img alt="繁體中文" src="https://img.shields.io/badge/繁體中文-d9d9d9"></a>
|
||||||
|
<a href="../ja-JP/README.md"><img alt="日本語" src="https://img.shields.io/badge/日本語-d9d9d9"></a>
|
||||||
|
<a href="../es-ES/README.md"><img alt="Español" src="https://img.shields.io/badge/Español-d9d9d9"></a>
|
||||||
|
<a href="../fr-FR/README.md"><img alt="Français" src="https://img.shields.io/badge/Français-d9d9d9"></a>
|
||||||
|
<a href="../ko-KR/README.md"><img alt="한국어" src="https://img.shields.io/badge/한국어-d9d9d9"></a>
|
||||||
|
<a href="../ar-SA/README.md"><img alt="العربية" src="https://img.shields.io/badge/العربية-d9d9d9"></a>
|
||||||
|
<a href="../vi-VN/README.md"><img alt="Tiếng_Việt" src="https://img.shields.io/badge/Tiếng_Việt-d9d9d9"></a>
|
||||||
|
<a href="../de-DE/README.md"><img alt="Deutsch" src="https://img.shields.io/badge/Deutsch-d9d9d9"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<table align="center">
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-header.png" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>초보자 맞춤형 학습 지도</strong>
|
||||||
|
<br>
|
||||||
|
<sub>명확한 가이드로 "배우고 잊어버리는" 고리를 끊어줍니다</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-tutorial.png" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>단계별 시각 튜토리얼</strong>
|
||||||
|
<br>
|
||||||
|
<sub>개인 과외 선생님처럼 친절하게 안내하는 상세 실습 가이드</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-ide.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>몰입형 시뮬레이션 코딩</strong>
|
||||||
|
<br>
|
||||||
|
<sub>가상 마우스 가이드로 IDE 핵심 워크플로우를 빠르게 익힙니다</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-diffusion.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>눈으로 보는 AI 원리</strong>
|
||||||
|
<br>
|
||||||
|
<sub>애니메이션 해설로 AI가 이미지를 생성하는 과정을 쉽게 이해합니다</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-rag.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>게임처럼 배우는 RAG</strong>
|
||||||
|
<br>
|
||||||
|
<sub>인터랙티브 컴포넌트로 RAG 데이터 흐름을 클릭 한 번에 파악합니다</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/git-terminal.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>시각화된 터미널 개념</strong>
|
||||||
|
<br>
|
||||||
|
<sub>명령어 동작이 시각화되어 배경 원리를 직관적으로 이해합니다</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div align="center">
|
||||||
|
<h3>⭐ <a href="https://github.com/datawhalechina/easy-vibe" style="color: #d0cd16ff;">여기를 클릭하여 Star</a>를 눌러 업데이트를 가속해주세요 ❤️</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align="center" style="margin: 30px 0;">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/issues/new?template=story_submission.md">
|
||||||
|
<img src="https://raw.githubusercontent.com/datawhalechina/easy-vibe/main/assets/stories_image.png" alt="나만의 Vibe 스토리 공유하기" width="80%" style="border-radius: 10px; box-shadow: 0 4px 12px rgba(0,0,0,0.15);">
|
||||||
|
</a>
|
||||||
|
<p style="margin-top: 15px; font-size: 1.1em; color: #666;">
|
||||||
|
📝 <strong>나만의 vibe 코딩 스토리가 있나요?</strong>
|
||||||
|
여기에 공유하여 다른 사람들에게 영감을 주세요!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 목차
|
||||||
|
|
||||||
|
- [왜 Easy-Vibe인가](#왜-easy-vibe인가)
|
||||||
|
- [소식](#-소식)
|
||||||
|
- [이런 분들에게 추천합니다](#이런-분들에게-추천합니다)
|
||||||
|
- [학습 경로](#학습-경로)
|
||||||
|
- [학습 제안](#학습-제안)
|
||||||
|
- [I. 초보자 입문](#i-초보자-입문)
|
||||||
|
- [II. 주니어 및 미들 개발자](#ii-주니어-및-미들-개발자)
|
||||||
|
- [III. 시니어 개발자](#iii-시니어-개발자)
|
||||||
|
- [부록 지식 베이스](#-부록-지식-베이스)
|
||||||
|
- [학습 방법](#️-학습-방법)
|
||||||
|
- [로컬 실행](#-로컬-실행)
|
||||||
|
- [다른 강좌](#다른-강좌)
|
||||||
|
- [기여 및 기여자](#기여-및-기여자)
|
||||||
|
- [라이선스](#-라이선스)
|
||||||
|
|
||||||
|
## 왜 Easy-Vibe인가
|
||||||
|
|
||||||
|
가계부 앱이 필요하신가요? 말하면 됩니다.
|
||||||
|
|
||||||
|
위챗 로그인 예약 시스템이 필요하신가요? 말하면 됩니다.
|
||||||
|
|
||||||
|
댓글이 달리는 블로그를 만들고 싶나요? 말하면 됩니다.
|
||||||
|
|
||||||
|
AI 시대의 프로그래밍은 원하는 것을 설명하는 데서 시작합니다.
|
||||||
|
|
||||||
|
Easy-Vibe는 그것을 실제 제품으로 만드는 방법을 가르칩니다.
|
||||||
|
|
||||||
|
|
||||||
|
## 🔥 소식
|
||||||
|
|
||||||
|
- **[2026-05-20]** 🌍 **Stage 1 다국어 커버리지 완료**: Stage 1 은 지원되는 모든 언어(zh-cn, en, zh-tw, ja-jp, ko-kr, es-es, fr-fr, de-de, ar-sa, vi-vn)에서 완전하게 제공됩니다. 내비게이션/빌드 검증을 통해 404 를 방지했습니다.
|
||||||
|
- **[2026-03-29]** ✨ **Vibe 스토리 공개 및 실제 사용자 여정으로 업그레이드**: 홈페이지에 인터랙티브 스토리 캐러셀과 전용 스토리 페이지를 추가하고, 시골 초등학교 교사, 대학생, 고등학교 IT 교사, 트럭 운전사의 실제 사용자 스토리 4편으로 교체했습니다. [👉 스토리 보기](https://datawhalechina.github.io/easy-vibe/zh-cn/vibe-stories/story-1.html)
|
||||||
|
- **[2026-03-26]** 🚀 **단계 2 실습 대규모 업데이트**: SaaS 캡스톤 프로젝트 "[첫 번째 SaaS 풀스택 앱: 카피라이팅 생성기 웹사이트](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/fullstack-app/)"를 완료하고 "[Stripe 및 결제 시스템 통합 방법](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/stripe-payment/)" 섹션을 대폭 확장했으며, 멀티 프로덕트 UI 및 위챗 미니 프로그램 백엔드 워크플로우 핵심 콘텐츠를 추가했습니다.
|
||||||
|
- **[2026-03-25]** 📚 **새로운 부록: 사용자 연구 및 요구사항 검증**: 아이디어 소싱, 더블 다이아몬드 모델, Jobs to Be Done, The Mom Test를 다루는 4편의 새로운 글을 추가하여 초보자가 제품 아이디어를 발견하고 검증하는 데 도움을 줍니다. [👉 부록 읽기](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
- **[2026-03-25]** 📚 **영문 문서 전면 업데이트**: 단계 2(풀스택 개발)와 단계 3(고급 개발)이 완전히 영어로 제공됩니다. [👉 학습 시작하기](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
<details>
|
||||||
|
<summary>이전 소식</summary>
|
||||||
|
|
||||||
|
- **[2026-03-02]** 🦞 **OpenClaw 및 AI Agent 친화적 지원**: `llms.txt`를 추가하여 OpenClaw, Claude, Cursor, Trae 및 기타 AI Agent가 저장소 구조를 빠르게 이해하고 적절한 튜토리얼 콘텐츠를 찾을 수 있습니다.
|
||||||
|
- **[2026-03-01]** [고급 개발 섹션](https://datawhalechina.github.io/easy-vibe/en/stage-3/)이 Claude Code 심층 가이드(MCP, Skills, Agent Teams 등)와 8개의 크로스 플랫폼 프로젝트 튜토리얼로 포괄적으로 업그레이드되었습니다.
|
||||||
|
- **[2026-02-25]** [부록 지식 베이스](https://datawhalechina.github.io/easy-vibe/en/appendix/)가 업데이트되어 9개 지식 영역과 80개 이상의 인터랙티브 주제를 다룹니다.
|
||||||
|
- **[2026-01-27]** Android 및 iOS 앱 개발 튜토리얼이 추가되었습니다.
|
||||||
|
- **[2026-01-19]** 프롬프트 엔지니어링, AI 역사, 인증 설계, Git 원리 등을 위한 인터랙티브 데모가 출시되었습니다.
|
||||||
|
- **[2026-01-16]** 프로젝트 구조를 재구성하고 초보자 입문 경로를 공식 확립했습니다.
|
||||||
|
- **[2026-01-14]** 단계 1 제품 프로토타입 문서 대규모 업데이트를 완료했습니다.
|
||||||
|
- **[2026-01-13]** 문서 아키텍처를 리팩토링하고 다국어 지원을 완전히 활성화했습니다.
|
||||||
|
- **[2026-01-01]** 프로젝트의 핵심 학습 맵을 출시했습니다.
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## 이런 분들에게 추천합니다
|
||||||
|
|
||||||
|
- **왕초보자**: 먼저 첫 번째 프로젝트를 만들고, 작동 원리는 나중에 이해합니다
|
||||||
|
- **프로덕트 매니저 / 창업자**: 빠르게 아이디어를 검증하고 저비용으로 MVP를 만듭니다
|
||||||
|
- **학생**: AI 시대를 위한 실무 기술을 기릅니다
|
||||||
|
- **주니어 개발자**: 아이디어부터 런칭까지 전체 경로를 배웁니다
|
||||||
|
- **미들 및 시니어 개발자**: 복잡한 프로젝트를 위한 AI 협업 워크플로우를 업그레이드합니다
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 학습 경로
|
||||||
|
|
||||||
|
### 🎮 빠른 첫 성취를 원해요
|
||||||
|
**추천 대상**: 모든 사람
|
||||||
|
**학습 내용**: 간단하고 구체적인 실습 예제를 통해 AI 코딩이 실제로 어떤 느낌인지 체험합니다
|
||||||
|
**얻게 될 것**: 바이브 코딩에 대한 명확한 첫인상과 대화형 AI 작업 방법
|
||||||
|
|
||||||
|
[여기서 시작하기](https://datawhalechina.github.io/easy-vibe/en/stage-1/ai-capabilities-through-games/)
|
||||||
|
|
||||||
|
### 💡 아이디어를 제품 프로토타입으로 만들고 싶어요
|
||||||
|
**추천 대상**: 초보자 / 프로덕트 매니저 / 창업자
|
||||||
|
**학습 내용**: 학습 로드맵, AI IDE 도구, 아이디어 검증, 프로토타이핑, AI 기능 통합, 전체 데모 반복
|
||||||
|
**얻게 될 것**: 사용자나 팀원에게 실제로 보여줄 수 있는 데모 가능한 AI 제품 프로토타입
|
||||||
|
|
||||||
|
[학습 시작하기](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/)
|
||||||
|
|
||||||
|
### 🚀 엔드투엔드 풀스택 제품을 만들고 싶어요
|
||||||
|
**추천 대상**: 주니어 개발자 / 인디 해커 / 고급 학습자
|
||||||
|
**학습 내용**: 프론트엔드 워크플로우, 디자인-투-코드, 데이터베이스, 백엔드 API, 배포, 결제, 메이저 프로젝트
|
||||||
|
**얻게 될 것**: 현대적인 AI 탑재 웹 애플리케이션을 독립적으로 출시하는 능력
|
||||||
|
|
||||||
|
[학습 시작하기](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
|
||||||
|
### AI 네이티브: 고급 Claude Code 및 Agent 워크플로우를 원해요
|
||||||
|
**추천 대상**: AI 네이티브 엔지니어링에 관심 있는 개발자
|
||||||
|
**학습 내용**: Claude Code, MCP, Skills, Agent Teams, 장기 실행 작업, Spec Coding, 크로스 플랫폼 앱 제공
|
||||||
|
**얻게 될 것**: 복잡한 AI 지원 개발 및 자동화를 위한 더 강력한 워크플로우
|
||||||
|
|
||||||
|
[고급 개발로 이동](https://datawhalechina.github.io/easy-vibe/en/stage-3/)
|
||||||
|
|
||||||
|
### 📚 참고 자료와 기초 지식이 필요해요
|
||||||
|
**추천 대상**: 모든 사람
|
||||||
|
**학습 내용**: 컴퓨터 기초, 프론트엔드/백엔드 기본, 인프라, AI 원리, 엔지니어링 실무
|
||||||
|
**얻게 될 것**: 9개 주요 지식 영역을 다루는 장기 참고 지식 베이스
|
||||||
|
|
||||||
|
[지식 베이스 탐색하기](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
## 학습 제안
|
||||||
|
|
||||||
|
- 초보자, 프로덕트 매니저, 창업자라면 [단계 1](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/)부터 시작하세요
|
||||||
|
- 프로토타입에서 풀스택 제공으로 넘어가고 싶다면 [단계 2](https://datawhalechina.github.io/easy-vibe/en/stage-2/)부터 시작하세요
|
||||||
|
- 고급 Claude Code 워크플로우나 크로스 플랫폼 프로젝트를 원한다면 [단계 3](https://datawhalechina.github.io/easy-vibe/en/stage-3/)으로 이동하세요
|
||||||
|
- 개념이나 배경 지식 부족으로 막힌다면 [부록 지식 베이스](https://datawhalechina.github.io/easy-vibe/en/appendix/)를 활용하세요
|
||||||
|
|
||||||
|
### 📖 콘텐츠 내비게이션
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<img src="../../assets/readme-image1.png" alt="학습 지도" width="70%" style="border-radius: 10px; box-shadow: 0 8px 20px rgba(45,55,72,0.3); margin: 15px 0;"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
### I. 초보자 입문
|
||||||
|
|
||||||
|
| 섹션 | 핵심 내용 |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [학습 지도](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/) | 전체 학습 여정의 안내 개요 |
|
||||||
|
| [AI 시대: 말할 수 있으면 코딩할 수 있습니다](https://datawhalechina.github.io/easy-vibe/en/stage-1/ai-capabilities-through-games/) | 스네이크 게임 등 예제를 통해 AI 코딩을 처음으로 체험합니다 |
|
||||||
|
| [AI 프로그래밍 도구 마스터하기](https://datawhalechina.github.io/easy-vibe/en/stage-1/introduction-to-ai-ide/) | AI IDE 도구의 작동 방식을 배우고 간단한 로컬 프로젝트를 만듭니다 |
|
||||||
|
| [좋은 아이디어 찾기](https://datawhalechina.github.io/easy-vibe/en/stage-1/finding-great-idea/) | 만들 가치 있는 제품 아이디어를 발견하고 검증하는 방법을 배웁니다 |
|
||||||
|
| [제품 프로토타입 만들기](https://datawhalechina.github.io/easy-vibe/en/stage-1/building-prototype/) | 요구사항에서 단일 페이지 및 다중 페이지 제품 프로토타입으로 이동합니다 |
|
||||||
|
| [AI 기능 통합하기](https://datawhalechina.github.io/easy-vibe/en/stage-1/integrating-ai-capabilities/) | 텍스트, 이미지, 비디오 AI 기능을 통합합니다 |
|
||||||
|
| [완성된 프로젝트 실습](https://datawhalechina.github.io/easy-vibe/en/stage-1/complete-project-practice/) | 실제 시나리오를 시뮬레이션하고, 사용자 피드백을 수집하여 전체 프로젝트를 반복 개선합니다 |
|
||||||
|
|
||||||
|
#### 부록: 제품 및 비즈니스 사고
|
||||||
|
|
||||||
|
| 섹션 | 핵심 내용 |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [제품 사고와 솔루션 설계](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-a-product-thinking/) | 제품을 0에서 1로 만들기 위한 핵심 프레임워크 |
|
||||||
|
| [AI 산업 응용 시나리오 (B2B)](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-industry-scenarios/) | 다양한 산업에서 AI가 어떻게 활용되는지 이해합니다 |
|
||||||
|
| [AI 소비자 시나리오 인스피레이션 (B2C)](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-c-consumer-scenarios/) | 소비자 AI에서의 제품 기회를 탐색합니다 |
|
||||||
|
|
||||||
|
#### 부록: 사용자 연구 및 요구사항 검증
|
||||||
|
|
||||||
|
| 섹션 | 핵심 내용 |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [아이디어를 어디서 찾을까: 초보자에게 가장 잘 맞는 3가지 참고 소스](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-idea-sources/) | 구체적인 제품 기회를 찾기 위한 신뢰할 수 있는 파이프라인을 구축합니다 |
|
||||||
|
| [더블 다이아몬드: 먼저 올바른 일을 하고, 그 다음에 올바르게 하세요](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-double-diamond/) | 구조화된 프로세스를 통해 흩어진 영감에서 실행 가능한 방향으로 이동합니다 |
|
||||||
|
| [Jobs to Be Done으로 사용자가 진정으로 원하는 것을 찾기](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-jobs-to-be-done/) | 표면적인 기능 요청이 아닌 실제 작업을 통해 사용자 목표를 분석합니다 |
|
||||||
|
| [The Mom Test: 수요를 검증하기 위한 사용자 인터뷰 방법](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-mom-test/) | 더 나은 질문을 하는 방법을 배우고 거짓 긍정 피드백을 피합니다 |
|
||||||
|
|
||||||
|
#### 부록: 기술 솔루션
|
||||||
|
|
||||||
|
| 섹션 | 핵심 내용 |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [오류가 발생하면 어떻게 하나요](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-b-common-errors/) | 바이브 코딩의 일반적인 문제와 해결 방법 |
|
||||||
|
| [7가지 AI 프로그래밍 도구 비교](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-articles/example0-1/vibe-coding-tools-snake-game-tutorial) | 실습 테스트를 통해 주요 AI 코딩 플랫폼을 비교합니다 |
|
||||||
|
| [Agent로 웹사이트 디자인하기](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-articles/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents) | 실습에서 멀티 에이전트 협업을 배웁니다 |
|
||||||
|
|
||||||
|
### II. 주니어 및 미들 개발자
|
||||||
|
|
||||||
|
#### 프론트엔드
|
||||||
|
|
||||||
|
| 섹션 | 핵심 내용 |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [프론트엔드 0: Lovart로 나만의 에셋 제작 Agent 만들기](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/lovart-assets/) | Nanobanana와 Lovart를 사용하여 시각 에셋을 배치 생성하고 의도 인식이 가능한 드로잉 에이전트를 구축합니다 |
|
||||||
|
| [프론트엔드 1: Figma & MasterGo 기초](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/figma-mastergo/) | 디자인 초안에서 구현 가능한 UI 사고까지의 워크플로우를 배웁니다 |
|
||||||
|
| [프론트엔드 2: 첫 번째 모던 앱 만들기 - UI 디자인](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/ui-design/) | 모던 애플리케이션 인터페이스 뒤의 UI 디자인 기초를 배웁니다 |
|
||||||
|
| [프론트엔드 3: UI 가이드라인과 멀티 프로덕트 디자인](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/multi-product-ui/) | 공유 UI 규칙으로 여러 제품 전반의 일관성과 미학을 향상시킵니다 |
|
||||||
|
| [프론트엔드 4: LLM과 Skills로 인터페이스를 아름답게 만들기](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/llm-skills-beautiful/) | 프롬프트와 플러그인을 사용하여 AI가 더 세련되고 독특한 인터페이스를 생성하게 합니다 |
|
||||||
|
| [프론트엔드 4: 호그와트 초상화를 만들어봅시다](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/hogwarts-portraits/) | 처음부터 인터랙티브 AI 이미지 프론트엔드 프로젝트를 구축합니다 |
|
||||||
|
| [프론트엔드 6: 디자인 프로토타입에서 프로젝트 코드로](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/design-to-code/) | 디자인 프로토타입을 브라우저에서 실제로 실행되는 프론트엔드 코드로 변환합니다 |
|
||||||
|
| [프론트엔드 7: 모던 컴포넌트 라이브러리로 UI 업그레이드](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/modern-component-library/) | 컴포넌트 라이브러리를 사용하여 전문적인 인터페이스를 더 빠르게 구축합니다 |
|
||||||
|
|
||||||
|
#### 백엔드
|
||||||
|
|
||||||
|
| 섹션 | 핵심 내용 |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [백엔드 1: Git과 GitHub 배우기](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/git-workflow/) | Git의 핵심 버전 관리 작업과 협업 워크플로우를 마스터합니다 |
|
||||||
|
| [백엔드 2: 데이터베이스에서 Supabase까지](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/database-supabase/) | 관계형 데이터베이스 기초를 배우고 Supabase를 모던 BaaS 플랫폼으로 활용합니다 |
|
||||||
|
| [백엔드 3: 백엔드 API 설계 및 개발](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/ai-interface-code/) | AI를 활용하여 API 설계, 백엔드 코드 생성, API 문서를 작성합니다 |
|
||||||
|
| [백엔드 4: 제품 프로토타입 출시하기](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/zeabur-deployment/) | Zeabur를 사용하여 풀스택 애플리케이션을 클라우드에 빠르게 배포합니다 |
|
||||||
|
| [백엔드 5: IDE에서 CLI AI 코딩 도구까지](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/modern-cli/) | 모던 개발을 위한 터미널 우선 AI 코딩 워크플로우를 탐색합니다 |
|
||||||
|
| [백엔드 6: Stripe 및 기타 결제 시스템 통합](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/stripe-payment/) | 결제 및 청구 기능으로 수익화를 추가합니다 |
|
||||||
|
|
||||||
|
#### 메이저 프로젝트
|
||||||
|
|
||||||
|
| 섹션 | 핵심 내용 |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [메이저 프로젝트 1: 첫 번째 SaaS 풀스택 앱 - AI 카피라이팅 웹사이트](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/fullstack-app/) | 로그인, 생성, 결제, 관리자 기능이 있는 AI 마케팅 카피 워크스페이스를 구축합니다 |
|
||||||
|
| [메이저 프로젝트 2: 온라인 시험 및 관리 시스템](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/modern-frontend-trae/) | 문제 생성, 시험 응시 흐름, 관리자 도구가 있는 온라인 시험 시스템을 구축합니다 |
|
||||||
|
|
||||||
|
#### AI 기능 부록
|
||||||
|
|
||||||
|
| 섹션 | 핵심 내용 |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [AI 1: Dify 기초 및 지식 베이스 통합](https://datawhalechina.github.io/easy-vibe/en/stage-2/ai-capabilities/dify-knowledge-base/) | Dify로 AI 애플리케이션을 구축하고 프라이빗 지식 베이스를 통합하는 방법을 배웁니다 |
|
||||||
|
|
||||||
|
### III. 시니어 개발자
|
||||||
|
|
||||||
|
#### Claude Code 핵심 스킬
|
||||||
|
|
||||||
|
| 섹션 | 핵심 내용 |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Claude Code 시작하기](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/basics/) | 설치, 설정, 기본 사항 및 유용한 명령어 |
|
||||||
|
| [Claude Code MCP 가이드](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/mcp/) | MCP를 통해 Claude Code를 GitHub, 데이터베이스, API 및 기타 서비스에 연결합니다 |
|
||||||
|
| [Claude Code Skills 가이드](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/skills/) | 전문 지식을 재사용 가능한 스킬로 패키지합니다 |
|
||||||
|
| [장기 실행 작업에서 Claude Code가 계속 작동하게 하는 방법](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/long-running-tasks/) | 코딩 도구가 작업이 완료될 때까지 계속 작동하도록 장기 실행 작업을 설계합니다 |
|
||||||
|
| [Claude Agent Teams 가이드](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/agent-teams/) | 실제 개발 팀처럼 여러 AI 인스턴스를 조정합니다 |
|
||||||
|
| [엔지니어링급 개발을 위한 Claude Code 슈퍼파워](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/superpowers/) | TDD와 모범 사례를 통해 AI가 엔지니어링급 코드를 생성하도록 돕습니다 |
|
||||||
|
| [Claude Code 워크플로우 모범 사례](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/workflow/) | 리팩토링, 코드 리뷰, 일상적 개발을 위한 모범 사례 |
|
||||||
|
| [모바일에서 Claude Code 원격 개발](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/mobile-development/) | 데스크톱을 넘어 Claude Code를 사용하고 모바일 기기에서 생산적인 원격 워크플로우를 구축합니다 |
|
||||||
|
| [Claude Agent SDK 완전 가이드](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/claude-agent-sdk/) | SDK로 맞춤형 에이전트 워크플로우를 구축하고 Claude를 자체 도구에 통합합니다 |
|
||||||
|
| [바이브 코딩에서 스펙 코딩으로](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/spec-coding/) | 임시 프롬프팅에서 더 구조화되고 사양 기반의 AI 개발 워크플로우로 전환합니다 |
|
||||||
|
|
||||||
|
#### 크로스 플랫폼 개발
|
||||||
|
|
||||||
|
| 섹션 | 핵심 내용 |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [앱에 적합한 플랫폼 선택 방법](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/choose-platform/) | 앱 형태를 비교하고 사용자, 시나리오, 제공 목표에 따라 올바른 플랫폼을 선택합니다 |
|
||||||
|
| [위챗 미니 프로그램 만들기](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/wechat-miniprogram/) | 생태계를 이해하고 템플릿부터 런칭까지 프론트엔드 미니 프로그램을 제공합니다 |
|
||||||
|
| [백엔드가 포함된 위챗 미니 프로그램 만들기](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/wechat-miniprogram-backend/) | 백엔드 로직과 데이터베이스를 추가하여 전체 비즈니스 루프를 완성합니다 |
|
||||||
|
| [Android 앱 만들기](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/android-app/) | 모던 네이티브 워크플로우로 Android 앱 개발을 배웁니다 |
|
||||||
|
| [iOS 앱 만들기](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/ios-app/) | iOS 앱 개발과 Apple 생태계의 관례를 배웁니다 |
|
||||||
|
| [로컬 PWA 앱 만들기](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/pwa-local-app/) | 오프라인 지원, 푸시 알림, 설치 기능으로 웹사이트를 실제 앱으로 변환합니다 |
|
||||||
|
| [브라우저 AI 어시스턴트 확장 프로그램 만들기](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/browser-ai-extension/) | 클라우드 API 또는 내장 AI로 어떤 페이지든 요약하는 Chrome 확장 프로그램을 만듭니다 |
|
||||||
|
| [Electron 데스크톱 앱 만들기](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/electron-voice-to-text/) | Electron으로 3개 플랫폼을 위한 음성-투-텍스트 데스크톱 앱을 구축합니다 |
|
||||||
|
| [NFT를 빠르게 빌드하고 민팅하기](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/nft-minting/) | 처음부터 스마트 컨트랙트를 작성하고, 배포하고, 자신만의 NFT를 민팅합니다 |
|
||||||
|
| [VS Code 확장 프로그램 만들기](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/vscode-extension/) | 템플릿, 코드 채팅, 다중 파일 Q&A가 있는 AI 프로젝트 어시스턴트를 구축합니다 |
|
||||||
|
| [산업용 Qt 데스크톱 앱 만들기](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/qt-industrial-hmi/) | 트렌드, 알림, 모니터링이 있는 실시간 Qt HMI 시스템을 만듭니다 |
|
||||||
|
|
||||||
|
#### AI 기능 부록
|
||||||
|
|
||||||
|
| 섹션 | 핵심 내용 |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [RAG란 무엇이며 어떻게 작동하는가](https://datawhalechina.github.io/easy-vibe/en/stage-3/ai-advanced/rag-introduction/) | RAG 원리와 일반적인 아키텍처에 대한 체계적인 이해를 구축합니다 |
|
||||||
|
| [LangGraph를 활용한 중고급 RAG 워크플로우](https://datawhalechina.github.io/easy-vibe/en/stage-3/ai-advanced/langgraph-advanced-rag/) | 다단계 워크플로우와 더 고급 RAG 시스템을 설계합니다 |
|
||||||
|
|
||||||
|
### 📚 부록 지식 베이스
|
||||||
|
|
||||||
|
> **9개 주요 지식 영역**과 **80개 이상의 인터랙티브 주제**를 다루며, 애니메이션과 시각 컴포넌트를 사용하여 컴퓨터 기초부터 AI 최전선까지 핵심 개념을 직관적으로 이해할 수 있도록 돕습니다.
|
||||||
|
>
|
||||||
|
> 👉 [전체 부록 보기](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
### 🎓 다른 강좌
|
||||||
|
|
||||||
|
- [실전 모던 RL](#다른-강좌)
|
||||||
|
- [하니스 엔지니어링 배우기](#다른-강좌)
|
||||||
|
|
||||||
|
## 🛠️ 학습 방법
|
||||||
|
|
||||||
|
- 현재 수준에 맞는 섹션을 읽고 실습하세요. 막히는 부분이 있으면 언제든 이슈를 열어주세요.
|
||||||
|
|
||||||
|
## 💻 로컬 실행
|
||||||
|
|
||||||
|
### 모던 방식
|
||||||
|
|
||||||
|
VS Code, Cursor, Trae 등 AI IDE 채팅 창에서 다음과 같이 입력하세요:
|
||||||
|
|
||||||
|
```text
|
||||||
|
이 프로젝트를 로컬에서 실행해 주세요.
|
||||||
|
```
|
||||||
|
|
||||||
|
### 전통적 방식
|
||||||
|
|
||||||
|
1. `npm install`
|
||||||
|
2. `npm run dev`
|
||||||
|
3. 브라우저에서 `http://localhost:3000`을 엽니다.
|
||||||
|
|
||||||
|
## 다른 강좌
|
||||||
|
|
||||||
|
저희 팀이 만든 다른 강좌도 확인해 보세요!
|
||||||
|
|
||||||
|
[](https://github.com/walkinglabs/hands-on-modern-rl)
|
||||||
|
|
||||||
|
**실전 모던 RL**: 기본 RL 개념에서 LLM 정렬, RLVR, 고급 Agentic 시스템까지 이어주는 오픈소스 실전 커리큘럼입니다.
|
||||||
|
|
||||||
|
[](https://github.com/walkinglabs/learn-harness-engineering/tree/main)
|
||||||
|
|
||||||
|
**하니스 엔지니어링 배우기**: 하니스 엔지니어링에 대한 포괄적인 가이드입니다.
|
||||||
|
|
||||||
|
## 🤝 기여 및 기여자
|
||||||
|
|
||||||
|
- 문제를 발견하거나 개선할 수 있는 부분이 있다면 자유롭게 이슈를 열어주세요. 답변이 없으면 [Datawhale 지원 팀](https://github.com/datawhalechina/DOPMC/blob/main/OP.md)에 연락할 수도 있습니다.
|
||||||
|
- 기여하고 싶다면 풀 리퀘스트를 열어주세요. 답변이 없으면 [Datawhale 지원 팀](https://github.com/datawhalechina/DOPMC/blob/main/OP.md)에 연락할 수도 있습니다.
|
||||||
|
- 새로운 Datawhale 오픈소스 프로젝트를 시작하고 싶다면 [Datawhale 오픈소스 프로젝트 가이드](https://github.com/datawhalechina/DOPMC/blob/main/GUIDE.md)를 따르세요.
|
||||||
|
|
||||||
|
### 🙏 기여자
|
||||||
|
|
||||||
|
- [산부 - 프로젝트 리드](https://github.com/sanbuphy) (Datawhale 멤버)
|
||||||
|
- 팡커 - 멘토 (Datawhale 멤버, 칭화대학교)
|
||||||
|
- [예림 강](https://github.com/yerim25) (실습 프로젝트, 칭화대학교)
|
||||||
|
- [즈린 자오](https://github.com/ChileenZ) (실습 프로젝트, 칭화대학교)
|
||||||
|
- [이쉬안 리](https://yixuan20.github.io/) (비주얼 디자인, 칭화대학교)
|
||||||
|
- 쓰이 류 (실습 프로젝트, 칭화대학교)
|
||||||
|
- [리신 류](https://github.com/liulx25xx) (실습 프로젝트, 칭화대학교)
|
||||||
|
- AI Vibe Coding 101 내부 테스트 그룹에서 제안과 피드백을 공유한 모든 분들
|
||||||
|
|
||||||
|
### 특별 감사
|
||||||
|
|
||||||
|
- 이 프로젝트에 도움과 지원을 주신 [@Sm1les](https://github.com/Sm1les)님께 감사드립니다
|
||||||
|
- 피드백과 스타로 프로젝트를 지지해 주신 모든 기여자분들께 감사드립니다 ❤️
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a href="https://www.star-history.com/#datawhalechina/easy-vibe&type=timeline&legend=top-left">
|
||||||
|
<picture>
|
||||||
|
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=datawhalechina/easy-vibe&type=timeline&theme=dark&legend=top-left" />
|
||||||
|
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=datawhalechina/easy-vibe&type=timeline&legend=top-left" />
|
||||||
|
</picture>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align=center style="margin-top: 30px;">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=datawhalechina/easy-vibe" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 📄 라이선스
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
|
||||||
|
<img
|
||||||
|
alt="크리에이티브 커먼즈 라이선스"
|
||||||
|
style="border-width:0"
|
||||||
|
src="https://img.shields.io/badge/license-CC%20BY--NC--SA%204.0-lightgrey"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<br />
|
||||||
|
이 작업은 다음 라이선스에 따라 제공됩니다:
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
|
||||||
|
크리에이티브 커먼즈 저작자표시-비영리-동일조건변경허락 4.0 국제 라이선스
|
||||||
|
</a>.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Star History
|
||||||
|
|
||||||
|
[](https://www.star-history.com/#datawhalechina/easy-vibe&type=date&legend=top-left)
|
||||||
@@ -0,0 +1,448 @@
|
|||||||
|
<!-- trigger vercel build -->
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
<img src="../../assets/easy-vibe-logo-hd.svg" alt="Easy-Vibe Logo" width="300">
|
||||||
|
|
||||||
|
<img src="../../assets/banner.png" alt="Easy-Vibe Banner" width="100%">
|
||||||
|
|
||||||
|
<p align="center" style="font-size: 1.2em; color: #666; margin: 20px 0;">
|
||||||
|
Bat dau ngay va cung vibe nao. Chi can ban noi duoc, ban da co the lam app.<br>
|
||||||
|
<span style="font-size: 0.9em; color: #888;">直接上手,一起 vibe!会说话就会做应用。</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a href="https://trendshift.io/repositories/22079" target="_blank"><img src="https://trendshift.io/api/badge/repositories/22079" alt="datawhalechina/easy-vibe | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||||
|
|
||||||
|
<p align="center" style="font-size: 1.05em; color: #666; margin: 16px 0;">
|
||||||
|
你好 · Hello · 哈囉 · こんにちは · 안녕하세요 · Hola · Bonjour · Hallo · مرحبا · Xin chào<br>
|
||||||
|
Phần 1 của tutorial hiện đã hỗ trợ 10 ngôn ngữ. Chào mừng bạn bè khắp thế giới cùng bắt đầu coding!<br>
|
||||||
|
<span style="font-size: 0.9em; color: #888;">我们的教程(第一部分)已经支持 10 种语言,欢迎世界各地的朋友一起 coding!</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
🚀 <a href="https://datawhalechina.github.io/easy-vibe/welcome.html">Bat dau kham pha</a> · ✨ <a href="https://datawhalechina.github.io/easy-vibe/en/appendix/">Huong dan tuong tac</a> · 🦞 <a href="https://github.com/datawhalechina/hello-claw">Hoc OpenClaw</a> · 📖 <a href="#table-of-contents">Muc luc</a><br>
|
||||||
|
<span style="font-size: 0.85em; color: #888;">🚀 <a href="https://datawhalechina.github.io/easy-vibe/welcome.html">开始体验</a> · ✨ <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/">交互式教程</a> · 🦞 <a href="https://github.com/datawhalechina/hello-claw">学习 OpenClaw</a> · 📖 <a href="#table-of-contents">查看目录</a></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://datawhalechina.github.io/easy-vibe/welcome.html">Doc truc tuyen</a> ·
|
||||||
|
<a href="#-content-navigation">Lo trinh hoc</a><br>
|
||||||
|
<span style="font-size: 0.85em; color: #888;">
|
||||||
|
<a href="https://datawhalechina.github.io/easy-vibe/welcome.html">开始阅读</a> ·
|
||||||
|
<a href="#-content-navigation">学习地图</a>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/stargazers" target="_blank">
|
||||||
|
<img src="https://img.shields.io/github/stars/datawhalechina/easy-vibe?color=660874&style=for-the-badge&logo=star&logoColor=white&labelColor=1a1a2e" alt="Stars"></a>
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/network/members" target="_blank">
|
||||||
|
<img src="https://img.shields.io/github/forks/datawhalechina/easy-vibe?color=660874&style=for-the-badge&logo=git-fork&logoColor=white&labelColor=1a1a2e" alt="Forks"></a>
|
||||||
|
<a href="../../LICENSE" target="_blank">
|
||||||
|
<img src="https://img.shields.io/badge/License-CC_BY_NC_SA_4.0-4ecdc4?style=for-the-badge&logo=creative-commons&logoColor=white&labelColor=1a1a2e" alt="License"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="../../README.md"><img alt="English" src="https://img.shields.io/badge/English-d9d9d9"></a>
|
||||||
|
<a href="../zh-CN/README.md"><img alt="简体中文" src="https://img.shields.io/badge/简体中文-d9d9d9"></a>
|
||||||
|
<a href="../zh-TW/README.md"><img alt="繁體中文" src="https://img.shields.io/badge/繁體中文-d9d9d9"></a>
|
||||||
|
<a href="../ja-JP/README.md"><img alt="日本語" src="https://img.shields.io/badge/日本語-d9d9d9"></a>
|
||||||
|
<a href="../es-ES/README.md"><img alt="Español" src="https://img.shields.io/badge/Español-d9d9d9"></a>
|
||||||
|
<a href="../fr-FR/README.md"><img alt="Français" src="https://img.shields.io/badge/Français-d9d9d9"></a>
|
||||||
|
<a href="../ko-KR/README.md"><img alt="한국어" src="https://img.shields.io/badge/한국어-d9d9d9"></a>
|
||||||
|
<a href="../ar-SA/README.md"><img alt="العربية" src="https://img.shields.io/badge/العربية-d9d9d9"></a>
|
||||||
|
<a href="../vi-VN/README.md"><img alt="Tiếng_Việt" src="https://img.shields.io/badge/Tiếng_Việt-d9d9d9"></a>
|
||||||
|
<a href="../de-DE/README.md"><img alt="Deutsch" src="https://img.shields.io/badge/Deutsch-d9d9d9"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<table align="center">
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-header.png" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Lo trinh hoc cho nguoi moi</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Huong dan ro rang tu con so khong, giup ban ngung "hoc roi quen"</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-tutorial.png" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Huong dan truc quan tung buoc</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Chi tiet tung buoc nhu hoc voi gia su rieng</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-ide.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Lap trinh mo phong hap dan</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Chuot ao huong dan giup ban nhanh chong lam quen voi quy trinh IDE co ban</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-diffusion.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Nguyen ly AI co the nhin thay</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Giai thich bang hoat anh giup ban de hieu cach AI tao hinh anh</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-rag.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Hoc RAG nhu choi game</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Thanh phan tuong tac giup ban click qua toan bo luong du lieu RAG</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/git-terminal.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>Khai niem terminal truc quan</strong>
|
||||||
|
<br>
|
||||||
|
<sub>Hanh vi dong lenh tro nen truc quan khi logic ben duoi duoc hinh hoa</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div align="center">
|
||||||
|
<h3>⭐ <a href="https://github.com/datawhalechina/easy-vibe" style="color: #d0cd16ff;">Nhan Star cho repo tai day</a> de giup tang toc cap nhat ❤️</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align="center" style="margin: 30px 0;">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/issues/new?template=story_submission.md">
|
||||||
|
<img src="https://raw.githubusercontent.com/datawhalechina/easy-vibe/main/assets/stories_image.png" alt="Chia se cau chuyen Vibe cua ban" width="80%" style="border-radius: 10px; box-shadow: 0 4px 12px rgba(0,0,0,0.15);">
|
||||||
|
</a>
|
||||||
|
<p style="margin-top: 15px; font-size: 1.1em; color: #666;">
|
||||||
|
📝 <strong>Ban co cau chuyen vibe coding rieng?</strong>
|
||||||
|
Gui tai day va truyen cam hung cho nguoi khac!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Muc luc
|
||||||
|
|
||||||
|
- [Tai sao can Easy-Vibe](#tai-sao-can-easy-vibe)
|
||||||
|
- [Tin tuc](#-tin-tuc)
|
||||||
|
- [Danh cho ai](#danh-cho-ai)
|
||||||
|
- [Lo trinh hoc cua ban](#lo-trinh-hoc-cua-ban)
|
||||||
|
- [Loi khuyen hoc](#loi-khuyen-hoc)
|
||||||
|
- [I. Nhap mon nguoi moi](#i-nhap-mon-nguoi-moi)
|
||||||
|
- [II. Lap trinh vien trung cap](#ii-lap-trinh-vien-trung-cap)
|
||||||
|
- [III. Lap trinh vien cao cap](#iii-lap-trinh-vien-cao-cap)
|
||||||
|
- [Phu luc Co so kien thuc](#-phu-luc-co-so-kien-thuc)
|
||||||
|
- [Cach hoc](#️-cach-hoc)
|
||||||
|
- [Chay cuc bo](#-chay-cuc-bo)
|
||||||
|
- [Cac khoa hoc khac](#cac-khoa-hoc-khac)
|
||||||
|
- [Dong gop & Nguoi dong gop](#dong-gop--nguoi-dong-gop)
|
||||||
|
- [LICENSE](#-license)
|
||||||
|
|
||||||
|
## Tai sao can Easy-Vibe
|
||||||
|
|
||||||
|
Muon lam app ghi chep thu chi? Chi can noi ra.
|
||||||
|
|
||||||
|
Can mot he thong dat lich co dang nhap WeChat? Chi can noi ra.
|
||||||
|
|
||||||
|
Muon co blog kem binh luan? Chi can noi ra.
|
||||||
|
|
||||||
|
Trong thoi dai AI, lap trinh bat dau tu viec mo ta dieu ban muon.
|
||||||
|
|
||||||
|
Easy-Vibe giup ban bien dieu do thanh mot san pham that.
|
||||||
|
|
||||||
|
|
||||||
|
## 🔥 Tin tuc
|
||||||
|
|
||||||
|
- **[2026-05-20]** 🌍 **Da phu toan bo da ngon ngu cho Stage 1**: Stage 1 hien da co day du tren tat ca cac ngon ngu ho tro (zh-cn, en, zh-tw, ja-jp, ko-kr, es-es, fr-fr, de-de, ar-sa, vi-vn). Da kiem tra dieu huong/build de tranh 404.
|
||||||
|
- **[2026-03-29]** ✨ **Ra mat muc cau chuyen nguoi dung va nang cap voi nhung hanh trinh nguoi dung that**: Da them phan Vibe Stories moi tren trang chu voi carousel tuong tac va cac trang story rieng, sau do thay the noi dung tam bang bon cau chuyen that tu mot giao vien tieu hoc vung que, mot sinh vien dai hoc, mot giao vien CNTT trung hoc va mot tai xe xe tai da xay dung san pham that voi AI. [👉 Xem cau chuyen](https://datawhalechina.github.io/easy-vibe/zh-cn/vibe-stories/story-1.html)
|
||||||
|
- **[2026-03-26]** 🚀 **Cap nhat thuc hanh Giai doan 2 lon**: Hoan thanh du an SaaS tot nghiep "[Ung dung Full-stack SaaS dau tien: Trang web tao noi dung](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/fullstack-app/)" va mo rang dang ke phan "[Cach tich hop Stripe va he thong thanh toan](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/stripe-payment/)", cung nhu noi dung quan trong ve UI da san pham va quy trinh backend WeChat Mini Program.
|
||||||
|
- **[2026-03-25]** 📚 **Phu luc moi: Nghien cuu nguoi dung va Xac thuc yeu cau**: Them bon bai viet moi ve tim kiem y tuong, mo hinh Double Diamond, Jobs to Be Done va The Mom Test giup nguoi moi bat dau kham pha va xac thuc y tuong san pham. [👉 Doc phu luc](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
- **[2026-03-25]** 📚 **Tai lieu tieng Anh duoc cap nhat day du**: Giai doan 2 (Phat trien full-stack) va Giai doan 3 (Phat trien nang cao) hien da co day du bang tieng Anh. [👉 Bat dau hoc](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
<details>
|
||||||
|
<summary>Tin tuc truoc day</summary>
|
||||||
|
|
||||||
|
- **[2026-03-02]** 🦞 **Ho tro than thien cho OpenClaw va AI Agent**: Da them `llms.txt` de OpenClaw, Claude, Cursor, Trae va cac AI Agent khac co the nhanh chong hieu cau truc kho luu tru va tim dung noi dung huong dan.
|
||||||
|
- **[2026-03-01]** Phan [Phat trien Nang cao](https://datawhalechina.github.io/easy-vibe/en/stage-3/) da duoc nang cap toan dien voi huong dan sau ve Claude Code, bao gom MCP, Skills, Agent Teams va hon the nua, cung voi tam huong dan du an da nen tang.
|
||||||
|
- **[2026-02-25]** Cap nhat [Co so kien thuc Phu luc](https://datawhalechina.github.io/easy-vibe/en/appendix/), hien bao gom 9 linh vuc kien thuc va hon 80 chu de tuong tac.
|
||||||
|
- **[2026-01-27]** Them huong dan phat trien ung dung Android va iOS.
|
||||||
|
- **[2026-01-19]** Phat hanh cac ban demo tuong tac cho Prompt Engineering, lich su AI, thiet ke xac thuc, nguyen ly Git va hon the nua.
|
||||||
|
- **[2026-01-16]** Tai cau truc cau truc du an va thiet lap chinh thuc lo trinh nhap mon cho nguoi moi.
|
||||||
|
- **[2026-01-14]** Hoan thanh cap nhat lon cho tai lieu xay dung nguyen mau san pham Giai doan 1.
|
||||||
|
- **[2026-01-13]** Tai cau truc kien truc tai lieu va kich hoat day du ho tro da ngon ngu.
|
||||||
|
- **[2026-01-01]** Phat hanh ban do hoc tap cot loi cua du an.
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## Danh cho ai
|
||||||
|
|
||||||
|
- **Nguoi moi bat dau hoan toan**: Lam san pham dau tien truoc, roi hieu cach no hoat dong
|
||||||
|
- **Quan ly san pham / nguoi khoi nghiep**: Xac thuc y tuong nhanh va xay dung MVP voi chi phi thap
|
||||||
|
- **Hoc sinh, sinh vien**: Phat trien ky nang thuc te cho thoi dai AI
|
||||||
|
- **Lap trinh vien junior**: Hoc toan bo lo trinh tu y tuong den san pham that
|
||||||
|
- **Lap trinh vien trung va cao cap**: Nang cap quy trinh lam viec voi AI cho cac du an phuc tap
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Lo trinh hoc cua ban
|
||||||
|
|
||||||
|
### 🎮 Toi muon trai nghiem nhanh
|
||||||
|
**Phu hop voi**: Moi nguoi
|
||||||
|
**Ban se hoc**: Cam giac thuc su ve AI coding qua mot vi du thuc hanh don gian, cu the
|
||||||
|
**Ban se nhan duoc**: An tuong dau tien ro rang ve vibe coding va cach lam viec voi AI thong qua hoi thoai
|
||||||
|
|
||||||
|
[Bat dau tai day](https://datawhalechina.github.io/easy-vibe/en/stage-1/ai-capabilities-through-games/)
|
||||||
|
|
||||||
|
### 💡 Toi muon bien y tuong thanh nguyen mau san pham
|
||||||
|
**Phu hop voi**: Nguoi moi / quan ly san pham / nguoi khoi nghiep
|
||||||
|
**Ban se hoc**: Lo trinh hoc, cong cu AI IDE, xac thuc y tuong, tao nguyen mau, tich hop kha nang AI va lap day du demo
|
||||||
|
**Ban se nhan duoc**: Mot nguyen mau san pham AI co the trinh bay cho nguoi dung hoac dong doi
|
||||||
|
|
||||||
|
[Bat dau hoc](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/)
|
||||||
|
|
||||||
|
### 🚀 Toi muon xay dung san pham full-stack tron ven
|
||||||
|
**Phu hop voi**: Lap trinh vien junior / indie hacker / nguoi hoc nang cao
|
||||||
|
**Ban se hoc**: Quy trinh frontend, design-to-code, co so du lieu, backend API, trien khai, thanh toan va du an lon
|
||||||
|
**Ban se nhan duoc**: Kha nang doc lap trien khai ung dung web AI hien dai
|
||||||
|
|
||||||
|
[Bat dau hoc](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
|
||||||
|
### AI-Native: Toi muon quy trinh Claude Code va agent nang cao
|
||||||
|
**Phu hop voi**: Lap trinh vien quan tam den ky thuat AI-native
|
||||||
|
**Ban se hoc**: Claude Code, MCP, Skills, Agent Teams, tac vu chay dai, Spec Coding va giao phan ung dung da nen tang
|
||||||
|
**Ban se nhan duoc**: Quy trinh manh me hon cho phat trien co tro giup AI va tu dong hoa
|
||||||
|
|
||||||
|
[Den phat trien nang cao](https://datawhalechina.github.io/easy-vibe/en/stage-3/)
|
||||||
|
|
||||||
|
### 📚 Toi muon tai lieu tham khao va kien thuc co ban
|
||||||
|
**Phu hop voi**: Moi nguoi
|
||||||
|
**Ban se hoc**: Co ban tin hoc, co ban frontend/backend, ha tang, nguyen ly AI va thuc tien ky thuat
|
||||||
|
**Ban se nhan duoc**: Co so tai lieu tham khao dai han bao gom 9 linh vuc kien thuc lon
|
||||||
|
|
||||||
|
[Duyet co so kien thuc](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
## Loi khuyen hoc
|
||||||
|
|
||||||
|
- Neu ban la nguoi moi, quan ly san pham hoac nguoi khoi nghiep, bat dau voi [Giai doan 1](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/)
|
||||||
|
- Neu ban muon chuyen tu nguyen mau sang trien khai full-stack, bat dau voi [Giai doan 2](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
- Neu ban muon quy trinh Claude Code nang cao hoac du an da nen tang, den [Giai doan 3](https://datawhalechina.github.io/easy-vibe/en/stage-3/)
|
||||||
|
- Neu ban bi chan boi khai niem hoac thieu kien thuc nen tang, su dung [Phu luc Co so kien thuc](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
### 📖 Dieu huong noi dung
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<img src="../../assets/readme-image1.png" alt="Lo trinh hoc" width="70%" style="border-radius: 10px; box-shadow: 0 8px 20px rgba(45,55,72,0.3); margin: 15px 0;"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
### I. Nhap mon nguoi moi
|
||||||
|
|
||||||
|
| Phan | Noi dung chinh |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Ban do hoc tap](https://datawhalechina.github.io/easy-vibe/en/stage-1/learning-map/) | Tong quan huong dan toan bo hanh trinh hoc |
|
||||||
|
| [Thoi dai AI: Biet noi la biet code](https://datawhalechina.github.io/easy-vibe/en/stage-1/ai-capabilities-through-games/) | Cam nhan dau tien ve AI coding qua cac vi du nhu Snake |
|
||||||
|
| [Lam chu cong cu lap trinh AI](https://datawhalechina.github.io/easy-vibe/en/stage-1/introduction-to-ai-ide/) | Hoc cach hoat dong cua cac cong cu AI IDE va xay dung du an cuc bo don gian |
|
||||||
|
| [Tim y tuong hay](https://datawhalechina.github.io/easy-vibe/en/stage-1/finding-great-idea/) | Hoc cach kham pha va xac thuc y tuong san pham dang lam |
|
||||||
|
| [Xay dung nguyen mau san pham](https://datawhalechina.github.io/easy-vibe/en/stage-1/building-prototype/) | Di tu yeu cau den nguyen mau san pham mot trang va nhieu trang |
|
||||||
|
| [Tich hop kha nang AI](https://datawhalechina.github.io/easy-vibe/en/stage-1/integrating-ai-capabilities/) | Tich hop tinh nang AI van ban, hinh anh va video |
|
||||||
|
| [Thuc hanh du an hoan chinh](https://datawhalechina.github.io/easy-vibe/en/stage-1/complete-project-practice/) | Mo phong tinh huong that, thu thap phan hoi nguoi dung va lap du an hoan chinh |
|
||||||
|
|
||||||
|
#### Phu luc: Tu duy san pham va kinh doanh
|
||||||
|
|
||||||
|
| Phan | Noi dung chinh |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Tu duy san pham va thiet ke phuong an](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-a-product-thinking/) | Khung tu duy co ban tu khong den mot voi san pham |
|
||||||
|
| [Cac kich ban ung dung AI trong nganh (B2B)](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-industry-scenarios/) | Hieu cach AI duoc ung dung trong cac nganh nghe |
|
||||||
|
| [Cam hung kich ban tieu dung AI (B2C)](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-c-consumer-scenarios/) | Kham pha co hoi san pham trong AI tieu dung |
|
||||||
|
|
||||||
|
#### Phu luc: Nghien cuu nguoi dung va Xac thuc yeu cau
|
||||||
|
|
||||||
|
| Phan | Noi dung chinh |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Tim y tuong o dau: 3 nguon tham khao tot nhat cho nguoi moi](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-idea-sources/) | Xay dung luong thong tin tin cay de tim co hoi san pham cu the |
|
||||||
|
| [Double Diamond: Lam dung truoc, roi lam tot](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-double-diamond/) | Su dung quy trinh co cau truc de di tu cam hung lac long den huong kha thi |
|
||||||
|
| [Dung Jobs to Be Done de tim dieu nguoi dung thuc su muon](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-jobs-to-be-done/) | Phan tich muc tieu nguoi dung qua nhiem vu that thay vi yeu cau tinh nang be mat |
|
||||||
|
| [The Mom Test: Phuong phong phong van de xac thuc nhu cau](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-mom-test/) | Hoc cach hoi cau hoi tot hon va tranh phan hoi sai tich cuc |
|
||||||
|
|
||||||
|
#### Phu luc: Giai phap ky thuat
|
||||||
|
|
||||||
|
| Phan | Noi dung chinh |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Lam gi khi gap loi](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-b-common-errors/) | Cac van de vibe coding thuong gap va cach khac phuc |
|
||||||
|
| [So sanh bay cong cu lap trinh AI](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-articles/example0-1/vibe-coding-tools-snake-game-tutorial) | So sanh cac nen tang AI coding chinh qua thu nghiem thuc hanh |
|
||||||
|
| [Thiet ke website voi Agents](https://datawhalechina.github.io/easy-vibe/en/stage-1/appendix-articles/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents) | Hoc hop tac da agent trong thuc hanh |
|
||||||
|
|
||||||
|
### II. Lap trinh vien trung cap
|
||||||
|
|
||||||
|
#### Frontend
|
||||||
|
|
||||||
|
| Phan | Noi dung chinh |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Frontend 0: Xay dung Agent san xuat tai san cua rieng ban voi Lovart](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/lovart-assets/) | Su dung Nanobanana va Lovart de tao hang loat tai san truc quan va xay dung agent ve voi nhan dien y dich |
|
||||||
|
| [Frontend 1: Co ban Figma & MasterGo](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/figma-mastergo/) | Hoc quy trinh tu ban thiet ke den tu duy UI chuan bi trien khai |
|
||||||
|
| [Frontend 2: Xay dung ung dung hien dai dau tien - Thiet ke UI](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/ui-design/) | Hoc nen tang thiet ke UI phia sau giao dien ung dung hien dai |
|
||||||
|
| [Frontend 3: Huong dan UI va Thiet ke da san pham](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/multi-product-ui/) | Cai thien tinh nhat quan va tham my tren nhieu san pham voi quy tac UI chung |
|
||||||
|
| [Frontend 4: Lam giao dien dep voi LLM va Skills](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/llm-skills-beautiful/) | Su dung prompt va plugin de AI tao giao dien tinh te va doc dao hon |
|
||||||
|
| [Frontend 4: Cung xay dung Chân dung Hogwarts](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/hogwarts-portraits/) | Xay dung du an frontend AI-hinh anh tuong tac tu dau |
|
||||||
|
| [Frontend 6: Tu nguyen mau thiet ke den ma du an](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/design-to-code/) | Bien nguyen mau thiet ke thanh ma frontend co the chay that trong trinh duyet |
|
||||||
|
| [Frontend 7: Nang cap UI voi thu vien thanh phan hien dai](https://datawhalechina.github.io/easy-vibe/en/stage-2/frontend/modern-component-library/) | Su dung thu vien thanh phan de xay dung giao dien chuyen nghiep nhanh hon |
|
||||||
|
|
||||||
|
#### Backend
|
||||||
|
|
||||||
|
| Phan | Noi dung chinh |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Backend 1: Hoc Git va GitHub](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/git-workflow/) | Lam chu cac thao tac dieu khien phien ban va quy trinh hop tac voi Git |
|
||||||
|
| [Backend 2: Tu Co so du lieu den Supabase](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/database-supabase/) | Hoc co ban co so du lieu quan he va su dung Supabase nhu nen tang BaaS hien dai |
|
||||||
|
| [Backend 3: Thiet ke va Phat trien Backend API](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/ai-interface-code/) | Su dung AI ho tro thiet ke API, tao ma backend va tai lieu API |
|
||||||
|
| [Backend 4: Trien khai nguyen mau san pham cua ban](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/zeabur-deployment/) | Trien khai nhanh ung dung full-stack len may chu voi Zeabur |
|
||||||
|
| [Backend 5: Tu IDE den Cong cu AI Coding CLI](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/modern-cli/) | Kham pha quy trinh AI coding dau tien terminal cho phat trien hien dai |
|
||||||
|
| [Backend 6: Tich hop Stripe va cac He thong Thanh toan khac](https://datawhalechina.github.io/easy-vibe/en/stage-2/backend/stripe-payment/) | Them kha nang thanh toan voi tinh nang thanh toan va hoa don |
|
||||||
|
|
||||||
|
#### Du an lon
|
||||||
|
|
||||||
|
| Phan | Noi dung chinh |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Du an lon 1: Ung dung Full-stack SaaS dau tien - Trang web tao noi dung AI](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/fullstack-app/) | Xay dung khong gian lam viec AI marketing copy voi dang nhap, tao, thanh toan va quan ly admin |
|
||||||
|
| [Du an lon 2: He thong Ky thi va Quan ly truc tuyen](https://datawhalechina.github.io/easy-vibe/en/stage-2/assignments/modern-frontend-trae/) | Xay dung he thong ky thi truc tuyen voi tao cau hoi, quy trinh lam bai va cong cu admin |
|
||||||
|
|
||||||
|
#### Phu luc Kha nang AI
|
||||||
|
|
||||||
|
| Phan | Noi dung chinh |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [AI 1: Co ban Dify & Tich hop Co so kien thuc](https://datawhalechina.github.io/easy-vibe/en/stage-2/ai-capabilities/dify-knowledge-base/) | Hoc xay dung ung dung AI voi Dify va tich hop co so kien thuc rieng |
|
||||||
|
|
||||||
|
### III. Lap trinh vien cao cap
|
||||||
|
|
||||||
|
#### Ky nang cot loi Claude Code
|
||||||
|
|
||||||
|
| Phan | Noi dung chinh |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Bat dau voi Claude Code](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/basics/) | Cai dat, thiet lap, co ban va lenh huu ich |
|
||||||
|
| [Huong dan Claude Code MCP](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/mcp/) | Ket noi Claude Code voi GitHub, co so du lieu, API va cac dich vu khac thong qua MCP |
|
||||||
|
| [Huong dan Claude Code Skills](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/skills/) | Dong goi chuyen mon thanh ky nang tai su dung dung lai nhieu lan |
|
||||||
|
| [Cach giu Claude Code lam viec voi tac vu chay dai](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/long-running-tasks/) | Thiet ke tac vu chay dai de cong cu coding co the tiep tuc lam viec cho den khi xong |
|
||||||
|
| [Huong dan Claude Agent Teams](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/agent-teams/) | Phoi hop nhieu instance AI nhu mot doi ngu phat trien that |
|
||||||
|
| [Claude Code Superpowers cho phat trien cap ky thuat](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/superpowers/) | Giup AI tao ma cap ky thuat voi TDD va best practices |
|
||||||
|
| [Best practices quy trinh Claude Code](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/workflow/) | Best practices cho refactor, code review va phat trien hang ngay |
|
||||||
|
| [Phat trien tu xa Claude Code tren di dong](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/mobile-development/) | Su dung Claude Code vuot ra ngoai desktop va xay dung quy trinh lam viec tu xa hieu qua tren thiet bi di dong |
|
||||||
|
| [Huong dan day du Claude Agent SDK](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/claude-agent-sdk/) | Xay dung quy trinh agent tuy chinh va tich hop Claude vao cong cu cua rieng ban voi SDK |
|
||||||
|
| [Tu vibe coding den spec coding](https://datawhalechina.github.io/easy-vibe/en/stage-3/core-skills/spec-coding/) | Chuyen tu prompt ad-hoc sang quy trinh phat trien AI co cau truc va huong quy cach hon |
|
||||||
|
|
||||||
|
#### Phat trien da nen tang
|
||||||
|
|
||||||
|
| Phan | Noi dung chinh |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [Cach chon nen tang phu hop cho ung dung cua ban](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/choose-platform/) | So sanh cac hinh thuc ung dung va chon nen tang phu hop dua tren nguoi dung, tinh huong va muc tieu giao pho |
|
||||||
|
| [Xay dung WeChat Mini Program](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/wechat-miniprogram/) | Hieu he sinh thai va giao pho mini program frontend tu template den ra mat |
|
||||||
|
| [Xay dung WeChat Mini Program voi backend](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/wechat-miniprogram-backend/) | Them logic backend va co so du lieu de hoan thanh vong lap kinh doanh day du |
|
||||||
|
| [Xay dung ung dung Android](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/android-app/) | Hoc phat trien ung dung Android voi quy trinh native hien dai |
|
||||||
|
| [Xay dung ung dung iOS](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/ios-app/) | Hoc phat trien ung dung iOS va cac quy uoc cua he sinh thai Apple |
|
||||||
|
| [Xay dung ung dung PWA cuc bo](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/pwa-local-app/) | Bien website thanh ung dung that voi ho tro offline, push va cai dat |
|
||||||
|
| [Xay dung tien ich tro ly AI trinh duyet](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/browser-ai-extension/) | Tao tien ich Chrome tom tat bat ky trang nao voi cloud API hoac AI tich hop |
|
||||||
|
| [Xay dung ung dung desktop Electron](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/electron-voice-to-text/) | Xay dung ung dung chuyen giong noi thanh van ban bang Electron cho ba nen tang |
|
||||||
|
| [Nhanh chong xay dung va dap NFT](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/nft-minting/) | Viet smart contract tu dau, trien khai va dap NFT rieng cua ban |
|
||||||
|
| [Xay dung tien ich mo rong VS Code](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/vscode-extension/) | Xay dung tro ly du an AI voi template, code chat va hoi dap da file |
|
||||||
|
| [Xay dung ung dung desktop Qt cap cong nghiep](https://datawhalechina.github.io/easy-vibe/en/stage-3/cross-platform/qt-industrial-hmi/) | Tao he thong Qt HMI thoi gian that voi xu huong, canh bao va giam sat |
|
||||||
|
|
||||||
|
#### Phu luc Kha nang AI
|
||||||
|
|
||||||
|
| Phan | Noi dung chinh |
|
||||||
|
| :------ | :---------- |
|
||||||
|
| [RAG la gi va no hoat dong nhu the nao](https://datawhalechina.github.io/easy-vibe/en/stage-3/ai-advanced/rag-introduction/) | Xay dung hieu biet he thong ve nguyen ly RAG va cac kien truc thuong gap |
|
||||||
|
| [Quy trinh RAG trung va cao cap voi LangGraph](https://datawhalechina.github.io/easy-vibe/en/stage-3/ai-advanced/langgraph-advanced-rag/) | Thiet ke quy trinh da buoc va he thong RAG nang cao hon |
|
||||||
|
|
||||||
|
### 📚 Phu luc Co so kien thuc
|
||||||
|
|
||||||
|
> Bao gom **9 linh vuc kien thuc lon** va **hon 80 chu de tuong tac**, phu luc nay su dung hoat anh va thanh phan truc quan giup ban hieu truc quan cac khai niem co ban tu co ban tin hoc den tien tien AI.
|
||||||
|
>
|
||||||
|
> 👉 [Xem phu luc day du](https://datawhalechina.github.io/easy-vibe/en/appendix/)
|
||||||
|
|
||||||
|
### 🎓 Cac khoa hoc khac
|
||||||
|
|
||||||
|
- [Hands-on Modern RL](#cac-khoa-hoc-khac)
|
||||||
|
- [Learn Harness Engineering](#cac-khoa-hoc-khac)
|
||||||
|
|
||||||
|
## 🛠️ Cach hoc
|
||||||
|
|
||||||
|
- Doc va thuc hanh cac phan phu hop voi trinh do hien tai cua ban. Neu ban gap kho khan, cu thoai mai mo issue.
|
||||||
|
|
||||||
|
## 💻 Chay cuc bo
|
||||||
|
|
||||||
|
### Phuong phap hien dai
|
||||||
|
|
||||||
|
Trong cua so chat AI IDE nhu VS Code, Cursor hoac Trae, ban chi can noi:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Xin giup toi chay du an nay cuc bo.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phuong phap truyen thong
|
||||||
|
|
||||||
|
1. `npm install`
|
||||||
|
2. `npm run dev`
|
||||||
|
3. Mo `http://localhost:3000` trong trinh duyet cua ban.
|
||||||
|
|
||||||
|
## Cac khoa hoc khac
|
||||||
|
|
||||||
|
Nhom chung toi cung da tao cac khoa hoc khac! Kham pha ngay:
|
||||||
|
|
||||||
|
[](https://github.com/walkinglabs/hands-on-modern-rl)
|
||||||
|
|
||||||
|
**Hands-on Modern RL**: Mot chuong trinh hoc thu cong ma nguon mo, noi cau khoang cach tu co ban RL den LLM alignment, RLVR va cac he thong Agentic nang cao.
|
||||||
|
|
||||||
|
[](https://github.com/walkinglabs/learn-harness-engineering/tree/main)
|
||||||
|
|
||||||
|
**Learn Harness Engineering**: Huong dan toan dien ve harness engineering.
|
||||||
|
|
||||||
|
## 🤝 Dong gop & Nguoi dong gop
|
||||||
|
|
||||||
|
- Neu ban tim thay van de hoac thay dieu gi co the cai thien, cu thoai mai mo issue. Neu khong ai tra loi, ban cung co the lien he [doi ngu ho tro Datawhale](https://github.com/datawhalechina/DOPMC/blob/main/OP.md).
|
||||||
|
- Neu ban muon dong gop, mo pull request. Neu khong ai tra loi, ban cung co the lien he [doi ngu ho tro Datawhale](https://github.com/datawhalechina/DOPMC/blob/main/OP.md).
|
||||||
|
- Neu ban muon bat dau du an ma nguon mo Datawhale moi, vui long lam theo [Huong dan Du an Ma nguon mo Datawhale](https://github.com/datawhalechina/DOPMC/blob/main/GUIDE.md).
|
||||||
|
|
||||||
|
### 🙏 Nguoi dong gop
|
||||||
|
|
||||||
|
- [Sanbu - Truong du an](https://github.com/sanbuphy) (Thanh vien Datawhale)
|
||||||
|
- Fang Ke - Menh hoat (Thanh vien Datawhale, Dai hoc Tsinghua)
|
||||||
|
- [Yerim Kang](https://github.com/yerim25) (Du an thuc hanh, Dai hoc Tsinghua)
|
||||||
|
- [Zhilin Zhao](https://github.com/ChileenZ) (Du an thuc hanh, Dai hoc Tsinghua)
|
||||||
|
- [Yixuan Li](https://yixuan20.github.io/) (Thiet ke truc quan, Dai hoc Tsinghua)
|
||||||
|
- Siyi Liu (Du an thuc hanh, Dai hoc Tsinghua)
|
||||||
|
- [Lixin Liu](https://github.com/liulx25xx) (Du an thuc hanh, Dai hoc Tsinghua)
|
||||||
|
- Moi nguoi trong nhom thu nghiem noi bo AI Vibe Coding 101 da chia se y kien va phan hoi
|
||||||
|
|
||||||
|
### Cam on dac biet
|
||||||
|
|
||||||
|
- Cam on [@Sm1les](https://github.com/Sm1les) da giup do va ho tro du an nay
|
||||||
|
- Cam on moi nguoi dong gop va tat ca nhung nguoi da ho tro du an bang phan hoi va star ❤️
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a href="https://www.star-history.com/#datawhalechina/easy-vibe&type=timeline&legend=top-left">
|
||||||
|
<picture>
|
||||||
|
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=datawhalechina/easy-vibe&type=timeline&theme=dark&legend=top-left" />
|
||||||
|
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=datawhalechina/easy-vibe&type=timeline&legend=top-left" />
|
||||||
|
</picture>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align=center style="margin-top: 30px;">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=datawhalechina/easy-vibe" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 📄 LICENSE
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
|
||||||
|
<img
|
||||||
|
alt="Creative Commons License"
|
||||||
|
style="border-width:0"
|
||||||
|
src="https://img.shields.io/badge/license-CC%20BY--NC--SA%204.0-lightgrey"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<br />
|
||||||
|
Tac pham nay duoc cap phep duoi
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
|
||||||
|
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
|
||||||
|
</a>.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Lich su Star
|
||||||
|
|
||||||
|
[](https://www.star-history.com/#datawhalechina/easy-vibe&type=date&legend=top-left)
|
||||||
@@ -0,0 +1,522 @@
|
|||||||
|
<!-- trigger vercel build -->
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
<img src="../../assets/easy-vibe-logo-hd.svg" alt="Easy-Vibe Logo" width="300">
|
||||||
|
|
||||||
|
<img src="../../assets/banner.png" alt="Easy-Vibe Banner" width="100%">
|
||||||
|
|
||||||
|
<p align="center" style="font-size: 1.2em; color: #666; margin: 20px 0;">
|
||||||
|
直接上手,一起 vibe!会说话就会做应用。<br>
|
||||||
|
<span style="font-size: 0.9em; color: #888;">Jump right in and vibe together — if you can talk, you can build apps.</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a href="https://trendshift.io/repositories/22079" target="_blank"><img src="https://trendshift.io/api/badge/repositories/22079" alt="datawhalechina/easy-vibe | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||||
|
|
||||||
|
<p align="center" style="font-size: 1.05em; color: #666; margin: 16px 0;">
|
||||||
|
你好 · Hello · 哈囉 · こんにちは · 안녕하세요 · Hola · Bonjour · Hallo · مرحبا · Xin chào<br>
|
||||||
|
我们的教程(第一部分)已经支持 10 种语言,欢迎世界各地的朋友一起 coding!<br>
|
||||||
|
<span style="font-size: 0.9em; color: #888;">Stage 1 of our tutorial is now available in 10 languages. Friends around the world, let's start coding together!</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
🚀 <a href="https://datawhalechina.github.io/easy-vibe/welcome.html">开始体验</a> · ✨ <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/">交互式教程</a> · 🦞 <a href="https://github.com/datawhalechina/hello-claw">学习 OpenClaw</a> · 📖 <a href="#目录--table-of-contents">查看目录</a><br>
|
||||||
|
<span style="font-size: 0.85em; color: #888;">🚀 <a href="https://datawhalechina.github.io/easy-vibe/welcome.html">Start Exploring</a> · ✨ <a href="https://datawhalechina.github.io/easy-vibe/en/appendix/">Interactive Tutorial</a> · 🦞 <a href="https://github.com/datawhalechina/hello-claw">Learn OpenClaw</a> · 📖 <a href="#目录--table-of-contents">Table of Contents</a></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://datawhalechina.github.io/easy-vibe/welcome.html">开始阅读</a> ·
|
||||||
|
<a href="#-内容导航">学习地图</a><br>
|
||||||
|
<span style="font-size: 0.85em; color: #888;">
|
||||||
|
<a href="https://datawhalechina.github.io/easy-vibe/welcome.html">Read Online</a> ·
|
||||||
|
<a href="#-content-navigation">Learning Map</a>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/stargazers" target="_blank">
|
||||||
|
<img src="https://img.shields.io/github/stars/datawhalechina/easy-vibe?color=660874&style=for-the-badge&logo=star&logoColor=white&labelColor=1a1a2e" alt="Stars"></a>
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/network/members" target="_blank">
|
||||||
|
<img src="https://img.shields.io/github/forks/datawhalechina/easy-vibe?color=660874&style=for-the-badge&logo=git-fork&logoColor=white&labelColor=1a1a2e" alt="Forks"></a>
|
||||||
|
<a href="../../LICENSE" target="_blank">
|
||||||
|
<img src="https://img.shields.io/badge/License-CC_BY_NC_SA_4.0-4ecdc4?style=for-the-badge&logo=creative-commons&logoColor=white&labelColor=1a1a2e" alt="License"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="../zh-CN/README.md"><img alt="简体中文" src="https://img.shields.io/badge/简体中文-d9d9d9"></a>
|
||||||
|
<a href="../zh-TW/README.md"><img alt="繁體中文" src="https://img.shields.io/badge/繁體中文-d9d9d9"></a>
|
||||||
|
<a href="../en-US/README.md"><img alt="English" src="https://img.shields.io/badge/English-d9d9d9"></a>
|
||||||
|
<a href="../ja-JP/README.md"><img alt="日本語" src="https://img.shields.io/badge/日本語-d9d9d9"></a>
|
||||||
|
<a href="../es-ES/README.md"><img alt="Español" src="https://img.shields.io/badge/Español-d9d9d9"></a>
|
||||||
|
<a href="../fr-FR/README.md"><img alt="Français" src="https://img.shields.io/badge/Français-d9d9d9"></a>
|
||||||
|
<a href="../ko-KR/README.md"><img alt="한국어" src="https://img.shields.io/badge/한국어-d9d9d9"></a>
|
||||||
|
<a href="../ar-SA/README.md"><img alt="العربية" src="https://img.shields.io/badge/العربية-d9d9d9"></a>
|
||||||
|
<a href="../vi-VN/README.md"><img alt="Tiếng_Việt" src="https://img.shields.io/badge/Tiếng_Việt-d9d9d9"></a>
|
||||||
|
<a href="../de-DE/README.md"><img alt="Deutsch" src="https://img.shields.io/badge/Deutsch-d9d9d9"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<table align="center">
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-header.png" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>新手专属学习地图</strong>
|
||||||
|
<br>
|
||||||
|
<sub>零基础专属指引,清晰规划路径,告别“学了忘”</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-tutorial.png" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>手把手图文教程</strong>
|
||||||
|
<br>
|
||||||
|
<sub>保姆级图文详解,如同私教在旁,跟着做就能学会</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-ide.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>沉浸式模拟编程</strong>
|
||||||
|
<br>
|
||||||
|
<sub>虚拟鼠标自动导览,带你快速上手 IDE 核心用法</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-diffusion.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>看得见的 AI 原理</strong>
|
||||||
|
<br>
|
||||||
|
<sub>算法原理动画化,一眼看懂 AI 如何“画”出图片</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-rag.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>像玩游戏一样学 RAG</strong>
|
||||||
|
<br>
|
||||||
|
<sub>独家交互组件,点击即可看清 RAG 数据流向</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/git-terminal.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>可视化终端原理</strong>
|
||||||
|
<br>
|
||||||
|
<sub>命令行操作可视化,直观展示后台逻辑与原理</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div align="center">
|
||||||
|
<h3>⭐ 欢迎 <a href="https://github.com/datawhalechina/easy-vibe" style="color: #d0cd16ff;">点击此处Star</a> 加速更新 ❤️</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align="center" style="margin: 30px 0;">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/issues/new?template=story_submission.md">
|
||||||
|
<img src="https://raw.githubusercontent.com/datawhalechina/easy-vibe/main/assets/stories_image.png" alt="分享你的 Vibe 故事" width="80%" style="border-radius: 10px; box-shadow: 0 4px 12px rgba(0,0,0,0.15);">
|
||||||
|
</a>
|
||||||
|
<p style="margin-top: 15px; font-size: 1.1em; color: #666;">
|
||||||
|
📝 <strong>有自己的 vibe coding 故事?</strong>
|
||||||
|
在这里提交,激励更多人!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 目录 / Table of Contents
|
||||||
|
|
||||||
|
- [为什么需要 Easy-Vibe](#为什么需要-easy-vibe)
|
||||||
|
- [News](#-news)
|
||||||
|
- [适合谁](#适合谁)
|
||||||
|
- [你的学习路径](#你的学习路径)
|
||||||
|
- [学习建议](#学习建议)
|
||||||
|
- [一、零基础入门](#一零基础入门)
|
||||||
|
- [二、初中级开发工程师](#二初中级开发工程师)
|
||||||
|
- [三、高级开发工程师](#三高级开发工程师)
|
||||||
|
- [附录知识库](#-附录知识库)
|
||||||
|
- [如何学习](#️-如何学习)
|
||||||
|
- [本地启动本课件](#-本地启动本课件)
|
||||||
|
- [其他课程 / Other Courses](#-其他课程--other-courses)
|
||||||
|
- [参与贡献与致谢](#-参与贡献与致谢)
|
||||||
|
- [LICENSE](#-license)
|
||||||
|
|
||||||
|
## 为什么需要 Easy-Vibe
|
||||||
|
|
||||||
|
想做个记账小程序?说出来。
|
||||||
|
|
||||||
|
想要一个支持微信登录的预约系统?说出来。
|
||||||
|
|
||||||
|
想做一个带评论功能的博客?说出来。
|
||||||
|
|
||||||
|
在 AI 时代,编程先从描述你想要什么开始。
|
||||||
|
|
||||||
|
Easy-Vibe 教你的,就是怎样把它一步步做成真正的产品。
|
||||||
|
|
||||||
|
## 🔥 News
|
||||||
|
|
||||||
|
- **[2026-05-20]** 🌍 **第一阶段(Stage 1)多语言已全面覆盖**:Stage 1 已在所有支持的语言(zh-cn, en, zh-tw, ja-jp, ko-kr, es-es, fr-fr, de-de, ar-sa, vi-vn)下完整可用,并已完成导航/构建校验,确保不会出现 404。
|
||||||
|
- **[2026-03-29]** ✨ **「用户故事」专区上线并更新为真实案例**:首页新增交互式故事轮播组件和独立故事页面,并将原有占位内容替换为 4 篇真实用户故事,涵盖乡村小学老师、大学生、高中信息技术老师和货车司机,展示不同背景的学习者如何用 AI 解决真实问题、做出真实产品。[👉 查看故事](https://datawhalechina.github.io/easy-vibe/zh-cn/vibe-stories/story-1.html)
|
||||||
|
- **[2026-03-26]** 🚀 **阶段二实战内容集中更新**:补充完整 SaaS 全栈大作业[《第一个 SaaS 全栈应用——文案生成网站》](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/assignments/copywriting-platform-supabase/);同时大幅补全[《如何集成 Stripe 等收费系统》](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/backend/stripe-payment/),完善多产品 UI、微信小程序后端等关键章节。
|
||||||
|
- **[2026-03-25]** 📚 **新增附录「用户研究与需求验证」**:包含 4 篇文章——从哪里找点子、双钻模型、Jobs to Be Done、The Mom Test 用户访谈法,帮助新手学会发现和验证产品想法。[👉 阅读附录](https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/)
|
||||||
|
- **[2026-03-25]** 📚 **英文文档全面更新**:第二阶段(全栈开发)和第三阶段(高级开发)现已提供完整英文翻译。[👉 开始学习](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
- **[2026-03-02]** 🦞 **OpenClaw & AI Agent 友好支持**:新增 `llms.txt` AI 导航文件,让 OpenClaw、Claude、Cursor、Trae 等 AI Agent 能够快速理解本仓库结构,精准定位教程内容。希望每个🦞都学得愉快!
|
||||||
|
- **[2026-03-01]** [高级开发部分](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/)全面升级:新增 Claude Code 七大深度指南(MCP、Skills、Agent Teams 等)及八大跨平台开发实战(PWA、Electron、NFT、VS Code 插件、Qt 工业应用等)。
|
||||||
|
- **[2026-02-25]** 更新[附录知识库](https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/),涵盖 9 大知识领域、80+ 交互式专题。
|
||||||
|
- **[2026-01-27]** 新增 Android 和 iOS 平台应用开发教程。
|
||||||
|
- **[2026-01-19]** 发布 Prompt Engineering、AI 演进史、鉴权设计、Git 原理等一系列交互式演示组件,大幅提升可视化学习体验。
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Past News</summary>
|
||||||
|
|
||||||
|
- **[2026-01-16]** 重构项目结构,正式确立“新手入门”章节,降低上手门槛。
|
||||||
|
- **[2026-01-14]** 完成第一阶段“产品原型构建”文档的大规模更新。
|
||||||
|
- **[2026-01-13]** 完成文档架构重构,全面支持多语言 (i18n)。
|
||||||
|
- **[2026-01-01]** 发布项目核心学习地图 (Learning Map),明确学习路径。
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## 适合谁
|
||||||
|
|
||||||
|
- **零基础爱好者**:先做出第一个作品,再理解怎么做
|
||||||
|
- **产品经理 / 创业者**:快速验证想法,低成本做 MVP
|
||||||
|
- **学生**:建立 AI 时代的实战技能
|
||||||
|
- **初级开发者**:补齐从想法到上线的完整开发链路
|
||||||
|
- **中高级开发者**:掌握 AI 协作开发、复杂项目实战与效率升级
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 你的学习路径
|
||||||
|
|
||||||
|
### 🎮 我想先试试(5分钟体验)
|
||||||
|
**适合人群**:所有人
|
||||||
|
**学什么**:AI 编程初体验、贪吃蛇小游戏
|
||||||
|
**你会得到**:5 分钟做出第一个 AI 应用
|
||||||
|
|
||||||
|
[开始体验](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/learning-map/)
|
||||||
|
|
||||||
|
### 💡 我有个想法要实现
|
||||||
|
**适合人群**:零基础/产品经理/创业者
|
||||||
|
**学什么**:AI IDE 工具、需求拆解、页面设计、功能规划、提示词写法、原型迭代
|
||||||
|
**你会得到**:一个可演示的产品原型
|
||||||
|
|
||||||
|
[开始学习](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/learning-map/)
|
||||||
|
|
||||||
|
### 🚀 我想系统学习
|
||||||
|
**适合人群**:开发者/进阶学习者
|
||||||
|
**学什么**:前端、后端、数据库、AI 集成、部署运维、Claude Code 开发技巧
|
||||||
|
**你会得到**:独立完成一个可上线的全栈 AI 应用
|
||||||
|
|
||||||
|
[开始学习](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/)
|
||||||
|
|
||||||
|
### 🦞 我想构建 AI Agent
|
||||||
|
**适合人群**:对 AI Agent 感兴趣的开发者
|
||||||
|
**学什么**:OpenClaw AI 助理、Skills 系统、自动化工作流
|
||||||
|
**你会得到**:一个属于你的命令行 AI 助理
|
||||||
|
|
||||||
|
[开始学习](https://github.com/datawhalechina/hello-claw)
|
||||||
|
|
||||||
|
### 📚 我想查资料
|
||||||
|
**适合人群**:所有人
|
||||||
|
**学什么**:计算机基础、AI 原理、9 大知识领域
|
||||||
|
**你会得到**:80+ 交互式专题资料
|
||||||
|
|
||||||
|
[查看知识库](https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/)
|
||||||
|
|
||||||
|
## 学习建议
|
||||||
|
|
||||||
|
- 零基础、产品经理、创业者:从 [第一阶段](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/learning-map/) 开始
|
||||||
|
- 有开发经验:从 [第二阶段](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/) 开始
|
||||||
|
- 想直接做复杂项目:进入 [第三阶段](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/)
|
||||||
|
- 想学 AI Agent:看 [Hello Claw](https://github.com/datawhalechina/hello-claw)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 📖 内容导航
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<img src="../../assets/readme-image1.png" alt="Learning Map" width="70%" style="border-radius: 10px; box-shadow: 0 8px 20px rgba(45,55,72,0.3); margin: 15px 0;"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
### 一、零基础入门
|
||||||
|
|
||||||
|
| 章节 | 关键内容 |
|
||||||
|
| :----------------------------------------------------------------------------------- | :------------------------------------------------ |
|
||||||
|
| [学习地图](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/learning-map/) | 整体学习路径导览 |
|
||||||
|
| [AI 时代,会说话就会编程](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/ai-capabilities-through-games/) | 通过贪吃蛇等案例初步感受 AI 编程的能力 |
|
||||||
|
| [寻找好想法](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/finding-great-idea/) | 学会寻找和验证产品想法,找到值得做的项目 |
|
||||||
|
| [认识 AI IDE 工具](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/introduction-to-ai-ide/) | 学会使用 IDE,在本地制作小游戏 |
|
||||||
|
| [动手做出原型](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/building-prototype/) | 从需求分析、AI 生成单页面,再到生成多页面产品原型 |
|
||||||
|
| [给原型加上 AI 能力](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/integrating-ai-capabilities/) | 学会接入常见 AI 能力(文本、图片、视频) |
|
||||||
|
| [完整项目实战](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/complete-project-practice/) | 模拟真实场景、接受用户反馈迭代,完整化项目 |
|
||||||
|
|
||||||
|
#### 附录:业务思维
|
||||||
|
|
||||||
|
| 章节 | 关键内容 |
|
||||||
|
| :----------------------------------------------------------------------------------- | :----------------------------------------- |
|
||||||
|
| [产品思维与方案设计](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/appendix-a-product-thinking/) | 从零到一做产品需要考虑的思维框架 |
|
||||||
|
| [AI 行业应用场景参考 (B端)](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/appendix-industry-scenarios/) | 了解 AI 在不同产业的应用场景 |
|
||||||
|
| [AI 消费场景灵感参考 (C端)](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/appendix-c-consumer-scenarios/) | 探索 AI 在消费级产品中的应用场景 |
|
||||||
|
|
||||||
|
#### 附录:技术方案
|
||||||
|
|
||||||
|
| 章节 | 关键内容 |
|
||||||
|
| :---------------------------------------------------------------------------------------------------------------------- | :----------------------------------------- |
|
||||||
|
| [写代码时遇到错误怎么办](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/appendix-b-common-errors/) | vibe coding 中的常见错误及排查方法 |
|
||||||
|
| [七款 AI 编程工具对比](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/appendix-articles/example0-1/vibe-coding-tools-snake-game-tutorial) | 对比测试主流 AI 编程平台 |
|
||||||
|
| [用设计和编程 Agent 设计网站](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/appendix-articles/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents) | 学习如何使用 AI 智能体协同工作 |
|
||||||
|
|
||||||
|
### 二、初中级开发工程师
|
||||||
|
|
||||||
|
#### 前端部分
|
||||||
|
|
||||||
|
| 章节 | 关键内容 |
|
||||||
|
| :--------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------- |
|
||||||
|
| [从Lovart出发,搭建自己的素材生产Agent](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/frontend/lovart-assets/) | 从零开始,利用Nanobanana和Lovart批量生成高质量的设计素材,并动手构建一个能意图识别的绘图Agent |
|
||||||
|
| [Figma 与 MasterGo 入门](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/frontend/figma-mastergo/) | 用设计工具梳理信息架构和页面结构,为前端实现打基础 |
|
||||||
|
| [构建第一个现代应用程序-UI 设计](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/frontend/ui-design/) | 基于设计稿完成组件化界面,实现从设计到代码的第一条链路 |
|
||||||
|
| [参考 UI 设计规范与多产品 UI 设计](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/frontend/multi-product-ui/) | 围绕统一主视觉扩展多产品界面,练习系统化设计能力 |
|
||||||
|
| [用 LLM 和 Skills 让界面变好看](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/frontend/llm-skills-beautiful/) | 用提示词和 Skills 插件让 AI 生成美观独特的界面 |
|
||||||
|
| [一起做霍格沃茨画像](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/frontend/hogwarts-portraits/) | 从 0 到 1 做出接入 AI 能力的前端应用,串联设计与开发 |
|
||||||
|
| [从设计原型到项目代码](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/frontend/design-to-code/) | 三种路径将设计工具中的原型转化为前端代码 |
|
||||||
|
| [使用现代组件库更新你的界面](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/frontend/modern-component-library/) | 用组件库快速构建专业级界面,统一风格、提升开发效率 |
|
||||||
|
|
||||||
|
#### 后端开发部分
|
||||||
|
|
||||||
|
| 章节 | 关键内容 |
|
||||||
|
| :------------------------------------------------------------------------------------------------- | :---------------------------------------------------------- |
|
||||||
|
| [从数据库到 Supabase](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/backend/database-supabase/) | 在 Supabase 上落地数据库和 API,打通数据模型与前端页面 |
|
||||||
|
| [大模型辅助编写接口代码与接口文档](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/backend/ai-interface-code/) | 用大模型协助生成接口与数据库文档及代码,实现可读可测的后端 |
|
||||||
|
| [Git 和 GitHub 工作流](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/backend/git-workflow/) | 在 Git 工作流中管理代码,进行版本控制和协作 |
|
||||||
|
| [如何部署 Web 应用](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/backend/zeabur-deployment/) | 使用 CloudBase、Vercel、Zeabur 等平台部署应用上线 |
|
||||||
|
| [CLI AI 编程工具](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/backend/modern-cli/) | 使用 CLI 类 AI 编程工具加速开发与调试,形成个人工程化工作流 |
|
||||||
|
| [如何集成 Stripe 等收费系统](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/backend/stripe-payment/) | 接入支付系统,完成收费链路与基础结算流程 |
|
||||||
|
| [大作业:构建第一个现代应用程序-全栈应用](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/assignments/copywriting-platform-supabase/) | 综合前端、后端与支付模块,完成可上线的全栈 Web 应用 |
|
||||||
|
|
||||||
|
#### AI 能力附录
|
||||||
|
|
||||||
|
| 章节 | 关键内容 |
|
||||||
|
| :------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------- |
|
||||||
|
| [Dify 入门与知识库集成](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/ai-capabilities/dify-knowledge-base/) | 用 Dify Workflow 与基础 RAG 搭建工具类产品,为后续应用升级打样 |
|
||||||
|
|
||||||
|
### 三、高级开发工程师
|
||||||
|
|
||||||
|
#### Claude Code 核心技能
|
||||||
|
|
||||||
|
| 章节 | 关键内容 |
|
||||||
|
| :------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------- |
|
||||||
|
| [Claude Code 快速上手](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/core-skills/basics/) | 安装配置、基础操作、实用技巧和常用指令 |
|
||||||
|
| [Claude Code MCP 完全指南](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/core-skills/mcp/) | 通过 MCP 让 Claude Code 连接 GitHub、数据库、API 等外部服务 |
|
||||||
|
| [Claude Code Skills 完全指南](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/core-skills/skills/) | 将专业知识打包成可复用技能包,一次配置反复使用 |
|
||||||
|
| [Claude Code 工作流最佳实践](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/core-skills/workflow/) | 日常开发、代码重构、Code Review 等场景的最佳实践 |
|
||||||
|
| [Claude Agent Teams 完全指南](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/core-skills/agent-teams/) | 多 AI 实例协同工作,像真正的开发团队一样并行协作 |
|
||||||
|
| [Claude Code Superpowers 工程级开发](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/core-skills/superpowers/) | 让 AI 写出工程级代码,遵循 TDD 和最佳实践 |
|
||||||
|
| [如何让 Claude Code 长时间工作](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/core-skills/long-running-tasks/) | 设计长时间运行的任务,让 Coding Tools 持续工作直到完成 |
|
||||||
|
|
||||||
|
#### 多平台开发
|
||||||
|
|
||||||
|
| 章节 | 关键内容 |
|
||||||
|
| :------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------- |
|
||||||
|
| [如何构建微信小程序](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/cross-platform/wechat-miniprogram/) | 了解微信小程序生态,从官方模板到上线完成一个前端小程序 |
|
||||||
|
| [如何构建微信小程序-包含后端](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/cross-platform/wechat-miniprogram-backend/) | 在小程序中接入数据库与后端逻辑,打通完整业务闭环 |
|
||||||
|
| [如何构建安卓程序](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/cross-platform/android-app/) | 使用 Expo 等工具,完成 Web/原生一体化的安卓应用开发 |
|
||||||
|
| [如何构建 iOS 程序](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/cross-platform/ios-app/) | 使用 Expo 等工具,完成 Web/原生一体化的 iOS 应用开发 |
|
||||||
|
| [如何开发 PWA 本地应用](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/cross-platform/pwa-local-app/) | 让网页变成"真正的 App",支持离线、推送、桌面安装 |
|
||||||
|
| [如何开发浏览器 AI 助手插件](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/cross-platform/browser-ai-extension/) | 开发 Chrome 插件,一键总结任意网页,支持云端 API 和内置 AI |
|
||||||
|
| [如何开发 Electron 桌面程序](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/cross-platform/electron-voice-to-text/) | 用 Electron 构建语音转文字桌面应用,支持三平台安装运行 |
|
||||||
|
| [如何快速开发并铸造 NFT](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/cross-platform/nft-minting/) | 从零编写智能合约,部署到以太坊测试网,铸造自己的 NFT |
|
||||||
|
| [如何开发 VS Code 插件](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/cross-platform/vscode-extension/) | 开发 AI 项目助手插件,支持模板生成、代码对话、多文件问答 |
|
||||||
|
| [如何开发工业级 Qt 桌面应用](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/cross-platform/qt-industrial-hmi/) | 用 Qt 构建工业级水泵监控 HMI 系统,实时数据、趋势图、报警 |
|
||||||
|
|
||||||
|
#### AI 能力附录
|
||||||
|
|
||||||
|
| 章节 | 关键内容 |
|
||||||
|
| :---------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------ |
|
||||||
|
| [什么是 RAG 以及它如何工作](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/ai-advanced/rag-introduction/) | 系统理解 RAG 原理与常见架构,为复杂应用提供知识检索基础 |
|
||||||
|
| [中高级 RAG 与工作流编排:以 LangGraph 为例](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/ai-advanced/langgraph-advanced-rag/) | 使用 LangGraph 等工具设计多步工作流与中高级 RAG 系统 |
|
||||||
|
|
||||||
|
### 📚 附录知识库
|
||||||
|
|
||||||
|
> 涵盖 **9 大知识领域**、**80+ 交互式专题**,以动画和可视化组件帮助你直观理解从计算机底层到 AI 前沿的核心概念。
|
||||||
|
>
|
||||||
|
> 👉 [查看完整附录](https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/) · [AI 能力词典](https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/8-artificial-intelligence/ai-capability-dictionary)
|
||||||
|
|
||||||
|
### 🎓 其他课程 / Other Courses
|
||||||
|
|
||||||
|
- [Hands-on Modern RL](#other-courses)
|
||||||
|
- [Learn Harness Engineering](#other-courses)
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td valign="top" width="33%">
|
||||||
|
<strong>💻 计算机基础</strong><br><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/1-computer-fundamentals/transistor-to-cpu.html">从晶体管到 CPU</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/1-computer-fundamentals/operating-systems.html">操作系统</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/1-computer-fundamentals/data-encoding-storage.html">数据的编码、存储与传输</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/1-computer-fundamentals/computer-networks.html">网络:两台电脑如何对话</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/1-computer-fundamentals/data-structures.html">数据结构</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/1-computer-fundamentals/algorithm-thinking.html">算法思维入门</a>
|
||||||
|
</td>
|
||||||
|
<td valign="top" width="33%">
|
||||||
|
<strong>🔧 开发工具</strong><br><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/2-development-tools/git-version-control.html">Git:代码的时光机</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/2-development-tools/command-line-shell.html">命令行与 Shell 脚本</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/2-development-tools/package-managers.html">包管理器</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/2-development-tools/debugging-art/">调试的艺术</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/2-development-tools/regex.html">正则表达式</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/2-development-tools/environment-path.html">环境变量与 PATH</a>
|
||||||
|
</td>
|
||||||
|
<td valign="top" width="33%">
|
||||||
|
<strong>🌐 浏览器与前端</strong><br><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/3-browser-and-frontend/javascript-deep-dive.html">JavaScript 语言深入</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/3-browser-and-frontend/browser-as-os-rendering.html">浏览器渲染管道</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/3-browser-and-frontend/frontend-frameworks.html">前端框架对比</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/3-browser-and-frontend/graphics-animation.html">图形与动画</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/3-browser-and-frontend/web-performance.html">网页性能的度量与优化</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/3-browser-and-frontend/frontend-engineering.html">前端工程化全貌</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top" width="33%">
|
||||||
|
<strong>🖥️ 服务器与后端</strong><br><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/4-server-and-backend/http-protocol.html">HTTP 协议</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/4-server-and-backend/api-design.html">API 设计哲学</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/4-server-and-backend/auth-authorization.html">认证与授权体系</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/4-server-and-backend/concurrency-async.html">并发、异步与多线程</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/4-server-and-backend/message-queues.html">消息队列与事件驱动</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/4-server-and-backend/backend-layered-architecture.html">后端分层架构</a>
|
||||||
|
</td>
|
||||||
|
<td valign="top" width="33%">
|
||||||
|
<strong>📊 数据</strong><br><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/5-data/database-fundamentals.html">数据库原理与 SQL</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/5-data/database-fundamentals.html">数据库原理</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/5-data/data-tracking.html">数据埋点与用户行为采集</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/5-data/data-analysis.html">数据分析基础</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/5-data/ab-testing.html">A/B 测试与实验驱动</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/5-data/data-visualization.html">数据可视化与仪表盘</a>
|
||||||
|
</td>
|
||||||
|
<td valign="top" width="33%">
|
||||||
|
<strong>🏗️ 架构与系统设计</strong><br><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/6-architecture-and-system-design/monolith-to-microservices.html">从单体到微服务的演进</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/6-architecture-and-system-design/distributed-systems.html">分布式系统的挑战</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/6-architecture-and-system-design/high-availability.html">高可用与容灾</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/6-architecture-and-system-design/system-design-methodology.html">系统设计方法论</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top" width="33%">
|
||||||
|
<strong>☁️ 基础设施与运维</strong><br><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/7-infrastructure-and-operations/docker-containers.html">Docker 容器化</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/7-infrastructure-and-operations/kubernetes.html">Kubernetes 编排</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/7-infrastructure-and-operations/ci-cd.html">CI / CD 自动化</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/7-infrastructure-and-operations/dns-https.html">域名、DNS 与 HTTPS</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/7-infrastructure-and-operations/monitoring-logging.html">监控、日志与告警</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/7-infrastructure-and-operations/infrastructure-as-code.html">基础设施即代码</a>
|
||||||
|
</td>
|
||||||
|
<td valign="top" width="33%">
|
||||||
|
<strong>🤖 人工智能</strong><br><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/8-artificial-intelligence/llm-principles.html">大语言模型的工作原理</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/8-artificial-intelligence/transformer-attention.html">Transformer 与注意力机制</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/8-artificial-intelligence/rag.html">RAG 架构</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/8-artificial-intelligence/ai-agents.html">AI Agent 与工具调用</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/8-artificial-intelligence/prompt-engineering.html">提示词工程</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/8-artificial-intelligence/image-generation.html">图像生成原理</a>
|
||||||
|
</td>
|
||||||
|
<td valign="top" width="33%">
|
||||||
|
<strong>🎯 工程素养</strong><br><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/9-engineering-excellence/code-quality-refactoring.html">代码质量与重构</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/9-engineering-excellence/testing-strategies.html">测试策略</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/9-engineering-excellence/design-patterns.html">设计模式</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/9-engineering-excellence/security-thinking.html">安全思维与攻防基础</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/9-engineering-excellence/technical-writing.html">技术文档写作</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/9-engineering-excellence/open-source-collaboration.html">开源协作</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
## 🛠️ 如何学习
|
||||||
|
|
||||||
|
- 根据个人能力,选择性地阅读和实践相关章节,如果有问题欢迎 issue 提问。
|
||||||
|
|
||||||
|
## 💻 本地启动本课件
|
||||||
|
|
||||||
|
### 现代方案
|
||||||
|
|
||||||
|
在 AI IDE 对话框(vscode、cursor、trae 等)中,输入下列提示词启动本课件:
|
||||||
|
|
||||||
|
```
|
||||||
|
请你帮我运行这个项目的本地服务
|
||||||
|
```
|
||||||
|
|
||||||
|
### 旧方案
|
||||||
|
|
||||||
|
1. npm install
|
||||||
|
2. npm run dev
|
||||||
|
3. 打开浏览器访问 `http://localhost:3000` 即可查看。
|
||||||
|
|
||||||
|
## Other Courses
|
||||||
|
|
||||||
|
Our team has also created other courses! Check them out:
|
||||||
|
|
||||||
|
[](https://github.com/walkinglabs/hands-on-modern-rl)
|
||||||
|
|
||||||
|
**Hands-on Modern RL**: An open-source, hands-on curriculum bridging the gap from basic RL concepts to LLM alignment, RLVR, and advanced Agentic systems.
|
||||||
|
|
||||||
|
[](https://github.com/walkinglabs/learn-harness-engineering/tree/main)
|
||||||
|
|
||||||
|
**Learn Harness Engineering**: A comprehensive guide to harness engineering.
|
||||||
|
|
||||||
|
## 🤝 参与贡献与致谢
|
||||||
|
|
||||||
|
- 如果你发现了一些问题,或者觉得任何可以改进本项目的地方,可以提 Issue 进行反馈。如果提完没有人回复你可以联系[保姆团队](https://github.com/datawhalechina/DOPMC/blob/main/OP.md)的同学进行反馈跟进~
|
||||||
|
- 如果你想参与贡献本项目,可以提 Pull Request,如果提完没有人回复你可以联系[保姆团队](https://github.com/datawhalechina/DOPMC/blob/main/OP.md)的同学进行反馈跟进~
|
||||||
|
- 如果你对 Datawhale 很感兴趣并想要发起一个新的项目,请按照[Datawhale 开源项目指南](https://github.com/datawhalechina/DOPMC/blob/main/GUIDE.md)进行操作即可~
|
||||||
|
|
||||||
|
### 🙏 感谢每位贡献者
|
||||||
|
|
||||||
|
- [散步-项目负责人](https://github.com/sanbuphy) (Datawhale成员)
|
||||||
|
- 方可-指导老师(Datawhale成员, 清华大学)
|
||||||
|
- [Yerim Kang](https://github.com/yerim25)(实践项目部分-清华大学)
|
||||||
|
- [赵芷霖](https://github.com/ChileenZ)(实践项目部分-清华大学)
|
||||||
|
- [李亦萱](https://yixuan20.github.io/)(页面美术设计-清华大学)
|
||||||
|
- 刘思怡(实践项目部分-清华大学)
|
||||||
|
- [刘丽欣](https://github.com/liulx25xx)(实践项目部分-清华大学)
|
||||||
|
- AI Vibe Coding 101 内测群完整给建议体验的小伙伴们
|
||||||
|
|
||||||
|
### 特别感谢
|
||||||
|
|
||||||
|
- 感谢 [@Sm1les](https://github.com/Sm1les) 对本项目的帮助与支持
|
||||||
|
- 感谢所有为本项目做出贡献的开发者们和支持点赞的朋友们 ❤️
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
|
||||||
|
<a href="https://www.star-history.com/#datawhalechina/easy-vibe&type=timeline&legend=top-left">
|
||||||
|
<picture>
|
||||||
|
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=datawhalechina/easy-vibe&type=timeline&theme=dark&legend=top-left" />
|
||||||
|
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=datawhalechina/easy-vibe&type=timeline&legend=top-left" />
|
||||||
|
</picture>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align=center style="margin-top: 30px;">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=datawhalechina/easy-vibe" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 📄 LICENSE
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
|
||||||
|
<img
|
||||||
|
alt="知识共享许可协议"
|
||||||
|
style="border-width:0"
|
||||||
|
src="https://img.shields.io/badge/license-CC%20BY--NC--SA%204.0-lightgrey"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<br />
|
||||||
|
本作品采用
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
|
||||||
|
知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议
|
||||||
|
</a>
|
||||||
|
进行许可。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Star History
|
||||||
|
|
||||||
|
[](https://www.star-history.com/#datawhalechina/easy-vibe&type=date&legend=top-left)
|
||||||
@@ -0,0 +1,535 @@
|
|||||||
|
<!-- trigger vercel build -->
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
<img src="../../assets/easy-vibe-logo-hd.svg" alt="Easy-Vibe Logo" width="300">
|
||||||
|
|
||||||
|
<img src="../../assets/banner.png" alt="Easy-Vibe Banner" width="100%">
|
||||||
|
|
||||||
|
<p align="center" style="font-size: 1.2em; color: #666; margin: 20px 0;">
|
||||||
|
直接上手,一起 vibe!會說話就會做應用。<br>
|
||||||
|
<span style="font-size: 0.9em; color: #888;">Jump right in and vibe together — if you can talk, you can build apps.</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a href="https://trendshift.io/repositories/22079" target="_blank"><img src="https://trendshift.io/api/badge/repositories/22079" alt="datawhalechina/easy-vibe | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||||
|
|
||||||
|
<p align="center" style="font-size: 1.05em; color: #666; margin: 16px 0;">
|
||||||
|
你好 · Hello · 哈囉 · こんにちは · 안녕하세요 · Hola · Bonjour · Hallo · مرحبا · Xin chào<br>
|
||||||
|
我們的教程(第一部分)已經支援 10 種語言,歡迎世界各地的朋友一起 coding!<br>
|
||||||
|
<span style="font-size: 0.9em; color: #888;">Stage 1 of our tutorial is now available in 10 languages. Friends around the world, let's start coding together!</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
🚀 <a href="https://datawhalechina.github.io/easy-vibe/welcome.html">開始體驗</a> · ✨ <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/">互動式教程</a> · 🦞 <a href="https://github.com/datawhalechina/hello-claw">學習 OpenClaw</a> · 📖 <a href="#目錄--table-of-contents">查看目錄</a><br>
|
||||||
|
<span style="font-size: 0.85em; color: #888;">🚀 <a href="https://datawhalechina.github.io/easy-vibe/welcome.html">Start Exploring</a> · ✨ <a href="https://datawhalechina.github.io/easy-vibe/en/appendix/">Interactive Tutorial</a> · 🦞 <a href="https://github.com/datawhalechina/hello-claw">Learn OpenClaw</a> · 📖 <a href="#目錄--table-of-contents">Table of Contents</a></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://datawhalechina.github.io/easy-vibe/welcome.html">開始閱讀</a> ·
|
||||||
|
<a href="#-內容導航">學習地圖</a><br>
|
||||||
|
<span style="font-size: 0.85em; color: #888;">
|
||||||
|
<a href="https://datawhalechina.github.io/easy-vibe/welcome.html">Read Online</a> ·
|
||||||
|
<a href="#-content-navigation">Learning Map</a>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/stargazers" target="_blank">
|
||||||
|
<img src="https://img.shields.io/github/stars/datawhalechina/easy-vibe?color=660874&style=for-the-badge&logo=star&logoColor=white&labelColor=1a1a2e" alt="Stars"></a>
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/network/members" target="_blank">
|
||||||
|
<img src="https://img.shields.io/github/forks/datawhalechina/easy-vibe?color=660874&style=for-the-badge&logo=git-fork&logoColor=white&labelColor=1a1a2e" alt="Forks"></a>
|
||||||
|
<a href="../../LICENSE" target="_blank">
|
||||||
|
<img src="https://img.shields.io/badge/License-CC_BY_NC_SA_4.0-4ecdc4?style=for-the-badge&logo=creative-commons&logoColor=white&labelColor=1a1a2e" alt="License"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<a href="../zh-CN/README.md"><img alt="简体中文" src="https://img.shields.io/badge/简体中文-d9d9d9"></a>
|
||||||
|
<a href="../zh-TW/README.md"><img alt="繁體中文" src="https://img.shields.io/badge/繁體中文-d9d9d9"></a>
|
||||||
|
<a href="../en-US/README.md"><img alt="English" src="https://img.shields.io/badge/English-d9d9d9"></a>
|
||||||
|
<a href="../ja-JP/README.md"><img alt="日本語" src="https://img.shields.io/badge/日本語-d9d9d9"></a>
|
||||||
|
<a href="../es-ES/README.md"><img alt="Español" src="https://img.shields.io/badge/Español-d9d9d9"></a>
|
||||||
|
<a href="../fr-FR/README.md"><img alt="Français" src="https://img.shields.io/badge/Français-d9d9d9"></a>
|
||||||
|
<a href="../ko-KR/README.md"><img alt="한국어" src="https://img.shields.io/badge/한국어-d9d9d9"></a>
|
||||||
|
<a href="../ar-SA/README.md"><img alt="العربية" src="https://img.shields.io/badge/العربية-d9d9d9"></a>
|
||||||
|
<a href="../vi-VN/README.md"><img alt="Tiếng_Việt" src="https://img.shields.io/badge/Tiếng_Việt-d9d9d9"></a>
|
||||||
|
<a href="../de-DE/README.md"><img alt="Deutsch" src="https://img.shields.io/badge/Deutsch-d9d9d9"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<table align="center">
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-header.png" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>新手專屬學習地圖</strong>
|
||||||
|
<br>
|
||||||
|
<sub>零基礎專屬指引,清晰規劃路徑,告別「學了忘」</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-tutorial.png" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>手把手圖文教程</strong>
|
||||||
|
<br>
|
||||||
|
<sub>保姆級圖文詳解,如同私教在旁,跟著做就能學會</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-ide.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>沉浸式模擬編程</strong>
|
||||||
|
<br>
|
||||||
|
<sub>虛擬滑鼠自動導覽,帶你快速上手 IDE 核心用法</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-diffusion.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>看得見的 AI 原理</strong>
|
||||||
|
<br>
|
||||||
|
<sub>演算法原理動畫化,一眼看懂 AI 如何「畫」出圖片</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/gif-rag.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>像玩遊戲一樣學 RAG</strong>
|
||||||
|
<br>
|
||||||
|
<sub>獨家互動元件,點擊即可看清 RAG 資料流向</sub>
|
||||||
|
</td>
|
||||||
|
<td width="50%" valign="top" align="center">
|
||||||
|
<img src="../../assets/git-terminal.gif" width="100%">
|
||||||
|
<br>
|
||||||
|
<strong>視覺化終端原理</strong>
|
||||||
|
<br>
|
||||||
|
<sub>命令列操作視覺化,直觀展示後台邏輯與原理</sub>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<div align="center">
|
||||||
|
<h3>⭐ 歡迎 <a href="https://github.com/datawhalechina/easy-vibe" style="color: #d0cd16ff;">點擊此處 Star</a> 加速更新 ❤️</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align="center" style="margin: 30px 0;">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/issues/new?template=story_submission.md">
|
||||||
|
<img src="https://raw.githubusercontent.com/datawhalechina/easy-vibe/main/assets/stories_image.png" alt="分享你的 Vibe 故事" width="80%" style="border-radius: 10px; box-shadow: 0 4px 12px rgba(0,0,0,0.15);">
|
||||||
|
</a>
|
||||||
|
<p style="margin-top: 15px; font-size: 1.1em; color: #666;">
|
||||||
|
📝 <strong>有自己的 vibe coding 故事?</strong>
|
||||||
|
在這裡提交,激勵更多人!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 目錄 / Table of Contents
|
||||||
|
|
||||||
|
- [為什麼需要 Easy-Vibe](#為什麼需要-easy-vibe)
|
||||||
|
- [News](#-news)
|
||||||
|
- [適合誰](#適合誰)
|
||||||
|
- [你的學習路徑](#你的學習路徑)
|
||||||
|
- [學習建議](#學習建議)
|
||||||
|
- [一、零基礎入門](#一零基礎入門)
|
||||||
|
- [二、初中級開發工程師](#二初中級開發工程師)
|
||||||
|
- [三、高級開發工程師](#三高級開發工程師)
|
||||||
|
- [附錄知識庫](#-附錄知識庫)
|
||||||
|
- [如何學習](#️-如何學習)
|
||||||
|
- [本地啟動本課件](#-本地啟動本課件)
|
||||||
|
- [其他課程 / Other Courses](#-其他課程--other-courses)
|
||||||
|
- [參與貢獻與致謝](#-參與貢獻與致謝)
|
||||||
|
- [LICENSE](#-license)
|
||||||
|
|
||||||
|
## 為什麼需要 Easy-Vibe
|
||||||
|
|
||||||
|
想做個記帳小程式?說出來。
|
||||||
|
|
||||||
|
想要一個支援微信登入的預約系統?說出來。
|
||||||
|
|
||||||
|
想做一個帶留言功能的部落格?說出來。
|
||||||
|
|
||||||
|
在 AI 時代,程式設計先從描述你想要什麼開始。
|
||||||
|
|
||||||
|
Easy-Vibe 教你的,就是怎樣把它一步步做成真正的產品。
|
||||||
|
|
||||||
|
## 🔥 News
|
||||||
|
|
||||||
|
- **[2026-05-20]** 🌍 **第一階段(Stage 1)多語言已全面覆蓋**:Stage 1 已在所有支援的語言(zh-cn, en, zh-tw, ja-jp, ko-kr, es-es, fr-fr, de-de, ar-sa, vi-vn)下完整可用,並已完成導覽/建置校驗,避免出現 404。
|
||||||
|
- **[2026-03-29]** ✨ **「使用者故事」專區上線並更新為真實案例**:首頁新增互動式故事輪播元件與獨立故事頁面,並將原有佔位內容替換為 4 篇真實使用者故事,涵蓋鄉村小學老師、大學生、高中資訊科技老師和貨車司機,展示不同背景的學習者如何用 AI 解決真實問題、做出真實產品。[👉 查看故事](https://datawhalechina.github.io/easy-vibe/zh-cn/vibe-stories/story-1.html)
|
||||||
|
- **[2026-03-26]** 🚀 **階段二實戰內容集中更新**:補充完整 SaaS 全棧大作業[《第一個 SaaS 全棧應用——文案生成網站》](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/assignments/copywriting-platform-supabase/);同時大幅補全[《如何整合 Stripe 等收費系統》](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/backend/stripe-payment/),完善多產品 UI、微信小程式後端等關鍵章節。
|
||||||
|
- **[2026-03-25]** 📚 **新增附錄「使用者研究與需求驗證」**:包含 4 篇文章——從哪裡找點子、雙鑽模型、Jobs to Be Done、The Mom Test 使用者訪談法,幫助新手學會發現和驗證產品想法。[👉 閱讀附錄](https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/)
|
||||||
|
- **[2026-03-25]** 📚 **英文文件全面更新**:第二階段(全端開發)和第三階段(高級開發)現已提供完整英文翻譯。[👉 開始學習](https://datawhalechina.github.io/easy-vibe/en/stage-2/)
|
||||||
|
- **[2026-03-02]** 🦞 **OpenClaw & AI Agent 友好支援**:新增 `llms.txt` AI 導航檔案,讓 OpenClaw、Claude、Cursor、Trae 等 AI Agent 能夠快速理解本倉庫結構,精準定位教程內容。希望每個🦞都學得愉快!
|
||||||
|
- **[2026-03-01]** [高級開發部分](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/)全面升級:新增 Claude Code 七大深度指南(MCP、Skills、Agent Teams 等)及八大跨平台開發實戰(PWA、Electron、NFT、VS Code 外掛、Qt 工業應用等)。
|
||||||
|
- **[2026-02-25]** 更新[附錄知識庫](https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/),涵蓋 9 大知識領域、80+ 互動式專題。
|
||||||
|
- **[2026-01-27]** 新增 Android 和 iOS 平台應用開發教程。
|
||||||
|
- **[2026-01-19]** 發布 Prompt Engineering、AI 演進史、鑑權設計、Git 原理等一系列互動式演示元件,大幅提升視覺化學習體驗。
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Past News</summary>
|
||||||
|
|
||||||
|
- **[2026-01-16]** 重構專案結構,正式確立「新手入門」章節,降低上手門檻。
|
||||||
|
- **[2026-01-14]** 完成第一階段「產品原型建構」文件的大規模更新。
|
||||||
|
- **[2026-01-13]** 完成文件架構重構,全面支援多語言 (i18n)。
|
||||||
|
- **[2026-01-01]** 發布專案核心學習地圖 (Learning Map),明確學習路徑。
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## 適合誰
|
||||||
|
|
||||||
|
- **零基礎愛好者**:先做出第一個作品,再理解怎麼做
|
||||||
|
- **產品經理 / 創業者**:快速驗證想法,低成本做 MVP
|
||||||
|
- **學生**:建立 AI 時代的實戰技能
|
||||||
|
- **初級開發者**:補齊從想法到上線的完整開發鏈路
|
||||||
|
- **中高級開發者**:掌握 AI 協作開發、複雜專案實戰與效率升級
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 你的學習路徑
|
||||||
|
|
||||||
|
### 🎮 我想先試試(5 分鐘體驗)
|
||||||
|
**適合人群**:所有人
|
||||||
|
**學什麼**:AI 程式設計初體驗、貪吃蛇小遊戲
|
||||||
|
**你會得到**:5 分鐘做出第一個 AI 應用
|
||||||
|
|
||||||
|
[開始體驗](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/learning-map/)
|
||||||
|
|
||||||
|
### 💡 我有個想法要實現
|
||||||
|
**適合人群**:零基礎/產品經理/創業者
|
||||||
|
**學什麼**:AI IDE 工具、需求拆解、頁面設計、功能規劃、提示詞寫法、原型迭代
|
||||||
|
**你會得到**:一個可展示的產品原型
|
||||||
|
|
||||||
|
[開始學習](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/learning-map/)
|
||||||
|
|
||||||
|
### 🚀 我想系統學習
|
||||||
|
**適合人群**:開發者/進階學習者
|
||||||
|
**學什麼**:前端、後端、資料庫、AI 整合、部署維運、Claude Code 開發技巧
|
||||||
|
**你會得到**:獨立完成一個可上線的全端 AI 應用
|
||||||
|
|
||||||
|
[開始學習](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/)
|
||||||
|
|
||||||
|
### 🦞 我想建構 AI Agent
|
||||||
|
**適合人群**:對 AI Agent 感興趣的開發者
|
||||||
|
**學什麼**:OpenClaw AI 助理、Skills 系統、自動化工作流
|
||||||
|
**你會得到**:一個屬於你的命令列 AI 助理
|
||||||
|
|
||||||
|
[開始學習](https://github.com/datawhalechina/hello-claw)
|
||||||
|
|
||||||
|
### 📚 我想查資料
|
||||||
|
**適合人群**:所有人
|
||||||
|
**學什麼**:電腦基礎、AI 原理、9 大知識領域
|
||||||
|
**你會得到**:80+ 互動式專題資料
|
||||||
|
|
||||||
|
[查看知識庫](https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/)
|
||||||
|
|
||||||
|
## 學習建議
|
||||||
|
|
||||||
|
- 零基礎、產品經理、創業者:從 [第一階段](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/learning-map/) 開始
|
||||||
|
- 有開發經驗:從 [第二階段](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/) 開始
|
||||||
|
- 想直接做複雜專案:進入 [第三階段](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/)
|
||||||
|
- 想學 AI Agent:看 [Hello Claw](https://github.com/datawhalechina/hello-claw)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 📖 內容導航
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<img src="../../assets/readme-image1.png" alt="Learning Map" width="70%" style="border-radius: 10px; box-shadow: 0 8px 20px rgba(45,55,72,0.3); margin: 15px 0;"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
### 一、零基礎入門
|
||||||
|
|
||||||
|
| 章節 | 關鍵內容 |
|
||||||
|
| :----------------------------------------------------------------------------------- | :------------------------------------------------ |
|
||||||
|
| [學習地圖](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/learning-map/) | 整體學習路徑導覽 |
|
||||||
|
| [AI 時代,會說話就會程式設計](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/ai-capabilities-through-games/) | 透過貪吃蛇等案例初步感受 AI 程式設計的能力 |
|
||||||
|
| [尋找好想法](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/finding-great-idea/) | 學會尋找和驗證產品想法,找到值得做的專案 |
|
||||||
|
| [認識 AI IDE 工具](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/introduction-to-ai-ide/) | 學會使用 IDE,在本機製作小遊戲 |
|
||||||
|
| [動手做出原型](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/building-prototype/) | 從需求分析、AI 產生單頁面,再到產生多頁面產品原型 |
|
||||||
|
| [給原型加上 AI 能力](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/integrating-ai-capabilities/) | 學會接入常見 AI 能力(文字、圖片、影片) |
|
||||||
|
| [完整專案實戰](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/complete-project-practice/) | 模擬真實場景、接受使用者回饋迭代,完整化專案 |
|
||||||
|
|
||||||
|
#### 附錄:產品與業務思維
|
||||||
|
|
||||||
|
| 章節 | 關鍵內容 |
|
||||||
|
| :----------------------------------------------------------------------------------- | :----------------------------------------- |
|
||||||
|
| [產品思維與方案設計](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/appendix-a-product-thinking/) | 從零到一做產品需要考慮的思維框架 |
|
||||||
|
| [AI 行業應用場景參考 (B 端)](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/appendix-industry-scenarios/) | 了解 AI 在不同產業的應用場景 |
|
||||||
|
| [AI 消費場景靈感參考 (C 端)](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/appendix-c-consumer-scenarios/) | 探索 AI 在消費級產品中的應用場景 |
|
||||||
|
|
||||||
|
#### 附錄:使用者研究與需求驗證
|
||||||
|
|
||||||
|
| 章節 | 關鍵內容 |
|
||||||
|
| :----------------------------------------------------------------------------------- | :----------------------------------------- |
|
||||||
|
| [從哪裡找點子:最適合新手的 3 個參考來源](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/appendix-idea-sources/) | 建立可靠的管道來尋找具體的產品機會 |
|
||||||
|
| [雙鑽模型:先做對的事,再把事做對](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/appendix-double-diamond/) | 用結構化流程從零散靈感到可執行方向 |
|
||||||
|
| [用 Jobs to Be Done 找出使用者真正想完成的事](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/appendix-jobs-to-be-done/) | 透過真實任務分析使用者目標而非表面功能需求 |
|
||||||
|
| [The Mom Test:驗證需求的使用者訪談方法](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/appendix-mom-test/) | 學會問更好的問題,避免假陽性回饋 |
|
||||||
|
|
||||||
|
#### 附錄:技術方案
|
||||||
|
|
||||||
|
| 章節 | 關鍵內容 |
|
||||||
|
| :---------------------------------------------------------------------------------------------------------------------- | :----------------------------------------- |
|
||||||
|
| [寫程式時遇到錯誤怎麼辦](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/appendix-b-common-errors/) | vibe coding 中的常見錯誤及排查方法 |
|
||||||
|
| [七款 AI 程式設計工具對比](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/appendix-articles/example0-1/vibe-coding-tools-snake-game-tutorial) | 對比測試主流 AI 程式設計平台 |
|
||||||
|
| [用設計和程式設計 Agent 設計網站](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-1/appendix-articles/example0-2/vibe-coding-tools-build-website-with-ai-coding-and-design-agents) | 學習如何使用 AI 智慧體協同工作 |
|
||||||
|
|
||||||
|
### 二、初中級開發工程師
|
||||||
|
|
||||||
|
#### 前端部分
|
||||||
|
|
||||||
|
| 章節 | 關鍵內容 |
|
||||||
|
| :--------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------- |
|
||||||
|
| [從 Lovart 出發,搭建自己的素材生產 Agent](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/frontend/lovart-assets/) | 從零開始,利用 Nanobanana 和 Lovart 批次產生高品質的設計素材,並動手建構一個能意圖識別的繪圖 Agent |
|
||||||
|
| [Figma 與 MasterGo 入門](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/frontend/figma-mastergo/) | 用設計工具梳理資訊架構和頁面結構,為前端實作打基礎 |
|
||||||
|
| [建構第一個現代應用程式 - UI 設計](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/frontend/ui-design/) | 基於設計稿完成元件化介面,實現從設計到程式碼的第一條鏈路 |
|
||||||
|
| [參考 UI 設計規範與多產品 UI 設計](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/frontend/multi-product-ui/) | 圍繞統一主視覺擴展多產品介面,練習系統化設計能力 |
|
||||||
|
| [用 LLM 和 Skills 讓介面變好看](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/frontend/llm-skills-beautiful/) | 用提示詞和 Skills 外掛讓 AI 產生美觀獨特的介面 |
|
||||||
|
| [一起做霍格華茲畫像](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/frontend/hogwarts-portraits/) | 從 0 到 1 做出接入 AI 能力的前端應用,串聯設計與開發 |
|
||||||
|
| [從設計原型到專案程式碼](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/frontend/design-to-code/) | 三種路徑將設計工具中的原型轉化為前端程式碼 |
|
||||||
|
| [使用現代元件庫更新你的介面](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/frontend/modern-component-library/) | 用元件庫快速建構專業級介面,統一風格、提升開發效率 |
|
||||||
|
|
||||||
|
#### 後端開發部分
|
||||||
|
|
||||||
|
| 章節 | 關鍵內容 |
|
||||||
|
| :------------------------------------------------------------------------------------------------- | :---------------------------------------------------------- |
|
||||||
|
| [從資料庫到 Supabase](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/backend/database-supabase/) | 在 Supabase 上落地資料庫和 API,打通資料模型與前端頁面 |
|
||||||
|
| [大模型輔助編寫介面程式碼與介面文件](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/backend/ai-interface-code/) | 用大模型協助產生介面與資料庫文件及程式碼,實現可讀可測的後端 |
|
||||||
|
| [Git 和 GitHub 工作流](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/backend/git-workflow/) | 在 Git 工作流中管理程式碼,進行版本控制和協作 |
|
||||||
|
| [如何部署 Web 應用](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/backend/zeabur-deployment/) | 使用 CloudBase、Vercel、Zeabur 等平台部署應用上線 |
|
||||||
|
| [CLI AI 程式設計工具](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/backend/modern-cli/) | 使用 CLI 類 AI 程式設計工具加速開發與除錯,形成個人工程化工作流 |
|
||||||
|
| [如何整合 Stripe 等收費系統](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/backend/stripe-payment/) | 接入支付系統,完成收費鏈路與基礎結算流程 |
|
||||||
|
| [大作業:建構第一個現代應用程式 - 全端應用](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/assignments/copywriting-platform-supabase/) | 綜合前端、後端與支付模組,完成可上線的全端 Web 應用 |
|
||||||
|
|
||||||
|
#### AI 能力附錄
|
||||||
|
|
||||||
|
| 章節 | 關鍵內容 |
|
||||||
|
| :------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------- |
|
||||||
|
| [Dify 入門與知識庫整合](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-2/ai-capabilities/dify-knowledge-base/) | 用 Dify Workflow 與基礎 RAG 搭建工具類產品,為後續應用升級打樣 |
|
||||||
|
|
||||||
|
### 三、高級開發工程師
|
||||||
|
|
||||||
|
#### Claude Code 核心技能
|
||||||
|
|
||||||
|
| 章節 | 關鍵內容 |
|
||||||
|
| :------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------- |
|
||||||
|
| [Claude Code 快速上手](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/core-skills/basics/) | 安裝設定、基礎操作、實用技巧和常用指令 |
|
||||||
|
| [Claude Code MCP 完全指南](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/core-skills/mcp/) | 透過 MCP 讓 Claude Code 連接 GitHub、資料庫、API 等外部服務 |
|
||||||
|
| [Claude Code Skills 完全指南](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/core-skills/skills/) | 將專業知識打包成可複用技能包,一次設定反覆使用 |
|
||||||
|
| [如何讓 Claude Code 長時間工作](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/core-skills/long-running-tasks/) | 設計長時間執行的任務,讓 Coding Tools 持續工作直到完成 |
|
||||||
|
| [Claude Agent Teams 完全指南](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/core-skills/agent-teams/) | 多 AI 實例協同工作,像真正的開發團隊一樣並行協作 |
|
||||||
|
| [Claude Code Superpowers 工程級開發](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/core-skills/superpowers/) | 讓 AI 寫出工程級程式碼,遵循 TDD 和最佳實踐 |
|
||||||
|
| [Claude Code 工作流最佳實踐](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/core-skills/workflow/) | 日常開發、程式碼重構、Code Review 等場景的最佳實踐 |
|
||||||
|
| [Claude Code 行動端遠端開發](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/core-skills/mobile-development/) | 在行動裝置上使用 Claude Code,打造高效的遠端開發工作流 |
|
||||||
|
| [Claude Agent SDK 完全指南](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/core-skills/claude-agent-sdk/) | 使用 SDK 建構自訂 Agent 工作流,將 Claude 整合到你的工具中 |
|
||||||
|
| [從 Vibe Coding 到 Spec Coding](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/core-skills/spec-coding/) | 從即興提示轉向更結構化、規格驅動的 AI 開發工作流 |
|
||||||
|
|
||||||
|
#### 跨平台開發
|
||||||
|
|
||||||
|
| 章節 | 關鍵內容 |
|
||||||
|
| :------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------- |
|
||||||
|
| [如何選擇適合你的應用平台](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/cross-platform/choose-platform/) | 比較應用形態,根據使用者、場景和交付目標選擇合適的平台 |
|
||||||
|
| [如何建構微信小程式](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/cross-platform/wechat-miniprogram/) | 了解微信小程式生態,從官方範本到上線完成一個前端小程式 |
|
||||||
|
| [如何建構微信小程式 - 包含後端](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/cross-platform/wechat-miniprogram-backend/) | 在小程式中接入資料庫與後端邏輯,打通完整業務閉環 |
|
||||||
|
| [如何建構安卓程式](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/cross-platform/android-app/) | 使用 Expo 等工具,完成 Web/原生一體化的安卓應用開發 |
|
||||||
|
| [如何建構 iOS 程式](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/cross-platform/ios-app/) | 使用 Expo 等工具,完成 Web/原生一體化的 iOS 應用開發 |
|
||||||
|
| [如何開發 PWA 本機應用](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/cross-platform/pwa-local-app/) | 讓網頁變成「真正的 App」,支援離線、推送、桌面安裝 |
|
||||||
|
| [如何開發瀏覽器 AI 助手外掛](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/cross-platform/browser-ai-extension/) | 開發 Chrome 外掛,一鍵總結任意網頁,支援雲端 API 和內建 AI |
|
||||||
|
| [如何開發 Electron 桌面程式](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/cross-platform/electron-voice-to-text/) | 用 Electron 建構語音轉文字桌面應用,支援三平台安裝執行 |
|
||||||
|
| [如何快速開發並鑄造 NFT](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/cross-platform/nft-minting/) | 從零編寫智慧合約,部署到以太坊測試網,鑄造自己的 NFT |
|
||||||
|
| [如何開發 VS Code 外掛](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/cross-platform/vscode-extension/) | 開發 AI 專案助手外掛,支援範本產生、程式碼對話、多檔案問答 |
|
||||||
|
| [如何開發工業級 Qt 桌面應用](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/cross-platform/qt-industrial-hmi/) | 用 Qt 建構工業級水泵監控 HMI 系統,即時資料、趨勢圖、警報 |
|
||||||
|
|
||||||
|
#### AI 能力附錄
|
||||||
|
|
||||||
|
| 章節 | 關鍵內容 |
|
||||||
|
| :---------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------ |
|
||||||
|
| [什麼是 RAG 以及它如何運作](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/ai-advanced/rag-introduction/) | 系統理解 RAG 原理與常見架構,為複雜應用提供知識檢索基礎 |
|
||||||
|
| [中高級 RAG 與工作流編排:以 LangGraph 為例](https://datawhalechina.github.io/easy-vibe/zh-cn/stage-3/ai-advanced/langgraph-advanced-rag/) | 使用 LangGraph 等工具設計多步工作流與中高級 RAG 系統 |
|
||||||
|
|
||||||
|
### 📚 附錄知識庫
|
||||||
|
|
||||||
|
> 涵蓋 **9 大知識領域**、**80+ 互動式專題**,以動畫和視覺化元件幫助你直觀理解從電腦底層到 AI 前沿的核心概念。
|
||||||
|
>
|
||||||
|
> 👉 [查看完整附錄](https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/) · [AI 能力詞典](https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/8-artificial-intelligence/ai-capability-dictionary)
|
||||||
|
|
||||||
|
### 🎓 其他課程 / Other Courses
|
||||||
|
|
||||||
|
- [Hands-on Modern RL](#other-courses)
|
||||||
|
- [Learn Harness Engineering](#other-courses)
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td valign="top" width="33%">
|
||||||
|
<strong>💻 電腦基礎</strong><br><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/1-computer-fundamentals/transistor-to-cpu.html">從電晶體到 CPU</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/1-computer-fundamentals/operating-systems.html">作業系統</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/1-computer-fundamentals/data-encoding-storage.html">資料的編碼、儲存與傳輸</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/1-computer-fundamentals/computer-networks.html">網路:兩台電腦如何對話</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/1-computer-fundamentals/data-structures.html">資料結構</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/1-computer-fundamentals/algorithm-thinking.html">演算法思維入門</a>
|
||||||
|
</td>
|
||||||
|
<td valign="top" width="33%">
|
||||||
|
<strong>🔧 開發工具</strong><br><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/2-development-tools/git-version-control.html">Git:程式碼的時光機</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/2-development-tools/command-line-shell.html">命令列與 Shell 腳本</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/2-development-tools/package-managers.html">套件管理器</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/2-development-tools/debugging-art/">除錯的藝術</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/2-development-tools/regex.html">正規表示式</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/2-development-tools/environment-path.html">環境變數與 PATH</a>
|
||||||
|
</td>
|
||||||
|
<td valign="top" width="33%">
|
||||||
|
<strong>🌐 瀏覽器與前端</strong><br><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/3-browser-and-frontend/javascript-deep-dive.html">JavaScript 語言深入</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/3-browser-and-frontend/browser-as-os-rendering.html">瀏覽器渲染管道</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/3-browser-and-frontend/frontend-frameworks.html">前端框架對比</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/3-browser-and-frontend/graphics-animation.html">圖形與動畫</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/3-browser-and-frontend/web-performance.html">網頁效能的度量與最佳化</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/3-browser-and-frontend/frontend-engineering.html">前端工程化全貌</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top" width="33%">
|
||||||
|
<strong>🖥️ 伺服器與後端</strong><br><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/4-server-and-backend/http-protocol.html">HTTP 協定</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/4-server-and-backend/api-design.html">API 設計哲學</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/4-server-and-backend/auth-authorization.html">認證與授權體系</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/4-server-and-backend/concurrency-async.html">並行、非同步與多執行緒</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/4-server-and-backend/message-queues.html">訊息佇列與事件驅動</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/4-server-and-backend/backend-layered-architecture.html">後端分層架構</a>
|
||||||
|
</td>
|
||||||
|
<td valign="top" width="33%">
|
||||||
|
<strong>📊 資料</strong><br><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/5-data/database-fundamentals.html">資料庫原理與 SQL</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/5-data/database-fundamentals.html">資料庫原理</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/5-data/data-tracking.html">資料埋點與使用者行為採集</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/5-data/data-analysis.html">資料分析基礎</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/5-data/ab-testing.html">A/B 測試與實驗驅動</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/5-data/data-visualization.html">資料視覺化與儀表板</a>
|
||||||
|
</td>
|
||||||
|
<td valign="top" width="33%">
|
||||||
|
<strong>🏗️ 架構與系統設計</strong><br><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/6-architecture-and-system-design/monolith-to-microservices.html">從單體到微服務的演進</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/6-architecture-and-system-design/distributed-systems.html">分散式系統的挑戰</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/6-architecture-and-system-design/high-availability.html">高可用與容災</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/6-architecture-and-system-design/system-design-methodology.html">系統設計方法論</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top" width="33%">
|
||||||
|
<strong>☁️ 基礎設施與維運</strong><br><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/7-infrastructure-and-operations/docker-containers.html">Docker 容器化</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/7-infrastructure-and-operations/kubernetes.html">Kubernetes 編排</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/7-infrastructure-and-operations/ci-cd.html">CI / CD 自動化</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/7-infrastructure-and-operations/dns-https.html">網域、DNS 與 HTTPS</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/7-infrastructure-and-operations/monitoring-logging.html">監控、日誌與警報</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/7-infrastructure-and-operations/infrastructure-as-code.html">基礎設施即程式碼</a>
|
||||||
|
</td>
|
||||||
|
<td valign="top" width="33%">
|
||||||
|
<strong>🤖 人工智慧</strong><br><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/8-artificial-intelligence/llm-principles.html">大語言模型的運作原理</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/8-artificial-intelligence/transformer-attention.html">Transformer 與注意力機制</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/8-artificial-intelligence/rag.html">RAG 架構</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/8-artificial-intelligence/ai-agents.html">AI Agent 與工具呼叫</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/8-artificial-intelligence/prompt-engineering.html">提示詞工程</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/8-artificial-intelligence/image-generation.html">圖像生成原理</a>
|
||||||
|
</td>
|
||||||
|
<td valign="top" width="33%">
|
||||||
|
<strong>🎯 工程素養</strong><br><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/9-engineering-excellence/code-quality-refactoring.html">程式碼品質與重構</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/9-engineering-excellence/testing-strategies.html">測試策略</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/9-engineering-excellence/design-patterns.html">設計模式</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/9-engineering-excellence/security-thinking.html">安全思維與攻防基礎</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/9-engineering-excellence/technical-writing.html">技術文件寫作</a><br>
|
||||||
|
• <a href="https://datawhalechina.github.io/easy-vibe/zh-cn/appendix/9-engineering-excellence/open-source-collaboration.html">開源協作</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
## 🛠️ 如何學習
|
||||||
|
|
||||||
|
- 根據個人能力,選擇性地閱讀和實踐相關章節,如果有問題歡迎 issue 提問。
|
||||||
|
|
||||||
|
## 💻 本地啟動本課件
|
||||||
|
|
||||||
|
### 現代方案
|
||||||
|
|
||||||
|
在 AI IDE 對話框(VS Code、Cursor、Trae 等)中,輸入下列提示詞啟動本課件:
|
||||||
|
|
||||||
|
```
|
||||||
|
請你幫我執行這個專案的本機服務
|
||||||
|
```
|
||||||
|
|
||||||
|
### 傳統方案
|
||||||
|
|
||||||
|
1. `npm install`
|
||||||
|
2. `npm run dev`
|
||||||
|
3. 開啟瀏覽器造訪 `http://localhost:3000` 即可查看。
|
||||||
|
|
||||||
|
## Other Courses
|
||||||
|
|
||||||
|
Our team has also created other courses! Check them out:
|
||||||
|
|
||||||
|
[](https://github.com/walkinglabs/hands-on-modern-rl)
|
||||||
|
|
||||||
|
**Hands-on Modern RL**: An open-source, hands-on curriculum bridging the gap from basic RL concepts to LLM alignment, RLVR, and advanced Agentic systems.
|
||||||
|
|
||||||
|
[](https://github.com/walkinglabs/learn-harness-engineering/tree/main)
|
||||||
|
|
||||||
|
**Learn Harness Engineering**: A comprehensive guide to harness engineering.
|
||||||
|
|
||||||
|
## 🤝 參與貢獻與致謝
|
||||||
|
|
||||||
|
- 如果你發現了一些問題,或者覺得任何可以改進本專案的地方,可以提 Issue 進行回饋。如果提完沒有人回覆你可以聯繫[保姆團隊](https://github.com/datawhalechina/DOPMC/blob/main/OP.md)的同學進行回饋跟進~
|
||||||
|
- 如果你想參與貢獻本專案,可以提 Pull Request,如果提完沒有人回覆你可以聯繫[保姆團隊](https://github.com/datawhalechina/DOPMC/blob/main/OP.md)的同學進行回饋跟進~
|
||||||
|
- 如果你對 Datawhale 很感興趣並想要發起一個新的專案,請按照 [Datawhale 開源專案指南](https://github.com/datawhalechina/DOPMC/blob/main/GUIDE.md)進行操作即可~
|
||||||
|
|
||||||
|
### 🙏 感謝每位貢獻者
|
||||||
|
|
||||||
|
- [散步 - 專案負責人](https://github.com/sanbuphy) (Datawhale 成員)
|
||||||
|
- 方可 - 指導老師(Datawhale 成員, 清華大學)
|
||||||
|
- [Yerim Kang](https://github.com/yerim25)(實踐專案部分 - 清華大學)
|
||||||
|
- [趙芷霖](https://github.com/ChileenZ)(實踐專案部分 - 清華大學)
|
||||||
|
- [李亦萱](https://yixuan20.github.io/)(頁面美術設計 - 清華大學)
|
||||||
|
- 劉思怡(實踐專案部分 - 清華大學)
|
||||||
|
- [劉麗欣](https://github.com/liulx25xx)(實踐專案部分 - 清華大學)
|
||||||
|
- AI Vibe Coding 101 內測群完整給建議體驗的小夥伴們
|
||||||
|
|
||||||
|
### 特別感謝
|
||||||
|
|
||||||
|
- 感謝 [@Sm1les](https://github.com/Sm1les) 對本專案的幫助與支援
|
||||||
|
- 感謝所有為本專案做出貢獻的開發者們和支援點讚的朋友們 ❤️
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
|
||||||
|
<a href="https://www.star-history.com/#datawhalechina/easy-vibe&type=timeline&legend=top-left">
|
||||||
|
<picture>
|
||||||
|
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=datawhalechina/easy-vibe&type=timeline&theme=dark&legend=top-left" />
|
||||||
|
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=datawhalechina/easy-vibe&type=timeline&legend=top-left" />
|
||||||
|
</picture>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div align=center style="margin-top: 30px;">
|
||||||
|
<a href="https://github.com/datawhalechina/easy-vibe/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=datawhalechina/easy-vibe" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## 📄 LICENSE
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
|
||||||
|
<img
|
||||||
|
alt="知識共享授權協議"
|
||||||
|
style="border-width:0"
|
||||||
|
src="https://img.shields.io/badge/license-CC%20BY--NC--SA%204.0-lightgrey"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
<br />
|
||||||
|
本作品採用
|
||||||
|
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
|
||||||
|
知識共享署名-非商業性使用-相同方式共享 4.0 國際授權協議
|
||||||
|
</a>
|
||||||
|
進行授權。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Star History
|
||||||
|
|
||||||
|
[](https://www.star-history.com/#datawhalechina/easy-vibe&type=date&legend=top-left)
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
# Vue 组件开发规范(避免 Build 卡住)
|
||||||
|
|
||||||
|
本文档记录了在开发 VitePress 主题组件时需要注意的问题,以防止 `npm run build` 时进程卡住无法退出。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 问题描述
|
||||||
|
|
||||||
|
当 Vue 组件在模块加载时立即执行定时器(如 `setInterval`、`setTimeout`)或启动持续运行的逻辑时,VitePress 的 build 进程会卡住,无法正常退出。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 常见原因
|
||||||
|
|
||||||
|
### 1. 在组件顶层直接调用启动函数
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// ❌ 错误示例
|
||||||
|
function startTimer() {
|
||||||
|
timer = setInterval(() => { ... }, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
startTimer() // 模块加载时立即执行,导致 build 卡住
|
||||||
|
```
|
||||||
|
|
||||||
|
**解决方案**:不要在组件顶层直接调用启动函数,让用户交互触发。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. 使用 `setInterval` 但未清理
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// ❌ 错误示例
|
||||||
|
let timer = setInterval(() => { ... }, 1000)
|
||||||
|
```
|
||||||
|
|
||||||
|
**解决方案**:
|
||||||
|
- 使用 `onUnmounted` 清理定时器
|
||||||
|
- 不要在模块加载时启动定时器
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 正确示例
|
||||||
|
|
||||||
|
### 按钮触发启动
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<script setup>
|
||||||
|
import { ref, onUnmounted } from 'vue'
|
||||||
|
|
||||||
|
const running = ref(false)
|
||||||
|
let timer = null
|
||||||
|
|
||||||
|
function start() {
|
||||||
|
running.value = true
|
||||||
|
timer = setInterval(() => { ... }, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
function stop() {
|
||||||
|
running.value = false
|
||||||
|
if (timer) clearInterval(timer)
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (timer) clearInterval(timer)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<button @click="start" :disabled="running">开始</button>
|
||||||
|
<button @click="stop">停止</button>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 初始化状态使用 ref,不用立即启动定时器
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
// ❌ 不要这样
|
||||||
|
// reset() // 这会启动定时器
|
||||||
|
|
||||||
|
// ✅ 正确:初始化为静态值
|
||||||
|
const passed = ref(0)
|
||||||
|
const rejected = ref(0)
|
||||||
|
const tokens = ref(5) // 初始令牌数,不启动补充
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 排查步骤
|
||||||
|
|
||||||
|
如果 build 卡住:
|
||||||
|
|
||||||
|
1. **检查组件末尾是否有立即执行的函数调用**
|
||||||
|
2. **搜索 `setInterval`、`setTimeout`**:确认是否在用户交互时才调用
|
||||||
|
3. **添加 `onUnmounted` 清理**:确保组件卸载时清理定时器
|
||||||
|
4. **逐个注释组件**:锁定问题组件后,逐行排查
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 归档组件修复记录
|
||||||
|
|
||||||
|
| 组件 | 问题 | 修复方式 |
|
||||||
|
|------|------|----------|
|
||||||
|
| `RateLimitAlgorithmDemo.vue` | 模块加载时调用 `reset()` 启动定时器 | 移除末尾的 `reset()` 调用 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 相关文件
|
||||||
|
|
||||||
|
- `docs/.vitepress/theme/index.js` - 组件注册文件
|
||||||
|
- `docs/archived-components.md` - 已归档的组件列表
|
||||||
|
|
||||||
@@ -0,0 +1,952 @@
|
|||||||
|
<script setup>
|
||||||
|
import DefaultTheme from 'vitepress/theme'
|
||||||
|
import { useData, useRoute, withBase } from 'vitepress'
|
||||||
|
import TextType from './components/TextType.vue'
|
||||||
|
import GitHubStars from './components/GitHubStars.vue'
|
||||||
|
import PageSlidesButton from './components/PageSlidesButton.vue'
|
||||||
|
import { onMounted, onBeforeUnmount, ref, watch, computed } from 'vue'
|
||||||
|
import ReadingProgress from './components/ReadingProgress.vue'
|
||||||
|
import { Setting } from '@element-plus/icons-vue'
|
||||||
|
import easyVibePaths from './data/easyVibePaths.json'
|
||||||
|
|
||||||
|
const { frontmatter } = useData()
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const openWelcomeFromWordmark = () => {
|
||||||
|
const currentPath = window.location.pathname
|
||||||
|
window.location.href = withBase(
|
||||||
|
`/welcome/?next=${encodeURIComponent(currentPath)}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const homeTaglineTyping = {
|
||||||
|
typingSpeed: 45,
|
||||||
|
initialDelay: 0,
|
||||||
|
pauseDuration: 2500,
|
||||||
|
postDeletingDelay: 500,
|
||||||
|
deletingSpeed: 18
|
||||||
|
}
|
||||||
|
|
||||||
|
const FONT_SIZE_STORAGE_KEY = 'ev-doc-font-size'
|
||||||
|
const LINE_HEIGHT_STORAGE_KEY = 'ev-doc-line-height'
|
||||||
|
const MIN_FONT_SIZE = 12
|
||||||
|
const MAX_FONT_SIZE = 18
|
||||||
|
const DEFAULT_FONT_SIZE = 14
|
||||||
|
const MIN_LINE_HEIGHT = 1.25
|
||||||
|
const MAX_LINE_HEIGHT = 1.8
|
||||||
|
const DEFAULT_LINE_HEIGHT = 1.65
|
||||||
|
|
||||||
|
const fontSize = ref(DEFAULT_FONT_SIZE)
|
||||||
|
const lineHeight = ref(DEFAULT_LINE_HEIGHT)
|
||||||
|
const isHydrated = ref(false)
|
||||||
|
|
||||||
|
const clampFontSize = (value) => {
|
||||||
|
if (value === null || value === undefined || value === '')
|
||||||
|
return DEFAULT_FONT_SIZE
|
||||||
|
const numeric = Number(value)
|
||||||
|
if (!Number.isFinite(numeric)) return DEFAULT_FONT_SIZE
|
||||||
|
return Math.min(MAX_FONT_SIZE, Math.max(MIN_FONT_SIZE, numeric))
|
||||||
|
}
|
||||||
|
|
||||||
|
const clampLineHeight = (value) => {
|
||||||
|
if (value === null || value === undefined || value === '')
|
||||||
|
return DEFAULT_LINE_HEIGHT
|
||||||
|
const numeric = Number(value)
|
||||||
|
if (!Number.isFinite(numeric)) return DEFAULT_LINE_HEIGHT
|
||||||
|
return Math.min(MAX_LINE_HEIGHT, Math.max(MIN_LINE_HEIGHT, numeric))
|
||||||
|
}
|
||||||
|
|
||||||
|
const applyFontSize = (size) => {
|
||||||
|
if (typeof document === 'undefined') return
|
||||||
|
document.documentElement.style.setProperty('--ev-doc-font-size', `${size}px`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const applyLineHeight = (value) => {
|
||||||
|
if (typeof document === 'undefined') return
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
'--ev-doc-line-height',
|
||||||
|
String(value)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const decreaseFontSize = () => {
|
||||||
|
fontSize.value = clampFontSize(fontSize.value - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const increaseFontSize = () => {
|
||||||
|
fontSize.value = clampFontSize(fontSize.value + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetFontSize = () => {
|
||||||
|
fontSize.value = DEFAULT_FONT_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetLineHeight = () => {
|
||||||
|
lineHeight.value = DEFAULT_LINE_HEIGHT
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// 目录栏(左侧 VPSidebar)收起/展开功能
|
||||||
|
// ============================================
|
||||||
|
const SIDEBAR_COLLAPSED_KEY = 'ev-sidebar-collapsed'
|
||||||
|
const SIDEBAR_WIDTH_KEY = 'ev-sidebar-width'
|
||||||
|
const DEFAULT_SIDEBAR_WIDTH = 272
|
||||||
|
const MIN_SIDEBAR_WIDTH = 160
|
||||||
|
const MAX_SIDEBAR_WIDTH = 560
|
||||||
|
const sidebarCollapsed = ref(false)
|
||||||
|
const sidebarWidth = ref(DEFAULT_SIDEBAR_WIDTH)
|
||||||
|
const sidebarResizing = ref(false)
|
||||||
|
let sidebarResizeLeft = 0
|
||||||
|
|
||||||
|
const toggleSidebar = () => {
|
||||||
|
sidebarCollapsed.value = !sidebarCollapsed.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const getSidebarWidthBounds = () => {
|
||||||
|
if (typeof window === 'undefined') {
|
||||||
|
return {
|
||||||
|
min: MIN_SIDEBAR_WIDTH,
|
||||||
|
max: MAX_SIDEBAR_WIDTH
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const viewportMax = window.innerWidth - 240
|
||||||
|
return {
|
||||||
|
min: MIN_SIDEBAR_WIDTH,
|
||||||
|
max: Math.min(MAX_SIDEBAR_WIDTH, Math.max(MIN_SIDEBAR_WIDTH, viewportMax))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const clampSidebarWidth = (value) => {
|
||||||
|
const numeric = Number(value)
|
||||||
|
if (!Number.isFinite(numeric)) return DEFAULT_SIDEBAR_WIDTH
|
||||||
|
const bounds = getSidebarWidthBounds()
|
||||||
|
return Math.min(bounds.max, Math.max(bounds.min, numeric))
|
||||||
|
}
|
||||||
|
|
||||||
|
const applySidebarWidth = (width) => {
|
||||||
|
if (typeof document === 'undefined') return
|
||||||
|
document.documentElement.style.setProperty('--vp-sidebar-width', `${width}px`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const setSidebarWidth = (value, shouldPersist = true) => {
|
||||||
|
const normalized = clampSidebarWidth(value)
|
||||||
|
sidebarWidth.value = normalized
|
||||||
|
applySidebarWidth(normalized)
|
||||||
|
if (shouldPersist) {
|
||||||
|
localStorage.setItem(SIDEBAR_WIDTH_KEY, String(normalized))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getSidebarLeftBoundary = () => {
|
||||||
|
const sidebar = document.querySelector('.VPSidebar')
|
||||||
|
if (sidebar) {
|
||||||
|
return sidebar.getBoundingClientRect().left
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateSidebarWidthFromPointer = (clientX) => {
|
||||||
|
const nextWidth = clientX - sidebarResizeLeft
|
||||||
|
setSidebarWidth(nextWidth, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSidebarResizeMove = (event) => {
|
||||||
|
if (!sidebarResizing.value) return
|
||||||
|
updateSidebarWidthFromPointer(event.clientX)
|
||||||
|
}
|
||||||
|
|
||||||
|
const stopSidebarResize = () => {
|
||||||
|
if (!sidebarResizing.value) return
|
||||||
|
sidebarResizing.value = false
|
||||||
|
document.body.classList.remove('ev-sidebar-resizing')
|
||||||
|
localStorage.setItem(SIDEBAR_WIDTH_KEY, String(sidebarWidth.value))
|
||||||
|
window.removeEventListener('pointermove', handleSidebarResizeMove)
|
||||||
|
window.removeEventListener('pointerup', stopSidebarResize)
|
||||||
|
window.removeEventListener('pointercancel', stopSidebarResize)
|
||||||
|
}
|
||||||
|
|
||||||
|
const startSidebarResize = (event) => {
|
||||||
|
if (typeof window === 'undefined') return
|
||||||
|
if (window.innerWidth < 960 || sidebarCollapsed.value) return
|
||||||
|
event.preventDefault()
|
||||||
|
sidebarResizeLeft = getSidebarLeftBoundary()
|
||||||
|
sidebarResizing.value = true
|
||||||
|
document.body.classList.add('ev-sidebar-resizing')
|
||||||
|
updateSidebarWidthFromPointer(event.clientX)
|
||||||
|
window.addEventListener('pointermove', handleSidebarResizeMove)
|
||||||
|
window.addEventListener('pointerup', stopSidebarResize)
|
||||||
|
window.addEventListener('pointercancel', stopSidebarResize)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleViewportResize = () => {
|
||||||
|
setSidebarWidth(sidebarWidth.value, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
const isHomePage = computed(() => frontmatter.value.layout === 'home')
|
||||||
|
const isWelcomePage = computed(() =>
|
||||||
|
route.path === '/welcome/' ||
|
||||||
|
route.path.endsWith('/welcome/') ||
|
||||||
|
route.path.endsWith('/welcome.html')
|
||||||
|
)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const saved = clampFontSize(localStorage.getItem(FONT_SIZE_STORAGE_KEY))
|
||||||
|
const savedLineHeight = clampLineHeight(
|
||||||
|
localStorage.getItem(LINE_HEIGHT_STORAGE_KEY)
|
||||||
|
)
|
||||||
|
fontSize.value = saved
|
||||||
|
lineHeight.value = savedLineHeight
|
||||||
|
applyFontSize(saved)
|
||||||
|
applyLineHeight(savedLineHeight)
|
||||||
|
isHydrated.value = true
|
||||||
|
|
||||||
|
// 恢复目录栏收起状态
|
||||||
|
const savedCollapsed = localStorage.getItem(SIDEBAR_COLLAPSED_KEY)
|
||||||
|
if (savedCollapsed === 'true') {
|
||||||
|
sidebarCollapsed.value = true
|
||||||
|
document.body.classList.add('ev-sidebar-collapsed')
|
||||||
|
}
|
||||||
|
|
||||||
|
const savedSidebarWidth = localStorage.getItem(SIDEBAR_WIDTH_KEY)
|
||||||
|
if (savedSidebarWidth) {
|
||||||
|
setSidebarWidth(savedSidebarWidth, false)
|
||||||
|
} else {
|
||||||
|
setSidebarWidth(DEFAULT_SIDEBAR_WIDTH, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('resize', handleViewportResize)
|
||||||
|
|
||||||
|
initOutlineAutoScroll()
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
window.removeEventListener('resize', handleViewportResize)
|
||||||
|
stopSidebarResize()
|
||||||
|
})
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// Outline 侧边栏自动滚动跟随功能
|
||||||
|
// 当页面滚动时,自动滚动 outline 让当前激活项保持在可视区域
|
||||||
|
// ============================================
|
||||||
|
function initOutlineAutoScroll() {
|
||||||
|
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') {
|
||||||
|
const target = mutation.target
|
||||||
|
if (target.classList.contains('active') && target.tagName === 'A') {
|
||||||
|
scrollOutlineToActiveItem(target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
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) {
|
||||||
|
observer.observe(outlineContainer, {
|
||||||
|
attributes: true,
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
const originalPushState = history.pushState
|
||||||
|
const originalReplaceState = history.replaceState
|
||||||
|
|
||||||
|
history.pushState = function (...args) {
|
||||||
|
originalPushState.apply(this, args)
|
||||||
|
setTimeout(startObserving, 300)
|
||||||
|
}
|
||||||
|
|
||||||
|
history.replaceState = function (...args) {
|
||||||
|
originalReplaceState.apply(this, args)
|
||||||
|
setTimeout(startObserving, 300)
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('popstate', () => {
|
||||||
|
setTimeout(startObserving, 300)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 滚动 outline 让当前激活项保持在可视区域中心
|
||||||
|
function scrollOutlineToActiveItem(activeLink) {
|
||||||
|
const outlineContainer = document.querySelector('.VPDocAsideOutline')
|
||||||
|
if (!outlineContainer || !activeLink) return
|
||||||
|
|
||||||
|
const containerRect = outlineContainer.getBoundingClientRect()
|
||||||
|
const linkRect = activeLink.getBoundingClientRect()
|
||||||
|
|
||||||
|
// 计算链接相对于容器的位置
|
||||||
|
const linkTop = linkRect.top - containerRect.top + outlineContainer.scrollTop
|
||||||
|
const linkHeight = linkRect.height
|
||||||
|
const containerHeight = containerRect.height
|
||||||
|
|
||||||
|
// 判断链接是否在可视区域外
|
||||||
|
const isAbove = linkRect.top < containerRect.top + 20
|
||||||
|
const isBelow = linkRect.bottom > containerRect.bottom - 20
|
||||||
|
|
||||||
|
if (isAbove || isBelow) {
|
||||||
|
// 将激活项滚动到容器中间位置
|
||||||
|
const targetScrollTop = linkTop - containerHeight / 2 + linkHeight / 2
|
||||||
|
outlineContainer.scrollTo({
|
||||||
|
top: targetScrollTop,
|
||||||
|
behavior: 'smooth'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 滚动侧边栏让当前激活项保持在可视区域中心
|
||||||
|
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)
|
||||||
|
applyFontSize(normalized)
|
||||||
|
localStorage.setItem(FONT_SIZE_STORAGE_KEY, String(normalized))
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(lineHeight, (next) => {
|
||||||
|
if (!isHydrated.value) return
|
||||||
|
const normalized = clampLineHeight(next)
|
||||||
|
applyLineHeight(normalized)
|
||||||
|
localStorage.setItem(LINE_HEIGHT_STORAGE_KEY, String(normalized))
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(sidebarCollapsed, (collapsed) => {
|
||||||
|
if (typeof document === 'undefined') return
|
||||||
|
document.body.classList.toggle('ev-sidebar-collapsed', collapsed)
|
||||||
|
localStorage.setItem(SIDEBAR_COLLAPSED_KEY, String(collapsed))
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DefaultTheme.Layout>
|
||||||
|
<template v-if="!isHomePage && !isWelcomePage" #nav-bar-title-before>
|
||||||
|
<button
|
||||||
|
class="ev-sidebar-nav-btn"
|
||||||
|
type="button"
|
||||||
|
:aria-label="sidebarCollapsed ? '展开目录' : '收起目录'"
|
||||||
|
@click.stop.prevent="toggleSidebar"
|
||||||
|
>
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
||||||
|
<rect x="1" y="2" width="14" height="1.5" rx="0.75" />
|
||||||
|
<rect x="1" y="7.25" width="14" height="1.5" rx="0.75" />
|
||||||
|
<rect x="1" y="12.5" width="14" height="1.5" rx="0.75" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
<template #doc-before>
|
||||||
|
<CopyOrDownloadAsMarkdownButtons />
|
||||||
|
</template>
|
||||||
|
<template #nav-bar-content-after>
|
||||||
|
<GitHubStars />
|
||||||
|
<ClientOnly>
|
||||||
|
<PageSlidesButton />
|
||||||
|
</ClientOnly>
|
||||||
|
<ClientOnly>
|
||||||
|
<el-popover
|
||||||
|
placement="bottom-end"
|
||||||
|
trigger="click"
|
||||||
|
:width="260"
|
||||||
|
>
|
||||||
|
<template #reference>
|
||||||
|
<button
|
||||||
|
class="ev-fontsize-button"
|
||||||
|
type="button"
|
||||||
|
aria-label="阅读设置"
|
||||||
|
style="margin-left: 16px; padding: 0; width: 32px"
|
||||||
|
>
|
||||||
|
<el-icon :size="16">
|
||||||
|
<Setting />
|
||||||
|
</el-icon>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
<div class="ev-fontsize-panel">
|
||||||
|
<div class="ev-setting-group">
|
||||||
|
<div class="ev-setting-header">
|
||||||
|
<div class="ev-setting-title">
|
||||||
|
字号
|
||||||
|
</div>
|
||||||
|
<div class="ev-setting-value">
|
||||||
|
{{ fontSize }}px
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ev-fontsize-actions">
|
||||||
|
<button
|
||||||
|
class="ev-fontsize-action"
|
||||||
|
type="button"
|
||||||
|
@click="decreaseFontSize"
|
||||||
|
>
|
||||||
|
A-
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="ev-fontsize-action"
|
||||||
|
type="button"
|
||||||
|
@click="resetFontSize"
|
||||||
|
>
|
||||||
|
默认
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="ev-fontsize-action"
|
||||||
|
type="button"
|
||||||
|
@click="increaseFontSize"
|
||||||
|
>
|
||||||
|
A+
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<el-slider
|
||||||
|
v-model="fontSize"
|
||||||
|
:min="MIN_FONT_SIZE"
|
||||||
|
:max="MAX_FONT_SIZE"
|
||||||
|
:step="1"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ev-setting-group">
|
||||||
|
<div class="ev-setting-header">
|
||||||
|
<div class="ev-setting-title">
|
||||||
|
行距
|
||||||
|
</div>
|
||||||
|
<div class="ev-setting-value">
|
||||||
|
{{ lineHeight.toFixed(2) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ev-fontsize-actions">
|
||||||
|
<button
|
||||||
|
class="ev-fontsize-action"
|
||||||
|
type="button"
|
||||||
|
@click="resetLineHeight"
|
||||||
|
>
|
||||||
|
默认
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="ev-fontsize-action"
|
||||||
|
type="button"
|
||||||
|
@click="lineHeight = clampLineHeight(lineHeight - 0.05)"
|
||||||
|
>
|
||||||
|
更紧
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="ev-fontsize-action"
|
||||||
|
type="button"
|
||||||
|
@click="lineHeight = clampLineHeight(lineHeight + 0.05)"
|
||||||
|
>
|
||||||
|
更松
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<el-slider
|
||||||
|
v-model="lineHeight"
|
||||||
|
:min="MIN_LINE_HEIGHT"
|
||||||
|
:max="MAX_LINE_HEIGHT"
|
||||||
|
:step="0.05"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-popover>
|
||||||
|
</ClientOnly>
|
||||||
|
</template>
|
||||||
|
<template #home-hero-info-before>
|
||||||
|
<button
|
||||||
|
v-if="frontmatter.layout === 'home'"
|
||||||
|
class="vp-home-wordmark"
|
||||||
|
type="button"
|
||||||
|
aria-label="打开欢迎页"
|
||||||
|
@click="openWelcomeFromWordmark"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 460 220"
|
||||||
|
class="vp-home-wordmark-svg"
|
||||||
|
>
|
||||||
|
<defs>
|
||||||
|
<linearGradient
|
||||||
|
id="home-hero-ocean"
|
||||||
|
x1="0"
|
||||||
|
y1="0"
|
||||||
|
x2="460"
|
||||||
|
y2="0"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop offset="0%" stop-color="#06b6d4" />
|
||||||
|
<stop offset="50%" stop-color="#0ea5e9" />
|
||||||
|
<stop offset="100%" stop-color="#3b82f6" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<path
|
||||||
|
v-for="(path, index) in easyVibePaths"
|
||||||
|
:key="index"
|
||||||
|
:d="path"
|
||||||
|
class="vp-home-wordmark-path"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
<template #home-hero-info-after>
|
||||||
|
<div
|
||||||
|
v-if="
|
||||||
|
frontmatter.layout === 'home' &&
|
||||||
|
(frontmatter.hero?.tagline || frontmatter.hero?.typingTagline)
|
||||||
|
"
|
||||||
|
class="vp-typed-tagline"
|
||||||
|
>
|
||||||
|
<ClientOnly>
|
||||||
|
<TextType
|
||||||
|
:text="frontmatter.hero.typingTagline || frontmatter.hero.tagline"
|
||||||
|
v-bind="homeTaglineTyping"
|
||||||
|
:loop="true"
|
||||||
|
/>
|
||||||
|
</ClientOnly>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</DefaultTheme.Layout>
|
||||||
|
<ClientOnly>
|
||||||
|
<div
|
||||||
|
v-if="!isHomePage && !isWelcomePage"
|
||||||
|
class="ev-sidebar-hover-area"
|
||||||
|
:class="{ collapsed: sidebarCollapsed, resizing: sidebarResizing }"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="!sidebarCollapsed"
|
||||||
|
class="ev-sidebar-resizer"
|
||||||
|
role="separator"
|
||||||
|
aria-orientation="vertical"
|
||||||
|
@pointerdown="startSidebarResize"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
class="ev-sidebar-toggle-btn"
|
||||||
|
:class="{ collapsed: sidebarCollapsed }"
|
||||||
|
type="button"
|
||||||
|
:aria-label="sidebarCollapsed ? '展开目录' : '收起目录'"
|
||||||
|
@click="toggleSidebar"
|
||||||
|
>
|
||||||
|
<svg width="12" height="12" viewBox="0 0 12 12" fill="currentColor">
|
||||||
|
<path v-if="!sidebarCollapsed" d="M8 1L3 6l5 5" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
|
<path v-else d="M4 1l5 5-5 5" stroke="currentColor" stroke-width="1.5" fill="none" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</ClientOnly>
|
||||||
|
<ClientOnly>
|
||||||
|
<ReadingProgress v-if="!isHomePage && !isWelcomePage" />
|
||||||
|
</ClientOnly>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.VPNavBarTitle .VPImage.logo,
|
||||||
|
.VPNavBarTitle .logo {
|
||||||
|
width: 84px !important;
|
||||||
|
height: 40px !important;
|
||||||
|
max-width: 84px !important;
|
||||||
|
max-height: 40px !important;
|
||||||
|
object-fit: contain;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 隐藏默认的 tagline,因为我们用打字机效果替代了它 */
|
||||||
|
.VPHomeHero .tagline {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 调整打字机容器的样式,使其看起来像原来的 tagline */
|
||||||
|
.vp-typed-tagline {
|
||||||
|
padding-top: 0;
|
||||||
|
margin-top: 8px;
|
||||||
|
line-height: 28px;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
min-height: 28px;
|
||||||
|
display: flex;
|
||||||
|
/* 居中对齐 */
|
||||||
|
text-align: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 强制 HomeHero 内容居中 */
|
||||||
|
.VPHomeHero .container {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.VPHomeHero .main {
|
||||||
|
margin: -18px auto 0;
|
||||||
|
}
|
||||||
|
.VPHomeHero .name,
|
||||||
|
.VPHomeHero .text {
|
||||||
|
text-align: center;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
.VPHomeHero .name {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.VPHomeHero .text {
|
||||||
|
color: var(--vp-c-text-1) !important;
|
||||||
|
}
|
||||||
|
.VPHomeHero .actions {
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.vp-home-wordmark {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: -12px;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.vp-home-wordmark-svg {
|
||||||
|
width: min(380px, 52vw);
|
||||||
|
height: auto;
|
||||||
|
filter: none;
|
||||||
|
}
|
||||||
|
.vp-home-wordmark-path {
|
||||||
|
fill: url(#home-hero-ocean);
|
||||||
|
stroke: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
.vp-typed-tagline {
|
||||||
|
line-height: 32px;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 960px) {
|
||||||
|
.vp-typed-tagline {
|
||||||
|
line-height: 36px;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ev-fontsize-button {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 32px;
|
||||||
|
min-width: 32px;
|
||||||
|
padding: 0 10px;
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 999px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ev-fontsize-button:hover {
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
color: var(--vp-c-brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ev-fontsize-panel {
|
||||||
|
display: grid;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ev-setting-group {
|
||||||
|
display: grid;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ev-setting-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ev-setting-title {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ev-setting-value {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ev-fontsize-actions {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ev-fontsize-action {
|
||||||
|
height: 32px;
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 10px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ev-fontsize-action:hover {
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
color: var(--vp-c-brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
目录栏收起/展开
|
||||||
|
============================================ */
|
||||||
|
|
||||||
|
/* 导航栏左侧的收起按钮 */
|
||||||
|
.ev-sidebar-nav-btn {
|
||||||
|
display: none;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
cursor: pointer;
|
||||||
|
margin-right: 4px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.ev-sidebar-nav-btn:hover {
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 左侧边缘悬停区域 */
|
||||||
|
.ev-sidebar-hover-area {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
--ev-sidebar-divider-offset: 16px;
|
||||||
|
left: calc(var(--vp-sidebar-width, 272px) - var(--ev-sidebar-divider-offset));
|
||||||
|
width: 24px;
|
||||||
|
height: 100vh;
|
||||||
|
z-index: 30;
|
||||||
|
}
|
||||||
|
.ev-sidebar-hover-area.collapsed {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
.ev-sidebar-resizer {
|
||||||
|
position: absolute;
|
||||||
|
left: var(--ev-sidebar-divider-offset);
|
||||||
|
top: 0;
|
||||||
|
width: 2px;
|
||||||
|
height: 100%;
|
||||||
|
background: var(--vp-c-divider);
|
||||||
|
opacity: 0;
|
||||||
|
cursor: col-resize;
|
||||||
|
transition: opacity 0.2s ease, background-color 0.2s ease;
|
||||||
|
}
|
||||||
|
.ev-sidebar-hover-area:hover .ev-sidebar-resizer,
|
||||||
|
.ev-sidebar-hover-area.resizing .ev-sidebar-resizer {
|
||||||
|
opacity: 1;
|
||||||
|
background: var(--vp-c-brand-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 分界线上的收起按钮 */
|
||||||
|
.ev-sidebar-toggle-btn {
|
||||||
|
display: flex;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
left: calc(var(--ev-sidebar-divider-offset) - 4px);
|
||||||
|
width: 18px;
|
||||||
|
height: 36px;
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 0 4px 4px 0;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
color: var(--vp-c-text-3);
|
||||||
|
cursor: pointer;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: opacity 0.5s ease;
|
||||||
|
opacity: 0;
|
||||||
|
animation: ev-sidebar-btn-flash 2.5s ease-out 0.5s;
|
||||||
|
}
|
||||||
|
@keyframes ev-sidebar-btn-flash {
|
||||||
|
0% { opacity: 0; }
|
||||||
|
20% { opacity: 0.7; }
|
||||||
|
60% { opacity: 0.7; }
|
||||||
|
100% { opacity: 0; }
|
||||||
|
}
|
||||||
|
.ev-sidebar-toggle-btn:hover {
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
opacity: 1;
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
.ev-sidebar-hover-area:hover .ev-sidebar-toggle-btn {
|
||||||
|
opacity: 0.7;
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
.ev-sidebar-hover-area.resizing .ev-sidebar-toggle-btn {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 桌面端才显示按钮 */
|
||||||
|
@media (min-width: 960px) {
|
||||||
|
.ev-sidebar-nav-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
.ev-sidebar-hover-area {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @1440px 时分界线按钮跟随侧边栏实际宽度 */
|
||||||
|
@media (min-width: 1440px) {
|
||||||
|
.ev-sidebar-hover-area:not(.collapsed) {
|
||||||
|
left: calc((100% - (var(--vp-layout-max-width, 1440px) - 64px)) / 2 + var(--vp-sidebar-width, 272px) - var(--ev-sidebar-divider-offset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- 收起状态下的 CSS 覆盖 ---- */
|
||||||
|
|
||||||
|
/* 隐藏侧边栏 — 仅桌面端,避免覆盖移动端的汉堡菜单 */
|
||||||
|
@media (min-width: 960px) {
|
||||||
|
.ev-sidebar-collapsed .VPSidebar {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 修复侧边栏收起后导航栏标题 border-bottom 重叠问题 */
|
||||||
|
.ev-sidebar-collapsed .VPNavBar.has-sidebar .VPNavBarTitle .title {
|
||||||
|
border-bottom-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内容区域填满页面 */
|
||||||
|
@media (min-width: 960px) {
|
||||||
|
.ev-sidebar-collapsed .VPContent.has-sidebar {
|
||||||
|
padding-left: 0 !important;
|
||||||
|
}
|
||||||
|
.ev-sidebar-collapsed .VPNavBar.has-sidebar .content {
|
||||||
|
padding-left: 0 !important;
|
||||||
|
}
|
||||||
|
.ev-sidebar-collapsed .VPNavBar.has-sidebar .divider {
|
||||||
|
padding-left: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1440px) {
|
||||||
|
.ev-sidebar-collapsed .VPContent.has-sidebar {
|
||||||
|
padding-left: calc((100% - var(--vp-layout-max-width, 1440px)) / 2) !important;
|
||||||
|
}
|
||||||
|
.ev-sidebar-collapsed .VPNavBar.has-sidebar .content {
|
||||||
|
padding-left: calc((100% - var(--vp-layout-max-width, 1440px)) / 2) !important;
|
||||||
|
}
|
||||||
|
.ev-sidebar-collapsed .VPNavBar.has-sidebar .divider {
|
||||||
|
padding-left: calc((100% - var(--vp-layout-max-width, 1440px)) / 2) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 收起/展开过渡动画 */
|
||||||
|
.VPSidebar,
|
||||||
|
.VPContent.has-sidebar,
|
||||||
|
.VPNavBar.has-sidebar .content,
|
||||||
|
.VPNavBar.has-sidebar .divider {
|
||||||
|
transition: padding-left 0.3s ease, transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ev-sidebar-resizing,
|
||||||
|
.ev-sidebar-resizing * {
|
||||||
|
cursor: col-resize !important;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ev-sidebar-resizing .VPSidebar,
|
||||||
|
.ev-sidebar-resizing .VPContent.has-sidebar,
|
||||||
|
.ev-sidebar-resizing .VPNavBar.has-sidebar .content,
|
||||||
|
.ev-sidebar-resizing .VPNavBar.has-sidebar .divider {
|
||||||
|
transition: none !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,576 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { withBase } from 'vitepress'
|
||||||
|
|
||||||
|
const categories = [
|
||||||
|
{
|
||||||
|
id: 'computer-fundamentals',
|
||||||
|
name: '计算机基础',
|
||||||
|
icon: '💻',
|
||||||
|
color: '#10b981',
|
||||||
|
bgGradient: 'linear-gradient(135deg, #10b98115, #10b98108)',
|
||||||
|
description: '理解计算机最底层的工作原理',
|
||||||
|
whyLearn: '这是所有软件工程的基础。掌握计算机如何执行代码、管理内存、处理请求,能帮助你写出更高效的代码。',
|
||||||
|
learningGoals: ['CPU 与内存原理', '操作系统核心', '网络通信基础', '数据结构与算法'],
|
||||||
|
articles: [
|
||||||
|
{ title: 'Vibe Coding 全栈开发', path: '/zh-cn/appendix/1-computer-fundamentals/vibe-coding-fullstack', description: 'AI 辅助时代下的全栈开发全景图', detail: '从前端到后端、从数据库到部署,梳理 AI 辅助时代下全栈工程师需要掌握的完整技能树,帮你建立全局视野。' },
|
||||||
|
{ title: '从晶体管到 CPU', path: '/zh-cn/appendix/1-computer-fundamentals/transistor-to-cpu', description: '理解计算机最底层的硬件逻辑', detail: '从最基本的晶体管开关出发,逐步构建逻辑门、加法器、寄存器,最终理解 CPU 如何一步步执行你写的每一行代码。' },
|
||||||
|
{ title: '操作系统', path: '/zh-cn/appendix/1-computer-fundamentals/operating-systems', description: '进程管理、内存管理、文件系统', detail: '操作系统是硬件与软件之间的桥梁。了解进程调度、虚拟内存、文件系统的工作原理,理解程序运行的底层环境。' },
|
||||||
|
{ title: '数据结构', path: '/zh-cn/appendix/1-computer-fundamentals/data-structures', description: '数组、链表、树、图的组织方式', detail: '数据结构决定了程序如何高效地存储和访问数据。掌握数组、链表、栈、队列、树、图等核心结构及其适用场景。' },
|
||||||
|
{ title: '算法思维入门', path: '/zh-cn/appendix/1-computer-fundamentals/algorithm-thinking', description: '排序、搜索、递归的思维框架', detail: '算法是解决问题的思维方式。通过排序、搜索、递归、动态规划等经典问题,培养分析和拆解复杂问题的能力。' },
|
||||||
|
{ title: '编程语言图谱', path: '/zh-cn/appendix/1-computer-fundamentals/programming-languages', description: '从汇编到高级语言的演进', detail: '从机器码到汇编、从 C 到 Python,了解编程语言的演进历程、分类方式和各自的设计哲学与适用领域。' },
|
||||||
|
{ title: '网络基础', path: '/zh-cn/appendix/1-computer-fundamentals/computer-networks', description: '从网线到互联网的通信原理', detail: '从物理层到应用层,理解 TCP/IP 协议栈、DNS 解析、HTTP 通信等网络基础,搞懂两台电脑如何跨越万里对话。' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'development-tools',
|
||||||
|
name: '开发工具',
|
||||||
|
icon: '🔧',
|
||||||
|
color: '#3b82f6',
|
||||||
|
bgGradient: 'linear-gradient(135deg, #3b82f615, #3b82f608)',
|
||||||
|
description: '熟练使用命令行、Git、IDE 等工具',
|
||||||
|
whyLearn: '工具是开发者的武器。掌握高效的工具使用能让你事半功倍,减少重复劳动。',
|
||||||
|
learningGoals: ['IDE 高效使用', 'Git 版本控制', '命令行操作', '调试与排查'],
|
||||||
|
articles: [
|
||||||
|
{ title: 'IDE 基础', path: '/zh-cn/appendix/2-development-tools/ide-basics', description: 'VS Code、Cursor、Trae 的使用技巧', detail: '对比主流 IDE 的核心功能,掌握快捷键、插件生态、代码片段等提效技巧,让编辑器成为你最顺手的武器。' },
|
||||||
|
{ title: '命令行与 Shell', path: '/zh-cn/appendix/2-development-tools/command-line-shell', description: '终端操作与脚本自动化', detail: '从基础命令到 Shell 脚本编写,学会用命令行高效操作文件、管理进程、自动化重复任务,告别鼠标依赖。' },
|
||||||
|
{ title: 'Git 版本控制', path: '/zh-cn/appendix/2-development-tools/git-version-control', description: '版本控制与团队协作', detail: '从 init 到 rebase,系统掌握 Git 的分支模型、合并策略、冲突解决,理解团队协作中的 Git 工作流。' },
|
||||||
|
{ title: '环境变量与 PATH', path: '/zh-cn/appendix/2-development-tools/environment-path', description: '系统环境配置与问题排查', detail: '理解 PATH 的查找机制、环境变量的作用域,学会排查「命令找不到」「版本不对」等常见开发环境问题。' },
|
||||||
|
{ title: '包管理器', path: '/zh-cn/appendix/2-development-tools/package-managers', description: 'npm、pip、cargo 依赖管理', detail: '了解包管理器如何解决依赖地狱问题,掌握 npm、pip、cargo 等工具的使用方式和 lock 文件的意义。' },
|
||||||
|
{ title: '调试的艺术', path: '/zh-cn/appendix/2-development-tools/debugging-art/', description: '断点调试与问题定位', detail: '从 console.log 到断点调试,掌握系统化的问题定位方法论,学会用 DevTools、日志分析快速找到 Bug 根因。' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'browser-frontend',
|
||||||
|
name: '浏览器与前端',
|
||||||
|
icon: '🌍',
|
||||||
|
color: '#f59e0b',
|
||||||
|
bgGradient: 'linear-gradient(135deg, #f59e0b15, #f59e0b08)',
|
||||||
|
description: '掌握浏览器原理和前端开发技术',
|
||||||
|
whyLearn: '浏览器是用户接触软件的入口。理解浏览器如何渲染页面,能帮助你构建更流畅的 Web 应用。',
|
||||||
|
learningGoals: ['浏览器渲染原理', 'JavaScript 核心', '前端框架对比', '前端工程化'],
|
||||||
|
articles: [
|
||||||
|
{ title: 'JavaScript 深入', path: '/zh-cn/appendix/3-browser-and-frontend/javascript-deep-dive', description: '闭包、原型链、异步核心概念', detail: '深入理解 JavaScript 的闭包机制、原型继承链、事件循环与 Promise 异步模型,夯实前端开发的语言基础。' },
|
||||||
|
{ title: 'TypeScript', path: '/zh-cn/appendix/3-browser-and-frontend/typescript', description: '类型安全与接口定义', detail: '学习如何用类型系统在编译期捕获错误,掌握接口、泛型、类型推断等核心特性,写出更健壮的前端代码。' },
|
||||||
|
{ title: '浏览器是一个操作系统', path: '/zh-cn/appendix/3-browser-and-frontend/browser-as-os', description: '进程模型与资源管理', detail: '现代浏览器拥有多进程架构、沙箱隔离、任务调度等操作系统级能力。理解这些机制,才能写出高性能的 Web 应用。' },
|
||||||
|
{ title: '浏览器渲染管道', path: '/zh-cn/appendix/3-browser-and-frontend/browser-as-os-rendering', description: 'DOM、CSSOM、布局与绘制', detail: '从 HTML 解析到像素上屏,完整拆解浏览器渲染管道的每个阶段,理解重排与重绘的性能影响。' },
|
||||||
|
{ title: '前端框架对比', path: '/zh-cn/appendix/3-browser-and-frontend/frontend-frameworks', description: 'React、Vue、Svelte、Angular', detail: '横向对比主流前端框架的设计理念、响应式机制、生态系统和适用场景,帮你做出合理的技术选型。' },
|
||||||
|
{ title: '前端工程化', path: '/zh-cn/appendix/3-browser-and-frontend/frontend-engineering', description: '构建工具与模块化', detail: '从 Webpack 到 Vite,理解模块打包、代码分割、Tree Shaking 等工程化实践,搭建高效的前端开发流水线。' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'server-backend',
|
||||||
|
name: '服务端与后端',
|
||||||
|
icon: '⚙️',
|
||||||
|
color: '#8b5cf6',
|
||||||
|
bgGradient: 'linear-gradient(135deg, #8b5cf615, #8b5cf608)',
|
||||||
|
description: '构建可靠的后端服务和 API',
|
||||||
|
whyLearn: '后端是应用的神经中枢。学会设计 API、处理数据,能让你独立完成全栈开发。',
|
||||||
|
learningGoals: ['HTTP 协议', 'API 设计原则', '认证与授权', '缓存与消息队列'],
|
||||||
|
articles: [
|
||||||
|
{ title: '后端语言对比', path: '/zh-cn/appendix/4-server-and-backend/backend-languages', description: 'Go、Node.js、Python 后端选型', detail: '从性能、生态、开发效率等维度对比主流后端语言,帮你根据项目需求选择最合适的技术栈。' },
|
||||||
|
{ title: 'HTTP 协议', path: '/zh-cn/appendix/4-server-and-backend/http-protocol', description: '请求响应与状态码', detail: '深入理解 HTTP 请求方法、状态码、头部字段、Cookie 与缓存机制,这是所有 Web 开发的通信基础。' },
|
||||||
|
{ title: 'API 设计哲学', path: '/zh-cn/appendix/4-server-and-backend/api-design', description: 'RESTful 与 GraphQL 设计', detail: '对比 REST、GraphQL、gRPC 三种 API 风格的设计理念与适用场景,学会设计清晰、一致、易用的接口。' },
|
||||||
|
{ title: 'Web 框架的本质', path: '/zh-cn/appendix/4-server-and-backend/web-frameworks', description: '路由、中间件、模板引擎', detail: '剥开框架的外衣,理解路由匹配、中间件管道、请求上下文等核心机制,知其然更知其所以然。' },
|
||||||
|
{ title: '认证与授权', path: '/zh-cn/appendix/4-server-and-backend/auth-authorization', description: 'JWT、OAuth 与权限控制', detail: '从 Session 到 JWT,从密码登录到 OAuth 第三方授权,系统掌握用户身份验证与权限控制的完整方案。' },
|
||||||
|
{ title: '缓存策略', path: '/zh-cn/appendix/4-server-and-backend/caching', description: 'Redis 与 CDN 缓存', detail: '理解浏览器缓存、CDN 缓存、Redis 应用缓存的分层架构,学会用缓存策略大幅提升系统响应速度。' },
|
||||||
|
{ title: '消息队列', path: '/zh-cn/appendix/4-server-and-backend/message-queues', description: 'RabbitMQ、Kafka 应用', detail: '了解消息队列如何实现服务解耦、流量削峰和异步处理,对比 RabbitMQ 与 Kafka 的架构差异与适用场景。' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'data',
|
||||||
|
name: '数据',
|
||||||
|
icon: '📊',
|
||||||
|
color: '#ec4899',
|
||||||
|
bgGradient: 'linear-gradient(135deg, #ec489915, #ec489908)',
|
||||||
|
description: '掌握数据库和数据分析技能',
|
||||||
|
whyLearn: '数据是现代应用的核心资产。学会存储、查询、分析数据,能帮助你做出数据驱动的决策。',
|
||||||
|
learningGoals: ['SQL 查询', '数据库原理', '数据模型设计', '数据分析基础'],
|
||||||
|
articles: [
|
||||||
|
{ title: 'SQL', path: '/zh-cn/appendix/5-data/sql', description: '查询、聚合与事务', detail: '从 SELECT 到子查询,从 JOIN 到事务控制,系统学习 SQL 语言,掌握与数据库对话的核心能力。' },
|
||||||
|
{ title: '数据库原理', path: '/zh-cn/appendix/5-data/database-fundamentals', description: '索引、事务与隔离级别', detail: '深入 B+ 树索引结构、ACID 事务特性、MVCC 并发控制,理解数据库引擎如何保证数据的正确与高效。' },
|
||||||
|
{ title: '数据模型全景', path: '/zh-cn/appendix/5-data/data-models', description: '关系型 vs NoSQL vs NewSQL', detail: '对比关系型、文档型、图数据库、时序数据库等不同数据模型的设计理念,学会根据业务场景选择合适的存储方案。' },
|
||||||
|
{ title: '数据分析基础', path: '/zh-cn/appendix/5-data/data-analysis', description: 'Excel、SQL 与 BI 可视化', detail: '从数据采集到指标体系搭建,掌握漏斗分析、留存分析等常用方法,学会用数据驱动产品和业务决策。' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'architecture',
|
||||||
|
name: '架构设计',
|
||||||
|
icon: '🏗️',
|
||||||
|
color: '#14b8a6',
|
||||||
|
bgGradient: 'linear-gradient(135deg, #14b8a615, #14b8a608)',
|
||||||
|
description: '学习系统设计和架构模式',
|
||||||
|
whyLearn: '架构决定系统的未来。学会从宏观角度设计系统,能让你构建可扩展的大型应用。',
|
||||||
|
learningGoals: ['微服务架构', '分布式系统', '高可用设计', '系统设计方法论'],
|
||||||
|
articles: [
|
||||||
|
{ title: '从单体到微服务', path: '/zh-cn/appendix/6-architecture-and-system-design/monolith-to-microservices', description: '服务拆分与架构演进', detail: '理解单体架构的瓶颈,学习何时拆分、如何拆分微服务,以及拆分后面临的服务发现、数据一致性等新挑战。' },
|
||||||
|
{ title: '分布式系统', path: '/zh-cn/appendix/6-architecture-and-system-design/distributed-systems', description: 'CAP 定理与一致性', detail: '深入 CAP 定理、分布式事务、一致性协议(Paxos/Raft),理解分布式环境下数据一致性与可用性的权衡。' },
|
||||||
|
{ title: '高可用与容灾', path: '/zh-cn/appendix/6-architecture-and-system-design/high-availability', description: '负载均衡与故障转移', detail: '学习负载均衡策略、主从切换、异地多活、熔断降级等高可用设计模式,让系统在故障面前依然稳定运行。' },
|
||||||
|
{ title: '系统设计方法论', path: '/zh-cn/appendix/6-architecture-and-system-design/system-design-methodology', description: '从需求到方案的思路', detail: '掌握系统设计面试与实战中的思维框架:需求分析、容量估算、核心模块设计、瓶颈识别与架构权衡。' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'infrastructure',
|
||||||
|
name: '基础设施',
|
||||||
|
icon: '☁️',
|
||||||
|
color: '#06b6d4',
|
||||||
|
bgGradient: 'linear-gradient(135deg, #06b6d415, #06b6d408)',
|
||||||
|
description: '掌握云原生和运维技能',
|
||||||
|
whyLearn: '基础设施是应用的底座。学会容器化、自动化部署,能让你高效地运维应用。',
|
||||||
|
learningGoals: ['Linux 基础', 'Docker 容器化', 'Kubernetes', 'CI/CD 自动化'],
|
||||||
|
articles: [
|
||||||
|
{ title: 'Linux 基础', path: '/zh-cn/appendix/7-infrastructure-and-operations/linux-basics', description: '文件系统与进程管理', detail: '掌握 Linux 文件权限、进程管理、系统监控等核心操作,这是服务器运维和容器化部署的必备基础。' },
|
||||||
|
{ title: 'Docker 容器化', path: '/zh-cn/appendix/7-infrastructure-and-operations/docker-containers', description: '镜像、容器与网络', detail: '从 Dockerfile 编写到镜像构建,从容器网络到数据卷挂载,学会用 Docker 将应用打包成可移植的标准化单元。' },
|
||||||
|
{ title: 'Kubernetes', path: '/zh-cn/appendix/7-infrastructure-and-operations/kubernetes', description: 'Pod、Deployment 与 Service', detail: '理解 K8s 的核心概念:Pod 调度、Deployment 滚动更新、Service 服务发现,掌握容器编排的行业标准工具。' },
|
||||||
|
{ title: 'CI/CD 自动化', path: '/zh-cn/appendix/7-infrastructure-and-operations/ci-cd', description: 'GitHub Actions 与流水线', detail: '学习持续集成与持续部署的理念,用 GitHub Actions 搭建自动化流水线,实现代码提交后自动测试、构建和部署。' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'ai',
|
||||||
|
name: '人工智能',
|
||||||
|
icon: '🤖',
|
||||||
|
color: '#f97316',
|
||||||
|
bgGradient: 'linear-gradient(135deg, #f9731615, #f9731608)',
|
||||||
|
description: '了解 AI 原理和 LLM 应用开发',
|
||||||
|
whyLearn: 'AI 正在改变软件开发的方式。理解大语言模型,能帮助你更好地利用 AI 提升效率。',
|
||||||
|
learningGoals: ['神经网络基础', 'Transformer 架构', 'LLM 原理', 'RAG 与 Agent'],
|
||||||
|
articles: [
|
||||||
|
{ title: 'AI 简史', path: '/zh-cn/appendix/8-artificial-intelligence/ai-history', description: '从专家系统到深度学习', detail: '回顾 AI 从图灵测试到 GPT 的关键里程碑,理解每次技术突破背后的核心思想转变与驱动力。' },
|
||||||
|
{ title: '神经网络', path: '/zh-cn/appendix/8-artificial-intelligence/neural-networks', description: '感知机与反向传播', detail: '从单个神经元到多层网络,理解前向传播、损失函数、反向传播与梯度下降,这是所有深度学习的基石。' },
|
||||||
|
{ title: 'Transformer', path: '/zh-cn/appendix/8-artificial-intelligence/transformer-attention', description: '注意力机制与自注意力', detail: '深入 Transformer 架构的核心——自注意力机制,理解它如何让模型捕捉长距离依赖,成为现代大模型的基础。' },
|
||||||
|
{ title: '大语言模型原理', path: '/zh-cn/appendix/8-artificial-intelligence/llm-principles', description: '预训练与指令微调', detail: '从海量文本预训练到 RLHF 对齐,拆解 GPT、Claude 等大语言模型的训练流程与核心工作原理。' },
|
||||||
|
{ title: 'RAG 架构', path: '/zh-cn/appendix/8-artificial-intelligence/rag', description: '检索增强生成实战', detail: '学习如何用向量检索为 LLM 注入外部知识,掌握 RAG 的完整流程:文档切分、Embedding、检索与生成。' },
|
||||||
|
{ title: 'AI Agent', path: '/zh-cn/appendix/8-artificial-intelligence/ai-agents', description: 'Agent 架构与工具调用', detail: '了解 AI Agent 如何通过规划、记忆、工具调用实现自主决策,掌握 ReAct、Function Calling 等核心模式。' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'engineering',
|
||||||
|
name: '工程素养',
|
||||||
|
icon: '✨',
|
||||||
|
color: '#a855f7',
|
||||||
|
bgGradient: 'linear-gradient(135deg, #a855f715, #a855f708)',
|
||||||
|
description: '提升代码质量和工程实践能力',
|
||||||
|
whyLearn: '代码是写给人看的。掌握设计模式、测试策略,能让你写出更优雅、更易维护的代码。',
|
||||||
|
learningGoals: ['设计模式', '代码重构', '测试策略', '技术写作'],
|
||||||
|
articles: [
|
||||||
|
{ title: '设计模式', path: '/zh-cn/appendix/9-engineering-excellence/design-patterns', description: 'SOLID 原则与 23 种模式', detail: '从 SOLID 五大原则到工厂、观察者、策略等经典模式,学会用设计模式解决代码中反复出现的结构性问题。' },
|
||||||
|
{ title: '代码质量与重构', path: '/zh-cn/appendix/9-engineering-excellence/code-quality-refactoring', description: '坏味道与重构手法', detail: '识别重复代码、过长函数、过度耦合等常见坏味道,掌握提取方法、内联变量、搬移字段等系统化重构手法。' },
|
||||||
|
{ title: '测试策略', path: '/zh-cn/appendix/9-engineering-excellence/testing-strategies', description: '单元测试、集成测试、E2E', detail: '理解测试金字塔的分层策略,学会编写单元测试、集成测试和端到端测试,用自动化测试守护代码质量。' },
|
||||||
|
{ title: '技术写作', path: '/zh-cn/appendix/9-engineering-excellence/technical-writing', description: '文档与 API 编写规范', detail: '学习如何写出清晰的 README、API 文档和技术方案,好的技术写作能力是高级工程师的核心软技能。' },
|
||||||
|
{ title: '开源协作', path: '/zh-cn/appendix/9-engineering-excellence/open-source-collaboration', description: 'Issue、PR 与社区参与', detail: '掌握 GitHub 开源协作流程:提 Issue、Fork 仓库、提交 PR、Code Review,学会参与和维护开源项目。' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const activeCategory = ref(categories[0].id)
|
||||||
|
const hoveredArticle = ref(null)
|
||||||
|
|
||||||
|
const toggleCategory = (id) => {
|
||||||
|
activeCategory.value = id
|
||||||
|
hoveredArticle.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
const articleCount = categories.reduce((sum, cat) => sum + cat.articles.length, 0)
|
||||||
|
|
||||||
|
const activeCategoryData = computed(() => {
|
||||||
|
if (!activeCategory.value) return null
|
||||||
|
return categories.find(cat => cat.id === activeCategory.value)
|
||||||
|
})
|
||||||
|
|
||||||
|
const hoveredArticleData = computed(() => {
|
||||||
|
if (!hoveredArticle.value || !activeCategoryData.value) return null
|
||||||
|
return activeCategoryData.value.articles.find(a => a.path === hoveredArticle.value)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="appendix-bento">
|
||||||
|
<div class="bento-header">
|
||||||
|
<h3 class="bento-title">探索附录</h3>
|
||||||
|
<p class="bento-subtitle">9 个主题方向 · {{ articleCount }} 篇文章</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bento-main">
|
||||||
|
<!-- 左侧:卡片网格 -->
|
||||||
|
<div class="bento-left">
|
||||||
|
<div class="bento-grid">
|
||||||
|
<div
|
||||||
|
v-for="category in categories"
|
||||||
|
:key="category.id"
|
||||||
|
class="bento-card"
|
||||||
|
:class="{ active: activeCategory === category.id }"
|
||||||
|
:style="{
|
||||||
|
'--card-color': category.color,
|
||||||
|
'--card-bg': category.bgGradient
|
||||||
|
}"
|
||||||
|
@click="toggleCategory(category.id)"
|
||||||
|
>
|
||||||
|
<div class="card-icon">{{ category.icon }}</div>
|
||||||
|
<div class="card-content">
|
||||||
|
<h4 class="card-title">{{ category.name }}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="card-indicator">
|
||||||
|
<span>{{ category.articles.length }} 篇 {{ activeCategory === category.id ? '↓' : '→' }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧:详情面板 -->
|
||||||
|
<div
|
||||||
|
class="detail-panel"
|
||||||
|
:style="{ '--panel-color': activeCategoryData.color }"
|
||||||
|
:key="activeCategoryData.id"
|
||||||
|
>
|
||||||
|
<div class="panel-header">
|
||||||
|
<div class="panel-title-row">
|
||||||
|
<span class="panel-icon">{{ hoveredArticleData ? '📄' : activeCategoryData.icon }}</span>
|
||||||
|
<div class="panel-title-group">
|
||||||
|
<h4 class="panel-title">{{ hoveredArticleData?.title || activeCategoryData.name }}</h4>
|
||||||
|
<p class="panel-desc">{{ hoveredArticleData?.description || activeCategoryData.description }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p class="intro-text">{{ hoveredArticleData?.detail || activeCategoryData.whyLearn }}</p>
|
||||||
|
</div>
|
||||||
|
<div v-if="!hoveredArticleData" class="panel-goals">
|
||||||
|
<h5 class="goals-title">能学到什么?</h5>
|
||||||
|
<div class="goals-list">
|
||||||
|
<span v-for="(goal, index) in activeCategoryData.learningGoals" :key="index" class="goal-tag">
|
||||||
|
{{ goal }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel-articles">
|
||||||
|
<div class="articles-header">
|
||||||
|
<span class="articles-icon">{{ activeCategoryData.icon }}</span>
|
||||||
|
<span class="articles-title">文章列表 ({{ activeCategoryData.articles.length }}篇)</span>
|
||||||
|
</div>
|
||||||
|
<div class="articles-list-scroll">
|
||||||
|
<a
|
||||||
|
v-for="article in activeCategoryData.articles"
|
||||||
|
:key="article.path"
|
||||||
|
:href="withBase(article.path)"
|
||||||
|
class="article-item"
|
||||||
|
:class="{ hover: hoveredArticle === article.path }"
|
||||||
|
@mouseenter="hoveredArticle = article.path"
|
||||||
|
@mouseleave="hoveredArticle = null"
|
||||||
|
>
|
||||||
|
<span class="article-bullet"></span>
|
||||||
|
<div class="article-info">
|
||||||
|
<span class="article-name">{{ article.title }}</span>
|
||||||
|
<span class="article-desc">{{ article.description }}</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.appendix-bento {
|
||||||
|
padding: 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bento-header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bento-title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
margin: 0 0 0.25rem;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bento-subtitle {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bento-main {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 280px;
|
||||||
|
height: 520px;
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bento-left {
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bento-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bento-card {
|
||||||
|
position: relative;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 1.25rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bento-card::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: var(--card-bg);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bento-card:hover::before {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bento-card:hover {
|
||||||
|
border-color: var(--card-color);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bento-card.active {
|
||||||
|
border-color: var(--card-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bento-card.active::before {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-icon {
|
||||||
|
font-size: 2rem;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-content {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
margin: 0 0 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-indicator {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--vp-c-text-3);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bento-card:hover .card-indicator {
|
||||||
|
color: var(--card-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 右侧面板 */
|
||||||
|
.detail-panel {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border-left: 1px solid var(--vp-c-divider);
|
||||||
|
overflow-y: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-header {
|
||||||
|
padding: 1rem;
|
||||||
|
border-bottom: 1px solid var(--vp-c-divider);
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
height: 200px;
|
||||||
|
overflow-y: auto;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-title-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.75rem;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-icon {
|
||||||
|
font-size: 1.75rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-title-group {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-title {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
margin: 0 0 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-desc {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-body {
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro-text {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
line-height: 1.5;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 学习目标 */
|
||||||
|
.panel-goals {
|
||||||
|
margin-top: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goals-title {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--panel-color);
|
||||||
|
margin: 0 0 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goals-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goal-tag {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
padding: 0.3rem 0.6rem;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 6px;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 文章列表区 */
|
||||||
|
.panel-articles {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.articles-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border-bottom: 1px solid var(--vp-c-divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
.articles-icon {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.articles-title {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--panel-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.articles-list-scroll {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.6rem;
|
||||||
|
padding: 0.6rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-item:hover,
|
||||||
|
.article-item.hover {
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-bullet {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--panel-color);
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-top: 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-info {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.15rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-name {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-desc {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.bento-main {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
height: auto;
|
||||||
|
max-height: 80vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bento-left {
|
||||||
|
max-height: 300px;
|
||||||
|
border-bottom: 1px solid var(--vp-c-divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-panel {
|
||||||
|
border-left: none;
|
||||||
|
max-height: 400px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.bento-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
<script setup>
|
||||||
|
import { withBase } from 'vitepress'
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
title: String,
|
||||||
|
description: String,
|
||||||
|
link: String,
|
||||||
|
tags: Array
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a
|
||||||
|
:href="withBase(link)"
|
||||||
|
class="article-card"
|
||||||
|
>
|
||||||
|
<div class="card-content">
|
||||||
|
<h3 class="title">{{ title }}</h3>
|
||||||
|
<p class="description">{{ description }}</p>
|
||||||
|
<div
|
||||||
|
v-if="tags && tags.length"
|
||||||
|
class="tags"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
v-for="tag in tags"
|
||||||
|
:key="tag"
|
||||||
|
class="tag"
|
||||||
|
>{{ tag }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="arrow">→</div>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.article-card {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at 100% -10%, color-mix(in srgb, var(--vp-c-brand-1) 10%, transparent), transparent 42%),
|
||||||
|
linear-gradient(160deg, color-mix(in srgb, var(--vp-c-brand-1) 6%, var(--vp-c-bg-soft)) 0%, var(--vp-c-bg-soft) 100%);
|
||||||
|
border: 1px solid color-mix(in srgb, var(--vp-c-brand-1) 10%, var(--vp-c-divider));
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 18px 20px;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: transform 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
|
||||||
|
height: 100%;
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-card:hover {
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
transform: translateY(-4px) scale(1.01);
|
||||||
|
box-shadow: 0 18px 40px rgba(0, 113, 227, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .article-card:hover {
|
||||||
|
box-shadow: 0 18px 36px rgba(0, 0, 0, 0.32);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-content {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin: 0 0 10px;
|
||||||
|
font-size: 1.08rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
line-height: 1.4;
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
line-height: 1.65;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tags {
|
||||||
|
margin-top: 14px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
padding: 4px 10px;
|
||||||
|
border-radius: 999px;
|
||||||
|
background-color: color-mix(in srgb, var(--vp-c-brand-1) 10%, var(--vp-c-bg-mute));
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrow {
|
||||||
|
margin-left: 16px;
|
||||||
|
margin-top: 2px;
|
||||||
|
font-size: 1rem;
|
||||||
|
color: var(--vp-c-text-3);
|
||||||
|
transition: transform 0.2s;
|
||||||
|
line-height: 1;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-card:hover .arrow {
|
||||||
|
transform: translateX(4px);
|
||||||
|
color: var(--vp-c-brand);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<script setup>
|
||||||
|
import ArticleCard from './ArticleCard.vue'
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
items: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="article-grid">
|
||||||
|
<ArticleCard
|
||||||
|
v-for="(item, i) in items"
|
||||||
|
:key="i"
|
||||||
|
v-bind="item"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.article-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||||
|
gap: 18px;
|
||||||
|
margin-top: 24px;
|
||||||
|
margin-bottom: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.article-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 14px;
|
||||||
|
margin-top: 18px;
|
||||||
|
margin-bottom: 28px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
<script setup>
|
||||||
|
import ArticleCard from './ArticleCard.vue'
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
categories: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="category-index">
|
||||||
|
<div
|
||||||
|
v-for="(category, index) in categories"
|
||||||
|
:key="index"
|
||||||
|
class="category-section"
|
||||||
|
>
|
||||||
|
<h2
|
||||||
|
v-if="category.title"
|
||||||
|
class="category-title"
|
||||||
|
>
|
||||||
|
{{ category.title }}
|
||||||
|
</h2>
|
||||||
|
<p
|
||||||
|
v-if="category.description"
|
||||||
|
class="category-desc"
|
||||||
|
>
|
||||||
|
{{ category.description }}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card-grid">
|
||||||
|
<ArticleCard
|
||||||
|
v-for="(item, i) in category.items"
|
||||||
|
:key="i"
|
||||||
|
v-bind="item"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.category-index {
|
||||||
|
margin-top: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-section {
|
||||||
|
margin-bottom: 52px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-title {
|
||||||
|
font-size: 1.65rem;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
border-bottom: none;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-desc {
|
||||||
|
font-size: 1rem;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
line-height: 1.68;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||||
|
gap: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.category-section {
|
||||||
|
margin-bottom: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-title {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,336 @@
|
|||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { useI18n } from '../composables/useI18n.js'
|
||||||
|
import chapterIntroductionLocale from '../locales/chapter-introduction/index.js'
|
||||||
|
|
||||||
|
const { t } = useI18n(chapterIntroductionLocale)
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
duration: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
expectedOutput: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
coreOutput: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
assignment: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
tags: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const hasMeta = computed(
|
||||||
|
() =>
|
||||||
|
props.duration ||
|
||||||
|
props.expectedOutput ||
|
||||||
|
props.coreOutput ||
|
||||||
|
props.assignment
|
||||||
|
)
|
||||||
|
const hasTags = computed(() => props.tags && props.tags.length > 0)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="chapter-introduction">
|
||||||
|
<!-- Learning Objective -->
|
||||||
|
<div class="objective-section">
|
||||||
|
<div class="objective-label">
|
||||||
|
<span class="icon">🎯</span>
|
||||||
|
<span class="title">{{ t('title') }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<!-- If tags are provided, show tags list -->
|
||||||
|
<div
|
||||||
|
v-if="hasTags"
|
||||||
|
class="tags-container"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
v-for="(tag, index) in tags"
|
||||||
|
:key="index"
|
||||||
|
class="objective-tag"
|
||||||
|
>
|
||||||
|
{{ tag }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Slot content (full description) always rendered below tags if tags exist, or alone if not -->
|
||||||
|
<div
|
||||||
|
class="description-text"
|
||||||
|
:class="{ 'has-tags': hasTags }"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Metrics Grid -->
|
||||||
|
<div
|
||||||
|
v-if="hasMeta"
|
||||||
|
class="metrics-grid"
|
||||||
|
>
|
||||||
|
<!-- Duration Card -->
|
||||||
|
<div
|
||||||
|
v-if="duration"
|
||||||
|
class="metric-card time-card"
|
||||||
|
>
|
||||||
|
<div class="card-icon">
|
||||||
|
⏱️
|
||||||
|
</div>
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="card-label">
|
||||||
|
{{ t('duration') }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="card-value"
|
||||||
|
v-html="duration"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Output Card -->
|
||||||
|
<div
|
||||||
|
v-if="expectedOutput || coreOutput"
|
||||||
|
class="metric-card output-card"
|
||||||
|
>
|
||||||
|
<div class="card-icon">
|
||||||
|
📦
|
||||||
|
</div>
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="card-label">
|
||||||
|
{{ t('output') }}
|
||||||
|
</div>
|
||||||
|
<div class="output-container">
|
||||||
|
<div
|
||||||
|
v-if="coreOutput"
|
||||||
|
class="core-output"
|
||||||
|
>
|
||||||
|
{{ coreOutput }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="expectedOutput"
|
||||||
|
class="output-desc"
|
||||||
|
v-html="expectedOutput"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Assignment Card -->
|
||||||
|
<div
|
||||||
|
v-if="assignment"
|
||||||
|
class="metric-card task-card"
|
||||||
|
>
|
||||||
|
<div class="card-icon">
|
||||||
|
📝
|
||||||
|
</div>
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="card-label">
|
||||||
|
{{ t('assignment') }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="card-value"
|
||||||
|
v-html="assignment"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.chapter-introduction {
|
||||||
|
margin: 16px 0;
|
||||||
|
border-radius: 12px;
|
||||||
|
background-color: var(--vp-c-bg-soft);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.objective-section {
|
||||||
|
padding: 16px 20px;
|
||||||
|
background: linear-gradient(
|
||||||
|
to right,
|
||||||
|
rgba(var(--vp-c-brand-rgb), 0.05),
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
border-bottom: 1px dashed var(--vp-c-divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
.objective-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: var(--vp-c-brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: 1.2em;
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 0.95em;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
font-size: 1em;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tags Styling */
|
||||||
|
.tags-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.description-text {
|
||||||
|
font-size: 1em;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.description-text.has-tags {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 0.95em;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
border-top: 1px solid var(--vp-c-divider);
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Support for bold text in slot content */
|
||||||
|
.description-text :deep(strong),
|
||||||
|
.description-text :deep(b) {
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.objective-tag {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 4px 10px;
|
||||||
|
background-color: var(--vp-c-bg-alt);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 99px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.objective-tag:hover {
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
color: var(--vp-c-brand);
|
||||||
|
background-color: var(--vp-c-bg-soft);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Metrics Grid */
|
||||||
|
.metrics-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 1px;
|
||||||
|
background-color: var(--vp-c-divider);
|
||||||
|
border-top: 1px solid var(--vp-c-divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-card {
|
||||||
|
flex: 1 1 200px;
|
||||||
|
background-color: var(--vp-c-bg-soft);
|
||||||
|
padding: 14px 18px;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 16px;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.metric-card:hover {
|
||||||
|
background-color: var(--vp-c-bg-alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-icon {
|
||||||
|
font-size: 1.4em;
|
||||||
|
line-height: 1;
|
||||||
|
padding-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-content {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-label {
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
margin-bottom: 4px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-value {
|
||||||
|
font-size: 0.95em;
|
||||||
|
line-height: 1.4;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-value :deep(strong) {
|
||||||
|
display: inline-block;
|
||||||
|
color: var(--vp-c-brand-dark);
|
||||||
|
font-weight: 800;
|
||||||
|
font-size: 1.1em;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Output Container Styling */
|
||||||
|
.output-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.core-output {
|
||||||
|
font-size: 1.1em;
|
||||||
|
font-weight: 800;
|
||||||
|
color: var(--vp-c-brand);
|
||||||
|
line-height: 1.3;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.output-desc {
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.output-desc :deep(strong) {
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile adjustments */
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.metric-card {
|
||||||
|
padding: 12px 16px;
|
||||||
|
flex-basis: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.objective-section {
|
||||||
|
padding: 14px 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 180 180"><path fill="currentColor" d="M101.228 164.247q-7.425 0-14.108-2.821a38.3 38.3 0 0 1-11.88-7.871q-5.643 1.93-11.731 1.931-9.95 0-18.414-4.901T31.433 137.22q-5.05-8.464-5.05-18.859 0-4.307 1.189-9.356-5.94-5.494-9.207-12.622-3.267-7.276-3.267-15.147 0-8.019 3.415-15.444t9.504-12.771q6.237-5.495 14.405-7.574 1.634-8.465 6.83-15.147 5.348-6.83 13.07-10.692t16.483-3.86q7.425 0 14.108 2.82a38.3 38.3 0 0 1 11.88 7.871q5.643-1.93 11.731-1.93 9.95 0 18.414 4.9t13.514 13.365q5.197 8.465 5.197 18.86 0 4.306-1.188 9.355 5.94 5.495 9.207 12.771a35.6 35.6 0 0 1 3.267 14.999q0 8.019-3.415 15.444t-9.653 12.919q-6.088 5.346-14.256 7.425-1.633 8.465-6.979 15.147-5.198 6.831-12.92 10.692t-16.483 3.861m-36.68-18.562q7.425 0 12.92-3.119l27.918-16.038q1.485-1.04 1.485-2.821v-12.771l-35.937 20.641q-3.267 1.93-6.534 0l-28.067-16.186q0 .445-.148 1.039v1.782q0 7.574 3.564 13.959 3.712 6.237 10.246 9.801 6.534 3.713 14.553 3.713m1.485-24.206q.891.446 1.634.446t1.485-.446l11.137-6.385-35.788-20.79q-3.267-1.93-3.267-5.792V56.288q-7.425 3.267-11.88 10.098-4.455 6.683-4.455 14.85 0 7.276 3.712 13.959t9.653 10.098zm35.195 32.967q7.87 0 14.256-3.564t10.098-9.801 3.712-13.959V95.046q0-1.782-1.485-2.673l-11.286-6.534v41.432q0 3.86-3.267 5.791L85.19 149.249q7.276 5.197 16.038 5.197m5.643-54.351V79.899L90.09 70.395 73.161 79.9v20.196L90.09 109.6zM63.509 52.724q0-3.861 3.267-5.792l28.066-16.186q-7.276-5.198-16.038-5.198-7.87 0-14.256 3.564-6.385 3.564-10.098 9.801-3.564 6.237-3.564 13.96V84.8q0 1.782 1.485 2.821l11.138 6.534zm75.438 70.983q7.425-3.267 11.731-10.098 4.455-6.831 4.455-14.85 0-7.276-3.712-13.96-3.713-6.681-9.653-10.097l-27.769-16.038q-.891-.594-1.634-.446-.743 0-1.485.446L99.743 64.9l35.937 20.938q1.633.891 2.376 2.376.891 1.337.891 3.267zm-29.849-75.438q3.267-2.079 6.534 0l28.215 16.483V62.08q0-7.128-3.564-13.513-3.415-6.534-9.949-10.395-6.386-3.861-14.85-3.861-7.425 0-12.92 3.118L74.646 53.466q-1.485 1.04-1.485 2.822v12.77z"/></svg>
|
||||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>
|
||||||
|
After Width: | Height: | Size: 191 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-chevron-down-icon lucide-chevron-down" viewBox="0 0 24 24"><path d="m6 9 6 6 6-6"/></svg>
|
||||||
|
After Width: | Height: | Size: 248 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" overflow="visible" viewBox="0 0 100 101"><path fill="currentColor" d="m96.138 40.515 3.5 2v1.5l-1 3.5-42.5 10-3.996-9.93zm0 0" transform-origin="50px 50px"/><path fill="currentColor" d="m80.626 11.495 4.894 1.027 1.299 1.6 1.239 3.837-.514 2.447-28.521 39-9.5-9.5 26.3-34.514zm0 0" transform-origin="50px 50px"/><path fill="currentColor" d="m56.537 5.537 3-2 2.5 1 2.5 3.5-6.849 41.162-4.65-3.162-2-5.5 3.5-31zm0 0" transform-origin="50px 50px"/><path fill="currentColor" d="m25.058 6.102 3.082-3.937 2.01-.46 3.99.584 1.968 1.54 14.345 31.804 5.19 15.11-6.071 3.376-23.139-41.987zm0 0" transform-origin="50px 50px"/><path fill="currentColor" d="m10.766 27.61-1-4.003 3-3.5 3.5.5h1l21 15.5 6.5 5 9 7-5 8.5-4.5-3.5-3-3-29-20.5zm0 0" transform-origin="50px 50px"/><path fill="currentColor" d="m4.856 53-2.263-2.5v-2.224l2.263-.776 25.5 1.5 25 2-.812 4.978L6.856 53.5zm0 0" transform-origin="50px 50px"/><path fill="currentColor" d="M19.428 78.51h-5l-1.988-2.29v-2.737l8.488-6 34.508-21.966 3.492 5.966zm0 0" transform-origin="50px 50px"/><path fill="currentColor" d="m28.59 92.082-2 .5-3-1.5.5-2.5 29.5-39 4 5.5-22 29zm0 0" transform-origin="50px 50px"/><path fill="currentColor" d="m53.09 96.91-1.5 2-3 1-2.5-2-1.5-3 7.5-40.5 4.5.5zm0 0" transform-origin="50px 50px"/><path fill="currentColor" d="M77.985 86.16v4l-.5 1.5-2 1-3.5-.466-24.033-35.77 9.533-7.264 8 14.5.75 5.25zm0 0" transform-origin="50px 50px"/><path fill="currentColor" d="m89.132 80.508.5 2.5-1.5 2-1.5-.5-8.5-6-13-11.5-10-7 3-9.5 5 3 3 5.5zm0 0" transform-origin="50px 50px"/><path fill="currentColor" d="m82.5 55.5 12.5 1 3 2 2 3v2.159L94.5 66l-28-7-11.5-.5L58 48l8 6zm0 0" transform-origin="50px 50px"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>
|
||||||
|
After Width: | Height: | Size: 287 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-file-down-icon lucide-file-down" viewBox="0 0 24 24"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"/><path d="M14 2v5a1 1 0 0 0 1 1h5m-8 10v-6m-3 3 3 3 3-3"/></svg>
|
||||||
|
After Width: | Height: | Size: 397 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="lucide lucide-arrow-up-right-icon lucide-arrow-up-right" viewBox="0 0 24 24"><path d="M7 7h10v10M7 17 17 7"/></svg>
|
||||||
|
After Width: | Height: | Size: 260 B |
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" fill-rule="evenodd" d="M0 8a4 4 0 0 1 4-4h16a4 4 0 0 1 4 4v8a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4zm4-2a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2zm1.684 2.051A1 1 0 0 1 6.8 8.4L9 11.333 11.2 8.4A1 1 0 0 1 13 9v6a1 1 0 1 1-2 0v-3l-1.2 1.6a1 1 0 0 1-1.6 0L7 12v3a1 1 0 1 1-2 0V9a1 1 0 0 1 .684-.949M18 9a1 1 0 1 0-2 0v3.586l-.293-.293a1 1 0 0 0-1.414 1.414l2 2a1 1 0 0 0 1.414 0l2-2a1 1 0 0 0-1.414-1.414l-.293.293z" clip-rule="evenodd"/></svg>
|
||||||
|
After Width: | Height: | Size: 541 B |
@@ -0,0 +1,348 @@
|
|||||||
|
<template>
|
||||||
|
<div class="markdown-copy-buttons">
|
||||||
|
<div class="markdown-copy-buttons-inner">
|
||||||
|
<div class="dropdown-container" ref="dropdownContainer">
|
||||||
|
<!-- Main button -->
|
||||||
|
<div class="dropdown-trigger">
|
||||||
|
<!-- Copy area -->
|
||||||
|
<button class="copy-page" @click="copyAsMarkdown">
|
||||||
|
<span v-html="copied ? iconCheck : iconCopy" class="icon"></span>
|
||||||
|
<span class="label">
|
||||||
|
{{ copied ? 'Copied' : 'Copy page' }}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<span class="divider"></span>
|
||||||
|
|
||||||
|
<!-- Chevron area -->
|
||||||
|
<button class="chevron-wrapper" @click.stop="toggleDropdown">
|
||||||
|
<span v-html="iconChevron" class="icon chevron" :class="{ open: isOpen }"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Dropdown -->
|
||||||
|
<div v-if="isRendered" ref="dropdownMenu" class="dropdown-menu" :class="{ open: isOpen }">
|
||||||
|
<button class="dropdown-item" @click="viewAsMarkdown">
|
||||||
|
<span v-html="iconMarkdown" class="icon"></span>
|
||||||
|
View as Markdown
|
||||||
|
<span v-html="iconExternal" class="icon external"></span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
v-for="provider in aiProviders"
|
||||||
|
:key="provider.name"
|
||||||
|
class="dropdown-item"
|
||||||
|
@click="openInAI(provider)"
|
||||||
|
>
|
||||||
|
<span v-html="provider.icon" class="icon"></span>
|
||||||
|
Open in {{ provider.name }}
|
||||||
|
<span v-html="iconExternal" class="icon external"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Download button -->
|
||||||
|
<button class="download-btn" @click="downloadMarkdown">
|
||||||
|
<span v-html="downloaded ? iconCheck : iconDownload" class="icon"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, onUnmounted, ref, computed } from 'vue'
|
||||||
|
import { useData } from 'vitepress'
|
||||||
|
|
||||||
|
import iconChatGPT from './icons/chatgpt.svg?raw'
|
||||||
|
import iconCheck from './icons/check.svg?raw'
|
||||||
|
import iconChevron from './icons/chevron.svg?raw'
|
||||||
|
import iconClaude from './icons/claude.svg?raw'
|
||||||
|
import iconCopy from './icons/copy.svg?raw'
|
||||||
|
import iconDownload from './icons/download.svg?raw'
|
||||||
|
import iconExternal from './icons/external.svg?raw'
|
||||||
|
import iconMarkdown from './icons/markdown.svg?raw'
|
||||||
|
|
||||||
|
import { downloadFile } from './utils'
|
||||||
|
|
||||||
|
const { page, site } = useData()
|
||||||
|
|
||||||
|
const getMarkdownUrl = () => {
|
||||||
|
const origin = window.location.origin
|
||||||
|
let base = site.value.base || '/'
|
||||||
|
if (!base.endsWith('/')) base += '/'
|
||||||
|
return `${origin}${base}${page.value.filePath}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const aiProviders = [
|
||||||
|
{ name: 'ChatGPT', icon: iconChatGPT, url: 'https://chatgpt.com/?hints=search&prompt=' },
|
||||||
|
{ name: 'Claude', icon: iconClaude, url: 'https://claude.ai/new?q=' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const isOpen = ref(false)
|
||||||
|
const copied = ref(false)
|
||||||
|
const downloaded = ref(false)
|
||||||
|
const dropdownContainer = ref(null)
|
||||||
|
const isRendered = ref(false)
|
||||||
|
const dropdownMenu = ref(null)
|
||||||
|
|
||||||
|
function toggleDropdown() {
|
||||||
|
if (isOpen.value) {
|
||||||
|
// close
|
||||||
|
isOpen.value = false
|
||||||
|
|
||||||
|
const el = dropdownMenu.value
|
||||||
|
if (!el) return
|
||||||
|
|
||||||
|
const onEnd = () => {
|
||||||
|
isRendered.value = false
|
||||||
|
el.removeEventListener('transitionend', onEnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
el.addEventListener('transitionend', onEnd)
|
||||||
|
} else {
|
||||||
|
// open
|
||||||
|
isRendered.value = true
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
isOpen.value = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyAsMarkdown() {
|
||||||
|
fetch(getMarkdownUrl())
|
||||||
|
.then((r) => r.text())
|
||||||
|
.then((text) => navigator.clipboard.writeText(text))
|
||||||
|
.then(() => {
|
||||||
|
copied.value = true
|
||||||
|
setTimeout(() => {
|
||||||
|
copied.value = false
|
||||||
|
}, 2000)
|
||||||
|
})
|
||||||
|
.catch((e) => console.error('❌ Error:', e))
|
||||||
|
|
||||||
|
isOpen.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function viewAsMarkdown() {
|
||||||
|
window.open(getMarkdownUrl(), '_blank')
|
||||||
|
isOpen.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function openInAI(provider) {
|
||||||
|
const markdownUrl = getMarkdownUrl()
|
||||||
|
const prompt = `Read from ${markdownUrl} so I can ask questions about it.`
|
||||||
|
window.open(provider.url + encodeURIComponent(prompt), '_blank')
|
||||||
|
isOpen.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function downloadMarkdown() {
|
||||||
|
fetch(getMarkdownUrl())
|
||||||
|
.then((r) => r.text())
|
||||||
|
.then((text) => {
|
||||||
|
const filename = page.value.filePath.split('/').pop() || 'page.md'
|
||||||
|
downloadFile(filename, text, 'text/markdown')
|
||||||
|
downloaded.value = true
|
||||||
|
setTimeout(() => {
|
||||||
|
downloaded.value = false
|
||||||
|
}, 2000)
|
||||||
|
})
|
||||||
|
.catch((e) => console.error('❌ Error:', e))
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleClickOutside(event) {
|
||||||
|
if (dropdownContainer.value && !dropdownContainer.value.contains(event.target)) {
|
||||||
|
isOpen.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => document.addEventListener('click', handleClickOutside))
|
||||||
|
onUnmounted(() => document.removeEventListener('click', handleClickOutside))
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.markdown-copy-buttons {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown-copy-buttons-inner {
|
||||||
|
margin: 16px 0;
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-container {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-trigger {
|
||||||
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 6px;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-page {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
width: 1px;
|
||||||
|
height: 25px;
|
||||||
|
align-self: center;
|
||||||
|
background: var(--vp-c-divider);
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chevron-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-menu {
|
||||||
|
position: absolute;
|
||||||
|
top: calc(100% + 4px);
|
||||||
|
left: 0;
|
||||||
|
min-width: 240px;
|
||||||
|
background: var(--vp-c-bg-elv);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
z-index: 100;
|
||||||
|
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
|
||||||
|
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-6px) scale(0.96);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-menu.open {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0) scale(1);
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 10px 16px;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item .icon.external {
|
||||||
|
margin-left: auto;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.download-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px 12px;
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 6px;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chevron.open {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item:hover .icon.external {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: no-preference) {
|
||||||
|
.dropdown-menu {
|
||||||
|
transition:
|
||||||
|
opacity 0.18s cubic-bezier(0.4, 0, 0.2, 1),
|
||||||
|
transform 0.18s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
transform-origin: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hover zones */
|
||||||
|
.copy-page:hover,
|
||||||
|
.chevron-wrapper:hover,
|
||||||
|
.download-btn:hover {
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-trigger,
|
||||||
|
.copy-page,
|
||||||
|
.chevron-wrapper,
|
||||||
|
.dropdown-item,
|
||||||
|
.dropdown-item .icon.external,
|
||||||
|
.download-btn {
|
||||||
|
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-trigger:hover,
|
||||||
|
.download-btn:hover {
|
||||||
|
border-color: var(--vp-c-brand-1);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 100%;
|
||||||
|
background: var(--vp-c-brand-1);
|
||||||
|
transition: width 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item:hover {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item:hover::before {
|
||||||
|
width: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chevron {
|
||||||
|
transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
var removeHtmlExtension = (pathSegment) => {
|
||||||
|
const lastSlashIndex = pathSegment.lastIndexOf('/')
|
||||||
|
const lastDotIndex = pathSegment.lastIndexOf('.')
|
||||||
|
if (
|
||||||
|
lastDotIndex > lastSlashIndex &&
|
||||||
|
lastDotIndex !== -1 &&
|
||||||
|
pathSegment.endsWith('.html')
|
||||||
|
) {
|
||||||
|
return pathSegment.slice(0, lastDotIndex)
|
||||||
|
}
|
||||||
|
return pathSegment
|
||||||
|
}
|
||||||
|
function cleanUrl(url) {
|
||||||
|
const { origin, pathname } = new URL(url)
|
||||||
|
const pathnameWithoutTrailingSlash = pathname.replace(/\/+$/, '')
|
||||||
|
if (pathname.length > 0) {
|
||||||
|
return origin + removeHtmlExtension(pathnameWithoutTrailingSlash)
|
||||||
|
}
|
||||||
|
return origin
|
||||||
|
}
|
||||||
|
function resolveMarkdownPageURL(url) {
|
||||||
|
const cleanedURL = cleanUrl(url)
|
||||||
|
return `${cleanedURL}/index.md`
|
||||||
|
}
|
||||||
|
function downloadFile(filename, content, blobType = 'text/plain') {
|
||||||
|
const blob =
|
||||||
|
content instanceof Blob ? content : new Blob([content], { type: blobType })
|
||||||
|
const url = URL.createObjectURL(blob)
|
||||||
|
Object.assign(document.createElement('a'), {
|
||||||
|
href: url,
|
||||||
|
download: filename
|
||||||
|
}).click()
|
||||||
|
URL.revokeObjectURL(url)
|
||||||
|
}
|
||||||
|
export { resolveMarkdownPageURL, downloadFile, cleanUrl }
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref, onMounted } from 'vue'
|
||||||
|
|
||||||
|
const stars = ref(0)
|
||||||
|
const formattedStars = ref('')
|
||||||
|
|
||||||
|
const formatStars = (count) => {
|
||||||
|
if (count >= 1000) {
|
||||||
|
return (count / 1000).toFixed(1) + 'k'
|
||||||
|
}
|
||||||
|
return count.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const CACHE_KEY = 'github-stars-cache'
|
||||||
|
const CACHE_DURATION = 5 * 60 * 1000 // 5 minutes
|
||||||
|
|
||||||
|
try {
|
||||||
|
const cached = localStorage.getItem(CACHE_KEY)
|
||||||
|
if (cached) {
|
||||||
|
const { count, timestamp } = JSON.parse(cached)
|
||||||
|
if (Date.now() - timestamp < CACHE_DURATION) {
|
||||||
|
stars.value = count
|
||||||
|
formattedStars.value = formatStars(count)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await fetch(
|
||||||
|
'https://api.github.com/repos/datawhalechina/easy-vibe'
|
||||||
|
)
|
||||||
|
if (res.ok) {
|
||||||
|
const data = await res.json()
|
||||||
|
stars.value = data.stargazers_count
|
||||||
|
formattedStars.value = formatStars(stars.value)
|
||||||
|
|
||||||
|
localStorage.setItem(
|
||||||
|
CACHE_KEY,
|
||||||
|
JSON.stringify({
|
||||||
|
count: stars.value,
|
||||||
|
timestamp: Date.now()
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to fetch GitHub stars:', e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="github-stars-wrapper">
|
||||||
|
<a
|
||||||
|
class="github-stars-link"
|
||||||
|
href="https://github.com/datawhalechina/easy-vibe"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
aria-label="GitHub"
|
||||||
|
>
|
||||||
|
<span class="icon">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M12 2A10 10 0 0 0 2 12c0 4.42 2.87 8.17 6.84 9.5c.5.08.66-.23.66-.5v-1.69c-2.77.6-3.36-1.34-3.36-1.34c-.46-1.16-1.11-1.47-1.11-1.47c-.91-.62.07-.6.07-.6c1 .07 1.53 1.03 1.53 1.03c.87 1.52 2.34 1.07 2.91.83c.09-.65.35-1.09.63-1.34c-2.22-.25-4.55-1.11-4.55-4.92c0-1.11.38-2 1.03-2.71c-.1-.25-.45-1.29.1-2.64c0 0 .84-.27 2.75 1.02c.79-.22 1.65-.33 2.5-.33c.85 0 1.71.11 2.5.33c1.91-1.29 2.75-1.02 2.75-1.02c.55 1.35.2 2.39.1 2.64c.65.71 1.03 1.6 1.03 2.71c0 3.82-2.34 4.66-4.57 4.91c.36.31.69.92.69 1.85V21c0 .27.16.59.67.5C19.14 20.16 22 16.42 22 12A10 10 0 0 0 12 2Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
v-if="formattedStars"
|
||||||
|
class="stars-count"
|
||||||
|
>{{
|
||||||
|
formattedStars
|
||||||
|
}}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.github-stars-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-left: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.github-stars-link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
transition: color 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.github-stars-link:hover {
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon svg {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stars-count {
|
||||||
|
margin-left: 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,853 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref, onMounted, onUnmounted, computed } from 'vue'
|
||||||
|
import { useRouter, withBase, useData } from 'vitepress'
|
||||||
|
import GitHubStars from './GitHubStars.vue'
|
||||||
|
import VibeStories from './VibeStories.vue'
|
||||||
|
import { provide } from 'vue'
|
||||||
|
import { i18n } from './home/HomeI18n'
|
||||||
|
import { locales } from './home/HomeData'
|
||||||
|
import HomeStage1 from './home/HomeStage1.vue'
|
||||||
|
import HomeStage2 from './home/HomeStage2.vue'
|
||||||
|
import HomeStage3 from './home/HomeStage3.vue'
|
||||||
|
import HomeAppendix from './home/HomeAppendix.vue'
|
||||||
|
import HomeAppleFooter from './home/HomeAppleFooter.vue'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const { site, page, lang } = useData()
|
||||||
|
const activeTab = ref('home')
|
||||||
|
const showLangMenu = ref(false)
|
||||||
|
const topPromoProgress = ref(1)
|
||||||
|
const topPromoDismissed = ref(false)
|
||||||
|
const topPromoIntroProgress = ref(0)
|
||||||
|
const topPromoColorProgress = ref(0)
|
||||||
|
let topPromoIntroRaf = 0
|
||||||
|
let topPromoColorRaf = 0
|
||||||
|
let topPromoColorTimer = 0
|
||||||
|
const WELCOME_SEEN_KEY = 'easy-vibe-welcome-seen'
|
||||||
|
|
||||||
|
const vibeStoriesSection = ref(null)
|
||||||
|
|
||||||
|
const t = computed(() => {
|
||||||
|
const code = lang.value ? lang.value.toLowerCase() : 'zh-cn'
|
||||||
|
const result = i18n[code] || i18n['en']
|
||||||
|
result._locale = code
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
|
||||||
|
provide('t', t)
|
||||||
|
|
||||||
|
const isCjkLocale = computed(() => {
|
||||||
|
const code = lang.value ? lang.value.toLowerCase() : ''
|
||||||
|
if (['zh-cn', 'zh-tw', 'ja-jp', 'ko-kr'].includes(code)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
const path = router.route.path.toLowerCase()
|
||||||
|
return /^\/(zh-cn|zh-tw|ja-jp|ko-kr)\//.test(path)
|
||||||
|
})
|
||||||
|
|
||||||
|
const topPromo = computed(() => {
|
||||||
|
const code = lang.value ? lang.value.toLowerCase() : 'en'
|
||||||
|
const isChinese = code === 'zh-cn' || code === 'zh-tw'
|
||||||
|
return {
|
||||||
|
text: isChinese
|
||||||
|
? '用 Easy-Vibe 构建你的第一个 AI 应用,最快当天可上线原型。'
|
||||||
|
: 'Build your first AI app with Easy-Vibe and ship a working prototype fast.',
|
||||||
|
cta: isChinese ? '开始学习 ›' : 'Start learning ›',
|
||||||
|
link: `/${code}/stage-1/learning-map/`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const toggleLangMenu = () => {
|
||||||
|
showLangMenu.value = !showLangMenu.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateHash = (id) => {
|
||||||
|
const targetHash = id === 'home' ? '#home' : `#${id}`
|
||||||
|
const currentUrl = `${window.location.pathname}${window.location.search}${window.location.hash}`
|
||||||
|
const nextUrl = `${window.location.pathname}${window.location.search}${targetHash}`
|
||||||
|
if (currentUrl !== nextUrl) {
|
||||||
|
window.history.replaceState(null, '', nextUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const syncTopPromoWithHash = () => {
|
||||||
|
const rawHash = window.location.hash.replace(/^#/, '')
|
||||||
|
const targetId = rawHash || 'home'
|
||||||
|
if (targetId === 'home') {
|
||||||
|
topPromoDismissed.value = false
|
||||||
|
topPromoProgress.value = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
topPromoDismissed.value = true
|
||||||
|
topPromoProgress.value = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeLang = (targetLocale) => {
|
||||||
|
const currentPath = router.route.path
|
||||||
|
const currentLocale = locales.find((l) =>
|
||||||
|
currentPath.startsWith(`/${l.code}/`)
|
||||||
|
)
|
||||||
|
|
||||||
|
let newPath
|
||||||
|
if (currentLocale) {
|
||||||
|
newPath = currentPath.replace(
|
||||||
|
`/${currentLocale.code}/`,
|
||||||
|
`/${targetLocale}/`
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
newPath = `/${targetLocale}/`
|
||||||
|
}
|
||||||
|
|
||||||
|
const hash = window.location.hash || ''
|
||||||
|
router.go(withBase(`${newPath}${hash}`))
|
||||||
|
showLangMenu.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const scrollTo = (id) => {
|
||||||
|
if (id === 'home') {
|
||||||
|
window.scrollTo({ top: 0, behavior: 'smooth' })
|
||||||
|
activeTab.value = 'home'
|
||||||
|
updateHash('home')
|
||||||
|
syncTopPromoWithHash()
|
||||||
|
updateTopPromoVisibility()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const el = document.getElementById(id)
|
||||||
|
if (el) {
|
||||||
|
const navHeight = 48
|
||||||
|
const elementPosition = el.getBoundingClientRect().top + window.pageYOffset
|
||||||
|
const extraOffset = id === 'vibe-stories' ? 20 : 40
|
||||||
|
const offset = elementPosition - navHeight - extraOffset
|
||||||
|
window.scrollTo({ top: offset, behavior: 'smooth' })
|
||||||
|
activeTab.value = id
|
||||||
|
updateHash(id)
|
||||||
|
syncTopPromoWithHash()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const scrollToHashTarget = (behavior = 'auto') => {
|
||||||
|
const rawHash = window.location.hash.replace(/^#/, '')
|
||||||
|
const targetId = rawHash || 'home'
|
||||||
|
if (targetId === 'home') {
|
||||||
|
window.scrollTo({ top: 0, behavior })
|
||||||
|
activeTab.value = 'home'
|
||||||
|
syncTopPromoWithHash()
|
||||||
|
updateTopPromoVisibility()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const el = document.getElementById(targetId)
|
||||||
|
if (el) {
|
||||||
|
const navHeight = 48
|
||||||
|
const elementPosition = el.getBoundingClientRect().top + window.pageYOffset
|
||||||
|
const extraOffset = targetId === 'vibe-stories' ? 20 : 40
|
||||||
|
const offset = elementPosition - navHeight - extraOffset
|
||||||
|
window.scrollTo({ top: offset, behavior })
|
||||||
|
activeTab.value = targetId
|
||||||
|
syncTopPromoWithHash()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeLangMenu = (e) => {
|
||||||
|
if (!e.target.closest('.lang-switch-wrapper')) {
|
||||||
|
showLangMenu.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateTopPromoVisibility = () => {
|
||||||
|
if (topPromoDismissed.value) {
|
||||||
|
topPromoProgress.value = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!vibeStoriesSection.value) {
|
||||||
|
topPromoProgress.value = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const navHeight = 44
|
||||||
|
const sectionTop =
|
||||||
|
vibeStoriesSection.value.getBoundingClientRect().top + window.pageYOffset
|
||||||
|
const endY = sectionTop - navHeight
|
||||||
|
const startY = endY - 96
|
||||||
|
const scrollY = window.pageYOffset
|
||||||
|
if (scrollY <= startY) {
|
||||||
|
topPromoProgress.value = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (scrollY >= endY) {
|
||||||
|
topPromoProgress.value = 0
|
||||||
|
topPromoDismissed.value = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
topPromoProgress.value = (endY - scrollY) / (endY - startY)
|
||||||
|
}
|
||||||
|
|
||||||
|
const topPromoStyle = computed(() => {
|
||||||
|
const scrollProgress = topPromoProgress.value
|
||||||
|
const introProgress = topPromoIntroProgress.value
|
||||||
|
const colorProgress = topPromoColorProgress.value
|
||||||
|
const progress = scrollProgress * introProgress
|
||||||
|
const scrollOffset = -100 * (1 - scrollProgress)
|
||||||
|
const startTextColor = { r: 255, g: 255, b: 255 }
|
||||||
|
const endTextColor = { r: 29, g: 29, b: 31 }
|
||||||
|
const startBgColor = { r: 0, g: 113, b: 227 }
|
||||||
|
const endBgColor = { r: 245, g: 245, b: 247 }
|
||||||
|
const startLinkColor = { r: 255, g: 255, b: 255 }
|
||||||
|
const endLinkColor = { r: 0, g: 102, b: 204 }
|
||||||
|
const textColor = `rgb(${Math.round(startTextColor.r + (endTextColor.r - startTextColor.r) * colorProgress)}, ${Math.round(startTextColor.g + (endTextColor.g - startTextColor.g) * colorProgress)}, ${Math.round(startTextColor.b + (endTextColor.b - startTextColor.b) * colorProgress)})`
|
||||||
|
const bgColor = `rgb(${Math.round(startBgColor.r + (endBgColor.r - startBgColor.r) * colorProgress)}, ${Math.round(startBgColor.g + (endBgColor.g - startBgColor.g) * colorProgress)}, ${Math.round(startBgColor.b + (endBgColor.b - startBgColor.b) * colorProgress)})`
|
||||||
|
const linkColor = `rgb(${Math.round(startLinkColor.r + (endLinkColor.r - startLinkColor.r) * colorProgress)}, ${Math.round(startLinkColor.g + (endLinkColor.g - startLinkColor.g) * colorProgress)}, ${Math.round(startLinkColor.b + (endLinkColor.b - startLinkColor.b) * colorProgress)})`
|
||||||
|
return {
|
||||||
|
opacity: progress,
|
||||||
|
transform: `translateY(${scrollOffset}%)`,
|
||||||
|
maxHeight: `${30 * progress}px`,
|
||||||
|
backgroundColor: bgColor,
|
||||||
|
color: textColor,
|
||||||
|
'--top-promo-link-color': linkColor,
|
||||||
|
pointerEvents: progress < 0.02 ? 'none' : 'auto'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const resolveFooterHref = (link) => {
|
||||||
|
if (link.startsWith('http://') || link.startsWith('https://')) {
|
||||||
|
return link
|
||||||
|
}
|
||||||
|
return withBase(link)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const introDuration = 1800
|
||||||
|
const colorDelay = 500
|
||||||
|
const colorDuration = 1800
|
||||||
|
const introStart = performance.now()
|
||||||
|
const stepTopPromoIntro = (now) => {
|
||||||
|
const raw = Math.min(1, (now - introStart) / introDuration)
|
||||||
|
const eased = 1 - Math.pow(1 - raw, 3)
|
||||||
|
topPromoIntroProgress.value = eased
|
||||||
|
if (raw < 1) {
|
||||||
|
topPromoIntroRaf = window.requestAnimationFrame(stepTopPromoIntro)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
topPromoColorTimer = window.setTimeout(() => {
|
||||||
|
const colorStart = performance.now()
|
||||||
|
const stepTopPromoColor = (time) => {
|
||||||
|
const colorRaw = Math.min(1, (time - colorStart) / colorDuration)
|
||||||
|
const colorEased = 1 - Math.pow(1 - colorRaw, 3)
|
||||||
|
topPromoColorProgress.value = colorEased
|
||||||
|
if (colorRaw < 1) {
|
||||||
|
topPromoColorRaf = window.requestAnimationFrame(stepTopPromoColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
topPromoColorRaf = window.requestAnimationFrame(stepTopPromoColor)
|
||||||
|
}, colorDelay)
|
||||||
|
}
|
||||||
|
topPromoIntroRaf = window.requestAnimationFrame(stepTopPromoIntro)
|
||||||
|
|
||||||
|
const currentPath = window.location.pathname
|
||||||
|
const basePath = site.value.base || '/'
|
||||||
|
const normalizedBase = basePath.endsWith('/') ? basePath : `${basePath}/`
|
||||||
|
const normalizedPath = currentPath.endsWith('/')
|
||||||
|
? currentPath
|
||||||
|
: `${currentPath}/`
|
||||||
|
const localeHomeSuffixes = [
|
||||||
|
'/zh-cn/',
|
||||||
|
'/en/',
|
||||||
|
'/zh-tw/',
|
||||||
|
'/ja-jp/',
|
||||||
|
'/ko-kr/',
|
||||||
|
'/es-es/',
|
||||||
|
'/fr-fr/',
|
||||||
|
'/de-de/',
|
||||||
|
'/ar-sa/',
|
||||||
|
'/vi-vn/'
|
||||||
|
]
|
||||||
|
const isLocaleHome = localeHomeSuffixes.some(
|
||||||
|
(suffix) =>
|
||||||
|
currentPath.endsWith(suffix) ||
|
||||||
|
currentPath.endsWith(`${suffix}index.html`)
|
||||||
|
)
|
||||||
|
const isRootHome =
|
||||||
|
normalizedPath === normalizedBase ||
|
||||||
|
currentPath === `${normalizedBase}index.html`
|
||||||
|
if (isRootHome && !isLocaleHome) {
|
||||||
|
const hasSeenWelcome = window.localStorage.getItem(WELCOME_SEEN_KEY) === '1'
|
||||||
|
if (!hasSeenWelcome) {
|
||||||
|
router.go(withBase(`/welcome/?next=${encodeURIComponent(currentPath)}`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('click', closeLangMenu)
|
||||||
|
syncTopPromoWithHash()
|
||||||
|
window.setTimeout(() => {
|
||||||
|
scrollToHashTarget('auto')
|
||||||
|
}, 0)
|
||||||
|
updateTopPromoVisibility()
|
||||||
|
window.addEventListener('scroll', updateTopPromoVisibility, { passive: true })
|
||||||
|
window.addEventListener('resize', updateTopPromoVisibility)
|
||||||
|
window.addEventListener('hashchange', scrollToHashTarget)
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (topPromoIntroRaf) {
|
||||||
|
window.cancelAnimationFrame(topPromoIntroRaf)
|
||||||
|
topPromoIntroRaf = 0
|
||||||
|
}
|
||||||
|
if (topPromoColorRaf) {
|
||||||
|
window.cancelAnimationFrame(topPromoColorRaf)
|
||||||
|
topPromoColorRaf = 0
|
||||||
|
}
|
||||||
|
if (topPromoColorTimer) {
|
||||||
|
window.clearTimeout(topPromoColorTimer)
|
||||||
|
topPromoColorTimer = 0
|
||||||
|
}
|
||||||
|
document.removeEventListener('click', closeLangMenu)
|
||||||
|
window.removeEventListener('scroll', updateTopPromoVisibility)
|
||||||
|
window.removeEventListener('resize', updateTopPromoVisibility)
|
||||||
|
window.removeEventListener('hashchange', scrollToHashTarget)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="apple-container">
|
||||||
|
<nav class="sticky-nav glass">
|
||||||
|
<div class="nav-content">
|
||||||
|
<div class="nav-cluster">
|
||||||
|
<div
|
||||||
|
class="nav-title"
|
||||||
|
:aria-label="t.nav.title"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
class="nav-title-logo no-viewer"
|
||||||
|
:src="withBase('/assets/easy-vibe-logo-hd.svg')"
|
||||||
|
:alt="t.nav.title"
|
||||||
|
width="64"
|
||||||
|
height="30"
|
||||||
|
draggable="false"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="nav-links">
|
||||||
|
<button
|
||||||
|
:class="{ active: activeTab === 'home' }"
|
||||||
|
class="nav-link-item"
|
||||||
|
@click="scrollTo('home')"
|
||||||
|
>
|
||||||
|
{{ t.nav.home }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
:class="{ active: activeTab === 'vibe-stories' }"
|
||||||
|
class="nav-link-item"
|
||||||
|
@click="scrollTo('vibe-stories')"
|
||||||
|
>
|
||||||
|
{{ t.nav.stories || 'Vibe 故事' }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
:class="{ active: activeTab === 'pm' }"
|
||||||
|
class="nav-link-item"
|
||||||
|
@click="scrollTo('pm')"
|
||||||
|
>
|
||||||
|
{{ t.nav.pm }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
:class="{ active: activeTab === 'junior' }"
|
||||||
|
class="nav-link-item"
|
||||||
|
@click="scrollTo('junior')"
|
||||||
|
>
|
||||||
|
{{ t.nav.junior }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
:class="{ active: activeTab === 'senior' }"
|
||||||
|
class="nav-link-item"
|
||||||
|
@click="scrollTo('senior')"
|
||||||
|
>
|
||||||
|
{{ t.nav.senior }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
:class="{ active: activeTab === 'appendix' }"
|
||||||
|
class="nav-link-item"
|
||||||
|
@click="scrollTo('appendix')"
|
||||||
|
>
|
||||||
|
{{ t.nav.appendix }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="nav-action">
|
||||||
|
<div class="nav-icons">
|
||||||
|
<div class="lang-switch-wrapper">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="button"
|
||||||
|
aria-haspopup="true"
|
||||||
|
:aria-expanded="showLangMenu"
|
||||||
|
aria-label="Change language"
|
||||||
|
@click.stop="toggleLangMenu"
|
||||||
|
>
|
||||||
|
<span class="text">
|
||||||
|
<span class="vpi-languages option-icon" />
|
||||||
|
<span class="vpi-chevron-down text-icon" />
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
v-if="showLangMenu"
|
||||||
|
class="lang-dropdown glass"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
v-for="locale in locales"
|
||||||
|
:key="locale.code"
|
||||||
|
class="lang-item"
|
||||||
|
@click="changeLang(locale.code)"
|
||||||
|
>
|
||||||
|
{{ locale.text }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<GitHubStars class="nav-github-stars" />
|
||||||
|
</div>
|
||||||
|
<a
|
||||||
|
class="buy-btn"
|
||||||
|
:href="withBase(t.stage1.cards[0].link)"
|
||||||
|
>{{ t.footer.btn }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="nav-promo"
|
||||||
|
:style="topPromoStyle"
|
||||||
|
>
|
||||||
|
<span>{{ topPromo.text }}</span>
|
||||||
|
<a :href="resolveFooterHref(topPromo.link)">{{ topPromo.cta }}</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div
|
||||||
|
id="home"
|
||||||
|
style="height: 0"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<section
|
||||||
|
id="vibe-stories"
|
||||||
|
ref="vibeStoriesSection"
|
||||||
|
class="section-container"
|
||||||
|
>
|
||||||
|
<VibeStories />
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="section-band section-band-learning">
|
||||||
|
<HomeStage1 />
|
||||||
|
<HomeStage2 />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<HomeStage3 />
|
||||||
|
<HomeAppendix />
|
||||||
|
<HomeAppleFooter :is-cjk-locale="isCjkLocale" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.apple-container {
|
||||||
|
font-family:
|
||||||
|
-apple-system, BlinkMacSystemFont, 'SF Pro Text', 'PingFang SC',
|
||||||
|
'Helvetica Neue', sans-serif;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
#vibe-stories,
|
||||||
|
#vibe-stories:focus,
|
||||||
|
#vibe-stories:focus-visible,
|
||||||
|
#vibe-stories:target {
|
||||||
|
outline: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
:is(.buy-btn) {
|
||||||
|
border-bottom: none !important;
|
||||||
|
outline: none !important;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
:is(.buy-btn):is(:hover, :focus, :focus-visible, :active) {
|
||||||
|
border-bottom-color: transparent !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlight {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sticky-nav {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 100;
|
||||||
|
border-bottom: 1px solid #d2d2d7;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
background: rgba(245, 245, 247, 0.82);
|
||||||
|
backdrop-filter: blur(20px);
|
||||||
|
-webkit-backdrop-filter: blur(20px);
|
||||||
|
}
|
||||||
|
|
||||||
|
:root.dark .sticky-nav {
|
||||||
|
background: rgba(18, 18, 20, 0.8);
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-content {
|
||||||
|
max-width: 1280px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 28px;
|
||||||
|
height: 44px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-cluster {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-title {
|
||||||
|
flex-shrink: 0;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
cursor: default;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-title-logo {
|
||||||
|
display: block;
|
||||||
|
max-width: 64px !important;
|
||||||
|
max-height: 30px !important;
|
||||||
|
height: 30px !important;
|
||||||
|
width: 64px !important;
|
||||||
|
min-width: 64px;
|
||||||
|
min-height: 30px;
|
||||||
|
object-fit: contain;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
filter: grayscale(1) brightness(0.28) contrast(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links button,
|
||||||
|
.nav-link-item {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--vp-c-text-1) !important;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1;
|
||||||
|
font-weight: 400;
|
||||||
|
opacity: 0.76;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links button:hover,
|
||||||
|
.nav-links button.active,
|
||||||
|
.nav-link-item:hover {
|
||||||
|
color: var(--vp-c-text-1) !important;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-action {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-icons {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.nav-github-stars) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.nav-github-stars .github-stars-link) {
|
||||||
|
color: var(--vp-c-text-1) !important;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.nav-github-stars .github-stars-link:hover) {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.nav-github-stars .github-stars-wrapper) {
|
||||||
|
padding-left: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-promo {
|
||||||
|
height: 30px;
|
||||||
|
max-height: 30px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #1d1d1f;
|
||||||
|
padding: 0 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
transform-origin: top center;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
will-change: transform, opacity, max-height, background-color, color;
|
||||||
|
transition:
|
||||||
|
transform 0.16s ease-out,
|
||||||
|
opacity 0.16s ease-out,
|
||||||
|
max-height 0.16s ease-out,
|
||||||
|
background-color 0.22s ease-out,
|
||||||
|
color 0.22s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-promo a {
|
||||||
|
color: var(--top-promo-link-color, #0066cc);
|
||||||
|
text-decoration: none;
|
||||||
|
transition: color 0.25s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
color: var(--vp-c-text-1) !important;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:hover {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button .text {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button .option-icon {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
color: var(--vp-c-text-1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button .text-icon {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
color: var(--vp-c-text-1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lang-switch-wrapper {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lang-dropdown {
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
right: -10px;
|
||||||
|
margin-top: 12px;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 6px;
|
||||||
|
min-width: 140px;
|
||||||
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.14);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
max-height: 300px;
|
||||||
|
overflow-y: auto;
|
||||||
|
z-index: 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lang-item {
|
||||||
|
text-align: left;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
transition: background 0.2s;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lang-item:hover {
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
.buy-btn {
|
||||||
|
background: #0071e3;
|
||||||
|
color: #fff !important;
|
||||||
|
padding: 7px 16px;
|
||||||
|
border-radius: 980px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buy-btn:hover {
|
||||||
|
background: #0077ed;
|
||||||
|
transform: scale(1.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
.buy-btn.large {
|
||||||
|
padding: 12px 24px;
|
||||||
|
font-size: 15px;
|
||||||
|
margin-top: 20px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-container {
|
||||||
|
max-width: 1280px;
|
||||||
|
margin: 0 auto 96px;
|
||||||
|
padding: 0 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-band-learning {
|
||||||
|
width: 100vw;
|
||||||
|
max-width: none;
|
||||||
|
margin: 0 calc(50% - 50vw) 96px;
|
||||||
|
background: #f5f5f7;
|
||||||
|
border-radius: 0;
|
||||||
|
padding-top: 64px;
|
||||||
|
padding-bottom: 64px;
|
||||||
|
padding-left: max(40px, calc((100vw - 1280px) / 2 + 40px));
|
||||||
|
padding-right: max(40px, calc((100vw - 1280px) / 2 + 40px));
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-band-learning .section-container {
|
||||||
|
max-width: 1280px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-band-learning .section-junior {
|
||||||
|
margin-top: 72px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .section-band-learning {
|
||||||
|
background: rgba(255, 255, 255, 0.03);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
margin-bottom: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-category {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
color: #1d1d1f;
|
||||||
|
letter-spacing: -0.024em;
|
||||||
|
font-family:
|
||||||
|
-apple-system, BlinkMacSystemFont, 'SF Pro Display', 'PingFang SC',
|
||||||
|
sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-headline {
|
||||||
|
font-size: 64px;
|
||||||
|
line-height: 1.08;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -0.034em;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: #1d1d1f;
|
||||||
|
font-family:
|
||||||
|
-apple-system, BlinkMacSystemFont, 'SF Pro Display', 'PingFang SC',
|
||||||
|
sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-sub {
|
||||||
|
font-size: 21px;
|
||||||
|
line-height: 1.4;
|
||||||
|
font-weight: 400;
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
color: #6e6e73;
|
||||||
|
max-width: 760px;
|
||||||
|
font-family:
|
||||||
|
-apple-system, BlinkMacSystemFont, 'SF Pro Text', 'PingFang SC',
|
||||||
|
sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .section-category,
|
||||||
|
.dark .section-headline {
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .section-sub {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.section-headline {
|
||||||
|
font-size: 42px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-links {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-promo {
|
||||||
|
font-size: 12px;
|
||||||
|
height: 28px;
|
||||||
|
justify-content: flex-start;
|
||||||
|
overflow-x: auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-band-learning {
|
||||||
|
margin-bottom: 96px;
|
||||||
|
padding-top: 42px;
|
||||||
|
padding-bottom: 42px;
|
||||||
|
padding-left: 24px;
|
||||||
|
padding-right: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-band-learning .section-junior {
|
||||||
|
margin-top: 56px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.VPHome {
|
||||||
|
padding-top: 84px !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,170 @@
|
|||||||
|
<script setup>
|
||||||
|
import { withBase } from 'vitepress'
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
href: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a
|
||||||
|
:href="withBase(href)"
|
||||||
|
class="nav-card-link"
|
||||||
|
>
|
||||||
|
<div class="nav-card">
|
||||||
|
<div class="card-top">
|
||||||
|
<div class="card-header">
|
||||||
|
<span
|
||||||
|
v-if="icon"
|
||||||
|
class="card-icon"
|
||||||
|
>{{ icon }}</span>
|
||||||
|
<span class="card-title">{{ title }}</span>
|
||||||
|
</div>
|
||||||
|
<span class="card-arrow">↗</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="description"
|
||||||
|
class="card-desc"
|
||||||
|
>{{ description }}</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.nav-card-link {
|
||||||
|
text-decoration: none !important;
|
||||||
|
color: inherit !important;
|
||||||
|
display: block;
|
||||||
|
outline: none;
|
||||||
|
border-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-card-link:focus,
|
||||||
|
.nav-card-link:focus-visible,
|
||||||
|
.nav-card-link:active {
|
||||||
|
outline: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
border-bottom: 0 !important;
|
||||||
|
border-bottom-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-card-link:hover,
|
||||||
|
.nav-card-link:visited {
|
||||||
|
text-decoration: none !important;
|
||||||
|
border-bottom: 0 !important;
|
||||||
|
border-bottom-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-card-link:focus-visible .nav-card {
|
||||||
|
border-color: #0066cc;
|
||||||
|
box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-card {
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.04);
|
||||||
|
border-radius: 24px;
|
||||||
|
padding: 20px 22px;
|
||||||
|
transition: all 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
|
||||||
|
background: #fff;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 124px;
|
||||||
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05);
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-card:hover {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.08);
|
||||||
|
border-color: rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .nav-card {
|
||||||
|
border-color: rgba(255, 255, 255, 0.08);
|
||||||
|
background: var(--vp-c-bg-mute);
|
||||||
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .nav-card:hover {
|
||||||
|
border-color: rgba(255, 255, 255, 0.14);
|
||||||
|
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.34);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-top {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-icon {
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
font-size: 17px;
|
||||||
|
line-height: 1.35;
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-arrow {
|
||||||
|
color: #0066cc;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
opacity: 0.9;
|
||||||
|
transition: transform 0.25s ease, opacity 0.25s ease;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-card:hover .card-arrow {
|
||||||
|
transform: translate(2px, -2px);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-desc {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.nav-card {
|
||||||
|
border-radius: 18px;
|
||||||
|
padding: 16px 18px;
|
||||||
|
min-height: 108px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-desc {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<template>
|
||||||
|
<div class="nav-grid">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.nav-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 18px;
|
||||||
|
margin: 20px 0 26px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1400px) {
|
||||||
|
.nav-grid {
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.nav-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 12px;
|
||||||
|
margin: 16px 0 22px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,597 @@
|
|||||||
|
<template>
|
||||||
|
<Transition name="progress-fade">
|
||||||
|
<div
|
||||||
|
v-if="showProgress"
|
||||||
|
class="reading-progress"
|
||||||
|
:class="{ 'is-dragging': isDragging }"
|
||||||
|
:title="progressTitle"
|
||||||
|
@mousedown="startDrag"
|
||||||
|
@touchstart="startDrag"
|
||||||
|
@click="handleClick"
|
||||||
|
>
|
||||||
|
<svg class="progress-ring" viewBox="0 0 56 56">
|
||||||
|
<circle
|
||||||
|
class="progress-ring-bg"
|
||||||
|
cx="28"
|
||||||
|
cy="28"
|
||||||
|
r="24"
|
||||||
|
/>
|
||||||
|
<circle
|
||||||
|
class="progress-ring-circle"
|
||||||
|
cx="28"
|
||||||
|
cy="28"
|
||||||
|
r="24"
|
||||||
|
:style="{ strokeDashoffset: circumference - (progress / 100) * circumference }"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<Transition name="content-switch">
|
||||||
|
<div v-if="showArrow && !isDragging" key="arrow" class="progress-arrow">↑</div>
|
||||||
|
<div v-else key="percent" class="progress-text">{{ progress }}%</div>
|
||||||
|
</Transition>
|
||||||
|
|
||||||
|
<div v-if="!isDragging && bookmarkLabel" class="bookmark-label">
|
||||||
|
{{ bookmarkLabel }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 拖拽时的提示 -->
|
||||||
|
<div v-if="isDragging" class="drag-hint">拖动调整</div>
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, nextTick, ref, onMounted, onUnmounted, watch } from 'vue'
|
||||||
|
import { useRoute } from 'vitepress'
|
||||||
|
import {
|
||||||
|
createReadingBookmarkSnapshot,
|
||||||
|
readReadingBookmark,
|
||||||
|
writeReadingBookmark
|
||||||
|
} from '../utils/readingBookmark.js'
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const progress = ref(0)
|
||||||
|
const showProgress = ref(false)
|
||||||
|
const showArrow = ref(false)
|
||||||
|
const articleTitle = ref('')
|
||||||
|
const activeSection = ref('')
|
||||||
|
const restoredBookmark = ref(null)
|
||||||
|
// Circle circumference = 2 * PI * r, where r=24
|
||||||
|
const circumference = 2 * Math.PI * 24
|
||||||
|
let scrollTimer = null
|
||||||
|
let saveTimer = null
|
||||||
|
let restoreTimer = null
|
||||||
|
let clickSaveTimer = null
|
||||||
|
|
||||||
|
// 拖拽相关状态
|
||||||
|
const isDragging = ref(false)
|
||||||
|
const startY = ref(0)
|
||||||
|
const startProgress = ref(0)
|
||||||
|
const movedDuringDrag = ref(false)
|
||||||
|
let dragRafId = null
|
||||||
|
let skipNextClick = false
|
||||||
|
|
||||||
|
const currentPath = () =>
|
||||||
|
`${window.location.pathname}${window.location.search || ''}`
|
||||||
|
|
||||||
|
const getClientStorage = () => {
|
||||||
|
try {
|
||||||
|
return window.localStorage
|
||||||
|
} catch {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getMaxScrollY = () =>
|
||||||
|
Math.max(0, document.documentElement.scrollHeight - window.innerHeight)
|
||||||
|
|
||||||
|
const getArticleTitle = () => {
|
||||||
|
const heading = document.querySelector('.vp-doc h1')
|
||||||
|
return (heading?.textContent || document.title || '').trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateActiveSection = () => {
|
||||||
|
const headings = Array.from(
|
||||||
|
document.querySelectorAll('.vp-doc h2, .vp-doc h3')
|
||||||
|
)
|
||||||
|
let current = ''
|
||||||
|
|
||||||
|
for (const heading of headings) {
|
||||||
|
if (heading.getBoundingClientRect().top <= 96) {
|
||||||
|
current = heading.textContent?.trim() || ''
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
activeSection.value = current
|
||||||
|
}
|
||||||
|
|
||||||
|
const bookmarkLabel = computed(() => {
|
||||||
|
const title = articleTitle.value || restoredBookmark.value?.title || ''
|
||||||
|
const section = activeSection.value || restoredBookmark.value?.section || ''
|
||||||
|
return section || title
|
||||||
|
})
|
||||||
|
|
||||||
|
const bookmarkTitle = computed(() => {
|
||||||
|
const title =
|
||||||
|
articleTitle.value || restoredBookmark.value?.title || '当前文章'
|
||||||
|
const section = activeSection.value || restoredBookmark.value?.section || ''
|
||||||
|
return section ? `${title} - ${section}` : title
|
||||||
|
})
|
||||||
|
|
||||||
|
const progressTitle = computed(() =>
|
||||||
|
isDragging.value
|
||||||
|
? '拖动调整位置'
|
||||||
|
: `${bookmarkTitle.value} · 阅读进度 ${progress.value}%`
|
||||||
|
)
|
||||||
|
|
||||||
|
const clearBookmarkSaveTimer = () => {
|
||||||
|
if (saveTimer) {
|
||||||
|
window.clearTimeout(saveTimer)
|
||||||
|
saveTimer = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const clearClickSaveTimer = () => {
|
||||||
|
if (clickSaveTimer) {
|
||||||
|
window.clearTimeout(clickSaveTimer)
|
||||||
|
clickSaveTimer = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveBookmark = (path = currentPath()) => {
|
||||||
|
writeReadingBookmark(
|
||||||
|
getClientStorage(),
|
||||||
|
createReadingBookmarkSnapshot({
|
||||||
|
path,
|
||||||
|
getTitle: () => articleTitle.value,
|
||||||
|
getSection: () => activeSection.value,
|
||||||
|
getScrollY: () => window.scrollY,
|
||||||
|
getProgress: () => progress.value
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const scheduleBookmarkSave = () => {
|
||||||
|
const path = currentPath()
|
||||||
|
clearBookmarkSaveTimer()
|
||||||
|
saveTimer = window.setTimeout(() => {
|
||||||
|
saveTimer = null
|
||||||
|
saveBookmark(path)
|
||||||
|
}, 180)
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateProgress = () => {
|
||||||
|
// 拖拽时不更新进度,避免冲突
|
||||||
|
if (isDragging.value) return
|
||||||
|
|
||||||
|
articleTitle.value = getArticleTitle()
|
||||||
|
updateActiveSection()
|
||||||
|
|
||||||
|
const scrollTop = window.scrollY
|
||||||
|
const docHeight = getMaxScrollY()
|
||||||
|
const scrollPercent = docHeight > 0 ? (scrollTop / docHeight) * 100 : 0
|
||||||
|
|
||||||
|
progress.value = Math.min(Math.round(scrollPercent), 100)
|
||||||
|
showProgress.value = scrollTop > 0 // 开始滚动就显示
|
||||||
|
restoredBookmark.value = null
|
||||||
|
|
||||||
|
// 滚动时显示百分比
|
||||||
|
showArrow.value = false
|
||||||
|
|
||||||
|
// 清除之前的定时器
|
||||||
|
if (scrollTimer) {
|
||||||
|
clearTimeout(scrollTimer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 停止滚动1.5秒后显示箭头
|
||||||
|
scrollTimer = window.setTimeout(() => {
|
||||||
|
if (window.scrollY > 0) {
|
||||||
|
showArrow.value = true
|
||||||
|
}
|
||||||
|
}, 1500)
|
||||||
|
|
||||||
|
scheduleBookmarkSave()
|
||||||
|
}
|
||||||
|
|
||||||
|
const restoreBookmark = async () => {
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
|
if (restoreTimer) {
|
||||||
|
window.clearTimeout(restoreTimer)
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreTimer = window.setTimeout(() => {
|
||||||
|
articleTitle.value = getArticleTitle()
|
||||||
|
updateActiveSection()
|
||||||
|
|
||||||
|
const saved = readReadingBookmark(
|
||||||
|
getClientStorage(),
|
||||||
|
currentPath(),
|
||||||
|
getMaxScrollY()
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!saved || saved.scrollY <= 0) {
|
||||||
|
updateProgress()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
restoredBookmark.value = saved
|
||||||
|
articleTitle.value = saved.title || articleTitle.value
|
||||||
|
activeSection.value = saved.section || activeSection.value
|
||||||
|
progress.value = saved.progress
|
||||||
|
showProgress.value = true
|
||||||
|
showArrow.value = true
|
||||||
|
|
||||||
|
window.scrollTo({
|
||||||
|
top: saved.scrollY,
|
||||||
|
behavior: 'auto'
|
||||||
|
})
|
||||||
|
|
||||||
|
window.setTimeout(updateProgress, 0)
|
||||||
|
}, 80)
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetRouteState = () => {
|
||||||
|
progress.value = 0
|
||||||
|
showProgress.value = false
|
||||||
|
showArrow.value = false
|
||||||
|
restoredBookmark.value = null
|
||||||
|
articleTitle.value = ''
|
||||||
|
activeSection.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始拖拽
|
||||||
|
const startDrag = (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
isDragging.value = true
|
||||||
|
startY.value = 'touches' in e ? e.touches[0].clientY : e.clientY
|
||||||
|
startProgress.value = progress.value
|
||||||
|
movedDuringDrag.value = false
|
||||||
|
|
||||||
|
// 添加全局事件监听
|
||||||
|
document.addEventListener('mousemove', onDrag, { passive: false })
|
||||||
|
document.addEventListener('mouseup', endDrag)
|
||||||
|
document.addEventListener('touchmove', onDrag, { passive: false })
|
||||||
|
document.addEventListener('touchend', endDrag)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拖拽中
|
||||||
|
const onDrag = (e) => {
|
||||||
|
if (!isDragging.value) return
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
const currentY = 'touches' in e ? e.touches[0].clientY : e.clientY
|
||||||
|
const deltaY = startY.value - currentY // 向上拖动为正值
|
||||||
|
if (Math.abs(deltaY) > 4) {
|
||||||
|
movedDuringDrag.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每拖动 3 像素调整 1% 进度
|
||||||
|
const sensitivity = 3
|
||||||
|
const progressDelta = deltaY / sensitivity
|
||||||
|
|
||||||
|
// 计算新的进度值
|
||||||
|
let newProgress = startProgress.value + progressDelta
|
||||||
|
newProgress = Math.max(0, Math.min(100, newProgress))
|
||||||
|
|
||||||
|
// 使用 requestAnimationFrame 优化性能
|
||||||
|
if (dragRafId) {
|
||||||
|
cancelAnimationFrame(dragRafId)
|
||||||
|
}
|
||||||
|
|
||||||
|
dragRafId = requestAnimationFrame(() => {
|
||||||
|
progress.value = Math.round(newProgress)
|
||||||
|
|
||||||
|
// 实时滚动页面
|
||||||
|
const docHeight = document.documentElement.scrollHeight - window.innerHeight
|
||||||
|
if (docHeight > 0) {
|
||||||
|
window.scrollTo({
|
||||||
|
top: (progress.value / 100) * docHeight,
|
||||||
|
behavior: 'auto' // 拖拽时使用 auto 避免延迟
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 结束拖拽
|
||||||
|
const endDrag = () => {
|
||||||
|
const shouldSkipClick = movedDuringDrag.value
|
||||||
|
isDragging.value = false
|
||||||
|
|
||||||
|
// 清除事件监听
|
||||||
|
document.removeEventListener('mousemove', onDrag)
|
||||||
|
document.removeEventListener('mouseup', endDrag)
|
||||||
|
document.removeEventListener('touchmove', onDrag)
|
||||||
|
document.removeEventListener('touchend', endDrag)
|
||||||
|
|
||||||
|
if (dragRafId) {
|
||||||
|
cancelAnimationFrame(dragRafId)
|
||||||
|
dragRafId = null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 恢复箭头显示
|
||||||
|
if (window.scrollY > 0) {
|
||||||
|
showArrow.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
articleTitle.value = getArticleTitle()
|
||||||
|
updateActiveSection()
|
||||||
|
saveBookmark()
|
||||||
|
|
||||||
|
if (shouldSkipClick) {
|
||||||
|
skipNextClick = true
|
||||||
|
window.setTimeout(() => {
|
||||||
|
skipNextClick = false
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 点击回到顶部
|
||||||
|
const handleClick = () => {
|
||||||
|
// 如果是拖拽结束后的点击,不触发回到顶部
|
||||||
|
if (isDragging.value || skipNextClick) {
|
||||||
|
skipNextClick = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
window.scrollTo({
|
||||||
|
top: 0,
|
||||||
|
behavior: 'smooth'
|
||||||
|
})
|
||||||
|
|
||||||
|
const path = currentPath()
|
||||||
|
clearClickSaveTimer()
|
||||||
|
clickSaveTimer = window.setTimeout(() => {
|
||||||
|
clickSaveTimer = null
|
||||||
|
updateProgress()
|
||||||
|
saveBookmark(path)
|
||||||
|
}, 400)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
window.addEventListener('scroll', updateProgress, { passive: true })
|
||||||
|
restoreBookmark()
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('scroll', updateProgress)
|
||||||
|
if (scrollTimer) {
|
||||||
|
clearTimeout(scrollTimer)
|
||||||
|
}
|
||||||
|
clearBookmarkSaveTimer()
|
||||||
|
if (restoreTimer) {
|
||||||
|
clearTimeout(restoreTimer)
|
||||||
|
}
|
||||||
|
clearClickSaveTimer()
|
||||||
|
// 清理拖拽事件
|
||||||
|
document.removeEventListener('mousemove', onDrag)
|
||||||
|
document.removeEventListener('mouseup', endDrag)
|
||||||
|
document.removeEventListener('touchmove', onDrag)
|
||||||
|
document.removeEventListener('touchend', endDrag)
|
||||||
|
if (dragRafId) {
|
||||||
|
cancelAnimationFrame(dragRafId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.path,
|
||||||
|
() => {
|
||||||
|
clearBookmarkSaveTimer()
|
||||||
|
clearClickSaveTimer()
|
||||||
|
resetRouteState()
|
||||||
|
restoreBookmark()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.reading-progress {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 32px;
|
||||||
|
right: 32px;
|
||||||
|
width: 56px;
|
||||||
|
height: 56px;
|
||||||
|
cursor: grab;
|
||||||
|
z-index: 100;
|
||||||
|
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.1));
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
user-select: none;
|
||||||
|
touch-action: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reading-progress:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reading-progress:focus-visible {
|
||||||
|
outline: 2px solid var(--vp-c-brand-1);
|
||||||
|
outline-offset: 2px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .reading-progress {
|
||||||
|
filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.3));
|
||||||
|
}
|
||||||
|
|
||||||
|
.reading-progress:hover {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.reading-progress:active {
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
.reading-progress.is-dragging {
|
||||||
|
cursor: grabbing;
|
||||||
|
transform: scale(1.15);
|
||||||
|
filter: drop-shadow(0 4px 16px rgba(0, 0, 0, 0.2));
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-ring {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-ring-bg {
|
||||||
|
fill: var(--vp-c-bg);
|
||||||
|
stroke: var(--vp-c-divider);
|
||||||
|
stroke-width: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-ring-circle {
|
||||||
|
fill: none;
|
||||||
|
stroke: var(--vp-c-brand-1);
|
||||||
|
stroke-width: 3;
|
||||||
|
stroke-linecap: round;
|
||||||
|
stroke-dasharray: 150.796; /* 2πr = 2 * 3.14159 * 24 */
|
||||||
|
transition: stroke-dashoffset 0.1s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reading-progress.is-dragging .progress-ring-circle {
|
||||||
|
transition: none; /* 拖拽时移除过渡动画,更跟手 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-text {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-arrow {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
font-size: 26px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--vp-c-brand-1);
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
animation: bounce 1s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bookmark-label {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 100%;
|
||||||
|
width: max-content;
|
||||||
|
max-width: min(260px, calc(100vw - 48px));
|
||||||
|
margin-bottom: 8px;
|
||||||
|
padding: 5px 9px;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.4;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0;
|
||||||
|
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08);
|
||||||
|
transition: opacity 0.18s ease, transform 0.18s ease;
|
||||||
|
transform: translateY(4px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.reading-progress:hover .bookmark-label {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes bounce {
|
||||||
|
0%, 100% {
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translate(-50%, -60%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 拖拽提示 */
|
||||||
|
.drag-hint {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 100%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
margin-bottom: 8px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
white-space: nowrap;
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0;
|
||||||
|
animation: fadeIn 0.2s ease forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 内容切换动画 */
|
||||||
|
.content-switch-enter-active {
|
||||||
|
transition: opacity 0.2s ease, transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-switch-leave-active {
|
||||||
|
transition: opacity 0.15s ease, transform 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-switch-enter-from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate(-50%, -40%) scale(0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-switch-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate(-50%, -60%) scale(0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 渐入渐出动画 */
|
||||||
|
.progress-fade-enter-active,
|
||||||
|
.progress-fade-leave-active {
|
||||||
|
transition: opacity 0.3s ease, transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-fade-enter-from,
|
||||||
|
.progress-fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.8) translateY(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 移动端适配 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.reading-progress {
|
||||||
|
bottom: 20px;
|
||||||
|
right: 20px;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-text {
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-arrow {
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
<script setup>
|
||||||
|
import NavCard from './NavCard.vue'
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '继续阅读'
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
items: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<section class="related-section">
|
||||||
|
<div class="related-header">
|
||||||
|
<h2 class="related-title">
|
||||||
|
{{ title }}
|
||||||
|
</h2>
|
||||||
|
<p
|
||||||
|
v-if="description"
|
||||||
|
class="related-description"
|
||||||
|
>
|
||||||
|
{{ description }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="related-grid">
|
||||||
|
<NavCard
|
||||||
|
v-for="(item, index) in items"
|
||||||
|
:key="item.href || index"
|
||||||
|
:href="item.href"
|
||||||
|
:title="item.title"
|
||||||
|
:description="item.description"
|
||||||
|
:icon="item.icon"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.related-section {
|
||||||
|
margin: 44px 0 10px;
|
||||||
|
padding: 22px;
|
||||||
|
border-radius: 28px;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.06);
|
||||||
|
background: linear-gradient(180deg, rgba(0, 102, 204, 0.04) 0%, rgba(255, 255, 255, 0.98) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .related-section {
|
||||||
|
border-color: rgba(255, 255, 255, 0.1);
|
||||||
|
background: linear-gradient(180deg, rgba(60, 160, 255, 0.1) 0%, var(--vp-c-bg-soft) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-header {
|
||||||
|
margin-bottom: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-title {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
line-height: 1.35;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-description {
|
||||||
|
margin: 8px 0 0;
|
||||||
|
font-size: 0.92rem;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
line-height: 1.65;
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.related-section {
|
||||||
|
margin-top: 36px;
|
||||||
|
padding: 18px;
|
||||||
|
border-radius: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<template>
|
||||||
|
<el-steps
|
||||||
|
:active="active"
|
||||||
|
align-center
|
||||||
|
>
|
||||||
|
<el-step
|
||||||
|
v-for="(item, index) in items"
|
||||||
|
:key="index"
|
||||||
|
:title="item.title"
|
||||||
|
:description="item.description"
|
||||||
|
/>
|
||||||
|
</el-steps>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
defineProps({
|
||||||
|
active: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
items: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [
|
||||||
|
{ title: '困境与机会', description: '普通人的编程新可能' },
|
||||||
|
{ title: '能力初探', description: '60秒极速开发体验' },
|
||||||
|
{ title: '原生实战', description: '打造AI原生贪吃蛇' },
|
||||||
|
{ title: '拓展创造', description: '举一反三做游戏' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,335 @@
|
|||||||
|
<script setup>
|
||||||
|
const props = defineProps({
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '本幕小结'
|
||||||
|
},
|
||||||
|
sections: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
outputs: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="summary-card">
|
||||||
|
<div class="summary-header">
|
||||||
|
<div class="header-icon">
|
||||||
|
📚
|
||||||
|
</div>
|
||||||
|
<div class="header-content">
|
||||||
|
<div class="summary-title">
|
||||||
|
{{ title }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="summary-body">
|
||||||
|
<!-- Sections -->
|
||||||
|
<div
|
||||||
|
v-if="sections.length > 0"
|
||||||
|
class="sections-container"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(section, index) in sections"
|
||||||
|
:key="index"
|
||||||
|
class="section-item"
|
||||||
|
>
|
||||||
|
<div class="section-header">
|
||||||
|
<span class="section-number">{{ section.number }}</span>
|
||||||
|
<span class="section-title">{{ section.title }}</span>
|
||||||
|
</div>
|
||||||
|
<ul class="section-list">
|
||||||
|
<li
|
||||||
|
v-for="(item, itemIndex) in section.items"
|
||||||
|
:key="itemIndex"
|
||||||
|
class="list-item"
|
||||||
|
>
|
||||||
|
<span class="item-marker">•</span>
|
||||||
|
<span
|
||||||
|
class="item-content"
|
||||||
|
v-html="item"
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Outputs -->
|
||||||
|
<div
|
||||||
|
v-if="outputs.length > 0"
|
||||||
|
class="outputs-section"
|
||||||
|
>
|
||||||
|
<div class="outputs-header">
|
||||||
|
<span class="outputs-icon">📦</span>
|
||||||
|
<span class="outputs-title">本幕输出:</span>
|
||||||
|
</div>
|
||||||
|
<ul class="outputs-list">
|
||||||
|
<li
|
||||||
|
v-for="(output, index) in outputs"
|
||||||
|
:key="index"
|
||||||
|
class="output-item"
|
||||||
|
>
|
||||||
|
<span class="output-marker">✓</span>
|
||||||
|
<span
|
||||||
|
class="output-content"
|
||||||
|
v-html="output"
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.summary-card {
|
||||||
|
margin: 14px 0;
|
||||||
|
border-radius: 14px;
|
||||||
|
background: linear-gradient(
|
||||||
|
160deg,
|
||||||
|
rgba(var(--vp-c-brand-rgb), 0.06) 0%,
|
||||||
|
rgba(var(--vp-c-brand-rgb), 0.015) 40%,
|
||||||
|
var(--vp-c-bg) 100%
|
||||||
|
);
|
||||||
|
border: 1px solid rgba(var(--vp-c-brand-rgb), 0.12);
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow:
|
||||||
|
0 8px 24px rgba(0, 0, 0, 0.06),
|
||||||
|
0 2px 8px rgba(0, 0, 0, 0.04);
|
||||||
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 10px 14px;
|
||||||
|
background: linear-gradient(
|
||||||
|
120deg,
|
||||||
|
rgba(var(--vp-c-brand-rgb), 0.16),
|
||||||
|
rgba(var(--vp-c-brand-rgb), 0.04)
|
||||||
|
);
|
||||||
|
border-bottom: 1px solid rgba(var(--vp-c-brand-rgb), 0.16);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-icon {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 10px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 1.1em;
|
||||||
|
background: rgba(var(--vp-c-brand-rgb), 0.18);
|
||||||
|
color: var(--vp-c-brand);
|
||||||
|
box-shadow: inset 0 0 0 1px rgba(var(--vp-c-brand-rgb), 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-content {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-title {
|
||||||
|
font-size: 1em;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
letter-spacing: 0.2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-body {
|
||||||
|
padding: 12px 14px 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sections */
|
||||||
|
.sections-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-item {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
border: 1px solid rgba(var(--vp-c-brand-rgb), 0.12);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.04);
|
||||||
|
transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-item:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
border-color: rgba(var(--vp-c-brand-rgb), 0.3);
|
||||||
|
box-shadow: 0 10px 18px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 4px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-number {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
padding: 0 7px;
|
||||||
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
var(--vp-c-brand),
|
||||||
|
var(--vp-c-brand-dark)
|
||||||
|
);
|
||||||
|
color: white;
|
||||||
|
border-radius: 999px;
|
||||||
|
font-size: 0.74em;
|
||||||
|
font-weight: 700;
|
||||||
|
box-shadow: 0 4px 10px rgba(var(--vp-c-brand-rgb), 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 0.95em;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-list {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 3px 0;
|
||||||
|
line-height: 1.45;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-marker {
|
||||||
|
color: var(--vp-c-brand);
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.9em;
|
||||||
|
line-height: 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-content {
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
font-size: 0.92em;
|
||||||
|
line-height: 1.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-content :deep(strong) {
|
||||||
|
color: var(--vp-c-brand-dark);
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Outputs */
|
||||||
|
.outputs-section {
|
||||||
|
margin-top: 12px;
|
||||||
|
padding: 10px 12px 8px;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: rgba(var(--vp-c-brand-rgb), 0.06);
|
||||||
|
border: 1px dashed rgba(var(--vp-c-brand-rgb), 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.outputs-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outputs-icon {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outputs-title {
|
||||||
|
font-size: 0.9em;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.outputs-list {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.output-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 2px 0;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.output-marker {
|
||||||
|
color: #42d392;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 0.85em;
|
||||||
|
line-height: 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
border-radius: 6px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: rgba(66, 211, 146, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.output-content {
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
font-size: 0.92em;
|
||||||
|
line-height: 1.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
.output-content :deep(strong) {
|
||||||
|
color: var(--vp-c-brand-dark);
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive */
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.summary-card {
|
||||||
|
margin: 14px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-header {
|
||||||
|
padding: 8px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-body {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-item {
|
||||||
|
padding: 8px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-content,
|
||||||
|
.output-content {
|
||||||
|
font-size: 0.88em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,308 @@
|
|||||||
|
<script setup>
|
||||||
|
import {
|
||||||
|
computed,
|
||||||
|
onMounted,
|
||||||
|
onUnmounted,
|
||||||
|
ref,
|
||||||
|
useAttrs,
|
||||||
|
watchEffect
|
||||||
|
} from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
text: {
|
||||||
|
type: [String, Array],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
as: {
|
||||||
|
type: [String, Object],
|
||||||
|
default: 'div'
|
||||||
|
},
|
||||||
|
typingSpeed: {
|
||||||
|
type: Number,
|
||||||
|
default: 50
|
||||||
|
},
|
||||||
|
initialDelay: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
pauseDuration: {
|
||||||
|
type: Number,
|
||||||
|
default: 2000
|
||||||
|
},
|
||||||
|
postDeletingDelay: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
deletingSpeed: {
|
||||||
|
type: Number,
|
||||||
|
default: 30
|
||||||
|
},
|
||||||
|
loop: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
className: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
showCursor: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
hideCursorWhileTyping: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
cursorCharacter: {
|
||||||
|
type: String,
|
||||||
|
default: '|'
|
||||||
|
},
|
||||||
|
cursorClassName: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
cursorBlinkDuration: {
|
||||||
|
type: Number,
|
||||||
|
default: 0.5
|
||||||
|
},
|
||||||
|
textColors: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
variableSpeed: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
onSentenceComplete: {
|
||||||
|
type: Function,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
startOnVisible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
reverseMode: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const isClient = typeof window !== 'undefined'
|
||||||
|
|
||||||
|
const attrs = useAttrs()
|
||||||
|
|
||||||
|
const displayedText = ref('')
|
||||||
|
const currentCharIndex = ref(0)
|
||||||
|
const isDeleting = ref(false)
|
||||||
|
const currentTextIndex = ref(0)
|
||||||
|
const isVisible = ref(!props.startOnVisible)
|
||||||
|
const containerRef = ref(null)
|
||||||
|
|
||||||
|
const textArray = computed(() =>
|
||||||
|
Array.isArray(props.text) ? props.text : [props.text]
|
||||||
|
)
|
||||||
|
|
||||||
|
const cursorStyle = computed(() => ({
|
||||||
|
animationDuration: `${props.cursorBlinkDuration}s`
|
||||||
|
}))
|
||||||
|
|
||||||
|
const currentColor = computed(() => {
|
||||||
|
if (!props.textColors.length) return undefined
|
||||||
|
return props.textColors[currentTextIndex.value % props.textColors.length]
|
||||||
|
})
|
||||||
|
|
||||||
|
const getRandomSpeed = () => {
|
||||||
|
if (!props.variableSpeed) return props.typingSpeed
|
||||||
|
const min =
|
||||||
|
typeof props.variableSpeed.min === 'number'
|
||||||
|
? props.variableSpeed.min
|
||||||
|
: props.typingSpeed
|
||||||
|
const max =
|
||||||
|
typeof props.variableSpeed.max === 'number'
|
||||||
|
? props.variableSpeed.max
|
||||||
|
: props.typingSpeed
|
||||||
|
if (max <= min) return min
|
||||||
|
return Math.random() * (max - min) + min
|
||||||
|
}
|
||||||
|
|
||||||
|
let observer
|
||||||
|
onMounted(() => {
|
||||||
|
if (!props.startOnVisible || !containerRef.value) return
|
||||||
|
observer = new IntersectionObserver(
|
||||||
|
(entries) => {
|
||||||
|
for (const entry of entries) {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
isVisible.value = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ threshold: 0.1 }
|
||||||
|
)
|
||||||
|
observer.observe(containerRef.value)
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (observer) observer.disconnect()
|
||||||
|
})
|
||||||
|
|
||||||
|
watchEffect((onCleanup) => {
|
||||||
|
if (!isVisible.value) return
|
||||||
|
|
||||||
|
if (!textArray.value.length) {
|
||||||
|
displayedText.value = ''
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentText = textArray.value[currentTextIndex.value] ?? ''
|
||||||
|
const processedText = props.reverseMode
|
||||||
|
? String(currentText).split('').reverse().join('')
|
||||||
|
: String(currentText)
|
||||||
|
|
||||||
|
if (!isClient) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const shouldStopAtEnd =
|
||||||
|
!props.loop && currentTextIndex.value === textArray.value.length - 1
|
||||||
|
|
||||||
|
let timeoutId
|
||||||
|
|
||||||
|
const schedule = () => {
|
||||||
|
if (isDeleting.value) {
|
||||||
|
if (!displayedText.value) {
|
||||||
|
isDeleting.value = false
|
||||||
|
if (props.onSentenceComplete) {
|
||||||
|
props.onSentenceComplete(
|
||||||
|
textArray.value[currentTextIndex.value],
|
||||||
|
currentTextIndex.value
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (shouldStopAtEnd) return
|
||||||
|
timeoutId = setTimeout(() => {
|
||||||
|
currentTextIndex.value =
|
||||||
|
(currentTextIndex.value + 1) % textArray.value.length
|
||||||
|
currentCharIndex.value = 0
|
||||||
|
}, props.postDeletingDelay)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
timeoutId = setTimeout(() => {
|
||||||
|
displayedText.value = displayedText.value.slice(0, -1)
|
||||||
|
}, props.deletingSpeed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentCharIndex.value < processedText.length) {
|
||||||
|
timeoutId = setTimeout(
|
||||||
|
() => {
|
||||||
|
displayedText.value += processedText[currentCharIndex.value]
|
||||||
|
currentCharIndex.value += 1
|
||||||
|
},
|
||||||
|
props.variableSpeed ? getRandomSpeed() : props.typingSpeed
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldStopAtEnd) return
|
||||||
|
timeoutId = setTimeout(() => {
|
||||||
|
isDeleting.value = true
|
||||||
|
}, props.pauseDuration)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
currentCharIndex.value === 0 &&
|
||||||
|
!isDeleting.value &&
|
||||||
|
!displayedText.value
|
||||||
|
) {
|
||||||
|
timeoutId = setTimeout(schedule, props.initialDelay)
|
||||||
|
} else {
|
||||||
|
schedule()
|
||||||
|
}
|
||||||
|
|
||||||
|
onCleanup(() => clearTimeout(timeoutId))
|
||||||
|
})
|
||||||
|
|
||||||
|
const shouldHideCursor = computed(() => {
|
||||||
|
if (!props.hideCursorWhileTyping) return false
|
||||||
|
const currentText = textArray.value[currentTextIndex.value] ?? ''
|
||||||
|
const processedText = props.reverseMode
|
||||||
|
? String(currentText).split('').reverse().join('')
|
||||||
|
: String(currentText)
|
||||||
|
return currentCharIndex.value < processedText.length || isDeleting.value
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<component
|
||||||
|
:is="as"
|
||||||
|
ref="containerRef"
|
||||||
|
:class="['text-type', className]"
|
||||||
|
v-bind="attrs"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="text-type__content"
|
||||||
|
:style="{ color: currentColor || 'inherit' }"
|
||||||
|
>
|
||||||
|
{{ displayedText }}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
v-if="showCursor"
|
||||||
|
class="text-type__cursor"
|
||||||
|
:class="[
|
||||||
|
cursorClassName,
|
||||||
|
shouldHideCursor ? 'text-type__cursor--hidden' : ''
|
||||||
|
]"
|
||||||
|
:style="cursorStyle"
|
||||||
|
>
|
||||||
|
{{ cursorCharacter }}
|
||||||
|
</span>
|
||||||
|
</component>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.text-type {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: baseline;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-type__content {
|
||||||
|
display: inline;
|
||||||
|
white-space: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 960px) {
|
||||||
|
.text-type {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.text-type__content {
|
||||||
|
display: inline-block;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-type__cursor {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 2px;
|
||||||
|
animation-name: text-type-blink;
|
||||||
|
animation-timing-function: ease-in-out;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
animation-direction: alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-type__cursor--hidden {
|
||||||
|
opacity: 0;
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes text-type-blink {
|
||||||
|
from {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,590 @@
|
|||||||
|
<script setup>
|
||||||
|
import { computed, inject, onMounted, onUnmounted, ref } from 'vue'
|
||||||
|
import { withBase } from 'vitepress'
|
||||||
|
import macbookImage from '../../../../assets/macbook.png'
|
||||||
|
import story1Cover from '../../../zh-cn/vibe-stories/images/story-1/image5.png'
|
||||||
|
import story2Cover from '../../../zh-cn/vibe-stories/images/story-2/image4.png'
|
||||||
|
import story3Cover from '../../../zh-cn/vibe-stories/images/story-3/image3.png'
|
||||||
|
import story4Cover from '../../../zh-cn/vibe-stories/images/story-4/image7.png'
|
||||||
|
|
||||||
|
// Try to inject translation context from parent or provide a default fallback
|
||||||
|
const t = inject('t', {
|
||||||
|
value: {
|
||||||
|
stories: {
|
||||||
|
cat: '用户故事',
|
||||||
|
title: '看见每一个<br><span class="highlight">闪亮的你</span>',
|
||||||
|
sub: '加入他们,分享你的 vibe coding 故事',
|
||||||
|
authorPrefix: '讲述者:',
|
||||||
|
ui: {
|
||||||
|
prevLabel: '上一则故事',
|
||||||
|
nextLabel: '下一则故事',
|
||||||
|
selectLabel: '查看这个故事',
|
||||||
|
imageAlt: '用户故事封面'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const tStories = computed(() => [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: t.value?.stories?.s1?.title || '放弃月入过万,他在农村小学带孩子们“用AI赶苍蝇”',
|
||||||
|
author: t.value?.stories?.s1?.author || '小学老师小浩',
|
||||||
|
avatar: '👨🏫',
|
||||||
|
image: story1Cover,
|
||||||
|
imageStyle: {
|
||||||
|
objectPosition: 'center center'
|
||||||
|
},
|
||||||
|
link: '/zh-cn/vibe-stories/story-1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
title: t.value?.stories?.s2?.title || '期末考试周,我偷偷用AI造了个“校园闲鱼”',
|
||||||
|
author: t.value?.stories?.s2?.author || '一位大二学生',
|
||||||
|
avatar: '🎓',
|
||||||
|
image: story2Cover,
|
||||||
|
imageStyle: {
|
||||||
|
objectPosition: 'center center'
|
||||||
|
},
|
||||||
|
link: '/zh-cn/vibe-stories/story-2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
title: t.value?.stories?.s3?.title || '我给每个学生,做了一个不会累的“学霸同桌”',
|
||||||
|
author: t.value?.stories?.s3?.author || '高中信息技术老师',
|
||||||
|
avatar: '🧑🏫',
|
||||||
|
image: story3Cover,
|
||||||
|
imageStyle: {
|
||||||
|
objectPosition: '34% center'
|
||||||
|
},
|
||||||
|
link: '/zh-cn/vibe-stories/story-3'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
title: t.value?.stories?.s4?.title || '48岁货车司机,熬了几个通宵,硬是用AI磕出一个出海工具站',
|
||||||
|
author: t.value?.stories?.s4?.author || '货车司机老黄',
|
||||||
|
avatar: '🚚',
|
||||||
|
image: story4Cover,
|
||||||
|
imageStyle: {
|
||||||
|
objectPosition: 'center center'
|
||||||
|
},
|
||||||
|
link: '/zh-cn/vibe-stories/story-4'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const defaultScreenViewport = Object.freeze({
|
||||||
|
left: 19,
|
||||||
|
top: 1.75,
|
||||||
|
width: 62.75,
|
||||||
|
height: 71.5,
|
||||||
|
radius: 12
|
||||||
|
})
|
||||||
|
|
||||||
|
const currentIndex = ref(0)
|
||||||
|
let autoplayTimer = null
|
||||||
|
const isPaginating = ref(false)
|
||||||
|
const containerRef = ref(null)
|
||||||
|
const laptopRef = ref(null)
|
||||||
|
let wheelHandler = null
|
||||||
|
let resizeObserver = null
|
||||||
|
|
||||||
|
const LAPTOP_ASPECT_RATIO = 2675 / 4608
|
||||||
|
const laptopHeightPx = ref(null)
|
||||||
|
|
||||||
|
// Visible image container geometry relative to `.laptop-container`.
|
||||||
|
// Adjust these five values directly to control the screen viewport.
|
||||||
|
const screenViewport = ref({ ...defaultScreenViewport })
|
||||||
|
|
||||||
|
const formatPercent = (value) => `${value}%`
|
||||||
|
const formatPixels = (value) => `${value}px`
|
||||||
|
|
||||||
|
// The percentages below are always resolved against `.laptop-container`.
|
||||||
|
const screenViewportStyle = computed(() => ({
|
||||||
|
'--screen-left': formatPercent(screenViewport.value.left),
|
||||||
|
'--screen-top': formatPercent(screenViewport.value.top),
|
||||||
|
'--screen-width': formatPercent(screenViewport.value.width),
|
||||||
|
'--screen-height': formatPercent(screenViewport.value.height),
|
||||||
|
'--screen-radius': formatPixels(screenViewport.value.radius)
|
||||||
|
}))
|
||||||
|
|
||||||
|
const currentStory = computed(() => tStories.value[currentIndex.value] ?? tStories.value[0])
|
||||||
|
|
||||||
|
const currentImageStyle = computed(() => currentStory.value?.imageStyle || {})
|
||||||
|
|
||||||
|
const laptopContainerStyle = computed(() => (
|
||||||
|
laptopHeightPx.value
|
||||||
|
? { height: `${laptopHeightPx.value}px` }
|
||||||
|
: {}
|
||||||
|
))
|
||||||
|
|
||||||
|
const transitionName = ref('slide-left')
|
||||||
|
|
||||||
|
const next = () => {
|
||||||
|
if (isPaginating.value) return
|
||||||
|
isPaginating.value = true
|
||||||
|
transitionName.value = 'slide-left'
|
||||||
|
currentIndex.value = (currentIndex.value + 1) % tStories.value.length
|
||||||
|
setTimeout(() => {
|
||||||
|
isPaginating.value = false
|
||||||
|
}, 800)
|
||||||
|
}
|
||||||
|
|
||||||
|
const prev = () => {
|
||||||
|
if (isPaginating.value) return
|
||||||
|
isPaginating.value = true
|
||||||
|
transitionName.value = 'slide-right'
|
||||||
|
currentIndex.value = (currentIndex.value - 1 + tStories.value.length) % tStories.value.length
|
||||||
|
setTimeout(() => {
|
||||||
|
isPaginating.value = false
|
||||||
|
}, 800)
|
||||||
|
}
|
||||||
|
|
||||||
|
const setIndex = (index) => {
|
||||||
|
if (index === currentIndex.value) return
|
||||||
|
transitionName.value = index > currentIndex.value ? 'slide-left' : 'slide-right'
|
||||||
|
currentIndex.value = index
|
||||||
|
}
|
||||||
|
|
||||||
|
const startAutoplay = () => {
|
||||||
|
autoplayTimer = setInterval(() => {
|
||||||
|
if (!isPaginating.value) {
|
||||||
|
transitionName.value = 'slide-left'
|
||||||
|
currentIndex.value = (currentIndex.value + 1) % tStories.value.length
|
||||||
|
}
|
||||||
|
}, 4000)
|
||||||
|
}
|
||||||
|
|
||||||
|
const stopAutoplay = () => {
|
||||||
|
if (autoplayTimer) {
|
||||||
|
clearInterval(autoplayTimer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateLaptopHeight = () => {
|
||||||
|
const laptop = laptopRef.value
|
||||||
|
if (!laptop) return
|
||||||
|
|
||||||
|
const nextHeight = laptop.clientWidth * LAPTOP_ASPECT_RATIO
|
||||||
|
laptopHeightPx.value = nextHeight > 0 ? nextHeight : null
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
startAutoplay()
|
||||||
|
const container = containerRef.value
|
||||||
|
const laptop = laptopRef.value
|
||||||
|
if (!container) return
|
||||||
|
|
||||||
|
wheelHandler = (e) => {
|
||||||
|
if (Math.abs(e.deltaX) > 20 && Math.abs(e.deltaX) > Math.abs(e.deltaY)) {
|
||||||
|
e.preventDefault()
|
||||||
|
if (e.deltaX > 0) {
|
||||||
|
next()
|
||||||
|
} else {
|
||||||
|
prev()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
container.addEventListener('wheel', wheelHandler, { passive: false })
|
||||||
|
|
||||||
|
updateLaptopHeight()
|
||||||
|
|
||||||
|
if (typeof ResizeObserver !== 'undefined' && laptop) {
|
||||||
|
resizeObserver = new ResizeObserver(() => {
|
||||||
|
updateLaptopHeight()
|
||||||
|
})
|
||||||
|
resizeObserver.observe(laptop)
|
||||||
|
} else if (typeof window !== 'undefined') {
|
||||||
|
window.addEventListener('resize', updateLaptopHeight)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
stopAutoplay()
|
||||||
|
const container = containerRef.value
|
||||||
|
if (container && wheelHandler) {
|
||||||
|
container.removeEventListener('wheel', wheelHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resizeObserver) {
|
||||||
|
resizeObserver.disconnect()
|
||||||
|
resizeObserver = null
|
||||||
|
} else if (typeof window !== 'undefined') {
|
||||||
|
window.removeEventListener('resize', updateLaptopHeight)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div ref="containerRef" class="vibe-stories-container">
|
||||||
|
<div class="section-header">
|
||||||
|
<h3 class="section-headline" v-html="t.stories?.title || '看见每一个<br><span class=\'highlight\'>闪亮的你</span>'"></h3>
|
||||||
|
<p class="section-sub">{{ t.stories?.sub || '加入他们,分享你的 vibe coding 故事' }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="laptop-wrapper" @mouseenter="stopAutoplay" @mouseleave="startAutoplay">
|
||||||
|
<div ref="laptopRef" class="laptop-container" :style="laptopContainerStyle">
|
||||||
|
<!-- Navigation Controls -->
|
||||||
|
<button class="nav-btn prev" :aria-label="t.stories?.ui?.prevLabel || 'Previous story'" @click="prev">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6" /></svg>
|
||||||
|
</button>
|
||||||
|
<button class="nav-btn next" :aria-label="t.stories?.ui?.nextLabel || 'Next story'" @click="next">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6" /></svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="screen-content" :style="screenViewportStyle">
|
||||||
|
<a :href="withBase(currentStory.link)" class="screen-link">
|
||||||
|
<transition :name="transitionName">
|
||||||
|
<div :key="currentStory.id" class="screen-image-wrapper">
|
||||||
|
<img
|
||||||
|
:src="currentStory.image"
|
||||||
|
class="screen-image"
|
||||||
|
:style="currentImageStyle"
|
||||||
|
:alt="t.stories?.ui?.imageAlt || 'Story screenshot'"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<!-- Laptop Frame -->
|
||||||
|
<img :src="macbookImage" class="laptop-frame" alt="MacBook Frame" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Story Info & Avatar -->
|
||||||
|
<div class="story-info">
|
||||||
|
<div class="story-avatar">{{ currentStory.avatar }}</div>
|
||||||
|
<div class="story-text">
|
||||||
|
<a :href="withBase(currentStory.link)" class="story-title">
|
||||||
|
{{ currentStory.title }}
|
||||||
|
</a>
|
||||||
|
<div class="story-author">{{ t.stories?.authorPrefix || 'by' }} {{ currentStory.author }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Indicators -->
|
||||||
|
<div class="indicators">
|
||||||
|
<button
|
||||||
|
v-for="(_, index) in tStories"
|
||||||
|
:key="index"
|
||||||
|
class="indicator-dot"
|
||||||
|
:class="{ active: index === currentIndex }"
|
||||||
|
:aria-label="t.stories?.ui?.selectLabel || 'Select story'"
|
||||||
|
@click="setIndex(index)"
|
||||||
|
></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.vibe-stories-container {
|
||||||
|
max-width: 1120px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 20px 28px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-headline {
|
||||||
|
font-size: 60px;
|
||||||
|
line-height: 1.08;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -0.034em;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: #1d1d1f;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'PingFang SC', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .section-headline {
|
||||||
|
color: #f5f5f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlight {
|
||||||
|
background: linear-gradient(120deg, #0066cc, #3399ff);
|
||||||
|
background-clip: text;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .highlight {
|
||||||
|
background: linear-gradient(120deg, #2997ff, #66b3ff);
|
||||||
|
background-clip: text;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-sub {
|
||||||
|
font-size: 19px;
|
||||||
|
line-height: 1.4;
|
||||||
|
font-weight: 400;
|
||||||
|
letter-spacing: -0.01em;
|
||||||
|
color: #6e6e73;
|
||||||
|
max-width: 760px;
|
||||||
|
margin: 0 auto;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'PingFang SC', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .section-sub {
|
||||||
|
color: #a1a1a6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.laptop-wrapper {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.laptop-container {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 700px;
|
||||||
|
margin: 0 auto;
|
||||||
|
aspect-ratio: 4608 / 2675;
|
||||||
|
}
|
||||||
|
|
||||||
|
.laptop-frame {
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
pointer-events: none;
|
||||||
|
filter: drop-shadow(0 25px 25px rgb(0 0 0 / 0.15));
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .laptop-frame {
|
||||||
|
filter: drop-shadow(0 25px 25px rgb(255 255 255 / 0.05));
|
||||||
|
}
|
||||||
|
|
||||||
|
.screen-content {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
top: var(--screen-top);
|
||||||
|
left: var(--screen-left);
|
||||||
|
width: var(--screen-width);
|
||||||
|
height: var(--screen-height);
|
||||||
|
border-radius: var(--screen-radius);
|
||||||
|
background: #0b0b0f;
|
||||||
|
overflow: hidden;
|
||||||
|
perspective: 1000px;
|
||||||
|
transform: translateZ(0);
|
||||||
|
-webkit-transform: translateZ(0);
|
||||||
|
-webkit-mask-image: -webkit-radial-gradient(white, black);
|
||||||
|
mask-image: radial-gradient(white, black);
|
||||||
|
isolation: isolate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.screen-link {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
display: block;
|
||||||
|
background: transparent;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.screen-link:focus,
|
||||||
|
.screen-link:focus-visible {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.screen-image-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.screen-image {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
min-width: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
max-width: none;
|
||||||
|
max-height: none;
|
||||||
|
object-fit: cover;
|
||||||
|
object-position: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Transitions */
|
||||||
|
.slide-left-enter-active,
|
||||||
|
.slide-left-leave-active,
|
||||||
|
.slide-right-enter-active,
|
||||||
|
.slide-right-leave-active {
|
||||||
|
transition: transform 0.6s cubic-bezier(0.25, 1, 0.5, 1);
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-left-enter-from {
|
||||||
|
transform: translateX(100%);
|
||||||
|
}
|
||||||
|
.slide-left-leave-to {
|
||||||
|
transform: translateX(-100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-right-enter-from {
|
||||||
|
transform: translateX(-100%);
|
||||||
|
}
|
||||||
|
.slide-right-leave-to {
|
||||||
|
transform: translateX(100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nav Buttons */
|
||||||
|
.nav-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
z-index: 20;
|
||||||
|
background: rgba(255, 255, 255, 0.6);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
border: none;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #333;
|
||||||
|
opacity: 0;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.laptop-wrapper:hover .nav-btn {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-btn:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.9);
|
||||||
|
transform: translateY(-50%) scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-btn.prev {
|
||||||
|
left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-btn.next {
|
||||||
|
right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.nav-btn {
|
||||||
|
opacity: 1;
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
.nav-btn.prev { left: 10px; }
|
||||||
|
.nav-btn.next { right: 10px; }
|
||||||
|
|
||||||
|
.section-headline { font-size: 42px; }
|
||||||
|
.section-sub { font-size: 17px; }
|
||||||
|
.laptop-container { max-width: 100%; }
|
||||||
|
.story-info {
|
||||||
|
margin-top: 18px;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Story Info */
|
||||||
|
.story-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 16px;
|
||||||
|
margin-top: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.story-avatar {
|
||||||
|
font-size: 48px;
|
||||||
|
line-height: 1;
|
||||||
|
background: #f5f5f7;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 72px;
|
||||||
|
height: 72px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .story-avatar {
|
||||||
|
background: #2c2c2e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.story-text {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.story-title {
|
||||||
|
display: block;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1d1d1f;
|
||||||
|
text-decoration: none;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
transition: color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .story-title {
|
||||||
|
color: #f5f5f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.story-title:hover {
|
||||||
|
color: #0066cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .story-title:hover {
|
||||||
|
color: #2997ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.story-author {
|
||||||
|
font-size: 15px;
|
||||||
|
color: #86868b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Indicators */
|
||||||
|
.indicators {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indicator-dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #d2d2d7;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .indicator-dot {
|
||||||
|
background: #424245;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indicator-dot:hover {
|
||||||
|
background: #86868b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.indicator-dot.active {
|
||||||
|
width: 24px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #1d1d1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .indicator-dot.active {
|
||||||
|
background: #f5f5f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,322 @@
|
|||||||
|
<script setup>
|
||||||
|
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||||
|
import { useRouter, withBase } from 'vitepress'
|
||||||
|
import easyVibePaths from '../data/easyVibePaths.json'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const WELCOME_SEEN_KEY = 'easy-vibe-welcome-seen'
|
||||||
|
const phase = ref('reset')
|
||||||
|
const theme = ref('ocean')
|
||||||
|
const themes = ['ocean', 'rainbow', 'sunset']
|
||||||
|
let timers = []
|
||||||
|
|
||||||
|
const themeColor = computed(() => `url(#welcome-${theme.value})`)
|
||||||
|
const themeClass = computed(() => `welcome-theme-${theme.value}`)
|
||||||
|
|
||||||
|
const clearTimers = () => {
|
||||||
|
timers.forEach((timer) => clearTimeout(timer))
|
||||||
|
timers = []
|
||||||
|
}
|
||||||
|
|
||||||
|
const runLoop = () => {
|
||||||
|
clearTimers()
|
||||||
|
const run = () => {
|
||||||
|
phase.value = 'draw'
|
||||||
|
timers.push(
|
||||||
|
setTimeout(() => {
|
||||||
|
phase.value = 'fade'
|
||||||
|
}, 5800)
|
||||||
|
)
|
||||||
|
timers.push(
|
||||||
|
setTimeout(() => {
|
||||||
|
phase.value = 'reset'
|
||||||
|
}, 7600)
|
||||||
|
)
|
||||||
|
timers.push(
|
||||||
|
setTimeout(() => {
|
||||||
|
const currentIndex = themes.indexOf(theme.value)
|
||||||
|
theme.value = themes[(currentIndex + 1) % themes.length]
|
||||||
|
run()
|
||||||
|
}, 7800)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
timers.push(setTimeout(run, 80))
|
||||||
|
}
|
||||||
|
|
||||||
|
const enterHome = () => {
|
||||||
|
const params = new URLSearchParams(window.location.search)
|
||||||
|
const nextPath = params.get('next')
|
||||||
|
window.localStorage.setItem(WELCOME_SEEN_KEY, '1')
|
||||||
|
if (nextPath) {
|
||||||
|
router.go(nextPath)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
router.go(withBase('/'))
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
runLoop()
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
clearTimers()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="welcome-overlay"
|
||||||
|
:class="themeClass"
|
||||||
|
@click="enterHome"
|
||||||
|
>
|
||||||
|
<div class="welcome-content">
|
||||||
|
<div
|
||||||
|
class="welcome-logo"
|
||||||
|
:style="{ '--welcome-theme-color': themeColor }"
|
||||||
|
:class="{
|
||||||
|
'welcome-fin': phase === 'draw' || phase === 'fade',
|
||||||
|
'welcome-fade': phase === 'fade',
|
||||||
|
'welcome-reset': phase === 'reset'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 460 220"
|
||||||
|
class="welcome-svg"
|
||||||
|
>
|
||||||
|
<defs>
|
||||||
|
<linearGradient
|
||||||
|
id="welcome-rainbow"
|
||||||
|
x1="0"
|
||||||
|
y1="0"
|
||||||
|
x2="460"
|
||||||
|
y2="0"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop offset="0%" stop-color="#00a6ff" />
|
||||||
|
<stop offset="18%" stop-color="#00c6a2" />
|
||||||
|
<stop offset="36%" stop-color="#53d93e" />
|
||||||
|
<stop offset="54%" stop-color="#f4c732" />
|
||||||
|
<stop offset="72%" stop-color="#ff7a1a" />
|
||||||
|
<stop offset="86%" stop-color="#ff3c81" />
|
||||||
|
<stop offset="100%" stop-color="#9d4edd" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="welcome-ocean"
|
||||||
|
x1="0"
|
||||||
|
y1="0"
|
||||||
|
x2="460"
|
||||||
|
y2="0"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop offset="0%" stop-color="#06b6d4" />
|
||||||
|
<stop offset="50%" stop-color="#0ea5e9" />
|
||||||
|
<stop offset="100%" stop-color="#3b82f6" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="welcome-sunset"
|
||||||
|
x1="0"
|
||||||
|
y1="0"
|
||||||
|
x2="460"
|
||||||
|
y2="0"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop offset="0%" stop-color="#f43f5e" />
|
||||||
|
<stop offset="50%" stop-color="#f97316" />
|
||||||
|
<stop offset="100%" stop-color="#f59e0b" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<path
|
||||||
|
v-for="(path, index) in easyVibePaths"
|
||||||
|
:key="index"
|
||||||
|
:d="path"
|
||||||
|
class="welcome-path"
|
||||||
|
:class="`welcome-path-${index}`"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<p class="welcome-tip">
|
||||||
|
Click anywhere to enter home
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.welcome-overlay {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
isolation: isolate;
|
||||||
|
background:
|
||||||
|
radial-gradient(120% 90% at 50% -20%, rgba(255, 255, 255, 0.86), rgba(255, 255, 255, 0)),
|
||||||
|
linear-gradient(135deg, #e8f8ff 0%, #e9edff 36%, #efe7ff 68%, #ffeef4 100%);
|
||||||
|
background-size: 130% 130%;
|
||||||
|
background-position: 0% 0%;
|
||||||
|
cursor: pointer;
|
||||||
|
animation: welcome-bg-base-flow 42s ease-in-out infinite alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-overlay::before,
|
||||||
|
.welcome-overlay::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: -18%;
|
||||||
|
pointer-events: none;
|
||||||
|
will-change: transform, opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-overlay::before {
|
||||||
|
background:
|
||||||
|
radial-gradient(60% 58% at 18% 45%, rgba(182, 225, 255, 0.32), rgba(182, 225, 255, 0)),
|
||||||
|
radial-gradient(48% 52% at 82% 62%, rgba(223, 199, 255, 0.28), rgba(223, 199, 255, 0));
|
||||||
|
animation: welcome-bg-wave-a 26s ease-in-out infinite alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-overlay::after {
|
||||||
|
background:
|
||||||
|
radial-gradient(54% 52% at 68% 26%, rgba(186, 245, 228, 0.24), rgba(186, 245, 228, 0)),
|
||||||
|
radial-gradient(56% 48% at 30% 82%, rgba(255, 219, 189, 0.22), rgba(255, 219, 189, 0));
|
||||||
|
animation: welcome-bg-wave-b 34s ease-in-out infinite alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-theme-ocean {
|
||||||
|
background:
|
||||||
|
radial-gradient(120% 90% at 50% -20%, rgba(255, 255, 255, 0.88), rgba(255, 255, 255, 0)),
|
||||||
|
linear-gradient(135deg, #e0f7fa 0%, #e7f0ff 45%, #eef3ff 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-theme-rainbow {
|
||||||
|
background:
|
||||||
|
radial-gradient(120% 90% at 50% -20%, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0)),
|
||||||
|
linear-gradient(135deg, #e8f8ff 0%, #e9edff 36%, #efe7ff 68%, #ffeef4 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-theme-sunset {
|
||||||
|
background:
|
||||||
|
radial-gradient(120% 90% at 50% -20%, rgba(255, 255, 255, 0.86), rgba(255, 255, 255, 0)),
|
||||||
|
linear-gradient(135deg, #fff0e8 0%, #ffe9dc 45%, #ffe1f0 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-content {
|
||||||
|
width: min(88vw, 700px);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 24px;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-logo {
|
||||||
|
width: 100%;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-svg {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-path {
|
||||||
|
fill: var(--welcome-theme-color);
|
||||||
|
fill-opacity: 0;
|
||||||
|
stroke: var(--welcome-theme-color);
|
||||||
|
stroke-width: 2;
|
||||||
|
stroke-linecap: round;
|
||||||
|
stroke-linejoin: round;
|
||||||
|
stroke-dasharray: 1000;
|
||||||
|
stroke-dashoffset: 1000;
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-fin .welcome-path {
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
fill-opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-fin .welcome-path-0 { transition: stroke-dashoffset 0.62s ease-in-out 0s, fill-opacity 0.45s ease-in 2.75s; }
|
||||||
|
.welcome-fin .welcome-path-1 { transition: stroke-dashoffset 0.62s ease-in-out 0.28s, fill-opacity 0.45s ease-in 2.75s; }
|
||||||
|
.welcome-fin .welcome-path-2 { transition: stroke-dashoffset 0.62s ease-in-out 0.56s, fill-opacity 0.45s ease-in 2.75s; }
|
||||||
|
.welcome-fin .welcome-path-3 { transition: stroke-dashoffset 0.62s ease-in-out 0.84s, fill-opacity 0.45s ease-in 2.75s; }
|
||||||
|
.welcome-fin .welcome-path-4 { transition: stroke-dashoffset 0.62s ease-in-out 1.12s, fill-opacity 0.45s ease-in 2.75s; }
|
||||||
|
.welcome-fin .welcome-path-5 { transition: stroke-dashoffset 0.62s ease-in-out 1.4s, fill-opacity 0.45s ease-in 2.75s; }
|
||||||
|
.welcome-fin .welcome-path-6 { transition: stroke-dashoffset 0.62s ease-in-out 1.68s, fill-opacity 0.45s ease-in 2.75s; }
|
||||||
|
.welcome-fin .welcome-path-7 { transition: stroke-dashoffset 0.62s ease-in-out 1.96s, fill-opacity 0.45s ease-in 2.75s; }
|
||||||
|
.welcome-fin .welcome-path-8 { transition: stroke-dashoffset 0.62s ease-in-out 2.24s, fill-opacity 0.45s ease-in 2.75s; }
|
||||||
|
|
||||||
|
.welcome-fade {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.85s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-reset {
|
||||||
|
opacity: 0;
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-tip {
|
||||||
|
margin: 44px 0 0;
|
||||||
|
font-size: 11px;
|
||||||
|
letter-spacing: 0.2em;
|
||||||
|
color: rgba(34, 34, 34, 0.32);
|
||||||
|
text-transform: uppercase;
|
||||||
|
animation: welcome-tip-breathe 5s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes welcome-tip-breathe {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
40% {
|
||||||
|
opacity: 0.55;
|
||||||
|
}
|
||||||
|
80% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes welcome-bg-base-flow {
|
||||||
|
0% {
|
||||||
|
background-position: 0% 0%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-position: 100% 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes welcome-bg-wave-a {
|
||||||
|
0% {
|
||||||
|
transform: translate3d(-2.5%, 1.8%, 0) scale(1.02);
|
||||||
|
opacity: 0.72;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translate3d(2%, -1.6%, 0) scale(1.06);
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translate3d(4%, -2.4%, 0) scale(1.08);
|
||||||
|
opacity: 0.72;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes welcome-bg-wave-b {
|
||||||
|
0% {
|
||||||
|
transform: translate3d(2.2%, -1.4%, 0) scale(1.01);
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translate3d(-2.6%, 1.6%, 0) scale(1.05);
|
||||||
|
opacity: 0.86;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translate3d(-4.4%, 2.4%, 0) scale(1.07);
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,231 @@
|
|||||||
|
<!--
|
||||||
|
AgentArchitectureDemo.vue
|
||||||
|
Agent 架构“点哪看哪”:点击模块,右侧展示它负责什么 + 典型输入输出。
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div class="arch">
|
||||||
|
<div class="header">
|
||||||
|
<div>
|
||||||
|
<div class="title">
|
||||||
|
Agent 由哪些模块拼起来?
|
||||||
|
</div>
|
||||||
|
<div class="subtitle">
|
||||||
|
点一下模块,看它“负责什么”。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<div class="diagram">
|
||||||
|
<button
|
||||||
|
v-for="m in modules"
|
||||||
|
:key="m.id"
|
||||||
|
:class="['node', { active: current.id === m.id }]"
|
||||||
|
@click="current = m"
|
||||||
|
>
|
||||||
|
<span class="icon">{{ m.icon }}</span>
|
||||||
|
<span class="name">{{ m.name }}</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="pipes">
|
||||||
|
<div class="pipe">
|
||||||
|
用户目标 → 计划 → 工具调用 → 结果 → 再计划…
|
||||||
|
</div>
|
||||||
|
<div class="pipe small">
|
||||||
|
(记忆会贯穿整个过程)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-title">
|
||||||
|
{{ current.icon }} {{ current.name }}
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
{{ current.desc }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="io">
|
||||||
|
<div class="io-title">
|
||||||
|
典型输入
|
||||||
|
</div>
|
||||||
|
<pre><code>{{ current.input }}</code></pre>
|
||||||
|
</div>
|
||||||
|
<div class="io">
|
||||||
|
<div class="io-title">
|
||||||
|
典型输出
|
||||||
|
</div>
|
||||||
|
<pre><code>{{ current.output }}</code></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
const modules = [
|
||||||
|
{
|
||||||
|
id: 'llm',
|
||||||
|
icon: '🧠',
|
||||||
|
name: 'LLM(大脑)',
|
||||||
|
desc: '负责理解目标、生成计划、选择动作、组织语言输出。',
|
||||||
|
input: '用户目标 + 当前状态 + 可用工具列表',
|
||||||
|
output: '下一步计划 / 工具调用参数 / 最终回答'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tools',
|
||||||
|
icon: '🔧',
|
||||||
|
name: 'Tools(手脚)',
|
||||||
|
desc: '负责真正“做事”:搜索、读写文件、调用 API、运行命令。',
|
||||||
|
input: 'tool_name + input_schema 参数',
|
||||||
|
output: '工具执行结果(文本/数据/文件变更)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'memory',
|
||||||
|
icon: '💾',
|
||||||
|
name: 'Memory(记忆)',
|
||||||
|
desc: '把“已经做过什么、得到什么结果”存起来,避免重复与跑偏。',
|
||||||
|
input: '对话历史 / 工具结果 / 当前任务状态',
|
||||||
|
output: '可检索的上下文(短期/长期/工作记忆)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'planner',
|
||||||
|
icon: '🧩',
|
||||||
|
name: 'Planning(规划)',
|
||||||
|
desc: '把大目标拆成小步骤,并在失败时改计划(计划不是一次性的)。',
|
||||||
|
input: '目标 + 约束(预算/时间/安全) + 当前进度',
|
||||||
|
output: '步骤清单 / 下一步动作 / 停止条件'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'guard',
|
||||||
|
icon: '🛡️',
|
||||||
|
name: 'Guardrails(护栏)',
|
||||||
|
desc: '限制风险:权限白名单、预算上限、敏感操作确认、沙箱执行。',
|
||||||
|
input: '请求执行的动作 + 安全策略',
|
||||||
|
output: '允许/拒绝/要求确认 + 审计日志'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const current = ref(modules[0])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.arch {
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
padding: 16px;
|
||||||
|
margin: 20px 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
.subtitle {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diagram {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node.active {
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
border-radius: 6px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
}
|
||||||
|
.name {
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pipes {
|
||||||
|
margin-top: 6px;
|
||||||
|
padding-top: 10px;
|
||||||
|
border-top: 1px dashed var(--vp-c-divider);
|
||||||
|
}
|
||||||
|
.pipe {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
.pipe.small {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--vp-c-text-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
.panel-title {
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
.panel-body {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
.io-title {
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
margin: 0;
|
||||||
|
background: #0b1221;
|
||||||
|
color: #e5e7eb;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 12px;
|
||||||
|
font-family: var(--vp-font-family-mono);
|
||||||
|
font-size: 13px;
|
||||||
|
overflow-x: auto;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,216 @@
|
|||||||
|
<!--
|
||||||
|
AgentChallengesDemo.vue
|
||||||
|
挑战不是“列清单”,而是“能感受到风险”:
|
||||||
|
- 开关护栏(步数上限/预算/确认/沙箱)
|
||||||
|
- 看风险分数怎么变化
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div class="risk">
|
||||||
|
<div class="header">
|
||||||
|
<div>
|
||||||
|
<div class="title">
|
||||||
|
Agent 的挑战:没护栏就容易“翻车”
|
||||||
|
</div>
|
||||||
|
<div class="subtitle">
|
||||||
|
打开这些护栏,风险会明显下降。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="score"
|
||||||
|
:class="scoreClass"
|
||||||
|
>
|
||||||
|
风险分数:{{ score }}/100
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="controls">
|
||||||
|
<label class="toggle"><input
|
||||||
|
v-model="maxSteps"
|
||||||
|
type="checkbox"
|
||||||
|
>
|
||||||
|
最大迭代次数(防死循环)</label>
|
||||||
|
<label class="toggle"><input
|
||||||
|
v-model="budget"
|
||||||
|
type="checkbox"
|
||||||
|
> 预算上限(防烧钱)</label>
|
||||||
|
<label class="toggle"><input
|
||||||
|
v-model="confirm"
|
||||||
|
type="checkbox"
|
||||||
|
> 危险操作二次确认</label>
|
||||||
|
<label class="toggle"><input
|
||||||
|
v-model="sandbox"
|
||||||
|
type="checkbox"
|
||||||
|
> 沙箱执行(隔离系统)</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<div class="card">
|
||||||
|
<div class="k">
|
||||||
|
常见风险
|
||||||
|
</div>
|
||||||
|
<ul>
|
||||||
|
<li>重复尝试 → 死循环</li>
|
||||||
|
<li>乱用工具 → 误删/误发</li>
|
||||||
|
<li>外部内容注入 → 被带偏</li>
|
||||||
|
<li>调用太多 → 成本失控</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="k">
|
||||||
|
你现在开启了什么?
|
||||||
|
</div>
|
||||||
|
<div class="v">
|
||||||
|
{{ enabledList }}
|
||||||
|
</div>
|
||||||
|
<div class="note">
|
||||||
|
建议:最少也要有“最大步数 + 确认”。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="k">
|
||||||
|
一句话建议
|
||||||
|
</div>
|
||||||
|
<div class="v">
|
||||||
|
{{ advice }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
|
||||||
|
const maxSteps = ref(true)
|
||||||
|
const budget = ref(false)
|
||||||
|
const confirm = ref(true)
|
||||||
|
const sandbox = ref(false)
|
||||||
|
|
||||||
|
const score = computed(() => {
|
||||||
|
let s = 85
|
||||||
|
if (maxSteps.value) s -= 18
|
||||||
|
if (budget.value) s -= 15
|
||||||
|
if (confirm.value) s -= 22
|
||||||
|
if (sandbox.value) s -= 18
|
||||||
|
return Math.max(0, s)
|
||||||
|
})
|
||||||
|
|
||||||
|
const scoreClass = computed(() => {
|
||||||
|
if (score.value <= 35) return 'good'
|
||||||
|
if (score.value <= 60) return 'mid'
|
||||||
|
return 'bad'
|
||||||
|
})
|
||||||
|
|
||||||
|
const enabledList = computed(() => {
|
||||||
|
const items = []
|
||||||
|
if (maxSteps.value) items.push('最大步数')
|
||||||
|
if (budget.value) items.push('预算上限')
|
||||||
|
if (confirm.value) items.push('二次确认')
|
||||||
|
if (sandbox.value) items.push('沙箱')
|
||||||
|
return items.length ? items.join('、') : '(都没开)'
|
||||||
|
})
|
||||||
|
|
||||||
|
const advice = computed(() => {
|
||||||
|
if (!maxSteps.value && !confirm.value)
|
||||||
|
return '先加“最大步数”和“二次确认”,这是最低成本的安全感。'
|
||||||
|
if (score.value <= 35)
|
||||||
|
return '很稳了:可以开始做更复杂的任务,但记得加日志与监控。'
|
||||||
|
if (score.value <= 60) return '还不错:建议再加预算或沙箱,避免极端情况。'
|
||||||
|
return '风险偏高:建议优先补护栏,再让 Agent 真去执行。'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.risk {
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
padding: 16px;
|
||||||
|
margin: 20px 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
.subtitle {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.score {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 999px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
||||||
|
.score.good {
|
||||||
|
color: #22c55e;
|
||||||
|
border-color: rgba(34, 197, 94, 0.4);
|
||||||
|
}
|
||||||
|
.score.mid {
|
||||||
|
color: #f59e0b;
|
||||||
|
border-color: rgba(245, 158, 11, 0.4);
|
||||||
|
}
|
||||||
|
.score.bad {
|
||||||
|
color: #ef4444;
|
||||||
|
border-color: rgba(239, 68, 68, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.toggle {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
accent-color: var(--vp-c-brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.card {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
.k {
|
||||||
|
font-weight: 900;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
.v {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
.note {
|
||||||
|
margin-top: 6px;
|
||||||
|
color: var(--vp-c-text-3);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 18px;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
<!--
|
||||||
|
AgentFutureDemo.vue
|
||||||
|
Agent 未来方向:点选趋势,看看“会带来什么变化”和“现在就能做的准备”。
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div class="future">
|
||||||
|
<div class="header">
|
||||||
|
<div>
|
||||||
|
<div class="title">
|
||||||
|
Agent 的未来:更稳、更强、更协作
|
||||||
|
</div>
|
||||||
|
<div class="subtitle">
|
||||||
|
点一个趋势,看它意味着什么。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="chips">
|
||||||
|
<button
|
||||||
|
v-for="t in trends"
|
||||||
|
:key="t.id"
|
||||||
|
:class="['chip', { active: current.id === t.id }]"
|
||||||
|
@click="current = t"
|
||||||
|
>
|
||||||
|
{{ t.label }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel">
|
||||||
|
<div class="p-title">
|
||||||
|
{{ current.label }}
|
||||||
|
</div>
|
||||||
|
<div class="p-body">
|
||||||
|
{{ current.desc }}
|
||||||
|
</div>
|
||||||
|
<div class="grid">
|
||||||
|
<div class="card">
|
||||||
|
<div class="k">
|
||||||
|
会带来什么?
|
||||||
|
</div>
|
||||||
|
<div class="v">
|
||||||
|
{{ current.impact }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="k">
|
||||||
|
你现在能做什么准备?
|
||||||
|
</div>
|
||||||
|
<div class="v">
|
||||||
|
{{ current.prepare }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
const trends = [
|
||||||
|
{
|
||||||
|
id: 'planning',
|
||||||
|
label: '更强规划',
|
||||||
|
desc: '把大目标拆成更合理的子任务,并能动态改计划。',
|
||||||
|
impact: '更少跑题、更少漏步骤,复杂任务成功率更高。',
|
||||||
|
prepare: '学会写“计划/检查点”,并把任务拆成可验收小块。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'memory',
|
||||||
|
label: '更好记忆',
|
||||||
|
desc: '长期记住偏好、事实与项目状态,跨任务复用。',
|
||||||
|
impact: '更像长期同事:越用越懂你,重复工作更少。',
|
||||||
|
prepare: '设计记忆结构:短期/长期/工作记忆,并做好隐私与脱敏。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'multi',
|
||||||
|
label: '多 Agent 协作',
|
||||||
|
desc: '多个角色并行处理,再由协调者合并输出。',
|
||||||
|
impact: '大任务并行化,质量更稳(研究/实现/评审分工)。',
|
||||||
|
prepare: '先把“角色边界”和“交付格式”定义清楚。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'safety',
|
||||||
|
label: '更强安全护栏',
|
||||||
|
desc: '更细的权限、确认与审计,降低工具滥用风险。',
|
||||||
|
impact: '更容易上线到真实业务场景,减少事故。',
|
||||||
|
prepare: '默认开启:最大步数、预算上限、危险操作确认、沙箱。'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const current = ref(trends[0])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.future {
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
padding: 16px;
|
||||||
|
margin: 20px 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
.subtitle {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chips {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.chip {
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.chip.active {
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
color: var(--vp-c-brand);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
.p-title {
|
||||||
|
font-weight: 900;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
.p-body {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
line-height: 1.6;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
.card {
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border: 1px dashed var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
.k {
|
||||||
|
font-weight: 900;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
.v {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,198 @@
|
|||||||
|
<!--
|
||||||
|
AgentLevelDemo.vue
|
||||||
|
Agent 分级(L0-L5)交互:拖动等级,看到“能做什么/不能做什么/典型任务”。
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div class="levels">
|
||||||
|
<div class="header">
|
||||||
|
<div>
|
||||||
|
<div class="title">
|
||||||
|
Agent 能力分级(从聊天到协作)
|
||||||
|
</div>
|
||||||
|
<div class="subtitle">
|
||||||
|
拖动看看:等级越高,越像“能独立干活的同事”。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="badge">
|
||||||
|
当前:{{ current.name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="slider">
|
||||||
|
<input
|
||||||
|
v-model.number="level"
|
||||||
|
type="range"
|
||||||
|
min="0"
|
||||||
|
max="5"
|
||||||
|
step="1"
|
||||||
|
>
|
||||||
|
<div class="ticks">
|
||||||
|
<span
|
||||||
|
v-for="n in 6"
|
||||||
|
:key="n"
|
||||||
|
>{{ n - 1 }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<div class="card">
|
||||||
|
<div class="k">
|
||||||
|
能做什么
|
||||||
|
</div>
|
||||||
|
<ul>
|
||||||
|
<li
|
||||||
|
v-for="x in current.can"
|
||||||
|
:key="x"
|
||||||
|
>
|
||||||
|
{{ x }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="k">
|
||||||
|
容易出的问题
|
||||||
|
</div>
|
||||||
|
<ul>
|
||||||
|
<li
|
||||||
|
v-for="x in current.risk"
|
||||||
|
:key="x"
|
||||||
|
>
|
||||||
|
{{ x }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<div class="k">
|
||||||
|
典型任务
|
||||||
|
</div>
|
||||||
|
<div class="v">
|
||||||
|
{{ current.example }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
|
||||||
|
const level = ref(2)
|
||||||
|
|
||||||
|
const levels = [
|
||||||
|
{
|
||||||
|
name: 'L0:纯对话',
|
||||||
|
can: ['回答问题', '写文本/代码(但不执行)'],
|
||||||
|
risk: ['只能“说”,不能“做”', '需要你手动分步骤'],
|
||||||
|
example: '解释概念、写一段文案'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'L1:单工具',
|
||||||
|
can: ['调用一个固定工具', '把结果解释给你'],
|
||||||
|
risk: ['工具用错参数', '缺少复杂规划'],
|
||||||
|
example: '只会查一次搜索/只会跑一次代码'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'L2:多工具',
|
||||||
|
can: ['在多个工具间选择', '按需要组合调用'],
|
||||||
|
risk: ['选择工具不稳', '权限与安全需要控制'],
|
||||||
|
example: '搜索 + 打开网页 + 摘要'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'L3:多步骤执行',
|
||||||
|
can: ['先计划后执行', '完成一串步骤', '记录中间结果'],
|
||||||
|
risk: ['步骤漏/顺序错', '成本上升(更多调用)'],
|
||||||
|
example: '读代码 → 改代码 → 跑测试 → 出报告'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'L4:自我纠错',
|
||||||
|
can: ['失败后换策略', '用检查点避免跑偏'],
|
||||||
|
risk: ['可能反复尝试(需要上限)', '更依赖监控与日志'],
|
||||||
|
example: '测试失败后自动定位并尝试修复'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'L5:多 Agent 协作',
|
||||||
|
can: ['多个角色分工', '并行处理任务', '合并结果'],
|
||||||
|
risk: ['协作成本更高', '需要清晰协议与仲裁机制'],
|
||||||
|
example: '研究员找资料 + 工程师实现 + 编辑写总结'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const current = computed(() => levels[level.value])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.levels {
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
padding: 16px;
|
||||||
|
margin: 20px 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
.subtitle {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.badge {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 999px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
}
|
||||||
|
input[type='range'] {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.ticks {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
font-size: 12px;
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.card {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
.k {
|
||||||
|
font-weight: 800;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
.v {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
margin: 0;
|
||||||
|
padding-left: 18px;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,495 @@
|
|||||||
|
<template>
|
||||||
|
<div class="memory-demo">
|
||||||
|
<div class="header">
|
||||||
|
<div class="title">
|
||||||
|
💾 Agent 的记忆系统
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 快捷操作 -->
|
||||||
|
<div class="quick-actions">
|
||||||
|
<button
|
||||||
|
v-for="action in quickActions"
|
||||||
|
:key="action"
|
||||||
|
class="action-btn"
|
||||||
|
:disabled="isTyping"
|
||||||
|
@click="sendMessage(action)"
|
||||||
|
>
|
||||||
|
{{ action }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="action-btn reset"
|
||||||
|
@click="resetConversation"
|
||||||
|
>
|
||||||
|
🔄 重置
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 主区域 -->
|
||||||
|
<div class="main-area">
|
||||||
|
<!-- 对话区 -->
|
||||||
|
<div class="chat-box">
|
||||||
|
<div class="box-header">
|
||||||
|
💬 对话
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
ref="chatContainer"
|
||||||
|
class="messages"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(msg, i) in messages.slice(-4)"
|
||||||
|
:key="i"
|
||||||
|
class="msg-row"
|
||||||
|
:class="msg.role"
|
||||||
|
>
|
||||||
|
<span class="avatar">{{ msg.role === 'user' ? '👤' : '🤖' }}</span>
|
||||||
|
<span class="text">{{ msg.content }}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="isTyping"
|
||||||
|
class="msg-row assistant typing"
|
||||||
|
>
|
||||||
|
<span class="avatar">🤖</span>
|
||||||
|
<span class="dots"><span /><span /><span /></span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="messages.length === 0"
|
||||||
|
class="empty-msg"
|
||||||
|
>
|
||||||
|
点击上方按钮开始对话
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 三种记忆并排 -->
|
||||||
|
<div class="memory-row">
|
||||||
|
<div class="memory-card">
|
||||||
|
<div class="card-header">
|
||||||
|
<span>⏱️ 短期记忆</span>
|
||||||
|
<span class="count">{{ shortTermMemory.length }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div
|
||||||
|
v-for="(item, i) in shortTermMemory.slice(-3)"
|
||||||
|
:key="i"
|
||||||
|
class="mem-item"
|
||||||
|
>
|
||||||
|
<span class="role">{{ item.role === 'user' ? 'U' : 'A' }}</span>
|
||||||
|
<span class="content">{{ truncate(item.content, 20) }}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="shortTermMemory.length === 0"
|
||||||
|
class="empty"
|
||||||
|
>
|
||||||
|
空
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="memory-card">
|
||||||
|
<div class="card-header">
|
||||||
|
<span>📝 工作记忆</span>
|
||||||
|
<span class="count">{{ Object.keys(workingMemory).length }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div
|
||||||
|
v-for="(v, k) in workingMemory"
|
||||||
|
:key="k"
|
||||||
|
class="mem-item kv"
|
||||||
|
>
|
||||||
|
<span class="key">{{ k }}</span>
|
||||||
|
<span class="value">{{ v }}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="Object.keys(workingMemory).length === 0"
|
||||||
|
class="empty"
|
||||||
|
>
|
||||||
|
空
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="memory-card">
|
||||||
|
<div class="card-header">
|
||||||
|
<span>🗄️ 长期记忆</span>
|
||||||
|
<span class="count">{{ longTermMemory.length }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div
|
||||||
|
v-for="(item, i) in longTermMemory.slice(-2)"
|
||||||
|
:key="i"
|
||||||
|
class="mem-item"
|
||||||
|
>
|
||||||
|
<span class="tag">{{ item.category }}</span>
|
||||||
|
<span class="content">{{ item.content }}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="longTermMemory.length === 0"
|
||||||
|
class="empty"
|
||||||
|
>
|
||||||
|
空
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 记忆操作提示 -->
|
||||||
|
<div
|
||||||
|
v-if="lastOp"
|
||||||
|
class="op-bar"
|
||||||
|
>
|
||||||
|
<span>{{ lastOp.icon }}</span>
|
||||||
|
<span>{{ lastOp.text }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 提示 -->
|
||||||
|
<div class="tip-bar">
|
||||||
|
<span>💡</span>
|
||||||
|
<span><strong>短期</strong>=当前对话,<strong>工作</strong>=临时变量,<strong>长期</strong>=跨会话知识</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, nextTick } from 'vue'
|
||||||
|
|
||||||
|
const messages = ref([])
|
||||||
|
const shortTermMemory = ref([])
|
||||||
|
const workingMemory = ref({})
|
||||||
|
const longTermMemory = ref([])
|
||||||
|
const isTyping = ref(false)
|
||||||
|
const lastOp = ref(null)
|
||||||
|
|
||||||
|
const quickActions = [
|
||||||
|
'我叫张三',
|
||||||
|
'我喜欢 Python',
|
||||||
|
'推荐编程书',
|
||||||
|
'我叫什么?'
|
||||||
|
]
|
||||||
|
|
||||||
|
const responses = {
|
||||||
|
'我叫张三': {
|
||||||
|
reply: '好的,我记住了你叫张三。',
|
||||||
|
op: { icon: '💾', text: '长期记忆: 姓名=张三' },
|
||||||
|
update: () => longTermMemory.value.push({ category: '身份', content: '姓名: 张三' })
|
||||||
|
},
|
||||||
|
'我喜欢 Python': {
|
||||||
|
reply: '收到!记录了你偏好 Python。',
|
||||||
|
op: { icon: '💾', text: '工作记忆: 偏好=Python | 长期记忆: 技术偏好' },
|
||||||
|
update: () => {
|
||||||
|
workingMemory.value['偏好'] = 'Python'
|
||||||
|
longTermMemory.value.push({ category: '偏好', content: '编程语言: Python' })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'推荐编程书': {
|
||||||
|
reply: '基于你偏好 Python,推荐《流畅的Python》。',
|
||||||
|
op: { icon: '🔍', text: '检索工作记忆: 偏好=Python → 生成推荐' }
|
||||||
|
},
|
||||||
|
'我叫什么?': {
|
||||||
|
reply: '你叫张三。',
|
||||||
|
op: { icon: '🔍', text: '检索长期记忆: 姓名=张三' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const sendMessage = async (text) => {
|
||||||
|
messages.value.push({ role: 'user', content: text })
|
||||||
|
shortTermMemory.value.push({ role: 'user', content: text })
|
||||||
|
isTyping.value = true
|
||||||
|
scrollToBottom()
|
||||||
|
|
||||||
|
await wait(600)
|
||||||
|
|
||||||
|
const config = responses[text] || { reply: '收到', op: null, update: () => {} }
|
||||||
|
config.update()
|
||||||
|
lastOp.value = config.op
|
||||||
|
|
||||||
|
messages.value.push({ role: 'assistant', content: config.reply })
|
||||||
|
shortTermMemory.value.push({ role: 'assistant', content: config.reply })
|
||||||
|
isTyping.value = false
|
||||||
|
scrollToBottom()
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetConversation = () => {
|
||||||
|
messages.value = []
|
||||||
|
shortTermMemory.value = []
|
||||||
|
workingMemory.value = {}
|
||||||
|
longTermMemory.value = []
|
||||||
|
lastOp.value = null
|
||||||
|
isTyping.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const scrollToBottom = async () => {
|
||||||
|
await nextTick()
|
||||||
|
const container = document.querySelector('.messages')
|
||||||
|
if (container) container.scrollTop = container.scrollHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
const truncate = (text, len) => text.length > len ? text.slice(0, len) + '...' : text
|
||||||
|
const wait = (ms) => new Promise(r => setTimeout(r, ms))
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.memory-demo {
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 700;
|
||||||
|
background: linear-gradient(120deg, var(--vp-c-brand), #9c27b0);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 快捷操作 */
|
||||||
|
.quick-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
padding: 8px 14px;
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 16px;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 13px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn:hover:not(:disabled) {
|
||||||
|
background: var(--vp-c-brand-soft);
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn.reset {
|
||||||
|
background: #fee2e2;
|
||||||
|
border-color: #fecaca;
|
||||||
|
color: #991b1b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||||
|
|
||||||
|
/* 主区域 */
|
||||||
|
.main-area {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 2fr;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.main-area { grid-template-columns: 1fr; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 对话区 */
|
||||||
|
.chat-box {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box-header {
|
||||||
|
padding: 10px 12px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border-bottom: 1px solid var(--vp-c-divider);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.messages {
|
||||||
|
padding: 12px;
|
||||||
|
min-height: 120px;
|
||||||
|
max-height: 160px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.msg-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.msg-row.user { flex-direction: row-reverse; }
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
font-size: 14px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
.msg-row.user .text {
|
||||||
|
background: var(--vp-c-brand);
|
||||||
|
color: white;
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dots {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dots span {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
background: var(--vp-c-text-3);
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: bounce 1.4s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dots span:nth-child(1) { animation-delay: 0s; }
|
||||||
|
.dots span:nth-child(2) { animation-delay: 0.2s; }
|
||||||
|
.dots span:nth-child(3) { animation-delay: 0.4s; }
|
||||||
|
|
||||||
|
@keyframes bounce {
|
||||||
|
0%, 80%, 100% { transform: scale(0); }
|
||||||
|
40% { transform: scale(1); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-msg {
|
||||||
|
text-align: center;
|
||||||
|
color: var(--vp-c-text-3);
|
||||||
|
padding: 40px 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 记忆行 */
|
||||||
|
.memory-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.memory-row { grid-template-columns: 1fr; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.memory-card {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 12px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border-bottom: 1px solid var(--vp-c-divider);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.count {
|
||||||
|
padding: 2px 8px;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border-radius: 10px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
padding: 10px;
|
||||||
|
min-height: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mem-item {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 6px 8px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-size: 11px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mem-item .role {
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--vp-c-brand);
|
||||||
|
min-width: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mem-item .content {
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mem-item.kv .key {
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--vp-c-brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mem-item.kv .value {
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mem-item .tag {
|
||||||
|
padding: 1px 6px;
|
||||||
|
background: var(--vp-c-brand-soft);
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
color: var(--vp-c-brand-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty {
|
||||||
|
text-align: center;
|
||||||
|
color: var(--vp-c-text-3);
|
||||||
|
padding: 20px 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 操作提示 */
|
||||||
|
.op-bar {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 10px 14px;
|
||||||
|
background: #dcfce7;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #166534;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 提示 */
|
||||||
|
.tip-bar {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 10px 14px;
|
||||||
|
background: var(--vp-c-brand-soft);
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,975 @@
|
|||||||
|
<template>
|
||||||
|
<div class="multi-tool-principle">
|
||||||
|
<div class="header">
|
||||||
|
<div class="title">
|
||||||
|
🔧 多工具调用原理:Agent 如何"串联"工具完成任务
|
||||||
|
</div>
|
||||||
|
<div class="subtitle">
|
||||||
|
理解 Agent 的链式思考(Chain-of-Thought)和工具编排机制
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 场景选择 -->
|
||||||
|
<div class="scenario-tabs">
|
||||||
|
<button
|
||||||
|
v-for="s in scenarios"
|
||||||
|
:key="s.id"
|
||||||
|
:class="['tab-btn', { active: currentScenario === s.id }]"
|
||||||
|
@click="selectScenario(s.id)"
|
||||||
|
>
|
||||||
|
<span>{{ s.icon }}</span>
|
||||||
|
<span>{{ s.name }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 用户意图 -->
|
||||||
|
<div class="intent-box">
|
||||||
|
<div class="intent-label">
|
||||||
|
👤 用户意图
|
||||||
|
</div>
|
||||||
|
<div class="intent-text">
|
||||||
|
{{ currentData.intent }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 执行流程可视化 -->
|
||||||
|
<div class="execution-flow">
|
||||||
|
<div class="flow-title">
|
||||||
|
🔄 工具调用执行流程
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 思考阶段 -->
|
||||||
|
<div
|
||||||
|
class="phase thinking-phase"
|
||||||
|
:class="{ active: currentPhase >= 0 }"
|
||||||
|
>
|
||||||
|
<div class="phase-header">
|
||||||
|
<span class="phase-icon">🧠</span>
|
||||||
|
<span class="phase-name">思考规划</span>
|
||||||
|
<span class="phase-status">{{ currentPhase > 0 ? '✅ 完成' : currentPhase === 0 ? '🔄 进行中' : '⏳ 等待' }}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="currentPhase >= 0"
|
||||||
|
class="phase-content"
|
||||||
|
>
|
||||||
|
<div class="thought-steps">
|
||||||
|
<div
|
||||||
|
v-for="(step, idx) in currentData.planningSteps"
|
||||||
|
:key="idx"
|
||||||
|
class="thought-step"
|
||||||
|
>
|
||||||
|
<span class="step-num">{{ idx + 1 }}</span>
|
||||||
|
<span class="step-text">{{ step }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 工具执行阶段 -->
|
||||||
|
<div
|
||||||
|
class="phase tools-phase"
|
||||||
|
:class="{ active: currentPhase >= 1 }"
|
||||||
|
>
|
||||||
|
<div class="phase-header">
|
||||||
|
<span class="phase-icon">🔧</span>
|
||||||
|
<span class="phase-name">工具执行</span>
|
||||||
|
<span class="phase-status">{{ currentPhase > 1 ? '✅ 完成' : currentPhase === 1 ? '🔄 进行中' : '⏳ 等待' }}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="currentPhase >= 1"
|
||||||
|
class="phase-content"
|
||||||
|
>
|
||||||
|
<div class="tools-chain">
|
||||||
|
<div
|
||||||
|
v-for="(tool, idx) in currentData.tools"
|
||||||
|
:key="idx"
|
||||||
|
class="tool-node"
|
||||||
|
:class="{
|
||||||
|
completed: currentTool > idx,
|
||||||
|
executing: currentTool === idx,
|
||||||
|
pending: currentTool < idx
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="idx > 0"
|
||||||
|
class="node-connector"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="connector-line"
|
||||||
|
:class="{ active: currentTool >= idx }"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="node-content">
|
||||||
|
<div class="node-icon">
|
||||||
|
{{ tool.icon }}
|
||||||
|
</div>
|
||||||
|
<div class="node-name">
|
||||||
|
{{ tool.name }}
|
||||||
|
</div>
|
||||||
|
<div class="node-status">
|
||||||
|
<span
|
||||||
|
v-if="currentTool > idx"
|
||||||
|
class="status-done"
|
||||||
|
>✓</span>
|
||||||
|
<span
|
||||||
|
v-else-if="currentTool === idx"
|
||||||
|
class="status-running"
|
||||||
|
>
|
||||||
|
<span class="pulse" />
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
v-else
|
||||||
|
class="status-wait"
|
||||||
|
>○</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 工具详情 -->
|
||||||
|
<div
|
||||||
|
v-if="currentTool >= idx"
|
||||||
|
class="tool-detail-popup"
|
||||||
|
>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="detail-label">输入:</span>
|
||||||
|
<code class="detail-code">{{ tool.input }}</code>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="currentTool > idx"
|
||||||
|
class="detail-row"
|
||||||
|
>
|
||||||
|
<span class="detail-label">输出:</span>
|
||||||
|
<span class="detail-output">{{ truncate(tool.output, 50) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 数据流转示意 -->
|
||||||
|
<div
|
||||||
|
v-if="currentPhase === 1"
|
||||||
|
class="data-flow-hint"
|
||||||
|
>
|
||||||
|
<div class="flow-arrow">
|
||||||
|
⬇️ 数据在工具间流转,上一步的输出成为下一步的输入
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 结果整合阶段 -->
|
||||||
|
<div
|
||||||
|
class="phase result-phase"
|
||||||
|
:class="{ active: currentPhase >= 2 }"
|
||||||
|
>
|
||||||
|
<div class="phase-header">
|
||||||
|
<span class="phase-icon">📝</span>
|
||||||
|
<span class="phase-name">结果整合</span>
|
||||||
|
<span class="phase-status">{{ currentPhase > 2 ? '✅ 完成' : currentPhase === 2 ? '🔄 进行中' : '⏳ 等待' }}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="currentPhase >= 2"
|
||||||
|
class="phase-content"
|
||||||
|
>
|
||||||
|
<div class="integration-steps">
|
||||||
|
<div
|
||||||
|
class="integration-step"
|
||||||
|
:class="{ done: integrationStep >= 0 }"
|
||||||
|
>
|
||||||
|
<span class="check">{{ integrationStep >= 0 ? '✓' : '○' }}</span>
|
||||||
|
<span>收集所有工具输出</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="integration-step"
|
||||||
|
:class="{ done: integrationStep >= 1 }"
|
||||||
|
>
|
||||||
|
<span class="check">{{ integrationStep >= 1 ? '✓' : '○' }}</span>
|
||||||
|
<span>去重与验证</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="integration-step"
|
||||||
|
:class="{ done: integrationStep >= 2 }"
|
||||||
|
>
|
||||||
|
<span class="check">{{ integrationStep >= 2 ? '✓' : '○' }}</span>
|
||||||
|
<span>结构化整理</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="integration-step"
|
||||||
|
:class="{ done: integrationStep >= 3 }"
|
||||||
|
>
|
||||||
|
<span class="check">{{ integrationStep >= 3 ? '✓' : '○' }}</span>
|
||||||
|
<span>生成自然语言回复</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 最终输出 -->
|
||||||
|
<div
|
||||||
|
class="phase output-phase"
|
||||||
|
:class="{ active: currentPhase >= 3 }"
|
||||||
|
>
|
||||||
|
<div class="phase-header">
|
||||||
|
<span class="phase-icon">💬</span>
|
||||||
|
<span class="phase-name">最终输出</span>
|
||||||
|
<span class="phase-status">{{ currentPhase >= 3 ? '✅ 完成' : '⏳ 等待' }}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="currentPhase >= 3"
|
||||||
|
class="phase-content"
|
||||||
|
>
|
||||||
|
<div class="final-output">
|
||||||
|
<div class="output-bubble">
|
||||||
|
{{ currentData.finalOutput }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 控制按钮 -->
|
||||||
|
<div class="controls">
|
||||||
|
<button
|
||||||
|
v-if="!isRunning && currentPhase === -1"
|
||||||
|
class="control-btn primary"
|
||||||
|
@click="startDemo"
|
||||||
|
>
|
||||||
|
▶ 开始演示
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-else-if="isRunning"
|
||||||
|
class="control-btn"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
⏳ 执行中...
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-else
|
||||||
|
class="control-btn secondary"
|
||||||
|
@click="reset"
|
||||||
|
>
|
||||||
|
🔄 重新演示
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 原理说明 -->
|
||||||
|
<div class="principle-explanation">
|
||||||
|
<div class="explanation-title">
|
||||||
|
📚 核心原理
|
||||||
|
</div>
|
||||||
|
<div class="explanation-grid">
|
||||||
|
<div class="explanation-card">
|
||||||
|
<div class="card-icon">
|
||||||
|
🧩
|
||||||
|
</div>
|
||||||
|
<div class="card-title">
|
||||||
|
任务分解
|
||||||
|
</div>
|
||||||
|
<div class="card-desc">
|
||||||
|
Agent 将复杂任务拆解为多个子任务,每个子任务对应一个工具调用
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="explanation-card">
|
||||||
|
<div class="card-icon">
|
||||||
|
🔗
|
||||||
|
</div>
|
||||||
|
<div class="card-title">
|
||||||
|
链式调用
|
||||||
|
</div>
|
||||||
|
<div class="card-desc">
|
||||||
|
工具按依赖关系串联执行,前一个工具的输出成为后一个工具的输入
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="explanation-card">
|
||||||
|
<div class="card-icon">
|
||||||
|
🔄
|
||||||
|
</div>
|
||||||
|
<div class="card-title">
|
||||||
|
动态调整
|
||||||
|
</div>
|
||||||
|
<div class="card-desc">
|
||||||
|
根据中间结果,Agent 可以动态决定下一步调用哪个工具
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="explanation-card">
|
||||||
|
<div class="card-icon">
|
||||||
|
🎯
|
||||||
|
</div>
|
||||||
|
<div class="card-title">
|
||||||
|
结果整合
|
||||||
|
</div>
|
||||||
|
<div class="card-desc">
|
||||||
|
将所有工具输出整合为连贯、有用的最终回复
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 与 LLM 对比 -->
|
||||||
|
<div class="comparison-section">
|
||||||
|
<div class="comparison-title">
|
||||||
|
⚖️ 为什么需要多工具调用?
|
||||||
|
</div>
|
||||||
|
<div class="comparison-table">
|
||||||
|
<div class="comparison-row header">
|
||||||
|
<div class="col scenario">
|
||||||
|
场景
|
||||||
|
</div>
|
||||||
|
<div class="col llm">
|
||||||
|
普通 LLM
|
||||||
|
</div>
|
||||||
|
<div class="col agent">
|
||||||
|
Agent + 多工具
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-for="(item, idx) in comparisons"
|
||||||
|
:key="idx"
|
||||||
|
class="comparison-row"
|
||||||
|
>
|
||||||
|
<div class="col scenario">
|
||||||
|
{{ item.scenario }}
|
||||||
|
</div>
|
||||||
|
<div class="col llm">
|
||||||
|
{{ item.llm }}
|
||||||
|
</div>
|
||||||
|
<div class="col agent">
|
||||||
|
{{ item.agent }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
|
||||||
|
const scenarios = [
|
||||||
|
{
|
||||||
|
id: 'travel',
|
||||||
|
icon: '✈️',
|
||||||
|
name: '旅行规划',
|
||||||
|
intent: '规划一个3天2晚的东京旅行,预算1万元',
|
||||||
|
planningSteps: [
|
||||||
|
'分析需求:东京、3天2晚、预算1万',
|
||||||
|
'确定需要查询:机票、酒店、景点、路线、预算',
|
||||||
|
'规划工具调用顺序:机票→酒店→景点→路线→预算汇总'
|
||||||
|
],
|
||||||
|
tools: [
|
||||||
|
{ icon: '✈️', name: '查机票', input: '{from:上海, to:东京, date:3.15}', output: '往返¥3,200' },
|
||||||
|
{ icon: '🏨', name: '查酒店', input: '{city:东京, nights:2, budget:3000}', output: '新宿酒店¥1,200/晚' },
|
||||||
|
{ icon: '📍', name: '查景点', input: '{city:东京, days:3}', output: '推荐5个景点' },
|
||||||
|
{ icon: '🗺️', name: '规划路线', input: '{spots:[...], days:3}', output: '3天路线规划' },
|
||||||
|
{ icon: '💰', name: '算预算', input: '{items:[...]}', output: '总计¥8,400' }
|
||||||
|
],
|
||||||
|
finalOutput: '✈️ 东京3天2晚行程已规划好!\n• 机票:¥3,200\n• 酒店:¥2,400\n• 餐饮交通:¥2,000\n• 门票购物:¥1,000\n• 总计:¥8,400(剩余¥1,600)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'research',
|
||||||
|
icon: '📊',
|
||||||
|
name: '行业研究',
|
||||||
|
intent: '生成2024年新能源汽车行业分析报告',
|
||||||
|
planningSteps: [
|
||||||
|
'分析需求:行业报告需要市场数据、厂商信息、技术趋势、政策',
|
||||||
|
'确定数据来源:市场数据库、公司信息、技术文献、政策文件',
|
||||||
|
'规划工具调用:市场数据→厂商排名→技术趋势→政策→可视化→报告生成'
|
||||||
|
],
|
||||||
|
tools: [
|
||||||
|
{ icon: '📈', name: '市场数据', input: '{industry:NEV, year:2024}', output: '销量1700万辆,+35%' },
|
||||||
|
{ icon: '🏢', name: '厂商信息', input: '{industry:NEV, top:10}', output: '比亚迪302万,特斯拉181万...' },
|
||||||
|
{ icon: '🔋', name: '技术趋势', input: '{field:NEV, tech:[电池,智驾]}', output: '固态电池、L2+智驾普及' },
|
||||||
|
{ icon: '📋', name: '政策查询', input: '{region:全球, topic:NEV}', output: '中国减免购置税至2027' },
|
||||||
|
{ icon: '📊', name: '数据可视化', input: '{type:饼图, data:市场份额}', output: '生成6个图表' },
|
||||||
|
{ icon: '📝', name: '报告生成', input: '{sections:[...]}', output: '12页完整报告' }
|
||||||
|
],
|
||||||
|
finalOutput: '📊 2024新能源汽车行业分析报告已完成!\n• 全球销量1700万辆(+35%)\n• 比亚迪领先(302万辆)\n• 技术趋势:固态电池、800V快充\n• 完整报告:12页,6个图表'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'shopping',
|
||||||
|
icon: '🛒',
|
||||||
|
name: '智能购物',
|
||||||
|
intent: '买5000元笔记本,编程+轻度游戏',
|
||||||
|
planningSteps: [
|
||||||
|
'分析需求:5000元、编程、轻度游戏',
|
||||||
|
'确定评估维度:机型、规格、价格、评价、性能跑分',
|
||||||
|
'规划工具调用:搜索→查规格→比价格→看评价→跑分对比'
|
||||||
|
],
|
||||||
|
tools: [
|
||||||
|
{ icon: '🔍', name: '搜索机型', input: '{category:笔记本, budget:5000}', output: '找到6款候选机型' },
|
||||||
|
{ icon: '⚙️', name: '查规格', input: '{products:[...]}', output: 'CPU/内存/屏幕参数' },
|
||||||
|
{ icon: '💰', name: '比价格', input: '{products:[...]}', output: '价格对比表' },
|
||||||
|
{ icon: '⭐', name: '看评价', input: '{products:[...], source:电商}', output: '好评率96% vs 94%' },
|
||||||
|
{ icon: '📊', name: '跑分对比', input: '{products:[...], tests:[CPU,GPU]}', output: 'R7>i5,续航8h vs 6.5h' }
|
||||||
|
],
|
||||||
|
finalOutput: '💻 笔记本推荐结果\n🥇 首选:联想小新Pro16(¥4,999)\n• R7-7840HS/16G/1TB/2.5K\n• 性能强、屏幕好、存储大\n\n🥈 备选:ThinkBook14+(¥5,299)\n• 做工好、续航长、接口全'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const comparisons = [
|
||||||
|
{ scenario: '查天气+穿衣建议', llm: '只能推测,无法获取实时数据', agent: '调用天气API获取实时数据,再给出穿衣建议' },
|
||||||
|
{ scenario: '股票分析', llm: '无法获取股价,只能泛泛而谈', agent: '股价+新闻+技术分析,三个工具串联完成深度分析' },
|
||||||
|
{ scenario: '旅行规划', llm: '只能给建议,无法查询实时价格', agent: '机票+酒店+景点+路线+预算,5个工具完成完整规划' },
|
||||||
|
{ scenario: '数据分析', llm: '无法访问数据,只能讲分析方法', agent: '查询+分组+计算+可视化,6个工具完成完整分析' }
|
||||||
|
]
|
||||||
|
|
||||||
|
const currentScenario = ref('travel')
|
||||||
|
const currentPhase = ref(-1)
|
||||||
|
const currentTool = ref(-1)
|
||||||
|
const integrationStep = ref(-1)
|
||||||
|
const isRunning = ref(false)
|
||||||
|
|
||||||
|
const currentData = computed(() => scenarios.find(s => s.id === currentScenario.value))
|
||||||
|
|
||||||
|
const selectScenario = (id) => {
|
||||||
|
currentScenario.value = id
|
||||||
|
reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
const startDemo = async () => {
|
||||||
|
isRunning.value = true
|
||||||
|
currentPhase.value = 0
|
||||||
|
currentTool.value = -1
|
||||||
|
integrationStep.value = -1
|
||||||
|
|
||||||
|
// 思考阶段
|
||||||
|
await wait(1500)
|
||||||
|
|
||||||
|
// 工具执行阶段
|
||||||
|
currentPhase.value = 1
|
||||||
|
const tools = currentData.value.tools
|
||||||
|
|
||||||
|
for (let i = 0; i < tools.length; i++) {
|
||||||
|
currentTool.value = i
|
||||||
|
await wait(1200)
|
||||||
|
}
|
||||||
|
currentTool.value = tools.length
|
||||||
|
|
||||||
|
await wait(500)
|
||||||
|
|
||||||
|
// 结果整合阶段
|
||||||
|
currentPhase.value = 2
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
integrationStep.value = i
|
||||||
|
await wait(600)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 最终输出
|
||||||
|
await wait(300)
|
||||||
|
currentPhase.value = 3
|
||||||
|
|
||||||
|
isRunning.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
currentPhase.value = -1
|
||||||
|
currentTool.value = -1
|
||||||
|
integrationStep.value = -1
|
||||||
|
isRunning.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const wait = (ms) => new Promise(r => setTimeout(r, ms))
|
||||||
|
const truncate = (str, len) => str.length > len ? str.slice(0, len) + '...' : str
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.multi-tool-principle {
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 700;
|
||||||
|
background: linear-gradient(120deg, var(--vp-c-brand), #9c27b0);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 场景标签 */
|
||||||
|
.scenario-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 8px 14px;
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 20px;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-btn:hover {
|
||||||
|
background: var(--vp-c-bg-alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-btn.active {
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
background: var(--vp-c-brand-soft);
|
||||||
|
color: var(--vp-c-brand-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 用户意图 */
|
||||||
|
.intent-box {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 14px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intent-label {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intent-text {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 执行流程 */
|
||||||
|
.execution-flow {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flow-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 阶段 */
|
||||||
|
.phase {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
opacity: 0.5;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phase.active {
|
||||||
|
opacity: 1;
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
.phase-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 10px 14px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border-bottom: 1px solid var(--vp-c-divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
.phase-icon {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phase-name {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phase-status {
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.phase-content {
|
||||||
|
padding: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 思考步骤 */
|
||||||
|
.thought-steps {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thought-step {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
background: #fef3c7;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-num {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--vp-c-brand);
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-text {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #92400e;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 工具链 */
|
||||||
|
.tools-chain {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-node {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
transition: all 0.3s;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-node.completed {
|
||||||
|
border-color: #86efac;
|
||||||
|
background: #f0fdf4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-node.executing {
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
background: var(--vp-c-brand-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-node.pending {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-connector {
|
||||||
|
position: absolute;
|
||||||
|
left: 24px;
|
||||||
|
top: -14px;
|
||||||
|
width: 2px;
|
||||||
|
height: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connector-line {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: var(--vp-c-divider);
|
||||||
|
transition: background 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.connector-line.active {
|
||||||
|
background: var(--vp-c-brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-icon {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-name {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-status {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-done {
|
||||||
|
color: #16a34a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-running .pulse {
|
||||||
|
display: inline-block;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
background: var(--vp-c-brand);
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: pulse 1s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0%, 100% { opacity: 1; transform: scale(1); }
|
||||||
|
50% { opacity: 0.5; transform: scale(1.2); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-wait {
|
||||||
|
color: var(--vp-c-text-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 工具详情 */
|
||||||
|
.tool-detail-popup {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-row:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-label {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-code {
|
||||||
|
background: #1e1e1e;
|
||||||
|
color: #d4d4d4;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-output {
|
||||||
|
color: #16a34a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-flow-hint {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 12px;
|
||||||
|
padding: 10px;
|
||||||
|
background: var(--vp-c-brand-soft);
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--vp-c-brand-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 整合步骤 */
|
||||||
|
.integration-steps {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.integration-step {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.integration-step.done {
|
||||||
|
background: #dcfce7;
|
||||||
|
color: #166534;
|
||||||
|
}
|
||||||
|
|
||||||
|
.check {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 最终输出 */
|
||||||
|
.final-output {
|
||||||
|
padding: 12px;
|
||||||
|
background: #dcfce7;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.output-bubble {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #166534;
|
||||||
|
line-height: 1.6;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 控制按钮 */
|
||||||
|
.controls {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-btn {
|
||||||
|
padding: 10px 24px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-btn.primary {
|
||||||
|
background: var(--vp-c-brand);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-btn.primary:hover {
|
||||||
|
background: var(--vp-c-brand-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-btn.secondary {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-btn.secondary:hover {
|
||||||
|
background: var(--vp-c-bg-alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
.control-btn:disabled {
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 原理解释 */
|
||||||
|
.principle-explanation {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.explanation-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.explanation-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.explanation-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.explanation-card {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 14px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-icon {
|
||||||
|
font-size: 24px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-desc {
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 对比表格 */
|
||||||
|
.comparison-section {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comparison-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.comparison-table {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1px;
|
||||||
|
background: var(--vp-c-divider);
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comparison-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 100px 1fr 1fr;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
font-size: 12px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comparison-row.header {
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col.scenario {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col.llm {
|
||||||
|
color: #6b7280;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col.agent {
|
||||||
|
color: var(--vp-c-brand-dark);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,598 @@
|
|||||||
|
<template>
|
||||||
|
<div class="planning-demo">
|
||||||
|
<div class="header">
|
||||||
|
<div class="title">
|
||||||
|
📋 Agent 的规划能力
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 任务选择 -->
|
||||||
|
<div class="task-tabs">
|
||||||
|
<button
|
||||||
|
v-for="task in tasks"
|
||||||
|
:key="task.id"
|
||||||
|
:class="['task-btn', { active: currentTask === task.id }]"
|
||||||
|
@click="selectTask(task.id)"
|
||||||
|
>
|
||||||
|
<span>{{ task.icon }}</span>
|
||||||
|
<span>{{ task.name }}</span>
|
||||||
|
<span
|
||||||
|
class="complexity"
|
||||||
|
:class="task.complexity"
|
||||||
|
>{{ task.complexityLabel }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 目标 -->
|
||||||
|
<div class="goal-bar">
|
||||||
|
<span class="label">🎯</span>
|
||||||
|
<span class="text">{{ currentTaskData.goal }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 执行区域 -->
|
||||||
|
<div class="execution-area">
|
||||||
|
<!-- 步骤进度条 -->
|
||||||
|
<div class="steps-progress">
|
||||||
|
<div
|
||||||
|
v-for="(step, index) in currentTaskData.steps"
|
||||||
|
:key="index"
|
||||||
|
class="step-node"
|
||||||
|
:class="{ completed: stepStatus[index] === 'completed', running: stepStatus[index] === 'running' }"
|
||||||
|
>
|
||||||
|
<div class="node-circle">
|
||||||
|
{{ index + 1 }}
|
||||||
|
</div>
|
||||||
|
<div class="node-name">
|
||||||
|
{{ step.name }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="index < currentTaskData.steps.length - 1"
|
||||||
|
class="node-line"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 日志和思考 -->
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="log-box">
|
||||||
|
<div class="box-header">
|
||||||
|
<span>📝 执行日志</span>
|
||||||
|
<span
|
||||||
|
v-if="executionStatus === 'running'"
|
||||||
|
class="status running"
|
||||||
|
>执行中</span>
|
||||||
|
<span
|
||||||
|
v-else-if="executionStatus === 'completed'"
|
||||||
|
class="status completed"
|
||||||
|
>已完成</span>
|
||||||
|
</div>
|
||||||
|
<div class="log-content">
|
||||||
|
<div
|
||||||
|
v-if="logs.length === 0"
|
||||||
|
class="empty"
|
||||||
|
>
|
||||||
|
点击"开始执行"查看过程
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-for="(log, i) in logs.slice(-4)"
|
||||||
|
:key="i"
|
||||||
|
class="log-line"
|
||||||
|
:class="log.type"
|
||||||
|
>
|
||||||
|
<span class="time">{{ log.time }}</span>
|
||||||
|
<span class="icon">{{ log.icon }}</span>
|
||||||
|
<span
|
||||||
|
class="msg"
|
||||||
|
v-html="log.message"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="currentThought"
|
||||||
|
class="thought-box"
|
||||||
|
>
|
||||||
|
<div class="box-header">
|
||||||
|
🧠 正在思考
|
||||||
|
</div>
|
||||||
|
<div class="thought-content">
|
||||||
|
{{ currentThought }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 控制栏 -->
|
||||||
|
<div class="control-bar">
|
||||||
|
<button
|
||||||
|
v-if="executionStatus === 'idle'"
|
||||||
|
class="ctrl-btn primary"
|
||||||
|
@click="startExecution"
|
||||||
|
>
|
||||||
|
▶ 开始执行
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-else-if="executionStatus === 'running'"
|
||||||
|
class="ctrl-btn"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
⏳ 执行中...
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-else
|
||||||
|
class="ctrl-btn"
|
||||||
|
@click="reset"
|
||||||
|
>
|
||||||
|
🔄 重置
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="executionStatus === 'completed'"
|
||||||
|
class="stats"
|
||||||
|
>
|
||||||
|
<span class="stat">{{ currentTaskData.steps.length }} 步骤</span>
|
||||||
|
<span class="stat">{{ executionTime }}s</span>
|
||||||
|
<span class="stat">{{ toolCalls }} 调用</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="step-dots">
|
||||||
|
<span
|
||||||
|
v-for="n in currentTaskData.steps.length"
|
||||||
|
:key="n"
|
||||||
|
:class="['dot', { active: stepStatus[n-1] === 'completed' }]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 提示 -->
|
||||||
|
<div class="tip-bar">
|
||||||
|
<span>💡</span>
|
||||||
|
<span>规划核心:将复杂任务分解为<strong>原子操作</strong>,根据上一步结果<strong>动态调整</strong>后续计划</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, nextTick } from 'vue'
|
||||||
|
|
||||||
|
const tasks = [
|
||||||
|
{
|
||||||
|
id: 'simple',
|
||||||
|
icon: '🌤️',
|
||||||
|
name: '查天气',
|
||||||
|
complexity: 'easy',
|
||||||
|
complexityLabel: '简单',
|
||||||
|
goal: '查询北京今天的天气',
|
||||||
|
steps: [
|
||||||
|
{ name: '调用天气 API', tool: 'weather_api' },
|
||||||
|
{ name: '格式化结果', tool: 'formatter' }
|
||||||
|
],
|
||||||
|
logs: [
|
||||||
|
{ type: 'think', icon: '🧠', message: '需要查询北京天气' },
|
||||||
|
{ type: 'action', icon: '🔧', message: 'weather_api(city="北京")' },
|
||||||
|
{ type: 'result', icon: '📥', message: '晴, 25°C, 空气质量良' },
|
||||||
|
{ type: 'complete', icon: '✅', message: '北京今天天气晴朗' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'medium',
|
||||||
|
icon: '📊',
|
||||||
|
name: '数据分析',
|
||||||
|
complexity: 'medium',
|
||||||
|
complexityLabel: '中等',
|
||||||
|
goal: '分析销售 CSV,找出销售额最高月份',
|
||||||
|
steps: [
|
||||||
|
{ name: '读取 CSV', tool: 'file_reader' },
|
||||||
|
{ name: '解析数据', tool: 'data_parser' },
|
||||||
|
{ name: '聚合计算', tool: 'calculator' },
|
||||||
|
{ name: '生成报告', tool: 'report_generator' }
|
||||||
|
],
|
||||||
|
logs: [
|
||||||
|
{ type: 'think', icon: '🧠', message: '读取销售数据文件' },
|
||||||
|
{ type: 'action', icon: '🔧', message: 'file_reader(path="sales.csv")' },
|
||||||
|
{ type: 'result', icon: '📥', message: '读取 1200 行数据' },
|
||||||
|
{ type: 'think', icon: '🧠', message: '解析数据结构' },
|
||||||
|
{ type: 'action', icon: '🔧', message: 'data_parser(data)' },
|
||||||
|
{ type: 'result', icon: '📥', message: '解析完成' },
|
||||||
|
{ type: 'think', icon: '🧠', message: '按月份聚合销售额' },
|
||||||
|
{ type: 'action', icon: '🔧', message: 'calculator.aggregate(by="month")' },
|
||||||
|
{ type: 'result', icon: '📥', message: '11月销售额最高 ¥320K' },
|
||||||
|
{ type: 'complete', icon: '✅', message: '分析完成' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'complex',
|
||||||
|
icon: '🔬',
|
||||||
|
name: '研究报告',
|
||||||
|
complexity: 'hard',
|
||||||
|
complexityLabel: '复杂',
|
||||||
|
goal: '调研 AI Agent 进展,撰写完整报告',
|
||||||
|
steps: [
|
||||||
|
{ name: '搜索资讯', tool: 'web_search' },
|
||||||
|
{ name: '阅读文章', tool: 'web_reader' },
|
||||||
|
{ name: '提取信息', tool: 'extractor' },
|
||||||
|
{ name: '搜索厂商', tool: 'web_search' },
|
||||||
|
{ name: '生成大纲', tool: 'planner' },
|
||||||
|
{ name: '撰写报告', tool: 'writer' }
|
||||||
|
],
|
||||||
|
logs: [
|
||||||
|
{ type: 'think', icon: '🧠', message: '搜索最新 AI Agent 资讯' },
|
||||||
|
{ type: 'action', icon: '🔧', message: 'web_search("AI Agent 2024")' },
|
||||||
|
{ type: 'result', icon: '📥', message: '找到 15 篇文章' },
|
||||||
|
{ type: 'action', icon: '🔧', message: 'web_reader(urls=[...])' },
|
||||||
|
{ type: 'result', icon: '📥', message: '成功读取内容' },
|
||||||
|
{ type: 'action', icon: '🔧', message: 'extractor(fields=[...])' },
|
||||||
|
{ type: 'result', icon: '📥', message: '提取 45 个数据点' },
|
||||||
|
{ type: 'action', icon: '🔧', message: 'web_search("AI Agent companies")' },
|
||||||
|
{ type: 'result', icon: '📥', message: 'OpenAI, Anthropic, Microsoft...' },
|
||||||
|
{ type: 'action', icon: '🔧', message: 'planner.generate_outline()' },
|
||||||
|
{ type: 'result', icon: '📥', message: '大纲生成完成' },
|
||||||
|
{ type: 'action', icon: '🔧', message: 'writer.generate_content()' },
|
||||||
|
{ type: 'complete', icon: '✅', message: '报告生成完成,2500字' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const currentTask = ref('simple')
|
||||||
|
const executionStatus = ref('idle')
|
||||||
|
const stepStatus = ref([])
|
||||||
|
const logs = ref([])
|
||||||
|
const currentThought = ref('')
|
||||||
|
const executionTime = ref(0)
|
||||||
|
const toolCalls = ref(0)
|
||||||
|
|
||||||
|
const currentTaskData = computed(() => tasks.find(t => t.id === currentTask.value))
|
||||||
|
|
||||||
|
const selectTask = (id) => {
|
||||||
|
currentTask.value = id
|
||||||
|
reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
executionStatus.value = 'idle'
|
||||||
|
stepStatus.value = new Array(currentTaskData.value.steps.length).fill('pending')
|
||||||
|
logs.value = []
|
||||||
|
currentThought.value = ''
|
||||||
|
executionTime.value = 0
|
||||||
|
toolCalls.value = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const startExecution = async () => {
|
||||||
|
executionStatus.value = 'running'
|
||||||
|
stepStatus.value = new Array(currentTaskData.value.steps.length).fill('pending')
|
||||||
|
logs.value = []
|
||||||
|
toolCalls.value = 0
|
||||||
|
|
||||||
|
const startTime = Date.now()
|
||||||
|
const taskLogs = currentTaskData.value.logs
|
||||||
|
|
||||||
|
for (let i = 0; i < taskLogs.length; i++) {
|
||||||
|
const log = taskLogs[i]
|
||||||
|
|
||||||
|
if (log.type === 'think') currentThought.value = log.message
|
||||||
|
if (log.type === 'action') {
|
||||||
|
const stepIndex = Math.min(toolCalls.value, currentTaskData.value.steps.length - 1)
|
||||||
|
stepStatus.value = stepStatus.value.map((s, idx) => {
|
||||||
|
if (idx < stepIndex) return 'completed'
|
||||||
|
if (idx === stepIndex) return 'running'
|
||||||
|
return 'pending'
|
||||||
|
})
|
||||||
|
toolCalls.value++
|
||||||
|
}
|
||||||
|
if (log.type === 'complete') currentThought.value = ''
|
||||||
|
|
||||||
|
logs.value.push({ ...log, time: new Date().toLocaleTimeString('zh-CN', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' }) })
|
||||||
|
await wait(700)
|
||||||
|
}
|
||||||
|
|
||||||
|
stepStatus.value = stepStatus.value.map(() => 'completed')
|
||||||
|
executionTime.value = ((Date.now() - startTime) / 1000).toFixed(1)
|
||||||
|
executionStatus.value = 'completed'
|
||||||
|
}
|
||||||
|
|
||||||
|
const wait = (ms) => new Promise(resolve => setTimeout(resolve, ms))
|
||||||
|
reset()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.planning-demo {
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 700;
|
||||||
|
background: linear-gradient(120deg, var(--vp-c-brand), #9c27b0);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 任务标签 */
|
||||||
|
.task-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 8px 14px;
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 20px;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 13px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-btn.active {
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
background: var(--vp-c-brand-soft);
|
||||||
|
color: var(--vp-c-brand-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.complexity {
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.complexity.easy { background: #dcfce7; color: #166534; }
|
||||||
|
.complexity.medium { background: #fef3c7; color: #92400e; }
|
||||||
|
.complexity.hard { background: #fee2e2; color: #991b1b; }
|
||||||
|
|
||||||
|
/* 目标 */
|
||||||
|
.goal-bar {
|
||||||
|
background: var(--vp-c-brand-soft);
|
||||||
|
border-left: 3px solid var(--vp-c-brand);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 10px 14px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goal-bar .label { margin-right: 8px; }
|
||||||
|
.goal-bar .text { font-weight: 600; }
|
||||||
|
|
||||||
|
/* 步骤进度 */
|
||||||
|
.steps-progress {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
overflow-x: auto;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-node {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-circle {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 2px solid var(--vp-c-divider);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-node.running .node-circle {
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
background: var(--vp-c-brand-soft);
|
||||||
|
animation: pulse 1.5s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-node.completed .node-circle {
|
||||||
|
border-color: #22c55e;
|
||||||
|
background: #dcfce7;
|
||||||
|
color: #166534;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0%, 100% { transform: scale(1); }
|
||||||
|
50% { transform: scale(1.1); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-name {
|
||||||
|
font-size: 11px;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-node.completed .node-name,
|
||||||
|
.step-node.running .node-name {
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node-line {
|
||||||
|
position: absolute;
|
||||||
|
top: 16px;
|
||||||
|
right: -16px;
|
||||||
|
width: 24px;
|
||||||
|
height: 2px;
|
||||||
|
background: var(--vp-c-divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-node.completed + .step-node .node-line {
|
||||||
|
background: #22c55e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 信息行 */
|
||||||
|
.info-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 2fr 1fr;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.info-row { grid-template-columns: 1fr; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-box, .thought-box {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 12px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border-bottom: 1px solid var(--vp-c-divider);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status.running { background: #fef3c7; color: #92400e; }
|
||||||
|
.status.completed { background: #dcfce7; color: #166534; }
|
||||||
|
|
||||||
|
.log-content {
|
||||||
|
padding: 10px 12px;
|
||||||
|
min-height: 100px;
|
||||||
|
max-height: 140px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty {
|
||||||
|
color: var(--vp-c-text-3);
|
||||||
|
text-align: center;
|
||||||
|
padding: 30px 0;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-line {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-line .time {
|
||||||
|
color: var(--vp-c-text-3);
|
||||||
|
font-size: 10px;
|
||||||
|
min-width: 55px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-line .icon {
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-line .msg {
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-line.think .msg { color: #3b82f6; }
|
||||||
|
.log-line.action .msg { color: #f59e0b; }
|
||||||
|
.log-line.result .msg { color: #10b981; }
|
||||||
|
.log-line.complete .msg { color: #8b5cf6; font-weight: 600; }
|
||||||
|
|
||||||
|
.thought-content {
|
||||||
|
padding: 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
font-style: italic;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 控制栏 */
|
||||||
|
.control-bar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ctrl-btn {
|
||||||
|
padding: 8px 18px;
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ctrl-btn.primary {
|
||||||
|
background: var(--vp-c-brand);
|
||||||
|
color: white;
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat {
|
||||||
|
padding: 4px 10px;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-dots {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--vp-c-divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot.active { background: #22c55e; }
|
||||||
|
|
||||||
|
/* 提示 */
|
||||||
|
.tip-bar {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 10px 14px;
|
||||||
|
background: var(--vp-c-brand-soft);
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,733 @@
|
|||||||
|
<template>
|
||||||
|
<div class="agent-chat-demo">
|
||||||
|
<div class="header">
|
||||||
|
<div class="title">
|
||||||
|
🤖 Agent 初体验:从"能说"到"能做"
|
||||||
|
</div>
|
||||||
|
<div class="subtitle">
|
||||||
|
体验 Agent 如何自动调用工具完成任务
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 场景选择 -->
|
||||||
|
<div class="scenario-tabs">
|
||||||
|
<button
|
||||||
|
v-for="s in scenarios"
|
||||||
|
:key="s.id"
|
||||||
|
:class="['tab-btn', { active: currentScenario === s.id }]"
|
||||||
|
@click="selectScenario(s.id)"
|
||||||
|
>
|
||||||
|
<span>{{ s.icon }}</span>
|
||||||
|
<span>{{ s.name }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 聊天窗口 -->
|
||||||
|
<div class="chat-window">
|
||||||
|
<!-- 用户消息 -->
|
||||||
|
<div class="message user">
|
||||||
|
<div class="avatar">
|
||||||
|
👤
|
||||||
|
</div>
|
||||||
|
<div class="bubble">
|
||||||
|
{{ currentScenarioData.query }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- LLM 回复(对比) -->
|
||||||
|
<div class="message llm">
|
||||||
|
<div class="avatar">
|
||||||
|
🤖
|
||||||
|
</div>
|
||||||
|
<div class="bubble llm-bubble">
|
||||||
|
<div class="llm-label">
|
||||||
|
普通 LLM
|
||||||
|
</div>
|
||||||
|
<div class="llm-content">
|
||||||
|
{{ currentScenarioData.llmResponse }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Agent 回复 -->
|
||||||
|
<div class="message agent">
|
||||||
|
<div class="avatar agent-avatar">
|
||||||
|
🦾
|
||||||
|
</div>
|
||||||
|
<div class="bubble agent-bubble">
|
||||||
|
<div class="agent-label">
|
||||||
|
Agent 智能体
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 思考过程(可折叠) -->
|
||||||
|
<div
|
||||||
|
v-if="showThinking"
|
||||||
|
class="thinking-section"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="thinking-header"
|
||||||
|
@click="toggleThinking"
|
||||||
|
>
|
||||||
|
<span>🧠 思考过程</span>
|
||||||
|
<span class="toggle-icon">{{ thinkingExpanded ? '▼' : '▶' }}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="thinkingExpanded"
|
||||||
|
class="thinking-content"
|
||||||
|
>
|
||||||
|
<div class="thought-item">
|
||||||
|
{{ currentScenarioData.thinking }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 工具调用(可折叠) -->
|
||||||
|
<div
|
||||||
|
v-if="showTools"
|
||||||
|
ref="toolsSection"
|
||||||
|
class="tools-section"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="tools-header"
|
||||||
|
@click="toggleTools"
|
||||||
|
>
|
||||||
|
<span>🔧 工具调用 ({{ currentScenarioData.tools.length }}个)</span>
|
||||||
|
<span class="toggle-icon">{{ toolsExpanded ? '▼' : '▶' }}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="toolsExpanded"
|
||||||
|
class="tools-list"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(tool, idx) in currentScenarioData.tools"
|
||||||
|
:key="idx"
|
||||||
|
:ref="el => setToolRef(el, idx)"
|
||||||
|
class="tool-item"
|
||||||
|
:class="{ completed: toolExecuted > idx, executing: toolExecuting === idx }"
|
||||||
|
>
|
||||||
|
<div class="tool-status">
|
||||||
|
<span v-if="toolExecuted > idx">✅</span>
|
||||||
|
<span
|
||||||
|
v-else-if="toolExecuting === idx"
|
||||||
|
class="spinner"
|
||||||
|
>⏳</span>
|
||||||
|
<span v-else>⏸️</span>
|
||||||
|
</div>
|
||||||
|
<div class="tool-info">
|
||||||
|
<div class="tool-name">
|
||||||
|
{{ tool.name }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="toolExecuted > idx || toolExecuting === idx"
|
||||||
|
class="tool-detail"
|
||||||
|
>
|
||||||
|
<code class="tool-params">{{ tool.params }}</code>
|
||||||
|
<div
|
||||||
|
v-if="toolExecuted > idx"
|
||||||
|
class="tool-result"
|
||||||
|
>
|
||||||
|
{{ tool.result }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 最终回复 -->
|
||||||
|
<div
|
||||||
|
v-if="showResponse"
|
||||||
|
class="final-response"
|
||||||
|
>
|
||||||
|
<div class="response-header">
|
||||||
|
💬 最终回复
|
||||||
|
</div>
|
||||||
|
<div class="response-content">
|
||||||
|
{{ currentScenarioData.agentResponse }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 执行按钮 -->
|
||||||
|
<button
|
||||||
|
v-if="!isExecuting && !executionComplete"
|
||||||
|
class="execute-btn"
|
||||||
|
@click="startExecution"
|
||||||
|
>
|
||||||
|
▶ 让 Agent 执行
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-else-if="executionComplete"
|
||||||
|
class="execute-btn reset"
|
||||||
|
@click="reset"
|
||||||
|
>
|
||||||
|
🔄 重置对话
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 核心区别 -->
|
||||||
|
<div class="insight-bar">
|
||||||
|
<span class="insight-label">💡 核心区别:</span>
|
||||||
|
<span class="insight-text">{{ currentScenarioData.insight }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, nextTick } from 'vue'
|
||||||
|
|
||||||
|
const scenarios = [
|
||||||
|
{
|
||||||
|
id: 'weather',
|
||||||
|
icon: '🌤️',
|
||||||
|
name: '查天气',
|
||||||
|
query: '北京今天天气怎么样?适合穿什么衣服?',
|
||||||
|
llmResponse: '我无法获取实时天气信息。北京一般在春季比较温和,建议穿薄外套。',
|
||||||
|
thinking: '用户想知道北京今天的天气和穿衣建议。我需要:1) 查询实时天气 2) 根据温度给出穿衣建议',
|
||||||
|
tools: [
|
||||||
|
{ name: 'weather_api', params: '{"city": "北京", "date": "today"}', result: '☀️ 晴,15-25°C,空气质量良' }
|
||||||
|
],
|
||||||
|
agentResponse: '北京今天天气晴朗,15-25°C,空气质量良。建议穿薄外套或长袖T恤,早晚温差较大,可以带件薄外套。',
|
||||||
|
insight: 'Agent 调用天气 API 获取实时数据,LLM 只能基于训练数据推测。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'calculate',
|
||||||
|
icon: '🧮',
|
||||||
|
name: '复杂计算',
|
||||||
|
query: '帮我算一下:如果贷款100万,年利率4.2%,30年等额本息,每月还多少?总利息多少?',
|
||||||
|
llmResponse: '根据公式计算,月供大约5000元左右,总利息约80万。这只是估算,建议用专业计算器。',
|
||||||
|
thinking: '这是房贷计算问题,需要用到等额本息公式。月供 = 贷款本金 × 月利率 × (1+月利率)^还款月数 / [(1+月利率)^还款月数 - 1]',
|
||||||
|
tools: [
|
||||||
|
{ name: 'calculator', params: '{"principal": 1000000, "rate": 0.042, "years": 30}', result: '月供: ¥4,890.19, 总利息: ¥760,468.40' }
|
||||||
|
],
|
||||||
|
agentResponse: '计算结果:\n• 每月还款:¥4,890.19\n• 还款总额:¥1,760,468.40\n• 总利息:¥760,468.40\n\n30年下来利息约占本金的76%。',
|
||||||
|
insight: 'Agent 调用计算器确保 100% 准确,LLM 心算可能出错。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'stock',
|
||||||
|
icon: '📈',
|
||||||
|
name: '股票分析',
|
||||||
|
query: '分析一下特斯拉股票最近的表现,并预测明天走势',
|
||||||
|
llmResponse: '我无法获取实时股票数据。特斯拉是知名电动车公司,股价波动较大,建议查看专业财经网站。',
|
||||||
|
thinking: '用户需要特斯拉股票的近期表现分析和预测。我需要:1) 获取最新股价 2) 获取历史数据 3) 进行技术分析',
|
||||||
|
tools: [
|
||||||
|
{ name: 'stock_api', params: '{"symbol": "TSLA", "period": "1mo"}', result: '当前价: $248.50, 月涨幅: +12.3%, 成交量: 1.2亿' },
|
||||||
|
{ name: 'news_search', params: '{"query": "Tesla stock news", "limit": 5}', result: '找到5条相关新闻:财报超预期、新车型发布...' },
|
||||||
|
{ name: 'technical_analysis', params: '{"data": "TSLA_price_data", "indicators": ["MA", "RSI"]}', result: 'RSI: 68(接近超买), MA20: $235, 趋势: 上升' }
|
||||||
|
],
|
||||||
|
agentResponse: '特斯拉(TSLA)最近表现:\n📈 月涨幅 +12.3%,现报 $248.50\n📊 技术指标:RSI 68(接近超买),站上20日均线\n📰 消息面:财报超预期、新车型发布利好\n\n预测:短期可能回调,中长期看好。',
|
||||||
|
insight: 'Agent 串联多个工具(股价+新闻+技术分析)完成复杂分析任务。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'travel',
|
||||||
|
icon: '✈️',
|
||||||
|
name: '旅行规划',
|
||||||
|
query: '帮我规划一个3天2晚的东京旅行,预算1万人民币,包含机票、酒店、景点',
|
||||||
|
llmResponse: '东京是个好地方!我可以给你一些建议:浅草寺、东京塔、银座购物区都很值得去。预算1万可能有点紧张,建议提前预订。',
|
||||||
|
thinking: '用户需要完整的东京3天2晚旅行规划。我需要:1) 查询机票价格 2) 搜索酒店 3) 推荐景点 4) 规划路线 5) 计算总预算',
|
||||||
|
tools: [
|
||||||
|
{ name: 'flight_search', params: '{"from": "上海", "to": "东京", "depart": "2024-03-15", "return": "2024-03-17"}', result: '往返机票: ¥3,200 (春秋航空)' },
|
||||||
|
{ name: 'hotel_search', params: '{"city": "东京", "checkin": "2024-03-15", "nights": 2, "budget": 3000}', result: '新宿华盛顿酒店: ¥1,200/晚, 评分4.5' },
|
||||||
|
{ name: 'attractions_search', params: '{"city": "东京", "days": 3}', result: '推荐景点: 浅草寺、东京塔、涩谷十字路口、明治神宫、秋叶原' },
|
||||||
|
{ name: 'route_planner', params: '{"spots": ["浅草寺", "东京塔", "涩谷", "秋叶原"], "days": 3}', result: 'Day1: 浅草寺→东京塔, Day2: 涩谷→明治神宫, Day3: 秋叶原→银座' },
|
||||||
|
{ name: 'budget_calculator', params: '{"flight": 3200, "hotel": 2400, "food": 1500, "transport": 500, "tickets": 800}', result: '总预算: ¥8,400 (剩余¥1,600用于购物)' }
|
||||||
|
],
|
||||||
|
agentResponse: '✈️ 东京3天2晚行程规划\n\n📅 Day1: 浅草寺→东京塔\n📅 Day2: 涩谷→明治神宫\n📅 Day3: 秋叶原→银座\n\n💰 预算明细:\n• 往返机票: ¥3,200\n• 酒店2晚: ¥2,400\n• 餐饮: ¥1,500\n• 交通: ¥500\n• 门票: ¥800\n• 总计: ¥8,400 (剩余¥1,600购物)',
|
||||||
|
insight: 'Agent 调用5个工具完成机票、酒店、景点、路线、预算的完整规划。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'shopping',
|
||||||
|
icon: '🛒',
|
||||||
|
name: '智能购物',
|
||||||
|
query: '我想买一台5000元左右的笔记本电脑,主要用于编程和轻度游戏,推荐几款并对比',
|
||||||
|
llmResponse: '5000元预算可以买到不错的笔记本。推荐联想小新Pro、华为MateBook、小米RedmiBook。具体配置建议16GB内存、512GB SSD。',
|
||||||
|
thinking: '用户需要5000元价位的编程+游戏笔记本推荐。我需要:1) 搜索当前热门机型 2) 获取详细规格参数 3) 查询实时价格 4) 查看用户评价 5) 进行性能对比',
|
||||||
|
tools: [
|
||||||
|
{ name: 'product_search', params: '{"category": "laptop", "budget": 5000, "usage": "programming,gaming"}', result: '找到6款: 联想小新Pro16、ThinkBook14+、华为MateBook14、RedmiBook Pro15、荣耀MagicBook14、机械革命极光Pro' },
|
||||||
|
{ name: 'specs_query', params: '{"products": ["联想小新Pro16", "ThinkBook14+", "华为MateBook14"]}', result: '小新Pro16: R7-7840HS/16G/1TB/2.5K; ThinkBook14+: i5-13500H/16G/512G/2.8K; MateBook14: i5-1340P/16G/512G/2K触控' },
|
||||||
|
{ name: 'price_compare', params: '{"products": ["联想小新Pro16", "ThinkBook14+", "华为MateBook14"]}', result: '小新Pro16: ¥4,999; ThinkBook14+: ¥5,299; MateBook14: ¥5,499' },
|
||||||
|
{ name: 'reviews_search', params: '{"products": ["联想小新Pro16", "ThinkBook14+"], "source": "jd,tmall"}', result: '小新Pro16: 好评率96%, praised for screen and performance; ThinkBook14+: 好评率94%, praised for build quality' },
|
||||||
|
{ name: 'benchmark_compare', params: '{"products": ["联想小新Pro16", "ThinkBook14+"], "tests": ["cpu", "gpu", "battery"]}', result: 'CPU: 小新Pro16(R7) > ThinkBook14+(i5); GPU: 两者均为核显; 续航: ThinkBook14+ 8h > 小新Pro16 6.5h' }
|
||||||
|
],
|
||||||
|
agentResponse: '💻 5000元笔记本推荐对比\n\n🥇 首选: 联想小新Pro16\n• 配置: R7-7840HS/16G/1TB/2.5K 120Hz\n• 价格: ¥4,999\n• 优势: 性能强、屏幕好、存储大\n• 适合: 编程+轻度游戏\n\n🥈 备选: ThinkBook14+\n• 配置: i5-13500H/16G/512G/2.8K\n• 价格: ¥5,299\n• 优势: 做工好、续航长、接口全\n• 适合: 商务办公+编程',
|
||||||
|
insight: 'Agent 调用5个工具完成搜索、查规格、比价格、看评价、跑分对比的完整购物决策。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'report',
|
||||||
|
icon: '📊',
|
||||||
|
name: '研究报告',
|
||||||
|
query: '帮我生成一份2024年新能源汽车行业分析报告,包含市场规模、主要玩家、技术趋势',
|
||||||
|
llmResponse: '新能源汽车行业正在快速发展。特斯拉、比亚迪是行业领导者。市场规模预计持续增长,电池技术是关键。建议查阅专业行业报告获取详细数据。',
|
||||||
|
thinking: '用户需要一份完整的新能源汽车行业分析报告。我需要:1) 查询最新市场数据 2) 搜索主要厂商信息 3) 获取技术发展趋势 4) 查找政策法规 5) 生成数据可视化 6) 整理成报告格式',
|
||||||
|
tools: [
|
||||||
|
{ name: 'market_data', params: '{"industry": "NEV", "year": 2024, "metrics": ["size", "growth", "penetration"]}', result: '2024年全球NEV销量: 1,700万辆(+35%), 中国占比60%, 渗透率: 全球18%, 中国35%' },
|
||||||
|
{ name: 'company_search', params: '{"industry": "NEV", "ranking": "top10"}', result: 'TOP5: 比亚迪(302万辆)、特斯拉(181万辆)、大众(77万辆)、吉利(68万辆)、上汽(63万辆)' },
|
||||||
|
{ name: 'tech_trends', params: '{"field": "NEV", "technologies": ["battery", "autonomous", "charging"]}', result: '电池: 固态电池量产在即, 能量密度>400Wh/kg; 智驾: L2+普及率>50%, L4开始商用; 充电: 800V高压平台普及, 5分钟补能200km' },
|
||||||
|
{ name: 'policy_search', params: '{"region": "global", "topic": "NEV_policy", "year": 2024}', result: '中国: 购置税减免延续至2027年; 欧盟: 2035年禁售燃油车; 美国: IRA法案补贴本土化生产' },
|
||||||
|
{ name: 'data_visualization', params: '{"type": "chart", "data": "NEV_market_share", "chart_type": "pie"}', result: '生成市场份额饼图: 比亚迪35%, 特斯拉21%, 其他44%' },
|
||||||
|
{ name: 'report_generator', params: '{"title": "2024新能源汽车行业分析报告", "sections": ["market", "players", "tech", "policy"], "format": "markdown"}', result: '报告已生成: 12页, 包含6个图表, 3个数据表格' }
|
||||||
|
],
|
||||||
|
agentResponse: '📊 2024新能源汽车行业分析报告\n\n📈 市场规模\n• 全球销量: 1,700万辆 (+35%)\n• 中国市场占比: 60%\n• 全球渗透率: 18% (中国35%)\n\n🏆 主要玩家\n1. 比亚迪: 302万辆 (35%)\n2. 特斯拉: 181万辆 (21%)\n3. 大众: 77万辆\n\n🔋 技术趋势\n• 固态电池能量密度>400Wh/kg\n• L2+智驾普及率超50%\n• 800V高压快充普及\n\n📋 报告已生成: 12页完整分析',
|
||||||
|
insight: 'Agent 调用6个工具完成数据收集、分析、可视化和报告生成的完整研究流程。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'code-run',
|
||||||
|
icon: '💻',
|
||||||
|
name: '代码执行',
|
||||||
|
query: '生成一个1-100的随机数列表,找出其中的质数,并计算平均值',
|
||||||
|
llmResponse: '我可以写出代码,但无法实际执行。质数是指只能被1和自身整除的数,比如2,3,5,7...',
|
||||||
|
thinking: '用户需要:1) 生成随机数列表 2) 筛选质数 3) 计算平均值。我需要在沙箱中执行Python代码',
|
||||||
|
tools: [
|
||||||
|
{ name: 'python_executor', params: '{"code": "import random; nums = [random.randint(1,100) for _ in range(20)]; primes = [n for n in nums if all(n%i!=0 for i in range(2,int(n**0.5)+1)) and n>1]; print(f\"随机数: {nums}\"); print(f\"质数: {primes}\"); print(f\"平均值: {sum(nums)/len(nums):.2f}\")"}', result: '随机数: [42, 17, 89, 23, 56, 71, 34, 91, 13, 67...]\n质数: [17, 89, 23, 71, 13, 67, 47, 79]\n平均值: 52.35' }
|
||||||
|
],
|
||||||
|
agentResponse: '执行结果:\n🎲 生成20个随机数:42, 17, 89, 23, 56, 71...\n🔢 其中质数:17, 89, 23, 71, 13, 67, 47, 79 (共8个)\n📊 所有数平均值:52.35',
|
||||||
|
insight: 'Agent 在沙箱中实际执行代码,LLM 只能推理无法验证结果。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'data-analysis',
|
||||||
|
icon: '📉',
|
||||||
|
name: '数据分析',
|
||||||
|
query: '分析一下我们公司上季度的销售数据,找出增长最快的产品线和地区',
|
||||||
|
llmResponse: '我无法访问您公司的内部销售数据。建议您使用Excel或专业BI工具进行分析,关注同比和环比增长率。',
|
||||||
|
thinking: '用户需要分析公司销售数据。我需要:1) 连接数据库获取销售数据 2) 按产品线分组统计 3) 按地区分组统计 4) 计算增长率 5) 生成可视化图表 6) 输出分析报告',
|
||||||
|
tools: [
|
||||||
|
{ name: 'database_query', params: '{"table": "sales", "period": "Q4_2023", "fields": ["product", "region", "amount", "quantity"]}', result: '获取Q4销售记录: 15,230条, 涵盖12个产品线, 8个地区' },
|
||||||
|
{ name: 'data_groupby', params: '{"data": "sales_q4", "group": "product", "agg": ["sum", "count", "avg"]}', result: '产品线统计: 电子产品¥2.1M(+45%), 服装¥1.8M(+12%), 家居¥1.2M(+28%)...' },
|
||||||
|
{ name: 'data_groupby', params: '{"data": "sales_q4", "group": "region", "agg": ["sum", "growth"]}', result: '地区统计: 华东¥3.2M(+38%), 华南¥2.1M(+52%), 华北¥1.5M(+15%)...' },
|
||||||
|
{ name: 'growth_calculator', params: '{"current": "Q4_2023", "previous": "Q3_2023", "dimensions": ["product", "region"]}', result: '增长最快产品线: 电子产品+45%; 增长最快地区: 华南+52%' },
|
||||||
|
{ name: 'chart_generator', params: '{"type": "bar", "data": "product_growth", "title": "产品线增长率对比"}', result: '生成柱状图: 电子产品45%, 家居28%, 服装12%' },
|
||||||
|
{ name: 'chart_generator', params: '{"type": "map", "data": "region_sales", "title": "地区销售热力图"}', result: '生成中国地图热力图: 华东、华南为深色高值区' }
|
||||||
|
],
|
||||||
|
agentResponse: '📊 Q4销售数据分析报告\n\n🏆 增长最快产品线\n1. 电子产品: +45% (¥2.1M)\n2. 家居用品: +28% (¥1.2M)\n3. 服装: +12% (¥1.8M)\n\n🌍 增长最快地区\n1. 华南: +52% (¥2.1M)\n2. 华东: +38% (¥3.2M)\n3. 西南: +22% (¥0.8M)\n\n💡 建议: 加大电子产品投入,重点拓展华南市场',
|
||||||
|
insight: 'Agent 调用6个工具完成数据查询、分组统计、增长率计算、可视化的完整分析流程。'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const currentScenario = ref('weather')
|
||||||
|
const isExecuting = ref(false)
|
||||||
|
const executionComplete = ref(false)
|
||||||
|
const toolExecuting = ref(-1)
|
||||||
|
const toolExecuted = ref(0)
|
||||||
|
const showThinking = ref(false)
|
||||||
|
const showTools = ref(false)
|
||||||
|
const showResponse = ref(false)
|
||||||
|
const thinkingExpanded = ref(true)
|
||||||
|
const toolsExpanded = ref(true)
|
||||||
|
const toolsSection = ref(null)
|
||||||
|
const toolRefs = ref([])
|
||||||
|
|
||||||
|
const currentScenarioData = computed(() => scenarios.find(s => s.id === currentScenario.value))
|
||||||
|
|
||||||
|
const setToolRef = (el, idx) => {
|
||||||
|
if (el) {
|
||||||
|
toolRefs.value[idx] = el
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectScenario = (id) => {
|
||||||
|
currentScenario.value = id
|
||||||
|
reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
const startExecution = async () => {
|
||||||
|
isExecuting.value = true
|
||||||
|
executionComplete.value = false
|
||||||
|
toolExecuting.value = -1
|
||||||
|
toolExecuted.value = 0
|
||||||
|
showThinking.value = true
|
||||||
|
showTools.value = false
|
||||||
|
showResponse.value = false
|
||||||
|
thinkingExpanded.value = true
|
||||||
|
toolsExpanded.value = true
|
||||||
|
|
||||||
|
// 显示思考
|
||||||
|
await wait(800)
|
||||||
|
|
||||||
|
// 显示工具调用
|
||||||
|
showTools.value = true
|
||||||
|
toolsExpanded.value = true
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
|
||||||
|
const tools = currentScenarioData.value.tools
|
||||||
|
|
||||||
|
for (let i = 0; i < tools.length; i++) {
|
||||||
|
toolExecuting.value = i
|
||||||
|
|
||||||
|
// 滚动到当前执行的工具
|
||||||
|
await nextTick()
|
||||||
|
const toolEl = toolRefs.value[i]
|
||||||
|
if (toolEl && toolsSection.value) {
|
||||||
|
toolEl.scrollIntoView({ behavior: 'smooth', block: 'center' })
|
||||||
|
}
|
||||||
|
|
||||||
|
await wait(1000)
|
||||||
|
toolExecuted.value = i + 1
|
||||||
|
toolExecuting.value = -1
|
||||||
|
await wait(300)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示最终回复
|
||||||
|
await wait(500)
|
||||||
|
showResponse.value = true
|
||||||
|
isExecuting.value = false
|
||||||
|
executionComplete.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
isExecuting.value = false
|
||||||
|
executionComplete.value = false
|
||||||
|
toolExecuting.value = -1
|
||||||
|
toolExecuted.value = 0
|
||||||
|
showThinking.value = false
|
||||||
|
showTools.value = false
|
||||||
|
showResponse.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleThinking = () => {
|
||||||
|
thinkingExpanded.value = !thinkingExpanded.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleTools = () => {
|
||||||
|
toolsExpanded.value = !toolsExpanded.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const wait = (ms) => new Promise(r => setTimeout(r, ms))
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.agent-chat-demo {
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 700;
|
||||||
|
background: linear-gradient(120deg, var(--vp-c-brand), #9c27b0);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 场景标签 */
|
||||||
|
.scenario-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 8px 14px;
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 20px;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-btn:hover {
|
||||||
|
background: var(--vp-c-bg-alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-btn.active {
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
background: var(--vp-c-brand-soft);
|
||||||
|
color: var(--vp-c-brand-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 聊天窗口 */
|
||||||
|
.chat-window {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 16px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 消息 */
|
||||||
|
.message {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message.user {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 16px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar.agent-avatar {
|
||||||
|
background: var(--vp-c-brand-soft);
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bubble {
|
||||||
|
max-width: 75%;
|
||||||
|
padding: 12px 14px;
|
||||||
|
border-radius: 14px;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message.user .bubble {
|
||||||
|
background: var(--vp-c-brand);
|
||||||
|
color: white;
|
||||||
|
border-bottom-right-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message.llm .bubble {
|
||||||
|
background: #f3f4f6;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message.agent .bubble {
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
max-width: 85%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-label, .agent-label {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.agent-label {
|
||||||
|
color: var(--vp-c-brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
.llm-content {
|
||||||
|
color: #6b7280;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 思考过程 */
|
||||||
|
.thinking-section {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thinking-header, .tools-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px 12px;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thinking-header:hover, .tools-header:hover {
|
||||||
|
background: var(--vp-c-bg-alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-icon {
|
||||||
|
font-size: 10px;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.thinking-content {
|
||||||
|
padding: 10px 12px;
|
||||||
|
background: #fef3c7;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #92400e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thought-item {
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 工具调用 */
|
||||||
|
.tools-section {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools-list {
|
||||||
|
padding: 10px;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item.completed {
|
||||||
|
border-color: #86efac;
|
||||||
|
background: #f0fdf4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-item.executing {
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
background: var(--vp-c-brand-soft);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-status {
|
||||||
|
font-size: 14px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner {
|
||||||
|
animation: spin 1s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
from { transform: rotate(0deg); }
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-info {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-name {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-params {
|
||||||
|
display: block;
|
||||||
|
background: #1e1e1e;
|
||||||
|
color: #d4d4d4;
|
||||||
|
padding: 6px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
font-family: monospace;
|
||||||
|
overflow-x: auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-result {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #16a34a;
|
||||||
|
padding: 6px 8px;
|
||||||
|
background: #dcfce7;
|
||||||
|
border-radius: 4px;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 最终回复 */
|
||||||
|
.final-response {
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 12px;
|
||||||
|
background: #dcfce7;
|
||||||
|
border: 1px solid #86efac;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.response-header {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #166534;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.response-content {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #166534;
|
||||||
|
line-height: 1.6;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 执行按钮 */
|
||||||
|
.execute-btn {
|
||||||
|
margin-top: 12px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
background: var(--vp-c-brand);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.execute-btn:hover {
|
||||||
|
background: var(--vp-c-brand-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.execute-btn.reset {
|
||||||
|
background: #6b7280;
|
||||||
|
}
|
||||||
|
|
||||||
|
.execute-btn.reset:hover {
|
||||||
|
background: #4b5563;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 核心区别 */
|
||||||
|
.insight-bar {
|
||||||
|
margin-top: 16px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: var(--vp-c-brand-soft);
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.insight-label {
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--vp-c-brand-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.insight-text {
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,219 @@
|
|||||||
|
<!--
|
||||||
|
AgentTaskFlowDemo.vue
|
||||||
|
任务执行流:像看“回放”一样看 Agent 一步步完成一个任务。
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div class="flow">
|
||||||
|
<div class="header">
|
||||||
|
<div>
|
||||||
|
<div class="title">
|
||||||
|
任务回放:Agent 怎么一步步做完?
|
||||||
|
</div>
|
||||||
|
<div class="subtitle">
|
||||||
|
点步骤,看“工具调用”和“中间结果”。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="actions">
|
||||||
|
<button
|
||||||
|
class="btn"
|
||||||
|
:disabled="step === 0"
|
||||||
|
@click="step = Math.max(0, step - 1)"
|
||||||
|
>
|
||||||
|
上一步
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="btn primary"
|
||||||
|
:disabled="step === steps.length - 1"
|
||||||
|
@click="step = Math.min(steps.length - 1, step + 1)"
|
||||||
|
>
|
||||||
|
下一步
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="timeline">
|
||||||
|
<button
|
||||||
|
v-for="(s, i) in steps"
|
||||||
|
:key="s.title"
|
||||||
|
:class="['t', { active: i === step }]"
|
||||||
|
@click="step = i"
|
||||||
|
>
|
||||||
|
<span class="n">{{ i + 1 }}</span>
|
||||||
|
<span class="txt">{{ s.title }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-title">
|
||||||
|
当前步骤
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
{{ steps[step].desc }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-title">
|
||||||
|
工具调用(示意)
|
||||||
|
</div>
|
||||||
|
<pre><code>{{ steps[step].tool }}</code></pre>
|
||||||
|
</div>
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-title">
|
||||||
|
结果(示意)
|
||||||
|
</div>
|
||||||
|
<pre><code>{{ steps[step].result }}</code></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
const step = ref(0)
|
||||||
|
|
||||||
|
const steps = [
|
||||||
|
{
|
||||||
|
title: '理解目标',
|
||||||
|
desc: '把用户需求拆成“可交付”的输出结构。',
|
||||||
|
tool: 'LLM: parse_goal({ task, constraints, output_format })',
|
||||||
|
result: '目标:找 3 篇文章;输出:标题 + 一句话总结(Markdown 列表)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '搜索',
|
||||||
|
desc: '先用搜索工具拿到候选链接。',
|
||||||
|
tool: 'tool:web_search({ query: \"agent introduction\" })',
|
||||||
|
result: '- link1\n- link2\n- link3\n- link4 ...'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '读取页面',
|
||||||
|
desc: '打开前三个链接,取出核心段落。',
|
||||||
|
tool: 'tool:read_page({ url: link1/link2/link3 })',
|
||||||
|
result: '每篇文章的核心段落(已截取)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '压缩与整理',
|
||||||
|
desc: '把每篇文章压缩成“一句话总结”,统一格式。',
|
||||||
|
tool: 'LLM: summarize_each({ paragraphs, max_len: 25 })',
|
||||||
|
result: '- 标题A:一句话…\n- 标题B:一句话…\n- 标题C:一句话…'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '自检与交付',
|
||||||
|
desc: '检查是否满足“3 条 + 一句话 + 格式正确”,再输出。',
|
||||||
|
tool: 'LLM: self_check({ checklist })',
|
||||||
|
result: '✅ 满足要求;输出已就绪'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.flow {
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
padding: 16px;
|
||||||
|
margin: 20px 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
.subtitle {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.btn {
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.btn.primary {
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
color: var(--vp-c-brand);
|
||||||
|
}
|
||||||
|
.btn:disabled {
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeline {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
.t {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 10px;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.t.active {
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
.n {
|
||||||
|
width: 26px;
|
||||||
|
height: 26px;
|
||||||
|
border-radius: 6px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
.txt {
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.panel {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
.panel-title {
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
.panel-body {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
margin: 0;
|
||||||
|
background: #0b1221;
|
||||||
|
color: #e5e7eb;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 12px;
|
||||||
|
font-family: var(--vp-font-family-mono);
|
||||||
|
font-size: 13px;
|
||||||
|
overflow-x: auto;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,612 @@
|
|||||||
|
<template>
|
||||||
|
<div class="tool-use-demo">
|
||||||
|
<div class="header">
|
||||||
|
<div class="title">
|
||||||
|
🔧 揭秘:Agent 如何调用工具?
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 场景选择 -->
|
||||||
|
<div class="scenario-tabs">
|
||||||
|
<button
|
||||||
|
v-for="s in scenarios"
|
||||||
|
:key="s.id"
|
||||||
|
:class="['tab-btn', { active: currentScenario === s.id }]"
|
||||||
|
@click="selectScenario(s.id)"
|
||||||
|
>
|
||||||
|
<span>{{ s.icon }}</span>
|
||||||
|
<span>{{ s.name }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 用户输入 -->
|
||||||
|
<div class="user-input-bar">
|
||||||
|
<span class="label">👤</span>
|
||||||
|
<span class="text">"{{ currentData.userInput }}"</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 横向流程 -->
|
||||||
|
<div
|
||||||
|
ref="flowRowRef"
|
||||||
|
class="flow-row"
|
||||||
|
>
|
||||||
|
<!-- 步骤1: 理解 -->
|
||||||
|
<div
|
||||||
|
class="flow-card"
|
||||||
|
:class="{ active: currentStep >= 1 }"
|
||||||
|
>
|
||||||
|
<div class="card-num">
|
||||||
|
1
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="card-title">
|
||||||
|
分析需求
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="currentStep >= 1"
|
||||||
|
class="card-content"
|
||||||
|
>
|
||||||
|
<div class="intent-box">
|
||||||
|
<div class="intent-label">
|
||||||
|
用户想要:
|
||||||
|
</div>
|
||||||
|
<div class="intent-value">
|
||||||
|
{{ currentData.intent.type }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="extract-box">
|
||||||
|
<div class="extract-label">
|
||||||
|
提取信息:
|
||||||
|
</div>
|
||||||
|
<div class="extract-tags">
|
||||||
|
<span
|
||||||
|
v-for="(e, i) in currentData.intent.entities"
|
||||||
|
:key="i"
|
||||||
|
class="entity"
|
||||||
|
>{{ e }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="flow-arrow"
|
||||||
|
:class="{ active: currentStep >= 2 }"
|
||||||
|
>
|
||||||
|
→
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 步骤2: 选工具 -->
|
||||||
|
<div
|
||||||
|
class="flow-card"
|
||||||
|
:class="{ active: currentStep >= 2 }"
|
||||||
|
>
|
||||||
|
<div class="card-num">
|
||||||
|
2
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="card-title">
|
||||||
|
选择工具
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="currentStep >= 2"
|
||||||
|
class="card-content"
|
||||||
|
>
|
||||||
|
<div class="tool-list">
|
||||||
|
<div
|
||||||
|
v-for="tool in currentData.availableTools.slice(0, 2)"
|
||||||
|
:key="tool.name"
|
||||||
|
class="tool-mini"
|
||||||
|
:class="{ selected: tool.selected }"
|
||||||
|
>
|
||||||
|
<span>{{ tool.icon }}</span>
|
||||||
|
<span class="tool-name">{{ tool.name }}</span>
|
||||||
|
<span
|
||||||
|
v-if="tool.selected"
|
||||||
|
class="check"
|
||||||
|
>✓</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="flow-arrow"
|
||||||
|
:class="{ active: currentStep >= 3 }"
|
||||||
|
>
|
||||||
|
→
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 步骤3: 构造参数 -->
|
||||||
|
<div
|
||||||
|
class="flow-card"
|
||||||
|
:class="{ active: currentStep >= 3 }"
|
||||||
|
>
|
||||||
|
<div class="card-num">
|
||||||
|
3
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="card-title">
|
||||||
|
构造参数
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="currentStep >= 3"
|
||||||
|
class="card-content"
|
||||||
|
>
|
||||||
|
<code class="params-code">{{ JSON.stringify(currentData.finalParams.params) }}</code>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="flow-arrow"
|
||||||
|
:class="{ active: currentStep >= 4 }"
|
||||||
|
>
|
||||||
|
→
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 步骤4: 执行 -->
|
||||||
|
<div
|
||||||
|
class="flow-card"
|
||||||
|
:class="{ active: currentStep >= 4 }"
|
||||||
|
>
|
||||||
|
<div class="card-num">
|
||||||
|
4
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="card-title">
|
||||||
|
执行返回
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="currentStep >= 4"
|
||||||
|
class="card-content"
|
||||||
|
>
|
||||||
|
<div class="exec-flow">
|
||||||
|
<span class="from">Agent</span>
|
||||||
|
<span class="arrow">→</span>
|
||||||
|
<span class="to">{{ currentData.selectedTool }}</span>
|
||||||
|
<span class="arrow">→</span>
|
||||||
|
<span class="from">结果</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 最终结果 -->
|
||||||
|
<div
|
||||||
|
v-if="currentStep >= 4"
|
||||||
|
class="final-result"
|
||||||
|
>
|
||||||
|
<span class="result-label">💬 回复:</span>
|
||||||
|
<span class="result-text">{{ currentData.finalResponse }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 控制栏 -->
|
||||||
|
<div class="control-bar">
|
||||||
|
<button
|
||||||
|
v-if="currentStep === 0"
|
||||||
|
class="ctrl-btn primary"
|
||||||
|
@click="nextStep"
|
||||||
|
>
|
||||||
|
▶ 开始演示
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-else-if="currentStep < 4"
|
||||||
|
class="ctrl-btn primary"
|
||||||
|
@click="nextStep"
|
||||||
|
>
|
||||||
|
下一步 →
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-else
|
||||||
|
class="ctrl-btn"
|
||||||
|
@click="reset"
|
||||||
|
>
|
||||||
|
🔄 重置
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="step-dots">
|
||||||
|
<span
|
||||||
|
v-for="n in 4"
|
||||||
|
:key="n"
|
||||||
|
:class="['dot', { active: currentStep >= n }]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 提示 -->
|
||||||
|
<div class="tip-bar">
|
||||||
|
<span>💡</span>
|
||||||
|
<span>Tool Calling 本质:LLM 生成结构化文本(JSON),外部系统执行后返回结果</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, watch, nextTick } from 'vue'
|
||||||
|
|
||||||
|
const scenarios = [
|
||||||
|
{
|
||||||
|
id: 'weather',
|
||||||
|
icon: '🌤️',
|
||||||
|
name: '查天气',
|
||||||
|
userInput: '明天上海需要带伞吗?',
|
||||||
|
intent: { type: '天气查询', entities: ['明天', '上海'], confidence: 95 },
|
||||||
|
availableTools: [
|
||||||
|
{ name: 'weather_api', icon: '🌤️', description: '获取天气', selected: true, score: 95 },
|
||||||
|
{ name: 'calculator', icon: '🧮', description: '数学计算', selected: false, score: 10 },
|
||||||
|
],
|
||||||
|
selectedTool: 'weather_api',
|
||||||
|
finalParams: { tool: 'weather_api', params: { city: '上海', date: 'tomorrow' } },
|
||||||
|
finalResponse: '明天上海有小雨,建议带伞。气温 8-15°C。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'calculate',
|
||||||
|
icon: '🧮',
|
||||||
|
name: '计算',
|
||||||
|
userInput: '1250 除以 25 乘以 8 等于多少',
|
||||||
|
intent: { type: '数学计算', entities: ['1250', '25', '8'], confidence: 98 },
|
||||||
|
availableTools: [
|
||||||
|
{ name: 'weather_api', icon: '🌤️', description: '获取天气', selected: false, score: 5 },
|
||||||
|
{ name: 'calculator', icon: '🧮', description: '数学计算', selected: true, score: 98 },
|
||||||
|
],
|
||||||
|
selectedTool: 'calculator',
|
||||||
|
finalParams: { tool: 'calculator', params: { expression: '(1250/25)*8' } },
|
||||||
|
finalResponse: '计算结果:400。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'search',
|
||||||
|
icon: '🔍',
|
||||||
|
name: '搜索',
|
||||||
|
userInput: '搜索最近关于人工智能的新闻',
|
||||||
|
intent: { type: '信息检索', entities: ['AI', '新闻'], confidence: 92 },
|
||||||
|
availableTools: [
|
||||||
|
{ name: 'web_search', icon: '🔍', description: '网络搜索', selected: true, score: 92 },
|
||||||
|
{ name: 'calculator', icon: '🧮', description: '数学计算', selected: false, score: 5 },
|
||||||
|
],
|
||||||
|
selectedTool: 'web_search',
|
||||||
|
finalParams: { tool: 'web_search', params: { query: 'AI news', max: 5 } },
|
||||||
|
finalResponse: '为您找到 5 条最新 AI 新闻...'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const currentScenario = ref('weather')
|
||||||
|
const currentStep = ref(0)
|
||||||
|
|
||||||
|
const currentData = computed(() => scenarios.find(s => s.id === currentScenario.value))
|
||||||
|
|
||||||
|
const selectScenario = (id) => {
|
||||||
|
currentScenario.value = id
|
||||||
|
reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
const flowRowRef = ref(null)
|
||||||
|
|
||||||
|
const nextStep = () => {
|
||||||
|
if (currentStep.value < 4) {
|
||||||
|
currentStep.value++
|
||||||
|
// 自动滚动到当前步骤
|
||||||
|
nextTick(() => {
|
||||||
|
if (flowRowRef.value) {
|
||||||
|
const cards = flowRowRef.value.querySelectorAll('.flow-card')
|
||||||
|
const currentCard = cards[currentStep.value - 1]
|
||||||
|
if (currentCard) {
|
||||||
|
currentCard.scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const reset = () => { currentStep.value = 0 }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tool-use-demo {
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 700;
|
||||||
|
background: linear-gradient(120deg, var(--vp-c-brand), #9c27b0);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 场景标签 */
|
||||||
|
.scenario-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 6px 14px;
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 16px;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 13px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-btn.active {
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
background: var(--vp-c-brand-soft);
|
||||||
|
color: var(--vp-c-brand-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 用户输入 */
|
||||||
|
.user-input-bar {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 10px 14px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-input-bar .label { margin-right: 8px; }
|
||||||
|
.user-input-bar .text { font-weight: 600; color: var(--vp-c-text-1); }
|
||||||
|
|
||||||
|
/* 横向流程 */
|
||||||
|
.flow-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.flow-row {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.flow-arrow {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.flow-card {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 140px;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 12px;
|
||||||
|
opacity: 0.4;
|
||||||
|
transition: all 0.3s;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flow-card.active {
|
||||||
|
opacity: 1;
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-num {
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--vp-c-bg-mute);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flow-card.active .card-num {
|
||||||
|
background: var(--vp-c-brand);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-content {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 意图内容 */
|
||||||
|
.intent-box {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intent-label {
|
||||||
|
font-size: 10px;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intent-value {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 4px 10px;
|
||||||
|
background: var(--vp-c-brand-soft);
|
||||||
|
color: var(--vp-c-brand-dark);
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.extract-box {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.extract-label {
|
||||||
|
font-size: 10px;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.extract-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.entity {
|
||||||
|
padding: 3px 8px;
|
||||||
|
background: #fef3c7;
|
||||||
|
border: 1px solid #fde68a;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #92400e;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 工具列表 */
|
||||||
|
.tool-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-mini {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 6px 8px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-mini.selected {
|
||||||
|
background: #dcfce7;
|
||||||
|
border: 1px solid #86efac;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-name { flex: 1; }
|
||||||
|
.check { color: #16a34a; font-weight: 700; }
|
||||||
|
|
||||||
|
/* 参数代码 */
|
||||||
|
.params-code {
|
||||||
|
display: block;
|
||||||
|
background: #1e1e1e;
|
||||||
|
color: #d4d4d4;
|
||||||
|
padding: 8px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 10px;
|
||||||
|
overflow-x: auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 执行流程 */
|
||||||
|
.exec-flow {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
font-size: 11px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.from, .to {
|
||||||
|
padding: 3px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.from { background: var(--vp-c-brand-soft); color: var(--vp-c-brand-dark); }
|
||||||
|
.to { background: #fef3c7; color: #92400e; }
|
||||||
|
.arrow { color: var(--vp-c-text-3); }
|
||||||
|
|
||||||
|
/* 箭头 */
|
||||||
|
.flow-arrow {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: var(--vp-c-divider);
|
||||||
|
font-size: 18px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flow-arrow.active { color: var(--vp-c-brand); }
|
||||||
|
|
||||||
|
/* 最终结果 */
|
||||||
|
.final-result {
|
||||||
|
background: var(--vp-c-brand-soft);
|
||||||
|
border-left: 3px solid var(--vp-c-brand);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-label { font-weight: 600; margin-right: 8px; }
|
||||||
|
.result-text { color: var(--vp-c-text-1); }
|
||||||
|
|
||||||
|
/* 控制栏 */
|
||||||
|
.control-bar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ctrl-btn {
|
||||||
|
padding: 8px 18px;
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ctrl-btn.primary {
|
||||||
|
background: var(--vp-c-brand);
|
||||||
|
color: white;
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-dots {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--vp-c-divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot.active { background: var(--vp-c-brand); }
|
||||||
|
|
||||||
|
/* 提示 */
|
||||||
|
.tip-bar {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 10px 14px;
|
||||||
|
background: var(--vp-c-brand-soft);
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--vp-c-text-1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,253 @@
|
|||||||
|
<!--
|
||||||
|
AgentWorkflowDemo.vue
|
||||||
|
Agent 核心循环(更像“先玩后讲”的演示):
|
||||||
|
- 点步骤:看这一轮 Agent “在干什么”
|
||||||
|
- 点“下一轮”:看它如何反复迭代直到完成
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div class="workflow">
|
||||||
|
<div class="header">
|
||||||
|
<div>
|
||||||
|
<div class="title">
|
||||||
|
先玩一下:Agent 不是“聊天”,是“循环行动”
|
||||||
|
</div>
|
||||||
|
<div class="subtitle">
|
||||||
|
它会反复:观察 → 计划 → 用工具 → 检查结果。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="actions">
|
||||||
|
<button
|
||||||
|
class="btn"
|
||||||
|
@click="reset"
|
||||||
|
>
|
||||||
|
重置
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="btn primary"
|
||||||
|
@click="nextRound"
|
||||||
|
>
|
||||||
|
下一轮 ({{ round }}/3)
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cycle">
|
||||||
|
<button
|
||||||
|
v-for="s in steps"
|
||||||
|
:key="s.id"
|
||||||
|
:class="['step', { active: currentStep === s.id }]"
|
||||||
|
@click="currentStep = s.id"
|
||||||
|
>
|
||||||
|
<span class="icon">{{ s.icon }}</span>
|
||||||
|
<span class="name">{{ s.name }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panels">
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-title">
|
||||||
|
任务
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
帮我找 3 篇 “Agent” 入门文章,并输出:标题 + 一句话总结。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-title">
|
||||||
|
这一轮发生了什么?
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
{{ detail }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="log">
|
||||||
|
<div class="log-title">
|
||||||
|
Agent 运行日志(示意)
|
||||||
|
</div>
|
||||||
|
<pre><code>{{ logText }}</code></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
|
||||||
|
const steps = [
|
||||||
|
{ id: 'observe', name: '观察', icon: '👀' },
|
||||||
|
{ id: 'plan', name: '计划', icon: '🧩' },
|
||||||
|
{ id: 'act', name: '行动', icon: '🔧' },
|
||||||
|
{ id: 'check', name: '检查', icon: '✅' }
|
||||||
|
]
|
||||||
|
|
||||||
|
const round = ref(1)
|
||||||
|
const currentStep = ref('observe')
|
||||||
|
|
||||||
|
const scenarios = [
|
||||||
|
{
|
||||||
|
observe: '看到用户目标:要 3 篇入门文章 + 简短总结。',
|
||||||
|
plan: '计划:1) 搜索关键词 2) 打开前几条 3) 抽取标题与要点。',
|
||||||
|
act: '调用工具:web_search(query="agent introduction")。',
|
||||||
|
check: '检查:结果里有 3 条可用链接,还缺“每条一句话总结”。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
observe: '拿到链接列表,准备逐条打开并提取要点。',
|
||||||
|
plan: '计划:依次 read_page 3 次,把内容压缩成一句话。',
|
||||||
|
act: '调用工具:read_page(url=...) × 3。',
|
||||||
|
check: '检查:信息够了,但标题格式不统一,需要整理输出。'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
observe: '材料齐全:标题 + 文章要点都已提取。',
|
||||||
|
plan: '计划:统一格式,输出 Markdown 列表。',
|
||||||
|
act: '组织输出:每条“标题 - 一句话总结”。',
|
||||||
|
check: '完成:满足“3 条 + 一句话总结 + 可直接复制”。'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const current = computed(() => scenarios[round.value - 1])
|
||||||
|
|
||||||
|
const detail = computed(() => current.value[currentStep.value])
|
||||||
|
|
||||||
|
const logText = computed(() => {
|
||||||
|
const logs = []
|
||||||
|
for (let i = 0; i < round.value; i++) {
|
||||||
|
logs.push(`--- Round ${i + 1} ---`)
|
||||||
|
logs.push(`OBS: ${scenarios[i].observe}`)
|
||||||
|
logs.push(`PLAN: ${scenarios[i].plan}`)
|
||||||
|
logs.push(`ACT: ${scenarios[i].act}`)
|
||||||
|
logs.push(`CHECK: ${scenarios[i].check}`)
|
||||||
|
logs.push('')
|
||||||
|
}
|
||||||
|
return logs.join('\n')
|
||||||
|
})
|
||||||
|
|
||||||
|
const nextRound = () => {
|
||||||
|
if (round.value >= 3) return
|
||||||
|
round.value++
|
||||||
|
currentStep.value = 'observe'
|
||||||
|
}
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
round.value = 1
|
||||||
|
currentStep.value = 'observe'
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.workflow {
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
padding: 16px;
|
||||||
|
margin: 20px 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
.subtitle {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.btn {
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.btn.primary {
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
color: var(--vp-c-brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cycle {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
.step {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.step.active {
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
border-radius: 6px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
}
|
||||||
|
.name {
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panels {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.panel {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
.panel-title {
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
.panel-body {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px dashed var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
.log-title {
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
margin: 0;
|
||||||
|
background: #0b1221;
|
||||||
|
color: #e5e7eb;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 12px;
|
||||||
|
font-family: var(--vp-font-family-mono);
|
||||||
|
font-size: 13px;
|
||||||
|
overflow-x: auto;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
<!--
|
||||||
|
FrameworkComparisonDemo.vue
|
||||||
|
框架对比(更直观):选择关注点,表格高亮适配度。
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div class="cmp">
|
||||||
|
<div class="header">
|
||||||
|
<div>
|
||||||
|
<div class="title">
|
||||||
|
主流框架对比(先看“适配度”)
|
||||||
|
</div>
|
||||||
|
<div class="subtitle">
|
||||||
|
先选你的关注点,再看推荐。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="focus">
|
||||||
|
<button
|
||||||
|
v-for="f in focuses"
|
||||||
|
:key="f.id"
|
||||||
|
:class="['chip', { active: focus === f.id }]"
|
||||||
|
@click="focus = f.id"
|
||||||
|
>
|
||||||
|
{{ f.label }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table">
|
||||||
|
<div class="row head">
|
||||||
|
<div>框架</div>
|
||||||
|
<div>上手</div>
|
||||||
|
<div>可控</div>
|
||||||
|
<div>多 Agent</div>
|
||||||
|
<div>适合做什么</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-for="fw in frameworks"
|
||||||
|
:key="fw.name"
|
||||||
|
:class="['row', { best: fw.name === best }]"
|
||||||
|
>
|
||||||
|
<div class="name">
|
||||||
|
{{ fw.name }}
|
||||||
|
</div>
|
||||||
|
<div>{{ fw.learn }}</div>
|
||||||
|
<div>{{ fw.control }}</div>
|
||||||
|
<div>{{ fw.multi }}</div>
|
||||||
|
<div class="use">
|
||||||
|
{{ fw.use }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="rec">
|
||||||
|
<div class="rec-title">
|
||||||
|
此刻更推荐:{{ best }}
|
||||||
|
</div>
|
||||||
|
<div class="rec-body">
|
||||||
|
{{ reason }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
|
||||||
|
const focuses = [
|
||||||
|
{ id: 'start', label: '快速上手' },
|
||||||
|
{ id: 'control', label: '可控可调试' },
|
||||||
|
{ id: 'team', label: '多 Agent 协作' }
|
||||||
|
]
|
||||||
|
|
||||||
|
const focus = ref('control')
|
||||||
|
|
||||||
|
const frameworks = [
|
||||||
|
{
|
||||||
|
name: 'LangChain / LangGraph',
|
||||||
|
learn: '中',
|
||||||
|
control: '高',
|
||||||
|
multi: '中',
|
||||||
|
use: '可控的工具调用、工作流、企业集成'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'AutoGen',
|
||||||
|
learn: '中',
|
||||||
|
control: '中',
|
||||||
|
multi: '高',
|
||||||
|
use: '多 Agent 对话协作、编程/分析助手'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'CrewAI',
|
||||||
|
learn: '低',
|
||||||
|
control: '中',
|
||||||
|
multi: '高',
|
||||||
|
use: '角色分工清晰的团队协作任务'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const best = computed(() => {
|
||||||
|
if (focus.value === 'start') return 'CrewAI'
|
||||||
|
if (focus.value === 'team') return 'AutoGen'
|
||||||
|
return 'LangChain / LangGraph'
|
||||||
|
})
|
||||||
|
|
||||||
|
const reason = computed(() => {
|
||||||
|
if (focus.value === 'start')
|
||||||
|
return '概念更直观(角色+任务),适合先跑通一个最小团队。'
|
||||||
|
if (focus.value === 'team')
|
||||||
|
return '多 Agent 对话与协作是强项,适合需要分工的场景。'
|
||||||
|
return '把流程“画成图/写成步骤”,更利于调试、上线与长期维护。'
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.cmp {
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
padding: 16px;
|
||||||
|
margin: 20px 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
.subtitle {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.focus {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.chip {
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.chip.active {
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
color: var(--vp-c-brand);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1.4fr 0.8fr 0.8fr 0.9fr 2.1fr;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
border-top: 1px solid var(--vp-c-divider);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.row.head {
|
||||||
|
border-top: none;
|
||||||
|
font-weight: 800;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
}
|
||||||
|
.name {
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
.use {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
}
|
||||||
|
.row.best {
|
||||||
|
outline: 2px solid var(--vp-c-brand);
|
||||||
|
outline-offset: -2px;
|
||||||
|
background: rgba(0, 0, 0, 0.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rec {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px dashed var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
.rec-title {
|
||||||
|
font-weight: 800;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
.rec-body {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
<!--
|
||||||
|
FrameworkSelectionDemo.vue
|
||||||
|
框架选择小向导:回答 3 个问题,给出推荐 + 适配理由 + 你需要注意什么。
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div class="sel">
|
||||||
|
<div class="header">
|
||||||
|
<div>
|
||||||
|
<div class="title">
|
||||||
|
三问选框架
|
||||||
|
</div>
|
||||||
|
<div class="subtitle">
|
||||||
|
目标:先跑通一个最小 Agent,再逐步增强。
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="q">
|
||||||
|
<div class="q-title">
|
||||||
|
1) 你更在乎什么?
|
||||||
|
</div>
|
||||||
|
<div class="opts">
|
||||||
|
<button
|
||||||
|
v-for="o in q1"
|
||||||
|
:key="o.id"
|
||||||
|
:class="['opt', { active: a1 === o.id }]"
|
||||||
|
@click="a1 = o.id"
|
||||||
|
>
|
||||||
|
{{ o.label }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="q">
|
||||||
|
<div class="q-title">
|
||||||
|
2) 你的任务像哪种?
|
||||||
|
</div>
|
||||||
|
<div class="opts">
|
||||||
|
<button
|
||||||
|
v-for="o in q2"
|
||||||
|
:key="o.id"
|
||||||
|
:class="['opt', { active: a2 === o.id }]"
|
||||||
|
@click="a2 = o.id"
|
||||||
|
>
|
||||||
|
{{ o.label }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="q">
|
||||||
|
<div class="q-title">
|
||||||
|
3) 需要多 Agent 分工吗?
|
||||||
|
</div>
|
||||||
|
<div class="opts">
|
||||||
|
<button
|
||||||
|
v-for="o in q3"
|
||||||
|
:key="o.id"
|
||||||
|
:class="['opt', { active: a3 === o.id }]"
|
||||||
|
@click="a3 = o.id"
|
||||||
|
>
|
||||||
|
{{ o.label }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="result">
|
||||||
|
<div class="r-title">
|
||||||
|
推荐:{{ rec.name }}
|
||||||
|
</div>
|
||||||
|
<div class="r-body">
|
||||||
|
{{ rec.reason }}
|
||||||
|
</div>
|
||||||
|
<div class="r-note">
|
||||||
|
<strong>注意:</strong>{{ rec.note }}
|
||||||
|
</div>
|
||||||
|
<div class="r-next">
|
||||||
|
<strong>下一步:</strong>{{ rec.next }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
|
||||||
|
const q1 = [
|
||||||
|
{ id: 'easy', label: '快速上手' },
|
||||||
|
{ id: 'stable', label: '可控可上线' },
|
||||||
|
{ id: 'team', label: '团队协作' }
|
||||||
|
]
|
||||||
|
const q2 = [
|
||||||
|
{ id: 'workflow', label: '有明确流程(步骤/图)' },
|
||||||
|
{ id: 'chat', label: '偏对话与协商' },
|
||||||
|
{ id: 'explore', label: '探索式试错' }
|
||||||
|
]
|
||||||
|
const q3 = [
|
||||||
|
{ id: 'no', label: '不需要' },
|
||||||
|
{ id: 'maybe', label: '可能需要' },
|
||||||
|
{ id: 'yes', label: '必须需要' }
|
||||||
|
]
|
||||||
|
|
||||||
|
const a1 = ref('stable')
|
||||||
|
const a2 = ref('workflow')
|
||||||
|
const a3 = ref('maybe')
|
||||||
|
|
||||||
|
const rec = computed(() => {
|
||||||
|
// Multi-agent first
|
||||||
|
if (a3.value === 'yes' || a1.value === 'team') {
|
||||||
|
if (a2.value === 'chat') {
|
||||||
|
return {
|
||||||
|
name: 'AutoGen',
|
||||||
|
reason: '多 Agent 对话协作是强项,适合“互相讨论、分工协作”。',
|
||||||
|
note: '先把角色边界写清楚,否则容易重复劳动或互怼。',
|
||||||
|
next: '从 2 个 Agent 开始:研究员 + 执行者。'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
name: 'CrewAI',
|
||||||
|
reason: '角色+任务模型很直观,适合“分工明确”的团队工作流。',
|
||||||
|
note: '先把输入/输出格式定死,避免多人输出难合并。',
|
||||||
|
next: '先搭 2-3 个角色:Researcher/Writer/Reviewer。'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Single-agent / controllable workflow
|
||||||
|
if (a1.value === 'stable' || a2.value === 'workflow') {
|
||||||
|
return {
|
||||||
|
name: 'LangChain / LangGraph',
|
||||||
|
reason: '更适合把 Agent 写成“可控流程”,便于调试、上线、加护栏。',
|
||||||
|
note: '别一上来做大系统,先把 1 个工具调用跑通。',
|
||||||
|
next: '用 LangGraph 画一个 3-5 节点的小图。'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Easy start
|
||||||
|
return {
|
||||||
|
name: 'CrewAI',
|
||||||
|
reason: '上手快、概念直观,适合先做出一个“能跑”的 demo。',
|
||||||
|
note: 'demo 能跑不代表可上线,后续要补安全与可观测。',
|
||||||
|
next: '先做一个“研究+写作”的最小团队。'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.sel {
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
padding: 16px;
|
||||||
|
margin: 20px 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
.subtitle {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.q {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
.q-title {
|
||||||
|
font-weight: 800;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.opts {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.opt {
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.opt.active {
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
color: var(--vp-c-brand);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.result {
|
||||||
|
background: var(--vp-c-bg);
|
||||||
|
border: 1px dashed var(--vp-c-divider);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
.r-title {
|
||||||
|
font-weight: 900;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
.r-body {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
line-height: 1.6;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
.r-note,
|
||||||
|
.r-next {
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
<template>
|
||||||
|
<div class="demo-card">
|
||||||
|
<div class="era-container">
|
||||||
|
<div class="era-header">
|
||||||
|
{{ t('erasComparison.header') }}
|
||||||
|
</div>
|
||||||
|
<div class="era-grid">
|
||||||
|
<div v-for="(era, i) in localEras" :key="i" class="era-item" :style="{ borderTopColor: eraStyles[i]?.color }">
|
||||||
|
<div class="e-icon" :style="{ background: eraStyles[i]?.color }">{{ eraStyles[i]?.icon }}</div>
|
||||||
|
<div class="e-name" :style="{ color: eraStyles[i]?.color }">{{ era.name }}</div>
|
||||||
|
<div class="e-time">{{ era.time }}</div>
|
||||||
|
|
||||||
|
<div class="e-section">
|
||||||
|
<div class="e-label">{{ t('erasComparison.driverLabel') }}</div>
|
||||||
|
<div class="e-value">{{ era.driver }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="e-section">
|
||||||
|
<div class="e-label">{{ t('erasComparison.mechanismLabel') }}</div>
|
||||||
|
<div class="e-value">
|
||||||
|
<span class="highlight">{{ era.mechanism }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="e-section">
|
||||||
|
<div class="e-label">{{ t('erasComparison.examplesLabel') }}</div>
|
||||||
|
<div class="e-tags">
|
||||||
|
<span v-for="tag in era.examples" :key="tag" class="e-tag">{{ tag }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { useI18n } from '../../../composables/useI18n.js'
|
||||||
|
import { aiHistoryLocale } from '../../../locales/ai-history/index.js'
|
||||||
|
|
||||||
|
const { t, messages } = useI18n(aiHistoryLocale)
|
||||||
|
const localEras = computed(() => messages.value.erasComparison?.eras ?? [])
|
||||||
|
|
||||||
|
const eraStyles = [
|
||||||
|
{ icon: '📜', color: '#059669' },
|
||||||
|
{ icon: '📊', color: '#d97706' },
|
||||||
|
{ icon: '🧠', color: '#dc2626' },
|
||||||
|
{ icon: '💬', color: '#7c3aed' },
|
||||||
|
{ icon: '🤖', color: '#0284c7' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.demo-card { border: 1px solid var(--vp-c-divider); border-radius: 8px; background: var(--vp-c-bg-soft); padding: 1.25rem; margin: 1.5rem 0; overflow-x: auto; }
|
||||||
|
.era-container { min-width: 800px; display: flex; flex-direction: column; gap: 1rem; }
|
||||||
|
.era-header { text-align: center; font-weight: bold; font-size: 1.1rem; color: var(--vp-c-text-1); margin-bottom: 0.5rem; }
|
||||||
|
|
||||||
|
.era-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 0.8rem; }
|
||||||
|
.era-item { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-top: 4px solid; border-radius: 8px; padding: 1rem; display: flex; flex-direction: column; align-items: center; text-align: center; gap: 0.8rem; }
|
||||||
|
|
||||||
|
.e-icon { width: 36px; height: 36px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 1.2rem; margin-bottom: 0.2rem; }
|
||||||
|
.e-name { font-weight: 800; font-size: 0.95rem; }
|
||||||
|
.e-time { font-size: 0.75rem; color: var(--vp-c-text-3); font-weight: bold; margin-top: -0.6rem; }
|
||||||
|
|
||||||
|
.e-section { width: 100%; display: flex; flex-direction: column; gap: 0.3rem; margin-top: 0.2rem; }
|
||||||
|
.e-label { font-size: 0.7rem; color: var(--vp-c-text-3); text-transform: uppercase; letter-spacing: 0.5px; }
|
||||||
|
.e-value { font-size: 0.8rem; color: var(--vp-c-text-2); line-height: 1.4; }
|
||||||
|
.highlight { display: inline-block; background: var(--vp-c-bg-soft); padding: 0.2rem 0.5rem; border-radius: 4px; font-weight: 600; color: var(--vp-c-text-1); border: 1px dashed var(--vp-c-divider); }
|
||||||
|
|
||||||
|
.e-tags { display: flex; flex-direction: column; gap: 0.4rem; align-items: center; justify-content: center; }
|
||||||
|
.e-tag { font-size: 0.75rem; background: var(--vp-c-bg-alt); border: 1px solid var(--vp-c-divider); color: var(--vp-c-text-1); padding: 0.25rem 0.6rem; border-radius: 12px; width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
|
.html.dark .highlight { background: var(--vp-c-bg-alt); }
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<template>
|
||||||
|
<div></div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<template>
|
||||||
|
<div class="demo-card">
|
||||||
|
<div class="timeline-visual">
|
||||||
|
<div v-for="(era, i) in eras" :key="i" class="era" :style="{ flex: era.flex, background: era.bg }">
|
||||||
|
<div class="era-label">{{ localeEras[i]?.label ?? era.label }}</div>
|
||||||
|
<div class="era-years">{{ localeEras[i]?.years ?? era.years }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="legend">
|
||||||
|
<span class="legend-item"><span class="dot" style="background:#059669"></span>{{ t('aiEvolution.legend.wave') }}</span>
|
||||||
|
<span class="legend-item"><span class="dot" style="background:#94a3b8"></span>{{ t('aiEvolution.legend.winter') }}</span>
|
||||||
|
<span class="legend-item"><span class="dot" style="background:#7c3aed"></span>{{ t('aiEvolution.legend.llm') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { useI18n } from '../../../composables/useI18n.js'
|
||||||
|
import { aiHistoryLocale } from '../../../locales/ai-history/index.js'
|
||||||
|
|
||||||
|
const { t, messages } = useI18n(aiHistoryLocale)
|
||||||
|
const localeEras = computed(() => messages.value.aiEvolution?.eras ?? [])
|
||||||
|
|
||||||
|
const eras = [
|
||||||
|
{ flex: 1.5, bg: 'linear-gradient(135deg, #dbeafe, #bfdbfe)' },
|
||||||
|
{ flex: 1.5, bg: 'linear-gradient(135deg, #d1fae5, #a7f3d0)' },
|
||||||
|
{ flex: 0.7, bg: 'linear-gradient(135deg, #e2e8f0, #cbd5e1)' },
|
||||||
|
{ flex: 1, bg: 'linear-gradient(135deg, #d1fae5, #a7f3d0)' },
|
||||||
|
{ flex: 0.7, bg: 'linear-gradient(135deg, #e2e8f0, #cbd5e1)' },
|
||||||
|
{ flex: 1.5, bg: 'linear-gradient(135deg, #d1fae5, #6ee7b7)' },
|
||||||
|
{ flex: 1.2, bg: 'linear-gradient(135deg, #a7f3d0, #34d399)' },
|
||||||
|
{ flex: 1.2, bg: 'linear-gradient(135deg, #c4b5fd, #a78bfa)' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.demo-card { border: 1px solid var(--vp-c-divider); border-radius: 8px; background: var(--vp-c-bg-soft); padding: 1rem; margin: 1rem 0; }
|
||||||
|
.timeline-visual { display: flex; border-radius: 6px; overflow: hidden; border: 1px solid var(--vp-c-divider); min-height: 60px; }
|
||||||
|
.era { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 0.4rem 0.2rem; text-align: center; border-right: 1px solid rgba(255,255,255,0.4); }
|
||||||
|
.era:last-child { border-right: none; }
|
||||||
|
.era-label { font-size: 0.65rem; font-weight: bold; color: #1e293b; line-height: 1.2; }
|
||||||
|
.era-years { font-size: 0.55rem; color: #475569; margin-top: 0.15rem; }
|
||||||
|
.legend { display: flex; gap: 1rem; margin-top: 0.6rem; flex-wrap: wrap; }
|
||||||
|
.legend-item { display: flex; align-items: center; gap: 0.3rem; font-size: 0.72rem; color: var(--vp-c-text-2); }
|
||||||
|
.dot { width: 8px; height: 8px; border-radius: 2px; }
|
||||||
|
@media (max-width: 640px) { .era-label { font-size: 0.58rem; } .era-years { display: none; } }
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
<template>
|
||||||
|
<div class="demo-card">
|
||||||
|
<div class="attention-layout">
|
||||||
|
<div class="sentence-col">
|
||||||
|
<div class="col-label" v-html="colLabel"></div>
|
||||||
|
<div class="sentence-box">
|
||||||
|
<span v-for="(word, i) in sentence" :key="i" class="word-token" :class="{ focus: i === focusIdx }">{{ word }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bars-col">
|
||||||
|
<div v-for="(item, i) in weights" :key="i" class="attention-item">
|
||||||
|
<span class="bar-word" :class="{ focus: i === focusIdx }">{{ item.word }}</span>
|
||||||
|
<div class="bar-bg">
|
||||||
|
<div class="bar-fill" :style="{ width: item.w * 100 + '%', background: barColor(item.w) }"></div>
|
||||||
|
</div>
|
||||||
|
<span class="bar-pct">{{ Math.round(item.w * 100) }}%</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="caption">
|
||||||
|
{{ t('attention.caption') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { useI18n } from '../../../composables/useI18n.js'
|
||||||
|
import { aiHistoryLocale } from '../../../locales/ai-history/index.js'
|
||||||
|
|
||||||
|
const { t, messages } = useI18n(aiHistoryLocale)
|
||||||
|
|
||||||
|
const attnData = computed(() => messages.value.attention ?? {})
|
||||||
|
const sentence = computed(() => attnData.value.sentence ?? [])
|
||||||
|
const focusIdx = computed(() => attnData.value.focusIdx ?? 4)
|
||||||
|
const rawWeights = computed(() => attnData.value.weights ?? [])
|
||||||
|
const weights = computed(() => sentence.value.map((word, i) => ({ word, w: rawWeights.value[i] ?? 0 })))
|
||||||
|
const focusWord = computed(() => sentence.value[focusIdx.value] ?? '')
|
||||||
|
const colLabel = computed(() => (attnData.value.colLabel ?? '').replace('{word}', focusWord.value))
|
||||||
|
|
||||||
|
const barColor = (v) => v > 0.5 ? '#dc2626' : v > 0.15 ? '#d97706' : v > 0.06 ? '#059669' : 'var(--vp-c-divider)'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.demo-card { border: 1px solid var(--vp-c-divider); border-radius: 8px; background: var(--vp-c-bg-soft); padding: 1.25rem; margin: 1rem 0; }
|
||||||
|
.attention-layout { display: grid; grid-template-columns: 1fr 1.3fr; gap: 1rem; background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-radius: 6px; padding: 0.9rem; margin-bottom: 0.5rem; }
|
||||||
|
@media (max-width: 560px) { .attention-layout { grid-template-columns: 1fr; } }
|
||||||
|
.col-label { font-size: 0.76rem; color: var(--vp-c-text-2); margin-bottom: 0.5rem; font-weight: bold; }
|
||||||
|
.sentence-box { display: flex; flex-wrap: wrap; gap: 0.35rem; background: var(--vp-c-bg-alt); padding: 0.6rem; border-radius: 5px; border: 1px dashed var(--vp-c-divider); }
|
||||||
|
.word-token { font-size: 0.88rem; font-weight: bold; padding: 0.2rem 0.5rem; background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-radius: 4px; }
|
||||||
|
.word-token.focus { background: var(--vp-c-brand); color: white; border-color: var(--vp-c-brand); }
|
||||||
|
.bars-col { display: flex; flex-direction: column; gap: 0.3rem; justify-content: center; }
|
||||||
|
.attention-item { display: flex; align-items: center; gap: 0.4rem; }
|
||||||
|
.bar-word { width: 30px; text-align: right; font-size: 0.8rem; font-weight: bold; color: var(--vp-c-text-2); flex-shrink: 0; }
|
||||||
|
.bar-word.focus { color: var(--vp-c-brand); }
|
||||||
|
.bar-bg { flex: 1; height: 12px; background: var(--vp-c-bg-alt); border-radius: 6px; overflow: hidden; border: 1px solid var(--vp-c-divider); }
|
||||||
|
.bar-fill { height: 100%; border-radius: 6px; }
|
||||||
|
.bar-pct { font-size: 0.7rem; font-weight: bold; color: var(--vp-c-text-2); width: 30px; flex-shrink: 0; }
|
||||||
|
.caption { font-size: 0.75rem; color: var(--vp-c-text-3); text-align: center; }
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
<template>
|
||||||
|
<div class="demo-card">
|
||||||
|
<div class="bp-flow">
|
||||||
|
<div v-for="(step, i) in localSteps" :key="i" class="step-block" :style="{ borderTopColor: stepColors[i] }">
|
||||||
|
<div class="step-num" :style="{ background: stepColors[i] }">{{ i + 1 }}</div>
|
||||||
|
<div class="step-icon">{{ step.icon }}</div>
|
||||||
|
<div class="step-name">{{ step.name }}</div>
|
||||||
|
<div class="step-desc">{{ step.desc }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="loss-visual">
|
||||||
|
<div class="loss-label">{{ t('backprop.lossLabel') }}</div>
|
||||||
|
<svg viewBox="0 0 320 130" class="loss-svg">
|
||||||
|
<!-- Axes -->
|
||||||
|
<line x1="40" y1="110" x2="300" y2="110" stroke="var(--vp-c-text-3)" stroke-width="1.5" />
|
||||||
|
<line x1="40" y1="110" x2="40" y2="15" stroke="var(--vp-c-text-3)" stroke-width="1.5" />
|
||||||
|
|
||||||
|
<!-- X Arrow -->
|
||||||
|
<polygon points="300,107 305,110 300,113" fill="var(--vp-c-text-3)" />
|
||||||
|
<!-- Y Arrow -->
|
||||||
|
<polygon points="37,15 40,10 43,15" fill="var(--vp-c-text-3)" />
|
||||||
|
|
||||||
|
<!-- Y Label -->
|
||||||
|
<text x="30" y="25" text-anchor="end" class="ax-text">{{ t('backprop.axisHigh') }}</text>
|
||||||
|
<text x="30" y="105" text-anchor="end" class="ax-text">{{ t('backprop.axisLow') }}</text>
|
||||||
|
<text x="20" y="65" text-anchor="middle" transform="rotate(-90 20 65)" class="ax-title">Loss</text>
|
||||||
|
|
||||||
|
<!-- X Label -->
|
||||||
|
<text x="300" y="125" text-anchor="end" class="ax-title">{{ t('backprop.axisEpochs') }}</text>
|
||||||
|
|
||||||
|
<!-- Loss 曲线 -->
|
||||||
|
<polyline :points="lossPoints" fill="none" stroke="var(--vp-c-brand)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { useI18n } from '../../../composables/useI18n.js'
|
||||||
|
import { aiHistoryLocale } from '../../../locales/ai-history/index.js'
|
||||||
|
|
||||||
|
const { t, messages } = useI18n(aiHistoryLocale)
|
||||||
|
const localSteps = computed(() => messages.value.backprop?.steps ?? [])
|
||||||
|
|
||||||
|
const stepColors = ['#3b82f6', '#d97706', '#dc2626', '#059669']
|
||||||
|
const lossPoints = (() => {
|
||||||
|
const pts = []
|
||||||
|
for (let i = 0; i <= 50; i++) {
|
||||||
|
const x = 40 + i * 5; // 40 to 290
|
||||||
|
// Y从上(小值)到下(大值),Loss越来越低,意味着Y越来越大,靠近110
|
||||||
|
// 我们让一开始的高Loss出现在 y=20 附近,最终的低Loss停留 在 y=105 附近
|
||||||
|
let noise = (Math.random() - 0.5) * 3;
|
||||||
|
let y = 105 - 85 * Math.exp(-i * 0.12) + noise;
|
||||||
|
|
||||||
|
if (i === 0) y = 20; // 确保起点干净
|
||||||
|
if (y > 108) y = 108; // 不超过底轴
|
||||||
|
|
||||||
|
pts.push(`${x},${y}`)
|
||||||
|
}
|
||||||
|
return pts.join(' ')
|
||||||
|
})()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.demo-card { border: 1px solid var(--vp-c-divider); border-radius: 8px; background: var(--vp-c-bg-soft); padding: 1.25rem; margin: 1rem 0; }
|
||||||
|
.bp-flow { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.5rem; margin-bottom: 0.8rem; }
|
||||||
|
@media (max-width: 600px) { .bp-flow { grid-template-columns: repeat(2, 1fr); } }
|
||||||
|
.step-block { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-top: 3px solid; border-radius: 6px; padding: 0.7rem 0.5rem; display: flex; flex-direction: column; align-items: center; gap: 0.25rem; text-align: center; }
|
||||||
|
.step-num { width: 16px; height: 16px; border-radius: 50%; color: white; font-size: 0.6rem; font-weight: bold; display: flex; align-items: center; justify-content: center; }
|
||||||
|
.step-icon { font-size: 1.2rem; }
|
||||||
|
.step-name { font-weight: bold; font-size: 0.78rem; }
|
||||||
|
.step-desc { font-size: 0.68rem; color: var(--vp-c-text-2); line-height: 1.3; }
|
||||||
|
.loss-visual { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-radius: 6px; padding: 0.7rem; }
|
||||||
|
.loss-label { font-size: 0.75rem; color: var(--vp-c-text-2); margin-bottom: 0.3rem; }
|
||||||
|
.loss-svg { width: 100%; max-width: 460px; height: auto; display: block; margin: 0 auto; overflow: visible; font-family: sans-serif; }
|
||||||
|
.axis-line { color: var(--vp-c-text-3); }
|
||||||
|
.ax-text { font-size: 10px; fill: var(--vp-c-text-2); }
|
||||||
|
.ax-title { font-size: 11px; fill: var(--vp-c-text-1); font-weight: 500; }
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
<template>
|
||||||
|
<div></div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<template>
|
||||||
|
<div class="demo-card">
|
||||||
|
<div class="schools-grid">
|
||||||
|
<div v-for="(s, i) in schoolStyles" :key="i" class="school-card" :style="{ borderTopColor: s.color }">
|
||||||
|
<div class="card-head">
|
||||||
|
<span class="school-icon">{{ s.icon }}</span>
|
||||||
|
<span class="school-name" :style="{ color: s.color }">{{ localeItems[i]?.name }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="school-idea">{{ localeItems[i]?.idea }}</div>
|
||||||
|
<div class="school-rep">{{ t('schools.repLabel') }}:{{ localeItems[i]?.rep }}</div>
|
||||||
|
<div class="school-status">{{ localeItems[i]?.status }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { useI18n } from '../../../composables/useI18n.js'
|
||||||
|
import { aiHistoryLocale } from '../../../locales/ai-history/index.js'
|
||||||
|
|
||||||
|
const { t, messages } = useI18n(aiHistoryLocale)
|
||||||
|
const localeItems = computed(() => messages.value.schools?.items ?? [])
|
||||||
|
|
||||||
|
const schoolStyles = [
|
||||||
|
{ icon: '📜', color: '#059669' },
|
||||||
|
{ icon: '🧠', color: '#7c3aed' },
|
||||||
|
{ icon: '🎮', color: '#d97706' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.demo-card { border: 1px solid var(--vp-c-divider); border-radius: 8px; background: var(--vp-c-bg-soft); padding: 1.25rem; margin: 1rem 0; }
|
||||||
|
.schools-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.7rem; }
|
||||||
|
@media (max-width: 640px) { .schools-grid { grid-template-columns: 1fr; } }
|
||||||
|
.school-card { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-top: 3px solid; border-radius: 6px; padding: 0.9rem; display: flex; flex-direction: column; gap: 0.4rem; }
|
||||||
|
.card-head { display: flex; align-items: center; gap: 0.5rem; }
|
||||||
|
.school-icon { font-size: 1.3rem; }
|
||||||
|
.school-name { font-weight: bold; font-size: 0.9rem; }
|
||||||
|
.school-idea { font-size: 0.78rem; color: var(--vp-c-text-1); background: var(--vp-c-bg-alt); padding: 0.35rem 0.5rem; border-radius: 4px; }
|
||||||
|
.school-rep { font-size: 0.72rem; color: var(--vp-c-text-3); }
|
||||||
|
.school-status { font-size: 0.72rem; color: var(--vp-c-text-2); border-top: 1px dashed var(--vp-c-divider); padding-top: 0.35rem; }
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
<template>
|
||||||
|
<div class="demo-card">
|
||||||
|
<div class="expert-system-flow">
|
||||||
|
<div class="es-card success">
|
||||||
|
<div class="es-title">🌟 专家系统的辉煌</div>
|
||||||
|
<div class="es-list">
|
||||||
|
<div class="es-item">
|
||||||
|
<span class="es-box input">人类专家经验</span>
|
||||||
|
<span class="es-arrow">→</span>
|
||||||
|
<span class="es-box rules">转为 IF-THEN 规则库</span>
|
||||||
|
</div>
|
||||||
|
<div class="es-item">
|
||||||
|
<span class="es-box input">特定领域问题</span>
|
||||||
|
<span class="es-arrow">→</span>
|
||||||
|
<span class="es-box output">推理解答 (诊断/配置)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="es-tags">
|
||||||
|
<span class="es-tag">1965: Dendral (化学)</span>
|
||||||
|
<span class="es-tag">1977: MYCIN (医疗)</span>
|
||||||
|
<span class="es-tag">1980: XCON (配置)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="es-arrow-down">⬇️ 局限性爆发 ⬇️</div>
|
||||||
|
|
||||||
|
<div class="es-card winter">
|
||||||
|
<div class="es-title"><span class="snow">❄️</span> 第一次 AI 寒冬 (1974-1980)</div>
|
||||||
|
<div class="winter-reasons">
|
||||||
|
<div class="reason">
|
||||||
|
<span class="r-icon">📝</span>
|
||||||
|
<div class="r-text">
|
||||||
|
<strong>知识获取瓶颈</strong>
|
||||||
|
<span>波兰尼悖论:人类无法说清所有规律。大量"常识"无法被人工硬编码。</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="reason">
|
||||||
|
<span class="r-icon">💥</span>
|
||||||
|
<div class="r-text">
|
||||||
|
<strong>组合爆炸 & 脆性问题</strong>
|
||||||
|
<span>现实情况太多,穷举极难;且缺少常识,稍微偏离规则库系统就直接崩溃。</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="reason">
|
||||||
|
<span class="r-icon">📉</span>
|
||||||
|
<div class="r-text">
|
||||||
|
<strong>算力不足 & 经费断层</strong>
|
||||||
|
<span>当时的硬件算力根本无法支撑爆发性的逻辑推演,遭遇 DARPA 研发经费大削减。</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.demo-card { border: 1px solid var(--vp-c-divider); border-radius: 8px; background: var(--vp-c-bg-soft); padding: 1.25rem; margin: 1rem 0; }
|
||||||
|
.expert-system-flow { display: flex; flex-direction: column; align-items: center; gap: 0.8rem; }
|
||||||
|
.es-card { width: 100%; max-width: 500px; border: 1px solid var(--vp-c-divider); border-radius: 6px; padding: 1rem; background: var(--vp-c-bg); }
|
||||||
|
.es-card.success { border-top: 3px solid #059669; }
|
||||||
|
.es-card.winter { border-top: 3px solid #3b82f6; background: rgba(59, 130, 246, 0.03); }
|
||||||
|
.es-title { font-weight: bold; font-size: 0.9rem; margin-bottom: 0.8rem; text-align: center; color: var(--vp-c-text-1); }
|
||||||
|
.es-list { display: flex; flex-direction: column; gap: 0.6rem; margin-bottom: 1rem; }
|
||||||
|
.es-item { display: flex; align-items: center; justify-content: center; gap: 0.4rem; font-size: 0.75rem; }
|
||||||
|
.es-box { padding: 0.4rem 0.6rem; border-radius: 4px; font-weight: 500; border: 1px solid var(--vp-c-divider); text-align: center; }
|
||||||
|
.es-box.input { background: var(--vp-c-bg-soft); color: var(--vp-c-text-2); }
|
||||||
|
.es-box.rules { background: #d1fae5; color: #065f46; border-color: #34d399; }
|
||||||
|
.es-box.output { background: #e0e7ff; color: #3730a3; border-color: #818cf8; }
|
||||||
|
.html.dark .es-box.rules { background: rgba(5, 150, 105, 0.2); color: #a7f3d0; border-color: #059669; }
|
||||||
|
.html.dark .es-box.output { background: rgba(79, 70, 229, 0.2); color: #c7d2fe; border-color: #4f46e5; }
|
||||||
|
|
||||||
|
.es-arrow { color: var(--vp-c-text-3); font-weight: bold; }
|
||||||
|
.es-tags { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.5rem; }
|
||||||
|
.es-tag { font-size: 0.65rem; background: var(--vp-c-bg-soft); padding: 0.15rem 0.5rem; border-radius: 12px; color: var(--vp-c-text-2); border: 1px solid var(--vp-c-divider); }
|
||||||
|
.es-arrow-down { font-size: 0.8rem; color: var(--vp-c-text-3); font-weight: bold; margin: 0.2rem 0; }
|
||||||
|
.snow { color: #3b82f6; margin-right: 0.2rem; }
|
||||||
|
.winter-reasons { display: flex; flex-direction: column; gap: 0.6rem; }
|
||||||
|
.reason { display: flex; align-items: flex-start; gap: 0.6rem; background: var(--vp-c-bg-alt); padding: 0.6rem; border-radius: 6px; border: 1px solid var(--vp-c-divider); }
|
||||||
|
.r-icon { font-size: 1.2rem; margin-top: 0.1rem; }
|
||||||
|
.r-text { display: flex; flex-direction: column; }
|
||||||
|
.r-text strong { font-size: 0.8rem; color: var(--vp-c-text-1); }
|
||||||
|
.r-text span { font-size: 0.7rem; color: var(--vp-c-text-2); line-height: 1.4; margin-top: 0.15rem; }
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
<template>
|
||||||
|
<div class="demo-card">
|
||||||
|
<div class="demo-label">{{ t('foundation.label') }}</div>
|
||||||
|
<div class="code-block">
|
||||||
|
<div v-for="(line, i) in foundationLines" :key="i" class="code-line" :class="{ indent: line.indent }">
|
||||||
|
<template v-for="(p, j) in line.parts" :key="j">
|
||||||
|
<span v-if="p.kw" class="kw">{{ p.kw }}</span>
|
||||||
|
<span v-else-if="p.str" class="str">{{ p.str }}</span>
|
||||||
|
<template v-else>{{ p.text }}</template>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div class="code-line comment">{{ t('foundation.comment') }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="demo-caption">{{ t('foundation.caption') }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { useI18n } from '../../../composables/useI18n.js'
|
||||||
|
import { aiHistoryLocale } from '../../../locales/ai-history/index.js'
|
||||||
|
|
||||||
|
const { t, messages } = useI18n(aiHistoryLocale)
|
||||||
|
const foundationLines = computed(() => messages.value.foundation?.lines ?? [])
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.demo-card {
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
padding: 1rem 1.2rem;
|
||||||
|
margin: 1rem 0;
|
||||||
|
}
|
||||||
|
.demo-label {
|
||||||
|
font-size: 0.78rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--vp-c-text-2);
|
||||||
|
margin-bottom: 0.6rem;
|
||||||
|
letter-spacing: 0.2px;
|
||||||
|
}
|
||||||
|
.code-block {
|
||||||
|
background: #1e1e2e;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 0.9rem 1.1rem;
|
||||||
|
font-family: 'JetBrains Mono', 'Fira Code', monospace;
|
||||||
|
font-size: 0.82rem;
|
||||||
|
line-height: 1.85;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.05rem;
|
||||||
|
}
|
||||||
|
.code-line { color: #cdd6f4; white-space: nowrap; overflow-x: auto; }
|
||||||
|
.code-line.indent { padding-left: 2rem; }
|
||||||
|
.kw { color: #89b4fa; font-weight: bold; } /* blue – keywords */
|
||||||
|
.str { color: #a6e3a1; } /* green – strings */
|
||||||
|
.comment { color: #585b70; font-size: 0.75rem; margin-top: 0.4rem; font-style: italic; }
|
||||||
|
.demo-caption {
|
||||||
|
font-size: 0.72rem;
|
||||||
|
color: var(--vp-c-text-3);
|
||||||
|
margin-top: 0.6rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<template>
|
||||||
|
<div class="demo-card">
|
||||||
|
<div class="gpt-grid">
|
||||||
|
<div v-for="(m, i) in models" :key="i" class="gpt-card" :style="{ borderTopColor: modelColors[i] }">
|
||||||
|
<div class="card-top">
|
||||||
|
<span class="gpt-name" :style="{ color: modelColors[i] }">{{ m.name }}</span>
|
||||||
|
<span class="gpt-year">{{ m.year }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="param-val">{{ m.params }}</div>
|
||||||
|
<div class="param-bar-bg">
|
||||||
|
<div class="param-bar" :style="{ width: m.barWidth, background: modelColors[i] }"></div>
|
||||||
|
</div>
|
||||||
|
<div class="gpt-key">{{ m.key }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { useI18n } from '../../../composables/useI18n.js'
|
||||||
|
import { aiHistoryLocale } from '../../../locales/ai-history/index.js'
|
||||||
|
|
||||||
|
const { messages } = useI18n(aiHistoryLocale)
|
||||||
|
const models = computed(() => messages.value.gptEvolution ?? [])
|
||||||
|
|
||||||
|
const modelColors = ['#94a3b8', '#3b82f6', '#7c3aed', '#dc2626']
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.demo-card { border: 1px solid var(--vp-c-divider); border-radius: 8px; background: var(--vp-c-bg-soft); padding: 1.25rem; margin: 1rem 0; }
|
||||||
|
.gpt-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.5rem; }
|
||||||
|
@media (max-width: 640px) { .gpt-grid { grid-template-columns: repeat(2, 1fr); } }
|
||||||
|
.gpt-card { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-top: 3px solid; border-radius: 6px; padding: 0.7rem; display: flex; flex-direction: column; gap: 0.35rem; }
|
||||||
|
.card-top { display: flex; justify-content: space-between; }
|
||||||
|
.gpt-name { font-weight: bold; font-size: 0.88rem; }
|
||||||
|
.gpt-year { font-size: 0.68rem; color: var(--vp-c-text-3); }
|
||||||
|
.param-val { font-size: 0.78rem; font-weight: bold; font-family: monospace; color: var(--vp-c-text-1); }
|
||||||
|
.param-bar-bg { height: 6px; background: var(--vp-c-bg-alt); border-radius: 3px; overflow: hidden; }
|
||||||
|
.param-bar { height: 100%; border-radius: 3px; min-width: 3px; }
|
||||||
|
.gpt-key { font-size: 0.7rem; color: var(--vp-c-brand-1); background: var(--vp-c-brand-soft); padding: 0.15rem 0.4rem; border-radius: 3px; }
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
<template>
|
||||||
|
<div class="demo-card">
|
||||||
|
<div class="net-layout">
|
||||||
|
<div class="svg-wrap">
|
||||||
|
<svg viewBox="0 0 380 200" class="net-svg">
|
||||||
|
<line v-for="c in connections" :key="c.id" :x1="c.x1" :y1="c.y1" :x2="c.x2" :y2="c.y2" stroke="#94a3b8" stroke-width="1.2" opacity="0.35" />
|
||||||
|
<g v-for="layer in layers" :key="layer.idx">
|
||||||
|
<circle v-for="n in layer.nodes" :key="n.id" :cx="n.x" :cy="n.y" r="15" :fill="layer.fill" :stroke="layer.stroke" stroke-width="2" />
|
||||||
|
</g>
|
||||||
|
<text v-for="(layer, i) in layers" :key="'l-'+layer.idx" :x="layer.x" y="194" text-anchor="middle" :fill="layer.stroke" class="lbl">{{ localLayers[i]?.name }}</text>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class="layer-cards">
|
||||||
|
<div v-for="(info, i) in localLayers" :key="i" class="layer-card" :style="{ borderLeftColor: layerColors[i]?.color }">
|
||||||
|
<div class="lc-title" :style="{ color: layerColors[i]?.color }">{{ info.name }}</div>
|
||||||
|
<div class="lc-desc">{{ info.desc }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { useI18n } from '../../../composables/useI18n.js'
|
||||||
|
import { aiHistoryLocale } from '../../../locales/ai-history/index.js'
|
||||||
|
|
||||||
|
const { messages } = useI18n(aiHistoryLocale)
|
||||||
|
const localLayers = computed(() => messages.value.neuralNet?.layers ?? [])
|
||||||
|
|
||||||
|
const W = 380, H = 185
|
||||||
|
const layerColors = [
|
||||||
|
{ color: '#3b82f6', fill: '#dbeafe' },
|
||||||
|
{ color: '#7c3aed', fill: '#ede9fe' },
|
||||||
|
{ color: '#059669', fill: '#d1fae5' },
|
||||||
|
]
|
||||||
|
const layerCounts = [3, 4, 2]
|
||||||
|
const xFracs = [0.13, 0.5, 0.87]
|
||||||
|
|
||||||
|
const layers = layerColors.map((l, idx) => {
|
||||||
|
const x = xFracs[idx] * W
|
||||||
|
const count = layerCounts[idx]
|
||||||
|
const gap = Math.min(46, (H - 36) / (count - 1 || 1))
|
||||||
|
const startY = (H - gap * (count - 1)) / 2
|
||||||
|
return { idx, x, fill: l.fill, stroke: l.color, nodes: Array.from({ length: count }, (_, i) => ({ id: `${idx}-${i}`, x, y: startY + i * gap })) }
|
||||||
|
})
|
||||||
|
const connections = []
|
||||||
|
for (let li = 0; li < layers.length - 1; li++) {
|
||||||
|
layers[li].nodes.forEach(a => { layers[li + 1].nodes.forEach(b => { connections.push({ id: `${a.id}-${b.id}`, x1: a.x, y1: a.y, x2: b.x, y2: b.y }) }) })
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.demo-card { border: 1px solid var(--vp-c-divider); border-radius: 8px; background: var(--vp-c-bg-soft); padding: 1.25rem; margin: 1rem 0; }
|
||||||
|
.net-layout { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-radius: 6px; padding: 0.9rem; }
|
||||||
|
@media (max-width: 600px) { .net-layout { grid-template-columns: 1fr; } }
|
||||||
|
.svg-wrap { display: flex; align-items: center; justify-content: center; background: var(--vp-c-bg-alt); border-radius: 6px; }
|
||||||
|
.net-svg { width: 100%; height: auto; }
|
||||||
|
.lbl { font-size: 9px; font-weight: bold; }
|
||||||
|
.layer-cards { display: flex; flex-direction: column; gap: 0.4rem; justify-content: center; }
|
||||||
|
.layer-card { border-left: 3px solid; padding: 0.5rem 0.7rem; background: var(--vp-c-bg-alt); border-radius: 0 5px 5px 0; }
|
||||||
|
.lc-title { font-weight: bold; font-size: 0.78rem; margin-bottom: 0.15rem; }
|
||||||
|
.lc-desc { font-size: 0.73rem; color: var(--vp-c-text-2); line-height: 1.4; }
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<div class="demo-card">
|
||||||
|
<div class="perceptron-layout">
|
||||||
|
<div class="inputs-col">
|
||||||
|
<div v-for="(inp, i) in inputs" :key="i" class="input-node">
|
||||||
|
<span class="node-circle">{{ inp.val }}</span>
|
||||||
|
<span class="node-label">{{ featureLabels[i] }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="weights-col">
|
||||||
|
<div v-for="(inp, i) in inputs" :key="i" class="weight-arrow">
|
||||||
|
<span class="arrow">→</span>
|
||||||
|
<span class="w-tag">×{{ inp.weight }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="neuron-col">
|
||||||
|
<div class="neuron-circle">
|
||||||
|
<div class="n-sym">Σ</div>
|
||||||
|
<div class="n-val">{{ sum }}</div>
|
||||||
|
</div>
|
||||||
|
<span class="bias-tag">{{ t('perceptron.biasLabel') }} {{ bias }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="act-col">
|
||||||
|
<span class="arrow big">→</span>
|
||||||
|
<div class="act-box">sum > 0 ?</div>
|
||||||
|
<span class="arrow big">→</span>
|
||||||
|
</div>
|
||||||
|
<div class="output-col">
|
||||||
|
<div class="output-node" :class="{ on: output === 1 }">
|
||||||
|
<span class="out-val">{{ output }}</span>
|
||||||
|
<span class="out-lbl">{{ output ? t('perceptron.activated') : t('perceptron.silent') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="caption">{{ t('perceptron.caption') }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { useI18n } from '../../../composables/useI18n.js'
|
||||||
|
import { aiHistoryLocale } from '../../../locales/ai-history/index.js'
|
||||||
|
|
||||||
|
const { t, messages } = useI18n(aiHistoryLocale)
|
||||||
|
const featureLabels = computed(() => messages.value.perceptron?.features ?? [])
|
||||||
|
|
||||||
|
const inputs = [{ val: 1, weight: 0.6 }, { val: 0, weight: 0.4 }]
|
||||||
|
const bias = -0.3
|
||||||
|
const sum = computed(() => Number((inputs.reduce((s, i) => s + i.val * i.weight, 0) + bias).toFixed(2)))
|
||||||
|
const output = computed(() => sum.value > 0 ? 1 : 0)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.demo-card { border: 1px solid var(--vp-c-divider); border-radius: 8px; background: var(--vp-c-bg-soft); padding: 1.25rem; margin: 1rem 0; }
|
||||||
|
.perceptron-layout { display: flex; align-items: center; justify-content: center; gap: 0.5rem; background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-radius: 6px; padding: 1.2rem 0.8rem; flex-wrap: wrap; }
|
||||||
|
.inputs-col, .weights-col, .neuron-col, .act-col, .output-col { display: flex; flex-direction: column; align-items: center; gap: 1rem; }
|
||||||
|
.input-node { display: flex; flex-direction: column; align-items: center; gap: 0.2rem; }
|
||||||
|
.node-circle { width: 40px; height: 40px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: bold; background: var(--vp-c-brand-soft); border: 2px solid var(--vp-c-brand); color: var(--vp-c-brand-1); }
|
||||||
|
.node-label { font-size: 0.62rem; color: var(--vp-c-text-2); }
|
||||||
|
.weight-arrow { display: flex; align-items: center; gap: 0.3rem; }
|
||||||
|
.arrow { color: var(--vp-c-text-3); font-size: 1.1rem; }
|
||||||
|
.arrow.big { font-size: 1.4rem; }
|
||||||
|
.w-tag { font-size: 0.72rem; font-weight: bold; font-family: monospace; background: var(--vp-c-bg-alt); border: 1px solid var(--vp-c-divider); padding: 0.1rem 0.4rem; border-radius: 4px; color: var(--vp-c-brand-1); }
|
||||||
|
.neuron-circle { width: 64px; height: 64px; border-radius: 50%; border: 3px solid var(--vp-c-brand); background: var(--vp-c-bg-alt); display: flex; flex-direction: column; align-items: center; justify-content: center; }
|
||||||
|
.n-sym { font-size: 1.2rem; font-weight: bold; color: var(--vp-c-brand); }
|
||||||
|
.n-val { font-size: 0.8rem; font-weight: bold; font-family: monospace; }
|
||||||
|
.bias-tag { font-size: 0.62rem; color: var(--vp-c-text-3); padding: 0.1rem 0.4rem; border: 1px dashed var(--vp-c-divider); border-radius: 4px; }
|
||||||
|
.act-col { flex-direction: row; }
|
||||||
|
.act-box { font-size: 0.72rem; font-family: monospace; background: var(--vp-c-bg-alt); border: 1px solid var(--vp-c-divider); border-radius: 6px; padding: 0.4rem 0.6rem; }
|
||||||
|
.output-node { width: 54px; height: 54px; border-radius: 50%; border: 2px solid var(--vp-c-divider); background: var(--vp-c-bg-alt); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.1rem; }
|
||||||
|
.output-node.on { border-color: #059669; background: rgba(5,150,105,0.08); }
|
||||||
|
.out-val { font-size: 1.3rem; font-weight: bold; }
|
||||||
|
.out-lbl { font-size: 0.58rem; color: var(--vp-c-text-2); }
|
||||||
|
.caption { font-size: 0.75rem; color: var(--vp-c-text-3); text-align: center; margin-top: 0.6rem; }
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<template>
|
||||||
|
<div class="demo-card">
|
||||||
|
<div class="demo-header">
|
||||||
|
<span class="title">关键发展路径总结</span>
|
||||||
|
</div>
|
||||||
|
<div class="path-flow">
|
||||||
|
<div v-for="(item, i) in path" :key="i" class="path-item">
|
||||||
|
<div class="path-card" :style="{ borderLeftColor: item.color }">
|
||||||
|
<div class="path-top">
|
||||||
|
<span class="path-icon" :style="{ background: item.color }">{{ i + 1 }}</span>
|
||||||
|
<div>
|
||||||
|
<div class="path-name">{{ item.name }}</div>
|
||||||
|
<div class="path-years">{{ item.years }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="path-desc">{{ item.desc }}</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="i < path.length - 1" class="path-connector">
|
||||||
|
<svg width="20" height="24" viewBox="0 0 20 24"><path d="M10 0 L10 18 L5 13 M10 18 L15 13" fill="none" stroke="var(--vp-c-text-3)" stroke-width="1.5" stroke-linecap="round" /></svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const path = [
|
||||||
|
{ name: '理论奠基', years: '1940s-1950s', desc: '图灵测试、达特茅斯会议,符号主义诞生', color: '#3b82f6' },
|
||||||
|
{ name: '符号主义主导', years: '1960s-1980s', desc: '专家系统兴起与两次 AI 寒冬', color: '#059669' },
|
||||||
|
{ name: '机器学习转型', years: '1990s-2000s', desc: '统计方法取代规则,连接主义复苏', color: '#d97706' },
|
||||||
|
{ name: '深度学习革命', years: '2010s', desc: 'AlexNet、AlphaGo、Transformer 架构,连接主义成为主流', color: '#dc2626' },
|
||||||
|
{ name: '大模型时代', years: '2018 至今', desc: 'GPT 系列、多模态融合,通用智能曙光初现', color: '#7c3aed' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.demo-card { border: 1px solid var(--vp-c-divider); border-radius: 8px; background: var(--vp-c-bg-soft); padding: 1.25rem; margin: 1rem 0; }
|
||||||
|
.demo-header { margin-bottom: 1rem; }
|
||||||
|
.demo-header .title { font-weight: bold; font-size: 1rem; }
|
||||||
|
.path-flow { display: flex; flex-direction: column; align-items: stretch; }
|
||||||
|
.path-item { display: flex; flex-direction: column; align-items: center; }
|
||||||
|
.path-card { background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider); border-left: 4px solid; border-radius: 0 8px 8px 0; padding: 0.8rem 1rem; width: 100%; }
|
||||||
|
.path-top { display: flex; align-items: center; gap: 0.7rem; margin-bottom: 0.35rem; }
|
||||||
|
.path-icon { width: 24px; height: 24px; border-radius: 50%; color: white; font-size: 0.72rem; font-weight: bold; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
|
||||||
|
.path-name { font-weight: bold; font-size: 0.9rem; color: var(--vp-c-text-1); }
|
||||||
|
.path-years { font-size: 0.72rem; color: var(--vp-c-text-3); font-weight: bold; }
|
||||||
|
.path-desc { font-size: 0.8rem; color: var(--vp-c-text-2); line-height: 1.4; padding-left: 2.2rem; }
|
||||||
|
.path-connector { display: flex; justify-content: center; padding: 0.15rem 0; }
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,245 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flow-demo">
|
||||||
|
<div class="header">
|
||||||
|
<div class="title">AI 应用请求处理流程</div>
|
||||||
|
<div class="subtitle">点击"发送请求",观察一次 AI 请求的完整生命周期</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="pipeline">
|
||||||
|
<div
|
||||||
|
v-for="(step, idx) in steps"
|
||||||
|
:key="step.id"
|
||||||
|
:class="['pipe-step', {
|
||||||
|
active: currentStep === idx,
|
||||||
|
done: currentStep > idx
|
||||||
|
}]"
|
||||||
|
>
|
||||||
|
<div class="step-icon">{{ currentStep > idx ? '✅' : step.icon }}</div>
|
||||||
|
<div class="step-info">
|
||||||
|
<div class="step-name">{{ step.name }}</div>
|
||||||
|
<div class="step-en">{{ step.en }}</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="idx < steps.length - 1" class="arrow">→</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="control-bar">
|
||||||
|
<button
|
||||||
|
v-if="!isRunning && currentStep < 0"
|
||||||
|
class="action-btn"
|
||||||
|
@click="startFlow"
|
||||||
|
>
|
||||||
|
▶ 发送请求
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
v-else-if="!isRunning && currentStep >= steps.length"
|
||||||
|
class="action-btn reset"
|
||||||
|
@click="resetFlow"
|
||||||
|
>
|
||||||
|
🔄 重置
|
||||||
|
</button>
|
||||||
|
<div v-else-if="isRunning" class="running-hint">
|
||||||
|
⏳ 处理中...
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="currentStep >= 0" class="detail-area">
|
||||||
|
<div class="detail-card">
|
||||||
|
<div class="detail-title">
|
||||||
|
{{ activeStep.icon }} {{ activeStep.name }}
|
||||||
|
</div>
|
||||||
|
<div class="detail-desc">{{ activeStep.detail }}</div>
|
||||||
|
|
||||||
|
<div class="io-section">
|
||||||
|
<div class="io-block">
|
||||||
|
<div class="io-label">输入</div>
|
||||||
|
<pre class="io-code"><code>{{ activeStep.input }}</code></pre>
|
||||||
|
</div>
|
||||||
|
<div class="io-block">
|
||||||
|
<div class="io-label">输出</div>
|
||||||
|
<pre class="io-code"><code>{{ activeStep.output }}</code></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="latency-bar">
|
||||||
|
<span class="latency-label">耗时</span>
|
||||||
|
<div class="latency-track">
|
||||||
|
<div
|
||||||
|
class="latency-fill"
|
||||||
|
:style="{ width: activeStep.latencyPct + '%' }"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span class="latency-val">{{ activeStep.latency }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="insight-bar">
|
||||||
|
<span class="insight-label">💡 关键洞察:</span>
|
||||||
|
<span class="insight-text">
|
||||||
|
AI 应用的请求链路比传统应用更长,模型推理通常占总耗时的 60-80%。
|
||||||
|
优化重点在于:Prompt 缓存、流式输出、异步处理。
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
|
||||||
|
const steps = [
|
||||||
|
{
|
||||||
|
id: 'input', icon: '👤', name: '用户输入', en: 'User Input',
|
||||||
|
detail: '用户通过自然语言输入请求。系统需要处理多种输入形式:文本、语音转文字、图片描述等。与传统应用的表单提交不同,输入是开放式的、非结构化的。',
|
||||||
|
input: '"帮我总结这篇文章的核心观点"',
|
||||||
|
output: '{ text: "帮我总结...", type: "text", lang: "zh" }',
|
||||||
|
latency: '~0ms', latencyPct: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'preprocess', icon: '🔧', name: '预处理', en: 'Preprocessing',
|
||||||
|
detail: '对用户输入进行清洗和增强:意图识别、关键词提取、上下文拼接、RAG 检索相关文档片段、构建完整的 Prompt。这一步决定了模型能获得多少有效信息。',
|
||||||
|
input: '{ text: "帮我总结...", context: [...历史对话] }',
|
||||||
|
output: '{ system_prompt: "你是...", user_prompt: "...", retrieved_docs: [...] }',
|
||||||
|
latency: '~200ms', latencyPct: 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'model', icon: '🧠', name: '模型推理', en: 'Model Inference',
|
||||||
|
detail: '将构建好的 Prompt 发送给大语言模型进行推理。这是整个链路中耗时最长的环节。模型会根据 Prompt 中的指令、上下文和检索到的知识,生成回答。',
|
||||||
|
input: '{ messages: [...], model: "gpt-4", temperature: 0.7 }',
|
||||||
|
output: '{ content: "这篇文章的核心观点有三个...", tokens: 256 }',
|
||||||
|
latency: '~2-8s', latencyPct: 75
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'postprocess', icon: '🛡️', name: '后处理', en: 'Post-processing',
|
||||||
|
detail: '对模型输出进行安全检查和格式化:内容审核过滤、幻觉检测、格式转换(Markdown 渲染)、引用来源标注、敏感信息脱敏等。',
|
||||||
|
input: '{ raw_output: "这篇文章的核心观点有三个..." }',
|
||||||
|
output: '{ safe: true, formatted: "## 核心观点\\n1. ...", sources: [...] }',
|
||||||
|
latency: '~100ms', latencyPct: 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'response', icon: '💬', name: '响应输出', en: 'Response',
|
||||||
|
detail: '将处理后的结果以流式方式返回给用户。前端逐步渲染 Markdown 内容,同时展示引用来源和置信度。用户可以在生成过程中随时中断或追问。',
|
||||||
|
input: '{ formatted: "## 核心观点\\n1. ...", stream: true }',
|
||||||
|
output: '用户看到逐字出现的回答 + 来源引用',
|
||||||
|
latency: '~50ms (首字节)', latencyPct: 5
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const currentStep = ref(-1)
|
||||||
|
const isRunning = ref(false)
|
||||||
|
|
||||||
|
const activeStep = computed(() => {
|
||||||
|
const idx = Math.min(currentStep.value, steps.length - 1)
|
||||||
|
return idx >= 0 ? steps[idx] : steps[0]
|
||||||
|
})
|
||||||
|
|
||||||
|
const startFlow = async () => {
|
||||||
|
isRunning.value = true
|
||||||
|
for (let i = 0; i < steps.length; i++) {
|
||||||
|
currentStep.value = i
|
||||||
|
await new Promise(r => setTimeout(r, 1200))
|
||||||
|
}
|
||||||
|
currentStep.value = steps.length
|
||||||
|
isRunning.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetFlow = () => {
|
||||||
|
currentStep.value = -1
|
||||||
|
isRunning.value = false
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.flow-demo {
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px; padding: 20px; margin: 20px 0;
|
||||||
|
}
|
||||||
|
.header { text-align: center; margin-bottom: 16px; }
|
||||||
|
.title {
|
||||||
|
font-size: 17px; font-weight: 700;
|
||||||
|
background: linear-gradient(120deg, #10b981, #3b82f6);
|
||||||
|
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
|
||||||
|
}
|
||||||
|
.subtitle { font-size: 12px; color: var(--vp-c-text-2); margin-top: 4px; }
|
||||||
|
|
||||||
|
.pipeline {
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
gap: 4px; flex-wrap: wrap; margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.pipe-step {
|
||||||
|
display: flex; align-items: center; gap: 6px;
|
||||||
|
padding: 8px 12px; border-radius: 8px;
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
background: var(--vp-c-bg); transition: all 0.3s;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.pipe-step.active {
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
background: var(--vp-c-brand-soft);
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
|
||||||
|
}
|
||||||
|
.pipe-step.done {
|
||||||
|
border-color: #86efac; background: #f0fdf4;
|
||||||
|
}
|
||||||
|
.step-icon { font-size: 18px; }
|
||||||
|
.step-name { font-weight: 600; font-size: 12px; }
|
||||||
|
.step-en { font-size: 10px; color: var(--vp-c-text-3); }
|
||||||
|
.arrow { color: var(--vp-c-text-3); font-size: 14px; margin: 0 2px; }
|
||||||
|
|
||||||
|
.control-bar { text-align: center; margin-bottom: 16px; }
|
||||||
|
.action-btn {
|
||||||
|
padding: 10px 28px; background: var(--vp-c-brand);
|
||||||
|
color: white; border: none; border-radius: 8px;
|
||||||
|
font-size: 13px; cursor: pointer; transition: background 0.2s;
|
||||||
|
}
|
||||||
|
.action-btn:hover { background: var(--vp-c-brand-dark); }
|
||||||
|
.action-btn.reset { background: #6b7280; }
|
||||||
|
.action-btn.reset:hover { background: #4b5563; }
|
||||||
|
.running-hint { color: var(--vp-c-brand); font-size: 13px; }
|
||||||
|
|
||||||
|
.detail-area { margin-bottom: 16px; }
|
||||||
|
.detail-card {
|
||||||
|
background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px; padding: 16px;
|
||||||
|
}
|
||||||
|
.detail-title { font-weight: 700; font-size: 15px; margin-bottom: 8px; }
|
||||||
|
.detail-desc {
|
||||||
|
color: var(--vp-c-text-2); font-size: 13px;
|
||||||
|
line-height: 1.7; margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.io-section {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||||
|
gap: 10px; margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.io-label { font-weight: 600; font-size: 11px; margin-bottom: 4px; color: var(--vp-c-text-2); }
|
||||||
|
.io-code {
|
||||||
|
margin: 0; background: #0b1221; color: #e5e7eb;
|
||||||
|
border-radius: 8px; padding: 10px;
|
||||||
|
font-family: var(--vp-font-family-mono);
|
||||||
|
font-size: 11px; overflow-x: auto; white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.latency-bar {
|
||||||
|
display: flex; align-items: center; gap: 10px;
|
||||||
|
}
|
||||||
|
.latency-label { font-size: 11px; font-weight: 600; color: var(--vp-c-text-2); }
|
||||||
|
.latency-track {
|
||||||
|
flex: 1; height: 8px; background: var(--vp-c-bg-soft);
|
||||||
|
border-radius: 4px; overflow: hidden;
|
||||||
|
}
|
||||||
|
.latency-fill {
|
||||||
|
height: 100%; border-radius: 4px;
|
||||||
|
background: var(--vp-c-brand); transition: width 0.5s;
|
||||||
|
}
|
||||||
|
.latency-val { font-size: 11px; font-weight: 600; min-width: 80px; text-align: right; }
|
||||||
|
|
||||||
|
.insight-bar {
|
||||||
|
padding: 12px 16px; background: var(--vp-c-brand-soft);
|
||||||
|
border-radius: 6px; font-size: 13px;
|
||||||
|
}
|
||||||
|
.insight-label { font-weight: 600; color: var(--vp-c-brand-dark); }
|
||||||
|
.insight-text { color: var(--vp-c-text-1); }
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,222 @@
|
|||||||
|
<template>
|
||||||
|
<div class="principle-demo">
|
||||||
|
<div class="header">
|
||||||
|
<div class="title">AI 原生设计原则</div>
|
||||||
|
<div class="subtitle">点击卡片,深入了解每条设计原则</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="principle-grid">
|
||||||
|
<div
|
||||||
|
v-for="p in principles"
|
||||||
|
:key="p.id"
|
||||||
|
:class="['principle-card', { active: selected === p.id }]"
|
||||||
|
@click="selected = p.id"
|
||||||
|
>
|
||||||
|
<div class="p-icon">{{ p.icon }}</div>
|
||||||
|
<div class="p-name">{{ p.name }}</div>
|
||||||
|
<div class="p-brief">{{ p.brief }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="selected" class="detail-panel">
|
||||||
|
<div class="detail-header">
|
||||||
|
<span>{{ currentPrinciple.icon }} {{ currentPrinciple.name }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="detail-body">
|
||||||
|
<div class="detail-desc">{{ currentPrinciple.detail }}</div>
|
||||||
|
|
||||||
|
<div class="example-section">
|
||||||
|
<div class="example-title">实践对比</div>
|
||||||
|
<div class="compare-grid">
|
||||||
|
<div class="compare-bad">
|
||||||
|
<div class="compare-label bad-label">❌ 反面示例</div>
|
||||||
|
<div class="compare-text">{{ currentPrinciple.bad }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="compare-good">
|
||||||
|
<div class="compare-label good-label">✅ 正确做法</div>
|
||||||
|
<div class="compare-text">{{ currentPrinciple.good }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="checklist">
|
||||||
|
<div class="checklist-title">检查清单</div>
|
||||||
|
<div
|
||||||
|
v-for="(item, idx) in currentPrinciple.checklist"
|
||||||
|
:key="idx"
|
||||||
|
:class="['check-item', { checked: checkedItems[selected]?.[idx] }]"
|
||||||
|
@click="toggleCheck(idx)"
|
||||||
|
>
|
||||||
|
<span class="check-box">
|
||||||
|
{{ checkedItems[selected]?.[idx] ? '☑' : '☐' }}
|
||||||
|
</span>
|
||||||
|
<span>{{ item }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, reactive } from 'vue'
|
||||||
|
|
||||||
|
const principles = [
|
||||||
|
{
|
||||||
|
id: 'graceful',
|
||||||
|
icon: '🛡️',
|
||||||
|
name: '优雅降级',
|
||||||
|
brief: 'AI 失败时,系统仍然可用',
|
||||||
|
detail: 'AI 模型可能超时、返回错误、产生幻觉。优雅降级意味着:当 AI 不可用时,系统应该有兜底方案,而不是直接崩溃。这是 AI 原生应用与玩具项目的分水岭。',
|
||||||
|
bad: '模型 API 超时后,页面显示空白错误页,用户只能刷新重试。',
|
||||||
|
good: '模型超时后,显示缓存的上一次回答或推荐相关文档,同时后台自动重试。',
|
||||||
|
checklist: [
|
||||||
|
'设置合理的 API 超时时间(通常 30-60s)',
|
||||||
|
'准备降级方案:缓存、规则引擎、人工转接',
|
||||||
|
'向用户透明地展示当前状态',
|
||||||
|
'记录失败日志用于后续优化'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'human',
|
||||||
|
icon: '🤝',
|
||||||
|
name: '人机协作',
|
||||||
|
brief: '关键决策由人类确认',
|
||||||
|
detail: 'AI 擅长生成和建议,但不应该在高风险场景中自主决策。人机协作(Human-in-the-Loop)模式让 AI 负责草稿和推荐,人类负责审核和确认。',
|
||||||
|
bad: 'AI 自动发送邮件给客户,内容未经人工审核,导致错误信息传播。',
|
||||||
|
good: 'AI 生成邮件草稿并高亮不确定的部分,用户审核修改后手动发送。',
|
||||||
|
checklist: [
|
||||||
|
'识别哪些操作是"高风险"的(发送、删除、支付)',
|
||||||
|
'高风险操作前必须有人工确认步骤',
|
||||||
|
'AI 输出标注置信度,低置信内容需人工复核',
|
||||||
|
'提供便捷的编辑和修改界面'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'transparent',
|
||||||
|
icon: '🔍',
|
||||||
|
name: '透明可解释',
|
||||||
|
brief: '让用户理解 AI 的推理过程',
|
||||||
|
detail: 'AI 不是黑盒魔法。用户需要知道 AI 为什么给出这个回答、依据了哪些信息、有多大把握。透明性建立信任,也帮助用户判断何时该相信 AI、何时该质疑。',
|
||||||
|
bad: 'AI 直接给出一个结论,没有任何解释或来源引用,用户无法判断可靠性。',
|
||||||
|
good: '回答附带推理过程、引用来源链接、置信度指示,用户可以追溯验证。',
|
||||||
|
checklist: [
|
||||||
|
'展示 AI 的推理链路或思考过程',
|
||||||
|
'标注信息来源和引用',
|
||||||
|
'显示置信度或不确定性指标',
|
||||||
|
'提供"为什么这样回答"的解释入口'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'feedback',
|
||||||
|
icon: '🔄',
|
||||||
|
name: '反馈闭环',
|
||||||
|
brief: '用户反馈驱动持续改进',
|
||||||
|
detail: '每一次用户交互都是改进的机会。通过收集用户对 AI 输出的评价(点赞/点踩、修改记录、追问模式),持续优化 Prompt、微调模型、改进检索策略。',
|
||||||
|
bad: 'AI 回答错误后,没有任何反馈渠道,同样的错误会反复出现。',
|
||||||
|
good: '用户可以标记错误回答,系统自动收集并用于优化 Prompt 和检索策略。',
|
||||||
|
checklist: [
|
||||||
|
'提供简单的反馈机制(👍👎 按钮)',
|
||||||
|
'记录用户的修改和追问作为隐式反馈',
|
||||||
|
'定期分析反馈数据,优化 Prompt 模板',
|
||||||
|
'建立 A/B 测试机制验证改进效果'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const selected = ref('graceful')
|
||||||
|
const checkedItems = reactive({})
|
||||||
|
|
||||||
|
const currentPrinciple = computed(() =>
|
||||||
|
principles.find(p => p.id === selected.value) || principles[0]
|
||||||
|
)
|
||||||
|
|
||||||
|
const toggleCheck = (idx) => {
|
||||||
|
if (!checkedItems[selected.value]) {
|
||||||
|
checkedItems[selected.value] = {}
|
||||||
|
}
|
||||||
|
checkedItems[selected.value][idx] = !checkedItems[selected.value][idx]
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.principle-demo {
|
||||||
|
background: var(--vp-c-bg-soft);
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px; padding: 20px; margin: 20px 0;
|
||||||
|
}
|
||||||
|
.header { text-align: center; margin-bottom: 16px; }
|
||||||
|
.title {
|
||||||
|
font-size: 17px; font-weight: 700;
|
||||||
|
background: linear-gradient(120deg, #ef4444, #f59e0b);
|
||||||
|
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
|
||||||
|
}
|
||||||
|
.subtitle { font-size: 12px; color: var(--vp-c-text-2); margin-top: 4px; }
|
||||||
|
|
||||||
|
.principle-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
||||||
|
gap: 10px; margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.principle-card {
|
||||||
|
background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 10px; padding: 14px; cursor: pointer;
|
||||||
|
transition: all 0.2s; text-align: center;
|
||||||
|
}
|
||||||
|
.principle-card:hover { background: var(--vp-c-bg-alt); }
|
||||||
|
.principle-card.active {
|
||||||
|
border-color: var(--vp-c-brand);
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
|
||||||
|
}
|
||||||
|
.p-icon { font-size: 24px; margin-bottom: 6px; }
|
||||||
|
.p-name { font-weight: 600; font-size: 13px; }
|
||||||
|
.p-brief { font-size: 11px; color: var(--vp-c-text-2); margin-top: 4px; }
|
||||||
|
|
||||||
|
.detail-panel {
|
||||||
|
background: var(--vp-c-bg); border: 1px solid var(--vp-c-divider);
|
||||||
|
border-radius: 12px; overflow: hidden;
|
||||||
|
}
|
||||||
|
.detail-header {
|
||||||
|
padding: 14px 16px; font-weight: 700; font-size: 15px;
|
||||||
|
border-bottom: 1px solid var(--vp-c-divider);
|
||||||
|
}
|
||||||
|
.detail-body { padding: 16px; }
|
||||||
|
.detail-desc {
|
||||||
|
color: var(--vp-c-text-2); font-size: 13px;
|
||||||
|
line-height: 1.7; margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-section { margin-bottom: 16px; }
|
||||||
|
.example-title { font-weight: 600; font-size: 13px; margin-bottom: 8px; }
|
||||||
|
.compare-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
.compare-bad, .compare-good {
|
||||||
|
padding: 12px; border-radius: 8px; font-size: 13px; line-height: 1.6;
|
||||||
|
}
|
||||||
|
.compare-bad { background: #fef2f2; border: 1px solid #fecaca; }
|
||||||
|
.compare-good { background: #f0fdf4; border: 1px solid #bbf7d0; }
|
||||||
|
.compare-label {
|
||||||
|
font-weight: 600; font-size: 11px; margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
.bad-label { color: #dc2626; }
|
||||||
|
.good-label { color: #16a34a; }
|
||||||
|
.compare-text { color: var(--vp-c-text-1); }
|
||||||
|
|
||||||
|
.checklist-title { font-weight: 600; font-size: 13px; margin-bottom: 8px; }
|
||||||
|
.check-item {
|
||||||
|
display: flex; align-items: center; gap: 8px;
|
||||||
|
padding: 8px 10px; border-radius: 6px; font-size: 13px;
|
||||||
|
cursor: pointer; transition: background 0.2s;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
.check-item:hover { background: var(--vp-c-bg-soft); }
|
||||||
|
.check-item.checked {
|
||||||
|
background: #f0fdf4; border-color: #bbf7d0;
|
||||||
|
text-decoration: line-through; color: var(--vp-c-text-3);
|
||||||
|
}
|
||||||
|
.check-box { font-size: 16px; flex-shrink: 0; }
|
||||||
|
</style>
|
||||||