721 lines
25 KiB
Python
721 lines
25 KiB
Python
#!/usr/bin/env python
|
||
# -*- coding: utf-8 -*-
|
||
|
||
"""
|
||
库位管理API路由
|
||
实现库位的管理功能
|
||
"""
|
||
|
||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||
from sqlalchemy.orm import Session
|
||
from typing import Any, Dict, Optional
|
||
|
||
from data.session import get_db
|
||
from services.operate_point_service import OperatePointService
|
||
from routes.model.base import ApiResponse
|
||
from routes.model.operate_point_model import (
|
||
# OperatePointListRequest, OperatePointListResponse,
|
||
StorageLocationListRequest, StorageLocationListResponse,
|
||
StorageLocationStatusUpdateRequest, StorageLocationStatusUpdateResponse,
|
||
BatchStorageLocationStatusUpdateRequest, BatchStorageLocationStatusUpdateResponse,
|
||
StorageLocationActionEnum,
|
||
# StorageAreaTypeEnum
|
||
ExtendedPropertyCreateRequest, ExtendedPropertyCreateResponse,
|
||
ExtendedPropertyListRequest, ExtendedPropertyListResponse,
|
||
ExtendedPropertyDeleteResponse,
|
||
StorageLocationDetailResponse, StorageLocationEditRequest, StorageLocationEditResponse,
|
||
StorageLocationLogListRequest, StorageLocationLogListResponse,
|
||
)
|
||
from routes.common_api import format_response, error_response
|
||
from utils.logger import get_logger
|
||
from data.models import OperatePointLayer
|
||
from data.models import OperatePoint # Added missing import
|
||
|
||
# 创建路由
|
||
router = APIRouter(prefix="/api/vwed-operate-point", tags=["动作点管理"])
|
||
|
||
# 设置日志
|
||
logger = get_logger("app.operate_point_api")
|
||
|
||
|
||
def get_action_descriptions():
|
||
"""获取操作类型的说明文档"""
|
||
descriptions = {
|
||
StorageLocationActionEnum.OCCUPY: "占用库位",
|
||
StorageLocationActionEnum.RELEASE: "释放库位",
|
||
StorageLocationActionEnum.LOCK: "锁定库位(需要提供锁定者)",
|
||
StorageLocationActionEnum.UNLOCK: "解锁库位",
|
||
StorageLocationActionEnum.ENABLE: "启用库位",
|
||
StorageLocationActionEnum.DISABLE: "禁用库位",
|
||
StorageLocationActionEnum.SET_EMPTY_TRAY: "设置为空托盘",
|
||
StorageLocationActionEnum.CLEAR_EMPTY_TRAY: "清除空托盘状态"
|
||
}
|
||
return descriptions
|
||
|
||
|
||
# 标准API响应格式
|
||
def api_response(code: int = 200, message: str = "操作成功", data: Any = None) -> Dict[str, Any]:
|
||
"""
|
||
标准API响应格式
|
||
|
||
Args:
|
||
code: 状态码
|
||
message: 响应消息
|
||
data: 响应数据
|
||
|
||
Returns:
|
||
Dict[str, Any]: 格式化的响应数据
|
||
"""
|
||
return {
|
||
"code": code,
|
||
"message": message,
|
||
"data": data
|
||
}
|
||
|
||
|
||
@router.get("/list", response_model=ApiResponse[StorageLocationListResponse])
|
||
async def get_storage_location_list(
|
||
scene_id: Optional[str] = Query(None, description="场景ID"),
|
||
storage_area_id: Optional[str] = Query(None, description="库区ID"),
|
||
station_name: Optional[str] = Query(None, description="站点名称(支持模糊搜索)"),
|
||
layer_name: Optional[str] = Query(None, description="层名称(支持模糊搜索)"),
|
||
is_disabled: Optional[bool] = Query(None, description="是否禁用"),
|
||
is_occupied: Optional[bool] = Query(None, description="是否占用"),
|
||
is_locked: Optional[bool] = Query(None, description="是否锁定"),
|
||
is_empty_tray: Optional[bool] = Query(None, description="是否空托盘"),
|
||
include_operate_point_info: bool = Query(True, description="是否包含动作点信息"),
|
||
include_extended_fields: bool = Query(True, description="是否包含扩展字段"),
|
||
page: int = Query(1, ge=1, description="页码"),
|
||
page_size: int = Query(20, ge=1, le=100, description="每页数量"),
|
||
db: Session = Depends(get_db)
|
||
):
|
||
"""
|
||
获取库位列表
|
||
|
||
库位基于动作点分层(OperatePointLayer),每一层对应一个库位。
|
||
|
||
支持多种筛选条件:
|
||
- 场景ID:根据场景筛选库位
|
||
- 库区ID:根据库区筛选库位
|
||
- 站点名称:支持模糊搜索
|
||
- 层名称:支持模糊搜索
|
||
- 是否禁用:筛选禁用/启用的库位
|
||
- 是否占用:筛选已占用/空闲的库位
|
||
- 是否锁定:筛选锁定/解锁的库位
|
||
- 是否空托盘:筛选空托盘/非空托盘的库位
|
||
- 是否包含动作点信息:控制返回数据是否包含所属动作点的详细信息
|
||
- 是否包含扩展字段:控制返回数据是否包含自定义扩展字段
|
||
|
||
返回数据包含:
|
||
- 库位基本信息(ID、层索引、层名称等)
|
||
- 库位状态(是否占用、锁定、禁用、空托盘等)
|
||
- 货物信息(货物内容、重量、体积等)
|
||
- 库位规格(最大承重、最大体积、层高等)
|
||
- 动作点信息(如果启用include_operate_point_info)
|
||
- 扩展字段(如果启用include_extended_fields)
|
||
- 统计信息(总数、各种状态的数量、使用率等)
|
||
|
||
Args:
|
||
scene_id: 场景ID
|
||
storage_area_id: 库区ID
|
||
station_name: 站点名称
|
||
layer_name: 层名称
|
||
is_disabled: 是否禁用
|
||
is_occupied: 是否占用
|
||
is_locked: 是否锁定
|
||
is_empty_tray: 是否空托盘
|
||
include_operate_point_info: 是否包含动作点信息
|
||
include_extended_fields: 是否包含扩展字段
|
||
page: 页码
|
||
page_size: 每页数量
|
||
db: 数据库会话
|
||
|
||
Returns:
|
||
ApiResponse[StorageLocationListResponse]: 库位列表响应
|
||
"""
|
||
try:
|
||
# 构建请求对象
|
||
request = StorageLocationListRequest(
|
||
scene_id=scene_id,
|
||
storage_area_id=storage_area_id,
|
||
station_name=station_name,
|
||
layer_name=layer_name,
|
||
is_disabled=is_disabled,
|
||
is_occupied=is_occupied,
|
||
is_locked=is_locked,
|
||
is_empty_tray=is_empty_tray,
|
||
include_operate_point_info=include_operate_point_info,
|
||
include_extended_fields=include_extended_fields,
|
||
page=page,
|
||
page_size=page_size
|
||
)
|
||
|
||
# 调用服务层方法获取库位列表
|
||
result = OperatePointService.get_storage_location_list(db=db, request=request)
|
||
|
||
return api_response(message="查询成功", data=result)
|
||
|
||
except ValueError as e:
|
||
# 数据验证错误
|
||
return error_response(str(e), 400)
|
||
|
||
except Exception as e:
|
||
logger.error(f"获取库位列表失败: {str(e)}")
|
||
return error_response(f"获取库位列表失败: {str(e)}", 500)
|
||
|
||
|
||
|
||
@router.put("/status", response_model=ApiResponse[StorageLocationStatusUpdateResponse])
|
||
async def update_storage_location_status(
|
||
request: StorageLocationStatusUpdateRequest,
|
||
db: Session = Depends(get_db)
|
||
):
|
||
"""
|
||
更新库位状态
|
||
|
||
支持的操作类型:
|
||
- occupy: 占用库位
|
||
- release: 释放库位
|
||
- lock: 锁定库位(需要提供锁定者)
|
||
- unlock: 解锁库位
|
||
- enable: 启用库位
|
||
- disable: 禁用库位
|
||
- set_empty_tray: 设置为空托盘
|
||
- clear_empty_tray: 清除空托盘状态
|
||
|
||
Args:
|
||
request: 库位状态更新请求
|
||
db: 数据库会话
|
||
|
||
Returns:
|
||
ApiResponse[StorageLocationStatusUpdateResponse]: 状态更新响应
|
||
"""
|
||
try:
|
||
# 验证操作类型 - 使用枚举类型
|
||
valid_actions = [action.value for action in StorageLocationActionEnum]
|
||
if request.action not in valid_actions:
|
||
return error_response(f"不支持的操作类型: {request.action},支持的操作:{', '.join(valid_actions)}", 400)
|
||
|
||
# 锁定操作必须提供锁定者
|
||
if request.action == StorageLocationActionEnum.LOCK and not request.locked_by:
|
||
return error_response("锁定操作必须提供锁定者", 400)
|
||
|
||
# 调用服务层方法
|
||
result = OperatePointService.update_storage_location_status(db=db, request=request)
|
||
|
||
return api_response(message="状态更新完成", data=result)
|
||
|
||
except ValueError as e:
|
||
return error_response(str(e), 400)
|
||
|
||
except Exception as e:
|
||
logger.error(f"更新库位状态失败: {str(e)}")
|
||
return error_response(f"更新库位状态失败: {str(e)}", 500)
|
||
|
||
|
||
@router.put("/batch-status", response_model=ApiResponse[BatchStorageLocationStatusUpdateResponse])
|
||
async def batch_update_storage_location_status(
|
||
request: BatchStorageLocationStatusUpdateRequest,
|
||
db: Session = Depends(get_db)
|
||
):
|
||
"""
|
||
批量更新库位状态
|
||
|
||
支持的操作类型:
|
||
- occupy: 占用库位
|
||
- release: 释放库位
|
||
- lock: 锁定库位(需要提供锁定者)
|
||
- unlock: 解锁库位
|
||
- enable: 启用库位
|
||
- disable: 禁用库位
|
||
- set_empty_tray: 设置为空托盘
|
||
- clear_empty_tray: 清除空托盘状态
|
||
|
||
Args:
|
||
request: 批量库位状态更新请求
|
||
db: 数据库会话
|
||
|
||
Returns:
|
||
ApiResponse[BatchStorageLocationStatusUpdateResponse]: 批量状态更新响应
|
||
"""
|
||
try:
|
||
# 验证操作类型 - 使用枚举类型
|
||
valid_actions = [action.value for action in StorageLocationActionEnum]
|
||
if request.action not in valid_actions:
|
||
return error_response(f"不支持的操作类型: {request.action},支持的操作:{', '.join(valid_actions)}", 400)
|
||
|
||
# 锁定操作必须提供锁定者
|
||
if request.action == StorageLocationActionEnum.LOCK and not request.locked_by:
|
||
return error_response("锁定操作必须提供锁定者", 400)
|
||
|
||
# 验证库位名称列表
|
||
if not request.layer_names:
|
||
return error_response("库位名称列表不能为空", 400)
|
||
|
||
if len(request.layer_names) > 100:
|
||
return error_response("批量操作的库位数量不能超过100个", 400)
|
||
|
||
# 调用服务层方法
|
||
result = OperatePointService.batch_update_storage_location_status(db=db, request=request)
|
||
|
||
# 构建更详细的响应消息
|
||
success_details = []
|
||
if result.success_count > 0:
|
||
success_details.append(f"成功操作 {result.success_count} 个库位")
|
||
if result.failed_count > 0:
|
||
success_details.append(f"失败操作 {result.failed_count} 个库位")
|
||
|
||
# 统计无需更改的操作
|
||
no_change_count = sum(1 for r in result.results
|
||
if r.success and "无需重复操作" in r.message)
|
||
actual_update_count = result.success_count - no_change_count
|
||
|
||
if no_change_count > 0:
|
||
success_details.append(f"其中 {no_change_count} 个库位已是目标状态")
|
||
if actual_update_count > 0:
|
||
success_details.append(f"实际更新 {actual_update_count} 个库位")
|
||
|
||
detailed_message = f"批量状态更新完成:{', '.join(success_details)}"
|
||
|
||
return api_response(message=detailed_message, data=result)
|
||
|
||
except ValueError as e:
|
||
return error_response(str(e), 400)
|
||
|
||
except Exception as e:
|
||
logger.error(f"批量更新库位状态失败: {str(e)}")
|
||
return error_response(f"批量更新库位状态失败: {str(e)}", 500)
|
||
|
||
|
||
@router.get("/actions")
|
||
async def get_supported_actions():
|
||
"""
|
||
获取支持的操作类型列表
|
||
|
||
Returns:
|
||
ApiResponse: 支持的操作类型列表及其说明
|
||
"""
|
||
try:
|
||
descriptions = get_action_descriptions()
|
||
|
||
actions = []
|
||
for action_enum in StorageLocationActionEnum:
|
||
actions.append({
|
||
"value": action_enum.value,
|
||
"description": descriptions.get(action_enum, "")
|
||
})
|
||
|
||
return api_response(
|
||
message="获取支持的操作类型成功",
|
||
data={
|
||
"actions": actions,
|
||
"count": len(actions)
|
||
}
|
||
)
|
||
|
||
except Exception as e:
|
||
logger.error(f"获取支持的操作类型失败: {str(e)}")
|
||
return error_response(f"获取支持的操作类型失败: {str(e)}", 500)
|
||
|
||
|
||
@router.get("/{layer_name}/status")
|
||
async def get_storage_location_status(
|
||
layer_name: str,
|
||
db: Session = Depends(get_db)
|
||
):
|
||
"""
|
||
获取单个库位状态信息
|
||
|
||
Args:
|
||
layer_name: 库位名称
|
||
db: 数据库会话
|
||
|
||
Returns:
|
||
ApiResponse: 库位状态信息
|
||
"""
|
||
try:
|
||
# 查询库位
|
||
storage_location = db.query(OperatePointLayer).filter(
|
||
OperatePointLayer.layer_name == layer_name,
|
||
OperatePointLayer.is_deleted == False
|
||
).first()
|
||
|
||
if not storage_location:
|
||
return error_response("库位不存在", 404)
|
||
|
||
# 获取状态信息
|
||
status = OperatePointService._get_storage_location_status(storage_location)
|
||
|
||
return api_response(message="查询成功", data=status)
|
||
|
||
except Exception as e:
|
||
logger.error(f"获取库位状态失败: {str(e)}")
|
||
return error_response(f"获取库位状态失败: {str(e)}", 500)
|
||
|
||
|
||
# 扩展属性管理接口
|
||
@router.post("/extended-properties", response_model=ApiResponse[ExtendedPropertyCreateResponse])
|
||
async def create_extended_property(
|
||
request: ExtendedPropertyCreateRequest,
|
||
db: Session = Depends(get_db)
|
||
):
|
||
"""
|
||
创建扩展属性
|
||
|
||
用于创建新的扩展属性定义,这些属性可以在库位管理中使用。
|
||
|
||
重要提示:
|
||
- 创建扩展属性后,会自动将该属性添加到所有现有的库位层中
|
||
- 每个库位层的config_json会自动更新,包含新的扩展属性配置
|
||
- 新属性会使用指定的默认值进行初始化
|
||
|
||
支持的属性类型:
|
||
- string: 字符串
|
||
- integer: 整数
|
||
- float: 浮点数
|
||
- boolean: 布尔值
|
||
- date: 日期
|
||
- datetime: 日期时间
|
||
- text: 长文本
|
||
- select: 下拉选择
|
||
- multiselect: 多选
|
||
|
||
Args:
|
||
request: 扩展属性创建请求
|
||
db: 数据库会话
|
||
|
||
Returns:
|
||
ApiResponse[ExtendedPropertyCreateResponse]: 创建响应
|
||
"""
|
||
try:
|
||
# 调用服务层方法
|
||
result = OperatePointService.create_extended_property(db=db, request=request)
|
||
|
||
return api_response(message="扩展属性创建成功", data=result)
|
||
|
||
except ValueError as e:
|
||
return error_response(str(e), 400)
|
||
|
||
except Exception as e:
|
||
logger.error(f"创建扩展属性失败: {str(e)}")
|
||
return error_response(f"创建扩展属性失败: {str(e)}", 500)
|
||
|
||
|
||
@router.get("/extended-properties", response_model=ApiResponse[ExtendedPropertyListResponse])
|
||
async def get_extended_property_list(
|
||
property_name: Optional[str] = Query(None, description="属性名称(支持模糊搜索)"),
|
||
property_type: Optional[str] = Query(None, description="属性类型"),
|
||
category: Optional[str] = Query(None, description="属性分类"),
|
||
is_enabled: Optional[bool] = Query(None, description="是否启用"),
|
||
page: int = Query(1, ge=1, description="页码"),
|
||
page_size: int = Query(20, ge=1, le=100, description="每页数量"),
|
||
db: Session = Depends(get_db)
|
||
):
|
||
"""
|
||
获取扩展属性列表
|
||
|
||
支持多种筛选条件:
|
||
- 属性名称:支持模糊搜索
|
||
- 属性类型:精确匹配
|
||
- 属性分类:精确匹配
|
||
- 是否启用:筛选启用/禁用的属性
|
||
|
||
返回数据包含:
|
||
- 属性基本信息(ID、名称、类型等)
|
||
- 属性设置(是否必填、是否启用等)
|
||
- 验证规则和选项配置
|
||
- 显示设置(宽度、格式等)
|
||
- 创建和更新时间
|
||
|
||
Args:
|
||
property_name: 属性名称
|
||
property_type: 属性类型
|
||
category: 属性分类
|
||
is_enabled: 是否启用
|
||
page: 页码
|
||
page_size: 每页数量
|
||
db: 数据库会话
|
||
|
||
Returns:
|
||
ApiResponse[ExtendedPropertyListResponse]: 属性列表响应
|
||
"""
|
||
try:
|
||
# 构建请求对象
|
||
request = ExtendedPropertyListRequest(
|
||
property_name=property_name,
|
||
property_type=property_type,
|
||
category=category,
|
||
is_enabled=is_enabled,
|
||
page=page,
|
||
page_size=page_size
|
||
)
|
||
|
||
# 调用服务层方法
|
||
result = OperatePointService.get_extended_property_list(db=db, request=request)
|
||
|
||
return api_response(message="查询成功", data=result)
|
||
|
||
except ValueError as e:
|
||
return error_response(str(e), 400)
|
||
|
||
except Exception as e:
|
||
logger.error(f"获取扩展属性列表失败: {str(e)}")
|
||
return error_response(f"获取扩展属性列表失败: {str(e)}", 500)
|
||
|
||
|
||
@router.delete("/extended-properties/{property_id}", response_model=ApiResponse[ExtendedPropertyDeleteResponse])
|
||
async def delete_extended_property(
|
||
property_id: str,
|
||
db: Session = Depends(get_db)
|
||
):
|
||
"""
|
||
删除扩展属性
|
||
|
||
删除指定的扩展属性(软删除)。
|
||
|
||
重要提示:
|
||
- 删除扩展属性后,会自动从所有现有的库位层中移除该属性
|
||
- 每个库位层的config_json会自动更新,清除已删除的扩展属性配置
|
||
- 此操作会影响所有库位的扩展属性数据
|
||
|
||
注意:此操作不可逆,请谨慎使用。
|
||
|
||
Args:
|
||
property_id: 属性ID
|
||
db: 数据库会话
|
||
|
||
Returns:
|
||
ApiResponse[ExtendedPropertyDeleteResponse]: 删除响应
|
||
"""
|
||
try:
|
||
# 调用服务层方法
|
||
result = OperatePointService.delete_extended_property(db=db, property_id=property_id)
|
||
|
||
return api_response(message="扩展属性删除成功", data=result)
|
||
|
||
except ValueError as e:
|
||
return error_response(str(e), 400)
|
||
|
||
except Exception as e:
|
||
logger.error(f"删除扩展属性失败: {str(e)}")
|
||
return error_response(f"删除扩展属性失败: {str(e)}", 500)
|
||
|
||
|
||
# @router.get("/extended-properties/types")
|
||
# async def get_extended_property_types():
|
||
# """
|
||
# 获取支持的扩展属性类型列表
|
||
|
||
# 返回系统支持的所有扩展属性类型及其说明。
|
||
|
||
# Returns:
|
||
# ApiResponse: 支持的属性类型列表
|
||
# """
|
||
# try:
|
||
# from data.models.extended_property import ExtendedPropertyTypeEnum
|
||
|
||
# # 属性类型说明
|
||
# type_descriptions = {
|
||
# ExtendedPropertyTypeEnum.STRING: "字符串 - 适用于短文本输入",
|
||
# ExtendedPropertyTypeEnum.INTEGER: "整数 - 适用于整数值",
|
||
# ExtendedPropertyTypeEnum.FLOAT: "浮点数 - 适用于小数值",
|
||
# ExtendedPropertyTypeEnum.BOOLEAN: "布尔值 - 适用于是/否选择",
|
||
# ExtendedPropertyTypeEnum.DATE: "日期 - 适用于日期选择",
|
||
# ExtendedPropertyTypeEnum.DATETIME: "日期时间 - 适用于日期和时间选择",
|
||
# ExtendedPropertyTypeEnum.TEXT: "长文本 - 适用于多行文本输入",
|
||
# ExtendedPropertyTypeEnum.SELECT: "下拉选择 - 适用于单选择",
|
||
# ExtendedPropertyTypeEnum.MULTISELECT: "多选 - 适用于多选择"
|
||
# }
|
||
|
||
# types = []
|
||
# for type_enum in ExtendedPropertyTypeEnum:
|
||
# types.append({
|
||
# "value": type_enum.value,
|
||
# "description": type_descriptions.get(type_enum, "")
|
||
# })
|
||
|
||
# return api_response(
|
||
# message="获取扩展属性类型成功",
|
||
# data={
|
||
# "types": types,
|
||
# "count": len(types)
|
||
# }
|
||
# )
|
||
|
||
# except Exception as e:
|
||
# logger.error(f"获取扩展属性类型失败: {str(e)}")
|
||
# return error_response(f"获取扩展属性类型失败: {str(e)}", 500)
|
||
|
||
|
||
@router.get("/operation-logs", response_model=ApiResponse[StorageLocationLogListResponse])
|
||
async def get_storage_location_operation_logs(
|
||
layer_name: Optional[str] = Query(None, description="库位名称"),
|
||
operator: Optional[str] = Query(None, description="操作人(支持模糊搜索)"),
|
||
operation_type: Optional[str] = Query(None, description="操作类型"),
|
||
start_time: Optional[str] = Query(None, description="开始时间 (格式: YYYY-MM-DD HH:MM:SS)"),
|
||
end_time: Optional[str] = Query(None, description="结束时间 (格式: YYYY-MM-DD HH:MM:SS)"),
|
||
page: int = Query(1, ge=1, description="页码"),
|
||
page_size: int = Query(20, ge=1, le=100, description="每页数量"),
|
||
db: Session = Depends(get_db)
|
||
):
|
||
"""
|
||
获取库位操作记录列表
|
||
|
||
获取库位相关的操作记录,包括:
|
||
- 状态更新操作(占用、释放、锁定、解锁、启用、禁用等)
|
||
- 库位信息编辑操作
|
||
- 其他库位相关的操作
|
||
|
||
支持多种筛选条件:
|
||
- 库位名称:查询特定库位的操作记录
|
||
- 操作人:支持模糊搜索操作人姓名
|
||
- 操作类型:筛选特定类型的操作
|
||
- 时间范围:指定操作时间的开始和结束时间
|
||
|
||
操作记录按时间倒序排列(最新的操作在前)。
|
||
|
||
Args:
|
||
layer_name: 库位名称
|
||
operator: 操作人
|
||
operation_type: 操作类型
|
||
start_time: 开始时间
|
||
end_time: 结束时间
|
||
page: 页码
|
||
page_size: 每页数量
|
||
db: 数据库会话
|
||
|
||
Returns:
|
||
ApiResponse[StorageLocationLogListResponse]: 操作记录列表响应
|
||
"""
|
||
try:
|
||
# 时间格式转换
|
||
start_time_dt = None
|
||
end_time_dt = None
|
||
|
||
if start_time:
|
||
try:
|
||
from datetime import datetime
|
||
start_time_dt = datetime.strptime(start_time, "%Y-%m-%d %H:%M:%S")
|
||
except ValueError:
|
||
return error_response("开始时间格式错误,请使用格式:YYYY-MM-DD HH:MM:SS", 400)
|
||
|
||
if end_time:
|
||
try:
|
||
from datetime import datetime
|
||
end_time_dt = datetime.strptime(end_time, "%Y-%m-%d %H:%M:%S")
|
||
except ValueError:
|
||
return error_response("结束时间格式错误,请使用格式:YYYY-MM-DD HH:MM:SS", 400)
|
||
|
||
# 验证时间范围
|
||
if start_time_dt and end_time_dt and start_time_dt > end_time_dt:
|
||
return error_response("开始时间不能大于结束时间", 400)
|
||
|
||
# 构建请求对象
|
||
request = StorageLocationLogListRequest(
|
||
layer_name=layer_name,
|
||
operator=operator,
|
||
operation_type=operation_type,
|
||
start_time=start_time_dt,
|
||
end_time=end_time_dt,
|
||
page=page,
|
||
page_size=page_size
|
||
)
|
||
|
||
# 调用服务层方法
|
||
result = OperatePointService.get_storage_location_logs(db=db, request=request)
|
||
|
||
return api_response(message="查询操作记录成功", data=result)
|
||
|
||
except ValueError as e:
|
||
return error_response(str(e), 400)
|
||
|
||
except Exception as e:
|
||
logger.error(f"获取库位操作记录失败: {str(e)}")
|
||
return error_response(f"获取库位操作记录失败: {str(e)}", 500)
|
||
|
||
|
||
@router.get("/{layer_name}", response_model=ApiResponse[StorageLocationDetailResponse])
|
||
async def get_storage_location_detail(
|
||
layer_name: str,
|
||
db: Session = Depends(get_db)
|
||
):
|
||
"""
|
||
获取库位详情
|
||
|
||
获取指定库位的详细信息,包括:
|
||
- 库位基本信息和当前状态
|
||
- 动作点详细信息
|
||
- 扩展字段定义和值
|
||
- 状态变更历史记录
|
||
|
||
Args:
|
||
layer_name: 库位名称
|
||
db: 数据库会话
|
||
|
||
Returns:
|
||
ApiResponse[StorageLocationDetailResponse]: 库位详情响应
|
||
"""
|
||
try:
|
||
# 调用服务层方法
|
||
result = OperatePointService.get_storage_location_detail(db=db, layer_name=layer_name)
|
||
|
||
return api_response(message="获取库位详情成功", data=result)
|
||
|
||
except ValueError as e:
|
||
return error_response(str(e), 404)
|
||
|
||
except Exception as e:
|
||
logger.error(f"获取库位详情失败: {str(e)}")
|
||
return error_response(f"获取库位详情失败: {str(e)}", 500)
|
||
|
||
|
||
@router.put("/{layer_name}", response_model=ApiResponse[StorageLocationEditResponse])
|
||
async def edit_storage_location(
|
||
layer_name: str,
|
||
request: StorageLocationEditRequest,
|
||
db: Session = Depends(get_db)
|
||
):
|
||
"""
|
||
编辑库位信息
|
||
|
||
允许修改库位的各种属性,包括:
|
||
- 货物信息:货物内容、重量、体积等
|
||
- 库位规格:最大承重、最大体积、层高等
|
||
- 状态字段:是否锁定、是否禁用、是否空托盘
|
||
- 扩展字段:自定义的扩展属性值
|
||
- 其他属性:标签、描述等
|
||
|
||
注意:
|
||
- 只有传入的字段且值发生变化时才会被更新
|
||
- 层名称(layer_name)不能通过此接口修改
|
||
- 扩展字段必须在系统中已定义且已启用
|
||
- 如果所有字段都没有发生变化,会返回相应提示信息
|
||
|
||
Args:
|
||
layer_name: 库位名称
|
||
request: 库位编辑请求
|
||
db: 数据库会话
|
||
|
||
Returns:
|
||
ApiResponse[StorageLocationEditResponse]: 编辑响应
|
||
"""
|
||
try:
|
||
# 调用服务层方法
|
||
result = OperatePointService.edit_storage_location(
|
||
db=db,
|
||
layer_name=layer_name,
|
||
request=request
|
||
)
|
||
|
||
return api_response(message="库位信息编辑成功", data=result)
|
||
|
||
except ValueError as e:
|
||
return error_response(str(e), 400)
|
||
|
||
except Exception as e:
|
||
logger.error(f"编辑库位信息失败: {str(e)}")
|
||
return error_response(f"编辑库位信息失败: {str(e)}", 500)
|
||
|
||
|
||
|