Compare commits

...

2 Commits

Author SHA1 Message Date
6f865cc7b5 实现AI生成测试项接口 2026-05-29 16:20:30 +08:00
56aed87497 完成3月试用问题修改 2026-04-24 16:45:18 +08:00
117 changed files with 1150 additions and 831 deletions

View File

@@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="FacetManager">
<facet type="django" name="Django">
<configuration>
<option name="rootFolder" value="$MODULE_DIR$" />
<option name="settingsModule" value="cdtestplant_v1/settings.py" />
<option name="manageScript" value="manage.py" />
<option name="environment" value="&lt;map/&gt;" />
<option name="doNotUseTestRunner" value="false" />
<option name="trackFilePattern" value="" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/.venv" />
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="jdk" jdkName="uv (cdtestplant_v1)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TemplatesService">
<option name="TEMPLATE_CONFIGURATION" value="Django" />
<option name="TEMPLATE_FOLDERS">
<list>
<option value="$MODULE_DIR$/dist/run/templates" />
</list>
</option>
</component>
</module>

2
.idea/modules.xml generated
View File

@@ -2,7 +2,7 @@
<project version="4"> <project version="4">
<component name="ProjectModuleManager"> <component name="ProjectModuleManager">
<modules> <modules>
<module fileurl="file://$PROJECT_DIR$/.idea/cdtestplant_v1.iml" filepath="$PROJECT_DIR$/.idea/cdtestplant_v1.iml" /> <module fileurl="file://$PROJECT_DIR$/.idea/cdtestplant-v1.iml" filepath="$PROJECT_DIR$/.idea/cdtestplant-v1.iml" />
</modules> </modules>
</component> </component>
</project> </project>

View File

