|
|
import urllib.parse
|
|
|
import psutil
|
|
|
import os
|
|
|
import time
|
|
|
import random
|
|
|
import getpass
|
|
|
import platform
|
|
|
from io import BytesIO
|
|
|
from os import path
|
|
|
from app.conf.Setting import settings
|
|
|
import openpyxl
|
|
|
from openpyxl import Workbook
|
|
|
from openpyxl.styles import Alignment
|
|
|
from openpyxl.drawing.image import Image
|
|
|
from openpyxl.styles import Font
|
|
|
from datetime import datetime
|
|
|
import matplotlib.pyplot as plt
|
|
|
from app.lib.Utils import Utils
|
|
|
from openpyxl.styles import PatternFill, Border, Side
|
|
|
|
|
|
system_name = platform.system()
|
|
|
|
|
|
|
|
|
class ExcelExport():
|
|
|
def __init__(self, file_name, data, download_type):
|
|
|
self.file_name = file_name
|
|
|
self.data = data
|
|
|
self.download_type = download_type
|
|
|
self.book = Workbook()
|
|
|
self.side = Side(style='thin', color='000000') # 颜色可以是RGB值或者颜色名称
|
|
|
self.border = Border(left=self.side, right=self.side, top=self.side, bottom=self.side)
|
|
|
|
|
|
def set_title(self, sheet):
|
|
|
"""设置标题"""
|
|
|
for i in range(1, 13):
|
|
|
sheet.column_dimensions[openpyxl.utils.get_column_letter(i)].width = 15
|
|
|
sheet.merge_cells(f'A1:L1')
|
|
|
# sheet.merge_cells(f'A1:{chr(64 + self.culumn)}1')
|
|
|
cell = sheet.cell(row=1, column=1)
|
|
|
cell.value = self.file_name
|
|
|
cell.alignment = Alignment(horizontal='center', vertical='center')
|
|
|
sheet.row_dimensions[1].height = 40
|
|
|
# 设置背景色
|
|
|
fill = PatternFill(start_color="D9E1F4", end_color="D9E1F4", fill_type="solid")
|
|
|
sheet['A1'].fill = fill
|
|
|
# sheet['A1'].border = self.border
|
|
|
|
|
|
def set_column_title(self, sheet, experiment_type):
|
|
|
sheet.merge_cells(f'A2:A8')
|
|
|
cell = sheet.cell(row=2, column=1)
|
|
|
cell.value = '基本信息'
|
|
|
cell.alignment = Alignment(horizontal='center', vertical='center')
|
|
|
if experiment_type == '1':
|
|
|
sheet.merge_cells(f'A9:A12')
|
|
|
else:
|
|
|
sheet.merge_cells(f'A9:A13')
|
|
|
cell = sheet.cell(row=9, column=1)
|
|
|
cell.value = '报告信息'
|
|
|
cell.alignment = Alignment(horizontal='center', vertical='center')
|
|
|
fill = PatternFill(start_color="D9D9D9", end_color="D9D9D9", fill_type="solid")
|
|
|
sheet['A2'].fill = fill
|
|
|
sheet['A9'].fill = fill
|
|
|
# sheet['A2'].border = self.border
|
|
|
# sheet['A9'].border = self.border
|
|
|
|
|
|
def set_columns(self, sheet, title_list):
|
|
|
"""设置列名"""
|
|
|
for i in range(len(title_list)):
|
|
|
sheet.merge_cells(f'B{i + 2}:E{i + 2}')
|
|
|
sheet.merge_cells(f'F{i + 2}:I{i + 2}')
|
|
|
cell = sheet.cell(row=i + 2, column=2)
|
|
|
cell.value = title_list[i]
|
|
|
cell.alignment = Alignment(horizontal='center', vertical='center')
|
|
|
|
|
|
def set_temp(self, sheet, data_item):
|
|
|
"""设置40,60,80,100"""
|
|
|
temp = ['校准物质40℃升温速率', '校准物质60℃升温速率', '校准物质80℃升温速率', '校准物质100℃升温速率']
|
|
|
temp1 = ['校准物质40℃降温速率', '校准物质60℃降温速率', '校准物质80℃降温速率', '校准物质100℃降温速率']
|
|
|
for i in range(len(temp)):
|
|
|
sheet.merge_cells(f'B{i + 9}:C{i + 9}')
|
|
|
sheet.merge_cells(f'D{i + 9}:E{i + 9}')
|
|
|
sheet.merge_cells(f'F{i + 9}:G{i + 9}')
|
|
|
sheet.merge_cells(f'H{i + 9}:I{i + 9}')
|
|
|
cell = sheet.cell(row=i + 9, column=2)
|
|
|
cell.value = temp[i]
|
|
|
cell.alignment = Alignment(horizontal='center', vertical='center')
|
|
|
cell = sheet.cell(row=i + 9, column=4)
|
|
|
cell.value = data_item["temp_data"][i]
|
|
|
cell.alignment = Alignment(horizontal='center', vertical='center')
|
|
|
cell1 = sheet.cell(row=i + 9, column=6)
|
|
|
cell1.value = temp1[i]
|
|
|
cell1.alignment = Alignment(horizontal='center', vertical='center')
|
|
|
cell = sheet.cell(row=i + 9, column=8)
|
|
|
cell.value = data_item["temp_data1"][i]
|
|
|
cell.alignment = Alignment(horizontal='center', vertical='center')
|
|
|
|
|
|
def insert_data(self, sheet, data_item, key_list):
|
|
|
"""插入数据"""
|
|
|
|
|
|
for i in range(len(key_list)):
|
|
|
cell = sheet.cell(row=i + 2, column=6)
|
|
|
cell.value = data_item[key_list[i]]
|
|
|
cell.alignment = Alignment(horizontal='center', vertical='center')
|
|
|
|
|
|
# def insert_chart(self, sheet,chart_result,ro):
|
|
|
# """插入图表"""
|
|
|
#
|
|
|
#
|
|
|
# plt.rcParams['xtick.direction'] = 'in' # 将x周的刻度线方向设置向内
|
|
|
# plt.rcParams['ytick.direction'] = 'in' # 将y轴的刻度方向设置向内
|
|
|
# ax1_color = '#1f77b4'
|
|
|
# ax2_color = '#d62728'
|
|
|
# ax3_color = '#573627'
|
|
|
#
|
|
|
# data = chart_result
|
|
|
#
|
|
|
# x_data = [int(float(i[-1])) for i in data] # 时间
|
|
|
# y_data = [round(float(i[2]), 2) for i in data] # 压力
|
|
|
# y_data2 = [round(float(i[3]), 2) for i in data] # 温度
|
|
|
# # y_data3 = [round(float(i[-5] or 0) + 250, 2) for i in data] # 热表面温度 + 250
|
|
|
# # 创建主轴的图表
|
|
|
# fig, ax1 = plt.subplots()
|
|
|
# ax1.plot(x_data, y_data, 'b-', label='["压力","时间"]', linewidth=1, color=ax1_color)
|
|
|
# ax2 = ax1.twinx()
|
|
|
# ax1.plot(x_data, y_data2, 'b-', label='["温度","时间"]', linewidth=1, color=ax2_color)
|
|
|
# # ax1.plot(x_data, y_data3, 'b-', label='["高热表面温度250","时间"]', linewidth=1, color=ax3_color)
|
|
|
# plt.title('试验数据')
|
|
|
#
|
|
|
# ax1.set_xlabel('时间')
|
|
|
# ax1.set_ylabel('压力')
|
|
|
# ax1.legend(loc='upper left')
|
|
|
# ax2.legend(loc='upper right')
|
|
|
#
|
|
|
#
|
|
|
# # 图表标题
|
|
|
# # 设置中文字体
|
|
|
# plt.rcParams['font.sans-serif'] = ['SimHei']
|
|
|
# # 设置负号字体
|
|
|
# plt.rcParams['axes.unicode_minus'] = False
|
|
|
# # 保存 Matplotlib 图表为图像文件
|
|
|
# chart_file_path = path.join(settings.BASE_PATH, f'resource/{int(time.time() * 1000)}.png')
|
|
|
# print(chart_file_path)
|
|
|
# plt.savefig(chart_file_path, dpi=400)
|
|
|
# # 将图像插入到 Excel 工作表中
|
|
|
# img = Image(chart_file_path)
|
|
|
# img.width = 960
|
|
|
# img.height = 400
|
|
|
# sheet.add_image(img, 'B' + str(ro+2))
|
|
|
|
|
|
def insert_chart(self, sheet,chart_result,ro,type):
|
|
|
"""插入图表"""
|
|
|
|
|
|
|
|
|
plt.rcParams['xtick.direction'] = 'in' # 将x周的刻度线方向设置向内
|
|
|
plt.rcParams['ytick.direction'] = 'in' # 将y轴的刻度方向设置向内
|
|
|
# ax1_color = '#1f77b4'
|
|
|
# ax2_color = '#d62728'
|
|
|
# ax3_color = '#573627'
|
|
|
|
|
|
data = chart_result
|
|
|
|
|
|
x_data = [int(float(i.time)) for i in data] # 时间
|
|
|
if type == 1:
|
|
|
y_data = [round(float(i.surface_temperature), 2) for i in data] # 温度1 表面温度
|
|
|
ax_color = '#1f77b4'
|
|
|
label='["表面温度","时间"]'
|
|
|
ylabel = '表面温度'
|
|
|
elif type == 2:
|
|
|
y_data = [round(float(i.battery_voltage), 2) for i in data] # 温度2 电池电压
|
|
|
ax_color = '#d62728'
|
|
|
label='["电池电压","时间"]'
|
|
|
ylabel = '电池电压'
|
|
|
else:
|
|
|
y_data = [round(float(i.battery_electricity), 2) for i in data] # 温度3 电池电流
|
|
|
ax_color = '#573627'
|
|
|
label='["电池电流","时间"]'
|
|
|
ylabel = '电池电流'
|
|
|
# y_data = [round(float(i.surface_temperature), 2) for i in data] # 温度1 表面温度
|
|
|
# y_data2 = [round(float(i.battery_voltage), 2) for i in data] # 温度2 电池电压
|
|
|
# y_data3 = [round(float(i.battery_electricity), 2) for i in data] # 温度3 电池电流
|
|
|
# 创建主轴的图表
|
|
|
fig, ax1 = plt.subplots()
|
|
|
ax1.plot(x_data, y_data, 'b-', label=label, linewidth=1, color=ax_color)
|
|
|
# ax1.plot(x_data, y_data2, 'b-', label='["电池电压","时间"]', linewidth=1, color=ax2_color)
|
|
|
# ax1.plot(x_data, y_data3, 'b-', label='["电池电流","时间"]', linewidth=1, color=ax3_color)
|
|
|
plt.title('试验数据')
|
|
|
|
|
|
ax1.set_xlabel('时间')
|
|
|
ax1.set_ylabel(ylabel)
|
|
|
ax1.legend(loc='upper left')
|
|
|
|
|
|
|
|
|
# 图表标题
|
|
|
# 设置中文字体
|
|
|
plt.rcParams['font.sans-serif'] = ['SimHei']
|
|
|
# 设置负号字体
|
|
|
plt.rcParams['axes.unicode_minus'] = False
|
|
|
# 保存 Matplotlib 图表为图像文件
|
|
|
chart_file_path = path.join(settings.BASE_PATH, f'resource/{int(time.time() * 1000)}.png')
|
|
|
print(chart_file_path)
|
|
|
plt.savefig(chart_file_path, dpi=400)
|
|
|
# 将图像插入到 Excel 工作表中
|
|
|
img = Image(chart_file_path)
|
|
|
img.width = 960
|
|
|
img.height = 400
|
|
|
sheet.add_image(img, 'E' + str(ro+2))
|
|
|
|
|
|
ro+=20
|
|
|
|
|
|
# def insert_chart(self, sheet,chart_result,ro):
|
|
|
#
|
|
|
#
|
|
|
#
|
|
|
#
|
|
|
# # 设置全局字体和刻度线方向
|
|
|
# plt.rcParams['xtick.direction'] = 'in' # x轴刻度线方向
|
|
|
# plt.rcParams['ytick.direction'] = 'in' # y轴刻度线方向
|
|
|
# plt.rcParams['font.sans-serif'] = ['SimHei'] # 中文字体
|
|
|
# plt.rcParams['axes.unicode_minus'] = False # 负号显示
|
|
|
#
|
|
|
# # 假设这是你获取的实验数据
|
|
|
# data = chart_result
|
|
|
# x_data = [int(float(i.time)) for i in data] # 时间
|
|
|
# y_data = [round(float(i.surface_temperature), 2) for i in data] # 表面温度
|
|
|
# y_data2 = [round(float(i.battery_voltage), 2) for i in data] # 电池电压
|
|
|
# y_data3 = [round(float(i.battery_electricity), 2) for i in data] # 电池电流
|
|
|
#
|
|
|
# # 创建图表并设置主轴
|
|
|
# fig, ax1 = plt.subplots()
|
|
|
#
|
|
|
# # 绘制第一个数据系列:表面温度
|
|
|
# ax1.set_xlabel('时间')
|
|
|
# ax1.set_ylabel('表面温度 (°C)', color='#1f77b4')
|
|
|
# ax1.plot(x_data, y_data, label='表面温度', color='#1f77b4', linewidth=1)
|
|
|
# ax1.tick_params(axis='y', labelcolor='#1f77b4')
|
|
|
#
|
|
|
# # 设置第一个 y 轴的范围(根据数据调整)
|
|
|
# ax1.set_ylim([min(y_data) - 1, max(y_data) + 1]) # 适当调整范围,避免线条挤压
|
|
|
#
|
|
|
# # 创建第二个 y 轴:电池电压
|
|
|
# ax2 = ax1.twinx() # 创建第二个 y 轴
|
|
|
# ax2.set_ylabel('电池电压 (V)', color='#d62728')
|
|
|
# ax2.plot(x_data, y_data2, label='电池电压', color='#d62728', linewidth=1)
|
|
|
# ax2.tick_params(axis='y', labelcolor='#d62728')
|
|
|
#
|
|
|
# # 设置第二个 y 轴的范围(根据数据调整)
|
|
|
# ax2.set_ylim([min(y_data2) - 0.5, max(y_data2) + 0.5]) # 适当调整范围
|
|
|
#
|
|
|
# # 将第二个 y 轴移到左侧
|
|
|
# ax2.spines['left'].set_position(('outward', 60)) # 将第二个 y 轴移到外面
|
|
|
#
|
|
|
# # 创建第三个 y 轴:电池电流
|
|
|
# ax3 = ax1.twinx() # 创建第三个 y 轴
|
|
|
# ax3.spines['left'].set_position(('outward', 320)) # 将第三个 y 轴移到外面
|
|
|
# ax3.set_ylabel('电池电流 (A)', color='#573627')
|
|
|
# ax3.plot(x_data, y_data3, label='电池电流', color='#573627', linewidth=1)
|
|
|
# ax3.tick_params(axis='y', labelcolor='#573627')
|
|
|
#
|
|
|
# # 设置第三个 y 轴的范围(根据数据调整)
|
|
|
# ax3.set_ylim([min(y_data3) - 0.1, max(y_data3) + 0.1]) # 适当调整范围
|
|
|
#
|
|
|
# # 图表标题
|
|
|
# plt.title('试验数据')
|
|
|
#
|
|
|
# # 图例
|
|
|
# fig.tight_layout() # 自动调整子图间距
|
|
|
# ax1.legend(loc='upper left')
|
|
|
#
|
|
|
# # 保存图表为图片
|
|
|
# chart_file_path = path.join(settings.BASE_PATH, f'resource/{int(time.time() * 1000)}.png')
|
|
|
# print(chart_file_path)
|
|
|
# plt.savefig(chart_file_path, dpi=400)
|
|
|
#
|
|
|
# # 将图像插入到 Excel 工作表中
|
|
|
# img = Image(chart_file_path)
|
|
|
# img.width = 960
|
|
|
# img.height = 400
|
|
|
# sheet.add_image(img, 'D' + str(ro + 2))
|
|
|
|
|
|
|
|
|
|
|
|
def experiment_table(self):
|
|
|
"""试验报表"""
|
|
|
for item in self.data:
|
|
|
base_data_title = item['base_data_title']
|
|
|
base_data_list = item['base_data_list']
|
|
|
sheet_title = item['sheet_title']
|
|
|
title_list = item['title_list']
|
|
|
specimen_data = item['specimen_data']
|
|
|
sheet = self.book.create_sheet(str(sheet_title)) # 创建工作表用试验时间作工作表名称
|
|
|
|
|
|
self.set_title(sheet) # 设置标题
|
|
|
for i in range(len(title_list)):
|
|
|
sheet.merge_cells(f'A{i + 1}:L{i + 1}')
|
|
|
cell = sheet.cell(row=i+1, column=1)
|
|
|
cell.value = title_list[i]
|
|
|
cell.alignment = Alignment(horizontal='center', vertical='center')
|
|
|
if i == 0:
|
|
|
cell.font = Font(size=22, bold=True)
|
|
|
ro = 2
|
|
|
|
|
|
for key, value in specimen_data.items():
|
|
|
cell = sheet.cell(row=ro, column=1)
|
|
|
cell.value = key
|
|
|
# sheet.merge_cells(f'B{ro + 1}:E{ro + 1}')
|
|
|
cell_b = sheet.cell(row=ro, column=2)
|
|
|
cell_b.value = value
|
|
|
ro += 1
|
|
|
ro +=1
|
|
|
for index,value in enumerate(base_data_title):
|
|
|
if value:
|
|
|
cell = sheet.cell(row=ro, column=index+1)
|
|
|
cell.value = value
|
|
|
cell.alignment = Alignment(horizontal='center', vertical='center')
|
|
|
ro += 1
|
|
|
for i in base_data_list:
|
|
|
for index, value in enumerate(base_data_title):
|
|
|
cell = sheet.cell(row=ro, column=index + 1)
|
|
|
cell.value = i[base_data_title[index]]
|
|
|
cell.alignment = Alignment(horizontal='center', vertical='center')
|
|
|
ro += 1
|
|
|
|
|
|
# 在数据行下方增加一行,并填充新的列标题('实验时间', '表面温度', '电池电压', '电池电流')
|
|
|
new_row_title = ['实验时间', '表面温度', '电池电压', '电池电流']
|
|
|
|
|
|
# 填充新的一行数据标题,紧接数据区域下方
|
|
|
for index, value in enumerate(new_row_title):
|
|
|
cell = sheet.cell(row=ro+4, column=index + 1)
|
|
|
cell.value = value
|
|
|
cell.alignment = Alignment(horizontal='center', vertical='center') # 可选,居中对齐标题
|
|
|
|
|
|
fill_ro = ro+5
|
|
|
# 填充额外数据('实验时间', '表面温度', '电池电压', '电池电流')
|
|
|
for i in base_data_list[0]['other_data']:
|
|
|
cell_css= Alignment(horizontal='center', vertical='center') # 可选,居中对齐数据
|
|
|
time_cell = sheet.cell(row=fill_ro, column= 1)
|
|
|
time_cell.value = i.time # 时间
|
|
|
time_cell.alignment = cell_css
|
|
|
hxwd_cell = sheet.cell(row=fill_ro, column= 2)
|
|
|
hxwd_cell.value = i.surface_temperature # 表面温度
|
|
|
hxwd_cell.alignment = cell_css
|
|
|
ypwd_cell = sheet.cell(row=fill_ro, column= 3)
|
|
|
ypwd_cell.value = i.battery_voltage # 电池电压
|
|
|
ypwd_cell.alignment = cell_css
|
|
|
dcdl_cell = sheet.cell(row=fill_ro, column= 4)
|
|
|
dcdl_cell.value = i.battery_electricity # 电池电流
|
|
|
dcdl_cell.alignment = cell_css
|
|
|
fill_ro += 1 # 每填充一行数据后,增加行号
|
|
|
|
|
|
for i in base_data_list:
|
|
|
result_row_data = i['other_data']
|
|
|
if result_row_data:
|
|
|
char_data =[]
|
|
|
for row in result_row_data:
|
|
|
# if row[0] in [4,'4']:
|
|
|
char_data.append(row)
|
|
|
# 循环三次、表面温度、电池电压、电池电流
|
|
|
type = 1
|
|
|
for i in range(3):
|
|
|
self.insert_chart(sheet, char_data, ro,type)
|
|
|
type += 1
|
|
|
ro += 20
|
|
|
|
|
|
|
|
|
# 获取所有工作表的列表
|
|
|
sheets = self.book.sheetnames
|
|
|
# 删除第一个工作表
|
|
|
first_sheet_name = sheets[0]
|
|
|
self.book.remove(self.book[first_sheet_name])
|
|
|
|
|
|
# 导出
|
|
|
return self.export()
|
|
|
|
|
|
def export(self):
|
|
|
"""
|
|
|
导出
|
|
|
"""
|
|
|
binary = BytesIO()
|
|
|
self.book.save(binary)
|
|
|
self.book.close()
|
|
|
binary.seek(0)
|
|
|
filename = f"{datetime.now().strftime('%Y%m%d%H%M%S')}-{self.file_name}-报表.xlsx"
|
|
|
if self.download_type == 'usb':
|
|
|
try:
|
|
|
self.put_in(filename, binary)
|
|
|
return 200, "导出成功"
|
|
|
except Exception as e:
|
|
|
print(e)
|
|
|
return 404, "U盘未找到"
|
|
|
encoded_filename = urllib.parse.quote(filename)
|
|
|
|
|
|
return binary, encoded_filename
|
|
|
|
|
|
def put_in(self, filename: str, bin: BytesIO):
|
|
|
if system_name == 'Windows':
|
|
|
usbs = [disk.device for disk in psutil.disk_partitions() if disk.opts == 'rw,removable']
|
|
|
if not usbs:
|
|
|
raise Exception()
|
|
|
# with open(f"D:\\{filename}", 'wb') as f:
|
|
|
# f.write(bin.getbuffer())
|
|
|
# return
|
|
|
path_file = path.join(usbs[0], filename)
|
|
|
else:
|
|
|
usbs = [item for item in psutil.disk_partitions() if item.mountpoint.startswith(f'/media/{getpass.getuser()}')]
|
|
|
if not usbs:
|
|
|
raise Exception()
|
|
|
path_file = path.join(usbs[0].mountpoint, filename)
|
|
|
with open(path_file, 'wb') as f:
|
|
|
f.write(bin.getbuffer())
|