Files
test-repo/docs/.vitepress/theme/components/appendix/api-intro/ApiConceptDemo.vue
T

396 lines
7.2 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="api-concept-demo">
<!-- 标题和说明 -->
<div class="demo-header">
<h3>🍽 API = 软件世界的"服务员"</h3>
<p class="subtitle">点击菜单项观察 API 如何传递请求</p>
</div>
<!-- 主场景 -->
<div class="scene-container">
<!-- 顾客区域 -->
<div class="customer-zone">
<div class="customer-avatar">👤</div>
<div class="menu">
<h4>菜单</h4>
<button
v-for="item in menuItems"
:key="item.id"
@click="orderDish(item)"
:disabled="isProcessing"
class="menu-item"
>
{{ item.name }}
</button>
</div>
</div>
<!-- API/服务员 -->
<div class="api-zone">
<div class="waiter" :class="{ 'moving': isProcessing }">
<div class="waiter-avatar">🧑💼</div>
<div class="api-label">API</div>
</div>
<div class="request-flow" v-if="currentRequest">
<div class="flow-arrow"></div>
<div class="request-info">
<div>请求: GET /{{ currentRequest }}</div>
</div>
</div>
</div>
<!-- 厨房/服务器区域 -->
<div class="kitchen-zone">
<div class="kitchen-avatar">👨🍳</div>
<div class="kitchen-label">服务器</div>
<div class="status" :class="statusClass">
{{ statusText }}
</div>
</div>
</div>
<!-- 对比演示 -->
<div class="comparison">
<button @click="showComparison = !showComparison">
{{ showComparison ? '隐藏' : '显示' }}对比 API vs API
</button>
<div v-if="showComparison" class="comparison-scene">
<div class="with-api">
<h4> API服务员</h4>
<div class="comparison-visual">
顾客 服务员 厨房
</div>
<p>秩序井然高效清晰</p>
</div>
<div class="without-api">
<h4> API直接冲进厨房</h4>
<div class="comparison-visual chaotic">
顾客 厨房 👷 厨房 👨🍳
</div>
<p>混乱不堪效率低下</p>
</div>
</div>
</div>
<!-- 关键点总结 -->
<div class="key-points">
<h4>💡 关键点</h4>
<ul>
<li>API 是软件之间的"服务员"</li>
<li>调用 API = 向服务员点餐</li>
<li>API 返回数据 = 服务员端菜上来</li>
<li>有了 API软件之间可以"对话"</li>
</ul>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const isProcessing = ref(false)
const currentRequest = ref(null)
const statusText = ref('空闲')
const showComparison = ref(false)
const menuItems = [
{ id: 1, name: '宫保鸡丁', endpoint: 'dishes/kungpao' },
{ id: 2, name: '鱼香肉丝', endpoint: 'dishes/yuxiang' },
{ id: 3, name: '麻婆豆腐', endpoint: 'dishes/mapo' }
]
const statusClass = computed(() => {
if (isProcessing.value) return 'processing'
return 'idle'
})
function orderDish(item) {
if (isProcessing.value) return
currentRequest.value = item.endpoint
isProcessing.value = true
statusText.value = '处理中...'
// 模拟 API 调用过程
setTimeout(() => {
statusText.value = '制作完成'
setTimeout(() => {
isProcessing.value = false
currentRequest.value = null
statusText.value = '空闲'
}, 1000)
}, 2000)
}
</script>
<style scoped>
.api-concept-demo {
border: 2px solid #e0e0e0;
border-radius: 12px;
padding: 24px;
background: linear-gradient(135deg, #f5f7fa 0%, #ffffff 100%);
}
.demo-header {
text-align: center;
margin-bottom: 24px;
}
.demo-header h3 {
font-size: 24px;
margin: 0 0 8px 0;
color: #2c3e50;
}
.subtitle {
color: #666;
font-size: 14px;
margin: 0;
}
.scene-container {
display: flex;
justify-content: space-between;
align-items: center;
gap: 24px;
margin: 32px 0;
padding: 24px;
background: white;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.customer-zone,
.kitchen-zone {
flex: 1;
text-align: center;
padding: 16px;
border-radius: 8px;
background: #f8f9fa;
}
.api-zone {
flex: 1;
text-align: center;
padding: 16px;
border-radius: 8px;
background: #fff3cd;
border: 2px dashed #ffc107;
}
.customer-avatar,
.kitchen-avatar {
font-size: 48px;
margin-bottom: 8px;
}
.waiter-avatar {
font-size: 48px;
margin-bottom: 8px;
transition: transform 0.3s;
}
.waiter.moving .waiter-avatar {
animation: bounce 0.5s infinite;
}
@keyframes bounce {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-10px);
}
}
.api-label,
.kitchen-label {
font-weight: bold;
color: #856404;
font-size: 14px;
}
.menu {
margin-top: 16px;
}
.menu-item {
display: block;
width: 100%;
padding: 8px 16px;
margin: 8px 0;
border: 1px solid #ddd;
border-radius: 4px;
background: white;
cursor: pointer;
transition: all 0.2s;
}
.menu-item:hover:not(:disabled) {
background: #007bff;
color: white;
border-color: #007bff;
}
.menu-item:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.status {
margin-top: 12px;
padding: 8px;
border-radius: 4px;
font-weight: bold;
}
.status.idle {
background: #d4edda;
color: #155724;
}
.status.processing {
background: #fff3cd;
color: #856404;
animation: pulse 1s infinite;
}
@keyframes pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.7;
}
}
.comparison {
margin-top: 24px;
text-align: center;
}
.comparison button {
padding: 8px 16px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.comparison button:hover {
background: #0056b3;
}
.comparison-scene {
display: flex;
gap: 24px;
margin-top: 16px;
}
.with-api,
.without-api {
flex: 1;
padding: 16px;
border-radius: 8px;
}
.with-api {
background: #d4edda;
}
.without-api {
background: #f8d7da;
}
.comparison-visual {
font-size: 24px;
margin: 12px 0;
}
.comparison-visual.chaotic {
animation: shake 0.5s infinite;
}
@keyframes shake {
0%,
100% {
transform: translateX(0);
}
25% {
transform: translateX(-5px);
}
75% {
transform: translateX(5px);
}
}
.key-points {
margin-top: 24px;
padding: 16px;
background: #e7f3ff;
border-left: 4px solid #007bff;
border-radius: 4px;
}
.key-points h4 {
margin: 0 0 12px 0;
color: #007bff;
}
.key-points ul {
margin: 0;
padding-left: 20px;
}
.key-points li {
margin: 8px 0;
color: #333;
}
/* Dark mode support */
@media (prefers-color-scheme: dark) {
.api-concept-demo {
background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%);
border-color: #444;
}
.demo-header h3 {
color: #e0e0e0;
}
.scene-container {
background: #2d2d2d;
}
.customer-zone,
.kitchen-zone {
background: #363636;
}
.menu-item {
background: #2d2d2d;
border-color: #555;
color: #e0e0e0;
}
.menu-item:hover:not(:disabled) {
background: #007bff;
color: white;
}
.key-points {
background: #1e3a5f;
border-left-color: #4dabf7;
}
.key-points li {
color: #c0c0c0;
}
}
</style>