@@ -3,12 +3,12 @@ from pathlib import Path
from ninja_extra import api_controller, ControllerBase, route from ninja_extra import api_controller, ControllerBase, route
from django.db import transaction from django.db import transaction
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.db.models import Q, QuerySet from django.db.models import Q
from docxtpl import DocxTemplate from docxtpl import DocxTemplate
from typing import Optional from typing import Optional
from docx import Document from docx import Document
from ninja_extra.permissions import IsAuthenticated from ninja_extra.permissions import IsAuthenticated # type:ignore
from ninja_jwt.authentication import JWTAuth from ninja_jwt.authentication import JWTAuth # type:ignore
# 导入模型 # 导入模型
from apps.project.models import Project, Dut, TestDemand, Problem from apps.project.models import Project, Dut, TestDemand, Problem
# 工具类函数 # 工具类函数
@@ -143,18 +143,18 @@ class GenerateControllerBG(ControllerBase):
# 找到第一轮轮次对象、第二轮轮次对象 # 找到第一轮轮次对象、第二轮轮次对象
round1 = project_obj.pField.filter(key='0').first() round1 = project_obj.pField.filter(key='0').first()
# 第一轮测试项个数 # 第一轮测试项个数
round1_demand_qs = round1.rtField.all() round1_demand_qs = round1 and round1.rtField.all()
# 第一轮用例个数 # 第一轮用例个数
round1_case_qs = round1.rcField.all() round1_case_qs = round1.rcField.all() # type:ignore
# 这部分找出第一轮的所有测试类型,输出字符串,并排序 # 这部分找出第一轮的所有测试类型,输出字符串,并排序
test_type_set: set = set() test_type_set: set = set()
for case in round1_case_qs: for case in round1_case_qs: # type:ignore
demand: TestDemand = case.test demand: TestDemand = case.test
test_type_set.add(demand.testType) test_type_set.add(demand.testType)
round1_testType_list = list( round1_testType_list = list(
map(lambda x: x['ident_version'], get_list_dict('testType', list(test_type_set)))) map(lambda x: x['ident_version'], get_list_dict('testType', list(test_type_set))))
# 这里找出第一轮,源代码被测件,并获取版本 # 这里找出第一轮,源代码被测件,并获取版本
so_dut = round1.rdField.filter(type='SO').first() so_dut = round1.rdField.filter(type='SO').first() # type:ignore
so_dut_verson = "$请添加第一轮的源代码信息$" so_dut_verson = "$请添加第一轮的源代码信息$"
if so_dut: if so_dut:
so_dut_verson = so_dut.version so_dut_verson = so_dut.version
@@ -193,7 +193,7 @@ class GenerateControllerBG(ControllerBase):
'start_time_year': project_obj.beginTime.year, 'start_time_year': project_obj.beginTime.year,
'start_time_month': project_obj.beginTime.month, 'start_time_month': project_obj.beginTime.month,
'round1_case_count': round1_case_qs.count(), 'round1_case_count': round1_case_qs.count(),
'round1_demand_count': round1_demand_qs.count(), 'round1_demand_count': round1_demand_qs.count(), # type:ignore
'round1_testType_str': ''.join(round1_testType_list), 'round1_testType_str': ''.join(round1_testType_list),
'testType_count': len(round1_testType_list), 'testType_count': len(round1_testType_list),
'round1_version': so_dut_verson, 'round1_version': so_dut_verson,
@@ -290,26 +290,26 @@ class GenerateControllerBG(ControllerBase):
problems_doc_r1 = problems_r1.filter(case__test__testType='8') # 第一轮所有文档问题 problems_doc_r1 = problems_r1.filter(case__test__testType='8') # 第一轮所有文档问题
# 3.第一轮代码审查问题统计/版本 # 3.第一轮代码审查问题统计/版本
source_r1_dut = round1.rdField.filter(type='SO').first() # !warning:小变量-第一轮源代码对象 source_r1_dut = round1.rdField.filter(type='SO').first() # type:ignore
program_r1_problems = problems_r1.filter(case__test__testType='2') program_r1_problems = problems_r1.filter(case__test__testType='2')
# 4.第一轮代码走查问题统计/版本 # 4.第一轮代码走查问题统计/版本
zou_r1_problems = problems_r1.filter(case__test__testType='3') zou_r1_problems = problems_r1.filter(case__test__testType='3')
# 找下是否存在代码走查测试项 # 找下是否存在代码走查测试项
r1_demand_qs = round1.rtField.filter(testType='3') r1_demand_qs = round1.rtField.filter(testType='3') # type:ignore
has_zou = True if r1_demand_qs.count() > 0 else False has_zou = True if r1_demand_qs.count() > 0 else False
# 5.第一轮静态分析问题统计 # 5.第一轮静态分析问题统计
static_problems = problems_r1.filter(case__test__testType='15') static_problems = problems_r1.filter(case__test__testType='15')
# 6.第一轮动态测试用例个数(动态测试-非静态分析、文档审查、代码审查、代码走查4个) # 6.第一轮动态测试用例个数(动态测试-非静态分析、文档审查、代码审查、代码走查4个)
case_r1_qs = round1.rcField.filter(~Q(test__testType='2'), ~Q(test__testType='3'), case_r1_qs = round1.rcField.filter(~Q(test__testType='2'), ~Q(test__testType='3'), # type:ignore
~Q(test__testType='8'), ~Q(test__testType='8'),
~Q(test__testType='15'), ~Q(test__testType='15'),
round__key='0') # !warning:中变量-第一轮动态测试用例qs round__key='0') # !warning:中变量-第一轮动态测试用例qs
testType_list, testType_count = create_str_testType_list(case_r1_qs) testType_list, testType_count = create_str_testType_list(case_r1_qs)
## 动态测试(第一轮)各个类型测试用例执行表/各个测试需求表 ## 动态测试(第一轮)各个类型测试用例执行表/各个测试需求表
demand_r1_dynamic_qs = round1.rtField.filter(~Q(testType='2'), ~Q(testType='3'), ~Q(testType='8'), demand_r1_dynamic_qs = round1.rtField.filter(~Q(testType='2'), ~Q(testType='3'), ~Q(testType='8'), # type:ignore
~Q(testType='15')) # !warning:中变量:第一轮动态测试的测试项 ~Q(testType='15')) # !warning:中变量:第一轮动态测试的测试项
summary_r1_demand_info, summry_r1_demandType_info = create_demand_summary(demand_r1_dynamic_qs, summary_r1_demand_info, summry_r1_demandType_info = create_demand_summary(demand_r1_dynamic_qs,
project_ident) project_ident)
@@ -678,14 +678,14 @@ class GenerateControllerBG(ControllerBase):
case__test__testType__in=['2', '3', '8', '15']).distinct() case__test__testType__in=['2', '3', '8', '15']).distinct()
for problem in r1_static_problems: for problem in r1_static_problems:
problem_dict = create_one_problem_dit(problem, problem_prefix, doc) problem_dict = create_one_problem_dit(problem, problem_prefix, doc)
round_dict['static'].append(problem_dict) round_dict['static'].append(problem_dict) # type:ignore
# 找出轮次中动态问题 # 找出轮次中动态问题
r1_dynamic_problems = problems.filter(case__round__key=round_str).exclude( r1_dynamic_problems = problems.filter(case__round__key=round_str).exclude(
case__test__testType__in=['2', '3', '8', '15']).distinct() case__test__testType__in=['2', '3', '8', '15']).distinct()
for problem in r1_dynamic_problems: for problem in r1_dynamic_problems:
problem_dict = create_one_problem_dit(problem, problem_prefix, doc) problem_dict = create_one_problem_dit(problem, problem_prefix, doc)
round_dict['dynamic'].append(problem_dict) round_dict['dynamic'].append(problem_dict) # type:ignore
data_list.append(round_dict) data_list.append(round_dict)
context = { context = {

View File

@@ -31,7 +31,8 @@ from apps.createSeiTaiDocument.extensions.logger import GenerateLogger
# 导入mixins-处理文档片段 # 导入mixins-处理文档片段
from apps.createDocument.extensions.mixins import FragementToolsMixin from apps.createDocument.extensions.mixins import FragementToolsMixin
# 导入工具 # 导入工具
from apps.createDocument.extensions.tools import demand_sort_by_designKey, set_table_border_by_cell_position, set_cell_margins from apps.createDocument.extensions.tools import demand_sort_by_designKey, set_table_border_by_cell_position
from apps.createDocument.extensions.table_creator import create_table_context, RoundType, uniform_static_dynamic_response
# @api_controller("/generate", tags=['生成大纲文档'], auth=JWTAuth(), permissions=[IsAuthenticated]) # @api_controller("/generate", tags=['生成大纲文档'], auth=JWTAuth(), permissions=[IsAuthenticated])
@api_controller("/generate", tags=['生成大纲文档']) @api_controller("/generate", tags=['生成大纲文档'])
@@ -54,7 +55,7 @@ class GenerateControllerDG(ControllerBase, FragementToolsMixin):
# 查出第一轮所有testdemand # 查出第一轮所有testdemand
project_round_one = project_qs.pField.filter(key=0).first() project_round_one = project_qs.pField.filter(key=0).first()
testDemand_qs = project_round_one.rtField.all().select_related('design') testDemand_qs = project_round_one.rtField.all().select_related('design') # type:ignore
# 按照自己key排序这样可以按照design的key排序 # 按照自己key排序这样可以按照design的key排序
sorted_demand_qs = sorted(testDemand_qs, key=demand_sort_by_designKey) sorted_demand_qs = sorted(testDemand_qs, key=demand_sort_by_designKey)
@@ -227,9 +228,9 @@ class GenerateControllerDG(ControllerBase, FragementToolsMixin):
# 2025/12/11将20250417格式改为2025年04月17日 - 封装函数,传入字典和键值,修改对应键值信息 # 2025/12/11将20250417格式改为2025年04月17日 - 封装函数,传入字典和键值,修改对应键值信息
def change_time_to_another(self, context: dict, key_list: list[str]): def change_time_to_another(self, context: dict, key_list: list[str]):
for key in key_list: for key in key_list:
time_val = context.get(key, None) time_val = context.get(key)
if time_val: if time_val:
context[key] = datetime.strptime(time_val, "%Y%m%d").strftime("%Y年%m月%d") context[key] = datetime.strptime(time_val, "%Y%m%d").strftime("%Y年%m月%d") # type:ignore
return context return context
# 生成【主要功能和性能指标】文档片段 # 生成【主要功能和性能指标】文档片段
@@ -360,7 +361,7 @@ class GenerateControllerDG(ControllerBase, FragementToolsMixin):
if qs.exists(): if qs.exists():
data_qs = qs.first().data_schemas data_qs = qs.first().data_schemas
context = cls.create_data_schema_list_context(data_qs, doc) context = cls.create_data_schema_list_context(data_qs, doc)
doc.render(context) doc.render(context or {})
try: try:
doc.save(Path.cwd() / "media" / project_path(id) / "output_dir" / r_filename) doc.save(Path.cwd() / "media" / project_path(id) / "output_dir" / r_filename)
return ChenResponse(status=200, code=200, message="文档生成成功!") return ChenResponse(status=200, code=200, message="文档生成成功!")
@@ -429,9 +430,9 @@ class GenerateControllerDG(ControllerBase, FragementToolsMixin):
image_render = None image_render = None
fontnote = None fontnote = None
if image_obj.exists(): if image_obj.exists():
base64_bytes = base64.b64decode(image_obj.first().content.replace("data:image/png;base64,", "")) base64_bytes = base64.b64decode(image_obj.first().content.replace("data:image/png;base64,", "")) # type:ignore
image_render = InlineImage(doc, io.BytesIO(base64_bytes), width=Mm(120)) image_render = InlineImage(doc, io.BytesIO(base64_bytes), width=Mm(120))
fontnote = image_obj.first().fontnote fontnote = image_obj.first().fontnote # type:ignore
context = { context = {
'project_name': project_name, 'project_name': project_name,
'iters': interfaceNameList, 'iters': interfaceNameList,
@@ -483,101 +484,10 @@ class GenerateControllerDG(ControllerBase, FragementToolsMixin):
except PermissionError as e: except PermissionError as e:
return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e)) return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e))
# 通用生成静态软件项、静态硬件项、动态软件项、动态硬件信息、测评数据的context包含fontnote和table
@classmethod
def create_table_context(cls, table_data: list[list[str]], doc: DocxTemplate):
"""注意:该函数会增加一列序号列,并且支持单元格内回车换行(段落换行)"""
subdoc = doc.new_subdoc()
rows = len(table_data)
cols = len(table_data[0]) + 1
table = subdoc.add_table(rows=rows, cols=cols)
# 单元格处理
for row in range(rows):
for col in range(cols):
cell = table.cell(row, col)
set_cell_margins(cell, left=100, right=100, top=100, bottom=100)
# 获取要显示的文本内容(字符串或按行拆分后的列表)
if col == 0:
# 序号列
lines = ["序号"] if row == 0 else [str(row)]
else:
raw_text = table_data[row][col - 1]
# 按换行符 \n 拆分为多个段落
lines = raw_text.split('\n') if raw_text else ['']
# 清空单元格原有段落add_table 默认有一个段落)
cell.text = ""
# 删除默认段落,稍后统一添加
for para in cell.paragraphs:
p = para._element
p.getparent().remove(p)
# 逐个添加段落
for i, line in enumerate(lines):
if i == 0:
para = cell.add_paragraph(line)
else:
para = cell.add_paragraph(line)
# 设置段落对齐(第一列居中,其他左对齐,可根据需要调整)
if col == 0:
para.alignment = WD_ALIGN_PARAGRAPH.CENTER
else:
para.alignment = WD_ALIGN_PARAGRAPH.LEFT
# 对第一行(表头)设置黑体字体
if row == 0:
for run in para.runs:
run.font.name = '黑体'
run._element.rPr.rFonts.set(qn('w:eastAsia'), '黑体')
run.font.bold = False
# 表头段落居中(覆盖前面的 left
para.alignment = WD_ALIGN_PARAGRAPH.CENTER
# 垂直居中
cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
# 设置序号列宽度
for cell in table.columns[0].cells:
cell.width = Mm(15)
for para in cell.paragraphs:
para.alignment = WD_ALIGN_PARAGRAPH.CENTER
# 表格居中
table.alignment = WD_ALIGN_PARAGRAPH.CENTER
# 设置表格外边框
set_table_border_by_cell_position(table)
return subdoc
# 统一静态软件项、静态硬件项、动态软件项、动态硬件信息的word生成 - 模版模式
@classmethod
def uniform_static_dynamic_response(cls, id: int, filename: str, r_filename: str, model) -> ChenResponse | None:
project_obj = get_object_or_404(Project, id=id)
input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'dg' / filename
doc = DocxTemplate(input_path)
qs = model.objects.filter(project=project_obj)
if qs.exists():
obj = qs.first()
table_data = obj.table
subdoc = cls.create_table_context(table_data, doc)
context = {
'fontnote': obj.fontnote,
'table': subdoc,
}
doc.render(context, autoescape=True)
try:
doc.save(Path.cwd() / "media" / project_path(id) / "output_dir" / r_filename)
return ChenResponse(status=200, code=200, message="文档生成成功!")
except PermissionError as e:
return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e))
return None
# 静态软件项 # 静态软件项
@route.get('/create/static_soft', url_name='create-static_soft') @route.get('/create/static_soft', url_name='create-static_soft')
def create_static_soft(self, id: int): def create_static_soft(self, id: int, current_round: RoundType = "0"):
res = self.uniform_static_dynamic_response(id, '静态软件项_2.docx', '静态软件项.docx', StaticSoftItem) res = uniform_static_dynamic_response(id, '静态软件项_2.docx', '静态软件项.docx', StaticSoftItem, current_round)
if res is not None: if res is not None:
return res return res
@@ -592,8 +502,11 @@ class GenerateControllerDG(ControllerBase, FragementToolsMixin):
# 静态硬件和固件项 # 静态硬件和固件项
@route.get('/create/static_hard', url_name='create-static_hard') @route.get('/create/static_hard', url_name='create-static_hard')
def create_static_hard(self, id: int): def create_static_hard(self, id: int, current_round: RoundType = "0"):
res = self.uniform_static_dynamic_response(id, '静态硬件和固件项_2.docx', '静态硬件和固件项.docx', StaticSoftHardware) res = uniform_static_dynamic_response(id, '静态硬件和固件项_2.docx',
'静态硬件和固件项.docx',
StaticSoftHardware,
current_round)
if res is not None: if res is not None:
return res return res
@@ -632,8 +545,8 @@ class GenerateControllerDG(ControllerBase, FragementToolsMixin):
# 动态软件项 # 动态软件项
@route.get('/create/dynamic_soft', url_name='create-dynamic_soft') @route.get('/create/dynamic_soft', url_name='create-dynamic_soft')
def create_dynamic_soft(self, id: int): def create_dynamic_soft(self, id: int, current_round: RoundType = "0"):
res = self.uniform_static_dynamic_response(id, '动态软件项_2.docx', '动态软件项.docx', DynamicSoftTable) res = uniform_static_dynamic_response(id, '动态软件项_2.docx', '动态软件项.docx', DynamicSoftTable, current_round)
if res is not None: if res is not None:
return res return res
@@ -650,9 +563,9 @@ class GenerateControllerDG(ControllerBase, FragementToolsMixin):
# 动态硬件项 # 动态硬件项
@route.get('/create/dynamic_hard', url_name='create-dynamic_hard') @route.get('/create/dynamic_hard', url_name='create-dynamic_hard')
def create_dynamic_hard(self, id: int): def create_dynamic_hard(self, id: int, current_round: RoundType = "0"):
res = self.uniform_static_dynamic_response(id, '动态硬件和固件项_2.docx', res = uniform_static_dynamic_response(id, '动态硬件和固件项_2.docx',
'动态硬件和固件项.docx', DynamicHardwareTable) '动态硬件和固件项.docx', DynamicHardwareTable, current_round)
if res is not None: if res is not None:
return res return res
@@ -667,9 +580,9 @@ class GenerateControllerDG(ControllerBase, FragementToolsMixin):
# 测试数据 # 测试数据
@route.get('/create/test_data', url_name='create-test_data') @route.get('/create/test_data', url_name='create-test_data')
def create_test_data(self, id: int): def create_test_data(self, id: int, current_round: RoundType = "0"):
res = self.uniform_static_dynamic_response(id, '测评数据_2.docx', res = uniform_static_dynamic_response(id, '测评数据_2.docx',
'测评数据.docx', EvaluateData) '测评数据.docx', EvaluateData, current_round)
if res is not None: if res is not None:
return res return res
# 老内容 # 老内容
@@ -691,12 +604,12 @@ class GenerateControllerDG(ControllerBase, FragementToolsMixin):
qs = EnvAnalysis.objects.filter(project=project_obj) qs = EnvAnalysis.objects.filter(project=project_obj)
if qs.exists(): if qs.exists():
obj = qs.first() obj = qs.first()
table_data = obj.table table_data = obj.table # type:ignore
subdoc = self.create_table_context(table_data, doc) subdoc = create_table_context(table_data, doc)
context = { context = {
"description": obj.description, "description": obj.description, # type:ignore
"table": subdoc, "table": subdoc,
"fontnote": obj.fontnote, "fontnote": obj.fontnote, # type:ignore
} }
doc.render(context, autoescape=True) doc.render(context, autoescape=True)
try: try:
@@ -730,7 +643,7 @@ class GenerateControllerDG(ControllerBase, FragementToolsMixin):
devplant_list = [item['ident_version'] for item in devplants] devplant_list = [item['ident_version'] for item in devplants]
# 版本先找第一轮 # 版本先找第一轮
project_round = project_qs.pField.filter(key=0).first() project_round = project_qs.pField.filter(key=0).first()
first_round_SO = project_round.rdField.filter(type='SO').first() first_round_SO = project_round.rdField.filter(type='SO').first() # type:ignore
if not first_round_SO: if not first_round_SO:
return ChenResponse(code=400, status=400, message='您还未创建轮次,请进入工作区创建') return ChenResponse(code=400, status=400, message='您还未创建轮次,请进入工作区创建')
version = first_round_SO.version version = first_round_SO.version
@@ -808,7 +721,7 @@ class GenerateControllerDG(ControllerBase, FragementToolsMixin):
isDmsc = True if int(security) <= 2 else False isDmsc = True if int(security) <= 2 else False
# 获取第一轮所有测试项QuerySet # 获取第一轮所有测试项QuerySet
project_round_one = project_qs.pField.filter(key=0).first() project_round_one = project_qs.pField.filter(key=0).first()
testDemand_qs = project_round_one.rtField.all() testDemand_qs = project_round_one.rtField.all() # type:ignore
# grouped_data的键是测试类型名称值为测试项名称数组 # grouped_data的键是测试类型名称值为测试项名称数组
grouped_data = {} grouped_data = {}
for item in testDemand_qs: for item in testDemand_qs:
@@ -906,9 +819,9 @@ class GenerateControllerDG(ControllerBase, FragementToolsMixin):
design_list = [] # 先按照design的思路进行追踪 design_list = [] # 先按照design的思路进行追踪
# 查询第一轮次 # 查询第一轮次
project_round_one = project_qs.pField.filter(key=0).first() project_round_one = project_qs.pField.filter(key=0).first()
testType_list, last_chapter_items = create_csx_chapter_dict(project_round_one) testType_list, last_chapter_items = create_csx_chapter_dict(project_round_one) # type:ignore
# 找出第一轮的研总 # 找出第一轮的研总
yz_dut = project_round_one.rdField.filter(type='YZ').first() yz_dut = project_round_one.rdField.filter(type='YZ').first() # type:ignore
if yz_dut: if yz_dut:
# 查询出验证所有design # 查询出验证所有design
yz_designs = yz_dut.rsField.all() yz_designs = yz_dut.rsField.all()
@@ -930,7 +843,7 @@ class GenerateControllerDG(ControllerBase, FragementToolsMixin):
str(test_item_last_chapter)]) str(test_item_last_chapter)])
test_item_dict = {'name': test_item.name, 'chapter': test_chapter, test_item_dict = {'name': test_item.name, 'chapter': test_chapter,
'ident': reveal_ident} 'ident': reveal_ident}
design_dict['test_demand'].append(test_item_dict) design_dict['test_demand'].append(test_item_dict) # type:ignore
design_list.append(design_dict) design_list.append(design_dict)
try: try:
design_list = sorted(design_list, key=chapter_key) design_list = sorted(design_list, key=chapter_key)
@@ -976,7 +889,7 @@ class GenerateControllerDG(ControllerBase, FragementToolsMixin):
str(test_item_last_chapter)]) str(test_item_last_chapter)])
test_item_dict = {'name': test_item.name, 'chapter': test_chapter, test_item_dict = {'name': test_item.name, 'chapter': test_chapter,
'ident': reveal_ident} 'ident': reveal_ident}
design_dict['test_demand'].append(test_item_dict) design_dict['test_demand'].append(test_item_dict) # type:ignore
design_list.append(design_dict) design_list.append(design_dict)
if xq_dut: if xq_dut:
@@ -999,7 +912,7 @@ class GenerateControllerDG(ControllerBase, FragementToolsMixin):
str(test_item_last_chapter)]) str(test_item_last_chapter)])
test_item_dict = {'name': test_item.name, 'chapter': test_chapter, test_item_dict = {'name': test_item.name, 'chapter': test_chapter,
'ident': reveal_ident} 'ident': reveal_ident}
design_dict['test_demand'].append(test_item_dict) design_dict['test_demand'].append(test_item_dict) # type:ignore
design_list.append(design_dict) design_list.append(design_dict)
# 根据design的chapter排序-为防止报错崩溃使用try-但难排查 # 根据design的chapter排序-为防止报错崩溃使用try-但难排查
@@ -1020,10 +933,10 @@ class GenerateControllerDG(ControllerBase, FragementToolsMixin):
test_item_prefix = '6.2' test_item_prefix = '6.2'
# 取出第一轮所有测试项的章节处理列表和字典 # 取出第一轮所有测试项的章节处理列表和字典
project_round_one = project_qs.pField.filter(key=0).first() project_round_one = project_qs.pField.filter(key=0).first()
testType_list, last_chapter_items = create_csx_chapter_dict(project_round_one) testType_list, last_chapter_items = create_csx_chapter_dict(project_round_one) # type:ignore
# 查询第一轮所有测试项 # 查询第一轮所有测试项
test_items = [] test_items = []
test_items.extend(project_round_one.rtField.all()) test_items.extend(project_round_one.rtField.all()) # type:ignore
# 最后渲染列表 # 最后渲染列表
items_list = [] items_list = []
for test_item in test_items: for test_item in test_items:

