1
0
forked from erp-dev/erp
Files
erpnew/stateflow/models.py
2025-11-11 18:05:10 +08:00

160 lines
6.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from flower.common import ModelBase
from typing import List
class State(ModelBase):
"""State model representing a state in a stateflow diagram."""
name = models.CharField(max_length=100, verbose_name='状态名称')
# previous = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='上一级状态')
description = models.CharField(max_length=200, blank=True, verbose_name='状态描述')
def __str__(self):
return self.name
def add_additional_params(self, params: dict):
"""Add additional parameters to the state's data field."""
if not self.data:
self.data = {}
self.data.update(params)
self.save()
def get_additional_params(self) -> dict:
"""Retrieve additional parameters from the state's data field."""
return self.data if self.data else {}
class Meta:
verbose_name = '流程节点'
verbose_name_plural = '流程节点'
class StateParameter(ModelBase):
"""StateParameter model representing parameters associated with a state."""
state = models.ForeignKey(State, on_delete=models.PROTECT, related_name='parameters', verbose_name='关联参数')
key = models.CharField(max_length=100, verbose_name='参数键')
value = models.CharField(max_length=200, verbose_name='参数值')
description = models.CharField(max_length=200, blank=True, verbose_name='参数描述')
def __str__(self):
return f"{self.state.name} - {self.key}"
class Meta:
verbose_name = '工艺参数'
verbose_name_plural = '工艺参数'
class Process(ModelBase):
"""Process model representing a stateflow process template."""
name = models.CharField(max_length=100, verbose_name='流程名称')
state_nodes = models.ManyToManyField(
State,
through='ProcessNode',
related_name='processes',
verbose_name='节点列表',
)
description = models.TextField(blank=True, verbose_name='流程描述')
def __str__(self):
return self.name
def replace_nodes(self, nodes: List[State]):
"""Replace all nodes with new ordered list."""
# 清空现有节点后按照传入顺序重建
self.process_nodes.all().delete()
for order, node in enumerate(nodes):
ProcessNode.objects.create(process=self, state=node, order=order)
def get_nodes(self) -> List[State]:
"""Retrieve the list of state nodes as State instances."""
process_nodes = self.process_nodes.select_related('state').order_by('order', 'id')
return [item.state for item in process_nodes]
class Meta:
verbose_name = '印染流程'
verbose_name_plural = '印染流程'
class ProcessNode(ModelBase):
"""Intermediate model describing ordered relation between Process and State."""
process = models.ForeignKey(Process, on_delete=models.CASCADE, related_name='process_nodes', verbose_name='流程')
state = models.ForeignKey(State, on_delete=models.PROTECT, related_name='state_process_nodes', verbose_name='节点')
order = models.PositiveIntegerField(default=0, verbose_name='顺序')
class Meta:
verbose_name = '流程节点关联'
verbose_name_plural = '流程节点关联'
ordering = ['order', 'id']
unique_together = ('process', 'order')
def __str__(self) -> str:
return f"{self.process.name} -> {self.state.name} ({self.order})"
class BusinessObject(ModelBase):
"""业务对象 - 代表流程的一个实例,通过日志跟踪进度"""
name = models.CharField(max_length=100, verbose_name='业务对象名称')
process = models.ForeignKey(Process, on_delete=models.PROTECT, related_name='business_objects', verbose_name='关联流程')
description = models.TextField(blank=True, verbose_name='描述')
# GenericForeignKey - 关联到任意模型(可选)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, null=True, blank=True, verbose_name='关联对象类型')
object_id = models.PositiveIntegerField(null=True, blank=True, verbose_name='关联对象ID')
content_object = GenericForeignKey('content_type', 'object_id')
def __str__(self):
return f"{self.name} ({self.process.name})"
def get_current_state(self) -> 'State':
"""获取当前状态通过services推导"""
from . import services
return services.get_business_object_current_state(self)
def get_completed_node_ids(self) -> List[int]:
"""获取已完成的节点ID列表"""
from . import services
return services.get_completed_node_ids(self)
def get_current_parameters(self) -> List['StateParameter']:
"""获取当前状态的参数"""
from . import services
return services.get_current_state_parameters(self)
def get_progress_percentage(self) -> float:
"""计算进度百分比"""
from . import services
return services.get_progress_percentage(self)
def get_state_status(self, state: 'State') -> str:
"""获取指定状态的状态"""
from . import services
return services.get_business_object_state_status(self, state)
def get_timeline(self) -> List[dict]:
"""获取状态时间线"""
from . import services
return services.get_business_object_state_timeline(self)
class Meta:
db_table = 'business_object'
verbose_name = '业务对象'
verbose_name_plural = '业务对象'
class StateFlowRecord(ModelBase):
"""状态流转记录"""
business_object = models.ForeignKey(BusinessObject, on_delete=models.CASCADE, related_name='state_logs', verbose_name='业务对象')
state = models.ForeignKey(State, on_delete=models.CASCADE, verbose_name='状态')
completed_at = models.DateTimeField(auto_now_add=True, verbose_name='完成时间')
completed_by = models.ForeignKey('auth.User', on_delete=models.SET_NULL, null=True, verbose_name='操作人')
cancelled_at = models.DateTimeField(null=True, blank=True, verbose_name='撤销时间')
is_cancelled = models.BooleanField(default=False, verbose_name='是否已撤销')
class Meta:
db_table = 'state_flow_record'
verbose_name = '状态流转记录'
verbose_name_plural = '状态流转记录'
unique_together = [['business_object', 'state']]
ordering = ['completed_at']