This commit is contained in:
zty 2025-09-19 09:22:49 +08:00
commit d8ad57fa7e
6 changed files with 178 additions and 4 deletions

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.12 on 2025-09-19 01:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wf', '0002_alter_state_filter_dept'),
]
operations = [
migrations.AddField(
model_name='workflow',
name='view_path',
field=models.TextField(blank=True, null=True, verbose_name='前端自定义页面路径'),
),
]

View File

@ -21,6 +21,7 @@ class Workflow(CommonAModel):
'标题模板', max_length=50, default='{title}', null=True, blank=True, help_text='工单字段的值可以作为参数写到模板中,格式如:你有一个待办工单:{title}') '标题模板', max_length=50, default='{title}', null=True, blank=True, help_text='工单字段的值可以作为参数写到模板中,格式如:你有一个待办工单:{title}')
content_template = models.CharField( content_template = models.CharField(
'内容模板', max_length=1000, default='标题:{title}, 创建时间:{create_time}', null=True, blank=True, help_text='工单字段的值可以作为参数写到模板中,格式如:标题:{title}, 创建时间:{create_time}') '内容模板', max_length=1000, default='标题:{title}, 创建时间:{create_time}', null=True, blank=True, help_text='工单字段的值可以作为参数写到模板中,格式如:标题:{title}, 创建时间:{create_time}')
view_path = models.TextField('前端自定义页面路径', null=True, blank=True)
class Meta: class Meta:
verbose_name = '工作流' verbose_name = '工作流'

View File

@ -27,7 +27,7 @@ class StateSerializer(CustomModelSerializer):
class WorkflowSimpleSerializer(CustomModelSerializer): class WorkflowSimpleSerializer(CustomModelSerializer):
class Meta: class Meta:
model = Workflow model = Workflow
fields = ['id', 'name', 'key'] fields = ['id', 'name', 'key', 'view_path']
class StateSimpleSerializer(CustomModelSerializer): class StateSimpleSerializer(CustomModelSerializer):

View File

@ -1149,6 +1149,12 @@ class HandoverbSerializer(CustomModelSerializer):
read_only_fields = EXCLUDE_FIELDS_BASE + ['handover'] read_only_fields = EXCLUDE_FIELDS_BASE + ['handover']
extra_kwargs = {'wm': {'required': True}} extra_kwargs = {'wm': {'required': True}}
class HandoverbListSerializer(CustomModelSerializer):
defect_name = serializers.CharField(source="wm.defect.name", read_only=True)
class Meta:
model = Handoverb
fields = "__all__"
class HandoverSerializer(CustomModelSerializer): class HandoverSerializer(CustomModelSerializer):
# wm = serializers.PrimaryKeyRelatedField( # wm = serializers.PrimaryKeyRelatedField(
# label='车间库存ID', queryset=WMaterial.objects.all()) # label='车间库存ID', queryset=WMaterial.objects.all())
@ -1363,6 +1369,8 @@ class HandoverUpdateSerializer(CustomModelSerializer):
model = Handover model = Handover
fields = ['id', 'send_date', 'send_user', 'count', 'count_eweight', 'recive_user', 'note'] fields = ['id', 'send_date', 'send_user', 'count', 'count_eweight', 'recive_user', 'note']
class HandoverListSerializer(HandoverSerializer):
handoverb = HandoverbListSerializer(many=True, required=False)
class GenHandoverSerializer(serializers.Serializer): class GenHandoverSerializer(serializers.Serializer):

View File

