from ninja.errors import HttpError from ninja_extra import ControllerBase, api_controller, route from ninja_extra.permissions import IsAuthenticated from ninja_jwt.authentication import JWTAuth from django.db import transaction from django.db.models import Q from docxtpl import DocxTemplate from pathlib import Path from utils.chen_response import ChenResponse # 导入数据库ORM from apps.project.models import Project, Contact, Abbreviation from apps.dict.models import Dict # 导入工具函数 from utils.util import get_str_dict, get_list_dict, get_testType, get_ident, get_str_abbr from utils.chapter_tools.csx_chapter import create_csx_chapter_dict from utils.util import MyHTMLParser_p from django.shortcuts import get_object_or_404 from django.forms.models import model_to_dict from apps.createDocument.extensions.util import create_dg_docx from apps.createDocument.extensions.parse_rich_text import RichParser from apps.createDocument.extensions.documentTime import DocTime from utils.path_utils import project_path # 记录生成日志 from apps.createSeiTaiDocument.extensions.logger import GenerateLogger # 导入mixins-处理文档片段 from apps.createDocument.extensions.mixins import FragementToolsMixin # @api_controller("/generate", tags=['生成大纲文档'], auth=JWTAuth(), permissions=[IsAuthenticated]) @api_controller("/generate", tags=['生成大纲文档']) class GenerateControllerDG(ControllerBase, FragementToolsMixin): logger = GenerateLogger('测评大纲') @route.get("/create/testdemand", url_name="create-testdemand") @transaction.atomic def create_testdemand(self, id: int): # type:ignore """目前生成第一轮测试项""" tplTestDemandGenerate_path = Path.cwd() / "media" / project_path(id) / "form_template" / "dg" / "测试项及方法.docx" doc = DocxTemplate(tplTestDemandGenerate_path) # 获取指定的项目对象 project_qs = get_object_or_404(Project, id=id) # 先查询dict字典,查出总共有多少个testType 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 _ in range(1, test_type_len + 1)] # 查出第一轮所有testdemand project_round_one = project_qs.pField.filter(key=0).first() testDemand_qs = project_round_one.rtField.all() # 遍历第一轮测试项:默认是ID排序 for single_qs in testDemand_qs: type_index = type_number_list.index(int(single_qs.testType)) # 先查询其testDemandContent信息 content_list = [] for (index, content) in enumerate(single_qs.testQField.all()): content_dict = { "index": index + 1, "rindex": str(index + 1).rjust(2, '0'), "subName": content.subName, # 修改遍历content下面的step,content变量是TestDemandContent表 "subStep": [ {'index': index + 1, 'operation': step_obj.operation, 'expect': step_obj.expect} for (index, step_obj) in enumerate(content.testStepField.all()) ], } content_list.append(content_dict) # 查询测试项中testMethod testmethod_str = '' for dict_item_qs in Dict.objects.get(code="testMethod").dictItem.all(): for tm_item in single_qs.testMethod: if tm_item == dict_item_qs.key: testmethod_str += dict_item_qs.title + " " # 富文本解析 # ***Inspect-start:检查设计需求的描述是否为空*** if single_qs.design.description == '': design_info = single_qs.design.ident + '-' + single_qs.design.name self.logger.write_warning_log('测试项', f'设计需求中的描述为空,请检查 -> {design_info}') # ***Inspect-end*** html_parser = RichParser(single_qs.design.description) desc_list = html_parser.get_final_list(doc) # 查询关联design以及普通design doc_list = [{'dut_name': single_qs.dut.name, 'design_chapter': single_qs.design.chapter, 'design_name': single_qs.design.name}] for relate_design in single_qs.otherDesign.all(): ddict = {'dut_name': relate_design.dut.name, 'design_chapter': relate_design.chapter, 'design_name': relate_design.name} doc_list.append(ddict) # 组装单个测试项 testdemand_dict = { "name": single_qs.name, "key": single_qs.key, "ident": get_ident(single_qs), "priority": get_str_dict(single_qs.priority, "priority"), "doc_list": doc_list, "design_description": desc_list, "test_demand_content": content_list, "testMethod": testmethod_str, "adequacy": single_qs.adequacy.replace("\n", "\a"), "testDesciption": single_qs.testDesciption.replace("\n", "\a") # 测试项描述 } list_list[type_index].append(testdemand_dict) # 定义渲染context字典 context = { "project_name": project_qs.name } 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) # 排序1:测试类型排序 output_list = sorted(output_list, key=(lambda x: x["sort"])) context["data"] = output_list doc.render(context) try: doc.save(Path.cwd() / "media" / project_path(id) / "output_dir" / "测试项及方法.docx") return ChenResponse(status=200, code=200, message="文档生成成功!") except PermissionError as e: return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e)) @route.get("/create/yiju", url_name='create-yiju') @transaction.atomic def create_yiju(self, id: int): # 先找出所属项目 project_qs = get_object_or_404(Project, id=id) # 找出该项目的真实依据文件qs yiju_list = get_list_dict('standard', project_qs.standard) context = { 'std_documents': yiju_list } return create_dg_docx('标准依据文件.docx', context, id) @route.get("/create/techyiju", url_name='create-techyiju') @transaction.atomic def create_techyiju(self, id: int): # 找出所属项目 project_qs = get_object_or_404(Project, id=id) # 根据项目找出被测件-只找第一轮次 duties_qs = project_qs.pdField.filter(Q(type='XQ') | Q(type='SJ') | Q(type='XY') | Q(type='YZ')).filter( round__key='0') # 先定义个字典 std_documents = [] for duty in duties_qs: one_duty = {'doc_name': duty.name, 'ident_version': duty.ref + '-' + duty.version, 'publish_date': duty.release_date, 'source': duty.release_union} std_documents.append(one_duty) # 生成二级文档 context = { 'std_documents': std_documents } return create_dg_docx('技术依据文件.docx', context, id) @route.get("/create/contact", url_name='create-contact') @transaction.atomic def create_contact(self, id: int): # 先找出所属项目 project_qs = get_object_or_404(Project, id=id) contact_dict = model_to_dict(project_qs, fields=['entrust_unit', 'entrust_contact', 'entrust_contact_phone', 'dev_unit', 'dev_contact', 'dev_contact_phone', 'test_unit', 'test_contact', 'test_contact_phone']) # 根据entrust_unit、dev_unit、test_unit查找Contact中地址信息 entrust_addr = Contact.objects.get(name=contact_dict['entrust_unit']).addr dev_addr = Contact.objects.get(name=contact_dict['dev_unit']).addr test_addr = Contact.objects.get(name=contact_dict['test_unit']).addr contact_dict['entrust_addr'] = entrust_addr contact_dict['dev_addr'] = dev_addr contact_dict['test_addr'] = test_addr context = { 'datas': contact_dict } return create_dg_docx('联系人和方式.docx', context, id) # 生成测评时间和地点 @route.get('/create/timeaddress', url_name='create-timeaddress') @transaction.atomic def create_timeaddress(self, id: int): doc_timer = DocTime(id) context = doc_timer.dg_address_time() return create_dg_docx('测评时间和地点.docx', context, id) # 生成【主要功能和性能指标】文档片段 @route.get('/create/indicators', url_name='create-indicators') @transaction.atomic def create_indicators(self, id: int): # 获取文档片段模版路径 input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'dg' / '主要功能和性能指标.docx' doc = DocxTemplate(input_path) # 获取项目对象 project_obj: Project = get_object_or_404(Project, id=id) # 定义JINJA上下文 # 获取第一轮次所有功能、性能的设计需求[目前只支持XQ和YZ],因为要获取dut信息进行连表查询 q_ex = Q(dut__type='XQ') | Q(dut__type='YZ') design_qs = project_obj.psField.filter(q_ex, round__key='0').select_related('dut') # 1.功能性能覆盖表 # 定义功能/性能两个列表 func_design_list = [] performance_design_list = [] # 遍历设计需求,然后放入两个列表 for design_obj in design_qs: # 功能指标描述 description = RichParser(design_obj.description).get_final_p_list() # 覆盖情况-【查询测试项-测试子项名称】 demand_qs = design_obj.dtField.all() str_list = [] for demand in demand_qs: # 再查询测试子项 for subDemand in demand.testQField.all(): str_list.append(subDemand.subName) coverage_str = "、".join(str_list) design_context_obj = { 'chapter_info': f"《{design_obj.dut.name}》{design_obj.chapter}-{design_obj.name}", 'indicator': "\a".join(description), 'coverage': f"对{design_obj.name}进行全覆盖测试,包含{coverage_str},验证所描述内容是否满足需求等文档的要求" } demandType_str = get_str_dict(design_obj.demandType, 'demandType') # 判断是否包含“功能”/“性能”字样 if '功能' in demandType_str: func_design_list.append(design_context_obj) elif '性能' in demandType_str: performance_design_list.append(design_context_obj) # 2.摸底指标清单 # 先查第一轮次所有测试项 is_has_modi = False md_demand_list = [] round1_demand_qs = project_obj.ptField.filter(round__key='0') for one_demand in round1_demand_qs: testType_str = get_str_dict(one_demand.testType, 'testType') if '摸底' in testType_str: is_has_modi = True md_demand_list.append({ 'xq_source': "隐含需求", 'desc': one_demand.testDesciption, 'demand_name': one_demand.name, 'demand_ident': "".join(["XQ_MD_", one_demand.ident]) }) # 上下文添加 context = { 'project_name': project_obj.name, 'func_design_list': func_design_list, 'performance_design_list': performance_design_list, 'md_demand_list': md_demand_list, 'is_has_modi': is_has_modi } doc.render(context) try: doc.save(Path.cwd() / "media" / project_path(id) / "output_dir" / '主要功能和性能指标.docx') return ChenResponse(status=200, code=200, message="文档生成成功!") except PermissionError as e: return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e)) # 生成测评对象 - 包括大纲、说明、回归说明和报告 @route.get('/create/softComposition', url_name='create-softComposition') @transaction.atomic def create_softComposition(self, id: int): input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'dg' / '测评对象.docx' doc = DocxTemplate(input_path) replace, frag, rich_text_list = self._generate_frag(id, doc, '测评对象') context = { "replace": replace, # 指定是否由数据库文档片段进行生成 "user_content": frag and rich_text_list } doc.render(context) try: doc.save(Path.cwd() / "media" / project_path(id) / "output_dir" / '测评对象.docx') return ChenResponse(status=200, code=200, message="文档生成成功!") except PermissionError as e: return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e)) # 生成被测软件接口章节 @route.get('/create/interface', url_name='create-interface') def create_interface(self, id: int): project_qs = get_object_or_404(Project, id=id) project_name = project_qs.name interfaceNameList = [] # 查询接口列表 iters = project_qs.psField.filter(demandType=3) iters_length = len(iters) index = 0 for inter in iters: interfaceNameList.append(inter.name) index += 1 if index < iters_length: interfaceNameList.append('、') # 对每个接口进行字典处理 interface_list = [] for interface in iters: interface_dict = { 'name': interface.name, 'ident': interface.ident, 'source': interface.source, 'to': interface.to, 'type': interface.type, 'protocal': interface.protocal, } interface_list.append(interface_dict) context = { 'project_name': project_name, 'iters': interfaceNameList, 'iter_list': interface_list, } return create_dg_docx('被测软件接口.docx', context, id) # 生成顶层技术文件 @route.get('/create/top_file', url_name='create-performance') def create_top_file(self, id: int): project_obj: Project = get_object_or_404(Project, id=id) is_JD = True if project_obj.report_type == '9' else False dut_qs = project_obj.pdField.filter(type='YZ') dut_list = [{ 'index': index + 2 if is_JD else index + 1, 'name': dut_obj.name, 'ident_and_version': '-'.join([dut_obj.ref, dut_obj.version]), 'publish_date': dut_obj.release_date, 'source': dut_obj.release_union, } for index, dut_obj in enumerate(dut_qs)] context = { 'project_name': project_obj.name, 'is_JD': is_JD, 'dut_list': dut_list, } return create_dg_docx('顶层技术文件.docx', context, id) # 静态测试环境说明 @route.get('/create/static_env', url_name='create-static_env') def create_static_env(self, id: int): input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'dg' / '静态测试环境说明.docx' doc = DocxTemplate(input_path) replace, frag, rich_text_list = self._generate_frag(id, doc, '静态测试环境说明') context = { "replace": replace, # 指定是否由数据库文档片段进行生成 "user_content": frag and rich_text_list } doc.render(context) try: doc.save(Path.cwd() / "media" / project_path(id) / "output_dir" / '静态测试环境说明.docx') return ChenResponse(status=200, code=200, message="文档生成成功!") except PermissionError as e: return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e)) # 静态软件项 @route.get('/create/static_soft', url_name='create-static_soft') def create_static_soft(self, id: int): input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'dg' / '静态软件项.docx' doc = DocxTemplate(input_path) replace, frag, rich_text_list = self._generate_frag(id, doc, '静态软件项') context = { "replace": replace, # 指定是否由数据库文档片段进行生成 "user_content": frag and rich_text_list } return create_dg_docx("静态软件项.docx", context, id) # 静态硬件和固件项 @route.get('/create/static_hard', url_name='create-static_hard') def create_static_hard(self, id: int): input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'dg' / '静态硬件和固件项.docx' doc = DocxTemplate(input_path) replace, frag, rich_text_list = self._generate_frag(id, doc, '静态硬件和固件项') context = { "replace": replace, # 指定是否由数据库文档片段进行生成 "user_content": frag and rich_text_list } return create_dg_docx("静态硬件和固件项.docx", context, id) # 动态测评环境说明 @route.get('/create/dynamic_env', url_name='create-dynamic_env') def create_dynamic_env(self, id: int): input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'dg' / '动态测试环境说明.docx' doc = DocxTemplate(input_path) replace, frag, rich_text_list = self._generate_frag(id, doc, '动态测试环境说明') context = { "replace": replace, "user_content": frag and rich_text_list } doc.render(context) try: doc.save(Path.cwd() / "media" / project_path(id) / "output_dir" / '动态测试环境说明.docx') return ChenResponse(status=200, code=200, message="文档生成成功!") except PermissionError as e: return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e)) # 动态软件项 @route.get('/create/dynamic_soft', url_name='create-dynamic_soft') def create_dynamic_soft(self, id: int): input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'dg' / '动态软件项.docx' doc = DocxTemplate(input_path) replace, frag, rich_text_list = self._generate_frag(id, doc, '动态软件项') context = { "replace": replace, "user_content": frag and rich_text_list } return create_dg_docx("动态软件项.docx", context, id) # 动态软件项 @route.get('/create/dynamic_hard', url_name='create-dynamic_hard') def create_dynamic_hard(self, id: int): input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'dg' / '动态硬件和固件项.docx' doc = DocxTemplate(input_path) replace, frag, rich_text_list = self._generate_frag(id, doc, '动态硬件和固件项') context = { "replace": replace, "user_content": frag and rich_text_list } return create_dg_docx("动态硬件和固件项.docx", context, id) # 测试数据 @route.get('/create/test_data', url_name='create-test_data') def create_test_data(self, id: int): input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'dg' / '测评数据.docx' doc = DocxTemplate(input_path) replace, frag, rich_text_list = self._generate_frag(id, doc, '测评数据') context = { "replace": replace, "user_content": frag and rich_text_list } return create_dg_docx("测评数据.docx", context, id) # 环境差异性分析 @route.get('/create/env_diff', url_name='create-env_diff') def create_env_diff(self, id: int): input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'dg' / '环境差异性分析.docx' doc = DocxTemplate(input_path) replace, frag, rich_text_list = self._generate_frag(id, doc, '环境差异性分析') context = { "replace": replace, "user_content": frag and rich_text_list } return create_dg_docx("环境差异性分析.docx", context, id) # 生成被测软件-基本信息 @route.get('/create/baseInformation', url_name='create-baseInformation') def create_information(self, id: int): project_qs = get_object_or_404(Project, id=id) security = get_str_dict(project_qs.security_level, 'security_level') languages = get_list_dict('language', project_qs.language) runtime = get_str_dict(project_qs.runtime, 'runtime') devplant = get_str_dict(project_qs.devplant, 'devplant') language_list = [] for language in languages: language_list.append(language.get('ident_version')) # 版本先找第一轮 project_round = project_qs.pField.filter(key=0).first() first_round_SO = project_round.rdField.filter(type='SO').first() if not first_round_SO: return ChenResponse(code=400, status=400, message='您还未创建轮次,请进入工作区创建') version = first_round_SO.version line_count = int(first_round_SO.total_lines) dev_unit = project_qs.dev_unit # 渲染上下文 context = { 'project_name': project_qs.name, 'security_level': security, 'language': "\a".join(language_list), 'version': version, 'line_count': line_count, 'effective_line': int(first_round_SO.effective_lines), 'recv_date': project_qs.beginTime.strftime("%Y-%m-%d"), 'dev_unit': dev_unit, 'soft_type': project_qs.get_soft_type_display(), 'runtime': runtime, 'devplant': devplant } return create_dg_docx('被测软件基本信息.docx', context, id) # 生成测试级别和测试类型 @route.get('/create/levelAndType', url_name='create-levelAndType') def create_levelAndType(self, id: int): input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'dg' / '测试级别和测试类型.docx' doc = DocxTemplate(input_path) replace, frag, rich_text_list = self._generate_frag(id, doc, '测试级别和测试类型') if replace: context = { "replace": replace, "user_content": frag and rich_text_list } else: # 如果没有片段替换,则利用数据生成信息 project_qs = get_object_or_404(Project, id=id) # 获取所有已录入测试类型 test_types = project_qs.ptField.values("testType").distinct() # 通过测试类型查询字典中的中文 type_name_list = list(map(lambda qs_item: get_str_dict(qs_item['testType'], 'testType'), test_types)) # 定义测试类型一览的顺序,注意word里面也要一样 word_types = ['文档审查', '静态分析', '代码审查', '逻辑测试', '功能测试', '性能测试', '边界测试', '恢复性测试', '安装性测试', '数据处理测试', '余量测试', '强度测试', '接口测试', '人机交互界面测试', '兼容性测试'] type_index = [] for index, test_type in enumerate(word_types): for exist_type in type_name_list: if exist_type == test_type: type_index.append(str(index)) context = { "testTypes": "、".join(type_name_list), "project_name": project_qs.name, "type_index": type_index } return create_dg_docx("测试级别和测试类型.docx", context, id) # 生成测试策略 @route.get('/create/strategy', url_name='create-strategy') def create_strategy(self, id: int): input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'dg' / '测试策略.docx' doc = DocxTemplate(input_path) replace, frag, rich_text_list = self._generate_frag(id, doc, '测试策略') if replace: context = { "replace": replace, "user_content": frag and rich_text_list } else: # 如果没有片段替换,则利用数据生成信息 project_qs = get_object_or_404(Project, id=id) # 根据关键等级检查是否有代码审查 security = project_qs.security_level isDmsc = True if int(security) <= 2 else False # 获取当前测试项的测试类型 test_types = project_qs.ptField.values("testType").distinct() type_name_list = list(map(lambda qs_item: get_str_dict(qs_item['testType'], 'testType'), test_types)) context = { "project_name": project_qs.name, # 查询关键等级-类似“关键”输出 "security_level_str": get_str_abbr(security, 'security_level'), "isDmsc": isDmsc, "test_types": type_name_list } return create_dg_docx("测试策略.docx", context, id) # 生成-测试内容充分性及测试方法有效性 @route.get('/create/adequacy_effectiveness', url_name='create-adequacy_effectiveness') def create_adequacy_effectiveness(self, id: int): project_qs = get_object_or_404(Project, id=id) # 统计测试种类数量-只统计第一轮测试 project_round_one = project_qs.pField.filter(key=0).first() if not project_round_one: return ChenResponse(status=400, code=400, message="未找到首轮测试信息!") # 通过字典获取-测试方法 type_dict = {} # key为测试类型,value为数量 testDemands = project_round_one.rtField.all() for testDemand in testDemands: # 获取每个测试项测试类型 test_type = get_list_dict('testType', [testDemand.testType])[0].get('ident_version') # 如果字典没有该key,则创建并value=1 if not test_type in type_dict: type_dict[test_type] = 1 else: type_dict[test_type] += 1 length = len(type_dict) type_str_list = [] for key, value in type_dict.items(): type_str_list.append(f"{key}{value}项") context = { 'project_name': project_qs.name, 'length': length, 'type_str': "、".join(type_str_list), } return create_dg_docx('测试内容充分性及测试方法有效性分析.docx', context, id) # 生成-测评项目组组成和分工 @route.get('/create/group', url_name='create_group') def create_group(self, id: int): project_qs = get_object_or_404(Project, id=id) context = { 'duty_person': project_qs.duty_person, 'member_str': "、".join(project_qs.member), 'quality_person': project_qs.quality_person, 'vise_person': project_qs.vise_person, 'config_person': project_qs.config_person, 'dev_unit': project_qs.dev_unit, } return create_dg_docx('测评组织及任务分工.docx', context, id) # 生成-测评条件保障 @route.get('/create/guarantee', url_name='create-guarantee') def create_guarantee(self, id: int): project_qs = get_object_or_404(Project, id=id) context = { 'project': project_qs } return create_dg_docx('测评条件保障.docx', context, id) # 生成-缩略语 @route.get('/create/abbreviation', url_name='create-abbreviation') def create_abbreviation(self, id: int): project_qs = get_object_or_404(Project, id=id) abbreviations = [] for abbr in project_qs.abbreviation: abbr_dict = {'title': abbr, 'des': Abbreviation.objects.filter(title=abbr).first().des} abbreviations.append(abbr_dict) context = { 'abbreviations': abbreviations } return create_dg_docx('缩略语.docx', context, id) # 生成研制总要求-测试项追踪关系表 @route.get('/create/yzComparison', url_name='create-yzComparison') def create_yzComparison(self, id: int): """目前追踪需求项的章节号是硬编码,按6.2章节起步,6.2.1~x.x.x依次排序""" # 规定测试项的章节号开头 test_item_prefix = '6.2' # 计算有多少种testType - '文档审查'/'功能测试' -> # 形成一个数组['1','2','3','4','9']后面用来判断测试项的章节号 project_qs = get_object_or_404(Project, id=id) design_list = [] # 先按照design的思路进行追踪 # 判断是否为鉴定测评,有则生成该表 if project_qs.report_type == '9': project_round_one = project_qs.pField.filter(key=0).first() testType_list, last_chapter_items = create_csx_chapter_dict(project_round_one) # 找出第一轮的研总 yz_dut = project_round_one.rdField.filter(type='YZ').first() if yz_dut: # 查询出验证所有design yz_designs = yz_dut.rsField.all() # 遍历所有研总的design for design in yz_designs: design_dict = {'name': design.name, 'chapter': design.chapter, 'test_demand': []} # 获取一个design的所有测试项 test_items = design.dtField.all() for test_item in test_items: reveal_ident = "_".join( ["XQ", get_testType(test_item.testType, "testType"), test_item.ident]) # 查字典方式确认章节号最后一位 test_item_last_chapter = last_chapter_items[test_item.testType].index(test_item.key) + 1 test_chapter = ".".join([test_item_prefix, str(testType_list.index(test_item.testType) + 1), str(test_item_last_chapter)]) test_item_dict = {'name': test_item.name, 'chapter': test_chapter, 'ident': reveal_ident} design_dict['test_demand'].append(test_item_dict) design_list.append(design_dict) context = { 'design_list': design_list } return create_dg_docx('研制总要求追踪表.docx', context, id) # 生成需求规格说明-测试项追踪关系表 @route.get('/create/xqComparison', url_name='create-xqComparison') def create_xqComparison(self, id: int): project_qs = get_object_or_404(Project, id=id) test_item_prefix = '6.2' design_list = [] project_round_one = project_qs.pField.filter(key=0).first() if project_round_one: testType_list, last_chapter_items = create_csx_chapter_dict(project_round_one) # 找出第一轮的被测件为'XQ' xq_dut = project_round_one.rdField.filter(type='XQ').first() # 找出第一轮被测件为'SO',其中的测试项 so_dut = project_round_one.rdField.filter(type='SO').first() if so_dut: so_designs = so_dut.rsField.all() for design in so_designs: design_dict = {'name': "/", 'chapter': "/", 'test_demand': []} # 获取一个design的所有测试项 test_items = [] test_items.extend(design.dtField.all()) test_items.extend(design.odField.all()) for test_item in test_items: # 只对文档审查、静态分析、代码走查、代码审查进行处理 if test_item.testType in ['8', '15', '3', '2']: reveal_ident = "_".join( ["XQ", get_testType(test_item.testType, "testType"), test_item.ident]) # 查字典方式确认章节号最后一位 test_item_last_chapter = last_chapter_items[test_item.testType].index(test_item.key) + 1 test_chapter = ".".join([test_item_prefix, str(testType_list.index(test_item.testType) + 1), str(test_item_last_chapter)]) test_item_dict = {'name': test_item.name, 'chapter': test_chapter, 'ident': reveal_ident} design_dict['test_demand'].append(test_item_dict) design_list.append(design_dict) if xq_dut: xq_designs = xq_dut.rsField.all() for design in xq_designs: design_dict = {'name': design.name, 'chapter': design.chapter, 'test_demand': []} # 获取一个design的所有测试项 test_items = [] test_items.extend(design.dtField.all()) test_items.extend(design.odField.all()) for test_item in test_items: reveal_ident = "_".join( ["XQ", get_testType(test_item.testType, "testType"), test_item.ident]) # 查字典方式确认章节号最后一位 test_item_last_chapter = last_chapter_items[test_item.testType].index(test_item.key) + 1 test_chapter = ".".join([test_item_prefix, str(testType_list.index(test_item.testType) + 1), str(test_item_last_chapter)]) test_item_dict = {'name': test_item.name, 'chapter': test_chapter, 'ident': reveal_ident} design_dict['test_demand'].append(test_item_dict) design_list.append(design_dict) context = { 'design_list': design_list } return create_dg_docx('需求规格说明追踪表.docx', context, id) raise HttpError(400, "生成需求追踪表出错") # 生成测试项-需求规格说明关系表【反向】 @route.get('/create/fanXqComparison', url_name='create-fanXqComparison') def create_fanXqComparison(self, id: int): project_qs = get_object_or_404(Project, id=id) test_item_prefix = '6.2' # 取出第一轮所有测试项的章节处理列表和字典 project_round_one = project_qs.pField.filter(key=0).first() testType_list, last_chapter_items = create_csx_chapter_dict(project_round_one) # 查询第一轮所有测试项 test_items = [] test_items.extend(project_round_one.rtField.all()) # 最后渲染列表 items_list = [] for test_item in test_items: # 第二个处理被测件为"XQ",第二个处理被测件为'SO',并且为测试项testType为['8', '15', '3', '2']的 if test_item.dut.type == 'XQ' or (test_item.dut.type == 'SO' and test_item.testType in ['8', '15', '3', '2']): reveal_ident = "_".join( ["XQ", get_testType(test_item.testType, "testType"), test_item.ident]) # 查字典方式确认章节号最后一位 test_item_last_chapter = last_chapter_items[test_item.testType].index(test_item.key) + 1 test_chapter = ".".join([test_item_prefix, str(testType_list.index(test_item.testType) + 1), str(test_item_last_chapter)]) # 如果是SO里面的 if test_item.testType in ['8', '15', '3', '2'] and test_item.dut.type == 'SO': test_item_dict = {'name': test_item.name, 'chapter': test_chapter, 'ident': reveal_ident, 'design': { 'name': "/", 'chapter': "/" }} else: test_item_dict = {'name': test_item.name, 'chapter': test_chapter, 'ident': reveal_ident, 'design': { 'name': test_item.design.name, 'chapter': test_item.design.chapter }} items_list.append(test_item_dict) context = { 'items_list': items_list, } return create_dg_docx('反向需求规格追踪表.docx', context, id) # 生成代码质量度量分析表 @route.get('/create/codeQuality', url_name='create-codeQuality') def create_codeQuality(self, id: int): project_qs = get_object_or_404(Project, id=id) project_round_one = project_qs.pField.filter(key=0).first() context = {} context.update({'project_name': project_qs.name}) if project_round_one: source_dut: Dut = project_round_one.rdField.filter(type='SO').first() # type:ignore if source_dut: context.update({'version': source_dut.version}) # type:ignore context.update({'size': int(source_dut.total_lines)}) context.update({'total_code_line': int(source_dut.effective_lines)}) context.update({'comment_line': int(source_dut.comment_lines)}) comment_ratio = int(source_dut.comment_lines) / int(source_dut.total_lines) context.update({ 'comment_ratio': f"{comment_ratio * 100:.2f}%", 'comment_ratio_right': '满足' if comment_ratio >= 0.2 else '不满足' }) # 如果已经有metrics if hasattr(source_dut, 'metrics'): context.update({ 'black_line': source_dut.metrics.total_blanks, 'function_count': source_dut.metrics.function_count, 'avg_function_lines': source_dut.metrics.avg_function_lines, 'avg_function_lines_right': '满足' if source_dut.metrics.avg_function_lines <= 200 else '不满足', 'avg_fan_out': source_dut.metrics.avg_fan_out, 'avg_fan_out_right': '满足' if source_dut.metrics.avg_fan_out <= 7 else '不满足', 'avg_cyclomatic': source_dut.metrics.avg_cyclomatic, 'avg_cyclomatic_right': '满足' if source_dut.metrics.avg_cyclomatic <= 10 else '不满足', 'max_cyclomatic': source_dut.metrics.max_cyclomatic, 'max_cyclomatic_right': '满足' if source_dut.metrics.max_cyclomatic <= 80 else '不满足', 'high_cyclomatic_ratio': source_dut.metrics.high_cyclomatic_ratio, 'high_cyclomatic_ratio_right': '满足' if source_dut.metrics.high_cyclomatic_ratio <= 0.2 else '不满足', }) else: return ChenResponse(message='未找到源代码被测件', code=400) return create_dg_docx('代码质量度量分析表.docx', context, id)