修复说明reuse文件夹图片丢失问题
This commit is contained in:
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -1,348 +1,352 @@
|
|||||||
"""该文件是:替换文档片段然后生成辅助生成最终文档"""
|
"""该文件是:替换文档片段然后生成辅助生成最终文档"""
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from typing import List, Dict
|
from typing import List, Dict
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from docx import Document
|
from docx import Document
|
||||||
from docx.text.paragraph import Paragraph
|
from docx.text.paragraph import Paragraph
|
||||||
from docx.table import Table
|
from docx.table import Table
|
||||||
from docx.oxml.table import CT_Tbl
|
from docx.oxml.table import CT_Tbl
|
||||||
from docx.oxml.text.paragraph import CT_P
|
from docx.oxml.text.paragraph import CT_P
|
||||||
from docx.oxml.text.run import CT_R
|
from docx.oxml.text.run import CT_R
|
||||||
from docx.oxml.shape import CT_Picture
|
from docx.oxml.shape import CT_Picture
|
||||||
from docx.parts.image import ImagePart
|
from docx.parts.image import ImagePart
|
||||||
from docx.text.run import Run
|
from docx.text.run import Run
|
||||||
from docx.shared import Mm
|
from docx.shared import Mm
|
||||||
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
|
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
|
||||||
from lxml.etree import _Element
|
from lxml.etree import _Element
|
||||||
|
|
||||||
# 路径工具
|
# 路径工具
|
||||||
from utils.path_utils import project_path
|
from utils.path_utils import project_path
|
||||||
|
|
||||||
### 模块变量:定义常用图片所在区域的宽高
|
### 模块变量:定义常用图片所在区域的宽高
|
||||||
Demand_table_xqms = Mm(134) # 1.测评大纲-测试项里面-需求描述单元格
|
Demand_table_xqms = Mm(134) # 1.测评大纲-测试项里面-需求描述单元格
|
||||||
Timing_diagram_width = Mm(242) # 2.测试记录-时序图
|
Timing_diagram_width = Mm(242) # 2.测试记录-时序图
|
||||||
Test_result_width = Mm(78) # 3.测试记录-测试结果
|
Test_result_width = Mm(78) # 3.测试记录-测试结果
|
||||||
Horizatal_width = Mm(130) # 4.所有文档-页面图片的横向距离(图片宽度预设置)
|
Horizatal_width = Mm(130) # 4.所有文档-页面图片的横向距离(图片宽度预设置)
|
||||||
|
|
||||||
def getParentRunNode(node):
|
def getParentRunNode(node):
|
||||||
"""传入oxml节点对象,获取其祖先节点的CT_R"""
|
"""传入oxml节点对象,获取其祖先节点的CT_R"""
|
||||||
if isinstance(node, CT_R):
|
if isinstance(node, CT_R):
|
||||||
return node
|
return node
|
||||||
return getParentRunNode(node.getparent())
|
return getParentRunNode(node.getparent())
|
||||||
|
|
||||||
def generate_temp_doc(doc_type: str, project_id: int, round_num=None, frag_list=None):
|
def generate_temp_doc(doc_type: str, project_id: int, round_num=None, frag_list=None):
|
||||||
""" 该函数参数:
|
""" 该函数参数:
|
||||||
:param frag_list: 储存用户不覆盖的片段列表
|
:param frag_list: 储存用户不覆盖的片段列表
|
||||||
:param round_num: 只有回归说明和回归记录有
|
:param round_num: 只有回归说明和回归记录有
|
||||||
:param project_id: 项目id
|
:param project_id: 项目id
|
||||||
:param doc_type:大纲 sm:说明 jl:记录 bg:报告 hsm:回归测试说明 hjl:回归测试记录,默认路径为dg -> 所以如果传错就生成生成大纲了
|
:param doc_type:大纲 sm:说明 jl:记录 bg:报告 hsm:回归测试说明 hjl:回归测试记录,默认路径为dg -> 所以如果传错就生成生成大纲了
|
||||||
:return (to_tpl_file路径, seitai_final_file路径)
|
:return (to_tpl_file路径, seitai_final_file路径)
|
||||||
"""
|
"""
|
||||||
if frag_list is None:
|
if frag_list is None:
|
||||||
frag_list = []
|
frag_list = []
|
||||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
project_path_str = project_path(project_id)
|
project_path_str = project_path(project_id)
|
||||||
# 根据传入需要处理的文档类型,自动获路径
|
# 根据传入需要处理的文档类型,自动获路径
|
||||||
prefix = Path.cwd() / 'media' / project_path_str
|
prefix = Path.cwd() / 'media' / project_path_str
|
||||||
template_file: Path = prefix / 'form_template' / 'products' / '测评大纲.docx'
|
template_file: Path = prefix / 'form_template' / 'products' / '测评大纲.docx'
|
||||||
to_tpl_file: Path = prefix / 'temp' / '测评大纲.docx'
|
to_tpl_file: Path = prefix / 'temp' / '测评大纲.docx'
|
||||||
seitai_final_file: Path = prefix / 'final_seitai' / '测评大纲.docx'
|
seitai_final_file: Path = prefix / 'final_seitai' / '测评大纲.docx'
|
||||||
if doc_type == 'sm':
|
if doc_type == 'sm':
|
||||||
template_file = prefix / 'form_template' / 'products' / '测试说明.docx'
|
template_file = prefix / 'form_template' / 'products' / '测试说明.docx'
|
||||||
to_tpl_file = prefix / 'temp' / '测试说明.docx'
|
to_tpl_file = prefix / 'temp' / '测试说明.docx'
|
||||||
seitai_final_file: Path = prefix / 'final_seitai' / '测试说明.docx'
|
seitai_final_file: Path = prefix / 'final_seitai' / '测试说明.docx'
|
||||||
elif doc_type == 'jl':
|
elif doc_type == 'jl':
|
||||||
template_file = prefix / 'form_template' / 'products' / '测试记录.docx'
|
template_file = prefix / 'form_template' / 'products' / '测试记录.docx'
|
||||||
to_tpl_file = prefix / 'temp' / '测试记录.docx'
|
to_tpl_file = prefix / 'temp' / '测试记录.docx'
|
||||||
seitai_final_file: Path = prefix / 'final_seitai' / '测试记录.docx'
|
seitai_final_file: Path = prefix / 'final_seitai' / '测试记录.docx'
|
||||||
elif doc_type == 'bg':
|
elif doc_type == 'bg':
|
||||||
template_file = prefix / 'form_template' / 'products' / '测评报告.docx'
|
template_file = prefix / 'form_template' / 'products' / '测评报告.docx'
|
||||||
to_tpl_file = prefix / 'temp' / '测评报告.docx'
|
to_tpl_file = prefix / 'temp' / '测评报告.docx'
|
||||||
seitai_final_file: Path = prefix / 'final_seitai' / '测评报告.docx'
|
seitai_final_file: Path = prefix / 'final_seitai' / '测评报告.docx'
|
||||||
elif doc_type == 'hsm':
|
elif doc_type == 'hsm':
|
||||||
# 如果products里面存在“用户上传的第n轮回归测试说明.docx,则使用它作为模版”
|
# 如果products里面存在“用户上传的第n轮回归测试说明.docx,则使用它作为模版”
|
||||||
template_file = prefix / 'form_template' / 'products' / f'第{round_num}轮回归测试说明.docx'
|
template_file = prefix / 'form_template' / 'products' / f'第{round_num}轮回归测试说明.docx'
|
||||||
if not template_file.exists():
|
if not template_file.exists():
|
||||||
template_file = prefix / 'form_template' / 'products' / '回归测试说明.docx'
|
template_file = prefix / 'form_template' / 'products' / '回归测试说明.docx'
|
||||||
to_tpl_file = prefix / 'temp' / f'第{round_num}轮回归测试说明.docx'
|
to_tpl_file = prefix / 'temp' / f'第{round_num}轮回归测试说明.docx'
|
||||||
seitai_final_file: Path = prefix / 'final_seitai' / f'第{round_num}轮回归测试说明.docx'
|
seitai_final_file: Path = prefix / 'final_seitai' / f'第{round_num}轮回归测试说明.docx'
|
||||||
elif doc_type == 'hjl':
|
elif doc_type == 'hjl':
|
||||||
# 如果products里面存在“用户上传的第n轮回归测试记录.docx,则使用它作为模版”
|
# 如果products里面存在“用户上传的第n轮回归测试记录.docx,则使用它作为模版”
|
||||||
template_file = prefix / 'form_template' / 'products' / f'第{round_num}轮回归测试记录.docx'
|
template_file = prefix / 'form_template' / 'products' / f'第{round_num}轮回归测试记录.docx'
|
||||||
if not template_file.exists():
|
if not template_file.exists():
|
||||||
template_file = prefix / 'form_template' / 'products' / '回归测试记录.docx'
|
template_file = prefix / 'form_template' / 'products' / '回归测试记录.docx'
|
||||||
to_tpl_file = prefix / 'temp' / f'第{round_num}轮回归测试记录.docx'
|
to_tpl_file = prefix / 'temp' / f'第{round_num}轮回归测试记录.docx'
|
||||||
seitai_final_file: Path = prefix / 'final_seitai' / f'第{round_num}轮回归测试记录.docx'
|
seitai_final_file: Path = prefix / 'final_seitai' / f'第{round_num}轮回归测试记录.docx'
|
||||||
elif doc_type == 'wtd':
|
elif doc_type == 'wtd':
|
||||||
template_file = prefix / 'form_template' / 'products' / '问题单.docx'
|
template_file = prefix / 'form_template' / 'products' / '问题单.docx'
|
||||||
to_tpl_file = prefix / 'temp' / '问题单.docx'
|
to_tpl_file = prefix / 'temp' / '问题单.docx'
|
||||||
seitai_final_file: Path = prefix / 'final_seitai' / '问题单.docx'
|
seitai_final_file: Path = prefix / 'final_seitai' / '问题单.docx'
|
||||||
# 定义找寻被复制文件根路径 - 后续会根据type找子路径
|
# 定义找寻被复制文件根路径 - 后续会根据type找子路径
|
||||||
output_files_path = prefix / 'output_dir'
|
output_files_path = prefix / 'output_dir'
|
||||||
# 这里可能修改,储存大纲里面的文档片段
|
# 这里可能修改,储存大纲里面的文档片段
|
||||||
dg_copied_files = []
|
dg_copied_files = []
|
||||||
# 储存sm/jl/hsm/hjl/bg/wtd的文档片段
|
# 储存sm/jl/hsm/hjl/bg/wtd的文档片段
|
||||||
exclusive_copied_files = []
|
exclusive_copied_files = []
|
||||||
# 新:储存reuse的文档片段
|
# 新:储存reuse的文档片段
|
||||||
reuse_files = []
|
reuse_files = []
|
||||||
# 将被拷贝文件分别放入不同两个数组
|
# 将被拷贝文件分别放入不同两个数组
|
||||||
for file in output_files_path.iterdir():
|
for file in output_files_path.iterdir():
|
||||||
if file.is_file():
|
if file.is_file():
|
||||||
if file.suffix == '.docx':
|
if file.suffix == '.docx':
|
||||||
dg_copied_files.append(file)
|
dg_copied_files.append(file)
|
||||||
elif file.is_dir():
|
elif file.is_dir():
|
||||||
# 如果文件夹名称为sm/jl/hsm/hjl/bg/wtd则进入该判断
|
# 如果文件夹名称为sm/jl/hsm/hjl/bg/wtd则进入该判断
|
||||||
# 所以要求文件系统文件夹名称必须是sm/jl/hsm/hjl/bg/wtd不然无法生成
|
# 所以要求文件系统文件夹名称必须是sm/jl/hsm/hjl/bg/wtd不然无法生成
|
||||||
if file.stem == doc_type:
|
if file.stem == doc_type:
|
||||||
for f in file.iterdir():
|
for f in file.iterdir():
|
||||||
if f.suffix == '.docx':
|
if f.suffix == '.docx':
|
||||||
exclusive_copied_files.append(f)
|
exclusive_copied_files.append(f)
|
||||||
for file in (prefix / 'reuse').iterdir():
|
for file in (prefix / 'reuse').iterdir():
|
||||||
if file.is_file():
|
if file.is_file():
|
||||||
if file.suffix == '.docx':
|
if file.suffix == '.docx':
|
||||||
reuse_files.append(file)
|
reuse_files.append(file)
|
||||||
# 找到基础模版的所有std域
|
# 找到基础模版的所有std域
|
||||||
doc = Document(template_file.as_posix())
|
doc = Document(template_file.as_posix())
|
||||||
body = doc.element.body
|
body = doc.element.body
|
||||||
sdt_element_list = body.xpath('./w:sdt')
|
sdt_element_list = body.xpath('./w:sdt')
|
||||||
# 找到sdt域的名称 -> 为了对应output_dir文件 / 储存所有output_dir图片
|
# 找到sdt域的名称 -> 为了对应output_dir文件 / 储存所有output_dir图片
|
||||||
area_name_list = []
|
area_name_list = []
|
||||||
image_part_list = [] # 修改为字典两个字段{ 'name':'测评对象', 'img':ImagePart }
|
image_part_list = [] # 修改为字典两个字段{ 'name':'测评对象', 'img':ImagePart }
|
||||||
# 筛选片段【二】:用户前端要求不要覆盖的文档片段
|
# 筛选片段【二】:用户前端要求不要覆盖的文档片段
|
||||||
frag_is_cover_dict = {item.name: item.isCover for item in frag_list}
|
frag_is_cover_dict = {item.name: item.isCover for item in frag_list}
|
||||||
# 遍历所有控件 -> 放入area_name_list【这里准备提取公共代码】
|
# 遍历所有控件 -> 放入area_name_list【这里准备提取公共代码】
|
||||||
for sdt_ele in sdt_element_list:
|
for sdt_ele in sdt_element_list:
|
||||||
isLock = False
|
isLock = False
|
||||||
for elem in sdt_ele.iterchildren():
|
for elem in sdt_ele.iterchildren():
|
||||||
# 【一】用户设置lock - 下面2个if将需要被替换的(控件名称)存入area_name_list
|
# 【一】用户设置lock - 下面2个if将需要被替换的(控件名称)存入area_name_list
|
||||||
if elem.tag.endswith('sdtPr'):
|
if elem.tag.endswith('sdtPr'):
|
||||||
for el in elem.getchildren():
|
for el in elem.getchildren():
|
||||||
if el.tag.endswith('lock'):
|
if el.tag.endswith('lock'):
|
||||||
isLock = True
|
isLock = True
|
||||||
if elem.tag.endswith('sdtPr'):
|
if elem.tag.endswith('sdtPr'):
|
||||||
for el in elem.getchildren():
|
for el in elem.getchildren():
|
||||||
if el.tag.endswith('alias'):
|
if el.tag.endswith('alias'):
|
||||||
# 筛序【一】:取出用户设置lock的文档片段
|
# 筛序【一】:取出用户设置lock的文档片段
|
||||||
if len(el.attrib.values()) > 0 and (isLock == False):
|
if len(el.attrib.values()) > 0 and (isLock == False):
|
||||||
area_name = el.attrib.values()[0]
|
area_name = el.attrib.values()[0]
|
||||||
# 筛选【二】:前端用户选择要覆盖的片段
|
# 筛选【二】:前端用户选择要覆盖的片段
|
||||||
if frag_is_cover_dict.get(area_name):
|
if frag_is_cover_dict.get(area_name):
|
||||||
area_name_list.append(area_name)
|
area_name_list.append(area_name)
|
||||||
# 下面开始替换area_name_list的“域”(这时已经被筛选-因为sdtPr和sdtContent是成对出现)
|
# 下面开始替换area_name_list的“域”(这时已经被筛选-因为sdtPr和sdtContent是成对出现)
|
||||||
if elem.tag.endswith('sdtContent'):
|
if elem.tag.endswith('sdtContent'):
|
||||||
if len(area_name_list) > 0:
|
if len(area_name_list) > 0:
|
||||||
# 从第一个片段名称开始取,取到模版的“域”名称
|
# 从第一个片段名称开始取,取到模版的“域”名称
|
||||||
area_pop_name = area_name_list.pop(0)
|
area_pop_name = area_name_list.pop(0)
|
||||||
# 这里先去找media/output_dir/xx下文件,然后找media/output下文件
|
# 这里先去找media/output_dir/xx下文件,然后找media/output下文件
|
||||||
copied_file_path = ""
|
copied_file_path = ""
|
||||||
# 下面if...else是找output_dir下面文件与“域”名称匹配,匹配到存入copied_file_path
|
# 下面if...else是找output_dir下面文件与“域”名称匹配,匹配到存入copied_file_path
|
||||||
if doc_type == 'dg':
|
if doc_type == 'dg':
|
||||||
for file in dg_copied_files:
|
for file in dg_copied_files:
|
||||||
if file.stem == area_pop_name:
|
if file.stem == area_pop_name:
|
||||||
copied_file_path = file
|
copied_file_path = file
|
||||||
else:
|
else:
|
||||||
# 如果不是大纲
|
# 如果不是大纲
|
||||||
if round_num is None:
|
if round_num is None:
|
||||||
# 如果非回归说明、记录
|
# 如果非回归说明、记录
|
||||||
for file in exclusive_copied_files:
|
for file in exclusive_copied_files:
|
||||||
if file.stem == area_pop_name:
|
if file.stem == area_pop_name:
|
||||||
copied_file_path = file
|
copied_file_path = file
|
||||||
# 这里判断是否copied_file_path没取到文件,然后遍历reuse下文件
|
# 这里判断是否copied_file_path没取到文件,然后遍历reuse下文件
|
||||||
if not copied_file_path:
|
if not copied_file_path:
|
||||||
for file in reuse_files:
|
for file in reuse_files:
|
||||||
if file.stem == area_pop_name:
|
if file.stem == area_pop_name:
|
||||||
copied_file_path = file
|
copied_file_path = file
|
||||||
# 如果上面被复制文件还没找到,然后遍历output_dir下文件
|
# 如果上面被复制文件还没找到,然后遍历output_dir下文件
|
||||||
if not copied_file_path:
|
if not copied_file_path:
|
||||||
for file in dg_copied_files:
|
for file in dg_copied_files:
|
||||||
if file.stem == area_pop_name:
|
if file.stem == area_pop_name:
|
||||||
copied_file_path = file
|
copied_file_path = file
|
||||||
else:
|
else:
|
||||||
# 因为回归的轮次,前面会加 -> 第{round_num}轮
|
# 因为回归的轮次,前面会加 -> 第{round_num}轮
|
||||||
for file in exclusive_copied_files: # 这里多了第{round_num}轮
|
for file in exclusive_copied_files: # 这里多了第{round_num}轮
|
||||||
if file.stem == f"第{round_num}轮{area_pop_name}":
|
if file.stem == f"第{round_num}轮{area_pop_name}":
|
||||||
copied_file_path = file
|
copied_file_path = file
|
||||||
if not copied_file_path:
|
if not copied_file_path:
|
||||||
for file in reuse_files:
|
for file in reuse_files:
|
||||||
if file.stem == area_pop_name:
|
if file.stem == area_pop_name:
|
||||||
copied_file_path = file
|
copied_file_path = file
|
||||||
if not copied_file_path:
|
if not copied_file_path:
|
||||||
for file in dg_copied_files:
|
for file in dg_copied_files:
|
||||||
if file.stem == area_pop_name:
|
if file.stem == area_pop_name:
|
||||||
copied_file_path = file
|
copied_file_path = file
|
||||||
# 找到文档片段.docx,将其数据复制到对应area_name的“域”
|
# 找到文档片段.docx,将其数据复制到对应area_name的“域”
|
||||||
if copied_file_path:
|
if copied_file_path:
|
||||||
doc_copied = Document(copied_file_path)
|
doc_copied = Document(copied_file_path)
|
||||||
copied_element_list = []
|
copied_element_list = []
|
||||||
element_list = doc_copied.element.body.inner_content_elements
|
element_list = doc_copied.element.body.inner_content_elements
|
||||||
for elet in element_list:
|
for elet in element_list:
|
||||||
if isinstance(elet, CT_P):
|
if isinstance(elet, CT_P):
|
||||||
copied_element_list.append(Paragraph(elet, doc_copied))
|
copied_element_list.append(Paragraph(elet, doc_copied))
|
||||||
if isinstance(elet, CT_Tbl):
|
if isinstance(elet, CT_Tbl):
|
||||||
copied_element_list.append(Table(elet, doc_copied))
|
copied_element_list.append(Table(elet, doc_copied))
|
||||||
elem.clear()
|
elem.clear()
|
||||||
for para_copied in copied_element_list:
|
for para_copied in copied_element_list:
|
||||||
elem.append(para_copied._element)
|
elem.append(para_copied._element)
|
||||||
|
|
||||||
# 下面代码就是将图片全部提取到image_part_list,以便后续插入,注意这时候已经是筛选后的
|
# 下面代码就是将图片全部提取到image_part_list,以便后续插入,注意这时候已经是筛选后的
|
||||||
doc_copied = Document(copied_file_path) # 需要重新获取否则namespace错误
|
doc_copied = Document(copied_file_path) # 需要重新获取否则namespace错误
|
||||||
copied_body = doc_copied.element.body
|
copied_body = doc_copied.element.body
|
||||||
img_node_list = copied_body.xpath('.//pic:pic')
|
img_node_list = copied_body.xpath('.//pic:pic')
|
||||||
if not img_node_list:
|
if not img_node_list:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
for img_node in img_node_list:
|
for img_node in img_node_list:
|
||||||
img: CT_Picture = img_node
|
img: CT_Picture = img_node
|
||||||
# 根据节点找到图片的关联id
|
# 根据节点找到图片的关联id
|
||||||
embed = img.xpath('.//a:blip/@r:embed')[0]
|
embed = img.xpath('.//a:blip/@r:embed')[0]
|
||||||
# 这里得到ImagePart -> 马上要给新文档添加
|
# 这里得到ImagePart -> 马上要给新文档添加
|
||||||
related_part: ImagePart = doc_copied.part.related_parts[embed]
|
related_part: ImagePart = doc_copied.part.related_parts.get(embed)
|
||||||
# doc_copied.part.related_parts是一个字典
|
if related_part is None:
|
||||||
image_part_list.append({'name': area_pop_name, 'img': related_part})
|
# 可选:记录警告日志,便于排查哪些文档片段有问题
|
||||||
|
print(f"警告: 文档片段 '{area_pop_name}' 中的图片引用 {embed} 未找到,已跳过!!!!")
|
||||||
# 现在是替换后,找到替换后文档所有pic:pic,并对“域”名称进行识别
|
continue
|
||||||
graph_node_list = body.xpath('.//pic:pic')
|
# doc_copied.part.related_parts是一个字典
|
||||||
graph_node_list_transform = []
|
image_part_list.append({'name': area_pop_name, 'img': related_part})
|
||||||
for picNode in graph_node_list:
|
|
||||||
# 遍历替换后模版的所有pic,去找祖先
|
# 现在是替换后,找到替换后文档所有pic:pic,并对“域”名称进行识别
|
||||||
sdt_node = picNode.xpath('ancestor::w:sdt[1]')[0]
|
graph_node_list = body.xpath('.//pic:pic')
|
||||||
for sdt_node_child in sdt_node.iterchildren():
|
graph_node_list_transform = []
|
||||||
# 找到sdt下一级的stdPr
|
for picNode in graph_node_list:
|
||||||
if sdt_node_child.tag.endswith('sdtPr'):
|
# 遍历替换后模版的所有pic,去找祖先
|
||||||
for sdtPr_node_child in sdt_node_child.getchildren():
|
sdt_node = picNode.xpath('ancestor::w:sdt[1]')[0]
|
||||||
if sdtPr_node_child.tag.endswith('alias'):
|
for sdt_node_child in sdt_node.iterchildren():
|
||||||
yu_name = sdtPr_node_child.attrib.values()[0]
|
# 找到sdt下一级的stdPr
|
||||||
graph_node_list_transform.append({'yu_name': yu_name, 'yu_node': picNode})
|
if sdt_node_child.tag.endswith('sdtPr'):
|
||||||
for graph_node in graph_node_list_transform:
|
for sdtPr_node_child in sdt_node_child.getchildren():
|
||||||
image_run_node = getParentRunNode(graph_node['yu_node'])
|
if sdtPr_node_child.tag.endswith('alias'):
|
||||||
image_run_node.clear()
|
yu_name = sdtPr_node_child.attrib.values()[0]
|
||||||
# 循环去image_part_list找name和yu_name相等的图片
|
graph_node_list_transform.append({'yu_name': yu_name, 'yu_node': picNode})
|
||||||
for img_part in image_part_list:
|
for graph_node in graph_node_list_transform:
|
||||||
# 1.如果找到相等
|
image_run_node = getParentRunNode(graph_node['yu_node'])
|
||||||
if img_part['name'] == graph_node['yu_name']:
|
image_run_node.clear()
|
||||||
# 2.找到即可添加图片到“域”
|
# 循环去image_part_list找name和yu_name相等的图片
|
||||||
image_run_node.clear()
|
for img_part in image_part_list:
|
||||||
# 辅助:去找其父节点是否为段落,是段落则存起来,后面好居中
|
# 1.如果找到相等
|
||||||
image_run_parent_paragraph = image_run_node.getparent()
|
if img_part['name'] == graph_node['yu_name']:
|
||||||
father_paragraph = None
|
# 2.找到即可添加图片到“域”
|
||||||
if isinstance(image_run_parent_paragraph, CT_P):
|
image_run_node.clear()
|
||||||
father_paragraph = Paragraph(image_run_parent_paragraph, doc)
|
# 辅助:去找其父节点是否为段落,是段落则存起来,后面好居中
|
||||||
copied_bytes_io = BytesIO(img_part['img'].image.blob)
|
image_run_parent_paragraph = image_run_node.getparent()
|
||||||
r_element = Run(image_run_node, doc)
|
father_paragraph = None
|
||||||
inline_shape = r_element.add_picture(copied_bytes_io)
|
if isinstance(image_run_parent_paragraph, CT_P):
|
||||||
## 2.1.统一:这里设置文档片段里面的图片大小和位置
|
father_paragraph = Paragraph(image_run_parent_paragraph, doc)
|
||||||
source_width = inline_shape.width
|
copied_bytes_io = BytesIO(img_part['img'].image.blob)
|
||||||
source_height = inline_shape.height
|
r_element = Run(image_run_node, doc)
|
||||||
if source_width >= source_height:
|
inline_shape = r_element.add_picture(copied_bytes_io)
|
||||||
inline_shape.width = Mm(120)
|
## 2.1.统一:这里设置文档片段里面的图片大小和位置
|
||||||
inline_shape.height = int(inline_shape.height * (inline_shape.width / source_width))
|
source_width = inline_shape.width
|
||||||
else:
|
source_height = inline_shape.height
|
||||||
inline_shape.height = Mm(60)
|
if source_width >= source_height:
|
||||||
inline_shape.width = int(inline_shape.width * (inline_shape.height / source_height))
|
inline_shape.width = Mm(120)
|
||||||
## 2.2.设置图片所在段落居中对齐
|
inline_shape.height = int(inline_shape.height * (inline_shape.width / source_width))
|
||||||
if father_paragraph:
|
else:
|
||||||
father_paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
|
inline_shape.height = Mm(60)
|
||||||
r_element.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
|
inline_shape.width = int(inline_shape.width * (inline_shape.height / source_height))
|
||||||
# 3.因为按顺序的,所以移除image_part_list中已经替换的图片
|
## 2.2.设置图片所在段落居中对齐
|
||||||
image_part_list.remove(img_part)
|
if father_paragraph:
|
||||||
break
|
father_paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
|
||||||
try:
|
r_element.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
|
||||||
# 这里直接生成产品文档
|
# 3.因为按顺序的,所以移除image_part_list中已经替换的图片
|
||||||
doc.save(str(to_tpl_file))
|
image_part_list.remove(img_part)
|
||||||
return to_tpl_file, seitai_final_file
|
break
|
||||||
except PermissionError as e:
|
try:
|
||||||
return {'code': 'error', 'msg': '生成的temp文件已打开,请关闭后重试...'}
|
# 这里直接生成产品文档
|
||||||
|
doc.save(str(to_tpl_file))
|
||||||
def get_frag_from_document(doc_path: Path) -> List[Dict]:
|
return to_tpl_file, seitai_final_file
|
||||||
"""传入products的文件路径,识别出所有文档片段名称,数组返回:要求docx里面文档名称不能更变"""
|
except PermissionError as e:
|
||||||
doc = Document(doc_path.as_posix())
|
return {'code': 'error', 'msg': '生成的temp文件已打开,请关闭后重试...'}
|
||||||
sdt_element_list = doc.element.body.xpath('./w:sdt')
|
|
||||||
# 整个for循环识别文档片段名称
|
def get_frag_from_document(doc_path: Path) -> List[Dict]:
|
||||||
area_name_list = []
|
"""传入products的文件路径,识别出所有文档片段名称,数组返回:要求docx里面文档名称不能更变"""
|
||||||
for sdt_ele in sdt_element_list:
|
doc = Document(doc_path.as_posix())
|
||||||
isLock = False
|
sdt_element_list = doc.element.body.xpath('./w:sdt')
|
||||||
alias_value = None
|
# 整个for循环识别文档片段名称
|
||||||
for elem in sdt_ele.iterchildren():
|
area_name_list = []
|
||||||
if elem.tag.endswith('sdtPr'):
|
for sdt_ele in sdt_element_list:
|
||||||
for el in elem.getchildren():
|
isLock = False
|
||||||
if el.tag.endswith('alias'):
|
alias_value = None
|
||||||
alias_value = el.attrib.values()
|
for elem in sdt_ele.iterchildren():
|
||||||
# 查找是否被用户在模版上标记了Lock
|
if elem.tag.endswith('sdtPr'):
|
||||||
if el.tag.endswith('lock'):
|
for el in elem.getchildren():
|
||||||
isLock = True
|
if el.tag.endswith('alias'):
|
||||||
if alias_value and len(alias_value):
|
alias_value = el.attrib.values()
|
||||||
area_name_list.append({'frag_name': alias_value[0], 'isLock': isLock})
|
# 查找是否被用户在模版上标记了Lock
|
||||||
return area_name_list
|
if el.tag.endswith('lock'):
|
||||||
|
isLock = True
|
||||||
# 辅助函数-传入temp文件路径(已替换文档片段的temp文档),输出stdContent
|
if alias_value and len(alias_value):
|
||||||
def get_jinja_stdContent_element(temp_docx_path: Path):
|
area_name_list.append({'frag_name': alias_value[0], 'isLock': isLock})
|
||||||
doc_docx = Document(temp_docx_path.as_posix())
|
return area_name_list
|
||||||
body = doc_docx.element.body
|
|
||||||
# 储存文本片段
|
# 辅助函数-传入temp文件路径(已替换文档片段的temp文档),输出stdContent
|
||||||
text_frag_name_list = []
|
def get_jinja_stdContent_element(temp_docx_path: Path):
|
||||||
sdt_element_list = body.xpath('//w:sdt')
|
doc_docx = Document(temp_docx_path.as_posix())
|
||||||
|
body = doc_docx.element.body
|
||||||
# 注意python-docx的页头的文本片段不在body里面,而在section.header里面
|
# 储存文本片段
|
||||||
# 所以定义辅助函数,统一处理
|
text_frag_name_list = []
|
||||||
def deel_sdt_content(*args):
|
sdt_element_list = body.xpath('//w:sdt')
|
||||||
"""传入sdt_element列表,将其sdtContent加入外部的文本片段列表"""
|
|
||||||
for sdt_ele in args:
|
# 注意python-docx的页头的文本片段不在body里面,而在section.header里面
|
||||||
# 找出每个sdt下面的3个标签
|
# 所以定义辅助函数,统一处理
|
||||||
tag_value = None
|
def deel_sdt_content(*args):
|
||||||
alias_value = None
|
"""传入sdt_element列表,将其sdtContent加入外部的文本片段列表"""
|
||||||
sdtContent_ele = None
|
for sdt_ele in args:
|
||||||
for sdt_ele_child in sdt_ele.iterchildren():
|
# 找出每个sdt下面的3个标签
|
||||||
if sdt_ele_child.tag.endswith('sdtPr'):
|
tag_value = None
|
||||||
for sdtPr_ele_child in sdt_ele_child.getchildren():
|
alias_value = None
|
||||||
if sdtPr_ele_child.tag.endswith('tag'):
|
sdtContent_ele = None
|
||||||
if len(sdtPr_ele_child.attrib.values()) > 0:
|
for sdt_ele_child in sdt_ele.iterchildren():
|
||||||
tag_value = sdtPr_ele_child.attrib.values()[0]
|
if sdt_ele_child.tag.endswith('sdtPr'):
|
||||||
if sdtPr_ele_child.tag.endswith('alias'):
|
for sdtPr_ele_child in sdt_ele_child.getchildren():
|
||||||
if len(sdtPr_ele_child.attrib.values()) > 0:
|
if sdtPr_ele_child.tag.endswith('tag'):
|
||||||
alias_value = sdtPr_ele_child.attrib.values()[0]
|
if len(sdtPr_ele_child.attrib.values()) > 0:
|
||||||
if sdt_ele_child.tag.endswith('sdtContent'):
|
tag_value = sdtPr_ele_child.attrib.values()[0]
|
||||||
sdtContent_ele = sdt_ele_child
|
if sdtPr_ele_child.tag.endswith('alias'):
|
||||||
# 找出所有tag_value为jinja的文本片段
|
if len(sdtPr_ele_child.attrib.values()) > 0:
|
||||||
if tag_value == 'jinja' and alias_value is not None and sdtContent_ele is not None:
|
alias_value = sdtPr_ele_child.attrib.values()[0]
|
||||||
text_frag_name_list.append({'alias': alias_value, 'sdtContent': sdtContent_ele})
|
if sdt_ele_child.tag.endswith('sdtContent'):
|
||||||
|
sdtContent_ele = sdt_ele_child
|
||||||
deel_sdt_content(*sdt_element_list)
|
# 找出所有tag_value为jinja的文本片段
|
||||||
for section in doc_docx.sections:
|
if tag_value == 'jinja' and alias_value is not None and sdtContent_ele is not None:
|
||||||
header = section.header
|
text_frag_name_list.append({'alias': alias_value, 'sdtContent': sdtContent_ele})
|
||||||
header_sdt_list = header.part.element.xpath('//w:sdt')
|
|
||||||
deel_sdt_content(*header_sdt_list)
|
deel_sdt_content(*sdt_element_list)
|
||||||
|
for section in doc_docx.sections:
|
||||||
return text_frag_name_list, doc_docx
|
header = section.header
|
||||||
|
header_sdt_list = header.part.element.xpath('//w:sdt')
|
||||||
# 封装一个根据alias名称修改stdContent的函数 -> 在接口处理函数中取数据放入函数修改文档
|
deel_sdt_content(*header_sdt_list)
|
||||||
def stdContent_modify(modify_str: str | bool, doc_docx: Document, sdtContent: _Element):
|
|
||||||
# 正常处理
|
return text_frag_name_list, doc_docx
|
||||||
for ele in sdtContent:
|
|
||||||
if isinstance(ele, CT_R):
|
# 封装一个根据alias名称修改stdContent的函数 -> 在接口处理函数中取数据放入函数修改文档
|
||||||
run_ele = Run(ele, doc_docx)
|
def stdContent_modify(modify_str: str | bool, doc_docx: Document, sdtContent: _Element):
|
||||||
if isinstance(modify_str, bool):
|
# 正常处理
|
||||||
# 如果是True,则不修改原来
|
for ele in sdtContent:
|
||||||
if modify_str:
|
if isinstance(ele, CT_R):
|
||||||
break
|
run_ele = Run(ele, doc_docx)
|
||||||
else:
|
if isinstance(modify_str, bool):
|
||||||
modify_str = ""
|
# 如果是True,则不修改原来
|
||||||
# 有时候会int类型,转换一下防止报错
|
if modify_str:
|
||||||
if isinstance(modify_str, int):
|
break
|
||||||
modify_str = str(modify_str)
|
else:
|
||||||
run_ele.text = modify_str
|
modify_str = ""
|
||||||
sdtContent.clear()
|
# 有时候会int类型,转换一下防止报错
|
||||||
sdtContent.append(run_ele._element)
|
if isinstance(modify_str, int):
|
||||||
break
|
modify_str = str(modify_str)
|
||||||
|
run_ele.text = modify_str
|
||||||
if isinstance(ele, CT_P):
|
sdtContent.clear()
|
||||||
para_ele = Paragraph(ele, doc_docx)
|
sdtContent.append(run_ele._element)
|
||||||
if isinstance(modify_str, bool):
|
break
|
||||||
if modify_str:
|
|
||||||
break
|
if isinstance(ele, CT_P):
|
||||||
else:
|
para_ele = Paragraph(ele, doc_docx)
|
||||||
modify_str = ""
|
if isinstance(modify_str, bool):
|
||||||
para_ele.clear()
|
if modify_str:
|
||||||
para_ele.text = modify_str
|
break
|
||||||
sdtContent.clear()
|
else:
|
||||||
sdtContent.append(para_ele._element)
|
modify_str = ""
|
||||||
break
|
para_ele.clear()
|
||||||
|
para_ele.text = modify_str
|
||||||
|
sdtContent.clear()
|
||||||
|
sdtContent.append(para_ele._element)
|
||||||
|
break
|
||||||
|
|||||||
BIN
cdtestplant_v1/__pycache__/__init__.cpython-314.pyc
Normal file
BIN
cdtestplant_v1/__pycache__/__init__.cpython-314.pyc
Normal file
Binary file not shown.
BIN
cdtestplant_v1/__pycache__/settings.cpython-314.pyc
Normal file
BIN
cdtestplant_v1/__pycache__/settings.cpython-314.pyc
Normal file
Binary file not shown.
BIN
conf/__pycache__/__init__.cpython-314.pyc
Normal file
BIN
conf/__pycache__/__init__.cpython-314.pyc
Normal file
Binary file not shown.
BIN
conf/__pycache__/env.cpython-314.pyc
Normal file
BIN
conf/__pycache__/env.cpython-314.pyc
Normal file
Binary file not shown.
1422
dbdata.sql
Normal file
1422
dbdata.sql
Normal file
File diff suppressed because one or more lines are too long
@@ -1,2 +0,0 @@
|
|||||||
[WARNING][2025-04-29 14:20:41,997][logger.py:25][回归测试记录模块][单个问题单表格]片段:问题单4未关联用例,请检查
|
|
||||||
[WARNING][2026-01-20 16:34:34,986][logger.py:25][回归测试说明模块][当前文档全部片段]片段:该项目没有创建轮次
|
|
||||||
|
|||||||
2159
logs/root_log
2159
logs/root_log
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
media/R2601/final_seitai/测评大纲.docx
Normal file
BIN
media/R2601/final_seitai/测评大纲.docx
Normal file
Binary file not shown.
BIN
media/R2601/final_seitai/测试记录.docx
Normal file
BIN
media/R2601/final_seitai/测试记录.docx
Normal file
Binary file not shown.
BIN
media/R2601/final_seitai/测试说明.docx
Normal file
BIN
media/R2601/final_seitai/测试说明.docx
Normal file
Binary file not shown.
BIN
media/R2601/final_seitai/问题单.docx
Normal file
BIN
media/R2601/final_seitai/问题单.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/bg/temporary/研总需归追踪_temp.docx
Normal file
BIN
media/R2601/form_template/bg/temporary/研总需归追踪_temp.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/bg/总体结论.docx
Normal file
BIN
media/R2601/form_template/bg/总体结论.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/bg/技术依据文件.docx
Normal file
BIN
media/R2601/form_template/bg/技术依据文件.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/bg/摸底清单.docx
Normal file
BIN
media/R2601/form_template/bg/摸底清单.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/bg/测评完成情况.docx
Normal file
BIN
media/R2601/form_template/bg/测评完成情况.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/bg/测评时间和地点.docx
Normal file
BIN
media/R2601/form_template/bg/测评时间和地点.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/bg/测试内容和结果_第一轮次.docx
Normal file
BIN
media/R2601/form_template/bg/测试内容和结果_第一轮次.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/bg/测试内容和结果_第二轮次.docx
Normal file
BIN
media/R2601/form_template/bg/测试内容和结果_第二轮次.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/bg/测试有效性充分性说明.docx
Normal file
BIN
media/R2601/form_template/bg/测试有效性充分性说明.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/bg/研总需归追踪.docx
Normal file
BIN
media/R2601/form_template/bg/研总需归追踪.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/bg/综述.docx
Normal file
BIN
media/R2601/form_template/bg/综述.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/bg/被测软件基本信息.docx
Normal file
BIN
media/R2601/form_template/bg/被测软件基本信息.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/bg/软件质量评价.docx
Normal file
BIN
media/R2601/form_template/bg/软件质量评价.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/bg/软件问题统计.docx
Normal file
BIN
media/R2601/form_template/bg/软件问题统计.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/bg/问题汇总表.docx
Normal file
BIN
media/R2601/form_template/bg/问题汇总表.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/bg/需求指标符合性情况.docx
Normal file
BIN
media/R2601/form_template/bg/需求指标符合性情况.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/主要功能和性能指标.docx
Normal file
BIN
media/R2601/form_template/dg/主要功能和性能指标.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/主要战技指标.docx
Normal file
BIN
media/R2601/form_template/dg/主要战技指标.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/代码质量度量分析表.docx
Normal file
BIN
media/R2601/form_template/dg/代码质量度量分析表.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/动态测试环境说明.docx
Normal file
BIN
media/R2601/form_template/dg/动态测试环境说明.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/动态测试环境说明_2.docx
Normal file
BIN
media/R2601/form_template/dg/动态测试环境说明_2.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/动态硬件和固件项.docx
Normal file
BIN
media/R2601/form_template/dg/动态硬件和固件项.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/动态硬件和固件项_2.docx
Normal file
BIN
media/R2601/form_template/dg/动态硬件和固件项_2.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/动态软件项.docx
Normal file
BIN
media/R2601/form_template/dg/动态软件项.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/动态软件项_2.docx
Normal file
BIN
media/R2601/form_template/dg/动态软件项_2.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/反向需求规格追踪表.docx
Normal file
BIN
media/R2601/form_template/dg/反向需求规格追踪表.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/技术依据文件.docx
Normal file
BIN
media/R2601/form_template/dg/技术依据文件.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/标准依据文件.docx
Normal file
BIN
media/R2601/form_template/dg/标准依据文件.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/测评对象.docx
Normal file
BIN
media/R2601/form_template/dg/测评对象.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/测评对象_2.docx
Normal file
BIN
media/R2601/form_template/dg/测评对象_2.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/测评数据.docx
Normal file
BIN
media/R2601/form_template/dg/测评数据.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/测评数据_2.docx
Normal file
BIN
media/R2601/form_template/dg/测评数据_2.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/测评时间和地点.docx
Normal file
BIN
media/R2601/form_template/dg/测评时间和地点.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/测评条件保障.docx
Normal file
BIN
media/R2601/form_template/dg/测评条件保障.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/测评组织及任务分工.docx
Normal file
BIN
media/R2601/form_template/dg/测评组织及任务分工.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/测试内容充分性及测试方法有效性分析.docx
Normal file
BIN
media/R2601/form_template/dg/测试内容充分性及测试方法有效性分析.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/测试策略.docx
Normal file
BIN
media/R2601/form_template/dg/测试策略.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/测试级别和测试类型.docx
Normal file
BIN
media/R2601/form_template/dg/测试级别和测试类型.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/测试项及方法.docx
Normal file
BIN
media/R2601/form_template/dg/测试项及方法.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/环境差异性分析.docx
Normal file
BIN
media/R2601/form_template/dg/环境差异性分析.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/环境差异性分析_2.docx
Normal file
BIN
media/R2601/form_template/dg/环境差异性分析_2.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/研制总要求追踪表.docx
Normal file
BIN
media/R2601/form_template/dg/研制总要求追踪表.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/缩略语.docx
Normal file
BIN
media/R2601/form_template/dg/缩略语.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/联系人和方式.docx
Normal file
BIN
media/R2601/form_template/dg/联系人和方式.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/被测软件功能.docx
Normal file
BIN
media/R2601/form_template/dg/被测软件功能.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/被测软件基本信息.docx
Normal file
BIN
media/R2601/form_template/dg/被测软件基本信息.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/被测软件性能.docx
Normal file
BIN
media/R2601/form_template/dg/被测软件性能.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/被测软件接口.docx
Normal file
BIN
media/R2601/form_template/dg/被测软件接口.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/需求规格说明追踪表.docx
Normal file
BIN
media/R2601/form_template/dg/需求规格说明追踪表.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/静态测试环境说明.docx
Normal file
BIN
media/R2601/form_template/dg/静态测试环境说明.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/静态硬件和固件项.docx
Normal file
BIN
media/R2601/form_template/dg/静态硬件和固件项.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/静态硬件和固件项_2.docx
Normal file
BIN
media/R2601/form_template/dg/静态硬件和固件项_2.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/静态软件项.docx
Normal file
BIN
media/R2601/form_template/dg/静态软件项.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/静态软件项_2.docx
Normal file
BIN
media/R2601/form_template/dg/静态软件项_2.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/dg/顶层技术文件.docx
Normal file
BIN
media/R2601/form_template/dg/顶层技术文件.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/hjl/测试用例记录.docx
Normal file
BIN
media/R2601/form_template/hjl/测试用例记录.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/hjl/被测软件基本信息.docx
Normal file
BIN
media/R2601/form_template/hjl/被测软件基本信息.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/hsm/temporary/第三轮用例追踪_temp.docx
Normal file
BIN
media/R2601/form_template/hsm/temporary/第三轮用例追踪_temp.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/hsm/temporary/第二轮用例追踪_temp.docx
Normal file
BIN
media/R2601/form_template/hsm/temporary/第二轮用例追踪_temp.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/hsm/回归测试用例概述.docx
Normal file
BIN
media/R2601/form_template/hsm/回归测试用例概述.docx
Normal file
Binary file not shown.
BIN
media/R2601/form_template/hsm/回归测试需求.docx
Normal file
BIN
media/R2601/form_template/hsm/回归测试需求.docx
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user