日常修复内容
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,212 +1,216 @@
|
||||
from copy import deepcopy
|
||||
from pathlib import Path
|
||||
from ninja_extra import api_controller, ControllerBase, route
|
||||
from ninja_extra.permissions import IsAuthenticated
|
||||
from ninja_jwt.authentication import JWTAuth
|
||||
from django.db import transaction
|
||||
from django.db.models import QuerySet
|
||||
from docxtpl import DocxTemplate
|
||||
from apps.dict.models import Dict
|
||||
from utils.chen_response import ChenResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from typing import Union
|
||||
from docxtpl import InlineImage
|
||||
from apps.project.models import Dut, Project, Round
|
||||
from utils.util import get_list_dict, get_str_dict, get_ident, get_case_ident
|
||||
from utils.chapter_tools.csx_chapter import create_csx_chapter_dict
|
||||
from utils.path_utils import project_path
|
||||
from apps.createDocument.extensions.util import delete_dir_files
|
||||
from apps.createDocument.extensions.parse_rich_text import RichParser
|
||||
# 导入生成日志记录模块
|
||||
from apps.createSeiTaiDocument.extensions.logger import GenerateLogger
|
||||
|
||||
chinese_round_name: list = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十']
|
||||
|
||||
# @api_controller("/generateHSM", tags=['生成回归记录系列文档'], auth=JWTAuth(), permissions=[IsAuthenticated])
|
||||
@api_controller("/generateHJL", tags=['生成回归记录系列文档'])
|
||||
class GenerateControllerHJL(ControllerBase):
|
||||
logger = GenerateLogger('回归测试记录')
|
||||
|
||||
# important:删除之前的文件
|
||||
@route.get('/create/deleteHJLDocument', url_name='delete-hjl-document')
|
||||
def delete_hjl_document(self, id: int):
|
||||
project_path_str = project_path(id)
|
||||
save_path = Path.cwd() / 'media' / project_path_str / 'output_dir/hjl'
|
||||
delete_dir_files(save_path)
|
||||
|
||||
@route.get("/create/basicInformation", url_name="create-basicInformation")
|
||||
@transaction.atomic
|
||||
def create_basicInformation(self, id: int):
|
||||
"""生成回归测试记录的被测软件基本信息"""
|
||||
project_path_str = project_path(id)
|
||||
tpl_path = Path.cwd() / 'media' / project_path_str / 'form_template/hjl' / '被测软件基本信息.docx'
|
||||
doc = DocxTemplate(tpl_path)
|
||||
project_obj = get_object_or_404(Project, id=id)
|
||||
# 第一轮次对象
|
||||
round1_obj: Union[Round, None] = project_obj.pField.filter(key='0').first()
|
||||
# 第一轮源代码被测件对象
|
||||
round1_so_dut: Union[Dut, None] = round1_obj.rdField.filter(type='SO').first()
|
||||
languages = get_list_dict('language', project_obj.language)
|
||||
language_list = [item['ident_version'] for item in languages]
|
||||
# 取非第一轮次
|
||||
hround_list: QuerySet = project_obj.pField.exclude(key='0')
|
||||
if len(hround_list) < 1:
|
||||
# ***Inspect-start***
|
||||
self.logger.model = '回归测试记录'
|
||||
self.logger.write_warning_log('当前文档全部片段', f'该项目没有创建轮次')
|
||||
# ***Inspect-end***
|
||||
return ChenResponse(code=400, status=400, message='您未创建轮次,请创建完毕后再试')
|
||||
|
||||
context = {
|
||||
'project_name': project_obj.name,
|
||||
'language': "、".join(language_list),
|
||||
'soft_type': project_obj.get_soft_type_display(),
|
||||
'security_level': get_str_dict(project_obj.security_level, 'security_level'),
|
||||
'runtime': get_str_dict(project_obj.runtime, 'runtime'),
|
||||
'devplant': get_str_dict(project_obj.devplant, 'devplant'),
|
||||
'recv_date': project_obj.beginTime.strftime("%Y-%m-%d"),
|
||||
'dev_unit': project_obj.dev_unit,
|
||||
}
|
||||
|
||||
version_info = [{'version': round1_so_dut.version,
|
||||
'line_count': int(round1_so_dut.total_lines),
|
||||
'effective_line': int(round1_so_dut.effective_lines)}]
|
||||
# 循环回归的轮次
|
||||
for hround in hround_list:
|
||||
# 每个轮次独立渲染context
|
||||
context_round = deepcopy(context)
|
||||
# 取中文名称
|
||||
cname = chinese_round_name[int(hround.key)] # 输出二、三...
|
||||
# 取该轮次源代码版本放入版本列表
|
||||
so_dut: Dut = hround.rdField.filter(type='SO').first()
|
||||
if not so_dut:
|
||||
return ChenResponse(code=400, status=400, message=f'您第{cname}轮次中缺少源代码被测件,请添加')
|
||||
version_info.append(
|
||||
{'version': so_dut.version, 'line_count': int(so_dut.total_lines),
|
||||
'effective_line': int(so_dut.effective_lines)})
|
||||
context_round['version_info'] = version_info
|
||||
# 开始渲染每个轮次的二级文档
|
||||
save_path = Path.cwd() / 'media' / project_path_str / 'output_dir/hjl' / f"第{cname}轮被测软件基本信息.docx"
|
||||
doc.render(context=context_round, autoescape=True)
|
||||
try:
|
||||
doc.save(save_path)
|
||||
except PermissionError:
|
||||
return ChenResponse(code=400, status=400, message='您打开了生成的文档,请关闭后重试')
|
||||
return ChenResponse(code=200, status=200, message='多轮回归说明文档基本信息生成完毕')
|
||||
|
||||
@route.get("/create/caseinfo", url_name="create-caseinfo")
|
||||
@transaction.atomic
|
||||
def create_caseinfo(self, id: int):
|
||||
"""生成回归测试记录的-{测试用例记录}"""
|
||||
project_path_str = project_path(id)
|
||||
tpl_path = Path.cwd() / 'media' / project_path_str / 'form_template/hjl' / '测试用例记录.docx'
|
||||
doc = DocxTemplate(tpl_path)
|
||||
project_obj = get_object_or_404(Project, id=id)
|
||||
hround_list: QuerySet = project_obj.pField.exclude(key='0')
|
||||
if len(hround_list) < 1:
|
||||
return None
|
||||
demand_prefix = '3.1'
|
||||
# 循环每轮轮次对象
|
||||
for hround in hround_list:
|
||||
cname = chinese_round_name[int(hround.key)] # var:输出二、三字样
|
||||
test_type_len = Dict.objects.get(code='testType').dictItem.count() # 测试类型的个数
|
||||
type_number_list = [i for i in range(1, test_type_len + 1)] # 测试类型编号对应的列表
|
||||
list_list = [[] for j in range(1, test_type_len + 1)] # 每个测试类型组合为一个列表[[],[],[],[]]
|
||||
testType_list, last_chapter_items = create_csx_chapter_dict(hround)
|
||||
testDemands = hround.rtField.all() # 本轮所有测试项
|
||||
for demand in testDemands:
|
||||
type_index = type_number_list.index(int(demand.testType))
|
||||
demand_ident = get_ident(demand)
|
||||
# ~~~组装测试项~~~
|
||||
demand_last_chapter = last_chapter_items[demand.testType].index(demand.key) + 1
|
||||
demand_chapter = ".".join([demand_prefix, str(testType_list.index(demand.testType) + 1),
|
||||
str(demand_last_chapter)])
|
||||
demand_dict = {
|
||||
'name': demand.name,
|
||||
'ident': demand_ident,
|
||||
'chapter': demand_chapter,
|
||||
'item': []
|
||||
}
|
||||
# ~~~这里组装测试项里面的测试用例~~~
|
||||
for case in demand.tcField.all():
|
||||
step_list = []
|
||||
index = 1
|
||||
for one in case.step.all():
|
||||
# 这里需要对operation富文本处理
|
||||
rich_parser = RichParser(one.operation)
|
||||
desc_list = rich_parser.get_final_list(doc, img_size=68)
|
||||
rich_parser2 = RichParser(one.result)
|
||||
res_list = rich_parser2.get_final_list(doc, img_size=75)
|
||||
# 组装用例里面的步骤dict
|
||||
passed = '通过'
|
||||
if one.passed == '2':
|
||||
passed = '未通过'
|
||||
if one.passed == '3':
|
||||
passed = '未执行'
|
||||
step_dict = {
|
||||
'index': index,
|
||||
'operation': desc_list,
|
||||
'expect': one.expect,
|
||||
'result': res_list,
|
||||
'passed': passed,
|
||||
}
|
||||
step_list.append(step_dict)
|
||||
index += 1
|
||||
# 查询所有的problem
|
||||
problem_list = []
|
||||
problem_prefix = "PT"
|
||||
proj_ident = project_obj.ident
|
||||
for problem in case.caseField.all():
|
||||
problem_list.append("_".join([problem_prefix, proj_ident, problem.ident]))
|
||||
# fpga的时序图
|
||||
rich_parser3 = RichParser(case.timing_diagram)
|
||||
timing_diagram = rich_parser3.get_final_list(doc, img_size=115, height=50)
|
||||
has_timing_diagram = False
|
||||
if len(timing_diagram) > 0:
|
||||
if isinstance(timing_diagram[0], InlineImage):
|
||||
has_timing_diagram = True
|
||||
# 组装用例的dict
|
||||
case_dict = {
|
||||
'name': case.name,
|
||||
'ident': get_case_ident(demand_ident, case),
|
||||
'summary': case.summarize,
|
||||
'initialization': case.initialization,
|
||||
'premise': case.premise,
|
||||
'design_person': case.designPerson,
|
||||
'test_person': case.testPerson,
|
||||
'monitor_person': case.monitorPerson,
|
||||
'step': step_list,
|
||||
'time': str(case.exe_time) if case.exe_time is not None else str(case.update_datetime),
|
||||
'problems': "、".join(problem_list),
|
||||
'round_num_chn': cname,
|
||||
# 2025年4月24日新增
|
||||
'has_timing_diagram': has_timing_diagram,
|
||||
'timing_diagram': timing_diagram,
|
||||
}
|
||||
demand_dict['item'].append(case_dict)
|
||||
|
||||
list_list[type_index].append(demand_dict)
|
||||
# 定义渲染上下文
|
||||
context = {}
|
||||
output_list = []
|
||||
for (index, li) in enumerate(list_list):
|
||||
qs = Dict.objects.get(code="testType").dictItem.get(key=str(index + 1))
|
||||
context_str = qs.title
|
||||
sort = qs.sort
|
||||
table = {
|
||||
"type": context_str,
|
||||
"item": li,
|
||||
"sort": sort
|
||||
}
|
||||
output_list.append(table)
|
||||
# 排序
|
||||
output_list = sorted(output_list, key=(lambda x: x["sort"]))
|
||||
context["data"] = output_list
|
||||
# 最后渲染
|
||||
save_path = Path.cwd() / 'media' / project_path_str / 'output_dir/hjl' / f"第{cname}轮测试用例记录.docx"
|
||||
doc.render(context, autoescape=True)
|
||||
try:
|
||||
doc.save(save_path)
|
||||
except PermissionError:
|
||||
return ChenResponse(code=400, status=400, message='您打开了生成的文档,请关闭后重试')
|
||||
return ChenResponse(code=200, status=200, message='多轮回归测试用例记录生成完毕')
|
||||
from copy import deepcopy
|
||||
from pathlib import Path
|
||||
from ninja_extra import api_controller, ControllerBase, route
|
||||
from ninja_extra.permissions import IsAuthenticated
|
||||
from ninja_jwt.authentication import JWTAuth
|
||||
from django.db import transaction
|
||||
from django.db.models import QuerySet
|
||||
from docxtpl import DocxTemplate
|
||||
from apps.dict.models import Dict
|
||||
from utils.chen_response import ChenResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from typing import Union
|
||||
from docxtpl import InlineImage
|
||||
from apps.project.models import Dut, Project, Round
|
||||
from utils.util import get_list_dict, get_str_dict, get_ident, get_case_ident
|
||||
from utils.chapter_tools.csx_chapter import create_csx_chapter_dict
|
||||
from utils.path_utils import project_path
|
||||
from apps.createDocument.extensions.util import delete_dir_files
|
||||
from apps.createDocument.extensions.parse_rich_text import RichParser
|
||||
# 导入生成日志记录模块
|
||||
from apps.createSeiTaiDocument.extensions.logger import GenerateLogger
|
||||
|
||||
chinese_round_name: list = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十']
|
||||
|
||||
# @api_controller("/generateHSM", tags=['生成回归记录系列文档'], auth=JWTAuth(), permissions=[IsAuthenticated])
|
||||
@api_controller("/generateHJL", tags=['生成回归记录系列文档'])
|
||||
class GenerateControllerHJL(ControllerBase):
|
||||
logger = GenerateLogger('回归测试记录')
|
||||
|
||||
# important:删除之前的文件
|
||||
@route.get('/create/deleteHJLDocument', url_name='delete-hjl-document')
|
||||
def delete_hjl_document(self, id: int):
|
||||
project_path_str = project_path(id)
|
||||
save_path = Path.cwd() / 'media' / project_path_str / 'output_dir/hjl'
|
||||
delete_dir_files(save_path)
|
||||
|
||||
@route.get("/create/basicInformation", url_name="create-basicInformation")
|
||||
@transaction.atomic
|
||||
def create_basicInformation(self, id: int):
|
||||
"""生成回归测试记录的被测软件基本信息"""
|
||||
project_path_str = project_path(id)
|
||||
tpl_path = Path.cwd() / 'media' / project_path_str / 'form_template/hjl' / '被测软件基本信息.docx'
|
||||
doc = DocxTemplate(tpl_path)
|
||||
project_obj = get_object_or_404(Project, id=id)
|
||||
# 第一轮次对象
|
||||
round1_obj: Union[Round, None] = project_obj.pField.filter(key='0').first()
|
||||
# 第一轮源代码被测件对象
|
||||
round1_so_dut: Union[Dut, None] = round1_obj.rdField.filter(type='SO').first()
|
||||
languages = get_list_dict('language', project_obj.language)
|
||||
language_list = [item['ident_version'] for item in languages]
|
||||
runtimes = get_list_dict('runtime', project_obj.runtime)
|
||||
runtime_list = [item['ident_version'] for item in runtimes]
|
||||
devplants = get_list_dict('devplant', project_obj.devplant)
|
||||
devplant_list = [item['ident_version'] for item in devplants]
|
||||
# 取非第一轮次
|
||||
hround_list: QuerySet = project_obj.pField.exclude(key='0')
|
||||
if len(hround_list) < 1:
|
||||
# ***Inspect-start***
|
||||
self.logger.model = '回归测试记录'
|
||||
self.logger.write_warning_log('当前文档全部片段', f'该项目没有创建轮次')
|
||||
# ***Inspect-end***
|
||||
return ChenResponse(code=400, status=400, message='您未创建轮次,请创建完毕后再试')
|
||||
|
||||
context = {
|
||||
'project_name': project_obj.name,
|
||||
'language': "、".join(language_list),
|
||||
'soft_type': project_obj.get_soft_type_display(),
|
||||
'security_level': get_str_dict(project_obj.security_level, 'security_level'),
|
||||
'runtime': "、".join(runtime_list),
|
||||
'devplant': "、".join(devplant_list),
|
||||
'recv_date': project_obj.beginTime.strftime("%Y-%m-%d"),
|
||||
'dev_unit': project_obj.dev_unit,
|
||||
}
|
||||
|
||||
version_info = [{'version': round1_so_dut.version,
|
||||
'line_count': int(round1_so_dut.total_lines),
|
||||
'effective_line': int(round1_so_dut.effective_lines)}]
|
||||
# 循环回归的轮次
|
||||
for hround in hround_list:
|
||||
# 每个轮次独立渲染context
|
||||
context_round = deepcopy(context)
|
||||
# 取中文名称
|
||||
cname = chinese_round_name[int(hround.key)] # 输出二、三...
|
||||
# 取该轮次源代码版本放入版本列表
|
||||
so_dut: Dut = hround.rdField.filter(type='SO').first()
|
||||
if not so_dut:
|
||||
return ChenResponse(code=400, status=400, message=f'您第{cname}轮次中缺少源代码被测件,请添加')
|
||||
version_info.append(
|
||||
{'version': so_dut.version, 'line_count': int(so_dut.total_lines),
|
||||
'effective_line': int(so_dut.effective_lines)})
|
||||
context_round['version_info'] = version_info
|
||||
# 开始渲染每个轮次的二级文档
|
||||
save_path = Path.cwd() / 'media' / project_path_str / 'output_dir/hjl' / f"第{cname}轮被测软件基本信息.docx"
|
||||
doc.render(context=context_round, autoescape=True)
|
||||
try:
|
||||
doc.save(save_path)
|
||||
except PermissionError:
|
||||
return ChenResponse(code=400, status=400, message='您打开了生成的文档,请关闭后重试')
|
||||
return ChenResponse(code=200, status=200, message='多轮回归说明文档基本信息生成完毕')
|
||||
|
||||
@route.get("/create/caseinfo", url_name="create-caseinfo")
|
||||
@transaction.atomic
|
||||
def create_caseinfo(self, id: int):
|
||||
"""生成回归测试记录的-{测试用例记录}"""
|
||||
project_path_str = project_path(id)
|
||||
tpl_path = Path.cwd() / 'media' / project_path_str / 'form_template/hjl' / '测试用例记录.docx'
|
||||
doc = DocxTemplate(tpl_path)
|
||||
project_obj = get_object_or_404(Project, id=id)
|
||||
hround_list: QuerySet = project_obj.pField.exclude(key='0')
|
||||
if len(hround_list) < 1:
|
||||
return None
|
||||
demand_prefix = '3.1'
|
||||
# 循环每轮轮次对象
|
||||
for hround in hround_list:
|
||||
cname = chinese_round_name[int(hround.key)] # var:输出二、三字样
|
||||
test_type_len = Dict.objects.get(code='testType').dictItem.count() # 测试类型的个数
|
||||
type_number_list = [i for i in range(1, test_type_len + 1)] # 测试类型编号对应的列表
|
||||
list_list = [[] for j in range(1, test_type_len + 1)] # 每个测试类型组合为一个列表[[],[],[],[]]
|
||||
testType_list, last_chapter_items = create_csx_chapter_dict(hround)
|
||||
testDemands = hround.rtField.all() # 本轮所有测试项
|
||||
for demand in testDemands:
|
||||
type_index = type_number_list.index(int(demand.testType))
|
||||
demand_ident = get_ident(demand)
|
||||
# ~~~组装测试项~~~
|
||||
demand_last_chapter = last_chapter_items[demand.testType].index(demand.key) + 1
|
||||
demand_chapter = ".".join([demand_prefix, str(testType_list.index(demand.testType) + 1),
|
||||
str(demand_last_chapter)])
|
||||
demand_dict = {
|
||||
'name': demand.name,
|
||||
'ident': demand_ident,
|
||||
'chapter': demand_chapter,
|
||||
'item': []
|
||||
}
|
||||
# ~~~这里组装测试项里面的测试用例~~~
|
||||
for case in demand.tcField.all():
|
||||
step_list = []
|
||||
index = 1
|
||||
for one in case.step.all():
|
||||
# 这里需要对operation富文本处理
|
||||
rich_parser = RichParser(one.operation)
|
||||
desc_list = rich_parser.get_final_list(doc, img_size=68)
|
||||
rich_parser2 = RichParser(one.result)
|
||||
res_list = rich_parser2.get_final_list(doc, img_size=75)
|
||||
# 组装用例里面的步骤dict
|
||||
passed = '通过'
|
||||
if one.passed == '2':
|
||||
passed = '未通过'
|
||||
if one.passed == '3':
|
||||
passed = '未执行'
|
||||
step_dict = {
|
||||
'index': index,
|
||||
'operation': desc_list,
|
||||
'expect': one.expect,
|
||||
'result': res_list,
|
||||
'passed': passed,
|
||||
}
|
||||
step_list.append(step_dict)
|
||||
index += 1
|
||||
# 查询所有的problem
|
||||
problem_list = []
|
||||
problem_prefix = "PT"
|
||||
proj_ident = project_obj.ident
|
||||
for problem in case.caseField.all():
|
||||
problem_list.append("_".join([problem_prefix, proj_ident, problem.ident]))
|
||||
# fpga的时序图
|
||||
rich_parser3 = RichParser(case.timing_diagram)
|
||||
timing_diagram = rich_parser3.get_final_list(doc, img_size=115, height=50)
|
||||
has_timing_diagram = False
|
||||
if len(timing_diagram) > 0:
|
||||
if isinstance(timing_diagram[0], InlineImage):
|
||||
has_timing_diagram = True
|
||||
# 组装用例的dict
|
||||
case_dict = {
|
||||
'name': case.name,
|
||||
'ident': get_case_ident(demand_ident, case),
|
||||
'summary': case.summarize,
|
||||
'initialization': case.initialization,
|
||||
'premise': case.premise,
|
||||
'design_person': case.designPerson,
|
||||
'test_person': case.testPerson,
|
||||
'monitor_person': case.monitorPerson,
|
||||
'step': step_list,
|
||||
'time': str(case.exe_time) if case.exe_time is not None else str(case.update_datetime),
|
||||
'problems': "、".join(problem_list),
|
||||
'round_num_chn': cname,
|
||||
# 2025年4月24日新增
|
||||
'has_timing_diagram': has_timing_diagram,
|
||||
'timing_diagram': timing_diagram,
|
||||
}
|
||||
demand_dict['item'].append(case_dict)
|
||||
|
||||
list_list[type_index].append(demand_dict)
|
||||
# 定义渲染上下文
|
||||
context = {}
|
||||
output_list = []
|
||||
for (index, li) in enumerate(list_list):
|
||||
qs = Dict.objects.get(code="testType").dictItem.get(key=str(index + 1))
|
||||
context_str = qs.title
|
||||
sort = qs.sort
|
||||
table = {
|
||||
"type": context_str,
|
||||
"item": li,
|
||||
"sort": sort
|
||||
}
|
||||
output_list.append(table)
|
||||
# 排序
|
||||
output_list = sorted(output_list, key=(lambda x: x["sort"]))
|
||||
context["data"] = output_list
|
||||
# 最后渲染
|
||||
save_path = Path.cwd() / 'media' / project_path_str / 'output_dir/hjl' / f"第{cname}轮测试用例记录.docx"
|
||||
doc.render(context, autoescape=True)
|
||||
try:
|
||||
doc.save(save_path)
|
||||
except PermissionError:
|
||||
return ChenResponse(code=400, status=400, message='您打开了生成的文档,请关闭后重试')
|
||||
return ChenResponse(code=200, status=200, message='多轮回归测试用例记录生成完毕')
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,155 +1,155 @@
|
||||
# 导入内置模块
|
||||
from pathlib import Path
|
||||
# 导入django、ninja等模块
|
||||
from ninja_extra import api_controller, ControllerBase, route
|
||||
from django.db import transaction
|
||||
from django.shortcuts import get_object_or_404
|
||||
# 导入文档处理模块
|
||||
from docxtpl import DocxTemplate, InlineImage
|
||||
# 导入ORM模型
|
||||
from apps.project.models import Project
|
||||
# 导入工具
|
||||
from utils.util import get_str_abbr, get_str_dict
|
||||
from utils.chen_response import ChenResponse
|
||||
from utils.path_utils import project_path
|
||||
from apps.createDocument.extensions.parse_rich_text import RichParser
|
||||
# 导入生成日志记录模块
|
||||
from apps.createSeiTaiDocument.extensions.logger import GenerateLogger
|
||||
|
||||
gloger = GenerateLogger("问题单二段文档")
|
||||
|
||||
# @api_controller("/generateWtd", tags=['生成问题单文档系列'], auth=JWTAuth(), permissions=[IsAuthenticated])
|
||||
@api_controller('/generateWtd', tags=['生成问题单文档系列'])
|
||||
class GenerateControllerWtd(ControllerBase):
|
||||
@route.get("/create/problem", url_name="create-problem")
|
||||
@transaction.atomic
|
||||
def create_problem(self, id: int):
|
||||
"""生成问题单"""
|
||||
project_path_str = project_path(id)
|
||||
tpl_path = Path.cwd() / 'media' / project_path_str / 'form_template/wtd' / '问题详情表.docx'
|
||||
doc = DocxTemplate(tpl_path)
|
||||
project_obj = get_object_or_404(Project, id=id)
|
||||
problem_list = list(project_obj.projField.distinct()) # 去掉重复,因为和case是多对多
|
||||
problem_list.sort(key=lambda x: int(x.ident))
|
||||
data_list = []
|
||||
for problem in problem_list:
|
||||
problem_dict = {'ident': problem.ident, 'name': problem.name}
|
||||
# 1.生成被测对象名称、被测对象标识、被测对象版本
|
||||
cases = problem.case.all()
|
||||
# generate_log:无关联问题单进入生成日志
|
||||
if cases.count() < 1:
|
||||
gloger.write_warning_log('单个问题单表格', f'问题单{problem.ident}未关联用例,请检查')
|
||||
str_dut_name_list = []
|
||||
str_dut_ident_list = []
|
||||
str_dut_version_list = []
|
||||
# 2.所属用例标识
|
||||
case_ident_list = []
|
||||
# 3.获取依据要求
|
||||
case_design_list = []
|
||||
for case in cases:
|
||||
if case.test.testType == '8':
|
||||
# 1.1.如果为文档审查,提取所属文档名称、文档被测件标识、文档被测件版本
|
||||
str_dut_name_list.append(case.dut.name)
|
||||
str_dut_ident_list.append(case.dut.ref)
|
||||
str_dut_version_list.append(case.dut.version)
|
||||
# 对应dut名称,design章节号,design描述
|
||||
case_design_list.append("".join([case.dut.name, case.design.chapter]))
|
||||
else:
|
||||
# 1.2.如果不为文档审查,则提取该轮次源代码dut的信息
|
||||
so_dut = case.round.rdField.filter(type='SO').first()
|
||||
if so_dut:
|
||||
str_dut_name_list.append(project_obj.name + '软件')
|
||||
str_dut_ident_list.append(so_dut.ref)
|
||||
str_dut_version_list.append(so_dut.version)
|
||||
# TODO:如何处理设计需求的内容,暂时设置为取出图片,只保留文字
|
||||
p_list = []
|
||||
rich_parse_remove_img = RichParser(case.design.description)
|
||||
rich_list = rich_parse_remove_img.get_final_list(doc)
|
||||
for rich in rich_list:
|
||||
if isinstance(rich, dict) or isinstance(rich, InlineImage):
|
||||
continue
|
||||
else:
|
||||
p_list.append(rich)
|
||||
|
||||
case_design_list.append(
|
||||
"-".join([case.dut.name, case.design.chapter + '章节' + ":" + ''.join(p_list)]))
|
||||
# 2.用例标识修改-YL_测试项类型_测试项标识_用例key+1
|
||||
demand = case.test # 中间变量
|
||||
demand_testType = demand.testType # 中间变量
|
||||
testType_abbr = get_str_abbr(demand_testType, 'testType') # 输出FT
|
||||
case_ident_list.append("_".join(
|
||||
['YL', testType_abbr, demand.ident, str(int(case.key[-1]) + 1).rjust(3, '0')]))
|
||||
problem_dict['duts_name'] = "/".join(set(str_dut_name_list))
|
||||
problem_dict['duts_ref'] = "/".join(set(str_dut_ident_list))
|
||||
problem_dict['duts_version'] = "/".join(set(str_dut_version_list))
|
||||
temp_name_version = []
|
||||
for i in range(len(str_dut_name_list)):
|
||||
temp_name_version.append(
|
||||
"".join([str_dut_name_list[i] + str_dut_ident_list[i], '/V', str_dut_version_list[i]]))
|
||||
problem_dict['dut_name_version'] = "\a".join(temp_name_version)
|
||||
problem_dict['case_ident'] = ",".join(set(case_ident_list))
|
||||
problem_dict['type'] = get_str_dict(problem.type, 'problemType')
|
||||
problem_dict['grade'] = get_str_dict(problem.grade, 'problemGrade')
|
||||
|
||||
# 依据要求-获取其设计需求
|
||||
problem_dict['yaoqiu'] = "\a".join(case_design_list)
|
||||
# 问题操作 - HTML解析
|
||||
desc_list = ['【问题操作】']
|
||||
rich_parser = RichParser(problem.operation)
|
||||
desc_list.extend(rich_parser.get_final_list(doc))
|
||||
|
||||
# 问题影响
|
||||
desc_list_result = [f'\a【问题影响】\a{problem.result}']
|
||||
desc_list.extend(desc_list_result)
|
||||
# 问题描述赋值
|
||||
problem_dict['desc'] = desc_list
|
||||
|
||||
# 4.原因分析
|
||||
desc_list_3 = [f'【原因分析】\a{problem.analysis}']
|
||||
problem_dict['cause'] = desc_list_3
|
||||
|
||||
# 5.影响域分析~~~~
|
||||
desc_list_4 = [f'【影响域分析】\a{problem.effect_scope}']
|
||||
problem_dict['effect_scope'] = desc_list_4
|
||||
|
||||
# 6.改正措施
|
||||
problem_dict['solve'] = problem.solve
|
||||
|
||||
# 7.回归验证结果
|
||||
desc_list_5 = []
|
||||
rich_parser5 = RichParser(problem.verify_result)
|
||||
desc_list_5.extend(rich_parser5.get_final_list(doc))
|
||||
problem_dict['verify_result'] = desc_list_5
|
||||
|
||||
# 8.其他日期和人员
|
||||
problem_dict['postPerson'] = problem.postPerson
|
||||
problem_dict['postDate'] = problem.postDate
|
||||
close_str = '□修改文档 □修改程序 □不修改'
|
||||
if len(problem.closeMethod) < 1:
|
||||
close_str = '□修改文档 □修改程序 ■不修改'
|
||||
elif len(problem.closeMethod) == 2:
|
||||
close_str = '■修改文档 ■修改程序 □不修改'
|
||||
else:
|
||||
if problem.closeMethod[0] == '1':
|
||||
close_str = '■修改文档 □修改程序 □不修改'
|
||||
elif problem.closeMethod[0] == '2':
|
||||
close_str = '□修改文档 ■修改程序 □不修改'
|
||||
else:
|
||||
close_str = '□修改文档 □修改程序 □不修改'
|
||||
problem_dict['closeMethod'] = close_str
|
||||
problem_dict['designer'] = problem.designerPerson
|
||||
problem_dict['designDate'] = problem.designDate
|
||||
problem_dict['verifyPerson'] = problem.verifyPerson
|
||||
problem_dict['verifyDate'] = problem.verifyDate
|
||||
data_list.append(problem_dict)
|
||||
context = {
|
||||
'project_name': project_obj.name,
|
||||
'project_ident': project_obj.ident,
|
||||
'problem_list': data_list,
|
||||
}
|
||||
doc.render(context, autoescape=True)
|
||||
try:
|
||||
doc.save(Path.cwd() / "media" / project_path_str / "output_dir/wtd" / '问题详情表.docx')
|
||||
return ChenResponse(status=200, code=200, message="文档生成成功!")
|
||||
except PermissionError as e:
|
||||
return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e))
|
||||
# 导入内置模块
|
||||
from pathlib import Path
|
||||
from django.db.models import QuerySet
|
||||
# 导入django、ninja等模块
|
||||
from ninja_extra import api_controller, ControllerBase, route
|
||||
from django.db import transaction
|
||||
from django.shortcuts import get_object_or_404
|
||||
# 导入文档处理模块
|
||||
from docxtpl import DocxTemplate, InlineImage
|
||||
# 导入ORM模型
|
||||
from apps.project.models import Project, Case
|
||||
# 导入工具
|
||||
from utils.util import get_str_abbr, get_str_dict
|
||||
from utils.chen_response import ChenResponse
|
||||
from utils.path_utils import project_path
|
||||
from apps.createDocument.extensions.parse_rich_text import RichParser
|
||||
# 导入生成日志记录模块
|
||||
from apps.createSeiTaiDocument.extensions.logger import GenerateLogger
|
||||
|
||||
gloger = GenerateLogger("问题单二段文档")
|
||||
|
||||
# @api_controller("/generateWtd", tags=['生成问题单文档系列'], auth=JWTAuth(), permissions=[IsAuthenticated])
|
||||
@api_controller('/generateWtd', tags=['生成问题单文档系列'])
|
||||
class GenerateControllerWtd(ControllerBase):
|
||||
@route.get("/create/problem", url_name="create-problem")
|
||||
@transaction.atomic
|
||||
def create_problem(self, id: int):
|
||||
"""生成问题单"""
|
||||
project_path_str = project_path(id)
|
||||
tpl_path = Path.cwd() / 'media' / project_path_str / 'form_template/wtd' / '问题详情表.docx'
|
||||
doc = DocxTemplate(tpl_path)
|
||||
project_obj = get_object_or_404(Project, id=id)
|
||||
problem_list = list(project_obj.projField.distinct()) # 去掉重复,因为和case是多对多
|
||||
problem_list.sort(key=lambda x: int(x.ident))
|
||||
data_list = []
|
||||
for problem in problem_list:
|
||||
problem_dict = {'ident': problem.ident, 'name': problem.name}
|
||||
# 1.生成被测对象名称、被测对象标识、被测对象版本
|
||||
cases: QuerySet[Case] = problem.case.all()
|
||||
# generate_log:无关联问题单进入生成日志
|
||||
if cases.count() < 1:
|
||||
gloger.write_warning_log('单个问题单表格', f'问题单{problem.ident}未关联用例,请检查')
|
||||
str_dut_name_list = []
|
||||
str_dut_ident_list = []
|
||||
str_dut_version_list = []
|
||||
# 2.所属用例标识
|
||||
case_ident_list = []
|
||||
# 3.获取依据要求
|
||||
case_design_list = []
|
||||
for case in cases:
|
||||
if case.test.testType == '8':
|
||||
# 1.1.如果为文档审查,提取所属文档名称、文档被测件标识、文档被测件版本
|
||||
str_dut_name_list.append(case.dut.name)
|
||||
str_dut_ident_list.append(case.dut.ref)
|
||||
str_dut_version_list.append(case.dut.version)
|
||||
# 对应dut名称,design章节号,design描述
|
||||
case_design_list.append("".join([case.dut.name, case.design.chapter]))
|
||||
else:
|
||||
# 1.2.如果不为文档审查,则提取该轮次源代码dut的信息
|
||||
so_dut = case.round.rdField.filter(type='SO').first()
|
||||
if so_dut:
|
||||
str_dut_name_list.append(project_obj.name + '软件')
|
||||
str_dut_ident_list.append(so_dut.ref)
|
||||
str_dut_version_list.append(so_dut.version)
|
||||
# TODO:如何处理设计需求的内容,暂时设置为取出图片,只保留文字
|
||||
p_list = []
|
||||
rich_parse_remove_img = RichParser(case.design.description)
|
||||
rich_list = rich_parse_remove_img.get_final_list(doc)
|
||||
for rich in rich_list:
|
||||
if isinstance(rich, dict) or isinstance(rich, InlineImage):
|
||||
continue
|
||||
else:
|
||||
p_list.append(rich)
|
||||
case_design_list.append("-".join([case.dut.name, case.design.chapter + '章节' + ":" + ''.join(p_list)]))
|
||||
# 2.用例标识修改-YL_测试项类型_测试项标识_用例key+1
|
||||
demand = case.test # 中间变量
|
||||
demand_testType = demand.testType # 中间变量
|
||||
testType_abbr = get_str_abbr(demand_testType, 'testType') # 输出FT
|
||||
case_ident_list.append("_".join(
|
||||
['YL', testType_abbr, demand.ident, str(int(case.key[-1]) + 1).rjust(3, '0')]))
|
||||
problem_dict['duts_name'] = "/".join(set(str_dut_name_list))
|
||||
problem_dict['duts_ref'] = "/".join(set(str_dut_ident_list))
|
||||
problem_dict['duts_version'] = "/".join(set(str_dut_version_list))
|
||||
temp_name_version = []
|
||||
for i in range(len(str_dut_name_list)):
|
||||
temp_name_version.append(
|
||||
"".join([str_dut_name_list[i] + str_dut_ident_list[i], '/V', str_dut_version_list[i]]))
|
||||
problem_dict['dut_name_version'] = "\a".join(set(temp_name_version))
|
||||
problem_dict['case_ident'] = ",".join(set(case_ident_list))
|
||||
problem_dict['type'] = get_str_dict(problem.type, 'problemType')
|
||||
problem_dict['grade'] = get_str_dict(problem.grade, 'problemGrade')
|
||||
|
||||
# 依据要求-获取其设计需求
|
||||
print(case_design_list)
|
||||
problem_dict['yaoqiu'] = "\a".join(case_design_list)
|
||||
# 问题操作 - HTML解析
|
||||
desc_list = ['【问题操作】']
|
||||
rich_parser = RichParser(problem.operation)
|
||||
desc_list.extend(rich_parser.get_final_list(doc))
|
||||
|
||||
# 问题影响
|
||||
desc_list_result = [f'\a【问题影响】\a{problem.result}']
|
||||
desc_list.extend(desc_list_result)
|
||||
# 问题描述赋值
|
||||
problem_dict['desc'] = desc_list
|
||||
|
||||
# 4.原因分析
|
||||
desc_list_3 = [f'【原因分析】\a{problem.analysis}']
|
||||
problem_dict['cause'] = desc_list_3
|
||||
|
||||
# 5.影响域分析~~~~
|
||||
desc_list_4 = [f'【影响域分析】\a{problem.effect_scope}']
|
||||
problem_dict['effect_scope'] = desc_list_4
|
||||
|
||||
# 6.改正措施
|
||||
problem_dict['solve'] = problem.solve
|
||||
|
||||
# 7.回归验证结果
|
||||
desc_list_5 = []
|
||||
rich_parser5 = RichParser(problem.verify_result)
|
||||
desc_list_5.extend(rich_parser5.get_final_list(doc))
|
||||
problem_dict['verify_result'] = desc_list_5
|
||||
|
||||
# 8.其他日期和人员
|
||||
problem_dict['postPerson'] = problem.postPerson
|
||||
problem_dict['postDate'] = problem.postDate
|
||||
close_str = '□修改文档 □修改程序 □不修改'
|
||||
if len(problem.closeMethod) < 1:
|
||||
close_str = '□修改文档 □修改程序 ■不修改'
|
||||
elif len(problem.closeMethod) == 2:
|
||||
close_str = '■修改文档 ■修改程序 □不修改'
|
||||
else:
|
||||
if problem.closeMethod[0] == '1':
|
||||
close_str = '■修改文档 □修改程序 □不修改'
|
||||
elif problem.closeMethod[0] == '2':
|
||||
close_str = '□修改文档 ■修改程序 □不修改'
|
||||
else:
|
||||
close_str = '□修改文档 □修改程序 □不修改'
|
||||
problem_dict['closeMethod'] = close_str
|
||||
problem_dict['designer'] = problem.designerPerson
|
||||
problem_dict['designDate'] = problem.designDate
|
||||
problem_dict['verifyPerson'] = problem.verifyPerson
|
||||
problem_dict['verifyDate'] = problem.verifyDate
|
||||
data_list.append(problem_dict)
|
||||
context = {
|
||||
'project_name': project_obj.name,
|
||||
'project_ident': project_obj.ident,
|
||||
'problem_list': data_list,
|
||||
}
|
||||
doc.render(context, autoescape=True)
|
||||
try:
|
||||
doc.save(Path.cwd() / "media" / project_path_str / "output_dir/wtd" / '问题详情表.docx')
|
||||
return ChenResponse(status=200, code=200, message="文档生成成功!")
|
||||
except PermissionError as e:
|
||||
return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e))
|
||||
|
||||
Binary file not shown.
@@ -1,141 +1,143 @@
|
||||
"""
|
||||
专门解析富文本插件tinymce的html内容
|
||||
"""
|
||||
import pandas as pd
|
||||
from bs4 import BeautifulSoup
|
||||
from bs4.element import Tag, NavigableString
|
||||
import base64
|
||||
import io
|
||||
from docxtpl import InlineImage
|
||||
from docx.shared import Mm
|
||||
import re
|
||||
|
||||
# text.replace('\xa0', ' '))
|
||||
class RichParser:
|
||||
def __init__(self, rich_text):
|
||||
# 将rich_text的None变为空字符串:鲁棒
|
||||
if rich_text is None:
|
||||
rich_text = ""
|
||||
# 对原始html解析后的bs对象
|
||||
self.bs = BeautifulSoup(rich_text, 'html.parser')
|
||||
self.content = self.remove_n_in_contents()
|
||||
# 最终的解析后的列表
|
||||
self.data_list = []
|
||||
self.line_parse()
|
||||
# 匹配“表1-3”或“表1”等字符的正则
|
||||
self.biao_pattern = re.compile(r"表\d+(?:-\d+)?")
|
||||
|
||||
# 1.函数:将self.bs.contents去掉\n,获取每行数据
|
||||
def remove_n_in_contents(self):
|
||||
content_list = []
|
||||
for line in self.bs.contents:
|
||||
if line != '\n':
|
||||
content_list.append(line)
|
||||
return content_list
|
||||
|
||||
# 2.逐个遍历self.content,去掉table元素Tag对象单独解析
|
||||
def line_parse(self):
|
||||
for tag in self.content:
|
||||
if isinstance(tag, NavigableString):
|
||||
self.data_list.append(tag.text)
|
||||
elif isinstance(tag, Tag):
|
||||
if tag.name == 'p':
|
||||
img_list = tag.find_all('img')
|
||||
if len(img_list) > 0:
|
||||
for img_item in img_list:
|
||||
self.data_list.append(img_item.get('src'))
|
||||
else:
|
||||
self.data_list.append(tag.text)
|
||||
elif tag.name == 'table':
|
||||
df_dict_list = self.parse_tag2list(tag)
|
||||
self.data_list.append(df_dict_list)
|
||||
elif tag.name == 'div':
|
||||
table_list = tag.find_all('table')
|
||||
if len(table_list) > 0:
|
||||
for table in table_list:
|
||||
df_dict_list = self.parse_tag2list(table)
|
||||
self.data_list.append(df_dict_list)
|
||||
|
||||
# 3.1.辅助方法,将<table>的Tag对象转为[[]]二维列表格式
|
||||
def parse_tag2list(self, table_tag):
|
||||
# str(tag)可直接变成<table>xxx</table>
|
||||
pd_list = pd.read_html(io.StringIO(str(table_tag)))
|
||||
# 将dataframe变为数组
|
||||
df = pd_list[0]
|
||||
# 处理第一行为数字的情况,如果为数字则删除第一行,让第二行为列名
|
||||
if all(isinstance(col, int) for col in df.columns):
|
||||
df.columns = df.iloc[0]
|
||||
df = df.drop(0) # 删除原来的第一行
|
||||
# 转为列表的列表(二维列表)
|
||||
# return df.values.tolist()
|
||||
return df.fillna('').T.reset_index().T.values.tolist()
|
||||
|
||||
# 3.2.辅助方法,打印解析后列表
|
||||
def print_content(self):
|
||||
for line in self.data_list:
|
||||
print(line)
|
||||
|
||||
# 4.1.最终方法,生成给docxtpl可用的列表 -> 注意需要传递DocxTemplate对象,在接口函数里面初始化的
|
||||
def get_final_list(self, doc, /, *, img_size=100, height=80):
|
||||
"""注意关键字传参可修改图片大小img_size:int=100"""
|
||||
final_list = []
|
||||
for oneline in self.data_list:
|
||||
# 这里要单独处理下二维列表
|
||||
if isinstance(oneline, list):
|
||||
final_list.append({'isTable': True, 'data': oneline})
|
||||
continue
|
||||
if oneline.startswith("data:image/png;base64") or oneline.startswith("data:image/jpeg;base64,") or oneline.startswith(
|
||||
"data:image/jpg;base64,"):
|
||||
base64_bytes = base64.b64decode(oneline.replace("data:image/png;base64,", ""))
|
||||
# ~~~设置了固定宽度、高度~~~
|
||||
inline_image = InlineImage(doc, io.BytesIO(base64_bytes), width=Mm(img_size), height=Mm(height))
|
||||
final_list.append(inline_image)
|
||||
else:
|
||||
final_list.append(oneline)
|
||||
if len(final_list) <= 0:
|
||||
final_list.append("")
|
||||
# 针对tinymce中,粘贴表格最后一行显示句号问题,这里统一删除
|
||||
if final_list[-1] == '\xa0':
|
||||
final_list.pop()
|
||||
return final_list
|
||||
|
||||
# 4.2.最终方法,在上面方法基础上,增加格式,例如<p>增加缩进,图片居中,<p>包含“图x”则居中
|
||||
def get_final_format_list(self, doc, /, *, img_size=115, height=80):
|
||||
final_list = []
|
||||
for oneline in self.data_list:
|
||||
# 这里要单独处理下二维列表
|
||||
if isinstance(oneline, list):
|
||||
final_list.append({'isTable': True, 'data': oneline})
|
||||
continue
|
||||
if oneline.startswith("data:image/png;base64"):
|
||||
base64_bytes = base64.b64decode(oneline.replace("data:image/png;base64,", ""))
|
||||
# 1.和上面函数变化:图片更改为dict然后isCenter属性居中
|
||||
final_list.append(
|
||||
{'isCenter': True,
|
||||
'data': InlineImage(doc, io.BytesIO(base64_bytes), width=Mm(img_size), height=height)})
|
||||
else:
|
||||
# 2.和上面区别:如果<p>带有“图”则居中
|
||||
if re.match(r"[表图]\d.*", oneline):
|
||||
final_list.append({"isCenter": True, "data": oneline})
|
||||
else:
|
||||
final_list.append({"isCenter": False, "data": oneline})
|
||||
if len(final_list) <= 0:
|
||||
final_list.append("")
|
||||
return final_list
|
||||
|
||||
# 5.最终方法,去掉图片和table元素 -> 纯文本列表
|
||||
def get_final_p_list(self):
|
||||
final_list = []
|
||||
for oneline in self.data_list:
|
||||
if isinstance(oneline, list) or oneline.startswith("data:image/png;base64"):
|
||||
continue
|
||||
cleaned_line = oneline
|
||||
cleaned_line = re.sub(r'\s+', '', cleaned_line)
|
||||
cleaned_line = cleaned_line.replace(')', ')')
|
||||
cleaned_line = cleaned_line.strip()
|
||||
# 去掉以“表3”的行
|
||||
if self.biao_pattern.search(cleaned_line):
|
||||
continue
|
||||
if cleaned_line:
|
||||
final_list.append(cleaned_line)
|
||||
return final_list
|
||||
"""
|
||||
专门解析富文本插件tinymce的html内容
|
||||
"""
|
||||
import pandas as pd
|
||||
from bs4 import BeautifulSoup
|
||||
from bs4.element import Tag, NavigableString
|
||||
import base64
|
||||
import io
|
||||
from docxtpl import InlineImage
|
||||
from docx.shared import Mm
|
||||
import re
|
||||
|
||||
# text.replace('\xa0', ' '))
|
||||
class RichParser:
|
||||
def __init__(self, rich_text):
|
||||
# 将rich_text的None变为空字符串:鲁棒
|
||||
if rich_text is None:
|
||||
rich_text = ""
|
||||
# 对原始html解析后的bs对象
|
||||
self.bs = BeautifulSoup(rich_text, 'html.parser')
|
||||
self.content = self.remove_n_in_contents()
|
||||
# 最终的解析后的列表
|
||||
self.data_list = []
|
||||
self.line_parse()
|
||||
# 匹配“表1-3”或“表1”等字符的正则
|
||||
self.biao_pattern = re.compile(r"表\d+(?:-\d+)?")
|
||||
|
||||
# 1.函数:将self.bs.contents去掉\n,获取每行数据
|
||||
def remove_n_in_contents(self):
|
||||
content_list = []
|
||||
for line in self.bs.contents:
|
||||
if line != '\n':
|
||||
content_list.append(line)
|
||||
return content_list
|
||||
|
||||
# 2.逐个遍历self.content,去掉table元素Tag对象单独解析
|
||||
def line_parse(self):
|
||||
for tag in self.content:
|
||||
if isinstance(tag, NavigableString):
|
||||
self.data_list.append(tag.text)
|
||||
elif isinstance(tag, Tag):
|
||||
if tag.name == 'p':
|
||||
img_list = tag.find_all('img')
|
||||
if len(img_list) > 0:
|
||||
for img_item in img_list:
|
||||
self.data_list.append(img_item.get('src'))
|
||||
else:
|
||||
self.data_list.append(tag.text)
|
||||
elif tag.name == 'table':
|
||||
df_dict_list = self.parse_tag2list(tag)
|
||||
self.data_list.append(df_dict_list)
|
||||
elif tag.name == 'div':
|
||||
table_list = tag.find_all('table')
|
||||
if len(table_list) > 0:
|
||||
for table in table_list:
|
||||
df_dict_list = self.parse_tag2list(table)
|
||||
self.data_list.append(df_dict_list)
|
||||
|
||||
# 3.1.辅助方法,将<table>的Tag对象转为[[]]二维列表格式
|
||||
def parse_tag2list(self, table_tag):
|
||||
# str(tag)可直接变成<table>xxx</table>
|
||||
pd_list = pd.read_html(io.StringIO(str(table_tag)))
|
||||
# 将dataframe变为数组
|
||||
df = pd_list[0]
|
||||
# 处理第一行为数字的情况,如果为数字则删除第一行,让第二行为列名
|
||||
if all(isinstance(col, int) for col in df.columns):
|
||||
df.columns = df.iloc[0]
|
||||
df = df.drop(0) # 删除原来的第一行
|
||||
# 转为列表的列表(二维列表)
|
||||
# return df.values.tolist()
|
||||
return df.fillna('').T.reset_index().T.values.tolist()
|
||||
|
||||
# 3.2.辅助方法,打印解析后列表
|
||||
def print_content(self):
|
||||
for line in self.data_list:
|
||||
print(line)
|
||||
|
||||
# 4.1.最终方法,生成给docxtpl可用的列表 -> 注意需要传递DocxTemplate对象,在接口函数里面初始化的
|
||||
def get_final_list(self, doc, /, *, img_size=100, height=80):
|
||||
"""注意关键字传参可修改图片大小img_size:int=100"""
|
||||
final_list = []
|
||||
for oneline in self.data_list:
|
||||
# 这里要单独处理下二维列表
|
||||
if isinstance(oneline, list):
|
||||
final_list.append({'isTable': True, 'data': oneline})
|
||||
continue
|
||||
if oneline.startswith("data:image/png;base64") or oneline.startswith("data:image/jpeg;base64,") or oneline.startswith(
|
||||
"data:image/jpg;base64,"):
|
||||
base64_bytes = base64.b64decode(oneline.replace("data:image/png;base64,", ""))
|
||||
# ~~~设置了固定宽度、高度~~~
|
||||
inline_image = InlineImage(doc, io.BytesIO(base64_bytes), width=Mm(img_size), height=Mm(height))
|
||||
final_list.append(inline_image)
|
||||
else:
|
||||
# ~~~新增:将\xa0修改为普通空格~~~
|
||||
oneline = oneline.replace('\xa0', ' ')
|
||||
final_list.append(oneline)
|
||||
if len(final_list) <= 0:
|
||||
final_list.append("")
|
||||
# 针对tinymce中,粘贴表格最后一行显示句号问题,这里统一删除
|
||||
if final_list[-1] == '\xa0':
|
||||
final_list.pop()
|
||||
return final_list
|
||||
|
||||
# 4.2.最终方法,在上面方法基础上,增加格式,例如<p>增加缩进,图片居中,<p>包含“图x”则居中
|
||||
def get_final_format_list(self, doc, /, *, img_size=115, height=80):
|
||||
final_list = []
|
||||
for oneline in self.data_list:
|
||||
# 这里要单独处理下二维列表
|
||||
if isinstance(oneline, list):
|
||||
final_list.append({'isTable': True, 'data': oneline})
|
||||
continue
|
||||
if oneline.startswith("data:image/png;base64"):
|
||||
base64_bytes = base64.b64decode(oneline.replace("data:image/png;base64,", ""))
|
||||
# 1.和上面函数变化:图片更改为dict然后isCenter属性居中
|
||||
final_list.append(
|
||||
{'isCenter': True,
|
||||
'data': InlineImage(doc, io.BytesIO(base64_bytes), width=Mm(img_size), height=height)})
|
||||
else:
|
||||
# 2.和上面区别:如果<p>带有“图”则居中
|
||||
if re.match(r"[表图]\d.*", oneline):
|
||||
final_list.append({"isCenter": True, "data": oneline.replace('\xa0', ' ')})
|
||||
else:
|
||||
final_list.append({"isCenter": False, "data": oneline.replace('\xa0', ' ')})
|
||||
if len(final_list) <= 0:
|
||||
final_list.append("")
|
||||
return final_list
|
||||
|
||||
# 5.最终方法,去掉图片和table元素 -> 纯文本列表
|
||||
def get_final_p_list(self):
|
||||
final_list = []
|
||||
for oneline in self.data_list:
|
||||
if isinstance(oneline, list) or oneline.startswith("data:image/png;base64"):
|
||||
continue
|
||||
cleaned_line = oneline
|
||||
cleaned_line = re.sub(r'\s+', '', cleaned_line)
|
||||
cleaned_line = cleaned_line.replace(')', ')')
|
||||
cleaned_line = cleaned_line.strip()
|
||||
# 去掉以“表3”的行
|
||||
if self.biao_pattern.search(cleaned_line):
|
||||
continue
|
||||
if cleaned_line:
|
||||
final_list.append(cleaned_line)
|
||||
return final_list
|
||||
|
||||
Reference in New Issue
Block a user