大表功能完成
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -7,11 +7,14 @@ from ninja.errors import HttpError
|
|||||||
from utils.chen_pagination import MyPagination
|
from utils.chen_pagination import MyPagination
|
||||||
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.functions import Replace
|
||||||
|
from django.db.models import Q, F, Value
|
||||||
from typing import List
|
from typing import List
|
||||||
from utils.chen_response import ChenResponse
|
from utils.chen_response import ChenResponse
|
||||||
from utils.chen_crud import multi_delete_case
|
from utils.chen_crud import multi_delete_case
|
||||||
from apps.project.models import Design, Dut, Round, TestDemand, Case, CaseStep, Project, Problem
|
from apps.project.models import Design, Dut, Round, TestDemand, Case, CaseStep, Project, Problem
|
||||||
from apps.project.schemas.case import DeleteSchema, CaseModelOutSchema, CaseFilterSchema, CaseTreeReturnSchema, \
|
from apps.project.schemas.case import DeleteSchema, CaseModelOutSchema, CaseFilterSchema, \
|
||||||
|
CaseTreeReturnSchema, ReplaceCaseSchema, PersonReplaceSchema, ExetimeReplaceSchema, \
|
||||||
CaseTreeInputSchema, CaseCreateOutSchema, CaseCreateInputSchema, DemandNodeSchema
|
CaseTreeInputSchema, CaseCreateOutSchema, CaseCreateInputSchema, DemandNodeSchema
|
||||||
from utils.util import get_testType
|
from utils.util import get_testType
|
||||||
from utils.codes import HTTP_INDEX_ERROR, HTTP_EXISTS_CASES
|
from utils.codes import HTTP_INDEX_ERROR, HTTP_EXISTS_CASES
|
||||||
@@ -35,15 +38,23 @@ class CaseController(ControllerBase):
|
|||||||
qs = Case.objects.filter(id=case_id) # type:ignore
|
qs = Case.objects.filter(id=case_id) # type:ignore
|
||||||
else:
|
else:
|
||||||
conditionNoneToBlank(data)
|
conditionNoneToBlank(data)
|
||||||
|
query_params = {
|
||||||
|
'project__id': data.project_id,
|
||||||
|
'ident__icontains': data.ident,
|
||||||
|
'name__icontains': data.name,
|
||||||
|
'designPerson__icontains': data.designPerson,
|
||||||
|
'testPerson__icontains': data.testPerson,
|
||||||
|
'monitorPerson__icontains': data.monitorPerson,
|
||||||
|
'summarize__icontains': data.summarize
|
||||||
|
}
|
||||||
|
# 如果没有多个key则是“那个汇总界面”
|
||||||
|
if data.dut_id and data.design_id and data.test_id:
|
||||||
test_key = "".join([data.round_id, '-', data.dut_id, '-', data.design_id, '-', data.test_id])
|
test_key = "".join([data.round_id, '-', data.dut_id, '-', data.design_id, '-', data.test_id])
|
||||||
qs = Case.objects.filter(project__id=data.project_id, test__key=test_key, # type:ignore
|
query_params['test__key'] = test_key
|
||||||
ident__icontains=data.ident,
|
else:
|
||||||
name__icontains=data.name,
|
# 汇总界面只查round
|
||||||
designPerson__icontains=data.designPerson,
|
query_params['round__key'] = data.round_id
|
||||||
testPerson__icontains=data.testPerson,
|
qs = Case.objects.filter(**query_params).order_by("key")
|
||||||
monitorPerson__icontains=data.monitorPerson,
|
|
||||||
summarize__icontains=data.summarize,
|
|
||||||
).order_by("key")
|
|
||||||
# 由于有嵌套query_set存在,把每个用例的schema加上一个字段
|
# 由于有嵌套query_set存在,把每个用例的schema加上一个字段
|
||||||
query_list = []
|
query_list = []
|
||||||
for query_single in qs:
|
for query_single in qs:
|
||||||
@@ -54,6 +65,14 @@ class CaseController(ControllerBase):
|
|||||||
related_problem: Problem = query_single.caseField.first()
|
related_problem: Problem = query_single.caseField.first()
|
||||||
if query_single.caseField.all():
|
if query_single.caseField.all():
|
||||||
setattr(query_single, 'problem', related_problem)
|
setattr(query_single, 'problem', related_problem)
|
||||||
|
# 2025年5月10日在test字段加上testContent
|
||||||
|
test_obj = query_single.test
|
||||||
|
sub_list = []
|
||||||
|
for step_obj in test_obj.testQField.all():
|
||||||
|
setattr(step_obj, "subStep", step_obj.testStepField.all().values())
|
||||||
|
sub_list.append(step_obj)
|
||||||
|
setattr(test_obj, "testContent", sub_list)
|
||||||
|
setattr(query_single, 'test', test_obj)
|
||||||
query_list.append(query_single)
|
query_list.append(query_single)
|
||||||
return query_list
|
return query_list
|
||||||
|
|
||||||
@@ -69,6 +88,17 @@ class CaseController(ControllerBase):
|
|||||||
return case
|
return case
|
||||||
raise HttpError(500, "您获取的数据不存在")
|
raise HttpError(500, "您获取的数据不存在")
|
||||||
|
|
||||||
|
@route.get("/getCaseOneById", response=CaseModelOutSchemaWithoutProblem, url_name='case-one-by-id')
|
||||||
|
@transaction.atomic
|
||||||
|
def get_case_by_id(self, id: int):
|
||||||
|
"""用于在用例树状页面,获取promblem信息,这里根据key获取信息"""
|
||||||
|
case = Case.objects.filter(id=id).first()
|
||||||
|
if case:
|
||||||
|
setattr(case, "testStep", case.step.all().values())
|
||||||
|
setattr(case, 'testType', get_testType(case.test.testType, dict_code='testType'))
|
||||||
|
return case
|
||||||
|
raise HttpError(500, "您获取的数据不存在")
|
||||||
|
|
||||||
# 处理树状数据
|
# 处理树状数据
|
||||||
@route.get("/getCaseInfo", response=List[CaseTreeReturnSchema], url_name="case-info")
|
@route.get("/getCaseInfo", response=List[CaseTreeReturnSchema], url_name="case-info")
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
@@ -108,7 +138,8 @@ class CaseController(ControllerBase):
|
|||||||
# 直接把测试项的标识给前端处理显示
|
# 直接把测试项的标识给前端处理显示
|
||||||
asert_dict['ident'] = test_instance.ident
|
asert_dict['ident'] = test_instance.ident
|
||||||
# ~~~~~~~~~end~~~~~~~~~
|
# ~~~~~~~~~end~~~~~~~~~
|
||||||
asert_dict.update({'key': key_string, 'round': round_instance, 'dut': dut_instance, 'design': design_instance,
|
asert_dict.update(
|
||||||
|
{'key': key_string, 'round': round_instance, 'dut': dut_instance, 'design': design_instance,
|
||||||
"test": test_instance, 'title': payload.name})
|
"test": test_instance, 'title': payload.name})
|
||||||
asert_dict.pop("round_key")
|
asert_dict.pop("round_key")
|
||||||
asert_dict.pop("dut_key")
|
asert_dict.pop("dut_key")
|
||||||
@@ -144,7 +175,8 @@ class CaseController(ControllerBase):
|
|||||||
content_single.delete()
|
content_single.delete()
|
||||||
data_list = []
|
data_list = []
|
||||||
for item in value:
|
for item in value:
|
||||||
if item['operation'] or item['expect'] or item['result'] or item['passed'] or item['status']:
|
if item['operation'] or item['expect'] or item['result'] or item['passed'] or item[
|
||||||
|
'status']:
|
||||||
item["case"] = case_qs
|
item["case"] = case_qs
|
||||||
data_list.append(CaseStep(**item))
|
data_list.append(CaseStep(**item))
|
||||||
CaseStep.objects.bulk_create(data_list) # type:ignore
|
CaseStep.objects.bulk_create(data_list) # type:ignore
|
||||||
@@ -186,7 +218,8 @@ class CaseController(ControllerBase):
|
|||||||
# 先查询当前测试项下面有无case
|
# 先查询当前测试项下面有无case
|
||||||
case_exists = demand.tcField.exists()
|
case_exists = demand.tcField.exists()
|
||||||
if case_exists:
|
if case_exists:
|
||||||
return ChenResponse(status=500, code=HTTP_EXISTS_CASES, message='测试项下面有用例,请删除后生成')
|
return ChenResponse(status=500, code=HTTP_EXISTS_CASES,
|
||||||
|
message='测试项下面有用例,请删除后生成')
|
||||||
# 查询所有测试子项
|
# 查询所有测试子项
|
||||||
sub_items = demand.testQField.all()
|
sub_items = demand.testQField.all()
|
||||||
# 每一个子项都创建一个用例,先声明一个列表,后面可以bulk_create
|
# 每一个子项都创建一个用例,先声明一个列表,后面可以bulk_create
|
||||||
@@ -224,7 +257,8 @@ class CaseController(ControllerBase):
|
|||||||
CaseStep.objects.create(**case_step_dict) # type:ignore
|
CaseStep.objects.create(**case_step_dict) # type:ignore
|
||||||
index += 1
|
index += 1
|
||||||
# 这里返回一个demand的key用于前端刷新树状图
|
# 这里返回一个demand的key用于前端刷新树状图
|
||||||
return ChenResponse(data={'key': demand_node.key}, status=200, code=200, message='测试项自动生成用例成功')
|
return ChenResponse(data={'key': demand_node.key}, status=200, code=200,
|
||||||
|
message='测试项自动生成用例成功')
|
||||||
|
|
||||||
# 测试用例复制/移动到测试项上
|
# 测试用例复制/移动到测试项上
|
||||||
@route.get("/case/copy_or_move_to_demand", url_name='case-copy-move-demand')
|
@route.get("/case/copy_or_move_to_demand", url_name='case-copy-move-demand')
|
||||||
@@ -240,6 +274,56 @@ class CaseController(ControllerBase):
|
|||||||
# 测试用例复制/移动到用例
|
# 测试用例复制/移动到用例
|
||||||
@route.get("/case/copy_or_move_by_case", url_name='case-copy-move-case')
|
@route.get("/case/copy_or_move_by_case", url_name='case-copy-move-case')
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def copy_move_case_by_case(self, project_id: int, drag_key: str, drop_key: str, move: bool, position: int):
|
def copy_move_case_by_case(self, project_id: int, drag_key: str, drop_key: str, move: bool,
|
||||||
|
position: int):
|
||||||
case_to_case_copy_or_move(project_id, drag_key, drop_key, move, position)
|
case_to_case_copy_or_move(project_id, drag_key, drop_key, move, position)
|
||||||
return ChenResponse(data={'old': {'key': drag_key}, 'new': {'key': drop_key}})
|
return ChenResponse(data={'old': {'key': drag_key}, 'new': {'key': drop_key}})
|
||||||
|
|
||||||
|
# 用例-替换接口
|
||||||
|
@route.post("/case/replace/", url_name='case-replace')
|
||||||
|
@transaction.atomic
|
||||||
|
def replace_case_step_content(self, payload: ReplaceCaseSchema):
|
||||||
|
# 1.首先查询项目
|
||||||
|
project_obj: Project = get_object_or_404(Project, id=payload.project_id)
|
||||||
|
# 2.查询[所有轮次]的selectRows的id
|
||||||
|
case_qs = project_obj.pcField.filter(id__in=payload.selectRows, round__key=payload.round_key)
|
||||||
|
# 3.批量替换里面文本(解构不影响老数组)
|
||||||
|
selectColumn = [x for x in payload.selectColumn if x != 'testStep']
|
||||||
|
replace_kwargs = {
|
||||||
|
field_name: Replace(F(field_name), Value(payload.originText), Value(payload.replaceText))
|
||||||
|
for field_name in selectColumn
|
||||||
|
}
|
||||||
|
# 4.单独处理testContentStep的操作、预期-查询所有
|
||||||
|
# 4.1.获取所有关联的TestDemandContentStep
|
||||||
|
step_count = 0
|
||||||
|
if 'testStep' in payload.selectColumn:
|
||||||
|
caseStep_qs = CaseStep.objects.filter(case__in=case_qs)
|
||||||
|
# 批量更新 operation 和 expect
|
||||||
|
step_count = caseStep_qs.update(
|
||||||
|
operation=Replace(F('operation'), Value(payload.originText), Value(payload.replaceText)),
|
||||||
|
expect=Replace(F('expect'), Value(payload.originText), Value(payload.replaceText))
|
||||||
|
)
|
||||||
|
# 5.提交更新
|
||||||
|
replace_count = case_qs.update(**replace_kwargs)
|
||||||
|
return {'count': replace_count + step_count}
|
||||||
|
|
||||||
|
# 批量替换设计人员、执行人员、审核人员
|
||||||
|
@route.post("/case/personReplace/", url_name='case-person-replace')
|
||||||
|
@transaction.atomic
|
||||||
|
def bulk_replace_person(self, payload: PersonReplaceSchema):
|
||||||
|
# 替换设计人员
|
||||||
|
case_qs = Case.objects.filter(id__in=payload.selectRows)
|
||||||
|
if payload.designPerson != '不替换' and payload.designPerson != '':
|
||||||
|
case_qs.update(designPerson=payload.designPerson)
|
||||||
|
if payload.testPerson != '不替换' and payload.testPerson != '':
|
||||||
|
case_qs.update(testPerson=payload.testPerson)
|
||||||
|
if payload.monitorPerson != '不替换' and payload.monitorPerson != '':
|
||||||
|
case_qs.update(monitorPerson=payload.monitorPerson)
|
||||||
|
|
||||||
|
# 批量替换事件
|
||||||
|
@route.post("/case/timeReplace/", url_name='case-time-replace')
|
||||||
|
@transaction.atomic
|
||||||
|
def bulk_replace_time(self, payload: ExetimeReplaceSchema):
|
||||||
|
# 替换设计人员
|
||||||
|
case_qs = Case.objects.filter(id__in=payload.selectRows)
|
||||||
|
case_qs.update(exe_time=payload.exetime)
|
||||||
|
|||||||
@@ -6,30 +6,44 @@ from ninja.pagination import paginate
|
|||||||
from ninja.errors import HttpError
|
from ninja.errors import HttpError
|
||||||
from utils.chen_pagination import MyPagination
|
from utils.chen_pagination import MyPagination
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
from django.db.models import F, Value
|
||||||
|
from django.db.models.functions import Replace
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from typing import List
|
from typing import List
|
||||||
from utils.chen_response import ChenResponse
|
from utils.chen_response import ChenResponse
|
||||||
from utils.chen_crud import multi_delete_design
|
from utils.chen_crud import multi_delete_design
|
||||||
from utils.codes import HTTP_INDEX_ERROR
|
from utils.codes import HTTP_INDEX_ERROR
|
||||||
from apps.project.models import Design, Dut, Round, Project
|
from apps.project.models import Design, Dut, Round, Project
|
||||||
from apps.project.schemas.design import DeleteSchema, DesignFilterSchema, DesignModelOutSchema, DesignTreeReturnSchema, \
|
from apps.project.schemas.design import DeleteSchema, DesignFilterSchema, DesignModelOutSchema, \
|
||||||
DesignTreeInputSchema, DesignCreateOutSchema, DesignCreateInputSchema, MultiDesignCreateInputSchema
|
DesignTreeReturnSchema, \
|
||||||
|
DesignTreeInputSchema, DesignCreateOutSchema, DesignCreateInputSchema, MultiDesignCreateInputSchema, \
|
||||||
|
ReplaceDesignContentSchema
|
||||||
from apps.project.tools.delete_change_key import design_delete_sub_node_key
|
from apps.project.tools.delete_change_key import design_delete_sub_node_key
|
||||||
from utils.smallTools.interfaceTools import conditionNoneToBlank
|
from utils.smallTools.interfaceTools import conditionNoneToBlank
|
||||||
|
|
||||||
@api_controller("/project", auth=JWTAuth(), permissions=[IsAuthenticated], tags=['设计需求数据'])
|
@api_controller("/project", auth=JWTAuth(), permissions=[IsAuthenticated], tags=['设计需求数据'])
|
||||||
class DesignController(ControllerBase):
|
class DesignController(ControllerBase):
|
||||||
@route.get("/getDesignDemandList", response=List[DesignModelOutSchema], exclude_none=True, url_name="design-list")
|
@route.get("/getDesignDemandList", response=List[DesignModelOutSchema], exclude_none=True,
|
||||||
|
url_name="design-list")
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
@paginate(MyPagination)
|
@paginate(MyPagination)
|
||||||
def get_design_list(self, datafilter: DesignFilterSchema = Query(...)):
|
def get_design_list(self, datafilter: DesignFilterSchema = Query(...)):
|
||||||
conditionNoneToBlank(datafilter)
|
conditionNoneToBlank(datafilter)
|
||||||
dut_key = "".join([datafilter.round_id, '-', datafilter.dut_id])
|
query_params = {
|
||||||
qs = Design.objects.filter(project__id=datafilter.project_id, dut__key=dut_key,
|
'project__id': datafilter.project_id,
|
||||||
ident__icontains=datafilter.ident,
|
'ident__icontains': datafilter.ident,
|
||||||
name__icontains=datafilter.name,
|
'name__icontains': datafilter.name,
|
||||||
demandType__contains=datafilter.demandType,
|
'demandType__contains': datafilter.demandType,
|
||||||
chapter__icontains=datafilter.chapter).order_by('id')
|
'chapter__icontains': datafilter.chapter
|
||||||
|
}
|
||||||
|
# 判断是否传递dut_id,如果没传递则查询轮次全部
|
||||||
|
if datafilter.dut_id:
|
||||||
|
dut_key = f"{datafilter.round_id}-{datafilter.dut_id}"
|
||||||
|
query_params['dut__key'] = dut_key
|
||||||
|
else:
|
||||||
|
# 如果没有dut__key则要查询round__key
|
||||||
|
query_params['round__key'] = datafilter.round_id
|
||||||
|
qs = Design.objects.filter(**query_params).order_by('id')
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
@route.get("/getDesignOne", response=DesignModelOutSchema, url_name='design-one')
|
@route.get("/getDesignOne", response=DesignModelOutSchema, url_name='design-one')
|
||||||
@@ -39,6 +53,13 @@ class DesignController(ControllerBase):
|
|||||||
return design_qs
|
return design_qs
|
||||||
raise HttpError(500, "未找到相应的数据")
|
raise HttpError(500, "未找到相应的数据")
|
||||||
|
|
||||||
|
@route.get("/getDesignOneById", response=DesignModelOutSchema, url_name='design-one-by-id')
|
||||||
|
def get_one_by_id(self, id: int):
|
||||||
|
design_qs = Design.objects.filter(id=id).first()
|
||||||
|
if design_qs:
|
||||||
|
return design_qs
|
||||||
|
raise HttpError(500, "未找到相应的数据")
|
||||||
|
|
||||||
# 处理树状数据
|
# 处理树状数据
|
||||||
@route.get("/getDesignDemandInfo", response=List[DesignTreeReturnSchema], url_name="design-info")
|
@route.get("/getDesignDemandInfo", response=List[DesignTreeReturnSchema], url_name="design-info")
|
||||||
def get_design_tree(self, payload: DesignTreeInputSchema = Query(...)):
|
def get_design_tree(self, payload: DesignTreeInputSchema = Query(...)):
|
||||||
@@ -55,7 +76,8 @@ class DesignController(ControllerBase):
|
|||||||
# 构造dut_key
|
# 构造dut_key
|
||||||
dut_key = "".join([payload.round_key, "-", payload.dut_key])
|
dut_key = "".join([payload.round_key, "-", payload.dut_key])
|
||||||
# 判重标识-不需要再查询round以后的
|
# 判重标识-不需要再查询round以后的
|
||||||
if Design.objects.filter(project__id=payload.project_id, round__key=payload.round_key, dut__key=dut_key,
|
if Design.objects.filter(project__id=payload.project_id, round__key=payload.round_key,
|
||||||
|
dut__key=dut_key,
|
||||||
ident=payload.ident).exists() and asert_dict['ident'] != "":
|
ident=payload.ident).exists() and asert_dict['ident'] != "":
|
||||||
return ChenResponse(code=400, status=400, message='研制需求的标识重复,请检查')
|
return ChenResponse(code=400, status=400, message='研制需求的标识重复,请检查')
|
||||||
# 查询当前key应该为多少
|
# 查询当前key应该为多少
|
||||||
@@ -64,7 +86,8 @@ class DesignController(ControllerBase):
|
|||||||
# 查询当前的round_id
|
# 查询当前的round_id
|
||||||
round_instance = Round.objects.get(project__id=payload.project_id, key=payload.round_key)
|
round_instance = Round.objects.get(project__id=payload.project_id, key=payload.round_key)
|
||||||
dut_instance = Dut.objects.get(project__id=payload.project_id, key=dut_key)
|
dut_instance = Dut.objects.get(project__id=payload.project_id, key=dut_key)
|
||||||
asert_dict.update({'key': key_string, 'round': round_instance, 'dut': dut_instance, 'title': payload.name})
|
asert_dict.update(
|
||||||
|
{'key': key_string, 'round': round_instance, 'dut': dut_instance, 'title': payload.name})
|
||||||
asert_dict.pop("round_key")
|
asert_dict.pop("round_key")
|
||||||
asert_dict.pop("dut_key")
|
asert_dict.pop("dut_key")
|
||||||
qs = Design.objects.create(**asert_dict)
|
qs = Design.objects.create(**asert_dict)
|
||||||
@@ -156,3 +179,20 @@ class DesignController(ControllerBase):
|
|||||||
round_dict['children'].append(dut_dict)
|
round_dict['children'].append(dut_dict)
|
||||||
data_list.append(round_dict)
|
data_list.append(round_dict)
|
||||||
return ChenResponse(message='获取成功', data=data_list)
|
return ChenResponse(message='获取成功', data=data_list)
|
||||||
|
|
||||||
|
# 设计需求-替换接口
|
||||||
|
@route.post("/designDemand/replace/", url_name='design-replace')
|
||||||
|
@transaction.atomic
|
||||||
|
def replace_content(self, payload: ReplaceDesignContentSchema):
|
||||||
|
# 1.首先查询项目
|
||||||
|
project_obj: Project = get_object_or_404(Project, id=payload.project_id)
|
||||||
|
# 2.查询[所有轮次]的selectRows的id
|
||||||
|
design_qs = project_obj.psField.filter(id__in=payload.selectRows, round__key=payload.round_key)
|
||||||
|
# 3.批量替换里面文本
|
||||||
|
replace_kwargs = {
|
||||||
|
field_name: Replace(F(field_name), Value(payload.originText), Value(payload.replaceText))
|
||||||
|
for field_name in payload.selectColumn
|
||||||
|
}
|
||||||
|
# 4.提交更新
|
||||||
|
replace_count = design_qs.update(**replace_kwargs)
|
||||||
|
return {'count': replace_count}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class DutController(ControllerBase):
|
|||||||
qs = Dut.objects.filter(project__id=payload.project_id, round__key=payload.key)
|
qs = Dut.objects.filter(project__id=payload.project_id, round__key=payload.key)
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
# 获取单个dut
|
# 获取单个dut-根据项目id和dut.key
|
||||||
@route.get("/getDutOne", response=DutModelOutSchema, url_name="dut-one")
|
@route.get("/getDutOne", response=DutModelOutSchema, url_name="dut-one")
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def get_dut(self, project_id: int, key: str):
|
def get_dut(self, project_id: int, key: str):
|
||||||
@@ -51,6 +51,13 @@ class DutController(ControllerBase):
|
|||||||
return dut_qs
|
return dut_qs
|
||||||
raise HttpError(500, "未找到相应的数据")
|
raise HttpError(500, "未找到相应的数据")
|
||||||
|
|
||||||
|
@route.get("/getDutOneById", response=DutModelOutSchema, url_name='dut-one-by-id')
|
||||||
|
def get_one_by_id(self, id: int):
|
||||||
|
dut_qs = Dut.objects.filter(id=id).first()
|
||||||
|
if dut_qs:
|
||||||
|
return dut_qs
|
||||||
|
raise HttpError(500, "未找到相应的数据")
|
||||||
|
|
||||||
# 添加被测件
|
# 添加被测件
|
||||||
@route.post("/dut/save", url_name="dut-create", response=DutCreateOutSchema)
|
@route.post("/dut/save", url_name="dut-create", response=DutCreateOutSchema)
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ from ninja.pagination import paginate
|
|||||||
from ninja.errors import HttpError
|
from ninja.errors import HttpError
|
||||||
from utils.chen_pagination import MyPagination
|
from utils.chen_pagination import MyPagination
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
from django.db.models.functions import Replace
|
||||||
|
from django.db.models import Q, F, Value
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from typing import List
|
from typing import List
|
||||||
from utils.chen_response import ChenResponse
|
from utils.chen_response import ChenResponse
|
||||||
@@ -13,7 +15,8 @@ from utils.chen_crud import multi_delete_testDemand
|
|||||||
from utils.codes import HTTP_INDEX_ERROR
|
from utils.codes import HTTP_INDEX_ERROR
|
||||||
from apps.project.models import Design, Dut, Round, TestDemand, TestDemandContent, TestDemandContentStep
|
from apps.project.models import Design, Dut, Round, TestDemand, TestDemandContent, TestDemandContentStep
|
||||||
from apps.project.schemas.testDemand import DeleteSchema, TestDemandModelOutSchema, TestDemandFilterSchema, \
|
from apps.project.schemas.testDemand import DeleteSchema, TestDemandModelOutSchema, TestDemandFilterSchema, \
|
||||||
TestDemandTreeReturnSchema, TestDemandTreeInputSchema, TestDemandCreateOutSchema, TestDemandCreateInputSchema, \
|
TestDemandTreeReturnSchema, TestDemandTreeInputSchema, TestDemandCreateOutSchema, \
|
||||||
|
TestDemandCreateInputSchema, ReplaceDemandContentSchema, \
|
||||||
TestDemandRelatedSchema, TestDemandExistRelatedSchema, DemandCopyToDesignSchema
|
TestDemandRelatedSchema, TestDemandExistRelatedSchema, DemandCopyToDesignSchema
|
||||||
# 导入ORM
|
# 导入ORM
|
||||||
from apps.project.models import Project
|
from apps.project.models import Project
|
||||||
@@ -30,12 +33,29 @@ class TestDemandController(ControllerBase):
|
|||||||
@paginate(MyPagination)
|
@paginate(MyPagination)
|
||||||
def get_test_demand_list(self, datafilter: TestDemandFilterSchema = Query(...)):
|
def get_test_demand_list(self, datafilter: TestDemandFilterSchema = Query(...)):
|
||||||
conditionNoneToBlank(datafilter)
|
conditionNoneToBlank(datafilter)
|
||||||
|
query_params = {
|
||||||
|
'project__id': datafilter.project_id,
|
||||||
|
'ident__icontains': datafilter.ident,
|
||||||
|
'name__icontains': datafilter.name,
|
||||||
|
'testType__contains': datafilter.testType,
|
||||||
|
'priority__icontains': datafilter.priority
|
||||||
|
}
|
||||||
|
# 如果没有传递多个key则认为是“那个轮次汇总界面”
|
||||||
|
if datafilter.dut_id and datafilter.design_id:
|
||||||
design_key = "".join([datafilter.round_id, '-', datafilter.dut_id, '-', datafilter.design_id])
|
design_key = "".join([datafilter.round_id, '-', datafilter.dut_id, '-', datafilter.design_id])
|
||||||
qs = TestDemand.objects.filter(project__id=datafilter.project_id, design__key=design_key,
|
query_params['design__key'] = design_key
|
||||||
ident__icontains=datafilter.ident,
|
else:
|
||||||
name__icontains=datafilter.name,
|
# 轮次汇总界面要查round__key
|
||||||
testType__contains=datafilter.testType,
|
query_params['round__key'] = datafilter.round_id
|
||||||
priority__icontains=datafilter.priority).order_by("key")
|
# 判断是否存在testDesciption有则表示是大表查询
|
||||||
|
if datafilter.testDesciption:
|
||||||
|
query_params['testDesciption__icontains'] = datafilter.testDesciption
|
||||||
|
qs = TestDemand.objects.filter(**query_params).order_by("key")
|
||||||
|
# 判断是否存在testContent有则表示是大表查询,这里需要查询子字段
|
||||||
|
if datafilter.testContent:
|
||||||
|
qs = qs.filter(Q(testQField__subName__icontains=datafilter.testContent) |
|
||||||
|
Q(testQField__testStepField__operation__icontains=datafilter.testContent) |
|
||||||
|
Q(testQField__testStepField__expect__icontains=datafilter.testContent))
|
||||||
# 由于有嵌套query_set存在,把每个测试需求的schema加上一个字段
|
# 由于有嵌套query_set存在,把每个测试需求的schema加上一个字段
|
||||||
query_list = []
|
query_list = []
|
||||||
for query_single in qs:
|
for query_single in qs:
|
||||||
@@ -61,6 +81,20 @@ class TestDemandController(ControllerBase):
|
|||||||
return demand_qs
|
return demand_qs
|
||||||
raise HttpError(500, "未找到相应的数据")
|
raise HttpError(500, "未找到相应的数据")
|
||||||
|
|
||||||
|
# 根据id直接查询
|
||||||
|
@route.get("/getTestDemandOneById", response=TestDemandModelOutSchema, url_name='testDemand-one-by-id')
|
||||||
|
@transaction.atomic
|
||||||
|
def get_demand_by_id(self, id: int):
|
||||||
|
demand_qs = TestDemand.objects.filter(id=id).first()
|
||||||
|
if demand_qs:
|
||||||
|
sub_list = []
|
||||||
|
for step_obj in demand_qs.testQField.all():
|
||||||
|
setattr(step_obj, "subStep", step_obj.testStepField.all().values())
|
||||||
|
sub_list.append(step_obj)
|
||||||
|
setattr(demand_qs, "testContent", sub_list)
|
||||||
|
return demand_qs
|
||||||
|
raise HttpError(500, "未找到相应的数据")
|
||||||
|
|
||||||
# 处理树状数据
|
# 处理树状数据
|
||||||
@route.get("/getTestdemandInfo", response=List[TestDemandTreeReturnSchema], url_name="testDemand-info")
|
@route.get("/getTestdemandInfo", response=List[TestDemandTreeReturnSchema], url_name="testDemand-info")
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
@@ -78,11 +112,13 @@ class TestDemandController(ControllerBase):
|
|||||||
if payload.ident and project_qs:
|
if payload.ident and project_qs:
|
||||||
exists = project_qs.ptField.filter(ident=payload.ident).exists()
|
exists = project_qs.ptField.filter(ident=payload.ident).exists()
|
||||||
if exists:
|
if exists:
|
||||||
return ChenResponse(code=500, status=500, message='测试项标识和其他测试项重复,请更换测试项标识!!!')
|
return ChenResponse(code=500, status=500,
|
||||||
|
message='测试项标识和其他测试项重复,请更换测试项标识!!!')
|
||||||
# 构造design_key
|
# 构造design_key
|
||||||
design_key = "".join([payload.round_key, "-", payload.dut_key, '-', payload.design_key])
|
design_key = "".join([payload.round_key, "-", payload.dut_key, '-', payload.design_key])
|
||||||
# 查询当前key应该为多少
|
# 查询当前key应该为多少
|
||||||
test_demand_count = TestDemand.objects.filter(project__id=payload.project_id, design__key=design_key).count()
|
test_demand_count = TestDemand.objects.filter(project__id=payload.project_id,
|
||||||
|
design__key=design_key).count()
|
||||||
key_string = ''.join([design_key, "-", str(test_demand_count)])
|
key_string = ''.join([design_key, "-", str(test_demand_count)])
|
||||||
# 查询当前各个前面节点的instance
|
# 查询当前各个前面节点的instance
|
||||||
round_instance = Round.objects.get(project__id=payload.project_id, key=payload.round_key)
|
round_instance = Round.objects.get(project__id=payload.project_id, key=payload.round_key)
|
||||||
@@ -90,7 +126,8 @@ class TestDemandController(ControllerBase):
|
|||||||
key="".join([payload.round_key, "-", payload.dut_key]))
|
key="".join([payload.round_key, "-", payload.dut_key]))
|
||||||
design_instance = Design.objects.get(project__id=payload.project_id, key="".join(
|
design_instance = Design.objects.get(project__id=payload.project_id, key="".join(
|
||||||
[payload.round_key, "-", payload.dut_key, '-', payload.design_key]))
|
[payload.round_key, "-", payload.dut_key, '-', payload.design_key]))
|
||||||
asert_dict.update({'key': key_string, 'round': round_instance, 'dut': dut_instance, 'design': design_instance,
|
asert_dict.update(
|
||||||
|
{'key': key_string, 'round': round_instance, 'dut': dut_instance, 'design': design_instance,
|
||||||
'title': payload.name})
|
'title': payload.name})
|
||||||
asert_dict.pop("round_key")
|
asert_dict.pop("round_key")
|
||||||
asert_dict.pop("dut_key")
|
asert_dict.pop("dut_key")
|
||||||
@@ -153,11 +190,13 @@ class TestDemandController(ControllerBase):
|
|||||||
)
|
)
|
||||||
for step in item["subStep"]
|
for step in item["subStep"]
|
||||||
])
|
])
|
||||||
|
setattr(testDemand_qs, attr, value)
|
||||||
# ~~~2024年5月9日:测试项更新标识后还要更新下面用例的标识~~~
|
# ~~~2024年5月9日:测试项更新标识后还要更新下面用例的标识~~~
|
||||||
if testDemand_qs.ident != old_ident:
|
if testDemand_qs.ident != old_ident:
|
||||||
for case in testDemand_qs.tcField.all():
|
for case in testDemand_qs.tcField.all():
|
||||||
case.ident = testDemand_qs.ident
|
case.ident = testDemand_qs.ident
|
||||||
case.save()
|
case.save()
|
||||||
|
testDemand_qs.save()
|
||||||
return testDemand_qs
|
return testDemand_qs
|
||||||
|
|
||||||
# 删除测试项
|
# 删除测试项
|
||||||
@@ -215,7 +254,8 @@ class TestDemandController(ControllerBase):
|
|||||||
if ti.pk == test_id:
|
if ti.pk == test_id:
|
||||||
non_exist_ids.remove(test_id)
|
non_exist_ids.remove(test_id)
|
||||||
if len(non_exist_ids) <= 0 < len(test_item_ids):
|
if len(non_exist_ids) <= 0 < len(test_item_ids):
|
||||||
return ChenResponse(status=400, code=200, message='选择的测试项全部存在于当前设计需求中,请重新选择...')
|
return ChenResponse(status=400, code=200,
|
||||||
|
message='选择的测试项全部存在于当前设计需求中,请重新选择...')
|
||||||
# 先查询现在有的关联测试项
|
# 先查询现在有的关联测试项
|
||||||
for item in design_item.odField.values('id'):
|
for item in design_item.odField.values('id'):
|
||||||
item_id = item.get('id', None)
|
item_id = item.get('id', None)
|
||||||
@@ -251,3 +291,32 @@ class TestDemandController(ControllerBase):
|
|||||||
"""前端测试项右键复制到某个设计需求下面"""
|
"""前端测试项右键复制到某个设计需求下面"""
|
||||||
new_demand_key = demand_copy_to_design(data.project_id, data.demand_key, data.design_id, data.depth)
|
new_demand_key = demand_copy_to_design(data.project_id, data.demand_key, data.design_id, data.depth)
|
||||||
return ChenResponse(data={'key': new_demand_key})
|
return ChenResponse(data={'key': new_demand_key})
|
||||||
|
|
||||||
|
# 测试项-替换接口
|
||||||
|
@route.post("/testDemand/replace/", url_name='testDemand-replace')
|
||||||
|
@transaction.atomic
|
||||||
|
def replace_demand_content(self, payload: ReplaceDemandContentSchema):
|
||||||
|
# 1.首先查询项目
|
||||||
|
project_obj: Project = get_object_or_404(Project, id=payload.project_id)
|
||||||
|
# 2.查询[所有轮次]的selectRows的id
|
||||||
|
demand_qs = project_obj.ptField.filter(id__in=payload.selectRows, round__key=payload.round_key)
|
||||||
|
# 3.批量替换里面文本(解构不影响老数组)
|
||||||
|
selectColumn = [x for x in payload.selectColumn if x != 'testContent']
|
||||||
|
replace_kwargs = {
|
||||||
|
field_name: Replace(F(field_name), Value(payload.originText), Value(payload.replaceText))
|
||||||
|
for field_name in selectColumn
|
||||||
|
}
|
||||||
|
# 4.单独处理testContentStep的操作、预期-查询所有
|
||||||
|
# 4.1.获取所有关联的TestDemandContentStep
|
||||||
|
step_count = 0
|
||||||
|
if 'testContent' in payload.selectColumn:
|
||||||
|
test_demand_contents = TestDemandContent.objects.filter(testDemand__in=demand_qs)
|
||||||
|
test_steps = TestDemandContentStep.objects.filter(testDemandContent__in=test_demand_contents)
|
||||||
|
# 批量更新 operation 和 expect
|
||||||
|
step_count = test_steps.update(
|
||||||
|
operation=Replace(F('operation'), Value(payload.originText), Value(payload.replaceText)),
|
||||||
|
expect=Replace(F('expect'), Value(payload.originText), Value(payload.replaceText))
|
||||||
|
)
|
||||||
|
# 5.提交更新
|
||||||
|
replace_count = demand_qs.update(**replace_kwargs)
|
||||||
|
return {'count': replace_count + step_count}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -5,6 +5,7 @@ from typing import List, Union, Optional
|
|||||||
from datetime import date
|
from datetime import date
|
||||||
# 关联问题单
|
# 关联问题单
|
||||||
from apps.project.schemas.problem import ProblemModelOutSchema
|
from apps.project.schemas.problem import ProblemModelOutSchema
|
||||||
|
from apps.project.schemas.testDemand import TestDemandModelOutSchemaOrigin
|
||||||
|
|
||||||
# 删除schema
|
# 删除schema
|
||||||
class DeleteSchema(Schema):
|
class DeleteSchema(Schema):
|
||||||
@@ -31,12 +32,25 @@ class CaseModelOutSchemaWithoutProblem(ModelSchema):
|
|||||||
model = Case
|
model = Case
|
||||||
model_exclude = ['project', 'round', 'dut', 'design', 'test', 'remark', 'sort']
|
model_exclude = ['project', 'round', 'dut', 'design', 'test', 'remark', 'sort']
|
||||||
|
|
||||||
|
# 输出case:关联问题单
|
||||||
|
class CaseModelOutSchemaOrigin(ModelSchema):
|
||||||
|
testStep: List[CaseStepSchema]
|
||||||
|
testType: str # 用例额外字段,用于测试类型FT的标识给前端
|
||||||
|
# 新增:关联的问题单
|
||||||
|
problem: Optional[ProblemModelOutSchema] = None
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
model = Case
|
||||||
|
model_exclude = ['project', 'round', 'dut', 'design', 'test', 'remark', 'sort']
|
||||||
|
|
||||||
# 输出case:关联问题单
|
# 输出case:关联问题单
|
||||||
class CaseModelOutSchema(ModelSchema):
|
class CaseModelOutSchema(ModelSchema):
|
||||||
testStep: List[CaseStepSchema]
|
testStep: List[CaseStepSchema]
|
||||||
testType: str # 用例额外字段,用于测试类型FT的标识给前端
|
testType: str # 用例额外字段,用于测试类型FT的标识给前端
|
||||||
# 新增:关联的问题单
|
# 新增:关联的问题单
|
||||||
problem: Optional[ProblemModelOutSchema] = None
|
problem: Optional[ProblemModelOutSchema] = None
|
||||||
|
# 2025年5月10日新增上级字段
|
||||||
|
test: Optional[TestDemandModelOutSchemaOrigin] = None
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
model = Case
|
model = Case
|
||||||
@@ -119,3 +133,24 @@ class DemandNodeSchema(Schema):
|
|||||||
isLeaf: bool = False
|
isLeaf: bool = False
|
||||||
key: str = Field(None, alias='nodekey')
|
key: str = Field(None, alias='nodekey')
|
||||||
title: str = Field(None)
|
title: str = Field(None)
|
||||||
|
|
||||||
|
# 替换文本输入Schema
|
||||||
|
class ReplaceCaseSchema(Schema):
|
||||||
|
project_id: int
|
||||||
|
round_key: str
|
||||||
|
originText: str
|
||||||
|
replaceText: str
|
||||||
|
selectRows: List[int]
|
||||||
|
selectColumn: List[str]
|
||||||
|
|
||||||
|
# 人员替换Schema
|
||||||
|
class PersonReplaceSchema(Schema):
|
||||||
|
selectRows: List[int] = None
|
||||||
|
designPerson: str
|
||||||
|
testPerson: str
|
||||||
|
monitorPerson: str
|
||||||
|
|
||||||
|
# 事件替换Schema
|
||||||
|
class ExetimeReplaceSchema(Schema):
|
||||||
|
selectRows: List[int] = None
|
||||||
|
exetime: str
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
|
from typing import Optional
|
||||||
from apps.project.models import Design
|
from apps.project.models import Design
|
||||||
from ninja import Field, Schema, ModelSchema
|
from ninja import Field, Schema, ModelSchema
|
||||||
from typing import List, Union
|
from typing import List, Union
|
||||||
from pydantic import AliasChoices
|
from pydantic import AliasChoices
|
||||||
|
# 上级dut-schema
|
||||||
|
from apps.project.schemas.dut import DutModelOutSchema
|
||||||
|
|
||||||
# 删除schema
|
# 删除schema
|
||||||
class DeleteSchema(Schema):
|
class DeleteSchema(Schema):
|
||||||
@@ -18,7 +21,16 @@ class DesignFilterSchema(Schema):
|
|||||||
# 新增字段 - chapter
|
# 新增字段 - chapter
|
||||||
chapter: str = Field(None, alias='chapter')
|
chapter: str = Field(None, alias='chapter')
|
||||||
|
|
||||||
|
# 2025年改为2个输出,因为下级需要上级,原始不再嵌套上级
|
||||||
|
class DesignModelOutSchemaOrigin(ModelSchema):
|
||||||
|
class Config:
|
||||||
|
model = Design
|
||||||
|
model_exclude = ['project', 'round', 'dut', 'remark', 'sort']
|
||||||
|
|
||||||
class DesignModelOutSchema(ModelSchema):
|
class DesignModelOutSchema(ModelSchema):
|
||||||
|
# 新增字段 - 上级的dut对象
|
||||||
|
dut: Optional[DutModelOutSchema] = None
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
model = Design
|
model = Design
|
||||||
model_exclude = ['project', 'round', 'dut', 'remark', 'sort']
|
model_exclude = ['project', 'round', 'dut', 'remark', 'sort']
|
||||||
@@ -72,3 +84,12 @@ class MultiDesignCreateInputSchema(Schema):
|
|||||||
project_id: int = Field(..., alias="projectId")
|
project_id: int = Field(..., alias="projectId")
|
||||||
dut_key: str = Field(..., alias="key")
|
dut_key: str = Field(..., alias="key")
|
||||||
data: List[SingleDesignSchema]
|
data: List[SingleDesignSchema]
|
||||||
|
|
||||||
|
# 批量替换design的接口Schema
|
||||||
|
class ReplaceDesignContentSchema(Schema):
|
||||||
|
project_id: int
|
||||||
|
round_key: str
|
||||||
|
originText: str
|
||||||
|
replaceText: str
|
||||||
|
selectRows: List[int]
|
||||||
|
selectColumn: List[str]
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from apps.project.models import TestDemand, TestDemandContent, TestDemandContentStep
|
from apps.project.models import TestDemand, TestDemandContent, TestDemandContentStep
|
||||||
|
from apps.project.schemas.design import DesignModelOutSchemaOrigin # 注意导入的是不含上级的Schema
|
||||||
from ninja import Field, Schema, ModelSchema
|
from ninja import Field, Schema, ModelSchema
|
||||||
from typing import List, Union, Optional
|
from typing import List, Union, Optional
|
||||||
from pydantic import AliasChoices
|
from pydantic import AliasChoices
|
||||||
@@ -20,8 +21,18 @@ class TestContentSchema(ModelSchema):
|
|||||||
model = TestDemandContent
|
model = TestDemandContent
|
||||||
fields = ["subName"]
|
fields = ["subName"]
|
||||||
|
|
||||||
|
# 2025年修改为两个,一个含上级一个不含
|
||||||
|
class TestDemandModelOutSchemaOrigin(ModelSchema):
|
||||||
|
testContent: List[TestContentSchema] # 下级对象
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = TestDemand
|
||||||
|
exclude = ['project', 'round', 'dut', 'design', 'remark', 'sort']
|
||||||
|
|
||||||
class TestDemandModelOutSchema(ModelSchema):
|
class TestDemandModelOutSchema(ModelSchema):
|
||||||
testContent: List[TestContentSchema]
|
testContent: List[TestContentSchema] # 下级对象
|
||||||
|
# 2025年5月9日新增上级字段design
|
||||||
|
design: Optional[DesignModelOutSchemaOrigin] = None
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TestDemand
|
model = TestDemand
|
||||||
@@ -38,6 +49,9 @@ class TestDemandFilterSchema(Schema):
|
|||||||
testType: str = Field(None, alias='testType')
|
testType: str = Field(None, alias='testType')
|
||||||
name: str = Field(None, alias='name')
|
name: str = Field(None, alias='name')
|
||||||
priority: str = Field(None, alias="priority")
|
priority: str = Field(None, alias="priority")
|
||||||
|
# 新增查询字段,给大表的查询
|
||||||
|
testDesciption: str = Field(None, alias="testDesciption")
|
||||||
|
testContent: str = Field(None, alias="testContent")
|
||||||
|
|
||||||
# 处理树状结构的schema
|
# 处理树状结构的schema
|
||||||
class TestDemandTreeReturnSchema(Schema):
|
class TestDemandTreeReturnSchema(Schema):
|
||||||
@@ -102,3 +116,12 @@ class DemandCopyToDesignSchema(Schema):
|
|||||||
design_id: int
|
design_id: int
|
||||||
demand_key: str
|
demand_key: str
|
||||||
depth: bool = False
|
depth: bool = False
|
||||||
|
|
||||||
|
# 替换文本输入Schema
|
||||||
|
class ReplaceDemandContentSchema(Schema):
|
||||||
|
project_id: int
|
||||||
|
round_key: str
|
||||||
|
originText: str
|
||||||
|
replaceText: str
|
||||||
|
selectRows: List[int]
|
||||||
|
selectColumn: List[str]
|
||||||
|
|||||||
2595
logs/root_log
2595
logs/root_log
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user