- 修复前端路由守卫:未登录时不显示提示,直接跳转登录页 - 修复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>
333 lines
10 KiB
Python
333 lines
10 KiB
Python
"""
|
|
资产分配相关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()
|