新增:影响域分析-软件更改部分

This commit is contained in:
2026-02-08 15:10:43 +08:00
parent a76cd8674c
commit 2f58bdc668
55 changed files with 112 additions and 22 deletions

View File

@@ -1,6 +1,6 @@
from pathlib import Path from pathlib import Path
from copy import deepcopy from copy import deepcopy
from typing import Union from typing import Union, TypedDict, Optional
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
@@ -240,26 +240,31 @@ class GenerateControllerHSM(ControllerBase):
## 先查找是否有影响域分析填写 ## 先查找是否有影响域分析填写
area_qs = InfluenceArea.objects.filter(round=hround) area_qs = InfluenceArea.objects.filter(round=hround)
## 如果存在则查询items ## 如果存在则查询items
item_render_list = []
if area_qs.exists(): if area_qs.exists():
area_obj = area_qs.first() area_obj = area_qs.first()
items_qs = area_obj.influence_items.all() items_qs = area_obj.influence_items.all()
if items_qs.exists(): if items_qs.exists():
# 遍历items index = 1
item_render_list = []
for item in items_qs: for item in items_qs:
# 1.处理关联case - 找第一轮cases # 1.处理关联case - 找第一轮cases
case_str_list = [] case_str_list = []
for case in project_obj.pcField.filter(key__in=item.effect_cases): for case in project_obj.pcField.filter(key__in=item.effect_cases):
case_ident_index = str(int(case.key.split("-")[-1]) + 1).zfill(3) case_ident_index = str(int(case.key.split("-")[-1]) + 1).zfill(3)
case_str_list.append("_".join(["YL", get_str_abbr(case.test.testType, "testType"), case.ident, case_ident_index])) case_str_list.append("_".join(["YL", get_str_abbr(case.test.testType, "testType"), case.ident, case_ident_index]))
# 2.处理富文本框
parser = RichParser(item.change_des)
item_dict = { item_dict = {
"change_type": item.change_type, "change_type": item.change_type,
"change_influ": item.change_influ, "change_influ": item.change_influ,
"case_str_list": case_str_list, "case_str_list": case_str_list,
"change_des": item.change_des, # 富文本未处理 "change_des": parser.get_final_list(doc, img_size=40, height=30), # 富文本未处理
"index": str(index),
} }
index = index + 1
item_render_list.append(item_dict) item_render_list.append(item_dict)
# 将影响域分析加入context
context_round['influence'] = item_render_list # noqa
# 如果存在这个轮次的需求文档,则查询上个版本 # 如果存在这个轮次的需求文档,则查询上个版本
last_xq_version = "" last_xq_version = ""
if xq_dut: if xq_dut:

View File

@@ -7,7 +7,7 @@ from bs4.element import Tag, NavigableString
import base64 import base64
import io import io
from docxtpl import InlineImage from docxtpl import InlineImage
from docx.shared import Mm, Cm from docx.shared import Mm
import re import re
# text.replace('\xa0', ' ')) # text.replace('\xa0', ' '))
@@ -82,11 +82,12 @@ class RichParser:
if isinstance(oneline, list): if isinstance(oneline, list):
final_list.append({'isTable': True, 'data': oneline}) final_list.append({'isTable': True, 'data': oneline})
continue continue
if oneline.startswith("data:image/png;base64"): if oneline.startswith("data:image/png;base64") or oneline.startswith("data:image/jpeg;base64,") or oneline.startswith(
"data:image/jpg;base64,"):
base64_bytes = base64.b64decode(oneline.replace("data:image/png;base64,", "")) base64_bytes = base64.b64decode(oneline.replace("data:image/png;base64,", ""))
# ~~~设置了固定宽度、高度~~~ # ~~~设置了固定宽度、高度~~~
final_list.append( inline_image = InlineImage(doc, io.BytesIO(base64_bytes), width=Mm(img_size), height=Mm(height))
InlineImage(doc, io.BytesIO(base64_bytes), width=Mm(img_size), height=Mm(height))) final_list.append(inline_image)
else: else:
final_list.append(oneline) final_list.append(oneline)
if len(final_list) <= 0: if len(final_list) <= 0:

View File

@@ -405,7 +405,7 @@ class CaseController(ControllerBase):
# dut -> design # dut -> design
data_list = [] data_list = []
for dut in previous_round_obj.rdField.all(): for dut in previous_round_obj.rdField.all():
dut_dict = {'label': dut.name, 'value': dut.id, 'children': []} dut_dict = {'label': dut.name, 'value': dut.id, 'key': dut.key, 'children': []}
for design in dut.rsField.all(): for design in dut.rsField.all():
design_dict = {'label': design.name, 'value': design.id, 'key': design.key, 'children': []} design_dict = {'label': design.name, 'value': design.id, 'key': design.key, 'children': []}
for case in design.dcField.all(): for case in design.dcField.all():

