新增:软件概述model、新增修改软件概述

This commit is contained in:
2026-02-02 17:32:53 +08:00
parent beb8c2d25b
commit 4a1881bf32
11 changed files with 609 additions and 180 deletions

View File

@@ -2,6 +2,8 @@ from pathlib import Path
from datetime import date
from typing import List
from shutil import copytree, rmtree
from IPython.core import payload
from django.shortcuts import get_object_or_404
from django.db import transaction
from ninja_extra import api_controller, ControllerBase, route
@@ -13,8 +15,9 @@ from ninja.pagination import paginate
from ninja import Query
from utils.chen_response import ChenResponse
from utils.chen_crud import create, multi_delete_project
from apps.project.models import Project, Round
from apps.project.schemas.project import ProjectRetrieveSchema, ProjectFilterSchema, ProjectCreateInput, DeleteSchema
from apps.project.models import Project, Round, ProjectSoftSummary, StuctSortData
from apps.project.schemas.project import ProjectRetrieveSchema, ProjectFilterSchema, ProjectCreateInput, \
DeleteSchema, SoftSummarySchema, DataSchema
from utils.util import get_str_dict
# 时间处理模块
from apps.project.tool.timeList import time_return_to
@@ -89,7 +92,8 @@ class ProjectController(ControllerBase):
try:
copytree(src_dir, dist_dir) # shutil模块直接是复制并命名如果命名文件存在则抛出FileExists异常
except PermissionError:
return ChenResponse(code=500, status=500, message="错误检查是否打开了服务器的conf中的文档关闭后重试")
return ChenResponse(code=500, status=500,
message="错误检查是否打开了服务器的conf中的文档关闭后重试")
except FileExistsError:
return ChenResponse(code=500, status=500, message='文件标识已存在或输入为空格,请修改')
except FileNotFoundError:
@@ -183,8 +187,8 @@ class ProjectController(ControllerBase):
# 7.将时间提取 todo:后续将计算的事件放入该页面
timers = {'round_time': []}
rounds = project_obj.pField.all()
timers['start_time'] = project_obj.beginTime
timers['end_time'] = project_obj.endTime
timers['start_time'] = project_obj.beginTime # type:ignore
timers['end_time'] = project_obj.endTime # type:ignore
for round in rounds:
round_number = int(round.key) + 1
timers['round_time'].append({
@@ -197,7 +201,8 @@ class ProjectController(ControllerBase):
# 9.提取测试类型下面测试项数量、用例数量
data_list = []
for round in rounds:
round_dict = {'name': f'{int(round.key) + 1}轮次', 'desings': [], 'method_demand': {}, 'method_case': {}}
round_dict = {'name': f'{int(round.key) + 1}轮次', 'desings': [], 'method_demand': {},
'method_case': {}}
designs = round.dsField.all()
for design in designs:
design_dict = {
@@ -264,3 +269,54 @@ class ProjectController(ControllerBase):
def document_time_show(self, id: int):
time = time_return_to(id)
return time
# 项目级信息前端告警数据获取
@classmethod
def bulk_create_data_schemas(cls, summary_obj: ProjectSoftSummary, data: list[DataSchema]):
"""提取后面2个函数的公共新增dataschemas方法"""
data_list = []
for data in data:
data_list.append(
StuctSortData(
soft_summary=summary_obj,
type=data.type,
fontnote=data.fontnote,
content=data.content,
)
)
StuctSortData.objects.bulk_create(data_list)
# ~~~软件概述-新增和修改~~~
@route.post('/soft_summary/')
@transaction.atomic
def soft_summary(self, payload: SoftSummarySchema):
project_obj = self.get_project_by_id(payload.id)
# 安全获取-软件概述
soft_summary_qs = ProjectSoftSummary.objects.filter(project=project_obj)
if soft_summary_qs.exists():
soft_summary = soft_summary_qs.first()
# 如果存在则修改:先删除然后创建
soft_summary.data_schemas.all().delete()
self.bulk_create_data_schemas(soft_summary, payload.data)
else:
# 不存在软件概述则创建
soft_summary_obj = ProjectSoftSummary.objects.create(project=project_obj)
self.bulk_create_data_schemas(soft_summary_obj, payload.data)
# ~~~软件概述-新增和修改~~~
@route.get("/get_soft_summary/", response=list[DataSchema])
@transaction.atomic
def get_soft_summary(self, id: int):
project_obj = self.get_project_by_id(id)
soft_summary_qs = ProjectSoftSummary.objects.filter(project=project_obj)
if soft_summary_qs.exists():
# 如果存在则返回数据
soft_summary = soft_summary_qs.first()
dataSchem_qs = soft_summary.data_schemas.all()
return ChenResponse(status=200, code=25001, data=[{
"type": item.type,
"content": item.content,
"fontnote": item.fontnote,
} for item in dataSchem_qs])
return ChenResponse(status=200, code=25002, data=None)

View File

@@ -0,0 +1,45 @@
# Generated by Django 6.0.1 on 2026-02-02 15:00
import apps.project.models
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('project', '0018_testdemandcontent_subdescription'),
]
operations = [
migrations.CreateModel(
name='ProjectSoftSummary',
fields=[
('project', models.OneToOneField(db_constraint=False, help_text='关联项目', on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='projSoftSummary', serialize=False, to='project.project', verbose_name='关联项目')),
],
options={
'verbose_name': '软件概述表',
'verbose_name_plural': '软件概述表',
'db_table': 'project_soft_summary',
},
),
migrations.CreateModel(
name='StuctSortData',
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='显示排序')),
('type', models.CharField(choices=[('text', '文本'), ('table', '表格'), ('image', '图片')], default='text', max_length=20, verbose_name='数据类型')),
('fontnote', models.CharField(blank=True, default='', help_text='数据的题注说明', max_length=256, verbose_name='题注')),
('content', models.JSONField(default=apps.project.models.default_json_value, help_text='存储文本内容或二维表格数据或图片数据', verbose_name='内容')),
('soft_summary', models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.CASCADE, related_name='data_schemas', to='project.projectsoftsummary', verbose_name='所属软件概述')),
],
options={
'verbose_name': '结构排序化数据',
'verbose_name_plural': '结构排序化数据',
'db_table': 'data_schemas',
},
),
]