View File

@@ -24,6 +24,9 @@ from apps.createDocument.extensions.content_result_tool import create_influence_
from apps.createSeiTaiDocument.extensions.logger import GenerateLogger from apps.createSeiTaiDocument.extensions.logger import GenerateLogger
# 导入排序 # 导入排序
from apps.createDocument.extensions.tools import demand_sort_by_designKey from apps.createDocument.extensions.tools import demand_sort_by_designKey
# 导入静态软件项、静态硬件项、动态软件项、动态硬件项、测评数据辅助函数和模型
from apps.createDocument.extensions.table_creator import uniform_static_dynamic_response, RoundType
from apps.project.models import StaticSoftItem, StaticSoftHardware, DynamicSoftTable, DynamicHardwareTable, EvaluateData
chinese_round_name: list = ['', '', '', '', '', '', '', '', '', ''] chinese_round_name: list = ['', '', '', '', '', '', '', '', '', '']
@@ -42,6 +45,38 @@ class GenerateControllerHSM(ControllerBase):
except PermissionError: except PermissionError:
return ChenResponse(code=400, status=400, message='另一个程序正在占用文件,请关闭后重试') return ChenResponse(code=400, status=400, message='另一个程序正在占用文件,请关闭后重试')
# ~~~新增5个接口回归测试说明的~~~
# 静态软件项
@route.get('/create/static_soft', url_name='create-static_soft-hsm')
def create_hsm_static_soft(self, id: int, current_round: RoundType = "0"):
return uniform_static_dynamic_response(id, '静态软件项_2.docx', '静态软件项.docx', StaticSoftItem, current_round, isHsm=True)
# 静态硬件和固件项
@route.get('/create/static_hard', url_name='create-static_hard-hsm')
def create_hsm_static_hard(self, id: int, current_round: RoundType = "0"):
return uniform_static_dynamic_response(id, '静态硬件和固件项_2.docx',
'静态硬件和固件项.docx',
StaticSoftHardware,
current_round)
# 动态软件项
@route.get('/create/dynamic_soft', url_name='create-dynamic_soft-hsm')
def create_hsm_dynamic_soft(self, id: int, current_round: RoundType = "0"):
return uniform_static_dynamic_response(id, '动态软件项_2.docx', '动态软件项.docx', DynamicSoftTable, current_round, isHsm=True)
# 动态硬件项
@route.get('/create/dynamic_hard', url_name='create-dynamic_hard-hsm')
def create_hsm_dynamic_hard(self, id: int, current_round: RoundType = "0"):
return uniform_static_dynamic_response(id, '动态硬件和固件项_2.docx',
'动态硬件和固件项.docx', DynamicHardwareTable, current_round, isHsm=True)
# 测试数据
@route.get('/create/test_data', url_name='create-test_data-hsm')
def create_hsm_test_data(self, id: int, current_round: RoundType = "0"):
return uniform_static_dynamic_response(id, '测评数据_2.docx',
'测评数据.docx', EvaluateData, current_round, isHsm=True)
# ~~~5个接口end~~~
@route.get("/create/basicInformation", url_name="create-basicInformation") @route.get("/create/basicInformation", url_name="create-basicInformation")
@transaction.atomic @transaction.atomic
def create_basicInformation(self, id: int): def create_basicInformation(self, id: int):

View File

