fix: 能管的工段异常修改
This commit is contained in:
parent
6f058dc757
commit
2030812c18
|
@ -127,7 +127,7 @@ class CorrectViewSet(CustomGenericViewSet):
|
|||
|
||||
矫正工单流水号
|
||||
"""
|
||||
data = request.data
|
||||
data = request.data
|
||||
from apps.wf.models import Ticket
|
||||
from apps.wf.services import WfService
|
||||
from django.utils.timezone import localtime
|
||||
|
@ -150,10 +150,11 @@ class CorrectViewSet(CustomGenericViewSet):
|
|||
from apps.enm.models import Mpoint
|
||||
for mpoint in Mpoint.objects.exclude(mgroup=None):
|
||||
mgroup = mpoint.mgroup
|
||||
mpoint.mgroups_allocate = [{'mgroup': mgroup.id, 'mgroup_name': mgroup.name, 'ratio': 1}]
|
||||
mpoint.mgroups_allocate = [
|
||||
{'mgroup': mgroup.id, 'mgroup_name': mgroup.name, 'ratio': 1}]
|
||||
mpoint.save()
|
||||
return Response()
|
||||
|
||||
|
||||
@action(methods=['post'], detail=False, serializer_class=Serializer)
|
||||
def mpointstat(self, request, pk=None):
|
||||
"""矫正测点统计数据
|
||||
|
@ -194,7 +195,7 @@ class CorrectViewSet(CustomGenericViewSet):
|
|||
item.shift = item.sflog.shift
|
||||
item.save()
|
||||
return Response()
|
||||
|
||||
|
||||
# @action(methods=['post'], detail=False, serializer_class=Serializer)
|
||||
# def global_img_compressed(self, request, pk=None):
|
||||
# """矫正全景压缩照片
|
||||
|
@ -209,6 +210,7 @@ class CorrectViewSet(CustomGenericViewSet):
|
|||
# event.save()
|
||||
# return Response()
|
||||
|
||||
|
||||
class TestViewSet(CustomGenericViewSet):
|
||||
authentication_classes = ()
|
||||
permission_classes = ()
|
||||
|
@ -261,7 +263,8 @@ class TestViewSet(CustomGenericViewSet):
|
|||
m = importlib.import_module(module)
|
||||
f = getattr(m, func)
|
||||
if vdata['delay']:
|
||||
task = f.delay(*vdata.get('args', []), **vdata.get('kwargs', {})) # 同步执行
|
||||
task = f.delay(*vdata.get('args', []), **
|
||||
vdata.get('kwargs', {})) # 同步执行
|
||||
return Response({'task_id': task.id})
|
||||
else:
|
||||
f(*vdata.get('args', []), **vdata.get('kwargs', {}))
|
||||
|
@ -299,7 +302,8 @@ class TestViewSet(CustomGenericViewSet):
|
|||
from apps.hrm.services import HrmService
|
||||
# data = {'id': 25198, 'category': 'alarm', 'method': 'alarm.msg', 'info': {'orgName': '河北省', 'nodeCode': '1000096$7$0$0', 'deviceCode': '1000096', 'alarmCode': 'd38c98b842334581a8219b3125ca72d5', 'alarmPicture': '6ad010cf-ce45-11ec-9715-e4246c7d1635/20221123/1/dsf_43aee9e6-6ae2-11ed-9872-e4246c7d1635_42018473_42037732.jpg', 'nodeType': '2', 'alarmDate': 1669187805, 'alarmGrade': 2, 'isSave': False, 'unitType': 7, 'extend': {'deptName': '设备管理部', 'deptIdList': [25], 'acsChannelCode': '1000096$7$0$0', 'maskState': 0, 'enterOrExit': 1, 'openTypeStr': '人脸刷门', 'swingTime': '2022-11-23 15:16:45', 'deviceName': '厂区门入', 'personCode': '8jtfoa', 'openType': '61', 'isOverTemp': False, 'orgCode': '001', 'paperNumber': '61012419850304335X', 'errorDetail': '', 'from': 'evo-accesscontrol', 'id': 1044994923113353216, 'beginTime': 1669187805000, 'acsChannelName': '厂区门入_门禁通道_1', 'cardStatus': '0', 'faceImageUrl': ['http://10.99.5.24:8927/6ad010cf-ce45-11ec-9715-e4246c7d1635/20221123/1/dsf_43aee9e6-6ae2-11ed-9872-e4246c7d1635_42018473_42037732.jpg'], 'orgName': '河北省', 'openFailedCode': 0, 'sex': 1, 'deptId': '25', 'cardType': 0, 'curTemp': 35.5, 'deviceCode': '1000096', 'personName': '谭刚位', 'personImg': '6ae577ee-ce45-11ec-bb54-e4246c7d1635/20221110/1/3313679c-6092-11ed-b963-e4246c7d1635.jpg', 'openResult': 1, 'personId': 673, 'recordImage1': '6ad010cf-ce45-11ec-9715-e4246c7d1635/20221123/1/dsf_43aee9e6-6ae2-11ed-9872-e4246c7d1635_42018473_42037732.jpg', 'category': '0', 'cardNumber': '0525871590', 'rfidType': 0, 'age': 0}, 'alarmType': 61, 'channelSeq': 0, 'orgCode': '001', 'channelName': '厂区门入_门禁通道_1', 'alarmStat': 1, 'isEvent': True}, 'subsystem': 'evo-accesscontrol', 'userIds': None, 'sid': None, 'domainId': None, 'infoArray': None, 'protocol': None}
|
||||
# data = {'id': 29870, 'category': 'alarm', 'method': 'alarm.msg', 'info': {'orgName': '河北省', 'nodeCode': '1002222$7$0$0', 'deviceCode': '1002222', 'alarmCode': '191f4a8d0a2c4b6282448af04df6ec11', 'alarmPicture': '6ad010cf-ce45-11ec-9715-e4246c7d1635/20221124/1/dsf_b8662018-6b9c-11ed-9872-e4246c7d1635_51799202_51816153.jpg', 'nodeType': '2', 'alarmDate': 1669263013, 'alarmGrade': 2, 'isSave': False, 'unitType': 7, 'extend': {'deptName': '安全生产部', 'deptIdList': [28], 'acsChannelCode': '1002222$7$0$0', 'maskState': 3, 'enterOrExit': 3, 'openTypeStr': '人脸刷门', 'swingTime': '2022-11-24 12:10:13', 'deviceName': '办公楼考勤面板', 'personCode': '13911097513', 'openType': '61', 'orgCode': '001', 'paperNumber': '110107196804040335', 'errorDetail': '', 'from': 'evo-accesscontrol', 'id': 1045310360703340544, 'beginTime': 1669263013000, 'acsChannelName': '办公楼考勤面板_门禁通道_1', 'cardStatus': '0', 'faceImageUrl': ['http://10.99.5.24:8927/6ad010cf-ce45-11ec-9715-e4246c7d1635/20221124/1/dsf_b8662018-6b9c-11ed-9872-e4246c7d1635_51799202_51816153.jpg'], 'orgName': '河北省', 'openFailedCode': 0, 'sex': 1, 'deptId': '28', 'cardType': 0, 'deviceCode': '1002222', 'personName': '刘静元', 'personImg': '6ae577ee-ce45-11ec-bb54-e4246c7d1635/20220907/1/d841d821-2e67-11ed-b073-e4246c7d1635.jpg', 'openResult': 1, 'personId': 237, 'recordImage1': '6ad010cf-ce45-11ec-9715-e4246c7d1635/20221124/1/dsf_b8662018-6b9c-11ed-9872-e4246c7d1635_51799202_51816153.jpg', 'category': '0', 'cardNumber': '5973291203', 'rfidType': 0, 'age': 0}, 'alarmType': 61, 'channelSeq': 0, 'orgCode': '001', 'channelName': '办公楼考勤面板_门禁通道_1', 'alarmStat': 1, 'isEvent': True}, 'subsystem': 'evo-accesscontrol', 'userIds': None, 'sid': None, 'domainId': None, 'infoArray': None, 'protocol': None}
|
||||
data = {'id': 70781, 'category': 'alarm', 'method': 'alarm.msg', 'info': {'orgName': '河北省', 'nodeCode': '1002222$7$0$0', 'deviceCode': '1002222', 'alarmCode': '74ac9b9511774388a975dc5daa6ad8b9', 'alarmPicture': '6ad010cf-ce45-11ec-9715-e4246c7d1635/20230419/1/dsf_93e4c0ab-de83-11ed-af40-e4246c7d1635_45533104_45552146.jpg', 'nodeType': '2', 'alarmDate': 1681897834, 'alarmGrade': 2, 'isSave': False, 'unitType': 7, 'extend': {'deptName': '企业管理部', 'deptIdList': [21], 'acsChannelCode': '1002222$7$0$0', 'maskState': 0, 'enterOrExit': 3, 'openTypeStr': '人脸刷门', 'swingTime': '2023-04-19 17:50:34', 'deviceName': '办公楼考勤面板', 'personCode': '13731293508', 'openType': '61', 'orgCode': '001', 'paperNumber': '130634198612035821', 'errorDetail': '', 'from': 'evo-accesscontrol', 'id': 1098304215199125504, 'beginTime': 1681897834000, 'acsChannelName': '办公楼考勤面板_门禁通道_1', 'cardStatus': '0', 'faceImageUrl': ['http://10.99.5.24:8927/6ad010cf-ce45-11ec-9715-e4246c7d1635/20230419/1/dsf_93e4c0ab-de83-11ed-af40-e4246c7d1635_45533104_45552146.jpg'], 'orgName': '河北省', 'openFailedCode': 0, 'sex': 1, 'deptId': '21', 'cardType': 0, 'deviceCode': '1002222', 'personName': '李贝', 'personImg': '6ae577ee-ce45-11ec-bb54-e4246c7d1635/20220907/1/9ab9a1eb-2e74-11ed-b073-e4246c7d1635.jpg', 'openResult': 1, 'personId': 331, 'recordImage1': '6ad010cf-ce45-11ec-9715-e4246c7d1635/20230419/1/dsf_93e4c0ab-de83-11ed-af40-e4246c7d1635_45533104_45552146.jpg', 'category': '0', 'cardNumber': '6705501569', 'rfidType': 0, 'age': 0}, 'alarmType': 61, 'channelSeq': 0, 'orgCode': '001', 'channelName': '办公楼考勤面板_门禁通道_1', 'alarmStat': 1, 'isEvent': True}, 'subsystem': 'evo-accesscontrol', 'userIds': None, 'sid': None, 'domainId': None, 'infoArray': None, 'protocol': None}
|
||||
data = {'id': 70781, 'category': 'alarm', 'method': 'alarm.msg', 'info': {'orgName': '河北省', 'nodeCode': '1002222$7$0$0', 'deviceCode': '1002222', 'alarmCode': '74ac9b9511774388a975dc5daa6ad8b9', 'alarmPicture': '6ad010cf-ce45-11ec-9715-e4246c7d1635/20230419/1/dsf_93e4c0ab-de83-11ed-af40-e4246c7d1635_45533104_45552146.jpg', 'nodeType': '2', 'alarmDate': 1681897834, 'alarmGrade': 2, 'isSave': False, 'unitType': 7, 'extend': {'deptName': '企业管理部', 'deptIdList': [21], 'acsChannelCode': '1002222$7$0$0', 'maskState': 0, 'enterOrExit': 3, 'openTypeStr': '人脸刷门', 'swingTime': '2023-04-19 17:50:34', 'deviceName': '办公楼考勤面板', 'personCode': '13731293508', 'openType': '61', 'orgCode': '001', 'paperNumber': '130634198612035821', 'errorDetail': '', 'from': 'evo-accesscontrol', 'id': 1098304215199125504, 'beginTime': 1681897834000, 'acsChannelName': '办公楼考勤面板_门禁通道_1', 'cardStatus': '0', 'faceImageUrl': [
|
||||
'http://10.99.5.24:8927/6ad010cf-ce45-11ec-9715-e4246c7d1635/20230419/1/dsf_93e4c0ab-de83-11ed-af40-e4246c7d1635_45533104_45552146.jpg'], 'orgName': '河北省', 'openFailedCode': 0, 'sex': 1, 'deptId': '21', 'cardType': 0, 'deviceCode': '1002222', 'personName': '李贝', 'personImg': '6ae577ee-ce45-11ec-bb54-e4246c7d1635/20220907/1/9ab9a1eb-2e74-11ed-b073-e4246c7d1635.jpg', 'openResult': 1, 'personId': 331, 'recordImage1': '6ad010cf-ce45-11ec-9715-e4246c7d1635/20230419/1/dsf_93e4c0ab-de83-11ed-af40-e4246c7d1635_45533104_45552146.jpg', 'category': '0', 'cardNumber': '6705501569', 'rfidType': 0, 'age': 0}, 'alarmType': 61, 'channelSeq': 0, 'orgCode': '001', 'channelName': '办公楼考勤面板_门禁通道_1', 'alarmStat': 1, 'isEvent': True}, 'subsystem': 'evo-accesscontrol', 'userIds': None, 'sid': None, 'domainId': None, 'infoArray': None, 'protocol': None}
|
||||
HrmService.swipe(data=data)
|
||||
return Response()
|
||||
|
||||
|
@ -572,6 +576,6 @@ class TestViewSet(CustomGenericViewSet):
|
|||
|
||||
@action(methods=['post'], detail=False, serializer_class=Serializer, permission_classes=[])
|
||||
def test_cal(self, request, pk=None):
|
||||
from apps.wpm.tasks import cal_shut_hour
|
||||
cal_shut_hour('3397169058570170368')
|
||||
return Response()
|
||||
from apps.wpm.tasks import cal_exp_duration_hour
|
||||
cal_exp_duration_hour('3397169058570170368')
|
||||
return Response()
|
||||
|
|
|
@ -14,7 +14,8 @@ def translate_eval_formula(exp_str: str, year: int, month: int, day: int, hour:
|
|||
pattern = r"\${(.*?)}"
|
||||
matches = re.findall(pattern, exp_str)
|
||||
for match in matches:
|
||||
mpst = MpointStat.objects.filter(Q(mpoint__id=match)|Q(mpoint__name=match)|Q(mpoint__code=match), type='hour', year=year, month=month, day=day, hour=hour).first()
|
||||
mpst = MpointStat.objects.filter(Q(mpoint__id=match) | Q(mpoint__name=match) | Q(
|
||||
mpoint__code=match), type='hour', year=year, month=month, day=day, hour=hour).first()
|
||||
if mpst:
|
||||
exp_str = exp_str.replace(f"${{{match}}}", str(mpst.val))
|
||||
rval = eval(exp_str)
|
||||
|
@ -55,7 +56,7 @@ def get_day_s(year: int, month: int, day: int, hour: int, hour_split: int = 21):
|
|||
# month_s = data['month_s']
|
||||
# for item in data['qua_data']:
|
||||
# qua_rate[f'{item["material_name"]}_{item["testitem_name"]}'] = item["rate_pass"]
|
||||
|
||||
|
||||
# goal_dict = get_mgroup_goals(data['mgroup'], data['year_s'], False)
|
||||
# goal_data = {}
|
||||
# try:
|
||||
|
@ -76,27 +77,43 @@ def get_day_s(year: int, month: int, day: int, hour: int, hour_split: int = 21):
|
|||
# print(traceback.format_exc())
|
||||
# return goal_data, score
|
||||
|
||||
|
||||
def shutdown_or_startup(mplog: MpLog):
|
||||
from apps.wpm.models import StLog
|
||||
from apps.wpm.tasks import cal_shut_hour
|
||||
from apps.wpm.tasks import cal_exp_duration_hour
|
||||
from apps.wpm.services import get_sflog
|
||||
mpoint = mplog.mpoint
|
||||
mgroup = mpoint.mgroup
|
||||
last_stlog = StLog.objects.filter(mgroup=mgroup).order_by('start_time').last()
|
||||
last_stlog = StLog.objects.filter(
|
||||
mgroup=mgroup, is_shutdown=True).order_by('start_time').last() # 找到最后一次停机记录
|
||||
if last_stlog:
|
||||
if mplog.tag_update >= last_stlog.start_time: # 认为是有效信号
|
||||
if last_stlog.end_time is None and mplog.tag_val==1:
|
||||
if last_stlog.end_time is None and mplog.tag_val == 1: # 从停到开
|
||||
last_stlog.end_time = mplog.tag_update
|
||||
last_stlog.duration = (last_stlog.end_time - last_stlog.start_time).total_seconds()/3600
|
||||
last_stlog.duration = (
|
||||
last_stlog.end_time - last_stlog.start_time).total_seconds()/3600
|
||||
last_stlog.save()
|
||||
mgroup.is_runing = True
|
||||
mgroup.save()
|
||||
cal_shut_hour(last_stlog.id) # 触发停机时间分配
|
||||
elif last_stlog.end_time and mplog.tag_val==0 and mplog.tag_update > last_stlog.end_time:
|
||||
StLog.objects.create(mgroup=mgroup, end_time=None, start_time=mplog.tag_update)
|
||||
cal_exp_duration_hour(last_stlog.id) # 触发时间分配
|
||||
elif last_stlog.end_time and mplog.tag_val == 0 and mplog.tag_update > last_stlog.end_time: # 从开到停
|
||||
StLog.objects.create(
|
||||
title='停机',
|
||||
is_shutdown=True,
|
||||
mgroup=mgroup,
|
||||
end_time=None,
|
||||
start_time=mplog.tag_update,
|
||||
sflog=get_sflog(mgroup, mplog.tag_update)
|
||||
)
|
||||
mgroup.is_runing = False
|
||||
mgroup.save()
|
||||
else:
|
||||
StLog.objects.create(mgroup=mgroup, end_time=None, start_time=mplog.tag_update)
|
||||
StLog.objects.create(
|
||||
title='停机',
|
||||
is_shutdown=True,
|
||||
mgroup=mgroup,
|
||||
end_time=None,
|
||||
start_time=mplog.tag_update,
|
||||
sflog=get_sflog(mgroup, mplog.tag_update))
|
||||
mgroup.is_runing = False
|
||||
mgroup.save()
|
||||
|
|
@ -12,7 +12,7 @@ import datetime
|
|||
from django.db.models import Sum, Avg
|
||||
from dateutil import tz
|
||||
from django.conf import settings
|
||||
from apps.wpm.services import make_sflogs
|
||||
from apps.wpm.services import get_sflog
|
||||
from apps.mtm.models import Mgroup, Material
|
||||
from apps.fim.services import get_cost_unit, get_price_unit
|
||||
from apps.fim.models import Fee
|
||||
|
@ -156,13 +156,7 @@ def cal_mpointstat_hour(mpointId: str, year: int, month: int, day: int, hour: in
|
|||
mgroup = Mgroup.objects.get(id=allocate['mgroup'])
|
||||
ratio = allocate['ratio']
|
||||
# 查找并绑定值班记录
|
||||
sflog = SfLog.objects.filter(
|
||||
start_time__lt=dt, end_time__gte=dt, mgroup=mgroup).first()
|
||||
if sflog is None: # 需要创建值班记录
|
||||
make_sflogs(mgroup=mgroup, start_date=(
|
||||
dt-datetime.timedelta(days=1)).date(), end_date=dt.date())
|
||||
sflog = SfLog.objects.filter(
|
||||
start_time__lt=dt, end_time__gte=dt, mgroup=mgroup).first()
|
||||
sflog = get_sflog(mgroup, dt)
|
||||
year_s, month_s, day_s = sflog.get_ymd
|
||||
|
||||
params_hour_s = {'type': 'hour_s', 'mpoint': mpoint, 'sflog': sflog, 'mgroup': mgroup, 'year': year,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from django_filters import rest_framework as filters
|
||||
from apps.wpm.models import SfLog, SfLogExp, WMaterial, Mlog, Handover
|
||||
from apps.wpm.models import SfLog, StLog, WMaterial, Mlog, Handover
|
||||
['mgroup', 'shift', 'team', 'leader', 'team__belong_dept']
|
||||
|
||||
|
||||
|
@ -17,27 +17,18 @@ class SfLogFilter(filters.FilterSet):
|
|||
}
|
||||
|
||||
|
||||
class SfLogExpFilter(filters.FilterSet):
|
||||
is_st = filters.BooleanFilter(method='filter_is_st', label='是否停机')
|
||||
|
||||
class StLogFilter(filters.FilterSet):
|
||||
class Meta:
|
||||
model = SfLogExp
|
||||
model = StLog
|
||||
fields = {
|
||||
"mgroup": ["exact"],
|
||||
"mgroup__name": ["exact"],
|
||||
"start_time": ["day", "month", "year"],
|
||||
"end_time": ["isnull"],
|
||||
"sflog": ["exact"],
|
||||
"sflog__mgroup": ["exact"],
|
||||
"sflog__mgroup__name": ["exact"],
|
||||
"happen_time": ["day", "month", "year"],
|
||||
"sflog__end_time": ["day", "month", "year"],
|
||||
"stlog": ["exact"],
|
||||
"stlog__start_time": ["day", "month", "year"],
|
||||
"stlog__end_time": ["day", "month", "year"]
|
||||
"sflogs": ["exact"]
|
||||
}
|
||||
|
||||
def filter_is_st(self, queryset, name, value):
|
||||
if value:
|
||||
return queryset.exclude(stlog=None)
|
||||
return queryset.filter(stlog=None)
|
||||
|
||||
|
||||
class WMaterialFilter(filters.FilterSet):
|
||||
class Meta:
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
# Generated by Django 3.2.12 on 2023-11-22 07:51
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wpm', '0033_sflog_total_hour'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='sflogexp',
|
||||
name='cate',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='sflogexp',
|
||||
name='handler',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='sflogexp',
|
||||
name='happen_time',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='sflogexp',
|
||||
name='is_current_down',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='sflogexp',
|
||||
name='measure',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='sflogexp',
|
||||
name='reason',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='sflogexp',
|
||||
name='title',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='sflogexp',
|
||||
name='note',
|
||||
field=models.TextField(blank=True, default='', verbose_name='处理备注'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='stlog',
|
||||
name='cate',
|
||||
field=models.CharField(blank=True, max_length=10, null=True, verbose_name='原因类别'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='stlog',
|
||||
name='handler',
|
||||
field=models.CharField(default='', max_length=100, verbose_name='处理人'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='stlog',
|
||||
name='is_shutdown',
|
||||
field=models.BooleanField(default=False, verbose_name='是否是停机'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='stlog',
|
||||
name='measure',
|
||||
field=models.TextField(default='', max_length=100, verbose_name='处置措施'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='stlog',
|
||||
name='reason',
|
||||
field=models.TextField(default='', max_length=100, verbose_name='事件原因'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='stlog',
|
||||
name='sflog',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='wpm.sflog', verbose_name='发生时所在值班'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='stlog',
|
||||
name='sflogs',
|
||||
field=models.ManyToManyField(related_name='stlog_sflogs', through='wpm.SfLogExp', to='wpm.SfLog', verbose_name='关联所有当班'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='stlog',
|
||||
name='title',
|
||||
field=models.CharField(default='', max_length=20, verbose_name='异常名称'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='sflog',
|
||||
name='stlogs',
|
||||
field=models.ManyToManyField(related_name='sflog_stlogs', through='wpm.SfLogExp', to='wpm.StLog', verbose_name='关联异常记录'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='sflogexp',
|
||||
name='duration',
|
||||
field=models.FloatField(blank=True, null=True, verbose_name='持续时长(h)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='sflogexp',
|
||||
name='stlog',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wpm.stlog', verbose_name='关联异常记录'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='stlog',
|
||||
name='duration',
|
||||
field=models.FloatField(blank=True, null=True, verbose_name='持续时间(h)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='stlog',
|
||||
name='end_time',
|
||||
field=models.DateTimeField(blank=True, null=True, verbose_name='结束时间'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='stlog',
|
||||
name='start_time',
|
||||
field=models.DateTimeField(verbose_name='发生时间'),
|
||||
),
|
||||
]
|
|
@ -10,17 +10,6 @@ from apps.system.models import Dept
|
|||
# Create your models here.
|
||||
|
||||
|
||||
class StLog(CommonADModel):
|
||||
"""
|
||||
停机记录
|
||||
"""
|
||||
mgroup = models.ForeignKey(
|
||||
Mgroup, verbose_name='关联工段', on_delete=models.CASCADE)
|
||||
start_time = models.DateTimeField('停机开始')
|
||||
end_time = models.DateTimeField('停机结束', null=True, blank=True)
|
||||
duration = models.FloatField('停机时长(h)', null=True, blank=True)
|
||||
|
||||
|
||||
class SfLog(CommonADModel):
|
||||
"""值班记录
|
||||
"""
|
||||
|
@ -37,7 +26,7 @@ class SfLog(CommonADModel):
|
|||
end_time = models.DateTimeField('值班结束')
|
||||
note = models.TextField('其他备注', null=True, blank=True)
|
||||
stlogs = models.ManyToManyField(
|
||||
'wpm.stlog', verbose_name='关联停机记录', through='wpm.sflogexp')
|
||||
'wpm.stlog', verbose_name='关联异常记录', through='wpm.sflogexp', related_name='sflog_stlogs')
|
||||
last_test_time = models.DateTimeField('最后质检时间', null=True, blank=True)
|
||||
total_hour_now = models.FloatField('总时长动', default=0)
|
||||
total_hour = models.FloatField('总时长', default=12)
|
||||
|
@ -53,22 +42,37 @@ class SfLog(CommonADModel):
|
|||
return end_time_local.year, end_time_local.month, end_time_local.day
|
||||
|
||||
|
||||
class SfLogExp(CommonADModel):
|
||||
class StLog(CommonADModel):
|
||||
"""
|
||||
生产异常情况记录
|
||||
异常记录
|
||||
"""
|
||||
title = models.CharField('异常名称', max_length=20, default='')
|
||||
is_shutdown = models.BooleanField('是否是停机', default=False)
|
||||
mgroup = models.ForeignKey(
|
||||
Mgroup, verbose_name='关联工段', on_delete=models.CASCADE)
|
||||
sflog = models.ForeignKey(
|
||||
SfLog, on_delete=models.CASCADE, verbose_name='关联值班记录')
|
||||
stlog = models.ForeignKey(
|
||||
StLog, verbose_name='关联停机记录', on_delete=models.CASCADE, null=True, blank=True)
|
||||
title = models.CharField('异常名称', max_length=20)
|
||||
happen_time = models.DateTimeField('发生时间', null=True, blank=True)
|
||||
SfLog, on_delete=models.CASCADE, verbose_name='发生时所在值班', null=True, blank=True)
|
||||
sflogs = models.ManyToManyField(
|
||||
'wpm.sflog', verbose_name='关联所有当班', through='wpm.sflogexp', related_name='stlog_sflogs')
|
||||
start_time = models.DateTimeField('发生时间')
|
||||
end_time = models.DateTimeField('结束时间', null=True, blank=True)
|
||||
duration = models.FloatField('持续时间(h)', null=True, blank=True)
|
||||
cate = models.CharField('原因类别', max_length=10, null=True, blank=True)
|
||||
reason = models.TextField('事件原因', default='', max_length=100)
|
||||
measure = models.TextField('处置措施', default='', max_length=100)
|
||||
handler = models.CharField('处理人', default='', max_length=100)
|
||||
is_current_down = models.BooleanField('是否本班停机', default=False)
|
||||
duration = models.FloatField('停机时长(h)', null=True, blank=True)
|
||||
|
||||
|
||||
class SfLogExp(CommonADModel):
|
||||
"""
|
||||
异常处理
|
||||
"""
|
||||
sflog = models.ForeignKey(
|
||||
SfLog, on_delete=models.CASCADE, verbose_name='关联值班记录')
|
||||
stlog = models.ForeignKey(
|
||||
StLog, verbose_name='关联异常记录', on_delete=models.CASCADE)
|
||||
duration = models.FloatField('持续时长(h)', null=True, blank=True)
|
||||
note = models.TextField('处理备注', default='', blank=True)
|
||||
|
||||
|
||||
class WMaterial(CommonBDModel):
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
from apps.utils.constants import EXCLUDE_FIELDS
|
||||
from apps.utils.serializers import CustomModelSerializer
|
||||
from rest_framework import serializers
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.exceptions import ValidationError, ParseError
|
||||
from datetime import datetime
|
||||
|
||||
from .models import SfLog, StLog, SfLogExp, WMaterial, Mlog, Handover, Mlogb, AttLog
|
||||
from apps.system.models import Dept, User
|
||||
from apps.system.serializers import UserSimpleSerializer
|
||||
from apps.pm.models import Mtask
|
||||
from apps.wpm.tasks import cal_enstat_when_pcoal_heat_change, cal_enstat_when_team_change
|
||||
from apps.wpm.tasks import cal_enstat_when_pcoal_heat_change, cal_enstat_when_team_change, cal_exp_duration_hour
|
||||
from apps.wpm.services import get_sflog
|
||||
from apps.mtm.models import Mgroup, TeamMember, Shift
|
||||
from apps.mtm.serializers import MaterialSimpleSerializer
|
||||
from django.db import transaction
|
||||
|
@ -16,10 +18,62 @@ from django.utils import timezone
|
|||
|
||||
class StLogSerializer(CustomModelSerializer):
|
||||
mgroup_name = serializers.CharField(source='mgroup.name', read_only=True)
|
||||
current_sflog = serializers.CharField(label='当前处理值班', write_only=True)
|
||||
current_note = serializers.CharField(
|
||||
label='值班处理备注', write_only=True, allow_blank=True)
|
||||
|
||||
class Meta:
|
||||
model = StLog
|
||||
fields = '__all__'
|
||||
read_only_fields = EXCLUDE_FIELDS + \
|
||||
['is_shutdown', 'sflog', 'duration']
|
||||
|
||||
def create(self, validated_data):
|
||||
current_sflog = validated_data.pop('current_sflog')
|
||||
current_note = validated_data.pop('note', '')
|
||||
with transaction.atomic():
|
||||
validated_data['sflog'] = get_sflog(
|
||||
validated_data['mgroup'], validated_data['start_time'])
|
||||
if current_sflog != validated_data['sflog']:
|
||||
raise ParseError('值班时间与发生时间不一致')
|
||||
instance = super().create(validated_data)
|
||||
SfLogExp.objects.create(
|
||||
sflog=current_sflog, stlog=instance, create_by=self.context['request'].user, note=current_note)
|
||||
return instance
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
if instance.is_shutdown: # 停机不可编辑end_time
|
||||
validated_data.pop('end_time', None)
|
||||
if instance.end_time:
|
||||
raise ParseError('该异常已结束无需编辑')
|
||||
with transaction.atomic():
|
||||
validated_data.pop('mgroup', None)
|
||||
validated_data.pop('start_time', None)
|
||||
end_time = validated_data.pop('end_time', None)
|
||||
if end_time: # 需要把涉及到的sflog都拉入
|
||||
cal_exp_duration_hour(instance.id)
|
||||
current_sflog = validated_data.pop('current_sflog')
|
||||
current_note = validated_data.pop('current_note', '')
|
||||
instance = super().update(instance, validated_data)
|
||||
try:
|
||||
sflogexp = SfLogExp.objects.get(
|
||||
stlog=instance.stlog, sflog=current_sflog)
|
||||
sflogexp.note = current_note
|
||||
sflogexp.save()
|
||||
except SfLogExp.DoesNotExist:
|
||||
raise ParseError('该异常无需本班填写')
|
||||
return instance
|
||||
|
||||
def validate(self, attrs):
|
||||
start_time: datetime = attrs['start_time']
|
||||
end_time: datetime = attrs.get('end_time', None)
|
||||
if end_time:
|
||||
if end_time > start_time:
|
||||
attrs['duration'] = (
|
||||
end_time - start_time).total_seconds / 3600
|
||||
else:
|
||||
raise ParseError('结束时间应大于开始时间')
|
||||
return super().validate(attrs)
|
||||
|
||||
|
||||
class SfLogSerializer(CustomModelSerializer):
|
||||
|
@ -68,17 +122,17 @@ class SfLogSerializer(CustomModelSerializer):
|
|||
|
||||
|
||||
class SflogExpSerializer(CustomModelSerializer):
|
||||
mgroup = serializers.CharField(source='sflog.mgroup.id', read_only=True)
|
||||
mgroup_name = serializers.CharField(
|
||||
source='sflog.mgroup.name', read_only=True)
|
||||
stlog_ = StLogSerializer(source='stlog', read_only=True)
|
||||
happen_time = serializers.DateTimeField(required=True, label='发生时间')
|
||||
cate = serializers.CharField(required=True, label='原因类别')
|
||||
# mgroup = serializers.CharField(source='sflog.mgroup.id', read_only=True)
|
||||
# mgroup_name = serializers.CharField(
|
||||
# source='sflog.mgroup.name', read_only=True)
|
||||
# stlog_ = StLogSerializer(source='stlog', read_only=True)
|
||||
# happen_time = serializers.DateTimeField(required=True, label='发生时间')
|
||||
# cate = serializers.CharField(required=True, label='原因类别')
|
||||
|
||||
class Meta:
|
||||
model = SfLogExp
|
||||
fields = '__all__'
|
||||
read_only_fields = EXCLUDE_FIELDS + ['stlog', 'is_current_down']
|
||||
read_only_fields = EXCLUDE_FIELDS + ['sflog', 'stlog', 'duration']
|
||||
|
||||
|
||||
class WMaterialSerializer(CustomModelSerializer):
|
||||
|
|
|
@ -16,6 +16,17 @@ from apps.mtm.models import Mgroup, Shift, Material, Route
|
|||
from .models import SfLog, SfLogExp, WMaterial, Mlog, Mlogb, Handover
|
||||
|
||||
|
||||
def get_sflog(mgroup: Mgroup, happen_time: datetime):
|
||||
sflog = SfLog.objects.filter(
|
||||
start_time__lt=happen_time, end_time__gte=happen_time, mgroup=mgroup).first()
|
||||
if sflog is None: # 需要创建值班记录
|
||||
make_sflogs(mgroup=mgroup, start_date=(
|
||||
happen_time-datetime.timedelta(days=1)).date(), end_date=happen_time.date())
|
||||
sflog = SfLog.objects.filter(
|
||||
start_time__lt=happen_time, end_time__gte=happen_time, mgroup=mgroup).first()
|
||||
return sflog
|
||||
|
||||
|
||||
def make_sflogs(mgroup: Mgroup, start_date: datetime.date, end_date: datetime.date, create_by=None):
|
||||
shift_rule = mgroup.shift_rule
|
||||
shifts = Shift.objects.filter(rule=shift_rule) # 根据排班规则制定排班记录
|
||||
|
|
|
@ -58,33 +58,34 @@ def get_total_hour_now(sflogId: str):
|
|||
|
||||
|
||||
@shared_task(base=CustomTask)
|
||||
def cal_shut_hour(stlogId: str):
|
||||
def cal_exp_duration_hour(stlogId: str):
|
||||
"""
|
||||
计算停机记录对应的班停时长
|
||||
计算异常记录对应的每班持续时间
|
||||
"""
|
||||
from apps.enm.tasks import cal_enstat
|
||||
from apps.enm.tasks import cal_enstat # 如果是停机需要进行统计停机时长
|
||||
if stlogId:
|
||||
stlogs = StLog.objects.filter(id=stlogId)
|
||||
else:
|
||||
else: # 不传就默认更新所有的
|
||||
stlogs = StLog.objects.filter(end_time=None)
|
||||
now = timezone.now()
|
||||
for stlog in stlogs:
|
||||
need_cal_enstat = True
|
||||
if stlog.is_shutdown is False:
|
||||
need_cal_enstat = False
|
||||
st_start = stlog.start_time
|
||||
if st_start >= now:
|
||||
break
|
||||
if stlog.end_time is None: # 说明停机还未结束,此时也需要计算duration
|
||||
if stlog.end_time is None: # 说明异常还未结束,此时也需要计算duration
|
||||
st_end = now
|
||||
else:
|
||||
st_end = stlog.end_time
|
||||
sf_qs = SfLog.objects.filter(mgroup=stlog.mgroup)
|
||||
sf_qs = (sf_qs.filter(start_time__gte=st_start, start_time__lt=st_end) | sf_qs.filter(end_time__gt=st_start,
|
||||
end_time__lte=st_end) | sf_qs.filter(start_time__lte=st_start, end_time__gte=st_end)).order_by('start_time').distinct()
|
||||
SfLogExp.objects.filter(stlog=stlog, sflog__in=sf_qs).delete()
|
||||
for ind, sflog in enumerate(sf_qs):
|
||||
is_current_down = False
|
||||
if ind == 0:
|
||||
is_current_down = True
|
||||
sflogexp, _ = SfLogExp.objects.get_or_create(stlog=stlog, sflog=sflog, defaults={
|
||||
'stlog': stlog, 'sflog': sflog, 'is_current_down': is_current_down, 'title': '停机'})
|
||||
'stlog': stlog, 'sflog': sflog})
|
||||
# 计算duration
|
||||
sf_end, sf_start = sflog.end_time, sflog.start_time
|
||||
duration_item_delta = min(sf_end, st_end) - max(sf_start, st_start)
|
||||
|
@ -95,18 +96,19 @@ def cal_shut_hour(stlogId: str):
|
|||
duration_item = total_seconds/3600
|
||||
sflogexp.duration = duration_item
|
||||
sflogexp.save()
|
||||
# 计算每班的总停机时间
|
||||
ret = SfLogExp.objects.filter(sflog=sflog).exclude(
|
||||
stlog=None).aggregate(sum=Sum('duration'))
|
||||
if ret.get('sum', 0):
|
||||
sflog.shut_hour = ret['sum']
|
||||
sflog.save()
|
||||
# 更新sflog总时长
|
||||
if sflog.end_time > now:
|
||||
get_total_hour_now(sflog.id)
|
||||
if stlogId:
|
||||
cal_enstat('sflog', sflog.id, sflog.mgroup.id, None, None, None,
|
||||
None, None, None, None, cascade=True, cal_attrs=['run_hour'])
|
||||
if need_cal_enstat:
|
||||
# 计算每班的总停机时间
|
||||
ret = SfLogExp.objects.filter(
|
||||
sflog=sflog, stlog__is_shutdown=True).aggregate(sum=Sum('duration'))
|
||||
if ret.get('sum', 0):
|
||||
sflog.shut_hour = ret['sum']
|
||||
sflog.save()
|
||||
# 更新sflog总时长
|
||||
if sflog.end_time > now:
|
||||
get_total_hour_now(sflog.id)
|
||||
if stlogId:
|
||||
cal_enstat('sflog', sflog.id, sflog.mgroup.id, None, None, None,
|
||||
None, None, None, None, cascade=True, cal_attrs=['run_hour'])
|
||||
|
||||
|
||||
@shared_task(base=CustomTask)
|
||||
|
|
|
@ -13,7 +13,7 @@ from apps.pm.models import Mtask
|
|||
from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet
|
||||
from apps.utils.mixins import BulkCreateModelMixin
|
||||
|
||||
from .filters import SfLogExpFilter, SfLogFilter, WMaterialFilter, MlogFilter, HandoverFilter
|
||||
from .filters import StLogFilter, SfLogFilter, WMaterialFilter, MlogFilter, HandoverFilter
|
||||
from .models import SfLog, SfLogExp, StLog, WMaterial, Mlog, Handover, Mlogb, AttLog
|
||||
from .serializers import (SflogExpSerializer, SfLogSerializer, StLogSerializer, WMaterialSerializer,
|
||||
MlogSerializer, MlogRelatedSerializer, DeptBatchSerializer, HandoverSerializer,
|
||||
|
@ -22,19 +22,24 @@ from .services import mlog_submit, update_mtask, handover_submit
|
|||
# Create your views here.
|
||||
|
||||
|
||||
class StLogViewSet(ListModelMixin, CustomGenericViewSet):
|
||||
class StLogViewSet(CustomModelViewSet):
|
||||
"""
|
||||
list:停机记录
|
||||
list:异常记录
|
||||
|
||||
停机记录
|
||||
异常记录
|
||||
"""
|
||||
perms_map = {'get': '*'}
|
||||
queryset = StLog.objects.all()
|
||||
serializer_class = StLogSerializer
|
||||
select_related_fields = ['mgroup']
|
||||
filterset_fields = ['mgroup']
|
||||
filterset_class = StLogFilter
|
||||
ordering = ['-start_time']
|
||||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
obj: StLog = self.get_object()
|
||||
if obj.is_shutdown:
|
||||
raise ParseError('停机记录不可删除')
|
||||
return super().destroy(request, *args, **kwargs)
|
||||
|
||||
|
||||
class SfLogViewSet(UpdateModelMixin, ListModelMixin, DestroyModelMixin, CustomGenericViewSet):
|
||||
"""
|
||||
|
@ -76,16 +81,16 @@ class SfLogViewSet(UpdateModelMixin, ListModelMixin, DestroyModelMixin, CustomGe
|
|||
return Response(sr.data)
|
||||
|
||||
|
||||
class SfLogExpViewSet(CustomModelViewSet):
|
||||
class SfLogExpViewSet(ListModelMixin, UpdateModelMixin, CustomGenericViewSet):
|
||||
"""
|
||||
list:生产异常动态
|
||||
list:异常值班处理
|
||||
|
||||
生产异常动态
|
||||
异常值班处理
|
||||
"""
|
||||
queryset = SfLogExp.objects.all()
|
||||
serializer_class = SflogExpSerializer
|
||||
select_related_fields = ['sflog', 'sflog__mgroup', 'stlog']
|
||||
filterset_class = SfLogExpFilter
|
||||
filterset_fields = ['sflog', 'stlog']
|
||||
|
||||
|
||||
class WMaterialViewSet(ListModelMixin, CustomGenericViewSet):
|
||||
|
|
Loading…
Reference in New Issue