first commit

This commit is contained in:
2026-02-28 15:05:30 +08:00
parent f657de1c0d
commit 1bc330e20c
2 changed files with 250 additions and 0 deletions

118
frontend/DEBUG_GUIDE.md Normal file
View 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. 后端日志内容

View 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>