fix: 修复多个关键问题

- 修复前端路由守卫:未登录时不显示提示,直接跳转登录页
- 修复API拦截器:401错误不显示提示,直接跳转
- 增强验证码显示:图片尺寸从120x40增加到200x80
- 增大验证码字体:从28号增加到48号
- 优化验证码字符:排除易混淆的0和1
- 减少干扰线:从5条减少到3条,添加背景色优化
- 增强登录API日志:添加详细的调试日志
- 增强验证码生成和验证日志
- 优化异常处理和错误追踪

影响文件:
- src/router/index.ts
- src/api/request.ts
- app/services/auth_service.py
- app/api/v1/auth.py
- app/schemas/user.py

测试状态:
- 前端构建通过
- 后端语法检查通过
- 验证码显示效果优化完成

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Claude
2026-01-25 00:26:21 +08:00
commit e71181f0a3
150 changed files with 39549 additions and 0 deletions

View File

@@ -0,0 +1,259 @@
"""
文件管理模块测试
"""
import pytest
import os
from io import BytesIO
from fastapi.testclient import TestClient
from PIL import Image
def test_upload_file(client: TestClient, auth_headers: dict):
"""测试文件上传"""
# 创建测试图片
img = Image.new('RGB', (100, 100), color='red')
img_io = BytesIO()
img.save(img_io, 'JPEG')
img_io.seek(0)
response = client.post(
"/api/v1/files/upload",
headers=auth_headers,
files={"file": ("test.jpg", img_io, "image/jpeg")},
data={"remark": "测试文件"}
)
assert response.status_code == 200
data = response.json()
assert data["original_name"] == "test.jpg"
assert data["file_type"] == "image/jpeg"
assert data["message"] == "上传成功"
assert "id" in data
assert "download_url" in data
def test_upload_large_file(client: TestClient, auth_headers: dict):
"""测试大文件上传(应失败)"""
# 创建超过限制的文件11MB
large_content = b"x" * (11 * 1024 * 1024)
response = client.post(
"/api/v1/files/upload",
headers=auth_headers,
files={"file": ("large.jpg", BytesIO(large_content), "image/jpeg")}
)
assert response.status_code == 400
def test_upload_invalid_type(client: TestClient, auth_headers: dict):
"""测试不支持的文件类型(应失败)"""
response = client.post(
"/api/v1/files/upload",
headers=auth_headers,
files={"file": ("test.exe", BytesIO(b"test"), "application/x-msdownload")}
)
assert response.status_code == 400
def test_get_file_list(client: TestClient, auth_headers: dict):
"""测试获取文件列表"""
response = client.get(
"/api/v1/files/",
headers=auth_headers,
params={"page": 1, "page_size": 20}
)
assert response.status_code == 200
data = response.json()
assert isinstance(data, list)
def test_get_file_detail(client: TestClient, auth_headers: dict):
"""测试获取文件详情"""
# 先上传一个文件
img = Image.new('RGB', (100, 100), color='blue')
img_io = BytesIO()
img.save(img_io, 'PNG')
img_io.seek(0)
upload_response = client.post(
"/api/v1/files/upload",
headers=auth_headers,
files={"file": ("test.png", img_io, "image/png")}
)
file_id = upload_response.json()["id"]
# 获取文件详情
response = client.get(
f"/api/v1/files/{file_id}",
headers=auth_headers
)
assert response.status_code == 200
data = response.json()
assert data["id"] == file_id
assert "download_url" in data
def test_get_file_statistics(client: TestClient, auth_headers: dict):
"""测试获取文件统计"""
response = client.get(
"/api/v1/files/statistics",
headers=auth_headers
)
assert response.status_code == 200
data = response.json()
assert "total_files" in data
assert "total_size" in data
assert "type_distribution" in data
def test_create_share_link(client: TestClient, auth_headers: dict):
"""测试生成分享链接"""
# 先上传一个文件
img = Image.new('RGB', (100, 100), color='green')
img_io = BytesIO()
img.save(img_io, 'JPEG')
img_io.seek(0)
upload_response = client.post(
"/api/v1/files/upload",
headers=auth_headers,
files={"file": ("share.jpg", img_io, "image/jpeg")}
)
file_id = upload_response.json()["id"]
# 生成分享链接
response = client.post(
f"/api/v1/files/{file_id}/share",
headers=auth_headers,
json={"expire_days": 7}
)
assert response.status_code == 200
data = response.json()
assert "share_code" in data
assert "share_url" in data
assert "expire_time" in data
def test_delete_file(client: TestClient, auth_headers: dict):
"""测试删除文件"""
# 先上传一个文件
img = Image.new('RGB', (100, 100), color='yellow')
img_io = BytesIO()
img.save(img_io, 'JPEG')
img_io.seek(0)
upload_response = client.post(
"/api/v1/files/upload",
headers=auth_headers,
files={"file": ("delete.jpg", img_io, "image/jpeg")}
)
file_id = upload_response.json()["id"]
# 删除文件
response = client.delete(
f"/api/v1/files/{file_id}",
headers=auth_headers
)
assert response.status_code == 204
def test_batch_delete_files(client: TestClient, auth_headers: dict):
"""测试批量删除文件"""
# 上传多个文件
file_ids = []
for i in range(3):
img = Image.new('RGB', (100, 100), color='red')
img_io = BytesIO()
img.save(img_io, 'JPEG')
img_io.seek(0)
upload_response = client.post(
"/api/v1/files/upload",
headers=auth_headers,
files={"file": (f"batch_{i}.jpg", img_io, "image/jpeg")}
)
file_ids.append(upload_response.json()["id"])
# 批量删除
response = client.delete(
"/api/v1/files/batch",
headers=auth_headers,
json={"file_ids": file_ids}
)
assert response.status_code == 204
def test_chunk_upload_init(client: TestClient, auth_headers: dict):
"""测试初始化分片上传"""
response = client.post(
"/api/v1/files/chunks/init",
headers=auth_headers,
json={
"file_name": "large_file.zip",
"file_size": 10485760, # 10MB
"file_type": "application/zip",
"total_chunks": 2
}
)
assert response.status_code == 200
data = response.json()
assert "upload_id" in data
def test_access_shared_file(client: TestClient, auth_headers: dict):
"""测试访问分享文件"""
# 先上传一个文件
img = Image.new('RGB', (100, 100), color='purple')
img_io = BytesIO()
img.save(img_io, 'JPEG')
img_io.seek(0)
upload_response = client.post(
"/api/v1/files/upload",
headers=auth_headers,
files={"file": ("shared.jpg", img_io, "image/jpeg")}
)
file_id = upload_response.json()["id"]
# 生成分享链接
share_response = client.post(
f"/api/v1/files/{file_id}/share",
headers=auth_headers,
json={"expire_days": 7}
)
share_code = share_response.json()["share_code"]
# 访问分享文件(无需认证)
response = client.get(f"/api/v1/files/share/{share_code}")
assert response.status_code == 200
# 运行测试的fixtures
@pytest.fixture
def auth_headers(client: TestClient):
"""获取认证头"""
# 先登录
response = client.post(
"/api/v1/auth/login",
json={
"username": "admin",
"password": "admin123"
}
)
if response.status_code == 200:
token = response.json()["access_token"]
return {"Authorization": f"Bearer {token}"}
# 如果登录失败使用测试token
return {"Authorization": "Bearer test_token"}