日常修复内容20260422
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -15,7 +15,7 @@ from pathlib import Path
|
||||
from utils.chen_response import ChenResponse
|
||||
# 导入数据库ORM
|
||||
from apps.project.models import Project, Contact, Abbreviation, ProjectSoftSummary, StuctSortData, StaticSoftItem, StaticSoftHardware, \
|
||||
DynamicSoftTable, DynamicHardwareTable, ProjectDynamicDescription, EvaluateData, EnvAnalysis
|
||||
DynamicSoftTable, DynamicHardwareTable, ProjectDynamicDescription, EvaluateData, EnvAnalysis, Design
|
||||
from apps.dict.models import Dict
|
||||
# 导入工具函数
|
||||
from utils.util import get_str_dict, get_list_dict, get_testType, get_ident, get_str_abbr
|
||||
@@ -91,12 +91,23 @@ class GenerateControllerDG(ControllerBase, FragementToolsMixin):
|
||||
html_parser = RichParser(single_qs.design.description)
|
||||
desc_list = html_parser.get_final_list(doc)
|
||||
# 查询关联design以及普通design
|
||||
doc_list = [{'dut_name': single_qs.dut.name, 'design_chapter': single_qs.design.chapter,
|
||||
'design_name': single_qs.design.name}]
|
||||
for relate_design in single_qs.otherDesign.all():
|
||||
ddict = {'dut_name': relate_design.dut.name, 'design_chapter': relate_design.chapter,
|
||||
'design_name': relate_design.name}
|
||||
doc_list = [{
|
||||
'dut_name': single_qs.dut.name,
|
||||
'design_chapter': single_qs.design.chapter,
|
||||
'design_name': single_qs.design.name,
|
||||
'dut_type': single_qs.dut.type # 添加 type 字段用于排序
|
||||
}]
|
||||
for relate_design in single_qs.otherDesign.all(): # type: Design
|
||||
ddict = {
|
||||
'dut_name': relate_design.dut.name,
|
||||
'design_chapter': relate_design.chapter,
|
||||
'design_name': relate_design.name,
|
||||
'dut_type': relate_design.dut.type # 添加 type 字段用于排序
|
||||
}
|
||||
doc_list.append(ddict)
|
||||
# 定义排序顺序映射
|
||||
TYPE_ORDER = {'YZ': 0, 'XQ': 1, 'XY': 2, 'SJ': 3, None: 99, '': 999}
|
||||
doc_list.sort(key=lambda x: TYPE_ORDER.get(x.get('dut_type'), 999))
|
||||
|
||||
# 组装单个测试项
|
||||
## 打印本项目是FPGA还是CPU
|
||||
@@ -403,10 +414,13 @@ class GenerateControllerDG(ControllerBase, FragementToolsMixin):
|
||||
interface_dict = {
|
||||
'name': interface.name,
|
||||
'ident': interface.ident,
|
||||
'source': interface.source,
|
||||
'to': interface.to,
|
||||
'type': interface.type,
|
||||
'protocal': interface.protocal,
|
||||
'is_bidirectional': interface.is_bidirectional, # 是否有反向
|
||||
'jk_info_list': [{
|
||||
'source': item.source,
|
||||
'destination': item.destination,
|
||||
'description': item.description,
|
||||
} for item in interface.jkField.all()]
|
||||
}
|
||||
interface_list.append(interface_dict)
|
||||
# 项目接口图处理 - 2026/2/4
|
||||
@@ -423,7 +437,7 @@ class GenerateControllerDG(ControllerBase, FragementToolsMixin):
|
||||
'iters': interfaceNameList,
|
||||
'iter_list': interface_list,
|
||||
'image_render': image_render if image_render else "",
|
||||
'fontnote': fontnote if fontnote else "".join([project_name, '接口示意图'])
|
||||
'fontnote': fontnote if fontnote else "".join([project_name, '接口示意图']),
|
||||
}
|
||||
doc.render(context, autoescape=True)
|
||||
try:
|
||||
@@ -469,7 +483,7 @@ class GenerateControllerDG(ControllerBase, FragementToolsMixin):
|
||||
except PermissionError as e:
|
||||
return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e))
|
||||
|
||||
# 通用生成静态软件项、静态硬件项、动态软件项、动态硬件信息的context,包含fontnote和table
|
||||
# 通用生成静态软件项、静态硬件项、动态软件项、动态硬件信息、测评数据的context,包含fontnote和table
|
||||
@classmethod
|
||||
def create_table_context(cls, table_data: list[list[str]], doc: DocxTemplate):
|
||||
"""注意:该函数会增加一列序号列,并且支持单元格内回车换行(段落换行)"""
|
||||
|
||||
@@ -8,7 +8,7 @@ from django.db.models import QuerySet, Q
|
||||
from docxtpl import DocxTemplate
|
||||
from docx import Document
|
||||
# 导入模型
|
||||
from apps.project.models import Project, Round, Dut, InfluenceArea
|
||||
from apps.project.models import Project, Round, Dut
|
||||
from apps.dict.models import Dict
|
||||
# 导入项目工具
|
||||
from utils.util import get_list_dict, get_str_dict, get_ident, get_case_ident, get_testType
|
||||
@@ -19,7 +19,6 @@ from utils.path_utils import project_path
|
||||
from apps.createDocument.extensions.util import delete_dir_files
|
||||
from apps.createDocument.extensions.parse_rich_text import RichParser
|
||||
from apps.createDocument.extensions.documentTime import DocTime
|
||||
from utils.util import get_str_abbr
|
||||
from apps.createDocument.extensions.content_result_tool import create_influence_context
|
||||
# 导入生成日志记录模块
|
||||
from apps.createSeiTaiDocument.extensions.logger import GenerateLogger
|
||||
@@ -234,7 +233,7 @@ class GenerateControllerHSM(ControllerBase):
|
||||
xq_dut: Dut = hround.rdField.filter(type='XQ').first()
|
||||
# 处理代码版本
|
||||
last_round_key = str(int(hround.key) - 1)
|
||||
last_round: Round = project_obj.pField.filter(key=last_round_key).first()
|
||||
last_round: Round | None = project_obj.pField.filter(key=last_round_key).first()
|
||||
last_round_so_dut = last_round.rdField.filter(type='SO').first()
|
||||
if not last_round_so_dut:
|
||||
return ChenResponse(code=400, status=400,
|
||||
|
||||
Binary file not shown.
@@ -1,98 +1,109 @@
|
||||
from pathlib import Path
|
||||
from docxtpl import DocxTemplate
|
||||
from docx.table import Table
|
||||
from utils.chen_response import ChenResponse
|
||||
from typing import Any
|
||||
from apps.project.models import Project
|
||||
from utils.path_utils import project_path
|
||||
|
||||
def merge_all_cell(table: Table) -> None:
|
||||
"""生成需求研总对照表工具:逐个找第二列和第三列单元格的text,如果一致则合并"""
|
||||
col_list = [table.columns[1], table.columns[2]]
|
||||
# 合并第二列相同的单元格
|
||||
for col_right in col_list:
|
||||
index = 0
|
||||
temp_text = ""
|
||||
for cell in col_right.cells:
|
||||
if index == 0:
|
||||
temp_text = cell.text
|
||||
else:
|
||||
if cell.text == temp_text:
|
||||
if cell.text == '': # 不知道什么原因必须这样判断下
|
||||
cell.text = '/'
|
||||
text_temp = cell.text
|
||||
ce = cell.merge(col_right.cells[index - 1])
|
||||
ce.text = text_temp
|
||||
else:
|
||||
temp_text = cell.text
|
||||
index += 1
|
||||
|
||||
def create_sm_docx(template_name: str, context: dict, id: int) -> ChenResponse:
|
||||
"""生成最终说明文档工具函数"""
|
||||
input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'sm' / template_name
|
||||
doc = DocxTemplate(input_path)
|
||||
doc.render(context, autoescape=True)
|
||||
try:
|
||||
doc.save(Path.cwd() / "media" / project_path(id) / "output_dir/sm" / template_name)
|
||||
return ChenResponse(status=200, code=200, message="文档生成成功!")
|
||||
except PermissionError as e:
|
||||
return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e))
|
||||
|
||||
def create_dg_docx(template_name: str, context: dict, id: int) -> ChenResponse:
|
||||
"""生成最终大纲文档工具函数"""
|
||||
input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'dg' / template_name
|
||||
doc = DocxTemplate(input_path)
|
||||
doc.render(context, autoescape=True)
|
||||
try:
|
||||
doc.save(Path.cwd() / "media" / project_path(id) / "output_dir" / template_name)
|
||||
return ChenResponse(status=200, code=200, message="文档生成成功!")
|
||||
except PermissionError as e:
|
||||
return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e))
|
||||
|
||||
def create_bg_docx(template_name: str, context: dict, id: int) -> ChenResponse:
|
||||
"""生成最终报告文档工具函数"""
|
||||
input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'bg' / template_name
|
||||
doc = DocxTemplate(input_path)
|
||||
doc.render(context, autoescape=True)
|
||||
try:
|
||||
doc.save(Path.cwd() / "media" / project_path(id) / "output_dir/bg" / template_name)
|
||||
return ChenResponse(status=200, code=200, message="文档生成成功!")
|
||||
except PermissionError as e:
|
||||
return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e))
|
||||
|
||||
def create_wtd_docx(template_name: str, context: dict, id: int) -> ChenResponse:
|
||||
"""生成最终问题单文档工具函数"""
|
||||
input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'wtd' / template_name
|
||||
doc = DocxTemplate(input_path)
|
||||
doc.render(context, autoescape=True)
|
||||
try:
|
||||
doc.save(Path.cwd() / "media" / project_path(id) / "output_dir/wtd" / template_name)
|
||||
return ChenResponse(status=200, code=200, message="文档生成成功!")
|
||||
except PermissionError as e:
|
||||
return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e))
|
||||
|
||||
def get_round1_problem(project: Project) -> Any:
|
||||
"""
|
||||
从项目返回第一轮问题单
|
||||
:param project: Project项目Model对象
|
||||
:return: 问题单的列表
|
||||
"""
|
||||
all_problem_qs = project.projField.all()
|
||||
# 遍历每个问题,找出第一轮的问题
|
||||
problem_set = set()
|
||||
for problem in all_problem_qs:
|
||||
flag = False
|
||||
for case in problem.case.all():
|
||||
if case.round.key == '0':
|
||||
flag = True
|
||||
if flag:
|
||||
problem_set.add(problem)
|
||||
return list(problem_set)
|
||||
|
||||
def delete_dir_files(path: Path) -> Any:
|
||||
"""传入一个Path对象,如果是文件夹则删除里面所有的文件(不删除文件夹)"""
|
||||
if path.is_dir():
|
||||
for file in path.iterdir():
|
||||
if file.is_file():
|
||||
file.unlink()
|
||||
|
||||
from pathlib import Path
|
||||
from docxtpl import DocxTemplate
|
||||
from docx.table import Table
|
||||
from utils.chen_response import ChenResponse
|
||||
from typing import Any
|
||||
from apps.project.models import Project
|
||||
from utils.path_utils import project_path
|
||||
|
||||
def merge_all_cell(table: Table) -> None:
|
||||
"""生成需求研总对照表工具:逐个找第二列和第三列单元格的text,如果一致则合并"""
|
||||
col_list = [table.columns[1], table.columns[2]]
|
||||
# 合并第二列相同的单元格
|
||||
for col_right in col_list:
|
||||
index = 0
|
||||
temp_text = ""
|
||||
for cell in col_right.cells:
|
||||
if index == 0:
|
||||
temp_text = cell.text
|
||||
else:
|
||||
if cell.text == temp_text:
|
||||
if cell.text == '': # 不知道什么原因必须这样判断下
|
||||
cell.text = '/'
|
||||
text_temp = cell.text
|
||||
ce = cell.merge(col_right.cells[index - 1])
|
||||
ce.text = text_temp
|
||||
else:
|
||||
temp_text = cell.text
|
||||
index += 1
|
||||
|
||||
def create_sm_docx(template_name: str, context: dict, id: int) -> ChenResponse:
|
||||
"""生成最终说明文档工具函数"""
|
||||
input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'sm' / template_name
|
||||
doc = DocxTemplate(input_path)
|
||||
doc.render(context, autoescape=True)
|
||||
try:
|
||||
doc.save(Path.cwd() / "media" / project_path(id) / "output_dir/sm" / template_name)
|
||||
return ChenResponse(status=200, code=200, message="文档生成成功!")
|
||||
except PermissionError as e:
|
||||
return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e))
|
||||
|
||||
def create_hsm_docx(template_name: str, context: dict, id: int) -> ChenResponse:
|
||||
"""生成最终回归测试说明文档工具函数"""
|
||||
input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'hsm' / template_name
|
||||
doc = DocxTemplate(input_path)
|
||||
doc.render(context, autoescape=True)
|
||||
try:
|
||||
doc.save(Path.cwd() / "media" / project_path(id) / "output_dir/hsm" / template_name)
|
||||
return ChenResponse(status=200, code=200, message="文档生成成功!")
|
||||
except PermissionError as e:
|
||||
return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e))
|
||||
|
||||
def create_dg_docx(template_name: str, context: dict, id: int) -> ChenResponse:
|
||||
"""生成最终大纲文档工具函数"""
|
||||
input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'dg' / template_name
|
||||
doc = DocxTemplate(input_path)
|
||||
doc.render(context, autoescape=True)
|
||||
try:
|
||||
doc.save(Path.cwd() / "media" / project_path(id) / "output_dir" / template_name)
|
||||
return ChenResponse(status=200, code=200, message="文档生成成功!")
|
||||
except PermissionError as e:
|
||||
return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e))
|
||||
|
||||
def create_bg_docx(template_name: str, context: dict, id: int) -> ChenResponse:
|
||||
"""生成最终报告文档工具函数"""
|
||||
input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'bg' / template_name
|
||||
doc = DocxTemplate(input_path)
|
||||
doc.render(context, autoescape=True)
|
||||
try:
|
||||
doc.save(Path.cwd() / "media" / project_path(id) / "output_dir/bg" / template_name)
|
||||
return ChenResponse(status=200, code=200, message="文档生成成功!")
|
||||
except PermissionError as e:
|
||||
return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e))
|
||||
|
||||
def create_wtd_docx(template_name: str, context: dict, id: int) -> ChenResponse:
|
||||
"""生成最终问题单文档工具函数"""
|
||||
input_path = Path.cwd() / 'media' / project_path(id) / 'form_template' / 'wtd' / template_name
|
||||
doc = DocxTemplate(input_path)
|
||||
doc.render(context, autoescape=True)
|
||||
try:
|
||||
doc.save(Path.cwd() / "media" / project_path(id) / "output_dir/wtd" / template_name)
|
||||
return ChenResponse(status=200, code=200, message="文档生成成功!")
|
||||
except PermissionError as e:
|
||||
return ChenResponse(status=400, code=400, message="模版文件已打开,请关闭后再试,{0}".format(e))
|
||||
|
||||
def get_round1_problem(project: Project) -> Any:
|
||||
"""
|
||||
从项目返回第一轮问题单
|
||||
:param project: Project项目Model对象
|
||||
:return: 问题单的列表
|
||||
"""
|
||||
all_problem_qs = project.projField.all()
|
||||
# 遍历每个问题,找出第一轮的问题
|
||||
problem_set = set()
|
||||
for problem in all_problem_qs:
|
||||
flag = False
|
||||
for case in problem.case.all():
|
||||
if case.round.key == '0':
|
||||
flag = True
|
||||
if flag:
|
||||
problem_set.add(problem)
|
||||
return list(problem_set)
|
||||
|
||||
def delete_dir_files(path: Path) -> Any:
|
||||
"""传入一个Path对象,如果是文件夹则删除里面所有的文件(不删除文件夹)"""
|
||||
if path.is_dir():
|
||||
for file in path.iterdir():
|
||||
if file.is_file():
|
||||
file.unlink()
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -15,7 +15,7 @@ from typing import List
|
||||
from utils.chen_response import ChenResponse
|
||||
from utils.chen_crud import multi_delete_design
|
||||
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, JKDesignInfo
|
||||
from apps.project.schemas.design import DeleteSchema, DesignFilterSchema, DesignModelOutSchema, \
|
||||
DesignTreeReturnSchema, \
|
||||
DesignTreeInputSchema, DesignCreateOutSchema, DesignCreateInputSchema, MultiDesignCreateInputSchema, \
|
||||
@@ -25,6 +25,22 @@ from utils.smallTools.interfaceTools import conditionNoneToBlank
|
||||
from apps.project.tools.auto_create_data import auto_create_renji
|
||||
from apps.project.tool.dragAndDrop import DesignDrapAtoB
|
||||
|
||||
def _save_jk_direction_info(design: Design, direction: str, source: str, destination: str, description: str):
|
||||
"""保存或更新 JKDesignInfo 记录"""
|
||||
if not source and not destination and not description:
|
||||
# 如果三个字段全为空,则删除可能存在的记录(避免冗余数据)
|
||||
JKDesignInfo.objects.filter(jk=design, direction=direction).delete()
|
||||
return
|
||||
JKDesignInfo.objects.update_or_create(
|
||||
jk=design,
|
||||
direction=direction,
|
||||
defaults={
|
||||
'source': source or '',
|
||||
'destination': destination or '',
|
||||
'description': description or '',
|
||||
}
|
||||
)
|
||||
|
||||
@api_controller("/project", auth=JWTAuth(), permissions=[IsAuthenticated], tags=['设计需求数据'])
|
||||
class DesignController(ControllerBase):
|
||||
@route.get("/getDesignDemandList", response=List[DesignModelOutSchema], exclude_none=True,
|
||||
@@ -97,7 +113,30 @@ class DesignController(ControllerBase):
|
||||
{'key': key_string, 'round': round_instance, 'dut': dut_instance, 'title': payload.name})
|
||||
asert_dict.pop("round_key")
|
||||
asert_dict.pop("dut_key")
|
||||
# 去掉Design不使用的字段
|
||||
asert_dict.pop("forward_source", None)
|
||||
asert_dict.pop("forward_destination", None)
|
||||
asert_dict.pop("forward_description", None)
|
||||
asert_dict.pop("reverse_source", None)
|
||||
asert_dict.pop("reverse_destination", None)
|
||||
asert_dict.pop("reverse_description", None)
|
||||
qs = Design.objects.create(**asert_dict)
|
||||
# 处理接口方向信息(仅当 demandType == '3' 且存在正向/反向数据时)
|
||||
if payload.demandType == '3':
|
||||
_save_jk_direction_info(
|
||||
design=qs,
|
||||
direction=JKDesignInfo.Direction.FORWARD,
|
||||
source=payload.forward_source,
|
||||
destination=payload.forward_destination,
|
||||
description=payload.forward_description,
|
||||
)
|
||||
_save_jk_direction_info(
|
||||
design=qs,
|
||||
direction=JKDesignInfo.Direction.REVERSE,
|
||||
source=payload.reverse_source,
|
||||
destination=payload.reverse_destination,
|
||||
description=payload.reverse_description,
|
||||
)
|
||||
return qs
|
||||
|
||||
# 批量增加设计需求,对应前端批量增加页面modal
|
||||
@@ -136,15 +175,36 @@ class DesignController(ControllerBase):
|
||||
# 判断是否和同项目同轮次的标识重复
|
||||
if len(design_search) > 1 and payload.ident != '':
|
||||
return ChenResponse(code=400, status=400, message='研制需求的标识重复,请检查')
|
||||
|
||||
# 查到当前
|
||||
design_qs = Design.objects.get(id=id)
|
||||
for attr, value in payload.dict().items():
|
||||
if attr == 'project_id' or attr == 'round_key' or attr == 'dut_key':
|
||||
if attr in ('project_id', 'round_key', 'dut_key'):
|
||||
continue
|
||||
if attr == 'name':
|
||||
setattr(design_qs, "title", value)
|
||||
setattr(design_qs, attr, value)
|
||||
design_qs.save()
|
||||
|
||||
# 处理接口方向信息更新
|
||||
if payload.demandType == '3':
|
||||
_save_jk_direction_info(
|
||||
design=design_qs,
|
||||
direction=JKDesignInfo.Direction.FORWARD,
|
||||
source=payload.forward_source,
|
||||
destination=payload.forward_destination,
|
||||
description=payload.forward_description,
|
||||
)
|
||||
_save_jk_direction_info(
|
||||
design=design_qs,
|
||||
direction=JKDesignInfo.Direction.REVERSE,
|
||||
source=payload.reverse_source,
|
||||
destination=payload.reverse_destination,
|
||||
description=payload.reverse_description,
|
||||
)
|
||||
else:
|
||||
# 如果需求类型不再是接口,则删除已有的方向信息
|
||||
JKDesignInfo.objects.filter(jk=design_qs).delete()
|
||||
return design_qs
|
||||
|
||||
# 删除设计需求
|
||||
|
||||
@@ -463,7 +463,7 @@ class ProjectController(ControllerBase):
|
||||
return ChenResponse(status=200, code=25001, data={"table": item_obj.table, "fontnote": item_obj.fontnote})
|
||||
return ChenResponse(status=200, code=25002, data=None)
|
||||
|
||||
# ~~~静态软件项、静态硬件项、动态软件项、动态硬件项 - 新增或修改~~~
|
||||
# ~~~静态软件项、静态硬件项、动态软件项、动态硬件项、测评数据 - 新增或修改~~~
|
||||
@route.post("/post_static_dynamic_item/")
|
||||
@transaction.atomic
|
||||
def post_static_dynamic_item(self, data: StaticDynamicData):
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
# Generated by Django 6.0.4 on 2026-04-21 18:21
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('project', '0032_alter_design_protocal'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='design',
|
||||
name='protocal',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='design',
|
||||
name='to',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='design',
|
||||
name='type',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='design',
|
||||
name='source',
|
||||
field=models.CharField(blank=True, default='', help_text='接口来源', max_length=256, null=True, verbose_name='接口来源'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='JKDesignInfo',
|
||||
fields=[
|
||||
('id', models.BigAutoField(help_text='Id', primary_key=True, serialize=False, verbose_name='Id')),
|
||||
('remark', models.CharField(blank=True, help_text='描述', max_length=255, null=True, verbose_name='描述')),
|
||||
('update_datetime', models.DateField(auto_now=True, help_text='修改时间', null=True, verbose_name='修改时间')),
|
||||
('create_datetime', models.DateField(auto_now_add=True, help_text='创建时间', null=True, verbose_name='创建时间')),
|
||||
('sort', models.IntegerField(blank=True, default=1, help_text='显示排序', null=True, verbose_name='显示排序')),
|
||||
('direction', models.CharField(choices=[('forward', '正向'), ('reverse', '反向')], max_length=10, verbose_name='方向')),
|
||||
('description', models.TextField(blank=True, default='', max_length=1024, null=True, verbose_name='接口描述')),
|
||||
('source', models.CharField(blank=True, default='', max_length=200, null=True, verbose_name='来源')),
|
||||
('destination', models.CharField(blank=True, default='', max_length=200, null=True, verbose_name='目的地')),
|
||||
('jk', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='jkField', to='project.design', verbose_name='所属接口Design')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '接口一个方向的信息',
|
||||
'verbose_name_plural': '接口一个方向的信息',
|
||||
'unique_together': {('jk', 'direction')},
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,37 @@
|
||||
# Generated by Django 6.0.4 on 2026-04-21 18:27
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('project', '0033_remove_design_protocal_remove_design_to_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='design',
|
||||
name='source',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='design',
|
||||
name='type',
|
||||
field=models.CharField(blank=True, default='', help_text='接口类型', max_length=1024, null=True, verbose_name='接口类型'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='jkdesigninfo',
|
||||
name='description',
|
||||
field=models.TextField(blank=True, max_length=1024, null=True, verbose_name='接口描述'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='jkdesigninfo',
|
||||
name='destination',
|
||||
field=models.CharField(blank=True, max_length=200, null=True, verbose_name='目的地'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='jkdesigninfo',
|
||||
name='source',
|
||||
field=models.CharField(blank=True, max_length=200, null=True, verbose_name='来源'),
|
||||
),
|
||||
]
|
||||
18
apps/project/migrations/0035_design_is_bidirectional.py
Normal file
18
apps/project/migrations/0035_design_is_bidirectional.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 6.0.4 on 2026-04-21 18:38
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('project', '0034_remove_design_source_design_type_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='design',
|
||||
name='is_bidirectional',
|
||||
field=models.BooleanField(default=False, verbose_name='是否双向'),
|
||||
),
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -15,9 +15,9 @@ class Project(CoreModel):
|
||||
help_text="项目标识", unique=True) # 唯一
|
||||
name = models.CharField(max_length=100, blank=True, null=True, verbose_name="项目名称",
|
||||
help_text="项目名称")
|
||||
beginTime = models.DateField(auto_now_add=True, null=True, blank=True, help_text="开始时间",
|
||||
beginTime = models.DateField(null=True, blank=True, help_text="开始时间",
|
||||
verbose_name="开始时间")
|
||||
endTime = models.DateField(auto_now_add=True, null=True, blank=True, help_text="结束时间",
|
||||
endTime = models.DateField(null=True, blank=True, help_text="结束时间",
|
||||
verbose_name="结束时间")
|
||||
duty_person = models.CharField(max_length=64, verbose_name="负责人", help_text="负责人")
|
||||
member = models.JSONField(null=True, blank=True, help_text="项目成员", verbose_name="项目成员",
|
||||
@@ -198,15 +198,12 @@ class Design(CoreModel):
|
||||
dut = models.ForeignKey(to="Dut", db_constraint=False, related_name="rsField", on_delete=models.CASCADE,
|
||||
verbose_name='归属轮次', help_text='归属轮次', related_query_name='rsQuery')
|
||||
# 如果是demandTye='3'则加上如下字段
|
||||
source = models.CharField(max_length=64, blank=True, null=True, default='', verbose_name='接口来源',
|
||||
help_text='接口来源')
|
||||
to = models.CharField(max_length=64, blank=True, null=True, default='', verbose_name='接口目的地',
|
||||
help_text='接口目的地')
|
||||
type = models.CharField(max_length=64, blank=True, null=True, default='', verbose_name='接口类型',
|
||||
type = models.CharField(max_length=1024, blank=True, null=True, default='', verbose_name='接口类型',
|
||||
help_text='接口类型')
|
||||
# 注意:该字段改为接口数据
|
||||
protocal = models.CharField(max_length=1024, blank=True, null=True, default='', verbose_name='接口数据',
|
||||
help_text='接口数据')
|
||||
is_bidirectional = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name="是否双向"
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return f'设计需求:{self.name}'
|
||||
@@ -217,6 +214,29 @@ class Design(CoreModel):
|
||||
verbose_name_plural = verbose_name
|
||||
ordering = ('key',)
|
||||
|
||||
class JKDesignInfo(CoreModel):
|
||||
class Direction(models.TextChoices):
|
||||
FORWARD = 'forward', '正向'
|
||||
REVERSE = 'reverse', '反向'
|
||||
|
||||
jk = models.ForeignKey(Design, on_delete=models.CASCADE, related_name="jkField", verbose_name="所属接口Design")
|
||||
direction = models.CharField(
|
||||
max_length=10,
|
||||
choices=Direction.choices, # type: ignore
|
||||
verbose_name="方向"
|
||||
)
|
||||
description = models.TextField(max_length=1024, blank=True, null=True, verbose_name="接口描述")
|
||||
source = models.CharField(max_length=200, blank=True, null=True, verbose_name="来源")
|
||||
destination = models.CharField(max_length=200, blank=True, null=True, verbose_name="目的地")
|
||||
|
||||
class Meta:
|
||||
unique_together = [['jk', 'direction']] # 同一个方向仅一条记录
|
||||
verbose_name = "接口一个方向的信息"
|
||||
verbose_name_plural = "接口一个方向的信息"
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.jk.name} - {self.get_direction_display()}"
|
||||
|
||||
class TestDemand(CoreModel):
|
||||
"""测试项"""
|
||||
objects = models.Manager()
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,5 @@
|
||||
from typing import Optional
|
||||
from apps.project.models import Design
|
||||
from apps.project.models import Design, JKDesignInfo
|
||||
from ninja import Field, Schema, ModelSchema
|
||||
from typing import List, Union
|
||||
from pydantic import AliasChoices
|
||||
@@ -30,11 +30,54 @@ class DesignModelOutSchemaOrigin(ModelSchema):
|
||||
class DesignModelOutSchema(ModelSchema):
|
||||
# 新增字段 - 上级的dut对象
|
||||
dut: Optional[DutModelOutSchema] = None
|
||||
is_bidirectional: bool = Field(False, alias='is_bidirectional')
|
||||
forward_source: str = Field("")
|
||||
forward_destination: str = Field("")
|
||||
forward_description: str = Field("")
|
||||
reverse_source: str = Field("")
|
||||
reverse_destination: str = Field("")
|
||||
reverse_description: str = Field("")
|
||||
|
||||
class Meta:
|
||||
model = Design
|
||||
exclude = ['project', 'round', 'dut', 'remark', 'sort']
|
||||
|
||||
# ---------- 解析器方法 ----------
|
||||
@staticmethod
|
||||
def resolve_is_bidirectional(obj: Design) -> bool:
|
||||
return obj.is_bidirectional
|
||||
|
||||
@staticmethod
|
||||
def resolve_forward_source(obj: Design) -> str:
|
||||
"""从 JKDesignInfo 正向记录中获取 source"""
|
||||
info = obj.jkField.filter(direction=JKDesignInfo.Direction.FORWARD).first()
|
||||
return info.source if info else ""
|
||||
|
||||
@staticmethod
|
||||
def resolve_forward_destination(obj: Design) -> str:
|
||||
info = obj.jkField.filter(direction=JKDesignInfo.Direction.FORWARD).first()
|
||||
return info.destination if info else ""
|
||||
|
||||
@staticmethod
|
||||
def resolve_forward_description(obj: Design) -> str:
|
||||
info = obj.jkField.filter(direction=JKDesignInfo.Direction.FORWARD).first()
|
||||
return info.description if info else ""
|
||||
|
||||
@staticmethod
|
||||
def resolve_reverse_source(obj: Design) -> str:
|
||||
info = obj.jkField.filter(direction=JKDesignInfo.Direction.REVERSE).first()
|
||||
return info.source if info else ""
|
||||
|
||||
@staticmethod
|
||||
def resolve_reverse_destination(obj: Design) -> str:
|
||||
info = obj.jkField.filter(direction=JKDesignInfo.Direction.REVERSE).first()
|
||||
return info.destination if info else ""
|
||||
|
||||
@staticmethod
|
||||
def resolve_reverse_description(obj: Design) -> str:
|
||||
info = obj.jkField.filter(direction=JKDesignInfo.Direction.REVERSE).first()
|
||||
return info.description if info else ""
|
||||
|
||||
# 处理树状结构的schema
|
||||
class DesignTreeReturnSchema(Schema):
|
||||
title: str = Field(..., alias='title')
|
||||
@@ -66,11 +109,15 @@ class DesignCreateInputSchema(Schema):
|
||||
demandType: str = Field(None, alias="demandType")
|
||||
description: str = Field("", alias="description")
|
||||
chapter: str = Field(None, alias='chapter')
|
||||
# 接口独有的4个字段
|
||||
source: str = Field('', alias='source')
|
||||
to: str = Field('', alias='to')
|
||||
# 接口类型包含
|
||||
type: str = Field('', alias='type')
|
||||
protocal: str = Field('', alias='protocal')
|
||||
is_bidirectional: bool = Field(False, alias='is_bidirectional')
|
||||
forward_source: str = Field("")
|
||||
forward_destination: str = Field("")
|
||||
forward_description: str = Field("")
|
||||
reverse_source: str = Field("")
|
||||
reverse_destination: str = Field("")
|
||||
reverse_description: str = Field("")
|
||||
|
||||
class SingleDesignSchema(Schema):
|
||||
ident: str = Field(None, alias="ident")
|
||||
|
||||
Reference in New Issue
Block a user