feat: 完成前后端API联调测试并修复配置问题
- 启动后端go-zero API服务 (端口8080) - 修复前端API配置中的端口号 (8888→8080) - 完善前端API状态监控组件 - 创建categoryService服务层 - 更新前端数据查询和转换逻辑 - 完成完整API集成测试,验证所有接口正常工作 - 验证用户认证、分类管理、照片管理等核心功能 - 创建API集成测试脚本 - 更新任务进度文档 测试结果: ✅ 后端健康检查正常 ✅ 用户认证功能正常 (admin/admin123) ✅ 分类API正常 (5个分类) ✅ 照片API正常 (0张照片,数据库为空) ✅ 前后端API连接完全正常 下一步: 实现照片展示页面和搜索过滤功能
This commit is contained in:
97
frontend/components/api-status.tsx
Normal file
97
frontend/components/api-status.tsx
Normal file
@ -0,0 +1,97 @@
|
||||
"use client"
|
||||
|
||||
import { useState, useEffect } from 'react'
|
||||
import { Badge } from './ui/badge'
|
||||
import { Button } from './ui/button'
|
||||
import { Alert, AlertDescription } from './ui/alert'
|
||||
import { Wifi, WifiOff, RefreshCw, Settings } from 'lucide-react'
|
||||
import api from '@/lib/api'
|
||||
|
||||
export function ApiStatus() {
|
||||
const [isOnline, setIsOnline] = useState(false)
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
const [useRealApi, setUseRealApi] = useState(process.env.NEXT_PUBLIC_USE_REAL_API === 'true')
|
||||
const [apiUrl, setApiUrl] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
if (useRealApi) {
|
||||
setApiUrl(process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8080/api/v1')
|
||||
} else {
|
||||
setApiUrl(process.env.NEXT_PUBLIC_MOCK_API_URL || 'http://localhost:3001/api')
|
||||
}
|
||||
}, [useRealApi])
|
||||
|
||||
const checkApiStatus = async () => {
|
||||
setIsLoading(true)
|
||||
try {
|
||||
if (useRealApi) {
|
||||
// 检查后端 API 健康状态
|
||||
await api.get('/health')
|
||||
} else {
|
||||
// 检查 Mock API
|
||||
await api.get('/photos')
|
||||
}
|
||||
setIsOnline(true)
|
||||
} catch (error) {
|
||||
setIsOnline(false)
|
||||
console.error('API检查失败:', error)
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
checkApiStatus()
|
||||
// 每30秒检查一次API状态
|
||||
const interval = setInterval(checkApiStatus, 30000)
|
||||
return () => clearInterval(interval)
|
||||
}, [useRealApi])
|
||||
|
||||
const toggleApiMode = () => {
|
||||
const newMode = !useRealApi
|
||||
setUseRealApi(newMode)
|
||||
// 在生产环境中,这里应该通过其他方式切换,而不是修改环境变量
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem('useRealApi', newMode.toString())
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
return null // 生产环境不显示此组件
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed bottom-4 right-4 z-50 max-w-sm">
|
||||
<Alert className="mb-2">
|
||||
<Settings className="h-4 w-4" />
|
||||
<AlertDescription>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
{isLoading ? (
|
||||
<RefreshCw className="h-4 w-4 animate-spin" />
|
||||
) : isOnline ? (
|
||||
<Wifi className="h-4 w-4 text-green-500" />
|
||||
) : (
|
||||
<WifiOff className="h-4 w-4 text-red-500" />
|
||||
)}
|
||||
<Badge variant={isOnline ? "default" : "destructive"}>
|
||||
{useRealApi ? '后端API' : 'Mock API'}
|
||||
</Badge>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={toggleApiMode}
|
||||
className="ml-2"
|
||||
>
|
||||
切换
|
||||
</Button>
|
||||
</div>
|
||||
<div className="text-xs text-muted-foreground mt-1">
|
||||
{apiUrl}
|
||||
</div>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user