Files
cdtestplant_v1/apps/createDocument/extensions/table_creator.py

147 lines
6.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from pathlib import Path
from typing import Literal
from docxtpl import DocxTemplate
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_ALIGN_VERTICAL
from docx.oxml.ns import qn
from docx.shared import Mm
from apps.createDocument.extensions.tools import set_table_border_by_cell_position, set_cell_margins
from utils.path_utils import project_path
from utils.chen_response import ChenResponse
from django.shortcuts import get_object_or_404
from apps.project.models import Project, Round
from django.db.models import QuerySet
# 创建当前轮次别名
RoundType = Literal["0", "not0", "last"]
chinese_round_name: list = ['', '', '', '', '', '', '', '', '', '']
# 通用生成静态软件项、静态硬件项、动态软件项、动态硬件信息、测评数据的context包含fontnote和table
def create_table_context(table_data: list[list[str]], doc: DocxTemplate, rounds_map: list[list[str]] = None,
current_round: str = None):
"""
注意:该函数会增加一列序号列,并且支持单元格内回车换行(段落换行)
传入当前轮次以及rounds_map来过滤一些其他轮次的数据为None则不过滤
"""
# 过滤数据处理
if rounds_map is not None and current_round is not None and current_round != 'last':
filtered_data = []
for i, row in enumerate(table_data):
# 第一行作为表头,始终保留
if i == 0:
filtered_data.append(row)
else:
# 检查该行是否属于当前轮次
if current_round in rounds_map[i]:
filtered_data.append(row)
# table_data先替换后再执行下方生成表格
table_data = filtered_data
subdoc = doc.new_subdoc()
rows = len(table_data)
cols = len(table_data[0]) + 1
table = subdoc.add_table(rows=rows, cols=cols)
# 单元格处理
for row in range(rows):
for col in range(cols):
cell = table.cell(row, col) # 从上倒下从左到右取cell
set_cell_margins(cell, left=100, right=100, top=100, bottom=100)
# 获取要显示的文本内容(字符串或按行拆分后的列表)
if col == 0:
# 序号列
lines = ["序号"] if row == 0 else [str(row)]
else:
raw_text = table_data[row][col - 1]
# 按换行符 \n 拆分为多个段落
lines = raw_text.split('\n') if raw_text else ['']
# 清空单元格原有段落add_table 默认有一个段落)
cell.text = ""
# 删除默认段落,稍后统一添加
for para in cell.paragraphs:
p = para._element
p.getparent().remove(p)
# 逐个添加段落
for i, line in enumerate(lines):
if i == 0:
para = cell.add_paragraph(line)
else:
para = cell.add_paragraph(line)
# 设置段落对齐(第一列居中,其他左对齐,可根据需要调整)
if col == 0:
para.alignment = WD_ALIGN_PARAGRAPH.CENTER
else:
para.alignment = WD_ALIGN_PARAGRAPH.LEFT
# 对第一行(表头)设置黑体字体
if row == 0:
for run in para.runs:
run.font.name = '黑体'
run._element.rPr.rFonts.set(qn('w:eastAsia'), '黑体')
run.font.bold = False
# 表头段落居中(覆盖前面的 left
para.alignment = WD_ALIGN_PARAGRAPH.CENTER
# 垂直居中
cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
# 设置序号列宽度
for cell in table.columns[0].cells:
cell.width = Mm(15)
for para in cell.paragraphs:
para.alignment = WD_ALIGN_PARAGRAPH.CENTER
# 表格居中
table.alignment = WD_ALIGN_PARAGRAPH.CENTER
# 设置表格外边框
set_table_border_by_cell_position(table)
return subdoc
# 统一静态软件项、静态硬件项、动态软件项、动态硬件信息、测评数据5个的word生成 - 模版模式
def uniform_static_dynamic_response(id: int, filename: str, r_filename: str, model,
current_round: str = "0", isHsm: bool = None) -> ChenResponse | None:
""" 通过形参isHsm判断是否是回归测试说明 """
project_obj = get_object_or_404(Project, id=id)
input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'dg' / filename # 取相同模版
doc = DocxTemplate(input_path)
qs = model.objects.filter(project=project_obj)
if qs.exists():
obj = qs.first()
table_data = obj.table
# 回归测试说明生成多轮次回归测试说明的5个接口分支
if isHsm:
hround_list: QuerySet[Round] = project_obj.pField.exclude(key='0')
for hround in hround_list:
round_key = hround.key
cname = chinese_round_name[int(round_key)] # 取中文:一、二、三...
# key就是current_round这里就解决文件名和那个的问题
subdoc = create_table_context(table_data, doc, obj.rounds_map, round_key)
context = {
'fontnote': obj.fontnote,
'table': subdoc,
}
doc.render(context, autoescape=True)
try:
doc.save(Path.cwd() / "media" / project_path(id) / "output_dir/hsm" / "".join([f"{cname}", r_filename]))
except PermissionError as e:
return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e))
return ChenResponse(status=200,code=200,message="多个轮次5接口渲染完毕文档生成完毕")
# 新增传入rounds_map进行渲染
subdoc = create_table_context(table_data, doc, obj.rounds_map, current_round)
context = {
'fontnote': obj.fontnote,
'table': subdoc,
}
doc.render(context, autoescape=True)
try:
doc.save(Path.cwd() / "media" / project_path(id) / "output_dir" / r_filename)
return ChenResponse(status=200, code=200, message="文档生成成功!")
except PermissionError as e:
return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e))
return None