Files
zcglxt/app/api/v1/assets.py
Claude e71181f0a3 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>
2026-01-25 00:26:21 +08:00

246 lines
6.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
资产管理API路由
"""
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, status, Query
from sqlalchemy.orm import Session
from app.core.deps import get_db, get_current_user
from app.schemas.asset import (
AssetCreate,
AssetUpdate,
AssetResponse,
AssetWithRelations,
AssetStatusHistoryResponse,
AssetStatusTransition,
AssetQueryParams
)
from app.services.asset_service import asset_service
router = APIRouter()
@router.get("/", response_model=List[AssetResponse])
def get_assets(
skip: int = Query(0, ge=0, description="跳过条数"),
limit: int = Query(20, ge=1, le=100, description="返回条数"),
keyword: Optional[str] = Query(None, description="搜索关键词"),
device_type_id: Optional[int] = Query(None, description="设备类型ID"),
organization_id: Optional[int] = Query(None, description="网点ID"),
status: Optional[str] = Query(None, description="状态"),
purchase_date_start: Optional[str] = Query(None, description="采购日期开始(YYYY-MM-DD)"),
purchase_date_end: Optional[str] = Query(None, description="采购日期结束(YYYY-MM-DD)"),
db: Session = Depends(get_db),
current_user = Depends(get_current_user)
):
"""
获取资产列表
- **skip**: 跳过条数
- **limit**: 返回条数最大100
- **keyword**: 搜索关键词(编码/名称/型号/序列号)
- **device_type_id**: 设备类型ID筛选
- **organization_id**: 网点ID筛选
- **status**: 状态筛选
- **purchase_date_start**: 采购日期开始
- **purchase_date_end**: 采购日期结束
"""
items, total = asset_service.get_assets(
db=db,
skip=skip,
limit=limit,
keyword=keyword,
device_type_id=device_type_id,
organization_id=organization_id,
status=status,
purchase_date_start=purchase_date_start,
purchase_date_end=purchase_date_end
)
return items
@router.get("/statistics")
def get_asset_statistics(
organization_id: Optional[int] = Query(None, description="网点ID筛选"),
db: Session = Depends(get_db),
current_user = Depends(get_current_user)
):
"""
获取资产统计信息
- **organization_id**: 网点ID筛选
返回资产总数、总价值、状态分布等统计信息
"""
return asset_service.get_statistics(db, organization_id)
@router.get("/{asset_id}", response_model=AssetWithRelations)
def get_asset(
asset_id: int,
db: Session = Depends(get_db),
current_user = Depends(get_current_user)
):
"""
获取资产详情
- **asset_id**: 资产ID
返回资产详情及其关联信息
"""
return asset_service.get_asset(db, asset_id)
@router.get("/scan/{asset_code}", response_model=AssetWithRelations)
def scan_asset(
asset_code: str,
db: Session = Depends(get_db),
current_user = Depends(get_current_user)
):
"""
扫码查询资产
- **asset_code**: 资产编码
通过扫描二维码查询资产详情
"""
return asset_service.scan_asset_by_code(db, asset_code)
@router.post("/", response_model=AssetResponse, status_code=status.HTTP_201_CREATED)
def create_asset(
obj_in: AssetCreate,
db: Session = Depends(get_db),
current_user = Depends(get_current_user)
):
"""
创建资产
- **asset_name**: 资产名称
- **device_type_id**: 设备类型ID
- **brand_id**: 品牌ID可选
- **model**: 规格型号
- **serial_number**: 序列号
- **supplier_id**: 供应商ID
- **purchase_date**: 采购日期
- **purchase_price**: 采购价格
- **warranty_period**: 保修期(月)
- **organization_id**: 所属网点ID
- **location**: 存放位置
- **dynamic_attributes**: 动态字段值
- **remark**: 备注
"""
return asset_service.create_asset(
db=db,
obj_in=obj_in,
creator_id=current_user.id
)
@router.put("/{asset_id}", response_model=AssetResponse)
def update_asset(
asset_id: int,
obj_in: AssetUpdate,
db: Session = Depends(get_db),
current_user = Depends(get_current_user)
):
"""
更新资产
- **asset_id**: 资产ID
- **asset_name**: 资产名称
- **brand_id**: 品牌ID
- **model**: 规格型号
- **serial_number**: 序列号
- **supplier_id**: 供应商ID
- **purchase_date**: 采购日期
- **purchase_price**: 采购价格
- **warranty_period**: 保修期
- **organization_id**: 所属网点ID
- **location**: 存放位置
- **dynamic_attributes**: 动态字段值
- **remark**: 备注
"""
return asset_service.update_asset(
db=db,
asset_id=asset_id,
obj_in=obj_in,
updater_id=current_user.id
)
@router.delete("/{asset_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_asset(
asset_id: int,
db: Session = Depends(get_db),
current_user = Depends(get_current_user)
):
"""
删除资产
- **asset_id**: 资产ID
软删除资产
"""
asset_service.delete_asset(
db=db,
asset_id=asset_id,
deleter_id=current_user.id
)
return None
# ===== 状态管理 =====
@router.post("/{asset_id}/status", response_model=AssetResponse)
def change_asset_status(
asset_id: int,
status_transition: AssetStatusTransition,
db: Session = Depends(get_db),
current_user = Depends(get_current_user)
):
"""
变更资产状态
- **asset_id**: 资产ID
- **new_status**: 目标状态
- **remark**: 备注
- **extra_data**: 额外数据
状态说明:
- pending: 待入库
- in_stock: 库存中
- in_use: 使用中
- transferring: 调拨中
- maintenance: 维修中
- pending_scrap: 待报废
- scrapped: 已报废
- lost: 已丢失
"""
return asset_service.change_asset_status(
db=db,
asset_id=asset_id,
status_transition=status_transition,
operator_id=current_user.id,
operator_name=current_user.real_name
)
@router.get("/{asset_id}/history", response_model=List[AssetStatusHistoryResponse])
def get_asset_status_history(
asset_id: int,
skip: int = Query(0, ge=0, description="跳过条数"),
limit: int = Query(50, ge=1, le=100, description="返回条数"),
db: Session = Depends(get_db),
current_user = Depends(get_current_user)
):
"""
获取资产状态历史
- **asset_id**: 资产ID
- **skip**: 跳过条数
- **limit**: 返回条数
返回资产的所有状态变更记录
"""
return asset_service.get_asset_status_history(db, asset_id, skip, limit)