View File

@@ -478,3 +478,53 @@ class Abbreviation(models.Model):
db_table = 'project_abbreviation'
verbose_name = '缩略语和行业词汇'
verbose_name_plural = '缩略语和行业词汇'
# 一对一项目model软件概述
class ProjectSoftSummary(models.Model):
project = models.OneToOneField(to="Project", primary_key=True, db_constraint=False, related_name="projSoftSummary", on_delete=models.CASCADE,
verbose_name="关联项目", help_text="关联项目")
class Meta:
db_table = 'project_soft_summary'
verbose_name = "软件概述表"
verbose_name_plural = verbose_name
def default_json_value():
return ""
# 结构化排序数据
class StuctSortData(CoreModel):
"""
数据模式模型,对应 DataSchema。
通过外键与 SoftSummary 关联,形成一对多关系(数据模式对应多个项目的一对一字段)。
"""
soft_summary = models.ForeignKey(ProjectSoftSummary, db_constraint=False, related_name="data_schemas", verbose_name="所属软件概述",
on_delete=models.CASCADE)
type = models.CharField(
max_length=20,
choices=(('text', '文本'), ('table', '表格'), ('image', '图片')),
default='text',
verbose_name="数据类型",
)
# 题注字段
fontnote = models.CharField(
max_length=256,
blank=True,
default="",
verbose_name="题注",
help_text="数据的题注说明"
)
# 内容字段 - 存储字符串、列表、字典
content = models.JSONField(
verbose_name="内容",
help_text="存储文本内容或二维表格数据或图片数据",
default=default_json_value
)
class Meta:
db_table = 'data_schemas'
verbose_name = "结构排序化数据"
verbose_name_plural = verbose_name
def __str__(self):
return f"{self.soft_summary} - 结构排序化数据:({self.pk})"

View File

@@ -1,5 +1,7 @@
from ninja.errors import HttpError
from apps.project.models import Project
from pyasn1_modules.rfc2315 import Data
from apps.project.models import Project, StuctSortData
from ninja import Schema, ModelSchema
from pydantic import field_validator
from typing import List, Optional
@@ -39,3 +41,14 @@ class ProjectCreateInput(ModelSchema):
class DeleteSchema(Schema):
ids: List[int]
# ~~~软件概述~~~
class DataSchema(Schema):
type: Optional[str] = "text"
fontnote: Optional[str] = ""
content: str | list[list[str]]
## 输入
class SoftSummarySchema(Schema):
id: int
data: list[DataSchema]