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,359 @@
"""
性能测试 - Locust文件
测试内容:
- 并发用户测试
- 接口响应时间
- 吞吐量测试
- 负载测试
- 压力测试
"""
from locust import HttpUser, task, between, events
from locust.runners import MasterRunner
import time
import random
# 测试数据
TEST_USERS = [
{"username": "admin", "password": "Admin123"},
{"username": "user1", "password": "Test123"},
{"username": "user2", "password": "Test123"},
]
ASSET_NAMES = ["联想台式机", "戴尔笔记本", "惠普打印机", "苹果显示器", "罗技鼠标"]
DEVICE_TYPES = [1, 2, 3, 4, 5]
ORGANIZATIONS = [1, 2, 3, 4, 5]
class AssetManagementUser(HttpUser):
"""
资产管理系统用户模拟
模拟真实用户的行为模式
"""
# 等待时间: 用户操作之间间隔1-3秒
wait_time = between(1, 3)
def on_start(self):
"""用户登录时执行"""
self.login()
self.token = None
self.headers = {}
def login(self):
"""登录获取token"""
user = random.choice(TEST_USERS)
# 先获取验证码
captcha_resp = self.client.get("/api/v1/auth/captcha")
if captcha_resp.status_code == 200:
captcha_data = captcha_resp.json()
captcha_key = captcha_data["data"]["captcha_key"]
# 登录
login_resp = self.client.post(
"/api/v1/auth/login",
json={
"username": user["username"],
"password": user["password"],
"captcha": "1234", # 测试环境固定验证码
"captcha_key": captcha_key
}
)
if login_resp.status_code == 200:
self.token = login_resp.json()["data"]["access_token"]
self.headers = {
"Authorization": f"Bearer {self.token}",
"Content-Type": "application/json"
}
@task(10)
def view_asset_list(self):
"""查看资产列表 (高频操作)"""
self.client.get(
"/api/v1/assets",
headers=self.headers,
params={
"page": random.randint(1, 5),
"page_size": 20
}
)
@task(5)
def search_assets(self):
"""搜索资产 (中频操作)"""
keywords = ["联想", "戴尔", "台式机", "笔记本", "打印机"]
keyword = random.choice(keywords)
self.client.get(
"/api/v1/assets",
headers=self.headers,
params={"keyword": keyword}
)
@task(3)
def view_asset_detail(self):
"""查看资产详情 (中频操作)"""
asset_id = random.randint(1, 100)
self.client.get(
f"/api/v1/assets/{asset_id}",
headers=self.headers
)
@task(2)
def view_statistics(self):
"""查看统计数据 (低频操作)"""
self.client.get(
"/api/v1/statistics/overview",
headers=self.headers
)
@task(1)
def create_asset(self):
"""创建资产 (低频操作)"""
asset_data = {
"asset_name": f"{random.choice(ASSET_NAMES)}-{int(time.time())}",
"device_type_id": random.choice(DEVICE_TYPES),
"organization_id": random.choice(ORGANIZATIONS),
"model": f"测试型号-{int(time.time())}",
"serial_number": f"SN-{int(time.time())}",
"location": f"测试位置-{random.randint(1, 10)}"
}
self.client.post(
"/api/v1/assets",
headers=self.headers,
json=asset_data
)
@task(1)
def filter_assets(self):
"""筛选资产 (低频操作)"""
statuses = ["in_stock", "in_use", "maintenance", "scrapped"]
status = random.choice(statuses)
self.client.get(
"/api/v1/assets",
headers=self.headers,
params={"status": status}
)
class AssetManagementUserRead(AssetManagementUser):
"""
只读用户
只执行查询操作,不执行写操作
"""
@task(10)
def view_asset_list(self):
"""查看资产列表"""
self.client.get(
"/api/v1/assets",
headers=self.headers,
params={"page": random.randint(1, 10), "page_size": 20}
)
@task(5)
def view_asset_detail(self):
"""查看资产详情"""
asset_id = random.randint(1, 100)
self.client.get(
f"/api/v1/assets/{asset_id}",
headers=self.headers
)
@task(3)
def search_assets(self):
"""搜索资产"""
keywords = ["联想", "戴尔", "惠普"]
self.client.get(
"/api/v1/assets",
headers=self.headers,
params={"keyword": random.choice(keywords)}
)
@task(2)
def view_statistics(self):
"""查看统计数据"""
self.client.get(
"/api/v1/statistics/overview",
headers=self.headers
)
# 自定义事件处理器
@events.request.add_listener
def on_request(request_type, name, response_time, response_length, **kwargs):
"""
请求事件监听器
记录慢请求
"""
if response_time > 1000: # 响应时间超过1秒
print(f"慢请求警告: {name} 耗时 {response_time}ms")
@events.test_stop.add_listener
def on_test_stop(environment, **kwargs):
"""
测试结束事件
输出测试统计
"""
if not isinstance(environment.runner, MasterRunner):
print("\n" + "="*50)
print("性能测试完成")
print("="*50)
stats = environment.stats
print(f"\n总请求数: {stats.total.num_requests}")
print(f"失败请求数: {stats.total.num_failures}")
print(f"平均响应时间: {stats.total.avg_response_time}ms")
print(f"中位数响应时间: {stats.total.median_response_time}ms")
print(f"95%请求响应时间: {stats.total.get_response_time_percentile(0.95)}ms")
print(f"99%请求响应时间: {stats.total.get_response_time_percentile(0.99)}ms")
print(f"请求/秒 (RPS): {stats.total.total_rps}")
print(f"失败率: {stats.total.fail_ratio * 100:.2f}%")
# 性能指标评估
print("\n性能评估:")
avg_response = stats.total.avg_response_time
if avg_response < 200:
print("✓ 响应时间: 优秀 (< 200ms)")
elif avg_response < 500:
print("✓ 响应时间: 良好 (< 500ms)")
elif avg_response < 1000:
print("⚠ 响应时间: 一般 (< 1000ms)")
else:
print("✗ 响应时间: 差 (> 1000ms)")
rps = stats.total.total_rps
if rps > 100:
print("✓ 吞吐量: 优秀 (> 100 RPS)")
elif rps > 50:
print("✓ 吞吐量: 良好 (> 50 RPS)")
elif rps > 20:
print("⚠ 吞吐量: 一般 (> 20 RPS)")
else:
print("✗ 吞吐量: 差 (< 20 RPS)")
fail_ratio = stats.total.fail_ratio * 100
if fail_ratio < 1:
print("✓ 失败率: 优秀 (< 1%)")
elif fail_ratio < 5:
print("✓ 失败率: 良好 (< 5%)")
else:
print("✗ 失败率: 差 (> 5%)")
print("="*50 + "\n")
# 性能测试目标
PERFORMANCE_TARGETS = {
"avg_response_time": 500, # 平均响应时间 < 500ms
"p95_response_time": 1000, # 95%响应时间 < 1000ms
"rps": 50, # 吞吐量 > 50 RPS
"fail_ratio": 0.01 # 失败率 < 1%
}
class PerformanceTestRunner:
"""
性能测试运行器
提供不同场景的性能测试
"""
def __init__(self):
self.scenarios = {
"smoke": self.smoke_test,
"normal": self.normal_load_test,
"stress": self.stress_test,
"spike": self.spike_test,
"endurance": self.endurance_test
}
def smoke_test(self):
"""
冒烟测试
少量用户,验证系统基本功能
"""
return {
"num_users": 10,
"spawn_rate": 2,
"run_time": "1m"
}
def normal_load_test(self):
"""
正常负载测试
模拟日常使用情况
"""
return {
"num_users": 50,
"spawn_rate": 5,
"run_time": "5m"
}
def stress_test(self):
"""
压力测试
逐步增加用户直到系统达到极限
"""
return {
"num_users": 200,
"spawn_rate": 10,
"run_time": "10m"
}
def spike_test(self):
"""
尖峰测试
突然大量用户访问
"""
return {
"num_users": 500,
"spawn_rate": 50,
"run_time": "2m"
}
def endurance_test(self):
"""
耐力测试
长时间稳定负载
"""
return {
"num_users": 100,
"spawn_rate": 10,
"run_time": "30m"
}
# 使用说明
"""
运行性能测试:
1. 冒烟测试 (10用户, 1分钟):
locust -f locustfile.py --headless -u 10 -r 2 -t 1m
2. 正常负载测试 (50用户, 5分钟):
locust -f locustfile.py --headless -u 50 -r 5 -t 5m
3. 压力测试 (200用户, 10分钟):
locust -f locustfile.py --headless -u 200 -r 10 -t 10m
4. 尖峰测试 (500用户, 2分钟):
locust -f locustfile.py --headless -u 500 -r 50 -t 2m
5. Web界面模式:
locust -f locustfile.py --host=http://localhost:8000
然后访问 http://localhost:8089
6. 分布式测试 (Master):
locust -f locustfile.py --master --expect-workers=4
7. 分布式测试 (Worker):
locust -f locustfile.py --worker --master-host=<master-ip>
"""