first commit
This commit is contained in:
118
frontend/DEBUG_GUIDE.md
Normal file
118
frontend/DEBUG_GUIDE.md
Normal file
@@ -0,0 +1,118 @@
|
||||
# 前端接口调试指南
|
||||
|
||||
## 问题诊断步骤
|
||||
|
||||
### 1. 打开浏览器开发者工具
|
||||
- 按 F12 或右键 → 检查
|
||||
- 切换到 **Console(控制台)** 标签
|
||||
- 切换到 **Network(网络)** 标签
|
||||
|
||||
### 2. 查看控制台错误
|
||||
在控制台查看具体的错误信息,常见错误:
|
||||
|
||||
#### 错误类型 1: CORS 错误
|
||||
```
|
||||
Access to XMLHttpRequest at 'http://localhost:8000/api/v1/...'
|
||||
from origin 'http://localhost:5173' has been blocked by CORS policy
|
||||
```
|
||||
**解决方法**: 这是正常的,说明请求到达了后端,检查后端 CORS 配置
|
||||
|
||||
#### 错误类型 2: 404 Not Found
|
||||
```
|
||||
GET http://localhost:5173/api/v1/departments 404 (Not Found)
|
||||
```
|
||||
**原因**: Vite 代理配置问题
|
||||
**解决方法**: 重启前端开发服务器
|
||||
|
||||
#### 错误类型 3: 500 Internal Server Error
|
||||
```
|
||||
POST http://localhost:8000/api/v1/auth/login 500 (Internal Server Error)
|
||||
```
|
||||
**原因**: 后端服务错误
|
||||
**解决方法**: 检查后端日志 `backend/logs/error_*.log`
|
||||
|
||||
#### 错误类型 4: Network Error
|
||||
```
|
||||
Error: Network Error
|
||||
```
|
||||
**原因**: 后端服务未运行
|
||||
**解决方法**: 启动后端服务 `cd backend && uvicorn app.main:app --reload`
|
||||
|
||||
### 3. 查看网络请求
|
||||
|
||||
在 Network 标签中:
|
||||
1. 找到失败的请求(红色)
|
||||
2. 点击请求查看详情
|
||||
3. 查看 **Response(响应)** 标签,查看后端返回的错误信息
|
||||
|
||||
### 4. 常见接口错误及解决
|
||||
|
||||
#### 登录失败
|
||||
**检查点**:
|
||||
- 后端是否运行:访问 http://localhost:8000/health
|
||||
- 账号密码是否正确:admin / admin123
|
||||
- Content-Type 是否为 `application/x-www-form-urlencoded`
|
||||
|
||||
#### 科室/员工/指标列表失败
|
||||
**检查点**:
|
||||
- 是否已登录获取 token
|
||||
- token 是否过期
|
||||
- 请求头是否包含 `Authorization: Bearer {token}`
|
||||
|
||||
#### 统计报表失败
|
||||
**检查点**:
|
||||
- 参数是否正确(period_year, period_month)
|
||||
- 数据库中是否有对应数据
|
||||
|
||||
### 5. 快速测试工具
|
||||
|
||||
访问 http://localhost:5173/test-api.html 使用内置的 API 测试工具
|
||||
|
||||
### 6. 清除缓存
|
||||
|
||||
如果遇到问题:
|
||||
1. 清除浏览器缓存:Ctrl+Shift+Delete
|
||||
2. 清除 localStorage:
|
||||
```javascript
|
||||
localStorage.clear()
|
||||
```
|
||||
3. 硬刷新:Ctrl+F5
|
||||
|
||||
### 7. 重启服务
|
||||
|
||||
如果以上都无效:
|
||||
```bash
|
||||
# 停止所有 Python 进程
|
||||
powershell -Command "Get-Process | Where-Object {$_.ProcessName -eq 'python'} | Stop-Process -Force"
|
||||
|
||||
# 重启后端
|
||||
cd D:\医院绩效系统\backend
|
||||
python -m uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
|
||||
|
||||
# 重启前端(新终端)
|
||||
cd D:\医院绩效系统\frontend
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## 当前系统状态
|
||||
|
||||
### 后端状态
|
||||
- 地址:http://localhost:8000
|
||||
- 健康检查:http://localhost:8000/health
|
||||
- API 文档:http://localhost:8000/api/v1/docs
|
||||
- 日志目录:`backend/logs/`
|
||||
|
||||
### 前端状态
|
||||
- 地址:http://localhost:5173
|
||||
- Vite 配置:代理 `/api` 到 `http://localhost:8000`
|
||||
|
||||
### 默认账号
|
||||
- 用户名:admin
|
||||
- 密码:admin123
|
||||
|
||||
## 联系支持
|
||||
|
||||
如果问题仍未解决,请提供:
|
||||
1. 控制台错误截图
|
||||
2. Network 标签中失败请求的详情
|
||||
3. 后端日志内容
|
||||
132
frontend/public/test-api.html
Normal file
132
frontend/public/test-api.html
Normal file
@@ -0,0 +1,132 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>API 测试</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; padding: 20px; }
|
||||
.result { background: #f5f5f5; padding: 10px; margin: 10px 0; border-radius: 4px; }
|
||||
.success { background: #d4edda; }
|
||||
.error { background: #f8d7da; }
|
||||
button { padding: 10px 20px; margin: 5px; cursor: pointer; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>前端 API 测试</h1>
|
||||
|
||||
<div>
|
||||
<button onclick="testHealth()">测试健康检查</button>
|
||||
<button onclick="testLogin()">测试登录</button>
|
||||
<button onclick="testDepartments()">测试科室列表</button>
|
||||
<button onclick="testIndicators()">测试指标列表</button>
|
||||
<button onclick="testStats()">测试统计</button>
|
||||
<button onclick="clearResults()">清空结果</button>
|
||||
</div>
|
||||
|
||||
<div id="results"></div>
|
||||
|
||||
<script>
|
||||
const API_BASE = 'http://localhost:8000/api/v1';
|
||||
let token = '';
|
||||
|
||||
function log(message, type = 'info') {
|
||||
const div = document.createElement('div');
|
||||
div.className = `result ${type}`;
|
||||
div.textContent = message;
|
||||
document.getElementById('results').appendChild(div);
|
||||
}
|
||||
|
||||
function clearResults() {
|
||||
document.getElementById('results').innerHTML = '';
|
||||
}
|
||||
|
||||
async function testHealth() {
|
||||
try {
|
||||
const res = await fetch('http://localhost:8000/health');
|
||||
const data = await res.json();
|
||||
log(`健康检查:${res.status} - ${JSON.stringify(data)}`, 'success');
|
||||
} catch (error) {
|
||||
log(`健康检查失败:${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function testLogin() {
|
||||
try {
|
||||
const params = new URLSearchParams();
|
||||
params.append('username', 'admin');
|
||||
params.append('password', 'admin123');
|
||||
|
||||
const res = await fetch(`${API_BASE}/auth/login`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: params
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
if (res.status === 200) {
|
||||
token = data.access_token;
|
||||
log(`登录成功:Token=${token.substring(0, 30)}...`, 'success');
|
||||
} else {
|
||||
log(`登录失败:${res.status} - ${JSON.stringify(data)}`, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
log(`登录异常:${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function testDepartments() {
|
||||
if (!token) {
|
||||
log('请先登录', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/departments`, {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
log(`科室列表:${res.status} - ${data.message || ''} (共${data.data?.length || 0}个)`, 'success');
|
||||
} catch (error) {
|
||||
log(`科室列表失败:${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function testIndicators() {
|
||||
if (!token) {
|
||||
log('请先登录', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/indicators?page=1&page_size=20`, {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
log(`指标列表:${res.status} - ${data.message || ''} (共${data.data?.length || 0}个)`, 'success');
|
||||
} catch (error) {
|
||||
log(`指标列表失败:${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function testStats() {
|
||||
if (!token) {
|
||||
log('请先登录', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch(`${API_BASE}/stats/department?period_year=2026&period_month=2`, {
|
||||
headers: { 'Authorization': `Bearer ${token}` }
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
log(`科室统计:${res.status} - ${data.message || ''} (共${data.data?.length || 0}个科室)`, 'success');
|
||||
} catch (error) {
|
||||
log(`科室统计失败:${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user