from apps.utils.serializers import CustomModelSerializer from apps.enm.models import Mpoint, MpointStat, EnStat, EnStat2, MpLogx, Xscript from apps.utils.constants import EXCLUDE_FIELDS, EXCLUDE_FIELDS_BASE from rest_framework import serializers from apps.mtm.models import Mgroup from rest_framework.exceptions import ParseError from django.core.cache import cache from django.db import transaction from django_celery_beat.models import PeriodicTask from django_celery_results.models import TaskResult from apps.system.serializers import PTaskResultSerializer import json from apps.utils.tools import CodeAnalyzer class MpointSerializer(CustomModelSerializer): mgroup = serializers.PrimaryKeyRelatedField(label="测点集", queryset=Mgroup.objects.all(), required=False, allow_null=True) mgroup_name = serializers.CharField(source="mgroup.name", read_only=True) belong_dept_name = serializers.CharField(source="belong_dept.name", read_only=True) ep_monitored_name = serializers.CharField(source="ep_monitored.name", read_only=True) ep_monitored_power_kw = serializers.CharField(source="ep_monitored.power_kw", read_only=True) ep_belong_name = serializers.CharField(source="ep_belong.name", read_only=True) material_name = serializers.CharField(source="material.name", read_only=True) formula = serializers.CharField(allow_blank=True, required=False) last_data = serializers.SerializerMethodField() gather_state = serializers.SerializerMethodField() class Meta: model = Mpoint fields = "__all__" read_only_fields = EXCLUDE_FIELDS + ["belong_dept", "cate"] def create(self, validated_data): code = validated_data["code"] if Mpoint.objects.get_queryset(all=True).filter(code=code).exists(): raise ParseError("测点编号已存在") return super().create(validated_data) def get_last_data(self, obj): cache_mp = cache.get(Mpoint.cache_key(obj.code)) if isinstance(cache_mp, dict): last_data = cache_mp.get('last_data', {}) else: last_data = {} return last_data def get_gather_state(self, obj): cache_mp = cache.get(Mpoint.cache_key(obj.code)) if isinstance(cache_mp, dict): gather_state = cache_mp.get('gather_state', -2) else: gather_state = -2 return gather_state def validate(self, attrs): if "material" in attrs and attrs["material"]: attrs["cate"] = "material" if "mgroup" in attrs and attrs["mgroup"]: attrs["belong_dept"] = attrs["mgroup"].belong_dept formula = attrs.get("formula", "") if formula: pass return attrs # class MpLogSerializer(CustomModelSerializer): # mpoint_name = serializers.CharField(source='mpoint.name', read_only=True) # class Meta: # model = MpLog # fields = '__all__' # read_only_fields = EXCLUDE_FIELDS + ['mpoint_name'] class MpLogxSerializer(CustomModelSerializer): """Serializer for EnvData model""" class Meta: model = MpLogx fields = "__all__" class MpointStatSerializer(CustomModelSerializer): mpoint_name = serializers.CharField(source="mpoint.name", read_only=True) mpoint_nickname = serializers.CharField(source="mpoint.nickname", read_only=True) ep_monitored_name = serializers.CharField(source="mpoint.ep_monitored.name", read_only=True) ep_monitored_number = serializers.CharField(source="mpoint.ep_monitored.number", read_only=True) ep_monitored_power_kw = serializers.CharField(source="mpoint.ep_monitored.power_kw", read_only=True) ep_belong_name = serializers.CharField(source="mpoint.ep_belong.name", read_only=True) mgroup_name = serializers.CharField(source="mgroup.name", read_only=True) belong_dept_name = serializers.CharField(source="mgroup.belong_dept.name", read_only=True) sflog_start_time = serializers.DateTimeField(source="sflog.start_time", read_only=True) sflog_end_time = serializers.DateTimeField(source="sflog.end_time", read_only=True) class Meta: model = MpointStat fields = "__all__" read_only_fields = EXCLUDE_FIELDS + ["mpoint_name", "type", "year", "month", "day"] def check_required_keys(dictionary, keys): for key in keys: if key not in dictionary or not dictionary[key]: return False return True def create(self, validated_data): if MpointStat.objects.filter(mpoint=validated_data["mpoint"], sflog=validated_data["sflog"]).exists(): raise ParseError("该数据已录入") return super().create(validated_data) def validate(self, attrs): mpoint = attrs["mpoint"] if 'mgroup' not in attrs: raise ParseError("请选择工段") if mpoint.material and mpoint.type is Mpoint.MT_MANUAL and "sflog" in attrs and attrs["sflog"]: attrs["type"] = "sflog" sflog = attrs["sflog"] attrs["year_s"], attrs["month_s"], attrs["day_s"] = sflog.get_ymd attrs["mgroup"] = sflog.mgroup else: raise ParseError("该数据不支持手工录入") # if 'sflog' in attrs and attrs['sflog']: # else: # keys = ['hour', 'day_s', 'month_s', 'year_s'] # for ind, key in enumerate(keys): # if key in attrs and attrs['key']: # if not self.check_required_keys(attrs, keys[ind+1:]): # raise ParseError('缺少数据') # attrs['type'] = key return super().validate(attrs) def to_representation(self, instance): ret = super().to_representation(instance) my_dic_keys = list(ret.keys()) for key in my_dic_keys: ret_one_val = ret[key] if isinstance(ret_one_val, float): ret[key] = "{:.2f}".format(round(ret_one_val, 2)) return ret class EnStatUpdateSerializer(CustomModelSerializer): class Meta: model = EnStat fields = ["id", "note"] class EnStatSerializer(CustomModelSerializer): mgroup_name = serializers.CharField(source="mgroup.name", read_only=True) team_name = serializers.CharField(source="team.name", read_only=True) belong_dept_name = serializers.CharField(source="mgroup.belong_dept.name", read_only=True) class Meta: model = EnStat fields = "__all__" def to_representation(self, instance): ret = super().to_representation(instance) if 'run_sec' in ret: ret['run_hour'] = ret['run_sec'] / 3600 my_dic_keys = list(ret.keys()) for key in my_dic_keys: ret_one_val = ret[key] if isinstance(ret_one_val, float): if key in ["en_consume_unit"]: ret[key] = "{:.4f}".format(round(ret_one_val, 4)) else: ret[key] = "{:.2f}".format(round(ret_one_val, 2)) qua_data = ret.get("qua_data", {}) equip_elec_data = ret.get("equip_elec_data", {}) if qua_data: for item in qua_data: if item.get("rate_pass" )is None: ret[f'{item["material_name"]}_{item["testitem_name"].replace("-", "")}_rate_pass'] = 0 else: value = item["rate_pass"] rounded_value = round(value, 2) if value is not None else 0 formatted_value = "{:.2f}".format(rounded_value) ret[f'{item["material_name"]}_{item["testitem_name"].replace("-", "")}_rate_pass'] = formatted_value if equip_elec_data: for item in equip_elec_data: val = item.get("consume_unit", None) if val: val = "{:.2f}".format(round(val, 2)) ret[f'{item["equipment_name"]}_consume_unit'] = val # 根据material_name分组排序 if 'qua_data' in ret: ret['qua_data'] = sorted(ret['qua_data'], key=lambda x: x['material_name']) return ret class EnStat2Serializer(CustomModelSerializer): class Meta: model = EnStat2 fields = "__all__" def to_representation(self, instance): ret = super().to_representation(instance) my_dic_keys = list(ret.keys()) for key in my_dic_keys: ret_one_val = ret[key] if isinstance(ret_one_val, float): ret[key] = "{:.2f}".format(round(ret_one_val, 2)) return ret class ReCalSerializer(serializers.Serializer): start_time = serializers.DateTimeField(label="开始时间") end_time = serializers.DateTimeField(label="结束时间") class MpointStatCorrectSerializer(CustomModelSerializer): class Meta: model = MpointStat fields = ['val_correct', 'id'] class EnStatAnaSerializer(serializers.Serializer): start_date = serializers.DateField(label="开始日期") end_date = serializers.DateField(label="结束日期") class XscriptSerializer(CustomModelSerializer): myschedule_name = serializers.CharField(source="myschedule.name", read_only=True) enabled = serializers.BooleanField(source='periodictask.enabled', read_only=True) last_run_at = serializers.DateTimeField(source='periodictask.last_run_at', read_only=True) total_run_count = serializers.IntegerField(source='periodictask.total_run_count', read_only=True) class Meta: model = Xscript fields = "__all__" read_only_fields = EXCLUDE_FIELDS_BASE + ['periodictask', 'change_data'] def validate(self, attrs): code = attrs['code'] analyzer = CodeAnalyzer() analyzer.analyze(code) if analyzer.errors: raise ParseError(f'脚本错误:{analyzer.errors[0]}') return super().validate(attrs) @transaction.atomic def create(self, validated_data): ins: Xscript = super().create(validated_data) pobj = PeriodicTask() pobj.name = f'{ins.name}_{str(ins.id)[-8:]}' pobj.task = 'apps.enm.tasks.insert_mplogx_from_xscript' sch = ins.myschedule if sch.crontab: pobj.crontab = sch.crontab elif sch.interval: pobj.interval = sch.interval else: raise ParseError('不支持的定时策略') pobj.kwargs = json.dumps({'xscript_id': ins.id}) pobj.enabled = False pobj.save() ins.periodictask = pobj ins.save() return ins @transaction.atomic def update(self, instance, validated_data): ins = super().update(instance, validated_data) pobj = instance.periodictask pobj.name = f'{ins.name}_{str(ins.id)[-8:]}' sch = ins.myschedule if sch.crontab: pobj.crontab = sch.crontab pobj.interval = None elif sch.interval: pobj.interval = sch.interval pobj.crontab = None else: raise ParseError('不支持的定时策略') pobj.save() return ins class XscriptDetailSerializer(XscriptSerializer): last_run_data = serializers.SerializerMethodField() def get_last_run_data(self, obj): tr = TaskResult.objects.filter(task_kwargs__contains=obj.id).order_by('-date_done').first() if tr: return PTaskResultSerializer(instance=tr).data return None