252 lines
8.5 KiB
Python
252 lines
8.5 KiB
Python
from fastapi import APIRouter, Depends, HTTPException, status
|
||
from fastapi.responses import FileResponse, StreamingResponse
|
||
from sqlalchemy.orm import Session
|
||
from typing import Optional, Dict, Any
|
||
from ..core.database import get_db
|
||
from ..core.response_code import ResponseCode, ResponseMessage
|
||
from ..core.exceptions import BusinessException, DataNotFoundException, AccountNotFoundException
|
||
from ..schemas.export_excel import ExportExcelRequest, ExportSettlementRequest, ExportLevelDataRequest
|
||
from ..services.section_data import SectionDataService
|
||
from ..services.export_excel import ExportExcelService
|
||
import logging
|
||
import pandas as pd
|
||
from io import BytesIO
|
||
from datetime import datetime
|
||
import os
|
||
import tempfile
|
||
|
||
router = APIRouter(prefix="/export", tags=["数据导出"])
|
||
logger = logging.getLogger(__name__)
|
||
|
||
# 实例化服务类
|
||
section_service = SectionDataService()
|
||
export_excel_service = ExportExcelService()
|
||
|
||
@router.post("/section_data")
|
||
def export_section_data(
|
||
request: ExportExcelRequest,
|
||
db: Session = Depends(get_db)
|
||
):
|
||
"""导出断面数据为Excel文件"""
|
||
try:
|
||
logger.info(f"导出断面数据,请求参数: section_id={request.section_id}, account_id={request.account_id}")
|
||
|
||
result = section_service.search_sections_with_checkpoints(
|
||
db,
|
||
section_id=request.section_id,
|
||
mileage=request.mileage,
|
||
work_site=request.work_site,
|
||
number=request.number,
|
||
status=request.status,
|
||
account_id=request.account_id,
|
||
skip=0,
|
||
limit=10000 # 设置一个较大的限制值
|
||
)
|
||
|
||
data_list = result.get('data', [])
|
||
|
||
if not data_list:
|
||
logger.warning("未找到符合条件的断面数据")
|
||
return {
|
||
"code": ResponseCode.SUCCESS,
|
||
"message": "未找到符合条件的数据,无法导出",
|
||
"data": None
|
||
}
|
||
|
||
# 转换为DataFrame
|
||
df = pd.DataFrame(data_list)
|
||
|
||
# 生成文件名
|
||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||
filename = f"断面数据_{timestamp}.xlsx"
|
||
|
||
# 创建临时文件
|
||
temp_dir = tempfile.gettempdir()
|
||
file_path = os.path.join(temp_dir, filename)
|
||
|
||
# 保存Excel文件
|
||
with pd.ExcelWriter(file_path, engine='openpyxl') as writer:
|
||
df.to_excel(writer, index=False, sheet_name='断面数据')
|
||
|
||
# 获取工作表对象以便调整列宽
|
||
worksheet = writer.sheets['断面数据']
|
||
|
||
# 自动调整列宽
|
||
for column in worksheet.columns:
|
||
max_length = 0
|
||
column_letter = column[0].column_letter
|
||
for cell in column:
|
||
try:
|
||
if len(str(cell.value)) > max_length:
|
||
max_length = len(str(cell.value))
|
||
except:
|
||
pass
|
||
adjusted_width = min(max_length + 2, 50) # 最大宽度限制为50
|
||
worksheet.column_dimensions[column_letter].width = adjusted_width
|
||
|
||
logger.info(f"成功导出{len(data_list)}条断面数据,保存到文件: {file_path}")
|
||
|
||
# 返回文件下载响应
|
||
return FileResponse(
|
||
path=file_path,
|
||
filename=filename,
|
||
media_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||
)
|
||
|
||
except Exception as e:
|
||
logger.error(f"导出断面数据失败: {str(e)}", exc_info=True)
|
||
return {
|
||
"code": ResponseCode.EXPORT_FAILED,
|
||
"message": f"{ResponseMessage.EXPORT_FAILED}: {str(e)}",
|
||
"data": None
|
||
}
|
||
|
||
@router.post("/settlement_data")
|
||
def export_settlement_data(
|
||
request: ExportSettlementRequest,
|
||
db: Session = Depends(get_db)
|
||
):
|
||
"""导出沉降数据Excel文件(包含断面、观测点、水准数据)"""
|
||
try:
|
||
logger.info(f"导出沉降数据,请求参数: project_name={request.project_name}")
|
||
|
||
# 生成文件名
|
||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||
filename = f"{request.project_name}_沉降数据_{timestamp}.xlsx"
|
||
|
||
# 创建临时文件
|
||
temp_dir = tempfile.gettempdir()
|
||
file_path = os.path.join(temp_dir, filename)
|
||
|
||
# 调用服务层导出数据到文件
|
||
export_excel_service.export_settlement_data_to_file(
|
||
db,
|
||
project_name=request.project_name,
|
||
file_path=file_path
|
||
)
|
||
|
||
logger.info(f"成功生成沉降数据Excel文件: {file_path}")
|
||
|
||
# 返回文件下载响应
|
||
return FileResponse(
|
||
path=file_path,
|
||
filename=filename,
|
||
media_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||
)
|
||
|
||
except AccountNotFoundException as e:
|
||
logger.warning(f"账号不存在: {str(e)}")
|
||
raise HTTPException(
|
||
status_code=status.HTTP_404_NOT_FOUND,
|
||
detail={
|
||
"code": e.code,
|
||
"message": e.message,
|
||
"data": None
|
||
}
|
||
)
|
||
except DataNotFoundException as e:
|
||
logger.warning(f"数据不存在: {str(e)}")
|
||
raise HTTPException(
|
||
status_code=status.HTTP_404_NOT_FOUND,
|
||
detail={
|
||
"code": e.code,
|
||
"message": e.message,
|
||
"data": None
|
||
}
|
||
)
|
||
except BusinessException as e:
|
||
logger.warning(f"业务异常: {str(e)}")
|
||
raise HTTPException(
|
||
status_code=status.HTTP_400_BAD_REQUEST,
|
||
detail={
|
||
"code": e.code,
|
||
"message": e.message,
|
||
"data": None
|
||
}
|
||
)
|
||
except Exception as e:
|
||
logger.error(f"导出沉降数据失败: {str(e)}", exc_info=True)
|
||
raise HTTPException(
|
||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||
detail={
|
||
"code": ResponseCode.EXPORT_FAILED,
|
||
"message": f"{ResponseMessage.EXPORT_FAILED}: {str(e)}",
|
||
"data": None
|
||
}
|
||
)
|
||
|
||
@router.post("/level_data")
|
||
def export_level_data(
|
||
request: ExportLevelDataRequest,
|
||
db: Session = Depends(get_db)
|
||
):
|
||
"""导出水准数据Excel文件(以水准数据为主体,包含断面、观测点、沉降、原始数据)"""
|
||
try:
|
||
logger.info(f"导出水准数据,请求参数: project_name={request.project_name}")
|
||
|
||
# 生成文件名
|
||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||
filename = f"{request.project_name}_水准数据_{timestamp}.xlsx"
|
||
|
||
# 创建临时文件
|
||
temp_dir = tempfile.gettempdir()
|
||
file_path = os.path.join(temp_dir, filename)
|
||
|
||
# 调用服务层导出数据到文件
|
||
export_excel_service.export_level_data_to_file(
|
||
db,
|
||
project_name=request.project_name,
|
||
file_path=file_path
|
||
)
|
||
|
||
logger.info(f"成功生成水准数据Excel文件: {file_path}")
|
||
|
||
# 返回文件下载响应
|
||
return FileResponse(
|
||
path=file_path,
|
||
filename=filename,
|
||
media_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||
)
|
||
|
||
except AccountNotFoundException as e:
|
||
logger.warning(f"账号不存在: {str(e)}")
|
||
raise HTTPException(
|
||
status_code=status.HTTP_404_NOT_FOUND,
|
||
detail={
|
||
"code": e.code,
|
||
"message": e.message,
|
||
"data": None
|
||
}
|
||
)
|
||
except DataNotFoundException as e:
|
||
logger.warning(f"数据不存在: {str(e)}")
|
||
raise HTTPException(
|
||
status_code=status.HTTP_404_NOT_FOUND,
|
||
detail={
|
||
"code": e.code,
|
||
"message": e.message,
|
||
"data": None
|
||
}
|
||
)
|
||
except BusinessException as e:
|
||
logger.warning(f"业务异常: {str(e)}")
|
||
raise HTTPException(
|
||
status_code=status.HTTP_400_BAD_REQUEST,
|
||
detail={
|
||
"code": e.code,
|
||
"message": e.message,
|
||
"data": None
|
||
}
|
||
)
|
||
except Exception as e:
|
||
logger.error(f"导出水准数据失败: {str(e)}", exc_info=True)
|
||
raise HTTPException(
|
||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||
detail={
|
||
"code": ResponseCode.EXPORT_FAILED,
|
||
"message": f"{ResponseMessage.EXPORT_FAILED}: {str(e)}",
|
||
"data": None
|
||
}
|
||
)
|
||
|