feat: 添加route pack dag显示

This commit is contained in:
caoqianming 2025-03-26 17:23:38 +08:00
parent 2d7183f8dd
commit a31faa0cda
3 changed files with 61 additions and 15 deletions

View File

@ -3,6 +3,7 @@ from apps.system.models import CommonAModel, Dictionary, CommonBModel, CommonADM
from rest_framework.exceptions import ParseError
from apps.utils.models import CommonBDModel
from collections import defaultdict, deque
from django.db.models import Q
class Process(CommonBModel):
"""
@ -245,21 +246,23 @@ class Route(CommonADModel):
parent = models.ForeignKey('self', verbose_name='上级路线', on_delete=models.CASCADE, null=True, blank=True)
@staticmethod
def get_routes(material: Material):
def get_routes(material: Material=None, routepack:RoutePack=None):
"""
返回工艺路线带车间(不关联工艺包)
"""
kwargs = {'material': material, 'routepack__isnull': True}
# 校验工艺路线是否正常
rq = Route.objects.filter(
**kwargs).order_by('sort', 'process__sort', 'create_time')
if not rq.exists():
raise ParseError('未配置工艺路线')
if rq.first().material_in is None or rq.last().material_out is None or rq.last().material_out != rq.last().material:
raise ParseError('首步缺少输入/最后一步缺少输出')
if not rq.filter(is_count_utask=True).exists():
raise ParseError('未指定统计步骤')
return rq
if material:
kwargs = {'material': material, 'routepack__isnull': True}
rqs = Route.objects.filter(
**kwargs).order_by('sort', 'process__sort', 'create_time')
# if not rq.exists():
# raise ParseError('未配置工艺路线')
# if rq.first().material_in is None or rq.last().material_out is None or rq.last().material_out != rq.last().material:
# raise ParseError('首步缺少输入/最后一步缺少输出')
# if not rq.filter(is_count_utask=True).exists():
# raise ParseError('未指定统计步骤')
elif routepack:
rqs = Route.objects.filter(routepack=routepack).order_by('sort', 'process__sort', 'create_time')
return rqs
@classmethod
def validate_dag(cls, final_material_out:Material, rqs):
@ -345,6 +348,47 @@ class Route(CommonADModel):
return True
@classmethod
def get_dag(cls, rqs):
# 收集所有相关批次和边
nodes_set = set()
edges = []
for rq in rqs:
source = rq.material_in.id
target = rq.material_out.id
nodes_set.update([source, target])
edges.append({
'source': source,
'target': target,
'label': rq.process.name,
})
# 去重边
unique_edges = {}
for edge in edges:
key = (edge['source'], edge['target'])
if key not in unique_edges:
unique_edges[key] = edge
# 将批次号排序
nodes_qs = Material.objects.filter(id__in=nodes_set).order_by("process__sort", "create_time")
# batch_to_id = {batch: idx for idx, batch in enumerate(nodes_list)}
# 构建节点数据,默认使用'rect'形状
nodes = [{
'id': item.id,
'label': str(item),
'shape': 'rect' # 可根据业务需求调整形状
} for item in nodes_qs]
# 构建边数据
edges_converted = [{
'source': edge['source'],
'target': edge['target'],
'label': edge['label']
} for edge in unique_edges.values()]
return {'nodes': nodes, 'edges': edges_converted}
class RouteMat(BaseModel):
route = models.ForeignKey(Route, verbose_name='关联路线', on_delete=models.CASCADE, related_name="routemat_route")
material = models.ForeignKey(Material, verbose_name='辅助物料', on_delete=models.CASCADE)

View File

@ -283,7 +283,9 @@ class RoutePackViewSet(CustomModelViewSet):
ins.save()
return Response()
@action(methods=['get'], detail=True, perms_map={'get': '*'})
def dag(self, request, *args, **kwargs):
return Response(Route.get_dag(rqs=Route.objects.filter(routepack=self.get_object())))
class RouteViewSet(CustomModelViewSet):
queryset = Route.objects.all()
serializer_class = RouteSerializer

View File

@ -167,9 +167,9 @@ class PmService:
else:
# 获取产品的加工路线
if utask.routepack: # 指定工艺路线
rqs = Route.objects.filter(routepack=utask.routepack).order_by('sort', 'process__sort', 'create_time')
rqs = Route.get_routes(routepack=utask.routepack)
else:
rqs = Route.get_routes(product)
rqs = Route.get_routes(material=product)
if not rqs.exists():
raise ParseError('未配置工艺路线')