@ -15,7 +15,7 @@ from apps.utils.mixins import CustomListModelMixin, BulkCreateModelMixin, Comple
from .filters import StLogFilter, SfLogFilter, WMaterialFilter, MlogFilter, HandoverFilter, MlogbFilter, BatchStFilter, MlogbwFilter from .filters import StLogFilter, SfLogFilter, WMaterialFilter, MlogFilter, HandoverFilter, MlogbFilter, BatchStFilter, MlogbwFilter
from .models import (SfLog, SfLogExp, StLog, WMaterial, Mlog, Handover, Mlogb, from .models import (SfLog, SfLogExp, StLog, WMaterial, Mlog, Handover, Mlogb,
Mlogbw, AttLog, OtherLog, Fmlog, BatchSt, MlogbDefect, MlogUser, BatchLog) Mlogbw, AttLog, OtherLog, Fmlog, BatchSt, MlogbDefect, MlogUser, BatchLog, Handoverb)
from .serializers import (SflogExpSerializer, SfLogSerializer, StLogSerializer, WMaterialSerializer, from .serializers import (SflogExpSerializer, SfLogSerializer, StLogSerializer, WMaterialSerializer,
MlogRevertSerializer, MlogRevertSerializer,
MlogSerializer, MlogRelatedSerializer, DeptBatchSerializer, HandoverSerializer, MlogSerializer, MlogRelatedSerializer, DeptBatchSerializer, HandoverSerializer,
@ -25,7 +25,8 @@ from .serializers import (SflogExpSerializer, SfLogSerializer, StLogSerializer,
MlogbDetailSerializer, MlogbInSerializer, MlogbInUpdateSerializer, MlogbDetailSerializer, MlogbInSerializer, MlogbInUpdateSerializer,
MlogbOutUpdateSerializer, FmlogSerializer, FmlogUpdateSerializer, BatchStSerializer, MlogbOutUpdateSerializer, FmlogSerializer, FmlogUpdateSerializer, BatchStSerializer,
MlogbwCreateUpdateSerializer, HandoverMgroupSerializer, MlogListSerializer, MlogbwCreateUpdateSerializer, HandoverMgroupSerializer, MlogListSerializer,
MlogbSerializer, MlogUserSerializer, BatchLogSerializer, MlogQuickSerializer, MlogbwStartTestSerializer) MlogbSerializer, MlogUserSerializer, BatchLogSerializer, MlogQuickSerializer,
MlogbwStartTestSerializer, HandoverListSerializer)
from .services import mlog_submit, handover_submit, mlog_revert, get_batch_dag, handover_revert from .services import mlog_submit, handover_submit, mlog_revert, get_batch_dag, handover_revert
from apps.wpm.services import mlog_submit_validate, generate_new_batch from apps.wpm.services import mlog_submit_validate, generate_new_batch
from apps.wf.models import State, Ticket from apps.wf.models import State, Ticket
@ -493,12 +494,15 @@ class HandoverViewSet(CustomModelViewSet):
交接记录 交接记录
""" """
queryset = Handover.objects.all() queryset = Handover.objects.all()
list_serializer_class = HandoverListSerializer
serializer_class = HandoverSerializer serializer_class = HandoverSerializer
select_related_fields = ['send_user', 'send_mgroup', 'send_dept', 'recive_user', 'recive_mgroup', 'recive_dept', 'wm'] select_related_fields = ['send_user', 'send_mgroup', 'send_dept', 'recive_user', 'recive_mgroup', 'recive_dept', 'wm']
filterset_class = HandoverFilter filterset_class = HandoverFilter
search_fields = ['id', 'material__name', search_fields = ['id', 'material__name',
'material__number', 'material__specification', 'batch', 'material__model', 'b_handover__batch', "new_batch", "wm__batch"] 'material__number', 'material__specification', 'batch', 'material__model', 'b_handover__batch', "new_batch", "wm__batch"]
prefetch_related_fields = ["b_handover"] prefetch_related_fields = [
Prefetch('b_handover', queryset=Handoverb.objects.select_related('wm__defect'))
]
def perform_destroy(self, instance): def perform_destroy(self, instance):
user = self.request.user user = self.request.user

143
out_service/insert_kvt.py Normal file
View File

@ -0,0 +1,143 @@
import requests
import os
import sys
import django
import json
import logging
import time
import threading
CUR_DIR = os.path.dirname(os.path.abspath(__file__))
BASE_DIR = os.path.dirname(CUR_DIR)
sys.path.insert(0, BASE_DIR)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "server.settings")
django.setup()
from apps.enm.services import insert_mplogx_item
from django.utils import timezone
from apps.utils.tasks import send_mail_task
from datetime import datetime, timedelta
CUR_DIR = os.path.dirname(os.path.abspath(__file__))
BASE_DIR = os.path.dirname(CUR_DIR)
sys.path.insert(0, BASE_DIR)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "server.settings")
django.setup()
SERVER = '192.168.1.37'
PORT = '8089'
PATH = f'http://{SERVER}:{PORT}/GetTagList'
SERVER2 = '192.168.1.43'
PORT2 = '8081'
PATH2 = f'http://{SERVER2}:{PORT2}/GetTagList'
#MIN_LIST = set(range(0,61,5))
MIN_LIST = [0]
myLogger = logging.getLogger("log")
class MailController:
def __init__(self):
self.last_sent_time = None
self.interval = timedelta(days=1)
self.lock = threading.Lock()
self._is_sending = False
def should_send_mail(self):
now = datetime.now()
# thread_name = threading.current_thread().name
with self.lock:
if self._is_sending:
# myLogger.info(f"线程 {thread_name}: 邮件正在发送中,跳过")
return False
if self.last_sent_time is None:
# myLogger.info(f"线程 {thread_name}: 首次发送邮件")
self._is_sending = True
return True
time_since_last = now - self.last_sent_time
if time_since_last > self.interval:
# myLogger.info(f"线程 {thread_name}: 距离上次发送已超过间隔,允许发送")
self._is_sending = True
return True
else:
# myLogger.info(f"线程 {thread_name}: 距离上次发送不足间隔,跳过")
return False
def mark_as_sent(self):
with self.lock:
self.last_sent_time = datetime.now()
self._is_sending = False
myLogger.info("邮件发送状态已重置")
mail_controller = MailController()
def send_error_notification(error_message):
"""
发送错误通知
"""
if mail_controller.should_send_mail():
try:
send_mail_task.delay(subject='insert_kvt_error', message=str(error_message))
myLogger.error(f"请求组态王失败:{str(error_message)}")
except Exception as e:
myLogger.exception(f"发送错误邮件失败: {e}")
finally:
mail_controller.mark_as_sent()
def fetch_data(timex, enp_mpoint_dict, path):
"""
从数据库转存到超表
"""
response = None
try:
response = requests.get(path, timeout=5)
response.raise_for_status() # 如果响应码不是 200将触发异常
except requests.RequestException as e:
send_error_notification(e)
if response is None:
return
try:
lines = response.text
json_line = [line.strip() for line in lines.split('\n') if line.strip() ]
current_object = []
# 将碎片分组为完整的 JSON 对象
for line in json_line:
current_object.append(line.strip()) # 将当前行加入对象
if line.strip() == '}': # 遇到结束大括号时
try:
obj_str = ' '.join(current_object).replace(',}', '}')
obj_dict = json.loads(obj_str)
insert_mplogx_item(obj_dict.get('strVarName'), obj_dict.get('VarValue'), timex, enp_mpoint_dict)
except json.JSONDecodeError as e:
send_error_notification(e)
current_object = [] # 重置,准备处理下一个对象
except Exception as e:
send_error_notification(e)
def get_data():
last_triggered = None
while True:
now = timezone.now()
now = now.replace(microsecond=0)
if now.second in MIN_LIST:
if last_triggered != now:
last_triggered = now
enp_mpoint_dict= {}
threads = [
threading.Thread(target=fetch_data, args=(now, enp_mpoint_dict, PATH), daemon=True),
threading.Thread(target=fetch_data, args=(now, enp_mpoint_dict, PATH2), daemon=True)
]
for t in threads:
t.start()
for t in threads:
t.join(timeout=10) # 设置超时防止线程挂起
time.sleep(0.5)
if __name__ == '__main__':
get_data()