Files
paste-framework/paste/util/xlsx.py
T
2026-06-02 16:26:10 +08:00

155 lines
4.2 KiB
Python

from typing import Union, List, Optional, Dict, Any
import pandas as pd
from paste.util import ufont
def cm_to_excel_units(cm):
"""
厘米转Excel列宽单位。
:param cm: 厘米单位
"""
return cm / 2.54 * 7 # 1英寸=2.54厘米, 1Excel单位=1/7英寸
def auto_width_cm(series: pd.Series, font_name='Microsoft YaHei', font_size=11, min_cm=1.5, max_cm=20):
"""
自动列宽计算方法(区分中英文)。
:param series: pandas Series (数据列)
:param font_name: 字体名称
:param font_size: 字号
:param min_cm: 最小列宽(厘米)
:param max_cm: 最大列宽(厘米)
:return: 建议的列宽(厘米)
"""
# 获取精确字体度量
en_width_cm, cn_width_cm = ufont.get_font_metrics(font_name, font_size)
def calculate_text_width(text):
"""计算文本总宽度"""
cn_count = 0
en_count = 0
for char in str(text):
if '\u4e00' <= char <= '\u9fff':
cn_count += 1
else:
en_count += 1
_total_width = (cn_count * cn_width_cm) + (en_count * en_width_cm)
return _total_width
# 计算列标题宽度
title_width = calculate_text_width(series.name)
# 计算数据内容最大宽度
content_width = series.astype(str).apply(calculate_text_width).max()
# 取最大值并增加边距,15%额外边距
total_width = max(title_width, content_width) * 1.2
return max(min(total_width, max_cm), min_cm)
def auto_column_width(df, worksheet):
"""
根据内容自动设置列的宽度。
:param df: pandas DataFrame
:param worksheet: 工作表
"""
_font_name_set = ufont.get_fonts()
for col_num, col_name in enumerate(df.columns):
# 计算列宽
width_cm = auto_width_cm(df[col_name], font_name=_font_name_set[0], font_size=11)
# 设置列宽
worksheet.set_column(col_num, col_num, cm_to_excel_units(width_cm))
def apply_header_style(df, worksheet, workbook, **kwargs):
"""
应用表头样式。
:param df: 原始 DataFrame
:param worksheet: xlsxwriter worksheet对象
:param workbook: xlsxwriter workbook对象
:param kwargs: 样式参数
:return: 无
"""
_style_sheet = {
'font_size': 12,
'bg_color': '#F2F2F2',
'border': 1,
'bold': True,
}
_header_style = workbook.add_format({**_style_sheet, **kwargs})
for col_num, value in enumerate(df.columns.values):
worksheet.write(0, col_num, value, _header_style)
def apply_data_style(df, worksheet, workbook, **kwargs):
"""
应用数据单元格样式。
:param df: 原始 DataFrame
:param worksheet: xlsxwriter worksheet对象
:param workbook: xlsxwriter workbook对象
:param kwargs: 样式参数
:return: 无
"""
_style_sheet = {
'font_size': 12,
'border': 1,
}
_cell_style = workbook.add_format({**_style_sheet, **kwargs})
for row in range(1, len(df) + 1):
for col in range(0, len(df.columns)):
worksheet.write(row, col, df.iloc[row - 1, col], _cell_style)
def insert_text_to_column(
worksheet,
workbook,
column: int,
start_row: int,
texts: Union[str, List[str]],
text_format: Optional[Dict[str, Any]] = None
) -> None:
"""
向Excel表格的指定列插入文本。
:param worksheet: xlsxwriter worksheet
:param workbook: xlsxwriter workbook
:param column: 列号
:param start_row: 开始插入的行号(1-based)
:param texts: 要插入的文本(字符串或字符串列表)
:param text_format: 格式字典,None则使用默认格式
:return: None
"""
# 设置默认格式
default_format = {
'font_size': 12,
}
# 合并用户自定义格式
fmt = workbook.add_format({**default_format, **(text_format or {})})
# 转换列号为数字索引(1-based)
if isinstance(column, str):
col_idx = ord(column.upper()) - ord('A') + 1
else:
col_idx = column
# 确保texts是列表形式
if isinstance(texts, str):
texts = [texts]
# 处理每行数据
for i, text in enumerate(texts):
row_num = start_row + i
worksheet.write(row_num, col_idx, text, fmt)