excel_util.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. # -*- coding: utf-8 -*-
  2. import io
  3. import pandas as pd
  4. from typing import Any
  5. from openpyxl import Workbook
  6. from openpyxl.utils import get_column_letter
  7. from openpyxl.styles import Alignment, PatternFill
  8. from openpyxl.worksheet.datavalidation import DataValidation
  9. class ExcelUtil:
  10. """Excel文件处理工具类"""
  11. @classmethod
  12. def __mapping_list(cls, list_data: list[dict[str, Any]], mapping_dict: dict) -> list:
  13. """
  14. 工具方法:将列表数据中的字段名映射为对应的中文字段名。
  15. 参数:
  16. - list_data (list[dict[str, Any]]): 数据列表。
  17. - mapping_dict (dict): 字段名映射字典。
  18. 返回:
  19. - list: 映射后的数据列表。
  20. """
  21. mapping_data = [{mapping_dict.get(key): item.get(key) for key in mapping_dict} for item in list_data]
  22. return mapping_data
  23. @classmethod
  24. def get_excel_template(cls, header_list: list[str], selector_header_list: list[str], option_list: list[dict[str, list[str]]]) -> bytes:
  25. """
  26. 生成 Excel 模板文件。
  27. 参数:
  28. - header_list (list[str]): 表头列表。
  29. - selector_header_list (list[str]): 需要设置下拉选择的表头列表。
  30. - option_list (list[dict[str, list[str]]]): 下拉选项配置列表。
  31. 返回:
  32. - bytes: Excel 文件的二进制数据。
  33. """
  34. wb = Workbook()
  35. ws = wb.active
  36. if not ws:
  37. raise ValueError("不存在活动工作表")
  38. # 设置表头样式
  39. header_fill = PatternFill(start_color='ababab', end_color='ababab', fill_type='solid')
  40. # 写入表头
  41. for col_num, header in enumerate(header_list, 1):
  42. cell = ws.cell(row=1, column=col_num)
  43. cell.value = header
  44. cell.fill = header_fill
  45. # 设置水平居中对齐
  46. cell.alignment = Alignment(horizontal='center')
  47. # 设置列宽度为16
  48. ws.column_dimensions[get_column_letter(col_num)].width = 12
  49. # 设置下拉选择
  50. for selector_header in selector_header_list:
  51. col_idx = header_list.index(selector_header) + 1
  52. # 获取当前表头的选项列表
  53. header_options = next((opt.get(selector_header) for opt in option_list if selector_header in opt), [])
  54. if header_options:
  55. dv = DataValidation(type='list', formula1=f'"{",".join(header_options)}"')
  56. dv.add(f'{get_column_letter(col_idx)}2:{get_column_letter(col_idx)}1048576')
  57. ws.add_data_validation(dv)
  58. # 导出为二进制数据
  59. buffer = io.BytesIO()
  60. wb.save(buffer)
  61. buffer.seek(0)
  62. # 读取字节数据
  63. excel_data = buffer.getvalue()
  64. return excel_data
  65. @classmethod
  66. def export_list2excel(cls, list_data: list[dict[str, Any]], mapping_dict: dict) -> bytes:
  67. """
  68. 将列表数据导出为 Excel 文件。
  69. 参数:
  70. - list_data (list[dict[str, Any]]): 要导出的数据列表。
  71. - mapping_dict (dict): 字段名映射字典。
  72. 返回:
  73. - bytes: Excel 文件的二进制数据。
  74. """
  75. mapping_data = cls.__mapping_list(list_data, mapping_dict)
  76. df = pd.DataFrame(mapping_data)
  77. buffer = io.BytesIO()
  78. df.to_excel(buffer, index=False, engine='openpyxl')
  79. binary_data = buffer.getvalue()
  80. return binary_data