# -*- coding: utf-8 -*- # @Time : 2023/9/26 10:58 # @Author : tx # @File : base.py # @Description : import string from io import BytesIO import urllib.parse from openpyxl.workbook import Workbook from openpyxl.styles import Alignment, Side, Border, Font, PatternFill from helper.utils import timezone_now from helper import usb from datetime import datetime, timezone class ReportExport: def __init__(self): self.title = "" self.stateDict = {} # 新建一个workbook self.wb = Workbook() # 定义设置样式 self.a = 0 self.styleTrue = '\u2611' # 打勾 self.styleFalse = '\u25A1' # 空框 def set_style(self, title='sheet1', ty=1): # 如果是第一次调用则删除默认创建的sheet表 if self.a == 0: self.wb.remove(self.wb['Sheet']) self.a += 1 # 创建第几个sheet self.ws = self.wb.create_sheet() # 设置sheet的标题 self.ws.title = title # 设置1 2 3 行固定的高度 self.ws.row_dimensions[1].height = 35 self.ws.row_dimensions[2].height = 25 self.ws.row_dimensions[3].height = 28 # 水平对齐, 居中对齐 self.alignment_style2 = Alignment( horizontal='left', vertical='top', wrapText=True) self.alignment_style = Alignment( horizontal='center', vertical='center', wrapText=True) # 定义Border边框样式 left, right, top, bottom = [Side(style='thin', color='000000')] * 4 self.border_style = Border( left=left, right=right, top=top, bottom=bottom) # 设置列宽 # 生成前14个大写字母 ascii_uppercase生成所有大写字母 self.upper_string = string.ascii_uppercase[:15] # 定义字体 self.font_size = Font(size=9) width_list = [20, 15, 10, 15, 15, 22, 15, 22, 15, 15] for col in self.upper_string: try: width = width_list[self.upper_string.index(col)] except: width = 20 self.ws.column_dimensions[col].width = width def editor_state(self, col_): """ 状态解析 :param col_: :return: """ self.max_lines = self.ws.max_row for row_ in range(2, self.max_lines + 1): b = self.ws[col_ + str(row_)].value if "状态" in str(b): continue self.ws[col_ + str(row_)].value = self.stateDict.get(b) def create_row(self, data_list,title=''): if title: n=2 self.ws.merge_cells(start_row=1, end_row=1, start_column=1, end_column=len(data_list)) # 写入值 self.ws.cell(row=1, column=1).value = title self.ws['A1'].alignment = self.alignment_style self.ws['A1'].font = Font(size=16, bold=True) else: n=1 for data in range(n, len(data_list) + n): if n ==2: data =data-1 # 第一行写入值 self.ws.cell(row=n, column=data).value = data_list[data - 1] # 设置文本水平居中, 垂直居中 self.ws.cell(row=n, column=data).alignment = self.alignment_style # 设置字体加粗 self.ws.cell(row=n, column=data).font = Font(bold=True, size=9) # 边框样式 self.ws.cell(row=n, column=data).border = self.border_style def create_multiple_rows(self, start_row, data_list, keys_list): # 从第2行创建 for row_number in range(start_row, len(data_list) + start_row): # 设置每一行的行高 self.ws.row_dimensions[row_number].height = 60 # 遍历每一个对象的长度 col_ = 1 for key_ in keys_list: # 写入值 try: if key_ =='ysr': value ='李世光' elif key_ =='info': value=f'{self.styleTrue}标识清晰\r\n{self.styleTrue}外观完整、无破损\r\n{self.styleTrue}形状无明显改变\r\n{self.styleTrue}符合申购要求\r\n{self.styleFalse}其他' elif key_ =='jg': value=f'{self.styleTrue}合格\r\n{self.styleFalse}不合格' else: value = data_list[row_number - start_row][key_] if isinstance(value, datetime) and value.tzinfo is not None: # 如果是带有时区信息的datetime对象,则移除时区信息 value = value.replace(tzinfo=None) except: value = "/" self.ws.cell(row=row_number, column=col_).value = value # 设置文本水平居中, 垂直居中 if key_ == "acceptace" or key_ == "info" or key_ == "jg": self.ws.cell(row=row_number, column=col_).alignment = self.alignment_style2 else: self.ws.cell(row=row_number, column=col_).alignment = self.alignment_style # 设置边框样式 self.ws.cell(row=row_number, column=col_).border = self.border_style # 设置字体大小 self.ws.cell(row=row_number, column=col_).font = Font(size=9) col_ += 1 def build_file(self,title='', **kwargs): self.set_style(title="Sheet") # 数据条目 data_list = kwargs.pop("data_list") # 英文列名 key_list = kwargs.pop("key_list") # 中文列名 finds_name = kwargs.pop("finds_list") # 创建标题 self.create_row(finds_name,title) # 创建数据 if title: n=3 else: n=2 self.create_multiple_rows(n, data_list, key_list) for i in key_list: if "state" in i: # 如果行超过25行异常处理 if key_list.index(i) <= 25: self.editor_state(string.ascii_uppercase[key_list.index(i)]) else: # AA AB AC AD... divisor = key_list.index(i) // 25 - 1 string_divisor = string.ascii_uppercase[divisor] remainder = key_list.index(i) % 25 - 1 string_remainder = string.ascii_uppercase[remainder] self.editor_state(f"{string_divisor}{string_remainder}") def export(self, data, download_type='usb'): """ 导出 :param data: :param download_type: :return: """ binary = BytesIO() self.wb.save(binary) self.wb.close() binary.seek(0) filename = f"{timezone_now().strftime('%Y%m%d%H%M%S')}-{self.title}-报表.xlsx" if download_type == 'usb': try: usb.put_in(filename, binary) return 200, "导出成功" except usb.DeviceNotFound: return 404, "U盘未找到" encoded_filename = urllib.parse.quote(filename) return binary, encoded_filename