View File

@@ -114,7 +114,6 @@ class RoundController(ControllerBase):
@route.post("/round/create_influence", url_name="round-influence-create") @route.post("/round/create_influence", url_name="round-influence-create")
@transaction.atomic @transaction.atomic
def post_influence(self, data: InfluenceInputSchema): def post_influence(self, data: InfluenceInputSchema):
print(data)
round_obj = Round.objects.filter(project_id=data.id, key=data.round_key).first() round_obj = Round.objects.filter(project_id=data.id, key=data.round_key).first()
influence_area_qs = InfluenceArea.objects.filter(round=round_obj) influence_area_qs = InfluenceArea.objects.filter(round=round_obj)
if influence_area_qs.exists(): if influence_area_qs.exists():

View File

@@ -596,3 +596,88 @@ ValueError: Cannot assign "<QuerySet [<InfluenceArea: InfluenceArea object (195)
[WARNING][2026-02-07 15:20:44,503][log.py:249]Unprocessable Content: /api/project/round/create_influence [WARNING][2026-02-07 15:20:44,503][log.py:249]Unprocessable Content: /api/project/round/create_influence
[WARNING][2026-02-07 15:21:39,506][operation.py:131]"POST - RoundController[post_influence] /api/project/round/create_influence" ([{'type': 'string_type', 'loc': ('body', 'data', 'item_list', 0, 'effect_cases', 0), 'msg': 'Input should be a valid string'}, {'type': 'string_type', 'loc': ('body', 'data', 'item_list', 0, 'effect_cases', 1), 'msg': 'Input should be a valid string'}, {'type': 'string_type', 'loc': ('body', 'data', 'item_list', 0, 'effect_cases', 2), 'msg': 'Input should be a valid string'}, {'type': 'string_type', 'loc': ('body', 'data', 'item_list', 0, 'effect_cases', 3), 'msg': 'Input should be a valid string'}],) [WARNING][2026-02-07 15:21:39,506][operation.py:131]"POST - RoundController[post_influence] /api/project/round/create_influence" ([{'type': 'string_type', 'loc': ('body', 'data', 'item_list', 0, 'effect_cases', 0), 'msg': 'Input should be a valid string'}, {'type': 'string_type', 'loc': ('body', 'data', 'item_list', 0, 'effect_cases', 1), 'msg': 'Input should be a valid string'}, {'type': 'string_type', 'loc': ('body', 'data', 'item_list', 0, 'effect_cases', 2), 'msg': 'Input should be a valid string'}, {'type': 'string_type', 'loc': ('body', 'data', 'item_list', 0, 'effect_cases', 3), 'msg': 'Input should be a valid string'}],)
[WARNING][2026-02-07 15:21:39,515][log.py:249]Unprocessable Content: /api/project/round/create_influence [WARNING][2026-02-07 15:21:39,515][log.py:249]Unprocessable Content: /api/project/round/create_influence
[WARNING][2026-02-08 13:53:10,479][log.py:249]Unauthorized: /api/system/getInfo
[WARNING][2026-02-08 13:53:10,577][log.py:249]Unauthorized: /api/system/logout
[WARNING][2026-02-08 13:53:14,760][backend.py:91]Caught LDAPError looking up user: SERVER_DOWN({'result': -1, 'desc': "Can't contact LDAP server", 'ctrls': []})
[WARNING][2026-02-08 13:53:32,251][operation.py:131]"GET - GenerateControllerHSM[create_changePart] /api/generateHSM/create/changePart" ("RichParser.get_final_list() missing 1 required positional argument: 'doc'",)
[ERROR][2026-02-08 13:53:32,252][errors.py:131]RichParser.get_final_list() missing 1 required positional argument: 'doc': 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 212, 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 "D:\programs\uv\python\cpython-3.13.11-windows-x86_64-none\Lib\contextlib.py", line 85, in inner
return func(*args, **kwds)
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\hsm.py", line 257, in create_changePart
print(parser.get_final_list())
~~~~~~~~~~~~~~~~~~~~~^^
TypeError: RichParser.get_final_list() missing 1 required positional argument: 'doc': Did you fail to use functools.wraps() in a decorator?
[ERROR][2026-02-08 13:53:32,259][log.py:249]Internal Server Error: /api/generateHSM/create/changePart
[WARNING][2026-02-08 15:04:43,157][operation.py:131]"GET - GenerateControllerHSM[create_changePart] /api/generateHSM/create/changePart" ("Expected an expression, got 'end of print statement'",)
[ERROR][2026-02-08 15:04:43,157][errors.py:131]Expected an expression, got 'end of print statement'
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 212, 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 "D:\programs\uv\python\cpython-3.13.11-windows-x86_64-none\Lib\contextlib.py", line 85, in inner
return func(*args, **kwds)
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\hsm.py", line 285, in create_changePart
doc.render(context_round, autoescape=True)
~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docxtpl\template.py", line 489, in render
xml_src = self.build_xml(context, jinja_env)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docxtpl\template.py", line 436, in build_xml
xml = self.render_xml_part(xml, self.docx._part, context, jinja_env)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docxtpl\template.py", line 322, in render_xml_part
raise exc
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docxtpl\template.py", line 310, in render_xml_part
template = jinja_env.from_string(src_xml)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\jinja2\environment.py", line 1111, in from_string
return cls.from_code(self, self.compile(source), gs, None)
~~~~~~~~~~~~^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\jinja2\environment.py", line 771, in compile
self.handle_exception(source=source_hint)
~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\jinja2\environment.py", line 942, in handle_exception
raise rewrite_traceback_stack(source=source)
File "<unknown>", line 16, in template
jinja2.exceptions.TemplateSyntaxError: Expected an expression, got 'end of print statement'
[ERROR][2026-02-08 15:04:43,182][log.py:249]Internal Server Error: /api/generateHSM/create/changePart
[WARNING][2026-02-08 15:05:05,418][operation.py:131]"GET - GenerateControllerHSM[create_changePart] /api/generateHSM/create/changePart" ("Expected an expression, got 'end of print statement'",)
[ERROR][2026-02-08 15:05:05,419][errors.py:131]Expected an expression, got 'end of print statement'
Traceback (most recent call last):
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\ninja_extra\operation.py", line 212, 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 "D:\programs\uv\python\cpython-3.13.11-windows-x86_64-none\Lib\contextlib.py", line 85, in inner
return func(*args, **kwds)
File "E:\pycharmProjects\cdtestplant_v1\apps\createDocument\controllers\hsm.py", line 285, in create_changePart
doc.render(context_round, autoescape=True)
~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docxtpl\template.py", line 489, in render
xml_src = self.build_xml(context, jinja_env)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docxtpl\template.py", line 436, in build_xml
xml = self.render_xml_part(xml, self.docx._part, context, jinja_env)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docxtpl\template.py", line 322, in render_xml_part
raise exc
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\docxtpl\template.py", line 310, in render_xml_part
template = jinja_env.from_string(src_xml)
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\jinja2\environment.py", line 1111, in from_string
return cls.from_code(self, self.compile(source), gs, None)
~~~~~~~~~~~~^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\jinja2\environment.py", line 771, in compile
self.handle_exception(source=source_hint)
~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
File "E:\pycharmProjects\cdtestplant_v1\.venv\Lib\site-packages\jinja2\environment.py", line 942, in handle_exception
raise rewrite_traceback_stack(source=source)
File "<unknown>", line 16, in template
jinja2.exceptions.TemplateSyntaxError: Expected an expression, got 'end of print statement'
[ERROR][2026-02-08 15:05:05,438][log.py:249]Internal Server Error: /api/generateHSM/create/changePart

