fix_bug_log-export_格式和乱码

This commit is contained in:
superlishunqin 2025-05-17 00:11:20 +08:00
parent 0378834133
commit 772748eaae
2 changed files with 103 additions and 16 deletions

View File

@ -93,16 +93,13 @@ def log_detail(log_id):
@permission_required('view_logs') # 替代 @admin_required @permission_required('view_logs') # 替代 @admin_required
def export_logs(): def export_logs():
"""导出日志API""" """导出日志API"""
import csv
from io import StringIO
from flask import Response
data = request.get_json() data = request.get_json()
user_id = data.get('user_id') user_id = data.get('user_id')
action = data.get('action') action = data.get('action')
target_type = data.get('target_type') target_type = data.get('target_type')
start_date_str = data.get('start_date') start_date_str = data.get('start_date')
end_date_str = data.get('end_date') end_date_str = data.get('end_date')
export_format = data.get('format', 'csv') # 获取导出格式参数
# 处理日期范围 # 处理日期范围
start_date = None start_date = None
@ -129,9 +126,35 @@ def export_logs():
logs = query.all() logs = query.all()
# 生成CSV文件 try:
si = StringIO() # 根据格式选择导出方法
csv_writer = csv.writer(si) if export_format == 'xlsx':
return export_as_xlsx(logs)
else:
return export_as_csv(logs)
except Exception as e:
# 记录错误以便调试
import traceback
error_details = traceback.format_exc()
current_app.logger.error(f"Export error: {str(e)}\n{error_details}")
return jsonify({
'success': False,
'message': f'导出失败: {str(e)}'
}), 500
def export_as_csv(logs):
"""导出为CSV格式"""
import csv
from io import StringIO
import base64
# 创建CSV文件
output = StringIO()
output.write('\ufeff') # 添加BOM标记解决Excel中文乱码
csv_writer = csv.writer(output)
# 写入标题行 # 写入标题行
csv_writer.writerow(['ID', '用户', '操作类型', '目标类型', '目标ID', 'IP地址', '描述', '创建时间']) csv_writer.writerow(['ID', '用户', '操作类型', '目标类型', '目标ID', 'IP地址', '描述', '创建时间'])
@ -150,25 +173,88 @@ def export_logs():
log.created_at.strftime('%Y-%m-%d %H:%M:%S') log.created_at.strftime('%Y-%m-%d %H:%M:%S')
]) ])
# 设置响应头,使浏览器将其识别为下载文件 # 获取CSV字符串并进行Base64编码
csv_string = output.getvalue()
csv_bytes = csv_string.encode('utf-8')
b64_encoded = base64.b64encode(csv_bytes).decode('utf-8')
# 设置文件名
filename = f"system_logs_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv" filename = f"system_logs_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
output = si.getvalue()
# 返回Base64编码的CSV数据
import base64
encoded_data = base64.b64encode(output.encode('utf-8')).decode('utf-8')
return jsonify({ return jsonify({
'success': True, 'success': True,
'message': f'已生成 {len(logs)} 条日志记录', 'message': f'已生成 {len(logs)} 条日志记录',
'count': len(logs), 'count': len(logs),
'filename': filename, 'filename': filename,
'filedata': encoded_data, 'filedata': b64_encoded,
'filetype': 'text/csv' 'filetype': 'text/csv'
}) })
def export_as_xlsx(logs):
"""导出为XLSX格式"""
import base64
from io import BytesIO
try:
# 动态导入openpyxl如果不存在则抛出异常
import openpyxl
except ImportError:
raise Exception("未安装openpyxl库无法导出Excel格式。请安装后重试: pip install openpyxl")
# 创建工作簿和工作表
wb = openpyxl.Workbook()
ws = wb.active
ws.title = "系统日志"
# 写入标题行
headers = ['ID', '用户', '操作类型', '目标类型', '目标ID', 'IP地址', '描述', '创建时间']
for col_idx, header in enumerate(headers, 1):
ws.cell(row=1, column=col_idx, value=header)
# 写入数据行
for row_idx, log in enumerate(logs, 2):
username = log.user.username if log.user else "未登录"
ws.cell(row=row_idx, column=1, value=log.id)
ws.cell(row=row_idx, column=2, value=username)
ws.cell(row=row_idx, column=3, value=log.action)
ws.cell(row=row_idx, column=4, value=log.target_type or '')
ws.cell(row=row_idx, column=5, value=log.target_id or '')
ws.cell(row=row_idx, column=6, value=log.ip_address or '')
ws.cell(row=row_idx, column=7, value=log.description or '')
ws.cell(row=row_idx, column=8, value=log.created_at.strftime('%Y-%m-%d %H:%M:%S'))
# 调整列宽
for col_idx, header in enumerate(headers, 1):
column_letter = openpyxl.utils.get_column_letter(col_idx)
if header == '描述':
ws.column_dimensions[column_letter].width = 40
else:
ws.column_dimensions[column_letter].width = 15
# 保存到内存
output = BytesIO()
wb.save(output)
output.seek(0)
# 编码为Base64
xlsx_data = output.getvalue()
b64_encoded = base64.b64encode(xlsx_data).decode('utf-8')
# 设置文件名
filename = f"system_logs_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
return jsonify({
'success': True,
'message': f'已生成 {len(logs)} 条日志记录',
'count': len(logs),
'filename': filename,
'filedata': b64_encoded,
'filetype': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
})
@log_bp.route('/api/clear', methods=['POST']) @log_bp.route('/api/clear', methods=['POST'])
@login_required @login_required
@permission_required('view_logs') # 替代 @admin_required @permission_required('view_logs') # 替代 @admin_required

View File

@ -13,4 +13,5 @@ pandas
flask-login flask-login
openpyxl openpyxl
xlrd xlrd
xlsxwriter xlsxwriter
openpyxl