@@ -1,207 +1,209 @@
# 本模块主要以项目开始时间、结束时间、轮次开始时间、结束时间计算文档中的各个时间 # 本模块主要以项目开始时间、结束时间、轮次开始时间、结束时间计算文档中的各个时间
from datetime import timedelta, date from datetime import timedelta, date
from apps.project.models import Project from apps.project.models import Project
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from ninja.errors import HttpError # 从代码抛出该异常被ninja截取变为response from ninja.errors import HttpError # 从代码抛出该异常被ninja截取变为response
from utils.codes import PROJECT_ENDTIME_ERROR_CODE
def format_remove_heng(dateT: date) -> str:
"""该函数将date对象的横杠-去掉输出str""" def format_remove_heng(dateT: date) -> str:
return str(dateT).replace('-', '') """该函数将date对象的横杠-去掉输出str"""
return str(dateT).replace('-', '')
def times_by_cover_time(cover_time: date) -> dict:
"""该函数为每个产品文档根据封面时间,渲染签署页时间、文档变更记录时间""" def times_by_cover_time(cover_time: date) -> dict:
return { """该函数为每个产品文档根据封面时间,渲染签署页时间、文档变更记录时间"""
'preparation_time_no_format': cover_time - timedelta(days=2), return {
'preparation_time': format_remove_heng(cover_time - timedelta(days=2)), # 拟制时间:为编制结束时间-2天 'preparation_time_no_format': cover_time - timedelta(days=2),
'inspect_time': format_remove_heng(cover_time - timedelta(days=1)), # 校对时间:为编制时间+1 'preparation_time': format_remove_heng(cover_time - timedelta(days=2)), # 拟制时间:为编制结束时间-2
'auditing_time': format_remove_heng(cover_time), 'inspect_time': format_remove_heng(cover_time - timedelta(days=1)), # 校对时间:为编制时间+1天
'ratify_time': format_remove_heng(cover_time), 'auditing_time': format_remove_heng(cover_time),
'create_doc_time': format_remove_heng(cover_time - timedelta(days=2)), 'ratify_time': format_remove_heng(cover_time),
'doc_v1_time': format_remove_heng(cover_time) 'create_doc_time': format_remove_heng(cover_time - timedelta(days=2)),
} 'doc_v1_time': format_remove_heng(cover_time)
}
class DocTime:
def __init__(self, project_id: int): class DocTime:
self.project = get_object_or_404(Project, id=project_id) def __init__(self, project_id: int):
# 用户录入时间-项目 self.project = get_object_or_404(Project, id=project_id)
self.p_start = self.project.beginTime # 被测件接收时间/ # 用户录入时间-项目
self.p_end = self.project.endTime # 大纲测评时间周期结束时间/ self.p_start = self.project.beginTime # 被测件接收时间/
# 遍历轮次时间-多个 self.p_end = self.project.endTime # 大纲测评时间周期结束时间/
self.round_count = self.project.pField.count() # 遍历轮次时间-多个
self.round_time = [] # 轮次按顺序排序 self.round_count = self.project.pField.count()
for round in self.project.pField.all(): self.round_time = [] # 轮次按顺序排序
self.round_time.append({ for round in self.project.pField.all():
'start': round.beginTime, self.round_time.append({
'end': round.endTime, 'start': round.beginTime,
'location': round.location 'end': round.endTime,
}) 'location': round.location
# ~~~~由上面时间二次计算得出时间~~~~ -> TODO:可由用户设置间隔时间!!!! })
self.dg_bz_start = self.p_start + timedelta(days=1) # 大纲编制开始时间,项目开始时间+1天 # ~~~~由上面时间二次计算得出时间~~~~ -> TODO:可由用户设置间隔时间!!!!
self.dg_bz_end = self.dg_bz_start + timedelta(days=6) # 大纲编制结束时间,大纲编制开始+6 self.dg_bz_start = self.p_start + timedelta(days=1) # 大纲编制开始时间,项目开始时间+1
self.test_sj_start = self.dg_bz_end + timedelta(days=1) # 测评设计与实现时间,大纲编制结束+1 self.dg_bz_end = self.dg_bz_start + timedelta(days=6) # 大纲编制结束时间,大纲编制开始+6
self.test_sj_end = self.test_sj_start + timedelta(days=5) # 测评设计与实现结束,在开始+5 self.test_sj_start = self.dg_bz_end + timedelta(days=1) # 测评设计与实现时间,在大纲编制结束+1
# ~~~~储存每个文档的cover_time~~~~ self.test_sj_end = self.test_sj_start + timedelta(days=5) # 测评设计与实现结束,在开始+5天
self.dg_cover_time = self.dg_bz_end # ~~~~储存每个文档的cover_time~~~~
self.sm_cover_time = self.test_sj_end self.dg_cover_time = self.dg_bz_end
self.jl_cover_time = self.round_time[0]['end'] self.sm_cover_time = self.test_sj_end
self.wtd_cover_time = self.round_time[-1]['end'] self.jl_cover_time = self.round_time[0]['end']
self.wtd_cover_time = self.round_time[-1]['end']
# 该函数生成大纲文档片段-测评时间和地点的时间和地点信息
def dg_address_time(self): # 该函数生成大纲文档片段-测评时间和地点的时间和地点信息
"""直接返回context去渲染""" def dg_address_time(self):
# 需要判断round_time是否有值 """直接返回context去渲染"""
if len(self.round_time) <= 0: # 需要判断round_time是否有值
raise HttpError(status_code=400, message='您还未创建轮次时间,请填写后生成') if len(self.round_time) <= 0:
return { raise HttpError(status_code=400, message='您还未创建轮次时间,请填写后生成')
'start_year': self.p_start.year, return {
'start_month': self.p_start.month, 'start_year': self.p_start.year,
'end_year': self.p_end.year, 'start_month': self.p_start.month,
'end_month': self.p_end.month, 'end_year': self.p_end.year,
'beginTime_strf': format_remove_heng(self.p_start), 'end_month': self.p_end.month,
'dgCompileStart': format_remove_heng(self.dg_bz_start), 'beginTime_strf': format_remove_heng(self.p_start),
'dgCompileEnd': format_remove_heng(self.dg_bz_end), 'dgCompileStart': format_remove_heng(self.dg_bz_start),
'designStart': format_remove_heng(self.test_sj_start), 'dgCompileEnd': format_remove_heng(self.dg_bz_end),
'designEnd': format_remove_heng(self.test_sj_end), 'designStart': format_remove_heng(self.test_sj_start),
'location': self.round_time[0]['location'] 'designEnd': format_remove_heng(self.test_sj_end),
} 'location': self.round_time[0]['location']
}
# 该函数生成报告文档片段-测评时间和地点【注意使用了dg_address_time -> 所以后续有修改注意前导】
def bg_address_time(self): # 该函数生成报告文档片段-测评时间和地点【注意使用了dg_address_time -> 所以后续有修改注意前导】
if len(self.round_time) <= 0: def bg_address_time(self):
raise HttpError(status_code=400, message='您还未创建轮次时间,请填写后生成') if len(self.round_time) <= 0:
# 先使用大纲的时间行数作为前三行 raise HttpError(status_code=400, message='您还未创建轮次时间,请填写后生成')
cname = ['首轮测试', '第二轮测试', '第三轮测试', '第四轮测试', '第五轮测试', '第六轮测试', '第七轮测试', # 先使用大纲的时间行数作为前三行
'轮测试', '轮测试', '轮测试'] cname = ['首轮测试', '第二轮测试', '第三轮测试', '第四轮测试', '轮测试', '轮测试', '轮测试',
dg_address_time = self.dg_address_time() '第八轮测试', '第九轮测试', '第十轮测试']
round_time_list = [] dg_address_time = self.dg_address_time()
index = 0 round_time_list = []
for round_dict in self.round_time: index = 0
one_dict = { for round_dict in self.round_time:
'name': cname[index], one_dict = {
'start': format_remove_heng(round_dict['start']), 'name': cname[index],
'end': format_remove_heng(round_dict['end']), 'start': format_remove_heng(round_dict['start']),
'location': round_dict['location'] 'end': format_remove_heng(round_dict['end']),
} 'location': round_dict['location']
index += 1 }
round_time_list.append(one_dict) index += 1
return { round_time_list.append(one_dict)
'begin_year': dg_address_time['start_year'], return {
'begin_month': dg_address_time['start_month'], 'begin_year': dg_address_time['start_year'],
'end_year': dg_address_time['end_year'], 'begin_month': dg_address_time['start_month'],
'end_month': dg_address_time['end_month'], 'end_year': dg_address_time['end_year'],
'begin_time': dg_address_time['beginTime_strf'], 'end_month': dg_address_time['end_month'],
'dg_weave_start_date': dg_address_time['dgCompileStart'], 'begin_time': dg_address_time['beginTime_strf'],
'dg_weave_end_date': dg_address_time['dgCompileEnd'], 'dg_weave_start_date': dg_address_time['dgCompileStart'],
'sj_weave_start_date': dg_address_time['designStart'], 'dg_weave_end_date': dg_address_time['dgCompileEnd'],
'sj_weave_end_date': dg_address_time['designEnd'], 'sj_weave_start_date': dg_address_time['designStart'],
'round_time_list': round_time_list, 'sj_weave_end_date': dg_address_time['designEnd'],
# 测评总结 -> 依据项目结束时间-7 ~ 项目结束时间 'round_time_list': round_time_list,
'summary_start_date': format_remove_heng(self.p_end - timedelta(days=7)), # 测评总结 -> 依据项目结束时间-7 ~ 项目结束时间
'summary_end_date': format_remove_heng(self.p_end), 'summary_start_date': format_remove_heng(self.p_end - timedelta(days=7)),
} 'summary_end_date': format_remove_heng(self.p_end),
}
# 生成报告中测评完成情况 -> 必须依据其他内容生成时间【注意使用了bg_address_time -> 所以后续有修改注意前导】
def bg_completion_situation(self): # 生成报告中测评完成情况 -> 必须依据其他内容生成时间【注意使用了bg_address_time -> 所以后续有修改注意前导】
bg_timer_dict = self.bg_address_time() def bg_completion_situation(self):
xq_fx_time_end = self.dg_bz_start + timedelta(days=2) bg_timer_dict = self.bg_address_time()
ch_time_start = xq_fx_time_end + timedelta(days=1) xq_fx_time_end = self.dg_bz_start + timedelta(days=2)
ch_time_end = self.dg_bz_end ch_time_start = xq_fx_time_end + timedelta(days=1)
if len(self.round_time) < 1: ch_time_end = self.dg_bz_end
raise HttpError(status_code=400, message='您还未创建第一轮测试的时间,请填写后再生成') if len(self.round_time) < 1:
return { raise HttpError(status_code=400, message='您还未创建第一轮测试的时间,请填写后再生成')
'start_time_year': bg_timer_dict['begin_year'], return {
'start_time_month': bg_timer_dict['begin_month'], 'start_time_year': bg_timer_dict['begin_year'],
'xq_fx_time_start_year': self.dg_bz_start.year, 'start_time_month': bg_timer_dict['begin_month'],
'xq_fx_time_start_month': self.dg_bz_start.month, 'xq_fx_time_start_year': self.dg_bz_start.year,
'xq_fx_time_start_day': self.dg_bz_start.day, 'xq_fx_time_start_month': self.dg_bz_start.month,
'xq_fx_time_end_year': xq_fx_time_end.year, # 需求分析结束时间是大纲编制开始+2 'xq_fx_time_start_day': self.dg_bz_start.day,
'xq_fx_time_end_month': xq_fx_time_end.month, 'xq_fx_time_end_year': xq_fx_time_end.year, # 需求分析结束时间是大纲编制开始+2
'xq_fx_time_end_day': xq_fx_time_end.day, 'xq_fx_time_end_month': xq_fx_time_end.month,
'ch_start_year': ch_time_start.year, 'xq_fx_time_end_day': xq_fx_time_end.day,
'ch_start_month': ch_time_start.month, 'ch_start_year': ch_time_start.year,
'ch_start_day': ch_time_start.day, 'ch_start_month': ch_time_start.month,
'ch_end_year': ch_time_end.year, 'ch_start_day': ch_time_start.day,
'ch_end_month': ch_time_end.month, 'ch_end_year': ch_time_end.year,
'ch_end_day': ch_time_end.day, 'ch_end_month': ch_time_end.month,
'sj_start_year': self.test_sj_start.year, 'ch_end_day': ch_time_end.day,
'sj_start_month': self.test_sj_start.month, 'sj_start_year': self.test_sj_start.year,
'sj_start_day': self.test_sj_start.day, 'sj_start_month': self.test_sj_start.month,
'sj_end_year': self.test_sj_end.year, 'sj_start_day': self.test_sj_start.day,
'sj_end_month': self.test_sj_end.month, 'sj_end_year': self.test_sj_end.year,
'sj_end_day': self.test_sj_end.day, 'sj_end_month': self.test_sj_end.month,
'end_time_year': self.p_end.year, 'sj_end_day': self.test_sj_end.day,
'end_time_month': self.p_end.month, 'end_time_year': self.p_end.year,
'exec_start_time_year': self.round_time[0]['start'].year, 'end_time_month': self.p_end.month,
'exec_start_time_month': self.round_time[0]['start'].month, 'exec_start_time_year': self.round_time[0]['start'].year,
'exec_start_time_day': self.round_time[0]['start'].day, 'exec_start_time_month': self.round_time[0]['start'].month,
'exec_end_time_year': self.round_time[0]['end'].year, 'exec_start_time_day': self.round_time[0]['start'].day,
'exec_end_time_month': self.round_time[0]['end'].month, 'exec_end_time_year': self.round_time[0]['end'].year,
'exec_end_time_day': self.round_time[0]['end'].day, 'exec_end_time_month': self.round_time[0]['end'].month,
} 'exec_end_time_day': self.round_time[0]['end'].day,
}
# 该函数生成最终大纲的时间
def dg_final_time(self): # 该函数生成最终大纲的时间
cover_time = self.dg_bz_end def dg_final_time(self):
context = times_by_cover_time(cover_time) cover_time = self.dg_bz_end
context.update(cover_time=cover_time.strftime("%Y年%m月%d")) context = times_by_cover_time(cover_time)
# 新增给大纲模版10.2章节context context.update(cover_time=cover_time.strftime("%Y年%m月%d"))
context.update(basic_line1=cover_time.strftime("%Y年%m月"), basic_line2=self.p_end.strftime("%Y年%m月")) # 新增给大纲模版10.2章节context
# 新增给大纲模版10.3.2章节的context context.update(basic_line1=cover_time.strftime("%Y年%m月"), basic_line2=self.p_end.strftime("%Y年%m月"))
sm_context = self.sm_final_time() # 新增给大纲模版10.3.2章节的context
context.update(sm_end_time=sm_context['preparation_time_no_format'].strftime("%Y年%m月")) sm_context = self.sm_final_time()
return context context.update(sm_end_time=sm_context['preparation_time_no_format'].strftime("%Y年%m月"))
return context
# 该函数生成说明文档的时间 -> 依据项目时间而非用户第一轮填写时间!
def sm_final_time(self): # 该函数生成说明文档的时间 -> 依据项目时间而非用户第一轮填写时间!
cover_time = self.test_sj_end # 封面时间:为大纲时间中“测评设计与实现”结束时间 def sm_final_time(self):
context = times_by_cover_time(cover_time) cover_time = self.test_sj_end # 封面时间:为大纲时间中“测评设计与实现”结束时间
context.update(cover_time=cover_time.strftime("%Y年%m月%d")) context = times_by_cover_time(cover_time)
return context context.update(cover_time=cover_time.strftime("%Y年%m月%d"))
return context
# 该函数生成记录文档的时间 -> 依据第一轮测试用户填写的事件
def jl_final_time(self): # 该函数生成记录文档的时间 -> 依据第一轮测试用户填写的事件
if len(self.round_time) < 1: def jl_final_time(self):
raise HttpError(status_code=400, message='您还未创建第一轮测试的时间,请填写后再生成') if len(self.round_time) < 1:
cover_time = self.round_time[0]['end'] # 封面时间为用户填写第一轮结束时间 raise HttpError(status_code=400, message='您还未创建第一轮测试的时间,请填写后再生成')
context = times_by_cover_time(cover_time) cover_time = self.round_time[0]['end'] # 封面时间为用户填写第一轮结束时间
context.update(cover_time=cover_time.strftime("%Y年%m月%d")) context = times_by_cover_time(cover_time)
return context context.update(cover_time=cover_time.strftime("%Y年%m月%d"))
return context
# 问题单的时间 -> 依据最后一轮次的结束时间+1天
def wtd_final_time(self): # 问题单的时间 -> 依据最后一轮次的结束时间+1天
if len(self.round_time) < 1: def wtd_final_time(self):
raise HttpError(status_code=400, message='您还未创建第一轮测试的时间,请填写后再生成') if len(self.round_time) < 1:
cover_time = self.round_time[-1]['end'] raise HttpError(status_code=400, message='您还未创建第一轮测试的时间,请填写后再生成')
context = times_by_cover_time(cover_time) cover_time = self.round_time[-1]['end']
context.update(cover_time=cover_time.strftime("%Y年%m月%d")) context = times_by_cover_time(cover_time)
return context context.update(cover_time=cover_time.strftime("%Y年%m月%d"))
return context
# 回归测试说明时间 -> 根据第二轮、第三轮...的开始时间
def hsm_final_time(self, round_key: str): # 回归测试说明时间 -> 根据第二轮、第三轮...的开始时间
if len(self.round_time) < int(round_key) + 1: def hsm_final_time(self, round_key: str):
raise HttpError(status_code=400, message='您填写的回归轮次时间不正确,请填写后再生成') if len(self.round_time) < int(round_key) + 1:
cover_time = self.round_time[int(round_key)]['start'] raise HttpError(status_code=400, message='您填写的回归轮次时间不正确,请填写后再生成')
context = times_by_cover_time(cover_time) cover_time = self.round_time[int(round_key)]['start']
context.update(cover_time=cover_time.strftime("%Y年%m月%d")) context = times_by_cover_time(cover_time)
return context context.update(cover_time=cover_time.strftime("%Y年%m月%d"))
return context
# 回归测试记录时间 -> 根据第二轮、第三轮...的结束时间
def hjl_final_time(self, round_key: str) -> dict: # 回归测试记录时间 -> 根据第二轮、第三轮...的结束时间
if len(self.round_time) < int(round_key) + 1: def hjl_final_time(self, round_key: str) -> dict:
raise HttpError(status_code=400, message='您填写的回归轮次时间不正确,请填写后再生成') if len(self.round_time) < int(round_key) + 1:
cover_time = self.round_time[int(round_key)]['end'] raise HttpError(status_code=400, message='您填写的回归轮次时间不正确,请填写后再生成')
context = times_by_cover_time(cover_time) cover_time = self.round_time[int(round_key)]['end']
context.update(cover_time=cover_time.strftime("%Y年%m月%d")) context = times_by_cover_time(cover_time)
return context context.update(cover_time=cover_time.strftime("%Y年%m月%d"))
return context
# 生成报告非过程时间 -> 根据项目结束时间来定
def bg_final_time(self) -> dict: # 生成报告非过程时间 -> 根据项目结束时间来定
if len(self.round_time) <= 0: def bg_final_time(self) -> dict:
raise HttpError(status_code=400, message='您还未创建轮次时间,请填写后生成') if len(self.round_time) <= 0:
cover_time = self.p_end raise HttpError(status_code=400, message='您还未创建轮次时间,请填写后生成')
# 这里做判断,如果项目结束时间/最后一轮结束时间 cover_time = self.p_end
if cover_time < self.round_time[-1]['end']: # 这里做判断,如果项目结束时间/最后一轮结束时间
raise HttpError(500, message='项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间') if cover_time < self.round_time[-1]['end']:
context = times_by_cover_time(cover_time) # 注意系统对HttpError异常重新处理所以该处status_code看api.py文件
context.update(cover_time=cover_time.strftime("%Y年%m月%d")) raise HttpError(PROJECT_ENDTIME_ERROR_CODE, message='项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
return context context = times_by_cover_time(cover_time)
context.update(cover_time=cover_time.strftime("%Y年%m月%d"))
return context

View File

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

View File

@@ -1,128 +1,85 @@
from datetime import date from datetime import date
from ninja_extra import api_controller, ControllerBase, route from ninja_extra import api_controller, ControllerBase, route
import json import json
from typing import Literal
from apps.project.models import Project from apps.project.models import Project
from django.db import transaction from django.db import transaction
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from utils.chen_response import ChenResponse import requests
from django.db.models import Q from utils.chen_response import ChenResponse
from ninja import Schema from django.db.models import Q
from ninja import Schema
Users = get_user_model()
Users = get_user_model()
class AIPostSchema(Schema):
question: str class AIPostSchema(Schema):
stream: bool question: str
project_type: Literal["cpu", "fpga"]
# AI测试接口
@api_controller("/local_doc_qa", tags=['AI测试接口']) # AI测试接口
class AITestController(ControllerBase): @api_controller("/local_doc_qa", tags=['AI测试接口'])
"""AI测试接口自定义延迟""" class AITestController(ControllerBase):
"""AI测试接口自定义延迟"""
@route.post("/testing_item")
def ai_return(self, item: AIPostSchema): @route.post("/testing_item")
import time def ai_return(self, item: AIPostSchema):
time.sleep(2) target_url = "http://192.168.0.63:8777/api/local_doc_qa/testing_item"
res = [ payload = {
{ "question": item.question,
"demandDescription": "验证外部32MHz品振时钟和内部10KHZ时钟能否正确布线至FPGA内部相应的全局时钟网络并通过指定缓冲器降低延迟。", "model_name": "qwen3.5", # 可能会变
"title": "时钟布线与缓冲功能测试", "project_type": item.project_type,
"children": [ "streaming": False,
{ "user_focus_points": "",
"name": "外部32MHz时钟布线到HCLKBUF级冲测试", }
"subDescription": "验证外部32MH布线的测试子项描述", try:
"subStep": [ resp = requests.post(target_url, json=payload, timeout=120, headers={"Content-Type": "application/json"})
{ resp.raise_for_status()
"operation": "配置FPGA逻辑将外部32MHz晶振输入连接到HCLKBUF缓冲器。", return resp.json()
"expect": "时钟信号成功接入HCLKBUF缓冲器无错误提示。" except requests.RequestException:
}, { # 调用失败,返回 502
"operation": "使用示波器或时序分析工具检测HCLKBUF输出端的时钟波形。", return ChenResponse(data={}, message="调用大模型接口失败,请联系管理员", code=502, status=502)
"expect": "输出端应稳定输出32MHz时钟信号频率准确目波形无明显失真。"
}, { # 这是其他common内容接口
"operation": "监测从HCLKBUF到各寄存器的时钟路径延迟。", @api_controller("/system", tags=['通用接口'])
"expect": "各路径延迟保持一致目为最小值,满足分布式延迟最低的变求。" class CommonController(ControllerBase):
} """通用接口类:工作台内的信息"""
]
}, { @route.get("/getNoticeList")
"name": "内部10KHz时钟布线到CLKINT缓冲测试", def get_notice(self, pageSize, orderBy, orderType):
"subDescription": "验证内部10KHz时钟布线到CLKINT缓冲的测试子项描述", item_list = []
"subStep": [ item1 = {"title": "测试管理平台V0.0.2测试发布", "created_at": "2023-09-23",
{ "content": "测试管理平台V0.0.2发布,正在进行内部测试.."}
"operation": "在FPGA中启用内部10KHz时钟源并将其连接至CLKINT缓冲器。", item_list.append(item1)
"expect": "内部时钟信号成功接入CLKINT缓冲器系统无报错。" item2 = {"title": "测试管理平台更新公共", "created_at": "2024-06-17",
}, { "content": "<p>1.修改大纲和报告模版<p><p>2.修复多个bug<p>"}
"operation": "测量CLKINT输出端的时钟频率。", item_list.append(item2)
"expect": "输出端应稳定输出10KHz时钟信号频率精度符合设计要求。" return item_list
}, {
"operation": "检查CLKINT是否将时钟广播到全局时钟网器", @route.get('/workplace/statistics')
"expect": "时钟能被正常分发至内部各个需要该时钟的模块。" @transaction.atomic
} def get_statistics(self):
] # 查询用户数量,进行的项目,项目总数,已完成项目数
}, { user_count = Users.objects.count()
"name": "异常情况下的时钟处理测试", project_qs = Project.objects.all()
"subDescription": "验证异常情况下的时钟处理测试的测试子项描述", project_count = project_qs.count()
"subStep": [ project_done_count = project_qs.filter(step='3').count()
{ project_processing_count = project_qs.filter(Q(step='1') | Q(step='2')).count()
"operation": "断开外部32MHz晶振输入后尝试进行HCLKBUF配置。", return ChenResponse(data={'pcount': project_count, 'ucount': user_count,
"expect": "系统应报告时钟缺失错误,无法完成正常的时钟分配。" 'pdcount': project_done_count, 'ppcount': project_processing_count})
}, {
"operation": "人为制造内部10KHz时钟不稳定(如干扰)后再送入CLKINT。", @route.get('/statistics/chart')
"expect": "CLKINT应拒绝不稳定的时钟或将错误上报给监控机制。" @transaction.atomic
}, { def get_chart(self):
"operation": "同时配置两个时钟但未正确绑定各自缓冲器。", """该接口返回当前年份下每月的项目统计返回横坐标12个月的字符串以及12个月数据"""
"expect": "系统应阻止非法配置操作,确保每个时钟进入正确的缓冲通道。" current_year = date.today().year
} month_list = []
] # 构造数组,里面是字典
} for i in range(12):
] month_dict = {'month': i + 1, 'count': 0}
} month_list.append(month_dict)
] project_qs = Project.objects.all()
return { for project in project_qs:
"history": [["我是没有用的", json.dumps(res)]] for m in month_list:
} if m['month'] == project.beginTime.month and project.beginTime.year == current_year:
m['count'] += 1
# 这是其他common内容接口 return ChenResponse(status=200, code=200, data=month_list)
@api_controller("/system", tags=['通用接口'])
class CommonController(ControllerBase):
"""通用接口类:工作台内的信息"""
@route.get("/getNoticeList")
def get_notice(self, pageSize, orderBy, orderType):
item_list = []
item1 = {"title": "测试管理平台V0.0.2测试发布", "created_at": "2023-09-23",
"content": "测试管理平台V0.0.2发布,正在进行内部测试.."}
item_list.append(item1)
item2 = {"title": "测试管理平台更新公共", "created_at": "2024-06-17",
"content": "<p>1.修改大纲和报告模版<p><p>2.修复多个bug<p>"}
item_list.append(item2)
return item_list
@route.get('/workplace/statistics')
@transaction.atomic
def get_statistics(self):
# 查询用户数量,进行的项目,项目总数,已完成项目数
user_count = Users.objects.count()
project_qs = Project.objects.all()
project_count = project_qs.count()
project_done_count = project_qs.filter(step='3').count()
project_processing_count = project_qs.filter(Q(step='1') | Q(step='2')).count()
return ChenResponse(data={'pcount': project_count, 'ucount': user_count,
'pdcount': project_done_count, 'ppcount': project_processing_count})
@route.get('/statistics/chart')
@transaction.atomic
def get_chart(self):
"""该接口返回当前年份下每月的项目统计返回横坐标12个月的字符串以及12个月数据"""
current_year = date.today().year
month_list = []
# 构造数组,里面是字典
for i in range(12):
month_dict = {'month': i + 1, 'count': 0}
month_list.append(month_dict)
project_qs = Project.objects.all()
for project in project_qs:
for m in month_list:
if m['month'] == project.beginTime.month and project.beginTime.year == current_year:
m['count'] += 1
return ChenResponse(status=200, code=200, data=month_list)

View File

@@ -460,7 +460,12 @@ class ProjectController(ControllerBase):
item_qs = self.get_model_from_category(category).objects.filter(project=project_obj) item_qs = self.get_model_from_category(category).objects.filter(project=project_obj)
if item_qs.exists(): if item_qs.exists():
item_obj = item_qs.first() item_obj = item_qs.first()
return ChenResponse(status=200, code=25001, data={"table": item_obj.table, "fontnote": item_obj.fontnote}) if item_obj:
return ChenResponse(status=200, code=25001, data={
"table": item_obj.table,
"fontnote": item_obj.fontnote,
"rounds": item_obj.rounds_map or []
})
return ChenResponse(status=200, code=25002, data=None) return ChenResponse(status=200, code=25002, data=None)
# ~~~静态软件项、静态硬件项、动态软件项、动态硬件项、测评数据 - 新增或修改~~~ # ~~~静态软件项、静态硬件项、动态软件项、动态硬件项、测评数据 - 新增或修改~~~
@@ -470,10 +475,21 @@ class ProjectController(ControllerBase):
project_obj = self.get_project_by_id(data.id) project_obj = self.get_project_by_id(data.id)
model = self.get_model_from_category(data.category) model = self.get_model_from_category(data.category)
item_qs = model.objects.filter(project=project_obj) item_qs = model.objects.filter(project=project_obj)
# 处理rounds_map
rounds = data.rounds
if rounds is None:
rounds = [["0"]] * len(data.table)
if item_qs.exists(): if item_qs.exists():
# 如果存在则修改 # 如果存在则修改
item_qs.delete() item_qs.delete()
model.objects.create(project=project_obj, table=data.table, fontnote=data.fontnote) model.objects.create(
project=project_obj,
table=data.table,
fontnote=data.fontnote,
rounds_map=rounds,
)
return ChenResponse(status=200, code=20000, message="保存成功")
# ~~~环境差异性分析 - 获取~~~ # ~~~环境差异性分析 - 获取~~~
@route.get("/get_env_analysis/") @route.get("/get_env_analysis/")

View File

@@ -0,0 +1,43 @@
# Generated by Django 6.0.4 on 2026-04-23 18:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('project', '0035_design_is_bidirectional'),
]
operations = [
migrations.AddField(
model_name='dynamichardwaretable',
name='rounds_map',
field=models.JSONField(blank=True, default=list, help_text='二维数组,每个内层数组是该行选中的轮次索引(字符串)', verbose_name='轮次数据'),
),
migrations.AddField(
model_name='dynamicsofttable',
name='rounds_map',
field=models.JSONField(blank=True, default=list, help_text='二维数组,每个内层数组是该行选中的轮次索引(字符串)', verbose_name='轮次数据'),
),
migrations.AddField(
model_name='evaluatedata',
name='rounds_map',
field=models.JSONField(blank=True, default=list, help_text='二维数组,每个内层数组是该行选中的轮次索引(字符串)', verbose_name='轮次数据'),
),
migrations.AddField(
model_name='staticsofthardware',
name='rounds_map',
field=models.JSONField(blank=True, default=list, help_text='二维数组,每个内层数组是该行选中的轮次索引(字符串)', verbose_name='轮次数据'),
),
migrations.AlterField(
model_name='project',
name='beginTime',
field=models.DateField(blank=True, help_text='开始时间', null=True, verbose_name='开始时间'),
),
migrations.AlterField(
model_name='project',
name='endTime',
field=models.DateField(blank=True, help_text='结束时间', null=True, verbose_name='结束时间'),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 6.0.4 on 2026-04-23 18:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('project', '0036_dynamichardwaretable_rounds_map_and_more'),
]
operations = [
migrations.AddField(
model_name='staticsoftitem',
name='rounds_map',
field=models.JSONField(blank=True, default=list, help_text='二维数组,每个内层数组是该行选中的轮次索引(字符串)', verbose_name='轮次数据'),
),
]

View File

@@ -499,6 +499,12 @@ class StaticSoftItem(models.Model):
verbose_name="关联项目", help_text="关联项目") verbose_name="关联项目", help_text="关联项目")
table = models.JSONField(verbose_name="储存表格二维数组", help_text="储存表格二维数组", default=default_json_value) table = models.JSONField(verbose_name="储存表格二维数组", help_text="储存表格二维数组", default=default_json_value)
fontnote = models.CharField(max_length=256, null=True, default="", verbose_name="题注", help_text="数据的题注说明") fontnote = models.CharField(max_length=256, null=True, default="", verbose_name="题注", help_text="数据的题注说明")
rounds_map = models.JSONField(
verbose_name="轮次数据",
help_text="二维数组,每个内层数组是该行选中的轮次索引(字符串)",
default=list,
blank=True,
)
class Meta: class Meta:
db_table = 'project_static_soft_item' db_table = 'project_static_soft_item'
@@ -511,6 +517,12 @@ class StaticSoftHardware(models.Model):
verbose_name="关联项目", help_text="关联项目") verbose_name="关联项目", help_text="关联项目")
table = models.JSONField(verbose_name="储存表格二维数组", help_text="储存表格二维数组", default=default_json_value) table = models.JSONField(verbose_name="储存表格二维数组", help_text="储存表格二维数组", default=default_json_value)
fontnote = models.CharField(max_length=256, null=True, default="", verbose_name="题注", help_text="数据的题注说明") fontnote = models.CharField(max_length=256, null=True, default="", verbose_name="题注", help_text="数据的题注说明")
rounds_map = models.JSONField(
verbose_name="轮次数据",
help_text="二维数组,每个内层数组是该行选中的轮次索引(字符串)",
default=list,
blank=True,
)
class Meta: class Meta:
db_table = 'project_static_hardware' db_table = 'project_static_hardware'
@@ -523,6 +535,12 @@ class DynamicSoftTable(models.Model):
verbose_name="关联项目", help_text="关联项目") verbose_name="关联项目", help_text="关联项目")
table = models.JSONField(verbose_name="储存表格二维数组", help_text="储存表格二维数组", default=default_json_value) table = models.JSONField(verbose_name="储存表格二维数组", help_text="储存表格二维数组", default=default_json_value)
fontnote = models.CharField(max_length=256, null=True, default="", verbose_name="题注", help_text="数据的题注说明") fontnote = models.CharField(max_length=256, null=True, default="", verbose_name="题注", help_text="数据的题注说明")
rounds_map = models.JSONField(
verbose_name="轮次数据",
help_text="二维数组,每个内层数组是该行选中的轮次索引(字符串)",
default=list,
blank=True,
)
class Meta: class Meta:
db_table = 'project_dynamic_soft_item' db_table = 'project_dynamic_soft_item'
@@ -535,6 +553,12 @@ class DynamicHardwareTable(models.Model):
verbose_name="关联项目", help_text="关联项目") verbose_name="关联项目", help_text="关联项目")
table = models.JSONField(verbose_name="储存表格二维数组", help_text="储存表格二维数组", default=default_json_value) table = models.JSONField(verbose_name="储存表格二维数组", help_text="储存表格二维数组", default=default_json_value)
fontnote = models.CharField(max_length=256, null=True, default="", verbose_name="题注", help_text="数据的题注说明") fontnote = models.CharField(max_length=256, null=True, default="", verbose_name="题注", help_text="数据的题注说明")
rounds_map = models.JSONField(
verbose_name="轮次数据",
help_text="二维数组,每个内层数组是该行选中的轮次索引(字符串)",
default=list,
blank=True,
)
class Meta: class Meta:
db_table = 'project_dynamic_hardware' db_table = 'project_dynamic_hardware'
@@ -547,6 +571,12 @@ class EvaluateData(models.Model):
verbose_name="关联项目", help_text="关联项目") verbose_name="关联项目", help_text="关联项目")
table = models.JSONField(verbose_name="储存表格二维数组", help_text="储存表格二维数组", default=default_json_value) table = models.JSONField(verbose_name="储存表格二维数组", help_text="储存表格二维数组", default=default_json_value)
fontnote = models.CharField(max_length=256, null=True, default="", verbose_name="题注", help_text="数据的题注说明") fontnote = models.CharField(max_length=256, null=True, default="", verbose_name="题注", help_text="数据的题注说明")
rounds_map = models.JSONField(
verbose_name="轮次数据",
help_text="二维数组,每个内层数组是该行选中的轮次索引(字符串)",
default=list,
blank=True,
)
class Meta: class Meta:
db_table = 'project_evaluate_data' db_table = 'project_evaluate_data'