Binary file not shown.

View File

@@ -17,8 +17,8 @@ dependencies = [
"django-tinymce>=5.0.0", "django-tinymce>=5.0.0",
"docxcompose", "docxcompose",
"docxtpl>=0.20.2", "docxtpl>=0.20.2",
"faker==40.1.2", "faker>=40.4.0",
"ipykernel>=7.1.0", "ipykernel>=7.2.0",
"lizard>=1.21.0", "lizard>=1.21.0",
"mysqlclient>=2.2.7", "mysqlclient>=2.2.7",
"ninja-schema>=0.14.3", "ninja-schema>=0.14.3",

16
uv.lock generated
View File

@@ -111,8 +111,8 @@ requires-dist = [
{ name = "django-tinymce", specifier = ">=5.0.0" }, { name = "django-tinymce", specifier = ">=5.0.0" },
{ name = "docxcompose" }, { name = "docxcompose" },
{ name = "docxtpl", specifier = ">=0.20.2" }, { name = "docxtpl", specifier = ">=0.20.2" },
{ name = "faker", specifier = "==40.1.2" }, { name = "faker", specifier = ">=40.4.0" },
{ name = "ipykernel", specifier = ">=7.1.0" }, { name = "ipykernel", specifier = ">=7.2.0" },
{ name = "lizard", specifier = ">=1.21.0" }, { name = "lizard", specifier = ">=1.21.0" },
{ name = "mysqlclient", specifier = ">=2.2.7" }, { name = "mysqlclient", specifier = ">=2.2.7" },
{ name = "ninja-schema", specifier = ">=0.14.3" }, { name = "ninja-schema", specifier = ">=0.14.3" },
@@ -413,14 +413,14 @@ wheels = [
[[package]] [[package]]
name = "faker" name = "faker"
version = "40.1.2" version = "40.4.0"
source = { registry = "https://mirrors.aliyun.com/pypi/simple" } source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
dependencies = [ dependencies = [
{ name = "tzdata", marker = "sys_platform == 'win32'" }, { name = "tzdata", marker = "sys_platform == 'win32'" },
] ]
sdist = { url = "https://mirrors.aliyun.com/pypi/packages/5e/77/1c3ff07b6739b9a1d23ca01ec0a90a309a33b78e345a3eb52f9ce9240e36/faker-40.1.2.tar.gz", hash = "sha256:b76a68163aa5f171d260fc24827a8349bc1db672f6a665359e8d0095e8135d30" } sdist = { url = "https://mirrors.aliyun.com/pypi/packages/fc/7e/dccb7013c9f3d66f2e379383600629fec75e4da2698548bdbf2041ea4b51/faker-40.4.0.tar.gz", hash = "sha256:76f8e74a3df28c3e2ec2caafa956e19e37a132fdc7ea067bc41783affcfee364" }
wheels = [ wheels = [
{ url = "https://mirrors.aliyun.com/pypi/packages/46/ec/91a434c8a53d40c3598966621dea9c50512bec6ce8e76fa1751015e74cef/faker-40.1.2-py3-none-any.whl", hash = "sha256:93503165c165d330260e4379fd6dc07c94da90c611ed3191a0174d2ab9966a42" }, { url = "https://mirrors.aliyun.com/pypi/packages/ac/63/58efa67c10fb27810d34351b7a10f85f109a7f7e2a07dc3773952459c47b/faker-40.4.0-py3-none-any.whl", hash = "sha256:486d43c67ebbb136bc932406418744f9a0bdf2c07f77703ea78b58b77e9aa443" },
] ]
[[package]] [[package]]
@@ -443,7 +443,7 @@ wheels = [
[[package]] [[package]]
name = "ipykernel" name = "ipykernel"
version = "7.1.0" version = "7.2.0"
source = { registry = "https://mirrors.aliyun.com/pypi/simple" } source = { registry = "https://mirrors.aliyun.com/pypi/simple" }
dependencies = [ dependencies = [
{ name = "appnope", marker = "sys_platform == 'darwin'" }, { name = "appnope", marker = "sys_platform == 'darwin'" },
@@ -460,9 +460,9 @@ dependencies = [
{ name = "tornado" }, { name = "tornado" },
{ name = "traitlets" }, { name = "traitlets" },
] ]
sdist = { url = "https://mirrors.aliyun.com/pypi/packages/b9/a4/4948be6eb88628505b83a1f2f40d90254cab66abf2043b3c40fa07dfce0f/ipykernel-7.1.0.tar.gz", hash = "sha256:58a3fc88533d5930c3546dc7eac66c6d288acde4f801e2001e65edc5dc9cf0db" } sdist = { url = "https://mirrors.aliyun.com/pypi/packages/ca/8d/b68b728e2d06b9e0051019640a40a9eb7a88fcd82c2e1b5ce70bef5ff044/ipykernel-7.2.0.tar.gz", hash = "sha256:18ed160b6dee2cbb16e5f3575858bc19d8f1fe6046a9a680c708494ce31d909e" }
wheels = [ wheels = [
{ url = "https://mirrors.aliyun.com/pypi/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl", hash = "sha256:763b5ec6c5b7776f6a8d7ce09b267693b4e5ce75cb50ae696aaefb3c85e1ea4c" }, { url = "https://mirrors.aliyun.com/pypi/packages/82/b9/e73d5d9f405cba7706c539aa8b311b49d4c2f3d698d9c12f815231169c71/ipykernel-7.2.0-py3-none-any.whl", hash = "sha256:3bbd4420d2b3cc105cbdf3756bfc04500b1e52f090a90716851f3916c62e1661" },
] ]
[[package]] [[package]]