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

332
app/crud/allocation.py Normal file
View File

@@ -0,0 +1,332 @@
"""
资产分配相关CRUD操作
"""
from typing import List, Optional, Tuple
from sqlalchemy.orm import Session
from sqlalchemy import and_, or_
from app.models.allocation import AssetAllocationOrder, AssetAllocationItem
from app.models.asset import Asset
from app.schemas.allocation import AllocationOrderCreate, AllocationOrderUpdate
class AllocationOrderCRUD:
"""分配单CRUD操作"""
def get(self, db: Session, id: int) -> Optional[AssetAllocationOrder]:
"""根据ID获取分配单"""
return db.query(AssetAllocationOrder).filter(
AssetAllocationOrder.id == id
).first()
def get_by_code(self, db: Session, order_code: str) -> Optional[AssetAllocationOrder]:
"""根据单号获取分配单"""
return db.query(AssetAllocationOrder).filter(
AssetAllocationOrder.order_code == order_code
).first()
def get_multi(
self,
db: Session,
skip: int = 0,
limit: int = 20,
order_type: Optional[str] = None,
approval_status: Optional[str] = None,
execute_status: Optional[str] = None,
applicant_id: Optional[int] = None,
target_organization_id: Optional[int] = None,
keyword: Optional[str] = None
) -> Tuple[List[AssetAllocationOrder], int]:
"""获取分配单列表"""
query = db.query(AssetAllocationOrder)
# 筛选条件
if order_type:
query = query.filter(AssetAllocationOrder.order_type == order_type)
if approval_status:
query = query.filter(AssetAllocationOrder.approval_status == approval_status)
if execute_status:
query = query.filter(AssetAllocationOrder.execute_status == execute_status)
if applicant_id:
query = query.filter(AssetAllocationOrder.applicant_id == applicant_id)
if target_organization_id:
query = query.filter(AssetAllocationOrder.target_organization_id == target_organization_id)
if keyword:
query = query.filter(
or_(
AssetAllocationOrder.order_code.like(f"%{keyword}%"),
AssetAllocationOrder.title.like(f"%{keyword}%")
)
)
# 排序
query = query.order_by(AssetAllocationOrder.created_at.desc())
# 总数
total = query.count()
# 分页
items = query.offset(skip).limit(limit).all()
return items, total
def create(
self,
db: Session,
obj_in: AllocationOrderCreate,
order_code: str,
applicant_id: int
) -> AssetAllocationOrder:
"""创建分配单"""
# 创建分配单
db_obj = AssetAllocationOrder(
order_code=order_code,
order_type=obj_in.order_type,
title=obj_in.title,
source_organization_id=obj_in.source_organization_id,
target_organization_id=obj_in.target_organization_id,
applicant_id=applicant_id,
expect_execute_date=obj_in.expect_execute_date,
remark=obj_in.remark,
created_by=applicant_id,
approval_status="pending",
execute_status="pending"
)
db.add(db_obj)
db.commit()
db.refresh(db_obj)
# 创建分配单明细
self._create_items(
db=db,
order_id=db_obj.id,
asset_ids=obj_in.asset_ids,
target_org_id=obj_in.target_organization_id
)
return db_obj
def update(
self,
db: Session,
db_obj: AssetAllocationOrder,
obj_in: AllocationOrderUpdate,
updater_id: int
) -> AssetAllocationOrder:
"""更新分配单"""
update_data = obj_in.model_dump(exclude_unset=True)
for field, value in update_data.items():
setattr(db_obj, field, value)
db_obj.updated_by = updater_id
db.add(db_obj)
db.commit()
db.refresh(db_obj)
return db_obj
def approve(
self,
db: Session,
db_obj: AssetAllocationOrder,
approval_status: str,
approver_id: int,
approval_remark: Optional[str] = None
) -> AssetAllocationOrder:
"""审批分配单"""
from datetime import datetime
db_obj.approval_status = approval_status
db_obj.approver_id = approver_id
db_obj.approval_time = datetime.utcnow()
db_obj.approval_remark = approval_remark
# 如果审批通过,自动设置为可执行状态
if approval_status == "approved":
db_obj.execute_status = "pending"
elif approval_status == "rejected":
db_obj.execute_status = "cancelled"
db.add(db_obj)
db.commit()
db.refresh(db_obj)
return db_obj
def execute(
self,
db: Session,
db_obj: AssetAllocationOrder,
executor_id: int
) -> AssetAllocationOrder:
"""执行分配单"""
from datetime import datetime, date
db_obj.execute_status = "completed"
db_obj.actual_execute_date = date.today()
db_obj.executor_id = executor_id
db.add(db_obj)
db.commit()
db.refresh(db_obj)
return db_obj
def cancel(self, db: Session, db_obj: AssetAllocationOrder) -> AssetAllocationOrder:
"""取消分配单"""
db_obj.approval_status = "cancelled"
db_obj.execute_status = "cancelled"
db.add(db_obj)
db.commit()
db.refresh(db_obj)
return db_obj
def delete(self, db: Session, id: int) -> bool:
"""删除分配单"""
obj = self.get(db, id)
if obj:
db.delete(obj)
db.commit()
return True
return False
def get_statistics(
self,
db: Session,
applicant_id: Optional[int] = None
) -> dict:
"""获取分配单统计信息"""
query = db.query(AssetAllocationOrder)
if applicant_id:
query = query.filter(AssetAllocationOrder.applicant_id == applicant_id)
total = query.count()
pending = query.filter(AssetAllocationOrder.approval_status == "pending").count()
approved = query.filter(AssetAllocationOrder.approval_status == "approved").count()
rejected = query.filter(AssetAllocationOrder.approval_status == "rejected").count()
executing = query.filter(AssetAllocationOrder.execute_status == "executing").count()
completed = query.filter(AssetAllocationOrder.execute_status == "completed").count()
return {
"total": total,
"pending": pending,
"approved": approved,
"rejected": rejected,
"executing": executing,
"completed": completed
}
def _create_items(
self,
db: Session,
order_id: int,
asset_ids: List[int],
target_org_id: int
):
"""创建分配单明细"""
# 查询资产信息
assets = db.query(Asset).filter(Asset.id.in_(asset_ids)).all()
for asset in assets:
item = AssetAllocationItem(
order_id=order_id,
asset_id=asset.id,
asset_code=asset.asset_code,
asset_name=asset.asset_name,
from_organization_id=asset.organization_id,
to_organization_id=target_org_id,
from_status=asset.status,
to_status=self._get_target_status(asset.status),
execute_status="pending"
)
db.add(item)
db.commit()
def _get_target_status(self, current_status: str) -> str:
"""根据当前状态获取目标状态"""
status_map = {
"in_stock": "transferring",
"in_use": "transferring",
"maintenance": "in_stock"
}
return status_map.get(current_status, "transferring")
class AllocationItemCRUD:
"""分配单明细CRUD操作"""
def get_by_order(self, db: Session, order_id: int) -> List[AssetAllocationItem]:
"""根据分配单ID获取明细列表"""
return db.query(AssetAllocationItem).filter(
AssetAllocationItem.order_id == order_id
).order_by(AssetAllocationItem.id).all()
def get_multi(
self,
db: Session,
skip: int = 0,
limit: int = 20,
order_id: Optional[int] = None,
execute_status: Optional[str] = None
) -> Tuple[List[AssetAllocationItem], int]:
"""获取明细列表"""
query = db.query(AssetAllocationItem)
if order_id:
query = query.filter(AssetAllocationItem.order_id == order_id)
if execute_status:
query = query.filter(AssetAllocationItem.execute_status == execute_status)
total = query.count()
items = query.offset(skip).limit(limit).all()
return items, total
def update_execute_status(
self,
db: Session,
item_id: int,
execute_status: str,
failure_reason: Optional[str] = None
) -> AssetAllocationItem:
"""更新明细执行状态"""
from datetime import datetime
item = db.query(AssetAllocationItem).filter(
AssetAllocationItem.id == item_id
).first()
if item:
item.execute_status = execute_status
item.execute_time = datetime.utcnow()
item.failure_reason = failure_reason
db.add(item)
db.commit()
db.refresh(item)
return item
def batch_update_execute_status(
self,
db: Session,
order_id: int,
execute_status: str
):
"""批量更新明细执行状态"""
from datetime import datetime
items = db.query(AssetAllocationItem).filter(
and_(
AssetAllocationItem.order_id == order_id,
AssetAllocationItem.execute_status == "pending"
)
).all()
for item in items:
item.execute_status = execute_status
item.execute_time = datetime.utcnow()
db.add(item)
db.commit()
# 创建全局实例
allocation_order = AllocationOrderCRUD()
allocation_item = AllocationItemCRUD()