From 5f9ef83c6e8d6bbec2c64d35a1ec308042ba9e1b Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 14 Jun 2023 15:30:51 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84enm=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/em/migrations/0001_initial.py | 51 ++++++ apps/em/migrations/__init__.py | 0 apps/enm/migrations/0001_initial.py | 249 ++++++++++++++++++++++++++++ apps/enm/models.py | 76 ++++++++- apps/enm/serializers.py | 32 +++- apps/enm/services.py | 0 apps/enm/tasks.py | 72 +++++++- apps/enm/urls.py | 6 +- apps/enm/views.py | 49 +++++- 9 files changed, 515 insertions(+), 20 deletions(-) create mode 100644 apps/em/migrations/0001_initial.py create mode 100644 apps/em/migrations/__init__.py create mode 100644 apps/enm/migrations/0001_initial.py create mode 100644 apps/enm/services.py diff --git a/apps/em/migrations/0001_initial.py b/apps/em/migrations/0001_initial.py new file mode 100644 index 00000000..cf0c24d0 --- /dev/null +++ b/apps/em/migrations/0001_initial.py @@ -0,0 +1,51 @@ +# Generated by Django 3.2.12 on 2023-06-09 09:13 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('system', '0002_myschedule'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Equipment', + fields=[ + ('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('type', models.PositiveSmallIntegerField(choices=[(10, '生产设备'), (20, '计量检测工具')], default=10, verbose_name='类型')), + ('name', models.CharField(max_length=50, verbose_name='设备名称')), + ('number', models.CharField(max_length=50, unique=True, verbose_name='设备编号')), + ('model', models.CharField(blank=True, default='', max_length=60, verbose_name='规格型号')), + ('factory', models.CharField(blank=True, default='', max_length=50, verbose_name='生产厂')), + ('production_date', models.DateField(blank=True, null=True, verbose_name='生产日期')), + ('buy_date', models.DateField(blank=True, null=True, verbose_name='购置日期')), + ('state', models.PositiveIntegerField(choices=[(10, '完好'), (20, '限用'), (30, '在修'), (40, '禁用'), (50, '报废')], default=10, verbose_name='设备状态')), + ('parameter', models.TextField(blank=True, default='', verbose_name='技术参数')), + ('place', models.CharField(blank=True, default='', max_length=50, verbose_name='安装/存放位置')), + ('count', models.PositiveIntegerField(default=1, verbose_name='数量')), + ('description', models.CharField(default='', max_length=200, null=True, verbose_name='描述')), + ('cycle', models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='校准或检定周期(月)')), + ('check_date', models.DateField(blank=True, null=True, verbose_name='最近校准检查日期')), + ('next_check_date', models.DateField(blank=True, null=True, verbose_name='预计下次校准检查日期')), + ('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='equipment_belong_dept', to='system.dept', verbose_name='所属部门')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='equipment_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('keeper', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='责任人')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='equipment_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'verbose_name': '设备信息', + 'verbose_name_plural': '设备信息', + }, + ), + ] diff --git a/apps/em/migrations/__init__.py b/apps/em/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/enm/migrations/0001_initial.py b/apps/enm/migrations/0001_initial.py new file mode 100644 index 00000000..cedb0997 --- /dev/null +++ b/apps/enm/migrations/0001_initial.py @@ -0,0 +1,249 @@ +# Generated by Django 3.2.12 on 2023-06-14 07:27 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('em', '0001_initial'), + ('system', '0002_myschedule'), + ] + + operations = [ + migrations.CreateModel( + name='Mgroup', + fields=[ + ('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('name', models.CharField(max_length=50, verbose_name='名称')), + ('cate', models.CharField(default='section', max_length=50, verbose_name='分类')), + ('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mgroup_belong_dept', to='system.dept', verbose_name='所属部门')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mgroup_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mgroup_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'verbose_name': '测点集', + }, + ), + migrations.CreateModel( + name='SfLog', + fields=[ + ('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('start_time', models.DateTimeField(verbose_name='值班开始')), + ('end_time', models.DateTimeField(verbose_name='值班结束')), + ('note', models.TextField(blank=True, null=True, verbose_name='生产情况记录')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sflog_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('leader', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='班长')), + ('mgroup', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='enm.mgroup', verbose_name='关联工段')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='StLog', + fields=[ + ('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('start_time', models.DateTimeField(verbose_name='停机开始')), + ('end_time', models.DateTimeField(blank=True, null=True, verbose_name='停机结束')), + ('duration', models.FloatField(blank=True, null=True, verbose_name='停机时长(h)')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='stlog_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('mgroup', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='enm.mgroup', verbose_name='关联工段')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='stlog_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Team', + fields=[ + ('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('name', models.CharField(max_length=50, verbose_name='名称')), + ('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='team_belong_dept', to='system.dept', verbose_name='所属部门')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='team_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('leader', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='班长')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='team_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='StSfLog', + fields=[ + ('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('is_current_down', models.BooleanField(default=False, verbose_name='是否本班停机')), + ('reason', models.TextField(blank=True, null=True, verbose_name='停机原因')), + ('sflog', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='enm.sflog', verbose_name='关联值班记录')), + ('stlog', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='enm.stlog', verbose_name='关联停机记录')), + ], + options={ + 'ordering': ['sflog__start_time'], + }, + ), + migrations.CreateModel( + name='Shift', + fields=[ + ('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('name', models.CharField(max_length=50, verbose_name='名称')), + ('start_time_o', models.TimeField(verbose_name='开始时间')), + ('end_time_o', models.TimeField(verbose_name='结束时间')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='shift_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='shift_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'verbose_name': '班次', + }, + ), + migrations.AddField( + model_name='sflog', + name='shift', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='enm.shift', verbose_name='当班班次'), + ), + migrations.AddField( + model_name='sflog', + name='stlogs', + field=models.ManyToManyField(through='enm.StSfLog', to='enm.StLog', verbose_name='关联停机记录'), + ), + migrations.AddField( + model_name='sflog', + name='team', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='enm.team', verbose_name='班组'), + ), + migrations.AddField( + model_name='sflog', + name='update_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sflog_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人'), + ), + migrations.CreateModel( + name='Product', + fields=[ + ('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('name', models.CharField(max_length=50, verbose_name='名称')), + ('code', models.CharField(blank=True, max_length=50, null=True, verbose_name='编号')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='product_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='product_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'verbose_name': '产品', + }, + ), + migrations.CreateModel( + name='Mpoint', + fields=[ + ('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('name', models.CharField(max_length=50, verbose_name='测点名称')), + ('code', models.CharField(max_length=50, unique=True, verbose_name='测点编号')), + ('unit', models.CharField(max_length=50, verbose_name='单位')), + ('cate', models.CharField(default='elec', max_length=50, verbose_name='分类')), + ('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mpoint_belong_dept', to='system.dept', verbose_name='所属部门')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mpoint_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('ep_belong', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mp_ep_belong', to='em.equipment', verbose_name='属于哪个设备')), + ('ep_monitored', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mp_ep_monitored', to='em.equipment', verbose_name='监测哪个设备')), + ('mgroup', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='enm.mgroup', verbose_name='所在集合')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mpoint_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='MpLog', + fields=[ + ('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('tag_id', models.BigIntegerField(db_index=True, verbose_name='记录ID')), + ('tag_code', models.CharField(max_length=50, verbose_name='测点编号')), + ('tag_update', models.DateTimeField(verbose_name='更新时间')), + ('tag_val', models.FloatField(verbose_name='当前值')), + ('mpoint', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='enm.mpoint', verbose_name='关联测点')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='HourStat', + fields=[ + ('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('year', models.PositiveSmallIntegerField(verbose_name='年')), + ('month', models.PositiveSmallIntegerField(verbose_name='月')), + ('day', models.PositiveSmallIntegerField(verbose_name='日')), + ('hour', models.PositiveSmallIntegerField(verbose_name='时')), + ('val', models.FloatField(default=0, verbose_name='统计值')), + ('is_calculated', models.BooleanField(default=False, verbose_name='是否计算过')), + ('mpoint', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='enm.mpoint', verbose_name='关联测点')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='Goal', + fields=[ + ('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('year', models.PositiveSmallIntegerField(verbose_name='年')), + ('goal_name', models.CharField(help_text='总产量/台时产量/单位产品分布电耗/', max_length=50, verbose_name='目标名称')), + ('goal_val', models.FloatField(verbose_name='全年目标值')), + ('goal_val_1', models.FloatField(verbose_name='1月份目标值')), + ('goal_val_2', models.FloatField(verbose_name='2月份目标值')), + ('goal_val_3', models.FloatField(verbose_name='3月份目标值')), + ('goal_val_4', models.FloatField(verbose_name='4月份目标值')), + ('goal_val_5', models.FloatField(verbose_name='5月份目标值')), + ('goal_val_6', models.FloatField(verbose_name='6月份目标值')), + ('goal_val_7', models.FloatField(verbose_name='7月份目标值')), + ('goal_val_8', models.FloatField(verbose_name='8月份目标值')), + ('goal_val_9', models.FloatField(verbose_name='9月份目标值')), + ('goal_val_10', models.FloatField(verbose_name='10月份目标值')), + ('goal_val_11', models.FloatField(verbose_name='11月份目标值')), + ('goal_val_12', models.FloatField(verbose_name='12月份目标值')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='goal_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('mgroup', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='enm.mgroup', verbose_name='关联工段')), + ('product', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='enm.product', verbose_name='关联产品')), + ('team', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='enm.team', verbose_name='关联班组')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='goal_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/apps/enm/models.py b/apps/enm/models.py index 3426fd93..58afd33c 100644 --- a/apps/enm/models.py +++ b/apps/enm/models.py @@ -21,10 +21,11 @@ class Shift(CommonAModel): class Meta: verbose_name = '班次' -class Mgroup(CommonBDModel): +class Mgroup(CommonBModel): """测点集 """ name = models.CharField('名称', max_length=50) + cate = models.CharField('分类', max_length=50, default='section') # section是工段 class Meta: verbose_name = '测点集' @@ -41,29 +42,88 @@ class Mpoint(CommonBDModel): """测点 """ name = models.CharField('测点名称', max_length=50) - code = models.CharField('测点编号', max_length=50) + code = models.CharField('测点编号', max_length=50, unique=True) unit = models.CharField('单位', max_length=50) - + cate = models.CharField('分类', max_length=50, default='elec') ep_monitored = models.ForeignKey('em.equipment', verbose_name='监测哪个设备', related_name='mp_ep_monitored', on_delete=models.SET_NULL, null=True, blank=True) ep_belong = models.ForeignKey('em.equipment', verbose_name='属于哪个设备', related_name='mp_ep_belong', on_delete=models.SET_NULL, null=True, blank=True) mgroup = models.ForeignKey('enm.mgroup', verbose_name='所在集合', on_delete=models.SET_NULL, null=True, blank=True) -class Mrecord(BaseModel): +class MpLog(BaseModel): """测点原始记录 """ mpoint = models.ForeignKey(Mpoint, verbose_name='关联测点', on_delete=models.SET_NULL, null=True, blank=True) - tag_id = models.BigIntegerField('记录ID') + tag_id = models.BigIntegerField('记录ID', db_index=True) tag_code = models.CharField('测点编号', max_length=50) tag_update = models.DateTimeField('更新时间') tag_val = models.FloatField('当前值') +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 Drecord(CommonADModel): + +class SfLog(CommonADModel): """值班记录 """ + mgroup = models.ForeignKey(Mgroup, verbose_name='关联工段', on_delete=models.CASCADE) team = models.ForeignKey(Team, verbose_name='班组', on_delete=models.CASCADE) - shit = models.ForeignKey(Shift, verbose_name='当班班次', on_delete=models.CASCADE) + shift = models.ForeignKey(Shift, verbose_name='当班班次', on_delete=models.CASCADE) leader = models.ForeignKey('system.user', verbose_name='班长', on_delete=models.CASCADE) start_time = models.DateTimeField('值班开始') - end_time = models.DateTimeField('值班结束') \ No newline at end of file + end_time = models.DateTimeField('值班结束') + note = models.TextField('生产情况记录', null=True, blank=True) + stlogs = models.ManyToManyField('enm.stlog', verbose_name='关联停机记录', through='enm.stsflog') + + +class StSfLog(BaseModel): + """ + 停机-值班记录关联表 + """ + stlog = models.ForeignKey(StLog, verbose_name='关联停机记录', on_delete=models.CASCADE) + sflog = models.ForeignKey(SfLog, verbose_name='关联值班记录', on_delete=models.CASCADE) + is_current_down = models.BooleanField('是否本班停机', default=False) + reason = models.TextField('停机原因', null=True, blank=True) + + class Meta: + ordering = ['sflog__start_time'] + +class HourStat(BaseModel): + """小时统计表 + """ + year = models.PositiveSmallIntegerField('年') + month = models.PositiveSmallIntegerField('月') + day = models.PositiveSmallIntegerField('日') + hour = models.PositiveSmallIntegerField('时') + mpoint = models.ForeignKey(Mpoint, verbose_name='关联测点', on_delete=models.CASCADE) + val = models.FloatField('统计值', default=0) + is_calculated = models.BooleanField('是否计算过', default=False) + + +class Goal(CommonADModel): + """目标 + """ + mgroup = models.ForeignKey(Mgroup, verbose_name='关联工段', on_delete=models.CASCADE, null=True, blank=True) + product = models.ForeignKey(Product, verbose_name='关联产品', on_delete=models.CASCADE, null=True, blank=True) + team = models.ForeignKey(Team, verbose_name='关联班组', on_delete=models.CASCADE, null=True, blank=True) + year = models.PositiveSmallIntegerField('年') + goal_name = models.CharField('目标名称', max_length=50, help_text='总产量/台时产量/单位产品分布电耗/') + goal_val = models.FloatField('全年目标值') + goal_val_1 = models.FloatField('1月份目标值') + goal_val_2 = models.FloatField('2月份目标值') + goal_val_3 = models.FloatField('3月份目标值') + goal_val_4 = models.FloatField('4月份目标值') + goal_val_5 = models.FloatField('5月份目标值') + goal_val_6 = models.FloatField('6月份目标值') + goal_val_7 = models.FloatField('7月份目标值') + goal_val_8 = models.FloatField('8月份目标值') + goal_val_9 = models.FloatField('9月份目标值') + goal_val_10 = models.FloatField('10月份目标值') + goal_val_11 = models.FloatField('11月份目标值') + goal_val_12 = models.FloatField('12月份目标值') \ No newline at end of file diff --git a/apps/enm/serializers.py b/apps/enm/serializers.py index 5ce4138a..3d96f8b2 100644 --- a/apps/enm/serializers.py +++ b/apps/enm/serializers.py @@ -1,5 +1,5 @@ from apps.utils.serializers import CustomModelSerializer -from apps.enm.models import Mpoint, Mgroup, Mrecord, Team, Drecord +from apps.enm.models import Mpoint, Mgroup, MpLog, Team, SfLog, StLog from apps.system.models import Dept from apps.system.serializers import DeptSimpleSerializer from apps.utils.constants import EXCLUDE_FIELDS, EXCLUDE_FIELDS_BASE @@ -33,9 +33,35 @@ class MpointSerializer(CustomModelSerializer): read_only_fields = EXCLUDE_FIELDS + ['mgroup_name', 'belong_dept_name'] -class MrecordSerializer(CustomModelSerializer): +class MpLogSerializer(CustomModelSerializer): mpoint_name = serializers.CharField(source='mpoint.name') class Meta: - model = Mrecord + model = MpLog fields = '__all__' read_only_fields = EXCLUDE_FIELDS + ['mpoint_name'] + + +class StLogSerializer(CustomModelSerializer): + mgroup_name = serializers.CharField(source='mgroup.name') + class Meta: + model = StLog + fields = '__all__' + + +class SfLogSerializer(CustomModelSerializer): + mgroup_name = serializers.CharField(source='mgroup.name') + team_name = serializers.CharField(source='team.name') + shift_name = serializers.CharField(source='shift.name') + leader_name = serializers.CharField(source='leader.name') + class Meta: + model = SfLog + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS + ['mgroup_name', 'team_name', 'shift_name', 'leader_name'] + update_fields = ['start_time', 'end_time', 'note'] + + def to_internal_value(self, data): + if hasattr(self.Meta, 'update_fields') and self.context['request'].method in ['PUT', 'PATCH']: + u_fields = self.Meta.update_fields + new_data = {key: data[key] for key in u_fields if key in data} + return super().to_internal_value(new_data) + return super().to_internal_value(data) \ No newline at end of file diff --git a/apps/enm/services.py b/apps/enm/services.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/enm/tasks.py b/apps/enm/tasks.py index b6db1bb9..ef2f4984 100644 --- a/apps/enm/tasks.py +++ b/apps/enm/tasks.py @@ -4,12 +4,78 @@ from apps.utils.tasks import CustomTask from celery import shared_task from apps.utils.sql import DbConnection from server.settings import get_sysconfig +from django.core.cache import cache +from apps.enm.models import Mrecord, Mpoint, HourStat +import datetime + +def get_current_and_previous_hour(): + now = datetime.datetime.now() + current_hour = now.hour + current_date = now.date() + + current_start_time = datetime.datetime.combine(current_date, datetime.time(current_hour, 0, 0)) + current_end_time = datetime.datetime.combine(current_date, datetime.time(current_hour, 59, 59)) + current_time_range = (current_start_time, current_end_time) + + previous_hour = current_hour - 1 if current_hour > 0 else 23 + previous_date = current_date if previous_hour < current_hour else current_date - datetime.timedelta(days=1) + + previous_start_time = datetime.datetime.combine(previous_date, datetime.time(previous_hour, 0, 0)) + previous_end_time = datetime.datetime.combine(previous_date, datetime.time(previous_hour, 59, 59)) + previous_time_range = (previous_start_time, previous_end_time) + + return current_time_range, previous_time_range @shared_task(base=CustomTask) def get_tag_val(): config = get_sysconfig() with DbConnection(config['enm']['db_host'], config['enm']['db_user'], config['enm']['db_password'], config['enm']['db_database']) as cursor: - cursor.execute("select * from tag_value") - results = cursor.fetchall() + last_tag_id = cache.get('last_tag_id') + if last_tag_id is None: + mr = Mrecord.objects.all().order_by('-tag_update', 'tag_id').first() + if mr is None: + last_tag_id = 0 + else: + last_tag_id = mr.tag_id + cache.set('last_tag_id', last_tag_id) + cursor.execute("select id, val, tag_code, update_time from tag_value where id > %s order by id", (last_tag_id)) + results = cursor.fetchall() # 获取数据后保存至本地 for row in results: - print(row) \ No newline at end of file + mr_one = Mrecord() + mr_one.tag_id, mr_one.tag_val, mr_one.tag_code, mr_one.tag_update = row + mr_one.mpoint, _ = Mpoint.objects.get_or_create(code=mr_one.tag_code, defaults={'name': mr_one.tag_code, 'code': mr_one.tag_code, 'unit': 'unknown'}) + mr_one.save() + +@shared_task(base=CustomTask) +def cal_hourstat(): + """ + 计算小时统计量,默认计算本小时和上小时 + """ + for mpoint in Mpoint.objects.all(): + c_t_r, p_t_r = get_current_and_previous_hour() + if mpoint.cate == 'elec': # 是否是电能 + # 计算本小时,可能不需要 + start_time = c_t_r[0] + params = {'mpoint': mpoint} + params['year'], params['month'], params['day'], params['hour'] = start_time.year, start_time.month, start_time.day, start_time.hour + mrs = Mrecord.objects.filter(mpoint=mpoint, tag_update__gte=c_t_r[0], tag_update__lte=c_t_r[1]).order_by('tag_update') + val = 0 + if mrs.exists(): + val = mrs.last() - mrs.first() + hs, _ = HourStat.objects.get_or_create(**params, defaults=params) + hs.val = val + hs.save() + + # 计算上小时 + start_time2 = p_t_r[0] + params = {'mpoint': mpoint} + params['year'], params['month'], params['day'], params['hour'] = start_time2.year, start_time2.month, start_time2.day, start_time2.hour + hs, _ = HourStat.objects.get_or_create(**params, defaults=params) + if not hs.is_calculated: + mrs = Mrecord.objects.filter(mpoint=mpoint, tag_update__gte=p_t_r[0], tag_update__lte=p_t_r[1]).order_by('tag_update') + val = 0 + if mrs.exists(): + val = mrs.last() - mrs.first() + hs.val = val + hs.is_calculated = True + hs.save() \ No newline at end of file diff --git a/apps/enm/urls.py b/apps/enm/urls.py index 6f15d882..f5d2b3c2 100644 --- a/apps/enm/urls.py +++ b/apps/enm/urls.py @@ -1,6 +1,6 @@ from django.urls import path, include from rest_framework.routers import DefaultRouter -from apps.enm.views import MpointViewSet, MgroupViewSet, TeamViewSet +from apps.enm.views import MpointViewSet, MgroupViewSet, TeamViewSet, MpLogViewSet, SfLogViewSet, StLogViewSet API_BASE_URL = 'api/enm/' HTML_BASE_URL = 'enm/' @@ -9,7 +9,9 @@ router = DefaultRouter() router.register('mpoint', MpointViewSet, basename='mpoint') router.register('mgroup', MgroupViewSet, basename='mgroup') router.register('team', TeamViewSet, basename='team') - +router.register('mplog', MpLogViewSet, basename='mplog') +router.register('sflog', SfLogViewSet, basename='sflog') +router.register('stlog', StLogViewSet, basename='stlog') urlpatterns = [ path(API_BASE_URL, include(router.urls)), ] \ No newline at end of file diff --git a/apps/enm/views.py b/apps/enm/views.py index a23f6718..2402ea48 100644 --- a/apps/enm/views.py +++ b/apps/enm/views.py @@ -1,8 +1,11 @@ from django.shortcuts import render -from apps.enm.models import Mpoint, Mgroup, Team, Mrecord -from apps.utils.viewsets import CustomModelViewSet -from apps.enm.serializers import MpointSerializer, TeamSerializer, MgroupSerializer +from apps.enm.models import Mpoint, Mgroup, Team, MpLog, SfLog, StLog, StSfLog +from apps.utils.viewsets import CustomModelViewSet, GenericViewSet +from rest_framework.mixins import ListModelMixin +from apps.enm.serializers import MpointSerializer, TeamSerializer, MgroupSerializer, MpLogSerializer, SfLogSerializer, StLogSerializer from rest_framework.exceptions import ParseError +from django.db import transaction +from django.db.models import Q class MgroupViewSet(CustomModelViewSet): queryset = Mgroup.objects.all() @@ -25,4 +28,42 @@ class MpointViewSet(CustomModelViewSet): serializer_class = MpointSerializer select_related_fields = ['create_by', 'belong_dept', 'ep_monitored', 'ep_belong', 'mgroup'] filterset_fields = ['belong_dept', 'ep_monitored', 'ep_belong', 'mgroup'] - search_fields = ['number', 'code'] \ No newline at end of file + search_fields = ['number', 'code'] + + +class MpLogViewSet(ListModelMixin, GenericViewSet): + queryset = MpLog.objects.all() + serializer_class = MpLogSerializer + select_related_fields = ['mpoint'] + filterset_fields = ['mpoint'] + + +class StLogViewSet(ListModelMixin, GenericViewSet): + queryset = StLog.objects.all() + serializer_class = StLogSerializer + select_related_fields = ['mgroup'] + filterset_fields = ['mgroup'] + ordering = ['-start_time'] + + +class SfLogViewSet(CustomModelViewSet): + queryset = SfLog.objects.all() + serializer_class = SfLogSerializer + select_related_fields = ['mgroup', 'shift', 'team', 'leader'] + filterset_fields = ['mgroup', 'shift', 'team', 'leader', 'team__belong_dept'] + search_fields = ['note'] + + @transaction.atomic + def perform_create(self, serializer): + ins = serializer.save() + # 查看并比对停机记录 + stls = StLog.objects.filter(mroup=ins.mgroup) + stls_ = (stls.filter(start_time__gte=ins.start_time, start_time__lt=ins.end_time)| + stls.exclude(end_time=None).filter(start_time__lte=ins.start_time, end_time__gt=ins.end_time)| + stls.exclude(end_time=None).filter(end_time__gte=ins.start_time, end_time__lt=ins.end_time)) + for i in stls_: + StSfLog.objects.get_or_create(stlog=i, sflog=ins, defaults={'stlog': i, 'sflog': ins}) + stsflog = StSfLog.objects.filter(stlog=i).order_by('-sflog__start_time').first() + if stsflog: + stsflog.is_current_down = True + stsflog.save() \ No newline at end of file