View File

@@ -62,6 +62,7 @@ class StaticDynamicData(Schema):
category: str category: str
table: list[list[str]] table: list[list[str]]
fontnote: Optional[str] = "" fontnote: Optional[str] = ""
rounds: Optional[List[List[str]]] = None # 允许不传递
# ~~~环境差异性分析~~~ # ~~~环境差异性分析~~~
class EnvAnalysisSchema(Schema): class EnvAnalysisSchema(Schema):

View File

@@ -1,9 +1,12 @@
from utils.chen_ninja import ChenNinjaAPI from utils.chen_ninja import ChenNinjaAPI
from ninja.errors import HttpError
# 导入orjson解析器渲染器提升性能 # 导入orjson解析器渲染器提升性能
from cdtestplant_v1.parser import MyParser from cdtestplant_v1.parser import MyParser
from cdtestplant_v1.renderer import MyRenderer from cdtestplant_v1.renderer import MyRenderer
# swagger-ui配置 # swagger-ui配置
from ninja import Swagger from ninja import Swagger
# 错误码
from utils.codes import PROJECT_ENDTIME_ERROR_CODE
api = ChenNinjaAPI( api = ChenNinjaAPI(
title="测试管理平台API", title="测试管理平台API",
@@ -14,5 +17,14 @@ api = ChenNinjaAPI(
docs=Swagger({"persistAuthorization": True}) docs=Swagger({"persistAuthorization": True})
) )
# 捕获HttpError - 注意这种方式不过create_response函数需自己定义
@api.exception_handler(HttpError)
def in_program_exception_handler(request, exc):
# HttpError的status_code这里处理为自定义码而非HTTP协议的
data = {}
if exc.status_code is PROJECT_ENDTIME_ERROR_CODE:
data['flag'] = PROJECT_ENDTIME_ERROR_CODE
return api.create_response(request, status=500, message=exc.message, data=data)
# 自动寻找每个app下面controllers.py中被@api_controller修饰的类 # 自动寻找每个app下面controllers.py中被@api_controller修饰的类
api.auto_discover_controllers() api.auto_discover_controllers()

View File

@@ -1,27 +1,5 @@
[WARNING][2026-04-22 09:45:35,603][log.py:249]Unauthorized: /api/system/getInfo [WARNING][2026-04-23 15:28:58,739][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[WARNING][2026-04-22 09:45:35,677][log.py:249]Unauthorized: /api/system/logout [ERROR][2026-04-23 15:28:58,748][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-22 09:45:39,967][backend.py:91]Caught LDAPError looking up user: SERVER_DOWN({'result': -1, 'desc': "Can't contact LDAP server", 'ctrls': []})
[WARNING][2026-04-22 11:03:49,239][operation.py:136]"PUT - DesignController[update_design] /api/project/editDesignDemand/4030" (1048, "Column 'is_bidirectional' cannot be null")
[ERROR][2026-04-22 11:03:49,239][errors.py:131](1048, "Column 'is_bidirectional' cannot be null")
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute
return self.cursor.execute(sql, params)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\mysql\base.py", line 78, in execute
return self.cursor.execute(query, args)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 179, in execute
res = self._query(mogrified_query)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 330, in _query
db.query(q)
~~~~~~~~^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\connections.py", line 286, in query
_mysql.connection.query(self, query)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
MySQLdb.IntegrityError: (1048, "Column 'is_bidirectional' cannot be null")
The above exception was the direct cause of the following exception:
Traceback (most recent call last): Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 217, in run File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 217, in run
result = self.view_func(request, **ctx.kwargs["view_func_kwargs"]) result = self.view_func(request, **ctx.kwargs["view_func_kwargs"])
@@ -31,79 +9,43 @@ Traceback (most recent call last):
) )
File "D:\programs\uv\python\cpython-3.13.11-windows-x86_64-none\Lib\contextlib.py", line 85, in inner File "D:\programs\uv\python\cpython-3.13.11-windows-x86_64-none\Lib\contextlib.py", line 85, in inner
return func(*args, **kwds) return func(*args, **kwds)
File "E:\pycharmProjects\cdtestplant_v1\apps\project\controllers\design.py", line 148, in update_design File "E:\pycharmProjects\cdtestplant_v1\apps\project\controllers\project.py", line 271, in document_time_show
design_qs.save() time = time_return_to(id)
~~~~~~~~~~~~~~^^ File "E:\pycharmProjects\cdtestplant_v1\apps\project\tool\timeList.py", line 94, in time_return_to
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 874, in save temp_dict = time_parser.bg_final_time()
self.save_base( File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\extensions\documentTime.py", line 206, in bg_final_time
~~~~~~~~~~~~~~^ raise HttpError(PROJECT_ENDTIME_ERROR_CODE, message='项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
using=using, ninja.errors.HttpError: 项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间
^^^^^^^^^^^^
...<2 lines>... During handling of the above exception, another exception occurred:
update_fields=update_fields,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Traceback (most recent call last):
) File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\core\handlers\exception.py", line 55, in inner
^ response = get_response(request)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 966, in save_base File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\core\handlers\base.py", line 198, in _get_response
updated = self._save_table( response = wrapped_callback(request, *callback_args, **callback_kwargs)
raw, File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja\operation.py", line 661, in sync_view_wrapper
...<4 lines>... return self._sync_view(request, *args, **kwargs)
update_fields, ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
) File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 322, in _sync_view
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 1110, in _save_table return super(PathView, self)._sync_view(request, *args, **kwargs)
results = self._do_update( ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
base_qs, File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja\operation.py", line 673, in _sync_view
...<5 lines>... return operation.run(request, *a, **kw)
returning_fields, ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
) File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 231, in run
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 1213, in _do_update return self.api.on_exception(request, e)
return filtered._update(values, returning_fields) ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^ File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja\main.py", line 617, in on_exception
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\query.py", line 1327, in _update return handler(request, exc)
return query.get_compiler(self.db).execute_returning_sql(returning_fields) File "E:\pycharmProjects\cdtestplant_v1\cdtestplant_v1\api.py", line 24, in in_program_exception_handler
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^ if exc.detail is PROJECT_ENDTIME_ERROR_CODE:
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\sql\compiler.py", line 2140, in execute_returning_sql ^^^^^^^^^^
row_count = self.execute_sql(ROW_COUNT) AttributeError: 'HttpError' object has no attribute 'detail'
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\sql\compiler.py", line 2111, in execute_sql [WARNING][2026-04-23 15:29:14,430][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
row_count = super().execute_sql(result_type) [ERROR][2026-04-23 15:29:14,438][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\sql\compiler.py", line 1624, in execute_sql [WARNING][2026-04-23 15:30:11,756][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
cursor.execute(sql, params) [ERROR][2026-04-23 15:30:11,772][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 122, in execute
return super().execute(sql, params)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 79, in execute
return self._execute_with_wrappers(
~~~~~~~~~~~~~~~~~~~~~~~~~~~^
sql, params, many=False, executor=self._execute
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 92, in _execute_with_wrappers
return executor(sql, params, many, context)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 100, in _execute
with self.db.wrap_database_errors:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\utils.py", line 94, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\utils.py", line 105, in _execute
return self.cursor.execute(sql, params)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\backends\mysql\base.py", line 78, in execute
return self.cursor.execute(query, args)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 179, in execute
res = self._query(mogrified_query)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\cursors.py", line 330, in _query
db.query(q)
~~~~~~~~^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\MySQLdb\connections.py", line 286, in query
_mysql.connection.query(self, query)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
django.db.utils.IntegrityError: (1048, "Column 'is_bidirectional' cannot be null")
[ERROR][2026-04-22 11:03:49,254][log.py:249]Internal Server Error: /api/project/editDesignDemand/4030
[WARNING][2026-04-22 11:23:22,342][operation.py:136]"POST - DesignController[create_design] /api/project/designDemand/save" ("Design() got unexpected keyword arguments: 'forward_source', 'forward_destination', 'forward_description', 'reverse_source', 'reverse_destination', 'reverse_description'",)
[ERROR][2026-04-22 11:23:22,342][errors.py:131]Design() got unexpected keyword arguments: 'forward_source', 'forward_destination', 'forward_description', 'reverse_source', 'reverse_destination', 'reverse_description'
Traceback (most recent call last): Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 217, in run File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 217, in run
result = self.view_func(request, **ctx.kwargs["view_func_kwargs"]) result = self.view_func(request, **ctx.kwargs["view_func_kwargs"])
@@ -113,21 +55,88 @@ Traceback (most recent call last):
) )
File "D:\programs\uv\python\cpython-3.13.11-windows-x86_64-none\Lib\contextlib.py", line 85, in inner File "D:\programs\uv\python\cpython-3.13.11-windows-x86_64-none\Lib\contextlib.py", line 85, in inner
return func(*args, **kwds) return func(*args, **kwds)
File "E:\pycharmProjects\cdtestplant_v1\apps\project\controllers\design.py", line 116, in create_design File "E:\pycharmProjects\cdtestplant_v1\apps\project\controllers\project.py", line 271, in document_time_show
qs = Design.objects.create(**asert_dict) time = time_return_to(id)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\manager.py", line 87, in manager_method File "E:\pycharmProjects\cdtestplant_v1\apps\project\tool\timeList.py", line 94, in time_return_to
return getattr(self.get_queryset(), name)(*args, **kwargs) temp_dict = time_parser.bg_final_time()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^ File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\extensions\documentTime.py", line 206, in bg_final_time
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\query.py", line 667, in create raise HttpError(PROJECT_ENDTIME_ERROR_CODE, message='项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
obj = self.model(**kwargs) ninja.errors.HttpError: 项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\db\models\base.py", line 590, in __init__
raise TypeError( During handling of the above exception, another exception occurred:
...<2 lines>...
) Traceback (most recent call last):
TypeError: Design() got unexpected keyword arguments: 'forward_source', 'forward_destination', 'forward_description', 'reverse_source', 'reverse_destination', 'reverse_description' File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\core\handlers\exception.py", line 55, in inner
[ERROR][2026-04-22 11:23:22,347][log.py:249]Internal Server Error: /api/project/designDemand/save response = get_response(request)
[WARNING][2026-04-22 13:13:59,640][operation.py:136]"GET - GenerateControllerDG[create_interface] /api/generate/create/interface" ("'Design' object has no attribute 'source'",) File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\django\core\handlers\base.py", line 198, in _get_response
[ERROR][2026-04-22 13:13:59,640][errors.py:131]'Design' object has no attribute 'source' response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja\operation.py", line 661, in sync_view_wrapper
return self._sync_view(request, *args, **kwargs)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 322, in _sync_view
return super(PathView, self)._sync_view(request, *args, **kwargs)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja\operation.py", line 673, in _sync_view
return operation.run(request, *a, **kw)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 231, in run
return self.api.on_exception(request, e)
~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja\main.py", line 617, in on_exception
return handler(request, exc)
File "E:\pycharmProjects\cdtestplant_v1\cdtestplant_v1\api.py", line 26, in in_program_exception_handler
return api.create_response(request, status=500, message=exc.message)
~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: ChenNinjaAPI.create_response() missing 1 required positional argument: 'data'
[WARNING][2026-04-23 15:31:00,940][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:31:00,948][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-23 15:31:09,568][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:31:09,578][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-23 15:34:41,469][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:34:41,477][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-23 15:34:45,816][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:34:45,824][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-23 15:34:50,470][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:34:50,480][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-23 15:34:55,380][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:34:55,388][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-23 15:34:58,806][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:34:58,814][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-23 15:35:14,656][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:35:14,664][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-23 15:35:41,998][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:35:42,007][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-23 15:38:50,737][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:38:50,745][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-23 15:43:24,757][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:43:24,765][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-23 15:44:02,062][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:44:02,071][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-23 15:44:21,790][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:44:21,798][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-23 15:44:32,220][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:44:32,227][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-23 15:46:42,165][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:46:42,174][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-23 15:47:01,501][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:47:01,509][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-23 15:47:40,712][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:47:40,722][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-23 15:47:43,095][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:47:43,103][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-23 15:53:49,660][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:53:49,667][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-23 15:54:00,089][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:54:00,097][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-23 15:56:58,912][operation.py:136]"GET - ProjectController[document_time_show] /api/testmanage/project/document_time_show" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:56:58,918][log.py:249]Internal Server Error: /api/testmanage/project/document_time_show
[WARNING][2026-04-23 15:58:44,243][operation.py:136]"POST - GenerateSeitaiController[create_bgDocument] /api/create/bgDocument" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-23 15:58:44,244][log.py:249]Internal Server Error: /api/create/bgDocument
[WARNING][2026-04-24 13:56:12,151][log.py:249]Unauthorized: /api/system/getInfo
[WARNING][2026-04-24 13:56:12,209][log.py:249]Unauthorized: /api/system/logout
[WARNING][2026-04-24 13:56:16,702][backend.py:91]Caught LDAPError looking up user: SERVER_DOWN({'result': -1, 'desc': "Can't contact LDAP server", 'ctrls': []})
[WARNING][2026-04-24 14:06:28,243][operation.py:136]"GET - GenerateControllerDG[create_static_soft] /api/generate/create/static_soft" ('GenerateControllerDG.create_table_context() takes 3 positional arguments but 4 were given',)
[ERROR][2026-04-24 14:06:28,243][errors.py:131]GenerateControllerDG.create_table_context() takes 3 positional arguments but 4 were given
Traceback (most recent call last): Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 217, in run File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 217, in run
result = self.view_func(request, **ctx.kwargs["view_func_kwargs"]) result = self.view_func(request, **ctx.kwargs["view_func_kwargs"])
@@ -135,8 +144,110 @@ Traceback (most recent call last):
result = self.route.view_func( result = self.route.view_func(
ctx.controller_instance, *args, **ctx.view_func_kwargs ctx.controller_instance, *args, **ctx.view_func_kwargs
) )
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 417, in create_interface File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 581, in create_static_soft
'source': interface.source, res = self.uniform_static_dynamic_response(id, '静态软件项_2.docx', '静态软件项.docx', StaticSoftItem)
^^^^^^^^^^^^^^^^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Design' object has no attribute 'source' File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 565, in uniform_static_dynamic_response
[ERROR][2026-04-22 13:13:59,650][log.py:249]Internal Server Error: /api/generate/create/interface subdoc = cls.create_table_context(table_data, doc, obj.rounds_map)
TypeError: GenerateControllerDG.create_table_context() takes 3 positional arguments but 4 were given
[ERROR][2026-04-24 14:06:28,258][log.py:249]Internal Server Error: /api/generate/create/static_soft
[WARNING][2026-04-24 14:06:28,259][operation.py:136]"GET - GenerateControllerDG[create_static_hard] /api/generate/create/static_hard" ('GenerateControllerDG.create_table_context() takes 3 positional arguments but 4 were given',)
[ERROR][2026-04-24 14:06:28,274][errors.py:131]GenerateControllerDG.create_table_context() takes 3 positional arguments but 4 were given
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 217, in run
result = self.view_func(request, **ctx.kwargs["view_func_kwargs"])
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\controllers\route\route_functions.py", line 108, in as_view
result = self.route.view_func(
ctx.controller_instance, *args, **ctx.view_func_kwargs
)
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 597, in create_static_hard
res = self.uniform_static_dynamic_response(id, '静态硬件和固件项_2.docx', '静态硬件和固件项.docx', StaticSoftHardware)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 565, in uniform_static_dynamic_response
subdoc = cls.create_table_context(table_data, doc, obj.rounds_map)
TypeError: GenerateControllerDG.create_table_context() takes 3 positional arguments but 4 were given
[ERROR][2026-04-24 14:06:28,278][log.py:249]Internal Server Error: /api/generate/create/static_hard
[WARNING][2026-04-24 14:06:28,316][operation.py:136]"GET - GenerateControllerDG[create_dynamic_soft] /api/generate/create/dynamic_soft" ('GenerateControllerDG.create_table_context() takes 3 positional arguments but 4 were given',)
[ERROR][2026-04-24 14:06:28,316][errors.py:131]GenerateControllerDG.create_table_context() takes 3 positional arguments but 4 were given
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 217, in run
result = self.view_func(request, **ctx.kwargs["view_func_kwargs"])
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\controllers\route\route_functions.py", line 108, in as_view
result = self.route.view_func(
ctx.controller_instance, *args, **ctx.view_func_kwargs
)
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 637, in create_dynamic_soft
res = self.uniform_static_dynamic_response(id, '动态软件项_2.docx', '动态软件项.docx', DynamicSoftTable)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 565, in uniform_static_dynamic_response
subdoc = cls.create_table_context(table_data, doc, obj.rounds_map)
TypeError: GenerateControllerDG.create_table_context() takes 3 positional arguments but 4 were given
[ERROR][2026-04-24 14:06:28,319][log.py:249]Internal Server Error: /api/generate/create/dynamic_soft
[WARNING][2026-04-24 14:06:28,324][operation.py:136]"GET - GenerateControllerDG[create_test_data] /api/generate/create/test_data" ('GenerateControllerDG.create_table_context() takes 3 positional arguments but 4 were given',)
[WARNING][2026-04-24 14:06:28,324][operation.py:136]"GET - GenerateControllerDG[create_dynamic_hard] /api/generate/create/dynamic_hard" ('GenerateControllerDG.create_table_context() takes 3 positional arguments but 4 were given',)
[ERROR][2026-04-24 14:06:28,326][errors.py:131]GenerateControllerDG.create_table_context() takes 3 positional arguments but 4 were given
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 217, in run
result = self.view_func(request, **ctx.kwargs["view_func_kwargs"])
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\controllers\route\route_functions.py", line 108, in as_view
result = self.route.view_func(
ctx.controller_instance, *args, **ctx.view_func_kwargs
)
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 672, in create_test_data
res = self.uniform_static_dynamic_response(id, '测评数据_2.docx',
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
'测评数据.docx', EvaluateData)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 565, in uniform_static_dynamic_response
subdoc = cls.create_table_context(table_data, doc, obj.rounds_map)
TypeError: GenerateControllerDG.create_table_context() takes 3 positional arguments but 4 were given
[ERROR][2026-04-24 14:06:28,326][errors.py:131]GenerateControllerDG.create_table_context() takes 3 positional arguments but 4 were given
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 217, in run
result = self.view_func(request, **ctx.kwargs["view_func_kwargs"])
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\controllers\route\route_functions.py", line 108, in as_view
result = self.route.view_func(
ctx.controller_instance, *args, **ctx.view_func_kwargs
)
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 655, in create_dynamic_hard
res = self.uniform_static_dynamic_response(id, '动态硬件和固件项_2.docx',
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
'动态硬件和固件项.docx', DynamicHardwareTable)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 565, in uniform_static_dynamic_response
subdoc = cls.create_table_context(table_data, doc, obj.rounds_map)
TypeError: GenerateControllerDG.create_table_context() takes 3 positional arguments but 4 were given
[ERROR][2026-04-24 14:06:28,336][log.py:249]Internal Server Error: /api/generate/create/dynamic_hard
[ERROR][2026-04-24 14:06:28,336][log.py:249]Internal Server Error: /api/generate/create/test_data
[WARNING][2026-04-24 14:09:36,188][operation.py:136]"GET - GenerateControllerDG[create_env_diff] /api/generate/create/env_diff" ("GenerateControllerDG.create_table_context() missing 1 required positional argument: 'rounds_map'",)
[ERROR][2026-04-24 14:09:36,188][errors.py:131]GenerateControllerDG.create_table_context() missing 1 required positional argument: 'rounds_map': Did you fail to use functools.wraps() in a decorator?
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 217, in run
result = self.view_func(request, **ctx.kwargs["view_func_kwargs"])
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\controllers\route\route_functions.py", line 108, in as_view
result = self.route.view_func(
ctx.controller_instance, *args, **ctx.view_func_kwargs
)
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 697, in create_env_diff
subdoc = self.create_table_context(table_data, doc)
TypeError: GenerateControllerDG.create_table_context() missing 1 required positional argument: 'rounds_map': Did you fail to use functools.wraps() in a decorator?
[ERROR][2026-04-24 14:09:36,192][log.py:249]Internal Server Error: /api/generate/create/env_diff
[WARNING][2026-04-24 14:43:28,969][operation.py:136]"POST - GenerateSeitaiController[create_bgDocument] /api/create/bgDocument" (500412, '项目结束时间早于最后一轮次结束时间或等于开始时间,请修改项目结束时间')
[ERROR][2026-04-24 14:43:28,969][log.py:249]Internal Server Error: /api/create/bgDocument
[WARNING][2026-04-24 15:11:55,484][operation.py:136]"GET - GenerateControllerDG[create_env_diff] /api/generate/create/env_diff" ("'GenerateControllerDG' object has no attribute 'create_table_context'",)
[ERROR][2026-04-24 15:11:55,484][errors.py:131]'GenerateControllerDG' object has no attribute 'create_table_context'
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 217, in run
result = self.view_func(request, **ctx.kwargs["view_func_kwargs"])
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\controllers\route\route_functions.py", line 108, in as_view
result = self.route.view_func(
ctx.controller_instance, *args, **ctx.view_func_kwargs
)
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\dg.py", line 633, in create_env_diff
subdoc = self.create_table_context(table_data, doc)
^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'GenerateControllerDG' object has no attribute 'create_table_context'
[ERROR][2026-04-24 15:11:55,488][log.py:249]Internal Server Error: /api/generate/create/env_diff
[WARNING][2026-05-29 14:44:48,323][backend.py:91]Caught LDAPError looking up user: SERVER_DOWN({'result': -1, 'desc': "Can't contact LDAP server", 'ctrls': []})
[WARNING][2026-05-29 14:45:02,302][operation.py:136]"POST - AITestController[ai_return] /api/local_doc_qa/testing_item" ([{'type': 'missing', 'loc': ('body', 'item', 'stream'), 'msg': 'Field required'}],)
[WARNING][2026-05-29 14:45:02,302][log.py:249]Unprocessable Content: /api/local_doc_qa/testing_item

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More