调整部分前端布局和后端增删改逻辑
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
"""首页运营驾驶舱接口。"""
|
||||
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Request, Response
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from common.aspect.db_seesion import DBSessionDependency
|
||||
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
|
||||
from common.router import APIRouterPro
|
||||
from common.vo import PageResponseModel
|
||||
from module_admin.entity.vo.user_vo import CurrentUserModel
|
||||
from module_business.entity.vo.dashboard_vo import ScanExceptionModel
|
||||
from module_business.service.dashboard_service import DashboardService
|
||||
from utils.response_util import ResponseUtil
|
||||
|
||||
|
||||
dashboard_controller = APIRouterPro(
|
||||
prefix='/business/dashboard',
|
||||
tags=['业务管理-运营驾驶舱'],
|
||||
dependencies=[PreAuthDependency()],
|
||||
)
|
||||
|
||||
|
||||
@dashboard_controller.get(
|
||||
'/scan-exceptions',
|
||||
summary='获取首页扫码异常分页列表接口',
|
||||
description='普通用户仅查看本人扫码异常,超级管理员查看全部扫码异常',
|
||||
response_model=PageResponseModel[ScanExceptionModel],
|
||||
)
|
||||
async def get_business_dashboard_scan_exceptions(
|
||||
request: Request,
|
||||
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||
) -> Response:
|
||||
result = await DashboardService.get_scan_exception_list_services(query_db, current_user)
|
||||
return ResponseUtil.success(model_content=result)
|
||||
@@ -78,6 +78,13 @@ async def get_business_filling_strain_options(
|
||||
response_model=DataResponseModel[PalletScanResponseModel],
|
||||
dependencies=[UserInterfaceAuthDependency('business:filling:query')],
|
||||
)
|
||||
@Log(
|
||||
title='扫码操作',
|
||||
business_type=BusinessType.OTHER,
|
||||
request_log_mode='none',
|
||||
response_log_mode='summary',
|
||||
oper_url_mode='route',
|
||||
)
|
||||
async def scan_business_filling_pallet(
|
||||
request: Request,
|
||||
qr_token: Annotated[
|
||||
|
||||
@@ -81,6 +81,13 @@ async def get_business_inbound_warehouse_options(
|
||||
response_model=DataResponseModel[PalletScanResponseModel],
|
||||
dependencies=[UserInterfaceAuthDependency('business:inbound:query')],
|
||||
)
|
||||
@Log(
|
||||
title='扫码操作',
|
||||
business_type=BusinessType.OTHER,
|
||||
request_log_mode='none',
|
||||
response_log_mode='summary',
|
||||
oper_url_mode='route',
|
||||
)
|
||||
async def scan_business_inbound_pallet(
|
||||
request: Request,
|
||||
qr_token: Annotated[
|
||||
|
||||
@@ -82,6 +82,13 @@ async def get_business_return_warehouse_options(
|
||||
response_model=DataResponseModel[PalletScanResponseModel],
|
||||
dependencies=[UserInterfaceAuthDependency('business:return:query')],
|
||||
)
|
||||
@Log(
|
||||
title='扫码操作',
|
||||
business_type=BusinessType.OTHER,
|
||||
request_log_mode='none',
|
||||
response_log_mode='summary',
|
||||
oper_url_mode='route',
|
||||
)
|
||||
async def scan_business_return_pallet(
|
||||
request: Request,
|
||||
qr_token: Annotated[
|
||||
|
||||
@@ -98,6 +98,13 @@ async def get_business_shipment_site_options(
|
||||
response_model=DataResponseModel[PalletScanResponseModel],
|
||||
dependencies=[UserInterfaceAuthDependency('business:shipment:query')],
|
||||
)
|
||||
@Log(
|
||||
title='扫码操作',
|
||||
business_type=BusinessType.OTHER,
|
||||
request_log_mode='none',
|
||||
response_log_mode='summary',
|
||||
oper_url_mode='route',
|
||||
)
|
||||
async def scan_business_shipment_pallet(
|
||||
request: Request,
|
||||
qr_token: Annotated[
|
||||
|
||||
@@ -82,6 +82,13 @@ async def get_business_usage_line_options(
|
||||
response_model=DataResponseModel[PalletScanResponseModel],
|
||||
dependencies=[UserInterfaceAuthDependency('business:usage:query')],
|
||||
)
|
||||
@Log(
|
||||
title='扫码操作',
|
||||
business_type=BusinessType.OTHER,
|
||||
request_log_mode='none',
|
||||
response_log_mode='summary',
|
||||
oper_url_mode='route',
|
||||
)
|
||||
async def scan_business_usage_pallet(
|
||||
request: Request,
|
||||
qr_token: Annotated[
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from pydantic.alias_generators import to_camel
|
||||
|
||||
|
||||
class ScanExceptionModel(BaseModel):
|
||||
"""首页扫码异常记录。"""
|
||||
|
||||
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True, populate_by_name=True)
|
||||
|
||||
oper_id: int = Field(gt=0, description='异常日志ID')
|
||||
source: str = Field(min_length=1, max_length=50, description='扫码来源')
|
||||
error_message: str = Field(min_length=1, max_length=2000, description='异常消息')
|
||||
operator_name: str = Field(min_length=1, max_length=50, description='操作人员')
|
||||
occurred_at: datetime | None = Field(default=None, description='异常时间')
|
||||
@@ -0,0 +1,73 @@
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from common.vo import PageModel
|
||||
from exceptions.exception import ServiceException
|
||||
from module_admin.dao.log_dao import OperationLogDao
|
||||
from module_admin.entity.vo.user_vo import CurrentUserModel
|
||||
from module_business.entity.vo.dashboard_vo import ScanExceptionModel
|
||||
|
||||
|
||||
class DashboardService:
|
||||
"""首页运营驾驶舱数据服务。"""
|
||||
|
||||
_SCAN_EXCEPTION_LIMIT = 5
|
||||
_SCAN_SOURCE_LABELS = {
|
||||
'/business/inbound/scan/{qr_token}': '首次入库扫码',
|
||||
'/business/filling/scan/{qr_token}': '托盘装填扫码',
|
||||
'/business/shipment/scan/{qr_token}': '整托发货扫码',
|
||||
'/business/usage/scan/{qr_token}': '托盘使用扫码',
|
||||
'/business/return/scan/{qr_token}': '托盘退回扫码',
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _row_value(row: Any, *keys: str) -> Any:
|
||||
if isinstance(row, dict):
|
||||
for key in keys:
|
||||
if key in row:
|
||||
return row[key]
|
||||
return None
|
||||
for key in keys:
|
||||
value = getattr(row, key, None)
|
||||
if value is not None:
|
||||
return value
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def _scan_source(cls, oper_url: str | None) -> str:
|
||||
if not oper_url:
|
||||
return '扫码接口'
|
||||
for route_path, label in cls._SCAN_SOURCE_LABELS.items():
|
||||
route_prefix = route_path.split('/{', 1)[0]
|
||||
if oper_url == route_path or oper_url.startswith(f'{route_prefix}/'):
|
||||
return label
|
||||
return '扫码接口'
|
||||
|
||||
@classmethod
|
||||
async def get_scan_exception_list_services(
|
||||
cls, query_db: AsyncSession, current_user: CurrentUserModel
|
||||
) -> PageModel[ScanExceptionModel]:
|
||||
"""按用户范围获取首页最近扫码异常。"""
|
||||
if current_user.user is None or not current_user.user.user_name:
|
||||
raise ServiceException(message='当前用户信息无效')
|
||||
|
||||
oper_name = None if current_user.user.admin else current_user.user.user_name
|
||||
page = await OperationLogDao.get_scan_exception_log_list(query_db, oper_name, cls._SCAN_EXCEPTION_LIMIT)
|
||||
rows = [
|
||||
ScanExceptionModel(
|
||||
oper_id=cls._row_value(row, 'operId', 'oper_id'),
|
||||
source=cls._scan_source(cls._row_value(row, 'operUrl', 'oper_url')),
|
||||
error_message=cls._row_value(row, 'errorMsg', 'error_msg') or '扫码请求失败',
|
||||
operator_name=cls._row_value(row, 'operName', 'oper_name') or '未知用户',
|
||||
occurred_at=cls._row_value(row, 'operTime', 'oper_time'),
|
||||
)
|
||||
for row in page.rows
|
||||
]
|
||||
return PageModel[ScanExceptionModel](
|
||||
rows=rows,
|
||||
pageNum=page.page_num,
|
||||
pageSize=page.page_size,
|
||||
total=page.total,
|
||||
hasNext=page.has_next,
|
||||
)
|
||||
Reference in New Issue
Block a user